"use client";
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
import * as React from "react";
import {
  Activity,
  AlertTriangle,
  BadgeQuestionMark,
  Bot,
  ChartNoAxesCombined,
  Check,
  ChevronDown,
  ChevronRight,
  Circle,
  CircleAlert,
  CircleCheck,
  CircleDashed,
  Copy,
  Database,
  Download,
  FileQuestion,
  GitBranch,
  Handshake,
  Lightbulb,
  ListChecks,
  Loader2,
  Maximize2,
  Paperclip,
  Plus,
  Search,
  Send,
  Square,
  TrendingDown,
  User,
  Wrench,
  X
} from "lucide-react";
import ReactMarkdown from "react-markdown";
import remarkGfm from "remark-gfm";
import { useT } from "@open-mercato/shared/lib/i18n/context";
import { cn } from "@open-mercato/shared/lib/utils";
import { Alert, AlertDescription, AlertTitle } from "../primitives/alert.js";
import { Button } from "../primitives/button.js";
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogHeader,
  DialogTitle
} from "../primitives/dialog.js";
import { IconButton } from "../primitives/icon-button.js";
import { Label } from "../primitives/label.js";
import { Textarea } from "../primitives/textarea.js";
import { apiCall } from "../backend/utils/apiCall.js";
import { parseAiContentSegments } from "./AiMessageContent.js";
import {
  ModelPicker
} from "./ModelPicker.js";
import { RecordCard } from "./records/RecordCard.js";
import {
  defaultAiUiPartRegistry,
  isReservedAiUiPartId
} from "./ui-part-registry.js";
import {
  useAiChat
} from "./useAiChat.js";
import { useAiChatUpload } from "./useAiChatUpload.js";
import { useAiShortcuts } from "./useAiShortcuts.js";
import { LoopTracePanel } from "./LoopTracePanel.js";
import { AiIcon } from "./AiIcon.js";
const PREVIEW_DATA_URL_MAX_BYTES = 2 * 1024 * 1024;
const COMPACT_FOOTER_MAX_WIDTH = 640;
const MODEL_PICKER_STORAGE_PREFIX = "om-ai-model-picker:";
function readModelPickerValue(agentId) {
  if (typeof window === "undefined") return null;
  try {
    const raw = window.localStorage.getItem(`${MODEL_PICKER_STORAGE_PREFIX}${agentId}`);
    if (!raw) return null;
    const parsed = JSON.parse(raw);
    if (parsed && typeof parsed === "object" && typeof parsed.providerId === "string" && typeof parsed.modelId === "string") {
      const value = parsed;
      return { providerId: value.providerId, modelId: value.modelId };
    }
    return null;
  } catch {
    return null;
  }
}
function writeModelPickerValue(agentId, value) {
  if (typeof window === "undefined") return;
  try {
    const key = `${MODEL_PICKER_STORAGE_PREFIX}${agentId}`;
    if (value === null) {
      window.localStorage.removeItem(key);
    } else {
      window.localStorage.setItem(key, JSON.stringify({ providerId: value.providerId, modelId: value.modelId }));
    }
  } catch {
  }
}
function useAgentModels(agent) {
  const [providers, setProviders] = React.useState([]);
  const [allowRuntimeOverride, setAllowRuntimeOverride] = React.useState(false);
  const [defaultLabel, setDefaultLabel] = React.useState(null);
  const [loaded, setLoaded] = React.useState(false);
  React.useEffect(() => {
    const modelsUrl = `/api/ai_assistant/ai/agents/${encodeURIComponent(agent)}/models`;
    setLoaded(false);
    setDefaultLabel(null);
    void apiCall(modelsUrl).then((result) => {
      if (!result.ok || !result.result) {
        setLoaded(true);
        return;
      }
      const effectiveAllowRuntimeOverride = result.result.allowRuntimeOverride ?? result.result.allowRuntimeModelOverride ?? false;
      setAllowRuntimeOverride(effectiveAllowRuntimeOverride);
      setProviders(result.result.providers);
      setDefaultLabel(
        result.result.defaultProviderName && result.result.defaultModelName ? `${result.result.defaultProviderName} / ${result.result.defaultModelName}` : result.result.defaultProviderId && result.result.defaultModelId ? `${result.result.defaultProviderId} / ${result.result.defaultModelId}` : null
      );
      setLoaded(true);
    });
  }, [agent]);
  return {
    providers,
    allowRuntimeOverride,
    allowRuntimeModelOverride: allowRuntimeOverride,
    defaultLabel,
    loaded
  };
}
function isModelPickerValueAvailable(value, providers) {
  return providers.some(
    (provider) => provider.id === value.providerId && provider.models.some((model) => model.id === value.modelId)
  );
}
async function readFileAsDataUrl(file) {
  if (!file.type.startsWith("image/")) return void 0;
  if (file.size > PREVIEW_DATA_URL_MAX_BYTES) return void 0;
  return new Promise((resolve) => {
    const reader = new FileReader();
    reader.onload = () => resolve(typeof reader.result === "string" ? reader.result : void 0);
    reader.onerror = () => resolve(void 0);
    try {
      reader.readAsDataURL(file);
    } catch {
      resolve(void 0);
    }
  });
}
function mapErrorCodeToVariant(code) {
  if (!code) return "destructive";
  const warningCodes = /* @__PURE__ */ new Set([
    "tool_not_whitelisted",
    "tool_features_denied",
    "attachment_type_not_accepted"
  ]);
  return warningCodes.has(code) ? "warning" : "destructive";
}
const MARKDOWN_TYPOGRAPHY_CLASS = cn(
  "[&_p]:my-1 [&_p:first-child]:mt-0 [&_p:last-child]:mb-0",
  "[&_ul]:my-2 [&_ol]:my-2 [&_ul]:ml-4 [&_ol]:ml-4 [&_ul]:list-disc [&_ol]:list-decimal",
  "[&_li]:my-0.5",
  "[&_h1]:mt-3 [&_h1]:mb-2 [&_h1]:text-base [&_h1]:font-semibold",
  "[&_h2]:mt-3 [&_h2]:mb-2 [&_h2]:text-sm [&_h2]:font-semibold",
  "[&_h3]:mt-2 [&_h3]:mb-1 [&_h3]:text-sm [&_h3]:font-semibold",
  "[&_a]:text-primary [&_a]:underline [&_a]:underline-offset-2",
  "[&_code]:rounded [&_code]:bg-muted [&_code]:px-1 [&_code]:py-0.5 [&_code]:font-mono [&_code]:text-xs",
  "[&_pre]:my-2 [&_pre]:overflow-x-auto [&_pre]:rounded-md [&_pre]:border [&_pre]:border-border [&_pre]:bg-muted [&_pre]:p-3",
  "[&_pre_code]:bg-transparent [&_pre_code]:p-0",
  "[&_blockquote]:my-2 [&_blockquote]:border-l-2 [&_blockquote]:border-border [&_blockquote]:pl-3 [&_blockquote]:text-muted-foreground",
  "[&_table]:my-2 [&_table]:w-full [&_table]:border-collapse [&_table]:text-xs",
  "[&_th]:border [&_th]:border-border [&_th]:px-2 [&_th]:py-1 [&_th]:text-left [&_th]:font-medium",
  "[&_td]:border [&_td]:border-border [&_td]:px-2 [&_td]:py-1"
);
const MARKDOWN_COMPONENTS = {
  a: ({ node, ...props }) => /* @__PURE__ */ jsx("a", { ...props, target: "_blank", rel: "noreferrer" })
};
function MarkdownChunk({ text }) {
  if (!text.trim()) return null;
  return /* @__PURE__ */ jsx("div", { className: cn("text-sm", MARKDOWN_TYPOGRAPHY_CLASS), children: /* @__PURE__ */ jsx(ReactMarkdown, { remarkPlugins: [remarkGfm], components: MARKDOWN_COMPONENTS, children: text }) });
}
function MessageContent({ content, isAssistant }) {
  if (!isAssistant) {
    return /* @__PURE__ */ jsx("div", { className: "whitespace-pre-wrap text-sm", children: content });
  }
  if (!content) {
    return null;
  }
  const segments = parseAiContentSegments(content);
  if (segments.length === 0) {
    return null;
  }
  return /* @__PURE__ */ jsx("div", { className: "space-y-1", "data-ai-message-content": "", children: segments.map((segment, index) => {
    if (segment.kind === "record-card") {
      return /* @__PURE__ */ jsx(RecordCard, { data: segment.payload }, `card-${index}`);
    }
    if (segment.kind === "invalid-card") {
      return /* @__PURE__ */ jsx(
        "pre",
        {
          className: "my-2 max-h-60 overflow-auto rounded-md border border-dashed border-border bg-muted p-2 text-xs",
          "data-ai-record-card-invalid": segment.info,
          children: segment.raw
        },
        `raw-${index}`
      );
    }
    return /* @__PURE__ */ jsx(MarkdownChunk, { text: segment.text }, `md-${index}`);
  }) });
}
function safeStringify(value) {
  if (value === null || value === void 0) return "";
  if (typeof value === "string") return value;
  try {
    return JSON.stringify(value, null, 2);
  } catch {
    return String(value);
  }
}
function titleWords(value) {
  return value.replace(/\b[a-z]/g, (char) => char.toUpperCase());
}
function formatToolCaption(call) {
  const rawCaption = call.caption?.trim();
  if (!rawCaption) return call.toolName;
  const caption = titleWords(rawCaption.replace(/\s*·\s*/g, " - "));
  return `${caption} (${call.toolName})`;
}
function AiChatTaskPlan({ tasks }) {
  const t = useT();
  if (!tasks || tasks.length === 0) return null;
  return /* @__PURE__ */ jsxs(
    "div",
    {
      className: "rounded-md border border-border bg-muted/30",
      "data-ai-chat-task-plan": "",
      "data-ai-chat-task-plan-count": tasks.length,
      children: [
        /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 border-b border-border/60 px-2 py-1.5 text-[11px] font-medium uppercase tracking-wide text-muted-foreground", children: [
          /* @__PURE__ */ jsx(ListChecks, { className: "size-3.5 text-muted-foreground", "aria-hidden": true }),
          /* @__PURE__ */ jsx("span", { children: t("ai_assistant.chat.taskPlanTitle", "Plan") }),
          /* @__PURE__ */ jsx("span", { className: "ml-auto font-mono", children: tasks.length })
        ] }),
        /* @__PURE__ */ jsx("ul", { className: "divide-y divide-border/60", "data-ai-chat-task-plan-list": "", children: tasks.map((task) => /* @__PURE__ */ jsx(AiChatTaskRow, { task }, task.id)) })
      ]
    }
  );
}
function AiChatTaskRow({ task }) {
  const t = useT();
  const statusLabel = task.state === "running" ? t("ai_assistant.chat.taskRunning", "running\u2026") : task.state === "done" ? t("ai_assistant.chat.taskDone", "done") : task.state === "failed" ? t("ai_assistant.chat.taskFailed", "failed") : task.state === "skipped" ? t("ai_assistant.chat.taskSkipped", "skipped") : t("ai_assistant.chat.taskPending", "pending");
  const Icon = task.state === "running" ? Loader2 : task.state === "done" ? CircleCheck : task.state === "failed" ? CircleAlert : task.state === "skipped" ? CircleDashed : Circle;
  const iconClassName = cn(
    "size-3.5 shrink-0",
    task.state === "running" && "animate-spin text-muted-foreground",
    task.state === "done" && "text-status-success-icon",
    task.state === "failed" && "text-destructive",
    task.state === "skipped" && "text-muted-foreground",
    task.state === "pending" && "text-muted-foreground"
  );
  const statusBadgeClassName = cn(
    "ml-auto text-[10px] uppercase tracking-wide",
    task.state === "done" && "text-status-success-text",
    task.state === "failed" && "text-destructive",
    task.state !== "done" && task.state !== "failed" && "text-muted-foreground"
  );
  return /* @__PURE__ */ jsxs(
    "li",
    {
      className: "flex h-7 items-center gap-2 px-2 text-xs",
      "data-ai-chat-task-id": task.id,
      "data-ai-chat-task-state": task.state,
      "data-ai-chat-task-source": task.source,
      "data-ai-chat-task-tool-call-id": task.toolCallId,
      children: [
        /* @__PURE__ */ jsx(Icon, { className: iconClassName, "aria-hidden": true }),
        /* @__PURE__ */ jsx("span", { className: "truncate", title: task.detail ?? task.label, children: task.label }),
        /* @__PURE__ */ jsx("span", { className: statusBadgeClassName, children: statusLabel })
      ]
    }
  );
}
function ToolCallList({ toolCalls }) {
  const t = useT();
  const [openId, setOpenId] = React.useState(null);
  if (!toolCalls || toolCalls.length === 0) return null;
  return /* @__PURE__ */ jsxs(
    "div",
    {
      className: "rounded-md border border-border bg-muted/30",
      "data-ai-chat-tool-calls": "",
      "data-ai-chat-tool-call-count": toolCalls.length,
      children: [
        /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 border-b border-border/60 px-2 py-1.5 text-[11px] font-medium uppercase tracking-wide text-muted-foreground", children: [
          /* @__PURE__ */ jsx(Wrench, { className: "size-3.5 text-muted-foreground", "aria-hidden": true }),
          /* @__PURE__ */ jsx("span", { children: t("ai_assistant.chat.agentTasksTitle", "Tool calls") }),
          /* @__PURE__ */ jsx("span", { className: "ml-auto font-mono", children: toolCalls.length })
        ] }),
        /* @__PURE__ */ jsx("ul", { className: "divide-y divide-border/60", children: toolCalls.map((call) => {
          const isOpen = openId === call.id;
          const isError = call.state === "error";
          const isPending = call.state === "pending";
          const isComplete = call.state === "complete";
          const statusLabel = isError ? t("ai_assistant.chat.toolError", "failed") : isPending ? t("ai_assistant.chat.toolRunning", "running\u2026") : t("ai_assistant.chat.toolDone", "done");
          return /* @__PURE__ */ jsxs(
            "li",
            {
              className: cn(
                isError ? "bg-destructive/5" : ""
              ),
              "data-ai-chat-tool-call": call.toolName,
              "data-ai-chat-tool-state": call.state,
              children: [
                /* @__PURE__ */ jsxs(
                  Button,
                  {
                    variant: "ghost",
                    size: "2xs",
                    type: "button",
                    onClick: () => setOpenId(isOpen ? null : call.id),
                    className: "w-full justify-start rounded-none px-2 text-left hover:bg-muted/60",
                    children: [
                      isOpen ? /* @__PURE__ */ jsx(ChevronDown, { className: "size-3.5 text-muted-foreground", "aria-hidden": true }) : /* @__PURE__ */ jsx(ChevronRight, { className: "size-3.5 text-muted-foreground", "aria-hidden": true }),
                      isPending ? /* @__PURE__ */ jsx(Loader2, { className: "size-3.5 animate-spin text-muted-foreground", "aria-hidden": true }) : /* @__PURE__ */ jsx(
                        Wrench,
                        {
                          className: cn(
                            "size-3.5",
                            isError ? "text-destructive" : "text-muted-foreground"
                          ),
                          "aria-hidden": true
                        }
                      ),
                      /* @__PURE__ */ jsx("span", { className: "truncate", title: formatToolCaption(call), children: formatToolCaption(call) }),
                      /* @__PURE__ */ jsx(
                        "span",
                        {
                          className: cn(
                            "ml-auto text-[10px] uppercase tracking-wide",
                            isError ? "text-destructive" : isComplete ? "text-status-success-text" : "text-muted-foreground"
                          ),
                          children: statusLabel
                        }
                      )
                    ]
                  }
                ),
                isOpen ? /* @__PURE__ */ jsxs("div", { className: "space-y-1 border-t border-border/60 px-2 py-1.5 text-xs", children: [
                  call.input !== void 0 ? /* @__PURE__ */ jsxs("div", { children: [
                    /* @__PURE__ */ jsx("div", { className: "text-[10px] uppercase tracking-wide text-muted-foreground", children: t("ai_assistant.chat.toolInput", "Input") }),
                    /* @__PURE__ */ jsx("pre", { className: "mt-0.5 max-h-32 overflow-auto rounded bg-background p-1.5 font-mono text-[11px]", children: safeStringify(call.input) })
                  ] }) : null,
                  call.output !== void 0 && !isError ? /* @__PURE__ */ jsxs("div", { children: [
                    /* @__PURE__ */ jsx("div", { className: "text-[10px] uppercase tracking-wide text-muted-foreground", children: t("ai_assistant.chat.toolOutput", "Output") }),
                    /* @__PURE__ */ jsx("pre", { className: "mt-0.5 max-h-32 overflow-auto rounded bg-background p-1.5 font-mono text-[11px]", children: safeStringify(call.output) })
                  ] }) : null,
                  call.errorMessage ? /* @__PURE__ */ jsx("div", { className: "text-destructive", children: call.errorMessage }) : null
                ] }) : null
              ]
            },
            call.id
          );
        }) })
      ]
    }
  );
}
function ReasoningPanel({ text, streaming }) {
  const t = useT();
  const [open, setOpen] = React.useState(false);
  if (!text) return null;
  return /* @__PURE__ */ jsxs(
    "div",
    {
      className: "rounded-md border border-border bg-muted/30",
      "data-ai-chat-reasoning": streaming ? "streaming" : "complete",
      children: [
        /* @__PURE__ */ jsxs(
          "button",
          {
            type: "button",
            onClick: () => setOpen((o) => !o),
            className: "flex w-full items-center gap-2 px-2 py-1.5 text-left text-xs font-medium hover:bg-muted/60",
            children: [
              open ? /* @__PURE__ */ jsx(ChevronDown, { className: "size-3.5 text-muted-foreground", "aria-hidden": true }) : /* @__PURE__ */ jsx(ChevronRight, { className: "size-3.5 text-muted-foreground", "aria-hidden": true }),
              /* @__PURE__ */ jsx(Lightbulb, { className: "size-3.5 text-muted-foreground", "aria-hidden": true }),
              /* @__PURE__ */ jsx("span", { children: t("ai_assistant.chat.reasoning", "Reasoning") }),
              streaming ? /* @__PURE__ */ jsx(
                Loader2,
                {
                  className: "ml-1 size-3 animate-spin text-muted-foreground",
                  "aria-hidden": true
                }
              ) : null
            ]
          }
        ),
        open ? /* @__PURE__ */ jsx("pre", { className: "max-h-48 overflow-auto whitespace-pre-wrap border-t border-border/60 px-2 py-1.5 text-xs text-muted-foreground", children: text }) : null
      ]
    }
  );
}
function getAttachmentImageUrl(file) {
  if (file.id) return `/api/attachments/image/${encodeURIComponent(file.id)}`;
  return file.previewUrl ?? null;
}
function getAttachmentDownloadUrl(file) {
  if (file.id) return `/api/attachments/file/${encodeURIComponent(file.id)}?download=1`;
  return file.previewUrl ?? null;
}
function MessageFileAttachment({ file }) {
  const t = useT();
  const [zoomOpen, setZoomOpen] = React.useState(false);
  const imageUrl = file.previewUrl ? getAttachmentImageUrl(file) : null;
  const downloadUrl = getAttachmentDownloadUrl(file);
  const downloadLabel = t("ai_assistant.chat.downloadFile", "Download {name}").replace(
    "{name}",
    file.name
  );
  const zoomLabel = t("ai_assistant.chat.zoomImage", "Open {name} preview").replace(
    "{name}",
    file.name
  );
  if (!file.previewUrl) {
    return /* @__PURE__ */ jsxs("span", { className: "inline-flex max-w-full items-center gap-1 rounded-full border border-border bg-muted px-2 py-0.5 text-xs", children: [
      /* @__PURE__ */ jsx(Paperclip, { className: "size-3 shrink-0", "aria-hidden": true }),
      /* @__PURE__ */ jsx("span", { className: "max-w-[180px] truncate", children: file.name }),
      downloadUrl ? /* @__PURE__ */ jsx(
        IconButton,
        {
          asChild: true,
          variant: "ghost",
          size: "xs",
          className: "-mr-1 size-5 shrink-0",
          children: /* @__PURE__ */ jsx("a", { href: downloadUrl, download: file.name, "aria-label": downloadLabel, children: /* @__PURE__ */ jsx(Download, { className: "size-3", "aria-hidden": true }) })
        }
      ) : null
    ] });
  }
  return /* @__PURE__ */ jsxs(Fragment, { children: [
    /* @__PURE__ */ jsxs("div", { className: "group/file relative max-w-full", children: [
      /* @__PURE__ */ jsxs(
        "button",
        {
          type: "button",
          className: "block max-w-full rounded-md border border-border bg-muted/30 focus-visible:outline-none focus-visible:shadow-focus",
          onClick: () => setZoomOpen(true),
          "aria-label": zoomLabel,
          "data-ai-chat-image-preview": "",
          children: [
            /* @__PURE__ */ jsx(
              "img",
              {
                src: file.previewUrl,
                alt: file.name,
                className: "max-h-32 max-w-[200px] rounded-md object-cover"
              }
            ),
            /* @__PURE__ */ jsx("span", { className: "pointer-events-none absolute right-1 top-1 inline-flex size-6 items-center justify-center rounded-md bg-background/90 text-muted-foreground opacity-0 shadow-xs transition-opacity group-hover/file:opacity-100 group-focus-within/file:opacity-100", children: /* @__PURE__ */ jsx(Maximize2, { className: "size-3.5", "aria-hidden": true }) })
          ]
        }
      ),
      downloadUrl ? /* @__PURE__ */ jsx(
        IconButton,
        {
          asChild: true,
          variant: "white",
          size: "xs",
          className: "absolute bottom-1 right-1 opacity-0 shadow-xs transition-opacity group-hover/file:opacity-100 group-focus-within/file:opacity-100",
          children: /* @__PURE__ */ jsx(
            "a",
            {
              href: downloadUrl,
              download: file.name,
              "aria-label": downloadLabel,
              onClick: (event) => event.stopPropagation(),
              "data-ai-chat-file-download": "",
              children: /* @__PURE__ */ jsx(Download, { className: "size-3.5", "aria-hidden": true })
            }
          )
        }
      ) : null
    ] }),
    /* @__PURE__ */ jsx(Dialog, { open: zoomOpen, onOpenChange: setZoomOpen, children: /* @__PURE__ */ jsxs(DialogContent, { className: "gap-3 p-4 sm:max-w-[min(96vw,960px)]", children: [
      /* @__PURE__ */ jsxs(DialogHeader, { className: "min-w-0 pr-16", children: [
        /* @__PURE__ */ jsx(DialogTitle, { className: "truncate text-sm", children: file.name }),
        /* @__PURE__ */ jsx(DialogDescription, { className: "sr-only", children: t("ai_assistant.chat.imagePreviewDialogDescription", "Image preview") })
      ] }),
      /* @__PURE__ */ jsxs("div", { className: "relative flex min-h-0 items-center justify-center overflow-auto rounded-md bg-muted/30 p-2", children: [
        /* @__PURE__ */ jsx(
          "img",
          {
            src: imageUrl ?? file.previewUrl,
            alt: file.name,
            className: "max-h-[75vh] max-w-full object-contain"
          }
        ),
        downloadUrl ? /* @__PURE__ */ jsx(
          IconButton,
          {
            asChild: true,
            variant: "white",
            size: "sm",
            className: "absolute bottom-3 right-3 shadow-xs",
            children: /* @__PURE__ */ jsx(
              "a",
              {
                href: downloadUrl,
                download: file.name,
                "aria-label": downloadLabel,
                "data-ai-chat-file-download": "",
                children: /* @__PURE__ */ jsx(Download, { className: "size-4", "aria-hidden": true })
              }
            )
          }
        ) : null
      ] })
    ] }) })
  ] });
}
function MessageRow({
  message,
  registry,
  onMutationRequested
}) {
  const t = useT();
  const isAssistant = message.role === "assistant";
  const label = isAssistant ? t("ai_assistant.chat.assistantRoleLabel", "Assistant") : t("ai_assistant.chat.userRoleLabel", "You");
  const Icon = isAssistant ? Bot : User;
  const [copied, setCopied] = React.useState(false);
  const copyTimerRef = React.useRef(null);
  const visibleTaskPlan = isAssistant && message.taskPlan ? message.taskPlan.filter((task) => task.source === "agent") : [];
  React.useEffect(() => {
    return () => {
      if (copyTimerRef.current) clearTimeout(copyTimerRef.current);
    };
  }, []);
  const handleCopy = React.useCallback(async () => {
    const text = message.content;
    if (!text) return;
    try {
      if (typeof navigator !== "undefined" && navigator.clipboard?.writeText) {
        await navigator.clipboard.writeText(text);
      } else {
        const textarea = document.createElement("textarea");
        textarea.value = text;
        textarea.setAttribute("readonly", "");
        textarea.style.position = "absolute";
        textarea.style.left = "-9999px";
        document.body.appendChild(textarea);
        textarea.select();
        document.execCommand("copy");
        document.body.removeChild(textarea);
      }
      setCopied(true);
      if (copyTimerRef.current) clearTimeout(copyTimerRef.current);
      copyTimerRef.current = setTimeout(() => setCopied(false), 1500);
    } catch {
    }
  }, [message.content]);
  return /* @__PURE__ */ jsxs(
    "div",
    {
      className: cn(
        "group/message flex gap-3 px-3 py-2",
        isAssistant ? "bg-muted/40 rounded-md" : ""
      ),
      "data-role": message.role,
      children: [
        /* @__PURE__ */ jsx(
          "div",
          {
            className: cn(
              "flex size-6 shrink-0 items-center justify-center rounded-full",
              isAssistant ? "bg-primary/10 text-primary" : "bg-secondary text-secondary-foreground"
            ),
            "aria-hidden": true,
            children: /* @__PURE__ */ jsx(Icon, { className: "size-4" })
          }
        ),
        /* @__PURE__ */ jsxs("div", { className: "flex-1 space-y-1", children: [
          /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2", children: [
            /* @__PURE__ */ jsx("div", { className: "text-xs font-medium text-muted-foreground", children: label }),
            message.content ? /* @__PURE__ */ jsx(
              IconButton,
              {
                type: "button",
                variant: "ghost",
                size: "sm",
                onClick: handleCopy,
                "aria-label": copied ? t("ai_assistant.chat.copied", "Copied") : t("ai_assistant.chat.copyMessage", "Copy message"),
                "data-ai-chat-copy-button": "",
                className: "opacity-0 transition-opacity group-hover/message:opacity-100 focus-visible:opacity-100",
                children: copied ? /* @__PURE__ */ jsx(Check, { className: "size-3.5 text-status-success-icon", "aria-hidden": true }) : /* @__PURE__ */ jsx(Copy, { className: "size-3.5", "aria-hidden": true })
              }
            ) : null
          ] }),
          message.files && message.files.length > 0 ? /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-2 py-1", children: message.files.map((file, i) => /* @__PURE__ */ jsx(MessageFileAttachment, { file }, `${file.id ?? file.name}:${i}`)) }) : null,
          isAssistant && message.reasoning ? /* @__PURE__ */ jsx(
            ReasoningPanel,
            {
              text: message.reasoning,
              streaming: message.reasoningStreaming === true
            }
          ) : null,
          visibleTaskPlan.length > 0 ? /* @__PURE__ */ jsx(AiChatTaskPlan, { tasks: visibleTaskPlan }) : null,
          isAssistant && message.toolCalls && message.toolCalls.length > 0 ? /* @__PURE__ */ jsx(ToolCallList, { toolCalls: message.toolCalls }) : null,
          /* @__PURE__ */ jsx(MessageContent, { content: message.content, isAssistant }),
          isAssistant && registry && message.uiParts && message.uiParts.length > 0 ? /* @__PURE__ */ jsx(
            MessageUiParts,
            {
              parts: message.uiParts,
              registry,
              onMutationRequested
            }
          ) : null
        ] })
      ]
    }
  );
}
function MessageUiParts({
  parts,
  registry,
  onMutationRequested
}) {
  return /* @__PURE__ */ jsx("div", { className: "mt-2 flex flex-col gap-2", "data-ai-message-ui-parts": "", children: parts.map((part) => /* @__PURE__ */ jsx(
    AiUiPartRenderer,
    {
      part: {
        componentId: part.componentId,
        payload: part.payload,
        pendingActionId: part.pendingActionId
      },
      registry,
      onMutationRequested
    },
    part.key
  )) });
}
function UnknownUiPartPlaceholder({ componentId }) {
  const t = useT();
  return /* @__PURE__ */ jsx(
    "div",
    {
      className: "inline-flex items-center gap-2 rounded-full border border-dashed border-border bg-muted px-3 py-1 text-xs text-muted-foreground",
      "data-ai-ui-part-placeholder": componentId,
      children: /* @__PURE__ */ jsxs("span", { children: [
        t("ai_assistant.chat.uiPartPending", "Pending UI part:"),
        " ",
        componentId
      ] })
    }
  );
}
function AiUiPartRenderer({
  part,
  registry,
  onMutationRequested
}) {
  const Component = registry.resolve(part.componentId);
  const isReserved = isReservedAiUiPartId(part.componentId);
  React.useEffect(() => {
    if (Component) return;
    if (isReserved) return;
    try {
      console.warn(
        `[AiChat] No component registered for UI part "${part.componentId}".`
      );
    } catch {
    }
  }, [Component, part.componentId, isReserved]);
  React.useEffect(() => {
    if (part.pendingActionId) {
      onMutationRequested?.(part.pendingActionId);
    }
  }, [part.pendingActionId, onMutationRequested]);
  if (!Component) {
    return /* @__PURE__ */ jsx(UnknownUiPartPlaceholder, { componentId: part.componentId });
  }
  return /* @__PURE__ */ jsx(
    Component,
    {
      componentId: part.componentId,
      payload: part.payload,
      pendingActionId: part.pendingActionId
    }
  );
}
function getSuggestionIcon(suggestion) {
  if (suggestion.icon) return { icon: suggestion.icon, name: "custom" };
  const text = `${suggestion.label} ${suggestion.prompt}`.toLowerCase();
  const iconClassName = "size-4 text-foreground";
  if (/\b(analy[sz]e|analysis|health|score|summary|summari[sz]e)\b/.test(text)) {
    return { icon: /* @__PURE__ */ jsx(ChartNoAxesCombined, { className: iconClassName }), name: "analysis" };
  }
  if (/\b(at[-\s]?risk|risk|stalled|stale|overdue|danger)\b/.test(text)) {
    return { icon: /* @__PURE__ */ jsx(AlertTriangle, { className: iconClassName }), name: "risk" };
  }
  if (/\bpipeline|stage|funnel\b/.test(text)) {
    return { icon: /* @__PURE__ */ jsx(GitBranch, { className: iconClassName }), name: "pipeline" };
  }
  if (/\bdeal|opportunit(?:y|ies)\b/.test(text)) {
    return { icon: /* @__PURE__ */ jsx(Handshake, { className: iconClassName }), name: "deal" };
  }
  if (/\bdata|access|record|records|schema\b/.test(text)) {
    return { icon: /* @__PURE__ */ jsx(Database, { className: iconClassName }), name: "data" };
  }
  if (/\bwhat can you help|help me|capabilit(?:y|ies)\b/.test(text)) {
    return { icon: /* @__PURE__ */ jsx(BadgeQuestionMark, { className: iconClassName }), name: "capabilities" };
  }
  if (/\bsuggest|try|idea|ideas|recommend\b/.test(text)) {
    return { icon: /* @__PURE__ */ jsx(Lightbulb, { className: iconClassName }), name: "ideas" };
  }
  if (/\bhow do i|how to|use this|instructions?|guide\b/.test(text)) {
    return { icon: /* @__PURE__ */ jsx(FileQuestion, { className: iconClassName }), name: "guide" };
  }
  if (/\bfind|search|show|list|lookup\b/.test(text)) {
    return { icon: /* @__PURE__ */ jsx(Search, { className: iconClassName }), name: "search" };
  }
  if (/\bactivity|activities|timeline|recent\b/.test(text)) {
    return { icon: /* @__PURE__ */ jsx(Activity, { className: iconClassName }), name: "activity" };
  }
  if (/\bdown|drop|declin|loss|lost\b/.test(text)) {
    return { icon: /* @__PURE__ */ jsx(TrendingDown, { className: iconClassName }), name: "trend-down" };
  }
  return { icon: /* @__PURE__ */ jsx(AiIcon, { className: iconClassName }), name: "ai" };
}
function WelcomeState({
  title,
  description,
  suggestions,
  onSuggestionClick
}) {
  const t = useT();
  const heading = title ?? t("ai_assistant.chat.welcomeTitle", "How can I help?");
  const desc = description ?? t(
    "ai_assistant.chat.welcomeDescription",
    "Ask me anything about your data. Here are some things I can do:"
  );
  return /* @__PURE__ */ jsxs("div", { className: "flex flex-1 flex-col items-center justify-center gap-4 px-4 py-8", children: [
    /* @__PURE__ */ jsx(
      "div",
      {
        className: "flex size-12 items-center justify-center rounded-full bg-primary/10 text-primary",
        "aria-hidden": true,
        children: /* @__PURE__ */ jsx(Bot, { className: "size-6" })
      }
    ),
    /* @__PURE__ */ jsxs("div", { className: "space-y-1 text-center", children: [
      /* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold", children: heading }),
      /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: desc })
    ] }),
    suggestions && suggestions.length > 0 ? /* @__PURE__ */ jsx("div", { className: "flex w-full max-w-md flex-col gap-2", "data-ai-chat-suggestions": "", children: suggestions.map((suggestion, index) => {
      const suggestionIcon = getSuggestionIcon(suggestion);
      return /* @__PURE__ */ jsxs(
        Button,
        {
          variant: "outline",
          type: "button",
          className: "h-auto w-full justify-start whitespace-normal rounded-lg bg-card px-3 py-2.5 text-left text-sm",
          onClick: () => onSuggestionClick(suggestion.prompt),
          "data-ai-chat-suggestion": index,
          "data-ai-chat-suggestion-icon": suggestionIcon.name,
          children: [
            /* @__PURE__ */ jsx("span", { className: "shrink-0 text-muted-foreground", "aria-hidden": true, children: suggestionIcon.icon }),
            /* @__PURE__ */ jsx("span", { children: suggestion.label })
          ]
        },
        index
      );
    }) }) : null
  ] });
}
function ContextItemsPill({ items }) {
  if (items.length === 0) return null;
  return /* @__PURE__ */ jsx(
    "div",
    {
      className: "flex flex-wrap gap-1.5 border-b border-border px-3 py-2",
      "data-ai-chat-context-items": "",
      children: items.map((item, index) => /* @__PURE__ */ jsx(
        "span",
        {
          className: "inline-flex items-center gap-1 rounded-full border border-border bg-secondary px-2 py-0.5 text-xs text-secondary-foreground",
          "data-ai-chat-context-item": index,
          title: item.detail,
          children: item.label
        },
        index
      ))
    }
  );
}
function AiChat({
  agent,
  apiPath,
  pageContext,
  attachmentIds,
  initialMessages,
  debug,
  className,
  placeholder,
  onMutationRequested,
  onError,
  registry,
  uiParts: uiPartsProp,
  debugTools,
  debugPromptSections,
  loopTrace,
  conversationId,
  suggestions,
  contextItems,
  welcomeTitle,
  welcomeDescription,
  defaultCompactFooter = false
}) {
  const t = useT();
  const textareaRef = React.useRef(null);
  const transcriptRef = React.useRef(null);
  const fileInputRef = React.useRef(null);
  const [input, setInput] = React.useState("");
  const [pendingFiles, setPendingFiles] = React.useState([]);
  const upload = useAiChatUpload();
  const isUploading = upload.busy;
  const footerRef = React.useRef(null);
  const [isCompactFooter, setIsCompactFooter] = React.useState(defaultCompactFooter);
  React.useEffect(() => {
    const element = footerRef.current;
    if (!element || typeof ResizeObserver === "undefined") return;
    const updateCompactState = (width) => {
      setIsCompactFooter(width < COMPACT_FOOTER_MAX_WIDTH);
    };
    updateCompactState(element.getBoundingClientRect().width);
    const observer = new ResizeObserver((entries) => {
      const entry = entries[0];
      if (!entry) return;
      updateCompactState(entry.contentRect.width);
    });
    observer.observe(element);
    return () => observer.disconnect();
  }, []);
  const uploadedAttachmentIds = React.useMemo(
    () => pendingFiles.map((entry) => entry.attachmentId).filter((id) => typeof id === "string" && id.length > 0),
    [pendingFiles]
  );
  const allAttachmentIds = React.useMemo(
    () => [...attachmentIds ?? [], ...uploadedAttachmentIds],
    [attachmentIds, uploadedAttachmentIds]
  );
  const {
    providers: modelProviders,
    allowRuntimeOverride,
    allowRuntimeModelOverride,
    defaultLabel: modelDefaultLabel,
    loaded: modelProvidersLoaded
  } = useAgentModels(agent);
  const [modelPickerValue, setModelPickerValue] = React.useState(
    () => readModelPickerValue(agent)
  );
  const effectiveModelPickerValue = React.useMemo(() => {
    if (!modelProvidersLoaded || !allowRuntimeOverride || modelProviders.length === 0) {
      return null;
    }
    if (modelPickerValue && isModelPickerValueAvailable(modelPickerValue, modelProviders)) {
      return modelPickerValue;
    }
    return null;
  }, [
    allowRuntimeOverride,
    modelPickerValue,
    modelProviders,
    modelProvidersLoaded
  ]);
  React.useEffect(() => {
    setModelPickerValue(readModelPickerValue(agent));
  }, [agent]);
  React.useEffect(() => {
    if (!modelProvidersLoaded) return;
    if (!allowRuntimeModelOverride || modelProviders.length === 0) {
      if (modelPickerValue !== null) {
        setModelPickerValue(null);
        writeModelPickerValue(agent, null);
      }
      return;
    }
    if (modelPickerValue && !isModelPickerValueAvailable(modelPickerValue, modelProviders)) {
      setModelPickerValue(null);
      writeModelPickerValue(agent, null);
    }
  }, [
    agent,
    allowRuntimeModelOverride,
    modelPickerValue,
    modelProviders,
    modelProvidersLoaded
  ]);
  const handleModelPickerChange = React.useCallback(
    (value) => {
      setModelPickerValue(value);
      writeModelPickerValue(agent, value);
    },
    [agent]
  );
  const chat = useAiChat({
    agent,
    apiPath,
    pageContext,
    attachmentIds: allAttachmentIds.length > 0 ? allAttachmentIds : void 0,
    debug,
    initialMessages,
    onError,
    conversationId,
    providerOverride: effectiveModelPickerValue?.providerId ?? null,
    modelOverride: effectiveModelPickerValue?.modelId ?? null
  });
  const isStreaming = chat.status === "streaming";
  const isSubmitting = chat.status === "submitting";
  const isBusy = isStreaming || isSubmitting;
  const lastAssistant = React.useMemo(() => {
    for (let index = chat.messages.length - 1; index >= 0; index -= 1) {
      const candidate = chat.messages[index];
      if (candidate?.role === "assistant") return candidate;
    }
    return null;
  }, [chat.messages]);
  const trimmedContent = lastAssistant?.content?.trim() ?? "";
  const hasReasoning = !!(lastAssistant?.reasoning && lastAssistant.reasoning.length > 0);
  const toolCalls = lastAssistant?.toolCalls ?? [];
  const hasPendingToolCall = toolCalls.some((call) => call.state === "pending");
  const hasCompletedToolCall = toolCalls.some(
    (call) => call.state === "complete" || call.state === "error"
  );
  const hasAnyVisibleSignal = !!(trimmedContent || hasReasoning || toolCalls.length > 0);
  const assistantStreamSnapshot = React.useMemo(() => {
    if (!lastAssistant) return "";
    const toolSig = toolCalls.map((call) => `${call.id}:${call.state}:${call.output != null ? 1 : 0}`).join("|");
    return [
      lastAssistant.id,
      lastAssistant.content?.length ?? 0,
      lastAssistant.reasoning?.length ?? 0,
      lastAssistant.reasoningStreaming ? 1 : 0,
      toolSig
    ].join("#");
  }, [lastAssistant]);
  const lastSnapshotRef = React.useRef("");
  const [, setStreamTick] = React.useState(0);
  React.useEffect(() => {
    if (assistantStreamSnapshot !== lastSnapshotRef.current) {
      lastSnapshotRef.current = assistantStreamSnapshot;
      setStreamTick((value) => value + 1);
    }
  }, [assistantStreamSnapshot]);
  const showThinkingIndicator = isSubmitting || isStreaming && (!hasAnyVisibleSignal || hasPendingToolCall || // Tool just returned and the model hasn't started speaking yet.
  hasCompletedToolCall && !trimmedContent);
  const activeRegistry = registry ?? defaultAiUiPartRegistry;
  const uiParts = React.useMemo(
    () => (uiPartsProp ?? []).map((part) => ({
      componentId: part.componentId,
      payload: part.payload,
      pendingActionId: part.pendingActionId
    })),
    [uiPartsProp]
  );
  const hasUploadingFiles = React.useMemo(
    () => pendingFiles.some((entry) => !entry.attachmentId && !entry.error),
    [pendingFiles]
  );
  const handleSendMessage = React.useCallback(
    (text) => {
      if (!text.trim() || isBusy) return;
      if (hasUploadingFiles || isUploading) return;
      const filesToAttach = pendingFiles.map((entry) => {
        const isImage = entry.file.type.startsWith("image/");
        const fallback = isImage ? URL.createObjectURL(entry.file) : void 0;
        return {
          id: entry.attachmentId,
          name: entry.file.name,
          type: entry.file.type,
          previewUrl: isImage ? entry.previewDataUrl ?? fallback : void 0
        };
      });
      setInput("");
      setPendingFiles([]);
      void chat.sendMessage(text, filesToAttach.length > 0 ? filesToAttach : void 0);
    },
    [chat, hasUploadingFiles, isBusy, isUploading, pendingFiles]
  );
  const handleSubmit = React.useCallback(() => {
    handleSendMessage(input);
  }, [handleSendMessage, input]);
  React.useEffect(() => {
    if (typeof window === "undefined") return;
    const handler = (event) => {
      const detail = event.detail;
      const message = detail?.message;
      if (typeof message !== "string" || message.trim().length === 0) return;
      handleSendMessage(message);
    };
    window.addEventListener("om-ai-chat-fix-request", handler);
    return () => {
      window.removeEventListener("om-ai-chat-fix-request", handler);
    };
  }, [handleSendMessage]);
  const cancelOrBlur = React.useCallback(() => {
    if (isBusy) {
      chat.cancel();
      return;
    }
    textareaRef.current?.blur();
  }, [chat, isBusy]);
  const handleFileSelect = React.useCallback(
    async (event) => {
      const files = Array.from(event.target.files ?? []);
      if (files.length === 0) return;
      const queued = files.map((file) => ({ file }));
      setPendingFiles((prev) => [...prev, ...queued]);
      const [previewResults, result] = await Promise.all([
        Promise.all(files.map((file) => readFileAsDataUrl(file))),
        upload.upload(files)
      ]);
      const idByIndex = /* @__PURE__ */ new Map();
      for (const item of result.items) {
        if (typeof item.inputIndex === "number") idByIndex.set(item.inputIndex, item.attachmentId);
      }
      const errorByIndex = /* @__PURE__ */ new Map();
      for (const failure of result.failed) {
        if (typeof failure.inputIndex === "number") errorByIndex.set(failure.inputIndex, failure.message);
      }
      setPendingFiles((prev) => {
        const next = prev.slice();
        const baseIndex = next.length - files.length;
        for (let offset = 0; offset < files.length; offset += 1) {
          const index = baseIndex + offset;
          if (index < 0) continue;
          const entry = next[index];
          if (!entry) continue;
          const dataUrl = previewResults[offset];
          const patch = {
            ...entry,
            previewDataUrl: dataUrl ?? entry.previewDataUrl
          };
          if (!patch.attachmentId) {
            const id = idByIndex.get(offset);
            if (id) {
              patch.attachmentId = id;
              patch.error = void 0;
            } else {
              const explicitError = errorByIndex.get(offset);
              patch.error = explicitError ?? "Upload finished without a server response. Remove the file and try again.";
            }
          }
          next[index] = patch;
        }
        return next;
      });
      if (fileInputRef.current) fileInputRef.current.value = "";
    },
    [upload]
  );
  const removePendingFile = React.useCallback((index) => {
    setPendingFiles((prev) => prev.filter((_, i) => i !== index));
  }, []);
  const { handleKeyDown } = useAiShortcuts({
    onSubmit: handleSubmit,
    onCancel: cancelOrBlur
  });
  React.useEffect(() => {
    textareaRef.current?.focus();
  }, []);
  const stickToBottomRef = React.useRef(true);
  const SCROLL_STICK_TOLERANCE_PX = 64;
  React.useEffect(() => {
    const node = transcriptRef.current;
    if (!node) return;
    const handleScroll = () => {
      const distanceFromBottom = node.scrollHeight - node.scrollTop - node.clientHeight;
      stickToBottomRef.current = distanceFromBottom <= SCROLL_STICK_TOLERANCE_PX;
    };
    node.addEventListener("scroll", handleScroll, { passive: true });
    return () => node.removeEventListener("scroll", handleScroll);
  }, []);
  React.useEffect(() => {
    const node = transcriptRef.current;
    if (!node) return;
    if (!stickToBottomRef.current) return;
    node.scrollTop = node.scrollHeight;
  }, [chat.messages]);
  React.useEffect(() => {
    if (typeof document === "undefined") return;
    const previous = document.body.getAttribute("data-ai-chat-open");
    document.body.setAttribute("data-ai-chat-open", "true");
    return () => {
      if (previous === null) {
        document.body.removeAttribute("data-ai-chat-open");
      } else {
        document.body.setAttribute("data-ai-chat-open", previous);
      }
    };
  }, []);
  const handleNewConversation = React.useCallback(() => {
    chat.reset();
    setInput("");
    setPendingFiles([]);
    upload.reset();
    setTimeout(() => textareaRef.current?.focus(), 0);
  }, [chat, upload]);
  const resolvedPlaceholder = placeholder ?? t("ai_assistant.chat.composerPlaceholder", "Message the AI agent...");
  const errorVariant = mapErrorCodeToVariant(chat.error?.code);
  return /* @__PURE__ */ jsxs(
    "section",
    {
      className: cn(
        "flex h-full min-h-[320px] min-w-0 flex-col gap-3 overflow-hidden rounded-lg border border-border bg-background p-3",
        className
      ),
      "aria-label": t("ai_assistant.chat.regionLabel", "AI chat"),
      "data-ai-chat-agent": agent,
      "data-ai-chat-conversation-id": chat.conversationId,
      children: [
        /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 items-center justify-between gap-2 border-b border-border pb-2", children: [
          /* @__PURE__ */ jsx("div", { className: "flex min-w-0 flex-1 items-center gap-2 text-xs text-muted-foreground", children: contextItems && contextItems.length > 0 ? /* @__PURE__ */ jsx(ContextItemsPill, { items: contextItems }) : /* @__PURE__ */ jsx("span", { className: "font-mono opacity-70", "aria-hidden": true, children: chat.conversationId.slice(0, 8) }) }),
          /* @__PURE__ */ jsx(
            IconButton,
            {
              type: "button",
              variant: "ghost",
              size: "sm",
              onClick: handleNewConversation,
              disabled: isBusy,
              "aria-label": t("ai_assistant.chat.newConversation", "Start new conversation"),
              title: t("ai_assistant.chat.newConversation", "Start new conversation"),
              "data-ai-chat-new-conversation": "",
              children: /* @__PURE__ */ jsx(Plus, { className: "size-4", "aria-hidden": true })
            }
          )
        ] }),
        /* @__PURE__ */ jsxs(
          "div",
          {
            ref: transcriptRef,
            role: "log",
            "aria-live": "polite",
            "aria-label": t("ai_assistant.chat.transcriptLabel", "Chat transcript"),
            className: "min-w-0 flex-1 space-y-2 overflow-y-auto overflow-x-hidden pr-1",
            children: [
              chat.messages.length === 0 ? /* @__PURE__ */ jsx(
                WelcomeState,
                {
                  title: welcomeTitle,
                  description: welcomeDescription,
                  suggestions,
                  onSuggestionClick: handleSendMessage
                }
              ) : chat.messages.map((message) => /* @__PURE__ */ jsx(
                MessageRow,
                {
                  message,
                  registry: activeRegistry,
                  onMutationRequested
                },
                message.id
              )),
              uiParts.map((part, index) => /* @__PURE__ */ jsx(
                AiUiPartRenderer,
                {
                  part,
                  registry: activeRegistry,
                  onMutationRequested
                },
                `${part.componentId}-${index}`
              )),
              showThinkingIndicator ? /* @__PURE__ */ jsxs(
                "div",
                {
                  className: "flex items-center gap-2 px-3 py-2 text-xs text-muted-foreground",
                  "data-ai-chat-state": "thinking",
                  children: [
                    /* @__PURE__ */ jsx(Loader2, { className: "size-4 animate-spin", "aria-hidden": true }),
                    /* @__PURE__ */ jsx("span", { children: t("ai_assistant.chat.thinking", "Thinking...") })
                  ]
                }
              ) : null
            ]
          }
        ),
        chat.error ? /* @__PURE__ */ jsxs(Alert, { variant: errorVariant, "data-ai-chat-error": chat.error.code ?? "unknown", children: [
          /* @__PURE__ */ jsx(AlertTitle, { children: t("ai_assistant.chat.errorTitle", "Agent dispatch failed") }),
          /* @__PURE__ */ jsxs(AlertDescription, { children: [
            chat.error.code ? /* @__PURE__ */ jsx("span", { className: "mr-2 font-mono text-xs", children: chat.error.code }) : null,
            chat.error.message
          ] })
        ] }) : null,
        /* @__PURE__ */ jsxs(
          "form",
          {
            className: "flex min-w-0 flex-col gap-2",
            onSubmit: (event) => {
              event.preventDefault();
              handleSubmit();
            },
            children: [
              /* @__PURE__ */ jsx(
                Label,
                {
                  htmlFor: "ai-chat-composer",
                  className: "sr-only",
                  children: t("ai_assistant.chat.composerLabel", "Message composer")
                }
              ),
              pendingFiles.length > 0 ? /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-1.5 rounded-md border border-border bg-muted/30 px-2 py-1.5", "data-ai-chat-attachments": "", children: [
                pendingFiles.map((entry, index) => /* @__PURE__ */ jsxs(
                  "span",
                  {
                    className: "inline-flex items-center gap-1 rounded-full border border-border bg-background px-2 py-0.5 text-xs",
                    title: entry.error ? entry.error : void 0,
                    "data-ai-chat-attachment-state": entry.error ? "error" : entry.attachmentId ? "ready" : "uploading",
                    children: [
                      /* @__PURE__ */ jsx(Paperclip, { className: "size-3 text-muted-foreground", "aria-hidden": true }),
                      /* @__PURE__ */ jsx("span", { className: "max-w-[120px] truncate", children: entry.file.name }),
                      !entry.attachmentId && !entry.error ? /* @__PURE__ */ jsx(Loader2, { className: "size-3 animate-spin text-muted-foreground", "aria-hidden": true }) : null,
                      /* @__PURE__ */ jsx(
                        "button",
                        {
                          type: "button",
                          className: "ml-0.5 rounded-full p-0.5 hover:bg-muted",
                          onClick: () => removePendingFile(index),
                          "aria-label": t("ai_assistant.chat.removeFile", "Remove file"),
                          children: /* @__PURE__ */ jsx(X, { className: "size-3" })
                        }
                      )
                    ]
                  },
                  index
                )),
                isUploading ? /* @__PURE__ */ jsx(Loader2, { className: "size-3 animate-spin text-muted-foreground", "aria-hidden": true }) : null
              ] }) : null,
              /* @__PURE__ */ jsx(
                Textarea,
                {
                  id: "ai-chat-composer",
                  ref: textareaRef,
                  value: input,
                  placeholder: resolvedPlaceholder,
                  onChange: (event) => setInput(event.target.value),
                  onKeyDown: handleKeyDown,
                  rows: 3,
                  "aria-label": t("ai_assistant.chat.composerLabel", "Message composer"),
                  className: "min-w-0 resize-none"
                }
              ),
              /* @__PURE__ */ jsx(
                "input",
                {
                  ref: fileInputRef,
                  type: "file",
                  multiple: true,
                  accept: "image/*,.pdf,.doc,.docx,.txt,.csv",
                  className: "hidden",
                  onChange: handleFileSelect,
                  "data-ai-chat-file-input": ""
                }
              ),
              /* @__PURE__ */ jsxs(
                "div",
                {
                  ref: footerRef,
                  className: "flex min-w-0 items-center justify-between gap-2",
                  "data-ai-chat-footer": "",
                  "data-ai-chat-footer-compact": isCompactFooter ? "true" : "false",
                  children: [
                    /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 items-center gap-2", children: [
                      /* @__PURE__ */ jsx(
                        IconButton,
                        {
                          type: "button",
                          variant: "ghost",
                          size: "sm",
                          onClick: () => fileInputRef.current?.click(),
                          disabled: isBusy || isUploading,
                          "aria-label": t("ai_assistant.chat.attachFile", "Attach file"),
                          children: /* @__PURE__ */ jsx(Paperclip, { className: "size-4", "aria-hidden": true })
                        }
                      ),
                      allowRuntimeOverride && modelProviders.length > 0 ? /* @__PURE__ */ jsx(
                        ModelPicker,
                        {
                          agentId: agent,
                          value: effectiveModelPickerValue,
                          onChange: handleModelPickerChange,
                          availableProviders: modelProviders,
                          disabled: isBusy,
                          compact: isCompactFooter,
                          defaultLabel: modelDefaultLabel,
                          className: "shrink-0"
                        }
                      ) : null,
                      /* @__PURE__ */ jsx("p", { className: cn("text-xs text-muted-foreground", isCompactFooter && "hidden"), children: hasUploadingFiles || isUploading ? t(
                        "ai_assistant.chat.uploadingHint",
                        "Uploading attachments\u2026 Send is disabled until they finish."
                      ) : t(
                        "ai_assistant.chat.shortcutHint",
                        "Press Enter to send, Shift+Enter for new line."
                      ) })
                    ] }),
                    /* @__PURE__ */ jsxs("div", { className: "flex shrink-0 items-center gap-2", children: [
                      isStreaming ? /* @__PURE__ */ jsx(
                        IconButton,
                        {
                          type: "button",
                          variant: "outline",
                          size: "sm",
                          onClick: () => chat.cancel(),
                          "aria-label": t("ai_assistant.chat.cancel", "Cancel streaming response"),
                          children: /* @__PURE__ */ jsx(Square, { className: "size-4", "aria-hidden": true })
                        }
                      ) : null,
                      /* @__PURE__ */ jsxs(
                        Button,
                        {
                          type: "submit",
                          size: "sm",
                          disabled: isBusy || isUploading || hasUploadingFiles || input.trim().length === 0,
                          "aria-label": hasUploadingFiles || isUploading ? t("ai_assistant.chat.sendWaitingForUpload", "Waiting for upload to finish\u2026") : t("ai_assistant.chat.send", "Send message"),
                          title: hasUploadingFiles || isUploading ? t("ai_assistant.chat.sendWaitingForUpload", "Waiting for upload to finish\u2026") : void 0,
                          className: cn(isCompactFooter && "w-8 px-0"),
                          children: [
                            /* @__PURE__ */ jsx(Send, { className: "size-4", "aria-hidden": true }),
                            !isCompactFooter ? /* @__PURE__ */ jsx("span", { children: t("ai_assistant.chat.send", "Send message") }) : null
                          ]
                        }
                      )
                    ] })
                  ]
                }
              )
            ]
          }
        ),
        debug ? /* @__PURE__ */ jsx(
          AiChatDebugPanel,
          {
            tools: debugTools,
            promptSections: debugPromptSections,
            loopTrace: loopTrace ?? chat.lastLoopTrace ?? void 0,
            lastRequestDebug: chat.lastRequestDebug,
            lastResponseDebug: chat.lastResponseDebug,
            status: chat.status,
            errorCode: chat.error?.code
          }
        ) : null
      ]
    }
  );
}
function AiChatDebugPanel({
  tools,
  promptSections,
  loopTrace,
  lastRequestDebug,
  lastResponseDebug,
  status,
  errorCode
}) {
  const t = useT();
  return /* @__PURE__ */ jsxs(
    "div",
    {
      className: "flex flex-col gap-2 rounded-md border border-border bg-muted/60 p-2 text-xs",
      "data-ai-chat-debug": "true",
      children: [
        /* @__PURE__ */ jsx("div", { className: "font-semibold", children: t("ai_assistant.chat.debug.panelTitle", "Debug panel") }),
        loopTrace ? /* @__PURE__ */ jsx(LoopTracePanel, { trace: loopTrace }) : null,
        /* @__PURE__ */ jsxs("details", { className: "rounded border border-border bg-background", "data-ai-chat-debug-section": "tools", open: true, children: [
          /* @__PURE__ */ jsxs("summary", { className: "cursor-pointer px-2 py-1 font-semibold", children: [
            t("ai_assistant.chat.debug.toolsSection", "Resolved tools"),
            tools ? /* @__PURE__ */ jsxs("span", { className: "ml-2 font-mono text-muted-foreground", children: [
              "(",
              tools.length,
              ")"
            ] }) : null
          ] }),
          /* @__PURE__ */ jsx("div", { className: "px-2 pb-2", children: tools && tools.length > 0 ? /* @__PURE__ */ jsx("ul", { className: "flex flex-col gap-1", "data-ai-chat-debug-tools": true, children: tools.map((tool) => /* @__PURE__ */ jsxs(
            "li",
            {
              className: "flex flex-col rounded border border-border bg-muted/40 px-2 py-1",
              "data-ai-chat-debug-tool": tool.name,
              children: [
                /* @__PURE__ */ jsx("span", { className: "font-mono", children: tool.name }),
                tool.displayName ? /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: tool.displayName }) : null,
                /* @__PURE__ */ jsxs("span", { className: "mt-1 flex flex-wrap gap-2 text-muted-foreground", children: [
                  /* @__PURE__ */ jsx("span", { children: tool.isMutation ? t("ai_assistant.chat.debug.toolMutation", "mutation") : t("ai_assistant.chat.debug.toolRead", "read") }),
                  tool.requiredFeatures && tool.requiredFeatures.length > 0 ? /* @__PURE__ */ jsxs("span", { className: "font-mono", children: [
                    "[",
                    tool.requiredFeatures.join(", "),
                    "]"
                  ] }) : /* @__PURE__ */ jsx("span", { children: t("ai_assistant.chat.debug.toolNoFeatures", "no required features") })
                ] })
              ]
            },
            tool.name
          )) }) : /* @__PURE__ */ jsx("p", { className: "text-muted-foreground", children: t(
            "ai_assistant.chat.debug.toolsEmpty",
            "No tools resolved for this agent yet."
          ) }) })
        ] }),
        /* @__PURE__ */ jsxs(
          "details",
          {
            className: "rounded border border-border bg-background",
            "data-ai-chat-debug-section": "promptSections",
            children: [
              /* @__PURE__ */ jsxs("summary", { className: "cursor-pointer px-2 py-1 font-semibold", children: [
                t("ai_assistant.chat.debug.promptSection", "Prompt sections"),
                promptSections ? /* @__PURE__ */ jsxs("span", { className: "ml-2 font-mono text-muted-foreground", children: [
                  "(",
                  promptSections.length,
                  ")"
                ] }) : null
              ] }),
              /* @__PURE__ */ jsx("div", { className: "px-2 pb-2", children: promptSections && promptSections.length > 0 ? /* @__PURE__ */ jsx("ul", { className: "flex flex-col gap-1", "data-ai-chat-debug-prompt-sections": true, children: promptSections.map((section) => /* @__PURE__ */ jsxs(
                "li",
                {
                  className: "rounded border border-border bg-muted/40 px-2 py-1",
                  "data-ai-chat-debug-prompt-section-id": section.id,
                  children: [
                    /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2", children: [
                      /* @__PURE__ */ jsx("span", { className: "font-mono", children: section.id }),
                      /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: section.source === "override" ? t("ai_assistant.chat.debug.promptOverride", "override") : section.source === "placeholder" ? t("ai_assistant.chat.debug.promptPlaceholder", "placeholder") : t("ai_assistant.chat.debug.promptDefault", "default") })
                    ] }),
                    section.text ? /* @__PURE__ */ jsx("pre", { className: "mt-1 max-h-24 overflow-auto whitespace-pre-wrap font-mono text-muted-foreground", children: section.text }) : null
                  ]
                },
                section.id
              )) }) : /* @__PURE__ */ jsx("p", { className: "text-muted-foreground", children: t(
                "ai_assistant.chat.debug.promptEmpty",
                "No prompt sections resolved for this agent."
              ) }) })
            ]
          }
        ),
        /* @__PURE__ */ jsxs(
          "details",
          {
            className: "rounded border border-border bg-background",
            "data-ai-chat-debug-section": "lastRequest",
            children: [
              /* @__PURE__ */ jsx("summary", { className: "cursor-pointer px-2 py-1 font-semibold", children: t("ai_assistant.chat.debug.lastRequestSection", "Last request") }),
              /* @__PURE__ */ jsx("div", { className: "px-2 pb-2", children: lastRequestDebug ? /* @__PURE__ */ jsx(
                "pre",
                {
                  className: "max-h-40 overflow-auto whitespace-pre-wrap font-mono",
                  "data-ai-chat-debug-last-request": true,
                  children: JSON.stringify(lastRequestDebug, null, 2)
                }
              ) : /* @__PURE__ */ jsx("p", { className: "text-muted-foreground", children: t(
                "ai_assistant.chat.debug.lastRequestEmpty",
                "No request has been sent yet."
              ) }) })
            ]
          }
        ),
        /* @__PURE__ */ jsxs(
          "details",
          {
            className: "rounded border border-border bg-background",
            "data-ai-chat-debug-section": "lastResponse",
            children: [
              /* @__PURE__ */ jsx("summary", { className: "cursor-pointer px-2 py-1 font-semibold", children: t("ai_assistant.chat.debug.lastResponseSection", "Last response") }),
              /* @__PURE__ */ jsx("div", { className: "px-2 pb-2", children: lastResponseDebug ? /* @__PURE__ */ jsx(
                "pre",
                {
                  className: "max-h-40 overflow-auto whitespace-pre-wrap font-mono",
                  "data-ai-chat-debug-last-response": true,
                  children: JSON.stringify(
                    { status: lastResponseDebug.status, text: lastResponseDebug.text, errorCode },
                    null,
                    2
                  )
                }
              ) : /* @__PURE__ */ jsx("p", { className: "text-muted-foreground", children: t(
                "ai_assistant.chat.debug.lastResponseEmpty",
                "No response received yet."
              ) }) })
            ]
          }
        ),
        /* @__PURE__ */ jsxs("div", { className: "text-muted-foreground", "data-ai-chat-debug-status": status, children: [
          t("ai_assistant.chat.debug.statusLabel", "Status:"),
          " ",
          /* @__PURE__ */ jsx("span", { className: "font-mono", children: status })
        ] })
      ]
    }
  );
}
var AiChat_default = AiChat;
export {
  AiChat,
  AiChat_default as default
};
//# sourceMappingURL=AiChat.js.map
