@assistant-ui/react 0.0.16 → 0.0.18
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 +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,
|