"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CrewAIParser = void 0;
const spanDeduplicator_1 = require("../utils/spanDeduplicator");
const toolCallAnalyzer_1 = require("../utils/toolCallAnalyzer");
const toolArgumentFields_1 = require("../utils/toolArgumentFields");
const utilts_1 = require("../utils/utilts");
/**
 * CrewAI Parser
 */
class CrewAIParser {
    constructor() {
        this.name = 'crewai';
        this.deduplicator = new spanDeduplicator_1.SpanDeduplicator();
        this.toolAnalyzer = new toolCallAnalyzer_1.ToolCallAnalyzer();
    }
    canParse(spans) {
        return spans.some(s => s.attributes['gen_ai.system'] === 'crewai' ||
            s.attributes['genai.system'] === 'crewai' ||
            s.name.includes('invoke_agent') && s.attributes['gen_ai.system'] !== 'autogen' ||
            s.name === 'Task Execution' ||
            (s.name === 'Tool Usage' && s.attributes?.['crewai_version']));
    }
    getTools(spans) {
        this.deduplicator.reset();
        const tools = [];
        const seenTools = new Set();
        for (const span of spans) {
            if (this.deduplicator.isDuplicate(span)) {
                continue;
            }
            // Filter out infrastructure spans
            if (this.isInfrastructureSpan(span)) {
                continue;
            }
            if (this.isToolSpan(span) && !seenTools.has(span.id)) {
                const tool = this.extractTool(span);
                if (tool) {
                    tools.push(tool);
                    seenTools.add(span.id);
                }
            }
        }
        return this.enrichToolsArgumentMetadata(tools, spans);
    }
    /**
     * CrewAI "Tool Usage" spans often omit I/O; inputs appear on the previous `chat` span as
     * `Action:` / `Action Input:` in `gen_ai.completion`, and tool contracts in `gen_ai.prompt`
     * (`Tool Name` / `Tool Arguments` / `Tool Description`) — see samples/crewai-1.json.
     * `Observation:` (tool result) is taken from the next sibling chat transcript when present (ReAct-shaped).
     */
    enrichToolsArgumentMetadata(tools, spans) {
        const spanById = new Map(spans.map((s) => [s.id, s]));
        return tools.map((t) => {
            const span = spanById.get(t.spanId);
            const attrs = span ? (0, toolArgumentFields_1.mergedSpanAttributes)(span) : {};
            const fromTrace = span ? this.enrichCrewToolFromAgentSiblings(span, t.name, spans) : {};
            const input = t.input ?? fromTrace.input;
            const output = t.output ?? fromTrace.output;
            const argument_defination = (0, toolArgumentFields_1.getToolArgumentDefinitionFromAttrs)(attrs) ??
                fromTrace.argument_defination ??
                (0, toolArgumentFields_1.inferArgumentDefinationFromInputValue)(input);
            const description = (0, toolArgumentFields_1.getToolDescriptionFromAttrs)(attrs) ?? fromTrace.description;
            return {
                ...t,
                ...(input !== undefined && { input }),
                argument: input,
                ...(output !== undefined && { output }),
                ...(description != null && { description }),
                ...(argument_defination !== undefined && { argument_defination }),
            };
        });
    }
    getAgents(spans) {
        this.deduplicator.reset();
        const agents = [];
        const seenAgents = new Set();
        const spanById = new Map(spans.map((s) => [s.id, s]));
        for (const span of spans) {
            if (this.deduplicator.isDuplicate(span)) {
                continue;
            }
            // Filter out infrastructure spans
            if (this.isInfrastructureSpan(span)) {
                continue;
            }
            if (this.isAgentSpan(span) && !seenAgents.has(span.id)) {
                const agent = this.extractAgent(span);
                if (agent) {
                    let toolDefinitions = (0, toolArgumentFields_1.collectAgentToolDefinitions)(agent.id, spans, spanById, (sp) => this.isToolSpan(sp), {
                        resolveToolDisplayName: (sp, merged) => {
                            const fromSpan = sp.attributes['tool_name'] ||
                                this.toolAnalyzer.extractToolName(sp);
                            const name = String(fromSpan ?? merged.name ?? '').trim();
                            return name || merged.name;
                        },
                    });
                    toolDefinitions = toolDefinitions.map((def) => {
                        const sp = spanById.get(def.spanId);
                        if (!sp) {
                            return def;
                        }
                        const fromTrace = this.enrichCrewToolFromAgentSiblings(sp, def.name, spans);
                        return {
                            ...def,
                            ...(def.argument === undefined && fromTrace.input !== undefined && { argument: fromTrace.input }),
                            ...(def.output === undefined && fromTrace.output !== undefined && { output: fromTrace.output }),
                            ...(def.description == null && fromTrace.description != null && { description: fromTrace.description }),
                            ...(def.argument_defination === undefined &&
                                fromTrace.argument_defination !== undefined && { argument_defination: fromTrace.argument_defination }),
                        };
                    });
                    agents.push(toolDefinitions.length > 0 ? { ...agent, toolDefinitions } : agent);
                    seenAgents.add(span.id);
                }
            }
        }
        return agents;
    }
    getModels(spans) {
        this.deduplicator.reset();
        const models = [];
        const seenModels = new Set();
        const spanById = new Map(spans.map((s) => [s.id, s]));
        // Valid entity span IDs (agents or tools) — models must have an ancestor in this set
        const validAncestorSpanIds = new Set();
        for (const span of spans) {
            if (!this.isInfrastructureSpan(span) && (this.isAgentSpan(span) || this.isToolSpan(span))) {
                validAncestorSpanIds.add(span.id);
            }
        }
        const hasAgentOrToolAncestor = (spanId) => {
            let cur = spanId;
            const seen = new Set();
            for (let i = 0; i < 50 && cur; i++) {
                if (seen.has(cur)) {
                    return false;
                }
                seen.add(cur);
                if (validAncestorSpanIds.has(cur)) {
                    return true;
                }
                cur = spanById.get(cur)?.parentSpanId ?? null;
            }
            return false;
        };
        for (const span of spans) {
            if (this.deduplicator.isDuplicate(span)) {
                continue;
            }
            if (this.isInfrastructureSpan(span)) {
                continue;
            }
            if (this.isModelSpan(span) && !seenModels.has(span.id)) {
                // Model must have some ancestor that is an agent or tool (handles agent→chat and agent→tool→…→chat)
                const parentId = span.parentSpanId ?? null;
                if (!parentId || !hasAgentOrToolAncestor(parentId)) {
                    continue;
                }
                const model = this.extractModel(span);
                if (model) {
                    models.push(model);
                    seenModels.add(span.id);
                }
            }
        }
        return models;
    }
    generateDag(spans) {
        this.deduplicator.reset();
        // Only prompt/response/model(llm)/agent/tool — exclude workflow so prompt isn't orphaned
        const allowedTypes = new Set(['llm', 'tool', 'agent']);
        const uniqueSpans = spans
            .filter(s => !this.deduplicator.isDuplicate(s))
            .filter(s => !this.isInfrastructureSpan(s))
            .filter(s => allowedTypes.has(this.getNodeType(s)));
        const nodes = uniqueSpans.map(span => {
            let displayName = span.name;
            if (this.isToolSpan(span)) {
                const toolName = span.attributes?.['tool_name'] || span.attributes['tool_name'];
                if (toolName)
                    displayName = toolName;
            }
            return {
                id: span.id,
                type: this.getNodeType(span),
                name: displayName,
                children: [],
                metadata: { span }
            };
        });
        const nodeMap = new Map(nodes.map(n => [n.id, n]));
        uniqueSpans.forEach(span => {
            if (span.parentSpanId && nodeMap.has(span.parentSpanId)) {
                nodeMap.get(span.parentSpanId).children.push(span.id);
            }
        });
        const byTime = [...uniqueSpans].sort((a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime());
        const firstSpanId = byTime.length > 0 ? byTime[0].id : undefined;
        const lastSpanId = byTime.length > 0 ? byTime[byTime.length - 1].id : undefined;
        if (firstSpanId != null) {
            nodes.push({
                id: 'prompt',
                type: 'prompt',
                name: 'Prompt',
                children: [firstSpanId],
                metadata: {}
            });
        }
        if (lastSpanId != null) {
            const lastNode = nodeMap.get(lastSpanId);
            if (lastNode) {
                lastNode.children = [...lastNode.children, 'response'];
            }
            nodes.push({
                id: 'response',
                type: 'response',
                name: 'Response',
                children: [],
                metadata: {}
            });
        }
        return nodes;
    }
    // generateLinearFlow(spans: Span[]): LinearStep[] {
    //   this.deduplicator.reset();
    //   return spans
    //     .filter(s => !this.deduplicator.isDuplicate(s))
    //     .filter(s => !this.isInfrastructureSpan(s))
    //     .sort((a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime())
    //     .map((span, index) => {
    //       const attrs = span.attributes;
    //       // Extract input/output based on span type
    //       const input = attrs['genai.workflow.input'] || attrs['gen_ai.prompt'];
    //       let output = attrs['genai.workflow.output'] || attrs['gen_ai.completion'];
    //       // For agent spans, try to get the event-based completion
    //       // Handle both structured events array and loose eventsAttributes array
    //       if (span.name.startsWith('invoke_agent')) {
    //         // Check structured events
    //         if (span.events) {
    //           const completionEvent = span.events.find(e => e.name === 'gen_ai.content.completion');
    //           if (completionEvent?.attributes?.['gen_ai.completion']) {
    //             output = completionEvent.attributes['gen_ai.completion'];
    //           }
    //         }
    //         // Check loose eventsAttributes (some ingestion paths use this)
    //         const looseEvents = (span as any)?.eventsAttributes;
    //         if (Array.isArray(looseEvents) && looseEvents.length > 0) {
    //           const completionData = looseEvents.find((e: any) => e?.['gen_ai.completion']);
    //           if (completionData?.['gen_ai.completion']) {
    //             output = completionData['gen_ai.completion'];
    //           }
    //         }
    //       }
    //       // For tool spans, use tool_name from attributes instead of generic "Tool Usage"
    //       let displayName = span.name;
    //       if (this.isToolSpan(span)) {
    //         const toolName = span.attributes?.['tool_name'] || span.attributes['tool_name'];
    //         if (toolName) {
    //           displayName = toolName;
    //         }
    //       }
    //       return {
    //         stepNumber: index + 1,
    //         spanId: span.id,
    //         type: this.getNodeType(span),
    //         name: displayName,
    //         timestamp: span.timestamp,
    //         duration: span.duration,
    //         input,
    //         output
    //       };
    //     });
    // }
    /**
     * Linear flow: only prompt/response/model(llm)/agent/tool.
     * Prompt → steps (agent/tool/llm) → Response.
     */
    generateLinearFlow(spans) {
        this.deduplicator.reset();
        const allowedTypes = new Set(['agent', 'tool', 'llm']);
        const filtered = spans
            .filter(s => !this.deduplicator.isDuplicate(s))
            .filter(s => !this.isInfrastructureSpan(s))
            .filter((span) => allowedTypes.has(this.getNodeType(span)))
            .sort((a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime());
        return filtered.map((span, index) => {
            let displayName = span.name;
            if (this.isToolSpan(span)) {
                const toolName = span.attributes?.['tool_name'] || span.attributes['tool_name'];
                if (toolName)
                    displayName = toolName;
            }
            return {
                stepNumber: index + 1,
                spanId: span.id,
                type: this.getNodeType(span),
                name: displayName,
                timestamp: span.timestamp,
                duration: span.duration,
                input: span.attributes['genai.workflow.input'] ??
                    span.attributes['gen_ai.prompt'],
                output: span.attributes['genai.workflow.output'] ??
                    span.attributes['gen_ai.completion']
            };
        });
    }
    // Helper methods
    isToolSpan(span) {
        return (span.name === 'Tool Usage' ||
            span.attributes?.['tool_name'] !== undefined ||
            span.attributes['tool_name'] !== undefined ||
            span.attributes['genai.tool.name'] !== undefined);
    }
    isAgentSpan(span) {
        // Explicitly exclude infrastructure spans first
        if (span.name === 'invoke_agent crew' ||
            span.name === 'invoke_agent task') {
            return false;
        }
        return (span.name.includes('invoke_agent') ||
            span.attributes['gen_ai.operation.name'] === 'invoke_agent' ||
            span.attributes?.['gen_ai.operation.name'] === 'invoke_agent' ||
            span.attributes['gen_ai.agent.name'] ||
            span.attributes?.['gen_ai.agent.name'] ||
            span.attributes['genai.agent.name']);
    }
    isModelSpan(span) {
        const attrs = span.attributes;
        if (span.name.startsWith('chat ')) {
            return true;
        }
        if (span.attributes['gen_ai.operation.name'] === 'chat') {
            return true;
        }
        if (span.attributes?.['gen_ai.operation.name'] === 'chat') {
            return true;
        }
        if (utilts_1.FrameworkUtils.getModelAttr(attrs, 'gen_ai.request.model', 'genai.request.model', 'gen_ai.response.model', 'genai.response.model')) {
            return true;
        }
        return false;
    }
    extractTool(span) {
        const merged = (0, toolArgumentFields_1.mergedSpanAttributes)(span);
        const toolName = span.attributes?.['tool_name'] ||
            span.attributes['tool_name'] ||
            this.toolAnalyzer.extractToolName(span);
        if (!toolName) {
            return null;
        }
        const input = utilts_1.FrameworkUtils.getAttr(merged, 'gen_ai.tool.input', 'genai.tool.input', 'gen_ai.workflow.input', 'genai.workflow.input', 'gen_ai.prompt', 'genai.prompt');
        const output = utilts_1.FrameworkUtils.getAttr(merged, 'gen_ai.tool.output', 'genai.tool.output', 'gen_ai.workflow.output', 'genai.workflow.output', 'gen_ai.completion', 'genai.completion');
        return (0, utilts_1.buildCanonicalTool)({
            id: span.id,
            name: toolName,
            input,
            output,
            duration: span.duration,
            timestamp: span.timestamp,
            spanId: span.id,
            executionType: 'actual',
            metadata: { spanId: span.id },
        });
    }
    extractAgent(span) {
        const attrs = span.attributes;
        // Extract agent name from span name like "invoke_agent Chief Investment Officer"
        let agentName = attrs['gen_ai.agent.name'] ||
            attrs['genai.agent.name'];
        if (!agentName && span.name.startsWith('invoke_agent ')) {
            agentName = span.name.replace('invoke_agent ', '').trim();
        }
        if (!agentName) {
            return null;
        }
        // Explicitly reject infrastructure-related agent names
        const infrastructureNames = ['crew', 'task', 'unknown'];
        if (infrastructureNames.includes(agentName.toLowerCase())) {
            return null;
        }
        const description = attrs['gen_ai.agent.description'] || attrs?.['gen_ai.agent.description'];
        const allowDelegation = attrs['gen_ai.agent.allow_delegation'] || attrs?.['gen_ai.agent.allow_delegation'];
        const maxRetryLimit = attrs['gen_ai.agent.max_retry_limit'] || attrs?.['gen_ai.agent.max_retry_limit'];
        const allowCodeExecution = attrs['gen_ai.agent.allow_code_execution'] || attrs?.['gen_ai.agent.allow_code_execution'];
        const mergedAttrs = { ...attrs };
        const toolsDeclared = mergedAttrs['gen_ai.agent.tools'] ?? mergedAttrs['genai.agent.tools'];
        return (0, utilts_1.buildCanonicalAgent)({
            id: span.id,
            name: agentName,
            type: 'crewai',
            ...((0, toolArgumentFields_1.getAgentDescriptionFromAttrs)(mergedAttrs) != null && {
                description: (0, toolArgumentFields_1.getAgentDescriptionFromAttrs)(mergedAttrs),
            }),
            role: attrs['agent_role'],
            goal: attrs['gen_ai.agent.goal'],
            backstory: attrs['gen_ai.agent.backstory'],
            metadata: {
                spanId: span.id,
                timestamp: span.timestamp,
                duration: span.duration,
                agentId: attrs['gen_ai.agent.id'] || attrs?.['gen_ai.agent.id'],
                description,
                allowDelegation,
                maxRetryLimit,
                allowCodeExecution,
                ...(toolsDeclared != null && toolsDeclared !== '' && { toolsDeclared }),
            },
        });
    }
    extractModel(span) {
        const attrs = span.attributes;
        // Get model name - try multiple attribute formats
        const modelName = utilts_1.FrameworkUtils.getModelAttrResponseFirst(attrs);
        if (!modelName) {
            return null;
        }
        // Extract token usage - try multiple formats
        const inputTokens = utilts_1.FrameworkUtils.safeParseInt(utilts_1.FrameworkUtils.getAttr(attrs, 'gen_ai.usage.input_tokens', 'genai.usage.inputtokens'));
        const outputTokens = utilts_1.FrameworkUtils.safeParseInt(utilts_1.FrameworkUtils.getAttr(attrs, 'gen_ai.usage.output_tokens', 'genai.usage.outputtokens'));
        let totalTokens = utilts_1.FrameworkUtils.safeParseInt(utilts_1.FrameworkUtils.getAttr(attrs, 'gen_ai.usage.total_tokens', 'genai.usage.totaltokens'));
        if (!totalTokens && (inputTokens || outputTokens)) {
            totalTokens = inputTokens + outputTokens;
        }
        const { cacheRead, cacheWrite } = utilts_1.FrameworkUtils.getCacheTokens(attrs);
        const provider = utilts_1.FrameworkUtils.getAttr(attrs, 'gen_ai.system', 'genai.system') ||
            'openai';
        return (0, utilts_1.buildCanonicalExtendedModel)({
            id: span.id,
            provider: String(provider),
            modelName: String(modelName),
            tokenUsage: {
                inputTokens: inputTokens || 0,
                outputTokens: outputTokens || 0,
                totalTokens: totalTokens || 0,
                ...(cacheRead != null && { cacheRead }),
                ...(cacheWrite != null && { cacheWrite }),
            },
            spanId: span.id,
            timestamp: span.timestamp,
            temperature: utilts_1.FrameworkUtils.safeParseFloat(utilts_1.FrameworkUtils.getAttr(attrs, 'gen_ai.request.temperature', 'genai.request.temperature')),
            cost: utilts_1.FrameworkUtils.safeParseFloat(utilts_1.FrameworkUtils.getAttr(attrs, 'gen_ai.usage.cost', 'genai.usage.cost')) || 0,
            ttft: utilts_1.FrameworkUtils.safeParseFloat(attrs['gen_ai.server.time_to_first_token']),
            serverTimePerOutputToken: utilts_1.FrameworkUtils.safeParseFloat(attrs['gen_ai.server.time_per_output_token']),
            prompt: utilts_1.FrameworkUtils.getAttr(attrs, 'gen_ai.prompt', 'genai.prompt'),
            completion: utilts_1.FrameworkUtils.getAttr(attrs, 'gen_ai.completion', 'genai.completion'),
            duration: utilts_1.FrameworkUtils.safeParseFloat(span.duration ?? 0) ?? 0,
        });
    }
    getNodeType(span) {
        // Check for specific CrewAI span types
        if (span.name === 'Tool Usage') {
            return 'tool';
        }
        if (span.name === 'Task Execution' || span.name === 'Task Created' || span.name === 'Crew Created') {
            return 'workflow';
        }
        if (span.name.startsWith('invoke_agent ') && !span.name.includes('crew') && !span.name.includes('task')) {
            return 'agent';
        }
        if (span.name.startsWith('chat ')) {
            return 'llm';
        }
        // Fall back to attribute-based detection
        if (this.isAgentSpan(span)) {
            return 'agent';
        }
        if (this.isToolSpan(span)) {
            return 'tool';
        }
        if (this.isModelSpan(span)) {
            return 'llm';
        }
        return 'workflow';
    }
    /** Monotonic time for ordering sibling spans (matches collectAgentToolDefinitions). */
    spanTimeMs(span) {
        const t = span.timestamp;
        if (typeof t === 'number') {
            return t <= 1e12 ? t : t / 1e6;
        }
        const p = Date.parse(String(t));
        return Number.isFinite(p) ? p : 0;
    }
    /**
     * From OpenLit chat spans under the same agent as `toolSpan`: Action Input JSON and
     * tool contract lines embedded in the system prompt.
     */
    enrichCrewToolFromAgentSiblings(toolSpan, toolName, spans) {
        const parentId = toolSpan.parentSpanId;
        if (!parentId) {
            return {};
        }
        const siblings = spans.filter((s) => s.parentSpanId === parentId);
        siblings.sort((a, b) => this.spanTimeMs(a) - this.spanTimeMs(b));
        const toolIdx = siblings.findIndex((s) => s.id === toolSpan.id);
        if (toolIdx === -1) {
            return {};
        }
        let description;
        let argument_defination;
        for (const s of siblings) {
            if (!this.isModelSpan(s)) {
                continue;
            }
            const merged = (0, toolArgumentFields_1.mergedSpanAttributes)(s);
            const prompt = utilts_1.FrameworkUtils.getAttr(merged, 'gen_ai.prompt', 'genai.prompt');
            if (typeof prompt !== 'string' || !prompt.includes('Tool Name:')) {
                continue;
            }
            const parsed = this.parseCrewToolContractFromPrompt(prompt, toolName);
            if (parsed.description) {
                description = parsed.description;
            }
            if (parsed.argument_defination !== undefined) {
                argument_defination = parsed.argument_defination;
            }
        }
        let output;
        for (let i = toolIdx + 1; i < siblings.length; i++) {
            const s = siblings[i];
            if (!this.isModelSpan(s)) {
                continue;
            }
            const merged = (0, toolArgumentFields_1.mergedSpanAttributes)(s);
            const prompt = utilts_1.FrameworkUtils.getAttr(merged, 'gen_ai.prompt', 'genai.prompt') ?? '';
            const completion = utilts_1.FrameworkUtils.getAttr(merged, 'gen_ai.completion', 'genai.completion') ?? '';
            for (const h of [prompt, completion]) {
                if (typeof h !== 'string' || h.length === 0) {
                    continue;
                }
                const raw = this.extractObservationForToolFromTranscript(h, toolName);
                if (raw) {
                    output = this.parseObservationPayload(raw);
                    break;
                }
            }
            if (output !== undefined) {
                break;
            }
        }
        let input;
        for (let i = toolIdx - 1; i >= 0; i--) {
            const s = siblings[i];
            if (!this.isModelSpan(s)) {
                continue;
            }
            const merged = (0, toolArgumentFields_1.mergedSpanAttributes)(s);
            const completion = utilts_1.FrameworkUtils.getAttr(merged, 'gen_ai.completion', 'genai.completion');
            if (typeof completion !== 'string') {
                continue;
            }
            const jsonStr = this.extractActionInputJsonFromCompletion(completion, toolName);
            if (jsonStr) {
                try {
                    input = JSON.parse(jsonStr);
                }
                catch {
                    input = jsonStr;
                }
                break;
            }
        }
        if (argument_defination === undefined && input !== undefined) {
            argument_defination = (0, toolArgumentFields_1.inferArgumentDefinationFromInputValue)(input);
        }
        return {
            ...(input !== undefined && { input }),
            ...(output !== undefined && { output }),
            ...(description !== undefined && { description }),
            ...(argument_defination !== undefined && { argument_defination }),
        };
    }
    /**
     * Best-effort: ReAct transcripts often include `Observation:` after `Action` / `Action Input` for this tool.
     * Only reliable when that formatting is present (typical CrewAI + OpenLit); otherwise returns undefined.
     */
    extractObservationForToolFromTranscript(text, toolName) {
        const esc = toolName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
        const blockRe = new RegExp(`Action\\s*:\\s*${esc}`, 'gi');
        let lastStart = -1;
        let m;
        while ((m = blockRe.exec(text)) !== null) {
            lastStart = m.index;
        }
        if (lastStart === -1) {
            return undefined;
        }
        const fromAction = text.slice(lastStart);
        const obsIdx = fromAction.search(/Observation\s*:/i);
        if (obsIdx === -1) {
            return undefined;
        }
        const afterObs = fromAction.slice(obsIdx);
        const colon = afterObs.match(/^Observation\s*:\s*/i);
        if (!colon) {
            return undefined;
        }
        const rest = afterObs.slice(colon[0].length).trimStart();
        if (rest.startsWith('{')) {
            return this.extractBalancedBraceObject(rest, 0);
        }
        if (rest.startsWith('[')) {
            return this.extractBalancedBracketArray(rest, 0);
        }
        const stop = rest.search(/\n\n(?=[A-Z])/);
        const segment = stop === -1 ? rest : rest.slice(0, stop);
        const firstLine = segment.split(/\n/)[0]?.trim();
        return firstLine || undefined;
    }
    extractBalancedBracketArray(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;
    }
    /** Parse JSON when possible; otherwise return the raw observation string (e.g. Python repr). */
    parseObservationPayload(raw) {
        const t = raw.trim();
        if (!t) {
            return undefined;
        }
        try {
            return JSON.parse(t);
        }
        catch {
            return t;
        }
    }
    /**
     * Match `Action: <tool>` then `Action Input: { ... }` in a ReAct-style completion (CrewAI / OpenLit).
     */
    extractActionInputJsonFromCompletion(completion, toolName) {
        const esc = toolName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
        const blockRe = new RegExp(`Action\\s*:\\s*${esc}`, 'i');
        const idx = completion.search(blockRe);
        if (idx === -1) {
            return undefined;
        }
        const after = completion.slice(idx);
        const ai = after.search(/Action\s*Input\s*:/i);
        if (ai === -1) {
            return undefined;
        }
        const tail = after.slice(ai);
        const brace = tail.indexOf('{');
        if (brace === -1) {
            return undefined;
        }
        return this.extractBalancedBraceObject(tail, brace);
    }
    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;
    }
    /**
     * Parse `Tool Name` / `Tool Arguments` / `Tool Description` blocks from the agent system prompt.
     */
    parseCrewToolContractFromPrompt(prompt, toolName) {
        const target = toolName.trim().toLowerCase();
        const lines = prompt.split(/\r?\n/);
        for (let i = 0; i < lines.length; i++) {
            const m = lines[i].match(/^Tool Name:\s*(.+)$/i);
            if (!m || m[1].trim().toLowerCase() !== target) {
                continue;
            }
            let argsLine = '';
            let desc = '';
            for (let j = i + 1; j < Math.min(i + 30, lines.length); j++) {
                const argsM = lines[j].match(/^Tool Arguments:\s*(.+)$/i);
                if (argsM) {
                    argsLine = argsM[1].trim();
                }
                const descM = lines[j].match(/^Tool Description:\s*(.+)$/i);
                if (descM) {
                    desc = descM[1].trim();
                    break;
                }
            }
            const argument_defination = argsLine.length > 0 ? (0, toolArgumentFields_1.inferTopLevelKeysFromToolArgumentsSchemaRepr)(argsLine) : undefined;
            return {
                ...(desc.length > 0 && { description: desc }),
                ...(argument_defination !== undefined && { argument_defination }),
            };
        }
        return {};
    }
    /**
     * Filter infrastructure spans to clean up the visualization
     * Filters out:
     * - HTTP/POST spans (OpenAI API calls)
     * - Task/Crew creation spans (orchestration metadata)
     * - "invoke_agent crew" and "invoke_agent task" wrapper spans
     *
     * NOTE: Task Execution spans are kept as they contain actual agent work
     */
    isInfrastructureSpan(span) {
        // Filter HTTP infrastructure
        if (span.attributes['http.method'] !== undefined ||
            span.attributes['http.url'] !== undefined ||
            span.name === 'POST') {
            return true;
        }
        // Filter CrewAI orchestration metadata spans
        // NOTE: Do NOT filter "Task Execution" as it may contain actual work
        if (span.name === 'Task Created' ||
            span.name === 'Crew Created') {
            return true;
        }
        // Filter wrapper spans for crew and task orchestration
        if (span.name === 'invoke_agent crew' ||
            span.name === 'invoke_agent task') {
            return true;
        }
        return false;
    }
}
exports.CrewAIParser = CrewAIParser;
//# sourceMappingURL=crewai.js.map