fix: remove Brave search tools from API payload when no BRAVE_API_KEY
The model_select event doesn't reliably fire on startup, so Brave tools remained visible to Claude even without a key. Now before_provider_request filters search-the-web and search_and_read from the payload directly, ensuring Claude only sees the native web_search tool. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
2252a6dfca
commit
e22a2f7622
2 changed files with 83 additions and 1 deletions
|
|
@ -111,10 +111,22 @@ export function registerNativeSearchHooks(pi: NativeSearchPI): { getIsAnthropic:
|
|||
|
||||
if (!Array.isArray(payload.tools)) payload.tools = [];
|
||||
|
||||
let tools = payload.tools as Array<Record<string, unknown>>;
|
||||
|
||||
// Don't double-inject if already present
|
||||
const tools = payload.tools as Array<Record<string, unknown>>;
|
||||
if (tools.some((t) => t.type === "web_search_20250305")) return;
|
||||
|
||||
// When no Brave key, remove Brave-based search tool definitions from the
|
||||
// payload so Claude doesn't see (and try to call) broken tools.
|
||||
// This is more reliable than setActiveTools since model_select may not fire.
|
||||
const hasBrave = !!process.env.BRAVE_API_KEY;
|
||||
if (!hasBrave) {
|
||||
tools = tools.filter(
|
||||
(t) => !BRAVE_TOOL_NAMES.includes(t.name as string)
|
||||
);
|
||||
payload.tools = tools;
|
||||
}
|
||||
|
||||
tools.push({
|
||||
type: "web_search_20250305",
|
||||
name: "web_search",
|
||||
|
|
|
|||
|
|
@ -331,6 +331,76 @@ test("BRAVE_TOOL_NAMES contains expected tool names", () => {
|
|||
assert.deepEqual(BRAVE_TOOL_NAMES, ["search-the-web", "search_and_read"]);
|
||||
});
|
||||
|
||||
test("before_provider_request removes Brave tools from payload when no BRAVE_API_KEY", async () => {
|
||||
const originalKey = process.env.BRAVE_API_KEY;
|
||||
delete process.env.BRAVE_API_KEY;
|
||||
|
||||
try {
|
||||
const pi = createMockPI();
|
||||
registerNativeSearchHooks(pi);
|
||||
|
||||
const payload: Record<string, unknown> = {
|
||||
model: "claude-sonnet-4-6-20250514",
|
||||
tools: [
|
||||
{ name: "bash", type: "function" },
|
||||
{ name: "search-the-web", type: "function" },
|
||||
{ name: "search_and_read", type: "function" },
|
||||
{ name: "fetch_page", type: "function" },
|
||||
],
|
||||
};
|
||||
|
||||
const result = await pi.fire("before_provider_request", {
|
||||
type: "before_provider_request",
|
||||
payload,
|
||||
});
|
||||
|
||||
const tools = ((result as any)?.tools ?? payload.tools) as any[];
|
||||
const names = tools.map((t: any) => t.name);
|
||||
|
||||
assert.ok(!names.includes("search-the-web"), "search-the-web should be removed from payload");
|
||||
assert.ok(!names.includes("search_and_read"), "search_and_read should be removed from payload");
|
||||
assert.ok(names.includes("bash"), "bash should remain");
|
||||
assert.ok(names.includes("fetch_page"), "fetch_page should remain");
|
||||
assert.ok(names.includes("web_search"), "native web_search should be injected");
|
||||
} finally {
|
||||
if (originalKey) process.env.BRAVE_API_KEY = originalKey;
|
||||
else delete process.env.BRAVE_API_KEY;
|
||||
}
|
||||
});
|
||||
|
||||
test("before_provider_request keeps Brave tools in payload when BRAVE_API_KEY set", async () => {
|
||||
const originalKey = process.env.BRAVE_API_KEY;
|
||||
process.env.BRAVE_API_KEY = "test-key";
|
||||
|
||||
try {
|
||||
const pi = createMockPI();
|
||||
registerNativeSearchHooks(pi);
|
||||
|
||||
const payload: Record<string, unknown> = {
|
||||
model: "claude-sonnet-4-6-20250514",
|
||||
tools: [
|
||||
{ name: "search-the-web", type: "function" },
|
||||
{ name: "search_and_read", type: "function" },
|
||||
],
|
||||
};
|
||||
|
||||
const result = await pi.fire("before_provider_request", {
|
||||
type: "before_provider_request",
|
||||
payload,
|
||||
});
|
||||
|
||||
const tools = ((result as any)?.tools ?? payload.tools) as any[];
|
||||
const names = tools.map((t: any) => t.name);
|
||||
|
||||
assert.ok(names.includes("search-the-web"), "search-the-web should remain with Brave key");
|
||||
assert.ok(names.includes("search_and_read"), "search_and_read should remain with Brave key");
|
||||
assert.ok(names.includes("web_search"), "native web_search should also be injected");
|
||||
} finally {
|
||||
if (originalKey) process.env.BRAVE_API_KEY = originalKey;
|
||||
else delete process.env.BRAVE_API_KEY;
|
||||
}
|
||||
});
|
||||
|
||||
// ─── stripThinkingFromHistory tests ─────────────────────────────────────────
|
||||
|
||||
test("stripThinkingFromHistory removes thinking from earlier assistant messages", () => {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue