@assistant-ui/react 0.0.8 → 0.0.10
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 +19 -19
- package/dist/index.d.ts +19 -19
- package/dist/index.js +253 -231
- package/dist/index.mjs +256 -232
- package/package.json +2 -2
package/dist/index.js
CHANGED
@@ -86,9 +86,9 @@ var useThreadIf = (props) => {
|
|
86
86
|
return false;
|
87
87
|
if (props.empty === false && thread.messages.length === 0)
|
88
88
|
return false;
|
89
|
-
if (props.
|
89
|
+
if (props.running === true && !thread.isRunning)
|
90
90
|
return false;
|
91
|
-
if (props.
|
91
|
+
if (props.running === false && thread.isRunning)
|
92
92
|
return false;
|
93
93
|
return true;
|
94
94
|
});
|
@@ -153,12 +153,12 @@ var import_react4 = require("react");
|
|
153
153
|
var useOnScrollToBottom = (callback) => {
|
154
154
|
const callbackRef = (0, import_react4.useRef)(callback);
|
155
155
|
callbackRef.current = callback;
|
156
|
-
const {
|
156
|
+
const { useViewport } = useAssistantContext();
|
157
157
|
(0, import_react4.useEffect)(() => {
|
158
|
-
return
|
158
|
+
return useViewport.getState().onScrollToBottom(() => {
|
159
159
|
callbackRef.current();
|
160
160
|
});
|
161
|
-
}, [
|
161
|
+
}, [useViewport]);
|
162
162
|
};
|
163
163
|
|
164
164
|
// src/primitives/thread/ThreadViewport.tsx
|
@@ -166,18 +166,20 @@ var ThreadViewport = (0, import_react5.forwardRef)(({ autoScroll = true, onScrol
|
|
166
166
|
const messagesEndRef = (0, import_react5.useRef)(null);
|
167
167
|
const divRef = (0, import_react5.useRef)(null);
|
168
168
|
const ref = (0, import_react_compose_refs.useComposedRefs)(forwardedRef, divRef);
|
169
|
-
const {
|
169
|
+
const { useViewport } = useAssistantContext();
|
170
170
|
const firstRenderRef = (0, import_react5.useRef)(true);
|
171
|
+
const lastScrollTop = (0, import_react5.useRef)(0);
|
171
172
|
const scrollToBottom = () => {
|
172
173
|
const div = messagesEndRef.current;
|
173
174
|
if (!div || !autoScroll)
|
174
175
|
return;
|
175
176
|
const behavior = firstRenderRef.current ? "instant" : "auto";
|
176
177
|
firstRenderRef.current = false;
|
178
|
+
useViewport.setState({ isAtBottom: true });
|
177
179
|
div.scrollIntoView({ behavior });
|
178
180
|
};
|
179
181
|
useOnResizeContent(divRef, () => {
|
180
|
-
if (!
|
182
|
+
if (!useViewport.getState().isAtBottom)
|
181
183
|
return;
|
182
184
|
scrollToBottom();
|
183
185
|
});
|
@@ -188,11 +190,13 @@ var ThreadViewport = (0, import_react5.forwardRef)(({ autoScroll = true, onScrol
|
|
188
190
|
const div = divRef.current;
|
189
191
|
if (!div)
|
190
192
|
return;
|
191
|
-
const isAtBottom =
|
192
|
-
const newIsAtBottom = div.scrollHeight - div.scrollTop <= div.clientHeight
|
193
|
-
if (newIsAtBottom
|
194
|
-
|
193
|
+
const isAtBottom = useViewport.getState().isAtBottom;
|
194
|
+
const newIsAtBottom = div.scrollHeight - div.scrollTop <= div.clientHeight;
|
195
|
+
if (!newIsAtBottom && lastScrollTop.current < div.scrollTop) {
|
196
|
+
} else if (newIsAtBottom !== isAtBottom) {
|
197
|
+
useViewport.setState({ isAtBottom: newIsAtBottom });
|
195
198
|
}
|
199
|
+
lastScrollTop.current = div.scrollTop;
|
196
200
|
};
|
197
201
|
return /* @__PURE__ */ React.createElement(
|
198
202
|
import_react_primitive2.Primitive.div,
|
@@ -206,15 +210,19 @@ var ThreadViewport = (0, import_react5.forwardRef)(({ autoScroll = true, onScrol
|
|
206
210
|
);
|
207
211
|
});
|
208
212
|
|
209
|
-
// src/vercel/useVercelAIBranches.tsx
|
213
|
+
// src/adapters/vercel/useVercelAIBranches.tsx
|
210
214
|
var import_react6 = require("react");
|
211
|
-
|
215
|
+
|
216
|
+
// src/utils/context/stores/AssistantTypes.ts
|
217
|
+
var ROOT_PARENT_ID = "__ROOT_ID__";
|
218
|
+
|
219
|
+
// src/adapters/vercel/useVercelAIBranches.tsx
|
212
220
|
var UPCOMING_MESSAGE_ID = "__UPCOMING_MESSAGE_ID__";
|
213
221
|
var updateBranchData = (data, messages) => {
|
214
222
|
for (let i = 0; i < messages.length; i++) {
|
215
223
|
const child = messages[i];
|
216
224
|
const childId = child.id;
|
217
|
-
const parentId = messages[i - 1]?.id ??
|
225
|
+
const parentId = messages[i - 1]?.id ?? ROOT_PARENT_ID;
|
218
226
|
data.parentMap.set(childId, parentId);
|
219
227
|
const parentArray = data.branchMap.get(parentId);
|
220
228
|
if (!parentArray) {
|
@@ -225,32 +233,32 @@ var updateBranchData = (data, messages) => {
|
|
225
233
|
data.snapshots.set(childId, messages);
|
226
234
|
}
|
227
235
|
};
|
228
|
-
var getParentId = (data, messages,
|
229
|
-
if (
|
236
|
+
var getParentId = (data, messages, messageId) => {
|
237
|
+
if (messageId === UPCOMING_MESSAGE_ID) {
|
230
238
|
const parent = messages.at(-1);
|
231
239
|
if (!parent)
|
232
|
-
return
|
240
|
+
return ROOT_PARENT_ID;
|
233
241
|
return parent.id;
|
234
242
|
}
|
235
|
-
const parentId = data.parentMap.get(
|
243
|
+
const parentId = data.parentMap.get(messageId);
|
236
244
|
if (!parentId)
|
237
245
|
throw new Error("Unexpected: Message parent not found");
|
238
246
|
return parentId;
|
239
247
|
};
|
240
|
-
var getBranchStateImpl = (data, messages,
|
241
|
-
const parentId = getParentId(data, messages,
|
248
|
+
var getBranchStateImpl = (data, messages, messageId) => {
|
249
|
+
const parentId = getParentId(data, messages, messageId);
|
242
250
|
const branches = data.branchMap.get(parentId) ?? [];
|
243
|
-
const branchId =
|
251
|
+
const branchId = messageId === UPCOMING_MESSAGE_ID ? branches.length : branches.indexOf(messageId);
|
244
252
|
if (branchId === -1)
|
245
253
|
throw new Error("Unexpected: Message not found in parent children");
|
246
|
-
const upcomingOffset =
|
254
|
+
const upcomingOffset = messageId === UPCOMING_MESSAGE_ID ? 1 : 0;
|
247
255
|
return {
|
248
256
|
branchId,
|
249
257
|
branchCount: branches.length + upcomingOffset
|
250
258
|
};
|
251
259
|
};
|
252
|
-
var switchToBranchImpl = (data, messages,
|
253
|
-
const parentId = getParentId(data, messages,
|
260
|
+
var switchToBranchImpl = (data, messages, messageId, branchId) => {
|
261
|
+
const parentId = getParentId(data, messages, messageId);
|
254
262
|
const branches = data.branchMap.get(parentId);
|
255
263
|
if (!branches)
|
256
264
|
throw new Error("Unexpected: Parent children not found");
|
@@ -259,20 +267,22 @@ var switchToBranchImpl = (data, messages, message, branchId) => {
|
|
259
267
|
throw new Error("Unexpected: Requested branch not found");
|
260
268
|
if (branchId < 0 || branchId >= branches.length)
|
261
269
|
throw new Error("Switch to branch called with a branch index out of range");
|
262
|
-
if (newMessageId ===
|
270
|
+
if (newMessageId === messageId)
|
263
271
|
return messages;
|
264
272
|
const snapshot = data.snapshots.get(newMessageId);
|
265
273
|
if (!snapshot)
|
266
274
|
throw new Error("Unexpected: Branch snapshot not found");
|
267
275
|
return snapshot;
|
268
276
|
};
|
269
|
-
var sliceMessagesUntil = (messages,
|
270
|
-
if (
|
277
|
+
var sliceMessagesUntil = (messages, messageId) => {
|
278
|
+
if (messageId === ROOT_PARENT_ID)
|
279
|
+
return [];
|
280
|
+
if (messageId === UPCOMING_MESSAGE_ID)
|
271
281
|
return messages;
|
272
|
-
const messageIdx = messages.findIndex((m) => m.id ===
|
282
|
+
const messageIdx = messages.findIndex((m) => m.id === messageId);
|
273
283
|
if (messageIdx === -1)
|
274
284
|
throw new Error("Unexpected: Message not found");
|
275
|
-
return messages.slice(0, messageIdx);
|
285
|
+
return messages.slice(0, messageIdx + 1);
|
276
286
|
};
|
277
287
|
var useVercelAIBranches = (chat, context) => {
|
278
288
|
const data = (0, import_react6.useRef)({
|
@@ -282,17 +292,17 @@ var useVercelAIBranches = (chat, context) => {
|
|
282
292
|
}).current;
|
283
293
|
updateBranchData(data, chat.messages);
|
284
294
|
const getBranchState = (0, import_react6.useCallback)(
|
285
|
-
(
|
286
|
-
return getBranchStateImpl(data, chat.messages,
|
295
|
+
(messageId) => {
|
296
|
+
return getBranchStateImpl(data, chat.messages, messageId);
|
287
297
|
},
|
288
298
|
[data, chat.messages]
|
289
299
|
);
|
290
300
|
const switchToBranch = (0, import_react6.useCallback)(
|
291
|
-
(
|
301
|
+
(messageId, branchId) => {
|
292
302
|
const newMessages = switchToBranchImpl(
|
293
303
|
data,
|
294
304
|
chat.messages,
|
295
|
-
|
305
|
+
messageId,
|
296
306
|
branchId
|
297
307
|
);
|
298
308
|
chat.setMessages(newMessages);
|
@@ -300,27 +310,27 @@ var useVercelAIBranches = (chat, context) => {
|
|
300
310
|
[data, chat.messages, chat.setMessages]
|
301
311
|
);
|
302
312
|
const reloadMaybe = "reload" in chat ? chat.reload : void 0;
|
303
|
-
const
|
304
|
-
async (
|
313
|
+
const startRun = (0, import_react6.useCallback)(
|
314
|
+
async (parentId) => {
|
305
315
|
if (!reloadMaybe)
|
306
316
|
throw new Error("Reload not supported by Vercel AI SDK's useAssistant");
|
307
|
-
const newMessages = sliceMessagesUntil(chat.messages,
|
317
|
+
const newMessages = sliceMessagesUntil(chat.messages, parentId);
|
308
318
|
chat.setMessages(newMessages);
|
309
|
-
context.
|
319
|
+
context.useViewport.getState().scrollToBottom();
|
310
320
|
await reloadMaybe();
|
311
321
|
},
|
312
322
|
[context, chat.messages, chat.setMessages, reloadMaybe]
|
313
323
|
);
|
314
|
-
const
|
315
|
-
async (message
|
316
|
-
const newMessages = sliceMessagesUntil(chat.messages, message);
|
324
|
+
const append = (0, import_react6.useCallback)(
|
325
|
+
async (message) => {
|
326
|
+
const newMessages = sliceMessagesUntil(chat.messages, message.parentId);
|
317
327
|
chat.setMessages(newMessages);
|
318
|
-
if (
|
328
|
+
if (message.content.length !== 1 || message.content[0]?.type !== "text")
|
319
329
|
throw new Error("Only text content is currently supported");
|
320
|
-
context.
|
330
|
+
context.useViewport.getState().scrollToBottom();
|
321
331
|
await chat.append({
|
322
332
|
role: "user",
|
323
|
-
content:
|
333
|
+
content: message.content[0].text
|
324
334
|
});
|
325
335
|
},
|
326
336
|
[context, chat.messages, chat.setMessages, chat.append]
|
@@ -329,14 +339,14 @@ var useVercelAIBranches = (chat, context) => {
|
|
329
339
|
() => ({
|
330
340
|
getBranchState,
|
331
341
|
switchToBranch,
|
332
|
-
|
333
|
-
|
342
|
+
append,
|
343
|
+
startRun
|
334
344
|
}),
|
335
|
-
[getBranchState, switchToBranch,
|
345
|
+
[getBranchState, switchToBranch, append, startRun]
|
336
346
|
);
|
337
347
|
};
|
338
348
|
var hasUpcomingMessage = (thread) => {
|
339
|
-
return thread.
|
349
|
+
return thread.isRunning && thread.messages[thread.messages.length - 1]?.role !== "assistant";
|
340
350
|
};
|
341
351
|
|
342
352
|
// src/utils/context/useComposerContext.ts
|
@@ -389,16 +399,62 @@ __export(message_exports, {
|
|
389
399
|
|
390
400
|
// src/primitives/message/MessageProvider.tsx
|
391
401
|
var import_react9 = require("react");
|
402
|
+
var import_zustand2 = require("zustand");
|
403
|
+
|
404
|
+
// src/utils/context/stores/ComposerStore.ts
|
392
405
|
var import_zustand = require("zustand");
|
393
|
-
var
|
406
|
+
var makeBaseComposer = (set) => ({
|
407
|
+
value: "",
|
408
|
+
setValue: (value) => {
|
409
|
+
set({ value });
|
410
|
+
}
|
411
|
+
});
|
412
|
+
var makeMessageComposerStore = ({
|
413
|
+
onEdit,
|
414
|
+
onSend
|
415
|
+
}) => (0, import_zustand.create)()((set, get, store) => ({
|
416
|
+
...makeBaseComposer(set, get, store),
|
417
|
+
canCancel: true,
|
418
|
+
isEditing: false,
|
419
|
+
edit: () => {
|
420
|
+
const value = onEdit();
|
421
|
+
set({ isEditing: true, value });
|
422
|
+
},
|
423
|
+
send: () => {
|
424
|
+
const value = get().value;
|
425
|
+
set({ isEditing: false });
|
426
|
+
return onSend(value);
|
427
|
+
},
|
428
|
+
cancel: () => {
|
429
|
+
set({ isEditing: false });
|
430
|
+
}
|
431
|
+
}));
|
432
|
+
var makeThreadComposerStore = ({
|
433
|
+
onSend,
|
434
|
+
onCancel
|
435
|
+
}) => (0, import_zustand.create)()((set, get, store) => ({
|
436
|
+
...makeBaseComposer(set, get, store),
|
437
|
+
isEditing: true,
|
438
|
+
canCancel: false,
|
439
|
+
send: () => {
|
440
|
+
const value = get().value;
|
441
|
+
set({ value: "", canCancel: true });
|
442
|
+
onSend(value).then(() => {
|
443
|
+
set({ canCancel: false });
|
444
|
+
});
|
445
|
+
},
|
446
|
+
cancel: onCancel
|
447
|
+
}));
|
448
|
+
|
449
|
+
// src/primitives/message/MessageProvider.tsx
|
394
450
|
var getIsLast = (thread, message) => {
|
395
451
|
const hasUpcoming = hasUpcomingMessage(thread);
|
396
452
|
return hasUpcoming ? message.id === UPCOMING_MESSAGE_ID : thread.messages[thread.messages.length - 1]?.id === message.id;
|
397
453
|
};
|
398
454
|
var useMessageContext2 = () => {
|
399
|
-
const { useBranchObserver } = useAssistantContext();
|
400
455
|
const [context] = (0, import_react9.useState)(() => {
|
401
|
-
const
|
456
|
+
const { useThread } = useAssistantContext();
|
457
|
+
const useMessage = (0, import_zustand2.create)(() => ({
|
402
458
|
message: null,
|
403
459
|
isLast: false,
|
404
460
|
isCopied: false,
|
@@ -406,40 +462,25 @@ var useMessageContext2 = () => {
|
|
406
462
|
setIsCopied: () => {
|
407
463
|
},
|
408
464
|
setIsHovering: () => {
|
409
|
-
},
|
410
|
-
branchState: {
|
411
|
-
branchId: 0,
|
412
|
-
branchCount: 0
|
413
465
|
}
|
414
466
|
}));
|
415
|
-
const useComposer = (
|
416
|
-
|
417
|
-
canCancel: true,
|
418
|
-
edit: () => {
|
467
|
+
const useComposer = makeMessageComposerStore({
|
468
|
+
onEdit: () => {
|
419
469
|
const message = useMessage.getState().message;
|
420
470
|
if (message.role !== "user")
|
421
471
|
throw new Error("Editing is only supported for user messages");
|
422
472
|
if (message.content[0]?.type !== "text")
|
423
473
|
throw new Error("Editing is only supported for text-only messages");
|
424
|
-
return
|
425
|
-
isEditing: true,
|
426
|
-
value: message.content[0].text
|
427
|
-
});
|
474
|
+
return message.content[0].text;
|
428
475
|
},
|
429
|
-
|
430
|
-
send: () => {
|
476
|
+
onSend: (text) => {
|
431
477
|
const message = useMessage.getState().message;
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
role: "user",
|
436
|
-
content: [{ type: "text", text: get().value }]
|
478
|
+
return useThread.getState().append({
|
479
|
+
parentId: message.parentId,
|
480
|
+
content: [{ type: "text", text }]
|
437
481
|
});
|
438
|
-
|
439
|
-
|
440
|
-
value: "",
|
441
|
-
setValue: (value) => set({ value })
|
442
|
-
}));
|
482
|
+
}
|
483
|
+
});
|
443
484
|
return { useMessage, useComposer };
|
444
485
|
});
|
445
486
|
return context;
|
@@ -448,11 +489,8 @@ var MessageProvider = ({
|
|
448
489
|
message,
|
449
490
|
children
|
450
491
|
}) => {
|
451
|
-
const { useThread
|
492
|
+
const { useThread } = useAssistantContext();
|
452
493
|
const context = useMessageContext2();
|
453
|
-
const branchState = useBranchObserver(
|
454
|
-
(0, import_shallow.useShallow)((b) => b.getBranchState(message))
|
455
|
-
);
|
456
494
|
const isLast = useThread((thread) => getIsLast(thread, message));
|
457
495
|
const [isCopied, setIsCopied] = (0, import_react9.useState)(false);
|
458
496
|
const [isHovering, setIsHovering] = (0, import_react9.useState)(false);
|
@@ -464,12 +502,11 @@ var MessageProvider = ({
|
|
464
502
|
isCopied,
|
465
503
|
isHovering,
|
466
504
|
setIsCopied,
|
467
|
-
setIsHovering
|
468
|
-
branchState
|
505
|
+
setIsHovering
|
469
506
|
},
|
470
507
|
true
|
471
508
|
);
|
472
|
-
}, [context, message, isLast, isCopied, isHovering
|
509
|
+
}, [context, message, isLast, isCopied, isHovering]);
|
473
510
|
return /* @__PURE__ */ React.createElement(MessageContext.Provider, { value: context }, children);
|
474
511
|
};
|
475
512
|
|
@@ -502,29 +539,21 @@ var MessageRoot = (0, import_react10.forwardRef)(
|
|
502
539
|
// src/primitives/message/MessageIf.tsx
|
503
540
|
var useMessageIf = (props) => {
|
504
541
|
const { useMessage } = useMessageContext();
|
505
|
-
return useMessage(
|
506
|
-
(
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
return false;
|
521
|
-
if (props.copied === true && !isCopied)
|
522
|
-
return false;
|
523
|
-
if (props.copied === false && isCopied)
|
524
|
-
return false;
|
525
|
-
return true;
|
526
|
-
}
|
527
|
-
);
|
542
|
+
return useMessage(({ message, isLast, isCopied, isHovering }) => {
|
543
|
+
if (props.hasBranches === true && message.branchCount < 2)
|
544
|
+
return false;
|
545
|
+
if (props.user && message.role !== "user")
|
546
|
+
return false;
|
547
|
+
if (props.assistant && message.role !== "assistant")
|
548
|
+
return false;
|
549
|
+
if (props.lastOrHover === true && !isHovering && !isLast)
|
550
|
+
return false;
|
551
|
+
if (props.copied === true && !isCopied)
|
552
|
+
return false;
|
553
|
+
if (props.copied === false && isCopied)
|
554
|
+
return false;
|
555
|
+
return true;
|
556
|
+
});
|
528
557
|
};
|
529
558
|
var MessageIf = ({ children, ...query }) => {
|
530
559
|
const result = useMessageIf(query);
|
@@ -595,7 +624,12 @@ var ThreadMessages = ({ components }) => {
|
|
595
624
|
message: {
|
596
625
|
id: UPCOMING_MESSAGE_ID,
|
597
626
|
role: "assistant",
|
598
|
-
content: [{ type: "text", text: "..." }]
|
627
|
+
content: [{ type: "text", text: "..." }],
|
628
|
+
parentId: messages.at(-1)?.id ?? ROOT_PARENT_ID,
|
629
|
+
// TODO fix these (move upcoming message to AssistantContext)
|
630
|
+
branchId: 0,
|
631
|
+
branchCount: 1,
|
632
|
+
createdAt: /* @__PURE__ */ new Date()
|
599
633
|
}
|
600
634
|
},
|
601
635
|
/* @__PURE__ */ React.createElement(AssistantMessage, null)
|
@@ -607,18 +641,16 @@ var import_primitive3 = require("@radix-ui/primitive");
|
|
607
641
|
var import_react_primitive4 = require("@radix-ui/react-primitive");
|
608
642
|
var import_react11 = require("react");
|
609
643
|
var ThreadScrollToBottom = (0, import_react11.forwardRef)(({ onClick, ...rest }, ref) => {
|
610
|
-
const {
|
611
|
-
const isAtBottom =
|
644
|
+
const { useViewport } = useAssistantContext();
|
645
|
+
const isAtBottom = useViewport((s) => s.isAtBottom);
|
612
646
|
const handleScrollToBottom = () => {
|
613
|
-
|
614
|
-
thread.scrollToBottom();
|
647
|
+
useViewport.getState().scrollToBottom();
|
615
648
|
};
|
616
|
-
if (isAtBottom)
|
617
|
-
return null;
|
618
649
|
return /* @__PURE__ */ React.createElement(
|
619
650
|
import_react_primitive4.Primitive.button,
|
620
651
|
{
|
621
652
|
...rest,
|
653
|
+
disabled: isAtBottom,
|
622
654
|
ref,
|
623
655
|
onClick: (0, import_primitive3.composeEventHandlers)(onClick, handleScrollToBottom)
|
624
656
|
}
|
@@ -688,8 +720,8 @@ var ComposerInput = (0, import_react13.forwardRef)(
|
|
688
720
|
useComposer.getState().cancel();
|
689
721
|
}
|
690
722
|
if (e.key === "Enter" && e.shiftKey === false) {
|
691
|
-
const
|
692
|
-
if (!
|
723
|
+
const isRunning = useThread.getState().isRunning;
|
724
|
+
if (!isRunning) {
|
693
725
|
e.preventDefault();
|
694
726
|
composer.send();
|
695
727
|
}
|
@@ -812,20 +844,17 @@ var useCombinedStore = (stores, selector) => {
|
|
812
844
|
|
813
845
|
// src/actions/useGoToNextBranch.tsx
|
814
846
|
var useGoToNextBranch = () => {
|
815
|
-
const { useThread
|
847
|
+
const { useThread } = useAssistantContext();
|
816
848
|
const { useComposer, useMessage } = useMessageContext();
|
817
849
|
const disabled = useCombinedStore(
|
818
850
|
[useThread, useComposer, useMessage],
|
819
|
-
(t, c, m) => t.
|
851
|
+
(t, c, m) => t.isRunning || c.isEditing || m.message.branchId + 1 >= m.message.branchCount
|
820
852
|
);
|
821
853
|
if (disabled)
|
822
854
|
return null;
|
823
855
|
return () => {
|
824
|
-
const {
|
825
|
-
|
826
|
-
branchState: { branchId }
|
827
|
-
} = useMessage.getState();
|
828
|
-
useBranchObserver.getState().switchToBranch(message, branchId + 1);
|
856
|
+
const { message } = useMessage.getState();
|
857
|
+
useThread.getState().switchToBranch(message.id, message.branchId + 1);
|
829
858
|
};
|
830
859
|
};
|
831
860
|
|
@@ -856,20 +885,17 @@ var BranchPickerNext = createActionButton(useGoToNextBranch);
|
|
856
885
|
|
857
886
|
// src/actions/useGoToPreviousBranch.tsx
|
858
887
|
var useGoToPreviousBranch = () => {
|
859
|
-
const { useThread
|
888
|
+
const { useThread } = useAssistantContext();
|
860
889
|
const { useComposer, useMessage } = useMessageContext();
|
861
890
|
const disabled = useCombinedStore(
|
862
891
|
[useThread, useComposer, useMessage],
|
863
|
-
(t, c, m) => t.
|
892
|
+
(t, c, m) => t.isRunning || c.isEditing || m.message.branchId <= 0
|
864
893
|
);
|
865
894
|
if (disabled)
|
866
895
|
return null;
|
867
896
|
return () => {
|
868
|
-
const {
|
869
|
-
|
870
|
-
branchState: { branchId }
|
871
|
-
} = useMessage.getState();
|
872
|
-
useBranchObserver.getState().switchToBranch(message, branchId - 1);
|
897
|
+
const { message } = useMessage.getState();
|
898
|
+
useThread.getState().switchToBranch(message.id, message.branchId - 1);
|
873
899
|
};
|
874
900
|
};
|
875
901
|
|
@@ -879,14 +905,14 @@ var BranchPickerPrevious = createActionButton(useGoToPreviousBranch);
|
|
879
905
|
// src/primitives/branchPicker/BranchPickerCount.tsx
|
880
906
|
var BranchPickerCount = () => {
|
881
907
|
const { useMessage } = useMessageContext();
|
882
|
-
const branchCount = useMessage((s) => s.
|
908
|
+
const branchCount = useMessage((s) => s.message.branchCount);
|
883
909
|
return /* @__PURE__ */ React.createElement(React.Fragment, null, branchCount);
|
884
910
|
};
|
885
911
|
|
886
912
|
// src/primitives/branchPicker/BranchPickerNumber.tsx
|
887
913
|
var BranchPickerNumber = () => {
|
888
914
|
const { useMessage } = useMessageContext();
|
889
|
-
const branchId = useMessage((s) => s.
|
915
|
+
const branchId = useMessage((s) => s.message.branchId);
|
890
916
|
return /* @__PURE__ */ React.createElement(React.Fragment, null, branchId + 1);
|
891
917
|
};
|
892
918
|
|
@@ -909,20 +935,20 @@ __export(actionBar_exports, {
|
|
909
935
|
// src/primitives/actionBar/ActionBarRoot.tsx
|
910
936
|
var import_react_primitive10 = require("@radix-ui/react-primitive");
|
911
937
|
var import_react20 = require("react");
|
912
|
-
var ActionBarRoot = (0, import_react20.forwardRef)(({
|
938
|
+
var ActionBarRoot = (0, import_react20.forwardRef)(({ hideWhenRunning, autohide, autohideFloat, ...rest }, ref) => {
|
913
939
|
const { useThread } = useAssistantContext();
|
914
940
|
const { useMessage } = useMessageContext();
|
915
941
|
const hideAndfloatStatus = useCombinedStore(
|
916
942
|
[useThread, useMessage],
|
917
943
|
(t, m) => {
|
918
|
-
if (
|
944
|
+
if (hideWhenRunning && t.isRunning)
|
919
945
|
return "hidden" /* Hidden */;
|
920
946
|
const autohideEnabled = autohide === "always" || autohide === "not-last" && !m.isLast;
|
921
947
|
if (!autohideEnabled)
|
922
948
|
return "normal" /* Normal */;
|
923
949
|
if (!m.isHovering)
|
924
950
|
return "hidden" /* Hidden */;
|
925
|
-
if (autohideFloat === "always" || autohideFloat === "single-branch" && m.
|
951
|
+
if (autohideFloat === "always" || autohideFloat === "single-branch" && m.message.branchCount <= 1)
|
926
952
|
return "floating" /* Floating */;
|
927
953
|
return "normal" /* Normal */;
|
928
954
|
}
|
@@ -960,11 +986,11 @@ var ActionBarCopy = createActionButton(useCopyMessage);
|
|
960
986
|
|
961
987
|
// src/actions/useReloadMessage.tsx
|
962
988
|
var useReloadMessage = () => {
|
963
|
-
const { useThread
|
989
|
+
const { useThread } = useAssistantContext();
|
964
990
|
const { useMessage } = useMessageContext();
|
965
991
|
const disabled = useCombinedStore(
|
966
992
|
[useThread, useMessage],
|
967
|
-
(t, m) => t.
|
993
|
+
(t, m) => t.isRunning || m.message.role !== "assistant"
|
968
994
|
);
|
969
995
|
if (disabled)
|
970
996
|
return null;
|
@@ -972,7 +998,7 @@ var useReloadMessage = () => {
|
|
972
998
|
const message = useMessage.getState().message;
|
973
999
|
if (message.role !== "assistant")
|
974
1000
|
throw new Error("Reloading is only supported on assistant messages");
|
975
|
-
|
1001
|
+
useThread.getState().startRun(message.parentId);
|
976
1002
|
};
|
977
1003
|
};
|
978
1004
|
|
@@ -997,95 +1023,98 @@ var useBeginMessageEdit = () => {
|
|
997
1023
|
// src/primitives/actionBar/ActionBarEdit.tsx
|
998
1024
|
var ActionBarEdit = createActionButton(useBeginMessageEdit);
|
999
1025
|
|
1000
|
-
// src/vercel/VercelAIAssistantProvider.tsx
|
1026
|
+
// src/adapters/vercel/VercelAIAssistantProvider.tsx
|
1001
1027
|
var import_react22 = require("react");
|
1002
1028
|
|
1003
|
-
// src/vercel/useDummyAIAssistantContext.tsx
|
1029
|
+
// src/adapters/vercel/useDummyAIAssistantContext.tsx
|
1004
1030
|
var import_react21 = require("react");
|
1005
|
-
var
|
1031
|
+
var import_zustand4 = require("zustand");
|
1032
|
+
|
1033
|
+
// src/utils/context/stores/ViewportStore.tsx
|
1034
|
+
var import_zustand3 = require("zustand");
|
1035
|
+
var makeViewportStore = () => {
|
1036
|
+
const scrollToBottomListeners = /* @__PURE__ */ new Set();
|
1037
|
+
return (0, import_zustand3.create)(() => ({
|
1038
|
+
isAtBottom: true,
|
1039
|
+
scrollToBottom: () => {
|
1040
|
+
for (const listener of scrollToBottomListeners) {
|
1041
|
+
listener();
|
1042
|
+
}
|
1043
|
+
},
|
1044
|
+
onScrollToBottom: (callback) => {
|
1045
|
+
scrollToBottomListeners.add(callback);
|
1046
|
+
return () => {
|
1047
|
+
scrollToBottomListeners.delete(callback);
|
1048
|
+
};
|
1049
|
+
}
|
1050
|
+
}));
|
1051
|
+
};
|
1052
|
+
|
1053
|
+
// src/adapters/vercel/useDummyAIAssistantContext.tsx
|
1006
1054
|
var useDummyAIAssistantContext = () => {
|
1007
1055
|
const [context] = (0, import_react21.useState)(() => {
|
1008
|
-
const
|
1009
|
-
|
1056
|
+
const useThread = (0, import_zustand4.create)()(() => ({
|
1057
|
+
id: "",
|
1010
1058
|
messages: [],
|
1011
|
-
|
1059
|
+
isRunning: false,
|
1012
1060
|
append: async () => {
|
1013
1061
|
throw new Error("Not implemented");
|
1014
1062
|
},
|
1015
|
-
|
1016
|
-
throw new Error("Not implemented");
|
1017
|
-
},
|
1018
|
-
isAtBottom: true,
|
1019
|
-
scrollToBottom: () => {
|
1020
|
-
for (const listener of scrollToBottomListeners) {
|
1021
|
-
listener();
|
1022
|
-
}
|
1023
|
-
},
|
1024
|
-
onScrollToBottom: (callback) => {
|
1025
|
-
scrollToBottomListeners.add(callback);
|
1026
|
-
return () => {
|
1027
|
-
scrollToBottomListeners.delete(callback);
|
1028
|
-
};
|
1029
|
-
}
|
1030
|
-
}));
|
1031
|
-
const useComposer = (0, import_zustand2.create)()(() => ({
|
1032
|
-
isEditing: true,
|
1033
|
-
canCancel: false,
|
1034
|
-
value: "",
|
1035
|
-
setValue: (value) => {
|
1036
|
-
useComposer.setState({ value });
|
1037
|
-
},
|
1038
|
-
edit: () => {
|
1063
|
+
cancelRun: () => {
|
1039
1064
|
throw new Error("Not implemented");
|
1040
1065
|
},
|
1041
|
-
send: () => {
|
1042
|
-
useThread.getState().append({
|
1043
|
-
role: "user",
|
1044
|
-
content: [{ type: "text", text: useComposer.getState().value }]
|
1045
|
-
});
|
1046
|
-
useComposer.getState().setValue("");
|
1047
|
-
},
|
1048
|
-
cancel: () => {
|
1049
|
-
useThread.getState().stop();
|
1050
|
-
}
|
1051
|
-
}));
|
1052
|
-
const useBranchObserver = (0, import_zustand2.create)()(() => ({
|
1053
|
-
getBranchState: () => ({
|
1054
|
-
branchId: 0,
|
1055
|
-
branchCount: 1
|
1056
|
-
}),
|
1057
1066
|
switchToBranch: () => {
|
1058
1067
|
throw new Error("Not implemented");
|
1059
1068
|
},
|
1060
|
-
|
1061
|
-
throw new Error("Not implemented");
|
1062
|
-
},
|
1063
|
-
reloadAt: async () => {
|
1069
|
+
startRun: async () => {
|
1064
1070
|
throw new Error("Not implemented");
|
1065
1071
|
}
|
1066
1072
|
}));
|
1067
|
-
|
1073
|
+
const useViewport = makeViewportStore();
|
1074
|
+
const useComposer = makeThreadComposerStore({
|
1075
|
+
onSend: async (text) => {
|
1076
|
+
await useThread.getState().append({
|
1077
|
+
parentId: useThread.getState().messages.at(-1)?.id ?? ROOT_PARENT_ID,
|
1078
|
+
content: [{ type: "text", text }]
|
1079
|
+
});
|
1080
|
+
},
|
1081
|
+
onCancel: () => {
|
1082
|
+
useThread.getState().cancelRun();
|
1083
|
+
}
|
1084
|
+
});
|
1085
|
+
return { useThread, useViewport, useComposer };
|
1068
1086
|
});
|
1069
1087
|
return context;
|
1070
1088
|
};
|
1071
1089
|
|
1072
|
-
// src/vercel/VercelAIAssistantProvider.tsx
|
1090
|
+
// src/adapters/vercel/VercelAIAssistantProvider.tsx
|
1073
1091
|
var ThreadMessageCache = /* @__PURE__ */ new WeakMap();
|
1074
|
-
var vercelToThreadMessage = (message) => {
|
1092
|
+
var vercelToThreadMessage = (message, parentId, branchId, branchCount) => {
|
1075
1093
|
if (message.role !== "user" && message.role !== "assistant")
|
1076
1094
|
throw new Error("Unsupported role");
|
1077
1095
|
return {
|
1096
|
+
parentId,
|
1078
1097
|
id: message.id,
|
1079
1098
|
role: message.role,
|
1080
|
-
content: [{ type: "text", text: message.content }]
|
1099
|
+
content: [{ type: "text", text: message.content }],
|
1100
|
+
branchId,
|
1101
|
+
branchCount,
|
1102
|
+
createdAt: message.createdAt ?? /* @__PURE__ */ new Date()
|
1081
1103
|
};
|
1082
1104
|
};
|
1083
|
-
var vercelToCachedThreadMessages = (messages) => {
|
1084
|
-
return messages.map((m) => {
|
1105
|
+
var vercelToCachedThreadMessages = (messages, getBranchState) => {
|
1106
|
+
return messages.map((m, idx) => {
|
1085
1107
|
const cached = ThreadMessageCache.get(m);
|
1086
|
-
|
1108
|
+
const parentId = messages[idx - 1]?.id ?? ROOT_PARENT_ID;
|
1109
|
+
const { branchId, branchCount } = getBranchState(m.id);
|
1110
|
+
if (cached && cached.parentId === parentId && cached.branchId === branchId && cached.branchCount === branchCount)
|
1087
1111
|
return cached;
|
1088
|
-
const newMessage = vercelToThreadMessage(
|
1112
|
+
const newMessage = vercelToThreadMessage(
|
1113
|
+
m,
|
1114
|
+
parentId,
|
1115
|
+
branchId,
|
1116
|
+
branchCount
|
1117
|
+
);
|
1089
1118
|
ThreadMessageCache.set(m, newMessage);
|
1090
1119
|
return newMessage;
|
1091
1120
|
});
|
@@ -1096,70 +1125,64 @@ var VercelAIAssistantProvider = ({
|
|
1096
1125
|
}) => {
|
1097
1126
|
const context = useDummyAIAssistantContext();
|
1098
1127
|
const vercel = "chat" in rest ? rest.chat : rest.assistant;
|
1128
|
+
const branches = useVercelAIBranches(vercel, context);
|
1099
1129
|
const messages = (0, import_react22.useMemo)(() => {
|
1100
|
-
return vercelToCachedThreadMessages(
|
1101
|
-
|
1102
|
-
|
1103
|
-
|
1104
|
-
|
1105
|
-
|
1106
|
-
}
|
1107
|
-
context.useThread.getState().scrollToBottom();
|
1108
|
-
await vercel.append({
|
1109
|
-
role: message.role,
|
1110
|
-
content: message.content[0].text
|
1111
|
-
});
|
1112
|
-
},
|
1113
|
-
[context, vercel.append]
|
1114
|
-
);
|
1115
|
-
const stop = (0, import_react22.useCallback)(() => {
|
1130
|
+
return vercelToCachedThreadMessages(
|
1131
|
+
vercel.messages,
|
1132
|
+
branches.getBranchState
|
1133
|
+
);
|
1134
|
+
}, [vercel.messages, branches.getBranchState]);
|
1135
|
+
const cancelRun = (0, import_react22.useCallback)(() => {
|
1116
1136
|
const lastMessage = vercel.messages.at(-1);
|
1117
1137
|
vercel.stop();
|
1118
1138
|
if (lastMessage?.role === "user") {
|
1119
1139
|
vercel.setInput(lastMessage.content);
|
1120
1140
|
}
|
1121
1141
|
}, [vercel.messages, vercel.stop, vercel.setInput]);
|
1122
|
-
const
|
1142
|
+
const isRunning = "isLoading" in vercel ? vercel.isLoading : vercel.status === "in_progress";
|
1123
1143
|
(0, import_react22.useMemo)(() => {
|
1124
1144
|
context.useThread.setState({
|
1125
1145
|
messages,
|
1126
|
-
|
1127
|
-
|
1128
|
-
|
1146
|
+
isRunning,
|
1147
|
+
cancelRun,
|
1148
|
+
switchToBranch: branches.switchToBranch,
|
1149
|
+
append: branches.append,
|
1150
|
+
startRun: branches.startRun
|
1129
1151
|
});
|
1130
|
-
}, [context, messages,
|
1152
|
+
}, [context, messages, isRunning, cancelRun, branches]);
|
1131
1153
|
(0, import_react22.useMemo)(() => {
|
1132
1154
|
context.useComposer.setState({
|
1133
|
-
canCancel:
|
1155
|
+
canCancel: isRunning,
|
1134
1156
|
value: vercel.input,
|
1135
1157
|
setValue: vercel.setInput
|
1136
1158
|
});
|
1137
|
-
}, [context,
|
1138
|
-
const branches = useVercelAIBranches(vercel, context);
|
1139
|
-
(0, import_react22.useMemo)(() => {
|
1140
|
-
context.useBranchObserver.setState(branches, true);
|
1141
|
-
}, [context, branches]);
|
1159
|
+
}, [context, isRunning, vercel.input, vercel.setInput]);
|
1142
1160
|
return /* @__PURE__ */ React.createElement(AssistantContext.Provider, { value: context }, children);
|
1143
1161
|
};
|
1144
1162
|
|
1145
|
-
// src/vercel/VercelRSCAssistantProvider.tsx
|
1163
|
+
// src/adapters/vercel/VercelRSCAssistantProvider.tsx
|
1146
1164
|
var import_react23 = require("react");
|
1147
1165
|
var ThreadMessageCache2 = /* @__PURE__ */ new WeakMap();
|
1148
|
-
var vercelToThreadMessage2 = (message) => {
|
1166
|
+
var vercelToThreadMessage2 = (parentId, message) => {
|
1149
1167
|
if (message.role !== "user" && message.role !== "assistant")
|
1150
1168
|
throw new Error("Unsupported role");
|
1151
1169
|
return {
|
1170
|
+
parentId,
|
1152
1171
|
id: message.id,
|
1153
1172
|
role: message.role,
|
1154
|
-
content: [{ type: "ui", display: message.display }]
|
1173
|
+
content: [{ type: "ui", display: message.display }],
|
1174
|
+
createdAt: message.createdAt ?? /* @__PURE__ */ new Date(),
|
1175
|
+
branchId: 0,
|
1176
|
+
branchCount: 1
|
1155
1177
|
};
|
1156
1178
|
};
|
1157
1179
|
var vercelToCachedThreadMessages2 = (messages) => {
|
1158
|
-
return messages.map((m) => {
|
1180
|
+
return messages.map((m, idx) => {
|
1159
1181
|
const cached = ThreadMessageCache2.get(m);
|
1160
|
-
|
1182
|
+
const parentId = messages[idx - 1]?.id ?? ROOT_PARENT_ID;
|
1183
|
+
if (cached && cached.parentId === parentId)
|
1161
1184
|
return cached;
|
1162
|
-
const newMessage = vercelToThreadMessage2(m);
|
1185
|
+
const newMessage = vercelToThreadMessage2(parentId, m);
|
1163
1186
|
ThreadMessageCache2.set(m, newMessage);
|
1164
1187
|
return newMessage;
|
1165
1188
|
});
|
@@ -1175,14 +1198,13 @@ var VercelRSCAssistantProvider = ({
|
|
1175
1198
|
}, [vercelMessages]);
|
1176
1199
|
const append = (0, import_react23.useCallback)(
|
1177
1200
|
async (message) => {
|
1201
|
+
if (message.parentId !== (context.useThread.getState().messages.at(-1)?.id ?? ROOT_PARENT_ID))
|
1202
|
+
throw new Error("Unexpected: Message editing is not supported");
|
1178
1203
|
if (message.content[0]?.type !== "text") {
|
1179
1204
|
throw new Error("Only text content is currently supported");
|
1180
1205
|
}
|
1181
|
-
context.
|
1182
|
-
await vercelAppend(
|
1183
|
-
role: message.role,
|
1184
|
-
content: [{ type: "text", text: message.content[0].text }]
|
1185
|
-
});
|
1206
|
+
context.useViewport.getState().scrollToBottom();
|
1207
|
+
await vercelAppend(message);
|
1186
1208
|
},
|
1187
1209
|
[context, vercelAppend]
|
1188
1210
|
);
|