@marimo-team/frontend 0.23.14-dev19 → 0.23.14-dev21

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.
Files changed (90) hide show
  1. package/dist/assets/{CellStatus-B3d9WY2x.js → CellStatus-CSZHI8sz.js} +1 -1
  2. package/dist/assets/{JsonOutput-C3c9GGaV.js → JsonOutput-CYIo9GSP.js} +12 -12
  3. package/dist/assets/MarimoErrorOutput-BokuSnpU.js +11 -0
  4. package/dist/assets/{RenderHTML-v15QgtRg.js → RenderHTML-B9mw7TD1.js} +1 -1
  5. package/dist/assets/{RunButton-Bz4eaTJM.js → RunButton-CX_nNY62.js} +1 -1
  6. package/dist/assets/{add-cell-with-ai-wau9Yzcj.js → add-cell-with-ai-DwzlK27e.js} +47 -34
  7. package/dist/assets/{add-connection-dialog-_KCPEn7U.js → add-connection-dialog-fmiSisf0.js} +6 -6
  8. package/dist/assets/{agent-panel-Bn9AgwJH.js → agent-panel-BDO44WWH.js} +5 -5
  9. package/dist/assets/{ai-model-dropdown-BeZrAec-.js → ai-model-dropdown-BP8gjnOy.js} +3 -3
  10. package/dist/assets/{app-config-button-BG9ONWMU.js → app-config-button-CVpG64c2.js} +1 -1
  11. package/dist/assets/{cell-editor-24ykqaHj.js → cell-editor-Bbir67_U.js} +10 -10
  12. package/dist/assets/cell-link-CBRggkzf.js +1 -0
  13. package/dist/assets/{cells-DENsmH9t.js → cells-RJTD-euN.js} +44 -44
  14. package/dist/assets/{chat-display-CcL_dydg.js → chat-display-17k5Uy0b.js} +1 -1
  15. package/dist/assets/{chat-panel-CA-2-S1C.js → chat-panel-CGwZggen.js} +2 -2
  16. package/dist/assets/{chat-ui-DQeA0_b5.js → chat-ui-BrSyHh93.js} +1 -1
  17. package/dist/assets/{column-preview-BPgYXdDd.js → column-preview-dW7xtQ7S.js} +1 -1
  18. package/dist/assets/{command-palette-WlkKgdrI.js → command-palette-DtKhXIMn.js} +1 -1
  19. package/dist/assets/{common-DdBQICbD.js → common-DHzo8K8C.js} +1 -1
  20. package/dist/assets/components-ChBJEsmj.js +1 -0
  21. package/dist/assets/datasource-RP7m6Xrh.js +3 -0
  22. package/dist/assets/{dependency-graph-panel-nYHPHFU4.js → dependency-graph-panel-CjdEazj5.js} +4 -4
  23. package/dist/assets/{documentation-panel-Dw9tYBNf.js → documentation-panel-BcUF41gA.js} +1 -1
  24. package/dist/assets/{download-4NoBestd.js → download-CJ6tdZ-1.js} +4 -4
  25. package/dist/assets/{edit-page-CAfBRrHn.js → edit-page-lo6LC4Ie.js} +6 -6
  26. package/dist/assets/{error-panel-Ddr_mbqR.js → error-panel-D_1OmgVJ.js} +1 -1
  27. package/dist/assets/{file-explorer-panel-DhpN8_pR.js → file-explorer-panel-CG5na8ox.js} +3 -3
  28. package/dist/assets/{file-icons-BFLcd4J7.js → file-icons-CGJ6uWXm.js} +1 -1
  29. package/dist/assets/{file-name-input-x53prQQ6.js → file-name-input-DC8-M5r1.js} +1 -1
  30. package/dist/assets/{floating-outline--OlHG_yX.js → floating-outline-BOkj3eC_.js} +1 -1
  31. package/dist/assets/{focus-CZUEQpxX.js → focus-BViZMdHR.js} +1 -1
  32. package/dist/assets/{form-CJ3pB1ow.js → form-BbqpGicG.js} +2 -2
  33. package/dist/assets/{home-page-pH8-XovY.js → home-page-CU6li-ts.js} +2 -2
  34. package/dist/assets/{hooks-BqjZMbeu.js → hooks-CPpze3O4.js} +1 -1
  35. package/dist/assets/{html-to-image-B6eCuh-2.js → html-to-image-B8ja7wwq.js} +2 -2
  36. package/dist/assets/{index-CNmQbGXF.js → index-BcxGcwkJ.js} +6 -6
  37. package/dist/assets/kiosk-mode-BP35ALfP.js +1 -0
  38. package/dist/assets/{layout-DLJQyOOv.js → layout-BSHt96Sb.js} +5 -5
  39. package/dist/assets/{logs-panel-BBGNeMzu.js → logs-panel-CbZLi2XS.js} +1 -1
  40. package/dist/assets/{markdown-renderer-CcLl4-oB.js → markdown-renderer-jghC8PFL.js} +2 -2
  41. package/dist/assets/{name-cell-input-CNq9BTL7.js → name-cell-input-CN4MRZOm.js} +1 -1
  42. package/dist/assets/{outline-panel-CnGBTEs0.js → outline-panel-CvB3hUJ2.js} +1 -1
  43. package/dist/assets/{packages-panel-B17awHIF.js → packages-panel-BGgZLApn.js} +1 -1
  44. package/dist/assets/{panels-P8wFgP-8.js → panels-DCWntQim.js} +1 -1
  45. package/dist/assets/process-output-xDK6-i-G.js +1 -0
  46. package/dist/assets/{radio-group-B8OldelF.js → radio-group-DFkF8CeQ.js} +1 -1
  47. package/dist/assets/{readonly-code-display-bvftv2Nk.js → readonly-code-display-BHx0vyug.js} +1 -1
  48. package/dist/assets/{readonly-python-code-CoFR55Yt.js → readonly-python-code-Cla-uJpn.js} +1 -1
  49. package/dist/assets/{reveal-component-CfBFUsP0.js → reveal-component-Bvxyfpeh.js} +15 -15
  50. package/dist/assets/{run-page-CFoRuGGY.js → run-page-Cxc4jqCp.js} +1 -1
  51. package/dist/assets/scratchpad-panel-Bp4sg_00.js +1 -0
  52. package/dist/assets/{session-panel-D5OQ5JSm.js → session-panel-WkryRIGA.js} +1 -1
  53. package/dist/assets/{snippets-panel-DvfXacKM.js → snippets-panel-BcDwLUNv.js} +1 -1
  54. package/dist/assets/{state-CQn0dE8X.js → state-CXzKtmF5.js} +2 -2
  55. package/dist/assets/{state-LM4pQmYL.js → state-DHqaTLr2.js} +1 -1
  56. package/dist/assets/{textarea-Tswrj-fB.js → textarea-B5Bp08T3.js} +1 -1
  57. package/dist/assets/{tracing-BMvzhCBv.js → tracing-clJBeQm6.js} +1 -1
  58. package/dist/assets/{tracing-panel-DJF6cCQK.js → tracing-panel-7j9NY9lO.js} +2 -2
  59. package/dist/assets/{tree-actions-Bnmh7YGo.js → tree-actions-DLySKXUq.js} +1 -1
  60. package/dist/assets/useCellActionButton-CvQRbg1P.js +1 -0
  61. package/dist/assets/{useDeleteCell-DwNTIWuB.js → useDeleteCell-Sj06CzJn.js} +1 -1
  62. package/dist/assets/{useDependencyPanelTab-BH_Eu2Kq.js → useDependencyPanelTab-BTgQmu1R.js} +1 -1
  63. package/dist/assets/{useNotebookActions-BmO8IOgN.js → useNotebookActions-9PPlpXk8.js} +1 -1
  64. package/dist/assets/useRunCells-D5aAUcAa.js +1 -0
  65. package/dist/assets/useSplitCell-CGE6jkuF.js +1 -0
  66. package/dist/index.html +22 -22
  67. package/package.json +2 -2
  68. package/src/components/editor/errors/__tests__/auto-fix.test.ts +11 -107
  69. package/src/components/editor/errors/auto-fix.tsx +11 -31
  70. package/src/components/editor/output/MarimoTracebackOutput.tsx +2 -2
  71. package/src/core/ai/context/__tests__/registry.test.ts +133 -3
  72. package/src/core/ai/context/providers/__tests__/datasource.test.ts +3 -1
  73. package/src/core/ai/context/providers/__tests__/error.test.ts +200 -15
  74. package/src/core/ai/context/providers/datasource.ts +27 -2
  75. package/src/core/ai/context/providers/error.ts +226 -36
  76. package/src/core/ai/context/registry.ts +77 -43
  77. package/src/core/codemirror/ai/resources.ts +15 -10
  78. package/src/core/errors/errors.ts +2 -1
  79. package/src/core/mime.ts +11 -4
  80. package/dist/assets/MarimoErrorOutput-D07aAGkQ.js +0 -12
  81. package/dist/assets/cell-link-exzcyUhT.js +0 -1
  82. package/dist/assets/components-DinLkTiR.js +0 -1
  83. package/dist/assets/datasource-BCOYpQ69.js +0 -3
  84. package/dist/assets/kiosk-mode-BBfHxqEx.js +0 -1
  85. package/dist/assets/process-output-BGcDSQBk.js +0 -1
  86. package/dist/assets/scratchpad-panel-DdKvJKy4.js +0 -1
  87. package/dist/assets/useCellActionButton-ibDHNca0.js +0 -1
  88. package/dist/assets/useRunCells-CTpvxsqp.js +0 -1
  89. package/dist/assets/useSplitCell-CFO4Cg5B.js +0 -1
  90. package/src/core/ai/context/providers/__tests__/__snapshots__/error.test.ts.snap +0 -3
package/dist/index.html CHANGED
@@ -66,7 +66,7 @@
66
66
  <marimo-server-token data-token="{{ server_token }}" hidden></marimo-server-token>
67
67
  <!-- /TODO -->
68
68
  <title>{{ title }}</title>
69
- <script type="module" crossorigin src="./assets/index-CNmQbGXF.js"></script>
69
+ <script type="module" crossorigin src="./assets/index-BcxGcwkJ.js"></script>
70
70
  <link rel="modulepreload" crossorigin href="./assets/preload-helper-BW0IMuFq.js">
71
71
  <link rel="modulepreload" crossorigin href="./assets/chunk-LvLJmgfZ.js">
72
72
  <link rel="modulepreload" crossorigin href="./assets/react-Bj1aDYRI.js">
@@ -133,7 +133,7 @@
133
133
  <link rel="modulepreload" crossorigin href="./assets/debounce-OiXznToA.js">
134
134
  <link rel="modulepreload" crossorigin href="./assets/database-zap-DIlSqcdp.js">
135
135
  <link rel="modulepreload" crossorigin href="./assets/main-DmhaVp6Y.js">
136
- <link rel="modulepreload" crossorigin href="./assets/cells-DENsmH9t.js">
136
+ <link rel="modulepreload" crossorigin href="./assets/cells-RJTD-euN.js">
137
137
  <link rel="modulepreload" crossorigin href="./assets/kbd-UVzWBHfi.js">
138
138
  <link rel="modulepreload" crossorigin href="./assets/useInstallPackage-C1Dd0aIZ.js">
139
139
  <link rel="modulepreload" crossorigin href="./assets/alert-dialog-CC0gG4Av.js">
@@ -146,40 +146,40 @@
146
146
  <link rel="modulepreload" crossorigin href="./assets/usePress-BSFUeqnS.js">
147
147
  <link rel="modulepreload" crossorigin href="./assets/input-DB2LiTiQ.js">
148
148
  <link rel="modulepreload" crossorigin href="./assets/ImperativeModal-B62Q6S9l.js">
149
- <link rel="modulepreload" crossorigin href="./assets/cell-link-exzcyUhT.js">
149
+ <link rel="modulepreload" crossorigin href="./assets/cell-link-CBRggkzf.js">
150
150
  <link rel="modulepreload" crossorigin href="./assets/config-DMNo9K-z.js">
151
151
  <link rel="modulepreload" crossorigin href="./assets/alert-1y_DnRWn.js">
152
152
  <link rel="modulepreload" crossorigin href="./assets/chevron-right-C7RH0Nc7.js">
153
153
  <link rel="modulepreload" crossorigin href="./assets/dropdown-menu-DfGLyCbP.js">
154
154
  <link rel="modulepreload" crossorigin href="./assets/links-CCkJpphF.js">
155
- <link rel="modulepreload" crossorigin href="./assets/useRunCells-CTpvxsqp.js">
155
+ <link rel="modulepreload" crossorigin href="./assets/useRunCells-D5aAUcAa.js">
156
156
  <link rel="modulepreload" crossorigin href="./assets/copy-D8MtpXgN.js">
157
157
  <link rel="modulepreload" crossorigin href="./assets/copy-IBNGDypD.js">
158
158
  <link rel="modulepreload" crossorigin href="./assets/copy-icon-EHMT-qlr.js">
159
- <link rel="modulepreload" crossorigin href="./assets/RenderHTML-v15QgtRg.js">
160
- <link rel="modulepreload" crossorigin href="./assets/datasource-BCOYpQ69.js">
161
- <link rel="modulepreload" crossorigin href="./assets/state-LM4pQmYL.js">
159
+ <link rel="modulepreload" crossorigin href="./assets/RenderHTML-B9mw7TD1.js">
160
+ <link rel="modulepreload" crossorigin href="./assets/datasource-RP7m6Xrh.js">
161
+ <link rel="modulepreload" crossorigin href="./assets/state-DHqaTLr2.js">
162
162
  <link rel="modulepreload" crossorigin href="./assets/hat-glasses-DlK0E4SX.js">
163
163
  <link rel="modulepreload" crossorigin href="./assets/package-BTIV9-Dk.js">
164
164
  <link rel="modulepreload" crossorigin href="./assets/sparkles-COaEc8Qn.js">
165
- <link rel="modulepreload" crossorigin href="./assets/MarimoErrorOutput-D07aAGkQ.js">
165
+ <link rel="modulepreload" crossorigin href="./assets/MarimoErrorOutput-BokuSnpU.js">
166
166
  <link rel="modulepreload" crossorigin href="./assets/ErrorBoundary-Bo313Z9X.js">
167
167
  <link rel="modulepreload" crossorigin href="./assets/eye-off-DI0EQXw0.js">
168
168
  <link rel="modulepreload" crossorigin href="./assets/refresh-cw-C9FftltI.js">
169
- <link rel="modulepreload" crossorigin href="./assets/tree-actions-Bnmh7YGo.js">
169
+ <link rel="modulepreload" crossorigin href="./assets/tree-actions-DLySKXUq.js">
170
170
  <link rel="modulepreload" crossorigin href="./assets/spinner-BbI9qk88.js">
171
- <link rel="modulepreload" crossorigin href="./assets/html-to-image-B6eCuh-2.js">
172
- <link rel="modulepreload" crossorigin href="./assets/focus-CZUEQpxX.js">
171
+ <link rel="modulepreload" crossorigin href="./assets/html-to-image-B8ja7wwq.js">
172
+ <link rel="modulepreload" crossorigin href="./assets/focus-BViZMdHR.js">
173
173
  <link rel="modulepreload" crossorigin href="./assets/useAsyncData-DAQcLiyE.js">
174
174
  <link rel="modulepreload" crossorigin href="./assets/LazyAnyLanguageCodeMirror-DpraoNlO.js">
175
175
  <link rel="modulepreload" crossorigin href="./assets/micromark-factory-space-BUQpMdx2.js">
176
176
  <link rel="modulepreload" crossorigin href="./assets/chunk-5FQGJX7Z-OScactr4.js">
177
- <link rel="modulepreload" crossorigin href="./assets/markdown-renderer-CcLl4-oB.js">
177
+ <link rel="modulepreload" crossorigin href="./assets/markdown-renderer-jghC8PFL.js">
178
178
  <link rel="modulepreload" crossorigin href="./assets/command-DRHbYHUP.js">
179
179
  <link rel="modulepreload" crossorigin href="./assets/field-DlNY-dDH.js">
180
180
  <link rel="modulepreload" crossorigin href="./assets/popover-DMNO6Poc.js">
181
181
  <link rel="modulepreload" crossorigin href="./assets/errors-9jMmWHd9.js">
182
- <link rel="modulepreload" crossorigin href="./assets/download-4NoBestd.js">
182
+ <link rel="modulepreload" crossorigin href="./assets/download-CJ6tdZ-1.js">
183
183
  <link rel="modulepreload" crossorigin href="./assets/table-CnW850Wt.js">
184
184
  <link rel="modulepreload" crossorigin href="./assets/useIframeCapabilities-B0dNZiKK.js">
185
185
  <link rel="modulepreload" crossorigin href="./assets/error-banner-BSQVN46J.js">
@@ -199,21 +199,21 @@
199
199
  <link rel="modulepreload" crossorigin href="./assets/plus-ZXRHY1up.js">
200
200
  <link rel="modulepreload" crossorigin href="./assets/trash-2-CqTUwVuU.js">
201
201
  <link rel="modulepreload" crossorigin href="./assets/react-resizable-panels.browser.esm-Ce2ksurd.js">
202
- <link rel="modulepreload" crossorigin href="./assets/JsonOutput-C3c9GGaV.js">
202
+ <link rel="modulepreload" crossorigin href="./assets/JsonOutput-CYIo9GSP.js">
203
203
  <link rel="modulepreload" crossorigin href="./assets/chart-no-axes-column-DVEV2j1H.js">
204
204
  <link rel="modulepreload" crossorigin href="./assets/square-function-Dx0pKHko.js">
205
205
  <link rel="modulepreload" crossorigin href="./assets/spec-CDgWI0fT.js">
206
- <link rel="modulepreload" crossorigin href="./assets/column-preview-BPgYXdDd.js">
206
+ <link rel="modulepreload" crossorigin href="./assets/column-preview-dW7xtQ7S.js">
207
207
  <link rel="modulepreload" crossorigin href="./assets/icons-avFV3lBF.js">
208
- <link rel="modulepreload" crossorigin href="./assets/radio-group-B8OldelF.js">
209
- <link rel="modulepreload" crossorigin href="./assets/floating-outline--OlHG_yX.js">
208
+ <link rel="modulepreload" crossorigin href="./assets/radio-group-DFkF8CeQ.js">
209
+ <link rel="modulepreload" crossorigin href="./assets/floating-outline-BOkj3eC_.js">
210
210
  <link rel="modulepreload" crossorigin href="./assets/objectWithoutPropertiesLoose-BkUn3I0-.js">
211
211
  <link rel="modulepreload" crossorigin href="./assets/esm-X3Tr2pur.js">
212
- <link rel="modulepreload" crossorigin href="./assets/readonly-python-code-CoFR55Yt.js">
212
+ <link rel="modulepreload" crossorigin href="./assets/readonly-python-code-Cla-uJpn.js">
213
213
  <link rel="modulepreload" crossorigin href="./assets/file-headphone-CUN2DC78.js">
214
214
  <link rel="modulepreload" crossorigin href="./assets/file-BvoBtS_V.js">
215
215
  <link rel="modulepreload" crossorigin href="./assets/image-BzUcK6ho.js">
216
- <link rel="modulepreload" crossorigin href="./assets/file-icons-BFLcd4J7.js">
216
+ <link rel="modulepreload" crossorigin href="./assets/file-icons-CGJ6uWXm.js">
217
217
  <link rel="modulepreload" crossorigin href="./assets/switch-DvDNxcZP.js">
218
218
  <link rel="modulepreload" crossorigin href="./assets/events-XR_LpvHc.js">
219
219
  <link rel="modulepreload" crossorigin href="./assets/globals-Bx8Km3LH.js">
@@ -222,11 +222,11 @@
222
222
  <link rel="modulepreload" crossorigin href="./assets/memoize-Tp7rARFe.js">
223
223
  <link rel="modulepreload" crossorigin href="./assets/get-C-qh_et5.js">
224
224
  <link rel="modulepreload" crossorigin href="./assets/_baseSet-CsW0tABf.js">
225
- <link rel="modulepreload" crossorigin href="./assets/state-CQn0dE8X.js">
225
+ <link rel="modulepreload" crossorigin href="./assets/state-CXzKtmF5.js">
226
226
  <link rel="modulepreload" crossorigin href="./assets/label-CFvCMYuj.js">
227
- <link rel="modulepreload" crossorigin href="./assets/textarea-Tswrj-fB.js">
227
+ <link rel="modulepreload" crossorigin href="./assets/textarea-B5Bp08T3.js">
228
228
  <link rel="modulepreload" crossorigin href="./assets/refresh-ccw-Bee7JLOl.js">
229
- <link rel="modulepreload" crossorigin href="./assets/form-CJ3pB1ow.js">
229
+ <link rel="modulepreload" crossorigin href="./assets/form-BbqpGicG.js">
230
230
  <link rel="modulepreload" crossorigin href="./assets/renderShortcut-LpVarhnQ.js">
231
231
  <link rel="modulepreload" crossorigin href="./assets/useBoolean-BMzj74q1.js">
232
232
  <link rel="modulepreload" crossorigin href="./assets/useDeepCompareMemoize-CWcgQCbT.js">
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@marimo-team/frontend",
3
- "version": "0.23.14-dev19",
3
+ "version": "0.23.14-dev21",
4
4
  "main": "dist/main.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "type": "module",
@@ -56,7 +56,7 @@
56
56
  "@lezer/python": "^1.1.18",
57
57
  "@marimo-team/codemirror-ai": "^0.3.7",
58
58
  "@marimo-team/codemirror-languageserver": "^1.16.12",
59
- "@marimo-team/codemirror-mcp": "^0.1.5",
59
+ "@marimo-team/codemirror-mcp": "^0.1.7",
60
60
  "@marimo-team/codemirror-sql": "^0.2.8",
61
61
  "@marimo-team/llm-info": "workspace:*",
62
62
  "@marimo-team/marimo-api": "workspace:*",
@@ -1,119 +1,23 @@
1
1
  /* Copyright 2026 Marimo. All rights reserved. */
2
2
 
3
- import { beforeEach, describe, expect, it, vi } from "vitest";
3
+ import { describe, expect, it } from "vitest";
4
4
  import { cellId } from "@/__tests__/branded";
5
- import type { MarimoError } from "@/core/kernel/messages";
5
+ import { buildFixInChatPrompt } from "../auto-fix";
6
6
 
7
- const getDatasourceContext = vi.fn<(id: unknown) => string | null>(() => null);
8
-
9
- vi.mock("@/core/ai/context/providers/datasource", () => ({
10
- getDatasourceContext: (id: unknown) => getDatasourceContext(id),
11
- }));
12
-
13
- const { buildFixPrompt, buildFixPromptFromText } = await import("../auto-fix");
14
-
15
- describe("buildFixPromptFromText", () => {
16
- beforeEach(() => {
17
- getDatasourceContext.mockReset();
18
- getDatasourceContext.mockReturnValue(null);
19
- });
20
-
21
- it("includes the cell id in the header when provided", () => {
22
- const prompt = buildFixPromptFromText("boom", cellId("cell-1"));
23
- expect(prompt).toBe(
24
- "My cell (id: cell-1) produced the following error. Please fix it:\n\nboom",
25
- );
26
- });
27
-
28
- it("uses a generic header when no cell id is provided", () => {
29
- const prompt = buildFixPromptFromText("boom");
30
- expect(prompt).toBe(
31
- "My code gives the following error. Please fix it:\n\nboom",
7
+ describe("buildFixInChatPrompt", () => {
8
+ it("references the per-cell error context URI", () => {
9
+ expect(buildFixInChatPrompt(cellId("cell-1"))).toBe(
10
+ "@error://cell-1\n\nPlease fix this error.",
32
11
  );
33
12
  });
34
13
 
35
- it("appends datasource context when explicitly requested for the cell", () => {
36
- getDatasourceContext.mockReturnValue("@datasource://my_db");
37
- const prompt = buildFixPromptFromText("boom", cellId("cell-1"), {
38
- includeDatasourceContext: true,
39
- });
40
- expect(prompt).toBe(
41
- "My cell (id: cell-1) produced the following error. Please fix it:\n\nboom\n\nDatabase schema: @datasource://my_db",
14
+ it("falls back to inline error text when no cell id", () => {
15
+ expect(buildFixInChatPrompt(undefined, "ValueError: boom")).toBe(
16
+ "My code gives the following error. Please fix it:\n\nValueError: boom",
42
17
  );
43
18
  });
44
19
 
45
- it("does not append datasource context by default", () => {
46
- getDatasourceContext.mockReturnValue("@datasource://my_db");
47
- const prompt = buildFixPromptFromText("boom", cellId("cell-1"));
48
- expect(prompt).toBe(
49
- "My cell (id: cell-1) produced the following error. Please fix it:\n\nboom",
50
- );
51
- expect(getDatasourceContext).not.toHaveBeenCalled();
52
- });
53
-
54
- it("does not look up datasource context without a cell id", () => {
55
- buildFixPromptFromText("boom", undefined, {
56
- includeDatasourceContext: true,
57
- });
58
- expect(getDatasourceContext).not.toHaveBeenCalled();
59
- });
60
- });
61
-
62
- describe("buildFixPrompt", () => {
63
- beforeEach(() => {
64
- getDatasourceContext.mockReset();
65
- getDatasourceContext.mockReturnValue(null);
66
- });
67
-
68
- it("uses the error message when present", () => {
69
- const errors: MarimoError[] = [
70
- { type: "sql-error", msg: "syntax error", sql_statement: "SELECT" },
71
- ];
72
- expect(buildFixPrompt(errors, cellId("cell-1"))).toBe(
73
- "My cell (id: cell-1) produced the following error. Please fix it:\n\nsyntax error",
74
- );
75
- });
76
-
77
- it("joins multiple errors with newlines", () => {
78
- const errors: MarimoError[] = [
79
- { type: "syntax", msg: "bad syntax" },
80
- {
81
- type: "exception",
82
- exception_type: "ValueError",
83
- msg: "bad value",
84
- raising_cell: null,
85
- },
86
- ];
87
- expect(buildFixPrompt(errors, cellId("cell-1"))).toBe(
88
- "My cell (id: cell-1) produced the following error. Please fix it:\n\nbad syntax\nbad value",
89
- );
90
- });
91
-
92
- it("falls back to the error type when there is no message", () => {
93
- const errors: MarimoError[] = [
94
- { type: "multiple-defs", name: "foo", cells: [cellId("foo")] },
95
- ];
96
- expect(buildFixPrompt(errors, cellId("cell-1"))).toBe(
97
- "My cell (id: cell-1) produced the following error. Please fix it:\n\nmultiple-defs",
98
- );
99
- });
100
-
101
- it("appends datasource context for SQL errors", () => {
102
- getDatasourceContext.mockReturnValue("@datasource://my_db");
103
- const errors: MarimoError[] = [
104
- { type: "sql-error", msg: "syntax error", sql_statement: "SELECT" },
105
- ];
106
- expect(buildFixPrompt(errors, cellId("cell-1"))).toBe(
107
- "My cell (id: cell-1) produced the following error. Please fix it:\n\nsyntax error\n\nDatabase schema: @datasource://my_db",
108
- );
109
- });
110
-
111
- it("does not append datasource context for non-SQL errors", () => {
112
- getDatasourceContext.mockReturnValue("@datasource://my_db");
113
- const errors: MarimoError[] = [{ type: "syntax", msg: "bad syntax" }];
114
- expect(buildFixPrompt(errors, cellId("cell-1"))).toBe(
115
- "My cell (id: cell-1) produced the following error. Please fix it:\n\nbad syntax",
116
- );
117
- expect(getDatasourceContext).not.toHaveBeenCalled();
20
+ it("uses a generic prompt when no cell id and no error text", () => {
21
+ expect(buildFixInChatPrompt(undefined)).toBe("Please fix this error.");
118
22
  });
119
23
  });
@@ -21,44 +21,24 @@ import { aiCompletionCellAtom } from "@/core/ai/state";
21
21
  import { notebookAtom, useCellActions } from "@/core/cells/cells";
22
22
  import type { CellId } from "@/core/cells/ids";
23
23
  import { aiFeaturesEnabledAtom } from "@/core/config/config";
24
- import { getDatasourceContext } from "@/core/ai/context/providers/datasource";
25
24
  import { getAutoFixes } from "@/core/errors/errors";
26
25
  import type { MarimoError } from "@/core/kernel/messages";
27
26
  import { cn } from "@/utils/cn";
28
27
  import { useOpenAiAssistant } from "../chrome/wrapper/useOpenAiAssistant";
29
28
  import { type FixMode, useFixMode } from "./fix-mode";
30
29
 
31
- export function buildFixPromptFromText(
32
- errorText: string,
33
- cellId?: CellId,
34
- {
35
- includeDatasourceContext = false,
36
- }: { includeDatasourceContext?: boolean } = {},
30
+ export function buildFixInChatPrompt(
31
+ cellId: CellId | undefined,
32
+ fallbackErrorText?: string,
37
33
  ): string {
38
- const header =
39
- cellId != null
40
- ? `My cell (id: ${cellId}) produced the following error. Please fix it:`
41
- : "My code gives the following error. Please fix it:";
42
- let prompt = `${header}\n\n${errorText}`;
43
- if (cellId != null && includeDatasourceContext) {
44
- const datasourceContext = getDatasourceContext(cellId);
45
- if (datasourceContext) {
46
- prompt += `\n\nDatabase schema: ${datasourceContext}`;
47
- }
34
+ if (cellId != null) {
35
+ return `@error://${cellId}\n\nPlease fix this error.`;
48
36
  }
49
- return prompt;
50
- }
51
-
52
- export function buildFixPrompt(errors: MarimoError[], cellId: CellId): string {
53
- const errorText = errors
54
- .map((error) => ("msg" in error && error.msg ? error.msg : error.type))
55
- .join("\n");
56
- const includeDatasourceContext = errors.some(
57
- (error) => error.type === "sql-error",
58
- );
59
- return buildFixPromptFromText(errorText, cellId, {
60
- includeDatasourceContext,
61
- });
37
+ const errorText = fallbackErrorText?.trim();
38
+ if (errorText) {
39
+ return `My code gives the following error. Please fix it:\n\n${errorText}`;
40
+ }
41
+ return "Please fix this error.";
62
42
  }
63
43
 
64
44
  export const AutoFixButton = ({
@@ -112,7 +92,7 @@ export const AutoFixButton = ({
112
92
 
113
93
  const openAISidebar = () => {
114
94
  openAiAssistant({
115
- prompt: buildFixPrompt(errors, cellId),
95
+ prompt: buildFixInChatPrompt(cellId),
116
96
  });
117
97
  };
118
98
 
@@ -42,7 +42,7 @@ import {
42
42
  getTracebackInfo,
43
43
  } from "@/utils/traceback";
44
44
  import { useOpenAiAssistant } from "../chrome/wrapper/useOpenAiAssistant";
45
- import { AIFixButton, buildFixPromptFromText } from "../errors/auto-fix";
45
+ import { AIFixButton, buildFixInChatPrompt } from "../errors/auto-fix";
46
46
  import { MangledSegments } from "../errors/mangled-local-chip";
47
47
  import { CellLinkTraceback } from "../links/cell-link";
48
48
  import type { OnRefactorWithAI } from "../Output";
@@ -101,7 +101,7 @@ export const MarimoTracebackOutput = ({
101
101
 
102
102
  const openAISidebar = () => {
103
103
  openAiAssistant({
104
- prompt: buildFixPromptFromText(lastTracebackLine, cellId),
104
+ prompt: buildFixInChatPrompt(cellId, lastTracebackLine),
105
105
  });
106
106
  };
107
107
 
@@ -176,6 +176,33 @@ class FileContextProvider extends AIContextProvider<FileContextItem> {
176
176
  }
177
177
  }
178
178
 
179
+ // Second mock provider with the same context type as MockContextProvider
180
+ class SecondaryMockProvider extends AIContextProvider<MockContextItem> {
181
+ readonly title = "Secondary Mock Items";
182
+ readonly mentionPrefix = "@";
183
+ readonly contextType = "mock";
184
+
185
+ getItems(): MockContextItem[] {
186
+ return [
187
+ {
188
+ type: "mock",
189
+ uri: this.asURI("secondary-item"),
190
+ name: "Secondary Item",
191
+ description: "From the second mock provider",
192
+ data: { value: "secondary" },
193
+ },
194
+ ];
195
+ }
196
+
197
+ formatContext(item: MockContextItem): string {
198
+ return `Secondary: ${item.name}`;
199
+ }
200
+
201
+ formatCompletion(item: MockContextItem): Completion {
202
+ return this.createBasicCompletion(item);
203
+ }
204
+ }
205
+
179
206
  describe("AIContextProvider", () => {
180
207
  let provider: MockContextProvider;
181
208
 
@@ -411,6 +438,95 @@ describe("AIContextRegistry", () => {
411
438
  });
412
439
  });
413
440
 
441
+ describe("resolveItems", () => {
442
+ let mockGetItems: ReturnType<typeof vi.spyOn>;
443
+ let fileGetItems: ReturnType<typeof vi.spyOn>;
444
+
445
+ beforeEach(() => {
446
+ registry.register(mockProvider);
447
+ registry.register(fileProvider);
448
+ mockGetItems = vi.spyOn(mockProvider, "getItems");
449
+ fileGetItems = vi.spyOn(fileProvider, "getItems");
450
+ });
451
+
452
+ it("should resolve valid IDs from the matching providers only", () => {
453
+ const resolved = registry.resolveItems([
454
+ "mock://item1",
455
+ "file://config.py",
456
+ ] as ContextLocatorId[]);
457
+
458
+ expect(resolved).toHaveLength(2);
459
+ expect(resolved.map((item) => item.uri)).toEqual([
460
+ "mock://item1",
461
+ "file://config.py",
462
+ ]);
463
+ expect(mockGetItems).toHaveBeenCalledTimes(1);
464
+ expect(fileGetItems).toHaveBeenCalledTimes(1);
465
+ });
466
+
467
+ it("should not call unrelated providers", () => {
468
+ registry.resolveItems(["mock://item1"] as ContextLocatorId[]);
469
+
470
+ expect(mockGetItems).toHaveBeenCalledTimes(1);
471
+ expect(fileGetItems).not.toHaveBeenCalled();
472
+ });
473
+
474
+ it("should ignore unknown or invalid URIs", () => {
475
+ const resolved = registry.resolveItems([
476
+ "mock://nonexistent",
477
+ "unknown://item",
478
+ "malformed" as ContextLocatorId,
479
+ ] as ContextLocatorId[]);
480
+
481
+ expect(resolved).toEqual([]);
482
+ expect(mockGetItems).toHaveBeenCalledTimes(1);
483
+ expect(fileGetItems).not.toHaveBeenCalled();
484
+ });
485
+
486
+ it("should return empty array for empty input", () => {
487
+ expect(registry.resolveItems([])).toEqual([]);
488
+ expect(mockGetItems).not.toHaveBeenCalled();
489
+ expect(fileGetItems).not.toHaveBeenCalled();
490
+ });
491
+
492
+ it("should preserve requested order when providers are interleaved", () => {
493
+ const resolved = registry.resolveItems([
494
+ "mock://item1",
495
+ "file://config.py",
496
+ "mock://item2",
497
+ "file://utils/helpers.py",
498
+ ] as ContextLocatorId[]);
499
+
500
+ expect(resolved.map((item) => item.uri)).toEqual([
501
+ "mock://item1",
502
+ "file://config.py",
503
+ "mock://item2",
504
+ "file://utils/helpers.py",
505
+ ]);
506
+ // Each provider is still queried only once, regardless of interleaving.
507
+ expect(mockGetItems).toHaveBeenCalledTimes(1);
508
+ expect(fileGetItems).toHaveBeenCalledTimes(1);
509
+ });
510
+
511
+ it("should resolve items from all providers that share a context type", () => {
512
+ const secondaryProvider = new SecondaryMockProvider();
513
+ const secondaryGetItems = vi.spyOn(secondaryProvider, "getItems");
514
+ registry.register(secondaryProvider);
515
+
516
+ const resolved = registry.resolveItems([
517
+ "mock://item1",
518
+ "mock://secondary-item",
519
+ ] as ContextLocatorId[]);
520
+
521
+ expect(resolved.map((item) => item.uri)).toEqual([
522
+ "mock://item1",
523
+ "mock://secondary-item",
524
+ ]);
525
+ expect(mockGetItems).toHaveBeenCalledTimes(1);
526
+ expect(secondaryGetItems).toHaveBeenCalledTimes(1);
527
+ });
528
+ });
529
+
414
530
  describe("getContextInfo", () => {
415
531
  beforeEach(() => {
416
532
  registry.register(mockProvider);
@@ -531,6 +647,19 @@ describe("AIContextRegistry", () => {
531
647
  expect(formatted).toContain("Mock: Item 1 (value1)");
532
648
  expect(formatted.split("\n\n")).toHaveLength(1);
533
649
  });
650
+
651
+ it("should format items from the provider that owns them", () => {
652
+ registry.register(new SecondaryMockProvider());
653
+
654
+ const formatted = registry.formatContextForAI([
655
+ "mock://item1",
656
+ "mock://secondary-item",
657
+ ] as ContextLocatorId[]);
658
+
659
+ expect(formatted).toBe(
660
+ "Mock: Item 1 (value1)\n\nSecondary: Secondary Item",
661
+ );
662
+ });
534
663
  });
535
664
 
536
665
  describe("edge cases and error handling", () => {
@@ -621,7 +750,7 @@ describe("AIContextRegistry", () => {
621
750
  expect(provider).toBe(errorProvider);
622
751
 
623
752
  const items = registry.getAllItems();
624
- expect(items).toHaveLength(1);
753
+ expect(items).toHaveLength(3);
625
754
  expect(items[0].type).toBe("error");
626
755
  expect(items[0].name).toBe("Errors");
627
756
  });
@@ -654,10 +783,11 @@ describe("AIContextRegistry", () => {
654
783
  expect(provider).toBeDefined();
655
784
 
656
785
  const items = provider!.getItems();
657
- expect(items).toHaveLength(1);
786
+ expect(items).toHaveLength(3);
658
787
 
659
788
  const completion = provider!.formatCompletion(items[0]);
660
789
  expect(completion.label).toBe("@Errors");
790
+ expect(completion.apply).toBe("@error://all");
661
791
  expect(completion.type).toBe("error");
662
792
  });
663
793
 
@@ -690,7 +820,7 @@ describe("AIContextRegistry", () => {
690
820
  const errorItems = items.filter((item) => item.type === "error");
691
821
  const mockItems = items.filter((item) => item.type === "mock");
692
822
 
693
- expect(errorItems).toHaveLength(1);
823
+ expect(errorItems).toHaveLength(3);
694
824
  expect(mockItems).toHaveLength(3);
695
825
  });
696
826
 
@@ -1,6 +1,7 @@
1
1
  /* Copyright 2026 Marimo. All rights reserved. */
2
2
  /* oxlint-disable typescript/no-explicit-any */
3
3
 
4
+ import { createStore } from "jotai";
4
5
  import { beforeEach, describe, expect, it } from "vitest";
5
6
  import { cellId, variableName } from "@/__tests__/branded";
6
7
  import type {
@@ -634,7 +635,8 @@ describe("DatasourceContextProvider", () => {
634
635
 
635
636
  describe("getDatasourceContext", () => {
636
637
  it("should return null if no cell ID is found", () => {
637
- const context = getDatasourceContext(cellId("1"));
638
+ const store = createStore();
639
+ const context = getDatasourceContext(cellId("1"), store);
638
640
  expect(context).toBeNull();
639
641
  });
640
642
  });