Agents: fix runtime web_search provider selection (#53020)

Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
This commit is contained in:
Jamil Zakirov
2026-03-23 20:30:45 +03:00
committed by GitHub
parent df18063260
commit 921a147196
2 changed files with 63 additions and 1 deletions

View File

@@ -1,4 +1,5 @@
import type { OpenClawConfig } from "../../config/config.js";
import { resolveBundledWebSearchPluginId } from "../../plugins/bundled-web-search-provider-ids.js";
import type { RuntimeWebSearchMetadata } from "../../secrets/runtime-web-tools.types.js";
import {
resolveWebSearchDefinition,
@@ -13,7 +14,13 @@ export function createWebSearchTool(options?: {
sandboxed?: boolean;
runtimeWebSearch?: RuntimeWebSearchMetadata;
}): AnyAgentTool | null {
const resolved = resolveWebSearchDefinition(options);
const runtimeProviderId =
options?.runtimeWebSearch?.selectedProvider ?? options?.runtimeWebSearch?.providerConfigured;
const resolved = resolveWebSearchDefinition({
...options,
preferRuntimeProviders:
Boolean(runtimeProviderId) && !resolveBundledWebSearchPluginId(runtimeProviderId),
});
if (!resolved) {
return null;
}

View File

@@ -1,5 +1,7 @@
import { EnvHttpProxyAgent } from "undici";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { createEmptyPluginRegistry } from "../../plugins/registry.js";
import { setActivePluginRegistry } from "../../plugins/runtime.js";
import { withFetchPreconnect } from "../../test-utils/fetch-mock.js";
import { __testing as webSearchTesting } from "./web-search.js";
import { createWebFetchTool, createWebSearchTool } from "./web-tools.js";
@@ -150,6 +152,10 @@ function createProviderSuccessPayload(
};
}
afterEach(() => {
setActivePluginRegistry(createEmptyPluginRegistry());
});
describe("web tools defaults", () => {
it("enables web_fetch by default (non-sandbox)", () => {
const tool = createWebFetchTool({ config: {}, sandboxed: false });
@@ -201,6 +207,55 @@ describe("web tools defaults", () => {
expect(String(mockFetch.mock.calls[0]?.[0])).toContain("generativelanguage.googleapis.com");
expect((result?.details as { provider?: string } | undefined)?.provider).toBe("gemini");
});
it("uses runtime-only web_search providers when runtime metadata is present", () => {
const registry = createEmptyPluginRegistry();
registry.webSearchProviders.push({
pluginId: "custom-search",
pluginName: "Custom Search",
source: "test",
provider: {
id: "custom",
label: "Custom Search",
hint: "Custom runtime provider",
envVars: ["CUSTOM_SEARCH_API_KEY"],
placeholder: "custom-...",
signupUrl: "https://example.com/signup",
autoDetectOrder: 1,
credentialPath: "tools.web.search.custom.apiKey",
getCredentialValue: () => "configured",
setCredentialValue: () => {},
createTool: () => ({
description: "custom runtime tool",
parameters: {},
execute: async () => ({ ok: true }),
}),
},
});
setActivePluginRegistry(registry);
const tool = createWebSearchTool({
config: {
tools: {
web: {
search: {
provider: "custom",
},
},
},
},
sandboxed: true,
runtimeWebSearch: {
providerConfigured: "custom",
providerSource: "configured",
selectedProvider: "custom",
selectedProviderKeySource: "config",
diagnostics: [],
},
});
expect(tool?.description).toBe("custom runtime tool");
});
});
describe("web_search country and language parameters", () => {