@assistant-ui/react 0.0.7 → 0.0.8
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 +11 -2
- package/dist/index.d.ts +11 -2
- package/dist/index.js +290 -192
- package/dist/index.mjs +278 -179
- package/package.json +1 -1
package/dist/index.js
CHANGED
@@ -53,6 +53,7 @@ __export(thread_exports, {
|
|
53
53
|
If: () => ThreadIf,
|
54
54
|
Messages: () => ThreadMessages,
|
55
55
|
Root: () => ThreadRoot,
|
56
|
+
ScrollToBottom: () => ThreadScrollToBottom,
|
56
57
|
Viewport: () => ThreadViewport
|
57
58
|
});
|
58
59
|
|
@@ -106,7 +107,7 @@ var ThreadEmpty = ({ children }) => {
|
|
106
107
|
var import_primitive = require("@radix-ui/primitive");
|
107
108
|
var import_react_compose_refs = require("@radix-ui/react-compose-refs");
|
108
109
|
var import_react_primitive2 = require("@radix-ui/react-primitive");
|
109
|
-
var
|
110
|
+
var import_react5 = require("react");
|
110
111
|
|
111
112
|
// src/utils/hooks/useOnResizeContent.tsx
|
112
113
|
var import_react3 = require("react");
|
@@ -147,22 +148,51 @@ var useOnResizeContent = (ref, callback) => {
|
|
147
148
|
}, [ref.current]);
|
148
149
|
};
|
149
150
|
|
151
|
+
// src/utils/hooks/useOnScrollToBottom.tsx
|
152
|
+
var import_react4 = require("react");
|
153
|
+
var useOnScrollToBottom = (callback) => {
|
154
|
+
const callbackRef = (0, import_react4.useRef)(callback);
|
155
|
+
callbackRef.current = callback;
|
156
|
+
const { useThread } = useAssistantContext();
|
157
|
+
(0, import_react4.useEffect)(() => {
|
158
|
+
return useThread.getState().onScrollToBottom(() => {
|
159
|
+
callbackRef.current();
|
160
|
+
});
|
161
|
+
}, [useThread]);
|
162
|
+
};
|
163
|
+
|
150
164
|
// src/primitives/thread/ThreadViewport.tsx
|
151
|
-
var ThreadViewport = (0,
|
152
|
-
const
|
165
|
+
var ThreadViewport = (0, import_react5.forwardRef)(({ autoScroll = true, onScroll, children, ...rest }, forwardedRef) => {
|
166
|
+
const messagesEndRef = (0, import_react5.useRef)(null);
|
167
|
+
const divRef = (0, import_react5.useRef)(null);
|
153
168
|
const ref = (0, import_react_compose_refs.useComposedRefs)(forwardedRef, divRef);
|
154
|
-
const
|
169
|
+
const { useThread } = useAssistantContext();
|
170
|
+
const firstRenderRef = (0, import_react5.useRef)(true);
|
171
|
+
const scrollToBottom = () => {
|
172
|
+
const div = messagesEndRef.current;
|
173
|
+
if (!div || !autoScroll)
|
174
|
+
return;
|
175
|
+
const behavior = firstRenderRef.current ? "instant" : "auto";
|
176
|
+
firstRenderRef.current = false;
|
177
|
+
div.scrollIntoView({ behavior });
|
178
|
+
};
|
155
179
|
useOnResizeContent(divRef, () => {
|
156
|
-
|
157
|
-
if (!div || !isAtBottom)
|
180
|
+
if (!useThread.getState().isAtBottom)
|
158
181
|
return;
|
159
|
-
|
182
|
+
scrollToBottom();
|
183
|
+
});
|
184
|
+
useOnScrollToBottom(() => {
|
185
|
+
scrollToBottom();
|
160
186
|
});
|
161
187
|
const handleScroll = () => {
|
162
188
|
const div = divRef.current;
|
163
189
|
if (!div)
|
164
190
|
return;
|
165
|
-
|
191
|
+
const isAtBottom = useThread.getState().isAtBottom;
|
192
|
+
const newIsAtBottom = div.scrollHeight - div.scrollTop <= div.clientHeight + 50;
|
193
|
+
if (newIsAtBottom !== isAtBottom) {
|
194
|
+
useThread.setState({ isAtBottom: newIsAtBottom });
|
195
|
+
}
|
166
196
|
};
|
167
197
|
return /* @__PURE__ */ React.createElement(
|
168
198
|
import_react_primitive2.Primitive.div,
|
@@ -171,12 +201,13 @@ var ThreadViewport = (0, import_react4.forwardRef)(({ onScroll, children, ...res
|
|
171
201
|
onScroll: (0, import_primitive.composeEventHandlers)(onScroll, handleScroll),
|
172
202
|
ref
|
173
203
|
},
|
174
|
-
children
|
204
|
+
children,
|
205
|
+
/* @__PURE__ */ React.createElement("div", { ref: messagesEndRef })
|
175
206
|
);
|
176
207
|
});
|
177
208
|
|
178
209
|
// src/vercel/useVercelAIBranches.tsx
|
179
|
-
var
|
210
|
+
var import_react6 = require("react");
|
180
211
|
var ROOT_ID = "__ROOT_ID__";
|
181
212
|
var UPCOMING_MESSAGE_ID = "__UPCOMING_MESSAGE_ID__";
|
182
213
|
var updateBranchData = (data, messages) => {
|
@@ -243,20 +274,20 @@ var sliceMessagesUntil = (messages, message) => {
|
|
243
274
|
throw new Error("Unexpected: Message not found");
|
244
275
|
return messages.slice(0, messageIdx);
|
245
276
|
};
|
246
|
-
var useVercelAIBranches = (chat) => {
|
247
|
-
const data = (0,
|
277
|
+
var useVercelAIBranches = (chat, context) => {
|
278
|
+
const data = (0, import_react6.useRef)({
|
248
279
|
parentMap: /* @__PURE__ */ new Map(),
|
249
280
|
branchMap: /* @__PURE__ */ new Map(),
|
250
281
|
snapshots: /* @__PURE__ */ new Map()
|
251
282
|
}).current;
|
252
283
|
updateBranchData(data, chat.messages);
|
253
|
-
const getBranchState = (0,
|
284
|
+
const getBranchState = (0, import_react6.useCallback)(
|
254
285
|
(message) => {
|
255
286
|
return getBranchStateImpl(data, chat.messages, message);
|
256
287
|
},
|
257
288
|
[data, chat.messages]
|
258
289
|
);
|
259
|
-
const switchToBranch = (0,
|
290
|
+
const switchToBranch = (0, import_react6.useCallback)(
|
260
291
|
(message, branchId) => {
|
261
292
|
const newMessages = switchToBranchImpl(
|
262
293
|
data,
|
@@ -269,30 +300,32 @@ var useVercelAIBranches = (chat) => {
|
|
269
300
|
[data, chat.messages, chat.setMessages]
|
270
301
|
);
|
271
302
|
const reloadMaybe = "reload" in chat ? chat.reload : void 0;
|
272
|
-
const reloadAt = (0,
|
303
|
+
const reloadAt = (0, import_react6.useCallback)(
|
273
304
|
async (message) => {
|
274
305
|
if (!reloadMaybe)
|
275
306
|
throw new Error("Reload not supported by Vercel AI SDK's useAssistant");
|
276
307
|
const newMessages = sliceMessagesUntil(chat.messages, message);
|
277
308
|
chat.setMessages(newMessages);
|
309
|
+
context.useThread.getState().scrollToBottom();
|
278
310
|
await reloadMaybe();
|
279
311
|
},
|
280
|
-
[chat.messages, chat.setMessages, reloadMaybe]
|
312
|
+
[context, chat.messages, chat.setMessages, reloadMaybe]
|
281
313
|
);
|
282
|
-
const editAt = (0,
|
314
|
+
const editAt = (0, import_react6.useCallback)(
|
283
315
|
async (message, newMessage) => {
|
284
316
|
const newMessages = sliceMessagesUntil(chat.messages, message);
|
285
317
|
chat.setMessages(newMessages);
|
286
318
|
if (newMessage.content[0]?.type !== "text")
|
287
319
|
throw new Error("Only text content is currently supported");
|
320
|
+
context.useThread.getState().scrollToBottom();
|
288
321
|
await chat.append({
|
289
322
|
role: "user",
|
290
323
|
content: newMessage.content[0].text
|
291
324
|
});
|
292
325
|
},
|
293
|
-
[chat.messages, chat.setMessages, chat.append]
|
326
|
+
[context, chat.messages, chat.setMessages, chat.append]
|
294
327
|
);
|
295
|
-
return (0,
|
328
|
+
return (0, import_react6.useMemo)(
|
296
329
|
() => ({
|
297
330
|
getBranchState,
|
298
331
|
switchToBranch,
|
@@ -306,24 +339,27 @@ var hasUpcomingMessage = (thread) => {
|
|
306
339
|
return thread.isLoading && thread.messages[thread.messages.length - 1]?.role !== "assistant";
|
307
340
|
};
|
308
341
|
|
309
|
-
// src/utils/context/
|
310
|
-
var
|
342
|
+
// src/utils/context/useComposerContext.ts
|
343
|
+
var import_react8 = require("react");
|
311
344
|
|
312
|
-
// src/utils/context/
|
313
|
-
var
|
314
|
-
var MessageContext = (0,
|
345
|
+
// src/utils/context/useMessageContext.ts
|
346
|
+
var import_react7 = require("react");
|
347
|
+
var MessageContext = (0, import_react7.createContext)(null);
|
315
348
|
var useMessageContext = () => {
|
316
|
-
const context = (0,
|
349
|
+
const context = (0, import_react7.useContext)(MessageContext);
|
317
350
|
if (!context)
|
318
351
|
throw new Error("useMessageContext must be used within a MessageProvider");
|
319
352
|
return context;
|
320
353
|
};
|
321
354
|
|
322
|
-
// src/utils/context/
|
355
|
+
// src/utils/context/useComposerContext.ts
|
323
356
|
var useComposerContext = () => {
|
324
357
|
const { useComposer: useAssisstantComposer } = useAssistantContext();
|
325
|
-
const { useComposer: useMessageComposer } = (0,
|
326
|
-
return {
|
358
|
+
const { useComposer: useMessageComposer } = (0, import_react8.useContext)(MessageContext) ?? {};
|
359
|
+
return {
|
360
|
+
useComposer: useMessageComposer ?? useAssisstantComposer,
|
361
|
+
type: useMessageComposer ? "message" : "assistant"
|
362
|
+
};
|
327
363
|
};
|
328
364
|
|
329
365
|
// src/primitives/composer/ComposerIf.tsx
|
@@ -352,7 +388,7 @@ __export(message_exports, {
|
|
352
388
|
});
|
353
389
|
|
354
390
|
// src/primitives/message/MessageProvider.tsx
|
355
|
-
var
|
391
|
+
var import_react9 = require("react");
|
356
392
|
var import_zustand = require("zustand");
|
357
393
|
var import_shallow = require("zustand/react/shallow");
|
358
394
|
var getIsLast = (thread, message) => {
|
@@ -361,7 +397,7 @@ var getIsLast = (thread, message) => {
|
|
361
397
|
};
|
362
398
|
var useMessageContext2 = () => {
|
363
399
|
const { useBranchObserver } = useAssistantContext();
|
364
|
-
const [context] = (0,
|
400
|
+
const [context] = (0, import_react9.useState)(() => {
|
365
401
|
const useMessage = (0, import_zustand.create)(() => ({
|
366
402
|
message: null,
|
367
403
|
isLast: false,
|
@@ -418,9 +454,9 @@ var MessageProvider = ({
|
|
418
454
|
(0, import_shallow.useShallow)((b) => b.getBranchState(message))
|
419
455
|
);
|
420
456
|
const isLast = useThread((thread) => getIsLast(thread, message));
|
421
|
-
const [isCopied, setIsCopied] = (0,
|
422
|
-
const [isHovering, setIsHovering] = (0,
|
423
|
-
(0,
|
457
|
+
const [isCopied, setIsCopied] = (0, import_react9.useState)(false);
|
458
|
+
const [isHovering, setIsHovering] = (0, import_react9.useState)(false);
|
459
|
+
(0, import_react9.useMemo)(() => {
|
424
460
|
context.useMessage.setState(
|
425
461
|
{
|
426
462
|
message,
|
@@ -440,8 +476,8 @@ var MessageProvider = ({
|
|
440
476
|
// src/primitives/message/MessageRoot.tsx
|
441
477
|
var import_primitive2 = require("@radix-ui/primitive");
|
442
478
|
var import_react_primitive3 = require("@radix-ui/react-primitive");
|
443
|
-
var
|
444
|
-
var MessageRoot = (0,
|
479
|
+
var import_react10 = require("react");
|
480
|
+
var MessageRoot = (0, import_react10.forwardRef)(
|
445
481
|
({ onMouseEnter, onMouseLeave, ...rest }, ref) => {
|
446
482
|
const { useMessage } = useMessageContext();
|
447
483
|
const setIsHovering = useMessage((s) => s.setIsHovering);
|
@@ -566,6 +602,29 @@ var ThreadMessages = ({ components }) => {
|
|
566
602
|
));
|
567
603
|
};
|
568
604
|
|
605
|
+
// src/primitives/thread/ThreadScrollToBottom.tsx
|
606
|
+
var import_primitive3 = require("@radix-ui/primitive");
|
607
|
+
var import_react_primitive4 = require("@radix-ui/react-primitive");
|
608
|
+
var import_react11 = require("react");
|
609
|
+
var ThreadScrollToBottom = (0, import_react11.forwardRef)(({ onClick, ...rest }, ref) => {
|
610
|
+
const { useThread } = useAssistantContext();
|
611
|
+
const isAtBottom = useThread((s) => s.isAtBottom);
|
612
|
+
const handleScrollToBottom = () => {
|
613
|
+
const thread = useThread.getState();
|
614
|
+
thread.scrollToBottom();
|
615
|
+
};
|
616
|
+
if (isAtBottom)
|
617
|
+
return null;
|
618
|
+
return /* @__PURE__ */ React.createElement(
|
619
|
+
import_react_primitive4.Primitive.button,
|
620
|
+
{
|
621
|
+
...rest,
|
622
|
+
ref,
|
623
|
+
onClick: (0, import_primitive3.composeEventHandlers)(onClick, handleScrollToBottom)
|
624
|
+
}
|
625
|
+
);
|
626
|
+
});
|
627
|
+
|
569
628
|
// src/primitives/composer/index.ts
|
570
629
|
var composer_exports = {};
|
571
630
|
__export(composer_exports, {
|
@@ -577,33 +636,15 @@ __export(composer_exports, {
|
|
577
636
|
});
|
578
637
|
|
579
638
|
// src/primitives/composer/ComposerRoot.tsx
|
580
|
-
var
|
639
|
+
var import_primitive4 = require("@radix-ui/primitive");
|
581
640
|
var import_react_compose_refs2 = require("@radix-ui/react-compose-refs");
|
582
|
-
var
|
583
|
-
var
|
584
|
-
var
|
585
|
-
var useComposerFormContext = () => {
|
586
|
-
const context = (0, import_react10.useContext)(ComposerFormContext);
|
587
|
-
if (!context) {
|
588
|
-
throw new Error(
|
589
|
-
"Composer compound components cannot be rendered outside the Composer component"
|
590
|
-
);
|
591
|
-
}
|
592
|
-
return context;
|
593
|
-
};
|
594
|
-
var ComposerRoot = (0, import_react10.forwardRef)(
|
641
|
+
var import_react_primitive5 = require("@radix-ui/react-primitive");
|
642
|
+
var import_react12 = require("react");
|
643
|
+
var ComposerRoot = (0, import_react12.forwardRef)(
|
595
644
|
({ onSubmit, ...rest }, forwardedRef) => {
|
596
645
|
const { useComposer } = useComposerContext();
|
597
|
-
const formRef = (0,
|
646
|
+
const formRef = (0, import_react12.useRef)(null);
|
598
647
|
const ref = (0, import_react_compose_refs2.useComposedRefs)(forwardedRef, formRef);
|
599
|
-
const composerContextValue = (0, import_react10.useMemo)(
|
600
|
-
() => ({
|
601
|
-
submit: () => formRef.current?.dispatchEvent(
|
602
|
-
new Event("submit", { cancelable: true, bubbles: true })
|
603
|
-
)
|
604
|
-
}),
|
605
|
-
[]
|
606
|
-
);
|
607
648
|
const handleSubmit = (e) => {
|
608
649
|
const composerState = useComposer.getState();
|
609
650
|
if (!composerState.isEditing)
|
@@ -611,73 +652,96 @@ var ComposerRoot = (0, import_react10.forwardRef)(
|
|
611
652
|
e.preventDefault();
|
612
653
|
composerState.send();
|
613
654
|
};
|
614
|
-
return /* @__PURE__ */ React.createElement(
|
615
|
-
|
655
|
+
return /* @__PURE__ */ React.createElement(
|
656
|
+
import_react_primitive5.Primitive.form,
|
616
657
|
{
|
617
658
|
...rest,
|
618
659
|
ref,
|
619
|
-
onSubmit: (0,
|
660
|
+
onSubmit: (0, import_primitive4.composeEventHandlers)(onSubmit, handleSubmit)
|
620
661
|
}
|
621
|
-
)
|
662
|
+
);
|
622
663
|
}
|
623
664
|
);
|
624
665
|
|
625
666
|
// src/primitives/composer/ComposerInput.tsx
|
626
|
-
var
|
667
|
+
var import_primitive5 = require("@radix-ui/primitive");
|
668
|
+
var import_react_compose_refs3 = require("@radix-ui/react-compose-refs");
|
627
669
|
var import_react_slot = require("@radix-ui/react-slot");
|
628
|
-
var
|
670
|
+
var import_react13 = require("react");
|
629
671
|
var import_react_textarea_autosize = __toESM(require("react-textarea-autosize"));
|
630
|
-
var ComposerInput = (0,
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
663
|
-
|
664
|
-
|
665
|
-
|
666
|
-
|
667
|
-
|
668
|
-
}
|
669
|
-
|
670
|
-
|
672
|
+
var ComposerInput = (0, import_react13.forwardRef)(
|
673
|
+
({ autoFocus, asChild, disabled, onChange, onKeyDown, ...rest }, forwardedRef) => {
|
674
|
+
const { useThread } = useAssistantContext();
|
675
|
+
const { useComposer, type } = useComposerContext();
|
676
|
+
const value = useComposer((c) => {
|
677
|
+
if (!c.isEditing)
|
678
|
+
return "";
|
679
|
+
return c.value;
|
680
|
+
});
|
681
|
+
const Component = asChild ? import_react_slot.Slot : import_react_textarea_autosize.default;
|
682
|
+
const handleKeyPress = (e) => {
|
683
|
+
if (disabled)
|
684
|
+
return;
|
685
|
+
const composer = useComposer.getState();
|
686
|
+
if (e.key === "Escape" && composer.canCancel) {
|
687
|
+
e.preventDefault();
|
688
|
+
useComposer.getState().cancel();
|
689
|
+
}
|
690
|
+
if (e.key === "Enter" && e.shiftKey === false) {
|
691
|
+
const isLoading = useThread.getState().isLoading;
|
692
|
+
if (!isLoading) {
|
693
|
+
e.preventDefault();
|
694
|
+
composer.send();
|
695
|
+
}
|
696
|
+
}
|
697
|
+
};
|
698
|
+
const textareaRef = (0, import_react13.useRef)(null);
|
699
|
+
const ref = (0, import_react_compose_refs3.useComposedRefs)(forwardedRef, textareaRef);
|
700
|
+
const autoFocusEnabled = autoFocus !== false && !disabled;
|
701
|
+
const focus = (0, import_react13.useCallback)(() => {
|
702
|
+
const textarea = textareaRef.current;
|
703
|
+
if (!textarea || !autoFocusEnabled)
|
704
|
+
return;
|
705
|
+
textarea.focus();
|
706
|
+
textarea.setSelectionRange(
|
707
|
+
textareaRef.current.value.length,
|
708
|
+
textareaRef.current.value.length
|
709
|
+
);
|
710
|
+
}, [autoFocusEnabled]);
|
711
|
+
(0, import_react13.useEffect)(() => focus(), [focus]);
|
712
|
+
useOnScrollToBottom(() => {
|
713
|
+
if (type === "assistant") {
|
714
|
+
focus();
|
715
|
+
}
|
716
|
+
});
|
717
|
+
return /* @__PURE__ */ React.createElement(
|
718
|
+
Component,
|
719
|
+
{
|
720
|
+
value,
|
721
|
+
...rest,
|
722
|
+
ref,
|
723
|
+
disabled,
|
724
|
+
onChange: (0, import_primitive5.composeEventHandlers)(onChange, (e) => {
|
725
|
+
const composerState = useComposer.getState();
|
726
|
+
if (!composerState.isEditing)
|
727
|
+
return;
|
728
|
+
return composerState.setValue(e.target.value);
|
729
|
+
}),
|
730
|
+
onKeyDown: (0, import_primitive5.composeEventHandlers)(onKeyDown, handleKeyPress)
|
731
|
+
}
|
732
|
+
);
|
733
|
+
}
|
734
|
+
);
|
671
735
|
|
672
736
|
// src/primitives/composer/ComposerSend.tsx
|
673
|
-
var
|
674
|
-
var
|
675
|
-
var ComposerSend = (0,
|
737
|
+
var import_react_primitive6 = require("@radix-ui/react-primitive");
|
738
|
+
var import_react14 = require("react");
|
739
|
+
var ComposerSend = (0, import_react14.forwardRef)(
|
676
740
|
({ disabled, ...rest }, ref) => {
|
677
741
|
const { useComposer } = useComposerContext();
|
678
742
|
const hasValue = useComposer((c) => c.isEditing && c.value.length > 0);
|
679
743
|
return /* @__PURE__ */ React.createElement(
|
680
|
-
|
744
|
+
import_react_primitive6.Primitive.button,
|
681
745
|
{
|
682
746
|
type: "submit",
|
683
747
|
...rest,
|
@@ -689,22 +753,22 @@ var ComposerSend = (0, import_react12.forwardRef)(
|
|
689
753
|
);
|
690
754
|
|
691
755
|
// src/primitives/composer/ComposerCancel.tsx
|
692
|
-
var
|
693
|
-
var
|
694
|
-
var
|
695
|
-
var ComposerCancel = (0,
|
756
|
+
var import_primitive6 = require("@radix-ui/primitive");
|
757
|
+
var import_react_primitive7 = require("@radix-ui/react-primitive");
|
758
|
+
var import_react15 = require("react");
|
759
|
+
var ComposerCancel = (0, import_react15.forwardRef)(({ disabled, onClick, ...rest }, ref) => {
|
696
760
|
const { useComposer } = useComposerContext();
|
697
761
|
const hasValue = useComposer((c) => c.canCancel);
|
698
762
|
const handleClose = () => {
|
699
763
|
useComposer.getState().cancel();
|
700
764
|
};
|
701
765
|
return /* @__PURE__ */ React.createElement(
|
702
|
-
|
766
|
+
import_react_primitive7.Primitive.button,
|
703
767
|
{
|
704
768
|
type: "button",
|
705
769
|
...rest,
|
706
770
|
ref,
|
707
|
-
onClick: (0,
|
771
|
+
onClick: (0, import_primitive6.composeEventHandlers)(onClick, handleClose),
|
708
772
|
disabled: disabled || !hasValue
|
709
773
|
}
|
710
774
|
);
|
@@ -720,16 +784,41 @@ __export(branchPicker_exports, {
|
|
720
784
|
Root: () => BranchPickerRoot
|
721
785
|
});
|
722
786
|
|
787
|
+
// src/utils/context/combined/useCombinedStore.ts
|
788
|
+
var import_react17 = require("react");
|
789
|
+
|
790
|
+
// src/utils/context/combined/createCombinedStore.ts
|
791
|
+
var import_react16 = require("react");
|
792
|
+
var createCombinedStore = (stores) => {
|
793
|
+
const subscribe = (callback) => {
|
794
|
+
const unsubscribes = stores.map((store) => store.subscribe(callback));
|
795
|
+
return () => {
|
796
|
+
for (const unsub of unsubscribes) {
|
797
|
+
unsub();
|
798
|
+
}
|
799
|
+
};
|
800
|
+
};
|
801
|
+
return (selector) => {
|
802
|
+
const getSnapshot = () => selector(...stores.map((store) => store.getState()));
|
803
|
+
return (0, import_react16.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
|
804
|
+
};
|
805
|
+
};
|
806
|
+
|
807
|
+
// src/utils/context/combined/useCombinedStore.ts
|
808
|
+
var useCombinedStore = (stores, selector) => {
|
809
|
+
const useCombined = (0, import_react17.useMemo)(() => createCombinedStore(stores), stores);
|
810
|
+
return useCombined(selector);
|
811
|
+
};
|
812
|
+
|
723
813
|
// src/actions/useGoToNextBranch.tsx
|
724
814
|
var useGoToNextBranch = () => {
|
725
815
|
const { useThread, useBranchObserver } = useAssistantContext();
|
726
816
|
const { useComposer, useMessage } = useMessageContext();
|
727
|
-
const
|
728
|
-
|
729
|
-
|
730
|
-
({ branchState: { branchId, branchCount } }) => branchId + 1 < branchCount
|
817
|
+
const disabled = useCombinedStore(
|
818
|
+
[useThread, useComposer, useMessage],
|
819
|
+
(t, c, m) => t.isLoading || c.isEditing || m.branchState.branchId + 1 >= m.branchState.branchCount
|
731
820
|
);
|
732
|
-
if (
|
821
|
+
if (disabled)
|
733
822
|
return null;
|
734
823
|
return () => {
|
735
824
|
const {
|
@@ -741,21 +830,21 @@ var useGoToNextBranch = () => {
|
|
741
830
|
};
|
742
831
|
|
743
832
|
// src/utils/createActionButton.tsx
|
744
|
-
var
|
745
|
-
var
|
746
|
-
var
|
833
|
+
var import_react18 = require("react");
|
834
|
+
var import_react_primitive8 = require("@radix-ui/react-primitive");
|
835
|
+
var import_primitive7 = require("@radix-ui/primitive");
|
747
836
|
var createActionButton = (useActionButton) => {
|
748
|
-
return (0,
|
837
|
+
return (0, import_react18.forwardRef)(
|
749
838
|
(props, forwardedRef) => {
|
750
839
|
const onClick = useActionButton(props);
|
751
840
|
return /* @__PURE__ */ React.createElement(
|
752
|
-
|
841
|
+
import_react_primitive8.Primitive.button,
|
753
842
|
{
|
754
843
|
type: "button",
|
755
844
|
disabled: !onClick,
|
756
845
|
...props,
|
757
846
|
ref: forwardedRef,
|
758
|
-
onClick: (0,
|
847
|
+
onClick: (0, import_primitive7.composeEventHandlers)(props.onClick, onClick ?? void 0)
|
759
848
|
}
|
760
849
|
);
|
761
850
|
}
|
@@ -769,10 +858,11 @@ var BranchPickerNext = createActionButton(useGoToNextBranch);
|
|
769
858
|
var useGoToPreviousBranch = () => {
|
770
859
|
const { useThread, useBranchObserver } = useAssistantContext();
|
771
860
|
const { useComposer, useMessage } = useMessageContext();
|
772
|
-
const
|
773
|
-
|
774
|
-
|
775
|
-
|
861
|
+
const disabled = useCombinedStore(
|
862
|
+
[useThread, useComposer, useMessage],
|
863
|
+
(t, c, m) => t.isLoading || c.isEditing || m.branchState.branchId <= 0
|
864
|
+
);
|
865
|
+
if (disabled)
|
776
866
|
return null;
|
777
867
|
return () => {
|
778
868
|
const {
|
@@ -801,10 +891,10 @@ var BranchPickerNumber = () => {
|
|
801
891
|
};
|
802
892
|
|
803
893
|
// src/primitives/branchPicker/BranchPickerRoot.tsx
|
804
|
-
var
|
805
|
-
var
|
806
|
-
var BranchPickerRoot = (0,
|
807
|
-
return /* @__PURE__ */ React.createElement(MessageIf, { hasBranches: hideWhenSingleBranch ? true : void 0 }, /* @__PURE__ */ React.createElement(
|
894
|
+
var import_react_primitive9 = require("@radix-ui/react-primitive");
|
895
|
+
var import_react19 = require("react");
|
896
|
+
var BranchPickerRoot = (0, import_react19.forwardRef)(({ hideWhenSingleBranch, ...rest }, ref) => {
|
897
|
+
return /* @__PURE__ */ React.createElement(MessageIf, { hasBranches: hideWhenSingleBranch ? true : void 0 }, /* @__PURE__ */ React.createElement(import_react_primitive9.Primitive.div, { ...rest, ref }));
|
808
898
|
});
|
809
899
|
|
810
900
|
// src/primitives/actionBar/index.ts
|
@@ -817,28 +907,30 @@ __export(actionBar_exports, {
|
|
817
907
|
});
|
818
908
|
|
819
909
|
// src/primitives/actionBar/ActionBarRoot.tsx
|
820
|
-
var
|
821
|
-
var
|
822
|
-
var ActionBarRoot = (0,
|
910
|
+
var import_react_primitive10 = require("@radix-ui/react-primitive");
|
911
|
+
var import_react20 = require("react");
|
912
|
+
var ActionBarRoot = (0, import_react20.forwardRef)(({ hideWhenBusy, autohide, autohideFloat, ...rest }, ref) => {
|
823
913
|
const { useThread } = useAssistantContext();
|
824
914
|
const { useMessage } = useMessageContext();
|
825
|
-
const hideAndfloatStatus =
|
826
|
-
|
827
|
-
|
915
|
+
const hideAndfloatStatus = useCombinedStore(
|
916
|
+
[useThread, useMessage],
|
917
|
+
(t, m) => {
|
918
|
+
if (hideWhenBusy && t.isLoading)
|
919
|
+
return "hidden" /* Hidden */;
|
920
|
+
const autohideEnabled = autohide === "always" || autohide === "not-last" && !m.isLast;
|
921
|
+
if (!autohideEnabled)
|
922
|
+
return "normal" /* Normal */;
|
923
|
+
if (!m.isHovering)
|
924
|
+
return "hidden" /* Hidden */;
|
925
|
+
if (autohideFloat === "always" || autohideFloat === "single-branch" && m.branchState.branchCount <= 1)
|
926
|
+
return "floating" /* Floating */;
|
828
927
|
return "normal" /* Normal */;
|
829
|
-
|
830
|
-
|
831
|
-
if (autohideFloat === "always" || autohideFloat === "single-branch" && m.branchState.branchCount <= 1)
|
832
|
-
return "floating" /* Floating */;
|
833
|
-
return "normal" /* Normal */;
|
834
|
-
});
|
835
|
-
const busy = useThread((t) => t.isLoading);
|
836
|
-
if (hideWhenBusy && busy)
|
837
|
-
return null;
|
928
|
+
}
|
929
|
+
);
|
838
930
|
if (hideAndfloatStatus === "hidden" /* Hidden */)
|
839
931
|
return null;
|
840
932
|
return /* @__PURE__ */ React.createElement(
|
841
|
-
|
933
|
+
import_react_primitive10.Primitive.div,
|
842
934
|
{
|
843
935
|
"data-floating": hideAndfloatStatus === "floating" /* Floating */,
|
844
936
|
...rest,
|
@@ -870,9 +962,11 @@ var ActionBarCopy = createActionButton(useCopyMessage);
|
|
870
962
|
var useReloadMessage = () => {
|
871
963
|
const { useThread, useBranchObserver } = useAssistantContext();
|
872
964
|
const { useMessage } = useMessageContext();
|
873
|
-
const
|
874
|
-
|
875
|
-
|
965
|
+
const disabled = useCombinedStore(
|
966
|
+
[useThread, useMessage],
|
967
|
+
(t, m) => t.isLoading || m.message.role !== "assistant"
|
968
|
+
);
|
969
|
+
if (disabled)
|
876
970
|
return null;
|
877
971
|
return () => {
|
878
972
|
const message = useMessage.getState().message;
|
@@ -888,9 +982,11 @@ var ActionBarReload = createActionButton(useReloadMessage);
|
|
888
982
|
// src/actions/useBeginMessageEdit.tsx
|
889
983
|
var useBeginMessageEdit = () => {
|
890
984
|
const { useMessage, useComposer } = useMessageContext();
|
891
|
-
const
|
892
|
-
|
893
|
-
|
985
|
+
const disabled = useCombinedStore(
|
986
|
+
[useMessage, useComposer],
|
987
|
+
(m, c) => m.message.role !== "user" || c.isEditing
|
988
|
+
);
|
989
|
+
if (disabled)
|
894
990
|
return null;
|
895
991
|
return () => {
|
896
992
|
const { edit } = useComposer.getState();
|
@@ -902,24 +998,34 @@ var useBeginMessageEdit = () => {
|
|
902
998
|
var ActionBarEdit = createActionButton(useBeginMessageEdit);
|
903
999
|
|
904
1000
|
// src/vercel/VercelAIAssistantProvider.tsx
|
905
|
-
var
|
1001
|
+
var import_react22 = require("react");
|
906
1002
|
|
907
1003
|
// src/vercel/useDummyAIAssistantContext.tsx
|
908
|
-
var
|
1004
|
+
var import_react21 = require("react");
|
909
1005
|
var import_zustand2 = require("zustand");
|
910
1006
|
var useDummyAIAssistantContext = () => {
|
911
|
-
const [context] = (0,
|
1007
|
+
const [context] = (0, import_react21.useState)(() => {
|
1008
|
+
const scrollToBottomListeners = /* @__PURE__ */ new Set();
|
912
1009
|
const useThread = (0, import_zustand2.create)()(() => ({
|
913
1010
|
messages: [],
|
914
1011
|
isLoading: false,
|
915
|
-
reload: async () => {
|
916
|
-
throw new Error("Not implemented");
|
917
|
-
},
|
918
1012
|
append: async () => {
|
919
1013
|
throw new Error("Not implemented");
|
920
1014
|
},
|
921
1015
|
stop: () => {
|
922
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
|
+
};
|
923
1029
|
}
|
924
1030
|
}));
|
925
1031
|
const useComposer = (0, import_zustand2.create)()(() => ({
|
@@ -990,28 +1096,23 @@ var VercelAIAssistantProvider = ({
|
|
990
1096
|
}) => {
|
991
1097
|
const context = useDummyAIAssistantContext();
|
992
1098
|
const vercel = "chat" in rest ? rest.chat : rest.assistant;
|
993
|
-
const messages = (0,
|
1099
|
+
const messages = (0, import_react22.useMemo)(() => {
|
994
1100
|
return vercelToCachedThreadMessages(vercel.messages);
|
995
1101
|
}, [vercel.messages]);
|
996
|
-
const
|
997
|
-
const reload = (0, import_react18.useCallback)(async () => {
|
998
|
-
if (!maybeReload)
|
999
|
-
throw new Error("Reload not supported");
|
1000
|
-
await maybeReload();
|
1001
|
-
}, [maybeReload]);
|
1002
|
-
const append = (0, import_react18.useCallback)(
|
1102
|
+
const append = (0, import_react22.useCallback)(
|
1003
1103
|
async (message) => {
|
1004
1104
|
if (message.content[0]?.type !== "text") {
|
1005
1105
|
throw new Error("Only text content is currently supported");
|
1006
1106
|
}
|
1107
|
+
context.useThread.getState().scrollToBottom();
|
1007
1108
|
await vercel.append({
|
1008
1109
|
role: message.role,
|
1009
1110
|
content: message.content[0].text
|
1010
1111
|
});
|
1011
1112
|
},
|
1012
|
-
[vercel.append]
|
1113
|
+
[context, vercel.append]
|
1013
1114
|
);
|
1014
|
-
const stop = (0,
|
1115
|
+
const stop = (0, import_react22.useCallback)(() => {
|
1015
1116
|
const lastMessage = vercel.messages.at(-1);
|
1016
1117
|
vercel.stop();
|
1017
1118
|
if (lastMessage?.role === "user") {
|
@@ -1019,34 +1120,30 @@ var VercelAIAssistantProvider = ({
|
|
1019
1120
|
}
|
1020
1121
|
}, [vercel.messages, vercel.stop, vercel.setInput]);
|
1021
1122
|
const isLoading = "isLoading" in vercel ? vercel.isLoading : vercel.status === "in_progress";
|
1022
|
-
(0,
|
1023
|
-
context.useThread.setState(
|
1024
|
-
|
1025
|
-
|
1026
|
-
|
1027
|
-
|
1028
|
-
|
1029
|
-
|
1030
|
-
|
1031
|
-
true
|
1032
|
-
);
|
1033
|
-
}, [context, messages, reload, append, stop, isLoading]);
|
1034
|
-
(0, import_react18.useMemo)(() => {
|
1123
|
+
(0, import_react22.useMemo)(() => {
|
1124
|
+
context.useThread.setState({
|
1125
|
+
messages,
|
1126
|
+
isLoading,
|
1127
|
+
append,
|
1128
|
+
stop
|
1129
|
+
});
|
1130
|
+
}, [context, messages, append, stop, isLoading]);
|
1131
|
+
(0, import_react22.useMemo)(() => {
|
1035
1132
|
context.useComposer.setState({
|
1036
1133
|
canCancel: isLoading,
|
1037
1134
|
value: vercel.input,
|
1038
1135
|
setValue: vercel.setInput
|
1039
1136
|
});
|
1040
1137
|
}, [context, isLoading, vercel.input, vercel.setInput]);
|
1041
|
-
const branches = useVercelAIBranches(vercel);
|
1042
|
-
(0,
|
1138
|
+
const branches = useVercelAIBranches(vercel, context);
|
1139
|
+
(0, import_react22.useMemo)(() => {
|
1043
1140
|
context.useBranchObserver.setState(branches, true);
|
1044
1141
|
}, [context, branches]);
|
1045
1142
|
return /* @__PURE__ */ React.createElement(AssistantContext.Provider, { value: context }, children);
|
1046
1143
|
};
|
1047
1144
|
|
1048
1145
|
// src/vercel/VercelRSCAssistantProvider.tsx
|
1049
|
-
var
|
1146
|
+
var import_react23 = require("react");
|
1050
1147
|
var ThreadMessageCache2 = /* @__PURE__ */ new WeakMap();
|
1051
1148
|
var vercelToThreadMessage2 = (message) => {
|
1052
1149
|
if (message.role !== "user" && message.role !== "assistant")
|
@@ -1073,22 +1170,23 @@ var VercelRSCAssistantProvider = ({
|
|
1073
1170
|
append: vercelAppend
|
1074
1171
|
}) => {
|
1075
1172
|
const context = useDummyAIAssistantContext();
|
1076
|
-
const messages = (0,
|
1173
|
+
const messages = (0, import_react23.useMemo)(() => {
|
1077
1174
|
return vercelToCachedThreadMessages2(vercelMessages);
|
1078
1175
|
}, [vercelMessages]);
|
1079
|
-
const append = (0,
|
1176
|
+
const append = (0, import_react23.useCallback)(
|
1080
1177
|
async (message) => {
|
1081
1178
|
if (message.content[0]?.type !== "text") {
|
1082
1179
|
throw new Error("Only text content is currently supported");
|
1083
1180
|
}
|
1181
|
+
context.useThread.getState().scrollToBottom();
|
1084
1182
|
await vercelAppend({
|
1085
1183
|
role: message.role,
|
1086
1184
|
content: [{ type: "text", text: message.content[0].text }]
|
1087
1185
|
});
|
1088
1186
|
},
|
1089
|
-
[vercelAppend]
|
1187
|
+
[context, vercelAppend]
|
1090
1188
|
);
|
1091
|
-
(0,
|
1189
|
+
(0, import_react23.useMemo)(() => {
|
1092
1190
|
context.useThread.setState({
|
1093
1191
|
messages,
|
1094
1192
|
append
|