@marimo-team/islands 0.25.3-dev248 → 0.25.3-dev251
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-BBihxHrr.js → ConnectedDataExplorerComponent-DGOAQFtf.js} +11 -11
- package/dist/{ErrorBoundary-CD1s2-yk.js → ErrorBoundary-CZ19wGWT.js} +7 -7
- package/dist/{abnfDiagram-VCTEODGH-DBcJVxYP.js → abnfDiagram-VCTEODGH-DzrZZXRD.js} +2 -2
- package/dist/{any-language-editor-jGaR0EAo.js → any-language-editor-Be7dA2VK.js} +3 -3
- package/dist/{architectureDiagram-5GKGNRK7-BcHZXF4S.js → architectureDiagram-5GKGNRK7-iF_snyFL.js} +1 -1
- package/dist/{button-B6RjDKJx.js → button-0-RqY1DW.js} +2 -1
- package/dist/{capabilities-CkVzWJEX.js → capabilities-B6yy_CBN.js} +1 -1
- package/dist/{chat-ui-DgaVxFrc.js → chat-ui-zbfp80GW.js} +1547 -1482
- package/dist/{check-Z_vtI3OL.js → check-CSvxZk5I.js} +1 -1
- package/dist/{chunk-IMKFNOWR-CTZlwBAA.js → chunk-IMKFNOWR-B7xytD4B.js} +1 -1
- package/dist/{chunk-SHT3W25Y-53g_RZHm.js → chunk-SHT3W25Y-I8ZFP5L1.js} +1 -1
- package/dist/{chunk-SVP7TREG-P6abNGV_.js → chunk-SVP7TREG-Di-uAPdT.js} +1 -1
- package/dist/{chunk-TICWLB2K-BTJJqkyF.js → chunk-TICWLB2K-BFpUy0ud.js} +1 -1
- package/dist/{classDiagram-ZZMXUADV-BUGqOrTm.js → classDiagram-ZZMXUADV-Cqm4JGpx.js} +2 -2
- package/dist/{classDiagram-v2-VYDZK3BY-CXpQvO-s.js → classDiagram-v2-VYDZK3BY-DFHRJpN3.js} +2 -2
- package/dist/{code-visibility-BLiMCTCu.js → code-visibility-D2D_sL1T.js} +4 -4
- package/dist/{common-H6uadBsj.js → common-DSIM5DHJ.js} +262 -262
- package/dist/{config-DbjzjwxX.js → config-mwEjAmvP.js} +2 -2
- package/dist/{copy-icon-CG57cxwb.js → copy-icon-DD8bdw4L.js} +3 -3
- package/dist/{createReducer-DePYJ0F3.js → createReducer-Bx81cw8_.js} +1 -1
- package/dist/{cynefinDiagram-5FMLGOSQ-DOcnl8wW.js → cynefinDiagram-5FMLGOSQ-cuGOeTBC.js} +1 -1
- package/dist/{dagre-GXQ25YYZ-CuHR9QfG.js → dagre-GXQ25YYZ-DJ76aC4k.js} +1 -1
- package/dist/{data-grid-overlay-editor-Ba360Exn.js → data-grid-overlay-editor-ByfOIO6H.js} +1 -1
- package/dist/{diagram-S7CK7UJ4-BPiG4kso.js → diagram-S7CK7UJ4-DLLc0sw7.js} +1 -1
- package/dist/{diagram-UQ7AKVKN-_piBOvOC.js → diagram-UQ7AKVKN-Tz_d6qmk.js} +1 -1
- package/dist/{diagram-VX7I27RA-DCzVeJ8M.js → diagram-VX7I27RA-D7SzPrDN.js} +1 -1
- package/dist/{diagram-Z3DM3KII-D64CF1jQ.js → diagram-Z3DM3KII-qr37XV58.js} +1 -1
- package/dist/{dialog-DsZ49mmU.js → dialog-BHYPX87J.js} +3 -3
- package/dist/{dropdown-menu-BRiE7Vnp.js → dropdown-menu-Blu7V6Mk.js} +6 -6
- package/dist/{ebnfDiagram-PWID7BFC-BapQPML-.js → ebnfDiagram-PWID7BFC-BKOQb4J0.js} +2 -2
- package/dist/{erDiagram-RLTQ6QDP-CNQvC2_Q.js → erDiagram-RLTQ6QDP-CM15Vq68.js} +1 -1
- package/dist/{error-banner-IsonnvA0.js → error-banner-DbRFOd2O.js} +2 -2
- package/dist/{error-entries-CRPfxMqm.js → error-entries-BuIE3Ius.js} +9 -9
- package/dist/{feedback-button-Cfjlex_J.js → feedback-button-VT03EJ1h.js} +7 -7
- package/dist/{flowDiagram-HODETNUW-BBt6S6oe.js → flowDiagram-HODETNUW-Dt3N5yFT.js} +2 -2
- package/dist/{formats-BK4VefeF.js → formats-gGospKWJ.js} +2 -2
- package/dist/{glide-data-editor-CREvupa1.js → glide-data-editor-C94G7kD7.js} +10 -10
- package/dist/{glide-utils-CQddGpa-.js → glide-utils-qbkRZpEy.js} +3 -3
- package/dist/{globals-DUIx9HDW.js → globals-D7JZ5hgJ.js} +2 -2
- package/dist/{html-to-image-Gx4q3ZoD.js → html-to-image-BXrAd5q8.js} +460 -455
- package/dist/{infoDiagram-27XIBGKW-Hd8Ifz82.js → infoDiagram-27XIBGKW-C7axJMCl.js} +1 -1
- package/dist/{ishikawaDiagram-5VMMS53U-CP7hnHWx.js → ishikawaDiagram-5VMMS53U-CdC9Eur7.js} +1 -1
- package/dist/{kanban-definition-UXKFOSKX-CX91sa9b.js → kanban-definition-UXKFOSKX-BHnMIgD7.js} +1 -1
- package/dist/{loader-BisjOLiW.js → loader-BVEtQ4F3.js} +1 -1
- package/dist/main.js +236 -236
- package/dist/{mermaid-Djb3Ni9t.js → mermaid-DFYN_PXd.js} +35 -35
- package/dist/{mindmap-definition-YA3MSWOX-DgCNo07O.js → mindmap-definition-YA3MSWOX-BagHoCGU.js} +1 -1
- package/dist/{number-overlay-editor-B8TTAovO.js → number-overlay-editor-CdcscCHp.js} +1 -1
- package/dist/{pegDiagram-XKGWAZYB-SGJhnIKo.js → pegDiagram-XKGWAZYB-8IIZczip.js} +2 -2
- package/dist/{pieDiagram-E7YTZNPT-1stXIWCQ.js → pieDiagram-E7YTZNPT-CE6dKBIr.js} +1 -1
- package/dist/{process-output-D2ISIyIs.js → process-output-D2ZjxrHe.js} +4 -4
- package/dist/{railroadDiagram-O6MQD6OU-DY1mojzB.js → railroadDiagram-O6MQD6OU-CkexPq3b.js} +2 -2
- package/dist/{requirementDiagram-BXWQKSXE-gHzhUp0D.js → requirementDiagram-BXWQKSXE-B0-OkuAe.js} +1 -1
- package/dist/{reveal-component-CmZQtS97.js → reveal-component-Cr9euMM2.js} +8 -8
- package/dist/{select-BSxlITBo.js → select-CcidPqlM.js} +5 -5
- package/dist/{sequenceDiagram-WJ2MYXX4-rjPtD9fB.js → sequenceDiagram-WJ2MYXX4-Dxysg8DX.js} +1 -1
- package/dist/{spec-Dq8RNplp.js → spec-ZwfZcgsm.js} +4 -4
- package/dist/{stateDiagram-D77RDMKH-DMNxjUxV.js → stateDiagram-D77RDMKH-DTEN3-OJ.js} +2 -2
- package/dist/{stateDiagram-v2-MP3YSRHH-CumAaqGo.js → stateDiagram-v2-MP3YSRHH-vktk3Xc5.js} +2 -2
- package/dist/{strings-BGW-fXVJ.js → strings-BYJNyKmg.js} +3 -3
- package/dist/style.css +1 -1
- package/dist/{swimlanes-42K2YHIH-BU14_Tej.js → swimlanes-42K2YHIH-Cjveh9OM.js} +1 -1
- package/dist/{swimlanesDiagram-VR7AAH4N-CieAnPqJ.js → swimlanesDiagram-VR7AAH4N-Bdr7Ev_2.js} +2 -2
- package/dist/{swiper-component-Dir1o8ml.js → swiper-component-Dvj-goaD.js} +2 -2
- package/dist/{timeline-definition-24CTP7MA-CrVj4E1K.js → timeline-definition-24CTP7MA-KIuDcefn.js} +1 -1
- package/dist/{toast-BWIPi3aF.js → toast-CkB5Jq9K.js} +4 -4
- package/dist/{tooltip-C3UnvsRe.js → tooltip-Bzl4k00l.js} +2 -2
- package/dist/{use-restore-focus-BWO0z1lo.js → use-restore-focus-CmflVLWJ.js} +1 -1
- package/dist/{useDateFormatter-ChB4eyim.js → useDateFormatter-CYo5fm8s.js} +2 -2
- package/dist/{useIframeCapabilities-cMNQ80CK.js → useIframeCapabilities-BIolGsF1.js} +1 -1
- package/dist/{useLifecycle-BquH9ET-.js → useLifecycle-GNgvNwI-.js} +2 -2
- package/dist/{useTheme-DgOLVISn.js → useTheme-BZ2GGLgm.js} +141 -139
- package/dist/{vega-component-Bwg_Kuh-.js → vega-component-DOtem7Hf.js} +7 -7
- package/dist/{vennDiagram-4TSXK5OY-ZLxQ8yhm.js → vennDiagram-4TSXK5OY-DrIOUHfb.js} +1 -1
- package/dist/{wardleyDiagram-VM6X3IG4-D88pcLY1.js → wardleyDiagram-VM6X3IG4-CJNjf4OH.js} +1 -1
- package/dist/{xychartDiagram-S5SC5T6Z-_13d4g8g.js → xychartDiagram-S5SC5T6Z-DEshFho-.js} +1 -1
- package/package.json +1 -1
- package/src/__tests__/fixtures/pair-config.ts +1 -1
- package/src/components/app-config/__tests__/state.test.tsx +50 -0
- package/src/components/app-config/ai-config.tsx +1 -1
- package/src/components/chat/__tests__/capabilities-popover.test.tsx +0 -1
- package/src/components/chat/__tests__/chat-display.test.tsx +125 -0
- package/src/components/chat/__tests__/chat-markdown.test.tsx +43 -0
- package/src/components/chat/__tests__/chat-utils.test.ts +51 -1
- package/src/components/chat/acp/__tests__/agent-panel-initialization.test.tsx +1 -1
- package/src/components/chat/acp/__tests__/agent-panel.test.tsx +22 -17
- package/src/components/chat/acp/agent-panel.tsx +4 -3
- package/src/components/chat/acp/blocks.tsx +10 -10
- package/src/components/chat/acp/common.tsx +4 -5
- package/src/components/chat/acp/model-selector.tsx +1 -1
- package/src/components/chat/capabilities-popover.tsx +1 -6
- package/src/components/chat/chat-components.tsx +7 -4
- package/src/components/chat/chat-display.tsx +51 -6
- package/src/components/chat/chat-history-popover.tsx +6 -1
- package/src/components/chat/chat-markdown.tsx +15 -0
- package/src/components/chat/chat-panel.tsx +105 -119
- package/src/components/chat/chat-typography.css +108 -0
- package/src/components/chat/chat-utils.ts +8 -3
- package/src/components/chat/notebook-access-selector.tsx +1 -1
- package/src/components/chat/reasoning-accordion.tsx +3 -3
- package/src/components/chat/tool-call/tool-activity-group.tsx +49 -0
- package/src/components/chat/tool-call/tool-history-row.tsx +3 -30
- package/src/components/chat/tool-call/tool-result.tsx +1 -1
- package/src/components/chat/use-chat-generation.ts +19 -0
- package/src/components/editor/actions/__tests__/pair-with-agent-commands.test.ts +18 -37
- package/src/components/editor/actions/__tests__/pair-with-agent-modal.test.tsx +5 -8
- package/src/components/editor/actions/__tests__/pair-with-agent.test.tsx +5 -19
- package/src/components/editor/actions/pair-with-agent-commands.ts +0 -1
- package/src/components/editor/actions/pair-with-agent-modal.tsx +7 -11
- package/src/components/editor/actions/pair-with-agent.tsx +3 -31
- package/src/components/editor/actions/useCellActionButton.tsx +1 -1
- package/src/components/editor/ai/ai-completion-editor.tsx +1 -1
- package/src/components/editor/ai/prompt-input.tsx +189 -0
- package/src/components/editor/cell/StagedAICell.tsx +3 -3
- package/src/components/editor/cell/code/cell-editor.tsx +14 -1
- package/src/components/editor/chrome/panels/panel-header.tsx +13 -0
- package/src/components/editor/chrome/types.ts +1 -1
- package/src/components/editor/chrome/wrapper/__tests__/pending-ai-cells.test.tsx +53 -45
- package/src/components/editor/chrome/wrapper/__tests__/useAskAiAboutCell.test.tsx +58 -0
- package/src/components/editor/chrome/wrapper/app-chrome.tsx +89 -72
- package/src/components/editor/chrome/wrapper/pending-ai-cells.tsx +5 -8
- package/src/components/editor/chrome/wrapper/useAskAiAboutCell.ts +36 -0
- package/src/components/editor/renderers/__tests__/add-cell-buttons.test.tsx +18 -0
- package/src/components/editor/renderers/cell-array.tsx +10 -67
- package/src/components/markdown/markdown-renderer.tsx +35 -20
- package/src/components/mcp/mcp-status-indicator.tsx +18 -14
- package/src/core/ai/__tests__/staged-cells.test.ts +1 -467
- package/src/core/ai/context/context.ts +2 -0
- package/src/core/ai/context/providers/__tests__/cell.test.ts +49 -0
- package/src/core/ai/context/providers/cell.ts +54 -0
- package/src/core/ai/staged-cells.ts +4 -280
- package/src/core/ai/state.ts +3 -0
- package/src/core/codemirror/__tests__/setup.test.ts +32 -0
- package/src/core/codemirror/cells/state.ts +1 -0
- package/src/core/codemirror/cm.ts +5 -1
- package/src/core/codemirror/config/types.ts +1 -1
- package/src/core/codemirror/language/languages/python.ts +3 -3
- package/src/core/codemirror/placeholder/__tests__/extensions.test.ts +16 -0
- package/src/core/codemirror/placeholder/extensions.ts +57 -19
- package/src/core/hotkeys/hotkeys.ts +2 -1
- package/src/core/notebook/document/__tests__/codemirror.test.ts +1 -0
- package/src/plugins/impl/chat/__tests__/chat-prompts.test.tsx +1 -1
- package/src/plugins/impl/chat/chat-ui.tsx +1 -1
- package/src/components/editor/ai/__tests__/staged-cell-submission.test.ts +0 -106
- package/src/components/editor/ai/add-cell-with-ai.tsx +0 -506
- package/src/components/editor/ai/staged-cell-submission.ts +0 -46
- package/src/components/editor/cell/__tests__/StagedAICell.test.tsx +0 -66
|
@@ -146,7 +146,9 @@ export async function handleToolCall({
|
|
|
146
146
|
addToolOutput({
|
|
147
147
|
tool: toolCall.toolName,
|
|
148
148
|
toolCallId: toolCall.toolCallId,
|
|
149
|
-
|
|
149
|
+
...(response.error
|
|
150
|
+
? { state: "output-error", errorText: response.error }
|
|
151
|
+
: { output: response.result }),
|
|
150
152
|
});
|
|
151
153
|
} else {
|
|
152
154
|
// Invoke the backend/mcp tool
|
|
@@ -157,7 +159,9 @@ export async function handleToolCall({
|
|
|
157
159
|
addToolOutput({
|
|
158
160
|
tool: toolCall.toolName,
|
|
159
161
|
toolCallId: toolCall.toolCallId,
|
|
160
|
-
|
|
162
|
+
...(response.error
|
|
163
|
+
? { state: "output-error", errorText: response.error }
|
|
164
|
+
: { output: response.result }),
|
|
161
165
|
});
|
|
162
166
|
}
|
|
163
167
|
} catch (error) {
|
|
@@ -165,7 +169,8 @@ export async function handleToolCall({
|
|
|
165
169
|
addToolOutput({
|
|
166
170
|
tool: toolCall.toolName,
|
|
167
171
|
toolCallId: toolCall.toolCallId,
|
|
168
|
-
|
|
172
|
+
state: "output-error",
|
|
173
|
+
errorText: error instanceof Error ? error.message : String(error),
|
|
169
174
|
});
|
|
170
175
|
}
|
|
171
176
|
}
|
|
@@ -64,7 +64,7 @@ export const NotebookAccessSelector = ({
|
|
|
64
64
|
<SelectTrigger
|
|
65
65
|
aria-label={`Notebook access: ${selected.label}`}
|
|
66
66
|
title={`Notebook access: ${selected.description}`}
|
|
67
|
-
className="h-6 text-xs border-border
|
|
67
|
+
className="chat-control chat-selector h-6 text-xs border-border py-0 px-2 gap-1.5 shrink-0"
|
|
68
68
|
>
|
|
69
69
|
<selected.Icon className="h-3 w-3" />
|
|
70
70
|
<span className="text-nowrap">{selected.label}</span>
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { BotMessageSquareIcon } from "lucide-react";
|
|
4
4
|
import React from "react";
|
|
5
|
-
import {
|
|
5
|
+
import { ChatMarkdown } from "./chat-markdown";
|
|
6
6
|
import {
|
|
7
7
|
Accordion,
|
|
8
8
|
AccordionContent,
|
|
@@ -49,9 +49,9 @@ export const ReasoningAccordion: React.FC<ReasoningAccordionProps> = ({
|
|
|
49
49
|
</span>
|
|
50
50
|
</AccordionTrigger>
|
|
51
51
|
<AccordionContent className="pb-2 px-2">
|
|
52
|
-
<div className="bg-muted/30 border border-muted/50 rounded-md p-3
|
|
52
|
+
<div className="bg-muted/30 border border-muted/50 rounded-md p-3 text-muted-foreground relative">
|
|
53
53
|
<div className="pr-6">
|
|
54
|
-
<
|
|
54
|
+
<ChatMarkdown content={reasoning} />
|
|
55
55
|
</div>
|
|
56
56
|
</div>
|
|
57
57
|
</AccordionContent>
|
|
@@ -0,0 +1,49 @@
|
|
|
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,12 +1,6 @@
|
|
|
1
1
|
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
BanIcon,
|
|
5
|
-
CheckCircleIcon,
|
|
6
|
-
CircleSlashIcon,
|
|
7
|
-
Loader2,
|
|
8
|
-
WrenchIcon,
|
|
9
|
-
} from "lucide-react";
|
|
3
|
+
import { BanIcon, CircleSlashIcon, Loader2, WrenchIcon } from "lucide-react";
|
|
10
4
|
import React from "react";
|
|
11
5
|
import {
|
|
12
6
|
Accordion,
|
|
@@ -54,7 +48,7 @@ const StatusIcon: React.FC<{ state: HistoryState; interrupted: boolean }> = ({
|
|
|
54
48
|
case "approval-responded":
|
|
55
49
|
return <Loader2 className="h-3 w-3 animate-spin" />;
|
|
56
50
|
case "output-available":
|
|
57
|
-
return
|
|
51
|
+
return null;
|
|
58
52
|
case "output-denied":
|
|
59
53
|
return <BanIcon className="h-3 w-3 text-muted-foreground" />;
|
|
60
54
|
default:
|
|
@@ -63,22 +57,6 @@ const StatusIcon: React.FC<{ state: HistoryState; interrupted: boolean }> = ({
|
|
|
63
57
|
}
|
|
64
58
|
};
|
|
65
59
|
|
|
66
|
-
function getTriggerToneClass(state: HistoryState): string {
|
|
67
|
-
switch (state) {
|
|
68
|
-
case "output-available":
|
|
69
|
-
return "text-(--grass-11)/80";
|
|
70
|
-
case "output-denied":
|
|
71
|
-
return "text-muted-foreground";
|
|
72
|
-
case "input-streaming":
|
|
73
|
-
case "input-available":
|
|
74
|
-
case "approval-responded":
|
|
75
|
-
return "";
|
|
76
|
-
default:
|
|
77
|
-
logNever(state);
|
|
78
|
-
return "";
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
60
|
interface ToolHistoryRowProps {
|
|
83
61
|
toolName: string;
|
|
84
62
|
state: HistoryState;
|
|
@@ -109,12 +87,7 @@ export const ToolHistoryRow: React.FC<ToolHistoryRowProps> = ({
|
|
|
109
87
|
className={cn("w-full", className)}
|
|
110
88
|
>
|
|
111
89
|
<AccordionItem value="tool-call" className="border-0">
|
|
112
|
-
<AccordionTrigger
|
|
113
|
-
className={cn(
|
|
114
|
-
"h-6 text-xs border-border shadow-none! ring-0! bg-muted/60 hover:bg-muted py-0 px-2 gap-1 rounded-sm [&[data-state=open]>svg]:rotate-180 hover:no-underline",
|
|
115
|
-
interrupted ? "text-muted-foreground" : getTriggerToneClass(state),
|
|
116
|
-
)}
|
|
117
|
-
>
|
|
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">
|
|
118
91
|
<span className="flex items-center gap-1">
|
|
119
92
|
<StatusIcon state={state} interrupted={interrupted} />
|
|
120
93
|
{interrupted ? "Interrupted" : STATUS_LABEL[state]}:
|
|
@@ -47,7 +47,7 @@ const PrettySuccessResult: React.FC<{ data: SuccessResult }> = ({ data }) => {
|
|
|
47
47
|
Tool Result
|
|
48
48
|
</h3>
|
|
49
49
|
<div className="flex items-center gap-2">
|
|
50
|
-
<span className="text-xs
|
|
50
|
+
<span className="text-xs text-muted-foreground capitalize">
|
|
51
51
|
{status}
|
|
52
52
|
</span>
|
|
53
53
|
{auth_required && (
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
|
+
|
|
3
|
+
import type { ChatStatus } from "ai";
|
|
4
|
+
import { useSetAtom } from "jotai";
|
|
5
|
+
import { useEffect } from "react";
|
|
6
|
+
import { chatGenerationInProgressAtom } from "@/core/ai/state";
|
|
7
|
+
|
|
8
|
+
export function useChatGeneration(status: ChatStatus) {
|
|
9
|
+
const setGenerating = useSetAtom(chatGenerationInProgressAtom);
|
|
10
|
+
const isGenerating = status === "submitted" || status === "streaming";
|
|
11
|
+
|
|
12
|
+
useEffect(() => {
|
|
13
|
+
setGenerating(isGenerating);
|
|
14
|
+
// useChat stops its request when the panel unmounts or becomes hidden.
|
|
15
|
+
return () => setGenerating(false);
|
|
16
|
+
}, [isGenerating, setGenerating]);
|
|
17
|
+
|
|
18
|
+
return isGenerating;
|
|
19
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { describe, expect, it } from "vitest";
|
|
4
4
|
import { PAIR_CONFIG } from "@/__tests__/fixtures/pair-config";
|
|
5
5
|
import { shellQuote } from "@/utils/shell";
|
|
6
6
|
import {
|
|
@@ -44,18 +44,6 @@ describe("shellQuote", () => {
|
|
|
44
44
|
});
|
|
45
45
|
});
|
|
46
46
|
|
|
47
|
-
describe("getMarimoCommand", () => {
|
|
48
|
-
afterEach(() => vi.unstubAllEnvs());
|
|
49
|
-
it("uses the checkout command in development", () => {
|
|
50
|
-
vi.stubEnv("DEV", true);
|
|
51
|
-
expect(getMarimoCommand()).toBe("uv run marimo");
|
|
52
|
-
});
|
|
53
|
-
it("uses uvx outside development", () => {
|
|
54
|
-
vi.stubEnv("DEV", false);
|
|
55
|
-
expect(getMarimoCommand()).toBe("uvx marimo@latest");
|
|
56
|
-
});
|
|
57
|
-
});
|
|
58
|
-
|
|
59
47
|
describe("getTerminalCommand", () => {
|
|
60
48
|
it.each([
|
|
61
49
|
["claude", "claude"],
|
|
@@ -63,7 +51,7 @@ describe("getTerminalCommand", () => {
|
|
|
63
51
|
["opencode", "opencode --prompt"],
|
|
64
52
|
] as const)("launches %s through the public CLI", (agent, cli) => {
|
|
65
53
|
expect(getTerminalCommand(agent, CONNECTION, true, PAIR_CONFIG)).toBe(
|
|
66
|
-
`${cli} "$(
|
|
54
|
+
`${cli} "$(marimo pair prompt \\\n --url http://localhost:8000 \\\n --notebook nb-one \\\n --with-token)"`,
|
|
67
55
|
);
|
|
68
56
|
});
|
|
69
57
|
it("uses a stable Session ID for editor execution", () => {
|
|
@@ -89,20 +77,15 @@ describe("getTerminalCommand", () => {
|
|
|
89
77
|
expect(command).not.toContain("--with-token");
|
|
90
78
|
});
|
|
91
79
|
it("uses the CLI without injected configuration", () => {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
/--claude|MARIMO_PAIR_NEXT|--file|--session|--notebook/,
|
|
102
|
-
);
|
|
103
|
-
} finally {
|
|
104
|
-
vi.unstubAllEnvs();
|
|
105
|
-
}
|
|
80
|
+
const command = getTerminalCommand(
|
|
81
|
+
"claude",
|
|
82
|
+
CONNECTION_WITHOUT_TARGET,
|
|
83
|
+
false,
|
|
84
|
+
);
|
|
85
|
+
expect(command).toContain(`${getMarimoCommand()} pair prompt`);
|
|
86
|
+
expect(command).not.toMatch(
|
|
87
|
+
/--claude|MARIMO_PAIR_NEXT|--file|--session|--notebook/,
|
|
88
|
+
);
|
|
106
89
|
});
|
|
107
90
|
});
|
|
108
91
|
|
|
@@ -133,21 +116,19 @@ describe("getRawPrompt", () => {
|
|
|
133
116
|
"Session: stable-one\n",
|
|
134
117
|
],
|
|
135
118
|
])("renders the shared CLI prompt for %j", (connection, target) => {
|
|
136
|
-
const expected = `Pair with me on this running marimo notebook.\n\nURL: http://localhost:8000\n${target}\nRun \`
|
|
119
|
+
const expected = `Pair with me on this running marimo notebook.\n\nURL: http://localhost:8000\n${target}\nRun \`marimo pair --help\` first.\nUse \`marimo\` for all marimo commands.`;
|
|
137
120
|
expect(getRawPrompt(connection, null, PAIR_CONFIG)).toBe(expected);
|
|
138
121
|
expect(
|
|
139
122
|
getRawPrompt(connection, null, { ...PAIR_CONFIG, hostEnabled: false }),
|
|
140
123
|
).toBe(expected);
|
|
141
124
|
});
|
|
142
125
|
it("matches the shared prompt without injected templates", () => {
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
)
|
|
148
|
-
|
|
149
|
-
vi.unstubAllEnvs();
|
|
150
|
-
}
|
|
126
|
+
expect(getRawPrompt(CONNECTION, "secret-token")).toBe(
|
|
127
|
+
getRawPrompt(CONNECTION, "secret-token", {
|
|
128
|
+
...PAIR_CONFIG,
|
|
129
|
+
command: getMarimoCommand(),
|
|
130
|
+
}),
|
|
131
|
+
);
|
|
151
132
|
});
|
|
152
133
|
});
|
|
153
134
|
|
|
@@ -99,14 +99,11 @@ describe("PairWithAgentModal", () => {
|
|
|
99
99
|
expect(panel).not.toHaveTextContent("--file");
|
|
100
100
|
expect(panel).not.toHaveTextContent("File:");
|
|
101
101
|
expect(panel).not.toHaveTextContent("notebook.py");
|
|
102
|
-
expect(
|
|
103
|
-
panel.textContent?.includes("Agent connections require OpenCode 2.x"),
|
|
104
|
-
).toBe(tab === "OpenCode");
|
|
105
102
|
expect(
|
|
106
103
|
within(panel).getByText(
|
|
107
104
|
tab === "Other Agents"
|
|
108
|
-
? "
|
|
109
|
-
: "Run in your terminal",
|
|
105
|
+
? "Paste this prompt into your coding agent:"
|
|
106
|
+
: "Run this command in your terminal:",
|
|
110
107
|
{ exact: true },
|
|
111
108
|
),
|
|
112
109
|
).toBeInTheDocument();
|
|
@@ -367,15 +364,15 @@ describe("PairWithAgentModal", () => {
|
|
|
367
364
|
});
|
|
368
365
|
|
|
369
366
|
const panel = screen.getByRole("tabpanel");
|
|
370
|
-
expect(panel).toHaveTextContent("1. Run in your terminal");
|
|
371
|
-
expect(panel).toHaveTextContent("2.
|
|
367
|
+
expect(panel).toHaveTextContent("1. Run this command in your terminal:");
|
|
368
|
+
expect(panel).toHaveTextContent("2. When prompted, paste this token:");
|
|
372
369
|
expect(panel).not.toHaveTextContent("secret-token");
|
|
373
370
|
fireEvent.click(
|
|
374
371
|
within(panel).getByRole("button", { name: "Copy command" }),
|
|
375
372
|
);
|
|
376
373
|
await waitFor(() =>
|
|
377
374
|
expect(copyToClipboard).toHaveBeenCalledWith(
|
|
378
|
-
String.raw`claude "$(
|
|
375
|
+
String.raw`claude "$(marimo pair prompt \
|
|
379
376
|
--url http://localhost:8000/ \
|
|
380
377
|
--notebook ${NOTEBOOK_ID} \
|
|
381
378
|
--with-token)"`,
|
|
@@ -7,7 +7,7 @@ import { afterEach, describe, expect, it, vi } from "vitest";
|
|
|
7
7
|
import { ModalProvider } from "@/components/modal/ImperativeModal";
|
|
8
8
|
import { TooltipProvider } from "@/components/ui/tooltip";
|
|
9
9
|
import { store } from "@/core/state/jotai";
|
|
10
|
-
import { PairWithAgentBanner
|
|
10
|
+
import { PairWithAgentBanner } from "../pair-with-agent";
|
|
11
11
|
|
|
12
12
|
const mocks = vi.hoisted(() => ({
|
|
13
13
|
isWasm: vi.fn(() => false),
|
|
@@ -75,29 +75,15 @@ describe("PairWithAgent", () => {
|
|
|
75
75
|
}),
|
|
76
76
|
);
|
|
77
77
|
|
|
78
|
-
expect(
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
it("opens the pairing dialog and preserves a passed click handler", () => {
|
|
82
|
-
const onClick = vi.fn();
|
|
83
|
-
stubTokenFetch();
|
|
84
|
-
render(<PairWithAgentButton onClick={onClick} />, { wrapper });
|
|
85
|
-
|
|
86
|
-
fireEvent.click(screen.getByRole("button", { name: "Pair your agent" }));
|
|
87
|
-
|
|
88
|
-
expect(onClick).toHaveBeenCalledOnce();
|
|
89
|
-
expect(screen.getByRole("dialog", { name: "Pair an agent" })).toBeVisible();
|
|
78
|
+
expect(
|
|
79
|
+
screen.getByRole("dialog", { name: "Pair an agent to this notebook" }),
|
|
80
|
+
).toBeVisible();
|
|
90
81
|
});
|
|
91
82
|
|
|
92
83
|
it("hides pairing controls in WASM", () => {
|
|
93
84
|
mocks.isWasm.mockReturnValue(true);
|
|
94
85
|
|
|
95
|
-
const { container
|
|
96
|
-
wrapper,
|
|
97
|
-
});
|
|
98
|
-
expect(container).toBeEmptyDOMElement();
|
|
99
|
-
|
|
100
|
-
rerender(<PairWithAgentBanner />);
|
|
86
|
+
const { container } = render(<PairWithAgentBanner />, { wrapper });
|
|
101
87
|
expect(container).toBeEmptyDOMElement();
|
|
102
88
|
});
|
|
103
89
|
});
|
|
@@ -17,7 +17,6 @@ export const AGENT_LABELS: Record<AgentTab, string> = {
|
|
|
17
17
|
prompt: "Other Agents",
|
|
18
18
|
};
|
|
19
19
|
|
|
20
|
-
/** How to invoke marimo: from the local checkout in dev, else via uvx. */
|
|
21
20
|
export function getMarimoCommand(): string {
|
|
22
21
|
return import.meta.env.DEV ? "uv run marimo" : "uvx marimo@latest";
|
|
23
22
|
}
|
|
@@ -116,11 +116,12 @@ export const PairWithAgentModal: React.FC<{
|
|
|
116
116
|
return (
|
|
117
117
|
<DialogContent className="sm:max-w-2xl">
|
|
118
118
|
<DialogHeader>
|
|
119
|
-
<DialogTitle>Pair an agent</DialogTitle>
|
|
119
|
+
<DialogTitle>Pair an agent to this notebook</DialogTitle>
|
|
120
120
|
<DialogDescription>
|
|
121
|
-
|
|
121
|
+
Choose your coding agent, then follow the instructions below to
|
|
122
|
+
connect it to this notebook using marimo pair.{" "}
|
|
122
123
|
<a
|
|
123
|
-
href="https://links.marimo.app/marimo-pair"
|
|
124
|
+
href="https://links.marimo.app/docs-marimo-pair"
|
|
124
125
|
target="_blank"
|
|
125
126
|
rel="noopener noreferrer"
|
|
126
127
|
className="underline"
|
|
@@ -160,12 +161,7 @@ export const PairWithAgentModal: React.FC<{
|
|
|
160
161
|
>
|
|
161
162
|
<Step
|
|
162
163
|
index={hasToken ? 1 : undefined}
|
|
163
|
-
title="Run in your terminal"
|
|
164
|
-
hint={
|
|
165
|
-
hostEnabled && tab === "opencode"
|
|
166
|
-
? "Agent connections require OpenCode 2.x."
|
|
167
|
-
: undefined
|
|
168
|
-
}
|
|
164
|
+
title="Run this command in your terminal:"
|
|
169
165
|
>
|
|
170
166
|
<CommandBlock
|
|
171
167
|
command={getTerminalCommand(
|
|
@@ -178,7 +174,7 @@ export const PairWithAgentModal: React.FC<{
|
|
|
178
174
|
/>
|
|
179
175
|
</Step>
|
|
180
176
|
{hasToken && authToken && (
|
|
181
|
-
<Step index={2} title="
|
|
177
|
+
<Step index={2} title="When prompted, paste this token:">
|
|
182
178
|
<CommandBlock
|
|
183
179
|
command={authToken}
|
|
184
180
|
display={maskToken(authToken)}
|
|
@@ -191,7 +187,7 @@ export const PairWithAgentModal: React.FC<{
|
|
|
191
187
|
|
|
192
188
|
<TabsContent value="prompt" className="mt-4 flex flex-col gap-4">
|
|
193
189
|
<Step
|
|
194
|
-
title="
|
|
190
|
+
title="Paste this prompt into your coding agent:"
|
|
195
191
|
hint={
|
|
196
192
|
hasToken
|
|
197
193
|
? "Includes your auth token — keep it private."
|
|
@@ -4,7 +4,7 @@ import { ArrowUpRightIcon, BotIcon } from "lucide-react";
|
|
|
4
4
|
import React from "react";
|
|
5
5
|
import { AiProviderIcon } from "@/components/ai/ai-provider-icon";
|
|
6
6
|
import { useImperativeModal } from "@/components/modal/ImperativeModal";
|
|
7
|
-
import { Button
|
|
7
|
+
import { Button } from "@/components/ui/button";
|
|
8
8
|
import { isWasm } from "@/core/wasm/utils";
|
|
9
9
|
import { cn } from "@/utils/cn";
|
|
10
10
|
import { PairWithAgentModal } from "./pair-with-agent-modal";
|
|
@@ -31,38 +31,10 @@ export const usePairWithAgentModal = () => {
|
|
|
31
31
|
);
|
|
32
32
|
};
|
|
33
33
|
|
|
34
|
-
export const PairWithAgentButton: React.FC<
|
|
35
|
-
ButtonProps & { label?: string }
|
|
36
|
-
> = ({ className, label = "Pair your agent", onClick, ...props }) => {
|
|
37
|
-
const openPairWithAgentModal = usePairWithAgentModal();
|
|
38
|
-
|
|
39
|
-
if (isWasm()) {
|
|
40
|
-
return null;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
return (
|
|
44
|
-
<Button
|
|
45
|
-
type="button"
|
|
46
|
-
variant="link"
|
|
47
|
-
size="xs"
|
|
48
|
-
className={cn("h-auto gap-1 px-0", className)}
|
|
49
|
-
onClick={(event) => {
|
|
50
|
-
onClick?.(event);
|
|
51
|
-
if (!event.defaultPrevented) {
|
|
52
|
-
openPairWithAgentModal();
|
|
53
|
-
}
|
|
54
|
-
}}
|
|
55
|
-
{...props}
|
|
56
|
-
>
|
|
57
|
-
{label}
|
|
58
|
-
</Button>
|
|
59
|
-
);
|
|
60
|
-
};
|
|
61
|
-
|
|
62
34
|
export const PairWithAgentBanner: React.FC<{
|
|
63
35
|
label?: string;
|
|
64
36
|
className?: string;
|
|
65
|
-
}> = ({ label = "Pair your agent", className }) => {
|
|
37
|
+
}> = ({ label = "Pair your coding agent", className }) => {
|
|
66
38
|
const openPairWithAgentModal = usePairWithAgentModal();
|
|
67
39
|
|
|
68
40
|
if (isWasm()) {
|
|
@@ -76,7 +48,7 @@ export const PairWithAgentBanner: React.FC<{
|
|
|
76
48
|
className,
|
|
77
49
|
)}
|
|
78
50
|
>
|
|
79
|
-
<div className="flex items-center gap-2 text-sm font-semibold">
|
|
51
|
+
<div className="flex flex-wrap items-center gap-2 text-sm font-semibold">
|
|
80
52
|
{label}
|
|
81
53
|
<fieldset
|
|
82
54
|
className="m-0 flex min-w-0 -space-x-1.5 border-0 p-0 mb-0.5"
|
|
@@ -159,7 +159,7 @@ export function useCellActionButtons({ cell, closePopover }: Props) {
|
|
|
159
159
|
},
|
|
160
160
|
{
|
|
161
161
|
icon: <SparklesIcon size={13} strokeWidth={1.5} />,
|
|
162
|
-
label: "Refactor
|
|
162
|
+
label: "Refactor cell",
|
|
163
163
|
hidden: !aiFeaturesEnabled,
|
|
164
164
|
handle: () => {
|
|
165
165
|
setAiCompletionCell((current) =>
|
|
@@ -45,7 +45,7 @@ import { useTheme } from "@/theme/useTheme";
|
|
|
45
45
|
import { cn } from "@/utils/cn";
|
|
46
46
|
import { prettyError } from "@/utils/errors";
|
|
47
47
|
import { retryWithTimeout } from "@/utils/timeout";
|
|
48
|
-
import { PromptInput } from "./
|
|
48
|
+
import { PromptInput } from "./prompt-input";
|
|
49
49
|
import {
|
|
50
50
|
AcceptCompletionButton,
|
|
51
51
|
AI_EDIT_ACTION_LABELS,
|