From 8a4ab2d69df8f0279da5e3ecb867a0e516688dd3 Mon Sep 17 00:00:00 2001 From: ekko Date: Sun, 19 Apr 2026 15:05:05 +0800 Subject: [PATCH] fix: provider-aware model selection to prevent cross-provider conflicts When multiple providers share the same model name, the selector now uses both model ID and provider as the unique identifier instead of model name alone. Backend returns default_provider alongside default model, and model switching sends provider to the config. Fixes #52 Co-Authored-By: Claude Opus 4.6 --- packages/client/src/api/hermes/system.ts | 1 + .../client/src/components/layout/ModelSelector.vue | 10 +++++----- packages/client/src/stores/hermes/app.ts | 4 ++++ packages/server/src/routes/hermes/filesystem.ts | 4 +++- 4 files changed, 13 insertions(+), 6 deletions(-) diff --git a/packages/client/src/api/hermes/system.ts b/packages/client/src/api/hermes/system.ts index 1eeddab..4835202 100644 --- a/packages/client/src/api/hermes/system.ts +++ b/packages/client/src/api/hermes/system.ts @@ -33,6 +33,7 @@ export interface AvailableModelGroup { export interface AvailableModelsResponse { default: string + default_provider: string groups: AvailableModelGroup[] } diff --git a/packages/client/src/components/layout/ModelSelector.vue b/packages/client/src/components/layout/ModelSelector.vue index 7861378..91c5ee3 100644 --- a/packages/client/src/components/layout/ModelSelector.vue +++ b/packages/client/src/components/layout/ModelSelector.vue @@ -30,8 +30,8 @@ function isGroupCollapsed(provider: string) { return !!collapsedGroups.value[provider] } -function handleSelect(model: string) { - appStore.switchModel(model) +function handleSelect(model: string, provider: string) { + appStore.switchModel(model, provider) showModal.value = false searchQuery.value = '' } @@ -85,11 +85,11 @@ function openModal() { v-for="model in group.models" :key="model" class="model-item" - :class="{ active: model === appStore.selectedModel }" - @click="handleSelect(model)" + :class="{ active: model === appStore.selectedModel && group.provider === appStore.selectedProvider }" + @click="handleSelect(model, group.provider)" > {{ model }} - + diff --git a/packages/client/src/stores/hermes/app.ts b/packages/client/src/stores/hermes/app.ts index 3206dec..9267417 100644 --- a/packages/client/src/stores/hermes/app.ts +++ b/packages/client/src/stores/hermes/app.ts @@ -18,6 +18,7 @@ export const useAppStore = defineStore('app', () => { const updating = ref(false) const modelGroups = ref([]) const selectedModel = ref('') + const selectedProvider = ref('') const healthPollTimer = ref>() // Settings @@ -56,6 +57,7 @@ export const useAppStore = defineStore('app', () => { const res = await fetchAvailableModels() modelGroups.value = res.groups selectedModel.value = res.default + selectedProvider.value = res.default_provider || '' } catch { // ignore } @@ -68,6 +70,7 @@ export const useAppStore = defineStore('app', () => { const provider = providerOverride || group?.provider || '' await updateDefaultModel({ default: modelId, provider }) selectedModel.value = modelId + selectedProvider.value = provider || '' } catch (err: any) { console.error('Failed to switch model:', err) } @@ -117,6 +120,7 @@ export const useAppStore = defineStore('app', () => { doUpdate, modelGroups, selectedModel, + selectedProvider, streamEnabled, sessionPersistence, maxTokens, diff --git a/packages/server/src/routes/hermes/filesystem.ts b/packages/server/src/routes/hermes/filesystem.ts index f0e007b..1b1812c 100644 --- a/packages/server/src/routes/hermes/filesystem.ts +++ b/packages/server/src/routes/hermes/filesystem.ts @@ -466,8 +466,10 @@ fsRoutes.get('/api/hermes/available-models', async (ctx) => { const config = await readConfigYaml() const modelSection = config.model let currentDefault = '' + let currentDefaultProvider = '' if (typeof modelSection === 'object' && modelSection !== null) { currentDefault = String(modelSection.default || '').trim() + currentDefaultProvider = String(modelSection.provider || '').trim() } else if (typeof modelSection === 'string') { currentDefault = modelSection.trim() } @@ -592,7 +594,7 @@ fsRoutes.get('/api/hermes/available-models', async (ctx) => { return } - ctx.body = { default: currentDefault, groups: dedupedGroups } + ctx.body = { default: currentDefault, default_provider: currentDefaultProvider, groups: dedupedGroups } } catch (err: any) { ctx.status = 500 ctx.body = { error: err.message }