From ae8b8eeca32d3c3d0c5f1ecd779fadb69a81d97f Mon Sep 17 00:00:00 2001 From: Tom Boucher Date: Tue, 17 Mar 2026 10:23:05 -0400 Subject: [PATCH] fix: limit native web_search to max_uses:5 per response (#817) (#869) --- src/resources/extensions/search-the-web/native-search.ts | 4 ++++ src/tests/native-search.test.ts | 6 ++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/resources/extensions/search-the-web/native-search.ts b/src/resources/extensions/search-the-web/native-search.ts index f46bd42a4..3c50eda67 100644 --- a/src/resources/extensions/search-the-web/native-search.ts +++ b/src/resources/extensions/search-the-web/native-search.ts @@ -157,6 +157,10 @@ export function registerNativeSearchHooks(pi: NativeSearchPI): { getIsAnthropic: tools.push({ type: "web_search_20250305", name: "web_search", + // Cap server-side searches per response to prevent the model from + // looping on web_search without synthesizing results (#817). + // 5 searches is generous — most queries need 1-2. + max_uses: 5, }); return payload; diff --git a/src/tests/native-search.test.ts b/src/tests/native-search.test.ts index 09fd7597e..3547c0ce2 100644 --- a/src/tests/native-search.test.ts +++ b/src/tests/native-search.test.ts @@ -92,11 +92,12 @@ test("before_provider_request injects web_search for claude models", async () => }); const tools = (result as any)?.tools ?? payload.tools; - const hasNative = (tools as any[]).some( + const nativeTool = (tools as any[]).find( (t: any) => t.type === "web_search_20250305" ); - assert.ok(hasNative, "Should inject web_search_20250305 tool"); + assert.ok(nativeTool, "Should inject web_search_20250305 tool"); assert.equal((tools as any[]).length, 2, "Should have original + injected tool"); + assert.equal(nativeTool.max_uses, 5, "Should set max_uses to 5 to prevent search loops (#817)"); }); test("before_provider_request injects web_search for claude models even without model_select", async () => { @@ -278,6 +279,7 @@ test("before_provider_request creates tools array if missing", async () => { assert.ok(Array.isArray(tools), "Should create tools array"); assert.equal((tools as any[]).length, 1, "Should have exactly 1 tool"); assert.equal((tools as any[])[0].type, "web_search_20250305"); + assert.equal((tools as any[])[0].max_uses, 5, "Should include max_uses limit"); }); test("before_provider_request skips when payload is falsy", async () => {