@copilotkit/react-core 1.61.2 → 1.62.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.
Files changed (34) hide show
  1. package/dist/{copilotkit-Be-o2UaU.mjs → copilotkit-BtRkFsNR.mjs} +941 -404
  2. package/dist/copilotkit-BtRkFsNR.mjs.map +1 -0
  3. package/dist/{copilotkit-CTCjVxkH.cjs → copilotkit-CdpDZi3i.cjs} +943 -400
  4. package/dist/copilotkit-CdpDZi3i.cjs.map +1 -0
  5. package/dist/{copilotkit-ClqbUuGX.d.cts → copilotkit-Cga6AHO0.d.cts} +429 -149
  6. package/dist/copilotkit-Cga6AHO0.d.cts.map +1 -0
  7. package/dist/{copilotkit-Bpt1c_-q.d.mts → copilotkit-DnLpJ2Cl.d.mts} +429 -149
  8. package/dist/copilotkit-DnLpJ2Cl.d.mts.map +1 -0
  9. package/dist/index.cjs +1 -1
  10. package/dist/index.d.cts +1 -1
  11. package/dist/index.d.mts +1 -1
  12. package/dist/index.mjs +1 -1
  13. package/dist/index.umd.js +193 -176
  14. package/dist/index.umd.js.map +1 -1
  15. package/dist/v2/headless.cjs +156 -11
  16. package/dist/v2/headless.cjs.map +1 -1
  17. package/dist/v2/headless.d.cts +111 -1
  18. package/dist/v2/headless.d.cts.map +1 -1
  19. package/dist/v2/headless.d.mts +111 -1
  20. package/dist/v2/headless.d.mts.map +1 -1
  21. package/dist/v2/headless.mjs +157 -12
  22. package/dist/v2/headless.mjs.map +1 -1
  23. package/dist/v2/index.cjs +2 -1
  24. package/dist/v2/index.css +1 -1
  25. package/dist/v2/index.d.cts +2 -2
  26. package/dist/v2/index.d.mts +2 -2
  27. package/dist/v2/index.mjs +2 -2
  28. package/dist/v2/index.umd.js +949 -412
  29. package/dist/v2/index.umd.js.map +1 -1
  30. package/package.json +8 -6
  31. package/dist/copilotkit-Be-o2UaU.mjs.map +0 -1
  32. package/dist/copilotkit-Bpt1c_-q.d.mts.map +0 -1
  33. package/dist/copilotkit-CTCjVxkH.cjs.map +0 -1
  34. package/dist/copilotkit-ClqbUuGX.d.cts.map +0 -1
@@ -144,6 +144,25 @@ const CopilotChatDefaultLabels = {
144
144
  modalHeaderTitle: "CopilotKit Chat",
145
145
  welcomeMessageText: "How can I help you today?"
146
146
  };
147
+ /**
148
+ * Mobile breakpoint below which the chat modal and the thread-list drawer are
149
+ * mutually exclusive. At or above this width both surfaces may coexist. This
150
+ * mirrors the `(max-width: 767px)` / `(min-width: 768px)` split already used by
151
+ * CopilotChatInput and CopilotSidebarView.
152
+ */
153
+ const MOBILE_MAX_WIDTH_PX = 767;
154
+ /**
155
+ * Reports whether the current viewport is in the mobile range (`<768px`), where
156
+ * the chat modal and drawer must not be open simultaneously. SSR-safe and
157
+ * defensive against environments without `matchMedia` (treated as desktop, so
158
+ * no mutual-exclusion constraint is applied).
159
+ *
160
+ * @returns `true` when the viewport is mobile-width, `false` otherwise.
161
+ */
162
+ function isMobileViewport() {
163
+ if (typeof window === "undefined" || typeof window.matchMedia !== "function") return false;
164
+ return window.matchMedia(`(max-width: ${MOBILE_MAX_WIDTH_PX}px)`).matches;
165
+ }
147
166
  const CopilotChatConfiguration = (0, react.createContext)(null);
148
167
  const CopilotChatConfigurationProvider = ({ children, labels, agentId, threadId, hasExplicitThreadId, isModalDefaultOpen }) => {
149
168
  const parentConfig = (0, react.useContext)(CopilotChatConfiguration);
@@ -154,12 +173,22 @@ const CopilotChatConfigurationProvider = ({ children, labels, agentId, threadId,
154
173
  ...stableLabels
155
174
  }), [stableLabels, parentConfig?.labels]);
156
175
  const resolvedAgentId = agentId ?? parentConfig?.agentId ?? _copilotkit_shared.DEFAULT_AGENT_ID;
176
+ const threadIdPropIsAuthoritative = threadId !== void 0 && hasExplicitThreadId !== false;
177
+ const isThreadIdControlled = threadIdPropIsAuthoritative;
178
+ const [activeThreadOverride, setActiveThreadOverride] = (0, react.useState)(null);
157
179
  const resolvedThreadId = (0, react.useMemo)(() => {
158
- if (threadId) return threadId;
180
+ if (threadIdPropIsAuthoritative) return threadId;
181
+ if (activeThreadOverride) return activeThreadOverride.threadId;
159
182
  if (parentConfig?.threadId) return parentConfig.threadId;
183
+ if (threadId) return threadId;
160
184
  return (0, _copilotkit_shared.randomUUID)();
161
- }, [threadId, parentConfig?.threadId]);
162
- const resolvedHasExplicitThreadId = (hasExplicitThreadId !== void 0 ? hasExplicitThreadId : !!threadId) || !!parentConfig?.hasExplicitThreadId;
185
+ }, [
186
+ threadIdPropIsAuthoritative,
187
+ threadId,
188
+ parentConfig?.threadId,
189
+ activeThreadOverride
190
+ ]);
191
+ const resolvedHasExplicitThreadId = (threadIdPropIsAuthoritative ? true : activeThreadOverride?.explicit ?? hasExplicitThreadId ?? false) || !!parentConfig?.hasExplicitThreadId;
163
192
  const [internalModalOpen, setInternalModalOpen] = (0, react.useState)(isModalDefaultOpen ?? true);
164
193
  const hasExplicitDefault = isModalDefaultOpen !== void 0;
165
194
  const setAndSync = (0, react.useCallback)((open) => {
@@ -178,20 +207,113 @@ const CopilotChatConfigurationProvider = ({ children, labels, agentId, threadId,
178
207
  }, [parentConfig?.isModalOpen, hasExplicitDefault]);
179
208
  const resolvedIsModalOpen = hasExplicitDefault ? internalModalOpen : parentConfig?.isModalOpen ?? internalModalOpen;
180
209
  const resolvedSetModalOpen = hasExplicitDefault ? setAndSync : parentConfig?.setModalOpen ?? setInternalModalOpen;
210
+ const [ownDrawerOpen, setOwnDrawerOpen] = (0, react.useState)(false);
211
+ const [ownDrawerCount, setOwnDrawerCount] = (0, react.useState)(0);
212
+ const modalCloseRef = (0, react.useRef)(() => {});
213
+ modalCloseRef.current = resolvedSetModalOpen;
214
+ const registeredModalClosersRef = (0, react.useRef)([]);
215
+ const ownRegisterModalCloser = (0, react.useCallback)((closeModal) => {
216
+ registeredModalClosersRef.current.push(closeModal);
217
+ return () => {
218
+ registeredModalClosersRef.current = registeredModalClosersRef.current.filter((entry) => entry !== closeModal);
219
+ };
220
+ }, []);
221
+ const ownSetDrawerOpen = (0, react.useCallback)((open) => {
222
+ setOwnDrawerOpen(open);
223
+ if (open && isMobileViewport()) {
224
+ const registered = registeredModalClosersRef.current;
225
+ (registered.length > 0 ? registered[registered.length - 1] : modalCloseRef.current)(false);
226
+ }
227
+ }, []);
228
+ const ownRegisterDrawer = (0, react.useCallback)(() => {
229
+ setOwnDrawerCount((count) => count + 1);
230
+ return () => {
231
+ setOwnDrawerCount((count) => Math.max(0, count - 1));
232
+ };
233
+ }, []);
234
+ const resolvedDrawerOpen = parentConfig ? parentConfig.drawerOpen : ownDrawerOpen;
235
+ const resolvedSetDrawerOpen = parentConfig ? parentConfig.setDrawerOpen : ownSetDrawerOpen;
236
+ const resolvedDrawerRegistered = parentConfig ? parentConfig.drawerRegistered : ownDrawerCount > 0;
237
+ const resolvedRegisterDrawer = parentConfig ? parentConfig.registerDrawer : ownRegisterDrawer;
238
+ const resolvedRegisterModalCloser = parentConfig ? parentConfig.ɵregisterModalCloser : ownRegisterModalCloser;
239
+ (0, react.useEffect)(() => {
240
+ if (!hasExplicitDefault) return;
241
+ return resolvedRegisterModalCloser(resolvedSetModalOpen);
242
+ }, [
243
+ hasExplicitDefault,
244
+ resolvedRegisterModalCloser,
245
+ resolvedSetModalOpen
246
+ ]);
247
+ const isThreadIdControlledRef = (0, react.useRef)(isThreadIdControlled);
248
+ isThreadIdControlledRef.current = isThreadIdControlled;
249
+ const ownSetActiveThreadId = (0, react.useCallback)((id, options) => {
250
+ setActiveThreadOverride({
251
+ threadId: id,
252
+ explicit: options?.explicit ?? true
253
+ });
254
+ }, []);
255
+ const ownStartNewThread = (0, react.useCallback)(() => {
256
+ setActiveThreadOverride({
257
+ threadId: (0, _copilotkit_shared.randomUUID)(),
258
+ explicit: false
259
+ });
260
+ }, []);
261
+ const parentSetActiveThreadId = parentConfig?.setActiveThreadId;
262
+ const parentStartNewThread = parentConfig?.startNewThread;
263
+ const resolvedSetActiveThreadId = (0, react.useCallback)((id, options) => {
264
+ if (isThreadIdControlledRef.current) {
265
+ console.warn("[CopilotKit] Ignoring setActiveThreadId(): threadId is controlled via the `threadId` prop on CopilotChatConfigurationProvider.");
266
+ return;
267
+ }
268
+ if (parentSetActiveThreadId) {
269
+ parentSetActiveThreadId(id, options);
270
+ return;
271
+ }
272
+ ownSetActiveThreadId(id, options);
273
+ }, [parentSetActiveThreadId, ownSetActiveThreadId]);
274
+ const resolvedStartNewThread = (0, react.useCallback)(() => {
275
+ if (isThreadIdControlledRef.current) {
276
+ console.warn("[CopilotKit] Ignoring startNewThread(): threadId is controlled via the `threadId` prop on CopilotChatConfigurationProvider.");
277
+ return;
278
+ }
279
+ if (parentStartNewThread) {
280
+ parentStartNewThread();
281
+ return;
282
+ }
283
+ ownStartNewThread();
284
+ }, [parentStartNewThread, ownStartNewThread]);
285
+ const setModalOpenWithDrawerExclusion = (0, react.useCallback)((open) => {
286
+ if (open && isMobileViewport()) resolvedSetDrawerOpen(false);
287
+ resolvedSetModalOpen(open);
288
+ }, [resolvedSetModalOpen, resolvedSetDrawerOpen]);
181
289
  const configurationValue = (0, react.useMemo)(() => ({
182
290
  labels: mergedLabels,
183
291
  agentId: resolvedAgentId,
184
292
  threadId: resolvedThreadId,
185
293
  hasExplicitThreadId: resolvedHasExplicitThreadId,
186
294
  isModalOpen: resolvedIsModalOpen,
187
- setModalOpen: resolvedSetModalOpen
295
+ setModalOpen: setModalOpenWithDrawerExclusion,
296
+ drawerOpen: resolvedDrawerOpen,
297
+ setDrawerOpen: resolvedSetDrawerOpen,
298
+ drawerRegistered: resolvedDrawerRegistered,
299
+ registerDrawer: resolvedRegisterDrawer,
300
+ ɵregisterModalCloser: resolvedRegisterModalCloser,
301
+ setActiveThreadId: resolvedSetActiveThreadId,
302
+ startNewThread: resolvedStartNewThread
188
303
  }), [
189
304
  mergedLabels,
190
305
  resolvedAgentId,
191
306
  resolvedThreadId,
192
307
  resolvedHasExplicitThreadId,
193
308
  resolvedIsModalOpen,
194
- resolvedSetModalOpen
309
+ setModalOpenWithDrawerExclusion,
310
+ resolvedDrawerOpen,
311
+ resolvedSetDrawerOpen,
312
+ resolvedDrawerRegistered,
313
+ resolvedRegisterDrawer,
314
+ resolvedRegisterModalCloser,
315
+ resolvedSetActiveThreadId,
316
+ resolvedStartNewThread
195
317
  ]);
196
318
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopilotChatConfiguration.Provider, {
197
319
  value: configurationValue,
@@ -1021,7 +1143,7 @@ function useThreadStoreSelector(store, selector) {
1021
1143
  return (0, react.useSyncExternalStore)((0, react.useCallback)((onStoreChange) => {
1022
1144
  const subscription = store.select(selector).subscribe(onStoreChange);
1023
1145
  return () => subscription.unsubscribe();
1024
- }, [store, selector]), () => selector(store.getState()));
1146
+ }, [store, selector]), () => selector(store.getState()), () => selector(store.getServerState()));
1025
1147
  }
1026
1148
  /**
1027
1149
  * React hook for listing and managing Intelligence platform threads.
@@ -1064,7 +1186,7 @@ function useThreadStoreSelector(store, selector) {
1064
1186
  * }
1065
1187
  * ```
1066
1188
  */
1067
- function useThreads({ agentId, includeArchived, limit }) {
1189
+ function useThreads({ agentId, includeArchived, limit, enabled = true }) {
1068
1190
  const { copilotkit } = (0, _copilotkit_react_core_v2_context.useCopilotKit)();
1069
1191
  const [store] = (0, react.useState)(() => (0, _copilotkit_core.ɵcreateThreadStore)({ fetch: globalThis.fetch }));
1070
1192
  const coreThreads = useThreadStoreSelector(store, _copilotkit_core.ɵselectThreads);
@@ -1081,6 +1203,7 @@ function useThreads({ agentId, includeArchived, limit }) {
1081
1203
  const storeError = useThreadStoreSelector(store, _copilotkit_core.ɵselectThreadsError);
1082
1204
  const hasMoreThreads = useThreadStoreSelector(store, _copilotkit_core.ɵselectHasNextPage);
1083
1205
  const isFetchingMoreThreads = useThreadStoreSelector(store, _copilotkit_core.ɵselectIsFetchingNextPage);
1206
+ const isMutating = useThreadStoreSelector(store, _copilotkit_core.ɵselectIsMutating);
1084
1207
  const headersKey = (0, react.useMemo)(() => {
1085
1208
  return JSON.stringify(Object.entries(copilotkit.headers ?? {}).sort(([left], [right]) => left.localeCompare(right)));
1086
1209
  }, [copilotkit.headers]);
@@ -1101,9 +1224,16 @@ function useThreads({ agentId, includeArchived, limit }) {
1101
1224
  return /* @__PURE__ */ new Error("Thread mutations are not available on this CopilotKit runtime");
1102
1225
  }, [threadMutationsSupported]);
1103
1226
  const [hasDispatchedContext, setHasDispatchedContext] = (0, react.useState)(false);
1104
- const preConnectLoading = !!copilotkit.runtimeUrl && !threadEndpointsUnavailable && !hasDispatchedContext;
1105
- const isLoading = runtimeError || threadEndpointsError ? false : preConnectLoading || storeIsLoading;
1106
- const error = runtimeError ?? threadEndpointsError ?? storeError;
1227
+ const preConnectLoading = enabled && !!copilotkit.runtimeUrl && !threadEndpointsUnavailable && !hasDispatchedContext;
1228
+ const [configErrorDismissed, setConfigErrorDismissed] = (0, react.useState)(false);
1229
+ (0, react.useEffect)(() => {
1230
+ setConfigErrorDismissed(false);
1231
+ }, [runtimeError, threadEndpointsError]);
1232
+ const activeRuntimeError = configErrorDismissed ? null : runtimeError;
1233
+ const activeThreadEndpointsError = configErrorDismissed ? null : threadEndpointsError;
1234
+ const isLoading = activeRuntimeError || activeThreadEndpointsError ? false : preConnectLoading || storeIsLoading;
1235
+ const error = activeRuntimeError ?? activeThreadEndpointsError ?? storeError;
1236
+ const listError = storeError;
1107
1237
  (0, react.useEffect)(() => {
1108
1238
  store.start();
1109
1239
  return () => {
@@ -1111,6 +1241,7 @@ function useThreads({ agentId, includeArchived, limit }) {
1111
1241
  };
1112
1242
  }, [store]);
1113
1243
  (0, react.useEffect)(() => {
1244
+ if (!enabled) return;
1114
1245
  copilotkit.registerThreadStore(agentId, store);
1115
1246
  return () => {
1116
1247
  copilotkit.unregisterThreadStore(agentId);
@@ -1118,9 +1249,15 @@ function useThreads({ agentId, includeArchived, limit }) {
1118
1249
  }, [
1119
1250
  copilotkit,
1120
1251
  agentId,
1121
- store
1252
+ store,
1253
+ enabled
1122
1254
  ]);
1123
1255
  (0, react.useEffect)(() => {
1256
+ if (!enabled) {
1257
+ store.setContext(null);
1258
+ setHasDispatchedContext(false);
1259
+ return;
1260
+ }
1124
1261
  if (!copilotkit.runtimeUrl) {
1125
1262
  store.setContext(null);
1126
1263
  setHasDispatchedContext(false);
@@ -1144,6 +1281,7 @@ function useThreads({ agentId, includeArchived, limit }) {
1144
1281
  setHasDispatchedContext(true);
1145
1282
  }, [
1146
1283
  store,
1284
+ enabled,
1147
1285
  copilotkit.runtimeUrl,
1148
1286
  runtimeStatus,
1149
1287
  headersKey,
@@ -1167,9 +1305,16 @@ function useThreads({ agentId, includeArchived, limit }) {
1167
1305
  threads,
1168
1306
  isLoading,
1169
1307
  error,
1308
+ listError,
1170
1309
  hasMoreThreads,
1171
1310
  isFetchingMoreThreads,
1311
+ isMutating,
1172
1312
  fetchMoreThreads: (0, react.useCallback)(() => store.fetchNextPage(), [store]),
1313
+ refetchThreads: (0, react.useCallback)(() => store.refetchThreads(), [store]),
1314
+ startNewThread: (0, react.useCallback)(() => {
1315
+ setConfigErrorDismissed(true);
1316
+ store.startNewThread();
1317
+ }, [store]),
1173
1318
  renameThread,
1174
1319
  archiveThread,
1175
1320
  unarchiveThread,