"use strict";
/**
 * Shared tool argument metadata for LangGraph, LangChain, and other OpenLit-style traces.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.mergedSpanAttributes = mergedSpanAttributes;
exports.getToolArgumentDefinitionFromAttrs = getToolArgumentDefinitionFromAttrs;
exports.getToolDescriptionFromAttrs = getToolDescriptionFromAttrs;
exports.getAgentDescriptionFromAttrs = getAgentDescriptionFromAttrs;
exports.inferArgumentDefinationFromInput = inferArgumentDefinationFromInput;
exports.inferArgumentDefinationFromInputValue = inferArgumentDefinationFromInputValue;
exports.buildToolArgumentFieldForLangChainEnrichment = buildToolArgumentFieldForLangChainEnrichment;
exports.enrichToolArgumentFieldsForLangChainFromSpan = enrichToolArgumentFieldsForLangChainFromSpan;
exports.inferTopLevelKeysFromToolArgumentsSchemaRepr = inferTopLevelKeysFromToolArgumentsSchemaRepr;
exports.extractOpenLitStyleToolFieldsFromSpan = extractOpenLitStyleToolFieldsFromSpan;
exports.mergeToolCallMessageDetailsIntoOpenLitFields = mergeToolCallMessageDetailsIntoOpenLitFields;
exports.isSpanDescendantOf = isSpanDescendantOf;
exports.collectAgentToolDefinitions = collectAgentToolDefinitions;
const utilts_1 = require("./utilts");
/** Attributes + spanAttributes (latter wins) for SDKs that put fields on spanAttributes (e.g. CrewAI). */
function mergedSpanAttributes(s) {
    return s?.attributes;
}
function getToolArgumentDefinitionFromAttrs(attributes) {
    return utilts_1.FrameworkUtils.getAttr(attributes, 'gen_ai.tool.definition', 'genai.tool.definition', 'gen_ai.tool.parameters', 'genai.tool.parameters', 'gen_ai.tool.json_schema', 'genai.tool.json_schema');
}
function getToolDescriptionFromAttrs(attributes) {
    const description = utilts_1.FrameworkUtils.getAttr(attributes, 'gen_ai.tool.description', 'genai.tool.description', 'gen_ai.tool.definition.description', 'genai.tool.definition.description');
    return typeof description === 'string' && description.trim() ? description.trim() : undefined;
}
function getAgentDescriptionFromAttrs(attributes) {
    const description = utilts_1.FrameworkUtils.getAttr(attributes, 'gen_ai.agent.description', 'genai.agent.description', 'gen_ai.workflow.description', 'genai.workflow.description');
    return typeof description === 'string' && description.trim() ? description.trim() : undefined;
}
/**
 * When the SDK does not emit a schema, infer parameter names from a Python-ish repr or JSON tool input string.
 * e.g. "{'stock': 'TCS'}" -> ["stock"]
 */
function inferArgumentDefinationFromInput(inputVal) {
    if (inputVal == null) {
        return undefined;
    }
    const s = typeof inputVal === 'string' ? inputVal.trim() : String(inputVal);
    if (!s) {
        return undefined;
    }
    const keys = new Set();
    const re = /['"]?([a-zA-Z_][a-zA-Z0-9_]*)['"]?\s*:/g;
    let m;
    while ((m = re.exec(s)) !== null) {
        keys.add(m[1]);
    }
    if (keys.size === 0) {
        return undefined;
    }
    return [...keys].sort((a, b) => a.localeCompare(b));
}
/**
 * Prefer actual input object keys when the runtime value is a plain object (avoids "[object Object]" stringification).
 */
function inferArgumentDefinationFromInputValue(inputVal) {
    if (inputVal != null && typeof inputVal === 'object' && !Array.isArray(inputVal)) {
        const keys = Object.keys(inputVal);
        if (keys.length > 0) {
            return [...keys].sort((a, b) => a.localeCompare(b));
        }
    }
    return inferArgumentDefinationFromInput(inputVal);
}
function getInputValueForParamKey(input, key) {
    if (input != null && typeof input === 'object' && !Array.isArray(input)) {
        return input[key];
    }
    if (typeof input === 'string') {
        const trimmed = input.trim();
        if (!trimmed.length) {
            return undefined;
        }
        try {
            const parsed = JSON.parse(trimmed);
            if (parsed != null && typeof parsed === 'object' && !Array.isArray(parsed)) {
                return parsed[key];
            }
        }
        catch {
            try {
                const jsonish = trimmed.replace(/'/g, '"');
                const parsed = JSON.parse(jsonish);
                if (parsed != null && typeof parsed === 'object' && !Array.isArray(parsed)) {
                    return parsed[key];
                }
            }
            catch {
                // ignore
            }
        }
    }
    return undefined;
}
/**
 * When the trace has no `gen_ai.tool.definition` / parameters, infer parameter names from input;
 * for multiple parameters, shape `argument` as `{ param1: value | '', ... }` so consumers see real
 * keys (e.g. pulse evaluation `extractArgumentNames`). When a schema is present on the span, keep
 * the raw `input` as `argument`.
 */
function buildToolArgumentFieldForLangChainEnrichment(input, definitionFromAttrs, inferredParamNames) {
    if (definitionFromAttrs != null) {
        return input;
    }
    if (inferredParamNames != null && inferredParamNames.length > 0) {
        if (inferredParamNames.length === 1) {
            const k = inferredParamNames[0];
            const v = getInputValueForParamKey(input, k);
            return { [k]: v == null ? '' : v };
        }
        const out = {};
        for (const k of inferredParamNames) {
            const v = getInputValueForParamKey(input, k);
            out[k] = v == null ? '' : v;
        }
        return out;
    }
    if (input === undefined) {
        return input;
    }
    return { arg: input };
}
/**
 * Single place for LangChain `argument` / `argument_defination` shaping (getTools enrichment and
 * {@link collectAgentToolDefinitions} output for agents).
 */
function enrichToolArgumentFieldsForLangChainFromSpan(input, attributes) {
    const definitionFromAttrs = getToolArgumentDefinitionFromAttrs(attributes);
    const inferredParamNames = definitionFromAttrs == null ? inferArgumentDefinationFromInputValue(input) : undefined;
    const argument_defination = definitionFromAttrs ?? inferredParamNames;
    const argument = buildToolArgumentFieldForLangChainEnrichment(input, definitionFromAttrs, inferredParamNames);
    return {
        argument,
        ...(argument_defination !== undefined && { argument_defination }),
    };
}
/**
 * CrewAI system prompts use a schema-shaped `Tool Arguments:` line, e.g.
 * `{'stock_symbol': {'description': None, 'type': 'str'}}` — only **top-level** keys are tool parameters;
 * nested `description` / `type` must not appear in `argument_defination`.
 */
function inferTopLevelKeysFromToolArgumentsSchemaRepr(s) {
    const trimmed = s.trim();
    if (!trimmed.length) {
        return undefined;
    }
    if (!trimmed.startsWith('{')) {
        return inferArgumentDefinationFromInput(trimmed);
    }
    let depth = 0;
    const keys = [];
    let i = 0;
    while (i < trimmed.length) {
        const c = trimmed[i];
        if (c === '{') {
            depth++;
            i++;
            continue;
        }
        if (c === '}') {
            depth--;
            i++;
            continue;
        }
        if (depth === 1) {
            const rest = trimmed.slice(i);
            const qm = rest.match(/^['"]([^'"]+)['"]\s*:/);
            if (qm) {
                keys.push(qm[1]);
                i += qm[0].length;
                continue;
            }
            const bm = rest.match(/^([a-zA-Z_][a-zA-Z0-9_]*)\s*:/);
            if (bm) {
                keys.push(bm[1]);
                i += bm[0].length;
                continue;
            }
        }
        i++;
    }
    if (keys.length > 0) {
        return [...new Set(keys)].sort((a, b) => a.localeCompare(b));
    }
    return inferArgumentDefinationFromInput(trimmed);
}
/**
 * Tool name + I/O + argument fields from standard gen_ai.tool.* / workflow fallbacks.
 */
function extractOpenLitStyleToolFieldsFromSpan(s) {
    const merged = mergedSpanAttributes(s);
    const toolNameAttr = utilts_1.FrameworkUtils.getAttr(merged, 'gen_ai.tool.name', 'genai.tool.name');
    const crewToolName = merged['tool_name'];
    const name = typeof s.name === 'string' && s.name.startsWith('tool ')
        ? s.name.replace(/^tool\s+/i, '').trim()
        : (crewToolName ?? toolNameAttr ?? s.name ?? '').toString().replace(/^tool\s+/i, '').trim();
    const input = utilts_1.FrameworkUtils.getAttr(merged, 'gen_ai.tool.input', 'genai.tool.input', 'gen_ai.workflow.input', 'genai.workflow.input');
    const output = utilts_1.FrameworkUtils.getAttr(merged, 'gen_ai.tool.output', 'genai.tool.output', 'gen_ai.workflow.output', 'genai.workflow.output');
    const description = getToolDescriptionFromAttrs(merged);
    const argument_defination = getToolArgumentDefinitionFromAttrs(merged) ?? inferArgumentDefinationFromInput(input);
    return { name, description, input, output, argument: input, argument_defination };
}
/**
 * Merge tool call payloads from message JSON when span attrs omit input/output.
 * Matches {@link extractOpenLitStyleToolFieldsFromSpan} + message merge used for {@link Tool} extraction.
 */
function mergeToolCallMessageDetailsIntoOpenLitFields(span, details, fields) {
    if (!details) {
        return fields;
    }
    const resolvedInput = fields.input ?? details.arguments;
    const resolvedOutput = fields.output ?? details.output;
    const merged = mergedSpanAttributes(span);
    const argument_defination = getToolArgumentDefinitionFromAttrs(merged) ?? inferArgumentDefinationFromInput(resolvedInput);
    return {
        ...fields,
        input: resolvedInput,
        output: resolvedOutput,
        argument: resolvedInput,
        argument_defination,
    };
}
function isSpanDescendantOf(spanId, ancestorId, spanById) {
    let cur = spanById.get(spanId)?.parentSpanId ?? null;
    const seen = new Set();
    while (cur) {
        if (cur === ancestorId) {
            return true;
        }
        if (seen.has(cur)) {
            return false;
        }
        seen.add(cur);
        cur = spanById.get(cur)?.parentSpanId ?? null;
    }
    return false;
}
/** Tool spans under this agent (recursive descendants), ordered by span start time. */
function collectAgentToolDefinitions(agentSpanId, spans, spanById, isToolSpan, options) {
    const toolSpans = spans.filter((sp) => isToolSpan(sp) && isSpanDescendantOf(sp.id, agentSpanId, spanById));
    const byTime = (sp) => {
        const t = sp.timestamp;
        if (typeof t === 'number') {
            return t <= 1e12 ? t : t / 1e6;
        }
        const p = Date.parse(String(t));
        return Number.isFinite(p) ? p : 0;
    };
    toolSpans.sort((a, b) => byTime(a) - byTime(b));
    const seen = new Set();
    const out = [];
    for (const sp of toolSpans) {
        if (seen.has(sp.id)) {
            continue;
        }
        seen.add(sp.id);
        const f = extractOpenLitStyleToolFieldsFromSpan(sp);
        const details = options?.mergeMessageDetails?.(sp);
        const merged = details ? mergeToolCallMessageDetailsIntoOpenLitFields(sp, details, f) : f;
        const name = options?.resolveToolDisplayName?.(sp, merged, details) ?? merged.name;
        if (options?.resolveToolDisplayName && !String(name ?? '').trim()) {
            continue;
        }
        out.push({
            name: String(name ?? ''),
            spanId: sp.id,
            ...(merged.description != null && { description: merged.description }),
            argument: merged.argument,
            output: merged.output,
            argument_defination: merged.argument_defination,
        });
    }
    return out;
}
//# sourceMappingURL=toolArgumentFields.js.map