@yourgpt/copilot-sdk 2.5.1-beta.0 → 2.5.2-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1730,6 +1730,12 @@ type ChatProps = {
1730
1730
  onSwitchThread?: (threadId: string) => void;
1731
1731
  /** Whether a thread operation is in progress (disables controls) */
1732
1732
  isThreadBusy?: boolean;
1733
+ /**
1734
+ * Set of thread IDs with an in-flight request. Populated only when
1735
+ * `concurrentThreads` is enabled on the CopilotProvider. Use in a custom
1736
+ * thread picker to show a per-thread streaming indicator.
1737
+ */
1738
+ busyThreadIds?: ReadonlySet<string>;
1733
1739
  /**
1734
1740
  * Returns branch navigation info for a message ID.
1735
1741
  * Provide this to enable the ← N/M → navigator below edited user messages.
@@ -1834,6 +1840,11 @@ interface CopilotChatInternalContext {
1834
1840
  onSwitchThread?: (id: string) => void;
1835
1841
  onDeleteThread?: (id: string) => void;
1836
1842
  isThreadBusy?: boolean;
1843
+ /**
1844
+ * Set of thread IDs that currently have an in-flight request. Populated
1845
+ * only when `concurrentThreads` is enabled on the CopilotProvider.
1846
+ */
1847
+ busyThreadIds?: ReadonlySet<string>;
1837
1848
  }
1838
1849
  /**
1839
1850
  * Hook to access CopilotChat internal context.
@@ -1929,7 +1940,7 @@ declare function BackButton({ className, children, disabled, "aria-label": ariaL
1929
1940
  */
1930
1941
  type ThreadPickerCompoundProps = Omit<ThreadPickerProps, "value" | "threads" | "onSelect" | "onNewThread" | "onDeleteThread" | "disabled">;
1931
1942
  declare function ThreadPickerCompound(props: ThreadPickerCompoundProps): react_jsx_runtime.JSX.Element | null;
1932
- declare function ChatComponent({ messages, onSendMessage, onStop, isLoading, error, children, placeholder, welcomeMessage, title, showHeader, header, threadPicker, logo, name, onClose, showPoweredBy, showUserAvatar, userAvatar: userAvatarProp, assistantAvatar: assistantAvatarProp, loaderVariant, fontSize, maxFileSize, allowedFileTypes, attachmentsEnabled, attachmentsDisabledTooltip, upload: uploadProp, processAttachment: deprecatedProcessAttachment, suggestions, onSuggestionClick, welcome, recentThreads, onSelectThread, onDeleteThread, onViewMoreThreads, isProcessing, registeredTools, toolRenderers, mcpToolRenderer, fallbackToolRenderer, onApproveToolExecution, onRejectToolExecution, showFollowUps, followUpClassName, followUpButtonClassName, citations, allowToCopyMessage, messageView, renderMessage, wrapMessage, renderInput, renderHeader, groupConsecutiveMessages, className, classNames, onNewChat, threads, currentThreadId, onSwitchThread, isThreadBusy, getBranchInfo, onSwitchBranch, onEditMessage, }: ChatProps): react_jsx_runtime.JSX.Element;
1943
+ declare function ChatComponent({ messages, onSendMessage, onStop, isLoading, error, children, placeholder, welcomeMessage, title, showHeader, header, threadPicker, logo, name, onClose, showPoweredBy, showUserAvatar, userAvatar: userAvatarProp, assistantAvatar: assistantAvatarProp, loaderVariant, fontSize, maxFileSize, allowedFileTypes, attachmentsEnabled, attachmentsDisabledTooltip, upload: uploadProp, processAttachment: deprecatedProcessAttachment, suggestions, onSuggestionClick, welcome, recentThreads, onSelectThread, onDeleteThread, onViewMoreThreads, isProcessing, registeredTools, toolRenderers, mcpToolRenderer, fallbackToolRenderer, onApproveToolExecution, onRejectToolExecution, showFollowUps, followUpClassName, followUpButtonClassName, citations, allowToCopyMessage, messageView, renderMessage, wrapMessage, renderInput, renderHeader, groupConsecutiveMessages, className, classNames, onNewChat, threads, currentThreadId, onSwitchThread, isThreadBusy, busyThreadIds, getBranchInfo, onSwitchBranch, onEditMessage, }: ChatProps): react_jsx_runtime.JSX.Element;
1933
1944
  /**
1934
1945
  * Chat component with compound component pattern.
1935
1946
  *
@@ -1730,6 +1730,12 @@ type ChatProps = {
1730
1730
  onSwitchThread?: (threadId: string) => void;
1731
1731
  /** Whether a thread operation is in progress (disables controls) */
1732
1732
  isThreadBusy?: boolean;
1733
+ /**
1734
+ * Set of thread IDs with an in-flight request. Populated only when
1735
+ * `concurrentThreads` is enabled on the CopilotProvider. Use in a custom
1736
+ * thread picker to show a per-thread streaming indicator.
1737
+ */
1738
+ busyThreadIds?: ReadonlySet<string>;
1733
1739
  /**
1734
1740
  * Returns branch navigation info for a message ID.
1735
1741
  * Provide this to enable the ← N/M → navigator below edited user messages.
@@ -1834,6 +1840,11 @@ interface CopilotChatInternalContext {
1834
1840
  onSwitchThread?: (id: string) => void;
1835
1841
  onDeleteThread?: (id: string) => void;
1836
1842
  isThreadBusy?: boolean;
1843
+ /**
1844
+ * Set of thread IDs that currently have an in-flight request. Populated
1845
+ * only when `concurrentThreads` is enabled on the CopilotProvider.
1846
+ */
1847
+ busyThreadIds?: ReadonlySet<string>;
1837
1848
  }
1838
1849
  /**
1839
1850
  * Hook to access CopilotChat internal context.
@@ -1929,7 +1940,7 @@ declare function BackButton({ className, children, disabled, "aria-label": ariaL
1929
1940
  */
1930
1941
  type ThreadPickerCompoundProps = Omit<ThreadPickerProps, "value" | "threads" | "onSelect" | "onNewThread" | "onDeleteThread" | "disabled">;
1931
1942
  declare function ThreadPickerCompound(props: ThreadPickerCompoundProps): react_jsx_runtime.JSX.Element | null;
1932
- declare function ChatComponent({ messages, onSendMessage, onStop, isLoading, error, children, placeholder, welcomeMessage, title, showHeader, header, threadPicker, logo, name, onClose, showPoweredBy, showUserAvatar, userAvatar: userAvatarProp, assistantAvatar: assistantAvatarProp, loaderVariant, fontSize, maxFileSize, allowedFileTypes, attachmentsEnabled, attachmentsDisabledTooltip, upload: uploadProp, processAttachment: deprecatedProcessAttachment, suggestions, onSuggestionClick, welcome, recentThreads, onSelectThread, onDeleteThread, onViewMoreThreads, isProcessing, registeredTools, toolRenderers, mcpToolRenderer, fallbackToolRenderer, onApproveToolExecution, onRejectToolExecution, showFollowUps, followUpClassName, followUpButtonClassName, citations, allowToCopyMessage, messageView, renderMessage, wrapMessage, renderInput, renderHeader, groupConsecutiveMessages, className, classNames, onNewChat, threads, currentThreadId, onSwitchThread, isThreadBusy, getBranchInfo, onSwitchBranch, onEditMessage, }: ChatProps): react_jsx_runtime.JSX.Element;
1943
+ declare function ChatComponent({ messages, onSendMessage, onStop, isLoading, error, children, placeholder, welcomeMessage, title, showHeader, header, threadPicker, logo, name, onClose, showPoweredBy, showUserAvatar, userAvatar: userAvatarProp, assistantAvatar: assistantAvatarProp, loaderVariant, fontSize, maxFileSize, allowedFileTypes, attachmentsEnabled, attachmentsDisabledTooltip, upload: uploadProp, processAttachment: deprecatedProcessAttachment, suggestions, onSuggestionClick, welcome, recentThreads, onSelectThread, onDeleteThread, onViewMoreThreads, isProcessing, registeredTools, toolRenderers, mcpToolRenderer, fallbackToolRenderer, onApproveToolExecution, onRejectToolExecution, showFollowUps, followUpClassName, followUpButtonClassName, citations, allowToCopyMessage, messageView, renderMessage, wrapMessage, renderInput, renderHeader, groupConsecutiveMessages, className, classNames, onNewChat, threads, currentThreadId, onSwitchThread, isThreadBusy, busyThreadIds, getBranchInfo, onSwitchBranch, onEditMessage, }: ChatProps): react_jsx_runtime.JSX.Element;
1933
1944
  /**
1934
1945
  * Chat component with compound component pattern.
1935
1946
  *
package/dist/ui/index.js CHANGED
@@ -1,8 +1,8 @@
1
- import { useThreadManager } from '../chunk-YYLTWY5R.js';
1
+ import { useThreadManager } from '../chunk-VHJ46HKC.js';
2
2
  import { DEFAULT_MCP_UI_SANDBOX, parseMCPUIMessage } from '../chunk-G4SF2PNQ.js';
3
3
  import { cn, Loader, TextShimmerLoader } from '../chunk-TXQ37MAO.js';
4
4
  export { Loader, cn } from '../chunk-TXQ37MAO.js';
5
- import { useCopilot } from '../chunk-JPUKXFR4.js';
5
+ import { useCopilot } from '../chunk-37HN4F6S.js';
6
6
  import { createLocalStorageAdapter, createServerAdapter } from '../chunk-J5D3AZF6.js';
7
7
  import '../chunk-EWVQWTNV.js';
8
8
  import '../chunk-VNLLW3ZI.js';
@@ -4310,7 +4310,8 @@ function FloatingActions({
4310
4310
  role,
4311
4311
  align = "left",
4312
4312
  onEdit,
4313
- className
4313
+ className,
4314
+ copyContent
4314
4315
  }) {
4315
4316
  const ctx = useMessageActionsContext();
4316
4317
  const [copiedId, setCopiedId] = React19.useState(null);
@@ -4328,6 +4329,9 @@ function FloatingActions({
4328
4329
  ),
4329
4330
  children: actions.map((action) => {
4330
4331
  const isHidden = typeof action.hidden === "function" ? action.hidden({ message }) : action.hidden;
4332
+ if (action.id === "copy" && copyContent != null && !copyContent.trim())
4333
+ return null;
4334
+ if (action.id === "copy" && copyContent === null) return null;
4331
4335
  if (isHidden) return null;
4332
4336
  const isCopied = copiedId === action.id;
4333
4337
  return /* @__PURE__ */ jsx(
@@ -4350,7 +4354,8 @@ function FloatingActions({
4350
4354
  return;
4351
4355
  }
4352
4356
  if (action.id === "copy") {
4353
- navigator.clipboard.writeText(message.content ?? "");
4357
+ const text = copyContent !== void 0 ? copyContent ?? "" : message.content ?? "";
4358
+ navigator.clipboard.writeText(text);
4354
4359
  setCopiedId("copy");
4355
4360
  setTimeout(() => setCopiedId(null), 1500);
4356
4361
  return;
@@ -4730,18 +4735,30 @@ function DefaultMessage({
4730
4735
  isLastMessage && isProcessing && !completedTools?.length && !pendingApprovalTools?.length ? /* @__PURE__ */ jsx("div", { className: "rounded-lg bg-muted px-4 py-2", children: /* @__PURE__ */ jsx(Loader, { variant: "dots", size: "sm" }) }) : (
4731
4736
  /* Show streaming loader when loading with no content and no tools */
4732
4737
  isLastMessage && isLoading && !cleanContent?.trim() && !toolsWithCustomRender?.length && !toolsWithoutCustomRender?.length && !pendingApprovalTools?.length ? /* @__PURE__ */ jsx("div", { className: "rounded-lg bg-muted px-4 py-2", children: /* @__PURE__ */ jsx(Loader, { variant: loaderVariant, size: "sm" }) }) : /* @__PURE__ */ jsxs("div", { className: "relative", children: [
4733
- cleanContent?.trim() && /* @__PURE__ */ jsx(
4734
- MessageContent,
4735
- {
4736
- className: cn(
4737
- "csdk-message-assistant rounded-lg px-4 py-2 bg-muted",
4738
- assistantMessageClassName
4739
- ),
4740
- markdown: true,
4741
- size,
4742
- children: cleanContent
4743
- }
4744
- ),
4738
+ cleanContent?.trim() && /* @__PURE__ */ jsxs("div", { className: "relative", children: [
4739
+ /* @__PURE__ */ jsx(
4740
+ MessageContent,
4741
+ {
4742
+ className: cn(
4743
+ "csdk-message-assistant rounded-lg px-4 py-2 bg-muted",
4744
+ assistantMessageClassName
4745
+ ),
4746
+ markdown: true,
4747
+ size,
4748
+ children: cleanContent
4749
+ }
4750
+ ),
4751
+ /* @__PURE__ */ jsx(
4752
+ FloatingActions,
4753
+ {
4754
+ message,
4755
+ role: "assistant",
4756
+ align: "right",
4757
+ className: "absolute bottom-1 right-1",
4758
+ copyContent: cleanContent
4759
+ }
4760
+ )
4761
+ ] }),
4745
4762
  toolsWithCustomRender && toolsWithCustomRender.length > 0 && /* @__PURE__ */ jsx("div", { className: cn("space-y-2", cleanContent?.trim() && "mt-2"), children: toolsWithCustomRender.map((exec) => {
4746
4763
  const toolDef = registeredTools?.find(
4747
4764
  (t) => t.name === exec.name
@@ -4929,15 +4946,6 @@ function DefaultMessage({
4929
4946
  className: followUpClassName,
4930
4947
  buttonClassName: followUpButtonClassName
4931
4948
  }
4932
- ),
4933
- /* @__PURE__ */ jsx(
4934
- FloatingActions,
4935
- {
4936
- message,
4937
- role: "assistant",
4938
- align: "right",
4939
- className: "absolute bottom-1 right-1"
4940
- }
4941
4949
  )
4942
4950
  ] })
4943
4951
  )
@@ -5956,6 +5964,7 @@ function ChatComponent({
5956
5964
  currentThreadId,
5957
5965
  onSwitchThread,
5958
5966
  isThreadBusy,
5967
+ busyThreadIds,
5959
5968
  // Branching
5960
5969
  getBranchInfo,
5961
5970
  onSwitchBranch,
@@ -6197,7 +6206,8 @@ function ChatComponent({
6197
6206
  currentThreadId,
6198
6207
  onSwitchThread,
6199
6208
  onDeleteThread,
6200
- isThreadBusy
6209
+ isThreadBusy,
6210
+ busyThreadIds
6201
6211
  }),
6202
6212
  [
6203
6213
  view,
@@ -6213,7 +6223,8 @@ function ChatComponent({
6213
6223
  currentThreadId,
6214
6224
  onSwitchThread,
6215
6225
  onDeleteThread,
6216
- isThreadBusy
6226
+ isThreadBusy,
6227
+ busyThreadIds
6217
6228
  ]
6218
6229
  );
6219
6230
  return /* @__PURE__ */ jsx(MessageActionsProvider, { children: /* @__PURE__ */ jsx(CopilotChatContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxs(
@@ -6893,7 +6904,11 @@ function useInternalThreadManager(config = {}) {
6893
6904
  getAllMessages,
6894
6905
  switchBranch,
6895
6906
  threadId: sdkThreadId,
6896
- setActiveThread
6907
+ setActiveThread,
6908
+ concurrentThreads,
6909
+ busyThreadIds,
6910
+ assignLocalThreadId,
6911
+ sessionStatus
6897
6912
  } = useCopilot();
6898
6913
  useEffect(() => {
6899
6914
  if (!enabled || state.initialized || !currentThread) return;
@@ -6902,8 +6917,16 @@ function useInternalThreadManager(config = {}) {
6902
6917
  if (currentThread.messages && currentThread.messages.length > 0) {
6903
6918
  const uiMessages = currentThread.messages.map(coreToUI);
6904
6919
  const snapshot = getMessageSnapshot(uiMessages);
6905
- setMessages(uiMessages);
6906
- if (currentThread.activeLeafId) switchBranch(currentThread.activeLeafId);
6920
+ if (concurrentThreads) {
6921
+ setActiveThread(currentThread.id, {
6922
+ hydrateMessages: uiMessages,
6923
+ hydrateActiveLeafId: currentThread.activeLeafId
6924
+ });
6925
+ } else {
6926
+ setMessages(uiMessages);
6927
+ if (currentThread.activeLeafId)
6928
+ switchBranch(currentThread.activeLeafId);
6929
+ }
6907
6930
  onThreadChange?.(currentThread.id);
6908
6931
  dispatch({
6909
6932
  type: "RESTORE_COMPLETE",
@@ -6911,6 +6934,9 @@ function useInternalThreadManager(config = {}) {
6911
6934
  snapshot
6912
6935
  });
6913
6936
  } else {
6937
+ if (concurrentThreads) {
6938
+ setActiveThread(currentThread.id);
6939
+ }
6914
6940
  onThreadChange?.(currentThread.id);
6915
6941
  dispatch({
6916
6942
  type: "RESTORE_COMPLETE",
@@ -6927,7 +6953,9 @@ function useInternalThreadManager(config = {}) {
6927
6953
  state.initialized,
6928
6954
  setMessages,
6929
6955
  switchBranch,
6930
- onThreadChange
6956
+ onThreadChange,
6957
+ concurrentThreads,
6958
+ setActiveThread
6931
6959
  ]);
6932
6960
  useEffect(() => {
6933
6961
  if (!enabled) {
@@ -6942,11 +6970,24 @@ function useInternalThreadManager(config = {}) {
6942
6970
  if (!enabled) return;
6943
6971
  if (state.phase !== "idle") return;
6944
6972
  if (isLoadingRef.current) return;
6945
- if (status === "streaming" || status === "submitted") return;
6946
6973
  if (messages.length === 0) return;
6947
6974
  if (currentThreadId) return;
6975
+ const streaming = status === "streaming" || status === "submitted";
6976
+ if (streaming && !concurrentThreads) return;
6977
+ if (concurrentThreads && sessionStatus === "creating" && !sdkThreadId) {
6978
+ return;
6979
+ }
6948
6980
  dispatch({ type: "FIRST_RESPONSE_COMPLETE" });
6949
- }, [enabled, state.phase, status, messages.length, currentThreadId]);
6981
+ }, [
6982
+ enabled,
6983
+ state.phase,
6984
+ status,
6985
+ messages.length,
6986
+ currentThreadId,
6987
+ concurrentThreads,
6988
+ sdkThreadId,
6989
+ sessionStatus
6990
+ ]);
6950
6991
  useEffect(() => {
6951
6992
  if (state.phase !== "awaiting_server_id") return;
6952
6993
  if (sdkThreadId) {
@@ -6963,11 +7004,15 @@ function useInternalThreadManager(config = {}) {
6963
7004
  );
6964
7005
  const activeLeafId = messages[messages.length - 1]?.id;
6965
7006
  const snapshot = getMessageSnapshot(messages);
7007
+ const usingLocalId = !sdkThreadId;
6966
7008
  createThread({
6967
7009
  id: sdkThreadId ?? void 0,
6968
7010
  messages: coreMessages,
6969
7011
  activeLeafId
6970
7012
  }).then((thread) => {
7013
+ if (concurrentThreads && usingLocalId) {
7014
+ assignLocalThreadId(thread.id);
7015
+ }
6971
7016
  dispatch({ type: "THREAD_CREATED", threadId: thread.id, snapshot });
6972
7017
  onThreadChange?.(thread.id);
6973
7018
  });
@@ -7004,41 +7049,62 @@ function useInternalThreadManager(config = {}) {
7004
7049
  dispatch({ type: "START_SWITCH" });
7005
7050
  isLoadingRef.current = true;
7006
7051
  const thread = await switchThread(threadId);
7007
- if (thread?.messages) {
7008
- const uiMessages = thread.messages.map(coreToUI);
7009
- const snapshot = getMessageSnapshot(uiMessages);
7010
- setMessages(uiMessages);
7011
- if (thread.activeLeafId) switchBranch(thread.activeLeafId);
7012
- onThreadChange?.(threadId);
7013
- dispatch({ type: "SWITCH_COMPLETE", threadId, snapshot });
7052
+ const uiMessages = thread?.messages ? thread.messages.map(coreToUI) : [];
7053
+ const snapshot = thread?.messages ? getMessageSnapshot(uiMessages) : "";
7054
+ if (concurrentThreads) {
7055
+ setActiveThread(threadId, {
7056
+ hydrateMessages: uiMessages,
7057
+ hydrateActiveLeafId: thread?.activeLeafId
7058
+ });
7014
7059
  } else {
7015
- setMessages([]);
7016
- onThreadChange?.(threadId);
7017
- dispatch({ type: "SWITCH_COMPLETE", threadId, snapshot: "" });
7060
+ if (thread?.messages) {
7061
+ setMessages(uiMessages);
7062
+ if (thread.activeLeafId) switchBranch(thread.activeLeafId);
7063
+ } else {
7064
+ setMessages([]);
7065
+ }
7018
7066
  }
7067
+ onThreadChange?.(threadId);
7068
+ dispatch({ type: "SWITCH_COMPLETE", threadId, snapshot });
7019
7069
  requestAnimationFrame(() => {
7020
7070
  isLoadingRef.current = false;
7021
7071
  });
7022
7072
  },
7023
- [switchThread, setMessages, switchBranch, onThreadChange]
7073
+ [
7074
+ switchThread,
7075
+ setMessages,
7076
+ switchBranch,
7077
+ onThreadChange,
7078
+ concurrentThreads,
7079
+ setActiveThread
7080
+ ]
7024
7081
  );
7025
7082
  const handleNewThread = useCallback(async () => {
7026
7083
  isLoadingRef.current = true;
7027
7084
  clearCurrentThread();
7028
- setMessages([]);
7085
+ if (!concurrentThreads) {
7086
+ setMessages([]);
7087
+ }
7029
7088
  setActiveThread(null);
7030
7089
  onThreadChange?.(null);
7031
7090
  dispatch({ type: "NEW_THREAD" });
7032
7091
  requestAnimationFrame(() => {
7033
7092
  isLoadingRef.current = false;
7034
7093
  });
7035
- }, [clearCurrentThread, setMessages, setActiveThread, onThreadChange]);
7036
- const isBusy = isLoading || status === "streaming" || status === "submitted";
7094
+ }, [
7095
+ clearCurrentThread,
7096
+ setMessages,
7097
+ setActiveThread,
7098
+ onThreadChange,
7099
+ concurrentThreads
7100
+ ]);
7101
+ const isBusy = !concurrentThreads && (isLoading || status === "streaming" || status === "submitted");
7037
7102
  return {
7038
7103
  threadManager,
7039
7104
  handleSwitchThread,
7040
7105
  handleNewThread,
7041
- isBusy
7106
+ isBusy,
7107
+ busyThreadIds
7042
7108
  };
7043
7109
  }
7044
7110
  function parsePersistenceConfig(persistence, onThreadChange) {
@@ -7123,7 +7189,8 @@ function CopilotChatBase(props) {
7123
7189
  switchBranch,
7124
7190
  getBranchInfo,
7125
7191
  editMessage,
7126
- error: chatError
7192
+ error: chatError,
7193
+ disposeThreadInstance
7127
7194
  } = useCopilot();
7128
7195
  const toolExecutions = rawToolExecutions.map(
7129
7196
  (exec) => ({
@@ -7276,16 +7343,23 @@ function CopilotChatBase(props) {
7276
7343
  suggestions: classNames.suggestions,
7277
7344
  footer: classNames.footer
7278
7345
  } : void 0;
7279
- const { threadManager, handleSwitchThread, handleNewThread, isBusy } = threadManagerResult;
7346
+ const {
7347
+ threadManager,
7348
+ handleSwitchThread,
7349
+ handleNewThread,
7350
+ isBusy,
7351
+ busyThreadIds
7352
+ } = threadManagerResult;
7280
7353
  const handleDeleteThread = React19__default.useCallback(
7281
7354
  (threadId) => {
7282
7355
  const isCurrentThread = threadManager.currentThreadId === threadId;
7356
+ disposeThreadInstance(threadId);
7283
7357
  threadManager.deleteThread(threadId);
7284
7358
  if (isCurrentThread) {
7285
7359
  handleNewThread();
7286
7360
  }
7287
7361
  },
7288
- [threadManager, handleNewThread]
7362
+ [threadManager, handleNewThread, disposeThreadInstance]
7289
7363
  );
7290
7364
  const threadPickerElement = isPersistenceEnabled && showThreadPicker ? /* @__PURE__ */ jsx(
7291
7365
  ThreadPicker,
@@ -7335,6 +7409,7 @@ function CopilotChatBase(props) {
7335
7409
  currentThreadId: threadManager.currentThreadId,
7336
7410
  onSwitchThread: isPersistenceEnabled ? handleSwitchThread : void 0,
7337
7411
  isThreadBusy: isBusy,
7412
+ busyThreadIds,
7338
7413
  getBranchInfo,
7339
7414
  onSwitchBranch: switchBranch,
7340
7415
  onEditMessage: allowEdit ? editMessage : void 0,