




















@@ -3,14 +3,183 @@ import path from "node:path";
33import { afterAll, beforeAll, describe, expect, it, vi } from "vitest";
44import type { AuthProfileStore } from "../agents/auth-profiles.js";
55import type { OpenClawConfig } from "../config/config.js";
6-import type { PluginOrigin } from "../plugins/types.js";
6+import type {
7+PluginOrigin,
8+PluginWebFetchProviderEntry,
9+PluginWebSearchProviderEntry,
10+} from "../plugins/types.js";
711import { getPath, setPathCreateStrict } from "./path-utils.js";
812import { canonicalizeSecretTargetCoverageId } from "./target-registry-test-helpers.js";
9131014vi.mock("../plugins/installed-plugin-index-records.js", () => ({
1115loadInstalledPluginIndexInstallRecordsSync: () => ({}),
1216}));
131718+function createCoverageWebSearchProvider(params: {
19+pluginId: string;
20+id: string;
21+envVar: string;
22+order: number;
23+}): PluginWebSearchProviderEntry {
24+const credentialPath = `plugins.entries.${params.pluginId}.config.webSearch.apiKey`;
25+const readConfiguredCredential = (config?: OpenClawConfig): unknown =>
26+(config?.plugins?.entries?.[params.pluginId]?.config as { webSearch?: { apiKey?: unknown } })
27+?.webSearch?.apiKey;
28+return {
29+pluginId: params.pluginId,
30+id: params.id,
31+label: params.id,
32+hint: `${params.id} coverage provider`,
33+envVars: [params.envVar],
34+placeholder: `${params.id}-key`,
35+signupUrl: `https://example.com/${params.id}`,
36+autoDetectOrder: params.order,
37+ credentialPath,
38+inactiveSecretPaths: [credentialPath],
39+getCredentialValue: () => undefined,
40+setCredentialValue: () => {},
41+getConfiguredCredentialValue: readConfiguredCredential,
42+setConfiguredCredentialValue: (configTarget, value) => {
43+setPathCreateStrict(
44+configTarget,
45+["plugins", "entries", params.pluginId, "config", "webSearch", "apiKey"],
46+value,
47+);
48+},
49+createTool: () => null,
50+};
51+}
52+53+function createCoverageWebFetchProvider(params: {
54+pluginId: string;
55+id: string;
56+envVar: string;
57+}): PluginWebFetchProviderEntry {
58+const credentialPath = `plugins.entries.${params.pluginId}.config.webFetch.apiKey`;
59+const readConfiguredCredential = (config?: OpenClawConfig): unknown =>
60+(config?.plugins?.entries?.[params.pluginId]?.config as { webFetch?: { apiKey?: unknown } })
61+?.webFetch?.apiKey;
62+return {
63+pluginId: params.pluginId,
64+id: params.id,
65+label: params.id,
66+hint: `${params.id} coverage fetch provider`,
67+envVars: [params.envVar],
68+placeholder: `${params.id}-key`,
69+signupUrl: `https://example.com/${params.id}`,
70+autoDetectOrder: 10,
71+ credentialPath,
72+inactiveSecretPaths: [credentialPath],
73+getCredentialValue: () => undefined,
74+setCredentialValue: () => {},
75+getConfiguredCredentialValue: readConfiguredCredential,
76+setConfiguredCredentialValue: (configTarget, value) => {
77+setPathCreateStrict(
78+configTarget,
79+["plugins", "entries", params.pluginId, "config", "webFetch", "apiKey"],
80+value,
81+);
82+},
83+createTool: () => null,
84+};
85+}
86+87+const COVERAGE_WEB_SEARCH_PROVIDERS = new Map(
88+[
89+createCoverageWebSearchProvider({
90+pluginId: "brave",
91+id: "brave",
92+envVar: "BRAVE_API_KEY",
93+order: 10,
94+}),
95+createCoverageWebSearchProvider({
96+pluginId: "google",
97+id: "gemini",
98+envVar: "GEMINI_API_KEY",
99+order: 20,
100+}),
101+createCoverageWebSearchProvider({
102+pluginId: "xai",
103+id: "grok",
104+envVar: "XAI_API_KEY",
105+order: 30,
106+}),
107+createCoverageWebSearchProvider({
108+pluginId: "moonshot",
109+id: "kimi",
110+envVar: "MOONSHOT_API_KEY",
111+order: 40,
112+}),
113+createCoverageWebSearchProvider({
114+pluginId: "perplexity",
115+id: "perplexity",
116+envVar: "PERPLEXITY_API_KEY",
117+order: 50,
118+}),
119+createCoverageWebSearchProvider({
120+pluginId: "firecrawl",
121+id: "firecrawl",
122+envVar: "FIRECRAWL_API_KEY",
123+order: 60,
124+}),
125+createCoverageWebSearchProvider({
126+pluginId: "exa",
127+id: "exa",
128+envVar: "EXA_API_KEY",
129+order: 65,
130+}),
131+createCoverageWebSearchProvider({
132+pluginId: "minimax",
133+id: "minimax",
134+envVar: "MINIMAX_API_KEY",
135+order: 70,
136+}),
137+createCoverageWebSearchProvider({
138+pluginId: "tavily",
139+id: "tavily",
140+envVar: "TAVILY_API_KEY",
141+order: 80,
142+}),
143+].map((provider) => [provider.pluginId, provider]),
144+);
145+146+const COVERAGE_WEB_FETCH_PROVIDERS = new Map(
147+[
148+createCoverageWebFetchProvider({
149+pluginId: "firecrawl",
150+id: "firecrawl",
151+envVar: "FIRECRAWL_API_KEY",
152+}),
153+].map((provider) => [provider.pluginId, provider]),
154+);
155+156+vi.mock("../plugins/web-provider-public-artifacts.explicit.js", () => ({
157+resolveBundledExplicitWebFetchProvidersFromPublicArtifacts: (params: {
158+onlyPluginIds: readonly string[];
159+}) => {
160+const providers = params.onlyPluginIds.map((pluginId) =>
161+COVERAGE_WEB_FETCH_PROVIDERS.get(pluginId),
162+);
163+return providers.every(
164+(provider): provider is PluginWebFetchProviderEntry => provider !== undefined,
165+)
166+ ? providers
167+ : null;
168+},
169+resolveBundledExplicitWebSearchProvidersFromPublicArtifacts: (params: {
170+onlyPluginIds: readonly string[];
171+}) => {
172+const providers = params.onlyPluginIds.map((pluginId) =>
173+COVERAGE_WEB_SEARCH_PROVIDERS.get(pluginId),
174+);
175+return providers.every(
176+(provider): provider is PluginWebSearchProviderEntry => provider !== undefined,
177+)
178+ ? providers
179+ : null;
180+},
181+}));
182+14183type SecretRegistryEntry = {
15184id: string;
16185configFile: "openclaw.json" | "auth-profiles.json";
@@ -159,6 +328,23 @@ function buildCoverageLoadablePluginOrigins(
159328return origins;
160329}
161330331+function resolveCoverageLoadablePluginOrigins(
332+entries: readonly SecretRegistryEntry[],
333+): ReadonlyMap<string, PluginOrigin> | undefined {
334+const origins = new Map<string, PluginOrigin>();
335+for (const entry of entries) {
336+if (!entry.id.startsWith("plugins.entries.")) {
337+continue;
338+}
339+const pluginId = entry.id.split(".")[2];
340+const origin = pluginId ? COVERAGE_LOADABLE_PLUGIN_ORIGINS.get(pluginId) : undefined;
341+if (pluginId && origin) {
342+origins.set(pluginId, origin);
343+}
344+}
345+return origins.size > 0 ? origins : undefined;
346+}
347+162348function resolveCoverageBatchKey(entry: SecretRegistryEntry): string {
163349if (entry.id.startsWith("agents.defaults.")) {
164350return entry.id;
@@ -569,7 +755,7 @@ async function expectOpenClawCoverageEntriesResolved(
569755const snapshot = await prepareConfigCoverageSnapshot({
570756 config,
571757 env,
572-loadablePluginOrigins: COVERAGE_LOADABLE_PLUGIN_ORIGINS,
758+loadablePluginOrigins: resolveCoverageLoadablePluginOrigins(batch),
573759includeRuntimeWebTools: batchNeedsRuntimeWebTools(batch),
574760skipConfigCollectors: batchUsesRuntimeWebToolsOnly(batch),
575761});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。