From 8a0977f405750a7103abccfc089d4cee9d85bd28 Mon Sep 17 00:00:00 2001 From: Gustavo Madeira Santana Date: Fri, 17 Apr 2026 17:26:09 -0400 Subject: [PATCH] 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. --- .../tavily/src/tavily-search-provider.ts | 61 ++++++++----------- 1 file changed, 27 insertions(+), 34 deletions(-) diff --git a/extensions/tavily/src/tavily-search-provider.ts b/extensions/tavily/src/tavily-search-provider.ts index 6fe230521b9..c05981e54a1 100644 --- a/extensions/tavily/src/tavily-search-provider.ts +++ b/extensions/tavily/src/tavily-search-provider.ts @@ -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; 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, - }), + }); + }, }), }; }