From 40109e9c429c15c87e88cd721ab61d3426fb8724 Mon Sep 17 00:00:00 2001 From: ekko <152005280+EKKOLearnAI@users.noreply.github.com> Date: Wed, 20 May 2026 18:26:01 +0800 Subject: [PATCH] [codex] fix profile scoped model selection (#881) * fix profile scoped model selection * test profile scoped provider refresh --- package.json | 2 +- packages/client/src/api/hermes/system.ts | 10 ++--- .../src/components/hermes/chat/ChatPanel.vue | 39 +++++++++++++++---- .../hermes/chat/SessionListItem.vue | 33 +++++++++++++++- .../src/components/layout/ModelSelector.vue | 15 ++++++- packages/client/src/data/changelog.ts | 2 +- packages/client/src/i18n/locales/de.ts | 1 + packages/client/src/i18n/locales/en.ts | 1 + packages/client/src/i18n/locales/es.ts | 1 + packages/client/src/i18n/locales/fr.ts | 1 + packages/client/src/i18n/locales/ja.ts | 1 + packages/client/src/i18n/locales/ko.ts | 1 + packages/client/src/i18n/locales/pt.ts | 1 + packages/client/src/i18n/locales/zh-TW.ts | 1 + packages/client/src/i18n/locales/zh.ts | 1 + packages/client/src/stores/hermes/models.ts | 8 ++-- packages/client/src/stores/hermes/profiles.ts | 2 + tests/client/models-store.test.ts | 25 ++++++++++-- 18 files changed, 119 insertions(+), 26 deletions(-) diff --git a/package.json b/package.json index 98ad023..19fa167 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hermes-web-ui", - "version": "0.5.31", + "version": "0.5.32", "description": "Self-hosted AI chat dashboard for Hermes Agent — multi-model web UI with multi-platform integration", "repository": { "type": "git", diff --git a/packages/client/src/api/hermes/system.ts b/packages/client/src/api/hermes/system.ts index 338de68..f05660f 100644 --- a/packages/client/src/api/hermes/system.ts +++ b/packages/client/src/api/hermes/system.ts @@ -84,15 +84,11 @@ export async function fetchConfigModels(): Promise { return request('/api/hermes/config/models') } -function currentProfileName(): string { - try { - return localStorage.getItem('hermes_active_profile_name') || 'default' - } catch { - return 'default' - } +export async function fetchAvailableModels(): Promise { + return request('/api/hermes/available-models') } -export async function fetchAvailableModels(profile = currentProfileName()): Promise { +export async function fetchAvailableModelsForProfile(profile: string): Promise { const params = new URLSearchParams() params.set('profile', profile || 'default') return request(`/api/hermes/available-models?${params.toString()}`) diff --git a/packages/client/src/components/hermes/chat/ChatPanel.vue b/packages/client/src/components/hermes/chat/ChatPanel.vue index c6a0220..e7441ee 100644 --- a/packages/client/src/components/hermes/chat/ChatPanel.vue +++ b/packages/client/src/components/hermes/chat/ChatPanel.vue @@ -157,7 +157,7 @@ function getModelGroupsForProfile(profile: string) { const profileModels = appStore.profileModelGroups.find( (entry) => entry.profile === profile, ); - return profileModels?.groups?.length ? profileModels.groups : appStore.modelGroups; + return profileModels?.groups || []; } function getDefaultModelForProfile(profile: string) { @@ -449,7 +449,7 @@ async function handleContextMenuSelect(key: string) { workspaceValue.value = session?.workspace || ""; showWorkspaceModal.value = true; } else if (key === "model") { - openSessionModelModal(contextSessionId.value); + await openSessionModelModal(contextSessionId.value); } else if (key === "rename") { const session = chatStore.sessions.find( (s) => s.id === contextSessionId.value, @@ -522,13 +522,13 @@ const sessionModelProvider = ref(""); const sessionModelCustomInput = ref(""); const sessionModelCustomProvider = ref(""); -const sessionModelProfile = computed(() => { +const sessionModelProfile = computed(() => { const session = chatStore.sessions.find((s) => s.id === sessionModelSessionId.value); - return session?.profile || profilesStore.activeProfileName || "default"; + return session?.profile || null; }); const sessionModelBaseGroups = computed(() => - getModelGroupsForProfile(sessionModelProfile.value), + sessionModelProfile.value ? getModelGroupsForProfile(sessionModelProfile.value) : [], ); const sessionModelProviderOptions = computed(() => @@ -561,9 +561,14 @@ const filteredSessionModelGroups = computed(() => { .filter((group) => group.models.length > 0 || group.label.toLowerCase().includes(query)); }); -function openSessionModelModal(sessionId: string) { +async function openSessionModelModal(sessionId: string) { + if (appStore.modelGroups.length === 0 && appStore.profileModelGroups.length === 0) { + await appStore.loadModels(); + } const session = chatStore.sessions.find((s) => s.id === sessionId); - const defaults = getDefaultModelForProfile(session?.profile || profilesStore.activeProfileName || "default"); + const defaults = session?.profile + ? getDefaultModelForProfile(session.profile) + : { provider: "", model: "" }; sessionModelSessionId.value = sessionId; sessionModelValue.value = session?.model || defaults.model || ""; sessionModelProvider.value = session?.provider || defaults.provider || ""; @@ -1626,6 +1631,26 @@ async function handleSessionModelCustomSubmit() { &.active .session-item-title { color: $accent-primary; } + + &.missing-models { + color: #b42318; + background: rgba(220, 38, 38, 0.08); + + .session-item-title, + .session-item-profile-name, + .session-item-time { + color: #b42318; + } + + .session-item-model { + color: #b42318; + background: rgba(220, 38, 38, 0.12); + } + + &:hover { + background: rgba(220, 38, 38, 0.12); + } + } } :deep(.session-item-content) { diff --git a/packages/client/src/components/hermes/chat/SessionListItem.vue b/packages/client/src/components/hermes/chat/SessionListItem.vue index b00237b..bf1c0d7 100644 --- a/packages/client/src/components/hermes/chat/SessionListItem.vue +++ b/packages/client/src/components/hermes/chat/SessionListItem.vue @@ -1,6 +1,6 @@