Add session-level bridge model settings (#811)
This commit is contained in:
@@ -17,6 +17,7 @@ import { hasApiKey } from '@/api/client'
|
||||
const WEB_UI_VERSION = __APP_VERSION__
|
||||
|
||||
const SIDEBAR_COLLAPSED_KEY = 'hermes_sidebar_collapsed'
|
||||
const MODELS_CACHE_TTL_MS = 30000
|
||||
|
||||
export const useAppStore = defineStore('app', () => {
|
||||
const sidebarOpen = ref(false)
|
||||
@@ -42,6 +43,8 @@ export const useAppStore = defineStore('app', () => {
|
||||
const streamEnabled = ref(true)
|
||||
const sessionPersistence = ref(true)
|
||||
const maxTokens = ref(4096)
|
||||
let modelsLoadPromise: Promise<void> | null = null
|
||||
let modelsLoadedAt = 0
|
||||
|
||||
async function doUpdate(): Promise<boolean> {
|
||||
updating.value = true
|
||||
@@ -128,14 +131,26 @@ export const useAppStore = defineStore('app', () => {
|
||||
}
|
||||
}
|
||||
|
||||
async function loadModels() {
|
||||
async function loadModels(force = false) {
|
||||
if (!hasApiKey()) return
|
||||
try {
|
||||
const res = await fetchAvailableModels()
|
||||
applyAvailableModelsResponse(res)
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
if (!force && modelsLoadPromise) return modelsLoadPromise
|
||||
if (!force && modelGroups.value.length > 0 && Date.now() - modelsLoadedAt < MODELS_CACHE_TTL_MS) return
|
||||
modelsLoadPromise = (async () => {
|
||||
try {
|
||||
const res = await fetchAvailableModels()
|
||||
applyAvailableModelsResponse(res)
|
||||
modelsLoadedAt = Date.now()
|
||||
} catch {
|
||||
// ignore
|
||||
} finally {
|
||||
modelsLoadPromise = null
|
||||
}
|
||||
})()
|
||||
return modelsLoadPromise
|
||||
}
|
||||
|
||||
async function reloadModels() {
|
||||
return loadModels(true)
|
||||
}
|
||||
|
||||
function getModelAlias(modelId: string, provider?: string): string {
|
||||
@@ -220,7 +235,7 @@ export const useAppStore = defineStore('app', () => {
|
||||
async function setModelVisibility(provider: string, rule: ModelVisibilityRule) {
|
||||
const res = await updateModelVisibility({ provider, mode: rule.mode, models: rule.models })
|
||||
modelVisibility.value = res.model_visibility || {}
|
||||
await loadModels()
|
||||
await reloadModels()
|
||||
}
|
||||
|
||||
function startHealthPolling(interval = 30000) {
|
||||
@@ -285,6 +300,7 @@ export const useAppStore = defineStore('app', () => {
|
||||
maxTokens,
|
||||
checkConnection,
|
||||
loadModels,
|
||||
reloadModels,
|
||||
applyAvailableModelsResponse,
|
||||
switchModel,
|
||||
removeCustomModel,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { startRunViaSocket, resumeSession, registerSessionHandlers, unregisterSessionHandlers, getChatRunSocket, respondToolApproval, type RunEvent, type ContentBlock as ContentBlockImport } from '@/api/hermes/chat'
|
||||
import { deleteSession as deleteSessionApi, fetchSession, fetchSessions, type HermesMessage, type SessionSummary } from '@/api/hermes/sessions'
|
||||
import { deleteSession as deleteSessionApi, fetchSession, fetchSessions, setSessionModel, type HermesMessage, type SessionSummary } from '@/api/hermes/sessions'
|
||||
import { getApiKey } from '@/api/client'
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref, computed } from 'vue'
|
||||
@@ -238,7 +238,7 @@ function mapHermesSession(s: SessionSummary): Session {
|
||||
createdAt: Math.round(s.started_at * 1000),
|
||||
updatedAt: Math.round((s.last_active || s.ended_at || s.started_at) * 1000),
|
||||
model: s.model,
|
||||
provider: (s as any).billing_provider || '',
|
||||
provider: s.provider || (s as any).billing_provider || '',
|
||||
messageCount: s.message_count,
|
||||
endedAt: s.ended_at != null ? Math.round(s.ended_at * 1000) : null,
|
||||
lastActiveAt: s.last_active != null ? Math.round(s.last_active * 1000) : undefined,
|
||||
@@ -611,18 +611,25 @@ export const useChatStore = defineStore('chat', () => {
|
||||
// Inherit current global model
|
||||
const appStore = useAppStore()
|
||||
session.model = appStore.selectedModel || undefined
|
||||
session.provider = appStore.selectedProvider || ''
|
||||
switchSession(session.id)
|
||||
}
|
||||
|
||||
async function switchSessionModel(modelId: string, provider?: string) {
|
||||
if (!activeSession.value) return
|
||||
activeSession.value.model = modelId
|
||||
activeSession.value.provider = provider || ''
|
||||
// If provider changed, update global config too (Hermes requires it)
|
||||
if (provider) {
|
||||
const { useAppStore } = await import('./app')
|
||||
await useAppStore().switchModel(modelId, provider)
|
||||
async function switchSessionModel(modelId: string, provider?: string, sessionId?: string): Promise<boolean> {
|
||||
const targetId = sessionId || activeSession.value?.id
|
||||
if (!targetId) return false
|
||||
const ok = await setSessionModel(targetId, modelId, provider || '')
|
||||
if (!ok) return false
|
||||
const target = sessions.value.find(s => s.id === targetId)
|
||||
if (target) {
|
||||
target.model = modelId
|
||||
target.provider = provider || ''
|
||||
}
|
||||
if (activeSession.value?.id === targetId) {
|
||||
activeSession.value.model = modelId
|
||||
activeSession.value.provider = provider || ''
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
async function deleteSession(sessionId: string) {
|
||||
@@ -903,13 +910,21 @@ export const useChatStore = defineStore('chat', () => {
|
||||
}
|
||||
|
||||
const appStore = useAppStore()
|
||||
await appStore.loadModels()
|
||||
const sessionModel = activeSession.value?.model || appStore.selectedModel
|
||||
const isBridgeSource = activeSession.value?.source === 'cli'
|
||||
const sessionProvider = activeSession.value?.provider || appStore.selectedProvider
|
||||
const runPayload = {
|
||||
input,
|
||||
session_id: sid,
|
||||
model: sessionModel || undefined,
|
||||
model: isBridgeSource ? undefined : sessionModel || undefined,
|
||||
provider: isBridgeSource ? undefined : sessionProvider || undefined,
|
||||
model_groups: appStore.modelGroups.map(group => ({
|
||||
provider: group.provider,
|
||||
models: group.models,
|
||||
})),
|
||||
queue_id: userMsg.id,
|
||||
source: (activeSession.value?.source === 'cli' ? 'cli' : 'api_server') as 'cli' | 'api_server',
|
||||
source: (isBridgeSource ? 'cli' : 'api_server') as 'cli' | 'api_server',
|
||||
}
|
||||
|
||||
if (shouldQueue) {
|
||||
|
||||
@@ -52,21 +52,17 @@ export const useModelsStore = defineStore('models', () => {
|
||||
await systemApi.updateDefaultModel({ default: modelId, provider })
|
||||
defaultModel.value = modelId
|
||||
const appStore = useAppStore()
|
||||
appStore.loadModels()
|
||||
appStore.reloadModels()
|
||||
}
|
||||
|
||||
async function addProvider(data: CustomProvider) {
|
||||
await systemApi.addCustomProvider(data)
|
||||
await fetchProviders()
|
||||
const appStore = useAppStore()
|
||||
appStore.loadModels()
|
||||
}
|
||||
|
||||
async function removeProvider(name: string) {
|
||||
await systemApi.removeCustomProvider(name)
|
||||
await fetchProviders()
|
||||
const appStore = useAppStore()
|
||||
appStore.loadModels()
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user