@marimo-team/frontend 0.15.5 → 0.16.0
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/assets/{ConnectedDataExplorerComponent-Cn5-l2X1.js → ConnectedDataExplorerComponent-BErMbWvG.js} +1 -1
- package/dist/assets/{ImageComparisonComponent-CEXMKKA4.js → ImageComparisonComponent-fTHv1Ih0.js} +1 -1
- package/dist/assets/{VegaLite-Bt14Ds9k.js → VegaLite-Bdi-TyfY.js} +6 -6
- package/dist/assets/_baseEach-CNBxBxvS.js +1 -0
- package/dist/assets/_baseMap-D1WHjKrd.js +1 -0
- package/dist/assets/_baseUniq-CCgDNtZb.js +1 -0
- package/dist/assets/_createAggregator-DcD0kTA5.js +1 -0
- package/dist/assets/agent-panel-Crv430aI.js +268 -0
- package/dist/assets/agent-panel-D92Mfy1i.css +1 -0
- package/dist/assets/{any-language-editor-DiwNT6zp.js → any-language-editor-CQh552Wu.js} +1 -1
- package/dist/assets/architectureDiagram-W76B3OCA-BAJeBxzt.js +36 -0
- package/dist/assets/{between-horizontal-start-FyewyCGn.js → between-horizontal-start-Boxgxbt_.js} +1 -1
- package/dist/assets/{blockDiagram-QIGZ2CNN-BrOkAf_c.js → blockDiagram-QIGZ2CNN-CL-1svEK.js} +1 -1
- package/dist/assets/{c4Diagram-FPNF74CW-BHPzDxE2.js → c4Diagram-FPNF74CW-BbEqbCTl.js} +5 -5
- package/dist/assets/channel-_2eNSz0n.js +1 -0
- package/dist/assets/chat-panel-CXh5Wl6C.js +3 -0
- package/dist/assets/{chunk-4BX2VUAB-DLxaCNYh.js → chunk-4BX2VUAB-C--8TXeE.js} +1 -1
- package/dist/assets/{chunk-55IACEB6-DdzvO3HR.js → chunk-55IACEB6-Bj00HDqq.js} +1 -1
- package/dist/assets/{chunk-FMBD7UC4-R5o-nSiG.js → chunk-FMBD7UC4-C-lhB6hN.js} +1 -1
- package/dist/assets/{chunk-K7UQS3LO-DxaMrGgG.js → chunk-K7UQS3LO-B-pGTXPt.js} +1 -1
- package/dist/assets/{chunk-QN33PNHL-DqS9-FYm.js → chunk-QN33PNHL-DqUzGhvm.js} +1 -1
- package/dist/assets/{chunk-QZHKN3VN-BZ-TzajS.js → chunk-QZHKN3VN-TntJHfSk.js} +1 -1
- package/dist/assets/{chunk-TVAH2DTR-BsgP2dyv.js → chunk-TVAH2DTR-HUJb1psV.js} +1 -1
- package/dist/assets/{chunk-TZMSLE5B-D-h3ahXI.js → chunk-TZMSLE5B-BK3C__t3.js} +1 -1
- package/dist/assets/{circle-play-CQtRZ-rT.js → circle-play-DBLOv1Yu.js} +1 -1
- package/dist/assets/classDiagram-KNZD7YFC-BGmh9POF.js +1 -0
- package/dist/assets/classDiagram-v2-RKCZMP56-BGmh9POF.js +1 -0
- package/dist/assets/{clear-button-BY6Z_ViL.js → clear-button-BeoFbEKH.js} +1 -1
- package/dist/assets/clone-BFDSPAj3.js +1 -0
- package/dist/assets/command-palette-CXZiSv0I.js +1 -0
- package/dist/assets/common-C7oJcmCT.js +1 -0
- package/dist/assets/{compile-Ct_jzdKr.js → compile-7L0MwhyI.js} +1 -1
- package/dist/assets/cose-bilkent-S5V4N54A-BMkGLcVC.js +1 -0
- package/dist/assets/dagre-5GWH7T2D-BJtRienS.js +4 -0
- package/dist/assets/{data-grid-overlay-editor-BN_wulc3.js → data-grid-overlay-editor-DBkmGtNs.js} +1 -1
- package/dist/assets/datasources-panel-B7FbYLiy.js +1 -0
- package/dist/assets/{dependency-graph-panel-BOmSCZf7.js → dependency-graph-panel-DEdOxp2X.js} +4 -4
- package/dist/assets/diagram-N5W7TBWH-CmECY3nb.js +24 -0
- package/dist/assets/diagram-QEK2KX5R-DMOVSNKD.js +43 -0
- package/dist/assets/diagram-S2PKOQOG-BiJ96PNQ.js +24 -0
- package/dist/assets/{documentation-panel-BxjJO_Gw.js → documentation-panel-xULhaEv3.js} +1 -1
- package/dist/assets/edit-page-BrYda9VE.js +129 -0
- package/dist/assets/{ellipsis-vertical-UHbmjI2n.js → ellipsis-vertical-BBqXIlc2.js} +1 -1
- package/dist/assets/{empty-state-BIBXzY_0.js → empty-state-B3dA3G5P.js} +1 -1
- package/dist/assets/{erDiagram-AWTI2OKA-E84mAle_.js → erDiagram-AWTI2OKA-MP1DiFRo.js} +1 -1
- package/dist/assets/{error-panel-MEvQ6K7h.js → error-panel-Cc1sv-Ag.js} +1 -1
- package/dist/assets/file-explorer-panel-Bw59Kva1.js +1 -0
- package/dist/assets/{flowDiagram-PVAE7QVJ-DfbIRSAW.js → flowDiagram-PVAE7QVJ-BX7caPp7.js} +1 -1
- package/dist/assets/{ganttDiagram-OWAHRB6G-DR4HZ1z_.js → ganttDiagram-OWAHRB6G-B462g4Yf.js} +3 -3
- package/dist/assets/gitGraphDiagram-NY62KEGX-CGgvZ9-9.js +65 -0
- package/dist/assets/{glide-data-editor-nNmo1lPq.js → glide-data-editor-C0gUFZON.js} +4 -4
- package/dist/assets/graph-CHRVBzY5.js +1 -0
- package/dist/assets/{home-page-9eW6qida.js → home-page-Fb2osjys.js} +3 -3
- package/dist/assets/{index-DMomwMcN.js → index-BVgAenPd.js} +1 -1
- package/dist/assets/{index-B8llrTSo.js → index-BY93Ejhl.js} +1 -1
- package/dist/assets/{index-BFSnz7iM.js → index-C-8WADat.js} +1 -1
- package/dist/assets/{index-CPN7TRA1.js → index-C-GhZ7ti.js} +1 -1
- package/dist/assets/{index-DyLSuOH1.js → index-C1v_Z9et.js} +1 -1
- package/dist/assets/{index-VPWqq2Pg.js → index-C4Tn5NvJ.js} +1 -1
- package/dist/assets/{index-BAH034Ue.js → index-C77h_TXN.js} +1 -1
- package/dist/assets/{index-Dt9UWeWn.js → index-CQDrxQ0j.js} +1 -1
- package/dist/assets/{index-DWOaniGT.js → index-CWMgowgL.js} +1 -1
- package/dist/assets/{index-B1_GXGaP.js → index-Clbi_Yaq.js} +1 -1
- package/dist/assets/{index-B7yXbrLa.js → index-CpTPJo4k.js} +1 -1
- package/dist/assets/{index-CknhX2Vy.css → index-Cx0bsY1w.css} +1 -1
- package/dist/assets/{index-DqzMPAC8.js → index-D1vmG6DS.js} +2 -2
- package/dist/assets/{index-c6If577Q.js → index-D9UKkrr2.js} +1 -1
- package/dist/assets/{index-CB2pnVQG.js → index-DEQvTChO.js} +1 -1
- package/dist/assets/{index-OC46250R.js → index-DKEudB02.js} +205 -197
- package/dist/assets/{index-CSgxTUzD.js → index-DRMm6SNo.js} +1 -1
- package/dist/assets/{index-Bq516OmX.js → index-DoRmcrKM.js} +1 -1
- package/dist/assets/{index-DSU75csX.js → index-lYa_leQE.js} +1 -1
- package/dist/assets/{index-BLu5CX6z.js → index-vmICa5KN.js} +1 -1
- package/dist/assets/{index-uacyUula.js → index-z9bohSQJ.js} +1 -1
- package/dist/assets/infoDiagram-STP46IZ2-CVyrdLc8.js +2 -0
- package/dist/assets/isEmpty-DU_ogP_D.js +1 -0
- package/dist/assets/{journeyDiagram-BIP6EPQ6-BBiFyygf.js → journeyDiagram-BIP6EPQ6-C6EgLP_Q.js} +1 -1
- package/dist/assets/{kanban-definition-6OIFK2YF-DhgA6Nt6.js → kanban-definition-6OIFK2YF-BXzYO1yj.js} +4 -4
- package/dist/assets/layout-jihVw5-i.js +1 -0
- package/dist/assets/linear-C4blANlC.js +1 -0
- package/dist/assets/{links-CbvGxbsJ.js → links-D59GIweI.js} +3 -3
- package/dist/assets/{logs-panel-B9SmTZAW.js → logs-panel-D401qzZh.js} +1 -1
- package/dist/assets/markdown-renderer-Cd9eYyaL.js +263 -0
- package/dist/assets/{agent-panel-DpQ6muj-.css → markdown-renderer-ClyzDMmG.css} +1 -1
- package/dist/assets/mermaid-BEVuRz_O.js +1 -0
- package/dist/assets/{mermaid.core-4nVOEVX3.js → mermaid.core-CaSnaLH0.js} +41 -41
- package/dist/assets/min-DUMu_zeK.js +1 -0
- package/dist/assets/{mindmap-definition-Q6HEUPPD-CVLQNn1q.js → mindmap-definition-Q6HEUPPD-BXUM5MT2.js} +2 -2
- package/dist/assets/{number-overlay-editor-CzRzXLcd.js → number-overlay-editor-4uWXGlPG.js} +1 -1
- package/dist/assets/{outline-panel-uvsS-YEQ.js → outline-panel-DIzkvm2I.js} +1 -1
- package/dist/assets/packages-panel-CJL0MVlj.js +1 -0
- package/dist/assets/{pieDiagram-ADFJNKIX-C5IQ5DBZ.js → pieDiagram-ADFJNKIX-Dxt5PVNo.js} +3 -3
- package/dist/assets/{quadrantDiagram-LMRXKWRM-CFXFnQxx.js → quadrantDiagram-LMRXKWRM-D4pUaA31.js} +1 -1
- package/dist/assets/{react-plotly-mzdv02_Y.js → react-plotly-cJZ0VWBq.js} +1 -1
- package/dist/assets/{requirementDiagram-4UW4RH46-D9bPC89T.js → requirementDiagram-4UW4RH46-DVRTjgas.js} +1 -1
- package/dist/assets/run-page-BUEnMC9w.js +1 -0
- package/dist/assets/sankeyDiagram-GR3RE2ED-CVFnD9C-.js +10 -0
- package/dist/assets/scratchpad-panel-BIgRENkI.js +1 -0
- package/dist/assets/secrets-panel-xY5-V_BD.js +1 -0
- package/dist/assets/{sequenceDiagram-C3RYC4MD-6N7_hY4k.js → sequenceDiagram-C3RYC4MD-_lY4ZN_S.js} +4 -4
- package/dist/assets/{slides-component-EcjC8sDK.js → slides-component-Xjymwj7X.js} +1 -1
- package/dist/assets/snippets-panel-CTPYW41n.js +1 -0
- package/dist/assets/sortBy-BNZKwiq_.js +1 -0
- package/dist/assets/state-C4NiC9tO.js +1 -0
- package/dist/assets/stateDiagram-KXAO66HF-Da0JQWCn.js +1 -0
- package/dist/assets/stateDiagram-v2-UMBNRL4Z-D5lYZOOt.js +1 -0
- package/dist/assets/storage-CMdLzB_c.js +26 -0
- package/dist/assets/terminal-BPwTkXae.js +10 -0
- package/dist/assets/time-Dv5_Ouz_.js +1 -0
- package/dist/assets/{timeline-definition-XQNQX7LJ-BEaynAiY.js → timeline-definition-XQNQX7LJ-Dxh5Zu2e.js} +1 -1
- package/dist/assets/tracing-BCIurUfa.js +2 -0
- package/dist/assets/{tracing-panel-BmuHLPrY.js → tracing-panel-DAzrzNmm.js} +2 -2
- package/dist/assets/{trash-UBqfK4mR.js → trash-Dc6DSjz_.js} +1 -1
- package/dist/assets/{tree-XiEycetl.js → tree-jheoerAX.js} +1 -1
- package/dist/assets/{treemap-75Q7IDZK-CnuVFbBG.js → treemap-75Q7IDZK-IgpxeGaf.js} +21 -21
- package/dist/assets/{ts-tags-CloPe9IY.js → ts-tags-DxCDHihD.js} +1 -1
- package/dist/assets/variable-panel-DYAiLBmF.js +1 -0
- package/dist/assets/{vega-component-DsTH4tuX.js → vega-component-BpfpiPKI.js} +1 -1
- package/dist/assets/{xychartDiagram-6GGTOJPD-Dcz3O-A3.js → xychartDiagram-6GGTOJPD-CmNigJ31.js} +1 -1
- package/dist/index.html +2 -2
- package/package.json +8 -4
- package/src/__tests__/mocks.ts +43 -0
- package/src/components/app-config/user-config-form.tsx +32 -0
- package/src/components/chat/acp/__tests__/__snapshots__/prompt.test.ts.snap +55 -23
- package/src/components/chat/acp/__tests__/context-utils.test.ts +222 -0
- package/src/components/chat/acp/__tests__/prompt.test.ts +1 -1
- package/src/components/chat/acp/__tests__/state.test.ts +2 -6
- package/src/components/chat/acp/agent-docs.tsx +33 -6
- package/src/components/chat/acp/agent-panel.css +0 -18
- package/src/components/chat/acp/agent-panel.tsx +397 -72
- package/src/components/chat/acp/agent-selector.tsx +7 -1
- package/src/components/chat/acp/blocks.tsx +40 -10
- package/src/components/chat/acp/common.tsx +10 -2
- package/src/components/chat/acp/context-utils.ts +127 -0
- package/src/components/chat/acp/prompt.ts +34 -10
- package/src/components/chat/acp/state.ts +1 -1
- package/src/components/chat/acp/types.ts +8 -0
- package/src/components/chat/chat-panel.tsx +23 -88
- package/src/components/chat/chat-utils.ts +127 -1
- package/src/components/chat/markdown-renderer.css +39 -0
- package/src/components/chat/markdown-renderer.tsx +7 -38
- package/src/components/chat/tool-call-accordion.tsx +113 -23
- package/src/components/editor/Cell.tsx +6 -0
- package/src/components/editor/actions/name-cell-input.tsx +6 -1
- package/src/components/editor/actions/useCellActionButton.tsx +3 -1
- package/src/components/editor/ai/__tests__/completion-utils.test.ts +178 -1
- package/src/components/editor/ai/add-cell-with-ai.tsx +68 -66
- package/src/components/editor/ai/ai-completion-editor.tsx +29 -26
- package/src/components/editor/ai/completion-handlers.tsx +44 -6
- package/src/components/editor/ai/completion-utils.ts +92 -0
- package/src/components/editor/ai/transport/chat-transport.tsx +36 -0
- package/src/components/editor/cell/StagedAICell.tsx +51 -0
- package/src/components/editor/cell/cell-actions.tsx +2 -1
- package/src/components/terminal/__tests__/state.test.ts +207 -0
- package/src/components/terminal/hooks.ts +41 -0
- package/src/components/terminal/state.ts +75 -0
- package/src/components/terminal/terminal.tsx +334 -13
- package/src/components/terminal/theme.tsx +56 -0
- package/src/core/ai/__tests__/staged-cells.test.ts +356 -0
- package/src/core/ai/staged-cells.ts +208 -0
- package/src/core/cells/cells.ts +1 -1
- package/src/core/codemirror/lsp/federated-lsp.ts +1 -1
- package/src/core/islands/main.ts +2 -2
- package/src/core/kernel/messages.ts +8 -12
- package/src/core/saving/__tests__/filename.test.ts +37 -0
- package/src/core/static/__tests__/download-html.test.ts +43 -1
- package/src/core/websocket/useMarimoWebSocket.tsx +2 -2
- package/src/css/app/Cell.css +11 -0
- package/src/plugins/core/RenderHTML.tsx +36 -2
- package/src/plugins/core/__test__/RenderHTML.test.ts +72 -0
- package/src/plugins/core/registerReactComponent.tsx +28 -0
- package/src/plugins/impl/FileBrowserPlugin.tsx +8 -2
- package/src/stories/cell.stories.tsx +1 -1
- package/src/stories/layout/vertical/one-column.stories.tsx +1 -1
- package/src/utils/__tests__/cell-urls.test.ts +29 -0
- package/src/utils/__tests__/filenames.test.ts +18 -0
- package/src/utils/__tests__/path.test.ts +38 -0
- package/src/utils/__tests__/urls.test.ts +56 -1
- package/src/utils/errors.ts +9 -0
- package/dist/assets/_baseEach-C1FLm7WW.js +0 -1
- package/dist/assets/_baseMap-DBVArUYD.js +0 -1
- package/dist/assets/_baseUniq-Dk7ZPJ3N.js +0 -1
- package/dist/assets/_createAggregator-Bn38fDd3.js +0 -1
- package/dist/assets/agent-panel-COUYnuIK.js +0 -475
- package/dist/assets/architectureDiagram-W76B3OCA-DBzWQKKu.js +0 -36
- package/dist/assets/channel-CjhbjOv4.js +0 -1
- package/dist/assets/chat-panel-BPXKoTnZ.js +0 -7
- package/dist/assets/chat-panel-Brrs_eeH.css +0 -1
- package/dist/assets/classDiagram-KNZD7YFC-DHs5cFzy.js +0 -1
- package/dist/assets/classDiagram-v2-RKCZMP56-DHs5cFzy.js +0 -1
- package/dist/assets/clone-DM1YNjEn.js +0 -1
- package/dist/assets/command-palette-S0bzQp7v.js +0 -1
- package/dist/assets/common-B8U9k2Ly.js +0 -1
- package/dist/assets/cose-bilkent-S5V4N54A-wz1Sfx7j.js +0 -1
- package/dist/assets/dagre-5GWH7T2D-BfpcVBgq.js +0 -4
- package/dist/assets/datasources-panel-DfuURLJw.js +0 -1
- package/dist/assets/diagram-N5W7TBWH-Bf0oqqQh.js +0 -24
- package/dist/assets/diagram-QEK2KX5R-ZTc3qikh.js +0 -43
- package/dist/assets/diagram-S2PKOQOG-tLScBy7Z.js +0 -24
- package/dist/assets/edit-page-DJ8kJZ9w.js +0 -129
- package/dist/assets/file-explorer-panel-CzNUJ63G.js +0 -1
- package/dist/assets/gitGraphDiagram-NY62KEGX-C1t6QtVa.js +0 -65
- package/dist/assets/graph-CssCVWIq.js +0 -1
- package/dist/assets/index-DcCIe7np.js +0 -28
- package/dist/assets/infoDiagram-STP46IZ2-CwiAoz9f.js +0 -2
- package/dist/assets/layout-DpQrxGW-.js +0 -1
- package/dist/assets/linear-NsreOeBF.js +0 -1
- package/dist/assets/mermaid-DSt0r6IQ.js +0 -1
- package/dist/assets/min-D259kI3t.js +0 -1
- package/dist/assets/packages-panel-xMz9W2hW.js +0 -1
- package/dist/assets/run-page-Bb68qdhQ.js +0 -1
- package/dist/assets/sankeyDiagram-GR3RE2ED-BSJOau8E.js +0 -10
- package/dist/assets/scratchpad-panel-BF4BO-U4.js +0 -1
- package/dist/assets/secrets-panel-CdIX44dQ.js +0 -1
- package/dist/assets/snippets-panel-Dco9h0rb.js +0 -1
- package/dist/assets/sortBy-aLGA-PGK.js +0 -1
- package/dist/assets/stateDiagram-KXAO66HF-Bd68WT3b.js +0 -1
- package/dist/assets/stateDiagram-v2-UMBNRL4Z-BXz_GSwb.js +0 -1
- package/dist/assets/storage-CGlP4lCF.js +0 -26
- package/dist/assets/terminal-CxkHubcu.js +0 -9
- package/dist/assets/time-D2nr1UgQ.js +0 -1
- package/dist/assets/tracing-kTqHxa7q.js +0 -2
- package/dist/assets/variable-panel-noTnH-AQ.js +0 -1
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
/* Copyright 2024 Marimo. All rights reserved. */
|
|
2
2
|
|
|
3
|
-
import type {
|
|
3
|
+
import type { components } from "@marimo-team/marimo-api";
|
|
4
|
+
import type { FileUIPart, ToolUIPart, UIMessage } from "ai";
|
|
5
|
+
import type {
|
|
6
|
+
InvokeAiToolRequest,
|
|
7
|
+
InvokeAiToolResponse,
|
|
8
|
+
} from "@/core/network/types";
|
|
9
|
+
import type { ChatMessage } from "@/plugins/impl/chat/types";
|
|
4
10
|
import { blobToString } from "@/utils/fileToBase64";
|
|
11
|
+
import { Logger } from "@/utils/Logger";
|
|
12
|
+
import { getAICompletionBodyWithAttachments } from "../editor/ai/completion-utils";
|
|
5
13
|
|
|
6
14
|
export function generateChatTitle(message: string): string {
|
|
7
15
|
return message.length > 50 ? `${message.slice(0, 50)}...` : message;
|
|
@@ -48,3 +56,121 @@ export function isLastMessageReasoning(messages: UIMessage[]): boolean {
|
|
|
48
56
|
const lastPart = parts[parts.length - 1];
|
|
49
57
|
return lastPart.type === "reasoning";
|
|
50
58
|
}
|
|
59
|
+
|
|
60
|
+
function stringifyTextParts(parts: UIMessage["parts"]): string {
|
|
61
|
+
return parts
|
|
62
|
+
.map((part) => (part.type === "text" ? part.text : ""))
|
|
63
|
+
.join("\n");
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export async function buildCompletionRequestBody(
|
|
67
|
+
messages: UIMessage[],
|
|
68
|
+
): Promise<{
|
|
69
|
+
messages: ChatMessage[];
|
|
70
|
+
context?: (null | components["schemas"]["AiCompletionContext"]) | undefined;
|
|
71
|
+
includeOtherCode: string;
|
|
72
|
+
selectedText?: string | null | undefined;
|
|
73
|
+
}> {
|
|
74
|
+
const input = stringifyTextParts(messages.flatMap((m) => m.parts));
|
|
75
|
+
const completionBody = await getAICompletionBodyWithAttachments({ input });
|
|
76
|
+
|
|
77
|
+
// Map from UIMessage to our ChatMessage type
|
|
78
|
+
// If it's the last message, add the attachments from the completion body
|
|
79
|
+
function toChatMessage(message: UIMessage, isLast: boolean): ChatMessage {
|
|
80
|
+
// Clone parts to avoid mutating the original message
|
|
81
|
+
const parts = [...message.parts];
|
|
82
|
+
if (isLast) {
|
|
83
|
+
parts.push(...completionBody.attachments);
|
|
84
|
+
}
|
|
85
|
+
return {
|
|
86
|
+
role: message.role,
|
|
87
|
+
content: stringifyTextParts(message.parts), // This is no longer used in the backend
|
|
88
|
+
parts,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return {
|
|
93
|
+
...completionBody.body,
|
|
94
|
+
messages: messages.map((m, idx) =>
|
|
95
|
+
toChatMessage(m, idx === messages.length - 1),
|
|
96
|
+
),
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
interface AddToolResult {
|
|
101
|
+
tool: string;
|
|
102
|
+
toolCallId: string;
|
|
103
|
+
output: unknown;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export async function handleToolCall({
|
|
107
|
+
invokeAiTool,
|
|
108
|
+
addToolResult,
|
|
109
|
+
toolCall,
|
|
110
|
+
}: {
|
|
111
|
+
invokeAiTool: (request: InvokeAiToolRequest) => Promise<InvokeAiToolResponse>;
|
|
112
|
+
addToolResult: (result: AddToolResult) => Promise<void>;
|
|
113
|
+
toolCall: {
|
|
114
|
+
toolName: string;
|
|
115
|
+
toolCallId: string;
|
|
116
|
+
input: Record<string, never>;
|
|
117
|
+
};
|
|
118
|
+
}) {
|
|
119
|
+
try {
|
|
120
|
+
const response = await invokeAiTool({
|
|
121
|
+
toolName: toolCall.toolName,
|
|
122
|
+
arguments: toolCall.input,
|
|
123
|
+
});
|
|
124
|
+
addToolResult({
|
|
125
|
+
tool: toolCall.toolName,
|
|
126
|
+
toolCallId: toolCall.toolCallId,
|
|
127
|
+
output: response.result || response.error,
|
|
128
|
+
});
|
|
129
|
+
} catch (error) {
|
|
130
|
+
Logger.error("Tool call failed:", error);
|
|
131
|
+
addToolResult({
|
|
132
|
+
tool: toolCall.toolName,
|
|
133
|
+
toolCallId: toolCall.toolCallId,
|
|
134
|
+
output: `Error: ${error instanceof Error ? error.message : String(error)}`,
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Checks if we should send a message automatically based on the messages.
|
|
141
|
+
* We only want to send a message if we have completed tool calls and there is no reply yet.
|
|
142
|
+
*/
|
|
143
|
+
export function hasPendingToolCalls(messages: UIMessage[]): boolean {
|
|
144
|
+
if (messages.length === 0) {
|
|
145
|
+
return false;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const lastMessage = messages[messages.length - 1];
|
|
149
|
+
const parts = lastMessage.parts;
|
|
150
|
+
|
|
151
|
+
if (parts.length === 0) {
|
|
152
|
+
return false;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Only auto-send if the last message is an assistant message
|
|
156
|
+
// Because assistant messages are the ones that can have tool calls
|
|
157
|
+
if (lastMessage.role !== "assistant") {
|
|
158
|
+
return false;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const toolParts = parts.filter((part) =>
|
|
162
|
+
part.type.startsWith("tool-"),
|
|
163
|
+
) as ToolUIPart[];
|
|
164
|
+
|
|
165
|
+
const hasCompletedToolCalls = toolParts.some(
|
|
166
|
+
(part) => part.state === "output-available",
|
|
167
|
+
);
|
|
168
|
+
|
|
169
|
+
// Check if the last part has any text content
|
|
170
|
+
const lastPart = parts[parts.length - 1];
|
|
171
|
+
const hasTextContent =
|
|
172
|
+
lastPart.type === "text" && lastPart.text?.trim().length > 0;
|
|
173
|
+
|
|
174
|
+
// Only auto-send if we have completed tool calls and there is no reply yet
|
|
175
|
+
return hasCompletedToolCalls && !hasTextContent;
|
|
176
|
+
}
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
+
@source "../../../node_modules/streamdown/dist/index.js";
|
|
2
|
+
|
|
1
3
|
.mo-markdown-renderer {
|
|
4
|
+
/* Make headers a bit smaller */
|
|
5
|
+
--text-2xl: 1rem;
|
|
6
|
+
--text-3xl: 1.2rem;
|
|
7
|
+
|
|
2
8
|
h1,
|
|
3
9
|
h2,
|
|
4
10
|
h3,
|
|
@@ -12,4 +18,37 @@
|
|
|
12
18
|
margin-top: 8px;
|
|
13
19
|
margin-bottom: 12px;
|
|
14
20
|
}
|
|
21
|
+
|
|
22
|
+
pre {
|
|
23
|
+
width: 100%;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
[data-code-block-container="true"] {
|
|
27
|
+
margin-top: 0 !important;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
[data-code-block-header="true"] {
|
|
31
|
+
padding: 4px !important;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
code {
|
|
35
|
+
font-size: inherit !important;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
li.task-list-item {
|
|
39
|
+
list-style-type: none;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
li {
|
|
43
|
+
padding-left: 6px;
|
|
44
|
+
|
|
45
|
+
> input {
|
|
46
|
+
margin-right: 6px;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
ul,
|
|
51
|
+
ol {
|
|
52
|
+
padding-left: 10px;
|
|
53
|
+
}
|
|
15
54
|
}
|
|
@@ -3,10 +3,8 @@
|
|
|
3
3
|
import { EditorView } from "@codemirror/view";
|
|
4
4
|
import { useAtomValue } from "jotai";
|
|
5
5
|
import { BetweenHorizontalStartIcon } from "lucide-react";
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import Markdown, { type Components } from "react-markdown";
|
|
9
|
-
import remarkGfm from "remark-gfm";
|
|
6
|
+
import { memo, Suspense, useEffect, useState } from "react";
|
|
7
|
+
import { Streamdown, type StreamdownProps } from "streamdown";
|
|
10
8
|
import { Button, type ButtonProps } from "@/components/ui/button";
|
|
11
9
|
import { maybeAddMarimoImport } from "@/core/cells/add-missing-import";
|
|
12
10
|
import { useCellActions } from "@/core/cells/cells";
|
|
@@ -171,6 +169,8 @@ const CopyButton: React.FC<ButtonProps> = ({ onClick, ...props }) => {
|
|
|
171
169
|
);
|
|
172
170
|
};
|
|
173
171
|
|
|
172
|
+
type Components = StreamdownProps["components"];
|
|
173
|
+
|
|
174
174
|
const COMPONENTS: Components = {
|
|
175
175
|
code: ({ children, className }) => {
|
|
176
176
|
const language = className?.replace("language-", "");
|
|
@@ -186,42 +186,11 @@ const COMPONENTS: Components = {
|
|
|
186
186
|
},
|
|
187
187
|
};
|
|
188
188
|
|
|
189
|
-
function parseMarkdownIntoBlocks(markdown: string): string[] {
|
|
190
|
-
const tokens = marked.lexer(markdown);
|
|
191
|
-
return tokens.map((token) => token.raw);
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
const PLUGINS = [remarkGfm];
|
|
195
|
-
|
|
196
|
-
const MemoizedMarkdownBlock = memo(
|
|
197
|
-
({ content }: { content: string }) => {
|
|
198
|
-
return (
|
|
199
|
-
<Markdown
|
|
200
|
-
components={COMPONENTS}
|
|
201
|
-
remarkPlugins={PLUGINS}
|
|
202
|
-
className="mo-markdown-renderer prose dark:prose-invert max-w-none prose-pre:pl-0"
|
|
203
|
-
>
|
|
204
|
-
{content}
|
|
205
|
-
</Markdown>
|
|
206
|
-
);
|
|
207
|
-
},
|
|
208
|
-
(prevProps, nextProps) => prevProps.content === nextProps.content,
|
|
209
|
-
);
|
|
210
|
-
|
|
211
|
-
MemoizedMarkdownBlock.displayName = "MemoizedMarkdownBlock";
|
|
212
|
-
|
|
213
189
|
export const MarkdownRenderer = memo(({ content }: { content: string }) => {
|
|
214
|
-
const blocks = useMemo(() => parseMarkdownIntoBlocks(content), [content]);
|
|
215
|
-
|
|
216
190
|
return (
|
|
217
|
-
|
|
218
|
-
{
|
|
219
|
-
|
|
220
|
-
content={block}
|
|
221
|
-
key={`markdown-block-${index}`}
|
|
222
|
-
/>
|
|
223
|
-
))}
|
|
224
|
-
</>
|
|
191
|
+
<Streamdown components={COMPONENTS} className="mo-markdown-renderer">
|
|
192
|
+
{content}
|
|
193
|
+
</Streamdown>
|
|
225
194
|
);
|
|
226
195
|
});
|
|
227
196
|
MarkdownRenderer.displayName = "MarkdownRenderer";
|
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
/* Copyright 2024 Marimo. All rights reserved. */
|
|
2
2
|
|
|
3
3
|
import type { ToolUIPart } from "ai";
|
|
4
|
+
import { isEmpty } from "lodash-es";
|
|
4
5
|
import {
|
|
5
6
|
CheckCircleIcon,
|
|
7
|
+
InfoIcon,
|
|
6
8
|
Loader2,
|
|
7
9
|
WrenchIcon,
|
|
8
10
|
XCircleIcon,
|
|
9
11
|
} from "lucide-react";
|
|
10
12
|
import React from "react";
|
|
13
|
+
import { z } from "zod";
|
|
11
14
|
import {
|
|
12
15
|
Accordion,
|
|
13
16
|
AccordionContent,
|
|
@@ -16,12 +19,101 @@ import {
|
|
|
16
19
|
} from "@/components/ui/accordion";
|
|
17
20
|
import { cn } from "@/utils/cn";
|
|
18
21
|
|
|
22
|
+
// Zod schema matching the Python SuccessResult dataclass
|
|
23
|
+
const SuccessResultSchema = z
|
|
24
|
+
.object({
|
|
25
|
+
status: z.string().default("success"),
|
|
26
|
+
auth_required: z.boolean().default(false),
|
|
27
|
+
action_url: z.any(),
|
|
28
|
+
next_steps: z.any(),
|
|
29
|
+
meta: z.any(),
|
|
30
|
+
message: z.string().nullish(),
|
|
31
|
+
})
|
|
32
|
+
.passthrough();
|
|
33
|
+
|
|
34
|
+
type SuccessResult = z.infer<typeof SuccessResultSchema>;
|
|
35
|
+
|
|
36
|
+
const PrettySuccessResult: React.FC<{ data: SuccessResult }> = ({ data }) => {
|
|
37
|
+
const {
|
|
38
|
+
status,
|
|
39
|
+
auth_required,
|
|
40
|
+
action_url: _action_url,
|
|
41
|
+
meta: _meta,
|
|
42
|
+
next_steps: _next_steps,
|
|
43
|
+
message,
|
|
44
|
+
...rest
|
|
45
|
+
} = data;
|
|
46
|
+
|
|
47
|
+
return (
|
|
48
|
+
<div className="py-1 flex flex-col gap-1">
|
|
49
|
+
{/* Status */}
|
|
50
|
+
<div className="flex items-center gap-2">
|
|
51
|
+
<span className="text-xs font-medium text-[var(--grass-11)] capitalize">
|
|
52
|
+
{status}
|
|
53
|
+
</span>
|
|
54
|
+
{auth_required && (
|
|
55
|
+
<span className="text-xs px-2 py-0.5 bg-[var(--amber-2)] text-[var(--amber-11)] rounded-full">
|
|
56
|
+
Auth Required
|
|
57
|
+
</span>
|
|
58
|
+
)}
|
|
59
|
+
</div>
|
|
60
|
+
|
|
61
|
+
{/* Message */}
|
|
62
|
+
{message && (
|
|
63
|
+
<div className="flex items-start gap-2">
|
|
64
|
+
<InfoIcon className="h-3 w-3 text-[var(--blue-11)] mt-0.5 flex-shrink-0" />
|
|
65
|
+
<div className="text-xs text-foreground">{message}</div>
|
|
66
|
+
</div>
|
|
67
|
+
)}
|
|
68
|
+
|
|
69
|
+
{/* Data */}
|
|
70
|
+
{rest && (
|
|
71
|
+
<div className="flex flex-col gap-1">
|
|
72
|
+
{Object.entries(rest).map(([key, value]) => {
|
|
73
|
+
if (isEmpty(value)) {
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
return (
|
|
77
|
+
<div key={key}>
|
|
78
|
+
<div className="text-xs font-medium text-muted-foreground mb-1 capitalize">
|
|
79
|
+
{key}:
|
|
80
|
+
</div>
|
|
81
|
+
<pre className="bg-[var(--slate-2)] p-1 text-muted-foreground border border-[var(--slate-4)] rounded text-xs overflow-auto scrollbar-thin max-h-64">
|
|
82
|
+
{JSON.stringify(value, null, 2)}
|
|
83
|
+
</pre>
|
|
84
|
+
</div>
|
|
85
|
+
);
|
|
86
|
+
})}
|
|
87
|
+
</div>
|
|
88
|
+
)}
|
|
89
|
+
</div>
|
|
90
|
+
);
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
const ResultRenderer: React.FC<{ result: unknown }> = ({ result }) => {
|
|
94
|
+
// Try to parse the result with our Zod schema
|
|
95
|
+
const parseResult = SuccessResultSchema.safeParse(result);
|
|
96
|
+
|
|
97
|
+
if (parseResult.success) {
|
|
98
|
+
// If it matches the SuccessResult schema, show the pretty UI
|
|
99
|
+
return <PrettySuccessResult data={parseResult.data} />;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Otherwise, fall back to the current JSON viewer
|
|
103
|
+
return (
|
|
104
|
+
<div className="text-xs font-medium text-muted-foreground mb-1">
|
|
105
|
+
{typeof result === "string" ? result : JSON.stringify(result, null, 2)}
|
|
106
|
+
</div>
|
|
107
|
+
);
|
|
108
|
+
};
|
|
109
|
+
|
|
19
110
|
interface ToolCallAccordionProps {
|
|
20
111
|
toolName: string;
|
|
21
112
|
result: unknown;
|
|
22
113
|
error?: string;
|
|
23
114
|
index?: number;
|
|
24
115
|
state?: ToolUIPart["state"];
|
|
116
|
+
className?: string;
|
|
25
117
|
}
|
|
26
118
|
|
|
27
119
|
export const ToolCallAccordion: React.FC<ToolCallAccordionProps> = ({
|
|
@@ -30,6 +122,7 @@ export const ToolCallAccordion: React.FC<ToolCallAccordionProps> = ({
|
|
|
30
122
|
error,
|
|
31
123
|
index = 0,
|
|
32
124
|
state,
|
|
125
|
+
className,
|
|
33
126
|
}) => {
|
|
34
127
|
const hasResult = state === "output-available" && (result || error);
|
|
35
128
|
const status = error ? "error" : hasResult ? "success" : "loading";
|
|
@@ -39,9 +132,9 @@ export const ToolCallAccordion: React.FC<ToolCallAccordionProps> = ({
|
|
|
39
132
|
case "loading":
|
|
40
133
|
return <Loader2 className="h-3 w-3 animate-spin" />;
|
|
41
134
|
case "error":
|
|
42
|
-
return <XCircleIcon className="h-3 w-3 text-
|
|
135
|
+
return <XCircleIcon className="h-3 w-3 text-[var(--red-11)]" />;
|
|
43
136
|
case "success":
|
|
44
|
-
return <CheckCircleIcon className="h-3 w-3 text-
|
|
137
|
+
return <CheckCircleIcon className="h-3 w-3 text-[var(--grass-11)]" />;
|
|
45
138
|
default:
|
|
46
139
|
return <WrenchIcon className="h-3 w-3" />;
|
|
47
140
|
}
|
|
@@ -49,13 +142,13 @@ export const ToolCallAccordion: React.FC<ToolCallAccordionProps> = ({
|
|
|
49
142
|
|
|
50
143
|
const getStatusText = () => {
|
|
51
144
|
if (status === "loading") {
|
|
52
|
-
return "Running
|
|
145
|
+
return "Running";
|
|
53
146
|
}
|
|
54
147
|
if (error) {
|
|
55
|
-
return "Failed
|
|
148
|
+
return "Failed";
|
|
56
149
|
}
|
|
57
150
|
if (hasResult) {
|
|
58
|
-
return "Done
|
|
151
|
+
return "Done";
|
|
59
152
|
}
|
|
60
153
|
return "Tool call";
|
|
61
154
|
};
|
|
@@ -65,20 +158,22 @@ export const ToolCallAccordion: React.FC<ToolCallAccordionProps> = ({
|
|
|
65
158
|
key={`tool-${index}`}
|
|
66
159
|
type="single"
|
|
67
160
|
collapsible={true}
|
|
68
|
-
className="w-full"
|
|
161
|
+
className={cn("w-full", className)}
|
|
69
162
|
>
|
|
70
163
|
<AccordionItem value="tool-call" className="border-0">
|
|
71
164
|
<AccordionTrigger
|
|
72
165
|
className={cn(
|
|
73
|
-
"h-6 text-xs border-border shadow-none! ring-0! bg-muted hover:bg-muted
|
|
74
|
-
status === "error" && "text-
|
|
75
|
-
status === "success" && "text-
|
|
166
|
+
"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",
|
|
167
|
+
status === "error" && "text-[var(--red-11)]/80",
|
|
168
|
+
status === "success" && "text-[var(--grass-11)]/80",
|
|
76
169
|
)}
|
|
77
170
|
>
|
|
78
171
|
<span className="flex items-center gap-1">
|
|
79
172
|
{getStatusIcon()}
|
|
80
|
-
{getStatusText()}:
|
|
81
|
-
<code className="font-mono text-xs">
|
|
173
|
+
{getStatusText()}:
|
|
174
|
+
<code className="font-mono text-xs">
|
|
175
|
+
{formatToolName(toolName)}
|
|
176
|
+
</code>
|
|
82
177
|
</span>
|
|
83
178
|
</AccordionTrigger>
|
|
84
179
|
<AccordionContent className="pb-2 px-2">
|
|
@@ -86,25 +181,16 @@ export const ToolCallAccordion: React.FC<ToolCallAccordionProps> = ({
|
|
|
86
181
|
{hasResult && (
|
|
87
182
|
<div className="space-y-3">
|
|
88
183
|
{result !== undefined && result !== null && (
|
|
89
|
-
<
|
|
90
|
-
<div className="text-xs font-medium text-muted-foreground mt-2 mb-1">
|
|
91
|
-
Result:
|
|
92
|
-
</div>
|
|
93
|
-
<div className="text-xs font-medium text-muted-foreground mb-1">
|
|
94
|
-
{typeof result === "string"
|
|
95
|
-
? result
|
|
96
|
-
: JSON.stringify(result, null, 2)}
|
|
97
|
-
</div>
|
|
98
|
-
</div>
|
|
184
|
+
<ResultRenderer result={result} />
|
|
99
185
|
)}
|
|
100
186
|
|
|
101
187
|
{/* Error */}
|
|
102
188
|
{error && (
|
|
103
189
|
<div>
|
|
104
|
-
<div className="text-xs font-medium text-
|
|
190
|
+
<div className="text-xs font-medium text-[var(--red-11)] mb-1">
|
|
105
191
|
Error:
|
|
106
192
|
</div>
|
|
107
|
-
<div className="bg-
|
|
193
|
+
<div className="bg-[var(--red-2)] border border-[var(--red-6)] rounded-md p-3 text-sm text-[var(--red-11)]">
|
|
108
194
|
{error}
|
|
109
195
|
</div>
|
|
110
196
|
</div>
|
|
@@ -116,3 +202,7 @@ export const ToolCallAccordion: React.FC<ToolCallAccordionProps> = ({
|
|
|
116
202
|
</Accordion>
|
|
117
203
|
);
|
|
118
204
|
};
|
|
205
|
+
|
|
206
|
+
function formatToolName(toolName: string) {
|
|
207
|
+
return toolName.replace("tool-", "");
|
|
208
|
+
}
|
|
@@ -72,6 +72,10 @@ import { CollapsedCellBanner, CollapseToggle } from "./cell/collapse";
|
|
|
72
72
|
import { DeleteButton } from "./cell/DeleteButton";
|
|
73
73
|
import { PendingDeleteConfirmation } from "./cell/PendingDeleteConfirmation";
|
|
74
74
|
import { RunButton } from "./cell/RunButton";
|
|
75
|
+
import {
|
|
76
|
+
StagedAICellBackground,
|
|
77
|
+
StagedAICellFooter,
|
|
78
|
+
} from "./cell/StagedAICell";
|
|
75
79
|
import { useDeleteCellCallback } from "./cell/useDeleteCell";
|
|
76
80
|
import { useRunCell } from "./cell/useRunCells";
|
|
77
81
|
import { HideCodeButton } from "./code/readonly-python-code";
|
|
@@ -571,6 +575,7 @@ const EditableCellComponent = ({
|
|
|
571
575
|
>
|
|
572
576
|
{cellOutput === "above" && outputArea}
|
|
573
577
|
<div className={cn("tray")} data-hidden={isMarkdownCodeHidden}>
|
|
578
|
+
<StagedAICellBackground cellId={cellId} />
|
|
574
579
|
<div className="absolute right-2 -top-4 z-10">
|
|
575
580
|
<CellToolbar
|
|
576
581
|
edited={cellData.edited}
|
|
@@ -729,6 +734,7 @@ const EditableCellComponent = ({
|
|
|
729
734
|
/>
|
|
730
735
|
<PendingDeleteConfirmation cellId={cellId} />
|
|
731
736
|
</div>
|
|
737
|
+
<StagedAICellFooter cellId={cellId} />
|
|
732
738
|
{isCollapsed && (
|
|
733
739
|
<CollapsedCellBanner
|
|
734
740
|
onClick={() => actions.expandCell({ cellId })}
|
|
@@ -19,12 +19,14 @@ interface Props
|
|
|
19
19
|
value: string;
|
|
20
20
|
onChange: (newName: string) => void;
|
|
21
21
|
placeholder?: string;
|
|
22
|
+
onEnterKey?: () => void;
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
export const NameCellInput: React.FC<Props> = ({
|
|
25
26
|
value,
|
|
26
27
|
onChange,
|
|
27
28
|
placeholder,
|
|
29
|
+
onEnterKey,
|
|
28
30
|
...props
|
|
29
31
|
}) => {
|
|
30
32
|
const ref = useRef<HTMLInputElement>(null);
|
|
@@ -53,7 +55,10 @@ export const NameCellInput: React.FC<Props> = ({
|
|
|
53
55
|
ref={ref}
|
|
54
56
|
placeholder={placeholder}
|
|
55
57
|
className="shadow-none! hover:shadow-none focus:shadow-none focus-visible:shadow-none"
|
|
56
|
-
onKeyDown={Events.onEnter(
|
|
58
|
+
onKeyDown={Events.onEnter((e) => {
|
|
59
|
+
Events.stopPropagation()(e);
|
|
60
|
+
onEnterKey?.();
|
|
61
|
+
})}
|
|
57
62
|
{...props}
|
|
58
63
|
/>
|
|
59
64
|
);
|
|
@@ -73,9 +73,10 @@ export interface CellActionButtonProps
|
|
|
73
73
|
|
|
74
74
|
interface Props {
|
|
75
75
|
cell: CellActionButtonProps | null;
|
|
76
|
+
closePopover?: () => void;
|
|
76
77
|
}
|
|
77
78
|
|
|
78
|
-
export function useCellActionButtons({ cell }: Props) {
|
|
79
|
+
export function useCellActionButtons({ cell, closePopover }: Props) {
|
|
79
80
|
const {
|
|
80
81
|
createNewCell: createCell,
|
|
81
82
|
updateCellConfig,
|
|
@@ -177,6 +178,7 @@ export function useCellActionButtons({ cell }: Props) {
|
|
|
177
178
|
placeholder={"cell name"}
|
|
178
179
|
value={name}
|
|
179
180
|
onChange={(newName) => updateCellName({ cellId, name: newName })}
|
|
181
|
+
onEnterKey={() => closePopover?.()}
|
|
180
182
|
/>
|
|
181
183
|
),
|
|
182
184
|
},
|