import { formatError } from '../utils/error-formatter.js';
import { validateArgsAgainstSchema } from '../utils/schema-validate.js';
/**
 * Thrown by a validated tool handler when its arguments fail validation.
 * Carries the structured details so callers can render a field-level message
 * for a self-correcting LLM rather than a flat sentence.
 */
export class ToolValidationError extends Error {
    details;
    constructor(message, details) {
        super(message);
        this.name = 'ToolValidationError';
        this.details = details;
    }
}
/**
 * Render a validation failure into the string that goes back to the model.
 * Appends one line per structured detail when present.
 */
export function formatValidationError(error, details) {
    const base = `⚒ Validation failed: ${error}`;
    if (!details || details.length === 0) {
        return base;
    }
    const lines = details.map(d => {
        const field = d.path ? `\`${d.path}\`` : 'argument';
        const parts = [];
        if (d.expected !== undefined)
            parts.push(`expected ${d.expected}`);
        if (d.received !== undefined)
            parts.push(`received ${d.received}`);
        const detail = parts.length > 0 ? `: ${parts.join(', ')}` : '';
        const extra = d.message ? ` (${d.message})` : '';
        return `  - ${field}${detail}${extra}`;
    });
    return `${base}\n${lines.join('\n')}`;
}
/**
 * Convert any error thrown during tool execution into the string content the
 * model sees. Validation failures get structured field-level formatting;
 * everything else falls back to the generic error message.
 */
export function toolErrorToContent(error) {
    if (error instanceof ToolValidationError) {
        return formatValidationError(error.message, error.details);
    }
    return `Error: ${formatError(error)}`;
}
/**
 * Wrap a tool handler so type-checking and its validator run immediately
 * before execution.
 *
 * This is the single place tool validation lives: because every execution
 * path (interactive loop, plain shell, subagents) ultimately invokes the
 * registry handler, validating here means no path can bypass it. On failure
 * the wrapper throws a {@link ToolValidationError}; callers already catch
 * handler exceptions and turn them into an error tool-result.
 *
 * When a `schema` is supplied, arguments are first type-checked against it.
 * A wrong-typed argument (e.g. an object where a string is expected) is
 * returned to the model as a structured error so it can correct itself and
 * retry — instead of the bad value reaching execution or the UI.
 */
export function withValidation(handler, validator, schema) {
    if (!validator && !schema)
        return handler;
    return async (args) => {
        if (schema) {
            const typeErrors = validateArgsAgainstSchema(args, schema);
            if (typeErrors.length > 0) {
                throw new ToolValidationError('one or more arguments have the wrong type — fix the types and call the tool again', typeErrors);
            }
        }
        if (validator) {
            const result = await validator(args);
            if (!result.valid) {
                throw new ToolValidationError(result.error, result.details);
            }
        }
        return handler(args);
    };
}
//# sourceMappingURL=tool-validation.js.map