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 <noreply@anthropic.com>
This commit is contained in:
@@ -33,6 +33,7 @@ export interface AvailableModelGroup {
|
||||
|
||||
export interface AvailableModelsResponse {
|
||||
default: string
|
||||
default_provider: string
|
||||
groups: AvailableModelGroup[]
|
||||
}
|
||||
|
||||
|
||||
@@ -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)"
|
||||
>
|
||||
<span class="model-item-name">{{ model }}</span>
|
||||
<svg v-if="model === appStore.selectedModel" class="model-check" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<svg v-if="model === appStore.selectedModel && group.provider === appStore.selectedProvider" class="model-check" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<polyline points="20 6 9 17 4 12" />
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
@@ -18,6 +18,7 @@ export const useAppStore = defineStore('app', () => {
|
||||
const updating = ref(false)
|
||||
const modelGroups = ref<AvailableModelGroup[]>([])
|
||||
const selectedModel = ref('')
|
||||
const selectedProvider = ref('')
|
||||
const healthPollTimer = ref<ReturnType<typeof setInterval>>()
|
||||
|
||||
// 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,
|
||||
|
||||
@@ -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 }
|
||||
|
||||
Reference in New Issue
Block a user