@assistant-ui/react 0.0.12 → 0.0.14

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.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 = {