@marimo-team/frontend 0.15.1-dev33 → 0.15.1-dev35
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/{ConnectedDataExplorerComponent-B0S6KZz0.js → ConnectedDataExplorerComponent-BYxPTiA6.js} +1 -1
- package/dist/assets/{ImageComparisonComponent-C-VZ4Tnc.js → ImageComparisonComponent-DBpvpxlw.js} +1 -1
- package/dist/assets/{VegaLite-BnVARnZA.js → VegaLite-DzkGo9LJ.js} +1 -1
- package/dist/assets/{_baseEach-CnkgAoU6.js → _baseEach-CnK_W3-W.js} +1 -1
- package/dist/assets/_baseMap-CIc0IDdl.js +1 -0
- package/dist/assets/{_baseUniq-CwJ2iszo.js → _baseUniq-DsEUejTO.js} +1 -1
- package/dist/assets/{_createAggregator-DzNuEiXE.js → _createAggregator-xSD3e6yX.js} +1 -1
- package/dist/assets/{any-language-editor-CkEw-cSX.js → any-language-editor-CSLfx3Fo.js} +1 -1
- package/dist/assets/{architectureDiagram-KFL7JDKH-D5bxGLSO.js → architectureDiagram-KFL7JDKH-DDJcEe4E.js} +1 -1
- package/dist/assets/{blockDiagram-ZYB65J3Q-lBSpJVzg.js → blockDiagram-ZYB65J3Q-DrajNxU6.js} +1 -1
- package/dist/assets/{c4Diagram-AAMF2YG6-Cp2ZcvGq.js → c4Diagram-AAMF2YG6-DkbBAlkB.js} +1 -1
- package/dist/assets/channel-D2aPrBH4.js +1 -0
- package/dist/assets/{chunk-ANTBXLJU-BI9zlp2d.js → chunk-ANTBXLJU-CyFpCIAD.js} +1 -1
- package/dist/assets/{chunk-FHKO5MBM-DmqxuwHW.js → chunk-FHKO5MBM-DaRG9EJ9.js} +1 -1
- package/dist/assets/{chunk-GLLZNHP4-DDRTaZzv.js → chunk-GLLZNHP4-C852Uilf.js} +1 -1
- package/dist/assets/{chunk-JBRWN2VN-CT2Hh2iP.js → chunk-JBRWN2VN-DF6c2w7p.js} +1 -1
- package/dist/assets/{chunk-LXBSTHXV-DAMSTx1Q.js → chunk-LXBSTHXV-DJc1jClD.js} +1 -1
- package/dist/assets/{chunk-NRVI72HA-BZuYvBej.js → chunk-NRVI72HA-BYzJjL14.js} +1 -1
- package/dist/assets/{chunk-OMD6QJNC-BU_2rBlE.js → chunk-OMD6QJNC-DpzW6M54.js} +1 -1
- package/dist/assets/{chunk-WVR4S24B-CovEV1lg.js → chunk-WVR4S24B-Ds_Fnulu.js} +1 -1
- package/dist/assets/{circle-play-D59wTwHu.js → circle-play-ILK7D0lo.js} +1 -1
- package/dist/assets/classDiagram-3BZAVTQC-DAUNRz1h.js +1 -0
- package/dist/assets/classDiagram-v2-QTMF73CY-DAUNRz1h.js +1 -0
- package/dist/assets/clone-CYXehyk_.js +1 -0
- package/dist/assets/{compile-BKBdwA1q.js → compile-Q6b1NW0Y.js} +1 -1
- package/dist/assets/{dagre-2BBEFEWP-BmXAp5fB.js → dagre-2BBEFEWP-DUplj_Iy.js} +1 -1
- package/dist/assets/{data-grid-overlay-editor-BycmLqkg.js → data-grid-overlay-editor-BHVNUwJL.js} +1 -1
- package/dist/assets/{diagram-4IRLE6MV-CI8uZuDu.js → diagram-4IRLE6MV-CqSPK4-w.js} +1 -1
- package/dist/assets/{diagram-GUPCWM2R-DM01dWOn.js → diagram-GUPCWM2R-Yz9pe62o.js} +1 -1
- package/dist/assets/{diagram-RP2FKANI-3A7xcD_S.js → diagram-RP2FKANI-DAvv4Av_.js} +1 -1
- package/dist/assets/{edit-page-r0MON4eX.js → edit-page-hlKtRc6p.js} +4 -4
- package/dist/assets/{erDiagram-HZWUO2LU-DVhn3kEV.js → erDiagram-HZWUO2LU-BIlDOHrw.js} +1 -1
- package/dist/assets/{flowDiagram-THRYKUMA-ByiKsMTR.js → flowDiagram-THRYKUMA-w6HYIjcR.js} +1 -1
- package/dist/assets/{ganttDiagram-WV7ZQ7D5-C3yWfK7N.js → ganttDiagram-WV7ZQ7D5-CS1t__7-.js} +1 -1
- package/dist/assets/{gitGraphDiagram-OJR772UL-DT2oVbFG.js → gitGraphDiagram-OJR772UL-DCcukZnI.js} +1 -1
- package/dist/assets/{glide-data-editor-B-hKUbt8.js → glide-data-editor-BoQ4MEIu.js} +4 -4
- package/dist/assets/{graph-DKF8gkY7.js → graph-DzywueYf.js} +1 -1
- package/dist/assets/{home-page-DG5IpRSH.js → home-page-CTLf7o0o.js} +1 -1
- package/dist/assets/{index-COS_Xbgw.js → index-B8egTd_Y.js} +1 -1
- package/dist/assets/{index-CxQa_cAw.js → index-BNpIaqHq.js} +1 -1
- package/dist/assets/{index-B4KTvqjC.js → index-BNuSEPHf.js} +1 -1
- package/dist/assets/{index-Cxy_1y9a.js → index-BOaSI40H.js} +1 -1
- package/dist/assets/{index-B_03AI_O.js → index-BVdia1-T.js} +1 -1
- package/dist/assets/{index-BDye4bMD.js → index-BbrvgVGd.js} +1 -1
- package/dist/assets/{index-kCp9Vp_G.js → index-BobSdMcV.js} +1 -1
- package/dist/assets/{index-BSq77Vg9.js → index-BsZupkBE.js} +1 -1
- package/dist/assets/{index-BciA4s2J.js → index-CTTXrsVd.js} +1 -1
- package/dist/assets/{index-CDzLk5Q3.js → index-C_ZOWmXX.js} +1 -1
- package/dist/assets/{index-tI3mZqES.js → index-CjvmeMRd.js} +1 -1
- package/dist/assets/{index-C89mOURj.js → index-DMgZFfTJ.js} +1 -1
- package/dist/assets/{index-DTE_Lol9.js → index-DMvScaq6.js} +133 -133
- package/dist/assets/{index-BJMIm3h5.js → index-DNjb9MyH.js} +1 -1
- package/dist/assets/{index-BQCqmfXS.js → index-DUumP-lt.js} +1 -1
- package/dist/assets/{index-RfoHYoLS.js → index-Dl6_NSX4.js} +1 -1
- package/dist/assets/{index-BKnuS3t4.js → index-DsMyERcC.js} +1 -1
- package/dist/assets/{index-BAre-3Jh.js → index-EaCZDGUn.js} +1 -1
- package/dist/assets/{index-CKZtF7JM.js → index-gZP0fYKG.js} +1 -1
- package/dist/assets/{index-CDxt4mvu.js → index-txir7kB2.js} +1 -1
- package/dist/assets/{infoDiagram-6WOFNB3A-CVxc3Oq6.js → infoDiagram-6WOFNB3A-B1zwcYam.js} +1 -1
- package/dist/assets/{journeyDiagram-FFXJYRFH-yx-qCooh.js → journeyDiagram-FFXJYRFH-IwybgEnB.js} +1 -1
- package/dist/assets/{kanban-definition-KOZQBZVT-DpJgEsNc.js → kanban-definition-KOZQBZVT-BnLxznwF.js} +1 -1
- package/dist/assets/{layout-HC2KG283.js → layout-lIKJEEeS.js} +1 -1
- package/dist/assets/{linear-DwZzRezN.js → linear-DzfVWjvh.js} +1 -1
- package/dist/assets/{links-_NwdJ11g.js → links-yIZ6advT.js} +1 -1
- package/dist/assets/{mermaid-BsNRTdZg.js → mermaid-CEpdDmik.js} +4 -4
- package/dist/assets/{min-DdOdESXu.js → min-CH9RTxJs.js} +1 -1
- package/dist/assets/{mindmap-definition-LNHGMQRG-Ds3h-hI5.js → mindmap-definition-LNHGMQRG-BGOBqdZQ.js} +1 -1
- package/dist/assets/{number-overlay-editor-CYrbVyKN.js → number-overlay-editor-Bp8EEFG4.js} +1 -1
- package/dist/assets/{pieDiagram-DBDJKBY4-Ce-oEPaV.js → pieDiagram-DBDJKBY4-BH18DMec.js} +1 -1
- package/dist/assets/{quadrantDiagram-YPSRARAO-Urm8U0LY.js → quadrantDiagram-YPSRARAO-DyEaA3Tj.js} +1 -1
- package/dist/assets/{react-plotly-DGqhBdP1.js → react-plotly-BWJyJ31U.js} +1 -1
- package/dist/assets/{requirementDiagram-EGVEC5DT-CCTq9hQZ.js → requirementDiagram-EGVEC5DT-BIDYwWds.js} +1 -1
- package/dist/assets/{run-page-CsCj50OD.js → run-page-CFGHZjjp.js} +1 -1
- package/dist/assets/{sankeyDiagram-HRAUVNP4-C2I9sfem.js → sankeyDiagram-HRAUVNP4-CI7WE82z.js} +1 -1
- package/dist/assets/{sequenceDiagram-WFGC7UMF-CLQmyPy2.js → sequenceDiagram-WFGC7UMF-CAt5_R3a.js} +1 -1
- package/dist/assets/{slides-component-DJCkXPus.js → slides-component-BE3m7wod.js} +1 -1
- package/dist/assets/{sortBy-Duwc1vyP.js → sortBy-D8wYLA9x.js} +1 -1
- package/dist/assets/{stateDiagram-UUKSUZ4H-VvU373AQ.js → stateDiagram-UUKSUZ4H-B9ghWYn7.js} +1 -1
- package/dist/assets/stateDiagram-v2-EYPG3UTE-DtL7XYtB.js +1 -0
- package/dist/assets/{storage-1hHZMyeU.js → storage-BseyfFaj.js} +3 -3
- package/dist/assets/{terminal-DV-tPxSZ.js → terminal-R2SnqHO_.js} +1 -1
- package/dist/assets/{time-4bh0fJAY.js → time-CftJc27E.js} +1 -1
- package/dist/assets/{timeline-definition-3HZDQTIS-D5z1lzVG.js → timeline-definition-3HZDQTIS-B8ej5Uev.js} +1 -1
- package/dist/assets/{tracing-C32etwYw.js → tracing-OU6KdAjg.js} +2 -2
- package/dist/assets/{trash-W9nmeKd9.js → trash-BX0buH-6.js} +1 -1
- package/dist/assets/{treemap-75Q7IDZK-CHza0lWj.js → treemap-75Q7IDZK-C6t8vi8s.js} +1 -1
- package/dist/assets/{vega-component-BDWLTrqk.js → vega-component-a-Wve7v1.js} +1 -1
- package/dist/assets/{xychartDiagram-FDP5SA34-DVdoRkWV.js → xychartDiagram-FDP5SA34-DmTMju1m.js} +1 -1
- package/dist/index.html +1 -1
- package/package.json +1 -1
- package/src/__mocks__/notebook.ts +108 -0
- package/src/components/editor/ai/__tests__/completion-utils.test.ts +119 -139
- package/src/components/editor/ai/completion-utils.ts +7 -33
- package/src/core/ai/context/__tests__/registry.test.ts +154 -0
- package/src/core/ai/context/__tests__/utils.test.ts +174 -0
- package/src/core/ai/context/context.ts +3 -1
- package/src/core/ai/context/providers/__tests__/__snapshots__/error.test.ts.snap +3 -0
- package/src/core/ai/context/providers/__tests__/__snapshots__/tables.test.ts.snap +8 -12
- package/src/core/ai/context/providers/__tests__/__snapshots__/variable.test.ts.snap +4 -20
- package/src/core/ai/context/providers/__tests__/error.test.ts +328 -0
- package/src/core/ai/context/providers/common.ts +1 -0
- package/src/core/ai/context/providers/error.ts +165 -0
- package/src/core/ai/context/providers/tables.ts +14 -6
- package/src/core/ai/context/providers/variable.ts +11 -2
- package/src/core/ai/context/utils.ts +49 -0
- package/src/core/cells/cells.ts +1 -1
- package/src/core/dom/outline.ts +16 -2
- package/dist/assets/_baseMap-BQjPNy9z.js +0 -1
- package/dist/assets/channel-8Z-5YHHd.js +0 -1
- package/dist/assets/classDiagram-3BZAVTQC-BOvgzS6u.js +0 -1
- package/dist/assets/classDiagram-v2-QTMF73CY-BOvgzS6u.js +0 -1
- package/dist/assets/clone-DVVP9Odz.js +0 -1
- package/dist/assets/stateDiagram-v2-EYPG3UTE-D41Oi10c.js +0 -1
@@ -52,41 +52,40 @@ describe("getAICompletionBody", () => {
|
|
52
52
|
const input = "Use @data://dataset1 and @data://dataset2 for analysis";
|
53
53
|
const result = getAICompletionBody({ input });
|
54
54
|
|
55
|
-
expect(result).
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
],
|
74
|
-
variables: [],
|
75
|
-
},
|
76
|
-
});
|
55
|
+
expect(result).toMatchInlineSnapshot(`
|
56
|
+
{
|
57
|
+
"context": {
|
58
|
+
"plainText": "<data name="dataset1" source="unknown">
|
59
|
+
Columns:
|
60
|
+
- col1: number
|
61
|
+
- col2: string</data>
|
62
|
+
|
63
|
+
<data name="dataset2" source="unknown">
|
64
|
+
Columns:
|
65
|
+
- col3: boolean
|
66
|
+
- col4: date</data>",
|
67
|
+
"schema": [],
|
68
|
+
"variables": [],
|
69
|
+
},
|
70
|
+
"includeOtherCode": "// Some other code",
|
71
|
+
}
|
72
|
+
`);
|
77
73
|
});
|
78
74
|
|
79
75
|
it("should handle input with no mentioned datasets", () => {
|
80
76
|
const input = "Perform some analysis without mentioning @data://datasets";
|
81
77
|
const result = getAICompletionBody({ input });
|
82
78
|
|
83
|
-
expect(result).
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
79
|
+
expect(result).toMatchInlineSnapshot(`
|
80
|
+
{
|
81
|
+
"context": {
|
82
|
+
"plainText": "",
|
83
|
+
"schema": [],
|
84
|
+
"variables": [],
|
85
|
+
},
|
86
|
+
"includeOtherCode": "// Some other code",
|
87
|
+
}
|
88
|
+
`);
|
90
89
|
});
|
91
90
|
|
92
91
|
it("should handle input with non-existent datasets", () => {
|
@@ -106,21 +105,19 @@ describe("getAICompletionBody", () => {
|
|
106
105
|
"Use @data://existingDataset and @data://nonExistentDataset for analysis";
|
107
106
|
const result = getAICompletionBody({ input });
|
108
107
|
|
109
|
-
expect(result).
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
},
|
123
|
-
});
|
108
|
+
expect(result).toMatchInlineSnapshot(`
|
109
|
+
{
|
110
|
+
"context": {
|
111
|
+
"plainText": "<data name="existingDataset" source="unknown">
|
112
|
+
Columns:
|
113
|
+
- col1: number
|
114
|
+
- col2: string</data>",
|
115
|
+
"schema": [],
|
116
|
+
"variables": [],
|
117
|
+
},
|
118
|
+
"includeOtherCode": "// Some other code",
|
119
|
+
}
|
120
|
+
`);
|
124
121
|
});
|
125
122
|
|
126
123
|
it("should handle dataset names with dots", () => {
|
@@ -144,25 +141,23 @@ describe("getAICompletionBody", () => {
|
|
144
141
|
"Use @data://dataset.with.dots and @data://regular_dataset for analysis";
|
145
142
|
const result = getAICompletionBody({ input });
|
146
143
|
|
147
|
-
expect(result).
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
},
|
165
|
-
});
|
144
|
+
expect(result).toMatchInlineSnapshot(`
|
145
|
+
{
|
146
|
+
"context": {
|
147
|
+
"plainText": "<data name="dataset.with.dots" source="unknown">
|
148
|
+
Columns:
|
149
|
+
- col1: number
|
150
|
+
- col2: string</data>
|
151
|
+
|
152
|
+
<data name="regular_dataset" source="unknown">
|
153
|
+
Columns:
|
154
|
+
- col3: boolean</data>",
|
155
|
+
"schema": [],
|
156
|
+
"variables": [],
|
157
|
+
},
|
158
|
+
"includeOtherCode": "// Some other code",
|
159
|
+
}
|
160
|
+
`);
|
166
161
|
});
|
167
162
|
|
168
163
|
it("should handle connections", () => {
|
@@ -200,18 +195,18 @@ describe("getAICompletionBody", () => {
|
|
200
195
|
const input = "Use @data://table1 for analysis";
|
201
196
|
const result = getAICompletionBody({ input });
|
202
197
|
|
203
|
-
expect(result).
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
}
|
214
|
-
|
198
|
+
expect(result).toMatchInlineSnapshot(`
|
199
|
+
{
|
200
|
+
"context": {
|
201
|
+
"plainText": "<data name="table1" source="unknown">
|
202
|
+
Columns:
|
203
|
+
- col1: number</data>",
|
204
|
+
"schema": [],
|
205
|
+
"variables": [],
|
206
|
+
},
|
207
|
+
"includeOtherCode": "// Some other code",
|
208
|
+
}
|
209
|
+
`);
|
215
210
|
});
|
216
211
|
|
217
212
|
it("should return the correct completion body with mentioned variables", () => {
|
@@ -237,24 +232,18 @@ describe("getAICompletionBody", () => {
|
|
237
232
|
const input = "Use @variable://var1 and @variable://var2 for analysis";
|
238
233
|
const result = getAICompletionBody({ input });
|
239
234
|
|
240
|
-
expect(result).
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
valueType: "number",
|
253
|
-
previewValue: "42",
|
254
|
-
},
|
255
|
-
],
|
256
|
-
},
|
257
|
-
});
|
235
|
+
expect(result).toMatchInlineSnapshot(`
|
236
|
+
{
|
237
|
+
"context": {
|
238
|
+
"plainText": "<variable name="var1" dataType="string">"string value"</variable>
|
239
|
+
|
240
|
+
<variable name="var2" dataType="number">"42"</variable>",
|
241
|
+
"schema": [],
|
242
|
+
"variables": [],
|
243
|
+
},
|
244
|
+
"includeOtherCode": "// Some other code",
|
245
|
+
}
|
246
|
+
`);
|
258
247
|
});
|
259
248
|
|
260
249
|
it("should handle input with both datasets and variables", () => {
|
@@ -284,27 +273,21 @@ describe("getAICompletionBody", () => {
|
|
284
273
|
const input = "Use @data://dataset1 and @variable://var1 for analysis";
|
285
274
|
const result = getAICompletionBody({ input });
|
286
275
|
|
287
|
-
expect(result).
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
valueType: "string",
|
303
|
-
previewValue: "string value",
|
304
|
-
},
|
305
|
-
],
|
306
|
-
},
|
307
|
-
});
|
276
|
+
expect(result).toMatchInlineSnapshot(`
|
277
|
+
{
|
278
|
+
"context": {
|
279
|
+
"plainText": "<data name="dataset1" source="unknown">
|
280
|
+
Columns:
|
281
|
+
- col1: number
|
282
|
+
- col2: string</data>
|
283
|
+
|
284
|
+
<variable name="var1" dataType="string">"string value"</variable>",
|
285
|
+
"schema": [],
|
286
|
+
"variables": [],
|
287
|
+
},
|
288
|
+
"includeOtherCode": "// Some other code",
|
289
|
+
}
|
290
|
+
`);
|
308
291
|
});
|
309
292
|
|
310
293
|
it("should handle non-existent variables", () => {
|
@@ -324,19 +307,16 @@ describe("getAICompletionBody", () => {
|
|
324
307
|
"Use @variable://existingVar and @variable://nonExistentVar for analysis";
|
325
308
|
const result = getAICompletionBody({ input });
|
326
309
|
|
327
|
-
expect(result).
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
],
|
338
|
-
},
|
339
|
-
});
|
310
|
+
expect(result).toMatchInlineSnapshot(`
|
311
|
+
{
|
312
|
+
"context": {
|
313
|
+
"plainText": "<variable name="existingVar" dataType="string">"string value"</variable>",
|
314
|
+
"schema": [],
|
315
|
+
"variables": [],
|
316
|
+
},
|
317
|
+
"includeOtherCode": "// Some other code",
|
318
|
+
}
|
319
|
+
`);
|
340
320
|
});
|
341
321
|
|
342
322
|
it("should prioritize datasets over variables when there's a name conflict", () => {
|
@@ -363,17 +343,17 @@ describe("getAICompletionBody", () => {
|
|
363
343
|
const input = "Use @data://conflict for analysis";
|
364
344
|
const result = getAICompletionBody({ input });
|
365
345
|
|
366
|
-
expect(result).
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
}
|
377
|
-
|
346
|
+
expect(result).toMatchInlineSnapshot(`
|
347
|
+
{
|
348
|
+
"context": {
|
349
|
+
"plainText": "<data name="conflict" source="unknown">
|
350
|
+
Columns:
|
351
|
+
- col1: number</data>",
|
352
|
+
"schema": [],
|
353
|
+
"variables": [],
|
354
|
+
},
|
355
|
+
"includeOtherCode": "// Some other code",
|
356
|
+
}
|
357
|
+
`);
|
378
358
|
});
|
379
359
|
});
|
@@ -6,13 +6,9 @@ import type {
|
|
6
6
|
CompletionSource,
|
7
7
|
} from "@codemirror/autocomplete";
|
8
8
|
import { getAIContextRegistry } from "@/core/ai/context/context";
|
9
|
-
import type { TableContextItem } from "@/core/ai/context/providers/tables";
|
10
|
-
import type { VariableContextItem } from "@/core/ai/context/providers/variable";
|
11
9
|
import { getCodes } from "@/core/codemirror/copilot/getCodes";
|
12
|
-
import type { DataTable } from "@/core/kernel/messages";
|
13
10
|
import type { AiCompletionRequest } from "@/core/network/types";
|
14
11
|
import { store } from "@/core/state/jotai";
|
15
|
-
import type { Variable } from "@/core/variables/types";
|
16
12
|
import { Logger } from "@/utils/Logger";
|
17
13
|
|
18
14
|
/**
|
@@ -23,26 +19,15 @@ export function getAICompletionBody({
|
|
23
19
|
}: {
|
24
20
|
input: string;
|
25
21
|
}): Omit<AiCompletionRequest, "language" | "prompt" | "code"> {
|
26
|
-
const
|
27
|
-
Logger.debug("Included
|
28
|
-
Logger.debug("Included variables", variables);
|
22
|
+
const contextString = extractDatasetsAndVariables(input);
|
23
|
+
Logger.debug("Included context", contextString);
|
29
24
|
|
30
25
|
return {
|
31
26
|
includeOtherCode: getCodes(""),
|
32
27
|
context: {
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
name: column.name,
|
37
|
-
type: column.type,
|
38
|
-
sampleValues: column.sample_values,
|
39
|
-
})),
|
40
|
-
})),
|
41
|
-
variables: variables.map((variable) => ({
|
42
|
-
name: variable.name,
|
43
|
-
valueType: variable.dataType ?? "",
|
44
|
-
previewValue: variable.value,
|
45
|
-
})),
|
28
|
+
plainText: contextString,
|
29
|
+
schema: [],
|
30
|
+
variables: [],
|
46
31
|
},
|
47
32
|
};
|
48
33
|
}
|
@@ -52,21 +37,10 @@ export function getAICompletionBody({
|
|
52
37
|
* References are with @<name> in the input.
|
53
38
|
* Prioritizes datasets over variables if there's a name conflict.
|
54
39
|
*/
|
55
|
-
function extractDatasetsAndVariables(input: string): {
|
56
|
-
datasets: DataTable[];
|
57
|
-
variables: Variable[];
|
58
|
-
} {
|
40
|
+
function extractDatasetsAndVariables(input: string): string {
|
59
41
|
const registry = getAIContextRegistry(store);
|
60
42
|
const contextIds = registry.parseAllContextIds(input);
|
61
|
-
|
62
|
-
const datasets: DataTable[] = contextInfo
|
63
|
-
.filter((info): info is TableContextItem => info.type === "data")
|
64
|
-
.map((info) => info.data);
|
65
|
-
const variables: Variable[] = contextInfo
|
66
|
-
.filter((info): info is VariableContextItem => info.type === "variable")
|
67
|
-
.map((info) => info.data.variable);
|
68
|
-
|
69
|
-
return { datasets, variables };
|
43
|
+
return registry.formatContextForAI(contextIds);
|
70
44
|
}
|
71
45
|
|
72
46
|
/**
|
@@ -1,7 +1,15 @@
|
|
1
1
|
/* Copyright 2024 Marimo. All rights reserved. */
|
2
2
|
|
3
3
|
import type { Completion } from "@codemirror/autocomplete";
|
4
|
+
import { createStore } from "jotai";
|
4
5
|
import { beforeEach, describe, expect, it } from "vitest";
|
6
|
+
import { MockNotebook } from "@/__mocks__/notebook";
|
7
|
+
import { notebookAtom } from "@/core/cells/cells";
|
8
|
+
import { CellId as CellIdClass } from "@/core/cells/ids";
|
9
|
+
import {
|
10
|
+
type ErrorContextItem,
|
11
|
+
ErrorContextProvider,
|
12
|
+
} from "../providers/error";
|
5
13
|
import {
|
6
14
|
type AIContextItem,
|
7
15
|
AIContextProvider,
|
@@ -513,4 +521,150 @@ describe("AIContextRegistry", () => {
|
|
513
521
|
expect(provider).toBe(mockProvider);
|
514
522
|
});
|
515
523
|
});
|
524
|
+
|
525
|
+
describe("Integration with ErrorContextProvider", () => {
|
526
|
+
let errorProvider: ErrorContextProvider;
|
527
|
+
let store: ReturnType<typeof createStore>;
|
528
|
+
let registry: AIContextRegistry<ErrorContextItem>;
|
529
|
+
|
530
|
+
beforeEach(() => {
|
531
|
+
store = createStore();
|
532
|
+
|
533
|
+
// Create mock notebook with errors using the new MockNotebook utilities
|
534
|
+
const cellId1 = CellIdClass.create();
|
535
|
+
const cellId2 = CellIdClass.create();
|
536
|
+
|
537
|
+
const notebookState = MockNotebook.notebookStateWithErrors([
|
538
|
+
{
|
539
|
+
cellId: cellId1,
|
540
|
+
cellName: "Cell 1",
|
541
|
+
errorData: [
|
542
|
+
MockNotebook.errors.syntax("Invalid syntax"),
|
543
|
+
MockNotebook.errors.exception("Runtime error"),
|
544
|
+
],
|
545
|
+
},
|
546
|
+
{
|
547
|
+
cellId: cellId2,
|
548
|
+
cellName: "Cell 2",
|
549
|
+
errorData: [MockNotebook.errors.cycle()],
|
550
|
+
},
|
551
|
+
]);
|
552
|
+
|
553
|
+
store.set(notebookAtom, notebookState);
|
554
|
+
errorProvider = new ErrorContextProvider(store);
|
555
|
+
registry = new AIContextRegistry<ErrorContextItem>().register(
|
556
|
+
errorProvider,
|
557
|
+
);
|
558
|
+
});
|
559
|
+
|
560
|
+
it("should register and provide error context items", () => {
|
561
|
+
const provider = registry.getProvider("error");
|
562
|
+
expect(provider).toBe(errorProvider);
|
563
|
+
|
564
|
+
const items = registry.getAllItems();
|
565
|
+
expect(items).toHaveLength(1);
|
566
|
+
expect(items[0].type).toBe("error");
|
567
|
+
expect(items[0].name).toBe("Errors");
|
568
|
+
});
|
569
|
+
|
570
|
+
it("should parse error context IDs correctly", () => {
|
571
|
+
const contextIds = registry.parseAllContextIds(
|
572
|
+
"Use @error://all to analyze errors",
|
573
|
+
);
|
574
|
+
expect(contextIds).toEqual(["error://all"]);
|
575
|
+
|
576
|
+
const contextInfo = registry.getContextInfo(contextIds);
|
577
|
+
expect(contextInfo).toHaveLength(1);
|
578
|
+
expect(contextInfo[0].type).toBe("error");
|
579
|
+
});
|
580
|
+
|
581
|
+
it("should format error context for AI", () => {
|
582
|
+
const contextIds = ["error://all"] as ContextLocatorId[];
|
583
|
+
const formattedContext = registry.formatContextForAI(contextIds);
|
584
|
+
|
585
|
+
expect(formattedContext).toContain("<error");
|
586
|
+
expect(formattedContext).toContain("Cell 1");
|
587
|
+
expect(formattedContext).toContain("Cell 2");
|
588
|
+
expect(formattedContext).toContain("Invalid syntax");
|
589
|
+
expect(formattedContext).toContain("This cell is in a cycle");
|
590
|
+
});
|
591
|
+
|
592
|
+
it("should provide error completions", () => {
|
593
|
+
// Get the error provider and test its completion directly
|
594
|
+
const provider = registry.getProvider("error");
|
595
|
+
expect(provider).toBeDefined();
|
596
|
+
|
597
|
+
const items = provider!.getItems();
|
598
|
+
expect(items).toHaveLength(1);
|
599
|
+
|
600
|
+
const completion = provider!.formatCompletion(items[0]);
|
601
|
+
expect(completion.label).toBe("@Errors");
|
602
|
+
expect(completion.type).toBe("error");
|
603
|
+
});
|
604
|
+
|
605
|
+
it("should handle empty errors gracefully", () => {
|
606
|
+
// Create store with no errors using MockNotebook
|
607
|
+
const emptyStore = createStore();
|
608
|
+
const emptyNotebookState = MockNotebook.notebookStateWithErrors([]);
|
609
|
+
emptyStore.set(notebookAtom, emptyNotebookState);
|
610
|
+
|
611
|
+
const emptyErrorProvider = new ErrorContextProvider(emptyStore);
|
612
|
+
const emptyRegistry = new AIContextRegistry().register(
|
613
|
+
emptyErrorProvider,
|
614
|
+
);
|
615
|
+
|
616
|
+
const items = emptyRegistry.getAllItems();
|
617
|
+
expect(items).toHaveLength(0);
|
618
|
+
});
|
619
|
+
|
620
|
+
it("should work with mixed providers", () => {
|
621
|
+
const mixedRegistry = new AIContextRegistry<
|
622
|
+
ErrorContextItem | MockContextItem
|
623
|
+
>()
|
624
|
+
.register(errorProvider)
|
625
|
+
.register(mockProvider);
|
626
|
+
|
627
|
+
const items = mixedRegistry.getAllItems();
|
628
|
+
expect(items.length).toBeGreaterThan(1);
|
629
|
+
|
630
|
+
// Should have both error and mock items
|
631
|
+
const errorItems = items.filter((item) => item.type === "error");
|
632
|
+
const mockItems = items.filter((item) => item.type === "mock");
|
633
|
+
|
634
|
+
expect(errorItems).toHaveLength(1);
|
635
|
+
expect(mockItems).toHaveLength(3);
|
636
|
+
});
|
637
|
+
|
638
|
+
it("should parse mixed context IDs", () => {
|
639
|
+
const mixedRegistry = new AIContextRegistry<
|
640
|
+
ErrorContextItem | MockContextItem
|
641
|
+
>()
|
642
|
+
.register(errorProvider)
|
643
|
+
.register(mockProvider);
|
644
|
+
|
645
|
+
const input = "Use @error://all and @mock://item1 for analysis";
|
646
|
+
const contextIds = mixedRegistry.parseAllContextIds(input);
|
647
|
+
|
648
|
+
expect(contextIds).toContain("error://all");
|
649
|
+
expect(contextIds).toContain("mock://item1");
|
650
|
+
expect(contextIds).toHaveLength(2);
|
651
|
+
});
|
652
|
+
|
653
|
+
it("should format mixed context for AI", () => {
|
654
|
+
const mixedRegistry = new AIContextRegistry<
|
655
|
+
ErrorContextItem | MockContextItem
|
656
|
+
>()
|
657
|
+
.register(errorProvider)
|
658
|
+
.register(mockProvider);
|
659
|
+
|
660
|
+
const contextIds = ["error://all", "mock://item1"] as ContextLocatorId[];
|
661
|
+
const formattedContext = mixedRegistry.formatContextForAI(contextIds);
|
662
|
+
|
663
|
+
// Should contain both error and mock context
|
664
|
+
expect(formattedContext).toContain("<error");
|
665
|
+
expect(formattedContext).toContain("Mock:");
|
666
|
+
expect(formattedContext).toContain("Cell 1");
|
667
|
+
expect(formattedContext).toContain("Item 1");
|
668
|
+
});
|
669
|
+
});
|
516
670
|
});
|