@assistant-ui/react 0.0.12 → 0.0.14

Sign up to get free protection for your applications and to get access to all the features.
package/dist/index.js CHANGED
@@ -54,6 +54,7 @@ __export(thread_exports, {
54
54
  Messages: () => ThreadMessages,
55
55
  Root: () => ThreadRoot,
56
56
  ScrollToBottom: () => ThreadScrollToBottom,
57
+ Suggestion: () => ThreadSuggestion,
57
58
  Viewport: () => ThreadViewport
58
59
  });
59
60
 
@@ -74,7 +75,7 @@ var useAssistantContext = () => {
74
75
  const context = (0, import_react2.useContext)(AssistantContext);
75
76
  if (!context)
76
77
  throw new Error(
77
- "useAssistantContext must be used within a AssistantProvider"
78
+ "This component must be used within a AssistantProvider"
78
79
  );
79
80
  return context;
80
81
  };
@@ -224,7 +225,7 @@ var MessageContext = (0, import_react6.createContext)(null);
224
225
  var useMessageContext = () => {
225
226
  const context = (0, import_react6.useContext)(MessageContext);
226
227
  if (!context)
227
- throw new Error("useMessageContext must be used within a MessageProvider");
228
+ throw new Error("This component must be used within a MessageProvider");
228
229
  return context;
229
230
  };
230
231
 
@@ -329,6 +330,7 @@ var useMessageContext2 = () => {
329
330
  const [context] = (0, import_react8.useState)(() => {
330
331
  const useMessage = (0, import_zustand2.create)(() => ({
331
332
  message: null,
333
+ parentId: null,
332
334
  branches: [],
333
335
  isLast: false,
334
336
  isCopied: false,
@@ -343,15 +345,19 @@ var useMessageContext2 = () => {
343
345
  const message = useMessage.getState().message;
344
346
  if (message.role !== "user")
345
347
  throw new Error("Editing is only supported for user messages");
346
- if (message.content[0]?.type !== "text")
347
- throw new Error("Editing is only supported for text-only messages");
348
- return message.content[0].text;
348
+ const text = message.content.filter((part) => part.type === "text").map((part) => part.text).join("\n");
349
+ return text;
349
350
  },
350
351
  onSend: (text) => {
351
- const message = useMessage.getState().message;
352
+ const { message, parentId } = useMessage.getState();
353
+ if (message.role !== "user")
354
+ throw new Error("Editing is only supported for user messages");
355
+ const nonTextParts = message.content.filter(
356
+ (part) => part.type !== "text" && part.type !== "ui"
357
+ );
352
358
  useThread.getState().append({
353
- parentId: message.parentId,
354
- content: [{ type: "text", text }]
359
+ parentId,
360
+ content: [{ type: "text", text }, ...nonTextParts]
355
361
  });
356
362
  }
357
363
  });
@@ -361,6 +367,7 @@ var useMessageContext2 = () => {
361
367
  };
362
368
  var MessageProvider = ({
363
369
  message,
370
+ parentId,
364
371
  children
365
372
  }) => {
366
373
  const { useThread } = useAssistantContext();
@@ -373,6 +380,7 @@ var MessageProvider = ({
373
380
  context.useMessage.setState(
374
381
  {
375
382
  message,
383
+ parentId,
376
384
  branches,
377
385
  isLast,
378
386
  isCopied,
@@ -382,7 +390,7 @@ var MessageProvider = ({
382
390
  },
383
391
  true
384
392
  );
385
- }, [context, message, branches, isLast, isCopied, isHovering]);
393
+ }, [context, message, parentId, branches, isLast, isCopied, isHovering]);
386
394
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(MessageContext.Provider, { value: context, children });
387
395
  };
388
396
 
@@ -493,15 +501,21 @@ var ThreadMessages = ({ components }) => {
493
501
  if (messages.length === 0)
494
502
  return null;
495
503
  return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_jsx_runtime7.Fragment, { children: messages.map((message, idx) => {
496
- return (
497
- // biome-ignore lint/suspicious/noArrayIndexKey: fixes a11y issues with branch navigation
498
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(MessageProvider, { message, children: [
499
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(MessageIf, { user: true, children: [
500
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ComposerIf, { editing: false, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(UserMessage, {}) }),
501
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ComposerIf, { editing: true, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(EditComposer, {}) })
502
- ] }),
503
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(MessageIf, { assistant: true, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(AssistantMessage, {}) })
504
- ] }, idx)
504
+ const parentId = messages[idx - 1]?.id ?? null;
505
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
506
+ MessageProvider,
507
+ {
508
+ message,
509
+ parentId,
510
+ children: [
511
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(MessageIf, { user: true, children: [
512
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ComposerIf, { editing: false, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(UserMessage, {}) }),
513
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ComposerIf, { editing: true, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(EditComposer, {}) })
514
+ ] }),
515
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(MessageIf, { assistant: true, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(AssistantMessage, {}) })
516
+ ]
517
+ },
518
+ parentId ?? "__ROOT__"
505
519
  );
506
520
  }) });
507
521
  };
@@ -528,6 +542,33 @@ var ThreadScrollToBottom = (0, import_react10.forwardRef)(({ onClick, ...rest },
528
542
  );
529
543
  });
530
544
 
545
+ // src/primitives/thread/ThreadSuggestion.tsx
546
+ var import_primitive4 = require("@radix-ui/primitive");
547
+ var import_react_primitive5 = require("@radix-ui/react-primitive");
548
+ var import_react11 = require("react");
549
+ var import_jsx_runtime9 = require("react/jsx-runtime");
550
+ var ThreadSuggestion = (0, import_react11.forwardRef)(({ onClick, prompt, method, autoSend: send, ...rest }, ref) => {
551
+ const { useThread, useComposer } = useAssistantContext();
552
+ const isDisabled = useThread((t) => t.isRunning);
553
+ const handleApplySuggestion = () => {
554
+ const thread = useThread.getState();
555
+ const composer = useComposer.getState();
556
+ composer.setValue(prompt);
557
+ if (send && !thread.isRunning) {
558
+ composer.send();
559
+ }
560
+ };
561
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
562
+ import_react_primitive5.Primitive.button,
563
+ {
564
+ ...rest,
565
+ disabled: isDisabled,
566
+ ref,
567
+ onClick: (0, import_primitive4.composeEventHandlers)(onClick, handleApplySuggestion)
568
+ }
569
+ );
570
+ });
571
+
531
572
  // src/primitives/composer/index.ts
532
573
  var composer_exports = {};
533
574
  __export(composer_exports, {
@@ -539,16 +580,16 @@ __export(composer_exports, {
539
580
  });
540
581
 
541
582
  // src/primitives/composer/ComposerRoot.tsx
542
- var import_primitive4 = require("@radix-ui/primitive");
583
+ var import_primitive5 = require("@radix-ui/primitive");
543
584
  var import_react_compose_refs2 = require("@radix-ui/react-compose-refs");
544
- var import_react_primitive5 = require("@radix-ui/react-primitive");
545
- var import_react11 = require("react");
546
- var import_jsx_runtime9 = require("react/jsx-runtime");
547
- var ComposerRoot = (0, import_react11.forwardRef)(
585
+ var import_react_primitive6 = require("@radix-ui/react-primitive");
586
+ var import_react12 = require("react");
587
+ var import_jsx_runtime10 = require("react/jsx-runtime");
588
+ var ComposerRoot = (0, import_react12.forwardRef)(
548
589
  ({ onSubmit, ...rest }, forwardedRef) => {
549
590
  const { useViewport } = useAssistantContext();
550
591
  const { useComposer } = useComposerContext();
551
- const formRef = (0, import_react11.useRef)(null);
592
+ const formRef = (0, import_react12.useRef)(null);
552
593
  const ref = (0, import_react_compose_refs2.useComposedRefs)(forwardedRef, formRef);
553
594
  const handleSubmit = (e) => {
554
595
  const composerState = useComposer.getState();
@@ -558,26 +599,26 @@ var ComposerRoot = (0, import_react11.forwardRef)(
558
599
  composerState.send();
559
600
  useViewport.getState().scrollToBottom();
560
601
  };
561
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
562
- import_react_primitive5.Primitive.form,
602
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
603
+ import_react_primitive6.Primitive.form,
563
604
  {
564
605
  ...rest,
565
606
  ref,
566
- onSubmit: (0, import_primitive4.composeEventHandlers)(onSubmit, handleSubmit)
607
+ onSubmit: (0, import_primitive5.composeEventHandlers)(onSubmit, handleSubmit)
567
608
  }
568
609
  );
569
610
  }
570
611
  );
571
612
 
572
613
  // src/primitives/composer/ComposerInput.tsx
573
- var import_primitive5 = require("@radix-ui/primitive");
614
+ var import_primitive6 = require("@radix-ui/primitive");
574
615
  var import_react_compose_refs3 = require("@radix-ui/react-compose-refs");
575
616
  var import_react_slot = require("@radix-ui/react-slot");
576
- var import_react12 = require("react");
617
+ var import_react13 = require("react");
577
618
  var import_react_textarea_autosize = __toESM(require("react-textarea-autosize"));
578
- var import_jsx_runtime10 = require("react/jsx-runtime");
579
- var ComposerInput = (0, import_react12.forwardRef)(
580
- ({ autoFocus, asChild, disabled, onChange, onKeyDown, ...rest }, forwardedRef) => {
619
+ var import_jsx_runtime11 = require("react/jsx-runtime");
620
+ var ComposerInput = (0, import_react13.forwardRef)(
621
+ ({ autoFocus = false, asChild, disabled, onChange, onKeyDown, ...rest }, forwardedRef) => {
581
622
  const { useThread, useViewport } = useAssistantContext();
582
623
  const { useComposer, type } = useComposerContext();
583
624
  const value = useComposer((c) => {
@@ -603,10 +644,10 @@ var ComposerInput = (0, import_react12.forwardRef)(
603
644
  }
604
645
  }
605
646
  };
606
- const textareaRef = (0, import_react12.useRef)(null);
647
+ const textareaRef = (0, import_react13.useRef)(null);
607
648
  const ref = (0, import_react_compose_refs3.useComposedRefs)(forwardedRef, textareaRef);
608
- const autoFocusEnabled = autoFocus !== false && !disabled;
609
- const focus = (0, import_react12.useCallback)(() => {
649
+ const autoFocusEnabled = autoFocus && !disabled;
650
+ const focus = (0, import_react13.useCallback)(() => {
610
651
  const textarea = textareaRef.current;
611
652
  if (!textarea || !autoFocusEnabled)
612
653
  return;
@@ -616,41 +657,41 @@ var ComposerInput = (0, import_react12.forwardRef)(
616
657
  textareaRef.current.value.length
617
658
  );
618
659
  }, [autoFocusEnabled]);
619
- (0, import_react12.useEffect)(() => focus(), [focus]);
660
+ (0, import_react13.useEffect)(() => focus(), [focus]);
620
661
  useOnScrollToBottom(() => {
621
662
  if (type === "assistant") {
622
663
  focus();
623
664
  }
624
665
  });
625
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
666
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
626
667
  Component,
627
668
  {
628
669
  value,
629
670
  ...rest,
630
671
  ref,
631
672
  disabled,
632
- onChange: (0, import_primitive5.composeEventHandlers)(onChange, (e) => {
673
+ onChange: (0, import_primitive6.composeEventHandlers)(onChange, (e) => {
633
674
  const composerState = useComposer.getState();
634
675
  if (!composerState.isEditing)
635
676
  return;
636
677
  return composerState.setValue(e.target.value);
637
678
  }),
638
- onKeyDown: (0, import_primitive5.composeEventHandlers)(onKeyDown, handleKeyPress)
679
+ onKeyDown: (0, import_primitive6.composeEventHandlers)(onKeyDown, handleKeyPress)
639
680
  }
640
681
  );
641
682
  }
642
683
  );
643
684
 
644
685
  // src/primitives/composer/ComposerSend.tsx
645
- var import_react_primitive6 = require("@radix-ui/react-primitive");
646
- var import_react13 = require("react");
647
- var import_jsx_runtime11 = require("react/jsx-runtime");
648
- var ComposerSend = (0, import_react13.forwardRef)(
686
+ var import_react_primitive7 = require("@radix-ui/react-primitive");
687
+ var import_react14 = require("react");
688
+ var import_jsx_runtime12 = require("react/jsx-runtime");
689
+ var ComposerSend = (0, import_react14.forwardRef)(
649
690
  ({ disabled, ...rest }, ref) => {
650
691
  const { useComposer } = useComposerContext();
651
692
  const hasValue = useComposer((c) => c.isEditing && c.value.length > 0);
652
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
653
- import_react_primitive6.Primitive.button,
693
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
694
+ import_react_primitive7.Primitive.button,
654
695
  {
655
696
  type: "submit",
656
697
  ...rest,
@@ -662,22 +703,22 @@ var ComposerSend = (0, import_react13.forwardRef)(
662
703
  );
663
704
 
664
705
  // src/primitives/composer/ComposerCancel.tsx
665
- var import_primitive6 = require("@radix-ui/primitive");
666
- var import_react_primitive7 = require("@radix-ui/react-primitive");
667
- var import_react14 = require("react");
668
- var import_jsx_runtime12 = require("react/jsx-runtime");
669
- var ComposerCancel = (0, import_react14.forwardRef)(({ onClick, ...rest }, ref) => {
706
+ var import_primitive7 = require("@radix-ui/primitive");
707
+ var import_react_primitive8 = require("@radix-ui/react-primitive");
708
+ var import_react15 = require("react");
709
+ var import_jsx_runtime13 = require("react/jsx-runtime");
710
+ var ComposerCancel = (0, import_react15.forwardRef)(({ onClick, ...rest }, ref) => {
670
711
  const { useComposer } = useComposerContext();
671
712
  const handleCancel = () => {
672
713
  useComposer.getState().cancel();
673
714
  };
674
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
675
- import_react_primitive7.Primitive.button,
715
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
716
+ import_react_primitive8.Primitive.button,
676
717
  {
677
718
  type: "button",
678
719
  ...rest,
679
720
  ref,
680
- onClick: (0, import_primitive6.composeEventHandlers)(onClick, handleCancel)
721
+ onClick: (0, import_primitive7.composeEventHandlers)(onClick, handleCancel)
681
722
  }
682
723
  );
683
724
  });
@@ -693,10 +734,10 @@ __export(branchPicker_exports, {
693
734
  });
694
735
 
695
736
  // src/utils/context/combined/useCombinedStore.ts
696
- var import_react16 = require("react");
737
+ var import_react17 = require("react");
697
738
 
698
739
  // src/utils/context/combined/createCombinedStore.ts
699
- var import_react15 = require("react");
740
+ var import_react16 = require("react");
700
741
  var createCombinedStore = (stores) => {
701
742
  const subscribe = (callback) => {
702
743
  const unsubscribes = stores.map((store) => store.subscribe(callback));
@@ -708,13 +749,13 @@ var createCombinedStore = (stores) => {
708
749
  };
709
750
  return (selector) => {
710
751
  const getSnapshot = () => selector(...stores.map((store) => store.getState()));
711
- return (0, import_react15.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
752
+ return (0, import_react16.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
712
753
  };
713
754
  };
714
755
 
715
756
  // src/utils/context/combined/useCombinedStore.ts
716
757
  var useCombinedStore = (stores, selector) => {
717
- const useCombined = (0, import_react16.useMemo)(() => createCombinedStore(stores), stores);
758
+ const useCombined = (0, import_react17.useMemo)(() => createCombinedStore(stores), stores);
718
759
  return useCombined(selector);
719
760
  };
720
761
 
@@ -735,22 +776,22 @@ var useGoToNextBranch = () => {
735
776
  };
736
777
 
737
778
  // src/utils/createActionButton.tsx
738
- var import_primitive7 = require("@radix-ui/primitive");
739
- var import_react_primitive8 = require("@radix-ui/react-primitive");
740
- var import_react17 = require("react");
741
- var import_jsx_runtime13 = require("react/jsx-runtime");
779
+ var import_primitive8 = require("@radix-ui/primitive");
780
+ var import_react_primitive9 = require("@radix-ui/react-primitive");
781
+ var import_react18 = require("react");
782
+ var import_jsx_runtime14 = require("react/jsx-runtime");
742
783
  var createActionButton = (useActionButton) => {
743
- return (0, import_react17.forwardRef)(
784
+ return (0, import_react18.forwardRef)(
744
785
  (props, forwardedRef) => {
745
786
  const onClick = useActionButton(props);
746
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
747
- import_react_primitive8.Primitive.button,
787
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
788
+ import_react_primitive9.Primitive.button,
748
789
  {
749
790
  type: "button",
750
791
  disabled: !onClick,
751
792
  ...props,
752
793
  ref: forwardedRef,
753
- onClick: (0, import_primitive7.composeEventHandlers)(props.onClick, onClick ?? void 0)
794
+ onClick: (0, import_primitive8.composeEventHandlers)(props.onClick, onClick ?? void 0)
754
795
  }
755
796
  );
756
797
  }
@@ -783,27 +824,27 @@ var useGoToPreviousBranch = () => {
783
824
  var BranchPickerPrevious = createActionButton(useGoToPreviousBranch);
784
825
 
785
826
  // src/primitives/branchPicker/BranchPickerCount.tsx
786
- var import_jsx_runtime14 = require("react/jsx-runtime");
827
+ var import_jsx_runtime15 = require("react/jsx-runtime");
787
828
  var BranchPickerCount = () => {
788
829
  const { useMessage } = useMessageContext();
789
830
  const branchCount = useMessage((s) => s.branches.length);
790
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_jsx_runtime14.Fragment, { children: branchCount });
831
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_jsx_runtime15.Fragment, { children: branchCount });
791
832
  };
792
833
 
793
834
  // src/primitives/branchPicker/BranchPickerNumber.tsx
794
- var import_jsx_runtime15 = require("react/jsx-runtime");
835
+ var import_jsx_runtime16 = require("react/jsx-runtime");
795
836
  var BranchPickerNumber = () => {
796
837
  const { useMessage } = useMessageContext();
797
838
  const branchIdx = useMessage((s) => s.branches.indexOf(s.message.id));
798
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_jsx_runtime15.Fragment, { children: branchIdx + 1 });
839
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_jsx_runtime16.Fragment, { children: branchIdx + 1 });
799
840
  };
800
841
 
801
842
  // src/primitives/branchPicker/BranchPickerRoot.tsx
802
- var import_react_primitive9 = require("@radix-ui/react-primitive");
803
- var import_react18 = require("react");
804
- var import_jsx_runtime16 = require("react/jsx-runtime");
805
- var BranchPickerRoot = (0, import_react18.forwardRef)(({ hideWhenSingleBranch, ...rest }, ref) => {
806
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(MessageIf, { hasBranches: hideWhenSingleBranch ? true : void 0, children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_react_primitive9.Primitive.div, { ...rest, ref }) });
843
+ var import_react_primitive10 = require("@radix-ui/react-primitive");
844
+ var import_react19 = require("react");
845
+ var import_jsx_runtime17 = require("react/jsx-runtime");
846
+ var BranchPickerRoot = (0, import_react19.forwardRef)(({ hideWhenSingleBranch, ...rest }, ref) => {
847
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(MessageIf, { hasBranches: hideWhenSingleBranch ? true : void 0, children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_react_primitive10.Primitive.div, { ...rest, ref }) });
807
848
  });
808
849
 
809
850
  // src/primitives/actionBar/index.ts
@@ -816,10 +857,10 @@ __export(actionBar_exports, {
816
857
  });
817
858
 
818
859
  // src/primitives/actionBar/ActionBarRoot.tsx
819
- var import_react_primitive10 = require("@radix-ui/react-primitive");
820
- var import_react19 = require("react");
821
- var import_jsx_runtime17 = require("react/jsx-runtime");
822
- var ActionBarRoot = (0, import_react19.forwardRef)(({ hideWhenRunning, autohide, autohideFloat, ...rest }, ref) => {
860
+ var import_react_primitive11 = require("@radix-ui/react-primitive");
861
+ var import_react20 = require("react");
862
+ var import_jsx_runtime18 = require("react/jsx-runtime");
863
+ var ActionBarRoot = (0, import_react20.forwardRef)(({ hideWhenRunning, autohide, autohideFloat, ...rest }, ref) => {
823
864
  const { useThread } = useAssistantContext();
824
865
  const { useMessage } = useMessageContext();
825
866
  const hideAndfloatStatus = useCombinedStore(
@@ -839,8 +880,8 @@ var ActionBarRoot = (0, import_react19.forwardRef)(({ hideWhenRunning, autohide,
839
880
  );
840
881
  if (hideAndfloatStatus === "hidden" /* Hidden */)
841
882
  return null;
842
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
843
- import_react_primitive10.Primitive.div,
883
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
884
+ import_react_primitive11.Primitive.div,
844
885
  {
845
886
  "data-floating": hideAndfloatStatus === "floating" /* Floating */,
846
887
  ...rest,
@@ -879,10 +920,10 @@ var useReloadMessage = () => {
879
920
  if (disabled)
880
921
  return null;
881
922
  return () => {
882
- const message = useMessage.getState().message;
923
+ const { message, parentId } = useMessage.getState();
883
924
  if (message.role !== "assistant")
884
925
  throw new Error("Reloading is only supported on assistant messages");
885
- useThread.getState().startRun(message.parentId);
926
+ useThread.getState().startRun(parentId);
886
927
  useViewport.getState().scrollToBottom();
887
928
  };
888
929
  };
@@ -909,10 +950,10 @@ var useBeginMessageEdit = () => {
909
950
  var ActionBarEdit = createActionButton(useBeginMessageEdit);
910
951
 
911
952
  // src/adapters/vercel/VercelAIAssistantProvider.tsx
912
- var import_react22 = require("react");
953
+ var import_react23 = require("react");
913
954
 
914
955
  // src/adapters/vercel/useDummyAIAssistantContext.tsx
915
- var import_react20 = require("react");
956
+ var import_react21 = require("react");
916
957
  var import_zustand4 = require("zustand");
917
958
 
918
959
  // src/utils/context/stores/ViewportStore.tsx
@@ -958,7 +999,7 @@ var makeDummyThreadStore = () => {
958
999
  }));
959
1000
  };
960
1001
  var useDummyAIAssistantContext = () => {
961
- const [context] = (0, import_react20.useState)(() => {
1002
+ const [context] = (0, import_react21.useState)(() => {
962
1003
  const useThread = makeDummyThreadStore();
963
1004
  const useViewport = makeViewportStore();
964
1005
  const useComposer = makeThreadComposerStore(useThread);
@@ -967,8 +1008,8 @@ var useDummyAIAssistantContext = () => {
967
1008
  return context;
968
1009
  };
969
1010
 
970
- // src/adapters/vercel/useVercelAIBranches.tsx
971
- var import_react21 = require("react");
1011
+ // src/adapters/vercel/useVercelAIThreadState.tsx
1012
+ var import_react22 = require("react");
972
1013
 
973
1014
  // src/adapters/MessageRepository.tsx
974
1015
  var import_non_secure = require("nanoid/non-secure");
@@ -996,17 +1037,26 @@ var MessageRepository = class {
996
1037
  }
997
1038
  return messages;
998
1039
  }
999
- addOrUpdateMessage(message) {
1040
+ // TODO previousId is confusing
1041
+ // TODO previousId does not fix children
1042
+ // TODO cut / link operations
1043
+ addOrUpdateMessage(parentId, message, previousId = message.id) {
1000
1044
  const item = this.messages.get(message.id);
1001
1045
  if (item) {
1002
- if (item.current.parentId !== message.parentId) {
1003
- this.deleteMessage(message.id);
1004
- } else {
1005
- item.current = message;
1006
- return;
1046
+ if (item.prev?.current.id !== parentId) {
1047
+ if ((item.prev?.current.id ?? null) !== parentId) {
1048
+ this.deleteMessage(message.id);
1049
+ } else {
1050
+ item.current = message;
1051
+ if (previousId !== message.id) {
1052
+ this.messages.delete(previousId);
1053
+ this.messages.set(message.id, item);
1054
+ }
1055
+ return;
1056
+ }
1007
1057
  }
1008
1058
  }
1009
- const prev = message.parentId ? this.messages.get(message.parentId) : null;
1059
+ const prev = parentId ? this.messages.get(parentId) : null;
1010
1060
  if (prev === void 0)
1011
1061
  throw new Error("Unexpected: Parent message not found");
1012
1062
  const newItem = {
@@ -1055,16 +1105,27 @@ var MessageRepository = class {
1055
1105
  this.head = message.prev ? findHead(message.prev) : null;
1056
1106
  }
1057
1107
  }
1058
- getOptimisticId = () => {
1108
+ getOptimisticId() {
1059
1109
  let optimisticId;
1060
1110
  do {
1061
1111
  optimisticId = generateOptimisticId();
1062
1112
  } while (this.messages.has(optimisticId));
1063
1113
  return optimisticId;
1064
- };
1114
+ }
1115
+ commitOptimisticAppend(message) {
1116
+ const optimisticIdUser = this.getOptimisticId();
1117
+ this.addOrUpdateMessage(message.parentId, {
1118
+ id: optimisticIdUser,
1119
+ role: "user",
1120
+ content: message.content,
1121
+ createdAt: /* @__PURE__ */ new Date()
1122
+ });
1123
+ const optimisticIdAssistant = this.commitOptimisticRun(optimisticIdUser);
1124
+ return [optimisticIdUser, optimisticIdAssistant];
1125
+ }
1065
1126
  commitOptimisticRun(parentId) {
1066
1127
  const optimisticId = this.getOptimisticId();
1067
- this.addOrUpdateMessage({
1128
+ this.addOrUpdateMessage(parentId, {
1068
1129
  id: optimisticId,
1069
1130
  role: "assistant",
1070
1131
  content: [
@@ -1073,7 +1134,6 @@ var MessageRepository = class {
1073
1134
  text: ""
1074
1135
  }
1075
1136
  ],
1076
- parentId,
1077
1137
  createdAt: /* @__PURE__ */ new Date()
1078
1138
  });
1079
1139
  return optimisticId;
@@ -1113,7 +1173,37 @@ var MessageRepository = class {
1113
1173
  }
1114
1174
  };
1115
1175
 
1116
- // src/adapters/vercel/useVercelAIBranches.tsx
1176
+ // src/adapters/ThreadMessageConverter.tsx
1177
+ var ThreadMessageConverter = class {
1178
+ constructor(converter2) {
1179
+ this.converter = converter2;
1180
+ }
1181
+ cache = /* @__PURE__ */ new WeakMap();
1182
+ convertMessages(messages) {
1183
+ return messages.map((m) => {
1184
+ const cached = this.cache.get(m);
1185
+ if (cached)
1186
+ return cached;
1187
+ const newMessage = this.converter(m);
1188
+ this.cache.set(m, newMessage);
1189
+ return newMessage;
1190
+ });
1191
+ }
1192
+ };
1193
+
1194
+ // src/adapters/vercel/useVercelAIThreadState.tsx
1195
+ var vercelToThreadMessage = (message) => {
1196
+ if (message.role !== "user" && message.role !== "assistant")
1197
+ throw new Error("Unsupported role");
1198
+ return {
1199
+ id: message.id,
1200
+ role: message.role,
1201
+ content: [{ type: "text", text: message.content }],
1202
+ createdAt: message.createdAt ?? /* @__PURE__ */ new Date(),
1203
+ innerMessage: message
1204
+ };
1205
+ };
1206
+ var converter = new ThreadMessageConverter(vercelToThreadMessage);
1117
1207
  var sliceMessagesUntil = (messages, messageId) => {
1118
1208
  if (messageId == null)
1119
1209
  return [];
@@ -1127,195 +1217,188 @@ var sliceMessagesUntil = (messages, messageId) => {
1127
1217
  var hasUpcomingMessage = (isRunning, messages) => {
1128
1218
  return isRunning && messages[messages.length - 1]?.role !== "assistant";
1129
1219
  };
1130
- var useVercelAIBranches = (chat, messages) => {
1131
- const [data] = (0, import_react21.useState)(() => new MessageRepository());
1132
- const isRunning = "isLoading" in chat ? chat.isLoading : chat.status === "in_progress";
1133
- const assistantOptimisticIdRef = (0, import_react21.useRef)(null);
1134
- const messagesEx = (0, import_react21.useMemo)(() => {
1135
- for (const message of messages) {
1136
- data.addOrUpdateMessage(message);
1220
+ var getIsRunning = (vercel) => {
1221
+ if ("isLoading" in vercel)
1222
+ return vercel.isLoading;
1223
+ return vercel.status === "in_progress";
1224
+ };
1225
+ var useVercelAIThreadState = (vercel) => {
1226
+ const [data] = (0, import_react22.useState)(() => new MessageRepository());
1227
+ const vercelRef = (0, import_react22.useRef)(vercel);
1228
+ vercelRef.current = vercel;
1229
+ const isRunning = getIsRunning(vercelRef.current);
1230
+ const assistantOptimisticIdRef = (0, import_react22.useRef)(null);
1231
+ const messages = (0, import_react22.useMemo)(() => {
1232
+ const vm = converter.convertMessages(vercel.messages);
1233
+ for (let i = 0; i < vm.length; i++) {
1234
+ const message = vm[i];
1235
+ const parent = vm[i - 1];
1236
+ data.addOrUpdateMessage(parent?.id ?? null, message);
1137
1237
  }
1138
1238
  if (assistantOptimisticIdRef.current) {
1139
1239
  data.deleteMessage(assistantOptimisticIdRef.current);
1140
1240
  assistantOptimisticIdRef.current = null;
1141
1241
  }
1142
- if (hasUpcomingMessage(isRunning, messages)) {
1242
+ if (hasUpcomingMessage(isRunning, vm)) {
1143
1243
  assistantOptimisticIdRef.current = data.commitOptimisticRun(
1144
- messages.at(-1)?.id ?? null
1244
+ vm.at(-1)?.id ?? null
1145
1245
  );
1146
1246
  }
1147
- data.resetHead(
1148
- assistantOptimisticIdRef.current ?? messages.at(-1)?.id ?? null
1149
- );
1247
+ data.resetHead(assistantOptimisticIdRef.current ?? vm.at(-1)?.id ?? null);
1150
1248
  return data.getMessages();
1151
- }, [data, isRunning, messages]);
1152
- const getBranches = (0, import_react21.useCallback)(
1249
+ }, [data, isRunning, vercel.messages]);
1250
+ const getBranches = (0, import_react22.useCallback)(
1153
1251
  (messageId) => {
1154
1252
  return data.getBranches(messageId);
1155
1253
  },
1156
1254
  [data]
1157
1255
  );
1158
- const switchToBranch = (0, import_react21.useCallback)(
1256
+ const switchToBranch = (0, import_react22.useCallback)(
1159
1257
  (messageId) => {
1160
1258
  data.switchToBranch(messageId);
1161
- chat.setMessages(
1259
+ vercelRef.current.setMessages(
1162
1260
  data.getMessages().filter((m) => !isOptimisticId(m.id)).map((m) => m.innerMessage)
1163
1261
  );
1164
1262
  },
1165
- [data, chat.setMessages]
1166
- );
1167
- const reloadMaybe = "reload" in chat ? chat.reload : void 0;
1168
- const startRun = (0, import_react21.useCallback)(
1169
- async (parentId) => {
1170
- if (!reloadMaybe)
1171
- throw new Error("Reload not supported by Vercel AI SDK's useAssistant");
1172
- const newMessages = sliceMessagesUntil(chat.messages, parentId);
1173
- chat.setMessages(newMessages);
1174
- await reloadMaybe();
1175
- },
1176
- [chat.messages, chat.setMessages, reloadMaybe]
1177
- );
1178
- const append = (0, import_react21.useCallback)(
1179
- async (message) => {
1180
- if (message.content.length !== 1 || message.content[0]?.type !== "text")
1181
- throw new Error("Only text content is supported by Vercel AI SDK");
1182
- const newMessages = sliceMessagesUntil(chat.messages, message.parentId);
1183
- chat.setMessages(newMessages);
1184
- await chat.append({
1185
- role: "user",
1186
- content: message.content[0].text
1187
- });
1188
- },
1189
- [chat.messages, chat.setMessages, chat.append]
1263
+ [data]
1190
1264
  );
1191
- return (0, import_react21.useMemo)(
1265
+ const startRun = (0, import_react22.useCallback)(async (parentId) => {
1266
+ const reloadMaybe = "reload" in vercelRef.current ? vercelRef.current.reload : void 0;
1267
+ if (!reloadMaybe)
1268
+ throw new Error("Reload not supported by Vercel AI SDK's useAssistant");
1269
+ const newMessages = sliceMessagesUntil(
1270
+ vercelRef.current.messages,
1271
+ parentId
1272
+ );
1273
+ vercelRef.current.setMessages(newMessages);
1274
+ await reloadMaybe();
1275
+ }, []);
1276
+ const append = (0, import_react22.useCallback)(async (message) => {
1277
+ if (message.content.length !== 1 || message.content[0]?.type !== "text")
1278
+ throw new Error("Only text content is supported by Vercel AI SDK");
1279
+ const newMessages = sliceMessagesUntil(
1280
+ vercelRef.current.messages,
1281
+ message.parentId
1282
+ );
1283
+ vercelRef.current.setMessages(newMessages);
1284
+ await vercelRef.current.append({
1285
+ role: "user",
1286
+ content: message.content[0].text
1287
+ });
1288
+ }, []);
1289
+ const cancelRun = (0, import_react22.useCallback)(() => {
1290
+ const lastMessage = vercelRef.current.messages.at(-1);
1291
+ vercelRef.current.stop();
1292
+ if (lastMessage?.role === "user") {
1293
+ vercelRef.current.setInput(lastMessage.content);
1294
+ }
1295
+ }, []);
1296
+ return (0, import_react22.useMemo)(
1192
1297
  () => ({
1193
- messages: messagesEx,
1298
+ isRunning,
1299
+ messages,
1194
1300
  getBranches,
1195
1301
  switchToBranch,
1196
1302
  append,
1197
- startRun
1303
+ startRun,
1304
+ cancelRun
1198
1305
  }),
1199
- [messagesEx, getBranches, switchToBranch, append, startRun]
1306
+ [
1307
+ isRunning,
1308
+ messages,
1309
+ getBranches,
1310
+ switchToBranch,
1311
+ append,
1312
+ startRun,
1313
+ cancelRun
1314
+ ]
1200
1315
  );
1201
1316
  };
1202
1317
 
1203
1318
  // src/adapters/vercel/VercelAIAssistantProvider.tsx
1204
- var import_jsx_runtime18 = require("react/jsx-runtime");
1205
- var ThreadMessageCache = /* @__PURE__ */ new WeakMap();
1206
- var vercelToThreadMessage = (message, parentId) => {
1207
- if (message.role !== "user" && message.role !== "assistant")
1208
- throw new Error("Unsupported role");
1209
- return {
1210
- parentId,
1211
- id: message.id,
1212
- role: message.role,
1213
- content: [{ type: "text", text: message.content }],
1214
- createdAt: message.createdAt ?? /* @__PURE__ */ new Date(),
1215
- innerMessage: message
1216
- };
1217
- };
1218
- var vercelToCachedThreadMessages = (messages) => {
1219
- return messages.map((m, idx) => {
1220
- const cached = ThreadMessageCache.get(m);
1221
- const parentId = messages[idx - 1]?.id ?? null;
1222
- if (cached && cached.parentId === parentId)
1223
- return cached;
1224
- const newMessage = vercelToThreadMessage(m, parentId);
1225
- ThreadMessageCache.set(m, newMessage);
1226
- return newMessage;
1227
- });
1228
- };
1319
+ var import_jsx_runtime19 = require("react/jsx-runtime");
1229
1320
  var VercelAIAssistantProvider = ({
1230
1321
  children,
1231
1322
  ...rest
1232
1323
  }) => {
1233
1324
  const context = useDummyAIAssistantContext();
1234
1325
  const vercel = "chat" in rest ? rest.chat : rest.assistant;
1235
- const messages = (0, import_react22.useMemo)(() => {
1236
- return vercelToCachedThreadMessages(vercel.messages);
1237
- }, [vercel.messages]);
1238
- const branches = useVercelAIBranches(vercel, messages);
1239
- const cancelRun = (0, import_react22.useCallback)(() => {
1240
- const lastMessage = vercel.messages.at(-1);
1241
- vercel.stop();
1242
- if (lastMessage?.role === "user") {
1243
- vercel.setInput(lastMessage.content);
1244
- }
1245
- }, [vercel.messages, vercel.stop, vercel.setInput]);
1246
- const isRunning = "isLoading" in vercel ? vercel.isLoading : vercel.status === "in_progress";
1247
- (0, import_react22.useMemo)(() => {
1248
- context.useThread.setState(
1249
- {
1250
- messages: branches.messages,
1251
- isRunning,
1252
- getBranches: branches.getBranches,
1253
- switchToBranch: branches.switchToBranch,
1254
- append: branches.append,
1255
- startRun: branches.startRun,
1256
- cancelRun
1257
- },
1258
- true
1259
- );
1260
- }, [context, isRunning, cancelRun, branches]);
1261
- (0, import_react22.useMemo)(() => {
1326
+ const threadState = useVercelAIThreadState(vercel);
1327
+ (0, import_react23.useMemo)(() => {
1328
+ context.useThread.setState(threadState, true);
1329
+ }, [context, threadState]);
1330
+ (0, import_react23.useMemo)(() => {
1262
1331
  context.useComposer.setState({
1263
1332
  value: vercel.input,
1264
1333
  setValue: vercel.setInput
1265
1334
  });
1266
1335
  }, [context, vercel.input, vercel.setInput]);
1267
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(AssistantContext.Provider, { value: context, children });
1336
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(AssistantContext.Provider, { value: context, children });
1268
1337
  };
1269
1338
 
1270
1339
  // src/adapters/vercel/VercelRSCAssistantProvider.tsx
1271
- var import_react23 = require("react");
1272
- var import_jsx_runtime19 = require("react/jsx-runtime");
1273
- var ThreadMessageCache2 = /* @__PURE__ */ new WeakMap();
1274
- var vercelToThreadMessage2 = (parentId, message) => {
1340
+ var import_react24 = require("react");
1341
+ var import_jsx_runtime20 = require("react/jsx-runtime");
1342
+ var vercelToThreadMessage2 = (message) => {
1275
1343
  if (message.role !== "user" && message.role !== "assistant")
1276
1344
  throw new Error("Unsupported role");
1277
1345
  return {
1278
- parentId,
1279
1346
  id: message.id,
1280
1347
  role: message.role,
1281
1348
  content: [{ type: "ui", display: message.display }],
1282
1349
  createdAt: message.createdAt ?? /* @__PURE__ */ new Date()
1283
1350
  };
1284
1351
  };
1285
- var vercelToCachedThreadMessages2 = (messages) => {
1286
- return messages.map((m, idx) => {
1287
- const cached = ThreadMessageCache2.get(m);
1288
- const parentId = messages[idx - 1]?.id ?? null;
1289
- if (cached && cached.parentId === parentId)
1290
- return cached;
1291
- const newMessage = vercelToThreadMessage2(parentId, m);
1292
- ThreadMessageCache2.set(m, newMessage);
1293
- return newMessage;
1294
- });
1295
- };
1296
- var VercelRSCAssistantProvider = ({ children, messages: vercelMessages, append: vercelAppend }) => {
1352
+ var VercelRSCAssistantProvider = ({
1353
+ children,
1354
+ convertMessage,
1355
+ messages: vercelMessages,
1356
+ append: appendCallback,
1357
+ edit,
1358
+ reload
1359
+ }) => {
1297
1360
  const context = useDummyAIAssistantContext();
1298
- const messages = (0, import_react23.useMemo)(() => {
1299
- return vercelToCachedThreadMessages2(vercelMessages);
1300
- }, [vercelMessages]);
1301
- const append = (0, import_react23.useCallback)(
1361
+ const converter2 = (0, import_react24.useMemo)(() => {
1362
+ const rscConverter = convertMessage ?? ((m) => m);
1363
+ return new ThreadMessageConverter((m) => {
1364
+ return vercelToThreadMessage2(rscConverter(m));
1365
+ });
1366
+ }, [convertMessage]);
1367
+ const messages = (0, import_react24.useMemo)(() => {
1368
+ return converter2.convertMessages(vercelMessages);
1369
+ }, [converter2, vercelMessages]);
1370
+ const append = (0, import_react24.useCallback)(
1302
1371
  async (message) => {
1303
- if (message.parentId !== (context.useThread.getState().messages.at(-1)?.id ?? null))
1304
- throw new Error("Unexpected: Message editing is not supported");
1305
- if (message.content[0]?.type !== "text") {
1306
- throw new Error("Only text content is currently supported");
1372
+ if (message.parentId !== (context.useThread.getState().messages.at(-1)?.id ?? null)) {
1373
+ if (!edit)
1374
+ throw new Error(
1375
+ "Unexpected: Message editing is not supported, no edit callback was provided to VercelRSCAssistantProvider."
1376
+ );
1377
+ await edit(message);
1378
+ } else {
1379
+ await appendCallback(message);
1307
1380
  }
1308
- await vercelAppend(message);
1309
1381
  },
1310
- [context, vercelAppend]
1382
+ [context, appendCallback, edit]
1311
1383
  );
1312
- (0, import_react23.useMemo)(() => {
1384
+ const startRun = (0, import_react24.useCallback)(
1385
+ async (parentId) => {
1386
+ if (!reload)
1387
+ throw new Error(
1388
+ "Unexpected: Message reloading is not supported, no reload callback was provided to VercelRSCAssistantProvider."
1389
+ );
1390
+ await reload(parentId);
1391
+ },
1392
+ [reload]
1393
+ );
1394
+ (0, import_react24.useMemo)(() => {
1313
1395
  context.useThread.setState({
1314
1396
  messages,
1315
- append
1397
+ append,
1398
+ startRun
1316
1399
  });
1317
- }, [context, messages, append]);
1318
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(AssistantContext.Provider, { value: context, children });
1400
+ }, [context, messages, append, startRun]);
1401
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(AssistantContext.Provider, { value: context, children });
1319
1402
  };
1320
1403
  // Annotate the CommonJS export names for ESM import in node:
1321
1404
  0 && (module.exports = {