@marimo-team/islands 0.23.9-dev9 → 0.23.10-dev0
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-OzrfMM5L.js → ConnectedDataExplorerComponent-CyV83R2m.js} +4 -4
- package/dist/assets/__vite-browser-external-Ci2ZQfXU.js +1 -0
- package/dist/assets/{worker-CpBbwbQo.js → worker-ip3AI_sN.js} +2 -2
- package/dist/{chat-ui-BDI3FMI8.js → chat-ui-ChD4VvCo.js} +3060 -3033
- package/dist/{code-visibility-DgHF4q8X.js → code-visibility-CjGICDxg.js} +1368 -1204
- package/dist/{formats-DQ5qjo_Q.js → formats-DHxc-FdY.js} +1 -1
- package/dist/{glide-data-editor-DqRY9naW.js → glide-data-editor-BOmK9ETQ.js} +2 -2
- package/dist/{html-to-image-CiSinpSR.js → html-to-image-BHv7CEU_.js} +2145 -2153
- package/dist/{input-CZD2z6X2.js → input-_2sjvfne.js} +1 -1
- package/dist/main.js +680 -705
- package/dist/{mermaid-IU93XzmY.js → mermaid-lXOw5Py9.js} +2 -2
- package/dist/{process-output-5qJjMRKh.js → process-output-BvySRgli.js} +33 -25
- package/dist/{reveal-component-qpHJES_u.js → reveal-component-DVWED--8.js} +312 -291
- package/dist/{spec-a6DaqW__.js → spec-B96zNUEA.js} +1 -1
- package/dist/style.css +1 -1
- package/dist/{toDate-ZVVIBmdk.js → toDate-x-WRDCH7.js} +1 -1
- package/dist/{useAsyncData-C008zUPi.js → useAsyncData-iRgKDT5s.js} +1 -1
- package/dist/{useDeepCompareMemoize-BrA3_n61.js → useDeepCompareMemoize-CkQ57VS2.js} +1 -1
- package/dist/{useLifecycle-BNaoJ5a4.js → useLifecycle-BBO9PIph.js} +1 -1
- package/dist/{useTheme-7O0YWlE5.js → useTheme-DHIrRQOe.js} +34 -21
- package/dist/{vega-component-DJNmOdUj.js → vega-component-Dq-SH463.js} +5 -5
- package/package.json +1 -1
- package/src/components/ai/__tests__/ai-utils.test.ts +43 -38
- package/src/components/ai/ai-model-dropdown.tsx +2 -2
- package/src/components/app-config/ai-config.tsx +147 -16
- package/src/components/app-config/user-config-form.tsx +37 -1
- package/src/components/chat/__tests__/chat-utils.test.ts +269 -0
- package/src/components/chat/chat-panel.tsx +38 -5
- package/src/components/chat/chat-utils.ts +14 -58
- package/src/components/data-table/TableBottomBar.tsx +5 -8
- package/src/components/data-table/__tests__/column-explorer.test.tsx +128 -0
- package/src/components/data-table/__tests__/header-items.test.tsx +220 -10
- package/src/components/data-table/column-explorer-panel/column-explorer.tsx +95 -29
- package/src/components/data-table/column-header.tsx +17 -12
- package/src/components/data-table/data-table.tsx +4 -0
- package/src/components/data-table/export-actions.tsx +19 -12
- package/src/components/data-table/header-items.tsx +40 -16
- package/src/components/data-table/hooks/use-column-visibility.ts +14 -0
- package/src/components/data-table/schemas.ts +2 -2
- package/src/components/data-table/table-explorer-panel/table-explorer-panel.tsx +16 -6
- package/src/components/databases/display.tsx +2 -0
- package/src/components/datasources/__tests__/utils.test.ts +82 -0
- package/src/components/datasources/utils.ts +16 -15
- package/src/components/editor/Disconnected.tsx +1 -60
- package/src/components/editor/__tests__/viewer-banner.test.tsx +89 -0
- package/src/components/editor/actions/pair-with-agent-modal.tsx +1 -0
- package/src/components/editor/actions/useCellActionButton.tsx +3 -3
- package/src/components/editor/actions/useNotebookActions.tsx +5 -2
- package/src/components/editor/cell/code/cell-editor.tsx +25 -5
- package/src/components/editor/chrome/types.ts +13 -6
- package/src/components/editor/chrome/wrapper/app-chrome.tsx +6 -4
- package/src/components/editor/chrome/wrapper/footer-items/ai-status.tsx +10 -1
- package/src/components/editor/chrome/wrapper/sidebar.tsx +7 -5
- package/src/components/editor/errors/auto-fix.tsx +3 -3
- package/src/components/editor/header/__tests__/status.test.tsx +0 -15
- package/src/components/editor/header/app-header.tsx +1 -4
- package/src/components/editor/header/status.tsx +4 -13
- package/src/components/editor/navigation/__tests__/navigation.test.ts +15 -0
- package/src/components/editor/navigation/navigation.ts +5 -0
- package/src/components/editor/output/MarimoErrorOutput.tsx +103 -25
- package/src/components/editor/output/MarimoTracebackOutput.tsx +28 -39
- package/src/components/editor/renderers/cell-array.tsx +27 -24
- package/src/components/editor/renderers/slides-layout/__tests__/compute-slide-cells.test.ts +30 -17
- package/src/components/editor/renderers/slides-layout/compute-slide-cells.ts +17 -8
- package/src/components/editor/renderers/slides-layout/slides-layout.tsx +10 -12
- package/src/components/editor/viewer-banner.tsx +82 -0
- package/src/components/slides/minimap.tsx +45 -9
- package/src/components/slides/reveal-component.tsx +82 -37
- package/src/components/slides/slide-cell-view.tsx +12 -1
- package/src/components/slides/slide-form.tsx +11 -3
- package/src/components/static-html/static-banner.tsx +28 -22
- package/src/core/ai/__tests__/model-registry.test.ts +72 -60
- package/src/core/ai/model-registry.ts +33 -28
- package/src/core/cells/__tests__/actions.test.ts +48 -0
- package/src/core/cells/actions.ts +5 -6
- package/src/core/codemirror/__tests__/setup.test.ts +29 -0
- package/src/core/codemirror/cells/traceback-decorations.ts +1 -1
- package/src/core/codemirror/cm.ts +50 -3
- package/src/core/codemirror/completion/hints.ts +4 -1
- package/src/core/codemirror/format.ts +1 -0
- package/src/core/codemirror/keymaps/vim.ts +63 -0
- package/src/core/codemirror/language/languages/sql/sql.ts +1 -0
- package/src/core/codemirror/language/languages/sql/utils.ts +2 -0
- package/src/core/config/__tests__/config-schema.test.ts +4 -0
- package/src/core/config/config-schema.ts +4 -0
- package/src/core/config/config.ts +16 -0
- package/src/core/edit-app.tsx +3 -0
- package/src/core/islands/bootstrap.ts +2 -0
- package/src/core/kernel/__tests__/handlers.test.ts +5 -0
- package/src/core/websocket/__tests__/useMarimoKernelConnection.test.ts +0 -13
- package/src/core/websocket/types.ts +0 -6
- package/src/core/websocket/useMarimoKernelConnection.tsx +3 -12
- package/src/css/app/Cell.css +0 -1
- package/src/plugins/impl/DataTablePlugin.tsx +48 -22
- package/src/plugins/impl/chat/ChatPlugin.tsx +7 -1
- package/src/plugins/impl/chat/__tests__/chat-ui.test.ts +278 -0
- package/src/plugins/impl/chat/chat-ui.tsx +106 -59
- package/src/plugins/impl/chat/types.ts +5 -0
- package/src/utils/__tests__/json-parser.test.ts +1 -69
- package/src/utils/json/json-parser.ts +0 -30
- package/dist/assets/__vite-browser-external-CAdMKBac.js +0 -1
|
@@ -6,7 +6,7 @@ import { _ as Logger } from "./button-C5K9fIPF.js";
|
|
|
6
6
|
import { t as require_compiler_runtime } from "./compiler-runtime-CEbnTgxf.js";
|
|
7
7
|
import { u as createLucideIcon } from "./dist-C1BYNeCR.js";
|
|
8
8
|
import { r as KnownQueryParams } from "./constants-T20xxyNf.js";
|
|
9
|
-
import {
|
|
9
|
+
import { b as atom, d as store, m as isIslands, p as waitFor } from "./useTheme-DHIrRQOe.js";
|
|
10
10
|
import { t as invariant } from "./invariant-wRzNXIsJ.js";
|
|
11
11
|
var CircleQuestionMark = createLucideIcon("circle-question-mark", [
|
|
12
12
|
["circle", {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { s as __toESM } from "./chunk-BNovOVIE.js";
|
|
2
2
|
import { t as require_react } from "./react-DA-nE2FX.js";
|
|
3
3
|
import { t as require_compiler_runtime } from "./compiler-runtime-CEbnTgxf.js";
|
|
4
|
-
import {
|
|
4
|
+
import { T as useEvent_default } from "./useTheme-DHIrRQOe.js";
|
|
5
5
|
import { t as invariant } from "./invariant-wRzNXIsJ.js";
|
|
6
6
|
var import_compiler_runtime = require_compiler_runtime(), import_react = /* @__PURE__ */ __toESM(require_react(), 1), Result = {
|
|
7
7
|
error(e, s) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { s as __toESM } from "./chunk-BNovOVIE.js";
|
|
2
2
|
import { t as require_react } from "./react-DA-nE2FX.js";
|
|
3
|
-
import {
|
|
3
|
+
import { w as dequal } from "./useTheme-DHIrRQOe.js";
|
|
4
4
|
var import_react = /* @__PURE__ */ __toESM(require_react(), 1);
|
|
5
5
|
function useDeepCompareMemoize(e) {
|
|
6
6
|
let i = import_react.useRef(e);
|
|
@@ -4,7 +4,7 @@ import { t as require_react } from "./react-DA-nE2FX.js";
|
|
|
4
4
|
import { t as require_compiler_runtime } from "./compiler-runtime-CEbnTgxf.js";
|
|
5
5
|
import { u as createLucideIcon } from "./dist-C1BYNeCR.js";
|
|
6
6
|
import { t as require_jsx_runtime } from "./jsx-runtime-DebpN0FN.js";
|
|
7
|
-
import {
|
|
7
|
+
import { b as atom, v as useSetAtom } from "./useTheme-DHIrRQOe.js";
|
|
8
8
|
var Calendar = createLucideIcon("calendar", [
|
|
9
9
|
["path", {
|
|
10
10
|
d: "M8 2v4",
|
|
@@ -556,6 +556,7 @@ const UserConfigSchema = looseObject({
|
|
|
556
556
|
completion: object({
|
|
557
557
|
activate_on_typing: boolean().prefault(true),
|
|
558
558
|
signature_hint_on_typing: boolean().prefault(false),
|
|
559
|
+
auto_close_pairs: boolean().prefault(true),
|
|
559
560
|
copilot: union([boolean(), _enum([
|
|
560
561
|
"github",
|
|
561
562
|
"codeium",
|
|
@@ -605,7 +606,9 @@ const UserConfigSchema = looseObject({
|
|
|
605
606
|
}).prefault({}),
|
|
606
607
|
package_management: looseObject({ manager: _enum(PackageManagerNames).prefault("pip") }).prefault({}),
|
|
607
608
|
ai: looseObject({
|
|
609
|
+
enabled: boolean().prefault(true),
|
|
608
610
|
rules: string().prefault(""),
|
|
611
|
+
max_tokens: number().int().positive().nullable().optional(),
|
|
609
612
|
mode: _enum(COPILOT_MODES).prefault("manual"),
|
|
610
613
|
inline_tooltip: boolean().prefault(false),
|
|
611
614
|
open_ai: AiConfigSchema.optional(),
|
|
@@ -640,7 +643,8 @@ const UserConfigSchema = looseObject({
|
|
|
640
643
|
}).prefault(() => ({})),
|
|
641
644
|
sharing: looseObject({
|
|
642
645
|
html: boolean().optional(),
|
|
643
|
-
wasm: boolean().optional()
|
|
646
|
+
wasm: boolean().optional(),
|
|
647
|
+
molab: boolean().optional()
|
|
644
648
|
}).optional(),
|
|
645
649
|
mcp: looseObject({ presets: array(_enum(["marimo", "context7"])).optional() }).optional().prefault({})
|
|
646
650
|
}).partial().prefault(() => ({
|
|
@@ -704,13 +708,21 @@ function useResolvedMarimoConfig() {
|
|
|
704
708
|
function getResolvedMarimoConfig() {
|
|
705
709
|
return store.get(resolvedMarimoConfigAtom);
|
|
706
710
|
}
|
|
707
|
-
|
|
711
|
+
atom((e) => isAiEnabled(e(resolvedMarimoConfigAtom))), atom((e) => isAiModelConfigured(e(resolvedMarimoConfigAtom)));
|
|
712
|
+
const aiFeaturesEnabledAtom = atom((e) => isAiFeatureEnabled(e(resolvedMarimoConfigAtom)));
|
|
708
713
|
atom((e) => e(resolvedMarimoConfigAtom).display.code_editor_font_size);
|
|
709
714
|
const localeAtom = atom((e) => e(resolvedMarimoConfigAtom).display.locale);
|
|
710
715
|
function isAiEnabled(e) {
|
|
716
|
+
var _a;
|
|
717
|
+
return ((_a = e.ai) == null ? void 0 : _a.enabled) !== false;
|
|
718
|
+
}
|
|
719
|
+
function isAiModelConfigured(e) {
|
|
711
720
|
var _a, _b, _c, _d, _e, _f;
|
|
712
721
|
return !!((_b = (_a = e.ai) == null ? void 0 : _a.models) == null ? void 0 : _b.chat_model) || !!((_d = (_c = e.ai) == null ? void 0 : _c.models) == null ? void 0 : _d.edit_model) || !!((_f = (_e = e.ai) == null ? void 0 : _e.models) == null ? void 0 : _f.autocomplete_model);
|
|
713
722
|
}
|
|
723
|
+
function isAiFeatureEnabled(e) {
|
|
724
|
+
return isAiEnabled(e) && isAiModelConfigured(e);
|
|
725
|
+
}
|
|
714
726
|
const appConfigAtom = atom(parseAppConfig({}));
|
|
715
727
|
atom((e) => e(appConfigAtom).width), atom((e) => {
|
|
716
728
|
var _a, _b;
|
|
@@ -777,28 +789,29 @@ function useTheme() {
|
|
|
777
789
|
return e[1] === j ? M = e[2] : (M = { theme: j }, e[1] = j, e[2] = M), M;
|
|
778
790
|
}
|
|
779
791
|
export {
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
792
|
+
getBuildingBlocks as C,
|
|
793
|
+
buildStore as S,
|
|
794
|
+
useEvent_default as T,
|
|
795
|
+
useAtomValue as _,
|
|
783
796
|
getResolvedMarimoConfig as a,
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
797
|
+
atom as b,
|
|
798
|
+
useResolvedMarimoConfig as c,
|
|
799
|
+
store as d,
|
|
800
|
+
useJotaiEffect as f,
|
|
801
|
+
useAtom as g,
|
|
802
|
+
Provider as h,
|
|
790
803
|
autoInstantiateAtom as i,
|
|
791
|
-
|
|
792
|
-
|
|
804
|
+
AppConfigSchema as l,
|
|
805
|
+
isIslands as m,
|
|
793
806
|
useTheme as n,
|
|
794
807
|
localeAtom as o,
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
808
|
+
waitFor as p,
|
|
809
|
+
aiFeaturesEnabledAtom as r,
|
|
810
|
+
resolvedMarimoConfigAtom as s,
|
|
798
811
|
resolvedThemeAtom as t,
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
812
|
+
createDeepEqualAtom as u,
|
|
813
|
+
useSetAtom as v,
|
|
814
|
+
dequal as w,
|
|
815
|
+
createStore as x,
|
|
816
|
+
useStore as y
|
|
804
817
|
};
|
|
@@ -2,23 +2,23 @@ import { s as __toESM } from "./chunk-BNovOVIE.js";
|
|
|
2
2
|
import { _ as Logger, c as Objects, g as cn, h as Events } from "./button-C5K9fIPF.js";
|
|
3
3
|
import { t as require_react } from "./react-DA-nE2FX.js";
|
|
4
4
|
import { t as require_compiler_runtime } from "./compiler-runtime-CEbnTgxf.js";
|
|
5
|
-
import { c as asRemoteURL, v as CircleQuestionMark } from "./toDate-
|
|
5
|
+
import { c as asRemoteURL, v as CircleQuestionMark } from "./toDate-x-WRDCH7.js";
|
|
6
6
|
import "./react-dom-BTJzcVJ9.js";
|
|
7
7
|
import { t as require_jsx_runtime } from "./jsx-runtime-DebpN0FN.js";
|
|
8
8
|
import "./zod-CoBiJ5v4.js";
|
|
9
9
|
import { n as ErrorBanner } from "./error-banner-5bz0L9hS.js";
|
|
10
10
|
import { t as Tooltip } from "./tooltip-C5FYOpQc.js";
|
|
11
11
|
import { i as debounce_default } from "./constants-T20xxyNf.js";
|
|
12
|
-
import {
|
|
12
|
+
import { T as useEvent_default, n as useTheme } from "./useTheme-DHIrRQOe.js";
|
|
13
13
|
import { s as uniq } from "./arrays-sEtDRoG4.js";
|
|
14
|
-
import { a as isValid, i as AlertTitle, n as Alert, t as arrow } from "./formats-
|
|
14
|
+
import { a as isValid, i as AlertTitle, n as Alert, t as arrow } from "./formats-DHxc-FdY.js";
|
|
15
15
|
import { n as formats } from "./vega-loader.browser-CZ-J8Py3.js";
|
|
16
16
|
import { a as getContainerWidth, n as vegaLoadData, s as tooltipHandler } from "./loader-BWLPpjKK.js";
|
|
17
17
|
import { t as j } from "./react-vega-B0sAlDTL.js";
|
|
18
18
|
import "./defaultLocale-u-3osm0P.js";
|
|
19
19
|
import "./defaultLocale-BoHTsDG6.js";
|
|
20
|
-
import { t as useAsyncData } from "./useAsyncData-
|
|
21
|
-
import { t as useDeepCompareMemoize } from "./useDeepCompareMemoize-
|
|
20
|
+
import { t as useAsyncData } from "./useAsyncData-iRgKDT5s.js";
|
|
21
|
+
import { t as useDeepCompareMemoize } from "./useDeepCompareMemoize-CkQ57VS2.js";
|
|
22
22
|
import { t as Semaphore } from "./semaphore-CNDGTzkX.js";
|
|
23
23
|
var import_compiler_runtime = require_compiler_runtime(), import_react = /* @__PURE__ */ __toESM(require_react(), 1);
|
|
24
24
|
function fixRelativeUrl(e) {
|
package/package.json
CHANGED
|
@@ -4,46 +4,51 @@ import type { AiModel } from "@marimo-team/llm-info";
|
|
|
4
4
|
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
5
5
|
import type { UserConfig } from "@/core/config/config-schema";
|
|
6
6
|
|
|
7
|
-
// Mock the models.json import
|
|
8
7
|
vi.mock("@marimo-team/llm-info/models.json", () => {
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
8
|
+
const make = (
|
|
9
|
+
overrides: Partial<AiModel> & Pick<AiModel, "name" | "model">,
|
|
10
|
+
): AiModel => ({
|
|
11
|
+
description: "",
|
|
12
|
+
roles: ["chat", "edit"],
|
|
13
|
+
capabilities: [],
|
|
14
|
+
input_types: [],
|
|
15
|
+
output_types: [],
|
|
16
|
+
release_date: "1970-01-01",
|
|
17
|
+
...overrides,
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
const models: Record<string, AiModel[]> = {
|
|
21
|
+
openai: [
|
|
22
|
+
make({
|
|
23
|
+
name: "GPT-4",
|
|
24
|
+
model: "gpt-4",
|
|
25
|
+
description: "OpenAI GPT-4 model",
|
|
26
|
+
}),
|
|
27
|
+
],
|
|
28
|
+
anthropic: [
|
|
29
|
+
make({
|
|
30
|
+
name: "Claude 3",
|
|
31
|
+
model: "claude-3-sonnet",
|
|
32
|
+
description: "Anthropic Claude 3 Sonnet",
|
|
33
|
+
}),
|
|
34
|
+
],
|
|
35
|
+
google: [
|
|
36
|
+
make({
|
|
37
|
+
name: "Gemini Pro",
|
|
38
|
+
model: "gemini-pro",
|
|
39
|
+
description: "Google Gemini Pro model",
|
|
40
|
+
}),
|
|
41
|
+
],
|
|
42
|
+
ollama: [
|
|
43
|
+
make({
|
|
44
|
+
name: "Ollama Model",
|
|
45
|
+
model: "llama2",
|
|
46
|
+
description: "Ollama Llama 2 model",
|
|
47
|
+
}),
|
|
48
|
+
],
|
|
46
49
|
};
|
|
50
|
+
|
|
51
|
+
return { models };
|
|
47
52
|
});
|
|
48
53
|
|
|
49
54
|
// Must import after mock
|
|
@@ -305,7 +305,7 @@ const AiModelDropdownItem = ({
|
|
|
305
305
|
<div className="flex flex-row w-full items-center">
|
|
306
306
|
<span>{model.name}</span>
|
|
307
307
|
<div className="ml-auto">
|
|
308
|
-
{model.thinking && (
|
|
308
|
+
{model.capabilities.includes("thinking") && (
|
|
309
309
|
<Tooltip content="Reasoning model">
|
|
310
310
|
<BrainIcon
|
|
311
311
|
className={`h-5 w-5 rounded-md p-1 ${getTagColour("thinking")}`}
|
|
@@ -362,7 +362,7 @@ export const AiModelInfoDisplay = ({
|
|
|
362
362
|
</div>
|
|
363
363
|
)}
|
|
364
364
|
|
|
365
|
-
{model.thinking && (
|
|
365
|
+
{model.capabilities.includes("thinking") && (
|
|
366
366
|
<div className="flex items-center gap-2">
|
|
367
367
|
<div className="w-2 h-2 bg-purple-500 rounded-full animate-pulse" />
|
|
368
368
|
<span className="text-xs text-muted-foreground">
|
|
@@ -509,7 +509,7 @@ const ModelInfoCard = ({ model }: { model: AiModel }) => {
|
|
|
509
509
|
<Tooltip content="Custom model">
|
|
510
510
|
{model.custom && <BotIcon className="h-4 w-4" />}
|
|
511
511
|
</Tooltip>
|
|
512
|
-
{model.thinking && (
|
|
512
|
+
{model.capabilities.includes("thinking") && (
|
|
513
513
|
<div
|
|
514
514
|
className={cn(
|
|
515
515
|
"flex items-center gap-1 rounded px-1 py-0.5 w-fit",
|
|
@@ -1253,6 +1253,13 @@ export const AiAssistConfig: React.FC<AiConfigProps> = ({
|
|
|
1253
1253
|
config,
|
|
1254
1254
|
onSubmit,
|
|
1255
1255
|
}) => {
|
|
1256
|
+
// Tracked locally rather than derived from the field value so that clearing
|
|
1257
|
+
// the input (a transient empty value, which commits `null`) does not disable
|
|
1258
|
+
// the input mid-edit and force the user to re-tick the Override checkbox.
|
|
1259
|
+
const [maxTokensEnabled, setMaxTokensEnabled] = useState(
|
|
1260
|
+
config.ai?.max_tokens != null,
|
|
1261
|
+
);
|
|
1262
|
+
|
|
1256
1263
|
return (
|
|
1257
1264
|
<SettingGroup>
|
|
1258
1265
|
<SettingSubtitle>AI Assistant</SettingSubtitle>
|
|
@@ -1279,6 +1286,71 @@ export const AiAssistConfig: React.FC<AiConfigProps> = ({
|
|
|
1279
1286
|
)}
|
|
1280
1287
|
/>
|
|
1281
1288
|
|
|
1289
|
+
<FormField
|
|
1290
|
+
control={form.control}
|
|
1291
|
+
name="ai.max_tokens"
|
|
1292
|
+
render={({ field }) => {
|
|
1293
|
+
return (
|
|
1294
|
+
<div className="flex flex-col gap-y-1">
|
|
1295
|
+
<div className="flex items-center gap-x-2">
|
|
1296
|
+
<FormItem className={formItemClasses}>
|
|
1297
|
+
<FormLabel className="font-normal">
|
|
1298
|
+
Max output tokens
|
|
1299
|
+
</FormLabel>
|
|
1300
|
+
<FormControl>
|
|
1301
|
+
<Input
|
|
1302
|
+
data-testid="ai-max-tokens-input"
|
|
1303
|
+
type="number"
|
|
1304
|
+
min={1}
|
|
1305
|
+
disabled={!maxTokensEnabled}
|
|
1306
|
+
className="w-28 h-6"
|
|
1307
|
+
value={field.value ?? (maxTokensEnabled ? "" : 32768)}
|
|
1308
|
+
onChange={(e) => {
|
|
1309
|
+
const n = Number.parseInt(e.target.value, 10);
|
|
1310
|
+
field.onChange(Number.isFinite(n) && n > 0 ? n : null);
|
|
1311
|
+
}}
|
|
1312
|
+
/>
|
|
1313
|
+
</FormControl>
|
|
1314
|
+
</FormItem>
|
|
1315
|
+
<FormItem className={formItemClasses}>
|
|
1316
|
+
<Checkbox
|
|
1317
|
+
data-testid="ai-max-tokens-checkbox"
|
|
1318
|
+
checked={maxTokensEnabled}
|
|
1319
|
+
onCheckedChange={(checked) => {
|
|
1320
|
+
const isChecked = checked === true;
|
|
1321
|
+
setMaxTokensEnabled(isChecked);
|
|
1322
|
+
// null signals delete to the server; cast because
|
|
1323
|
+
// UserConfig (OpenAPI-derived) types max_tokens as
|
|
1324
|
+
// `number | undefined`, but zod accepts `null`.
|
|
1325
|
+
const next = (
|
|
1326
|
+
isChecked ? (field.value ?? 32768) : null
|
|
1327
|
+
) as number | undefined;
|
|
1328
|
+
// shouldDirty: true forces RHF to keep this in
|
|
1329
|
+
// dirtyFields even when `next` happens to equal the
|
|
1330
|
+
// form's defaultValue (e.g. untick → tick when disk
|
|
1331
|
+
// started with 32768). Otherwise getDirtyValues
|
|
1332
|
+
// would skip it and the save body would be empty.
|
|
1333
|
+
form.setValue("ai.max_tokens", next, {
|
|
1334
|
+
shouldDirty: true,
|
|
1335
|
+
shouldTouch: true,
|
|
1336
|
+
});
|
|
1337
|
+
onSubmit(form.getValues());
|
|
1338
|
+
}}
|
|
1339
|
+
/>
|
|
1340
|
+
<FormLabel className="font-normal">Override</FormLabel>
|
|
1341
|
+
</FormItem>
|
|
1342
|
+
</div>
|
|
1343
|
+
|
|
1344
|
+
<FormDescription>
|
|
1345
|
+
Each provider sets its own max output tokens (Anthropic uses a
|
|
1346
|
+
recommended default). Adjust to control costs or enable more
|
|
1347
|
+
output.
|
|
1348
|
+
</FormDescription>
|
|
1349
|
+
</div>
|
|
1350
|
+
);
|
|
1351
|
+
}}
|
|
1352
|
+
/>
|
|
1353
|
+
|
|
1282
1354
|
<FormErrorsBanner />
|
|
1283
1355
|
<ModelSelector
|
|
1284
1356
|
label="Chat Model"
|
|
@@ -1777,6 +1849,38 @@ export type AiSettingsSubTab =
|
|
|
1777
1849
|
| "ai-models"
|
|
1778
1850
|
| "mcp";
|
|
1779
1851
|
|
|
1852
|
+
const AiEnabledConfig: React.FC<AiConfigProps> = ({ form, config }) => {
|
|
1853
|
+
return (
|
|
1854
|
+
<SettingGroup>
|
|
1855
|
+
<FormField
|
|
1856
|
+
control={form.control}
|
|
1857
|
+
name="ai.enabled"
|
|
1858
|
+
render={({ field }) => (
|
|
1859
|
+
<div className="flex flex-col gap-y-1">
|
|
1860
|
+
<FormItem className={formItemClasses}>
|
|
1861
|
+
<FormLabel className="font-normal">Enable AI features</FormLabel>
|
|
1862
|
+
<FormControl>
|
|
1863
|
+
<Checkbox
|
|
1864
|
+
data-testid="ai-enabled-checkbox"
|
|
1865
|
+
checked={field.value !== false}
|
|
1866
|
+
onCheckedChange={(checked) =>
|
|
1867
|
+
field.onChange(checked === true)
|
|
1868
|
+
}
|
|
1869
|
+
/>
|
|
1870
|
+
</FormControl>
|
|
1871
|
+
<IsOverridden userConfig={config} name="ai.enabled" />
|
|
1872
|
+
</FormItem>
|
|
1873
|
+
<FormDescription>
|
|
1874
|
+
When disabled, AI actions and panels are hidden from the marimo
|
|
1875
|
+
UI.
|
|
1876
|
+
</FormDescription>
|
|
1877
|
+
</div>
|
|
1878
|
+
)}
|
|
1879
|
+
/>
|
|
1880
|
+
</SettingGroup>
|
|
1881
|
+
);
|
|
1882
|
+
};
|
|
1883
|
+
|
|
1780
1884
|
export const AiConfig: React.FC<AiConfigProps> = ({
|
|
1781
1885
|
form,
|
|
1782
1886
|
config,
|
|
@@ -1785,18 +1889,30 @@ export const AiConfig: React.FC<AiConfigProps> = ({
|
|
|
1785
1889
|
// MCP is not supported in WASM
|
|
1786
1890
|
const wasm = isWasm();
|
|
1787
1891
|
const [activeTab, setActiveTab] = useAtom(aiSettingsSubTabAtom);
|
|
1892
|
+
const aiEnabled = useWatch({
|
|
1893
|
+
control: form.control,
|
|
1894
|
+
name: "ai.enabled",
|
|
1895
|
+
});
|
|
1896
|
+
const activeVisibleTab =
|
|
1897
|
+
aiEnabled === false && activeTab !== "ai-features"
|
|
1898
|
+
? "ai-features"
|
|
1899
|
+
: activeTab;
|
|
1788
1900
|
|
|
1789
1901
|
return (
|
|
1790
1902
|
<Tabs
|
|
1791
|
-
value={
|
|
1903
|
+
value={activeVisibleTab}
|
|
1792
1904
|
onValueChange={(value) => setActiveTab(value as AiSettingsSubTab)}
|
|
1793
1905
|
className="flex-1"
|
|
1794
1906
|
>
|
|
1795
1907
|
<TabsList className="mb-2">
|
|
1796
1908
|
<TabsTrigger value="ai-features">AI Features</TabsTrigger>
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1909
|
+
{aiEnabled !== false && (
|
|
1910
|
+
<>
|
|
1911
|
+
<TabsTrigger value="ai-providers">AI Providers</TabsTrigger>
|
|
1912
|
+
<TabsTrigger value="ai-models">AI Models</TabsTrigger>
|
|
1913
|
+
{!wasm && <TabsTrigger value="mcp">MCP</TabsTrigger>}
|
|
1914
|
+
</>
|
|
1915
|
+
)}
|
|
1800
1916
|
</TabsList>
|
|
1801
1917
|
|
|
1802
1918
|
<TabsContent value="ai-features">
|
|
@@ -1805,18 +1921,33 @@ export const AiConfig: React.FC<AiConfigProps> = ({
|
|
|
1805
1921
|
config={config}
|
|
1806
1922
|
onSubmit={onSubmit}
|
|
1807
1923
|
/>
|
|
1808
|
-
<
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
</TabsContent>
|
|
1813
|
-
<TabsContent value="ai-models">
|
|
1814
|
-
<AiModelDisplayConfig form={form} config={config} onSubmit={onSubmit} />
|
|
1924
|
+
<AiEnabledConfig form={form} config={config} onSubmit={onSubmit} />
|
|
1925
|
+
{aiEnabled !== false && (
|
|
1926
|
+
<AiAssistConfig form={form} config={config} onSubmit={onSubmit} />
|
|
1927
|
+
)}
|
|
1815
1928
|
</TabsContent>
|
|
1816
|
-
{
|
|
1817
|
-
|
|
1818
|
-
<
|
|
1819
|
-
|
|
1929
|
+
{aiEnabled !== false && (
|
|
1930
|
+
<>
|
|
1931
|
+
<TabsContent value="ai-providers">
|
|
1932
|
+
<AiProvidersConfig
|
|
1933
|
+
form={form}
|
|
1934
|
+
config={config}
|
|
1935
|
+
onSubmit={onSubmit}
|
|
1936
|
+
/>
|
|
1937
|
+
</TabsContent>
|
|
1938
|
+
<TabsContent value="ai-models">
|
|
1939
|
+
<AiModelDisplayConfig
|
|
1940
|
+
form={form}
|
|
1941
|
+
config={config}
|
|
1942
|
+
onSubmit={onSubmit}
|
|
1943
|
+
/>
|
|
1944
|
+
</TabsContent>
|
|
1945
|
+
{!wasm && (
|
|
1946
|
+
<TabsContent value="mcp">
|
|
1947
|
+
<MCPConfig form={form} onSubmit={onSubmit} />
|
|
1948
|
+
</TabsContent>
|
|
1949
|
+
)}
|
|
1950
|
+
</>
|
|
1820
1951
|
)}
|
|
1821
1952
|
</Tabs>
|
|
1822
1953
|
);
|
|
@@ -503,6 +503,42 @@ export const UserConfigForm: React.FC = () => {
|
|
|
503
503
|
</div>
|
|
504
504
|
)}
|
|
505
505
|
/>
|
|
506
|
+
<FormField
|
|
507
|
+
control={form.control}
|
|
508
|
+
name="completion.auto_close_pairs"
|
|
509
|
+
render={({ field }) => (
|
|
510
|
+
<div className="flex flex-col space-y-1">
|
|
511
|
+
<FormItem className={formItemClasses}>
|
|
512
|
+
<FormLabel className="font-normal">
|
|
513
|
+
Auto-close pairs
|
|
514
|
+
</FormLabel>
|
|
515
|
+
<FormControl>
|
|
516
|
+
<Checkbox
|
|
517
|
+
data-testid="auto-close-pairs-checkbox"
|
|
518
|
+
checked={field.value ?? true}
|
|
519
|
+
disabled={field.disabled}
|
|
520
|
+
onCheckedChange={(checked) => {
|
|
521
|
+
field.onChange(Boolean(checked));
|
|
522
|
+
}}
|
|
523
|
+
/>
|
|
524
|
+
</FormControl>
|
|
525
|
+
<FormMessage />
|
|
526
|
+
<IsOverridden
|
|
527
|
+
userConfig={config}
|
|
528
|
+
name="completion.auto_close_pairs"
|
|
529
|
+
/>
|
|
530
|
+
</FormItem>
|
|
531
|
+
<FormDescription>
|
|
532
|
+
Automatically insert closing brackets{" "}
|
|
533
|
+
<code className="text-xs">{"()"}</code>,{" "}
|
|
534
|
+
<code className="text-xs">{"[]"}</code>,{" "}
|
|
535
|
+
<code className="text-xs">{"{}"}</code>, and quotes{" "}
|
|
536
|
+
<code className="text-xs">{`""`}</code>,{" "}
|
|
537
|
+
<code className="text-xs">{`''`}</code> when opening one.
|
|
538
|
+
</FormDescription>
|
|
539
|
+
</div>
|
|
540
|
+
)}
|
|
541
|
+
/>
|
|
506
542
|
</SettingGroup>
|
|
507
543
|
<SettingGroup title="Language Servers">
|
|
508
544
|
<FormDescription>
|
|
@@ -1319,7 +1355,7 @@ export const UserConfigForm: React.FC = () => {
|
|
|
1319
1355
|
<Form {...form}>
|
|
1320
1356
|
<form
|
|
1321
1357
|
ref={formElement}
|
|
1322
|
-
onChange={form.handleSubmit(onSubmit)}
|
|
1358
|
+
onChange={form.handleSubmit((values) => onSubmit(values))}
|
|
1323
1359
|
className="flex text-pretty overflow-hidden"
|
|
1324
1360
|
>
|
|
1325
1361
|
<Tabs
|