import { streamChat } from '../providers/openrouter.js';
/** Rough token estimate: ~4 chars per token. Good enough for a status line. */
export function estimateTokens(messages) {
    let chars = 0;
    for (const m of messages) {
        chars += typeof m.content === 'string' ? m.content.length : 0;
        if (m.role === 'assistant' && m.tool_calls) {
            for (const tc of m.tool_calls)
                chars += tc.function.arguments.length + tc.function.name.length;
        }
    }
    return Math.ceil(chars / 4);
}
const KEEP_RECENT = 4;
/** Fraction of the model's context window at which auto-compaction kicks in. */
export const COMPACT_THRESHOLD = 0.8;
export function shouldCompact(messages, contextLength) {
    if (!contextLength || contextLength <= 0)
        return false;
    return estimateTokens(messages) > contextLength * COMPACT_THRESHOLD;
}
/**
 * Summarize everything except the system prompt and the most recent messages,
 * then rebuild the history around the summary. Called manually via /compact
 * or automatically by the loop near the context limit.
 */
export async function compactMessages(opts) {
    const { messages } = opts;
    const system = messages.filter((m) => m.role === 'system');
    const rest = messages.filter((m) => m.role !== 'system');
    if (rest.length <= KEEP_RECENT) {
        return { messages, summarizedCount: 0 };
    }
    // Never split an assistant tool_calls message from its tool results.
    let cut = rest.length - KEEP_RECENT;
    while (cut > 0 && rest[cut].role === 'tool')
        cut--;
    const toSummarize = rest.slice(0, cut);
    const toKeep = rest.slice(cut);
    if (toSummarize.length === 0)
        return { messages, summarizedCount: 0 };
    const transcript = toSummarize
        .map((m) => {
        if (m.role === 'tool')
            return `[tool result]: ${m.content.slice(0, 1500)}`;
        if (m.role === 'assistant') {
            const calls = m.tool_calls?.map((tc) => `${tc.function.name}(${tc.function.arguments.slice(0, 300)})`) ?? [];
            return `assistant: ${m.content}${calls.length ? `\n[called: ${calls.join(', ')}]` : ''}`;
        }
        return `${m.role}: ${m.content}`;
    })
        .join('\n\n');
    const result = await streamChat({
        apiKey: opts.apiKey,
        model: opts.model,
        provider: opts.provider,
        messages: [
            {
                role: 'system',
                content: 'Summarize this coding-agent conversation so the agent can continue seamlessly. ' +
                    'Preserve: the original task and constraints, key decisions, files created/modified (with paths), ' +
                    'important code details, current state, and what remains to be done. Be dense and factual.',
            },
            { role: 'user', content: transcript },
        ],
    });
    const compacted = [
        ...system,
        {
            role: 'user',
            content: `[Conversation so far was compacted. Summary:]\n\n${result.content}`,
        },
        ...toKeep,
    ];
    return { messages: compacted, summarizedCount: toSummarize.length };
}
