@assistant-ui/react 0.5.74 → 0.5.76

Sign up to get free protection for your applications and to get access to all the features.
package/dist/index.mjs CHANGED
@@ -605,20 +605,13 @@ var useActionBarReload = () => {
605
605
  // src/primitive-hooks/actionBar/useActionBarSpeak.tsx
606
606
  import { useCallback as useCallback6 } from "react";
607
607
  var useActionBarSpeak = () => {
608
- const messageStore = useMessageStore();
609
- const editComposerStore = useEditComposerStore();
610
608
  const messageRunime = useMessageRuntime();
611
- const messageUtilsStore = useMessageUtilsStore();
612
- const hasSpeakableContent = useCombinedStore(
613
- [messageStore, editComposerStore],
614
- (message, c) => {
615
- return !c.isEditing && (message.role !== "assistant" || message.status.type !== "running") && message.content.some((c2) => c2.type === "text" && c2.text.length > 0);
616
- }
617
- );
618
609
  const callback = useCallback6(async () => {
619
- const utt = messageRunime.speak();
620
- messageUtilsStore.getState().addUtterance(utt);
621
- }, [messageRunime, messageUtilsStore]);
610
+ messageRunime.speak();
611
+ }, [messageRunime]);
612
+ const hasSpeakableContent = useMessage((m) => {
613
+ return (m.role !== "assistant" || m.status.type !== "running") && m.content.some((c) => c.type === "text" && c.text.length > 0);
614
+ });
622
615
  if (!hasSpeakableContent) return null;
623
616
  return callback;
624
617
  };
@@ -626,11 +619,11 @@ var useActionBarSpeak = () => {
626
619
  // src/primitive-hooks/actionBar/useActionBarStopSpeaking.tsx
627
620
  import { useCallback as useCallback7 } from "react";
628
621
  var useActionBarStopSpeaking = () => {
629
- const messageUtilsStore = useMessageUtilsStore();
630
- const isSpeaking = useMessageUtils((u) => u.isSpeaking);
622
+ const messageRuntime = useMessageRuntime();
623
+ const isSpeaking = useMessage((u) => u.speech != null);
631
624
  const callback = useCallback7(async () => {
632
- messageUtilsStore.getState().stopSpeaking();
633
- }, [messageUtilsStore]);
625
+ messageRuntime.stopSpeaking();
626
+ }, [messageRuntime]);
634
627
  if (!isSpeaking) return null;
635
628
  return callback;
636
629
  };
@@ -639,13 +632,9 @@ var useActionBarStopSpeaking = () => {
639
632
  import { useCallback as useCallback8 } from "react";
640
633
  var useActionBarFeedbackPositive = () => {
641
634
  const messageRuntime = useMessageRuntime();
642
- const messageUtilsStore = useMessageUtilsStore();
643
635
  const callback = useCallback8(() => {
644
- messageRuntime.submitFeedback({
645
- type: "positive"
646
- });
647
- messageUtilsStore.getState().setSubmittedFeedback("positive");
648
- }, [messageUtilsStore, messageRuntime]);
636
+ messageRuntime.submitFeedback({ type: "positive" });
637
+ }, [messageRuntime]);
649
638
  return callback;
650
639
  };
651
640
 
@@ -653,13 +642,9 @@ var useActionBarFeedbackPositive = () => {
653
642
  import { useCallback as useCallback9 } from "react";
654
643
  var useActionBarFeedbackNegative = () => {
655
644
  const messageRuntime = useMessageRuntime();
656
- const messageUtilsStore = useMessageUtilsStore();
657
645
  const callback = useCallback9(() => {
658
- messageRuntime.submitFeedback({
659
- type: "negative"
660
- });
661
- messageUtilsStore.getState().setSubmittedFeedback("negative");
662
- }, [messageUtilsStore, messageRuntime]);
646
+ messageRuntime.submitFeedback({ type: "negative" });
647
+ }, [messageRuntime]);
663
648
  return callback;
664
649
  };
665
650
 
@@ -747,23 +732,21 @@ var useComposerSend = () => {
747
732
  import { useCallback as useCallback14 } from "react";
748
733
  var useComposerAddAttachment = () => {
749
734
  const disabled = useComposer((c) => !c.isEditing);
750
- const threadComposerStore = useThreadComposerStore();
751
- const threadRuntimeStore = useThreadComposerStore();
735
+ const composerRuntime = useComposerRuntime();
752
736
  const callback = useCallback14(() => {
753
- const { addAttachment } = threadComposerStore.getState();
754
- const { attachmentAccept } = threadRuntimeStore.getState();
755
737
  const input = document.createElement("input");
756
738
  input.type = "file";
739
+ const attachmentAccept = composerRuntime.getAttachmentAccept();
757
740
  if (attachmentAccept !== "*") {
758
741
  input.accept = attachmentAccept;
759
742
  }
760
743
  input.onchange = (e) => {
761
744
  const file = e.target.files?.[0];
762
745
  if (!file) return;
763
- addAttachment(file);
746
+ composerRuntime.addAttachment(file);
764
747
  };
765
748
  input.click();
766
- }, [threadComposerStore, threadRuntimeStore]);
749
+ }, [composerRuntime]);
767
750
  if (disabled) return null;
768
751
  return callback;
769
752
  };
@@ -810,7 +793,15 @@ var useMessageIf = (props) => {
810
793
  const messageUtilsStore = useMessageUtilsStore();
811
794
  return useCombinedStore(
812
795
  [messageStore, messageUtilsStore],
813
- ({ role, attachments, branchCount, isLast }, { isCopied, isHovering, isSpeaking, submittedFeedback }) => {
796
+ ({
797
+ role,
798
+ attachments,
799
+ content,
800
+ branchCount,
801
+ isLast,
802
+ speech,
803
+ submittedFeedback
804
+ }, { isCopied, isHovering }) => {
814
805
  if (props.hasBranches === true && branchCount < 2) return false;
815
806
  if (props.user && role !== "user") return false;
816
807
  if (props.assistant && role !== "assistant") return false;
@@ -818,13 +809,15 @@ var useMessageIf = (props) => {
818
809
  if (props.lastOrHover === true && !isHovering && !isLast) return false;
819
810
  if (props.copied === true && !isCopied) return false;
820
811
  if (props.copied === false && isCopied) return false;
821
- if (props.speaking === true && !isSpeaking) return false;
822
- if (props.speaking === false && isSpeaking) return false;
812
+ if (props.speaking === true && speech == null) return false;
813
+ if (props.speaking === false && speech != null) return false;
823
814
  if (props.hasAttachments === true && (role !== "user" || !attachments.length))
824
815
  return false;
825
816
  if (props.hasAttachments === false && role === "user" && !!attachments.length)
826
817
  return false;
827
- if (props.submittedFeedback !== void 0 && submittedFeedback !== props.submittedFeedback)
818
+ if (props.hasContent === true && content.length === 0) return false;
819
+ if (props.hasContent === false && content.length > 0) return false;
820
+ if (props.submittedFeedback !== void 0 && (submittedFeedback?.type ?? null) !== props.submittedFeedback)
828
821
  return false;
829
822
  return true;
830
823
  }
@@ -920,7 +913,7 @@ var useActionBarFloatStatus = ({
920
913
  const autohideEnabled = autohide === "always" || autohide === "not-last" && !m.isLast;
921
914
  if (!autohideEnabled) return "normal" /* Normal */;
922
915
  if (!mu.isHovering) return "hidden" /* Hidden */;
923
- if (autohideFloat === "always" || autohideFloat === "single-branch" && m.branches.length <= 1)
916
+ if (autohideFloat === "always" || autohideFloat === "single-branch" && m.branchCount <= 1)
924
917
  return "floating" /* Floating */;
925
918
  return "normal" /* Normal */;
926
919
  }
@@ -1058,8 +1051,8 @@ import { composeEventHandlers as composeEventHandlers4 } from "@radix-ui/primiti
1058
1051
  import { Primitive as Primitive5 } from "@radix-ui/react-primitive";
1059
1052
  import { jsx as jsx8 } from "react/jsx-runtime";
1060
1053
  var ActionBarPrimitiveFeedbackPositive = forwardRef5(({ onClick, disabled, ...props }, forwardedRef) => {
1061
- const isSubmitted = useMessageUtils(
1062
- (u) => u.submittedFeedback === "positive"
1054
+ const isSubmitted = useMessage(
1055
+ (u) => u.submittedFeedback?.type === "positive"
1063
1056
  );
1064
1057
  const callback = useActionBarFeedbackPositive();
1065
1058
  return /* @__PURE__ */ jsx8(
@@ -1084,8 +1077,8 @@ import { composeEventHandlers as composeEventHandlers5 } from "@radix-ui/primiti
1084
1077
  import { Primitive as Primitive6 } from "@radix-ui/react-primitive";
1085
1078
  import { jsx as jsx9 } from "react/jsx-runtime";
1086
1079
  var ActionBarPrimitiveFeedbackNegative = forwardRef6(({ onClick, disabled, ...props }, forwardedRef) => {
1087
- const isSubmitted = useMessageUtils(
1088
- (u) => u.submittedFeedback === "negative"
1080
+ const isSubmitted = useMessage(
1081
+ (u) => u.submittedFeedback?.type === "negative"
1089
1082
  );
1090
1083
  const callback = useActionBarFeedbackNegative();
1091
1084
  return /* @__PURE__ */ jsx9(
@@ -1309,9 +1302,9 @@ var { useAttachment: useMessageAttachment } = createContextStoreHook(
1309
1302
  // src/primitives/attachment/AttachmentThumb.tsx
1310
1303
  import { Primitive as Primitive8 } from "@radix-ui/react-primitive";
1311
1304
  import { jsxs } from "react/jsx-runtime";
1312
- var AttachmentPrimitiveThumb = forwardRef11(() => {
1305
+ var AttachmentPrimitiveThumb = forwardRef11((props, ref) => {
1313
1306
  const ext = useAttachment((a) => a.name.split(".").pop());
1314
- return /* @__PURE__ */ jsxs(Primitive8.div, { children: [
1307
+ return /* @__PURE__ */ jsxs(Primitive8.div, { ...props, ref, children: [
1315
1308
  ".",
1316
1309
  ext
1317
1310
  ] });
@@ -1348,7 +1341,7 @@ __export(branchPicker_exports, {
1348
1341
  Count: () => BranchPickerPrimitiveCount,
1349
1342
  Next: () => BranchPickerPrimitiveNext,
1350
1343
  Number: () => BranchPickerPrimitiveNumber,
1351
- Previous: () => BranchPickerPrevious,
1344
+ Previous: () => BranchPickerPrimitivePrevious,
1352
1345
  Root: () => BranchPickerPrimitiveRoot
1353
1346
  });
1354
1347
 
@@ -1359,7 +1352,7 @@ var BranchPickerPrimitiveNext = createActionButton(
1359
1352
  );
1360
1353
 
1361
1354
  // src/primitives/branchPicker/BranchPickerPrevious.tsx
1362
- var BranchPickerPrevious = createActionButton(
1355
+ var BranchPickerPrimitivePrevious = createActionButton(
1363
1356
  "BranchPickerPrimitive.Previous",
1364
1357
  useBranchPickerPrevious
1365
1358
  );
@@ -1852,7 +1845,6 @@ var getThreadComposerState = (runtime, focus, onFocus) => {
1852
1845
  isEmpty: runtime?.isEmpty ?? true,
1853
1846
  text: runtime?.text ?? "",
1854
1847
  attachments: runtime?.attachments ?? EMPTY_ARRAY,
1855
- attachmentAccept: runtime?.attachmentAccept ?? "*",
1856
1848
  value: runtime?.text ?? "",
1857
1849
  setValue: runtime?.setText.bind(runtime) ?? METHOD_NOT_SUPPORTED,
1858
1850
  setText: runtime?.setText.bind(runtime) ?? METHOD_NOT_SUPPORTED,
@@ -1874,7 +1866,6 @@ var getEditComposerState = (runtime, beginEdit) => {
1874
1866
  isEmpty: runtime?.isEmpty ?? true,
1875
1867
  text: runtime?.text ?? "",
1876
1868
  attachments: runtime?.attachments ?? EMPTY_ARRAY,
1877
- attachmentAccept: runtime?.attachmentAccept ?? "*",
1878
1869
  value: runtime?.text ?? "",
1879
1870
  setValue: runtime?.setText.bind(runtime) ?? METHOD_NOT_SUPPORTED,
1880
1871
  setText: runtime?.setText.bind(runtime) ?? METHOD_NOT_SUPPORTED,
@@ -1911,12 +1902,6 @@ var ComposerRuntimeImpl = class {
1911
1902
  get text() {
1912
1903
  return this.getState().text;
1913
1904
  }
1914
- /**
1915
- * @deprecated Use `getState().attachmentAccept` instead. This will be removed in 0.6.0.
1916
- */
1917
- get attachmentAccept() {
1918
- return this.getState().attachmentAccept;
1919
- }
1920
1905
  /**
1921
1906
  * @deprecated Use `getState().attachments` instead. This will be removed in 0.6.0.
1922
1907
  */
@@ -1971,6 +1956,11 @@ var ComposerRuntimeImpl = class {
1971
1956
  subscribe(callback) {
1972
1957
  return this._core.subscribe(callback);
1973
1958
  }
1959
+ getAttachmentAccept() {
1960
+ const core = this._core.getState();
1961
+ if (!core) throw new Error("Composer is not available");
1962
+ return core.getAttachmentAccept();
1963
+ }
1974
1964
  };
1975
1965
  var ThreadComposerRuntimeImpl = class extends ComposerRuntimeImpl {
1976
1966
  get type() {
@@ -2173,6 +2163,16 @@ var MessageRuntimeImpl = class {
2173
2163
  if (!state) throw new Error("Message is not available");
2174
2164
  return this._threadBinding.getState().speak(state.id);
2175
2165
  }
2166
+ stopSpeaking() {
2167
+ const state = this._core.getState();
2168
+ if (!state) throw new Error("Message is not available");
2169
+ const thread = this._threadBinding.getState();
2170
+ if (thread.speech?.messageId === state.id) {
2171
+ this._threadBinding.getState().stopSpeaking();
2172
+ } else {
2173
+ throw new Error("Message is not being spoken");
2174
+ }
2175
+ }
2176
2176
  submitFeedback({ type }) {
2177
2177
  const state = this._core.getState();
2178
2178
  if (!state) throw new Error("Message is not available");
@@ -2817,7 +2817,6 @@ import { create as create10 } from "zustand";
2817
2817
  // src/context/stores/MessageUtils.ts
2818
2818
  import { create as create9 } from "zustand";
2819
2819
  var makeMessageUtilsStore = () => create9((set) => {
2820
- let utterance = null;
2821
2820
  return {
2822
2821
  isCopied: false,
2823
2822
  setIsCopied: (value) => {
@@ -2826,21 +2825,6 @@ var makeMessageUtilsStore = () => create9((set) => {
2826
2825
  isHovering: false,
2827
2826
  setIsHovering: (value) => {
2828
2827
  set({ isHovering: value });
2829
- },
2830
- isSpeaking: false,
2831
- stopSpeaking: () => {
2832
- utterance?.cancel();
2833
- },
2834
- addUtterance: (utt) => {
2835
- utterance = utt;
2836
- set({ isSpeaking: true });
2837
- utt.onEnd(() => {
2838
- set({ isSpeaking: false });
2839
- });
2840
- },
2841
- submittedFeedback: null,
2842
- setSubmittedFeedback: (feedback) => {
2843
- set({ submittedFeedback: feedback });
2844
2828
  }
2845
2829
  };
2846
2830
  });
@@ -3037,7 +3021,9 @@ __export(internal_exports, {
3037
3021
  var isAttachmentComplete = (a) => a.status.type === "complete";
3038
3022
  var BaseComposerRuntimeCore = class {
3039
3023
  isEditing = true;
3040
- attachmentAccept = "*";
3024
+ getAttachmentAccept() {
3025
+ return this.getAttachmentAdapter()?.accept ?? "*";
3026
+ }
3041
3027
  _attachments = [];
3042
3028
  set attachments(value) {
3043
3029
  this._attachments = value;
@@ -3063,10 +3049,11 @@ var BaseComposerRuntimeCore = class {
3063
3049
  this.notifySubscribers();
3064
3050
  }
3065
3051
  async send() {
3066
- const attachments = this._attachmentAdapter ? await Promise.all(
3052
+ const adapter = this.getAttachmentAdapter();
3053
+ const attachments = adapter && this.attachments.length > 0 ? await Promise.all(
3067
3054
  this.attachments.map(async (a) => {
3068
3055
  if (isAttachmentComplete(a)) return a;
3069
- const result = await this._attachmentAdapter.send(a);
3056
+ const result = await adapter.send(a);
3070
3057
  if (result.status?.type !== "complete") {
3071
3058
  result.status = { type: "complete" };
3072
3059
  }
@@ -3081,19 +3068,10 @@ var BaseComposerRuntimeCore = class {
3081
3068
  this.reset();
3082
3069
  this.handleSend(message);
3083
3070
  }
3084
- _attachmentAdapter;
3085
- setAttachmentAdapter(adapter) {
3086
- this._attachmentAdapter = adapter;
3087
- const accept = adapter?.accept ?? "*";
3088
- if (this.attachmentAccept !== accept) {
3089
- this.attachmentAccept = accept;
3090
- this.notifySubscribers();
3091
- }
3092
- }
3093
3071
  async addAttachment(file) {
3094
- if (!this._attachmentAdapter)
3095
- throw new Error("Attachments are not supported");
3096
- const attachment = await this._attachmentAdapter.add({ file });
3072
+ const adapter = this.getAttachmentAdapter();
3073
+ if (!adapter) throw new Error("Attachments are not supported");
3074
+ const attachment = await adapter.add({ file });
3097
3075
  if (attachment.status === void 0) {
3098
3076
  attachment.status = { type: "requires-action", reason: "composer-send" };
3099
3077
  }
@@ -3101,12 +3079,12 @@ var BaseComposerRuntimeCore = class {
3101
3079
  this.notifySubscribers();
3102
3080
  }
3103
3081
  async removeAttachment(attachmentId) {
3104
- if (!this._attachmentAdapter)
3105
- throw new Error("Attachments are not supported");
3082
+ const adapter = this.getAttachmentAdapter();
3083
+ if (!adapter) throw new Error("Attachments are not supported");
3106
3084
  const index = this._attachments.findIndex((a) => a.id === attachmentId);
3107
3085
  if (index === -1) throw new Error("Attachment not found");
3108
3086
  const attachment = this._attachments[index];
3109
- await this._attachmentAdapter.remove(attachment);
3087
+ await adapter.remove(attachment);
3110
3088
  this._attachments = this._attachments.toSpliced(index, 1);
3111
3089
  this.notifySubscribers();
3112
3090
  }
@@ -3134,6 +3112,9 @@ var DefaultThreadComposerRuntimeCore = class extends BaseComposerRuntimeCore {
3134
3112
  get attachments() {
3135
3113
  return super.attachments;
3136
3114
  }
3115
+ getAttachmentAdapter() {
3116
+ return this.runtime.adapters?.attachments;
3117
+ }
3137
3118
  connect() {
3138
3119
  return this.runtime.subscribe(() => {
3139
3120
  if (this.canCancel !== this.runtime.capabilities.cancel) {
@@ -3512,36 +3493,6 @@ var TooltipIconButton = forwardRef23(({ children, tooltip, side = "bottom", ...r
3512
3493
  });
3513
3494
  TooltipIconButton.displayName = "TooltipIconButton";
3514
3495
 
3515
- // src/api/AssistantRuntime.ts
3516
- var AssistantRuntimeImpl = class {
3517
- constructor(_core, CustomThreadRuntime) {
3518
- this._core = _core;
3519
- this.thread = new CustomThreadRuntime(
3520
- new NestedSubscriptionSubject({
3521
- getState: () => this._core.thread,
3522
- subscribe: (callback) => this._core.subscribe(callback)
3523
- })
3524
- );
3525
- }
3526
- thread;
3527
- switchToNewThread() {
3528
- return this._core.switchToNewThread();
3529
- }
3530
- switchToThread(threadId) {
3531
- return this._core.switchToThread(threadId);
3532
- }
3533
- registerModelConfigProvider(provider) {
3534
- return this._core.registerModelConfigProvider(provider);
3535
- }
3536
- // TODO events for thread switching
3537
- /**
3538
- * @deprecated Thread is now static and never gets updated. This will be removed in 0.6.0.
3539
- */
3540
- subscribe(callback) {
3541
- return this._core.subscribe(callback);
3542
- }
3543
- };
3544
-
3545
3496
  // src/api/ThreadRuntime.ts
3546
3497
  var toAppendMessage = (messages2, message) => {
3547
3498
  if (typeof message === "string") {
@@ -3571,7 +3522,8 @@ var getThreadState = (runtime) => {
3571
3522
  isRunning: lastMessage?.role !== "assistant" ? false : lastMessage.status.type === "running",
3572
3523
  messages: runtime.messages,
3573
3524
  suggestions: runtime.suggestions,
3574
- extras: runtime.extras
3525
+ extras: runtime.extras,
3526
+ speech: runtime.speech
3575
3527
  });
3576
3528
  };
3577
3529
  var ThreadRuntimeImpl = class {
@@ -3618,6 +3570,12 @@ var ThreadRuntimeImpl = class {
3618
3570
  get messages() {
3619
3571
  return this._threadBinding.getState().messages;
3620
3572
  }
3573
+ /**
3574
+ * @deprecated Use `getState().speechState` instead. This will be removed in 0.6.0.
3575
+ */
3576
+ get speech() {
3577
+ return this._threadBinding.getState().speech;
3578
+ }
3621
3579
  unstable_getCore() {
3622
3580
  return this._threadBinding.getState();
3623
3581
  }
@@ -3678,15 +3636,21 @@ var ThreadRuntimeImpl = class {
3678
3636
  switchToBranch(branchId) {
3679
3637
  return this._threadBinding.getState().switchToBranch(branchId);
3680
3638
  }
3681
- // /**
3682
- // * @deprecated Use `getMesssageById(id).speak()` instead. This will be removed in 0.6.0.
3683
- // */
3639
+ /**
3640
+ * @deprecated Use `getMesssageById(id).speak()` instead. This will be removed in 0.6.0.
3641
+ */
3684
3642
  speak(messageId) {
3685
3643
  return this._threadBinding.getState().speak(messageId);
3686
3644
  }
3687
- // /**
3688
- // * @deprecated Use `getMesssageById(id).submitFeedback({ type })` instead. This will be removed in 0.6.0.
3689
- // */
3645
+ stopSpeaking() {
3646
+ return this._threadBinding.getState().stopSpeaking();
3647
+ }
3648
+ getSubmittedFeedback(messageId) {
3649
+ return this._threadBinding.getState().getSubmittedFeedback(messageId);
3650
+ }
3651
+ /**
3652
+ * @deprecated Use `getMesssageById(id).submitFeedback({ type })` instead. This will be removed in 0.6.0.
3653
+ */
3690
3654
  submitFeedback(options) {
3691
3655
  return this._threadBinding.getState().submitFeedback(options);
3692
3656
  }
@@ -3713,10 +3677,12 @@ var ThreadRuntimeImpl = class {
3713
3677
  return new MessageRuntimeImpl(
3714
3678
  new ShallowMemoizeSubject({
3715
3679
  getState: () => {
3716
- const messages2 = this.getState().messages;
3680
+ const { messages: messages2, speech: speechState } = this.getState();
3717
3681
  const message = messages2[idx];
3718
3682
  if (!message) return SKIP_UPDATE;
3719
- const branches = this._threadBinding.getState().getBranches(message.id);
3683
+ const thread = this._threadBinding.getState();
3684
+ const branches = thread.getBranches(message.id);
3685
+ const submittedFeedback = thread.getSubmittedFeedback(message.id);
3720
3686
  return {
3721
3687
  ...message,
3722
3688
  message,
@@ -3724,7 +3690,9 @@ var ThreadRuntimeImpl = class {
3724
3690
  parentId: messages2[idx - 1]?.id ?? null,
3725
3691
  branches,
3726
3692
  branchNumber: branches.indexOf(message.id) + 1,
3727
- branchCount: branches.length
3693
+ branchCount: branches.length,
3694
+ speech: speechState?.messageId === message.id ? speechState : void 0,
3695
+ submittedFeedback
3728
3696
  };
3729
3697
  },
3730
3698
  subscribe: (callback) => this._threadBinding.subscribe(callback)
@@ -3734,6 +3702,47 @@ var ThreadRuntimeImpl = class {
3734
3702
  }
3735
3703
  };
3736
3704
 
3705
+ // src/api/AssistantRuntime.ts
3706
+ var AssistantRuntimeImpl = class _AssistantRuntimeImpl {
3707
+ constructor(_core, _thread) {
3708
+ this._core = _core;
3709
+ this._thread = _thread;
3710
+ }
3711
+ get thread() {
3712
+ return this._thread;
3713
+ }
3714
+ switchToNewThread() {
3715
+ return this._core.switchToNewThread();
3716
+ }
3717
+ switchToThread(threadId) {
3718
+ return this._core.switchToThread(threadId);
3719
+ }
3720
+ registerModelConfigProvider(provider) {
3721
+ return this._core.registerModelConfigProvider(provider);
3722
+ }
3723
+ // TODO events for thread switching
3724
+ /**
3725
+ * @deprecated Thread is now static and never gets updated. This will be removed in 0.6.0.
3726
+ */
3727
+ subscribe(callback) {
3728
+ return this._core.subscribe(callback);
3729
+ }
3730
+ static createThreadRuntime(_core, CustomThreadRuntime = ThreadRuntimeImpl) {
3731
+ return new CustomThreadRuntime(
3732
+ new NestedSubscriptionSubject({
3733
+ getState: () => _core.thread,
3734
+ subscribe: (callback) => _core.subscribe(callback)
3735
+ })
3736
+ );
3737
+ }
3738
+ static create(_core, CustomThreadRuntime = ThreadRuntimeImpl) {
3739
+ return new _AssistantRuntimeImpl(
3740
+ _core,
3741
+ _AssistantRuntimeImpl.createThreadRuntime(_core, CustomThreadRuntime)
3742
+ );
3743
+ }
3744
+ };
3745
+
3737
3746
  // src/runtimes/edge/converters/fromLanguageModelMessages.ts
3738
3747
  var fromLanguageModelMessages = (lm, { mergeSteps }) => {
3739
3748
  const messages2 = [];
@@ -4096,10 +4105,14 @@ var DefaultEditComposerRuntimeCore = class extends BaseComposerRuntimeCore {
4096
4105
  this._nonTextParts = message.content.filter(
4097
4106
  (part) => part.type !== "text" && part.type !== "ui"
4098
4107
  );
4108
+ this.attachments = message.attachments ?? [];
4099
4109
  }
4100
4110
  get canCancel() {
4101
4111
  return true;
4102
4112
  }
4113
+ getAttachmentAdapter() {
4114
+ return this.runtime.adapters?.attachments;
4115
+ }
4103
4116
  _nonTextParts;
4104
4117
  _previousText;
4105
4118
  _parentId;
@@ -4121,10 +4134,107 @@ var DefaultEditComposerRuntimeCore = class extends BaseComposerRuntimeCore {
4121
4134
  }
4122
4135
  };
4123
4136
 
4137
+ // src/runtimes/core/BaseThreadRuntimeCore.tsx
4138
+ var BaseThreadRuntimeCore = class {
4139
+ constructor(configProvider) {
4140
+ this.configProvider = configProvider;
4141
+ }
4142
+ _subscriptions = /* @__PURE__ */ new Set();
4143
+ repository = new MessageRepository();
4144
+ get messages() {
4145
+ return this.repository.getMessages();
4146
+ }
4147
+ composer = new DefaultThreadComposerRuntimeCore(this);
4148
+ getModelConfig() {
4149
+ return this.configProvider.getModelConfig();
4150
+ }
4151
+ _editComposers = /* @__PURE__ */ new Map();
4152
+ getEditComposer(messageId) {
4153
+ return this._editComposers.get(messageId);
4154
+ }
4155
+ beginEdit(messageId) {
4156
+ if (this._editComposers.has(messageId))
4157
+ throw new Error("Edit already in progress");
4158
+ this._editComposers.set(
4159
+ messageId,
4160
+ new DefaultEditComposerRuntimeCore(
4161
+ this,
4162
+ () => this._editComposers.delete(messageId),
4163
+ this.repository.getMessage(messageId)
4164
+ )
4165
+ );
4166
+ this.notifySubscribers();
4167
+ }
4168
+ getBranches(messageId) {
4169
+ return this.repository.getBranches(messageId);
4170
+ }
4171
+ switchToBranch(branchId) {
4172
+ this.repository.switchToBranch(branchId);
4173
+ this.notifySubscribers();
4174
+ }
4175
+ notifySubscribers() {
4176
+ for (const callback of this._subscriptions) callback();
4177
+ }
4178
+ subscribe(callback) {
4179
+ this._subscriptions.add(callback);
4180
+ return () => this._subscriptions.delete(callback);
4181
+ }
4182
+ _submittedFeedback = {};
4183
+ getSubmittedFeedback(messageId) {
4184
+ return this._submittedFeedback[messageId];
4185
+ }
4186
+ submitFeedback({ messageId, type }) {
4187
+ const adapter = this.adapters?.feedback;
4188
+ if (!adapter) throw new Error("Feedback adapter not configured");
4189
+ const { message } = this.repository.getMessage(messageId);
4190
+ adapter.submit({ message, type });
4191
+ this._submittedFeedback[messageId] = { type };
4192
+ this.notifySubscribers();
4193
+ }
4194
+ _stopSpeaking;
4195
+ speech;
4196
+ speak(messageId) {
4197
+ const adapter = this.adapters?.speech;
4198
+ if (!adapter) throw new Error("Speech adapter not configured");
4199
+ const { message } = this.repository.getMessage(messageId);
4200
+ this._stopSpeaking?.();
4201
+ const utterance = adapter.speak(message);
4202
+ const unsub = utterance.subscribe(() => {
4203
+ if (utterance.status.type === "ended") {
4204
+ this._stopSpeaking = void 0;
4205
+ this.speech = void 0;
4206
+ } else {
4207
+ this.speech = { messageId, status: utterance.status };
4208
+ }
4209
+ this.notifySubscribers();
4210
+ });
4211
+ this.speech = { messageId, status: utterance.status };
4212
+ this.notifySubscribers();
4213
+ this._stopSpeaking = () => {
4214
+ utterance.cancel();
4215
+ unsub();
4216
+ this.speech = void 0;
4217
+ this._stopSpeaking = void 0;
4218
+ };
4219
+ }
4220
+ stopSpeaking() {
4221
+ if (!this._stopSpeaking) throw new Error("No message is being spoken");
4222
+ this._stopSpeaking();
4223
+ this.notifySubscribers();
4224
+ }
4225
+ export() {
4226
+ return this.repository.export();
4227
+ }
4228
+ import(data) {
4229
+ this.repository.import(data);
4230
+ this.notifySubscribers();
4231
+ }
4232
+ };
4233
+
4124
4234
  // src/runtimes/local/LocalThreadRuntimeCore.tsx
4125
- var LocalThreadRuntimeCore = class {
4235
+ var LocalThreadRuntimeCore = class extends BaseThreadRuntimeCore {
4126
4236
  constructor(configProvider, adapter, { initialMessages, ...options }) {
4127
- this.configProvider = configProvider;
4237
+ super(configProvider);
4128
4238
  this.adapter = adapter;
4129
4239
  this.threadId = generateId();
4130
4240
  this.options = options;
@@ -4137,28 +4247,22 @@ var LocalThreadRuntimeCore = class {
4137
4247
  }
4138
4248
  }
4139
4249
  }
4140
- _subscriptions = /* @__PURE__ */ new Set();
4141
- abortController = null;
4142
- repository = new MessageRepository();
4143
4250
  capabilities = {
4144
4251
  switchToBranch: true,
4145
4252
  edit: true,
4146
4253
  reload: true,
4147
4254
  cancel: true,
4148
4255
  unstable_copy: true,
4149
- speak: false,
4256
+ speech: false,
4150
4257
  attachments: false,
4151
4258
  feedback: false
4152
4259
  };
4260
+ abortController = null;
4153
4261
  threadId;
4154
4262
  isDisabled = false;
4155
4263
  suggestions = [];
4156
- get messages() {
4157
- return this.repository.getMessages();
4158
- }
4159
- composer = new DefaultThreadComposerRuntimeCore(this);
4160
- getModelConfig() {
4161
- return this.configProvider.getModelConfig();
4264
+ get adapters() {
4265
+ return this.options.adapters;
4162
4266
  }
4163
4267
  _options;
4164
4268
  get options() {
@@ -4171,11 +4275,10 @@ var LocalThreadRuntimeCore = class {
4171
4275
  this._options = options;
4172
4276
  let hasUpdates = false;
4173
4277
  const canSpeak = options.adapters?.speech !== void 0;
4174
- if (this.capabilities.speak !== canSpeak) {
4175
- this.capabilities.speak = canSpeak;
4278
+ if (this.capabilities.speech !== canSpeak) {
4279
+ this.capabilities.speech = canSpeak;
4176
4280
  hasUpdates = true;
4177
4281
  }
4178
- this.composer.setAttachmentAdapter(options.adapters?.attachments);
4179
4282
  const canAttach = options.adapters?.attachments !== void 0;
4180
4283
  if (this.capabilities.attachments !== canAttach) {
4181
4284
  this.capabilities.attachments = canAttach;
@@ -4188,30 +4291,6 @@ var LocalThreadRuntimeCore = class {
4188
4291
  }
4189
4292
  if (hasUpdates) this.notifySubscribers();
4190
4293
  }
4191
- _editComposers = /* @__PURE__ */ new Map();
4192
- getEditComposer(messageId) {
4193
- return this._editComposers.get(messageId);
4194
- }
4195
- beginEdit(messageId) {
4196
- if (this._editComposers.has(messageId))
4197
- throw new Error("Edit already in progress");
4198
- this._editComposers.set(
4199
- messageId,
4200
- new DefaultEditComposerRuntimeCore(
4201
- this,
4202
- () => this._editComposers.delete(messageId),
4203
- this.repository.getMessage(messageId)
4204
- )
4205
- );
4206
- this.notifySubscribers();
4207
- }
4208
- getBranches(messageId) {
4209
- return this.repository.getBranches(messageId);
4210
- }
4211
- switchToBranch(branchId) {
4212
- this.repository.switchToBranch(branchId);
4213
- this.notifySubscribers();
4214
- }
4215
4294
  async append(message) {
4216
4295
  const newMessage = fromCoreMessage(message, {
4217
4296
  attachments: message.attachments
@@ -4288,7 +4367,7 @@ var LocalThreadRuntimeCore = class {
4288
4367
  const promiseOrGenerator = this.adapter.run({
4289
4368
  messages: messages2,
4290
4369
  abortSignal: this.abortController.signal,
4291
- config: this.configProvider.getModelConfig(),
4370
+ config: this.getModelConfig(),
4292
4371
  onUpdate: updateMessage
4293
4372
  });
4294
4373
  if (Symbol.asyncIterator in promiseOrGenerator) {
@@ -4320,17 +4399,9 @@ var LocalThreadRuntimeCore = class {
4320
4399
  return message;
4321
4400
  }
4322
4401
  cancelRun() {
4323
- if (!this.abortController) return;
4324
- this.abortController.abort();
4402
+ this.abortController?.abort();
4325
4403
  this.abortController = null;
4326
4404
  }
4327
- notifySubscribers() {
4328
- for (const callback of this._subscriptions) callback();
4329
- }
4330
- subscribe(callback) {
4331
- this._subscriptions.add(callback);
4332
- return () => this._subscriptions.delete(callback);
4333
- }
4334
4405
  addToolResult({
4335
4406
  messageId,
4336
4407
  toolCallId,
@@ -4364,38 +4435,6 @@ var LocalThreadRuntimeCore = class {
4364
4435
  this.performRoundtrip(parentId, message);
4365
4436
  }
4366
4437
  }
4367
- // TODO lift utterance state to thread runtime
4368
- _utterance;
4369
- speak(messageId) {
4370
- const adapter = this.options.adapters?.speech;
4371
- if (!adapter) throw new Error("Speech adapter not configured");
4372
- const { message } = this.repository.getMessage(messageId);
4373
- if (this._utterance) {
4374
- this._utterance.cancel();
4375
- this._utterance = void 0;
4376
- }
4377
- const utterance = adapter.speak(message);
4378
- utterance.onEnd(() => {
4379
- if (this._utterance === utterance) {
4380
- this._utterance = void 0;
4381
- }
4382
- });
4383
- this._utterance = utterance;
4384
- return this._utterance;
4385
- }
4386
- submitFeedback({ messageId, type }) {
4387
- const adapter = this.options.adapters?.feedback;
4388
- if (!adapter) throw new Error("Feedback adapter not configured");
4389
- const { message } = this.repository.getMessage(messageId);
4390
- adapter.submit({ message, type });
4391
- }
4392
- export() {
4393
- return this.repository.export();
4394
- }
4395
- import(data) {
4396
- this.repository.import(data);
4397
- this.notifySubscribers();
4398
- }
4399
4438
  };
4400
4439
 
4401
4440
  // src/runtimes/local/LocalRuntimeCore.tsx
@@ -4439,14 +4478,20 @@ var LocalRuntimeCore = class extends BaseAssistantRuntimeCore {
4439
4478
  };
4440
4479
 
4441
4480
  // src/runtimes/local/useLocalRuntime.tsx
4442
- var LocalRuntime = class extends AssistantRuntimeImpl {
4443
- constructor(core) {
4444
- super(core, ThreadRuntimeImpl);
4481
+ var LocalRuntimeImpl = class _LocalRuntimeImpl extends AssistantRuntimeImpl {
4482
+ constructor(core, thread) {
4483
+ super(core, thread);
4445
4484
  this.core = core;
4446
4485
  }
4447
4486
  reset(options) {
4448
4487
  this.core.reset(options);
4449
4488
  }
4489
+ static create(_core) {
4490
+ return new _LocalRuntimeImpl(
4491
+ _core,
4492
+ AssistantRuntimeImpl.createThreadRuntime(_core, ThreadRuntimeImpl)
4493
+ );
4494
+ }
4450
4495
  };
4451
4496
  var useLocalRuntime = (adapter, options = {}) => {
4452
4497
  const [runtime] = useState11(() => new LocalRuntimeCore(adapter, options));
@@ -4454,7 +4499,7 @@ var useLocalRuntime = (adapter, options = {}) => {
4454
4499
  runtime.thread.adapter = adapter;
4455
4500
  runtime.thread.options = options;
4456
4501
  });
4457
- return useMemo11(() => new LocalRuntime(runtime), [runtime]);
4502
+ return useMemo11(() => LocalRuntimeImpl.create(runtime), [runtime]);
4458
4503
  };
4459
4504
 
4460
4505
  // src/runtimes/external-store/useExternalStoreRuntime.tsx
@@ -4567,13 +4612,7 @@ var EMPTY_ARRAY2 = Object.freeze([]);
4567
4612
  var hasUpcomingMessage = (isRunning, messages2) => {
4568
4613
  return isRunning && messages2[messages2.length - 1]?.role !== "assistant";
4569
4614
  };
4570
- var ExternalStoreThreadRuntimeCore = class {
4571
- constructor(configProvider, store) {
4572
- this.configProvider = configProvider;
4573
- this.store = store;
4574
- }
4575
- _subscriptions = /* @__PURE__ */ new Set();
4576
- repository = new MessageRepository();
4615
+ var ExternalStoreThreadRuntimeCore = class extends BaseThreadRuntimeCore {
4577
4616
  assistantOptimisticId = null;
4578
4617
  _capabilities = {
4579
4618
  switchToBranch: false,
@@ -4581,7 +4620,7 @@ var ExternalStoreThreadRuntimeCore = class {
4581
4620
  reload: false,
4582
4621
  cancel: false,
4583
4622
  unstable_copy: false,
4584
- speak: false,
4623
+ speech: false,
4585
4624
  attachments: false,
4586
4625
  feedback: false
4587
4626
  };
@@ -4589,29 +4628,26 @@ var ExternalStoreThreadRuntimeCore = class {
4589
4628
  return this._capabilities;
4590
4629
  }
4591
4630
  threadId;
4592
- messages;
4631
+ _messages;
4593
4632
  isDisabled;
4633
+ get messages() {
4634
+ return this._messages;
4635
+ }
4636
+ get adapters() {
4637
+ return this._store.adapters;
4638
+ }
4594
4639
  suggestions = [];
4595
4640
  extras = void 0;
4596
4641
  _converter = new ThreadMessageConverter();
4597
4642
  _store;
4598
- composer = new DefaultThreadComposerRuntimeCore(this);
4599
- _editComposers = /* @__PURE__ */ new Map();
4600
- getEditComposer(messageId) {
4601
- return this._editComposers.get(messageId);
4602
- }
4603
4643
  beginEdit(messageId) {
4604
- if (this._editComposers.has(messageId))
4605
- throw new Error("Edit already in progress");
4606
- this._editComposers.set(
4607
- messageId,
4608
- new DefaultEditComposerRuntimeCore(
4609
- this,
4610
- () => this._editComposers.delete(messageId),
4611
- this.repository.getMessage(messageId)
4612
- )
4613
- );
4614
- this.notifySubscribers();
4644
+ if (!this.store.onEdit)
4645
+ throw new Error("Runtime does not support editing.");
4646
+ super.beginEdit(messageId);
4647
+ }
4648
+ constructor(configProvider, store) {
4649
+ super(configProvider);
4650
+ this.store = store;
4615
4651
  }
4616
4652
  get store() {
4617
4653
  return this._store;
@@ -4630,13 +4666,12 @@ var ExternalStoreThreadRuntimeCore = class {
4630
4666
  edit: this._store.onEdit !== void 0,
4631
4667
  reload: this._store.onReload !== void 0,
4632
4668
  cancel: this._store.onCancel !== void 0,
4633
- speak: this._store.onSpeak !== void 0,
4669
+ speech: this._store.adapters?.speech !== void 0,
4634
4670
  unstable_copy: this._store.unstable_capabilities?.copy !== false,
4635
4671
  // default true
4636
4672
  attachments: !!this.store.adapters?.attachments,
4637
4673
  feedback: !!this.store.adapters?.feedback
4638
4674
  };
4639
- this.composer.setAttachmentAdapter(this._store.adapters?.attachments);
4640
4675
  if (oldStore) {
4641
4676
  if (oldStore.convertMessage !== store.convertMessage) {
4642
4677
  this._converter = new ThreadMessageConverter();
@@ -4680,18 +4715,9 @@ var ExternalStoreThreadRuntimeCore = class {
4680
4715
  this.repository.resetHead(
4681
4716
  this.assistantOptimisticId ?? messages2.at(-1)?.id ?? null
4682
4717
  );
4683
- this.messages = this.repository.getMessages();
4718
+ this._messages = this.repository.getMessages();
4684
4719
  this.notifySubscribers();
4685
4720
  }
4686
- getModelConfig() {
4687
- return this.configProvider.getModelConfig();
4688
- }
4689
- notifySubscribers() {
4690
- for (const callback of this._subscriptions) callback();
4691
- }
4692
- getBranches(messageId) {
4693
- return this.repository.getBranches(messageId);
4694
- }
4695
4721
  switchToBranch(branchId) {
4696
4722
  if (!this._store.setMessages)
4697
4723
  throw new Error("Runtime does not support switching branches.");
@@ -4740,33 +4766,11 @@ var ExternalStoreThreadRuntimeCore = class {
4740
4766
  throw new Error("Runtime does not support tool results.");
4741
4767
  this._store.onAddToolResult(options);
4742
4768
  }
4743
- speak(messageId) {
4744
- if (!this._store.onSpeak)
4745
- throw new Error("Runtime does not support speaking.");
4746
- const { message } = this.repository.getMessage(messageId);
4747
- return this._store.onSpeak(message);
4748
- }
4749
- submitFeedback({ messageId, type }) {
4750
- const adapter = this._store.adapters?.feedback;
4751
- if (!adapter) throw new Error("Feedback adapter not configured");
4752
- const { message } = this.repository.getMessage(messageId);
4753
- adapter.submit({ message, type });
4754
- }
4755
- subscribe(callback) {
4756
- this._subscriptions.add(callback);
4757
- return () => this._subscriptions.delete(callback);
4758
- }
4759
4769
  updateMessages = (messages2) => {
4760
4770
  this._store.setMessages?.(
4761
4771
  messages2.flatMap(getExternalStoreMessage).filter((m) => m != null)
4762
4772
  );
4763
4773
  };
4764
- import(repository) {
4765
- this.repository.import(repository);
4766
- }
4767
- export() {
4768
- return this.repository.export();
4769
- }
4770
4774
  };
4771
4775
 
4772
4776
  // src/runtimes/external-store/ExternalStoreRuntimeCore.tsx
@@ -4821,7 +4825,7 @@ var useExternalStoreRuntime = (store) => {
4821
4825
  runtime.thread.store = store;
4822
4826
  });
4823
4827
  return useMemo12(
4824
- () => new AssistantRuntimeImpl(runtime, ThreadRuntimeImpl),
4828
+ () => AssistantRuntimeImpl.create(runtime, ThreadRuntimeImpl),
4825
4829
  [runtime]
4826
4830
  );
4827
4831
  };
@@ -5011,11 +5015,11 @@ var WebSpeechSynthesisAdapter = class {
5011
5015
  speak(message) {
5012
5016
  const text = getThreadMessageText(message);
5013
5017
  const utterance = new SpeechSynthesisUtterance(text);
5014
- const endHandlers = /* @__PURE__ */ new Set();
5018
+ const subscribers = /* @__PURE__ */ new Set();
5015
5019
  const handleEnd = (reason, error) => {
5016
5020
  if (res.status.type === "ended") return;
5017
5021
  res.status = { type: "ended", reason, error };
5018
- endHandlers.forEach((handler) => handler());
5022
+ subscribers.forEach((handler) => handler());
5019
5023
  };
5020
5024
  utterance.addEventListener("end", () => handleEnd("finished"));
5021
5025
  utterance.addEventListener("error", (e) => handleEnd("error", e.error));
@@ -5026,7 +5030,7 @@ var WebSpeechSynthesisAdapter = class {
5026
5030
  window.speechSynthesis.cancel();
5027
5031
  handleEnd("cancelled");
5028
5032
  },
5029
- onEnd: (callback) => {
5033
+ subscribe: (callback) => {
5030
5034
  if (res.status.type === "ended") {
5031
5035
  let cancelled = false;
5032
5036
  queueMicrotask(() => {
@@ -5036,9 +5040,9 @@ var WebSpeechSynthesisAdapter = class {
5036
5040
  cancelled = true;
5037
5041
  };
5038
5042
  } else {
5039
- endHandlers.add(callback);
5043
+ subscribers.add(callback);
5040
5044
  return () => {
5041
- endHandlers.delete(callback);
5045
+ subscribers.delete(callback);
5042
5046
  };
5043
5047
  }
5044
5048
  }
@@ -5241,8 +5245,8 @@ var useAllowCopy = (ensureCapability = false) => {
5241
5245
  };
5242
5246
  var useAllowSpeak = (ensureCapability = false) => {
5243
5247
  const { assistantMessage: { allowSpeak = true } = {} } = useThreadConfig();
5244
- const speakSupported = useThread((t) => t.capabilities.speak);
5245
- return allowSpeak && (!ensureCapability || speakSupported);
5248
+ const speechSupported = useThread((t) => t.capabilities.speech);
5249
+ return allowSpeak && (!ensureCapability || speechSupported);
5246
5250
  };
5247
5251
  var useAllowReload = (ensureCapability = false) => {
5248
5252
  const { assistantMessage: { allowReload = true } = {} } = useThreadConfig();
@@ -5288,13 +5292,13 @@ var AssistantActionBarRoot = withDefaults(actionBar_exports.Root, {
5288
5292
  className: "aui-assistant-action-bar-root"
5289
5293
  });
5290
5294
  AssistantActionBarRoot.displayName = "AssistantActionBarRoot";
5291
- var AssistantActionBarCopy = forwardRef24((props, ref) => {
5295
+ var AssistantActionBarCopy = forwardRef24(({ copiedDuration, ...props }, ref) => {
5292
5296
  const {
5293
5297
  strings: {
5294
5298
  assistantMessage: { copy: { tooltip = "Copy" } = {} } = {}
5295
5299
  } = {}
5296
5300
  } = useThreadConfig();
5297
- return /* @__PURE__ */ jsx39(actionBar_exports.Copy, { asChild: true, children: /* @__PURE__ */ jsx39(TooltipIconButton, { tooltip, ...props, ref, children: props.children ?? /* @__PURE__ */ jsxs4(Fragment5, { children: [
5301
+ return /* @__PURE__ */ jsx39(actionBar_exports.Copy, { copiedDuration, asChild: true, children: /* @__PURE__ */ jsx39(TooltipIconButton, { tooltip, ...props, ref, children: props.children ?? /* @__PURE__ */ jsxs4(Fragment5, { children: [
5298
5302
  /* @__PURE__ */ jsx39(message_exports.If, { copied: true, children: /* @__PURE__ */ jsx39(CheckIcon, {}) }),
5299
5303
  /* @__PURE__ */ jsx39(message_exports.If, { copied: false, children: /* @__PURE__ */ jsx39(CopyIcon, {}) })
5300
5304
  ] }) }) });
@@ -5409,7 +5413,7 @@ var BranchPicker = () => {
5409
5413
  const allowBranchPicker = useAllowBranchPicker(true);
5410
5414
  if (!allowBranchPicker) return null;
5411
5415
  return /* @__PURE__ */ jsxs5(BranchPickerRoot, { hideWhenSingleBranch: true, children: [
5412
- /* @__PURE__ */ jsx40(BranchPickerPrevious2, {}),
5416
+ /* @__PURE__ */ jsx40(BranchPickerPrevious, {}),
5413
5417
  /* @__PURE__ */ jsx40(BranchPickerState, {}),
5414
5418
  /* @__PURE__ */ jsx40(BranchPickerNext, {})
5415
5419
  ] });
@@ -5419,7 +5423,7 @@ var BranchPickerRoot = withDefaults(branchPicker_exports.Root, {
5419
5423
  className: "aui-branch-picker-root"
5420
5424
  });
5421
5425
  BranchPickerRoot.displayName = "BranchPickerRoot";
5422
- var BranchPickerPrevious2 = forwardRef25((props, ref) => {
5426
+ var BranchPickerPrevious = forwardRef25((props, ref) => {
5423
5427
  const {
5424
5428
  strings: {
5425
5429
  branchPicker: { previous: { tooltip = "Previous" } = {} } = {}
@@ -5428,7 +5432,7 @@ var BranchPickerPrevious2 = forwardRef25((props, ref) => {
5428
5432
  const allowBranchPicker = useAllowBranchPicker();
5429
5433
  return /* @__PURE__ */ jsx40(branchPicker_exports.Previous, { disabled: !allowBranchPicker, asChild: true, children: /* @__PURE__ */ jsx40(TooltipIconButton, { tooltip, ...props, ref, children: props.children ?? /* @__PURE__ */ jsx40(ChevronLeftIcon, {}) }) });
5430
5434
  });
5431
- BranchPickerPrevious2.displayName = "BranchPickerPrevious";
5435
+ BranchPickerPrevious.displayName = "BranchPickerPrevious";
5432
5436
  var BranchPickerStateWrapper = withDefaults("span", {
5433
5437
  className: "aui-branch-picker-state"
5434
5438
  });
@@ -5450,7 +5454,7 @@ var BranchPickerNext = forwardRef25((props, ref) => {
5450
5454
  BranchPickerNext.displayName = "BranchPickerNext";
5451
5455
  var exports2 = {
5452
5456
  Root: BranchPickerRoot,
5453
- Previous: BranchPickerPrevious2,
5457
+ Previous: BranchPickerPrevious,
5454
5458
  Next: BranchPickerNext
5455
5459
  };
5456
5460
  var branch_picker_default = Object.assign(BranchPicker, exports2);
@@ -5591,12 +5595,30 @@ import { forwardRef as forwardRef27 } from "react";
5591
5595
  import { CircleXIcon } from "lucide-react";
5592
5596
  import { jsx as jsx45, jsxs as jsxs8 } from "react/jsx-runtime";
5593
5597
  var ComposerAttachmentRoot = withDefaults(attachment_exports.Root, {
5594
- className: "aui-composer-attachment-root"
5598
+ className: "aui-attachment-root"
5595
5599
  });
5596
5600
  ComposerAttachmentRoot.displayName = "ComposerAttachmentRoot";
5597
5601
  var ComposerAttachment2 = () => {
5602
+ const typeLabel = useAttachment((a) => {
5603
+ const type = a.type;
5604
+ switch (type) {
5605
+ case "image":
5606
+ return "Image";
5607
+ case "document":
5608
+ return "Document";
5609
+ case "file":
5610
+ return "File";
5611
+ default:
5612
+ const _exhaustiveCheck = type;
5613
+ throw new Error(`Unknown attachment type: ${_exhaustiveCheck}`);
5614
+ }
5615
+ });
5598
5616
  return /* @__PURE__ */ jsxs8(ComposerAttachmentRoot, { children: [
5599
- /* @__PURE__ */ jsx45(attachment_exports.unstable_Thumb, {}),
5617
+ /* @__PURE__ */ jsx45(attachment_exports.unstable_Thumb, { className: "aui-attachment-thumb" }),
5618
+ /* @__PURE__ */ jsxs8("div", { className: "aui-attachment-text", children: [
5619
+ /* @__PURE__ */ jsx45("p", { className: "aui-attachment-name", children: /* @__PURE__ */ jsx45(attachment_exports.Name, {}) }),
5620
+ /* @__PURE__ */ jsx45("p", { className: "aui-attachment-type", children: typeLabel })
5621
+ ] }),
5600
5622
  /* @__PURE__ */ jsx45(ComposerAttachmentRemove, {})
5601
5623
  ] });
5602
5624
  };
@@ -5720,23 +5742,27 @@ var ComposerSendButton = withDefaults(TooltipIconButton, {
5720
5742
  variant: "default",
5721
5743
  className: "aui-composer-send"
5722
5744
  });
5723
- var ComposerSend = forwardRef28((props, ref) => {
5724
- const {
5725
- strings: { composer: { send: { tooltip = "Send" } = {} } = {} } = {}
5726
- } = useThreadConfig();
5727
- return /* @__PURE__ */ jsx46(composer_exports.Send, { asChild: true, children: /* @__PURE__ */ jsx46(ComposerSendButton, { tooltip, ...props, ref, children: props.children ?? /* @__PURE__ */ jsx46(SendHorizontalIcon, {}) }) });
5728
- });
5745
+ var ComposerSend = forwardRef28(
5746
+ (props, ref) => {
5747
+ const {
5748
+ strings: { composer: { send: { tooltip = "Send" } = {} } = {} } = {}
5749
+ } = useThreadConfig();
5750
+ return /* @__PURE__ */ jsx46(composer_exports.Send, { asChild: true, children: /* @__PURE__ */ jsx46(ComposerSendButton, { tooltip, ...props, ref, children: props.children ?? /* @__PURE__ */ jsx46(SendHorizontalIcon, {}) }) });
5751
+ }
5752
+ );
5729
5753
  ComposerSend.displayName = "ComposerSend";
5730
5754
  var ComposerCancelButton = withDefaults(TooltipIconButton, {
5731
5755
  variant: "default",
5732
5756
  className: "aui-composer-cancel"
5733
5757
  });
5734
- var ComposerCancel = forwardRef28((props, ref) => {
5735
- const {
5736
- strings: { composer: { cancel: { tooltip = "Cancel" } = {} } = {} } = {}
5737
- } = useThreadConfig();
5738
- return /* @__PURE__ */ jsx46(composer_exports.Cancel, { asChild: true, children: /* @__PURE__ */ jsx46(ComposerCancelButton, { tooltip, ...props, ref, children: props.children ?? /* @__PURE__ */ jsx46(CircleStopIcon, {}) }) });
5739
- });
5758
+ var ComposerCancel = forwardRef28(
5759
+ (props, ref) => {
5760
+ const {
5761
+ strings: { composer: { cancel: { tooltip = "Cancel" } = {} } = {} } = {}
5762
+ } = useThreadConfig();
5763
+ return /* @__PURE__ */ jsx46(composer_exports.Cancel, { asChild: true, children: /* @__PURE__ */ jsx46(ComposerCancelButton, { tooltip, ...props, ref, children: props.children ?? /* @__PURE__ */ jsx46(CircleStopIcon, {}) }) });
5764
+ }
5765
+ );
5740
5766
  ComposerCancel.displayName = "ComposerCancel";
5741
5767
  var exports6 = {
5742
5768
  Root: ComposerRoot,
@@ -5768,11 +5794,9 @@ var ThreadWelcomeRootStyled = withDefaults("div", {
5768
5794
  var ThreadWelcomeCenter = withDefaults("div", {
5769
5795
  className: "aui-thread-welcome-center"
5770
5796
  });
5771
- var ThreadWelcomeRoot = forwardRef29(
5772
- (props, ref) => {
5773
- return /* @__PURE__ */ jsx47(thread_exports.Empty, { children: /* @__PURE__ */ jsx47(ThreadWelcomeRootStyled, { ...props, ref }) });
5774
- }
5775
- );
5797
+ var ThreadWelcomeRoot = forwardRef29((props, ref) => {
5798
+ return /* @__PURE__ */ jsx47(thread_exports.Empty, { children: /* @__PURE__ */ jsx47(ThreadWelcomeRootStyled, { ...props, ref }) });
5799
+ });
5776
5800
  ThreadWelcomeRoot.displayName = "ThreadWelcomeRoot";
5777
5801
  var ThreadWelcomeAvatar = () => {
5778
5802
  const { assistantAvatar: avatar = { fallback: "A" } } = useThreadConfig();
@@ -5854,13 +5878,33 @@ var exports8 = {
5854
5878
  var user_action_bar_default = Object.assign(UserActionBar, exports8);
5855
5879
 
5856
5880
  // src/ui/user-message-attachment.tsx
5857
- import { jsx as jsx49 } from "react/jsx-runtime";
5881
+ import { jsx as jsx49, jsxs as jsxs11 } from "react/jsx-runtime";
5858
5882
  var UserMessageAttachmentRoot = withDefaults(attachment_exports.Root, {
5859
- className: "aui-user-message-attachment-root"
5883
+ className: "aui-attachment-root"
5860
5884
  });
5861
5885
  UserMessageAttachmentRoot.displayName = "UserMessageAttachmentRoot";
5862
5886
  var UserMessageAttachment = () => {
5863
- return /* @__PURE__ */ jsx49(UserMessageAttachmentRoot, { children: /* @__PURE__ */ jsx49(attachment_exports.unstable_Thumb, {}) });
5887
+ const typeLabel = useAttachment((a) => {
5888
+ const type = a.type;
5889
+ switch (type) {
5890
+ case "image":
5891
+ return "Image";
5892
+ case "document":
5893
+ return "Document";
5894
+ case "file":
5895
+ return "File";
5896
+ default:
5897
+ const _exhaustiveCheck = type;
5898
+ throw new Error(`Unknown attachment type: ${_exhaustiveCheck}`);
5899
+ }
5900
+ });
5901
+ return /* @__PURE__ */ jsxs11(UserMessageAttachmentRoot, { children: [
5902
+ /* @__PURE__ */ jsx49(attachment_exports.unstable_Thumb, { className: "aui-attachment-thumb" }),
5903
+ /* @__PURE__ */ jsxs11("div", { className: "aui-attachment-text", children: [
5904
+ /* @__PURE__ */ jsx49("p", { className: "aui-attachment-name", children: /* @__PURE__ */ jsx49(attachment_exports.Name, {}) }),
5905
+ /* @__PURE__ */ jsx49("p", { className: "aui-attachment-type", children: typeLabel })
5906
+ ] })
5907
+ ] });
5864
5908
  };
5865
5909
  UserMessageAttachment.displayName = "UserMessageAttachment";
5866
5910
  var exports9 = {
@@ -5872,12 +5916,14 @@ var user_message_attachment_default = Object.assign(
5872
5916
  );
5873
5917
 
5874
5918
  // src/ui/user-message.tsx
5875
- import { jsx as jsx50, jsxs as jsxs11 } from "react/jsx-runtime";
5919
+ import { jsx as jsx50, jsxs as jsxs12 } from "react/jsx-runtime";
5876
5920
  var UserMessage = () => {
5877
- return /* @__PURE__ */ jsxs11(UserMessageRoot, { children: [
5921
+ return /* @__PURE__ */ jsxs12(UserMessageRoot, { children: [
5878
5922
  /* @__PURE__ */ jsx50(UserMessageAttachments, {}),
5879
- /* @__PURE__ */ jsx50(user_action_bar_default, {}),
5880
- /* @__PURE__ */ jsx50(UserMessageContent, {}),
5923
+ /* @__PURE__ */ jsxs12(message_exports.If, { hasContent: true, children: [
5924
+ /* @__PURE__ */ jsx50(user_action_bar_default, {}),
5925
+ /* @__PURE__ */ jsx50(UserMessageContent, {})
5926
+ ] }),
5881
5927
  /* @__PURE__ */ jsx50(branch_picker_default, {})
5882
5928
  ] });
5883
5929
  };
@@ -5889,19 +5935,17 @@ UserMessageRoot.displayName = "UserMessageRoot";
5889
5935
  var UserMessageContentWrapper = withDefaults("div", {
5890
5936
  className: "aui-user-message-content"
5891
5937
  });
5892
- var UserMessageContent = forwardRef31(
5893
- ({ components, ...props }, ref) => {
5894
- return /* @__PURE__ */ jsx50(UserMessageContentWrapper, { ...props, ref, children: /* @__PURE__ */ jsx50(
5895
- message_exports.Content,
5896
- {
5897
- components: {
5898
- ...components,
5899
- Text: components?.Text ?? content_part_default.Text
5900
- }
5938
+ var UserMessageContent = forwardRef31(({ components, ...props }, ref) => {
5939
+ return /* @__PURE__ */ jsx50(UserMessageContentWrapper, { ...props, ref, children: /* @__PURE__ */ jsx50(
5940
+ message_exports.Content,
5941
+ {
5942
+ components: {
5943
+ ...components,
5944
+ Text: components?.Text ?? content_part_default.Text
5901
5945
  }
5902
- ) });
5903
- }
5904
- );
5946
+ }
5947
+ ) });
5948
+ });
5905
5949
  UserMessageContent.displayName = "UserMessageContent";
5906
5950
  var UserMessageAttachmentsContainer = withDefaults("div", {
5907
5951
  className: "aui-user-message-attachments"
@@ -5928,11 +5972,11 @@ var user_message_default = Object.assign(UserMessage, exports10);
5928
5972
 
5929
5973
  // src/ui/edit-composer.tsx
5930
5974
  import { forwardRef as forwardRef32 } from "react";
5931
- import { jsx as jsx51, jsxs as jsxs12 } from "react/jsx-runtime";
5975
+ import { jsx as jsx51, jsxs as jsxs13 } from "react/jsx-runtime";
5932
5976
  var EditComposer = () => {
5933
- return /* @__PURE__ */ jsxs12(EditComposerRoot, { children: [
5977
+ return /* @__PURE__ */ jsxs13(EditComposerRoot, { children: [
5934
5978
  /* @__PURE__ */ jsx51(EditComposerInput, {}),
5935
- /* @__PURE__ */ jsxs12(EditComposerFooter, { children: [
5979
+ /* @__PURE__ */ jsxs13(EditComposerFooter, { children: [
5936
5980
  /* @__PURE__ */ jsx51(EditComposerCancel, {}),
5937
5981
  /* @__PURE__ */ jsx51(EditComposerSend, {})
5938
5982
  ] })
@@ -5951,25 +5995,19 @@ var EditComposerFooter = withDefaults("div", {
5951
5995
  className: "aui-edit-composer-footer"
5952
5996
  });
5953
5997
  EditComposerFooter.displayName = "EditComposerFooter";
5954
- var EditComposerCancel = forwardRef32(
5955
- (props, ref) => {
5956
- const {
5957
- strings: {
5958
- editComposer: { cancel: { label = "Cancel" } = {} } = {}
5959
- } = {}
5960
- } = useThreadConfig();
5961
- return /* @__PURE__ */ jsx51(composer_exports.Cancel, { asChild: true, children: /* @__PURE__ */ jsx51(Button, { variant: "ghost", ...props, ref, children: props.children ?? label }) });
5962
- }
5963
- );
5998
+ var EditComposerCancel = forwardRef32((props, ref) => {
5999
+ const {
6000
+ strings: { editComposer: { cancel: { label = "Cancel" } = {} } = {} } = {}
6001
+ } = useThreadConfig();
6002
+ return /* @__PURE__ */ jsx51(composer_exports.Cancel, { asChild: true, children: /* @__PURE__ */ jsx51(Button, { variant: "ghost", ...props, ref, children: props.children ?? label }) });
6003
+ });
5964
6004
  EditComposerCancel.displayName = "EditComposerCancel";
5965
- var EditComposerSend = forwardRef32(
5966
- (props, ref) => {
5967
- const {
5968
- strings: { editComposer: { send: { label = "Send" } = {} } = {} } = {}
5969
- } = useThreadConfig();
5970
- return /* @__PURE__ */ jsx51(composer_exports.Send, { asChild: true, children: /* @__PURE__ */ jsx51(Button, { ...props, ref, children: props.children ?? label }) });
5971
- }
5972
- );
6005
+ var EditComposerSend = forwardRef32((props, ref) => {
6006
+ const {
6007
+ strings: { editComposer: { send: { label = "Send" } = {} } = {} } = {}
6008
+ } = useThreadConfig();
6009
+ return /* @__PURE__ */ jsx51(composer_exports.Send, { asChild: true, children: /* @__PURE__ */ jsx51(Button, { ...props, ref, children: props.children ?? label }) });
6010
+ });
5973
6011
  EditComposerSend.displayName = "EditComposerSend";
5974
6012
  var exports11 = {
5975
6013
  Root: EditComposerRoot,
@@ -5981,7 +6019,7 @@ var exports11 = {
5981
6019
  var edit_composer_default = Object.assign(EditComposer, exports11);
5982
6020
 
5983
6021
  // src/ui/thread.tsx
5984
- import { Fragment as Fragment7, jsx as jsx52, jsxs as jsxs13 } from "react/jsx-runtime";
6022
+ import { Fragment as Fragment7, jsx as jsx52, jsxs as jsxs14 } from "react/jsx-runtime";
5985
6023
  var Thread = (config) => {
5986
6024
  const {
5987
6025
  components: {
@@ -5989,11 +6027,11 @@ var Thread = (config) => {
5989
6027
  ThreadWelcome: ThreadWelcomeComponent = thread_welcome_default
5990
6028
  } = {}
5991
6029
  } = config;
5992
- return /* @__PURE__ */ jsx52(ThreadRoot, { config, children: /* @__PURE__ */ jsxs13(ThreadViewport, { children: [
6030
+ return /* @__PURE__ */ jsx52(ThreadRoot, { config, children: /* @__PURE__ */ jsxs14(ThreadViewport, { children: [
5993
6031
  /* @__PURE__ */ jsx52(ThreadWelcomeComponent, {}),
5994
6032
  /* @__PURE__ */ jsx52(ThreadMessages, {}),
5995
6033
  /* @__PURE__ */ jsx52(ThreadFollowupSuggestions, {}),
5996
- /* @__PURE__ */ jsxs13(ThreadViewportFooter, { children: [
6034
+ /* @__PURE__ */ jsxs14(ThreadViewportFooter, { children: [
5997
6035
  /* @__PURE__ */ jsx52(ThreadScrollToBottom, {}),
5998
6036
  /* @__PURE__ */ jsx52(ComposerComponent, {})
5999
6037
  ] })
@@ -6018,7 +6056,7 @@ var ThreadViewportFooter = withDefaults("div", {
6018
6056
  ThreadViewportFooter.displayName = "ThreadViewportFooter";
6019
6057
  var SystemMessage = () => null;
6020
6058
  var ThreadMessages = ({ components, unstable_flexGrowDiv: flexGrowDiv = true, ...rest }) => {
6021
- return /* @__PURE__ */ jsxs13(Fragment7, { children: [
6059
+ return /* @__PURE__ */ jsxs14(Fragment7, { children: [
6022
6060
  /* @__PURE__ */ jsx52(
6023
6061
  thread_exports.Messages,
6024
6062
  {
@@ -6073,15 +6111,18 @@ var exports12 = {
6073
6111
  var thread_default = Object.assign(Thread, exports12);
6074
6112
 
6075
6113
  // src/ui/assistant-modal.tsx
6076
- import { Fragment as Fragment8, jsx as jsx53, jsxs as jsxs14 } from "react/jsx-runtime";
6114
+ import { Fragment as Fragment8, jsx as jsx53, jsxs as jsxs15 } from "react/jsx-runtime";
6077
6115
  var AssistantModal = (config) => {
6078
- return /* @__PURE__ */ jsxs14(AssistantModalRoot, { config, children: [
6116
+ return /* @__PURE__ */ jsxs15(AssistantModalRoot, { config, children: [
6079
6117
  /* @__PURE__ */ jsx53(AssistantModalTrigger, {}),
6080
6118
  /* @__PURE__ */ jsx53(AssistantModalContent, { children: /* @__PURE__ */ jsx53(thread_default, {}) })
6081
6119
  ] });
6082
6120
  };
6083
6121
  AssistantModal.displayName = "AssistantModal";
6084
- var AssistantModalRoot = ({ config, ...props }) => {
6122
+ var AssistantModalRoot = ({
6123
+ config,
6124
+ ...props
6125
+ }) => {
6085
6126
  return /* @__PURE__ */ jsx53(ThreadConfigProvider, { config, children: /* @__PURE__ */ jsx53(assistantModal_exports.Root, { ...props }) });
6086
6127
  };
6087
6128
  AssistantModalRoot.displayName = "AssistantModalRoot";
@@ -6119,7 +6160,7 @@ var AssistantModalButton = forwardRef34(({ "data-state": state, ...rest }, ref)
6119
6160
  "data-state": state,
6120
6161
  ...rest,
6121
6162
  ref,
6122
- children: rest.children ?? /* @__PURE__ */ jsxs14(Fragment8, { children: [
6163
+ children: rest.children ?? /* @__PURE__ */ jsxs15(Fragment8, { children: [
6123
6164
  /* @__PURE__ */ jsx53(
6124
6165
  BotIcon,
6125
6166
  {