From 3d6028da4cf615eb0253d3edf4b44b3510252d8f Mon Sep 17 00:00:00 2001 From: joshavant <830519+joshavant@users.noreply.github.com> Date: Mon, 10 Aug 2026 19:59:32 -0500 Subject: [PATCH] test(auto-reply): prove prepared ownership through queue params --- .../run.overflow-compaction.harness.ts | 10 ++- .../agent-runner-execution.test-support.ts | 83 ++++++++++--------- ...arness-source-delivery.integration.test.ts | 14 +++- 3 files changed, 64 insertions(+), 43 deletions(-) diff --git a/src/agents/embedded-agent-runner/run.overflow-compaction.harness.ts b/src/agents/embedded-agent-runner/run.overflow-compaction.harness.ts index b379548caf69..be31d586abf4 100644 --- a/src/agents/embedded-agent-runner/run.overflow-compaction.harness.ts +++ b/src/agents/embedded-agent-runner/run.overflow-compaction.harness.ts @@ -802,6 +802,7 @@ export async function loadRunOverflowCompactionHarness(): Promise<{ prepareProviderRuntimeAuth: mockedPrepareProviderRuntimeAuth, resolveProviderCapabilitiesWithPlugin: vi.fn(() => ({})), resolveProviderAuthProfileId: vi.fn(() => undefined), + resolveProviderReasoningOutputModeWithPlugin: vi.fn(() => undefined), shouldPreferProviderRuntimeResolvedModel: vi.fn(() => false), prepareProviderExtraParams: vi.fn(async () => ({})), wrapProviderStreamFn: vi.fn((_cfg: unknown, _model: unknown, fn: unknown) => fn), @@ -950,7 +951,10 @@ export async function loadRunOverflowCompactionHarness(): Promise<{ redactRunIdentifier: vi.fn((value?: string) => value ?? ""), })); - vi.doMock("../embedded-agent-helpers.js", () => ({ + vi.doMock("../embedded-agent-helpers.js", async () => ({ + ...(await vi.importActual( + "../embedded-agent-helpers.js", + )), formatBillingErrorMessage: mockedFormatBillingErrorMessage, classifyFailoverReason: mockedClassifyFailoverReason, classifyAssistantFailoverReason: mockedClassifyAssistantFailoverReason, @@ -1058,10 +1062,12 @@ export async function loadRunOverflowCompactionHarness(): Promise<{ DEFAULT_PROVIDER: "anthropic", })); - vi.doMock("../failover-error.js", () => ({ + vi.doMock("../failover-error.js", async () => ({ + ...(await vi.importActual("../failover-error.js")), FailoverError: MockedFailoverError, coerceToFailoverError: mockedCoerceToFailoverError, describeFailoverError: mockedDescribeFailoverError, + isFailoverError: (error: unknown) => error instanceof MockedFailoverError, resolveFailoverStatus: mockedResolveFailoverStatus, })); diff --git a/src/auto-reply/reply/agent-runner-execution.test-support.ts b/src/auto-reply/reply/agent-runner-execution.test-support.ts index cf5da0be3700..8abe2a0a7382 100644 --- a/src/auto-reply/reply/agent-runner-execution.test-support.ts +++ b/src/auto-reply/reply/agent-runner-execution.test-support.ts @@ -13,6 +13,7 @@ import { import { createTestUserTurnTranscriptTarget } from "../../sessions/user-turn-transcript.test-support.js"; import type { TemplateContext } from "../templating.js"; import type { GetReplyOptions, ReplyPayload } from "../types.js"; +import type { buildEmbeddedRunExecutionParams } from "./agent-runner-utils.js"; import type { FollowupRun } from "./queue.js"; import type { ReplyOperation } from "./reply-run-registry.js"; import type { TypingSignaler } from "./typing-mode.js"; @@ -61,6 +62,9 @@ const state = vi.hoisted(() => ({ updateSessionStoreMock: vi.fn(), resolveCurrentTurnImagesMock: vi.fn(), peekSessionMcpRuntimeMock: vi.fn(), + productionBuildEmbeddedRunExecutionParams: undefined as + | typeof buildEmbeddedRunExecutionParams + | undefined, })); export const GENERIC_RUN_FAILURE_TEXT = @@ -245,46 +249,38 @@ vi.mock("./current-turn-images.js", () => ({ })); vi.mock("./agent-runner-utils.js", () => ({ - buildEmbeddedRunExecutionParams: (params: { - provider: string; - model: string; - run: Record & { - provider?: string; - thinkLevel?: string; - authProfileId?: string; - authProfileIdSource?: "auto" | "user"; - agentAccountId?: string; - chatType?: string; - }; - replyRoute?: { - originatingChannel?: string; - originatingTo?: string; - originatingAccountId?: string; - originatingChatType?: string; - }; - sessionCtx: { AccountId?: string; ChatType?: string }; - }) => ({ - embeddedContext: { - ...params.run, - messageProvider: params.replyRoute?.originatingChannel, - messageTo: params.replyRoute?.originatingTo, - agentAccountId: - params.replyRoute?.originatingAccountId ?? - params.sessionCtx.AccountId ?? - params.run.agentAccountId, - chatType: - params.replyRoute?.originatingChatType ?? params.sessionCtx.ChatType ?? params.run.chatType, - }, - senderContext: {}, - runBaseParams: { - provider: params.provider, - model: params.model, - thinkLevel: params.run.thinkLevel, - authProfileId: params.provider === params.run.provider ? params.run.authProfileId : undefined, - authProfileIdSource: - params.provider === params.run.provider ? params.run.authProfileIdSource : undefined, - }, - }), + buildEmbeddedRunExecutionParams: ( + params: Parameters[0], + ) => + // Most execution tests isolate fallback policy from config/channel discovery. Ownership + // regressions opt into the production builder so queue metadata must cross the real boundary. + state.productionBuildEmbeddedRunExecutionParams + ? state.productionBuildEmbeddedRunExecutionParams(params) + : { + embeddedContext: { + ...params.run, + messageProvider: params.replyRoute?.originatingChannel, + messageTo: params.replyRoute?.originatingTo, + agentAccountId: + params.replyRoute?.originatingAccountId ?? + params.sessionCtx.AccountId ?? + params.run.agentAccountId, + chatType: + params.replyRoute?.originatingChatType ?? + params.sessionCtx.ChatType ?? + params.run.chatType, + }, + senderContext: {}, + runBaseParams: { + provider: params.provider, + model: params.model, + thinkLevel: params.run.thinkLevel, + authProfileId: + params.provider === params.run.provider ? params.run.authProfileId : undefined, + authProfileIdSource: + params.provider === params.run.provider ? params.run.authProfileIdSource : undefined, + }, + }, resolveQueuedReplyRuntimeConfig: (config: T) => config, resolveModelFallbackOptions: vi.fn( (run: { provider?: string; model?: string; config?: unknown; agentDir?: string }) => ({ @@ -342,6 +338,12 @@ export async function getExecuteAgentTurnForTest() { }; } +export async function useProductionEmbeddedRunExecutionParamsForTest(): Promise { + const actual = + await vi.importActual("./agent-runner-utils.js"); + state.productionBuildEmbeddedRunExecutionParams = actual.buildEmbeddedRunExecutionParams; +} + export async function loadActualRunCliAgentForTest(): Promise { return ( await vi.importActual("../../agents/cli-runner.js") @@ -689,6 +691,7 @@ export function setupAgentRunnerExecutionTestState() { state.updateSessionStoreMock.mockReset(); state.resolveCurrentTurnImagesMock.mockReset(); state.peekSessionMcpRuntimeMock.mockReset(); + state.productionBuildEmbeddedRunExecutionParams = undefined; state.peekSessionMcpRuntimeMock.mockReturnValue(undefined); state.resolveCurrentTurnImagesMock.mockImplementation( async (params: { images?: unknown[]; imageOrder?: unknown[] }) => ({ diff --git a/src/auto-reply/reply/prepared-harness-source-delivery.integration.test.ts b/src/auto-reply/reply/prepared-harness-source-delivery.integration.test.ts index d2f75050bb41..ea6515573af2 100644 --- a/src/auto-reply/reply/prepared-harness-source-delivery.integration.test.ts +++ b/src/auto-reply/reply/prepared-harness-source-delivery.integration.test.ts @@ -17,6 +17,7 @@ import { getExecuteAgentTurnForTest, setupAgentRunnerExecutionTestState, type FallbackRunnerParams, + useProductionEmbeddedRunExecutionParamsForTest, } from "./agent-runner-execution.test-support.js"; import { emptyConfig, sessionStoreMocks } from "./dispatch-from-config.shared.test-harness.js"; import { @@ -58,7 +59,18 @@ describe("prepared harness source delivery", () => { expectedPartials: 0, expectedFinals: 0, }, + { + name: "keeps prepared tool ownership after a failed CLI primary", + failsCliPrimary: true, + preliminaryVisibleReplies: "automatic" as const, + preparedVisibleReplies: "message_tool" as const, + expectedTransitions: ["message_tool_only", "message_tool_only"], + expectedDeliveries: 0, + expectedPartials: 0, + expectedFinals: 0, + }, ])("$name", async (testCase) => { + await useProductionEmbeddedRunExecutionParamsForTest(); const { runEmbeddedAgent, registerPreparedAgentHarness } = await loadRunOverflowCompactionHarness(); mockedGlobalHookRunner.hasHooks.mockImplementation( @@ -219,7 +231,6 @@ describe("prepared harness source delivery", () => { expect.any(Object), ); expect(emittedStreamingCallbacks).toEqual(["partial", "block"]); - expect(modeTransitions).toEqual(testCase.expectedTransitions); expect(onPartialReply).toHaveBeenCalledTimes(testCase.expectedPartials); expect(result.queuedFinal).toBe(testCase.expectedDeliveries === 1); if (testCase.expectedDeliveries === 1) { @@ -238,5 +249,6 @@ describe("prepared harness source delivery", () => { final: testCase.expectedFinals, }); expect(dispatcher.getFailedCounts()).toEqual({ tool: 0, block: 0, final: 0 }); + expect(modeTransitions).toEqual(testCase.expectedTransitions); }); });