@marimo-team/islands 0.25.3-dev189 → 0.25.3-dev191
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/{ConnectedDataExplorerComponent-Le_OBfmt.js → ConnectedDataExplorerComponent-BBbOElk3.js} +4 -4
- package/dist/{ErrorBoundary-CWtCjh3m.js → ErrorBoundary--X0z83Yx.js} +2 -2
- package/dist/{abnfDiagram-VCTEODGH-Tf1ghyQQ.js → abnfDiagram-VCTEODGH-DhMT6Uhd.js} +2 -2
- package/dist/{architectureDiagram-5GKGNRK7-xlnbTG0T.js → architectureDiagram-5GKGNRK7-BVbEiJLq.js} +1 -1
- package/dist/assets/__vite-browser-external-C8gQho07.js +1 -0
- package/dist/assets/{worker-C1pfNBsx.js → worker-C6e9ERyd.js} +2 -2
- package/dist/{chat-ui-X-cWrL9u.js → chat-ui-BguxTQEL.js} +7 -7
- package/dist/{chunk-IMKFNOWR-Cmd4a5jy.js → chunk-IMKFNOWR-By5hSbJJ.js} +1 -1
- package/dist/{chunk-SHT3W25Y-mSNp-WpO.js → chunk-SHT3W25Y-DFrEYG54.js} +1 -1
- package/dist/{chunk-SVP7TREG-CWC49D8X.js → chunk-SVP7TREG-DFXGc9ew.js} +1 -1
- package/dist/{chunk-TICWLB2K-De9FINtG.js → chunk-TICWLB2K-DZdNIpoZ.js} +1 -1
- package/dist/{classDiagram-ZZMXUADV-DweTkYdp.js → classDiagram-ZZMXUADV-Cgj_eEQA.js} +2 -2
- package/dist/{classDiagram-v2-VYDZK3BY-A6MR2TiE.js → classDiagram-v2-VYDZK3BY-DLAUrSqj.js} +2 -2
- package/dist/{code-visibility-BZDPS5dP.js → code-visibility-uDyLo9_i.js} +4 -4
- package/dist/{common-rusLIanu.js → common-DWKY45Md.js} +9 -9
- package/dist/{cynefinDiagram-5FMLGOSQ-BSvo5le-.js → cynefinDiagram-5FMLGOSQ-Cikf9AKa.js} +1 -1
- package/dist/{dagre-GXQ25YYZ-tXRQslO6.js → dagre-GXQ25YYZ-C5KEi5_l.js} +1 -1
- package/dist/{data-grid-overlay-editor-Dc_HCUPe.js → data-grid-overlay-editor-CRnYWD1L.js} +1 -1
- package/dist/{diagram-S7CK7UJ4-r3t5VtwI.js → diagram-S7CK7UJ4-BaoBTQjR.js} +1 -1
- package/dist/{diagram-UQ7AKVKN-qgbC8YnT.js → diagram-UQ7AKVKN-DDufBsUA.js} +1 -1
- package/dist/{diagram-VX7I27RA-CiHxEwtp.js → diagram-VX7I27RA-CY6RALJ8.js} +1 -1
- package/dist/{diagram-Z3DM3KII-D95u15Ev.js → diagram-Z3DM3KII-Bc-LHsD6.js} +1 -1
- package/dist/{dropdown-menu-DCMbbQ35.js → dropdown-menu-drDjxJyV.js} +1 -1
- package/dist/{ebnfDiagram-PWID7BFC-P7e4bryK.js → ebnfDiagram-PWID7BFC-Cz0J-tcC.js} +2 -2
- package/dist/{erDiagram-RLTQ6QDP-CUHZcmRj.js → erDiagram-RLTQ6QDP-DTXTDgFu.js} +1 -1
- package/dist/{error-entries-mpoD5t79.js → error-entries-CZ1NQ6Kv.js} +4 -4
- package/dist/{feedback-button-C3gqiY5b.js → feedback-button-CDf1yRm_.js} +5 -5
- package/dist/{flowDiagram-HODETNUW-BGZ95AzI.js → flowDiagram-HODETNUW-RbwWf2zc.js} +2 -2
- package/dist/{formats-DI7HEVv7.js → formats-DbXnijtH.js} +1 -1
- package/dist/{glide-data-editor-defMDM3B.js → glide-data-editor-CvRiA49N.js} +5 -5
- package/dist/{globals-D9kDDdYk.js → globals-BR4CmGOS.js} +2 -2
- package/dist/{html-to-image-BoZthB4P.js → html-to-image-D_4_hQ8U.js} +5 -5
- package/dist/{infoDiagram-27XIBGKW-BF0YX70D.js → infoDiagram-27XIBGKW-DlmzZjmI.js} +1 -1
- package/dist/{ishikawaDiagram-5VMMS53U-_itsAAn-.js → ishikawaDiagram-5VMMS53U-EN3TYP_q.js} +1 -1
- package/dist/{kanban-definition-UXKFOSKX-VNW2Beqh.js → kanban-definition-UXKFOSKX-CK_-Ru7Q.js} +1 -1
- package/dist/main.js +22 -22
- package/dist/{mermaid-CZ6FrClS.js → mermaid-DU9ZRmkG.js} +34 -34
- package/dist/{mindmap-definition-YA3MSWOX-DR4ripvd.js → mindmap-definition-YA3MSWOX-C-hqgUvF.js} +1 -1
- package/dist/{number-overlay-editor-CR5KeIcI.js → number-overlay-editor-DiYGbxNa.js} +1 -1
- package/dist/{pegDiagram-XKGWAZYB-CFr3XlGl.js → pegDiagram-XKGWAZYB-BiMejYPB.js} +2 -2
- package/dist/{pieDiagram-E7YTZNPT-j91XYSLY.js → pieDiagram-E7YTZNPT-B1zCZ1eq.js} +1 -1
- package/dist/{process-output-DLS4Mqg_.js → process-output-DxSCHBWp.js} +2 -2
- package/dist/{railroadDiagram-O6MQD6OU-Cd47ZV9E.js → railroadDiagram-O6MQD6OU-BLcfaASl.js} +2 -2
- package/dist/{requirementDiagram-BXWQKSXE-eJH6gLtX.js → requirementDiagram-BXWQKSXE-DtBOf52-.js} +1 -1
- package/dist/{reveal-component-DxZaPN5S.js → reveal-component-D3DsXPIm.js} +6 -6
- package/dist/{sequenceDiagram-WJ2MYXX4-DdfFEIrm.js → sequenceDiagram-WJ2MYXX4-DIwF19_n.js} +1 -1
- package/dist/{spec-h69nC3SI.js → spec-DZDnnlgT.js} +1 -1
- package/dist/{stateDiagram-D77RDMKH-DkjDvip8.js → stateDiagram-D77RDMKH-sWk1AdYL.js} +2 -2
- package/dist/{stateDiagram-v2-MP3YSRHH-DBHACnOo.js → stateDiagram-v2-MP3YSRHH-CiNo-OI7.js} +2 -2
- package/dist/style.css +1 -1
- package/dist/{swimlanes-42K2YHIH-ogImlOmp.js → swimlanes-42K2YHIH-Bj3hiOY5.js} +1 -1
- package/dist/{swimlanesDiagram-VR7AAH4N-D6x-zsci.js → swimlanesDiagram-VR7AAH4N-BzEo2r_N.js} +2 -2
- package/dist/{timeline-definition-24CTP7MA-DQpLtsHD.js → timeline-definition-24CTP7MA-CrPQk42H.js} +1 -1
- package/dist/{toDate-CDzoofJo.js → toDate-Cu2pIZcC.js} +1 -1
- package/dist/{useAsyncData-Bn8SxUqM.js → useAsyncData-DEhLdRIu.js} +1 -1
- package/dist/{useDeepCompareMemoize-CC2tnPCk.js → useDeepCompareMemoize-RjZGVhBV.js} +1 -1
- package/dist/{useLifecycle-BJlxHqWa.js → useLifecycle-DtcB2s1z.js} +1 -1
- package/dist/{useTheme-DMfQYmlG.js → useTheme-CoEtr4mK.js} +1 -1
- package/dist/{vega-component-CovWHi60.js → vega-component-BhjTrP9-.js} +5 -5
- package/dist/{vennDiagram-4TSXK5OY-BD-SL_vq.js → vennDiagram-4TSXK5OY-BaYMoIpj.js} +1 -1
- package/dist/{wardleyDiagram-VM6X3IG4-BDgJV4ah.js → wardleyDiagram-VM6X3IG4-DjHeuj8p.js} +1 -1
- package/dist/{xychartDiagram-S5SC5T6Z-1hIHN6Rl.js → xychartDiagram-S5SC5T6Z-Bc_hcuXS.js} +1 -1
- package/package.json +1 -1
- package/src/components/chat/__tests__/notebook-access-selector.test.tsx +64 -0
- package/src/components/chat/chat-panel.tsx +9 -91
- package/src/components/chat/notebook-access-selector.stories.tsx +22 -0
- package/src/components/chat/notebook-access-selector.tsx +100 -0
- package/src/core/ai/tools/__tests__/edit-notebook-tool.test.ts +1 -5
- package/src/core/ai/tools/__tests__/registry.test.ts +17 -0
- package/src/core/ai/tools/base.ts +0 -6
- package/src/core/ai/tools/edit-notebook-tool.ts +1 -2
- package/src/core/ai/tools/registry.ts +0 -2
- package/src/core/config/__tests__/config-schema.test.ts +7 -2
- package/src/core/config/config-schema.ts +4 -1
- package/dist/assets/__vite-browser-external-DVeFf2e7.js +0 -1
- package/src/core/ai/tools/__tests__/run-cells-tool.test.ts +0 -656
- package/src/core/ai/tools/run-cells-tool.ts +0 -303
|
@@ -9,7 +9,7 @@ import "./chunk-4HAMMTFA-D4eFPyFh.js";
|
|
|
9
9
|
import "./chunk-GVQU2GXP-Cwbt-lF0.js";
|
|
10
10
|
import "./chunk-L3NEJ4N5-n-zgIVSy.js";
|
|
11
11
|
import { o as n } from "./chunk-OSK3NFVY-DXa-Cxbn.js";
|
|
12
|
-
import { c as r } from "./mermaid-
|
|
12
|
+
import { c as r } from "./mermaid-DU9ZRmkG.js";
|
|
13
13
|
//#region ../node_modules/.pnpm/mermaid@11.17.2/node_modules/mermaid/dist/chunks/mermaid.core/swimlanes-42K2YHIH.mjs
|
|
14
14
|
var i = 5, a = 1e-5, o = 1e-6;
|
|
15
15
|
function s(e) {
|
package/dist/{swimlanesDiagram-VR7AAH4N-D6x-zsci.js → swimlanesDiagram-VR7AAH4N-BzEo2r_N.js}
RENAMED
|
@@ -9,11 +9,11 @@ import "./chunk-4HAMMTFA-D4eFPyFh.js";
|
|
|
9
9
|
import "./chunk-GVQU2GXP-Cwbt-lF0.js";
|
|
10
10
|
import "./chunk-L3NEJ4N5-n-zgIVSy.js";
|
|
11
11
|
import "./chunk-OSK3NFVY-DXa-Cxbn.js";
|
|
12
|
-
import "./mermaid-
|
|
12
|
+
import "./mermaid-DU9ZRmkG.js";
|
|
13
13
|
import "./chunk-F27PBJKO-ufseIn5y.js";
|
|
14
14
|
import "./chunk-XXDRQBXY-Dnl5VBqG.js";
|
|
15
15
|
import "./chunk-POPQ4Y6H-hYOXbYH_.js";
|
|
16
|
-
import { r as t, t as n } from "./chunk-SHT3W25Y-
|
|
16
|
+
import { r as t, t as n } from "./chunk-SHT3W25Y-DFrEYG54.js";
|
|
17
17
|
//#region ../node_modules/.pnpm/mermaid@11.17.2/node_modules/mermaid/dist/chunks/mermaid.core/swimlanesDiagram-VR7AAH4N.mjs
|
|
18
18
|
var r = n({
|
|
19
19
|
defaultLayout: "swimlane",
|
package/dist/{timeline-definition-24CTP7MA-DQpLtsHD.js → timeline-definition-24CTP7MA-CrPQk42H.js}
RENAMED
|
@@ -3,7 +3,7 @@ import { p as t } from "./chunk-75Z2AOVW-D7gxIs2Q.js";
|
|
|
3
3
|
import { n, t as r } from "./src-CA_m4ONl.js";
|
|
4
4
|
import { n as i, t as a } from "./chunk-Y2CYZVJY-DKKS1VyV.js";
|
|
5
5
|
import { $ as o, J as s, a as c, b as l, et as u, nt as d, o as f, x as p } from "./chunk-DU6HZSFF-BwiyaNpg.js";
|
|
6
|
-
import { p as m } from "./mermaid-
|
|
6
|
+
import { p as m } from "./mermaid-DU9ZRmkG.js";
|
|
7
7
|
//#region ../node_modules/.pnpm/mermaid@11.17.2/node_modules/mermaid/dist/chunks/mermaid.core/timeline-definition-24CTP7MA.mjs
|
|
8
8
|
var h = (function() {
|
|
9
9
|
var e = /* @__PURE__ */ i(function(e, t, n, r) {
|
|
@@ -2,7 +2,7 @@ import { t as e } from "./rolldown-runtime-Cb76FRpK.js";
|
|
|
2
2
|
import { g as t } from "./button-BQRdqQi1.js";
|
|
3
3
|
import { t as n } from "./compiler-runtime-CldRdSsv.js";
|
|
4
4
|
import { m as r } from "./tooltip-s4zZxwKe.js";
|
|
5
|
-
import { D as i, _ as a, a as o, w as s, x as c } from "./useTheme-
|
|
5
|
+
import { D as i, _ as a, a as o, w as s, x as c } from "./useTheme-CoEtr4mK.js";
|
|
6
6
|
import { t as l } from "./invariant-DLmrl-hA.js";
|
|
7
7
|
var u = r("circle-question-mark", [
|
|
8
8
|
["circle", {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { a as e } from "./rolldown-runtime-Cb76FRpK.js";
|
|
2
2
|
import { t } from "./react-sHtZdjeP.js";
|
|
3
3
|
import { t as n } from "./compiler-runtime-CldRdSsv.js";
|
|
4
|
-
import { A as r } from "./useTheme-
|
|
4
|
+
import { A as r } from "./useTheme-CoEtr4mK.js";
|
|
5
5
|
import { t as i } from "./invariant-DLmrl-hA.js";
|
|
6
6
|
//#region src/hooks/useAsyncData.ts
|
|
7
7
|
var a = n(), o = /* @__PURE__ */ e(t(), 1), s = {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { a as e } from "./rolldown-runtime-Cb76FRpK.js";
|
|
2
2
|
import { t } from "./react-sHtZdjeP.js";
|
|
3
|
-
import { b as n } from "./useTheme-
|
|
3
|
+
import { b as n } from "./useTheme-CoEtr4mK.js";
|
|
4
4
|
//#region src/hooks/useDeepCompareMemoize.ts
|
|
5
5
|
var r = /* @__PURE__ */ e(t(), 1);
|
|
6
6
|
function i(e) {
|
|
@@ -4,7 +4,7 @@ import { t as i } from "./react-sHtZdjeP.js";
|
|
|
4
4
|
import { t as a } from "./compiler-runtime-CldRdSsv.js";
|
|
5
5
|
import { m as o } from "./tooltip-s4zZxwKe.js";
|
|
6
6
|
import { t as s } from "./jsx-runtime-3BD1kT0s.js";
|
|
7
|
-
import { D as c, T as l } from "./useTheme-
|
|
7
|
+
import { D as c, T as l } from "./useTheme-CoEtr4mK.js";
|
|
8
8
|
var u = o("calendar", [
|
|
9
9
|
["path", {
|
|
10
10
|
d: "M8 2v4",
|
|
@@ -681,7 +681,7 @@ var ze = [
|
|
|
681
681
|
enabled: p().prefault(!0),
|
|
682
682
|
rules: u().prefault(""),
|
|
683
683
|
max_tokens: d().int().positive().nullable().optional(),
|
|
684
|
-
mode: m(We).
|
|
684
|
+
mode: m(We).transform((e) => e === "manual" ? "ask" : e).prefault("ask"),
|
|
685
685
|
inline_tooltip: p().prefault(!1),
|
|
686
686
|
allow_provider_config: p().prefault(!0),
|
|
687
687
|
open_ai: J.optional(),
|
|
@@ -3,20 +3,20 @@ import { g as t, h as n, m as r, o as i } from "./button-BQRdqQi1.js";
|
|
|
3
3
|
import { t as a } from "./react-sHtZdjeP.js";
|
|
4
4
|
import { t as o } from "./compiler-runtime-CldRdSsv.js";
|
|
5
5
|
import { t as s } from "./tooltip-s4zZxwKe.js";
|
|
6
|
-
import { C as c, a as l } from "./toDate-
|
|
6
|
+
import { C as c, a as l } from "./toDate-Cu2pIZcC.js";
|
|
7
7
|
import { t as u } from "./jsx-runtime-3BD1kT0s.js";
|
|
8
8
|
import { n as d } from "./error-banner-DxJ3s8YO.js";
|
|
9
9
|
import { t as f } from "./debounce-C3jyATpc.js";
|
|
10
|
-
import { A as p, n as ee } from "./useTheme-
|
|
10
|
+
import { A as p, n as ee } from "./useTheme-CoEtr4mK.js";
|
|
11
11
|
import { c as m, t as h } from "./arrays-R6JsImiT.js";
|
|
12
12
|
import { t as te } from "./objects-DCmMvZtn.js";
|
|
13
|
-
import { t as ne } from "./useAsyncData-
|
|
14
|
-
import { a as g, i as re, n as ie, t as ae } from "./formats-
|
|
13
|
+
import { t as ne } from "./useAsyncData-DEhLdRIu.js";
|
|
14
|
+
import { a as g, i as re, n as ie, t as ae } from "./formats-DbXnijtH.js";
|
|
15
15
|
import { t as _ } from "./semaphore-89jsoHtS.js";
|
|
16
16
|
import { D as oe, n as se } from "./vega-loader.browser-B9Pz0EGP.js";
|
|
17
17
|
import { t as ce } from "./react-vega-C4T9Rb_w.js";
|
|
18
18
|
import { a as le, n as v } from "./loader-DOVB0Syl.js";
|
|
19
|
-
import { t as ue } from "./useDeepCompareMemoize-
|
|
19
|
+
import { t as ue } from "./useDeepCompareMemoize-RjZGVhBV.js";
|
|
20
20
|
import { t as de } from "./use-vega-container-remeasure-Bz4PZMtt.js";
|
|
21
21
|
//#region src/plugins/impl/vega/fix-relative-url.ts
|
|
22
22
|
var fe = /* @__PURE__ */ e(a(), 1), pe = o();
|
|
@@ -3,7 +3,7 @@ import { t } from "./src-CA_m4ONl.js";
|
|
|
3
3
|
import { n } from "./chunk-Y2CYZVJY-DKKS1VyV.js";
|
|
4
4
|
import { $ as r, H as i, K as a, U as o, a as s, b as c, c as l, et as u, f as d, nt as f, tt as p, v as m, w as h, y as g } from "./chunk-DU6HZSFF-BwiyaNpg.js";
|
|
5
5
|
import { t as _ } from "./rough.esm-CtV9AnV1.js";
|
|
6
|
-
import { p as v } from "./mermaid-
|
|
6
|
+
import { p as v } from "./mermaid-DU9ZRmkG.js";
|
|
7
7
|
//#region ../node_modules/.pnpm/khroma@2.1.0/node_modules/khroma/dist/methods/transparentize.js
|
|
8
8
|
var y = (e, t) => p(e, "a", -t), b = 1e-10;
|
|
9
9
|
function x(e, t) {
|
|
@@ -2,7 +2,7 @@ import { i as e } from "./chunk-75Z2AOVW-D7gxIs2Q.js";
|
|
|
2
2
|
import { n as t } from "./src-CA_m4ONl.js";
|
|
3
3
|
import { n } from "./chunk-Y2CYZVJY-DKKS1VyV.js";
|
|
4
4
|
import { D as r, H as i, K as a, U as o, a as s, b as c, c as l, v as u, w as d, x as f, y as p } from "./chunk-DU6HZSFF-BwiyaNpg.js";
|
|
5
|
-
import { p as m } from "./mermaid-
|
|
5
|
+
import { p as m } from "./mermaid-DU9ZRmkG.js";
|
|
6
6
|
import { n as h } from "./mermaid-parser.core-DxuSfYwJ.js";
|
|
7
7
|
import { t as g } from "./chunk-JWPE2WC7-DJvv1t8U.js";
|
|
8
8
|
//#region ../node_modules/.pnpm/mermaid@11.17.2/node_modules/mermaid/dist/chunks/mermaid.core/wardleyDiagram-VM6X3IG4.mjs
|
|
@@ -9,7 +9,7 @@ import { n as s } from "./chunk-Y2CYZVJY-DKKS1VyV.js";
|
|
|
9
9
|
import { D as c, H as l, K as u, U as d, a as f, b as p, c as m, f as h, v as g, w as _, y as v, z as y } from "./chunk-DU6HZSFF-BwiyaNpg.js";
|
|
10
10
|
import "./chunk-PWAF6VOD-CQw5qATZ.js";
|
|
11
11
|
import { t as b } from "./chunk-GMAD6QVW-BhaJx0X3.js";
|
|
12
|
-
import { p as x } from "./mermaid-
|
|
12
|
+
import { p as x } from "./mermaid-DU9ZRmkG.js";
|
|
13
13
|
//#region ../node_modules/.pnpm/d3-scale@4.0.2/node_modules/d3-scale/src/band.js
|
|
14
14
|
function S() {
|
|
15
15
|
var e = t().unknown(void 0), r = e.domain, i = e.range, o = 0, s = 1, c, l, u = !1, d = 0, f = 0, p = .5;
|
package/package.json
CHANGED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
|
+
|
|
3
|
+
import { fireEvent, render, screen } from "@testing-library/react";
|
|
4
|
+
import { describe, expect, it, vi } from "vitest";
|
|
5
|
+
import type { CopilotMode } from "@/core/config/config-schema";
|
|
6
|
+
import { NotebookAccessSelector } from "../notebook-access-selector";
|
|
7
|
+
|
|
8
|
+
Element.prototype.scrollIntoView = vi.fn();
|
|
9
|
+
|
|
10
|
+
describe("NotebookAccessSelector", () => {
|
|
11
|
+
it("shows legacy Manual as Read only and offers exactly three levels", async () => {
|
|
12
|
+
const onValueChange = vi.fn();
|
|
13
|
+
render(
|
|
14
|
+
<NotebookAccessSelector value="manual" onValueChange={onValueChange} />,
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
fireEvent.keyDown(
|
|
18
|
+
screen.getByRole("combobox", { name: "Notebook access: Read only" }),
|
|
19
|
+
{ key: "ArrowDown" },
|
|
20
|
+
);
|
|
21
|
+
const options = await screen.findAllByRole("option");
|
|
22
|
+
expect(options.map((option) => option.getAttribute("data-state"))).toEqual([
|
|
23
|
+
"checked",
|
|
24
|
+
"unchecked",
|
|
25
|
+
"unchecked",
|
|
26
|
+
]);
|
|
27
|
+
expect(options.map((option) => option.textContent)).toEqual([
|
|
28
|
+
"Read onlyRead notebook code, outputs, and variable previews.",
|
|
29
|
+
"Suggest editsRead the notebook and propose cell changes for review.",
|
|
30
|
+
"Full accessRead, edit, and run cells, with Python scratchpad access.",
|
|
31
|
+
]);
|
|
32
|
+
expect(onValueChange).not.toHaveBeenCalled();
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it.each<{ mode: CopilotMode; label: string }>([
|
|
36
|
+
{ mode: "ask", label: "Read only" },
|
|
37
|
+
{ mode: "agent", label: "Suggest edits" },
|
|
38
|
+
{ mode: "code_mode", label: "Full access" },
|
|
39
|
+
])("maps $label to the existing $mode setting", async ({ mode, label }) => {
|
|
40
|
+
const onValueChange = vi.fn();
|
|
41
|
+
const { rerender } = render(
|
|
42
|
+
<NotebookAccessSelector value={mode} onValueChange={onValueChange} />,
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
expect(
|
|
46
|
+
screen.getByRole("combobox", { name: `Notebook access: ${label}` }),
|
|
47
|
+
).toHaveTextContent(label);
|
|
48
|
+
expect(onValueChange).not.toHaveBeenCalled();
|
|
49
|
+
|
|
50
|
+
rerender(
|
|
51
|
+
<NotebookAccessSelector
|
|
52
|
+
value={mode === "ask" ? "agent" : "ask"}
|
|
53
|
+
onValueChange={onValueChange}
|
|
54
|
+
/>,
|
|
55
|
+
);
|
|
56
|
+
fireEvent.keyDown(screen.getByRole("combobox"), { key: "ArrowDown" });
|
|
57
|
+
const option = await screen.findByRole("option", {
|
|
58
|
+
name: new RegExp(`^${label} `),
|
|
59
|
+
});
|
|
60
|
+
fireEvent.keyDown(option, { key: "Enter" });
|
|
61
|
+
|
|
62
|
+
expect(onValueChange).toHaveBeenCalledExactlyOnceWith(mode);
|
|
63
|
+
});
|
|
64
|
+
});
|
|
@@ -13,28 +13,15 @@ import {
|
|
|
13
13
|
import { useAtom, useAtomValue, useSetAtom, useStore } from "jotai";
|
|
14
14
|
import {
|
|
15
15
|
BotMessageSquareIcon,
|
|
16
|
-
HatGlasses,
|
|
17
16
|
ArrowRightIcon,
|
|
18
17
|
Loader2,
|
|
19
|
-
type LucideIcon,
|
|
20
|
-
MessageCircleIcon,
|
|
21
|
-
NotebookText,
|
|
22
18
|
PlusIcon,
|
|
23
19
|
SparklesIcon,
|
|
24
20
|
SettingsIcon,
|
|
25
|
-
CodeIcon,
|
|
26
21
|
} from "lucide-react";
|
|
27
22
|
import { memo, useEffect, useRef, useState } from "react";
|
|
28
23
|
import useEvent from "react-use-event-hook";
|
|
29
24
|
import { Button } from "@/components/ui/button";
|
|
30
|
-
import {
|
|
31
|
-
Select,
|
|
32
|
-
SelectContent,
|
|
33
|
-
SelectGroup,
|
|
34
|
-
SelectItem,
|
|
35
|
-
SelectLabel,
|
|
36
|
-
SelectTrigger,
|
|
37
|
-
} from "@/components/ui/select";
|
|
38
25
|
import { replaceMessagesInChat } from "@/core/ai/chat-utils";
|
|
39
26
|
import { useAIConfigActions } from "@/core/ai/config";
|
|
40
27
|
import { AI_SDK_UI_THROTTLE_MS } from "@/core/ai/constants";
|
|
@@ -49,10 +36,7 @@ import {
|
|
|
49
36
|
pendingAiPromptAtom,
|
|
50
37
|
} from "@/core/ai/state";
|
|
51
38
|
import type { ToolNotebookContext } from "@/core/ai/tools/base";
|
|
52
|
-
import {
|
|
53
|
-
type CopilotMode,
|
|
54
|
-
FRONTEND_TOOL_REGISTRY,
|
|
55
|
-
} from "@/core/ai/tools/registry";
|
|
39
|
+
import { FRONTEND_TOOL_REGISTRY } from "@/core/ai/tools/registry";
|
|
56
40
|
import { useCellActions } from "@/core/cells/actions";
|
|
57
41
|
import { aiAtom, aiModelConfiguredAtom } from "@/core/config/config";
|
|
58
42
|
import { DEFAULT_AI_MODEL } from "@/core/config/config-schema";
|
|
@@ -97,6 +81,7 @@ import {
|
|
|
97
81
|
import { renderUIMessage } from "./chat-display";
|
|
98
82
|
import { ChatHistoryPopover } from "./chat-history-popover";
|
|
99
83
|
import { CapabilitiesPopover } from "./capabilities-popover";
|
|
84
|
+
import { NotebookAccessSelector } from "./notebook-access-selector";
|
|
100
85
|
import {
|
|
101
86
|
type ChatMessagePart,
|
|
102
87
|
convertToFileUIPart,
|
|
@@ -117,7 +102,7 @@ import ScrollToBottomButton from "./acp/scroll-to-bottom-button";
|
|
|
117
102
|
import { useChatControllerId } from "./use-chat-controller-id";
|
|
118
103
|
|
|
119
104
|
// Default mode for the AI
|
|
120
|
-
const DEFAULT_MODE = "
|
|
105
|
+
const DEFAULT_MODE = "ask";
|
|
121
106
|
|
|
122
107
|
const QueuedMessageDisplay = memo(
|
|
123
108
|
({ message }: { message: QueuedUserMessage }) => {
|
|
@@ -321,82 +306,17 @@ const ChatInputFooter: React.FC<ChatInputFooterProps> = memo(
|
|
|
321
306
|
|
|
322
307
|
const { saveModeChange } = useAIConfigActions();
|
|
323
308
|
|
|
324
|
-
const modeOptions: {
|
|
325
|
-
value: CopilotMode;
|
|
326
|
-
label: string;
|
|
327
|
-
subtitle: string;
|
|
328
|
-
Icon: LucideIcon;
|
|
329
|
-
}[] = [
|
|
330
|
-
{
|
|
331
|
-
value: "manual",
|
|
332
|
-
label: "Manual",
|
|
333
|
-
subtitle: "Pure chat, no tool usage",
|
|
334
|
-
Icon: MessageCircleIcon,
|
|
335
|
-
},
|
|
336
|
-
{
|
|
337
|
-
value: "ask",
|
|
338
|
-
label: "Ask",
|
|
339
|
-
subtitle: "AI with access to read-only tools like documentation search",
|
|
340
|
-
Icon: NotebookText,
|
|
341
|
-
},
|
|
342
|
-
{
|
|
343
|
-
value: "agent",
|
|
344
|
-
label: "Agent",
|
|
345
|
-
subtitle: "AI with access to read and write tools",
|
|
346
|
-
Icon: HatGlasses,
|
|
347
|
-
},
|
|
348
|
-
{
|
|
349
|
-
value: "code_mode",
|
|
350
|
-
label: "Code Mode (beta)",
|
|
351
|
-
subtitle:
|
|
352
|
-
"AI with access to the notebook's kernel. Potentially destructive.",
|
|
353
|
-
Icon: CodeIcon,
|
|
354
|
-
},
|
|
355
|
-
];
|
|
356
|
-
|
|
357
309
|
const isAttachmentSupported =
|
|
358
310
|
PROVIDERS_THAT_SUPPORT_ATTACHMENTS.has(currentProvider);
|
|
359
311
|
|
|
360
|
-
const currentModeOption = modeOptions.find((o) => o.value === currentMode);
|
|
361
|
-
const CurrentModeIcon = currentModeOption?.Icon;
|
|
362
|
-
const CurrentModeLabel = currentModeOption?.label;
|
|
363
|
-
|
|
364
312
|
return (
|
|
365
313
|
<TooltipProvider>
|
|
366
314
|
<div className="px-3 py-2 border-t border-border/20 flex flex-wrap items-center gap-1">
|
|
367
315
|
<div className="flex flex-wrap items-center gap-1">
|
|
368
|
-
<
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
</SelectTrigger>
|
|
373
|
-
<SelectContent>
|
|
374
|
-
<SelectGroup>
|
|
375
|
-
<SelectLabel className="text-xs uppercase tracking-wider text-muted-foreground/70 font-medium">
|
|
376
|
-
AI Mode
|
|
377
|
-
</SelectLabel>
|
|
378
|
-
{modeOptions.map((option) => (
|
|
379
|
-
<SelectItem
|
|
380
|
-
key={option.value}
|
|
381
|
-
value={option.value}
|
|
382
|
-
className="text-xs py-1"
|
|
383
|
-
>
|
|
384
|
-
<div className="flex items-start gap-2.5">
|
|
385
|
-
<span className="mt-1 text-muted-foreground">
|
|
386
|
-
<option.Icon className="h-3 w-3" />
|
|
387
|
-
</span>
|
|
388
|
-
<div className="flex flex-col gap-0.5">
|
|
389
|
-
<span className="font-semibold">{option.label}</span>
|
|
390
|
-
<span className="text-muted-foreground">
|
|
391
|
-
{option.subtitle}
|
|
392
|
-
</span>
|
|
393
|
-
</div>
|
|
394
|
-
</div>
|
|
395
|
-
</SelectItem>
|
|
396
|
-
))}
|
|
397
|
-
</SelectGroup>
|
|
398
|
-
</SelectContent>
|
|
399
|
-
</Select>
|
|
316
|
+
<NotebookAccessSelector
|
|
317
|
+
value={currentMode}
|
|
318
|
+
onValueChange={saveModeChange}
|
|
319
|
+
/>
|
|
400
320
|
<AIModelDropdown
|
|
401
321
|
placeholder="Model"
|
|
402
322
|
triggerClassName="h-6 text-xs shadow-none! ring-0! bg-muted hover:bg-muted/30 rounded-sm max-w-[200px]"
|
|
@@ -573,7 +493,7 @@ const ChatPanelBody = () => {
|
|
|
573
493
|
setAbortNotice(null);
|
|
574
494
|
});
|
|
575
495
|
const runtimeManager = useRuntimeManager();
|
|
576
|
-
const { invokeAiTool
|
|
496
|
+
const { invokeAiTool } = useRequestClient();
|
|
577
497
|
const { openModal, closeModal } = useImperativeModal();
|
|
578
498
|
|
|
579
499
|
const activeChatId = activeChat?.id;
|
|
@@ -582,12 +502,10 @@ const ChatPanelBody = () => {
|
|
|
582
502
|
const store = useStore();
|
|
583
503
|
|
|
584
504
|
const { addStagedCell } = useStagedAICellsActions();
|
|
585
|
-
const {
|
|
505
|
+
const { createCell } = useCellActions();
|
|
586
506
|
const toolContext: ToolNotebookContext = {
|
|
587
507
|
addStagedCell,
|
|
588
508
|
createCell,
|
|
589
|
-
prepareForRun,
|
|
590
|
-
sendRun,
|
|
591
509
|
store,
|
|
592
510
|
};
|
|
593
511
|
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
|
+
|
|
3
|
+
import type { Meta, StoryObj } from "@storybook/react-vite";
|
|
4
|
+
import { useState } from "react";
|
|
5
|
+
import { NotebookAccessSelector } from "./notebook-access-selector";
|
|
6
|
+
|
|
7
|
+
const meta = {
|
|
8
|
+
title: "Chat/Notebook access",
|
|
9
|
+
component: NotebookAccessSelector,
|
|
10
|
+
args: { value: "ask", onValueChange: () => undefined },
|
|
11
|
+
render: function Render(args) {
|
|
12
|
+
const [value, setValue] = useState(args.value);
|
|
13
|
+
return <NotebookAccessSelector value={value} onValueChange={setValue} />;
|
|
14
|
+
},
|
|
15
|
+
} satisfies Meta<typeof NotebookAccessSelector>;
|
|
16
|
+
|
|
17
|
+
export default meta;
|
|
18
|
+
type Story = StoryObj<typeof meta>;
|
|
19
|
+
|
|
20
|
+
export const ReadOnly: Story = { args: { value: "ask" } };
|
|
21
|
+
export const SuggestEdits: Story = { args: { value: "agent" } };
|
|
22
|
+
export const FullAccess: Story = { args: { value: "code_mode" } };
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
EyeIcon,
|
|
5
|
+
type LucideIcon,
|
|
6
|
+
PencilIcon,
|
|
7
|
+
TerminalIcon,
|
|
8
|
+
} from "lucide-react";
|
|
9
|
+
import {
|
|
10
|
+
Select,
|
|
11
|
+
SelectContent,
|
|
12
|
+
SelectGroup,
|
|
13
|
+
SelectItem,
|
|
14
|
+
SelectLabel,
|
|
15
|
+
SelectTrigger,
|
|
16
|
+
} from "@/components/ui/select";
|
|
17
|
+
import type { CopilotMode } from "@/core/config/config-schema";
|
|
18
|
+
|
|
19
|
+
const ACCESS_LEVELS = {
|
|
20
|
+
ask: {
|
|
21
|
+
label: "Read only",
|
|
22
|
+
description: "Read notebook code, outputs, and variable previews.",
|
|
23
|
+
Icon: EyeIcon,
|
|
24
|
+
},
|
|
25
|
+
agent: {
|
|
26
|
+
label: "Suggest edits",
|
|
27
|
+
description: "Read the notebook and propose cell changes for review.",
|
|
28
|
+
Icon: PencilIcon,
|
|
29
|
+
},
|
|
30
|
+
code_mode: {
|
|
31
|
+
label: "Full access",
|
|
32
|
+
description: "Read, edit, and run cells, with Python scratchpad access.",
|
|
33
|
+
Icon: TerminalIcon,
|
|
34
|
+
},
|
|
35
|
+
} satisfies Record<
|
|
36
|
+
Exclude<CopilotMode, "manual">,
|
|
37
|
+
{ label: string; description: string; Icon: LucideIcon }
|
|
38
|
+
>;
|
|
39
|
+
|
|
40
|
+
const ACCESS_MODES = ["ask", "agent", "code_mode"] as const;
|
|
41
|
+
|
|
42
|
+
interface NotebookAccessSelectorProps {
|
|
43
|
+
value: CopilotMode;
|
|
44
|
+
onValueChange: (value: CopilotMode) => void;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export const NotebookAccessSelector = ({
|
|
48
|
+
value,
|
|
49
|
+
onValueChange,
|
|
50
|
+
}: NotebookAccessSelectorProps) => {
|
|
51
|
+
const mode = value === "manual" ? "ask" : value;
|
|
52
|
+
const selected = ACCESS_LEVELS[mode];
|
|
53
|
+
|
|
54
|
+
return (
|
|
55
|
+
<Select
|
|
56
|
+
value={mode}
|
|
57
|
+
onValueChange={(value) => {
|
|
58
|
+
const mode = ACCESS_MODES.find((mode) => mode === value);
|
|
59
|
+
if (mode) {
|
|
60
|
+
onValueChange(mode);
|
|
61
|
+
}
|
|
62
|
+
}}
|
|
63
|
+
>
|
|
64
|
+
<SelectTrigger
|
|
65
|
+
aria-label={`Notebook access: ${selected.label}`}
|
|
66
|
+
title={`Notebook access: ${selected.description}`}
|
|
67
|
+
className="h-6 text-xs border-border shadow-none! ring-0! bg-muted hover:bg-muted/30 py-0 px-2 gap-1.5 shrink-0"
|
|
68
|
+
>
|
|
69
|
+
<selected.Icon className="h-3 w-3" />
|
|
70
|
+
<span className="text-nowrap">{selected.label}</span>
|
|
71
|
+
</SelectTrigger>
|
|
72
|
+
<SelectContent className="max-w-[calc(100vw-2rem)]">
|
|
73
|
+
<SelectGroup>
|
|
74
|
+
<SelectLabel className="text-xs uppercase tracking-wider text-muted-foreground/70 font-medium">
|
|
75
|
+
Notebook access
|
|
76
|
+
</SelectLabel>
|
|
77
|
+
{ACCESS_MODES.map((mode) => {
|
|
78
|
+
const { label, description, Icon } = ACCESS_LEVELS[mode];
|
|
79
|
+
return (
|
|
80
|
+
<SelectItem
|
|
81
|
+
key={mode}
|
|
82
|
+
value={mode}
|
|
83
|
+
textValue={label}
|
|
84
|
+
className="text-xs py-1"
|
|
85
|
+
>
|
|
86
|
+
<div className="flex items-start gap-2.5">
|
|
87
|
+
<Icon className="h-3 w-3 mt-1 shrink-0 text-muted-foreground" />
|
|
88
|
+
<div className="flex flex-col gap-0.5">
|
|
89
|
+
<span className="font-semibold">{label}</span>
|
|
90
|
+
<span className="text-muted-foreground">{description}</span>
|
|
91
|
+
</div>
|
|
92
|
+
</div>
|
|
93
|
+
</SelectItem>
|
|
94
|
+
);
|
|
95
|
+
})}
|
|
96
|
+
</SelectGroup>
|
|
97
|
+
</SelectContent>
|
|
98
|
+
</Select>
|
|
99
|
+
);
|
|
100
|
+
};
|
|
@@ -65,8 +65,6 @@ describe("EditNotebookTool", () => {
|
|
|
65
65
|
let toolContext: {
|
|
66
66
|
addStagedCell: ReturnType<typeof vi.fn>;
|
|
67
67
|
createCell: ReturnType<typeof vi.fn>;
|
|
68
|
-
prepareForRun: ReturnType<typeof vi.fn>;
|
|
69
|
-
sendRun: ReturnType<typeof vi.fn>;
|
|
70
68
|
store: ReturnType<typeof getDefaultStore>;
|
|
71
69
|
};
|
|
72
70
|
|
|
@@ -82,8 +80,6 @@ describe("EditNotebookTool", () => {
|
|
|
82
80
|
store.set(stagedAICellsAtom, new Map(current).set(cellId, edit));
|
|
83
81
|
}),
|
|
84
82
|
createCell: vi.fn(),
|
|
85
|
-
prepareForRun: vi.fn(),
|
|
86
|
-
sendRun: vi.fn().mockResolvedValue(null),
|
|
87
83
|
store,
|
|
88
84
|
};
|
|
89
85
|
tool = new EditNotebookTool();
|
|
@@ -100,7 +96,7 @@ describe("EditNotebookTool", () => {
|
|
|
100
96
|
it("should have correct metadata", () => {
|
|
101
97
|
expect(tool.name).toBe("edit_notebook_tool");
|
|
102
98
|
expect(tool.description).toBeDefined();
|
|
103
|
-
expect(tool.description.baseDescription).toContain("
|
|
99
|
+
expect(tool.description.baseDescription).toContain("Propose cell edits");
|
|
104
100
|
expect(tool.schema).toBeDefined();
|
|
105
101
|
expect(tool.outputSchema).toBeDefined();
|
|
106
102
|
expect(tool.mode).toEqual(["agent"]);
|
|
@@ -10,6 +10,23 @@ import { TestFrontendTool } from "../sample-tool";
|
|
|
10
10
|
const INVALID_KEYS_IN_SCHEMA_PARAMS = new Set(["anyOf", "oneOf"]);
|
|
11
11
|
|
|
12
12
|
describe("FrontendToolRegistry", () => {
|
|
13
|
+
it("only offers cell proposals with Suggest edits access", () => {
|
|
14
|
+
expect(
|
|
15
|
+
Object.fromEntries(
|
|
16
|
+
COPILOT_MODES.map((mode) => [
|
|
17
|
+
mode,
|
|
18
|
+
FRONTEND_TOOL_REGISTRY.getToolSchemas(mode).map((tool) => tool.name),
|
|
19
|
+
]),
|
|
20
|
+
),
|
|
21
|
+
).toEqual({
|
|
22
|
+
manual: [],
|
|
23
|
+
ask: [],
|
|
24
|
+
agent: ["edit_notebook_tool"],
|
|
25
|
+
code_mode: [],
|
|
26
|
+
});
|
|
27
|
+
expect(FRONTEND_TOOL_REGISTRY.has("run_stale_cells_tool")).toBe(false);
|
|
28
|
+
});
|
|
29
|
+
|
|
13
30
|
it("registers tools via constructor and supports has()", () => {
|
|
14
31
|
const registry = new FrontendToolRegistry([new TestFrontendTool()]);
|
|
15
32
|
expect(registry.has("test_frontend_tool")).toBe(true);
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
import type { CreateCell } from "@/core/cells/actions";
|
|
5
5
|
import type { CellId } from "@/core/cells/ids";
|
|
6
|
-
import type { ExecuteCellsRequest } from "@/core/network/types";
|
|
7
6
|
import type { JotaiStore } from "@/core/state/jotai";
|
|
8
7
|
import type { Edit } from "../staged-cells";
|
|
9
8
|
import type { CopilotMode } from "./registry";
|
|
@@ -67,9 +66,6 @@ export class ToolExecutionError extends Error {
|
|
|
67
66
|
}
|
|
68
67
|
}
|
|
69
68
|
|
|
70
|
-
// Can be any input
|
|
71
|
-
export type EmptyToolInput = unknown;
|
|
72
|
-
|
|
73
69
|
/**
|
|
74
70
|
* Base interface for tool output responses.
|
|
75
71
|
* Mirrors the SuccessResult dataclass from marimo/_ai/_tools/types.py
|
|
@@ -114,8 +110,6 @@ export interface ToolNotebookContext {
|
|
|
114
110
|
store: JotaiStore;
|
|
115
111
|
addStagedCell: (payload: { cellId: CellId; edit: Edit }) => void;
|
|
116
112
|
createCell: CreateCell;
|
|
117
|
-
prepareForRun: (payload: { cellId: CellId }) => void;
|
|
118
|
-
sendRun: (request: ExecuteCellsRequest) => Promise<null>;
|
|
119
113
|
}
|
|
120
114
|
|
|
121
115
|
export interface AiTool<TIn, TOut> {
|
|
@@ -21,7 +21,7 @@ import type { CopilotMode } from "./registry";
|
|
|
21
21
|
|
|
22
22
|
const description: ToolDescription = {
|
|
23
23
|
baseDescription:
|
|
24
|
-
"
|
|
24
|
+
"Propose cell edits for the user to review in the current notebook. You should prefer to create new cells unless you need to edit existing cells. Call this tool multiple times to perform multiple edits. Separate code into logical individual cells to take advantage of the notebook's reactive execution model.",
|
|
25
25
|
prerequisites: [
|
|
26
26
|
"If you are updating existing cells, you need the cellIds. If they are not known, call the lightweight_cell_map_tool to find out.",
|
|
27
27
|
],
|
|
@@ -254,7 +254,6 @@ export class EditNotebookTool implements AiTool<
|
|
|
254
254
|
next_steps: [
|
|
255
255
|
"If you need to perform more edits, call this tool again.",
|
|
256
256
|
"You should use the lint notebook tool to check for errors and lint issues. Fix them by editing the notebook.",
|
|
257
|
-
"You should use the run stale cells tool to run the cells that have been edited or newly added. This allows you to see the output of the cells and fix any errors.",
|
|
258
257
|
],
|
|
259
258
|
};
|
|
260
259
|
};
|
|
@@ -9,7 +9,6 @@ import {
|
|
|
9
9
|
type ToolNotebookContext,
|
|
10
10
|
} from "./base";
|
|
11
11
|
import { EditNotebookTool } from "./edit-notebook-tool";
|
|
12
|
-
import { RunStaleCellsTool } from "./run-cells-tool";
|
|
13
12
|
import { formatToolDescription } from "./utils";
|
|
14
13
|
|
|
15
14
|
export type AnyZodObject = ZodObject<z.ZodRawShape>;
|
|
@@ -148,5 +147,4 @@ export class FrontendToolRegistry {
|
|
|
148
147
|
|
|
149
148
|
export const FRONTEND_TOOL_REGISTRY = new FrontendToolRegistry([
|
|
150
149
|
new EditNotebookTool(),
|
|
151
|
-
new RunStaleCellsTool(),
|
|
152
150
|
]);
|
|
@@ -16,6 +16,11 @@ import {
|
|
|
16
16
|
UserConfigSchema,
|
|
17
17
|
} from "../config-schema";
|
|
18
18
|
|
|
19
|
+
test("legacy Manual config resolves to Read only", () => {
|
|
20
|
+
const config = UserConfigSchema.parse({ ai: { mode: "manual" } });
|
|
21
|
+
expect(config).toEqual(UserConfigSchema.parse({ ai: { mode: "ask" } }));
|
|
22
|
+
});
|
|
23
|
+
|
|
19
24
|
test("default AppConfig", () => {
|
|
20
25
|
const defaultConfig = AppConfigSchema.parse({});
|
|
21
26
|
expect(defaultConfig).toMatchInlineSnapshot(`
|
|
@@ -51,7 +56,7 @@ test("default UserConfig - empty", () => {
|
|
|
51
56
|
"custom_providers": {},
|
|
52
57
|
"enabled": true,
|
|
53
58
|
"inline_tooltip": false,
|
|
54
|
-
"mode": "
|
|
59
|
+
"mode": "ask",
|
|
55
60
|
"models": {
|
|
56
61
|
"custom_models": [],
|
|
57
62
|
"displayed_models": [],
|
|
@@ -128,7 +133,7 @@ test("default UserConfig - one level", () => {
|
|
|
128
133
|
"custom_providers": {},
|
|
129
134
|
"enabled": true,
|
|
130
135
|
"inline_tooltip": false,
|
|
131
|
-
"mode": "
|
|
136
|
+
"mode": "ask",
|
|
132
137
|
"models": {
|
|
133
138
|
"custom_models": [],
|
|
134
139
|
"displayed_models": [],
|