mirror of https://github.com/openclaw/openclaw.git
104 lines
3.2 KiB
TypeScript
104 lines
3.2 KiB
TypeScript
import { loadSessionStore, resolveStorePath, type SessionEntry } from "../config/sessions.js";
|
|
import { resolveDefaultModelForAgent } from "./model-selection.js";
|
|
import {
|
|
consumeEmbeddedRunModelSwitch,
|
|
requestEmbeddedRunModelSwitch,
|
|
type EmbeddedRunModelSwitchRequest,
|
|
} from "./pi-embedded-runner/runs.js";
|
|
import { abortEmbeddedPiRun } from "./pi-embedded.js";
|
|
|
|
export type LiveSessionModelSelection = EmbeddedRunModelSwitchRequest;
|
|
|
|
export class LiveSessionModelSwitchError extends Error {
|
|
provider: string;
|
|
model: string;
|
|
authProfileId?: string;
|
|
authProfileIdSource?: "auto" | "user";
|
|
|
|
constructor(selection: LiveSessionModelSelection) {
|
|
super(`Live session model switch requested: ${selection.provider}/${selection.model}`);
|
|
this.name = "LiveSessionModelSwitchError";
|
|
this.provider = selection.provider;
|
|
this.model = selection.model;
|
|
this.authProfileId = selection.authProfileId;
|
|
this.authProfileIdSource = selection.authProfileIdSource;
|
|
}
|
|
}
|
|
|
|
export function resolveLiveSessionModelSelection(params: {
|
|
cfg?: { session?: { store?: string } } | undefined;
|
|
sessionKey?: string;
|
|
agentId?: string;
|
|
defaultProvider: string;
|
|
defaultModel: string;
|
|
}): LiveSessionModelSelection | null {
|
|
const sessionKey = params.sessionKey?.trim();
|
|
const cfg = params.cfg;
|
|
if (!cfg || !sessionKey) {
|
|
return null;
|
|
}
|
|
const agentId = params.agentId?.trim();
|
|
const defaultModelRef = agentId
|
|
? resolveDefaultModelForAgent({
|
|
cfg,
|
|
agentId,
|
|
})
|
|
: { provider: params.defaultProvider, model: params.defaultModel };
|
|
const storePath = resolveStorePath(cfg.session?.store, {
|
|
agentId,
|
|
});
|
|
const entry = loadSessionStore(storePath, { skipCache: true })[sessionKey];
|
|
const provider = entry?.providerOverride?.trim() || defaultModelRef.provider;
|
|
const model = entry?.modelOverride?.trim() || defaultModelRef.model;
|
|
const authProfileId = entry?.authProfileOverride?.trim() || undefined;
|
|
return {
|
|
provider,
|
|
model,
|
|
authProfileId,
|
|
authProfileIdSource: authProfileId ? entry?.authProfileOverrideSource : undefined,
|
|
};
|
|
}
|
|
|
|
export function requestLiveSessionModelSwitch(params: {
|
|
sessionEntry?: Pick<SessionEntry, "sessionId">;
|
|
selection: LiveSessionModelSelection;
|
|
}): boolean {
|
|
const sessionId = params.sessionEntry?.sessionId?.trim();
|
|
if (!sessionId) {
|
|
return false;
|
|
}
|
|
const aborted = abortEmbeddedPiRun(sessionId);
|
|
if (!aborted) {
|
|
return false;
|
|
}
|
|
requestEmbeddedRunModelSwitch(sessionId, params.selection);
|
|
return true;
|
|
}
|
|
|
|
export function consumeLiveSessionModelSwitch(
|
|
sessionId: string,
|
|
): LiveSessionModelSelection | undefined {
|
|
return consumeEmbeddedRunModelSwitch(sessionId);
|
|
}
|
|
|
|
export function hasDifferentLiveSessionModelSelection(
|
|
current: {
|
|
provider: string;
|
|
model: string;
|
|
authProfileId?: string;
|
|
authProfileIdSource?: string;
|
|
},
|
|
next: LiveSessionModelSelection | null | undefined,
|
|
): next is LiveSessionModelSelection {
|
|
if (!next) {
|
|
return false;
|
|
}
|
|
return (
|
|
current.provider !== next.provider ||
|
|
current.model !== next.model ||
|
|
(current.authProfileId?.trim() || undefined) !== next.authProfileId ||
|
|
(current.authProfileId?.trim() ? current.authProfileIdSource : undefined) !==
|
|
next.authProfileIdSource
|
|
);
|
|
}
|