@marimo-team/islands 0.23.7-dev9 → 0.23.7-dev90
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-DnRhpPMJ.js → ConnectedDataExplorerComponent-2lBNiUv6.js} +13 -13
- package/dist/{ErrorBoundary-Da4UeYxT.js → ErrorBoundary-D3wrPNma.js} +1 -1
- package/dist/{any-language-editor-DDubl8YH.js → any-language-editor-VWs_7v27.js} +5 -5
- package/dist/assets/__vite-browser-external-CAdMKBac.js +1 -0
- package/dist/assets/worker-CpBbwbQo.js +73 -0
- package/dist/{button-CA5pI2YF.js → button-Dj4BTre0.js} +5 -0
- package/dist/{capabilities-6laDasij.js → capabilities-C9rrYCzf.js} +1 -1
- package/dist/{chat-ui-BmWZZ3mE.js → chat-ui-D3XBept8.js} +625 -233
- package/dist/{check-CFM2mVDr.js → check-BcUIXnUT.js} +1 -1
- package/dist/{code-visibility-CRHzv49w.js → code-visibility-C5NrPsUC.js} +11480 -1992
- package/dist/{copy-TGGAUEWp.js → copy-DLf4aN7I.js} +2 -2
- package/dist/{dist-ESg7xyoD.js → dist-D3ZI9nhS.js} +2 -2
- package/dist/{error-banner-DnBPzEWg.js → error-banner-CVkfBUT3.js} +2 -2
- package/dist/{esm-Dd1z1auZ.js → esm-CWp0KQeK.js} +1 -1
- package/dist/{extends-CzJgxo2J.js → extends-vAi97cpa.js} +4 -4
- package/dist/{formats-CgaK7Gmx.js → formats-Dsy9kkZu.js} +3 -3
- package/dist/{glide-data-editor-B-3A3G02.js → glide-data-editor-DucgdjRo.js} +9 -9
- package/dist/{html-to-image-BwZL1Pkk.js → html-to-image-CpggM7u1.js} +2667 -2408
- package/dist/{input-BAOe64zx.js → input-D4kjoQUB.js} +8 -6
- package/dist/{label-BCWi-Oqu.js → label-BLqV33b1.js} +2 -2
- package/dist/{loader-BvW0-YWZ.js → loader-Dr8Qem8p.js} +1 -1
- package/dist/main.js +1697 -10282
- package/dist/{mermaid-cXSZ1pfD.js → mermaid-DO-Daq7u.js} +5 -5
- package/dist/{process-output-lpVrk7d5.js → process-output-X8TR20AK.js} +3 -3
- package/dist/reveal-component-kMIwe09M.js +7447 -0
- package/dist/{spec-DSIuqd3f.js → spec-hVaaZsY5.js} +4 -4
- package/dist/{strings-B_FOH6eV.js → strings-BiIhGaI8.js} +4 -4
- package/dist/style.css +1 -1
- package/dist/{swiper-component-BHs0PWwp.js → swiper-component-DlD2GU2g.js} +2 -2
- package/dist/{toDate-CHtl9vts.js → toDate-CIpC_34u.js} +33 -20
- package/dist/{tooltip-B0mtKTXm.js → tooltip-DRaMBu06.js} +3 -3
- package/dist/{types-DBtDeUKD.js → types-Dzuoc3LN.js} +1 -1
- package/dist/{useAsyncData-B6hCGywC.js → useAsyncData-C56Khv_R.js} +1 -1
- package/dist/{useDateFormatter-B3mCQMP3.js → useDateFormatter-B_9k85Ex.js} +2 -2
- package/dist/{useDeepCompareMemoize-CmwDuYUH.js → useDeepCompareMemoize-Dt98v2ua.js} +1 -1
- package/dist/{useIframeCapabilities-DbdLoEDm.js → useIframeCapabilities-BkYHTrss.js} +1 -1
- package/dist/{useLifecycle-CjMjllqy.js → useLifecycle-BF6-z62y.js} +3 -3
- package/dist/{useTheme-CByZUW0p.js → useTheme-DykuNHR2.js} +2 -2
- package/dist/{vega-component-C2BYPkfd.js → vega-component-cSdqoAxe.js} +10 -10
- package/dist/{zod-BxdsqRPd.js → zod-BWkcDORu.js} +1 -1
- package/package.json +3 -3
- package/src/components/chat/chat-components.tsx +47 -0
- package/src/components/chat/chat-display.tsx +41 -7
- package/src/components/chat/chat-panel.tsx +37 -10
- package/src/components/chat/chat-utils.ts +42 -20
- package/src/components/chat/reasoning-accordion.tsx +14 -3
- package/src/components/chat/tool-call/shared.ts +13 -0
- package/src/components/chat/tool-call/tool-approval-card.tsx +62 -0
- package/src/components/chat/tool-call/tool-args.tsx +26 -0
- package/src/components/chat/tool-call/tool-call-view.tsx +99 -0
- package/src/components/chat/tool-call/tool-error-card.tsx +81 -0
- package/src/components/chat/tool-call/tool-history-row.tsx +153 -0
- package/src/components/chat/tool-call/tool-result.tsx +101 -0
- package/src/components/data-table/__tests__/column-header.test.ts +3 -1
- package/src/components/data-table/__tests__/column-header.test.tsx +308 -0
- package/src/components/data-table/__tests__/filter-by-values-picker.test.tsx +112 -0
- package/src/components/data-table/__tests__/filter-pill-editor.test.tsx +261 -0
- package/src/components/data-table/__tests__/filters.test.ts +196 -49
- package/src/components/data-table/charts/components/form-fields.tsx +1 -0
- package/src/components/data-table/column-header.tsx +349 -170
- package/src/components/data-table/date-filter-inputs.tsx +325 -0
- package/src/components/data-table/filter-by-values-picker.tsx +70 -9
- package/src/components/data-table/filter-pill-editor.tsx +410 -156
- package/src/components/data-table/filter-pills.tsx +69 -54
- package/src/components/data-table/filters.ts +218 -101
- package/src/components/data-table/header-items.tsx +8 -1
- package/src/components/data-table/operator-labels.ts +25 -0
- package/src/components/data-table/regex-input.tsx +61 -0
- package/src/components/dependency-graph/minimap-content.tsx +14 -3
- package/src/components/editor/actions/pair-with-agent-modal.tsx +140 -49
- package/src/components/editor/actions/useNotebookActions.tsx +3 -1
- package/src/components/editor/app-container.tsx +7 -1
- package/src/components/editor/chrome/panels/context-aware-panel/context-aware-panel.tsx +10 -2
- package/src/components/editor/chrome/wrapper/app-chrome.tsx +1 -0
- package/src/components/editor/chrome/wrapper/footer-items/backend-status.tsx +1 -1
- package/src/components/editor/chrome/wrapper/footer.tsx +4 -1
- package/src/components/editor/chrome/wrapper/panels.tsx +4 -1
- package/src/components/editor/chrome/wrapper/sidebar.tsx +4 -1
- package/src/components/editor/controls/Controls.tsx +11 -3
- package/src/components/editor/file-tree/file-explorer.tsx +12 -2
- package/src/components/editor/header/__tests__/status.test.tsx +108 -0
- package/src/components/editor/header/status.tsx +44 -10
- package/src/components/editor/navigation/__tests__/clipboard.test.ts +106 -0
- package/src/components/editor/navigation/__tests__/navigation.test.ts +70 -0
- package/src/components/editor/navigation/clipboard.ts +99 -25
- package/src/components/editor/navigation/navigation.ts +15 -1
- package/src/components/editor/notebook-cell.tsx +5 -0
- package/src/components/editor/output/console/ConsoleOutput.tsx +23 -5
- package/src/components/editor/output/console/__tests__/ConsoleOutput.test.tsx +114 -0
- package/src/components/editor/renderers/slides-layout/__tests__/compute-slide-cells.test.ts +5 -4
- package/src/components/editor/renderers/slides-layout/__tests__/plugin.test.ts +55 -15
- package/src/components/editor/renderers/slides-layout/plugin.tsx +8 -25
- package/src/components/editor/renderers/slides-layout/slides-layout.tsx +19 -6
- package/src/components/editor/renderers/slides-layout/types.ts +40 -31
- package/src/components/editor/renderers/vertical-layout/vertical-layout.tsx +1 -0
- package/src/components/home/components.tsx +6 -0
- package/src/components/pages/run-page.tsx +4 -1
- package/src/components/scratchpad/scratchpad.tsx +1 -0
- package/src/components/slides/__tests__/slide-notes.test.ts +131 -0
- package/src/components/slides/reveal-component.tsx +252 -147
- package/src/components/slides/slide-notes-editor.tsx +127 -0
- package/src/components/slides/slide-notes.ts +64 -0
- package/src/components/slides/slides.css +14 -0
- package/src/components/ui/combobox.tsx +24 -5
- package/src/components/ui/number-field.tsx +2 -0
- package/src/core/ai/tools/__tests__/registry.test.ts +10 -12
- package/src/core/ai/tools/registry.ts +9 -5
- package/src/core/cells/__tests__/cells.test.ts +187 -0
- package/src/core/cells/__tests__/pending-cut-service.test.tsx +123 -0
- package/src/core/cells/cells.ts +102 -17
- package/src/core/cells/document-changes.ts +6 -1
- package/src/core/cells/pending-cut-service.ts +55 -0
- package/src/core/cells/utils.ts +11 -0
- package/src/core/codemirror/cells/extensions.ts +10 -0
- package/src/core/codemirror/go-to-definition/__tests__/commands.test.ts +152 -0
- package/src/core/codemirror/go-to-definition/__tests__/utils.test.ts +99 -0
- package/src/core/codemirror/go-to-definition/commands.ts +382 -22
- package/src/core/codemirror/go-to-definition/utils.ts +23 -5
- package/src/core/edit-app.tsx +3 -2
- package/src/core/hotkeys/hotkeys.ts +5 -0
- package/src/core/islands/worker/worker.tsx +3 -2
- package/src/core/run-app.tsx +2 -1
- package/src/core/runtime/__tests__/runtime.test.ts +38 -17
- package/src/core/runtime/runtime.ts +57 -34
- package/src/core/wasm/__tests__/utils.test.ts +34 -0
- package/src/core/wasm/utils.ts +14 -0
- package/src/core/wasm/worker/bootstrap.ts +3 -2
- package/src/core/wasm/worker/worker.ts +3 -2
- package/src/core/websocket/__tests__/useMarimoKernelConnection.hook.test.tsx +156 -0
- package/src/core/websocket/__tests__/useMarimoKernelConnection.test.ts +101 -0
- package/src/core/websocket/transports/__tests__/ws.test.ts +125 -0
- package/src/core/websocket/transports/basic.ts +1 -1
- package/src/core/websocket/transports/ws.ts +96 -0
- package/src/core/websocket/useMarimoKernelConnection.tsx +133 -54
- package/src/core/websocket/useWebSocket.tsx +3 -15
- package/src/css/app/Cell.css +10 -0
- package/src/plugins/core/__test__/sanitize.test.ts +30 -0
- package/src/plugins/impl/DropdownPlugin.tsx +12 -1
- package/src/plugins/impl/MultiselectPlugin.tsx +4 -0
- package/src/plugins/impl/SearchableSelect.tsx +11 -1
- package/src/plugins/impl/TabsPlugin.tsx +35 -7
- package/src/plugins/impl/__tests__/DropdownPlugin.test.tsx +56 -0
- package/src/plugins/impl/__tests__/TabsPlugin.test.tsx +154 -0
- package/src/plugins/impl/data-frames/forms/__tests__/__snapshots__/form.test.tsx.snap +48 -36
- package/src/plugins/impl/data-frames/schema.ts +4 -1
- package/src/plugins/layout/DownloadPlugin.tsx +9 -7
- package/src/utils/__tests__/id-tree.test.ts +71 -0
- package/src/utils/download.ts +4 -2
- package/src/utils/id-tree.tsx +89 -0
- package/dist/assets/__vite-browser-external-rrUYDKRl.js +0 -1
- package/dist/assets/worker-Bfy15ViQ.js +0 -73
- package/dist/reveal-component-C97Ceb7e.js +0 -4863
- package/src/components/chat/tool-call-accordion.tsx +0 -247
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { s as __toESM } from "./chunk-BNovOVIE.js";
|
|
2
|
-
import { g as cn, l as useEventListener, t as Button } from "./button-
|
|
2
|
+
import { g as cn, l as useEventListener, t as Button } from "./button-Dj4BTre0.js";
|
|
3
3
|
import { t as require_react } from "./react-DA-nE2FX.js";
|
|
4
4
|
import { t as require_compiler_runtime } from "./compiler-runtime-CEbnTgxf.js";
|
|
5
5
|
import { t as require_jsx_runtime } from "./jsx-runtime-COBk7ree.js";
|
|
6
|
-
import { t as useIframeCapabilities } from "./useIframeCapabilities-
|
|
6
|
+
import { t as useIframeCapabilities } from "./useIframeCapabilities-BkYHTrss.js";
|
|
7
7
|
var import_compiler_runtime = require_compiler_runtime(), import_react = /* @__PURE__ */ __toESM(require_react(), 1);
|
|
8
8
|
function isObject$2(t2) {
|
|
9
9
|
return typeof t2 == "object" && !!t2 && "constructor" in t2 && t2.constructor === Object;
|
|
@@ -2,11 +2,11 @@ var __defProp = Object.defineProperty;
|
|
|
2
2
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
3
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
4
4
|
import { t as __commonJSMin } from "./chunk-BNovOVIE.js";
|
|
5
|
-
import { _ as Logger } from "./button-
|
|
5
|
+
import { _ as Logger } from "./button-Dj4BTre0.js";
|
|
6
6
|
import { t as require_compiler_runtime } from "./compiler-runtime-CEbnTgxf.js";
|
|
7
|
-
import { u as createLucideIcon } from "./dist-
|
|
7
|
+
import { u as createLucideIcon } from "./dist-D3ZI9nhS.js";
|
|
8
8
|
import { r as KnownQueryParams } from "./constants-D0gkYoE2.js";
|
|
9
|
-
import { f as waitFor, p as isIslands, u as store, y as atom } from "./useTheme-
|
|
9
|
+
import { f as waitFor, p as isIslands, u as store, y as atom } from "./useTheme-DykuNHR2.js";
|
|
10
10
|
import { t as invariant } from "./invariant-UcGKQEhF.js";
|
|
11
11
|
var CircleQuestionMark = createLucideIcon("circle-question-mark", [
|
|
12
12
|
["circle", {
|
|
@@ -512,15 +512,21 @@ var RuntimeManager = class {
|
|
|
512
512
|
get isSameOrigin() {
|
|
513
513
|
return this.httpURL.origin === window.location.origin;
|
|
514
514
|
}
|
|
515
|
-
|
|
516
|
-
|
|
515
|
+
get isServerless() {
|
|
516
|
+
return isWasm() || isIslands() || isStaticNotebook();
|
|
517
|
+
}
|
|
518
|
+
formatHttpURL({ path: e = "", searchParams: b, restrictToKnownQueryParams: x = true }) {
|
|
517
519
|
let S = this.httpURL, w = new URLSearchParams(window.location.search);
|
|
518
520
|
if (b) for (let [e2, x2] of b.entries()) S.searchParams.set(e2, x2);
|
|
519
521
|
for (let [e2, b2] of w.entries()) x && !Object.values(KnownQueryParams).includes(e2) || S.searchParams.set(e2, b2);
|
|
520
522
|
return S.pathname = `${S.pathname.replace(/\/$/, "")}/${e.replace(/^\//, "")}`, S.hash = "", S;
|
|
521
523
|
}
|
|
522
524
|
formatWsURL(e, b) {
|
|
523
|
-
let x = this.formatHttpURL(
|
|
525
|
+
let x = this.formatHttpURL({
|
|
526
|
+
path: e,
|
|
527
|
+
searchParams: b,
|
|
528
|
+
restrictToKnownQueryParams: false
|
|
529
|
+
});
|
|
524
530
|
return !this.isSameOrigin && this.config.authToken && x.searchParams.set(KnownQueryParams.accessToken, this.config.authToken), asWsUrl(x.toString());
|
|
525
531
|
}
|
|
526
532
|
getWsURL(e) {
|
|
@@ -546,26 +552,33 @@ var RuntimeManager = class {
|
|
|
546
552
|
return this.formatWsURL(`/lsp/${e}`);
|
|
547
553
|
}
|
|
548
554
|
getAiURL(e) {
|
|
549
|
-
return this.formatHttpURL(`/api/ai/${e}`);
|
|
555
|
+
return this.formatHttpURL({ path: `/api/ai/${e}` });
|
|
550
556
|
}
|
|
551
557
|
healthURL() {
|
|
552
|
-
return this.formatHttpURL("/health");
|
|
558
|
+
return this.formatHttpURL({ path: "/health" });
|
|
553
559
|
}
|
|
554
|
-
async
|
|
555
|
-
if (isWasm() || isIslands() || isStaticNotebook()) return true;
|
|
560
|
+
async fetchHealth() {
|
|
556
561
|
try {
|
|
557
|
-
|
|
558
|
-
if (e.redirected) {
|
|
559
|
-
Logger.debug(`Runtime redirected to ${e.url}`);
|
|
560
|
-
let x2 = new URL(e.url);
|
|
561
|
-
x2.pathname = x2.pathname.replace(/\/health$/, ""), this.config.url = x2.toString();
|
|
562
|
-
}
|
|
563
|
-
let x = e.ok;
|
|
564
|
-
return x && this.setDOMBaseUri(this.config.url), x;
|
|
562
|
+
return await fetch(this.healthURL().toString());
|
|
565
563
|
} catch (e) {
|
|
566
|
-
return Logger.error(`Failed to check health: ${e instanceof Error ? e.message : "Unknown error"}`, { cause: e }),
|
|
564
|
+
return Logger.error(`Failed to check health: ${e instanceof Error ? e.message : "Unknown error"}`, { cause: e }), null;
|
|
567
565
|
}
|
|
568
566
|
}
|
|
567
|
+
async reconcileFromHealth() {
|
|
568
|
+
if (this.isServerless) return true;
|
|
569
|
+
let e = await this.fetchHealth();
|
|
570
|
+
if (!e) return false;
|
|
571
|
+
if (e.redirected) {
|
|
572
|
+
Logger.debug(`Runtime redirected to ${e.url}`);
|
|
573
|
+
let x = new URL(e.url);
|
|
574
|
+
x.pathname = x.pathname.replace(/\/health$/, ""), this.config.url = x.toString();
|
|
575
|
+
}
|
|
576
|
+
return e.ok && this.setDOMBaseUri(this.config.url), e.ok;
|
|
577
|
+
}
|
|
578
|
+
async probeHealth() {
|
|
579
|
+
var _a;
|
|
580
|
+
return this.isServerless ? true : ((_a = await this.fetchHealth()) == null ? void 0 : _a.ok) ?? false;
|
|
581
|
+
}
|
|
569
582
|
setDOMBaseUri(e) {
|
|
570
583
|
e = e.split("?", 1)[0], e.endsWith("/") || (e += "/");
|
|
571
584
|
let b = document.querySelector("base");
|
|
@@ -574,7 +587,7 @@ var RuntimeManager = class {
|
|
|
574
587
|
async init(e) {
|
|
575
588
|
Logger.debug("Initializing runtime...");
|
|
576
589
|
let x = 0;
|
|
577
|
-
for (; !await this.
|
|
590
|
+
for (; !await this.reconcileFromHealth(); ) {
|
|
578
591
|
if (x >= 25) {
|
|
579
592
|
Logger.error("Failed to connect after 25 retries"), this.initialHealthyCheck.reject(/* @__PURE__ */ Error("Failed to connect after 25 retries"));
|
|
580
593
|
return;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { s as __toESM } from "./chunk-BNovOVIE.js";
|
|
2
|
-
import { f as createSlottable, g as cn, m as useComposedRefs } from "./button-
|
|
2
|
+
import { f as createSlottable, g as cn, m as useComposedRefs } from "./button-Dj4BTre0.js";
|
|
3
3
|
import { t as require_react } from "./react-DA-nE2FX.js";
|
|
4
4
|
import { t as require_compiler_runtime } from "./compiler-runtime-CEbnTgxf.js";
|
|
5
|
-
import { a as createPopperScope, i as Root2, n as Arrow, r as Content, s as Root, t as Anchor } from "./dist-
|
|
5
|
+
import { a as createPopperScope, i as Root2, n as Arrow, r as Content, s as Root, t as Anchor } from "./dist-D3ZI9nhS.js";
|
|
6
6
|
import { t as require_jsx_runtime } from "./jsx-runtime-COBk7ree.js";
|
|
7
|
-
import { $ as StyleNamespace, X as withFullScreenAsRoot, Z as withSmartCollisionBoundary, _t as Primitive, dt as Presence, ft as useControllableState, gt as createContextScope, it as Portal, mt as composeEventHandlers, st as DismissableLayer, ut as useId } from "./zod-
|
|
7
|
+
import { $ as StyleNamespace, X as withFullScreenAsRoot, Z as withSmartCollisionBoundary, _t as Primitive, dt as Presence, ft as useControllableState, gt as createContextScope, it as Portal, mt as composeEventHandlers, st as DismissableLayer, ut as useId } from "./zod-BWkcDORu.js";
|
|
8
8
|
var import_react = /* @__PURE__ */ __toESM(require_react(), 1), import_jsx_runtime = /* @__PURE__ */ __toESM(require_jsx_runtime(), 1), [createTooltipContext, createTooltipScope] = createContextScope("Tooltip", [createPopperScope]), usePopperScope = createPopperScope(), PROVIDER_NAME = "TooltipProvider", DEFAULT_DELAY_DURATION = 700, TOOLTIP_OPEN = "tooltip.open", [TooltipProviderContextProvider, useTooltipProviderContext] = createTooltipContext(PROVIDER_NAME), TooltipProvider$1 = (n) => {
|
|
9
9
|
let { __scopeTooltip: j, delayDuration: M = DEFAULT_DELAY_DURATION, skipDelayDuration: N = 300, disableHoverableContent: P = false, children: F } = n, I = import_react.useRef(true), L = import_react.useRef(false), R = import_react.useRef(0);
|
|
10
10
|
return import_react.useEffect(() => {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { u as createLucideIcon } from "./dist-
|
|
1
|
+
import { u as createLucideIcon } from "./dist-D3ZI9nhS.js";
|
|
2
2
|
var Pencil = createLucideIcon("pencil", [["path", {
|
|
3
3
|
d: "M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z",
|
|
4
4
|
key: "1a8usu"
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { s as __toESM } from "./chunk-BNovOVIE.js";
|
|
2
2
|
import { t as require_react } from "./react-DA-nE2FX.js";
|
|
3
3
|
import { t as require_compiler_runtime } from "./compiler-runtime-CEbnTgxf.js";
|
|
4
|
-
import { w as useEvent_default } from "./useTheme-
|
|
4
|
+
import { w as useEvent_default } from "./useTheme-DykuNHR2.js";
|
|
5
5
|
import { t as invariant } from "./invariant-UcGKQEhF.js";
|
|
6
6
|
var import_compiler_runtime = require_compiler_runtime(), import_react = /* @__PURE__ */ __toESM(require_react(), 1), Result = {
|
|
7
7
|
error(e, s) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { s as __toESM } from "./chunk-BNovOVIE.js";
|
|
2
2
|
import { t as require_react } from "./react-DA-nE2FX.js";
|
|
3
|
-
import { u as createLucideIcon } from "./dist-
|
|
4
|
-
import { T as $18f2051aff69b9bf$export$43bb16f9c6d9e3f7 } from "./strings-
|
|
3
|
+
import { u as createLucideIcon } from "./dist-D3ZI9nhS.js";
|
|
4
|
+
import { T as $18f2051aff69b9bf$export$43bb16f9c6d9e3f7 } from "./strings-BiIhGaI8.js";
|
|
5
5
|
var ChartPie = createLucideIcon("chart-pie", [["path", {
|
|
6
6
|
d: "M21 12c.552 0 1.005-.449.95-.998a10 10 0 0 0-8.953-8.951c-.55-.055-.998.398-.998.95v8a1 1 0 0 0 1 1z",
|
|
7
7
|
key: "pzmjnu"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { s as __toESM } from "./chunk-BNovOVIE.js";
|
|
2
2
|
import { t as require_react } from "./react-DA-nE2FX.js";
|
|
3
|
-
import { C as dequal } from "./useTheme-
|
|
3
|
+
import { C as dequal } from "./useTheme-DykuNHR2.js";
|
|
4
4
|
var import_react = /* @__PURE__ */ __toESM(require_react(), 1);
|
|
5
5
|
function useDeepCompareMemoize(e) {
|
|
6
6
|
let i = import_react.useRef(e);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { s as __toESM } from "./chunk-BNovOVIE.js";
|
|
2
2
|
import { t as require_react } from "./react-DA-nE2FX.js";
|
|
3
3
|
import { t as require_compiler_runtime } from "./compiler-runtime-CEbnTgxf.js";
|
|
4
|
-
import { t as getIframeCapabilities } from "./capabilities-
|
|
4
|
+
import { t as getIframeCapabilities } from "./capabilities-C9rrYCzf.js";
|
|
5
5
|
var import_compiler_runtime = require_compiler_runtime();
|
|
6
6
|
require_react();
|
|
7
7
|
function useIframeCapabilities() {
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { s as __toESM } from "./chunk-BNovOVIE.js";
|
|
2
|
-
import { _ as Logger, g as cn, r as cva } from "./button-
|
|
2
|
+
import { _ as Logger, g as cn, r as cva } from "./button-Dj4BTre0.js";
|
|
3
3
|
import { t as require_react } from "./react-DA-nE2FX.js";
|
|
4
4
|
import { t as require_compiler_runtime } from "./compiler-runtime-CEbnTgxf.js";
|
|
5
|
-
import { u as createLucideIcon } from "./dist-
|
|
5
|
+
import { u as createLucideIcon } from "./dist-D3ZI9nhS.js";
|
|
6
6
|
import { t as require_jsx_runtime } from "./jsx-runtime-COBk7ree.js";
|
|
7
|
-
import { _ as useSetAtom, y as atom } from "./useTheme-
|
|
7
|
+
import { _ as useSetAtom, y as atom } from "./useTheme-DykuNHR2.js";
|
|
8
8
|
var Calendar = createLucideIcon("calendar", [
|
|
9
9
|
["path", {
|
|
10
10
|
d: "M8 2v4",
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { s as __toESM } from "./chunk-BNovOVIE.js";
|
|
2
|
-
import { _ as Logger, a as OverridingHotkeyProvider, s as resolvePlatform } from "./button-
|
|
2
|
+
import { _ as Logger, a as OverridingHotkeyProvider, s as resolvePlatform } from "./button-Dj4BTre0.js";
|
|
3
3
|
import { t as require_react } from "./react-DA-nE2FX.js";
|
|
4
4
|
import { t as require_compiler_runtime } from "./compiler-runtime-CEbnTgxf.js";
|
|
5
|
-
import { A as looseObject, B as union, I as record, N as number, P as object, R as string, T as boolean, b as _enum, w as array } from "./zod-
|
|
5
|
+
import { A as looseObject, B as union, I as record, N as number, P as object, R as string, T as boolean, b as _enum, w as array } from "./zod-BWkcDORu.js";
|
|
6
6
|
import { t as merge_default } from "./merge-CHn7Yx0N.js";
|
|
7
7
|
var import_react = /* @__PURE__ */ __toESM(require_react()), useInsertionEffect = typeof window < "u" ? import_react.useInsertionEffect || import_react.useLayoutEffect : () => {
|
|
8
8
|
};
|
|
@@ -1,24 +1,24 @@
|
|
|
1
1
|
import { s as __toESM } from "./chunk-BNovOVIE.js";
|
|
2
|
-
import { _ as Logger, c as Objects, g as cn, h as Events } from "./button-
|
|
2
|
+
import { _ as Logger, c as Objects, g as cn, h as Events } from "./button-Dj4BTre0.js";
|
|
3
3
|
import { t as require_react } from "./react-DA-nE2FX.js";
|
|
4
4
|
import { t as require_compiler_runtime } from "./compiler-runtime-CEbnTgxf.js";
|
|
5
|
-
import { c as asRemoteURL, v as CircleQuestionMark } from "./toDate-
|
|
5
|
+
import { c as asRemoteURL, v as CircleQuestionMark } from "./toDate-CIpC_34u.js";
|
|
6
6
|
import "./react-dom-BWRJ_g_k.js";
|
|
7
7
|
import { t as require_jsx_runtime } from "./jsx-runtime-COBk7ree.js";
|
|
8
|
-
import "./zod-
|
|
9
|
-
import { n as ErrorBanner } from "./error-banner-
|
|
10
|
-
import { t as Tooltip } from "./tooltip-
|
|
8
|
+
import "./zod-BWkcDORu.js";
|
|
9
|
+
import { n as ErrorBanner } from "./error-banner-CVkfBUT3.js";
|
|
10
|
+
import { t as Tooltip } from "./tooltip-DRaMBu06.js";
|
|
11
11
|
import { i as debounce_default } from "./constants-D0gkYoE2.js";
|
|
12
|
-
import { n as useTheme, w as useEvent_default } from "./useTheme-
|
|
12
|
+
import { n as useTheme, w as useEvent_default } from "./useTheme-DykuNHR2.js";
|
|
13
13
|
import { s as uniq } from "./arrays-CldYf7p7.js";
|
|
14
|
-
import { a as isValid, i as AlertTitle, n as Alert, t as arrow } from "./formats-
|
|
14
|
+
import { a as isValid, i as AlertTitle, n as Alert, t as arrow } from "./formats-Dsy9kkZu.js";
|
|
15
15
|
import { n as formats } from "./vega-loader.browser-3_z8GoFC.js";
|
|
16
|
-
import { a as getContainerWidth, n as vegaLoadData, s as tooltipHandler } from "./loader-
|
|
17
|
-
import { t as useAsyncData } from "./useAsyncData-
|
|
16
|
+
import { a as getContainerWidth, n as vegaLoadData, s as tooltipHandler } from "./loader-Dr8Qem8p.js";
|
|
17
|
+
import { t as useAsyncData } from "./useAsyncData-C56Khv_R.js";
|
|
18
18
|
import { t as j } from "./react-vega-Dh6-UKKe.js";
|
|
19
19
|
import "./defaultLocale-BpsHxBd7.js";
|
|
20
20
|
import "./defaultLocale-DoeErsX2.js";
|
|
21
|
-
import { t as useDeepCompareMemoize } from "./useDeepCompareMemoize-
|
|
21
|
+
import { t as useDeepCompareMemoize } from "./useDeepCompareMemoize-Dt98v2ua.js";
|
|
22
22
|
import { t as Semaphore } from "./semaphore-CNDGTzkX.js";
|
|
23
23
|
var import_compiler_runtime = require_compiler_runtime(), import_react = /* @__PURE__ */ __toESM(require_react(), 1);
|
|
24
24
|
function fixRelativeUrl(e) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { r as __export, s as __toESM } from "./chunk-BNovOVIE.js";
|
|
2
|
-
import { d as createSlot, l as useEventListener, m as useComposedRefs } from "./button-
|
|
2
|
+
import { d as createSlot, l as useEventListener, m as useComposedRefs } from "./button-Dj4BTre0.js";
|
|
3
3
|
import { t as require_react } from "./react-DA-nE2FX.js";
|
|
4
4
|
import { t as require_compiler_runtime } from "./compiler-runtime-CEbnTgxf.js";
|
|
5
5
|
import { t as require_react_dom } from "./react-dom-BWRJ_g_k.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@marimo-team/islands",
|
|
3
|
-
"version": "0.23.7-
|
|
3
|
+
"version": "0.23.7-dev90",
|
|
4
4
|
"main": "dist/main.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"type": "module",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"./unstable_internal/*": "./src/*"
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@ai-sdk/react": "^3.0.
|
|
24
|
+
"@ai-sdk/react": "^3.0.134",
|
|
25
25
|
"@anywidget/types": "^0.2.0",
|
|
26
26
|
"@codemirror/autocomplete": "^6.20.1",
|
|
27
27
|
"@codemirror/commands": "^6.10.2",
|
|
@@ -120,7 +120,7 @@
|
|
|
120
120
|
"lz-string": "^1.5.0",
|
|
121
121
|
"marked": "^15.0.12",
|
|
122
122
|
"mermaid": "^11.12.3",
|
|
123
|
-
"partysocket": "1.1.
|
|
123
|
+
"partysocket": "1.1.13",
|
|
124
124
|
"path-to-regexp": "^8.4.0",
|
|
125
125
|
"plotly.js": "^3.3.1",
|
|
126
126
|
"pyodide": "0.27.7",
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
} from "lucide-react";
|
|
14
14
|
import { useState } from "react";
|
|
15
15
|
import { cn } from "@/utils/cn";
|
|
16
|
+
import { isUrl } from "@/utils/urls";
|
|
16
17
|
import { Spinner } from "../icons/spinner";
|
|
17
18
|
import { Button } from "../ui/button";
|
|
18
19
|
import { Input } from "../ui/input";
|
|
@@ -182,3 +183,49 @@ function renderFileIcon(file: File): React.ReactNode {
|
|
|
182
183
|
|
|
183
184
|
return <FileIcon className={classNames} />;
|
|
184
185
|
}
|
|
186
|
+
|
|
187
|
+
export const SourceChip = ({
|
|
188
|
+
icon,
|
|
189
|
+
title,
|
|
190
|
+
subtitle,
|
|
191
|
+
href,
|
|
192
|
+
}: {
|
|
193
|
+
icon: React.ReactNode;
|
|
194
|
+
title: string;
|
|
195
|
+
subtitle?: string;
|
|
196
|
+
href?: string;
|
|
197
|
+
}) => {
|
|
198
|
+
const content = (
|
|
199
|
+
<>
|
|
200
|
+
{icon}
|
|
201
|
+
<span className="truncate font-medium">{title}</span>
|
|
202
|
+
{subtitle && <span className="truncate opacity-70">({subtitle})</span>}
|
|
203
|
+
</>
|
|
204
|
+
);
|
|
205
|
+
|
|
206
|
+
const className =
|
|
207
|
+
"inline-flex max-w-full items-center gap-1.5 rounded-md border bg-muted/50 px-2 py-1 my-1 text-xs text-muted-foreground";
|
|
208
|
+
|
|
209
|
+
// Only treat absolute http(s) URLs as safe to render as a clickable link.
|
|
210
|
+
// Source URLs come from model output (e.g. citations) and could otherwise
|
|
211
|
+
// smuggle in `javascript:`/`data:` schemes.
|
|
212
|
+
if (href && isUrl(href)) {
|
|
213
|
+
return (
|
|
214
|
+
<a
|
|
215
|
+
href={href}
|
|
216
|
+
target="_blank"
|
|
217
|
+
rel="noopener noreferrer"
|
|
218
|
+
title={subtitle ?? title}
|
|
219
|
+
className={`${className} hover:bg-muted hover:text-foreground transition-colors`}
|
|
220
|
+
>
|
|
221
|
+
{content}
|
|
222
|
+
</a>
|
|
223
|
+
);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
return (
|
|
227
|
+
<div className={className} title={subtitle ?? title}>
|
|
228
|
+
{content}
|
|
229
|
+
</div>
|
|
230
|
+
);
|
|
231
|
+
};
|
|
@@ -1,23 +1,31 @@
|
|
|
1
1
|
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
2
|
|
|
3
|
-
import type {
|
|
3
|
+
import type {
|
|
4
|
+
ChatAddToolApproveResponseFunction,
|
|
5
|
+
DataUIPart,
|
|
6
|
+
ToolUIPart,
|
|
7
|
+
UIMessage,
|
|
8
|
+
} from "ai";
|
|
9
|
+
import { ExternalLinkIcon, FileTextIcon } from "lucide-react";
|
|
4
10
|
import React from "react";
|
|
5
11
|
import { renderHTML } from "@/plugins/core/RenderHTML";
|
|
6
12
|
import { logNever } from "@/utils/assertNever";
|
|
7
13
|
import { Logger } from "@/utils/Logger";
|
|
8
14
|
import { MarkdownRenderer } from "../markdown/markdown-renderer";
|
|
9
|
-
import { AttachmentRenderer } from "./chat-components";
|
|
15
|
+
import { AttachmentRenderer, SourceChip } from "./chat-components";
|
|
10
16
|
import { ReasoningAccordion } from "./reasoning-accordion";
|
|
11
|
-
import {
|
|
17
|
+
import { ToolCallView } from "./tool-call/tool-call-view";
|
|
12
18
|
|
|
13
19
|
export const renderUIMessage = ({
|
|
14
20
|
message,
|
|
15
21
|
isStreamingReasoning,
|
|
16
22
|
isLast,
|
|
23
|
+
addToolApprovalResponse,
|
|
17
24
|
}: {
|
|
18
25
|
message: UIMessage;
|
|
19
26
|
isStreamingReasoning: boolean;
|
|
20
27
|
isLast: boolean;
|
|
28
|
+
addToolApprovalResponse?: ChatAddToolApproveResponseFunction;
|
|
21
29
|
}) => {
|
|
22
30
|
return (
|
|
23
31
|
<>{message.parts.map((part, index) => renderUIMessagePart(part, index))}</>
|
|
@@ -29,14 +37,18 @@ export const renderUIMessage = ({
|
|
|
29
37
|
) {
|
|
30
38
|
if (isToolPart(part)) {
|
|
31
39
|
return (
|
|
32
|
-
<
|
|
40
|
+
<ToolCallView
|
|
33
41
|
key={index}
|
|
34
42
|
index={index}
|
|
35
43
|
toolName={part.type}
|
|
36
44
|
result={part.output}
|
|
45
|
+
errorText={part.state === "output-error" ? part.errorText : undefined}
|
|
37
46
|
className="my-2"
|
|
38
47
|
state={part.state}
|
|
39
48
|
input={part.input}
|
|
49
|
+
approval={part.approval}
|
|
50
|
+
onApprove={addToolApprovalResponse}
|
|
51
|
+
isLive={isLast}
|
|
40
52
|
/>
|
|
41
53
|
);
|
|
42
54
|
}
|
|
@@ -69,7 +81,7 @@ export const renderUIMessage = ({
|
|
|
69
81
|
isStreaming={
|
|
70
82
|
isStreamingReasoning &&
|
|
71
83
|
isLast &&
|
|
72
|
-
// If there are multiple reasoning parts, only
|
|
84
|
+
// If there are multiple reasoning parts, only stream the last one
|
|
73
85
|
index === (message.parts.length || 0) - 1
|
|
74
86
|
}
|
|
75
87
|
/>
|
|
@@ -78,18 +90,40 @@ export const renderUIMessage = ({
|
|
|
78
90
|
return <AttachmentRenderer attachment={part} key={index} />;
|
|
79
91
|
case "dynamic-tool":
|
|
80
92
|
return (
|
|
81
|
-
<
|
|
93
|
+
<ToolCallView
|
|
82
94
|
key={index}
|
|
83
95
|
toolName={part.toolName}
|
|
84
96
|
result={part.output}
|
|
97
|
+
errorText={
|
|
98
|
+
part.state === "output-error" ? part.errorText : undefined
|
|
99
|
+
}
|
|
85
100
|
state={part.state}
|
|
86
101
|
input={part.input}
|
|
102
|
+
approval={part.approval}
|
|
103
|
+
onApprove={addToolApprovalResponse}
|
|
104
|
+
isLive={isLast}
|
|
87
105
|
/>
|
|
88
106
|
);
|
|
89
107
|
case "source-document":
|
|
108
|
+
return (
|
|
109
|
+
<SourceChip
|
|
110
|
+
key={index}
|
|
111
|
+
icon={<FileTextIcon className="h-3 w-3 shrink-0" />}
|
|
112
|
+
title={part.title}
|
|
113
|
+
subtitle={part.filename}
|
|
114
|
+
/>
|
|
115
|
+
);
|
|
90
116
|
case "source-url":
|
|
117
|
+
return (
|
|
118
|
+
<SourceChip
|
|
119
|
+
key={index}
|
|
120
|
+
icon={<ExternalLinkIcon className="h-3 w-3 shrink-0" />}
|
|
121
|
+
title={part.title ?? part.url}
|
|
122
|
+
subtitle={part.title ? part.url : undefined}
|
|
123
|
+
href={part.url}
|
|
124
|
+
/>
|
|
125
|
+
);
|
|
91
126
|
case "step-start":
|
|
92
|
-
Logger.debug("Found non-renderable part", part);
|
|
93
127
|
return null;
|
|
94
128
|
default:
|
|
95
129
|
logNever(part);
|
|
@@ -4,7 +4,13 @@ import type { UIMessage } from "@ai-sdk/react";
|
|
|
4
4
|
import { useChat } from "@ai-sdk/react";
|
|
5
5
|
import { storePrompt } from "@marimo-team/codemirror-ai";
|
|
6
6
|
import type { ReactCodeMirrorRef } from "@uiw/react-codemirror";
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
type ChatAddToolApproveResponseFunction,
|
|
9
|
+
DefaultChatTransport,
|
|
10
|
+
type FileUIPart,
|
|
11
|
+
safeValidateUIMessages,
|
|
12
|
+
type TextUIPart,
|
|
13
|
+
} from "ai";
|
|
8
14
|
import { useAtom, useAtomValue, useSetAtom, useStore } from "jotai";
|
|
9
15
|
import {
|
|
10
16
|
BotMessageSquareIcon,
|
|
@@ -131,10 +137,18 @@ interface ChatMessageProps {
|
|
|
131
137
|
onEdit: (index: number, newValue: string) => void;
|
|
132
138
|
isStreamingReasoning: boolean;
|
|
133
139
|
isLast: boolean;
|
|
140
|
+
addToolApprovalResponse?: ChatAddToolApproveResponseFunction;
|
|
134
141
|
}
|
|
135
142
|
|
|
136
143
|
const ChatMessageDisplay: React.FC<ChatMessageProps> = memo(
|
|
137
|
-
({
|
|
144
|
+
({
|
|
145
|
+
message,
|
|
146
|
+
index,
|
|
147
|
+
onEdit,
|
|
148
|
+
isStreamingReasoning,
|
|
149
|
+
isLast,
|
|
150
|
+
addToolApprovalResponse,
|
|
151
|
+
}) => {
|
|
138
152
|
const renderUserMessage = (message: UIMessage) => {
|
|
139
153
|
const textParts = message.parts?.filter(
|
|
140
154
|
(p): p is TextUIPart => p.type === "text",
|
|
@@ -181,7 +195,12 @@ const ChatMessageDisplay: React.FC<ChatMessageProps> = memo(
|
|
|
181
195
|
<div className="absolute right-1 top-1 opacity-0 group-hover:opacity-100 transition-opacity">
|
|
182
196
|
<CopyClipboardIcon className="h-3 w-3" value={content || ""} />
|
|
183
197
|
</div>
|
|
184
|
-
{renderUIMessage({
|
|
198
|
+
{renderUIMessage({
|
|
199
|
+
message,
|
|
200
|
+
isStreamingReasoning,
|
|
201
|
+
isLast,
|
|
202
|
+
addToolApprovalResponse,
|
|
203
|
+
})}
|
|
185
204
|
</div>
|
|
186
205
|
);
|
|
187
206
|
};
|
|
@@ -458,6 +477,7 @@ const ChatPanelBody = () => {
|
|
|
458
477
|
regenerate,
|
|
459
478
|
stop,
|
|
460
479
|
addToolOutput,
|
|
480
|
+
addToolApprovalResponse,
|
|
461
481
|
id: chatId,
|
|
462
482
|
} = useChat({
|
|
463
483
|
id: activeChatId,
|
|
@@ -467,6 +487,19 @@ const ChatPanelBody = () => {
|
|
|
467
487
|
api: runtimeManager.getAiURL("chat").toString(),
|
|
468
488
|
headers: () => runtimeManager.headers(),
|
|
469
489
|
prepareSendMessagesRequest: async (options) => {
|
|
490
|
+
// Canary: flag outgoing messages that don't match the AI SDK's own
|
|
491
|
+
// schema. The server-side sanitizer in `_pydantic_ai_utils.py` corrects these before validation;
|
|
492
|
+
// this log surfaces drift early without affecting the request.
|
|
493
|
+
const validation = await safeValidateUIMessages({
|
|
494
|
+
messages: options.messages,
|
|
495
|
+
});
|
|
496
|
+
if (!validation.success) {
|
|
497
|
+
Logger.debug(
|
|
498
|
+
"Outgoing chat messages failed AI SDK schema validation",
|
|
499
|
+
validation.error,
|
|
500
|
+
);
|
|
501
|
+
}
|
|
502
|
+
|
|
470
503
|
const completionBody = await buildCompletionRequestBody(
|
|
471
504
|
options.messages,
|
|
472
505
|
);
|
|
@@ -495,13 +528,6 @@ const ChatPanelBody = () => {
|
|
|
495
528
|
});
|
|
496
529
|
},
|
|
497
530
|
onToolCall: async ({ toolCall }) => {
|
|
498
|
-
// Dynamic tool calls will throw an error for toolName
|
|
499
|
-
// https://ai-sdk.dev/docs/ai-sdk-ui/chatbot-tool-usage#client-side-page
|
|
500
|
-
if (toolCall.dynamic) {
|
|
501
|
-
Logger.debug("Skipping dynamic tool call", toolCall);
|
|
502
|
-
return;
|
|
503
|
-
}
|
|
504
|
-
|
|
505
531
|
await handleToolCall({
|
|
506
532
|
invokeAiTool,
|
|
507
533
|
addToolOutput,
|
|
@@ -712,6 +738,7 @@ const ChatPanelBody = () => {
|
|
|
712
738
|
onEdit={handleMessageEdit}
|
|
713
739
|
isStreamingReasoning={isStreamingReasoning}
|
|
714
740
|
isLast={idx === messages.length - 1}
|
|
741
|
+
addToolApprovalResponse={addToolApprovalResponse}
|
|
715
742
|
/>
|
|
716
743
|
))}
|
|
717
744
|
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
2
|
|
|
3
3
|
import type { components } from "@marimo-team/marimo-api";
|
|
4
|
-
import
|
|
5
|
-
ChatAddToolOutputFunction,
|
|
6
|
-
FileUIPart,
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
import {
|
|
5
|
+
type ChatAddToolOutputFunction,
|
|
6
|
+
type FileUIPart,
|
|
7
|
+
isToolUIPart,
|
|
8
|
+
type ToolUIPart,
|
|
9
|
+
type UIMessage,
|
|
9
10
|
} from "ai";
|
|
10
11
|
import { useState } from "react";
|
|
11
12
|
import useEvent from "react-use-event-hook";
|
|
@@ -16,6 +17,7 @@ import type {
|
|
|
16
17
|
InvokeAiToolRequest,
|
|
17
18
|
InvokeAiToolResponse,
|
|
18
19
|
} from "@/core/network/types";
|
|
20
|
+
import { logNever } from "@/utils/assertNever";
|
|
19
21
|
import { blobToString } from "@/utils/fileToBase64";
|
|
20
22
|
import { Logger } from "@/utils/Logger";
|
|
21
23
|
import { getAICompletionBodyWithAttachments } from "../editor/ai/completion-utils";
|
|
@@ -134,11 +136,11 @@ export async function handleToolCall({
|
|
|
134
136
|
try {
|
|
135
137
|
if (FRONTEND_TOOL_REGISTRY.has(toolCall.toolName)) {
|
|
136
138
|
// Invoke the frontend tool
|
|
137
|
-
const response = await FRONTEND_TOOL_REGISTRY.invoke(
|
|
138
|
-
toolCall.toolName,
|
|
139
|
-
toolCall.input,
|
|
140
|
-
toolContext,
|
|
141
|
-
);
|
|
139
|
+
const response = await FRONTEND_TOOL_REGISTRY.invoke({
|
|
140
|
+
toolName: toolCall.toolName,
|
|
141
|
+
rawArgs: toolCall.input,
|
|
142
|
+
toolContext: toolContext,
|
|
143
|
+
});
|
|
142
144
|
addToolOutput({
|
|
143
145
|
tool: toolCall.toolName,
|
|
144
146
|
toolCallId: toolCall.toolCallId,
|
|
@@ -166,9 +168,33 @@ export async function handleToolCall({
|
|
|
166
168
|
}
|
|
167
169
|
}
|
|
168
170
|
|
|
171
|
+
/**
|
|
172
|
+
* Returns true if a tool call is "ready to be sent back to the server" — i.e.
|
|
173
|
+
* either it has reached a terminal output state, or the user has just supplied
|
|
174
|
+
* an approval response that the server hasn't seen yet.
|
|
175
|
+
*/
|
|
176
|
+
function isToolCallReadyToSend(state: ToolUIPart["state"]): boolean {
|
|
177
|
+
switch (state) {
|
|
178
|
+
case "output-available":
|
|
179
|
+
case "output-error":
|
|
180
|
+
case "output-denied":
|
|
181
|
+
case "approval-responded":
|
|
182
|
+
return true;
|
|
183
|
+
case "input-streaming":
|
|
184
|
+
case "input-available":
|
|
185
|
+
case "approval-requested":
|
|
186
|
+
return false;
|
|
187
|
+
default:
|
|
188
|
+
logNever(state);
|
|
189
|
+
return false;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
169
193
|
/**
|
|
170
194
|
* Checks if we should send a message automatically based on the messages.
|
|
171
|
-
* We
|
|
195
|
+
* We auto-send when every tool call on the last assistant message has either
|
|
196
|
+
* finished (output-available/error/denied) or has just received a user
|
|
197
|
+
* approval response, and the assistant hasn't replied yet.
|
|
172
198
|
*/
|
|
173
199
|
export function hasPendingToolCalls(messages: UIMessage[]): boolean {
|
|
174
200
|
if (messages.length === 0) {
|
|
@@ -188,17 +214,14 @@ export function hasPendingToolCalls(messages: UIMessage[]): boolean {
|
|
|
188
214
|
return false;
|
|
189
215
|
}
|
|
190
216
|
|
|
191
|
-
const toolParts = parts.filter(
|
|
192
|
-
part.type.startsWith("tool-"),
|
|
193
|
-
) as ToolUIPart[];
|
|
217
|
+
const toolParts = parts.filter(isToolUIPart);
|
|
194
218
|
|
|
195
|
-
// Guard against no tool parts
|
|
196
219
|
if (toolParts.length === 0) {
|
|
197
220
|
return false;
|
|
198
221
|
}
|
|
199
222
|
|
|
200
|
-
const
|
|
201
|
-
(part
|
|
223
|
+
const allToolCallsReady = toolParts.every((part) =>
|
|
224
|
+
isToolCallReadyToSend(part.state),
|
|
202
225
|
);
|
|
203
226
|
|
|
204
227
|
// Check if the last part has any text content
|
|
@@ -206,10 +229,9 @@ export function hasPendingToolCalls(messages: UIMessage[]): boolean {
|
|
|
206
229
|
const hasTextContent =
|
|
207
230
|
lastPart.type === "text" && lastPart.text?.trim().length > 0;
|
|
208
231
|
|
|
209
|
-
Logger.
|
|
232
|
+
Logger.debug("All tool calls ready to send: %s", allToolCallsReady);
|
|
210
233
|
|
|
211
|
-
|
|
212
|
-
return allToolCallsCompleted && !hasTextContent;
|
|
234
|
+
return allToolCallsReady && !hasTextContent;
|
|
213
235
|
}
|
|
214
236
|
|
|
215
237
|
export function useFileState() {
|