/* Copyright 2026 Marimo. All rights reserved. */ import { type DOMNode, Element, Text } from "html-react-parser"; import { useAtomValue } from "jotai"; import { BugPlayIcon, ChevronDown, CopyIcon, ExternalLinkIcon, MessageCircleIcon, SearchIcon, } from "lucide-react"; import { type JSX, useState } from "react"; import { Accordion, AccordionContent, AccordionItem, } from "@/components/ui/accordion"; import { Button } from "@/components/ui/button"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import { Kbd } from "@/components/ui/kbd"; import { Tooltip } from "@/components/ui/tooltip"; import { getCellEditorView } from "@/core/cells/cells"; import type { CellId } from "@/core/cells/ids"; import { SCRATCH_CELL_ID } from "@/core/cells/ids"; import { insertDebuggerAtLine } from "@/core/codemirror/editing/debugging"; import { aiEnabledAtom } from "@/core/config/config"; import { getRequestClient } from "@/core/network/requests"; import { isStaticNotebook } from "@/core/static/static-state"; import { isWasm } from "@/core/wasm/utils"; import { renderHTML } from "@/plugins/core/RenderHTML"; import { sanitizeHtml } from "@/plugins/core/sanitize-html"; import { copyToClipboard } from "@/utils/copy"; import { elementContainsMarimoCellFile, extractAllTracebackInfo, getTracebackInfo, } from "@/utils/traceback"; import { cn } from "../../../utils/cn"; import { AIFixButton } from "../errors/auto-fix"; import { CellLinkTraceback } from "../links/cell-link"; import type { OnRefactorWithAI } from "../Output"; interface Props { cellId: CellId | undefined; traceback: string; onRefactorWithAI?: OnRefactorWithAI; } const KEY = "item"; /** * List of errors due to violations of Marimo semantics. */ export const MarimoTracebackOutput = ({ onRefactorWithAI, traceback, cellId, }: Props): JSX.Element => { const htmlTraceback = renderHTML({ html: traceback, additionalReplacements: [replaceTracebackFilenames, replaceTracebackPrefix], }); const [expanded, setExpanded] = useState(true); const lastTracebackLine = lastLine(traceback); const aiEnabled = useAtomValue(aiEnabledAtom); // Get last traceback info const tracebackInfo = extractAllTracebackInfo(traceback)?.at(0); // Don't show in wasm, static notebooks, or scratchpad const showDebugger = tracebackInfo && tracebackInfo.kind === "cell" && !isWasm() && !isStaticNotebook() && cellId !== SCRATCH_CELL_ID; const showAIFix = onRefactorWithAI && aiEnabled && !isStaticNotebook(); const showSearch = !isStaticNotebook(); const handleRefactorWithAI = (triggerImmediately: boolean) => { onRefactorWithAI?.({ prompt: `My code gives the following error:\n\n${lastTracebackLine}`, triggerImmediately, }); }; const [error, errorMessage] = lastTracebackLine.split(":", 2); return (