import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
import { useState, useEffect, useMemo, useRef, useLayoutEffect, useCallback } from "react";
import { formatTime } from "../utils";
import { useEditContext } from "../client/editContext";
import { ToolCallDisplay } from "./ToolCallDisplay";
import { MediaImage } from "./MediaImage";
import { X, Brain, ChevronDown, ChevronRight, Loader2, Undo2, Check } from "lucide-react";
import { Button } from "../../components/ui/button";
import { Checkbox } from "../../components/ui/checkbox";
import { Tooltip, TooltipTrigger, TooltipContent, } from "../../components/ui/tooltip";
import { SecretAgentIcon } from "../ui/Icons";
import { CopyButton } from "../../components/ui/copy-button";
import { sanitizeHtml, sanitizeSvg } from "../../lib/sanitize";
// Helper to extract partial quick actions from potentially incomplete JSON during streaming
const extractPartialQuickActions = (jsonText) => {
    const actions = [];
    // First try to parse complete JSON
    try {
        const parsed = JSON.parse(jsonText);
        const rawActions = Array.isArray(parsed)
            ? parsed
            : parsed?.actions || parsed?.buttons || parsed?.choices || [];
        if (Array.isArray(rawActions)) {
            rawActions.forEach((a) => {
                if (!a)
                    return;
                const label = a.label || a.text || String(a.value || a.prompt || "");
                if (label) {
                    actions.push({
                        id: a.id,
                        label,
                        prompt: a.prompt,
                        value: a.value,
                        style: a.style,
                        behavior: a.behavior &&
                            (a.behavior === "compose" || a.behavior === "submit")
                            ? a.behavior
                            : a.submit === false ||
                                a.compose === true ||
                                a.draft === true ||
                                a.mode === "compose"
                                ? "compose"
                                : undefined,
                        placeholder: a.placeholder,
                    });
                }
            });
        }
        return actions;
    }
    catch (e) {
        // JSON is incomplete, try to extract whatever complete action objects we can find
    }
    // Look for individual action objects in the partial JSON
    // Match patterns like: { "label": "...", ... }
    const labelPattern = /"(?:label|text)"\s*:\s*"([^"\\]*(\\.[^"\\]*)*)"/g;
    const labelMatches = [];
    let labelMatch;
    while ((labelMatch = labelPattern.exec(jsonText)) !== null) {
        if (labelMatch[1]) {
            labelMatches.push({
                label: labelMatch[1],
                startIdx: labelMatch.index,
            });
        }
    }
    // For each label field found, try to find and parse the enclosing object
    for (const { label, startIdx } of labelMatches) {
        // Find the opening brace before this label field
        let openBrace = -1;
        for (let i = startIdx - 1; i >= 0; i--) {
            if (jsonText[i] === "{") {
                openBrace = i;
                break;
            }
            if (jsonText[i] === "}")
                break; // Hit another object's end
        }
        if (openBrace === -1)
            continue;
        // Find the closing brace after this label field
        let closeBrace = -1;
        let depth = 0;
        for (let i = openBrace; i < jsonText.length; i++) {
            if (jsonText[i] === "{")
                depth++;
            if (jsonText[i] === "}") {
                depth--;
                if (depth === 0) {
                    closeBrace = i;
                    break;
                }
            }
        }
        // Extract the object and try to parse it
        const objStr = closeBrace !== -1
            ? jsonText.substring(openBrace, closeBrace + 1)
            : jsonText.substring(openBrace) + "}"; // Try to close incomplete object
        try {
            const obj = JSON.parse(objStr);
            const actionLabel = obj.label || obj.text || String(obj.value || obj.prompt || "");
            if (actionLabel) {
                actions.push({
                    id: obj.id,
                    label: actionLabel,
                    prompt: obj.prompt,
                    value: obj.value,
                    style: obj.style,
                    behavior: obj.behavior &&
                        (obj.behavior === "compose" || obj.behavior === "submit")
                        ? obj.behavior
                        : obj.submit === false ||
                            obj.compose === true ||
                            obj.draft === true ||
                            obj.mode === "compose"
                            ? "compose"
                            : undefined,
                    placeholder: obj.placeholder,
                });
            }
        }
        catch (e) {
            // Skip malformed objects
        }
    }
    return actions;
};
function parseContentSegments(content, hideIncomplete) {
    if (!content)
        return [];
    const segments = [];
    const fencedQuickToken = "```quick_action_buttons";
    const plainQuickToken = "quick_action_buttons";
    const fencedTodoToken = "```todo_list";
    const plainTodoToken = "todo_list";
    const fencedMediaToken = "```media_item";
    const fencedJsonToken = "```json";
    // Helper: find next valid plain token occurrence (at line start or after newline)
    const findNextPlainHeader = (token, fromIndex) => {
        let idx = content.indexOf(token, fromIndex);
        while (idx !== -1) {
            const before = idx > 0 ? content[idx - 1] : "\n";
            const after = content[idx + token.length] || "\n";
            const isBoundaryBefore = before === "\n" || before === "\r";
            const isBoundaryAfter = after === "\n" || after === "\r" || after === ":" || /\s/.test(after);
            // Ensure it's not the fenced token which would have ``` right before
            const isFencedPrefix = content.slice(Math.max(0, idx - 3), idx) === "```";
            if (isBoundaryBefore && isBoundaryAfter && !isFencedPrefix)
                return idx;
            idx = content.indexOf(token, idx + 1);
        }
        return -1;
    };
    // Helper: match JSON object braces starting at first '{'
    const findMatchingBraceEnd = (startPos) => {
        let i = startPos;
        let depth = 0;
        let inString = false;
        let stringQuote = null;
        let escaped = false;
        for (; i < content.length; i++) {
            const ch = content[i];
            if (inString) {
                if (escaped) {
                    escaped = false;
                }
                else if (ch === "\\") {
                    escaped = true;
                }
                else if (ch === stringQuote) {
                    inString = false;
                    stringQuote = null;
                }
                continue;
            }
            else {
                if (ch === '"' || ch === "'") {
                    inString = true;
                    stringQuote = ch;
                    continue;
                }
                if (ch === "{")
                    depth++;
                if (ch === "}") {
                    depth--;
                    if (depth === 0)
                        return i;
                }
            }
        }
        return -1;
    };
    let cursor = 0;
    while (cursor < content.length) {
        const nextFencedQuick = content.indexOf(fencedQuickToken, cursor);
        const nextPlainQuick = findNextPlainHeader(plainQuickToken, cursor);
        const nextFencedTodo = content.indexOf(fencedTodoToken, cursor);
        const nextPlainTodo = findNextPlainHeader(plainTodoToken, cursor);
        const nextFencedMedia = content.indexOf(fencedMediaToken, cursor);
        const nextFencedJson = content.indexOf(fencedJsonToken, cursor);
        const candidates = [];
        if (nextFencedQuick !== -1)
            candidates.push({
                start: nextFencedQuick,
                kind: "fenced",
                type: "quick",
            });
        if (nextPlainQuick !== -1)
            candidates.push({ start: nextPlainQuick, kind: "plain", type: "quick" });
        if (nextFencedTodo !== -1)
            candidates.push({ start: nextFencedTodo, kind: "fenced", type: "todo" });
        if (nextPlainTodo !== -1)
            candidates.push({ start: nextPlainTodo, kind: "plain", type: "todo" });
        if (nextFencedMedia !== -1)
            candidates.push({
                start: nextFencedMedia,
                kind: "fenced",
                type: "media",
            });
        if (nextFencedJson !== -1)
            candidates.push({ start: nextFencedJson, kind: "fenced", type: "json" });
        let pick = null;
        if (candidates.length > 0) {
            pick = candidates.reduce((min, cur) => cur.start < min.start ? cur : min);
        }
        if (pick === null) {
            const tail = content.slice(cursor);
            if (tail)
                segments.push({ kind: "text", text: tail });
            break;
        }
        // Push any text before the token
        const textBefore = content.slice(cursor, pick.start);
        if (textBefore)
            segments.push({ kind: "text", text: textBefore });
        if (pick.kind === "fenced") {
            const openTokenLength = pick.type === "quick"
                ? fencedQuickToken.length
                : pick.type === "todo"
                    ? fencedTodoToken.length
                    : pick.type === "json"
                        ? fencedJsonToken.length
                        : fencedMediaToken.length;
            const afterOpenLineStart = pick.start + openTokenLength;
            const openLineMatch = content
                .slice(afterOpenLineStart)
                .match(/^[^\n\r]*\r?\n?/);
            const openLineLength = openLineMatch ? openLineMatch[0].length : 0;
            const jsonStart = afterOpenLineStart + openLineLength;
            const close = content.indexOf("```", jsonStart);
            const jsonText = (close === -1
                ? content.slice(jsonStart)
                : content.slice(jsonStart, close)).trim();
            if (close === -1) {
                // Incomplete fenced block during streaming
                if (hideIncomplete && pick.type === "quick") {
                    // Try to parse partial quick actions and show what we have so far
                    const partialActions = extractPartialQuickActions(jsonText);
                    if (partialActions.length > 0) {
                        segments.push({ kind: "actions", actions: partialActions });
                    }
                    break;
                }
                else if (hideIncomplete && pick.type === "json") {
                    // Try to show partial JSON during streaming
                    if (jsonText.trim()) {
                        try {
                            // Try to parse complete JSON
                            const parsed = JSON.parse(jsonText);
                            segments.push({ kind: "json", data: parsed, raw: jsonText });
                        }
                        catch {
                            // Show raw partial JSON during streaming
                            segments.push({
                                kind: "json",
                                data: null,
                                raw: jsonText + "...",
                            });
                        }
                    }
                    break;
                }
                else if (hideIncomplete) {
                    break;
                }
                else {
                    segments.push({ kind: "text", text: content.slice(pick.start) });
                    break;
                }
            }
            // Handle media_item blocks separately (pipe-delimited format, not JSON)
            if (pick.type === "media") {
                const items = [];
                // Parse pipe-delimited format: {GUID}|Label or just {GUID}
                const lines = jsonText
                    .split(/\r?\n/)
                    .map((l) => l.trim())
                    .filter((l) => l);
                for (const line of lines) {
                    // Only parse complete lines (must have closing brace)
                    if (line.includes("}")) {
                        const pipeIndex = line.indexOf("|");
                        if (pipeIndex !== -1) {
                            // Has label
                            const itemId = line.substring(0, pipeIndex).trim();
                            const label = line.substring(pipeIndex + 1).trim();
                            if (itemId && /\{[0-9a-fA-F-]+\}/.test(itemId)) {
                                items.push({ itemId, label: label || undefined });
                            }
                        }
                        else {
                            // No label
                            const itemId = line.trim();
                            if (itemId && /\{[0-9a-fA-F-]+\}/.test(itemId)) {
                                items.push({ itemId });
                            }
                        }
                    }
                }
                if (items.length > 0) {
                    segments.push({
                        kind: "media",
                        items: items,
                    });
                }
                cursor = close + 3;
                continue;
            }
            // Handle json blocks - display as formatted JSON
            if (pick.type === "json") {
                try {
                    const parsed = JSON.parse(jsonText);
                    segments.push({
                        kind: "json",
                        data: parsed,
                        raw: jsonText,
                    });
                }
                catch {
                    // If JSON is invalid, show as raw text
                    segments.push({
                        kind: "json",
                        data: null,
                        raw: jsonText,
                    });
                }
                cursor = close + 3;
                continue;
            }
            try {
                const parsed = JSON.parse(jsonText);
                if (pick.type === "quick") {
                    const rawActions = Array.isArray(parsed)
                        ? parsed
                        : parsed?.actions || parsed?.buttons || parsed?.choices || [];
                    const actions = [];
                    if (Array.isArray(rawActions)) {
                        rawActions.forEach((a) => {
                            if (!a)
                                return;
                            const action = {
                                id: a.id,
                                label: a.label || a.text || String(a.value || a.prompt || ""),
                                prompt: a.prompt,
                                value: a.value,
                                style: a.style,
                                behavior: a.behavior &&
                                    (a.behavior === "compose" || a.behavior === "submit")
                                    ? a.behavior
                                    : a.submit === false ||
                                        a.compose === true ||
                                        a.draft === true ||
                                        a.mode === "compose"
                                        ? "compose"
                                        : undefined,
                                placeholder: a.placeholder,
                            };
                            if (action.label)
                                actions.push(action);
                        });
                    }
                    if (actions.length > 0) {
                        segments.push({ kind: "actions", actions });
                    }
                }
                else if (pick.type === "todo") {
                    // todo_list
                    const todoItems = Array.isArray(parsed)
                        ? parsed
                        : parsed?.items || [];
                    const title = Array.isArray(parsed) ? undefined : parsed?.title;
                    const cleaned = (Array.isArray(todoItems) ? todoItems : [])
                        .map((i) => {
                        if (!i)
                            return null;
                        const text = i.text || i.label || String(i.task || i.title || "");
                        if (!text)
                            return null;
                        return {
                            id: i.id,
                            title: text,
                            status: i.status || "pending",
                            instructions: i.note || i.description,
                        };
                    })
                        .filter(Boolean);
                    if (cleaned.length > 0) {
                        segments.push({ kind: "todo", title, items: cleaned });
                    }
                }
            }
            catch {
                if (!hideIncomplete) {
                    segments.push({
                        kind: "text",
                        text: content.slice(pick.start, close + 3),
                    });
                }
            }
            cursor = close + 3;
            continue;
        }
        // Plain header without backticks
        const headerTokenLength = pick.type === "quick" ? plainQuickToken.length : plainTodoToken.length;
        const afterHeaderStart = pick.start + headerTokenLength;
        const headerRestMatch = content
            .slice(afterHeaderStart)
            .match(/^[^\n\r]*\r?\n?/);
        const headerRestLen = headerRestMatch ? headerRestMatch[0].length : 0;
        const afterHeader = afterHeaderStart + headerRestLen;
        // Find first '{' after header (could be same line or following lines)
        const braceStart = content.indexOf("{", afterHeader);
        if (braceStart === -1) {
            if (hideIncomplete) {
                break;
            }
            else {
                // Treat as plain text if no JSON object is present
                cursor = afterHeader;
                continue;
            }
        }
        const braceEnd = findMatchingBraceEnd(braceStart);
        const jsonText = (braceEnd === -1
            ? content.slice(braceStart)
            : content.slice(braceStart, braceEnd + 1)).trim();
        if (braceEnd === -1) {
            // Incomplete plain JSON block during streaming
            if (hideIncomplete && pick.type === "quick") {
                // Try to parse partial quick actions and show what we have so far
                const partialActions = extractPartialQuickActions(jsonText);
                if (partialActions.length > 0) {
                    segments.push({ kind: "actions", actions: partialActions });
                }
                break;
            }
            else if (hideIncomplete) {
                break;
            }
            else {
                // Incomplete JSON; include the rest as text
                const remaining = content.slice(pick.start);
                if (remaining)
                    segments.push({ kind: "text", text: remaining });
                break;
            }
        }
        try {
            const parsed = JSON.parse(jsonText);
            if (pick.type === "quick") {
                const rawActions = Array.isArray(parsed)
                    ? parsed
                    : parsed?.actions || parsed?.buttons || parsed?.choices || [];
                const actions = [];
                if (Array.isArray(rawActions)) {
                    rawActions.forEach((a) => {
                        if (!a)
                            return;
                        const action = {
                            id: a.id,
                            label: a.label || a.text || String(a.value || a.prompt || ""),
                            prompt: a.prompt,
                            value: a.value,
                            style: a.style,
                            behavior: a.behavior &&
                                (a.behavior === "compose" || a.behavior === "submit")
                                ? a.behavior
                                : a.submit === false ||
                                    a.compose === true ||
                                    a.draft === true ||
                                    a.mode === "compose"
                                    ? "compose"
                                    : undefined,
                            placeholder: a.placeholder,
                        };
                        if (action.label)
                            actions.push(action);
                    });
                }
                if (actions.length > 0) {
                    segments.push({ kind: "actions", actions });
                }
            }
            else {
                const todoItems = Array.isArray(parsed) ? parsed : parsed?.items || [];
                const title = Array.isArray(parsed) ? undefined : parsed?.title;
                const cleaned = (Array.isArray(todoItems) ? todoItems : [])
                    .map((i) => {
                    if (!i)
                        return null;
                    const text = i.text || i.label || String(i.task || i.title || "");
                    if (!text)
                        return null;
                    return {
                        id: i.id,
                        title: text,
                        status: i.status || "pending",
                        instructions: i.note || i.description,
                    };
                })
                    .filter(Boolean);
                if (cleaned.length > 0) {
                    segments.push({ kind: "todo", title, items: cleaned });
                }
            }
        }
        catch {
            // On parse failure, keep original as text (excluding already-pushed prefix)
            const fallbackText = content.slice(pick.start, braceEnd + 1);
            if (!hideIncomplete && fallbackText) {
                segments.push({ kind: "text", text: fallbackText });
            }
        }
        cursor = braceEnd + 1;
    }
    return segments;
}
// Helper to extract command links from markdown
function extractCommandLinks(text) {
    const links = [];
    const commandLinkPattern = /\[([^\]]+)\]\(command:([^)]+)\)/g;
    let match;
    while ((match = commandLinkPattern.exec(text)) !== null) {
        if (match[1] && match[2]) {
            links.push({
                label: match[1],
                command: match[2],
                index: match.index,
            });
        }
    }
    return { text, links };
}
// JSON Block Display Component
function JsonBlockDisplay({ data, raw, className, defaultCollapsed = false, }) {
    const [isExpanded, setIsExpanded] = useState(!defaultCollapsed);
    const [isCopied, setIsCopied] = useState(false);
    const handleCopy = async () => {
        try {
            const textToCopy = data ? JSON.stringify(data, null, 2) : raw;
            await navigator.clipboard.writeText(textToCopy);
            setIsCopied(true);
            setTimeout(() => setIsCopied(false), 2000);
        }
        catch (err) {
            console.error("Failed to copy:", err);
        }
    };
    // Try to extract a meaningful title from the JSON data
    const getTitle = () => {
        if (!data)
            return "JSON";
        if (data.__typename)
            return data.__typename;
        if (data.name)
            return data.name;
        if (data.type)
            return data.type;
        if (data.title)
            return data.title;
        if (Array.isArray(data))
            return `Array (${data.length} items)`;
        return "JSON";
    };
    // Render JSON with syntax highlighting
    const renderJsonValue = (value, indent = 0) => {
        const indentStr = "  ".repeat(indent);
        const nextIndent = indent + 1;
        if (value === null) {
            return _jsx("span", { className: "text-gray-400", children: "null" });
        }
        if (typeof value === "boolean") {
            return _jsx("span", { className: "text-purple-600", children: value.toString() });
        }
        if (typeof value === "number") {
            return _jsx("span", { className: "text-blue-600", children: value });
        }
        if (typeof value === "string") {
            // Check if it looks like a GUID
            const isGuid = /^\{?[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}\}?$/.test(value);
            return (_jsxs("span", { className: isGuid ? "text-amber-600" : "text-green-600", children: ["\"", value, "\""] }));
        }
        if (Array.isArray(value)) {
            if (value.length === 0) {
                return _jsx("span", { className: "text-gray-600", children: "[]" });
            }
            return (_jsxs(_Fragment, { children: [_jsx("span", { className: "text-gray-600", children: "[" }), value.map((item, idx) => (_jsxs("div", { className: "pl-4", children: [renderJsonValue(item, nextIndent), idx < value.length - 1 && (_jsx("span", { className: "text-gray-600", children: "," }))] }, idx))), _jsx("span", { className: "text-gray-600", children: "]" })] }));
        }
        if (typeof value === "object") {
            const entries = Object.entries(value);
            if (entries.length === 0) {
                return _jsx("span", { className: "text-gray-600", children: "{}" });
            }
            return (_jsxs(_Fragment, { children: [_jsx("span", { className: "text-gray-600", children: "{" }), entries.map(([key, val], idx) => (_jsxs("div", { className: "pl-4", children: [_jsxs("span", { className: "text-rose-600", children: ["\"", key, "\""] }), _jsx("span", { className: "text-gray-600", children: ": " }), renderJsonValue(val, nextIndent), idx < entries.length - 1 && (_jsx("span", { className: "text-gray-600", children: "," }))] }, key))), _jsx("span", { className: "text-gray-600", children: "}" })] }));
        }
        return _jsx("span", { children: String(value) });
    };
    return (_jsxs("div", { className: `my-2 overflow-hidden rounded-lg border border-gray-200 bg-gray-50 ${className || ""}`, children: [_jsxs("div", { className: "flex items-center justify-between border-b border-gray-200 bg-gray-100 px-3 py-2", children: [_jsxs("button", { onClick: () => setIsExpanded(!isExpanded), className: "flex items-center gap-2 text-xs font-medium text-gray-700 hover:text-gray-900", children: [isExpanded ? _jsx(ChevronDown, { size: 14 }) : _jsx(ChevronRight, { size: 14 }), _jsx("span", { children: getTitle() })] }), _jsx("button", { onClick: handleCopy, className: "rounded px-2 py-1 text-xs text-gray-500 transition-colors hover:bg-gray-200 hover:text-gray-700", children: isCopied ? "Copied!" : "Copy" })] }), isExpanded && (_jsx("div", { className: "overflow-x-auto p-3", children: data ? (_jsx("pre", { className: "font-mono text-[11px] leading-relaxed", children: renderJsonValue(data) })) : (_jsx("pre", { className: "font-mono text-[11px] leading-relaxed whitespace-pre-wrap text-gray-600", children: raw })) }))] }));
}
function simpleFormatToHtml(text) {
    //Inline formatting
    const format = (s) => s
        .replace(/\[([^\]]+)\]\(([^)]+)\)/g, (_, text, url) => `<a href="${url}" style="color: #3b82f6; text-decoration: underline;" target="_blank" rel="noopener noreferrer">${text.replace(/\*\*(.*?)\*\*/g, "<strong>$1</strong>")}</a>`)
        .replace(/^######\s+(.+)$/, '<h6 style="font-size: 0.75rem; font-weight: 500; margin: 0.75rem 0 0.25rem 0; color: #6b7280; letter-spacing: 0.01em; line-height: 1.3;">$1</h6>')
        .replace(/^#####\s+(.+)$/, '<h5 style="font-size: 0.875rem; font-weight: 500; margin: 0.875rem 0 0.375rem 0; color: #4b5563; letter-spacing: 0.01em; line-height: 1.35;">$1</h5>')
        .replace(/^####\s+(.+)$/, '<h4 style="font-size: 1rem; font-weight: 600; margin: 1rem 0 0.5rem 0; color: #374151; letter-spacing: -0.01em; line-height: 1.4;">$1</h4>')
        .replace(/^###\s+(.+)$/, '<h3 style="font-size: 1.125rem; font-weight: 600; margin: 1.125rem 0 0.5rem 0; color: #1f2937; letter-spacing: -0.015em; line-height: 1.4;">$1</h3>')
        .replace(/^##\s+(.+)$/, '<h2 style="font-size: 1.375rem; font-weight: 600; margin: 1.25rem 0 0.625rem 0; color: #111827; letter-spacing: -0.02em; line-height: 1.3;">$1</h2>')
        .replace(/^#\s+(.+)$/, '<h1 style="font-size: 1.75rem; font-weight: 700; margin: 1.5rem 0 0.75rem 0; color: #0f172a; letter-spacing: -0.025em; line-height: 1.2;">$1</h1>')
        .replace(/\*\*(.*?)\*\*/g, "<strong>$1</strong>");
    const lines = text.split(/\r?\n/);
    const blocks = [];
    let i = 0;
    while (i < lines.length) {
        const line = lines[i];
        if (!line) {
            i++;
            continue;
        }
        const t = line.trim();
        // Sepperator Lines
        if (/^[\-\*\_]{3,}$/.test(t)) {
            blocks.push('<hr style="border: none; border-top: 1px solid #e5e7eb; margin: 0.75rem 0;" />');
            i++;
            continue;
        }
        // Table
        if (t.startsWith("|") && t.endsWith("|") && t.split("|").length >= 3) {
            const rows = [];
            let j = i;
            while (j < lines.length) {
                const l = lines[j];
                if (!l)
                    break;
                const lt = l.trim();
                if (lt.startsWith("|") && lt.endsWith("|")) {
                    if (/^[\|\s:\-]+$/.test(lt)) {
                        j++; // Skip separator
                        continue;
                    }
                    rows.push(lt
                        .split("|")
                        .slice(1, -1)
                        .map((c) => c.trim()));
                    j++;
                }
                else
                    break;
            }
            if (rows.length > 0 && rows[0]) {
                let html = '<table style="border-collapse: collapse; width: 100%; margin: 0.5rem 0; font-size: 0.75rem;"><thead><tr style="border-bottom: 2px solid #e5e7eb;">';
                rows[0].forEach((c) => (html += `<th style="padding: 0.375rem 0.5rem; text-align: left; font-weight: 600; color: #374151;">${format(c)}</th>`));
                html += "</tr></thead>";
                if (rows.length > 1) {
                    html += "<tbody>";
                    for (let k = 1; k < rows.length; k++) {
                        html += '<tr style="border-bottom: 1px solid #f3f4f6;">';
                        rows[k]?.forEach((c) => (html += `<td style="padding: 0.375rem 0.5rem; color: #6b7280;">${format(c)}</td>`));
                        html += "</tr>";
                    }
                    html += "</tbody>";
                }
                blocks.push(html + "</table>");
                i = j;
                continue;
            }
        }
        // List (supports nested mixed ul/ol without recursion)
        const listLineMatch = line.match(/^(\s*)([\-\*]|\d+\.)\s+(.+)$/);
        if (listLineMatch && listLineMatch[2] && listLineMatch[3]) {
            const listLines = [];
            let j = i;
            while (j < lines.length) {
                const currentLine = lines[j];
                if (!currentLine)
                    break;
                const m = currentLine.match(/^(\s*)([\-\*]|\d+\.)\s+(.+)$/);
                if (!m || !m[2] || !m[3])
                    break;
                listLines.push({
                    indent: m[1]?.length || 0,
                    marker: m[2],
                    content: m[3],
                });
                j++;
            }
            if (listLines.length > 0) {
                const listStyleByTag = {
                    ul: "list-style: disc;",
                    ol: "list-style: decimal;",
                };
                const indentStack = [];
                const tagStack = [];
                let html = "";
                let itemOpen = false;
                const openList = (tag, indent) => {
                    html += `<${tag} style="${listStyleByTag[tag]} padding-left: 1.5rem; margin: 0.25rem 0;">`;
                    tagStack.push(tag);
                    indentStack.push(indent);
                };
                const closeItem = () => {
                    if (!itemOpen)
                        return;
                    html += "</li>";
                    itemOpen = false;
                };
                const closeList = () => {
                    closeItem();
                    const tag = tagStack.pop();
                    indentStack.pop();
                    if (tag)
                        html += `</${tag}>`;
                };
                for (const entry of listLines) {
                    const tag = /\d/.test(entry.marker) ? "ol" : "ul";
                    if (tagStack.length === 0) {
                        openList(tag, entry.indent);
                    }
                    else {
                        let currentIndent = indentStack[indentStack.length - 1];
                        while (tagStack.length > 0 &&
                            currentIndent !== undefined &&
                            entry.indent < currentIndent) {
                            closeList();
                            currentIndent = indentStack[indentStack.length - 1];
                        }
                        if (currentIndent === undefined ||
                            (entry.indent !== currentIndent && entry.indent > currentIndent)) {
                            if (!itemOpen) {
                                html += '<li style="margin: 0.25rem 0; color: #6b7280;">';
                                itemOpen = true;
                            }
                            openList(tag, entry.indent);
                        }
                        else if (entry.indent === currentIndent) {
                            const currentTag = tagStack[tagStack.length - 1];
                            if (currentTag && currentTag !== tag) {
                                closeList();
                                openList(tag, entry.indent);
                            }
                        }
                        else if (currentIndent === undefined) {
                            openList(tag, entry.indent);
                        }
                    }
                    closeItem();
                    html += `<li style="margin: 0.25rem 0; color: #6b7280;">${format(entry.content)}`;
                    itemOpen = true;
                }
                while (tagStack.length > 0)
                    closeList();
                if (html) {
                    blocks.push(html);
                    i = j;
                    continue;
                }
            }
        }
        // Regular text
        blocks.push(format(line));
        i++;
    }
    // Join blocks with <br/> between text, but not between block elements
    let result = "";
    for (let k = 0; k < blocks.length; k++) {
        const block = blocks[k];
        if (!block)
            continue;
        result += block;
        if (k < blocks.length - 1) {
            const next = blocks[k + 1];
            if (!next)
                continue;
            const isBlock = /^<(table|ul|ol|hr|h[1-6])/i.test(block);
            const nextIsBlock = /^<(table|ul|ol|hr|h[1-6])/i.test(next);
            if (!isBlock && !nextIsBlock)
                result += "<br/>";
        }
    }
    return sanitizeHtml(result.replace(/<\/(h[1-6])><br\/>/g, "</$1>"));
}
// Thinking block component with auto-scroll
function ThinkingBlock({ text, isStreaming, isCollapsed, thinkingKey, onToggleCollapse, }) {
    const contentRef = useRef(null);
    // Auto-scroll to bottom when content changes during streaming
    useLayoutEffect(() => {
        if (isStreaming && !isCollapsed && contentRef.current) {
            contentRef.current.scrollTop = contentRef.current.scrollHeight;
        }
    }, [text, isStreaming, isCollapsed]);
    return (_jsxs("div", { className: `my-2 flex flex-col gap-1 rounded-lg border text-[11px] transition-colors duration-200 ${isStreaming
            ? "border-gray-200 bg-gray-50/50 text-gray-700"
            : "border-gray-100 bg-gray-50/50 text-gray-500"}`, children: [_jsxs("div", { className: `flex cursor-pointer items-center gap-1.5 p-2 text-[10px] font-medium tracking-wider uppercase transition-colors ${isStreaming
                    ? "text-gray-500 hover:bg-gray-100/50"
                    : "text-gray-400 hover:bg-gray-100/50"}`, onClick: onToggleCollapse, children: [isCollapsed ? _jsx(ChevronRight, { size: 12 }) : _jsx(ChevronDown, { size: 12 }), _jsx(Brain, { size: 12, className: isStreaming ? "animate-pulse" : "" }), _jsx("span", { children: "Thinking" }), isStreaming && (_jsx(Loader2, { className: "ml-1 h-3 w-3 animate-spin text-gray-400", strokeWidth: 1.5 }))] }), !isCollapsed && (_jsxs("div", { ref: contentRef, className: `prose-sm max-h-[6rem] overflow-y-auto px-2 pb-2 leading-relaxed whitespace-pre-wrap italic ${isStreaming ? "text-gray-600" : ""}`, children: [text, isStreaming && (_jsx("span", { className: "ml-0.5 inline-block h-3 w-0.5 animate-pulse bg-gray-400" }))] }))] }));
}
export function AiResponseMessage({ messages, finished, editOperations, error, onQuickAction, defaultCollapseJson = false, profileSvgIcon, agentId, agentName, allPendingApprovals, onSwitchToAutonomous, browserCaptureInlinePrompt, }) {
    const editContext = useEditContext();
    // const [showFunctions, setShowFunctions] = useState(false);
    const [changesRejected, setChangesRejected] = useState(undefined);
    const [confirmingUndo, setConfirmingUndo] = useState(false);
    // Store tool calls to preserve them during streaming
    const [preservedToolCalls, setPreservedToolCalls] = useState({});
    // Track popover open state for each tool call
    const [openPopovers, setOpenPopovers] = useState({});
    // Track collapsed state for thinking sections (default to collapsed)
    const [collapsedThinking, setCollapsedThinking] = useState({});
    // Track which tool call approval dialogs have been shown (for deduplication)
    const [seenApprovalDialogs, setSeenApprovalDialogs] = useState(() => new Set());
    const normalizeToolArguments = useCallback((value) => {
        if (value === undefined || value === null)
            return "";
        if (typeof value === "string")
            return value;
        try {
            return JSON.stringify(value);
        }
        catch {
            return String(value);
        }
    }, []);
    const getToolArgumentsScore = useCallback((value) => {
        const normalized = normalizeToolArguments(value).trim();
        if (!normalized)
            return 0;
        // Treat placeholders as low-value argument payloads.
        if (normalized === "{}" || normalized === "[]" || normalized === "null") {
            return 1;
        }
        // Prefer richer JSON payloads over placeholders.
        try {
            const parsed = JSON.parse(normalized);
            if (Array.isArray(parsed)) {
                return parsed.length > 0 ? 1000 + normalized.length : 1;
            }
            if (parsed && typeof parsed === "object") {
                return Object.keys(parsed).length > 0 ? 1000 + normalized.length : 1;
            }
        }
        catch {
            // Non-JSON string payload; compare by length.
        }
        return normalized.length;
    }, [normalizeToolArguments]);
    // Callback to mark a tool call as having shown its approval dialog
    const handleApprovalDialogShown = useCallback((toolCallId) => {
        setSeenApprovalDialogs((prev) => {
            if (prev.has(toolCallId))
                return prev;
            const next = new Set(prev);
            next.add(toolCallId);
            return next;
        });
    }, []);
    // Helper to avoid unnecessary updates when tool calls are unchanged
    const areToolCallsEqual = (a, b) => {
        if (a === b)
            return true;
        if (!a || !b)
            return false;
        if (a.length !== b.length)
            return false;
        for (let i = 0; i < a.length; i++) {
            const ai = a[i];
            const bi = b[i];
            if (ai?.id !== bi?.id ||
                ai?.displayName !== bi?.displayName ||
                ai?.function?.name !== bi?.function?.name ||
                ai?.function?.result !== bi?.function?.result ||
                ai?.function?.error !== bi?.function?.error ||
                ai?.isCompleted !== bi?.isCompleted ||
                ai?.responseTimeMs !== bi?.responseTimeMs ||
                ai?.createdDate !== bi?.createdDate ||
                normalizeToolArguments(ai?.function?.arguments) !==
                    normalizeToolArguments(bi?.function?.arguments)) {
                return false;
            }
        }
        return true;
    };
    // Update preserved tool calls when messages change, but only if values actually change
    useEffect(() => {
        setPreservedToolCalls((prev) => {
            let changed = false;
            const next = { ...prev };
            for (const message of messages) {
                const hasToolCalls = !!(message.tool_calls && message.tool_calls.length > 0);
                if (!hasToolCalls)
                    continue;
                if (!areToolCallsEqual(next[message.id], message.tool_calls)) {
                    next[message.id] = message.tool_calls;
                    changed = true;
                }
            }
            return changed ? next : prev;
        });
    }, [messages]);
    // Filter out operations that are already undone
    const undoableOperations = editOperations.filter((op) => !op.undone);
    // Check if all operations have been undone (for persistent "undone" state after reload)
    const allOperationsUndone = editOperations.length > 0 && undoableOperations.length === 0;
    // Show undo button if there are any operations that aren't undone
    const canUndo = undoableOperations.length > 0;
    // Calculate if we're currently streaming (for loading indicator)
    const isStreaming = !finished && messages.length > 0;
    // Get the last message for timestamp
    const lastMessage = messages[messages.length - 1];
    // Memoize filtered messages and their parsed content segments to avoid hooks inside loops
    const nonToolAssistantMessages = useMemo(() => messages.filter((x) => x.role !== "tool" && x.role !== "user"), [messages]);
    const flatItems = useMemo(() => {
        const items = [];
        // Collect all unique tool call IDs and their latest versions across all messages in this group
        const latestToolCalls = new Map();
        nonToolAssistantMessages.forEach((message) => {
            const tcs = message.tool_calls && message.tool_calls.length > 0
                ? message.tool_calls
                : preservedToolCalls[message.id] || [];
            tcs.forEach((tc) => {
                if (tc.id) {
                    // If we already have this tool call, only update if the new one is more "complete"
                    const existing = latestToolCalls.get(tc.id);
                    const newArgScore = getToolArgumentsScore(tc.function?.arguments);
                    const existingArgScore = getToolArgumentsScore(existing?.function?.arguments);
                    const isNewer = !existing ||
                        (!existing.function?.result && tc.function?.result) ||
                        (!existing.function?.error && tc.function?.error) ||
                        (!existing.requiresApproval && tc.requiresApproval) ||
                        newArgScore > existingArgScore;
                    if (isNewer) {
                        latestToolCalls.set(tc.id, tc);
                    }
                }
            });
        });
        const emittedToolCallIds = new Set();
        nonToolAssistantMessages.forEach((message, msgIndex) => {
            const isLastMessage = msgIndex === nonToolAssistantMessages.length - 1;
            // Add reasoning segment if present
            if (message.reasoning) {
                items.push({
                    type: "segment",
                    segment: { kind: "reasoning", text: message.reasoning },
                    messageId: message.id,
                    message,
                    isLastMessage,
                });
            }
            const contentString = (message.content ||
                message.formattedContent ||
                "");
            const segments = parseContentSegments(contentString, isStreaming);
            // Add content segments
            segments.forEach((segment) => {
                items.push({
                    type: "segment",
                    segment,
                    messageId: message.id,
                    message,
                    isLastMessage,
                });
            });
            // Add tool calls if present, but only if they haven't been emitted yet
            const tcs = message.tool_calls && message.tool_calls.length > 0
                ? message.tool_calls
                : preservedToolCalls[message.id] || [];
            if (tcs.length > 0) {
                const uniqueToolCallsInThisMessage = [];
                tcs.forEach((tc) => {
                    if (!tc.id || !emittedToolCallIds.has(tc.id)) {
                        if (tc.id) {
                            emittedToolCallIds.add(tc.id);
                            // Use the latest version we found earlier
                            const latestToolCall = latestToolCalls.get(tc.id) || tc;
                            uniqueToolCallsInThisMessage.push(latestToolCall.messageId
                                ? latestToolCall
                                : {
                                    ...latestToolCall,
                                    messageId: message.id,
                                });
                        }
                        else {
                            uniqueToolCallsInThisMessage.push(tc.messageId
                                ? tc
                                : {
                                    ...tc,
                                    messageId: message.id,
                                });
                        }
                    }
                });
                if (uniqueToolCallsInThisMessage.length > 0) {
                    items.push({
                        type: "toolcalls",
                        toolCalls: uniqueToolCallsInThisMessage,
                        messageId: message.id,
                        message,
                        isLastMessage,
                    });
                }
            }
        });
        const mergedItems = [];
        items.forEach((item) => {
            const previousItem = mergedItems[mergedItems.length - 1];
            if (item.type === "toolcalls" && previousItem?.type === "toolcalls") {
                mergedItems[mergedItems.length - 1] = {
                    ...previousItem,
                    toolCalls: [...previousItem.toolCalls, ...item.toolCalls],
                    messageId: `${previousItem.messageId}__${item.messageId}`,
                    message: item.message,
                    isLastMessage: item.isLastMessage,
                };
                return;
            }
            mergedItems.push(item);
        });
        return mergedItems;
    }, [
        nonToolAssistantMessages,
        isStreaming,
        preservedToolCalls,
        getToolArgumentsScore,
    ]);
    // Check if any reasoning block is currently showing a spinner
    const isAnyReasoningStreaming = useMemo(() => {
        if (!isStreaming || allPendingApprovals?.length)
            return false;
        // Check if the last item is a reasoning segment that hasn't started output yet
        const lastItem = flatItems[flatItems.length - 1];
        if (lastItem?.type === "segment" &&
            lastItem.segment.kind === "reasoning" &&
            lastItem.isLastMessage) {
            const message = lastItem.message;
            const contentString = (message.content ||
                message.formattedContent ||
                "");
            const hasToolCalls = (message.tool_calls && message.tool_calls.length > 0) ||
                (preservedToolCalls[message.id] &&
                    preservedToolCalls[message.id].length > 0);
            const hasStartedOutput = contentString.trim().length > 0 || hasToolCalls;
            return !hasStartedOutput;
        }
        return false;
    }, [
        isStreaming,
        flatItems,
        allPendingApprovals?.length,
        preservedToolCalls,
    ]);
    // Extract copyable text content from all text and reasoning segments
    const copyableText = useMemo(() => {
        const textParts = [];
        flatItems.forEach((item) => {
            if (item.type === "segment") {
                const segment = item.segment;
                if (segment.kind === "text") {
                    // Extract plain text from HTML if needed, or use raw text
                    const text = segment.text.trim();
                    if (text) {
                        textParts.push(text);
                    }
                }
                else if (segment.kind === "reasoning") {
                    const text = segment.text.trim();
                    if (text) {
                        textParts.push(text);
                    }
                }
            }
        });
        return textParts.join("\n\n");
    }, [flatItems]);
    return (_jsxs("div", { className: "flex gap-3 px-4 py-3", "data-testid": "agent-message", children: [_jsx("div", { className: "flex-shrink-0", children: profileSvgIcon ? (_jsx("div", { className: "text-gray-2 flex h-6 w-6 items-center justify-center [&>svg]:h-full [&>svg]:w-full", dangerouslySetInnerHTML: {
                        __html: sanitizeSvg(profileSvgIcon),
                    } })) : (_jsx(SecretAgentIcon, { size: 20, strokeWidth: 1, className: "text-gray-2" })) }), _jsxs("div", { className: "min-w-0 flex-1 select-text", children: [_jsxs("div", { className: "mb-1 flex items-center gap-2", children: [_jsx("span", { className: "text-dark text-xs font-medium", children: agentName || "Agent" }), lastMessage && lastMessage.createdDate && (_jsx("span", { className: "text-xs text-gray-400", "data-testid": "agent-message-timestamp", "data-timestamp": lastMessage.createdDate, children: formatTime(new Date(lastMessage.createdDate)) }))] }), error && (_jsx("div", { className: "mb-2 rounded-lg border-l-4 border-red-500 bg-red-50 p-2.5", "data-testid": "agent-error", children: _jsxs("div", { className: "flex items-start", children: [_jsx("div", { className: "flex-shrink-0", children: _jsx(X, { className: "h-5 w-5 text-red-400", strokeWidth: 1 }) }), _jsxs("div", { className: "ml-3", children: [_jsx("p", { className: "text-sm font-medium text-red-800", children: "Agent Error" }), _jsx("p", { className: "mt-1 text-sm text-red-700", children: error })] })] }) })), flatItems.map((item, itemIndex) => {
                        const prevItem = itemIndex > 0 ? flatItems[itemIndex - 1] : null;
                        const isLastItem = itemIndex === flatItems.length - 1;
                        const shouldAddSpacing = prevItem?.type === "toolcalls" && item.type === "segment";
                        if (item.type === "segment") {
                            const segment = item.segment;
                            const message = item.message;
                            if (segment.kind === "reasoning") {
                                const thinkingKey = `thinking-${message.id}-${itemIndex}`;
                                // Only show the "Thinking" spinner while we're still in the pre-output phase.
                                // Once any actual response content starts appearing, thinking has effectively finished,
                                // even if the overall response is still streaming.
                                const contentString = (message.content ||
                                    message.formattedContent ||
                                    "");
                                const hasToolCalls = (message.tool_calls && message.tool_calls.length > 0) || (preservedToolCalls[message.id] && preservedToolCalls[message.id].length > 0);
                                const hasStartedOutput = contentString.trim().length > 0 || hasToolCalls;
                                // Check if this reasoning block is still actively streaming
                                const isReasoningStreaming = !!(isStreaming &&
                                    item.isLastMessage &&
                                    !hasStartedOutput &&
                                    !allPendingApprovals?.length);
                                // During streaming, default to expanded; after streaming, default to collapsed
                                const isCollapsed = collapsedThinking[thinkingKey] !== undefined
                                    ? collapsedThinking[thinkingKey]
                                    : !isReasoningStreaming; // Expanded during streaming, collapsed after
                                return (_jsx(ThinkingBlock, { text: segment.text, isStreaming: isReasoningStreaming, isCollapsed: isCollapsed, thinkingKey: thinkingKey, onToggleCollapse: () => {
                                        setCollapsedThinking((prev) => ({
                                            ...prev,
                                            [thinkingKey]: !isCollapsed,
                                        }));
                                    } }, `item-${itemIndex}`));
                            }
                            if (segment.kind === "text") {
                                const trimmedText = segment.text.trim();
                                if (!trimmedText)
                                    return null;
                                // Check for command links in the text
                                const { text, links } = extractCommandLinks(trimmedText);
                                if (links.length > 0) {
                                    // Split text around command links and render buttons
                                    const parts = [];
                                    let lastIndex = 0;
                                    links.forEach((link, linkIdx) => {
                                        // Add text before the link
                                        if (link.index > lastIndex) {
                                            const textBefore = text.substring(lastIndex, link.index);
                                            const html = simpleFormatToHtml(textBefore);
                                            if (html) {
                                                parts.push(_jsx("span", { dangerouslySetInnerHTML: { __html: html } }, `text-${itemIndex}-${linkIdx}`));
                                            }
                                        }
                                        // Add the button
                                        // Calculate the actual text that will be submitted (same logic as in AgentTerminal.tsx)
                                        // For command links: prompt=command, value=command, so submitted text is link.command
                                        const submittedText = (link.command ||
                                            link.label ||
                                            "").trim();
                                        parts.push(_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx(Button, { size: "sm", variant: "outline", className: "mx-1 inline-flex", onClick: () => onQuickAction?.({
                                                            label: link.label,
                                                            value: link.command,
                                                            prompt: link.command,
                                                        }, message), children: link.label }) }), submittedText && (_jsx(TooltipContent, { children: _jsx("p", { className: "max-w-xs break-words", children: submittedText }) }))] }, `btn-${itemIndex}-${linkIdx}`));
                                        // Find the end of this match in the original text
                                        const matchEnd = link.index +
                                            `[${link.label}](command:${link.command})`.length;
                                        lastIndex = matchEnd;
                                    });
                                    // Add any remaining text after the last link
                                    if (lastIndex < text.length) {
                                        const textAfter = text.substring(lastIndex);
                                        const html = simpleFormatToHtml(textAfter);
                                        if (html) {
                                            parts.push(_jsx("span", { dangerouslySetInnerHTML: { __html: html } }, `text-${itemIndex}-end`));
                                        }
                                    }
                                    return (_jsxs("div", { className: `prose prose-sm max-w-none text-xs text-gray-700 select-text ${shouldAddSpacing ? "mt-2" : ""}`, children: [parts, isStreaming && isLastItem && (_jsx("span", { className: "ml-0.5 inline-block h-3 w-0.5 animate-pulse bg-gray-400" }))] }, `item-${itemIndex}`));
                                }
                                const html = simpleFormatToHtml(trimmedText);
                                if (!html)
                                    return null;
                                return (_jsxs("div", { className: `prose prose-sm max-w-none text-xs text-gray-700 select-text ${shouldAddSpacing ? "mt-2" : ""}`, children: [_jsx("span", { dangerouslySetInnerHTML: { __html: html } }), isStreaming && isLastItem && (_jsx("span", { className: "ml-0.5 inline-block h-3 w-0.5 animate-pulse bg-gray-400" }))] }, `item-${itemIndex}`));
                            }
                            if (segment.kind === "todo") {
                                const todo = segment;
                                return (_jsxs("div", { className: `my-1 ${shouldAddSpacing ? "mt-2" : ""}`, children: [todo.title && (_jsx("div", { className: "mb-1 text-xs font-medium text-gray-800", children: todo.title })), _jsx("div", { className: "flex flex-col gap-1", children: todo.items.map((todoItem, iIdx) => (_jsxs("label", { className: "flex items-start gap-2 text-xs text-gray-700", children: [_jsx(Checkbox, { checked: todoItem.status === "completed", onCheckedChange: () => { }, "aria-readonly": true, className: "mt-0.5" }), _jsxs("div", { children: [_jsx("div", { className: todoItem.status === "completed" || todoItem.status === "cancelled"
                                                                    ? "line-through opacity-70"
                                                                    : todoItem.status === "in_progress"
                                                                        ? "text-blue-700 font-medium"
                                                                        : "", children: todoItem.title }), todoItem.instructions && (_jsx("div", { className: "text-gray-1 text-xs", children: todoItem.instructions }))] })] }, (todoItem.id || todoItem.title || "todo") + "-" + iIdx))) })] }, `item-${itemIndex}`));
                            }
                            if (segment.kind === "media") {
                                const media = segment;
                                return (_jsx("div", { className: `my-2 flex flex-col gap-3 ${shouldAddSpacing ? "mt-2" : ""}`, children: media.items.map((mediaItem, mIdx) => (_jsx(MediaImage, { itemId: mediaItem.itemId, label: mediaItem.label }, mediaItem.itemId || `media-${itemIndex}-${mIdx}`))) }, `item-${itemIndex}`));
                            }
                            if (segment.kind === "json") {
                                return (_jsx(JsonBlockDisplay, { data: segment.data, raw: segment.raw, defaultCollapsed: defaultCollapseJson, className: shouldAddSpacing ? "mt-2" : "" }, `item-${itemIndex}`));
                            }
                            // segment.kind === "actions"
                            const actions = segment.actions;
                            return (_jsx("div", { className: `my-3 flex flex-wrap gap-2 ${shouldAddSpacing ? "mt-2" : ""}`, children: actions.map((a, aIdx) => {
                                    const variant = a.style === "destructive"
                                        ? "destructive"
                                        : a.style === "outline"
                                            ? "outline"
                                            : a.style === "secondary"
                                                ? "secondary"
                                                : "default"; // primary
                                    // Calculate the actual text that will be submitted (same logic as in AgentTerminal.tsx)
                                    const submittedText = (a.prompt ||
                                        a.value ||
                                        a.label ||
                                        "").trim();
                                    return (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx(Button, { size: "xs", variant: variant, onClick: () => onQuickAction?.({
                                                        label: a.label,
                                                        prompt: a.prompt,
                                                        value: a.value,
                                                        behavior: a.behavior,
                                                        placeholder: a.placeholder,
                                                    }, message), children: a.label }) }), submittedText && (_jsx(TooltipContent, { children: _jsx("p", { className: "max-w-xs break-words", children: submittedText }) }))] }, (a.id || a.label || "btn") + "-" + aIdx));
                                }) }, `item-${itemIndex}`));
                        }
                        // item.type === "toolcalls"
                        return (_jsx("div", { className: shouldAddSpacing ? "mt-2" : "", children: _jsx(ToolCallDisplay, { toolCalls: item.toolCalls, finished: finished, openPopovers: openPopovers, setOpenPopovers: setOpenPopovers, messageId: item.messageId, agentId: agentId, allPendingApprovals: allPendingApprovals, onSwitchToAutonomous: onSwitchToAutonomous, seenApprovalDialogs: seenApprovalDialogs, onApprovalDialogShown: handleApprovalDialogShown, browserCaptureInlinePrompt: browserCaptureInlinePrompt }) }, `item-${itemIndex}`));
                    }), isStreaming &&
                        !error &&
                        !allPendingApprovals?.length &&
                        !isAnyReasoningStreaming && (_jsxs("div", { className: "flex items-center gap-1 pt-2", "data-testid": "agent-streaming-dots", children: [_jsx("div", { className: "h-1 w-1 animate-bounce rounded-full bg-gray-400 [animation-delay:-0.3s]" }), _jsx("div", { className: "h-1 w-1 animate-bounce rounded-full bg-gray-400 [animation-delay:-0.15s]" }), _jsx("div", { className: "h-1 w-1 animate-bounce rounded-full bg-gray-400" })] })), (copyableText || (finished && editOperations.length > 0)) && (_jsxs("div", { className: "mt-3 flex items-center justify-end gap-2", children: [copyableText && (_jsx(CopyButton, { textToCopy: copyableText, iconOnly: false })), finished && editOperations.length > 0 && (_jsxs(_Fragment, { children: [canUndo && !changesRejected && !confirmingUndo && (_jsxs("button", { type: "button", title: `Undo ${editOperations.length} change${editOperations.length !== 1 ? "s" : ""}`, className: "tour-ai-response-message-changes flex cursor-pointer items-center gap-1 text-xs text-gray-400 hover:text-gray-600", onClick: (e) => {
                                            e.stopPropagation();
                                            setConfirmingUndo(true);
                                        }, children: [_jsx(Undo2, { strokeWidth: 1.5, size: 12 }), " Undo"] })), canUndo && !changesRejected && confirmingUndo && (_jsxs("div", { className: "flex items-center gap-2 text-xs", children: [_jsxs("span", { className: "text-gray-500", children: ["Undo ", editOperations.length, " change", editOperations.length !== 1 ? "s" : "", "?"] }), _jsx("button", { type: "button", className: "cursor-pointer text-red-500 hover:text-red-600", onClick: async (e) => {
                                                    e.stopPropagation();
                                                    const operationIds = undoableOperations.map((op) => op.id);
                                                    if (!editContext?.operations?.undoOperations) {
                                                        setConfirmingUndo(false);
                                                        return;
                                                    }
                                                    if (operationIds.length === 0) {
                                                        setConfirmingUndo(false);
                                                        return;
                                                    }
                                                    try {
                                                        const success = await editContext.operations.undoOperations(operationIds);
                                                        if (success) {
                                                            setChangesRejected(true);
                                                        }
                                                    }
                                                    catch (error) {
                                                        // Undo operation failed
                                                    }
                                                    setConfirmingUndo(false);
                                                }, children: "Yes" }), _jsx("button", { type: "button", className: "cursor-pointer text-gray-400 hover:text-gray-600", onClick: (e) => {
                                                    e.stopPropagation();
                                                    setConfirmingUndo(false);
                                                }, children: "No" })] })), (changesRejected || allOperationsUndone) && (_jsxs("span", { className: "inline-flex items-center gap-1 text-xs text-gray-400", children: [_jsx(Check, { strokeWidth: 2, size: 12 }), " Undone"] }))] }))] }))] })] }));
}
//# sourceMappingURL=AiResponseMessage.js.map