test: lazy-load duckduckgo web search runtime

Keep DuckDuckGo provider metadata on the contract path and defer
client plus runtime argument helpers until search execution.
This commit is contained in:
Gustavo Madeira Santana
2026-04-17 17:49:17 -04:00
parent 5d6041de81
commit c9dfb19001

View File

@@ -1,37 +1,29 @@
import { Type } from "@sinclair/typebox";
import {
enablePluginInConfig,
getScopedCredentialValue,
readNumberParam,
readStringParam,
setScopedCredentialValue,
createWebSearchProviderContractFields,
type WebSearchProviderPlugin,
} from "openclaw/plugin-sdk/provider-web-search";
import { runDuckDuckGoSearch } from "./ddg-client.js";
} from "openclaw/plugin-sdk/provider-web-search-contract";
const DuckDuckGoSearchSchema = Type.Object(
{
query: Type.String({ description: "Search query string." }),
count: Type.Optional(
Type.Number({
description: "Number of results to return (1-10).",
minimum: 1,
maximum: 10,
}),
),
region: Type.Optional(
Type.String({
description: "Optional DuckDuckGo region code such as us-en, uk-en, or de-de.",
}),
),
safeSearch: Type.Optional(
Type.String({
description: "SafeSearch level: strict, moderate, or off.",
}),
),
const DuckDuckGoSearchSchema = {
type: "object",
properties: {
query: { type: "string", description: "Search query string." },
count: {
type: "number",
description: "Number of results to return (1-10).",
minimum: 1,
maximum: 10,
},
region: {
type: "string",
description: "Optional DuckDuckGo region code such as us-en, uk-en, or de-de.",
},
safeSearch: {
type: "string",
description: "SafeSearch level: strict, moderate, or off.",
},
},
{ additionalProperties: false },
);
additionalProperties: false,
} satisfies Record<string, unknown>;
export function createDuckDuckGoWebSearchProvider(): WebSearchProviderPlugin {
return {
@@ -45,17 +37,21 @@ export function createDuckDuckGoWebSearchProvider(): WebSearchProviderPlugin {
docsUrl: "https://docs.openclaw.ai/tools/web",
autoDetectOrder: 100,
credentialPath: "",
inactiveSecretPaths: [],
getCredentialValue: (searchConfig) => getScopedCredentialValue(searchConfig, "duckduckgo"),
setCredentialValue: (searchConfigTarget, value) =>
setScopedCredentialValue(searchConfigTarget, "duckduckgo", value),
applySelectionConfig: (config) => enablePluginInConfig(config, "duckduckgo").config,
...createWebSearchProviderContractFields({
credentialPath: "",
searchCredential: { type: "scoped", scopeId: "duckduckgo" },
selectionPluginId: "duckduckgo",
}),
createTool: (ctx) => ({
description:
"Search the web using DuckDuckGo. Returns titles, URLs, and snippets with no API key required.",
parameters: DuckDuckGoSearchSchema,
execute: async (args) =>
await runDuckDuckGoSearch({
execute: async (args) => {
const [{ runDuckDuckGoSearch }, { readNumberParam, readStringParam }] = await Promise.all([
import("./ddg-client.js"),
import("openclaw/plugin-sdk/provider-web-search"),
]);
return await runDuckDuckGoSearch({
config: ctx.config,
query: readStringParam(args, "query", { required: true }),
count: readNumberParam(args, "count", { integer: true }),
@@ -65,7 +61,8 @@ export function createDuckDuckGoWebSearchProvider(): WebSearchProviderPlugin {
| "moderate"
| "off"
| undefined,
}),
});
},
}),
};
}