"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.TOOL_DEFINITIONS = void 0;
exports.getToolSchemas = getToolSchemas;
exports.getAvailableTools = getAvailableTools;
/**
 * Tool definitions module - Frontend-safe
 *
 * Single source of truth for all tool definitions.
 * Zod schemas are defined here and JSON schemas are auto-generated.
 */
const zod_1 = require("zod");
const toolLimits_1 = require("../../constants/toolLimits");
const zod_to_json_schema_1 = require("zod-to-json-schema");
/**
 * Tool definitions: single source of truth
 * Key = tool name, Value = { description, schema }
 */
exports.TOOL_DEFINITIONS = {
    bash: {
        description: "Execute a bash command with a configurable timeout. " +
            `Output is strictly limited to ${toolLimits_1.BASH_HARD_MAX_LINES} lines, ${toolLimits_1.BASH_MAX_LINE_BYTES} bytes per line, and ${toolLimits_1.BASH_MAX_TOTAL_BYTES} bytes total. ` +
            "Commands that exceed these limits will FAIL with an error (no partial output returned). " +
            "Be conservative: use 'head', 'tail', 'grep', or other filters to limit output before running commands.",
        schema: zod_1.z.object({
            script: zod_1.z.string().describe("The bash script/command to execute"),
            timeout_secs: zod_1.z
                .number()
                .positive()
                .optional()
                .describe(`Timeout (seconds, default: ${toolLimits_1.BASH_DEFAULT_TIMEOUT_SECS}). Start small and increase on retry; avoid large initial values to keep UX responsive`),
        }),
    },
    file_read: {
        description: "Read the contents of a file from the file system. Read as little as possible to complete the task.",
        schema: zod_1.z.object({
            filePath: zod_1.z.string().describe("The path to the file to read (absolute or relative)"),
            offset: zod_1.z
                .number()
                .int()
                .positive()
                .optional()
                .describe("1-based starting line number (optional, defaults to 1)"),
            limit: zod_1.z
                .number()
                .int()
                .positive()
                .optional()
                .describe("Number of lines to return from offset (optional, returns all if not specified)"),
        }),
    },
    file_edit_replace_string: {
        description: "Apply one or more edits to a file by replacing exact text matches. All edits are applied sequentially. Each old_string must be unique in the file unless replace_count > 1 or replace_count is -1.",
        schema: zod_1.z.object({
            file_path: zod_1.z.string().describe("The absolute path to the file to edit"),
            old_string: zod_1.z
                .string()
                .describe("The exact text to replace (must be unique in file if replace_count is 1). Include enough context (indentation, surrounding lines) to make it unique."),
            new_string: zod_1.z.string().describe("The replacement text"),
            replace_count: zod_1.z
                .number()
                .int()
                .optional()
                .describe("Number of occurrences to replace (default: 1). Use -1 to replace all occurrences. If 1, old_string must be unique in the file."),
        }),
    },
    file_edit_replace_lines: {
        description: "Replace a range of lines in a file. Use this for line-based edits when you know the exact line numbers to modify.",
        schema: zod_1.z.object({
            file_path: zod_1.z.string().describe("The absolute path to the file to edit"),
            start_line: zod_1.z.number().int().min(1).describe("1-indexed start line (inclusive) to replace"),
            end_line: zod_1.z.number().int().min(1).describe("1-indexed end line (inclusive) to replace"),
            new_lines: zod_1.z
                .array(zod_1.z.string())
                .describe("Replacement lines. Provide an empty array to delete the specified range."),
            expected_lines: zod_1.z
                .array(zod_1.z.string())
                .optional()
                .describe("Optional safety check. When provided, the current lines in the specified range must match exactly."),
        }),
    },
    file_edit_insert: {
        description: "Insert content at a specific line position in a file. Line offset is 1-indexed: 0 inserts at the top, 1 inserts after line 1, etc.",
        schema: zod_1.z.object({
            file_path: zod_1.z.string().describe("The absolute path to the file to edit"),
            line_offset: zod_1.z
                .number()
                .int()
                .min(0)
                .describe("1-indexed line position (0 = insert at top, N = insert after line N)"),
            content: zod_1.z.string().describe("The content to insert"),
            create: zod_1.z
                .boolean()
                .optional()
                .describe("If true, create the file if it doesn't exist (default: false)"),
        }),
    },
    propose_plan: {
        description: "Propose a plan before taking action. The plan should be complete but minimal - cover what needs to be decided or understood, nothing more. Use this tool to get approval before proceeding with implementation.",
        schema: zod_1.z.object({
            title: zod_1.z
                .string()
                .describe("A short, descriptive title for the plan (e.g., 'Add User Authentication')"),
            plan: zod_1.z
                .string()
                .describe("Implementation plan in markdown (start at h2 level). " +
                "Scale the detail to match the task complexity: for straightforward changes, briefly state what and why; " +
                "for complex changes, explain approach, key decisions, risks/tradeoffs; " +
                "for uncertain changes, clarify options and what needs user input. " +
                "When presenting options, always provide your recommendation for the overall best option for the user. " +
                "For highly complex concepts, use mermaid diagrams where they'd clarify better than text. " +
                "Cover what's necessary to understand and approve the approach. Omit obvious details or ceremony."),
        }),
    },
    todo_write: {
        description: "Create or update the todo list for tracking multi-step tasks (limit: 7 items). " +
            "Use this for ALL complex, multi-step plans to keep the user informed of progress. " +
            "Replace the entire list on each call - the AI should track which tasks are completed. " +
            "\n\n" +
            "Structure the list with high precision at the center:\n" +
            "- Old completed work: Summarize into 1 overview item (e.g., 'Set up project infrastructure (4 tasks)')\n" +
            "- Recent completions: Keep detailed (last 1-2 items)\n" +
            "- Current work: One in_progress item with clear description\n" +
            "- Immediate next steps: Detailed pending items (next 2-3 actions)\n" +
            "- Far future work: Summarize into phase items (e.g., 'Testing and polish (3 items)')\n" +
            "\n" +
            "Update frequently as work progresses. As tasks complete, older completions should be " +
            "condensed to make room. Similarly, summarized future work expands into detailed items " +
            "as it becomes immediate. " +
            "\n\n" +
            "Mark ONE task as in_progress at a time. " +
            "Order tasks as: completed first, then in_progress (max 1), then pending last. " +
            "Before finishing your response, ensure all todos are marked as completed. " +
            "Use appropriate tense in content: past tense for completed (e.g., 'Added tests'), " +
            "present progressive for in_progress (e.g., 'Adding tests'), " +
            "and imperative/infinitive for pending (e.g., 'Add tests').",
        schema: zod_1.z.object({
            todos: zod_1.z.array(zod_1.z.object({
                content: zod_1.z
                    .string()
                    .describe("Task description with tense matching status: past for completed, present progressive for in_progress, imperative for pending"),
                status: zod_1.z.enum(["pending", "in_progress", "completed"]).describe("Task status"),
            })),
        }),
    },
    todo_read: {
        description: "Read the current todo list",
        schema: zod_1.z.object({}),
    },
    status_set: {
        description: "Set a status indicator to show what the agent is currently doing. " +
            "The emoji appears left of the streaming indicator, and the message shows on hover. " +
            "IMPORTANT: Always set a status at the start of each response and update it as your work progresses. " +
            "Set a final status before finishing your response that reflects the outcome: " +
            "'✅ PR checks pass and ready to merge' (success), " +
            "'❌ CreateWorkspace Tests failed' (failure), " +
            "'⚠️ Encountered serious issue with design' (warning/blocker). " +
            "The status is cleared at the start of each new response, so you must set it again. " +
            "Use this to communicate ongoing activities (e.g., '🔍 Analyzing code', '📝 Writing tests', '🔧 Refactoring logic').",
        schema: zod_1.z
            .object({
            emoji: zod_1.z.string().describe("A single emoji character representing the current activity"),
            message: zod_1.z
                .string()
                .max(40)
                .describe("A brief description of the current activity (max 40 characters)"),
        })
            .strict(),
    },
};
/**
 * Get tool definition schemas for token counting
 * JSON schemas are auto-generated from zod schemas
 *
 * @returns Record of tool name to schema
 */
function getToolSchemas() {
    return Object.fromEntries(Object.entries(exports.TOOL_DEFINITIONS).map(([name, def]) => [
        name,
        {
            name,
            description: def.description,
            inputSchema: (0, zod_to_json_schema_1.zodToJsonSchema)(def.schema),
        },
    ]));
}
/**
 * Get which tools are available for a given model
 * @param modelString The model string (e.g., "anthropic:claude-opus-4-1")
 * @returns Array of tool names available for the model
 */
function getAvailableTools(modelString) {
    const [provider] = modelString.split(":");
    // Base tools available for all models
    const baseTools = [
        "bash",
        "file_read",
        "file_edit_replace_string",
        // "file_edit_replace_lines", // DISABLED: causes models to break repo state
        "file_edit_insert",
        "propose_plan",
        "todo_write",
        "todo_read",
        "status_set",
    ];
    // Add provider-specific tools
    switch (provider) {
        case "anthropic":
            return [...baseTools, "web_search"];
        case "openai":
            // Only some OpenAI models support web search
            if (modelString.includes("gpt-4") || modelString.includes("gpt-5")) {
                return [...baseTools, "web_search"];
            }
            return baseTools;
        case "google":
            return [...baseTools, "google_search"];
        default:
            return baseTools;
    }
}
//# sourceMappingURL=toolDefinitions.js.map