@marimo-team/frontend 0.15.1-dev34 → 0.15.1-dev36
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-BcJwEN2q.js → ConnectedDataExplorerComponent-D8km1NYJ.js} +1 -1
- package/dist/assets/{ImageComparisonComponent-CnwGwcTi.js → ImageComparisonComponent-CERR01UB.js} +1 -1
- package/dist/assets/{VegaLite-Cnk7Ozer.js → VegaLite-DzZIYwlo.js} +1 -1
- package/dist/assets/{_baseEach-DJPM6ZzY.js → _baseEach-DO-XcSIV.js} +1 -1
- package/dist/assets/_baseMap-Dg1mkEJY.js +1 -0
- package/dist/assets/{_baseUniq-CrXjB6JP.js → _baseUniq-urG2vBXB.js} +1 -1
- package/dist/assets/{_createAggregator-Cd0noqMc.js → _createAggregator-DBxX1xI5.js} +1 -1
- package/dist/assets/{any-language-editor-ZfVYrHPH.js → any-language-editor-BhBzti0Q.js} +1 -1
- package/dist/assets/{architectureDiagram-KFL7JDKH-DuJCaD_M.js → architectureDiagram-KFL7JDKH-mgZE9P9E.js} +1 -1
- package/dist/assets/{blockDiagram-ZYB65J3Q-B0f3bVJ0.js → blockDiagram-ZYB65J3Q-DhlvqBBN.js} +1 -1
- package/dist/assets/{c4Diagram-AAMF2YG6-3srX8_ui.js → c4Diagram-AAMF2YG6-WgF7TmcX.js} +1 -1
- package/dist/assets/channel-D1aHTD78.js +1 -0
- package/dist/assets/{chunk-ANTBXLJU-CD8Ya77t.js → chunk-ANTBXLJU-Cc0FLBv4.js} +1 -1
- package/dist/assets/{chunk-FHKO5MBM-34L0hhh_.js → chunk-FHKO5MBM-TDVJkINs.js} +1 -1
- package/dist/assets/{chunk-GLLZNHP4-CRWkmhQj.js → chunk-GLLZNHP4-BFZQsgmM.js} +1 -1
- package/dist/assets/{chunk-JBRWN2VN-CB8a_SQv.js → chunk-JBRWN2VN-jewL7EcA.js} +1 -1
- package/dist/assets/{chunk-LXBSTHXV-YNRk01ob.js → chunk-LXBSTHXV-DtMvensd.js} +1 -1
- package/dist/assets/{chunk-NRVI72HA-nFtyi9pH.js → chunk-NRVI72HA-B7LxIi5N.js} +1 -1
- package/dist/assets/{chunk-OMD6QJNC-BXZ4Kapq.js → chunk-OMD6QJNC-D77lwHsv.js} +1 -1
- package/dist/assets/{chunk-WVR4S24B-ZnYlHppS.js → chunk-WVR4S24B-BdzaJi_f.js} +1 -1
- package/dist/assets/{circle-play-k88jloBa.js → circle-play-DbLJhgWd.js} +1 -1
- package/dist/assets/classDiagram-3BZAVTQC-C8Rjm-tQ.js +1 -0
- package/dist/assets/classDiagram-v2-QTMF73CY-C8Rjm-tQ.js +1 -0
- package/dist/assets/clone-BWlvmMhq.js +1 -0
- package/dist/assets/{compile-CDMtSySK.js → compile-ittiAa-p.js} +1 -1
- package/dist/assets/{dagre-2BBEFEWP-Bfm20vyd.js → dagre-2BBEFEWP-woDg8Awj.js} +1 -1
- package/dist/assets/{data-grid-overlay-editor-CwEfDFcK.js → data-grid-overlay-editor-ncLMoVIb.js} +1 -1
- package/dist/assets/{diagram-4IRLE6MV-A9psNOWP.js → diagram-4IRLE6MV-PAN7AATi.js} +1 -1
- package/dist/assets/{diagram-GUPCWM2R-B23WLgai.js → diagram-GUPCWM2R-Ce2AHqMP.js} +1 -1
- package/dist/assets/{diagram-RP2FKANI-CU5qL55k.js → diagram-RP2FKANI-2WiKea8D.js} +1 -1
- package/dist/assets/{edit-page-DYm-s1ff.js → edit-page-CZn2bhY3.js} +42 -42
- package/dist/assets/{erDiagram-HZWUO2LU-D31RvIVf.js → erDiagram-HZWUO2LU-D5yTZwmt.js} +1 -1
- package/dist/assets/{flowDiagram-THRYKUMA-ClYGAL8Y.js → flowDiagram-THRYKUMA-CgN86sZ8.js} +1 -1
- package/dist/assets/{ganttDiagram-WV7ZQ7D5-Cmed9KL9.js → ganttDiagram-WV7ZQ7D5-5skQ2H3l.js} +1 -1
- package/dist/assets/{gitGraphDiagram-OJR772UL-CWvdnGVc.js → gitGraphDiagram-OJR772UL-C75De8fN.js} +1 -1
- package/dist/assets/{glide-data-editor-CFVz2aZ5.js → glide-data-editor-x0d0Up5U.js} +4 -4
- package/dist/assets/{graph-OxTx0_rA.js → graph-Die-6Bfl.js} +1 -1
- package/dist/assets/{home-page-Dt3nnRSz.js → home-page-XrEKfDMd.js} +1 -1
- package/dist/assets/{index-C0Q8e5FM.js → index-B1-fG89N.js} +1 -1
- package/dist/assets/{index-BLXqwIOX.js → index-B3-zxsj0.js} +1 -1
- package/dist/assets/{index-DjT-1R5N.js → index-B7JwzNrx.js} +1 -1
- package/dist/assets/{index-quG0To4_.js → index-BSJet7Zq.js} +1 -1
- package/dist/assets/{index-Bu3XvTHk.js → index-BWBg8Lhk.js} +1 -1
- package/dist/assets/{index-DLO62gfd.js → index-BfqMljbw.js} +1 -1
- package/dist/assets/{index-DHlxJ27b.js → index-CCZkMG5j.js} +1 -1
- package/dist/assets/{index-CQFSXxPp.js → index-CXwX4pUI.js} +133 -133
- package/dist/assets/{index-DETsDEp1.js → index-CoAopzxc.js} +1 -1
- package/dist/assets/{index-BOFl7de8.js → index-D9ot8WPl.js} +1 -1
- package/dist/assets/{index-WltWzc1Z.js → index-D_ebOE-e.js} +1 -1
- package/dist/assets/{index-Bd2C9zUZ.js → index-De7juNGF.js} +1 -1
- package/dist/assets/{index-KCIhgRrL.js → index-Dh8C39yO.js} +1 -1
- package/dist/assets/{index-BUwTI3go.js → index-Dlrab0dK.js} +1 -1
- package/dist/assets/{index-4GKIL9qL.js → index-DmHX1Rlv.js} +1 -1
- package/dist/assets/{index-Baw8vWOg.js → index-F531CohR.js} +1 -1
- package/dist/assets/{index-BM1NAxco.js → index-UAPuSZUk.js} +1 -1
- package/dist/assets/{index-DsWckHTg.js → index-jwhWh6uS.js} +1 -1
- package/dist/assets/{index-B-P7QUhF.js → index-kraNHKP1.js} +1 -1
- package/dist/assets/{index-D4HfKv3U.js → index-v546YXgW.js} +1 -1
- package/dist/assets/{infoDiagram-6WOFNB3A-BQOY1VMN.js → infoDiagram-6WOFNB3A-mJ455ogl.js} +1 -1
- package/dist/assets/{journeyDiagram-FFXJYRFH-BLEcUGJo.js → journeyDiagram-FFXJYRFH-CrWxkiXG.js} +1 -1
- package/dist/assets/{kanban-definition-KOZQBZVT-RanT6u8e.js → kanban-definition-KOZQBZVT-D5haTqpz.js} +1 -1
- package/dist/assets/{layout-D4n_CEl8.js → layout-BEc7rmra.js} +1 -1
- package/dist/assets/{linear-BbPKk0w3.js → linear-BLmy5c_P.js} +1 -1
- package/dist/assets/{links-B7_BzQLv.js → links-BGVSWGyv.js} +1 -1
- package/dist/assets/{mermaid-CUkYs7pX.js → mermaid-Bu2fp8N3.js} +4 -4
- package/dist/assets/{min-Yuyj_o4k.js → min-BF5a70Ha.js} +1 -1
- package/dist/assets/{mindmap-definition-LNHGMQRG-x4MjCJ_j.js → mindmap-definition-LNHGMQRG-jD2ylGBG.js} +1 -1
- package/dist/assets/{number-overlay-editor-DeKR_mfB.js → number-overlay-editor-BadGHMrr.js} +1 -1
- package/dist/assets/{pieDiagram-DBDJKBY4-ZOMhJp-a.js → pieDiagram-DBDJKBY4-B11UeqxS.js} +1 -1
- package/dist/assets/{quadrantDiagram-YPSRARAO-vZeyiYxN.js → quadrantDiagram-YPSRARAO-DznrQXs-.js} +1 -1
- package/dist/assets/{react-plotly-BV6-1ruP.js → react-plotly-B6W1vV_l.js} +1 -1
- package/dist/assets/{requirementDiagram-EGVEC5DT-DkgbH0oi.js → requirementDiagram-EGVEC5DT-BuWp2ov9.js} +1 -1
- package/dist/assets/{run-page-0slxHZwl.js → run-page-BD4YehOu.js} +1 -1
- package/dist/assets/{sankeyDiagram-HRAUVNP4-BuFPw2i8.js → sankeyDiagram-HRAUVNP4-BmDCzHkG.js} +1 -1
- package/dist/assets/{sequenceDiagram-WFGC7UMF-BKGIaix6.js → sequenceDiagram-WFGC7UMF-B6aCHwAd.js} +1 -1
- package/dist/assets/{slides-component-DYhLRND3.js → slides-component-CkHAJhvv.js} +1 -1
- package/dist/assets/{sortBy-C_bWmRoh.js → sortBy-BgSF6Z3p.js} +1 -1
- package/dist/assets/{stateDiagram-UUKSUZ4H-Cm2zkw0M.js → stateDiagram-UUKSUZ4H-DcGKoXUB.js} +1 -1
- package/dist/assets/stateDiagram-v2-EYPG3UTE-BW5Lhcrb.js +1 -0
- package/dist/assets/{storage-Dk-ciwQU.js → storage-BX5GfYeC.js} +3 -3
- package/dist/assets/{terminal-DrDWxiEU.js → terminal-CpmTRzDD.js} +1 -1
- package/dist/assets/{time-DW3BCgky.js → time-igUPFhda.js} +1 -1
- package/dist/assets/{timeline-definition-3HZDQTIS-B_ZdpuLp.js → timeline-definition-3HZDQTIS-7b4K28uW.js} +1 -1
- package/dist/assets/{tracing-BuGDnWcg.js → tracing-BWeRyJmf.js} +2 -2
- package/dist/assets/{trash-BKmRbRfw.js → trash-Bv9cD3VE.js} +1 -1
- package/dist/assets/{treemap-75Q7IDZK-BBbbCdps.js → treemap-75Q7IDZK-DPkOPTcz.js} +1 -1
- package/dist/assets/{vega-component-DogOWa6S.js → vega-component-CGVDFtwG.js} +1 -1
- package/dist/assets/{xychartDiagram-FDP5SA34-3B1j_9pq.js → xychartDiagram-FDP5SA34-BbvKlNzf.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/Cell.tsx +16 -17
- package/src/components/editor/ai/__tests__/completion-utils.test.ts +119 -139
- package/src/components/editor/ai/completion-utils.ts +7 -33
- package/src/components/editor/navigation/navigation.ts +7 -7
- package/src/components/editor/navigation/state.ts +34 -2
- 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/dist/assets/_baseMap-u5TY8JMW.js +0 -1
- package/dist/assets/channel-BIZI32eZ.js +0 -1
- package/dist/assets/classDiagram-3BZAVTQC-DfPpF-gd.js +0 -1
- package/dist/assets/classDiagram-v2-QTMF73CY-DfPpF-gd.js +0 -1
- package/dist/assets/clone-yHYNh3QG.js +0 -1
- package/dist/assets/stateDiagram-v2-EYPG3UTE-DX5NRIHK.js +0 -1
@@ -2,8 +2,7 @@
|
|
2
2
|
import { closeCompletion, completionStatus } from "@codemirror/autocomplete";
|
3
3
|
import type { EditorView } from "@codemirror/view";
|
4
4
|
import clsx from "clsx";
|
5
|
-
import {
|
6
|
-
import { ScopeProvider } from "jotai-scope";
|
5
|
+
import { useAtomValue, useSetAtom } from "jotai";
|
7
6
|
import {
|
8
7
|
HelpCircleIcon,
|
9
8
|
MoreHorizontalIcon,
|
@@ -78,7 +77,10 @@ import { useRunCell } from "./cell/useRunCells";
|
|
78
77
|
import { HideCodeButton } from "./code/readonly-python-code";
|
79
78
|
import { cellDomProps } from "./common";
|
80
79
|
import { useCellNavigationProps } from "./navigation/navigation";
|
81
|
-
import {
|
80
|
+
import {
|
81
|
+
useTemporarilyShownCode,
|
82
|
+
useTemporarilyShownCodeActions,
|
83
|
+
} from "./navigation/state";
|
82
84
|
import { OutputArea } from "./Output";
|
83
85
|
import { ConsoleOutput } from "./output/ConsoleOutput";
|
84
86
|
import { CellDragHandle, SortableCell } from "./SortableCell";
|
@@ -157,9 +159,8 @@ function useCellHiddenLogic({
|
|
157
159
|
editorView: React.RefObject<EditorView | null>;
|
158
160
|
editorViewParentRef: React.RefObject<HTMLDivElement | null>;
|
159
161
|
}) {
|
160
|
-
const
|
161
|
-
|
162
|
-
);
|
162
|
+
const temporarilyVisible = useTemporarilyShownCode(cellId);
|
163
|
+
const temporarilyShownCodeActions = useTemporarilyShownCodeActions();
|
163
164
|
const isUntouched = useAtomValue(
|
164
165
|
useMemo(() => createUntouchedCellAtom(cellId), [cellId]),
|
165
166
|
);
|
@@ -179,7 +180,7 @@ function useCellHiddenLogic({
|
|
179
180
|
|
180
181
|
// Default to true
|
181
182
|
const focus = opts?.focus ?? true;
|
182
|
-
|
183
|
+
temporarilyShownCodeActions.add(cellId);
|
183
184
|
|
184
185
|
if (focus) {
|
185
186
|
editorView.current?.focus();
|
@@ -297,16 +298,14 @@ const CellComponent = (props: CellProps) => {
|
|
297
298
|
|
298
299
|
if (mode === "edit") {
|
299
300
|
return (
|
300
|
-
<
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
/>
|
309
|
-
</ScopeProvider>
|
301
|
+
<EditableCellComponent
|
302
|
+
{...props}
|
303
|
+
cellId={cellId}
|
304
|
+
editorView={editorView}
|
305
|
+
setEditorView={(ev) => {
|
306
|
+
editorView.current = ev;
|
307
|
+
}}
|
308
|
+
/>
|
310
309
|
);
|
311
310
|
}
|
312
311
|
|
@@ -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
|
/**
|
@@ -33,7 +33,7 @@ import {
|
|
33
33
|
useCellSelectionActions,
|
34
34
|
useIsCellSelected,
|
35
35
|
} from "./selection";
|
36
|
-
import {
|
36
|
+
import { useTemporarilyShownCodeActions } from "./state";
|
37
37
|
import { handleVimKeybinding } from "./vim-bindings";
|
38
38
|
|
39
39
|
interface HotkeyHandler {
|
@@ -85,7 +85,7 @@ function addSingleHandler(handler: HotkeyHandler["bulkHandle"]): HotkeyHandler {
|
|
85
85
|
function useCellFocusProps(cellId: CellId) {
|
86
86
|
const focusActions = useCellFocusActions();
|
87
87
|
const actions = useCellActions();
|
88
|
-
const
|
88
|
+
const temporarilyShownCodeActions = useTemporarilyShownCodeActions();
|
89
89
|
|
90
90
|
// This occurs at the cell level and descedants.
|
91
91
|
const { focusWithinProps } = useFocusWithin({
|
@@ -95,7 +95,7 @@ function useCellFocusProps(cellId: CellId) {
|
|
95
95
|
},
|
96
96
|
onBlurWithin: () => {
|
97
97
|
// On blur, hide the code if it was temporarily shown.
|
98
|
-
|
98
|
+
temporarilyShownCodeActions.remove(cellId);
|
99
99
|
actions.markTouched({ cellId });
|
100
100
|
focusActions.blurCell();
|
101
101
|
},
|
@@ -132,7 +132,7 @@ export function useCellNavigationProps(
|
|
132
132
|
const setAiCompletionCell = useSetAtom(aiCompletionCellAtom);
|
133
133
|
const actions = useCellActions();
|
134
134
|
const store = useStore();
|
135
|
-
const
|
135
|
+
const temporarilyShownCodeActions = useTemporarilyShownCodeActions();
|
136
136
|
const runCells = useRunCells();
|
137
137
|
const keymapPreset = useAtomValue(keymapPresetAtom);
|
138
138
|
const { copyCells, pasteAtCell } = useCellClipboard();
|
@@ -275,7 +275,7 @@ export function useCellNavigationProps(
|
|
275
275
|
},
|
276
276
|
// Enter will focus the cell editor.
|
277
277
|
Enter: () => {
|
278
|
-
|
278
|
+
temporarilyShownCodeActions.add(cellId);
|
279
279
|
focusCellEditor(store, cellId);
|
280
280
|
selectionActions.clear();
|
281
281
|
return true;
|
@@ -608,7 +608,7 @@ export function useCellEditorNavigationProps(
|
|
608
608
|
cellId: CellId,
|
609
609
|
editorView: React.RefObject<EditorView | null>,
|
610
610
|
) {
|
611
|
-
const
|
611
|
+
const temporarilyShownCodeActions = useTemporarilyShownCodeActions();
|
612
612
|
const keymapPreset = useAtomValue(keymapPresetAtom);
|
613
613
|
const hotkeys = useAtomValue(hotkeysAtom);
|
614
614
|
|
@@ -618,7 +618,7 @@ export function useCellEditorNavigationProps(
|
|
618
618
|
}, [hotkeys]);
|
619
619
|
|
620
620
|
const exitToCommandMode = () => {
|
621
|
-
|
621
|
+
temporarilyShownCodeActions.remove(cellId);
|
622
622
|
focusCell(cellId);
|
623
623
|
};
|
624
624
|
|
@@ -1,5 +1,37 @@
|
|
1
1
|
/* Copyright 2024 Marimo. All rights reserved. */
|
2
2
|
|
3
|
-
import { atom } from "jotai";
|
3
|
+
import { atom, useAtomValue } from "jotai";
|
4
|
+
import { useMemo } from "react";
|
5
|
+
import type { CellId } from "@/core/cells/ids";
|
6
|
+
import { createReducerAndAtoms } from "@/utils/createReducer";
|
4
7
|
|
5
|
-
|
8
|
+
type TemporarilyShownCodeState = Set<CellId>;
|
9
|
+
|
10
|
+
// This previously used jotai-scope, but unfortunately this bug creates unnecessary work:
|
11
|
+
// https://github.com/jotaijs/jotai-scope/issues/25
|
12
|
+
|
13
|
+
const {
|
14
|
+
valueAtom: temporarilyShownCodeAtom,
|
15
|
+
useActions: useTemporarilyShownCodeActions,
|
16
|
+
} = createReducerAndAtoms(() => new Set<CellId>(), {
|
17
|
+
add: (state: TemporarilyShownCodeState, cellId: CellId) => {
|
18
|
+
const newState = new Set(state);
|
19
|
+
newState.add(cellId);
|
20
|
+
return newState;
|
21
|
+
},
|
22
|
+
remove: (state: TemporarilyShownCodeState, cellId: CellId) => {
|
23
|
+
const newState = new Set(state);
|
24
|
+
newState.delete(cellId);
|
25
|
+
return newState;
|
26
|
+
},
|
27
|
+
});
|
28
|
+
|
29
|
+
const createTemporarilyShownCodeAtom = (cellId: CellId) =>
|
30
|
+
atom((get) => get(temporarilyShownCodeAtom).has(cellId));
|
31
|
+
|
32
|
+
export function useTemporarilyShownCode(cellId: CellId) {
|
33
|
+
const atom = useMemo(() => createTemporarilyShownCodeAtom(cellId), [cellId]);
|
34
|
+
return useAtomValue(atom);
|
35
|
+
}
|
36
|
+
|
37
|
+
export { temporarilyShownCodeAtom, useTemporarilyShownCodeActions };
|