@marimo-team/islands 0.25.3-dev266 → 0.25.3-dev267
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{ConnectedDataExplorerComponent-C_hj7Poi.js → ConnectedDataExplorerComponent-C4yCN38h.js} +1 -1
- package/dist/{ErrorBoundary-CvxlC3F1.js → ErrorBoundary-CewXPyL5.js} +64 -69
- package/dist/{abnfDiagram-VCTEODGH-DzrZZXRD.js → abnfDiagram-VCTEODGH-o6Ay6Q63.js} +2 -2
- package/dist/{any-language-editor-CFeWfC3o.js → any-language-editor-DnG26QXh.js} +1 -1
- package/dist/{architectureDiagram-5GKGNRK7-iF_snyFL.js → architectureDiagram-5GKGNRK7-BhiwwlVg.js} +1 -1
- package/dist/{chat-ui-DFxNgzXF.js → chat-ui-CbgR5ivy.js} +1964 -1740
- package/dist/{chunk-IMKFNOWR-B7xytD4B.js → chunk-IMKFNOWR-WMSMf4Nj.js} +1 -1
- package/dist/{chunk-SHT3W25Y-I8ZFP5L1.js → chunk-SHT3W25Y-BRfADrzD.js} +1 -1
- package/dist/{chunk-SVP7TREG-Di-uAPdT.js → chunk-SVP7TREG-CuK5QFre.js} +1 -1
- package/dist/{chunk-TICWLB2K-BFpUy0ud.js → chunk-TICWLB2K-Bcun_jhJ.js} +1 -1
- package/dist/{classDiagram-ZZMXUADV-Cqm4JGpx.js → classDiagram-ZZMXUADV-CgWDbUDT.js} +2 -2
- package/dist/{classDiagram-v2-VYDZK3BY-DFHRJpN3.js → classDiagram-v2-VYDZK3BY-DYmc9SFU.js} +2 -2
- package/dist/{code-visibility-SRM1JiD_.js → code-visibility-BKBl9Rh6.js} +9 -9
- package/dist/{common-yiRhZ6ZZ.js → common-N3Jd_6m9.js} +5944 -5626
- package/dist/{cynefinDiagram-5FMLGOSQ-cuGOeTBC.js → cynefinDiagram-5FMLGOSQ-PPKWipjT.js} +1 -1
- package/dist/{dagre-GXQ25YYZ-DJ76aC4k.js → dagre-GXQ25YYZ-niRBZh--.js} +1 -1
- package/dist/{data-grid-overlay-editor-DLTzcQ4O.js → data-grid-overlay-editor-Cp59CrqZ.js} +1 -1
- package/dist/{diagram-S7CK7UJ4-DLLc0sw7.js → diagram-S7CK7UJ4-DPiP9rot.js} +1 -1
- package/dist/{diagram-UQ7AKVKN-Tz_d6qmk.js → diagram-UQ7AKVKN-B0WZuaxV.js} +1 -1
- package/dist/{diagram-VX7I27RA-D7SzPrDN.js → diagram-VX7I27RA-Rn42WBuN.js} +1 -1
- package/dist/{diagram-Z3DM3KII-qr37XV58.js → diagram-Z3DM3KII-BB93--ry.js} +1 -1
- package/dist/{dropdown-menu-CkJ7ErY6.js → dropdown-menu-BpImEfn3.js} +1211 -1205
- package/dist/{ebnfDiagram-PWID7BFC-BKOQb4J0.js → ebnfDiagram-PWID7BFC-V4t5h6mZ.js} +2 -2
- package/dist/{erDiagram-RLTQ6QDP-CM15Vq68.js → erDiagram-RLTQ6QDP-C1MsAKXd.js} +1 -1
- package/dist/{error-banner-DbRFOd2O.js → error-banner-DPc9eIw5.js} +3 -3
- package/dist/{error-entries-CMoaUX9V.js → error-entries-CJGdD2ky.js} +49 -42
- package/dist/{feedback-button-DBUrE4OL.js → feedback-button-Qc1f9iPq.js} +70 -70
- package/dist/{flowDiagram-HODETNUW-Dt3N5yFT.js → flowDiagram-HODETNUW-DHjeJP96.js} +2 -2
- package/dist/{glide-data-editor-Cfv4HeOh.js → glide-data-editor-hCq3K0sd.js} +2042 -2041
- package/dist/{glide-utils-Ba9WD2IN.js → glide-utils-DC3sk6EX.js} +28 -34
- package/dist/{globals-dIbBIR5-.js → globals-B2_uMYDY.js} +1 -1
- package/dist/{html-to-image-D_5CMreP.js → html-to-image-S7spRQCi.js} +5526 -5828
- package/dist/{infoDiagram-27XIBGKW-C7axJMCl.js → infoDiagram-27XIBGKW-Dovv6iKx.js} +1 -1
- package/dist/{ishikawaDiagram-5VMMS53U-CdC9Eur7.js → ishikawaDiagram-5VMMS53U-D2nyygsc.js} +1 -1
- package/dist/{kanban-definition-UXKFOSKX-BHnMIgD7.js → kanban-definition-UXKFOSKX-KyVx0uTY.js} +1 -1
- package/dist/main.js +1288 -1287
- package/dist/{mermaid-DFYN_PXd.js → mermaid-B-jKSwGt.js} +33 -33
- package/dist/{mindmap-definition-YA3MSWOX-BagHoCGU.js → mindmap-definition-YA3MSWOX-Bz9tKQFl.js} +1 -1
- package/dist/{number-overlay-editor-CTiJp5Mj.js → number-overlay-editor-CfNYvbdz.js} +1 -1
- package/dist/{pegDiagram-XKGWAZYB-8IIZczip.js → pegDiagram-XKGWAZYB-C_qpq6Tv.js} +2 -2
- package/dist/pencil-DcT8AE0h.js +10 -0
- package/dist/{pieDiagram-E7YTZNPT-CE6dKBIr.js → pieDiagram-E7YTZNPT-Bp9ucgI4.js} +1 -1
- package/dist/{process-output-CGFNVC60.js → process-output-f34bkXTm.js} +2 -2
- package/dist/{railroadDiagram-O6MQD6OU-CkexPq3b.js → railroadDiagram-O6MQD6OU-tq-VEH6j.js} +2 -2
- package/dist/{requirementDiagram-BXWQKSXE-B0-OkuAe.js → requirementDiagram-BXWQKSXE-DW-vHadb.js} +1 -1
- package/dist/{reveal-component-DH09ygHo.js → reveal-component-CUxv-kkP.js} +9 -9
- package/dist/{sequenceDiagram-WJ2MYXX4-Dxysg8DX.js → sequenceDiagram-WJ2MYXX4-Dv9U9qRP.js} +1 -1
- package/dist/{stateDiagram-D77RDMKH-DTEN3-OJ.js → stateDiagram-D77RDMKH-DTmPQ0EB.js} +2 -2
- package/dist/{stateDiagram-v2-MP3YSRHH-vktk3Xc5.js → stateDiagram-v2-MP3YSRHH-CkCif0Iw.js} +2 -2
- package/dist/style.css +1 -1
- package/dist/{swimlanes-42K2YHIH-Cjveh9OM.js → swimlanes-42K2YHIH-21kCq6l8.js} +1 -1
- package/dist/{swimlanesDiagram-VR7AAH4N-Bdr7Ev_2.js → swimlanesDiagram-VR7AAH4N-BpRJP6KU.js} +2 -2
- package/dist/{timeline-definition-24CTP7MA-KIuDcefn.js → timeline-definition-24CTP7MA-Ckgh4lS4.js} +1 -1
- package/dist/{toast-CY1_Qv41.js → toast-DpczUryP.js} +1 -1
- package/dist/{vega-component-C-lqjV0q.js → vega-component-CF9kI6C4.js} +1 -1
- package/dist/{vennDiagram-4TSXK5OY-DrIOUHfb.js → vennDiagram-4TSXK5OY-CDei2Bt3.js} +1 -1
- package/dist/{wardleyDiagram-VM6X3IG4-CJNjf4OH.js → wardleyDiagram-VM6X3IG4-CXavT601.js} +1 -1
- package/dist/{xychartDiagram-S5SC5T6Z-DEshFho-.js → xychartDiagram-S5SC5T6Z-CvJhcZri.js} +1 -1
- package/package.json +1 -1
- package/src/components/chat/__tests__/chat-display.test.tsx +157 -86
- package/src/components/chat/__tests__/chat-utils.test.ts +42 -0
- package/src/components/chat/__tests__/turn-timing.test.ts +84 -0
- package/src/components/chat/__tests__/use-assistant-turn.test.ts +95 -0
- package/src/components/chat/__tests__/user-message.test.tsx +27 -0
- package/src/components/chat/acp/agent-panel.tsx +2 -0
- package/src/components/chat/agent-activity.tsx +132 -0
- package/src/components/chat/chat-display.tsx +125 -96
- package/src/components/chat/chat-panel.tsx +123 -106
- package/src/components/chat/chat-utils.ts +12 -24
- package/src/components/chat/tool-call/__tests__/tool-labels.test.ts +76 -0
- package/src/components/chat/tool-call/__tests__/tool-step.test.tsx +57 -0
- package/src/components/chat/tool-call/shared.ts +6 -0
- package/src/components/chat/tool-call/tool-call-view.tsx +22 -76
- package/src/components/chat/tool-call/tool-labels.ts +172 -0
- package/src/components/chat/tool-call/tool-step.tsx +145 -0
- package/src/components/chat/turn-timing.ts +73 -0
- package/src/components/chat/use-assistant-turn.ts +65 -0
- package/src/components/chat/use-chat-generation.ts +5 -4
- package/src/components/chat/user-message.tsx +145 -0
- package/src/components/editor/actions/__tests__/useCellActionButton.test.tsx +18 -1
- package/src/components/editor/actions/useCellActionButton.tsx +3 -0
- package/src/components/editor/ai/completion-handlers.tsx +0 -37
- package/src/components/editor/cell/StagedAICell.tsx +51 -144
- package/src/components/editor/chrome/wrapper/__tests__/pending-ai-cells.test.tsx +193 -32
- package/src/components/editor/chrome/wrapper/app-chrome.tsx +2 -2
- package/src/components/editor/chrome/wrapper/pending-ai-cells.tsx +145 -81
- package/src/components/editor/chrome/wrapper/pending-ai-changes-badge.tsx +25 -0
- package/src/components/editor/chrome/wrapper/sidebar.tsx +6 -0
- package/src/components/editor/links/cell-link.tsx +4 -4
- package/src/components/editor/notebook-cell.tsx +3 -11
- package/src/components/ui/toast.tsx +1 -1
- package/src/core/ai/__tests__/staged-cells.test.ts +74 -126
- package/src/core/ai/staged-cells.ts +48 -38
- package/src/core/cells/scrollCellIntoView.ts +6 -0
- package/src/core/codemirror/placeholder/__tests__/extensions.test.ts +59 -0
- package/src/core/codemirror/placeholder/extensions.ts +23 -0
- package/src/core/session/__tests__/useNotebookSession.hook.test.tsx +34 -0
- package/src/core/session/useNotebookSession.tsx +7 -2
- package/src/css/app/Cell.css +7 -36
- package/src/plugins/impl/chat/chat-ui.tsx +2 -3
- package/src/plugins/impl/common/error-banner.tsx +5 -3
- package/src/components/chat/reasoning-accordion.tsx +0 -61
- package/src/components/chat/tool-call/tool-activity-group.tsx +0 -49
- package/src/components/chat/tool-call/tool-error-card.tsx +0 -81
- package/src/components/chat/tool-call/tool-history-row.tsx +0 -147
- package/src/components/icons/loading-ellipsis.tsx +0 -46
package/src/css/app/Cell.css
CHANGED
|
@@ -27,20 +27,9 @@
|
|
|
27
27
|
outline: none;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
&:has(.mo-ai-generated-cell) {
|
|
31
|
-
border-color: var(--blue-7);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
30
|
/* Styling for cells marked for deletion by AI */
|
|
35
31
|
&:has(.mo-ai-deleted-cell) {
|
|
36
|
-
|
|
37
|
-
border-color: var(--red-7);
|
|
38
|
-
|
|
39
|
-
.output-area,
|
|
40
|
-
.cm-gutters,
|
|
41
|
-
.cm {
|
|
42
|
-
background-color: var(--red-2);
|
|
43
|
-
}
|
|
32
|
+
box-shadow: -2px 0 0 var(--red-7);
|
|
44
33
|
|
|
45
34
|
/* Add strikethrough effect to the code */
|
|
46
35
|
.cm-content {
|
|
@@ -218,14 +207,18 @@
|
|
|
218
207
|
|
|
219
208
|
/* Focus state */
|
|
220
209
|
|
|
221
|
-
&.focus-outline
|
|
222
|
-
|
|
210
|
+
&.focus-outline,
|
|
211
|
+
&[data-ai-review-selected] {
|
|
223
212
|
border-color: var(--blue-8) !important;
|
|
224
213
|
|
|
225
214
|
/* custom shadow until our theme overrides can support colored shadow */
|
|
226
215
|
@apply shadow-lg shadow-[var(--blue-8)];
|
|
227
216
|
}
|
|
228
217
|
|
|
218
|
+
&.focus-outline {
|
|
219
|
+
transition: all 0.6s;
|
|
220
|
+
}
|
|
221
|
+
|
|
229
222
|
/* Published - when its just the output */
|
|
230
223
|
|
|
231
224
|
&.published {
|
|
@@ -303,20 +296,6 @@
|
|
|
303
296
|
@apply bg-background;
|
|
304
297
|
}
|
|
305
298
|
|
|
306
|
-
.mo-ai-cell-footer {
|
|
307
|
-
display: flex;
|
|
308
|
-
align-items: center;
|
|
309
|
-
justify-content: space-between;
|
|
310
|
-
gap: 0.75rem;
|
|
311
|
-
width: 100%;
|
|
312
|
-
padding: 0.375rem 0.5rem;
|
|
313
|
-
background: var(--gray-2);
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
.dark .mo-ai-cell-footer {
|
|
317
|
-
background: var(--gray-3);
|
|
318
|
-
}
|
|
319
|
-
|
|
320
299
|
.dark .marimo-cell {
|
|
321
300
|
@apply border-border;
|
|
322
301
|
|
|
@@ -355,14 +334,6 @@
|
|
|
355
334
|
}
|
|
356
335
|
}
|
|
357
336
|
|
|
358
|
-
.dark .marimo-cell:has(.mo-ai-generated-cell) {
|
|
359
|
-
border-color: var(--blue-8);
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
.dark .marimo-cell:has(.mo-ai-deleted-cell) {
|
|
363
|
-
border-color: var(--red-8);
|
|
364
|
-
}
|
|
365
|
-
|
|
366
337
|
#cell-setup,
|
|
367
338
|
#cell-setup .cm-editor,
|
|
368
339
|
#cell-setup .cm-gutter {
|
|
@@ -482,12 +482,11 @@ export const Chatbot: React.FC<Props> = (props) => {
|
|
|
482
482
|
className={`max-w-[80%] p-3 rounded-lg ${
|
|
483
483
|
message.role === "user"
|
|
484
484
|
? "bg-(--sky-11) text-(--slate-1) whitespace-pre-wrap"
|
|
485
|
-
: "bg-(--slate-4) text-(--slate-12)"
|
|
485
|
+
: "bg-(--slate-4) text-(--slate-12) [--muted-foreground:var(--slate-11)]"
|
|
486
486
|
}`}
|
|
487
487
|
>
|
|
488
488
|
{renderUIMessage({
|
|
489
489
|
message,
|
|
490
|
-
isStreamingReasoning: status === "streaming",
|
|
491
490
|
isLast,
|
|
492
491
|
isActive: isLoading,
|
|
493
492
|
addToolApprovalResponse: isLast
|
|
@@ -514,7 +513,7 @@ export const Chatbot: React.FC<Props> = (props) => {
|
|
|
514
513
|
);
|
|
515
514
|
})}
|
|
516
515
|
|
|
517
|
-
{isLoading && (
|
|
516
|
+
{isLoading && messages.at(-1)?.role !== "assistant" && (
|
|
518
517
|
<div className="flex items-center justify-center mb-4">
|
|
519
518
|
<Spinner size="small" />
|
|
520
519
|
</div>
|
|
@@ -47,11 +47,13 @@ export const ErrorBanner = ({
|
|
|
47
47
|
<AlertDialog open={open} onOpenChange={setOpen}>
|
|
48
48
|
<AlertDialogContent className="max-w-[80%] max-h-[80%] overflow-hidden flex flex-col">
|
|
49
49
|
<AlertDialogHeader>
|
|
50
|
-
<AlertDialogTitle className="text-
|
|
50
|
+
<AlertDialogTitle className="text-(--red-11)">
|
|
51
|
+
Error
|
|
52
|
+
</AlertDialogTitle>
|
|
51
53
|
</AlertDialogHeader>
|
|
52
54
|
<AlertDialogDescription
|
|
53
55
|
asChild={true}
|
|
54
|
-
className="text-
|
|
56
|
+
className="text-(--red-11) text-sm p-2 font-mono overflow-auto whitespace-pre-wrap"
|
|
55
57
|
>
|
|
56
58
|
<pre>{message}</pre>
|
|
57
59
|
</AlertDialogDescription>
|
|
@@ -72,7 +74,7 @@ const bannerStyle = cva(
|
|
|
72
74
|
variants: {
|
|
73
75
|
kind: {
|
|
74
76
|
danger:
|
|
75
|
-
"text-
|
|
77
|
+
"text-(--red-11) border-(--red-6) shadow-md-solid shadow-error bg-(--red-1)",
|
|
76
78
|
info: "text-primary border-(--blue-6) shadow-md-solid shadow-accent bg-(--blue-1)",
|
|
77
79
|
warn: "border-(--yellow-6) bg-(--yellow-2) dark:bg-(--yellow-4) text-(--yellow-11) dark:text-(--yellow-12)",
|
|
78
80
|
},
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
|
-
|
|
3
|
-
import { BotMessageSquareIcon } from "lucide-react";
|
|
4
|
-
import React from "react";
|
|
5
|
-
import { ChatMarkdown } from "./chat-markdown";
|
|
6
|
-
import {
|
|
7
|
-
Accordion,
|
|
8
|
-
AccordionContent,
|
|
9
|
-
AccordionItem,
|
|
10
|
-
AccordionTrigger,
|
|
11
|
-
} from "@/components/ui/accordion";
|
|
12
|
-
|
|
13
|
-
interface ReasoningAccordionProps {
|
|
14
|
-
reasoning: string;
|
|
15
|
-
index?: number;
|
|
16
|
-
isStreaming?: boolean;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export const ReasoningAccordion: React.FC<ReasoningAccordionProps> = ({
|
|
20
|
-
reasoning,
|
|
21
|
-
index = 0,
|
|
22
|
-
isStreaming = false,
|
|
23
|
-
}) => {
|
|
24
|
-
const [openItem, setOpenItem] = React.useState<string>("");
|
|
25
|
-
|
|
26
|
-
// Some reasoning models emit a reasoning part with no surfaced content
|
|
27
|
-
// (e.g. OpenAI's o-series, which hides chain-of-thought but still marks
|
|
28
|
-
// its boundaries on the wire). pydantic-ai's Vercel adapter forwards the
|
|
29
|
-
// empty start/end pair, producing a 0-char ReasoningUIPart. Skip it.
|
|
30
|
-
if (!reasoning && !isStreaming) {
|
|
31
|
-
return null;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
return (
|
|
35
|
-
<Accordion
|
|
36
|
-
key={index}
|
|
37
|
-
type="single"
|
|
38
|
-
collapsible={true}
|
|
39
|
-
className="w-full mb-2"
|
|
40
|
-
value={isStreaming ? "reasoning" : openItem}
|
|
41
|
-
onValueChange={setOpenItem}
|
|
42
|
-
>
|
|
43
|
-
<AccordionItem value="reasoning" className="border-0">
|
|
44
|
-
<AccordionTrigger className="text-xs text-muted-foreground hover:bg-muted/50 px-2 py-1 h-auto rounded-sm [&[data-state=open]>svg]:rotate-180">
|
|
45
|
-
<span className="flex items-center gap-2">
|
|
46
|
-
<BotMessageSquareIcon className="h-3 w-3" />
|
|
47
|
-
{isStreaming ? "Thinking" : "View reasoning"}
|
|
48
|
-
{reasoning.length > 0 && ` (${reasoning.length} chars)`}
|
|
49
|
-
</span>
|
|
50
|
-
</AccordionTrigger>
|
|
51
|
-
<AccordionContent className="pb-2 px-2">
|
|
52
|
-
<div className="bg-muted/30 border border-muted/50 rounded-md p-3 text-muted-foreground relative">
|
|
53
|
-
<div className="pr-6">
|
|
54
|
-
<ChatMarkdown content={reasoning} />
|
|
55
|
-
</div>
|
|
56
|
-
</div>
|
|
57
|
-
</AccordionContent>
|
|
58
|
-
</AccordionItem>
|
|
59
|
-
</Accordion>
|
|
60
|
-
);
|
|
61
|
-
};
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
|
-
|
|
3
|
-
import type { PropsWithChildren } from "react";
|
|
4
|
-
import {
|
|
5
|
-
Accordion,
|
|
6
|
-
AccordionContent,
|
|
7
|
-
AccordionItem,
|
|
8
|
-
AccordionTrigger,
|
|
9
|
-
} from "@/components/ui/accordion";
|
|
10
|
-
import { formatToolName, type ToolState } from "./shared";
|
|
11
|
-
|
|
12
|
-
interface ToolActivity {
|
|
13
|
-
toolName: string;
|
|
14
|
-
state: ToolState;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export function ToolActivityGroup({
|
|
18
|
-
tools,
|
|
19
|
-
isActive,
|
|
20
|
-
children,
|
|
21
|
-
}: PropsWithChildren<{ tools: ToolActivity[]; isActive: boolean }>) {
|
|
22
|
-
const pending = tools.some((tool) => tool.state !== "output-available");
|
|
23
|
-
const editing = tools.every(
|
|
24
|
-
(tool) => formatToolName(tool.toolName) === "edit_notebook_tool",
|
|
25
|
-
);
|
|
26
|
-
const count = tools.length;
|
|
27
|
-
const label = pending
|
|
28
|
-
? isActive
|
|
29
|
-
? editing
|
|
30
|
-
? "Editing notebook…"
|
|
31
|
-
: "Working…"
|
|
32
|
-
: "Stopped before completing all steps"
|
|
33
|
-
: editing
|
|
34
|
-
? `Edited notebook · ${count} ${count === 1 ? "operation" : "operations"}`
|
|
35
|
-
: `Completed ${count} ${count === 1 ? "step" : "steps"}`;
|
|
36
|
-
|
|
37
|
-
return (
|
|
38
|
-
<Accordion type="single" collapsible={true} className="my-1 w-full">
|
|
39
|
-
<AccordionItem value="activity" className="border-0">
|
|
40
|
-
<AccordionTrigger className="h-auto pl-0 pr-2 py-1 gap-2 rounded text-xs font-normal text-muted-foreground hover:bg-(--slate-2) hover:text-foreground hover:no-underline">
|
|
41
|
-
{label}
|
|
42
|
-
</AccordionTrigger>
|
|
43
|
-
<AccordionContent className="pb-2 pl-3 border-l border-border">
|
|
44
|
-
{children}
|
|
45
|
-
</AccordionContent>
|
|
46
|
-
</AccordionItem>
|
|
47
|
-
</Accordion>
|
|
48
|
-
);
|
|
49
|
-
}
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
|
-
|
|
3
|
-
import { ChevronDownIcon, XCircleIcon } from "lucide-react";
|
|
4
|
-
import React from "react";
|
|
5
|
-
import { cn } from "@/utils/cn";
|
|
6
|
-
import { formatToolName } from "./shared";
|
|
7
|
-
import { ToolArgsRenderer } from "./tool-args";
|
|
8
|
-
|
|
9
|
-
interface ToolErrorCardProps {
|
|
10
|
-
toolName: string;
|
|
11
|
-
input: unknown;
|
|
12
|
-
errorText?: string;
|
|
13
|
-
// When false, defaults to collapsed (the conversation has moved past this).
|
|
14
|
-
isLive: boolean;
|
|
15
|
-
className?: string;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export const ToolErrorCard: React.FC<ToolErrorCardProps> = ({
|
|
19
|
-
toolName,
|
|
20
|
-
input,
|
|
21
|
-
errorText,
|
|
22
|
-
isLive,
|
|
23
|
-
className,
|
|
24
|
-
}) => {
|
|
25
|
-
const [open, setOpen] = React.useState(isLive);
|
|
26
|
-
|
|
27
|
-
// Auto-collapse once when the conversation moves past this turn.
|
|
28
|
-
// The user can still re-open manually afterwards; we only do this on the
|
|
29
|
-
// live → not-live transition, never the reverse.
|
|
30
|
-
const wasLive = React.useRef(isLive);
|
|
31
|
-
React.useEffect(() => {
|
|
32
|
-
if (wasLive.current && !isLive) {
|
|
33
|
-
setOpen(false);
|
|
34
|
-
}
|
|
35
|
-
wasLive.current = isLive;
|
|
36
|
-
}, [isLive]);
|
|
37
|
-
|
|
38
|
-
return (
|
|
39
|
-
<div
|
|
40
|
-
className={cn(
|
|
41
|
-
"rounded-md border border-(--red-6) bg-(--red-2)",
|
|
42
|
-
className,
|
|
43
|
-
)}
|
|
44
|
-
>
|
|
45
|
-
<button
|
|
46
|
-
type="button"
|
|
47
|
-
onClick={() => setOpen((prev) => !prev)}
|
|
48
|
-
className="w-full flex items-center gap-2 px-3 py-2 text-xs text-(--red-11) hover:bg-(--red-3) rounded-md transition-colors"
|
|
49
|
-
aria-expanded={open}
|
|
50
|
-
>
|
|
51
|
-
<XCircleIcon className="h-3.5 w-3.5 shrink-0" />
|
|
52
|
-
<span className="flex-1 text-left">
|
|
53
|
-
<span className="font-semibold">Failed:</span>{" "}
|
|
54
|
-
<code className="font-mono">{formatToolName(toolName)}</code>
|
|
55
|
-
</span>
|
|
56
|
-
<ChevronDownIcon
|
|
57
|
-
className={cn(
|
|
58
|
-
"h-3.5 w-3.5 shrink-0 transition-transform",
|
|
59
|
-
open && "rotate-180",
|
|
60
|
-
)}
|
|
61
|
-
/>
|
|
62
|
-
</button>
|
|
63
|
-
|
|
64
|
-
{open && (
|
|
65
|
-
<div className="px-3 pb-3 space-y-3 border-t border-(--red-6)/40 pt-3">
|
|
66
|
-
<ToolArgsRenderer input={input} />
|
|
67
|
-
{errorText && (
|
|
68
|
-
<div>
|
|
69
|
-
<h3 className="text-xs font-semibold text-(--red-11) mb-1">
|
|
70
|
-
Error
|
|
71
|
-
</h3>
|
|
72
|
-
<pre className="bg-(--red-2) border border-(--red-6) rounded p-2 text-xs text-(--red-11) leading-relaxed overflow-auto scrollbar-thin max-h-64 whitespace-pre-wrap">
|
|
73
|
-
{errorText}
|
|
74
|
-
</pre>
|
|
75
|
-
</div>
|
|
76
|
-
)}
|
|
77
|
-
</div>
|
|
78
|
-
)}
|
|
79
|
-
</div>
|
|
80
|
-
);
|
|
81
|
-
};
|
|
@@ -1,147 +0,0 @@
|
|
|
1
|
-
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
|
-
|
|
3
|
-
import { BanIcon, CircleSlashIcon, Loader2, WrenchIcon } from "lucide-react";
|
|
4
|
-
import React from "react";
|
|
5
|
-
import {
|
|
6
|
-
Accordion,
|
|
7
|
-
AccordionContent,
|
|
8
|
-
AccordionItem,
|
|
9
|
-
AccordionTrigger,
|
|
10
|
-
} from "@/components/ui/accordion";
|
|
11
|
-
import { logNever } from "@/utils/assertNever";
|
|
12
|
-
import { cn } from "@/utils/cn";
|
|
13
|
-
import { formatToolName, type ToolApproval, type ToolState } from "./shared";
|
|
14
|
-
import { ToolArgsRenderer } from "./tool-args";
|
|
15
|
-
import { ResultRenderer } from "./tool-result";
|
|
16
|
-
|
|
17
|
-
// States considered "inert" — they represent past or background work that the
|
|
18
|
-
// user does not need to act on.
|
|
19
|
-
export type HistoryState = Exclude<
|
|
20
|
-
ToolState,
|
|
21
|
-
"approval-requested" | "output-error"
|
|
22
|
-
>;
|
|
23
|
-
|
|
24
|
-
const STATUS_LABEL: Record<HistoryState, string> = {
|
|
25
|
-
"input-streaming": "Generating",
|
|
26
|
-
"input-available": "Running",
|
|
27
|
-
"approval-responded": "Awaiting result",
|
|
28
|
-
"output-available": "Done",
|
|
29
|
-
"output-denied": "Denied",
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
const PENDING_STATES = new Set<HistoryState>([
|
|
33
|
-
"input-streaming",
|
|
34
|
-
"input-available",
|
|
35
|
-
"approval-responded",
|
|
36
|
-
]);
|
|
37
|
-
|
|
38
|
-
const StatusIcon: React.FC<{ state: HistoryState; interrupted: boolean }> = ({
|
|
39
|
-
state,
|
|
40
|
-
interrupted,
|
|
41
|
-
}) => {
|
|
42
|
-
if (interrupted) {
|
|
43
|
-
return <CircleSlashIcon className="h-3 w-3 text-muted-foreground" />;
|
|
44
|
-
}
|
|
45
|
-
switch (state) {
|
|
46
|
-
case "input-streaming":
|
|
47
|
-
case "input-available":
|
|
48
|
-
case "approval-responded":
|
|
49
|
-
return <Loader2 className="h-3 w-3 animate-spin" />;
|
|
50
|
-
case "output-available":
|
|
51
|
-
return null;
|
|
52
|
-
case "output-denied":
|
|
53
|
-
return <BanIcon className="h-3 w-3 text-muted-foreground" />;
|
|
54
|
-
default:
|
|
55
|
-
logNever(state);
|
|
56
|
-
return <WrenchIcon className="h-3 w-3" />;
|
|
57
|
-
}
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
interface ToolHistoryRowProps {
|
|
61
|
-
toolName: string;
|
|
62
|
-
state: HistoryState;
|
|
63
|
-
input: unknown;
|
|
64
|
-
result?: unknown;
|
|
65
|
-
approval?: ToolApproval;
|
|
66
|
-
index?: number;
|
|
67
|
-
className?: string;
|
|
68
|
-
isActive?: boolean;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
export const ToolHistoryRow: React.FC<ToolHistoryRowProps> = ({
|
|
72
|
-
toolName,
|
|
73
|
-
state,
|
|
74
|
-
input,
|
|
75
|
-
result,
|
|
76
|
-
approval,
|
|
77
|
-
index = 0,
|
|
78
|
-
className,
|
|
79
|
-
isActive = true,
|
|
80
|
-
}) => {
|
|
81
|
-
const interrupted = !isActive && PENDING_STATES.has(state);
|
|
82
|
-
return (
|
|
83
|
-
<Accordion
|
|
84
|
-
key={`tool-${index}`}
|
|
85
|
-
type="single"
|
|
86
|
-
collapsible={true}
|
|
87
|
-
className={cn("w-full", className)}
|
|
88
|
-
>
|
|
89
|
-
<AccordionItem value="tool-call" className="border-0">
|
|
90
|
-
<AccordionTrigger className="h-auto pl-0 pr-2 py-1 gap-2 rounded text-xs font-normal text-muted-foreground hover:bg-(--slate-2) hover:text-foreground hover:no-underline">
|
|
91
|
-
<span className="flex items-center gap-1">
|
|
92
|
-
<StatusIcon state={state} interrupted={interrupted} />
|
|
93
|
-
{interrupted ? "Interrupted" : STATUS_LABEL[state]}:
|
|
94
|
-
<code className="font-mono text-xs">
|
|
95
|
-
{formatToolName(toolName)}
|
|
96
|
-
</code>
|
|
97
|
-
</span>
|
|
98
|
-
</AccordionTrigger>
|
|
99
|
-
<AccordionContent className="py-2 px-2">
|
|
100
|
-
<HistoryContent
|
|
101
|
-
state={state}
|
|
102
|
-
input={input}
|
|
103
|
-
result={result}
|
|
104
|
-
approval={approval}
|
|
105
|
-
/>
|
|
106
|
-
</AccordionContent>
|
|
107
|
-
</AccordionItem>
|
|
108
|
-
</Accordion>
|
|
109
|
-
);
|
|
110
|
-
};
|
|
111
|
-
|
|
112
|
-
const HistoryContent: React.FC<{
|
|
113
|
-
state: HistoryState;
|
|
114
|
-
input: unknown;
|
|
115
|
-
result?: unknown;
|
|
116
|
-
approval?: ToolApproval;
|
|
117
|
-
}> = ({ state, input, result, approval }) => {
|
|
118
|
-
switch (state) {
|
|
119
|
-
case "input-streaming":
|
|
120
|
-
case "input-available":
|
|
121
|
-
case "approval-responded":
|
|
122
|
-
return <ToolArgsRenderer input={input} />;
|
|
123
|
-
|
|
124
|
-
case "output-available":
|
|
125
|
-
return (
|
|
126
|
-
<div className="space-y-3">
|
|
127
|
-
<ToolArgsRenderer input={input} />
|
|
128
|
-
{result != null && <ResultRenderer result={result} />}
|
|
129
|
-
</div>
|
|
130
|
-
);
|
|
131
|
-
|
|
132
|
-
case "output-denied":
|
|
133
|
-
return (
|
|
134
|
-
<div className="space-y-3">
|
|
135
|
-
<ToolArgsRenderer input={input} />
|
|
136
|
-
<div className="bg-muted/40 border border-border rounded-md p-3 text-xs text-muted-foreground leading-relaxed">
|
|
137
|
-
Tool execution was denied
|
|
138
|
-
{approval?.reason ? `: ${approval.reason}` : "."}
|
|
139
|
-
</div>
|
|
140
|
-
</div>
|
|
141
|
-
);
|
|
142
|
-
|
|
143
|
-
default:
|
|
144
|
-
logNever(state);
|
|
145
|
-
return null;
|
|
146
|
-
}
|
|
147
|
-
};
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
|
-
|
|
3
|
-
import clsx from "clsx";
|
|
4
|
-
import { Circle } from "lucide-react";
|
|
5
|
-
import React from "react";
|
|
6
|
-
|
|
7
|
-
interface LoadingEllipsisProps {
|
|
8
|
-
/** Extra Tailwind classes */
|
|
9
|
-
className?: string;
|
|
10
|
-
/** Diameter of each dot in pixels */
|
|
11
|
-
size?: number;
|
|
12
|
-
/** Tailwind gap utility between dots (e.g. "gap-1" or "gap-2") */
|
|
13
|
-
gap?: string;
|
|
14
|
-
/** Pulse cycle length in milliseconds */
|
|
15
|
-
durationMs?: number;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
const LoadingEllipsis: React.FC<LoadingEllipsisProps> = ({
|
|
19
|
-
className,
|
|
20
|
-
size = 8,
|
|
21
|
-
gap = "gap-1",
|
|
22
|
-
durationMs = 1200,
|
|
23
|
-
}) => {
|
|
24
|
-
const baseStyle: React.CSSProperties = {
|
|
25
|
-
animationDuration: `${durationMs}ms`,
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
return (
|
|
29
|
-
<div className={clsx("flex", gap, className)} aria-label="Loading">
|
|
30
|
-
{[0, 1, 2].map((i) => (
|
|
31
|
-
<Circle
|
|
32
|
-
key={i}
|
|
33
|
-
width={size}
|
|
34
|
-
height={size}
|
|
35
|
-
className="fill-current text-current animate-ellipsis-dot"
|
|
36
|
-
style={{
|
|
37
|
-
...baseStyle,
|
|
38
|
-
animationDelay: `${(durationMs / 3) * i}ms`,
|
|
39
|
-
}}
|
|
40
|
-
/>
|
|
41
|
-
))}
|
|
42
|
-
</div>
|
|
43
|
-
);
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
export { LoadingEllipsis };
|