diff --git a/src/plugins/web-fetch-providers.runtime.test.ts b/src/plugins/web-fetch-providers.runtime.test.ts index 2739d8e025f..de5630f1e7f 100644 --- a/src/plugins/web-fetch-providers.runtime.test.ts +++ b/src/plugins/web-fetch-providers.runtime.test.ts @@ -133,6 +133,18 @@ describe("resolvePluginWebFetchProviders", () => { expect(loadOpenClawPluginsMock).toHaveBeenCalledTimes(1); }); + it("loads manifest-declared web-fetch providers in setup mode without the plugin loader", () => { + const providers = resolvePluginWebFetchProviders({ + config: createFirecrawlAllowConfig(), + mode: "setup", + }); + + expect(providers.map((provider) => `${provider.pluginId}:${provider.id}`)).toEqual([ + "firecrawl:firecrawl", + ]); + expect(loadOpenClawPluginsMock).not.toHaveBeenCalled(); + }); + it("does not force a fresh snapshot load when the same web-provider load is already in flight", () => { const inFlightSpy = vi .spyOn(loaderModule, "isPluginRegistryLoadInFlight") diff --git a/src/plugins/web-fetch-providers.runtime.ts b/src/plugins/web-fetch-providers.runtime.ts index 52744558f25..4048a5bbeb2 100644 --- a/src/plugins/web-fetch-providers.runtime.ts +++ b/src/plugins/web-fetch-providers.runtime.ts @@ -6,6 +6,7 @@ import { resolveBundledWebFetchResolutionConfig, sortWebFetchProviders, } from "./web-fetch-providers.shared.js"; +import { resolveBundledWebFetchProvidersFromPublicArtifacts } from "./web-provider-public-artifacts.js"; import { mapRegistryProviders, resolveManifestDeclaredWebProviderCandidatePluginIds, @@ -71,6 +72,7 @@ export function resolvePluginWebFetchProviders(params: { resolveBundledResolutionConfig: resolveBundledWebFetchResolutionConfig, resolveCandidatePluginIds: resolveWebFetchCandidatePluginIds, mapRegistryProviders: mapRegistryWebFetchProviders, + resolveBundledPublicArtifactProviders: resolveBundledWebFetchProvidersFromPublicArtifacts, }); } diff --git a/src/plugins/web-provider-runtime-shared.ts b/src/plugins/web-provider-runtime-shared.ts index 2f108d9dbc0..54fa992b1c6 100644 --- a/src/plugins/web-provider-runtime-shared.ts +++ b/src/plugins/web-provider-runtime-shared.ts @@ -67,6 +67,13 @@ type ResolveWebProviderRuntimeDeps = { registry: PluginRegistry; onlyPluginIds?: readonly string[]; }) => TEntry[]; + resolveBundledPublicArtifactProviders?: (params: { + config?: PluginLoadOptions["config"]; + workspaceDir?: string; + env?: PluginLoadOptions["env"]; + bundledAllowlistCompat?: boolean; + onlyPluginIds?: readonly string[]; + }) => TEntry[] | null; }; export function createWebProviderSnapshotCache(): WebProviderSnapshotCache { @@ -132,6 +139,18 @@ export function resolvePluginWebProviders( if (pluginIds.length === 0) { return []; } + if (params.activate !== true) { + const bundledArtifactProviders = deps.resolveBundledPublicArtifactProviders?.({ + config: params.config, + workspaceDir, + env, + bundledAllowlistCompat: params.bundledAllowlistCompat, + onlyPluginIds: pluginIds, + }); + if (bundledArtifactProviders) { + return bundledArtifactProviders; + } + } const registry = loadOpenClawPlugins( buildPluginRuntimeLoadOptionsFromValues( { diff --git a/src/plugins/web-search-providers.runtime.test.ts b/src/plugins/web-search-providers.runtime.test.ts index f7b35a11e41..228d60c1769 100644 --- a/src/plugins/web-search-providers.runtime.test.ts +++ b/src/plugins/web-search-providers.runtime.test.ts @@ -401,19 +401,7 @@ describe("resolvePluginWebSearchProviders", () => { }); expect(toRuntimeProviderKeys(providers)).toEqual(["brave:brave"]); - expect(loadOpenClawPluginsMock).toHaveBeenCalledWith( - expect.objectContaining({ - onlyPluginIds: ["brave"], - config: expect.objectContaining({ - plugins: expect.objectContaining({ - allow: ["perplexity", "brave"], - entries: { - brave: { enabled: true }, - }, - }), - }), - }), - ); + expect(loadOpenClawPluginsMock).not.toHaveBeenCalled(); }); it("loads plugin web-search providers from the auto-enabled config snapshot", () => { diff --git a/src/plugins/web-search-providers.runtime.ts b/src/plugins/web-search-providers.runtime.ts index 1136b2ffe0b..9738fb0fa04 100644 --- a/src/plugins/web-search-providers.runtime.ts +++ b/src/plugins/web-search-providers.runtime.ts @@ -2,6 +2,7 @@ import { loadOpenClawPlugins } from "./loader.js"; import type { PluginLoadOptions } from "./loader.js"; import { type PluginManifestRecord } from "./manifest-registry.js"; import type { PluginWebSearchProviderEntry } from "./types.js"; +import { resolveBundledWebSearchProvidersFromPublicArtifacts } from "./web-provider-public-artifacts.js"; import { mapRegistryProviders, resolveManifestDeclaredWebProviderCandidatePluginIds, @@ -71,6 +72,7 @@ export function resolvePluginWebSearchProviders(params: { resolveBundledResolutionConfig: resolveBundledWebSearchResolutionConfig, resolveCandidatePluginIds: resolveWebSearchCandidatePluginIds, mapRegistryProviders: mapRegistryWebSearchProviders, + resolveBundledPublicArtifactProviders: resolveBundledWebSearchProvidersFromPublicArtifacts, }); } diff --git a/test/helpers/plugins/bundled-web-search-fast-path-contract.ts b/test/helpers/plugins/bundled-web-search-fast-path-contract.ts index 84e40c2a0c5..c7fc787622f 100644 --- a/test/helpers/plugins/bundled-web-search-fast-path-contract.ts +++ b/test/helpers/plugins/bundled-web-search-fast-path-contract.ts @@ -1,6 +1,5 @@ import { describe, expect, it } from "vitest"; import type { OpenClawConfig } from "../../../src/config/config.js"; -import { loadBundledCapabilityRuntimeRegistry } from "../../../src/plugins/bundled-capability-runtime.js"; import { resolveManifestContractOwnerPluginId } from "../../../src/plugins/manifest-registry.js"; import { resolveBundledExplicitWebSearchProvidersFromPublicArtifacts } from "../../../src/plugins/web-provider-public-artifacts.explicit.js"; import { resolvePluginWebSearchProviders } from "../../../src/plugins/web-search-providers.runtime.js"; @@ -95,21 +94,18 @@ export function describeBundledWebSearchFastPathContract(pluginId: string) { } }); - it("keeps fast-path provider metadata aligned with the bundled runtime registry", async () => { + it("keeps fast-path provider metadata aligned with bundled public artifacts", async () => { const fastPathProviders = resolvePluginWebSearchProviders({ origin: "bundled", onlyPluginIds: [pluginId], + mode: "setup", }).filter((provider) => provider.pluginId === pluginId); - const pluginSdkResolution = process.env.VITEST ? "src" : "dist"; - const bundledProviderEntries = loadBundledCapabilityRuntimeRegistry({ - pluginIds: [pluginId], - pluginSdkResolution, - }) - .webSearchProviders.filter((entry) => entry.pluginId === pluginId) - .map((entry) => ({ - pluginId: entry.pluginId, - ...entry.provider, - })); + const bundledProviderEntries = + resolveBundledExplicitWebSearchProvidersFromPublicArtifacts({ + onlyPluginIds: [pluginId], + })?.filter((entry) => entry.pluginId === pluginId) ?? []; + + expect(bundledProviderEntries.length).toBeGreaterThan(0); expect( sortComparableEntries(