mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-01 12:21:25 +00:00
130 lines
4.2 KiB
TypeScript
130 lines
4.2 KiB
TypeScript
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
import { importFreshModule } from "../../test/helpers/import-fresh.js";
|
|
|
|
const state = vi.hoisted(() => ({
|
|
abortEmbeddedPiRunMock: vi.fn(),
|
|
requestEmbeddedRunModelSwitchMock: vi.fn(),
|
|
consumeEmbeddedRunModelSwitchMock: vi.fn(),
|
|
resolveDefaultModelForAgentMock: vi.fn(),
|
|
loadSessionStoreMock: vi.fn(),
|
|
resolveStorePathMock: vi.fn(),
|
|
}));
|
|
|
|
vi.mock("./pi-embedded.js", () => ({
|
|
abortEmbeddedPiRun: (...args: unknown[]) => state.abortEmbeddedPiRunMock(...args),
|
|
}));
|
|
|
|
vi.mock("./pi-embedded-runner/runs.js", () => ({
|
|
requestEmbeddedRunModelSwitch: (...args: unknown[]) =>
|
|
state.requestEmbeddedRunModelSwitchMock(...args),
|
|
consumeEmbeddedRunModelSwitch: (...args: unknown[]) =>
|
|
state.consumeEmbeddedRunModelSwitchMock(...args),
|
|
}));
|
|
|
|
vi.mock("./model-selection.js", () => ({
|
|
resolveDefaultModelForAgent: (...args: unknown[]) =>
|
|
state.resolveDefaultModelForAgentMock(...args),
|
|
}));
|
|
|
|
vi.mock("../config/sessions.js", () => ({
|
|
loadSessionStore: (...args: unknown[]) => state.loadSessionStoreMock(...args),
|
|
resolveStorePath: (...args: unknown[]) => state.resolveStorePathMock(...args),
|
|
}));
|
|
|
|
async function loadModule() {
|
|
return await importFreshModule<typeof import("./live-model-switch.js")>(
|
|
import.meta.url,
|
|
`./live-model-switch.js?scope=${Math.random().toString(36).slice(2)}`,
|
|
);
|
|
}
|
|
|
|
describe("live model switch", () => {
|
|
beforeEach(() => {
|
|
vi.resetModules();
|
|
state.abortEmbeddedPiRunMock.mockReset().mockReturnValue(false);
|
|
state.requestEmbeddedRunModelSwitchMock.mockReset();
|
|
state.consumeEmbeddedRunModelSwitchMock.mockReset();
|
|
state.resolveDefaultModelForAgentMock
|
|
.mockReset()
|
|
.mockReturnValue({ provider: "anthropic", model: "claude-opus-4-6" });
|
|
state.loadSessionStoreMock.mockReset().mockReturnValue({});
|
|
state.resolveStorePathMock.mockReset().mockReturnValue("/tmp/session-store.json");
|
|
});
|
|
|
|
afterEach(() => {
|
|
vi.clearAllMocks();
|
|
});
|
|
|
|
it("resolves persisted session overrides ahead of agent defaults", async () => {
|
|
state.loadSessionStoreMock.mockReturnValue({
|
|
main: {
|
|
providerOverride: "openai",
|
|
modelOverride: "gpt-5.4",
|
|
authProfileOverride: "profile-gpt",
|
|
authProfileOverrideSource: "user",
|
|
},
|
|
});
|
|
|
|
const { resolveLiveSessionModelSelection } = await loadModule();
|
|
|
|
expect(
|
|
resolveLiveSessionModelSelection({
|
|
cfg: { session: { store: "/tmp/custom-store.json" } },
|
|
sessionKey: "main",
|
|
agentId: "reply",
|
|
defaultProvider: "anthropic",
|
|
defaultModel: "claude-opus-4-6",
|
|
}),
|
|
).toEqual({
|
|
provider: "openai",
|
|
model: "gpt-5.4",
|
|
authProfileId: "profile-gpt",
|
|
authProfileIdSource: "user",
|
|
});
|
|
expect(state.resolveDefaultModelForAgentMock).toHaveBeenCalledWith({
|
|
cfg: { session: { store: "/tmp/custom-store.json" } },
|
|
agentId: "reply",
|
|
});
|
|
expect(state.resolveStorePathMock).toHaveBeenCalledWith("/tmp/custom-store.json", {
|
|
agentId: "reply",
|
|
});
|
|
});
|
|
|
|
it("queues a live switch only when an active run was aborted", async () => {
|
|
state.abortEmbeddedPiRunMock.mockReturnValue(true);
|
|
|
|
const { requestLiveSessionModelSwitch } = await loadModule();
|
|
|
|
expect(
|
|
requestLiveSessionModelSwitch({
|
|
sessionEntry: { sessionId: "session-1" },
|
|
selection: { provider: "openai", model: "gpt-5.4", authProfileId: "profile-gpt" },
|
|
}),
|
|
).toBe(true);
|
|
expect(state.abortEmbeddedPiRunMock).toHaveBeenCalledWith("session-1");
|
|
expect(state.requestEmbeddedRunModelSwitchMock).toHaveBeenCalledWith("session-1", {
|
|
provider: "openai",
|
|
model: "gpt-5.4",
|
|
authProfileId: "profile-gpt",
|
|
});
|
|
});
|
|
|
|
it("treats auth-profile-source changes as no-op when no auth profile is selected", async () => {
|
|
const { hasDifferentLiveSessionModelSelection } = await loadModule();
|
|
|
|
expect(
|
|
hasDifferentLiveSessionModelSelection(
|
|
{
|
|
provider: "openai",
|
|
model: "gpt-5.4",
|
|
authProfileIdSource: "auto",
|
|
},
|
|
{
|
|
provider: "openai",
|
|
model: "gpt-5.4",
|
|
},
|
|
),
|
|
).toBe(false);
|
|
});
|
|
});
|