@copilotkit/react-core 1.56.0 → 1.56.2-canary.pin-to-send

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 (60) hide show
  1. package/dist/{copilotkit-BebqQrYT.mjs → copilotkit-BBYbekCa.mjs} +265 -76
  2. package/dist/copilotkit-BBYbekCa.mjs.map +1 -0
  3. package/dist/{copilotkit-Cvb6WpAX.cjs → copilotkit-D5JT2Pu3.cjs} +264 -75
  4. package/dist/copilotkit-D5JT2Pu3.cjs.map +1 -0
  5. package/dist/{copilotkit-f2Uq0RwG.d.mts → copilotkit-DArT2Iuw.d.mts} +71 -18
  6. package/dist/copilotkit-DArT2Iuw.d.mts.map +1 -0
  7. package/dist/{copilotkit-Dv8zU8_U.d.cts → copilotkit-KEc28l8G.d.cts} +71 -18
  8. package/dist/copilotkit-KEc28l8G.d.cts.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 +30 -46
  14. package/dist/index.umd.js.map +1 -1
  15. package/dist/v2/index.cjs +1 -1
  16. package/dist/v2/index.css +1 -1
  17. package/dist/v2/index.d.cts +2 -2
  18. package/dist/v2/index.d.mts +2 -2
  19. package/dist/v2/index.mjs +1 -1
  20. package/dist/v2/index.umd.js +264 -79
  21. package/dist/v2/index.umd.js.map +1 -1
  22. package/package.json +6 -6
  23. package/src/components/CopilotListeners.tsx +15 -4
  24. package/src/components/__tests__/CopilotListeners.test.tsx +38 -0
  25. package/src/v2/components/chat/CopilotChat.tsx +80 -4
  26. package/src/v2/components/chat/CopilotChatAssistantMessage.tsx +4 -4
  27. package/src/v2/components/chat/CopilotChatInput.tsx +43 -2
  28. package/src/v2/components/chat/CopilotChatView.tsx +206 -11
  29. package/src/v2/components/chat/__tests__/CopilotChat.absentThreadConnect.test.tsx +66 -0
  30. package/src/v2/components/chat/__tests__/CopilotChatActivityRendering.e2e.test.tsx +300 -2
  31. package/src/v2/components/chat/__tests__/CopilotChatAssistantMessage.thumbs.test.tsx +72 -0
  32. package/src/v2/components/chat/__tests__/CopilotChatInput.test.tsx +38 -0
  33. package/src/v2/components/chat/__tests__/CopilotChatView.connectingGate.test.tsx +56 -0
  34. package/src/v2/components/chat/__tests__/CopilotChatView.pinToSend.test.tsx +94 -0
  35. package/src/v2/components/chat/__tests__/copilot-chat-throttle.test.tsx +0 -1
  36. package/src/v2/components/chat/__tests__/normalize-auto-scroll.test.ts +37 -0
  37. package/src/v2/components/chat/index.ts +2 -0
  38. package/src/v2/components/chat/last-user-message-context.ts +21 -0
  39. package/src/v2/components/chat/normalize-auto-scroll.ts +17 -0
  40. package/src/v2/components/license-warning-banner.tsx +20 -1
  41. package/src/v2/components/ui/button.tsx +12 -11
  42. package/src/v2/hooks/__tests__/use-agent-stability.test.tsx +6 -0
  43. package/src/v2/hooks/__tests__/use-agent-thread-isolation.test.tsx +6 -0
  44. package/src/v2/hooks/__tests__/use-agent-throttle.test.tsx +76 -50
  45. package/src/v2/hooks/__tests__/use-pin-to-send.test.tsx +219 -0
  46. package/src/v2/hooks/__tests__/use-render-custom-messages.test.tsx +55 -0
  47. package/src/v2/hooks/__tests__/use-threads.test.tsx +68 -0
  48. package/src/v2/hooks/use-agent.tsx +34 -77
  49. package/src/v2/hooks/use-pin-to-send.ts +94 -0
  50. package/src/v2/hooks/use-render-custom-messages.tsx +1 -1
  51. package/src/v2/hooks/use-render-tool-call.tsx +3 -0
  52. package/src/v2/hooks/use-render-tool.tsx +3 -0
  53. package/src/v2/hooks/use-threads.tsx +55 -12
  54. package/src/v2/providers/CopilotKitProvider.tsx +2 -11
  55. package/src/v2/types/defineToolCallRenderer.ts +3 -0
  56. package/src/v2/types/react-tool-call-renderer.ts +3 -0
  57. package/dist/copilotkit-BebqQrYT.mjs.map +0 -1
  58. package/dist/copilotkit-Cvb6WpAX.cjs.map +0 -1
  59. package/dist/copilotkit-Dv8zU8_U.d.cts.map +0 -1
  60. package/dist/copilotkit-f2Uq0RwG.d.mts.map +0 -1
@@ -286,8 +286,9 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
286
286
  size: "default"
287
287
  }
288
288
  });
289
- function Button({ className, variant, size, asChild = false, ...props }) {
289
+ const Button = react.forwardRef(function Button({ className, variant, size, asChild = false, ...props }, ref) {
290
290
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(asChild ? _radix_ui_react_slot.Slot : "button", {
291
+ ref,
291
292
  "data-slot": "button",
292
293
  className: cn(buttonVariants({
293
294
  variant,
@@ -296,7 +297,7 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
296
297
  })),
297
298
  ...props
298
299
  });
299
- }
300
+ });
300
301
 
301
302
  //#endregion
302
303
  //#region src/v2/components/ui/tooltip.tsx
@@ -598,7 +599,7 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
598
599
  //#region src/v2/components/chat/CopilotChatInput.tsx
599
600
  const SLASH_MENU_MAX_VISIBLE_ITEMS = 5;
600
601
  const SLASH_MENU_ITEM_HEIGHT_PX = 40;
601
- function CopilotChatInput({ mode = "input", onSubmitMessage, onStop, isRunning = false, onStartTranscribe, onCancelTranscribe, onFinishTranscribe, onFinishTranscribeWithAudio, onAddFile, onChange, value, toolsMenu, autoFocus = false, positioning = "static", keyboardHeight = 0, containerRef, showDisclaimer, textArea, sendButton, startTranscribeButton, cancelTranscribeButton, finishTranscribeButton, addMenuButton, audioRecorder, disclaimer, children, className, ...props }) {
602
+ function CopilotChatInput({ mode = "input", onSubmitMessage, onStop, isRunning = false, onStartTranscribe, onCancelTranscribe, onFinishTranscribe, onFinishTranscribeWithAudio, onAddFile, onChange, value, toolsMenu, autoFocus = false, positioning = "static", keyboardHeight = 0, containerRef, showDisclaimer, bottomAnchored = false, textArea, sendButton, startTranscribeButton, cancelTranscribeButton, finishTranscribeButton, addMenuButton, audioRecorder, disclaimer, children, className, ...props }) {
602
603
  var _config$labels;
603
604
  const isControlled = value !== void 0;
604
605
  const [internalValue, setInternalValue] = (0, react.useState)(() => value !== null && value !== void 0 ? value : "");
@@ -747,6 +748,7 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
747
748
  });
748
749
  }, [clearInputValue]);
749
750
  const handleKeyDown = (e) => {
751
+ if (e.nativeEvent.isComposing || e.keyCode === 229) return;
750
752
  if (commandQuery !== null && mode === "input") {
751
753
  if (e.key === "ArrowDown") {
752
754
  if (filteredCommands.length > 0) {
@@ -794,10 +796,8 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
794
796
  const trimmed = resolvedValue.trim();
795
797
  if (!trimmed) return;
796
798
  onSubmitMessage(trimmed);
797
- if (!isControlled) {
798
- setInternalValue("");
799
- onChange === null || onChange === void 0 || onChange("");
800
- }
799
+ if (!isControlled) setInternalValue("");
800
+ onChange === null || onChange === void 0 || onChange("");
801
801
  if (inputRef.current) inputRef.current.focus();
802
802
  };
803
803
  const BoundTextArea = renderSlot(textArea, CopilotChatInput.TextArea, {
@@ -805,6 +805,12 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
805
805
  value: resolvedValue,
806
806
  onChange: handleChange,
807
807
  onKeyDown: handleKeyDown,
808
+ onCompositionStart: () => {
809
+ isComposingRef.current = true;
810
+ },
811
+ onCompositionEnd: () => {
812
+ isComposingRef.current = false;
813
+ },
808
814
  autoFocus,
809
815
  className: (0, tailwind_merge.twMerge)("cpk:w-full cpk:py-3", isExpanded ? "cpk:px-5" : "cpk:pr-5")
810
816
  });
@@ -879,9 +885,10 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
879
885
  const target = e.target;
880
886
  if (target.tagName !== "BUTTON" && !target.closest("button") && inputRef.current && mode === "input") inputRef.current.focus();
881
887
  };
888
+ const isComposingRef = (0, react.useRef)(false);
882
889
  const ensureMeasurements = (0, react.useCallback)(() => {
883
890
  const textarea = inputRef.current;
884
- if (!textarea) return;
891
+ if (!textarea || isComposingRef.current) return;
885
892
  const previousValue = textarea.value;
886
893
  const previousHeight = textarea.style.height;
887
894
  textarea.style.height = "auto";
@@ -1127,7 +1134,8 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
1127
1134
  className: cn("cpk:pointer-events-none cpk:relative cpk:z-20", positioning === "absolute" && "cpk:absolute cpk:bottom-0 cpk:left-0 cpk:right-0", className),
1128
1135
  style: {
1129
1136
  transform: keyboardHeight > 0 ? `translateY(-${keyboardHeight}px)` : void 0,
1130
- transition: "transform 0.2s ease-out"
1137
+ transition: "transform 0.2s ease-out",
1138
+ ...positioning === "absolute" || bottomAnchored ? { paddingBottom: "var(--copilotkit-license-banner-offset, 0px)" } : {}
1131
1139
  },
1132
1140
  ...props,
1133
1141
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
@@ -1354,6 +1362,8 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
1354
1362
 
1355
1363
  //#endregion
1356
1364
  //#region src/v2/components/license-warning-banner.tsx
1365
+ const LICENSE_BANNER_OFFSET_PX = 52;
1366
+ const LICENSE_BANNER_OFFSET_VAR = "--copilotkit-license-banner-offset";
1357
1367
  const BANNER_STYLES = {
1358
1368
  base: {
1359
1369
  position: "fixed",
@@ -1395,6 +1405,14 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
1395
1405
  }
1396
1406
  }
1397
1407
  function BannerShell({ severity, message, actionLabel, actionUrl, onDismiss }) {
1408
+ (0, react.useEffect)(() => {
1409
+ if (typeof document === "undefined") return;
1410
+ const root = document.documentElement;
1411
+ root.style.setProperty(LICENSE_BANNER_OFFSET_VAR, `${LICENSE_BANNER_OFFSET_PX}px`);
1412
+ return () => {
1413
+ root.style.removeProperty(LICENSE_BANNER_OFFSET_VAR);
1414
+ };
1415
+ }, []);
1398
1416
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1399
1417
  style: {
1400
1418
  ...BANNER_STYLES.base,
@@ -3379,7 +3397,6 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
3379
3397
  didMountRef.current = true;
3380
3398
  }, []);
3381
3399
  (0, react.useEffect)(() => {
3382
- if (defaultThrottleMs !== void 0 && (!Number.isFinite(defaultThrottleMs) || defaultThrottleMs < 0)) console.error(`CopilotKitProvider: defaultThrottleMs must be a non-negative finite number, got ${defaultThrottleMs}. useAgent hooks without an explicit throttleMs will fall back to unthrottled.`);
3383
3400
  copilotkit.setDefaultThrottleMs(defaultThrottleMs);
3384
3401
  }, [copilotkit, defaultThrottleMs]);
3385
3402
  const designSkill = (_openGenerativeUI$des = openGenerativeUI === null || openGenerativeUI === void 0 ? void 0 : openGenerativeUI.designSkill) !== null && _openGenerativeUI$des !== void 0 ? _openGenerativeUI$des : DEFAULT_DESIGN_SKILL;
@@ -3477,18 +3494,21 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
3477
3494
  const toolName = toolCall.function.name;
3478
3495
  if (toolMessage) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RenderComponent, {
3479
3496
  name: toolName,
3497
+ toolCallId: toolCall.id,
3480
3498
  args,
3481
3499
  status: _copilotkit_core.ToolCallStatus.Complete,
3482
3500
  result: toolMessage.content
3483
3501
  });
3484
3502
  else if (isExecuting) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RenderComponent, {
3485
3503
  name: toolName,
3504
+ toolCallId: toolCall.id,
3486
3505
  args,
3487
3506
  status: _copilotkit_core.ToolCallStatus.Executing,
3488
3507
  result: void 0
3489
3508
  });
3490
3509
  else return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RenderComponent, {
3491
3510
  name: toolName,
3511
+ toolCallId: toolCall.id,
3492
3512
  args,
3493
3513
  status: _copilotkit_core.ToolCallStatus.InProgress,
3494
3514
  result: void 0
@@ -3598,16 +3618,6 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
3598
3618
  const providerThrottleMs = copilotkit.defaultThrottleMs;
3599
3619
  const chatConfig = useCopilotChatConfiguration();
3600
3620
  (_threadId = threadId) !== null && _threadId !== void 0 || (threadId = chatConfig === null || chatConfig === void 0 ? void 0 : chatConfig.threadId);
3601
- const effectiveThrottleMs = (0, react.useMemo)(() => {
3602
- var _ref;
3603
- const resolved = (_ref = throttleMs !== null && throttleMs !== void 0 ? throttleMs : providerThrottleMs) !== null && _ref !== void 0 ? _ref : 0;
3604
- if (!Number.isFinite(resolved) || resolved < 0) {
3605
- const source = throttleMs !== void 0 ? "hook-level throttleMs" : "provider-level defaultThrottleMs";
3606
- console.error(`useAgent: ${source} must be a non-negative finite number, got ${resolved}. Falling back to unthrottled.`);
3607
- return 0;
3608
- }
3609
- return resolved;
3610
- }, [throttleMs, providerThrottleMs]);
3611
3621
  const [, forceUpdate] = (0, react.useReducer)((x) => x + 1, 0);
3612
3622
  const updateFlags = (0, react.useMemo)(() => updates !== null && updates !== void 0 ? updates : ALL_UPDATES, [JSON.stringify(updates)]);
3613
3623
  const provisionalAgentCache = (0, react.useRef)(/* @__PURE__ */ new Map());
@@ -3671,9 +3681,8 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
3671
3681
  ]);
3672
3682
  (0, react.useEffect)(() => {
3673
3683
  if (updateFlags.length === 0) return;
3674
- const handlers = {};
3675
- let timerId = null;
3676
3684
  let active = true;
3685
+ const handlers = {};
3677
3686
  let batchScheduled = false;
3678
3687
  const batchedForceUpdate = () => {
3679
3688
  if (!active) return;
@@ -3685,46 +3694,24 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
3685
3694
  });
3686
3695
  }
3687
3696
  };
3688
- if (updateFlags.includes(UseAgentUpdate.OnMessagesChanged)) {
3689
- const ms = effectiveThrottleMs;
3690
- if (ms > 0) {
3691
- let throttleActive = false;
3692
- let pending = false;
3693
- const throttledNotify = () => {
3694
- if (!active) return;
3695
- if (!throttleActive) {
3696
- throttleActive = true;
3697
- pending = false;
3698
- forceUpdate();
3699
- timerId = setTimeout(function trailingEdge() {
3700
- timerId = null;
3701
- if (active && pending) {
3702
- pending = false;
3703
- forceUpdate();
3704
- timerId = setTimeout(trailingEdge, ms);
3705
- } else throttleActive = false;
3706
- }, ms);
3707
- } else pending = true;
3708
- };
3709
- handlers.onMessagesChanged = throttledNotify;
3710
- } else handlers.onMessagesChanged = forceUpdate;
3711
- }
3697
+ if (updateFlags.includes(UseAgentUpdate.OnMessagesChanged)) handlers.onMessagesChanged = forceUpdate;
3712
3698
  if (updateFlags.includes(UseAgentUpdate.OnStateChanged)) handlers.onStateChanged = batchedForceUpdate;
3713
3699
  if (updateFlags.includes(UseAgentUpdate.OnRunStatusChanged)) {
3714
3700
  handlers.onRunInitialized = batchedForceUpdate;
3715
3701
  handlers.onRunFinalized = batchedForceUpdate;
3716
3702
  handlers.onRunFailed = batchedForceUpdate;
3703
+ handlers.onRunErrorEvent = batchedForceUpdate;
3717
3704
  }
3718
- const subscription = agent.subscribe(handlers);
3705
+ const subscription = copilotkit.subscribeToAgentWithOptions(agent, handlers, { throttleMs });
3719
3706
  return () => {
3720
3707
  active = false;
3721
- if (timerId !== null) clearTimeout(timerId);
3722
3708
  subscription.unsubscribe();
3723
3709
  };
3724
3710
  }, [
3725
3711
  agent,
3726
3712
  forceUpdate,
3727
- effectiveThrottleMs,
3713
+ throttleMs,
3714
+ providerThrottleMs,
3728
3715
  updateFlags
3729
3716
  ]);
3730
3717
  (0, react.useEffect)(() => {
@@ -3753,7 +3740,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
3753
3740
  const runId = resolvedRunId !== null && resolvedRunId !== void 0 ? resolvedRunId : `missing-run-id:${message.id}`;
3754
3741
  const registryAgent = copilotkit.getAgent(agentId);
3755
3742
  const agent = (_getThreadClone = getThreadClone(registryAgent, threadId)) !== null && _getThreadClone !== void 0 ? _getThreadClone : registryAgent;
3756
- if (!agent) throw new Error("Agent not found");
3743
+ if (!agent) return null;
3757
3744
  const messagesIdsInRun = resolvedRunId ? agent.messages.filter((msg) => copilotkit.getRunIdForMessage(agentId, threadId, msg.id) === resolvedRunId).map((msg) => msg.id) : [message.id];
3758
3745
  const rawMessageIndex = agent.messages.findIndex((msg) => msg.id === message.id);
3759
3746
  const messageIndex = rawMessageIndex >= 0 ? rawMessageIndex : 0;
@@ -4695,13 +4682,14 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4695
4682
  const { copilotkit } = useCopilotKit();
4696
4683
  const [store] = (0, react.useState)(() => (0, _copilotkit_core.ɵcreateThreadStore)({ fetch: globalThis.fetch }));
4697
4684
  const coreThreads = useThreadStoreSelector(store, _copilotkit_core.ɵselectThreads);
4698
- const threads = (0, react.useMemo)(() => coreThreads.map(({ id, agentId, name, archived, createdAt, updatedAt }) => ({
4685
+ const threads = (0, react.useMemo)(() => coreThreads.map(({ id, agentId, name, archived, createdAt, updatedAt, lastRunAt }) => ({
4699
4686
  id,
4700
4687
  agentId,
4701
4688
  name,
4702
4689
  archived,
4703
4690
  createdAt,
4704
- updatedAt
4691
+ updatedAt,
4692
+ ...lastRunAt !== void 0 ? { lastRunAt } : {}
4705
4693
  })), [coreThreads]);
4706
4694
  const storeIsLoading = useThreadStoreSelector(store, _copilotkit_core.ɵselectThreadsIsLoading);
4707
4695
  const storeError = useThreadStoreSelector(store, _copilotkit_core.ɵselectThreadsError);
@@ -4715,7 +4703,9 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4715
4703
  if (copilotkit.runtimeUrl) return null;
4716
4704
  return /* @__PURE__ */ new Error("Runtime URL is not configured");
4717
4705
  }, [copilotkit.runtimeUrl]);
4718
- const isLoading = runtimeError ? false : storeIsLoading;
4706
+ const [hasDispatchedContext, setHasDispatchedContext] = (0, react.useState)(false);
4707
+ const preConnectLoading = !!copilotkit.runtimeUrl && !hasDispatchedContext;
4708
+ const isLoading = runtimeError ? false : preConnectLoading || storeIsLoading;
4719
4709
  const error = runtimeError !== null && runtimeError !== void 0 ? runtimeError : storeError;
4720
4710
  (0, react.useEffect)(() => {
4721
4711
  store.start();
@@ -4723,20 +4713,28 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4723
4713
  store.stop();
4724
4714
  };
4725
4715
  }, [store]);
4716
+ const runtimeStatus = copilotkit.runtimeConnectionStatus;
4726
4717
  (0, react.useEffect)(() => {
4727
4718
  var _copilotkit$intellige;
4728
- const context = copilotkit.runtimeUrl ? {
4719
+ if (!copilotkit.runtimeUrl) {
4720
+ store.setContext(null);
4721
+ return;
4722
+ }
4723
+ if (runtimeStatus !== _copilotkit_core.CopilotKitCoreRuntimeConnectionStatus.Connected) return;
4724
+ const context = {
4729
4725
  runtimeUrl: copilotkit.runtimeUrl,
4730
4726
  headers: { ...copilotkit.headers },
4731
4727
  wsUrl: (_copilotkit$intellige = copilotkit.intelligence) === null || _copilotkit$intellige === void 0 ? void 0 : _copilotkit$intellige.wsUrl,
4732
4728
  agentId,
4733
4729
  includeArchived,
4734
4730
  limit
4735
- } : null;
4731
+ };
4736
4732
  store.setContext(context);
4733
+ setHasDispatchedContext(true);
4737
4734
  }, [
4738
4735
  store,
4739
4736
  copilotkit.runtimeUrl,
4737
+ runtimeStatus,
4740
4738
  headersKey,
4741
4739
  (_copilotkit$intellige2 = copilotkit.intelligence) === null || _copilotkit$intellige2 === void 0 ? void 0 : _copilotkit$intellige2.wsUrl,
4742
4740
  agentId,
@@ -4953,10 +4951,10 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4953
4951
  if (message.content) return await (0, _copilotkit_shared.copyToClipboard)(message.content);
4954
4952
  return false;
4955
4953
  } });
4956
- const boundThumbsUpButton = renderSlot(thumbsUpButton, CopilotChatAssistantMessage.ThumbsUpButton, { onClick: onThumbsUp });
4957
- const boundThumbsDownButton = renderSlot(thumbsDownButton, CopilotChatAssistantMessage.ThumbsDownButton, { onClick: onThumbsDown });
4958
- const boundReadAloudButton = renderSlot(readAloudButton, CopilotChatAssistantMessage.ReadAloudButton, { onClick: onReadAloud });
4959
- const boundRegenerateButton = renderSlot(regenerateButton, CopilotChatAssistantMessage.RegenerateButton, { onClick: onRegenerate });
4954
+ const boundThumbsUpButton = renderSlot(thumbsUpButton, CopilotChatAssistantMessage.ThumbsUpButton, { onClick: onThumbsUp ? () => onThumbsUp(message) : void 0 });
4955
+ const boundThumbsDownButton = renderSlot(thumbsDownButton, CopilotChatAssistantMessage.ThumbsDownButton, { onClick: onThumbsDown ? () => onThumbsDown(message) : void 0 });
4956
+ const boundReadAloudButton = renderSlot(readAloudButton, CopilotChatAssistantMessage.ReadAloudButton, { onClick: onReadAloud ? () => onReadAloud(message) : void 0 });
4957
+ const boundRegenerateButton = renderSlot(regenerateButton, CopilotChatAssistantMessage.RegenerateButton, { onClick: onRegenerate ? () => onRegenerate(message) : void 0 });
4960
4958
  const boundToolbar = renderSlot(toolbar, CopilotChatAssistantMessage.Toolbar, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4961
4959
  className: "cpk:flex cpk:items-center cpk:gap-1",
4962
4960
  children: [
@@ -6298,9 +6296,97 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
6298
6296
  return keyboardState;
6299
6297
  }
6300
6298
 
6299
+ //#endregion
6300
+ //#region src/v2/components/chat/normalize-auto-scroll.ts
6301
+ const VALID = [
6302
+ "pin-to-bottom",
6303
+ "pin-to-send",
6304
+ "none"
6305
+ ];
6306
+ function normalizeAutoScroll(value) {
6307
+ if (value === void 0) return "pin-to-bottom";
6308
+ if (value === true) return "pin-to-bottom";
6309
+ if (value === false) return "none";
6310
+ if (VALID.includes(value)) return value;
6311
+ return "pin-to-bottom";
6312
+ }
6313
+
6314
+ //#endregion
6315
+ //#region src/v2/components/chat/last-user-message-context.ts
6316
+ const LastUserMessageContext = react.default.createContext({
6317
+ id: null,
6318
+ sendNonce: 0
6319
+ });
6320
+
6321
+ //#endregion
6322
+ //#region src/v2/hooks/use-pin-to-send.ts
6323
+ function usePinToSend({ scrollRef, contentRef, spacerRef, topOffset = 16 }) {
6324
+ const { id, sendNonce } = (0, react.useContext)(LastUserMessageContext);
6325
+ const lastNonceRef = (0, react.useRef)(-1);
6326
+ const currentSpacerHeightRef = (0, react.useRef)(0);
6327
+ (0, react.useEffect)(() => {
6328
+ if (sendNonce === lastNonceRef.current) return;
6329
+ lastNonceRef.current = sendNonce;
6330
+ if (!id) return;
6331
+ const scrollEl = scrollRef.current;
6332
+ const contentEl = contentRef.current;
6333
+ const spacerEl = spacerRef.current;
6334
+ if (!scrollEl || !contentEl || !spacerEl) return;
6335
+ const escaped = typeof CSS !== "undefined" && CSS.escape ? CSS.escape(id) : id.replace(/[!"#$%&'()*+,./:;<=>?@[\\\]^`{|}~]/g, "\\$&");
6336
+ const targetEl = contentEl.querySelector(`[data-message-id="${escaped}"]`);
6337
+ if (!targetEl) return;
6338
+ const viewportHeight = scrollEl.clientHeight;
6339
+ const userMessageHeight = targetEl.getBoundingClientRect().height;
6340
+ const paddingTop = parseFloat(getComputedStyle(targetEl).paddingTop) || 0;
6341
+ const bubbleHeight = Math.max(0, userMessageHeight - paddingTop);
6342
+ const spacerHeight = Math.max(0, viewportHeight - bubbleHeight - topOffset);
6343
+ spacerEl.style.height = `${spacerHeight}px`;
6344
+ currentSpacerHeightRef.current = spacerHeight;
6345
+ const raf = requestAnimationFrame(() => {
6346
+ const targetTop = computeOffsetTop(targetEl, scrollEl) + paddingTop - topOffset;
6347
+ scrollEl.scrollTo({
6348
+ top: Math.max(0, targetTop),
6349
+ behavior: "smooth"
6350
+ });
6351
+ });
6352
+ const ro = new ResizeObserver(() => {
6353
+ if (!contentEl || !spacerEl || !scrollEl) return;
6354
+ const consumedBelow = contentEl.getBoundingClientRect().height - computeOffsetTop(targetEl, contentEl) - userMessageHeight;
6355
+ const remaining = Math.max(0, spacerHeight - consumedBelow);
6356
+ if (remaining < currentSpacerHeightRef.current) {
6357
+ spacerEl.style.height = `${remaining}px`;
6358
+ currentSpacerHeightRef.current = remaining;
6359
+ }
6360
+ });
6361
+ ro.observe(contentEl);
6362
+ return () => {
6363
+ cancelAnimationFrame(raf);
6364
+ ro.disconnect();
6365
+ };
6366
+ }, [
6367
+ id,
6368
+ sendNonce,
6369
+ scrollRef,
6370
+ contentRef,
6371
+ spacerRef,
6372
+ topOffset
6373
+ ]);
6374
+ }
6375
+ function computeOffsetTop(el, stopAt) {
6376
+ const elRect = el.getBoundingClientRect();
6377
+ const stopRect = stopAt.getBoundingClientRect();
6378
+ return elRect.top - stopRect.top + stopAt.scrollTop;
6379
+ }
6380
+
6301
6381
  //#endregion
6302
6382
  //#region src/v2/components/chat/CopilotChatView.tsx
6303
6383
  const FEATHER_HEIGHT = 96;
6384
+ const PIN_TO_SEND_FEATHER_HEIGHT = 48;
6385
+ const PinToSendSoftFeather = ({ className, style, ...props }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6386
+ className: cn("cpk:absolute cpk:bottom-0 cpk:left-0 cpk:right-4 cpk:h-12 cpk:pointer-events-none cpk:z-10 cpk:bg-gradient-to-t", "cpk:from-white cpk:to-transparent", "cpk:dark:from-[rgb(33,33,33)]", className),
6387
+ style,
6388
+ ...props
6389
+ });
6304
6390
  function DropOverlay() {
6305
6391
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6306
6392
  className: cn("cpk:absolute cpk:inset-0 cpk:z-50 cpk:pointer-events-none", "cpk:flex cpk:items-center cpk:justify-center", "cpk:bg-primary/5 cpk:backdrop-blur-[2px]", "cpk:border-2 cpk:border-dashed cpk:border-primary/40 cpk:rounded-lg cpk:m-2"),
@@ -6313,7 +6399,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
6313
6399
  })
6314
6400
  });
6315
6401
  }
6316
- function CopilotChatView({ messageView, input, scrollView, suggestionView, welcomeScreen, messages = [], autoScroll = true, isRunning = false, suggestions, suggestionLoadingIndexes, onSelectSuggestion, onSubmitMessage, onStop, inputMode, inputValue, onInputChange, onStartTranscribe, onCancelTranscribe, onFinishTranscribe, onFinishTranscribeWithAudio, attachments, onRemoveAttachment, onAddFile, dragOver, onDragOver, onDragLeave, onDrop, disclaimer, children, className, ...props }) {
6402
+ function CopilotChatView({ messageView, input, scrollView, suggestionView, welcomeScreen, messages = [], autoScroll = true, isRunning = false, suggestions, suggestionLoadingIndexes, onSelectSuggestion, onSubmitMessage, onStop, inputMode, inputValue, onInputChange, onStartTranscribe, onCancelTranscribe, onFinishTranscribe, onFinishTranscribeWithAudio, attachments, onRemoveAttachment, onAddFile, dragOver, onDragOver, onDragLeave, onDrop, isConnecting = false, hasExplicitThreadId = false, disclaimer, children, className, ...props }) {
6317
6403
  const inputContainerRef = (0, react.useRef)(null);
6318
6404
  const [inputContainerHeight, setInputContainerHeight] = (0, react.useState)(0);
6319
6405
  const [isResizing, setIsResizing] = (0, react.useState)(false);
@@ -6365,9 +6451,10 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
6365
6451
  keyboardHeight: isKeyboardOpen ? keyboardHeight : 0,
6366
6452
  containerRef: inputContainerRef,
6367
6453
  showDisclaimer: true,
6454
+ bottomAnchored: true,
6368
6455
  ...disclaimer !== void 0 ? { disclaimer } : {}
6369
6456
  });
6370
- const hasSuggestions = Array.isArray(suggestions) && suggestions.length > 0;
6457
+ const hasSuggestions = !isConnecting && !isRunning && Array.isArray(suggestions) && suggestions.length > 0;
6371
6458
  const BoundSuggestionView = hasSuggestions ? renderSlot(suggestionView, CopilotChatSuggestionView, {
6372
6459
  suggestions,
6373
6460
  loadingIndexes: suggestionLoadingIndexes,
@@ -6389,7 +6476,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
6389
6476
  })
6390
6477
  })
6391
6478
  });
6392
- if (messages.length === 0 && !(welcomeScreen === false)) {
6479
+ if (messages.length === 0 && !(welcomeScreen === false) && !isConnecting && !hasExplicitThreadId) {
6393
6480
  const BoundInputForWelcome = renderSlot(input, CopilotChatInput_default, {
6394
6481
  onSubmitMessage,
6395
6482
  onStop,
@@ -6497,9 +6584,60 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
6497
6584
  ] })
6498
6585
  });
6499
6586
  };
6500
- _CopilotChatView.ScrollView = ({ children, autoScroll = true, scrollToBottomButton, feather, inputContainerHeight = 0, isResizing = false, className, ...props }) => {
6587
+ const PinToSendScrollContainer = ({ children, scrollRef, contentRef, scrollToBottom, scrollToBottomButton, feather, inputContainerHeight, isResizing, nonAutoScrollEl, nonAutoScrollRefCallback, showScrollButton, className, ...props }) => {
6588
+ const spacerRef = (0, react.useRef)(null);
6589
+ usePinToSend({
6590
+ scrollRef,
6591
+ contentRef,
6592
+ spacerRef,
6593
+ topOffset: 16
6594
+ });
6595
+ const BoundFeather = renderSlot(feather, PinToSendSoftFeather, {});
6596
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ScrollElementContext.Provider, {
6597
+ value: nonAutoScrollEl,
6598
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6599
+ className: cn("cpk:h-full cpk:max-h-full cpk:flex cpk:flex-col cpk:min-h-0 cpk:relative", className),
6600
+ children: [
6601
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6602
+ ref: nonAutoScrollRefCallback,
6603
+ className: "cpk:flex-1 cpk:min-h-0 cpk:overflow-y-auto cpk:overflow-x-hidden",
6604
+ ...props,
6605
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6606
+ ref: contentRef,
6607
+ className: "cpk:px-4 cpk:sm:px-0 cpk:[div[data-sidebar-chat]_&]:px-8 cpk:[div[data-popup-chat]_&]:px-6",
6608
+ children
6609
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6610
+ ref: spacerRef,
6611
+ "data-pin-to-send-spacer": true,
6612
+ "aria-hidden": "true",
6613
+ style: {
6614
+ height: 0,
6615
+ flex: "0 0 auto"
6616
+ }
6617
+ })]
6618
+ }),
6619
+ BoundFeather,
6620
+ showScrollButton && !isResizing && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6621
+ className: "cpk:absolute cpk:inset-x-0 cpk:flex cpk:justify-center cpk:z-30 cpk:pointer-events-none",
6622
+ style: { bottom: `${inputContainerHeight + PIN_TO_SEND_FEATHER_HEIGHT + 16}px` },
6623
+ children: renderSlot(scrollToBottomButton, CopilotChatView.ScrollToBottomButton, { onClick: () => scrollToBottom() })
6624
+ })
6625
+ ]
6626
+ })
6627
+ });
6628
+ };
6629
+ _CopilotChatView.ScrollView = ({ children, autoScroll = "pin-to-bottom", scrollToBottomButton, feather, inputContainerHeight = 0, isResizing = false, className, ...props }) => {
6630
+ const mode = normalizeAutoScroll(autoScroll);
6501
6631
  const [hasMounted, setHasMounted] = (0, react.useState)(false);
6502
- const { scrollRef, contentRef, scrollToBottom } = (0, use_stick_to_bottom.useStickToBottom)();
6632
+ const scrollRef = (0, react.useRef)(null);
6633
+ const contentRef = (0, react.useRef)(null);
6634
+ const scrollToBottom = (0, react.useCallback)(() => {
6635
+ const el = scrollRef.current;
6636
+ if (el) el.scrollTo({
6637
+ top: el.scrollHeight,
6638
+ behavior: "smooth"
6639
+ });
6640
+ }, []);
6503
6641
  const [showScrollButton, setShowScrollButton] = (0, react.useState)(false);
6504
6642
  const [nonAutoScrollEl, setNonAutoScrollEl] = (0, react.useState)(null);
6505
6643
  const nonAutoScrollRefCallback = (0, react.useCallback)((el) => {
@@ -6510,7 +6648,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
6510
6648
  setHasMounted(true);
6511
6649
  }, []);
6512
6650
  (0, react.useEffect)(() => {
6513
- if (autoScroll) return;
6651
+ if (mode === "pin-to-bottom") return;
6514
6652
  const scrollElement = scrollRef.current;
6515
6653
  if (!scrollElement) return;
6516
6654
  const checkScroll = () => {
@@ -6524,7 +6662,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
6524
6662
  scrollElement.removeEventListener("scroll", checkScroll);
6525
6663
  resizeObserver.disconnect();
6526
6664
  };
6527
- }, [scrollRef, autoScroll]);
6665
+ }, [scrollRef, mode]);
6528
6666
  if (!hasMounted) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6529
6667
  className: "cpk:h-full cpk:max-h-full cpk:flex cpk:flex-col cpk:min-h-0 cpk:overflow-y-auto cpk:overflow-x-hidden",
6530
6668
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
@@ -6532,7 +6670,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
6532
6670
  children
6533
6671
  })
6534
6672
  });
6535
- if (!autoScroll) {
6673
+ if (mode === "none") {
6536
6674
  const BoundFeather = renderSlot(feather, CopilotChatView.Feather, {});
6537
6675
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ScrollElementContext.Provider, {
6538
6676
  value: nonAutoScrollEl,
@@ -6556,6 +6694,21 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
6556
6694
  })
6557
6695
  });
6558
6696
  }
6697
+ if (mode === "pin-to-send") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PinToSendScrollContainer, {
6698
+ scrollRef,
6699
+ contentRef,
6700
+ scrollToBottom,
6701
+ scrollToBottomButton,
6702
+ feather,
6703
+ inputContainerHeight,
6704
+ isResizing,
6705
+ nonAutoScrollEl,
6706
+ nonAutoScrollRefCallback,
6707
+ showScrollButton,
6708
+ className,
6709
+ ...props,
6710
+ children
6711
+ });
6559
6712
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(use_stick_to_bottom.StickToBottom, {
6560
6713
  className: cn("cpk:flex-1 cpk:max-h-full cpk:flex cpk:flex-col cpk:min-h-0", className),
6561
6714
  resize: "smooth",
@@ -6752,10 +6905,8 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
6752
6905
  var _ref, _attachmentsConfig$ac;
6753
6906
  const existingConfig = useCopilotChatConfiguration();
6754
6907
  const resolvedAgentId = (_ref = agentId !== null && agentId !== void 0 ? agentId : existingConfig === null || existingConfig === void 0 ? void 0 : existingConfig.agentId) !== null && _ref !== void 0 ? _ref : _copilotkit_shared.DEFAULT_AGENT_ID;
6755
- const resolvedThreadId = (0, react.useMemo)(() => {
6756
- var _ref2;
6757
- return (_ref2 = threadId !== null && threadId !== void 0 ? threadId : existingConfig === null || existingConfig === void 0 ? void 0 : existingConfig.threadId) !== null && _ref2 !== void 0 ? _ref2 : (0, _copilotkit_shared.randomUUID)();
6758
- }, [threadId, existingConfig === null || existingConfig === void 0 ? void 0 : existingConfig.threadId]);
6908
+ const providedThreadId = threadId !== null && threadId !== void 0 ? threadId : existingConfig === null || existingConfig === void 0 ? void 0 : existingConfig.threadId;
6909
+ const resolvedThreadId = (0, react.useMemo)(() => providedThreadId !== null && providedThreadId !== void 0 ? providedThreadId : (0, _copilotkit_shared.randomUUID)(), [providedThreadId]);
6759
6910
  const { agent } = useAgent({
6760
6911
  agentId: resolvedAgentId,
6761
6912
  threadId: resolvedThreadId,
@@ -6797,7 +6948,10 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
6797
6948
  const isTranscriptionEnabled = copilotkit.audioFileTranscriptionEnabled;
6798
6949
  const isMediaRecorderSupported = typeof window !== "undefined" && typeof MediaRecorder !== "undefined";
6799
6950
  const { messageView: providedMessageView, suggestionView: providedSuggestionView, onStop: providedStopHandler, ...restProps } = props;
6951
+ const [lastConnectedThreadId, setLastConnectedThreadId] = (0, react.useState)(null);
6952
+ const isConnecting = !!providedThreadId && lastConnectedThreadId !== resolvedThreadId;
6800
6953
  (0, react.useEffect)(() => {
6954
+ if (!providedThreadId) return;
6801
6955
  let detached = false;
6802
6956
  const connectAbortController = new AbortController();
6803
6957
  if (agent instanceof _ag_ui_client.HttpAgent) agent.abortController = connectAbortController;
@@ -6807,6 +6961,10 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
6807
6961
  } catch (error) {
6808
6962
  if (detached) return;
6809
6963
  console.error("CopilotChat: connectAgent failed", error);
6964
+ } finally {
6965
+ if (!detached) (typeof requestAnimationFrame === "function" ? requestAnimationFrame : (cb) => setTimeout(cb, 16))(() => {
6966
+ if (!detached) setLastConnectedThreadId(resolvedThreadId);
6967
+ });
6810
6968
  }
6811
6969
  };
6812
6970
  connect(agent);
@@ -6818,7 +6976,8 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
6818
6976
  }, [
6819
6977
  resolvedThreadId,
6820
6978
  agent,
6821
- resolvedAgentId
6979
+ resolvedAgentId,
6980
+ providedThreadId
6822
6981
  ]);
6823
6982
  const onSubmitInput = (0, react.useCallback)(async (value) => {
6824
6983
  if (selectedAttachments.some((a) => a.status === "uploading")) {
@@ -6975,6 +7134,22 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
6975
7134
  }).join(";") : "";
6976
7135
  return `${m.id}:${m.role}:${contentKey}:${toolCallsKey}`;
6977
7136
  }).join(",")]);
7137
+ const lastUserMessageId = (0, react.useMemo)(() => {
7138
+ for (let i = messages.length - 1; i >= 0; i--) if (messages[i].role === "user") return messages[i].id;
7139
+ return null;
7140
+ }, [messages]);
7141
+ const [sendNonce, setSendNonce] = (0, react.useState)(0);
7142
+ const prevLastUserMessageIdRef = (0, react.useRef)(lastUserMessageId);
7143
+ (0, react.useEffect)(() => {
7144
+ if (lastUserMessageId && lastUserMessageId !== prevLastUserMessageIdRef.current) {
7145
+ setSendNonce((n) => n + 1);
7146
+ prevLastUserMessageIdRef.current = lastUserMessageId;
7147
+ }
7148
+ }, [lastUserMessageId]);
7149
+ const lastUserMessageState = (0, react.useMemo)(() => ({
7150
+ id: lastUserMessageId,
7151
+ sendNonce
7152
+ }), [lastUserMessageId, sendNonce]);
6978
7153
  const RenderedChatView = renderSlot(chatView, CopilotChatView, {
6979
7154
  ...mergedProps,
6980
7155
  messages,
@@ -6993,7 +7168,9 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
6993
7168
  dragOver,
6994
7169
  onDragOver: handleDragOver,
6995
7170
  onDragLeave: handleDragLeave,
6996
- onDrop: handleDrop
7171
+ onDrop: handleDrop,
7172
+ isConnecting,
7173
+ hasExplicitThreadId: !!providedThreadId
6997
7174
  });
6998
7175
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopilotChatConfigurationProvider, {
6999
7176
  agentId: resolvedAgentId,
@@ -7028,7 +7205,10 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
7028
7205
  },
7029
7206
  children: transcriptionError
7030
7207
  }),
7031
- RenderedChatView
7208
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LastUserMessageContext.Provider, {
7209
+ value: lastUserMessageState,
7210
+ children: RenderedChatView
7211
+ })
7032
7212
  ]
7033
7213
  })
7034
7214
  });
@@ -9077,13 +9257,18 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
9077
9257
  };
9078
9258
  }, [agent, getSubscriber]);
9079
9259
  };
9260
+ function CopilotListenersAgentSubscription() {
9261
+ const existingConfig = useCopilotChatConfiguration();
9262
+ const { agent } = useAgent({ agentId: existingConfig === null || existingConfig === void 0 ? void 0 : existingConfig.agentId });
9263
+ usePredictStateSubscription(agent);
9264
+ return null;
9265
+ }
9080
9266
  function CopilotListeners() {
9267
+ var _copilotkit$agents;
9081
9268
  const { copilotkit } = useCopilotKit();
9082
- const existingConfig = useCopilotChatConfiguration();
9083
- const resolvedAgentId = existingConfig === null || existingConfig === void 0 ? void 0 : existingConfig.agentId;
9084
9269
  const { setBannerError } = useToast();
9085
- const { agent } = useAgent({ agentId: resolvedAgentId });
9086
- usePredictStateSubscription(agent);
9270
+ const hasAgents = Object.keys((_copilotkit$agents = copilotkit.agents) !== null && _copilotkit$agents !== void 0 ? _copilotkit$agents : {}).length > 0;
9271
+ const hasRuntime = copilotkit.runtimeUrl !== void 0;
9087
9272
  (0, react.useEffect)(() => {
9088
9273
  const subscription = copilotkit.subscribe({ onError: ({ error, code, context }) => {
9089
9274
  if (error.name === "AbortError" || error.message === "Fetch is aborted" || error.message === "signal is aborted without reason" || error.message === "component unmounted" || !error.message) return;
@@ -9105,7 +9290,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
9105
9290
  subscription.unsubscribe();
9106
9291
  };
9107
9292
  }, [copilotkit === null || copilotkit === void 0 ? void 0 : copilotkit.subscribe]);
9108
- return null;
9293
+ return hasAgents || hasRuntime ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopilotListenersAgentSubscription, {}) : null;
9109
9294
  }
9110
9295
 
9111
9296
  //#endregion