@marimo-team/islands 0.14.18-dev37 → 0.14.18-dev39

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 (71) hide show
  1. package/dist/{ConnectedDataExplorerComponent-Agqj2ooM.js → ConnectedDataExplorerComponent-3RtvsK5H.js} +2 -2
  2. package/dist/{ImageComparisonComponent-DPGANUHl.js → ImageComparisonComponent-BNAZDH44.js} +1 -1
  3. package/dist/{_baseUniq-CpMSR4IQ.js → _baseUniq-BVfJUeQb.js} +1 -1
  4. package/dist/{any-language-editor-CFdNKVB5.js → any-language-editor-Ks7PGJCn.js} +1 -1
  5. package/dist/{architectureDiagram-SUXI7LT5-DtrTZbYk.js → architectureDiagram-SUXI7LT5-BolOAqtB.js} +5 -5
  6. package/dist/assets/{worker-IDMFdmDA.js → worker-COGufAQn.js} +70 -70
  7. package/dist/{blockDiagram-6J76NXCF-Cp-0RluB.js → blockDiagram-6J76NXCF-CWGz15YB.js} +5 -5
  8. package/dist/{c4Diagram-6F6E4RAY-DQ2kylH0.js → c4Diagram-6F6E4RAY-DiNVqHzw.js} +2 -2
  9. package/dist/{channel-BS-z-DLr.js → channel-94lD77dB.js} +1 -1
  10. package/dist/{chunk-353BL4L5-D0W0s9ka.js → chunk-353BL4L5-CETvj-tT.js} +1 -1
  11. package/dist/{chunk-67H74DCK-CA-VzWuj.js → chunk-67H74DCK-D5k3YQ75.js} +1 -1
  12. package/dist/{chunk-AACKK3MU-BHjbkUMB.js → chunk-AACKK3MU-CLcCi13Y.js} +1 -1
  13. package/dist/{chunk-BFAMUDN2-Dfk1hsa2.js → chunk-BFAMUDN2-DZ_4EPIC.js} +1 -1
  14. package/dist/{chunk-E2GYISFI-ATcFQCw7.js → chunk-E2GYISFI-D7WEFN0I.js} +1 -1
  15. package/dist/{chunk-OW32GOEJ-D5ZiaOi7.js → chunk-OW32GOEJ-xW1cu7Ta.js} +3 -3
  16. package/dist/{chunk-SKB7J2MH-C06x1AM-.js → chunk-SKB7J2MH-BCCadknO.js} +1 -1
  17. package/dist/{chunk-SZ463SBG-COrdHOzF.js → chunk-SZ463SBG-Da0noPdf.js} +4 -4
  18. package/dist/{classDiagram-v2-YAWTLIQI-ClXfLaA6.js → classDiagram-M3E45YP4-BgjOa5oq.js} +2 -2
  19. package/dist/{classDiagram-M3E45YP4-ClXfLaA6.js → classDiagram-v2-YAWTLIQI-BgjOa5oq.js} +2 -2
  20. package/dist/{clone-DVZ4x5LN.js → clone-Bu53USnE.js} +1 -1
  21. package/dist/{dagre-JOIXM2OF-CIM0a0_j.js → dagre-JOIXM2OF-lXTzFbYK.js} +6 -6
  22. package/dist/{data-grid-overlay-editor-B_f-XmH8.js → data-grid-overlay-editor-nbxFCqIc.js} +2 -2
  23. package/dist/{diagram-5UYTHUR4-CJ5-7BUI.js → diagram-5UYTHUR4-DpsLtTC4.js} +3 -3
  24. package/dist/{diagram-VMROVX33-xCZwSfL2.js → diagram-VMROVX33-Dl99FSjs.js} +5 -5
  25. package/dist/{diagram-ZTM2IBQH-BwMLyLo9.js → diagram-ZTM2IBQH-C6IZmxtP.js} +3 -3
  26. package/dist/{erDiagram-3M52JZNH-DChgswtA.js → erDiagram-3M52JZNH-BJAfHqCe.js} +4 -4
  27. package/dist/{flowDiagram-KYDEHFYC-D041bGnc.js → flowDiagram-KYDEHFYC-DQ4ZD8eZ.js} +5 -5
  28. package/dist/{ganttDiagram-EK5VF46D-B7M48jZ_.js → ganttDiagram-EK5VF46D-BiUE232l.js} +4 -4
  29. package/dist/{gitGraphDiagram-GW3U2K7C-QA3k2S0X.js → gitGraphDiagram-GW3U2K7C-DcXDrK5d.js} +4 -4
  30. package/dist/{glide-data-editor-uxbE445v.js → glide-data-editor-BCANW8UP.js} +3 -3
  31. package/dist/{graph-CU2kk2IH.js → graph-31Sn9Cfm.js} +3 -3
  32. package/dist/{index-RWaQzJSd.js → index-65RV0mXZ.js} +1 -1
  33. package/dist/{index-_qCoCBPD.js → index-BqBV4ZfA.js} +1 -1
  34. package/dist/{index-ByAs2ixu.js → index-Cfkm9mAj.js} +1 -1
  35. package/dist/{index-CtEeLUrb.js → index-pQ3WHloE.js} +1 -1
  36. package/dist/{index-B-Ueew3R.js → index-vELYSc2I.js} +3 -3
  37. package/dist/{infoDiagram-LHK5PUON-BMLaF5rR.js → infoDiagram-LHK5PUON-BmBFxuqN.js} +2 -2
  38. package/dist/{journeyDiagram-EWQZEKCU-DdcK-ELK.js → journeyDiagram-EWQZEKCU-yNJKWCpQ.js} +3 -3
  39. package/dist/{kanban-definition-ZSS6B67P-DlAqmjND.js → kanban-definition-ZSS6B67P-7VUAd5gR.js} +2 -2
  40. package/dist/{layout-DyfYCx-G.js → layout-DANNdOvY.js} +4 -4
  41. package/dist/{linear-60P382Ey.js → linear-C63wbs-u.js} +1 -1
  42. package/dist/{main-YndPucih.js → main-kUMPG4DJ.js} +12584 -12584
  43. package/dist/main.js +1 -1
  44. package/dist/{mermaid-bHfZQVOX.js → mermaid-CN_OTOT4.js} +29 -29
  45. package/dist/{min-dlJMdVHY.js → min-CQkFw4Vk.js} +2 -2
  46. package/dist/{mindmap-definition-6CBA2TL7-Dr0M7ZVJ.js → mindmap-definition-6CBA2TL7-B0Vipg3p.js} +2 -2
  47. package/dist/{number-overlay-editor-OG-7Y1Dx.js → number-overlay-editor-0wXc3j78.js} +2 -2
  48. package/dist/{pieDiagram-NIOCPIFQ-BmGwhj4Q.js → pieDiagram-NIOCPIFQ-DVmPkj3p.js} +3 -3
  49. package/dist/{quadrantDiagram-2OG54O6I-XUAIoa5o.js → quadrantDiagram-2OG54O6I-OyhnTUp0.js} +2 -2
  50. package/dist/{react-plotly-DDGiywdq.js → react-plotly-TMdrxs3a.js} +1 -1
  51. package/dist/{requirementDiagram-QOLK2EJ7-0ca9BSWg.js → requirementDiagram-QOLK2EJ7-CY3Oayeg.js} +3 -3
  52. package/dist/{sankeyDiagram-4UZDY2LN-FJagmBot.js → sankeyDiagram-4UZDY2LN-DZHba4BC.js} +1 -1
  53. package/dist/{sequenceDiagram-SKLFT4DO-CRzbF56l.js → sequenceDiagram-SKLFT4DO-nMdmIMLD.js} +3 -3
  54. package/dist/{slides-component-DVst__vX.js → slides-component-BABoru31.js} +1 -1
  55. package/dist/{stateDiagram-MI5ZYTHO-DIe7eGfc.js → stateDiagram-MI5ZYTHO-C4-gl_HF.js} +4 -4
  56. package/dist/{stateDiagram-v2-5AN5P6BG-C_re8HoC.js → stateDiagram-v2-5AN5P6BG-RVtW0Jhm.js} +2 -2
  57. package/dist/{time-AgleFMg4.js → time-Bc9yXFIT.js} +2 -2
  58. package/dist/{timeline-definition-MYPXXCX6-DTQKnm70.js → timeline-definition-MYPXXCX6-CXtqBPWZ.js} +1 -1
  59. package/dist/{treemap-75Q7IDZK-DsSdguo2.js → treemap-75Q7IDZK-dEViVYg5.js} +5 -5
  60. package/dist/{vega-component-DnXRdUc_.js → vega-component-Dx_TVBpx.js} +2 -2
  61. package/dist/{xychartDiagram-H2YORKM3-MLsV7Keh.js → xychartDiagram-H2YORKM3-D7xC_ETv.js} +2 -2
  62. package/package.json +1 -1
  63. package/src/components/ai/ai-model-dropdown.tsx +1 -1
  64. package/src/components/chat/chat-panel.tsx +8 -51
  65. package/src/components/editor/ai/add-cell-with-ai.tsx +114 -60
  66. package/src/components/editor/ai/ai-completion-editor.tsx +27 -15
  67. package/src/core/ai/config.ts +76 -0
  68. package/src/core/config/config-schema.ts +18 -12
  69. package/src/core/static/__tests__/files.test.ts +311 -0
  70. package/src/core/static/files.ts +35 -33
  71. package/src/plugins/impl/chat/chat-ui.tsx +0 -3
@@ -16,10 +16,11 @@ import ReactCodeMirror, {
16
16
  type ReactCodeMirrorRef,
17
17
  } from "@uiw/react-codemirror";
18
18
  import { useCompletion } from "ai/react";
19
- import { useAtom, useStore } from "jotai";
19
+ import { useAtom, useAtomValue, useStore } from "jotai";
20
20
  import { atomWithStorage } from "jotai/utils";
21
21
  import {
22
22
  ChevronsUpDown,
23
+ DatabaseIcon,
23
24
  Loader2Icon,
24
25
  SendHorizontal,
25
26
  SparklesIcon,
@@ -27,22 +28,28 @@ import {
27
28
  } from "lucide-react";
28
29
  import { useMemo, useState } from "react";
29
30
  import useEvent from "react-use-event-hook";
31
+ import { AIModelDropdown } from "@/components/ai/ai-model-dropdown";
30
32
  import { Button } from "@/components/ui/button";
31
33
  import {
32
34
  DropdownMenu,
33
35
  DropdownMenuContent,
34
36
  DropdownMenuItem,
37
+ DropdownMenuSeparator,
35
38
  DropdownMenuTrigger,
36
39
  } from "@/components/ui/dropdown-menu";
37
40
  import { toast } from "@/components/ui/use-toast";
41
+ import { useModelChange } from "@/core/ai/config";
38
42
  import { resourceExtension } from "@/core/codemirror/ai/resources";
39
43
  import { customPythonLanguageSupport } from "@/core/codemirror/language/languages/python";
40
44
  import { SQLLanguageAdapter } from "@/core/codemirror/language/languages/sql/sql";
45
+ import { aiAtom } from "@/core/config/config";
46
+ import { DEFAULT_AI_MODEL } from "@/core/config/config-schema";
41
47
  import { useRuntimeManager } from "@/core/runtime/config";
42
- import { type ResolvedTheme, useTheme } from "@/theme/useTheme";
48
+ import { useTheme } from "@/theme/useTheme";
43
49
  import { cn } from "@/utils/cn";
44
50
  import { prettyError } from "@/utils/errors";
45
51
  import { useCellActions } from "../../../core/cells/cells";
52
+ import { PythonIcon } from "../cell/code/icons";
46
53
  import {
47
54
  getAICompletionBody,
48
55
  mentionsCompletionSource,
@@ -72,6 +79,10 @@ export const AddCellWithAI: React.FC<{
72
79
  const { theme } = useTheme();
73
80
  const runtimeManager = useRuntimeManager();
74
81
 
82
+ const ai = useAtomValue(aiAtom);
83
+ const editModel = ai?.models?.edit_model || DEFAULT_AI_MODEL;
84
+ const { saveModelChange } = useModelChange();
85
+
75
86
  const {
76
87
  completion,
77
88
  input,
@@ -109,32 +120,50 @@ export const AddCellWithAI: React.FC<{
109
120
  }
110
121
  };
111
122
 
123
+ const pythonIcon = (
124
+ <>
125
+ <PythonIcon className="size-4 mr-2" />
126
+ Python
127
+ </>
128
+ );
129
+
130
+ const sqlIcon = (
131
+ <>
132
+ <DatabaseIcon className="size-4 mr-2" />
133
+ SQL
134
+ </>
135
+ );
136
+
137
+ const languageDropdown = (
138
+ <DropdownMenu modal={false}>
139
+ <DropdownMenuTrigger asChild={true}>
140
+ <Button
141
+ variant="text"
142
+ className="ml-2"
143
+ size="xs"
144
+ data-testid="language-button"
145
+ >
146
+ {language === "python" ? pythonIcon : sqlIcon}
147
+ <ChevronsUpDown className="ml-1 h-3.5 w-3.5 text-muted-foreground/70" />
148
+ </Button>
149
+ </DropdownMenuTrigger>
150
+ <DropdownMenuContent align="center">
151
+ <div className="px-2 py-1 font-semibold">Select language</div>
152
+ <DropdownMenuSeparator />
153
+ <DropdownMenuItem onClick={() => setLanguage("python")}>
154
+ {pythonIcon}
155
+ </DropdownMenuItem>
156
+ <DropdownMenuItem onClick={() => setLanguage("sql")}>
157
+ {sqlIcon}
158
+ </DropdownMenuItem>
159
+ </DropdownMenuContent>
160
+ </DropdownMenu>
161
+ );
162
+
112
163
  const inputComponent = (
113
164
  <div className="flex items-center px-3">
114
- <SparklesIcon className="size-4 text-(--blue-11)" />
115
- <DropdownMenu modal={false}>
116
- <DropdownMenuTrigger asChild={true}>
117
- <Button
118
- variant="text"
119
- className="ml-2"
120
- size="xs"
121
- data-testid="language-button"
122
- >
123
- {language === "python" ? "Python" : "SQL"}
124
- <ChevronsUpDown className="ml-1 h-3.5 w-3.5 text-muted-foreground/70" />
125
- </Button>
126
- </DropdownMenuTrigger>
127
- <DropdownMenuContent align="center">
128
- <DropdownMenuItem onClick={() => setLanguage("python")}>
129
- Python
130
- </DropdownMenuItem>
131
- <DropdownMenuItem onClick={() => setLanguage("sql")}>
132
- SQL
133
- </DropdownMenuItem>
134
- </DropdownMenuContent>
135
- </DropdownMenu>
165
+ <SparklesIcon className="size-4 text-(--blue-11) mr-2" />
136
166
  <PromptInput
137
- theme={theme}
138
167
  onClose={() => {
139
168
  setCompletion("");
140
169
  onClose();
@@ -158,33 +187,10 @@ export const AddCellWithAI: React.FC<{
158
187
  Stop
159
188
  </Button>
160
189
  )}
161
- {!isLoading && completion && (
162
- <Button
163
- data-testid="accept-completion-button"
164
- variant="text"
165
- size="sm"
166
- className="mb-0"
167
- disabled={isLoading}
168
- onClick={() => {
169
- createNewCell({
170
- cellId: "__end__",
171
- before: false,
172
- code:
173
- language === "python"
174
- ? completion
175
- : SQLLanguageAdapter.fromQuery(completion),
176
- });
177
- setCompletion("");
178
- onClose();
179
- }}
180
- >
181
- <span className="text-(--grass-11) opacity-100">Accept</span>
182
- </Button>
183
- )}
184
190
  <Button variant="text" size="sm" onClick={submit} title="Submit">
185
191
  <SendHorizontal className="size-4" />
186
192
  </Button>
187
- <Button variant="text" size="sm" className="mb-0" onClick={onClose}>
193
+ <Button variant="text" size="sm" className="mb-0 px-1" onClick={onClose}>
188
194
  <XIcon className="size-4" />
189
195
  </Button>
190
196
  </div>
@@ -193,16 +199,65 @@ export const AddCellWithAI: React.FC<{
193
199
  return (
194
200
  <div className={cn("flex flex-col w-full gap-2 py-2")}>
195
201
  {inputComponent}
196
- {!completion && (
197
- <span className="text-xs text-muted-foreground px-3 flex flex-col gap-1">
198
- <span>
199
- You can mention <span className="text-(--cyan-11)">@dataframe</span>{" "}
200
- or <span className="text-(--cyan-11)">@sql_table</span> to pull
201
- additional context such as column names.
202
+ <div className="flex flex-row justify-between -mt-1 ml-1 mr-3">
203
+ {!completion && (
204
+ <span className="text-xs text-muted-foreground px-3 flex flex-col gap-1">
205
+ <span>
206
+ You can mention{" "}
207
+ <span className="text-(--cyan-11)">@dataframe</span> or{" "}
208
+ <span className="text-(--cyan-11)">@sql_table</span> to pull
209
+ additional context such as column names.
210
+ </span>
211
+ <span>Code from other cells is automatically included.</span>
202
212
  </span>
203
- <span>Code from other cells is automatically included.</span>
204
- </span>
205
- )}
213
+ )}
214
+ {completion && (
215
+ <>
216
+ <Button
217
+ data-testid="accept-completion-button"
218
+ variant="text"
219
+ size="sm"
220
+ className="mb-0"
221
+ onClick={() => {
222
+ createNewCell({
223
+ cellId: "__end__",
224
+ before: false,
225
+ code:
226
+ language === "python"
227
+ ? completion
228
+ : SQLLanguageAdapter.fromQuery(completion),
229
+ });
230
+ setCompletion("");
231
+ onClose();
232
+ }}
233
+ >
234
+ <span className="text-(--grass-11)">Accept</span>
235
+ </Button>
236
+ <Button
237
+ data-testid="decline-completion-button"
238
+ variant="text"
239
+ size="sm"
240
+ className="mb-0 pl-1"
241
+ onClick={() => setCompletion("")}
242
+ >
243
+ <span className="text-(--red-10)">Reject</span>
244
+ </Button>
245
+ </>
246
+ )}
247
+ <div className="ml-auto flex items-center gap-1">
248
+ {languageDropdown}
249
+ <AIModelDropdown
250
+ value={editModel}
251
+ onSelect={(model) => {
252
+ saveModelChange(model, "edit");
253
+ }}
254
+ triggerClassName="h-7 text-xs max-w-64"
255
+ iconSize="small"
256
+ forRole="edit"
257
+ />
258
+ </div>
259
+ </div>
260
+
206
261
  {completion && (
207
262
  <ReactCodeMirror
208
263
  value={completion}
@@ -230,7 +285,6 @@ interface PromptInputProps {
230
285
  onChange: (value: string) => void;
231
286
  onSubmit: (e: KeyboardEvent | undefined, value: string) => void;
232
287
  additionalCompletions?: AdditionalCompletions;
233
- theme: ResolvedTheme;
234
288
  maxHeight?: string;
235
289
  }
236
290
 
@@ -249,12 +303,12 @@ export const PromptInput = ({
249
303
  onSubmit,
250
304
  onClose,
251
305
  additionalCompletions,
252
- theme,
253
306
  maxHeight,
254
307
  }: PromptInputProps) => {
255
308
  const handleSubmit = onSubmit;
256
309
  const handleEscape = onClose;
257
310
  const store = useStore();
311
+ const { theme } = useTheme();
258
312
 
259
313
  const additionalCompletionsSource: CompletionSource = useEvent(
260
314
  (context: CompletionContext) => {
@@ -150,7 +150,6 @@ export const AiCompletionEditor: React.FC<Props> = ({
150
150
  <SparklesIcon className="text-(--blue-10) shrink-0" size={16} />
151
151
  <PromptInput
152
152
  inputRef={inputRef}
153
- theme={theme}
154
153
  onClose={() => {
155
154
  declineChange();
156
155
  setCompletion("");
@@ -178,20 +177,33 @@ export const AiCompletionEditor: React.FC<Props> = ({
178
177
  Stop
179
178
  </Button>
180
179
  )}
181
- {!isLoading && completion && (
182
- <Button
183
- data-testid="accept-completion-button"
184
- variant="text"
185
- size="xs"
186
- className="mb-0"
187
- disabled={isLoading}
188
- onClick={() => {
189
- acceptChange(completion);
190
- setCompletion("");
191
- }}
192
- >
193
- <span className="text-(--grass-11) opacity-100">Accept</span>
194
- </Button>
180
+ {completion && (
181
+ <>
182
+ <Button
183
+ data-testid="accept-completion-button"
184
+ variant="text"
185
+ size="xs"
186
+ className="mb-0"
187
+ disabled={isLoading}
188
+ onClick={() => {
189
+ acceptChange(completion);
190
+ setCompletion("");
191
+ }}
192
+ >
193
+ <span className="text-(--grass-11) opacity-100">Accept</span>
194
+ </Button>
195
+ <Button
196
+ data-testid="decline-completion-button"
197
+ variant="text"
198
+ size="xs"
199
+ className="mb-0 pl-1"
200
+ onClick={() => {
201
+ setCompletion("");
202
+ }}
203
+ >
204
+ <span className="text-(--red-10)">Reject</span>
205
+ </Button>
206
+ </>
195
207
  )}
196
208
  <div className="h-full w-px bg-border mx-2" />
197
209
  <Tooltip content="Include code from other cells">
@@ -0,0 +1,76 @@
1
+ /* Copyright 2024 Marimo. All rights reserved. */
2
+
3
+ import type { Role } from "@marimo-team/llm-info";
4
+ import { useAtom } from "jotai";
5
+ import type { QualifiedModelId } from "@/core/ai/ids/ids";
6
+ import { userConfigAtom } from "@/core/config/config";
7
+ import type { AIModelKey, UserConfig } from "@/core/config/config-schema";
8
+ import { useRequestClient } from "@/core/network/requests";
9
+
10
+ // Extract only the supported roles from the Role type
11
+ type SupportedRole = Extract<Role, "chat" | "autocomplete" | "edit">;
12
+
13
+ const getModelKeyForRole = (forRole: SupportedRole): AIModelKey | null => {
14
+ switch (forRole) {
15
+ case "chat":
16
+ return "chat_model";
17
+ case "autocomplete":
18
+ return "autocomplete_model";
19
+ case "edit":
20
+ return "edit_model";
21
+ }
22
+ };
23
+
24
+ /**
25
+ * Hook for saving model and mode changes.
26
+ */
27
+ export const useModelChange = () => {
28
+ const [userConfig, setUserConfig] = useAtom(userConfigAtom);
29
+ const { saveUserConfig } = useRequestClient();
30
+
31
+ const saveConfig = async (newConfig: UserConfig) => {
32
+ await saveUserConfig({ config: newConfig }).then(() => {
33
+ setUserConfig(newConfig);
34
+ });
35
+ };
36
+
37
+ const saveModelChange = async (
38
+ model: QualifiedModelId,
39
+ forRole: SupportedRole,
40
+ ) => {
41
+ const modelKey = getModelKeyForRole(forRole);
42
+
43
+ if (!modelKey) {
44
+ return;
45
+ }
46
+
47
+ const newConfig: UserConfig = {
48
+ ...userConfig,
49
+ ai: {
50
+ ...userConfig.ai,
51
+ models: {
52
+ custom_models: userConfig.ai?.models?.custom_models ?? [],
53
+ displayed_models: userConfig.ai?.models?.displayed_models ?? [],
54
+ ...userConfig.ai?.models,
55
+ [modelKey]: model,
56
+ },
57
+ },
58
+ };
59
+
60
+ saveConfig(newConfig);
61
+ };
62
+
63
+ const saveModeChange = async (newMode: "ask" | "manual") => {
64
+ const newConfig: UserConfig = {
65
+ ...userConfig,
66
+ ai: {
67
+ ...userConfig.ai,
68
+ mode: newMode,
69
+ },
70
+ };
71
+
72
+ saveConfig(newConfig);
73
+ };
74
+
75
+ return { saveModelChange, saveModeChange };
76
+ };
@@ -51,6 +51,20 @@ const AiConfigSchema = z
51
51
  })
52
52
  .passthrough();
53
53
 
54
+ const AiModelsSchema = z.object({
55
+ chat_model: z.string().nullish(),
56
+ edit_model: z.string().nullish(),
57
+ autocomplete_model: z.string().nullish(),
58
+ displayed_models: z.array(z.string()).default([]),
59
+ custom_models: z.array(z.string()).default([]),
60
+ });
61
+
62
+ // Extract the model key type from the schema
63
+ export type AIModelKey = keyof Pick<
64
+ z.infer<typeof AiModelsSchema>,
65
+ "chat_model" | "edit_model" | "autocomplete_model"
66
+ >;
67
+
54
68
  export const UserConfigSchema = z
55
69
  .object({
56
70
  completion: z
@@ -158,18 +172,10 @@ export const UserConfigSchema = z
158
172
  aws_secret_access_key: z.string().optional(),
159
173
  })
160
174
  .optional(),
161
- models: z
162
- .object({
163
- chat_model: z.string().nullish(),
164
- edit_model: z.string().nullish(),
165
- autocomplete_model: z.string().nullish(),
166
- displayed_models: z.array(z.string()).default([]),
167
- custom_models: z.array(z.string()).default([]),
168
- })
169
- .default({
170
- displayed_models: [],
171
- custom_models: [],
172
- }),
175
+ models: AiModelsSchema.default({
176
+ displayed_models: [],
177
+ custom_models: [],
178
+ }),
173
179
  })
174
180
  .passthrough()
175
181
  .default({}),