"use strict";
/**
 * LlamaIndex OpenInference spans: AgentWorkflow.call_tool uses input.value / output.value
 * with embedded ToolCall(...) / ToolCallResult(...) Python repr strings — see samples/llamaindex-1.json.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseLlamaIndexCallToolAttrs = parseLlamaIndexCallToolAttrs;
exports.getMergedSpanAttrs = getMergedSpanAttrs;
exports.enrichLlamaIndexToolFields = enrichLlamaIndexToolFields;
const toolArgumentFields_1 = require("../../utils/toolArgumentFields");
function safeParseJson(val) {
    if (val == null) {
        return null;
    }
    if (typeof val === 'object') {
        return val;
    }
    if (typeof val !== 'string') {
        return null;
    }
    try {
        const parsed = JSON.parse(val);
        return typeof parsed === 'object' && parsed !== null ? parsed : null;
    }
    catch {
        return null;
    }
}
function extractBalancedBraceObject(s, startIdx) {
    let depth = 0;
    for (let i = startIdx; i < s.length; i++) {
        const c = s[i];
        if (c === '{') {
            depth++;
        }
        else if (c === '}') {
            depth--;
            if (depth === 0) {
                return s.slice(startIdx, i + 1);
            }
        }
    }
    return undefined;
}
/**
 * Flat Python dict literals in ToolCallResult (single-quoted keys/strings, None/True/False).
 * Best-effort JSON.parse after quote swap — fails on `'` inside string values.
 */
function tryParsePythonDictLiteral(dictStr) {
    const trimmed = dictStr.trim();
    if (!trimmed.startsWith('{')) {
        return undefined;
    }
    try {
        const normalized = trimmed
            .replace(/\bNone\b/g, 'null')
            .replace(/\bTrue\b/g, 'true')
            .replace(/\bFalse\b/g, 'false');
        const jsonCandidate = normalized.replace(/'/g, '"');
        const o = JSON.parse(jsonCandidate);
        if (o !== null && typeof o === 'object' && !Array.isArray(o)) {
            return o;
        }
    }
    catch {
        /**/
    }
    return undefined;
}
function extractDictAfterKey(s, key) {
    const re = new RegExp(`${key}\\s*=\\s*`);
    const m = s.match(re);
    if (!m || m.index === undefined) {
        return undefined;
    }
    const from = s.slice(m.index + m[0].length).trimStart();
    if (!from.startsWith('{')) {
        return undefined;
    }
    return extractBalancedBraceObject(from, 0);
}
function extractRawOutputFromRepr(s) {
    const dictStr = extractDictAfterKey(s, 'raw_output');
    if (dictStr) {
        const obj = tryParsePythonDictLiteral(dictStr);
        if (obj) {
            return obj;
        }
        return dictStr;
    }
    const listStr = (() => {
        const idx = s.search(/raw_output\s*=\s*\[/);
        if (idx === -1) {
            return undefined;
        }
        const from = s.slice(idx).replace(/^raw_output\s*=\s*/, '');
        if (!from.startsWith('[')) {
            return undefined;
        }
        let depth = 0;
        for (let i = 0; i < from.length; i++) {
            const c = from[i];
            if (c === '[') {
                depth++;
            }
            else if (c === ']') {
                depth--;
                if (depth === 0) {
                    return from.slice(0, i + 1);
                }
            }
        }
        return undefined;
    })();
    if (listStr) {
        try {
            return JSON.parse(listStr.replace(/'/g, '"'));
        }
        catch {
            return listStr;
        }
    }
    return undefined;
}
function searchToolCallRepr(s, out) {
    if (typeof s !== 'string' || (!s.includes('ToolCall(') && !s.includes('ToolCallResult('))) {
        return;
    }
    const nameMatch = s.match(/tool_name\s*=\s*['"]([^'"]+)['"]/);
    if (nameMatch) {
        out.toolName = nameMatch[1];
    }
    const kwargsDictStr = extractDictAfterKey(s, 'tool_kwargs');
    if (kwargsDictStr) {
        const parsed = tryParsePythonDictLiteral(kwargsDictStr);
        if (parsed) {
            out.toolKwargs = parsed;
        }
        else {
            const keys = (0, toolArgumentFields_1.inferTopLevelKeysFromToolArgumentsSchemaRepr)(kwargsDictStr);
            if (keys?.length) {
                out.toolKwargs = Object.fromEntries(keys.map((k) => [k, undefined]));
            }
        }
        if (out.toolKwargs?.to_agent != null) {
            out.isHandoff = true;
        }
    }
}
/**
 * Parse OpenInference `AgentWorkflow.call_tool` attributes (input.value / output.value).
 */
function parseLlamaIndexCallToolAttrs(attrs) {
    let inputVal = attrs['input.value'] ?? attrs['input'];
    const outputVal = attrs['output.value'] ?? attrs['output'];
    if (typeof inputVal === 'string') {
        const parsed = safeParseJson(inputVal);
        if (parsed && typeof parsed.ev === 'string') {
            inputVal = parsed.ev;
        }
    }
    const inputObj = safeParseJson(inputVal);
    const outputObj = safeParseJson(outputVal);
    const acc = { toolName: undefined, toolKwargs: undefined, isHandoff: false };
    if (typeof inputVal === 'string') {
        searchToolCallRepr(inputVal, acc);
    }
    if ((!acc.toolName || !acc.toolKwargs) && typeof outputVal === 'string' && (outputVal.includes('ToolCallResult(') || outputVal.includes('ToolCall('))) {
        searchToolCallRepr(outputVal, acc);
    }
    let toolName = acc.toolName;
    const toolKwargs = acc.toolKwargs;
    let isHandoff = acc.isHandoff;
    if (!toolName && outputObj && typeof outputObj.tool_name === 'string') {
        toolName = outputObj.tool_name;
        if (outputObj.tool_kwargs?.to_agent != null) {
            isHandoff = true;
        }
    }
    let output = outputObj?.raw_output ??
        outputObj?.tool_output ??
        outputObj?.raw_output ??
        outputObj ??
        outputVal;
    if (typeof outputVal === 'string' && (outputVal.includes('ToolCallResult(') || outputVal.includes('raw_output='))) {
        const raw = extractRawOutputFromRepr(outputVal);
        if (raw !== undefined) {
            output = raw;
        }
    }
    if (typeof inputVal === 'string' && inputVal.includes('ToolCallResult(')) {
        const raw = extractRawOutputFromRepr(inputVal);
        if (raw !== undefined) {
            output = raw;
        }
    }
    return {
        toolName,
        toolKwargs,
        input: inputObj ?? inputVal,
        output,
        isHandoff,
    };
}
/** Merge attributes + spanAttributes for OpenLit-style keys. */
function getMergedSpanAttrs(span) {
    return (0, toolArgumentFields_1.mergedSpanAttributes)(span);
}
/**
 * Add description, argument, argument_defination (and normalize argument from toolKwargs).
 */
function enrichLlamaIndexToolFields(tool, span, parsed) {
    const attrs = getMergedSpanAttrs(span);
    const argument = parsed.toolKwargs ?? tool.input;
    const argument_defination = (0, toolArgumentFields_1.getToolArgumentDefinitionFromAttrs)(attrs) ??
        (0, toolArgumentFields_1.inferArgumentDefinationFromInputValue)(argument);
    const description = (0, toolArgumentFields_1.getToolDescriptionFromAttrs)(attrs);
    const output = parsed.output === undefined ? tool.output : parsed.output;
    return {
        ...tool,
        ...(argument !== undefined && { input: argument }),
        argument,
        ...(output !== undefined && { output }),
        ...(description != null && { description }),
        ...(argument_defination !== undefined && { argument_defination }),
    };
}
//# sourceMappingURL=parseLlamaIndexCallToolIo.js.map