@marimo-team/islands 0.19.3-dev42 → 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/main.js +43 -135
- package/package.json +1 -1
- package/src/plugins/impl/chat/ChatPlugin.tsx +2 -4
- package/src/plugins/impl/chat/chat-ui.tsx +46 -187
package/dist/main.js
CHANGED
|
@@ -71227,6 +71227,7 @@ Image URL: ${r.imageUrl}`)), contextToXml({
|
|
|
71227
71227
|
}), z = (0, import_react.useRef)(null), { data: G } = useAsyncData(async () => (await e.get_chat_history({})).messages, []), q = e.value.length > 0 ? e.value : G, { messages: LY, sendMessage: RY, setMessages: zY, status: BY, stop: VY, error: HY, regenerate: UY, clearError: WY } = useChat({
|
|
71228
71228
|
transport: new DefaultChatTransport({
|
|
71229
71229
|
fetch: async (r2, c2) => {
|
|
71230
|
+
var _a3;
|
|
71230
71231
|
if (c2 === void 0) return fetch(r2);
|
|
71231
71232
|
let d2 = JSON.parse(c2.body), f2 = c2.signal, h2 = {
|
|
71232
71233
|
max_tokens: M.current.max_tokens,
|
|
@@ -71238,98 +71239,49 @@ Image URL: ${r.imageUrl}`)), contextToXml({
|
|
|
71238
71239
|
};
|
|
71239
71240
|
try {
|
|
71240
71241
|
let r3 = d2.messages.map((e2) => {
|
|
71241
|
-
var
|
|
71242
|
+
var _a4;
|
|
71242
71243
|
return {
|
|
71243
71244
|
...e2,
|
|
71244
|
-
content: (
|
|
71245
|
+
content: (_a4 = e2.parts) == null ? void 0 : _a4.map((e3) => "text" in e3 ? e3.text : "").join("\n")
|
|
71245
71246
|
};
|
|
71246
|
-
})
|
|
71247
|
-
|
|
71248
|
-
|
|
71249
|
-
|
|
71250
|
-
|
|
71251
|
-
|
|
71252
|
-
|
|
71253
|
-
|
|
71254
|
-
|
|
71255
|
-
|
|
71256
|
-
error: e3
|
|
71257
|
-
});
|
|
71258
|
-
}
|
|
71259
|
-
z.current = null;
|
|
71260
|
-
};
|
|
71261
|
-
return f2 == null ? void 0 : f2.addEventListener("abort", r4), () => {
|
|
71262
|
-
f2 == null ? void 0 : f2.removeEventListener("abort", r4);
|
|
71263
|
-
};
|
|
71264
|
-
},
|
|
71265
|
-
cancel() {
|
|
71266
|
-
z.current = null;
|
|
71267
|
-
}
|
|
71268
|
-
});
|
|
71269
|
-
return e.send_prompt({
|
|
71270
|
-
messages: r3,
|
|
71271
|
-
config: h2
|
|
71272
|
-
}).catch((e2) => {
|
|
71273
|
-
var _a3;
|
|
71274
|
-
(_a3 = z.current) == null ? void 0 : _a3.error(e2), z.current = null;
|
|
71275
|
-
}), createUIMessageStreamResponse({
|
|
71276
|
-
stream: c4
|
|
71277
|
-
});
|
|
71278
|
-
}
|
|
71279
|
-
if (f2 == null ? void 0 : f2.aborted) return new Response("Aborted", {
|
|
71280
|
-
status: 499
|
|
71281
|
-
});
|
|
71282
|
-
let c3 = Date.now().toString();
|
|
71283
|
-
zY((e2) => [
|
|
71284
|
-
...e2,
|
|
71285
|
-
{
|
|
71286
|
-
id: c3,
|
|
71287
|
-
role: "assistant",
|
|
71288
|
-
parts: [
|
|
71289
|
-
{
|
|
71290
|
-
type: "text",
|
|
71291
|
-
text: ""
|
|
71247
|
+
}), c3 = new ReadableStream({
|
|
71248
|
+
start(e2) {
|
|
71249
|
+
z.current = e2;
|
|
71250
|
+
let r4 = () => {
|
|
71251
|
+
try {
|
|
71252
|
+
e2.close();
|
|
71253
|
+
} catch (e3) {
|
|
71254
|
+
Logger.debug("Controller may already be closed", {
|
|
71255
|
+
error: e3
|
|
71256
|
+
});
|
|
71292
71257
|
}
|
|
71293
|
-
|
|
71258
|
+
z.current = null;
|
|
71259
|
+
};
|
|
71260
|
+
return f2 == null ? void 0 : f2.addEventListener("abort", r4), () => {
|
|
71261
|
+
f2 == null ? void 0 : f2.removeEventListener("abort", r4);
|
|
71262
|
+
};
|
|
71263
|
+
},
|
|
71264
|
+
cancel() {
|
|
71265
|
+
z.current = null;
|
|
71294
71266
|
}
|
|
71295
|
-
|
|
71296
|
-
|
|
71267
|
+
});
|
|
71268
|
+
return e.send_prompt({
|
|
71297
71269
|
messages: r3,
|
|
71298
71270
|
config: h2
|
|
71299
|
-
})
|
|
71300
|
-
|
|
71301
|
-
|
|
71302
|
-
|
|
71303
|
-
|
|
71304
|
-
f2 == null ? void 0 : f2.removeEventListener("abort", c4);
|
|
71305
|
-
});
|
|
71271
|
+
}).catch((e2) => {
|
|
71272
|
+
var _a4;
|
|
71273
|
+
(_a4 = z.current) == null ? void 0 : _a4.error(e2), z.current = null;
|
|
71274
|
+
}), createUIMessageStreamResponse({
|
|
71275
|
+
stream: c3
|
|
71306
71276
|
});
|
|
71307
|
-
return v2 === null ? (Logger.error("Non-frontend-managed response is null", {
|
|
71308
|
-
response: v2
|
|
71309
|
-
}), new Response("Internal server error", {
|
|
71310
|
-
status: 500
|
|
71311
|
-
})) : (I.current.backendMessageId === null && I.current.frontendMessageIndex === null && zY((e2) => {
|
|
71312
|
-
let r4 = [
|
|
71313
|
-
...e2
|
|
71314
|
-
], d3 = r4.findIndex((e3) => e3.id === c3);
|
|
71315
|
-
return d3 !== -1 && (r4[d3] = {
|
|
71316
|
-
...r4[d3],
|
|
71317
|
-
parts: [
|
|
71318
|
-
{
|
|
71319
|
-
type: "text",
|
|
71320
|
-
text: v2
|
|
71321
|
-
}
|
|
71322
|
-
]
|
|
71323
|
-
}), r4;
|
|
71324
|
-
}), new Response(v2));
|
|
71325
71277
|
} catch (e2) {
|
|
71326
71278
|
if (I.current = {
|
|
71327
71279
|
backendMessageId: null,
|
|
71328
71280
|
frontendMessageIndex: null
|
|
71329
|
-
}, e2.name === "AbortError") return new Response("Aborted", {
|
|
71281
|
+
}, e2 instanceof Error && e2.name === "AbortError") return new Response("Aborted", {
|
|
71330
71282
|
status: 499
|
|
71331
71283
|
});
|
|
71332
|
-
let r3 = e2.message.split("failed with exception ").pop();
|
|
71284
|
+
let r3 = (_a3 = e2.message) == null ? void 0 : _a3.split("failed with exception ").pop();
|
|
71333
71285
|
return new Response(r3, {
|
|
71334
71286
|
status: 400
|
|
71335
71287
|
});
|
|
@@ -71341,7 +71293,7 @@ Image URL: ${r.imageUrl}`)), contextToXml({
|
|
|
71341
71293
|
y(void 0), S.current && (S.current.value = ""), Logger.debug("Finished streaming message:", r2), I.current = {
|
|
71342
71294
|
backendMessageId: null,
|
|
71343
71295
|
frontendMessageIndex: null
|
|
71344
|
-
}, e.
|
|
71296
|
+
}, e.setValue(r2.messages);
|
|
71345
71297
|
},
|
|
71346
71298
|
onError: (e2) => {
|
|
71347
71299
|
Logger.error("An error occurred:", e2), I.current = {
|
|
@@ -71350,52 +71302,13 @@ Image URL: ${r.imageUrl}`)), contextToXml({
|
|
|
71350
71302
|
};
|
|
71351
71303
|
}
|
|
71352
71304
|
});
|
|
71353
|
-
useEventListener(e.host, MarimoIncomingMessageEvent.TYPE, (
|
|
71354
|
-
let
|
|
71355
|
-
if (typeof
|
|
71356
|
-
|
|
71357
|
-
|
|
71358
|
-
|
|
71359
|
-
|
|
71360
|
-
r3.content && e2.enqueue(r3.content), r3.is_final && (e2.close(), z.current = null);
|
|
71361
|
-
return;
|
|
71362
|
-
}
|
|
71363
|
-
let d2 = c2;
|
|
71364
|
-
I.current.backendMessageId === null && zY((e2) => {
|
|
71365
|
-
let r3 = [
|
|
71366
|
-
...e2
|
|
71367
|
-
];
|
|
71368
|
-
for (let e3 = r3.length - 1; e3 >= 0; e3--) if (r3[e3].role === "assistant") {
|
|
71369
|
-
I.current = {
|
|
71370
|
-
backendMessageId: d2.message_id,
|
|
71371
|
-
frontendMessageIndex: e3
|
|
71372
|
-
};
|
|
71373
|
-
break;
|
|
71374
|
-
}
|
|
71375
|
-
return r3;
|
|
71376
|
-
});
|
|
71377
|
-
let f2 = I.current.frontendMessageIndex;
|
|
71378
|
-
I.current.backendMessageId === d2.message_id && f2 !== null && (zY((e2) => {
|
|
71379
|
-
let r3 = [
|
|
71380
|
-
...e2
|
|
71381
|
-
], c3 = f2;
|
|
71382
|
-
if (c3 < r3.length) {
|
|
71383
|
-
let e3 = r3[c3];
|
|
71384
|
-
e3.role === "assistant" && (r3[c3] = {
|
|
71385
|
-
...e3,
|
|
71386
|
-
parts: [
|
|
71387
|
-
{
|
|
71388
|
-
type: "text",
|
|
71389
|
-
text: d2.content
|
|
71390
|
-
}
|
|
71391
|
-
]
|
|
71392
|
-
});
|
|
71393
|
-
}
|
|
71394
|
-
return r3;
|
|
71395
|
-
}), d2.is_final && (I.current = {
|
|
71396
|
-
backendMessageId: null,
|
|
71397
|
-
frontendMessageIndex: null
|
|
71398
|
-
}));
|
|
71305
|
+
useEventListener(e.host, MarimoIncomingMessageEvent.TYPE, (e2) => {
|
|
71306
|
+
let r2 = e2.detail.message;
|
|
71307
|
+
if (typeof r2 != "object" || !r2 || !("type" in r2) || r2.type !== "stream_chunk") return;
|
|
71308
|
+
let c2 = z.current;
|
|
71309
|
+
if (!c2) return;
|
|
71310
|
+
let d2 = r2;
|
|
71311
|
+
d2.content && c2.enqueue(d2.content), d2.is_final && (c2.close(), z.current = null);
|
|
71399
71312
|
});
|
|
71400
71313
|
let GY = BY === "submitted" || BY === "streaming", KY = (r2) => {
|
|
71401
71314
|
let c2 = LY.findIndex((e2) => e2.id === r2);
|
|
@@ -71403,7 +71316,7 @@ Image URL: ${r.imageUrl}`)), contextToXml({
|
|
|
71403
71316
|
let d2 = LY.filter((e2) => e2.id !== r2);
|
|
71404
71317
|
e.delete_chat_message({
|
|
71405
71318
|
index: c2
|
|
71406
|
-
}), zY(d2), e.
|
|
71319
|
+
}), zY(d2), e.setValue(d2);
|
|
71407
71320
|
}
|
|
71408
71321
|
}, qY = Array.isArray(e.allowAttachments) && e.allowAttachments.length > 0 || e.allowAttachments === true, JY = {
|
|
71409
71322
|
triggerCompletionRegex: /^\/(\w+)?/,
|
|
@@ -71509,7 +71422,7 @@ Image URL: ${r.imageUrl}`)), contextToXml({
|
|
|
71509
71422
|
]
|
|
71510
71423
|
})
|
|
71511
71424
|
]
|
|
71512
|
-
}, e2.id);
|
|
71425
|
+
}, `${e2.id}-${r2}`);
|
|
71513
71426
|
}),
|
|
71514
71427
|
GY && (0, import_jsx_runtime.jsxs)("div", {
|
|
71515
71428
|
className: "flex items-center justify-center space-x-2 mb-4",
|
|
@@ -71975,8 +71888,7 @@ Image URL: ${r.imageUrl}`)), contextToXml({
|
|
|
71975
71888
|
allowAttachments: union([
|
|
71976
71889
|
boolean$2(),
|
|
71977
71890
|
string$2().array()
|
|
71978
|
-
])
|
|
71979
|
-
frontendManaged: boolean$2()
|
|
71891
|
+
])
|
|
71980
71892
|
})).withFunctions({
|
|
71981
71893
|
get_chat_history: rpc.input(object$1({})).output(object$1({
|
|
71982
71894
|
messages: messageSchema
|
|
@@ -71988,10 +71900,7 @@ Image URL: ${r.imageUrl}`)), contextToXml({
|
|
|
71988
71900
|
send_prompt: rpc.input(object$1({
|
|
71989
71901
|
messages: messageSchema,
|
|
71990
71902
|
config: configSchema
|
|
71991
|
-
})).output(
|
|
71992
|
-
string$2(),
|
|
71993
|
-
_null()
|
|
71994
|
-
]))
|
|
71903
|
+
})).output(unknown())
|
|
71995
71904
|
}).renderer((e) => {
|
|
71996
71905
|
var _a2;
|
|
71997
71906
|
return (0, import_jsx_runtime.jsx)(TooltipProvider, {
|
|
@@ -72001,7 +71910,6 @@ Image URL: ${r.imageUrl}`)), contextToXml({
|
|
|
72001
71910
|
showConfigurationControls: e.data.showConfigurationControls,
|
|
72002
71911
|
maxHeight: e.data.maxHeight,
|
|
72003
71912
|
allowAttachments: e.data.allowAttachments,
|
|
72004
|
-
frontendManaged: e.data.frontendManaged,
|
|
72005
71913
|
config: e.data.config,
|
|
72006
71914
|
get_chat_history: e.functions.get_chat_history,
|
|
72007
71915
|
delete_chat_history: e.functions.delete_chat_history,
|
|
@@ -101153,7 +101061,7 @@ Defaulting to \`null\`.`;
|
|
|
101153
101061
|
return Logger.warn("Failed to get version from mount config"), null;
|
|
101154
101062
|
}
|
|
101155
101063
|
}
|
|
101156
|
-
const marimoVersionAtom = atom(getVersionFromMountConfig() || "0.19.3-
|
|
101064
|
+
const marimoVersionAtom = atom(getVersionFromMountConfig() || "0.19.3-dev45"), showCodeInRunModeAtom = atom(true);
|
|
101157
101065
|
atom(null);
|
|
101158
101066
|
var VIRTUAL_FILE_REGEX = /\/@file\/([^\s"&'/]+)\.([\dA-Za-z]+)/g, VirtualFileTracker = class e {
|
|
101159
101067
|
constructor() {
|
package/package.json
CHANGED
|
@@ -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",
|