@copilotkit/react-core 1.55.0-next.9 → 1.55.1-next.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.
- package/CHANGELOG.md +46 -6
- package/dist/{copilotkit-DeOzjPsb.mjs → copilotkit-BY5S1-0P.mjs} +2402 -552
- package/dist/copilotkit-BY5S1-0P.mjs.map +1 -0
- package/dist/{copilotkit-BqcyhQjT.d.mts → copilotkit-BuhSUZHb.d.mts} +228 -17
- package/dist/copilotkit-BuhSUZHb.d.mts.map +1 -0
- package/dist/{copilotkit-BDNjFNmk.cjs → copilotkit-Bz5-ImDl.cjs} +2421 -541
- package/dist/copilotkit-Bz5-ImDl.cjs.map +1 -0
- package/dist/{copilotkit-l-IBF4Xp.d.cts → copilotkit-dwDWYpya.d.cts} +228 -17
- package/dist/copilotkit-dwDWYpya.d.cts.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.umd.js +1400 -238
- package/dist/index.umd.js.map +1 -1
- package/dist/v2/index.cjs +13 -1
- package/dist/v2/index.css +1 -1
- package/dist/v2/index.d.cts +3 -3
- package/dist/v2/index.d.mts +3 -3
- package/dist/v2/index.mjs +3 -2
- package/dist/v2/index.umd.js +2442 -552
- package/dist/v2/index.umd.js.map +1 -1
- package/package.json +62 -54
- package/scripts/scope-preflight.mjs +1 -2
- package/src/components/CopilotListeners.tsx +41 -8
- package/src/components/copilot-provider/copilotkit-props.tsx +4 -2
- package/src/components/toast/toast-provider.tsx +269 -194
- package/src/v2/__tests__/A2UIMessageRenderer.test.tsx +86 -22
- package/src/v2/__tests__/utils/test-helpers.tsx +67 -0
- package/src/v2/a2ui/A2UICatalogContext.tsx +79 -0
- package/src/v2/a2ui/A2UIMessageRenderer.tsx +125 -37
- package/src/v2/a2ui/A2UIToolCallRenderer.tsx +290 -0
- package/src/v2/components/CopilotKitInspector.tsx +2 -0
- package/src/v2/components/OpenGenerativeUIRenderer.tsx +598 -0
- package/src/v2/components/__tests__/OpenGenerativeUIRenderer.test.tsx +665 -0
- package/src/v2/components/chat/CopilotChat.tsx +193 -50
- package/src/v2/components/chat/CopilotChatAssistantMessage.tsx +17 -2
- package/src/v2/components/chat/CopilotChatAttachmentQueue.tsx +481 -0
- package/src/v2/components/chat/CopilotChatAttachmentRenderer.tsx +139 -0
- package/src/v2/components/chat/CopilotChatInput.tsx +146 -77
- package/src/v2/components/chat/CopilotChatMessageView.tsx +253 -149
- package/src/v2/components/chat/CopilotChatSuggestionView.tsx +1 -0
- package/src/v2/components/chat/CopilotChatUserMessage.tsx +54 -0
- package/src/v2/components/chat/CopilotChatView.tsx +179 -66
- package/src/v2/components/chat/__tests__/CopilotChat.attachments.test.tsx +168 -0
- package/src/v2/components/chat/__tests__/CopilotChatActivityRendering.e2e.test.tsx +63 -2
- package/src/v2/components/chat/__tests__/CopilotChatInput.test.tsx +544 -1
- package/src/v2/components/chat/__tests__/CopilotChatPerf.e2e.test.tsx +268 -0
- package/src/v2/components/chat/__tests__/CopilotChatPropsRerender.e2e.test.tsx +249 -0
- package/src/v2/components/chat/__tests__/MCPAppsActivityRenderer.e2e.test.tsx +43 -2
- package/src/v2/components/chat/__tests__/copilot-chat-throttle.test.tsx +138 -0
- package/src/v2/components/chat/index.ts +9 -0
- package/src/v2/components/chat/scroll-element-context.ts +13 -0
- package/src/v2/hooks/__tests__/use-agent-throttle.test.tsx +1003 -0
- package/src/v2/hooks/__tests__/use-attachments.test.tsx +169 -0
- package/src/v2/hooks/__tests__/use-threads.test.tsx +54 -0
- package/src/v2/hooks/index.ts +5 -0
- package/src/v2/hooks/use-agent.tsx +95 -10
- package/src/v2/hooks/use-attachments.tsx +269 -0
- package/src/v2/hooks/use-frontend-tool.tsx +5 -2
- package/src/v2/hooks/use-render-activity-message.tsx +9 -2
- package/src/v2/hooks/use-threads.tsx +35 -15
- package/src/v2/index.ts +5 -1
- package/src/v2/lib/__tests__/processPartialHtml.test.ts +112 -0
- package/src/v2/lib/__tests__/slots.test.ts +56 -0
- package/src/v2/lib/processPartialHtml.ts +45 -0
- package/src/v2/lib/slots.tsx +42 -1
- package/src/v2/providers/CopilotChatConfigurationProvider.tsx +9 -3
- package/src/v2/providers/CopilotKitProvider.tsx +268 -32
- package/src/v2/providers/SandboxFunctionsContext.ts +10 -0
- package/src/v2/providers/__tests__/CopilotKitProvider.sandboxFunctions.test.tsx +198 -0
- package/src/v2/providers/__tests__/CopilotKitProvider.test.tsx +71 -0
- package/src/v2/providers/index.ts +7 -0
- package/src/v2/styles/globals.css +2 -1
- package/src/v2/types/index.ts +1 -0
- package/src/v2/types/sandbox-function.ts +11 -0
- package/dist/copilotkit-BDNjFNmk.cjs.map +0 -1
- package/dist/copilotkit-BqcyhQjT.d.mts.map +0 -1
- package/dist/copilotkit-DeOzjPsb.mjs.map +0 -1
- package/dist/copilotkit-l-IBF4Xp.d.cts.map +0 -1
- package/src/v2/components/__tests__/license-warning-banner.test.tsx +0 -46
|
@@ -44,19 +44,120 @@ let streamdown = require("streamdown");
|
|
|
44
44
|
let zod = require("zod");
|
|
45
45
|
let _lit_labs_react = require("@lit-labs/react");
|
|
46
46
|
let _copilotkit_a2ui_renderer = require("@copilotkit/a2ui-renderer");
|
|
47
|
-
let
|
|
48
|
-
let
|
|
47
|
+
let zod_to_json_schema = require("zod-to-json-schema");
|
|
48
|
+
let _tanstack_react_virtual = require("@tanstack/react-virtual");
|
|
49
49
|
let react_dom = require("react-dom");
|
|
50
|
+
let use_stick_to_bottom = require("use-stick-to-bottom");
|
|
50
51
|
let react_markdown = require("react-markdown");
|
|
51
52
|
react_markdown = __toESM(react_markdown);
|
|
52
53
|
|
|
54
|
+
//#region src/v2/lib/slots.tsx
|
|
55
|
+
/**
|
|
56
|
+
* Shallow equality comparison for objects.
|
|
57
|
+
*/
|
|
58
|
+
function shallowEqual(obj1, obj2) {
|
|
59
|
+
const keys1 = Object.keys(obj1);
|
|
60
|
+
const keys2 = Object.keys(obj2);
|
|
61
|
+
if (keys1.length !== keys2.length) return false;
|
|
62
|
+
for (const key of keys1) if (obj1[key] !== obj2[key]) return false;
|
|
63
|
+
return true;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Returns true only for plain JS objects (`{}`), excluding arrays, Dates,
|
|
67
|
+
* class instances, and other exotic objects that happen to have typeof "object".
|
|
68
|
+
*/
|
|
69
|
+
function isPlainObject(obj) {
|
|
70
|
+
return obj !== null && typeof obj === "object" && Object.prototype.toString.call(obj) === "[object Object]";
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Returns the same reference as long as the value is shallowly equal to the
|
|
74
|
+
* previous render's value.
|
|
75
|
+
*
|
|
76
|
+
* - Identical references bail out immediately (O(1)).
|
|
77
|
+
* - Plain objects ({}) are shallow-compared key-by-key.
|
|
78
|
+
* - Arrays, Dates, class instances, functions, and primitives are compared by
|
|
79
|
+
* reference only — shallowEqual is never called on non-plain objects, which
|
|
80
|
+
* avoids incorrect equality for e.g. [1,2] vs [1,2] (different arrays).
|
|
81
|
+
*
|
|
82
|
+
* Typical use: stabilize inline slot props so MemoizedSlotWrapper's shallow
|
|
83
|
+
* equality check isn't defeated by a new object reference on every render.
|
|
84
|
+
*/
|
|
85
|
+
function useShallowStableRef(value) {
|
|
86
|
+
const ref = (0, react.useRef)(value);
|
|
87
|
+
if (ref.current === value) return ref.current;
|
|
88
|
+
if (isPlainObject(ref.current) && isPlainObject(value)) {
|
|
89
|
+
if (shallowEqual(ref.current, value)) return ref.current;
|
|
90
|
+
}
|
|
91
|
+
ref.current = value;
|
|
92
|
+
return ref.current;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Check if a value is a React component type (function, class, forwardRef, memo, etc.)
|
|
96
|
+
*/
|
|
97
|
+
function isReactComponentType(value) {
|
|
98
|
+
if (typeof value === "function") return true;
|
|
99
|
+
if (value && typeof value === "object" && "$$typeof" in value && !react.default.isValidElement(value)) return true;
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Internal function to render a slot value as a React element (non-memoized).
|
|
104
|
+
*/
|
|
105
|
+
function renderSlotElement(slot, DefaultComponent, props) {
|
|
106
|
+
if (typeof slot === "string") {
|
|
107
|
+
const existingClassName = props.className;
|
|
108
|
+
return react.default.createElement(DefaultComponent, {
|
|
109
|
+
...props,
|
|
110
|
+
className: (0, tailwind_merge.twMerge)(existingClassName, slot)
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
if (isReactComponentType(slot)) return react.default.createElement(slot, props);
|
|
114
|
+
if (slot && typeof slot === "object" && !react.default.isValidElement(slot)) return react.default.createElement(DefaultComponent, {
|
|
115
|
+
...props,
|
|
116
|
+
...slot
|
|
117
|
+
});
|
|
118
|
+
return react.default.createElement(DefaultComponent, props);
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Internal memoized wrapper component for renderSlot.
|
|
122
|
+
* Uses forwardRef to support ref forwarding.
|
|
123
|
+
*/
|
|
124
|
+
const MemoizedSlotWrapper = react.default.memo(react.default.forwardRef(function MemoizedSlotWrapper(props, ref) {
|
|
125
|
+
const { $slot, $component, ...rest } = props;
|
|
126
|
+
return renderSlotElement($slot, $component, ref !== null ? {
|
|
127
|
+
...rest,
|
|
128
|
+
ref
|
|
129
|
+
} : rest);
|
|
130
|
+
}), (prev, next) => {
|
|
131
|
+
if (prev.$slot !== next.$slot) return false;
|
|
132
|
+
if (prev.$component !== next.$component) return false;
|
|
133
|
+
const { $slot: _ps, $component: _pc, ...prevRest } = prev;
|
|
134
|
+
const { $slot: _ns, $component: _nc, ...nextRest } = next;
|
|
135
|
+
return shallowEqual(prevRest, nextRest);
|
|
136
|
+
});
|
|
137
|
+
/**
|
|
138
|
+
* Renders a slot value as a memoized React element.
|
|
139
|
+
* Automatically prevents unnecessary re-renders using shallow prop comparison.
|
|
140
|
+
* Supports ref forwarding.
|
|
141
|
+
*
|
|
142
|
+
* @example
|
|
143
|
+
* renderSlot(customInput, CopilotChatInput, { onSubmit: handleSubmit })
|
|
144
|
+
*/
|
|
145
|
+
function renderSlot(slot, DefaultComponent, props) {
|
|
146
|
+
return react.default.createElement(MemoizedSlotWrapper, {
|
|
147
|
+
...props,
|
|
148
|
+
$slot: slot,
|
|
149
|
+
$component: DefaultComponent
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
//#endregion
|
|
53
154
|
//#region src/v2/providers/CopilotChatConfigurationProvider.tsx
|
|
54
155
|
const CopilotChatDefaultLabels = {
|
|
55
156
|
chatInputPlaceholder: "Type a message...",
|
|
56
157
|
chatInputToolbarStartTranscribeButtonLabel: "Transcribe",
|
|
57
158
|
chatInputToolbarCancelTranscribeButtonLabel: "Cancel",
|
|
58
159
|
chatInputToolbarFinishTranscribeButtonLabel: "Finish",
|
|
59
|
-
chatInputToolbarAddButtonLabel: "Add
|
|
160
|
+
chatInputToolbarAddButtonLabel: "Add attachments",
|
|
60
161
|
chatInputToolbarToolsButtonLabel: "Tools",
|
|
61
162
|
assistantMessageToolbarCopyCodeLabel: "Copy",
|
|
62
163
|
assistantMessageToolbarCopyCodeCopiedLabel: "Copied",
|
|
@@ -76,11 +177,12 @@ const CopilotChatDefaultLabels = {
|
|
|
76
177
|
const CopilotChatConfiguration = (0, react.createContext)(null);
|
|
77
178
|
const CopilotChatConfigurationProvider = ({ children, labels, agentId, threadId, isModalDefaultOpen }) => {
|
|
78
179
|
const parentConfig = (0, react.useContext)(CopilotChatConfiguration);
|
|
180
|
+
const stableLabels = useShallowStableRef(labels);
|
|
79
181
|
const mergedLabels = (0, react.useMemo)(() => ({
|
|
80
182
|
...CopilotChatDefaultLabels,
|
|
81
183
|
...parentConfig?.labels ?? {},
|
|
82
|
-
...
|
|
83
|
-
}), [
|
|
184
|
+
...stableLabels ?? {}
|
|
185
|
+
}), [stableLabels, parentConfig?.labels]);
|
|
84
186
|
const resolvedAgentId = agentId ?? parentConfig?.agentId ?? _copilotkit_shared.DEFAULT_AGENT_ID;
|
|
85
187
|
const resolvedThreadId = (0, react.useMemo)(() => {
|
|
86
188
|
if (threadId) return threadId;
|
|
@@ -129,9 +231,9 @@ const useCopilotChatConfiguration = () => {
|
|
|
129
231
|
|
|
130
232
|
//#endregion
|
|
131
233
|
//#region src/v2/lib/utils.ts
|
|
132
|
-
const twMerge$
|
|
234
|
+
const twMerge$7 = (0, tailwind_merge.extendTailwindMerge)({ prefix: "cpk" });
|
|
133
235
|
function cn(...inputs) {
|
|
134
|
-
return twMerge$
|
|
236
|
+
return twMerge$7((0, clsx.clsx)(inputs));
|
|
135
237
|
}
|
|
136
238
|
|
|
137
239
|
//#endregion
|
|
@@ -503,82 +605,11 @@ const CopilotChatAudioRecorder = (0, react.forwardRef)((props, ref) => {
|
|
|
503
605
|
});
|
|
504
606
|
CopilotChatAudioRecorder.displayName = "CopilotChatAudioRecorder";
|
|
505
607
|
|
|
506
|
-
//#endregion
|
|
507
|
-
//#region src/v2/lib/slots.tsx
|
|
508
|
-
/**
|
|
509
|
-
* Shallow equality comparison for objects.
|
|
510
|
-
*/
|
|
511
|
-
function shallowEqual(obj1, obj2) {
|
|
512
|
-
const keys1 = Object.keys(obj1);
|
|
513
|
-
const keys2 = Object.keys(obj2);
|
|
514
|
-
if (keys1.length !== keys2.length) return false;
|
|
515
|
-
for (const key of keys1) if (obj1[key] !== obj2[key]) return false;
|
|
516
|
-
return true;
|
|
517
|
-
}
|
|
518
|
-
/**
|
|
519
|
-
* Check if a value is a React component type (function, class, forwardRef, memo, etc.)
|
|
520
|
-
*/
|
|
521
|
-
function isReactComponentType(value) {
|
|
522
|
-
if (typeof value === "function") return true;
|
|
523
|
-
if (value && typeof value === "object" && "$$typeof" in value && !react.default.isValidElement(value)) return true;
|
|
524
|
-
return false;
|
|
525
|
-
}
|
|
526
|
-
/**
|
|
527
|
-
* Internal function to render a slot value as a React element (non-memoized).
|
|
528
|
-
*/
|
|
529
|
-
function renderSlotElement(slot, DefaultComponent, props) {
|
|
530
|
-
if (typeof slot === "string") {
|
|
531
|
-
const existingClassName = props.className;
|
|
532
|
-
return react.default.createElement(DefaultComponent, {
|
|
533
|
-
...props,
|
|
534
|
-
className: (0, tailwind_merge.twMerge)(existingClassName, slot)
|
|
535
|
-
});
|
|
536
|
-
}
|
|
537
|
-
if (isReactComponentType(slot)) return react.default.createElement(slot, props);
|
|
538
|
-
if (slot && typeof slot === "object" && !react.default.isValidElement(slot)) return react.default.createElement(DefaultComponent, {
|
|
539
|
-
...props,
|
|
540
|
-
...slot
|
|
541
|
-
});
|
|
542
|
-
return react.default.createElement(DefaultComponent, props);
|
|
543
|
-
}
|
|
544
|
-
/**
|
|
545
|
-
* Internal memoized wrapper component for renderSlot.
|
|
546
|
-
* Uses forwardRef to support ref forwarding.
|
|
547
|
-
*/
|
|
548
|
-
const MemoizedSlotWrapper = react.default.memo(react.default.forwardRef(function MemoizedSlotWrapper(props, ref) {
|
|
549
|
-
const { $slot, $component, ...rest } = props;
|
|
550
|
-
return renderSlotElement($slot, $component, ref !== null ? {
|
|
551
|
-
...rest,
|
|
552
|
-
ref
|
|
553
|
-
} : rest);
|
|
554
|
-
}), (prev, next) => {
|
|
555
|
-
if (prev.$slot !== next.$slot) return false;
|
|
556
|
-
if (prev.$component !== next.$component) return false;
|
|
557
|
-
const { $slot: _ps, $component: _pc, ...prevRest } = prev;
|
|
558
|
-
const { $slot: _ns, $component: _nc, ...nextRest } = next;
|
|
559
|
-
return shallowEqual(prevRest, nextRest);
|
|
560
|
-
});
|
|
561
|
-
/**
|
|
562
|
-
* Renders a slot value as a memoized React element.
|
|
563
|
-
* Automatically prevents unnecessary re-renders using shallow prop comparison.
|
|
564
|
-
* Supports ref forwarding.
|
|
565
|
-
*
|
|
566
|
-
* @example
|
|
567
|
-
* renderSlot(customInput, CopilotChatInput, { onSubmit: handleSubmit })
|
|
568
|
-
*/
|
|
569
|
-
function renderSlot(slot, DefaultComponent, props) {
|
|
570
|
-
return react.default.createElement(MemoizedSlotWrapper, {
|
|
571
|
-
...props,
|
|
572
|
-
$slot: slot,
|
|
573
|
-
$component: DefaultComponent
|
|
574
|
-
});
|
|
575
|
-
}
|
|
576
|
-
|
|
577
608
|
//#endregion
|
|
578
609
|
//#region src/v2/components/chat/CopilotChatInput.tsx
|
|
579
610
|
const SLASH_MENU_MAX_VISIBLE_ITEMS = 5;
|
|
580
611
|
const SLASH_MENU_ITEM_HEIGHT_PX = 40;
|
|
581
|
-
function CopilotChatInput({ mode = "input", onSubmitMessage, onStop, isRunning = false, onStartTranscribe, onCancelTranscribe, onFinishTranscribe, onFinishTranscribeWithAudio, onAddFile, onChange, value, toolsMenu, autoFocus =
|
|
612
|
+
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 }) {
|
|
582
613
|
const isControlled = value !== void 0;
|
|
583
614
|
const [internalValue, setInternalValue] = (0, react.useState)(() => value ?? "");
|
|
584
615
|
(0, react.useEffect)(() => {
|
|
@@ -607,6 +638,7 @@ function CopilotChatInput({ mode = "input", onSubmitMessage, onStop, isRunning =
|
|
|
607
638
|
paddingLeft: 0,
|
|
608
639
|
paddingRight: 0
|
|
609
640
|
});
|
|
641
|
+
const containerCacheRef = (0, react.useRef)(null);
|
|
610
642
|
const commandItems = (0, react.useMemo)(() => {
|
|
611
643
|
const entries = [];
|
|
612
644
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -651,7 +683,7 @@ function CopilotChatInput({ mode = "input", onSubmitMessage, onStop, isRunning =
|
|
|
651
683
|
previousModalStateRef.current = config?.isModalOpen;
|
|
652
684
|
return;
|
|
653
685
|
}
|
|
654
|
-
if (config?.isModalOpen && !previousModalStateRef.current) inputRef.current?.focus();
|
|
686
|
+
if (config?.isModalOpen && !previousModalStateRef.current) inputRef.current?.focus({ preventScroll: true });
|
|
655
687
|
previousModalStateRef.current = config?.isModalOpen;
|
|
656
688
|
}, [config?.isModalOpen, autoFocus]);
|
|
657
689
|
(0, react.useEffect)(() => {
|
|
@@ -894,6 +926,25 @@ function CopilotChatInput({ mode = "input", onSubmitMessage, onStop, isRunning =
|
|
|
894
926
|
return nextLayout;
|
|
895
927
|
});
|
|
896
928
|
}, []);
|
|
929
|
+
const updateContainerCache = (0, react.useCallback)(() => {
|
|
930
|
+
const grid = gridRef.current;
|
|
931
|
+
const addContainer = addButtonContainerRef.current;
|
|
932
|
+
const actionsContainer = actionsContainerRef.current;
|
|
933
|
+
if (!grid || !addContainer || !actionsContainer) return null;
|
|
934
|
+
const gridStyles = window.getComputedStyle(grid);
|
|
935
|
+
const paddingLeft = parseFloat(gridStyles.paddingLeft) || 0;
|
|
936
|
+
const paddingRight = parseFloat(gridStyles.paddingRight) || 0;
|
|
937
|
+
const columnGap = parseFloat(gridStyles.columnGap) || 0;
|
|
938
|
+
const gridAvailableWidth = grid.clientWidth - paddingLeft - paddingRight;
|
|
939
|
+
if (gridAvailableWidth <= 0) return null;
|
|
940
|
+
const addWidth = addContainer.getBoundingClientRect().width;
|
|
941
|
+
const actionsWidth = actionsContainer.getBoundingClientRect().width;
|
|
942
|
+
const compactWidth = Math.max(gridAvailableWidth - addWidth - actionsWidth - columnGap * 2, 0);
|
|
943
|
+
if (compactWidth <= 0) return null;
|
|
944
|
+
const result = { compactWidth };
|
|
945
|
+
containerCacheRef.current = result;
|
|
946
|
+
return result;
|
|
947
|
+
}, []);
|
|
897
948
|
const evaluateLayout = (0, react.useCallback)(() => {
|
|
898
949
|
if (mode !== "input") {
|
|
899
950
|
updateLayout("compact");
|
|
@@ -919,31 +970,31 @@ function CopilotChatInput({ mode = "input", onSubmitMessage, onStop, isRunning =
|
|
|
919
970
|
const renderedMultiline = baseline > 0 ? scrollHeight > baseline + 1 : false;
|
|
920
971
|
let shouldExpand = hasExplicitBreak || renderedMultiline;
|
|
921
972
|
if (!shouldExpand) {
|
|
922
|
-
const
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
const gridAvailableWidth = grid.clientWidth - paddingLeft - paddingRight;
|
|
927
|
-
if (gridAvailableWidth > 0) {
|
|
928
|
-
const addWidth = addContainer.getBoundingClientRect().width;
|
|
929
|
-
const actionsWidth = actionsContainer.getBoundingClientRect().width;
|
|
930
|
-
const compactWidth = Math.max(gridAvailableWidth - addWidth - actionsWidth - columnGap * 2, 0);
|
|
931
|
-
const canvas = measurementCanvasRef.current ?? document.createElement("canvas");
|
|
932
|
-
if (!measurementCanvasRef.current) measurementCanvasRef.current = canvas;
|
|
933
|
-
const context = canvas.getContext("2d");
|
|
934
|
-
if (context) {
|
|
973
|
+
const cache = containerCacheRef.current ?? 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) {
|
|
935
977
|
const textareaStyles = window.getComputedStyle(textarea);
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
let longestWidth = 0;
|
|
941
|
-
for (const line of lines) {
|
|
942
|
-
const metrics = context.measureText(line || " ");
|
|
943
|
-
if (metrics.width > longestWidth) longestWidth = metrics.width;
|
|
944
|
-
}
|
|
945
|
-
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}`;
|
|
946
982
|
}
|
|
983
|
+
if (font?.trim()) {
|
|
984
|
+
const canvas = measurementCanvasRef.current ?? document.createElement("canvas");
|
|
985
|
+
if (!measurementCanvasRef.current) measurementCanvasRef.current = canvas;
|
|
986
|
+
const context = canvas.getContext("2d");
|
|
987
|
+
if (context) {
|
|
988
|
+
context.font = font;
|
|
989
|
+
const lines = resolvedValue.length > 0 ? resolvedValue.split("\n") : [""];
|
|
990
|
+
let longestWidth = 0;
|
|
991
|
+
for (const line of lines) {
|
|
992
|
+
const metrics = context.measureText(line || " ");
|
|
993
|
+
if (metrics.width > longestWidth) longestWidth = metrics.width;
|
|
994
|
+
}
|
|
995
|
+
if (longestWidth > compactInnerWidth) shouldExpand = true;
|
|
996
|
+
} else if (process.env.NODE_ENV !== "production") console.warn("[CopilotChatInput] canvas.getContext('2d') returned null. Text-width-based expansion will be unavailable.");
|
|
997
|
+
} 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.");
|
|
947
998
|
}
|
|
948
999
|
}
|
|
949
1000
|
}
|
|
@@ -953,6 +1004,7 @@ function CopilotChatInput({ mode = "input", onSubmitMessage, onStop, isRunning =
|
|
|
953
1004
|
ensureMeasurements,
|
|
954
1005
|
mode,
|
|
955
1006
|
resolvedValue,
|
|
1007
|
+
updateContainerCache,
|
|
956
1008
|
updateLayout
|
|
957
1009
|
]);
|
|
958
1010
|
(0, react.useLayoutEffect)(() => {
|
|
@@ -965,11 +1017,17 @@ function CopilotChatInput({ mode = "input", onSubmitMessage, onStop, isRunning =
|
|
|
965
1017
|
const addContainer = addButtonContainerRef.current;
|
|
966
1018
|
const actionsContainer = actionsContainerRef.current;
|
|
967
1019
|
if (!textarea || !grid || !addContainer || !actionsContainer) return;
|
|
968
|
-
const
|
|
1020
|
+
const containerTargets = new Set([
|
|
1021
|
+
grid,
|
|
1022
|
+
addContainer,
|
|
1023
|
+
actionsContainer
|
|
1024
|
+
]);
|
|
1025
|
+
const scheduleEvaluation = (invalidateCache) => {
|
|
969
1026
|
if (ignoreResizeRef.current) {
|
|
970
1027
|
ignoreResizeRef.current = false;
|
|
971
1028
|
return;
|
|
972
1029
|
}
|
|
1030
|
+
if (invalidateCache) containerCacheRef.current = null;
|
|
973
1031
|
if (typeof window === "undefined") {
|
|
974
1032
|
evaluateLayout();
|
|
975
1033
|
return;
|
|
@@ -980,8 +1038,13 @@ function CopilotChatInput({ mode = "input", onSubmitMessage, onStop, isRunning =
|
|
|
980
1038
|
evaluateLayout();
|
|
981
1039
|
});
|
|
982
1040
|
};
|
|
983
|
-
const observer = new ResizeObserver(() => {
|
|
984
|
-
|
|
1041
|
+
const observer = new ResizeObserver((entries) => {
|
|
1042
|
+
let shouldInvalidate = false;
|
|
1043
|
+
for (const entry of entries) if (containerTargets.has(entry.target)) {
|
|
1044
|
+
shouldInvalidate = true;
|
|
1045
|
+
break;
|
|
1046
|
+
}
|
|
1047
|
+
scheduleEvaluation(shouldInvalidate);
|
|
985
1048
|
});
|
|
986
1049
|
observer.observe(grid);
|
|
987
1050
|
observer.observe(addContainer);
|
|
@@ -1126,6 +1189,8 @@ function CopilotChatInput({ mode = "input", onSubmitMessage, onStop, isRunning =
|
|
|
1126
1189
|
});
|
|
1127
1190
|
_CopilotChatInput.AddMenuButton = ({ className, toolsMenu, onAddFile, disabled, ...props }) => {
|
|
1128
1191
|
const labels = useCopilotChatConfiguration()?.labels ?? CopilotChatDefaultLabels;
|
|
1192
|
+
const [mounted, setMounted] = (0, react.useState)(false);
|
|
1193
|
+
(0, react.useEffect)(() => setMounted(true), []);
|
|
1129
1194
|
const menuItems = (0, react.useMemo)(() => {
|
|
1130
1195
|
const items = [];
|
|
1131
1196
|
if (onAddFile) items.push({
|
|
@@ -1156,26 +1221,28 @@ function CopilotChatInput({ mode = "input", onSubmitMessage, onStop, isRunning =
|
|
|
1156
1221
|
}), []);
|
|
1157
1222
|
const hasMenuItems = menuItems.length > 0;
|
|
1158
1223
|
const isDisabled = disabled || !hasMenuItems;
|
|
1224
|
+
const button = /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
|
|
1225
|
+
type: "button",
|
|
1226
|
+
"data-testid": "copilot-add-menu-button",
|
|
1227
|
+
variant: "chatInputToolbarSecondary",
|
|
1228
|
+
size: "chatInputToolbarIcon",
|
|
1229
|
+
className: (0, tailwind_merge.twMerge)("cpk:ml-1", className),
|
|
1230
|
+
disabled: isDisabled,
|
|
1231
|
+
...props,
|
|
1232
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Plus, { className: "cpk:size-[20px]" })
|
|
1233
|
+
});
|
|
1234
|
+
if (!mounted) return button;
|
|
1159
1235
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(DropdownMenu, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Tooltip, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(TooltipTrigger, {
|
|
1160
1236
|
asChild: true,
|
|
1161
1237
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DropdownMenuTrigger, {
|
|
1162
1238
|
asChild: true,
|
|
1163
|
-
children:
|
|
1164
|
-
type: "button",
|
|
1165
|
-
"data-testid": "copilot-add-menu-button",
|
|
1166
|
-
variant: "chatInputToolbarSecondary",
|
|
1167
|
-
size: "chatInputToolbarIcon",
|
|
1168
|
-
className: (0, tailwind_merge.twMerge)("cpk:ml-1", className),
|
|
1169
|
-
disabled: isDisabled,
|
|
1170
|
-
...props,
|
|
1171
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Plus, { className: "cpk:size-[20px]" })
|
|
1172
|
-
})
|
|
1239
|
+
children: button
|
|
1173
1240
|
})
|
|
1174
1241
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TooltipContent, {
|
|
1175
1242
|
side: "bottom",
|
|
1176
1243
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
|
|
1177
1244
|
className: "cpk:flex cpk:items-center cpk:gap-1 cpk:text-xs cpk:font-medium",
|
|
1178
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "Add
|
|
1245
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "Add attachments" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", {
|
|
1179
1246
|
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",
|
|
1180
1247
|
children: "/"
|
|
1181
1248
|
})]
|
|
@@ -1191,21 +1258,7 @@ function CopilotChatInput({ mode = "input", onSubmitMessage, onStop, isRunning =
|
|
|
1191
1258
|
const labels = useCopilotChatConfiguration()?.labels ?? CopilotChatDefaultLabels;
|
|
1192
1259
|
(0, react.useImperativeHandle)(ref, () => internalTextareaRef.current);
|
|
1193
1260
|
(0, react.useEffect)(() => {
|
|
1194
|
-
|
|
1195
|
-
if (!textarea) return;
|
|
1196
|
-
const handleFocus = () => {
|
|
1197
|
-
setTimeout(() => {
|
|
1198
|
-
textarea.scrollIntoView({
|
|
1199
|
-
behavior: "smooth",
|
|
1200
|
-
block: "nearest"
|
|
1201
|
-
});
|
|
1202
|
-
}, 300);
|
|
1203
|
-
};
|
|
1204
|
-
textarea.addEventListener("focus", handleFocus);
|
|
1205
|
-
return () => textarea.removeEventListener("focus", handleFocus);
|
|
1206
|
-
}, []);
|
|
1207
|
-
(0, react.useEffect)(() => {
|
|
1208
|
-
if (autoFocus) internalTextareaRef.current?.focus();
|
|
1261
|
+
if (autoFocus) internalTextareaRef.current?.focus({ preventScroll: true });
|
|
1209
1262
|
}, [autoFocus]);
|
|
1210
1263
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
|
|
1211
1264
|
ref: internalTextareaRef,
|
|
@@ -1912,8 +1965,411 @@ const MCPAppsActivityRenderer = function MCPAppsActivityRenderer({ content, agen
|
|
|
1912
1965
|
});
|
|
1913
1966
|
};
|
|
1914
1967
|
|
|
1968
|
+
//#endregion
|
|
1969
|
+
//#region src/v2/providers/SandboxFunctionsContext.ts
|
|
1970
|
+
const SandboxFunctionsContext = (0, react.createContext)([]);
|
|
1971
|
+
function useSandboxFunctions() {
|
|
1972
|
+
return (0, react.useContext)(SandboxFunctionsContext);
|
|
1973
|
+
}
|
|
1974
|
+
|
|
1975
|
+
//#endregion
|
|
1976
|
+
//#region src/v2/lib/processPartialHtml.ts
|
|
1977
|
+
/**
|
|
1978
|
+
* Extracts all complete `<style>` blocks from the raw HTML.
|
|
1979
|
+
* Returns the concatenated style tags, suitable for injection into `<head>`.
|
|
1980
|
+
*/
|
|
1981
|
+
function extractCompleteStyles(html) {
|
|
1982
|
+
const matches = html.match(/<style\b[^>]*>[\s\S]*?<\/style>/gi);
|
|
1983
|
+
return matches ? matches.join("") : "";
|
|
1984
|
+
}
|
|
1985
|
+
/**
|
|
1986
|
+
* Processes raw accumulated HTML for safe preview via innerHTML injection.
|
|
1987
|
+
* Pure function, no DOM dependencies.
|
|
1988
|
+
*
|
|
1989
|
+
* Pipeline (order matters):
|
|
1990
|
+
* 1. Strip incomplete tag at end
|
|
1991
|
+
* 2. Strip complete <style>, <script>, and <head> blocks
|
|
1992
|
+
* 3. Strip incomplete <style>/<script>/<head> blocks
|
|
1993
|
+
* 4. Strip incomplete HTML entities
|
|
1994
|
+
* 5. Extract body content (or use full string if no <body>)
|
|
1995
|
+
*/
|
|
1996
|
+
function processPartialHtml(html) {
|
|
1997
|
+
let result = html;
|
|
1998
|
+
result = result.replace(/<[^>]*$/, "");
|
|
1999
|
+
result = result.replace(/<(style|script|head)\b[^>]*>[\s\S]*?<\/\1>/gi, "");
|
|
2000
|
+
result = result.replace(/<(style|script|head)\b[^>]*>[\s\S]*$/gi, "");
|
|
2001
|
+
result = result.replace(/&[a-zA-Z0-9#]*$/, "");
|
|
2002
|
+
const bodyMatch = result.match(/<body[^>]*>([\s\S]*)/i);
|
|
2003
|
+
if (bodyMatch) {
|
|
2004
|
+
result = bodyMatch[1];
|
|
2005
|
+
result = result.replace(/<\/body>[\s\S]*/i, "");
|
|
2006
|
+
}
|
|
2007
|
+
return result;
|
|
2008
|
+
}
|
|
2009
|
+
|
|
2010
|
+
//#endregion
|
|
2011
|
+
//#region src/v2/components/OpenGenerativeUIRenderer.tsx
|
|
2012
|
+
const OpenGenerativeUIActivityType = "open-generative-ui";
|
|
2013
|
+
const OpenGenerativeUIContentSchema = zod.z.object({
|
|
2014
|
+
initialHeight: zod.z.number().optional(),
|
|
2015
|
+
generating: zod.z.boolean().optional(),
|
|
2016
|
+
css: zod.z.string().optional(),
|
|
2017
|
+
cssComplete: zod.z.boolean().optional(),
|
|
2018
|
+
html: zod.z.array(zod.z.string()).optional(),
|
|
2019
|
+
htmlComplete: zod.z.boolean().optional(),
|
|
2020
|
+
jsFunctions: zod.z.string().optional(),
|
|
2021
|
+
jsFunctionsComplete: zod.z.boolean().optional(),
|
|
2022
|
+
jsExpressions: zod.z.array(zod.z.string()).optional(),
|
|
2023
|
+
jsExpressionsComplete: zod.z.boolean().optional()
|
|
2024
|
+
});
|
|
2025
|
+
/**
|
|
2026
|
+
* Schema for the generateSandboxedUi tool call arguments.
|
|
2027
|
+
* Used by the frontend tool renderer to display placeholder messages.
|
|
2028
|
+
*/
|
|
2029
|
+
const GenerateSandboxedUiArgsSchema = zod.z.object({
|
|
2030
|
+
initialHeight: zod.z.number().optional(),
|
|
2031
|
+
placeholderMessages: zod.z.array(zod.z.string()).optional(),
|
|
2032
|
+
css: zod.z.string().optional(),
|
|
2033
|
+
html: zod.z.string().optional(),
|
|
2034
|
+
jsFunctions: zod.z.string().optional(),
|
|
2035
|
+
jsExpressions: zod.z.array(zod.z.string()).optional()
|
|
2036
|
+
});
|
|
2037
|
+
const THROTTLE_MS = 1e3;
|
|
2038
|
+
/**
|
|
2039
|
+
* Returns true when the inner component should re-render immediately
|
|
2040
|
+
* (no throttle delay).
|
|
2041
|
+
*/
|
|
2042
|
+
function shouldFlushImmediately(prev, next) {
|
|
2043
|
+
if (next.cssComplete && (!prev || !prev.cssComplete)) return true;
|
|
2044
|
+
if (next.htmlComplete) return true;
|
|
2045
|
+
if (next.generating === false) return true;
|
|
2046
|
+
if (next.jsFunctions && (!prev || !prev.jsFunctions)) return true;
|
|
2047
|
+
if ((next.jsExpressions?.length ?? 0) > (prev?.jsExpressions?.length ?? 0)) return true;
|
|
2048
|
+
if (next.html?.length && (!prev || !prev.html?.length)) return true;
|
|
2049
|
+
return false;
|
|
2050
|
+
}
|
|
2051
|
+
/**
|
|
2052
|
+
* Outer wrapper — absorbs every parent re-render but only forwards
|
|
2053
|
+
* throttled content snapshots to the memoized inner component.
|
|
2054
|
+
*/
|
|
2055
|
+
const OpenGenerativeUIActivityRenderer = function OpenGenerativeUIActivityRenderer({ content }) {
|
|
2056
|
+
const latestContentRef = (0, react.useRef)(content);
|
|
2057
|
+
latestContentRef.current = content;
|
|
2058
|
+
const [throttledContent, setThrottledContent] = (0, react.useState)(content);
|
|
2059
|
+
const throttledContentRef = (0, react.useRef)(throttledContent);
|
|
2060
|
+
const timerRef = (0, react.useRef)(null);
|
|
2061
|
+
if (throttledContentRef.current !== content) {
|
|
2062
|
+
if (shouldFlushImmediately(throttledContentRef.current, content)) {
|
|
2063
|
+
if (timerRef.current !== null) {
|
|
2064
|
+
clearTimeout(timerRef.current);
|
|
2065
|
+
timerRef.current = null;
|
|
2066
|
+
}
|
|
2067
|
+
throttledContentRef.current = content;
|
|
2068
|
+
setThrottledContent(content);
|
|
2069
|
+
}
|
|
2070
|
+
}
|
|
2071
|
+
const flush = (0, react.useCallback)(() => {
|
|
2072
|
+
timerRef.current = null;
|
|
2073
|
+
const latest = latestContentRef.current;
|
|
2074
|
+
throttledContentRef.current = latest;
|
|
2075
|
+
setThrottledContent(latest);
|
|
2076
|
+
}, []);
|
|
2077
|
+
(0, react.useEffect)(() => {
|
|
2078
|
+
if (throttledContentRef.current === content) return;
|
|
2079
|
+
if (timerRef.current === null) timerRef.current = setTimeout(flush, THROTTLE_MS);
|
|
2080
|
+
}, [content, flush]);
|
|
2081
|
+
(0, react.useEffect)(() => {
|
|
2082
|
+
return () => {
|
|
2083
|
+
if (timerRef.current !== null) clearTimeout(timerRef.current);
|
|
2084
|
+
};
|
|
2085
|
+
}, []);
|
|
2086
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(OpenGenerativeUIActivityRendererInner, { content: throttledContent });
|
|
2087
|
+
};
|
|
2088
|
+
function ensureHead(html) {
|
|
2089
|
+
if (/<head[\s>]/i.test(html)) return html;
|
|
2090
|
+
return `<head></head>${html}`;
|
|
2091
|
+
}
|
|
2092
|
+
function injectCssIntoHtml(html, css) {
|
|
2093
|
+
const headCloseIdx = html.indexOf("</head>");
|
|
2094
|
+
if (headCloseIdx !== -1) return html.slice(0, headCloseIdx) + `<style>${css}</style>` + html.slice(headCloseIdx);
|
|
2095
|
+
return `<head><style>${css}</style></head>${html}`;
|
|
2096
|
+
}
|
|
2097
|
+
const OpenGenerativeUIActivityRendererInner = react.default.memo(function OpenGenerativeUIActivityRendererInner({ content }) {
|
|
2098
|
+
const initialHeight = content.initialHeight ?? 200;
|
|
2099
|
+
const [autoHeight, setAutoHeight] = (0, react.useState)(null);
|
|
2100
|
+
const sandboxFunctions = useSandboxFunctions();
|
|
2101
|
+
const localApi = (0, react.useMemo)(() => {
|
|
2102
|
+
const api = {};
|
|
2103
|
+
for (const fn of sandboxFunctions) api[fn.name] = fn.handler;
|
|
2104
|
+
return api;
|
|
2105
|
+
}, [sandboxFunctions]);
|
|
2106
|
+
const fullHtml = content.htmlComplete && content.html?.length ? content.html.join("") : void 0;
|
|
2107
|
+
const css = content.cssComplete ? content.css : void 0;
|
|
2108
|
+
const cssReady = !!content.cssComplete;
|
|
2109
|
+
const partialHtml = !content.htmlComplete && content.html?.length ? content.html.join("") : void 0;
|
|
2110
|
+
const previewBody = partialHtml ? processPartialHtml(partialHtml) : void 0;
|
|
2111
|
+
const previewStyles = partialHtml ? extractCompleteStyles(partialHtml) : "";
|
|
2112
|
+
const hasPreview = cssReady && !!previewBody?.trim();
|
|
2113
|
+
const hasVisibleSandbox = !!fullHtml || hasPreview;
|
|
2114
|
+
const containerRef = (0, react.useRef)(null);
|
|
2115
|
+
const sandboxRef = (0, react.useRef)(null);
|
|
2116
|
+
const previewSandboxRef = (0, react.useRef)(null);
|
|
2117
|
+
const previewReadyRef = (0, react.useRef)(false);
|
|
2118
|
+
const sandboxReadyRef = (0, react.useRef)(false);
|
|
2119
|
+
const executedIndexRef = (0, react.useRef)(0);
|
|
2120
|
+
const pendingQueueRef = (0, react.useRef)([]);
|
|
2121
|
+
const jsFunctionsInjectedRef = (0, react.useRef)(false);
|
|
2122
|
+
(0, react.useEffect)(() => {
|
|
2123
|
+
const container = containerRef.current;
|
|
2124
|
+
if (!container || fullHtml || !hasPreview || previewSandboxRef.current) return;
|
|
2125
|
+
let cancelled = false;
|
|
2126
|
+
import("@jetbrains/websandbox").then((mod) => {
|
|
2127
|
+
if (cancelled) return;
|
|
2128
|
+
const sandbox = (mod.default?.default ?? mod.default).create({}, {
|
|
2129
|
+
frameContainer: container,
|
|
2130
|
+
frameContent: "<head></head><body></body>",
|
|
2131
|
+
allowAdditionalAttributes: ""
|
|
2132
|
+
});
|
|
2133
|
+
previewSandboxRef.current = sandbox;
|
|
2134
|
+
sandbox.iframe.style.width = "100%";
|
|
2135
|
+
sandbox.iframe.style.height = "100%";
|
|
2136
|
+
sandbox.iframe.style.border = "none";
|
|
2137
|
+
sandbox.iframe.style.backgroundColor = "transparent";
|
|
2138
|
+
sandbox.promise.then(() => {
|
|
2139
|
+
if (cancelled) return;
|
|
2140
|
+
previewReadyRef.current = true;
|
|
2141
|
+
sandbox.run(`
|
|
2142
|
+
var s = document.createElement('style');
|
|
2143
|
+
s.textContent = 'html, body { overflow: hidden !important; }';
|
|
2144
|
+
document.head.appendChild(s);
|
|
2145
|
+
`);
|
|
2146
|
+
const headParts = [];
|
|
2147
|
+
if (css) headParts.push(`<style>${css}</style>`);
|
|
2148
|
+
if (previewStyles) headParts.push(previewStyles);
|
|
2149
|
+
if (headParts.length) sandbox.run(`document.head.innerHTML = ${JSON.stringify(headParts.join(""))}`);
|
|
2150
|
+
if (previewBody) sandbox.run(`document.body.innerHTML = ${JSON.stringify(previewBody)}`);
|
|
2151
|
+
});
|
|
2152
|
+
}).catch((err) => {
|
|
2153
|
+
console.error("[OpenGenerativeUI] Failed to load sandbox module:", err);
|
|
2154
|
+
});
|
|
2155
|
+
return () => {
|
|
2156
|
+
cancelled = true;
|
|
2157
|
+
};
|
|
2158
|
+
}, [hasPreview, fullHtml]);
|
|
2159
|
+
(0, react.useEffect)(() => {
|
|
2160
|
+
if (!previewSandboxRef.current || !previewReadyRef.current) return;
|
|
2161
|
+
const headParts = [];
|
|
2162
|
+
if (css) headParts.push(`<style>${css}</style>`);
|
|
2163
|
+
if (previewStyles) headParts.push(previewStyles);
|
|
2164
|
+
if (headParts.length) previewSandboxRef.current.run(`document.head.innerHTML = ${JSON.stringify(headParts.join(""))}`);
|
|
2165
|
+
if (!previewBody) return;
|
|
2166
|
+
previewSandboxRef.current.run(`document.body.innerHTML = ${JSON.stringify(previewBody)}`);
|
|
2167
|
+
}, [
|
|
2168
|
+
previewBody,
|
|
2169
|
+
previewStyles,
|
|
2170
|
+
css
|
|
2171
|
+
]);
|
|
2172
|
+
(0, react.useEffect)(() => {
|
|
2173
|
+
const container = containerRef.current;
|
|
2174
|
+
if (!container || !fullHtml) return;
|
|
2175
|
+
if (previewSandboxRef.current) {
|
|
2176
|
+
previewSandboxRef.current.destroy();
|
|
2177
|
+
previewSandboxRef.current = null;
|
|
2178
|
+
previewReadyRef.current = false;
|
|
2179
|
+
}
|
|
2180
|
+
let cancelled = false;
|
|
2181
|
+
executedIndexRef.current = 0;
|
|
2182
|
+
jsFunctionsInjectedRef.current = false;
|
|
2183
|
+
sandboxReadyRef.current = false;
|
|
2184
|
+
pendingQueueRef.current = [];
|
|
2185
|
+
const htmlContent = css ? injectCssIntoHtml(fullHtml, css) : fullHtml;
|
|
2186
|
+
import("@jetbrains/websandbox").then((mod) => {
|
|
2187
|
+
if (cancelled) return;
|
|
2188
|
+
const sandbox = (mod.default?.default ?? mod.default).create(localApi, {
|
|
2189
|
+
frameContainer: container,
|
|
2190
|
+
frameContent: ensureHead(htmlContent),
|
|
2191
|
+
allowAdditionalAttributes: ""
|
|
2192
|
+
});
|
|
2193
|
+
sandboxRef.current = sandbox;
|
|
2194
|
+
sandbox.iframe.style.width = "100%";
|
|
2195
|
+
sandbox.iframe.style.height = "100%";
|
|
2196
|
+
sandbox.iframe.style.border = "none";
|
|
2197
|
+
sandbox.iframe.style.backgroundColor = "transparent";
|
|
2198
|
+
sandbox.promise.then(() => {
|
|
2199
|
+
if (cancelled) return;
|
|
2200
|
+
sandboxReadyRef.current = true;
|
|
2201
|
+
sandbox.run(`
|
|
2202
|
+
var s = document.createElement('style');
|
|
2203
|
+
s.textContent = 'html, body { overflow: hidden !important; }';
|
|
2204
|
+
document.head.appendChild(s);
|
|
2205
|
+
`);
|
|
2206
|
+
const queue = pendingQueueRef.current;
|
|
2207
|
+
pendingQueueRef.current = [];
|
|
2208
|
+
for (const code of queue) sandbox.run(code);
|
|
2209
|
+
});
|
|
2210
|
+
}).catch((err) => {
|
|
2211
|
+
console.error("[OpenGenerativeUI] Failed to load sandbox module:", err);
|
|
2212
|
+
});
|
|
2213
|
+
return () => {
|
|
2214
|
+
cancelled = true;
|
|
2215
|
+
if (previewSandboxRef.current) {
|
|
2216
|
+
previewSandboxRef.current.destroy();
|
|
2217
|
+
previewSandboxRef.current = null;
|
|
2218
|
+
previewReadyRef.current = false;
|
|
2219
|
+
}
|
|
2220
|
+
if (sandboxRef.current) {
|
|
2221
|
+
sandboxRef.current.destroy();
|
|
2222
|
+
sandboxRef.current = null;
|
|
2223
|
+
}
|
|
2224
|
+
sandboxReadyRef.current = false;
|
|
2225
|
+
setAutoHeight(null);
|
|
2226
|
+
};
|
|
2227
|
+
}, [
|
|
2228
|
+
fullHtml,
|
|
2229
|
+
css,
|
|
2230
|
+
localApi
|
|
2231
|
+
]);
|
|
2232
|
+
(0, react.useEffect)(() => {
|
|
2233
|
+
if (!content.jsFunctions || jsFunctionsInjectedRef.current) return;
|
|
2234
|
+
jsFunctionsInjectedRef.current = true;
|
|
2235
|
+
const sandbox = sandboxRef.current;
|
|
2236
|
+
if (sandboxReadyRef.current && sandbox) sandbox.run(content.jsFunctions);
|
|
2237
|
+
else pendingQueueRef.current.push(content.jsFunctions);
|
|
2238
|
+
}, [content.jsFunctions]);
|
|
2239
|
+
(0, react.useEffect)(() => {
|
|
2240
|
+
const expressions = content.jsExpressions;
|
|
2241
|
+
if (!expressions || expressions.length === 0) return;
|
|
2242
|
+
const startIndex = executedIndexRef.current;
|
|
2243
|
+
if (startIndex >= expressions.length) return;
|
|
2244
|
+
const newExprs = expressions.slice(startIndex);
|
|
2245
|
+
executedIndexRef.current = expressions.length;
|
|
2246
|
+
const sandbox = sandboxRef.current;
|
|
2247
|
+
if (sandboxReadyRef.current && sandbox) (async () => {
|
|
2248
|
+
for (const expr of newExprs) await sandbox.run(expr);
|
|
2249
|
+
})();
|
|
2250
|
+
else pendingQueueRef.current.push(...newExprs);
|
|
2251
|
+
}, [content.jsExpressions?.length]);
|
|
2252
|
+
const generationDone = content.generating === false;
|
|
2253
|
+
(0, react.useEffect)(() => {
|
|
2254
|
+
const sandbox = sandboxRef.current;
|
|
2255
|
+
if (!generationDone || !sandbox) return;
|
|
2256
|
+
let handled = false;
|
|
2257
|
+
const onMessage = (e) => {
|
|
2258
|
+
if (handled) return;
|
|
2259
|
+
if (e.source === sandbox.iframe.contentWindow && e.data?.type === "__ck_resize") {
|
|
2260
|
+
handled = true;
|
|
2261
|
+
setAutoHeight(e.data.height);
|
|
2262
|
+
window.removeEventListener("message", onMessage);
|
|
2263
|
+
}
|
|
2264
|
+
};
|
|
2265
|
+
window.addEventListener("message", onMessage);
|
|
2266
|
+
const measureOnce = `
|
|
2267
|
+
(function() {
|
|
2268
|
+
var s = document.createElement('style');
|
|
2269
|
+
s.textContent = 'body { height: auto !important; min-height: 0 !important; }';
|
|
2270
|
+
document.head.appendChild(s);
|
|
2271
|
+
var h = document.body.scrollHeight;
|
|
2272
|
+
var cs = getComputedStyle(document.body);
|
|
2273
|
+
h += parseFloat(cs.marginTop) || 0;
|
|
2274
|
+
h += parseFloat(cs.marginBottom) || 0;
|
|
2275
|
+
s.remove();
|
|
2276
|
+
parent.postMessage({ type: "__ck_resize", height: Math.ceil(h) }, "*");
|
|
2277
|
+
})();
|
|
2278
|
+
`;
|
|
2279
|
+
if (sandboxReadyRef.current) sandbox.run(measureOnce);
|
|
2280
|
+
else pendingQueueRef.current.push(measureOnce);
|
|
2281
|
+
return () => {
|
|
2282
|
+
window.removeEventListener("message", onMessage);
|
|
2283
|
+
};
|
|
2284
|
+
}, [generationDone]);
|
|
2285
|
+
const height = autoHeight ?? initialHeight;
|
|
2286
|
+
const isGenerating = content.generating !== false;
|
|
2287
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2288
|
+
ref: containerRef,
|
|
2289
|
+
style: {
|
|
2290
|
+
position: "relative",
|
|
2291
|
+
width: "100%",
|
|
2292
|
+
height: `${height}px`,
|
|
2293
|
+
borderRadius: "8px",
|
|
2294
|
+
backgroundColor: hasVisibleSandbox ? "transparent" : "#f5f5f5",
|
|
2295
|
+
border: hasVisibleSandbox ? "none" : "1px solid #e0e0e0",
|
|
2296
|
+
display: hasVisibleSandbox ? "block" : "flex",
|
|
2297
|
+
alignItems: hasVisibleSandbox ? void 0 : "center",
|
|
2298
|
+
justifyContent: hasVisibleSandbox ? void 0 : "center",
|
|
2299
|
+
overflow: "hidden"
|
|
2300
|
+
},
|
|
2301
|
+
children: isGenerating && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2302
|
+
style: {
|
|
2303
|
+
position: "absolute",
|
|
2304
|
+
inset: 0,
|
|
2305
|
+
zIndex: 10,
|
|
2306
|
+
pointerEvents: "all",
|
|
2307
|
+
backgroundColor: "rgba(255, 255, 255, 0.5)",
|
|
2308
|
+
display: "flex",
|
|
2309
|
+
alignItems: "center",
|
|
2310
|
+
justifyContent: "center"
|
|
2311
|
+
},
|
|
2312
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
|
|
2313
|
+
width: "48",
|
|
2314
|
+
height: "48",
|
|
2315
|
+
viewBox: "0 0 24 24",
|
|
2316
|
+
fill: "none",
|
|
2317
|
+
style: { animation: "ck-spin 1s linear infinite" },
|
|
2318
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
|
|
2319
|
+
cx: "12",
|
|
2320
|
+
cy: "12",
|
|
2321
|
+
r: "10",
|
|
2322
|
+
stroke: "#e0e0e0",
|
|
2323
|
+
strokeWidth: "3"
|
|
2324
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
|
|
2325
|
+
d: "M12 2a10 10 0 0 1 10 10",
|
|
2326
|
+
stroke: "#999",
|
|
2327
|
+
strokeWidth: "3",
|
|
2328
|
+
strokeLinecap: "round"
|
|
2329
|
+
})]
|
|
2330
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("style", { children: `@keyframes ck-spin { to { transform: rotate(360deg) } }` })]
|
|
2331
|
+
})
|
|
2332
|
+
});
|
|
2333
|
+
}, (prev, next) => prev.content === next.content);
|
|
2334
|
+
/**
|
|
2335
|
+
* Frontend tool renderer for generateSandboxedUi.
|
|
2336
|
+
* Displays placeholder messages while the UI is being generated.
|
|
2337
|
+
*/
|
|
2338
|
+
const OpenGenerativeUIToolRenderer = function OpenGenerativeUIToolRenderer(props) {
|
|
2339
|
+
const [visibleMessageIndex, setVisibleMessageIndex] = (0, react.useState)(0);
|
|
2340
|
+
const prevMessageCountRef = (0, react.useRef)(0);
|
|
2341
|
+
const messages = props.args.placeholderMessages;
|
|
2342
|
+
(0, react.useEffect)(() => {
|
|
2343
|
+
if (!messages || messages.length === 0) return;
|
|
2344
|
+
if (messages.length !== prevMessageCountRef.current) {
|
|
2345
|
+
prevMessageCountRef.current = messages.length;
|
|
2346
|
+
setVisibleMessageIndex(messages.length - 1);
|
|
2347
|
+
}
|
|
2348
|
+
if (props.status === _copilotkit_core.ToolCallStatus.Complete) return;
|
|
2349
|
+
const timer = setInterval(() => {
|
|
2350
|
+
setVisibleMessageIndex((i) => (i + 1) % messages.length);
|
|
2351
|
+
}, 5e3);
|
|
2352
|
+
return () => clearInterval(timer);
|
|
2353
|
+
}, [messages?.length, props.status]);
|
|
2354
|
+
if (props.status === _copilotkit_core.ToolCallStatus.Complete) return null;
|
|
2355
|
+
if (!messages || messages.length === 0) return null;
|
|
2356
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2357
|
+
style: {
|
|
2358
|
+
padding: "8px 12px",
|
|
2359
|
+
color: "#999",
|
|
2360
|
+
fontSize: "14px"
|
|
2361
|
+
},
|
|
2362
|
+
children: messages[visibleMessageIndex] ?? messages[0]
|
|
2363
|
+
});
|
|
2364
|
+
};
|
|
2365
|
+
|
|
1915
2366
|
//#endregion
|
|
1916
2367
|
//#region src/v2/a2ui/A2UIMessageRenderer.tsx
|
|
2368
|
+
/**
|
|
2369
|
+
* The container key used to wrap A2UI operations for explicit detection.
|
|
2370
|
+
* Must match A2UI_OPERATIONS_KEY in @ag-ui/a2ui-middleware and copilotkit.a2ui (Python).
|
|
2371
|
+
*/
|
|
2372
|
+
const A2UI_OPERATIONS_KEY = "a2ui_operations";
|
|
1917
2373
|
let initialized = false;
|
|
1918
2374
|
function ensureInitialized() {
|
|
1919
2375
|
if (!initialized) {
|
|
@@ -1923,25 +2379,23 @@ function ensureInitialized() {
|
|
|
1923
2379
|
}
|
|
1924
2380
|
}
|
|
1925
2381
|
function createA2UIMessageRenderer(options) {
|
|
1926
|
-
const { theme } = options;
|
|
2382
|
+
const { theme, catalog, loadingComponent } = options;
|
|
1927
2383
|
return {
|
|
1928
2384
|
activityType: "a2ui-surface",
|
|
1929
2385
|
content: zod.z.any(),
|
|
1930
2386
|
render: ({ content, agent }) => {
|
|
1931
2387
|
ensureInitialized();
|
|
1932
2388
|
const [operations, setOperations] = (0, react.useState)([]);
|
|
1933
|
-
const lastSignatureRef = (0, react.useRef)(null);
|
|
1934
2389
|
const { copilotkit } = useCopilotKit();
|
|
2390
|
+
const lastContentRef = (0, react.useRef)(null);
|
|
1935
2391
|
(0, react.useEffect)(() => {
|
|
1936
|
-
if (
|
|
1937
|
-
|
|
2392
|
+
if (content === lastContentRef.current) return;
|
|
2393
|
+
lastContentRef.current = content;
|
|
2394
|
+
const incoming = content?.[A2UI_OPERATIONS_KEY];
|
|
2395
|
+
if (!content || !Array.isArray(incoming)) {
|
|
1938
2396
|
setOperations([]);
|
|
1939
2397
|
return;
|
|
1940
2398
|
}
|
|
1941
|
-
const incoming = content.operations;
|
|
1942
|
-
const signature = stringifyOperations(incoming);
|
|
1943
|
-
if (signature && signature === lastSignatureRef.current) return;
|
|
1944
|
-
lastSignatureRef.current = signature;
|
|
1945
2399
|
setOperations(incoming);
|
|
1946
2400
|
}, [content]);
|
|
1947
2401
|
const groupedOperations = (0, react.useMemo)(() => {
|
|
@@ -1953,7 +2407,7 @@ function createA2UIMessageRenderer(options) {
|
|
|
1953
2407
|
}
|
|
1954
2408
|
return groups;
|
|
1955
2409
|
}, [operations]);
|
|
1956
|
-
if (!groupedOperations.size) return
|
|
2410
|
+
if (!groupedOperations.size) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(loadingComponent ?? DefaultA2UILoading, {});
|
|
1957
2411
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1958
2412
|
className: "cpk:flex cpk:min-h-0 cpk:flex-1 cpk:flex-col cpk:gap-6 cpk:overflow-auto cpk:py-6",
|
|
1959
2413
|
children: Array.from(groupedOperations.entries()).map(([surfaceId, ops]) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ReactSurfaceHost, {
|
|
@@ -1961,7 +2415,8 @@ function createA2UIMessageRenderer(options) {
|
|
|
1961
2415
|
operations: ops,
|
|
1962
2416
|
theme,
|
|
1963
2417
|
agent,
|
|
1964
|
-
copilotkit
|
|
2418
|
+
copilotkit,
|
|
2419
|
+
catalog
|
|
1965
2420
|
}, surfaceId))
|
|
1966
2421
|
});
|
|
1967
2422
|
}
|
|
@@ -1971,14 +2426,14 @@ function createA2UIMessageRenderer(options) {
|
|
|
1971
2426
|
* Renders a single A2UI surface using the React renderer.
|
|
1972
2427
|
* Wraps A2UIProvider + A2UIRenderer and bridges actions back to CopilotKit.
|
|
1973
2428
|
*/
|
|
1974
|
-
function ReactSurfaceHost({ surfaceId, operations, theme, agent, copilotkit }) {
|
|
2429
|
+
function ReactSurfaceHost({ surfaceId, operations, theme, agent, copilotkit, catalog }) {
|
|
1975
2430
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1976
2431
|
className: "cpk:flex cpk:w-full cpk:flex-none cpk:flex-col cpk:gap-4",
|
|
1977
2432
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_copilotkit_a2ui_renderer.A2UIProvider, {
|
|
1978
2433
|
onAction: (0, react.useCallback)(async (message) => {
|
|
1979
2434
|
if (!agent) return;
|
|
2435
|
+
message.userAction;
|
|
1980
2436
|
try {
|
|
1981
|
-
console.info("[A2UI] Action dispatched", message.userAction);
|
|
1982
2437
|
copilotkit.setProperties({
|
|
1983
2438
|
...copilotkit.properties ?? {},
|
|
1984
2439
|
a2uiAction: message
|
|
@@ -1992,46 +2447,500 @@ function ReactSurfaceHost({ surfaceId, operations, theme, agent, copilotkit }) {
|
|
|
1992
2447
|
}
|
|
1993
2448
|
}, [agent, copilotkit]),
|
|
1994
2449
|
theme,
|
|
2450
|
+
catalog,
|
|
1995
2451
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(SurfaceMessageProcessor, {
|
|
1996
2452
|
surfaceId,
|
|
1997
2453
|
operations
|
|
1998
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
1999
|
-
surfaceId,
|
|
2000
|
-
className: "cpk:flex cpk:flex-1"
|
|
2001
|
-
})]
|
|
2454
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(A2UISurfaceOrError, { surfaceId })]
|
|
2002
2455
|
})
|
|
2003
2456
|
});
|
|
2004
2457
|
}
|
|
2005
2458
|
/**
|
|
2459
|
+
* Renders the A2UI surface, or an error message if processing failed.
|
|
2460
|
+
* Must be a child of A2UIProvider to access the error state.
|
|
2461
|
+
*/
|
|
2462
|
+
function A2UISurfaceOrError({ surfaceId }) {
|
|
2463
|
+
const error = (0, _copilotkit_a2ui_renderer.useA2UIError)();
|
|
2464
|
+
if (error) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2465
|
+
className: "cpk:rounded-lg cpk:border cpk:border-red-200 cpk:bg-red-50 cpk:p-3 cpk:text-sm cpk:text-red-700",
|
|
2466
|
+
children: ["A2UI render error: ", error]
|
|
2467
|
+
});
|
|
2468
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_copilotkit_a2ui_renderer.A2UIRenderer, {
|
|
2469
|
+
surfaceId,
|
|
2470
|
+
className: "cpk:flex cpk:flex-1"
|
|
2471
|
+
});
|
|
2472
|
+
}
|
|
2473
|
+
/**
|
|
2006
2474
|
* Processes A2UI operations into the provider's message processor.
|
|
2007
2475
|
* Must be a child of A2UIProvider to access the actions context.
|
|
2008
2476
|
*/
|
|
2009
2477
|
function SurfaceMessageProcessor({ surfaceId, operations }) {
|
|
2010
|
-
const { processMessages } = (0, _copilotkit_a2ui_renderer.useA2UIActions)();
|
|
2011
|
-
const
|
|
2478
|
+
const { processMessages, getSurface } = (0, _copilotkit_a2ui_renderer.useA2UIActions)();
|
|
2479
|
+
const lastHashRef = (0, react.useRef)("");
|
|
2012
2480
|
(0, react.useEffect)(() => {
|
|
2013
|
-
const
|
|
2014
|
-
if (
|
|
2015
|
-
|
|
2016
|
-
processMessages(operations);
|
|
2481
|
+
const hash = JSON.stringify(operations);
|
|
2482
|
+
if (hash === lastHashRef.current) return;
|
|
2483
|
+
lastHashRef.current = hash;
|
|
2484
|
+
processMessages(getSurface(surfaceId) ? operations.filter((op) => !op?.createSurface) : operations);
|
|
2017
2485
|
}, [
|
|
2018
2486
|
processMessages,
|
|
2487
|
+
getSurface,
|
|
2019
2488
|
surfaceId,
|
|
2020
2489
|
operations
|
|
2021
2490
|
]);
|
|
2022
2491
|
return null;
|
|
2023
2492
|
}
|
|
2493
|
+
/**
|
|
2494
|
+
* Default loading component shown while an A2UI surface is generating.
|
|
2495
|
+
* Displays an animated shimmer skeleton.
|
|
2496
|
+
*/
|
|
2497
|
+
function DefaultA2UILoading() {
|
|
2498
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2499
|
+
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",
|
|
2500
|
+
style: { minHeight: 120 },
|
|
2501
|
+
children: [
|
|
2502
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2503
|
+
className: "cpk:flex cpk:items-center cpk:gap-2",
|
|
2504
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2505
|
+
className: "cpk:h-3 cpk:w-3 cpk:rounded-full cpk:bg-gray-200",
|
|
2506
|
+
style: { animation: "cpk-a2ui-pulse 1.5s ease-in-out infinite" }
|
|
2507
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2508
|
+
className: "cpk:text-xs cpk:font-medium cpk:text-gray-400",
|
|
2509
|
+
children: "Generating UI..."
|
|
2510
|
+
})]
|
|
2511
|
+
}),
|
|
2512
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2513
|
+
className: "cpk:flex cpk:flex-col cpk:gap-2",
|
|
2514
|
+
children: [
|
|
2515
|
+
.8,
|
|
2516
|
+
.6,
|
|
2517
|
+
.4
|
|
2518
|
+
].map((width, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2519
|
+
className: "cpk:h-3 cpk:rounded cpk:bg-gray-200/70",
|
|
2520
|
+
style: {
|
|
2521
|
+
width: `${width * 100}%`,
|
|
2522
|
+
animation: `cpk-a2ui-pulse 1.5s ease-in-out ${i * .15}s infinite`
|
|
2523
|
+
}
|
|
2524
|
+
}, i))
|
|
2525
|
+
}),
|
|
2526
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("style", { children: `
|
|
2527
|
+
@keyframes cpk-a2ui-pulse {
|
|
2528
|
+
0%, 100% { opacity: 0.4; }
|
|
2529
|
+
50% { opacity: 1; }
|
|
2530
|
+
}
|
|
2531
|
+
` })
|
|
2532
|
+
]
|
|
2533
|
+
});
|
|
2534
|
+
}
|
|
2024
2535
|
function getOperationSurfaceId(operation) {
|
|
2025
2536
|
if (!operation || typeof operation !== "object") return null;
|
|
2026
2537
|
if (typeof operation.surfaceId === "string") return operation.surfaceId;
|
|
2027
|
-
return operation?.
|
|
2538
|
+
return operation?.createSurface?.surfaceId ?? operation?.updateComponents?.surfaceId ?? operation?.updateDataModel?.surfaceId ?? operation?.deleteSurface?.surfaceId ?? null;
|
|
2028
2539
|
}
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2540
|
+
|
|
2541
|
+
//#endregion
|
|
2542
|
+
//#region src/v2/types/defineToolCallRenderer.ts
|
|
2543
|
+
function defineToolCallRenderer(def) {
|
|
2544
|
+
const argsSchema = def.name === "*" && !def.args ? zod.z.any() : def.args;
|
|
2545
|
+
return {
|
|
2546
|
+
name: def.name,
|
|
2547
|
+
args: argsSchema,
|
|
2548
|
+
render: def.render,
|
|
2549
|
+
...def.agentId ? { agentId: def.agentId } : {}
|
|
2550
|
+
};
|
|
2551
|
+
}
|
|
2552
|
+
|
|
2553
|
+
//#endregion
|
|
2554
|
+
//#region src/v2/a2ui/A2UIToolCallRenderer.tsx
|
|
2555
|
+
/**
|
|
2556
|
+
* Tool name used by the dynamic A2UI generation secondary LLM.
|
|
2557
|
+
* This renderer is auto-registered when A2UI is enabled.
|
|
2558
|
+
*/
|
|
2559
|
+
const RENDER_A2UI_TOOL_NAME = "render_a2ui";
|
|
2560
|
+
/**
|
|
2561
|
+
* Built-in progress indicator for dynamic A2UI generation.
|
|
2562
|
+
* Shows a skeleton wireframe that progressively reveals as tokens stream in.
|
|
2563
|
+
*
|
|
2564
|
+
* Registered automatically when A2UI is enabled. Users can override by
|
|
2565
|
+
* providing their own `useRenderTool({ name: "render_a2ui", ... })`.
|
|
2566
|
+
*/
|
|
2567
|
+
function A2UIProgressIndicator({ parameters }) {
|
|
2568
|
+
const lastRef = (0, react.useRef)({
|
|
2569
|
+
time: 0,
|
|
2570
|
+
tokens: 0
|
|
2571
|
+
});
|
|
2572
|
+
const now = Date.now();
|
|
2573
|
+
let { tokens } = lastRef.current;
|
|
2574
|
+
if (now - lastRef.current.time > 200) {
|
|
2575
|
+
const chars = JSON.stringify(parameters ?? {}).length;
|
|
2576
|
+
tokens = Math.round(chars / 4);
|
|
2577
|
+
lastRef.current = {
|
|
2578
|
+
time: now,
|
|
2579
|
+
tokens
|
|
2580
|
+
};
|
|
2034
2581
|
}
|
|
2582
|
+
const phase = tokens < 50 ? 0 : tokens < 200 ? 1 : tokens < 400 ? 2 : 3;
|
|
2583
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2584
|
+
style: {
|
|
2585
|
+
margin: "12px 0",
|
|
2586
|
+
maxWidth: 320
|
|
2587
|
+
},
|
|
2588
|
+
children: [
|
|
2589
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2590
|
+
style: {
|
|
2591
|
+
position: "relative",
|
|
2592
|
+
overflow: "hidden",
|
|
2593
|
+
borderRadius: 12,
|
|
2594
|
+
border: "1px solid rgba(228,228,231,0.8)",
|
|
2595
|
+
backgroundColor: "#fff",
|
|
2596
|
+
boxShadow: "0 1px 2px rgba(0,0,0,0.04)",
|
|
2597
|
+
padding: "16px 18px 14px"
|
|
2598
|
+
},
|
|
2599
|
+
children: [
|
|
2600
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2601
|
+
style: {
|
|
2602
|
+
display: "flex",
|
|
2603
|
+
alignItems: "center",
|
|
2604
|
+
gap: 8,
|
|
2605
|
+
marginBottom: 12
|
|
2606
|
+
},
|
|
2607
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2608
|
+
style: {
|
|
2609
|
+
display: "flex",
|
|
2610
|
+
gap: 4
|
|
2611
|
+
},
|
|
2612
|
+
children: [
|
|
2613
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Dot, {}),
|
|
2614
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Dot, {}),
|
|
2615
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Dot, {})
|
|
2616
|
+
]
|
|
2617
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Bar, {
|
|
2618
|
+
w: 64,
|
|
2619
|
+
h: 6,
|
|
2620
|
+
bg: "#e4e4e7",
|
|
2621
|
+
opacity: phase >= 1 ? 1 : .4,
|
|
2622
|
+
transition: "opacity 0.5s"
|
|
2623
|
+
})]
|
|
2624
|
+
}),
|
|
2625
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2626
|
+
style: {
|
|
2627
|
+
display: "grid",
|
|
2628
|
+
gap: 7
|
|
2629
|
+
},
|
|
2630
|
+
children: [
|
|
2631
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Row, {
|
|
2632
|
+
show: phase >= 0,
|
|
2633
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Bar, {
|
|
2634
|
+
w: 36,
|
|
2635
|
+
h: 7,
|
|
2636
|
+
bg: "rgba(147,197,253,0.7)",
|
|
2637
|
+
anim: 0
|
|
2638
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Bar, {
|
|
2639
|
+
w: 80,
|
|
2640
|
+
h: 7,
|
|
2641
|
+
bg: "rgba(219,234,254,0.8)",
|
|
2642
|
+
anim: .2
|
|
2643
|
+
})]
|
|
2644
|
+
}),
|
|
2645
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Row, {
|
|
2646
|
+
show: phase >= 0,
|
|
2647
|
+
delay: .1,
|
|
2648
|
+
children: [
|
|
2649
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Spacer, {}),
|
|
2650
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Dot, {}),
|
|
2651
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Bar, {
|
|
2652
|
+
w: 100,
|
|
2653
|
+
h: 7,
|
|
2654
|
+
bg: "rgba(24,24,27,0.2)",
|
|
2655
|
+
anim: .3
|
|
2656
|
+
})
|
|
2657
|
+
]
|
|
2658
|
+
}),
|
|
2659
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Row, {
|
|
2660
|
+
show: phase >= 1,
|
|
2661
|
+
delay: .15,
|
|
2662
|
+
children: [
|
|
2663
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Spacer, {}),
|
|
2664
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Bar, {
|
|
2665
|
+
w: 48,
|
|
2666
|
+
h: 7,
|
|
2667
|
+
bg: "rgba(24,24,27,0.15)",
|
|
2668
|
+
anim: .1
|
|
2669
|
+
}),
|
|
2670
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Bar, {
|
|
2671
|
+
w: 40,
|
|
2672
|
+
h: 7,
|
|
2673
|
+
bg: "rgba(153,246,228,0.6)",
|
|
2674
|
+
anim: .5
|
|
2675
|
+
}),
|
|
2676
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Bar, {
|
|
2677
|
+
w: 56,
|
|
2678
|
+
h: 7,
|
|
2679
|
+
bg: "rgba(147,197,253,0.6)",
|
|
2680
|
+
anim: .3
|
|
2681
|
+
})
|
|
2682
|
+
]
|
|
2683
|
+
}),
|
|
2684
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Row, {
|
|
2685
|
+
show: phase >= 1,
|
|
2686
|
+
delay: .2,
|
|
2687
|
+
children: [
|
|
2688
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Spacer, {}),
|
|
2689
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Dot, {}),
|
|
2690
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Bar, {
|
|
2691
|
+
w: 60,
|
|
2692
|
+
h: 7,
|
|
2693
|
+
bg: "rgba(24,24,27,0.15)",
|
|
2694
|
+
anim: .4
|
|
2695
|
+
})
|
|
2696
|
+
]
|
|
2697
|
+
}),
|
|
2698
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Row, {
|
|
2699
|
+
show: phase >= 2,
|
|
2700
|
+
delay: .25,
|
|
2701
|
+
children: [
|
|
2702
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Bar, {
|
|
2703
|
+
w: 40,
|
|
2704
|
+
h: 7,
|
|
2705
|
+
bg: "rgba(153,246,228,0.5)",
|
|
2706
|
+
anim: .2
|
|
2707
|
+
}),
|
|
2708
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Dot, {}),
|
|
2709
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Bar, {
|
|
2710
|
+
w: 48,
|
|
2711
|
+
h: 7,
|
|
2712
|
+
bg: "rgba(24,24,27,0.15)",
|
|
2713
|
+
anim: .6
|
|
2714
|
+
}),
|
|
2715
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Bar, {
|
|
2716
|
+
w: 64,
|
|
2717
|
+
h: 7,
|
|
2718
|
+
bg: "rgba(147,197,253,0.5)",
|
|
2719
|
+
anim: .1
|
|
2720
|
+
})
|
|
2721
|
+
]
|
|
2722
|
+
}),
|
|
2723
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Row, {
|
|
2724
|
+
show: phase >= 2,
|
|
2725
|
+
delay: .3,
|
|
2726
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Bar, {
|
|
2727
|
+
w: 36,
|
|
2728
|
+
h: 7,
|
|
2729
|
+
bg: "rgba(147,197,253,0.6)",
|
|
2730
|
+
anim: .5
|
|
2731
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Bar, {
|
|
2732
|
+
w: 36,
|
|
2733
|
+
h: 7,
|
|
2734
|
+
bg: "rgba(24,24,27,0.12)",
|
|
2735
|
+
anim: .7
|
|
2736
|
+
})]
|
|
2737
|
+
}),
|
|
2738
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Row, {
|
|
2739
|
+
show: phase >= 3,
|
|
2740
|
+
delay: .35,
|
|
2741
|
+
children: [
|
|
2742
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Dot, {}),
|
|
2743
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Bar, {
|
|
2744
|
+
w: 44,
|
|
2745
|
+
h: 7,
|
|
2746
|
+
bg: "rgba(24,24,27,0.18)",
|
|
2747
|
+
anim: .3
|
|
2748
|
+
}),
|
|
2749
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Dot, {}),
|
|
2750
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Bar, {
|
|
2751
|
+
w: 56,
|
|
2752
|
+
h: 7,
|
|
2753
|
+
bg: "rgba(153,246,228,0.5)",
|
|
2754
|
+
anim: .8
|
|
2755
|
+
}),
|
|
2756
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Bar, {
|
|
2757
|
+
w: 48,
|
|
2758
|
+
h: 7,
|
|
2759
|
+
bg: "rgba(147,197,253,0.5)",
|
|
2760
|
+
anim: .4
|
|
2761
|
+
})
|
|
2762
|
+
]
|
|
2763
|
+
})
|
|
2764
|
+
]
|
|
2765
|
+
}),
|
|
2766
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { style: {
|
|
2767
|
+
pointerEvents: "none",
|
|
2768
|
+
position: "absolute",
|
|
2769
|
+
inset: 0,
|
|
2770
|
+
background: "linear-gradient(105deg, transparent 0%, transparent 40%, rgba(255,255,255,0.6) 50%, transparent 60%, transparent 100%)",
|
|
2771
|
+
backgroundSize: "250% 100%",
|
|
2772
|
+
animation: "cpk-a2ui-sweep 3s ease-in-out infinite"
|
|
2773
|
+
} })
|
|
2774
|
+
]
|
|
2775
|
+
}),
|
|
2776
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2777
|
+
style: {
|
|
2778
|
+
display: "flex",
|
|
2779
|
+
alignItems: "center",
|
|
2780
|
+
justifyContent: "center",
|
|
2781
|
+
gap: 8,
|
|
2782
|
+
marginTop: 8
|
|
2783
|
+
},
|
|
2784
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2785
|
+
style: {
|
|
2786
|
+
fontSize: 12,
|
|
2787
|
+
color: "#a1a1aa",
|
|
2788
|
+
letterSpacing: "0.025em"
|
|
2789
|
+
},
|
|
2790
|
+
children: "Building interface"
|
|
2791
|
+
}), tokens > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
2792
|
+
style: {
|
|
2793
|
+
fontSize: 11,
|
|
2794
|
+
color: "#d4d4d8",
|
|
2795
|
+
fontVariantNumeric: "tabular-nums"
|
|
2796
|
+
},
|
|
2797
|
+
children: [
|
|
2798
|
+
"~",
|
|
2799
|
+
tokens.toLocaleString(),
|
|
2800
|
+
" tokens"
|
|
2801
|
+
]
|
|
2802
|
+
})]
|
|
2803
|
+
}),
|
|
2804
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("style", { children: `
|
|
2805
|
+
@keyframes cpk-a2ui-fade {
|
|
2806
|
+
0%, 100% { opacity: 1; }
|
|
2807
|
+
50% { opacity: 0.5; }
|
|
2808
|
+
}
|
|
2809
|
+
@keyframes cpk-a2ui-sweep {
|
|
2810
|
+
0% { background-position: 250% 0; }
|
|
2811
|
+
100% { background-position: -250% 0; }
|
|
2812
|
+
}
|
|
2813
|
+
` })
|
|
2814
|
+
]
|
|
2815
|
+
});
|
|
2816
|
+
}
|
|
2817
|
+
function Dot() {
|
|
2818
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { style: {
|
|
2819
|
+
width: 7,
|
|
2820
|
+
height: 7,
|
|
2821
|
+
borderRadius: "50%",
|
|
2822
|
+
backgroundColor: "#d4d4d8",
|
|
2823
|
+
flexShrink: 0
|
|
2824
|
+
} });
|
|
2825
|
+
}
|
|
2826
|
+
function Spacer() {
|
|
2827
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { style: { width: 12 } });
|
|
2828
|
+
}
|
|
2829
|
+
function Bar({ w, h, bg, anim, opacity, transition }) {
|
|
2830
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { style: {
|
|
2831
|
+
width: w,
|
|
2832
|
+
height: h,
|
|
2833
|
+
borderRadius: 9999,
|
|
2834
|
+
backgroundColor: bg,
|
|
2835
|
+
...anim !== void 0 ? { animation: `cpk-a2ui-fade 2.4s ease-in-out ${anim}s infinite` } : {},
|
|
2836
|
+
...opacity !== void 0 ? { opacity } : {},
|
|
2837
|
+
...transition ? { transition } : {}
|
|
2838
|
+
} });
|
|
2839
|
+
}
|
|
2840
|
+
function Row({ children, show, delay = 0 }) {
|
|
2841
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2842
|
+
style: {
|
|
2843
|
+
display: "flex",
|
|
2844
|
+
alignItems: "center",
|
|
2845
|
+
gap: 6,
|
|
2846
|
+
opacity: show ? 1 : 0,
|
|
2847
|
+
transition: `opacity 0.4s ${delay}s`
|
|
2848
|
+
},
|
|
2849
|
+
children
|
|
2850
|
+
});
|
|
2851
|
+
}
|
|
2852
|
+
/**
|
|
2853
|
+
* Registers the built-in `render_a2ui` tool call renderer via the props-based
|
|
2854
|
+
* `setRenderToolCalls` mechanism (not `useRenderTool`).
|
|
2855
|
+
*
|
|
2856
|
+
* This ensures user-registered `useRenderTool({ name: "render_a2ui", ... })`
|
|
2857
|
+
* hooks automatically override the built-in, since the merge logic in
|
|
2858
|
+
* react-core.ts gives hook-based entries priority over prop-based entries.
|
|
2859
|
+
*/
|
|
2860
|
+
function A2UIBuiltInToolCallRenderer() {
|
|
2861
|
+
const { copilotkit } = useCopilotKit();
|
|
2862
|
+
(0, react.useEffect)(() => {
|
|
2863
|
+
const renderer = defineToolCallRenderer({
|
|
2864
|
+
name: RENDER_A2UI_TOOL_NAME,
|
|
2865
|
+
args: zod.z.any(),
|
|
2866
|
+
render: ({ status, args: parameters }) => {
|
|
2867
|
+
if (status === "complete") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, {});
|
|
2868
|
+
const params = parameters;
|
|
2869
|
+
const items = params?.items;
|
|
2870
|
+
if (Array.isArray(items) && items.length > 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, {});
|
|
2871
|
+
const components = params?.components;
|
|
2872
|
+
if (Array.isArray(components) && components.length > 2) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, {});
|
|
2873
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(A2UIProgressIndicator, { parameters });
|
|
2874
|
+
}
|
|
2875
|
+
});
|
|
2876
|
+
const existing = copilotkit._renderToolCalls ?? [];
|
|
2877
|
+
copilotkit.setRenderToolCalls([...existing.filter((rc) => rc.name !== RENDER_A2UI_TOOL_NAME), renderer]);
|
|
2878
|
+
}, [copilotkit]);
|
|
2879
|
+
return null;
|
|
2880
|
+
}
|
|
2881
|
+
|
|
2882
|
+
//#endregion
|
|
2883
|
+
//#region src/v2/hooks/use-agent-context.tsx
|
|
2884
|
+
function useAgentContext(context) {
|
|
2885
|
+
const { description, value } = context;
|
|
2886
|
+
const { copilotkit } = useCopilotKit();
|
|
2887
|
+
const stringValue = (0, react.useMemo)(() => {
|
|
2888
|
+
if (typeof value === "string") return value;
|
|
2889
|
+
return JSON.stringify(value);
|
|
2890
|
+
}, [value]);
|
|
2891
|
+
(0, react.useLayoutEffect)(() => {
|
|
2892
|
+
if (!copilotkit) return;
|
|
2893
|
+
const id = copilotkit.addContext({
|
|
2894
|
+
description,
|
|
2895
|
+
value: stringValue
|
|
2896
|
+
});
|
|
2897
|
+
return () => {
|
|
2898
|
+
copilotkit.removeContext(id);
|
|
2899
|
+
};
|
|
2900
|
+
}, [
|
|
2901
|
+
description,
|
|
2902
|
+
stringValue,
|
|
2903
|
+
copilotkit
|
|
2904
|
+
]);
|
|
2905
|
+
}
|
|
2906
|
+
|
|
2907
|
+
//#endregion
|
|
2908
|
+
//#region src/v2/a2ui/A2UICatalogContext.tsx
|
|
2909
|
+
/**
|
|
2910
|
+
* Renders agent context describing the available A2UI catalog and custom components.
|
|
2911
|
+
* Only mount this component when A2UI is enabled.
|
|
2912
|
+
*
|
|
2913
|
+
* When `includeSchema` is true, the full component schemas (JSON Schema) are also
|
|
2914
|
+
* sent as context using the same description key as the A2UI middleware, so the
|
|
2915
|
+
* middleware can optionally overwrite it with a server-side schema.
|
|
2916
|
+
*/
|
|
2917
|
+
function A2UICatalogContext({ catalog, includeSchema }) {
|
|
2918
|
+
useAgentContext({
|
|
2919
|
+
description: "A2UI catalog capabilities: available catalog IDs and custom component definitions the client can render.",
|
|
2920
|
+
value: (0, _copilotkit_a2ui_renderer.buildCatalogContextValue)(catalog)
|
|
2921
|
+
});
|
|
2922
|
+
const { copilotkit } = useCopilotKit();
|
|
2923
|
+
const schemaValue = (0, react.useMemo)(() => includeSchema !== false ? JSON.stringify((0, _copilotkit_a2ui_renderer.extractCatalogComponentSchemas)(catalog)) : null, [catalog, includeSchema]);
|
|
2924
|
+
(0, react.useLayoutEffect)(() => {
|
|
2925
|
+
if (!copilotkit || !schemaValue) return;
|
|
2926
|
+
const ids = [];
|
|
2927
|
+
ids.push(copilotkit.addContext({
|
|
2928
|
+
description: _copilotkit_a2ui_renderer.A2UI_SCHEMA_CONTEXT_DESCRIPTION,
|
|
2929
|
+
value: schemaValue
|
|
2930
|
+
}));
|
|
2931
|
+
ids.push(copilotkit.addContext({
|
|
2932
|
+
description: "A2UI generation guidelines — protocol rules, tool arguments, path rules, data model format, and form/two-way-binding instructions.",
|
|
2933
|
+
value: _copilotkit_shared.A2UI_DEFAULT_GENERATION_GUIDELINES
|
|
2934
|
+
}));
|
|
2935
|
+
ids.push(copilotkit.addContext({
|
|
2936
|
+
description: "A2UI design guidelines — visual design rules, component hierarchy tips, and action handler patterns.",
|
|
2937
|
+
value: _copilotkit_shared.A2UI_DEFAULT_DESIGN_GUIDELINES
|
|
2938
|
+
}));
|
|
2939
|
+
return () => {
|
|
2940
|
+
for (const id of ids) copilotkit.removeContext(id);
|
|
2941
|
+
};
|
|
2942
|
+
}, [copilotkit, schemaValue]);
|
|
2943
|
+
return null;
|
|
2035
2944
|
}
|
|
2036
2945
|
|
|
2037
2946
|
//#endregion
|
|
@@ -2134,6 +3043,17 @@ var CopilotKitCoreReact = class extends _copilotkit_core.CopilotKitCore {
|
|
|
2134
3043
|
//#region src/v2/providers/CopilotKitProvider.tsx
|
|
2135
3044
|
const HEADER_NAME = "X-CopilotCloud-Public-Api-Key";
|
|
2136
3045
|
const COPILOT_CLOUD_CHAT_URL$1 = "https://api.cloud.copilotkit.ai/copilotkit/v1";
|
|
3046
|
+
const DEFAULT_DESIGN_SKILL = `When generating UI with generateSandboxedUi, follow these design principles inspired by shadcn/ui:
|
|
3047
|
+
|
|
3048
|
+
- Use a minimal, flat aesthetic. Avoid drop shadows and gradients — rely on subtle borders (1px solid, light gray like #e5e7eb) to define surfaces.
|
|
3049
|
+
- Neutral base palette: white backgrounds, zinc/slate gray text (#09090b for headings, #71717a for secondary text). One accent color for interactive elements.
|
|
3050
|
+
- Use system font stacks (system-ui, -apple-system, sans-serif) at readable sizes (14px body, 600 weight for headings). Tight line-heights.
|
|
3051
|
+
- Small, consistent border-radius (6–8px). Cards and containers use border, not shadow, for separation.
|
|
3052
|
+
- Buttons: solid fill for primary (dark bg, white text), outline for secondary (border + transparent bg). Subtle hover state (slight opacity or background shift).
|
|
3053
|
+
- Use CSS Grid or Flexbox for layout. Ensure the UI looks good at any width.
|
|
3054
|
+
- Minimal transitions (150ms) for hover/focus states only. No decorative animations.
|
|
3055
|
+
- Keep the UI focused and dense — avoid excessive padding. Use compact spacing (8–12px gaps, 10–14px padding in controls).`;
|
|
3056
|
+
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)";
|
|
2137
3057
|
const CopilotKitContext = (0, react.createContext)({
|
|
2138
3058
|
copilotkit: null,
|
|
2139
3059
|
executingToolCallIds: /* @__PURE__ */ new Set()
|
|
@@ -2149,9 +3069,11 @@ function useStableArrayProp(prop, warningMessage, isMeaningfulChange) {
|
|
|
2149
3069
|
}, [value, warningMessage]);
|
|
2150
3070
|
return value;
|
|
2151
3071
|
}
|
|
2152
|
-
const CopilotKitProvider = ({ children, runtimeUrl, headers = {}, credentials, publicApiKey, publicLicenseKey, licenseToken, properties = {}, agents__unsafe_dev_only: agents = {}, selfManagedAgents = {}, renderToolCalls, renderActivityMessages, renderCustomMessages, frontendTools, humanInTheLoop, showDevConsole = false, useSingleEndpoint
|
|
3072
|
+
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 }) => {
|
|
2153
3073
|
const [shouldRenderInspector, setShouldRenderInspector] = (0, react.useState)(false);
|
|
2154
3074
|
const [runtimeA2UIEnabled, setRuntimeA2UIEnabled] = (0, react.useState)(false);
|
|
3075
|
+
const [runtimeOpenGenUIEnabled, setRuntimeOpenGenUIEnabled] = (0, react.useState)(false);
|
|
3076
|
+
const openGenUIActive = runtimeOpenGenUIEnabled || !!openGenerativeUI;
|
|
2155
3077
|
const [runtimeLicenseStatus, setRuntimeLicenseStatus] = (0, react.useState)(void 0);
|
|
2156
3078
|
(0, react.useEffect)(() => {
|
|
2157
3079
|
if (typeof window === "undefined") return;
|
|
@@ -2177,9 +3099,22 @@ const CopilotKitProvider = ({ children, runtimeUrl, headers = {}, credentials, p
|
|
|
2177
3099
|
content: MCPAppsActivityContentSchema,
|
|
2178
3100
|
render: MCPAppsActivityRenderer
|
|
2179
3101
|
}];
|
|
2180
|
-
if (
|
|
3102
|
+
if (openGenUIActive) renderers.push({
|
|
3103
|
+
activityType: OpenGenerativeUIActivityType,
|
|
3104
|
+
content: OpenGenerativeUIContentSchema,
|
|
3105
|
+
render: OpenGenerativeUIActivityRenderer
|
|
3106
|
+
});
|
|
3107
|
+
if (runtimeA2UIEnabled) renderers.unshift(createA2UIMessageRenderer({
|
|
3108
|
+
theme: a2ui?.theme ?? _copilotkit_a2ui_renderer.viewerTheme,
|
|
3109
|
+
catalog: a2ui?.catalog,
|
|
3110
|
+
loadingComponent: a2ui?.loadingComponent
|
|
3111
|
+
}));
|
|
2181
3112
|
return renderers;
|
|
2182
|
-
}, [
|
|
3113
|
+
}, [
|
|
3114
|
+
runtimeA2UIEnabled,
|
|
3115
|
+
openGenUIActive,
|
|
3116
|
+
a2ui
|
|
3117
|
+
]);
|
|
2183
3118
|
const allActivityRenderers = (0, react.useMemo)(() => {
|
|
2184
3119
|
return [...renderActivityMessagesList, ...builtInActivityRenderers];
|
|
2185
3120
|
}, [renderActivityMessagesList, builtInActivityRenderers]);
|
|
@@ -2205,6 +3140,7 @@ const CopilotKitProvider = ({ children, runtimeUrl, headers = {}, credentials, p
|
|
|
2205
3140
|
const chatApiEndpoint = runtimeUrl ?? (resolvedPublicKey ? COPILOT_CLOUD_CHAT_URL$1 : void 0);
|
|
2206
3141
|
const frontendToolsList = useStableArrayProp(frontendTools, "frontendTools must be a stable array. If you want to dynamically add or remove tools, use `useFrontendTool` instead.");
|
|
2207
3142
|
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.");
|
|
3143
|
+
const sandboxFunctionsList = useStableArrayProp(openGenerativeUI?.sandboxFunctions, "openGenerativeUI.sandboxFunctions must be a stable array.");
|
|
2208
3144
|
const processedHumanInTheLoopTools = (0, react.useMemo)(() => {
|
|
2209
3145
|
const processedTools = [];
|
|
2210
3146
|
const processedRenderToolCalls = [];
|
|
@@ -2235,15 +3171,31 @@ const CopilotKitProvider = ({ children, runtimeUrl, headers = {}, credentials, p
|
|
|
2235
3171
|
renderToolCalls: processedRenderToolCalls
|
|
2236
3172
|
};
|
|
2237
3173
|
}, [humanInTheLoopList]);
|
|
3174
|
+
const builtInFrontendTools = (0, react.useMemo)(() => {
|
|
3175
|
+
if (!openGenUIActive) return [];
|
|
3176
|
+
return [{
|
|
3177
|
+
name: "generateSandboxedUi",
|
|
3178
|
+
description: GENERATE_SANDBOXED_UI_DESCRIPTION,
|
|
3179
|
+
parameters: GenerateSandboxedUiArgsSchema,
|
|
3180
|
+
handler: async () => "UI generated",
|
|
3181
|
+
followUp: true,
|
|
3182
|
+
render: OpenGenerativeUIToolRenderer
|
|
3183
|
+
}];
|
|
3184
|
+
}, [openGenUIActive]);
|
|
2238
3185
|
const allTools = (0, react.useMemo)(() => {
|
|
2239
3186
|
const tools = [];
|
|
2240
3187
|
tools.push(...frontendToolsList);
|
|
3188
|
+
tools.push(...builtInFrontendTools);
|
|
2241
3189
|
tools.push(...processedHumanInTheLoopTools.tools);
|
|
2242
3190
|
return tools;
|
|
2243
|
-
}, [
|
|
3191
|
+
}, [
|
|
3192
|
+
frontendToolsList,
|
|
3193
|
+
builtInFrontendTools,
|
|
3194
|
+
processedHumanInTheLoopTools
|
|
3195
|
+
]);
|
|
2244
3196
|
const allRenderToolCalls = (0, react.useMemo)(() => {
|
|
2245
3197
|
const combined = [...renderToolCallsList];
|
|
2246
|
-
frontendToolsList.forEach((tool) => {
|
|
3198
|
+
[...frontendToolsList, ...builtInFrontendTools].forEach((tool) => {
|
|
2247
3199
|
if (tool.render) {
|
|
2248
3200
|
const args = tool.parameters || (tool.name === "*" ? zod.z.any() : void 0);
|
|
2249
3201
|
if (args) combined.push({
|
|
@@ -2258,25 +3210,31 @@ const CopilotKitProvider = ({ children, runtimeUrl, headers = {}, credentials, p
|
|
|
2258
3210
|
}, [
|
|
2259
3211
|
renderToolCallsList,
|
|
2260
3212
|
frontendToolsList,
|
|
3213
|
+
builtInFrontendTools,
|
|
2261
3214
|
processedHumanInTheLoopTools
|
|
2262
3215
|
]);
|
|
2263
3216
|
const copilotkitRef = (0, react.useRef)(null);
|
|
2264
|
-
if (copilotkitRef.current === null)
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
3217
|
+
if (copilotkitRef.current === null) {
|
|
3218
|
+
copilotkitRef.current = new CopilotKitCoreReact({
|
|
3219
|
+
runtimeUrl: chatApiEndpoint,
|
|
3220
|
+
runtimeTransport: useSingleEndpoint === true ? "single" : useSingleEndpoint === false ? "rest" : "auto",
|
|
3221
|
+
headers: mergedHeaders,
|
|
3222
|
+
credentials,
|
|
3223
|
+
properties,
|
|
3224
|
+
agents__unsafe_dev_only: mergedAgents,
|
|
3225
|
+
tools: allTools,
|
|
3226
|
+
renderToolCalls: allRenderToolCalls,
|
|
3227
|
+
renderActivityMessages: allActivityRenderers,
|
|
3228
|
+
renderCustomMessages: renderCustomMessagesList
|
|
3229
|
+
});
|
|
3230
|
+
if (defaultThrottleMs !== void 0) copilotkitRef.current.setDefaultThrottleMs(defaultThrottleMs);
|
|
3231
|
+
}
|
|
2276
3232
|
const copilotkit = copilotkitRef.current;
|
|
2277
3233
|
(0, react.useEffect)(() => {
|
|
3234
|
+
setRuntimeA2UIEnabled(copilotkit.a2uiEnabled);
|
|
2278
3235
|
const subscription = copilotkit.subscribe({ onRuntimeConnectionStatusChanged: () => {
|
|
2279
3236
|
setRuntimeA2UIEnabled(copilotkit.a2uiEnabled);
|
|
3237
|
+
setRuntimeOpenGenUIEnabled(copilotkit.openGenerativeUIEnabled);
|
|
2280
3238
|
setRuntimeLicenseStatus(copilotkit.licenseStatus);
|
|
2281
3239
|
} });
|
|
2282
3240
|
return () => {
|
|
@@ -2335,7 +3293,7 @@ const CopilotKitProvider = ({ children, runtimeUrl, headers = {}, credentials, p
|
|
|
2335
3293
|
}, [copilotkit]);
|
|
2336
3294
|
(0, react.useEffect)(() => {
|
|
2337
3295
|
copilotkit.setRuntimeUrl(chatApiEndpoint);
|
|
2338
|
-
copilotkit.setRuntimeTransport(useSingleEndpoint ? "single" : "rest");
|
|
3296
|
+
copilotkit.setRuntimeTransport(useSingleEndpoint === true ? "single" : useSingleEndpoint === false ? "rest" : "auto");
|
|
2339
3297
|
copilotkit.setHeaders(mergedHeaders);
|
|
2340
3298
|
copilotkit.setCredentials(credentials);
|
|
2341
3299
|
copilotkit.setProperties(properties);
|
|
@@ -2369,23 +3327,75 @@ const CopilotKitProvider = ({ children, runtimeUrl, headers = {}, credentials, p
|
|
|
2369
3327
|
(0, react.useEffect)(() => {
|
|
2370
3328
|
didMountRef.current = true;
|
|
2371
3329
|
}, []);
|
|
3330
|
+
(0, react.useEffect)(() => {
|
|
3331
|
+
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.`);
|
|
3332
|
+
copilotkit.setDefaultThrottleMs(defaultThrottleMs);
|
|
3333
|
+
}, [copilotkit, defaultThrottleMs]);
|
|
3334
|
+
const designSkill = openGenerativeUI?.designSkill ?? DEFAULT_DESIGN_SKILL;
|
|
3335
|
+
(0, react.useLayoutEffect)(() => {
|
|
3336
|
+
if (!copilotkit || !openGenUIActive) return;
|
|
3337
|
+
const id = copilotkit.addContext({
|
|
3338
|
+
description: "Design guidelines for the generateSandboxedUi tool. Follow these when building UI.",
|
|
3339
|
+
value: designSkill
|
|
3340
|
+
});
|
|
3341
|
+
return () => {
|
|
3342
|
+
copilotkit.removeContext(id);
|
|
3343
|
+
};
|
|
3344
|
+
}, [
|
|
3345
|
+
copilotkit,
|
|
3346
|
+
designSkill,
|
|
3347
|
+
openGenUIActive
|
|
3348
|
+
]);
|
|
3349
|
+
const sandboxFunctionsDescriptors = (0, react.useMemo)(() => {
|
|
3350
|
+
if (sandboxFunctionsList.length === 0) return null;
|
|
3351
|
+
return JSON.stringify(sandboxFunctionsList.map((fn) => ({
|
|
3352
|
+
name: fn.name,
|
|
3353
|
+
description: fn.description,
|
|
3354
|
+
parameters: (0, _copilotkit_shared.schemaToJsonSchema)(fn.parameters, { zodToJsonSchema: zod_to_json_schema.zodToJsonSchema })
|
|
3355
|
+
})));
|
|
3356
|
+
}, [sandboxFunctionsList]);
|
|
3357
|
+
(0, react.useLayoutEffect)(() => {
|
|
3358
|
+
if (!copilotkit || !sandboxFunctionsDescriptors || !openGenUIActive) return;
|
|
3359
|
+
const id = copilotkit.addContext({
|
|
3360
|
+
description: "Sandbox functions available in generated sandboxed UI code. Call via: await Websandbox.connection.remote.<functionName>(args)",
|
|
3361
|
+
value: sandboxFunctionsDescriptors
|
|
3362
|
+
});
|
|
3363
|
+
return () => {
|
|
3364
|
+
copilotkit.removeContext(id);
|
|
3365
|
+
};
|
|
3366
|
+
}, [
|
|
3367
|
+
copilotkit,
|
|
3368
|
+
sandboxFunctionsDescriptors,
|
|
3369
|
+
openGenUIActive
|
|
3370
|
+
]);
|
|
2372
3371
|
const contextValue = (0, react.useMemo)(() => ({
|
|
2373
3372
|
copilotkit,
|
|
2374
3373
|
executingToolCallIds
|
|
2375
3374
|
}), [copilotkit, executingToolCallIds]);
|
|
2376
3375
|
const licenseContextValue = (0, react.useMemo)(() => (0, _copilotkit_shared.createLicenseContextValue)(null), []);
|
|
2377
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
2378
|
-
value:
|
|
2379
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.
|
|
2380
|
-
value:
|
|
2381
|
-
children:
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
3376
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SandboxFunctionsContext.Provider, {
|
|
3377
|
+
value: sandboxFunctionsList,
|
|
3378
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopilotKitContext.Provider, {
|
|
3379
|
+
value: contextValue,
|
|
3380
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(LicenseContext.Provider, {
|
|
3381
|
+
value: licenseContextValue,
|
|
3382
|
+
children: [
|
|
3383
|
+
runtimeA2UIEnabled && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(A2UIBuiltInToolCallRenderer, {}),
|
|
3384
|
+
runtimeA2UIEnabled && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(A2UICatalogContext, {
|
|
3385
|
+
catalog: a2ui?.catalog,
|
|
3386
|
+
includeSchema: a2ui?.includeSchema
|
|
3387
|
+
}),
|
|
3388
|
+
children,
|
|
3389
|
+
shouldRenderInspector ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopilotKitInspector, {
|
|
3390
|
+
core: copilotkit,
|
|
3391
|
+
defaultAnchor: inspectorDefaultAnchor
|
|
3392
|
+
}) : null,
|
|
3393
|
+
runtimeLicenseStatus === "none" && !resolvedPublicKey && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LicenseWarningBanner, { type: "no_license" }),
|
|
3394
|
+
runtimeLicenseStatus === "expired" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LicenseWarningBanner, { type: "expired" }),
|
|
3395
|
+
runtimeLicenseStatus === "invalid" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LicenseWarningBanner, { type: "invalid" }),
|
|
3396
|
+
runtimeLicenseStatus === "expiring" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LicenseWarningBanner, { type: "expiring" })
|
|
3397
|
+
]
|
|
3398
|
+
})
|
|
2389
3399
|
})
|
|
2390
3400
|
});
|
|
2391
3401
|
};
|
|
@@ -2526,11 +3536,21 @@ function getOrCreateThreadClone(existing, threadId, headers) {
|
|
|
2526
3536
|
byThread.set(threadId, clone);
|
|
2527
3537
|
return clone;
|
|
2528
3538
|
}
|
|
2529
|
-
function useAgent({ agentId, threadId, updates } = {}) {
|
|
3539
|
+
function useAgent({ agentId, threadId, updates, throttleMs } = {}) {
|
|
2530
3540
|
agentId ??= _copilotkit_shared.DEFAULT_AGENT_ID;
|
|
2531
3541
|
const { copilotkit } = useCopilotKit();
|
|
3542
|
+
const providerThrottleMs = copilotkit.defaultThrottleMs;
|
|
2532
3543
|
const chatConfig = useCopilotChatConfiguration();
|
|
2533
3544
|
threadId ??= chatConfig?.threadId;
|
|
3545
|
+
const effectiveThrottleMs = (0, react.useMemo)(() => {
|
|
3546
|
+
const resolved = throttleMs ?? providerThrottleMs ?? 0;
|
|
3547
|
+
if (!Number.isFinite(resolved) || resolved < 0) {
|
|
3548
|
+
const source = throttleMs !== void 0 ? "hook-level throttleMs" : "provider-level defaultThrottleMs";
|
|
3549
|
+
console.error(`useAgent: ${source} must be a non-negative finite number, got ${resolved}. Falling back to unthrottled.`);
|
|
3550
|
+
return 0;
|
|
3551
|
+
}
|
|
3552
|
+
return resolved;
|
|
3553
|
+
}, [throttleMs, providerThrottleMs]);
|
|
2534
3554
|
const [, forceUpdate] = (0, react.useReducer)((x) => x + 1, 0);
|
|
2535
3555
|
const updateFlags = (0, react.useMemo)(() => updates ?? ALL_UPDATES, [JSON.stringify(updates)]);
|
|
2536
3556
|
const provisionalAgentCache = (0, react.useRef)(/* @__PURE__ */ new Map());
|
|
@@ -2594,9 +3614,32 @@ function useAgent({ agentId, threadId, updates } = {}) {
|
|
|
2594
3614
|
(0, react.useEffect)(() => {
|
|
2595
3615
|
if (updateFlags.length === 0) return;
|
|
2596
3616
|
const handlers = {};
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
3617
|
+
let timerId = null;
|
|
3618
|
+
let active = true;
|
|
3619
|
+
if (updateFlags.includes(UseAgentUpdate.OnMessagesChanged)) {
|
|
3620
|
+
const ms = effectiveThrottleMs;
|
|
3621
|
+
if (ms > 0) {
|
|
3622
|
+
let throttleActive = false;
|
|
3623
|
+
let pending = false;
|
|
3624
|
+
const throttledNotify = () => {
|
|
3625
|
+
if (!active) return;
|
|
3626
|
+
if (!throttleActive) {
|
|
3627
|
+
throttleActive = true;
|
|
3628
|
+
pending = false;
|
|
3629
|
+
forceUpdate();
|
|
3630
|
+
timerId = setTimeout(function trailingEdge() {
|
|
3631
|
+
timerId = null;
|
|
3632
|
+
if (active && pending) {
|
|
3633
|
+
pending = false;
|
|
3634
|
+
forceUpdate();
|
|
3635
|
+
timerId = setTimeout(trailingEdge, ms);
|
|
3636
|
+
} else throttleActive = false;
|
|
3637
|
+
}, ms);
|
|
3638
|
+
} else pending = true;
|
|
3639
|
+
};
|
|
3640
|
+
handlers.onMessagesChanged = throttledNotify;
|
|
3641
|
+
} else handlers.onMessagesChanged = forceUpdate;
|
|
3642
|
+
}
|
|
2600
3643
|
if (updateFlags.includes(UseAgentUpdate.OnStateChanged)) handlers.onStateChanged = forceUpdate;
|
|
2601
3644
|
if (updateFlags.includes(UseAgentUpdate.OnRunStatusChanged)) {
|
|
2602
3645
|
handlers.onRunInitialized = forceUpdate;
|
|
@@ -2604,11 +3647,16 @@ function useAgent({ agentId, threadId, updates } = {}) {
|
|
|
2604
3647
|
handlers.onRunFailed = forceUpdate;
|
|
2605
3648
|
}
|
|
2606
3649
|
const subscription = agent.subscribe(handlers);
|
|
2607
|
-
return () =>
|
|
3650
|
+
return () => {
|
|
3651
|
+
active = false;
|
|
3652
|
+
if (timerId !== null) clearTimeout(timerId);
|
|
3653
|
+
subscription.unsubscribe();
|
|
3654
|
+
};
|
|
2608
3655
|
}, [
|
|
2609
3656
|
agent,
|
|
2610
3657
|
forceUpdate,
|
|
2611
|
-
|
|
3658
|
+
effectiveThrottleMs,
|
|
3659
|
+
updateFlags
|
|
2612
3660
|
]);
|
|
2613
3661
|
(0, react.useEffect)(() => {
|
|
2614
3662
|
if (agent instanceof _ag_ui_client.HttpAgent) agent.headers = { ...copilotkit.headers };
|
|
@@ -2666,7 +3714,8 @@ function useRenderCustomMessages() {
|
|
|
2666
3714
|
//#region src/v2/hooks/use-render-activity-message.tsx
|
|
2667
3715
|
function useRenderActivityMessage() {
|
|
2668
3716
|
const { copilotkit } = useCopilotKit();
|
|
2669
|
-
const
|
|
3717
|
+
const config = useCopilotChatConfiguration();
|
|
3718
|
+
const agentId = config?.agentId ?? _copilotkit_shared.DEFAULT_AGENT_ID;
|
|
2670
3719
|
const renderers = copilotkit.renderActivityMessages;
|
|
2671
3720
|
const findRenderer = (0, react.useCallback)((activityType) => {
|
|
2672
3721
|
if (!renderers.length) return null;
|
|
@@ -2682,7 +3731,8 @@ function useRenderActivityMessage() {
|
|
|
2682
3731
|
return null;
|
|
2683
3732
|
}
|
|
2684
3733
|
const Component = renderer.render;
|
|
2685
|
-
const
|
|
3734
|
+
const registryAgent = copilotkit.getAgent(agentId);
|
|
3735
|
+
const agent = getThreadClone(registryAgent, config?.threadId) ?? registryAgent;
|
|
2686
3736
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Component, {
|
|
2687
3737
|
activityType: message.activityType,
|
|
2688
3738
|
content: parseResult.data,
|
|
@@ -2691,6 +3741,7 @@ function useRenderActivityMessage() {
|
|
|
2691
3741
|
}, message.id);
|
|
2692
3742
|
}, [
|
|
2693
3743
|
agentId,
|
|
3744
|
+
config?.threadId,
|
|
2694
3745
|
copilotkit,
|
|
2695
3746
|
findRenderer
|
|
2696
3747
|
]);
|
|
@@ -2716,7 +3767,7 @@ function useFrontendTool(tool, deps) {
|
|
|
2716
3767
|
copilotkit.removeTool(name, tool.agentId);
|
|
2717
3768
|
}
|
|
2718
3769
|
copilotkit.addTool(tool);
|
|
2719
|
-
if (tool.render
|
|
3770
|
+
if (tool.render) copilotkit.addHookRenderToolCall({
|
|
2720
3771
|
name,
|
|
2721
3772
|
args: tool.parameters,
|
|
2722
3773
|
agentId: tool.agentId,
|
|
@@ -2801,18 +3852,6 @@ function useComponent(config, deps) {
|
|
|
2801
3852
|
}, deps);
|
|
2802
3853
|
}
|
|
2803
3854
|
|
|
2804
|
-
//#endregion
|
|
2805
|
-
//#region src/v2/types/defineToolCallRenderer.ts
|
|
2806
|
-
function defineToolCallRenderer(def) {
|
|
2807
|
-
const argsSchema = def.name === "*" && !def.args ? zod.z.any() : def.args;
|
|
2808
|
-
return {
|
|
2809
|
-
name: def.name,
|
|
2810
|
-
args: argsSchema,
|
|
2811
|
-
render: def.render,
|
|
2812
|
-
...def.agentId ? { agentId: def.agentId } : {}
|
|
2813
|
-
};
|
|
2814
|
-
}
|
|
2815
|
-
|
|
2816
3855
|
//#endregion
|
|
2817
3856
|
//#region src/v2/hooks/use-render-tool.tsx
|
|
2818
3857
|
const EMPTY_DEPS = [];
|
|
@@ -3142,31 +4181,6 @@ function useHumanInTheLoop(tool, deps) {
|
|
|
3142
4181
|
]);
|
|
3143
4182
|
}
|
|
3144
4183
|
|
|
3145
|
-
//#endregion
|
|
3146
|
-
//#region src/v2/hooks/use-agent-context.tsx
|
|
3147
|
-
function useAgentContext(context) {
|
|
3148
|
-
const { description, value } = context;
|
|
3149
|
-
const { copilotkit } = useCopilotKit();
|
|
3150
|
-
const stringValue = (0, react.useMemo)(() => {
|
|
3151
|
-
if (typeof value === "string") return value;
|
|
3152
|
-
return JSON.stringify(value);
|
|
3153
|
-
}, [value]);
|
|
3154
|
-
(0, react.useLayoutEffect)(() => {
|
|
3155
|
-
if (!copilotkit) return;
|
|
3156
|
-
const id = copilotkit.addContext({
|
|
3157
|
-
description,
|
|
3158
|
-
value: stringValue
|
|
3159
|
-
});
|
|
3160
|
-
return () => {
|
|
3161
|
-
copilotkit.removeContext(id);
|
|
3162
|
-
};
|
|
3163
|
-
}, [
|
|
3164
|
-
description,
|
|
3165
|
-
stringValue,
|
|
3166
|
-
copilotkit
|
|
3167
|
-
]);
|
|
3168
|
-
}
|
|
3169
|
-
|
|
3170
4184
|
//#endregion
|
|
3171
4185
|
//#region src/v2/hooks/use-suggestions.tsx
|
|
3172
4186
|
function useSuggestions({ agentId } = {}) {
|
|
@@ -3576,11 +4590,19 @@ function useThreadStoreSelector(store, selector) {
|
|
|
3576
4590
|
function useThreads$1({ agentId, includeArchived, limit }) {
|
|
3577
4591
|
const { copilotkit } = useCopilotKit();
|
|
3578
4592
|
const [store] = (0, react.useState)(() => (0, _copilotkit_core.ɵcreateThreadStore)({ fetch: globalThis.fetch }));
|
|
3579
|
-
const
|
|
4593
|
+
const coreThreads = useThreadStoreSelector(store, _copilotkit_core.ɵselectThreads);
|
|
4594
|
+
const threads = (0, react.useMemo)(() => coreThreads.map(({ id, agentId, name, archived, createdAt, updatedAt }) => ({
|
|
4595
|
+
id,
|
|
4596
|
+
agentId,
|
|
4597
|
+
name,
|
|
4598
|
+
archived,
|
|
4599
|
+
createdAt,
|
|
4600
|
+
updatedAt
|
|
4601
|
+
})), [coreThreads]);
|
|
3580
4602
|
const storeIsLoading = useThreadStoreSelector(store, _copilotkit_core.ɵselectThreadsIsLoading);
|
|
3581
4603
|
const storeError = useThreadStoreSelector(store, _copilotkit_core.ɵselectThreadsError);
|
|
3582
|
-
const
|
|
3583
|
-
const
|
|
4604
|
+
const hasMoreThreads = useThreadStoreSelector(store, _copilotkit_core.ɵselectHasNextPage);
|
|
4605
|
+
const isFetchingMoreThreads = useThreadStoreSelector(store, _copilotkit_core.ɵselectIsFetchingNextPage);
|
|
3584
4606
|
const headersKey = (0, react.useMemo)(() => {
|
|
3585
4607
|
return JSON.stringify(Object.entries(copilotkit.headers ?? {}).sort(([left], [right]) => left.localeCompare(right)));
|
|
3586
4608
|
}, [copilotkit.headers]);
|
|
@@ -3623,15 +4645,173 @@ function useThreads$1({ agentId, includeArchived, limit }) {
|
|
|
3623
4645
|
threads,
|
|
3624
4646
|
isLoading,
|
|
3625
4647
|
error,
|
|
3626
|
-
|
|
3627
|
-
|
|
3628
|
-
|
|
4648
|
+
hasMoreThreads,
|
|
4649
|
+
isFetchingMoreThreads,
|
|
4650
|
+
fetchMoreThreads: (0, react.useCallback)(() => store.fetchNextPage(), [store]),
|
|
3629
4651
|
renameThread,
|
|
3630
4652
|
archiveThread,
|
|
3631
4653
|
deleteThread
|
|
3632
4654
|
};
|
|
3633
4655
|
}
|
|
3634
4656
|
|
|
4657
|
+
//#endregion
|
|
4658
|
+
//#region src/v2/hooks/use-attachments.tsx
|
|
4659
|
+
/**
|
|
4660
|
+
* Hook that manages file attachment state — uploads, drag-and-drop, paste,
|
|
4661
|
+
* and lifecycle. All returned callbacks are referentially stable across
|
|
4662
|
+
* renders (via useCallback) to avoid destabilizing downstream memoization.
|
|
4663
|
+
*/
|
|
4664
|
+
function useAttachments({ config }) {
|
|
4665
|
+
const enabled = config?.enabled ?? false;
|
|
4666
|
+
const [attachments, setAttachments] = (0, react.useState)([]);
|
|
4667
|
+
const [dragOver, setDragOver] = (0, react.useState)(false);
|
|
4668
|
+
const fileInputRef = (0, react.useRef)(null);
|
|
4669
|
+
const containerRef = (0, react.useRef)(null);
|
|
4670
|
+
const configRef = (0, react.useRef)(config);
|
|
4671
|
+
configRef.current = config;
|
|
4672
|
+
const attachmentsRef = (0, react.useRef)([]);
|
|
4673
|
+
attachmentsRef.current = attachments;
|
|
4674
|
+
const processFiles = (0, react.useCallback)(async (files) => {
|
|
4675
|
+
const cfg = configRef.current;
|
|
4676
|
+
const accept = cfg?.accept ?? "*/*";
|
|
4677
|
+
const maxSize = cfg?.maxSize ?? 20 * 1024 * 1024;
|
|
4678
|
+
const rejectedFiles = files.filter((file) => !(0, _copilotkit_shared.matchesAcceptFilter)(file, accept));
|
|
4679
|
+
for (const file of rejectedFiles) cfg?.onUploadFailed?.({
|
|
4680
|
+
reason: "invalid-type",
|
|
4681
|
+
file,
|
|
4682
|
+
message: `File "${file.name}" is not accepted. Supported types: ${accept}`
|
|
4683
|
+
});
|
|
4684
|
+
const validFiles = files.filter((file) => (0, _copilotkit_shared.matchesAcceptFilter)(file, accept));
|
|
4685
|
+
for (const file of validFiles) {
|
|
4686
|
+
if ((0, _copilotkit_shared.exceedsMaxSize)(file, maxSize)) {
|
|
4687
|
+
cfg?.onUploadFailed?.({
|
|
4688
|
+
reason: "file-too-large",
|
|
4689
|
+
file,
|
|
4690
|
+
message: `File "${file.name}" exceeds the maximum size of ${(0, _copilotkit_shared.formatFileSize)(maxSize)}`
|
|
4691
|
+
});
|
|
4692
|
+
continue;
|
|
4693
|
+
}
|
|
4694
|
+
const modality = (0, _copilotkit_shared.getModalityFromMimeType)(file.type);
|
|
4695
|
+
const placeholderId = (0, _copilotkit_shared.randomUUID)();
|
|
4696
|
+
const placeholder = {
|
|
4697
|
+
id: placeholderId,
|
|
4698
|
+
type: modality,
|
|
4699
|
+
source: {
|
|
4700
|
+
type: "data",
|
|
4701
|
+
value: "",
|
|
4702
|
+
mimeType: file.type
|
|
4703
|
+
},
|
|
4704
|
+
filename: file.name,
|
|
4705
|
+
size: file.size,
|
|
4706
|
+
status: "uploading"
|
|
4707
|
+
};
|
|
4708
|
+
setAttachments((prev) => [...prev, placeholder]);
|
|
4709
|
+
try {
|
|
4710
|
+
let source;
|
|
4711
|
+
let uploadMetadata;
|
|
4712
|
+
if (cfg?.onUpload) {
|
|
4713
|
+
const { metadata: meta, ...uploadSource } = await cfg.onUpload(file);
|
|
4714
|
+
source = uploadSource;
|
|
4715
|
+
uploadMetadata = meta;
|
|
4716
|
+
} else source = {
|
|
4717
|
+
type: "data",
|
|
4718
|
+
value: await (0, _copilotkit_shared.readFileAsBase64)(file),
|
|
4719
|
+
mimeType: file.type
|
|
4720
|
+
};
|
|
4721
|
+
let thumbnail;
|
|
4722
|
+
if (modality === "video") thumbnail = await (0, _copilotkit_shared.generateVideoThumbnail)(file);
|
|
4723
|
+
setAttachments((prev) => prev.map((att) => att.id === placeholderId ? {
|
|
4724
|
+
...att,
|
|
4725
|
+
source,
|
|
4726
|
+
status: "ready",
|
|
4727
|
+
thumbnail,
|
|
4728
|
+
metadata: uploadMetadata
|
|
4729
|
+
} : att));
|
|
4730
|
+
} catch (error) {
|
|
4731
|
+
setAttachments((prev) => prev.filter((att) => att.id !== placeholderId));
|
|
4732
|
+
console.error(`[CopilotKit] Failed to upload "${file.name}":`, error);
|
|
4733
|
+
cfg?.onUploadFailed?.({
|
|
4734
|
+
reason: "upload-failed",
|
|
4735
|
+
file,
|
|
4736
|
+
message: error instanceof Error ? error.message : `Failed to upload "${file.name}"`
|
|
4737
|
+
});
|
|
4738
|
+
}
|
|
4739
|
+
}
|
|
4740
|
+
}, []);
|
|
4741
|
+
const handleFileUpload = (0, react.useCallback)(async (e) => {
|
|
4742
|
+
if (!e.target.files?.length) return;
|
|
4743
|
+
try {
|
|
4744
|
+
await processFiles(Array.from(e.target.files));
|
|
4745
|
+
} catch (error) {
|
|
4746
|
+
console.error("[CopilotKit] Upload error:", error);
|
|
4747
|
+
}
|
|
4748
|
+
}, [processFiles]);
|
|
4749
|
+
const handleDragOver = (0, react.useCallback)((e) => {
|
|
4750
|
+
if (!configRef.current?.enabled) return;
|
|
4751
|
+
e.preventDefault();
|
|
4752
|
+
e.stopPropagation();
|
|
4753
|
+
setDragOver(true);
|
|
4754
|
+
}, []);
|
|
4755
|
+
const handleDragLeave = (0, react.useCallback)((e) => {
|
|
4756
|
+
e.preventDefault();
|
|
4757
|
+
e.stopPropagation();
|
|
4758
|
+
setDragOver(false);
|
|
4759
|
+
}, []);
|
|
4760
|
+
const handleDrop = (0, react.useCallback)(async (e) => {
|
|
4761
|
+
e.preventDefault();
|
|
4762
|
+
e.stopPropagation();
|
|
4763
|
+
setDragOver(false);
|
|
4764
|
+
if (!configRef.current?.enabled) return;
|
|
4765
|
+
const files = Array.from(e.dataTransfer.files);
|
|
4766
|
+
if (files.length > 0) try {
|
|
4767
|
+
await processFiles(files);
|
|
4768
|
+
} catch (error) {
|
|
4769
|
+
console.error("[CopilotKit] Drop error:", error);
|
|
4770
|
+
}
|
|
4771
|
+
}, [processFiles]);
|
|
4772
|
+
(0, react.useEffect)(() => {
|
|
4773
|
+
if (!enabled) return;
|
|
4774
|
+
const handlePaste = async (e) => {
|
|
4775
|
+
const target = e.target;
|
|
4776
|
+
if (!target || !containerRef.current?.contains(target)) return;
|
|
4777
|
+
const accept = configRef.current?.accept ?? "*/*";
|
|
4778
|
+
const fileItems = Array.from(e.clipboardData?.items || []).filter((item) => item.kind === "file" && item.getAsFile() !== null && (0, _copilotkit_shared.matchesAcceptFilter)(item.getAsFile(), accept));
|
|
4779
|
+
if (fileItems.length === 0) return;
|
|
4780
|
+
e.preventDefault();
|
|
4781
|
+
const files = fileItems.map((item) => item.getAsFile()).filter((f) => f !== null);
|
|
4782
|
+
try {
|
|
4783
|
+
await processFiles(files);
|
|
4784
|
+
} catch (error) {
|
|
4785
|
+
console.error("[CopilotKit] Paste error:", error);
|
|
4786
|
+
}
|
|
4787
|
+
};
|
|
4788
|
+
document.addEventListener("paste", handlePaste);
|
|
4789
|
+
return () => document.removeEventListener("paste", handlePaste);
|
|
4790
|
+
}, [enabled, processFiles]);
|
|
4791
|
+
return {
|
|
4792
|
+
attachments,
|
|
4793
|
+
enabled,
|
|
4794
|
+
dragOver,
|
|
4795
|
+
fileInputRef,
|
|
4796
|
+
containerRef,
|
|
4797
|
+
processFiles,
|
|
4798
|
+
handleFileUpload,
|
|
4799
|
+
handleDragOver,
|
|
4800
|
+
handleDragLeave,
|
|
4801
|
+
handleDrop,
|
|
4802
|
+
removeAttachment: (0, react.useCallback)((id) => {
|
|
4803
|
+
setAttachments((prev) => prev.filter((a) => a.id !== id));
|
|
4804
|
+
}, []),
|
|
4805
|
+
consumeAttachments: (0, react.useCallback)(() => {
|
|
4806
|
+
const ready = attachmentsRef.current.filter((a) => a.status === "ready");
|
|
4807
|
+
if (ready.length === 0) return ready;
|
|
4808
|
+
setAttachments((prev) => prev.filter((a) => a.status !== "ready"));
|
|
4809
|
+
if (fileInputRef.current) fileInputRef.current.value = "";
|
|
4810
|
+
return ready;
|
|
4811
|
+
}, [])
|
|
4812
|
+
};
|
|
4813
|
+
}
|
|
4814
|
+
|
|
3635
4815
|
//#endregion
|
|
3636
4816
|
//#region src/v2/components/chat/CopilotChatToolCallsView.tsx
|
|
3637
4817
|
function CopilotChatToolCallsView({ message, messages = [] }) {
|
|
@@ -3748,9 +4928,19 @@ function CopilotChatAssistantMessage({ message, messages, isRunning, onThumbsUp,
|
|
|
3748
4928
|
_CopilotChatAssistantMessage.CopyButton = ({ className, title, onClick, ...props }) => {
|
|
3749
4929
|
const labels = useCopilotChatConfiguration()?.labels ?? CopilotChatDefaultLabels;
|
|
3750
4930
|
const [copied, setCopied] = (0, react.useState)(false);
|
|
4931
|
+
const timerRef = (0, react.useRef)(null);
|
|
4932
|
+
(0, react.useEffect)(() => {
|
|
4933
|
+
return () => {
|
|
4934
|
+
if (timerRef.current !== null) clearTimeout(timerRef.current);
|
|
4935
|
+
};
|
|
4936
|
+
}, []);
|
|
3751
4937
|
const handleClick = (event) => {
|
|
3752
4938
|
setCopied(true);
|
|
3753
|
-
|
|
4939
|
+
if (timerRef.current !== null) clearTimeout(timerRef.current);
|
|
4940
|
+
timerRef.current = setTimeout(() => {
|
|
4941
|
+
timerRef.current = null;
|
|
4942
|
+
setCopied(false);
|
|
4943
|
+
}, 2e3);
|
|
3754
4944
|
if (onClick) onClick(event);
|
|
3755
4945
|
};
|
|
3756
4946
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ToolbarButton, {
|
|
@@ -3808,6 +4998,79 @@ CopilotChatAssistantMessage.ReadAloudButton.displayName = "CopilotChatAssistantM
|
|
|
3808
4998
|
CopilotChatAssistantMessage.RegenerateButton.displayName = "CopilotChatAssistantMessage.RegenerateButton";
|
|
3809
4999
|
var CopilotChatAssistantMessage_default = CopilotChatAssistantMessage;
|
|
3810
5000
|
|
|
5001
|
+
//#endregion
|
|
5002
|
+
//#region src/v2/components/chat/CopilotChatAttachmentRenderer.tsx
|
|
5003
|
+
const ImageAttachment = (0, react.memo)(function ImageAttachment({ src, className }) {
|
|
5004
|
+
const [error, setError] = (0, react.useState)(false);
|
|
5005
|
+
if (error) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
5006
|
+
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),
|
|
5007
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "Failed to load image" })
|
|
5008
|
+
});
|
|
5009
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
|
|
5010
|
+
src,
|
|
5011
|
+
alt: "Image attachment",
|
|
5012
|
+
className: cn("cpk:max-w-full cpk:h-auto cpk:rounded-lg", className),
|
|
5013
|
+
onError: () => setError(true)
|
|
5014
|
+
});
|
|
5015
|
+
});
|
|
5016
|
+
const AudioAttachment = (0, react.memo)(function AudioAttachment({ src, filename, className }) {
|
|
5017
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
5018
|
+
className: cn("cpk:flex cpk:flex-col cpk:gap-1", className),
|
|
5019
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("audio", {
|
|
5020
|
+
src,
|
|
5021
|
+
controls: true,
|
|
5022
|
+
preload: "metadata",
|
|
5023
|
+
className: "cpk:max-w-[300px] cpk:w-full cpk:h-10"
|
|
5024
|
+
}), filename && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
5025
|
+
className: "cpk:text-xs cpk:text-muted-foreground cpk:truncate cpk:max-w-[300px]",
|
|
5026
|
+
children: filename
|
|
5027
|
+
})]
|
|
5028
|
+
});
|
|
5029
|
+
});
|
|
5030
|
+
const VideoAttachment = (0, react.memo)(function VideoAttachment({ src, className }) {
|
|
5031
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("video", {
|
|
5032
|
+
src,
|
|
5033
|
+
controls: true,
|
|
5034
|
+
preload: "metadata",
|
|
5035
|
+
className: cn("cpk:max-w-[400px] cpk:w-full cpk:rounded-lg", className)
|
|
5036
|
+
});
|
|
5037
|
+
});
|
|
5038
|
+
const DocumentAttachment = (0, react.memo)(function DocumentAttachment({ source, filename, className }) {
|
|
5039
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
5040
|
+
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),
|
|
5041
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
5042
|
+
className: "cpk:text-xs cpk:font-bold cpk:uppercase",
|
|
5043
|
+
children: (0, _copilotkit_shared.getDocumentIcon)(source.mimeType ?? "")
|
|
5044
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
5045
|
+
className: "cpk:text-sm cpk:text-muted-foreground cpk:truncate",
|
|
5046
|
+
children: filename || source.mimeType || "Unknown type"
|
|
5047
|
+
})]
|
|
5048
|
+
});
|
|
5049
|
+
});
|
|
5050
|
+
const CopilotChatAttachmentRenderer = ({ type, source, filename, className }) => {
|
|
5051
|
+
const src = (0, _copilotkit_shared.getSourceUrl)(source);
|
|
5052
|
+
switch (type) {
|
|
5053
|
+
case "image": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ImageAttachment, {
|
|
5054
|
+
src,
|
|
5055
|
+
className
|
|
5056
|
+
});
|
|
5057
|
+
case "audio": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AudioAttachment, {
|
|
5058
|
+
src,
|
|
5059
|
+
filename,
|
|
5060
|
+
className
|
|
5061
|
+
});
|
|
5062
|
+
case "video": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(VideoAttachment, {
|
|
5063
|
+
src,
|
|
5064
|
+
className
|
|
5065
|
+
});
|
|
5066
|
+
case "document": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DocumentAttachment, {
|
|
5067
|
+
source,
|
|
5068
|
+
filename,
|
|
5069
|
+
className
|
|
5070
|
+
});
|
|
5071
|
+
}
|
|
5072
|
+
};
|
|
5073
|
+
|
|
3811
5074
|
//#endregion
|
|
3812
5075
|
//#region src/v2/components/chat/CopilotChatUserMessage.tsx
|
|
3813
5076
|
function flattenUserMessageContent(content) {
|
|
@@ -3818,8 +5081,17 @@ function flattenUserMessageContent(content) {
|
|
|
3818
5081
|
return "";
|
|
3819
5082
|
}).filter((text) => text.length > 0).join("\n");
|
|
3820
5083
|
}
|
|
5084
|
+
function getMediaParts(content) {
|
|
5085
|
+
if (!content || typeof content === "string") return [];
|
|
5086
|
+
return content.filter((part) => part.type === "image" || part.type === "audio" || part.type === "video" || part.type === "document");
|
|
5087
|
+
}
|
|
5088
|
+
function getFilename(part) {
|
|
5089
|
+
const meta = part.metadata;
|
|
5090
|
+
if (meta != null && typeof meta === "object" && "filename" in meta && typeof meta.filename === "string") return meta.filename;
|
|
5091
|
+
}
|
|
3821
5092
|
function CopilotChatUserMessage({ message, onEditMessage, branchIndex, numberOfBranches, onSwitchToBranch, additionalToolbarItems, messageRenderer, toolbar, copyButton, editButton, branchNavigation, children, className, ...props }) {
|
|
3822
5093
|
const flattenedContent = (0, react.useMemo)(() => flattenUserMessageContent(message.content), [message.content]);
|
|
5094
|
+
const mediaParts = (0, react.useMemo)(() => getMediaParts(message.content), [message.content]);
|
|
3823
5095
|
const BoundMessageRenderer = renderSlot(messageRenderer, CopilotChatUserMessage.MessageRenderer, { content: flattenedContent });
|
|
3824
5096
|
const BoundCopyButton = renderSlot(copyButton, CopilotChatUserMessage.CopyButton, { onClick: async () => {
|
|
3825
5097
|
if (flattenedContent) try {
|
|
@@ -3866,7 +5138,18 @@ function CopilotChatUserMessage({ message, onEditMessage, branchIndex, numberOfB
|
|
|
3866
5138
|
className: (0, tailwind_merge.twMerge)("copilotKitMessage copilotKitUserMessage cpk:flex cpk:flex-col cpk:items-end cpk:group cpk:pt-10", className),
|
|
3867
5139
|
"data-message-id": message.id,
|
|
3868
5140
|
...props,
|
|
3869
|
-
children: [
|
|
5141
|
+
children: [
|
|
5142
|
+
BoundMessageRenderer,
|
|
5143
|
+
mediaParts.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
5144
|
+
className: "cpk:flex cpk:flex-col cpk:items-end cpk:gap-2 cpk:mt-2",
|
|
5145
|
+
children: mediaParts.map((part, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopilotChatAttachmentRenderer, {
|
|
5146
|
+
type: part.type,
|
|
5147
|
+
source: part.source,
|
|
5148
|
+
filename: getFilename(part)
|
|
5149
|
+
}, index))
|
|
5150
|
+
}),
|
|
5151
|
+
BoundToolbar
|
|
5152
|
+
]
|
|
3870
5153
|
});
|
|
3871
5154
|
}
|
|
3872
5155
|
(function(_CopilotChatUserMessage) {
|
|
@@ -4164,6 +5447,7 @@ const CopilotChatSuggestionView = react.default.forwardRef(function CopilotChatS
|
|
|
4164
5447
|
const isLoading = loadingSet.has(index) || suggestion.isLoading === true;
|
|
4165
5448
|
const pill = renderSlot(suggestionSlot, CopilotChatSuggestionPill, {
|
|
4166
5449
|
children: suggestion.title,
|
|
5450
|
+
className: suggestion.className,
|
|
4167
5451
|
isLoading,
|
|
4168
5452
|
type: "button",
|
|
4169
5453
|
onClick: () => onSelectSuggestion?.(suggestion, index)
|
|
@@ -4200,9 +5484,43 @@ const CopilotChatSuggestionView = react.default.forwardRef(function CopilotChatS
|
|
|
4200
5484
|
});
|
|
4201
5485
|
CopilotChatSuggestionView.displayName = "CopilotChatSuggestionView";
|
|
4202
5486
|
|
|
5487
|
+
//#endregion
|
|
5488
|
+
//#region src/v2/components/chat/scroll-element-context.ts
|
|
5489
|
+
/**
|
|
5490
|
+
* Provides the scroll container element to child components that need it for
|
|
5491
|
+
* virtualization. Set by CopilotChatView.ScrollView; consumed by
|
|
5492
|
+
* CopilotChatMessageView to feed useVirtualizer's getScrollElement.
|
|
5493
|
+
*
|
|
5494
|
+
* Carries the element itself (not a ref) so that context consumers re-render
|
|
5495
|
+
* reactively when the scroll container is first mounted.
|
|
5496
|
+
*/
|
|
5497
|
+
const ScrollElementContext = react.default.createContext(null);
|
|
5498
|
+
|
|
4203
5499
|
//#endregion
|
|
4204
5500
|
//#region src/v2/components/chat/CopilotChatMessageView.tsx
|
|
4205
5501
|
/**
|
|
5502
|
+
* Resolves a slot value into a { Component, slotProps } pair, handling the three
|
|
5503
|
+
* slot forms: a component type, a className string, or a partial-props object.
|
|
5504
|
+
*/
|
|
5505
|
+
function resolveSlotComponent(slot, DefaultComponent) {
|
|
5506
|
+
if (isReactComponentType(slot)) return {
|
|
5507
|
+
Component: slot,
|
|
5508
|
+
slotProps: void 0
|
|
5509
|
+
};
|
|
5510
|
+
if (typeof slot === "string") return {
|
|
5511
|
+
Component: DefaultComponent,
|
|
5512
|
+
slotProps: { className: slot }
|
|
5513
|
+
};
|
|
5514
|
+
if (slot && typeof slot === "object") return {
|
|
5515
|
+
Component: DefaultComponent,
|
|
5516
|
+
slotProps: slot
|
|
5517
|
+
};
|
|
5518
|
+
return {
|
|
5519
|
+
Component: DefaultComponent,
|
|
5520
|
+
slotProps: void 0
|
|
5521
|
+
};
|
|
5522
|
+
}
|
|
5523
|
+
/**
|
|
4206
5524
|
* Memoized wrapper for assistant messages to prevent re-renders when other messages change.
|
|
4207
5525
|
*/
|
|
4208
5526
|
const MemoizedAssistantMessage = react.default.memo(function MemoizedAssistantMessage({ message, messages, isRunning, AssistantMessageComponent, slotProps }) {
|
|
@@ -4221,7 +5539,6 @@ const MemoizedAssistantMessage = react.default.memo(function MemoizedAssistantMe
|
|
|
4221
5539
|
if (prevToolCalls && nextToolCalls) for (let i = 0; i < prevToolCalls.length; i++) {
|
|
4222
5540
|
const prevTc = prevToolCalls[i];
|
|
4223
5541
|
const nextTc = nextToolCalls[i];
|
|
4224
|
-
if (!prevTc || !nextTc) return false;
|
|
4225
5542
|
if (prevTc.id !== nextTc.id) return false;
|
|
4226
5543
|
if (prevTc.function.arguments !== nextTc.function.arguments) return false;
|
|
4227
5544
|
}
|
|
@@ -4300,6 +5617,7 @@ const MemoizedCustomMessage = react.default.memo(function MemoizedCustomMessage(
|
|
|
4300
5617
|
if (JSON.stringify(prevProps.stateSnapshot) !== JSON.stringify(nextProps.stateSnapshot)) return false;
|
|
4301
5618
|
return true;
|
|
4302
5619
|
});
|
|
5620
|
+
const VIRTUALIZE_THRESHOLD = 50;
|
|
4303
5621
|
function CopilotChatMessageView({ messages = [], assistantMessage, userMessage, reasoningMessage, cursor, isRunning = false, children, className, ...props }) {
|
|
4304
5622
|
const renderCustomMessage = useRenderCustomMessages();
|
|
4305
5623
|
const { renderActivityMessage } = useRenderActivityMessage();
|
|
@@ -4333,9 +5651,34 @@ function CopilotChatMessageView({ messages = [], assistantMessage, userMessage,
|
|
|
4333
5651
|
if (!resolvedRunId) return void 0;
|
|
4334
5652
|
return copilotkit.getStateByRun(config.agentId, config.threadId, resolvedRunId);
|
|
4335
5653
|
};
|
|
4336
|
-
const deduplicatedMessages = [...new Map(messages.map((m) => [m.id, m])).values()];
|
|
5654
|
+
const deduplicatedMessages = (0, react.useMemo)(() => [...new Map(messages.map((m) => [m.id, m])).values()], [messages]);
|
|
4337
5655
|
if (process.env.NODE_ENV === "development" && deduplicatedMessages.length < messages.length) console.warn(`CopilotChatMessageView: Deduplicated ${messages.length - deduplicatedMessages.length} message(s) with duplicate IDs.`);
|
|
4338
|
-
const
|
|
5656
|
+
const { Component: AssistantComponent, slotProps: assistantSlotProps } = (0, react.useMemo)(() => resolveSlotComponent(assistantMessage, CopilotChatAssistantMessage_default), [assistantMessage]);
|
|
5657
|
+
const { Component: UserComponent, slotProps: userSlotProps } = (0, react.useMemo)(() => resolveSlotComponent(userMessage, CopilotChatUserMessage_default), [userMessage]);
|
|
5658
|
+
const { Component: ReasoningComponent, slotProps: reasoningSlotProps } = (0, react.useMemo)(() => resolveSlotComponent(reasoningMessage, CopilotChatReasoningMessage_default), [reasoningMessage]);
|
|
5659
|
+
const scrollElementFromCtx = (0, react.useContext)(ScrollElementContext);
|
|
5660
|
+
const scrollElement = scrollElementFromCtx && scrollElementFromCtx.clientHeight > 0 ? scrollElementFromCtx : null;
|
|
5661
|
+
(0, react.useEffect)(() => {
|
|
5662
|
+
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.");
|
|
5663
|
+
}, [scrollElementFromCtx]);
|
|
5664
|
+
const shouldVirtualize = !!scrollElement && !children && deduplicatedMessages.length > VIRTUALIZE_THRESHOLD;
|
|
5665
|
+
const virtualizer = (0, _tanstack_react_virtual.useVirtualizer)({
|
|
5666
|
+
count: shouldVirtualize ? deduplicatedMessages.length : 0,
|
|
5667
|
+
getScrollElement: () => scrollElement,
|
|
5668
|
+
estimateSize: () => 100,
|
|
5669
|
+
overscan: 5,
|
|
5670
|
+
measureElement: (el) => el?.getBoundingClientRect().height ?? 0,
|
|
5671
|
+
initialRect: {
|
|
5672
|
+
width: 0,
|
|
5673
|
+
height: 600
|
|
5674
|
+
}
|
|
5675
|
+
});
|
|
5676
|
+
const firstMessageId = deduplicatedMessages[0]?.id;
|
|
5677
|
+
(0, react.useLayoutEffect)(() => {
|
|
5678
|
+
if (!shouldVirtualize || !deduplicatedMessages.length) return;
|
|
5679
|
+
virtualizer.scrollToIndex(deduplicatedMessages.length - 1, { align: "end" });
|
|
5680
|
+
}, [shouldVirtualize, firstMessageId]);
|
|
5681
|
+
const renderMessageBlock = (message) => {
|
|
4339
5682
|
const elements = [];
|
|
4340
5683
|
const stateSnapshot = getStateSnapshotForMessage(message.id);
|
|
4341
5684
|
if (renderCustomMessage) elements.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(MemoizedCustomMessage, {
|
|
@@ -4344,58 +5687,38 @@ function CopilotChatMessageView({ messages = [], assistantMessage, userMessage,
|
|
|
4344
5687
|
renderCustomMessage,
|
|
4345
5688
|
stateSnapshot
|
|
4346
5689
|
}, `${message.id}-custom-before`));
|
|
4347
|
-
if (message.role === "assistant") {
|
|
4348
|
-
|
|
4349
|
-
|
|
4350
|
-
|
|
4351
|
-
|
|
4352
|
-
|
|
4353
|
-
|
|
4354
|
-
|
|
4355
|
-
|
|
4356
|
-
|
|
4357
|
-
|
|
4358
|
-
|
|
4359
|
-
|
|
4360
|
-
|
|
4361
|
-
|
|
4362
|
-
|
|
4363
|
-
|
|
4364
|
-
|
|
4365
|
-
|
|
4366
|
-
|
|
4367
|
-
|
|
4368
|
-
|
|
4369
|
-
|
|
4370
|
-
}, message.id));
|
|
4371
|
-
} else if (message.role === "activity") {
|
|
4372
|
-
const activityMsg = message;
|
|
4373
|
-
elements.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(MemoizedActivityMessage, {
|
|
4374
|
-
message: activityMsg,
|
|
4375
|
-
renderActivityMessage
|
|
4376
|
-
}, message.id));
|
|
4377
|
-
} else if (message.role === "reasoning") {
|
|
4378
|
-
let ReasoningComponent = CopilotChatReasoningMessage_default;
|
|
4379
|
-
let reasoningSlotProps;
|
|
4380
|
-
if (isReactComponentType(reasoningMessage)) ReasoningComponent = reasoningMessage;
|
|
4381
|
-
else if (typeof reasoningMessage === "string") reasoningSlotProps = { className: reasoningMessage };
|
|
4382
|
-
else if (reasoningMessage && typeof reasoningMessage === "object") reasoningSlotProps = reasoningMessage;
|
|
4383
|
-
elements.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(MemoizedReasoningMessage, {
|
|
4384
|
-
message,
|
|
4385
|
-
messages,
|
|
4386
|
-
isRunning,
|
|
4387
|
-
ReasoningMessageComponent: ReasoningComponent,
|
|
4388
|
-
slotProps: reasoningSlotProps
|
|
4389
|
-
}, message.id));
|
|
4390
|
-
}
|
|
5690
|
+
if (message.role === "assistant") elements.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(MemoizedAssistantMessage, {
|
|
5691
|
+
message,
|
|
5692
|
+
messages,
|
|
5693
|
+
isRunning,
|
|
5694
|
+
AssistantMessageComponent: AssistantComponent,
|
|
5695
|
+
slotProps: assistantSlotProps
|
|
5696
|
+
}, message.id));
|
|
5697
|
+
else if (message.role === "user") elements.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(MemoizedUserMessage, {
|
|
5698
|
+
message,
|
|
5699
|
+
UserMessageComponent: UserComponent,
|
|
5700
|
+
slotProps: userSlotProps
|
|
5701
|
+
}, message.id));
|
|
5702
|
+
else if (message.role === "activity") elements.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(MemoizedActivityMessage, {
|
|
5703
|
+
message,
|
|
5704
|
+
renderActivityMessage
|
|
5705
|
+
}, message.id));
|
|
5706
|
+
else if (message.role === "reasoning") elements.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(MemoizedReasoningMessage, {
|
|
5707
|
+
message,
|
|
5708
|
+
messages,
|
|
5709
|
+
isRunning,
|
|
5710
|
+
ReasoningMessageComponent: ReasoningComponent,
|
|
5711
|
+
slotProps: reasoningSlotProps
|
|
5712
|
+
}, message.id));
|
|
4391
5713
|
if (renderCustomMessage) elements.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(MemoizedCustomMessage, {
|
|
4392
5714
|
message,
|
|
4393
5715
|
position: "after",
|
|
4394
5716
|
renderCustomMessage,
|
|
4395
5717
|
stateSnapshot
|
|
4396
5718
|
}, `${message.id}-custom-after`));
|
|
4397
|
-
return elements;
|
|
4398
|
-
}
|
|
5719
|
+
return elements.filter(Boolean);
|
|
5720
|
+
};
|
|
5721
|
+
const messageElements = shouldVirtualize ? [] : deduplicatedMessages.flatMap(renderMessageBlock);
|
|
4399
5722
|
if (children) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4400
5723
|
"data-copilotkit": true,
|
|
4401
5724
|
style: { display: "contents" },
|
|
@@ -4409,27 +5732,353 @@ function CopilotChatMessageView({ messages = [], assistantMessage, userMessage,
|
|
|
4409
5732
|
const lastMessage = messages[messages.length - 1];
|
|
4410
5733
|
const showCursor = isRunning && lastMessage?.role !== "reasoning";
|
|
4411
5734
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4412
|
-
"data-copilotkit": true,
|
|
4413
|
-
"data-testid": "copilot-message-list",
|
|
4414
|
-
className: (0, tailwind_merge.twMerge)("copilotKitMessages cpk:flex cpk:flex-col", className),
|
|
4415
|
-
...props,
|
|
5735
|
+
"data-copilotkit": true,
|
|
5736
|
+
"data-testid": "copilot-message-list",
|
|
5737
|
+
className: (0, tailwind_merge.twMerge)("copilotKitMessages cpk:flex cpk:flex-col", className),
|
|
5738
|
+
...props,
|
|
5739
|
+
children: [
|
|
5740
|
+
shouldVirtualize ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
5741
|
+
style: {
|
|
5742
|
+
height: virtualizer.getTotalSize(),
|
|
5743
|
+
position: "relative"
|
|
5744
|
+
},
|
|
5745
|
+
children: virtualizer.getVirtualItems().map((virtualItem) => {
|
|
5746
|
+
const message = deduplicatedMessages[virtualItem.index];
|
|
5747
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
5748
|
+
"data-index": virtualItem.index,
|
|
5749
|
+
ref: virtualizer.measureElement,
|
|
5750
|
+
style: {
|
|
5751
|
+
position: "absolute",
|
|
5752
|
+
top: 0,
|
|
5753
|
+
left: 0,
|
|
5754
|
+
width: "100%",
|
|
5755
|
+
transform: `translateY(${virtualItem.start}px)`
|
|
5756
|
+
},
|
|
5757
|
+
children: renderMessageBlock(message)
|
|
5758
|
+
}, message.id);
|
|
5759
|
+
})
|
|
5760
|
+
}) : messageElements,
|
|
5761
|
+
interruptElement,
|
|
5762
|
+
showCursor && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
5763
|
+
className: "cpk:mt-2",
|
|
5764
|
+
children: renderSlot(cursor, CopilotChatMessageView.Cursor, {})
|
|
5765
|
+
})
|
|
5766
|
+
]
|
|
5767
|
+
});
|
|
5768
|
+
}
|
|
5769
|
+
CopilotChatMessageView.Cursor = function Cursor({ className, ...props }) {
|
|
5770
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
5771
|
+
"data-testid": "copilot-loading-cursor",
|
|
5772
|
+
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),
|
|
5773
|
+
...props
|
|
5774
|
+
});
|
|
5775
|
+
};
|
|
5776
|
+
|
|
5777
|
+
//#endregion
|
|
5778
|
+
//#region src/v2/components/chat/CopilotChatAttachmentQueue.tsx
|
|
5779
|
+
const CopilotChatAttachmentQueue = ({ attachments, onRemoveAttachment, className }) => {
|
|
5780
|
+
if (attachments.length === 0) return null;
|
|
5781
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
5782
|
+
className: cn("cpk:flex cpk:flex-wrap cpk:gap-2 cpk:p-2", className),
|
|
5783
|
+
children: attachments.map((attachment) => {
|
|
5784
|
+
const isMedia = attachment.type === "image" || attachment.type === "video";
|
|
5785
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
5786
|
+
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]"),
|
|
5787
|
+
children: [
|
|
5788
|
+
attachment.status === "uploading" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(UploadingOverlay, {}),
|
|
5789
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(AttachmentPreview, { attachment }),
|
|
5790
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
5791
|
+
onClick: () => onRemoveAttachment(attachment.id),
|
|
5792
|
+
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"),
|
|
5793
|
+
"aria-label": "Remove attachment",
|
|
5794
|
+
children: "✕"
|
|
5795
|
+
})
|
|
5796
|
+
]
|
|
5797
|
+
}, attachment.id);
|
|
5798
|
+
})
|
|
5799
|
+
});
|
|
5800
|
+
};
|
|
5801
|
+
function UploadingOverlay() {
|
|
5802
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
5803
|
+
className: "cpk:absolute cpk:inset-0 cpk:flex cpk:items-center cpk:justify-center cpk:bg-black/40 cpk:z-10",
|
|
5804
|
+
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" })
|
|
5805
|
+
});
|
|
5806
|
+
}
|
|
5807
|
+
function AttachmentPreview({ attachment }) {
|
|
5808
|
+
if (attachment.status === "uploading") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: "cpk:w-full cpk:h-full" });
|
|
5809
|
+
switch (attachment.type) {
|
|
5810
|
+
case "image": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ImagePreview, { attachment });
|
|
5811
|
+
case "audio": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AudioPreview, { attachment });
|
|
5812
|
+
case "video": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(VideoPreview, { attachment });
|
|
5813
|
+
case "document": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DocumentPreview, { attachment });
|
|
5814
|
+
}
|
|
5815
|
+
}
|
|
5816
|
+
function Lightbox({ onClose, children }) {
|
|
5817
|
+
(0, react.useEffect)(() => {
|
|
5818
|
+
const handleKey = (e) => {
|
|
5819
|
+
if (e.key === "Escape") onClose();
|
|
5820
|
+
};
|
|
5821
|
+
document.addEventListener("keydown", handleKey);
|
|
5822
|
+
return () => document.removeEventListener("keydown", handleKey);
|
|
5823
|
+
}, [onClose]);
|
|
5824
|
+
if (typeof document === "undefined") return null;
|
|
5825
|
+
return (0, react_dom.createPortal)(/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
5826
|
+
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",
|
|
5827
|
+
onClick: onClose,
|
|
5828
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
5829
|
+
onClick: onClose,
|
|
5830
|
+
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",
|
|
5831
|
+
"aria-label": "Close preview",
|
|
5832
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.X, { className: "cpk:w-5 cpk:h-5" })
|
|
5833
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
5834
|
+
onClick: (e) => e.stopPropagation(),
|
|
5835
|
+
children
|
|
5836
|
+
})]
|
|
5837
|
+
}), document.body);
|
|
5838
|
+
}
|
|
5839
|
+
/**
|
|
5840
|
+
* Hook that manages lightbox open/close and uses the View Transition API to
|
|
5841
|
+
* morph the thumbnail into fullscreen content.
|
|
5842
|
+
*
|
|
5843
|
+
* The trick: `view-transition-name` must live on exactly ONE element at a time.
|
|
5844
|
+
* - Old state (thumbnail visible): name is on the thumbnail.
|
|
5845
|
+
* - New state (lightbox visible): name moves to the lightbox content.
|
|
5846
|
+
* `flushSync` ensures React commits the DOM change synchronously inside the
|
|
5847
|
+
* `startViewTransition` callback so the API can snapshot old → new correctly.
|
|
5848
|
+
*/
|
|
5849
|
+
function useLightbox() {
|
|
5850
|
+
const thumbnailRef = (0, react.useRef)(null);
|
|
5851
|
+
const [open, setOpen] = (0, react.useState)(false);
|
|
5852
|
+
const vtName = (0, react.useId)();
|
|
5853
|
+
return {
|
|
5854
|
+
thumbnailRef,
|
|
5855
|
+
vtName,
|
|
5856
|
+
open,
|
|
5857
|
+
openLightbox: (0, react.useCallback)(() => {
|
|
5858
|
+
const thumb = thumbnailRef.current;
|
|
5859
|
+
const doc = document;
|
|
5860
|
+
if (doc.startViewTransition && thumb) {
|
|
5861
|
+
thumb.style.viewTransitionName = vtName;
|
|
5862
|
+
doc.startViewTransition(() => {
|
|
5863
|
+
thumb.style.viewTransitionName = "";
|
|
5864
|
+
(0, react_dom.flushSync)(() => setOpen(true));
|
|
5865
|
+
});
|
|
5866
|
+
} else setOpen(true);
|
|
5867
|
+
}, []),
|
|
5868
|
+
closeLightbox: (0, react.useCallback)(() => {
|
|
5869
|
+
const thumb = thumbnailRef.current;
|
|
5870
|
+
const doc = document;
|
|
5871
|
+
if (doc.startViewTransition && thumb) doc.startViewTransition(() => {
|
|
5872
|
+
(0, react_dom.flushSync)(() => setOpen(false));
|
|
5873
|
+
thumb.style.viewTransitionName = vtName;
|
|
5874
|
+
}).finished.then(() => {
|
|
5875
|
+
thumb.style.viewTransitionName = "";
|
|
5876
|
+
}).catch(() => {
|
|
5877
|
+
thumb.style.viewTransitionName = "";
|
|
5878
|
+
});
|
|
5879
|
+
else setOpen(false);
|
|
5880
|
+
}, [])
|
|
5881
|
+
};
|
|
5882
|
+
}
|
|
5883
|
+
function ImagePreview({ attachment }) {
|
|
5884
|
+
const src = (0, _copilotkit_shared.getSourceUrl)(attachment.source);
|
|
5885
|
+
const { thumbnailRef, vtName, open, openLightbox, closeLightbox } = useLightbox();
|
|
5886
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
|
|
5887
|
+
ref: thumbnailRef,
|
|
5888
|
+
src,
|
|
5889
|
+
alt: attachment.filename || "Image attachment",
|
|
5890
|
+
className: "cpk:w-full cpk:h-full cpk:object-cover cpk:cursor-pointer",
|
|
5891
|
+
onClick: openLightbox
|
|
5892
|
+
}), open && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Lightbox, {
|
|
5893
|
+
onClose: closeLightbox,
|
|
5894
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
|
|
5895
|
+
style: { viewTransitionName: vtName },
|
|
5896
|
+
src,
|
|
5897
|
+
alt: attachment.filename || "Image attachment",
|
|
5898
|
+
className: "cpk:max-w-[90vw] cpk:max-h-[90vh] cpk:object-contain cpk:rounded-lg"
|
|
5899
|
+
})
|
|
5900
|
+
})] });
|
|
5901
|
+
}
|
|
5902
|
+
function AudioPreview({ attachment }) {
|
|
5903
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
5904
|
+
className: "cpk:flex cpk:flex-col cpk:gap-1 cpk:w-full",
|
|
5905
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("audio", {
|
|
5906
|
+
src: (0, _copilotkit_shared.getSourceUrl)(attachment.source),
|
|
5907
|
+
controls: true,
|
|
5908
|
+
preload: "metadata",
|
|
5909
|
+
className: "cpk:w-full cpk:h-8"
|
|
5910
|
+
}), attachment.filename && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
5911
|
+
className: "cpk:text-xs cpk:font-medium cpk:overflow-hidden cpk:text-ellipsis cpk:whitespace-nowrap",
|
|
5912
|
+
children: attachment.filename
|
|
5913
|
+
})]
|
|
5914
|
+
});
|
|
5915
|
+
}
|
|
5916
|
+
function VideoPreview({ attachment }) {
|
|
5917
|
+
const src = (0, _copilotkit_shared.getSourceUrl)(attachment.source);
|
|
5918
|
+
const { thumbnailRef, vtName, open, openLightbox, closeLightbox } = useLightbox();
|
|
5919
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
5920
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
5921
|
+
ref: thumbnailRef,
|
|
5922
|
+
className: "cpk:w-full cpk:h-full",
|
|
5923
|
+
children: attachment.thumbnail ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
|
|
5924
|
+
src: attachment.thumbnail,
|
|
5925
|
+
alt: attachment.filename || "Video thumbnail",
|
|
5926
|
+
className: "cpk:w-full cpk:h-full cpk:object-cover"
|
|
5927
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("video", {
|
|
5928
|
+
src,
|
|
5929
|
+
preload: "metadata",
|
|
5930
|
+
muted: true,
|
|
5931
|
+
className: "cpk:w-full cpk:h-full cpk:object-cover"
|
|
5932
|
+
})
|
|
5933
|
+
}),
|
|
5934
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
5935
|
+
onClick: openLightbox,
|
|
5936
|
+
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",
|
|
5937
|
+
"aria-label": "Play video",
|
|
5938
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
5939
|
+
className: "cpk:w-8 cpk:h-8 cpk:rounded-full cpk:bg-black/60 cpk:flex cpk:items-center cpk:justify-center",
|
|
5940
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Play, { className: "cpk:w-4 cpk:h-4 cpk:text-white cpk:ml-0.5" })
|
|
5941
|
+
})
|
|
5942
|
+
}),
|
|
5943
|
+
open && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Lightbox, {
|
|
5944
|
+
onClose: closeLightbox,
|
|
5945
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("video", {
|
|
5946
|
+
style: { viewTransitionName: vtName },
|
|
5947
|
+
src,
|
|
5948
|
+
controls: true,
|
|
5949
|
+
autoPlay: true,
|
|
5950
|
+
className: "cpk:max-w-[90vw] cpk:max-h-[90vh] cpk:rounded-lg"
|
|
5951
|
+
})
|
|
5952
|
+
})
|
|
5953
|
+
] });
|
|
5954
|
+
}
|
|
5955
|
+
function isPdf(mimeType) {
|
|
5956
|
+
return !!mimeType && mimeType.includes("pdf");
|
|
5957
|
+
}
|
|
5958
|
+
function isText(mimeType) {
|
|
5959
|
+
return !!mimeType && mimeType.startsWith("text/");
|
|
5960
|
+
}
|
|
5961
|
+
function canPreviewInBrowser(mimeType) {
|
|
5962
|
+
return isPdf(mimeType) || isText(mimeType);
|
|
5963
|
+
}
|
|
5964
|
+
/**
|
|
5965
|
+
* Convert a base64-encoded data source to a blob: URL that browsers will
|
|
5966
|
+
* render inside an iframe (data: URLs are blocked for PDFs in most browsers).
|
|
5967
|
+
*/
|
|
5968
|
+
function useBlobUrl(attachment) {
|
|
5969
|
+
const [url, setUrl] = (0, react.useState)(null);
|
|
5970
|
+
(0, react.useEffect)(() => {
|
|
5971
|
+
if (attachment.source.type !== "data") return;
|
|
5972
|
+
try {
|
|
5973
|
+
const binary = atob(attachment.source.value);
|
|
5974
|
+
const bytes = new Uint8Array(binary.length);
|
|
5975
|
+
for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
|
|
5976
|
+
const blob = new Blob([bytes], { type: attachment.source.mimeType || "application/octet-stream" });
|
|
5977
|
+
const blobUrl = URL.createObjectURL(blob);
|
|
5978
|
+
setUrl(blobUrl);
|
|
5979
|
+
return () => URL.revokeObjectURL(blobUrl);
|
|
5980
|
+
} catch (error) {
|
|
5981
|
+
console.error("[CopilotKit] Failed to decode attachment data:", error);
|
|
5982
|
+
setUrl(null);
|
|
5983
|
+
}
|
|
5984
|
+
}, [
|
|
5985
|
+
attachment.source.type,
|
|
5986
|
+
attachment.source.value,
|
|
5987
|
+
attachment.source.mimeType
|
|
5988
|
+
]);
|
|
5989
|
+
if (attachment.source.type === "url") return attachment.source.value;
|
|
5990
|
+
return url;
|
|
5991
|
+
}
|
|
5992
|
+
function DocumentLightboxContent({ attachment, vtName }) {
|
|
5993
|
+
const mimeType = attachment.source.mimeType;
|
|
5994
|
+
const blobUrl = useBlobUrl(attachment);
|
|
5995
|
+
if (isPdf(mimeType)) {
|
|
5996
|
+
if (!blobUrl) return null;
|
|
5997
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("iframe", {
|
|
5998
|
+
style: { viewTransitionName: vtName },
|
|
5999
|
+
src: blobUrl,
|
|
6000
|
+
title: attachment.filename || "PDF preview",
|
|
6001
|
+
className: "cpk:w-[90vw] cpk:h-[90vh] cpk:max-w-[1000px] cpk:rounded-lg cpk:bg-white"
|
|
6002
|
+
});
|
|
6003
|
+
}
|
|
6004
|
+
if (isText(mimeType)) {
|
|
6005
|
+
const textContent = attachment.source.type === "data" ? (() => {
|
|
6006
|
+
try {
|
|
6007
|
+
return atob(attachment.source.value);
|
|
6008
|
+
} catch {
|
|
6009
|
+
return attachment.source.value;
|
|
6010
|
+
}
|
|
6011
|
+
})() : null;
|
|
6012
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6013
|
+
style: { viewTransitionName: vtName },
|
|
6014
|
+
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",
|
|
6015
|
+
children: [attachment.filename && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6016
|
+
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",
|
|
6017
|
+
children: attachment.filename
|
|
6018
|
+
}), textContent ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", {
|
|
6019
|
+
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",
|
|
6020
|
+
children: textContent
|
|
6021
|
+
}) : blobUrl ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("iframe", {
|
|
6022
|
+
src: blobUrl,
|
|
6023
|
+
title: attachment.filename || "Text preview",
|
|
6024
|
+
className: "cpk:w-full cpk:h-[80vh] cpk:border-none"
|
|
6025
|
+
}) : null]
|
|
6026
|
+
});
|
|
6027
|
+
}
|
|
6028
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6029
|
+
style: { viewTransitionName: vtName },
|
|
6030
|
+
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",
|
|
4416
6031
|
children: [
|
|
4417
|
-
|
|
4418
|
-
|
|
4419
|
-
|
|
4420
|
-
|
|
4421
|
-
|
|
6032
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6033
|
+
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",
|
|
6034
|
+
children: (0, _copilotkit_shared.getDocumentIcon)(mimeType ?? "")
|
|
6035
|
+
}),
|
|
6036
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6037
|
+
className: "cpk:text-center",
|
|
6038
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6039
|
+
className: "cpk:text-base cpk:font-medium cpk:text-gray-800 cpk:dark:text-gray-200",
|
|
6040
|
+
children: attachment.filename || "Document"
|
|
6041
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6042
|
+
className: "cpk:text-sm cpk:text-gray-500 cpk:dark:text-gray-400 cpk:mt-1",
|
|
6043
|
+
children: [mimeType || "Unknown type", attachment.size != null && ` · ${(0, _copilotkit_shared.formatFileSize)(attachment.size)}`]
|
|
6044
|
+
})]
|
|
6045
|
+
}),
|
|
6046
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6047
|
+
className: "cpk:text-xs cpk:text-gray-400 cpk:dark:text-gray-500",
|
|
6048
|
+
children: "No preview available for this file type"
|
|
4422
6049
|
})
|
|
4423
6050
|
]
|
|
4424
6051
|
});
|
|
4425
6052
|
}
|
|
4426
|
-
|
|
4427
|
-
|
|
4428
|
-
|
|
4429
|
-
|
|
4430
|
-
|
|
4431
|
-
|
|
4432
|
-
|
|
6053
|
+
function DocumentPreview({ attachment }) {
|
|
6054
|
+
const { thumbnailRef, vtName, open, openLightbox, closeLightbox } = useLightbox();
|
|
6055
|
+
const mimeType = attachment.source.mimeType;
|
|
6056
|
+
const previewable = canPreviewInBrowser(mimeType);
|
|
6057
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6058
|
+
ref: thumbnailRef,
|
|
6059
|
+
className: cn("cpk:flex cpk:items-center cpk:gap-2", previewable && "cpk:cursor-pointer"),
|
|
6060
|
+
onClick: previewable ? openLightbox : void 0,
|
|
6061
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6062
|
+
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",
|
|
6063
|
+
children: (0, _copilotkit_shared.getDocumentIcon)(mimeType ?? "")
|
|
6064
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6065
|
+
className: "cpk:flex cpk:flex-col cpk:min-w-0",
|
|
6066
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6067
|
+
className: "cpk:text-xs cpk:font-medium cpk:break-all cpk:leading-tight",
|
|
6068
|
+
children: attachment.filename || "Document"
|
|
6069
|
+
}), attachment.size != null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6070
|
+
className: "cpk:text-[11px] cpk:text-muted-foreground",
|
|
6071
|
+
children: (0, _copilotkit_shared.formatFileSize)(attachment.size)
|
|
6072
|
+
})]
|
|
6073
|
+
})]
|
|
6074
|
+
}), open && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Lightbox, {
|
|
6075
|
+
onClose: closeLightbox,
|
|
6076
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DocumentLightboxContent, {
|
|
6077
|
+
attachment,
|
|
6078
|
+
vtName
|
|
6079
|
+
})
|
|
6080
|
+
})] });
|
|
6081
|
+
}
|
|
4433
6082
|
|
|
4434
6083
|
//#endregion
|
|
4435
6084
|
//#region src/v2/hooks/use-keyboard-height.tsx
|
|
@@ -4475,7 +6124,19 @@ function useKeyboardHeight() {
|
|
|
4475
6124
|
//#endregion
|
|
4476
6125
|
//#region src/v2/components/chat/CopilotChatView.tsx
|
|
4477
6126
|
const FEATHER_HEIGHT = 96;
|
|
4478
|
-
function
|
|
6127
|
+
function DropOverlay() {
|
|
6128
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6129
|
+
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"),
|
|
6130
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6131
|
+
className: "cpk:flex cpk:flex-col cpk:items-center cpk:gap-2 cpk:text-primary/70",
|
|
6132
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Upload, { className: "cpk:w-8 cpk:h-8" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6133
|
+
className: "cpk:text-sm cpk:font-medium",
|
|
6134
|
+
children: "Drop files here"
|
|
6135
|
+
})]
|
|
6136
|
+
})
|
|
6137
|
+
});
|
|
6138
|
+
}
|
|
6139
|
+
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 }) {
|
|
4479
6140
|
const inputContainerRef = (0, react.useRef)(null);
|
|
4480
6141
|
const [inputContainerHeight, setInputContainerHeight] = (0, react.useState)(0);
|
|
4481
6142
|
const [isResizing, setIsResizing] = (0, react.useState)(false);
|
|
@@ -4522,6 +6183,7 @@ function CopilotChatView({ messageView, input, scrollView, suggestionView, welco
|
|
|
4522
6183
|
onCancelTranscribe,
|
|
4523
6184
|
onFinishTranscribe,
|
|
4524
6185
|
onFinishTranscribeWithAudio,
|
|
6186
|
+
onAddFile,
|
|
4525
6187
|
positioning: "static",
|
|
4526
6188
|
keyboardHeight: isKeyboardOpen ? keyboardHeight : 0,
|
|
4527
6189
|
containerRef: inputContainerRef,
|
|
@@ -4562,21 +6224,34 @@ function CopilotChatView({ messageView, input, scrollView, suggestionView, welco
|
|
|
4562
6224
|
onCancelTranscribe,
|
|
4563
6225
|
onFinishTranscribe,
|
|
4564
6226
|
onFinishTranscribeWithAudio,
|
|
6227
|
+
onAddFile,
|
|
4565
6228
|
positioning: "static",
|
|
4566
6229
|
showDisclaimer: true,
|
|
4567
6230
|
...disclaimer !== void 0 ? { disclaimer } : {}
|
|
4568
6231
|
});
|
|
4569
|
-
const
|
|
4570
|
-
|
|
6232
|
+
const welcomeScreenSlot = welcomeScreen === true ? void 0 : welcomeScreen;
|
|
6233
|
+
const inputWithAttachments = /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6234
|
+
className: "cpk:w-full",
|
|
6235
|
+
children: [attachments && attachments.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopilotChatAttachmentQueue, {
|
|
6236
|
+
attachments,
|
|
6237
|
+
onRemoveAttachment: (id) => onRemoveAttachment?.(id),
|
|
6238
|
+
className: "cpk:mb-2"
|
|
6239
|
+
}), BoundInputForWelcome]
|
|
6240
|
+
});
|
|
6241
|
+
const BoundWelcomeScreen = renderSlot(welcomeScreenSlot, CopilotChatView.WelcomeScreen, {
|
|
6242
|
+
input: inputWithAttachments,
|
|
4571
6243
|
suggestionView: BoundSuggestionView ?? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, {})
|
|
4572
6244
|
});
|
|
4573
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.
|
|
6245
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4574
6246
|
"data-copilotkit": true,
|
|
4575
6247
|
"data-testid": "copilot-chat",
|
|
4576
6248
|
"data-copilot-running": isRunning ? "true" : "false",
|
|
4577
|
-
|
|
6249
|
+
onDragOver,
|
|
6250
|
+
onDragLeave,
|
|
6251
|
+
onDrop,
|
|
6252
|
+
className: cn("copilotKitChat cpk:relative cpk:h-full cpk:flex cpk:flex-col", className),
|
|
4578
6253
|
...props,
|
|
4579
|
-
children: BoundWelcomeScreen
|
|
6254
|
+
children: [dragOver && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DropOverlay, {}), BoundWelcomeScreen]
|
|
4580
6255
|
});
|
|
4581
6256
|
}
|
|
4582
6257
|
if (children) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
@@ -4593,39 +6268,66 @@ function CopilotChatView({ messageView, input, scrollView, suggestionView, welco
|
|
|
4593
6268
|
"data-copilotkit": true,
|
|
4594
6269
|
"data-testid": "copilot-chat",
|
|
4595
6270
|
"data-copilot-running": isRunning ? "true" : "false",
|
|
4596
|
-
|
|
6271
|
+
onDragOver,
|
|
6272
|
+
onDragLeave,
|
|
6273
|
+
onDrop,
|
|
6274
|
+
className: cn("copilotKitChat cpk:relative cpk:h-full cpk:flex cpk:flex-col", className),
|
|
4597
6275
|
...props,
|
|
4598
|
-
children: [
|
|
6276
|
+
children: [
|
|
6277
|
+
dragOver && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DropOverlay, {}),
|
|
6278
|
+
BoundScrollView,
|
|
6279
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6280
|
+
className: "cpk:max-w-3xl cpk:mx-auto cpk:w-full",
|
|
6281
|
+
children: attachments && attachments.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopilotChatAttachmentQueue, {
|
|
6282
|
+
attachments,
|
|
6283
|
+
onRemoveAttachment: (id) => onRemoveAttachment?.(id),
|
|
6284
|
+
className: "cpk:px-4"
|
|
6285
|
+
})
|
|
6286
|
+
}),
|
|
6287
|
+
BoundInput
|
|
6288
|
+
]
|
|
4599
6289
|
});
|
|
4600
6290
|
}
|
|
4601
6291
|
(function(_CopilotChatView) {
|
|
4602
6292
|
const ScrollContent = ({ children, scrollToBottomButton, feather, inputContainerHeight, isResizing }) => {
|
|
4603
|
-
const { isAtBottom, scrollToBottom } = (0, use_stick_to_bottom.useStickToBottomContext)();
|
|
6293
|
+
const { isAtBottom, scrollToBottom, scrollRef } = (0, use_stick_to_bottom.useStickToBottomContext)();
|
|
6294
|
+
const [scrollEl, setScrollEl] = (0, react.useState)(null);
|
|
6295
|
+
(0, react.useLayoutEffect)(() => {
|
|
6296
|
+
setScrollEl(scrollRef.current ?? null);
|
|
6297
|
+
}, []);
|
|
4604
6298
|
const BoundFeather = renderSlot(feather, CopilotChatView.Feather, {});
|
|
4605
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.
|
|
4606
|
-
|
|
4607
|
-
|
|
4608
|
-
|
|
4609
|
-
|
|
4610
|
-
|
|
4611
|
-
|
|
4612
|
-
|
|
4613
|
-
|
|
4614
|
-
children
|
|
6299
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ScrollElementContext.Provider, {
|
|
6300
|
+
value: scrollEl,
|
|
6301
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
6302
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(use_stick_to_bottom.StickToBottom.Content, {
|
|
6303
|
+
className: "cpk:overflow-y-auto cpk:overflow-x-hidden",
|
|
6304
|
+
style: {
|
|
6305
|
+
flex: "1 1 0%",
|
|
6306
|
+
minHeight: 0
|
|
6307
|
+
},
|
|
6308
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6309
|
+
className: "cpk:px-4 cpk:sm:px-0 cpk:[div[data-sidebar-chat]_&]:px-8 cpk:[div[data-popup-chat]_&]:px-6",
|
|
6310
|
+
children
|
|
6311
|
+
})
|
|
6312
|
+
}),
|
|
6313
|
+
BoundFeather,
|
|
6314
|
+
!isAtBottom && !isResizing && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6315
|
+
className: "cpk:absolute cpk:inset-x-0 cpk:flex cpk:justify-center cpk:z-30 cpk:pointer-events-none",
|
|
6316
|
+
style: { bottom: `${inputContainerHeight + FEATHER_HEIGHT + 16}px` },
|
|
6317
|
+
children: renderSlot(scrollToBottomButton, CopilotChatView.ScrollToBottomButton, { onClick: () => scrollToBottom() })
|
|
4615
6318
|
})
|
|
4616
|
-
})
|
|
4617
|
-
|
|
4618
|
-
!isAtBottom && !isResizing && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4619
|
-
className: "cpk:absolute cpk:inset-x-0 cpk:flex cpk:justify-center cpk:z-30 cpk:pointer-events-none",
|
|
4620
|
-
style: { bottom: `${inputContainerHeight + FEATHER_HEIGHT + 16}px` },
|
|
4621
|
-
children: renderSlot(scrollToBottomButton, CopilotChatView.ScrollToBottomButton, { onClick: () => scrollToBottom() })
|
|
4622
|
-
})
|
|
4623
|
-
] });
|
|
6319
|
+
] })
|
|
6320
|
+
});
|
|
4624
6321
|
};
|
|
4625
6322
|
_CopilotChatView.ScrollView = ({ children, autoScroll = true, scrollToBottomButton, feather, inputContainerHeight = 0, isResizing = false, className, ...props }) => {
|
|
4626
6323
|
const [hasMounted, setHasMounted] = (0, react.useState)(false);
|
|
4627
6324
|
const { scrollRef, contentRef, scrollToBottom } = (0, use_stick_to_bottom.useStickToBottom)();
|
|
4628
6325
|
const [showScrollButton, setShowScrollButton] = (0, react.useState)(false);
|
|
6326
|
+
const [nonAutoScrollEl, setNonAutoScrollEl] = (0, react.useState)(null);
|
|
6327
|
+
const nonAutoScrollRefCallback = (0, react.useCallback)((el) => {
|
|
6328
|
+
scrollRef.current = el;
|
|
6329
|
+
setNonAutoScrollEl(el);
|
|
6330
|
+
}, []);
|
|
4629
6331
|
(0, react.useEffect)(() => {
|
|
4630
6332
|
setHasMounted(true);
|
|
4631
6333
|
}, []);
|
|
@@ -4654,23 +6356,26 @@ function CopilotChatView({ messageView, input, scrollView, suggestionView, welco
|
|
|
4654
6356
|
});
|
|
4655
6357
|
if (!autoScroll) {
|
|
4656
6358
|
const BoundFeather = renderSlot(feather, CopilotChatView.Feather, {});
|
|
4657
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.
|
|
4658
|
-
|
|
4659
|
-
|
|
4660
|
-
|
|
4661
|
-
|
|
4662
|
-
|
|
4663
|
-
|
|
4664
|
-
|
|
4665
|
-
|
|
4666
|
-
|
|
4667
|
-
|
|
4668
|
-
|
|
4669
|
-
|
|
4670
|
-
|
|
4671
|
-
|
|
4672
|
-
|
|
4673
|
-
|
|
6359
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ScrollElementContext.Provider, {
|
|
6360
|
+
value: nonAutoScrollEl,
|
|
6361
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6362
|
+
ref: nonAutoScrollRefCallback,
|
|
6363
|
+
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),
|
|
6364
|
+
...props,
|
|
6365
|
+
children: [
|
|
6366
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6367
|
+
ref: contentRef,
|
|
6368
|
+
className: "cpk:px-4 cpk:sm:px-0 cpk:[div[data-sidebar-chat]_&]:px-8 cpk:[div[data-popup-chat]_&]:px-6",
|
|
6369
|
+
children
|
|
6370
|
+
}),
|
|
6371
|
+
BoundFeather,
|
|
6372
|
+
showScrollButton && !isResizing && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6373
|
+
className: "cpk:absolute cpk:inset-x-0 cpk:flex cpk:justify-center cpk:z-30 cpk:pointer-events-none",
|
|
6374
|
+
style: { bottom: `${inputContainerHeight + FEATHER_HEIGHT + 16}px` },
|
|
6375
|
+
children: renderSlot(scrollToBottomButton, CopilotChatView.ScrollToBottomButton, { onClick: () => scrollToBottom() })
|
|
6376
|
+
})
|
|
6377
|
+
]
|
|
6378
|
+
})
|
|
4674
6379
|
});
|
|
4675
6380
|
}
|
|
4676
6381
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(use_stick_to_bottom.StickToBottom, {
|
|
@@ -4862,13 +6567,14 @@ async function transcribeAudio(core, audioBlob, filename = "recording.webm") {
|
|
|
4862
6567
|
|
|
4863
6568
|
//#endregion
|
|
4864
6569
|
//#region src/v2/components/chat/CopilotChat.tsx
|
|
4865
|
-
function CopilotChat({ agentId, threadId, labels, chatView, isModalDefaultOpen, onError, ...props }) {
|
|
6570
|
+
function CopilotChat({ agentId, threadId, labels, chatView, isModalDefaultOpen, attachments: attachmentsConfig, onError, throttleMs, ...props }) {
|
|
4866
6571
|
const existingConfig = useCopilotChatConfiguration();
|
|
4867
6572
|
const resolvedAgentId = agentId ?? existingConfig?.agentId ?? _copilotkit_shared.DEFAULT_AGENT_ID;
|
|
4868
6573
|
const resolvedThreadId = (0, react.useMemo)(() => threadId ?? existingConfig?.threadId ?? (0, _copilotkit_shared.randomUUID)(), [threadId, existingConfig?.threadId]);
|
|
4869
6574
|
const { agent } = useAgent({
|
|
4870
6575
|
agentId: resolvedAgentId,
|
|
4871
|
-
threadId: resolvedThreadId
|
|
6576
|
+
threadId: resolvedThreadId,
|
|
6577
|
+
throttleMs
|
|
4872
6578
|
});
|
|
4873
6579
|
const { copilotkit } = useCopilotKit();
|
|
4874
6580
|
const { suggestions: autoSuggestions } = useSuggestions({ agentId: resolvedAgentId });
|
|
@@ -4898,6 +6604,7 @@ function CopilotChat({ agentId, threadId, labels, chatView, isModalDefaultOpen,
|
|
|
4898
6604
|
const [inputValue, setInputValue] = (0, react.useState)("");
|
|
4899
6605
|
const [transcriptionError, setTranscriptionError] = (0, react.useState)(null);
|
|
4900
6606
|
const [isTranscribing, setIsTranscribing] = (0, react.useState)(false);
|
|
6607
|
+
const { attachments: selectedAttachments, enabled: attachmentsEnabled, dragOver, fileInputRef, containerRef: chatContainerRef, handleFileUpload, handleDragOver, handleDragLeave, handleDrop, removeAttachment, consumeAttachments } = useAttachments({ config: attachmentsConfig });
|
|
4901
6608
|
const isTranscriptionEnabled = copilotkit.audioFileTranscriptionEnabled;
|
|
4902
6609
|
const isMediaRecorderSupported = typeof window !== "undefined" && typeof MediaRecorder !== "undefined";
|
|
4903
6610
|
const { messageView: providedMessageView, suggestionView: providedSuggestionView, onStop: providedStopHandler, ...restProps } = props;
|
|
@@ -4925,7 +6632,31 @@ function CopilotChat({ agentId, threadId, labels, chatView, isModalDefaultOpen,
|
|
|
4925
6632
|
resolvedAgentId
|
|
4926
6633
|
]);
|
|
4927
6634
|
const onSubmitInput = (0, react.useCallback)(async (value) => {
|
|
4928
|
-
|
|
6635
|
+
if (selectedAttachments.some((a) => a.status === "uploading")) {
|
|
6636
|
+
console.error("[CopilotKit] Cannot send while attachments are uploading");
|
|
6637
|
+
return;
|
|
6638
|
+
}
|
|
6639
|
+
const readyAttachments = consumeAttachments();
|
|
6640
|
+
if (readyAttachments.length > 0) {
|
|
6641
|
+
const contentParts = [];
|
|
6642
|
+
if (value.trim()) contentParts.push({
|
|
6643
|
+
type: "text",
|
|
6644
|
+
text: value
|
|
6645
|
+
});
|
|
6646
|
+
for (const att of readyAttachments) contentParts.push({
|
|
6647
|
+
type: att.type,
|
|
6648
|
+
source: att.source,
|
|
6649
|
+
metadata: {
|
|
6650
|
+
...att.filename ? { filename: att.filename } : {},
|
|
6651
|
+
...att.metadata
|
|
6652
|
+
}
|
|
6653
|
+
});
|
|
6654
|
+
agent.addMessage({
|
|
6655
|
+
id: (0, _copilotkit_shared.randomUUID)(),
|
|
6656
|
+
role: "user",
|
|
6657
|
+
content: contentParts
|
|
6658
|
+
});
|
|
6659
|
+
} else agent.addMessage({
|
|
4929
6660
|
id: (0, _copilotkit_shared.randomUUID)(),
|
|
4930
6661
|
role: "user",
|
|
4931
6662
|
content: value
|
|
@@ -4936,7 +6667,11 @@ function CopilotChat({ agentId, threadId, labels, chatView, isModalDefaultOpen,
|
|
|
4936
6667
|
} catch (error) {
|
|
4937
6668
|
console.error("CopilotChat: runAgent failed", error);
|
|
4938
6669
|
}
|
|
4939
|
-
}, [
|
|
6670
|
+
}, [
|
|
6671
|
+
agent,
|
|
6672
|
+
selectedAttachments,
|
|
6673
|
+
consumeAttachments
|
|
6674
|
+
]);
|
|
4940
6675
|
const handleSelectSuggestion = (0, react.useCallback)(async (suggestion) => {
|
|
4941
6676
|
agent.addMessage({
|
|
4942
6677
|
id: (0, _copilotkit_shared.randomUUID)(),
|
|
@@ -5023,21 +6758,33 @@ function CopilotChat({ agentId, threadId, labels, chatView, isModalDefaultOpen,
|
|
|
5023
6758
|
return () => clearTimeout(timer);
|
|
5024
6759
|
}
|
|
5025
6760
|
}, [transcriptionError]);
|
|
5026
|
-
const
|
|
6761
|
+
const stableMessageView = useShallowStableRef(typeof providedMessageView === "string" ? { className: providedMessageView } : providedMessageView);
|
|
6762
|
+
const stableSuggestionView = useShallowStableRef(providedSuggestionView);
|
|
6763
|
+
const handleAddFile = (0, react.useCallback)(() => {
|
|
6764
|
+
setTimeout(() => {
|
|
6765
|
+
fileInputRef.current?.click();
|
|
6766
|
+
}, 100);
|
|
6767
|
+
}, []);
|
|
6768
|
+
const mergedProps = {
|
|
5027
6769
|
isRunning: agent.isRunning,
|
|
5028
6770
|
suggestions: autoSuggestions,
|
|
5029
6771
|
onSelectSuggestion: handleSelectSuggestion,
|
|
5030
|
-
suggestionView:
|
|
5031
|
-
|
|
5032
|
-
|
|
5033
|
-
|
|
5034
|
-
});
|
|
6772
|
+
suggestionView: stableSuggestionView,
|
|
6773
|
+
...restProps
|
|
6774
|
+
};
|
|
6775
|
+
if (stableMessageView !== void 0) mergedProps.messageView = stableMessageView;
|
|
5035
6776
|
const hasMessages = agent.messages.length > 0;
|
|
5036
6777
|
const effectiveStopHandler = agent.isRunning && hasMessages ? providedStopHandler ?? stopCurrentRun : providedStopHandler;
|
|
5037
6778
|
const showTranscription = isTranscriptionEnabled && isMediaRecorderSupported;
|
|
5038
6779
|
const effectiveMode = isTranscribing ? "processing" : transcribeMode;
|
|
5039
|
-
const
|
|
5040
|
-
|
|
6780
|
+
const messages = (0, react.useMemo)(() => [...agent.messages], [agent.messages.map((m) => {
|
|
6781
|
+
const contentKey = typeof m.content === "string" ? m.content.length : Array.isArray(m.content) ? m.content.length : 0;
|
|
6782
|
+
const toolCallsKey = "toolCalls" in m && Array.isArray(m.toolCalls) ? m.toolCalls.map((tc) => `${tc.id}:${tc.function?.arguments?.length ?? 0}`).join(";") : "";
|
|
6783
|
+
return `${m.id}:${m.role}:${contentKey}:${toolCallsKey}`;
|
|
6784
|
+
}).join(",")]);
|
|
6785
|
+
const RenderedChatView = renderSlot(chatView, CopilotChatView, {
|
|
6786
|
+
...mergedProps,
|
|
6787
|
+
messages,
|
|
5041
6788
|
onSubmitMessage: onSubmitInput,
|
|
5042
6789
|
onStop: effectiveStopHandler,
|
|
5043
6790
|
inputMode: effectiveMode,
|
|
@@ -5046,32 +6793,51 @@ function CopilotChat({ agentId, threadId, labels, chatView, isModalDefaultOpen,
|
|
|
5046
6793
|
onStartTranscribe: showTranscription ? handleStartTranscribe : void 0,
|
|
5047
6794
|
onCancelTranscribe: showTranscription ? handleCancelTranscribe : void 0,
|
|
5048
6795
|
onFinishTranscribe: showTranscription ? handleFinishTranscribe : void 0,
|
|
5049
|
-
onFinishTranscribeWithAudio: showTranscription ? handleFinishTranscribeWithAudio : void 0
|
|
5050
|
-
|
|
5051
|
-
|
|
6796
|
+
onFinishTranscribeWithAudio: showTranscription ? handleFinishTranscribeWithAudio : void 0,
|
|
6797
|
+
attachments: selectedAttachments,
|
|
6798
|
+
onRemoveAttachment: removeAttachment,
|
|
6799
|
+
onAddFile: attachmentsEnabled ? handleAddFile : void 0,
|
|
6800
|
+
dragOver,
|
|
6801
|
+
onDragOver: handleDragOver,
|
|
6802
|
+
onDragLeave: handleDragLeave,
|
|
6803
|
+
onDrop: handleDrop
|
|
6804
|
+
});
|
|
6805
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopilotChatConfigurationProvider, {
|
|
5052
6806
|
agentId: resolvedAgentId,
|
|
5053
6807
|
threadId: resolvedThreadId,
|
|
5054
6808
|
labels,
|
|
5055
6809
|
isModalDefaultOpen,
|
|
5056
|
-
children:
|
|
5057
|
-
|
|
5058
|
-
|
|
5059
|
-
|
|
5060
|
-
|
|
5061
|
-
|
|
5062
|
-
|
|
5063
|
-
|
|
5064
|
-
|
|
5065
|
-
|
|
5066
|
-
|
|
5067
|
-
|
|
5068
|
-
|
|
5069
|
-
|
|
5070
|
-
|
|
5071
|
-
|
|
5072
|
-
|
|
5073
|
-
|
|
5074
|
-
|
|
6810
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6811
|
+
ref: chatContainerRef,
|
|
6812
|
+
style: { display: "contents" },
|
|
6813
|
+
children: [
|
|
6814
|
+
attachmentsEnabled && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
6815
|
+
type: "file",
|
|
6816
|
+
multiple: true,
|
|
6817
|
+
ref: fileInputRef,
|
|
6818
|
+
onChange: handleFileUpload,
|
|
6819
|
+
accept: attachmentsConfig?.accept ?? "*/*",
|
|
6820
|
+
style: { display: "none" }
|
|
6821
|
+
}),
|
|
6822
|
+
!isChatLicensed && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InlineFeatureWarning, { featureName: "Chat" }),
|
|
6823
|
+
transcriptionError && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6824
|
+
style: {
|
|
6825
|
+
position: "absolute",
|
|
6826
|
+
bottom: "100px",
|
|
6827
|
+
left: "50%",
|
|
6828
|
+
transform: "translateX(-50%)",
|
|
6829
|
+
backgroundColor: "#ef4444",
|
|
6830
|
+
color: "white",
|
|
6831
|
+
padding: "8px 16px",
|
|
6832
|
+
borderRadius: "8px",
|
|
6833
|
+
fontSize: "14px",
|
|
6834
|
+
zIndex: 50
|
|
6835
|
+
},
|
|
6836
|
+
children: transcriptionError
|
|
6837
|
+
}),
|
|
6838
|
+
RenderedChatView
|
|
6839
|
+
]
|
|
6840
|
+
})
|
|
5075
6841
|
});
|
|
5076
6842
|
}
|
|
5077
6843
|
(function(_CopilotChat) {
|
|
@@ -5936,6 +7702,227 @@ function useToast() {
|
|
|
5936
7702
|
if (!context) throw new Error("useToast must be used within a ToastProvider");
|
|
5937
7703
|
return context;
|
|
5938
7704
|
}
|
|
7705
|
+
function formatBannerMessage(message) {
|
|
7706
|
+
const jsonMatch = message.match(/'message':\s*'([^']+)'/);
|
|
7707
|
+
if (jsonMatch) return jsonMatch[1];
|
|
7708
|
+
let cleaned = message.split(" - ")[0];
|
|
7709
|
+
cleaned = cleaned.split(": Error code")[0];
|
|
7710
|
+
cleaned = cleaned.replace(/:\s*\d{3}$/, "");
|
|
7711
|
+
cleaned = cleaned.replace(/See more:.*$/g, "");
|
|
7712
|
+
cleaned = cleaned.trim();
|
|
7713
|
+
return cleaned || "An error occurred.";
|
|
7714
|
+
}
|
|
7715
|
+
function extractUrl(message) {
|
|
7716
|
+
const markdownMatch = /\[([^\]]+)\]\(([^)]+)\)/.exec(message);
|
|
7717
|
+
if (markdownMatch) return {
|
|
7718
|
+
url: markdownMatch[2],
|
|
7719
|
+
text: "See More"
|
|
7720
|
+
};
|
|
7721
|
+
const plainMatch = /(https?:\/\/[^\s)]+)/.exec(message);
|
|
7722
|
+
if (plainMatch) return {
|
|
7723
|
+
url: plainMatch[0].replace(/[.,;:'"]*$/, ""),
|
|
7724
|
+
text: "See More"
|
|
7725
|
+
};
|
|
7726
|
+
return null;
|
|
7727
|
+
}
|
|
7728
|
+
function BannerErrorDisplay({ bannerError, onDismiss }) {
|
|
7729
|
+
const [detailsExpanded, setDetailsExpanded] = (0, react.useState)(false);
|
|
7730
|
+
const colors = getErrorColors(getErrorSeverity(bannerError));
|
|
7731
|
+
const details = bannerError.details;
|
|
7732
|
+
const link = extractUrl(bannerError.message);
|
|
7733
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
7734
|
+
style: {
|
|
7735
|
+
position: "fixed",
|
|
7736
|
+
bottom: "20px",
|
|
7737
|
+
left: "50%",
|
|
7738
|
+
transform: "translateX(-50%)",
|
|
7739
|
+
zIndex: 9999,
|
|
7740
|
+
backgroundColor: colors.background,
|
|
7741
|
+
border: `1px solid ${colors.border}`,
|
|
7742
|
+
borderLeft: `4px solid ${colors.border}`,
|
|
7743
|
+
borderRadius: "8px",
|
|
7744
|
+
padding: "12px 16px",
|
|
7745
|
+
fontSize: "13px",
|
|
7746
|
+
boxShadow: "0 4px 12px rgba(0, 0, 0, 0.15)",
|
|
7747
|
+
backdropFilter: "blur(8px)",
|
|
7748
|
+
maxWidth: "min(90vw, 700px)",
|
|
7749
|
+
width: "100%",
|
|
7750
|
+
boxSizing: "border-box",
|
|
7751
|
+
overflow: "hidden"
|
|
7752
|
+
},
|
|
7753
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
7754
|
+
style: {
|
|
7755
|
+
display: "flex",
|
|
7756
|
+
justifyContent: "space-between",
|
|
7757
|
+
alignItems: "center",
|
|
7758
|
+
gap: "10px"
|
|
7759
|
+
},
|
|
7760
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
7761
|
+
style: {
|
|
7762
|
+
display: "flex",
|
|
7763
|
+
alignItems: "center",
|
|
7764
|
+
gap: "8px",
|
|
7765
|
+
flex: 1,
|
|
7766
|
+
minWidth: 0
|
|
7767
|
+
},
|
|
7768
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { style: {
|
|
7769
|
+
width: "12px",
|
|
7770
|
+
height: "12px",
|
|
7771
|
+
borderRadius: "50%",
|
|
7772
|
+
backgroundColor: colors.border,
|
|
7773
|
+
flexShrink: 0
|
|
7774
|
+
} }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
7775
|
+
style: {
|
|
7776
|
+
display: "flex",
|
|
7777
|
+
alignItems: "center",
|
|
7778
|
+
gap: "10px",
|
|
7779
|
+
flex: 1,
|
|
7780
|
+
minWidth: 0
|
|
7781
|
+
},
|
|
7782
|
+
children: [
|
|
7783
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
7784
|
+
style: {
|
|
7785
|
+
color: colors.text,
|
|
7786
|
+
lineHeight: "1.4",
|
|
7787
|
+
fontWeight: "400",
|
|
7788
|
+
fontSize: "13px",
|
|
7789
|
+
flex: 1,
|
|
7790
|
+
wordBreak: "break-all",
|
|
7791
|
+
overflowWrap: "break-word",
|
|
7792
|
+
maxWidth: "550px",
|
|
7793
|
+
overflow: "hidden",
|
|
7794
|
+
display: "-webkit-box",
|
|
7795
|
+
WebkitLineClamp: 10,
|
|
7796
|
+
WebkitBoxOrient: "vertical"
|
|
7797
|
+
},
|
|
7798
|
+
children: formatBannerMessage(bannerError.message)
|
|
7799
|
+
}),
|
|
7800
|
+
link && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
7801
|
+
onClick: () => window.open(link.url, "_blank", "noopener,noreferrer"),
|
|
7802
|
+
style: {
|
|
7803
|
+
background: colors.border,
|
|
7804
|
+
color: "white",
|
|
7805
|
+
border: "none",
|
|
7806
|
+
borderRadius: "5px",
|
|
7807
|
+
padding: "4px 10px",
|
|
7808
|
+
fontSize: "11px",
|
|
7809
|
+
fontWeight: "500",
|
|
7810
|
+
cursor: "pointer",
|
|
7811
|
+
transition: "all 0.2s ease",
|
|
7812
|
+
flexShrink: 0
|
|
7813
|
+
},
|
|
7814
|
+
onMouseEnter: (e) => {
|
|
7815
|
+
e.currentTarget.style.opacity = "0.9";
|
|
7816
|
+
e.currentTarget.style.transform = "translateY(-1px)";
|
|
7817
|
+
},
|
|
7818
|
+
onMouseLeave: (e) => {
|
|
7819
|
+
e.currentTarget.style.opacity = "1";
|
|
7820
|
+
e.currentTarget.style.transform = "translateY(0)";
|
|
7821
|
+
},
|
|
7822
|
+
children: link.text
|
|
7823
|
+
}),
|
|
7824
|
+
details && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
7825
|
+
onClick: () => setDetailsExpanded(!detailsExpanded),
|
|
7826
|
+
style: {
|
|
7827
|
+
background: "transparent",
|
|
7828
|
+
border: `1px solid ${colors.border}`,
|
|
7829
|
+
borderRadius: "5px",
|
|
7830
|
+
padding: "4px 10px",
|
|
7831
|
+
fontSize: "11px",
|
|
7832
|
+
fontWeight: "500",
|
|
7833
|
+
cursor: "pointer",
|
|
7834
|
+
color: colors.text,
|
|
7835
|
+
flexShrink: 0,
|
|
7836
|
+
transition: "all 0.2s ease"
|
|
7837
|
+
},
|
|
7838
|
+
onMouseEnter: (e) => {
|
|
7839
|
+
e.currentTarget.style.background = "rgba(0, 0, 0, 0.05)";
|
|
7840
|
+
},
|
|
7841
|
+
onMouseLeave: (e) => {
|
|
7842
|
+
e.currentTarget.style.background = "transparent";
|
|
7843
|
+
},
|
|
7844
|
+
children: detailsExpanded ? "Hide Details" : "Show Details"
|
|
7845
|
+
})
|
|
7846
|
+
]
|
|
7847
|
+
})]
|
|
7848
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
7849
|
+
onClick: onDismiss,
|
|
7850
|
+
style: {
|
|
7851
|
+
background: "transparent",
|
|
7852
|
+
border: "none",
|
|
7853
|
+
color: colors.text,
|
|
7854
|
+
cursor: "pointer",
|
|
7855
|
+
padding: "2px",
|
|
7856
|
+
borderRadius: "3px",
|
|
7857
|
+
fontSize: "14px",
|
|
7858
|
+
lineHeight: "1",
|
|
7859
|
+
opacity: .6,
|
|
7860
|
+
transition: "all 0.2s ease",
|
|
7861
|
+
flexShrink: 0
|
|
7862
|
+
},
|
|
7863
|
+
title: "Dismiss",
|
|
7864
|
+
onMouseEnter: (e) => {
|
|
7865
|
+
e.currentTarget.style.opacity = "1";
|
|
7866
|
+
e.currentTarget.style.background = "rgba(0, 0, 0, 0.05)";
|
|
7867
|
+
},
|
|
7868
|
+
onMouseLeave: (e) => {
|
|
7869
|
+
e.currentTarget.style.opacity = "0.6";
|
|
7870
|
+
e.currentTarget.style.background = "transparent";
|
|
7871
|
+
},
|
|
7872
|
+
children: "x"
|
|
7873
|
+
})]
|
|
7874
|
+
}), detailsExpanded && details && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
7875
|
+
style: {
|
|
7876
|
+
marginTop: "10px",
|
|
7877
|
+
padding: "10px",
|
|
7878
|
+
background: "rgba(0, 0, 0, 0.04)",
|
|
7879
|
+
borderRadius: "6px",
|
|
7880
|
+
fontSize: "11px",
|
|
7881
|
+
fontFamily: "monospace",
|
|
7882
|
+
color: colors.text,
|
|
7883
|
+
lineHeight: "1.5",
|
|
7884
|
+
maxHeight: "200px",
|
|
7885
|
+
overflowY: "auto",
|
|
7886
|
+
whiteSpace: "pre-wrap",
|
|
7887
|
+
wordBreak: "break-all"
|
|
7888
|
+
},
|
|
7889
|
+
children: [
|
|
7890
|
+
details.code && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [
|
|
7891
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: "Code:" }),
|
|
7892
|
+
" ",
|
|
7893
|
+
details.code
|
|
7894
|
+
] }),
|
|
7895
|
+
details.originalMessage && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
7896
|
+
style: { marginTop: "4px" },
|
|
7897
|
+
children: [
|
|
7898
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: "Message:" }),
|
|
7899
|
+
" ",
|
|
7900
|
+
details.originalMessage
|
|
7901
|
+
]
|
|
7902
|
+
}),
|
|
7903
|
+
details.context && Object.keys(details.context).length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
7904
|
+
style: { marginTop: "4px" },
|
|
7905
|
+
children: [
|
|
7906
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: "Context:" }),
|
|
7907
|
+
" ",
|
|
7908
|
+
JSON.stringify(details.context, null, 2)
|
|
7909
|
+
]
|
|
7910
|
+
}),
|
|
7911
|
+
details.stack && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
7912
|
+
style: {
|
|
7913
|
+
marginTop: "4px",
|
|
7914
|
+
opacity: .7
|
|
7915
|
+
},
|
|
7916
|
+
children: [
|
|
7917
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: "Stack:" }),
|
|
7918
|
+
"\n",
|
|
7919
|
+
details.stack
|
|
7920
|
+
]
|
|
7921
|
+
})
|
|
7922
|
+
]
|
|
7923
|
+
})]
|
|
7924
|
+
});
|
|
7925
|
+
}
|
|
5939
7926
|
function ToastProvider({ enabled, children }) {
|
|
5940
7927
|
const [toasts, setToasts] = (0, react.useState)([]);
|
|
5941
7928
|
const [bannerError, setBannerErrorState] = (0, react.useState)(null);
|
|
@@ -5973,156 +7960,10 @@ function ToastProvider({ enabled, children }) {
|
|
|
5973
7960
|
};
|
|
5974
7961
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(ToastContext.Provider, {
|
|
5975
7962
|
value,
|
|
5976
|
-
children: [bannerError && ((
|
|
5977
|
-
|
|
5978
|
-
|
|
5979
|
-
|
|
5980
|
-
position: "fixed",
|
|
5981
|
-
bottom: "20px",
|
|
5982
|
-
left: "50%",
|
|
5983
|
-
transform: "translateX(-50%)",
|
|
5984
|
-
zIndex: 9999,
|
|
5985
|
-
backgroundColor: colors.background,
|
|
5986
|
-
border: `1px solid ${colors.border}`,
|
|
5987
|
-
borderLeft: `4px solid ${colors.border}`,
|
|
5988
|
-
borderRadius: "8px",
|
|
5989
|
-
padding: "12px 16px",
|
|
5990
|
-
fontSize: "13px",
|
|
5991
|
-
boxShadow: "0 4px 12px rgba(0, 0, 0, 0.15)",
|
|
5992
|
-
backdropFilter: "blur(8px)",
|
|
5993
|
-
maxWidth: "min(90vw, 700px)",
|
|
5994
|
-
width: "100%",
|
|
5995
|
-
boxSizing: "border-box",
|
|
5996
|
-
overflow: "hidden"
|
|
5997
|
-
},
|
|
5998
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
5999
|
-
style: {
|
|
6000
|
-
display: "flex",
|
|
6001
|
-
justifyContent: "space-between",
|
|
6002
|
-
alignItems: "center",
|
|
6003
|
-
gap: "10px"
|
|
6004
|
-
},
|
|
6005
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6006
|
-
style: {
|
|
6007
|
-
display: "flex",
|
|
6008
|
-
alignItems: "center",
|
|
6009
|
-
gap: "8px",
|
|
6010
|
-
flex: 1,
|
|
6011
|
-
minWidth: 0
|
|
6012
|
-
},
|
|
6013
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { style: {
|
|
6014
|
-
width: "12px",
|
|
6015
|
-
height: "12px",
|
|
6016
|
-
borderRadius: "50%",
|
|
6017
|
-
backgroundColor: colors.border,
|
|
6018
|
-
flexShrink: 0
|
|
6019
|
-
} }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6020
|
-
style: {
|
|
6021
|
-
display: "flex",
|
|
6022
|
-
alignItems: "center",
|
|
6023
|
-
gap: "10px",
|
|
6024
|
-
flex: 1,
|
|
6025
|
-
minWidth: 0
|
|
6026
|
-
},
|
|
6027
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6028
|
-
style: {
|
|
6029
|
-
color: colors.text,
|
|
6030
|
-
lineHeight: "1.4",
|
|
6031
|
-
fontWeight: "400",
|
|
6032
|
-
fontSize: "13px",
|
|
6033
|
-
flex: 1,
|
|
6034
|
-
wordBreak: "break-all",
|
|
6035
|
-
overflowWrap: "break-word",
|
|
6036
|
-
maxWidth: "550px",
|
|
6037
|
-
overflow: "hidden",
|
|
6038
|
-
display: "-webkit-box",
|
|
6039
|
-
WebkitLineClamp: 10,
|
|
6040
|
-
WebkitBoxOrient: "vertical"
|
|
6041
|
-
},
|
|
6042
|
-
children: (() => {
|
|
6043
|
-
let message = bannerError.message;
|
|
6044
|
-
const jsonMatch = message.match(/'message':\s*'([^']+)'/);
|
|
6045
|
-
if (jsonMatch) return jsonMatch[1];
|
|
6046
|
-
message = message.split(" - ")[0];
|
|
6047
|
-
message = message.split(": Error code")[0];
|
|
6048
|
-
message = message.replace(/:\s*\d{3}$/, "");
|
|
6049
|
-
message = message.replace(/See more:.*$/g, "");
|
|
6050
|
-
message = message.trim();
|
|
6051
|
-
return message || "Configuration error occurred.";
|
|
6052
|
-
})()
|
|
6053
|
-
}), (() => {
|
|
6054
|
-
const message = bannerError.message;
|
|
6055
|
-
const markdownLinkRegex = /\[([^\]]+)\]\(([^)]+)\)/g;
|
|
6056
|
-
const plainUrlRegex = /(https?:\/\/[^\s)]+)/g;
|
|
6057
|
-
let url = null;
|
|
6058
|
-
let buttonText = "See More";
|
|
6059
|
-
const markdownMatch = markdownLinkRegex.exec(message);
|
|
6060
|
-
if (markdownMatch) {
|
|
6061
|
-
url = markdownMatch[2];
|
|
6062
|
-
buttonText = "See More";
|
|
6063
|
-
} else {
|
|
6064
|
-
const urlMatch = plainUrlRegex.exec(message);
|
|
6065
|
-
if (urlMatch) {
|
|
6066
|
-
url = urlMatch[0].replace(/[.,;:'"]*$/, "");
|
|
6067
|
-
buttonText = "See More";
|
|
6068
|
-
}
|
|
6069
|
-
}
|
|
6070
|
-
if (!url) return null;
|
|
6071
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
6072
|
-
onClick: () => window.open(url, "_blank", "noopener,noreferrer"),
|
|
6073
|
-
style: {
|
|
6074
|
-
background: colors.border,
|
|
6075
|
-
color: "white",
|
|
6076
|
-
border: "none",
|
|
6077
|
-
borderRadius: "5px",
|
|
6078
|
-
padding: "4px 10px",
|
|
6079
|
-
fontSize: "11px",
|
|
6080
|
-
fontWeight: "500",
|
|
6081
|
-
cursor: "pointer",
|
|
6082
|
-
transition: "all 0.2s ease",
|
|
6083
|
-
flexShrink: 0
|
|
6084
|
-
},
|
|
6085
|
-
onMouseEnter: (e) => {
|
|
6086
|
-
e.currentTarget.style.opacity = "0.9";
|
|
6087
|
-
e.currentTarget.style.transform = "translateY(-1px)";
|
|
6088
|
-
},
|
|
6089
|
-
onMouseLeave: (e) => {
|
|
6090
|
-
e.currentTarget.style.opacity = "1";
|
|
6091
|
-
e.currentTarget.style.transform = "translateY(0)";
|
|
6092
|
-
},
|
|
6093
|
-
children: buttonText
|
|
6094
|
-
});
|
|
6095
|
-
})()]
|
|
6096
|
-
})]
|
|
6097
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
6098
|
-
onClick: () => setBannerError(null),
|
|
6099
|
-
style: {
|
|
6100
|
-
background: "transparent",
|
|
6101
|
-
border: "none",
|
|
6102
|
-
color: colors.text,
|
|
6103
|
-
cursor: "pointer",
|
|
6104
|
-
padding: "2px",
|
|
6105
|
-
borderRadius: "3px",
|
|
6106
|
-
fontSize: "14px",
|
|
6107
|
-
lineHeight: "1",
|
|
6108
|
-
opacity: .6,
|
|
6109
|
-
transition: "all 0.2s ease",
|
|
6110
|
-
flexShrink: 0
|
|
6111
|
-
},
|
|
6112
|
-
title: "Dismiss",
|
|
6113
|
-
onMouseEnter: (e) => {
|
|
6114
|
-
e.currentTarget.style.opacity = "1";
|
|
6115
|
-
e.currentTarget.style.background = "rgba(0, 0, 0, 0.05)";
|
|
6116
|
-
},
|
|
6117
|
-
onMouseLeave: (e) => {
|
|
6118
|
-
e.currentTarget.style.opacity = "0.6";
|
|
6119
|
-
e.currentTarget.style.background = "transparent";
|
|
6120
|
-
},
|
|
6121
|
-
children: "×"
|
|
6122
|
-
})]
|
|
6123
|
-
})
|
|
6124
|
-
});
|
|
6125
|
-
})(), children]
|
|
7963
|
+
children: [bannerError && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BannerErrorDisplay, {
|
|
7964
|
+
bannerError,
|
|
7965
|
+
onDismiss: () => setBannerError(null)
|
|
7966
|
+
}), children]
|
|
6126
7967
|
});
|
|
6127
7968
|
}
|
|
6128
7969
|
|
|
@@ -7129,12 +8970,21 @@ function CopilotListeners() {
|
|
|
7129
8970
|
const { agent } = useAgent({ agentId: resolvedAgentId });
|
|
7130
8971
|
usePredictStateSubscription(agent);
|
|
7131
8972
|
(0, react.useEffect)(() => {
|
|
7132
|
-
const subscription = copilotkit.subscribe({ onError: ({ error }) => {
|
|
7133
|
-
|
|
8973
|
+
const subscription = copilotkit.subscribe({ onError: ({ error, code, context }) => {
|
|
8974
|
+
if (error.name === "AbortError" || error.message === "Fetch is aborted" || error.message === "signal is aborted without reason" || error.message === "component unmounted" || !error.message) return;
|
|
8975
|
+
if (process.env.NODE_ENV === "development") console.error("[CopilotKit] Agent error:", error.message, "\n Code:", code, "\n Context:", context, "\n Stack:", error.stack);
|
|
8976
|
+
const ckError = new _copilotkit_shared.CopilotKitLowLevelError({
|
|
7134
8977
|
error,
|
|
7135
8978
|
message: error.message,
|
|
7136
8979
|
url: typeof window !== "undefined" ? window.location.href : ""
|
|
7137
|
-
})
|
|
8980
|
+
});
|
|
8981
|
+
ckError.details = {
|
|
8982
|
+
code,
|
|
8983
|
+
context,
|
|
8984
|
+
stack: error.stack,
|
|
8985
|
+
originalMessage: error.message
|
|
8986
|
+
};
|
|
8987
|
+
setBannerError(ckError);
|
|
7138
8988
|
} });
|
|
7139
8989
|
return () => {
|
|
7140
8990
|
subscription.unsubscribe();
|
|
@@ -7688,6 +9538,18 @@ Object.defineProperty(exports, 'CopilotChatAssistantMessage_default', {
|
|
|
7688
9538
|
return CopilotChatAssistantMessage_default;
|
|
7689
9539
|
}
|
|
7690
9540
|
});
|
|
9541
|
+
Object.defineProperty(exports, 'CopilotChatAttachmentQueue', {
|
|
9542
|
+
enumerable: true,
|
|
9543
|
+
get: function () {
|
|
9544
|
+
return CopilotChatAttachmentQueue;
|
|
9545
|
+
}
|
|
9546
|
+
});
|
|
9547
|
+
Object.defineProperty(exports, 'CopilotChatAttachmentRenderer', {
|
|
9548
|
+
enumerable: true,
|
|
9549
|
+
get: function () {
|
|
9550
|
+
return CopilotChatAttachmentRenderer;
|
|
9551
|
+
}
|
|
9552
|
+
});
|
|
7691
9553
|
Object.defineProperty(exports, 'CopilotChatAudioRecorder', {
|
|
7692
9554
|
enumerable: true,
|
|
7693
9555
|
get: function () {
|
|
@@ -7850,6 +9712,12 @@ Object.defineProperty(exports, 'MCPAppsActivityType', {
|
|
|
7850
9712
|
return MCPAppsActivityType;
|
|
7851
9713
|
}
|
|
7852
9714
|
});
|
|
9715
|
+
Object.defineProperty(exports, 'SandboxFunctionsContext', {
|
|
9716
|
+
enumerable: true,
|
|
9717
|
+
get: function () {
|
|
9718
|
+
return SandboxFunctionsContext;
|
|
9719
|
+
}
|
|
9720
|
+
});
|
|
7853
9721
|
Object.defineProperty(exports, 'ThreadsContext', {
|
|
7854
9722
|
enumerable: true,
|
|
7855
9723
|
get: function () {
|
|
@@ -7922,6 +9790,12 @@ Object.defineProperty(exports, 'useAsyncCallback', {
|
|
|
7922
9790
|
return useAsyncCallback;
|
|
7923
9791
|
}
|
|
7924
9792
|
});
|
|
9793
|
+
Object.defineProperty(exports, 'useAttachments', {
|
|
9794
|
+
enumerable: true,
|
|
9795
|
+
get: function () {
|
|
9796
|
+
return useAttachments;
|
|
9797
|
+
}
|
|
9798
|
+
});
|
|
7925
9799
|
Object.defineProperty(exports, 'useCoAgentStateRenders', {
|
|
7926
9800
|
enumerable: true,
|
|
7927
9801
|
get: function () {
|
|
@@ -8012,6 +9886,12 @@ Object.defineProperty(exports, 'useRenderToolCall', {
|
|
|
8012
9886
|
return useRenderToolCall;
|
|
8013
9887
|
}
|
|
8014
9888
|
});
|
|
9889
|
+
Object.defineProperty(exports, 'useSandboxFunctions', {
|
|
9890
|
+
enumerable: true,
|
|
9891
|
+
get: function () {
|
|
9892
|
+
return useSandboxFunctions;
|
|
9893
|
+
}
|
|
9894
|
+
});
|
|
8015
9895
|
Object.defineProperty(exports, 'useSuggestions', {
|
|
8016
9896
|
enumerable: true,
|
|
8017
9897
|
get: function () {
|
|
@@ -8036,4 +9916,4 @@ Object.defineProperty(exports, 'useToast', {
|
|
|
8036
9916
|
return useToast;
|
|
8037
9917
|
}
|
|
8038
9918
|
});
|
|
8039
|
-
//# sourceMappingURL=copilotkit-
|
|
9919
|
+
//# sourceMappingURL=copilotkit-Bz5-ImDl.cjs.map
|