@marimo-team/frontend 0.19.3-dev41 → 0.19.3-dev45
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/{add-cell-with-ai-Csh7GHT3.js → add-cell-with-ai-D2qS3Nos.js} +21 -21
- package/dist/assets/{agent-panel-C5C18dfm.js → agent-panel-BzV4XUTo.js} +1 -1
- package/dist/assets/{cell-editor-gOJZyTG_.js → cell-editor-Do6lWWk9.js} +1 -1
- package/dist/assets/{chat-panel-BwP6HOKA.js → chat-panel-71zcilvi.js} +1 -1
- package/dist/assets/{edit-page-KoYkiOm1.js → edit-page-DSuXLdcn.js} +3 -3
- package/dist/assets/index-C30GhE0W.css +2 -0
- package/dist/assets/index-VUoDw_Qb.js +43 -0
- package/dist/assets/{scratchpad-panel-BcE_ovEU.js → scratchpad-panel-CarbQVYs.js} +1 -1
- package/dist/index.html +3 -3
- package/package.json +1 -1
- package/src/components/chat/chat-utils.ts +0 -19
- package/src/components/editor/ai/completion-handlers.tsx +1 -1
- package/src/plugins/impl/chat/ChatPlugin.tsx +2 -4
- package/src/plugins/impl/chat/chat-ui.tsx +46 -187
- package/src/plugins/impl/chat/types.ts +5 -12
- package/dist/assets/index-Bq3Xa2YC.js +0 -43
- package/dist/assets/index-__6MNWbe.css +0 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
import{s as oe}from"./chunk-LvLJmgfZ.js";import{d as be,l as ye,n as H,p as ae,u as we}from"./useEvent-DlWF5OMa.js";import{t as Ne}from"./react-BGmjiNul.js";import{N as ke,ni as m,pn as ze,qr as Ce,ti as Se,w as Oe,__tla as Ae}from"./cells-Cv9PtwL9.js";import"./react-dom-C9fstfnp.js";import{t as se}from"./compiler-runtime-DeeZ7FnK.js";import"./tooltip-CrRUCOBw.js";import{f as ie}from"./hotkeys-uKX61F1_.js";import{v as Ie}from"./utils-CJJIceVn.js";import{t as Le}from"./constants-Bkp4R3bQ.js";import"./config-DFDEcYvy.js";import{t as Me}from"./jsx-runtime-DN_bIXfG.js";import{t as z}from"./button-B8cGZzP5.js";import{t as le}from"./cn-C1rgT0yh.js";import"./dist-CAcX026F.js";import{n as Pe,__tla as Ee}from"./JsonOutput-C8Eo1zBR.js";import"./cjs-Bj40p_Np.js";import"./main-CwSdzVhm.js";import"./useNonce-EAuSVK-5.js";import{r as Re}from"./requests-C0HaHO6a.js";import{t as ne}from"./createLucideIcon-CW2xpJ57.js";import{d as qe,__tla as De}from"./layout-9uQoV-6h.js";import{n as He,t as Ve,__tla as Te}from"./LazyAnyLanguageCodeMirror-Cp2punaU.js";import"./download-24bI2vH0.js";import"./markdown-renderer-DlVqlHOL.js";import{u as Ge}from"./toDate-5JckKRQn.js";import{t as Ue,__tla as Be}from"./cell-editor-
|
|
1
|
+
import{s as oe}from"./chunk-LvLJmgfZ.js";import{d as be,l as ye,n as H,p as ae,u as we}from"./useEvent-DlWF5OMa.js";import{t as Ne}from"./react-BGmjiNul.js";import{N as ke,ni as m,pn as ze,qr as Ce,ti as Se,w as Oe,__tla as Ae}from"./cells-Cv9PtwL9.js";import"./react-dom-C9fstfnp.js";import{t as se}from"./compiler-runtime-DeeZ7FnK.js";import"./tooltip-CrRUCOBw.js";import{f as ie}from"./hotkeys-uKX61F1_.js";import{v as Ie}from"./utils-CJJIceVn.js";import{t as Le}from"./constants-Bkp4R3bQ.js";import"./config-DFDEcYvy.js";import{t as Me}from"./jsx-runtime-DN_bIXfG.js";import{t as z}from"./button-B8cGZzP5.js";import{t as le}from"./cn-C1rgT0yh.js";import"./dist-CAcX026F.js";import{n as Pe,__tla as Ee}from"./JsonOutput-C8Eo1zBR.js";import"./cjs-Bj40p_Np.js";import"./main-CwSdzVhm.js";import"./useNonce-EAuSVK-5.js";import{r as Re}from"./requests-C0HaHO6a.js";import{t as ne}from"./createLucideIcon-CW2xpJ57.js";import{d as qe,__tla as De}from"./layout-9uQoV-6h.js";import{n as He,t as Ve,__tla as Te}from"./LazyAnyLanguageCodeMirror-Cp2punaU.js";import"./download-24bI2vH0.js";import"./markdown-renderer-DlVqlHOL.js";import{u as Ge}from"./toDate-5JckKRQn.js";import{t as Ue,__tla as Be}from"./cell-editor-Do6lWWk9.js";import{t as Fe}from"./play-BJDBXApx.js";import{t as Je}from"./spinner-C1czjtp7.js";import"./dist-HGZzCB0y.js";import"./dist-CVj-_Iiz.js";import"./dist-BVf1IY4_.js";import"./dist-Cq_4nPfh.js";import"./dist-RKnr9SNh.js";import{r as Ke}from"./useTheme-DfP1CWaW.js";import"./Combination-D1TsGrBC.js";import{t as C}from"./tooltip-CvjcEpZC.js";import"./dates-CdsE1R40.js";import"./popover-DtnzNVk-.js";import"./vega-loader.browser-C8wT63Va.js";import"./defaultLocale-BLUna9fQ.js";import"./defaultLocale-DzliDDTm.js";import"./purify.es-N-2faAGj.js";import{__tla as Qe}from"./chunk-OGVTOU66-CjNLT2C3.js";import"./katex-AwOI3EvM.js";import"./marked.esm-CHnOtnr3.js";import"./es-BITbuY9w.js";import{o as We}from"./focus-D1y1tXyC.js";import{a as Xe}from"./renderShortcut-D0Pei-OA.js";import"./esm-B3JckBtM.js";import{n as Ye,r as Ze,t as me}from"./react-resizable-panels.browser.esm-BqxQegSf.js";import"./name-cell-input-YMoA0SQj.js";import"./Inputs-DmoeP8nh.js";import{__tla as $e}from"./loro_wasm_bg-CghhyG7y.js";import"./ws-itdlXHqs.js";import"./dist-BRZzJw_5.js";import"./dist-P7JHert4.js";import"./dist-CoiWxjLF.js";import"./dist-cVYW_wBR.js";import"./dist-BAmo7Mv9.js";import"./dist-3oAtECdQ.js";import"./dist-D6Pwf0VF.js";import"./dist-D9HMoxdZ.js";import"./dist-JtCdI6tY.js";import"./esm-CCqLcax5.js";import{a as et,i as tt,t as rt}from"./kiosk-mode-DfyjlR7p.js";let ce,ot=Promise.all([(()=>{try{return Ae}catch{}})(),(()=>{try{return Ee}catch{}})(),(()=>{try{return De}catch{}})(),(()=>{try{return Te}catch{}})(),(()=>{try{return Be}catch{}})(),(()=>{try{return Qe}catch{}})(),(()=>{try{return $e}catch{}})()]).then(async()=>{var de=ne("eraser",[["path",{d:"M21 21H8a2 2 0 0 1-1.42-.587l-3.994-3.999a2 2 0 0 1 0-2.828l10-10a2 2 0 0 1 2.829 0l5.999 6a2 2 0 0 1 0 2.828L12.834 21",key:"g5wo59"}],["path",{d:"m5.082 11.09 8.828 8.828",key:"1wx5vj"}]]),pe=ne("history",[["path",{d:"M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8",key:"1357e3"}],["path",{d:"M3 3v5h5",key:"1xhq8a"}],["path",{d:"M12 7v5l4 2",key:"1fdv2h"}]]),he=se(),V=oe(Ne(),1),ue=15;const T=Ce("marimo:scratchpadHistory:v1",[],ze),fe=ae(!1),xe=ae(null,(e,s,i)=>{if(i=i.trim(),!i)return;let n=e(T);s(T,[i,...n.filter(c=>c!==i)].slice(0,ue))});var t=oe(Me(),1),_e={hide_code:!1,disabled:!1};const ve=()=>{var re;let e=(0,he.c)(60),s=ke(),[i]=Ie(),{theme:n}=Ke(),c=(0,V.useRef)(null),G=We(),{createNewCell:U,updateCellCode:d}=Oe(),{sendRunScratchpad:p}=Re(),S=tt(),B=et(),l=s.cellRuntime[m],F=l==null?void 0:l.output,O=l==null?void 0:l.status,J=l==null?void 0:l.consoleOutputs,r=((re=s.cellData.__scratch__)==null?void 0:re.code)??"",K=be(xe),[a,h]=ye(fe),u=we(T),A;e[0]!==K||e[1]!==r||e[2]!==p?(A=()=>{p({code:r}),K(r)},e[0]=K,e[1]=r,e[2]=p,e[3]=A):A=e[3];let f=H(A),I;e[4]!==r||e[5]!==U||e[6]!==G?(I=()=>{r.trim()&&U({code:r,before:!1,cellId:G??"__end__"})},e[4]=r,e[5]=U,e[6]=G,e[7]=I):I=e[7];let Q=H(I),L;e[8]!==p||e[9]!==d?(L=()=>{d({cellId:m,code:"",formattingChange:!1}),p({code:""});let o=c.current;o&&o.dispatch({changes:{from:0,to:o.state.doc.length,insert:""}})},e[8]=p,e[9]=d,e[10]=L):L=e[10];let W=H(L),M;e[11]!==h||e[12]!==d?(M=o=>{h(!1),d({cellId:m,code:o,formattingChange:!1});let k=c.current;k&&k.dispatch({changes:{from:0,to:k.state.doc.length,insert:o}})},e[11]=h,e[12]=d,e[13]=M):M=e[13];let X=H(M),[Y,ge]=(0,V.useState)(),P;e[14]!==X||e[15]!==u||e[16]!==a||e[17]!==n?(P=()=>a?(0,t.jsx)("div",{className:"absolute inset-0 z-100 bg-background p-3 border-none overflow-auto",children:(0,t.jsx)("div",{className:"overflow-auto flex flex-col gap-3",children:u.map((o,k)=>(0,t.jsx)("div",{className:"border rounded-md hover:shadow-sm cursor-pointer hover:border-input overflow-hidden",onClick:()=>X(o),children:(0,t.jsx)(V.Suspense,{children:(0,t.jsx)(Ve,{language:"python",theme:n,basicSetup:{highlightActiveLine:!1,highlightActiveLineGutter:!1},value:o.trim(),editable:!1,readOnly:!0})})},k))})}):null,e[14]=X,e[15]=u,e[16]=a,e[17]=n,e[18]=P):P=e[18];let Z=P,E;e[19]!==W||e[20]!==Q||e[21]!==f||e[22]!==u.length||e[23]!==a||e[24]!==h||e[25]!==O?(E=()=>(0,t.jsxs)("div",{className:"flex items-center shrink-0 border-b",children:[(0,t.jsx)(C,{content:Xe("cell.run"),children:(0,t.jsx)(z,{"data-testid":"scratchpad-run-button",onClick:f,disabled:a,variant:"text",size:"xs",children:(0,t.jsx)(Fe,{color:"var(--grass-11)",size:16})})}),(0,t.jsx)(C,{content:"Clear code and outputs",children:(0,t.jsx)(z,{disabled:a,size:"xs",variant:"text",onClick:W,children:(0,t.jsx)(de,{size:16})})}),(0,t.jsx)(rt,{children:(0,t.jsx)(C,{content:"Insert code",children:(0,t.jsx)(z,{disabled:a,size:"xs",variant:"text",onClick:Q,children:(0,t.jsx)(He,{size:16})})})}),(O==="running"||O==="queued")&&(0,t.jsx)(Je,{className:"inline",size:"small"}),(0,t.jsx)("div",{className:"flex-1"}),(0,t.jsx)(C,{content:"Toggle history",children:(0,t.jsx)(z,{size:"xs",variant:"text",className:le(a&&"bg-(--sky-3) rounded-none"),onClick:()=>h(!a),disabled:u.length===0,children:(0,t.jsx)(pe,{size:16})})}),(0,t.jsx)(C,{content:(0,t.jsx)("span",{className:"block max-w-prose",children:"Use this scratchpad to experiment with code without restrictions on variable names. Variables defined here aren't saved to notebook memory, and the code is not saved in the notebook file."}),children:(0,t.jsx)(z,{size:"xs",variant:"text",children:(0,t.jsx)(Ge,{size:16})})})]}),e[19]=W,e[20]=Q,e[21]=f,e[22]=u.length,e[23]=a,e[24]=h,e[25]=O,e[26]=E):E=e[26];let $=E,je=S==="vertical",R;e[27]===Symbol.for("react.memo_cache_sentinel")?(R=Se.create(m),e[27]=R):R=e[27];let x;e[28]===$?x=e[29]:(x=$(),e[28]=$,e[29]=x);let q;e[30]===Symbol.for("react.memo_cache_sentinel")?(q=o=>{c.current=o},e[30]=q):q=e[30];let _;e[31]!==r||e[32]!==f||e[33]!==Y||e[34]!==n||e[35]!==i?(_=(0,t.jsx)("div",{className:"flex-1 overflow-auto",children:(0,t.jsx)(Ue,{theme:n,showPlaceholder:!1,id:m,code:r,config:_e,status:"idle",serializedEditorState:null,runCell:f,userConfig:i,editorViewRef:c,setEditorView:q,hidden:!1,showHiddenCode:ie.NOOP,languageAdapter:Y,setLanguageAdapter:ge})}),e[31]=r,e[32]=f,e[33]=Y,e[34]=n,e[35]=i,e[36]=_):_=e[36];let v;e[37]===Z?v=e[38]:(v=Z(),e[37]=Z,e[38]=v);let g;e[39]!==v||e[40]!==x||e[41]!==_?(g=(0,t.jsx)(me,{defaultSize:40,minSize:20,maxSize:70,children:(0,t.jsxs)("div",{className:"h-full flex flex-col overflow-hidden relative",children:[x,_,v]})}),e[39]=v,e[40]=x,e[41]=_,e[42]=g):g=e[42];let ee=je?"h-1":"w-1",j;e[43]===ee?j=e[44]:(j=le("bg-border hover:bg-primary/50 transition-colors",ee),e[43]=ee,e[44]=j);let b;e[45]===j?b=e[46]:(b=(0,t.jsx)(Ze,{className:j}),e[45]=j,e[46]=b);let y;e[47]===F?y=e[48]:(y=(0,t.jsx)("div",{className:"flex-1 overflow-auto",children:(0,t.jsx)(Pe,{allowExpand:!1,output:F,className:Le.outputArea,cellId:m,stale:!1,loading:!1})}),e[47]=F,e[48]=y);let w;e[49]===J?w=e[50]:(w=(0,t.jsx)("div",{className:"overflow-auto shrink-0 max-h-[50%]",children:(0,t.jsx)(qe,{consoleOutputs:J,className:"overflow-auto",stale:!1,cellName:"_",onSubmitDebugger:ie.NOOP,cellId:m,debuggerActive:!1})}),e[49]=J,e[50]=w);let N;e[51]!==y||e[52]!==w?(N=(0,t.jsx)(me,{defaultSize:60,minSize:20,children:(0,t.jsxs)("div",{className:"h-full flex flex-col divide-y overflow-hidden",children:[y,w]})}),e[51]=y,e[52]=w,e[53]=N):N=e[53];let D;return e[54]!==S||e[55]!==B||e[56]!==g||e[57]!==b||e[58]!==N?(D=(0,t.jsx)("div",{className:"flex flex-col h-full overflow-hidden",id:R,children:(0,t.jsxs)(Ye,{direction:S,className:"h-full",children:[g,b,N]},B)}),e[54]=S,e[55]=B,e[56]=g,e[57]=b,e[58]=N,e[59]=D):D=e[59],D};let te;te=se(),ce=()=>{let e=(0,te.c)(1),s;return e[0]===Symbol.for("react.memo_cache_sentinel")?(s=(0,t.jsx)(ve,{}),e[0]=s):s=e[0],s}});export{ot as __tla,ce as default};
|
package/dist/index.html
CHANGED
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
<marimo-server-token data-token="{{ server_token }}" hidden></marimo-server-token>
|
|
67
67
|
<!-- /TODO -->
|
|
68
68
|
<title>{{ title }}</title>
|
|
69
|
-
<script type="module" crossorigin src="./assets/index-
|
|
69
|
+
<script type="module" crossorigin src="./assets/index-VUoDw_Qb.js"></script>
|
|
70
70
|
<link rel="modulepreload" crossorigin href="./assets/preload-helper-BW0IMuFq.js">
|
|
71
71
|
<link rel="modulepreload" crossorigin href="./assets/hotkeys-uKX61F1_.js">
|
|
72
72
|
<link rel="modulepreload" crossorigin href="./assets/defaultLocale-BLUna9fQ.js">
|
|
@@ -209,7 +209,7 @@
|
|
|
209
209
|
<link rel="modulepreload" crossorigin href="./assets/blob-Dg_vNTSs.js">
|
|
210
210
|
<link rel="modulepreload" crossorigin href="./assets/objectWithoutPropertiesLoose-CboCOq4o.js">
|
|
211
211
|
<link rel="modulepreload" crossorigin href="./assets/esm-B3JckBtM.js">
|
|
212
|
-
<link rel="modulepreload" crossorigin href="./assets/add-cell-with-ai-
|
|
212
|
+
<link rel="modulepreload" crossorigin href="./assets/add-cell-with-ai-D2qS3Nos.js">
|
|
213
213
|
<link rel="modulepreload" crossorigin href="./assets/chart-no-axes-column-D42sFB6d.js">
|
|
214
214
|
<link rel="modulepreload" crossorigin href="./assets/square-function-DxXFdbn8.js">
|
|
215
215
|
<link rel="modulepreload" crossorigin href="./assets/spec-qp_XZeSS.js">
|
|
@@ -257,7 +257,7 @@
|
|
|
257
257
|
<link rel="stylesheet" crossorigin href="./assets/cells-jmgGt1lS.css">
|
|
258
258
|
<link rel="stylesheet" crossorigin href="./assets/markdown-renderer-DdDKmWlR.css">
|
|
259
259
|
<link rel="stylesheet" crossorigin href="./assets/JsonOutput-B7vuddcd.css">
|
|
260
|
-
<link rel="stylesheet" crossorigin href="./assets/index-
|
|
260
|
+
<link rel="stylesheet" crossorigin href="./assets/index-C30GhE0W.css">
|
|
261
261
|
</head>
|
|
262
262
|
<body>
|
|
263
263
|
<div id="root"></div>
|
package/package.json
CHANGED
|
@@ -8,7 +8,6 @@ import type {
|
|
|
8
8
|
InvokeAiToolRequest,
|
|
9
9
|
InvokeAiToolResponse,
|
|
10
10
|
} from "@/core/network/types";
|
|
11
|
-
import type { ChatMessage } from "@/plugins/impl/chat/types";
|
|
12
11
|
import { blobToString } from "@/utils/fileToBase64";
|
|
13
12
|
import { Logger } from "@/utils/Logger";
|
|
14
13
|
import { getAICompletionBodyWithAttachments } from "../editor/ai/completion-utils";
|
|
@@ -68,7 +67,6 @@ function stringifyTextParts(parts: UIMessage["parts"]): string {
|
|
|
68
67
|
export async function buildCompletionRequestBody(
|
|
69
68
|
messages: UIMessage[],
|
|
70
69
|
): Promise<{
|
|
71
|
-
messages: ChatMessage[]; // Deprecated. TODO: Remove in the future
|
|
72
70
|
uiMessages: UIMessage[];
|
|
73
71
|
context?: (null | components["schemas"]["AiCompletionContext"]) | undefined;
|
|
74
72
|
includeOtherCode: string;
|
|
@@ -91,25 +89,8 @@ export async function buildCompletionRequestBody(
|
|
|
91
89
|
};
|
|
92
90
|
}
|
|
93
91
|
|
|
94
|
-
function toChatMessage(message: UIMessage, isLast: boolean): ChatMessage {
|
|
95
|
-
// Clone parts to avoid mutating the original message
|
|
96
|
-
const parts = [...message.parts];
|
|
97
|
-
if (isLast) {
|
|
98
|
-
parts.push(...completionBody.attachments);
|
|
99
|
-
}
|
|
100
|
-
return {
|
|
101
|
-
id: message.id,
|
|
102
|
-
role: message.role,
|
|
103
|
-
content: stringifyTextParts(message.parts), // This is no longer used in the backend
|
|
104
|
-
parts,
|
|
105
|
-
};
|
|
106
|
-
}
|
|
107
|
-
|
|
108
92
|
return {
|
|
109
93
|
...completionBody.body,
|
|
110
|
-
messages: messages.map((m, idx) =>
|
|
111
|
-
toChatMessage(m, idx === messages.length - 1),
|
|
112
|
-
),
|
|
113
94
|
uiMessages: messages.map((m, idx) =>
|
|
114
95
|
addAttachmentsToMessage(m, idx === messages.length - 1),
|
|
115
96
|
),
|
|
@@ -124,7 +124,7 @@ export const AcceptCompletionButton: React.FC<{
|
|
|
124
124
|
size={size}
|
|
125
125
|
disabled={isLoading}
|
|
126
126
|
onClick={handleAcceptAndRun}
|
|
127
|
-
className={`${baseClasses} rounded-l-none px-1.5 ${borderless && "border-0 border-l
|
|
127
|
+
className={`${baseClasses} rounded-l-none px-1.5 ${borderless && "border-0 border-l"} ${playButtonStyles}`}
|
|
128
128
|
>
|
|
129
129
|
<PlayIcon className="h-2.5 w-2.5" />
|
|
130
130
|
</Button>
|
|
@@ -15,7 +15,7 @@ export type PluginFunctions = {
|
|
|
15
15
|
get_chat_history: (req: {}) => Promise<{ messages: UIMessage[] }>;
|
|
16
16
|
delete_chat_history: (req: {}) => Promise<null>;
|
|
17
17
|
delete_chat_message: (req: { index: number }) => Promise<null>;
|
|
18
|
-
send_prompt: (req: SendMessageRequest) => Promise<
|
|
18
|
+
send_prompt: (req: SendMessageRequest) => Promise<unknown>;
|
|
19
19
|
};
|
|
20
20
|
|
|
21
21
|
const messageSchema = z.array(
|
|
@@ -47,7 +47,6 @@ export const ChatPlugin = createPlugin<{ messages: UIMessage[] }>(
|
|
|
47
47
|
maxHeight: z.number().optional(),
|
|
48
48
|
config: configSchema,
|
|
49
49
|
allowAttachments: z.union([z.boolean(), z.string().array()]),
|
|
50
|
-
frontendManaged: z.boolean(),
|
|
51
50
|
}),
|
|
52
51
|
)
|
|
53
52
|
.withFunctions<PluginFunctions>({
|
|
@@ -67,7 +66,7 @@ export const ChatPlugin = createPlugin<{ messages: UIMessage[] }>(
|
|
|
67
66
|
config: configSchema,
|
|
68
67
|
}),
|
|
69
68
|
)
|
|
70
|
-
.output(z.
|
|
69
|
+
.output(z.unknown()),
|
|
71
70
|
})
|
|
72
71
|
.renderer((props) => (
|
|
73
72
|
<TooltipProvider>
|
|
@@ -77,7 +76,6 @@ export const ChatPlugin = createPlugin<{ messages: UIMessage[] }>(
|
|
|
77
76
|
showConfigurationControls={props.data.showConfigurationControls}
|
|
78
77
|
maxHeight={props.data.maxHeight}
|
|
79
78
|
allowAttachments={props.data.allowAttachments}
|
|
80
|
-
frontendManaged={props.data.frontendManaged}
|
|
81
79
|
config={props.data.config}
|
|
82
80
|
get_chat_history={props.functions.get_chat_history}
|
|
83
81
|
delete_chat_history={props.functions.delete_chat_history}
|
|
@@ -66,7 +66,6 @@ interface Props extends PluginFunctions {
|
|
|
66
66
|
showConfigurationControls: boolean;
|
|
67
67
|
maxHeight: number | undefined;
|
|
68
68
|
allowAttachments: boolean | string[];
|
|
69
|
-
frontendManaged: boolean;
|
|
70
69
|
value: UIMessage[];
|
|
71
70
|
setValue: (messages: UIMessage[]) => void;
|
|
72
71
|
host: HTMLElement;
|
|
@@ -166,113 +165,42 @@ export const Chatbot: React.FC<Props> = (props) => {
|
|
|
166
165
|
};
|
|
167
166
|
});
|
|
168
167
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
frontendStreamControllerRef.current = controller;
|
|
168
|
+
const stream = new ReadableStream<UIMessageChunk>({
|
|
169
|
+
start(controller) {
|
|
170
|
+
frontendStreamControllerRef.current = controller;
|
|
173
171
|
|
|
174
|
-
const abortHandler = () => {
|
|
175
|
-
try {
|
|
176
|
-
controller.close();
|
|
177
|
-
} catch (error) {
|
|
178
|
-
Logger.debug("Controller may already be closed", { error });
|
|
179
|
-
}
|
|
180
|
-
frontendStreamControllerRef.current = null;
|
|
181
|
-
};
|
|
182
|
-
signal?.addEventListener("abort", abortHandler);
|
|
183
|
-
|
|
184
|
-
return () => {
|
|
185
|
-
signal?.removeEventListener("abort", abortHandler);
|
|
186
|
-
};
|
|
187
|
-
},
|
|
188
|
-
cancel() {
|
|
189
|
-
frontendStreamControllerRef.current = null;
|
|
190
|
-
},
|
|
191
|
-
});
|
|
192
|
-
|
|
193
|
-
// Start the prompt, chunks will be sent via events
|
|
194
|
-
props
|
|
195
|
-
.send_prompt({
|
|
196
|
-
messages: messages,
|
|
197
|
-
config: chatConfig,
|
|
198
|
-
})
|
|
199
|
-
.catch((error: Error) => {
|
|
200
|
-
frontendStreamControllerRef.current?.error(error);
|
|
201
|
-
frontendStreamControllerRef.current = null;
|
|
202
|
-
});
|
|
203
|
-
|
|
204
|
-
return createUIMessageStreamResponse({ stream });
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
if (signal?.aborted) {
|
|
208
|
-
return new Response("Aborted", { status: 499 });
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
// Create a placeholder message for streaming (backend-managed)
|
|
212
|
-
const messageId = Date.now().toString();
|
|
213
|
-
|
|
214
|
-
setMessages((prev) => [
|
|
215
|
-
...prev,
|
|
216
|
-
{
|
|
217
|
-
id: messageId,
|
|
218
|
-
role: "assistant",
|
|
219
|
-
parts: [{ type: "text", text: "" }],
|
|
220
|
-
},
|
|
221
|
-
]);
|
|
222
|
-
|
|
223
|
-
// Create an abort-aware promise for the send_prompt call
|
|
224
|
-
const sendPromptPromise = props.send_prompt({
|
|
225
|
-
messages: messages,
|
|
226
|
-
config: chatConfig,
|
|
227
|
-
});
|
|
228
|
-
|
|
229
|
-
// Race the send_prompt with an abort signal
|
|
230
|
-
const response = await new Promise<string | null>(
|
|
231
|
-
(resolve, reject) => {
|
|
232
|
-
// Listen for abort
|
|
233
172
|
const abortHandler = () => {
|
|
234
|
-
|
|
173
|
+
try {
|
|
174
|
+
controller.close();
|
|
175
|
+
} catch (error) {
|
|
176
|
+
Logger.debug("Controller may already be closed", { error });
|
|
177
|
+
}
|
|
178
|
+
frontendStreamControllerRef.current = null;
|
|
235
179
|
};
|
|
236
180
|
signal?.addEventListener("abort", abortHandler);
|
|
237
181
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
.finally(() => {
|
|
242
|
-
signal?.removeEventListener("abort", abortHandler);
|
|
243
|
-
});
|
|
182
|
+
return () => {
|
|
183
|
+
signal?.removeEventListener("abort", abortHandler);
|
|
184
|
+
};
|
|
244
185
|
},
|
|
245
|
-
|
|
186
|
+
cancel() {
|
|
187
|
+
frontendStreamControllerRef.current = null;
|
|
188
|
+
},
|
|
189
|
+
});
|
|
246
190
|
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
191
|
+
// Start the prompt, chunks will be sent via events
|
|
192
|
+
void props
|
|
193
|
+
.send_prompt({
|
|
194
|
+
messages: messages,
|
|
195
|
+
config: chatConfig,
|
|
196
|
+
})
|
|
197
|
+
.catch((error: Error) => {
|
|
198
|
+
frontendStreamControllerRef.current?.error(error);
|
|
199
|
+
frontendStreamControllerRef.current = null;
|
|
250
200
|
});
|
|
251
|
-
return new Response("Internal server error", { status: 500 });
|
|
252
|
-
}
|
|
253
201
|
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
if (
|
|
257
|
-
streamingStateRef.current.backendMessageId === null &&
|
|
258
|
-
streamingStateRef.current.frontendMessageIndex === null
|
|
259
|
-
) {
|
|
260
|
-
setMessages((prev) => {
|
|
261
|
-
const updated = [...prev];
|
|
262
|
-
const index = updated.findIndex((m) => m.id === messageId);
|
|
263
|
-
if (index !== -1) {
|
|
264
|
-
updated[index] = {
|
|
265
|
-
...updated[index],
|
|
266
|
-
parts: [{ type: "text", text: response }],
|
|
267
|
-
};
|
|
268
|
-
}
|
|
269
|
-
return updated;
|
|
270
|
-
});
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
return new Response(response);
|
|
274
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
275
|
-
} catch (error: any) {
|
|
202
|
+
return createUIMessageStreamResponse({ stream });
|
|
203
|
+
} catch (error: unknown) {
|
|
276
204
|
// Clear streaming state on error
|
|
277
205
|
streamingStateRef.current = {
|
|
278
206
|
backendMessageId: null,
|
|
@@ -280,13 +208,13 @@ export const Chatbot: React.FC<Props> = (props) => {
|
|
|
280
208
|
};
|
|
281
209
|
|
|
282
210
|
// Handle abort gracefully without showing an error
|
|
283
|
-
if (error.name === "AbortError") {
|
|
211
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
284
212
|
return new Response("Aborted", { status: 499 });
|
|
285
213
|
}
|
|
286
214
|
|
|
287
215
|
// HACK: strip the error message to clean up the response
|
|
288
|
-
const strippedError = error.message
|
|
289
|
-
|
|
216
|
+
const strippedError = (error as Error).message
|
|
217
|
+
?.split("failed with exception ")
|
|
290
218
|
.pop();
|
|
291
219
|
return new Response(strippedError, { status: 400 });
|
|
292
220
|
}
|
|
@@ -307,11 +235,7 @@ export const Chatbot: React.FC<Props> = (props) => {
|
|
|
307
235
|
frontendMessageIndex: null,
|
|
308
236
|
};
|
|
309
237
|
|
|
310
|
-
|
|
311
|
-
// Because useChat creates the proper message structure for us.
|
|
312
|
-
if (props.frontendManaged) {
|
|
313
|
-
props.setValue(message.messages);
|
|
314
|
-
}
|
|
238
|
+
props.setValue(message.messages);
|
|
315
239
|
},
|
|
316
240
|
onError: (error) => {
|
|
317
241
|
Logger.error("An error occurred:", error);
|
|
@@ -338,90 +262,28 @@ export const Chatbot: React.FC<Props> = (props) => {
|
|
|
338
262
|
return;
|
|
339
263
|
}
|
|
340
264
|
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
if (!controller) {
|
|
345
|
-
return;
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
const frontendMessage = message as {
|
|
349
|
-
type: string;
|
|
350
|
-
message_id: string;
|
|
351
|
-
content?: UIMessageChunk;
|
|
352
|
-
is_final?: boolean;
|
|
353
|
-
};
|
|
354
|
-
|
|
355
|
-
if (frontendMessage.content) {
|
|
356
|
-
controller.enqueue(frontendMessage.content);
|
|
357
|
-
}
|
|
358
|
-
if (frontendMessage.is_final) {
|
|
359
|
-
controller.close();
|
|
360
|
-
frontendStreamControllerRef.current = null;
|
|
361
|
-
}
|
|
265
|
+
// Push to the stream for useChat to process
|
|
266
|
+
const controller = frontendStreamControllerRef.current;
|
|
267
|
+
if (!controller) {
|
|
362
268
|
return;
|
|
363
269
|
}
|
|
364
270
|
|
|
365
|
-
|
|
366
|
-
const chunkMessage = message as {
|
|
271
|
+
const frontendMessage = message as {
|
|
367
272
|
type: string;
|
|
368
273
|
message_id: string;
|
|
369
|
-
content
|
|
370
|
-
is_final
|
|
274
|
+
content?: UIMessageChunk;
|
|
275
|
+
is_final?: boolean;
|
|
371
276
|
};
|
|
372
277
|
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
// Find the last assistant message (which should be the placeholder we created)
|
|
376
|
-
setMessages((prev) => {
|
|
377
|
-
const updated = [...prev];
|
|
378
|
-
// Find the last assistant message
|
|
379
|
-
for (let i = updated.length - 1; i >= 0; i--) {
|
|
380
|
-
if (updated[i].role === "assistant") {
|
|
381
|
-
streamingStateRef.current = {
|
|
382
|
-
backendMessageId: chunkMessage.message_id,
|
|
383
|
-
frontendMessageIndex: i,
|
|
384
|
-
};
|
|
385
|
-
break;
|
|
386
|
-
}
|
|
387
|
-
}
|
|
388
|
-
return updated;
|
|
389
|
-
});
|
|
278
|
+
if (frontendMessage.content) {
|
|
279
|
+
controller.enqueue(frontendMessage.content);
|
|
390
280
|
}
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
if (
|
|
395
|
-
streamingStateRef.current.backendMessageId ===
|
|
396
|
-
chunkMessage.message_id &&
|
|
397
|
-
frontendIndex !== null
|
|
398
|
-
) {
|
|
399
|
-
setMessages((prev) => {
|
|
400
|
-
const updated = [...prev];
|
|
401
|
-
const index = frontendIndex;
|
|
402
|
-
|
|
403
|
-
// Update the message at the tracked index
|
|
404
|
-
if (index < updated.length) {
|
|
405
|
-
const messageToUpdate = updated[index];
|
|
406
|
-
if (messageToUpdate.role === "assistant") {
|
|
407
|
-
updated[index] = {
|
|
408
|
-
...messageToUpdate,
|
|
409
|
-
parts: [{ type: "text", text: chunkMessage.content }],
|
|
410
|
-
};
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
return updated;
|
|
415
|
-
});
|
|
416
|
-
|
|
417
|
-
// Clear streaming state when final chunk arrives
|
|
418
|
-
if (chunkMessage.is_final) {
|
|
419
|
-
streamingStateRef.current = {
|
|
420
|
-
backendMessageId: null,
|
|
421
|
-
frontendMessageIndex: null,
|
|
422
|
-
};
|
|
423
|
-
}
|
|
281
|
+
if (frontendMessage.is_final) {
|
|
282
|
+
controller.close();
|
|
283
|
+
frontendStreamControllerRef.current = null;
|
|
424
284
|
}
|
|
285
|
+
|
|
286
|
+
return;
|
|
425
287
|
},
|
|
426
288
|
);
|
|
427
289
|
|
|
@@ -434,10 +296,7 @@ export const Chatbot: React.FC<Props> = (props) => {
|
|
|
434
296
|
props.delete_chat_message({ index });
|
|
435
297
|
setMessages(newMessages);
|
|
436
298
|
|
|
437
|
-
|
|
438
|
-
if (props.frontendManaged) {
|
|
439
|
-
props.setValue(newMessages);
|
|
440
|
-
}
|
|
299
|
+
props.setValue(newMessages);
|
|
441
300
|
}
|
|
442
301
|
};
|
|
443
302
|
|
|
@@ -526,7 +385,7 @@ export const Chatbot: React.FC<Props> = (props) => {
|
|
|
526
385
|
|
|
527
386
|
return (
|
|
528
387
|
<div
|
|
529
|
-
key={message.id}
|
|
388
|
+
key={`${message.id}-${index}`}
|
|
530
389
|
className={cn(
|
|
531
390
|
"flex flex-col group gap-2",
|
|
532
391
|
message.role === "user" ? "items-end" : "items-start",
|
|
@@ -8,18 +8,6 @@ export interface ChatMessage extends UIMessage {
|
|
|
8
8
|
content: string | null; // Content is only added for backwards compatibility
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
export interface SendMessageRequest {
|
|
12
|
-
messages: ChatMessage[];
|
|
13
|
-
config: {
|
|
14
|
-
max_tokens: number | null;
|
|
15
|
-
temperature: number | null;
|
|
16
|
-
top_p: number | null;
|
|
17
|
-
top_k: number | null;
|
|
18
|
-
frequency_penalty: number | null;
|
|
19
|
-
presence_penalty: number | null;
|
|
20
|
-
};
|
|
21
|
-
}
|
|
22
|
-
|
|
23
11
|
/**
|
|
24
12
|
* These are snake_case because they come from the backend,
|
|
25
13
|
* and are not modified when sent to the frontend.
|
|
@@ -32,3 +20,8 @@ export interface ChatConfig {
|
|
|
32
20
|
frequency_penalty: number | null;
|
|
33
21
|
presence_penalty: number | null;
|
|
34
22
|
}
|
|
23
|
+
|
|
24
|
+
export interface SendMessageRequest {
|
|
25
|
+
messages: ChatMessage[];
|
|
26
|
+
config: ChatConfig;
|
|
27
|
+
}
|