@marimo-team/islands 0.15.2 → 0.15.3
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-C39nQwtD.js → ConnectedDataExplorerComponent-DfvW3rBn.js} +323 -328
- package/dist/{ImageComparisonComponent-BhkiyswP.js → ImageComparisonComponent-XaJshw7d.js} +13 -13
- package/dist/{_baseUniq-DdHL34FO.js → _baseUniq-dN9WKF9m.js} +67 -67
- package/dist/any-language-editor-CpFniVi-.js +27 -0
- package/dist/{arc-BXrety1g.js → arc-BOhn-m2C.js} +1 -1
- package/dist/{architectureDiagram-KFL7JDKH-BMy6ywCF.js → architectureDiagram-W76B3OCA-Bpg85ZKv.js} +144 -144
- package/dist/assets/{worker-COGufAQn.js → worker-Y-Q4G-N2.js} +30 -26
- package/dist/asterisk-DS281yxp.js +271 -0
- package/dist/{blockDiagram-ZYB65J3Q-DYT2-nlI.js → blockDiagram-QIGZ2CNN-DS1kOHlW.js} +10 -10
- package/dist/{c4Diagram-AAMF2YG6-ZiQzioe6.js → c4Diagram-FPNF74CW-CyRVKssw.js} +8 -8
- package/dist/{channel-CeuXqUAU.js → channel-BilGXox7.js} +1 -1
- package/dist/{chunk-ANTBXLJU-BvYnIrdq.js → chunk-4BX2VUAB-CZR39zCO.js} +1 -1
- package/dist/{chunk-WVR4S24B-DXj8yaUk.js → chunk-55IACEB6-BIH-MYov.js} +1 -1
- package/dist/{chunk-GLLZNHP4-CyFsosAe.js → chunk-FMBD7UC4-4PZXFZE8.js} +1 -1
- package/dist/{chunk-JBRWN2VN-DA_EEhy2.js → chunk-K7UQS3LO-CEvWKznk.js} +117 -117
- package/dist/{chunk-NRVI72HA-BYx2jMlI.js → chunk-QN33PNHL-D5LO5Jq_.js} +1 -1
- package/dist/{chunk-FHKO5MBM-DfCztBk8.js → chunk-QZHKN3VN-6gwUonWI.js} +1 -1
- package/dist/{chunk-LXBSTHXV-Se7vdY6J.js → chunk-TVAH2DTR-3gm06QdU.js} +7 -7
- package/dist/{chunk-OMD6QJNC-CqgcPMgL.js → chunk-TZMSLE5B-Cm8Iy9bO.js} +1 -1
- package/dist/{classDiagram-v2-QTMF73CY-B19A3G1l.js → classDiagram-KNZD7YFC-DC529O_z.js} +2 -2
- package/dist/{classDiagram-3BZAVTQC-B19A3G1l.js → classDiagram-v2-RKCZMP56-DC529O_z.js} +2 -2
- package/dist/{clone-78au0tn1.js → clone-CLoRX3j6.js} +1 -1
- package/dist/cose-bilkent-S5V4N54A-qf5DlS6Y.js +2609 -0
- package/dist/{cytoscape.esm-BYnVVhJX.js → cytoscape.esm-DfdJODL8.js} +34 -34
- package/dist/{dagre-2BBEFEWP-BfEn3ZUV.js → dagre-5GWH7T2D-Ceocls0m.js} +6 -6
- package/dist/{data-grid-overlay-editor-CH_qLkV2.js → data-grid-overlay-editor-AqDS_UKe.js} +11 -11
- package/dist/{diagram-4IRLE6MV-CL8xidnG.js → diagram-N5W7TBWH-CP66oSiv.js} +59 -60
- package/dist/{diagram-RP2FKANI-B1BPcUew.js → diagram-QEK2KX5R-_YD4kxxi.js} +15 -15
- package/dist/{diagram-GUPCWM2R-CZ5cfqlq.js → diagram-S2PKOQOG-Cnj8T-OP.js} +10 -10
- package/dist/dockerfile-Cm8cRYCN.js +194 -0
- package/dist/ebnf-DUPDuY4r.js +78 -0
- package/dist/{erDiagram-HZWUO2LU-BEAIww50.js → erDiagram-AWTI2OKA-CGnvoHx6.js} +8 -8
- package/dist/fcl-CPC2WYrI.js +103 -0
- package/dist/{flowDiagram-THRYKUMA-Czs2UAI2.js → flowDiagram-PVAE7QVJ-DG-pr9R9.js} +9 -9
- package/dist/{ganttDiagram-WV7ZQ7D5-ByYIAVFO.js → ganttDiagram-OWAHRB6G-JmChtxvn.js} +34 -34
- package/dist/{gitGraphDiagram-OJR772UL-BcpDsiyB.js → gitGraphDiagram-NY62KEGX-D8wLfOPd.js} +4 -4
- package/dist/{glide-data-editor-CmN6FVyi.js → glide-data-editor-9nC3iCIZ.js} +33 -33
- package/dist/{graph-77W6heli.js → graph-CoRe7vAN.js} +3 -3
- package/dist/http-D9LttvKF.js +44 -0
- package/dist/{index-Bfk9dnyS.js → index-6qYeHHjQ.js} +33090 -32892
- package/dist/{index-BOojn38D.js → index-BpzLh4Qe.js} +7711 -7711
- package/dist/{index-CmozKMxx.js → index-BthgsgYX.js} +6 -6
- package/dist/{index-pBmAzQJl.js → index-MCx5v1x0.js} +2 -2
- package/dist/index-jkm77Jrz.js +98 -0
- package/dist/{infoDiagram-6WOFNB3A-CfzLHHVP.js → infoDiagram-STP46IZ2-BlXxvOrR.js} +2 -2
- package/dist/{journeyDiagram-FFXJYRFH-ndAcpkGn.js → journeyDiagram-BIP6EPQ6-CNRYs_Fc.js} +24 -26
- package/dist/{kanban-definition-KOZQBZVT-DcQYzNvc.js → kanban-definition-6OIFK2YF-B9HeMAuP.js} +14 -14
- package/dist/{layout-XySVHJgD.js → layout-m2vOUiW1.js} +81 -81
- package/dist/{linear-PbooOqg7.js → linear-DU6Q5CX3.js} +35 -35
- package/dist/{main-B5yML0bw.js → main-BD2KGFpU.js} +74594 -68034
- package/dist/main.js +1 -1
- package/dist/{mermaid-Cg5IX6Nv.js → mermaid-HVCtvbyx.js} +6160 -7493
- package/dist/min-DcGMA4e_.js +80 -0
- package/dist/mindmap-definition-Q6HEUPPD-BW8UmIDQ.js +785 -0
- package/dist/nginx-zDPm3Z74.js +89 -0
- package/dist/{number-overlay-editor-DUhfZqtP.js → number-overlay-editor-D8Hl0Syo.js} +19 -19
- package/dist/{pieDiagram-DBDJKBY4-DTOlNsja.js → pieDiagram-ADFJNKIX-Bg-3zg5U.js} +17 -17
- package/dist/{quadrantDiagram-YPSRARAO-BX2d8VS-.js → quadrantDiagram-LMRXKWRM-BO4IG6Yz.js} +6 -6
- package/dist/{react-plotly-Dcyw-3Sa.js → react-plotly-dkvHVuRb.js} +3577 -3577
- package/dist/{requirementDiagram-EGVEC5DT-D1T5u-wG.js → requirementDiagram-4UW4RH46-5sdTguSM.js} +7 -7
- package/dist/{sankeyDiagram-HRAUVNP4-G6xDfnp-.js → sankeyDiagram-GR3RE2ED-Buhlv9OI.js} +5 -5
- package/dist/sequenceDiagram-C3RYC4MD-C3qsM2UP.js +2519 -0
- package/dist/{slides-component-BJLlPJSr.js → slides-component-D209A0-s.js} +66 -66
- package/dist/solr-BNlsLglM.js +41 -0
- package/dist/spreadsheet-C-cy4P5N.js +49 -0
- package/dist/{stateDiagram-UUKSUZ4H-CYXbjaom.js → stateDiagram-KXAO66HF-CopJ7G6P.js} +5 -5
- package/dist/{stateDiagram-v2-EYPG3UTE-Br1HYKT6.js → stateDiagram-v2-UMBNRL4Z-CejL8AKf.js} +2 -2
- package/dist/style.css +1 -1
- package/dist/tiddlywiki-5wqsXtSk.js +155 -0
- package/dist/tiki-__Kn3CeS.js +181 -0
- package/dist/{time-B9SZnSen.js → time-BwSBitlN.js} +58 -58
- package/dist/{timeline-definition-3HZDQTIS-DeK_ZRD0.js → timeline-definition-XQNQX7LJ-DzMNTX-C.js} +10 -12
- package/dist/{timer-BYwnU4DF.js → timer-B0-z63CM.js} +16 -16
- package/dist/{treemap-75Q7IDZK-CKP4vV_0.js → treemap-75Q7IDZK-zeJG07dk.js} +14 -14
- package/dist/{vega-component-CpgdqX2d.js → vega-component-CUkiTayd.js} +30 -30
- package/dist/{xychartDiagram-FDP5SA34-AMEPsx_R.js → xychartDiagram-6GGTOJPD-DiENNXMS.js} +7 -7
- package/package.json +39 -39
- package/src/__mocks__/notebook.ts +3 -0
- package/src/__mocks__/requests.ts +3 -0
- package/src/__tests__/__snapshots__/CellStatus.test.tsx.snap +12 -12
- package/src/__tests__/chat-utils.test.ts +26 -211
- package/src/components/ai/ai-model-dropdown.tsx +25 -9
- package/src/components/app-config/ai-config.tsx +7 -0
- package/src/components/chat/chat-components.tsx +71 -0
- package/src/components/chat/chat-panel.tsx +481 -291
- package/src/components/chat/chat-utils.ts +50 -0
- package/src/components/chat/markdown-renderer.tsx +3 -7
- package/src/components/chat/tool-call-accordion.tsx +5 -5
- package/src/components/datasources/__tests__/utils.test.ts +6 -0
- package/src/components/datasources/column-preview.tsx +1 -3
- package/src/components/editor/actions/useNotebookActions.tsx +1 -1
- package/src/components/editor/ai/add-cell-with-ai.tsx +20 -15
- package/src/components/editor/ai/ai-completion-editor.tsx +22 -3
- package/src/components/editor/ai/completion-handlers.tsx +2 -4
- package/src/components/editor/ai/completion-utils.ts +85 -11
- package/src/components/editor/alerts/startup-logs-alert.tsx +72 -0
- package/src/components/editor/chrome/panels/datasources-panel.tsx +3 -1
- package/src/components/editor/chrome/panels/dependency-graph-panel.tsx +3 -1
- package/src/components/editor/chrome/panels/documentation-panel.tsx +3 -1
- package/src/components/editor/chrome/panels/error-panel.tsx +3 -1
- package/src/components/editor/chrome/panels/file-explorer-panel.tsx +3 -1
- package/src/components/editor/chrome/panels/logs-panel.tsx +3 -1
- package/src/components/editor/chrome/panels/outline-panel.tsx +3 -1
- package/src/components/editor/chrome/panels/packages-panel.tsx +4 -2
- package/src/components/editor/chrome/panels/scratchpad-panel.tsx +3 -1
- package/src/components/editor/chrome/panels/secrets-panel.tsx +3 -1
- package/src/components/editor/chrome/panels/snippets-panel.tsx +3 -1
- package/src/components/editor/chrome/panels/tracing-panel.tsx +3 -1
- package/src/components/editor/chrome/panels/variable-panel.tsx +3 -1
- package/src/components/editor/chrome/wrapper/app-chrome.tsx +38 -28
- package/src/components/editor/controls/command-palette-button.tsx +1 -1
- package/src/components/editor/controls/command-palette.tsx +5 -4
- package/src/components/editor/controls/state.ts +4 -0
- package/src/components/editor/package-alert.tsx +108 -58
- package/src/components/editor/renderers/CellArray.tsx +2 -0
- package/src/components/editor/renderers/vertical-layout/vertical-layout.tsx +0 -1
- package/src/components/pages/edit-page.tsx +7 -3
- package/src/core/ai/chat-utils.ts +26 -43
- package/src/core/ai/config.ts +1 -1
- package/src/core/ai/context/__tests__/registry.test.ts +277 -3
- package/src/core/ai/context/context.ts +11 -1
- package/src/core/ai/context/providers/__tests__/cell-output.test.ts +378 -0
- package/src/core/ai/context/providers/__tests__/error.test.ts +3 -2
- package/src/core/ai/context/providers/__tests__/file.test.ts +119 -0
- package/src/core/ai/context/providers/cell-output.ts +349 -0
- package/src/core/ai/context/providers/common.ts +5 -1
- package/src/core/ai/context/providers/file.ts +287 -0
- package/src/core/ai/context/registry.ts +79 -0
- package/src/core/ai/state.ts +22 -5
- package/src/core/alerts/state.ts +71 -3
- package/src/core/cells/cell.ts +2 -2
- package/src/core/cells/cells.ts +1 -1
- package/src/core/cells/logs.ts +1 -1
- package/src/core/cells/runs.ts +6 -5
- package/src/core/codemirror/ai/resources.ts +47 -5
- package/src/core/codemirror/ai/state.ts +12 -0
- package/src/core/codemirror/language/__tests__/sql.test.ts +45 -0
- package/src/core/codemirror/markdown/__tests__/commands.test.ts +1 -0
- package/src/core/codemirror/theme/dark.ts +1 -1
- package/src/core/config/capabilities.ts +1 -1
- package/src/core/datasets/__tests__/data-source.test.ts +24 -0
- package/src/core/errors/__tests__/errors.test.ts +2 -0
- package/src/core/islands/bridge.ts +1 -0
- package/src/core/islands/main.ts +1 -0
- package/src/core/kernel/messages.ts +12 -6
- package/src/core/layout/layout.ts +3 -3
- package/src/core/network/requests-network.ts +8 -0
- package/src/core/network/requests-static.ts +1 -0
- package/src/core/network/requests-toasting.ts +1 -0
- package/src/core/network/types.ts +4 -1
- package/src/core/wasm/bridge.ts +18 -2
- package/src/core/wasm/worker/bootstrap.ts +3 -1
- package/src/core/wasm/worker/getMarimoWheel.ts +3 -8
- package/src/core/wasm/worker/types.ts +3 -0
- package/src/core/websocket/useMarimoWebSocket.tsx +7 -1
- package/src/css/app/Cell.css +42 -21
- package/src/css/app/codemirror.css +5 -1
- package/src/css/globals.css +3 -0
- package/src/css/md.css +1 -1
- package/src/plugins/impl/MicrophonePlugin.tsx +2 -2
- package/src/plugins/impl/chat/ChatPlugin.tsx +2 -9
- package/src/plugins/impl/chat/chat-ui.tsx +129 -110
- package/src/plugins/impl/chat/types.ts +5 -8
- package/src/plugins/impl/code/__tests__/language.test.ts +15 -0
- package/src/plugins/impl/code/any-language-editor.tsx +11 -8
- package/src/plugins/layout/MimeRenderPlugin.tsx +3 -6
- package/src/stories/cell.stories.tsx +6 -0
- package/src/stories/layout/vertical/one-column.stories.tsx +215 -0
- package/src/theme/useTheme.ts +11 -6
- package/src/utils/__tests__/blob.test.ts +37 -0
- package/src/utils/arrays.ts +13 -0
- package/src/utils/fileToBase64.ts +21 -6
- package/src/utils/json/base64.ts +5 -2
- package/src/utils/numbers.ts +9 -7
- package/dist/any-language-editor-DC5170DQ.js +0 -45
- package/dist/asn1-jKiBa2Ya.js +0 -95
- package/dist/clojure-CCKyeQKf.js +0 -800
- package/dist/css-BkF-NPzE.js +0 -1553
- package/dist/index-5ZH_qS8j.js +0 -288
- package/dist/index-U4yn89qO.js +0 -341
- package/dist/javascript-C2yteZeJ.js +0 -691
- package/dist/min-DS5Jz-hg.js +0 -80
- package/dist/mindmap-definition-LNHGMQRG-0aOVaMR8.js +0 -3234
- package/dist/mllike-BSnXJBGA.js +0 -272
- package/dist/pug-CwAQJzGR.js +0 -248
- package/dist/python-BkR3uSy8.js +0 -313
- package/dist/rpm-IznJm2Xc.js +0 -57
- package/dist/sequenceDiagram-WFGC7UMF-DMhHzllb.js +0 -2284
- package/dist/ttcn-cfg-Bac_acMi.js +0 -88
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
import type { Completion } from "@codemirror/autocomplete";
|
|
4
4
|
import type { Resource } from "@marimo-team/codemirror-mcp";
|
|
5
|
+
import type { FileUIPart } from "ai";
|
|
6
|
+
import { Memoize } from "typescript-memoize";
|
|
7
|
+
import { Logger } from "@/utils/Logger";
|
|
8
|
+
import { MultiMap } from "@/utils/multi-map";
|
|
5
9
|
import type { TypedString } from "@/utils/typed";
|
|
6
10
|
|
|
7
11
|
/**
|
|
@@ -41,6 +45,12 @@ export abstract class AIContextProvider<
|
|
|
41
45
|
/** Format completion */
|
|
42
46
|
abstract formatCompletion(item: T): Completion;
|
|
43
47
|
|
|
48
|
+
/** Get attachments for context items (optional, async) */
|
|
49
|
+
async getAttachments(_items: T[]): Promise<FileUIPart[]> {
|
|
50
|
+
// Default implementation returns no attachments
|
|
51
|
+
return [];
|
|
52
|
+
}
|
|
53
|
+
|
|
44
54
|
asURI(id: string): ContextLocatorId {
|
|
45
55
|
return `${this.contextType}://${id}` as ContextLocatorId;
|
|
46
56
|
}
|
|
@@ -118,6 +128,7 @@ export class AIContextRegistry<T extends AIContextItem> {
|
|
|
118
128
|
);
|
|
119
129
|
}
|
|
120
130
|
|
|
131
|
+
@Memoize()
|
|
121
132
|
getAllItems(): T[] {
|
|
122
133
|
return [...this.providers].flatMap((provider) => provider.getItems());
|
|
123
134
|
}
|
|
@@ -177,4 +188,72 @@ export class AIContextRegistry<T extends AIContextItem> {
|
|
|
177
188
|
})
|
|
178
189
|
.join("\n\n");
|
|
179
190
|
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Get attachments for mentioned items
|
|
194
|
+
*/
|
|
195
|
+
async getAttachmentsForContext(
|
|
196
|
+
contextIds: ContextLocatorId[],
|
|
197
|
+
): Promise<FileUIPart[]> {
|
|
198
|
+
const allItems = new Map<ContextLocatorId, T>(
|
|
199
|
+
this.getAllItems().map((item) => [item.uri as ContextLocatorId, item]),
|
|
200
|
+
);
|
|
201
|
+
|
|
202
|
+
const contextInfo: T[] = [];
|
|
203
|
+
for (const contextId of contextIds) {
|
|
204
|
+
const item = allItems.get(contextId);
|
|
205
|
+
if (item) {
|
|
206
|
+
contextInfo.push(item);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
if (contextInfo.length === 0) {
|
|
211
|
+
return [];
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// Group items by provider type to batch attachment requests
|
|
215
|
+
const itemsByProvider = new MultiMap<string, T>();
|
|
216
|
+
for (const item of contextInfo) {
|
|
217
|
+
const providerType = item.type;
|
|
218
|
+
itemsByProvider.add(providerType, item);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// Collect attachments from all providers
|
|
222
|
+
const attachmentPromises = [...itemsByProvider.entries()].map(
|
|
223
|
+
async ([providerType, items]) => {
|
|
224
|
+
const provider = this.getProvider(providerType);
|
|
225
|
+
if (!provider) {
|
|
226
|
+
return [];
|
|
227
|
+
}
|
|
228
|
+
try {
|
|
229
|
+
return await provider.getAttachments(items);
|
|
230
|
+
} catch (error) {
|
|
231
|
+
Logger.error("Error getting attachments from provider", error);
|
|
232
|
+
return [];
|
|
233
|
+
}
|
|
234
|
+
},
|
|
235
|
+
);
|
|
236
|
+
|
|
237
|
+
const attachmentResults = await Promise.all(attachmentPromises);
|
|
238
|
+
const results = attachmentResults.flat();
|
|
239
|
+
|
|
240
|
+
// Print attachments to the console with a rich image preview
|
|
241
|
+
if (import.meta.env.DEV) {
|
|
242
|
+
for (const attachment of results) {
|
|
243
|
+
// If it's an image, print a rich preview
|
|
244
|
+
if (
|
|
245
|
+
/^data:image\/(png|jpeg|jpg|gif|svg\+xml);base64,/.test(
|
|
246
|
+
attachment.url,
|
|
247
|
+
)
|
|
248
|
+
) {
|
|
249
|
+
Logger.debug(
|
|
250
|
+
"%c ",
|
|
251
|
+
`font-size:1px;padding:140px 180px;background:url('${attachment.url}') no-repeat;background-size:contain;`,
|
|
252
|
+
);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
return results;
|
|
258
|
+
}
|
|
180
259
|
}
|
package/src/core/ai/state.ts
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
/* Copyright 2024 Marimo. All rights reserved. */
|
|
2
2
|
|
|
3
|
-
import type {
|
|
3
|
+
import type { UIMessage } from "@ai-sdk/react";
|
|
4
|
+
import type { FileUIPart } from "ai";
|
|
4
5
|
import { atom } from "jotai";
|
|
5
6
|
import { atomWithStorage } from "jotai/utils";
|
|
7
|
+
import { uniqueBy } from "@/utils/arrays";
|
|
6
8
|
import { adaptForLocalStorage } from "@/utils/storage";
|
|
7
9
|
import type { TypedString } from "@/utils/typed";
|
|
8
10
|
import type { CellId } from "../cells/ids";
|
|
9
11
|
|
|
10
|
-
const KEY = "marimo:ai:chatState:
|
|
12
|
+
const KEY = "marimo:ai:chatState:v5";
|
|
11
13
|
|
|
12
14
|
export type ChatId = TypedString<"ChatId">;
|
|
13
15
|
|
|
@@ -27,13 +29,14 @@ export interface Message {
|
|
|
27
29
|
role: "user" | "assistant" | "data" | "system";
|
|
28
30
|
content: string;
|
|
29
31
|
timestamp: number;
|
|
30
|
-
parts?:
|
|
32
|
+
parts?: UIMessage["parts"];
|
|
33
|
+
attachments?: FileUIPart[];
|
|
31
34
|
}
|
|
32
35
|
|
|
33
36
|
export interface Chat {
|
|
34
37
|
id: ChatId;
|
|
35
38
|
title: string;
|
|
36
|
-
messages:
|
|
39
|
+
messages: UIMessage[];
|
|
37
40
|
createdAt: number;
|
|
38
41
|
updatedAt: number;
|
|
39
42
|
}
|
|
@@ -43,6 +46,20 @@ export interface ChatState {
|
|
|
43
46
|
activeChatId: ChatId | null;
|
|
44
47
|
}
|
|
45
48
|
|
|
49
|
+
function removeEmptyChats(chatState: Map<ChatId, Chat>): Map<ChatId, Chat> {
|
|
50
|
+
const result = new Map<ChatId, Chat>();
|
|
51
|
+
|
|
52
|
+
// Dedupe messages with the same id
|
|
53
|
+
for (const [chatId, chat] of chatState.entries()) {
|
|
54
|
+
if (chat.messages.length === 0) {
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
const dedupedMessages = uniqueBy(chat.messages, (message) => message.id);
|
|
58
|
+
result.set(chatId, { ...chat, messages: dedupedMessages });
|
|
59
|
+
}
|
|
60
|
+
return result;
|
|
61
|
+
}
|
|
62
|
+
|
|
46
63
|
export const chatStateAtom = atomWithStorage<ChatState>(
|
|
47
64
|
KEY,
|
|
48
65
|
{
|
|
@@ -51,7 +68,7 @@ export const chatStateAtom = atomWithStorage<ChatState>(
|
|
|
51
68
|
},
|
|
52
69
|
adaptForLocalStorage({
|
|
53
70
|
toSerializable: (value: ChatState) => ({
|
|
54
|
-
chats: [...value.chats.entries()],
|
|
71
|
+
chats: [...removeEmptyChats(value.chats).entries()],
|
|
55
72
|
activeChatId: value.activeChatId,
|
|
56
73
|
}),
|
|
57
74
|
fromSerializable: (value) => ({
|
package/src/core/alerts/state.ts
CHANGED
|
@@ -16,6 +16,13 @@ export interface MissingPackageAlert {
|
|
|
16
16
|
export interface InstallingPackageAlert {
|
|
17
17
|
kind: "installing";
|
|
18
18
|
packages: PackageInstallationStatus;
|
|
19
|
+
logs?: { [key: string]: string } | null;
|
|
20
|
+
log_status?: "append" | "start" | "done" | null;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface StartupLogsAlert {
|
|
24
|
+
content: string;
|
|
25
|
+
status: "append" | "start" | "done";
|
|
19
26
|
}
|
|
20
27
|
|
|
21
28
|
export function isMissingPackageAlert(
|
|
@@ -39,26 +46,87 @@ interface AlertState {
|
|
|
39
46
|
| Identified<MissingPackageAlert>
|
|
40
47
|
| Identified<InstallingPackageAlert>
|
|
41
48
|
| null;
|
|
49
|
+
startupLogsAlert: StartupLogsAlert | null;
|
|
50
|
+
packageLogs: { [packageName: string]: string };
|
|
42
51
|
}
|
|
43
52
|
|
|
44
53
|
const { valueAtom: alertAtom, useActions } = createReducerAndAtoms(
|
|
45
|
-
() =>
|
|
54
|
+
() =>
|
|
55
|
+
({
|
|
56
|
+
packageAlert: null,
|
|
57
|
+
startupLogsAlert: null,
|
|
58
|
+
packageLogs: {},
|
|
59
|
+
}) as AlertState,
|
|
46
60
|
{
|
|
47
61
|
addPackageAlert: (
|
|
48
62
|
state,
|
|
49
63
|
alert: MissingPackageAlert | InstallingPackageAlert,
|
|
50
64
|
) => {
|
|
65
|
+
const newPackageLogs = { ...state.packageLogs };
|
|
66
|
+
|
|
67
|
+
// Handle streaming logs for installing package alerts
|
|
68
|
+
if (isInstallingPackageAlert(alert) && alert.logs && alert.log_status) {
|
|
69
|
+
for (const [packageName, newContent] of Object.entries(alert.logs)) {
|
|
70
|
+
switch (alert.log_status) {
|
|
71
|
+
case "start":
|
|
72
|
+
// Start new log for this package
|
|
73
|
+
newPackageLogs[packageName] = newContent;
|
|
74
|
+
|
|
75
|
+
break;
|
|
76
|
+
|
|
77
|
+
case "append": {
|
|
78
|
+
// Append to existing log
|
|
79
|
+
const prevContent = newPackageLogs[packageName] || "";
|
|
80
|
+
newPackageLogs[packageName] = prevContent + newContent;
|
|
81
|
+
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
case "done": {
|
|
85
|
+
// Append final content and mark as done
|
|
86
|
+
const prevContent = newPackageLogs[packageName] || "";
|
|
87
|
+
newPackageLogs[packageName] = prevContent + newContent;
|
|
88
|
+
|
|
89
|
+
break;
|
|
90
|
+
}
|
|
91
|
+
// No default
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const existingAlert = state.packageAlert;
|
|
97
|
+
const alertId = existingAlert?.id || generateUUID();
|
|
98
|
+
|
|
51
99
|
return {
|
|
52
100
|
...state,
|
|
53
|
-
packageAlert: { id:
|
|
101
|
+
packageAlert: { id: alertId, ...alert },
|
|
102
|
+
packageLogs: newPackageLogs,
|
|
54
103
|
};
|
|
55
104
|
},
|
|
56
105
|
|
|
57
106
|
clearPackageAlert: (state, id: string) => {
|
|
58
107
|
return state.packageAlert !== null && state.packageAlert.id === id
|
|
59
|
-
? { ...state, packageAlert: null }
|
|
108
|
+
? { ...state, packageAlert: null, packageLogs: {} }
|
|
60
109
|
: state;
|
|
61
110
|
},
|
|
111
|
+
|
|
112
|
+
addStartupLog: (
|
|
113
|
+
state,
|
|
114
|
+
logData: { content: string; status: "append" | "start" | "done" },
|
|
115
|
+
) => {
|
|
116
|
+
const prevContent = state.startupLogsAlert?.content || "";
|
|
117
|
+
return {
|
|
118
|
+
...state,
|
|
119
|
+
startupLogsAlert: {
|
|
120
|
+
...state.startupLogsAlert,
|
|
121
|
+
content: prevContent + logData.content,
|
|
122
|
+
status: logData.status,
|
|
123
|
+
},
|
|
124
|
+
};
|
|
125
|
+
},
|
|
126
|
+
|
|
127
|
+
clearStartupLogsAlert: (state) => {
|
|
128
|
+
return { ...state, startupLogsAlert: null };
|
|
129
|
+
},
|
|
62
130
|
},
|
|
63
131
|
);
|
|
64
132
|
|
package/src/core/cells/cell.ts
CHANGED
|
@@ -47,7 +47,7 @@ export function transitionCell(
|
|
|
47
47
|
case "idle":
|
|
48
48
|
if (cell.runStartTimestamp) {
|
|
49
49
|
nextCell.runElapsedTimeMs = Time.fromSeconds(
|
|
50
|
-
(message.timestamp - cell.runStartTimestamp) as Seconds,
|
|
50
|
+
((message.timestamp ?? 0) - cell.runStartTimestamp) as Seconds,
|
|
51
51
|
).toMilliseconds();
|
|
52
52
|
nextCell.runStartTimestamp = null;
|
|
53
53
|
nextCell.staleInputs = false;
|
|
@@ -210,7 +210,7 @@ export function outputIsStale(
|
|
|
210
210
|
status === "running" &&
|
|
211
211
|
output !== null &&
|
|
212
212
|
runStartTimestamp !== null &&
|
|
213
|
-
output.timestamp > runStartTimestamp;
|
|
213
|
+
(output.timestamp ?? 0) > runStartTimestamp;
|
|
214
214
|
|
|
215
215
|
// If loading and output has not been received while running
|
|
216
216
|
if (loading && !outputReceivedWhileRunning) {
|
package/src/core/cells/cells.ts
CHANGED
|
@@ -1372,7 +1372,7 @@ const {
|
|
|
1372
1372
|
|
|
1373
1373
|
function isCellCodeHidden(state: NotebookState, cellId: CellId): boolean {
|
|
1374
1374
|
return (
|
|
1375
|
-
state.cellData[cellId].config.hide_code &&
|
|
1375
|
+
Boolean(state.cellData[cellId].config.hide_code) &&
|
|
1376
1376
|
!state.untouchedNewCells.has(cellId)
|
|
1377
1377
|
);
|
|
1378
1378
|
}
|
package/src/core/cells/logs.ts
CHANGED
|
@@ -56,7 +56,7 @@ export function getCellLogsForMessage(cell: CellMessage): CellLog[] {
|
|
|
56
56
|
CellLogLogger.log({
|
|
57
57
|
level: "stderr",
|
|
58
58
|
cellId: cell.cell_id as CellId,
|
|
59
|
-
timestamp: cell.timestamp,
|
|
59
|
+
timestamp: cell.timestamp ?? 0,
|
|
60
60
|
message: JSON.stringify(error),
|
|
61
61
|
});
|
|
62
62
|
});
|
package/src/core/cells/runs.ts
CHANGED
|
@@ -45,6 +45,7 @@ const {
|
|
|
45
45
|
opts: { cellOperation: CellMessage; code: string },
|
|
46
46
|
): RunsState => {
|
|
47
47
|
const { cellOperation, code } = opts;
|
|
48
|
+
const timestamp = cellOperation.timestamp ?? 0;
|
|
48
49
|
const runId = cellOperation.run_id as RunId | undefined;
|
|
49
50
|
if (!runId) {
|
|
50
51
|
return state;
|
|
@@ -84,11 +85,11 @@ const {
|
|
|
84
85
|
code: code.slice(0, MAX_CODE_LENGTH),
|
|
85
86
|
elapsedTime: 0,
|
|
86
87
|
status: status,
|
|
87
|
-
startTime:
|
|
88
|
+
startTime: timestamp,
|
|
88
89
|
},
|
|
89
90
|
],
|
|
90
91
|
]),
|
|
91
|
-
runStartTime:
|
|
92
|
+
runStartTime: timestamp,
|
|
92
93
|
};
|
|
93
94
|
|
|
94
95
|
// Manage run history size
|
|
@@ -129,12 +130,12 @@ const {
|
|
|
129
130
|
|
|
130
131
|
const startTime =
|
|
131
132
|
cellOperation.status === "running"
|
|
132
|
-
?
|
|
133
|
+
? timestamp
|
|
133
134
|
: existingCellRun.startTime;
|
|
134
135
|
|
|
135
136
|
const elapsedTime =
|
|
136
137
|
status === "success" || status === "error"
|
|
137
|
-
?
|
|
138
|
+
? timestamp - existingCellRun.startTime
|
|
138
139
|
: undefined;
|
|
139
140
|
|
|
140
141
|
nextCellRuns.set(cellOperation.cell_id as CellId, {
|
|
@@ -149,7 +150,7 @@ const {
|
|
|
149
150
|
code: code.slice(0, MAX_CODE_LENGTH),
|
|
150
151
|
elapsedTime: 0,
|
|
151
152
|
status: status,
|
|
152
|
-
startTime:
|
|
153
|
+
startTime: timestamp,
|
|
153
154
|
});
|
|
154
155
|
}
|
|
155
156
|
|
|
@@ -12,30 +12,72 @@ import {
|
|
|
12
12
|
resourcesField,
|
|
13
13
|
resourceTheme,
|
|
14
14
|
} from "@marimo-team/codemirror-mcp";
|
|
15
|
-
import {
|
|
15
|
+
import {
|
|
16
|
+
getAIContextRegistry,
|
|
17
|
+
getFileContextProvider,
|
|
18
|
+
} from "@/core/ai/context/context";
|
|
16
19
|
import type { AIContextItem } from "@/core/ai/context/registry";
|
|
17
20
|
import type { JotaiStore } from "@/core/state/jotai";
|
|
18
21
|
import { Logger } from "@/utils/Logger";
|
|
22
|
+
import { contextCallbacks } from "./state";
|
|
23
|
+
|
|
24
|
+
const NONE_RESOURCE_TYPE = "_none_";
|
|
25
|
+
const NONE_RESOURCE = [
|
|
26
|
+
{
|
|
27
|
+
uri: "",
|
|
28
|
+
name: "No resources",
|
|
29
|
+
type: NONE_RESOURCE_TYPE,
|
|
30
|
+
data: {},
|
|
31
|
+
},
|
|
32
|
+
];
|
|
33
|
+
const NONE_RESOURCE_FORMAT_COMPLETION = {
|
|
34
|
+
info: "Variables, dataframes, and tables will appear here.",
|
|
35
|
+
apply: () => {
|
|
36
|
+
return;
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export function resourceExtension(opts: {
|
|
41
|
+
language: Language;
|
|
42
|
+
store: JotaiStore;
|
|
43
|
+
onAddFiles?: (files: File[]) => void;
|
|
44
|
+
}): Extension[] {
|
|
45
|
+
const { language, store, onAddFiles } = opts;
|
|
19
46
|
|
|
20
|
-
export function resourceExtension(
|
|
21
|
-
language: Language,
|
|
22
|
-
store: JotaiStore,
|
|
23
|
-
): Extension[] {
|
|
24
47
|
return [
|
|
25
48
|
language.data.of({
|
|
49
|
+
// Resource completion for static resources (variables, tables, etc.)
|
|
26
50
|
autocomplete: resourceCompletion(
|
|
27
51
|
async (): Promise<Resource[]> => {
|
|
28
52
|
const registry = getAIContextRegistry(store);
|
|
29
53
|
const resources = registry.getAllItems();
|
|
54
|
+
if (resources.length === 0) {
|
|
55
|
+
return NONE_RESOURCE;
|
|
56
|
+
}
|
|
30
57
|
return resources;
|
|
31
58
|
},
|
|
32
59
|
(resource) => {
|
|
60
|
+
if (resource.type === NONE_RESOURCE_TYPE) {
|
|
61
|
+
return NONE_RESOURCE_FORMAT_COMPLETION;
|
|
62
|
+
}
|
|
63
|
+
|
|
33
64
|
const registry = getAIContextRegistry(store);
|
|
34
65
|
const provider = registry.getProvider(resource.type);
|
|
35
66
|
return provider?.formatCompletion(resource as AIContextItem) || {};
|
|
36
67
|
},
|
|
37
68
|
),
|
|
38
69
|
}),
|
|
70
|
+
contextCallbacks.of({
|
|
71
|
+
addAttachment: (attachment) => onAddFiles?.([attachment]),
|
|
72
|
+
}),
|
|
73
|
+
// Dynamic file completion
|
|
74
|
+
...(onAddFiles
|
|
75
|
+
? [
|
|
76
|
+
language.data.of({
|
|
77
|
+
autocomplete: getFileContextProvider().createCompletionSource(),
|
|
78
|
+
}),
|
|
79
|
+
]
|
|
80
|
+
: []),
|
|
39
81
|
resourceDecorations,
|
|
40
82
|
resourceInputFilter,
|
|
41
83
|
resourcesField.init(() => {
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/* Copyright 2024 Marimo. All rights reserved. */
|
|
2
|
+
|
|
3
|
+
import { singleFacet } from "../facet";
|
|
4
|
+
|
|
5
|
+
interface ContextCallbacks {
|
|
6
|
+
addAttachment?: (attachment: File) => void;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* State for completion callbacks
|
|
11
|
+
*/
|
|
12
|
+
export const contextCallbacks = singleFacet<ContextCallbacks>();
|
|
@@ -664,6 +664,9 @@ describe("tablesCompletionSource", () => {
|
|
|
664
664
|
source: "duckdb",
|
|
665
665
|
source_type: "local",
|
|
666
666
|
type: "table",
|
|
667
|
+
num_columns: 0,
|
|
668
|
+
num_rows: 0,
|
|
669
|
+
variable_name: null,
|
|
667
670
|
columns: [
|
|
668
671
|
{
|
|
669
672
|
name: "id",
|
|
@@ -690,6 +693,9 @@ describe("tablesCompletionSource", () => {
|
|
|
690
693
|
source: "duckdb",
|
|
691
694
|
source_type: "local",
|
|
692
695
|
type: "table",
|
|
696
|
+
num_columns: 0,
|
|
697
|
+
num_rows: 0,
|
|
698
|
+
variable_name: null,
|
|
693
699
|
columns: [
|
|
694
700
|
{
|
|
695
701
|
name: "order_id",
|
|
@@ -763,6 +769,9 @@ describe("tablesCompletionSource", () => {
|
|
|
763
769
|
source: "postgres",
|
|
764
770
|
source_type: "local",
|
|
765
771
|
type: "table",
|
|
772
|
+
num_columns: 0,
|
|
773
|
+
num_rows: 0,
|
|
774
|
+
variable_name: null,
|
|
766
775
|
columns: [
|
|
767
776
|
{
|
|
768
777
|
name: "col1",
|
|
@@ -788,6 +797,9 @@ describe("tablesCompletionSource", () => {
|
|
|
788
797
|
source: "postgres",
|
|
789
798
|
source_type: "local",
|
|
790
799
|
type: "table",
|
|
800
|
+
num_columns: 0,
|
|
801
|
+
num_rows: 0,
|
|
802
|
+
variable_name: null,
|
|
791
803
|
columns: [
|
|
792
804
|
{
|
|
793
805
|
name: "col2",
|
|
@@ -856,6 +868,9 @@ describe("tablesCompletionSource", () => {
|
|
|
856
868
|
source: "postgres",
|
|
857
869
|
source_type: "local",
|
|
858
870
|
type: "table",
|
|
871
|
+
num_columns: 0,
|
|
872
|
+
num_rows: 0,
|
|
873
|
+
variable_name: null,
|
|
859
874
|
columns: [
|
|
860
875
|
{
|
|
861
876
|
name: "col1",
|
|
@@ -875,6 +890,9 @@ describe("tablesCompletionSource", () => {
|
|
|
875
890
|
source: "postgres",
|
|
876
891
|
source_type: "local",
|
|
877
892
|
type: "table",
|
|
893
|
+
num_columns: 0,
|
|
894
|
+
num_rows: 0,
|
|
895
|
+
variable_name: null,
|
|
878
896
|
columns: [
|
|
879
897
|
{
|
|
880
898
|
name: "col2",
|
|
@@ -900,6 +918,9 @@ describe("tablesCompletionSource", () => {
|
|
|
900
918
|
source: "postgres",
|
|
901
919
|
source_type: "local",
|
|
902
920
|
type: "table",
|
|
921
|
+
num_columns: 0,
|
|
922
|
+
num_rows: 0,
|
|
923
|
+
variable_name: null,
|
|
903
924
|
columns: [
|
|
904
925
|
{
|
|
905
926
|
name: "col2",
|
|
@@ -925,6 +946,9 @@ describe("tablesCompletionSource", () => {
|
|
|
925
946
|
source: "postgres",
|
|
926
947
|
source_type: "local",
|
|
927
948
|
type: "table",
|
|
949
|
+
num_columns: 0,
|
|
950
|
+
num_rows: 0,
|
|
951
|
+
variable_name: null,
|
|
928
952
|
columns: [
|
|
929
953
|
{
|
|
930
954
|
name: "col2",
|
|
@@ -1002,6 +1026,9 @@ describe("tablesCompletionSource", () => {
|
|
|
1002
1026
|
source: "postgres",
|
|
1003
1027
|
source_type: "local",
|
|
1004
1028
|
type: "table",
|
|
1029
|
+
num_columns: 0,
|
|
1030
|
+
num_rows: 0,
|
|
1031
|
+
variable_name: null,
|
|
1005
1032
|
columns: [
|
|
1006
1033
|
{
|
|
1007
1034
|
name: "id",
|
|
@@ -1070,6 +1097,9 @@ describe("tablesCompletionSource", () => {
|
|
|
1070
1097
|
source: "postgres",
|
|
1071
1098
|
source_type: "local",
|
|
1072
1099
|
type: "table",
|
|
1100
|
+
num_columns: 0,
|
|
1101
|
+
num_rows: 0,
|
|
1102
|
+
variable_name: null,
|
|
1073
1103
|
columns: [],
|
|
1074
1104
|
},
|
|
1075
1105
|
],
|
|
@@ -1109,6 +1139,9 @@ describe("tablesCompletionSource", () => {
|
|
|
1109
1139
|
source: "postgres",
|
|
1110
1140
|
source_type: "local",
|
|
1111
1141
|
type: "table",
|
|
1142
|
+
num_columns: 0,
|
|
1143
|
+
num_rows: 0,
|
|
1144
|
+
variable_name: null,
|
|
1112
1145
|
columns: [
|
|
1113
1146
|
{
|
|
1114
1147
|
name: "id",
|
|
@@ -1134,6 +1167,9 @@ describe("tablesCompletionSource", () => {
|
|
|
1134
1167
|
source: "postgres",
|
|
1135
1168
|
source_type: "local",
|
|
1136
1169
|
type: "table",
|
|
1170
|
+
num_columns: 0,
|
|
1171
|
+
num_rows: 0,
|
|
1172
|
+
variable_name: null,
|
|
1137
1173
|
columns: [
|
|
1138
1174
|
{
|
|
1139
1175
|
name: "order_id",
|
|
@@ -1279,6 +1315,9 @@ describe("tablesCompletionSource", () => {
|
|
|
1279
1315
|
source: "postgres",
|
|
1280
1316
|
source_type: "local",
|
|
1281
1317
|
type: "table",
|
|
1318
|
+
num_columns: 0,
|
|
1319
|
+
num_rows: 0,
|
|
1320
|
+
variable_name: null,
|
|
1282
1321
|
columns: [
|
|
1283
1322
|
{
|
|
1284
1323
|
name: "id",
|
|
@@ -1469,6 +1508,9 @@ describe("tablesCompletionSource", () => {
|
|
|
1469
1508
|
source: "duckdb",
|
|
1470
1509
|
source_type: "local",
|
|
1471
1510
|
type: "table",
|
|
1511
|
+
num_columns: 0,
|
|
1512
|
+
num_rows: 0,
|
|
1513
|
+
variable_name: null,
|
|
1472
1514
|
columns: [
|
|
1473
1515
|
{
|
|
1474
1516
|
name: "col1",
|
|
@@ -1613,6 +1655,9 @@ const mockConnection: DataSourceConnection = {
|
|
|
1613
1655
|
source: "duckdb",
|
|
1614
1656
|
source_type: "local",
|
|
1615
1657
|
type: "table",
|
|
1658
|
+
num_columns: 0,
|
|
1659
|
+
num_rows: 0,
|
|
1660
|
+
variable_name: null,
|
|
1616
1661
|
columns: [
|
|
1617
1662
|
{
|
|
1618
1663
|
name: "col1",
|