@assistant-ui/react 0.5.20 → 0.5.21

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,608 @@
1
+ "use client";
2
+ import {
3
+ mergeModelConfigs
4
+ } from "./chunk-QBS6JLLN.mjs";
5
+ import {
6
+ __export
7
+ } from "./chunk-BJPOCE4O.mjs";
8
+
9
+ // src/internal.ts
10
+ var internal_exports = {};
11
+ __export(internal_exports, {
12
+ BaseAssistantRuntime: () => BaseAssistantRuntime,
13
+ MessageRepository: () => MessageRepository,
14
+ ProxyConfigProvider: () => ProxyConfigProvider,
15
+ TooltipIconButton: () => TooltipIconButton,
16
+ generateId: () => generateId,
17
+ useSmooth: () => useSmooth,
18
+ useSmoothStatus: () => useSmoothStatus,
19
+ withSmoothContextProvider: () => withSmoothContextProvider
20
+ });
21
+
22
+ // src/utils/ProxyConfigProvider.ts
23
+ var ProxyConfigProvider = class {
24
+ _providers = /* @__PURE__ */ new Set();
25
+ getModelConfig() {
26
+ return mergeModelConfigs(this._providers);
27
+ }
28
+ registerModelConfigProvider(provider) {
29
+ this._providers.add(provider);
30
+ return () => {
31
+ this._providers.delete(provider);
32
+ };
33
+ }
34
+ };
35
+
36
+ // src/utils/idUtils.tsx
37
+ import { customAlphabet } from "nanoid/non-secure";
38
+ var generateId = customAlphabet(
39
+ "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
40
+ 7
41
+ );
42
+ var optimisticPrefix = "__optimistic__";
43
+ var generateOptimisticId = () => `${optimisticPrefix}${generateId()}`;
44
+
45
+ // src/runtimes/edge/converters/fromCoreMessage.ts
46
+ var fromCoreMessages = (message) => {
47
+ return message.map((message2) => fromCoreMessage(message2));
48
+ };
49
+ var fromCoreMessage = (message, {
50
+ id = generateId(),
51
+ status = { type: "complete", reason: "unknown" }
52
+ } = {}) => {
53
+ const commonProps = {
54
+ id,
55
+ createdAt: /* @__PURE__ */ new Date()
56
+ };
57
+ const role = message.role;
58
+ switch (role) {
59
+ case "assistant":
60
+ return {
61
+ ...commonProps,
62
+ role,
63
+ content: message.content.map((part) => {
64
+ if (part.type === "tool-call") {
65
+ return {
66
+ ...part,
67
+ argsText: JSON.stringify(part.args)
68
+ };
69
+ }
70
+ return part;
71
+ }),
72
+ status
73
+ };
74
+ case "user":
75
+ return {
76
+ ...commonProps,
77
+ role,
78
+ content: message.content
79
+ };
80
+ case "system":
81
+ return {
82
+ ...commonProps,
83
+ role,
84
+ content: message.content
85
+ };
86
+ default: {
87
+ const unsupportedRole = role;
88
+ throw new Error(`Unknown message role: ${unsupportedRole}`);
89
+ }
90
+ }
91
+ };
92
+
93
+ // src/runtimes/utils/MessageRepository.tsx
94
+ var findHead = (message) => {
95
+ if (message.next) return findHead(message.next);
96
+ return message;
97
+ };
98
+ var MessageRepository = class {
99
+ messages = /* @__PURE__ */ new Map();
100
+ // message_id -> item
101
+ head = null;
102
+ root = {
103
+ children: []
104
+ };
105
+ performOp(newParent, child, operation) {
106
+ const parentOrRoot = child.prev ?? this.root;
107
+ const newParentOrRoot = newParent ?? this.root;
108
+ if (operation === "relink" && parentOrRoot === newParentOrRoot) return;
109
+ if (operation !== "link") {
110
+ parentOrRoot.children = parentOrRoot.children.filter(
111
+ (m) => m !== child.current.id
112
+ );
113
+ if (child.prev?.next === child) {
114
+ const fallbackId = child.prev.children.at(-1);
115
+ const fallback = fallbackId ? this.messages.get(fallbackId) : null;
116
+ if (fallback === void 0) {
117
+ throw new Error(
118
+ "MessageRepository(performOp/cut): Fallback sibling message not found. This is likely an internal bug in assistant-ui."
119
+ );
120
+ }
121
+ child.prev.next = fallback;
122
+ }
123
+ }
124
+ if (operation !== "cut") {
125
+ newParentOrRoot.children = [
126
+ ...newParentOrRoot.children,
127
+ child.current.id
128
+ ];
129
+ if (newParent && (findHead(child) === this.head || newParent.next === null)) {
130
+ newParent.next = child;
131
+ }
132
+ child.prev = newParent;
133
+ }
134
+ }
135
+ getMessages() {
136
+ const messages = new Array(this.head?.level ?? 0);
137
+ for (let current = this.head; current; current = current.prev) {
138
+ messages[current.level] = current.current;
139
+ }
140
+ return messages;
141
+ }
142
+ addOrUpdateMessage(parentId, message) {
143
+ const existingItem = this.messages.get(message.id);
144
+ const prev = parentId ? this.messages.get(parentId) : null;
145
+ if (prev === void 0)
146
+ throw new Error(
147
+ "MessageRepository(addOrUpdateMessage): Parent message not found. This is likely an internal bug in assistant-ui."
148
+ );
149
+ if (existingItem) {
150
+ existingItem.current = message;
151
+ this.performOp(prev, existingItem, "relink");
152
+ return;
153
+ }
154
+ const newItem = {
155
+ prev,
156
+ current: message,
157
+ next: null,
158
+ children: [],
159
+ level: prev ? prev.level + 1 : 0
160
+ };
161
+ this.messages.set(message.id, newItem);
162
+ this.performOp(prev, newItem, "link");
163
+ if (this.head === prev) {
164
+ this.head = newItem;
165
+ }
166
+ }
167
+ getMessage(messageId) {
168
+ const message = this.messages.get(messageId);
169
+ if (!message)
170
+ throw new Error(
171
+ "MessageRepository(updateMessage): Message not found. This is likely an internal bug in assistant-ui."
172
+ );
173
+ return {
174
+ parentId: message.prev?.current.id ?? null,
175
+ message: message.current
176
+ };
177
+ }
178
+ appendOptimisticMessage(parentId, message) {
179
+ let optimisticId;
180
+ do {
181
+ optimisticId = generateOptimisticId();
182
+ } while (this.messages.has(optimisticId));
183
+ this.addOrUpdateMessage(
184
+ parentId,
185
+ fromCoreMessage(message, {
186
+ id: optimisticId,
187
+ status: { type: "running" }
188
+ })
189
+ );
190
+ return optimisticId;
191
+ }
192
+ deleteMessage(messageId, replacementId) {
193
+ const message = this.messages.get(messageId);
194
+ if (!message)
195
+ throw new Error(
196
+ "MessageRepository(deleteMessage): Optimistic message not found. This is likely an internal bug in assistant-ui."
197
+ );
198
+ const replacement = replacementId === void 0 ? message.prev : replacementId === null ? null : this.messages.get(replacementId);
199
+ if (replacement === void 0)
200
+ throw new Error(
201
+ "MessageRepository(deleteMessage): Replacement not found. This is likely an internal bug in assistant-ui."
202
+ );
203
+ for (const child of message.children) {
204
+ const childMessage = this.messages.get(child);
205
+ if (!childMessage)
206
+ throw new Error(
207
+ "MessageRepository(deleteMessage): Child message not found. This is likely an internal bug in assistant-ui."
208
+ );
209
+ this.performOp(replacement, childMessage, "relink");
210
+ }
211
+ this.performOp(null, message, "cut");
212
+ this.messages.delete(messageId);
213
+ if (this.head === message) {
214
+ this.head = replacement ? findHead(replacement) : null;
215
+ }
216
+ }
217
+ getBranches(messageId) {
218
+ const message = this.messages.get(messageId);
219
+ if (!message)
220
+ throw new Error(
221
+ "MessageRepository(getBranches): Message not found. This is likely an internal bug in assistant-ui."
222
+ );
223
+ const { children } = message.prev ?? this.root;
224
+ return children;
225
+ }
226
+ switchToBranch(messageId) {
227
+ const message = this.messages.get(messageId);
228
+ if (!message)
229
+ throw new Error(
230
+ "MessageRepository(switchToBranch): Branch not found. This is likely an internal bug in assistant-ui."
231
+ );
232
+ if (message.prev) {
233
+ message.prev.next = message;
234
+ }
235
+ this.head = findHead(message);
236
+ }
237
+ resetHead(messageId) {
238
+ if (messageId === null) {
239
+ this.head = null;
240
+ return;
241
+ }
242
+ const message = this.messages.get(messageId);
243
+ if (!message)
244
+ throw new Error(
245
+ "MessageRepository(resetHead): Branch not found. This is likely an internal bug in assistant-ui."
246
+ );
247
+ this.head = message;
248
+ for (let current = message; current; current = current.prev) {
249
+ if (current.prev) {
250
+ current.prev.next = current;
251
+ }
252
+ }
253
+ }
254
+ };
255
+
256
+ // src/runtimes/core/BaseAssistantRuntime.tsx
257
+ var BaseAssistantRuntime = class {
258
+ constructor(_thread) {
259
+ this._thread = _thread;
260
+ this._thread = _thread;
261
+ }
262
+ get thread() {
263
+ return this._thread;
264
+ }
265
+ set thread(thread) {
266
+ this._thread = thread;
267
+ this.subscriptionHandler();
268
+ }
269
+ _subscriptions = /* @__PURE__ */ new Set();
270
+ subscribe(callback) {
271
+ this._subscriptions.add(callback);
272
+ return () => this._subscriptions.delete(callback);
273
+ }
274
+ subscriptionHandler = () => {
275
+ for (const callback of this._subscriptions) callback();
276
+ };
277
+ };
278
+
279
+ // src/utils/smooth/useSmooth.tsx
280
+ import { useEffect, useMemo as useMemo2, useRef, useState as useState2 } from "react";
281
+
282
+ // src/context/react/AssistantContext.ts
283
+ import { createContext, useContext } from "react";
284
+ var AssistantContext = createContext(
285
+ null
286
+ );
287
+ function useAssistantContext(options) {
288
+ const context = useContext(AssistantContext);
289
+ if (!options?.optional && !context)
290
+ throw new Error(
291
+ "This component must be used within an AssistantRuntimeProvider."
292
+ );
293
+ return context;
294
+ }
295
+
296
+ // src/context/react/ThreadContext.ts
297
+ import { createContext as createContext2, useContext as useContext2 } from "react";
298
+ var ThreadContext = createContext2(null);
299
+ function useThreadContext(options) {
300
+ const context = useContext2(ThreadContext);
301
+ if (!options?.optional && !context)
302
+ throw new Error(
303
+ "This component must be used within an AssistantRuntimeProvider."
304
+ );
305
+ return context;
306
+ }
307
+
308
+ // src/context/react/ComposerContext.ts
309
+ import { useMemo } from "react";
310
+
311
+ // src/context/react/MessageContext.ts
312
+ import { createContext as createContext3, useContext as useContext3 } from "react";
313
+ var MessageContext = createContext3(null);
314
+ function useMessageContext(options) {
315
+ const context = useContext3(MessageContext);
316
+ if (!options?.optional && !context)
317
+ throw new Error(
318
+ "This component can only be used inside a component passed to <ThreadPrimitive.Messages components={...} />."
319
+ );
320
+ return context;
321
+ }
322
+
323
+ // src/context/react/ComposerContext.ts
324
+ var useComposerContext = () => {
325
+ const { useComposer } = useThreadContext();
326
+ const { useEditComposer } = useMessageContext({ optional: true }) ?? {};
327
+ return useMemo(
328
+ () => ({
329
+ useComposer: useEditComposer ?? useComposer,
330
+ type: useEditComposer ? "edit" : "new"
331
+ }),
332
+ [useEditComposer, useComposer]
333
+ );
334
+ };
335
+
336
+ // src/context/react/ContentPartContext.ts
337
+ import { createContext as createContext4, useContext as useContext4 } from "react";
338
+ var ContentPartContext = createContext4(
339
+ null
340
+ );
341
+ function useContentPartContext(options) {
342
+ const context = useContext4(ContentPartContext);
343
+ if (!options?.optional && !context)
344
+ throw new Error(
345
+ "This component can only be used inside a component passed to <MessagePrimitive.Content components={...} >."
346
+ );
347
+ return context;
348
+ }
349
+
350
+ // src/utils/smooth/SmoothContext.tsx
351
+ import {
352
+ createContext as createContext5,
353
+ forwardRef,
354
+ useContext as useContext5,
355
+ useState
356
+ } from "react";
357
+ import { create } from "zustand";
358
+ import { jsx } from "react/jsx-runtime";
359
+ var SmoothContext = createContext5(null);
360
+ var makeSmoothContext = (initialState) => {
361
+ const useSmoothStatus2 = create(() => initialState);
362
+ return { useSmoothStatus: useSmoothStatus2 };
363
+ };
364
+ var SmoothContextProvider = ({ children }) => {
365
+ const outer = useSmoothContext({ optional: true });
366
+ const { useContentPart } = useContentPartContext();
367
+ const [context] = useState(
368
+ () => makeSmoothContext(useContentPart.getState().status)
369
+ );
370
+ if (outer) return children;
371
+ return /* @__PURE__ */ jsx(SmoothContext.Provider, { value: context, children });
372
+ };
373
+ var withSmoothContextProvider = (Component) => {
374
+ const Wrapped = forwardRef((props, ref) => {
375
+ return /* @__PURE__ */ jsx(SmoothContextProvider, { children: /* @__PURE__ */ jsx(Component, { ...props, ref }) });
376
+ });
377
+ Wrapped.displayName = Component.displayName;
378
+ return Wrapped;
379
+ };
380
+ function useSmoothContext(options) {
381
+ const context = useContext5(SmoothContext);
382
+ if (!options?.optional && !context)
383
+ throw new Error(
384
+ "This component must be used within a SmoothContextProvider."
385
+ );
386
+ return context;
387
+ }
388
+ var useSmoothStatus = () => {
389
+ const { useSmoothStatus: useSmoothStatus2 } = useSmoothContext();
390
+ return useSmoothStatus2();
391
+ };
392
+
393
+ // src/utils/smooth/useSmooth.tsx
394
+ import { useCallbackRef } from "@radix-ui/react-use-callback-ref";
395
+ var TextStreamAnimator = class {
396
+ constructor(currentText, setText) {
397
+ this.currentText = currentText;
398
+ this.setText = setText;
399
+ }
400
+ animationFrameId = null;
401
+ lastUpdateTime = Date.now();
402
+ targetText = "";
403
+ start() {
404
+ if (this.animationFrameId !== null) return;
405
+ this.lastUpdateTime = Date.now();
406
+ this.animate();
407
+ }
408
+ stop() {
409
+ if (this.animationFrameId !== null) {
410
+ cancelAnimationFrame(this.animationFrameId);
411
+ this.animationFrameId = null;
412
+ }
413
+ }
414
+ animate = () => {
415
+ const currentTime = Date.now();
416
+ const deltaTime = currentTime - this.lastUpdateTime;
417
+ let timeToConsume = deltaTime;
418
+ const remainingChars = this.targetText.length - this.currentText.length;
419
+ const baseTimePerChar = Math.min(5, 250 / remainingChars);
420
+ let charsToAdd = 0;
421
+ while (timeToConsume >= baseTimePerChar && charsToAdd < remainingChars) {
422
+ charsToAdd++;
423
+ timeToConsume -= baseTimePerChar;
424
+ }
425
+ if (charsToAdd !== remainingChars) {
426
+ this.animationFrameId = requestAnimationFrame(this.animate);
427
+ } else {
428
+ this.animationFrameId = null;
429
+ }
430
+ if (charsToAdd === 0) return;
431
+ this.currentText = this.targetText.slice(
432
+ 0,
433
+ this.currentText.length + charsToAdd
434
+ );
435
+ this.lastUpdateTime = currentTime - timeToConsume;
436
+ this.setText(this.currentText);
437
+ };
438
+ };
439
+ var SMOOTH_STATUS = Object.freeze({
440
+ type: "running"
441
+ });
442
+ var useSmooth = (state, smooth = false) => {
443
+ const { useSmoothStatus: useSmoothStatus2 } = useSmoothContext({ optional: true }) ?? {};
444
+ const {
445
+ part: { text }
446
+ } = state;
447
+ const { useMessage } = useMessageContext();
448
+ const id = useMessage((m) => m.message.id);
449
+ const idRef = useRef(id);
450
+ const [displayedText, setDisplayedText] = useState2(text);
451
+ const setText = useCallbackRef((text2) => {
452
+ setDisplayedText(text2);
453
+ useSmoothStatus2?.setState(text2 !== state.part.text ? SMOOTH_STATUS : state.status);
454
+ });
455
+ const [animatorRef] = useState2(
456
+ new TextStreamAnimator(text, setText)
457
+ );
458
+ useEffect(() => {
459
+ if (!smooth) {
460
+ animatorRef.stop();
461
+ return;
462
+ }
463
+ if (idRef.current !== id || !text.startsWith(animatorRef.targetText)) {
464
+ idRef.current = id;
465
+ setText(text);
466
+ animatorRef.currentText = text;
467
+ animatorRef.targetText = text;
468
+ animatorRef.stop();
469
+ return;
470
+ }
471
+ animatorRef.targetText = text;
472
+ animatorRef.start();
473
+ }, [setText, animatorRef, id, smooth, text]);
474
+ useEffect(() => {
475
+ return () => {
476
+ animatorRef.stop();
477
+ };
478
+ }, [animatorRef]);
479
+ return useMemo2(
480
+ () => smooth ? {
481
+ part: { type: "text", text: displayedText },
482
+ status: text === displayedText ? state.status : SMOOTH_STATUS
483
+ } : state,
484
+ [smooth, displayedText, state, text]
485
+ );
486
+ };
487
+
488
+ // src/ui/base/tooltip-icon-button.tsx
489
+ import { forwardRef as forwardRef4 } from "react";
490
+
491
+ // src/ui/base/tooltip.tsx
492
+ import * as TooltipPrimitive from "@radix-ui/react-tooltip";
493
+
494
+ // src/ui/utils/withDefaults.tsx
495
+ import {
496
+ forwardRef as forwardRef2
497
+ } from "react";
498
+ import classNames from "classnames";
499
+ import { jsx as jsx2 } from "react/jsx-runtime";
500
+ var withDefaultProps = ({
501
+ className,
502
+ ...defaultProps
503
+ }) => ({ className: classNameProp, ...props }) => {
504
+ return {
505
+ className: classNames(className, classNameProp),
506
+ ...defaultProps,
507
+ ...props
508
+ };
509
+ };
510
+ var withDefaults = (Component, defaultProps) => {
511
+ const getProps = withDefaultProps(defaultProps);
512
+ const WithDefaults = forwardRef2(
513
+ (props, ref) => {
514
+ const ComponentAsAny = Component;
515
+ return /* @__PURE__ */ jsx2(ComponentAsAny, { ...getProps(props), ref });
516
+ }
517
+ );
518
+ WithDefaults.displayName = "withDefaults(" + (typeof Component === "string" ? Component : Component.displayName) + ")";
519
+ return WithDefaults;
520
+ };
521
+
522
+ // src/ui/base/tooltip.tsx
523
+ import { jsx as jsx3 } from "react/jsx-runtime";
524
+ var Tooltip = (props) => {
525
+ return /* @__PURE__ */ jsx3(TooltipPrimitive.Provider, { children: /* @__PURE__ */ jsx3(TooltipPrimitive.Root, { ...props }) });
526
+ };
527
+ Tooltip.displayName = "Tooltip";
528
+ var TooltipTrigger = TooltipPrimitive.Trigger;
529
+ var TooltipContent = withDefaults(TooltipPrimitive.Content, {
530
+ sideOffset: 4,
531
+ className: "aui-tooltip-content"
532
+ });
533
+ TooltipContent.displayName = "TooltipContent";
534
+
535
+ // src/ui/base/button.tsx
536
+ import { cva } from "class-variance-authority";
537
+ import { Primitive } from "@radix-ui/react-primitive";
538
+ import { forwardRef as forwardRef3 } from "react";
539
+ import { jsx as jsx4 } from "react/jsx-runtime";
540
+ var buttonVariants = cva("aui-button", {
541
+ variants: {
542
+ variant: {
543
+ default: "aui-button-primary",
544
+ outline: "aui-button-outline",
545
+ ghost: "aui-button-ghost"
546
+ },
547
+ size: {
548
+ default: "aui-button-medium",
549
+ icon: "aui-button-icon"
550
+ }
551
+ },
552
+ defaultVariants: {
553
+ variant: "default",
554
+ size: "default"
555
+ }
556
+ });
557
+ var Button = forwardRef3(
558
+ ({ className, variant, size, ...props }, ref) => {
559
+ return /* @__PURE__ */ jsx4(
560
+ Primitive.button,
561
+ {
562
+ className: buttonVariants({ variant, size, className }),
563
+ ...props,
564
+ ref
565
+ }
566
+ );
567
+ }
568
+ );
569
+ Button.displayName = "Button";
570
+
571
+ // src/ui/base/tooltip-icon-button.tsx
572
+ import { jsx as jsx5, jsxs } from "react/jsx-runtime";
573
+ var TooltipIconButton = forwardRef4(({ children, tooltip, side = "bottom", ...rest }, ref) => {
574
+ return /* @__PURE__ */ jsxs(Tooltip, { children: [
575
+ /* @__PURE__ */ jsx5(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(Button, { variant: "ghost", size: "icon", ...rest, ref, children: [
576
+ children,
577
+ /* @__PURE__ */ jsx5("span", { className: "aui-sr-only", children: tooltip })
578
+ ] }) }),
579
+ /* @__PURE__ */ jsx5(TooltipContent, { side, children: tooltip })
580
+ ] });
581
+ });
582
+ TooltipIconButton.displayName = "TooltipIconButton";
583
+
584
+ export {
585
+ AssistantContext,
586
+ useAssistantContext,
587
+ ProxyConfigProvider,
588
+ ThreadContext,
589
+ useThreadContext,
590
+ MessageContext,
591
+ useMessageContext,
592
+ useComposerContext,
593
+ ContentPartContext,
594
+ useContentPartContext,
595
+ withSmoothContextProvider,
596
+ useSmoothStatus,
597
+ useSmooth,
598
+ BaseAssistantRuntime,
599
+ generateId,
600
+ fromCoreMessages,
601
+ fromCoreMessage,
602
+ MessageRepository,
603
+ withDefaults,
604
+ Button,
605
+ TooltipIconButton,
606
+ internal_exports
607
+ };
608
+ //# sourceMappingURL=chunk-V66MVXBH.mjs.map