"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.normalizeToolCallPairs = normalizeToolCallPairs;
exports.hasAdjacentMatchingToolResult = hasAdjacentMatchingToolResult;
exports.hasAdjacentMatchingToolCall = hasAdjacentMatchingToolCall;
exports.formatUnresolvedToolCallText = formatUnresolvedToolCallText;
exports.findFirstToolCallAdjacencyViolation = findFirstToolCallAdjacencyViolation;
exports.sanitizeToolContextForProvider = sanitizeToolContextForProvider;
exports.formatToolCallAdjacencyViolation = formatToolCallAdjacencyViolation;
function isToolCallMsg(msg) {
    return msg?.type === 'func_call_msg';
}
function isToolResultMsg(msg) {
    return msg?.type === 'func_result_msg';
}
function normalizeToolCallPairs(context) {
    // Providers differ in how strictly they validate tool call/result ordering. Dominds can
    // temporarily produce a block of calls followed by a block of results when tools run in
    // parallel, so we interleave obvious pairs here before provider projection.
    const out = [];
    let i = 0;
    while (i < context.length) {
        const msg = context[i];
        if (!isToolCallMsg(msg)) {
            out.push(msg);
            i += 1;
            continue;
        }
        const calls = [];
        while (i < context.length && isToolCallMsg(context[i])) {
            calls.push(context[i]);
            i += 1;
        }
        const results = [];
        while (i < context.length && isToolResultMsg(context[i])) {
            results.push(context[i]);
            i += 1;
        }
        if (results.length === 0) {
            out.push(...calls);
            continue;
        }
        const resultsById = new Map();
        for (const result of results) {
            const existing = resultsById.get(result.id);
            if (existing) {
                existing.push(result);
            }
            else {
                resultsById.set(result.id, [result]);
            }
        }
        const used = new Set();
        for (const call of calls) {
            out.push(call);
            const queue = resultsById.get(call.id);
            if (queue && queue.length > 0) {
                const next = queue.shift();
                if (next) {
                    out.push(next);
                    used.add(next);
                }
            }
        }
        for (const result of results) {
            if (!used.has(result)) {
                out.push(result);
            }
        }
    }
    return out;
}
function hasAdjacentMatchingToolResult(context, index) {
    const current = context[index];
    const next = context[index + 1];
    return isToolCallMsg(current) && isToolResultMsg(next) && current.id === next.id;
}
function hasAdjacentMatchingToolCall(context, index) {
    const previous = context[index - 1];
    const current = context[index];
    return isToolCallMsg(previous) && isToolResultMsg(current) && previous.id === current.id;
}
function formatUnresolvedToolCallText(call) {
    const argumentsText = call.arguments.trim();
    if (argumentsText.length === 0 || argumentsText === '{}') {
        return `[unresolved_tool_call:${call.name}:${call.id}]`;
    }
    return `[unresolved_tool_call:${call.name}:${call.id}] arguments=${argumentsText}`;
}
function findFirstToolCallAdjacencyViolation(context) {
    for (let index = 0; index < context.length; index += 1) {
        const msg = context[index];
        if (isToolCallMsg(msg) && !hasAdjacentMatchingToolResult(context, index)) {
            return {
                kind: 'unresolved_call',
                index,
                callId: msg.id,
                toolName: msg.name,
            };
        }
        if (isToolResultMsg(msg) && !hasAdjacentMatchingToolCall(context, index)) {
            return {
                kind: 'orphaned_result',
                index,
                callId: msg.id,
                toolName: msg.name,
            };
        }
    }
    return null;
}
function sanitizeToolContextForProvider(context) {
    const normalized = normalizeToolCallPairs(context);
    const sanitized = [];
    const droppedViolations = [];
    for (let index = 0; index < normalized.length; index += 1) {
        const msg = normalized[index];
        if (isToolCallMsg(msg)) {
            const next = normalized[index + 1];
            if (isToolResultMsg(next) && next.id === msg.id) {
                sanitized.push(msg, next);
                index += 1;
                continue;
            }
            droppedViolations.push({
                kind: 'unresolved_call',
                index,
                callId: msg.id,
                toolName: msg.name,
            });
            continue;
        }
        if (isToolResultMsg(msg)) {
            droppedViolations.push({
                kind: 'orphaned_result',
                index,
                callId: msg.id,
                toolName: msg.name,
            });
            continue;
        }
        sanitized.push(msg);
    }
    return {
        messages: sanitized,
        droppedViolations,
    };
}
function formatToolCallAdjacencyViolation(violation, location) {
    switch (violation.kind) {
        case 'unresolved_call':
            return (`${location}: unresolved persisted tool call message detected ` +
                `(callId=${violation.callId}, tool=${violation.toolName}, index=${violation.index}). ` +
                'This means a tool call was persisted without a matching tool result message.');
        case 'orphaned_result':
            return (`${location}: orphaned persisted tool result message detected ` +
                `(callId=${violation.callId}, tool=${violation.toolName}, index=${violation.index}). ` +
                'This means a tool result was restored without the immediately preceding tool call message.');
    }
}
