@marimo-team/frontend 0.15.4 → 0.16.0-dev96986

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 (325) hide show
  1. package/dist/assets/ConnectedDataExplorerComponent-CNLoZkWr.js +19 -0
  2. package/dist/assets/{ImageComparisonComponent-CEXMKKA4.js → ImageComparisonComponent-SX7fDaTK.js} +1 -1
  3. package/dist/assets/{VegaLite-Bt14Ds9k.js → VegaLite-MJUW3b7C.js} +6 -6
  4. package/dist/assets/_baseEach-9_logFrf.js +1 -0
  5. package/dist/assets/_baseMap-NzEbKt5c.js +1 -0
  6. package/dist/assets/_baseUniq-C5LFcyNC.js +1 -0
  7. package/dist/assets/_createAggregator-ZRm2b6Zm.js +1 -0
  8. package/dist/assets/agent-panel-BBd11wNX.js +287 -0
  9. package/dist/assets/agent-panel-D92Mfy1i.css +1 -0
  10. package/dist/assets/{any-language-editor-DiwNT6zp.js → any-language-editor-DwAaEQfS.js} +1 -1
  11. package/dist/assets/architectureDiagram-W76B3OCA-BJmVXUoW.js +36 -0
  12. package/dist/assets/{between-horizontal-start-FyewyCGn.js → between-horizontal-start-KiwU-a3C.js} +1 -1
  13. package/dist/assets/{blockDiagram-QIGZ2CNN-BrOkAf_c.js → blockDiagram-QIGZ2CNN-DzxZjE7B.js} +1 -1
  14. package/dist/assets/{c4Diagram-FPNF74CW-BHPzDxE2.js → c4Diagram-FPNF74CW-DjmldG_J.js} +5 -5
  15. package/dist/assets/channel-DHcKBVM4.js +1 -0
  16. package/dist/assets/chat-panel-DgJZr0eS.js +3 -0
  17. package/dist/assets/{chunk-4BX2VUAB-DLxaCNYh.js → chunk-4BX2VUAB-EUTQThiZ.js} +1 -1
  18. package/dist/assets/{chunk-55IACEB6-DdzvO3HR.js → chunk-55IACEB6-DZAiDJxy.js} +1 -1
  19. package/dist/assets/{chunk-FMBD7UC4-R5o-nSiG.js → chunk-FMBD7UC4-Bd0Czs-J.js} +1 -1
  20. package/dist/assets/{chunk-K7UQS3LO-DxaMrGgG.js → chunk-K7UQS3LO-DEKMIknX.js} +1 -1
  21. package/dist/assets/{chunk-QN33PNHL-DqS9-FYm.js → chunk-QN33PNHL-E0jwHU_n.js} +1 -1
  22. package/dist/assets/{chunk-QZHKN3VN-BZ-TzajS.js → chunk-QZHKN3VN-BzaIHJbq.js} +1 -1
  23. package/dist/assets/{chunk-TVAH2DTR-BsgP2dyv.js → chunk-TVAH2DTR-CZFYvqnm.js} +1 -1
  24. package/dist/assets/{chunk-TZMSLE5B-D-h3ahXI.js → chunk-TZMSLE5B-BNqnFjtv.js} +1 -1
  25. package/dist/assets/{circle-play-CQtRZ-rT.js → circle-play-D3J_mYrF.js} +1 -1
  26. package/dist/assets/classDiagram-KNZD7YFC-D-xwLnlX.js +1 -0
  27. package/dist/assets/classDiagram-v2-RKCZMP56-D-xwLnlX.js +1 -0
  28. package/dist/assets/{clear-button-BY6Z_ViL.js → clear-button-ifzRuAR3.js} +1 -1
  29. package/dist/assets/clone-CSxIll62.js +1 -0
  30. package/dist/assets/command-palette-D2fdVSET.js +1 -0
  31. package/dist/assets/common-Ku-cF_2J.js +1 -0
  32. package/dist/assets/{compile-Ct_jzdKr.js → compile-BgZlHW1c.js} +1 -1
  33. package/dist/assets/cose-bilkent-S5V4N54A-CVM83SqK.js +1 -0
  34. package/dist/assets/dagre-5GWH7T2D-ouQPkxT3.js +4 -0
  35. package/dist/assets/{data-grid-overlay-editor-BN_wulc3.js → data-grid-overlay-editor-B47j5GJJ.js} +1 -1
  36. package/dist/assets/datasources-panel-Bt41Zir-.js +1 -0
  37. package/dist/assets/{dependency-graph-panel-BOmSCZf7.js → dependency-graph-panel-CZC_B7pK.js} +4 -4
  38. package/dist/assets/diagram-N5W7TBWH-CQ817ZdR.js +24 -0
  39. package/dist/assets/diagram-QEK2KX5R-DOK_psUO.js +43 -0
  40. package/dist/assets/diagram-S2PKOQOG-CVljmOW8.js +24 -0
  41. package/dist/assets/{documentation-panel-BxjJO_Gw.js → documentation-panel-C7yIvGg1.js} +1 -1
  42. package/dist/assets/edit-page-CyTMQV2u.js +129 -0
  43. package/dist/assets/{ellipsis-vertical-UHbmjI2n.js → ellipsis-vertical-C7FjlUsY.js} +1 -1
  44. package/dist/assets/{empty-state-BIBXzY_0.js → empty-state-DIOGM_CU.js} +1 -1
  45. package/dist/assets/{erDiagram-AWTI2OKA-E84mAle_.js → erDiagram-AWTI2OKA-DYu8cEdc.js} +1 -1
  46. package/dist/assets/{error-panel-MEvQ6K7h.js → error-panel-Ddb8RkFG.js} +1 -1
  47. package/dist/assets/file-explorer-panel-Oy9DbyFP.js +1 -0
  48. package/dist/assets/{flowDiagram-PVAE7QVJ-DfbIRSAW.js → flowDiagram-PVAE7QVJ-CmvW5iTb.js} +1 -1
  49. package/dist/assets/{ganttDiagram-OWAHRB6G-DR4HZ1z_.js → ganttDiagram-OWAHRB6G-BaKQlCaT.js} +4 -4
  50. package/dist/assets/gitGraphDiagram-NY62KEGX-CWO24eP6.js +65 -0
  51. package/dist/assets/{glide-data-editor-nNmo1lPq.js → glide-data-editor-CNDLEJ9a.js} +11 -11
  52. package/dist/assets/graph-BZKTtxsc.js +1 -0
  53. package/dist/assets/home-page-Bvwppn9N.js +9 -0
  54. package/dist/assets/{index-VPWqq2Pg.js → index-0XOUPdwT.js} +1 -1
  55. package/dist/assets/{index-uacyUula.js → index-BH7f3aiU.js} +1 -1
  56. package/dist/assets/{index-Dt9UWeWn.js → index-BJVyzkx5.js} +1 -1
  57. package/dist/assets/{index-BAH034Ue.js → index-B_d_JZGI.js} +1 -1
  58. package/dist/assets/{index-CB2pnVQG.js → index-BgXbBA39.js} +1 -1
  59. package/dist/assets/{index-B8llrTSo.js → index-Brf2DwUM.js} +1 -1
  60. package/dist/assets/{index-BLu5CX6z.js → index-CXrWwFX6.js} +1 -1
  61. package/dist/assets/{index-DyLSuOH1.js → index-CZaurnA9.js} +1 -1
  62. package/dist/assets/{index-BFSnz7iM.js → index-CerjupfZ.js} +1 -1
  63. package/dist/assets/{index-B7yXbrLa.js → index-D-tZfElD.js} +1 -1
  64. package/dist/assets/{index-c6If577Q.js → index-D3PqGupX.js} +1 -1
  65. package/dist/assets/{index-CSgxTUzD.js → index-DCkzth56.js} +1 -1
  66. package/dist/assets/{index-DWOaniGT.js → index-DFrGFNW1.js} +1 -1
  67. package/dist/assets/{index-CPN7TRA1.js → index-DZhOPkOB.js} +1 -1
  68. package/dist/assets/index-DadI618h.css +1 -0
  69. package/dist/assets/{index-DqzMPAC8.js → index-DkntzpX4.js} +2 -2
  70. package/dist/assets/{index-B1_GXGaP.js → index-DmgwT3sx.js} +1 -1
  71. package/dist/assets/index-PmY0x4Zd.js +578 -0
  72. package/dist/assets/{index-Bq516OmX.js → index-WXJFkQHg.js} +1 -1
  73. package/dist/assets/{index-DSU75csX.js → index-qE8lHQ-N.js} +1 -1
  74. package/dist/assets/{index-DMomwMcN.js → index-zrSUQXha.js} +1 -1
  75. package/dist/assets/infoDiagram-STP46IZ2-CAuVVehw.js +2 -0
  76. package/dist/assets/isEmpty-D1t7Gran.js +1 -0
  77. package/dist/assets/{journeyDiagram-BIP6EPQ6-BBiFyygf.js → journeyDiagram-BIP6EPQ6-D4Rp6H_h.js} +1 -1
  78. package/dist/assets/{kanban-definition-6OIFK2YF-DhgA6Nt6.js → kanban-definition-6OIFK2YF-DFt9DftA.js} +4 -4
  79. package/dist/assets/layout-D8WXi2_g.js +1 -0
  80. package/dist/assets/linear-BwY8e5hA.js +1 -0
  81. package/dist/assets/links-4B6ldZ5P.js +7 -0
  82. package/dist/assets/{logs-panel-B9SmTZAW.js → logs-panel-Dxiyt7dO.js} +1 -1
  83. package/dist/assets/{agent-panel-DpQ6muj-.css → markdown-renderer-ClyzDMmG.css} +1 -1
  84. package/dist/assets/markdown-renderer-VDu-NBKB.js +263 -0
  85. package/dist/assets/mermaid-B-O-Puyi.js +1 -0
  86. package/dist/assets/{mermaid.core-4nVOEVX3.js → mermaid.core-BFFCqfOn.js} +41 -41
  87. package/dist/assets/min-DtVSfYKl.js +1 -0
  88. package/dist/assets/{mindmap-definition-Q6HEUPPD-CVLQNn1q.js → mindmap-definition-Q6HEUPPD-kyvIY8Dg.js} +2 -2
  89. package/dist/assets/{number-overlay-editor-CzRzXLcd.js → number-overlay-editor-GjLB2UK4.js} +1 -1
  90. package/dist/assets/outline-panel-CMJjOoN7.js +1 -0
  91. package/dist/assets/packages-panel-nfXB-bKW.js +1 -0
  92. package/dist/assets/{pieDiagram-ADFJNKIX-C5IQ5DBZ.js → pieDiagram-ADFJNKIX-D8JFQcWR.js} +3 -3
  93. package/dist/assets/{quadrantDiagram-LMRXKWRM-CFXFnQxx.js → quadrantDiagram-LMRXKWRM-Nf8GzxXG.js} +1 -1
  94. package/dist/assets/{react-plotly-mzdv02_Y.js → react-plotly-CnW9p7ZA.js} +1 -1
  95. package/dist/assets/{requirementDiagram-4UW4RH46-D9bPC89T.js → requirementDiagram-4UW4RH46-CCUxF8BZ.js} +1 -1
  96. package/dist/assets/run-page-Bl4p3AbZ.js +1 -0
  97. package/dist/assets/sankeyDiagram-GR3RE2ED-Sr8kDwP1.js +10 -0
  98. package/dist/assets/scratchpad-panel-Ja1Mu-W3.js +1 -0
  99. package/dist/assets/secrets-panel-B-3fcSyP.js +1 -0
  100. package/dist/assets/{sequenceDiagram-C3RYC4MD-6N7_hY4k.js → sequenceDiagram-C3RYC4MD-CBJ152Q3.js} +4 -4
  101. package/dist/assets/{slides-component-DMjQomc3.css → slides-component-C-LoGC1U.css} +1 -1
  102. package/dist/assets/{slides-component-EcjC8sDK.js → slides-component-DGtsVP5o.js} +1 -1
  103. package/dist/assets/snippets-panel-ClNnwKBM.js +1 -0
  104. package/dist/assets/sortBy-D47H6Vyl.js +1 -0
  105. package/dist/assets/state-B_RCHTH5.js +1 -0
  106. package/dist/assets/stateDiagram-KXAO66HF-BlBFSAZr.js +1 -0
  107. package/dist/assets/stateDiagram-v2-UMBNRL4Z-DbA-iToo.js +1 -0
  108. package/dist/assets/storage-BNcWOH3-.js +26 -0
  109. package/dist/assets/terminal-CATzv5Hd.js +10 -0
  110. package/dist/assets/time-CsYqILfB.js +1 -0
  111. package/dist/assets/{timeline-definition-XQNQX7LJ-BEaynAiY.js → timeline-definition-XQNQX7LJ-CGrhjuAs.js} +1 -1
  112. package/dist/assets/tracing-DUbJtOyq.js +2 -0
  113. package/dist/assets/{tracing-panel-BmuHLPrY.js → tracing-panel-DmzqPUtc.js} +2 -2
  114. package/dist/assets/{trash-UBqfK4mR.js → trash-rxdjLzkf.js} +1 -1
  115. package/dist/assets/{tree-XiEycetl.js → tree-C2Ul1h1C.js} +1 -1
  116. package/dist/assets/{treemap-75Q7IDZK-CnuVFbBG.js → treemap-75Q7IDZK-N9hyUpyj.js} +20 -20
  117. package/dist/assets/{ts-tags-CloPe9IY.js → ts-tags-DxCDHihD.js} +1 -1
  118. package/dist/assets/variable-panel-BbgupOdG.js +1 -0
  119. package/dist/assets/{vega-component-DsTH4tuX.js → vega-component-CR_MHOBT.js} +1 -1
  120. package/dist/assets/worker-fHbtoWvT.js +1 -0
  121. package/dist/assets/{xychartDiagram-6GGTOJPD-Dcz3O-A3.js → xychartDiagram-6GGTOJPD-jdLZsMb2.js} +1 -1
  122. package/dist/index.html +2 -2
  123. package/package.json +10 -5
  124. package/src/__tests__/mocks.ts +43 -0
  125. package/src/components/app-config/user-config-form.tsx +78 -1
  126. package/src/components/chat/acp/__tests__/__snapshots__/prompt.test.ts.snap +116 -65
  127. package/src/components/chat/acp/__tests__/atoms.test.ts +1 -1
  128. package/src/components/chat/acp/__tests__/context-utils.test.ts +222 -0
  129. package/src/components/chat/acp/__tests__/prompt.test.ts +1 -1
  130. package/src/components/chat/acp/__tests__/state.test.ts +38 -42
  131. package/src/components/chat/acp/agent-docs.tsx +33 -6
  132. package/src/components/chat/acp/agent-panel.css +0 -18
  133. package/src/components/chat/acp/agent-panel.tsx +394 -72
  134. package/src/components/chat/acp/agent-selector.tsx +7 -1
  135. package/src/components/chat/acp/blocks.tsx +40 -10
  136. package/src/components/chat/acp/common.tsx +10 -2
  137. package/src/components/chat/acp/context-utils.ts +127 -0
  138. package/src/components/chat/acp/prompt.ts +96 -53
  139. package/src/components/chat/acp/state.ts +1 -1
  140. package/src/components/chat/acp/types.ts +8 -0
  141. package/src/components/chat/chat-panel.tsx +28 -89
  142. package/src/components/chat/chat-utils.ts +127 -1
  143. package/src/components/chat/markdown-renderer.css +39 -0
  144. package/src/components/chat/markdown-renderer.tsx +12 -47
  145. package/src/components/chat/tool-call-accordion.tsx +148 -26
  146. package/src/components/data-table/SearchBar.tsx +8 -7
  147. package/src/components/data-table/__tests__/column_formatting.test.ts +50 -35
  148. package/src/components/data-table/__tests__/data-table.test.tsx +39 -1
  149. package/src/components/data-table/cell-hover-template/feature.ts +14 -0
  150. package/src/components/data-table/cell-hover-template/types.ts +11 -0
  151. package/src/components/data-table/charts/components/form-fields.tsx +41 -37
  152. package/src/components/data-table/charts/forms/common-chart.tsx +2 -2
  153. package/src/components/data-table/column-explorer-panel/column-explorer.tsx +5 -2
  154. package/src/components/data-table/column-formatting/feature.ts +62 -29
  155. package/src/components/data-table/column-formatting/types.ts +1 -0
  156. package/src/components/data-table/column-header.tsx +3 -1
  157. package/src/components/data-table/column-summary/chart-spec-model.tsx +24 -7
  158. package/src/components/data-table/column-summary/column-summary.tsx +18 -9
  159. package/src/components/data-table/columns.tsx +42 -18
  160. package/src/components/data-table/data-table.tsx +10 -2
  161. package/src/components/data-table/date-popover.tsx +85 -75
  162. package/src/components/data-table/filter-pills.tsx +14 -9
  163. package/src/components/data-table/header-items.tsx +5 -1
  164. package/src/components/data-table/pagination.tsx +20 -13
  165. package/src/components/data-table/renderers.tsx +28 -0
  166. package/src/components/data-table/row-viewer-panel/row-viewer.tsx +10 -8
  167. package/src/components/datasources/column-preview.tsx +6 -2
  168. package/src/components/datasources/datasources.tsx +8 -12
  169. package/src/components/editor/Cell.tsx +6 -0
  170. package/src/components/editor/actions/name-cell-input.tsx +6 -1
  171. package/src/components/editor/actions/useCellActionButton.tsx +3 -1
  172. package/src/components/editor/ai/__tests__/completion-utils.test.ts +178 -1
  173. package/src/components/editor/ai/add-cell-with-ai.tsx +68 -66
  174. package/src/components/editor/ai/ai-completion-editor.tsx +29 -26
  175. package/src/components/editor/ai/completion-handlers.tsx +44 -6
  176. package/src/components/editor/ai/completion-utils.ts +92 -0
  177. package/src/components/editor/ai/transport/chat-transport.tsx +39 -0
  178. package/src/components/editor/cell/CellStatus.tsx +23 -20
  179. package/src/components/editor/cell/CreateCellButton.tsx +3 -4
  180. package/src/components/editor/cell/StagedAICell.tsx +51 -0
  181. package/src/components/editor/cell/cell-actions.tsx +2 -1
  182. package/src/components/editor/cell/code/language-toggle.tsx +3 -4
  183. package/src/components/editor/chrome/wrapper/footer-items/machine-stats.tsx +39 -28
  184. package/src/components/editor/controls/notebook-menu-dropdown.tsx +4 -2
  185. package/src/components/editor/file-tree/requesting-tree.tsx +14 -8
  186. package/src/components/editor/renderers/CellArray.tsx +3 -4
  187. package/src/components/editor/renderers/slides-layout/slides-layout.tsx +3 -3
  188. package/src/components/editor/renderers/slides-layout/types.ts +1 -0
  189. package/src/components/pages/home-page.tsx +4 -1
  190. package/src/components/slides/slides-component.tsx +1 -1
  191. package/src/components/slides/slides.css +6 -0
  192. package/src/components/terminal/__tests__/state.test.ts +207 -0
  193. package/src/components/terminal/hooks.ts +41 -0
  194. package/src/components/terminal/state.ts +75 -0
  195. package/src/components/terminal/terminal.tsx +334 -13
  196. package/src/components/terminal/theme.tsx +57 -0
  197. package/src/components/tracing/tracing-spec.ts +5 -4
  198. package/src/components/ui/range-slider.tsx +4 -2
  199. package/src/components/ui/slider.tsx +3 -1
  200. package/src/components/variables/variables-table.tsx +3 -0
  201. package/src/core/MarimoApp.tsx +9 -6
  202. package/src/core/ai/__tests__/staged-cells.test.ts +356 -0
  203. package/src/core/ai/context/__tests__/registry.test.ts +6 -4
  204. package/src/core/ai/context/providers/cell-output.ts +3 -2
  205. package/src/core/ai/context/providers/error.ts +3 -1
  206. package/src/core/ai/context/providers/file.ts +7 -2
  207. package/src/core/ai/context/providers/tables.ts +3 -2
  208. package/src/core/ai/context/providers/variable.ts +6 -4
  209. package/src/core/ai/staged-cells.ts +208 -0
  210. package/src/core/cells/cells.ts +1 -1
  211. package/src/core/cells/logs.ts +1 -1
  212. package/src/core/codemirror/find-replace/search-highlight.ts +3 -1
  213. package/src/core/codemirror/language/LanguageAdapters.ts +9 -3
  214. package/src/core/codemirror/lsp/federated-lsp.ts +1 -1
  215. package/src/core/codemirror/lsp/notebook-lsp.ts +8 -2
  216. package/src/core/codemirror/readonly/__tests__/extension.test.ts +1 -1
  217. package/src/core/codemirror/rtc/loro/awareness.ts +52 -17
  218. package/src/core/codemirror/rtc/loro/sync.ts +12 -4
  219. package/src/core/config/config-schema.ts +1 -0
  220. package/src/core/config/config.ts +4 -0
  221. package/src/core/hotkeys/hotkeys.ts +8 -4
  222. package/src/core/i18n/__tests__/locale-provider.test.tsx +176 -0
  223. package/src/core/i18n/locale-provider.tsx +35 -0
  224. package/src/core/i18n/with-locale.tsx +12 -0
  225. package/src/core/islands/components/web-components.tsx +13 -10
  226. package/src/core/islands/main.ts +2 -2
  227. package/src/core/kernel/RuntimeState.ts +4 -1
  228. package/src/core/kernel/messages.ts +8 -12
  229. package/src/core/network/DeferredRequestRegistry.ts +16 -4
  230. package/src/core/runtime/runtime.ts +5 -4
  231. package/src/core/saving/__tests__/filename.test.ts +37 -0
  232. package/src/core/static/__tests__/download-html.test.ts +43 -1
  233. package/src/core/wasm/bridge.ts +5 -1
  234. package/src/core/wasm/store.ts +4 -1
  235. package/src/core/wasm/worker/message-buffer.ts +3 -2
  236. package/src/core/websocket/types.ts +22 -16
  237. package/src/core/websocket/useMarimoWebSocket.tsx +2 -2
  238. package/src/css/app/Cell.css +11 -0
  239. package/src/hooks/useFormatting.ts +97 -0
  240. package/src/hooks/useTimer.ts +8 -5
  241. package/src/plugins/core/RenderHTML.tsx +36 -2
  242. package/src/plugins/core/__test__/RenderHTML.test.ts +72 -0
  243. package/src/plugins/core/registerReactComponent.tsx +44 -10
  244. package/src/plugins/impl/DataTablePlugin.tsx +4 -0
  245. package/src/plugins/impl/FileBrowserPlugin.tsx +8 -2
  246. package/src/plugins/impl/RangeSliderPlugin.tsx +5 -3
  247. package/src/plugins/impl/SliderPlugin.tsx +3 -1
  248. package/src/plugins/impl/anywidget/model.ts +16 -5
  249. package/src/plugins/impl/data-editor/types.ts +7 -5
  250. package/src/plugins/impl/data-explorer/components/column-summary.tsx +20 -13
  251. package/src/plugins/impl/panel/utils.ts +6 -4
  252. package/src/plugins/layout/OutlinePlugin.tsx +69 -0
  253. package/src/plugins/layout/StatPlugin.tsx +4 -1
  254. package/src/plugins/plugins.ts +2 -0
  255. package/src/stories/cell.stories.tsx +1 -1
  256. package/src/stories/layout/vertical/one-column.stories.tsx +1 -1
  257. package/src/utils/__tests__/cell-urls.test.ts +29 -0
  258. package/src/utils/__tests__/dates.test.ts +45 -24
  259. package/src/utils/__tests__/filenames.test.ts +18 -0
  260. package/src/utils/__tests__/numbers.test.ts +42 -30
  261. package/src/utils/__tests__/once.test.ts +187 -0
  262. package/src/utils/__tests__/path.test.ts +38 -0
  263. package/src/utils/__tests__/urls.test.ts +56 -1
  264. package/src/utils/dates.ts +15 -10
  265. package/src/utils/edit-distance.ts +8 -6
  266. package/src/utils/errors.ts +9 -0
  267. package/src/utils/id-tree.tsx +21 -10
  268. package/src/utils/localStorage.ts +13 -4
  269. package/src/utils/numbers.ts +11 -11
  270. package/src/utils/once.ts +32 -0
  271. package/src/utils/paths.ts +4 -1
  272. package/src/utils/pluralize.ts +12 -5
  273. package/src/utils/python-poet/poet.ts +30 -15
  274. package/src/utils/time.ts +5 -1
  275. package/dist/assets/ConnectedDataExplorerComponent-Cn5-l2X1.js +0 -19
  276. package/dist/assets/_baseEach-C1FLm7WW.js +0 -1
  277. package/dist/assets/_baseMap-DBVArUYD.js +0 -1
  278. package/dist/assets/_baseUniq-Dk7ZPJ3N.js +0 -1
  279. package/dist/assets/_createAggregator-Bn38fDd3.js +0 -1
  280. package/dist/assets/agent-panel-COUYnuIK.js +0 -475
  281. package/dist/assets/architectureDiagram-W76B3OCA-DBzWQKKu.js +0 -36
  282. package/dist/assets/channel-CjhbjOv4.js +0 -1
  283. package/dist/assets/chat-panel-BPXKoTnZ.js +0 -7
  284. package/dist/assets/chat-panel-Brrs_eeH.css +0 -1
  285. package/dist/assets/classDiagram-KNZD7YFC-DHs5cFzy.js +0 -1
  286. package/dist/assets/classDiagram-v2-RKCZMP56-DHs5cFzy.js +0 -1
  287. package/dist/assets/clone-DM1YNjEn.js +0 -1
  288. package/dist/assets/command-palette-S0bzQp7v.js +0 -1
  289. package/dist/assets/common-B8U9k2Ly.js +0 -1
  290. package/dist/assets/cose-bilkent-S5V4N54A-wz1Sfx7j.js +0 -1
  291. package/dist/assets/dagre-5GWH7T2D-BfpcVBgq.js +0 -4
  292. package/dist/assets/datasources-panel-DfuURLJw.js +0 -1
  293. package/dist/assets/diagram-N5W7TBWH-Bf0oqqQh.js +0 -24
  294. package/dist/assets/diagram-QEK2KX5R-ZTc3qikh.js +0 -43
  295. package/dist/assets/diagram-S2PKOQOG-tLScBy7Z.js +0 -24
  296. package/dist/assets/edit-page-DJ8kJZ9w.js +0 -129
  297. package/dist/assets/file-explorer-panel-CzNUJ63G.js +0 -1
  298. package/dist/assets/gitGraphDiagram-NY62KEGX-C1t6QtVa.js +0 -65
  299. package/dist/assets/graph-CssCVWIq.js +0 -1
  300. package/dist/assets/home-page-9eW6qida.js +0 -9
  301. package/dist/assets/index-CknhX2Vy.css +0 -1
  302. package/dist/assets/index-DcCIe7np.js +0 -28
  303. package/dist/assets/index-OC46250R.js +0 -570
  304. package/dist/assets/infoDiagram-STP46IZ2-CwiAoz9f.js +0 -2
  305. package/dist/assets/layout-DpQrxGW-.js +0 -1
  306. package/dist/assets/linear-NsreOeBF.js +0 -1
  307. package/dist/assets/links-CbvGxbsJ.js +0 -7
  308. package/dist/assets/mermaid-DSt0r6IQ.js +0 -1
  309. package/dist/assets/min-D259kI3t.js +0 -1
  310. package/dist/assets/outline-panel-uvsS-YEQ.js +0 -1
  311. package/dist/assets/packages-panel-xMz9W2hW.js +0 -1
  312. package/dist/assets/run-page-Bb68qdhQ.js +0 -1
  313. package/dist/assets/sankeyDiagram-GR3RE2ED-BSJOau8E.js +0 -10
  314. package/dist/assets/scratchpad-panel-BF4BO-U4.js +0 -1
  315. package/dist/assets/secrets-panel-CdIX44dQ.js +0 -1
  316. package/dist/assets/snippets-panel-Dco9h0rb.js +0 -1
  317. package/dist/assets/sortBy-aLGA-PGK.js +0 -1
  318. package/dist/assets/stateDiagram-KXAO66HF-Bd68WT3b.js +0 -1
  319. package/dist/assets/stateDiagram-v2-UMBNRL4Z-BXz_GSwb.js +0 -1
  320. package/dist/assets/storage-CGlP4lCF.js +0 -26
  321. package/dist/assets/terminal-CxkHubcu.js +0 -9
  322. package/dist/assets/time-D2nr1UgQ.js +0 -1
  323. package/dist/assets/tracing-kTqHxa7q.js +0 -2
  324. package/dist/assets/variable-panel-noTnH-AQ.js +0 -1
  325. package/dist/assets/worker-X5rxzQGQ.js +0 -1
@@ -8,7 +8,7 @@ import type { DatasetsState } from "@/core/datasets/types";
8
8
  import { store } from "@/core/state/jotai";
9
9
  import { variablesAtom } from "@/core/variables/state";
10
10
  import type { Variable, VariableName } from "@/core/variables/types";
11
- import { getAICompletionBody } from "../completion-utils";
11
+ import { codeToCells, getAICompletionBody } from "../completion-utils";
12
12
 
13
13
  // Mock getCodes function
14
14
  vi.mock("@/core/codemirror/copilot/getCodes", () => ({
@@ -357,3 +357,180 @@ describe("getAICompletionBody", () => {
357
357
  `);
358
358
  });
359
359
  });
360
+
361
+ describe("codeToCells", () => {
362
+ it("should return empty array for empty string", () => {
363
+ const code = "";
364
+ const result = codeToCells(code);
365
+ expect(result).toEqual([]);
366
+ });
367
+
368
+ it("should return empty array for whitespace only", () => {
369
+ const code = " \n\t ";
370
+ const result = codeToCells(code);
371
+ expect(result).toEqual([]);
372
+ });
373
+
374
+ it("should convert code without backticks to single python cell", () => {
375
+ const code = "print('Hello, world!')";
376
+ const result = codeToCells(code);
377
+ expect(result).toEqual([
378
+ { language: "python", code: "print('Hello, world!')" },
379
+ ]);
380
+ });
381
+
382
+ it("should convert code with single closed backticks to cells", () => {
383
+ const code = "```python\nprint('Hello, world!')\n```";
384
+ const result = codeToCells(code);
385
+ expect(result).toEqual([
386
+ { language: "python", code: "print('Hello, world!')" },
387
+ ]);
388
+ });
389
+
390
+ it("should convert code with unclosed backticks to cells", () => {
391
+ const code = "```python\nprint('Hello, world!')\n";
392
+ const result = codeToCells(code);
393
+ expect(result).toEqual([
394
+ { language: "python", code: "print('Hello, world!')" },
395
+ ]);
396
+ });
397
+
398
+ it("should convert code with multiple closed cells", () => {
399
+ const code =
400
+ "```python\nprint('Hello, world!')\n```\n```sql\nSELECT * FROM users\n```";
401
+ const result = codeToCells(code);
402
+ expect(result).toEqual([
403
+ { language: "python", code: "print('Hello, world!')" },
404
+ { language: "sql", code: "SELECT * FROM users" },
405
+ ]);
406
+ });
407
+
408
+ it("should handle code with no language identifier", () => {
409
+ const code = "```\nprint('Hello, world!')\n```";
410
+ const result = codeToCells(code);
411
+ expect(result).toEqual([
412
+ { language: "python", code: "print('Hello, world!')" },
413
+ ]);
414
+ });
415
+
416
+ it("should handle unclosed code with no language identifier", () => {
417
+ const code = "```\nprint('Hello, world!')\n";
418
+ const result = codeToCells(code);
419
+ expect(result).toEqual([
420
+ { language: "python", code: "print('Hello, world!')" },
421
+ ]);
422
+ });
423
+
424
+ it("should handle markdown language", () => {
425
+ const code = "```markdown\n# Hello, world!\n```";
426
+ const result = codeToCells(code);
427
+ expect(result).toEqual([{ language: "markdown", code: "# Hello, world!" }]);
428
+ });
429
+
430
+ it("should handle sql language", () => {
431
+ const code = "```sql\nSELECT * FROM users\n```";
432
+ const result = codeToCells(code);
433
+ expect(result).toEqual([{ language: "sql", code: "SELECT * FROM users" }]);
434
+ });
435
+
436
+ it("should handle unclosed markdown cell", () => {
437
+ const code = "```markdown\n# Hello, world!\n";
438
+ const result = codeToCells(code);
439
+ expect(result).toEqual([{ language: "markdown", code: "# Hello, world!" }]);
440
+ });
441
+
442
+ it("should handle unclosed sql cell", () => {
443
+ const code = "```sql\nSELECT * FROM users\n";
444
+ const result = codeToCells(code);
445
+ expect(result).toEqual([{ language: "sql", code: "SELECT * FROM users" }]);
446
+ });
447
+
448
+ it("should handle empty cells and skip them", () => {
449
+ const code = "```python\n\n```\n```sql\nSELECT * FROM users\n```";
450
+ const result = codeToCells(code);
451
+ expect(result).toEqual([{ language: "sql", code: "SELECT * FROM users" }]);
452
+ });
453
+
454
+ it("should handle cells with only whitespace and skip them", () => {
455
+ const code = "```python\n \n```\n```sql\nSELECT * FROM users\n```";
456
+ const result = codeToCells(code);
457
+ expect(result).toEqual([{ language: "sql", code: "SELECT * FROM users" }]);
458
+ });
459
+
460
+ it("should handle code with trailing newlines", () => {
461
+ const code = "```python\nprint('Hello, world!')\n\n\n```";
462
+ const result = codeToCells(code);
463
+ expect(result).toEqual([
464
+ { language: "python", code: "print('Hello, world!')" },
465
+ ]);
466
+ });
467
+
468
+ it("should handle unclosed code with trailing newlines", () => {
469
+ const code = "```python\nprint('Hello, world!')\n\n\n";
470
+ const result = codeToCells(code);
471
+ expect(result).toEqual([
472
+ { language: "python", code: "print('Hello, world!')" },
473
+ ]);
474
+ });
475
+
476
+ it("should handle multiple cells with different languages", () => {
477
+ const code =
478
+ "```python\nprint('Hello, world!')\n```\n```sql\nSELECT * FROM users\n```\n```markdown\n# Title\nThis is markdown\n```";
479
+
480
+ const result = codeToCells(code);
481
+ expect(result).toEqual([
482
+ { language: "python", code: "print('Hello, world!')" },
483
+ { language: "sql", code: "SELECT * FROM users" },
484
+ { language: "markdown", code: "# Title\nThis is markdown" },
485
+ ]);
486
+ });
487
+
488
+ it("should handle complex multiline code", () => {
489
+ const code =
490
+ '```python\ndef hello():\n print("Hello, world!")\n return "success"\n\nhello()\n```\n```sql\nSELECT \n id,\n name,\n email\nFROM users\nWHERE active = true\nORDER BY name;\n```';
491
+
492
+ const result = codeToCells(code);
493
+ expect(result).toEqual([
494
+ {
495
+ language: "python",
496
+ code: 'def hello():\n print("Hello, world!")\n return "success"\n\nhello()',
497
+ },
498
+ {
499
+ language: "sql",
500
+ code: "SELECT \n id,\n name,\n email\nFROM users\nWHERE active = true\nORDER BY name;",
501
+ },
502
+ ]);
503
+ });
504
+
505
+ it("should handle code with backticks in the content", () => {
506
+ const code = "```python\nprint('```')\n```";
507
+ const result = codeToCells(code);
508
+ expect(result).toEqual([{ language: "python", code: "print('" }]);
509
+ });
510
+
511
+ it("should handle code with no backticks in the last cell", () => {
512
+ const code =
513
+ "```python\nprint('Hello, world!')\n```\n```python\nprint('Hello, world!')";
514
+ const result = codeToCells(code);
515
+ expect(result).toEqual([
516
+ { language: "python", code: "print('Hello, world!')" },
517
+ { language: "python", code: "print('Hello, world!')" },
518
+ ]);
519
+ });
520
+
521
+ it("should handle case insensitive language detection", () => {
522
+ const code = "```PYTHON\nprint('Hello, world!')\n```";
523
+ const result = codeToCells(code);
524
+ expect(result).toEqual([
525
+ { language: "python", code: "print('Hello, world!')" },
526
+ ]);
527
+ });
528
+
529
+ it("should handle unknown language", { fails: true }, () => {
530
+ const code = "```javascript\nconsole.log('Hello, world!')\n```";
531
+ const result = codeToCells(code);
532
+ expect(result).toEqual([
533
+ { language: "javascript", code: "console.log('Hello, world!')" },
534
+ ]);
535
+ });
536
+ });
@@ -1,6 +1,6 @@
1
1
  /* Copyright 2024 Marimo. All rights reserved. */
2
2
 
3
- import { useCompletion } from "@ai-sdk/react";
3
+ import { useChat } from "@ai-sdk/react";
4
4
  import {
5
5
  autocompletion,
6
6
  type Completion,
@@ -8,7 +8,6 @@ import {
8
8
  type CompletionSource,
9
9
  } from "@codemirror/autocomplete";
10
10
  import { markdown } from "@codemirror/lang-markdown";
11
- import { sql } from "@codemirror/lang-sql";
12
11
  import { Prec } from "@codemirror/state";
13
12
  import { promptHistory, storePrompt } from "@marimo-team/codemirror-ai";
14
13
  import ReactCodeMirror, {
@@ -17,7 +16,7 @@ import ReactCodeMirror, {
17
16
  minimalSetup,
18
17
  type ReactCodeMirrorRef,
19
18
  } from "@uiw/react-codemirror";
20
- import { useAtom, useStore } from "jotai";
19
+ import { useAtom, useAtomValue, useStore } from "jotai";
21
20
  import { atomWithStorage } from "jotai/utils";
22
21
  import {
23
22
  ChevronsUpDown,
@@ -31,6 +30,10 @@ import { useMemo, useRef, useState } from "react";
31
30
  import useEvent from "react-use-event-hook";
32
31
  import { z } from "zod";
33
32
  import { AIModelDropdown } from "@/components/ai/ai-model-dropdown";
33
+ import {
34
+ buildCompletionRequestBody,
35
+ handleToolCall,
36
+ } from "@/components/chat/chat-utils";
34
37
  import { Button } from "@/components/ui/button";
35
38
  import {
36
39
  DropdownMenu,
@@ -40,31 +43,22 @@ import {
40
43
  DropdownMenuTrigger,
41
44
  } from "@/components/ui/dropdown-menu";
42
45
  import { toast } from "@/components/ui/use-toast";
46
+ import { stagedAICellsAtom, useStagedCells } from "@/core/ai/staged-cells";
43
47
  import { resourceExtension } from "@/core/codemirror/ai/resources";
44
- import { customPythonLanguageSupport } from "@/core/codemirror/language/languages/python";
45
- import { SQLLanguageAdapter } from "@/core/codemirror/language/languages/sql/sql";
48
+ import { useRequestClient } from "@/core/network/requests";
49
+ import type { AiCompletionRequest } from "@/core/network/types";
46
50
  import { useRuntimeManager } from "@/core/runtime/config";
47
51
  import { useTheme } from "@/theme/useTheme";
48
52
  import { cn } from "@/utils/cn";
49
53
  import { prettyError } from "@/utils/errors";
50
54
  import { ZodLocalStorage } from "@/utils/localStorage";
51
- import { useCellActions } from "../../../core/cells/cells";
52
55
  import { PythonIcon } from "../cell/code/icons";
53
56
  import {
54
57
  CompletionActions,
55
58
  createAiCompletionOnKeydown,
56
59
  } from "./completion-handlers";
57
- import {
58
- CONTEXT_TRIGGER,
59
- getAICompletionBody,
60
- mentionsCompletionSource,
61
- } from "./completion-utils";
62
-
63
- const pythonExtensions = [
64
- customPythonLanguageSupport(),
65
- EditorView.lineWrapping,
66
- ];
67
- const sqlExtensions = [sql(), EditorView.lineWrapping];
60
+ import { CONTEXT_TRIGGER, mentionsCompletionSource } from "./completion-utils";
61
+ import { StreamingChunkTransport } from "./transport/chat-transport";
68
62
 
69
63
  // Persist across sessions
70
64
  const languageAtom = atomWithStorage<"python" | "sql">(
@@ -82,32 +76,56 @@ const promptHistoryStorage = new ZodLocalStorage(z.array(z.string()), () => []);
82
76
  export const AddCellWithAI: React.FC<{
83
77
  onClose: () => void;
84
78
  }> = ({ onClose }) => {
85
- const { createNewCell } = useCellActions();
86
- const [completionBody, setCompletionBody] = useState<object>({});
79
+ const store = useStore();
80
+ const [input, setInput] = useState("");
81
+
82
+ const { deleteAllStagedCells, clearStagedCells, onStream } =
83
+ useStagedCells(store);
87
84
  const [language, setLanguage] = useAtom(languageAtom);
88
- const { theme } = useTheme();
89
85
  const runtimeManager = useRuntimeManager();
86
+ const { invokeAiTool } = useRequestClient();
90
87
 
88
+ const stagedAICells = useAtomValue(stagedAICellsAtom);
91
89
  const inputRef = useRef<ReactCodeMirrorRef>(null);
92
90
 
93
- const {
94
- completion,
95
- input,
96
- stop,
97
- isLoading,
98
- setCompletion,
99
- setInput,
100
- handleSubmit,
101
- } = useCompletion({
102
- api: runtimeManager.getAiURL("completion").toString(),
103
- headers: runtimeManager.headers(),
104
- streamProtocol: "text",
91
+ const { sendMessage, stop, status, addToolResult } = useChat({
105
92
  // Throttle the messages and data updates to 100ms
106
93
  experimental_throttle: 100,
107
- body: {
108
- ...completionBody,
109
- language: language,
110
- code: "",
94
+ transport: new StreamingChunkTransport(
95
+ {
96
+ api: runtimeManager.getAiURL("completion").toString(),
97
+ headers: runtimeManager.headers(),
98
+ prepareSendMessagesRequest: async (options) => {
99
+ const completionBody = await buildCompletionRequestBody(
100
+ options.messages,
101
+ );
102
+ const body: AiCompletionRequest = {
103
+ ...options,
104
+ ...completionBody,
105
+ code: "",
106
+ prompt: "", // Don't need prompt since we are using messages
107
+ language: language,
108
+ };
109
+
110
+ return {
111
+ body: body,
112
+ };
113
+ },
114
+ },
115
+ (chunk) => {
116
+ onStream(chunk);
117
+ },
118
+ ),
119
+ onToolCall: async ({ toolCall }) => {
120
+ await handleToolCall({
121
+ invokeAiTool,
122
+ addToolResult,
123
+ toolCall: {
124
+ toolName: toolCall.toolName,
125
+ toolCallId: toolCall.toolCallId,
126
+ input: toolCall.input as Record<string, never>,
127
+ },
128
+ });
111
129
  },
112
130
  onError: (error) => {
113
131
  toast({
@@ -115,18 +133,20 @@ export const AddCellWithAI: React.FC<{
115
133
  description: prettyError(error),
116
134
  });
117
135
  },
118
- onFinish: (_prompt, completion) => {
119
- // Remove trailing new lines
120
- setCompletion(completion.trimEnd());
121
- },
122
136
  });
123
137
 
138
+ const isLoading = status === "streaming" || status === "submitted";
139
+ const hasCompletion = stagedAICells.size > 0;
140
+ const multipleCompletions = stagedAICells.size > 1;
141
+
124
142
  const submit = () => {
125
143
  if (!isLoading) {
126
144
  if (inputRef.current?.view) {
127
145
  storePrompt(inputRef.current.view);
128
146
  }
129
- handleSubmit();
147
+ // TODO: When we have conversations, don't delete existing cells
148
+ deleteAllStagedCells();
149
+ sendMessage({ text: input });
130
150
  }
131
151
  };
132
152
 
@@ -171,20 +191,12 @@ export const AddCellWithAI: React.FC<{
171
191
  );
172
192
 
173
193
  const handleAcceptCompletion = () => {
174
- createNewCell({
175
- cellId: "__end__",
176
- before: false,
177
- code:
178
- language === "python"
179
- ? completion
180
- : SQLLanguageAdapter.fromQuery(completion),
181
- });
182
- setCompletion("");
194
+ clearStagedCells();
183
195
  onClose();
184
196
  };
185
197
 
186
198
  const handleDeclineCompletion = () => {
187
- setCompletion("");
199
+ deleteAllStagedCells();
188
200
  };
189
201
 
190
202
  const inputComponent = (
@@ -193,20 +205,19 @@ export const AddCellWithAI: React.FC<{
193
205
  <PromptInput
194
206
  inputRef={inputRef}
195
207
  onClose={() => {
196
- setCompletion("");
208
+ deleteAllStagedCells();
197
209
  onClose();
198
210
  }}
199
211
  value={input}
200
212
  onChange={(newValue) => {
201
213
  setInput(newValue);
202
- setCompletionBody(getAICompletionBody({ input: newValue }));
203
214
  }}
204
215
  onSubmit={submit}
205
216
  onKeyDown={createAiCompletionOnKeydown({
206
217
  handleAcceptCompletion,
207
218
  handleDeclineCompletion,
208
219
  isLoading,
209
- completion,
220
+ hasCompletion,
210
221
  })}
211
222
  />
212
223
  {isLoading && (
@@ -234,7 +245,7 @@ export const AddCellWithAI: React.FC<{
234
245
  <div className={cn("flex flex-col w-full gap-2 py-2")}>
235
246
  {inputComponent}
236
247
  <div className="flex flex-row justify-between -mt-1 ml-1 mr-3">
237
- {!completion && (
248
+ {!hasCompletion && (
238
249
  <span className="text-xs text-muted-foreground px-3 flex flex-col gap-1">
239
250
  <span>
240
251
  You can mention{" "}
@@ -245,12 +256,13 @@ export const AddCellWithAI: React.FC<{
245
256
  <span>Code from other cells is automatically included.</span>
246
257
  </span>
247
258
  )}
248
- {completion && (
259
+ {hasCompletion && (
249
260
  <CompletionActions
250
261
  isLoading={isLoading}
251
262
  onAccept={handleAcceptCompletion}
252
263
  onDecline={handleDeclineCompletion}
253
264
  size="sm"
265
+ multipleCompletions={multipleCompletions}
254
266
  />
255
267
  )}
256
268
  <div className="ml-auto flex items-center gap-1">
@@ -262,16 +274,6 @@ export const AddCellWithAI: React.FC<{
262
274
  />
263
275
  </div>
264
276
  </div>
265
-
266
- {completion && (
267
- <ReactCodeMirror
268
- value={completion}
269
- className="cm border-t"
270
- onChange={setCompletion}
271
- theme={theme === "dark" ? "dark" : "light"}
272
- extensions={language === "python" ? pythonExtensions : sqlExtensions}
273
- />
274
- )}
275
277
  </div>
276
278
  );
277
279
  };
@@ -165,7 +165,7 @@ export const AiCompletionEditor: React.FC<Props> = ({
165
165
  <SparklesIcon className="text-(--blue-10) shrink-0" size={16} />
166
166
  <PromptInput
167
167
  inputRef={inputRef}
168
- className="h-full my-0 py-2"
168
+ className="h-full my-0 py-2 flex items-center"
169
169
  onClose={() => {
170
170
  declineChange();
171
171
  setCompletion("");
@@ -187,7 +187,7 @@ export const AiCompletionEditor: React.FC<Props> = ({
187
187
  handleAcceptCompletion,
188
188
  handleDeclineCompletion,
189
189
  isLoading,
190
- completion,
190
+ hasCompletion: completion.trim().length > 0,
191
191
  })}
192
192
  />
193
193
  {isLoading && (
@@ -202,30 +202,33 @@ export const AiCompletionEditor: React.FC<Props> = ({
202
202
  Stop
203
203
  </Button>
204
204
  )}
205
- {completion && (
206
- <CompletionActions
207
- isLoading={isLoading}
208
- onAccept={handleAcceptCompletion}
209
- onDecline={handleDeclineCompletion}
210
- size="xs"
211
- />
212
- )}
213
- <div className="flex flex-row items-center gap-0.5 -ml-1.5 -mr-2">
214
- <Tooltip content="Add context">
215
- <Button
216
- variant="text"
217
- size="icon"
218
- onClick={() => addContextCompletion(inputRef)}
219
- >
220
- <AtSignIcon className="h-3 w-3" />
221
- </Button>
222
- </Tooltip>
223
- <AIModelDropdown
224
- triggerClassName="h-7"
225
- iconSize="small"
226
- displayIconOnly={true}
227
- forRole="edit"
228
- />
205
+ <div className="-mr-1.5 py-1.5">
206
+ <div className="flex flex-row items-center justify-end gap-0.5">
207
+ <Tooltip content="Add context">
208
+ <Button
209
+ variant="text"
210
+ size="icon"
211
+ onClick={() => addContextCompletion(inputRef)}
212
+ >
213
+ <AtSignIcon className="h-3 w-3" />
214
+ </Button>
215
+ </Tooltip>
216
+ <AIModelDropdown
217
+ triggerClassName="h-7 text-xs w-24"
218
+ iconSize="small"
219
+ forRole="edit"
220
+ />
221
+ </div>
222
+ {completion && (
223
+ <div className="-mb-1.5">
224
+ <CompletionActions
225
+ isLoading={isLoading}
226
+ onAccept={handleAcceptCompletion}
227
+ onDecline={handleDeclineCompletion}
228
+ size="xs"
229
+ />
230
+ </div>
231
+ )}
229
232
  </div>
230
233
 
231
234
  <div className="h-full w-px bg-border mx-2" />
@@ -12,20 +12,20 @@ export const createAiCompletionOnKeydown = (opts: {
12
12
  handleAcceptCompletion: () => void;
13
13
  handleDeclineCompletion: () => void;
14
14
  isLoading: boolean;
15
- completion: string;
15
+ hasCompletion: boolean;
16
16
  }) => {
17
17
  const {
18
18
  handleAcceptCompletion,
19
19
  handleDeclineCompletion,
20
20
  isLoading,
21
- completion,
21
+ hasCompletion,
22
22
  } = opts;
23
23
 
24
24
  return (e: React.KeyboardEvent<HTMLDivElement>) => {
25
25
  const metaKey = isPlatformMac() ? e.metaKey : e.ctrlKey;
26
26
 
27
27
  // Mod+Enter should accept the completion, if there is one
28
- if (metaKey && e.key === "Enter" && !isLoading && completion) {
28
+ if (metaKey && e.key === "Enter" && !isLoading && hasCompletion) {
29
29
  handleAcceptCompletion();
30
30
  }
31
31
 
@@ -49,6 +49,7 @@ export const CompletionActions: React.FC<{
49
49
  size?: "xs" | "sm";
50
50
  acceptShortcut?: string;
51
51
  declineShortcut?: string;
52
+ multipleCompletions?: boolean;
52
53
  }> = ({
53
54
  isLoading,
54
55
  onAccept,
@@ -56,6 +57,7 @@ export const CompletionActions: React.FC<{
56
57
  size = "sm",
57
58
  acceptShortcut = "Mod-↵",
58
59
  declineShortcut = "Shift-Mod-Delete",
60
+ multipleCompletions = false,
59
61
  }) => {
60
62
  return (
61
63
  <>
@@ -68,7 +70,7 @@ export const CompletionActions: React.FC<{
68
70
  onClick={onAccept}
69
71
  >
70
72
  <span className="text-(--grass-11) opacity-100">
71
- Accept{" "}
73
+ Accept{multipleCompletions && " all"}{" "}
72
74
  <MinimalHotkeys className="ml-1 inline" shortcut={acceptShortcut} />
73
75
  </span>
74
76
  </Button>
@@ -76,14 +78,50 @@ export const CompletionActions: React.FC<{
76
78
  data-testid="decline-completion-button"
77
79
  variant="text"
78
80
  size={size}
79
- className="mb-0 pl-1"
81
+ className="mb-0 pl-1 pr-0"
80
82
  onClick={onDecline}
81
83
  >
82
84
  <span className="text-(--red-10)">
83
- Reject{" "}
85
+ Reject{multipleCompletions && " all"}{" "}
84
86
  <MinimalHotkeys className="ml-1 inline" shortcut={declineShortcut} />
85
87
  </span>
86
88
  </Button>
87
89
  </>
88
90
  );
89
91
  };
92
+
93
+ export const CompletionActionsCellFooter: React.FC<{
94
+ isLoading: boolean;
95
+ onAccept: () => void;
96
+ onDecline: () => void;
97
+ size?: "xs" | "sm";
98
+ multipleCompletions?: boolean;
99
+ }> = ({ isLoading, onAccept, onDecline }) => {
100
+ return (
101
+ <>
102
+ <Button
103
+ variant="text"
104
+ size="xs"
105
+ disabled={isLoading}
106
+ onClick={onAccept}
107
+ className="h-6 text-(--grass-11) border-(--grass-7) bg-(--grass-3)/60
108
+ hover:bg-(--grass-3) dark:bg-(--grass-4)/80 dark:hover:bg-(--grass-3) rounded px-3 font-semibold
109
+ active:bg-(--grass-5) dark:active:bg-(--grass-4)
110
+ border-(--green-6) border hover:shadow-xs"
111
+ >
112
+ Accept
113
+ </Button>
114
+ <Button
115
+ variant="text"
116
+ size="xs"
117
+ onClick={onDecline}
118
+ className="h-6 text-(--red-10) border-(--red-7) bg-(--red-3)/60 hover:bg-(--red-3)
119
+ dark:bg-(--red-4)/80 dark:hover:bg-(--red-3) rounded px-3 font-semibold
120
+ active:bg-(--red-5) dark:active:bg-(--red-4)
121
+ border-(--red-6) border hover:shadow-xs"
122
+ >
123
+ Reject
124
+ </Button>
125
+ </>
126
+ );
127
+ };