@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.mjs
CHANGED
@@ -46,9 +46,9 @@ var useThreadIf = (props) => {
|
|
46
46
|
return false;
|
47
47
|
if (props.empty === false && thread.messages.length === 0)
|
48
48
|
return false;
|
49
|
-
if (props.
|
49
|
+
if (props.running === true && !thread.isRunning)
|
50
50
|
return false;
|
51
|
-
if (props.
|
51
|
+
if (props.running === false && thread.isRunning)
|
52
52
|
return false;
|
53
53
|
return true;
|
54
54
|
});
|
@@ -115,12 +115,12 @@ import { useEffect, useRef as useRef2 } from "react";
|
|
115
115
|
var useOnScrollToBottom = (callback) => {
|
116
116
|
const callbackRef = useRef2(callback);
|
117
117
|
callbackRef.current = callback;
|
118
|
-
const {
|
118
|
+
const { useViewport } = useAssistantContext();
|
119
119
|
useEffect(() => {
|
120
|
-
return
|
120
|
+
return useViewport.getState().onScrollToBottom(() => {
|
121
121
|
callbackRef.current();
|
122
122
|
});
|
123
|
-
}, [
|
123
|
+
}, [useViewport]);
|
124
124
|
};
|
125
125
|
|
126
126
|
// src/primitives/thread/ThreadViewport.tsx
|
@@ -128,18 +128,20 @@ var ThreadViewport = forwardRef2(({ autoScroll = true, onScroll, children, ...re
|
|
128
128
|
const messagesEndRef = useRef3(null);
|
129
129
|
const divRef = useRef3(null);
|
130
130
|
const ref = useComposedRefs(forwardedRef, divRef);
|
131
|
-
const {
|
131
|
+
const { useViewport } = useAssistantContext();
|
132
132
|
const firstRenderRef = useRef3(true);
|
133
|
+
const lastScrollTop = useRef3(0);
|
133
134
|
const scrollToBottom = () => {
|
134
135
|
const div = messagesEndRef.current;
|
135
136
|
if (!div || !autoScroll)
|
136
137
|
return;
|
137
138
|
const behavior = firstRenderRef.current ? "instant" : "auto";
|
138
139
|
firstRenderRef.current = false;
|
140
|
+
useViewport.setState({ isAtBottom: true });
|
139
141
|
div.scrollIntoView({ behavior });
|
140
142
|
};
|
141
143
|
useOnResizeContent(divRef, () => {
|
142
|
-
if (!
|
144
|
+
if (!useViewport.getState().isAtBottom)
|
143
145
|
return;
|
144
146
|
scrollToBottom();
|
145
147
|
});
|
@@ -150,11 +152,13 @@ var ThreadViewport = forwardRef2(({ autoScroll = true, onScroll, children, ...re
|
|
150
152
|
const div = divRef.current;
|
151
153
|
if (!div)
|
152
154
|
return;
|
153
|
-
const isAtBottom =
|
154
|
-
const newIsAtBottom = div.scrollHeight - div.scrollTop <= div.clientHeight
|
155
|
-
if (newIsAtBottom
|
156
|
-
|
155
|
+
const isAtBottom = useViewport.getState().isAtBottom;
|
156
|
+
const newIsAtBottom = div.scrollHeight - div.scrollTop <= div.clientHeight;
|
157
|
+
if (!newIsAtBottom && lastScrollTop.current < div.scrollTop) {
|
158
|
+
} else if (newIsAtBottom !== isAtBottom) {
|
159
|
+
useViewport.setState({ isAtBottom: newIsAtBottom });
|
157
160
|
}
|
161
|
+
lastScrollTop.current = div.scrollTop;
|
158
162
|
};
|
159
163
|
return /* @__PURE__ */ React.createElement(
|
160
164
|
Primitive2.div,
|
@@ -168,15 +172,19 @@ var ThreadViewport = forwardRef2(({ autoScroll = true, onScroll, children, ...re
|
|
168
172
|
);
|
169
173
|
});
|
170
174
|
|
171
|
-
// src/vercel/useVercelAIBranches.tsx
|
175
|
+
// src/adapters/vercel/useVercelAIBranches.tsx
|
172
176
|
import { useCallback, useMemo, useRef as useRef4 } from "react";
|
173
|
-
|
177
|
+
|
178
|
+
// src/utils/context/stores/AssistantTypes.ts
|
179
|
+
var ROOT_PARENT_ID = "__ROOT_ID__";
|
180
|
+
|
181
|
+
// src/adapters/vercel/useVercelAIBranches.tsx
|
174
182
|
var UPCOMING_MESSAGE_ID = "__UPCOMING_MESSAGE_ID__";
|
175
183
|
var updateBranchData = (data, messages) => {
|
176
184
|
for (let i = 0; i < messages.length; i++) {
|
177
185
|
const child = messages[i];
|
178
186
|
const childId = child.id;
|
179
|
-
const parentId = messages[i - 1]?.id ??
|
187
|
+
const parentId = messages[i - 1]?.id ?? ROOT_PARENT_ID;
|
180
188
|
data.parentMap.set(childId, parentId);
|
181
189
|
const parentArray = data.branchMap.get(parentId);
|
182
190
|
if (!parentArray) {
|
@@ -187,32 +195,32 @@ var updateBranchData = (data, messages) => {
|
|
187
195
|
data.snapshots.set(childId, messages);
|
188
196
|
}
|
189
197
|
};
|
190
|
-
var getParentId = (data, messages,
|
191
|
-
if (
|
198
|
+
var getParentId = (data, messages, messageId) => {
|
199
|
+
if (messageId === UPCOMING_MESSAGE_ID) {
|
192
200
|
const parent = messages.at(-1);
|
193
201
|
if (!parent)
|
194
|
-
return
|
202
|
+
return ROOT_PARENT_ID;
|
195
203
|
return parent.id;
|
196
204
|
}
|
197
|
-
const parentId = data.parentMap.get(
|
205
|
+
const parentId = data.parentMap.get(messageId);
|
198
206
|
if (!parentId)
|
199
207
|
throw new Error("Unexpected: Message parent not found");
|
200
208
|
return parentId;
|
201
209
|
};
|
202
|
-
var getBranchStateImpl = (data, messages,
|
203
|
-
const parentId = getParentId(data, messages,
|
210
|
+
var getBranchStateImpl = (data, messages, messageId) => {
|
211
|
+
const parentId = getParentId(data, messages, messageId);
|
204
212
|
const branches = data.branchMap.get(parentId) ?? [];
|
205
|
-
const branchId =
|
213
|
+
const branchId = messageId === UPCOMING_MESSAGE_ID ? branches.length : branches.indexOf(messageId);
|
206
214
|
if (branchId === -1)
|
207
215
|
throw new Error("Unexpected: Message not found in parent children");
|
208
|
-
const upcomingOffset =
|
216
|
+
const upcomingOffset = messageId === UPCOMING_MESSAGE_ID ? 1 : 0;
|
209
217
|
return {
|
210
218
|
branchId,
|
211
219
|
branchCount: branches.length + upcomingOffset
|
212
220
|
};
|
213
221
|
};
|
214
|
-
var switchToBranchImpl = (data, messages,
|
215
|
-
const parentId = getParentId(data, messages,
|
222
|
+
var switchToBranchImpl = (data, messages, messageId, branchId) => {
|
223
|
+
const parentId = getParentId(data, messages, messageId);
|
216
224
|
const branches = data.branchMap.get(parentId);
|
217
225
|
if (!branches)
|
218
226
|
throw new Error("Unexpected: Parent children not found");
|
@@ -221,20 +229,22 @@ var switchToBranchImpl = (data, messages, message, branchId) => {
|
|
221
229
|
throw new Error("Unexpected: Requested branch not found");
|
222
230
|
if (branchId < 0 || branchId >= branches.length)
|
223
231
|
throw new Error("Switch to branch called with a branch index out of range");
|
224
|
-
if (newMessageId ===
|
232
|
+
if (newMessageId === messageId)
|
225
233
|
return messages;
|
226
234
|
const snapshot = data.snapshots.get(newMessageId);
|
227
235
|
if (!snapshot)
|
228
236
|
throw new Error("Unexpected: Branch snapshot not found");
|
229
237
|
return snapshot;
|
230
238
|
};
|
231
|
-
var sliceMessagesUntil = (messages,
|
232
|
-
if (
|
239
|
+
var sliceMessagesUntil = (messages, messageId) => {
|
240
|
+
if (messageId === ROOT_PARENT_ID)
|
241
|
+
return [];
|
242
|
+
if (messageId === UPCOMING_MESSAGE_ID)
|
233
243
|
return messages;
|
234
|
-
const messageIdx = messages.findIndex((m) => m.id ===
|
244
|
+
const messageIdx = messages.findIndex((m) => m.id === messageId);
|
235
245
|
if (messageIdx === -1)
|
236
246
|
throw new Error("Unexpected: Message not found");
|
237
|
-
return messages.slice(0, messageIdx);
|
247
|
+
return messages.slice(0, messageIdx + 1);
|
238
248
|
};
|
239
249
|
var useVercelAIBranches = (chat, context) => {
|
240
250
|
const data = useRef4({
|
@@ -244,17 +254,17 @@ var useVercelAIBranches = (chat, context) => {
|
|
244
254
|
}).current;
|
245
255
|
updateBranchData(data, chat.messages);
|
246
256
|
const getBranchState = useCallback(
|
247
|
-
(
|
248
|
-
return getBranchStateImpl(data, chat.messages,
|
257
|
+
(messageId) => {
|
258
|
+
return getBranchStateImpl(data, chat.messages, messageId);
|
249
259
|
},
|
250
260
|
[data, chat.messages]
|
251
261
|
);
|
252
262
|
const switchToBranch = useCallback(
|
253
|
-
(
|
263
|
+
(messageId, branchId) => {
|
254
264
|
const newMessages = switchToBranchImpl(
|
255
265
|
data,
|
256
266
|
chat.messages,
|
257
|
-
|
267
|
+
messageId,
|
258
268
|
branchId
|
259
269
|
);
|
260
270
|
chat.setMessages(newMessages);
|
@@ -262,27 +272,27 @@ var useVercelAIBranches = (chat, context) => {
|
|
262
272
|
[data, chat.messages, chat.setMessages]
|
263
273
|
);
|
264
274
|
const reloadMaybe = "reload" in chat ? chat.reload : void 0;
|
265
|
-
const
|
266
|
-
async (
|
275
|
+
const startRun = useCallback(
|
276
|
+
async (parentId) => {
|
267
277
|
if (!reloadMaybe)
|
268
278
|
throw new Error("Reload not supported by Vercel AI SDK's useAssistant");
|
269
|
-
const newMessages = sliceMessagesUntil(chat.messages,
|
279
|
+
const newMessages = sliceMessagesUntil(chat.messages, parentId);
|
270
280
|
chat.setMessages(newMessages);
|
271
|
-
context.
|
281
|
+
context.useViewport.getState().scrollToBottom();
|
272
282
|
await reloadMaybe();
|
273
283
|
},
|
274
284
|
[context, chat.messages, chat.setMessages, reloadMaybe]
|
275
285
|
);
|
276
|
-
const
|
277
|
-
async (message
|
278
|
-
const newMessages = sliceMessagesUntil(chat.messages, message);
|
286
|
+
const append = useCallback(
|
287
|
+
async (message) => {
|
288
|
+
const newMessages = sliceMessagesUntil(chat.messages, message.parentId);
|
279
289
|
chat.setMessages(newMessages);
|
280
|
-
if (
|
290
|
+
if (message.content.length !== 1 || message.content[0]?.type !== "text")
|
281
291
|
throw new Error("Only text content is currently supported");
|
282
|
-
context.
|
292
|
+
context.useViewport.getState().scrollToBottom();
|
283
293
|
await chat.append({
|
284
294
|
role: "user",
|
285
|
-
content:
|
295
|
+
content: message.content[0].text
|
286
296
|
});
|
287
297
|
},
|
288
298
|
[context, chat.messages, chat.setMessages, chat.append]
|
@@ -291,14 +301,14 @@ var useVercelAIBranches = (chat, context) => {
|
|
291
301
|
() => ({
|
292
302
|
getBranchState,
|
293
303
|
switchToBranch,
|
294
|
-
|
295
|
-
|
304
|
+
append,
|
305
|
+
startRun
|
296
306
|
}),
|
297
|
-
[getBranchState, switchToBranch,
|
307
|
+
[getBranchState, switchToBranch, append, startRun]
|
298
308
|
);
|
299
309
|
};
|
300
310
|
var hasUpcomingMessage = (thread) => {
|
301
|
-
return thread.
|
311
|
+
return thread.isRunning && thread.messages[thread.messages.length - 1]?.role !== "assistant";
|
302
312
|
};
|
303
313
|
|
304
314
|
// src/utils/context/useComposerContext.ts
|
@@ -351,16 +361,64 @@ __export(message_exports, {
|
|
351
361
|
|
352
362
|
// src/primitives/message/MessageProvider.tsx
|
353
363
|
import { useMemo as useMemo2, useState } from "react";
|
354
|
-
import { create } from "zustand";
|
355
|
-
|
364
|
+
import { create as create2 } from "zustand";
|
365
|
+
|
366
|
+
// src/utils/context/stores/ComposerStore.ts
|
367
|
+
import {
|
368
|
+
create
|
369
|
+
} from "zustand";
|
370
|
+
var makeBaseComposer = (set) => ({
|
371
|
+
value: "",
|
372
|
+
setValue: (value) => {
|
373
|
+
set({ value });
|
374
|
+
}
|
375
|
+
});
|
376
|
+
var makeMessageComposerStore = ({
|
377
|
+
onEdit,
|
378
|
+
onSend
|
379
|
+
}) => create()((set, get, store) => ({
|
380
|
+
...makeBaseComposer(set, get, store),
|
381
|
+
canCancel: true,
|
382
|
+
isEditing: false,
|
383
|
+
edit: () => {
|
384
|
+
const value = onEdit();
|
385
|
+
set({ isEditing: true, value });
|
386
|
+
},
|
387
|
+
send: () => {
|
388
|
+
const value = get().value;
|
389
|
+
set({ isEditing: false });
|
390
|
+
return onSend(value);
|
391
|
+
},
|
392
|
+
cancel: () => {
|
393
|
+
set({ isEditing: false });
|
394
|
+
}
|
395
|
+
}));
|
396
|
+
var makeThreadComposerStore = ({
|
397
|
+
onSend,
|
398
|
+
onCancel
|
399
|
+
}) => create()((set, get, store) => ({
|
400
|
+
...makeBaseComposer(set, get, store),
|
401
|
+
isEditing: true,
|
402
|
+
canCancel: false,
|
403
|
+
send: () => {
|
404
|
+
const value = get().value;
|
405
|
+
set({ value: "", canCancel: true });
|
406
|
+
onSend(value).then(() => {
|
407
|
+
set({ canCancel: false });
|
408
|
+
});
|
409
|
+
},
|
410
|
+
cancel: onCancel
|
411
|
+
}));
|
412
|
+
|
413
|
+
// src/primitives/message/MessageProvider.tsx
|
356
414
|
var getIsLast = (thread, message) => {
|
357
415
|
const hasUpcoming = hasUpcomingMessage(thread);
|
358
416
|
return hasUpcoming ? message.id === UPCOMING_MESSAGE_ID : thread.messages[thread.messages.length - 1]?.id === message.id;
|
359
417
|
};
|
360
418
|
var useMessageContext2 = () => {
|
361
|
-
const { useBranchObserver } = useAssistantContext();
|
362
419
|
const [context] = useState(() => {
|
363
|
-
const
|
420
|
+
const { useThread } = useAssistantContext();
|
421
|
+
const useMessage = create2(() => ({
|
364
422
|
message: null,
|
365
423
|
isLast: false,
|
366
424
|
isCopied: false,
|
@@ -368,40 +426,25 @@ var useMessageContext2 = () => {
|
|
368
426
|
setIsCopied: () => {
|
369
427
|
},
|
370
428
|
setIsHovering: () => {
|
371
|
-
},
|
372
|
-
branchState: {
|
373
|
-
branchId: 0,
|
374
|
-
branchCount: 0
|
375
429
|
}
|
376
430
|
}));
|
377
|
-
const useComposer =
|
378
|
-
|
379
|
-
canCancel: true,
|
380
|
-
edit: () => {
|
431
|
+
const useComposer = makeMessageComposerStore({
|
432
|
+
onEdit: () => {
|
381
433
|
const message = useMessage.getState().message;
|
382
434
|
if (message.role !== "user")
|
383
435
|
throw new Error("Editing is only supported for user messages");
|
384
436
|
if (message.content[0]?.type !== "text")
|
385
437
|
throw new Error("Editing is only supported for text-only messages");
|
386
|
-
return
|
387
|
-
isEditing: true,
|
388
|
-
value: message.content[0].text
|
389
|
-
});
|
438
|
+
return message.content[0].text;
|
390
439
|
},
|
391
|
-
|
392
|
-
send: () => {
|
440
|
+
onSend: (text) => {
|
393
441
|
const message = useMessage.getState().message;
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
role: "user",
|
398
|
-
content: [{ type: "text", text: get().value }]
|
442
|
+
return useThread.getState().append({
|
443
|
+
parentId: message.parentId,
|
444
|
+
content: [{ type: "text", text }]
|
399
445
|
});
|
400
|
-
|
401
|
-
|
402
|
-
value: "",
|
403
|
-
setValue: (value) => set({ value })
|
404
|
-
}));
|
446
|
+
}
|
447
|
+
});
|
405
448
|
return { useMessage, useComposer };
|
406
449
|
});
|
407
450
|
return context;
|
@@ -410,11 +453,8 @@ var MessageProvider = ({
|
|
410
453
|
message,
|
411
454
|
children
|
412
455
|
}) => {
|
413
|
-
const { useThread
|
456
|
+
const { useThread } = useAssistantContext();
|
414
457
|
const context = useMessageContext2();
|
415
|
-
const branchState = useBranchObserver(
|
416
|
-
useShallow((b) => b.getBranchState(message))
|
417
|
-
);
|
418
458
|
const isLast = useThread((thread) => getIsLast(thread, message));
|
419
459
|
const [isCopied, setIsCopied] = useState(false);
|
420
460
|
const [isHovering, setIsHovering] = useState(false);
|
@@ -426,12 +466,11 @@ var MessageProvider = ({
|
|
426
466
|
isCopied,
|
427
467
|
isHovering,
|
428
468
|
setIsCopied,
|
429
|
-
setIsHovering
|
430
|
-
branchState
|
469
|
+
setIsHovering
|
431
470
|
},
|
432
471
|
true
|
433
472
|
);
|
434
|
-
}, [context, message, isLast, isCopied, isHovering
|
473
|
+
}, [context, message, isLast, isCopied, isHovering]);
|
435
474
|
return /* @__PURE__ */ React.createElement(MessageContext.Provider, { value: context }, children);
|
436
475
|
};
|
437
476
|
|
@@ -466,29 +505,21 @@ var MessageRoot = forwardRef3(
|
|
466
505
|
// src/primitives/message/MessageIf.tsx
|
467
506
|
var useMessageIf = (props) => {
|
468
507
|
const { useMessage } = useMessageContext();
|
469
|
-
return useMessage(
|
470
|
-
(
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
return false;
|
485
|
-
if (props.copied === true && !isCopied)
|
486
|
-
return false;
|
487
|
-
if (props.copied === false && isCopied)
|
488
|
-
return false;
|
489
|
-
return true;
|
490
|
-
}
|
491
|
-
);
|
508
|
+
return useMessage(({ message, isLast, isCopied, isHovering }) => {
|
509
|
+
if (props.hasBranches === true && message.branchCount < 2)
|
510
|
+
return false;
|
511
|
+
if (props.user && message.role !== "user")
|
512
|
+
return false;
|
513
|
+
if (props.assistant && message.role !== "assistant")
|
514
|
+
return false;
|
515
|
+
if (props.lastOrHover === true && !isHovering && !isLast)
|
516
|
+
return false;
|
517
|
+
if (props.copied === true && !isCopied)
|
518
|
+
return false;
|
519
|
+
if (props.copied === false && isCopied)
|
520
|
+
return false;
|
521
|
+
return true;
|
522
|
+
});
|
492
523
|
};
|
493
524
|
var MessageIf = ({ children, ...query }) => {
|
494
525
|
const result = useMessageIf(query);
|
@@ -559,7 +590,12 @@ var ThreadMessages = ({ components }) => {
|
|
559
590
|
message: {
|
560
591
|
id: UPCOMING_MESSAGE_ID,
|
561
592
|
role: "assistant",
|
562
|
-
content: [{ type: "text", text: "..." }]
|
593
|
+
content: [{ type: "text", text: "..." }],
|
594
|
+
parentId: messages.at(-1)?.id ?? ROOT_PARENT_ID,
|
595
|
+
// TODO fix these (move upcoming message to AssistantContext)
|
596
|
+
branchId: 0,
|
597
|
+
branchCount: 1,
|
598
|
+
createdAt: /* @__PURE__ */ new Date()
|
563
599
|
}
|
564
600
|
},
|
565
601
|
/* @__PURE__ */ React.createElement(AssistantMessage, null)
|
@@ -573,18 +609,16 @@ import {
|
|
573
609
|
} from "@radix-ui/react-primitive";
|
574
610
|
import { forwardRef as forwardRef4 } from "react";
|
575
611
|
var ThreadScrollToBottom = forwardRef4(({ onClick, ...rest }, ref) => {
|
576
|
-
const {
|
577
|
-
const isAtBottom =
|
612
|
+
const { useViewport } = useAssistantContext();
|
613
|
+
const isAtBottom = useViewport((s) => s.isAtBottom);
|
578
614
|
const handleScrollToBottom = () => {
|
579
|
-
|
580
|
-
thread.scrollToBottom();
|
615
|
+
useViewport.getState().scrollToBottom();
|
581
616
|
};
|
582
|
-
if (isAtBottom)
|
583
|
-
return null;
|
584
617
|
return /* @__PURE__ */ React.createElement(
|
585
618
|
Primitive4.button,
|
586
619
|
{
|
587
620
|
...rest,
|
621
|
+
disabled: isAtBottom,
|
588
622
|
ref,
|
589
623
|
onClick: composeEventHandlers3(onClick, handleScrollToBottom)
|
590
624
|
}
|
@@ -661,8 +695,8 @@ var ComposerInput = forwardRef6(
|
|
661
695
|
useComposer.getState().cancel();
|
662
696
|
}
|
663
697
|
if (e.key === "Enter" && e.shiftKey === false) {
|
664
|
-
const
|
665
|
-
if (!
|
698
|
+
const isRunning = useThread.getState().isRunning;
|
699
|
+
if (!isRunning) {
|
666
700
|
e.preventDefault();
|
667
701
|
composer.send();
|
668
702
|
}
|
@@ -789,20 +823,17 @@ var useCombinedStore = (stores, selector) => {
|
|
789
823
|
|
790
824
|
// src/actions/useGoToNextBranch.tsx
|
791
825
|
var useGoToNextBranch = () => {
|
792
|
-
const { useThread
|
826
|
+
const { useThread } = useAssistantContext();
|
793
827
|
const { useComposer, useMessage } = useMessageContext();
|
794
828
|
const disabled = useCombinedStore(
|
795
829
|
[useThread, useComposer, useMessage],
|
796
|
-
(t, c, m) => t.
|
830
|
+
(t, c, m) => t.isRunning || c.isEditing || m.message.branchId + 1 >= m.message.branchCount
|
797
831
|
);
|
798
832
|
if (disabled)
|
799
833
|
return null;
|
800
834
|
return () => {
|
801
|
-
const {
|
802
|
-
|
803
|
-
branchState: { branchId }
|
804
|
-
} = useMessage.getState();
|
805
|
-
useBranchObserver.getState().switchToBranch(message, branchId + 1);
|
835
|
+
const { message } = useMessage.getState();
|
836
|
+
useThread.getState().switchToBranch(message.id, message.branchId + 1);
|
806
837
|
};
|
807
838
|
};
|
808
839
|
|
@@ -835,20 +866,17 @@ var BranchPickerNext = createActionButton(useGoToNextBranch);
|
|
835
866
|
|
836
867
|
// src/actions/useGoToPreviousBranch.tsx
|
837
868
|
var useGoToPreviousBranch = () => {
|
838
|
-
const { useThread
|
869
|
+
const { useThread } = useAssistantContext();
|
839
870
|
const { useComposer, useMessage } = useMessageContext();
|
840
871
|
const disabled = useCombinedStore(
|
841
872
|
[useThread, useComposer, useMessage],
|
842
|
-
(t, c, m) => t.
|
873
|
+
(t, c, m) => t.isRunning || c.isEditing || m.message.branchId <= 0
|
843
874
|
);
|
844
875
|
if (disabled)
|
845
876
|
return null;
|
846
877
|
return () => {
|
847
|
-
const {
|
848
|
-
|
849
|
-
branchState: { branchId }
|
850
|
-
} = useMessage.getState();
|
851
|
-
useBranchObserver.getState().switchToBranch(message, branchId - 1);
|
878
|
+
const { message } = useMessage.getState();
|
879
|
+
useThread.getState().switchToBranch(message.id, message.branchId - 1);
|
852
880
|
};
|
853
881
|
};
|
854
882
|
|
@@ -858,14 +886,14 @@ var BranchPickerPrevious = createActionButton(useGoToPreviousBranch);
|
|
858
886
|
// src/primitives/branchPicker/BranchPickerCount.tsx
|
859
887
|
var BranchPickerCount = () => {
|
860
888
|
const { useMessage } = useMessageContext();
|
861
|
-
const branchCount = useMessage((s) => s.
|
889
|
+
const branchCount = useMessage((s) => s.message.branchCount);
|
862
890
|
return /* @__PURE__ */ React.createElement(React.Fragment, null, branchCount);
|
863
891
|
};
|
864
892
|
|
865
893
|
// src/primitives/branchPicker/BranchPickerNumber.tsx
|
866
894
|
var BranchPickerNumber = () => {
|
867
895
|
const { useMessage } = useMessageContext();
|
868
|
-
const branchId = useMessage((s) => s.
|
896
|
+
const branchId = useMessage((s) => s.message.branchId);
|
869
897
|
return /* @__PURE__ */ React.createElement(React.Fragment, null, branchId + 1);
|
870
898
|
};
|
871
899
|
|
@@ -892,20 +920,20 @@ import {
|
|
892
920
|
Primitive as Primitive10
|
893
921
|
} from "@radix-ui/react-primitive";
|
894
922
|
import { forwardRef as forwardRef11 } from "react";
|
895
|
-
var ActionBarRoot = forwardRef11(({
|
923
|
+
var ActionBarRoot = forwardRef11(({ hideWhenRunning, autohide, autohideFloat, ...rest }, ref) => {
|
896
924
|
const { useThread } = useAssistantContext();
|
897
925
|
const { useMessage } = useMessageContext();
|
898
926
|
const hideAndfloatStatus = useCombinedStore(
|
899
927
|
[useThread, useMessage],
|
900
928
|
(t, m) => {
|
901
|
-
if (
|
929
|
+
if (hideWhenRunning && t.isRunning)
|
902
930
|
return "hidden" /* Hidden */;
|
903
931
|
const autohideEnabled = autohide === "always" || autohide === "not-last" && !m.isLast;
|
904
932
|
if (!autohideEnabled)
|
905
933
|
return "normal" /* Normal */;
|
906
934
|
if (!m.isHovering)
|
907
935
|
return "hidden" /* Hidden */;
|
908
|
-
if (autohideFloat === "always" || autohideFloat === "single-branch" && m.
|
936
|
+
if (autohideFloat === "always" || autohideFloat === "single-branch" && m.message.branchCount <= 1)
|
909
937
|
return "floating" /* Floating */;
|
910
938
|
return "normal" /* Normal */;
|
911
939
|
}
|
@@ -943,11 +971,11 @@ var ActionBarCopy = createActionButton(useCopyMessage);
|
|
943
971
|
|
944
972
|
// src/actions/useReloadMessage.tsx
|
945
973
|
var useReloadMessage = () => {
|
946
|
-
const { useThread
|
974
|
+
const { useThread } = useAssistantContext();
|
947
975
|
const { useMessage } = useMessageContext();
|
948
976
|
const disabled = useCombinedStore(
|
949
977
|
[useThread, useMessage],
|
950
|
-
(t, m) => t.
|
978
|
+
(t, m) => t.isRunning || m.message.role !== "assistant"
|
951
979
|
);
|
952
980
|
if (disabled)
|
953
981
|
return null;
|
@@ -955,7 +983,7 @@ var useReloadMessage = () => {
|
|
955
983
|
const message = useMessage.getState().message;
|
956
984
|
if (message.role !== "assistant")
|
957
985
|
throw new Error("Reloading is only supported on assistant messages");
|
958
|
-
|
986
|
+
useThread.getState().startRun(message.parentId);
|
959
987
|
};
|
960
988
|
};
|
961
989
|
|
@@ -980,95 +1008,98 @@ var useBeginMessageEdit = () => {
|
|
980
1008
|
// src/primitives/actionBar/ActionBarEdit.tsx
|
981
1009
|
var ActionBarEdit = createActionButton(useBeginMessageEdit);
|
982
1010
|
|
983
|
-
// src/vercel/VercelAIAssistantProvider.tsx
|
1011
|
+
// src/adapters/vercel/VercelAIAssistantProvider.tsx
|
984
1012
|
import { useCallback as useCallback3, useMemo as useMemo4 } from "react";
|
985
1013
|
|
986
|
-
// src/vercel/useDummyAIAssistantContext.tsx
|
1014
|
+
// src/adapters/vercel/useDummyAIAssistantContext.tsx
|
987
1015
|
import { useState as useState2 } from "react";
|
988
|
-
import { create as
|
1016
|
+
import { create as create4 } from "zustand";
|
1017
|
+
|
1018
|
+
// src/utils/context/stores/ViewportStore.tsx
|
1019
|
+
import { create as create3 } from "zustand";
|
1020
|
+
var makeViewportStore = () => {
|
1021
|
+
const scrollToBottomListeners = /* @__PURE__ */ new Set();
|
1022
|
+
return create3(() => ({
|
1023
|
+
isAtBottom: true,
|
1024
|
+
scrollToBottom: () => {
|
1025
|
+
for (const listener of scrollToBottomListeners) {
|
1026
|
+
listener();
|
1027
|
+
}
|
1028
|
+
},
|
1029
|
+
onScrollToBottom: (callback) => {
|
1030
|
+
scrollToBottomListeners.add(callback);
|
1031
|
+
return () => {
|
1032
|
+
scrollToBottomListeners.delete(callback);
|
1033
|
+
};
|
1034
|
+
}
|
1035
|
+
}));
|
1036
|
+
};
|
1037
|
+
|
1038
|
+
// src/adapters/vercel/useDummyAIAssistantContext.tsx
|
989
1039
|
var useDummyAIAssistantContext = () => {
|
990
1040
|
const [context] = useState2(() => {
|
991
|
-
const
|
992
|
-
|
1041
|
+
const useThread = create4()(() => ({
|
1042
|
+
id: "",
|
993
1043
|
messages: [],
|
994
|
-
|
1044
|
+
isRunning: false,
|
995
1045
|
append: async () => {
|
996
1046
|
throw new Error("Not implemented");
|
997
1047
|
},
|
998
|
-
|
999
|
-
throw new Error("Not implemented");
|
1000
|
-
},
|
1001
|
-
isAtBottom: true,
|
1002
|
-
scrollToBottom: () => {
|
1003
|
-
for (const listener of scrollToBottomListeners) {
|
1004
|
-
listener();
|
1005
|
-
}
|
1006
|
-
},
|
1007
|
-
onScrollToBottom: (callback) => {
|
1008
|
-
scrollToBottomListeners.add(callback);
|
1009
|
-
return () => {
|
1010
|
-
scrollToBottomListeners.delete(callback);
|
1011
|
-
};
|
1012
|
-
}
|
1013
|
-
}));
|
1014
|
-
const useComposer = create2()(() => ({
|
1015
|
-
isEditing: true,
|
1016
|
-
canCancel: false,
|
1017
|
-
value: "",
|
1018
|
-
setValue: (value) => {
|
1019
|
-
useComposer.setState({ value });
|
1020
|
-
},
|
1021
|
-
edit: () => {
|
1048
|
+
cancelRun: () => {
|
1022
1049
|
throw new Error("Not implemented");
|
1023
1050
|
},
|
1024
|
-
send: () => {
|
1025
|
-
useThread.getState().append({
|
1026
|
-
role: "user",
|
1027
|
-
content: [{ type: "text", text: useComposer.getState().value }]
|
1028
|
-
});
|
1029
|
-
useComposer.getState().setValue("");
|
1030
|
-
},
|
1031
|
-
cancel: () => {
|
1032
|
-
useThread.getState().stop();
|
1033
|
-
}
|
1034
|
-
}));
|
1035
|
-
const useBranchObserver = create2()(() => ({
|
1036
|
-
getBranchState: () => ({
|
1037
|
-
branchId: 0,
|
1038
|
-
branchCount: 1
|
1039
|
-
}),
|
1040
1051
|
switchToBranch: () => {
|
1041
1052
|
throw new Error("Not implemented");
|
1042
1053
|
},
|
1043
|
-
|
1044
|
-
throw new Error("Not implemented");
|
1045
|
-
},
|
1046
|
-
reloadAt: async () => {
|
1054
|
+
startRun: async () => {
|
1047
1055
|
throw new Error("Not implemented");
|
1048
1056
|
}
|
1049
1057
|
}));
|
1050
|
-
|
1058
|
+
const useViewport = makeViewportStore();
|
1059
|
+
const useComposer = makeThreadComposerStore({
|
1060
|
+
onSend: async (text) => {
|
1061
|
+
await useThread.getState().append({
|
1062
|
+
parentId: useThread.getState().messages.at(-1)?.id ?? ROOT_PARENT_ID,
|
1063
|
+
content: [{ type: "text", text }]
|
1064
|
+
});
|
1065
|
+
},
|
1066
|
+
onCancel: () => {
|
1067
|
+
useThread.getState().cancelRun();
|
1068
|
+
}
|
1069
|
+
});
|
1070
|
+
return { useThread, useViewport, useComposer };
|
1051
1071
|
});
|
1052
1072
|
return context;
|
1053
1073
|
};
|
1054
1074
|
|
1055
|
-
// src/vercel/VercelAIAssistantProvider.tsx
|
1075
|
+
// src/adapters/vercel/VercelAIAssistantProvider.tsx
|
1056
1076
|
var ThreadMessageCache = /* @__PURE__ */ new WeakMap();
|
1057
|
-
var vercelToThreadMessage = (message) => {
|
1077
|
+
var vercelToThreadMessage = (message, parentId, branchId, branchCount) => {
|
1058
1078
|
if (message.role !== "user" && message.role !== "assistant")
|
1059
1079
|
throw new Error("Unsupported role");
|
1060
1080
|
return {
|
1081
|
+
parentId,
|
1061
1082
|
id: message.id,
|
1062
1083
|
role: message.role,
|
1063
|
-
content: [{ type: "text", text: message.content }]
|
1084
|
+
content: [{ type: "text", text: message.content }],
|
1085
|
+
branchId,
|
1086
|
+
branchCount,
|
1087
|
+
createdAt: message.createdAt ?? /* @__PURE__ */ new Date()
|
1064
1088
|
};
|
1065
1089
|
};
|
1066
|
-
var vercelToCachedThreadMessages = (messages) => {
|
1067
|
-
return messages.map((m) => {
|
1090
|
+
var vercelToCachedThreadMessages = (messages, getBranchState) => {
|
1091
|
+
return messages.map((m, idx) => {
|
1068
1092
|
const cached = ThreadMessageCache.get(m);
|
1069
|
-
|
1093
|
+
const parentId = messages[idx - 1]?.id ?? ROOT_PARENT_ID;
|
1094
|
+
const { branchId, branchCount } = getBranchState(m.id);
|
1095
|
+
if (cached && cached.parentId === parentId && cached.branchId === branchId && cached.branchCount === branchCount)
|
1070
1096
|
return cached;
|
1071
|
-
const newMessage = vercelToThreadMessage(
|
1097
|
+
const newMessage = vercelToThreadMessage(
|
1098
|
+
m,
|
1099
|
+
parentId,
|
1100
|
+
branchId,
|
1101
|
+
branchCount
|
1102
|
+
);
|
1072
1103
|
ThreadMessageCache.set(m, newMessage);
|
1073
1104
|
return newMessage;
|
1074
1105
|
});
|
@@ -1079,73 +1110,67 @@ var VercelAIAssistantProvider = ({
|
|
1079
1110
|
}) => {
|
1080
1111
|
const context = useDummyAIAssistantContext();
|
1081
1112
|
const vercel = "chat" in rest ? rest.chat : rest.assistant;
|
1113
|
+
const branches = useVercelAIBranches(vercel, context);
|
1082
1114
|
const messages = useMemo4(() => {
|
1083
|
-
return vercelToCachedThreadMessages(
|
1084
|
-
|
1085
|
-
|
1086
|
-
|
1087
|
-
|
1088
|
-
|
1089
|
-
}
|
1090
|
-
context.useThread.getState().scrollToBottom();
|
1091
|
-
await vercel.append({
|
1092
|
-
role: message.role,
|
1093
|
-
content: message.content[0].text
|
1094
|
-
});
|
1095
|
-
},
|
1096
|
-
[context, vercel.append]
|
1097
|
-
);
|
1098
|
-
const stop = useCallback3(() => {
|
1115
|
+
return vercelToCachedThreadMessages(
|
1116
|
+
vercel.messages,
|
1117
|
+
branches.getBranchState
|
1118
|
+
);
|
1119
|
+
}, [vercel.messages, branches.getBranchState]);
|
1120
|
+
const cancelRun = useCallback3(() => {
|
1099
1121
|
const lastMessage = vercel.messages.at(-1);
|
1100
1122
|
vercel.stop();
|
1101
1123
|
if (lastMessage?.role === "user") {
|
1102
1124
|
vercel.setInput(lastMessage.content);
|
1103
1125
|
}
|
1104
1126
|
}, [vercel.messages, vercel.stop, vercel.setInput]);
|
1105
|
-
const
|
1127
|
+
const isRunning = "isLoading" in vercel ? vercel.isLoading : vercel.status === "in_progress";
|
1106
1128
|
useMemo4(() => {
|
1107
1129
|
context.useThread.setState({
|
1108
1130
|
messages,
|
1109
|
-
|
1110
|
-
|
1111
|
-
|
1131
|
+
isRunning,
|
1132
|
+
cancelRun,
|
1133
|
+
switchToBranch: branches.switchToBranch,
|
1134
|
+
append: branches.append,
|
1135
|
+
startRun: branches.startRun
|
1112
1136
|
});
|
1113
|
-
}, [context, messages,
|
1137
|
+
}, [context, messages, isRunning, cancelRun, branches]);
|
1114
1138
|
useMemo4(() => {
|
1115
1139
|
context.useComposer.setState({
|
1116
|
-
canCancel:
|
1140
|
+
canCancel: isRunning,
|
1117
1141
|
value: vercel.input,
|
1118
1142
|
setValue: vercel.setInput
|
1119
1143
|
});
|
1120
|
-
}, [context,
|
1121
|
-
const branches = useVercelAIBranches(vercel, context);
|
1122
|
-
useMemo4(() => {
|
1123
|
-
context.useBranchObserver.setState(branches, true);
|
1124
|
-
}, [context, branches]);
|
1144
|
+
}, [context, isRunning, vercel.input, vercel.setInput]);
|
1125
1145
|
return /* @__PURE__ */ React.createElement(AssistantContext.Provider, { value: context }, children);
|
1126
1146
|
};
|
1127
1147
|
|
1128
|
-
// src/vercel/VercelRSCAssistantProvider.tsx
|
1148
|
+
// src/adapters/vercel/VercelRSCAssistantProvider.tsx
|
1129
1149
|
import {
|
1130
1150
|
useCallback as useCallback4,
|
1131
1151
|
useMemo as useMemo5
|
1132
1152
|
} from "react";
|
1133
1153
|
var ThreadMessageCache2 = /* @__PURE__ */ new WeakMap();
|
1134
|
-
var vercelToThreadMessage2 = (message) => {
|
1154
|
+
var vercelToThreadMessage2 = (parentId, message) => {
|
1135
1155
|
if (message.role !== "user" && message.role !== "assistant")
|
1136
1156
|
throw new Error("Unsupported role");
|
1137
1157
|
return {
|
1158
|
+
parentId,
|
1138
1159
|
id: message.id,
|
1139
1160
|
role: message.role,
|
1140
|
-
content: [{ type: "ui", display: message.display }]
|
1161
|
+
content: [{ type: "ui", display: message.display }],
|
1162
|
+
createdAt: message.createdAt ?? /* @__PURE__ */ new Date(),
|
1163
|
+
branchId: 0,
|
1164
|
+
branchCount: 1
|
1141
1165
|
};
|
1142
1166
|
};
|
1143
1167
|
var vercelToCachedThreadMessages2 = (messages) => {
|
1144
|
-
return messages.map((m) => {
|
1168
|
+
return messages.map((m, idx) => {
|
1145
1169
|
const cached = ThreadMessageCache2.get(m);
|
1146
|
-
|
1170
|
+
const parentId = messages[idx - 1]?.id ?? ROOT_PARENT_ID;
|
1171
|
+
if (cached && cached.parentId === parentId)
|
1147
1172
|
return cached;
|
1148
|
-
const newMessage = vercelToThreadMessage2(m);
|
1173
|
+
const newMessage = vercelToThreadMessage2(parentId, m);
|
1149
1174
|
ThreadMessageCache2.set(m, newMessage);
|
1150
1175
|
return newMessage;
|
1151
1176
|
});
|
@@ -1161,14 +1186,13 @@ var VercelRSCAssistantProvider = ({
|
|
1161
1186
|
}, [vercelMessages]);
|
1162
1187
|
const append = useCallback4(
|
1163
1188
|
async (message) => {
|
1189
|
+
if (message.parentId !== (context.useThread.getState().messages.at(-1)?.id ?? ROOT_PARENT_ID))
|
1190
|
+
throw new Error("Unexpected: Message editing is not supported");
|
1164
1191
|
if (message.content[0]?.type !== "text") {
|
1165
1192
|
throw new Error("Only text content is currently supported");
|
1166
1193
|
}
|
1167
|
-
context.
|
1168
|
-
await vercelAppend(
|
1169
|
-
role: message.role,
|
1170
|
-
content: [{ type: "text", text: message.content[0].text }]
|
1171
|
-
});
|
1194
|
+
context.useViewport.getState().scrollToBottom();
|
1195
|
+
await vercelAppend(message);
|
1172
1196
|
},
|
1173
1197
|
[context, vercelAppend]
|
1174
1198
|
);
|