From 2201d533fde7d72ee762d7ed3d72917ccf40440e Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Fri, 13 Mar 2026 03:21:50 +0000 Subject: [PATCH] fix: enable fast mode for isolated cron runs --- src/cron/isolated-agent/run.fast-mode.test.ts | 182 ++++++++++++++++++ src/cron/isolated-agent/run.ts | 7 + 2 files changed, 189 insertions(+) create mode 100644 src/cron/isolated-agent/run.fast-mode.test.ts diff --git a/src/cron/isolated-agent/run.fast-mode.test.ts b/src/cron/isolated-agent/run.fast-mode.test.ts new file mode 100644 index 000000000..471471e9e --- /dev/null +++ b/src/cron/isolated-agent/run.fast-mode.test.ts @@ -0,0 +1,182 @@ +import { describe, expect, it } from "vitest"; +import { + makeIsolatedAgentTurnJob, + makeIsolatedAgentTurnParams, + setupRunCronIsolatedAgentTurnSuite, +} from "./run.suite-helpers.js"; +import { + loadRunCronIsolatedAgentTurn, + makeCronSession, + resolveCronSessionMock, + runEmbeddedPiAgentMock, + runWithModelFallbackMock, +} from "./run.test-harness.js"; + +const runCronIsolatedAgentTurn = await loadRunCronIsolatedAgentTurn(); + +describe("runCronIsolatedAgentTurn — fast mode", () => { + setupRunCronIsolatedAgentTurnSuite(); + + it("passes config-driven fast mode into embedded cron runs", async () => { + const cronSession = makeCronSession(); + resolveCronSessionMock.mockReturnValue(cronSession); + + runWithModelFallbackMock.mockImplementation(async ({ provider, model, run }) => { + await run(provider, model); + return { + result: { + payloads: [{ text: "ok" }], + meta: { agentMeta: { usage: { input: 10, output: 20 } } }, + }, + provider, + model, + attempts: [], + }; + }); + + const result = await runCronIsolatedAgentTurn( + makeIsolatedAgentTurnParams({ + cfg: { + agents: { + defaults: { + models: { + "openai/gpt-4": { + params: { + fastMode: true, + }, + }, + }, + }, + }, + }, + job: makeIsolatedAgentTurnJob({ + payload: { + kind: "agentTurn", + message: "test fast mode", + model: "openai/gpt-4", + }, + }), + }), + ); + + expect(result.status).toBe("ok"); + expect(runEmbeddedPiAgentMock).toHaveBeenCalledOnce(); + expect(runEmbeddedPiAgentMock.mock.calls[0][0]).toMatchObject({ + provider: "openai", + model: "gpt-4", + fastMode: true, + }); + }); + + it("honors session fastMode=false over config fastMode=true", async () => { + const cronSession = makeCronSession({ + sessionEntry: { + ...makeCronSession().sessionEntry, + fastMode: false, + }, + }); + resolveCronSessionMock.mockReturnValue(cronSession); + + runWithModelFallbackMock.mockImplementation(async ({ provider, model, run }) => { + await run(provider, model); + return { + result: { + payloads: [{ text: "ok" }], + meta: { agentMeta: { usage: { input: 10, output: 20 } } }, + }, + provider, + model, + attempts: [], + }; + }); + + const result = await runCronIsolatedAgentTurn( + makeIsolatedAgentTurnParams({ + cfg: { + agents: { + defaults: { + models: { + "openai/gpt-4": { + params: { + fastMode: true, + }, + }, + }, + }, + }, + }, + job: makeIsolatedAgentTurnJob({ + payload: { + kind: "agentTurn", + message: "test fast mode override", + model: "openai/gpt-4", + }, + }), + }), + ); + + expect(result.status).toBe("ok"); + expect(runEmbeddedPiAgentMock).toHaveBeenCalledOnce(); + expect(runEmbeddedPiAgentMock.mock.calls[0][0]).toMatchObject({ + provider: "openai", + model: "gpt-4", + fastMode: false, + }); + }); + + it("honors session fastMode=true over config fastMode=false", async () => { + const cronSession = makeCronSession({ + sessionEntry: { + ...makeCronSession().sessionEntry, + fastMode: true, + }, + }); + resolveCronSessionMock.mockReturnValue(cronSession); + + runWithModelFallbackMock.mockImplementation(async ({ provider, model, run }) => { + await run(provider, model); + return { + result: { + payloads: [{ text: "ok" }], + meta: { agentMeta: { usage: { input: 10, output: 20 } } }, + }, + provider, + model, + attempts: [], + }; + }); + + const result = await runCronIsolatedAgentTurn( + makeIsolatedAgentTurnParams({ + cfg: { + agents: { + defaults: { + models: { + "openai/gpt-4": { + params: { + fastMode: false, + }, + }, + }, + }, + }, + }, + job: makeIsolatedAgentTurnJob({ + payload: { + kind: "agentTurn", + message: "test fast mode session override", + model: "openai/gpt-4", + }, + }), + }), + ); + + expect(result.status).toBe("ok"); + expect(runEmbeddedPiAgentMock).toHaveBeenCalledOnce(); + expect(runEmbeddedPiAgentMock.mock.calls[0][0]).toMatchObject({ + provider: "openai", + model: "gpt-4", + fastMode: true, + }); + }); +}); diff --git a/src/cron/isolated-agent/run.ts b/src/cron/isolated-agent/run.ts index 4c7a5c87f..8a074338d 100644 --- a/src/cron/isolated-agent/run.ts +++ b/src/cron/isolated-agent/run.ts @@ -12,6 +12,7 @@ import { getCliSessionId, setCliSessionId } from "../../agents/cli-session.js"; import { lookupContextTokens } from "../../agents/context.js"; import { resolveCronStyleNow } from "../../agents/current-time.js"; import { DEFAULT_CONTEXT_TOKENS, DEFAULT_MODEL, DEFAULT_PROVIDER } from "../../agents/defaults.js"; +import { resolveFastModeState } from "../../agents/fast-mode.js"; import { resolveNestedAgentLane } from "../../agents/lanes.js"; import { loadModelCatalog } from "../../agents/model-catalog.js"; import { runWithModelFallback } from "../../agents/model-fallback.js"; @@ -617,6 +618,12 @@ export async function runCronIsolatedAgentTurn(params: { authProfileId, authProfileIdSource, thinkLevel, + fastMode: resolveFastModeState({ + cfg: cfgWithAgentDefaults, + provider: providerOverride, + model: modelOverride, + sessionEntry: cronSession.sessionEntry, + }).enabled, verboseLevel: resolvedVerboseLevel, timeoutMs, bootstrapContextMode: agentPayload?.lightContext ? "lightweight" : undefined,