Merge de80b423944703501694fbfd2af037c099c8011e into 5e417b44e1540f528d2ae63e3e20229a902d1db2
This commit is contained in:
commit
359581ddd4
4
.github/labeler.yml
vendored
4
.github/labeler.yml
vendored
@ -325,3 +325,7 @@
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- "extensions/fal/**"
|
||||
"extensions: baidu":
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- "extensions/baidu/**"
|
||||
|
||||
@ -39,6 +39,7 @@ Scope intent:
|
||||
- `plugins.entries.perplexity.config.webSearch.apiKey`
|
||||
- `plugins.entries.firecrawl.config.webSearch.apiKey`
|
||||
- `plugins.entries.tavily.config.webSearch.apiKey`
|
||||
- `plugins.entries.baidu.config.webSearch.apiKey`
|
||||
- `tools.web.search.apiKey`
|
||||
- `tools.web.search.gemini.apiKey`
|
||||
- `tools.web.search.grok.apiKey`
|
||||
|
||||
@ -447,6 +447,13 @@
|
||||
"secretShape": "secret_input",
|
||||
"optIn": true
|
||||
},
|
||||
{
|
||||
"id": "plugins.entries.baidu.config.webSearch.apiKey",
|
||||
"configFile": "openclaw.json",
|
||||
"path": "plugins.entries.baidu.config.webSearch.apiKey",
|
||||
"secretShape": "secret_input",
|
||||
"optIn": true
|
||||
},
|
||||
{
|
||||
"id": "plugins.entries.brave.config.webSearch.apiKey",
|
||||
"configFile": "openclaw.json",
|
||||
|
||||
@ -11,7 +11,7 @@ title: "Web Tools"
|
||||
|
||||
OpenClaw ships two lightweight web tools:
|
||||
|
||||
- `web_search` — Search the web using Brave Search API, Firecrawl Search, Gemini with Google Search grounding, Grok, Kimi, Perplexity Search API, or Tavily Search API.
|
||||
- `web_search` — Search the web using Baidu Search API, Brave Search API, Firecrawl Search, Gemini with Google Search grounding, Grok, Kimi, Perplexity Search API, or Tavily Search API.
|
||||
- `web_fetch` — HTTP fetch + readable extraction (HTML → markdown/text).
|
||||
|
||||
These are **not** browser automation. For JS-heavy sites or logins, use the
|
||||
@ -33,6 +33,7 @@ See [Brave Search setup](/tools/brave-search), [Perplexity Search setup](/tools/
|
||||
|
||||
| Provider | Result shape | Provider-specific filters | Notes | API key |
|
||||
| ------------------------- | ---------------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------------------------ | ------------------------------------------- |
|
||||
| **Baidu** | Structured results with snippets | — | Uses Baidu Search | `BAIDU_SEARCH_API_KEY` |
|
||||
| **Brave Search API** | Structured results with snippets | `country`, `language`, `ui_lang`, time | Supports Brave `llm-context` mode | `BRAVE_API_KEY` |
|
||||
| **Firecrawl Search** | Structured results with snippets | Use `firecrawl_search` for Firecrawl-specific search options | Best for pairing search with Firecrawl scraping/extraction | `FIRECRAWL_API_KEY` |
|
||||
| **Gemini** | AI-synthesized answers + citations | — | Uses Google Search grounding | `GEMINI_API_KEY` |
|
||||
@ -45,13 +46,14 @@ See [Brave Search setup](/tools/brave-search), [Perplexity Search setup](/tools/
|
||||
|
||||
The table above is alphabetical. If no `provider` is explicitly set, runtime auto-detection checks providers in this order:
|
||||
|
||||
1. **Brave** — `BRAVE_API_KEY` env var or `plugins.entries.brave.config.webSearch.apiKey`
|
||||
2. **Gemini** — `GEMINI_API_KEY` env var or `plugins.entries.google.config.webSearch.apiKey`
|
||||
3. **Grok** — `XAI_API_KEY` env var or `plugins.entries.xai.config.webSearch.apiKey`
|
||||
4. **Kimi** — `KIMI_API_KEY` / `MOONSHOT_API_KEY` env var or `plugins.entries.moonshot.config.webSearch.apiKey`
|
||||
5. **Perplexity** — `PERPLEXITY_API_KEY`, `OPENROUTER_API_KEY`, or `plugins.entries.perplexity.config.webSearch.apiKey`
|
||||
6. **Firecrawl** — `FIRECRAWL_API_KEY` env var or `plugins.entries.firecrawl.config.webSearch.apiKey`
|
||||
7. **Tavily** — `TAVILY_API_KEY` env var or `plugins.entries.tavily.config.webSearch.apiKey`
|
||||
1. **Baidu** — `BAIDU_SEARCH_API_KEY` env var or `plugins.entries.baidu.config.webSearch.apiKey`
|
||||
2. **Brave** — `BRAVE_API_KEY` env var or `plugins.entries.brave.config.webSearch.apiKey`
|
||||
3. **Gemini** — `GEMINI_API_KEY` env var or `plugins.entries.google.config.webSearch.apiKey`
|
||||
4. **Grok** — `XAI_API_KEY` env var or `plugins.entries.xai.config.webSearch.apiKey`
|
||||
5. **Kimi** — `KIMI_API_KEY` / `MOONSHOT_API_KEY` env var or `plugins.entries.moonshot.config.webSearch.apiKey`
|
||||
6. **Perplexity** — `PERPLEXITY_API_KEY`, `OPENROUTER_API_KEY`, or `plugins.entries.perplexity.config.webSearch.apiKey`
|
||||
7. **Firecrawl** — `FIRECRAWL_API_KEY` env var or `plugins.entries.firecrawl.config.webSearch.apiKey`
|
||||
8. **Tavily** — `TAVILY_API_KEY` env var or `plugins.entries.tavily.config.webSearch.apiKey`
|
||||
|
||||
If no keys are found, it falls back to Brave (you'll get a missing-key error prompting you to configure one).
|
||||
|
||||
@ -65,6 +67,12 @@ Runtime SecretRef behavior:
|
||||
|
||||
Use `openclaw configure --section web` to set up your API key and choose a provider.
|
||||
|
||||
### Baidu Search
|
||||
|
||||
1. Visit the [Baidu AI Search Console](https://console.bce.baidu.com/ai-search/qianfan/ais/console/apiKey)
|
||||
2. Generate a new API key or select an existing one(format: `bce-v3/ALTAK-...`)
|
||||
3. Copy the API key and use it with OpenClaw
|
||||
|
||||
### Brave Search
|
||||
|
||||
1. Create a Brave Search API account at [brave.com/search/api](https://brave.com/search/api/)
|
||||
@ -94,6 +102,7 @@ See [Perplexity Search API Docs](https://docs.perplexity.ai/guides/search-quicks
|
||||
|
||||
**Via config:** run `openclaw configure --section web`. It stores the key under the provider-specific config path:
|
||||
|
||||
- Baidu: `plugins.entries.baidu.config.webSearch.apiKey`
|
||||
- Brave: `plugins.entries.brave.config.webSearch.apiKey`
|
||||
- Firecrawl: `plugins.entries.firecrawl.config.webSearch.apiKey`
|
||||
- Gemini: `plugins.entries.google.config.webSearch.apiKey`
|
||||
@ -106,6 +115,7 @@ All of these fields also support SecretRef objects.
|
||||
|
||||
**Via environment:** set provider env vars in the Gateway process environment:
|
||||
|
||||
- Baidu: `BAIDU_SEARCH_API_KEY`
|
||||
- Brave: `BRAVE_API_KEY`
|
||||
- Firecrawl: `FIRECRAWL_API_KEY`
|
||||
- Gemini: `GEMINI_API_KEY`
|
||||
@ -118,6 +128,32 @@ For a gateway install, put these in `~/.openclaw/.env` (or your service environm
|
||||
|
||||
### Config examples
|
||||
|
||||
**Baidu Search:**
|
||||
|
||||
```json5
|
||||
{
|
||||
plugins: {
|
||||
entries: {
|
||||
baidu: {
|
||||
config: {
|
||||
webSearch: {
|
||||
apiKey: "YOUR_BAIDU_API_KEY", // optional if BRAVE_API_KEY is set // pragma: allowlist secret
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
tools: {
|
||||
web: {
|
||||
search: {
|
||||
enabled: true,
|
||||
provider: "baidu",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
**Brave Search:**
|
||||
|
||||
```json5
|
||||
@ -355,6 +391,7 @@ Search the web using your configured provider.
|
||||
|
||||
- `tools.web.search.enabled` must not be `false` (default: enabled)
|
||||
- API key for your chosen provider:
|
||||
- **Baidu**: `BAIDU_SEARCH_API_KEY` or `plugins.entries.baidu.config.webSearch.apiKey`
|
||||
- **Brave**: `BRAVE_API_KEY` or `plugins.entries.brave.config.webSearch.apiKey`
|
||||
- **Firecrawl**: `FIRECRAWL_API_KEY` or `plugins.entries.firecrawl.config.webSearch.apiKey`
|
||||
- **Gemini**: `GEMINI_API_KEY` or `plugins.entries.google.config.webSearch.apiKey`
|
||||
|
||||
11
extensions/baidu/index.ts
Normal file
11
extensions/baidu/index.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import { definePluginEntry } from "openclaw/plugin-sdk/core";
|
||||
import { createBaiduWebSearchProvider } from "./src/baidu-web-search-provider.ts";
|
||||
|
||||
export default definePluginEntry({
|
||||
id: "baidu",
|
||||
name: "Baidu Plugin",
|
||||
description: "Bundled Baidu plugin",
|
||||
register(api) {
|
||||
api.registerWebSearchProvider(createBaiduWebSearchProvider());
|
||||
},
|
||||
});
|
||||
29
extensions/baidu/openclaw.plugin.json
Normal file
29
extensions/baidu/openclaw.plugin.json
Normal file
@ -0,0 +1,29 @@
|
||||
{
|
||||
"id": "baidu",
|
||||
"providerAuthEnvVars": {
|
||||
"brave": ["BAIDU_SEARCH_API_KEY"]
|
||||
},
|
||||
"uiHints": {
|
||||
"webSearch.apiKey": {
|
||||
"label": "Baidu Search API Key",
|
||||
"help": "Baidu Search API key (fallback: BAIDU_SEARCH_API_KEY env var).",
|
||||
"sensitive": true,
|
||||
"placeholder": "bce-..."
|
||||
}
|
||||
},
|
||||
"configSchema": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"webSearch": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"apiKey": {
|
||||
"type": ["string", "object"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
12
extensions/baidu/package.json
Normal file
12
extensions/baidu/package.json
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "@openclaw/baidu-plugin",
|
||||
"version": "2026.3.14",
|
||||
"private": true,
|
||||
"description": "OpenClaw Baidu plugin",
|
||||
"type": "module",
|
||||
"openclaw": {
|
||||
"extensions": [
|
||||
"./index.ts"
|
||||
]
|
||||
}
|
||||
}
|
||||
259
extensions/baidu/src/baidu-web-search-provider.ts
Normal file
259
extensions/baidu/src/baidu-web-search-provider.ts
Normal file
@ -0,0 +1,259 @@
|
||||
import { Type } from "@sinclair/typebox";
|
||||
import {
|
||||
buildSearchCacheKey,
|
||||
DEFAULT_SEARCH_COUNT,
|
||||
MAX_SEARCH_COUNT,
|
||||
readCachedSearchPayload,
|
||||
readConfiguredSecretString,
|
||||
readNumberParam,
|
||||
readProviderEnvValue,
|
||||
readStringParam,
|
||||
resolveSearchCacheTtlMs,
|
||||
resolveSearchCount,
|
||||
resolveSearchTimeoutSeconds,
|
||||
resolveProviderWebSearchPluginConfig,
|
||||
setProviderWebSearchPluginConfigValue,
|
||||
type SearchConfigRecord,
|
||||
type WebSearchProviderPlugin,
|
||||
type WebSearchProviderToolDefinition,
|
||||
withTrustedWebSearchEndpoint,
|
||||
wrapWebContent,
|
||||
writeCachedSearchPayload,
|
||||
} from "openclaw/plugin-sdk/provider-web-search";
|
||||
|
||||
const BAIDU_SEARCH_API_ENDPOINT = "https://qianfan.baidubce.com/v2/ai_search/web_search";
|
||||
|
||||
type BaiduConfig = {
|
||||
apiKey?: string;
|
||||
};
|
||||
|
||||
type BaiduSearchResult = {
|
||||
title?: string;
|
||||
url?: string;
|
||||
snippet?: string;
|
||||
date?: string;
|
||||
website?: string;
|
||||
};
|
||||
|
||||
type BaiduSearchResponse = {
|
||||
references?: BaiduSearchResult[];
|
||||
};
|
||||
|
||||
function createBaiduSchema() {
|
||||
return Type.Object({
|
||||
query: Type.String({ description: "Search query string." }),
|
||||
count: Type.Optional(
|
||||
Type.Number({
|
||||
description: "Number of results to return (1-20).",
|
||||
minimum: 1,
|
||||
maximum: MAX_SEARCH_COUNT,
|
||||
}),
|
||||
),
|
||||
country: Type.Optional(Type.String({ description: "Not supported by Baidu." })),
|
||||
language: Type.Optional(Type.String({ description: "Not supported by Baidu." })),
|
||||
freshness: Type.Optional(Type.String({ description: "Not supported by Baidu." })),
|
||||
date_after: Type.Optional(Type.String({ description: "Not supported by Baidu." })),
|
||||
date_before: Type.Optional(Type.String({ description: "Not supported by Baidu." })),
|
||||
});
|
||||
}
|
||||
|
||||
function resolveBaiduConfig(searchConfig?: SearchConfigRecord): BaiduConfig {
|
||||
const baidu = searchConfig?.baidu;
|
||||
return baidu && typeof baidu === "object" && !Array.isArray(baidu) ? (baidu as BaiduConfig) : {};
|
||||
}
|
||||
|
||||
function resolveBaiduApiKey(baidu?: BaiduConfig): string | undefined {
|
||||
return (
|
||||
readConfiguredSecretString(baidu?.apiKey, "tools.web.search.baidu.apiKey") ??
|
||||
readProviderEnvValue(["BAIDU_SEARCH_API_KEY"])
|
||||
);
|
||||
}
|
||||
|
||||
async function runBaiduSearch(params: {
|
||||
query: string;
|
||||
apiKey: string;
|
||||
timeoutSeconds: number;
|
||||
count: number;
|
||||
}): Promise<{ results: BaiduSearchResult[] }> {
|
||||
const body: Record<string, unknown> = {
|
||||
resource_type_filter: [
|
||||
{ type: "web", top_k: params.count > 0 ? params.count : DEFAULT_SEARCH_COUNT },
|
||||
],
|
||||
messages: [
|
||||
{
|
||||
role: "user",
|
||||
content: params.query,
|
||||
},
|
||||
],
|
||||
};
|
||||
return withTrustedWebSearchEndpoint(
|
||||
{
|
||||
url: BAIDU_SEARCH_API_ENDPOINT,
|
||||
timeoutSeconds: params.timeoutSeconds,
|
||||
init: {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
"X-Appbuilder-From": "openclaw",
|
||||
},
|
||||
body: JSON.stringify(body),
|
||||
},
|
||||
},
|
||||
async (res) => {
|
||||
if (!res.ok) {
|
||||
const detail = await res.text();
|
||||
throw new Error(`Baidu API error (${res.status}): ${detail || res.statusText}`);
|
||||
}
|
||||
const data = (await res.json()) as BaiduSearchResponse;
|
||||
const results = Array.isArray(data.references) ? data.references : [];
|
||||
const mapped = results.map((entry) => {
|
||||
const snippet = entry.snippet ?? "";
|
||||
const title = entry.title ?? "";
|
||||
const url = entry.url ?? "";
|
||||
const site = entry.website ?? "";
|
||||
return {
|
||||
title: title ? wrapWebContent(title, "web_search") : "",
|
||||
url, // Keep raw for tool chaining
|
||||
snippet: snippet ? wrapWebContent(snippet, "web_search") : "",
|
||||
date: entry.date || undefined,
|
||||
site: site,
|
||||
};
|
||||
});
|
||||
return { results: mapped };
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
function createBaiduToolDefinition(
|
||||
searchConfig?: SearchConfigRecord,
|
||||
): WebSearchProviderToolDefinition {
|
||||
return {
|
||||
description: "Search the web using Baidu Search",
|
||||
parameters: createBaiduSchema(),
|
||||
execute: async (args) => {
|
||||
const params = args as Record<string, unknown>;
|
||||
for (const name of ["country", "language", "freshness", "date_after", "date_before"]) {
|
||||
if (readStringParam(params, name)) {
|
||||
const label =
|
||||
name === "country"
|
||||
? "country filtering"
|
||||
: name === "language"
|
||||
? "language filtering"
|
||||
: name === "freshness"
|
||||
? "freshness filtering"
|
||||
: "date_after/date_before filtering";
|
||||
return {
|
||||
error: name.startsWith("date_") ? "unsupported_date_filter" : `unsupported_${name}`,
|
||||
message: `${label} is not supported by the baidu provider. Only Brave and Perplexity support ${name === "country" ? "country filtering" : name === "language" ? "language filtering" : name === "freshness" ? "freshness" : "date filtering"}.`,
|
||||
docs: "https://docs.openclaw.ai/tools/web",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const baiduConfig = resolveBaiduConfig(searchConfig);
|
||||
const apiKey = resolveBaiduApiKey(baiduConfig);
|
||||
if (!apiKey) {
|
||||
return {
|
||||
error: "missing_baidu_search_api_key",
|
||||
message:
|
||||
"web_search (baidu) needs a Baidu Search API key. Set BAIDU_SEARCH_API_KEY in the Gateway environment, or configure plugins.entries.baidu.config.webSearch.apiKey.",
|
||||
docs: "https://docs.openclaw.ai/tools/web",
|
||||
};
|
||||
}
|
||||
const query = readStringParam(params, "query", { required: true });
|
||||
const count =
|
||||
readNumberParam(params, "count", { integer: true }) ??
|
||||
searchConfig?.maxResults ??
|
||||
undefined;
|
||||
const cacheKey = buildSearchCacheKey([
|
||||
"baidu",
|
||||
query,
|
||||
resolveSearchCount(count, DEFAULT_SEARCH_COUNT),
|
||||
]);
|
||||
const cached = readCachedSearchPayload(cacheKey);
|
||||
if (cached) {
|
||||
return cached;
|
||||
}
|
||||
|
||||
const start = Date.now();
|
||||
const { results } = await runBaiduSearch({
|
||||
query,
|
||||
apiKey,
|
||||
timeoutSeconds: resolveSearchTimeoutSeconds(searchConfig),
|
||||
count: resolveSearchCount(count, DEFAULT_SEARCH_COUNT),
|
||||
});
|
||||
const payload = {
|
||||
query: params.query,
|
||||
provider: "baidu",
|
||||
tookMs: Date.now() - start,
|
||||
externalContent: {
|
||||
untrusted: true,
|
||||
source: "web_search",
|
||||
provider: "baidu",
|
||||
wrapped: true,
|
||||
},
|
||||
results: results,
|
||||
};
|
||||
writeCachedSearchPayload(cacheKey, payload, resolveSearchCacheTtlMs(searchConfig));
|
||||
return payload;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function createBaiduWebSearchProvider(): WebSearchProviderPlugin {
|
||||
return {
|
||||
id: "baidu",
|
||||
label: "Baidu Search",
|
||||
hint: "Structured results",
|
||||
envVars: ["BAIDU_SEARCH_API_KEY"],
|
||||
placeholder: "bce...",
|
||||
signupUrl: "https://console.bce.baidu.com/ai-search/qianfan/ais/console/apiKey",
|
||||
docsUrl: "https://docs.openclaw.ai/tools/web",
|
||||
autoDetectOrder: 5,
|
||||
credentialPath: "plugins.entries.baidu.config.webSearch.apiKey",
|
||||
inactiveSecretPaths: ["plugins.entries.baidu.config.webSearch.apiKey"],
|
||||
getCredentialValue: (searchConfig) => {
|
||||
const baidu = searchConfig?.baidu;
|
||||
return baidu && typeof baidu === "object" && !Array.isArray(baidu)
|
||||
? (baidu as Record<string, unknown>).apiKey
|
||||
: undefined;
|
||||
},
|
||||
setCredentialValue: (searchConfigTarget, value) => {
|
||||
const scoped = searchConfigTarget.baidu;
|
||||
if (!scoped || typeof scoped !== "object" || Array.isArray(scoped)) {
|
||||
searchConfigTarget.baidu = { apiKey: value };
|
||||
return;
|
||||
}
|
||||
(scoped as Record<string, unknown>).apiKey = value;
|
||||
},
|
||||
getConfiguredCredentialValue: (config) =>
|
||||
resolveProviderWebSearchPluginConfig(config, "baidu")?.apiKey,
|
||||
setConfiguredCredentialValue: (configTarget, value) => {
|
||||
setProviderWebSearchPluginConfigValue(configTarget, "baidu", "apiKey", value);
|
||||
},
|
||||
createTool: (ctx) =>
|
||||
createBaiduToolDefinition(
|
||||
(() => {
|
||||
const searchConfig = ctx.searchConfig as SearchConfigRecord | undefined;
|
||||
const pluginConfig = resolveProviderWebSearchPluginConfig(ctx.config, "baidu");
|
||||
if (!pluginConfig) {
|
||||
return searchConfig;
|
||||
}
|
||||
return {
|
||||
...(searchConfig ?? {}),
|
||||
baidu: {
|
||||
...resolveBaiduConfig(searchConfig),
|
||||
...pluginConfig,
|
||||
},
|
||||
} as SearchConfigRecord;
|
||||
})(),
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
export const __testing = {
|
||||
resolveBaiduConfig,
|
||||
resolveBaiduApiKey,
|
||||
runBaiduSearch,
|
||||
} as const;
|
||||
2
pnpm-lock.yaml
generated
2
pnpm-lock.yaml
generated
@ -245,6 +245,8 @@ importers:
|
||||
|
||||
extensions/anthropic: {}
|
||||
|
||||
extensions/baidu: {}
|
||||
|
||||
extensions/bluebubbles:
|
||||
dependencies:
|
||||
zod:
|
||||
|
||||
@ -12,6 +12,7 @@ const GENERIC_WEB_SEARCH_KEYS = new Set([
|
||||
]);
|
||||
|
||||
const LEGACY_PROVIDER_MAP = {
|
||||
baidu: "baidu",
|
||||
brave: "brave",
|
||||
firecrawl: "firecrawl",
|
||||
gemini: "google",
|
||||
@ -213,7 +214,14 @@ function normalizeLegacyWebSearchConfigRecord<T extends JsonRecord>(
|
||||
});
|
||||
}
|
||||
|
||||
for (const providerId of ["firecrawl", "gemini", "grok", "kimi", "perplexity"] as const) {
|
||||
for (const providerId of [
|
||||
"baidu",
|
||||
"firecrawl",
|
||||
"gemini",
|
||||
"grok",
|
||||
"kimi",
|
||||
"perplexity",
|
||||
] as const) {
|
||||
const scoped = copyLegacyProviderConfig(search, providerId);
|
||||
if (!scoped || Object.keys(scoped).length === 0) {
|
||||
continue;
|
||||
|
||||
@ -66,6 +66,7 @@ describe("bundled web search metadata", () => {
|
||||
|
||||
it("keeps bundled web search compat ids aligned with bundled manifests", () => {
|
||||
expect(resolveBundledWebSearchPluginIds({})).toEqual([
|
||||
"baidu",
|
||||
"brave",
|
||||
"firecrawl",
|
||||
"google",
|
||||
|
||||
@ -6,6 +6,7 @@ describe("resolveBundledPluginWebSearchProviders", () => {
|
||||
const providers = resolveBundledPluginWebSearchProviders({});
|
||||
|
||||
expect(providers.map((provider) => `${provider.pluginId}:${provider.id}`)).toEqual([
|
||||
"baidu:baidu",
|
||||
"brave:brave",
|
||||
"google:gemini",
|
||||
"xai:grok",
|
||||
@ -15,6 +16,7 @@ describe("resolveBundledPluginWebSearchProviders", () => {
|
||||
"tavily:tavily",
|
||||
]);
|
||||
expect(providers.map((provider) => provider.credentialPath)).toEqual([
|
||||
"plugins.entries.baidu.config.webSearch.apiKey",
|
||||
"plugins.entries.brave.config.webSearch.apiKey",
|
||||
"plugins.entries.google.config.webSearch.apiKey",
|
||||
"plugins.entries.xai.config.webSearch.apiKey",
|
||||
@ -42,6 +44,7 @@ describe("resolveBundledPluginWebSearchProviders", () => {
|
||||
});
|
||||
|
||||
expect(providers.map((provider) => provider.pluginId)).toEqual([
|
||||
"baidu",
|
||||
"brave",
|
||||
"google",
|
||||
"xai",
|
||||
@ -96,6 +99,7 @@ describe("resolveBundledPluginWebSearchProviders", () => {
|
||||
});
|
||||
|
||||
expect(providers.map((provider) => `${provider.pluginId}:${provider.id}`)).toEqual([
|
||||
"baidu:baidu",
|
||||
"brave:brave",
|
||||
"google:gemini",
|
||||
"xai:grok",
|
||||
|
||||
@ -23,7 +23,7 @@ vi.mock("../plugins/web-search-providers.runtime.js", () => ({
|
||||
}));
|
||||
|
||||
function createTestProvider(params: {
|
||||
id: "brave" | "gemini" | "grok" | "kimi" | "perplexity" | "firecrawl" | "tavily";
|
||||
id: "baidu" | "brave" | "gemini" | "grok" | "kimi" | "perplexity" | "firecrawl" | "tavily";
|
||||
pluginId: string;
|
||||
order: number;
|
||||
}): PluginWebSearchProviderEntry {
|
||||
@ -49,7 +49,7 @@ function createTestProvider(params: {
|
||||
getCredentialValue: readSearchConfigKey,
|
||||
setCredentialValue: (searchConfigTarget, value) => {
|
||||
const providerConfig =
|
||||
params.id === "brave" || params.id === "firecrawl"
|
||||
params.id === "brave" || params.id === "firecrawl" || params.id === "baidu"
|
||||
? searchConfigTarget
|
||||
: ((searchConfigTarget[params.id] ??= {}) as { apiKey?: unknown });
|
||||
providerConfig.apiKey = value;
|
||||
@ -77,6 +77,7 @@ function createTestProvider(params: {
|
||||
|
||||
function buildTestWebSearchProviders(): PluginWebSearchProviderEntry[] {
|
||||
return [
|
||||
createTestProvider({ id: "baidu", pluginId: "baidu", order: 5 }),
|
||||
createTestProvider({ id: "brave", pluginId: "brave", order: 10 }),
|
||||
createTestProvider({ id: "gemini", pluginId: "google", order: 20 }),
|
||||
createTestProvider({ id: "grok", pluginId: "xai", order: 30 }),
|
||||
@ -168,6 +169,9 @@ function buildConfigForOpenClawTarget(entry: SecretRegistryEntry, envId: string)
|
||||
"webhook",
|
||||
);
|
||||
}
|
||||
if (entry.id === "plugins.entries.baidu.config.webSearch.apiKey") {
|
||||
setPathCreateStrict(config, ["tools", "web", "search", "provider"], "baidu");
|
||||
}
|
||||
if (entry.id === "plugins.entries.brave.config.webSearch.apiKey") {
|
||||
setPathCreateStrict(config, ["tools", "web", "search", "provider"], "brave");
|
||||
}
|
||||
|
||||
@ -733,6 +733,17 @@ const SECRET_TARGET_REGISTRY: SecretTargetRegistryEntry[] = [
|
||||
includeInConfigure: true,
|
||||
includeInAudit: true,
|
||||
},
|
||||
{
|
||||
id: "plugins.entries.baidu.config.webSearch.apiKey",
|
||||
targetType: "plugins.entries.baidu.config.webSearch.apiKey",
|
||||
configFile: "openclaw.json",
|
||||
pathPattern: "plugins.entries.baidu.config.webSearch.apiKey",
|
||||
secretShape: SECRET_INPUT_SHAPE,
|
||||
expectedResolvedValue: "string",
|
||||
includeInPlan: true,
|
||||
includeInConfigure: true,
|
||||
includeInAudit: true,
|
||||
},
|
||||
{
|
||||
id: "plugins.entries.brave.config.webSearch.apiKey",
|
||||
targetType: "plugins.entries.brave.config.webSearch.apiKey",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user