@copilotkit/react-core 1.55.0-next.8 → 1.55.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 (94) hide show
  1. package/CHANGELOG.md +48 -5
  2. package/dist/{copilotkit-DNYSFuz5.mjs → copilotkit-BY5S1-0P.mjs} +2772 -858
  3. package/dist/copilotkit-BY5S1-0P.mjs.map +1 -0
  4. package/dist/{copilotkit-Dy5w3qEV.d.mts → copilotkit-BuhSUZHb.d.mts} +230 -17
  5. package/dist/copilotkit-BuhSUZHb.d.mts.map +1 -0
  6. package/dist/{copilotkit-B3Mb1yVE.cjs → copilotkit-Bz5-ImDl.cjs} +2776 -832
  7. package/dist/copilotkit-Bz5-ImDl.cjs.map +1 -0
  8. package/dist/{copilotkit-DBzgOMby.d.cts → copilotkit-dwDWYpya.d.cts} +230 -17
  9. package/dist/copilotkit-dwDWYpya.d.cts.map +1 -0
  10. package/dist/index.cjs +9 -4
  11. package/dist/index.cjs.map +1 -1
  12. package/dist/index.d.cts +1 -1
  13. package/dist/index.d.mts +1 -1
  14. package/dist/index.mjs +9 -4
  15. package/dist/index.mjs.map +1 -1
  16. package/dist/index.umd.js +1624 -396
  17. package/dist/index.umd.js.map +1 -1
  18. package/dist/v2/index.cjs +13 -1
  19. package/dist/v2/index.css +1 -1
  20. package/dist/v2/index.d.cts +3 -3
  21. package/dist/v2/index.d.mts +3 -3
  22. package/dist/v2/index.mjs +3 -2
  23. package/dist/v2/index.umd.js +2746 -790
  24. package/dist/v2/index.umd.js.map +1 -1
  25. package/package.json +62 -54
  26. package/scripts/scope-preflight.mjs +1 -2
  27. package/src/components/CopilotListeners.tsx +41 -8
  28. package/src/components/copilot-provider/__tests__/copilot-messages-key.test.tsx +92 -0
  29. package/src/components/copilot-provider/copilotkit-props.tsx +4 -2
  30. package/src/components/copilot-provider/copilotkit.tsx +3 -3
  31. package/src/components/toast/toast-provider.tsx +269 -194
  32. package/src/hooks/__tests__/use-copilot-chat-internal-connect.test.tsx +27 -16
  33. package/src/hooks/use-copilot-chat_internal.ts +15 -4
  34. package/src/v2/__tests__/A2UIMessageRenderer.test.tsx +86 -22
  35. package/src/v2/__tests__/utils/test-helpers.tsx +107 -7
  36. package/src/v2/a2ui/A2UICatalogContext.tsx +79 -0
  37. package/src/v2/a2ui/A2UIMessageRenderer.tsx +125 -37
  38. package/src/v2/a2ui/A2UIToolCallRenderer.tsx +290 -0
  39. package/src/v2/components/CopilotKitInspector.tsx +2 -0
  40. package/src/v2/components/OpenGenerativeUIRenderer.tsx +598 -0
  41. package/src/v2/components/__tests__/OpenGenerativeUIRenderer.test.tsx +665 -0
  42. package/src/v2/components/chat/CopilotChat.tsx +197 -52
  43. package/src/v2/components/chat/CopilotChatAssistantMessage.tsx +17 -2
  44. package/src/v2/components/chat/CopilotChatAttachmentQueue.tsx +481 -0
  45. package/src/v2/components/chat/CopilotChatAttachmentRenderer.tsx +139 -0
  46. package/src/v2/components/chat/CopilotChatInput.tsx +146 -77
  47. package/src/v2/components/chat/CopilotChatMessageView.tsx +260 -151
  48. package/src/v2/components/chat/CopilotChatSuggestionView.tsx +1 -0
  49. package/src/v2/components/chat/CopilotChatUserMessage.tsx +54 -0
  50. package/src/v2/components/chat/CopilotChatView.tsx +179 -66
  51. package/src/v2/components/chat/__tests__/CopilotChat.attachments.test.tsx +168 -0
  52. package/src/v2/components/chat/__tests__/CopilotChatActivityRendering.e2e.test.tsx +63 -2
  53. package/src/v2/components/chat/__tests__/CopilotChatInput.test.tsx +544 -1
  54. package/src/v2/components/chat/__tests__/CopilotChatPerf.e2e.test.tsx +268 -0
  55. package/src/v2/components/chat/__tests__/CopilotChatPropsRerender.e2e.test.tsx +249 -0
  56. package/src/v2/components/chat/__tests__/CopilotChatToolRendering.e2e.test.tsx +5 -2
  57. package/src/v2/components/chat/__tests__/CopilotChatToolRerenders.e2e.test.tsx +5 -2
  58. package/src/v2/components/chat/__tests__/MCPAppsActivityRenderer.e2e.test.tsx +60 -3
  59. package/src/v2/components/chat/__tests__/copilot-chat-throttle.test.tsx +138 -0
  60. package/src/v2/components/chat/index.ts +9 -0
  61. package/src/v2/components/chat/scroll-element-context.ts +13 -0
  62. package/src/v2/hooks/__tests__/use-agent-context-timing.e2e.test.tsx +8 -0
  63. package/src/v2/hooks/__tests__/use-agent-thread-isolation.test.tsx +327 -0
  64. package/src/v2/hooks/__tests__/use-agent-throttle.test.tsx +1003 -0
  65. package/src/v2/hooks/__tests__/use-agent.e2e.test.tsx +13 -2
  66. package/src/v2/hooks/__tests__/use-attachments.test.tsx +169 -0
  67. package/src/v2/hooks/__tests__/use-frontend-tool.e2e.test.tsx +23 -4
  68. package/src/v2/hooks/__tests__/use-threads.test.tsx +54 -0
  69. package/src/v2/hooks/index.ts +5 -0
  70. package/src/v2/hooks/use-agent.tsx +220 -15
  71. package/src/v2/hooks/use-attachments.tsx +269 -0
  72. package/src/v2/hooks/use-frontend-tool.tsx +5 -2
  73. package/src/v2/hooks/use-render-activity-message.tsx +9 -2
  74. package/src/v2/hooks/use-render-custom-messages.tsx +6 -1
  75. package/src/v2/hooks/use-threads.tsx +35 -15
  76. package/src/v2/index.ts +5 -1
  77. package/src/v2/lib/__tests__/processPartialHtml.test.ts +112 -0
  78. package/src/v2/lib/__tests__/slots.test.ts +56 -0
  79. package/src/v2/lib/processPartialHtml.ts +45 -0
  80. package/src/v2/lib/slots.tsx +42 -1
  81. package/src/v2/providers/CopilotChatConfigurationProvider.tsx +9 -3
  82. package/src/v2/providers/CopilotKitProvider.tsx +268 -32
  83. package/src/v2/providers/SandboxFunctionsContext.ts +10 -0
  84. package/src/v2/providers/__tests__/CopilotKitProvider.sandboxFunctions.test.tsx +198 -0
  85. package/src/v2/providers/__tests__/CopilotKitProvider.test.tsx +71 -0
  86. package/src/v2/providers/index.ts +7 -0
  87. package/src/v2/styles/globals.css +2 -1
  88. package/src/v2/types/index.ts +1 -0
  89. package/src/v2/types/sandbox-function.ts +11 -0
  90. package/dist/copilotkit-B3Mb1yVE.cjs.map +0 -1
  91. package/dist/copilotkit-DBzgOMby.d.cts.map +0 -1
  92. package/dist/copilotkit-DNYSFuz5.mjs.map +0 -1
  93. package/dist/copilotkit-Dy5w3qEV.d.mts.map +0 -1
  94. package/src/v2/components/__tests__/license-warning-banner.test.tsx +0 -46
@@ -1,10 +1,10 @@
1
1
  "use client";
2
2
 
3
3
  (function(global, factory) {
4
- typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('./index.css'), require('@copilotkit/core'), require('@ag-ui/client'), require('react'), require('tailwind-merge'), require('lucide-react'), require('@copilotkit/shared'), require('react/jsx-runtime'), require('@radix-ui/react-slot'), require('class-variance-authority'), require('clsx'), require('@radix-ui/react-tooltip'), require('@radix-ui/react-dropdown-menu'), require('streamdown'), require('zod'), require('@lit-labs/react'), require('@copilotkit/a2ui-renderer'), require('use-stick-to-bottom'), require('ts-deepmerge'), require('react-dom')) :
5
- typeof define === 'function' && define.amd ? define(['exports', './index.css', '@copilotkit/core', '@ag-ui/client', 'react', 'tailwind-merge', 'lucide-react', '@copilotkit/shared', 'react/jsx-runtime', '@radix-ui/react-slot', 'class-variance-authority', 'clsx', '@radix-ui/react-tooltip', '@radix-ui/react-dropdown-menu', 'streamdown', 'zod', '@lit-labs/react', '@copilotkit/a2ui-renderer', 'use-stick-to-bottom', 'ts-deepmerge', 'react-dom'], factory) :
6
- (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory((global.CopilotKitReactCoreV2 = {}), global.src_v2_index_css,global.CopilotKitCore,global.AgUIClient,global.React,global.tailwindMerge,global.lucideReact,global.CopilotKitShared,global.ReactJsxRuntime,global.RadixReactSlot,global.classVarianceAuthority,global.clsx,global.RadixReactTooltip,global.RadixReactDropdownMenu,global.streamdown,global.Zod,global.LitLabsReact,global.CopilotKitA2UIRenderer,global.useStickToBottom,global.tsDeepmerge,global.ReactDOM));
7
- })(this, function(exports, src_v2_index_css, _copilotkit_core, _ag_ui_client, react, tailwind_merge, lucide_react, _copilotkit_shared, react_jsx_runtime, _radix_ui_react_slot, class_variance_authority, clsx, _radix_ui_react_tooltip, _radix_ui_react_dropdown_menu, streamdown, zod, _lit_labs_react, _copilotkit_a2ui_renderer, use_stick_to_bottom, ts_deepmerge, react_dom) {
4
+ typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('./index.css'), require('@copilotkit/core'), require('@ag-ui/client'), require('react'), require('tailwind-merge'), require('lucide-react'), require('@copilotkit/shared'), require('react/jsx-runtime'), require('@radix-ui/react-slot'), require('class-variance-authority'), require('clsx'), require('@radix-ui/react-tooltip'), require('@radix-ui/react-dropdown-menu'), require('streamdown'), require('zod'), require('@lit-labs/react'), require('@copilotkit/a2ui-renderer'), require('zod-to-json-schema'), require('@tanstack/react-virtual'), require('react-dom'), require('use-stick-to-bottom')) :
5
+ typeof define === 'function' && define.amd ? define(['exports', './index.css', '@copilotkit/core', '@ag-ui/client', 'react', 'tailwind-merge', 'lucide-react', '@copilotkit/shared', 'react/jsx-runtime', '@radix-ui/react-slot', 'class-variance-authority', 'clsx', '@radix-ui/react-tooltip', '@radix-ui/react-dropdown-menu', 'streamdown', 'zod', '@lit-labs/react', '@copilotkit/a2ui-renderer', 'zod-to-json-schema', '@tanstack/react-virtual', 'react-dom', 'use-stick-to-bottom'], factory) :
6
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory((global.CopilotKitReactCoreV2 = {}), global.src_v2_index_css,global.CopilotKitCore,global.AgUIClient,global.React,global.tailwindMerge,global.lucideReact,global.CopilotKitShared,global.ReactJsxRuntime,global.RadixReactSlot,global.classVarianceAuthority,global.clsx,global.RadixReactTooltip,global.RadixReactDropdownMenu,global.streamdown,global.Zod,global.LitLabsReact,global.CopilotKitA2UIRenderer,global.zod_to_json_schema,global._tanstack_react_virtual,global.ReactDOM,global.useStickToBottom));
7
+ })(this, function(exports, src_v2_index_css, _copilotkit_core, _ag_ui_client, react, tailwind_merge, lucide_react, _copilotkit_shared, react_jsx_runtime, _radix_ui_react_slot, class_variance_authority, clsx, _radix_ui_react_tooltip, _radix_ui_react_dropdown_menu, streamdown, zod, _lit_labs_react, _copilotkit_a2ui_renderer, zod_to_json_schema, _tanstack_react_virtual, react_dom, use_stick_to_bottom) {
8
8
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
9
9
  //#region \0rolldown/runtime.js
10
10
  var __create = Object.create;
@@ -37,13 +37,113 @@ react = __toESM(react);
37
37
  _radix_ui_react_tooltip = __toESM(_radix_ui_react_tooltip);
38
38
  _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
39
39
 
40
+ //#region src/v2/lib/slots.tsx
41
+ /**
42
+ * Shallow equality comparison for objects.
43
+ */
44
+ function shallowEqual(obj1, obj2) {
45
+ const keys1 = Object.keys(obj1);
46
+ const keys2 = Object.keys(obj2);
47
+ if (keys1.length !== keys2.length) return false;
48
+ for (const key of keys1) if (obj1[key] !== obj2[key]) return false;
49
+ return true;
50
+ }
51
+ /**
52
+ * Returns true only for plain JS objects (`{}`), excluding arrays, Dates,
53
+ * class instances, and other exotic objects that happen to have typeof "object".
54
+ */
55
+ function isPlainObject(obj) {
56
+ return obj !== null && typeof obj === "object" && Object.prototype.toString.call(obj) === "[object Object]";
57
+ }
58
+ /**
59
+ * Returns the same reference as long as the value is shallowly equal to the
60
+ * previous render's value.
61
+ *
62
+ * - Identical references bail out immediately (O(1)).
63
+ * - Plain objects ({}) are shallow-compared key-by-key.
64
+ * - Arrays, Dates, class instances, functions, and primitives are compared by
65
+ * reference only — shallowEqual is never called on non-plain objects, which
66
+ * avoids incorrect equality for e.g. [1,2] vs [1,2] (different arrays).
67
+ *
68
+ * Typical use: stabilize inline slot props so MemoizedSlotWrapper's shallow
69
+ * equality check isn't defeated by a new object reference on every render.
70
+ */
71
+ function useShallowStableRef(value) {
72
+ const ref = (0, react.useRef)(value);
73
+ if (ref.current === value) return ref.current;
74
+ if (isPlainObject(ref.current) && isPlainObject(value)) {
75
+ if (shallowEqual(ref.current, value)) return ref.current;
76
+ }
77
+ ref.current = value;
78
+ return ref.current;
79
+ }
80
+ /**
81
+ * Check if a value is a React component type (function, class, forwardRef, memo, etc.)
82
+ */
83
+ function isReactComponentType(value) {
84
+ if (typeof value === "function") return true;
85
+ if (value && typeof value === "object" && "$$typeof" in value && !react.default.isValidElement(value)) return true;
86
+ return false;
87
+ }
88
+ /**
89
+ * Internal function to render a slot value as a React element (non-memoized).
90
+ */
91
+ function renderSlotElement(slot, DefaultComponent, props) {
92
+ if (typeof slot === "string") {
93
+ const existingClassName = props.className;
94
+ return react.default.createElement(DefaultComponent, {
95
+ ...props,
96
+ className: (0, tailwind_merge.twMerge)(existingClassName, slot)
97
+ });
98
+ }
99
+ if (isReactComponentType(slot)) return react.default.createElement(slot, props);
100
+ if (slot && typeof slot === "object" && !react.default.isValidElement(slot)) return react.default.createElement(DefaultComponent, {
101
+ ...props,
102
+ ...slot
103
+ });
104
+ return react.default.createElement(DefaultComponent, props);
105
+ }
106
+ /**
107
+ * Internal memoized wrapper component for renderSlot.
108
+ * Uses forwardRef to support ref forwarding.
109
+ */
110
+ const MemoizedSlotWrapper = react.default.memo(react.default.forwardRef(function MemoizedSlotWrapper(props, ref) {
111
+ const { $slot, $component, ...rest } = props;
112
+ return renderSlotElement($slot, $component, ref !== null ? {
113
+ ...rest,
114
+ ref
115
+ } : rest);
116
+ }), (prev, next) => {
117
+ if (prev.$slot !== next.$slot) return false;
118
+ if (prev.$component !== next.$component) return false;
119
+ const { $slot: _ps, $component: _pc, ...prevRest } = prev;
120
+ const { $slot: _ns, $component: _nc, ...nextRest } = next;
121
+ return shallowEqual(prevRest, nextRest);
122
+ });
123
+ /**
124
+ * Renders a slot value as a memoized React element.
125
+ * Automatically prevents unnecessary re-renders using shallow prop comparison.
126
+ * Supports ref forwarding.
127
+ *
128
+ * @example
129
+ * renderSlot(customInput, CopilotChatInput, { onSubmit: handleSubmit })
130
+ */
131
+ function renderSlot(slot, DefaultComponent, props) {
132
+ return react.default.createElement(MemoizedSlotWrapper, {
133
+ ...props,
134
+ $slot: slot,
135
+ $component: DefaultComponent
136
+ });
137
+ }
138
+
139
+ //#endregion
40
140
  //#region src/v2/providers/CopilotChatConfigurationProvider.tsx
41
141
  const CopilotChatDefaultLabels = {
42
142
  chatInputPlaceholder: "Type a message...",
43
143
  chatInputToolbarStartTranscribeButtonLabel: "Transcribe",
44
144
  chatInputToolbarCancelTranscribeButtonLabel: "Cancel",
45
145
  chatInputToolbarFinishTranscribeButtonLabel: "Finish",
46
- chatInputToolbarAddButtonLabel: "Add photos or files",
146
+ chatInputToolbarAddButtonLabel: "Add attachments",
47
147
  chatInputToolbarToolsButtonLabel: "Tools",
48
148
  assistantMessageToolbarCopyCodeLabel: "Copy",
49
149
  assistantMessageToolbarCopyCodeCopiedLabel: "Copied",
@@ -64,14 +164,15 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
64
164
  const CopilotChatConfigurationProvider = ({ children, labels, agentId, threadId, isModalDefaultOpen }) => {
65
165
  var _ref, _parentConfig$isModal, _parentConfig$setModa;
66
166
  const parentConfig = (0, react.useContext)(CopilotChatConfiguration);
167
+ const stableLabels = useShallowStableRef(labels);
67
168
  const mergedLabels = (0, react.useMemo)(() => {
68
169
  var _parentConfig$labels;
69
170
  return {
70
171
  ...CopilotChatDefaultLabels,
71
172
  ...(_parentConfig$labels = parentConfig === null || parentConfig === void 0 ? void 0 : parentConfig.labels) !== null && _parentConfig$labels !== void 0 ? _parentConfig$labels : {},
72
- ...labels !== null && labels !== void 0 ? labels : {}
173
+ ...stableLabels !== null && stableLabels !== void 0 ? stableLabels : {}
73
174
  };
74
- }, [labels, parentConfig === null || parentConfig === void 0 ? void 0 : parentConfig.labels]);
175
+ }, [stableLabels, parentConfig === null || parentConfig === void 0 ? void 0 : parentConfig.labels]);
75
176
  const resolvedAgentId = (_ref = agentId !== null && agentId !== void 0 ? agentId : parentConfig === null || parentConfig === void 0 ? void 0 : parentConfig.agentId) !== null && _ref !== void 0 ? _ref : _copilotkit_shared.DEFAULT_AGENT_ID;
76
177
  const resolvedThreadId = (0, react.useMemo)(() => {
77
178
  if (threadId) return threadId;
@@ -120,9 +221,9 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
120
221
 
121
222
  //#endregion
122
223
  //#region src/v2/lib/utils.ts
123
- const twMerge$8 = (0, tailwind_merge.extendTailwindMerge)({ prefix: "cpk" });
224
+ const twMerge$7 = (0, tailwind_merge.extendTailwindMerge)({ prefix: "cpk" });
124
225
  function cn(...inputs) {
125
- return twMerge$8((0, clsx.clsx)(inputs));
226
+ return twMerge$7((0, clsx.clsx)(inputs));
126
227
  }
127
228
 
128
229
  //#endregion
@@ -496,82 +597,11 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
496
597
  });
497
598
  CopilotChatAudioRecorder.displayName = "CopilotChatAudioRecorder";
498
599
 
499
- //#endregion
500
- //#region src/v2/lib/slots.tsx
501
- /**
502
- * Shallow equality comparison for objects.
503
- */
504
- function shallowEqual(obj1, obj2) {
505
- const keys1 = Object.keys(obj1);
506
- const keys2 = Object.keys(obj2);
507
- if (keys1.length !== keys2.length) return false;
508
- for (const key of keys1) if (obj1[key] !== obj2[key]) return false;
509
- return true;
510
- }
511
- /**
512
- * Check if a value is a React component type (function, class, forwardRef, memo, etc.)
513
- */
514
- function isReactComponentType(value) {
515
- if (typeof value === "function") return true;
516
- if (value && typeof value === "object" && "$$typeof" in value && !react.default.isValidElement(value)) return true;
517
- return false;
518
- }
519
- /**
520
- * Internal function to render a slot value as a React element (non-memoized).
521
- */
522
- function renderSlotElement(slot, DefaultComponent, props) {
523
- if (typeof slot === "string") {
524
- const existingClassName = props.className;
525
- return react.default.createElement(DefaultComponent, {
526
- ...props,
527
- className: (0, tailwind_merge.twMerge)(existingClassName, slot)
528
- });
529
- }
530
- if (isReactComponentType(slot)) return react.default.createElement(slot, props);
531
- if (slot && typeof slot === "object" && !react.default.isValidElement(slot)) return react.default.createElement(DefaultComponent, {
532
- ...props,
533
- ...slot
534
- });
535
- return react.default.createElement(DefaultComponent, props);
536
- }
537
- /**
538
- * Internal memoized wrapper component for renderSlot.
539
- * Uses forwardRef to support ref forwarding.
540
- */
541
- const MemoizedSlotWrapper = react.default.memo(react.default.forwardRef(function MemoizedSlotWrapper(props, ref) {
542
- const { $slot, $component, ...rest } = props;
543
- return renderSlotElement($slot, $component, ref !== null ? {
544
- ...rest,
545
- ref
546
- } : rest);
547
- }), (prev, next) => {
548
- if (prev.$slot !== next.$slot) return false;
549
- if (prev.$component !== next.$component) return false;
550
- const { $slot: _ps, $component: _pc, ...prevRest } = prev;
551
- const { $slot: _ns, $component: _nc, ...nextRest } = next;
552
- return shallowEqual(prevRest, nextRest);
553
- });
554
- /**
555
- * Renders a slot value as a memoized React element.
556
- * Automatically prevents unnecessary re-renders using shallow prop comparison.
557
- * Supports ref forwarding.
558
- *
559
- * @example
560
- * renderSlot(customInput, CopilotChatInput, { onSubmit: handleSubmit })
561
- */
562
- function renderSlot(slot, DefaultComponent, props) {
563
- return react.default.createElement(MemoizedSlotWrapper, {
564
- ...props,
565
- $slot: slot,
566
- $component: DefaultComponent
567
- });
568
- }
569
-
570
600
  //#endregion
571
601
  //#region src/v2/components/chat/CopilotChatInput.tsx
572
602
  const SLASH_MENU_MAX_VISIBLE_ITEMS = 5;
573
603
  const SLASH_MENU_ITEM_HEIGHT_PX = 40;
574
- function CopilotChatInput({ mode = "input", onSubmitMessage, onStop, isRunning = false, onStartTranscribe, onCancelTranscribe, onFinishTranscribe, onFinishTranscribeWithAudio, onAddFile, onChange, value, toolsMenu, autoFocus = true, positioning = "static", keyboardHeight = 0, containerRef, showDisclaimer, textArea, sendButton, startTranscribeButton, cancelTranscribeButton, finishTranscribeButton, addMenuButton, audioRecorder, disclaimer, children, className, ...props }) {
604
+ 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 }) {
575
605
  var _config$labels;
576
606
  const isControlled = value !== void 0;
577
607
  const [internalValue, setInternalValue] = (0, react.useState)(() => value !== null && value !== void 0 ? value : "");
@@ -601,6 +631,7 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
601
631
  paddingLeft: 0,
602
632
  paddingRight: 0
603
633
  });
634
+ const containerCacheRef = (0, react.useRef)(null);
604
635
  const commandItems = (0, react.useMemo)(() => {
605
636
  const entries = [];
606
637
  const seen = /* @__PURE__ */ new Set();
@@ -647,7 +678,7 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
647
678
  }
648
679
  if ((config === null || config === void 0 ? void 0 : config.isModalOpen) && !previousModalStateRef.current) {
649
680
  var _inputRef$current;
650
- (_inputRef$current = inputRef.current) === null || _inputRef$current === void 0 || _inputRef$current.focus();
681
+ (_inputRef$current = inputRef.current) === null || _inputRef$current === void 0 || _inputRef$current.focus({ preventScroll: true });
651
682
  }
652
683
  previousModalStateRef.current = config === null || config === void 0 ? void 0 : config.isModalOpen;
653
684
  }, [config === null || config === void 0 ? void 0 : config.isModalOpen, autoFocus]);
@@ -894,6 +925,25 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
894
925
  return nextLayout;
895
926
  });
896
927
  }, []);
928
+ const updateContainerCache = (0, react.useCallback)(() => {
929
+ const grid = gridRef.current;
930
+ const addContainer = addButtonContainerRef.current;
931
+ const actionsContainer = actionsContainerRef.current;
932
+ if (!grid || !addContainer || !actionsContainer) return null;
933
+ const gridStyles = window.getComputedStyle(grid);
934
+ const paddingLeft = parseFloat(gridStyles.paddingLeft) || 0;
935
+ const paddingRight = parseFloat(gridStyles.paddingRight) || 0;
936
+ const columnGap = parseFloat(gridStyles.columnGap) || 0;
937
+ const gridAvailableWidth = grid.clientWidth - paddingLeft - paddingRight;
938
+ if (gridAvailableWidth <= 0) return null;
939
+ const addWidth = addContainer.getBoundingClientRect().width;
940
+ const actionsWidth = actionsContainer.getBoundingClientRect().width;
941
+ const compactWidth = Math.max(gridAvailableWidth - addWidth - actionsWidth - columnGap * 2, 0);
942
+ if (compactWidth <= 0) return null;
943
+ const result = { compactWidth };
944
+ containerCacheRef.current = result;
945
+ return result;
946
+ }, []);
897
947
  const evaluateLayout = (0, react.useCallback)(() => {
898
948
  if (mode !== "input") {
899
949
  updateLayout("compact");
@@ -919,32 +969,33 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
919
969
  const renderedMultiline = baseline > 0 ? scrollHeight > baseline + 1 : false;
920
970
  let shouldExpand = hasExplicitBreak || renderedMultiline;
921
971
  if (!shouldExpand) {
922
- const gridStyles = window.getComputedStyle(grid);
923
- const paddingLeft = parseFloat(gridStyles.paddingLeft) || 0;
924
- const paddingRight = parseFloat(gridStyles.paddingRight) || 0;
925
- const columnGap = parseFloat(gridStyles.columnGap) || 0;
926
- const gridAvailableWidth = grid.clientWidth - paddingLeft - paddingRight;
927
- if (gridAvailableWidth > 0) {
928
- var _measurementCanvasRef;
929
- const addWidth = addContainer.getBoundingClientRect().width;
930
- const actionsWidth = actionsContainer.getBoundingClientRect().width;
931
- const compactWidth = Math.max(gridAvailableWidth - addWidth - actionsWidth - columnGap * 2, 0);
932
- const canvas = (_measurementCanvasRef = measurementCanvasRef.current) !== null && _measurementCanvasRef !== void 0 ? _measurementCanvasRef : document.createElement("canvas");
933
- if (!measurementCanvasRef.current) measurementCanvasRef.current = canvas;
934
- const context = canvas.getContext("2d");
935
- if (context) {
972
+ var _containerCacheRef$cu;
973
+ const cache = (_containerCacheRef$cu = containerCacheRef.current) !== null && _containerCacheRef$cu !== void 0 ? _containerCacheRef$cu : updateContainerCache();
974
+ if (cache && cache.compactWidth > 0) {
975
+ const compactInnerWidth = Math.max(cache.compactWidth - (measurementsRef.current.paddingLeft || 0) - (measurementsRef.current.paddingRight || 0), 0);
976
+ if (compactInnerWidth > 0) {
936
977
  const textareaStyles = window.getComputedStyle(textarea);
937
- context.font = textareaStyles.font || `${textareaStyles.fontStyle} ${textareaStyles.fontVariant} ${textareaStyles.fontWeight} ${textareaStyles.fontSize}/${textareaStyles.lineHeight} ${textareaStyles.fontFamily}`;
938
- const compactInnerWidth = Math.max(compactWidth - (measurementsRef.current.paddingLeft || 0) - (measurementsRef.current.paddingRight || 0), 0);
939
- if (compactInnerWidth > 0) {
940
- const lines = resolvedValue.length > 0 ? resolvedValue.split("\n") : [""];
941
- let longestWidth = 0;
942
- for (const line of lines) {
943
- const metrics = context.measureText(line || " ");
944
- if (metrics.width > longestWidth) longestWidth = metrics.width;
945
- }
946
- if (longestWidth > compactInnerWidth) shouldExpand = true;
978
+ let font = textareaStyles.font;
979
+ if (!font) {
980
+ const { fontStyle, fontVariant, fontWeight, fontSize, lineHeight, fontFamily } = textareaStyles;
981
+ if (fontSize && fontFamily) font = `${fontStyle} ${fontVariant} ${fontWeight} ${fontSize}/${lineHeight} ${fontFamily}`;
947
982
  }
983
+ if (font === null || font === void 0 ? void 0 : font.trim()) {
984
+ var _measurementCanvasRef;
985
+ const canvas = (_measurementCanvasRef = measurementCanvasRef.current) !== null && _measurementCanvasRef !== void 0 ? _measurementCanvasRef : document.createElement("canvas");
986
+ if (!measurementCanvasRef.current) measurementCanvasRef.current = canvas;
987
+ const context = canvas.getContext("2d");
988
+ if (context) {
989
+ context.font = font;
990
+ const lines = resolvedValue.length > 0 ? resolvedValue.split("\n") : [""];
991
+ let longestWidth = 0;
992
+ for (const line of lines) {
993
+ const metrics = context.measureText(line || " ");
994
+ if (metrics.width > longestWidth) longestWidth = metrics.width;
995
+ }
996
+ if (longestWidth > compactInnerWidth) shouldExpand = true;
997
+ } else if (process.env.NODE_ENV !== "production") console.warn("[CopilotChatInput] canvas.getContext('2d') returned null. Text-width-based expansion will be unavailable.");
998
+ } else if (process.env.NODE_ENV !== "production") console.warn("[CopilotChatInput] Could not resolve textarea font for layout measurement. Text-width-based expansion will be skipped until the next evaluation.");
948
999
  }
949
1000
  }
950
1001
  }
@@ -954,6 +1005,7 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
954
1005
  ensureMeasurements,
955
1006
  mode,
956
1007
  resolvedValue,
1008
+ updateContainerCache,
957
1009
  updateLayout
958
1010
  ]);
959
1011
  (0, react.useLayoutEffect)(() => {
@@ -966,11 +1018,17 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
966
1018
  const addContainer = addButtonContainerRef.current;
967
1019
  const actionsContainer = actionsContainerRef.current;
968
1020
  if (!textarea || !grid || !addContainer || !actionsContainer) return;
969
- const scheduleEvaluation = () => {
1021
+ const containerTargets = new Set([
1022
+ grid,
1023
+ addContainer,
1024
+ actionsContainer
1025
+ ]);
1026
+ const scheduleEvaluation = (invalidateCache) => {
970
1027
  if (ignoreResizeRef.current) {
971
1028
  ignoreResizeRef.current = false;
972
1029
  return;
973
1030
  }
1031
+ if (invalidateCache) containerCacheRef.current = null;
974
1032
  if (typeof window === "undefined") {
975
1033
  evaluateLayout();
976
1034
  return;
@@ -981,8 +1039,13 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
981
1039
  evaluateLayout();
982
1040
  });
983
1041
  };
984
- const observer = new ResizeObserver(() => {
985
- scheduleEvaluation();
1042
+ const observer = new ResizeObserver((entries) => {
1043
+ let shouldInvalidate = false;
1044
+ for (const entry of entries) if (containerTargets.has(entry.target)) {
1045
+ shouldInvalidate = true;
1046
+ break;
1047
+ }
1048
+ scheduleEvaluation(shouldInvalidate);
986
1049
  });
987
1050
  observer.observe(grid);
988
1051
  observer.observe(addContainer);
@@ -1133,6 +1196,8 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
1133
1196
  var _config$labels3;
1134
1197
  const config = useCopilotChatConfiguration();
1135
1198
  const labels = (_config$labels3 = config === null || config === void 0 ? void 0 : config.labels) !== null && _config$labels3 !== void 0 ? _config$labels3 : CopilotChatDefaultLabels;
1199
+ const [mounted, setMounted] = (0, react.useState)(false);
1200
+ (0, react.useEffect)(() => setMounted(true), []);
1136
1201
  const menuItems = (0, react.useMemo)(() => {
1137
1202
  const items = [];
1138
1203
  if (onAddFile) items.push({
@@ -1163,26 +1228,28 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
1163
1228
  }), []);
1164
1229
  const hasMenuItems = menuItems.length > 0;
1165
1230
  const isDisabled = disabled || !hasMenuItems;
1231
+ const button = /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
1232
+ type: "button",
1233
+ "data-testid": "copilot-add-menu-button",
1234
+ variant: "chatInputToolbarSecondary",
1235
+ size: "chatInputToolbarIcon",
1236
+ className: (0, tailwind_merge.twMerge)("cpk:ml-1", className),
1237
+ disabled: isDisabled,
1238
+ ...props,
1239
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Plus, { className: "cpk:size-[20px]" })
1240
+ });
1241
+ if (!mounted) return button;
1166
1242
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(DropdownMenu, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Tooltip, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(TooltipTrigger, {
1167
1243
  asChild: true,
1168
1244
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DropdownMenuTrigger, {
1169
1245
  asChild: true,
1170
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
1171
- type: "button",
1172
- "data-testid": "copilot-add-menu-button",
1173
- variant: "chatInputToolbarSecondary",
1174
- size: "chatInputToolbarIcon",
1175
- className: (0, tailwind_merge.twMerge)("cpk:ml-1", className),
1176
- disabled: isDisabled,
1177
- ...props,
1178
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Plus, { className: "cpk:size-[20px]" })
1179
- })
1246
+ children: button
1180
1247
  })
1181
1248
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TooltipContent, {
1182
1249
  side: "bottom",
1183
1250
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
1184
1251
  className: "cpk:flex cpk:items-center cpk:gap-1 cpk:text-xs cpk:font-medium",
1185
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "Add files and more" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", {
1252
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "Add attachments" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", {
1186
1253
  className: "cpk:rounded cpk:bg-[#4a4a4a] cpk:px-1 cpk:py-[1px] cpk:font-mono cpk:text-[11px] cpk:text-white cpk:dark:bg-[#e0e0e0] cpk:dark:text-black",
1187
1254
  children: "/"
1188
1255
  })]
@@ -1199,24 +1266,10 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
1199
1266
  const config = useCopilotChatConfiguration();
1200
1267
  const labels = (_config$labels4 = config === null || config === void 0 ? void 0 : config.labels) !== null && _config$labels4 !== void 0 ? _config$labels4 : CopilotChatDefaultLabels;
1201
1268
  (0, react.useImperativeHandle)(ref, () => internalTextareaRef.current);
1202
- (0, react.useEffect)(() => {
1203
- const textarea = internalTextareaRef.current;
1204
- if (!textarea) return;
1205
- const handleFocus = () => {
1206
- setTimeout(() => {
1207
- textarea.scrollIntoView({
1208
- behavior: "smooth",
1209
- block: "nearest"
1210
- });
1211
- }, 300);
1212
- };
1213
- textarea.addEventListener("focus", handleFocus);
1214
- return () => textarea.removeEventListener("focus", handleFocus);
1215
- }, []);
1216
1269
  (0, react.useEffect)(() => {
1217
1270
  if (autoFocus) {
1218
1271
  var _internalTextareaRef$;
1219
- (_internalTextareaRef$ = internalTextareaRef.current) === null || _internalTextareaRef$ === void 0 || _internalTextareaRef$.focus();
1272
+ (_internalTextareaRef$ = internalTextareaRef.current) === null || _internalTextareaRef$ === void 0 || _internalTextareaRef$.focus({ preventScroll: true });
1220
1273
  }
1221
1274
  }, [autoFocus]);
1222
1275
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
@@ -1936,128 +1989,991 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
1936
1989
  };
1937
1990
 
1938
1991
  //#endregion
1939
- //#region src/v2/a2ui/A2UIMessageRenderer.tsx
1940
- let initialized = false;
1941
- function ensureInitialized() {
1942
- if (!initialized) {
1943
- (0, _copilotkit_a2ui_renderer.initializeDefaultCatalog)();
1944
- (0, _copilotkit_a2ui_renderer.injectStyles)();
1945
- initialized = true;
1946
- }
1992
+ //#region src/v2/providers/SandboxFunctionsContext.ts
1993
+ const SandboxFunctionsContext = (0, react.createContext)([]);
1994
+ function useSandboxFunctions() {
1995
+ return (0, react.useContext)(SandboxFunctionsContext);
1947
1996
  }
1948
- function createA2UIMessageRenderer(options) {
1949
- const { theme } = options;
1950
- return {
1951
- activityType: "a2ui-surface",
1952
- content: zod.z.any(),
1953
- render: ({ content, agent }) => {
1954
- ensureInitialized();
1955
- const [operations, setOperations] = (0, react.useState)([]);
1956
- const lastSignatureRef = (0, react.useRef)(null);
1957
- const { copilotkit } = useCopilotKit();
1958
- (0, react.useEffect)(() => {
1959
- if (!content || !Array.isArray(content.operations)) {
1960
- lastSignatureRef.current = null;
1961
- setOperations([]);
1962
- return;
1963
- }
1964
- const incoming = content.operations;
1965
- const signature = stringifyOperations(incoming);
1966
- if (signature && signature === lastSignatureRef.current) return;
1967
- lastSignatureRef.current = signature;
1968
- setOperations(incoming);
1969
- }, [content]);
1970
- const groupedOperations = (0, react.useMemo)(() => {
1971
- const groups = /* @__PURE__ */ new Map();
1972
- for (const operation of operations) {
1973
- var _getOperationSurfaceI;
1974
- const surfaceId = (_getOperationSurfaceI = getOperationSurfaceId(operation)) !== null && _getOperationSurfaceI !== void 0 ? _getOperationSurfaceI : _copilotkit_a2ui_renderer.DEFAULT_SURFACE_ID;
1975
- if (!groups.has(surfaceId)) groups.set(surfaceId, []);
1976
- groups.get(surfaceId).push(operation);
1977
- }
1978
- return groups;
1979
- }, [operations]);
1980
- if (!groupedOperations.size) return null;
1981
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1982
- className: "cpk:flex cpk:min-h-0 cpk:flex-1 cpk:flex-col cpk:gap-6 cpk:overflow-auto cpk:py-6",
1983
- children: Array.from(groupedOperations.entries()).map(([surfaceId, ops]) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ReactSurfaceHost, {
1984
- surfaceId,
1985
- operations: ops,
1986
- theme,
1987
- agent,
1988
- copilotkit
1989
- }, surfaceId))
1990
- });
1991
- }
1992
- };
1997
+
1998
+ //#endregion
1999
+ //#region src/v2/lib/processPartialHtml.ts
2000
+ /**
2001
+ * Extracts all complete `<style>` blocks from the raw HTML.
2002
+ * Returns the concatenated style tags, suitable for injection into `<head>`.
2003
+ */
2004
+ function extractCompleteStyles(html) {
2005
+ const matches = html.match(/<style\b[^>]*>[\s\S]*?<\/style>/gi);
2006
+ return matches ? matches.join("") : "";
1993
2007
  }
1994
2008
  /**
1995
- * Renders a single A2UI surface using the React renderer.
1996
- * Wraps A2UIProvider + A2UIRenderer and bridges actions back to CopilotKit.
2009
+ * Processes raw accumulated HTML for safe preview via innerHTML injection.
2010
+ * Pure function, no DOM dependencies.
2011
+ *
2012
+ * Pipeline (order matters):
2013
+ * 1. Strip incomplete tag at end
2014
+ * 2. Strip complete <style>, <script>, and <head> blocks
2015
+ * 3. Strip incomplete <style>/<script>/<head> blocks
2016
+ * 4. Strip incomplete HTML entities
2017
+ * 5. Extract body content (or use full string if no <body>)
1997
2018
  */
1998
- function ReactSurfaceHost({ surfaceId, operations, theme, agent, copilotkit }) {
1999
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2000
- className: "cpk:flex cpk:w-full cpk:flex-none cpk:flex-col cpk:gap-4",
2001
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_copilotkit_a2ui_renderer.A2UIProvider, {
2002
- onAction: (0, react.useCallback)(async (message) => {
2003
- if (!agent) return;
2004
- try {
2005
- var _copilotkit$propertie;
2006
- console.info("[A2UI] Action dispatched", message.userAction);
2007
- copilotkit.setProperties({
2008
- ...(_copilotkit$propertie = copilotkit.properties) !== null && _copilotkit$propertie !== void 0 ? _copilotkit$propertie : {},
2009
- a2uiAction: message
2010
- });
2011
- await copilotkit.runAgent({ agent });
2012
- } finally {
2013
- if (copilotkit.properties) {
2014
- const { a2uiAction, ...rest } = copilotkit.properties;
2015
- copilotkit.setProperties(rest);
2016
- }
2017
- }
2018
- }, [agent, copilotkit]),
2019
- theme,
2020
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(SurfaceMessageProcessor, {
2021
- surfaceId,
2022
- operations
2023
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_copilotkit_a2ui_renderer.A2UIRenderer, {
2024
- surfaceId,
2025
- className: "cpk:flex cpk:flex-1"
2026
- })]
2027
- })
2028
- });
2019
+ function processPartialHtml(html) {
2020
+ let result = html;
2021
+ result = result.replace(/<[^>]*$/, "");
2022
+ result = result.replace(/<(style|script|head)\b[^>]*>[\s\S]*?<\/\1>/gi, "");
2023
+ result = result.replace(/<(style|script|head)\b[^>]*>[\s\S]*$/gi, "");
2024
+ result = result.replace(/&[a-zA-Z0-9#]*$/, "");
2025
+ const bodyMatch = result.match(/<body[^>]*>([\s\S]*)/i);
2026
+ if (bodyMatch) {
2027
+ result = bodyMatch[1];
2028
+ result = result.replace(/<\/body>[\s\S]*/i, "");
2029
+ }
2030
+ return result;
2029
2031
  }
2032
+
2033
+ //#endregion
2034
+ //#region src/v2/components/OpenGenerativeUIRenderer.tsx
2035
+ const OpenGenerativeUIActivityType = "open-generative-ui";
2036
+ const OpenGenerativeUIContentSchema = zod.z.object({
2037
+ initialHeight: zod.z.number().optional(),
2038
+ generating: zod.z.boolean().optional(),
2039
+ css: zod.z.string().optional(),
2040
+ cssComplete: zod.z.boolean().optional(),
2041
+ html: zod.z.array(zod.z.string()).optional(),
2042
+ htmlComplete: zod.z.boolean().optional(),
2043
+ jsFunctions: zod.z.string().optional(),
2044
+ jsFunctionsComplete: zod.z.boolean().optional(),
2045
+ jsExpressions: zod.z.array(zod.z.string()).optional(),
2046
+ jsExpressionsComplete: zod.z.boolean().optional()
2047
+ });
2030
2048
  /**
2031
- * Processes A2UI operations into the provider's message processor.
2032
- * Must be a child of A2UIProvider to access the actions context.
2049
+ * Schema for the generateSandboxedUi tool call arguments.
2050
+ * Used by the frontend tool renderer to display placeholder messages.
2033
2051
  */
2034
- function SurfaceMessageProcessor({ surfaceId, operations }) {
2035
- const { processMessages } = (0, _copilotkit_a2ui_renderer.useA2UIActions)();
2036
- const lastProcessedRef = (0, react.useRef)("");
2037
- (0, react.useEffect)(() => {
2038
- const key = `${surfaceId}-${JSON.stringify(operations)}`;
2039
- if (key === lastProcessedRef.current) return;
2040
- lastProcessedRef.current = key;
2041
- processMessages(operations);
2052
+ const GenerateSandboxedUiArgsSchema = zod.z.object({
2053
+ initialHeight: zod.z.number().optional(),
2054
+ placeholderMessages: zod.z.array(zod.z.string()).optional(),
2055
+ css: zod.z.string().optional(),
2056
+ html: zod.z.string().optional(),
2057
+ jsFunctions: zod.z.string().optional(),
2058
+ jsExpressions: zod.z.array(zod.z.string()).optional()
2059
+ });
2060
+ const THROTTLE_MS = 1e3;
2061
+ /**
2062
+ * Returns true when the inner component should re-render immediately
2063
+ * (no throttle delay).
2064
+ */
2065
+ function shouldFlushImmediately(prev, next) {
2066
+ var _next$jsExpressions$l, _next$jsExpressions, _prev$jsExpressions$l, _prev$jsExpressions, _next$html, _prev$html;
2067
+ if (next.cssComplete && (!prev || !prev.cssComplete)) return true;
2068
+ if (next.htmlComplete) return true;
2069
+ if (next.generating === false) return true;
2070
+ if (next.jsFunctions && (!prev || !prev.jsFunctions)) return true;
2071
+ if (((_next$jsExpressions$l = (_next$jsExpressions = next.jsExpressions) === null || _next$jsExpressions === void 0 ? void 0 : _next$jsExpressions.length) !== null && _next$jsExpressions$l !== void 0 ? _next$jsExpressions$l : 0) > ((_prev$jsExpressions$l = prev === null || prev === void 0 || (_prev$jsExpressions = prev.jsExpressions) === null || _prev$jsExpressions === void 0 ? void 0 : _prev$jsExpressions.length) !== null && _prev$jsExpressions$l !== void 0 ? _prev$jsExpressions$l : 0)) return true;
2072
+ if (((_next$html = next.html) === null || _next$html === void 0 ? void 0 : _next$html.length) && (!prev || !((_prev$html = prev.html) === null || _prev$html === void 0 ? void 0 : _prev$html.length))) return true;
2073
+ return false;
2074
+ }
2075
+ /**
2076
+ * Outer wrapper — absorbs every parent re-render but only forwards
2077
+ * throttled content snapshots to the memoized inner component.
2078
+ */
2079
+ const OpenGenerativeUIActivityRenderer = function OpenGenerativeUIActivityRenderer({ content }) {
2080
+ const latestContentRef = (0, react.useRef)(content);
2081
+ latestContentRef.current = content;
2082
+ const [throttledContent, setThrottledContent] = (0, react.useState)(content);
2083
+ const throttledContentRef = (0, react.useRef)(throttledContent);
2084
+ const timerRef = (0, react.useRef)(null);
2085
+ if (throttledContentRef.current !== content) {
2086
+ if (shouldFlushImmediately(throttledContentRef.current, content)) {
2087
+ if (timerRef.current !== null) {
2088
+ clearTimeout(timerRef.current);
2089
+ timerRef.current = null;
2090
+ }
2091
+ throttledContentRef.current = content;
2092
+ setThrottledContent(content);
2093
+ }
2094
+ }
2095
+ const flush = (0, react.useCallback)(() => {
2096
+ timerRef.current = null;
2097
+ const latest = latestContentRef.current;
2098
+ throttledContentRef.current = latest;
2099
+ setThrottledContent(latest);
2100
+ }, []);
2101
+ (0, react.useEffect)(() => {
2102
+ if (throttledContentRef.current === content) return;
2103
+ if (timerRef.current === null) timerRef.current = setTimeout(flush, THROTTLE_MS);
2104
+ }, [content, flush]);
2105
+ (0, react.useEffect)(() => {
2106
+ return () => {
2107
+ if (timerRef.current !== null) clearTimeout(timerRef.current);
2108
+ };
2109
+ }, []);
2110
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(OpenGenerativeUIActivityRendererInner, { content: throttledContent });
2111
+ };
2112
+ function ensureHead(html) {
2113
+ if (/<head[\s>]/i.test(html)) return html;
2114
+ return `<head></head>${html}`;
2115
+ }
2116
+ function injectCssIntoHtml(html, css) {
2117
+ const headCloseIdx = html.indexOf("</head>");
2118
+ if (headCloseIdx !== -1) return html.slice(0, headCloseIdx) + `<style>${css}</style>` + html.slice(headCloseIdx);
2119
+ return `<head><style>${css}</style></head>${html}`;
2120
+ }
2121
+ const OpenGenerativeUIActivityRendererInner = react.default.memo(function OpenGenerativeUIActivityRendererInner({ content }) {
2122
+ var _content$initialHeigh, _content$html, _content$html2, _content$jsExpression;
2123
+ const initialHeight = (_content$initialHeigh = content.initialHeight) !== null && _content$initialHeigh !== void 0 ? _content$initialHeigh : 200;
2124
+ const [autoHeight, setAutoHeight] = (0, react.useState)(null);
2125
+ const sandboxFunctions = useSandboxFunctions();
2126
+ const localApi = (0, react.useMemo)(() => {
2127
+ const api = {};
2128
+ for (const fn of sandboxFunctions) api[fn.name] = fn.handler;
2129
+ return api;
2130
+ }, [sandboxFunctions]);
2131
+ const fullHtml = content.htmlComplete && ((_content$html = content.html) === null || _content$html === void 0 ? void 0 : _content$html.length) ? content.html.join("") : void 0;
2132
+ const css = content.cssComplete ? content.css : void 0;
2133
+ const cssReady = !!content.cssComplete;
2134
+ const partialHtml = !content.htmlComplete && ((_content$html2 = content.html) === null || _content$html2 === void 0 ? void 0 : _content$html2.length) ? content.html.join("") : void 0;
2135
+ const previewBody = partialHtml ? processPartialHtml(partialHtml) : void 0;
2136
+ const previewStyles = partialHtml ? extractCompleteStyles(partialHtml) : "";
2137
+ const hasPreview = cssReady && !!(previewBody === null || previewBody === void 0 ? void 0 : previewBody.trim());
2138
+ const hasVisibleSandbox = !!fullHtml || hasPreview;
2139
+ const containerRef = (0, react.useRef)(null);
2140
+ const sandboxRef = (0, react.useRef)(null);
2141
+ const previewSandboxRef = (0, react.useRef)(null);
2142
+ const previewReadyRef = (0, react.useRef)(false);
2143
+ const sandboxReadyRef = (0, react.useRef)(false);
2144
+ const executedIndexRef = (0, react.useRef)(0);
2145
+ const pendingQueueRef = (0, react.useRef)([]);
2146
+ const jsFunctionsInjectedRef = (0, react.useRef)(false);
2147
+ (0, react.useEffect)(() => {
2148
+ const container = containerRef.current;
2149
+ if (!container || fullHtml || !hasPreview || previewSandboxRef.current) return;
2150
+ let cancelled = false;
2151
+ import("@jetbrains/websandbox").then((mod) => {
2152
+ var _mod$default$default, _mod$default;
2153
+ if (cancelled) return;
2154
+ const sandbox = ((_mod$default$default = (_mod$default = mod.default) === null || _mod$default === void 0 ? void 0 : _mod$default.default) !== null && _mod$default$default !== void 0 ? _mod$default$default : mod.default).create({}, {
2155
+ frameContainer: container,
2156
+ frameContent: "<head></head><body></body>",
2157
+ allowAdditionalAttributes: ""
2158
+ });
2159
+ previewSandboxRef.current = sandbox;
2160
+ sandbox.iframe.style.width = "100%";
2161
+ sandbox.iframe.style.height = "100%";
2162
+ sandbox.iframe.style.border = "none";
2163
+ sandbox.iframe.style.backgroundColor = "transparent";
2164
+ sandbox.promise.then(() => {
2165
+ if (cancelled) return;
2166
+ previewReadyRef.current = true;
2167
+ sandbox.run(`
2168
+ var s = document.createElement('style');
2169
+ s.textContent = 'html, body { overflow: hidden !important; }';
2170
+ document.head.appendChild(s);
2171
+ `);
2172
+ const headParts = [];
2173
+ if (css) headParts.push(`<style>${css}</style>`);
2174
+ if (previewStyles) headParts.push(previewStyles);
2175
+ if (headParts.length) sandbox.run(`document.head.innerHTML = ${JSON.stringify(headParts.join(""))}`);
2176
+ if (previewBody) sandbox.run(`document.body.innerHTML = ${JSON.stringify(previewBody)}`);
2177
+ });
2178
+ }).catch((err) => {
2179
+ console.error("[OpenGenerativeUI] Failed to load sandbox module:", err);
2180
+ });
2181
+ return () => {
2182
+ cancelled = true;
2183
+ };
2184
+ }, [hasPreview, fullHtml]);
2185
+ (0, react.useEffect)(() => {
2186
+ if (!previewSandboxRef.current || !previewReadyRef.current) return;
2187
+ const headParts = [];
2188
+ if (css) headParts.push(`<style>${css}</style>`);
2189
+ if (previewStyles) headParts.push(previewStyles);
2190
+ if (headParts.length) previewSandboxRef.current.run(`document.head.innerHTML = ${JSON.stringify(headParts.join(""))}`);
2191
+ if (!previewBody) return;
2192
+ previewSandboxRef.current.run(`document.body.innerHTML = ${JSON.stringify(previewBody)}`);
2193
+ }, [
2194
+ previewBody,
2195
+ previewStyles,
2196
+ css
2197
+ ]);
2198
+ (0, react.useEffect)(() => {
2199
+ const container = containerRef.current;
2200
+ if (!container || !fullHtml) return;
2201
+ if (previewSandboxRef.current) {
2202
+ previewSandboxRef.current.destroy();
2203
+ previewSandboxRef.current = null;
2204
+ previewReadyRef.current = false;
2205
+ }
2206
+ let cancelled = false;
2207
+ executedIndexRef.current = 0;
2208
+ jsFunctionsInjectedRef.current = false;
2209
+ sandboxReadyRef.current = false;
2210
+ pendingQueueRef.current = [];
2211
+ const htmlContent = css ? injectCssIntoHtml(fullHtml, css) : fullHtml;
2212
+ import("@jetbrains/websandbox").then((mod) => {
2213
+ var _mod$default$default2, _mod$default2;
2214
+ if (cancelled) return;
2215
+ const sandbox = ((_mod$default$default2 = (_mod$default2 = mod.default) === null || _mod$default2 === void 0 ? void 0 : _mod$default2.default) !== null && _mod$default$default2 !== void 0 ? _mod$default$default2 : mod.default).create(localApi, {
2216
+ frameContainer: container,
2217
+ frameContent: ensureHead(htmlContent),
2218
+ allowAdditionalAttributes: ""
2219
+ });
2220
+ sandboxRef.current = sandbox;
2221
+ sandbox.iframe.style.width = "100%";
2222
+ sandbox.iframe.style.height = "100%";
2223
+ sandbox.iframe.style.border = "none";
2224
+ sandbox.iframe.style.backgroundColor = "transparent";
2225
+ sandbox.promise.then(() => {
2226
+ if (cancelled) return;
2227
+ sandboxReadyRef.current = true;
2228
+ sandbox.run(`
2229
+ var s = document.createElement('style');
2230
+ s.textContent = 'html, body { overflow: hidden !important; }';
2231
+ document.head.appendChild(s);
2232
+ `);
2233
+ const queue = pendingQueueRef.current;
2234
+ pendingQueueRef.current = [];
2235
+ for (const code of queue) sandbox.run(code);
2236
+ });
2237
+ }).catch((err) => {
2238
+ console.error("[OpenGenerativeUI] Failed to load sandbox module:", err);
2239
+ });
2240
+ return () => {
2241
+ cancelled = true;
2242
+ if (previewSandboxRef.current) {
2243
+ previewSandboxRef.current.destroy();
2244
+ previewSandboxRef.current = null;
2245
+ previewReadyRef.current = false;
2246
+ }
2247
+ if (sandboxRef.current) {
2248
+ sandboxRef.current.destroy();
2249
+ sandboxRef.current = null;
2250
+ }
2251
+ sandboxReadyRef.current = false;
2252
+ setAutoHeight(null);
2253
+ };
2254
+ }, [
2255
+ fullHtml,
2256
+ css,
2257
+ localApi
2258
+ ]);
2259
+ (0, react.useEffect)(() => {
2260
+ if (!content.jsFunctions || jsFunctionsInjectedRef.current) return;
2261
+ jsFunctionsInjectedRef.current = true;
2262
+ const sandbox = sandboxRef.current;
2263
+ if (sandboxReadyRef.current && sandbox) sandbox.run(content.jsFunctions);
2264
+ else pendingQueueRef.current.push(content.jsFunctions);
2265
+ }, [content.jsFunctions]);
2266
+ (0, react.useEffect)(() => {
2267
+ const expressions = content.jsExpressions;
2268
+ if (!expressions || expressions.length === 0) return;
2269
+ const startIndex = executedIndexRef.current;
2270
+ if (startIndex >= expressions.length) return;
2271
+ const newExprs = expressions.slice(startIndex);
2272
+ executedIndexRef.current = expressions.length;
2273
+ const sandbox = sandboxRef.current;
2274
+ if (sandboxReadyRef.current && sandbox) (async () => {
2275
+ for (const expr of newExprs) await sandbox.run(expr);
2276
+ })();
2277
+ else pendingQueueRef.current.push(...newExprs);
2278
+ }, [(_content$jsExpression = content.jsExpressions) === null || _content$jsExpression === void 0 ? void 0 : _content$jsExpression.length]);
2279
+ const generationDone = content.generating === false;
2280
+ (0, react.useEffect)(() => {
2281
+ const sandbox = sandboxRef.current;
2282
+ if (!generationDone || !sandbox) return;
2283
+ let handled = false;
2284
+ const onMessage = (e) => {
2285
+ var _e$data;
2286
+ if (handled) return;
2287
+ if (e.source === sandbox.iframe.contentWindow && ((_e$data = e.data) === null || _e$data === void 0 ? void 0 : _e$data.type) === "__ck_resize") {
2288
+ handled = true;
2289
+ setAutoHeight(e.data.height);
2290
+ window.removeEventListener("message", onMessage);
2291
+ }
2292
+ };
2293
+ window.addEventListener("message", onMessage);
2294
+ const measureOnce = `
2295
+ (function() {
2296
+ var s = document.createElement('style');
2297
+ s.textContent = 'body { height: auto !important; min-height: 0 !important; }';
2298
+ document.head.appendChild(s);
2299
+ var h = document.body.scrollHeight;
2300
+ var cs = getComputedStyle(document.body);
2301
+ h += parseFloat(cs.marginTop) || 0;
2302
+ h += parseFloat(cs.marginBottom) || 0;
2303
+ s.remove();
2304
+ parent.postMessage({ type: "__ck_resize", height: Math.ceil(h) }, "*");
2305
+ })();
2306
+ `;
2307
+ if (sandboxReadyRef.current) sandbox.run(measureOnce);
2308
+ else pendingQueueRef.current.push(measureOnce);
2309
+ return () => {
2310
+ window.removeEventListener("message", onMessage);
2311
+ };
2312
+ }, [generationDone]);
2313
+ const height = autoHeight !== null && autoHeight !== void 0 ? autoHeight : initialHeight;
2314
+ const isGenerating = content.generating !== false;
2315
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2316
+ ref: containerRef,
2317
+ style: {
2318
+ position: "relative",
2319
+ width: "100%",
2320
+ height: `${height}px`,
2321
+ borderRadius: "8px",
2322
+ backgroundColor: hasVisibleSandbox ? "transparent" : "#f5f5f5",
2323
+ border: hasVisibleSandbox ? "none" : "1px solid #e0e0e0",
2324
+ display: hasVisibleSandbox ? "block" : "flex",
2325
+ alignItems: hasVisibleSandbox ? void 0 : "center",
2326
+ justifyContent: hasVisibleSandbox ? void 0 : "center",
2327
+ overflow: "hidden"
2328
+ },
2329
+ children: isGenerating && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2330
+ style: {
2331
+ position: "absolute",
2332
+ inset: 0,
2333
+ zIndex: 10,
2334
+ pointerEvents: "all",
2335
+ backgroundColor: "rgba(255, 255, 255, 0.5)",
2336
+ display: "flex",
2337
+ alignItems: "center",
2338
+ justifyContent: "center"
2339
+ },
2340
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
2341
+ width: "48",
2342
+ height: "48",
2343
+ viewBox: "0 0 24 24",
2344
+ fill: "none",
2345
+ style: { animation: "ck-spin 1s linear infinite" },
2346
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
2347
+ cx: "12",
2348
+ cy: "12",
2349
+ r: "10",
2350
+ stroke: "#e0e0e0",
2351
+ strokeWidth: "3"
2352
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
2353
+ d: "M12 2a10 10 0 0 1 10 10",
2354
+ stroke: "#999",
2355
+ strokeWidth: "3",
2356
+ strokeLinecap: "round"
2357
+ })]
2358
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("style", { children: `@keyframes ck-spin { to { transform: rotate(360deg) } }` })]
2359
+ })
2360
+ });
2361
+ }, (prev, next) => prev.content === next.content);
2362
+ /**
2363
+ * Frontend tool renderer for generateSandboxedUi.
2364
+ * Displays placeholder messages while the UI is being generated.
2365
+ */
2366
+ const OpenGenerativeUIToolRenderer = function OpenGenerativeUIToolRenderer(props) {
2367
+ var _messages$visibleMess;
2368
+ const [visibleMessageIndex, setVisibleMessageIndex] = (0, react.useState)(0);
2369
+ const prevMessageCountRef = (0, react.useRef)(0);
2370
+ const messages = props.args.placeholderMessages;
2371
+ (0, react.useEffect)(() => {
2372
+ if (!messages || messages.length === 0) return;
2373
+ if (messages.length !== prevMessageCountRef.current) {
2374
+ prevMessageCountRef.current = messages.length;
2375
+ setVisibleMessageIndex(messages.length - 1);
2376
+ }
2377
+ if (props.status === _copilotkit_core.ToolCallStatus.Complete) return;
2378
+ const timer = setInterval(() => {
2379
+ setVisibleMessageIndex((i) => (i + 1) % messages.length);
2380
+ }, 5e3);
2381
+ return () => clearInterval(timer);
2382
+ }, [messages === null || messages === void 0 ? void 0 : messages.length, props.status]);
2383
+ if (props.status === _copilotkit_core.ToolCallStatus.Complete) return null;
2384
+ if (!messages || messages.length === 0) return null;
2385
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2386
+ style: {
2387
+ padding: "8px 12px",
2388
+ color: "#999",
2389
+ fontSize: "14px"
2390
+ },
2391
+ children: (_messages$visibleMess = messages[visibleMessageIndex]) !== null && _messages$visibleMess !== void 0 ? _messages$visibleMess : messages[0]
2392
+ });
2393
+ };
2394
+
2395
+ //#endregion
2396
+ //#region src/v2/a2ui/A2UIMessageRenderer.tsx
2397
+ /**
2398
+ * The container key used to wrap A2UI operations for explicit detection.
2399
+ * Must match A2UI_OPERATIONS_KEY in @ag-ui/a2ui-middleware and copilotkit.a2ui (Python).
2400
+ */
2401
+ const A2UI_OPERATIONS_KEY = "a2ui_operations";
2402
+ let initialized = false;
2403
+ function ensureInitialized() {
2404
+ if (!initialized) {
2405
+ (0, _copilotkit_a2ui_renderer.initializeDefaultCatalog)();
2406
+ (0, _copilotkit_a2ui_renderer.injectStyles)();
2407
+ initialized = true;
2408
+ }
2409
+ }
2410
+ function createA2UIMessageRenderer(options) {
2411
+ const { theme, catalog, loadingComponent } = options;
2412
+ return {
2413
+ activityType: "a2ui-surface",
2414
+ content: zod.z.any(),
2415
+ render: ({ content, agent }) => {
2416
+ ensureInitialized();
2417
+ const [operations, setOperations] = (0, react.useState)([]);
2418
+ const { copilotkit } = useCopilotKit();
2419
+ const lastContentRef = (0, react.useRef)(null);
2420
+ (0, react.useEffect)(() => {
2421
+ if (content === lastContentRef.current) return;
2422
+ lastContentRef.current = content;
2423
+ const incoming = content === null || content === void 0 ? void 0 : content[A2UI_OPERATIONS_KEY];
2424
+ if (!content || !Array.isArray(incoming)) {
2425
+ setOperations([]);
2426
+ return;
2427
+ }
2428
+ setOperations(incoming);
2429
+ }, [content]);
2430
+ const groupedOperations = (0, react.useMemo)(() => {
2431
+ const groups = /* @__PURE__ */ new Map();
2432
+ for (const operation of operations) {
2433
+ var _getOperationSurfaceI;
2434
+ const surfaceId = (_getOperationSurfaceI = getOperationSurfaceId(operation)) !== null && _getOperationSurfaceI !== void 0 ? _getOperationSurfaceI : _copilotkit_a2ui_renderer.DEFAULT_SURFACE_ID;
2435
+ if (!groups.has(surfaceId)) groups.set(surfaceId, []);
2436
+ groups.get(surfaceId).push(operation);
2437
+ }
2438
+ return groups;
2439
+ }, [operations]);
2440
+ if (!groupedOperations.size) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(loadingComponent !== null && loadingComponent !== void 0 ? loadingComponent : DefaultA2UILoading, {});
2441
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2442
+ className: "cpk:flex cpk:min-h-0 cpk:flex-1 cpk:flex-col cpk:gap-6 cpk:overflow-auto cpk:py-6",
2443
+ children: Array.from(groupedOperations.entries()).map(([surfaceId, ops]) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ReactSurfaceHost, {
2444
+ surfaceId,
2445
+ operations: ops,
2446
+ theme,
2447
+ agent,
2448
+ copilotkit,
2449
+ catalog
2450
+ }, surfaceId))
2451
+ });
2452
+ }
2453
+ };
2454
+ }
2455
+ /**
2456
+ * Renders a single A2UI surface using the React renderer.
2457
+ * Wraps A2UIProvider + A2UIRenderer and bridges actions back to CopilotKit.
2458
+ */
2459
+ function ReactSurfaceHost({ surfaceId, operations, theme, agent, copilotkit, catalog }) {
2460
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2461
+ className: "cpk:flex cpk:w-full cpk:flex-none cpk:flex-col cpk:gap-4",
2462
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_copilotkit_a2ui_renderer.A2UIProvider, {
2463
+ onAction: (0, react.useCallback)(async (message) => {
2464
+ if (!agent) return;
2465
+ message.userAction;
2466
+ try {
2467
+ var _copilotkit$propertie;
2468
+ copilotkit.setProperties({
2469
+ ...(_copilotkit$propertie = copilotkit.properties) !== null && _copilotkit$propertie !== void 0 ? _copilotkit$propertie : {},
2470
+ a2uiAction: message
2471
+ });
2472
+ await copilotkit.runAgent({ agent });
2473
+ } finally {
2474
+ if (copilotkit.properties) {
2475
+ const { a2uiAction, ...rest } = copilotkit.properties;
2476
+ copilotkit.setProperties(rest);
2477
+ }
2478
+ }
2479
+ }, [agent, copilotkit]),
2480
+ theme,
2481
+ catalog,
2482
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(SurfaceMessageProcessor, {
2483
+ surfaceId,
2484
+ operations
2485
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(A2UISurfaceOrError, { surfaceId })]
2486
+ })
2487
+ });
2488
+ }
2489
+ /**
2490
+ * Renders the A2UI surface, or an error message if processing failed.
2491
+ * Must be a child of A2UIProvider to access the error state.
2492
+ */
2493
+ function A2UISurfaceOrError({ surfaceId }) {
2494
+ const error = (0, _copilotkit_a2ui_renderer.useA2UIError)();
2495
+ if (error) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2496
+ className: "cpk:rounded-lg cpk:border cpk:border-red-200 cpk:bg-red-50 cpk:p-3 cpk:text-sm cpk:text-red-700",
2497
+ children: ["A2UI render error: ", error]
2498
+ });
2499
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_copilotkit_a2ui_renderer.A2UIRenderer, {
2500
+ surfaceId,
2501
+ className: "cpk:flex cpk:flex-1"
2502
+ });
2503
+ }
2504
+ /**
2505
+ * Processes A2UI operations into the provider's message processor.
2506
+ * Must be a child of A2UIProvider to access the actions context.
2507
+ */
2508
+ function SurfaceMessageProcessor({ surfaceId, operations }) {
2509
+ const { processMessages, getSurface } = (0, _copilotkit_a2ui_renderer.useA2UIActions)();
2510
+ const lastHashRef = (0, react.useRef)("");
2511
+ (0, react.useEffect)(() => {
2512
+ const hash = JSON.stringify(operations);
2513
+ if (hash === lastHashRef.current) return;
2514
+ lastHashRef.current = hash;
2515
+ processMessages(getSurface(surfaceId) ? operations.filter((op) => !(op === null || op === void 0 ? void 0 : op.createSurface)) : operations);
2042
2516
  }, [
2043
2517
  processMessages,
2518
+ getSurface,
2044
2519
  surfaceId,
2045
2520
  operations
2046
2521
  ]);
2047
2522
  return null;
2048
2523
  }
2524
+ /**
2525
+ * Default loading component shown while an A2UI surface is generating.
2526
+ * Displays an animated shimmer skeleton.
2527
+ */
2528
+ function DefaultA2UILoading() {
2529
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2530
+ className: "cpk:flex cpk:flex-col cpk:gap-3 cpk:rounded-xl cpk:border cpk:border-gray-100 cpk:bg-gray-50/50 cpk:p-5",
2531
+ style: { minHeight: 120 },
2532
+ children: [
2533
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2534
+ className: "cpk:flex cpk:items-center cpk:gap-2",
2535
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2536
+ className: "cpk:h-3 cpk:w-3 cpk:rounded-full cpk:bg-gray-200",
2537
+ style: { animation: "cpk-a2ui-pulse 1.5s ease-in-out infinite" }
2538
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2539
+ className: "cpk:text-xs cpk:font-medium cpk:text-gray-400",
2540
+ children: "Generating UI..."
2541
+ })]
2542
+ }),
2543
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2544
+ className: "cpk:flex cpk:flex-col cpk:gap-2",
2545
+ children: [
2546
+ .8,
2547
+ .6,
2548
+ .4
2549
+ ].map((width, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2550
+ className: "cpk:h-3 cpk:rounded cpk:bg-gray-200/70",
2551
+ style: {
2552
+ width: `${width * 100}%`,
2553
+ animation: `cpk-a2ui-pulse 1.5s ease-in-out ${i * .15}s infinite`
2554
+ }
2555
+ }, i))
2556
+ }),
2557
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("style", { children: `
2558
+ @keyframes cpk-a2ui-pulse {
2559
+ 0%, 100% { opacity: 0.4; }
2560
+ 50% { opacity: 1; }
2561
+ }
2562
+ ` })
2563
+ ]
2564
+ });
2565
+ }
2049
2566
  function getOperationSurfaceId(operation) {
2050
- var _ref, _ref2, _ref3, _operation$beginRende, _operation$beginRende2, _operation$surfaceUpd, _operation$dataModelU, _operation$deleteSurf;
2567
+ var _ref, _ref2, _ref3, _operation$createSurf, _operation$createSurf2, _operation$updateComp, _operation$updateData, _operation$deleteSurf;
2051
2568
  if (!operation || typeof operation !== "object") return null;
2052
2569
  if (typeof operation.surfaceId === "string") return operation.surfaceId;
2053
- return (_ref = (_ref2 = (_ref3 = (_operation$beginRende = operation === null || operation === void 0 || (_operation$beginRende2 = operation.beginRendering) === null || _operation$beginRende2 === void 0 ? void 0 : _operation$beginRende2.surfaceId) !== null && _operation$beginRende !== void 0 ? _operation$beginRende : operation === null || operation === void 0 || (_operation$surfaceUpd = operation.surfaceUpdate) === null || _operation$surfaceUpd === void 0 ? void 0 : _operation$surfaceUpd.surfaceId) !== null && _ref3 !== void 0 ? _ref3 : operation === null || operation === void 0 || (_operation$dataModelU = operation.dataModelUpdate) === null || _operation$dataModelU === void 0 ? void 0 : _operation$dataModelU.surfaceId) !== null && _ref2 !== void 0 ? _ref2 : operation === null || operation === void 0 || (_operation$deleteSurf = operation.deleteSurface) === null || _operation$deleteSurf === void 0 ? void 0 : _operation$deleteSurf.surfaceId) !== null && _ref !== void 0 ? _ref : null;
2570
+ return (_ref = (_ref2 = (_ref3 = (_operation$createSurf = operation === null || operation === void 0 || (_operation$createSurf2 = operation.createSurface) === null || _operation$createSurf2 === void 0 ? void 0 : _operation$createSurf2.surfaceId) !== null && _operation$createSurf !== void 0 ? _operation$createSurf : operation === null || operation === void 0 || (_operation$updateComp = operation.updateComponents) === null || _operation$updateComp === void 0 ? void 0 : _operation$updateComp.surfaceId) !== null && _ref3 !== void 0 ? _ref3 : operation === null || operation === void 0 || (_operation$updateData = operation.updateDataModel) === null || _operation$updateData === void 0 ? void 0 : _operation$updateData.surfaceId) !== null && _ref2 !== void 0 ? _ref2 : operation === null || operation === void 0 || (_operation$deleteSurf = operation.deleteSurface) === null || _operation$deleteSurf === void 0 ? void 0 : _operation$deleteSurf.surfaceId) !== null && _ref !== void 0 ? _ref : null;
2054
2571
  }
2055
- function stringifyOperations(ops) {
2056
- try {
2057
- return JSON.stringify(ops);
2058
- } catch (error) {
2059
- return null;
2572
+
2573
+ //#endregion
2574
+ //#region src/v2/types/defineToolCallRenderer.ts
2575
+ function defineToolCallRenderer(def) {
2576
+ const argsSchema = def.name === "*" && !def.args ? zod.z.any() : def.args;
2577
+ return {
2578
+ name: def.name,
2579
+ args: argsSchema,
2580
+ render: def.render,
2581
+ ...def.agentId ? { agentId: def.agentId } : {}
2582
+ };
2583
+ }
2584
+
2585
+ //#endregion
2586
+ //#region src/v2/a2ui/A2UIToolCallRenderer.tsx
2587
+ /**
2588
+ * Tool name used by the dynamic A2UI generation secondary LLM.
2589
+ * This renderer is auto-registered when A2UI is enabled.
2590
+ */
2591
+ const RENDER_A2UI_TOOL_NAME = "render_a2ui";
2592
+ /**
2593
+ * Built-in progress indicator for dynamic A2UI generation.
2594
+ * Shows a skeleton wireframe that progressively reveals as tokens stream in.
2595
+ *
2596
+ * Registered automatically when A2UI is enabled. Users can override by
2597
+ * providing their own `useRenderTool({ name: "render_a2ui", ... })`.
2598
+ */
2599
+ function A2UIProgressIndicator({ parameters }) {
2600
+ const lastRef = (0, react.useRef)({
2601
+ time: 0,
2602
+ tokens: 0
2603
+ });
2604
+ const now = Date.now();
2605
+ let { tokens } = lastRef.current;
2606
+ if (now - lastRef.current.time > 200) {
2607
+ const chars = JSON.stringify(parameters !== null && parameters !== void 0 ? parameters : {}).length;
2608
+ tokens = Math.round(chars / 4);
2609
+ lastRef.current = {
2610
+ time: now,
2611
+ tokens
2612
+ };
2060
2613
  }
2614
+ const phase = tokens < 50 ? 0 : tokens < 200 ? 1 : tokens < 400 ? 2 : 3;
2615
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2616
+ style: {
2617
+ margin: "12px 0",
2618
+ maxWidth: 320
2619
+ },
2620
+ children: [
2621
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2622
+ style: {
2623
+ position: "relative",
2624
+ overflow: "hidden",
2625
+ borderRadius: 12,
2626
+ border: "1px solid rgba(228,228,231,0.8)",
2627
+ backgroundColor: "#fff",
2628
+ boxShadow: "0 1px 2px rgba(0,0,0,0.04)",
2629
+ padding: "16px 18px 14px"
2630
+ },
2631
+ children: [
2632
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2633
+ style: {
2634
+ display: "flex",
2635
+ alignItems: "center",
2636
+ gap: 8,
2637
+ marginBottom: 12
2638
+ },
2639
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2640
+ style: {
2641
+ display: "flex",
2642
+ gap: 4
2643
+ },
2644
+ children: [
2645
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Dot, {}),
2646
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Dot, {}),
2647
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Dot, {})
2648
+ ]
2649
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Bar, {
2650
+ w: 64,
2651
+ h: 6,
2652
+ bg: "#e4e4e7",
2653
+ opacity: phase >= 1 ? 1 : .4,
2654
+ transition: "opacity 0.5s"
2655
+ })]
2656
+ }),
2657
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2658
+ style: {
2659
+ display: "grid",
2660
+ gap: 7
2661
+ },
2662
+ children: [
2663
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Row, {
2664
+ show: phase >= 0,
2665
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Bar, {
2666
+ w: 36,
2667
+ h: 7,
2668
+ bg: "rgba(147,197,253,0.7)",
2669
+ anim: 0
2670
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Bar, {
2671
+ w: 80,
2672
+ h: 7,
2673
+ bg: "rgba(219,234,254,0.8)",
2674
+ anim: .2
2675
+ })]
2676
+ }),
2677
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Row, {
2678
+ show: phase >= 0,
2679
+ delay: .1,
2680
+ children: [
2681
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Spacer, {}),
2682
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Dot, {}),
2683
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Bar, {
2684
+ w: 100,
2685
+ h: 7,
2686
+ bg: "rgba(24,24,27,0.2)",
2687
+ anim: .3
2688
+ })
2689
+ ]
2690
+ }),
2691
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Row, {
2692
+ show: phase >= 1,
2693
+ delay: .15,
2694
+ children: [
2695
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Spacer, {}),
2696
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Bar, {
2697
+ w: 48,
2698
+ h: 7,
2699
+ bg: "rgba(24,24,27,0.15)",
2700
+ anim: .1
2701
+ }),
2702
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Bar, {
2703
+ w: 40,
2704
+ h: 7,
2705
+ bg: "rgba(153,246,228,0.6)",
2706
+ anim: .5
2707
+ }),
2708
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Bar, {
2709
+ w: 56,
2710
+ h: 7,
2711
+ bg: "rgba(147,197,253,0.6)",
2712
+ anim: .3
2713
+ })
2714
+ ]
2715
+ }),
2716
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Row, {
2717
+ show: phase >= 1,
2718
+ delay: .2,
2719
+ children: [
2720
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Spacer, {}),
2721
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Dot, {}),
2722
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Bar, {
2723
+ w: 60,
2724
+ h: 7,
2725
+ bg: "rgba(24,24,27,0.15)",
2726
+ anim: .4
2727
+ })
2728
+ ]
2729
+ }),
2730
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Row, {
2731
+ show: phase >= 2,
2732
+ delay: .25,
2733
+ children: [
2734
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Bar, {
2735
+ w: 40,
2736
+ h: 7,
2737
+ bg: "rgba(153,246,228,0.5)",
2738
+ anim: .2
2739
+ }),
2740
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Dot, {}),
2741
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Bar, {
2742
+ w: 48,
2743
+ h: 7,
2744
+ bg: "rgba(24,24,27,0.15)",
2745
+ anim: .6
2746
+ }),
2747
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Bar, {
2748
+ w: 64,
2749
+ h: 7,
2750
+ bg: "rgba(147,197,253,0.5)",
2751
+ anim: .1
2752
+ })
2753
+ ]
2754
+ }),
2755
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Row, {
2756
+ show: phase >= 2,
2757
+ delay: .3,
2758
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Bar, {
2759
+ w: 36,
2760
+ h: 7,
2761
+ bg: "rgba(147,197,253,0.6)",
2762
+ anim: .5
2763
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Bar, {
2764
+ w: 36,
2765
+ h: 7,
2766
+ bg: "rgba(24,24,27,0.12)",
2767
+ anim: .7
2768
+ })]
2769
+ }),
2770
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Row, {
2771
+ show: phase >= 3,
2772
+ delay: .35,
2773
+ children: [
2774
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Dot, {}),
2775
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Bar, {
2776
+ w: 44,
2777
+ h: 7,
2778
+ bg: "rgba(24,24,27,0.18)",
2779
+ anim: .3
2780
+ }),
2781
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Dot, {}),
2782
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Bar, {
2783
+ w: 56,
2784
+ h: 7,
2785
+ bg: "rgba(153,246,228,0.5)",
2786
+ anim: .8
2787
+ }),
2788
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Bar, {
2789
+ w: 48,
2790
+ h: 7,
2791
+ bg: "rgba(147,197,253,0.5)",
2792
+ anim: .4
2793
+ })
2794
+ ]
2795
+ })
2796
+ ]
2797
+ }),
2798
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { style: {
2799
+ pointerEvents: "none",
2800
+ position: "absolute",
2801
+ inset: 0,
2802
+ background: "linear-gradient(105deg, transparent 0%, transparent 40%, rgba(255,255,255,0.6) 50%, transparent 60%, transparent 100%)",
2803
+ backgroundSize: "250% 100%",
2804
+ animation: "cpk-a2ui-sweep 3s ease-in-out infinite"
2805
+ } })
2806
+ ]
2807
+ }),
2808
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2809
+ style: {
2810
+ display: "flex",
2811
+ alignItems: "center",
2812
+ justifyContent: "center",
2813
+ gap: 8,
2814
+ marginTop: 8
2815
+ },
2816
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2817
+ style: {
2818
+ fontSize: 12,
2819
+ color: "#a1a1aa",
2820
+ letterSpacing: "0.025em"
2821
+ },
2822
+ children: "Building interface"
2823
+ }), tokens > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2824
+ style: {
2825
+ fontSize: 11,
2826
+ color: "#d4d4d8",
2827
+ fontVariantNumeric: "tabular-nums"
2828
+ },
2829
+ children: [
2830
+ "~",
2831
+ tokens.toLocaleString(),
2832
+ " tokens"
2833
+ ]
2834
+ })]
2835
+ }),
2836
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("style", { children: `
2837
+ @keyframes cpk-a2ui-fade {
2838
+ 0%, 100% { opacity: 1; }
2839
+ 50% { opacity: 0.5; }
2840
+ }
2841
+ @keyframes cpk-a2ui-sweep {
2842
+ 0% { background-position: 250% 0; }
2843
+ 100% { background-position: -250% 0; }
2844
+ }
2845
+ ` })
2846
+ ]
2847
+ });
2848
+ }
2849
+ function Dot() {
2850
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { style: {
2851
+ width: 7,
2852
+ height: 7,
2853
+ borderRadius: "50%",
2854
+ backgroundColor: "#d4d4d8",
2855
+ flexShrink: 0
2856
+ } });
2857
+ }
2858
+ function Spacer() {
2859
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { style: { width: 12 } });
2860
+ }
2861
+ function Bar({ w, h, bg, anim, opacity, transition }) {
2862
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { style: {
2863
+ width: w,
2864
+ height: h,
2865
+ borderRadius: 9999,
2866
+ backgroundColor: bg,
2867
+ ...anim !== void 0 ? { animation: `cpk-a2ui-fade 2.4s ease-in-out ${anim}s infinite` } : {},
2868
+ ...opacity !== void 0 ? { opacity } : {},
2869
+ ...transition ? { transition } : {}
2870
+ } });
2871
+ }
2872
+ function Row({ children, show, delay = 0 }) {
2873
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2874
+ style: {
2875
+ display: "flex",
2876
+ alignItems: "center",
2877
+ gap: 6,
2878
+ opacity: show ? 1 : 0,
2879
+ transition: `opacity 0.4s ${delay}s`
2880
+ },
2881
+ children
2882
+ });
2883
+ }
2884
+ /**
2885
+ * Registers the built-in `render_a2ui` tool call renderer via the props-based
2886
+ * `setRenderToolCalls` mechanism (not `useRenderTool`).
2887
+ *
2888
+ * This ensures user-registered `useRenderTool({ name: "render_a2ui", ... })`
2889
+ * hooks automatically override the built-in, since the merge logic in
2890
+ * react-core.ts gives hook-based entries priority over prop-based entries.
2891
+ */
2892
+ function A2UIBuiltInToolCallRenderer() {
2893
+ const { copilotkit } = useCopilotKit();
2894
+ (0, react.useEffect)(() => {
2895
+ var _renderToolCalls;
2896
+ const renderer = defineToolCallRenderer({
2897
+ name: RENDER_A2UI_TOOL_NAME,
2898
+ args: zod.z.any(),
2899
+ render: ({ status, args: parameters }) => {
2900
+ if (status === "complete") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, {});
2901
+ const params = parameters;
2902
+ const items = params === null || params === void 0 ? void 0 : params.items;
2903
+ if (Array.isArray(items) && items.length > 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, {});
2904
+ const components = params === null || params === void 0 ? void 0 : params.components;
2905
+ if (Array.isArray(components) && components.length > 2) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, {});
2906
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(A2UIProgressIndicator, { parameters });
2907
+ }
2908
+ });
2909
+ const existing = (_renderToolCalls = copilotkit._renderToolCalls) !== null && _renderToolCalls !== void 0 ? _renderToolCalls : [];
2910
+ copilotkit.setRenderToolCalls([...existing.filter((rc) => rc.name !== RENDER_A2UI_TOOL_NAME), renderer]);
2911
+ }, [copilotkit]);
2912
+ return null;
2913
+ }
2914
+
2915
+ //#endregion
2916
+ //#region src/v2/hooks/use-agent-context.tsx
2917
+ function useAgentContext(context) {
2918
+ const { description, value } = context;
2919
+ const { copilotkit } = useCopilotKit();
2920
+ const stringValue = (0, react.useMemo)(() => {
2921
+ if (typeof value === "string") return value;
2922
+ return JSON.stringify(value);
2923
+ }, [value]);
2924
+ (0, react.useLayoutEffect)(() => {
2925
+ if (!copilotkit) return;
2926
+ const id = copilotkit.addContext({
2927
+ description,
2928
+ value: stringValue
2929
+ });
2930
+ return () => {
2931
+ copilotkit.removeContext(id);
2932
+ };
2933
+ }, [
2934
+ description,
2935
+ stringValue,
2936
+ copilotkit
2937
+ ]);
2938
+ }
2939
+
2940
+ //#endregion
2941
+ //#region src/v2/a2ui/A2UICatalogContext.tsx
2942
+ /**
2943
+ * Renders agent context describing the available A2UI catalog and custom components.
2944
+ * Only mount this component when A2UI is enabled.
2945
+ *
2946
+ * When `includeSchema` is true, the full component schemas (JSON Schema) are also
2947
+ * sent as context using the same description key as the A2UI middleware, so the
2948
+ * middleware can optionally overwrite it with a server-side schema.
2949
+ */
2950
+ function A2UICatalogContext({ catalog, includeSchema }) {
2951
+ useAgentContext({
2952
+ description: "A2UI catalog capabilities: available catalog IDs and custom component definitions the client can render.",
2953
+ value: (0, _copilotkit_a2ui_renderer.buildCatalogContextValue)(catalog)
2954
+ });
2955
+ const { copilotkit } = useCopilotKit();
2956
+ const schemaValue = (0, react.useMemo)(() => includeSchema !== false ? JSON.stringify((0, _copilotkit_a2ui_renderer.extractCatalogComponentSchemas)(catalog)) : null, [catalog, includeSchema]);
2957
+ (0, react.useLayoutEffect)(() => {
2958
+ if (!copilotkit || !schemaValue) return;
2959
+ const ids = [];
2960
+ ids.push(copilotkit.addContext({
2961
+ description: _copilotkit_a2ui_renderer.A2UI_SCHEMA_CONTEXT_DESCRIPTION,
2962
+ value: schemaValue
2963
+ }));
2964
+ ids.push(copilotkit.addContext({
2965
+ description: "A2UI generation guidelines — protocol rules, tool arguments, path rules, data model format, and form/two-way-binding instructions.",
2966
+ value: _copilotkit_shared.A2UI_DEFAULT_GENERATION_GUIDELINES
2967
+ }));
2968
+ ids.push(copilotkit.addContext({
2969
+ description: "A2UI design guidelines — visual design rules, component hierarchy tips, and action handler patterns.",
2970
+ value: _copilotkit_shared.A2UI_DEFAULT_DESIGN_GUIDELINES
2971
+ }));
2972
+ return () => {
2973
+ for (const id of ids) copilotkit.removeContext(id);
2974
+ };
2975
+ }, [copilotkit, schemaValue]);
2976
+ return null;
2061
2977
  }
2062
2978
 
2063
2979
  //#endregion
@@ -2167,6 +3083,17 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
2167
3083
  //#region src/v2/providers/CopilotKitProvider.tsx
2168
3084
  const HEADER_NAME = "X-CopilotCloud-Public-Api-Key";
2169
3085
  const COPILOT_CLOUD_CHAT_URL$1 = "https://api.cloud.copilotkit.ai/copilotkit/v1";
3086
+ const DEFAULT_DESIGN_SKILL = `When generating UI with generateSandboxedUi, follow these design principles inspired by shadcn/ui:
3087
+
3088
+ - Use a minimal, flat aesthetic. Avoid drop shadows and gradients — rely on subtle borders (1px solid, light gray like #e5e7eb) to define surfaces.
3089
+ - Neutral base palette: white backgrounds, zinc/slate gray text (#09090b for headings, #71717a for secondary text). One accent color for interactive elements.
3090
+ - Use system font stacks (system-ui, -apple-system, sans-serif) at readable sizes (14px body, 600 weight for headings). Tight line-heights.
3091
+ - Small, consistent border-radius (6–8px). Cards and containers use border, not shadow, for separation.
3092
+ - Buttons: solid fill for primary (dark bg, white text), outline for secondary (border + transparent bg). Subtle hover state (slight opacity or background shift).
3093
+ - Use CSS Grid or Flexbox for layout. Ensure the UI looks good at any width.
3094
+ - Minimal transitions (150ms) for hover/focus states only. No decorative animations.
3095
+ - Keep the UI focused and dense — avoid excessive padding. Use compact spacing (8–12px gaps, 10–14px padding in controls).`;
3096
+ const GENERATE_SANDBOXED_UI_DESCRIPTION = "Generate sandboxed UI. IMPORTANT: The generated code runs in a sandboxed iframe WITHOUT same-origin access. Do NOT use localStorage, sessionStorage, document.cookie, IndexedDB, or fetch/XMLHttpRequest to same-origin URLs. To communicate with the host application, use Websandbox.connection.remote.<functionName>(args) which returns a Promise.\n\nYou CAN use external libraries from CDNs by including <script> or <link> tags in the HTML <head> (e.g., Chart.js, D3, Three.js, x-data-spreadsheet, etc.). CDN resources load normally inside the sandbox.\n\nPARAMETER ORDER IS CRITICAL — generate parameters in exactly this order:\n1. initialHeight + placeholderMessages (shown to user while generating)\n2. css (all styles FIRST — the user sees a placeholder until CSS is complete)\n3. html (streams in live — the user watches the UI build as HTML is generated)\n4. jsFunctions (reusable helper functions)\n5. jsExpressions (applied one-by-one — the user sees each expression take effect)";
2170
3097
  const CopilotKitContext = (0, react.createContext)({
2171
3098
  copilotkit: null,
2172
3099
  executingToolCallIds: /* @__PURE__ */ new Set()
@@ -2182,9 +3109,12 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
2182
3109
  }, [value, warningMessage]);
2183
3110
  return value;
2184
3111
  }
2185
- const CopilotKitProvider = ({ children, runtimeUrl, headers = {}, credentials, publicApiKey, publicLicenseKey, licenseToken, properties = {}, agents__unsafe_dev_only: agents = {}, selfManagedAgents = {}, renderToolCalls, renderActivityMessages, renderCustomMessages, frontendTools, humanInTheLoop, showDevConsole = false, useSingleEndpoint = false, onError, a2ui }) => {
3112
+ const CopilotKitProvider = ({ children, runtimeUrl, headers = {}, credentials, publicApiKey, publicLicenseKey, licenseToken, properties = {}, agents__unsafe_dev_only: agents = {}, selfManagedAgents = {}, renderToolCalls, renderActivityMessages, renderCustomMessages, frontendTools, humanInTheLoop, openGenerativeUI, showDevConsole = false, useSingleEndpoint, onError, a2ui, defaultThrottleMs, inspectorDefaultAnchor }) => {
3113
+ var _openGenerativeUI$des;
2186
3114
  const [shouldRenderInspector, setShouldRenderInspector] = (0, react.useState)(false);
2187
3115
  const [runtimeA2UIEnabled, setRuntimeA2UIEnabled] = (0, react.useState)(false);
3116
+ const [runtimeOpenGenUIEnabled, setRuntimeOpenGenUIEnabled] = (0, react.useState)(false);
3117
+ const openGenUIActive = runtimeOpenGenUIEnabled || !!openGenerativeUI;
2188
3118
  const [runtimeLicenseStatus, setRuntimeLicenseStatus] = (0, react.useState)(void 0);
2189
3119
  (0, react.useEffect)(() => {
2190
3120
  if (typeof window === "undefined") return;
@@ -2213,12 +3143,25 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
2213
3143
  content: MCPAppsActivityContentSchema,
2214
3144
  render: MCPAppsActivityRenderer
2215
3145
  }];
3146
+ if (openGenUIActive) renderers.push({
3147
+ activityType: OpenGenerativeUIActivityType,
3148
+ content: OpenGenerativeUIContentSchema,
3149
+ render: OpenGenerativeUIActivityRenderer
3150
+ });
2216
3151
  if (runtimeA2UIEnabled) {
2217
3152
  var _a2ui$theme;
2218
- renderers.unshift(createA2UIMessageRenderer({ theme: (_a2ui$theme = a2ui === null || a2ui === void 0 ? void 0 : a2ui.theme) !== null && _a2ui$theme !== void 0 ? _a2ui$theme : _copilotkit_a2ui_renderer.viewerTheme }));
3153
+ renderers.unshift(createA2UIMessageRenderer({
3154
+ theme: (_a2ui$theme = a2ui === null || a2ui === void 0 ? void 0 : a2ui.theme) !== null && _a2ui$theme !== void 0 ? _a2ui$theme : _copilotkit_a2ui_renderer.viewerTheme,
3155
+ catalog: a2ui === null || a2ui === void 0 ? void 0 : a2ui.catalog,
3156
+ loadingComponent: a2ui === null || a2ui === void 0 ? void 0 : a2ui.loadingComponent
3157
+ }));
2219
3158
  }
2220
3159
  return renderers;
2221
- }, [runtimeA2UIEnabled, a2ui]);
3160
+ }, [
3161
+ runtimeA2UIEnabled,
3162
+ openGenUIActive,
3163
+ a2ui
3164
+ ]);
2222
3165
  const allActivityRenderers = (0, react.useMemo)(() => {
2223
3166
  return [...renderActivityMessagesList, ...builtInActivityRenderers];
2224
3167
  }, [renderActivityMessagesList, builtInActivityRenderers]);
@@ -2244,6 +3187,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
2244
3187
  const chatApiEndpoint = runtimeUrl !== null && runtimeUrl !== void 0 ? runtimeUrl : resolvedPublicKey ? COPILOT_CLOUD_CHAT_URL$1 : void 0;
2245
3188
  const frontendToolsList = useStableArrayProp(frontendTools, "frontendTools must be a stable array. If you want to dynamically add or remove tools, use `useFrontendTool` instead.");
2246
3189
  const humanInTheLoopList = useStableArrayProp(humanInTheLoop, "humanInTheLoop must be a stable array. If you want to dynamically add or remove human-in-the-loop tools, use `useHumanInTheLoop` instead.");
3190
+ const sandboxFunctionsList = useStableArrayProp(openGenerativeUI === null || openGenerativeUI === void 0 ? void 0 : openGenerativeUI.sandboxFunctions, "openGenerativeUI.sandboxFunctions must be a stable array.");
2247
3191
  const processedHumanInTheLoopTools = (0, react.useMemo)(() => {
2248
3192
  const processedTools = [];
2249
3193
  const processedRenderToolCalls = [];
@@ -2274,15 +3218,31 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
2274
3218
  renderToolCalls: processedRenderToolCalls
2275
3219
  };
2276
3220
  }, [humanInTheLoopList]);
3221
+ const builtInFrontendTools = (0, react.useMemo)(() => {
3222
+ if (!openGenUIActive) return [];
3223
+ return [{
3224
+ name: "generateSandboxedUi",
3225
+ description: GENERATE_SANDBOXED_UI_DESCRIPTION,
3226
+ parameters: GenerateSandboxedUiArgsSchema,
3227
+ handler: async () => "UI generated",
3228
+ followUp: true,
3229
+ render: OpenGenerativeUIToolRenderer
3230
+ }];
3231
+ }, [openGenUIActive]);
2277
3232
  const allTools = (0, react.useMemo)(() => {
2278
3233
  const tools = [];
2279
3234
  tools.push(...frontendToolsList);
3235
+ tools.push(...builtInFrontendTools);
2280
3236
  tools.push(...processedHumanInTheLoopTools.tools);
2281
3237
  return tools;
2282
- }, [frontendToolsList, processedHumanInTheLoopTools]);
3238
+ }, [
3239
+ frontendToolsList,
3240
+ builtInFrontendTools,
3241
+ processedHumanInTheLoopTools
3242
+ ]);
2283
3243
  const allRenderToolCalls = (0, react.useMemo)(() => {
2284
3244
  const combined = [...renderToolCallsList];
2285
- frontendToolsList.forEach((tool) => {
3245
+ [...frontendToolsList, ...builtInFrontendTools].forEach((tool) => {
2286
3246
  if (tool.render) {
2287
3247
  const args = tool.parameters || (tool.name === "*" ? zod.z.any() : void 0);
2288
3248
  if (args) combined.push({
@@ -2297,25 +3257,31 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
2297
3257
  }, [
2298
3258
  renderToolCallsList,
2299
3259
  frontendToolsList,
3260
+ builtInFrontendTools,
2300
3261
  processedHumanInTheLoopTools
2301
3262
  ]);
2302
3263
  const copilotkitRef = (0, react.useRef)(null);
2303
- if (copilotkitRef.current === null) copilotkitRef.current = new CopilotKitCoreReact({
2304
- runtimeUrl: chatApiEndpoint,
2305
- runtimeTransport: useSingleEndpoint ? "single" : "rest",
2306
- headers: mergedHeaders,
2307
- credentials,
2308
- properties,
2309
- agents__unsafe_dev_only: mergedAgents,
2310
- tools: allTools,
2311
- renderToolCalls: allRenderToolCalls,
2312
- renderActivityMessages: allActivityRenderers,
2313
- renderCustomMessages: renderCustomMessagesList
2314
- });
3264
+ if (copilotkitRef.current === null) {
3265
+ copilotkitRef.current = new CopilotKitCoreReact({
3266
+ runtimeUrl: chatApiEndpoint,
3267
+ runtimeTransport: useSingleEndpoint === true ? "single" : useSingleEndpoint === false ? "rest" : "auto",
3268
+ headers: mergedHeaders,
3269
+ credentials,
3270
+ properties,
3271
+ agents__unsafe_dev_only: mergedAgents,
3272
+ tools: allTools,
3273
+ renderToolCalls: allRenderToolCalls,
3274
+ renderActivityMessages: allActivityRenderers,
3275
+ renderCustomMessages: renderCustomMessagesList
3276
+ });
3277
+ if (defaultThrottleMs !== void 0) copilotkitRef.current.setDefaultThrottleMs(defaultThrottleMs);
3278
+ }
2315
3279
  const copilotkit = copilotkitRef.current;
2316
3280
  (0, react.useEffect)(() => {
3281
+ setRuntimeA2UIEnabled(copilotkit.a2uiEnabled);
2317
3282
  const subscription = copilotkit.subscribe({ onRuntimeConnectionStatusChanged: () => {
2318
3283
  setRuntimeA2UIEnabled(copilotkit.a2uiEnabled);
3284
+ setRuntimeOpenGenUIEnabled(copilotkit.openGenerativeUIEnabled);
2319
3285
  setRuntimeLicenseStatus(copilotkit.licenseStatus);
2320
3286
  } });
2321
3287
  return () => {
@@ -2375,7 +3341,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
2375
3341
  }, [copilotkit]);
2376
3342
  (0, react.useEffect)(() => {
2377
3343
  copilotkit.setRuntimeUrl(chatApiEndpoint);
2378
- copilotkit.setRuntimeTransport(useSingleEndpoint ? "single" : "rest");
3344
+ copilotkit.setRuntimeTransport(useSingleEndpoint === true ? "single" : useSingleEndpoint === false ? "rest" : "auto");
2379
3345
  copilotkit.setHeaders(mergedHeaders);
2380
3346
  copilotkit.setCredentials(credentials);
2381
3347
  copilotkit.setProperties(properties);
@@ -2409,23 +3375,75 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
2409
3375
  (0, react.useEffect)(() => {
2410
3376
  didMountRef.current = true;
2411
3377
  }, []);
3378
+ (0, react.useEffect)(() => {
3379
+ 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.`);
3380
+ copilotkit.setDefaultThrottleMs(defaultThrottleMs);
3381
+ }, [copilotkit, defaultThrottleMs]);
3382
+ const designSkill = (_openGenerativeUI$des = openGenerativeUI === null || openGenerativeUI === void 0 ? void 0 : openGenerativeUI.designSkill) !== null && _openGenerativeUI$des !== void 0 ? _openGenerativeUI$des : DEFAULT_DESIGN_SKILL;
3383
+ (0, react.useLayoutEffect)(() => {
3384
+ if (!copilotkit || !openGenUIActive) return;
3385
+ const id = copilotkit.addContext({
3386
+ description: "Design guidelines for the generateSandboxedUi tool. Follow these when building UI.",
3387
+ value: designSkill
3388
+ });
3389
+ return () => {
3390
+ copilotkit.removeContext(id);
3391
+ };
3392
+ }, [
3393
+ copilotkit,
3394
+ designSkill,
3395
+ openGenUIActive
3396
+ ]);
3397
+ const sandboxFunctionsDescriptors = (0, react.useMemo)(() => {
3398
+ if (sandboxFunctionsList.length === 0) return null;
3399
+ return JSON.stringify(sandboxFunctionsList.map((fn) => ({
3400
+ name: fn.name,
3401
+ description: fn.description,
3402
+ parameters: (0, _copilotkit_shared.schemaToJsonSchema)(fn.parameters, { zodToJsonSchema: zod_to_json_schema.zodToJsonSchema })
3403
+ })));
3404
+ }, [sandboxFunctionsList]);
3405
+ (0, react.useLayoutEffect)(() => {
3406
+ if (!copilotkit || !sandboxFunctionsDescriptors || !openGenUIActive) return;
3407
+ const id = copilotkit.addContext({
3408
+ description: "Sandbox functions available in generated sandboxed UI code. Call via: await Websandbox.connection.remote.<functionName>(args)",
3409
+ value: sandboxFunctionsDescriptors
3410
+ });
3411
+ return () => {
3412
+ copilotkit.removeContext(id);
3413
+ };
3414
+ }, [
3415
+ copilotkit,
3416
+ sandboxFunctionsDescriptors,
3417
+ openGenUIActive
3418
+ ]);
2412
3419
  const contextValue = (0, react.useMemo)(() => ({
2413
3420
  copilotkit,
2414
3421
  executingToolCallIds
2415
3422
  }), [copilotkit, executingToolCallIds]);
2416
3423
  const licenseContextValue = (0, react.useMemo)(() => (0, _copilotkit_shared.createLicenseContextValue)(null), []);
2417
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopilotKitContext.Provider, {
2418
- value: contextValue,
2419
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(LicenseContext.Provider, {
2420
- value: licenseContextValue,
2421
- children: [
2422
- children,
2423
- shouldRenderInspector ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopilotKitInspector, { core: copilotkit }) : null,
2424
- runtimeLicenseStatus === "none" && !resolvedPublicKey && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LicenseWarningBanner, { type: "no_license" }),
2425
- runtimeLicenseStatus === "expired" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LicenseWarningBanner, { type: "expired" }),
2426
- runtimeLicenseStatus === "invalid" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LicenseWarningBanner, { type: "invalid" }),
2427
- runtimeLicenseStatus === "expiring" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LicenseWarningBanner, { type: "expiring" })
2428
- ]
3424
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SandboxFunctionsContext.Provider, {
3425
+ value: sandboxFunctionsList,
3426
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopilotKitContext.Provider, {
3427
+ value: contextValue,
3428
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(LicenseContext.Provider, {
3429
+ value: licenseContextValue,
3430
+ children: [
3431
+ runtimeA2UIEnabled && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(A2UIBuiltInToolCallRenderer, {}),
3432
+ runtimeA2UIEnabled && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(A2UICatalogContext, {
3433
+ catalog: a2ui === null || a2ui === void 0 ? void 0 : a2ui.catalog,
3434
+ includeSchema: a2ui === null || a2ui === void 0 ? void 0 : a2ui.includeSchema
3435
+ }),
3436
+ children,
3437
+ shouldRenderInspector ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopilotKitInspector, {
3438
+ core: copilotkit,
3439
+ defaultAnchor: inspectorDefaultAnchor
3440
+ }) : null,
3441
+ runtimeLicenseStatus === "none" && !resolvedPublicKey && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LicenseWarningBanner, { type: "no_license" }),
3442
+ runtimeLicenseStatus === "expired" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LicenseWarningBanner, { type: "expired" }),
3443
+ runtimeLicenseStatus === "invalid" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LicenseWarningBanner, { type: "invalid" }),
3444
+ runtimeLicenseStatus === "expiring" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LicenseWarningBanner, { type: "expiring" })
3445
+ ]
3446
+ })
2429
3447
  })
2430
3448
  });
2431
3449
  };
@@ -2508,10 +3526,197 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
2508
3526
  isExecuting: executingToolCallIds.has(toolCall.id)
2509
3527
  }, toolCall.id);
2510
3528
  }, [
2511
- renderToolCalls,
2512
- executingToolCallIds,
2513
- agentId
3529
+ renderToolCalls,
3530
+ executingToolCallIds,
3531
+ agentId
3532
+ ]);
3533
+ }
3534
+
3535
+ //#endregion
3536
+ //#region src/v2/hooks/use-agent.tsx
3537
+ let UseAgentUpdate = /* @__PURE__ */ function(UseAgentUpdate) {
3538
+ UseAgentUpdate["OnMessagesChanged"] = "OnMessagesChanged";
3539
+ UseAgentUpdate["OnStateChanged"] = "OnStateChanged";
3540
+ UseAgentUpdate["OnRunStatusChanged"] = "OnRunStatusChanged";
3541
+ return UseAgentUpdate;
3542
+ }({});
3543
+ const ALL_UPDATES = [
3544
+ UseAgentUpdate.OnMessagesChanged,
3545
+ UseAgentUpdate.OnStateChanged,
3546
+ UseAgentUpdate.OnRunStatusChanged
3547
+ ];
3548
+ /**
3549
+ * Clone a registry agent for per-thread isolation.
3550
+ * Copies agent configuration (transport, headers, etc.) but resets conversation
3551
+ * state (messages, threadId, state) so each thread starts fresh.
3552
+ */
3553
+ function cloneForThread(source, threadId, headers) {
3554
+ const clone = source.clone();
3555
+ if (clone === source) throw new Error(`useAgent: ${source.constructor.name}.clone() returned the same instance. clone() must return a new, independent object.`);
3556
+ clone.threadId = threadId;
3557
+ clone.setMessages([]);
3558
+ clone.setState({});
3559
+ if (clone instanceof _ag_ui_client.HttpAgent) clone.headers = { ...headers };
3560
+ return clone;
3561
+ }
3562
+ /**
3563
+ * Module-level WeakMap: registryAgent → (threadId → clone).
3564
+ * Shared across all useAgent() calls so that every component using the same
3565
+ * (agentId, threadId) pair receives the same agent instance. Using WeakMap
3566
+ * ensures the clone map is garbage-collected when the registry agent is
3567
+ * replaced (e.g. after reconnect or hot-reload).
3568
+ */
3569
+ const globalThreadCloneMap = /* @__PURE__ */ new WeakMap();
3570
+ /**
3571
+ * Look up an existing per-thread clone without creating one.
3572
+ * Returns undefined when no clone has been created yet for this pair.
3573
+ */
3574
+ function getThreadClone(registryAgent, threadId) {
3575
+ var _globalThreadCloneMap;
3576
+ if (!registryAgent || !threadId) return void 0;
3577
+ return (_globalThreadCloneMap = globalThreadCloneMap.get(registryAgent)) === null || _globalThreadCloneMap === void 0 ? void 0 : _globalThreadCloneMap.get(threadId);
3578
+ }
3579
+ function getOrCreateThreadClone(existing, threadId, headers) {
3580
+ let byThread = globalThreadCloneMap.get(existing);
3581
+ if (!byThread) {
3582
+ byThread = /* @__PURE__ */ new Map();
3583
+ globalThreadCloneMap.set(existing, byThread);
3584
+ }
3585
+ const cached = byThread.get(threadId);
3586
+ if (cached) return cached;
3587
+ const clone = cloneForThread(existing, threadId, headers);
3588
+ byThread.set(threadId, clone);
3589
+ return clone;
3590
+ }
3591
+ function useAgent({ agentId, threadId, updates, throttleMs } = {}) {
3592
+ var _agentId, _threadId;
3593
+ (_agentId = agentId) !== null && _agentId !== void 0 || (agentId = _copilotkit_shared.DEFAULT_AGENT_ID);
3594
+ const { copilotkit } = useCopilotKit();
3595
+ const providerThrottleMs = copilotkit.defaultThrottleMs;
3596
+ const chatConfig = useCopilotChatConfiguration();
3597
+ (_threadId = threadId) !== null && _threadId !== void 0 || (threadId = chatConfig === null || chatConfig === void 0 ? void 0 : chatConfig.threadId);
3598
+ const effectiveThrottleMs = (0, react.useMemo)(() => {
3599
+ var _ref;
3600
+ const resolved = (_ref = throttleMs !== null && throttleMs !== void 0 ? throttleMs : providerThrottleMs) !== null && _ref !== void 0 ? _ref : 0;
3601
+ if (!Number.isFinite(resolved) || resolved < 0) {
3602
+ const source = throttleMs !== void 0 ? "hook-level throttleMs" : "provider-level defaultThrottleMs";
3603
+ console.error(`useAgent: ${source} must be a non-negative finite number, got ${resolved}. Falling back to unthrottled.`);
3604
+ return 0;
3605
+ }
3606
+ return resolved;
3607
+ }, [throttleMs, providerThrottleMs]);
3608
+ const [, forceUpdate] = (0, react.useReducer)((x) => x + 1, 0);
3609
+ const updateFlags = (0, react.useMemo)(() => updates !== null && updates !== void 0 ? updates : ALL_UPDATES, [JSON.stringify(updates)]);
3610
+ const provisionalAgentCache = (0, react.useRef)(/* @__PURE__ */ new Map());
3611
+ const agent = (0, react.useMemo)(() => {
3612
+ var _copilotkit$agents;
3613
+ const cacheKey = threadId ? `${agentId}:${threadId}` : agentId;
3614
+ const existing = copilotkit.getAgent(agentId);
3615
+ if (existing) {
3616
+ provisionalAgentCache.current.delete(cacheKey);
3617
+ provisionalAgentCache.current.delete(agentId);
3618
+ if (!threadId) return existing;
3619
+ return getOrCreateThreadClone(existing, threadId, copilotkit.headers);
3620
+ }
3621
+ const isRuntimeConfigured = copilotkit.runtimeUrl !== void 0;
3622
+ const status = copilotkit.runtimeConnectionStatus;
3623
+ if (isRuntimeConfigured && (status === _copilotkit_core.CopilotKitCoreRuntimeConnectionStatus.Disconnected || status === _copilotkit_core.CopilotKitCoreRuntimeConnectionStatus.Connecting)) {
3624
+ const cached = provisionalAgentCache.current.get(cacheKey);
3625
+ if (cached) {
3626
+ cached.headers = { ...copilotkit.headers };
3627
+ return cached;
3628
+ }
3629
+ const provisional = new _copilotkit_core.ProxiedCopilotRuntimeAgent({
3630
+ runtimeUrl: copilotkit.runtimeUrl,
3631
+ agentId,
3632
+ transport: copilotkit.runtimeTransport,
3633
+ runtimeMode: "pending"
3634
+ });
3635
+ provisional.headers = { ...copilotkit.headers };
3636
+ if (threadId) provisional.threadId = threadId;
3637
+ provisionalAgentCache.current.set(cacheKey, provisional);
3638
+ return provisional;
3639
+ }
3640
+ if (isRuntimeConfigured && status === _copilotkit_core.CopilotKitCoreRuntimeConnectionStatus.Error) {
3641
+ const cached = provisionalAgentCache.current.get(cacheKey);
3642
+ if (cached) {
3643
+ cached.headers = { ...copilotkit.headers };
3644
+ return cached;
3645
+ }
3646
+ const provisional = new _copilotkit_core.ProxiedCopilotRuntimeAgent({
3647
+ runtimeUrl: copilotkit.runtimeUrl,
3648
+ agentId,
3649
+ transport: copilotkit.runtimeTransport,
3650
+ runtimeMode: "pending"
3651
+ });
3652
+ provisional.headers = { ...copilotkit.headers };
3653
+ if (threadId) provisional.threadId = threadId;
3654
+ provisionalAgentCache.current.set(cacheKey, provisional);
3655
+ return provisional;
3656
+ }
3657
+ const knownAgents = Object.keys((_copilotkit$agents = copilotkit.agents) !== null && _copilotkit$agents !== void 0 ? _copilotkit$agents : {});
3658
+ const runtimePart = isRuntimeConfigured ? `runtimeUrl=${copilotkit.runtimeUrl}` : "no runtimeUrl";
3659
+ throw new Error(`useAgent: Agent '${agentId}' not found after runtime sync (${runtimePart}). ` + (knownAgents.length ? `Known agents: [${knownAgents.join(", ")}]` : "No agents registered.") + " Verify your runtime /info and/or agents__unsafe_dev_only.");
3660
+ }, [
3661
+ agentId,
3662
+ threadId,
3663
+ copilotkit.agents,
3664
+ copilotkit.runtimeConnectionStatus,
3665
+ copilotkit.runtimeUrl,
3666
+ copilotkit.runtimeTransport,
3667
+ JSON.stringify(copilotkit.headers)
3668
+ ]);
3669
+ (0, react.useEffect)(() => {
3670
+ if (updateFlags.length === 0) return;
3671
+ const handlers = {};
3672
+ let timerId = null;
3673
+ let active = true;
3674
+ if (updateFlags.includes(UseAgentUpdate.OnMessagesChanged)) {
3675
+ const ms = effectiveThrottleMs;
3676
+ if (ms > 0) {
3677
+ let throttleActive = false;
3678
+ let pending = false;
3679
+ const throttledNotify = () => {
3680
+ if (!active) return;
3681
+ if (!throttleActive) {
3682
+ throttleActive = true;
3683
+ pending = false;
3684
+ forceUpdate();
3685
+ timerId = setTimeout(function trailingEdge() {
3686
+ timerId = null;
3687
+ if (active && pending) {
3688
+ pending = false;
3689
+ forceUpdate();
3690
+ timerId = setTimeout(trailingEdge, ms);
3691
+ } else throttleActive = false;
3692
+ }, ms);
3693
+ } else pending = true;
3694
+ };
3695
+ handlers.onMessagesChanged = throttledNotify;
3696
+ } else handlers.onMessagesChanged = forceUpdate;
3697
+ }
3698
+ if (updateFlags.includes(UseAgentUpdate.OnStateChanged)) handlers.onStateChanged = forceUpdate;
3699
+ if (updateFlags.includes(UseAgentUpdate.OnRunStatusChanged)) {
3700
+ handlers.onRunInitialized = forceUpdate;
3701
+ handlers.onRunFinalized = forceUpdate;
3702
+ handlers.onRunFailed = forceUpdate;
3703
+ }
3704
+ const subscription = agent.subscribe(handlers);
3705
+ return () => {
3706
+ active = false;
3707
+ if (timerId !== null) clearTimeout(timerId);
3708
+ subscription.unsubscribe();
3709
+ };
3710
+ }, [
3711
+ agent,
3712
+ forceUpdate,
3713
+ effectiveThrottleMs,
3714
+ updateFlags
2514
3715
  ]);
3716
+ (0, react.useEffect)(() => {
3717
+ if (agent instanceof _ag_ui_client.HttpAgent) agent.headers = { ...copilotkit.headers };
3718
+ }, [agent, JSON.stringify(copilotkit.headers)]);
3719
+ return { agent };
2515
3720
  }
2516
3721
 
2517
3722
  //#endregion
@@ -2527,12 +3732,13 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
2527
3732
  return aHasAgent ? -1 : 1;
2528
3733
  });
2529
3734
  return function(params) {
2530
- var _copilotkit$getRunIdF;
3735
+ var _copilotkit$getRunIdF, _getThreadClone;
2531
3736
  if (!customMessageRenderers.length) return null;
2532
3737
  const { message, position } = params;
2533
3738
  const resolvedRunId = (_copilotkit$getRunIdF = copilotkit.getRunIdForMessage(agentId, threadId, message.id)) !== null && _copilotkit$getRunIdF !== void 0 ? _copilotkit$getRunIdF : copilotkit.getRunIdsForThread(agentId, threadId).slice(-1)[0];
2534
3739
  const runId = resolvedRunId !== null && resolvedRunId !== void 0 ? resolvedRunId : `missing-run-id:${message.id}`;
2535
- const agent = copilotkit.getAgent(agentId);
3740
+ const registryAgent = copilotkit.getAgent(agentId);
3741
+ const agent = (_getThreadClone = getThreadClone(registryAgent, threadId)) !== null && _getThreadClone !== void 0 ? _getThreadClone : registryAgent;
2536
3742
  if (!agent) throw new Error("Agent not found");
2537
3743
  const messagesIdsInRun = resolvedRunId ? agent.messages.filter((msg) => copilotkit.getRunIdForMessage(agentId, threadId, msg.id) === resolvedRunId).map((msg) => msg.id) : [message.id];
2538
3744
  const rawMessageIndex = agent.messages.findIndex((msg) => msg.id === message.id);
@@ -2575,6 +3781,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
2575
3781
  return (_ref = (_ref2 = (_matches$find = matches.find((candidate) => candidate.agentId === agentId)) !== null && _matches$find !== void 0 ? _matches$find : matches.find((candidate) => candidate.agentId === void 0)) !== null && _ref2 !== void 0 ? _ref2 : renderers.find((candidate) => candidate.activityType === "*")) !== null && _ref !== void 0 ? _ref : null;
2576
3782
  }, [agentId, renderers]);
2577
3783
  const renderActivityMessage = (0, react.useCallback)((message) => {
3784
+ var _getThreadClone;
2578
3785
  const renderer = findRenderer(message.activityType);
2579
3786
  if (!renderer) return null;
2580
3787
  const parseResult = renderer.content.safeParse(message.content);
@@ -2583,7 +3790,8 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
2583
3790
  return null;
2584
3791
  }
2585
3792
  const Component = renderer.render;
2586
- const agent = copilotkit.getAgent(agentId);
3793
+ const registryAgent = copilotkit.getAgent(agentId);
3794
+ const agent = (_getThreadClone = getThreadClone(registryAgent, config === null || config === void 0 ? void 0 : config.threadId)) !== null && _getThreadClone !== void 0 ? _getThreadClone : registryAgent;
2587
3795
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Component, {
2588
3796
  activityType: message.activityType,
2589
3797
  content: parseResult.data,
@@ -2592,6 +3800,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
2592
3800
  }, message.id);
2593
3801
  }, [
2594
3802
  agentId,
3803
+ config === null || config === void 0 ? void 0 : config.threadId,
2595
3804
  copilotkit,
2596
3805
  findRenderer
2597
3806
  ]);
@@ -2617,7 +3826,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
2617
3826
  copilotkit.removeTool(name, tool.agentId);
2618
3827
  }
2619
3828
  copilotkit.addTool(tool);
2620
- if (tool.render && tool.parameters) copilotkit.addHookRenderToolCall({
3829
+ if (tool.render) copilotkit.addHookRenderToolCall({
2621
3830
  name,
2622
3831
  args: tool.parameters,
2623
3832
  agentId: tool.agentId,
@@ -2702,18 +3911,6 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
2702
3911
  }, deps);
2703
3912
  }
2704
3913
 
2705
- //#endregion
2706
- //#region src/v2/types/defineToolCallRenderer.ts
2707
- function defineToolCallRenderer(def) {
2708
- const argsSchema = def.name === "*" && !def.args ? zod.z.any() : def.args;
2709
- return {
2710
- name: def.name,
2711
- args: argsSchema,
2712
- render: def.render,
2713
- ...def.agentId ? { agentId: def.agentId } : {}
2714
- };
2715
- }
2716
-
2717
3914
  //#endregion
2718
3915
  //#region src/v2/hooks/use-render-tool.tsx
2719
3916
  const EMPTY_DEPS = [];
@@ -2953,207 +4150,94 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
2953
4150
  style: {
2954
4151
  fontSize: "10px",
2955
4152
  textTransform: "uppercase",
2956
- letterSpacing: "0.05em",
2957
- color: "#71717a"
2958
- },
2959
- children: "Result"
2960
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", {
2961
- style: {
2962
- marginTop: "6px",
2963
- maxHeight: "200px",
2964
- overflow: "auto",
2965
- borderRadius: "6px",
2966
- backgroundColor: "#f4f4f5",
2967
- padding: "10px",
2968
- fontSize: "11px",
2969
- lineHeight: 1.6,
2970
- color: "#27272a",
2971
- whiteSpace: "pre-wrap",
2972
- wordBreak: "break-word"
2973
- },
2974
- children: typeof result === "string" ? result : JSON.stringify(result, null, 2)
2975
- })] })]
2976
- })]
2977
- })
2978
- });
2979
- }
2980
-
2981
- //#endregion
2982
- //#region src/v2/hooks/use-human-in-the-loop.tsx
2983
- function useHumanInTheLoop(tool, deps) {
2984
- const { copilotkit } = useCopilotKit();
2985
- const resolvePromiseRef = (0, react.useRef)(null);
2986
- const respond = (0, react.useCallback)(async (result) => {
2987
- if (resolvePromiseRef.current) {
2988
- resolvePromiseRef.current(result);
2989
- resolvePromiseRef.current = null;
2990
- }
2991
- }, []);
2992
- const handler = (0, react.useCallback)(async () => {
2993
- return new Promise((resolve) => {
2994
- resolvePromiseRef.current = resolve;
2995
- });
2996
- }, []);
2997
- const RenderComponent = (0, react.useCallback)((props) => {
2998
- const ToolComponent = tool.render;
2999
- if (props.status === "inProgress") {
3000
- const enhancedProps = {
3001
- ...props,
3002
- name: tool.name,
3003
- description: tool.description || "",
3004
- respond: void 0
3005
- };
3006
- return react.default.createElement(ToolComponent, enhancedProps);
3007
- } else if (props.status === "executing") {
3008
- const enhancedProps = {
3009
- ...props,
3010
- name: tool.name,
3011
- description: tool.description || "",
3012
- respond
3013
- };
3014
- return react.default.createElement(ToolComponent, enhancedProps);
3015
- } else if (props.status === "complete") {
3016
- const enhancedProps = {
3017
- ...props,
3018
- name: tool.name,
3019
- description: tool.description || "",
3020
- respond: void 0
3021
- };
3022
- return react.default.createElement(ToolComponent, enhancedProps);
3023
- }
3024
- return react.default.createElement(ToolComponent, props);
3025
- }, [
3026
- tool.render,
3027
- tool.name,
3028
- tool.description,
3029
- respond
3030
- ]);
3031
- useFrontendTool({
3032
- ...tool,
3033
- handler,
3034
- render: RenderComponent
3035
- }, deps);
3036
- (0, react.useEffect)(() => {
3037
- return () => {
3038
- copilotkit.removeHookRenderToolCall(tool.name, tool.agentId);
3039
- };
3040
- }, [
3041
- copilotkit,
3042
- tool.name,
3043
- tool.agentId
3044
- ]);
3045
- }
3046
-
3047
- //#endregion
3048
- //#region src/v2/hooks/use-agent.tsx
3049
- let UseAgentUpdate = /* @__PURE__ */ function(UseAgentUpdate) {
3050
- UseAgentUpdate["OnMessagesChanged"] = "OnMessagesChanged";
3051
- UseAgentUpdate["OnStateChanged"] = "OnStateChanged";
3052
- UseAgentUpdate["OnRunStatusChanged"] = "OnRunStatusChanged";
3053
- return UseAgentUpdate;
3054
- }({});
3055
- const ALL_UPDATES = [
3056
- UseAgentUpdate.OnMessagesChanged,
3057
- UseAgentUpdate.OnStateChanged,
3058
- UseAgentUpdate.OnRunStatusChanged
3059
- ];
3060
- function useAgent({ agentId, updates } = {}) {
3061
- var _agentId;
3062
- (_agentId = agentId) !== null && _agentId !== void 0 || (agentId = _copilotkit_shared.DEFAULT_AGENT_ID);
3063
- const { copilotkit } = useCopilotKit();
3064
- const [, forceUpdate] = (0, react.useReducer)((x) => x + 1, 0);
3065
- const updateFlags = (0, react.useMemo)(() => updates !== null && updates !== void 0 ? updates : ALL_UPDATES, [JSON.stringify(updates)]);
3066
- const provisionalAgentCache = (0, react.useRef)(/* @__PURE__ */ new Map());
3067
- const agent = (0, react.useMemo)(() => {
3068
- var _copilotkit$agents;
3069
- const existing = copilotkit.getAgent(agentId);
3070
- if (existing) {
3071
- provisionalAgentCache.current.delete(agentId);
3072
- return existing;
3073
- }
3074
- const isRuntimeConfigured = copilotkit.runtimeUrl !== void 0;
3075
- const status = copilotkit.runtimeConnectionStatus;
3076
- if (isRuntimeConfigured && (status === _copilotkit_core.CopilotKitCoreRuntimeConnectionStatus.Disconnected || status === _copilotkit_core.CopilotKitCoreRuntimeConnectionStatus.Connecting)) {
3077
- const cached = provisionalAgentCache.current.get(agentId);
3078
- if (cached) {
3079
- cached.headers = { ...copilotkit.headers };
3080
- return cached;
3081
- }
3082
- const provisional = new _copilotkit_core.ProxiedCopilotRuntimeAgent({
3083
- runtimeUrl: copilotkit.runtimeUrl,
3084
- agentId,
3085
- transport: copilotkit.runtimeTransport,
3086
- runtimeMode: "pending"
3087
- });
3088
- provisional.headers = { ...copilotkit.headers };
3089
- provisionalAgentCache.current.set(agentId, provisional);
3090
- return provisional;
3091
- }
3092
- if (isRuntimeConfigured && status === _copilotkit_core.CopilotKitCoreRuntimeConnectionStatus.Error) {
3093
- const provisional = new _copilotkit_core.ProxiedCopilotRuntimeAgent({
3094
- runtimeUrl: copilotkit.runtimeUrl,
3095
- agentId,
3096
- transport: copilotkit.runtimeTransport,
3097
- runtimeMode: "pending"
3098
- });
3099
- provisional.headers = { ...copilotkit.headers };
3100
- return provisional;
3101
- }
3102
- const knownAgents = Object.keys((_copilotkit$agents = copilotkit.agents) !== null && _copilotkit$agents !== void 0 ? _copilotkit$agents : {});
3103
- const runtimePart = isRuntimeConfigured ? `runtimeUrl=${copilotkit.runtimeUrl}` : "no runtimeUrl";
3104
- throw new Error(`useAgent: Agent '${agentId}' not found after runtime sync (${runtimePart}). ` + (knownAgents.length ? `Known agents: [${knownAgents.join(", ")}]` : "No agents registered.") + " Verify your runtime /info and/or agents__unsafe_dev_only.");
3105
- }, [
3106
- agentId,
3107
- copilotkit.agents,
3108
- copilotkit.runtimeConnectionStatus,
3109
- copilotkit.runtimeUrl,
3110
- copilotkit.runtimeTransport,
3111
- JSON.stringify(copilotkit.headers)
3112
- ]);
3113
- (0, react.useEffect)(() => {
3114
- if (updateFlags.length === 0) return;
3115
- const handlers = {};
3116
- if (updateFlags.includes(UseAgentUpdate.OnMessagesChanged)) handlers.onMessagesChanged = () => {
3117
- forceUpdate();
3118
- };
3119
- if (updateFlags.includes(UseAgentUpdate.OnStateChanged)) handlers.onStateChanged = forceUpdate;
3120
- if (updateFlags.includes(UseAgentUpdate.OnRunStatusChanged)) {
3121
- handlers.onRunInitialized = forceUpdate;
3122
- handlers.onRunFinalized = forceUpdate;
3123
- handlers.onRunFailed = forceUpdate;
3124
- }
3125
- const subscription = agent.subscribe(handlers);
3126
- return () => subscription.unsubscribe();
3127
- }, [
3128
- agent,
3129
- forceUpdate,
3130
- JSON.stringify(updateFlags)
3131
- ]);
3132
- return { agent };
4153
+ letterSpacing: "0.05em",
4154
+ color: "#71717a"
4155
+ },
4156
+ children: "Result"
4157
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", {
4158
+ style: {
4159
+ marginTop: "6px",
4160
+ maxHeight: "200px",
4161
+ overflow: "auto",
4162
+ borderRadius: "6px",
4163
+ backgroundColor: "#f4f4f5",
4164
+ padding: "10px",
4165
+ fontSize: "11px",
4166
+ lineHeight: 1.6,
4167
+ color: "#27272a",
4168
+ whiteSpace: "pre-wrap",
4169
+ wordBreak: "break-word"
4170
+ },
4171
+ children: typeof result === "string" ? result : JSON.stringify(result, null, 2)
4172
+ })] })]
4173
+ })]
4174
+ })
4175
+ });
3133
4176
  }
3134
4177
 
3135
4178
  //#endregion
3136
- //#region src/v2/hooks/use-agent-context.tsx
3137
- function useAgentContext(context) {
3138
- const { description, value } = context;
4179
+ //#region src/v2/hooks/use-human-in-the-loop.tsx
4180
+ function useHumanInTheLoop(tool, deps) {
3139
4181
  const { copilotkit } = useCopilotKit();
3140
- const stringValue = (0, react.useMemo)(() => {
3141
- if (typeof value === "string") return value;
3142
- return JSON.stringify(value);
3143
- }, [value]);
3144
- (0, react.useLayoutEffect)(() => {
3145
- if (!copilotkit) return;
3146
- const id = copilotkit.addContext({
3147
- description,
3148
- value: stringValue
4182
+ const resolvePromiseRef = (0, react.useRef)(null);
4183
+ const respond = (0, react.useCallback)(async (result) => {
4184
+ if (resolvePromiseRef.current) {
4185
+ resolvePromiseRef.current(result);
4186
+ resolvePromiseRef.current = null;
4187
+ }
4188
+ }, []);
4189
+ const handler = (0, react.useCallback)(async () => {
4190
+ return new Promise((resolve) => {
4191
+ resolvePromiseRef.current = resolve;
3149
4192
  });
4193
+ }, []);
4194
+ const RenderComponent = (0, react.useCallback)((props) => {
4195
+ const ToolComponent = tool.render;
4196
+ if (props.status === "inProgress") {
4197
+ const enhancedProps = {
4198
+ ...props,
4199
+ name: tool.name,
4200
+ description: tool.description || "",
4201
+ respond: void 0
4202
+ };
4203
+ return react.default.createElement(ToolComponent, enhancedProps);
4204
+ } else if (props.status === "executing") {
4205
+ const enhancedProps = {
4206
+ ...props,
4207
+ name: tool.name,
4208
+ description: tool.description || "",
4209
+ respond
4210
+ };
4211
+ return react.default.createElement(ToolComponent, enhancedProps);
4212
+ } else if (props.status === "complete") {
4213
+ const enhancedProps = {
4214
+ ...props,
4215
+ name: tool.name,
4216
+ description: tool.description || "",
4217
+ respond: void 0
4218
+ };
4219
+ return react.default.createElement(ToolComponent, enhancedProps);
4220
+ }
4221
+ return react.default.createElement(ToolComponent, props);
4222
+ }, [
4223
+ tool.render,
4224
+ tool.name,
4225
+ tool.description,
4226
+ respond
4227
+ ]);
4228
+ useFrontendTool({
4229
+ ...tool,
4230
+ handler,
4231
+ render: RenderComponent
4232
+ }, deps);
4233
+ (0, react.useEffect)(() => {
3150
4234
  return () => {
3151
- copilotkit.removeContext(id);
4235
+ copilotkit.removeHookRenderToolCall(tool.name, tool.agentId);
3152
4236
  };
3153
4237
  }, [
3154
- description,
3155
- stringValue,
3156
- copilotkit
4238
+ copilotkit,
4239
+ tool.name,
4240
+ tool.agentId
3157
4241
  ]);
3158
4242
  }
3159
4243
 
@@ -3578,11 +4662,19 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
3578
4662
  var _copilotkit$intellige2;
3579
4663
  const { copilotkit } = useCopilotKit();
3580
4664
  const [store] = (0, react.useState)(() => (0, _copilotkit_core.ɵcreateThreadStore)({ fetch: globalThis.fetch }));
3581
- const threads = useThreadStoreSelector(store, _copilotkit_core.ɵselectThreads);
4665
+ const coreThreads = useThreadStoreSelector(store, _copilotkit_core.ɵselectThreads);
4666
+ const threads = (0, react.useMemo)(() => coreThreads.map(({ id, agentId, name, archived, createdAt, updatedAt }) => ({
4667
+ id,
4668
+ agentId,
4669
+ name,
4670
+ archived,
4671
+ createdAt,
4672
+ updatedAt
4673
+ })), [coreThreads]);
3582
4674
  const storeIsLoading = useThreadStoreSelector(store, _copilotkit_core.ɵselectThreadsIsLoading);
3583
4675
  const storeError = useThreadStoreSelector(store, _copilotkit_core.ɵselectThreadsError);
3584
- const hasNextPage = useThreadStoreSelector(store, _copilotkit_core.ɵselectHasNextPage);
3585
- const isFetchingNextPage = useThreadStoreSelector(store, _copilotkit_core.ɵselectIsFetchingNextPage);
4676
+ const hasMoreThreads = useThreadStoreSelector(store, _copilotkit_core.ɵselectHasNextPage);
4677
+ const isFetchingMoreThreads = useThreadStoreSelector(store, _copilotkit_core.ɵselectIsFetchingNextPage);
3586
4678
  const headersKey = (0, react.useMemo)(() => {
3587
4679
  var _copilotkit$headers;
3588
4680
  return JSON.stringify(Object.entries((_copilotkit$headers = copilotkit.headers) !== null && _copilotkit$headers !== void 0 ? _copilotkit$headers : {}).sort(([left], [right]) => left.localeCompare(right)));
@@ -3627,15 +4719,184 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
3627
4719
  threads,
3628
4720
  isLoading,
3629
4721
  error,
3630
- hasNextPage,
3631
- isFetchingNextPage,
3632
- fetchNextPage: (0, react.useCallback)(() => store.fetchNextPage(), [store]),
4722
+ hasMoreThreads,
4723
+ isFetchingMoreThreads,
4724
+ fetchMoreThreads: (0, react.useCallback)(() => store.fetchNextPage(), [store]),
3633
4725
  renameThread,
3634
4726
  archiveThread,
3635
4727
  deleteThread
3636
4728
  };
3637
4729
  }
3638
4730
 
4731
+ //#endregion
4732
+ //#region src/v2/hooks/use-attachments.tsx
4733
+ /**
4734
+ * Hook that manages file attachment state — uploads, drag-and-drop, paste,
4735
+ * and lifecycle. All returned callbacks are referentially stable across
4736
+ * renders (via useCallback) to avoid destabilizing downstream memoization.
4737
+ */
4738
+ function useAttachments({ config }) {
4739
+ var _config$enabled;
4740
+ const enabled = (_config$enabled = config === null || config === void 0 ? void 0 : config.enabled) !== null && _config$enabled !== void 0 ? _config$enabled : false;
4741
+ const [attachments, setAttachments] = (0, react.useState)([]);
4742
+ const [dragOver, setDragOver] = (0, react.useState)(false);
4743
+ const fileInputRef = (0, react.useRef)(null);
4744
+ const containerRef = (0, react.useRef)(null);
4745
+ const configRef = (0, react.useRef)(config);
4746
+ configRef.current = config;
4747
+ const attachmentsRef = (0, react.useRef)([]);
4748
+ attachmentsRef.current = attachments;
4749
+ const processFiles = (0, react.useCallback)(async (files) => {
4750
+ var _cfg$accept, _cfg$maxSize;
4751
+ const cfg = configRef.current;
4752
+ const accept = (_cfg$accept = cfg === null || cfg === void 0 ? void 0 : cfg.accept) !== null && _cfg$accept !== void 0 ? _cfg$accept : "*/*";
4753
+ const maxSize = (_cfg$maxSize = cfg === null || cfg === void 0 ? void 0 : cfg.maxSize) !== null && _cfg$maxSize !== void 0 ? _cfg$maxSize : 20 * 1024 * 1024;
4754
+ const rejectedFiles = files.filter((file) => !(0, _copilotkit_shared.matchesAcceptFilter)(file, accept));
4755
+ for (const file of rejectedFiles) {
4756
+ var _cfg$onUploadFailed;
4757
+ cfg === null || cfg === void 0 || (_cfg$onUploadFailed = cfg.onUploadFailed) === null || _cfg$onUploadFailed === void 0 || _cfg$onUploadFailed.call(cfg, {
4758
+ reason: "invalid-type",
4759
+ file,
4760
+ message: `File "${file.name}" is not accepted. Supported types: ${accept}`
4761
+ });
4762
+ }
4763
+ const validFiles = files.filter((file) => (0, _copilotkit_shared.matchesAcceptFilter)(file, accept));
4764
+ for (const file of validFiles) {
4765
+ if ((0, _copilotkit_shared.exceedsMaxSize)(file, maxSize)) {
4766
+ var _cfg$onUploadFailed2;
4767
+ cfg === null || cfg === void 0 || (_cfg$onUploadFailed2 = cfg.onUploadFailed) === null || _cfg$onUploadFailed2 === void 0 || _cfg$onUploadFailed2.call(cfg, {
4768
+ reason: "file-too-large",
4769
+ file,
4770
+ message: `File "${file.name}" exceeds the maximum size of ${(0, _copilotkit_shared.formatFileSize)(maxSize)}`
4771
+ });
4772
+ continue;
4773
+ }
4774
+ const modality = (0, _copilotkit_shared.getModalityFromMimeType)(file.type);
4775
+ const placeholderId = (0, _copilotkit_shared.randomUUID)();
4776
+ const placeholder = {
4777
+ id: placeholderId,
4778
+ type: modality,
4779
+ source: {
4780
+ type: "data",
4781
+ value: "",
4782
+ mimeType: file.type
4783
+ },
4784
+ filename: file.name,
4785
+ size: file.size,
4786
+ status: "uploading"
4787
+ };
4788
+ setAttachments((prev) => [...prev, placeholder]);
4789
+ try {
4790
+ let source;
4791
+ let uploadMetadata;
4792
+ if (cfg === null || cfg === void 0 ? void 0 : cfg.onUpload) {
4793
+ const { metadata: meta, ...uploadSource } = await cfg.onUpload(file);
4794
+ source = uploadSource;
4795
+ uploadMetadata = meta;
4796
+ } else source = {
4797
+ type: "data",
4798
+ value: await (0, _copilotkit_shared.readFileAsBase64)(file),
4799
+ mimeType: file.type
4800
+ };
4801
+ let thumbnail;
4802
+ if (modality === "video") thumbnail = await (0, _copilotkit_shared.generateVideoThumbnail)(file);
4803
+ setAttachments((prev) => prev.map((att) => att.id === placeholderId ? {
4804
+ ...att,
4805
+ source,
4806
+ status: "ready",
4807
+ thumbnail,
4808
+ metadata: uploadMetadata
4809
+ } : att));
4810
+ } catch (error) {
4811
+ var _cfg$onUploadFailed3;
4812
+ setAttachments((prev) => prev.filter((att) => att.id !== placeholderId));
4813
+ console.error(`[CopilotKit] Failed to upload "${file.name}":`, error);
4814
+ cfg === null || cfg === void 0 || (_cfg$onUploadFailed3 = cfg.onUploadFailed) === null || _cfg$onUploadFailed3 === void 0 || _cfg$onUploadFailed3.call(cfg, {
4815
+ reason: "upload-failed",
4816
+ file,
4817
+ message: error instanceof Error ? error.message : `Failed to upload "${file.name}"`
4818
+ });
4819
+ }
4820
+ }
4821
+ }, []);
4822
+ const handleFileUpload = (0, react.useCallback)(async (e) => {
4823
+ var _e$target$files;
4824
+ if (!((_e$target$files = e.target.files) === null || _e$target$files === void 0 ? void 0 : _e$target$files.length)) return;
4825
+ try {
4826
+ await processFiles(Array.from(e.target.files));
4827
+ } catch (error) {
4828
+ console.error("[CopilotKit] Upload error:", error);
4829
+ }
4830
+ }, [processFiles]);
4831
+ const handleDragOver = (0, react.useCallback)((e) => {
4832
+ var _configRef$current;
4833
+ if (!((_configRef$current = configRef.current) === null || _configRef$current === void 0 ? void 0 : _configRef$current.enabled)) return;
4834
+ e.preventDefault();
4835
+ e.stopPropagation();
4836
+ setDragOver(true);
4837
+ }, []);
4838
+ const handleDragLeave = (0, react.useCallback)((e) => {
4839
+ e.preventDefault();
4840
+ e.stopPropagation();
4841
+ setDragOver(false);
4842
+ }, []);
4843
+ const handleDrop = (0, react.useCallback)(async (e) => {
4844
+ var _configRef$current2;
4845
+ e.preventDefault();
4846
+ e.stopPropagation();
4847
+ setDragOver(false);
4848
+ if (!((_configRef$current2 = configRef.current) === null || _configRef$current2 === void 0 ? void 0 : _configRef$current2.enabled)) return;
4849
+ const files = Array.from(e.dataTransfer.files);
4850
+ if (files.length > 0) try {
4851
+ await processFiles(files);
4852
+ } catch (error) {
4853
+ console.error("[CopilotKit] Drop error:", error);
4854
+ }
4855
+ }, [processFiles]);
4856
+ (0, react.useEffect)(() => {
4857
+ if (!enabled) return;
4858
+ const handlePaste = async (e) => {
4859
+ var _containerRef$current, _configRef$current$ac, _configRef$current3, _e$clipboardData;
4860
+ const target = e.target;
4861
+ if (!target || !((_containerRef$current = containerRef.current) === null || _containerRef$current === void 0 ? void 0 : _containerRef$current.contains(target))) return;
4862
+ const accept = (_configRef$current$ac = (_configRef$current3 = configRef.current) === null || _configRef$current3 === void 0 ? void 0 : _configRef$current3.accept) !== null && _configRef$current$ac !== void 0 ? _configRef$current$ac : "*/*";
4863
+ const fileItems = Array.from(((_e$clipboardData = e.clipboardData) === null || _e$clipboardData === void 0 ? void 0 : _e$clipboardData.items) || []).filter((item) => item.kind === "file" && item.getAsFile() !== null && (0, _copilotkit_shared.matchesAcceptFilter)(item.getAsFile(), accept));
4864
+ if (fileItems.length === 0) return;
4865
+ e.preventDefault();
4866
+ const files = fileItems.map((item) => item.getAsFile()).filter((f) => f !== null);
4867
+ try {
4868
+ await processFiles(files);
4869
+ } catch (error) {
4870
+ console.error("[CopilotKit] Paste error:", error);
4871
+ }
4872
+ };
4873
+ document.addEventListener("paste", handlePaste);
4874
+ return () => document.removeEventListener("paste", handlePaste);
4875
+ }, [enabled, processFiles]);
4876
+ return {
4877
+ attachments,
4878
+ enabled,
4879
+ dragOver,
4880
+ fileInputRef,
4881
+ containerRef,
4882
+ processFiles,
4883
+ handleFileUpload,
4884
+ handleDragOver,
4885
+ handleDragLeave,
4886
+ handleDrop,
4887
+ removeAttachment: (0, react.useCallback)((id) => {
4888
+ setAttachments((prev) => prev.filter((a) => a.id !== id));
4889
+ }, []),
4890
+ consumeAttachments: (0, react.useCallback)(() => {
4891
+ const ready = attachmentsRef.current.filter((a) => a.status === "ready");
4892
+ if (ready.length === 0) return ready;
4893
+ setAttachments((prev) => prev.filter((a) => a.status !== "ready"));
4894
+ if (fileInputRef.current) fileInputRef.current.value = "";
4895
+ return ready;
4896
+ }, [])
4897
+ };
4898
+ }
4899
+
3639
4900
  //#endregion
3640
4901
  //#region src/v2/components/chat/CopilotChatToolCallsView.tsx
3641
4902
  function CopilotChatToolCallsView({ message, messages = [] }) {
@@ -3755,9 +5016,19 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
3755
5016
  const config = useCopilotChatConfiguration();
3756
5017
  const labels = (_config$labels = config === null || config === void 0 ? void 0 : config.labels) !== null && _config$labels !== void 0 ? _config$labels : CopilotChatDefaultLabels;
3757
5018
  const [copied, setCopied] = (0, react.useState)(false);
5019
+ const timerRef = (0, react.useRef)(null);
5020
+ (0, react.useEffect)(() => {
5021
+ return () => {
5022
+ if (timerRef.current !== null) clearTimeout(timerRef.current);
5023
+ };
5024
+ }, []);
3758
5025
  const handleClick = (event) => {
3759
5026
  setCopied(true);
3760
- setTimeout(() => setCopied(false), 2e3);
5027
+ if (timerRef.current !== null) clearTimeout(timerRef.current);
5028
+ timerRef.current = setTimeout(() => {
5029
+ timerRef.current = null;
5030
+ setCopied(false);
5031
+ }, 2e3);
3761
5032
  if (onClick) onClick(event);
3762
5033
  };
3763
5034
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ToolbarButton, {
@@ -3823,6 +5094,80 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
3823
5094
  CopilotChatAssistantMessage.RegenerateButton.displayName = "CopilotChatAssistantMessage.RegenerateButton";
3824
5095
  var CopilotChatAssistantMessage_default = CopilotChatAssistantMessage;
3825
5096
 
5097
+ //#endregion
5098
+ //#region src/v2/components/chat/CopilotChatAttachmentRenderer.tsx
5099
+ const ImageAttachment = (0, react.memo)(function ImageAttachment({ src, className }) {
5100
+ const [error, setError] = (0, react.useState)(false);
5101
+ if (error) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5102
+ className: cn("cpk:flex cpk:flex-col cpk:items-center cpk:justify-center cpk:rounded-lg cpk:bg-muted cpk:p-4 cpk:text-sm cpk:text-muted-foreground", className),
5103
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "Failed to load image" })
5104
+ });
5105
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
5106
+ src,
5107
+ alt: "Image attachment",
5108
+ className: cn("cpk:max-w-full cpk:h-auto cpk:rounded-lg", className),
5109
+ onError: () => setError(true)
5110
+ });
5111
+ });
5112
+ const AudioAttachment = (0, react.memo)(function AudioAttachment({ src, filename, className }) {
5113
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5114
+ className: cn("cpk:flex cpk:flex-col cpk:gap-1", className),
5115
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("audio", {
5116
+ src,
5117
+ controls: true,
5118
+ preload: "metadata",
5119
+ className: "cpk:max-w-[300px] cpk:w-full cpk:h-10"
5120
+ }), filename && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5121
+ className: "cpk:text-xs cpk:text-muted-foreground cpk:truncate cpk:max-w-[300px]",
5122
+ children: filename
5123
+ })]
5124
+ });
5125
+ });
5126
+ const VideoAttachment = (0, react.memo)(function VideoAttachment({ src, className }) {
5127
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("video", {
5128
+ src,
5129
+ controls: true,
5130
+ preload: "metadata",
5131
+ className: cn("cpk:max-w-[400px] cpk:w-full cpk:rounded-lg", className)
5132
+ });
5133
+ });
5134
+ const DocumentAttachment = (0, react.memo)(function DocumentAttachment({ source, filename, className }) {
5135
+ var _source$mimeType;
5136
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5137
+ className: cn("cpk:inline-flex cpk:items-center cpk:gap-2 cpk:px-3 cpk:py-2 cpk:border cpk:border-border cpk:rounded-lg cpk:bg-muted", className),
5138
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5139
+ className: "cpk:text-xs cpk:font-bold cpk:uppercase",
5140
+ children: (0, _copilotkit_shared.getDocumentIcon)((_source$mimeType = source.mimeType) !== null && _source$mimeType !== void 0 ? _source$mimeType : "")
5141
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5142
+ className: "cpk:text-sm cpk:text-muted-foreground cpk:truncate",
5143
+ children: filename || source.mimeType || "Unknown type"
5144
+ })]
5145
+ });
5146
+ });
5147
+ const CopilotChatAttachmentRenderer = ({ type, source, filename, className }) => {
5148
+ const src = (0, _copilotkit_shared.getSourceUrl)(source);
5149
+ switch (type) {
5150
+ case "image": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ImageAttachment, {
5151
+ src,
5152
+ className
5153
+ });
5154
+ case "audio": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AudioAttachment, {
5155
+ src,
5156
+ filename,
5157
+ className
5158
+ });
5159
+ case "video": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(VideoAttachment, {
5160
+ src,
5161
+ className
5162
+ });
5163
+ case "document": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DocumentAttachment, {
5164
+ source,
5165
+ filename,
5166
+ className
5167
+ });
5168
+ }
5169
+ };
5170
+
3826
5171
  //#endregion
3827
5172
  //#region src/v2/components/chat/CopilotChatUserMessage.tsx
3828
5173
  function flattenUserMessageContent(content) {
@@ -3833,8 +5178,17 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
3833
5178
  return "";
3834
5179
  }).filter((text) => text.length > 0).join("\n");
3835
5180
  }
5181
+ function getMediaParts(content) {
5182
+ if (!content || typeof content === "string") return [];
5183
+ return content.filter((part) => part.type === "image" || part.type === "audio" || part.type === "video" || part.type === "document");
5184
+ }
5185
+ function getFilename(part) {
5186
+ const meta = part.metadata;
5187
+ if (meta != null && typeof meta === "object" && "filename" in meta && typeof meta.filename === "string") return meta.filename;
5188
+ }
3836
5189
  function CopilotChatUserMessage({ message, onEditMessage, branchIndex, numberOfBranches, onSwitchToBranch, additionalToolbarItems, messageRenderer, toolbar, copyButton, editButton, branchNavigation, children, className, ...props }) {
3837
5190
  const flattenedContent = (0, react.useMemo)(() => flattenUserMessageContent(message.content), [message.content]);
5191
+ const mediaParts = (0, react.useMemo)(() => getMediaParts(message.content), [message.content]);
3838
5192
  const BoundMessageRenderer = renderSlot(messageRenderer, CopilotChatUserMessage.MessageRenderer, { content: flattenedContent });
3839
5193
  const BoundCopyButton = renderSlot(copyButton, CopilotChatUserMessage.CopyButton, { onClick: async () => {
3840
5194
  if (flattenedContent) try {
@@ -3881,7 +5235,18 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
3881
5235
  className: (0, tailwind_merge.twMerge)("copilotKitMessage copilotKitUserMessage cpk:flex cpk:flex-col cpk:items-end cpk:group cpk:pt-10", className),
3882
5236
  "data-message-id": message.id,
3883
5237
  ...props,
3884
- children: [BoundMessageRenderer, BoundToolbar]
5238
+ children: [
5239
+ BoundMessageRenderer,
5240
+ mediaParts.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5241
+ className: "cpk:flex cpk:flex-col cpk:items-end cpk:gap-2 cpk:mt-2",
5242
+ children: mediaParts.map((part, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopilotChatAttachmentRenderer, {
5243
+ type: part.type,
5244
+ source: part.source,
5245
+ filename: getFilename(part)
5246
+ }, index))
5247
+ }),
5248
+ BoundToolbar
5249
+ ]
3885
5250
  });
3886
5251
  }
3887
5252
  (function(_CopilotChatUserMessage) {
@@ -4184,6 +5549,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4184
5549
  const isLoading = loadingSet.has(index) || suggestion.isLoading === true;
4185
5550
  const pill = renderSlot(suggestionSlot, CopilotChatSuggestionPill, {
4186
5551
  children: suggestion.title,
5552
+ className: suggestion.className,
4187
5553
  isLoading,
4188
5554
  type: "button",
4189
5555
  onClick: () => onSelectSuggestion === null || onSelectSuggestion === void 0 ? void 0 : onSelectSuggestion(suggestion, index)
@@ -4221,9 +5587,43 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4221
5587
  });
4222
5588
  CopilotChatSuggestionView.displayName = "CopilotChatSuggestionView";
4223
5589
 
5590
+ //#endregion
5591
+ //#region src/v2/components/chat/scroll-element-context.ts
5592
+ /**
5593
+ * Provides the scroll container element to child components that need it for
5594
+ * virtualization. Set by CopilotChatView.ScrollView; consumed by
5595
+ * CopilotChatMessageView to feed useVirtualizer's getScrollElement.
5596
+ *
5597
+ * Carries the element itself (not a ref) so that context consumers re-render
5598
+ * reactively when the scroll container is first mounted.
5599
+ */
5600
+ const ScrollElementContext = react.default.createContext(null);
5601
+
4224
5602
  //#endregion
4225
5603
  //#region src/v2/components/chat/CopilotChatMessageView.tsx
4226
5604
  /**
5605
+ * Resolves a slot value into a { Component, slotProps } pair, handling the three
5606
+ * slot forms: a component type, a className string, or a partial-props object.
5607
+ */
5608
+ function resolveSlotComponent(slot, DefaultComponent) {
5609
+ if (isReactComponentType(slot)) return {
5610
+ Component: slot,
5611
+ slotProps: void 0
5612
+ };
5613
+ if (typeof slot === "string") return {
5614
+ Component: DefaultComponent,
5615
+ slotProps: { className: slot }
5616
+ };
5617
+ if (slot && typeof slot === "object") return {
5618
+ Component: DefaultComponent,
5619
+ slotProps: slot
5620
+ };
5621
+ return {
5622
+ Component: DefaultComponent,
5623
+ slotProps: void 0
5624
+ };
5625
+ }
5626
+ /**
4227
5627
  * Memoized wrapper for assistant messages to prevent re-renders when other messages change.
4228
5628
  */
4229
5629
  const MemoizedAssistantMessage = react.default.memo(function MemoizedAssistantMessage({ message, messages, isRunning, AssistantMessageComponent, slotProps }) {
@@ -4243,7 +5643,6 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4243
5643
  if (prevToolCalls && nextToolCalls) for (let i = 0; i < prevToolCalls.length; i++) {
4244
5644
  const prevTc = prevToolCalls[i];
4245
5645
  const nextTc = nextToolCalls[i];
4246
- if (!prevTc || !nextTc) return false;
4247
5646
  if (prevTc.id !== nextTc.id) return false;
4248
5647
  if (prevTc.function.arguments !== nextTc.function.arguments) return false;
4249
5648
  }
@@ -4323,20 +5722,25 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4323
5722
  if (JSON.stringify(prevProps.stateSnapshot) !== JSON.stringify(nextProps.stateSnapshot)) return false;
4324
5723
  return true;
4325
5724
  });
5725
+ const VIRTUALIZE_THRESHOLD = 50;
4326
5726
  function CopilotChatMessageView({ messages = [], assistantMessage, userMessage, reasoningMessage, cursor, isRunning = false, children, className, ...props }) {
5727
+ var _deduplicatedMessages;
4327
5728
  const renderCustomMessage = useRenderCustomMessages();
4328
5729
  const { renderActivityMessage } = useRenderActivityMessage();
4329
5730
  const { copilotkit } = useCopilotKit();
4330
5731
  const config = useCopilotChatConfiguration();
4331
5732
  const [, forceUpdate] = (0, react.useReducer)((x) => x + 1, 0);
4332
5733
  (0, react.useEffect)(() => {
5734
+ var _getThreadClone;
4333
5735
  if (!(config === null || config === void 0 ? void 0 : config.agentId)) return;
4334
- const agent = copilotkit.getAgent(config.agentId);
5736
+ const registryAgent = copilotkit.getAgent(config.agentId);
5737
+ const agent = (_getThreadClone = getThreadClone(registryAgent, config.threadId)) !== null && _getThreadClone !== void 0 ? _getThreadClone : registryAgent;
4335
5738
  if (!agent) return;
4336
5739
  const subscription = agent.subscribe({ onStateChanged: forceUpdate });
4337
5740
  return () => subscription.unsubscribe();
4338
5741
  }, [
4339
5742
  config === null || config === void 0 ? void 0 : config.agentId,
5743
+ config === null || config === void 0 ? void 0 : config.threadId,
4340
5744
  copilotkit,
4341
5745
  forceUpdate
4342
5746
  ]);
@@ -4355,9 +5759,36 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4355
5759
  if (!resolvedRunId) return void 0;
4356
5760
  return copilotkit.getStateByRun(config.agentId, config.threadId, resolvedRunId);
4357
5761
  };
4358
- const deduplicatedMessages = [...new Map(messages.map((m) => [m.id, m])).values()];
5762
+ const deduplicatedMessages = (0, react.useMemo)(() => [...new Map(messages.map((m) => [m.id, m])).values()], [messages]);
4359
5763
  if (process.env.NODE_ENV === "development" && deduplicatedMessages.length < messages.length) console.warn(`CopilotChatMessageView: Deduplicated ${messages.length - deduplicatedMessages.length} message(s) with duplicate IDs.`);
4360
- const messageElements = deduplicatedMessages.flatMap((message) => {
5764
+ const { Component: AssistantComponent, slotProps: assistantSlotProps } = (0, react.useMemo)(() => resolveSlotComponent(assistantMessage, CopilotChatAssistantMessage_default), [assistantMessage]);
5765
+ const { Component: UserComponent, slotProps: userSlotProps } = (0, react.useMemo)(() => resolveSlotComponent(userMessage, CopilotChatUserMessage_default), [userMessage]);
5766
+ const { Component: ReasoningComponent, slotProps: reasoningSlotProps } = (0, react.useMemo)(() => resolveSlotComponent(reasoningMessage, CopilotChatReasoningMessage_default), [reasoningMessage]);
5767
+ const scrollElementFromCtx = (0, react.useContext)(ScrollElementContext);
5768
+ const scrollElement = scrollElementFromCtx && scrollElementFromCtx.clientHeight > 0 ? scrollElementFromCtx : null;
5769
+ (0, react.useEffect)(() => {
5770
+ if (process.env.NODE_ENV !== "production" && scrollElementFromCtx && scrollElementFromCtx.clientHeight === 0) console.warn("[CopilotKit] Chat scroll container has clientHeight=0 — virtualization disabled. Ensure the chat is rendered in a visible container with a non-zero height.");
5771
+ }, [scrollElementFromCtx]);
5772
+ const shouldVirtualize = !!scrollElement && !children && deduplicatedMessages.length > VIRTUALIZE_THRESHOLD;
5773
+ const virtualizer = (0, _tanstack_react_virtual.useVirtualizer)({
5774
+ count: shouldVirtualize ? deduplicatedMessages.length : 0,
5775
+ getScrollElement: () => scrollElement,
5776
+ estimateSize: () => 100,
5777
+ overscan: 5,
5778
+ measureElement: (el) => {
5779
+ var _el$getBoundingClient;
5780
+ return (_el$getBoundingClient = el === null || el === void 0 ? void 0 : el.getBoundingClientRect().height) !== null && _el$getBoundingClient !== void 0 ? _el$getBoundingClient : 0;
5781
+ },
5782
+ initialRect: {
5783
+ width: 0,
5784
+ height: 600
5785
+ }
5786
+ });
5787
+ (0, react.useLayoutEffect)(() => {
5788
+ if (!shouldVirtualize || !deduplicatedMessages.length) return;
5789
+ virtualizer.scrollToIndex(deduplicatedMessages.length - 1, { align: "end" });
5790
+ }, [shouldVirtualize, (_deduplicatedMessages = deduplicatedMessages[0]) === null || _deduplicatedMessages === void 0 ? void 0 : _deduplicatedMessages.id]);
5791
+ const renderMessageBlock = (message) => {
4361
5792
  const elements = [];
4362
5793
  const stateSnapshot = getStateSnapshotForMessage(message.id);
4363
5794
  if (renderCustomMessage) elements.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(MemoizedCustomMessage, {
@@ -4366,58 +5797,38 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4366
5797
  renderCustomMessage,
4367
5798
  stateSnapshot
4368
5799
  }, `${message.id}-custom-before`));
4369
- if (message.role === "assistant") {
4370
- let AssistantComponent = CopilotChatAssistantMessage_default;
4371
- let assistantSlotProps;
4372
- if (isReactComponentType(assistantMessage)) AssistantComponent = assistantMessage;
4373
- else if (typeof assistantMessage === "string") assistantSlotProps = { className: assistantMessage };
4374
- else if (assistantMessage && typeof assistantMessage === "object") assistantSlotProps = assistantMessage;
4375
- elements.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(MemoizedAssistantMessage, {
4376
- message,
4377
- messages,
4378
- isRunning,
4379
- AssistantMessageComponent: AssistantComponent,
4380
- slotProps: assistantSlotProps
4381
- }, message.id));
4382
- } else if (message.role === "user") {
4383
- let UserComponent = CopilotChatUserMessage_default;
4384
- let userSlotProps;
4385
- if (isReactComponentType(userMessage)) UserComponent = userMessage;
4386
- else if (typeof userMessage === "string") userSlotProps = { className: userMessage };
4387
- else if (userMessage && typeof userMessage === "object") userSlotProps = userMessage;
4388
- elements.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(MemoizedUserMessage, {
4389
- message,
4390
- UserMessageComponent: UserComponent,
4391
- slotProps: userSlotProps
4392
- }, message.id));
4393
- } else if (message.role === "activity") {
4394
- const activityMsg = message;
4395
- elements.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(MemoizedActivityMessage, {
4396
- message: activityMsg,
4397
- renderActivityMessage
4398
- }, message.id));
4399
- } else if (message.role === "reasoning") {
4400
- let ReasoningComponent = CopilotChatReasoningMessage_default;
4401
- let reasoningSlotProps;
4402
- if (isReactComponentType(reasoningMessage)) ReasoningComponent = reasoningMessage;
4403
- else if (typeof reasoningMessage === "string") reasoningSlotProps = { className: reasoningMessage };
4404
- else if (reasoningMessage && typeof reasoningMessage === "object") reasoningSlotProps = reasoningMessage;
4405
- elements.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(MemoizedReasoningMessage, {
4406
- message,
4407
- messages,
4408
- isRunning,
4409
- ReasoningMessageComponent: ReasoningComponent,
4410
- slotProps: reasoningSlotProps
4411
- }, message.id));
4412
- }
5800
+ if (message.role === "assistant") elements.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(MemoizedAssistantMessage, {
5801
+ message,
5802
+ messages,
5803
+ isRunning,
5804
+ AssistantMessageComponent: AssistantComponent,
5805
+ slotProps: assistantSlotProps
5806
+ }, message.id));
5807
+ else if (message.role === "user") elements.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(MemoizedUserMessage, {
5808
+ message,
5809
+ UserMessageComponent: UserComponent,
5810
+ slotProps: userSlotProps
5811
+ }, message.id));
5812
+ else if (message.role === "activity") elements.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(MemoizedActivityMessage, {
5813
+ message,
5814
+ renderActivityMessage
5815
+ }, message.id));
5816
+ else if (message.role === "reasoning") elements.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(MemoizedReasoningMessage, {
5817
+ message,
5818
+ messages,
5819
+ isRunning,
5820
+ ReasoningMessageComponent: ReasoningComponent,
5821
+ slotProps: reasoningSlotProps
5822
+ }, message.id));
4413
5823
  if (renderCustomMessage) elements.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(MemoizedCustomMessage, {
4414
5824
  message,
4415
5825
  position: "after",
4416
5826
  renderCustomMessage,
4417
5827
  stateSnapshot
4418
5828
  }, `${message.id}-custom-after`));
4419
- return elements;
4420
- }).filter(Boolean);
5829
+ return elements.filter(Boolean);
5830
+ };
5831
+ const messageElements = shouldVirtualize ? [] : deduplicatedMessages.flatMap(renderMessageBlock);
4421
5832
  if (children) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
4422
5833
  "data-copilotkit": true,
4423
5834
  style: { display: "contents" },
@@ -4428,30 +5839,356 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4428
5839
  interruptElement
4429
5840
  })
4430
5841
  });
4431
- const lastMessage = messages[messages.length - 1];
4432
- const showCursor = isRunning && (lastMessage === null || lastMessage === void 0 ? void 0 : lastMessage.role) !== "reasoning";
5842
+ const lastMessage = messages[messages.length - 1];
5843
+ const showCursor = isRunning && (lastMessage === null || lastMessage === void 0 ? void 0 : lastMessage.role) !== "reasoning";
5844
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5845
+ "data-copilotkit": true,
5846
+ "data-testid": "copilot-message-list",
5847
+ className: (0, tailwind_merge.twMerge)("copilotKitMessages cpk:flex cpk:flex-col", className),
5848
+ ...props,
5849
+ children: [
5850
+ shouldVirtualize ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5851
+ style: {
5852
+ height: virtualizer.getTotalSize(),
5853
+ position: "relative"
5854
+ },
5855
+ children: virtualizer.getVirtualItems().map((virtualItem) => {
5856
+ const message = deduplicatedMessages[virtualItem.index];
5857
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5858
+ "data-index": virtualItem.index,
5859
+ ref: virtualizer.measureElement,
5860
+ style: {
5861
+ position: "absolute",
5862
+ top: 0,
5863
+ left: 0,
5864
+ width: "100%",
5865
+ transform: `translateY(${virtualItem.start}px)`
5866
+ },
5867
+ children: renderMessageBlock(message)
5868
+ }, message.id);
5869
+ })
5870
+ }) : messageElements,
5871
+ interruptElement,
5872
+ showCursor && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5873
+ className: "cpk:mt-2",
5874
+ children: renderSlot(cursor, CopilotChatMessageView.Cursor, {})
5875
+ })
5876
+ ]
5877
+ });
5878
+ }
5879
+ CopilotChatMessageView.Cursor = function Cursor({ className, ...props }) {
5880
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5881
+ "data-testid": "copilot-loading-cursor",
5882
+ className: (0, tailwind_merge.twMerge)("cpk:w-[11px] cpk:h-[11px] cpk:rounded-full cpk:bg-foreground cpk:animate-pulse-cursor cpk:ml-1", className),
5883
+ ...props
5884
+ });
5885
+ };
5886
+
5887
+ //#endregion
5888
+ //#region src/v2/components/chat/CopilotChatAttachmentQueue.tsx
5889
+ const CopilotChatAttachmentQueue = ({ attachments, onRemoveAttachment, className }) => {
5890
+ if (attachments.length === 0) return null;
5891
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5892
+ className: cn("cpk:flex cpk:flex-wrap cpk:gap-2 cpk:p-2", className),
5893
+ children: attachments.map((attachment) => {
5894
+ const isMedia = attachment.type === "image" || attachment.type === "video";
5895
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5896
+ className: cn("cpk:relative cpk:inline-flex cpk:rounded-lg cpk:overflow-hidden cpk:border cpk:border-border", isMedia ? "cpk:w-[72px] cpk:h-[72px]" : attachment.type === "audio" ? "cpk:min-w-[200px] cpk:max-w-[280px] cpk:flex-col cpk:p-1 cpk:pr-8" : "cpk:p-2 cpk:px-3 cpk:pr-8 cpk:max-w-[240px]"),
5897
+ children: [
5898
+ attachment.status === "uploading" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(UploadingOverlay, {}),
5899
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AttachmentPreview, { attachment }),
5900
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5901
+ onClick: () => onRemoveAttachment(attachment.id),
5902
+ className: cn("cpk:absolute cpk:bg-black/60 cpk:text-white cpk:border-none cpk:rounded-full cpk:w-5 cpk:h-5 cpk:flex cpk:items-center cpk:justify-center cpk:cursor-pointer cpk:text-[10px] cpk:z-20", isMedia ? "cpk:top-1 cpk:right-1" : "cpk:top-1.5 cpk:right-1.5"),
5903
+ "aria-label": "Remove attachment",
5904
+ children: "✕"
5905
+ })
5906
+ ]
5907
+ }, attachment.id);
5908
+ })
5909
+ });
5910
+ };
5911
+ function UploadingOverlay() {
5912
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5913
+ className: "cpk:absolute cpk:inset-0 cpk:flex cpk:items-center cpk:justify-center cpk:bg-black/40 cpk:z-10",
5914
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: "cpk:w-5 cpk:h-5 cpk:border-2 cpk:border-white cpk:border-t-transparent cpk:rounded-full cpk:animate-spin" })
5915
+ });
5916
+ }
5917
+ function AttachmentPreview({ attachment }) {
5918
+ if (attachment.status === "uploading") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: "cpk:w-full cpk:h-full" });
5919
+ switch (attachment.type) {
5920
+ case "image": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ImagePreview, { attachment });
5921
+ case "audio": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AudioPreview, { attachment });
5922
+ case "video": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(VideoPreview, { attachment });
5923
+ case "document": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DocumentPreview, { attachment });
5924
+ }
5925
+ }
5926
+ function Lightbox({ onClose, children }) {
5927
+ (0, react.useEffect)(() => {
5928
+ const handleKey = (e) => {
5929
+ if (e.key === "Escape") onClose();
5930
+ };
5931
+ document.addEventListener("keydown", handleKey);
5932
+ return () => document.removeEventListener("keydown", handleKey);
5933
+ }, [onClose]);
5934
+ if (typeof document === "undefined") return null;
5935
+ return (0, react_dom.createPortal)(/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5936
+ className: "cpk:fixed cpk:inset-0 cpk:z-[9999] cpk:flex cpk:items-center cpk:justify-center cpk:bg-black/80 cpk:animate-fade-in",
5937
+ onClick: onClose,
5938
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5939
+ onClick: onClose,
5940
+ className: "cpk:absolute cpk:top-4 cpk:right-4 cpk:text-white cpk:bg-white/10 cpk:hover:bg-white/20 cpk:rounded-full cpk:w-10 cpk:h-10 cpk:flex cpk:items-center cpk:justify-center cpk:cursor-pointer cpk:border-none cpk:z-10",
5941
+ "aria-label": "Close preview",
5942
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.X, { className: "cpk:w-5 cpk:h-5" })
5943
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5944
+ onClick: (e) => e.stopPropagation(),
5945
+ children
5946
+ })]
5947
+ }), document.body);
5948
+ }
5949
+ /**
5950
+ * Hook that manages lightbox open/close and uses the View Transition API to
5951
+ * morph the thumbnail into fullscreen content.
5952
+ *
5953
+ * The trick: `view-transition-name` must live on exactly ONE element at a time.
5954
+ * - Old state (thumbnail visible): name is on the thumbnail.
5955
+ * - New state (lightbox visible): name moves to the lightbox content.
5956
+ * `flushSync` ensures React commits the DOM change synchronously inside the
5957
+ * `startViewTransition` callback so the API can snapshot old → new correctly.
5958
+ */
5959
+ function useLightbox() {
5960
+ const thumbnailRef = (0, react.useRef)(null);
5961
+ const [open, setOpen] = (0, react.useState)(false);
5962
+ const vtName = (0, react.useId)();
5963
+ return {
5964
+ thumbnailRef,
5965
+ vtName,
5966
+ open,
5967
+ openLightbox: (0, react.useCallback)(() => {
5968
+ const thumb = thumbnailRef.current;
5969
+ const doc = document;
5970
+ if (doc.startViewTransition && thumb) {
5971
+ thumb.style.viewTransitionName = vtName;
5972
+ doc.startViewTransition(() => {
5973
+ thumb.style.viewTransitionName = "";
5974
+ (0, react_dom.flushSync)(() => setOpen(true));
5975
+ });
5976
+ } else setOpen(true);
5977
+ }, []),
5978
+ closeLightbox: (0, react.useCallback)(() => {
5979
+ const thumb = thumbnailRef.current;
5980
+ const doc = document;
5981
+ if (doc.startViewTransition && thumb) doc.startViewTransition(() => {
5982
+ (0, react_dom.flushSync)(() => setOpen(false));
5983
+ thumb.style.viewTransitionName = vtName;
5984
+ }).finished.then(() => {
5985
+ thumb.style.viewTransitionName = "";
5986
+ }).catch(() => {
5987
+ thumb.style.viewTransitionName = "";
5988
+ });
5989
+ else setOpen(false);
5990
+ }, [])
5991
+ };
5992
+ }
5993
+ function ImagePreview({ attachment }) {
5994
+ const src = (0, _copilotkit_shared.getSourceUrl)(attachment.source);
5995
+ const { thumbnailRef, vtName, open, openLightbox, closeLightbox } = useLightbox();
5996
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
5997
+ ref: thumbnailRef,
5998
+ src,
5999
+ alt: attachment.filename || "Image attachment",
6000
+ className: "cpk:w-full cpk:h-full cpk:object-cover cpk:cursor-pointer",
6001
+ onClick: openLightbox
6002
+ }), open && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Lightbox, {
6003
+ onClose: closeLightbox,
6004
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
6005
+ style: { viewTransitionName: vtName },
6006
+ src,
6007
+ alt: attachment.filename || "Image attachment",
6008
+ className: "cpk:max-w-[90vw] cpk:max-h-[90vh] cpk:object-contain cpk:rounded-lg"
6009
+ })
6010
+ })] });
6011
+ }
6012
+ function AudioPreview({ attachment }) {
6013
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6014
+ className: "cpk:flex cpk:flex-col cpk:gap-1 cpk:w-full",
6015
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("audio", {
6016
+ src: (0, _copilotkit_shared.getSourceUrl)(attachment.source),
6017
+ controls: true,
6018
+ preload: "metadata",
6019
+ className: "cpk:w-full cpk:h-8"
6020
+ }), attachment.filename && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6021
+ className: "cpk:text-xs cpk:font-medium cpk:overflow-hidden cpk:text-ellipsis cpk:whitespace-nowrap",
6022
+ children: attachment.filename
6023
+ })]
6024
+ });
6025
+ }
6026
+ function VideoPreview({ attachment }) {
6027
+ const src = (0, _copilotkit_shared.getSourceUrl)(attachment.source);
6028
+ const { thumbnailRef, vtName, open, openLightbox, closeLightbox } = useLightbox();
6029
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
6030
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6031
+ ref: thumbnailRef,
6032
+ className: "cpk:w-full cpk:h-full",
6033
+ children: attachment.thumbnail ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
6034
+ src: attachment.thumbnail,
6035
+ alt: attachment.filename || "Video thumbnail",
6036
+ className: "cpk:w-full cpk:h-full cpk:object-cover"
6037
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("video", {
6038
+ src,
6039
+ preload: "metadata",
6040
+ muted: true,
6041
+ className: "cpk:w-full cpk:h-full cpk:object-cover"
6042
+ })
6043
+ }),
6044
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
6045
+ onClick: openLightbox,
6046
+ className: "cpk:absolute cpk:inset-0 cpk:flex cpk:items-center cpk:justify-center cpk:z-10 cpk:cursor-pointer cpk:bg-black/20 cpk:border-none cpk:p-0",
6047
+ "aria-label": "Play video",
6048
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6049
+ className: "cpk:w-8 cpk:h-8 cpk:rounded-full cpk:bg-black/60 cpk:flex cpk:items-center cpk:justify-center",
6050
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Play, { className: "cpk:w-4 cpk:h-4 cpk:text-white cpk:ml-0.5" })
6051
+ })
6052
+ }),
6053
+ open && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Lightbox, {
6054
+ onClose: closeLightbox,
6055
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("video", {
6056
+ style: { viewTransitionName: vtName },
6057
+ src,
6058
+ controls: true,
6059
+ autoPlay: true,
6060
+ className: "cpk:max-w-[90vw] cpk:max-h-[90vh] cpk:rounded-lg"
6061
+ })
6062
+ })
6063
+ ] });
6064
+ }
6065
+ function isPdf(mimeType) {
6066
+ return !!mimeType && mimeType.includes("pdf");
6067
+ }
6068
+ function isText(mimeType) {
6069
+ return !!mimeType && mimeType.startsWith("text/");
6070
+ }
6071
+ function canPreviewInBrowser(mimeType) {
6072
+ return isPdf(mimeType) || isText(mimeType);
6073
+ }
6074
+ /**
6075
+ * Convert a base64-encoded data source to a blob: URL that browsers will
6076
+ * render inside an iframe (data: URLs are blocked for PDFs in most browsers).
6077
+ */
6078
+ function useBlobUrl(attachment) {
6079
+ const [url, setUrl] = (0, react.useState)(null);
6080
+ (0, react.useEffect)(() => {
6081
+ if (attachment.source.type !== "data") return;
6082
+ try {
6083
+ const binary = atob(attachment.source.value);
6084
+ const bytes = new Uint8Array(binary.length);
6085
+ for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
6086
+ const blob = new Blob([bytes], { type: attachment.source.mimeType || "application/octet-stream" });
6087
+ const blobUrl = URL.createObjectURL(blob);
6088
+ setUrl(blobUrl);
6089
+ return () => URL.revokeObjectURL(blobUrl);
6090
+ } catch (error) {
6091
+ console.error("[CopilotKit] Failed to decode attachment data:", error);
6092
+ setUrl(null);
6093
+ }
6094
+ }, [
6095
+ attachment.source.type,
6096
+ attachment.source.value,
6097
+ attachment.source.mimeType
6098
+ ]);
6099
+ if (attachment.source.type === "url") return attachment.source.value;
6100
+ return url;
6101
+ }
6102
+ function DocumentLightboxContent({ attachment, vtName }) {
6103
+ const mimeType = attachment.source.mimeType;
6104
+ const blobUrl = useBlobUrl(attachment);
6105
+ if (isPdf(mimeType)) {
6106
+ if (!blobUrl) return null;
6107
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("iframe", {
6108
+ style: { viewTransitionName: vtName },
6109
+ src: blobUrl,
6110
+ title: attachment.filename || "PDF preview",
6111
+ className: "cpk:w-[90vw] cpk:h-[90vh] cpk:max-w-[1000px] cpk:rounded-lg cpk:bg-white"
6112
+ });
6113
+ }
6114
+ if (isText(mimeType)) {
6115
+ const textContent = attachment.source.type === "data" ? (() => {
6116
+ try {
6117
+ return atob(attachment.source.value);
6118
+ } catch (_unused) {
6119
+ return attachment.source.value;
6120
+ }
6121
+ })() : null;
6122
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6123
+ style: { viewTransitionName: vtName },
6124
+ className: "cpk:w-[90vw] cpk:max-w-[800px] cpk:max-h-[90vh] cpk:overflow-auto cpk:rounded-lg cpk:bg-white cpk:dark:bg-gray-900 cpk:p-6",
6125
+ children: [attachment.filename && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6126
+ className: "cpk:text-sm cpk:font-medium cpk:text-gray-500 cpk:dark:text-gray-400 cpk:mb-4 cpk:pb-2 cpk:border-b cpk:border-gray-200 cpk:dark:border-gray-700",
6127
+ children: attachment.filename
6128
+ }), textContent ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", {
6129
+ className: "cpk:text-sm cpk:whitespace-pre-wrap cpk:break-words cpk:text-gray-800 cpk:dark:text-gray-200 cpk:font-mono cpk:m-0",
6130
+ children: textContent
6131
+ }) : blobUrl ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("iframe", {
6132
+ src: blobUrl,
6133
+ title: attachment.filename || "Text preview",
6134
+ className: "cpk:w-full cpk:h-[80vh] cpk:border-none"
6135
+ }) : null]
6136
+ });
6137
+ }
4433
6138
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4434
- "data-copilotkit": true,
4435
- "data-testid": "copilot-message-list",
4436
- className: (0, tailwind_merge.twMerge)("copilotKitMessages cpk:flex cpk:flex-col", className),
4437
- ...props,
6139
+ style: { viewTransitionName: vtName },
6140
+ className: "cpk:flex cpk:flex-col cpk:items-center cpk:gap-4 cpk:p-8 cpk:rounded-lg cpk:bg-white cpk:dark:bg-gray-900",
4438
6141
  children: [
4439
- messageElements,
4440
- interruptElement,
4441
- showCursor && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
4442
- className: "cpk:mt-2",
4443
- children: renderSlot(cursor, CopilotChatMessageView.Cursor, {})
6142
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6143
+ className: "cpk:w-16 cpk:h-16 cpk:rounded-xl cpk:bg-primary cpk:text-primary-foreground cpk:flex cpk:items-center cpk:justify-center cpk:text-xl cpk:font-bold",
6144
+ children: (0, _copilotkit_shared.getDocumentIcon)(mimeType !== null && mimeType !== void 0 ? mimeType : "")
6145
+ }),
6146
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6147
+ className: "cpk:text-center",
6148
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6149
+ className: "cpk:text-base cpk:font-medium cpk:text-gray-800 cpk:dark:text-gray-200",
6150
+ children: attachment.filename || "Document"
6151
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6152
+ className: "cpk:text-sm cpk:text-gray-500 cpk:dark:text-gray-400 cpk:mt-1",
6153
+ children: [mimeType || "Unknown type", attachment.size != null && ` · ${(0, _copilotkit_shared.formatFileSize)(attachment.size)}`]
6154
+ })]
6155
+ }),
6156
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6157
+ className: "cpk:text-xs cpk:text-gray-400 cpk:dark:text-gray-500",
6158
+ children: "No preview available for this file type"
4444
6159
  })
4445
6160
  ]
4446
6161
  });
4447
6162
  }
4448
- CopilotChatMessageView.Cursor = function Cursor({ className, ...props }) {
4449
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
4450
- "data-testid": "copilot-loading-cursor",
4451
- className: (0, tailwind_merge.twMerge)("cpk:w-[11px] cpk:h-[11px] cpk:rounded-full cpk:bg-foreground cpk:animate-pulse-cursor cpk:ml-1", className),
4452
- ...props
4453
- });
4454
- };
6163
+ function DocumentPreview({ attachment }) {
6164
+ const { thumbnailRef, vtName, open, openLightbox, closeLightbox } = useLightbox();
6165
+ const mimeType = attachment.source.mimeType;
6166
+ const previewable = canPreviewInBrowser(mimeType);
6167
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6168
+ ref: thumbnailRef,
6169
+ className: cn("cpk:flex cpk:items-center cpk:gap-2", previewable && "cpk:cursor-pointer"),
6170
+ onClick: previewable ? openLightbox : void 0,
6171
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6172
+ className: "cpk:w-8 cpk:h-8 cpk:rounded-md cpk:bg-primary cpk:text-primary-foreground cpk:flex cpk:items-center cpk:justify-center cpk:text-[10px] cpk:font-semibold cpk:shrink-0",
6173
+ children: (0, _copilotkit_shared.getDocumentIcon)(mimeType !== null && mimeType !== void 0 ? mimeType : "")
6174
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6175
+ className: "cpk:flex cpk:flex-col cpk:min-w-0",
6176
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6177
+ className: "cpk:text-xs cpk:font-medium cpk:break-all cpk:leading-tight",
6178
+ children: attachment.filename || "Document"
6179
+ }), attachment.size != null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6180
+ className: "cpk:text-[11px] cpk:text-muted-foreground",
6181
+ children: (0, _copilotkit_shared.formatFileSize)(attachment.size)
6182
+ })]
6183
+ })]
6184
+ }), open && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Lightbox, {
6185
+ onClose: closeLightbox,
6186
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DocumentLightboxContent, {
6187
+ attachment,
6188
+ vtName
6189
+ })
6190
+ })] });
6191
+ }
4455
6192
 
4456
6193
  //#endregion
4457
6194
  //#region src/v2/hooks/use-keyboard-height.tsx
@@ -4497,7 +6234,19 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4497
6234
  //#endregion
4498
6235
  //#region src/v2/components/chat/CopilotChatView.tsx
4499
6236
  const FEATHER_HEIGHT = 96;
4500
- function CopilotChatView({ messageView, input, scrollView, suggestionView, welcomeScreen, messages = [], autoScroll = true, isRunning = false, suggestions, suggestionLoadingIndexes, onSelectSuggestion, onSubmitMessage, onStop, inputMode, inputValue, onInputChange, onStartTranscribe, onCancelTranscribe, onFinishTranscribe, onFinishTranscribeWithAudio, disclaimer, children, className, ...props }) {
6237
+ function DropOverlay() {
6238
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6239
+ 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"),
6240
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6241
+ className: "cpk:flex cpk:flex-col cpk:items-center cpk:gap-2 cpk:text-primary/70",
6242
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Upload, { className: "cpk:w-8 cpk:h-8" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6243
+ className: "cpk:text-sm cpk:font-medium",
6244
+ children: "Drop files here"
6245
+ })]
6246
+ })
6247
+ });
6248
+ }
6249
+ 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 }) {
4501
6250
  const inputContainerRef = (0, react.useRef)(null);
4502
6251
  const [inputContainerHeight, setInputContainerHeight] = (0, react.useState)(0);
4503
6252
  const [isResizing, setIsResizing] = (0, react.useState)(false);
@@ -4544,6 +6293,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4544
6293
  onCancelTranscribe,
4545
6294
  onFinishTranscribe,
4546
6295
  onFinishTranscribeWithAudio,
6296
+ onAddFile,
4547
6297
  positioning: "static",
4548
6298
  keyboardHeight: isKeyboardOpen ? keyboardHeight : 0,
4549
6299
  containerRef: inputContainerRef,
@@ -4584,21 +6334,34 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4584
6334
  onCancelTranscribe,
4585
6335
  onFinishTranscribe,
4586
6336
  onFinishTranscribeWithAudio,
6337
+ onAddFile,
4587
6338
  positioning: "static",
4588
6339
  showDisclaimer: true,
4589
6340
  ...disclaimer !== void 0 ? { disclaimer } : {}
4590
6341
  });
4591
- const BoundWelcomeScreen = renderSlot(welcomeScreen === true ? void 0 : welcomeScreen, CopilotChatView.WelcomeScreen, {
4592
- input: BoundInputForWelcome,
6342
+ const welcomeScreenSlot = welcomeScreen === true ? void 0 : welcomeScreen;
6343
+ const inputWithAttachments = /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6344
+ className: "cpk:w-full",
6345
+ children: [attachments && attachments.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopilotChatAttachmentQueue, {
6346
+ attachments,
6347
+ onRemoveAttachment: (id) => onRemoveAttachment === null || onRemoveAttachment === void 0 ? void 0 : onRemoveAttachment(id),
6348
+ className: "cpk:mb-2"
6349
+ }), BoundInputForWelcome]
6350
+ });
6351
+ const BoundWelcomeScreen = renderSlot(welcomeScreenSlot, CopilotChatView.WelcomeScreen, {
6352
+ input: inputWithAttachments,
4593
6353
  suggestionView: BoundSuggestionView !== null && BoundSuggestionView !== void 0 ? BoundSuggestionView : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, {})
4594
6354
  });
4595
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6355
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4596
6356
  "data-copilotkit": true,
4597
6357
  "data-testid": "copilot-chat",
4598
6358
  "data-copilot-running": isRunning ? "true" : "false",
4599
- className: (0, tailwind_merge.twMerge)("copilotKitChat cpk:relative cpk:h-full cpk:flex cpk:flex-col", className),
6359
+ onDragOver,
6360
+ onDragLeave,
6361
+ onDrop,
6362
+ className: cn("copilotKitChat cpk:relative cpk:h-full cpk:flex cpk:flex-col", className),
4600
6363
  ...props,
4601
- children: BoundWelcomeScreen
6364
+ children: [dragOver && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DropOverlay, {}), BoundWelcomeScreen]
4602
6365
  });
4603
6366
  }
4604
6367
  if (children) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
@@ -4615,39 +6378,67 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4615
6378
  "data-copilotkit": true,
4616
6379
  "data-testid": "copilot-chat",
4617
6380
  "data-copilot-running": isRunning ? "true" : "false",
4618
- className: (0, tailwind_merge.twMerge)("copilotKitChat cpk:relative cpk:h-full cpk:flex cpk:flex-col", className),
6381
+ onDragOver,
6382
+ onDragLeave,
6383
+ onDrop,
6384
+ className: cn("copilotKitChat cpk:relative cpk:h-full cpk:flex cpk:flex-col", className),
4619
6385
  ...props,
4620
- children: [BoundScrollView, BoundInput]
6386
+ children: [
6387
+ dragOver && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DropOverlay, {}),
6388
+ BoundScrollView,
6389
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6390
+ className: "cpk:max-w-3xl cpk:mx-auto cpk:w-full",
6391
+ children: attachments && attachments.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopilotChatAttachmentQueue, {
6392
+ attachments,
6393
+ onRemoveAttachment: (id) => onRemoveAttachment === null || onRemoveAttachment === void 0 ? void 0 : onRemoveAttachment(id),
6394
+ className: "cpk:px-4"
6395
+ })
6396
+ }),
6397
+ BoundInput
6398
+ ]
4621
6399
  });
4622
6400
  }
4623
6401
  (function(_CopilotChatView) {
4624
6402
  const ScrollContent = ({ children, scrollToBottomButton, feather, inputContainerHeight, isResizing }) => {
4625
- const { isAtBottom, scrollToBottom } = (0, use_stick_to_bottom.useStickToBottomContext)();
6403
+ const { isAtBottom, scrollToBottom, scrollRef } = (0, use_stick_to_bottom.useStickToBottomContext)();
6404
+ const [scrollEl, setScrollEl] = (0, react.useState)(null);
6405
+ (0, react.useLayoutEffect)(() => {
6406
+ var _scrollRef$current;
6407
+ setScrollEl((_scrollRef$current = scrollRef.current) !== null && _scrollRef$current !== void 0 ? _scrollRef$current : null);
6408
+ }, []);
4626
6409
  const BoundFeather = renderSlot(feather, CopilotChatView.Feather, {});
4627
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
4628
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(use_stick_to_bottom.StickToBottom.Content, {
4629
- className: "cpk:overflow-y-auto cpk:overflow-x-hidden",
4630
- style: {
4631
- flex: "1 1 0%",
4632
- minHeight: 0
4633
- },
4634
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
4635
- className: "cpk:px-4 cpk:sm:px-0 cpk:[div[data-sidebar-chat]_&]:px-8 cpk:[div[data-popup-chat]_&]:px-6",
4636
- children
6410
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ScrollElementContext.Provider, {
6411
+ value: scrollEl,
6412
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
6413
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(use_stick_to_bottom.StickToBottom.Content, {
6414
+ className: "cpk:overflow-y-auto cpk:overflow-x-hidden",
6415
+ style: {
6416
+ flex: "1 1 0%",
6417
+ minHeight: 0
6418
+ },
6419
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6420
+ className: "cpk:px-4 cpk:sm:px-0 cpk:[div[data-sidebar-chat]_&]:px-8 cpk:[div[data-popup-chat]_&]:px-6",
6421
+ children
6422
+ })
6423
+ }),
6424
+ BoundFeather,
6425
+ !isAtBottom && !isResizing && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6426
+ className: "cpk:absolute cpk:inset-x-0 cpk:flex cpk:justify-center cpk:z-30 cpk:pointer-events-none",
6427
+ style: { bottom: `${inputContainerHeight + FEATHER_HEIGHT + 16}px` },
6428
+ children: renderSlot(scrollToBottomButton, CopilotChatView.ScrollToBottomButton, { onClick: () => scrollToBottom() })
4637
6429
  })
4638
- }),
4639
- BoundFeather,
4640
- !isAtBottom && !isResizing && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
4641
- className: "cpk:absolute cpk:inset-x-0 cpk:flex cpk:justify-center cpk:z-30 cpk:pointer-events-none",
4642
- style: { bottom: `${inputContainerHeight + FEATHER_HEIGHT + 16}px` },
4643
- children: renderSlot(scrollToBottomButton, CopilotChatView.ScrollToBottomButton, { onClick: () => scrollToBottom() })
4644
- })
4645
- ] });
6430
+ ] })
6431
+ });
4646
6432
  };
4647
6433
  _CopilotChatView.ScrollView = ({ children, autoScroll = true, scrollToBottomButton, feather, inputContainerHeight = 0, isResizing = false, className, ...props }) => {
4648
6434
  const [hasMounted, setHasMounted] = (0, react.useState)(false);
4649
6435
  const { scrollRef, contentRef, scrollToBottom } = (0, use_stick_to_bottom.useStickToBottom)();
4650
6436
  const [showScrollButton, setShowScrollButton] = (0, react.useState)(false);
6437
+ const [nonAutoScrollEl, setNonAutoScrollEl] = (0, react.useState)(null);
6438
+ const nonAutoScrollRefCallback = (0, react.useCallback)((el) => {
6439
+ scrollRef.current = el;
6440
+ setNonAutoScrollEl(el);
6441
+ }, []);
4651
6442
  (0, react.useEffect)(() => {
4652
6443
  setHasMounted(true);
4653
6444
  }, []);
@@ -4676,23 +6467,26 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4676
6467
  });
4677
6468
  if (!autoScroll) {
4678
6469
  const BoundFeather = renderSlot(feather, CopilotChatView.Feather, {});
4679
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4680
- ref: scrollRef,
4681
- className: cn("cpk:h-full cpk:max-h-full cpk:flex cpk:flex-col cpk:min-h-0 cpk:overflow-y-auto cpk:overflow-x-hidden cpk:relative", className),
4682
- ...props,
4683
- children: [
4684
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
4685
- ref: contentRef,
4686
- className: "cpk:px-4 cpk:sm:px-0 cpk:[div[data-sidebar-chat]_&]:px-8 cpk:[div[data-popup-chat]_&]:px-6",
4687
- children
4688
- }),
4689
- BoundFeather,
4690
- showScrollButton && !isResizing && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
4691
- className: "cpk:absolute cpk:inset-x-0 cpk:flex cpk:justify-center cpk:z-30 cpk:pointer-events-none",
4692
- style: { bottom: `${inputContainerHeight + FEATHER_HEIGHT + 16}px` },
4693
- children: renderSlot(scrollToBottomButton, CopilotChatView.ScrollToBottomButton, { onClick: () => scrollToBottom() })
4694
- })
4695
- ]
6470
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ScrollElementContext.Provider, {
6471
+ value: nonAutoScrollEl,
6472
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6473
+ ref: nonAutoScrollRefCallback,
6474
+ className: cn("cpk:h-full cpk:max-h-full cpk:flex cpk:flex-col cpk:min-h-0 cpk:overflow-y-auto cpk:overflow-x-hidden cpk:relative", className),
6475
+ ...props,
6476
+ children: [
6477
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6478
+ ref: contentRef,
6479
+ className: "cpk:px-4 cpk:sm:px-0 cpk:[div[data-sidebar-chat]_&]:px-8 cpk:[div[data-popup-chat]_&]:px-6",
6480
+ children
6481
+ }),
6482
+ BoundFeather,
6483
+ showScrollButton && !isResizing && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6484
+ className: "cpk:absolute cpk:inset-x-0 cpk:flex cpk:justify-center cpk:z-30 cpk:pointer-events-none",
6485
+ style: { bottom: `${inputContainerHeight + FEATHER_HEIGHT + 16}px` },
6486
+ children: renderSlot(scrollToBottomButton, CopilotChatView.ScrollToBottomButton, { onClick: () => scrollToBottom() })
6487
+ })
6488
+ ]
6489
+ })
4696
6490
  });
4697
6491
  }
4698
6492
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(use_stick_to_bottom.StickToBottom, {
@@ -4887,15 +6681,19 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4887
6681
 
4888
6682
  //#endregion
4889
6683
  //#region src/v2/components/chat/CopilotChat.tsx
4890
- function CopilotChat({ agentId, threadId, labels, chatView, isModalDefaultOpen, onError, ...props }) {
4891
- var _ref;
6684
+ function CopilotChat({ agentId, threadId, labels, chatView, isModalDefaultOpen, attachments: attachmentsConfig, onError, throttleMs, ...props }) {
6685
+ var _ref, _attachmentsConfig$ac;
4892
6686
  const existingConfig = useCopilotChatConfiguration();
4893
6687
  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;
4894
6688
  const resolvedThreadId = (0, react.useMemo)(() => {
4895
6689
  var _ref2;
4896
6690
  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)();
4897
6691
  }, [threadId, existingConfig === null || existingConfig === void 0 ? void 0 : existingConfig.threadId]);
4898
- const { agent } = useAgent({ agentId: resolvedAgentId });
6692
+ const { agent } = useAgent({
6693
+ agentId: resolvedAgentId,
6694
+ threadId: resolvedThreadId,
6695
+ throttleMs
6696
+ });
4899
6697
  const { copilotkit } = useCopilotKit();
4900
6698
  const { suggestions: autoSuggestions } = useSuggestions({ agentId: resolvedAgentId });
4901
6699
  const { checkFeature } = useLicenseContext();
@@ -4928,6 +6726,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4928
6726
  const [inputValue, setInputValue] = (0, react.useState)("");
4929
6727
  const [transcriptionError, setTranscriptionError] = (0, react.useState)(null);
4930
6728
  const [isTranscribing, setIsTranscribing] = (0, react.useState)(false);
6729
+ const { attachments: selectedAttachments, enabled: attachmentsEnabled, dragOver, fileInputRef, containerRef: chatContainerRef, handleFileUpload, handleDragOver, handleDragLeave, handleDrop, removeAttachment, consumeAttachments } = useAttachments({ config: attachmentsConfig });
4931
6730
  const isTranscriptionEnabled = copilotkit.audioFileTranscriptionEnabled;
4932
6731
  const isMediaRecorderSupported = typeof window !== "undefined" && typeof MediaRecorder !== "undefined";
4933
6732
  const { messageView: providedMessageView, suggestionView: providedSuggestionView, onStop: providedStopHandler, ...restProps } = props;
@@ -4943,7 +6742,6 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4943
6742
  console.error("CopilotChat: connectAgent failed", error);
4944
6743
  }
4945
6744
  };
4946
- agent.threadId = resolvedThreadId;
4947
6745
  connect(agent);
4948
6746
  return () => {
4949
6747
  detached = true;
@@ -4956,7 +6754,31 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4956
6754
  resolvedAgentId
4957
6755
  ]);
4958
6756
  const onSubmitInput = (0, react.useCallback)(async (value) => {
4959
- agent.addMessage({
6757
+ if (selectedAttachments.some((a) => a.status === "uploading")) {
6758
+ console.error("[CopilotKit] Cannot send while attachments are uploading");
6759
+ return;
6760
+ }
6761
+ const readyAttachments = consumeAttachments();
6762
+ if (readyAttachments.length > 0) {
6763
+ const contentParts = [];
6764
+ if (value.trim()) contentParts.push({
6765
+ type: "text",
6766
+ text: value
6767
+ });
6768
+ for (const att of readyAttachments) contentParts.push({
6769
+ type: att.type,
6770
+ source: att.source,
6771
+ metadata: {
6772
+ ...att.filename ? { filename: att.filename } : {},
6773
+ ...att.metadata
6774
+ }
6775
+ });
6776
+ agent.addMessage({
6777
+ id: (0, _copilotkit_shared.randomUUID)(),
6778
+ role: "user",
6779
+ content: contentParts
6780
+ });
6781
+ } else agent.addMessage({
4960
6782
  id: (0, _copilotkit_shared.randomUUID)(),
4961
6783
  role: "user",
4962
6784
  content: value
@@ -4967,7 +6789,11 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4967
6789
  } catch (error) {
4968
6790
  console.error("CopilotChat: runAgent failed", error);
4969
6791
  }
4970
- }, [agent]);
6792
+ }, [
6793
+ agent,
6794
+ selectedAttachments,
6795
+ consumeAttachments
6796
+ ]);
4971
6797
  const handleSelectSuggestion = (0, react.useCallback)(async (suggestion) => {
4972
6798
  agent.addMessage({
4973
6799
  id: (0, _copilotkit_shared.randomUUID)(),
@@ -5054,21 +6880,37 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
5054
6880
  return () => clearTimeout(timer);
5055
6881
  }
5056
6882
  }, [transcriptionError]);
5057
- const mergedProps = (0, ts_deepmerge.merge)({
6883
+ const stableMessageView = useShallowStableRef(typeof providedMessageView === "string" ? { className: providedMessageView } : providedMessageView);
6884
+ const stableSuggestionView = useShallowStableRef(providedSuggestionView);
6885
+ const handleAddFile = (0, react.useCallback)(() => {
6886
+ setTimeout(() => {
6887
+ var _fileInputRef$current;
6888
+ (_fileInputRef$current = fileInputRef.current) === null || _fileInputRef$current === void 0 || _fileInputRef$current.click();
6889
+ }, 100);
6890
+ }, []);
6891
+ const mergedProps = {
5058
6892
  isRunning: agent.isRunning,
5059
6893
  suggestions: autoSuggestions,
5060
6894
  onSelectSuggestion: handleSelectSuggestion,
5061
- suggestionView: providedSuggestionView
5062
- }, {
5063
- ...restProps,
5064
- ...typeof providedMessageView === "string" ? { messageView: { className: providedMessageView } } : providedMessageView !== void 0 ? { messageView: providedMessageView } : {}
5065
- });
6895
+ suggestionView: stableSuggestionView,
6896
+ ...restProps
6897
+ };
6898
+ if (stableMessageView !== void 0) mergedProps.messageView = stableMessageView;
5066
6899
  const hasMessages = agent.messages.length > 0;
5067
6900
  const effectiveStopHandler = agent.isRunning && hasMessages ? providedStopHandler !== null && providedStopHandler !== void 0 ? providedStopHandler : stopCurrentRun : providedStopHandler;
5068
6901
  const showTranscription = isTranscriptionEnabled && isMediaRecorderSupported;
5069
6902
  const effectiveMode = isTranscribing ? "processing" : transcribeMode;
5070
- const RenderedChatView = renderSlot(chatView, CopilotChatView, (0, ts_deepmerge.merge)(mergedProps, {
5071
- messages: (0, react.useMemo)(() => [...agent.messages], [JSON.stringify(agent.messages)]),
6903
+ const messages = (0, react.useMemo)(() => [...agent.messages], [agent.messages.map((m) => {
6904
+ const contentKey = typeof m.content === "string" ? m.content.length : Array.isArray(m.content) ? m.content.length : 0;
6905
+ const toolCallsKey = "toolCalls" in m && Array.isArray(m.toolCalls) ? m.toolCalls.map((tc) => {
6906
+ var _tc$function$argument, _tc$function;
6907
+ return `${tc.id}:${(_tc$function$argument = (_tc$function = tc.function) === null || _tc$function === void 0 || (_tc$function = _tc$function.arguments) === null || _tc$function === void 0 ? void 0 : _tc$function.length) !== null && _tc$function$argument !== void 0 ? _tc$function$argument : 0}`;
6908
+ }).join(";") : "";
6909
+ return `${m.id}:${m.role}:${contentKey}:${toolCallsKey}`;
6910
+ }).join(",")]);
6911
+ const RenderedChatView = renderSlot(chatView, CopilotChatView, {
6912
+ ...mergedProps,
6913
+ messages,
5072
6914
  onSubmitMessage: onSubmitInput,
5073
6915
  onStop: effectiveStopHandler,
5074
6916
  inputMode: effectiveMode,
@@ -5077,32 +6919,51 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
5077
6919
  onStartTranscribe: showTranscription ? handleStartTranscribe : void 0,
5078
6920
  onCancelTranscribe: showTranscription ? handleCancelTranscribe : void 0,
5079
6921
  onFinishTranscribe: showTranscription ? handleFinishTranscribe : void 0,
5080
- onFinishTranscribeWithAudio: showTranscription ? handleFinishTranscribeWithAudio : void 0
5081
- }));
5082
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(CopilotChatConfigurationProvider, {
6922
+ onFinishTranscribeWithAudio: showTranscription ? handleFinishTranscribeWithAudio : void 0,
6923
+ attachments: selectedAttachments,
6924
+ onRemoveAttachment: removeAttachment,
6925
+ onAddFile: attachmentsEnabled ? handleAddFile : void 0,
6926
+ dragOver,
6927
+ onDragOver: handleDragOver,
6928
+ onDragLeave: handleDragLeave,
6929
+ onDrop: handleDrop
6930
+ });
6931
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopilotChatConfigurationProvider, {
5083
6932
  agentId: resolvedAgentId,
5084
6933
  threadId: resolvedThreadId,
5085
6934
  labels,
5086
6935
  isModalDefaultOpen,
5087
- children: [
5088
- !isChatLicensed && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InlineFeatureWarning, { featureName: "Chat" }),
5089
- transcriptionError && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5090
- style: {
5091
- position: "absolute",
5092
- bottom: "100px",
5093
- left: "50%",
5094
- transform: "translateX(-50%)",
5095
- backgroundColor: "#ef4444",
5096
- color: "white",
5097
- padding: "8px 16px",
5098
- borderRadius: "8px",
5099
- fontSize: "14px",
5100
- zIndex: 50
5101
- },
5102
- children: transcriptionError
5103
- }),
5104
- RenderedChatView
5105
- ]
6936
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6937
+ ref: chatContainerRef,
6938
+ style: { display: "contents" },
6939
+ children: [
6940
+ attachmentsEnabled && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
6941
+ type: "file",
6942
+ multiple: true,
6943
+ ref: fileInputRef,
6944
+ onChange: handleFileUpload,
6945
+ accept: (_attachmentsConfig$ac = attachmentsConfig === null || attachmentsConfig === void 0 ? void 0 : attachmentsConfig.accept) !== null && _attachmentsConfig$ac !== void 0 ? _attachmentsConfig$ac : "*/*",
6946
+ style: { display: "none" }
6947
+ }),
6948
+ !isChatLicensed && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InlineFeatureWarning, { featureName: "Chat" }),
6949
+ transcriptionError && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6950
+ style: {
6951
+ position: "absolute",
6952
+ bottom: "100px",
6953
+ left: "50%",
6954
+ transform: "translateX(-50%)",
6955
+ backgroundColor: "#ef4444",
6956
+ color: "white",
6957
+ padding: "8px 16px",
6958
+ borderRadius: "8px",
6959
+ fontSize: "14px",
6960
+ zIndex: 50
6961
+ },
6962
+ children: transcriptionError
6963
+ }),
6964
+ RenderedChatView
6965
+ ]
6966
+ })
5106
6967
  });
5107
6968
  }
5108
6969
  (function(_CopilotChat) {
@@ -5969,6 +7830,227 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
5969
7830
  if (!context) throw new Error("useToast must be used within a ToastProvider");
5970
7831
  return context;
5971
7832
  }
7833
+ function formatBannerMessage(message) {
7834
+ const jsonMatch = message.match(/'message':\s*'([^']+)'/);
7835
+ if (jsonMatch) return jsonMatch[1];
7836
+ let cleaned = message.split(" - ")[0];
7837
+ cleaned = cleaned.split(": Error code")[0];
7838
+ cleaned = cleaned.replace(/:\s*\d{3}$/, "");
7839
+ cleaned = cleaned.replace(/See more:.*$/g, "");
7840
+ cleaned = cleaned.trim();
7841
+ return cleaned || "An error occurred.";
7842
+ }
7843
+ function extractUrl(message) {
7844
+ const markdownMatch = /\[([^\]]+)\]\(([^)]+)\)/.exec(message);
7845
+ if (markdownMatch) return {
7846
+ url: markdownMatch[2],
7847
+ text: "See More"
7848
+ };
7849
+ const plainMatch = /(https?:\/\/[^\s)]+)/.exec(message);
7850
+ if (plainMatch) return {
7851
+ url: plainMatch[0].replace(/[.,;:'"]*$/, ""),
7852
+ text: "See More"
7853
+ };
7854
+ return null;
7855
+ }
7856
+ function BannerErrorDisplay({ bannerError, onDismiss }) {
7857
+ const [detailsExpanded, setDetailsExpanded] = (0, react.useState)(false);
7858
+ const colors = getErrorColors(getErrorSeverity(bannerError));
7859
+ const details = bannerError.details;
7860
+ const link = extractUrl(bannerError.message);
7861
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7862
+ style: {
7863
+ position: "fixed",
7864
+ bottom: "20px",
7865
+ left: "50%",
7866
+ transform: "translateX(-50%)",
7867
+ zIndex: 9999,
7868
+ backgroundColor: colors.background,
7869
+ border: `1px solid ${colors.border}`,
7870
+ borderLeft: `4px solid ${colors.border}`,
7871
+ borderRadius: "8px",
7872
+ padding: "12px 16px",
7873
+ fontSize: "13px",
7874
+ boxShadow: "0 4px 12px rgba(0, 0, 0, 0.15)",
7875
+ backdropFilter: "blur(8px)",
7876
+ maxWidth: "min(90vw, 700px)",
7877
+ width: "100%",
7878
+ boxSizing: "border-box",
7879
+ overflow: "hidden"
7880
+ },
7881
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7882
+ style: {
7883
+ display: "flex",
7884
+ justifyContent: "space-between",
7885
+ alignItems: "center",
7886
+ gap: "10px"
7887
+ },
7888
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7889
+ style: {
7890
+ display: "flex",
7891
+ alignItems: "center",
7892
+ gap: "8px",
7893
+ flex: 1,
7894
+ minWidth: 0
7895
+ },
7896
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { style: {
7897
+ width: "12px",
7898
+ height: "12px",
7899
+ borderRadius: "50%",
7900
+ backgroundColor: colors.border,
7901
+ flexShrink: 0
7902
+ } }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7903
+ style: {
7904
+ display: "flex",
7905
+ alignItems: "center",
7906
+ gap: "10px",
7907
+ flex: 1,
7908
+ minWidth: 0
7909
+ },
7910
+ children: [
7911
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7912
+ style: {
7913
+ color: colors.text,
7914
+ lineHeight: "1.4",
7915
+ fontWeight: "400",
7916
+ fontSize: "13px",
7917
+ flex: 1,
7918
+ wordBreak: "break-all",
7919
+ overflowWrap: "break-word",
7920
+ maxWidth: "550px",
7921
+ overflow: "hidden",
7922
+ display: "-webkit-box",
7923
+ WebkitLineClamp: 10,
7924
+ WebkitBoxOrient: "vertical"
7925
+ },
7926
+ children: formatBannerMessage(bannerError.message)
7927
+ }),
7928
+ link && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
7929
+ onClick: () => window.open(link.url, "_blank", "noopener,noreferrer"),
7930
+ style: {
7931
+ background: colors.border,
7932
+ color: "white",
7933
+ border: "none",
7934
+ borderRadius: "5px",
7935
+ padding: "4px 10px",
7936
+ fontSize: "11px",
7937
+ fontWeight: "500",
7938
+ cursor: "pointer",
7939
+ transition: "all 0.2s ease",
7940
+ flexShrink: 0
7941
+ },
7942
+ onMouseEnter: (e) => {
7943
+ e.currentTarget.style.opacity = "0.9";
7944
+ e.currentTarget.style.transform = "translateY(-1px)";
7945
+ },
7946
+ onMouseLeave: (e) => {
7947
+ e.currentTarget.style.opacity = "1";
7948
+ e.currentTarget.style.transform = "translateY(0)";
7949
+ },
7950
+ children: link.text
7951
+ }),
7952
+ details && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
7953
+ onClick: () => setDetailsExpanded(!detailsExpanded),
7954
+ style: {
7955
+ background: "transparent",
7956
+ border: `1px solid ${colors.border}`,
7957
+ borderRadius: "5px",
7958
+ padding: "4px 10px",
7959
+ fontSize: "11px",
7960
+ fontWeight: "500",
7961
+ cursor: "pointer",
7962
+ color: colors.text,
7963
+ flexShrink: 0,
7964
+ transition: "all 0.2s ease"
7965
+ },
7966
+ onMouseEnter: (e) => {
7967
+ e.currentTarget.style.background = "rgba(0, 0, 0, 0.05)";
7968
+ },
7969
+ onMouseLeave: (e) => {
7970
+ e.currentTarget.style.background = "transparent";
7971
+ },
7972
+ children: detailsExpanded ? "Hide Details" : "Show Details"
7973
+ })
7974
+ ]
7975
+ })]
7976
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
7977
+ onClick: onDismiss,
7978
+ style: {
7979
+ background: "transparent",
7980
+ border: "none",
7981
+ color: colors.text,
7982
+ cursor: "pointer",
7983
+ padding: "2px",
7984
+ borderRadius: "3px",
7985
+ fontSize: "14px",
7986
+ lineHeight: "1",
7987
+ opacity: .6,
7988
+ transition: "all 0.2s ease",
7989
+ flexShrink: 0
7990
+ },
7991
+ title: "Dismiss",
7992
+ onMouseEnter: (e) => {
7993
+ e.currentTarget.style.opacity = "1";
7994
+ e.currentTarget.style.background = "rgba(0, 0, 0, 0.05)";
7995
+ },
7996
+ onMouseLeave: (e) => {
7997
+ e.currentTarget.style.opacity = "0.6";
7998
+ e.currentTarget.style.background = "transparent";
7999
+ },
8000
+ children: "x"
8001
+ })]
8002
+ }), detailsExpanded && details && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8003
+ style: {
8004
+ marginTop: "10px",
8005
+ padding: "10px",
8006
+ background: "rgba(0, 0, 0, 0.04)",
8007
+ borderRadius: "6px",
8008
+ fontSize: "11px",
8009
+ fontFamily: "monospace",
8010
+ color: colors.text,
8011
+ lineHeight: "1.5",
8012
+ maxHeight: "200px",
8013
+ overflowY: "auto",
8014
+ whiteSpace: "pre-wrap",
8015
+ wordBreak: "break-all"
8016
+ },
8017
+ children: [
8018
+ details.code && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [
8019
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: "Code:" }),
8020
+ " ",
8021
+ details.code
8022
+ ] }),
8023
+ details.originalMessage && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8024
+ style: { marginTop: "4px" },
8025
+ children: [
8026
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: "Message:" }),
8027
+ " ",
8028
+ details.originalMessage
8029
+ ]
8030
+ }),
8031
+ details.context && Object.keys(details.context).length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8032
+ style: { marginTop: "4px" },
8033
+ children: [
8034
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: "Context:" }),
8035
+ " ",
8036
+ JSON.stringify(details.context, null, 2)
8037
+ ]
8038
+ }),
8039
+ details.stack && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8040
+ style: {
8041
+ marginTop: "4px",
8042
+ opacity: .7
8043
+ },
8044
+ children: [
8045
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: "Stack:" }),
8046
+ "\n",
8047
+ details.stack
8048
+ ]
8049
+ })
8050
+ ]
8051
+ })]
8052
+ });
8053
+ }
5972
8054
  function ToastProvider({ enabled, children }) {
5973
8055
  const [toasts, setToasts] = (0, react.useState)([]);
5974
8056
  const [bannerError, setBannerErrorState] = (0, react.useState)(null);
@@ -6007,156 +8089,10 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
6007
8089
  };
6008
8090
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(ToastContext.Provider, {
6009
8091
  value,
6010
- children: [bannerError && (() => {
6011
- const colors = getErrorColors(getErrorSeverity(bannerError));
6012
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6013
- style: {
6014
- position: "fixed",
6015
- bottom: "20px",
6016
- left: "50%",
6017
- transform: "translateX(-50%)",
6018
- zIndex: 9999,
6019
- backgroundColor: colors.background,
6020
- border: `1px solid ${colors.border}`,
6021
- borderLeft: `4px solid ${colors.border}`,
6022
- borderRadius: "8px",
6023
- padding: "12px 16px",
6024
- fontSize: "13px",
6025
- boxShadow: "0 4px 12px rgba(0, 0, 0, 0.15)",
6026
- backdropFilter: "blur(8px)",
6027
- maxWidth: "min(90vw, 700px)",
6028
- width: "100%",
6029
- boxSizing: "border-box",
6030
- overflow: "hidden"
6031
- },
6032
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6033
- style: {
6034
- display: "flex",
6035
- justifyContent: "space-between",
6036
- alignItems: "center",
6037
- gap: "10px"
6038
- },
6039
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6040
- style: {
6041
- display: "flex",
6042
- alignItems: "center",
6043
- gap: "8px",
6044
- flex: 1,
6045
- minWidth: 0
6046
- },
6047
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { style: {
6048
- width: "12px",
6049
- height: "12px",
6050
- borderRadius: "50%",
6051
- backgroundColor: colors.border,
6052
- flexShrink: 0
6053
- } }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6054
- style: {
6055
- display: "flex",
6056
- alignItems: "center",
6057
- gap: "10px",
6058
- flex: 1,
6059
- minWidth: 0
6060
- },
6061
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6062
- style: {
6063
- color: colors.text,
6064
- lineHeight: "1.4",
6065
- fontWeight: "400",
6066
- fontSize: "13px",
6067
- flex: 1,
6068
- wordBreak: "break-all",
6069
- overflowWrap: "break-word",
6070
- maxWidth: "550px",
6071
- overflow: "hidden",
6072
- display: "-webkit-box",
6073
- WebkitLineClamp: 10,
6074
- WebkitBoxOrient: "vertical"
6075
- },
6076
- children: (() => {
6077
- let message = bannerError.message;
6078
- const jsonMatch = message.match(/'message':\s*'([^']+)'/);
6079
- if (jsonMatch) return jsonMatch[1];
6080
- message = message.split(" - ")[0];
6081
- message = message.split(": Error code")[0];
6082
- message = message.replace(/:\s*\d{3}$/, "");
6083
- message = message.replace(/See more:.*$/g, "");
6084
- message = message.trim();
6085
- return message || "Configuration error occurred.";
6086
- })()
6087
- }), (() => {
6088
- const message = bannerError.message;
6089
- const markdownLinkRegex = /\[([^\]]+)\]\(([^)]+)\)/g;
6090
- const plainUrlRegex = /(https?:\/\/[^\s)]+)/g;
6091
- let url = null;
6092
- let buttonText = "See More";
6093
- const markdownMatch = markdownLinkRegex.exec(message);
6094
- if (markdownMatch) {
6095
- url = markdownMatch[2];
6096
- buttonText = "See More";
6097
- } else {
6098
- const urlMatch = plainUrlRegex.exec(message);
6099
- if (urlMatch) {
6100
- url = urlMatch[0].replace(/[.,;:'"]*$/, "");
6101
- buttonText = "See More";
6102
- }
6103
- }
6104
- if (!url) return null;
6105
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
6106
- onClick: () => window.open(url, "_blank", "noopener,noreferrer"),
6107
- style: {
6108
- background: colors.border,
6109
- color: "white",
6110
- border: "none",
6111
- borderRadius: "5px",
6112
- padding: "4px 10px",
6113
- fontSize: "11px",
6114
- fontWeight: "500",
6115
- cursor: "pointer",
6116
- transition: "all 0.2s ease",
6117
- flexShrink: 0
6118
- },
6119
- onMouseEnter: (e) => {
6120
- e.currentTarget.style.opacity = "0.9";
6121
- e.currentTarget.style.transform = "translateY(-1px)";
6122
- },
6123
- onMouseLeave: (e) => {
6124
- e.currentTarget.style.opacity = "1";
6125
- e.currentTarget.style.transform = "translateY(0)";
6126
- },
6127
- children: buttonText
6128
- });
6129
- })()]
6130
- })]
6131
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
6132
- onClick: () => setBannerError(null),
6133
- style: {
6134
- background: "transparent",
6135
- border: "none",
6136
- color: colors.text,
6137
- cursor: "pointer",
6138
- padding: "2px",
6139
- borderRadius: "3px",
6140
- fontSize: "14px",
6141
- lineHeight: "1",
6142
- opacity: .6,
6143
- transition: "all 0.2s ease",
6144
- flexShrink: 0
6145
- },
6146
- title: "Dismiss",
6147
- onMouseEnter: (e) => {
6148
- e.currentTarget.style.opacity = "1";
6149
- e.currentTarget.style.background = "rgba(0, 0, 0, 0.05)";
6150
- },
6151
- onMouseLeave: (e) => {
6152
- e.currentTarget.style.opacity = "0.6";
6153
- e.currentTarget.style.background = "transparent";
6154
- },
6155
- children: "×"
6156
- })]
6157
- })
6158
- });
6159
- })(), children]
8092
+ children: [bannerError && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BannerErrorDisplay, {
8093
+ bannerError,
8094
+ onDismiss: () => setBannerError(null)
8095
+ }), children]
6160
8096
  });
6161
8097
  }
6162
8098
 
@@ -7075,12 +9011,21 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
7075
9011
  const { agent } = useAgent({ agentId: resolvedAgentId });
7076
9012
  usePredictStateSubscription(agent);
7077
9013
  (0, react.useEffect)(() => {
7078
- const subscription = copilotkit.subscribe({ onError: ({ error }) => {
7079
- setBannerError(new _copilotkit_shared.CopilotKitLowLevelError({
9014
+ const subscription = copilotkit.subscribe({ onError: ({ error, code, context }) => {
9015
+ if (error.name === "AbortError" || error.message === "Fetch is aborted" || error.message === "signal is aborted without reason" || error.message === "component unmounted" || !error.message) return;
9016
+ if (process.env.NODE_ENV === "development") console.error("[CopilotKit] Agent error:", error.message, "\n Code:", code, "\n Context:", context, "\n Stack:", error.stack);
9017
+ const ckError = new _copilotkit_shared.CopilotKitLowLevelError({
7080
9018
  error,
7081
9019
  message: error.message,
7082
9020
  url: typeof window !== "undefined" ? window.location.href : ""
7083
- }));
9021
+ });
9022
+ ckError.details = {
9023
+ code,
9024
+ context,
9025
+ stack: error.stack,
9026
+ originalMessage: error.message
9027
+ };
9028
+ setBannerError(ckError);
7084
9029
  } });
7085
9030
  return () => {
7086
9031
  subscription.unsubscribe();
@@ -7566,7 +9511,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
7566
9511
  children: [
7567
9512
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopilotListeners, {}),
7568
9513
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopilotKitErrorBridge, {}),
7569
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(CoAgentStateRendersProvider, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(MessagesTapProvider, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(CopilotMessages, { children: [memoizedChildren, /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RegisteredActionsRenderer, {})] }) }), bannerError && showDevConsole && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(UsageBanner, {
9514
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(CoAgentStateRendersProvider, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(MessagesTapProvider, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(CopilotMessages, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(react.default.Fragment, { children: memoizedChildren }, "children"), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RegisteredActionsRenderer, {}, "actions")] }) }), bannerError && showDevConsole && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(UsageBanner, {
7570
9515
  severity: bannerError.severity,
7571
9516
  message: bannerError.message,
7572
9517
  onClose: () => setBannerError(null),
@@ -7619,6 +9564,8 @@ Object.defineProperty(exports, 'CopilotChat', {
7619
9564
  }
7620
9565
  });
7621
9566
  exports.CopilotChatAssistantMessage = CopilotChatAssistantMessage_default;
9567
+ exports.CopilotChatAttachmentQueue = CopilotChatAttachmentQueue;
9568
+ exports.CopilotChatAttachmentRenderer = CopilotChatAttachmentRenderer;
7622
9569
  exports.CopilotChatAudioRecorder = CopilotChatAudioRecorder;
7623
9570
  exports.CopilotChatConfigurationProvider = CopilotChatConfigurationProvider;
7624
9571
  exports.CopilotChatInput = CopilotChatInput_default;
@@ -7659,12 +9606,20 @@ Object.defineProperty(exports, 'CopilotSidebarView', {
7659
9606
  exports.MCPAppsActivityContentSchema = MCPAppsActivityContentSchema;
7660
9607
  exports.MCPAppsActivityRenderer = MCPAppsActivityRenderer;
7661
9608
  exports.MCPAppsActivityType = MCPAppsActivityType;
9609
+ exports.SandboxFunctionsContext = SandboxFunctionsContext;
7662
9610
  exports.UseAgentUpdate = UseAgentUpdate;
7663
9611
  exports.WildcardToolCallRender = WildcardToolCallRender;
9612
+ Object.defineProperty(exports, 'a2uiDefaultTheme', {
9613
+ enumerable: true,
9614
+ get: function () {
9615
+ return _copilotkit_a2ui_renderer.defaultTheme;
9616
+ }
9617
+ });
7664
9618
  exports.createA2UIMessageRenderer = createA2UIMessageRenderer;
7665
9619
  exports.defineToolCallRenderer = defineToolCallRenderer;
7666
9620
  exports.useAgent = useAgent;
7667
9621
  exports.useAgentContext = useAgentContext;
9622
+ exports.useAttachments = useAttachments;
7668
9623
  exports.useComponent = useComponent;
7669
9624
  exports.useConfigureSuggestions = useConfigureSuggestions;
7670
9625
  exports.useCopilotChatConfiguration = useCopilotChatConfiguration;
@@ -7677,6 +9632,7 @@ exports.useRenderActivityMessage = useRenderActivityMessage;
7677
9632
  exports.useRenderCustomMessages = useRenderCustomMessages;
7678
9633
  exports.useRenderTool = useRenderTool;
7679
9634
  exports.useRenderToolCall = useRenderToolCall;
9635
+ exports.useSandboxFunctions = useSandboxFunctions;
7680
9636
  exports.useSuggestions = useSuggestions;
7681
9637
  exports.useThreads = useThreads;
7682
9638
  Object.keys(_copilotkit_core).forEach(function (k) {