From 6ac482ca63c6e0d289cd64f3e3a3be8d79826666 Mon Sep 17 00:00:00 2001 From: Shakker Date: Sun, 12 Apr 2026 05:27:03 +0100 Subject: [PATCH] fix: allow bedrock signed thinking replay under anthropic policy --- src/agents/transcript-policy.test.ts | 32 +++++++++++++++++++++++----- src/agents/transcript-policy.ts | 13 ++++++----- 2 files changed, 35 insertions(+), 10 deletions(-) diff --git a/src/agents/transcript-policy.test.ts b/src/agents/transcript-policy.test.ts index 8ad1509771e..32fedb9adc5 100644 --- a/src/agents/transcript-policy.test.ts +++ b/src/agents/transcript-policy.test.ts @@ -4,6 +4,9 @@ vi.mock("../plugins/provider-runtime.js", async () => { const actual = await vi.importActual( "../plugins/provider-runtime.js", ); + const replayHelpers = await vi.importActual< + typeof import("../plugins/provider-replay-helpers.js") + >("../plugins/provider-replay-helpers.js"); return { ...actual, resolveProviderRuntimePlugin: vi.fn(({ provider }: { provider?: string }) => { @@ -51,7 +54,10 @@ vi.mock("../plugins/provider-runtime.js", async () => { repairToolUseResultPairing: true, validateAnthropicTurns: true, allowSyntheticToolResults: true, - ...(modelId.includes("claude") ? { dropThinkingBlocks: true } : {}), + ...(modelId.includes("claude") && + !replayHelpers.shouldPreserveThinkingBlocks(modelId) + ? { dropThinkingBlocks: true } + : {}), }; case "minimax": case "minimax-portal": @@ -71,7 +77,10 @@ vi.mock("../plugins/provider-runtime.js", async () => { repairToolUseResultPairing: true, validateAnthropicTurns: true, allowSyntheticToolResults: true, - ...(modelId.includes("claude") ? { dropThinkingBlocks: true } : {}), + ...(modelId.includes("claude") && + !replayHelpers.shouldPreserveThinkingBlocks(modelId) + ? { dropThinkingBlocks: true } + : {}), }; case "moonshot": case "ollama": @@ -182,9 +191,8 @@ let shouldAllowProviderOwnedThinkingReplay: typeof import("./transcript-policy.j describe("resolveTranscriptPolicy", () => { beforeAll(async () => { - ({ resolveTranscriptPolicy, shouldAllowProviderOwnedThinkingReplay } = await import( - "./transcript-policy.js" - )); + ({ resolveTranscriptPolicy, shouldAllowProviderOwnedThinkingReplay } = + await import("./transcript-policy.js")); }); beforeEach(() => { @@ -421,6 +429,20 @@ describe("resolveTranscriptPolicy", () => { ).toBe(true); }); + it("allows immutable provider-owned thinking replay for bedrock claude replay policies", () => { + const policy = resolveTranscriptPolicy({ + provider: "amazon-bedrock", + modelId: "us.anthropic.claude-opus-4-6-v1", + modelApi: "bedrock-converse-stream", + }); + expect( + shouldAllowProviderOwnedThinkingReplay({ + modelApi: "bedrock-converse-stream", + policy, + }), + ).toBe(true); + }); + it("does not allow immutable provider-owned thinking replay for strict openai-compatible replay", () => { const policy = resolveTranscriptPolicy({ provider: "vllm", diff --git a/src/agents/transcript-policy.ts b/src/agents/transcript-policy.ts index 3185c8823e9..00c1411fb16 100644 --- a/src/agents/transcript-policy.ts +++ b/src/agents/transcript-policy.ts @@ -31,13 +31,16 @@ export type TranscriptPolicy = { export function shouldAllowProviderOwnedThinkingReplay(params: { modelApi?: string | null; - policy: Pick; + policy: Pick< + TranscriptPolicy, + "validateAnthropicTurns" | "preserveSignatures" | "dropThinkingBlocks" + >; }): boolean { return ( - params.modelApi === "anthropic-messages" && - params.policy.validateAnthropicTurns === true && - params.policy.preserveSignatures === true && - params.policy.dropThinkingBlocks !== true + isAnthropicApi(params.modelApi) && + params.policy.validateAnthropicTurns && + params.policy.preserveSignatures && + !params.policy.dropThinkingBlocks ); }