UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

161 lines (160 loc) 7.5 kB
import { c as normalizeOptionalString } from "./string-coerce-mnp54Vah.js"; import { b as readStringParam, h as readNumberParam, v as readStringArrayParam } from "./common-C4yy9V-D.js"; import "./string-coerce-runtime-CEGJWkQ_.js"; import { S as writeCachedSearchPayload, _ as resolveSearchTimeoutSeconds, f as readCachedSearchPayload, h as resolveSearchCacheTtlMs, m as readProviderEnvValue, p as readConfiguredSecretString, x as withTrustedWebSearchEndpoint } from "./web-search-provider-common-DisZTXTb.js"; import { u as readPluginPackageVersion } from "./extension-shared-B8fkO3TV.js"; import { i as resolveProviderWebSearchPluginConfig, r as mergeScopedSearchConfig } from "./web-search-provider-config-BQzMMhw8.js"; import "./provider-web-search-9G87vZMY.js"; import { a as normalizeParallelClientModel, c as normalizeParallelSearchQueries, d as stripParallelGeneratedSessionId, i as mapParallelResults, l as normalizeParallelSessionId, n as buildParallelCacheKey, o as normalizeParallelObjective, r as invalidSearchQueriesPayload, s as normalizeParallelResults, t as PARALLEL_SESSION_ID_MAX_LENGTH, u as resolveParallelSearchCount } from "./parallel-search-normalize-BrqPQAw_.js"; import { createRequire } from "node:module"; //#region extensions/parallel/src/parallel-web-search-provider.runtime.ts const PARALLEL_BASE_URL = "https://api.parallel.ai"; const PARALLEL_SEARCH_PATHNAME = "/v1/search"; const USER_AGENT = `openclaw-parallel/${readPluginPackageVersion({ require: createRequire(import.meta.url) })} (${process.platform})`; function resolveParallelConfig(searchConfig) { const parallel = searchConfig?.parallel; return parallel && typeof parallel === "object" && !Array.isArray(parallel) ? parallel : {}; } function resolveParallelApiKey(parallel) { return readConfiguredSecretString(parallel?.apiKey, "tools.web.search.parallel.apiKey") ?? readProviderEnvValue(["PARALLEL_API_KEY"]); } function invalidBaseUrlPayload(value) { return { error: "invalid_base_url", message: `plugins.entries.parallel.config.webSearch.baseUrl must be a valid http(s) URL. Got: ${value}`, docs: "https://docs.openclaw.ai/tools/parallel-search" }; } function resolveParallelSearchEndpoint(parallel) { const configured = normalizeOptionalString(parallel?.baseUrl); if (!configured) return { endpoint: `${PARALLEL_BASE_URL}${PARALLEL_SEARCH_PATHNAME}` }; if (/^[a-z][a-z0-9+.-]*:\/\//i.test(configured) && !/^https?:\/\//i.test(configured)) return invalidBaseUrlPayload(configured); const candidate = /^https?:\/\//i.test(configured) ? configured : `https://${configured}`; let parsed; try { parsed = new URL(candidate); } catch { return invalidBaseUrlPayload(configured); } if (parsed.protocol !== "http:" && parsed.protocol !== "https:") return invalidBaseUrlPayload(configured); const pathname = parsed.pathname.replace(/\/+$/, ""); parsed.pathname = pathname.endsWith(PARALLEL_SEARCH_PATHNAME) ? pathname : `${pathname === "" ? "" : pathname}${PARALLEL_SEARCH_PATHNAME}`; parsed.hash = ""; return { endpoint: parsed.toString() }; } function missingParallelKeyPayload() { return { error: "missing_parallel_api_key", message: "web_search (parallel) needs a Parallel API key. Set PARALLEL_API_KEY in the Gateway environment, or configure plugins.entries.parallel.config.webSearch.apiKey.", docs: "https://docs.openclaw.ai/tools/parallel-search" }; } async function runParallelSearch(params) { const body = { search_queries: [...params.searchQueries], advanced_settings: { max_results: params.maxResults } }; if (params.objective) body.objective = params.objective; if (params.sessionId) body.session_id = params.sessionId; if (params.clientModel) body.client_model = params.clientModel; return withTrustedWebSearchEndpoint({ url: params.endpoint, timeoutSeconds: params.timeoutSeconds, init: { method: "POST", headers: { Accept: "application/json", "Content-Type": "application/json", "x-api-key": params.apiKey, "User-Agent": USER_AGENT }, body: JSON.stringify(body) } }, async (res) => { if (!res.ok) { const detail = await res.text().catch(() => ""); throw new Error(`Parallel API error (${res.status}): ${detail || res.statusText}`); } try { return await res.json(); } catch (cause) { throw new Error("Parallel API returned malformed JSON", { cause }); } }); } async function executeParallelWebSearchProviderTool(ctx, args) { const searchConfig = mergeScopedSearchConfig(ctx.searchConfig, "parallel", resolveProviderWebSearchPluginConfig(ctx.config, "parallel")); const parallelConfig = resolveParallelConfig(searchConfig); const apiKey = resolveParallelApiKey(parallelConfig); if (!apiKey) return missingParallelKeyPayload(); const endpointResult = resolveParallelSearchEndpoint(parallelConfig); if ("error" in endpointResult) return endpointResult; const endpoint = endpointResult.endpoint; const objective = normalizeParallelObjective(readStringParam(args, "objective")); const cliQuery = normalizeParallelObjective(readStringParam(args, "query")); let searchQueries = normalizeParallelSearchQueries(readStringArrayParam(args, "search_queries")); if (searchQueries.length === 0 && cliQuery) searchQueries = normalizeParallelSearchQueries([cliQuery]); if (searchQueries.length === 0) return invalidSearchQueriesPayload(); const count = resolveParallelSearchCount(readNumberParam(args, "count", { integer: true }) ?? (typeof searchConfig?.maxResults === "number" ? searchConfig.maxResults : void 0) ?? 5); const sessionId = normalizeParallelSessionId(readStringParam(args, "session_id"), PARALLEL_SESSION_ID_MAX_LENGTH); const clientModel = normalizeParallelClientModel(readStringParam(args, "client_model")); const cacheKey = buildParallelCacheKey({ endpoint, objective, searchQueries, count, sessionId, clientModel }); const cached = readCachedSearchPayload(cacheKey); if (cached) return cached; const start = Date.now(); const response = await runParallelSearch({ apiKey, endpoint, objective, searchQueries, maxResults: count, sessionId, clientModel, timeoutSeconds: resolveSearchTimeoutSeconds(searchConfig) }); const results = mapParallelResults(response); const payload = { ...objective ? { objective } : {}, searchQueries, provider: "parallel", count: results.length, tookMs: Date.now() - start, externalContent: { untrusted: true, source: "web_search", provider: "parallel", wrapped: true }, results }; if (typeof response.search_id === "string") payload.searchId = response.search_id; if (typeof response.session_id === "string") payload.sessionId = response.session_id; if (Array.isArray(response.warnings) && response.warnings.length > 0) payload.warnings = response.warnings; if (Array.isArray(response.usage) && response.usage.length > 0) payload.usage = response.usage; writeCachedSearchPayload(cacheKey, sessionId ? payload : stripParallelGeneratedSessionId(payload), resolveSearchCacheTtlMs(searchConfig)); return payload; } const testing = { buildParallelCacheKey, invalidSearchQueriesPayload, missingParallelKeyPayload, normalizeParallelClientModel, normalizeParallelObjective, normalizeParallelResults, normalizeParallelSearchQueries, normalizeParallelSessionId, resolveParallelApiKey, resolveParallelConfig, resolveParallelSearchCount, resolveParallelSearchEndpoint, USER_AGENT }; //#endregion export { testing as __testing, testing, executeParallelWebSearchProviderTool };