@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.
Files changed (115) hide show
  1. package/dist/assets/{ConnectedDataExplorerComponent-BcJwEN2q.js → ConnectedDataExplorerComponent-D8km1NYJ.js} +1 -1
  2. package/dist/assets/{ImageComparisonComponent-CnwGwcTi.js → ImageComparisonComponent-CERR01UB.js} +1 -1
  3. package/dist/assets/{VegaLite-Cnk7Ozer.js → VegaLite-DzZIYwlo.js} +1 -1
  4. package/dist/assets/{_baseEach-DJPM6ZzY.js → _baseEach-DO-XcSIV.js} +1 -1
  5. package/dist/assets/_baseMap-Dg1mkEJY.js +1 -0
  6. package/dist/assets/{_baseUniq-CrXjB6JP.js → _baseUniq-urG2vBXB.js} +1 -1
  7. package/dist/assets/{_createAggregator-Cd0noqMc.js → _createAggregator-DBxX1xI5.js} +1 -1
  8. package/dist/assets/{any-language-editor-ZfVYrHPH.js → any-language-editor-BhBzti0Q.js} +1 -1
  9. package/dist/assets/{architectureDiagram-KFL7JDKH-DuJCaD_M.js → architectureDiagram-KFL7JDKH-mgZE9P9E.js} +1 -1
  10. package/dist/assets/{blockDiagram-ZYB65J3Q-B0f3bVJ0.js → blockDiagram-ZYB65J3Q-DhlvqBBN.js} +1 -1
  11. package/dist/assets/{c4Diagram-AAMF2YG6-3srX8_ui.js → c4Diagram-AAMF2YG6-WgF7TmcX.js} +1 -1
  12. package/dist/assets/channel-D1aHTD78.js +1 -0
  13. package/dist/assets/{chunk-ANTBXLJU-CD8Ya77t.js → chunk-ANTBXLJU-Cc0FLBv4.js} +1 -1
  14. package/dist/assets/{chunk-FHKO5MBM-34L0hhh_.js → chunk-FHKO5MBM-TDVJkINs.js} +1 -1
  15. package/dist/assets/{chunk-GLLZNHP4-CRWkmhQj.js → chunk-GLLZNHP4-BFZQsgmM.js} +1 -1
  16. package/dist/assets/{chunk-JBRWN2VN-CB8a_SQv.js → chunk-JBRWN2VN-jewL7EcA.js} +1 -1
  17. package/dist/assets/{chunk-LXBSTHXV-YNRk01ob.js → chunk-LXBSTHXV-DtMvensd.js} +1 -1
  18. package/dist/assets/{chunk-NRVI72HA-nFtyi9pH.js → chunk-NRVI72HA-B7LxIi5N.js} +1 -1
  19. package/dist/assets/{chunk-OMD6QJNC-BXZ4Kapq.js → chunk-OMD6QJNC-D77lwHsv.js} +1 -1
  20. package/dist/assets/{chunk-WVR4S24B-ZnYlHppS.js → chunk-WVR4S24B-BdzaJi_f.js} +1 -1
  21. package/dist/assets/{circle-play-k88jloBa.js → circle-play-DbLJhgWd.js} +1 -1
  22. package/dist/assets/classDiagram-3BZAVTQC-C8Rjm-tQ.js +1 -0
  23. package/dist/assets/classDiagram-v2-QTMF73CY-C8Rjm-tQ.js +1 -0
  24. package/dist/assets/clone-BWlvmMhq.js +1 -0
  25. package/dist/assets/{compile-CDMtSySK.js → compile-ittiAa-p.js} +1 -1
  26. package/dist/assets/{dagre-2BBEFEWP-Bfm20vyd.js → dagre-2BBEFEWP-woDg8Awj.js} +1 -1
  27. package/dist/assets/{data-grid-overlay-editor-CwEfDFcK.js → data-grid-overlay-editor-ncLMoVIb.js} +1 -1
  28. package/dist/assets/{diagram-4IRLE6MV-A9psNOWP.js → diagram-4IRLE6MV-PAN7AATi.js} +1 -1
  29. package/dist/assets/{diagram-GUPCWM2R-B23WLgai.js → diagram-GUPCWM2R-Ce2AHqMP.js} +1 -1
  30. package/dist/assets/{diagram-RP2FKANI-CU5qL55k.js → diagram-RP2FKANI-2WiKea8D.js} +1 -1
  31. package/dist/assets/{edit-page-DYm-s1ff.js → edit-page-CZn2bhY3.js} +42 -42
  32. package/dist/assets/{erDiagram-HZWUO2LU-D31RvIVf.js → erDiagram-HZWUO2LU-D5yTZwmt.js} +1 -1
  33. package/dist/assets/{flowDiagram-THRYKUMA-ClYGAL8Y.js → flowDiagram-THRYKUMA-CgN86sZ8.js} +1 -1
  34. package/dist/assets/{ganttDiagram-WV7ZQ7D5-Cmed9KL9.js → ganttDiagram-WV7ZQ7D5-5skQ2H3l.js} +1 -1
  35. package/dist/assets/{gitGraphDiagram-OJR772UL-CWvdnGVc.js → gitGraphDiagram-OJR772UL-C75De8fN.js} +1 -1
  36. package/dist/assets/{glide-data-editor-CFVz2aZ5.js → glide-data-editor-x0d0Up5U.js} +4 -4
  37. package/dist/assets/{graph-OxTx0_rA.js → graph-Die-6Bfl.js} +1 -1
  38. package/dist/assets/{home-page-Dt3nnRSz.js → home-page-XrEKfDMd.js} +1 -1
  39. package/dist/assets/{index-C0Q8e5FM.js → index-B1-fG89N.js} +1 -1
  40. package/dist/assets/{index-BLXqwIOX.js → index-B3-zxsj0.js} +1 -1
  41. package/dist/assets/{index-DjT-1R5N.js → index-B7JwzNrx.js} +1 -1
  42. package/dist/assets/{index-quG0To4_.js → index-BSJet7Zq.js} +1 -1
  43. package/dist/assets/{index-Bu3XvTHk.js → index-BWBg8Lhk.js} +1 -1
  44. package/dist/assets/{index-DLO62gfd.js → index-BfqMljbw.js} +1 -1
  45. package/dist/assets/{index-DHlxJ27b.js → index-CCZkMG5j.js} +1 -1
  46. package/dist/assets/{index-CQFSXxPp.js → index-CXwX4pUI.js} +133 -133
  47. package/dist/assets/{index-DETsDEp1.js → index-CoAopzxc.js} +1 -1
  48. package/dist/assets/{index-BOFl7de8.js → index-D9ot8WPl.js} +1 -1
  49. package/dist/assets/{index-WltWzc1Z.js → index-D_ebOE-e.js} +1 -1
  50. package/dist/assets/{index-Bd2C9zUZ.js → index-De7juNGF.js} +1 -1
  51. package/dist/assets/{index-KCIhgRrL.js → index-Dh8C39yO.js} +1 -1
  52. package/dist/assets/{index-BUwTI3go.js → index-Dlrab0dK.js} +1 -1
  53. package/dist/assets/{index-4GKIL9qL.js → index-DmHX1Rlv.js} +1 -1
  54. package/dist/assets/{index-Baw8vWOg.js → index-F531CohR.js} +1 -1
  55. package/dist/assets/{index-BM1NAxco.js → index-UAPuSZUk.js} +1 -1
  56. package/dist/assets/{index-DsWckHTg.js → index-jwhWh6uS.js} +1 -1
  57. package/dist/assets/{index-B-P7QUhF.js → index-kraNHKP1.js} +1 -1
  58. package/dist/assets/{index-D4HfKv3U.js → index-v546YXgW.js} +1 -1
  59. package/dist/assets/{infoDiagram-6WOFNB3A-BQOY1VMN.js → infoDiagram-6WOFNB3A-mJ455ogl.js} +1 -1
  60. package/dist/assets/{journeyDiagram-FFXJYRFH-BLEcUGJo.js → journeyDiagram-FFXJYRFH-CrWxkiXG.js} +1 -1
  61. package/dist/assets/{kanban-definition-KOZQBZVT-RanT6u8e.js → kanban-definition-KOZQBZVT-D5haTqpz.js} +1 -1
  62. package/dist/assets/{layout-D4n_CEl8.js → layout-BEc7rmra.js} +1 -1
  63. package/dist/assets/{linear-BbPKk0w3.js → linear-BLmy5c_P.js} +1 -1
  64. package/dist/assets/{links-B7_BzQLv.js → links-BGVSWGyv.js} +1 -1
  65. package/dist/assets/{mermaid-CUkYs7pX.js → mermaid-Bu2fp8N3.js} +4 -4
  66. package/dist/assets/{min-Yuyj_o4k.js → min-BF5a70Ha.js} +1 -1
  67. package/dist/assets/{mindmap-definition-LNHGMQRG-x4MjCJ_j.js → mindmap-definition-LNHGMQRG-jD2ylGBG.js} +1 -1
  68. package/dist/assets/{number-overlay-editor-DeKR_mfB.js → number-overlay-editor-BadGHMrr.js} +1 -1
  69. package/dist/assets/{pieDiagram-DBDJKBY4-ZOMhJp-a.js → pieDiagram-DBDJKBY4-B11UeqxS.js} +1 -1
  70. package/dist/assets/{quadrantDiagram-YPSRARAO-vZeyiYxN.js → quadrantDiagram-YPSRARAO-DznrQXs-.js} +1 -1
  71. package/dist/assets/{react-plotly-BV6-1ruP.js → react-plotly-B6W1vV_l.js} +1 -1
  72. package/dist/assets/{requirementDiagram-EGVEC5DT-DkgbH0oi.js → requirementDiagram-EGVEC5DT-BuWp2ov9.js} +1 -1
  73. package/dist/assets/{run-page-0slxHZwl.js → run-page-BD4YehOu.js} +1 -1
  74. package/dist/assets/{sankeyDiagram-HRAUVNP4-BuFPw2i8.js → sankeyDiagram-HRAUVNP4-BmDCzHkG.js} +1 -1
  75. package/dist/assets/{sequenceDiagram-WFGC7UMF-BKGIaix6.js → sequenceDiagram-WFGC7UMF-B6aCHwAd.js} +1 -1
  76. package/dist/assets/{slides-component-DYhLRND3.js → slides-component-CkHAJhvv.js} +1 -1
  77. package/dist/assets/{sortBy-C_bWmRoh.js → sortBy-BgSF6Z3p.js} +1 -1
  78. package/dist/assets/{stateDiagram-UUKSUZ4H-Cm2zkw0M.js → stateDiagram-UUKSUZ4H-DcGKoXUB.js} +1 -1
  79. package/dist/assets/stateDiagram-v2-EYPG3UTE-BW5Lhcrb.js +1 -0
  80. package/dist/assets/{storage-Dk-ciwQU.js → storage-BX5GfYeC.js} +3 -3
  81. package/dist/assets/{terminal-DrDWxiEU.js → terminal-CpmTRzDD.js} +1 -1
  82. package/dist/assets/{time-DW3BCgky.js → time-igUPFhda.js} +1 -1
  83. package/dist/assets/{timeline-definition-3HZDQTIS-B_ZdpuLp.js → timeline-definition-3HZDQTIS-7b4K28uW.js} +1 -1
  84. package/dist/assets/{tracing-BuGDnWcg.js → tracing-BWeRyJmf.js} +2 -2
  85. package/dist/assets/{trash-BKmRbRfw.js → trash-Bv9cD3VE.js} +1 -1
  86. package/dist/assets/{treemap-75Q7IDZK-BBbbCdps.js → treemap-75Q7IDZK-DPkOPTcz.js} +1 -1
  87. package/dist/assets/{vega-component-DogOWa6S.js → vega-component-CGVDFtwG.js} +1 -1
  88. package/dist/assets/{xychartDiagram-FDP5SA34-3B1j_9pq.js → xychartDiagram-FDP5SA34-BbvKlNzf.js} +1 -1
  89. package/dist/index.html +1 -1
  90. package/package.json +1 -1
  91. package/src/__mocks__/notebook.ts +108 -0
  92. package/src/components/editor/Cell.tsx +16 -17
  93. package/src/components/editor/ai/__tests__/completion-utils.test.ts +119 -139
  94. package/src/components/editor/ai/completion-utils.ts +7 -33
  95. package/src/components/editor/navigation/navigation.ts +7 -7
  96. package/src/components/editor/navigation/state.ts +34 -2
  97. package/src/core/ai/context/__tests__/registry.test.ts +154 -0
  98. package/src/core/ai/context/__tests__/utils.test.ts +174 -0
  99. package/src/core/ai/context/context.ts +3 -1
  100. package/src/core/ai/context/providers/__tests__/__snapshots__/error.test.ts.snap +3 -0
  101. package/src/core/ai/context/providers/__tests__/__snapshots__/tables.test.ts.snap +8 -12
  102. package/src/core/ai/context/providers/__tests__/__snapshots__/variable.test.ts.snap +4 -20
  103. package/src/core/ai/context/providers/__tests__/error.test.ts +328 -0
  104. package/src/core/ai/context/providers/common.ts +1 -0
  105. package/src/core/ai/context/providers/error.ts +165 -0
  106. package/src/core/ai/context/providers/tables.ts +14 -6
  107. package/src/core/ai/context/providers/variable.ts +11 -2
  108. package/src/core/ai/context/utils.ts +49 -0
  109. package/src/core/cells/cells.ts +1 -1
  110. package/dist/assets/_baseMap-u5TY8JMW.js +0 -1
  111. package/dist/assets/channel-BIZI32eZ.js +0 -1
  112. package/dist/assets/classDiagram-3BZAVTQC-DfPpF-gd.js +0 -1
  113. package/dist/assets/classDiagram-v2-QTMF73CY-DfPpF-gd.js +0 -1
  114. package/dist/assets/clone-yHYNh3QG.js +0 -1
  115. package/dist/assets/stateDiagram-v2-EYPG3UTE-DX5NRIHK.js +0 -1
@@ -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
  });
@@ -0,0 +1,174 @@
1
+ /* Copyright 2024 Marimo. All rights reserved. */
2
+
3
+ import { describe, expect, it } from "vitest";
4
+ import { contextToXml } from "../utils";
5
+
6
+ describe("contextToXml", () => {
7
+ it("should convert basic context to XML", () => {
8
+ const context = {
9
+ type: "data",
10
+ data: {
11
+ name: "dataset1",
12
+ source: "memory",
13
+ },
14
+ };
15
+
16
+ const result = contextToXml(context);
17
+ expect(result).toBe('<data name="dataset1" source="memory"></data>');
18
+ });
19
+
20
+ it("should handle context with details", () => {
21
+ const context = {
22
+ type: "variable",
23
+ data: {
24
+ name: "my_var",
25
+ dataType: "string",
26
+ },
27
+ details: "This is a string variable",
28
+ };
29
+
30
+ const result = contextToXml(context);
31
+ expect(result).toBe(
32
+ '<variable name="my_var" dataType="string">This is a string variable</variable>',
33
+ );
34
+ });
35
+
36
+ it("should escape XML characters in attributes", () => {
37
+ const context = {
38
+ type: "data",
39
+ data: {
40
+ name: "dataset<>&\"'",
41
+ description: "Contains special chars",
42
+ },
43
+ };
44
+
45
+ const result = contextToXml(context);
46
+ expect(result).toMatchInlineSnapshot(
47
+ `"<data name="dataset&lt;&gt;&"'" description="Contains special chars"></data>"`,
48
+ );
49
+ });
50
+
51
+ it("should escape XML characters in details", () => {
52
+ const context = {
53
+ type: "error",
54
+ data: {
55
+ name: "error1",
56
+ },
57
+ details: "Error message with <tags> & \"quotes\" and 'apostrophes'",
58
+ };
59
+
60
+ const result = contextToXml(context);
61
+ expect(result).toMatchInlineSnapshot(
62
+ `"<error name="error1">Error message with &lt;tags&gt; & "quotes" and 'apostrophes'</error>"`,
63
+ );
64
+ });
65
+
66
+ it("should handle undefined values in data", () => {
67
+ const context = {
68
+ type: "variable",
69
+ data: {
70
+ name: "my_var",
71
+ dataType: undefined,
72
+ value: "test",
73
+ },
74
+ };
75
+
76
+ const result = contextToXml(context);
77
+ expect(result).toBe('<variable name="my_var" value="test"></variable>');
78
+ });
79
+
80
+ it("should handle empty data object", () => {
81
+ const context = {
82
+ type: "empty",
83
+ data: {},
84
+ };
85
+
86
+ const result = contextToXml(context);
87
+ expect(result).toBe("<empty></empty>");
88
+ });
89
+
90
+ it("should handle numeric values", () => {
91
+ const context = {
92
+ type: "metric",
93
+ data: {
94
+ count: 42,
95
+ percentage: 85.5,
96
+ isActive: true,
97
+ },
98
+ };
99
+
100
+ const result = contextToXml(context);
101
+ expect(result).toBe(
102
+ '<metric count="42" percentage="85.5" isActive="true"></metric>',
103
+ );
104
+ });
105
+
106
+ it("should handle complex nested data", () => {
107
+ const context = {
108
+ type: "complex",
109
+ data: {
110
+ name: "test",
111
+ config: JSON.stringify({ key: "value", nested: { prop: "test" } }),
112
+ },
113
+ details: "Complex configuration data",
114
+ };
115
+
116
+ const result = contextToXml(context);
117
+ expect(result).toMatchInlineSnapshot(
118
+ `"<complex name="test" config="{"key":"value","nested":{"prop":"test"}}">Complex configuration data</complex>"`,
119
+ );
120
+ });
121
+
122
+ it("should handle boolean values", () => {
123
+ const context = {
124
+ type: "flags",
125
+ data: {
126
+ enabled: true,
127
+ visible: false,
128
+ },
129
+ };
130
+
131
+ const result = contextToXml(context);
132
+ expect(result).toBe('<flags enabled="true" visible="false"></flags>');
133
+ });
134
+
135
+ it("should handle null values", () => {
136
+ const context = {
137
+ type: "nullable",
138
+ data: {
139
+ name: "test",
140
+ value: null,
141
+ },
142
+ };
143
+
144
+ const result = contextToXml(context);
145
+ expect(result).toBe('<nullable name="test" value="null"></nullable>');
146
+ });
147
+
148
+ it("should handle multiline details", () => {
149
+ const context = {
150
+ type: "multiline",
151
+ data: {
152
+ name: "test",
153
+ },
154
+ details: "Line 1\nLine 2\nLine 3",
155
+ };
156
+
157
+ const result = contextToXml(context);
158
+ expect(result).toBe(
159
+ '<multiline name="test">Line 1\nLine 2\nLine 3</multiline>',
160
+ );
161
+ });
162
+
163
+ it("should handle special characters in type name", () => {
164
+ const context = {
165
+ type: "data-source",
166
+ data: {
167
+ name: "test",
168
+ },
169
+ };
170
+
171
+ const result = contextToXml(context);
172
+ expect(result).toBe('<data-source name="test"></data-source>');
173
+ });
174
+ });
@@ -3,6 +3,7 @@
3
3
  import { allTablesAtom } from "@/core/datasets/data-source-connections";
4
4
  import type { JotaiStore } from "@/core/state/jotai";
5
5
  import { variablesAtom } from "@/core/variables/state";
6
+ import { ErrorContextProvider } from "./providers/error";
6
7
  import { TableContextProvider } from "./providers/tables";
7
8
  import { VariableContextProvider } from "./providers/variable";
8
9
  import { AIContextRegistry } from "./registry";
@@ -12,5 +13,6 @@ export function getAIContextRegistry(store: JotaiStore) {
12
13
  const variables = store.get(variablesAtom);
13
14
  return new AIContextRegistry()
14
15
  .register(new TableContextProvider(tablesMap))
15
- .register(new VariableContextProvider(variables, tablesMap));
16
+ .register(new VariableContextProvider(variables, tablesMap))
17
+ .register(new ErrorContextProvider(store));
16
18
  }
@@ -0,0 +1,3 @@
1
+ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
+
3
+ exports[`ErrorContextProvider > formatContext > should format context for basic errors > basic-error-context 1`] = `"<error name="Cell 1" description="Invalid syntax"></error>"`;
@@ -1,38 +1,34 @@
1
1
  // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
2
 
3
3
  exports[`TableContextProvider > formatContext > should format context for basic table > basic-table-context 1`] = `
4
- "Table: products
5
- Source: memory
4
+ "<data name="products" source="memory">
6
5
  Shape: 100 rows, 3 columns
7
6
  Columns:
8
7
  - id: integer
9
8
  - name: string
10
- - active: boolean"
9
+ - active: boolean</data>"
11
10
  `;
12
11
 
13
12
  exports[`TableContextProvider > formatContext > should format context for remote database table > remote-table-context 1`] = `
14
- "Table: remote_table
15
- Source: postgresql://localhost:5432/mydb
13
+ "<data name="remote_table" source="postgresql://localhost:5432/mydb">
16
14
  Shape: 100 rows, 3 columns
17
15
  Columns:
18
16
  - uuid: string
19
17
  - created_at: string
20
- - metadata: string"
18
+ - metadata: string</data>"
21
19
  `;
22
20
 
23
21
  exports[`TableContextProvider > formatContext > should format context for table without columns > no-columns-table-context 1`] = `
24
- "Table: no_columns
25
- Source: memory
26
- Shape: 100 rows, 3 columns"
22
+ "<data name="no_columns" source="memory">
23
+ Shape: 100 rows, 3 columns</data>"
27
24
  `;
28
25
 
29
26
  exports[`TableContextProvider > formatContext > should format context for table without shape info > no-shape-table-context 1`] = `
30
- "Table: no_shape
31
- Source: memory
27
+ "<data name="no_shape" source="memory">
32
28
  Columns:
33
29
  - id: integer
34
30
  - name: string
35
- - active: boolean"
31
+ - active: boolean</data>"
36
32
  `;
37
33
 
38
34
  exports[`TableContextProvider > getItems > should handle dataframe tables with variable names > dataframe-table 1`] = `
@@ -1,28 +1,12 @@
1
1
  // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
2
 
3
- exports[`VariableContextProvider > formatContext > should format context for basic variable > basic-variable-context 1`] = `
4
- "Variable: username
5
- Type: str
6
- Preview: "\\"alice\\"""
7
- `;
3
+ exports[`VariableContextProvider > formatContext > should format context for basic variable > basic-variable-context 1`] = `"<variable name="username" dataType="str">"\\"alice\\""</variable>"`;
8
4
 
9
- exports[`VariableContextProvider > formatContext > should format context for dataframe variable > dataframe-variable-context 1`] = `
10
- "Variable: sales_df
11
- Type: pandas.DataFrame
12
- Preview: "<DataFrame shape: (1000, 8)>\\n date product quantity price\\n0 2023-01-01 Widget A 10 29.99\\n1 2023-01-02 Widget B 5 49.99\\n...""
13
- `;
5
+ exports[`VariableContextProvider > formatContext > should format context for dataframe variable > dataframe-variable-context 1`] = `"<variable name="sales_df" dataType="pandas.DataFrame">"&lt;DataFrame shape: (1000, 8)&gt;\\n date product quantity price\\n0 2023-01-01 Widget A 10 29.99\\n1 2023-01-02 Widget B 5 49.99\\n..."</variable>"`;
14
6
 
15
- exports[`VariableContextProvider > formatContext > should format context for variable with complex value > complex-value-variable-context 1`] = `
16
- "Variable: complex_data
17
- Type: dict
18
- Preview: "{\\"users\\": [{\\"id\\": 1, \\"name\\": \\"Alice\\"}, {\\"id\\": 2, \\"name\\": \\"Bob\\"}], \\"total\\": 2}""
19
- `;
7
+ exports[`VariableContextProvider > formatContext > should format context for variable with complex value > complex-value-variable-context 1`] = `"<variable name="complex_data" dataType="dict">"{\\"users\\": [{\\"id\\": 1, \\"name\\": \\"Alice\\"}, {\\"id\\": 2, \\"name\\": \\"Bob\\"}], \\"total\\": 2}"</variable>"`;
20
8
 
21
- exports[`VariableContextProvider > formatContext > should format context for variable without dataType > no-datatype-variable-context 1`] = `
22
- "Variable: mystery_var
23
- Type: unknown
24
- Preview: "some_value""
25
- `;
9
+ exports[`VariableContextProvider > formatContext > should format context for variable without dataType > no-datatype-variable-context 1`] = `"<variable name="mystery_var" dataType="null">"some_value"</variable>"`;
26
10
 
27
11
  exports[`VariableContextProvider > getItems > should handle complex data types > complex-data-types 1`] = `
28
12
  [