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