mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-04 17:20:21 +00:00
feat(web-search): add DuckDuckGo bundled plugin (#52629)
* feat(web-search): add DuckDuckGo bundled plugin * chore(changelog): restore main changelog * fix(web-search): harden DuckDuckGo challenge detection
This commit is contained in:
@@ -7,7 +7,7 @@ import * as secretResolve from "./resolve.js";
|
||||
import { createResolverContext } from "./runtime-shared.js";
|
||||
import { resolveRuntimeWebTools } from "./runtime-web-tools.js";
|
||||
|
||||
type ProviderUnderTest = "brave" | "gemini" | "grok" | "kimi" | "perplexity";
|
||||
type ProviderUnderTest = "brave" | "gemini" | "grok" | "kimi" | "perplexity" | "duckduckgo";
|
||||
|
||||
const { resolvePluginWebSearchProvidersMock } = vi.hoisted(() => ({
|
||||
resolvePluginWebSearchProvidersMock: vi.fn(() => buildTestWebSearchProviders()),
|
||||
@@ -36,6 +36,8 @@ function asConfig(value: unknown): OpenClawConfig {
|
||||
|
||||
function providerPluginId(provider: ProviderUnderTest): string {
|
||||
switch (provider) {
|
||||
case "duckduckgo":
|
||||
return "duckduckgo";
|
||||
case "gemini":
|
||||
return "google";
|
||||
case "grok":
|
||||
@@ -81,13 +83,15 @@ function createTestProvider(params: {
|
||||
id: params.provider,
|
||||
label: params.provider,
|
||||
hint: `${params.provider} test provider`,
|
||||
envVars: [`${params.provider.toUpperCase()}_API_KEY`],
|
||||
placeholder: `${params.provider}-...`,
|
||||
requiresCredential: params.provider === "duckduckgo" ? false : undefined,
|
||||
envVars: params.provider === "duckduckgo" ? [] : [`${params.provider.toUpperCase()}_API_KEY`],
|
||||
placeholder: params.provider === "duckduckgo" ? "(no key needed)" : `${params.provider}-...`,
|
||||
signupUrl: `https://example.com/${params.provider}`,
|
||||
autoDetectOrder: params.order,
|
||||
credentialPath,
|
||||
inactiveSecretPaths: [credentialPath],
|
||||
getCredentialValue: (searchConfig) => searchConfig?.apiKey,
|
||||
credentialPath: params.provider === "duckduckgo" ? "" : credentialPath,
|
||||
inactiveSecretPaths: params.provider === "duckduckgo" ? [] : [credentialPath],
|
||||
getCredentialValue: (searchConfig) =>
|
||||
params.provider === "duckduckgo" ? "duckduckgo-no-key-needed" : searchConfig?.apiKey,
|
||||
setCredentialValue: (searchConfigTarget, value) => {
|
||||
searchConfigTarget.apiKey = value;
|
||||
},
|
||||
@@ -117,6 +121,7 @@ function buildTestWebSearchProviders(): PluginWebSearchProviderEntry[] {
|
||||
createTestProvider({ provider: "grok", pluginId: "xai", order: 30 }),
|
||||
createTestProvider({ provider: "kimi", pluginId: "moonshot", order: 40 }),
|
||||
createTestProvider({ provider: "perplexity", pluginId: "perplexity", order: 50 }),
|
||||
createTestProvider({ provider: "duckduckgo", pluginId: "duckduckgo", order: 100 }),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -231,6 +236,31 @@ describe("runtime web tools resolution", () => {
|
||||
expect(metadata.fetch.firecrawl.apiKeySource).toBe("env");
|
||||
});
|
||||
|
||||
it("auto-selects a keyless provider when no credentials are configured", async () => {
|
||||
const { metadata } = await runRuntimeWebTools({
|
||||
config: asConfig({
|
||||
tools: {
|
||||
web: {
|
||||
search: {
|
||||
enabled: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
||||
expect(metadata.search.selectedProvider).toBe("duckduckgo");
|
||||
expect(metadata.search.providerSource).toBe("auto-detect");
|
||||
expect(metadata.search.diagnostics).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
code: "WEB_SEARCH_AUTODETECT_SELECTED",
|
||||
message: expect.stringContaining('keyless provider "duckduckgo"'),
|
||||
}),
|
||||
]),
|
||||
);
|
||||
});
|
||||
|
||||
it.each([
|
||||
{
|
||||
provider: "brave" as const,
|
||||
|
||||
Reference in New Issue
Block a user