@yourgpt/copilot-sdk 2.5.1-beta.1 → 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';
@@ -5964,6 +5964,7 @@ function ChatComponent({
5964
5964
  currentThreadId,
5965
5965
  onSwitchThread,
5966
5966
  isThreadBusy,
5967
+ busyThreadIds,
5967
5968
  // Branching
5968
5969
  getBranchInfo,
5969
5970
  onSwitchBranch,
@@ -6205,7 +6206,8 @@ function ChatComponent({
6205
6206
  currentThreadId,
6206
6207
  onSwitchThread,
6207
6208
  onDeleteThread,
6208
- isThreadBusy
6209
+ isThreadBusy,
6210
+ busyThreadIds
6209
6211
  }),
6210
6212
  [
6211
6213
  view,
@@ -6221,7 +6223,8 @@ function ChatComponent({
6221
6223
  currentThreadId,
6222
6224
  onSwitchThread,
6223
6225
  onDeleteThread,
6224
- isThreadBusy
6226
+ isThreadBusy,
6227
+ busyThreadIds
6225
6228
  ]
6226
6229
  );
6227
6230
  return /* @__PURE__ */ jsx(MessageActionsProvider, { children: /* @__PURE__ */ jsx(CopilotChatContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxs(
@@ -6901,7 +6904,11 @@ function useInternalThreadManager(config = {}) {
6901
6904
  getAllMessages,
6902
6905
  switchBranch,
6903
6906
  threadId: sdkThreadId,
6904
- setActiveThread
6907
+ setActiveThread,
6908
+ concurrentThreads,
6909
+ busyThreadIds,
6910
+ assignLocalThreadId,
6911
+ sessionStatus
6905
6912
  } = useCopilot();
6906
6913
  useEffect(() => {
6907
6914
  if (!enabled || state.initialized || !currentThread) return;
@@ -6910,8 +6917,16 @@ function useInternalThreadManager(config = {}) {
6910
6917
  if (currentThread.messages && currentThread.messages.length > 0) {
6911
6918
  const uiMessages = currentThread.messages.map(coreToUI);
6912
6919
  const snapshot = getMessageSnapshot(uiMessages);
6913
- setMessages(uiMessages);
6914
- 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
+ }
6915
6930
  onThreadChange?.(currentThread.id);
6916
6931
  dispatch({
6917
6932
  type: "RESTORE_COMPLETE",
@@ -6919,6 +6934,9 @@ function useInternalThreadManager(config = {}) {
6919
6934
  snapshot
6920
6935
  });
6921
6936
  } else {
6937
+ if (concurrentThreads) {
6938
+ setActiveThread(currentThread.id);
6939
+ }
6922
6940
  onThreadChange?.(currentThread.id);
6923
6941
  dispatch({
6924
6942
  type: "RESTORE_COMPLETE",
@@ -6935,7 +6953,9 @@ function useInternalThreadManager(config = {}) {
6935
6953
  state.initialized,
6936
6954
  setMessages,
6937
6955
  switchBranch,
6938
- onThreadChange
6956
+ onThreadChange,
6957
+ concurrentThreads,
6958
+ setActiveThread
6939
6959
  ]);
6940
6960
  useEffect(() => {
6941
6961
  if (!enabled) {
@@ -6950,11 +6970,24 @@ function useInternalThreadManager(config = {}) {
6950
6970
  if (!enabled) return;
6951
6971
  if (state.phase !== "idle") return;
6952
6972
  if (isLoadingRef.current) return;
6953
- if (status === "streaming" || status === "submitted") return;
6954
6973
  if (messages.length === 0) return;
6955
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
+ }
6956
6980
  dispatch({ type: "FIRST_RESPONSE_COMPLETE" });
6957
- }, [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
+ ]);
6958
6991
  useEffect(() => {
6959
6992
  if (state.phase !== "awaiting_server_id") return;
6960
6993
  if (sdkThreadId) {
@@ -6971,11 +7004,15 @@ function useInternalThreadManager(config = {}) {
6971
7004
  );
6972
7005
  const activeLeafId = messages[messages.length - 1]?.id;
6973
7006
  const snapshot = getMessageSnapshot(messages);
7007
+ const usingLocalId = !sdkThreadId;
6974
7008
  createThread({
6975
7009
  id: sdkThreadId ?? void 0,
6976
7010
  messages: coreMessages,
6977
7011
  activeLeafId
6978
7012
  }).then((thread) => {
7013
+ if (concurrentThreads && usingLocalId) {
7014
+ assignLocalThreadId(thread.id);
7015
+ }
6979
7016
  dispatch({ type: "THREAD_CREATED", threadId: thread.id, snapshot });
6980
7017
  onThreadChange?.(thread.id);
6981
7018
  });
@@ -7012,41 +7049,62 @@ function useInternalThreadManager(config = {}) {
7012
7049
  dispatch({ type: "START_SWITCH" });
7013
7050
  isLoadingRef.current = true;
7014
7051
  const thread = await switchThread(threadId);
7015
- if (thread?.messages) {
7016
- const uiMessages = thread.messages.map(coreToUI);
7017
- const snapshot = getMessageSnapshot(uiMessages);
7018
- setMessages(uiMessages);
7019
- if (thread.activeLeafId) switchBranch(thread.activeLeafId);
7020
- onThreadChange?.(threadId);
7021
- 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
+ });
7022
7059
  } else {
7023
- setMessages([]);
7024
- onThreadChange?.(threadId);
7025
- 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
+ }
7026
7066
  }
7067
+ onThreadChange?.(threadId);
7068
+ dispatch({ type: "SWITCH_COMPLETE", threadId, snapshot });
7027
7069
  requestAnimationFrame(() => {
7028
7070
  isLoadingRef.current = false;
7029
7071
  });
7030
7072
  },
7031
- [switchThread, setMessages, switchBranch, onThreadChange]
7073
+ [
7074
+ switchThread,
7075
+ setMessages,
7076
+ switchBranch,
7077
+ onThreadChange,
7078
+ concurrentThreads,
7079
+ setActiveThread
7080
+ ]
7032
7081
  );
7033
7082
  const handleNewThread = useCallback(async () => {
7034
7083
  isLoadingRef.current = true;
7035
7084
  clearCurrentThread();
7036
- setMessages([]);
7085
+ if (!concurrentThreads) {
7086
+ setMessages([]);
7087
+ }
7037
7088
  setActiveThread(null);
7038
7089
  onThreadChange?.(null);
7039
7090
  dispatch({ type: "NEW_THREAD" });
7040
7091
  requestAnimationFrame(() => {
7041
7092
  isLoadingRef.current = false;
7042
7093
  });
7043
- }, [clearCurrentThread, setMessages, setActiveThread, onThreadChange]);
7044
- 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");
7045
7102
  return {
7046
7103
  threadManager,
7047
7104
  handleSwitchThread,
7048
7105
  handleNewThread,
7049
- isBusy
7106
+ isBusy,
7107
+ busyThreadIds
7050
7108
  };
7051
7109
  }
7052
7110
  function parsePersistenceConfig(persistence, onThreadChange) {
@@ -7131,7 +7189,8 @@ function CopilotChatBase(props) {
7131
7189
  switchBranch,
7132
7190
  getBranchInfo,
7133
7191
  editMessage,
7134
- error: chatError
7192
+ error: chatError,
7193
+ disposeThreadInstance
7135
7194
  } = useCopilot();
7136
7195
  const toolExecutions = rawToolExecutions.map(
7137
7196
  (exec) => ({
@@ -7284,16 +7343,23 @@ function CopilotChatBase(props) {
7284
7343
  suggestions: classNames.suggestions,
7285
7344
  footer: classNames.footer
7286
7345
  } : void 0;
7287
- const { threadManager, handleSwitchThread, handleNewThread, isBusy } = threadManagerResult;
7346
+ const {
7347
+ threadManager,
7348
+ handleSwitchThread,
7349
+ handleNewThread,
7350
+ isBusy,
7351
+ busyThreadIds
7352
+ } = threadManagerResult;
7288
7353
  const handleDeleteThread = React19__default.useCallback(
7289
7354
  (threadId) => {
7290
7355
  const isCurrentThread = threadManager.currentThreadId === threadId;
7356
+ disposeThreadInstance(threadId);
7291
7357
  threadManager.deleteThread(threadId);
7292
7358
  if (isCurrentThread) {
7293
7359
  handleNewThread();
7294
7360
  }
7295
7361
  },
7296
- [threadManager, handleNewThread]
7362
+ [threadManager, handleNewThread, disposeThreadInstance]
7297
7363
  );
7298
7364
  const threadPickerElement = isPersistenceEnabled && showThreadPicker ? /* @__PURE__ */ jsx(
7299
7365
  ThreadPicker,
@@ -7343,6 +7409,7 @@ function CopilotChatBase(props) {
7343
7409
  currentThreadId: threadManager.currentThreadId,
7344
7410
  onSwitchThread: isPersistenceEnabled ? handleSwitchThread : void 0,
7345
7411
  isThreadBusy: isBusy,
7412
+ busyThreadIds,
7346
7413
  getBranchInfo,
7347
7414
  onSwitchBranch: switchBranch,
7348
7415
  onEditMessage: allowEdit ? editMessage : void 0,