@marimo-team/frontend 0.25.3-dev104 → 0.25.3-dev108

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 (112) hide show
  1. package/dist/assets/{CellStatus-DVrvejMC.js → CellStatus-_Aw9_foI.js} +1 -1
  2. package/dist/assets/{ConnectedDataExplorerComponent-Dft8R6l5.js → ConnectedDataExplorerComponent-BRgqbAsc.js} +1 -1
  3. package/dist/assets/{ErrorBoundary-0akNKvJm.js → ErrorBoundary-DxSzjvbx.js} +2 -2
  4. package/dist/assets/{JsonOutput-DeUmpc_f.js → JsonOutput-B7pGj79O.js} +2 -2
  5. package/dist/assets/{MarimoErrorOutput-BazxeAYV.js → MarimoErrorOutput-Bzo6Bkp5.js} +1 -1
  6. package/dist/assets/{RenderHTML-CbAdeual.js → RenderHTML-D6AC0IhC.js} +1 -1
  7. package/dist/assets/{RunButton-CjKwgCFU.js → RunButton-BjYsPiKa.js} +1 -1
  8. package/dist/assets/{add-cell-with-ai-BKVEws3J.js → add-cell-with-ai-DlpS2-wQ.js} +4 -4
  9. package/dist/assets/{add-connection-dialog-DS7LTz1T.js → add-connection-dialog-CyNAB_W2.js} +1 -1
  10. package/dist/assets/{agent-panel-B34QcdOK.js → agent-panel-_lzeDJ1g.js} +1 -1
  11. package/dist/assets/{ai-model-dropdown-DqFJCFVR.js → ai-model-dropdown-DSTTUxpi.js} +1 -1
  12. package/dist/assets/{app-config-button-CVh4UKi9.js → app-config-button-ChYKLsLO.js} +1 -1
  13. package/dist/assets/{blob-Bw0ZQoLx.js → blob-DTYOX-m5.js} +1 -1
  14. package/dist/assets/{cell-editor-DQ0io5Ye.js → cell-editor-Beg8ahPA.js} +2 -2
  15. package/dist/assets/{cell-link-DvOIu6A3.js → cell-link-D3rkqgbU.js} +1 -1
  16. package/dist/assets/{cells-Do-63MKT.js → cells-2HETnlvE.js} +5 -5
  17. package/dist/assets/{chat-display-DnkhBxdh.js → chat-display-0GIEXLvN.js} +1 -1
  18. package/dist/assets/{chat-panel-CN3qoX9G.js → chat-panel-BuWn4Z_F.js} +1 -1
  19. package/dist/assets/{chat-ui-B54K5qqr.js → chat-ui-X0s3vvdf.js} +1 -1
  20. package/dist/assets/{column-preview-DmxzHzaW.js → column-preview-yI7-INkZ.js} +1 -1
  21. package/dist/assets/{command-palette-CciCeRhy.js → command-palette-D6WLW1Ie.js} +1 -1
  22. package/dist/assets/{common-BCyx7t1i.js → common-DgXKwblm.js} +1 -1
  23. package/dist/assets/{components-CDvWXfXq.js → components-CuMhY4Sf.js} +1 -1
  24. package/dist/assets/{datasource-DieftweT.js → datasource-D9JMcEAP.js} +1 -1
  25. package/dist/assets/{dependency-graph-panel-IfcqTHgq.js → dependency-graph-panel-BVJWPCvw.js} +3 -3
  26. package/dist/assets/{documentation-panel-DeLCgVcq.js → documentation-panel--wI4XHso.js} +1 -1
  27. package/dist/assets/{download-BzfVCqUq.js → download-Dod42wfD.js} +1 -1
  28. package/dist/assets/{edit-page-HMyk4cWw.js → edit-page-EmacXgdB.js} +4 -4
  29. package/dist/assets/{error-entries-DjjWrbt4.js → error-entries-D00nWhWE.js} +1 -1
  30. package/dist/assets/{error-panel-CiG3JJA3.js → error-panel-CcN_1PWf.js} +1 -1
  31. package/dist/assets/{feedback-button-B8zVQEi6.js → feedback-button-ByGgqUsX.js} +1 -1
  32. package/dist/assets/feedback-button-tbWwJ_t6.js +1 -0
  33. package/dist/assets/{file-explorer-panel-BPD8Q0L-.js → file-explorer-panel-eTEqtMPW.js} +1 -1
  34. package/dist/assets/{file-name-input-CdkF9K3I.js → file-name-input-D5SfTNWh.js} +1 -1
  35. package/dist/assets/{floating-outline-TfDWJXBm.js → floating-outline-B-k3P_AO.js} +1 -1
  36. package/dist/assets/{gallery-page-BJpenPdQ.js → gallery-page-BzbMhDHi.js} +1 -1
  37. package/dist/assets/{glide-data-editor-DO15Nm-R.js → glide-data-editor-BMqhUrHI.js} +1 -1
  38. package/dist/assets/{home-page-mvqldGvD.js → home-page-BvA1BCmX.js} +1 -1
  39. package/dist/assets/{hooks-C4AJfqV0.js → hooks-CaRBg2ni.js} +1 -1
  40. package/dist/assets/{index-C2XzUsS7.js → index-hwaZTQ9l.js} +9 -9
  41. package/dist/assets/{layout-1kSh6fBF.js → layout-C-NAerIZ.js} +3 -3
  42. package/dist/assets/{logs-panel--QbHo7uS.js → logs-panel-B3T1GFBk.js} +1 -1
  43. package/dist/assets/{markdown-renderer-DJ7H8Rps.js → markdown-renderer-BhiTvxtL.js} +1 -1
  44. package/dist/assets/{name-cell-input-6Gd19S8T.js → name-cell-input-CgAObR6N.js} +1 -1
  45. package/dist/assets/{outline-panel-CjKvunvX.js → outline-panel-BhBb7Vqw.js} +1 -1
  46. package/dist/assets/{packages-panel-Gyrqi-MZ.js → packages-panel-Dz8rOIrh.js} +1 -1
  47. package/dist/assets/{panel-accordion-state-D49TNCLQ.js → panel-accordion-state-ZsUdpAYn.js} +1 -1
  48. package/dist/assets/{panels-DfbxoeGa.js → panels-B0lqLcI0.js} +1 -1
  49. package/dist/assets/{process-output-CgkoeA1-.js → process-output-CeOMwE17.js} +1 -1
  50. package/dist/assets/{readonly-code-display-BMbl_4BR.js → readonly-code-display-TvOC7ESE.js} +1 -1
  51. package/dist/assets/{readonly-python-code-BnPfpOJM.js → readonly-python-code-Cqkfdeyo.js} +1 -1
  52. package/dist/assets/{reveal-component-D84yAzG7.js → reveal-component-y06O6YuH.js} +1 -1
  53. package/dist/assets/{run-page-B10s8Pre.js → run-page-DHE6ET5K.js} +1 -1
  54. package/dist/assets/{runtime-details-state-Bkmgb59p.js → runtime-details-state-CKqJSfSR.js} +1 -1
  55. package/dist/assets/{scratchpad-panel-DtyjJ3yN.js → scratchpad-panel-BW_HfG5l.js} +1 -1
  56. package/dist/assets/{session-panel-Chaq1do8.js → session-panel-CdHdKUCF.js} +1 -1
  57. package/dist/assets/{snippets-panel-BaZmddOW.js → snippets-panel-DYLWOLYw.js} +1 -1
  58. package/dist/assets/{spec-uCpVvaAR.js → spec-DlH4Mp7d.js} +1 -1
  59. package/dist/assets/{state-Db73TZVD.js → state-DAqdiGqq.js} +1 -1
  60. package/dist/assets/{state-CqnCwHhY.js → state-DZN9vZ6z.js} +1 -1
  61. package/dist/assets/{tracing-C2vQMUI0.js → tracing-B0J2ctTm.js} +1 -1
  62. package/dist/assets/{tracing-panel-B4L2S2ac.js → tracing-panel-C1OCpoeE.js} +2 -2
  63. package/dist/assets/{tree-actions-JXDiioHK.js → tree-actions-sjBxIglc.js} +1 -1
  64. package/dist/assets/{useAddCell-CP3HIjGl.js → useAddCell-CaXnFGki.js} +1 -1
  65. package/dist/assets/{useCellActionButton-yi1_-emd.js → useCellActionButton-CJ90CMEj.js} +1 -1
  66. package/dist/assets/{useDeleteCell-BPLwyClM.js → useDeleteCell-D9N85822.js} +1 -1
  67. package/dist/assets/{useDependencyPanelTab-DmBiydXO.js → useDependencyPanelTab-CzAE0cm-.js} +1 -1
  68. package/dist/assets/{useNotebookActions-CfmgcJGx.js → useNotebookActions-CTKkktJB.js} +1 -1
  69. package/dist/assets/{useRunCells-jF-7tJkw.js → useRunCells-DGakx8hj.js} +1 -1
  70. package/dist/assets/{useSplitCell-B6zWL8Zf.js → useSplitCell-AK5BKPGM.js} +1 -1
  71. package/dist/index.html +21 -21
  72. package/package.json +2 -2
  73. package/src/components/data-table/__tests__/chart-spec-model.test.ts +195 -195
  74. package/src/components/data-table/charts/__tests__/spec-snapshot.test.ts +20 -20
  75. package/src/components/data-table/charts/__tests__/spec.test.ts +78 -52
  76. package/src/components/data-table/charts/chart-spec/spec.ts +68 -43
  77. package/src/components/data-table/charts/charts.tsx +5 -5
  78. package/src/components/data-table/column-summary/chart-spec-model.tsx +23 -16
  79. package/src/components/dependency-graph/dependency-graph-tree.tsx +8 -8
  80. package/src/components/dependency-graph/elements.ts +24 -21
  81. package/src/components/dependency-graph/utils/__tests__/layout.test.ts +18 -11
  82. package/src/components/editor/output/ansi-reduce.ts +30 -23
  83. package/src/components/editor/renderers/grid-layout/grid-layout.tsx +12 -6
  84. package/src/core/ai/tools/base.ts +16 -7
  85. package/src/core/ai/tools/edit-notebook-tool.ts +47 -45
  86. package/src/core/ai/tools/registry.ts +13 -8
  87. package/src/core/ai/tools/sample-tool.ts +6 -7
  88. package/src/core/cells/__tests__/session.test.ts +117 -36
  89. package/src/core/codemirror/__tests__/setup.test.ts +28 -28
  90. package/src/core/codemirror/language/__tests__/sql.test.ts +22 -20
  91. package/src/core/codemirror/language/extension.ts +8 -8
  92. package/src/core/codemirror/language/languages/markdown.ts +8 -6
  93. package/src/core/codemirror/language/languages/python.ts +13 -7
  94. package/src/core/codemirror/language/languages/sql/sql.ts +9 -7
  95. package/src/core/codemirror/language/types.ts +7 -7
  96. package/src/core/codemirror/rtc/extension.ts +24 -12
  97. package/src/core/codemirror/rtc/loro/awareness.ts +34 -19
  98. package/src/core/codemirror/rtc/loro/sync.ts +1 -0
  99. package/src/core/codemirror/utils.ts +1 -0
  100. package/src/core/host/__tests__/static.test.ts +167 -0
  101. package/src/core/host/backend.ts +10 -0
  102. package/src/core/host/static.ts +70 -0
  103. package/src/core/islands/components/__tests__/IslandControls.test.tsx +7 -5
  104. package/src/core/static/__tests__/files.test.ts +38 -10
  105. package/src/plugins/__tests__/plugin-object-schemas.test.ts +104 -0
  106. package/src/plugins/impl/DataEditorPlugin.tsx +1 -1
  107. package/src/plugins/impl/DataTablePlugin.tsx +15 -18
  108. package/src/plugins/impl/data-frames/DataFramePlugin.tsx +1 -1
  109. package/src/plugins/impl/plotly/PlotlyPlugin.tsx +2 -5
  110. package/src/plugins/impl/plotly/selection.ts +25 -19
  111. package/src/plugins/impl/vega/VegaPlugin.tsx +2 -3
  112. package/dist/assets/feedback-button-DQdMkSvR.js +0 -1
@@ -381,24 +381,31 @@ export class StatefulOutputMessage implements OutputMessage {
381
381
  public static create(message: StringOutputMessage): StatefulOutputMessage {
382
382
  const ansiReducer = new AnsiReducer();
383
383
  ansiReducer.append(message.data);
384
- return new StatefulOutputMessage(
385
- message.mimetype,
386
- message.channel,
387
- message.timestamp,
384
+ return new StatefulOutputMessage({
385
+ mimetype: message.mimetype,
386
+ channel: message.channel,
387
+ timestamp: message.timestamp,
388
388
  ansiReducer,
389
- message.code,
390
- message.id,
391
- );
389
+ code: message.code,
390
+ id: message.id,
391
+ });
392
392
  }
393
393
 
394
- private constructor(
395
- mimetype: OutputMessage["mimetype"],
396
- channel: OutputMessage["channel"],
397
- timestamp: OutputMessage["timestamp"],
398
- ansiReducer: AnsiReducer,
399
- code: OutputMessage["code"],
400
- id: StringOutputMessage["id"],
401
- ) {
394
+ private constructor({
395
+ mimetype,
396
+ channel,
397
+ timestamp,
398
+ ansiReducer,
399
+ code,
400
+ id,
401
+ }: {
402
+ mimetype: OutputMessage["mimetype"];
403
+ channel: OutputMessage["channel"];
404
+ timestamp: OutputMessage["timestamp"];
405
+ ansiReducer: AnsiReducer;
406
+ code: OutputMessage["code"];
407
+ id: StringOutputMessage["id"];
408
+ }) {
402
409
  this.mimetype = mimetype;
403
410
  this.channel = channel;
404
411
  this.timestamp = timestamp;
@@ -410,14 +417,14 @@ export class StatefulOutputMessage implements OutputMessage {
410
417
 
411
418
  public appendData(chunk: string): StatefulOutputMessage {
412
419
  this.ansiReducer.append(chunk);
413
- return new StatefulOutputMessage(
414
- this.mimetype,
415
- this.channel,
416
- this.timestamp,
417
- this.ansiReducer,
418
- this.code,
419
- this.id,
420
- );
420
+ return new StatefulOutputMessage({
421
+ mimetype: this.mimetype,
422
+ channel: this.channel,
423
+ timestamp: this.timestamp,
424
+ ansiReducer: this.ansiReducer,
425
+ code: this.code,
426
+ id: this.id,
427
+ });
421
428
  }
422
429
 
423
430
  public toJSON(): StringOutputMessage {
@@ -190,12 +190,18 @@ export const GridLayoutRenderer: React.FC<Props> = ({
190
190
  cells: [...cellLayouts, dropped],
191
191
  });
192
192
  }}
193
- onDragStart={(_layout, _oldItem, _newItem, _placeholder, event) => {
194
- dragProps.onDragStart(event);
195
- }}
196
- onDrag={(_layout, _oldItem, _newItem, _placeholder, event) => {
197
- dragProps.onDragMove(event);
198
- }}
193
+ onDragStart={
194
+ // oxlint-disable-next-line marimo/prefer-object-params -- React Grid Layout supplies the event as the fifth argument.
195
+ (_layout, _oldItem, _newItem, _placeholder, event) => {
196
+ dragProps.onDragStart(event);
197
+ }
198
+ }
199
+ onDrag={
200
+ // oxlint-disable-next-line marimo/prefer-object-params -- React Grid Layout supplies the event as the fifth argument.
201
+ (_layout, _oldItem, _newItem, _placeholder, event) => {
202
+ dragProps.onDragMove(event);
203
+ }
204
+ }
199
205
  onDragStop={() => {
200
206
  dragProps.onDragStop();
201
207
  }}
@@ -20,9 +20,11 @@ export type StatusValue = "success" | "error" | "warning";
20
20
  * @example
21
21
  * throw new ToolExecutionError(
22
22
  * "Failed to fetch data",
23
- * "FETCH_ERROR",
24
- * true,
25
- * "Check your network connection"
23
+ * {
24
+ * code: "FETCH_ERROR",
25
+ * isRetryable: true,
26
+ * suggestedFix: "Check your network connection",
27
+ * }
26
28
  * );
27
29
  */
28
30
  export class ToolExecutionError extends Error {
@@ -33,10 +35,17 @@ export class ToolExecutionError extends Error {
33
35
 
34
36
  public constructor(
35
37
  message: string,
36
- code = "TOOL_ERROR",
37
- isRetryable = false,
38
- suggestedFix?: string,
39
- meta?: Record<string, unknown>,
38
+ {
39
+ code = "TOOL_ERROR",
40
+ isRetryable = false,
41
+ suggestedFix,
42
+ meta,
43
+ }: {
44
+ code?: string;
45
+ isRetryable?: boolean;
46
+ suggestedFix?: string;
47
+ meta?: Record<string, unknown>;
48
+ } = {},
40
49
  ) {
41
50
  super(message);
42
51
  this.name = "ToolExecutionError";
@@ -94,19 +94,17 @@ export class EditNotebookTool implements AiTool<
94
94
  const cellId = position.cellId as CellId | undefined;
95
95
 
96
96
  if (!cellId) {
97
- throw new ToolExecutionError(
98
- "Cell ID is required for update_cell",
99
- "CELL_ID_REQUIRED_FOR_UPDATE_CELL",
100
- true,
101
- "Provide a cell ID to update",
102
- );
97
+ throw new ToolExecutionError("Cell ID is required for update_cell", {
98
+ code: "CELL_ID_REQUIRED_FOR_UPDATE_CELL",
99
+ isRetryable: true,
100
+ suggestedFix: "Provide a cell ID to update",
101
+ });
103
102
  } else if (!code) {
104
- throw new ToolExecutionError(
105
- "Code is required for update_cell",
106
- "CODE_REQUIRED_FOR_UPDATE_CELL",
107
- true,
108
- "Provide the new code to update the cell",
109
- );
103
+ throw new ToolExecutionError("Code is required for update_cell", {
104
+ code: "CODE_REQUIRED_FOR_UPDATE_CELL",
105
+ isRetryable: true,
106
+ suggestedFix: "Provide the new code to update the cell",
107
+ });
110
108
  }
111
109
 
112
110
  const notebook = store.get(notebookAtom);
@@ -157,18 +155,22 @@ export class EditNotebookTool implements AiTool<
157
155
  if (!cellId) {
158
156
  throw new ToolExecutionError(
159
157
  "Cell ID is required for add_cell with relative position",
160
- "TOOL_ERROR",
161
- true,
162
- "Provide a cell ID to add the cell before",
158
+ {
159
+ code: "TOOL_ERROR",
160
+ isRetryable: true,
161
+ suggestedFix: "Provide a cell ID to add the cell before",
162
+ },
163
163
  );
164
164
  }
165
165
 
166
166
  if (position.before === undefined) {
167
167
  throw new ToolExecutionError(
168
168
  "Before is required for add_cell with relative position",
169
- "TOOL_ERROR",
170
- true,
171
- `Provide a boolean value for before, true to add before cell ${cellId}, false to add after the cell`,
169
+ {
170
+ code: "TOOL_ERROR",
171
+ isRetryable: true,
172
+ suggestedFix: `Provide a boolean value for before, true to add before cell ${cellId}, false to add after the cell`,
173
+ },
172
174
  );
173
175
  }
174
176
 
@@ -181,9 +183,12 @@ export class EditNotebookTool implements AiTool<
181
183
  if (!position.columnIndex) {
182
184
  throw new ToolExecutionError(
183
185
  "Column index is required for add_cell with column_end position",
184
- "TOOL_ERROR",
185
- true,
186
- "Provide a column index to add the cell at the end of",
186
+ {
187
+ code: "TOOL_ERROR",
188
+ isRetryable: true,
189
+ suggestedFix:
190
+ "Provide a column index to add the cell at the end of",
191
+ },
187
192
  );
188
193
  }
189
194
 
@@ -218,12 +223,11 @@ export class EditNotebookTool implements AiTool<
218
223
  const cellId = position.cellId as CellId | undefined;
219
224
 
220
225
  if (!cellId) {
221
- throw new ToolExecutionError(
222
- "Cell ID is required for delete_cell",
223
- "CELL_ID_REQUIRED_FOR_DELETE_CELL",
224
- true,
225
- "Provide a cell ID to delete",
226
- );
226
+ throw new ToolExecutionError("Cell ID is required for delete_cell", {
227
+ code: "CELL_ID_REQUIRED_FOR_DELETE_CELL",
228
+ isRetryable: true,
229
+ suggestedFix: "Provide a cell ID to delete",
230
+ });
227
231
  }
228
232
 
229
233
  const notebook = store.get(notebookAtom);
@@ -255,12 +259,11 @@ export class EditNotebookTool implements AiTool<
255
259
  private validateCellIdExists(cellId: CellId, notebook: NotebookState) {
256
260
  const cellIds = notebook.cellIds;
257
261
  if (!cellIds.getColumns().some((column) => column.idSet.has(cellId))) {
258
- throw new ToolExecutionError(
259
- "Cell not found",
260
- "CELL_NOT_FOUND",
261
- false,
262
- "Check which cells exist in the notebook",
263
- );
262
+ throw new ToolExecutionError("Cell not found", {
263
+ code: "CELL_NOT_FOUND",
264
+ isRetryable: false,
265
+ suggestedFix: "Check which cells exist in the notebook",
266
+ });
264
267
  }
265
268
  }
266
269
 
@@ -272,12 +275,12 @@ export class EditNotebookTool implements AiTool<
272
275
  const columns = cellIds.getColumns();
273
276
 
274
277
  if (columnIndex < 0 || columnIndex >= columns.length) {
275
- throw new ToolExecutionError(
276
- "Column index is out of range",
277
- "COLUMN_INDEX_OUT_OF_RANGE",
278
- true,
279
- "Choose a column index between 0 and the number of columns in the notebook (0-based)",
280
- );
278
+ throw new ToolExecutionError("Column index is out of range", {
279
+ code: "COLUMN_INDEX_OUT_OF_RANGE",
280
+ isRetryable: true,
281
+ suggestedFix:
282
+ "Choose a column index between 0 and the number of columns in the notebook (0-based)",
283
+ });
281
284
  }
282
285
  return columns[columnIndex].id;
283
286
  }
@@ -289,12 +292,11 @@ export class EditNotebookTool implements AiTool<
289
292
  const cellHandles = notebook.cellHandles;
290
293
  const cellHandle = cellHandles[cellId].current;
291
294
  if (!cellHandle?.editorView) {
292
- throw new ToolExecutionError(
293
- "Cell editor not found",
294
- "CELL_EDITOR_NOT_FOUND",
295
- false,
296
- "Internal error, ask the user to report this error",
297
- );
295
+ throw new ToolExecutionError("Cell editor not found", {
296
+ code: "CELL_EDITOR_NOT_FOUND",
297
+ isRetryable: false,
298
+ suggestedFix: "Internal error, ask the user to report this error",
299
+ });
298
300
  }
299
301
  return cellHandle.editorView;
300
302
  }
@@ -73,9 +73,11 @@ export class FrontendToolRegistry {
73
73
  const strError = z.prettifyError(inputResponse.error);
74
74
  throw new ToolExecutionError(
75
75
  `Tool ${toolName} returned invalid input: ${strError}`,
76
- "INVALID_ARGUMENTS",
77
- true,
78
- "Please check the arguments and try again.",
76
+ {
77
+ code: "INVALID_ARGUMENTS",
78
+ isRetryable: true,
79
+ suggestedFix: "Please check the arguments and try again.",
80
+ },
79
81
  );
80
82
  }
81
83
  const args = inputResponse.data;
@@ -110,12 +112,15 @@ export class FrontendToolRegistry {
110
112
  // Handle unknown/generic errors
111
113
  const genericError = new ToolExecutionError(
112
114
  error instanceof Error ? error.message : String(error),
113
- "TOOL_ERROR",
114
- false,
115
- "Check the error message and try again with valid arguments.",
116
115
  {
117
- args: rawArgs,
118
- errorType: error?.constructor?.name ?? typeof error,
116
+ code: "TOOL_ERROR",
117
+ isRetryable: false,
118
+ suggestedFix:
119
+ "Check the error message and try again with valid arguments.",
120
+ meta: {
121
+ args: rawArgs,
122
+ errorType: error?.constructor?.name ?? typeof error,
123
+ },
119
124
  },
120
125
  );
121
126
  return {
@@ -50,13 +50,12 @@ export class TestFrontendTool implements AiTool<Input, Output> {
50
50
  public async handler({ name }: Input): Promise<Output> {
51
51
  // Example: Validate input and throw ToolExecutionError on invalid data
52
52
  if (!name.trim()) {
53
- throw new ToolExecutionError(
54
- "Name cannot be empty",
55
- "INVALID_INPUT",
56
- false,
57
- "Please provide a non-empty name",
58
- { field: "name", received: name },
59
- );
53
+ throw new ToolExecutionError("Name cannot be empty", {
54
+ code: "INVALID_INPUT",
55
+ isRetryable: false,
56
+ suggestedFix: "Please provide a non-empty name",
57
+ meta: { field: "name", received: name },
58
+ });
60
59
  }
61
60
 
62
61
  return {
@@ -46,10 +46,17 @@ describe("notebookStateFromSession", () => {
46
46
 
47
47
  const createNotebookCell = (
48
48
  id: string,
49
- code: string | null = null,
50
- name: string | null = null,
51
- config: NotebookCell["config"] | null = null,
52
- code_hash: string | null = null,
49
+ {
50
+ code = null,
51
+ name = null,
52
+ config = null,
53
+ code_hash = null,
54
+ }: {
55
+ code?: string | null;
56
+ name?: string | null;
57
+ config?: NotebookCell["config"] | null;
58
+ code_hash?: string | null;
59
+ } = {},
53
60
  ): NotebookCell => ({
54
61
  id,
55
62
  code,
@@ -87,7 +94,7 @@ describe("notebookStateFromSession", () => {
87
94
 
88
95
  it("logs error when session and notebook have different cells", () => {
89
96
  const session = createSession([createSessionCell("cell-1")]);
90
- const notebook = createNotebook([createNotebookCell("cell-2")]);
97
+ const notebook = createNotebook([createNotebookCell("cell-2", {})]);
91
98
 
92
99
  const result = notebookStateFromSession(session, notebook);
93
100
 
@@ -328,7 +335,10 @@ describe("notebookStateFromSession", () => {
328
335
  describe("notebook only scenarios", () => {
329
336
  it("creates state from notebook with single cell", () => {
330
337
  const notebook = createNotebook([
331
- createNotebookCell("cell-1", "print('hello')", "my_cell"),
338
+ createNotebookCell("cell-1", {
339
+ code: "print('hello')",
340
+ name: "my_cell",
341
+ }),
332
342
  ]);
333
343
  const result = notebookStateFromSession(null, notebook);
334
344
 
@@ -356,11 +366,15 @@ describe("notebookStateFromSession", () => {
356
366
 
357
367
  it("creates state from notebook with custom config", () => {
358
368
  const notebook = createNotebook([
359
- createNotebookCell("cell-1", "code", "name", {
360
- hide_code: true,
361
- disabled: true,
362
- column: 1,
363
- expand_output: true,
369
+ createNotebookCell("cell-1", {
370
+ code: "code",
371
+ name: "name",
372
+ config: {
373
+ hide_code: true,
374
+ disabled: true,
375
+ column: 1,
376
+ expand_output: true,
377
+ },
364
378
  }),
365
379
  ]);
366
380
  const result = notebookStateFromSession(null, notebook);
@@ -464,7 +478,10 @@ describe("notebookStateFromSession", () => {
464
478
  ),
465
479
  ]);
466
480
  const notebook = createNotebook([
467
- createNotebookCell("cell-1", "print('hello')", "my_cell"),
481
+ createNotebookCell("cell-1", {
482
+ code: "print('hello')",
483
+ name: "my_cell",
484
+ }),
468
485
  ]);
469
486
  const result = notebookStateFromSession(session, notebook);
470
487
 
@@ -495,8 +512,8 @@ describe("notebookStateFromSession", () => {
495
512
  createSessionCell("cell-2"),
496
513
  ]);
497
514
  const notebook = createNotebook([
498
- createNotebookCell("cell-2"),
499
- createNotebookCell("cell-1"),
515
+ createNotebookCell("cell-2", {}),
516
+ createNotebookCell("cell-1", {}),
500
517
  ]);
501
518
 
502
519
  const result = notebookStateFromSession(session, notebook);
@@ -514,8 +531,8 @@ describe("notebookStateFromSession", () => {
514
531
  createSessionCell("cell-2"),
515
532
  ]);
516
533
  const notebook = createNotebook([
517
- createNotebookCell("cell-1"),
518
- createNotebookCell("cell-2"),
534
+ createNotebookCell("cell-1", {}),
535
+ createNotebookCell("cell-2", {}),
519
536
  ]);
520
537
 
521
538
  const result = notebookStateFromSession(session, notebook);
@@ -669,12 +686,42 @@ describe("notebookStateFromSession", () => {
669
686
  };
670
687
  // Create notebook cells with code values 'a' through 'f'
671
688
  const notebookCells = [
672
- createNotebookCell("cell-a", "a", null, null, hashes.a),
673
- createNotebookCell("cell-b", "b", null, null, hashes.b),
674
- createNotebookCell("cell-c", "c", null, null, hashes.c),
675
- createNotebookCell("cell-d", "d", null, null, hashes.d),
676
- createNotebookCell("cell-e", "e", null, null, hashes.e),
677
- createNotebookCell("cell-f", "f", null, null, hashes.f),
689
+ createNotebookCell("cell-a", {
690
+ code: "a",
691
+ name: null,
692
+ config: null,
693
+ code_hash: hashes.a,
694
+ }),
695
+ createNotebookCell("cell-b", {
696
+ code: "b",
697
+ name: null,
698
+ config: null,
699
+ code_hash: hashes.b,
700
+ }),
701
+ createNotebookCell("cell-c", {
702
+ code: "c",
703
+ name: null,
704
+ config: null,
705
+ code_hash: hashes.c,
706
+ }),
707
+ createNotebookCell("cell-d", {
708
+ code: "d",
709
+ name: null,
710
+ config: null,
711
+ code_hash: hashes.d,
712
+ }),
713
+ createNotebookCell("cell-e", {
714
+ code: "e",
715
+ name: null,
716
+ config: null,
717
+ code_hash: hashes.e,
718
+ }),
719
+ createNotebookCell("cell-f", {
720
+ code: "f",
721
+ name: null,
722
+ config: null,
723
+ code_hash: hashes.f,
724
+ }),
678
725
  ];
679
726
  // Create session cells with matching code_hashes
680
727
  const sessionCells = [
@@ -787,11 +834,36 @@ describe("notebookStateFromSession", () => {
787
834
 
788
835
  // Notebook has cells with code 'a', 'c', 'z', 'e', 'g'
789
836
  const notebookCells = [
790
- createNotebookCell("cell-a", "a", null, null, hashes.a),
791
- createNotebookCell("cell-c", "c", null, null, hashes.c),
792
- createNotebookCell("cell-z", "z", null, null, hashes.z),
793
- createNotebookCell("cell-e", "e", null, null, hashes.e),
794
- createNotebookCell("cell-g", "g", null, null, hashes.g),
837
+ createNotebookCell("cell-a", {
838
+ code: "a",
839
+ name: null,
840
+ config: null,
841
+ code_hash: hashes.a,
842
+ }),
843
+ createNotebookCell("cell-c", {
844
+ code: "c",
845
+ name: null,
846
+ config: null,
847
+ code_hash: hashes.c,
848
+ }),
849
+ createNotebookCell("cell-z", {
850
+ code: "z",
851
+ name: null,
852
+ config: null,
853
+ code_hash: hashes.z,
854
+ }),
855
+ createNotebookCell("cell-e", {
856
+ code: "e",
857
+ name: null,
858
+ config: null,
859
+ code_hash: hashes.e,
860
+ }),
861
+ createNotebookCell("cell-g", {
862
+ code: "g",
863
+ name: null,
864
+ config: null,
865
+ code_hash: hashes.g,
866
+ }),
795
867
  ];
796
868
 
797
869
  const session = createSession(sessionCells);
@@ -908,15 +980,24 @@ describe("notebookStateFromSession", () => {
908
980
 
909
981
  // Notebook has cells: cell-1 (1 / 0, no hash), cell-2 (mo.md("Hello"), hash=moMd), cell-3 (slider, hash=slider)
910
982
  const notebookCells = [
911
- createNotebookCell("cell-1", "1 / 0", null, null, null), // no hash
912
- createNotebookCell("cell-2", 'mo.md("Hello")', null, null, hashes.moMd),
913
- createNotebookCell(
914
- "cell-3",
915
- "x = mo.ui.slider(0, 10)",
916
- null,
917
- null,
918
- hashes.slider,
919
- ),
983
+ createNotebookCell("cell-1", {
984
+ code: "1 / 0",
985
+ name: null,
986
+ config: null,
987
+ code_hash: null,
988
+ }), // no hash
989
+ createNotebookCell("cell-2", {
990
+ code: 'mo.md("Hello")',
991
+ name: null,
992
+ config: null,
993
+ code_hash: hashes.moMd,
994
+ }),
995
+ createNotebookCell("cell-3", {
996
+ code: "x = mo.ui.slider(0, 10)",
997
+ name: null,
998
+ config: null,
999
+ code_hash: hashes.slider,
1000
+ }),
920
1001
  ];
921
1002
 
922
1003
  const session = createSession(sessionCells);
@@ -198,22 +198,22 @@ test("go to definition falls through to lower-priority LSP keymap", () => {
198
198
  test("placeholder adds another extension", () => {
199
199
  const opts = getOpts();
200
200
  const withAI = new PythonLanguageAdapter()
201
- .getExtension(
202
- opts.cellId,
203
- opts.completionConfig,
204
- opts.hotkeys,
205
- "marimo-import",
206
- opts.lspConfig,
207
- )
201
+ .getExtension({
202
+ cellId: opts.cellId,
203
+ completionConfig: opts.completionConfig,
204
+ hotkeys: opts.hotkeys,
205
+ placeholderType: "marimo-import",
206
+ lspConfig: opts.lspConfig,
207
+ })
208
208
  .flat();
209
209
  const withoutAI = new PythonLanguageAdapter()
210
- .getExtension(
211
- opts.cellId,
212
- opts.completionConfig,
213
- opts.hotkeys,
214
- "none",
215
- opts.lspConfig,
216
- )
210
+ .getExtension({
211
+ cellId: opts.cellId,
212
+ completionConfig: opts.completionConfig,
213
+ hotkeys: opts.hotkeys,
214
+ placeholderType: "none",
215
+ lspConfig: opts.lspConfig,
216
+ })
217
217
  .flat();
218
218
  expect(withAI.length - 1).toBe(withoutAI.length);
219
219
  });
@@ -221,22 +221,22 @@ test("placeholder adds another extension", () => {
221
221
  test("ai adds more extensions", () => {
222
222
  const opts = getOpts();
223
223
  const withAI = new PythonLanguageAdapter()
224
- .getExtension(
225
- opts.cellId,
226
- opts.completionConfig,
227
- opts.hotkeys,
228
- "ai",
229
- opts.lspConfig,
230
- )
224
+ .getExtension({
225
+ cellId: opts.cellId,
226
+ completionConfig: opts.completionConfig,
227
+ hotkeys: opts.hotkeys,
228
+ placeholderType: "ai",
229
+ lspConfig: opts.lspConfig,
230
+ })
231
231
  .flat();
232
232
  const withoutAI = new PythonLanguageAdapter()
233
- .getExtension(
234
- opts.cellId,
235
- opts.completionConfig,
236
- opts.hotkeys,
237
- "none",
238
- opts.lspConfig,
239
- )
233
+ .getExtension({
234
+ cellId: opts.cellId,
235
+ completionConfig: opts.completionConfig,
236
+ hotkeys: opts.hotkeys,
237
+ placeholderType: "none",
238
+ lspConfig: opts.lspConfig,
239
+ })
240
240
  .flat();
241
241
  expect(withAI.length - 2).toBe(withoutAI.length);
242
242
  });