@assistant-ui/react 0.0.6 → 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 +66 -13
- package/dist/index.d.ts +66 -13
- package/dist/index.js +410 -209
- package/dist/index.mjs +402 -198
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
@@ -11,6 +11,7 @@ __export(thread_exports, {
|
|
11
11
|
If: () => ThreadIf,
|
12
12
|
Messages: () => ThreadMessages,
|
13
13
|
Root: () => ThreadRoot,
|
14
|
+
ScrollToBottom: () => ThreadScrollToBottom,
|
14
15
|
Viewport: () => ThreadViewport
|
15
16
|
});
|
16
17
|
|
@@ -63,12 +64,12 @@ var ThreadEmpty = ({ children }) => {
|
|
63
64
|
};
|
64
65
|
|
65
66
|
// src/primitives/thread/ThreadViewport.tsx
|
66
|
-
import {
|
67
|
+
import { composeEventHandlers } from "@radix-ui/primitive";
|
68
|
+
import { useComposedRefs } from "@radix-ui/react-compose-refs";
|
67
69
|
import {
|
68
70
|
Primitive as Primitive2
|
69
71
|
} from "@radix-ui/react-primitive";
|
70
|
-
import {
|
71
|
-
import { composeEventHandlers } from "@radix-ui/primitive";
|
72
|
+
import { forwardRef as forwardRef2, useRef as useRef3 } from "react";
|
72
73
|
|
73
74
|
// src/utils/hooks/useOnResizeContent.tsx
|
74
75
|
import { useLayoutEffect, useRef } from "react";
|
@@ -101,34 +102,60 @@ var useOnResizeContent = (ref, callback) => {
|
|
101
102
|
mutationObserver.observe(el, { childList: true });
|
102
103
|
for (const child of el.children) {
|
103
104
|
resizeObserver.observe(child);
|
104
|
-
console.log("observing child", child);
|
105
105
|
}
|
106
106
|
return () => {
|
107
|
-
console.log("disconnecting");
|
108
107
|
resizeObserver.disconnect();
|
109
108
|
mutationObserver.disconnect();
|
110
109
|
};
|
111
110
|
}, [ref.current]);
|
112
111
|
};
|
113
112
|
|
113
|
+
// src/utils/hooks/useOnScrollToBottom.tsx
|
114
|
+
import { useEffect, useRef as useRef2 } from "react";
|
115
|
+
var useOnScrollToBottom = (callback) => {
|
116
|
+
const callbackRef = useRef2(callback);
|
117
|
+
callbackRef.current = callback;
|
118
|
+
const { useThread } = useAssistantContext();
|
119
|
+
useEffect(() => {
|
120
|
+
return useThread.getState().onScrollToBottom(() => {
|
121
|
+
callbackRef.current();
|
122
|
+
});
|
123
|
+
}, [useThread]);
|
124
|
+
};
|
125
|
+
|
114
126
|
// src/primitives/thread/ThreadViewport.tsx
|
115
|
-
var ThreadViewport = forwardRef2(({ onScroll, children, ...rest }, forwardedRef) => {
|
116
|
-
const
|
127
|
+
var ThreadViewport = forwardRef2(({ autoScroll = true, onScroll, children, ...rest }, forwardedRef) => {
|
128
|
+
const messagesEndRef = useRef3(null);
|
129
|
+
const divRef = useRef3(null);
|
117
130
|
const ref = useComposedRefs(forwardedRef, divRef);
|
118
|
-
const
|
131
|
+
const { useThread } = useAssistantContext();
|
132
|
+
const firstRenderRef = useRef3(true);
|
133
|
+
const scrollToBottom = () => {
|
134
|
+
const div = messagesEndRef.current;
|
135
|
+
if (!div || !autoScroll)
|
136
|
+
return;
|
137
|
+
const behavior = firstRenderRef.current ? "instant" : "auto";
|
138
|
+
firstRenderRef.current = false;
|
139
|
+
div.scrollIntoView({ behavior });
|
140
|
+
};
|
119
141
|
useOnResizeContent(divRef, () => {
|
120
|
-
|
121
|
-
if (!div || !isAtBottom)
|
142
|
+
if (!useThread.getState().isAtBottom)
|
122
143
|
return;
|
123
|
-
|
144
|
+
scrollToBottom();
|
145
|
+
});
|
146
|
+
useOnScrollToBottom(() => {
|
147
|
+
scrollToBottom();
|
124
148
|
});
|
125
149
|
const handleScroll = () => {
|
126
150
|
const div = divRef.current;
|
127
151
|
if (!div)
|
128
152
|
return;
|
129
|
-
|
153
|
+
const isAtBottom = useThread.getState().isAtBottom;
|
154
|
+
const newIsAtBottom = div.scrollHeight - div.scrollTop <= div.clientHeight + 50;
|
155
|
+
if (newIsAtBottom !== isAtBottom) {
|
156
|
+
useThread.setState({ isAtBottom: newIsAtBottom });
|
157
|
+
}
|
130
158
|
};
|
131
|
-
console.log(isAtBottom);
|
132
159
|
return /* @__PURE__ */ React.createElement(
|
133
160
|
Primitive2.div,
|
134
161
|
{
|
@@ -136,12 +163,13 @@ var ThreadViewport = forwardRef2(({ onScroll, children, ...rest }, forwardedRef)
|
|
136
163
|
onScroll: composeEventHandlers(onScroll, handleScroll),
|
137
164
|
ref
|
138
165
|
},
|
139
|
-
children
|
166
|
+
children,
|
167
|
+
/* @__PURE__ */ React.createElement("div", { ref: messagesEndRef })
|
140
168
|
);
|
141
169
|
});
|
142
170
|
|
143
171
|
// src/vercel/useVercelAIBranches.tsx
|
144
|
-
import { useCallback, useMemo, useRef as
|
172
|
+
import { useCallback, useMemo, useRef as useRef4 } from "react";
|
145
173
|
var ROOT_ID = "__ROOT_ID__";
|
146
174
|
var UPCOMING_MESSAGE_ID = "__UPCOMING_MESSAGE_ID__";
|
147
175
|
var updateBranchData = (data, messages) => {
|
@@ -208,8 +236,8 @@ var sliceMessagesUntil = (messages, message) => {
|
|
208
236
|
throw new Error("Unexpected: Message not found");
|
209
237
|
return messages.slice(0, messageIdx);
|
210
238
|
};
|
211
|
-
var useVercelAIBranches = (chat) => {
|
212
|
-
const data =
|
239
|
+
var useVercelAIBranches = (chat, context) => {
|
240
|
+
const data = useRef4({
|
213
241
|
parentMap: /* @__PURE__ */ new Map(),
|
214
242
|
branchMap: /* @__PURE__ */ new Map(),
|
215
243
|
snapshots: /* @__PURE__ */ new Map()
|
@@ -233,13 +261,17 @@ var useVercelAIBranches = (chat) => {
|
|
233
261
|
},
|
234
262
|
[data, chat.messages, chat.setMessages]
|
235
263
|
);
|
264
|
+
const reloadMaybe = "reload" in chat ? chat.reload : void 0;
|
236
265
|
const reloadAt = useCallback(
|
237
266
|
async (message) => {
|
267
|
+
if (!reloadMaybe)
|
268
|
+
throw new Error("Reload not supported by Vercel AI SDK's useAssistant");
|
238
269
|
const newMessages = sliceMessagesUntil(chat.messages, message);
|
239
270
|
chat.setMessages(newMessages);
|
240
|
-
|
271
|
+
context.useThread.getState().scrollToBottom();
|
272
|
+
await reloadMaybe();
|
241
273
|
},
|
242
|
-
[chat.messages, chat.setMessages,
|
274
|
+
[context, chat.messages, chat.setMessages, reloadMaybe]
|
243
275
|
);
|
244
276
|
const editAt = useCallback(
|
245
277
|
async (message, newMessage) => {
|
@@ -247,12 +279,13 @@ var useVercelAIBranches = (chat) => {
|
|
247
279
|
chat.setMessages(newMessages);
|
248
280
|
if (newMessage.content[0]?.type !== "text")
|
249
281
|
throw new Error("Only text content is currently supported");
|
282
|
+
context.useThread.getState().scrollToBottom();
|
250
283
|
await chat.append({
|
251
284
|
role: "user",
|
252
285
|
content: newMessage.content[0].text
|
253
286
|
});
|
254
287
|
},
|
255
|
-
[chat.messages, chat.setMessages, chat.append]
|
288
|
+
[context, chat.messages, chat.setMessages, chat.append]
|
256
289
|
);
|
257
290
|
return useMemo(
|
258
291
|
() => ({
|
@@ -268,10 +301,10 @@ var hasUpcomingMessage = (thread) => {
|
|
268
301
|
return thread.isLoading && thread.messages[thread.messages.length - 1]?.role !== "assistant";
|
269
302
|
};
|
270
303
|
|
271
|
-
// src/utils/context/
|
304
|
+
// src/utils/context/useComposerContext.ts
|
272
305
|
import { useContext as useContext3 } from "react";
|
273
306
|
|
274
|
-
// src/utils/context/
|
307
|
+
// src/utils/context/useMessageContext.ts
|
275
308
|
import { createContext as createContext2, useContext as useContext2 } from "react";
|
276
309
|
var MessageContext = createContext2(null);
|
277
310
|
var useMessageContext = () => {
|
@@ -281,11 +314,14 @@ var useMessageContext = () => {
|
|
281
314
|
return context;
|
282
315
|
};
|
283
316
|
|
284
|
-
// src/utils/context/
|
317
|
+
// src/utils/context/useComposerContext.ts
|
285
318
|
var useComposerContext = () => {
|
286
319
|
const { useComposer: useAssisstantComposer } = useAssistantContext();
|
287
320
|
const { useComposer: useMessageComposer } = useContext3(MessageContext) ?? {};
|
288
|
-
return {
|
321
|
+
return {
|
322
|
+
useComposer: useMessageComposer ?? useAssisstantComposer,
|
323
|
+
type: useMessageComposer ? "message" : "assistant"
|
324
|
+
};
|
289
325
|
};
|
290
326
|
|
291
327
|
// src/primitives/composer/ComposerIf.tsx
|
@@ -314,7 +350,7 @@ __export(message_exports, {
|
|
314
350
|
});
|
315
351
|
|
316
352
|
// src/primitives/message/MessageProvider.tsx
|
317
|
-
import { useMemo as useMemo2, useState
|
353
|
+
import { useMemo as useMemo2, useState } from "react";
|
318
354
|
import { create } from "zustand";
|
319
355
|
import { useShallow } from "zustand/react/shallow";
|
320
356
|
var getIsLast = (thread, message) => {
|
@@ -323,7 +359,7 @@ var getIsLast = (thread, message) => {
|
|
323
359
|
};
|
324
360
|
var useMessageContext2 = () => {
|
325
361
|
const { useBranchObserver } = useAssistantContext();
|
326
|
-
const [context] =
|
362
|
+
const [context] = useState(() => {
|
327
363
|
const useMessage = create(() => ({
|
328
364
|
message: null,
|
329
365
|
isLast: false,
|
@@ -380,8 +416,8 @@ var MessageProvider = ({
|
|
380
416
|
useShallow((b) => b.getBranchState(message))
|
381
417
|
);
|
382
418
|
const isLast = useThread((thread) => getIsLast(thread, message));
|
383
|
-
const [isCopied, setIsCopied] =
|
384
|
-
const [isHovering, setIsHovering] =
|
419
|
+
const [isCopied, setIsCopied] = useState(false);
|
420
|
+
const [isHovering, setIsHovering] = useState(false);
|
385
421
|
useMemo2(() => {
|
386
422
|
context.useMessage.setState(
|
387
423
|
{
|
@@ -460,12 +496,41 @@ var MessageIf = ({ children, ...query }) => {
|
|
460
496
|
};
|
461
497
|
|
462
498
|
// src/primitives/message/MessageContent.tsx
|
463
|
-
var
|
499
|
+
var defaultComponents = {
|
500
|
+
Text: ({ part }) => /* @__PURE__ */ React.createElement(React.Fragment, null, part.text),
|
501
|
+
Image: () => null,
|
502
|
+
UI: ({ part }) => part.display,
|
503
|
+
tools: {
|
504
|
+
Fallback: () => null
|
505
|
+
}
|
506
|
+
};
|
507
|
+
var MessageContent = ({
|
508
|
+
components: {
|
509
|
+
Text = defaultComponents.Text,
|
510
|
+
Image = defaultComponents.Image,
|
511
|
+
UI = defaultComponents.UI,
|
512
|
+
tools: { by_name = {}, Fallback = defaultComponents.tools.Fallback } = {}
|
513
|
+
} = {}
|
514
|
+
}) => {
|
464
515
|
const { useMessage } = useMessageContext();
|
465
516
|
const content = useMessage((s) => s.message.content);
|
466
|
-
|
467
|
-
|
468
|
-
|
517
|
+
return /* @__PURE__ */ React.createElement(React.Fragment, null, content.map((part, i) => {
|
518
|
+
const key = i;
|
519
|
+
switch (part.type) {
|
520
|
+
case "text":
|
521
|
+
return /* @__PURE__ */ React.createElement(Text, { key, part });
|
522
|
+
case "image":
|
523
|
+
return /* @__PURE__ */ React.createElement(Image, { key, part });
|
524
|
+
case "ui":
|
525
|
+
return /* @__PURE__ */ React.createElement(UI, { key, part });
|
526
|
+
case "tool-call": {
|
527
|
+
const Tool = by_name[part.name] || Fallback;
|
528
|
+
return /* @__PURE__ */ React.createElement(Tool, { key, part });
|
529
|
+
}
|
530
|
+
default:
|
531
|
+
return null;
|
532
|
+
}
|
533
|
+
}));
|
469
534
|
};
|
470
535
|
|
471
536
|
// src/primitives/thread/ThreadMessages.tsx
|
@@ -501,6 +566,31 @@ var ThreadMessages = ({ components }) => {
|
|
501
566
|
));
|
502
567
|
};
|
503
568
|
|
569
|
+
// src/primitives/thread/ThreadScrollToBottom.tsx
|
570
|
+
import { composeEventHandlers as composeEventHandlers3 } from "@radix-ui/primitive";
|
571
|
+
import {
|
572
|
+
Primitive as Primitive4
|
573
|
+
} from "@radix-ui/react-primitive";
|
574
|
+
import { forwardRef as forwardRef4 } from "react";
|
575
|
+
var ThreadScrollToBottom = forwardRef4(({ onClick, ...rest }, ref) => {
|
576
|
+
const { useThread } = useAssistantContext();
|
577
|
+
const isAtBottom = useThread((s) => s.isAtBottom);
|
578
|
+
const handleScrollToBottom = () => {
|
579
|
+
const thread = useThread.getState();
|
580
|
+
thread.scrollToBottom();
|
581
|
+
};
|
582
|
+
if (isAtBottom)
|
583
|
+
return null;
|
584
|
+
return /* @__PURE__ */ React.createElement(
|
585
|
+
Primitive4.button,
|
586
|
+
{
|
587
|
+
...rest,
|
588
|
+
ref,
|
589
|
+
onClick: composeEventHandlers3(onClick, handleScrollToBottom)
|
590
|
+
}
|
591
|
+
);
|
592
|
+
});
|
593
|
+
|
504
594
|
// src/primitives/composer/index.ts
|
505
595
|
var composer_exports = {};
|
506
596
|
__export(composer_exports, {
|
@@ -512,41 +602,17 @@ __export(composer_exports, {
|
|
512
602
|
});
|
513
603
|
|
514
604
|
// src/primitives/composer/ComposerRoot.tsx
|
515
|
-
import { composeEventHandlers as
|
605
|
+
import { composeEventHandlers as composeEventHandlers4 } from "@radix-ui/primitive";
|
516
606
|
import { useComposedRefs as useComposedRefs2 } from "@radix-ui/react-compose-refs";
|
517
607
|
import {
|
518
|
-
Primitive as
|
608
|
+
Primitive as Primitive5
|
519
609
|
} from "@radix-ui/react-primitive";
|
520
|
-
import {
|
521
|
-
|
522
|
-
forwardRef as forwardRef4,
|
523
|
-
useContext as useContext4,
|
524
|
-
useMemo as useMemo3,
|
525
|
-
useRef as useRef4
|
526
|
-
} from "react";
|
527
|
-
var ComposerFormContext = createContext3(null);
|
528
|
-
var useComposerFormContext = () => {
|
529
|
-
const context = useContext4(ComposerFormContext);
|
530
|
-
if (!context) {
|
531
|
-
throw new Error(
|
532
|
-
"Composer compound components cannot be rendered outside the Composer component"
|
533
|
-
);
|
534
|
-
}
|
535
|
-
return context;
|
536
|
-
};
|
537
|
-
var ComposerRoot = forwardRef4(
|
610
|
+
import { forwardRef as forwardRef5, useRef as useRef5 } from "react";
|
611
|
+
var ComposerRoot = forwardRef5(
|
538
612
|
({ onSubmit, ...rest }, forwardedRef) => {
|
539
613
|
const { useComposer } = useComposerContext();
|
540
|
-
const formRef =
|
614
|
+
const formRef = useRef5(null);
|
541
615
|
const ref = useComposedRefs2(forwardedRef, formRef);
|
542
|
-
const composerContextValue = useMemo3(
|
543
|
-
() => ({
|
544
|
-
submit: () => formRef.current?.dispatchEvent(
|
545
|
-
new Event("submit", { cancelable: true, bubbles: true })
|
546
|
-
)
|
547
|
-
}),
|
548
|
-
[]
|
549
|
-
);
|
550
616
|
const handleSubmit = (e) => {
|
551
617
|
const composerState = useComposer.getState();
|
552
618
|
if (!composerState.isEditing)
|
@@ -554,75 +620,103 @@ var ComposerRoot = forwardRef4(
|
|
554
620
|
e.preventDefault();
|
555
621
|
composerState.send();
|
556
622
|
};
|
557
|
-
return /* @__PURE__ */ React.createElement(
|
558
|
-
|
623
|
+
return /* @__PURE__ */ React.createElement(
|
624
|
+
Primitive5.form,
|
559
625
|
{
|
560
626
|
...rest,
|
561
627
|
ref,
|
562
|
-
onSubmit:
|
628
|
+
onSubmit: composeEventHandlers4(onSubmit, handleSubmit)
|
563
629
|
}
|
564
|
-
)
|
630
|
+
);
|
565
631
|
}
|
566
632
|
);
|
567
633
|
|
568
634
|
// src/primitives/composer/ComposerInput.tsx
|
569
|
-
import { composeEventHandlers as
|
635
|
+
import { composeEventHandlers as composeEventHandlers5 } from "@radix-ui/primitive";
|
636
|
+
import { useComposedRefs as useComposedRefs3 } from "@radix-ui/react-compose-refs";
|
570
637
|
import { Slot } from "@radix-ui/react-slot";
|
571
|
-
import {
|
638
|
+
import {
|
639
|
+
forwardRef as forwardRef6,
|
640
|
+
useCallback as useCallback2,
|
641
|
+
useEffect as useEffect2,
|
642
|
+
useRef as useRef6
|
643
|
+
} from "react";
|
572
644
|
import TextareaAutosize from "react-textarea-autosize";
|
573
|
-
var ComposerInput =
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
}
|
612
|
-
|
613
|
-
|
645
|
+
var ComposerInput = forwardRef6(
|
646
|
+
({ autoFocus, asChild, disabled, onChange, onKeyDown, ...rest }, forwardedRef) => {
|
647
|
+
const { useThread } = useAssistantContext();
|
648
|
+
const { useComposer, type } = useComposerContext();
|
649
|
+
const value = useComposer((c) => {
|
650
|
+
if (!c.isEditing)
|
651
|
+
return "";
|
652
|
+
return c.value;
|
653
|
+
});
|
654
|
+
const Component = asChild ? Slot : TextareaAutosize;
|
655
|
+
const handleKeyPress = (e) => {
|
656
|
+
if (disabled)
|
657
|
+
return;
|
658
|
+
const composer = useComposer.getState();
|
659
|
+
if (e.key === "Escape" && composer.canCancel) {
|
660
|
+
e.preventDefault();
|
661
|
+
useComposer.getState().cancel();
|
662
|
+
}
|
663
|
+
if (e.key === "Enter" && e.shiftKey === false) {
|
664
|
+
const isLoading = useThread.getState().isLoading;
|
665
|
+
if (!isLoading) {
|
666
|
+
e.preventDefault();
|
667
|
+
composer.send();
|
668
|
+
}
|
669
|
+
}
|
670
|
+
};
|
671
|
+
const textareaRef = useRef6(null);
|
672
|
+
const ref = useComposedRefs3(forwardedRef, textareaRef);
|
673
|
+
const autoFocusEnabled = autoFocus !== false && !disabled;
|
674
|
+
const focus = useCallback2(() => {
|
675
|
+
const textarea = textareaRef.current;
|
676
|
+
if (!textarea || !autoFocusEnabled)
|
677
|
+
return;
|
678
|
+
textarea.focus();
|
679
|
+
textarea.setSelectionRange(
|
680
|
+
textareaRef.current.value.length,
|
681
|
+
textareaRef.current.value.length
|
682
|
+
);
|
683
|
+
}, [autoFocusEnabled]);
|
684
|
+
useEffect2(() => focus(), [focus]);
|
685
|
+
useOnScrollToBottom(() => {
|
686
|
+
if (type === "assistant") {
|
687
|
+
focus();
|
688
|
+
}
|
689
|
+
});
|
690
|
+
return /* @__PURE__ */ React.createElement(
|
691
|
+
Component,
|
692
|
+
{
|
693
|
+
value,
|
694
|
+
...rest,
|
695
|
+
ref,
|
696
|
+
disabled,
|
697
|
+
onChange: composeEventHandlers5(onChange, (e) => {
|
698
|
+
const composerState = useComposer.getState();
|
699
|
+
if (!composerState.isEditing)
|
700
|
+
return;
|
701
|
+
return composerState.setValue(e.target.value);
|
702
|
+
}),
|
703
|
+
onKeyDown: composeEventHandlers5(onKeyDown, handleKeyPress)
|
704
|
+
}
|
705
|
+
);
|
706
|
+
}
|
707
|
+
);
|
614
708
|
|
615
709
|
// src/primitives/composer/ComposerSend.tsx
|
616
710
|
import {
|
617
|
-
Primitive as
|
711
|
+
Primitive as Primitive6
|
618
712
|
} from "@radix-ui/react-primitive";
|
619
|
-
import { forwardRef as
|
620
|
-
var ComposerSend =
|
713
|
+
import { forwardRef as forwardRef7 } from "react";
|
714
|
+
var ComposerSend = forwardRef7(
|
621
715
|
({ disabled, ...rest }, ref) => {
|
622
716
|
const { useComposer } = useComposerContext();
|
623
717
|
const hasValue = useComposer((c) => c.isEditing && c.value.length > 0);
|
624
718
|
return /* @__PURE__ */ React.createElement(
|
625
|
-
|
719
|
+
Primitive6.button,
|
626
720
|
{
|
627
721
|
type: "submit",
|
628
722
|
...rest,
|
@@ -634,24 +728,24 @@ var ComposerSend = forwardRef6(
|
|
634
728
|
);
|
635
729
|
|
636
730
|
// src/primitives/composer/ComposerCancel.tsx
|
637
|
-
import { composeEventHandlers as
|
731
|
+
import { composeEventHandlers as composeEventHandlers6 } from "@radix-ui/primitive";
|
638
732
|
import {
|
639
|
-
Primitive as
|
733
|
+
Primitive as Primitive7
|
640
734
|
} from "@radix-ui/react-primitive";
|
641
|
-
import { forwardRef as
|
642
|
-
var ComposerCancel =
|
735
|
+
import { forwardRef as forwardRef8 } from "react";
|
736
|
+
var ComposerCancel = forwardRef8(({ disabled, onClick, ...rest }, ref) => {
|
643
737
|
const { useComposer } = useComposerContext();
|
644
738
|
const hasValue = useComposer((c) => c.canCancel);
|
645
739
|
const handleClose = () => {
|
646
740
|
useComposer.getState().cancel();
|
647
741
|
};
|
648
742
|
return /* @__PURE__ */ React.createElement(
|
649
|
-
|
743
|
+
Primitive7.button,
|
650
744
|
{
|
651
745
|
type: "button",
|
652
746
|
...rest,
|
653
747
|
ref,
|
654
|
-
onClick:
|
748
|
+
onClick: composeEventHandlers6(onClick, handleClose),
|
655
749
|
disabled: disabled || !hasValue
|
656
750
|
}
|
657
751
|
);
|
@@ -667,16 +761,41 @@ __export(branchPicker_exports, {
|
|
667
761
|
Root: () => BranchPickerRoot
|
668
762
|
});
|
669
763
|
|
764
|
+
// src/utils/context/combined/useCombinedStore.ts
|
765
|
+
import { useMemo as useMemo3 } from "react";
|
766
|
+
|
767
|
+
// src/utils/context/combined/createCombinedStore.ts
|
768
|
+
import { useSyncExternalStore } from "react";
|
769
|
+
var createCombinedStore = (stores) => {
|
770
|
+
const subscribe = (callback) => {
|
771
|
+
const unsubscribes = stores.map((store) => store.subscribe(callback));
|
772
|
+
return () => {
|
773
|
+
for (const unsub of unsubscribes) {
|
774
|
+
unsub();
|
775
|
+
}
|
776
|
+
};
|
777
|
+
};
|
778
|
+
return (selector) => {
|
779
|
+
const getSnapshot = () => selector(...stores.map((store) => store.getState()));
|
780
|
+
return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
|
781
|
+
};
|
782
|
+
};
|
783
|
+
|
784
|
+
// src/utils/context/combined/useCombinedStore.ts
|
785
|
+
var useCombinedStore = (stores, selector) => {
|
786
|
+
const useCombined = useMemo3(() => createCombinedStore(stores), stores);
|
787
|
+
return useCombined(selector);
|
788
|
+
};
|
789
|
+
|
670
790
|
// src/actions/useGoToNextBranch.tsx
|
671
791
|
var useGoToNextBranch = () => {
|
672
792
|
const { useThread, useBranchObserver } = useAssistantContext();
|
673
793
|
const { useComposer, useMessage } = useMessageContext();
|
674
|
-
const
|
675
|
-
|
676
|
-
|
677
|
-
({ branchState: { branchId, branchCount } }) => branchId + 1 < branchCount
|
794
|
+
const disabled = useCombinedStore(
|
795
|
+
[useThread, useComposer, useMessage],
|
796
|
+
(t, c, m) => t.isLoading || c.isEditing || m.branchState.branchId + 1 >= m.branchState.branchCount
|
678
797
|
);
|
679
|
-
if (
|
798
|
+
if (disabled)
|
680
799
|
return null;
|
681
800
|
return () => {
|
682
801
|
const {
|
@@ -688,23 +807,23 @@ var useGoToNextBranch = () => {
|
|
688
807
|
};
|
689
808
|
|
690
809
|
// src/utils/createActionButton.tsx
|
691
|
-
import { forwardRef as
|
810
|
+
import { forwardRef as forwardRef9 } from "react";
|
692
811
|
import {
|
693
|
-
Primitive as
|
812
|
+
Primitive as Primitive8
|
694
813
|
} from "@radix-ui/react-primitive";
|
695
|
-
import { composeEventHandlers as
|
814
|
+
import { composeEventHandlers as composeEventHandlers7 } from "@radix-ui/primitive";
|
696
815
|
var createActionButton = (useActionButton) => {
|
697
|
-
return
|
816
|
+
return forwardRef9(
|
698
817
|
(props, forwardedRef) => {
|
699
818
|
const onClick = useActionButton(props);
|
700
819
|
return /* @__PURE__ */ React.createElement(
|
701
|
-
|
820
|
+
Primitive8.button,
|
702
821
|
{
|
703
822
|
type: "button",
|
704
823
|
disabled: !onClick,
|
705
824
|
...props,
|
706
825
|
ref: forwardedRef,
|
707
|
-
onClick:
|
826
|
+
onClick: composeEventHandlers7(props.onClick, onClick ?? void 0)
|
708
827
|
}
|
709
828
|
);
|
710
829
|
}
|
@@ -718,10 +837,11 @@ var BranchPickerNext = createActionButton(useGoToNextBranch);
|
|
718
837
|
var useGoToPreviousBranch = () => {
|
719
838
|
const { useThread, useBranchObserver } = useAssistantContext();
|
720
839
|
const { useComposer, useMessage } = useMessageContext();
|
721
|
-
const
|
722
|
-
|
723
|
-
|
724
|
-
|
840
|
+
const disabled = useCombinedStore(
|
841
|
+
[useThread, useComposer, useMessage],
|
842
|
+
(t, c, m) => t.isLoading || c.isEditing || m.branchState.branchId <= 0
|
843
|
+
);
|
844
|
+
if (disabled)
|
725
845
|
return null;
|
726
846
|
return () => {
|
727
847
|
const {
|
@@ -751,11 +871,11 @@ var BranchPickerNumber = () => {
|
|
751
871
|
|
752
872
|
// src/primitives/branchPicker/BranchPickerRoot.tsx
|
753
873
|
import {
|
754
|
-
Primitive as
|
874
|
+
Primitive as Primitive9
|
755
875
|
} from "@radix-ui/react-primitive";
|
756
|
-
import { forwardRef as
|
757
|
-
var BranchPickerRoot =
|
758
|
-
return /* @__PURE__ */ React.createElement(MessageIf, { hasBranches: hideWhenSingleBranch ? true : void 0 }, /* @__PURE__ */ React.createElement(
|
876
|
+
import { forwardRef as forwardRef10 } from "react";
|
877
|
+
var BranchPickerRoot = forwardRef10(({ hideWhenSingleBranch, ...rest }, ref) => {
|
878
|
+
return /* @__PURE__ */ React.createElement(MessageIf, { hasBranches: hideWhenSingleBranch ? true : void 0 }, /* @__PURE__ */ React.createElement(Primitive9.div, { ...rest, ref }));
|
759
879
|
});
|
760
880
|
|
761
881
|
// src/primitives/actionBar/index.ts
|
@@ -769,29 +889,31 @@ __export(actionBar_exports, {
|
|
769
889
|
|
770
890
|
// src/primitives/actionBar/ActionBarRoot.tsx
|
771
891
|
import {
|
772
|
-
Primitive as
|
892
|
+
Primitive as Primitive10
|
773
893
|
} from "@radix-ui/react-primitive";
|
774
|
-
import { forwardRef as
|
775
|
-
var ActionBarRoot =
|
894
|
+
import { forwardRef as forwardRef11 } from "react";
|
895
|
+
var ActionBarRoot = forwardRef11(({ hideWhenBusy, autohide, autohideFloat, ...rest }, ref) => {
|
776
896
|
const { useThread } = useAssistantContext();
|
777
897
|
const { useMessage } = useMessageContext();
|
778
|
-
const hideAndfloatStatus =
|
779
|
-
|
780
|
-
|
898
|
+
const hideAndfloatStatus = useCombinedStore(
|
899
|
+
[useThread, useMessage],
|
900
|
+
(t, m) => {
|
901
|
+
if (hideWhenBusy && t.isLoading)
|
902
|
+
return "hidden" /* Hidden */;
|
903
|
+
const autohideEnabled = autohide === "always" || autohide === "not-last" && !m.isLast;
|
904
|
+
if (!autohideEnabled)
|
905
|
+
return "normal" /* Normal */;
|
906
|
+
if (!m.isHovering)
|
907
|
+
return "hidden" /* Hidden */;
|
908
|
+
if (autohideFloat === "always" || autohideFloat === "single-branch" && m.branchState.branchCount <= 1)
|
909
|
+
return "floating" /* Floating */;
|
781
910
|
return "normal" /* Normal */;
|
782
|
-
|
783
|
-
|
784
|
-
if (autohideFloat === "always" || autohideFloat === "single-branch" && m.branchState.branchCount <= 1)
|
785
|
-
return "floating" /* Floating */;
|
786
|
-
return "normal" /* Normal */;
|
787
|
-
});
|
788
|
-
const busy = useThread((t) => t.isLoading);
|
789
|
-
if (hideWhenBusy && busy)
|
790
|
-
return null;
|
911
|
+
}
|
912
|
+
);
|
791
913
|
if (hideAndfloatStatus === "hidden" /* Hidden */)
|
792
914
|
return null;
|
793
915
|
return /* @__PURE__ */ React.createElement(
|
794
|
-
|
916
|
+
Primitive10.div,
|
795
917
|
{
|
796
918
|
"data-floating": hideAndfloatStatus === "floating" /* Floating */,
|
797
919
|
...rest,
|
@@ -823,9 +945,11 @@ var ActionBarCopy = createActionButton(useCopyMessage);
|
|
823
945
|
var useReloadMessage = () => {
|
824
946
|
const { useThread, useBranchObserver } = useAssistantContext();
|
825
947
|
const { useMessage } = useMessageContext();
|
826
|
-
const
|
827
|
-
|
828
|
-
|
948
|
+
const disabled = useCombinedStore(
|
949
|
+
[useThread, useMessage],
|
950
|
+
(t, m) => t.isLoading || m.message.role !== "assistant"
|
951
|
+
);
|
952
|
+
if (disabled)
|
829
953
|
return null;
|
830
954
|
return () => {
|
831
955
|
const message = useMessage.getState().message;
|
@@ -841,9 +965,11 @@ var ActionBarReload = createActionButton(useReloadMessage);
|
|
841
965
|
// src/actions/useBeginMessageEdit.tsx
|
842
966
|
var useBeginMessageEdit = () => {
|
843
967
|
const { useMessage, useComposer } = useMessageContext();
|
844
|
-
const
|
845
|
-
|
846
|
-
|
968
|
+
const disabled = useCombinedStore(
|
969
|
+
[useMessage, useComposer],
|
970
|
+
(m, c) => m.message.role !== "user" || c.isEditing
|
971
|
+
);
|
972
|
+
if (disabled)
|
847
973
|
return null;
|
848
974
|
return () => {
|
849
975
|
const { edit } = useComposer.getState();
|
@@ -855,25 +981,42 @@ var useBeginMessageEdit = () => {
|
|
855
981
|
var ActionBarEdit = createActionButton(useBeginMessageEdit);
|
856
982
|
|
857
983
|
// src/vercel/VercelAIAssistantProvider.tsx
|
858
|
-
import { useCallback as
|
984
|
+
import { useCallback as useCallback3, useMemo as useMemo4 } from "react";
|
985
|
+
|
986
|
+
// src/vercel/useDummyAIAssistantContext.tsx
|
987
|
+
import { useState as useState2 } from "react";
|
859
988
|
import { create as create2 } from "zustand";
|
860
|
-
var
|
861
|
-
const [context] =
|
989
|
+
var useDummyAIAssistantContext = () => {
|
990
|
+
const [context] = useState2(() => {
|
991
|
+
const scrollToBottomListeners = /* @__PURE__ */ new Set();
|
862
992
|
const useThread = create2()(() => ({
|
863
993
|
messages: [],
|
864
994
|
isLoading: false,
|
865
|
-
reload: async () => {
|
866
|
-
},
|
867
995
|
append: async () => {
|
996
|
+
throw new Error("Not implemented");
|
868
997
|
},
|
869
998
|
stop: () => {
|
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
|
+
};
|
870
1012
|
}
|
871
1013
|
}));
|
872
1014
|
const useComposer = create2()(() => ({
|
873
1015
|
isEditing: true,
|
874
1016
|
canCancel: false,
|
875
1017
|
value: "",
|
876
|
-
setValue: () => {
|
1018
|
+
setValue: (value) => {
|
1019
|
+
useComposer.setState({ value });
|
877
1020
|
},
|
878
1021
|
edit: () => {
|
879
1022
|
throw new Error("Not implemented");
|
@@ -892,19 +1035,24 @@ var useAIAssistantContext = () => {
|
|
892
1035
|
const useBranchObserver = create2()(() => ({
|
893
1036
|
getBranchState: () => ({
|
894
1037
|
branchId: 0,
|
895
|
-
branchCount:
|
1038
|
+
branchCount: 1
|
896
1039
|
}),
|
897
1040
|
switchToBranch: () => {
|
1041
|
+
throw new Error("Not implemented");
|
898
1042
|
},
|
899
1043
|
editAt: async () => {
|
1044
|
+
throw new Error("Not implemented");
|
900
1045
|
},
|
901
1046
|
reloadAt: async () => {
|
1047
|
+
throw new Error("Not implemented");
|
902
1048
|
}
|
903
1049
|
}));
|
904
1050
|
return { useThread, useComposer, useBranchObserver };
|
905
1051
|
});
|
906
1052
|
return context;
|
907
1053
|
};
|
1054
|
+
|
1055
|
+
// src/vercel/VercelAIAssistantProvider.tsx
|
908
1056
|
var ThreadMessageCache = /* @__PURE__ */ new WeakMap();
|
909
1057
|
var vercelToThreadMessage = (message) => {
|
910
1058
|
if (message.role !== "user" && message.role !== "assistant")
|
@@ -925,65 +1073,121 @@ var vercelToCachedThreadMessages = (messages) => {
|
|
925
1073
|
return newMessage;
|
926
1074
|
});
|
927
1075
|
};
|
928
|
-
var
|
929
|
-
|
1076
|
+
var VercelAIAssistantProvider = ({
|
1077
|
+
children,
|
1078
|
+
...rest
|
1079
|
+
}) => {
|
1080
|
+
const context = useDummyAIAssistantContext();
|
1081
|
+
const vercel = "chat" in rest ? rest.chat : rest.assistant;
|
930
1082
|
const messages = useMemo4(() => {
|
931
|
-
return vercelToCachedThreadMessages(
|
932
|
-
}, [
|
933
|
-
const
|
934
|
-
await chat.reload();
|
935
|
-
}, [chat.reload]);
|
936
|
-
const append = useCallback2(
|
1083
|
+
return vercelToCachedThreadMessages(vercel.messages);
|
1084
|
+
}, [vercel.messages]);
|
1085
|
+
const append = useCallback3(
|
937
1086
|
async (message) => {
|
938
1087
|
if (message.content[0]?.type !== "text") {
|
939
1088
|
throw new Error("Only text content is currently supported");
|
940
1089
|
}
|
941
|
-
|
1090
|
+
context.useThread.getState().scrollToBottom();
|
1091
|
+
await vercel.append({
|
942
1092
|
role: message.role,
|
943
1093
|
content: message.content[0].text
|
944
1094
|
});
|
945
1095
|
},
|
946
|
-
[
|
1096
|
+
[context, vercel.append]
|
947
1097
|
);
|
948
|
-
const stop =
|
949
|
-
const lastMessage =
|
950
|
-
|
1098
|
+
const stop = useCallback3(() => {
|
1099
|
+
const lastMessage = vercel.messages.at(-1);
|
1100
|
+
vercel.stop();
|
951
1101
|
if (lastMessage?.role === "user") {
|
952
|
-
|
1102
|
+
vercel.setInput(lastMessage.content);
|
953
1103
|
}
|
954
|
-
}, [
|
1104
|
+
}, [vercel.messages, vercel.stop, vercel.setInput]);
|
1105
|
+
const isLoading = "isLoading" in vercel ? vercel.isLoading : vercel.status === "in_progress";
|
955
1106
|
useMemo4(() => {
|
956
|
-
context.useThread.setState(
|
957
|
-
|
958
|
-
|
959
|
-
|
960
|
-
|
961
|
-
|
962
|
-
|
963
|
-
},
|
964
|
-
true
|
965
|
-
);
|
966
|
-
}, [context, messages, reload, append, stop, chat.isLoading]);
|
1107
|
+
context.useThread.setState({
|
1108
|
+
messages,
|
1109
|
+
isLoading,
|
1110
|
+
append,
|
1111
|
+
stop
|
1112
|
+
});
|
1113
|
+
}, [context, messages, append, stop, isLoading]);
|
967
1114
|
useMemo4(() => {
|
968
1115
|
context.useComposer.setState({
|
969
|
-
canCancel:
|
970
|
-
value:
|
971
|
-
setValue:
|
1116
|
+
canCancel: isLoading,
|
1117
|
+
value: vercel.input,
|
1118
|
+
setValue: vercel.setInput
|
972
1119
|
});
|
973
|
-
}, [context,
|
974
|
-
const branches = useVercelAIBranches(
|
1120
|
+
}, [context, isLoading, vercel.input, vercel.setInput]);
|
1121
|
+
const branches = useVercelAIBranches(vercel, context);
|
975
1122
|
useMemo4(() => {
|
976
1123
|
context.useBranchObserver.setState(branches, true);
|
977
1124
|
}, [context, branches]);
|
978
1125
|
return /* @__PURE__ */ React.createElement(AssistantContext.Provider, { value: context }, children);
|
979
1126
|
};
|
1127
|
+
|
1128
|
+
// src/vercel/VercelRSCAssistantProvider.tsx
|
1129
|
+
import {
|
1130
|
+
useCallback as useCallback4,
|
1131
|
+
useMemo as useMemo5
|
1132
|
+
} from "react";
|
1133
|
+
var ThreadMessageCache2 = /* @__PURE__ */ new WeakMap();
|
1134
|
+
var vercelToThreadMessage2 = (message) => {
|
1135
|
+
if (message.role !== "user" && message.role !== "assistant")
|
1136
|
+
throw new Error("Unsupported role");
|
1137
|
+
return {
|
1138
|
+
id: message.id,
|
1139
|
+
role: message.role,
|
1140
|
+
content: [{ type: "ui", display: message.display }]
|
1141
|
+
};
|
1142
|
+
};
|
1143
|
+
var vercelToCachedThreadMessages2 = (messages) => {
|
1144
|
+
return messages.map((m) => {
|
1145
|
+
const cached = ThreadMessageCache2.get(m);
|
1146
|
+
if (cached)
|
1147
|
+
return cached;
|
1148
|
+
const newMessage = vercelToThreadMessage2(m);
|
1149
|
+
ThreadMessageCache2.set(m, newMessage);
|
1150
|
+
return newMessage;
|
1151
|
+
});
|
1152
|
+
};
|
1153
|
+
var VercelRSCAssistantProvider = ({
|
1154
|
+
children,
|
1155
|
+
messages: vercelMessages,
|
1156
|
+
append: vercelAppend
|
1157
|
+
}) => {
|
1158
|
+
const context = useDummyAIAssistantContext();
|
1159
|
+
const messages = useMemo5(() => {
|
1160
|
+
return vercelToCachedThreadMessages2(vercelMessages);
|
1161
|
+
}, [vercelMessages]);
|
1162
|
+
const append = useCallback4(
|
1163
|
+
async (message) => {
|
1164
|
+
if (message.content[0]?.type !== "text") {
|
1165
|
+
throw new Error("Only text content is currently supported");
|
1166
|
+
}
|
1167
|
+
context.useThread.getState().scrollToBottom();
|
1168
|
+
await vercelAppend({
|
1169
|
+
role: message.role,
|
1170
|
+
content: [{ type: "text", text: message.content[0].text }]
|
1171
|
+
});
|
1172
|
+
},
|
1173
|
+
[context, vercelAppend]
|
1174
|
+
);
|
1175
|
+
useMemo5(() => {
|
1176
|
+
context.useThread.setState({
|
1177
|
+
messages,
|
1178
|
+
append
|
1179
|
+
});
|
1180
|
+
}, [context, messages, append]);
|
1181
|
+
return /* @__PURE__ */ React.createElement(AssistantContext.Provider, { value: context }, children);
|
1182
|
+
};
|
980
1183
|
export {
|
981
1184
|
actionBar_exports as ActionBarPrimitive,
|
982
1185
|
branchPicker_exports as BranchPickerPrimitive,
|
983
1186
|
composer_exports as ComposerPrimitive,
|
984
1187
|
message_exports as MessagePrimitive,
|
985
1188
|
thread_exports as ThreadPrimitive,
|
986
|
-
|
1189
|
+
VercelAIAssistantProvider,
|
1190
|
+
VercelRSCAssistantProvider as unstable_VercelRSCAssistantProvider,
|
987
1191
|
useMessageContext as unstable_useMessageContext,
|
988
1192
|
useBeginMessageEdit,
|
989
1193
|
useCopyMessage,
|