From ee04ba0386544249d10084aa1215c895e91041f6 Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Mon, 6 Apr 2026 23:21:26 +0100 Subject: [PATCH] perf(secrets): prefer light web search contract artifacts --- .../duckduckgo/web-search-contract-api.ts | 27 ++++++++++++++ .../firecrawl/web-search-contract-api.ts | 35 +++++++++++++++++++ extensions/google/web-search-contract-api.ts | 33 +++++++++++++++++ extensions/ollama/web-search-contract-api.ts | 24 +++++++++++++ src/plugins/web-provider-public-artifacts.ts | 6 +++- 5 files changed, 124 insertions(+), 1 deletion(-) create mode 100644 extensions/duckduckgo/web-search-contract-api.ts create mode 100644 extensions/firecrawl/web-search-contract-api.ts create mode 100644 extensions/google/web-search-contract-api.ts create mode 100644 extensions/ollama/web-search-contract-api.ts diff --git a/extensions/duckduckgo/web-search-contract-api.ts b/extensions/duckduckgo/web-search-contract-api.ts new file mode 100644 index 00000000000..eb62813fc58 --- /dev/null +++ b/extensions/duckduckgo/web-search-contract-api.ts @@ -0,0 +1,27 @@ +import { + enablePluginInConfig, + getScopedCredentialValue, + setScopedCredentialValue, + type WebSearchProviderPlugin, +} from "openclaw/plugin-sdk/provider-web-search"; + +export function createDuckDuckGoWebSearchProvider(): WebSearchProviderPlugin { + return { + id: "duckduckgo", + label: "DuckDuckGo Search (experimental)", + hint: "Free web search fallback with no API key required", + requiresCredential: false, + envVars: [], + placeholder: "(no key needed)", + signupUrl: "https://duckduckgo.com/", + 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, + createTool: () => null, + }; +} diff --git a/extensions/firecrawl/web-search-contract-api.ts b/extensions/firecrawl/web-search-contract-api.ts new file mode 100644 index 00000000000..c4e43002b31 --- /dev/null +++ b/extensions/firecrawl/web-search-contract-api.ts @@ -0,0 +1,35 @@ +import { + enablePluginInConfig, + getScopedCredentialValue, + resolveProviderWebSearchPluginConfig, + setProviderWebSearchPluginConfigValue, + setScopedCredentialValue, + type WebSearchProviderPlugin, +} from "openclaw/plugin-sdk/provider-web-search"; + +export function createFirecrawlWebSearchProvider(): WebSearchProviderPlugin { + return { + id: "firecrawl", + label: "Firecrawl Search", + hint: "Structured results with optional result scraping", + onboardingScopes: ["text-inference"], + credentialLabel: "Firecrawl API key", + envVars: ["FIRECRAWL_API_KEY"], + placeholder: "fc-...", + signupUrl: "https://www.firecrawl.dev/", + docsUrl: "https://docs.openclaw.ai/tools/firecrawl", + autoDetectOrder: 60, + credentialPath: "plugins.entries.firecrawl.config.webSearch.apiKey", + inactiveSecretPaths: ["plugins.entries.firecrawl.config.webSearch.apiKey"], + getCredentialValue: (searchConfig) => getScopedCredentialValue(searchConfig, "firecrawl"), + setCredentialValue: (searchConfigTarget, value) => + setScopedCredentialValue(searchConfigTarget, "firecrawl", value), + getConfiguredCredentialValue: (config) => + resolveProviderWebSearchPluginConfig(config, "firecrawl")?.apiKey, + setConfiguredCredentialValue: (configTarget, value) => { + setProviderWebSearchPluginConfigValue(configTarget, "firecrawl", "apiKey", value); + }, + applySelectionConfig: (config) => enablePluginInConfig(config, "firecrawl").config, + createTool: () => null, + }; +} diff --git a/extensions/google/web-search-contract-api.ts b/extensions/google/web-search-contract-api.ts new file mode 100644 index 00000000000..491763d207f --- /dev/null +++ b/extensions/google/web-search-contract-api.ts @@ -0,0 +1,33 @@ +import { + getScopedCredentialValue, + resolveProviderWebSearchPluginConfig, + setProviderWebSearchPluginConfigValue, + setScopedCredentialValue, + type WebSearchProviderPlugin, +} from "openclaw/plugin-sdk/provider-web-search"; + +export function createGeminiWebSearchProvider(): WebSearchProviderPlugin { + return { + id: "gemini", + label: "Gemini (Google Search)", + hint: "Requires Google Gemini API key · Google Search grounding", + onboardingScopes: ["text-inference"], + credentialLabel: "Google Gemini API key", + envVars: ["GEMINI_API_KEY"], + placeholder: "AIza...", + signupUrl: "https://aistudio.google.com/apikey", + docsUrl: "https://docs.openclaw.ai/tools/web", + autoDetectOrder: 20, + credentialPath: "plugins.entries.google.config.webSearch.apiKey", + inactiveSecretPaths: ["plugins.entries.google.config.webSearch.apiKey"], + getCredentialValue: (searchConfig) => getScopedCredentialValue(searchConfig, "gemini"), + setCredentialValue: (searchConfigTarget, value) => + setScopedCredentialValue(searchConfigTarget, "gemini", value), + getConfiguredCredentialValue: (config) => + resolveProviderWebSearchPluginConfig(config, "google")?.apiKey, + setConfiguredCredentialValue: (configTarget, value) => { + setProviderWebSearchPluginConfigValue(configTarget, "google", "apiKey", value); + }, + createTool: () => null, + }; +} diff --git a/extensions/ollama/web-search-contract-api.ts b/extensions/ollama/web-search-contract-api.ts new file mode 100644 index 00000000000..1592b457dbc --- /dev/null +++ b/extensions/ollama/web-search-contract-api.ts @@ -0,0 +1,24 @@ +import { + enablePluginInConfig, + type WebSearchProviderPlugin, +} from "openclaw/plugin-sdk/provider-web-search"; + +export function createOllamaWebSearchProvider(): WebSearchProviderPlugin { + return { + id: "ollama", + label: "Ollama Web Search", + hint: "Local Ollama host · requires ollama signin", + onboardingScopes: ["text-inference"], + requiresCredential: false, + envVars: [], + placeholder: "(run ollama signin)", + signupUrl: "https://ollama.com/", + docsUrl: "https://docs.openclaw.ai/tools/web", + autoDetectOrder: 110, + credentialPath: "", + getCredentialValue: () => undefined, + setCredentialValue: () => {}, + applySelectionConfig: (config) => enablePluginInConfig(config, "ollama").config, + createTool: () => null, + }; +} diff --git a/src/plugins/web-provider-public-artifacts.ts b/src/plugins/web-provider-public-artifacts.ts index ed009774452..ffcd8e53c91 100644 --- a/src/plugins/web-provider-public-artifacts.ts +++ b/src/plugins/web-provider-public-artifacts.ts @@ -13,7 +13,11 @@ import { resolveBundledWebFetchResolutionConfig } from "./web-fetch-providers.sh import { resolveManifestDeclaredWebProviderCandidatePluginIds } from "./web-provider-resolution-shared.js"; import { resolveBundledWebSearchResolutionConfig } from "./web-search-providers.shared.js"; -const WEB_SEARCH_ARTIFACT_CANDIDATES = ["web-search-provider.js", "web-search.js"] as const; +const WEB_SEARCH_ARTIFACT_CANDIDATES = [ + "web-search-contract-api.js", + "web-search-provider.js", + "web-search.js", +] as const; const WEB_FETCH_ARTIFACT_CANDIDATES = ["web-fetch-provider.js", "web-fetch.js"] as const; type BundledWebProviderPublicArtifactParams = {