@assistant-ui/react 0.0.15 → 0.0.16

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.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,