import { createLogger } from "../../utils/logger/index.js";
import { init_logger } from "../../utils/logger.js";
import { TimeoutError, executeWithTimeout } from "../lifecycle/timeout-wrapper.js";
import { withRetry } from "../../infra/retry.js";
//#region src/agent/tools/executor.ts
init_logger();
const log = createLogger("ToolExecutor");
const DEFAULT_CONFIG = {
	defaultTimeoutMs: 300 * 1e3,
	maxRetries: 2,
	retryDelayMs: 1e3,
	enableTimeout: true,
	enableRetry: true
};
function readToolHints(tool) {
	const t = tool;
	return {
		timeoutMs: typeof t.timeoutMs === "number" && t.timeoutMs > 0 ? t.timeoutMs : void 0,
		idempotent: t.idempotent === true
	};
}
function resolveTimeoutMs(tool, config) {
	return readToolHints(tool).timeoutMs ?? config.defaultTimeoutMs;
}
/**
* Execute tool with timeout (always) and retry (only for idempotent tools).
* Re-throws on failure so pi-agent records `isError=true`.
*/
async function executeToolWithProtection(tool, toolCallId, params, signal, onUpdate, config = {}) {
	const fullConfig = {
		...DEFAULT_CONFIG,
		...config
	};
	const toolName = tool.name;
	const hints = readToolHints(tool);
	const runOnce = () => tool.execute(toolCallId, params, signal, onUpdate);
	let operation = runOnce;
	if (fullConfig.enableTimeout) {
		const timeoutMs = resolveTimeoutMs(tool, fullConfig);
		const inner = operation;
		operation = () => executeWithTimeout(inner, {
			toolName,
			timeoutMs,
			description: `Executing ${toolName}`
		});
	}
	if (fullConfig.enableRetry && fullConfig.maxRetries > 0 && hints.idempotent) {
		const inner = operation;
		operation = () => withRetry(inner, {
			attempts: fullConfig.maxRetries + 1,
			minDelayMs: fullConfig.retryDelayMs,
			onRetry: (info) => {
				log.warn({
					tool: toolName,
					attempt: info.attempt,
					delayMs: info.delayMs,
					error: info.error
				}, "Tool execution failed, retrying (idempotent)");
			}
		});
	}
	const startTime = Date.now();
	try {
		const result = await operation();
		log.debug({
			tool: toolName,
			durationMs: Date.now() - startTime,
			success: true
		}, "Tool execution completed");
		return result;
	} catch (error) {
		const durationMs = Date.now() - startTime;
		if (error instanceof TimeoutError) {
			log.error({
				tool: toolName,
				timeoutMs: error.timeoutMs,
				durationMs
			}, "Tool execution timed out");
			throw new Error(`Tool '${toolName}' timed out after ${error.timeoutMs}ms`, { cause: error });
		}
		const errorMessage = error instanceof Error ? error.message : String(error);
		log.error({
			tool: toolName,
			error: errorMessage,
			durationMs
		}, "Tool execution failed");
		throw error instanceof Error ? error : new Error(errorMessage);
	}
}
/**
* Wrap a single tool with the protection pipeline. Preserves the original
* `execute` signature so streaming `signal` / `onUpdate` reach the tool.
*/
function wrapToolWithProtection(tool, config) {
	return {
		...tool,
		async execute(toolCallId, params, signal, onUpdate) {
			return executeToolWithProtection(tool, toolCallId, params, signal, onUpdate, config);
		}
	};
}
/**
* Wrap a batch of tools with protection.
*/
function wrapToolsWithProtection(tools, config) {
	return tools.map((tool) => wrapToolWithProtection(tool, config));
}
//#endregion
export { DEFAULT_CONFIG as DEFAULT_TOOL_EXECUTOR_CONFIG, executeToolWithProtection, wrapToolWithProtection, wrapToolsWithProtection };

//# sourceMappingURL=executor.js.map