mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-05 17:10:20 +00:00
refactor: simplify web provider plugin discovery
This commit is contained in:
@@ -11,30 +11,15 @@ const { resolvePluginWebSearchProvidersMock } = vi.hoisted(() => ({
|
||||
resolvePluginWebSearchProvidersMock: vi.fn(() => buildTestWebSearchProviders()),
|
||||
}));
|
||||
|
||||
const { resolveBundledPluginWebSearchProvidersMock } = vi.hoisted(() => ({
|
||||
resolveBundledPluginWebSearchProvidersMock: vi.fn(() => buildTestWebSearchProviders()),
|
||||
}));
|
||||
|
||||
const { resolvePluginWebFetchProvidersMock } = vi.hoisted(() => ({
|
||||
resolvePluginWebFetchProvidersMock: vi.fn(() => buildTestWebFetchProviders()),
|
||||
}));
|
||||
|
||||
const { resolveBundledPluginWebFetchProvidersMock } = vi.hoisted(() => ({
|
||||
resolveBundledPluginWebFetchProvidersMock: vi.fn(() => buildTestWebFetchProviders()),
|
||||
}));
|
||||
|
||||
let bundledWebSearchProviders: typeof import("../plugins/web-search-providers.js");
|
||||
let runtimeWebSearchProviders: typeof import("../plugins/web-search-providers.runtime.js");
|
||||
let bundledWebFetchProviders: typeof import("../plugins/web-fetch-providers.js");
|
||||
let runtimeWebFetchProviders: typeof import("../plugins/web-fetch-providers.runtime.js");
|
||||
let secretResolve: typeof import("./resolve.js");
|
||||
let createResolverContext: typeof import("./runtime-shared.js").createResolverContext;
|
||||
let resolveRuntimeWebTools: typeof import("./runtime-web-tools.js").resolveRuntimeWebTools;
|
||||
|
||||
vi.mock("../plugins/web-search-providers.js", () => ({
|
||||
resolveBundledPluginWebSearchProviders: resolveBundledPluginWebSearchProvidersMock,
|
||||
}));
|
||||
|
||||
vi.mock("../plugins/web-search-providers.runtime.js", async () => {
|
||||
const actual = await vi.importActual<typeof import("../plugins/web-search-providers.runtime.js")>(
|
||||
"../plugins/web-search-providers.runtime.js",
|
||||
@@ -45,10 +30,6 @@ vi.mock("../plugins/web-search-providers.runtime.js", async () => {
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock("../plugins/web-fetch-providers.js", () => ({
|
||||
resolveBundledPluginWebFetchProviders: resolveBundledPluginWebFetchProvidersMock,
|
||||
}));
|
||||
|
||||
vi.mock("../plugins/web-fetch-providers.runtime.js", async () => {
|
||||
const actual = await vi.importActual<typeof import("../plugins/web-fetch-providers.runtime.js")>(
|
||||
"../plugins/web-fetch-providers.runtime.js",
|
||||
@@ -264,9 +245,7 @@ function expectInactiveWebFetchProviderSecretRef(params: {
|
||||
|
||||
describe("runtime web tools resolution", () => {
|
||||
beforeAll(async () => {
|
||||
bundledWebSearchProviders = await import("../plugins/web-search-providers.js");
|
||||
runtimeWebSearchProviders = await import("../plugins/web-search-providers.runtime.js");
|
||||
bundledWebFetchProviders = await import("../plugins/web-fetch-providers.js");
|
||||
runtimeWebFetchProviders = await import("../plugins/web-fetch-providers.runtime.js");
|
||||
secretResolve = await import("./resolve.js");
|
||||
({ createResolverContext } = await import("./runtime-shared.js"));
|
||||
@@ -275,9 +254,7 @@ describe("runtime web tools resolution", () => {
|
||||
|
||||
beforeEach(() => {
|
||||
runtimeWebSearchProviders.__testing.resetWebSearchProviderSnapshotCacheForTests();
|
||||
vi.mocked(bundledWebSearchProviders.resolveBundledPluginWebSearchProviders).mockClear();
|
||||
vi.mocked(runtimeWebSearchProviders.resolvePluginWebSearchProviders).mockClear();
|
||||
vi.mocked(bundledWebFetchProviders.resolveBundledPluginWebFetchProviders).mockClear();
|
||||
vi.mocked(runtimeWebFetchProviders.resolvePluginWebFetchProviders).mockClear();
|
||||
});
|
||||
|
||||
@@ -665,9 +642,8 @@ describe("runtime web tools resolution", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("uses bundled provider resolution for configured bundled providers", async () => {
|
||||
const bundledSpy = vi.mocked(bundledWebSearchProviders.resolveBundledPluginWebSearchProviders);
|
||||
const genericSpy = vi.mocked(runtimeWebSearchProviders.resolvePluginWebSearchProviders);
|
||||
it("uses bundled-only runtime provider resolution for configured bundled providers", async () => {
|
||||
const runtimeSpy = vi.mocked(runtimeWebSearchProviders.resolvePluginWebSearchProviders);
|
||||
|
||||
const { metadata } = await runRuntimeWebTools({
|
||||
config: asConfig({
|
||||
@@ -698,13 +674,13 @@ describe("runtime web tools resolution", () => {
|
||||
});
|
||||
|
||||
expect(metadata.search.selectedProvider).toBe("gemini");
|
||||
expect(bundledSpy).toHaveBeenCalledWith(
|
||||
expect(runtimeSpy).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
bundledAllowlistCompat: true,
|
||||
onlyPluginIds: ["google"],
|
||||
origin: "bundled",
|
||||
}),
|
||||
);
|
||||
expect(genericSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("does not resolve web fetch provider SecretRef when web fetch is inactive", async () => {
|
||||
@@ -955,7 +931,6 @@ describe("runtime web tools resolution", () => {
|
||||
});
|
||||
|
||||
it("keeps web fetch provider discovery bundled-only during runtime secret resolution", async () => {
|
||||
const bundledSpy = vi.mocked(bundledWebFetchProviders.resolveBundledPluginWebFetchProviders);
|
||||
const runtimeSpy = vi.mocked(runtimeWebFetchProviders.resolvePluginWebFetchProviders);
|
||||
|
||||
const { metadata } = await runRuntimeWebTools({
|
||||
@@ -986,7 +961,11 @@ describe("runtime web tools resolution", () => {
|
||||
});
|
||||
|
||||
expect(metadata.fetch.selectedProvider).toBe("firecrawl");
|
||||
expect(bundledSpy).toHaveBeenCalled();
|
||||
expect(runtimeSpy).not.toHaveBeenCalled();
|
||||
expect(runtimeSpy).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
bundledAllowlistCompat: true,
|
||||
origin: "bundled",
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
import type { OpenClawConfig } from "../config/config.js";
|
||||
import { resolveSecretInputRef } from "../config/types.secrets.js";
|
||||
import { resolveBundledWebFetchPluginId } from "../plugins/bundled-web-fetch-provider-ids.js";
|
||||
import { listBundledWebSearchPluginIds } from "../plugins/bundled-web-search-ids.js";
|
||||
import { resolveBundledWebSearchPluginId } from "../plugins/bundled-web-search-provider-ids.js";
|
||||
import {
|
||||
resolveManifestContractOwnerPluginId,
|
||||
resolveManifestContractPluginIds,
|
||||
} from "../plugins/manifest-registry.js";
|
||||
import type {
|
||||
PluginWebFetchProviderEntry,
|
||||
PluginWebSearchProviderEntry,
|
||||
WebFetchCredentialResolutionSource,
|
||||
WebSearchCredentialResolutionSource,
|
||||
} from "../plugins/types.js";
|
||||
import { resolveBundledPluginWebFetchProviders } from "../plugins/web-fetch-providers.js";
|
||||
import { resolvePluginWebFetchProviders } from "../plugins/web-fetch-providers.runtime.js";
|
||||
import { sortWebFetchProvidersForAutoDetect } from "../plugins/web-fetch-providers.shared.js";
|
||||
import { resolveBundledPluginWebSearchProviders } from "../plugins/web-search-providers.js";
|
||||
import { resolvePluginWebSearchProviders } from "../plugins/web-search-providers.runtime.js";
|
||||
import { sortWebSearchProvidersForAutoDetect } from "../plugins/web-search-providers.shared.js";
|
||||
import { normalizeSecretInput } from "../utils/normalize-secret-input.js";
|
||||
@@ -101,7 +101,14 @@ function hasCustomWebSearchPluginRisk(config: OpenClawConfig): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
const bundledPluginIds = new Set<string>(listBundledWebSearchPluginIds());
|
||||
const bundledPluginIds = new Set<string>(
|
||||
resolveManifestContractPluginIds({
|
||||
contract: "webSearchProviders",
|
||||
origin: "bundled",
|
||||
config,
|
||||
env: process.env,
|
||||
}),
|
||||
);
|
||||
const hasNonBundledPluginId = (pluginId: string) => !bundledPluginIds.has(pluginId.trim());
|
||||
if (Array.isArray(plugins.allow) && plugins.allow.some(hasNonBundledPluginId)) {
|
||||
return true;
|
||||
@@ -364,7 +371,13 @@ export async function resolveRuntimeWebTools(params: {
|
||||
const search = isRecord(web?.search) ? web.search : undefined;
|
||||
const rawProvider =
|
||||
typeof search?.provider === "string" ? search.provider.trim().toLowerCase() : "";
|
||||
const configuredBundledPluginId = resolveBundledWebSearchPluginId(rawProvider);
|
||||
const configuredBundledPluginId = resolveManifestContractOwnerPluginId({
|
||||
contract: "webSearchProviders",
|
||||
value: rawProvider,
|
||||
origin: "bundled",
|
||||
config: params.sourceConfig,
|
||||
env: { ...process.env, ...params.context.env },
|
||||
});
|
||||
|
||||
const searchMetadata: RuntimeWebSearchMetadata = {
|
||||
providerSource: "none",
|
||||
@@ -373,17 +386,19 @@ export async function resolveRuntimeWebTools(params: {
|
||||
|
||||
const searchProviders = sortWebSearchProvidersForAutoDetect(
|
||||
configuredBundledPluginId
|
||||
? resolveBundledPluginWebSearchProviders({
|
||||
? resolvePluginWebSearchProviders({
|
||||
config: params.sourceConfig,
|
||||
env: { ...process.env, ...params.context.env },
|
||||
bundledAllowlistCompat: true,
|
||||
onlyPluginIds: [configuredBundledPluginId],
|
||||
origin: "bundled",
|
||||
})
|
||||
: !hasCustomWebSearchPluginRisk(params.sourceConfig)
|
||||
? resolveBundledPluginWebSearchProviders({
|
||||
? resolvePluginWebSearchProviders({
|
||||
config: params.sourceConfig,
|
||||
env: { ...process.env, ...params.context.env },
|
||||
bundledAllowlistCompat: true,
|
||||
origin: "bundled",
|
||||
})
|
||||
: resolvePluginWebSearchProviders({
|
||||
config: params.sourceConfig,
|
||||
@@ -664,23 +679,31 @@ export async function resolveRuntimeWebTools(params: {
|
||||
const fetch = isRecord(web?.fetch) ? (web.fetch as FetchConfig) : undefined;
|
||||
const rawFetchProvider =
|
||||
typeof fetch?.provider === "string" ? fetch.provider.trim().toLowerCase() : "";
|
||||
const configuredBundledFetchPluginId = resolveBundledWebFetchPluginId(rawFetchProvider);
|
||||
const configuredBundledFetchPluginId = resolveManifestContractOwnerPluginId({
|
||||
contract: "webFetchProviders",
|
||||
value: rawFetchProvider,
|
||||
origin: "bundled",
|
||||
config: params.sourceConfig,
|
||||
env: { ...process.env, ...params.context.env },
|
||||
});
|
||||
const fetchMetadata: RuntimeWebFetchMetadata = {
|
||||
providerSource: "none",
|
||||
diagnostics: [],
|
||||
};
|
||||
const fetchProviders = sortWebFetchProvidersForAutoDetect(
|
||||
configuredBundledFetchPluginId
|
||||
? resolveBundledPluginWebFetchProviders({
|
||||
? resolvePluginWebFetchProviders({
|
||||
config: params.sourceConfig,
|
||||
env: { ...process.env, ...params.context.env },
|
||||
bundledAllowlistCompat: true,
|
||||
onlyPluginIds: [configuredBundledFetchPluginId],
|
||||
origin: "bundled",
|
||||
})
|
||||
: resolveBundledPluginWebFetchProviders({
|
||||
: resolvePluginWebFetchProviders({
|
||||
config: params.sourceConfig,
|
||||
env: { ...process.env, ...params.context.env },
|
||||
bundledAllowlistCompat: true,
|
||||
origin: "bundled",
|
||||
}),
|
||||
);
|
||||
const hasConfiguredFetchSurface =
|
||||
|
||||
@@ -11,32 +11,20 @@ import { listSecretTargetRegistryEntries } from "./target-registry.js";
|
||||
|
||||
type SecretRegistryEntry = ReturnType<typeof listSecretTargetRegistryEntries>[number];
|
||||
|
||||
const { resolveBundledPluginWebSearchProvidersMock, resolvePluginWebSearchProvidersMock } =
|
||||
vi.hoisted(() => ({
|
||||
resolveBundledPluginWebSearchProvidersMock: vi.fn(() => buildTestWebSearchProviders()),
|
||||
resolvePluginWebSearchProvidersMock: vi.fn(() => buildTestWebSearchProviders()),
|
||||
}));
|
||||
const { resolveBundledPluginWebFetchProvidersMock, resolvePluginWebFetchProvidersMock } =
|
||||
vi.hoisted(() => ({
|
||||
resolveBundledPluginWebFetchProvidersMock: vi.fn(() => buildTestWebFetchProviders()),
|
||||
resolvePluginWebFetchProvidersMock: vi.fn(() => buildTestWebFetchProviders()),
|
||||
}));
|
||||
const { resolvePluginWebSearchProvidersMock } = vi.hoisted(() => ({
|
||||
resolvePluginWebSearchProvidersMock: vi.fn(() => buildTestWebSearchProviders()),
|
||||
}));
|
||||
const { resolvePluginWebFetchProvidersMock } = vi.hoisted(() => ({
|
||||
resolvePluginWebFetchProvidersMock: vi.fn(() => buildTestWebFetchProviders()),
|
||||
}));
|
||||
|
||||
let clearSecretsRuntimeSnapshot: typeof import("./runtime.js").clearSecretsRuntimeSnapshot;
|
||||
let prepareSecretsRuntimeSnapshot: typeof import("./runtime.js").prepareSecretsRuntimeSnapshot;
|
||||
|
||||
vi.mock("../plugins/web-search-providers.js", () => ({
|
||||
resolveBundledPluginWebSearchProviders: resolveBundledPluginWebSearchProvidersMock,
|
||||
}));
|
||||
|
||||
vi.mock("../plugins/web-search-providers.runtime.js", () => ({
|
||||
resolvePluginWebSearchProviders: resolvePluginWebSearchProvidersMock,
|
||||
}));
|
||||
|
||||
vi.mock("../plugins/web-fetch-providers.js", () => ({
|
||||
resolveBundledPluginWebFetchProviders: resolveBundledPluginWebFetchProvidersMock,
|
||||
}));
|
||||
|
||||
vi.mock("../plugins/web-fetch-providers.runtime.js", () => ({
|
||||
resolvePluginWebFetchProviders: resolvePluginWebFetchProvidersMock,
|
||||
}));
|
||||
@@ -343,9 +331,7 @@ describe("secrets runtime target coverage", () => {
|
||||
|
||||
afterEach(() => {
|
||||
clearSecretsRuntimeSnapshot();
|
||||
resolveBundledPluginWebSearchProvidersMock.mockReset();
|
||||
resolvePluginWebSearchProvidersMock.mockReset();
|
||||
resolveBundledPluginWebFetchProvidersMock.mockReset();
|
||||
resolvePluginWebFetchProvidersMock.mockReset();
|
||||
});
|
||||
|
||||
|
||||
@@ -10,14 +10,8 @@ import type { PluginWebSearchProviderEntry } from "../plugins/types.js";
|
||||
|
||||
type WebProviderUnderTest = "brave" | "gemini" | "grok" | "kimi" | "perplexity" | "firecrawl";
|
||||
|
||||
const { resolveBundledPluginWebSearchProvidersMock, resolvePluginWebSearchProvidersMock } =
|
||||
vi.hoisted(() => ({
|
||||
resolveBundledPluginWebSearchProvidersMock: vi.fn(() => buildTestWebSearchProviders()),
|
||||
resolvePluginWebSearchProvidersMock: vi.fn(() => buildTestWebSearchProviders()),
|
||||
}));
|
||||
|
||||
vi.mock("../plugins/web-search-providers.js", () => ({
|
||||
resolveBundledPluginWebSearchProviders: resolveBundledPluginWebSearchProvidersMock,
|
||||
const { resolvePluginWebSearchProvidersMock } = vi.hoisted(() => ({
|
||||
resolvePluginWebSearchProvidersMock: vi.fn(() => buildTestWebSearchProviders()),
|
||||
}));
|
||||
|
||||
vi.mock("../plugins/web-search-providers.runtime.js", () => ({
|
||||
@@ -132,8 +126,6 @@ describe("secrets runtime snapshot", () => {
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
resolveBundledPluginWebSearchProvidersMock.mockReset();
|
||||
resolveBundledPluginWebSearchProvidersMock.mockReturnValue(buildTestWebSearchProviders());
|
||||
resolvePluginWebSearchProvidersMock.mockReset();
|
||||
resolvePluginWebSearchProvidersMock.mockReturnValue(buildTestWebSearchProviders());
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user