/**
 * Client-side context budget helpers — aligned with V3 server context_budget.py.
 * Initial agent context JSON should leave headroom for system prompt + tool loops.
 */
export const DEFAULT_CODE_RUNTIME_CTX = Number(process.env.V3_CODE_35B_RUNTIME_CTX || '49152');
export const CONTEXT_SAFETY_MARGIN = Number(process.env.V3_CONTEXT_SAFETY_MARGIN || '2048');
export const DEFAULT_MAX_OUTPUT_TOKENS = Number(process.env.V3_MAX_TOKENS || '16384');
export const TOKEN_BUDGET_SAFETY_FACTOR = Number(process.env.V3_TOKEN_BUDGET_SAFETY_FACTOR || '1.2');
export const CHARS_PER_TOKEN_EST = 4;
/** Max chars per file in workspaceFiles hydration (matches server TOOL_HISTORY cap order-of-magnitude). */
export const WORKSPACE_FILE_CHAR_CAP = Number(process.env.V3_TOOL_HISTORY_CHAR_CAP || '12000');
export function estimateTokens(text) {
    return Math.max(1, Math.ceil(String(text || '').length / CHARS_PER_TOKEN_EST));
}
export function estimateTokensForBudget(text) {
    return Math.ceil(estimateTokens(text) * TOKEN_BUDGET_SAFETY_FACTOR);
}
export function estimateJsonTokens(value) {
    try {
        return estimateTokens(JSON.stringify(value ?? ''));
    }
    catch {
        return 1;
    }
}
export function resolveInputBudget(runtimeNctx = DEFAULT_CODE_RUNTIME_CTX, maxOutput = DEFAULT_MAX_OUTPUT_TOKENS) {
    const cappedOutput = Math.max(4096, Math.min(maxOutput, Math.floor(runtimeNctx / 4)));
    return Math.max(4096, Math.floor((runtimeNctx - cappedOutput - CONTEXT_SAFETY_MARGIN) / TOKEN_BUDGET_SAFETY_FACTOR));
}
/**
 * Char limit for the initial V3 context JSON payload.
 * ~45% of input token budget × 4 chars/token, clamped 32k–100k.
 */
export function resolveV3ContextCharLimit(runtimeNctx = DEFAULT_CODE_RUNTIME_CTX) {
    const inputBudget = resolveInputBudget(runtimeNctx);
    const initialTurnTokens = Math.floor(inputBudget * 0.45);
    const charLimit = initialTurnTokens * CHARS_PER_TOKEN_EST;
    return Math.min(100_000, Math.max(32_000, charLimit));
}
export function compactToolListingOutput(name, output, charCap) {
    const text = String(output || '');
    if (text.length <= charCap)
        return text;
    if (['list_directory', 'glob', 'grep', 'search_project'].includes(name)) {
        const lines = text.split('\n');
        if (lines.length > 80) {
            const head = lines.slice(0, 40).join('\n');
            const tail = lines.slice(-20).join('\n');
            return `${head}\n\n... [${lines.length} lines total, middle omitted for context budget] ...\n\n${tail}`;
        }
    }
    const head = Math.max(1200, Math.floor(charCap / 3));
    const tail = Math.max(1200, Math.floor(charCap / 3));
    return `${text.slice(0, head)}\n\n...[truncated for context budget]...\n\n${text.slice(-tail)}`;
}
