@copilotkit/react-core 1.55.0-next.9 → 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 (81) hide show
  1. package/CHANGELOG.md +36 -6
  2. package/dist/{copilotkit-DeOzjPsb.mjs → copilotkit-BY5S1-0P.mjs} +2402 -552
  3. package/dist/copilotkit-BY5S1-0P.mjs.map +1 -0
  4. package/dist/{copilotkit-BqcyhQjT.d.mts → copilotkit-BuhSUZHb.d.mts} +228 -17
  5. package/dist/copilotkit-BuhSUZHb.d.mts.map +1 -0
  6. package/dist/{copilotkit-BDNjFNmk.cjs → copilotkit-Bz5-ImDl.cjs} +2421 -541
  7. package/dist/copilotkit-Bz5-ImDl.cjs.map +1 -0
  8. package/dist/{copilotkit-l-IBF4Xp.d.cts → copilotkit-dwDWYpya.d.cts} +228 -17
  9. package/dist/copilotkit-dwDWYpya.d.cts.map +1 -0
  10. package/dist/index.cjs +1 -1
  11. package/dist/index.d.cts +1 -1
  12. package/dist/index.d.mts +1 -1
  13. package/dist/index.mjs +1 -1
  14. package/dist/index.umd.js +1400 -238
  15. package/dist/index.umd.js.map +1 -1
  16. package/dist/v2/index.cjs +13 -1
  17. package/dist/v2/index.css +1 -1
  18. package/dist/v2/index.d.cts +3 -3
  19. package/dist/v2/index.d.mts +3 -3
  20. package/dist/v2/index.mjs +3 -2
  21. package/dist/v2/index.umd.js +2442 -552
  22. package/dist/v2/index.umd.js.map +1 -1
  23. package/package.json +62 -54
  24. package/scripts/scope-preflight.mjs +1 -2
  25. package/src/components/CopilotListeners.tsx +41 -8
  26. package/src/components/copilot-provider/copilotkit-props.tsx +4 -2
  27. package/src/components/toast/toast-provider.tsx +269 -194
  28. package/src/v2/__tests__/A2UIMessageRenderer.test.tsx +86 -22
  29. package/src/v2/__tests__/utils/test-helpers.tsx +67 -0
  30. package/src/v2/a2ui/A2UICatalogContext.tsx +79 -0
  31. package/src/v2/a2ui/A2UIMessageRenderer.tsx +125 -37
  32. package/src/v2/a2ui/A2UIToolCallRenderer.tsx +290 -0
  33. package/src/v2/components/CopilotKitInspector.tsx +2 -0
  34. package/src/v2/components/OpenGenerativeUIRenderer.tsx +598 -0
  35. package/src/v2/components/__tests__/OpenGenerativeUIRenderer.test.tsx +665 -0
  36. package/src/v2/components/chat/CopilotChat.tsx +193 -50
  37. package/src/v2/components/chat/CopilotChatAssistantMessage.tsx +17 -2
  38. package/src/v2/components/chat/CopilotChatAttachmentQueue.tsx +481 -0
  39. package/src/v2/components/chat/CopilotChatAttachmentRenderer.tsx +139 -0
  40. package/src/v2/components/chat/CopilotChatInput.tsx +146 -77
  41. package/src/v2/components/chat/CopilotChatMessageView.tsx +253 -149
  42. package/src/v2/components/chat/CopilotChatSuggestionView.tsx +1 -0
  43. package/src/v2/components/chat/CopilotChatUserMessage.tsx +54 -0
  44. package/src/v2/components/chat/CopilotChatView.tsx +179 -66
  45. package/src/v2/components/chat/__tests__/CopilotChat.attachments.test.tsx +168 -0
  46. package/src/v2/components/chat/__tests__/CopilotChatActivityRendering.e2e.test.tsx +63 -2
  47. package/src/v2/components/chat/__tests__/CopilotChatInput.test.tsx +544 -1
  48. package/src/v2/components/chat/__tests__/CopilotChatPerf.e2e.test.tsx +268 -0
  49. package/src/v2/components/chat/__tests__/CopilotChatPropsRerender.e2e.test.tsx +249 -0
  50. package/src/v2/components/chat/__tests__/MCPAppsActivityRenderer.e2e.test.tsx +43 -2
  51. package/src/v2/components/chat/__tests__/copilot-chat-throttle.test.tsx +138 -0
  52. package/src/v2/components/chat/index.ts +9 -0
  53. package/src/v2/components/chat/scroll-element-context.ts +13 -0
  54. package/src/v2/hooks/__tests__/use-agent-throttle.test.tsx +1003 -0
  55. package/src/v2/hooks/__tests__/use-attachments.test.tsx +169 -0
  56. package/src/v2/hooks/__tests__/use-threads.test.tsx +54 -0
  57. package/src/v2/hooks/index.ts +5 -0
  58. package/src/v2/hooks/use-agent.tsx +95 -10
  59. package/src/v2/hooks/use-attachments.tsx +269 -0
  60. package/src/v2/hooks/use-frontend-tool.tsx +5 -2
  61. package/src/v2/hooks/use-render-activity-message.tsx +9 -2
  62. package/src/v2/hooks/use-threads.tsx +35 -15
  63. package/src/v2/index.ts +5 -1
  64. package/src/v2/lib/__tests__/processPartialHtml.test.ts +112 -0
  65. package/src/v2/lib/__tests__/slots.test.ts +56 -0
  66. package/src/v2/lib/processPartialHtml.ts +45 -0
  67. package/src/v2/lib/slots.tsx +42 -1
  68. package/src/v2/providers/CopilotChatConfigurationProvider.tsx +9 -3
  69. package/src/v2/providers/CopilotKitProvider.tsx +268 -32
  70. package/src/v2/providers/SandboxFunctionsContext.ts +10 -0
  71. package/src/v2/providers/__tests__/CopilotKitProvider.sandboxFunctions.test.tsx +198 -0
  72. package/src/v2/providers/__tests__/CopilotKitProvider.test.tsx +71 -0
  73. package/src/v2/providers/index.ts +7 -0
  74. package/src/v2/styles/globals.css +2 -1
  75. package/src/v2/types/index.ts +1 -0
  76. package/src/v2/types/sandbox-function.ts +11 -0
  77. package/dist/copilotkit-BDNjFNmk.cjs.map +0 -1
  78. package/dist/copilotkit-BqcyhQjT.d.mts.map +0 -1
  79. package/dist/copilotkit-DeOzjPsb.mjs.map +0 -1
  80. package/dist/copilotkit-l-IBF4Xp.d.cts.map +0 -1
  81. 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", {
@@ -1935,8 +1988,417 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
1935
1988
  });
1936
1989
  };
1937
1990
 
1991
+ //#endregion
1992
+ //#region src/v2/providers/SandboxFunctionsContext.ts
1993
+ const SandboxFunctionsContext = (0, react.createContext)([]);
1994
+ function useSandboxFunctions() {
1995
+ return (0, react.useContext)(SandboxFunctionsContext);
1996
+ }
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("") : "";
2007
+ }
2008
+ /**
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>)
2018
+ */
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;
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
+ });
2048
+ /**
2049
+ * Schema for the generateSandboxedUi tool call arguments.
2050
+ * Used by the frontend tool renderer to display placeholder messages.
2051
+ */
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
+
1938
2395
  //#endregion
1939
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";
1940
2402
  let initialized = false;
1941
2403
  function ensureInitialized() {
1942
2404
  if (!initialized) {
@@ -1946,25 +2408,23 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
1946
2408
  }
1947
2409
  }
1948
2410
  function createA2UIMessageRenderer(options) {
1949
- const { theme } = options;
2411
+ const { theme, catalog, loadingComponent } = options;
1950
2412
  return {
1951
2413
  activityType: "a2ui-surface",
1952
2414
  content: zod.z.any(),
1953
2415
  render: ({ content, agent }) => {
1954
2416
  ensureInitialized();
1955
2417
  const [operations, setOperations] = (0, react.useState)([]);
1956
- const lastSignatureRef = (0, react.useRef)(null);
1957
2418
  const { copilotkit } = useCopilotKit();
2419
+ const lastContentRef = (0, react.useRef)(null);
1958
2420
  (0, react.useEffect)(() => {
1959
- if (!content || !Array.isArray(content.operations)) {
1960
- lastSignatureRef.current = null;
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)) {
1961
2425
  setOperations([]);
1962
2426
  return;
1963
2427
  }
1964
- const incoming = content.operations;
1965
- const signature = stringifyOperations(incoming);
1966
- if (signature && signature === lastSignatureRef.current) return;
1967
- lastSignatureRef.current = signature;
1968
2428
  setOperations(incoming);
1969
2429
  }, [content]);
1970
2430
  const groupedOperations = (0, react.useMemo)(() => {
@@ -1977,7 +2437,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
1977
2437
  }
1978
2438
  return groups;
1979
2439
  }, [operations]);
1980
- if (!groupedOperations.size) return null;
2440
+ if (!groupedOperations.size) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(loadingComponent !== null && loadingComponent !== void 0 ? loadingComponent : DefaultA2UILoading, {});
1981
2441
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1982
2442
  className: "cpk:flex cpk:min-h-0 cpk:flex-1 cpk:flex-col cpk:gap-6 cpk:overflow-auto cpk:py-6",
1983
2443
  children: Array.from(groupedOperations.entries()).map(([surfaceId, ops]) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ReactSurfaceHost, {
@@ -1985,7 +2445,8 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
1985
2445
  operations: ops,
1986
2446
  theme,
1987
2447
  agent,
1988
- copilotkit
2448
+ copilotkit,
2449
+ catalog
1989
2450
  }, surfaceId))
1990
2451
  });
1991
2452
  }
@@ -1995,15 +2456,15 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
1995
2456
  * Renders a single A2UI surface using the React renderer.
1996
2457
  * Wraps A2UIProvider + A2UIRenderer and bridges actions back to CopilotKit.
1997
2458
  */
1998
- function ReactSurfaceHost({ surfaceId, operations, theme, agent, copilotkit }) {
2459
+ function ReactSurfaceHost({ surfaceId, operations, theme, agent, copilotkit, catalog }) {
1999
2460
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2000
2461
  className: "cpk:flex cpk:w-full cpk:flex-none cpk:flex-col cpk:gap-4",
2001
2462
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_copilotkit_a2ui_renderer.A2UIProvider, {
2002
2463
  onAction: (0, react.useCallback)(async (message) => {
2003
2464
  if (!agent) return;
2465
+ message.userAction;
2004
2466
  try {
2005
2467
  var _copilotkit$propertie;
2006
- console.info("[A2UI] Action dispatched", message.userAction);
2007
2468
  copilotkit.setProperties({
2008
2469
  ...(_copilotkit$propertie = copilotkit.properties) !== null && _copilotkit$propertie !== void 0 ? _copilotkit$propertie : {},
2009
2470
  a2uiAction: message
@@ -2017,48 +2478,503 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
2017
2478
  }
2018
2479
  }, [agent, copilotkit]),
2019
2480
  theme,
2481
+ catalog,
2020
2482
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(SurfaceMessageProcessor, {
2021
2483
  surfaceId,
2022
2484
  operations
2023
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_copilotkit_a2ui_renderer.A2UIRenderer, {
2024
- surfaceId,
2025
- className: "cpk:flex cpk:flex-1"
2026
- })]
2485
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(A2UISurfaceOrError, { surfaceId })]
2027
2486
  })
2028
2487
  });
2029
2488
  }
2030
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
+ /**
2031
2505
  * Processes A2UI operations into the provider's message processor.
2032
2506
  * Must be a child of A2UIProvider to access the actions context.
2033
2507
  */
2034
2508
  function SurfaceMessageProcessor({ surfaceId, operations }) {
2035
- const { processMessages } = (0, _copilotkit_a2ui_renderer.useA2UIActions)();
2036
- const lastProcessedRef = (0, react.useRef)("");
2509
+ const { processMessages, getSurface } = (0, _copilotkit_a2ui_renderer.useA2UIActions)();
2510
+ const lastHashRef = (0, react.useRef)("");
2037
2511
  (0, react.useEffect)(() => {
2038
- const key = `${surfaceId}-${JSON.stringify(operations)}`;
2039
- if (key === lastProcessedRef.current) return;
2040
- lastProcessedRef.current = key;
2041
- processMessages(operations);
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
  }
2049
- function getOperationSurfaceId(operation) {
2050
- var _ref, _ref2, _ref3, _operation$beginRende, _operation$beginRende2, _operation$surfaceUpd, _operation$dataModelU, _operation$deleteSurf;
2051
- if (!operation || typeof operation !== "object") return null;
2052
- 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;
2054
- }
2055
- function stringifyOperations(ops) {
2056
- try {
2057
- return JSON.stringify(ops);
2058
- } catch (error) {
2059
- return null;
2060
- }
2061
- }
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
+ }
2566
+ function getOperationSurfaceId(operation) {
2567
+ var _ref, _ref2, _ref3, _operation$createSurf, _operation$createSurf2, _operation$updateComp, _operation$updateData, _operation$deleteSurf;
2568
+ if (!operation || typeof operation !== "object") return null;
2569
+ if (typeof operation.surfaceId === "string") return operation.surfaceId;
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;
2571
+ }
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
+ };
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;
2977
+ }
2062
2978
 
2063
2979
  //#endregion
2064
2980
  //#region src/v2/lib/react-core.ts
@@ -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
  };
@@ -2570,12 +3588,23 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
2570
3588
  byThread.set(threadId, clone);
2571
3589
  return clone;
2572
3590
  }
2573
- function useAgent({ agentId, threadId, updates } = {}) {
3591
+ function useAgent({ agentId, threadId, updates, throttleMs } = {}) {
2574
3592
  var _agentId, _threadId;
2575
3593
  (_agentId = agentId) !== null && _agentId !== void 0 || (agentId = _copilotkit_shared.DEFAULT_AGENT_ID);
2576
3594
  const { copilotkit } = useCopilotKit();
3595
+ const providerThrottleMs = copilotkit.defaultThrottleMs;
2577
3596
  const chatConfig = useCopilotChatConfiguration();
2578
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]);
2579
3608
  const [, forceUpdate] = (0, react.useReducer)((x) => x + 1, 0);
2580
3609
  const updateFlags = (0, react.useMemo)(() => updates !== null && updates !== void 0 ? updates : ALL_UPDATES, [JSON.stringify(updates)]);
2581
3610
  const provisionalAgentCache = (0, react.useRef)(/* @__PURE__ */ new Map());
@@ -2640,9 +3669,32 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
2640
3669
  (0, react.useEffect)(() => {
2641
3670
  if (updateFlags.length === 0) return;
2642
3671
  const handlers = {};
2643
- if (updateFlags.includes(UseAgentUpdate.OnMessagesChanged)) handlers.onMessagesChanged = () => {
2644
- forceUpdate();
2645
- };
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
+ }
2646
3698
  if (updateFlags.includes(UseAgentUpdate.OnStateChanged)) handlers.onStateChanged = forceUpdate;
2647
3699
  if (updateFlags.includes(UseAgentUpdate.OnRunStatusChanged)) {
2648
3700
  handlers.onRunInitialized = forceUpdate;
@@ -2650,11 +3702,16 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
2650
3702
  handlers.onRunFailed = forceUpdate;
2651
3703
  }
2652
3704
  const subscription = agent.subscribe(handlers);
2653
- return () => subscription.unsubscribe();
3705
+ return () => {
3706
+ active = false;
3707
+ if (timerId !== null) clearTimeout(timerId);
3708
+ subscription.unsubscribe();
3709
+ };
2654
3710
  }, [
2655
3711
  agent,
2656
3712
  forceUpdate,
2657
- JSON.stringify(updateFlags)
3713
+ effectiveThrottleMs,
3714
+ updateFlags
2658
3715
  ]);
2659
3716
  (0, react.useEffect)(() => {
2660
3717
  if (agent instanceof _ag_ui_client.HttpAgent) agent.headers = { ...copilotkit.headers };
@@ -2724,6 +3781,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
2724
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;
2725
3782
  }, [agentId, renderers]);
2726
3783
  const renderActivityMessage = (0, react.useCallback)((message) => {
3784
+ var _getThreadClone;
2727
3785
  const renderer = findRenderer(message.activityType);
2728
3786
  if (!renderer) return null;
2729
3787
  const parseResult = renderer.content.safeParse(message.content);
@@ -2732,7 +3790,8 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
2732
3790
  return null;
2733
3791
  }
2734
3792
  const Component = renderer.render;
2735
- 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;
2736
3795
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Component, {
2737
3796
  activityType: message.activityType,
2738
3797
  content: parseResult.data,
@@ -2741,6 +3800,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
2741
3800
  }, message.id);
2742
3801
  }, [
2743
3802
  agentId,
3803
+ config === null || config === void 0 ? void 0 : config.threadId,
2744
3804
  copilotkit,
2745
3805
  findRenderer
2746
3806
  ]);
@@ -2766,7 +3826,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
2766
3826
  copilotkit.removeTool(name, tool.agentId);
2767
3827
  }
2768
3828
  copilotkit.addTool(tool);
2769
- if (tool.render && tool.parameters) copilotkit.addHookRenderToolCall({
3829
+ if (tool.render) copilotkit.addHookRenderToolCall({
2770
3830
  name,
2771
3831
  args: tool.parameters,
2772
3832
  agentId: tool.agentId,
@@ -2851,18 +3911,6 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
2851
3911
  }, deps);
2852
3912
  }
2853
3913
 
2854
- //#endregion
2855
- //#region src/v2/types/defineToolCallRenderer.ts
2856
- function defineToolCallRenderer(def) {
2857
- const argsSchema = def.name === "*" && !def.args ? zod.z.any() : def.args;
2858
- return {
2859
- name: def.name,
2860
- args: argsSchema,
2861
- render: def.render,
2862
- ...def.agentId ? { agentId: def.agentId } : {}
2863
- };
2864
- }
2865
-
2866
3914
  //#endregion
2867
3915
  //#region src/v2/hooks/use-render-tool.tsx
2868
3916
  const EMPTY_DEPS = [];
@@ -3193,31 +4241,6 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
3193
4241
  ]);
3194
4242
  }
3195
4243
 
3196
- //#endregion
3197
- //#region src/v2/hooks/use-agent-context.tsx
3198
- function useAgentContext(context) {
3199
- const { description, value } = context;
3200
- const { copilotkit } = useCopilotKit();
3201
- const stringValue = (0, react.useMemo)(() => {
3202
- if (typeof value === "string") return value;
3203
- return JSON.stringify(value);
3204
- }, [value]);
3205
- (0, react.useLayoutEffect)(() => {
3206
- if (!copilotkit) return;
3207
- const id = copilotkit.addContext({
3208
- description,
3209
- value: stringValue
3210
- });
3211
- return () => {
3212
- copilotkit.removeContext(id);
3213
- };
3214
- }, [
3215
- description,
3216
- stringValue,
3217
- copilotkit
3218
- ]);
3219
- }
3220
-
3221
4244
  //#endregion
3222
4245
  //#region src/v2/hooks/use-suggestions.tsx
3223
4246
  function useSuggestions({ agentId } = {}) {
@@ -3639,11 +4662,19 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
3639
4662
  var _copilotkit$intellige2;
3640
4663
  const { copilotkit } = useCopilotKit();
3641
4664
  const [store] = (0, react.useState)(() => (0, _copilotkit_core.ɵcreateThreadStore)({ fetch: globalThis.fetch }));
3642
- 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]);
3643
4674
  const storeIsLoading = useThreadStoreSelector(store, _copilotkit_core.ɵselectThreadsIsLoading);
3644
4675
  const storeError = useThreadStoreSelector(store, _copilotkit_core.ɵselectThreadsError);
3645
- const hasNextPage = useThreadStoreSelector(store, _copilotkit_core.ɵselectHasNextPage);
3646
- const isFetchingNextPage = useThreadStoreSelector(store, _copilotkit_core.ɵselectIsFetchingNextPage);
4676
+ const hasMoreThreads = useThreadStoreSelector(store, _copilotkit_core.ɵselectHasNextPage);
4677
+ const isFetchingMoreThreads = useThreadStoreSelector(store, _copilotkit_core.ɵselectIsFetchingNextPage);
3647
4678
  const headersKey = (0, react.useMemo)(() => {
3648
4679
  var _copilotkit$headers;
3649
4680
  return JSON.stringify(Object.entries((_copilotkit$headers = copilotkit.headers) !== null && _copilotkit$headers !== void 0 ? _copilotkit$headers : {}).sort(([left], [right]) => left.localeCompare(right)));
@@ -3688,15 +4719,184 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
3688
4719
  threads,
3689
4720
  isLoading,
3690
4721
  error,
3691
- hasNextPage,
3692
- isFetchingNextPage,
3693
- fetchNextPage: (0, react.useCallback)(() => store.fetchNextPage(), [store]),
4722
+ hasMoreThreads,
4723
+ isFetchingMoreThreads,
4724
+ fetchMoreThreads: (0, react.useCallback)(() => store.fetchNextPage(), [store]),
3694
4725
  renameThread,
3695
4726
  archiveThread,
3696
4727
  deleteThread
3697
4728
  };
3698
4729
  }
3699
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
+
3700
4900
  //#endregion
3701
4901
  //#region src/v2/components/chat/CopilotChatToolCallsView.tsx
3702
4902
  function CopilotChatToolCallsView({ message, messages = [] }) {
@@ -3816,9 +5016,19 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
3816
5016
  const config = useCopilotChatConfiguration();
3817
5017
  const labels = (_config$labels = config === null || config === void 0 ? void 0 : config.labels) !== null && _config$labels !== void 0 ? _config$labels : CopilotChatDefaultLabels;
3818
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
+ }, []);
3819
5025
  const handleClick = (event) => {
3820
5026
  setCopied(true);
3821
- 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);
3822
5032
  if (onClick) onClick(event);
3823
5033
  };
3824
5034
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ToolbarButton, {
@@ -3884,6 +5094,80 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
3884
5094
  CopilotChatAssistantMessage.RegenerateButton.displayName = "CopilotChatAssistantMessage.RegenerateButton";
3885
5095
  var CopilotChatAssistantMessage_default = CopilotChatAssistantMessage;
3886
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
+
3887
5171
  //#endregion
3888
5172
  //#region src/v2/components/chat/CopilotChatUserMessage.tsx
3889
5173
  function flattenUserMessageContent(content) {
@@ -3894,8 +5178,17 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
3894
5178
  return "";
3895
5179
  }).filter((text) => text.length > 0).join("\n");
3896
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
+ }
3897
5189
  function CopilotChatUserMessage({ message, onEditMessage, branchIndex, numberOfBranches, onSwitchToBranch, additionalToolbarItems, messageRenderer, toolbar, copyButton, editButton, branchNavigation, children, className, ...props }) {
3898
5190
  const flattenedContent = (0, react.useMemo)(() => flattenUserMessageContent(message.content), [message.content]);
5191
+ const mediaParts = (0, react.useMemo)(() => getMediaParts(message.content), [message.content]);
3899
5192
  const BoundMessageRenderer = renderSlot(messageRenderer, CopilotChatUserMessage.MessageRenderer, { content: flattenedContent });
3900
5193
  const BoundCopyButton = renderSlot(copyButton, CopilotChatUserMessage.CopyButton, { onClick: async () => {
3901
5194
  if (flattenedContent) try {
@@ -3942,7 +5235,18 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
3942
5235
  className: (0, tailwind_merge.twMerge)("copilotKitMessage copilotKitUserMessage cpk:flex cpk:flex-col cpk:items-end cpk:group cpk:pt-10", className),
3943
5236
  "data-message-id": message.id,
3944
5237
  ...props,
3945
- 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
+ ]
3946
5250
  });
3947
5251
  }
3948
5252
  (function(_CopilotChatUserMessage) {
@@ -4245,6 +5549,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4245
5549
  const isLoading = loadingSet.has(index) || suggestion.isLoading === true;
4246
5550
  const pill = renderSlot(suggestionSlot, CopilotChatSuggestionPill, {
4247
5551
  children: suggestion.title,
5552
+ className: suggestion.className,
4248
5553
  isLoading,
4249
5554
  type: "button",
4250
5555
  onClick: () => onSelectSuggestion === null || onSelectSuggestion === void 0 ? void 0 : onSelectSuggestion(suggestion, index)
@@ -4282,9 +5587,43 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4282
5587
  });
4283
5588
  CopilotChatSuggestionView.displayName = "CopilotChatSuggestionView";
4284
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
+
4285
5602
  //#endregion
4286
5603
  //#region src/v2/components/chat/CopilotChatMessageView.tsx
4287
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
+ /**
4288
5627
  * Memoized wrapper for assistant messages to prevent re-renders when other messages change.
4289
5628
  */
4290
5629
  const MemoizedAssistantMessage = react.default.memo(function MemoizedAssistantMessage({ message, messages, isRunning, AssistantMessageComponent, slotProps }) {
@@ -4304,7 +5643,6 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4304
5643
  if (prevToolCalls && nextToolCalls) for (let i = 0; i < prevToolCalls.length; i++) {
4305
5644
  const prevTc = prevToolCalls[i];
4306
5645
  const nextTc = nextToolCalls[i];
4307
- if (!prevTc || !nextTc) return false;
4308
5646
  if (prevTc.id !== nextTc.id) return false;
4309
5647
  if (prevTc.function.arguments !== nextTc.function.arguments) return false;
4310
5648
  }
@@ -4384,7 +5722,9 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4384
5722
  if (JSON.stringify(prevProps.stateSnapshot) !== JSON.stringify(nextProps.stateSnapshot)) return false;
4385
5723
  return true;
4386
5724
  });
5725
+ const VIRTUALIZE_THRESHOLD = 50;
4387
5726
  function CopilotChatMessageView({ messages = [], assistantMessage, userMessage, reasoningMessage, cursor, isRunning = false, children, className, ...props }) {
5727
+ var _deduplicatedMessages;
4388
5728
  const renderCustomMessage = useRenderCustomMessages();
4389
5729
  const { renderActivityMessage } = useRenderActivityMessage();
4390
5730
  const { copilotkit } = useCopilotKit();
@@ -4419,9 +5759,36 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4419
5759
  if (!resolvedRunId) return void 0;
4420
5760
  return copilotkit.getStateByRun(config.agentId, config.threadId, resolvedRunId);
4421
5761
  };
4422
- 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]);
4423
5763
  if (process.env.NODE_ENV === "development" && deduplicatedMessages.length < messages.length) console.warn(`CopilotChatMessageView: Deduplicated ${messages.length - deduplicatedMessages.length} message(s) with duplicate IDs.`);
4424
- 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) => {
4425
5792
  const elements = [];
4426
5793
  const stateSnapshot = getStateSnapshotForMessage(message.id);
4427
5794
  if (renderCustomMessage) elements.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(MemoizedCustomMessage, {
@@ -4430,58 +5797,38 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4430
5797
  renderCustomMessage,
4431
5798
  stateSnapshot
4432
5799
  }, `${message.id}-custom-before`));
4433
- if (message.role === "assistant") {
4434
- let AssistantComponent = CopilotChatAssistantMessage_default;
4435
- let assistantSlotProps;
4436
- if (isReactComponentType(assistantMessage)) AssistantComponent = assistantMessage;
4437
- else if (typeof assistantMessage === "string") assistantSlotProps = { className: assistantMessage };
4438
- else if (assistantMessage && typeof assistantMessage === "object") assistantSlotProps = assistantMessage;
4439
- elements.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(MemoizedAssistantMessage, {
4440
- message,
4441
- messages,
4442
- isRunning,
4443
- AssistantMessageComponent: AssistantComponent,
4444
- slotProps: assistantSlotProps
4445
- }, message.id));
4446
- } else if (message.role === "user") {
4447
- let UserComponent = CopilotChatUserMessage_default;
4448
- let userSlotProps;
4449
- if (isReactComponentType(userMessage)) UserComponent = userMessage;
4450
- else if (typeof userMessage === "string") userSlotProps = { className: userMessage };
4451
- else if (userMessage && typeof userMessage === "object") userSlotProps = userMessage;
4452
- elements.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(MemoizedUserMessage, {
4453
- message,
4454
- UserMessageComponent: UserComponent,
4455
- slotProps: userSlotProps
4456
- }, message.id));
4457
- } else if (message.role === "activity") {
4458
- const activityMsg = message;
4459
- elements.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(MemoizedActivityMessage, {
4460
- message: activityMsg,
4461
- renderActivityMessage
4462
- }, message.id));
4463
- } else if (message.role === "reasoning") {
4464
- let ReasoningComponent = CopilotChatReasoningMessage_default;
4465
- let reasoningSlotProps;
4466
- if (isReactComponentType(reasoningMessage)) ReasoningComponent = reasoningMessage;
4467
- else if (typeof reasoningMessage === "string") reasoningSlotProps = { className: reasoningMessage };
4468
- else if (reasoningMessage && typeof reasoningMessage === "object") reasoningSlotProps = reasoningMessage;
4469
- elements.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(MemoizedReasoningMessage, {
4470
- message,
4471
- messages,
4472
- isRunning,
4473
- ReasoningMessageComponent: ReasoningComponent,
4474
- slotProps: reasoningSlotProps
4475
- }, message.id));
4476
- }
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));
4477
5823
  if (renderCustomMessage) elements.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(MemoizedCustomMessage, {
4478
5824
  message,
4479
5825
  position: "after",
4480
5826
  renderCustomMessage,
4481
5827
  stateSnapshot
4482
5828
  }, `${message.id}-custom-after`));
4483
- return elements;
4484
- }).filter(Boolean);
5829
+ return elements.filter(Boolean);
5830
+ };
5831
+ const messageElements = shouldVirtualize ? [] : deduplicatedMessages.flatMap(renderMessageBlock);
4485
5832
  if (children) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
4486
5833
  "data-copilotkit": true,
4487
5834
  style: { display: "contents" },
@@ -4492,30 +5839,356 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4492
5839
  interruptElement
4493
5840
  })
4494
5841
  });
4495
- const lastMessage = messages[messages.length - 1];
4496
- 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
+ }
4497
6138
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4498
- "data-copilotkit": true,
4499
- "data-testid": "copilot-message-list",
4500
- className: (0, tailwind_merge.twMerge)("copilotKitMessages cpk:flex cpk:flex-col", className),
4501
- ...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",
4502
6141
  children: [
4503
- messageElements,
4504
- interruptElement,
4505
- showCursor && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
4506
- className: "cpk:mt-2",
4507
- 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"
4508
6159
  })
4509
6160
  ]
4510
6161
  });
4511
6162
  }
4512
- CopilotChatMessageView.Cursor = function Cursor({ className, ...props }) {
4513
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
4514
- "data-testid": "copilot-loading-cursor",
4515
- 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),
4516
- ...props
4517
- });
4518
- };
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
+ }
4519
6192
 
4520
6193
  //#endregion
4521
6194
  //#region src/v2/hooks/use-keyboard-height.tsx
@@ -4561,7 +6234,19 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4561
6234
  //#endregion
4562
6235
  //#region src/v2/components/chat/CopilotChatView.tsx
4563
6236
  const FEATHER_HEIGHT = 96;
4564
- 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 }) {
4565
6250
  const inputContainerRef = (0, react.useRef)(null);
4566
6251
  const [inputContainerHeight, setInputContainerHeight] = (0, react.useState)(0);
4567
6252
  const [isResizing, setIsResizing] = (0, react.useState)(false);
@@ -4608,6 +6293,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4608
6293
  onCancelTranscribe,
4609
6294
  onFinishTranscribe,
4610
6295
  onFinishTranscribeWithAudio,
6296
+ onAddFile,
4611
6297
  positioning: "static",
4612
6298
  keyboardHeight: isKeyboardOpen ? keyboardHeight : 0,
4613
6299
  containerRef: inputContainerRef,
@@ -4648,21 +6334,34 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4648
6334
  onCancelTranscribe,
4649
6335
  onFinishTranscribe,
4650
6336
  onFinishTranscribeWithAudio,
6337
+ onAddFile,
4651
6338
  positioning: "static",
4652
6339
  showDisclaimer: true,
4653
6340
  ...disclaimer !== void 0 ? { disclaimer } : {}
4654
6341
  });
4655
- const BoundWelcomeScreen = renderSlot(welcomeScreen === true ? void 0 : welcomeScreen, CopilotChatView.WelcomeScreen, {
4656
- 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,
4657
6353
  suggestionView: BoundSuggestionView !== null && BoundSuggestionView !== void 0 ? BoundSuggestionView : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, {})
4658
6354
  });
4659
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6355
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4660
6356
  "data-copilotkit": true,
4661
6357
  "data-testid": "copilot-chat",
4662
6358
  "data-copilot-running": isRunning ? "true" : "false",
4663
- 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),
4664
6363
  ...props,
4665
- children: BoundWelcomeScreen
6364
+ children: [dragOver && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DropOverlay, {}), BoundWelcomeScreen]
4666
6365
  });
4667
6366
  }
4668
6367
  if (children) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
@@ -4679,39 +6378,67 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4679
6378
  "data-copilotkit": true,
4680
6379
  "data-testid": "copilot-chat",
4681
6380
  "data-copilot-running": isRunning ? "true" : "false",
4682
- 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),
4683
6385
  ...props,
4684
- 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
+ ]
4685
6399
  });
4686
6400
  }
4687
6401
  (function(_CopilotChatView) {
4688
6402
  const ScrollContent = ({ children, scrollToBottomButton, feather, inputContainerHeight, isResizing }) => {
4689
- 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
+ }, []);
4690
6409
  const BoundFeather = renderSlot(feather, CopilotChatView.Feather, {});
4691
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
4692
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(use_stick_to_bottom.StickToBottom.Content, {
4693
- className: "cpk:overflow-y-auto cpk:overflow-x-hidden",
4694
- style: {
4695
- flex: "1 1 0%",
4696
- minHeight: 0
4697
- },
4698
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
4699
- className: "cpk:px-4 cpk:sm:px-0 cpk:[div[data-sidebar-chat]_&]:px-8 cpk:[div[data-popup-chat]_&]:px-6",
4700
- 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() })
4701
6429
  })
4702
- }),
4703
- BoundFeather,
4704
- !isAtBottom && !isResizing && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
4705
- className: "cpk:absolute cpk:inset-x-0 cpk:flex cpk:justify-center cpk:z-30 cpk:pointer-events-none",
4706
- style: { bottom: `${inputContainerHeight + FEATHER_HEIGHT + 16}px` },
4707
- children: renderSlot(scrollToBottomButton, CopilotChatView.ScrollToBottomButton, { onClick: () => scrollToBottom() })
4708
- })
4709
- ] });
6430
+ ] })
6431
+ });
4710
6432
  };
4711
6433
  _CopilotChatView.ScrollView = ({ children, autoScroll = true, scrollToBottomButton, feather, inputContainerHeight = 0, isResizing = false, className, ...props }) => {
4712
6434
  const [hasMounted, setHasMounted] = (0, react.useState)(false);
4713
6435
  const { scrollRef, contentRef, scrollToBottom } = (0, use_stick_to_bottom.useStickToBottom)();
4714
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
+ }, []);
4715
6442
  (0, react.useEffect)(() => {
4716
6443
  setHasMounted(true);
4717
6444
  }, []);
@@ -4740,23 +6467,26 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4740
6467
  });
4741
6468
  if (!autoScroll) {
4742
6469
  const BoundFeather = renderSlot(feather, CopilotChatView.Feather, {});
4743
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4744
- ref: scrollRef,
4745
- 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),
4746
- ...props,
4747
- children: [
4748
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
4749
- ref: contentRef,
4750
- className: "cpk:px-4 cpk:sm:px-0 cpk:[div[data-sidebar-chat]_&]:px-8 cpk:[div[data-popup-chat]_&]:px-6",
4751
- children
4752
- }),
4753
- BoundFeather,
4754
- showScrollButton && !isResizing && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
4755
- className: "cpk:absolute cpk:inset-x-0 cpk:flex cpk:justify-center cpk:z-30 cpk:pointer-events-none",
4756
- style: { bottom: `${inputContainerHeight + FEATHER_HEIGHT + 16}px` },
4757
- children: renderSlot(scrollToBottomButton, CopilotChatView.ScrollToBottomButton, { onClick: () => scrollToBottom() })
4758
- })
4759
- ]
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
+ })
4760
6490
  });
4761
6491
  }
4762
6492
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(use_stick_to_bottom.StickToBottom, {
@@ -4951,8 +6681,8 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4951
6681
 
4952
6682
  //#endregion
4953
6683
  //#region src/v2/components/chat/CopilotChat.tsx
4954
- function CopilotChat({ agentId, threadId, labels, chatView, isModalDefaultOpen, onError, ...props }) {
4955
- var _ref;
6684
+ function CopilotChat({ agentId, threadId, labels, chatView, isModalDefaultOpen, attachments: attachmentsConfig, onError, throttleMs, ...props }) {
6685
+ var _ref, _attachmentsConfig$ac;
4956
6686
  const existingConfig = useCopilotChatConfiguration();
4957
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;
4958
6688
  const resolvedThreadId = (0, react.useMemo)(() => {
@@ -4961,7 +6691,8 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4961
6691
  }, [threadId, existingConfig === null || existingConfig === void 0 ? void 0 : existingConfig.threadId]);
4962
6692
  const { agent } = useAgent({
4963
6693
  agentId: resolvedAgentId,
4964
- threadId: resolvedThreadId
6694
+ threadId: resolvedThreadId,
6695
+ throttleMs
4965
6696
  });
4966
6697
  const { copilotkit } = useCopilotKit();
4967
6698
  const { suggestions: autoSuggestions } = useSuggestions({ agentId: resolvedAgentId });
@@ -4995,6 +6726,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4995
6726
  const [inputValue, setInputValue] = (0, react.useState)("");
4996
6727
  const [transcriptionError, setTranscriptionError] = (0, react.useState)(null);
4997
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 });
4998
6730
  const isTranscriptionEnabled = copilotkit.audioFileTranscriptionEnabled;
4999
6731
  const isMediaRecorderSupported = typeof window !== "undefined" && typeof MediaRecorder !== "undefined";
5000
6732
  const { messageView: providedMessageView, suggestionView: providedSuggestionView, onStop: providedStopHandler, ...restProps } = props;
@@ -5022,7 +6754,31 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
5022
6754
  resolvedAgentId
5023
6755
  ]);
5024
6756
  const onSubmitInput = (0, react.useCallback)(async (value) => {
5025
- 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({
5026
6782
  id: (0, _copilotkit_shared.randomUUID)(),
5027
6783
  role: "user",
5028
6784
  content: value
@@ -5033,7 +6789,11 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
5033
6789
  } catch (error) {
5034
6790
  console.error("CopilotChat: runAgent failed", error);
5035
6791
  }
5036
- }, [agent]);
6792
+ }, [
6793
+ agent,
6794
+ selectedAttachments,
6795
+ consumeAttachments
6796
+ ]);
5037
6797
  const handleSelectSuggestion = (0, react.useCallback)(async (suggestion) => {
5038
6798
  agent.addMessage({
5039
6799
  id: (0, _copilotkit_shared.randomUUID)(),
@@ -5120,21 +6880,37 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
5120
6880
  return () => clearTimeout(timer);
5121
6881
  }
5122
6882
  }, [transcriptionError]);
5123
- 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 = {
5124
6892
  isRunning: agent.isRunning,
5125
6893
  suggestions: autoSuggestions,
5126
6894
  onSelectSuggestion: handleSelectSuggestion,
5127
- suggestionView: providedSuggestionView
5128
- }, {
5129
- ...restProps,
5130
- ...typeof providedMessageView === "string" ? { messageView: { className: providedMessageView } } : providedMessageView !== void 0 ? { messageView: providedMessageView } : {}
5131
- });
6895
+ suggestionView: stableSuggestionView,
6896
+ ...restProps
6897
+ };
6898
+ if (stableMessageView !== void 0) mergedProps.messageView = stableMessageView;
5132
6899
  const hasMessages = agent.messages.length > 0;
5133
6900
  const effectiveStopHandler = agent.isRunning && hasMessages ? providedStopHandler !== null && providedStopHandler !== void 0 ? providedStopHandler : stopCurrentRun : providedStopHandler;
5134
6901
  const showTranscription = isTranscriptionEnabled && isMediaRecorderSupported;
5135
6902
  const effectiveMode = isTranscribing ? "processing" : transcribeMode;
5136
- const RenderedChatView = renderSlot(chatView, CopilotChatView, (0, ts_deepmerge.merge)(mergedProps, {
5137
- 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,
5138
6914
  onSubmitMessage: onSubmitInput,
5139
6915
  onStop: effectiveStopHandler,
5140
6916
  inputMode: effectiveMode,
@@ -5143,32 +6919,51 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
5143
6919
  onStartTranscribe: showTranscription ? handleStartTranscribe : void 0,
5144
6920
  onCancelTranscribe: showTranscription ? handleCancelTranscribe : void 0,
5145
6921
  onFinishTranscribe: showTranscription ? handleFinishTranscribe : void 0,
5146
- onFinishTranscribeWithAudio: showTranscription ? handleFinishTranscribeWithAudio : void 0
5147
- }));
5148
- 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, {
5149
6932
  agentId: resolvedAgentId,
5150
6933
  threadId: resolvedThreadId,
5151
6934
  labels,
5152
6935
  isModalDefaultOpen,
5153
- children: [
5154
- !isChatLicensed && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InlineFeatureWarning, { featureName: "Chat" }),
5155
- transcriptionError && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5156
- style: {
5157
- position: "absolute",
5158
- bottom: "100px",
5159
- left: "50%",
5160
- transform: "translateX(-50%)",
5161
- backgroundColor: "#ef4444",
5162
- color: "white",
5163
- padding: "8px 16px",
5164
- borderRadius: "8px",
5165
- fontSize: "14px",
5166
- zIndex: 50
5167
- },
5168
- children: transcriptionError
5169
- }),
5170
- RenderedChatView
5171
- ]
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
+ })
5172
6967
  });
5173
6968
  }
5174
6969
  (function(_CopilotChat) {
@@ -6035,6 +7830,227 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
6035
7830
  if (!context) throw new Error("useToast must be used within a ToastProvider");
6036
7831
  return context;
6037
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
+ }
6038
8054
  function ToastProvider({ enabled, children }) {
6039
8055
  const [toasts, setToasts] = (0, react.useState)([]);
6040
8056
  const [bannerError, setBannerErrorState] = (0, react.useState)(null);
@@ -6073,156 +8089,10 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
6073
8089
  };
6074
8090
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(ToastContext.Provider, {
6075
8091
  value,
6076
- children: [bannerError && (() => {
6077
- const colors = getErrorColors(getErrorSeverity(bannerError));
6078
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6079
- style: {
6080
- position: "fixed",
6081
- bottom: "20px",
6082
- left: "50%",
6083
- transform: "translateX(-50%)",
6084
- zIndex: 9999,
6085
- backgroundColor: colors.background,
6086
- border: `1px solid ${colors.border}`,
6087
- borderLeft: `4px solid ${colors.border}`,
6088
- borderRadius: "8px",
6089
- padding: "12px 16px",
6090
- fontSize: "13px",
6091
- boxShadow: "0 4px 12px rgba(0, 0, 0, 0.15)",
6092
- backdropFilter: "blur(8px)",
6093
- maxWidth: "min(90vw, 700px)",
6094
- width: "100%",
6095
- boxSizing: "border-box",
6096
- overflow: "hidden"
6097
- },
6098
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6099
- style: {
6100
- display: "flex",
6101
- justifyContent: "space-between",
6102
- alignItems: "center",
6103
- gap: "10px"
6104
- },
6105
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6106
- style: {
6107
- display: "flex",
6108
- alignItems: "center",
6109
- gap: "8px",
6110
- flex: 1,
6111
- minWidth: 0
6112
- },
6113
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { style: {
6114
- width: "12px",
6115
- height: "12px",
6116
- borderRadius: "50%",
6117
- backgroundColor: colors.border,
6118
- flexShrink: 0
6119
- } }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6120
- style: {
6121
- display: "flex",
6122
- alignItems: "center",
6123
- gap: "10px",
6124
- flex: 1,
6125
- minWidth: 0
6126
- },
6127
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6128
- style: {
6129
- color: colors.text,
6130
- lineHeight: "1.4",
6131
- fontWeight: "400",
6132
- fontSize: "13px",
6133
- flex: 1,
6134
- wordBreak: "break-all",
6135
- overflowWrap: "break-word",
6136
- maxWidth: "550px",
6137
- overflow: "hidden",
6138
- display: "-webkit-box",
6139
- WebkitLineClamp: 10,
6140
- WebkitBoxOrient: "vertical"
6141
- },
6142
- children: (() => {
6143
- let message = bannerError.message;
6144
- const jsonMatch = message.match(/'message':\s*'([^']+)'/);
6145
- if (jsonMatch) return jsonMatch[1];
6146
- message = message.split(" - ")[0];
6147
- message = message.split(": Error code")[0];
6148
- message = message.replace(/:\s*\d{3}$/, "");
6149
- message = message.replace(/See more:.*$/g, "");
6150
- message = message.trim();
6151
- return message || "Configuration error occurred.";
6152
- })()
6153
- }), (() => {
6154
- const message = bannerError.message;
6155
- const markdownLinkRegex = /\[([^\]]+)\]\(([^)]+)\)/g;
6156
- const plainUrlRegex = /(https?:\/\/[^\s)]+)/g;
6157
- let url = null;
6158
- let buttonText = "See More";
6159
- const markdownMatch = markdownLinkRegex.exec(message);
6160
- if (markdownMatch) {
6161
- url = markdownMatch[2];
6162
- buttonText = "See More";
6163
- } else {
6164
- const urlMatch = plainUrlRegex.exec(message);
6165
- if (urlMatch) {
6166
- url = urlMatch[0].replace(/[.,;:'"]*$/, "");
6167
- buttonText = "See More";
6168
- }
6169
- }
6170
- if (!url) return null;
6171
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
6172
- onClick: () => window.open(url, "_blank", "noopener,noreferrer"),
6173
- style: {
6174
- background: colors.border,
6175
- color: "white",
6176
- border: "none",
6177
- borderRadius: "5px",
6178
- padding: "4px 10px",
6179
- fontSize: "11px",
6180
- fontWeight: "500",
6181
- cursor: "pointer",
6182
- transition: "all 0.2s ease",
6183
- flexShrink: 0
6184
- },
6185
- onMouseEnter: (e) => {
6186
- e.currentTarget.style.opacity = "0.9";
6187
- e.currentTarget.style.transform = "translateY(-1px)";
6188
- },
6189
- onMouseLeave: (e) => {
6190
- e.currentTarget.style.opacity = "1";
6191
- e.currentTarget.style.transform = "translateY(0)";
6192
- },
6193
- children: buttonText
6194
- });
6195
- })()]
6196
- })]
6197
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
6198
- onClick: () => setBannerError(null),
6199
- style: {
6200
- background: "transparent",
6201
- border: "none",
6202
- color: colors.text,
6203
- cursor: "pointer",
6204
- padding: "2px",
6205
- borderRadius: "3px",
6206
- fontSize: "14px",
6207
- lineHeight: "1",
6208
- opacity: .6,
6209
- transition: "all 0.2s ease",
6210
- flexShrink: 0
6211
- },
6212
- title: "Dismiss",
6213
- onMouseEnter: (e) => {
6214
- e.currentTarget.style.opacity = "1";
6215
- e.currentTarget.style.background = "rgba(0, 0, 0, 0.05)";
6216
- },
6217
- onMouseLeave: (e) => {
6218
- e.currentTarget.style.opacity = "0.6";
6219
- e.currentTarget.style.background = "transparent";
6220
- },
6221
- children: "×"
6222
- })]
6223
- })
6224
- });
6225
- })(), children]
8092
+ children: [bannerError && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BannerErrorDisplay, {
8093
+ bannerError,
8094
+ onDismiss: () => setBannerError(null)
8095
+ }), children]
6226
8096
  });
6227
8097
  }
6228
8098
 
@@ -7141,12 +9011,21 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
7141
9011
  const { agent } = useAgent({ agentId: resolvedAgentId });
7142
9012
  usePredictStateSubscription(agent);
7143
9013
  (0, react.useEffect)(() => {
7144
- const subscription = copilotkit.subscribe({ onError: ({ error }) => {
7145
- 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({
7146
9018
  error,
7147
9019
  message: error.message,
7148
9020
  url: typeof window !== "undefined" ? window.location.href : ""
7149
- }));
9021
+ });
9022
+ ckError.details = {
9023
+ code,
9024
+ context,
9025
+ stack: error.stack,
9026
+ originalMessage: error.message
9027
+ };
9028
+ setBannerError(ckError);
7150
9029
  } });
7151
9030
  return () => {
7152
9031
  subscription.unsubscribe();
@@ -7685,6 +9564,8 @@ Object.defineProperty(exports, 'CopilotChat', {
7685
9564
  }
7686
9565
  });
7687
9566
  exports.CopilotChatAssistantMessage = CopilotChatAssistantMessage_default;
9567
+ exports.CopilotChatAttachmentQueue = CopilotChatAttachmentQueue;
9568
+ exports.CopilotChatAttachmentRenderer = CopilotChatAttachmentRenderer;
7688
9569
  exports.CopilotChatAudioRecorder = CopilotChatAudioRecorder;
7689
9570
  exports.CopilotChatConfigurationProvider = CopilotChatConfigurationProvider;
7690
9571
  exports.CopilotChatInput = CopilotChatInput_default;
@@ -7725,12 +9606,20 @@ Object.defineProperty(exports, 'CopilotSidebarView', {
7725
9606
  exports.MCPAppsActivityContentSchema = MCPAppsActivityContentSchema;
7726
9607
  exports.MCPAppsActivityRenderer = MCPAppsActivityRenderer;
7727
9608
  exports.MCPAppsActivityType = MCPAppsActivityType;
9609
+ exports.SandboxFunctionsContext = SandboxFunctionsContext;
7728
9610
  exports.UseAgentUpdate = UseAgentUpdate;
7729
9611
  exports.WildcardToolCallRender = WildcardToolCallRender;
9612
+ Object.defineProperty(exports, 'a2uiDefaultTheme', {
9613
+ enumerable: true,
9614
+ get: function () {
9615
+ return _copilotkit_a2ui_renderer.defaultTheme;
9616
+ }
9617
+ });
7730
9618
  exports.createA2UIMessageRenderer = createA2UIMessageRenderer;
7731
9619
  exports.defineToolCallRenderer = defineToolCallRenderer;
7732
9620
  exports.useAgent = useAgent;
7733
9621
  exports.useAgentContext = useAgentContext;
9622
+ exports.useAttachments = useAttachments;
7734
9623
  exports.useComponent = useComponent;
7735
9624
  exports.useConfigureSuggestions = useConfigureSuggestions;
7736
9625
  exports.useCopilotChatConfiguration = useCopilotChatConfiguration;
@@ -7743,6 +9632,7 @@ exports.useRenderActivityMessage = useRenderActivityMessage;
7743
9632
  exports.useRenderCustomMessages = useRenderCustomMessages;
7744
9633
  exports.useRenderTool = useRenderTool;
7745
9634
  exports.useRenderToolCall = useRenderToolCall;
9635
+ exports.useSandboxFunctions = useSandboxFunctions;
7746
9636
  exports.useSuggestions = useSuggestions;
7747
9637
  exports.useThreads = useThreads;
7748
9638
  Object.keys(_copilotkit_core).forEach(function (k) {