test: cover bedrock signed thinking replay paths

This commit is contained in:
Shakker
2026-04-12 05:27:11 +01:00
committed by Shakker
parent 6ac482ca63
commit 01d092ff89
3 changed files with 82 additions and 0 deletions

View File

@@ -76,6 +76,8 @@ describeLive("pi embedded anthropic replay sanitization (live)", () => {
const wrapped = wrapStreamFnSanitizeMalformedToolCalls(baseFn as never, new Set(["noop"]), {
validateGeminiTurns: false,
validateAnthropicTurns: true,
preserveSignatures: false,
dropThinkingBlocks: false,
});
await Promise.resolve(wrapped(model as never, { messages } as never, {} as never));

View File

@@ -1010,6 +1010,34 @@ describe("sanitizeSessionHistory", () => {
});
});
it("uses immutable thinking replay for amazon-bedrock claude providers when policy preserves signatures", async () => {
setNonGoogleModelApi();
const messages = castAgentMessages([
makeUserMessage("retry"),
makeAssistantMessage([
{
type: "thinking",
thinking: "internal",
thinkingSignature: "sig_1",
},
{ type: "toolCall", id: "call_1", name: " read ", arguments: {} },
] as unknown as AssistantMessage["content"]),
]);
const result = await sanitizeAnthropicHistory({
provider: "amazon-bedrock",
modelApi: "bedrock-converse-stream",
messages,
});
expect(result).toHaveLength(1);
expect(result[0]).toMatchObject({
role: "user",
content: "retry",
});
});
it("keeps mutable thinking turns outside exact anthropic replay", async () => {
setNonGoogleModelApi();

View File

@@ -1006,6 +1006,50 @@ describe("wrapStreamFnSanitizeMalformedToolCalls", () => {
]);
});
it("drops signed thinking turns for bedrock claude replay when sibling tool calls are not replay-safe", async () => {
const messages = [
{
role: "assistant",
content: [
{ type: "thinking", thinking: "internal", thinkingSignature: "sig_1" },
{ type: "toolCall", id: "toolu_legacy", name: "gateway", arguments: {} },
],
},
{
role: "user",
content: [{ type: "text", text: "retry" }],
},
];
const baseFn = vi.fn((_model, _context) =>
createFakeStream({ events: [], resultMessage: { role: "assistant", content: [] } }),
);
const wrapped = wrapStreamFnSanitizeMalformedToolCalls(
baseFn as never,
new Set(["read"]),
{
validateAnthropicTurns: true,
preserveSignatures: true,
dropThinkingBlocks: false,
} as never,
);
const stream = wrapped(
{ api: "bedrock-converse-stream" } as never,
{ messages } as never,
{} as never,
) as FakeWrappedStream | Promise<FakeWrappedStream>;
await Promise.resolve(stream);
expect(baseFn).toHaveBeenCalledTimes(1);
const seenContext = baseFn.mock.calls[0]?.[1] as { messages: unknown[] };
expect(seenContext.messages).toEqual([
{
role: "user",
content: [{ type: "text", text: "retry" }],
},
]);
});
it("drops signed thinking turns when replay would expose inline sessions_spawn attachments", async () => {
const attachmentContent = "SIGNED_THINKING_INLINE_ATTACHMENT";
const messages = [
@@ -1588,6 +1632,8 @@ describe("wrapStreamFnSanitizeMalformedToolCalls", () => {
const wrapped = wrapStreamFnSanitizeMalformedToolCalls(baseFn as never, new Set(["read"]), {
validateGeminiTurns: false,
validateAnthropicTurns: true,
preserveSignatures: false,
dropThinkingBlocks: false,
});
const stream = wrapped({} as never, { messages } as never, {} as never) as
| FakeWrappedStream
@@ -1633,6 +1679,8 @@ describe("wrapStreamFnSanitizeMalformedToolCalls", () => {
const wrapped = wrapStreamFnSanitizeMalformedToolCalls(baseFn as never, new Set(["read"]), {
validateGeminiTurns: false,
validateAnthropicTurns: true,
preserveSignatures: false,
dropThinkingBlocks: false,
});
const stream = wrapped({} as never, { messages } as never, {} as never) as
| FakeWrappedStream
@@ -1682,6 +1730,8 @@ describe("wrapStreamFnSanitizeMalformedToolCalls", () => {
const wrapped = wrapStreamFnSanitizeMalformedToolCalls(baseFn as never, new Set(["read"]), {
validateGeminiTurns: false,
validateAnthropicTurns: true,
preserveSignatures: false,
dropThinkingBlocks: false,
});
const stream = wrapped({} as never, { messages } as never, {} as never) as
| FakeWrappedStream
@@ -1722,6 +1772,8 @@ describe("wrapStreamFnSanitizeMalformedToolCalls", () => {
const wrapped = wrapStreamFnSanitizeMalformedToolCalls(baseFn as never, new Set(["read"]), {
validateGeminiTurns: false,
validateAnthropicTurns: true,
preserveSignatures: false,
dropThinkingBlocks: false,
});
const stream = wrapped({} as never, { messages } as never, {} as never) as
| FakeWrappedStream