@marimo-team/frontend 0.14.18-dev38 → 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.
- package/dist/assets/{ConnectedDataExplorerComponent-Dv68DrL_.js → ConnectedDataExplorerComponent-Dluf8clT.js} +1 -1
- package/dist/assets/{ImageComparisonComponent-B1uRvjCG.js → ImageComparisonComponent-CK_fmBK6.js} +1 -1
- package/dist/assets/{VegaLite-DcJJGHdT.js → VegaLite-GAUrkYuV.js} +1 -1
- package/dist/assets/{_baseEach-DuV3zbFg.js → _baseEach-C0Sqwj1Y.js} +1 -1
- package/dist/assets/_baseMap-wbAXOiz5.js +1 -0
- package/dist/assets/{_baseUniq-B4fO5WxV.js → _baseUniq-C6CtZ9jJ.js} +1 -1
- package/dist/assets/{_createAggregator-B1gGJnz5.js → _createAggregator-DCg3aG5g.js} +1 -1
- package/dist/assets/{any-language-editor-gUm8Pr5k.js → any-language-editor-C1hAvQU_.js} +1 -1
- package/dist/assets/{architectureDiagram-SUXI7LT5-D8JW0vTZ.js → architectureDiagram-SUXI7LT5-CY6ZXfK5.js} +1 -1
- package/dist/assets/{blockDiagram-6J76NXCF-pje0e_9-.js → blockDiagram-6J76NXCF-BfT_qzzN.js} +1 -1
- package/dist/assets/{c4Diagram-6F6E4RAY-pRJXc-X6.js → c4Diagram-6F6E4RAY-BNmm8mbN.js} +1 -1
- package/dist/assets/channel-p2n1Ehs7.js +1 -0
- package/dist/assets/{chunk-353BL4L5-DWP0EAjK.js → chunk-353BL4L5-BD1eYYEv.js} +1 -1
- package/dist/assets/{chunk-67H74DCK-CxePEeQq.js → chunk-67H74DCK-D32ZcVIe.js} +1 -1
- package/dist/assets/{chunk-AACKK3MU-CyndqHmU.js → chunk-AACKK3MU-VRjqE2eS.js} +1 -1
- package/dist/assets/{chunk-BFAMUDN2-BE9bwlib.js → chunk-BFAMUDN2-C-cJmQLf.js} +1 -1
- package/dist/assets/{chunk-E2GYISFI-B85SWyoP.js → chunk-E2GYISFI-BVyg2Fo6.js} +1 -1
- package/dist/assets/{chunk-OW32GOEJ-C5Ag_xqO.js → chunk-OW32GOEJ-CJAy1Ibj.js} +1 -1
- package/dist/assets/{chunk-SKB7J2MH-DkUhr5YQ.js → chunk-SKB7J2MH-CNnoGuDT.js} +1 -1
- package/dist/assets/{chunk-SZ463SBG-Bz17SFYY.js → chunk-SZ463SBG-B-DyRJ-t.js} +1 -1
- package/dist/assets/{circle-play-BgNmoXvo.js → circle-play-DlcQmjy-.js} +1 -1
- package/dist/assets/classDiagram-M3E45YP4-CvCuraNp.js +1 -0
- package/dist/assets/classDiagram-v2-YAWTLIQI-CvCuraNp.js +1 -0
- package/dist/assets/clone-CglRxjPg.js +1 -0
- package/dist/assets/{compile-CHyG-xBK.js → compile-Da_Fjkgs.js} +1 -1
- package/dist/assets/{dagre-JOIXM2OF-tScjgBWM.js → dagre-JOIXM2OF-B6XR4pJX.js} +1 -1
- package/dist/assets/{data-grid-overlay-editor-CI501ZK0.js → data-grid-overlay-editor-v4eNCtyj.js} +1 -1
- package/dist/assets/{diagram-5UYTHUR4-1UwgEQLe.js → diagram-5UYTHUR4-fJ5HfR4m.js} +1 -1
- package/dist/assets/{diagram-VMROVX33-hKKw3I1i.js → diagram-VMROVX33-j3xejCo0.js} +1 -1
- package/dist/assets/{diagram-ZTM2IBQH-CyEG2YHp.js → diagram-ZTM2IBQH-dkgnTPsZ.js} +1 -1
- package/dist/assets/{edit-page-D9vV7W7m.js → edit-page-CmCSSEmo.js} +38 -38
- package/dist/assets/{erDiagram-3M52JZNH-a-tNhsYp.js → erDiagram-3M52JZNH-pjMXU-CR.js} +1 -1
- package/dist/assets/{flowDiagram-KYDEHFYC-CnZqSO3t.js → flowDiagram-KYDEHFYC-RFXKcK0k.js} +1 -1
- package/dist/assets/{ganttDiagram-EK5VF46D-6Pfp7XZd.js → ganttDiagram-EK5VF46D-BgmOCQC2.js} +1 -1
- package/dist/assets/{gitGraphDiagram-GW3U2K7C-CD6KQaJF.js → gitGraphDiagram-GW3U2K7C-DQPA3IzE.js} +1 -1
- package/dist/assets/{glide-data-editor-Bk9UyPiz.js → glide-data-editor-DWBodoS3.js} +4 -4
- package/dist/assets/{graph-BLBzFGRL.js → graph-DacIO-UV.js} +1 -1
- package/dist/assets/{home-page-Dtk3jnN0.js → home-page-CRXrPrxk.js} +1 -1
- package/dist/assets/{index-CA2h-g7e.js → index-8RrfVV3p.js} +1 -1
- package/dist/assets/{index-CofDTD9Q.js → index-BC3mHcN4.js} +1 -1
- package/dist/assets/{index-BVeys4As.js → index-BDUp_sLz.js} +1 -1
- package/dist/assets/{index-CFCxalSV.js → index-BHV0wUT7.js} +181 -180
- package/dist/assets/{index-Cdq0JLN7.js → index-BQF1L3gh.js} +1 -1
- package/dist/assets/{index-BMYfIFnR.js → index-BRCKCYPN.js} +1 -1
- package/dist/assets/{index-lRvedUef.js → index-BXCylVut.js} +1 -1
- package/dist/assets/{index-C4P8DJgN.js → index-Bg24ojRl.js} +1 -1
- package/dist/assets/{index-CCBKzLLu.js → index-BoaOUG3q.js} +1 -1
- package/dist/assets/{index-DLvVH5yg.js → index-BxSZURSP.js} +1 -1
- package/dist/assets/{index-CSP0KaW6.js → index-BxjU6sz1.js} +1 -1
- package/dist/assets/{index-Dke4Ikso.js → index-C8_gM-Yh.js} +1 -1
- package/dist/assets/{index-DiD7NRwC.js → index-CRoIS0e_.js} +1 -1
- package/dist/assets/index-CrH6PPjG.css +1 -0
- package/dist/assets/{index-BZMexvZ6.js → index-D-j7DlKu.js} +1 -1
- package/dist/assets/{index-IRmeC8mO.js → index-D6Npa4_9.js} +1 -1
- package/dist/assets/{index-D1i6-Vzt.js → index-M577h3xO.js} +1 -1
- package/dist/assets/{index-DVotKDCm.js → index-PXlQy2IY.js} +1 -1
- package/dist/assets/{index-FRgaLm_h.js → index-dlPsVpRk.js} +1 -1
- package/dist/assets/{index-DEhXWjAF.js → index-i68zQEWD.js} +1 -1
- package/dist/assets/{index-DfkIq4yn.js → index-txOE5caF.js} +1 -1
- package/dist/assets/infoDiagram-LHK5PUON-BQo83J9q.js +2 -0
- package/dist/assets/{journeyDiagram-EWQZEKCU-BJDGTPdN.js → journeyDiagram-EWQZEKCU--vn5uP9G.js} +1 -1
- package/dist/assets/{kanban-definition-ZSS6B67P-CvXSD86T.js → kanban-definition-ZSS6B67P-BsAtaVBp.js} +1 -1
- package/dist/assets/{layout-CAJqQFqW.js → layout-D89ZmFuH.js} +1 -1
- package/dist/assets/{linear-B1-iCo54.js → linear--2JfAOS_.js} +1 -1
- package/dist/assets/links-DHuoq13s.js +17 -0
- package/dist/assets/{mermaid-CoTltW6T.js → mermaid-BbIb2iAQ.js} +4 -4
- package/dist/assets/{min-CAtH1e7k.js → min-B719_H4j.js} +1 -1
- package/dist/assets/{mindmap-definition-6CBA2TL7-8_3hl_9G.js → mindmap-definition-6CBA2TL7-DbrwDtvS.js} +1 -1
- package/dist/assets/{number-overlay-editor-_U6Bi7tP.js → number-overlay-editor-VjmSOKWj.js} +1 -1
- package/dist/assets/{pieDiagram-NIOCPIFQ-5Piswj_j.js → pieDiagram-NIOCPIFQ-DDr_8e6N.js} +1 -1
- package/dist/assets/{quadrantDiagram-2OG54O6I-B-eCUAoN.js → quadrantDiagram-2OG54O6I-TFsW3qDt.js} +1 -1
- package/dist/assets/{react-plotly-4mSeoo5U.js → react-plotly-BJBcptDR.js} +1 -1
- package/dist/assets/{requirementDiagram-QOLK2EJ7-DcePxcNR.js → requirementDiagram-QOLK2EJ7-D5BaSClp.js} +1 -1
- package/dist/assets/{run-page-CojJ7qSs.js → run-page-D1TeIIYq.js} +1 -1
- package/dist/assets/{sankeyDiagram-4UZDY2LN-CFtqqzJ-.js → sankeyDiagram-4UZDY2LN-B-zmPQdl.js} +1 -1
- package/dist/assets/{sequenceDiagram-SKLFT4DO-B2b0ayzr.js → sequenceDiagram-SKLFT4DO-Dw--eukV.js} +1 -1
- package/dist/assets/{slides-component-Bo-bOPD4.js → slides-component-CUV-ryNw.js} +1 -1
- package/dist/assets/{sortBy-CQ7cYGOi.js → sortBy-C9K5SL89.js} +1 -1
- package/dist/assets/{stateDiagram-MI5ZYTHO-CraGSGCe.js → stateDiagram-MI5ZYTHO-WTQoQzCe.js} +1 -1
- package/dist/assets/stateDiagram-v2-5AN5P6BG-CoRRGWzU.js +1 -0
- package/dist/assets/{storage-B7zCO6St.js → storage-BgxGjrlK.js} +3 -3
- package/dist/assets/{terminal-tKrSa7wD.js → terminal-BRsJ5bg0.js} +1 -1
- package/dist/assets/{time-DfceXfii.js → time-Wo8mRr4h.js} +1 -1
- package/dist/assets/{timeline-definition-MYPXXCX6-mETqJEkh.js → timeline-definition-MYPXXCX6-DUiBvKXW.js} +1 -1
- package/dist/assets/{tracing-Df7FGhtp.js → tracing-DkTh5bjk.js} +2 -2
- package/dist/assets/{trash-D_witDuD.js → trash-_cwoDPy1.js} +1 -1
- package/dist/assets/{treemap-75Q7IDZK-2zY68G8S.js → treemap-75Q7IDZK-DndwJIAY.js} +1 -1
- package/dist/assets/{vega-component-BriH_8ZE.js → vega-component-BQrEMxr7.js} +1 -1
- package/dist/assets/{xychartDiagram-H2YORKM3-CBxGxXLd.js → xychartDiagram-H2YORKM3-Cn7nHPc6.js} +1 -1
- package/dist/index.html +2 -2
- package/package.json +1 -1
- package/src/components/ai/ai-model-dropdown.tsx +1 -1
- package/src/components/chat/chat-panel.tsx +8 -51
- package/src/components/editor/ai/add-cell-with-ai.tsx +114 -60
- package/src/components/editor/ai/ai-completion-editor.tsx +27 -15
- package/src/core/ai/config.ts +76 -0
- package/src/core/config/config-schema.ts +18 -12
- package/src/plugins/impl/chat/chat-ui.tsx +0 -3
- package/dist/assets/_baseMap-CXKOjduW.js +0 -1
- package/dist/assets/channel-DSfjdvRx.js +0 -1
- package/dist/assets/classDiagram-M3E45YP4-W7ZwJ9Nk.js +0 -1
- package/dist/assets/classDiagram-v2-YAWTLIQI-W7ZwJ9Nk.js +0 -1
- package/dist/assets/clone-D0s-H6Md.js +0 -1
- package/dist/assets/index-BH8vrBOf.css +0 -1
- package/dist/assets/infoDiagram-LHK5PUON-BcKRYZqP.js +0 -2
- package/dist/assets/links-Df4dtLc_.js +0 -18
- package/dist/assets/stateDiagram-v2-5AN5P6BG-B6V5_20O.js +0 -1
|
@@ -36,7 +36,7 @@ import {
|
|
|
36
36
|
SelectValue,
|
|
37
37
|
} from "@/components/ui/select";
|
|
38
38
|
import { addMessageToChat } from "@/core/ai/chat-utils";
|
|
39
|
-
import
|
|
39
|
+
import { useModelChange } from "@/core/ai/config";
|
|
40
40
|
import {
|
|
41
41
|
activeChatAtom,
|
|
42
42
|
type Chat,
|
|
@@ -44,13 +44,12 @@ import {
|
|
|
44
44
|
chatStateAtom,
|
|
45
45
|
} from "@/core/ai/state";
|
|
46
46
|
import { getCodes } from "@/core/codemirror/copilot/getCodes";
|
|
47
|
-
import { aiAtom, aiEnabledAtom
|
|
48
|
-
import { DEFAULT_AI_MODEL
|
|
47
|
+
import { aiAtom, aiEnabledAtom } from "@/core/config/config";
|
|
48
|
+
import { DEFAULT_AI_MODEL } from "@/core/config/config-schema";
|
|
49
49
|
import { FeatureFlagged } from "@/core/config/feature-flag";
|
|
50
50
|
import { useRequestClient } from "@/core/network/requests";
|
|
51
51
|
import { useRuntimeManager } from "@/core/runtime/config";
|
|
52
52
|
import { ErrorBanner } from "@/plugins/impl/common/error-banner";
|
|
53
|
-
import { type ResolvedTheme, useTheme } from "@/theme/useTheme";
|
|
54
53
|
import { cn } from "@/utils/cn";
|
|
55
54
|
import { timeAgo } from "@/utils/dates";
|
|
56
55
|
import { Logger } from "@/utils/Logger";
|
|
@@ -147,7 +146,6 @@ const ChatHeader: React.FC<ChatHeaderProps> = ({
|
|
|
147
146
|
interface ChatMessageProps {
|
|
148
147
|
message: Message;
|
|
149
148
|
index: number;
|
|
150
|
-
theme: ResolvedTheme;
|
|
151
149
|
onEdit: (index: number, newValue: string) => void;
|
|
152
150
|
setChatState: Dispatch<SetStateAction<ChatState>>;
|
|
153
151
|
chatState: ChatState;
|
|
@@ -156,7 +154,7 @@ interface ChatMessageProps {
|
|
|
156
154
|
}
|
|
157
155
|
|
|
158
156
|
const ChatMessage: React.FC<ChatMessageProps> = memo(
|
|
159
|
-
({ message, index,
|
|
157
|
+
({ message, index, onEdit, isStreamingReasoning, totalMessages }) => (
|
|
160
158
|
<div
|
|
161
159
|
className={cn(
|
|
162
160
|
"flex group relative",
|
|
@@ -168,7 +166,6 @@ const ChatMessage: React.FC<ChatMessageProps> = memo(
|
|
|
168
166
|
<PromptInput
|
|
169
167
|
key={message.id}
|
|
170
168
|
value={message.content}
|
|
171
|
-
theme={theme}
|
|
172
169
|
placeholder="Type your message..."
|
|
173
170
|
onChange={() => {
|
|
174
171
|
// noop
|
|
@@ -248,10 +245,9 @@ const DEFAULT_MODE = "manual";
|
|
|
248
245
|
const ChatInputFooter: React.FC<ChatInputFooterProps> = memo(
|
|
249
246
|
({ input, onSendClick, isLoading, onStop }) => {
|
|
250
247
|
const ai = useAtomValue(aiAtom);
|
|
251
|
-
const [userConfig, setUserConfig] = useAtom(userConfigAtom);
|
|
252
248
|
const currentMode = ai?.mode || DEFAULT_MODE;
|
|
253
249
|
const currentModel = ai?.models?.chat_model || DEFAULT_AI_MODEL;
|
|
254
|
-
const {
|
|
250
|
+
const { saveModeChange, saveModelChange } = useModelChange();
|
|
255
251
|
|
|
256
252
|
const modeOptions = [
|
|
257
253
|
{
|
|
@@ -266,44 +262,11 @@ const ChatInputFooter: React.FC<ChatInputFooterProps> = memo(
|
|
|
266
262
|
},
|
|
267
263
|
];
|
|
268
264
|
|
|
269
|
-
const handleModeChange = async (newMode: "ask" | "manual") => {
|
|
270
|
-
const newConfig: UserConfig = {
|
|
271
|
-
...userConfig,
|
|
272
|
-
ai: {
|
|
273
|
-
...userConfig.ai,
|
|
274
|
-
mode: newMode,
|
|
275
|
-
},
|
|
276
|
-
};
|
|
277
|
-
saveConfig(newConfig);
|
|
278
|
-
};
|
|
279
|
-
|
|
280
|
-
const handleModelChange = async (newModel: QualifiedModelId) => {
|
|
281
|
-
const newConfig: UserConfig = {
|
|
282
|
-
...userConfig,
|
|
283
|
-
ai: {
|
|
284
|
-
...userConfig.ai,
|
|
285
|
-
models: {
|
|
286
|
-
custom_models: [],
|
|
287
|
-
displayed_models: [],
|
|
288
|
-
...userConfig.ai?.models,
|
|
289
|
-
chat_model: newModel,
|
|
290
|
-
},
|
|
291
|
-
},
|
|
292
|
-
};
|
|
293
|
-
saveConfig(newConfig);
|
|
294
|
-
};
|
|
295
|
-
|
|
296
|
-
const saveConfig = async (newConfig: UserConfig) => {
|
|
297
|
-
await saveUserConfig({ config: newConfig }).then(() => {
|
|
298
|
-
setUserConfig(newConfig);
|
|
299
|
-
});
|
|
300
|
-
};
|
|
301
|
-
|
|
302
265
|
return (
|
|
303
266
|
<div className="px-3 py-2 border-t border-border/20 flex items-center justify-between">
|
|
304
267
|
<div className="flex items-center gap-2">
|
|
305
268
|
<FeatureFlagged feature="mcp_docs">
|
|
306
|
-
<Select value={currentMode} onValueChange={
|
|
269
|
+
<Select value={currentMode} onValueChange={saveModeChange}>
|
|
307
270
|
<SelectTrigger className="h-6 text-xs border-border shadow-none! ring-0! bg-muted hover:bg-muted/30 py-0 px-2 gap-1">
|
|
308
271
|
<SelectValue placeholder="manual" />
|
|
309
272
|
</SelectTrigger>
|
|
@@ -328,7 +291,7 @@ const ChatInputFooter: React.FC<ChatInputFooterProps> = memo(
|
|
|
328
291
|
<AIModelDropdown
|
|
329
292
|
value={currentModel}
|
|
330
293
|
placeholder="Model"
|
|
331
|
-
onSelect={
|
|
294
|
+
onSelect={(model) => saveModelChange(model, "chat")}
|
|
332
295
|
triggerClassName="h-6 text-xs shadow-none! ring-0! bg-muted hover:bg-muted/30 rounded-sm"
|
|
333
296
|
iconSize="small"
|
|
334
297
|
showAddCustomModelDocs={true}
|
|
@@ -359,14 +322,13 @@ interface ChatInputProps {
|
|
|
359
322
|
input: string;
|
|
360
323
|
setInput: (value: string) => void;
|
|
361
324
|
onSubmit: (e: KeyboardEvent | undefined, value: string) => void;
|
|
362
|
-
theme: ResolvedTheme;
|
|
363
325
|
inputRef: React.RefObject<ReactCodeMirrorRef | null>;
|
|
364
326
|
isLoading: boolean;
|
|
365
327
|
onStop: () => void;
|
|
366
328
|
}
|
|
367
329
|
|
|
368
330
|
const ChatInput: React.FC<ChatInputProps> = memo(
|
|
369
|
-
({ input, setInput, onSubmit,
|
|
331
|
+
({ input, setInput, onSubmit, inputRef, isLoading, onStop }) => {
|
|
370
332
|
const handleSendClick = () => {
|
|
371
333
|
if (input.trim()) {
|
|
372
334
|
onSubmit(undefined, input);
|
|
@@ -381,7 +343,6 @@ const ChatInput: React.FC<ChatInputProps> = memo(
|
|
|
381
343
|
onChange={setInput}
|
|
382
344
|
onSubmit={onSubmit}
|
|
383
345
|
onClose={() => inputRef.current?.editor?.blur()}
|
|
384
|
-
theme={theme}
|
|
385
346
|
placeholder="Type your message..."
|
|
386
347
|
/>
|
|
387
348
|
</div>
|
|
@@ -428,7 +389,6 @@ const ChatPanelBody = () => {
|
|
|
428
389
|
const newMessageInputRef = useRef<ReactCodeMirrorRef>(null);
|
|
429
390
|
const scrollContainerRef = useRef<HTMLDivElement>(null);
|
|
430
391
|
const messagesEndRef = useRef<HTMLDivElement>(null);
|
|
431
|
-
const { theme } = useTheme();
|
|
432
392
|
const runtimeManager = useRuntimeManager();
|
|
433
393
|
const { invokeAiTool } = useRequestClient();
|
|
434
394
|
|
|
@@ -687,7 +647,6 @@ const ChatPanelBody = () => {
|
|
|
687
647
|
key="new-thread-input"
|
|
688
648
|
value={newThreadInput}
|
|
689
649
|
placeholder="Ask anything, @ to include context about tables or dataframes"
|
|
690
|
-
theme={theme}
|
|
691
650
|
onClose={handleOnCloseThread}
|
|
692
651
|
onChange={setNewThreadInput}
|
|
693
652
|
onSubmit={handleNewThreadSubmit}
|
|
@@ -707,7 +666,6 @@ const ChatPanelBody = () => {
|
|
|
707
666
|
key={idx}
|
|
708
667
|
message={message}
|
|
709
668
|
index={idx}
|
|
710
|
-
theme={theme}
|
|
711
669
|
onEdit={handleMessageEdit}
|
|
712
670
|
setChatState={setChatState}
|
|
713
671
|
chatState={chatState}
|
|
@@ -747,7 +705,6 @@ const ChatPanelBody = () => {
|
|
|
747
705
|
input={input}
|
|
748
706
|
setInput={setInput}
|
|
749
707
|
onSubmit={handleChatInputSubmit}
|
|
750
|
-
theme={theme}
|
|
751
708
|
inputRef={newMessageInputRef}
|
|
752
709
|
isLoading={isLoading}
|
|
753
710
|
onStop={stop}
|
|
@@ -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 {
|
|
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
|
-
|
|
197
|
-
|
|
198
|
-
<span>
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
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
|
-
|
|
204
|
-
|
|
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
|
-
{
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
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:
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
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({}),
|
|
@@ -43,7 +43,6 @@ import { toast } from "@/components/ui/use-toast";
|
|
|
43
43
|
import { moveToEndOfEditor } from "@/core/codemirror/utils";
|
|
44
44
|
import { useAsyncData } from "@/hooks/useAsyncData";
|
|
45
45
|
import { renderHTML } from "@/plugins/core/RenderHTML";
|
|
46
|
-
import { useTheme } from "@/theme/useTheme";
|
|
47
46
|
import { cn } from "@/utils/cn";
|
|
48
47
|
import { copyToClipboard } from "@/utils/copy";
|
|
49
48
|
import { Logger } from "@/utils/Logger";
|
|
@@ -74,7 +73,6 @@ export const Chatbot: React.FC<Props> = (props) => {
|
|
|
74
73
|
const formRef = useRef<HTMLFormElement>(null);
|
|
75
74
|
const codeMirrorInputRef = useRef<ReactCodeMirrorRef>(null);
|
|
76
75
|
const scrollContainerRef = useRef<HTMLDivElement>(null);
|
|
77
|
-
const { theme } = useTheme();
|
|
78
76
|
|
|
79
77
|
const { data: initialMessages } = useAsyncData(async () => {
|
|
80
78
|
const chatMessages = await props.get_chat_history({});
|
|
@@ -374,7 +372,6 @@ export const Chatbot: React.FC<Props> = (props) => {
|
|
|
374
372
|
placeholder={promptInputPlaceholder}
|
|
375
373
|
value={input}
|
|
376
374
|
inputRef={codeMirrorInputRef}
|
|
377
|
-
theme={theme}
|
|
378
375
|
maxHeight={props.maxHeight ? `${props.maxHeight / 2}px` : undefined}
|
|
379
376
|
onChange={setInput}
|
|
380
377
|
onSubmit={(_evt, newValue) => {
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{b as m}from"./_baseEach-DuV3zbFg.js";import{x as s}from"./index-CFCxalSV.js";function e(r,o){var a=-1,t=s(r)?Array(r.length):[];return m(r,function(n,f,i){t[++a]=o(n,f,i)}),t}export{e as b};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{U as s,C as o}from"./mermaid-CoTltW6T.js";const n=(a,r)=>s.lang.round(o.parse(a)[r]);export{n as c};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{s as a,c as s,a as t,C as o}from"./chunk-SZ463SBG-Bz17SFYY.js";import{_ as e}from"./mermaid-CoTltW6T.js";import"./transform-B8bpuzxV.js";import"./chunk-E2GYISFI-B85SWyoP.js";import"./chunk-BFAMUDN2-BE9bwlib.js";import"./chunk-SKB7J2MH-DkUhr5YQ.js";import"./index-CFCxalSV.js";import"./step-BwsUM5iJ.js";import"./timer-BwIYMJWC.js";var i={parser:t,get db(){return new o},renderer:s,styles:a,init:e(r=>{r.class||(r.class={}),r.class.arrowMarkerAbsolute=r.arrowMarkerAbsolute},"init")};export{i as diagram};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{s as a,c as s,a as t,C as o}from"./chunk-SZ463SBG-Bz17SFYY.js";import{_ as e}from"./mermaid-CoTltW6T.js";import"./transform-B8bpuzxV.js";import"./chunk-E2GYISFI-B85SWyoP.js";import"./chunk-BFAMUDN2-BE9bwlib.js";import"./chunk-SKB7J2MH-DkUhr5YQ.js";import"./index-CFCxalSV.js";import"./step-BwsUM5iJ.js";import"./timer-BwIYMJWC.js";var i={parser:t,get db(){return new o},renderer:s,styles:a,init:e(r=>{r.class||(r.class={}),r.class.arrowMarkerAbsolute=r.arrowMarkerAbsolute},"init")};export{i as diagram};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{b as n}from"./_baseUniq-B4fO5WxV.js";function o(r){return n(r,4)}export{o as c};
|