mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-30 19:50:23 +00:00
fix(web-search): split runtime provider resolution
This commit is contained in:
129
src/plugins/web-search-providers.runtime.test.ts
Normal file
129
src/plugins/web-search-providers.runtime.test.ts
Normal file
@@ -0,0 +1,129 @@
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { createEmptyPluginRegistry } from "./registry.js";
|
||||
import { setActivePluginRegistry } from "./runtime.js";
|
||||
import {
|
||||
resolvePluginWebSearchProviders,
|
||||
resolveRuntimeWebSearchProviders,
|
||||
} from "./web-search-providers.runtime.js";
|
||||
|
||||
const BUNDLED_WEB_SEARCH_PROVIDERS = [
|
||||
{ pluginId: "brave", id: "brave", order: 10 },
|
||||
{ pluginId: "google", id: "gemini", order: 20 },
|
||||
{ pluginId: "xai", id: "grok", order: 30 },
|
||||
{ pluginId: "moonshot", id: "kimi", order: 40 },
|
||||
{ pluginId: "perplexity", id: "perplexity", order: 50 },
|
||||
{ pluginId: "firecrawl", id: "firecrawl", order: 60 },
|
||||
{ pluginId: "tavily", id: "tavily", order: 70 },
|
||||
] as const;
|
||||
|
||||
const { loadOpenClawPluginsMock } = vi.hoisted(() => ({
|
||||
loadOpenClawPluginsMock: vi.fn((params?: { config?: { plugins?: Record<string, unknown> } }) => {
|
||||
const plugins = params?.config?.plugins as
|
||||
| {
|
||||
enabled?: boolean;
|
||||
allow?: string[];
|
||||
entries?: Record<string, { enabled?: boolean }>;
|
||||
}
|
||||
| undefined;
|
||||
if (plugins?.enabled === false) {
|
||||
return { webSearchProviders: [] };
|
||||
}
|
||||
const allow = Array.isArray(plugins?.allow) && plugins.allow.length > 0 ? plugins.allow : null;
|
||||
const entries = plugins?.entries ?? {};
|
||||
const webSearchProviders = BUNDLED_WEB_SEARCH_PROVIDERS.filter((provider) => {
|
||||
if (allow && !allow.includes(provider.pluginId)) {
|
||||
return false;
|
||||
}
|
||||
if (entries[provider.pluginId]?.enabled === false) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}).map((provider) => ({
|
||||
pluginId: provider.pluginId,
|
||||
pluginName: provider.pluginId,
|
||||
source: "test" as const,
|
||||
provider: {
|
||||
id: provider.id,
|
||||
label: provider.id,
|
||||
hint: `${provider.id} provider`,
|
||||
envVars: [`${provider.id.toUpperCase()}_API_KEY`],
|
||||
placeholder: `${provider.id}-...`,
|
||||
signupUrl: `https://example.com/${provider.id}`,
|
||||
autoDetectOrder: provider.order,
|
||||
credentialPath: `plugins.entries.${provider.pluginId}.config.webSearch.apiKey`,
|
||||
getCredentialValue: () => "configured",
|
||||
setCredentialValue: () => {},
|
||||
createTool: () => ({
|
||||
description: provider.id,
|
||||
parameters: {},
|
||||
execute: async () => ({}),
|
||||
}),
|
||||
},
|
||||
}));
|
||||
return { webSearchProviders };
|
||||
}),
|
||||
}));
|
||||
|
||||
vi.mock("./loader.js", () => ({
|
||||
loadOpenClawPlugins: loadOpenClawPluginsMock,
|
||||
}));
|
||||
|
||||
describe("resolvePluginWebSearchProviders", () => {
|
||||
beforeEach(() => {
|
||||
loadOpenClawPluginsMock.mockClear();
|
||||
setActivePluginRegistry(createEmptyPluginRegistry());
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
setActivePluginRegistry(createEmptyPluginRegistry());
|
||||
});
|
||||
|
||||
it("loads bundled providers through the plugin loader in auto-detect order", () => {
|
||||
const providers = resolvePluginWebSearchProviders({});
|
||||
|
||||
expect(providers.map((provider) => `${provider.pluginId}:${provider.id}`)).toEqual([
|
||||
"brave:brave",
|
||||
"google:gemini",
|
||||
"xai:grok",
|
||||
"moonshot:kimi",
|
||||
"perplexity:perplexity",
|
||||
"firecrawl:firecrawl",
|
||||
"tavily:tavily",
|
||||
]);
|
||||
expect(loadOpenClawPluginsMock).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("prefers the active plugin registry for runtime resolution", () => {
|
||||
const registry = createEmptyPluginRegistry();
|
||||
registry.webSearchProviders.push({
|
||||
pluginId: "custom-search",
|
||||
pluginName: "Custom Search",
|
||||
provider: {
|
||||
id: "custom",
|
||||
label: "Custom Search",
|
||||
hint: "Custom runtime provider",
|
||||
envVars: ["CUSTOM_SEARCH_API_KEY"],
|
||||
placeholder: "custom-...",
|
||||
signupUrl: "https://example.com/signup",
|
||||
autoDetectOrder: 1,
|
||||
credentialPath: "tools.web.search.custom.apiKey",
|
||||
getCredentialValue: () => "configured",
|
||||
setCredentialValue: () => {},
|
||||
createTool: () => ({
|
||||
description: "custom",
|
||||
parameters: {},
|
||||
execute: async () => ({}),
|
||||
}),
|
||||
},
|
||||
source: "test",
|
||||
});
|
||||
setActivePluginRegistry(registry);
|
||||
|
||||
const providers = resolveRuntimeWebSearchProviders({});
|
||||
|
||||
expect(providers.map((provider) => `${provider.pluginId}:${provider.id}`)).toEqual([
|
||||
"custom-search:custom",
|
||||
]);
|
||||
expect(loadOpenClawPluginsMock).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
56
src/plugins/web-search-providers.runtime.ts
Normal file
56
src/plugins/web-search-providers.runtime.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
import { createSubsystemLogger } from "../logging/subsystem.js";
|
||||
import { loadOpenClawPlugins } from "./loader.js";
|
||||
import type { PluginLoadOptions } from "./loader.js";
|
||||
import { createPluginLoaderLogger } from "./logger.js";
|
||||
import { getActivePluginRegistry } from "./runtime.js";
|
||||
import type { PluginWebSearchProviderEntry } from "./types.js";
|
||||
import {
|
||||
resolveBundledWebSearchResolutionConfig,
|
||||
sortWebSearchProviders,
|
||||
} from "./web-search-providers.shared.js";
|
||||
|
||||
const log = createSubsystemLogger("plugins");
|
||||
|
||||
export function resolvePluginWebSearchProviders(params: {
|
||||
config?: PluginLoadOptions["config"];
|
||||
workspaceDir?: string;
|
||||
env?: PluginLoadOptions["env"];
|
||||
bundledAllowlistCompat?: boolean;
|
||||
activate?: boolean;
|
||||
cache?: boolean;
|
||||
}): PluginWebSearchProviderEntry[] {
|
||||
const { config } = resolveBundledWebSearchResolutionConfig(params);
|
||||
const registry = loadOpenClawPlugins({
|
||||
config,
|
||||
workspaceDir: params.workspaceDir,
|
||||
env: params.env,
|
||||
cache: params.cache ?? false,
|
||||
activate: params.activate ?? false,
|
||||
logger: createPluginLoaderLogger(log),
|
||||
});
|
||||
|
||||
return sortWebSearchProviders(
|
||||
registry.webSearchProviders.map((entry) => ({
|
||||
...entry.provider,
|
||||
pluginId: entry.pluginId,
|
||||
})),
|
||||
);
|
||||
}
|
||||
|
||||
export function resolveRuntimeWebSearchProviders(params: {
|
||||
config?: PluginLoadOptions["config"];
|
||||
workspaceDir?: string;
|
||||
env?: PluginLoadOptions["env"];
|
||||
bundledAllowlistCompat?: boolean;
|
||||
}): PluginWebSearchProviderEntry[] {
|
||||
const runtimeProviders = getActivePluginRegistry()?.webSearchProviders ?? [];
|
||||
if (runtimeProviders.length > 0) {
|
||||
return sortWebSearchProviders(
|
||||
runtimeProviders.map((entry) => ({
|
||||
...entry.provider,
|
||||
pluginId: entry.pluginId,
|
||||
})),
|
||||
);
|
||||
}
|
||||
return resolvePluginWebSearchProviders(params);
|
||||
}
|
||||
120
src/plugins/web-search-providers.shared.ts
Normal file
120
src/plugins/web-search-providers.shared.ts
Normal file
@@ -0,0 +1,120 @@
|
||||
import {
|
||||
withBundledPluginAllowlistCompat,
|
||||
withBundledPluginEnablementCompat,
|
||||
} from "./bundled-compat.js";
|
||||
import { resolveBundledWebSearchPluginIds } from "./bundled-web-search.js";
|
||||
import { normalizePluginsConfig, type NormalizedPluginsConfig } from "./config-state.js";
|
||||
import type { PluginLoadOptions } from "./loader.js";
|
||||
import type { PluginWebSearchProviderEntry } from "./types.js";
|
||||
|
||||
export function hasExplicitPluginConfig(config: PluginLoadOptions["config"]): boolean {
|
||||
const plugins = config?.plugins;
|
||||
if (!plugins) {
|
||||
return false;
|
||||
}
|
||||
if (typeof plugins.enabled === "boolean") {
|
||||
return true;
|
||||
}
|
||||
if (Array.isArray(plugins.allow) && plugins.allow.length > 0) {
|
||||
return true;
|
||||
}
|
||||
if (Array.isArray(plugins.deny) && plugins.deny.length > 0) {
|
||||
return true;
|
||||
}
|
||||
if (Array.isArray(plugins.load?.paths) && plugins.load.paths.length > 0) {
|
||||
return true;
|
||||
}
|
||||
if (plugins.entries && Object.keys(plugins.entries).length > 0) {
|
||||
return true;
|
||||
}
|
||||
if (plugins.slots && Object.keys(plugins.slots).length > 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function resolveBundledWebSearchCompatPluginIds(params: {
|
||||
config?: PluginLoadOptions["config"];
|
||||
workspaceDir?: string;
|
||||
env?: PluginLoadOptions["env"];
|
||||
}): string[] {
|
||||
return resolveBundledWebSearchPluginIds({
|
||||
config: params.config,
|
||||
workspaceDir: params.workspaceDir,
|
||||
env: params.env,
|
||||
});
|
||||
}
|
||||
|
||||
function withBundledWebSearchVitestCompat(params: {
|
||||
config: PluginLoadOptions["config"];
|
||||
pluginIds: readonly string[];
|
||||
env?: PluginLoadOptions["env"];
|
||||
}): PluginLoadOptions["config"] {
|
||||
const env = params.env ?? process.env;
|
||||
const isVitest = Boolean(env.VITEST || process.env.VITEST);
|
||||
if (!isVitest || hasExplicitPluginConfig(params.config) || params.pluginIds.length === 0) {
|
||||
return params.config;
|
||||
}
|
||||
|
||||
return {
|
||||
...params.config,
|
||||
plugins: {
|
||||
...params.config?.plugins,
|
||||
enabled: true,
|
||||
allow: [...params.pluginIds],
|
||||
slots: {
|
||||
...params.config?.plugins?.slots,
|
||||
memory: "none",
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function sortWebSearchProviders(
|
||||
providers: PluginWebSearchProviderEntry[],
|
||||
): PluginWebSearchProviderEntry[] {
|
||||
return providers.toSorted((a, b) => {
|
||||
const aOrder = a.autoDetectOrder ?? Number.MAX_SAFE_INTEGER;
|
||||
const bOrder = b.autoDetectOrder ?? Number.MAX_SAFE_INTEGER;
|
||||
if (aOrder !== bOrder) {
|
||||
return aOrder - bOrder;
|
||||
}
|
||||
return a.id.localeCompare(b.id);
|
||||
});
|
||||
}
|
||||
|
||||
export function resolveBundledWebSearchResolutionConfig(params: {
|
||||
config?: PluginLoadOptions["config"];
|
||||
workspaceDir?: string;
|
||||
env?: PluginLoadOptions["env"];
|
||||
bundledAllowlistCompat?: boolean;
|
||||
}): {
|
||||
config: PluginLoadOptions["config"];
|
||||
normalized: NormalizedPluginsConfig;
|
||||
} {
|
||||
const bundledCompatPluginIds = resolveBundledWebSearchCompatPluginIds({
|
||||
config: params.config,
|
||||
workspaceDir: params.workspaceDir,
|
||||
env: params.env,
|
||||
});
|
||||
const allowlistCompat = params.bundledAllowlistCompat
|
||||
? withBundledPluginAllowlistCompat({
|
||||
config: params.config,
|
||||
pluginIds: bundledCompatPluginIds,
|
||||
})
|
||||
: params.config;
|
||||
const enablementCompat = withBundledPluginEnablementCompat({
|
||||
config: allowlistCompat,
|
||||
pluginIds: bundledCompatPluginIds,
|
||||
});
|
||||
const config = withBundledWebSearchVitestCompat({
|
||||
config: enablementCompat,
|
||||
pluginIds: bundledCompatPluginIds,
|
||||
env: params.env,
|
||||
});
|
||||
|
||||
return {
|
||||
config,
|
||||
normalized: normalizePluginsConfig(config?.plugins),
|
||||
};
|
||||
}
|
||||
@@ -1,94 +1,9 @@
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import type { OpenClawConfig } from "../config/config.js";
|
||||
import { createEmptyPluginRegistry } from "./registry.js";
|
||||
import { setActivePluginRegistry } from "./runtime.js";
|
||||
import {
|
||||
resolveBundledPluginWebSearchProviders,
|
||||
resolvePluginWebSearchProviders,
|
||||
resolveRuntimeWebSearchProviders,
|
||||
} from "./web-search-providers.js";
|
||||
|
||||
const BUNDLED_WEB_SEARCH_PROVIDERS = [
|
||||
{ pluginId: "brave", id: "brave", order: 10 },
|
||||
{ pluginId: "google", id: "gemini", order: 20 },
|
||||
{ pluginId: "xai", id: "grok", order: 30 },
|
||||
{ pluginId: "moonshot", id: "kimi", order: 40 },
|
||||
{ pluginId: "perplexity", id: "perplexity", order: 50 },
|
||||
{ pluginId: "firecrawl", id: "firecrawl", order: 60 },
|
||||
{ pluginId: "tavily", id: "tavily", order: 70 },
|
||||
] as const;
|
||||
|
||||
const { loadOpenClawPluginsMock } = vi.hoisted(() => ({
|
||||
loadOpenClawPluginsMock: vi.fn((params?: { config?: { plugins?: Record<string, unknown> } }) => {
|
||||
const plugins = params?.config?.plugins as
|
||||
| {
|
||||
enabled?: boolean;
|
||||
allow?: string[];
|
||||
entries?: Record<string, { enabled?: boolean }>;
|
||||
}
|
||||
| undefined;
|
||||
if (plugins?.enabled === false) {
|
||||
return { webSearchProviders: [] };
|
||||
}
|
||||
const allow = Array.isArray(plugins?.allow) && plugins.allow.length > 0 ? plugins.allow : null;
|
||||
const entries = plugins?.entries ?? {};
|
||||
const webSearchProviders = BUNDLED_WEB_SEARCH_PROVIDERS.filter((provider) => {
|
||||
if (allow && !allow.includes(provider.pluginId)) {
|
||||
return false;
|
||||
}
|
||||
if (entries[provider.pluginId]?.enabled === false) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}).map((provider) => ({
|
||||
pluginId: provider.pluginId,
|
||||
pluginName: provider.pluginId,
|
||||
source: "test" as const,
|
||||
provider: {
|
||||
id: provider.id,
|
||||
label: provider.id,
|
||||
hint: `${provider.id} provider`,
|
||||
envVars: [`${provider.id.toUpperCase()}_API_KEY`],
|
||||
placeholder: `${provider.id}-...`,
|
||||
signupUrl: `https://example.com/${provider.id}`,
|
||||
autoDetectOrder: provider.order,
|
||||
credentialPath: `plugins.entries.${provider.pluginId}.config.webSearch.apiKey`,
|
||||
getCredentialValue: () => "configured",
|
||||
setCredentialValue: () => {},
|
||||
applySelectionConfig:
|
||||
provider.id === "firecrawl" ? (config: OpenClawConfig) => config : undefined,
|
||||
resolveRuntimeMetadata:
|
||||
provider.id === "perplexity"
|
||||
? () => ({
|
||||
perplexityTransport: "search_api" as const,
|
||||
})
|
||||
: undefined,
|
||||
createTool: () => ({
|
||||
description: provider.id,
|
||||
parameters: {},
|
||||
execute: async () => ({}),
|
||||
}),
|
||||
},
|
||||
}));
|
||||
return { webSearchProviders };
|
||||
}),
|
||||
}));
|
||||
|
||||
vi.mock("./loader.js", () => ({
|
||||
loadOpenClawPlugins: loadOpenClawPluginsMock,
|
||||
}));
|
||||
|
||||
describe("resolvePluginWebSearchProviders", () => {
|
||||
beforeEach(() => {
|
||||
loadOpenClawPluginsMock.mockClear();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
setActivePluginRegistry(createEmptyPluginRegistry());
|
||||
});
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { resolveBundledPluginWebSearchProviders } from "./web-search-providers.js";
|
||||
|
||||
describe("resolveBundledPluginWebSearchProviders", () => {
|
||||
it("returns bundled providers in auto-detect order", () => {
|
||||
const providers = resolvePluginWebSearchProviders({});
|
||||
const providers = resolveBundledPluginWebSearchProviders({});
|
||||
|
||||
expect(providers.map((provider) => `${provider.pluginId}:${provider.id}`)).toEqual([
|
||||
"brave:brave",
|
||||
@@ -117,7 +32,7 @@ describe("resolvePluginWebSearchProviders", () => {
|
||||
});
|
||||
|
||||
it("can augment restrictive allowlists for bundled compatibility", () => {
|
||||
const providers = resolvePluginWebSearchProviders({
|
||||
const providers = resolveBundledPluginWebSearchProviders({
|
||||
config: {
|
||||
plugins: {
|
||||
allow: ["openrouter"],
|
||||
@@ -138,7 +53,7 @@ describe("resolvePluginWebSearchProviders", () => {
|
||||
});
|
||||
|
||||
it("does not return bundled providers excluded by a restrictive allowlist without compat", () => {
|
||||
const providers = resolvePluginWebSearchProviders({
|
||||
const providers = resolveBundledPluginWebSearchProviders({
|
||||
config: {
|
||||
plugins: {
|
||||
allow: ["openrouter"],
|
||||
@@ -150,7 +65,7 @@ describe("resolvePluginWebSearchProviders", () => {
|
||||
});
|
||||
|
||||
it("preserves explicit bundled provider entry state", () => {
|
||||
const providers = resolvePluginWebSearchProviders({
|
||||
const providers = resolveBundledPluginWebSearchProviders({
|
||||
config: {
|
||||
plugins: {
|
||||
entries: {
|
||||
@@ -164,7 +79,7 @@ describe("resolvePluginWebSearchProviders", () => {
|
||||
});
|
||||
|
||||
it("returns no providers when plugins are globally disabled", () => {
|
||||
const providers = resolvePluginWebSearchProviders({
|
||||
const providers = resolveBundledPluginWebSearchProviders({
|
||||
config: {
|
||||
plugins: {
|
||||
enabled: false,
|
||||
@@ -189,7 +104,6 @@ describe("resolvePluginWebSearchProviders", () => {
|
||||
"firecrawl:firecrawl",
|
||||
"tavily:tavily",
|
||||
]);
|
||||
expect(loadOpenClawPluginsMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("can scope bundled resolution to one plugin id", () => {
|
||||
@@ -210,39 +124,5 @@ describe("resolvePluginWebSearchProviders", () => {
|
||||
expect(providers.map((provider) => `${provider.pluginId}:${provider.id}`)).toEqual([
|
||||
"google:gemini",
|
||||
]);
|
||||
expect(loadOpenClawPluginsMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("prefers the active plugin registry for runtime resolution", () => {
|
||||
const registry = createEmptyPluginRegistry();
|
||||
registry.webSearchProviders.push({
|
||||
pluginId: "custom-search",
|
||||
pluginName: "Custom Search",
|
||||
provider: {
|
||||
id: "custom",
|
||||
label: "Custom Search",
|
||||
hint: "Custom runtime provider",
|
||||
envVars: ["CUSTOM_SEARCH_API_KEY"],
|
||||
placeholder: "custom-...",
|
||||
signupUrl: "https://example.com/signup",
|
||||
autoDetectOrder: 1,
|
||||
credentialPath: "tools.web.search.custom.apiKey",
|
||||
getCredentialValue: () => "configured",
|
||||
setCredentialValue: () => {},
|
||||
createTool: () => ({
|
||||
description: "custom",
|
||||
parameters: {},
|
||||
execute: async () => ({}),
|
||||
}),
|
||||
},
|
||||
source: "test",
|
||||
});
|
||||
setActivePluginRegistry(registry);
|
||||
|
||||
const providers = resolveRuntimeWebSearchProviders({});
|
||||
|
||||
expect(providers.map((provider) => `${provider.pluginId}:${provider.id}`)).toEqual([
|
||||
"custom-search:custom",
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,135 +1,11 @@
|
||||
import { createSubsystemLogger } from "../logging/subsystem.js";
|
||||
import {
|
||||
withBundledPluginAllowlistCompat,
|
||||
withBundledPluginEnablementCompat,
|
||||
} from "./bundled-compat.js";
|
||||
import {
|
||||
listBundledWebSearchProviders as listBundledWebSearchProviderEntries,
|
||||
resolveBundledWebSearchPluginIds,
|
||||
} from "./bundled-web-search.js";
|
||||
import {
|
||||
normalizePluginsConfig,
|
||||
resolveEffectiveEnableState,
|
||||
type NormalizedPluginsConfig,
|
||||
} from "./config-state.js";
|
||||
import { loadOpenClawPlugins, type PluginLoadOptions } from "./loader.js";
|
||||
import { createPluginLoaderLogger } from "./logger.js";
|
||||
import { getActivePluginRegistry } from "./runtime.js";
|
||||
import { listBundledWebSearchProviders as listBundledWebSearchProviderEntries } from "./bundled-web-search.js";
|
||||
import { resolveEffectiveEnableState } from "./config-state.js";
|
||||
import type { PluginLoadOptions } from "./loader.js";
|
||||
import type { PluginWebSearchProviderEntry } from "./types.js";
|
||||
|
||||
const log = createSubsystemLogger("plugins");
|
||||
|
||||
function hasExplicitPluginConfig(config: PluginLoadOptions["config"]): boolean {
|
||||
const plugins = config?.plugins;
|
||||
if (!plugins) {
|
||||
return false;
|
||||
}
|
||||
if (typeof plugins.enabled === "boolean") {
|
||||
return true;
|
||||
}
|
||||
if (Array.isArray(plugins.allow) && plugins.allow.length > 0) {
|
||||
return true;
|
||||
}
|
||||
if (Array.isArray(plugins.deny) && plugins.deny.length > 0) {
|
||||
return true;
|
||||
}
|
||||
if (Array.isArray(plugins.load?.paths) && plugins.load.paths.length > 0) {
|
||||
return true;
|
||||
}
|
||||
if (plugins.entries && Object.keys(plugins.entries).length > 0) {
|
||||
return true;
|
||||
}
|
||||
if (plugins.slots && Object.keys(plugins.slots).length > 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function resolveBundledWebSearchCompatPluginIds(params: {
|
||||
config?: PluginLoadOptions["config"];
|
||||
workspaceDir?: string;
|
||||
env?: PluginLoadOptions["env"];
|
||||
}): string[] {
|
||||
return resolveBundledWebSearchPluginIds({
|
||||
config: params.config,
|
||||
workspaceDir: params.workspaceDir,
|
||||
env: params.env,
|
||||
});
|
||||
}
|
||||
|
||||
function withBundledWebSearchVitestCompat(params: {
|
||||
config: PluginLoadOptions["config"];
|
||||
pluginIds: readonly string[];
|
||||
env?: PluginLoadOptions["env"];
|
||||
}): PluginLoadOptions["config"] {
|
||||
const env = params.env ?? process.env;
|
||||
const isVitest = Boolean(env.VITEST || process.env.VITEST);
|
||||
if (!isVitest || hasExplicitPluginConfig(params.config) || params.pluginIds.length === 0) {
|
||||
return params.config;
|
||||
}
|
||||
|
||||
return {
|
||||
...params.config,
|
||||
plugins: {
|
||||
...params.config?.plugins,
|
||||
enabled: true,
|
||||
allow: [...params.pluginIds],
|
||||
slots: {
|
||||
...params.config?.plugins?.slots,
|
||||
memory: "none",
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function sortWebSearchProviders(
|
||||
providers: PluginWebSearchProviderEntry[],
|
||||
): PluginWebSearchProviderEntry[] {
|
||||
return providers.toSorted((a, b) => {
|
||||
const aOrder = a.autoDetectOrder ?? Number.MAX_SAFE_INTEGER;
|
||||
const bOrder = b.autoDetectOrder ?? Number.MAX_SAFE_INTEGER;
|
||||
if (aOrder !== bOrder) {
|
||||
return aOrder - bOrder;
|
||||
}
|
||||
return a.id.localeCompare(b.id);
|
||||
});
|
||||
}
|
||||
|
||||
function resolveBundledWebSearchResolutionConfig(params: {
|
||||
config?: PluginLoadOptions["config"];
|
||||
workspaceDir?: string;
|
||||
env?: PluginLoadOptions["env"];
|
||||
bundledAllowlistCompat?: boolean;
|
||||
}): {
|
||||
config: PluginLoadOptions["config"];
|
||||
normalized: NormalizedPluginsConfig;
|
||||
} {
|
||||
const bundledCompatPluginIds = resolveBundledWebSearchCompatPluginIds({
|
||||
config: params.config,
|
||||
workspaceDir: params.workspaceDir,
|
||||
env: params.env,
|
||||
});
|
||||
const allowlistCompat = params.bundledAllowlistCompat
|
||||
? withBundledPluginAllowlistCompat({
|
||||
config: params.config,
|
||||
pluginIds: bundledCompatPluginIds,
|
||||
})
|
||||
: params.config;
|
||||
const enablementCompat = withBundledPluginEnablementCompat({
|
||||
config: allowlistCompat,
|
||||
pluginIds: bundledCompatPluginIds,
|
||||
});
|
||||
const config = withBundledWebSearchVitestCompat({
|
||||
config: enablementCompat,
|
||||
pluginIds: bundledCompatPluginIds,
|
||||
env: params.env,
|
||||
});
|
||||
|
||||
return {
|
||||
config,
|
||||
normalized: normalizePluginsConfig(config?.plugins),
|
||||
};
|
||||
}
|
||||
import {
|
||||
resolveBundledWebSearchResolutionConfig,
|
||||
sortWebSearchProviders,
|
||||
} from "./web-search-providers.shared.js";
|
||||
|
||||
function listBundledWebSearchProviders(): PluginWebSearchProviderEntry[] {
|
||||
return sortWebSearchProviders(listBundledWebSearchProviderEntries());
|
||||
@@ -158,47 +34,3 @@ export function resolveBundledPluginWebSearchProviders(params: {
|
||||
}).enabled;
|
||||
});
|
||||
}
|
||||
|
||||
export function resolvePluginWebSearchProviders(params: {
|
||||
config?: PluginLoadOptions["config"];
|
||||
workspaceDir?: string;
|
||||
env?: PluginLoadOptions["env"];
|
||||
bundledAllowlistCompat?: boolean;
|
||||
activate?: boolean;
|
||||
cache?: boolean;
|
||||
}): PluginWebSearchProviderEntry[] {
|
||||
const { config } = resolveBundledWebSearchResolutionConfig(params);
|
||||
const registry = loadOpenClawPlugins({
|
||||
config,
|
||||
workspaceDir: params.workspaceDir,
|
||||
env: params.env,
|
||||
cache: params.cache ?? false,
|
||||
activate: params.activate ?? false,
|
||||
logger: createPluginLoaderLogger(log),
|
||||
});
|
||||
|
||||
return sortWebSearchProviders(
|
||||
registry.webSearchProviders.map((entry) => ({
|
||||
...entry.provider,
|
||||
pluginId: entry.pluginId,
|
||||
})),
|
||||
);
|
||||
}
|
||||
|
||||
export function resolveRuntimeWebSearchProviders(params: {
|
||||
config?: PluginLoadOptions["config"];
|
||||
workspaceDir?: string;
|
||||
env?: PluginLoadOptions["env"];
|
||||
bundledAllowlistCompat?: boolean;
|
||||
}): PluginWebSearchProviderEntry[] {
|
||||
const runtimeProviders = getActivePluginRegistry()?.webSearchProviders ?? [];
|
||||
if (runtimeProviders.length > 0) {
|
||||
return sortWebSearchProviders(
|
||||
runtimeProviders.map((entry) => ({
|
||||
...entry.provider,
|
||||
pluginId: entry.pluginId,
|
||||
})),
|
||||
);
|
||||
}
|
||||
return resolvePluginWebSearchProviders(params);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user