import { s as normalizeOptionalString } from "../../string-coerce-CIT1-v_a.js";
import { c as normalizeResolvedSecretInputString } from "../../types.secrets-CjPCMEo4.js";
import { n as normalizeSecretInput } from "../../normalize-secret-input-Cwg-vdk5.js";
import { c as jsonResult, d as readNumberParam, h as readStringParam } from "../../common-GZozRMXE.js";
import { c as wrapWebContent, s as wrapExternalContent } from "../../external-content-Bc0q27N7.js";
import { i as readCache, l as writeCache, o as resolveCacheTtlMs, r as normalizeCacheKey } from "../../web-shared-DIOTSdEe.js";
import { u as postTrustedWebToolsJson } from "../../web-search-provider-common-D7KLb-YX.js";
import { t as definePluginEntry } from "../../plugin-entry-CeANVrRz.js";
import "../../text-runtime-Drz6LusC.js";
import "../../security-runtime-DG4h6FAl.js";
import "../../secret-input-DlsuVcPz.js";
import { t as enablePluginInConfig } from "../../enable-JISGxmHP.js";
import { a as setProviderWebSearchPluginConfigValue, i as resolveProviderWebSearchPluginConfig, o as setScopedCredentialValue, t as getScopedCredentialValue } from "../../web-search-provider-config-DHBbi3K7.js";
import "../../provider-web-search-C8D_9xie.js";
import { Type } from "typebox";
//#region extensions/tavily/src/config.ts
const DEFAULT_TAVILY_BASE_URL = "https://api.tavily.com";
function resolveTavilySearchConfig(cfg) {
	const pluginWebSearch = (cfg?.plugins?.entries?.tavily?.config)?.webSearch;
	if (pluginWebSearch && typeof pluginWebSearch === "object" && !Array.isArray(pluginWebSearch)) return pluginWebSearch;
}
function normalizeConfiguredSecret(value, path) {
	return normalizeSecretInput(normalizeResolvedSecretInputString({
		value,
		path
	}));
}
function resolveTavilyApiKey(cfg) {
	return normalizeConfiguredSecret(resolveTavilySearchConfig(cfg)?.apiKey, "plugins.entries.tavily.config.webSearch.apiKey") || normalizeSecretInput(process.env.TAVILY_API_KEY) || void 0;
}
function resolveTavilyBaseUrl(cfg) {
	return (normalizeOptionalString(resolveTavilySearchConfig(cfg)?.baseUrl) ?? "") || normalizeSecretInput(process.env.TAVILY_BASE_URL) || "https://api.tavily.com";
}
function resolveTavilySearchTimeoutSeconds(override) {
	if (typeof override === "number" && Number.isFinite(override) && override > 0) return Math.floor(override);
	return 30;
}
function resolveTavilyExtractTimeoutSeconds(override) {
	if (typeof override === "number" && Number.isFinite(override) && override > 0) return Math.floor(override);
	return 60;
}
//#endregion
//#region extensions/tavily/src/tavily-client.ts
const SEARCH_CACHE = /* @__PURE__ */ new Map();
const EXTRACT_CACHE = /* @__PURE__ */ new Map();
const DEFAULT_SEARCH_COUNT = 5;
function resolveEndpoint(baseUrl, pathname) {
	const trimmed = baseUrl.trim();
	if (!trimmed) return `${DEFAULT_TAVILY_BASE_URL}${pathname}`;
	try {
		const url = new URL(trimmed);
		url.pathname = url.pathname.replace(/\/$/, "") + pathname;
		return url.toString();
	} catch {
		return `${DEFAULT_TAVILY_BASE_URL}${pathname}`;
	}
}
async function runTavilySearch(params) {
	const apiKey = resolveTavilyApiKey(params.cfg);
	if (!apiKey) throw new Error("web_search (tavily) needs a Tavily API key. Set TAVILY_API_KEY in the Gateway environment, or configure plugins.entries.tavily.config.webSearch.apiKey.");
	const count = typeof params.maxResults === "number" && Number.isFinite(params.maxResults) ? Math.max(1, Math.min(20, Math.floor(params.maxResults))) : DEFAULT_SEARCH_COUNT;
	const timeoutSeconds = resolveTavilySearchTimeoutSeconds(params.timeoutSeconds);
	const baseUrl = resolveTavilyBaseUrl(params.cfg);
	const cacheKey = normalizeCacheKey(JSON.stringify({
		type: "tavily-search",
		q: params.query,
		count,
		baseUrl,
		searchDepth: params.searchDepth,
		topic: params.topic,
		includeAnswer: params.includeAnswer,
		timeRange: params.timeRange,
		includeDomains: params.includeDomains,
		excludeDomains: params.excludeDomains
	}));
	const cached = readCache(SEARCH_CACHE, cacheKey);
	if (cached) return {
		...cached.value,
		cached: true
	};
	const body = {
		query: params.query,
		max_results: count
	};
	if (params.searchDepth) body.search_depth = params.searchDepth;
	if (params.topic) body.topic = params.topic;
	if (params.includeAnswer) body.include_answer = true;
	if (params.timeRange) body.time_range = params.timeRange;
	if (params.includeDomains?.length) body.include_domains = params.includeDomains;
	if (params.excludeDomains?.length) body.exclude_domains = params.excludeDomains;
	const start = Date.now();
	const payload = await postTrustedWebToolsJson({
		url: resolveEndpoint(baseUrl, "/search"),
		timeoutSeconds,
		apiKey,
		body,
		errorLabel: "Tavily Search",
		extraHeaders: { "X-Client-Source": "kaijibot" }
	}, async (response) => await response.json());
	const results = (Array.isArray(payload.results) ? payload.results : []).map((r) => ({
		title: typeof r.title === "string" ? wrapWebContent(r.title, "web_search") : "",
		url: typeof r.url === "string" ? r.url : "",
		snippet: typeof r.content === "string" ? wrapWebContent(r.content, "web_search") : "",
		score: typeof r.score === "number" ? r.score : void 0,
		...typeof r.published_date === "string" ? { published: r.published_date } : {}
	}));
	const result = {
		query: params.query,
		provider: "tavily",
		count: results.length,
		tookMs: Date.now() - start,
		externalContent: {
			untrusted: true,
			source: "web_search",
			provider: "tavily",
			wrapped: true
		},
		results
	};
	if (typeof payload.answer === "string" && payload.answer) result.answer = wrapWebContent(payload.answer, "web_search");
	writeCache(SEARCH_CACHE, cacheKey, result, resolveCacheTtlMs(void 0, 15));
	return result;
}
async function runTavilyExtract(params) {
	const apiKey = resolveTavilyApiKey(params.cfg);
	if (!apiKey) throw new Error("tavily_extract needs a Tavily API key. Set TAVILY_API_KEY in the Gateway environment, or configure plugins.entries.tavily.config.webSearch.apiKey.");
	const baseUrl = resolveTavilyBaseUrl(params.cfg);
	const timeoutSeconds = resolveTavilyExtractTimeoutSeconds(params.timeoutSeconds);
	const cacheKey = normalizeCacheKey(JSON.stringify({
		type: "tavily-extract",
		urls: params.urls,
		baseUrl,
		query: params.query,
		extractDepth: params.extractDepth,
		chunksPerSource: params.chunksPerSource,
		includeImages: params.includeImages
	}));
	const cached = readCache(EXTRACT_CACHE, cacheKey);
	if (cached) return {
		...cached.value,
		cached: true
	};
	const body = { urls: params.urls };
	if (params.query) body.query = params.query;
	if (params.extractDepth) body.extract_depth = params.extractDepth;
	if (params.chunksPerSource) body.chunks_per_source = params.chunksPerSource;
	if (params.includeImages) body.include_images = true;
	const start = Date.now();
	const payload = await postTrustedWebToolsJson({
		url: resolveEndpoint(baseUrl, "/extract"),
		timeoutSeconds,
		apiKey,
		body,
		errorLabel: "Tavily Extract",
		extraHeaders: { "X-Client-Source": "kaijibot" }
	}, async (response) => await response.json());
	const results = (Array.isArray(payload.results) ? payload.results : []).map((r) => ({
		url: typeof r.url === "string" ? r.url : "",
		rawContent: typeof r.raw_content === "string" ? wrapExternalContent(r.raw_content, {
			source: "web_fetch",
			includeWarning: false
		}) : "",
		...typeof r.content === "string" ? { content: wrapExternalContent(r.content, {
			source: "web_fetch",
			includeWarning: false
		}) } : {},
		...Array.isArray(r.images) ? { images: r.images.map((img) => wrapExternalContent(img, {
			source: "web_fetch",
			includeWarning: false
		})) } : {}
	}));
	const failedResults = Array.isArray(payload.failed_results) ? payload.failed_results : [];
	const result = {
		provider: "tavily",
		count: results.length,
		tookMs: Date.now() - start,
		externalContent: {
			untrusted: true,
			source: "web_fetch",
			provider: "tavily",
			wrapped: true
		},
		results,
		...failedResults.length > 0 ? { failedResults } : {}
	};
	writeCache(EXTRACT_CACHE, cacheKey, result, resolveCacheTtlMs(void 0, 15));
	return result;
}
//#endregion
//#region extensions/tavily/src/tavily-extract-tool.ts
function optionalStringEnum$1(values, options = {}) {
	return Type.Optional(Type.Unsafe({
		type: "string",
		enum: [...values],
		...options
	}));
}
const TavilyExtractToolSchema = Type.Object({
	urls: Type.Array(Type.String(), {
		description: "One or more URLs to extract content from (max 20).",
		minItems: 1,
		maxItems: 20
	}),
	query: Type.Optional(Type.String({ description: "Rerank extracted chunks by relevance to this query." })),
	extract_depth: optionalStringEnum$1(["basic", "advanced"], { description: "\"basic\" (default) or \"advanced\" (for JS-heavy pages)." }),
	chunks_per_source: Type.Optional(Type.Number({
		description: "Chunks per URL (1-5, requires query).",
		minimum: 1,
		maximum: 5
	})),
	include_images: Type.Optional(Type.Boolean({ description: "Include image URLs in extraction results." }))
}, { additionalProperties: false });
function createTavilyExtractTool(api) {
	return {
		name: "tavily_extract",
		label: "Tavily Extract",
		description: "Extract clean content from one or more URLs using Tavily. Handles JS-rendered pages. Supports query-focused chunking.",
		parameters: TavilyExtractToolSchema,
		execute: async (_toolCallId, rawParams) => {
			const urls = Array.isArray(rawParams.urls) ? rawParams.urls.filter(Boolean) : [];
			if (urls.length === 0) throw new Error("tavily_extract requires at least one URL.");
			const query = readStringParam(rawParams, "query") || void 0;
			const extractDepth = readStringParam(rawParams, "extract_depth") || void 0;
			const chunksPerSource = readNumberParam(rawParams, "chunks_per_source", { integer: true });
			if (chunksPerSource !== void 0 && !query) throw new Error("tavily_extract requires query when chunks_per_source is set.");
			const includeImages = rawParams.include_images === true;
			return jsonResult(await runTavilyExtract({
				cfg: api.config,
				urls,
				query,
				extractDepth,
				chunksPerSource,
				includeImages
			}));
		}
	};
}
//#endregion
//#region extensions/tavily/src/tavily-search-provider.ts
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
	}))
}, { additionalProperties: false });
function createTavilyWebSearchProvider() {
	return {
		id: "tavily",
		label: "Tavily Search",
		hint: "Structured results with domain filters and AI answer summaries",
		onboardingScopes: ["text-inference"],
		credentialLabel: "Tavily API key",
		envVars: ["TAVILY_API_KEY"],
		placeholder: "tvly-...",
		signupUrl: "https://tavily.com/",
		docsUrl: "https://docs.kaijibot.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,
		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({
				cfg: ctx.config,
				query: typeof args.query === "string" ? args.query : "",
				maxResults: typeof args.count === "number" ? args.count : void 0
			})
		})
	};
}
//#endregion
//#region extensions/tavily/src/tavily-search-tool.ts
function optionalStringEnum(values, options = {}) {
	return Type.Optional(Type.Unsafe({
		type: "string",
		enum: [...values],
		...options
	}));
}
const TavilySearchToolSchema = Type.Object({
	query: Type.String({ description: "Search query string." }),
	search_depth: optionalStringEnum(["basic", "advanced"], { description: "Search depth: \"basic\" (default, faster) or \"advanced\" (more thorough)." }),
	topic: optionalStringEnum([
		"general",
		"news",
		"finance"
	], { description: "Search topic: \"general\" (default), \"news\", or \"finance\"." }),
	max_results: Type.Optional(Type.Number({
		description: "Number of results to return (1-20).",
		minimum: 1,
		maximum: 20
	})),
	include_answer: Type.Optional(Type.Boolean({ description: "Include an AI-generated answer summary (default: false)." })),
	time_range: optionalStringEnum([
		"day",
		"week",
		"month",
		"year"
	], { description: "Filter results by recency: 'day', 'week', 'month', or 'year'." }),
	include_domains: Type.Optional(Type.Array(Type.String(), { description: "Only include results from these domains." })),
	exclude_domains: Type.Optional(Type.Array(Type.String(), { description: "Exclude results from these domains." }))
}, { additionalProperties: false });
function createTavilySearchTool(api) {
	return {
		name: "tavily_search",
		label: "Tavily Search",
		description: "Search the web using Tavily Search API. Supports search depth, topic filtering, domain filters, time ranges, and AI answer summaries.",
		parameters: TavilySearchToolSchema,
		execute: async (_toolCallId, rawParams) => {
			const query = readStringParam(rawParams, "query", { required: true });
			const searchDepth = readStringParam(rawParams, "search_depth") || void 0;
			const topic = readStringParam(rawParams, "topic") || void 0;
			const maxResults = readNumberParam(rawParams, "max_results", { integer: true });
			const includeAnswer = rawParams.include_answer === true;
			const timeRange = readStringParam(rawParams, "time_range") || void 0;
			const includeDomains = Array.isArray(rawParams.include_domains) ? rawParams.include_domains.filter(Boolean) : void 0;
			const excludeDomains = Array.isArray(rawParams.exclude_domains) ? rawParams.exclude_domains.filter(Boolean) : void 0;
			return jsonResult(await runTavilySearch({
				cfg: api.config,
				query,
				searchDepth,
				topic,
				maxResults,
				includeAnswer,
				timeRange,
				includeDomains: includeDomains?.length ? includeDomains : void 0,
				excludeDomains: excludeDomains?.length ? excludeDomains : void 0
			}));
		}
	};
}
//#endregion
//#region extensions/tavily/index.ts
var tavily_default = definePluginEntry({
	id: "tavily",
	name: "Tavily Plugin",
	description: "Bundled Tavily search and extract plugin",
	register(api) {
		api.registerWebSearchProvider(createTavilyWebSearchProvider());
		api.registerTool(createTavilySearchTool(api));
		api.registerTool(createTavilyExtractTool(api));
	}
});
//#endregion
export { tavily_default as default };
