/**
 * Loop tool — manage session-scoped recurring tasks.
 *
 * Lives behind the meta-tool wall (get_tool_info + execute_tool).
 * Never appears in the system prompt directly.
 *
 * Actions: start, stop, list, status.
 */
import { Type } from '@sinclair/typebox';
import { LOOP } from '../../tool-names.js';
// ---------------------------------------------------------------------------
// Schema
// ---------------------------------------------------------------------------
const schema = Type.Object({
    action: Type.Union([Type.Literal('start'), Type.Literal('stop'), Type.Literal('list'), Type.Literal('status')], { description: 'The action to perform' }),
    prompt: Type.Optional(Type.String({ description: 'The message to repeat on each tick (required for start)' })),
    intervalMs: Type.Optional(Type.Number({
        description: 'Interval in milliseconds between ticks (required for start, min 30000)'
    })),
    name: Type.Optional(Type.String({ description: 'Short name for the loop (auto-generated if omitted)' })),
    maxTicks: Type.Optional(Type.Number({ description: 'Maximum number of ticks before auto-stop (default: 100)' })),
    id: Type.Optional(Type.String({ description: 'Loop ID (required for stop)' }))
});
// ---------------------------------------------------------------------------
// Summary (for get_tool_info description)
// ---------------------------------------------------------------------------
export const LOOP_TOOL_SUMMARY = 'Manage recurring tasks within this session (start, stop, list)';
// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------
function formatLoop(loop) {
    const intervalSecs = Math.round(loop.intervalMs / 1000);
    const interval = intervalSecs >= 60 ? `${Math.round(intervalSecs / 60)}m` : `${intervalSecs}s`;
    const ticks = `${loop.tickCount}/${loop.maxTicks}`;
    const lastTick = loop.lastTickAtMs ? new Date(loop.lastTickAtMs).toISOString() : 'never';
    return [
        `  id: ${loop.id}`,
        `  name: ${loop.name}`,
        `  interval: ${interval}`,
        `  ticks: ${ticks}`,
        `  last tick: ${lastTick}`,
        `  prompt: ${loop.prompt}`
    ].join('\n');
}
// ---------------------------------------------------------------------------
// Description
// ---------------------------------------------------------------------------
const TOOL_DESCRIPTION = `\
Manage session-scoped recurring tasks (loops). Each loop periodically injects a message into the conversation.

**Actions:**
- \`start\` — Create a new loop (requires prompt, intervalMs)
- \`stop\` — Stop a loop (requires id)
- \`list\` — List all active loops
- \`status\` — Show loop count and next tick time

**Constraints:**
- Minimum interval: 30 seconds (30000ms)
- Maximum concurrent loops: 5
- Default max ticks: 100 (auto-stops after)

**Examples:**
- "every 5 minutes" → intervalMs: 300000
- "every 30 seconds" → intervalMs: 30000
- "every hour" → intervalMs: 3600000
`;
// ---------------------------------------------------------------------------
// Factory
// ---------------------------------------------------------------------------
export function createLoopTool(manager) {
    return {
        name: LOOP,
        label: 'Loop',
        isReadOnly: false,
        description: TOOL_DESCRIPTION,
        parameters: schema,
        async execute(_toolCallId, params) {
            let text;
            switch (params.action) {
                case 'start': {
                    if (!params.prompt) {
                        text = 'Error: "start" requires a "prompt" string.';
                        break;
                    }
                    if (!params.intervalMs) {
                        text = 'Error: "start" requires an "intervalMs" number.';
                        break;
                    }
                    try {
                        const loop = manager.start({
                            prompt: params.prompt,
                            intervalMs: params.intervalMs,
                            name: params.name,
                            maxTicks: params.maxTicks
                        });
                        const intervalSecs = Math.round(loop.intervalMs / 1000);
                        const interval = intervalSecs >= 60 ? `${Math.round(intervalSecs / 60)}m` : `${intervalSecs}s`;
                        text = `Loop started: "${loop.name}" (${loop.id})\nInterval: ${interval}\nMax ticks: ${loop.maxTicks}`;
                    }
                    catch (err) {
                        text = `Error: ${err instanceof Error ? err.message : String(err)}`;
                    }
                    break;
                }
                case 'stop': {
                    if (!params.id) {
                        text = 'Error: "stop" requires an "id".';
                        break;
                    }
                    const stopped = manager.stop(params.id);
                    text = stopped
                        ? `Loop ${params.id} stopped.`
                        : `Error: no loop with id "${params.id}". Use "list" to see active loops.`;
                    break;
                }
                case 'list': {
                    const loops = manager.list();
                    if (loops.length === 0) {
                        text = 'No active loops.';
                    }
                    else {
                        text = loops.map((l) => formatLoop(l)).join('\n\n');
                    }
                    break;
                }
                case 'status': {
                    const count = manager.size;
                    if (count === 0) {
                        text = 'No active loops.';
                    }
                    else {
                        const next = manager.nextTick();
                        const mins = next ? Math.max(0, Math.round(next.deltaMs / 60_000)) : 0;
                        text = `${count} active loop(s).${next ? ` Next tick: "${next.name}" in ~${mins}m.` : ''}`;
                    }
                    break;
                }
                default:
                    text = `Unknown action "${params.action}". Valid: start, stop, list, status.`;
            }
            return { content: [{ type: 'text', text }], details: undefined };
        }
    };
}
//# sourceMappingURL=loop.js.map