
























@@ -15,11 +15,15 @@ const state = vi.hoisted(() => ({
1515registerAgentRunContextMock: vi.fn(),
1616clearAgentRunContextMock: vi.fn(),
1717updateSessionStoreAfterAgentRunMock: vi.fn(),
18+updateSessionStoreFileMock: vi.fn(),
1819deliverAgentCommandResultMock: vi.fn(),
1920clearSessionAuthProfileOverrideMock: vi.fn(),
21+applyModelOverrideToSessionEntryMock: vi.fn((..._args: unknown[]) => ({ updated: false })),
2022authProfileStoreMock: { profiles: {} } as { profiles: Record<string, unknown> },
2123sessionEntryMock: undefined as unknown,
2224sessionStoreMock: undefined as unknown,
25+sessionStorePathMock: undefined as string | undefined,
26+persistedSessionStoreMock: undefined as Record<string, unknown> | undefined,
2327}));
24282529vi.mock("./model-fallback.js", () => ({
@@ -73,7 +77,7 @@ vi.mock("./command/session.js", () => ({
7377skillsSnapshot: { prompt: "", skills: [], version: 0 },
7478},
7579sessionStore: state.sessionStoreMock,
76-storePath: undefined,
80+storePath: state.sessionStorePathMock,
7781isNewSession: false,
7882persistedThinking: undefined,
7983persistedVerbose: undefined,
@@ -177,6 +181,10 @@ vi.mock("../config/sessions.js", () => ({
177181),
178182}));
179183184+vi.mock("../config/sessions/store.js", () => ({
185+updateSessionStore: (...args: unknown[]) => state.updateSessionStoreFileMock(...args),
186+}));
187+180188vi.mock("../config/sessions/transcript-resolve.runtime.js", () => ({
181189resolveSessionTranscriptFile: async () => ({
182190sessionFile: "/tmp/session.jsonl",
@@ -231,7 +239,8 @@ vi.mock("../sessions/level-overrides.js", () => ({
231239}));
232240233241vi.mock("../sessions/model-overrides.js", () => ({
234-applyModelOverrideToSessionEntry: () => ({ updated: false }),
242+applyModelOverrideToSessionEntry: (...args: unknown[]) =>
243+state.applyModelOverrideToSessionEntryMock(...args),
235244}));
236245237246vi.mock("../sessions/send-policy.js", () => ({
@@ -400,6 +409,38 @@ function expectFallbackOverrideCalls(first: boolean, second: boolean) {
400409});
401410}
402411412+function useRealisticDefaultModelOverrideReset() {
413+state.applyModelOverrideToSessionEntryMock.mockImplementation((params: unknown) => {
414+const { entry, selection } = params as {
415+entry: {
416+providerOverride?: string;
417+modelOverride?: string;
418+modelOverrideSource?: string;
419+authProfileOverride?: string;
420+authProfileOverrideSource?: string;
421+};
422+selection: { isDefault?: boolean };
423+};
424+if (!selection.isDefault) {
425+return { updated: false };
426+}
427+const before = { ...entry };
428+delete entry.providerOverride;
429+delete entry.modelOverride;
430+delete entry.modelOverrideSource;
431+delete entry.authProfileOverride;
432+delete entry.authProfileOverrideSource;
433+return {
434+updated:
435+before.providerOverride !== entry.providerOverride ||
436+before.modelOverride !== entry.modelOverride ||
437+before.modelOverrideSource !== entry.modelOverrideSource ||
438+before.authProfileOverride !== entry.authProfileOverride ||
439+before.authProfileOverrideSource !== entry.authProfileOverrideSource,
440+};
441+});
442+}
443+403444describe("agentCommand – LiveSessionModelSwitchError retry", () => {
404445beforeEach(() => {
405446vi.clearAllMocks();
@@ -430,6 +471,13 @@ describe("agentCommand – LiveSessionModelSwitchError retry", () => {
430471state.authProfileStoreMock = { profiles: {} };
431472state.sessionEntryMock = undefined;
432473state.sessionStoreMock = undefined;
474+state.sessionStorePathMock = undefined;
475+state.persistedSessionStoreMock = undefined;
476+state.applyModelOverrideToSessionEntryMock.mockReturnValue({ updated: false });
477+state.updateSessionStoreFileMock.mockImplementation(
478+async (_path: string, fn: (store: Record<string, unknown>) => unknown) =>
479+fn(state.persistedSessionStoreMock ?? {}),
480+);
433481state.deliverAgentCommandResultMock.mockResolvedValue(undefined);
434482state.updateSessionStoreAfterAgentRunMock.mockResolvedValue(undefined);
435483});
@@ -642,4 +690,64 @@ describe("agentCommand – LiveSessionModelSwitchError retry", () => {
642690643691expectFallbackOverrideCalls(false, true);
644692});
693+694+it("clears auto-fallback model overrides before the next command retries primary", async () => {
695+useRealisticDefaultModelOverrideReset();
696+697+const sessionEntry = {
698+sessionId: "session-1",
699+updatedAt: Date.now(),
700+providerOverride: "openai",
701+modelOverride: "gpt-5.4",
702+modelOverrideSource: "auto",
703+authProfileOverride: "openai:default",
704+authProfileOverrideSource: "auto",
705+skillsSnapshot: { prompt: "", skills: [], version: 0 },
706+};
707+state.sessionEntryMock = sessionEntry;
708+state.sessionStoreMock = { "agent:main": sessionEntry };
709+state.sessionStorePathMock = "/tmp/sessions.json";
710+state.persistedSessionStoreMock = { "agent:main": { ...sessionEntry } };
711+state.runWithModelFallbackMock.mockImplementation(async (params: FallbackRunnerParams) => {
712+const result = await params.run(params.provider, params.model);
713+return {
714+ result,
715+provider: params.provider,
716+model: params.model,
717+attempts: [],
718+};
719+});
720+state.runAgentAttemptMock.mockResolvedValue(makeSuccessResult("anthropic", "claude"));
721+722+await agentCommand({
723+message: "hello",
724+sessionKey: "agent:main",
725+senderIsOwner: true,
726+});
727+728+const fallbackParams = state.runWithModelFallbackMock.mock.calls[0]?.[0] as
729+| FallbackRunnerParams
730+| undefined;
731+expect(fallbackParams).toMatchObject({
732+provider: "anthropic",
733+model: "claude",
734+});
735+expect(state.resolveEffectiveModelFallbacksMock).toHaveBeenCalledWith(
736+expect.objectContaining({ hasSessionModelOverride: false }),
737+);
738+const activeStore = state.sessionStoreMock as Record<string, typeof sessionEntry>;
739+const persistedStore = state.persistedSessionStoreMock as Record<string, typeof sessionEntry>;
740+expect(activeStore["agent:main"]).toMatchObject({
741+sessionId: "session-1",
742+});
743+expect(activeStore["agent:main"].providerOverride).toBeUndefined();
744+expect(activeStore["agent:main"].modelOverride).toBeUndefined();
745+expect(activeStore["agent:main"].modelOverrideSource).toBeUndefined();
746+expect(persistedStore["agent:main"]).toMatchObject({
747+sessionId: "session-1",
748+});
749+expect(persistedStore["agent:main"].providerOverride).toBeUndefined();
750+expect(persistedStore["agent:main"].modelOverride).toBeUndefined();
751+expect(persistedStore["agent:main"].modelOverrideSource).toBeUndefined();
752+});
645753});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。