@assistant-ui/react 0.0.16 → 0.0.18
Sign up to get free protection for your applications and to get access to all the features.
- package/dist/index.d.mts +78 -9
- package/dist/index.d.ts +78 -9
- package/dist/index.js +403 -123
- package/dist/index.mjs +411 -136
- package/package.json +2 -1
package/dist/index.mjs
CHANGED
@@ -68,18 +68,18 @@ import { useComposedRefs } from "@radix-ui/react-compose-refs";
|
|
68
68
|
import {
|
69
69
|
Primitive as Primitive2
|
70
70
|
} from "@radix-ui/react-primitive";
|
71
|
-
import { forwardRef as forwardRef2, useRef
|
71
|
+
import { forwardRef as forwardRef2, useRef } from "react";
|
72
72
|
|
73
73
|
// src/utils/hooks/useOnResizeContent.tsx
|
74
|
-
import {
|
74
|
+
import { useCallbackRef } from "@radix-ui/react-use-callback-ref";
|
75
|
+
import { useEffect } from "react";
|
75
76
|
var useOnResizeContent = (ref, callback) => {
|
76
|
-
const callbackRef =
|
77
|
-
callbackRef.current = callback;
|
77
|
+
const callbackRef = useCallbackRef(callback);
|
78
78
|
useEffect(() => {
|
79
79
|
const el = ref.current;
|
80
80
|
if (!el) return;
|
81
81
|
const resizeObserver = new ResizeObserver(() => {
|
82
|
-
callbackRef
|
82
|
+
callbackRef();
|
83
83
|
});
|
84
84
|
const mutationObserver = new MutationObserver((mutations) => {
|
85
85
|
for (const mutation of mutations) {
|
@@ -94,7 +94,7 @@ var useOnResizeContent = (ref, callback) => {
|
|
94
94
|
}
|
95
95
|
}
|
96
96
|
}
|
97
|
-
callbackRef
|
97
|
+
callbackRef();
|
98
98
|
});
|
99
99
|
resizeObserver.observe(el);
|
100
100
|
mutationObserver.observe(el, { childList: true });
|
@@ -105,31 +105,31 @@ var useOnResizeContent = (ref, callback) => {
|
|
105
105
|
resizeObserver.disconnect();
|
106
106
|
mutationObserver.disconnect();
|
107
107
|
};
|
108
|
-
}, [ref.current]);
|
108
|
+
}, [ref.current, callbackRef]);
|
109
109
|
};
|
110
110
|
|
111
111
|
// src/utils/hooks/useOnScrollToBottom.tsx
|
112
|
-
import {
|
112
|
+
import { useCallbackRef as useCallbackRef2 } from "@radix-ui/react-use-callback-ref";
|
113
|
+
import { useEffect as useEffect2 } from "react";
|
113
114
|
var useOnScrollToBottom = (callback) => {
|
114
|
-
const callbackRef =
|
115
|
-
callbackRef.current = callback;
|
115
|
+
const callbackRef = useCallbackRef2(callback);
|
116
116
|
const { useViewport } = useAssistantContext();
|
117
117
|
useEffect2(() => {
|
118
118
|
return useViewport.getState().onScrollToBottom(() => {
|
119
|
-
callbackRef
|
119
|
+
callbackRef();
|
120
120
|
});
|
121
|
-
}, [useViewport]);
|
121
|
+
}, [useViewport, callbackRef]);
|
122
122
|
};
|
123
123
|
|
124
124
|
// src/primitives/thread/ThreadViewport.tsx
|
125
125
|
import { jsx as jsx3, jsxs } from "react/jsx-runtime";
|
126
126
|
var ThreadViewport = forwardRef2(({ autoScroll = true, onScroll, children, ...rest }, forwardedRef) => {
|
127
|
-
const messagesEndRef =
|
128
|
-
const divRef =
|
127
|
+
const messagesEndRef = useRef(null);
|
128
|
+
const divRef = useRef(null);
|
129
129
|
const ref = useComposedRefs(forwardedRef, divRef);
|
130
130
|
const { useViewport } = useAssistantContext();
|
131
|
-
const firstRenderRef =
|
132
|
-
const lastScrollTop =
|
131
|
+
const firstRenderRef = useRef(true);
|
132
|
+
const lastScrollTop = useRef(0);
|
133
133
|
const scrollToBottom = () => {
|
134
134
|
const div = messagesEndRef.current;
|
135
135
|
if (!div || !autoScroll) return;
|
@@ -214,7 +214,7 @@ var message_exports = {};
|
|
214
214
|
__export(message_exports, {
|
215
215
|
Content: () => MessageContent,
|
216
216
|
If: () => MessageIf,
|
217
|
-
|
217
|
+
InProgress: () => MessageInProgress,
|
218
218
|
Provider: () => MessageProvider,
|
219
219
|
Root: () => MessageRoot
|
220
220
|
});
|
@@ -296,11 +296,11 @@ var useMessageContext2 = () => {
|
|
296
296
|
parentId: null,
|
297
297
|
branches: [],
|
298
298
|
isLast: false,
|
299
|
-
|
299
|
+
inProgressIndicator: null,
|
300
300
|
isCopied: false,
|
301
301
|
isHovering: false,
|
302
|
-
|
303
|
-
set({
|
302
|
+
setInProgressIndicator: (value) => {
|
303
|
+
set({ inProgressIndicator: value });
|
304
304
|
},
|
305
305
|
setIsCopied: (value) => {
|
306
306
|
set({ isCopied: value });
|
@@ -443,15 +443,15 @@ var useContentPartContext = () => {
|
|
443
443
|
return context;
|
444
444
|
};
|
445
445
|
|
446
|
-
// src/primitives/contentPart/
|
447
|
-
var
|
446
|
+
// src/primitives/contentPart/ContentPartInProgressIndicator.tsx
|
447
|
+
var ContentPartInProgressIndicator = () => {
|
448
448
|
const { useMessage } = useMessageContext();
|
449
449
|
const { useContentPart } = useContentPartContext();
|
450
|
-
const
|
450
|
+
const indicator = useCombinedStore(
|
451
451
|
[useMessage, useContentPart],
|
452
|
-
(m, c) => c.
|
452
|
+
(m, c) => c.status === "in_progress" ? m.inProgressIndicator : null
|
453
453
|
);
|
454
|
-
return
|
454
|
+
return indicator;
|
455
455
|
};
|
456
456
|
|
457
457
|
// src/primitives/contentPart/ContentPartProvider.tsx
|
@@ -462,7 +462,7 @@ var useContentPartContext2 = () => {
|
|
462
462
|
const [context] = useState2(() => {
|
463
463
|
const useContentPart = create3(() => ({
|
464
464
|
part: null,
|
465
|
-
|
465
|
+
status: "done"
|
466
466
|
}));
|
467
467
|
return { useContentPart };
|
468
468
|
});
|
@@ -470,7 +470,7 @@ var useContentPartContext2 = () => {
|
|
470
470
|
};
|
471
471
|
var ContentPartProvider = ({
|
472
472
|
part,
|
473
|
-
|
473
|
+
status,
|
474
474
|
children
|
475
475
|
}) => {
|
476
476
|
const context = useContentPartContext2();
|
@@ -478,11 +478,11 @@ var ContentPartProvider = ({
|
|
478
478
|
context.useContentPart.setState(
|
479
479
|
{
|
480
480
|
part,
|
481
|
-
|
481
|
+
status
|
482
482
|
},
|
483
483
|
true
|
484
484
|
);
|
485
|
-
}, [context, part,
|
485
|
+
}, [context, part, status]);
|
486
486
|
return /* @__PURE__ */ jsx6(ContentPartContext.Provider, { value: context, children });
|
487
487
|
};
|
488
488
|
|
@@ -491,7 +491,7 @@ import { Fragment, jsx as jsx7, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
491
491
|
var defaultComponents = {
|
492
492
|
Text: ({ part }) => /* @__PURE__ */ jsxs2(Fragment, { children: [
|
493
493
|
part.text,
|
494
|
-
/* @__PURE__ */ jsx7(
|
494
|
+
/* @__PURE__ */ jsx7(ContentPartInProgressIndicator, {})
|
495
495
|
] }),
|
496
496
|
Image: () => null,
|
497
497
|
UI: ({ part }) => part.display,
|
@@ -507,13 +507,10 @@ var MessageContent = ({
|
|
507
507
|
tools: { by_name = {}, Fallback = defaultComponents.tools.Fallback } = {}
|
508
508
|
} = {}
|
509
509
|
}) => {
|
510
|
-
const { useThread } = useAssistantContext();
|
511
510
|
const { useMessage } = useMessageContext();
|
512
|
-
const
|
513
|
-
const
|
514
|
-
|
515
|
-
(t, s) => s.isLast && t.isRunning
|
516
|
-
);
|
511
|
+
const message = useMessage((s) => s.message);
|
512
|
+
const content = message.content;
|
513
|
+
const status = message.role === "assistant" ? message.status : "done";
|
517
514
|
return /* @__PURE__ */ jsx7(Fragment, { children: content.map((part, i) => {
|
518
515
|
const key = i;
|
519
516
|
const type = part.type;
|
@@ -540,7 +537,7 @@ var MessageContent = ({
|
|
540
537
|
ContentPartProvider,
|
541
538
|
{
|
542
539
|
part,
|
543
|
-
|
540
|
+
status: i === content.length - 1 ? status : "done",
|
544
541
|
children: component
|
545
542
|
},
|
546
543
|
key
|
@@ -548,16 +545,16 @@ var MessageContent = ({
|
|
548
545
|
}) });
|
549
546
|
};
|
550
547
|
|
551
|
-
// src/primitives/message/
|
548
|
+
// src/primitives/message/MessageInProgress.tsx
|
552
549
|
import {
|
553
550
|
Primitive as Primitive4
|
554
551
|
} from "@radix-ui/react-primitive";
|
555
552
|
import { forwardRef as forwardRef4, useMemo as useMemo4 } from "react";
|
556
553
|
import { jsx as jsx8 } from "react/jsx-runtime";
|
557
|
-
var
|
554
|
+
var MessageInProgress = forwardRef4((props, ref) => {
|
558
555
|
const { useMessage } = useMessageContext();
|
559
556
|
useMemo4(() => {
|
560
|
-
useMessage.getState().
|
557
|
+
useMessage.getState().setInProgressIndicator(/* @__PURE__ */ jsx8(Primitive4.div, { ...props, ref }));
|
561
558
|
}, [useMessage, props, ref]);
|
562
559
|
return null;
|
563
560
|
});
|
@@ -666,13 +663,13 @@ import { useComposedRefs as useComposedRefs2 } from "@radix-ui/react-compose-ref
|
|
666
663
|
import {
|
667
664
|
Primitive as Primitive7
|
668
665
|
} from "@radix-ui/react-primitive";
|
669
|
-
import { forwardRef as forwardRef7, useRef as
|
666
|
+
import { forwardRef as forwardRef7, useRef as useRef2 } from "react";
|
670
667
|
import { jsx as jsx12 } from "react/jsx-runtime";
|
671
668
|
var ComposerRoot = forwardRef7(
|
672
669
|
({ onSubmit, ...rest }, forwardedRef) => {
|
673
670
|
const { useViewport } = useAssistantContext();
|
674
671
|
const { useComposer } = useComposerContext();
|
675
|
-
const formRef =
|
672
|
+
const formRef = useRef2(null);
|
676
673
|
const ref = useComposedRefs2(forwardedRef, formRef);
|
677
674
|
const handleSubmit = (e) => {
|
678
675
|
const composerState = useComposer.getState();
|
@@ -700,7 +697,7 @@ import {
|
|
700
697
|
forwardRef as forwardRef8,
|
701
698
|
useCallback,
|
702
699
|
useEffect as useEffect3,
|
703
|
-
useRef as
|
700
|
+
useRef as useRef3
|
704
701
|
} from "react";
|
705
702
|
import TextareaAutosize from "react-textarea-autosize";
|
706
703
|
import { jsx as jsx13 } from "react/jsx-runtime";
|
@@ -729,7 +726,7 @@ var ComposerInput = forwardRef8(
|
|
729
726
|
}
|
730
727
|
}
|
731
728
|
};
|
732
|
-
const textareaRef =
|
729
|
+
const textareaRef = useRef3(null);
|
733
730
|
const ref = useComposedRefs3(forwardedRef, textareaRef);
|
734
731
|
const autoFocusEnabled = autoFocus && !disabled;
|
735
732
|
const focus = useCallback(() => {
|
@@ -876,7 +873,6 @@ var useGoToPreviousBranch = () => {
|
|
876
873
|
const { message, branches } = useMessage.getState();
|
877
874
|
useThread.getState().switchToBranch(
|
878
875
|
branches[branches.indexOf(message.id) - 1]
|
879
|
-
// TODO probably there's a more elegant way to do this
|
880
876
|
);
|
881
877
|
};
|
882
878
|
};
|
@@ -1013,7 +1009,7 @@ var ActionBarEdit = createActionButton(useBeginMessageEdit);
|
|
1013
1009
|
// src/primitives/contentPart/index.ts
|
1014
1010
|
var contentPart_exports = {};
|
1015
1011
|
__export(contentPart_exports, {
|
1016
|
-
|
1012
|
+
InProgressIndicator: () => ContentPartInProgressIndicator,
|
1017
1013
|
Provider: () => ContentPartProvider
|
1018
1014
|
});
|
1019
1015
|
|
@@ -1077,9 +1073,10 @@ var useDummyAIAssistantContext = () => {
|
|
1077
1073
|
};
|
1078
1074
|
|
1079
1075
|
// src/adapters/vercel/useVercelAIThreadState.tsx
|
1080
|
-
import {
|
1076
|
+
import { useCallbackRef as useCallbackRef3 } from "@radix-ui/react-use-callback-ref";
|
1077
|
+
import { useCallback as useCallback2, useMemo as useMemo5, useRef as useRef4, useState as useState4 } from "react";
|
1081
1078
|
|
1082
|
-
// src/adapters/
|
1079
|
+
// src/adapters/idUtils.tsx
|
1083
1080
|
import { customAlphabet } from "nanoid/non-secure";
|
1084
1081
|
var generateId = customAlphabet(
|
1085
1082
|
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
|
@@ -1087,7 +1084,8 @@ var generateId = customAlphabet(
|
|
1087
1084
|
);
|
1088
1085
|
var optimisticPrefix = "__optimistic__";
|
1089
1086
|
var generateOptimisticId = () => `${optimisticPrefix}${generateId()}`;
|
1090
|
-
|
1087
|
+
|
1088
|
+
// src/adapters/MessageRepository.tsx
|
1091
1089
|
var findHead = (message) => {
|
1092
1090
|
if (message.next) return findHead(message.next);
|
1093
1091
|
return message;
|
@@ -1099,15 +1097,6 @@ var MessageRepository = class {
|
|
1099
1097
|
root = {
|
1100
1098
|
children: []
|
1101
1099
|
};
|
1102
|
-
getFallbackChild(p) {
|
1103
|
-
const childId = p.children.at(-1);
|
1104
|
-
const child = childId ? this.messages.get(childId) : null;
|
1105
|
-
if (child === void 0)
|
1106
|
-
throw new Error(
|
1107
|
-
"MessageRepository(getFallbackChild): Child message not found. This is likely an internal bug in assistant-ui."
|
1108
|
-
);
|
1109
|
-
return child;
|
1110
|
-
}
|
1111
1100
|
performOp(newParent, child, operation) {
|
1112
1101
|
const parentOrRoot = child.prev ?? this.root;
|
1113
1102
|
const newParentOrRoot = newParent ?? this.root;
|
@@ -1117,7 +1106,14 @@ var MessageRepository = class {
|
|
1117
1106
|
(m) => m !== child.current.id
|
1118
1107
|
);
|
1119
1108
|
if (child.prev?.next === child) {
|
1120
|
-
child.prev.
|
1109
|
+
const fallbackId = child.prev.children.at(-1);
|
1110
|
+
const fallback = fallbackId ? this.messages.get(fallbackId) : null;
|
1111
|
+
if (fallback === void 0) {
|
1112
|
+
throw new Error(
|
1113
|
+
"MessageRepository(performOp/cut): Fallback sibling message not found. This is likely an internal bug in assistant-ui."
|
1114
|
+
);
|
1115
|
+
}
|
1116
|
+
child.prev.next = fallback;
|
1121
1117
|
}
|
1122
1118
|
}
|
1123
1119
|
if (operation !== "cut") {
|
@@ -1171,18 +1167,19 @@ var MessageRepository = class {
|
|
1171
1167
|
this.addOrUpdateMessage(parentId, {
|
1172
1168
|
...message,
|
1173
1169
|
id: optimisticId,
|
1174
|
-
createdAt: /* @__PURE__ */ new Date()
|
1170
|
+
createdAt: /* @__PURE__ */ new Date(),
|
1171
|
+
...message.role === "assistant" ? { status: "in_progress" } : void 0
|
1175
1172
|
});
|
1176
1173
|
return optimisticId;
|
1177
1174
|
}
|
1178
|
-
deleteMessage(messageId,
|
1175
|
+
deleteMessage(messageId, replacementId) {
|
1179
1176
|
const message = this.messages.get(messageId);
|
1180
|
-
const
|
1177
|
+
const replacement = replacementId ? this.messages.get(replacementId) : null;
|
1181
1178
|
if (!message)
|
1182
1179
|
throw new Error(
|
1183
1180
|
"MessageRepository(deleteMessage): Optimistic message not found. This is likely an internal bug in assistant-ui."
|
1184
1181
|
);
|
1185
|
-
if (
|
1182
|
+
if (replacement === void 0)
|
1186
1183
|
throw new Error(
|
1187
1184
|
"MessageRepository(deleteMessage): New message not found. This is likely an internal bug in assistant-ui."
|
1188
1185
|
);
|
@@ -1192,11 +1189,11 @@ var MessageRepository = class {
|
|
1192
1189
|
throw new Error(
|
1193
1190
|
"MessageRepository(deleteMessage): Child message not found. This is likely an internal bug in assistant-ui."
|
1194
1191
|
);
|
1195
|
-
this.performOp(
|
1192
|
+
this.performOp(replacement, childMessage, "relink");
|
1196
1193
|
}
|
1197
1194
|
this.messages.delete(messageId);
|
1198
1195
|
if (this.head === message) {
|
1199
|
-
this.head =
|
1196
|
+
this.head = replacement;
|
1200
1197
|
}
|
1201
1198
|
this.performOp(null, message, "cut");
|
1202
1199
|
}
|
@@ -1239,50 +1236,68 @@ var MessageRepository = class {
|
|
1239
1236
|
}
|
1240
1237
|
};
|
1241
1238
|
|
1242
|
-
// src/adapters/ThreadMessageConverter.
|
1239
|
+
// src/adapters/ThreadMessageConverter.ts
|
1243
1240
|
var ThreadMessageConverter = class {
|
1244
|
-
constructor(converter2) {
|
1245
|
-
this.converter = converter2;
|
1246
|
-
}
|
1247
1241
|
cache = /* @__PURE__ */ new WeakMap();
|
1248
|
-
convertMessages(messages) {
|
1242
|
+
convertMessages(converter, messages) {
|
1249
1243
|
return messages.map((m) => {
|
1250
1244
|
const cached = this.cache.get(m);
|
1251
|
-
|
1252
|
-
const newMessage = this.converter(m);
|
1245
|
+
const newMessage = converter(m, cached);
|
1253
1246
|
this.cache.set(m, newMessage);
|
1254
1247
|
return newMessage;
|
1255
1248
|
});
|
1256
1249
|
}
|
1257
1250
|
};
|
1258
1251
|
|
1252
|
+
// src/adapters/vercel/VercelThreadMessage.tsx
|
1253
|
+
var symbolInnerMessage = Symbol("innerMessage");
|
1254
|
+
var symbolInnerRSCMessage = Symbol("innerRSCMessage");
|
1255
|
+
var getVercelMessage = (message) => {
|
1256
|
+
return message[symbolInnerMessage];
|
1257
|
+
};
|
1258
|
+
var getVercelRSCMessage = (message) => {
|
1259
|
+
return message[symbolInnerRSCMessage];
|
1260
|
+
};
|
1261
|
+
|
1259
1262
|
// src/adapters/vercel/useVercelAIThreadState.tsx
|
1260
|
-
var vercelToThreadMessage = (message) => {
|
1261
|
-
|
1262
|
-
throw new Error(
|
1263
|
-
`You have a message with an unsupported role. The role ${message.role} is not supported.`
|
1264
|
-
);
|
1265
|
-
return {
|
1263
|
+
var vercelToThreadMessage = (message, status) => {
|
1264
|
+
const common = {
|
1266
1265
|
id: message.id,
|
1267
|
-
role: message.role,
|
1268
|
-
content: [
|
1269
|
-
...message.content ? [{ type: "text", text: message.content }] : [],
|
1270
|
-
...message.toolInvocations?.map((t) => ({
|
1271
|
-
type: "tool-call",
|
1272
|
-
name: t.toolName,
|
1273
|
-
args: t.args,
|
1274
|
-
result: "result" in t ? t.result : void 0
|
1275
|
-
})) ?? []
|
1276
|
-
],
|
1277
|
-
// ignore type mismatch for now
|
1278
1266
|
createdAt: message.createdAt ?? /* @__PURE__ */ new Date(),
|
1279
|
-
|
1267
|
+
[symbolInnerMessage]: message
|
1280
1268
|
};
|
1269
|
+
switch (message.role) {
|
1270
|
+
case "user":
|
1271
|
+
return {
|
1272
|
+
...common,
|
1273
|
+
role: "user",
|
1274
|
+
content: [{ type: "text", text: message.content }]
|
1275
|
+
};
|
1276
|
+
case "assistant":
|
1277
|
+
return {
|
1278
|
+
...common,
|
1279
|
+
role: "assistant",
|
1280
|
+
content: [
|
1281
|
+
...message.content ? [{ type: "text", text: message.content }] : [],
|
1282
|
+
...message.toolInvocations?.map(
|
1283
|
+
(t) => ({
|
1284
|
+
type: "tool-call",
|
1285
|
+
name: t.toolName,
|
1286
|
+
args: t.args,
|
1287
|
+
result: "result" in t ? t.result : void 0
|
1288
|
+
})
|
1289
|
+
) ?? []
|
1290
|
+
],
|
1291
|
+
status
|
1292
|
+
};
|
1293
|
+
default:
|
1294
|
+
throw new Error(
|
1295
|
+
`You have a message with an unsupported role. The role ${message.role} is not supported.`
|
1296
|
+
);
|
1297
|
+
}
|
1281
1298
|
};
|
1282
|
-
var converter = new ThreadMessageConverter(vercelToThreadMessage);
|
1283
1299
|
var sliceMessagesUntil = (messages, messageId) => {
|
1284
1300
|
if (messageId == null) return [];
|
1285
|
-
if (isOptimisticId(messageId)) return messages;
|
1286
1301
|
const messageIdx = messages.findIndex((m) => m.id === messageId);
|
1287
1302
|
if (messageIdx === -1)
|
1288
1303
|
throw new Error(
|
@@ -1299,12 +1314,18 @@ var getIsRunning = (vercel) => {
|
|
1299
1314
|
};
|
1300
1315
|
var useVercelAIThreadState = (vercel) => {
|
1301
1316
|
const [data] = useState4(() => new MessageRepository());
|
1302
|
-
const
|
1303
|
-
|
1304
|
-
const
|
1305
|
-
const assistantOptimisticIdRef = useRef6(null);
|
1317
|
+
const isRunning = getIsRunning(vercel);
|
1318
|
+
const converter = useMemo5(() => new ThreadMessageConverter(), []);
|
1319
|
+
const assistantOptimisticIdRef = useRef4(null);
|
1306
1320
|
const messages = useMemo5(() => {
|
1307
|
-
const
|
1321
|
+
const lastMessageId = vercel.messages.at(-1)?.id;
|
1322
|
+
const convertCallback = (message, cache) => {
|
1323
|
+
const status = lastMessageId === message.id && isRunning ? "in_progress" : "done";
|
1324
|
+
if (cache && (cache.role === "user" || cache.status === status))
|
1325
|
+
return cache;
|
1326
|
+
return vercelToThreadMessage(message, status);
|
1327
|
+
};
|
1328
|
+
const vm = converter.convertMessages(convertCallback, vercel.messages);
|
1308
1329
|
for (let i = 0; i < vm.length; i++) {
|
1309
1330
|
const message = vm[i];
|
1310
1331
|
const parent = vm[i - 1];
|
@@ -1325,55 +1346,46 @@ var useVercelAIThreadState = (vercel) => {
|
|
1325
1346
|
}
|
1326
1347
|
data.resetHead(assistantOptimisticIdRef.current ?? vm.at(-1)?.id ?? null);
|
1327
1348
|
return data.getMessages();
|
1328
|
-
}, [data, isRunning, vercel.messages]);
|
1349
|
+
}, [converter, data, isRunning, vercel.messages]);
|
1329
1350
|
const getBranches2 = useCallback2(
|
1330
1351
|
(messageId) => {
|
1331
1352
|
return data.getBranches(messageId);
|
1332
1353
|
},
|
1333
1354
|
[data]
|
1334
1355
|
);
|
1335
|
-
const switchToBranch2 =
|
1336
|
-
(messageId)
|
1337
|
-
|
1338
|
-
|
1339
|
-
|
1340
|
-
|
1341
|
-
|
1342
|
-
|
1343
|
-
);
|
1344
|
-
const startRun = useCallback2(async (parentId) => {
|
1345
|
-
const reloadMaybe = "reload" in vercelRef.current ? vercelRef.current.reload : void 0;
|
1356
|
+
const switchToBranch2 = useCallbackRef3((messageId) => {
|
1357
|
+
data.switchToBranch(messageId);
|
1358
|
+
vercel.setMessages(
|
1359
|
+
data.getMessages().map(getVercelMessage).filter((m) => m != null)
|
1360
|
+
);
|
1361
|
+
});
|
1362
|
+
const startRun = useCallbackRef3(async (parentId) => {
|
1363
|
+
const reloadMaybe = "reload" in vercel ? vercel.reload : void 0;
|
1346
1364
|
if (!reloadMaybe)
|
1347
1365
|
throw new Error(
|
1348
1366
|
"Reload is not supported by Vercel AI SDK's useAssistant."
|
1349
1367
|
);
|
1350
|
-
const newMessages = sliceMessagesUntil(
|
1351
|
-
|
1352
|
-
parentId
|
1353
|
-
);
|
1354
|
-
vercelRef.current.setMessages(newMessages);
|
1368
|
+
const newMessages = sliceMessagesUntil(vercel.messages, parentId);
|
1369
|
+
vercel.setMessages(newMessages);
|
1355
1370
|
await reloadMaybe();
|
1356
|
-
}
|
1357
|
-
const append =
|
1371
|
+
});
|
1372
|
+
const append = useCallbackRef3(async (message) => {
|
1358
1373
|
if (message.content.length !== 1 || message.content[0]?.type !== "text")
|
1359
1374
|
throw new Error("Only text content is supported by Vercel AI SDK.");
|
1360
|
-
const newMessages = sliceMessagesUntil(
|
1361
|
-
|
1362
|
-
|
1363
|
-
);
|
1364
|
-
vercelRef.current.setMessages(newMessages);
|
1365
|
-
await vercelRef.current.append({
|
1375
|
+
const newMessages = sliceMessagesUntil(vercel.messages, message.parentId);
|
1376
|
+
vercel.setMessages(newMessages);
|
1377
|
+
await vercel.append({
|
1366
1378
|
role: "user",
|
1367
1379
|
content: message.content[0].text
|
1368
1380
|
});
|
1369
|
-
}
|
1370
|
-
const cancelRun2 =
|
1371
|
-
const lastMessage =
|
1372
|
-
|
1381
|
+
});
|
1382
|
+
const cancelRun2 = useCallbackRef3(() => {
|
1383
|
+
const lastMessage = vercel.messages.at(-1);
|
1384
|
+
vercel.stop();
|
1373
1385
|
if (lastMessage?.role === "user") {
|
1374
|
-
|
1386
|
+
vercel.setInput(lastMessage.content);
|
1375
1387
|
}
|
1376
|
-
}
|
1388
|
+
});
|
1377
1389
|
return useMemo5(
|
1378
1390
|
() => ({
|
1379
1391
|
isRunning,
|
@@ -1424,12 +1436,15 @@ import {
|
|
1424
1436
|
useState as useState5
|
1425
1437
|
} from "react";
|
1426
1438
|
import { jsx as jsx22 } from "react/jsx-runtime";
|
1427
|
-
var vercelToThreadMessage2 = (
|
1439
|
+
var vercelToThreadMessage2 = (converter, rawMessage) => {
|
1440
|
+
const message = converter(rawMessage);
|
1428
1441
|
return {
|
1429
1442
|
id: message.id,
|
1430
1443
|
role: message.role,
|
1431
1444
|
content: [{ type: "ui", display: message.display }],
|
1432
|
-
createdAt: message.createdAt ?? /* @__PURE__ */ new Date()
|
1445
|
+
createdAt: message.createdAt ?? /* @__PURE__ */ new Date(),
|
1446
|
+
...{ status: "done" },
|
1447
|
+
[symbolInnerRSCMessage]: rawMessage
|
1433
1448
|
};
|
1434
1449
|
};
|
1435
1450
|
var EMPTY_BRANCHES = [];
|
@@ -1462,15 +1477,17 @@ var VercelRSCAssistantProvider = ({
|
|
1462
1477
|
setIsRunning(true);
|
1463
1478
|
return callback.finally(() => setIsRunning(false));
|
1464
1479
|
}, []);
|
1465
|
-
const
|
1480
|
+
const [converter, convertCallback] = useMemo7(() => {
|
1466
1481
|
const rscConverter = convertMessage ?? ((m) => m);
|
1467
|
-
|
1468
|
-
|
1469
|
-
|
1482
|
+
const convertCallback2 = (m, cache) => {
|
1483
|
+
if (cache) return cache;
|
1484
|
+
return vercelToThreadMessage2(rscConverter, m);
|
1485
|
+
};
|
1486
|
+
return [new ThreadMessageConverter(), convertCallback2];
|
1470
1487
|
}, [convertMessage]);
|
1471
1488
|
const messages = useMemo7(() => {
|
1472
|
-
return
|
1473
|
-
}, [
|
1489
|
+
return converter.convertMessages(convertCallback, vercelMessages);
|
1490
|
+
}, [converter, convertCallback, vercelMessages]);
|
1474
1491
|
const append = useCallback3(
|
1475
1492
|
async (message) => {
|
1476
1493
|
if (message.parentId !== (context.useThread.getState().messages.at(-1)?.id ?? null)) {
|
@@ -1511,6 +1528,259 @@ var VercelRSCAssistantProvider = ({
|
|
1511
1528
|
}, [context, messages, isRunning, append, startRun]);
|
1512
1529
|
return /* @__PURE__ */ jsx22(AssistantContext.Provider, { value: context, children });
|
1513
1530
|
};
|
1531
|
+
|
1532
|
+
// src/adapters/core/utils/useAssistantContext.tsx
|
1533
|
+
import { useEffect as useEffect4, useRef as useRef5, useState as useState6 } from "react";
|
1534
|
+
import { create as create6 } from "zustand";
|
1535
|
+
|
1536
|
+
// src/adapters/core/utils/AssistantMessageRepository.tsx
|
1537
|
+
var AssistantMessageRepository = class {
|
1538
|
+
constructor(flushCallback) {
|
1539
|
+
this.flushCallback = flushCallback;
|
1540
|
+
}
|
1541
|
+
repository = new MessageRepository();
|
1542
|
+
getBranches(messageId) {
|
1543
|
+
return this.repository.getBranches(messageId);
|
1544
|
+
}
|
1545
|
+
withModifications(callback) {
|
1546
|
+
const res = callback(this.repository);
|
1547
|
+
this.flushCallback(this.repository.getMessages());
|
1548
|
+
return res;
|
1549
|
+
}
|
1550
|
+
};
|
1551
|
+
|
1552
|
+
// src/adapters/core/utils/useAssistantContext.tsx
|
1553
|
+
var makeThreadStore = (runtimeRef) => {
|
1554
|
+
const repository = new AssistantMessageRepository((messages) => {
|
1555
|
+
useThread.setState({ messages });
|
1556
|
+
});
|
1557
|
+
const useThread = create6(() => ({
|
1558
|
+
messages: [],
|
1559
|
+
isRunning: false,
|
1560
|
+
getBranches: (messageId) => repository.getBranches(messageId),
|
1561
|
+
switchToBranch: (branchId) => {
|
1562
|
+
repository.withModifications((repository2) => {
|
1563
|
+
repository2.switchToBranch(branchId);
|
1564
|
+
});
|
1565
|
+
},
|
1566
|
+
startRun: async (parentId) => {
|
1567
|
+
const optimisticId = repository.withModifications((repository2) => {
|
1568
|
+
const optimisticId2 = repository2.appendOptimisticMessage(parentId, {
|
1569
|
+
role: "assistant",
|
1570
|
+
content: [{ type: "text", text: "" }]
|
1571
|
+
});
|
1572
|
+
repository2.resetHead(optimisticId2);
|
1573
|
+
return optimisticId2;
|
1574
|
+
});
|
1575
|
+
const { id } = await runtimeRef.current.startRun(parentId);
|
1576
|
+
repository.withModifications((repository2) => {
|
1577
|
+
repository2.deleteMessage(optimisticId, id);
|
1578
|
+
});
|
1579
|
+
},
|
1580
|
+
append: async (message) => {
|
1581
|
+
const [parentOptimisticId, optimisticId] = repository.withModifications(
|
1582
|
+
(repository2) => {
|
1583
|
+
const parentOptimisticId2 = repository2.appendOptimisticMessage(
|
1584
|
+
message.parentId,
|
1585
|
+
{
|
1586
|
+
role: "user",
|
1587
|
+
content: message.content
|
1588
|
+
}
|
1589
|
+
);
|
1590
|
+
const optimisticId2 = repository2.appendOptimisticMessage(
|
1591
|
+
parentOptimisticId2,
|
1592
|
+
{
|
1593
|
+
role: "assistant",
|
1594
|
+
content: [{ type: "text", text: "" }]
|
1595
|
+
}
|
1596
|
+
);
|
1597
|
+
repository2.resetHead(optimisticId2);
|
1598
|
+
return [parentOptimisticId2, optimisticId2];
|
1599
|
+
}
|
1600
|
+
);
|
1601
|
+
const { parentId, id } = await runtimeRef.current.append(message);
|
1602
|
+
repository.withModifications((repository2) => {
|
1603
|
+
repository2.deleteMessage(parentOptimisticId, parentId);
|
1604
|
+
repository2.deleteMessage(optimisticId, id);
|
1605
|
+
});
|
1606
|
+
},
|
1607
|
+
cancelRun: () => runtimeRef.current.cancelRun()
|
1608
|
+
}));
|
1609
|
+
const onNewMessage = (parentId, message) => {
|
1610
|
+
repository.withModifications((repository2) => {
|
1611
|
+
repository2.addOrUpdateMessage(parentId, message);
|
1612
|
+
});
|
1613
|
+
};
|
1614
|
+
const onRunningChange = (isRunning) => {
|
1615
|
+
useThread.setState({ isRunning });
|
1616
|
+
};
|
1617
|
+
return {
|
1618
|
+
useThread,
|
1619
|
+
onNewMessage,
|
1620
|
+
onRunningChange
|
1621
|
+
};
|
1622
|
+
};
|
1623
|
+
var useAssistantContext2 = (runtime) => {
|
1624
|
+
const runtimeRef = useRef5(runtime);
|
1625
|
+
runtimeRef.current = runtime;
|
1626
|
+
const [{ context, onNewMessage, onRunningChange }] = useState6(() => {
|
1627
|
+
const { useThread, onNewMessage: onNewMessage2, onRunningChange: onRunningChange2 } = makeThreadStore(runtimeRef);
|
1628
|
+
const useViewport = makeViewportStore();
|
1629
|
+
const useComposer = makeThreadComposerStore(useThread);
|
1630
|
+
return {
|
1631
|
+
context: { useViewport, useThread, useComposer },
|
1632
|
+
onNewMessage: onNewMessage2,
|
1633
|
+
onRunningChange: onRunningChange2
|
1634
|
+
};
|
1635
|
+
});
|
1636
|
+
useEffect4(() => {
|
1637
|
+
return runtime.subscribeToMessageUpdates(onNewMessage);
|
1638
|
+
}, [runtime, onNewMessage]);
|
1639
|
+
useEffect4(() => {
|
1640
|
+
return runtime.subscribeToStatusUpdates(onRunningChange);
|
1641
|
+
}, [runtime, onRunningChange]);
|
1642
|
+
return context;
|
1643
|
+
};
|
1644
|
+
|
1645
|
+
// src/adapters/core/AssistantProvider.tsx
|
1646
|
+
import { jsx as jsx23 } from "react/jsx-runtime";
|
1647
|
+
var AssistantProvider = ({ children, runtime }) => {
|
1648
|
+
const context = useAssistantContext2(runtime);
|
1649
|
+
return /* @__PURE__ */ jsx23(AssistantContext.Provider, { value: context, children });
|
1650
|
+
};
|
1651
|
+
|
1652
|
+
// src/adapters/core/local/useLocalRuntime.tsx
|
1653
|
+
import { useState as useState7 } from "react";
|
1654
|
+
|
1655
|
+
// src/adapters/core/local/LocalRuntime.tsx
|
1656
|
+
var LocalRuntime = class {
|
1657
|
+
constructor(adapter) {
|
1658
|
+
this.adapter = adapter;
|
1659
|
+
}
|
1660
|
+
_messageUpdateCallbacks = /* @__PURE__ */ new Set();
|
1661
|
+
_statusUpdateCallbacks = /* @__PURE__ */ new Set();
|
1662
|
+
abortController = null;
|
1663
|
+
repository = new MessageRepository();
|
1664
|
+
async append(message) {
|
1665
|
+
const userMessageId = generateId();
|
1666
|
+
const userMessage = {
|
1667
|
+
id: userMessageId,
|
1668
|
+
role: "user",
|
1669
|
+
content: message.content,
|
1670
|
+
createdAt: /* @__PURE__ */ new Date()
|
1671
|
+
};
|
1672
|
+
this.addOrUpdateMessage(message.parentId, userMessage);
|
1673
|
+
const { id } = await this.startRun(userMessageId);
|
1674
|
+
return { parentId: userMessageId, id };
|
1675
|
+
}
|
1676
|
+
async startRun(parentId) {
|
1677
|
+
const id = generateId();
|
1678
|
+
this.repository.resetHead(parentId);
|
1679
|
+
const messages = this.repository.getMessages();
|
1680
|
+
const message = {
|
1681
|
+
id,
|
1682
|
+
role: "assistant",
|
1683
|
+
status: "in_progress",
|
1684
|
+
content: [{ type: "text", text: "" }],
|
1685
|
+
createdAt: /* @__PURE__ */ new Date()
|
1686
|
+
};
|
1687
|
+
this.addOrUpdateMessage(parentId, message);
|
1688
|
+
void this.run(parentId, messages, message);
|
1689
|
+
return { id };
|
1690
|
+
}
|
1691
|
+
addOrUpdateMessage(parentId, message) {
|
1692
|
+
const clone = { ...message };
|
1693
|
+
this.repository.addOrUpdateMessage(parentId, clone);
|
1694
|
+
for (const callback of this._messageUpdateCallbacks)
|
1695
|
+
callback(parentId, clone);
|
1696
|
+
}
|
1697
|
+
async run(parentId, messages, message) {
|
1698
|
+
this.cancelRun();
|
1699
|
+
for (const callback of this._statusUpdateCallbacks) callback(true);
|
1700
|
+
this.abortController = new AbortController();
|
1701
|
+
try {
|
1702
|
+
await this.adapter.run({
|
1703
|
+
messages,
|
1704
|
+
abortSignal: this.abortController.signal,
|
1705
|
+
onUpdate: ({ content }) => {
|
1706
|
+
message.content = content;
|
1707
|
+
this.addOrUpdateMessage(parentId, message);
|
1708
|
+
}
|
1709
|
+
});
|
1710
|
+
message.status = "done";
|
1711
|
+
this.addOrUpdateMessage(parentId, message);
|
1712
|
+
} catch (e) {
|
1713
|
+
message.status = "error";
|
1714
|
+
this.addOrUpdateMessage(parentId, message);
|
1715
|
+
console.error(e);
|
1716
|
+
} finally {
|
1717
|
+
this.cancelRun();
|
1718
|
+
}
|
1719
|
+
}
|
1720
|
+
cancelRun() {
|
1721
|
+
if (!this.abortController) return;
|
1722
|
+
this.abortController.abort();
|
1723
|
+
this.abortController = null;
|
1724
|
+
for (const callback of this._statusUpdateCallbacks) callback(false);
|
1725
|
+
}
|
1726
|
+
subscribeToMessageUpdates(callback) {
|
1727
|
+
this._messageUpdateCallbacks.add(callback);
|
1728
|
+
return () => this._messageUpdateCallbacks.delete(callback);
|
1729
|
+
}
|
1730
|
+
subscribeToStatusUpdates(callback) {
|
1731
|
+
this._statusUpdateCallbacks.add(callback);
|
1732
|
+
return () => this._statusUpdateCallbacks.delete(callback);
|
1733
|
+
}
|
1734
|
+
};
|
1735
|
+
|
1736
|
+
// src/adapters/core/local/useLocalRuntime.tsx
|
1737
|
+
var useLocalRuntime = (adapter) => {
|
1738
|
+
const [runtime] = useState7(() => new LocalRuntime(adapter));
|
1739
|
+
runtime.adapter = adapter;
|
1740
|
+
return runtime;
|
1741
|
+
};
|
1742
|
+
|
1743
|
+
// src/adapters/core/local/vercel/VercelModelAdapter.tsx
|
1744
|
+
import { streamText } from "ai";
|
1745
|
+
var VercelModelAdapter = class {
|
1746
|
+
constructor(model) {
|
1747
|
+
this.model = model;
|
1748
|
+
}
|
1749
|
+
async run({ messages, abortSignal, onUpdate }) {
|
1750
|
+
const { fullStream } = await streamText({
|
1751
|
+
model: this.model,
|
1752
|
+
abortSignal,
|
1753
|
+
messages: messages.map((m) => ({
|
1754
|
+
role: m.role,
|
1755
|
+
content: m.content.filter((c) => c.type !== "ui")
|
1756
|
+
}))
|
1757
|
+
});
|
1758
|
+
const content = [];
|
1759
|
+
for await (const aiPart of fullStream) {
|
1760
|
+
switch (aiPart.type) {
|
1761
|
+
case "text-delta": {
|
1762
|
+
let part = content.at(-1);
|
1763
|
+
if (!part || part.type !== "text") {
|
1764
|
+
part = { type: "text", text: "" };
|
1765
|
+
content.push(part);
|
1766
|
+
}
|
1767
|
+
part.text += aiPart.textDelta;
|
1768
|
+
break;
|
1769
|
+
}
|
1770
|
+
case "tool-call": {
|
1771
|
+
content.push({
|
1772
|
+
type: "tool-call",
|
1773
|
+
name: aiPart.toolName,
|
1774
|
+
args: aiPart.args
|
1775
|
+
});
|
1776
|
+
break;
|
1777
|
+
}
|
1778
|
+
}
|
1779
|
+
onUpdate({ content });
|
1780
|
+
}
|
1781
|
+
return { content };
|
1782
|
+
}
|
1783
|
+
};
|
1514
1784
|
export {
|
1515
1785
|
actionBar_exports as ActionBarPrimitive,
|
1516
1786
|
branchPicker_exports as BranchPickerPrimitive,
|
@@ -1520,6 +1790,11 @@ export {
|
|
1520
1790
|
thread_exports as ThreadPrimitive,
|
1521
1791
|
VercelAIAssistantProvider,
|
1522
1792
|
VercelRSCAssistantProvider,
|
1793
|
+
AssistantProvider as unstable_AssistantProvider,
|
1794
|
+
VercelModelAdapter as unstable_VercelModelAdapter,
|
1795
|
+
getVercelMessage as unstable_getVercelMessage,
|
1796
|
+
getVercelRSCMessage as unstable_getVercelRSCMessage,
|
1797
|
+
useLocalRuntime as unstable_useLocalRuntime,
|
1523
1798
|
useMessageContext as unstable_useMessageContext,
|
1524
1799
|
useBeginMessageEdit,
|
1525
1800
|
useCopyMessage,
|