From b09cb35ab36cf0394885079add431fcc6817c0f0 Mon Sep 17 00:00:00 2001 From: Vadym O Date: Fri, 16 Oct 2026 11:35:38 +0800 Subject: [PATCH] fix(anthropic): cap the server-tool input buffer on the incoming fragment A single input_json_delta fragment past 4 KiB was appended whole when the buffer was empty, so the result handler retained and parsed input the cap means to discard. Append at most the remaining capacity. Co-Authored-By: Claude Code --- src/adapters/anthropic.ts | 2 +- .../claude-translated-server-tools.test.ts | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/adapters/anthropic.ts b/src/adapters/anthropic.ts index 653d91593ce..140bd336f3b 100644 --- a/src/adapters/anthropic.ts +++ b/src/adapters/anthropic.ts @@ -1416,7 +1416,7 @@ export function createAnthropicAdapter(provider: OcxProviderConfig, cacheRetenti } else if (delta.type === "input_json_delta" && typeof delta.partial_json === "string" && serverSearch?.streaming && serverSearch.json.length < 4096) { // Capped: an input past 4 KiB loses its label (query / url), never the call. - serverSearch.json += delta.partial_json; + serverSearch.json += delta.partial_json.slice(0, 4096 - serverSearch.json.length); } break; } diff --git a/tests/claude-integration/claude-translated-server-tools.test.ts b/tests/claude-integration/claude-translated-server-tools.test.ts index 75e45c572cf..35b385f3d0a 100644 --- a/tests/claude-integration/claude-translated-server-tools.test.ts +++ b/tests/claude-integration/claude-translated-server-tools.test.ts @@ -175,6 +175,17 @@ describe("server-side search across responses", () => { expect(starts[1]).toMatchObject({ tool_use_id: starts[0]!.id, content: [{ type: "web_search_result", url: "https://bun.sh/blog" }] }); }); + test("a single input fragment past 4 KiB is not retained beyond the cap", async () => { + const query = "q".repeat(5000); + const { clientSse } = await claudeTurn("https://api.anthropic.com", [ + ...SEARCH_TURN.slice(0, 2), + { type: "content_block_delta", index: 0, delta: { type: "input_json_delta", partial_json: JSON.stringify({ query }) } }, + ...SEARCH_TURN.slice(4), + ]); + expect(blockStarts(clientSse).map(b => b.type)).toEqual(["server_tool_use", "web_search_tool_result", "text"]); + expect(clientSse).not.toContain(query); + }); + test("a replayed search pair without encrypted_content never reaches Anthropic", async () => { const { wire } = await claudeTurn("https://api.anthropic.com", OK_TURN, "anth", [ { role: "user", content: "What did Bun release?" },