mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-27 11:56:43 +02:00
test: cover bedrock signed thinking replay paths
This commit is contained in:
@@ -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));
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user