UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

175 lines (174 loc) • 7.25 kB
import { l as normalizeOptionalString } from "./string-coerce-1VuiLaaR.mjs"; import { c as resolveSessionStorePathCore } from "./paths-Bonddxfk.mjs"; import { r as normalizeProviderId } from "./provider-id-D1VImdKk.mjs"; import { n as DEFAULT_MODEL, r as DEFAULT_PROVIDER } from "./defaults-Jag53zwP.mjs"; import { r as resolveCollapsedSessionAuthPinSource } from "./auth-profile-override-provenance-Jztnei-C.mjs"; import { h as resolveSessionAgentId } from "./agent-scope-bJOokm5r.mjs"; import { t as resolveDefaultModelForAgent } from "./model-selection-config-BC0CegJ7.mjs"; import { i as resolveSessionRuntimeOverrideForProvider } from "./session-runtime-compat-ro9WhJ4w.mjs"; import { o as normalizeStoredOverrideModel, r as resolvePersistedSelectedModelRef } from "./model-selection-Cpoq0B2R.mjs"; import { c as patchSessionEntryCore } from "./session-accessor.sqlite-entry-DLa7_9ui.mjs"; import "./session-accessor-C3ljJ974.mjs"; import { i as readSessionEntryReadOnlyInWorker } from "./session-entry-read-runtime-BdnQjoL6.mjs"; //#region src/agents/live-model-switch.ts /** * Resolves and persists live-session model switch requests. */ /** * Entry-snapshot variant of the selection resolver, so atomic patch callbacks * can evaluate the persisted selection against the exact row they may rewrite. */ function resolveSelectionFromSessionEntry(params) { const { cfg, entry } = params; const agentId = normalizeOptionalString(params.agentId); const defaultModelRef = agentId ? resolveDefaultModelForAgent({ cfg, agentId }) : { provider: params.defaultProvider, model: params.defaultModel }; const normalizedSelection = normalizeStoredOverrideModel({ providerOverride: entry?.providerOverride, modelOverride: entry?.modelOverride }); const persisted = resolvePersistedSelectedModelRef({ defaultProvider: defaultModelRef.provider, runtimeProvider: entry?.modelProvider, runtimeModel: entry?.model, overrideProvider: normalizedSelection.providerOverride, overrideModel: normalizedSelection.modelOverride }); const provider = persisted?.provider ?? normalizedSelection.providerOverride ?? entry?.providerOverride?.trim() ?? defaultModelRef.provider; const model = persisted?.model ?? defaultModelRef.model; const agentRuntimeOverride = resolveSessionRuntimeOverrideForProvider({ provider, entry, cfg }); const authProfileId = normalizeOptionalString(entry?.authProfileOverride); return { provider, model, ...agentRuntimeOverride ? { agentRuntimeOverride } : {}, authProfileId, authProfileIdSource: authProfileId ? resolveCollapsedSessionAuthPinSource(entry) : void 0 }; } function isAlreadyAppliedOpenAICodexRuntimePromotion(current, next) { return normalizeProviderId(current.provider) === "openai" && normalizeProviderId(next.provider) === "openai" && current.model === next.model; } function hasDifferentLiveSessionModelSelection(current, next) { return (current.provider !== next.provider || current.model !== next.model) && !isAlreadyAppliedOpenAICodexRuntimePromotion(current, next) || normalizeOptionalString(current.agentRuntimeOverride) !== next.agentRuntimeOverride || normalizeOptionalString(current.authProfileId) !== next.authProfileId || (normalizeOptionalString(current.authProfileId) ? current.authProfileIdSource : void 0) !== next.authProfileIdSource; } /** * Return a pending user selection and eagerly clear switches already applied. * The runner consumes an unapplied switch only when canRestartForLiveSwitch * permits it; otherwise the flag survives tool execution and later user turns. */ async function shouldSwitchToLiveModel(params) { const sessionKey = params.sessionKey?.trim(); const cfg = params.cfg; if (!cfg || !sessionKey || params.sessionPersistence === "detached") return; const storePath = resolveSessionStorePathCore(cfg.session?.store, { agentId: params.agentId?.trim() }); const entry = await readSessionEntryReadOnlyInWorker({ storePath, sessionKey, hydrateSkillPromptRefs: false, clone: false, readConsistency: "latest" }); if (!entry?.liveModelSwitchPending) return; const persisted = resolveSelectionFromSessionEntry({ cfg, entry, agentId: params.agentId, defaultProvider: params.defaultProvider, defaultModel: params.defaultModel }); if (!hasDifferentLiveSessionModelSelection({ provider: params.currentProvider, model: params.currentModel, agentRuntimeOverride: params.currentAgentRuntimeOverride, authProfileId: params.currentAuthProfileId, authProfileIdSource: params.currentAuthProfileIdSource }, persisted)) { clearLiveModelSwitchPending({ cfg, sessionKey, agentId: params.agentId, defaultProvider: params.defaultProvider, defaultModel: params.defaultModel, expectedSelection: persisted }).catch(() => {}); return; } return persisted; } /** * Completed runs, including CLI harness runs, consume their applied switch * regardless of runtime/auth drift. Compare and clear atomically so a concurrent * /model request cannot lose its newer selection. */ async function consolidateLiveModelSwitchAfterRun(params) { const sessionKey = normalizeOptionalString(params.sessionKey); const cfg = params.cfg; const providerUsed = normalizeOptionalString(params.providerUsed); const modelUsed = normalizeOptionalString(params.modelUsed); if (!cfg || !sessionKey || !providerUsed || !modelUsed) return; const agentId = resolveSessionAgentId({ sessionKey, config: cfg, agentId: params.agentId }); const storePath = resolveSessionStorePathCore(cfg.session?.store, { agentId }); if (params.usageCommit?.storePath === storePath && params.usageCommit.sessionKey === sessionKey && !params.usageCommit.entry.liveModelSwitchPending) return; await clearMatchingLiveModelSwitch({ cfg, sessionKey, storePath, agentId, defaultProvider: DEFAULT_PROVIDER, defaultModel: DEFAULT_MODEL }, (persisted) => providerUsed === persisted.provider && modelUsed === persisted.model || isAlreadyAppliedOpenAICodexRuntimePromotion({ provider: providerUsed, model: modelUsed }, persisted)); } /** * Consume only the observed selection; a newer request may commit while this clear queues. */ async function clearLiveModelSwitchPending(params) { const sessionKey = params.sessionKey?.trim(); const cfg = params.cfg; if (!cfg || !sessionKey) return; const agentId = params.agentId?.trim(); const storePath = resolveSessionStorePathCore(cfg.session?.store, { agentId }); await clearMatchingLiveModelSwitch({ ...params, cfg, sessionKey, storePath, agentId }, (persisted) => !hasDifferentLiveSessionModelSelection(params.expectedSelection, persisted)); } async function clearMatchingLiveModelSwitch(params, matches) { await patchSessionEntryCore({ storePath: params.storePath, sessionKey: params.sessionKey }, (entry) => { if (!entry.liveModelSwitchPending || !matches(resolveSelectionFromSessionEntry({ ...params, entry }))) return null; const next = { ...entry }; delete next.liveModelSwitchPending; return next; }, { replaceEntry: true, workerGuard: {}, prepareIf: { kind: "live-model-switch-pending" } }); } //#endregion export { consolidateLiveModelSwitchAfterRun as n, shouldSwitchToLiveModel as r, clearLiveModelSwitchPending as t };