@assistant-ui/react 0.0.7 → 0.0.9
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/index.d.mts +21 -12
- package/dist/index.d.ts +21 -12
- package/dist/index.js +412 -328
- package/dist/index.mjs +403 -318
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
@@ -11,6 +11,7 @@ __export(thread_exports, {
|
|
11
11
|
If: () => ThreadIf,
|
12
12
|
Messages: () => ThreadMessages,
|
13
13
|
Root: () => ThreadRoot,
|
14
|
+
ScrollToBottom: () => ThreadScrollToBottom,
|
14
15
|
Viewport: () => ThreadViewport
|
15
16
|
});
|
16
17
|
|
@@ -68,7 +69,7 @@ import { useComposedRefs } from "@radix-ui/react-compose-refs";
|
|
68
69
|
import {
|
69
70
|
Primitive as Primitive2
|
70
71
|
} from "@radix-ui/react-primitive";
|
71
|
-
import { forwardRef as forwardRef2, useRef as
|
72
|
+
import { forwardRef as forwardRef2, useRef as useRef3 } from "react";
|
72
73
|
|
73
74
|
// src/utils/hooks/useOnResizeContent.tsx
|
74
75
|
import { useLayoutEffect, useRef } from "react";
|
@@ -109,22 +110,55 @@ var useOnResizeContent = (ref, callback) => {
|
|
109
110
|
}, [ref.current]);
|
110
111
|
};
|
111
112
|
|
113
|
+
// src/utils/hooks/useOnScrollToBottom.tsx
|
114
|
+
import { useEffect, useRef as useRef2 } from "react";
|
115
|
+
var useOnScrollToBottom = (callback) => {
|
116
|
+
const callbackRef = useRef2(callback);
|
117
|
+
callbackRef.current = callback;
|
118
|
+
const { useThread } = useAssistantContext();
|
119
|
+
useEffect(() => {
|
120
|
+
return useThread.getState().onScrollToBottom(() => {
|
121
|
+
callbackRef.current();
|
122
|
+
});
|
123
|
+
}, [useThread]);
|
124
|
+
};
|
125
|
+
|
112
126
|
// src/primitives/thread/ThreadViewport.tsx
|
113
|
-
var ThreadViewport = forwardRef2(({ onScroll, children, ...rest }, forwardedRef) => {
|
114
|
-
const
|
127
|
+
var ThreadViewport = forwardRef2(({ autoScroll = true, onScroll, children, ...rest }, forwardedRef) => {
|
128
|
+
const messagesEndRef = useRef3(null);
|
129
|
+
const divRef = useRef3(null);
|
115
130
|
const ref = useComposedRefs(forwardedRef, divRef);
|
116
|
-
const
|
131
|
+
const { useThread } = useAssistantContext();
|
132
|
+
const firstRenderRef = useRef3(true);
|
133
|
+
const lastScrollTop = useRef3(0);
|
134
|
+
const scrollToBottom = () => {
|
135
|
+
const div = messagesEndRef.current;
|
136
|
+
if (!div || !autoScroll)
|
137
|
+
return;
|
138
|
+
const behavior = firstRenderRef.current ? "instant" : "auto";
|
139
|
+
firstRenderRef.current = false;
|
140
|
+
useThread.setState({ isAtBottom: true });
|
141
|
+
div.scrollIntoView({ behavior });
|
142
|
+
};
|
117
143
|
useOnResizeContent(divRef, () => {
|
118
|
-
|
119
|
-
if (!div || !isAtBottom)
|
144
|
+
if (!useThread.getState().isAtBottom)
|
120
145
|
return;
|
121
|
-
|
146
|
+
scrollToBottom();
|
147
|
+
});
|
148
|
+
useOnScrollToBottom(() => {
|
149
|
+
scrollToBottom();
|
122
150
|
});
|
123
151
|
const handleScroll = () => {
|
124
152
|
const div = divRef.current;
|
125
153
|
if (!div)
|
126
154
|
return;
|
127
|
-
|
155
|
+
const isAtBottom = useThread.getState().isAtBottom;
|
156
|
+
const newIsAtBottom = div.scrollHeight - div.scrollTop <= div.clientHeight;
|
157
|
+
if (!newIsAtBottom && lastScrollTop.current < div.scrollTop) {
|
158
|
+
} else if (newIsAtBottom !== isAtBottom) {
|
159
|
+
useThread.setState({ isAtBottom: newIsAtBottom });
|
160
|
+
}
|
161
|
+
lastScrollTop.current = div.scrollTop;
|
128
162
|
};
|
129
163
|
return /* @__PURE__ */ React.createElement(
|
130
164
|
Primitive2.div,
|
@@ -133,19 +167,24 @@ var ThreadViewport = forwardRef2(({ onScroll, children, ...rest }, forwardedRef)
|
|
133
167
|
onScroll: composeEventHandlers(onScroll, handleScroll),
|
134
168
|
ref
|
135
169
|
},
|
136
|
-
children
|
170
|
+
children,
|
171
|
+
/* @__PURE__ */ React.createElement("div", { ref: messagesEndRef })
|
137
172
|
);
|
138
173
|
});
|
139
174
|
|
140
|
-
// src/vercel/useVercelAIBranches.tsx
|
141
|
-
import { useCallback, useMemo, useRef as
|
142
|
-
|
175
|
+
// src/adapters/vercel/useVercelAIBranches.tsx
|
176
|
+
import { useCallback, useMemo, useRef as useRef4 } from "react";
|
177
|
+
|
178
|
+
// src/utils/context/stores/AssistantTypes.ts
|
179
|
+
var ROOT_PARENT_ID = "__ROOT_ID__";
|
180
|
+
|
181
|
+
// src/adapters/vercel/useVercelAIBranches.tsx
|
143
182
|
var UPCOMING_MESSAGE_ID = "__UPCOMING_MESSAGE_ID__";
|
144
183
|
var updateBranchData = (data, messages) => {
|
145
184
|
for (let i = 0; i < messages.length; i++) {
|
146
185
|
const child = messages[i];
|
147
186
|
const childId = child.id;
|
148
|
-
const parentId = messages[i - 1]?.id ??
|
187
|
+
const parentId = messages[i - 1]?.id ?? ROOT_PARENT_ID;
|
149
188
|
data.parentMap.set(childId, parentId);
|
150
189
|
const parentArray = data.branchMap.get(parentId);
|
151
190
|
if (!parentArray) {
|
@@ -156,32 +195,32 @@ var updateBranchData = (data, messages) => {
|
|
156
195
|
data.snapshots.set(childId, messages);
|
157
196
|
}
|
158
197
|
};
|
159
|
-
var getParentId = (data, messages,
|
160
|
-
if (
|
198
|
+
var getParentId = (data, messages, messageId) => {
|
199
|
+
if (messageId === UPCOMING_MESSAGE_ID) {
|
161
200
|
const parent = messages.at(-1);
|
162
201
|
if (!parent)
|
163
|
-
return
|
202
|
+
return ROOT_PARENT_ID;
|
164
203
|
return parent.id;
|
165
204
|
}
|
166
|
-
const parentId = data.parentMap.get(
|
205
|
+
const parentId = data.parentMap.get(messageId);
|
167
206
|
if (!parentId)
|
168
207
|
throw new Error("Unexpected: Message parent not found");
|
169
208
|
return parentId;
|
170
209
|
};
|
171
|
-
var getBranchStateImpl = (data, messages,
|
172
|
-
const parentId = getParentId(data, messages,
|
210
|
+
var getBranchStateImpl = (data, messages, messageId) => {
|
211
|
+
const parentId = getParentId(data, messages, messageId);
|
173
212
|
const branches = data.branchMap.get(parentId) ?? [];
|
174
|
-
const branchId =
|
213
|
+
const branchId = messageId === UPCOMING_MESSAGE_ID ? branches.length : branches.indexOf(messageId);
|
175
214
|
if (branchId === -1)
|
176
215
|
throw new Error("Unexpected: Message not found in parent children");
|
177
|
-
const upcomingOffset =
|
216
|
+
const upcomingOffset = messageId === UPCOMING_MESSAGE_ID ? 1 : 0;
|
178
217
|
return {
|
179
218
|
branchId,
|
180
219
|
branchCount: branches.length + upcomingOffset
|
181
220
|
};
|
182
221
|
};
|
183
|
-
var switchToBranchImpl = (data, messages,
|
184
|
-
const parentId = getParentId(data, messages,
|
222
|
+
var switchToBranchImpl = (data, messages, messageId, branchId) => {
|
223
|
+
const parentId = getParentId(data, messages, messageId);
|
185
224
|
const branches = data.branchMap.get(parentId);
|
186
225
|
if (!branches)
|
187
226
|
throw new Error("Unexpected: Parent children not found");
|
@@ -190,40 +229,42 @@ var switchToBranchImpl = (data, messages, message, branchId) => {
|
|
190
229
|
throw new Error("Unexpected: Requested branch not found");
|
191
230
|
if (branchId < 0 || branchId >= branches.length)
|
192
231
|
throw new Error("Switch to branch called with a branch index out of range");
|
193
|
-
if (newMessageId ===
|
232
|
+
if (newMessageId === messageId)
|
194
233
|
return messages;
|
195
234
|
const snapshot = data.snapshots.get(newMessageId);
|
196
235
|
if (!snapshot)
|
197
236
|
throw new Error("Unexpected: Branch snapshot not found");
|
198
237
|
return snapshot;
|
199
238
|
};
|
200
|
-
var sliceMessagesUntil = (messages,
|
201
|
-
if (
|
239
|
+
var sliceMessagesUntil = (messages, messageId) => {
|
240
|
+
if (messageId === ROOT_PARENT_ID)
|
241
|
+
return [];
|
242
|
+
if (messageId === UPCOMING_MESSAGE_ID)
|
202
243
|
return messages;
|
203
|
-
const messageIdx = messages.findIndex((m) => m.id ===
|
244
|
+
const messageIdx = messages.findIndex((m) => m.id === messageId);
|
204
245
|
if (messageIdx === -1)
|
205
246
|
throw new Error("Unexpected: Message not found");
|
206
|
-
return messages.slice(0, messageIdx);
|
247
|
+
return messages.slice(0, messageIdx + 1);
|
207
248
|
};
|
208
|
-
var useVercelAIBranches = (chat) => {
|
209
|
-
const data =
|
249
|
+
var useVercelAIBranches = (chat, context) => {
|
250
|
+
const data = useRef4({
|
210
251
|
parentMap: /* @__PURE__ */ new Map(),
|
211
252
|
branchMap: /* @__PURE__ */ new Map(),
|
212
253
|
snapshots: /* @__PURE__ */ new Map()
|
213
254
|
}).current;
|
214
255
|
updateBranchData(data, chat.messages);
|
215
256
|
const getBranchState = useCallback(
|
216
|
-
(
|
217
|
-
return getBranchStateImpl(data, chat.messages,
|
257
|
+
(messageId) => {
|
258
|
+
return getBranchStateImpl(data, chat.messages, messageId);
|
218
259
|
},
|
219
260
|
[data, chat.messages]
|
220
261
|
);
|
221
262
|
const switchToBranch = useCallback(
|
222
|
-
(
|
263
|
+
(messageId, branchId) => {
|
223
264
|
const newMessages = switchToBranchImpl(
|
224
265
|
data,
|
225
266
|
chat.messages,
|
226
|
-
|
267
|
+
messageId,
|
227
268
|
branchId
|
228
269
|
);
|
229
270
|
chat.setMessages(newMessages);
|
@@ -231,47 +272,49 @@ var useVercelAIBranches = (chat) => {
|
|
231
272
|
[data, chat.messages, chat.setMessages]
|
232
273
|
);
|
233
274
|
const reloadMaybe = "reload" in chat ? chat.reload : void 0;
|
234
|
-
const
|
235
|
-
async (
|
275
|
+
const reload = useCallback(
|
276
|
+
async (messageId) => {
|
236
277
|
if (!reloadMaybe)
|
237
278
|
throw new Error("Reload not supported by Vercel AI SDK's useAssistant");
|
238
|
-
const newMessages = sliceMessagesUntil(chat.messages,
|
279
|
+
const newMessages = sliceMessagesUntil(chat.messages, messageId);
|
239
280
|
chat.setMessages(newMessages);
|
281
|
+
context.useThread.getState().scrollToBottom();
|
240
282
|
await reloadMaybe();
|
241
283
|
},
|
242
|
-
[chat.messages, chat.setMessages, reloadMaybe]
|
284
|
+
[context, chat.messages, chat.setMessages, reloadMaybe]
|
243
285
|
);
|
244
|
-
const
|
245
|
-
async (message
|
246
|
-
const newMessages = sliceMessagesUntil(chat.messages, message);
|
286
|
+
const append = useCallback(
|
287
|
+
async (message) => {
|
288
|
+
const newMessages = sliceMessagesUntil(chat.messages, message.parentId);
|
247
289
|
chat.setMessages(newMessages);
|
248
|
-
if (
|
290
|
+
if (message.content.length !== 1 || message.content[0]?.type !== "text")
|
249
291
|
throw new Error("Only text content is currently supported");
|
292
|
+
context.useThread.getState().scrollToBottom();
|
250
293
|
await chat.append({
|
251
294
|
role: "user",
|
252
|
-
content:
|
295
|
+
content: message.content[0].text
|
253
296
|
});
|
254
297
|
},
|
255
|
-
[chat.messages, chat.setMessages, chat.append]
|
298
|
+
[context, chat.messages, chat.setMessages, chat.append]
|
256
299
|
);
|
257
300
|
return useMemo(
|
258
301
|
() => ({
|
259
302
|
getBranchState,
|
260
303
|
switchToBranch,
|
261
|
-
|
262
|
-
|
304
|
+
append,
|
305
|
+
reload
|
263
306
|
}),
|
264
|
-
[getBranchState, switchToBranch,
|
307
|
+
[getBranchState, switchToBranch, append, reload]
|
265
308
|
);
|
266
309
|
};
|
267
310
|
var hasUpcomingMessage = (thread) => {
|
268
311
|
return thread.isLoading && thread.messages[thread.messages.length - 1]?.role !== "assistant";
|
269
312
|
};
|
270
313
|
|
271
|
-
// src/utils/context/
|
314
|
+
// src/utils/context/useComposerContext.ts
|
272
315
|
import { useContext as useContext3 } from "react";
|
273
316
|
|
274
|
-
// src/utils/context/
|
317
|
+
// src/utils/context/useMessageContext.ts
|
275
318
|
import { createContext as createContext2, useContext as useContext2 } from "react";
|
276
319
|
var MessageContext = createContext2(null);
|
277
320
|
var useMessageContext = () => {
|
@@ -281,11 +324,14 @@ var useMessageContext = () => {
|
|
281
324
|
return context;
|
282
325
|
};
|
283
326
|
|
284
|
-
// src/utils/context/
|
327
|
+
// src/utils/context/useComposerContext.ts
|
285
328
|
var useComposerContext = () => {
|
286
329
|
const { useComposer: useAssisstantComposer } = useAssistantContext();
|
287
330
|
const { useComposer: useMessageComposer } = useContext3(MessageContext) ?? {};
|
288
|
-
return {
|
331
|
+
return {
|
332
|
+
useComposer: useMessageComposer ?? useAssisstantComposer,
|
333
|
+
type: useMessageComposer ? "message" : "assistant"
|
334
|
+
};
|
289
335
|
};
|
290
336
|
|
291
337
|
// src/primitives/composer/ComposerIf.tsx
|
@@ -314,16 +360,15 @@ __export(message_exports, {
|
|
314
360
|
});
|
315
361
|
|
316
362
|
// src/primitives/message/MessageProvider.tsx
|
317
|
-
import { useMemo as useMemo2, useState
|
363
|
+
import { useMemo as useMemo2, useState } from "react";
|
318
364
|
import { create } from "zustand";
|
319
|
-
import { useShallow } from "zustand/react/shallow";
|
320
365
|
var getIsLast = (thread, message) => {
|
321
366
|
const hasUpcoming = hasUpcomingMessage(thread);
|
322
367
|
return hasUpcoming ? message.id === UPCOMING_MESSAGE_ID : thread.messages[thread.messages.length - 1]?.id === message.id;
|
323
368
|
};
|
324
369
|
var useMessageContext2 = () => {
|
325
|
-
const
|
326
|
-
|
370
|
+
const [context] = useState(() => {
|
371
|
+
const { useThread } = useAssistantContext();
|
327
372
|
const useMessage = create(() => ({
|
328
373
|
message: null,
|
329
374
|
isLast: false,
|
@@ -332,10 +377,6 @@ var useMessageContext2 = () => {
|
|
332
377
|
setIsCopied: () => {
|
333
378
|
},
|
334
379
|
setIsHovering: () => {
|
335
|
-
},
|
336
|
-
branchState: {
|
337
|
-
branchId: 0,
|
338
|
-
branchCount: 0
|
339
380
|
}
|
340
381
|
}));
|
341
382
|
const useComposer = create((set, get) => ({
|
@@ -357,8 +398,8 @@ var useMessageContext2 = () => {
|
|
357
398
|
const message = useMessage.getState().message;
|
358
399
|
if (message.role !== "user")
|
359
400
|
throw new Error("Editing is only supported for user messages");
|
360
|
-
|
361
|
-
|
401
|
+
useThread.getState().append({
|
402
|
+
parentId: message.parentId,
|
362
403
|
content: [{ type: "text", text: get().value }]
|
363
404
|
});
|
364
405
|
set({ isEditing: false });
|
@@ -374,14 +415,11 @@ var MessageProvider = ({
|
|
374
415
|
message,
|
375
416
|
children
|
376
417
|
}) => {
|
377
|
-
const { useThread
|
418
|
+
const { useThread } = useAssistantContext();
|
378
419
|
const context = useMessageContext2();
|
379
|
-
const branchState = useBranchObserver(
|
380
|
-
useShallow((b) => b.getBranchState(message))
|
381
|
-
);
|
382
420
|
const isLast = useThread((thread) => getIsLast(thread, message));
|
383
|
-
const [isCopied, setIsCopied] =
|
384
|
-
const [isHovering, setIsHovering] =
|
421
|
+
const [isCopied, setIsCopied] = useState(false);
|
422
|
+
const [isHovering, setIsHovering] = useState(false);
|
385
423
|
useMemo2(() => {
|
386
424
|
context.useMessage.setState(
|
387
425
|
{
|
@@ -390,12 +428,11 @@ var MessageProvider = ({
|
|
390
428
|
isCopied,
|
391
429
|
isHovering,
|
392
430
|
setIsCopied,
|
393
|
-
setIsHovering
|
394
|
-
branchState
|
431
|
+
setIsHovering
|
395
432
|
},
|
396
433
|
true
|
397
434
|
);
|
398
|
-
}, [context, message, isLast, isCopied, isHovering
|
435
|
+
}, [context, message, isLast, isCopied, isHovering]);
|
399
436
|
return /* @__PURE__ */ React.createElement(MessageContext.Provider, { value: context }, children);
|
400
437
|
};
|
401
438
|
|
@@ -430,29 +467,21 @@ var MessageRoot = forwardRef3(
|
|
430
467
|
// src/primitives/message/MessageIf.tsx
|
431
468
|
var useMessageIf = (props) => {
|
432
469
|
const { useMessage } = useMessageContext();
|
433
|
-
return useMessage(
|
434
|
-
(
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
return false;
|
449
|
-
if (props.copied === true && !isCopied)
|
450
|
-
return false;
|
451
|
-
if (props.copied === false && isCopied)
|
452
|
-
return false;
|
453
|
-
return true;
|
454
|
-
}
|
455
|
-
);
|
470
|
+
return useMessage(({ message, isLast, isCopied, isHovering }) => {
|
471
|
+
if (props.hasBranches === true && message.branchCount < 2)
|
472
|
+
return false;
|
473
|
+
if (props.user && message.role !== "user")
|
474
|
+
return false;
|
475
|
+
if (props.assistant && message.role !== "assistant")
|
476
|
+
return false;
|
477
|
+
if (props.lastOrHover === true && !isHovering && !isLast)
|
478
|
+
return false;
|
479
|
+
if (props.copied === true && !isCopied)
|
480
|
+
return false;
|
481
|
+
if (props.copied === false && isCopied)
|
482
|
+
return false;
|
483
|
+
return true;
|
484
|
+
});
|
456
485
|
};
|
457
486
|
var MessageIf = ({ children, ...query }) => {
|
458
487
|
const result = useMessageIf(query);
|
@@ -523,13 +552,42 @@ var ThreadMessages = ({ components }) => {
|
|
523
552
|
message: {
|
524
553
|
id: UPCOMING_MESSAGE_ID,
|
525
554
|
role: "assistant",
|
526
|
-
content: [{ type: "text", text: "..." }]
|
555
|
+
content: [{ type: "text", text: "..." }],
|
556
|
+
parentId: messages.at(-1)?.id ?? ROOT_PARENT_ID,
|
557
|
+
// TODO fix these (move upcoming message to AssistantContext)
|
558
|
+
branchId: 0,
|
559
|
+
branchCount: 1,
|
560
|
+
createdAt: /* @__PURE__ */ new Date()
|
527
561
|
}
|
528
562
|
},
|
529
563
|
/* @__PURE__ */ React.createElement(AssistantMessage, null)
|
530
564
|
));
|
531
565
|
};
|
532
566
|
|
567
|
+
// src/primitives/thread/ThreadScrollToBottom.tsx
|
568
|
+
import { composeEventHandlers as composeEventHandlers3 } from "@radix-ui/primitive";
|
569
|
+
import {
|
570
|
+
Primitive as Primitive4
|
571
|
+
} from "@radix-ui/react-primitive";
|
572
|
+
import { forwardRef as forwardRef4 } from "react";
|
573
|
+
var ThreadScrollToBottom = forwardRef4(({ onClick, ...rest }, ref) => {
|
574
|
+
const { useThread } = useAssistantContext();
|
575
|
+
const isAtBottom = useThread((s) => s.isAtBottom);
|
576
|
+
const handleScrollToBottom = () => {
|
577
|
+
const thread = useThread.getState();
|
578
|
+
thread.scrollToBottom();
|
579
|
+
};
|
580
|
+
return /* @__PURE__ */ React.createElement(
|
581
|
+
Primitive4.button,
|
582
|
+
{
|
583
|
+
...rest,
|
584
|
+
disabled: isAtBottom,
|
585
|
+
ref,
|
586
|
+
onClick: composeEventHandlers3(onClick, handleScrollToBottom)
|
587
|
+
}
|
588
|
+
);
|
589
|
+
});
|
590
|
+
|
533
591
|
// src/primitives/composer/index.ts
|
534
592
|
var composer_exports = {};
|
535
593
|
__export(composer_exports, {
|
@@ -541,41 +599,17 @@ __export(composer_exports, {
|
|
541
599
|
});
|
542
600
|
|
543
601
|
// src/primitives/composer/ComposerRoot.tsx
|
544
|
-
import { composeEventHandlers as
|
602
|
+
import { composeEventHandlers as composeEventHandlers4 } from "@radix-ui/primitive";
|
545
603
|
import { useComposedRefs as useComposedRefs2 } from "@radix-ui/react-compose-refs";
|
546
604
|
import {
|
547
|
-
Primitive as
|
605
|
+
Primitive as Primitive5
|
548
606
|
} from "@radix-ui/react-primitive";
|
549
|
-
import {
|
550
|
-
|
551
|
-
forwardRef as forwardRef4,
|
552
|
-
useContext as useContext4,
|
553
|
-
useMemo as useMemo3,
|
554
|
-
useRef as useRef4
|
555
|
-
} from "react";
|
556
|
-
var ComposerFormContext = createContext3(null);
|
557
|
-
var useComposerFormContext = () => {
|
558
|
-
const context = useContext4(ComposerFormContext);
|
559
|
-
if (!context) {
|
560
|
-
throw new Error(
|
561
|
-
"Composer compound components cannot be rendered outside the Composer component"
|
562
|
-
);
|
563
|
-
}
|
564
|
-
return context;
|
565
|
-
};
|
566
|
-
var ComposerRoot = forwardRef4(
|
607
|
+
import { forwardRef as forwardRef5, useRef as useRef5 } from "react";
|
608
|
+
var ComposerRoot = forwardRef5(
|
567
609
|
({ onSubmit, ...rest }, forwardedRef) => {
|
568
610
|
const { useComposer } = useComposerContext();
|
569
|
-
const formRef =
|
611
|
+
const formRef = useRef5(null);
|
570
612
|
const ref = useComposedRefs2(forwardedRef, formRef);
|
571
|
-
const composerContextValue = useMemo3(
|
572
|
-
() => ({
|
573
|
-
submit: () => formRef.current?.dispatchEvent(
|
574
|
-
new Event("submit", { cancelable: true, bubbles: true })
|
575
|
-
)
|
576
|
-
}),
|
577
|
-
[]
|
578
|
-
);
|
579
613
|
const handleSubmit = (e) => {
|
580
614
|
const composerState = useComposer.getState();
|
581
615
|
if (!composerState.isEditing)
|
@@ -583,75 +617,103 @@ var ComposerRoot = forwardRef4(
|
|
583
617
|
e.preventDefault();
|
584
618
|
composerState.send();
|
585
619
|
};
|
586
|
-
return /* @__PURE__ */ React.createElement(
|
587
|
-
|
620
|
+
return /* @__PURE__ */ React.createElement(
|
621
|
+
Primitive5.form,
|
588
622
|
{
|
589
623
|
...rest,
|
590
624
|
ref,
|
591
|
-
onSubmit:
|
625
|
+
onSubmit: composeEventHandlers4(onSubmit, handleSubmit)
|
592
626
|
}
|
593
|
-
)
|
627
|
+
);
|
594
628
|
}
|
595
629
|
);
|
596
630
|
|
597
631
|
// src/primitives/composer/ComposerInput.tsx
|
598
|
-
import { composeEventHandlers as
|
632
|
+
import { composeEventHandlers as composeEventHandlers5 } from "@radix-ui/primitive";
|
633
|
+
import { useComposedRefs as useComposedRefs3 } from "@radix-ui/react-compose-refs";
|
599
634
|
import { Slot } from "@radix-ui/react-slot";
|
600
|
-
import {
|
635
|
+
import {
|
636
|
+
forwardRef as forwardRef6,
|
637
|
+
useCallback as useCallback2,
|
638
|
+
useEffect as useEffect2,
|
639
|
+
useRef as useRef6
|
640
|
+
} from "react";
|
601
641
|
import TextareaAutosize from "react-textarea-autosize";
|
602
|
-
var ComposerInput =
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
}
|
641
|
-
|
642
|
-
|
642
|
+
var ComposerInput = forwardRef6(
|
643
|
+
({ autoFocus, asChild, disabled, onChange, onKeyDown, ...rest }, forwardedRef) => {
|
644
|
+
const { useThread } = useAssistantContext();
|
645
|
+
const { useComposer, type } = useComposerContext();
|
646
|
+
const value = useComposer((c) => {
|
647
|
+
if (!c.isEditing)
|
648
|
+
return "";
|
649
|
+
return c.value;
|
650
|
+
});
|
651
|
+
const Component = asChild ? Slot : TextareaAutosize;
|
652
|
+
const handleKeyPress = (e) => {
|
653
|
+
if (disabled)
|
654
|
+
return;
|
655
|
+
const composer = useComposer.getState();
|
656
|
+
if (e.key === "Escape" && composer.canCancel) {
|
657
|
+
e.preventDefault();
|
658
|
+
useComposer.getState().cancel();
|
659
|
+
}
|
660
|
+
if (e.key === "Enter" && e.shiftKey === false) {
|
661
|
+
const isLoading = useThread.getState().isLoading;
|
662
|
+
if (!isLoading) {
|
663
|
+
e.preventDefault();
|
664
|
+
composer.send();
|
665
|
+
}
|
666
|
+
}
|
667
|
+
};
|
668
|
+
const textareaRef = useRef6(null);
|
669
|
+
const ref = useComposedRefs3(forwardedRef, textareaRef);
|
670
|
+
const autoFocusEnabled = autoFocus !== false && !disabled;
|
671
|
+
const focus = useCallback2(() => {
|
672
|
+
const textarea = textareaRef.current;
|
673
|
+
if (!textarea || !autoFocusEnabled)
|
674
|
+
return;
|
675
|
+
textarea.focus();
|
676
|
+
textarea.setSelectionRange(
|
677
|
+
textareaRef.current.value.length,
|
678
|
+
textareaRef.current.value.length
|
679
|
+
);
|
680
|
+
}, [autoFocusEnabled]);
|
681
|
+
useEffect2(() => focus(), [focus]);
|
682
|
+
useOnScrollToBottom(() => {
|
683
|
+
if (type === "assistant") {
|
684
|
+
focus();
|
685
|
+
}
|
686
|
+
});
|
687
|
+
return /* @__PURE__ */ React.createElement(
|
688
|
+
Component,
|
689
|
+
{
|
690
|
+
value,
|
691
|
+
...rest,
|
692
|
+
ref,
|
693
|
+
disabled,
|
694
|
+
onChange: composeEventHandlers5(onChange, (e) => {
|
695
|
+
const composerState = useComposer.getState();
|
696
|
+
if (!composerState.isEditing)
|
697
|
+
return;
|
698
|
+
return composerState.setValue(e.target.value);
|
699
|
+
}),
|
700
|
+
onKeyDown: composeEventHandlers5(onKeyDown, handleKeyPress)
|
701
|
+
}
|
702
|
+
);
|
703
|
+
}
|
704
|
+
);
|
643
705
|
|
644
706
|
// src/primitives/composer/ComposerSend.tsx
|
645
707
|
import {
|
646
|
-
Primitive as
|
708
|
+
Primitive as Primitive6
|
647
709
|
} from "@radix-ui/react-primitive";
|
648
|
-
import { forwardRef as
|
649
|
-
var ComposerSend =
|
710
|
+
import { forwardRef as forwardRef7 } from "react";
|
711
|
+
var ComposerSend = forwardRef7(
|
650
712
|
({ disabled, ...rest }, ref) => {
|
651
713
|
const { useComposer } = useComposerContext();
|
652
714
|
const hasValue = useComposer((c) => c.isEditing && c.value.length > 0);
|
653
715
|
return /* @__PURE__ */ React.createElement(
|
654
|
-
|
716
|
+
Primitive6.button,
|
655
717
|
{
|
656
718
|
type: "submit",
|
657
719
|
...rest,
|
@@ -663,24 +725,24 @@ var ComposerSend = forwardRef6(
|
|
663
725
|
);
|
664
726
|
|
665
727
|
// src/primitives/composer/ComposerCancel.tsx
|
666
|
-
import { composeEventHandlers as
|
728
|
+
import { composeEventHandlers as composeEventHandlers6 } from "@radix-ui/primitive";
|
667
729
|
import {
|
668
|
-
Primitive as
|
730
|
+
Primitive as Primitive7
|
669
731
|
} from "@radix-ui/react-primitive";
|
670
|
-
import { forwardRef as
|
671
|
-
var ComposerCancel =
|
732
|
+
import { forwardRef as forwardRef8 } from "react";
|
733
|
+
var ComposerCancel = forwardRef8(({ disabled, onClick, ...rest }, ref) => {
|
672
734
|
const { useComposer } = useComposerContext();
|
673
735
|
const hasValue = useComposer((c) => c.canCancel);
|
674
736
|
const handleClose = () => {
|
675
737
|
useComposer.getState().cancel();
|
676
738
|
};
|
677
739
|
return /* @__PURE__ */ React.createElement(
|
678
|
-
|
740
|
+
Primitive7.button,
|
679
741
|
{
|
680
742
|
type: "button",
|
681
743
|
...rest,
|
682
744
|
ref,
|
683
|
-
onClick:
|
745
|
+
onClick: composeEventHandlers6(onClick, handleClose),
|
684
746
|
disabled: disabled || !hasValue
|
685
747
|
}
|
686
748
|
);
|
@@ -696,44 +758,66 @@ __export(branchPicker_exports, {
|
|
696
758
|
Root: () => BranchPickerRoot
|
697
759
|
});
|
698
760
|
|
761
|
+
// src/utils/context/combined/useCombinedStore.ts
|
762
|
+
import { useMemo as useMemo3 } from "react";
|
763
|
+
|
764
|
+
// src/utils/context/combined/createCombinedStore.ts
|
765
|
+
import { useSyncExternalStore } from "react";
|
766
|
+
var createCombinedStore = (stores) => {
|
767
|
+
const subscribe = (callback) => {
|
768
|
+
const unsubscribes = stores.map((store) => store.subscribe(callback));
|
769
|
+
return () => {
|
770
|
+
for (const unsub of unsubscribes) {
|
771
|
+
unsub();
|
772
|
+
}
|
773
|
+
};
|
774
|
+
};
|
775
|
+
return (selector) => {
|
776
|
+
const getSnapshot = () => selector(...stores.map((store) => store.getState()));
|
777
|
+
return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
|
778
|
+
};
|
779
|
+
};
|
780
|
+
|
781
|
+
// src/utils/context/combined/useCombinedStore.ts
|
782
|
+
var useCombinedStore = (stores, selector) => {
|
783
|
+
const useCombined = useMemo3(() => createCombinedStore(stores), stores);
|
784
|
+
return useCombined(selector);
|
785
|
+
};
|
786
|
+
|
699
787
|
// src/actions/useGoToNextBranch.tsx
|
700
788
|
var useGoToNextBranch = () => {
|
701
|
-
const { useThread
|
789
|
+
const { useThread } = useAssistantContext();
|
702
790
|
const { useComposer, useMessage } = useMessageContext();
|
703
|
-
const
|
704
|
-
|
705
|
-
|
706
|
-
({ branchState: { branchId, branchCount } }) => branchId + 1 < branchCount
|
791
|
+
const disabled = useCombinedStore(
|
792
|
+
[useThread, useComposer, useMessage],
|
793
|
+
(t, c, m) => t.isLoading || c.isEditing || m.message.branchId + 1 >= m.message.branchCount
|
707
794
|
);
|
708
|
-
if (
|
795
|
+
if (disabled)
|
709
796
|
return null;
|
710
797
|
return () => {
|
711
|
-
const {
|
712
|
-
|
713
|
-
branchState: { branchId }
|
714
|
-
} = useMessage.getState();
|
715
|
-
useBranchObserver.getState().switchToBranch(message, branchId + 1);
|
798
|
+
const { message } = useMessage.getState();
|
799
|
+
useThread.getState().switchToBranch(message.id, message.branchId + 1);
|
716
800
|
};
|
717
801
|
};
|
718
802
|
|
719
803
|
// src/utils/createActionButton.tsx
|
720
|
-
import { forwardRef as
|
804
|
+
import { forwardRef as forwardRef9 } from "react";
|
721
805
|
import {
|
722
|
-
Primitive as
|
806
|
+
Primitive as Primitive8
|
723
807
|
} from "@radix-ui/react-primitive";
|
724
|
-
import { composeEventHandlers as
|
808
|
+
import { composeEventHandlers as composeEventHandlers7 } from "@radix-ui/primitive";
|
725
809
|
var createActionButton = (useActionButton) => {
|
726
|
-
return
|
810
|
+
return forwardRef9(
|
727
811
|
(props, forwardedRef) => {
|
728
812
|
const onClick = useActionButton(props);
|
729
813
|
return /* @__PURE__ */ React.createElement(
|
730
|
-
|
814
|
+
Primitive8.button,
|
731
815
|
{
|
732
816
|
type: "button",
|
733
817
|
disabled: !onClick,
|
734
818
|
...props,
|
735
819
|
ref: forwardedRef,
|
736
|
-
onClick:
|
820
|
+
onClick: composeEventHandlers7(props.onClick, onClick ?? void 0)
|
737
821
|
}
|
738
822
|
);
|
739
823
|
}
|
@@ -745,19 +829,17 @@ var BranchPickerNext = createActionButton(useGoToNextBranch);
|
|
745
829
|
|
746
830
|
// src/actions/useGoToPreviousBranch.tsx
|
747
831
|
var useGoToPreviousBranch = () => {
|
748
|
-
const { useThread
|
832
|
+
const { useThread } = useAssistantContext();
|
749
833
|
const { useComposer, useMessage } = useMessageContext();
|
750
|
-
const
|
751
|
-
|
752
|
-
|
753
|
-
|
834
|
+
const disabled = useCombinedStore(
|
835
|
+
[useThread, useComposer, useMessage],
|
836
|
+
(t, c, m) => t.isLoading || c.isEditing || m.message.branchId <= 0
|
837
|
+
);
|
838
|
+
if (disabled)
|
754
839
|
return null;
|
755
840
|
return () => {
|
756
|
-
const {
|
757
|
-
|
758
|
-
branchState: { branchId }
|
759
|
-
} = useMessage.getState();
|
760
|
-
useBranchObserver.getState().switchToBranch(message, branchId - 1);
|
841
|
+
const { message } = useMessage.getState();
|
842
|
+
useThread.getState().switchToBranch(message.id, message.branchId - 1);
|
761
843
|
};
|
762
844
|
};
|
763
845
|
|
@@ -767,24 +849,24 @@ var BranchPickerPrevious = createActionButton(useGoToPreviousBranch);
|
|
767
849
|
// src/primitives/branchPicker/BranchPickerCount.tsx
|
768
850
|
var BranchPickerCount = () => {
|
769
851
|
const { useMessage } = useMessageContext();
|
770
|
-
const branchCount = useMessage((s) => s.
|
852
|
+
const branchCount = useMessage((s) => s.message.branchCount);
|
771
853
|
return /* @__PURE__ */ React.createElement(React.Fragment, null, branchCount);
|
772
854
|
};
|
773
855
|
|
774
856
|
// src/primitives/branchPicker/BranchPickerNumber.tsx
|
775
857
|
var BranchPickerNumber = () => {
|
776
858
|
const { useMessage } = useMessageContext();
|
777
|
-
const branchId = useMessage((s) => s.
|
859
|
+
const branchId = useMessage((s) => s.message.branchId);
|
778
860
|
return /* @__PURE__ */ React.createElement(React.Fragment, null, branchId + 1);
|
779
861
|
};
|
780
862
|
|
781
863
|
// src/primitives/branchPicker/BranchPickerRoot.tsx
|
782
864
|
import {
|
783
|
-
Primitive as
|
865
|
+
Primitive as Primitive9
|
784
866
|
} from "@radix-ui/react-primitive";
|
785
|
-
import { forwardRef as
|
786
|
-
var BranchPickerRoot =
|
787
|
-
return /* @__PURE__ */ React.createElement(MessageIf, { hasBranches: hideWhenSingleBranch ? true : void 0 }, /* @__PURE__ */ React.createElement(
|
867
|
+
import { forwardRef as forwardRef10 } from "react";
|
868
|
+
var BranchPickerRoot = forwardRef10(({ hideWhenSingleBranch, ...rest }, ref) => {
|
869
|
+
return /* @__PURE__ */ React.createElement(MessageIf, { hasBranches: hideWhenSingleBranch ? true : void 0 }, /* @__PURE__ */ React.createElement(Primitive9.div, { ...rest, ref }));
|
788
870
|
});
|
789
871
|
|
790
872
|
// src/primitives/actionBar/index.ts
|
@@ -798,29 +880,31 @@ __export(actionBar_exports, {
|
|
798
880
|
|
799
881
|
// src/primitives/actionBar/ActionBarRoot.tsx
|
800
882
|
import {
|
801
|
-
Primitive as
|
883
|
+
Primitive as Primitive10
|
802
884
|
} from "@radix-ui/react-primitive";
|
803
|
-
import { forwardRef as
|
804
|
-
var ActionBarRoot =
|
885
|
+
import { forwardRef as forwardRef11 } from "react";
|
886
|
+
var ActionBarRoot = forwardRef11(({ hideWhenBusy, autohide, autohideFloat, ...rest }, ref) => {
|
805
887
|
const { useThread } = useAssistantContext();
|
806
888
|
const { useMessage } = useMessageContext();
|
807
|
-
const hideAndfloatStatus =
|
808
|
-
|
809
|
-
|
889
|
+
const hideAndfloatStatus = useCombinedStore(
|
890
|
+
[useThread, useMessage],
|
891
|
+
(t, m) => {
|
892
|
+
if (hideWhenBusy && t.isLoading)
|
893
|
+
return "hidden" /* Hidden */;
|
894
|
+
const autohideEnabled = autohide === "always" || autohide === "not-last" && !m.isLast;
|
895
|
+
if (!autohideEnabled)
|
896
|
+
return "normal" /* Normal */;
|
897
|
+
if (!m.isHovering)
|
898
|
+
return "hidden" /* Hidden */;
|
899
|
+
if (autohideFloat === "always" || autohideFloat === "single-branch" && m.message.branchCount <= 1)
|
900
|
+
return "floating" /* Floating */;
|
810
901
|
return "normal" /* Normal */;
|
811
|
-
|
812
|
-
|
813
|
-
if (autohideFloat === "always" || autohideFloat === "single-branch" && m.branchState.branchCount <= 1)
|
814
|
-
return "floating" /* Floating */;
|
815
|
-
return "normal" /* Normal */;
|
816
|
-
});
|
817
|
-
const busy = useThread((t) => t.isLoading);
|
818
|
-
if (hideWhenBusy && busy)
|
819
|
-
return null;
|
902
|
+
}
|
903
|
+
);
|
820
904
|
if (hideAndfloatStatus === "hidden" /* Hidden */)
|
821
905
|
return null;
|
822
906
|
return /* @__PURE__ */ React.createElement(
|
823
|
-
|
907
|
+
Primitive10.div,
|
824
908
|
{
|
825
909
|
"data-floating": hideAndfloatStatus === "floating" /* Floating */,
|
826
910
|
...rest,
|
@@ -850,17 +934,19 @@ var ActionBarCopy = createActionButton(useCopyMessage);
|
|
850
934
|
|
851
935
|
// src/actions/useReloadMessage.tsx
|
852
936
|
var useReloadMessage = () => {
|
853
|
-
const { useThread
|
937
|
+
const { useThread } = useAssistantContext();
|
854
938
|
const { useMessage } = useMessageContext();
|
855
|
-
const
|
856
|
-
|
857
|
-
|
939
|
+
const disabled = useCombinedStore(
|
940
|
+
[useThread, useMessage],
|
941
|
+
(t, m) => t.isLoading || m.message.role !== "assistant"
|
942
|
+
);
|
943
|
+
if (disabled)
|
858
944
|
return null;
|
859
945
|
return () => {
|
860
946
|
const message = useMessage.getState().message;
|
861
947
|
if (message.role !== "assistant")
|
862
948
|
throw new Error("Reloading is only supported on assistant messages");
|
863
|
-
|
949
|
+
useThread.getState().reload(message.id);
|
864
950
|
};
|
865
951
|
};
|
866
952
|
|
@@ -870,9 +956,11 @@ var ActionBarReload = createActionButton(useReloadMessage);
|
|
870
956
|
// src/actions/useBeginMessageEdit.tsx
|
871
957
|
var useBeginMessageEdit = () => {
|
872
958
|
const { useMessage, useComposer } = useMessageContext();
|
873
|
-
const
|
874
|
-
|
875
|
-
|
959
|
+
const disabled = useCombinedStore(
|
960
|
+
[useMessage, useComposer],
|
961
|
+
(m, c) => m.message.role !== "user" || c.isEditing
|
962
|
+
);
|
963
|
+
if (disabled)
|
876
964
|
return null;
|
877
965
|
return () => {
|
878
966
|
const { edit } = useComposer.getState();
|
@@ -883,25 +971,41 @@ var useBeginMessageEdit = () => {
|
|
883
971
|
// src/primitives/actionBar/ActionBarEdit.tsx
|
884
972
|
var ActionBarEdit = createActionButton(useBeginMessageEdit);
|
885
973
|
|
886
|
-
// src/vercel/VercelAIAssistantProvider.tsx
|
887
|
-
import { useCallback as
|
974
|
+
// src/adapters/vercel/VercelAIAssistantProvider.tsx
|
975
|
+
import { useCallback as useCallback3, useMemo as useMemo4 } from "react";
|
888
976
|
|
889
|
-
// src/vercel/useDummyAIAssistantContext.tsx
|
890
|
-
import { useState as
|
977
|
+
// src/adapters/vercel/useDummyAIAssistantContext.tsx
|
978
|
+
import { useState as useState2 } from "react";
|
891
979
|
import { create as create2 } from "zustand";
|
892
980
|
var useDummyAIAssistantContext = () => {
|
893
|
-
const [context] =
|
981
|
+
const [context] = useState2(() => {
|
982
|
+
const scrollToBottomListeners = /* @__PURE__ */ new Set();
|
894
983
|
const useThread = create2()(() => ({
|
895
984
|
messages: [],
|
896
985
|
isLoading: false,
|
897
|
-
reload: async () => {
|
898
|
-
throw new Error("Not implemented");
|
899
|
-
},
|
900
986
|
append: async () => {
|
901
987
|
throw new Error("Not implemented");
|
902
988
|
},
|
903
989
|
stop: () => {
|
904
990
|
throw new Error("Not implemented");
|
991
|
+
},
|
992
|
+
switchToBranch: () => {
|
993
|
+
throw new Error("Not implemented");
|
994
|
+
},
|
995
|
+
reload: async () => {
|
996
|
+
throw new Error("Not implemented");
|
997
|
+
},
|
998
|
+
isAtBottom: true,
|
999
|
+
scrollToBottom: () => {
|
1000
|
+
for (const listener of scrollToBottomListeners) {
|
1001
|
+
listener();
|
1002
|
+
}
|
1003
|
+
},
|
1004
|
+
onScrollToBottom: (callback) => {
|
1005
|
+
scrollToBottomListeners.add(callback);
|
1006
|
+
return () => {
|
1007
|
+
scrollToBottomListeners.delete(callback);
|
1008
|
+
};
|
905
1009
|
}
|
906
1010
|
}));
|
907
1011
|
const useComposer = create2()(() => ({
|
@@ -916,7 +1020,7 @@ var useDummyAIAssistantContext = () => {
|
|
916
1020
|
},
|
917
1021
|
send: () => {
|
918
1022
|
useThread.getState().append({
|
919
|
-
|
1023
|
+
parentId: useThread.getState().messages.at(-1)?.id ?? ROOT_PARENT_ID,
|
920
1024
|
content: [{ type: "text", text: useComposer.getState().value }]
|
921
1025
|
});
|
922
1026
|
useComposer.getState().setValue("");
|
@@ -925,43 +1029,39 @@ var useDummyAIAssistantContext = () => {
|
|
925
1029
|
useThread.getState().stop();
|
926
1030
|
}
|
927
1031
|
}));
|
928
|
-
|
929
|
-
getBranchState: () => ({
|
930
|
-
branchId: 0,
|
931
|
-
branchCount: 1
|
932
|
-
}),
|
933
|
-
switchToBranch: () => {
|
934
|
-
throw new Error("Not implemented");
|
935
|
-
},
|
936
|
-
editAt: async () => {
|
937
|
-
throw new Error("Not implemented");
|
938
|
-
},
|
939
|
-
reloadAt: async () => {
|
940
|
-
throw new Error("Not implemented");
|
941
|
-
}
|
942
|
-
}));
|
943
|
-
return { useThread, useComposer, useBranchObserver };
|
1032
|
+
return { useThread, useComposer };
|
944
1033
|
});
|
945
1034
|
return context;
|
946
1035
|
};
|
947
1036
|
|
948
|
-
// src/vercel/VercelAIAssistantProvider.tsx
|
1037
|
+
// src/adapters/vercel/VercelAIAssistantProvider.tsx
|
949
1038
|
var ThreadMessageCache = /* @__PURE__ */ new WeakMap();
|
950
|
-
var vercelToThreadMessage = (message) => {
|
1039
|
+
var vercelToThreadMessage = (message, parentId, branchId, branchCount) => {
|
951
1040
|
if (message.role !== "user" && message.role !== "assistant")
|
952
1041
|
throw new Error("Unsupported role");
|
953
1042
|
return {
|
1043
|
+
parentId,
|
954
1044
|
id: message.id,
|
955
1045
|
role: message.role,
|
956
|
-
content: [{ type: "text", text: message.content }]
|
1046
|
+
content: [{ type: "text", text: message.content }],
|
1047
|
+
branchId,
|
1048
|
+
branchCount,
|
1049
|
+
createdAt: message.createdAt ?? /* @__PURE__ */ new Date()
|
957
1050
|
};
|
958
1051
|
};
|
959
|
-
var vercelToCachedThreadMessages = (messages) => {
|
960
|
-
return messages.map((m) => {
|
1052
|
+
var vercelToCachedThreadMessages = (messages, getBranchState) => {
|
1053
|
+
return messages.map((m, idx) => {
|
961
1054
|
const cached = ThreadMessageCache.get(m);
|
962
|
-
|
1055
|
+
const parentId = messages[idx - 1]?.id ?? ROOT_PARENT_ID;
|
1056
|
+
const { branchId, branchCount } = getBranchState(m.id);
|
1057
|
+
if (cached && cached.parentId === parentId && cached.branchId === branchId && cached.branchCount === branchCount)
|
963
1058
|
return cached;
|
964
|
-
const newMessage = vercelToThreadMessage(
|
1059
|
+
const newMessage = vercelToThreadMessage(
|
1060
|
+
m,
|
1061
|
+
parentId,
|
1062
|
+
branchId,
|
1063
|
+
branchCount
|
1064
|
+
);
|
965
1065
|
ThreadMessageCache.set(m, newMessage);
|
966
1066
|
return newMessage;
|
967
1067
|
});
|
@@ -972,28 +1072,14 @@ var VercelAIAssistantProvider = ({
|
|
972
1072
|
}) => {
|
973
1073
|
const context = useDummyAIAssistantContext();
|
974
1074
|
const vercel = "chat" in rest ? rest.chat : rest.assistant;
|
1075
|
+
const branches = useVercelAIBranches(vercel, context);
|
975
1076
|
const messages = useMemo4(() => {
|
976
|
-
return vercelToCachedThreadMessages(
|
977
|
-
|
978
|
-
|
979
|
-
|
980
|
-
|
981
|
-
|
982
|
-
await maybeReload();
|
983
|
-
}, [maybeReload]);
|
984
|
-
const append = useCallback2(
|
985
|
-
async (message) => {
|
986
|
-
if (message.content[0]?.type !== "text") {
|
987
|
-
throw new Error("Only text content is currently supported");
|
988
|
-
}
|
989
|
-
await vercel.append({
|
990
|
-
role: message.role,
|
991
|
-
content: message.content[0].text
|
992
|
-
});
|
993
|
-
},
|
994
|
-
[vercel.append]
|
995
|
-
);
|
996
|
-
const stop = useCallback2(() => {
|
1077
|
+
return vercelToCachedThreadMessages(
|
1078
|
+
vercel.messages,
|
1079
|
+
branches.getBranchState
|
1080
|
+
);
|
1081
|
+
}, [vercel.messages, branches.getBranchState]);
|
1082
|
+
const stop = useCallback3(() => {
|
997
1083
|
const lastMessage = vercel.messages.at(-1);
|
998
1084
|
vercel.stop();
|
999
1085
|
if (lastMessage?.role === "user") {
|
@@ -1002,17 +1088,15 @@ var VercelAIAssistantProvider = ({
|
|
1002
1088
|
}, [vercel.messages, vercel.stop, vercel.setInput]);
|
1003
1089
|
const isLoading = "isLoading" in vercel ? vercel.isLoading : vercel.status === "in_progress";
|
1004
1090
|
useMemo4(() => {
|
1005
|
-
context.useThread.setState(
|
1006
|
-
|
1007
|
-
|
1008
|
-
|
1009
|
-
|
1010
|
-
|
1011
|
-
|
1012
|
-
|
1013
|
-
|
1014
|
-
);
|
1015
|
-
}, [context, messages, reload, append, stop, isLoading]);
|
1091
|
+
context.useThread.setState({
|
1092
|
+
messages,
|
1093
|
+
isLoading,
|
1094
|
+
stop,
|
1095
|
+
switchToBranch: branches.switchToBranch,
|
1096
|
+
append: branches.append,
|
1097
|
+
reload: branches.reload
|
1098
|
+
});
|
1099
|
+
}, [context, messages, isLoading, stop, branches]);
|
1016
1100
|
useMemo4(() => {
|
1017
1101
|
context.useComposer.setState({
|
1018
1102
|
canCancel: isLoading,
|
@@ -1020,34 +1104,35 @@ var VercelAIAssistantProvider = ({
|
|
1020
1104
|
setValue: vercel.setInput
|
1021
1105
|
});
|
1022
1106
|
}, [context, isLoading, vercel.input, vercel.setInput]);
|
1023
|
-
const branches = useVercelAIBranches(vercel);
|
1024
|
-
useMemo4(() => {
|
1025
|
-
context.useBranchObserver.setState(branches, true);
|
1026
|
-
}, [context, branches]);
|
1027
1107
|
return /* @__PURE__ */ React.createElement(AssistantContext.Provider, { value: context }, children);
|
1028
1108
|
};
|
1029
1109
|
|
1030
|
-
// src/vercel/VercelRSCAssistantProvider.tsx
|
1110
|
+
// src/adapters/vercel/VercelRSCAssistantProvider.tsx
|
1031
1111
|
import {
|
1032
|
-
useCallback as
|
1112
|
+
useCallback as useCallback4,
|
1033
1113
|
useMemo as useMemo5
|
1034
1114
|
} from "react";
|
1035
1115
|
var ThreadMessageCache2 = /* @__PURE__ */ new WeakMap();
|
1036
|
-
var vercelToThreadMessage2 = (message) => {
|
1116
|
+
var vercelToThreadMessage2 = (parentId, message) => {
|
1037
1117
|
if (message.role !== "user" && message.role !== "assistant")
|
1038
1118
|
throw new Error("Unsupported role");
|
1039
1119
|
return {
|
1120
|
+
parentId,
|
1040
1121
|
id: message.id,
|
1041
1122
|
role: message.role,
|
1042
|
-
content: [{ type: "ui", display: message.display }]
|
1123
|
+
content: [{ type: "ui", display: message.display }],
|
1124
|
+
createdAt: message.createdAt ?? /* @__PURE__ */ new Date(),
|
1125
|
+
branchId: 0,
|
1126
|
+
branchCount: 1
|
1043
1127
|
};
|
1044
1128
|
};
|
1045
1129
|
var vercelToCachedThreadMessages2 = (messages) => {
|
1046
|
-
return messages.map((m) => {
|
1130
|
+
return messages.map((m, idx) => {
|
1047
1131
|
const cached = ThreadMessageCache2.get(m);
|
1048
|
-
|
1132
|
+
const parentId = messages[idx - 1]?.id ?? ROOT_PARENT_ID;
|
1133
|
+
if (cached && cached.parentId === parentId)
|
1049
1134
|
return cached;
|
1050
|
-
const newMessage = vercelToThreadMessage2(m);
|
1135
|
+
const newMessage = vercelToThreadMessage2(parentId, m);
|
1051
1136
|
ThreadMessageCache2.set(m, newMessage);
|
1052
1137
|
return newMessage;
|
1053
1138
|
});
|
@@ -1061,17 +1146,17 @@ var VercelRSCAssistantProvider = ({
|
|
1061
1146
|
const messages = useMemo5(() => {
|
1062
1147
|
return vercelToCachedThreadMessages2(vercelMessages);
|
1063
1148
|
}, [vercelMessages]);
|
1064
|
-
const append =
|
1149
|
+
const append = useCallback4(
|
1065
1150
|
async (message) => {
|
1151
|
+
if (message.parentId !== (context.useThread.getState().messages.at(-1)?.id ?? ROOT_PARENT_ID))
|
1152
|
+
throw new Error("Unexpected: Message editing is not supported");
|
1066
1153
|
if (message.content[0]?.type !== "text") {
|
1067
1154
|
throw new Error("Only text content is currently supported");
|
1068
1155
|
}
|
1069
|
-
|
1070
|
-
|
1071
|
-
content: [{ type: "text", text: message.content[0].text }]
|
1072
|
-
});
|
1156
|
+
context.useThread.getState().scrollToBottom();
|
1157
|
+
await vercelAppend(message);
|
1073
1158
|
},
|
1074
|
-
[vercelAppend]
|
1159
|
+
[context, vercelAppend]
|
1075
1160
|
);
|
1076
1161
|
useMemo5(() => {
|
1077
1162
|
context.useThread.setState({
|