@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.mjs CHANGED
@@ -12,6 +12,7 @@ __export(thread_exports, {
12
12
  Messages: () => ThreadMessages,
13
13
  Root: () => ThreadRoot,
14
14
  ScrollToBottom: () => ThreadScrollToBottom,
15
+ Suggestion: () => ThreadSuggestion,
15
16
  Viewport: () => ThreadViewport
16
17
  });
17
18
 
@@ -34,7 +35,7 @@ var useAssistantContext = () => {
34
35
  const context = useContext(AssistantContext);
35
36
  if (!context)
36
37
  throw new Error(
37
- "useAssistantContext must be used within a AssistantProvider"
38
+ "This component must be used within a AssistantProvider"
38
39
  );
39
40
  return context;
40
41
  };
@@ -186,7 +187,7 @@ var MessageContext = createContext2(null);
186
187
  var useMessageContext = () => {
187
188
  const context = useContext2(MessageContext);
188
189
  if (!context)
189
- throw new Error("useMessageContext must be used within a MessageProvider");
190
+ throw new Error("This component must be used within a MessageProvider");
190
191
  return context;
191
192
  };
192
193
 
@@ -293,6 +294,7 @@ var useMessageContext2 = () => {
293
294
  const [context] = useState(() => {
294
295
  const useMessage = create2(() => ({
295
296
  message: null,
297
+ parentId: null,
296
298
  branches: [],
297
299
  isLast: false,
298
300
  isCopied: false,
@@ -307,15 +309,19 @@ var useMessageContext2 = () => {
307
309
  const message = useMessage.getState().message;
308
310
  if (message.role !== "user")
309
311
  throw new Error("Editing is only supported for user messages");
310
- if (message.content[0]?.type !== "text")
311
- throw new Error("Editing is only supported for text-only messages");
312
- return message.content[0].text;
312
+ const text = message.content.filter((part) => part.type === "text").map((part) => part.text).join("\n");
313
+ return text;
313
314
  },
314
315
  onSend: (text) => {
315
- const message = useMessage.getState().message;
316
+ const { message, parentId } = useMessage.getState();
317
+ if (message.role !== "user")
318
+ throw new Error("Editing is only supported for user messages");
319
+ const nonTextParts = message.content.filter(
320
+ (part) => part.type !== "text" && part.type !== "ui"
321
+ );
316
322
  useThread.getState().append({
317
- parentId: message.parentId,
318
- content: [{ type: "text", text }]
323
+ parentId,
324
+ content: [{ type: "text", text }, ...nonTextParts]
319
325
  });
320
326
  }
321
327
  });
@@ -325,6 +331,7 @@ var useMessageContext2 = () => {
325
331
  };
326
332
  var MessageProvider = ({
327
333
  message,
334
+ parentId,
328
335
  children
329
336
  }) => {
330
337
  const { useThread } = useAssistantContext();
@@ -337,6 +344,7 @@ var MessageProvider = ({
337
344
  context.useMessage.setState(
338
345
  {
339
346
  message,
347
+ parentId,
340
348
  branches,
341
349
  isLast,
342
350
  isCopied,
@@ -346,7 +354,7 @@ var MessageProvider = ({
346
354
  },
347
355
  true
348
356
  );
349
- }, [context, message, branches, isLast, isCopied, isHovering]);
357
+ }, [context, message, parentId, branches, isLast, isCopied, isHovering]);
350
358
  return /* @__PURE__ */ jsx4(MessageContext.Provider, { value: context, children });
351
359
  };
352
360
 
@@ -459,15 +467,21 @@ var ThreadMessages = ({ components }) => {
459
467
  if (messages.length === 0)
460
468
  return null;
461
469
  return /* @__PURE__ */ jsx7(Fragment2, { children: messages.map((message, idx) => {
462
- return (
463
- // biome-ignore lint/suspicious/noArrayIndexKey: fixes a11y issues with branch navigation
464
- /* @__PURE__ */ jsxs2(MessageProvider, { message, children: [
465
- /* @__PURE__ */ jsxs2(MessageIf, { user: true, children: [
466
- /* @__PURE__ */ jsx7(ComposerIf, { editing: false, children: /* @__PURE__ */ jsx7(UserMessage, {}) }),
467
- /* @__PURE__ */ jsx7(ComposerIf, { editing: true, children: /* @__PURE__ */ jsx7(EditComposer, {}) })
468
- ] }),
469
- /* @__PURE__ */ jsx7(MessageIf, { assistant: true, children: /* @__PURE__ */ jsx7(AssistantMessage, {}) })
470
- ] }, idx)
470
+ const parentId = messages[idx - 1]?.id ?? null;
471
+ return /* @__PURE__ */ jsxs2(
472
+ MessageProvider,
473
+ {
474
+ message,
475
+ parentId,
476
+ children: [
477
+ /* @__PURE__ */ jsxs2(MessageIf, { user: true, children: [
478
+ /* @__PURE__ */ jsx7(ComposerIf, { editing: false, children: /* @__PURE__ */ jsx7(UserMessage, {}) }),
479
+ /* @__PURE__ */ jsx7(ComposerIf, { editing: true, children: /* @__PURE__ */ jsx7(EditComposer, {}) })
480
+ ] }),
481
+ /* @__PURE__ */ jsx7(MessageIf, { assistant: true, children: /* @__PURE__ */ jsx7(AssistantMessage, {}) })
482
+ ]
483
+ },
484
+ parentId ?? "__ROOT__"
471
485
  );
472
486
  }) });
473
487
  };
@@ -496,6 +510,35 @@ var ThreadScrollToBottom = forwardRef4(({ onClick, ...rest }, ref) => {
496
510
  );
497
511
  });
498
512
 
513
+ // src/primitives/thread/ThreadSuggestion.tsx
514
+ import { composeEventHandlers as composeEventHandlers4 } from "@radix-ui/primitive";
515
+ import {
516
+ Primitive as Primitive5
517
+ } from "@radix-ui/react-primitive";
518
+ import { forwardRef as forwardRef5 } from "react";
519
+ import { jsx as jsx9 } from "react/jsx-runtime";
520
+ var ThreadSuggestion = forwardRef5(({ onClick, prompt, method, autoSend: send, ...rest }, ref) => {
521
+ const { useThread, useComposer } = useAssistantContext();
522
+ const isDisabled = useThread((t) => t.isRunning);
523
+ const handleApplySuggestion = () => {
524
+ const thread = useThread.getState();
525
+ const composer = useComposer.getState();
526
+ composer.setValue(prompt);
527
+ if (send && !thread.isRunning) {
528
+ composer.send();
529
+ }
530
+ };
531
+ return /* @__PURE__ */ jsx9(
532
+ Primitive5.button,
533
+ {
534
+ ...rest,
535
+ disabled: isDisabled,
536
+ ref,
537
+ onClick: composeEventHandlers4(onClick, handleApplySuggestion)
538
+ }
539
+ );
540
+ });
541
+
499
542
  // src/primitives/composer/index.ts
500
543
  var composer_exports = {};
501
544
  __export(composer_exports, {
@@ -507,14 +550,14 @@ __export(composer_exports, {
507
550
  });
508
551
 
509
552
  // src/primitives/composer/ComposerRoot.tsx
510
- import { composeEventHandlers as composeEventHandlers4 } from "@radix-ui/primitive";
553
+ import { composeEventHandlers as composeEventHandlers5 } from "@radix-ui/primitive";
511
554
  import { useComposedRefs as useComposedRefs2 } from "@radix-ui/react-compose-refs";
512
555
  import {
513
- Primitive as Primitive5
556
+ Primitive as Primitive6
514
557
  } from "@radix-ui/react-primitive";
515
- import { forwardRef as forwardRef5, useRef as useRef4 } from "react";
516
- import { jsx as jsx9 } from "react/jsx-runtime";
517
- var ComposerRoot = forwardRef5(
558
+ import { forwardRef as forwardRef6, useRef as useRef4 } from "react";
559
+ import { jsx as jsx10 } from "react/jsx-runtime";
560
+ var ComposerRoot = forwardRef6(
518
561
  ({ onSubmit, ...rest }, forwardedRef) => {
519
562
  const { useViewport } = useAssistantContext();
520
563
  const { useComposer } = useComposerContext();
@@ -528,31 +571,31 @@ var ComposerRoot = forwardRef5(
528
571
  composerState.send();
529
572
  useViewport.getState().scrollToBottom();
530
573
  };
531
- return /* @__PURE__ */ jsx9(
532
- Primitive5.form,
574
+ return /* @__PURE__ */ jsx10(
575
+ Primitive6.form,
533
576
  {
534
577
  ...rest,
535
578
  ref,
536
- onSubmit: composeEventHandlers4(onSubmit, handleSubmit)
579
+ onSubmit: composeEventHandlers5(onSubmit, handleSubmit)
537
580
  }
538
581
  );
539
582
  }
540
583
  );
541
584
 
542
585
  // src/primitives/composer/ComposerInput.tsx
543
- import { composeEventHandlers as composeEventHandlers5 } from "@radix-ui/primitive";
586
+ import { composeEventHandlers as composeEventHandlers6 } from "@radix-ui/primitive";
544
587
  import { useComposedRefs as useComposedRefs3 } from "@radix-ui/react-compose-refs";
545
588
  import { Slot } from "@radix-ui/react-slot";
546
589
  import {
547
- forwardRef as forwardRef6,
590
+ forwardRef as forwardRef7,
548
591
  useCallback,
549
592
  useEffect as useEffect2,
550
593
  useRef as useRef5
551
594
  } from "react";
552
595
  import TextareaAutosize from "react-textarea-autosize";
553
- import { jsx as jsx10 } from "react/jsx-runtime";
554
- var ComposerInput = forwardRef6(
555
- ({ autoFocus, asChild, disabled, onChange, onKeyDown, ...rest }, forwardedRef) => {
596
+ import { jsx as jsx11 } from "react/jsx-runtime";
597
+ var ComposerInput = forwardRef7(
598
+ ({ autoFocus = false, asChild, disabled, onChange, onKeyDown, ...rest }, forwardedRef) => {
556
599
  const { useThread, useViewport } = useAssistantContext();
557
600
  const { useComposer, type } = useComposerContext();
558
601
  const value = useComposer((c) => {
@@ -580,7 +623,7 @@ var ComposerInput = forwardRef6(
580
623
  };
581
624
  const textareaRef = useRef5(null);
582
625
  const ref = useComposedRefs3(forwardedRef, textareaRef);
583
- const autoFocusEnabled = autoFocus !== false && !disabled;
626
+ const autoFocusEnabled = autoFocus && !disabled;
584
627
  const focus = useCallback(() => {
585
628
  const textarea = textareaRef.current;
586
629
  if (!textarea || !autoFocusEnabled)
@@ -597,20 +640,20 @@ var ComposerInput = forwardRef6(
597
640
  focus();
598
641
  }
599
642
  });
600
- return /* @__PURE__ */ jsx10(
643
+ return /* @__PURE__ */ jsx11(
601
644
  Component,
602
645
  {
603
646
  value,
604
647
  ...rest,
605
648
  ref,
606
649
  disabled,
607
- onChange: composeEventHandlers5(onChange, (e) => {
650
+ onChange: composeEventHandlers6(onChange, (e) => {
608
651
  const composerState = useComposer.getState();
609
652
  if (!composerState.isEditing)
610
653
  return;
611
654
  return composerState.setValue(e.target.value);
612
655
  }),
613
- onKeyDown: composeEventHandlers5(onKeyDown, handleKeyPress)
656
+ onKeyDown: composeEventHandlers6(onKeyDown, handleKeyPress)
614
657
  }
615
658
  );
616
659
  }
@@ -618,16 +661,16 @@ var ComposerInput = forwardRef6(
618
661
 
619
662
  // src/primitives/composer/ComposerSend.tsx
620
663
  import {
621
- Primitive as Primitive6
664
+ Primitive as Primitive7
622
665
  } from "@radix-ui/react-primitive";
623
- import { forwardRef as forwardRef7 } from "react";
624
- import { jsx as jsx11 } from "react/jsx-runtime";
625
- var ComposerSend = forwardRef7(
666
+ import { forwardRef as forwardRef8 } from "react";
667
+ import { jsx as jsx12 } from "react/jsx-runtime";
668
+ var ComposerSend = forwardRef8(
626
669
  ({ disabled, ...rest }, ref) => {
627
670
  const { useComposer } = useComposerContext();
628
671
  const hasValue = useComposer((c) => c.isEditing && c.value.length > 0);
629
- return /* @__PURE__ */ jsx11(
630
- Primitive6.button,
672
+ return /* @__PURE__ */ jsx12(
673
+ Primitive7.button,
631
674
  {
632
675
  type: "submit",
633
676
  ...rest,
@@ -639,24 +682,24 @@ var ComposerSend = forwardRef7(
639
682
  );
640
683
 
641
684
  // src/primitives/composer/ComposerCancel.tsx
642
- import { composeEventHandlers as composeEventHandlers6 } from "@radix-ui/primitive";
685
+ import { composeEventHandlers as composeEventHandlers7 } from "@radix-ui/primitive";
643
686
  import {
644
- Primitive as Primitive7
687
+ Primitive as Primitive8
645
688
  } from "@radix-ui/react-primitive";
646
- import { forwardRef as forwardRef8 } from "react";
647
- import { jsx as jsx12 } from "react/jsx-runtime";
648
- var ComposerCancel = forwardRef8(({ onClick, ...rest }, ref) => {
689
+ import { forwardRef as forwardRef9 } from "react";
690
+ import { jsx as jsx13 } from "react/jsx-runtime";
691
+ var ComposerCancel = forwardRef9(({ onClick, ...rest }, ref) => {
649
692
  const { useComposer } = useComposerContext();
650
693
  const handleCancel = () => {
651
694
  useComposer.getState().cancel();
652
695
  };
653
- return /* @__PURE__ */ jsx12(
654
- Primitive7.button,
696
+ return /* @__PURE__ */ jsx13(
697
+ Primitive8.button,
655
698
  {
656
699
  type: "button",
657
700
  ...rest,
658
701
  ref,
659
- onClick: composeEventHandlers6(onClick, handleCancel)
702
+ onClick: composeEventHandlers7(onClick, handleCancel)
660
703
  }
661
704
  );
662
705
  });
@@ -714,24 +757,24 @@ var useGoToNextBranch = () => {
714
757
  };
715
758
 
716
759
  // src/utils/createActionButton.tsx
717
- import { composeEventHandlers as composeEventHandlers7 } from "@radix-ui/primitive";
760
+ import { composeEventHandlers as composeEventHandlers8 } from "@radix-ui/primitive";
718
761
  import {
719
- Primitive as Primitive8
762
+ Primitive as Primitive9
720
763
  } from "@radix-ui/react-primitive";
721
- import { forwardRef as forwardRef9 } from "react";
722
- import { jsx as jsx13 } from "react/jsx-runtime";
764
+ import { forwardRef as forwardRef10 } from "react";
765
+ import { jsx as jsx14 } from "react/jsx-runtime";
723
766
  var createActionButton = (useActionButton) => {
724
- return forwardRef9(
767
+ return forwardRef10(
725
768
  (props, forwardedRef) => {
726
769
  const onClick = useActionButton(props);
727
- return /* @__PURE__ */ jsx13(
728
- Primitive8.button,
770
+ return /* @__PURE__ */ jsx14(
771
+ Primitive9.button,
729
772
  {
730
773
  type: "button",
731
774
  disabled: !onClick,
732
775
  ...props,
733
776
  ref: forwardedRef,
734
- onClick: composeEventHandlers7(props.onClick, onClick ?? void 0)
777
+ onClick: composeEventHandlers8(props.onClick, onClick ?? void 0)
735
778
  }
736
779
  );
737
780
  }
@@ -764,29 +807,29 @@ var useGoToPreviousBranch = () => {
764
807
  var BranchPickerPrevious = createActionButton(useGoToPreviousBranch);
765
808
 
766
809
  // src/primitives/branchPicker/BranchPickerCount.tsx
767
- import { Fragment as Fragment3, jsx as jsx14 } from "react/jsx-runtime";
810
+ import { Fragment as Fragment3, jsx as jsx15 } from "react/jsx-runtime";
768
811
  var BranchPickerCount = () => {
769
812
  const { useMessage } = useMessageContext();
770
813
  const branchCount = useMessage((s) => s.branches.length);
771
- return /* @__PURE__ */ jsx14(Fragment3, { children: branchCount });
814
+ return /* @__PURE__ */ jsx15(Fragment3, { children: branchCount });
772
815
  };
773
816
 
774
817
  // src/primitives/branchPicker/BranchPickerNumber.tsx
775
- import { Fragment as Fragment4, jsx as jsx15 } from "react/jsx-runtime";
818
+ import { Fragment as Fragment4, jsx as jsx16 } from "react/jsx-runtime";
776
819
  var BranchPickerNumber = () => {
777
820
  const { useMessage } = useMessageContext();
778
821
  const branchIdx = useMessage((s) => s.branches.indexOf(s.message.id));
779
- return /* @__PURE__ */ jsx15(Fragment4, { children: branchIdx + 1 });
822
+ return /* @__PURE__ */ jsx16(Fragment4, { children: branchIdx + 1 });
780
823
  };
781
824
 
782
825
  // src/primitives/branchPicker/BranchPickerRoot.tsx
783
826
  import {
784
- Primitive as Primitive9
827
+ Primitive as Primitive10
785
828
  } from "@radix-ui/react-primitive";
786
- import { forwardRef as forwardRef10 } from "react";
787
- import { jsx as jsx16 } from "react/jsx-runtime";
788
- var BranchPickerRoot = forwardRef10(({ hideWhenSingleBranch, ...rest }, ref) => {
789
- return /* @__PURE__ */ jsx16(MessageIf, { hasBranches: hideWhenSingleBranch ? true : void 0, children: /* @__PURE__ */ jsx16(Primitive9.div, { ...rest, ref }) });
829
+ import { forwardRef as forwardRef11 } from "react";
830
+ import { jsx as jsx17 } from "react/jsx-runtime";
831
+ var BranchPickerRoot = forwardRef11(({ hideWhenSingleBranch, ...rest }, ref) => {
832
+ return /* @__PURE__ */ jsx17(MessageIf, { hasBranches: hideWhenSingleBranch ? true : void 0, children: /* @__PURE__ */ jsx17(Primitive10.div, { ...rest, ref }) });
790
833
  });
791
834
 
792
835
  // src/primitives/actionBar/index.ts
@@ -800,11 +843,11 @@ __export(actionBar_exports, {
800
843
 
801
844
  // src/primitives/actionBar/ActionBarRoot.tsx
802
845
  import {
803
- Primitive as Primitive10
846
+ Primitive as Primitive11
804
847
  } from "@radix-ui/react-primitive";
805
- import { forwardRef as forwardRef11 } from "react";
806
- import { jsx as jsx17 } from "react/jsx-runtime";
807
- var ActionBarRoot = forwardRef11(({ hideWhenRunning, autohide, autohideFloat, ...rest }, ref) => {
848
+ import { forwardRef as forwardRef12 } from "react";
849
+ import { jsx as jsx18 } from "react/jsx-runtime";
850
+ var ActionBarRoot = forwardRef12(({ hideWhenRunning, autohide, autohideFloat, ...rest }, ref) => {
808
851
  const { useThread } = useAssistantContext();
809
852
  const { useMessage } = useMessageContext();
810
853
  const hideAndfloatStatus = useCombinedStore(
@@ -824,8 +867,8 @@ var ActionBarRoot = forwardRef11(({ hideWhenRunning, autohide, autohideFloat, ..
824
867
  );
825
868
  if (hideAndfloatStatus === "hidden" /* Hidden */)
826
869
  return null;
827
- return /* @__PURE__ */ jsx17(
828
- Primitive10.div,
870
+ return /* @__PURE__ */ jsx18(
871
+ Primitive11.div,
829
872
  {
830
873
  "data-floating": hideAndfloatStatus === "floating" /* Floating */,
831
874
  ...rest,
@@ -864,10 +907,10 @@ var useReloadMessage = () => {
864
907
  if (disabled)
865
908
  return null;
866
909
  return () => {
867
- const message = useMessage.getState().message;
910
+ const { message, parentId } = useMessage.getState();
868
911
  if (message.role !== "assistant")
869
912
  throw new Error("Reloading is only supported on assistant messages");
870
- useThread.getState().startRun(message.parentId);
913
+ useThread.getState().startRun(parentId);
871
914
  useViewport.getState().scrollToBottom();
872
915
  };
873
916
  };
@@ -894,7 +937,7 @@ var useBeginMessageEdit = () => {
894
937
  var ActionBarEdit = createActionButton(useBeginMessageEdit);
895
938
 
896
939
  // src/adapters/vercel/VercelAIAssistantProvider.tsx
897
- import { useCallback as useCallback3, useMemo as useMemo4 } from "react";
940
+ import { useMemo as useMemo4 } from "react";
898
941
 
899
942
  // src/adapters/vercel/useDummyAIAssistantContext.tsx
900
943
  import { useState as useState2 } from "react";
@@ -952,7 +995,7 @@ var useDummyAIAssistantContext = () => {
952
995
  return context;
953
996
  };
954
997
 
955
- // src/adapters/vercel/useVercelAIBranches.tsx
998
+ // src/adapters/vercel/useVercelAIThreadState.tsx
956
999
  import { useCallback as useCallback2, useMemo as useMemo3, useRef as useRef6, useState as useState3 } from "react";
957
1000
 
958
1001
  // src/adapters/MessageRepository.tsx
@@ -981,17 +1024,26 @@ var MessageRepository = class {
981
1024
  }
982
1025
  return messages;
983
1026
  }
984
- addOrUpdateMessage(message) {
1027
+ // TODO previousId is confusing
1028
+ // TODO previousId does not fix children
1029
+ // TODO cut / link operations
1030
+ addOrUpdateMessage(parentId, message, previousId = message.id) {
985
1031
  const item = this.messages.get(message.id);
986
1032
  if (item) {
987
- if (item.current.parentId !== message.parentId) {
988
- this.deleteMessage(message.id);
989
- } else {
990
- item.current = message;
991
- return;
1033
+ if (item.prev?.current.id !== parentId) {
1034
+ if ((item.prev?.current.id ?? null) !== parentId) {
1035
+ this.deleteMessage(message.id);
1036
+ } else {
1037
+ item.current = message;
1038
+ if (previousId !== message.id) {
1039
+ this.messages.delete(previousId);
1040
+ this.messages.set(message.id, item);
1041
+ }
1042
+ return;
1043
+ }
992
1044
  }
993
1045
  }
994
- const prev = message.parentId ? this.messages.get(message.parentId) : null;
1046
+ const prev = parentId ? this.messages.get(parentId) : null;
995
1047
  if (prev === void 0)
996
1048
  throw new Error("Unexpected: Parent message not found");
997
1049
  const newItem = {
@@ -1040,16 +1092,27 @@ var MessageRepository = class {
1040
1092
  this.head = message.prev ? findHead(message.prev) : null;
1041
1093
  }
1042
1094
  }
1043
- getOptimisticId = () => {
1095
+ getOptimisticId() {
1044
1096
  let optimisticId;
1045
1097
  do {
1046
1098
  optimisticId = generateOptimisticId();
1047
1099
  } while (this.messages.has(optimisticId));
1048
1100
  return optimisticId;
1049
- };
1101
+ }
1102
+ commitOptimisticAppend(message) {
1103
+ const optimisticIdUser = this.getOptimisticId();
1104
+ this.addOrUpdateMessage(message.parentId, {
1105
+ id: optimisticIdUser,
1106
+ role: "user",
1107
+ content: message.content,
1108
+ createdAt: /* @__PURE__ */ new Date()
1109
+ });
1110
+ const optimisticIdAssistant = this.commitOptimisticRun(optimisticIdUser);
1111
+ return [optimisticIdUser, optimisticIdAssistant];
1112
+ }
1050
1113
  commitOptimisticRun(parentId) {
1051
1114
  const optimisticId = this.getOptimisticId();
1052
- this.addOrUpdateMessage({
1115
+ this.addOrUpdateMessage(parentId, {
1053
1116
  id: optimisticId,
1054
1117
  role: "assistant",
1055
1118
  content: [
@@ -1058,7 +1121,6 @@ var MessageRepository = class {
1058
1121
  text: ""
1059
1122
  }
1060
1123
  ],
1061
- parentId,
1062
1124
  createdAt: /* @__PURE__ */ new Date()
1063
1125
  });
1064
1126
  return optimisticId;
@@ -1098,7 +1160,37 @@ var MessageRepository = class {
1098
1160
  }
1099
1161
  };
1100
1162
 
1101
- // src/adapters/vercel/useVercelAIBranches.tsx
1163
+ // src/adapters/ThreadMessageConverter.tsx
1164
+ var ThreadMessageConverter = class {
1165
+ constructor(converter2) {
1166
+ this.converter = converter2;
1167
+ }
1168
+ cache = /* @__PURE__ */ new WeakMap();
1169
+ convertMessages(messages) {
1170
+ return messages.map((m) => {
1171
+ const cached = this.cache.get(m);
1172
+ if (cached)
1173
+ return cached;
1174
+ const newMessage = this.converter(m);
1175
+ this.cache.set(m, newMessage);
1176
+ return newMessage;
1177
+ });
1178
+ }
1179
+ };
1180
+
1181
+ // src/adapters/vercel/useVercelAIThreadState.tsx
1182
+ var vercelToThreadMessage = (message) => {
1183
+ if (message.role !== "user" && message.role !== "assistant")
1184
+ throw new Error("Unsupported role");
1185
+ return {
1186
+ id: message.id,
1187
+ role: message.role,
1188
+ content: [{ type: "text", text: message.content }],
1189
+ createdAt: message.createdAt ?? /* @__PURE__ */ new Date(),
1190
+ innerMessage: message
1191
+ };
1192
+ };
1193
+ var converter = new ThreadMessageConverter(vercelToThreadMessage);
1102
1194
  var sliceMessagesUntil = (messages, messageId) => {
1103
1195
  if (messageId == null)
1104
1196
  return [];
@@ -1112,28 +1204,36 @@ var sliceMessagesUntil = (messages, messageId) => {
1112
1204
  var hasUpcomingMessage = (isRunning, messages) => {
1113
1205
  return isRunning && messages[messages.length - 1]?.role !== "assistant";
1114
1206
  };
1115
- var useVercelAIBranches = (chat, messages) => {
1207
+ var getIsRunning = (vercel) => {
1208
+ if ("isLoading" in vercel)
1209
+ return vercel.isLoading;
1210
+ return vercel.status === "in_progress";
1211
+ };
1212
+ var useVercelAIThreadState = (vercel) => {
1116
1213
  const [data] = useState3(() => new MessageRepository());
1117
- const isRunning = "isLoading" in chat ? chat.isLoading : chat.status === "in_progress";
1214
+ const vercelRef = useRef6(vercel);
1215
+ vercelRef.current = vercel;
1216
+ const isRunning = getIsRunning(vercelRef.current);
1118
1217
  const assistantOptimisticIdRef = useRef6(null);
1119
- const messagesEx = useMemo3(() => {
1120
- for (const message of messages) {
1121
- data.addOrUpdateMessage(message);
1218
+ const messages = useMemo3(() => {
1219
+ const vm = converter.convertMessages(vercel.messages);
1220
+ for (let i = 0; i < vm.length; i++) {
1221
+ const message = vm[i];
1222
+ const parent = vm[i - 1];
1223
+ data.addOrUpdateMessage(parent?.id ?? null, message);
1122
1224
  }
1123
1225
  if (assistantOptimisticIdRef.current) {
1124
1226
  data.deleteMessage(assistantOptimisticIdRef.current);
1125
1227
  assistantOptimisticIdRef.current = null;
1126
1228
  }
1127
- if (hasUpcomingMessage(isRunning, messages)) {
1229
+ if (hasUpcomingMessage(isRunning, vm)) {
1128
1230
  assistantOptimisticIdRef.current = data.commitOptimisticRun(
1129
- messages.at(-1)?.id ?? null
1231
+ vm.at(-1)?.id ?? null
1130
1232
  );
1131
1233
  }
1132
- data.resetHead(
1133
- assistantOptimisticIdRef.current ?? messages.at(-1)?.id ?? null
1134
- );
1234
+ data.resetHead(assistantOptimisticIdRef.current ?? vm.at(-1)?.id ?? null);
1135
1235
  return data.getMessages();
1136
- }, [data, isRunning, messages]);
1236
+ }, [data, isRunning, vercel.messages]);
1137
1237
  const getBranches = useCallback2(
1138
1238
  (messageId) => {
1139
1239
  return data.getBranches(messageId);
@@ -1143,167 +1243,152 @@ var useVercelAIBranches = (chat, messages) => {
1143
1243
  const switchToBranch = useCallback2(
1144
1244
  (messageId) => {
1145
1245
  data.switchToBranch(messageId);
1146
- chat.setMessages(
1246
+ vercelRef.current.setMessages(
1147
1247
  data.getMessages().filter((m) => !isOptimisticId(m.id)).map((m) => m.innerMessage)
1148
1248
  );
1149
1249
  },
1150
- [data, chat.setMessages]
1151
- );
1152
- const reloadMaybe = "reload" in chat ? chat.reload : void 0;
1153
- const startRun = useCallback2(
1154
- async (parentId) => {
1155
- if (!reloadMaybe)
1156
- throw new Error("Reload not supported by Vercel AI SDK's useAssistant");
1157
- const newMessages = sliceMessagesUntil(chat.messages, parentId);
1158
- chat.setMessages(newMessages);
1159
- await reloadMaybe();
1160
- },
1161
- [chat.messages, chat.setMessages, reloadMaybe]
1162
- );
1163
- const append = useCallback2(
1164
- async (message) => {
1165
- if (message.content.length !== 1 || message.content[0]?.type !== "text")
1166
- throw new Error("Only text content is supported by Vercel AI SDK");
1167
- const newMessages = sliceMessagesUntil(chat.messages, message.parentId);
1168
- chat.setMessages(newMessages);
1169
- await chat.append({
1170
- role: "user",
1171
- content: message.content[0].text
1172
- });
1173
- },
1174
- [chat.messages, chat.setMessages, chat.append]
1250
+ [data]
1175
1251
  );
1252
+ const startRun = useCallback2(async (parentId) => {
1253
+ const reloadMaybe = "reload" in vercelRef.current ? vercelRef.current.reload : void 0;
1254
+ if (!reloadMaybe)
1255
+ throw new Error("Reload not supported by Vercel AI SDK's useAssistant");
1256
+ const newMessages = sliceMessagesUntil(
1257
+ vercelRef.current.messages,
1258
+ parentId
1259
+ );
1260
+ vercelRef.current.setMessages(newMessages);
1261
+ await reloadMaybe();
1262
+ }, []);
1263
+ const append = useCallback2(async (message) => {
1264
+ if (message.content.length !== 1 || message.content[0]?.type !== "text")
1265
+ throw new Error("Only text content is supported by Vercel AI SDK");
1266
+ const newMessages = sliceMessagesUntil(
1267
+ vercelRef.current.messages,
1268
+ message.parentId
1269
+ );
1270
+ vercelRef.current.setMessages(newMessages);
1271
+ await vercelRef.current.append({
1272
+ role: "user",
1273
+ content: message.content[0].text
1274
+ });
1275
+ }, []);
1276
+ const cancelRun = useCallback2(() => {
1277
+ const lastMessage = vercelRef.current.messages.at(-1);
1278
+ vercelRef.current.stop();
1279
+ if (lastMessage?.role === "user") {
1280
+ vercelRef.current.setInput(lastMessage.content);
1281
+ }
1282
+ }, []);
1176
1283
  return useMemo3(
1177
1284
  () => ({
1178
- messages: messagesEx,
1285
+ isRunning,
1286
+ messages,
1179
1287
  getBranches,
1180
1288
  switchToBranch,
1181
1289
  append,
1182
- startRun
1290
+ startRun,
1291
+ cancelRun
1183
1292
  }),
1184
- [messagesEx, getBranches, switchToBranch, append, startRun]
1293
+ [
1294
+ isRunning,
1295
+ messages,
1296
+ getBranches,
1297
+ switchToBranch,
1298
+ append,
1299
+ startRun,
1300
+ cancelRun
1301
+ ]
1185
1302
  );
1186
1303
  };
1187
1304
 
1188
1305
  // src/adapters/vercel/VercelAIAssistantProvider.tsx
1189
- import { jsx as jsx18 } from "react/jsx-runtime";
1190
- var ThreadMessageCache = /* @__PURE__ */ new WeakMap();
1191
- var vercelToThreadMessage = (message, parentId) => {
1192
- if (message.role !== "user" && message.role !== "assistant")
1193
- throw new Error("Unsupported role");
1194
- return {
1195
- parentId,
1196
- id: message.id,
1197
- role: message.role,
1198
- content: [{ type: "text", text: message.content }],
1199
- createdAt: message.createdAt ?? /* @__PURE__ */ new Date(),
1200
- innerMessage: message
1201
- };
1202
- };
1203
- var vercelToCachedThreadMessages = (messages) => {
1204
- return messages.map((m, idx) => {
1205
- const cached = ThreadMessageCache.get(m);
1206
- const parentId = messages[idx - 1]?.id ?? null;
1207
- if (cached && cached.parentId === parentId)
1208
- return cached;
1209
- const newMessage = vercelToThreadMessage(m, parentId);
1210
- ThreadMessageCache.set(m, newMessage);
1211
- return newMessage;
1212
- });
1213
- };
1306
+ import { jsx as jsx19 } from "react/jsx-runtime";
1214
1307
  var VercelAIAssistantProvider = ({
1215
1308
  children,
1216
1309
  ...rest
1217
1310
  }) => {
1218
1311
  const context = useDummyAIAssistantContext();
1219
1312
  const vercel = "chat" in rest ? rest.chat : rest.assistant;
1220
- const messages = useMemo4(() => {
1221
- return vercelToCachedThreadMessages(vercel.messages);
1222
- }, [vercel.messages]);
1223
- const branches = useVercelAIBranches(vercel, messages);
1224
- const cancelRun = useCallback3(() => {
1225
- const lastMessage = vercel.messages.at(-1);
1226
- vercel.stop();
1227
- if (lastMessage?.role === "user") {
1228
- vercel.setInput(lastMessage.content);
1229
- }
1230
- }, [vercel.messages, vercel.stop, vercel.setInput]);
1231
- const isRunning = "isLoading" in vercel ? vercel.isLoading : vercel.status === "in_progress";
1313
+ const threadState = useVercelAIThreadState(vercel);
1232
1314
  useMemo4(() => {
1233
- context.useThread.setState(
1234
- {
1235
- messages: branches.messages,
1236
- isRunning,
1237
- getBranches: branches.getBranches,
1238
- switchToBranch: branches.switchToBranch,
1239
- append: branches.append,
1240
- startRun: branches.startRun,
1241
- cancelRun
1242
- },
1243
- true
1244
- );
1245
- }, [context, isRunning, cancelRun, branches]);
1315
+ context.useThread.setState(threadState, true);
1316
+ }, [context, threadState]);
1246
1317
  useMemo4(() => {
1247
1318
  context.useComposer.setState({
1248
1319
  value: vercel.input,
1249
1320
  setValue: vercel.setInput
1250
1321
  });
1251
1322
  }, [context, vercel.input, vercel.setInput]);
1252
- return /* @__PURE__ */ jsx18(AssistantContext.Provider, { value: context, children });
1323
+ return /* @__PURE__ */ jsx19(AssistantContext.Provider, { value: context, children });
1253
1324
  };
1254
1325
 
1255
1326
  // src/adapters/vercel/VercelRSCAssistantProvider.tsx
1256
1327
  import {
1257
- useCallback as useCallback4,
1328
+ useCallback as useCallback3,
1258
1329
  useMemo as useMemo5
1259
1330
  } from "react";
1260
- import { jsx as jsx19 } from "react/jsx-runtime";
1261
- var ThreadMessageCache2 = /* @__PURE__ */ new WeakMap();
1262
- var vercelToThreadMessage2 = (parentId, message) => {
1331
+ import { jsx as jsx20 } from "react/jsx-runtime";
1332
+ var vercelToThreadMessage2 = (message) => {
1263
1333
  if (message.role !== "user" && message.role !== "assistant")
1264
1334
  throw new Error("Unsupported role");
1265
1335
  return {
1266
- parentId,
1267
1336
  id: message.id,
1268
1337
  role: message.role,
1269
1338
  content: [{ type: "ui", display: message.display }],
1270
1339
  createdAt: message.createdAt ?? /* @__PURE__ */ new Date()
1271
1340
  };
1272
1341
  };
1273
- var vercelToCachedThreadMessages2 = (messages) => {
1274
- return messages.map((m, idx) => {
1275
- const cached = ThreadMessageCache2.get(m);
1276
- const parentId = messages[idx - 1]?.id ?? null;
1277
- if (cached && cached.parentId === parentId)
1278
- return cached;
1279
- const newMessage = vercelToThreadMessage2(parentId, m);
1280
- ThreadMessageCache2.set(m, newMessage);
1281
- return newMessage;
1282
- });
1283
- };
1284
- var VercelRSCAssistantProvider = ({ children, messages: vercelMessages, append: vercelAppend }) => {
1342
+ var VercelRSCAssistantProvider = ({
1343
+ children,
1344
+ convertMessage,
1345
+ messages: vercelMessages,
1346
+ append: appendCallback,
1347
+ edit,
1348
+ reload
1349
+ }) => {
1285
1350
  const context = useDummyAIAssistantContext();
1351
+ const converter2 = useMemo5(() => {
1352
+ const rscConverter = convertMessage ?? ((m) => m);
1353
+ return new ThreadMessageConverter((m) => {
1354
+ return vercelToThreadMessage2(rscConverter(m));
1355
+ });
1356
+ }, [convertMessage]);
1286
1357
  const messages = useMemo5(() => {
1287
- return vercelToCachedThreadMessages2(vercelMessages);
1288
- }, [vercelMessages]);
1289
- const append = useCallback4(
1358
+ return converter2.convertMessages(vercelMessages);
1359
+ }, [converter2, vercelMessages]);
1360
+ const append = useCallback3(
1290
1361
  async (message) => {
1291
- if (message.parentId !== (context.useThread.getState().messages.at(-1)?.id ?? null))
1292
- throw new Error("Unexpected: Message editing is not supported");
1293
- if (message.content[0]?.type !== "text") {
1294
- throw new Error("Only text content is currently supported");
1362
+ if (message.parentId !== (context.useThread.getState().messages.at(-1)?.id ?? null)) {
1363
+ if (!edit)
1364
+ throw new Error(
1365
+ "Unexpected: Message editing is not supported, no edit callback was provided to VercelRSCAssistantProvider."
1366
+ );
1367
+ await edit(message);
1368
+ } else {
1369
+ await appendCallback(message);
1295
1370
  }
1296
- await vercelAppend(message);
1297
1371
  },
1298
- [context, vercelAppend]
1372
+ [context, appendCallback, edit]
1373
+ );
1374
+ const startRun = useCallback3(
1375
+ async (parentId) => {
1376
+ if (!reload)
1377
+ throw new Error(
1378
+ "Unexpected: Message reloading is not supported, no reload callback was provided to VercelRSCAssistantProvider."
1379
+ );
1380
+ await reload(parentId);
1381
+ },
1382
+ [reload]
1299
1383
  );
1300
1384
  useMemo5(() => {
1301
1385
  context.useThread.setState({
1302
1386
  messages,
1303
- append
1387
+ append,
1388
+ startRun
1304
1389
  });
1305
- }, [context, messages, append]);
1306
- return /* @__PURE__ */ jsx19(AssistantContext.Provider, { value: context, children });
1390
+ }, [context, messages, append, startRun]);
1391
+ return /* @__PURE__ */ jsx20(AssistantContext.Provider, { value: context, children });
1307
1392
  };
1308
1393
  export {
1309
1394
  actionBar_exports as ActionBarPrimitive,