test: lazy-load Tavily web search runtime

Keep Tavily provider registration on the lightweight contract path and
defer runtime client loading until generic search execution.
This commit is contained in:
Gustavo Madeira Santana
2026-04-17 17:26:09 -04:00
parent c86beb237e
commit 8a0977f405

View File

@@ -1,27 +1,22 @@
import { Type } from "@sinclair/typebox";
import {
enablePluginInConfig,
getScopedCredentialValue,
resolveProviderWebSearchPluginConfig,
setScopedCredentialValue,
setProviderWebSearchPluginConfigValue,
createWebSearchProviderContractFields,
type WebSearchProviderPlugin,
} from "openclaw/plugin-sdk/provider-web-search";
import { runTavilySearch } from "./tavily-client.js";
} from "openclaw/plugin-sdk/provider-web-search-contract";
const GenericTavilySearchSchema = 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: 20,
}),
),
const TAVILY_CREDENTIAL_PATH = "plugins.entries.tavily.config.webSearch.apiKey";
const GenericTavilySearchSchema = {
type: "object",
properties: {
query: { type: "string", description: "Search query string." },
count: {
type: "number",
description: "Number of results to return (1-20).",
minimum: 1,
maximum: 20,
},
},
{ additionalProperties: false },
);
additionalProperties: false,
} satisfies Record<string, unknown>;
export function createTavilyWebSearchProvider(): WebSearchProviderPlugin {
return {
@@ -35,27 +30,25 @@ export function createTavilyWebSearchProvider(): WebSearchProviderPlugin {
signupUrl: "https://tavily.com/",
docsUrl: "https://docs.openclaw.ai/tools/tavily",
autoDetectOrder: 70,
credentialPath: "plugins.entries.tavily.config.webSearch.apiKey",
inactiveSecretPaths: ["plugins.entries.tavily.config.webSearch.apiKey"],
getCredentialValue: (searchConfig) => getScopedCredentialValue(searchConfig, "tavily"),
setCredentialValue: (searchConfigTarget, value) =>
setScopedCredentialValue(searchConfigTarget, "tavily", value),
getConfiguredCredentialValue: (config) =>
resolveProviderWebSearchPluginConfig(config, "tavily")?.apiKey,
setConfiguredCredentialValue: (configTarget, value) => {
setProviderWebSearchPluginConfigValue(configTarget, "tavily", "apiKey", value);
},
applySelectionConfig: (config) => enablePluginInConfig(config, "tavily").config,
credentialPath: TAVILY_CREDENTIAL_PATH,
...createWebSearchProviderContractFields({
credentialPath: TAVILY_CREDENTIAL_PATH,
searchCredential: { type: "scoped", scopeId: "tavily" },
configuredCredential: { pluginId: "tavily" },
selectionPluginId: "tavily",
}),
createTool: (ctx) => ({
description:
"Search the web using Tavily. Returns structured results with snippets. Use tavily_search for Tavily-specific options like search depth, topic filtering, or AI answers.",
parameters: GenericTavilySearchSchema,
execute: async (args) =>
await runTavilySearch({
execute: async (args) => {
const { runTavilySearch } = await import("./tavily-client.js");
return await runTavilySearch({
cfg: ctx.config,
query: typeof args.query === "string" ? args.query : "",
maxResults: typeof args.count === "number" ? args.count : undefined,
}),
});
},
}),
};
}