import { resolveImageModelConfigForTool } from "../image/tool-model-config.js";
import { buildImageToolTextResult, resolvePromptAndModelOverride } from "../image/image-helpers.js";
import { describeImages } from "../image/understanding/runtime.js";
import { runWithImageModelFallback } from "../image/image-model-fallback.js";
import { loadImageForToolInput } from "../image/load-image-media.js";
import { Type } from "@sinclair/typebox";
//#region src/agent/tools/image-tool.ts
const DEFAULT_PROMPT = "Describe the image.";
const DEFAULT_MAX_IMAGES = 20;
function pickMaxBytes(cfg, maxBytesMb) {
	if (typeof maxBytesMb === "number" && Number.isFinite(maxBytesMb) && maxBytesMb > 0) return Math.floor(maxBytesMb * 1024 * 1024);
	const configured = cfg?.agents?.defaults?.mediaMaxMb;
	if (typeof configured === "number" && Number.isFinite(configured) && configured > 0) return Math.floor(configured * 1024 * 1024);
	return 20 * 1024 * 1024;
}
function createImageTool(options) {
	const imageModelConfig = resolveImageModelConfigForTool({ cfg: options.config });
	if (!imageModelConfig) return null;
	const description = options.modelHasVision ? "Analyze one or more images with a vision model. Use `image` for a single path/URL, or `images` for multiple (up to 20). Only use when images were NOT already in the user message." : "Analyze one or more images using the configured image model (agents.defaults.imageModel). Use `image` or `images` for paths/URLs; optional `prompt` for what to extract.";
	const localRoots = [options.workspace];
	return {
		name: "image",
		label: "Image",
		description,
		parameters: Type.Object({
			prompt: Type.Optional(Type.String()),
			image: Type.Optional(Type.String({ description: "Single image path or URL." })),
			images: Type.Optional(Type.Array(Type.String(), { description: "Multiple image paths or URLs (up to maxImages, default 20)." })),
			model: Type.Optional(Type.String({ description: "Optional provider/model override." })),
			maxBytesMb: Type.Optional(Type.Number()),
			maxImages: Type.Optional(Type.Number())
		}),
		async execute(_toolCallId, args) {
			const record = args && typeof args === "object" ? args : {};
			const imageCandidates = [];
			if (typeof record.image === "string") imageCandidates.push(record.image);
			if (Array.isArray(record.images)) imageCandidates.push(...record.images.filter((v) => typeof v === "string"));
			const seenImages = /* @__PURE__ */ new Set();
			const imageInputs = [];
			for (const candidate of imageCandidates) {
				const trimmedCandidate = candidate.trim();
				const normalizedForDedupe = trimmedCandidate.startsWith("@") ? trimmedCandidate.slice(1).trim() : trimmedCandidate;
				if (!normalizedForDedupe || seenImages.has(normalizedForDedupe)) continue;
				seenImages.add(normalizedForDedupe);
				imageInputs.push(trimmedCandidate);
			}
			if (imageInputs.length === 0) return {
				content: [{
					type: "text",
					text: "Error: provide `image` or `images`."
				}],
				details: { error: "missing_image" }
			};
			const maxImagesRaw = typeof record.maxImages === "number" ? record.maxImages : void 0;
			const maxImages = typeof maxImagesRaw === "number" && Number.isFinite(maxImagesRaw) && maxImagesRaw > 0 ? Math.floor(maxImagesRaw) : DEFAULT_MAX_IMAGES;
			if (imageInputs.length > maxImages) return {
				content: [{
					type: "text",
					text: `Too many images: ${imageInputs.length} (max ${maxImages}).`
				}],
				details: {
					error: "too_many_images",
					count: imageInputs.length,
					max: maxImages
				}
			};
			const { prompt: promptRaw, modelOverride } = resolvePromptAndModelOverride(record, DEFAULT_PROMPT);
			const maxBytesMb = typeof record.maxBytesMb === "number" ? record.maxBytesMb : void 0;
			const maxBytes = pickMaxBytes(options.config, maxBytesMb);
			const loadedImages = [];
			for (const imageRawInput of imageInputs) {
				const trimmed = imageRawInput.trim();
				const imageRaw = trimmed.startsWith("@") ? trimmed.slice(1).trim() : trimmed;
				if (!imageRaw) return {
					content: [{
						type: "text",
						text: "Error: empty image entry."
					}],
					details: { error: "empty_image" }
				};
				const looksLikeWindowsDrivePath = /^[a-zA-Z]:[\\/]/.test(imageRaw);
				const hasScheme = /^[a-z][a-z0-9+.-]*:/i.test(imageRaw);
				const isFileUrl = /^file:/i.test(imageRaw);
				const isHttpUrl = /^https?:\/\//i.test(imageRaw);
				const isDataUrl = /^data:/i.test(imageRaw);
				if (hasScheme && !looksLikeWindowsDrivePath && !isFileUrl && !isHttpUrl && !isDataUrl) return {
					content: [{
						type: "text",
						text: `Unsupported image reference: ${imageRawInput}. Use a path, file://, data:, or http(s) URL.`
					}],
					details: {
						error: "unsupported_image_reference",
						image: imageRawInput
					}
				};
				try {
					const media = await loadImageForToolInput(imageRaw, {
						maxBytes,
						workspace: options.workspace,
						localRoots
					});
					loadedImages.push({
						buffer: media.buffer,
						mimeType: media.mimeType,
						resolvedImage: imageRaw
					});
				} catch (e) {
					return {
						content: [{
							type: "text",
							text: `Failed to load image (${imageRawInput}): ${e instanceof Error ? e.message : String(e)}`
						}],
						details: {
							error: "load_failed",
							image: imageRawInput
						}
					};
				}
			}
			const { result: inner, attempts } = await runWithImageModelFallback({
				toolConfig: imageModelConfig,
				modelOverride,
				run: async (modelRef) => {
					const { text, provider, model } = await describeImages({
						modelRef,
						prompt: promptRaw,
						images: loadedImages.map((img) => ({
							buffer: img.buffer,
							mimeType: img.mimeType
						})),
						timeoutMs: 6e4
					});
					return {
						text,
						provider,
						model
					};
				}
			});
			return buildImageToolTextResult({
				text: inner.text,
				provider: inner.provider,
				model: inner.model,
				attempts
			}, loadedImages.length === 1 ? { image: loadedImages[0].resolvedImage } : { images: loadedImages.map((img) => ({ image: img.resolvedImage })) });
		}
	};
}
//#endregion
export { createImageTool, resolveImageModelConfigForTool };

//# sourceMappingURL=image-tool.js.map