Revert "feat(#445): full Models tab parity — settings, aux tasks, MOA config"
This reverts commit dc808daee8.
This commit is contained in:
1 parent
dc808daee8
commit
0ee24144c0
5 files changed
+394
-1671
No files matched your search
@@ -1,64 +0,0 @@
|
||||
package com.m57.hermescontrol.data.model
|
||||
|
||||
data class AuxiliaryTaskAssignment(
|
||||
val task: String,
|
||||
val provider: String,
|
||||
val model: String,
|
||||
val base_url: String? = null,
|
||||
)
|
||||
|
||||
data class AuxiliaryModelsResponse(
|
||||
val tasks: List<AuxiliaryTaskAssignment>,
|
||||
val main: MainModelAssignment,
|
||||
)
|
||||
|
||||
data class MainModelAssignment(
|
||||
val provider: String,
|
||||
val model: String,
|
||||
)
|
||||
|
||||
data class MoaModelSlot(
|
||||
val provider: String,
|
||||
val model: String,
|
||||
)
|
||||
|
||||
data class MoaConfigPreset(
|
||||
val reference_models: List<MoaModelSlot>,
|
||||
val aggregator: MoaModelSlot,
|
||||
val reference_temperature: Double = 0.7,
|
||||
val aggregator_temperature: Double = 0.3,
|
||||
val max_tokens: Int = 4096,
|
||||
val enabled: Boolean = true,
|
||||
)
|
||||
|
||||
data class MoaConfigResponse(
|
||||
val default_preset: String = "",
|
||||
val active_preset: String = "",
|
||||
val presets: Map<String, MoaConfigPreset> = emptyMap(),
|
||||
val reference_models: List<MoaModelSlot> = emptyList(),
|
||||
val aggregator: MoaModelSlot = MoaModelSlot("", ""),
|
||||
val reference_temperature: Double = 0.7,
|
||||
val aggregator_temperature: Double = 0.3,
|
||||
val max_tokens: Int = 4096,
|
||||
val enabled: Boolean = true,
|
||||
)
|
||||
|
||||
data class ModelAssignmentRequest(
|
||||
val confirm_expensive_model: Boolean = false,
|
||||
val scope: String,
|
||||
val provider: String,
|
||||
val model: String,
|
||||
val base_url: String? = null,
|
||||
val task: String? = null,
|
||||
)
|
||||
|
||||
data class ModelAssignmentResponse(
|
||||
val confirm_message: String? = null,
|
||||
val confirm_required: Boolean? = null,
|
||||
val ok: Boolean = false,
|
||||
val scope: String? = null,
|
||||
val provider: String? = null,
|
||||
val model: String? = null,
|
||||
val tasks: List<String>? = null,
|
||||
val reset: Boolean? = null,
|
||||
)
|
||||
@@ -4,7 +4,6 @@ import com.google.gson.JsonElement
|
||||
import com.m57.hermescontrol.data.model.AchievementsResponse
|
||||
import com.m57.hermescontrol.data.model.ActiveProfileResponse
|
||||
import com.m57.hermescontrol.data.model.AgentPluginInstallBody
|
||||
import com.m57.hermescontrol.data.model.AuxiliaryModelsResponse
|
||||
import com.m57.hermescontrol.data.model.ConfigSchemaResponse
|
||||
import com.m57.hermescontrol.data.model.ConfigUpdateRequest
|
||||
import com.m57.hermescontrol.data.model.CreateCronJobRequest
|
||||
@@ -26,9 +25,6 @@ import com.m57.hermescontrol.data.model.McpServersResponse
|
||||
import com.m57.hermescontrol.data.model.MessagingPlatformResponse
|
||||
import com.m57.hermescontrol.data.model.MessagingPlatformTestResult
|
||||
import com.m57.hermescontrol.data.model.MessagingPlatformUpdate
|
||||
import com.m57.hermescontrol.data.model.MoaConfigResponse
|
||||
import com.m57.hermescontrol.data.model.ModelAssignmentRequest
|
||||
import com.m57.hermescontrol.data.model.ModelAssignmentResponse
|
||||
import com.m57.hermescontrol.data.model.ModelOptionsResponse
|
||||
import com.m57.hermescontrol.data.model.PairingApproveRequest
|
||||
import com.m57.hermescontrol.data.model.PairingResponse
|
||||
@@ -289,22 +285,6 @@ interface HermesApiService {
|
||||
@GET("api/model/options")
|
||||
suspend fun getModelOptions(): Response<ModelOptionsResponse>
|
||||
|
||||
@GET("api/model/auxiliary")
|
||||
suspend fun getAuxiliaryModels(): Response<AuxiliaryModelsResponse>
|
||||
|
||||
@GET("api/model/moa")
|
||||
suspend fun getMoaModels(): Response<MoaConfigResponse>
|
||||
|
||||
@PUT("api/model/moa")
|
||||
suspend fun saveMoaModels(
|
||||
@Body body: MoaConfigResponse,
|
||||
): Response<MoaConfigResponse>
|
||||
|
||||
@POST("api/model/set")
|
||||
suspend fun setModelAssignment(
|
||||
@Body body: ModelAssignmentRequest,
|
||||
): Response<ModelAssignmentResponse>
|
||||
|
||||
@GET("api/logs")
|
||||
suspend fun getLogs(
|
||||
@Query("limit") limit: Int? = null,
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -3,9 +3,6 @@ package com.m57.hermescontrol.ui.model
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.m57.hermescontrol.data.local.AuthManager
|
||||
import com.m57.hermescontrol.data.model.AuxiliaryTaskAssignment
|
||||
import com.m57.hermescontrol.data.model.MoaConfigResponse
|
||||
import com.m57.hermescontrol.data.model.ModelAssignmentRequest
|
||||
import com.m57.hermescontrol.data.model.ModelProvider
|
||||
import com.m57.hermescontrol.data.model.PinnedModel
|
||||
import com.m57.hermescontrol.data.model.ProfileInfo
|
||||
@@ -23,22 +20,6 @@ import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
data class AuxTaskInfo(
|
||||
val key: String,
|
||||
val label: String,
|
||||
val hint: String,
|
||||
)
|
||||
|
||||
val AUX_TASKS =
|
||||
listOf(
|
||||
AuxTaskInfo("vision", "Vision", "image/video analysis"),
|
||||
AuxTaskInfo("session_search", "Session search", "past conversation search"),
|
||||
AuxTaskInfo("summarizer", "Compression", "context compression"),
|
||||
AuxTaskInfo("code_exec", "Code execution", "runtime for code blocks"),
|
||||
AuxTaskInfo("computer_use", "Computer use", "desktop/browser automation"),
|
||||
AuxTaskInfo("web_search", "Web search", "live search queries"),
|
||||
)
|
||||
|
||||
data class ModelUiState(
|
||||
val isLoading: Boolean = false,
|
||||
val providers: List<ModelProvider> = emptyList(),
|
||||
@@ -46,24 +27,6 @@ data class ModelUiState(
|
||||
val errorMessage: String? = null,
|
||||
val toastMessage: String? = null,
|
||||
val pinnedModels: List<PinnedModel> = emptyList(),
|
||||
// Main model
|
||||
val mainModelProvider: String = "",
|
||||
val mainModelModel: String = "",
|
||||
// Auxiliary tasks
|
||||
val auxTasks: List<AuxiliaryTaskAssignment> = emptyList(),
|
||||
// MOA config
|
||||
val moaConfig: MoaConfigResponse? = null,
|
||||
// Dialog state
|
||||
val showAuxDialog: Boolean = false,
|
||||
val showMoaDialog: Boolean = false,
|
||||
val showMainModelPicker: Boolean = false,
|
||||
val showAuxModelPicker: Boolean = false,
|
||||
val auxPickerTask: String = "",
|
||||
// Model picker busy (for expensive model confirmation)
|
||||
val modelPickerBusy: Boolean = false,
|
||||
val modelPickerConfirmMessage: String? = null,
|
||||
// Pending resolve
|
||||
val pendingModelPickerResolve: ((Boolean) -> Unit)? = null,
|
||||
)
|
||||
|
||||
class ModelViewModel :
|
||||
@@ -76,69 +39,37 @@ class ModelViewModel :
|
||||
_uiState.update { it.copy(pinnedModels = AuthManager.getPinnedModels()) }
|
||||
}
|
||||
|
||||
fun loadAll() {
|
||||
loadModelOptions()
|
||||
}
|
||||
|
||||
fun loadModelOptions() {
|
||||
_uiState.update { it.copy(isLoading = true, errorMessage = null) }
|
||||
viewModelScope.launch {
|
||||
val optionsDeferred =
|
||||
val responseResultDeferred =
|
||||
async(Dispatchers.IO) {
|
||||
safeApiCall { ApiClient.hermesApi.getModelOptions() }
|
||||
}
|
||||
val activeProfileDeferred =
|
||||
val activeProfileNameResResultDeferred =
|
||||
async(Dispatchers.IO) {
|
||||
safeApiCall { ApiClient.hermesApi.getActiveProfile() }
|
||||
}
|
||||
val profilesDeferred =
|
||||
val profilesResResultDeferred =
|
||||
async(Dispatchers.IO) {
|
||||
safeApiCall { ApiClient.hermesApi.getProfiles() }
|
||||
}
|
||||
val auxDeferred =
|
||||
async(Dispatchers.IO) {
|
||||
safeApiCall { ApiClient.hermesApi.getAuxiliaryModels() }
|
||||
}
|
||||
val moaDeferred =
|
||||
async(Dispatchers.IO) {
|
||||
safeApiCall { ApiClient.hermesApi.getMoaModels() }
|
||||
}
|
||||
|
||||
val optionsResult = optionsDeferred.await()
|
||||
val activeProfileResult = activeProfileDeferred.await()
|
||||
val profilesResult = profilesDeferred.await()
|
||||
val auxResult = auxDeferred.await()
|
||||
val moaResult = moaDeferred.await()
|
||||
val responseResult = responseResultDeferred.await()
|
||||
val activeProfileNameResResult = activeProfileNameResResultDeferred.await()
|
||||
val profilesResResult = profilesResResultDeferred.await()
|
||||
|
||||
when (optionsResult) {
|
||||
when (responseResult) {
|
||||
is NetworkResult.Success -> {
|
||||
val activeName =
|
||||
if (activeProfileResult is NetworkResult.Success) {
|
||||
activeProfileResult.data.active
|
||||
if (activeProfileNameResResult is NetworkResult.Success) {
|
||||
activeProfileNameResResult.data.active
|
||||
} else {
|
||||
null
|
||||
}
|
||||
val activeProfile =
|
||||
if (profilesResult is NetworkResult.Success && activeName != null) {
|
||||
profilesResult.data.profiles.find { it.name == activeName }
|
||||
} else {
|
||||
null
|
||||
}
|
||||
val mainModel =
|
||||
if (auxResult is NetworkResult.Success) {
|
||||
Pair(auxResult.data.main.provider, auxResult.data.main.model)
|
||||
} else {
|
||||
Pair("", "")
|
||||
}
|
||||
val auxTasks =
|
||||
if (auxResult is NetworkResult.Success) {
|
||||
auxResult.data.tasks
|
||||
} else {
|
||||
emptyList()
|
||||
}
|
||||
val moaConfig =
|
||||
if (moaResult is NetworkResult.Success) {
|
||||
moaResult.data
|
||||
if (profilesResResult is NetworkResult.Success && activeName != null) {
|
||||
profilesResResult.data.profiles.find { it.name == activeName }
|
||||
} else {
|
||||
null
|
||||
}
|
||||
@@ -146,21 +77,18 @@ class ModelViewModel :
|
||||
_uiState.update {
|
||||
it.copy(
|
||||
isLoading = false,
|
||||
providers = optionsResult.data.providers.orEmpty(),
|
||||
providers = responseResult.data.providers.orEmpty(),
|
||||
activeProfile = activeProfile,
|
||||
pinnedModels = AuthManager.getPinnedModels(),
|
||||
mainModelProvider = mainModel.first,
|
||||
mainModelModel = mainModel.second,
|
||||
auxTasks = auxTasks,
|
||||
moaConfig = moaConfig,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
is NetworkResult.Failure -> {
|
||||
_uiState.update {
|
||||
it.copy(
|
||||
isLoading = false,
|
||||
errorMessage = "Failed to load model options: ${optionsResult.error.message}",
|
||||
errorMessage = "Failed to load model options: ${responseResult.error.message}",
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -168,273 +96,6 @@ class ModelViewModel :
|
||||
}
|
||||
}
|
||||
|
||||
/** Open the main model picker dialog. */
|
||||
fun openMainModelPicker() {
|
||||
_uiState.update { it.copy(showMainModelPicker = true) }
|
||||
}
|
||||
|
||||
fun closeMainModelPicker() {
|
||||
_uiState.update { it.copy(showMainModelPicker = false) }
|
||||
}
|
||||
|
||||
/** Set the main model via /api/model/set. */
|
||||
fun setMainModel(
|
||||
provider: String,
|
||||
model: String,
|
||||
) {
|
||||
_uiState.update { it.copy(modelPickerBusy = true) }
|
||||
viewModelScope.launch {
|
||||
val result =
|
||||
withContext(Dispatchers.IO) {
|
||||
safeApiCall {
|
||||
ApiClient.hermesApi.setModelAssignment(
|
||||
ModelAssignmentRequest(
|
||||
scope = "main",
|
||||
provider = provider,
|
||||
model = model,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
when (result) {
|
||||
is NetworkResult.Success -> {
|
||||
val data = result.data
|
||||
if (data.confirm_required == true) {
|
||||
_uiState.update {
|
||||
it.copy(
|
||||
modelPickerConfirmMessage =
|
||||
data.confirm_message ?: "This model is expensive. Continue?",
|
||||
pendingModelPickerResolve = { confirmed ->
|
||||
if (confirmed) {
|
||||
setMainModelWithConfirm(provider, model)
|
||||
}
|
||||
_uiState.update {
|
||||
it.copy(
|
||||
modelPickerConfirmMessage = null,
|
||||
pendingModelPickerResolve = null,
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
} else {
|
||||
_uiState.update {
|
||||
it.copy(
|
||||
toastMessage = "Main model set to $provider / $model",
|
||||
showMainModelPicker = false,
|
||||
modelPickerBusy = false,
|
||||
)
|
||||
}
|
||||
loadModelOptions()
|
||||
}
|
||||
}
|
||||
is NetworkResult.Failure -> {
|
||||
_uiState.update {
|
||||
it.copy(
|
||||
toastMessage = "Failed to set main model: ${result.error.message}",
|
||||
modelPickerBusy = false,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setMainModelWithConfirm(
|
||||
provider: String,
|
||||
model: String,
|
||||
) {
|
||||
viewModelScope.launch {
|
||||
val result =
|
||||
withContext(Dispatchers.IO) {
|
||||
safeApiCall {
|
||||
ApiClient.hermesApi.setModelAssignment(
|
||||
ModelAssignmentRequest(
|
||||
confirm_expensive_model = true,
|
||||
scope = "main",
|
||||
provider = provider,
|
||||
model = model,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
when (result) {
|
||||
is NetworkResult.Success -> {
|
||||
_uiState.update {
|
||||
it.copy(
|
||||
toastMessage = "Main model set to $provider / $model",
|
||||
showMainModelPicker = false,
|
||||
modelPickerBusy = false,
|
||||
)
|
||||
}
|
||||
loadModelOptions()
|
||||
}
|
||||
is NetworkResult.Failure -> {
|
||||
_uiState.update {
|
||||
it.copy(
|
||||
toastMessage = "Failed to set main model: ${result.error.message}",
|
||||
modelPickerBusy = false,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun dismissModelPickerConfirm() {
|
||||
_uiState.update {
|
||||
it.copy(
|
||||
modelPickerConfirmMessage = null,
|
||||
pendingModelPickerResolve = null,
|
||||
)
|
||||
}
|
||||
_uiState.value.pendingModelPickerResolve?.invoke(false)
|
||||
}
|
||||
|
||||
fun confirmModelPickerExpensive() {
|
||||
_uiState.value.pendingModelPickerResolve?.invoke(true)
|
||||
}
|
||||
|
||||
// -------------------- Auxiliary tasks --------------------
|
||||
|
||||
fun openAuxDialog() {
|
||||
_uiState.update { it.copy(showAuxDialog = true) }
|
||||
}
|
||||
|
||||
fun closeAuxDialog() {
|
||||
_uiState.update { it.copy(showAuxDialog = false) }
|
||||
}
|
||||
|
||||
fun openAuxModelPicker(task: String) {
|
||||
_uiState.update { it.copy(showAuxModelPicker = true, auxPickerTask = task) }
|
||||
}
|
||||
|
||||
fun closeAuxModelPicker() {
|
||||
_uiState.update { it.copy(showAuxModelPicker = false, auxPickerTask = "") }
|
||||
}
|
||||
|
||||
/** Set an auxiliary task model override. */
|
||||
fun setAuxTask(
|
||||
task: String,
|
||||
provider: String,
|
||||
model: String,
|
||||
) {
|
||||
viewModelScope.launch {
|
||||
val result =
|
||||
withContext(Dispatchers.IO) {
|
||||
safeApiCall {
|
||||
ApiClient.hermesApi.setModelAssignment(
|
||||
ModelAssignmentRequest(
|
||||
scope = "auxiliary",
|
||||
task = task,
|
||||
provider = provider,
|
||||
model = model,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
when (result) {
|
||||
is NetworkResult.Success -> {
|
||||
_uiState.update {
|
||||
it.copy(
|
||||
toastMessage = "Aux task '$task' set to $provider / $model",
|
||||
showAuxModelPicker = false,
|
||||
auxPickerTask = "",
|
||||
)
|
||||
}
|
||||
loadModelOptions()
|
||||
}
|
||||
is NetworkResult.Failure -> {
|
||||
_uiState.update {
|
||||
it.copy(
|
||||
toastMessage = "Failed to set aux task: ${result.error.message}",
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Reset all auxiliary tasks to auto. */
|
||||
fun resetAllAuxTasks() {
|
||||
viewModelScope.launch {
|
||||
_uiState.update { it.copy(modelPickerBusy = true) }
|
||||
val result =
|
||||
withContext(Dispatchers.IO) {
|
||||
safeApiCall {
|
||||
ApiClient.hermesApi.setModelAssignment(
|
||||
ModelAssignmentRequest(
|
||||
scope = "auxiliary",
|
||||
task = "__reset__",
|
||||
provider = "",
|
||||
model = "",
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
when (result) {
|
||||
is NetworkResult.Success -> {
|
||||
_uiState.update {
|
||||
it.copy(toastMessage = "All auxiliary tasks reset to auto", modelPickerBusy = false)
|
||||
}
|
||||
loadModelOptions()
|
||||
}
|
||||
is NetworkResult.Failure -> {
|
||||
_uiState.update {
|
||||
it.copy(
|
||||
toastMessage = "Failed to reset aux tasks: ${result.error.message}",
|
||||
modelPickerBusy = false,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------- MOA config --------------------
|
||||
|
||||
fun openMoaDialog() {
|
||||
_uiState.update { it.copy(showMoaDialog = true) }
|
||||
}
|
||||
|
||||
fun closeMoaDialog() {
|
||||
_uiState.update { it.copy(showMoaDialog = false) }
|
||||
}
|
||||
|
||||
fun saveMoaConfig(config: MoaConfigResponse) {
|
||||
viewModelScope.launch {
|
||||
_uiState.update { it.copy(modelPickerBusy = true) }
|
||||
val result =
|
||||
withContext(Dispatchers.IO) {
|
||||
safeApiCall {
|
||||
ApiClient.hermesApi.saveMoaModels(config)
|
||||
}
|
||||
}
|
||||
when (result) {
|
||||
is NetworkResult.Success -> {
|
||||
_uiState.update {
|
||||
it.copy(
|
||||
moaConfig = result.data,
|
||||
toastMessage = "MOA config saved",
|
||||
showMoaDialog = false,
|
||||
modelPickerBusy = false,
|
||||
)
|
||||
}
|
||||
}
|
||||
is NetworkResult.Failure -> {
|
||||
_uiState.update {
|
||||
it.copy(
|
||||
toastMessage = "Failed to save MOA config: ${result.error.message}",
|
||||
modelPickerBusy = false,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------- Profile model selection (existing) --------------------
|
||||
|
||||
fun selectModel(
|
||||
providerSlug: String,
|
||||
modelName: String,
|
||||
@@ -454,6 +115,7 @@ class ModelViewModel :
|
||||
}
|
||||
return@launch
|
||||
}
|
||||
|
||||
is NetworkResult.Success -> {
|
||||
val activeProfileName = activeProfileNameResResult.data.active
|
||||
val updateResResult =
|
||||
@@ -467,13 +129,14 @@ class ModelViewModel :
|
||||
}
|
||||
when (updateResResult) {
|
||||
is NetworkResult.Success -> {
|
||||
_uiState.update { it.copy(toastMessage = "Successfully set profile model to $modelName") }
|
||||
_uiState.update { it.copy(toastMessage = "Successfully set model to $modelName") }
|
||||
loadModelOptions()
|
||||
}
|
||||
|
||||
is NetworkResult.Failure -> {
|
||||
_uiState.update {
|
||||
it.copy(
|
||||
toastMessage = "Failed to set profile model: ${updateResResult.error.message}",
|
||||
toastMessage = "Failed to set model: ${updateResResult.error.message}",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user