import { c as normalizeOptionalString } from "./string-coerce-mnp54Vah.js";
import { b as readStringParam, h as readNumberParam, v as readStringArrayParam } from "./common-BsQ_iy7_.js";
import "./string-coerce-runtime-6HjB7EiL.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-CGPXavPn.js";
import { u as readPluginPackageVersion } from "./extension-shared-DUH8eAKG.js";
import { i as resolveProviderWebSearchPluginConfig, r as mergeScopedSearchConfig } from "./web-search-provider-config-BQzMMhw8.js";
import "./provider-web-search-DXfMKVlV.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-BAvcmBXt.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 };
