import { z } from "zod";
import { toJsonSchema } from "../schema/to-json-schema.js";
/**
 * Stops the agentic tool execution loop and returns the content as the final response.
 * Return this from a tool's execute() method to immediately end the conversation turn.
 *
 * @example
 * ```typescript
 * class PaymentTool extends Tool {
 *   async execute({ amount }) {
 *     if (amount > 10000) {
 *       return this.halt("Payment requires manager approval. Please contact support.");
 *     }
 *     return processPayment(amount);
 *   }
 * }
 * ```
 */
export class ToolHalt {
    content;
    constructor(content) {
        this.content = content;
    }
    toString() {
        return this.content;
    }
    toJSON() {
        return { halt: true, content: this.content };
    }
}
/**
 * Subclass this to create tools with auto-generated schemas and type safety.
 */
export class Tool {
    /**
     * Whether to enforce strict JSON schema constraints for OpenAI and similar providers.
     * When true, additionalProperties: false and full required arrays are automatically applied.
     */
    strict;
    /**
     * Stop the agentic loop and return this message as the final tool result.
     * Use this when you want to end the conversation turn immediately.
     *
     * @example
     * ```typescript
     * async execute({ amount }) {
     *   if (amount > 10000) {
     *     return this.halt("Payment requires manager approval.");
     *   }
     *   return processPayment(amount);
     * }
     * ```
     */
    halt(message) {
        return new ToolHalt(message);
    }
    /**
     * Internal handler to bridge with LLM providers.
     * Converts any result to a string (usually JSON).
     * Preserves ToolHalt instances for the execution loop to detect.
     */
    async handler(args) {
        // 1. Runtime validation if Zod schema is provided
        let validatedArgs = args;
        if (this.schema instanceof z.ZodType) {
            validatedArgs = this.schema.parse(args);
        }
        const result = await this.execute(validatedArgs);
        // Preserve ToolHalt for the execution loop to handle
        if (result instanceof ToolHalt) {
            return result;
        }
        if (result === undefined || result === null)
            return "";
        return typeof result === "string" ? result : JSON.stringify(result);
    }
    /**
     * Converts the tool definition and logic into a standard ToolDefinition interface.
     * This is called automatically by NodeLLM when registering tools.
     */
    toLLMTool() {
        const rawSchema = toJsonSchema(this.schema);
        // We want the 'properties' and 'required' parts, not the full JSON Schema wrapper if present
        const parameters = rawSchema.type === "object"
            ? rawSchema
            : {
                type: "object",
                properties: rawSchema.properties || {},
                required: rawSchema.required || []
            };
        return {
            type: "function",
            function: {
                name: this.name,
                description: this.description,
                strict: this.strict,
                parameters: parameters
            },
            handler: (args) => this.handler(args)
        };
    }
}
