fix(ai): validated preserved web-search history blocks

Required non-empty server/result ids and a present result content field before narrowing gateway or stream blocks into replayable Anthropic web-search history. Malformed variants now remain flattened or ignored.
This commit is contained in:
roboomp
2026-07-24 11:07:13 +00:00
parent 6aa8c8cfb3
commit 0e2d2a226f
2 changed files with 32 additions and 1 deletions
+10 -1
View File
@@ -89,8 +89,17 @@ export type WebSearchToolResultBlockParam = {
export function isAnthropicWebSearchHistoryBlock(block: {
type: string;
name?: unknown;
id?: unknown;
tool_use_id?: unknown;
content?: unknown;
}): block is WebSearchServerToolUseBlockParam | WebSearchToolResultBlockParam {
return block.type === "web_search_tool_result" || (block.type === "server_tool_use" && block.name === "web_search");
if (block.type === "server_tool_use") {
return block.name === "web_search" && typeof block.id === "string" && block.id.length > 0;
}
if (block.type === "web_search_tool_result") {
return typeof block.tool_use_id === "string" && block.tool_use_id.length > 0 && Object.hasOwn(block, "content");
}
return false;
}
export type ThinkingBlockParam = {
@@ -344,6 +344,28 @@ describe("anthropic-messages parseRequest", () => {
]);
});
it("flattens malformed web-search history blocks instead of preserving invalid replay state", () => {
const parsed = parseRequest({
model: "claude-opus-4-7",
max_tokens: 8,
messages: [
{ role: "user", content: "weather?" },
{
role: "assistant",
content: [
{ type: "server_tool_use", name: "web_search" },
{ type: "web_search_tool_result", tool_use_id: "srvtoolu_1" },
{ type: "web_search_tool_result", content: [] },
],
},
],
});
const assistant = parsed.context.messages.find(message => message.role === "assistant");
expect(assistant?.content).toHaveLength(3);
expect(assistant?.content.every(block => block.type === "text")).toBe(true);
expect(assistant?.content.some(block => block.type === "anthropicServerTool")).toBe(false);
});
it("does not retain a partial code-execution server-tool history", () => {
const parsed = parseRequest({
model: "claude-opus-4-7",