@assistant-ui/react 0.0.15 → 0.0.16

Sign up to get free protection for your applications and to get access to all the features.
package/dist/index.mjs CHANGED
@@ -71,11 +71,11 @@ import {
71
71
  import { forwardRef as forwardRef2, useRef as useRef3 } from "react";
72
72
 
73
73
  // src/utils/hooks/useOnResizeContent.tsx
74
- import { useLayoutEffect, useRef } from "react";
74
+ import { useEffect, useRef } from "react";
75
75
  var useOnResizeContent = (ref, callback) => {
76
76
  const callbackRef = useRef(callback);
77
77
  callbackRef.current = callback;
78
- useLayoutEffect(() => {
78
+ useEffect(() => {
79
79
  const el = ref.current;
80
80
  if (!el) return;
81
81
  const resizeObserver = new ResizeObserver(() => {
@@ -109,12 +109,12 @@ var useOnResizeContent = (ref, callback) => {
109
109
  };
110
110
 
111
111
  // src/utils/hooks/useOnScrollToBottom.tsx
112
- import { useEffect, useRef as useRef2 } from "react";
112
+ import { useEffect as useEffect2, useRef as useRef2 } from "react";
113
113
  var useOnScrollToBottom = (callback) => {
114
114
  const callbackRef = useRef2(callback);
115
115
  callbackRef.current = callback;
116
116
  const { useViewport } = useAssistantContext();
117
- useEffect(() => {
117
+ useEffect2(() => {
118
118
  return useViewport.getState().onScrollToBottom(() => {
119
119
  callbackRef.current();
120
120
  });
@@ -179,7 +179,9 @@ var MessageContext = createContext2(null);
179
179
  var useMessageContext = () => {
180
180
  const context = useContext2(MessageContext);
181
181
  if (!context)
182
- throw new Error("This component must be used within a MessageProvider.");
182
+ throw new Error(
183
+ "This component must be used within a MessagePrimitive.Provider."
184
+ );
183
185
  return context;
184
186
  };
185
187
 
@@ -212,6 +214,7 @@ var message_exports = {};
212
214
  __export(message_exports, {
213
215
  Content: () => MessageContent,
214
216
  If: () => MessageIf,
217
+ Loading: () => MessageLoading,
215
218
  Provider: () => MessageProvider,
216
219
  Root: () => MessageRoot
217
220
  });
@@ -293,8 +296,12 @@ var useMessageContext2 = () => {
293
296
  parentId: null,
294
297
  branches: [],
295
298
  isLast: false,
299
+ loadingIndicator: null,
296
300
  isCopied: false,
297
301
  isHovering: false,
302
+ setLoadingIndicator: (value) => {
303
+ set({ loadingIndicator: value });
304
+ },
298
305
  setIsCopied: (value) => {
299
306
  set({ isCopied: value });
300
307
  },
@@ -398,10 +405,94 @@ var MessageIf = ({ children, ...query }) => {
398
405
  return result ? children : null;
399
406
  };
400
407
 
408
+ // src/utils/context/combined/useCombinedStore.ts
409
+ import { useMemo as useMemo2 } from "react";
410
+
411
+ // src/utils/context/combined/createCombinedStore.ts
412
+ import { useSyncExternalStore } from "react";
413
+ var createCombinedStore = (stores) => {
414
+ const subscribe = (callback) => {
415
+ const unsubscribes = stores.map((store) => store.subscribe(callback));
416
+ return () => {
417
+ for (const unsub of unsubscribes) {
418
+ unsub();
419
+ }
420
+ };
421
+ };
422
+ return (selector) => {
423
+ const getSnapshot = () => selector(...stores.map((store) => store.getState()));
424
+ return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
425
+ };
426
+ };
427
+
428
+ // src/utils/context/combined/useCombinedStore.ts
429
+ var useCombinedStore = (stores, selector) => {
430
+ const useCombined = useMemo2(() => createCombinedStore(stores), stores);
431
+ return useCombined(selector);
432
+ };
433
+
434
+ // src/utils/context/useContentPartContext.ts
435
+ import { createContext as createContext3, useContext as useContext4 } from "react";
436
+ var ContentPartContext = createContext3(null);
437
+ var useContentPartContext = () => {
438
+ const context = useContext4(ContentPartContext);
439
+ if (!context)
440
+ throw new Error(
441
+ "This component must be used within a ContentPartPrimitive.Provider."
442
+ );
443
+ return context;
444
+ };
445
+
446
+ // src/primitives/contentPart/ContentPartLoadingIndicator.tsx
447
+ var ContentPartLoadingIndicator = () => {
448
+ const { useMessage } = useMessageContext();
449
+ const { useContentPart } = useContentPartContext();
450
+ const loadingIndicator = useCombinedStore(
451
+ [useMessage, useContentPart],
452
+ (m, c) => c.isLoading ? m.loadingIndicator : null
453
+ );
454
+ return loadingIndicator;
455
+ };
456
+
457
+ // src/primitives/contentPart/ContentPartProvider.tsx
458
+ import { useMemo as useMemo3, useState as useState2 } from "react";
459
+ import { create as create3 } from "zustand";
460
+ import { jsx as jsx6 } from "react/jsx-runtime";
461
+ var useContentPartContext2 = () => {
462
+ const [context] = useState2(() => {
463
+ const useContentPart = create3(() => ({
464
+ part: null,
465
+ isLoading: false
466
+ }));
467
+ return { useContentPart };
468
+ });
469
+ return context;
470
+ };
471
+ var ContentPartProvider = ({
472
+ part,
473
+ isLoading,
474
+ children
475
+ }) => {
476
+ const context = useContentPartContext2();
477
+ useMemo3(() => {
478
+ context.useContentPart.setState(
479
+ {
480
+ part,
481
+ isLoading
482
+ },
483
+ true
484
+ );
485
+ }, [context, part, isLoading]);
486
+ return /* @__PURE__ */ jsx6(ContentPartContext.Provider, { value: context, children });
487
+ };
488
+
401
489
  // src/primitives/message/MessageContent.tsx
402
- import { Fragment, jsx as jsx6 } from "react/jsx-runtime";
490
+ import { Fragment, jsx as jsx7, jsxs as jsxs2 } from "react/jsx-runtime";
403
491
  var defaultComponents = {
404
- Text: ({ part }) => /* @__PURE__ */ jsx6(Fragment, { children: part.text }),
492
+ Text: ({ part }) => /* @__PURE__ */ jsxs2(Fragment, { children: [
493
+ part.text,
494
+ /* @__PURE__ */ jsx7(ContentPartLoadingIndicator, {})
495
+ ] }),
405
496
  Image: () => null,
406
497
  UI: ({ part }) => part.display,
407
498
  tools: {
@@ -416,29 +507,63 @@ var MessageContent = ({
416
507
  tools: { by_name = {}, Fallback = defaultComponents.tools.Fallback } = {}
417
508
  } = {}
418
509
  }) => {
510
+ const { useThread } = useAssistantContext();
419
511
  const { useMessage } = useMessageContext();
420
512
  const content = useMessage((s) => s.message.content);
421
- return /* @__PURE__ */ jsx6(Fragment, { children: content.map((part, i) => {
513
+ const isLoading = useCombinedStore(
514
+ [useThread, useMessage],
515
+ (t, s) => s.isLast && t.isRunning
516
+ );
517
+ return /* @__PURE__ */ jsx7(Fragment, { children: content.map((part, i) => {
422
518
  const key = i;
423
- switch (part.type) {
519
+ const type = part.type;
520
+ let component = null;
521
+ switch (type) {
424
522
  case "text":
425
- return /* @__PURE__ */ jsx6(Text, { part }, key);
523
+ component = /* @__PURE__ */ jsx7(Text, { part });
524
+ break;
426
525
  case "image":
427
- return /* @__PURE__ */ jsx6(Image, { part }, key);
526
+ component = /* @__PURE__ */ jsx7(Image, { part });
527
+ break;
428
528
  case "ui":
429
- return /* @__PURE__ */ jsx6(UI, { part }, key);
529
+ component = /* @__PURE__ */ jsx7(UI, { part });
530
+ break;
430
531
  case "tool-call": {
431
532
  const Tool = by_name[part.name] || Fallback;
432
- return /* @__PURE__ */ jsx6(Tool, { part }, key);
533
+ component = /* @__PURE__ */ jsx7(Tool, { part });
534
+ break;
433
535
  }
434
536
  default:
435
- return null;
537
+ throw new Error(`Unknown content part type: ${type}`);
436
538
  }
539
+ return /* @__PURE__ */ jsx7(
540
+ ContentPartProvider,
541
+ {
542
+ part,
543
+ isLoading: i === content.length - 1 && isLoading,
544
+ children: component
545
+ },
546
+ key
547
+ );
437
548
  }) });
438
549
  };
439
550
 
551
+ // src/primitives/message/MessageLoading.tsx
552
+ import {
553
+ Primitive as Primitive4
554
+ } from "@radix-ui/react-primitive";
555
+ import { forwardRef as forwardRef4, useMemo as useMemo4 } from "react";
556
+ import { jsx as jsx8 } from "react/jsx-runtime";
557
+ var MessageLoading = forwardRef4((props, ref) => {
558
+ const { useMessage } = useMessageContext();
559
+ useMemo4(() => {
560
+ useMessage.getState().setLoadingIndicator(/* @__PURE__ */ jsx8(Primitive4.div, { ...props, ref }));
561
+ }, [useMessage, props, ref]);
562
+ return null;
563
+ });
564
+
440
565
  // src/primitives/thread/ThreadMessages.tsx
441
- import { Fragment as Fragment2, jsx as jsx7, jsxs as jsxs2 } from "react/jsx-runtime";
566
+ import { Fragment as Fragment2, jsx as jsx9, jsxs as jsxs3 } from "react/jsx-runtime";
442
567
  var getComponents = (components) => {
443
568
  return {
444
569
  EditComposer: components.EditComposer ?? components.UserMessage ?? components.Message,
@@ -452,19 +577,19 @@ var ThreadMessages = ({ components }) => {
452
577
  const messages = thread.messages;
453
578
  const { UserMessage, EditComposer, AssistantMessage } = getComponents(components);
454
579
  if (messages.length === 0) return null;
455
- return /* @__PURE__ */ jsx7(Fragment2, { children: messages.map((message, idx) => {
580
+ return /* @__PURE__ */ jsx9(Fragment2, { children: messages.map((message, idx) => {
456
581
  const parentId = messages[idx - 1]?.id ?? null;
457
- return /* @__PURE__ */ jsxs2(
582
+ return /* @__PURE__ */ jsxs3(
458
583
  MessageProvider,
459
584
  {
460
585
  message,
461
586
  parentId,
462
587
  children: [
463
- /* @__PURE__ */ jsxs2(MessageIf, { user: true, children: [
464
- /* @__PURE__ */ jsx7(ComposerIf, { editing: false, children: /* @__PURE__ */ jsx7(UserMessage, {}) }),
465
- /* @__PURE__ */ jsx7(ComposerIf, { editing: true, children: /* @__PURE__ */ jsx7(EditComposer, {}) })
588
+ /* @__PURE__ */ jsxs3(MessageIf, { user: true, children: [
589
+ /* @__PURE__ */ jsx9(ComposerIf, { editing: false, children: /* @__PURE__ */ jsx9(UserMessage, {}) }),
590
+ /* @__PURE__ */ jsx9(ComposerIf, { editing: true, children: /* @__PURE__ */ jsx9(EditComposer, {}) })
466
591
  ] }),
467
- /* @__PURE__ */ jsx7(MessageIf, { assistant: true, children: /* @__PURE__ */ jsx7(AssistantMessage, {}) })
592
+ /* @__PURE__ */ jsx9(MessageIf, { assistant: true, children: /* @__PURE__ */ jsx9(AssistantMessage, {}) })
468
593
  ]
469
594
  },
470
595
  parentId ?? "__ROOT__"
@@ -475,18 +600,18 @@ var ThreadMessages = ({ components }) => {
475
600
  // src/primitives/thread/ThreadScrollToBottom.tsx
476
601
  import { composeEventHandlers as composeEventHandlers3 } from "@radix-ui/primitive";
477
602
  import {
478
- Primitive as Primitive4
603
+ Primitive as Primitive5
479
604
  } from "@radix-ui/react-primitive";
480
- import { forwardRef as forwardRef4 } from "react";
481
- import { jsx as jsx8 } from "react/jsx-runtime";
482
- var ThreadScrollToBottom = forwardRef4(({ onClick, ...rest }, ref) => {
605
+ import { forwardRef as forwardRef5 } from "react";
606
+ import { jsx as jsx10 } from "react/jsx-runtime";
607
+ var ThreadScrollToBottom = forwardRef5(({ onClick, ...rest }, ref) => {
483
608
  const { useViewport } = useAssistantContext();
484
609
  const isAtBottom = useViewport((s) => s.isAtBottom);
485
610
  const handleScrollToBottom = () => {
486
611
  useViewport.getState().scrollToBottom();
487
612
  };
488
- return /* @__PURE__ */ jsx8(
489
- Primitive4.button,
613
+ return /* @__PURE__ */ jsx10(
614
+ Primitive5.button,
490
615
  {
491
616
  ...rest,
492
617
  disabled: isAtBottom,
@@ -499,11 +624,11 @@ var ThreadScrollToBottom = forwardRef4(({ onClick, ...rest }, ref) => {
499
624
  // src/primitives/thread/ThreadSuggestion.tsx
500
625
  import { composeEventHandlers as composeEventHandlers4 } from "@radix-ui/primitive";
501
626
  import {
502
- Primitive as Primitive5
627
+ Primitive as Primitive6
503
628
  } from "@radix-ui/react-primitive";
504
- import { forwardRef as forwardRef5 } from "react";
505
- import { jsx as jsx9 } from "react/jsx-runtime";
506
- var ThreadSuggestion = forwardRef5(({ onClick, prompt, method, autoSend: send, ...rest }, ref) => {
629
+ import { forwardRef as forwardRef6 } from "react";
630
+ import { jsx as jsx11 } from "react/jsx-runtime";
631
+ var ThreadSuggestion = forwardRef6(({ onClick, prompt, method, autoSend: send, ...rest }, ref) => {
507
632
  const { useThread, useComposer } = useAssistantContext();
508
633
  const isDisabled = useThread((t) => t.isRunning);
509
634
  const handleApplySuggestion = () => {
@@ -514,8 +639,8 @@ var ThreadSuggestion = forwardRef5(({ onClick, prompt, method, autoSend: send, .
514
639
  composer.send();
515
640
  }
516
641
  };
517
- return /* @__PURE__ */ jsx9(
518
- Primitive5.button,
642
+ return /* @__PURE__ */ jsx11(
643
+ Primitive6.button,
519
644
  {
520
645
  ...rest,
521
646
  disabled: isDisabled,
@@ -539,11 +664,11 @@ __export(composer_exports, {
539
664
  import { composeEventHandlers as composeEventHandlers5 } from "@radix-ui/primitive";
540
665
  import { useComposedRefs as useComposedRefs2 } from "@radix-ui/react-compose-refs";
541
666
  import {
542
- Primitive as Primitive6
667
+ Primitive as Primitive7
543
668
  } from "@radix-ui/react-primitive";
544
- import { forwardRef as forwardRef6, useRef as useRef4 } from "react";
545
- import { jsx as jsx10 } from "react/jsx-runtime";
546
- var ComposerRoot = forwardRef6(
669
+ import { forwardRef as forwardRef7, useRef as useRef4 } from "react";
670
+ import { jsx as jsx12 } from "react/jsx-runtime";
671
+ var ComposerRoot = forwardRef7(
547
672
  ({ onSubmit, ...rest }, forwardedRef) => {
548
673
  const { useViewport } = useAssistantContext();
549
674
  const { useComposer } = useComposerContext();
@@ -556,8 +681,8 @@ var ComposerRoot = forwardRef6(
556
681
  composerState.send();
557
682
  useViewport.getState().scrollToBottom();
558
683
  };
559
- return /* @__PURE__ */ jsx10(
560
- Primitive6.form,
684
+ return /* @__PURE__ */ jsx12(
685
+ Primitive7.form,
561
686
  {
562
687
  ...rest,
563
688
  ref,
@@ -572,14 +697,14 @@ import { composeEventHandlers as composeEventHandlers6 } from "@radix-ui/primiti
572
697
  import { useComposedRefs as useComposedRefs3 } from "@radix-ui/react-compose-refs";
573
698
  import { Slot } from "@radix-ui/react-slot";
574
699
  import {
575
- forwardRef as forwardRef7,
700
+ forwardRef as forwardRef8,
576
701
  useCallback,
577
- useEffect as useEffect2,
702
+ useEffect as useEffect3,
578
703
  useRef as useRef5
579
704
  } from "react";
580
705
  import TextareaAutosize from "react-textarea-autosize";
581
- import { jsx as jsx11 } from "react/jsx-runtime";
582
- var ComposerInput = forwardRef7(
706
+ import { jsx as jsx13 } from "react/jsx-runtime";
707
+ var ComposerInput = forwardRef8(
583
708
  ({ autoFocus = false, asChild, disabled, onChange, onKeyDown, ...rest }, forwardedRef) => {
584
709
  const { useThread, useViewport } = useAssistantContext();
585
710
  const { useComposer, type } = useComposerContext();
@@ -616,13 +741,13 @@ var ComposerInput = forwardRef7(
616
741
  textareaRef.current.value.length
617
742
  );
618
743
  }, [autoFocusEnabled]);
619
- useEffect2(() => focus(), [focus]);
744
+ useEffect3(() => focus(), [focus]);
620
745
  useOnScrollToBottom(() => {
621
746
  if (type === "assistant") {
622
747
  focus();
623
748
  }
624
749
  });
625
- return /* @__PURE__ */ jsx11(
750
+ return /* @__PURE__ */ jsx13(
626
751
  Component,
627
752
  {
628
753
  value,
@@ -642,16 +767,16 @@ var ComposerInput = forwardRef7(
642
767
 
643
768
  // src/primitives/composer/ComposerSend.tsx
644
769
  import {
645
- Primitive as Primitive7
770
+ Primitive as Primitive8
646
771
  } from "@radix-ui/react-primitive";
647
- import { forwardRef as forwardRef8 } from "react";
648
- import { jsx as jsx12 } from "react/jsx-runtime";
649
- var ComposerSend = forwardRef8(
772
+ import { forwardRef as forwardRef9 } from "react";
773
+ import { jsx as jsx14 } from "react/jsx-runtime";
774
+ var ComposerSend = forwardRef9(
650
775
  ({ disabled, ...rest }, ref) => {
651
776
  const { useComposer } = useComposerContext();
652
777
  const hasValue = useComposer((c) => c.isEditing && c.value.length > 0);
653
- return /* @__PURE__ */ jsx12(
654
- Primitive7.button,
778
+ return /* @__PURE__ */ jsx14(
779
+ Primitive8.button,
655
780
  {
656
781
  type: "submit",
657
782
  ...rest,
@@ -665,17 +790,17 @@ var ComposerSend = forwardRef8(
665
790
  // src/primitives/composer/ComposerCancel.tsx
666
791
  import { composeEventHandlers as composeEventHandlers7 } from "@radix-ui/primitive";
667
792
  import {
668
- Primitive as Primitive8
793
+ Primitive as Primitive9
669
794
  } from "@radix-ui/react-primitive";
670
- import { forwardRef as forwardRef9 } from "react";
671
- import { jsx as jsx13 } from "react/jsx-runtime";
672
- var ComposerCancel = forwardRef9(({ onClick, ...rest }, ref) => {
795
+ import { forwardRef as forwardRef10 } from "react";
796
+ import { jsx as jsx15 } from "react/jsx-runtime";
797
+ var ComposerCancel = forwardRef10(({ onClick, ...rest }, ref) => {
673
798
  const { useComposer } = useComposerContext();
674
799
  const handleCancel = () => {
675
800
  useComposer.getState().cancel();
676
801
  };
677
- return /* @__PURE__ */ jsx13(
678
- Primitive8.button,
802
+ return /* @__PURE__ */ jsx15(
803
+ Primitive9.button,
679
804
  {
680
805
  type: "button",
681
806
  ...rest,
@@ -695,32 +820,6 @@ __export(branchPicker_exports, {
695
820
  Root: () => BranchPickerRoot
696
821
  });
697
822
 
698
- // src/utils/context/combined/useCombinedStore.ts
699
- import { useMemo as useMemo2 } from "react";
700
-
701
- // src/utils/context/combined/createCombinedStore.ts
702
- import { useSyncExternalStore } from "react";
703
- var createCombinedStore = (stores) => {
704
- const subscribe = (callback) => {
705
- const unsubscribes = stores.map((store) => store.subscribe(callback));
706
- return () => {
707
- for (const unsub of unsubscribes) {
708
- unsub();
709
- }
710
- };
711
- };
712
- return (selector) => {
713
- const getSnapshot = () => selector(...stores.map((store) => store.getState()));
714
- return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
715
- };
716
- };
717
-
718
- // src/utils/context/combined/useCombinedStore.ts
719
- var useCombinedStore = (stores, selector) => {
720
- const useCombined = useMemo2(() => createCombinedStore(stores), stores);
721
- return useCombined(selector);
722
- };
723
-
724
823
  // src/actions/useGoToNextBranch.tsx
725
824
  var useGoToNextBranch = () => {
726
825
  const { useThread } = useAssistantContext();
@@ -739,16 +838,16 @@ var useGoToNextBranch = () => {
739
838
  // src/utils/createActionButton.tsx
740
839
  import { composeEventHandlers as composeEventHandlers8 } from "@radix-ui/primitive";
741
840
  import {
742
- Primitive as Primitive9
841
+ Primitive as Primitive10
743
842
  } from "@radix-ui/react-primitive";
744
- import { forwardRef as forwardRef10 } from "react";
745
- import { jsx as jsx14 } from "react/jsx-runtime";
843
+ import { forwardRef as forwardRef11 } from "react";
844
+ import { jsx as jsx16 } from "react/jsx-runtime";
746
845
  var createActionButton = (useActionButton) => {
747
- return forwardRef10(
846
+ return forwardRef11(
748
847
  (props, forwardedRef) => {
749
848
  const onClick = useActionButton(props);
750
- return /* @__PURE__ */ jsx14(
751
- Primitive9.button,
849
+ return /* @__PURE__ */ jsx16(
850
+ Primitive10.button,
752
851
  {
753
852
  type: "button",
754
853
  disabled: !onClick,
@@ -786,29 +885,29 @@ var useGoToPreviousBranch = () => {
786
885
  var BranchPickerPrevious = createActionButton(useGoToPreviousBranch);
787
886
 
788
887
  // src/primitives/branchPicker/BranchPickerCount.tsx
789
- import { Fragment as Fragment3, jsx as jsx15 } from "react/jsx-runtime";
888
+ import { Fragment as Fragment3, jsx as jsx17 } from "react/jsx-runtime";
790
889
  var BranchPickerCount = () => {
791
890
  const { useMessage } = useMessageContext();
792
891
  const branchCount = useMessage((s) => s.branches.length);
793
- return /* @__PURE__ */ jsx15(Fragment3, { children: branchCount });
892
+ return /* @__PURE__ */ jsx17(Fragment3, { children: branchCount });
794
893
  };
795
894
 
796
895
  // src/primitives/branchPicker/BranchPickerNumber.tsx
797
- import { Fragment as Fragment4, jsx as jsx16 } from "react/jsx-runtime";
896
+ import { Fragment as Fragment4, jsx as jsx18 } from "react/jsx-runtime";
798
897
  var BranchPickerNumber = () => {
799
898
  const { useMessage } = useMessageContext();
800
899
  const branchIdx = useMessage((s) => s.branches.indexOf(s.message.id));
801
- return /* @__PURE__ */ jsx16(Fragment4, { children: branchIdx + 1 });
900
+ return /* @__PURE__ */ jsx18(Fragment4, { children: branchIdx + 1 });
802
901
  };
803
902
 
804
903
  // src/primitives/branchPicker/BranchPickerRoot.tsx
805
904
  import {
806
- Primitive as Primitive10
905
+ Primitive as Primitive11
807
906
  } from "@radix-ui/react-primitive";
808
- import { forwardRef as forwardRef11 } from "react";
809
- import { jsx as jsx17 } from "react/jsx-runtime";
810
- var BranchPickerRoot = forwardRef11(({ hideWhenSingleBranch, ...rest }, ref) => {
811
- return /* @__PURE__ */ jsx17(MessageIf, { hasBranches: hideWhenSingleBranch ? true : void 0, children: /* @__PURE__ */ jsx17(Primitive10.div, { ...rest, ref }) });
907
+ import { forwardRef as forwardRef12 } from "react";
908
+ import { jsx as jsx19 } from "react/jsx-runtime";
909
+ var BranchPickerRoot = forwardRef12(({ hideWhenSingleBranch, ...rest }, ref) => {
910
+ return /* @__PURE__ */ jsx19(MessageIf, { hasBranches: hideWhenSingleBranch ? true : void 0, children: /* @__PURE__ */ jsx19(Primitive11.div, { ...rest, ref }) });
812
911
  });
813
912
 
814
913
  // src/primitives/actionBar/index.ts
@@ -822,11 +921,11 @@ __export(actionBar_exports, {
822
921
 
823
922
  // src/primitives/actionBar/ActionBarRoot.tsx
824
923
  import {
825
- Primitive as Primitive11
924
+ Primitive as Primitive12
826
925
  } from "@radix-ui/react-primitive";
827
- import { forwardRef as forwardRef12 } from "react";
828
- import { jsx as jsx18 } from "react/jsx-runtime";
829
- var ActionBarRoot = forwardRef12(({ hideWhenRunning, autohide, autohideFloat, ...rest }, ref) => {
926
+ import { forwardRef as forwardRef13 } from "react";
927
+ import { jsx as jsx20 } from "react/jsx-runtime";
928
+ var ActionBarRoot = forwardRef13(({ hideWhenRunning, autohide, autohideFloat, ...rest }, ref) => {
830
929
  const { useThread } = useAssistantContext();
831
930
  const { useMessage } = useMessageContext();
832
931
  const hideAndfloatStatus = useCombinedStore(
@@ -842,8 +941,8 @@ var ActionBarRoot = forwardRef12(({ hideWhenRunning, autohide, autohideFloat, ..
842
941
  }
843
942
  );
844
943
  if (hideAndfloatStatus === "hidden" /* Hidden */) return null;
845
- return /* @__PURE__ */ jsx18(
846
- Primitive11.div,
944
+ return /* @__PURE__ */ jsx20(
945
+ Primitive12.div,
847
946
  {
848
947
  "data-floating": hideAndfloatStatus === "floating" /* Floating */,
849
948
  ...rest,
@@ -911,18 +1010,25 @@ var useBeginMessageEdit = () => {
911
1010
  // src/primitives/actionBar/ActionBarEdit.tsx
912
1011
  var ActionBarEdit = createActionButton(useBeginMessageEdit);
913
1012
 
1013
+ // src/primitives/contentPart/index.ts
1014
+ var contentPart_exports = {};
1015
+ __export(contentPart_exports, {
1016
+ LoadingIndicator: () => ContentPartLoadingIndicator,
1017
+ Provider: () => ContentPartProvider
1018
+ });
1019
+
914
1020
  // src/adapters/vercel/VercelAIAssistantProvider.tsx
915
- import { useMemo as useMemo4 } from "react";
1021
+ import { useMemo as useMemo6 } from "react";
916
1022
 
917
1023
  // src/adapters/vercel/useDummyAIAssistantContext.tsx
918
- import { useState as useState2 } from "react";
919
- import { create as create4 } from "zustand";
1024
+ import { useState as useState3 } from "react";
1025
+ import { create as create5 } from "zustand";
920
1026
 
921
1027
  // src/utils/context/stores/ViewportStore.tsx
922
- import { create as create3 } from "zustand";
1028
+ import { create as create4 } from "zustand";
923
1029
  var makeViewportStore = () => {
924
1030
  const scrollToBottomListeners = /* @__PURE__ */ new Set();
925
- return create3(() => ({
1031
+ return create4(() => ({
926
1032
  isAtBottom: true,
927
1033
  scrollToBottom: () => {
928
1034
  for (const listener of scrollToBottomListeners) {
@@ -940,7 +1046,7 @@ var makeViewportStore = () => {
940
1046
 
941
1047
  // src/adapters/vercel/useDummyAIAssistantContext.tsx
942
1048
  var makeDummyThreadStore = () => {
943
- return create4(() => ({
1049
+ return create5(() => ({
944
1050
  messages: [],
945
1051
  isRunning: false,
946
1052
  getBranches: () => {
@@ -961,7 +1067,7 @@ var makeDummyThreadStore = () => {
961
1067
  }));
962
1068
  };
963
1069
  var useDummyAIAssistantContext = () => {
964
- const [context] = useState2(() => {
1070
+ const [context] = useState3(() => {
965
1071
  const useThread = makeDummyThreadStore();
966
1072
  const useViewport = makeViewportStore();
967
1073
  const useComposer = makeThreadComposerStore(useThread);
@@ -971,7 +1077,7 @@ var useDummyAIAssistantContext = () => {
971
1077
  };
972
1078
 
973
1079
  // src/adapters/vercel/useVercelAIThreadState.tsx
974
- import { useCallback as useCallback2, useMemo as useMemo3, useRef as useRef6, useState as useState3 } from "react";
1080
+ import { useCallback as useCallback2, useMemo as useMemo5, useRef as useRef6, useState as useState4 } from "react";
975
1081
 
976
1082
  // src/adapters/MessageRepository.tsx
977
1083
  import { customAlphabet } from "nanoid/non-secure";
@@ -990,7 +1096,41 @@ var MessageRepository = class {
990
1096
  messages = /* @__PURE__ */ new Map();
991
1097
  // message_id -> item
992
1098
  head = null;
993
- rootChildren = [];
1099
+ root = {
1100
+ children: []
1101
+ };
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
+ performOp(newParent, child, operation) {
1112
+ const parentOrRoot = child.prev ?? this.root;
1113
+ const newParentOrRoot = newParent ?? this.root;
1114
+ if (operation === "relink" && parentOrRoot === newParentOrRoot) return;
1115
+ if (operation !== "link") {
1116
+ parentOrRoot.children = parentOrRoot.children.filter(
1117
+ (m) => m !== child.current.id
1118
+ );
1119
+ if (child.prev?.next === child) {
1120
+ child.prev.next = this.getFallbackChild(child.prev);
1121
+ }
1122
+ }
1123
+ if (operation !== "cut") {
1124
+ newParentOrRoot.children = [
1125
+ ...newParentOrRoot.children,
1126
+ child.current.id
1127
+ ];
1128
+ if (newParent && (findHead(child) === this.head || newParent.next === null)) {
1129
+ newParent.next = child;
1130
+ }
1131
+ child.prev = newParent;
1132
+ }
1133
+ }
994
1134
  getMessages() {
995
1135
  const messages = new Array(this.head?.level ?? 0);
996
1136
  for (let current = this.head; current; current = current.prev) {
@@ -999,20 +1139,17 @@ var MessageRepository = class {
999
1139
  return messages;
1000
1140
  }
1001
1141
  addOrUpdateMessage(parentId, message) {
1002
- const item = this.messages.get(message.id);
1003
- if (item) {
1004
- if ((item.prev?.current.id ?? null) !== parentId) {
1005
- this.deleteMessage(message.id);
1006
- } else {
1007
- item.current = message;
1008
- return;
1009
- }
1010
- }
1142
+ const existingItem = this.messages.get(message.id);
1011
1143
  const prev = parentId ? this.messages.get(parentId) : null;
1012
1144
  if (prev === void 0)
1013
1145
  throw new Error(
1014
1146
  "MessageRepository(addOrUpdateMessage): Parent message not found. This is likely an internal bug in assistant-ui."
1015
1147
  );
1148
+ if (existingItem) {
1149
+ existingItem.current = message;
1150
+ this.performOp(prev, existingItem, "relink");
1151
+ return;
1152
+ }
1016
1153
  const newItem = {
1017
1154
  prev,
1018
1155
  current: message,
@@ -1021,80 +1158,56 @@ var MessageRepository = class {
1021
1158
  level: prev ? prev.level + 1 : 0
1022
1159
  };
1023
1160
  this.messages.set(message.id, newItem);
1024
- if (prev) {
1025
- prev.children = [...prev.children, message.id];
1026
- prev.next = newItem;
1027
- } else {
1028
- this.rootChildren = [...this.rootChildren, message.id];
1029
- }
1030
1161
  if (this.head === prev) {
1031
1162
  this.head = newItem;
1032
1163
  }
1164
+ this.performOp(prev, newItem, "link");
1033
1165
  }
1034
- deleteMessage(messageId) {
1035
- const message = this.messages.get(messageId);
1036
- if (!message)
1037
- throw new Error(
1038
- "MessageRepository(deleteMessage): Message not found. This is likely an internal bug in assistant-ui."
1039
- );
1040
- if (message.children.length > 0) {
1041
- for (const child of message.children) {
1042
- this.deleteMessage(child);
1043
- }
1044
- }
1045
- this.messages.delete(messageId);
1046
- if (message.prev) {
1047
- message.prev.children = message.prev.children.filter(
1048
- (m) => m !== messageId
1049
- );
1050
- if (message.prev.next === message) {
1051
- const childId = message.prev.children.at(-1);
1052
- const child = childId ? this.messages.get(childId) : null;
1053
- if (child === void 0)
1054
- throw new Error(
1055
- "MessageRepository(deleteMessage): Child message not found. This is likely an internal bug in assistant-ui."
1056
- );
1057
- message.prev.next = child;
1058
- }
1059
- } else {
1060
- this.rootChildren = this.rootChildren.filter((m) => m !== messageId);
1061
- }
1062
- if (this.head === message) {
1063
- this.head = message.prev ? findHead(message.prev) : null;
1064
- }
1065
- }
1066
- getOptimisticId() {
1166
+ appendOptimisticMessage(parentId, message) {
1067
1167
  let optimisticId;
1068
1168
  do {
1069
1169
  optimisticId = generateOptimisticId();
1070
1170
  } while (this.messages.has(optimisticId));
1071
- return optimisticId;
1072
- }
1073
- commitOptimisticRun(parentId) {
1074
- const optimisticId = this.getOptimisticId();
1075
1171
  this.addOrUpdateMessage(parentId, {
1172
+ ...message,
1076
1173
  id: optimisticId,
1077
- role: "assistant",
1078
- content: [
1079
- {
1080
- type: "text",
1081
- text: ""
1082
- }
1083
- ],
1084
1174
  createdAt: /* @__PURE__ */ new Date()
1085
1175
  });
1086
1176
  return optimisticId;
1087
1177
  }
1178
+ deleteMessage(messageId, newParentId) {
1179
+ const message = this.messages.get(messageId);
1180
+ const newParent = newParentId ? this.messages.get(newParentId) : null;
1181
+ if (!message)
1182
+ throw new Error(
1183
+ "MessageRepository(deleteMessage): Optimistic message not found. This is likely an internal bug in assistant-ui."
1184
+ );
1185
+ if (newParent === void 0)
1186
+ throw new Error(
1187
+ "MessageRepository(deleteMessage): New message not found. This is likely an internal bug in assistant-ui."
1188
+ );
1189
+ for (const child of message.children) {
1190
+ const childMessage = this.messages.get(child);
1191
+ if (!childMessage)
1192
+ throw new Error(
1193
+ "MessageRepository(deleteMessage): Child message not found. This is likely an internal bug in assistant-ui."
1194
+ );
1195
+ this.performOp(newParent, childMessage, "relink");
1196
+ }
1197
+ this.messages.delete(messageId);
1198
+ if (this.head === message) {
1199
+ this.head = this.getFallbackChild(message.prev ?? this.root);
1200
+ }
1201
+ this.performOp(null, message, "cut");
1202
+ }
1088
1203
  getBranches(messageId) {
1089
1204
  const message = this.messages.get(messageId);
1090
1205
  if (!message)
1091
1206
  throw new Error(
1092
1207
  "MessageRepository(getBranches): Message not found. This is likely an internal bug in assistant-ui."
1093
1208
  );
1094
- if (message.prev) {
1095
- return message.prev.children;
1096
- }
1097
- return this.rootChildren;
1209
+ const { children } = message.prev ?? this.root;
1210
+ return children;
1098
1211
  }
1099
1212
  switchToBranch(messageId) {
1100
1213
  const message = this.messages.get(messageId);
@@ -1108,20 +1221,20 @@ var MessageRepository = class {
1108
1221
  this.head = findHead(message);
1109
1222
  }
1110
1223
  resetHead(messageId) {
1111
- if (messageId) {
1112
- const message = this.messages.get(messageId);
1113
- if (!message)
1114
- throw new Error(
1115
- "MessageRepository(resetHead): Branch not found. This is likely an internal bug in assistant-ui."
1116
- );
1117
- this.head = message;
1118
- for (let current = message; current; current = current.prev) {
1119
- if (current.prev) {
1120
- current.prev.next = current;
1121
- }
1122
- }
1123
- } else {
1224
+ if (messageId === null) {
1124
1225
  this.head = null;
1226
+ return;
1227
+ }
1228
+ const message = this.messages.get(messageId);
1229
+ if (!message)
1230
+ throw new Error(
1231
+ "MessageRepository(resetHead): Branch not found. This is likely an internal bug in assistant-ui."
1232
+ );
1233
+ this.head = message;
1234
+ for (let current = message; current; current = current.prev) {
1235
+ if (current.prev) {
1236
+ current.prev.next = current;
1237
+ }
1125
1238
  }
1126
1239
  }
1127
1240
  };
@@ -1185,12 +1298,12 @@ var getIsRunning = (vercel) => {
1185
1298
  return vercel.status === "in_progress";
1186
1299
  };
1187
1300
  var useVercelAIThreadState = (vercel) => {
1188
- const [data] = useState3(() => new MessageRepository());
1301
+ const [data] = useState4(() => new MessageRepository());
1189
1302
  const vercelRef = useRef6(vercel);
1190
1303
  vercelRef.current = vercel;
1191
1304
  const isRunning = getIsRunning(vercelRef.current);
1192
1305
  const assistantOptimisticIdRef = useRef6(null);
1193
- const messages = useMemo3(() => {
1306
+ const messages = useMemo5(() => {
1194
1307
  const vm = converter.convertMessages(vercel.messages);
1195
1308
  for (let i = 0; i < vm.length; i++) {
1196
1309
  const message = vm[i];
@@ -1198,12 +1311,16 @@ var useVercelAIThreadState = (vercel) => {
1198
1311
  data.addOrUpdateMessage(parent?.id ?? null, message);
1199
1312
  }
1200
1313
  if (assistantOptimisticIdRef.current) {
1201
- data.deleteMessage(assistantOptimisticIdRef.current);
1314
+ data.deleteMessage(assistantOptimisticIdRef.current, null);
1202
1315
  assistantOptimisticIdRef.current = null;
1203
1316
  }
1204
1317
  if (hasUpcomingMessage(isRunning, vm)) {
1205
- assistantOptimisticIdRef.current = data.commitOptimisticRun(
1206
- vm.at(-1)?.id ?? null
1318
+ assistantOptimisticIdRef.current = data.appendOptimisticMessage(
1319
+ vm.at(-1)?.id ?? null,
1320
+ {
1321
+ role: "assistant",
1322
+ content: [{ type: "text", text: "" }]
1323
+ }
1207
1324
  );
1208
1325
  }
1209
1326
  data.resetHead(assistantOptimisticIdRef.current ?? vm.at(-1)?.id ?? null);
@@ -1257,7 +1374,7 @@ var useVercelAIThreadState = (vercel) => {
1257
1374
  vercelRef.current.setInput(lastMessage.content);
1258
1375
  }
1259
1376
  }, []);
1260
- return useMemo3(
1377
+ return useMemo5(
1261
1378
  () => ({
1262
1379
  isRunning,
1263
1380
  messages,
@@ -1280,7 +1397,7 @@ var useVercelAIThreadState = (vercel) => {
1280
1397
  };
1281
1398
 
1282
1399
  // src/adapters/vercel/VercelAIAssistantProvider.tsx
1283
- import { jsx as jsx19 } from "react/jsx-runtime";
1400
+ import { jsx as jsx21 } from "react/jsx-runtime";
1284
1401
  var VercelAIAssistantProvider = ({
1285
1402
  children,
1286
1403
  ...rest
@@ -1288,25 +1405,25 @@ var VercelAIAssistantProvider = ({
1288
1405
  const context = useDummyAIAssistantContext();
1289
1406
  const vercel = "chat" in rest ? rest.chat : rest.assistant;
1290
1407
  const threadState = useVercelAIThreadState(vercel);
1291
- useMemo4(() => {
1408
+ useMemo6(() => {
1292
1409
  context.useThread.setState(threadState, true);
1293
1410
  }, [context, threadState]);
1294
- useMemo4(() => {
1411
+ useMemo6(() => {
1295
1412
  context.useComposer.setState({
1296
1413
  value: vercel.input,
1297
1414
  setValue: vercel.setInput
1298
1415
  });
1299
1416
  }, [context, vercel.input, vercel.setInput]);
1300
- return /* @__PURE__ */ jsx19(AssistantContext.Provider, { value: context, children });
1417
+ return /* @__PURE__ */ jsx21(AssistantContext.Provider, { value: context, children });
1301
1418
  };
1302
1419
 
1303
1420
  // src/adapters/vercel/VercelRSCAssistantProvider.tsx
1304
1421
  import {
1305
1422
  useCallback as useCallback3,
1306
- useMemo as useMemo5,
1307
- useState as useState4
1423
+ useMemo as useMemo7,
1424
+ useState as useState5
1308
1425
  } from "react";
1309
- import { jsx as jsx20 } from "react/jsx-runtime";
1426
+ import { jsx as jsx22 } from "react/jsx-runtime";
1310
1427
  var vercelToThreadMessage2 = (message) => {
1311
1428
  return {
1312
1429
  id: message.id,
@@ -1340,18 +1457,18 @@ var VercelRSCAssistantProvider = ({
1340
1457
  reload
1341
1458
  }) => {
1342
1459
  const context = useDummyAIAssistantContext();
1343
- const [isRunning, setIsRunning] = useState4(false);
1460
+ const [isRunning, setIsRunning] = useState5(false);
1344
1461
  const withRunning = useCallback3((callback) => {
1345
1462
  setIsRunning(true);
1346
1463
  return callback.finally(() => setIsRunning(false));
1347
1464
  }, []);
1348
- const converter2 = useMemo5(() => {
1465
+ const converter2 = useMemo7(() => {
1349
1466
  const rscConverter = convertMessage ?? ((m) => m);
1350
1467
  return new ThreadMessageConverter((m) => {
1351
1468
  return vercelToThreadMessage2(rscConverter(m));
1352
1469
  });
1353
1470
  }, [convertMessage]);
1354
- const messages = useMemo5(() => {
1471
+ const messages = useMemo7(() => {
1355
1472
  return converter2.convertMessages(vercelMessages);
1356
1473
  }, [converter2, vercelMessages]);
1357
1474
  const append = useCallback3(
@@ -1378,7 +1495,7 @@ var VercelRSCAssistantProvider = ({
1378
1495
  },
1379
1496
  [withRunning, reload]
1380
1497
  );
1381
- useMemo5(() => {
1498
+ useMemo7(() => {
1382
1499
  context.useThread.setState(
1383
1500
  {
1384
1501
  messages,
@@ -1392,12 +1509,13 @@ var VercelRSCAssistantProvider = ({
1392
1509
  true
1393
1510
  );
1394
1511
  }, [context, messages, isRunning, append, startRun]);
1395
- return /* @__PURE__ */ jsx20(AssistantContext.Provider, { value: context, children });
1512
+ return /* @__PURE__ */ jsx22(AssistantContext.Provider, { value: context, children });
1396
1513
  };
1397
1514
  export {
1398
1515
  actionBar_exports as ActionBarPrimitive,
1399
1516
  branchPicker_exports as BranchPickerPrimitive,
1400
1517
  composer_exports as ComposerPrimitive,
1518
+ contentPart_exports as ContentPartPrimitive,
1401
1519
  message_exports as MessagePrimitive,
1402
1520
  thread_exports as ThreadPrimitive,
1403
1521
  VercelAIAssistantProvider,