@copilotkit/react-core 1.79.1 → 1.80.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/dist/{copilotkit-CD3uPUN3.mjs → copilotkit-BNLtgOyD.mjs} +1855 -221
- package/dist/copilotkit-BNLtgOyD.mjs.map +1 -0
- package/dist/{copilotkit-Yz8qXx00.d.mts → copilotkit-CWOSXhRO.d.mts} +277 -40
- package/dist/copilotkit-CWOSXhRO.d.mts.map +1 -0
- package/dist/{copilotkit-DEaA0Cat.cjs → copilotkit-DKICi3nC.cjs} +1843 -196
- package/dist/copilotkit-DKICi3nC.cjs.map +1 -0
- package/dist/{copilotkit-k7IYk2AN.d.cts → copilotkit-Dfw9HzO9.d.cts} +277 -40
- package/dist/copilotkit-Dfw9HzO9.d.cts.map +1 -0
- package/dist/index.cjs +15 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +15 -3
- package/dist/index.mjs.map +1 -1
- package/dist/index.umd.js +127 -16
- package/dist/index.umd.js.map +1 -1
- package/dist/v2/context.d.cts +7 -0
- package/dist/v2/context.d.cts.map +1 -1
- package/dist/v2/context.d.mts +7 -0
- package/dist/v2/context.d.mts.map +1 -1
- package/dist/v2/headless.cjs +106 -16
- package/dist/v2/headless.cjs.map +1 -1
- package/dist/v2/headless.d.cts +20 -2
- package/dist/v2/headless.d.cts.map +1 -1
- package/dist/v2/headless.d.mts +20 -2
- package/dist/v2/headless.d.mts.map +1 -1
- package/dist/v2/headless.mjs +106 -16
- package/dist/v2/headless.mjs.map +1 -1
- package/dist/v2/index.cjs +3 -1
- package/dist/v2/index.css +1 -1
- package/dist/v2/index.d.cts +2 -2
- package/dist/v2/index.d.mts +2 -2
- package/dist/v2/index.mjs +2 -2
- package/dist/v2/index.umd.js +1858 -222
- package/dist/v2/index.umd.js.map +1 -1
- package/package.json +11 -8
- package/dist/copilotkit-CD3uPUN3.mjs.map +0 -1
- package/dist/copilotkit-DEaA0Cat.cjs.map +0 -1
- package/dist/copilotkit-Yz8qXx00.d.mts.map +0 -1
- package/dist/copilotkit-k7IYk2AN.d.cts.map +0 -1
package/dist/v2/index.umd.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
(function(global, factory) {
|
|
4
|
-
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('./index.css'), require('@copilotkit/core'), require('@ag-ui/client'), require('react'), require('tailwind-merge'), require('lucide-react'), require('@copilotkit/shared'), require('react/jsx-runtime'), require('@radix-ui/react-slot'), require('class-variance-authority'), require('clsx'), require('@radix-ui/react-tooltip'), require('@radix-ui/react-dropdown-menu'), require('streamdown'), require('@ag-ui/core'), require('zod'), require('@copilotkit/mcp-apps-renderer/activity'), require('@copilotkit/a2ui-renderer'), require('zod-to-json-schema'), require('react-dom'), require('@tanstack/react-virtual'), require('use-stick-to-bottom'), require('@copilotkit/web-components/threads-drawer')) :
|
|
5
|
-
typeof define === 'function' && define.amd ? define(['exports', './index.css', '@copilotkit/core', '@ag-ui/client', 'react', 'tailwind-merge', 'lucide-react', '@copilotkit/shared', 'react/jsx-runtime', '@radix-ui/react-slot', 'class-variance-authority', 'clsx', '@radix-ui/react-tooltip', '@radix-ui/react-dropdown-menu', 'streamdown', '@ag-ui/core', 'zod', '@copilotkit/mcp-apps-renderer/activity', '@copilotkit/a2ui-renderer', 'zod-to-json-schema', 'react-dom', '@tanstack/react-virtual', 'use-stick-to-bottom', '@copilotkit/web-components/threads-drawer'], factory) :
|
|
6
|
-
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory((global.CopilotKitReactCoreV2 = {}), global.src_v2_index_css,global.CopilotKitCore,global.AgUIClient,global.React,global.tailwindMerge,global.lucideReact,global.CopilotKitShared,global.ReactJsxRuntime,global.RadixReactSlot,global.classVarianceAuthority,global.clsx,global.RadixReactTooltip,global.RadixReactDropdownMenu,global.streamdown,global.AgUICore,global.Zod,global.CopilotKitMcpAppsRendererActivity,global.CopilotKitA2UIRenderer,global.zod_to_json_schema,global.ReactDOM,global._tanstack_react_virtual,global.useStickToBottom,global._copilotkit_web_components_threads_drawer));
|
|
7
|
-
})(this, function(exports, src_v2_index_css, _copilotkit_core, _ag_ui_client, react, tailwind_merge, lucide_react, _copilotkit_shared, react_jsx_runtime, _radix_ui_react_slot, class_variance_authority, clsx, _radix_ui_react_tooltip, _radix_ui_react_dropdown_menu, streamdown, _ag_ui_core, zod, _copilotkit_mcp_apps_renderer_activity, _copilotkit_a2ui_renderer, zod_to_json_schema, react_dom, _tanstack_react_virtual, use_stick_to_bottom, _copilotkit_web_components_threads_drawer) {
|
|
4
|
+
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('./index.css'), require('@copilotkit/core'), require('@ag-ui/client'), require('react'), require('tailwind-merge'), require('lucide-react'), require('@copilotkit/shared'), require('react/jsx-runtime'), require('@radix-ui/react-slot'), require('class-variance-authority'), require('clsx'), require('@radix-ui/react-tooltip'), require('@radix-ui/react-dropdown-menu'), require('streamdown'), require('@ag-ui/core'), require('zod'), require('@copilotkit/mcp-apps-renderer/activity'), require('@copilotkit/a2ui-renderer'), require('zod-to-json-schema'), require('@radix-ui/react-popover'), require('react-dom'), require('@tanstack/react-virtual'), require('use-stick-to-bottom'), require('@copilotkit/web-components/threads-drawer')) :
|
|
5
|
+
typeof define === 'function' && define.amd ? define(['exports', './index.css', '@copilotkit/core', '@ag-ui/client', 'react', 'tailwind-merge', 'lucide-react', '@copilotkit/shared', 'react/jsx-runtime', '@radix-ui/react-slot', 'class-variance-authority', 'clsx', '@radix-ui/react-tooltip', '@radix-ui/react-dropdown-menu', 'streamdown', '@ag-ui/core', 'zod', '@copilotkit/mcp-apps-renderer/activity', '@copilotkit/a2ui-renderer', 'zod-to-json-schema', '@radix-ui/react-popover', 'react-dom', '@tanstack/react-virtual', 'use-stick-to-bottom', '@copilotkit/web-components/threads-drawer'], factory) :
|
|
6
|
+
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory((global.CopilotKitReactCoreV2 = {}), global.src_v2_index_css,global.CopilotKitCore,global.AgUIClient,global.React,global.tailwindMerge,global.lucideReact,global.CopilotKitShared,global.ReactJsxRuntime,global.RadixReactSlot,global.classVarianceAuthority,global.clsx,global.RadixReactTooltip,global.RadixReactDropdownMenu,global.streamdown,global.AgUICore,global.Zod,global.CopilotKitMcpAppsRendererActivity,global.CopilotKitA2UIRenderer,global.zod_to_json_schema,global._radix_ui_react_popover,global.ReactDOM,global._tanstack_react_virtual,global.useStickToBottom,global._copilotkit_web_components_threads_drawer));
|
|
7
|
+
})(this, function(exports, src_v2_index_css, _copilotkit_core, _ag_ui_client, react, tailwind_merge, lucide_react, _copilotkit_shared, react_jsx_runtime, _radix_ui_react_slot, class_variance_authority, clsx, _radix_ui_react_tooltip, _radix_ui_react_dropdown_menu, streamdown, _ag_ui_core, zod, _copilotkit_mcp_apps_renderer_activity, _copilotkit_a2ui_renderer, zod_to_json_schema, _radix_ui_react_popover, react_dom, _tanstack_react_virtual, use_stick_to_bottom, _copilotkit_web_components_threads_drawer) {
|
|
8
8
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
9
9
|
//#region \0rolldown/runtime.js
|
|
10
10
|
var __create = Object.create;
|
|
@@ -36,6 +36,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
|
36
36
|
react = __toESM(react);
|
|
37
37
|
_radix_ui_react_tooltip = __toESM(_radix_ui_react_tooltip);
|
|
38
38
|
_radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
|
|
39
|
+
_radix_ui_react_popover = __toESM(_radix_ui_react_popover);
|
|
39
40
|
|
|
40
41
|
//#region src/v2/lib/react-core.ts
|
|
41
42
|
var CopilotKitCoreReact = class extends _copilotkit_core.CopilotKitCore {
|
|
@@ -180,7 +181,7 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
|
|
|
180
181
|
* Returns true only for plain JS objects (`{}`), excluding arrays, Dates,
|
|
181
182
|
* class instances, and other exotic objects that happen to have typeof "object".
|
|
182
183
|
*/
|
|
183
|
-
function isPlainObject(obj) {
|
|
184
|
+
function isPlainObject$1(obj) {
|
|
184
185
|
return obj !== null && typeof obj === "object" && Object.prototype.toString.call(obj) === "[object Object]";
|
|
185
186
|
}
|
|
186
187
|
/**
|
|
@@ -199,7 +200,7 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
|
|
|
199
200
|
function useShallowStableRef(value) {
|
|
200
201
|
const ref = (0, react.useRef)(value);
|
|
201
202
|
if (ref.current === value) return ref.current;
|
|
202
|
-
if (isPlainObject(ref.current) && isPlainObject(value)) {
|
|
203
|
+
if (isPlainObject$1(ref.current) && isPlainObject$1(value)) {
|
|
203
204
|
if (shallowEqual(ref.current, value)) return ref.current;
|
|
204
205
|
}
|
|
205
206
|
ref.current = value;
|
|
@@ -215,6 +216,8 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
|
|
|
215
216
|
chatInputToolbarFinishTranscribeButtonLabel: "Finish",
|
|
216
217
|
chatInputToolbarAddButtonLabel: "Add attachments",
|
|
217
218
|
chatInputToolbarToolsButtonLabel: "Tools",
|
|
219
|
+
chatInputToolbarSendButtonLabel: "Send message",
|
|
220
|
+
chatInputToolbarStopButtonLabel: "Stop",
|
|
218
221
|
assistantMessageToolbarCopyCodeLabel: "Copy",
|
|
219
222
|
assistantMessageToolbarCopyCodeCopiedLabel: "Copied",
|
|
220
223
|
assistantMessageToolbarCopyMessageLabel: "Copy",
|
|
@@ -227,13 +230,18 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
|
|
|
227
230
|
assistantMessageToolbarInspectorHideDescription: "Until you reload this page",
|
|
228
231
|
assistantMessageToolbarThumbsUpLabel: "Good response",
|
|
229
232
|
assistantMessageToolbarThumbsDownLabel: "Bad response",
|
|
233
|
+
assistantMessageFeedbackCommentPlaceholder: "Add a comment (optional)",
|
|
234
|
+
assistantMessageFeedbackCommentSubmitLabel: "Send comment",
|
|
230
235
|
assistantMessageToolbarReadAloudLabel: "Read aloud",
|
|
231
236
|
assistantMessageToolbarRegenerateLabel: "Regenerate",
|
|
232
237
|
userMessageToolbarCopyMessageLabel: "Copy",
|
|
233
238
|
userMessageToolbarEditMessageLabel: "Edit",
|
|
239
|
+
userMessageToolbarPreviousBranchLabel: "Previous branch",
|
|
240
|
+
userMessageToolbarNextBranchLabel: "Next branch",
|
|
234
241
|
chatDisclaimerText: "AI can make mistakes. Please verify important information.",
|
|
235
242
|
chatToggleOpenLabel: "Open chat",
|
|
236
243
|
chatToggleCloseLabel: "Close chat",
|
|
244
|
+
chatScrollToBottomLabel: "Scroll to bottom",
|
|
237
245
|
modalHeaderTitle: "CopilotKit Chat",
|
|
238
246
|
welcomeMessageText: "How can I help you today?"
|
|
239
247
|
};
|
|
@@ -495,9 +503,9 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
|
|
|
495
503
|
|
|
496
504
|
//#endregion
|
|
497
505
|
//#region src/v2/lib/utils.ts
|
|
498
|
-
const twMerge$
|
|
506
|
+
const twMerge$12 = (0, tailwind_merge.extendTailwindMerge)({ prefix: "cpk" });
|
|
499
507
|
function cn(...inputs) {
|
|
500
|
-
return twMerge$
|
|
508
|
+
return twMerge$12((0, clsx.clsx)(inputs));
|
|
501
509
|
}
|
|
502
510
|
|
|
503
511
|
//#endregion
|
|
@@ -945,6 +953,11 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
|
|
|
945
953
|
//#region src/v2/components/chat/CopilotChatInput.tsx
|
|
946
954
|
const SLASH_MENU_MAX_VISIBLE_ITEMS = 5;
|
|
947
955
|
const SLASH_MENU_ITEM_HEIGHT_PX = 40;
|
|
956
|
+
/**
|
|
957
|
+
* The chat composer: a text area with the add-menu, voice and send/stop
|
|
958
|
+
* buttons, and a slash-command menu that lists `toolsMenu` items once the text
|
|
959
|
+
* starts with "/".
|
|
960
|
+
*/
|
|
948
961
|
function CopilotChatInput({ mode = "input", onSubmitMessage, onStop, isRunning = false, onStartTranscribe, onCancelTranscribe, onFinishTranscribe, onFinishTranscribeWithAudio, onAddFile, onChange, value, toolsMenu, autoFocus = false, positioning = "static", keyboardHeight = 0, containerRef, showDisclaimer, bottomAnchored = false, textArea, sendButton, startTranscribeButton, cancelTranscribeButton, finishTranscribeButton, addMenuButton, audioRecorder, disclaimer, children, className, ...props }) {
|
|
949
962
|
const isControlled = value !== void 0;
|
|
950
963
|
const [internalValue, setInternalValue] = (0, react.useState)(() => value ?? "");
|
|
@@ -1164,10 +1177,12 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
|
|
|
1164
1177
|
send();
|
|
1165
1178
|
};
|
|
1166
1179
|
const BoundAudioRecorder = renderSlot(audioRecorder, CopilotChatAudioRecorder, { ref: audioRecorderRef });
|
|
1180
|
+
const showsStop = isProcessing && canStop;
|
|
1167
1181
|
const BoundSendButton = renderSlot(sendButton, CopilotChatInput.SendButton, {
|
|
1168
1182
|
onClick: handleSendButtonClick,
|
|
1169
1183
|
disabled: isProcessing ? !canStop : !canSend,
|
|
1170
|
-
|
|
1184
|
+
"aria-label": showsStop ? labels.chatInputToolbarStopButtonLabel : labels.chatInputToolbarSendButtonLabel,
|
|
1185
|
+
children: showsStop ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Square, { className: "cpk:size-[18px] cpk:fill-current" }) : void 0
|
|
1171
1186
|
});
|
|
1172
1187
|
const BoundStartTranscribeButton = renderSlot(startTranscribeButton, CopilotChatInput.StartTranscribeButton, { onClick: onStartTranscribe });
|
|
1173
1188
|
const BoundCancelTranscribeButton = renderSlot(cancelTranscribeButton, CopilotChatInput.CancelTranscribeButton, { onClick: onCancelTranscribe });
|
|
@@ -1479,18 +1494,22 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
|
|
|
1479
1494
|
});
|
|
1480
1495
|
}
|
|
1481
1496
|
(function(_CopilotChatInput) {
|
|
1482
|
-
_CopilotChatInput.SendButton = ({ className, children, ...props }) =>
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1497
|
+
_CopilotChatInput.SendButton = ({ className, children, ...props }) => {
|
|
1498
|
+
const labels = useCopilotChatConfiguration()?.labels ?? CopilotChatDefaultLabels;
|
|
1499
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1500
|
+
className: "cpk:mr-[10px]",
|
|
1501
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
|
|
1502
|
+
type: "button",
|
|
1503
|
+
"data-testid": "copilot-send-button",
|
|
1504
|
+
variant: "chatInputToolbarPrimary",
|
|
1505
|
+
size: "chatInputToolbarIcon",
|
|
1506
|
+
className,
|
|
1507
|
+
"aria-label": labels.chatInputToolbarSendButtonLabel,
|
|
1508
|
+
...props,
|
|
1509
|
+
children: children ?? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.ArrowUp, { className: "cpk:size-[18px]" })
|
|
1510
|
+
})
|
|
1511
|
+
});
|
|
1512
|
+
};
|
|
1494
1513
|
const ToolbarButton = _CopilotChatInput.ToolbarButton = ({ icon, labelKey, defaultClassName, className, ...props }) => {
|
|
1495
1514
|
const labels = useCopilotChatConfiguration()?.labels ?? CopilotChatDefaultLabels;
|
|
1496
1515
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Tooltip, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(TooltipTrigger, {
|
|
@@ -1500,6 +1519,7 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
|
|
|
1500
1519
|
variant: "chatInputToolbarSecondary",
|
|
1501
1520
|
size: "chatInputToolbarIcon",
|
|
1502
1521
|
className: (0, tailwind_merge.twMerge)(defaultClassName, className),
|
|
1522
|
+
"aria-label": labels[labelKey],
|
|
1503
1523
|
...props,
|
|
1504
1524
|
children: icon
|
|
1505
1525
|
})
|
|
@@ -1570,6 +1590,7 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
|
|
|
1570
1590
|
size: "chatInputToolbarIcon",
|
|
1571
1591
|
className: (0, tailwind_merge.twMerge)("cpk:ml-1", className),
|
|
1572
1592
|
disabled: isDisabled,
|
|
1593
|
+
"aria-label": labels.chatInputToolbarAddButtonLabel,
|
|
1573
1594
|
...props,
|
|
1574
1595
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Plus, { className: "cpk:size-[20px]" })
|
|
1575
1596
|
});
|
|
@@ -1719,6 +1740,32 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
|
|
|
1719
1740
|
}
|
|
1720
1741
|
}
|
|
1721
1742
|
/**
|
|
1743
|
+
* The tool-call renderers registered on the provider, kept current.
|
|
1744
|
+
* @internal
|
|
1745
|
+
*/
|
|
1746
|
+
function useToolCallRenderers() {
|
|
1747
|
+
const { copilotkit } = useCopilotKit();
|
|
1748
|
+
return (0, react.useSyncExternalStore)((callback) => copilotkit.subscribe({ onRenderToolCallsChanged: callback }).unsubscribe, () => copilotkit.renderToolCalls, () => copilotkit.renderToolCalls);
|
|
1749
|
+
}
|
|
1750
|
+
/**
|
|
1751
|
+
* Which tool names have a renderer of their own, whether a wildcard (`"*"`)
|
|
1752
|
+
* renderer is registered, and which of them opted into grouping.
|
|
1753
|
+
* @internal
|
|
1754
|
+
*/
|
|
1755
|
+
function useToolCallRendererNames() {
|
|
1756
|
+
const renderers = useToolCallRenderers();
|
|
1757
|
+
return (0, react.useMemo)(() => {
|
|
1758
|
+
const named = renderers.filter((rc) => rc.name !== "*");
|
|
1759
|
+
const wildcards = renderers.filter((rc) => rc.name === "*");
|
|
1760
|
+
return {
|
|
1761
|
+
named: new Set(named.map((rc) => rc.name)),
|
|
1762
|
+
groupedNames: new Set(named.filter((rc) => rc.group).map((rc) => rc.name)),
|
|
1763
|
+
wildcard: wildcards.length > 0,
|
|
1764
|
+
wildcardGroups: wildcards.some((rc) => rc.group)
|
|
1765
|
+
};
|
|
1766
|
+
}, [renderers]);
|
|
1767
|
+
}
|
|
1768
|
+
/**
|
|
1722
1769
|
* Hook that returns a function to render tool calls based on the render functions
|
|
1723
1770
|
* defined in CopilotKitProvider.
|
|
1724
1771
|
*
|
|
@@ -1729,9 +1776,7 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
|
|
|
1729
1776
|
const agentId = useCopilotChatConfiguration()?.agentId ?? _copilotkit_shared.DEFAULT_AGENT_ID;
|
|
1730
1777
|
const unrenderedToolNames = (0, react.useRef)(/* @__PURE__ */ new Set());
|
|
1731
1778
|
const warnedToolNames = (0, react.useRef)(/* @__PURE__ */ new Set());
|
|
1732
|
-
const renderToolCalls = (
|
|
1733
|
-
return copilotkit.subscribe({ onRenderToolCallsChanged: callback }).unsubscribe;
|
|
1734
|
-
}, () => copilotkit.renderToolCalls, () => copilotkit.renderToolCalls);
|
|
1779
|
+
const renderToolCalls = useToolCallRenderers();
|
|
1735
1780
|
const renderToolCall = (0, react.useCallback)(({ toolCall, toolMessage }) => {
|
|
1736
1781
|
const exactMatches = renderToolCalls.filter((rc) => rc.name === toolCall.function.name);
|
|
1737
1782
|
const renderConfig = exactMatches.find((rc) => rc.agentId === agentId) || exactMatches.find((rc) => !rc.agentId) || exactMatches[0] || renderToolCalls.find((rc) => rc.name === "*");
|
|
@@ -1766,7 +1811,7 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
|
|
|
1766
1811
|
|
|
1767
1812
|
//#endregion
|
|
1768
1813
|
//#region package.json
|
|
1769
|
-
var version = "1.
|
|
1814
|
+
var version = "1.80.0";
|
|
1770
1815
|
|
|
1771
1816
|
//#endregion
|
|
1772
1817
|
//#region src/v2/components/CopilotKitInspector.tsx
|
|
@@ -2002,7 +2047,7 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
|
|
|
2002
2047
|
* Fetches resource content on-demand via proxied MCP requests. The React shell
|
|
2003
2048
|
* owns the iframe; `bindMcpApp` owns the protocol.
|
|
2004
2049
|
*/
|
|
2005
|
-
const MCPAppsActivityRenderer = function MCPAppsActivityRenderer({ content, message, agent }) {
|
|
2050
|
+
const MCPAppsActivityRenderer = function MCPAppsActivityRenderer({ content, message, agent, allowSameOriginFallback }) {
|
|
2006
2051
|
const { copilotkit } = useCopilotKit();
|
|
2007
2052
|
const messageId = message?.id;
|
|
2008
2053
|
const containerRef = (0, react.useRef)(null);
|
|
@@ -2052,6 +2097,7 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
|
|
|
2052
2097
|
getAgent: () => agentRef.current,
|
|
2053
2098
|
host: copilotkit,
|
|
2054
2099
|
messageId,
|
|
2100
|
+
options: { allowSameOriginFallback },
|
|
2055
2101
|
hooks: {
|
|
2056
2102
|
onResource: (resource) => {
|
|
2057
2103
|
if (!mounted) return;
|
|
@@ -2093,6 +2139,7 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
|
|
|
2093
2139
|
agent,
|
|
2094
2140
|
copilotkit,
|
|
2095
2141
|
messageId,
|
|
2142
|
+
allowSameOriginFallback,
|
|
2096
2143
|
content.resourceUri,
|
|
2097
2144
|
content.serverHash,
|
|
2098
2145
|
content.serverId
|
|
@@ -3307,7 +3354,8 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
|
|
|
3307
3354
|
name: def.name,
|
|
3308
3355
|
args: argsSchema,
|
|
3309
3356
|
render: def.render,
|
|
3310
|
-
...def.agentId ? { agentId: def.agentId } : {}
|
|
3357
|
+
...def.agentId ? { agentId: def.agentId } : {},
|
|
3358
|
+
...def.group ? { group: true } : {}
|
|
3311
3359
|
};
|
|
3312
3360
|
}
|
|
3313
3361
|
|
|
@@ -3427,6 +3475,11 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
|
|
|
3427
3475
|
- Use CSS Grid or Flexbox for layout. Ensure the UI looks good at any width.
|
|
3428
3476
|
- Minimal transitions (150ms) for hover/focus states only. No decorative animations.
|
|
3429
3477
|
- Keep the UI focused and dense — avoid excessive padding. Use compact spacing (8–12px gaps, 10–14px padding in controls).`;
|
|
3478
|
+
/** The MCP Apps renderer with `mcpApps.allowSameOriginFallback` applied. */
|
|
3479
|
+
const SameOriginMCPAppsActivityRenderer = (props) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MCPAppsActivityRenderer, {
|
|
3480
|
+
...props,
|
|
3481
|
+
allowSameOriginFallback: true
|
|
3482
|
+
});
|
|
3430
3483
|
const DEFAULT_LEARNING = Object.freeze({});
|
|
3431
3484
|
function toLearningConfig(learning) {
|
|
3432
3485
|
if (learning === true) return DEFAULT_LEARNING;
|
|
@@ -3443,7 +3496,8 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
|
|
|
3443
3496
|
}, [value, warningMessage]);
|
|
3444
3497
|
return value;
|
|
3445
3498
|
}
|
|
3446
|
-
|
|
3499
|
+
/** Provide a shared core instance and synchronize runtime, tool, and UI configuration. */
|
|
3500
|
+
const CopilotKitProvider = ({ children, runtimeUrl, headers: headersProp = EMPTY_HEADERS, credentials, messageFilter, publicApiKey, publicLicenseKey, licenseToken, properties = EMPTY_PROPERTIES, agents__unsafe_dev_only: agents = EMPTY_AGENTS, selfManagedAgents = EMPTY_AGENTS, renderToolCalls, renderActivityMessages, renderCustomMessages, frontendTools, humanInTheLoop, openGenerativeUI, enableInspector, agentId, showIntelligenceIndicator = true, useSingleEndpoint, onError, a2ui, mcpApps, defaultThrottleMs, debug, learning }) => {
|
|
3447
3501
|
const learningConfig = (0, react.useMemo)(() => toLearningConfig(learning), [learning]);
|
|
3448
3502
|
const [shouldRenderInspector, setShouldRenderInspector] = (0, react.useState)(false);
|
|
3449
3503
|
const [inspectorVisible, setInspectorVisible] = (0, react.useState)(false);
|
|
@@ -3500,11 +3554,12 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
|
|
|
3500
3554
|
const core = copilotkitRef.current;
|
|
3501
3555
|
return (0, _copilotkit_a2ui_renderer.filterCatalog)(rawCatalog, (name) => core ? core.isCatalogComponentEnabled(name) : true);
|
|
3502
3556
|
}, [rawCatalog, catalogToggleVersion]);
|
|
3557
|
+
const mcpAppsAllowSameOrigin = mcpApps?.allowSameOriginFallback === true;
|
|
3503
3558
|
const builtInActivityRenderers = (0, react.useMemo)(() => {
|
|
3504
3559
|
const renderers = [{
|
|
3505
3560
|
activityType: _copilotkit_mcp_apps_renderer_activity.MCPAppsActivityType,
|
|
3506
3561
|
content: _copilotkit_mcp_apps_renderer_activity.MCPAppsActivityContentSchema,
|
|
3507
|
-
render: MCPAppsActivityRenderer
|
|
3562
|
+
render: mcpAppsAllowSameOrigin ? SameOriginMCPAppsActivityRenderer : MCPAppsActivityRenderer
|
|
3508
3563
|
}];
|
|
3509
3564
|
if (openGenUIActive) renderers.push({
|
|
3510
3565
|
activityType: OpenGenerativeUIActivityType,
|
|
@@ -3522,7 +3577,8 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
|
|
|
3522
3577
|
a2uiActive,
|
|
3523
3578
|
openGenUIActive,
|
|
3524
3579
|
a2ui,
|
|
3525
|
-
filteredCatalog
|
|
3580
|
+
filteredCatalog,
|
|
3581
|
+
mcpAppsAllowSameOrigin
|
|
3526
3582
|
]);
|
|
3527
3583
|
const allActivityRenderers = (0, react.useMemo)(() => {
|
|
3528
3584
|
return [...renderActivityMessagesList, ...builtInActivityRenderers];
|
|
@@ -3630,6 +3686,7 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
|
|
|
3630
3686
|
description: _copilotkit_shared.GENERATE_SANDBOXED_UI_DESCRIPTION,
|
|
3631
3687
|
parameters: GenerateSandboxedUiArgsSchema,
|
|
3632
3688
|
handler: async () => "UI generated",
|
|
3689
|
+
reconnectBehavior: "resume-pending",
|
|
3633
3690
|
followUp: true,
|
|
3634
3691
|
render: OpenGenerativeUIToolRenderer
|
|
3635
3692
|
}];
|
|
@@ -4035,12 +4092,86 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
|
|
|
4035
4092
|
}), [renderActivityMessage, findRenderer]);
|
|
4036
4093
|
}
|
|
4037
4094
|
|
|
4095
|
+
//#endregion
|
|
4096
|
+
//#region src/v2/hooks/tool-registration.ts
|
|
4097
|
+
/**
|
|
4098
|
+
* Deps comparison shared by `useFrontendTool` (and through it
|
|
4099
|
+
* `useHumanInTheLoop` and `useComponent`) and `useRenderTool`. Not part of the
|
|
4100
|
+
* public API.
|
|
4101
|
+
*/
|
|
4102
|
+
const EMPTY_DEPS$1 = [];
|
|
4103
|
+
function isPlainObject(value) {
|
|
4104
|
+
const proto = Object.getPrototypeOf(value);
|
|
4105
|
+
return proto === Object.prototype || proto === null;
|
|
4106
|
+
}
|
|
4107
|
+
/**
|
|
4108
|
+
* Plain data (primitives, plain objects, arrays, dates) compares by value.
|
|
4109
|
+
* Functions always compare equal: these hooks used to compare
|
|
4110
|
+
* `JSON.stringify(deps)`, which turns every function into `null`, and a
|
|
4111
|
+
* function that counted as changed would re-register on every render when it
|
|
4112
|
+
* is written inline (and loop in a component that also reads
|
|
4113
|
+
* `useRenderToolCall`). Everything else (class instances, maps, sets) compares
|
|
4114
|
+
* by identity. A cycle inside plain data is safe: a pair already being
|
|
4115
|
+
* compared counts as equal for that branch.
|
|
4116
|
+
*/
|
|
4117
|
+
function depEqual(a, b, seen) {
|
|
4118
|
+
if (Object.is(a, b)) return true;
|
|
4119
|
+
if (typeof a === "function" && typeof b === "function") return true;
|
|
4120
|
+
if (typeof a !== "object" || typeof b !== "object" || a === null || b === null) return false;
|
|
4121
|
+
if (a instanceof Date && b instanceof Date) return Object.is(a.getTime(), b.getTime());
|
|
4122
|
+
const aIsArray = Array.isArray(a);
|
|
4123
|
+
if (aIsArray !== Array.isArray(b)) return false;
|
|
4124
|
+
if (!aIsArray && !(isPlainObject(a) && isPlainObject(b))) return false;
|
|
4125
|
+
if (seen.get(a) === b) return true;
|
|
4126
|
+
seen.set(a, b);
|
|
4127
|
+
if (aIsArray) {
|
|
4128
|
+
const left = a;
|
|
4129
|
+
const right = b;
|
|
4130
|
+
if (left.length !== right.length) return false;
|
|
4131
|
+
for (let i = 0; i < left.length; i++) if (!depEqual(left[i], right[i], seen)) return false;
|
|
4132
|
+
return true;
|
|
4133
|
+
}
|
|
4134
|
+
const left = a;
|
|
4135
|
+
const right = b;
|
|
4136
|
+
const leftKeys = Object.keys(left);
|
|
4137
|
+
if (leftKeys.length !== Object.keys(right).length) return false;
|
|
4138
|
+
for (const key of leftKeys) {
|
|
4139
|
+
if (!Object.prototype.hasOwnProperty.call(right, key)) return false;
|
|
4140
|
+
if (!depEqual(left[key], right[key], seen)) return false;
|
|
4141
|
+
}
|
|
4142
|
+
return true;
|
|
4143
|
+
}
|
|
4144
|
+
/** Whether two deps arrays are equal. A change in length is always a change. */
|
|
4145
|
+
function depsEqual(prev, next) {
|
|
4146
|
+
if (prev.length !== next.length) return false;
|
|
4147
|
+
const seen = /* @__PURE__ */ new Map();
|
|
4148
|
+
for (let i = 0; i < prev.length; i++) if (!depEqual(prev[i], next[i], seen)) return false;
|
|
4149
|
+
return true;
|
|
4150
|
+
}
|
|
4151
|
+
/**
|
|
4152
|
+
* Turns a caller's `deps` array into a number that changes exactly when the
|
|
4153
|
+
* deps change, by the rules of {@link depsEqual}. Put the number, not the
|
|
4154
|
+
* array, in the registration effect's dependency list: that keeps the list a
|
|
4155
|
+
* constant length and never serializes a value.
|
|
4156
|
+
*/
|
|
4157
|
+
function useDepsVersion(deps) {
|
|
4158
|
+
const next = deps ?? EMPTY_DEPS$1;
|
|
4159
|
+
const ref = (0, react.useRef)({
|
|
4160
|
+
deps: next,
|
|
4161
|
+
version: 0
|
|
4162
|
+
});
|
|
4163
|
+
if (ref.current.deps !== next && !depsEqual(ref.current.deps, next)) ref.current = {
|
|
4164
|
+
deps: next,
|
|
4165
|
+
version: ref.current.version + 1
|
|
4166
|
+
};
|
|
4167
|
+
return ref.current.version;
|
|
4168
|
+
}
|
|
4169
|
+
|
|
4038
4170
|
//#endregion
|
|
4039
4171
|
//#region src/v2/hooks/use-frontend-tool.tsx
|
|
4040
|
-
const EMPTY_DEPS$2 = [];
|
|
4041
4172
|
function useFrontendTool(tool, deps) {
|
|
4042
4173
|
const { copilotkit } = useCopilotKit();
|
|
4043
|
-
const
|
|
4174
|
+
const depsVersion = useDepsVersion(deps);
|
|
4044
4175
|
(0, react.useLayoutEffect)(() => {
|
|
4045
4176
|
const name = tool.name;
|
|
4046
4177
|
if (copilotkit.getTool({
|
|
@@ -4064,14 +4195,14 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
|
|
|
4064
4195
|
tool.name,
|
|
4065
4196
|
tool.available,
|
|
4066
4197
|
copilotkit,
|
|
4067
|
-
|
|
4198
|
+
depsVersion,
|
|
4068
4199
|
JSON.stringify(tool.webmcp ?? null)
|
|
4069
4200
|
]);
|
|
4070
4201
|
}
|
|
4071
4202
|
|
|
4072
4203
|
//#endregion
|
|
4073
4204
|
//#region src/v2/hooks/use-frontend-tools.tsx
|
|
4074
|
-
const EMPTY_DEPS
|
|
4205
|
+
const EMPTY_DEPS = [];
|
|
4075
4206
|
const EMPTY_TOOLS = [];
|
|
4076
4207
|
/**
|
|
4077
4208
|
* Register a list of frontend tools whose length can change between renders.
|
|
@@ -4125,7 +4256,7 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
|
|
|
4125
4256
|
function useFrontendTools(tools, deps) {
|
|
4126
4257
|
const { copilotkit } = useCopilotKit();
|
|
4127
4258
|
const toolList = tools ?? EMPTY_TOOLS;
|
|
4128
|
-
const extraDeps = deps ?? EMPTY_DEPS
|
|
4259
|
+
const extraDeps = deps ?? EMPTY_DEPS;
|
|
4129
4260
|
(0, react.useLayoutEffect)(() => {
|
|
4130
4261
|
const deduped = /* @__PURE__ */ new Map();
|
|
4131
4262
|
for (const tool of toolList) {
|
|
@@ -4236,8 +4367,7 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
|
|
|
4236
4367
|
|
|
4237
4368
|
//#endregion
|
|
4238
4369
|
//#region src/v2/hooks/use-render-tool.tsx
|
|
4239
|
-
|
|
4240
|
-
/**
|
|
4370
|
+
/**
|
|
4241
4371
|
* Registers a renderer entry in CopilotKit's `renderToolCalls` registry.
|
|
4242
4372
|
*
|
|
4243
4373
|
* Key behavior:
|
|
@@ -4280,7 +4410,7 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
|
|
|
4280
4410
|
*/
|
|
4281
4411
|
function useRenderTool(config, deps) {
|
|
4282
4412
|
const { copilotkit } = useCopilotKit();
|
|
4283
|
-
const
|
|
4413
|
+
const depsVersion = useDepsVersion(deps);
|
|
4284
4414
|
(0, react.useEffect)(() => {
|
|
4285
4415
|
const renderer = config.name === "*" && !config.parameters ? defineToolCallRenderer({
|
|
4286
4416
|
name: "*",
|
|
@@ -4288,7 +4418,8 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
|
|
|
4288
4418
|
...props,
|
|
4289
4419
|
parameters: props.args
|
|
4290
4420
|
}),
|
|
4291
|
-
...config.agentId ? { agentId: config.agentId } : {}
|
|
4421
|
+
...config.agentId ? { agentId: config.agentId } : {},
|
|
4422
|
+
group: config.group
|
|
4292
4423
|
}) : defineToolCallRenderer({
|
|
4293
4424
|
name: config.name,
|
|
4294
4425
|
args: config.parameters,
|
|
@@ -4306,16 +4437,395 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
|
|
|
4306
4437
|
parameters: props.args
|
|
4307
4438
|
});
|
|
4308
4439
|
},
|
|
4309
|
-
...config.agentId ? { agentId: config.agentId } : {}
|
|
4440
|
+
...config.agentId ? { agentId: config.agentId } : {},
|
|
4441
|
+
group: config.group
|
|
4310
4442
|
});
|
|
4311
4443
|
copilotkit.addHookRenderToolCall(renderer);
|
|
4312
4444
|
}, [
|
|
4313
4445
|
config.name,
|
|
4446
|
+
config.group,
|
|
4314
4447
|
copilotkit,
|
|
4315
|
-
|
|
4448
|
+
depsVersion
|
|
4316
4449
|
]);
|
|
4317
4450
|
}
|
|
4318
4451
|
|
|
4452
|
+
//#endregion
|
|
4453
|
+
//#region src/v2/components/chat/CopilotChatToolCallGroup.tsx
|
|
4454
|
+
/**
|
|
4455
|
+
* Set by a group around the calls it shows, so CopilotKit's built-in tool card
|
|
4456
|
+
* draws itself as a compact row that fits the group instead of a card.
|
|
4457
|
+
* @internal
|
|
4458
|
+
*/
|
|
4459
|
+
const ToolCallGroupContext = (0, react.createContext)(null);
|
|
4460
|
+
/**
|
|
4461
|
+
* A call without a result is running only while the group is active: once
|
|
4462
|
+
* the run has moved on or ended, its result is never coming.
|
|
4463
|
+
*/
|
|
4464
|
+
const entryStatus = ({ toolMessage }, active) => toolMessage ? toolMessage.error ? "failed" : "done" : active ? "running" : "stopped";
|
|
4465
|
+
/** @internal */
|
|
4466
|
+
const statusLabels = {
|
|
4467
|
+
running: "Running",
|
|
4468
|
+
done: "Done",
|
|
4469
|
+
failed: "Failed",
|
|
4470
|
+
stopped: "Stopped"
|
|
4471
|
+
};
|
|
4472
|
+
/** The first non-empty string argument: usually a command, path or query. */
|
|
4473
|
+
function argumentPreview(parameters) {
|
|
4474
|
+
if (!parameters || typeof parameters !== "object") return void 0;
|
|
4475
|
+
return Object.values(parameters).find((v) => typeof v === "string" && v.trim().length > 0)?.replace(/\s+/g, " ");
|
|
4476
|
+
}
|
|
4477
|
+
const entryPreview = (entry) => argumentPreview((0, _copilotkit_shared.partialJSONParse)(entry.toolCall.function.arguments));
|
|
4478
|
+
/** "run_command ×2, read_file" */
|
|
4479
|
+
function toolNames(calls) {
|
|
4480
|
+
const counts = /* @__PURE__ */ new Map();
|
|
4481
|
+
for (const { toolCall } of calls) {
|
|
4482
|
+
const name = toolCall.function.name;
|
|
4483
|
+
counts.set(name, (counts.get(name) ?? 0) + 1);
|
|
4484
|
+
}
|
|
4485
|
+
return [...counts].map(([name, count]) => count > 1 ? `${name} ×${count}` : name).join(", ");
|
|
4486
|
+
}
|
|
4487
|
+
const pluralize = (count, noun) => `${count} ${noun}${count === 1 ? "" : "s"}`;
|
|
4488
|
+
/**
|
|
4489
|
+
* Height transition between closed and its content's height. Closed content
|
|
4490
|
+
* stays mounted (so its state survives) but is inert.
|
|
4491
|
+
* @internal
|
|
4492
|
+
*/
|
|
4493
|
+
function Collapsible({ open, id, className, children }) {
|
|
4494
|
+
const ref = (0, react.useRef)(null);
|
|
4495
|
+
(0, react.useLayoutEffect)(() => {
|
|
4496
|
+
ref.current?.toggleAttribute("inert", !open);
|
|
4497
|
+
}, [open]);
|
|
4498
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4499
|
+
ref,
|
|
4500
|
+
id,
|
|
4501
|
+
className: (0, tailwind_merge.twMerge)("cpk:grid cpk:transition-[grid-template-rows] cpk:duration-300 cpk:ease-[cubic-bezier(0.16,1,0.3,1)] cpk:motion-reduce:transition-none", className),
|
|
4502
|
+
style: { gridTemplateRows: open ? "1fr" : "0fr" },
|
|
4503
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4504
|
+
className: "cpk:min-h-0 cpk:overflow-hidden",
|
|
4505
|
+
children
|
|
4506
|
+
})
|
|
4507
|
+
});
|
|
4508
|
+
}
|
|
4509
|
+
function StatusIcon({ status, className }) {
|
|
4510
|
+
const Icon = {
|
|
4511
|
+
running: lucide_react.Loader2,
|
|
4512
|
+
done: lucide_react.Check,
|
|
4513
|
+
failed: lucide_react.X,
|
|
4514
|
+
stopped: lucide_react.Circle
|
|
4515
|
+
}[status];
|
|
4516
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, {
|
|
4517
|
+
"aria-hidden": "true",
|
|
4518
|
+
className: (0, tailwind_merge.twMerge)("cpk:size-3.5 cpk:shrink-0 cpk:text-muted-foreground", status === "running" && "cpk:animate-spin", status === "failed" && "cpk:text-destructive", className)
|
|
4519
|
+
});
|
|
4520
|
+
}
|
|
4521
|
+
function Chevron({ open, className }) {
|
|
4522
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.ChevronRight, {
|
|
4523
|
+
"aria-hidden": "true",
|
|
4524
|
+
className: (0, tailwind_merge.twMerge)("cpk:size-3.5 cpk:shrink-0 cpk:transition-transform cpk:duration-200", open && "cpk:rotate-90", className)
|
|
4525
|
+
});
|
|
4526
|
+
}
|
|
4527
|
+
function FailedCount({ calls }) {
|
|
4528
|
+
const failed = calls.filter((call) => call.toolMessage?.error).length;
|
|
4529
|
+
if (!failed) return null;
|
|
4530
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
4531
|
+
className: "cpk:shrink-0 cpk:text-destructive",
|
|
4532
|
+
children: [failed, " failed"]
|
|
4533
|
+
});
|
|
4534
|
+
}
|
|
4535
|
+
/**
|
|
4536
|
+
* Guarded JSON.stringify for the payload blocks. A circular reference would
|
|
4537
|
+
* otherwise crash the entire React tree on render.
|
|
4538
|
+
*/
|
|
4539
|
+
function stringifyPayload(value) {
|
|
4540
|
+
if (typeof value === "string") return value;
|
|
4541
|
+
try {
|
|
4542
|
+
return JSON.stringify(value, null, 2);
|
|
4543
|
+
} catch (err) {
|
|
4544
|
+
console.warn("[CopilotKit] Failed to JSON.stringify tool-call payload; falling back to String():", err);
|
|
4545
|
+
try {
|
|
4546
|
+
return String(value);
|
|
4547
|
+
} catch {
|
|
4548
|
+
return "[unserializable]";
|
|
4549
|
+
}
|
|
4550
|
+
}
|
|
4551
|
+
}
|
|
4552
|
+
function Payload({ label, value }) {
|
|
4553
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4554
|
+
className: "cpk:text-[11px] cpk:font-medium cpk:uppercase cpk:tracking-wide cpk:text-muted-foreground",
|
|
4555
|
+
children: label
|
|
4556
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", {
|
|
4557
|
+
className: "cpk:m-0 cpk:mt-1.5 cpk:max-h-[200px] cpk:overflow-auto cpk:rounded-lg cpk:bg-muted cpk:p-2.5 cpk:font-mono cpk:text-xs cpk:leading-relaxed cpk:text-foreground cpk:whitespace-pre-wrap cpk:break-words",
|
|
4558
|
+
children: stringifyPayload(value)
|
|
4559
|
+
})] });
|
|
4560
|
+
}
|
|
4561
|
+
/**
|
|
4562
|
+
* A tool call's arguments and, once it has one, its result.
|
|
4563
|
+
* @internal
|
|
4564
|
+
*/
|
|
4565
|
+
function ToolCallPayloads({ parameters, result, className }) {
|
|
4566
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4567
|
+
className: (0, tailwind_merge.twMerge)("cpk:grid cpk:gap-3", className),
|
|
4568
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Payload, {
|
|
4569
|
+
label: "Arguments",
|
|
4570
|
+
value: parameters ?? {}
|
|
4571
|
+
}), result !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Payload, {
|
|
4572
|
+
label: "Result",
|
|
4573
|
+
value: result
|
|
4574
|
+
})]
|
|
4575
|
+
});
|
|
4576
|
+
}
|
|
4577
|
+
/**
|
|
4578
|
+
* The built-in tool card drawn as a row inside a group: status, name and main
|
|
4579
|
+
* argument, opening to the payloads.
|
|
4580
|
+
* @internal
|
|
4581
|
+
*/
|
|
4582
|
+
function ToolCallRow({ name, parameters, result, status, appearance, className, ...props }) {
|
|
4583
|
+
const [open, setOpen] = (0, react.useState)(false);
|
|
4584
|
+
const detailsId = (0, react.useId)();
|
|
4585
|
+
const preview = argumentPreview(parameters);
|
|
4586
|
+
const line = appearance === "line";
|
|
4587
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4588
|
+
"data-copilotkit": true,
|
|
4589
|
+
className: (0, tailwind_merge.twMerge)(!line && "cpk:border-t cpk:border-border", className),
|
|
4590
|
+
...props,
|
|
4591
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
4592
|
+
type: "button",
|
|
4593
|
+
"aria-expanded": open,
|
|
4594
|
+
"aria-controls": detailsId,
|
|
4595
|
+
onClick: () => setOpen((value) => !value),
|
|
4596
|
+
className: (0, tailwind_merge.twMerge)("cpk:group/row cpk:m-0 cpk:flex cpk:min-w-0 cpk:cursor-pointer cpk:items-center cpk:gap-2 cpk:border-none cpk:bg-transparent cpk:text-left cpk:text-[13px] cpk:text-inherit cpk:transition-colors cpk:hover:bg-accent/60 cpk:focus-visible:outline-2 cpk:focus-visible:-outline-offset-2 cpk:focus-visible:outline-ring", line ? "cpk:-mx-1.5 cpk:w-[calc(100%+0.75rem)] cpk:rounded-md cpk:px-1.5 cpk:py-1" : "cpk:w-full cpk:px-3.5 cpk:py-2"),
|
|
4597
|
+
children: [
|
|
4598
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(StatusIcon, { status }),
|
|
4599
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4600
|
+
"data-testid": "copilot-tool-render-name",
|
|
4601
|
+
className: (0, tailwind_merge.twMerge)("cpk:shrink-0 cpk:font-mono cpk:text-[13px] cpk:font-medium cpk:text-foreground", status === "running" && "cpk-shimmer"),
|
|
4602
|
+
children: name
|
|
4603
|
+
}),
|
|
4604
|
+
preview && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4605
|
+
className: "cpk:min-w-0 cpk:truncate cpk:font-mono cpk:text-[13px] cpk:text-muted-foreground",
|
|
4606
|
+
children: preview
|
|
4607
|
+
}),
|
|
4608
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4609
|
+
"data-testid": "copilot-tool-render-status",
|
|
4610
|
+
className: "cpk:sr-only",
|
|
4611
|
+
children: statusLabels[status]
|
|
4612
|
+
}),
|
|
4613
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Chevron, {
|
|
4614
|
+
open,
|
|
4615
|
+
className: (0, tailwind_merge.twMerge)("cpk:ml-auto cpk:text-muted-foreground", !open && "cpk:opacity-0 cpk:group-hover/row:opacity-100 cpk:group-focus-visible/row:opacity-100")
|
|
4616
|
+
})
|
|
4617
|
+
]
|
|
4618
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Collapsible, {
|
|
4619
|
+
open,
|
|
4620
|
+
id: detailsId,
|
|
4621
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ToolCallPayloads, {
|
|
4622
|
+
parameters,
|
|
4623
|
+
result,
|
|
4624
|
+
className: line ? "cpk:mt-1 cpk:mb-2 cpk:ml-5.5" : "cpk:px-3.5 cpk:pt-1 cpk:pb-3"
|
|
4625
|
+
})
|
|
4626
|
+
})]
|
|
4627
|
+
});
|
|
4628
|
+
}
|
|
4629
|
+
/**
|
|
4630
|
+
* Tool calls made in a row, collapsed into one summary. While a call runs the
|
|
4631
|
+
* summary names it ("Running read_file src/app.ts"); once they're all done it
|
|
4632
|
+
* reads "Used 3 tools" and opens to the calls.
|
|
4633
|
+
*
|
|
4634
|
+
* Each call is drawn by its registered renderer. CopilotKit's built-in card
|
|
4635
|
+
* (`useDefaultRenderTool`) draws a compact row inside the card and line
|
|
4636
|
+
* appearances; a custom wildcard renderer draws whatever it draws.
|
|
4637
|
+
*/
|
|
4638
|
+
function CopilotChatToolCallGroup({ calls, renderCall, appearance = "card", isActive = false, className, ...props }) {
|
|
4639
|
+
const [open, setOpen] = (0, react.useState)(false);
|
|
4640
|
+
const bodyId = (0, react.useId)();
|
|
4641
|
+
const latest = calls[calls.length - 1];
|
|
4642
|
+
if (!latest) return null;
|
|
4643
|
+
const current = isActive ? calls.find((call) => !call.toolMessage) ?? latest : void 0;
|
|
4644
|
+
const preview = current ? entryPreview(current) : void 0;
|
|
4645
|
+
const done = calls.filter((call) => call.toolMessage).length;
|
|
4646
|
+
const statuses = calls.map((call) => entryStatus(call, isActive));
|
|
4647
|
+
const failedIds = new Set(calls.filter((_, index) => statuses[index] === "failed").map((call) => call.toolCall.id));
|
|
4648
|
+
const status = current ? "running" : failedIds.size > 0 ? "failed" : statuses.includes("stopped") ? "stopped" : "done";
|
|
4649
|
+
const rows = (rowAppearance) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ToolCallGroupContext.Provider, {
|
|
4650
|
+
value: {
|
|
4651
|
+
appearance: rowAppearance,
|
|
4652
|
+
failedIds,
|
|
4653
|
+
active: isActive
|
|
4654
|
+
},
|
|
4655
|
+
children: calls.map((call) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react.default.Fragment, { children: renderCall(call) }, call.toolCall.id))
|
|
4656
|
+
});
|
|
4657
|
+
const groupProps = {
|
|
4658
|
+
"data-copilotkit": true,
|
|
4659
|
+
"data-testid": "copilot-tool-call-group",
|
|
4660
|
+
"data-appearance": appearance,
|
|
4661
|
+
"data-state": status,
|
|
4662
|
+
...props
|
|
4663
|
+
};
|
|
4664
|
+
const runningLabel = current && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
4665
|
+
className: "cpk:shrink-0 cpk:font-medium cpk-shimmer",
|
|
4666
|
+
children: ["Running ", current.toolCall.function.name]
|
|
4667
|
+
}), preview && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4668
|
+
className: "cpk:min-w-0 cpk:truncate cpk:font-mono cpk:text-xs cpk:opacity-70",
|
|
4669
|
+
children: preview
|
|
4670
|
+
})] });
|
|
4671
|
+
if (appearance === "line") {
|
|
4672
|
+
if (calls.length === 1 && !current) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4673
|
+
...groupProps,
|
|
4674
|
+
className: (0, tailwind_merge.twMerge)("cpk:my-2", className),
|
|
4675
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ToolCallGroupContext.Provider, {
|
|
4676
|
+
value: {
|
|
4677
|
+
appearance: "line",
|
|
4678
|
+
failedIds,
|
|
4679
|
+
active: isActive
|
|
4680
|
+
},
|
|
4681
|
+
children: renderCall(latest)
|
|
4682
|
+
})
|
|
4683
|
+
});
|
|
4684
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4685
|
+
...groupProps,
|
|
4686
|
+
className: (0, tailwind_merge.twMerge)("cpk:my-3", className),
|
|
4687
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
4688
|
+
type: "button",
|
|
4689
|
+
"aria-expanded": open,
|
|
4690
|
+
"aria-controls": bodyId,
|
|
4691
|
+
onClick: () => setOpen((value) => !value),
|
|
4692
|
+
className: "cpk:m-0 cpk:inline-flex cpk:max-w-full cpk:min-w-0 cpk:cursor-pointer cpk:items-center cpk:gap-1.5 cpk:rounded-md cpk:border-none cpk:bg-transparent cpk:p-0 cpk:py-0.5 cpk:text-sm cpk:text-muted-foreground cpk:transition-colors cpk:hover:text-foreground cpk:focus-visible:outline-2 cpk:focus-visible:outline-ring",
|
|
4693
|
+
children: [runningLabel || /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
4694
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
4695
|
+
className: "cpk:shrink-0 cpk:font-medium",
|
|
4696
|
+
children: ["Used ", pluralize(calls.length, "tool")]
|
|
4697
|
+
}),
|
|
4698
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4699
|
+
className: "cpk:min-w-0 cpk:truncate cpk:font-mono cpk:text-xs cpk:opacity-70",
|
|
4700
|
+
children: toolNames(calls)
|
|
4701
|
+
}),
|
|
4702
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(FailedCount, { calls })
|
|
4703
|
+
] }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Chevron, { open })]
|
|
4704
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Collapsible, {
|
|
4705
|
+
open,
|
|
4706
|
+
id: bodyId,
|
|
4707
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4708
|
+
className: "cpk:mt-1 cpk:ml-1 cpk:border-l-2 cpk:border-border cpk:py-0.5 cpk:pl-3",
|
|
4709
|
+
children: rows("line")
|
|
4710
|
+
})
|
|
4711
|
+
})]
|
|
4712
|
+
});
|
|
4713
|
+
}
|
|
4714
|
+
if (appearance === "stack") {
|
|
4715
|
+
if (calls.length === 1) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4716
|
+
...groupProps,
|
|
4717
|
+
className: (0, tailwind_merge.twMerge)("cpk:py-1", className),
|
|
4718
|
+
children: renderCall(latest)
|
|
4719
|
+
});
|
|
4720
|
+
const behind = open ? 0 : Math.min(calls.length - 1, 2);
|
|
4721
|
+
const layer = "cpk:rounded-xl cpk:border cpk:border-border cpk:bg-card cpk:text-card-foreground";
|
|
4722
|
+
const latestStatus = entryStatus(latest, isActive);
|
|
4723
|
+
const latestPreview = entryPreview(latest);
|
|
4724
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4725
|
+
...groupProps,
|
|
4726
|
+
className: (0, tailwind_merge.twMerge)("cpk:my-3", className),
|
|
4727
|
+
style: {
|
|
4728
|
+
paddingBottom: behind * 6,
|
|
4729
|
+
...props.style
|
|
4730
|
+
},
|
|
4731
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4732
|
+
className: "cpk:relative cpk:isolate",
|
|
4733
|
+
children: [Array.from({ length: behind }, (_, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4734
|
+
"aria-hidden": "true",
|
|
4735
|
+
className: (0, tailwind_merge.twMerge)(layer, "cpk:absolute cpk:inset-0"),
|
|
4736
|
+
style: {
|
|
4737
|
+
transform: `translateY(${(index + 1) * 6}px) scaleX(${1 - (index + 1) * .045})`,
|
|
4738
|
+
zIndex: -1 - index,
|
|
4739
|
+
opacity: 1 - (index + 1) * .28
|
|
4740
|
+
}
|
|
4741
|
+
}, index)), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
4742
|
+
type: "button",
|
|
4743
|
+
"aria-expanded": open,
|
|
4744
|
+
"aria-controls": open ? bodyId : void 0,
|
|
4745
|
+
onClick: () => setOpen((value) => !value),
|
|
4746
|
+
className: (0, tailwind_merge.twMerge)("cpk:relative cpk:m-0 cpk:flex cpk:min-w-0 cpk:cursor-pointer cpk:items-center cpk:text-left cpk:transition-colors cpk:focus-visible:outline-2 cpk:focus-visible:outline-ring", open ? "cpk:mb-1 cpk:gap-1.5 cpk:rounded-md cpk:border-none cpk:bg-transparent cpk:p-0 cpk:py-0.5 cpk:text-xs cpk:text-muted-foreground cpk:hover:text-foreground" : (0, tailwind_merge.twMerge)(layer, "cpk:w-full cpk:gap-2 cpk:px-3.5 cpk:py-2.5 cpk:text-[13px] cpk:shadow-[0_1px_2px_rgb(0_0_0/0.04)] cpk:hover:bg-accent")),
|
|
4747
|
+
children: open ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
4748
|
+
pluralize(calls.length, "tool call"),
|
|
4749
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(FailedCount, { calls }),
|
|
4750
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Chevron, {
|
|
4751
|
+
open: true,
|
|
4752
|
+
className: "cpk:-rotate-90"
|
|
4753
|
+
}),
|
|
4754
|
+
"Collapse"
|
|
4755
|
+
] }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
4756
|
+
className: "cpk:flex cpk:min-w-0 cpk:flex-1 cpk:items-center cpk:gap-2 cpk:animate-[cpk-stack-drop_260ms_cubic-bezier(0.16,1,0.3,1)] cpk:motion-reduce:animate-none",
|
|
4757
|
+
children: [
|
|
4758
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(StatusIcon, { status: latestStatus }),
|
|
4759
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4760
|
+
className: (0, tailwind_merge.twMerge)("cpk:shrink-0 cpk:font-mono cpk:font-medium cpk:text-foreground", latestStatus === "running" && "cpk-shimmer"),
|
|
4761
|
+
children: latest.toolCall.function.name
|
|
4762
|
+
}),
|
|
4763
|
+
latestPreview && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4764
|
+
className: "cpk:min-w-0 cpk:truncate cpk:font-mono cpk:text-muted-foreground",
|
|
4765
|
+
children: latestPreview
|
|
4766
|
+
})
|
|
4767
|
+
]
|
|
4768
|
+
}, latest.toolCall.id), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
4769
|
+
className: "cpk:ml-2 cpk:inline-flex cpk:shrink-0 cpk:items-center cpk:gap-2 cpk:text-xs cpk:text-muted-foreground",
|
|
4770
|
+
children: [
|
|
4771
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(FailedCount, { calls }),
|
|
4772
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4773
|
+
className: "cpk:tabular-nums",
|
|
4774
|
+
children: pluralize(calls.length, "call")
|
|
4775
|
+
}),
|
|
4776
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Chevron, {
|
|
4777
|
+
open: false,
|
|
4778
|
+
className: "cpk:rotate-90"
|
|
4779
|
+
})
|
|
4780
|
+
]
|
|
4781
|
+
})] })
|
|
4782
|
+
})]
|
|
4783
|
+
}), open && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4784
|
+
id: bodyId,
|
|
4785
|
+
className: "cpk:[&>*]:animate-[cpk-stack-fan_300ms_cubic-bezier(0.16,1,0.3,1)_both] cpk:motion-reduce:[&>*]:animate-none",
|
|
4786
|
+
children: calls.map((call) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react.default.Fragment, { children: renderCall(call) }, call.toolCall.id))
|
|
4787
|
+
})]
|
|
4788
|
+
});
|
|
4789
|
+
}
|
|
4790
|
+
if (calls.length === 1) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4791
|
+
...groupProps,
|
|
4792
|
+
className: (0, tailwind_merge.twMerge)("cpk:py-1", className),
|
|
4793
|
+
children: renderCall(latest)
|
|
4794
|
+
});
|
|
4795
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4796
|
+
...groupProps,
|
|
4797
|
+
className: (0, tailwind_merge.twMerge)("cpk:my-3 cpk:overflow-hidden cpk:rounded-xl cpk:border cpk:border-border cpk:bg-card cpk:text-card-foreground", className),
|
|
4798
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
4799
|
+
type: "button",
|
|
4800
|
+
"aria-expanded": open,
|
|
4801
|
+
"aria-controls": bodyId,
|
|
4802
|
+
onClick: () => setOpen((value) => !value),
|
|
4803
|
+
className: "cpk:m-0 cpk:flex cpk:w-full cpk:min-w-0 cpk:cursor-pointer cpk:items-center cpk:gap-2.5 cpk:border-none cpk:bg-transparent cpk:px-3.5 cpk:py-2.5 cpk:text-left cpk:text-[13px] cpk:text-inherit cpk:transition-colors cpk:hover:bg-accent/60 cpk:focus-visible:outline-2 cpk:focus-visible:-outline-offset-2 cpk:focus-visible:outline-ring",
|
|
4804
|
+
children: [
|
|
4805
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(StatusIcon, { status }),
|
|
4806
|
+
runningLabel || /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
4807
|
+
className: "cpk:shrink-0 cpk:font-medium cpk:text-foreground",
|
|
4808
|
+
children: ["Used ", pluralize(calls.length, "tool")]
|
|
4809
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4810
|
+
className: "cpk:min-w-0 cpk:truncate cpk:font-mono cpk:text-xs cpk:text-muted-foreground",
|
|
4811
|
+
children: toolNames(calls)
|
|
4812
|
+
})] }),
|
|
4813
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
4814
|
+
className: "cpk:ml-auto cpk:flex cpk:shrink-0 cpk:items-center cpk:gap-2 cpk:pl-2 cpk:text-xs cpk:text-muted-foreground",
|
|
4815
|
+
children: [status === "failed" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FailedCount, { calls }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4816
|
+
className: "cpk:tabular-nums",
|
|
4817
|
+
children: status === "running" ? `${done} done` : statusLabels[status]
|
|
4818
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Chevron, { open })]
|
|
4819
|
+
})
|
|
4820
|
+
]
|
|
4821
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Collapsible, {
|
|
4822
|
+
open,
|
|
4823
|
+
id: bodyId,
|
|
4824
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { children: rows("card") })
|
|
4825
|
+
})]
|
|
4826
|
+
});
|
|
4827
|
+
}
|
|
4828
|
+
|
|
4319
4829
|
//#endregion
|
|
4320
4830
|
//#region src/v2/hooks/use-default-render-tool.tsx
|
|
4321
4831
|
/**
|
|
@@ -4399,7 +4909,8 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
|
|
|
4399
4909
|
const userRender = config?.render;
|
|
4400
4910
|
useRenderTool({
|
|
4401
4911
|
name: "*",
|
|
4402
|
-
render: userRender ? (raw) => userRender(adaptRendererProps(raw)) : (raw) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DefaultToolCallRenderer, { ...adaptRendererProps(raw) })
|
|
4912
|
+
render: userRender ? (raw) => userRender(adaptRendererProps(raw)) : (raw) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DefaultToolCallRenderer, { ...adaptRendererProps(raw) }),
|
|
4913
|
+
group: userRender ? config?.group === true : true
|
|
4403
4914
|
}, deps);
|
|
4404
4915
|
}
|
|
4405
4916
|
/**
|
|
@@ -4420,9 +4931,23 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
|
|
|
4420
4931
|
}
|
|
4421
4932
|
}
|
|
4422
4933
|
function DefaultToolCallRenderer({ name, toolCallId, parameters, status, result }) {
|
|
4934
|
+
const group = (0, react.useContext)(ToolCallGroupContext);
|
|
4423
4935
|
const [isExpanded, setIsExpanded] = (0, react.useState)(false);
|
|
4424
4936
|
const isActive = status === "inProgress" || status === "executing";
|
|
4425
4937
|
const isComplete = status === "complete";
|
|
4938
|
+
if (group) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ToolCallRow, {
|
|
4939
|
+
"data-testid": "copilot-tool-render",
|
|
4940
|
+
"data-tool-name": name,
|
|
4941
|
+
"data-tool-call-id": toolCallId,
|
|
4942
|
+
"data-status": status,
|
|
4943
|
+
"data-args": safeStringifyForAttr(parameters),
|
|
4944
|
+
"data-result": safeStringifyForAttr(result),
|
|
4945
|
+
name,
|
|
4946
|
+
parameters,
|
|
4947
|
+
result,
|
|
4948
|
+
status: isComplete ? group.failedIds.has(toolCallId) ? "failed" : "done" : group.active ? "running" : "stopped",
|
|
4949
|
+
appearance: group.appearance
|
|
4950
|
+
});
|
|
4426
4951
|
const statusLabel = isActive ? "Running" : isComplete ? "Done" : status;
|
|
4427
4952
|
const dotClassName = isActive ? "cpk:bg-amber-500" : isComplete ? "cpk:bg-emerald-500" : "cpk:bg-zinc-400";
|
|
4428
4953
|
const badgeClassName = isActive ? "cpk:bg-amber-100 cpk:text-amber-800 cpk:dark:bg-amber-500/15 cpk:dark:text-amber-400" : isComplete ? "cpk:bg-emerald-100 cpk:text-emerald-800 cpk:dark:bg-emerald-500/15 cpk:dark:text-emerald-400" : "cpk:bg-zinc-100 cpk:text-zinc-800 cpk:dark:bg-zinc-700/40 cpk:dark:text-zinc-300";
|
|
@@ -6119,38 +6644,227 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
|
|
|
6119
6644
|
});
|
|
6120
6645
|
}
|
|
6121
6646
|
|
|
6647
|
+
//#endregion
|
|
6648
|
+
//#region src/v2/components/chat/tool-call-display-context.ts
|
|
6649
|
+
/** @internal */
|
|
6650
|
+
const ToolCallDisplayContext = (0, react.createContext)(null);
|
|
6651
|
+
|
|
6652
|
+
//#endregion
|
|
6653
|
+
//#region src/v2/components/chat/tool-call-layout.ts
|
|
6654
|
+
function contentLength(content) {
|
|
6655
|
+
return typeof content === "string" ? content.length : JSON.stringify(content ?? "").length;
|
|
6656
|
+
}
|
|
6657
|
+
const entrySignature = ({ toolCall, toolMessage }) => [
|
|
6658
|
+
toolCall.id,
|
|
6659
|
+
toolCall.function.name,
|
|
6660
|
+
toolCall.function.arguments.length,
|
|
6661
|
+
toolMessage ? `${contentLength(toolMessage.content)}${toolMessage.error ? "!" : ""}` : "-"
|
|
6662
|
+
].join(":");
|
|
6663
|
+
function signatureOf(segments) {
|
|
6664
|
+
return segments.map((segment) => segment.kind === "call" ? `c(${entrySignature(segment.call)})` : `g${segment.trailing ? "*" : ""}(${segment.calls.map(entrySignature).join(",")})`).join("|");
|
|
6665
|
+
}
|
|
6666
|
+
/** Index of tool results by the call they answer. */
|
|
6667
|
+
function getToolResults(messages) {
|
|
6668
|
+
const results = /* @__PURE__ */ new Map();
|
|
6669
|
+
for (const message of messages) if (message.role === "tool") results.set(message.toolCallId, message);
|
|
6670
|
+
return results;
|
|
6671
|
+
}
|
|
6672
|
+
/**
|
|
6673
|
+
* Lays out the tool calls of every assistant message in `rendered`.
|
|
6674
|
+
*
|
|
6675
|
+
* Calls drawn by a renderer that opted into grouping join the group that's
|
|
6676
|
+
* open; anything else that shows between them closes it: assistant text, a
|
|
6677
|
+
* user, reasoning or activity message, or a call drawn by any other renderer. A group belongs to
|
|
6678
|
+
* the message where it starts, so later messages whose calls joined it render
|
|
6679
|
+
* no tool calls themselves.
|
|
6680
|
+
*
|
|
6681
|
+
* @param rendered - The messages as the chat renders them, in order.
|
|
6682
|
+
* @param all - Every message, for finding tool results (a transform may hide them).
|
|
6683
|
+
* @param renderers - The registered renderers.
|
|
6684
|
+
*/
|
|
6685
|
+
function getToolCallLayouts(rendered, all, renderers) {
|
|
6686
|
+
const results = getToolResults(all);
|
|
6687
|
+
const layouts = /* @__PURE__ */ new Map();
|
|
6688
|
+
let open;
|
|
6689
|
+
for (const message of rendered) {
|
|
6690
|
+
if (message.role === "tool") continue;
|
|
6691
|
+
if (message.role !== "assistant") {
|
|
6692
|
+
open = void 0;
|
|
6693
|
+
continue;
|
|
6694
|
+
}
|
|
6695
|
+
if (typeof message.content === "string" && message.content.trim()) open = void 0;
|
|
6696
|
+
const segments = [];
|
|
6697
|
+
layouts.set(message.id, segments);
|
|
6698
|
+
const toolCalls = /* @__PURE__ */ new Map();
|
|
6699
|
+
for (const toolCall of message.toolCalls ?? []) toolCalls.set(toolCall.id, toolCall);
|
|
6700
|
+
for (const toolCall of toolCalls.values()) {
|
|
6701
|
+
const entry = {
|
|
6702
|
+
toolCall,
|
|
6703
|
+
toolMessage: results.get(toolCall.id)
|
|
6704
|
+
};
|
|
6705
|
+
const name = toolCall.function.name;
|
|
6706
|
+
const named = renderers.named.has(name);
|
|
6707
|
+
const rendered = named || renderers.wildcard;
|
|
6708
|
+
const groups = named ? renderers.groupedNames.has(name) : renderers.wildcardGroups;
|
|
6709
|
+
if (!rendered || !groups) {
|
|
6710
|
+
if (rendered) open = void 0;
|
|
6711
|
+
segments.push({
|
|
6712
|
+
kind: "call",
|
|
6713
|
+
id: toolCall.id,
|
|
6714
|
+
call: entry,
|
|
6715
|
+
rendered
|
|
6716
|
+
});
|
|
6717
|
+
} else if (open) open.calls.push(entry);
|
|
6718
|
+
else {
|
|
6719
|
+
open = {
|
|
6720
|
+
kind: "group",
|
|
6721
|
+
id: toolCall.id,
|
|
6722
|
+
calls: [entry],
|
|
6723
|
+
trailing: false
|
|
6724
|
+
};
|
|
6725
|
+
segments.push(open);
|
|
6726
|
+
}
|
|
6727
|
+
}
|
|
6728
|
+
}
|
|
6729
|
+
if (open) open.trailing = true;
|
|
6730
|
+
const layout = /* @__PURE__ */ new Map();
|
|
6731
|
+
for (const [id, segments] of layouts) layout.set(id, {
|
|
6732
|
+
segments,
|
|
6733
|
+
signature: signatureOf(segments)
|
|
6734
|
+
});
|
|
6735
|
+
return layout;
|
|
6736
|
+
}
|
|
6737
|
+
/**
|
|
6738
|
+
* Finds the working phase of every reply in `rendered`: its messages up to the
|
|
6739
|
+
* last one that calls a tool. Text in there was narration; what follows is the
|
|
6740
|
+
* reply itself. Replies that called no tools are omitted, except the latest,
|
|
6741
|
+
* which may be about to.
|
|
6742
|
+
*/
|
|
6743
|
+
function getTurnWork(rendered, layouts) {
|
|
6744
|
+
const turns = /* @__PURE__ */ new Map();
|
|
6745
|
+
let start = 0;
|
|
6746
|
+
while (start < rendered.length) {
|
|
6747
|
+
let end = start;
|
|
6748
|
+
while (end < rendered.length && rendered[end].role !== "user") end++;
|
|
6749
|
+
const key = start > 0 ? rendered[start - 1].id : "start";
|
|
6750
|
+
const visible = rendered.slice(start, end).filter((message) => message.role !== "tool");
|
|
6751
|
+
const isLatest = end === rendered.length;
|
|
6752
|
+
const calls = [];
|
|
6753
|
+
for (const message of visible) for (const segment of layouts.get(message.id)?.segments ?? []) if (segment.kind === "group") calls.push(...segment.calls);
|
|
6754
|
+
else if (segment.rendered) calls.push(segment.call);
|
|
6755
|
+
const shown = new Set(calls.map((entry) => entry.toolCall.id));
|
|
6756
|
+
let lastWork = -1;
|
|
6757
|
+
visible.forEach((message, index) => {
|
|
6758
|
+
if (message.role === "assistant" && message.toolCalls?.some((call) => shown.has(call.id))) lastWork = index;
|
|
6759
|
+
});
|
|
6760
|
+
const first = visible[0];
|
|
6761
|
+
if (first && (calls.length > 0 || isLatest)) {
|
|
6762
|
+
let lastAssistant = -1;
|
|
6763
|
+
visible.forEach((message, index) => {
|
|
6764
|
+
if (message.role === "assistant") lastAssistant = index;
|
|
6765
|
+
});
|
|
6766
|
+
const replyText = visible[lastAssistant]?.content;
|
|
6767
|
+
const endsWithWork = lastAssistant >= 0 && lastAssistant <= lastWork && typeof replyText === "string" && replyText.trim().length > 0;
|
|
6768
|
+
turns.set(key, {
|
|
6769
|
+
key,
|
|
6770
|
+
firstMessageId: first.id,
|
|
6771
|
+
workMessageIds: new Set(visible.slice(0, lastWork + 1).map((message) => message.id)),
|
|
6772
|
+
replyTextMessageId: endsWithWork ? visible[lastAssistant].id : void 0,
|
|
6773
|
+
calls,
|
|
6774
|
+
isLatest
|
|
6775
|
+
});
|
|
6776
|
+
}
|
|
6777
|
+
start = end + 1;
|
|
6778
|
+
}
|
|
6779
|
+
return turns;
|
|
6780
|
+
}
|
|
6781
|
+
|
|
6122
6782
|
//#endregion
|
|
6123
6783
|
//#region src/v2/components/chat/CopilotChatToolCallsView.tsx
|
|
6124
|
-
|
|
6784
|
+
const appearances = {
|
|
6785
|
+
grouped: "card",
|
|
6786
|
+
line: "line",
|
|
6787
|
+
stacked: "stack"
|
|
6788
|
+
};
|
|
6789
|
+
function CopilotChatToolCallsView({ message, messages = [], display: displayProp, group }) {
|
|
6125
6790
|
const renderToolCall = useRenderToolCall();
|
|
6791
|
+
const rendererNames = useToolCallRendererNames();
|
|
6126
6792
|
const { copilotkit } = useCopilotKit();
|
|
6127
6793
|
const subscribe = (0, react.useCallback)((onChange) => copilotkit.ɵsubscribeToLearningConfigured(onChange), [copilotkit]);
|
|
6128
6794
|
const getSnapshot = () => copilotkit.ɵlearningConfigured;
|
|
6129
6795
|
const learningConfigured = (0, react.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
|
|
6796
|
+
const context = (0, react.useContext)(ToolCallDisplayContext);
|
|
6797
|
+
const display = displayProp ?? context?.display ?? "grouped";
|
|
6798
|
+
const viewLayout = context?.layouts.get(message.id);
|
|
6799
|
+
const layout = (0, react.useMemo)(() => {
|
|
6800
|
+
if (display === "separate") return void 0;
|
|
6801
|
+
return viewLayout ?? getToolCallLayouts([message], messages, rendererNames).get(message.id);
|
|
6802
|
+
}, [
|
|
6803
|
+
display,
|
|
6804
|
+
viewLayout,
|
|
6805
|
+
message,
|
|
6806
|
+
messages,
|
|
6807
|
+
rendererNames
|
|
6808
|
+
]);
|
|
6130
6809
|
if (!message.toolCalls || message.toolCalls.length === 0) return null;
|
|
6131
|
-
|
|
6810
|
+
const renderCall = (entry) => {
|
|
6132
6811
|
const rendered = renderToolCall({
|
|
6133
|
-
toolCall,
|
|
6134
|
-
toolMessage:
|
|
6812
|
+
toolCall: entry.toolCall,
|
|
6813
|
+
toolMessage: entry.toolMessage
|
|
6135
6814
|
});
|
|
6136
|
-
if (rendered === null) return
|
|
6137
|
-
if (!learningConfigured) return rendered;
|
|
6815
|
+
if (rendered === null || !learningConfigured) return rendered;
|
|
6138
6816
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6139
|
-
"data-tool-call-id": toolCall.id,
|
|
6817
|
+
"data-tool-call-id": entry.toolCall.id,
|
|
6140
6818
|
style: { display: "contents" },
|
|
6141
6819
|
children: rendered
|
|
6142
|
-
}
|
|
6820
|
+
});
|
|
6821
|
+
};
|
|
6822
|
+
if (!layout) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: message.toolCalls.map((toolCall) => {
|
|
6823
|
+
const toolMessage = messages.find((m) => m.role === "tool" && m.toolCallId === toolCall.id);
|
|
6824
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react.default.Fragment, { children: renderCall({
|
|
6825
|
+
toolCall,
|
|
6826
|
+
toolMessage
|
|
6827
|
+
}) }, toolCall.id);
|
|
6828
|
+
}) });
|
|
6829
|
+
const workOpen = context?.workOpen.get(message.id);
|
|
6830
|
+
const groupActive = (trailing) => trailing && (context ? context.isRunning : true);
|
|
6831
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: layout.segments.map((segment) => {
|
|
6832
|
+
if (segment.kind === "call") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react.default.Fragment, { children: renderCall(segment.call) }, segment.id);
|
|
6833
|
+
if (display === "turn") {
|
|
6834
|
+
const failedIds = new Set(segment.calls.filter((call) => call.toolMessage?.error).map((call) => call.toolCall.id));
|
|
6835
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Collapsible, {
|
|
6836
|
+
open: workOpen ?? true,
|
|
6837
|
+
className: "cpk:-mx-2",
|
|
6838
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6839
|
+
className: "cpk:px-2 cpk:py-1.5",
|
|
6840
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ToolCallGroupContext.Provider, {
|
|
6841
|
+
value: {
|
|
6842
|
+
appearance: "line",
|
|
6843
|
+
failedIds,
|
|
6844
|
+
active: groupActive(segment.trailing)
|
|
6845
|
+
},
|
|
6846
|
+
children: segment.calls.map((call) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react.default.Fragment, { children: renderCall(call) }, call.toolCall.id))
|
|
6847
|
+
})
|
|
6848
|
+
})
|
|
6849
|
+
}, segment.id);
|
|
6850
|
+
}
|
|
6851
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react.default.Fragment, { children: renderSlot(group, CopilotChatToolCallGroup, {
|
|
6852
|
+
calls: segment.calls,
|
|
6853
|
+
renderCall,
|
|
6854
|
+
appearance: appearances[display] ?? "card",
|
|
6855
|
+
isActive: groupActive(segment.trailing)
|
|
6856
|
+
}) }, segment.id);
|
|
6143
6857
|
}) });
|
|
6144
6858
|
}
|
|
6145
6859
|
|
|
6146
6860
|
//#endregion
|
|
6147
6861
|
//#region src/v2/components/chat/CopilotChatInspectorButton.tsx
|
|
6148
6862
|
let shortcutsHidden = false;
|
|
6149
|
-
const listeners = /* @__PURE__ */ new Set();
|
|
6863
|
+
const listeners$1 = /* @__PURE__ */ new Set();
|
|
6150
6864
|
const subscribe = (listener) => {
|
|
6151
|
-
listeners.add(listener);
|
|
6865
|
+
listeners$1.add(listener);
|
|
6152
6866
|
return () => {
|
|
6153
|
-
listeners.delete(listener);
|
|
6867
|
+
listeners$1.delete(listener);
|
|
6154
6868
|
};
|
|
6155
6869
|
};
|
|
6156
6870
|
const getSnapshot = () => shortcutsHidden;
|
|
@@ -6160,7 +6874,7 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
|
|
|
6160
6874
|
}
|
|
6161
6875
|
function hideShortcuts() {
|
|
6162
6876
|
shortcutsHidden = true;
|
|
6163
|
-
listeners.forEach((listener) => listener());
|
|
6877
|
+
listeners$1.forEach((listener) => listener());
|
|
6164
6878
|
}
|
|
6165
6879
|
function InspectorKiteIcon({ className, ...props }) {
|
|
6166
6880
|
const id = (0, react.useId)();
|
|
@@ -6427,47 +7141,544 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
|
|
|
6427
7141
|
}
|
|
6428
7142
|
|
|
6429
7143
|
//#endregion
|
|
6430
|
-
//#region src/v2/components/
|
|
6431
|
-
|
|
6432
|
-
|
|
6433
|
-
|
|
6434
|
-
|
|
6435
|
-
function BoundInspectorButton({ inspectorButton, messageId, openInspector, ...props }) {
|
|
6436
|
-
const chatConfiguration = useCopilotChatConfiguration();
|
|
6437
|
-
return renderSlot(inspectorButton, CopilotChatAssistantMessage.InspectorButton, {
|
|
6438
|
-
...props,
|
|
6439
|
-
onClick: () => openInspector({
|
|
6440
|
-
messageId,
|
|
6441
|
-
threadId: chatConfiguration?.threadId,
|
|
6442
|
-
agentId: chatConfiguration?.agentId
|
|
6443
|
-
})
|
|
7144
|
+
//#region src/v2/components/ui/popover.tsx
|
|
7145
|
+
function Popover({ ...props }) {
|
|
7146
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_radix_ui_react_popover.Root, {
|
|
7147
|
+
"data-slot": "popover",
|
|
7148
|
+
...props
|
|
6444
7149
|
});
|
|
6445
7150
|
}
|
|
6446
|
-
function
|
|
6447
|
-
|
|
6448
|
-
|
|
6449
|
-
|
|
6450
|
-
|
|
6451
|
-
|
|
6452
|
-
|
|
6453
|
-
|
|
6454
|
-
|
|
7151
|
+
function PopoverAnchor({ ...props }) {
|
|
7152
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_radix_ui_react_popover.Anchor, {
|
|
7153
|
+
"data-slot": "popover-anchor",
|
|
7154
|
+
...props
|
|
7155
|
+
});
|
|
7156
|
+
}
|
|
7157
|
+
/**
|
|
7158
|
+
* Popover content in a portal, so it floats over the page instead of taking
|
|
7159
|
+
* room in the layout, with the CopilotKit style scope on it.
|
|
7160
|
+
*/
|
|
7161
|
+
const PopoverContent = react.forwardRef(({ className, align = "start", sideOffset = 6, ...props }, ref) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_radix_ui_react_popover.Portal, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_radix_ui_react_popover.Content, {
|
|
7162
|
+
ref,
|
|
7163
|
+
"data-copilotkit": true,
|
|
7164
|
+
"data-copilotkit-popover": true,
|
|
7165
|
+
"data-slot": "popover-content",
|
|
7166
|
+
align,
|
|
7167
|
+
sideOffset,
|
|
7168
|
+
className: cn("cpk:z-50 cpk:outline-none cpk:data-[state=open]:animate-in cpk:data-[state=open]:fade-in-0 cpk:data-[state=open]:zoom-in-95 cpk:data-[side=bottom]:slide-in-from-top-1 cpk:data-[side=top]:slide-in-from-bottom-1", className),
|
|
7169
|
+
...props
|
|
7170
|
+
}) }));
|
|
7171
|
+
PopoverContent.displayName = "PopoverContent";
|
|
7172
|
+
|
|
7173
|
+
//#endregion
|
|
7174
|
+
//#region src/v2/lib/message-feedback.ts
|
|
7175
|
+
/** Trajectory event name for a rating of one assistant message. */
|
|
7176
|
+
const MESSAGE_FEEDBACK_EVENT_NAME = "message.feedback";
|
|
7177
|
+
/** Longest comment kept, in characters; the rest is cut so the event stays small. */
|
|
7178
|
+
const MESSAGE_FEEDBACK_MAX_COMMENT_LENGTH = 1e3;
|
|
7179
|
+
/** Longest excerpt of the rated response sent with the rating, in characters. */
|
|
7180
|
+
const RESPONSE_EXCERPT_LENGTH = 500;
|
|
7181
|
+
const ratings = /* @__PURE__ */ new Map();
|
|
7182
|
+
const listeners = /* @__PURE__ */ new Map();
|
|
7183
|
+
const threadKey = (agentId, threadId) => JSON.stringify([agentId, threadId]);
|
|
7184
|
+
const messageKey = (agentId, threadId, messageId) => JSON.stringify([
|
|
7185
|
+
agentId,
|
|
7186
|
+
threadId,
|
|
7187
|
+
messageId
|
|
7188
|
+
]);
|
|
7189
|
+
/** Cuts `text` to `max` characters without splitting a surrogate pair. */
|
|
7190
|
+
const clip = (text, max) => {
|
|
7191
|
+
const characters = Array.from(text);
|
|
7192
|
+
return characters.length > max ? characters.slice(0, max).join("") : text;
|
|
7193
|
+
};
|
|
7194
|
+
/** The comment as kept and sent: trimmed and capped, or none. */
|
|
7195
|
+
const normalizeComment = (comment) => {
|
|
7196
|
+
if (typeof comment !== "string") return void 0;
|
|
7197
|
+
const text = clip(comment.trim(), MESSAGE_FEEDBACK_MAX_COMMENT_LENGTH);
|
|
7198
|
+
return text === "" ? void 0 : text;
|
|
7199
|
+
};
|
|
7200
|
+
/** The rating this page gave one message, if any. */
|
|
7201
|
+
function getMessageFeedback(agentId, threadId, messageId) {
|
|
7202
|
+
return ratings.get(messageKey(agentId, threadId, messageId));
|
|
7203
|
+
}
|
|
7204
|
+
/** Calls `listener` whenever a rating in this Thread changes. */
|
|
7205
|
+
function subscribeToMessageFeedback(agentId, threadId, listener) {
|
|
7206
|
+
const key = threadKey(agentId, threadId);
|
|
7207
|
+
let set = listeners.get(key);
|
|
7208
|
+
if (set === void 0) {
|
|
7209
|
+
set = /* @__PURE__ */ new Set();
|
|
7210
|
+
listeners.set(key, set);
|
|
7211
|
+
}
|
|
7212
|
+
set.add(listener);
|
|
7213
|
+
return () => {
|
|
7214
|
+
set.delete(listener);
|
|
7215
|
+
if (set.size === 0) listeners.delete(key);
|
|
7216
|
+
};
|
|
7217
|
+
}
|
|
7218
|
+
/**
|
|
7219
|
+
* Sets (or, with `null`, clears) this page's rating of one message and sends
|
|
7220
|
+
* it to the active Trajectory. Every change is a new event; the newest event
|
|
7221
|
+
* for a `feedbackId` is the current one. Like any Trajectory event, a change
|
|
7222
|
+
* made while no Trajectory captures, for example during a reconnect, is not
|
|
7223
|
+
* sent; the page still shows it.
|
|
7224
|
+
*/
|
|
7225
|
+
function setMessageFeedback(params) {
|
|
7226
|
+
const { copilotkit, agentId, threadId, message } = params;
|
|
7227
|
+
const comment = normalizeComment(params.feedback?.comment);
|
|
7228
|
+
const feedback = params.feedback && {
|
|
7229
|
+
rating: params.feedback.rating,
|
|
7230
|
+
...comment ? { comment } : {}
|
|
7231
|
+
};
|
|
7232
|
+
const key = messageKey(agentId, threadId, message.id);
|
|
7233
|
+
if (feedback) ratings.set(key, feedback);
|
|
7234
|
+
else ratings.delete(key);
|
|
7235
|
+
for (const listener of listeners.get(threadKey(agentId, threadId)) ?? []) listener();
|
|
7236
|
+
const runId = copilotkit.getRunIdForMessage(agentId, threadId, message.id);
|
|
7237
|
+
copilotkit.emitTrajectoryEvent(MESSAGE_FEEDBACK_EVENT_NAME, {
|
|
7238
|
+
feedbackId: `${threadId}:${message.id}`,
|
|
7239
|
+
threadId,
|
|
7240
|
+
messageId: message.id,
|
|
7241
|
+
agentId,
|
|
7242
|
+
...runId ? { runId } : {},
|
|
7243
|
+
rating: feedback?.rating ?? null,
|
|
7244
|
+
...feedback?.comment ? { comment: feedback.comment } : {},
|
|
7245
|
+
...copilotkit.ɵlearningCapturesAgentText ? { response: clip(message.content ?? "", RESPONSE_EXCERPT_LENGTH) } : {}
|
|
7246
|
+
});
|
|
7247
|
+
}
|
|
7248
|
+
|
|
7249
|
+
//#endregion
|
|
7250
|
+
//#region src/v2/components/chat/message-feedback.tsx
|
|
7251
|
+
/**
|
|
7252
|
+
* Set by the message view while Learning is on for this chat. Assistant
|
|
7253
|
+
* messages without it show thumbs only when the app passes its own handlers
|
|
7254
|
+
* or thumb slots.
|
|
7255
|
+
*/
|
|
7256
|
+
const MessageFeedbackScopeContext = (0, react.createContext)(null);
|
|
7257
|
+
const capturedCores = /* @__PURE__ */ new WeakSet();
|
|
7258
|
+
const rememberCapture = (copilotkit) => {
|
|
7259
|
+
if (capturedCores.has(copilotkit)) return;
|
|
7260
|
+
capturedCores.add(copilotkit);
|
|
7261
|
+
const unsubscribe = copilotkit.ɵsubscribeToLearningConfigured(() => {
|
|
7262
|
+
if (copilotkit.ɵlearningConfigured) return;
|
|
7263
|
+
capturedCores.delete(copilotkit);
|
|
7264
|
+
unsubscribe();
|
|
7265
|
+
});
|
|
7266
|
+
};
|
|
7267
|
+
/**
|
|
7268
|
+
* Whether the thumbs record feedback for Learning. True once a Trajectory of
|
|
7269
|
+
* this Core has started and as long as Learning stays configured, also while
|
|
7270
|
+
* capture reconnects or is stopped, so the buttons do not flicker. Ratings
|
|
7271
|
+
* given meanwhile still show but, like any Trajectory event, are not
|
|
7272
|
+
* sent. A capture that never starts (for example without a license) leaves it
|
|
7273
|
+
* false.
|
|
7274
|
+
*/
|
|
7275
|
+
function useLearningFeedbackEnabled(copilotkit) {
|
|
7276
|
+
const configured = (0, react.useSyncExternalStore)((0, react.useCallback)((onChange) => copilotkit.ɵsubscribeToLearningConfigured(onChange), [copilotkit]), () => copilotkit.ɵlearningConfigured, () => false);
|
|
7277
|
+
const capturing = (0, react.useSyncExternalStore)((0, react.useCallback)((onChange) => copilotkit.subscribe({ onTrajectoryChanged: onChange }).unsubscribe, [copilotkit]), () => copilotkit.trajectoryId !== null, () => false);
|
|
7278
|
+
(0, react.useEffect)(() => {
|
|
7279
|
+
if (capturing) rememberCapture(copilotkit);
|
|
7280
|
+
}, [capturing, copilotkit]);
|
|
7281
|
+
return configured && (capturing || capturedCores.has(copilotkit));
|
|
7282
|
+
}
|
|
7283
|
+
const noSubscription = () => () => {};
|
|
7284
|
+
/** Feedback controls for `message`, or `null` when this chat collects none. */
|
|
7285
|
+
function useMessageFeedback(message) {
|
|
7286
|
+
const scope = (0, react.useContext)(MessageFeedbackScopeContext);
|
|
7287
|
+
const subscribe = (0, react.useCallback)((onChange) => scope ? subscribeToMessageFeedback(scope.agentId, scope.threadId, onChange) : noSubscription(), [scope]);
|
|
7288
|
+
const getSnapshot = () => scope ? getMessageFeedback(scope.agentId, scope.threadId, message.id) : void 0;
|
|
7289
|
+
const feedback = (0, react.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
|
|
7290
|
+
if (!scope) return null;
|
|
7291
|
+
const save = (next) => setMessageFeedback({
|
|
7292
|
+
...scope,
|
|
7293
|
+
message,
|
|
7294
|
+
feedback: next
|
|
7295
|
+
});
|
|
7296
|
+
return {
|
|
7297
|
+
feedback,
|
|
7298
|
+
rate: (rating) => {
|
|
7299
|
+
if (feedback?.rating !== rating) save({ rating });
|
|
7300
|
+
},
|
|
7301
|
+
clear: () => {
|
|
7302
|
+
if (feedback) save(null);
|
|
7303
|
+
},
|
|
7304
|
+
comment: (comment) => {
|
|
7305
|
+
if (feedback) save({
|
|
7306
|
+
rating: feedback.rating,
|
|
7307
|
+
comment
|
|
7308
|
+
});
|
|
7309
|
+
}
|
|
7310
|
+
};
|
|
7311
|
+
}
|
|
7312
|
+
/**
|
|
7313
|
+
* How long the pointer may be away from the rating and its comment before the
|
|
7314
|
+
* comment closes: enough to cross the gap between them, short enough that
|
|
7315
|
+
* passing over a rating does not leave it open.
|
|
7316
|
+
*/
|
|
7317
|
+
const FEEDBACK_COMMENT_CLOSE_DELAY_MS = 150;
|
|
7318
|
+
/**
|
|
7319
|
+
* Drives the comment popover of a rated message.
|
|
7320
|
+
*
|
|
7321
|
+
* It opens when a rating is given and whenever the pointer or keyboard focus
|
|
7322
|
+
* reaches the chosen thumb, with the saved comment in the field. It closes by
|
|
7323
|
+
* itself shortly after the pointer leaves the thumb and the popover, unless
|
|
7324
|
+
* focus is in the field: then it stays until focus moves away, Enter, or
|
|
7325
|
+
* Escape. Closing saves a changed comment; Escape, a click on a thumb, and
|
|
7326
|
+
* removing the rating discard it.
|
|
7327
|
+
*/
|
|
7328
|
+
function useFeedbackComment(controls) {
|
|
7329
|
+
const [open, setOpen] = (0, react.useState)(false);
|
|
7330
|
+
const [draft, setDraft] = (0, react.useState)("");
|
|
7331
|
+
const [focusRequest, setFocusRequest] = (0, react.useState)(0);
|
|
7332
|
+
const inputRef = (0, react.useRef)(null);
|
|
7333
|
+
const timer = (0, react.useRef)(void 0);
|
|
7334
|
+
const editing = (0, react.useRef)(false);
|
|
7335
|
+
const focusWaiting = (0, react.useRef)(false);
|
|
7336
|
+
const pointerOver = (0, react.useRef)(false);
|
|
7337
|
+
const returning = (0, react.useRef)(false);
|
|
7338
|
+
const latest = (0, react.useRef)({
|
|
7339
|
+
controls,
|
|
7340
|
+
draft,
|
|
7341
|
+
open
|
|
7342
|
+
});
|
|
7343
|
+
latest.current = {
|
|
7344
|
+
...latest.current,
|
|
7345
|
+
controls,
|
|
7346
|
+
draft,
|
|
7347
|
+
open
|
|
7348
|
+
};
|
|
7349
|
+
const takeFocusRequest = (0, react.useCallback)(() => {
|
|
7350
|
+
const waiting = focusWaiting.current;
|
|
7351
|
+
focusWaiting.current = false;
|
|
7352
|
+
return waiting;
|
|
7353
|
+
}, []);
|
|
7354
|
+
const cancelClose = (0, react.useCallback)(() => {
|
|
7355
|
+
if (timer.current === void 0) return;
|
|
7356
|
+
clearTimeout(timer.current);
|
|
7357
|
+
timer.current = void 0;
|
|
7358
|
+
}, []);
|
|
7359
|
+
(0, react.useEffect)(() => cancelClose, [cancelClose]);
|
|
7360
|
+
const savedComment = (0, react.useCallback)(() => latest.current.controls?.feedback?.comment ?? "", []);
|
|
7361
|
+
(0, react.useEffect)(() => () => {
|
|
7362
|
+
const { open: wasOpen, controls: current, draft: text } = latest.current;
|
|
7363
|
+
if (wasOpen && current?.feedback && text.trim() !== savedComment()) current.comment(text);
|
|
7364
|
+
}, []);
|
|
7365
|
+
const close = (0, react.useCallback)(({ save = true } = {}) => {
|
|
7366
|
+
cancelClose();
|
|
7367
|
+
focusWaiting.current = false;
|
|
7368
|
+
pointerOver.current = false;
|
|
7369
|
+
if (!latest.current.open) return;
|
|
7370
|
+
const current = latest.current.controls;
|
|
7371
|
+
if (save && current?.feedback && latest.current.draft.trim() !== savedComment()) current.comment(latest.current.draft);
|
|
7372
|
+
editing.current = false;
|
|
7373
|
+
latest.current = {
|
|
7374
|
+
...latest.current,
|
|
7375
|
+
open: false
|
|
7376
|
+
};
|
|
7377
|
+
setOpen(false);
|
|
7378
|
+
}, [cancelClose, savedComment]);
|
|
7379
|
+
const show = ({ comment, focus }) => {
|
|
7380
|
+
cancelClose();
|
|
7381
|
+
latest.current = {
|
|
7382
|
+
...latest.current,
|
|
7383
|
+
open: true,
|
|
7384
|
+
draft: comment
|
|
7385
|
+
};
|
|
7386
|
+
setDraft(comment);
|
|
7387
|
+
if (focus) {
|
|
7388
|
+
focusWaiting.current = true;
|
|
7389
|
+
setFocusRequest((request) => request + 1);
|
|
7390
|
+
}
|
|
7391
|
+
setOpen(true);
|
|
7392
|
+
};
|
|
7393
|
+
return {
|
|
7394
|
+
open,
|
|
7395
|
+
draft,
|
|
7396
|
+
setDraft,
|
|
7397
|
+
focusRequest,
|
|
7398
|
+
takeFocusRequest,
|
|
7399
|
+
inputRef,
|
|
7400
|
+
show,
|
|
7401
|
+
enter: (via = "focus") => {
|
|
7402
|
+
cancelClose();
|
|
7403
|
+
if (via === "pointer") pointerOver.current = true;
|
|
7404
|
+
if (returning.current) return;
|
|
7405
|
+
if (!latest.current.open && latest.current.controls?.feedback) show({
|
|
7406
|
+
comment: savedComment(),
|
|
7407
|
+
focus: false
|
|
7408
|
+
});
|
|
7409
|
+
},
|
|
7410
|
+
leave: (via = "focus") => {
|
|
7411
|
+
if (via === "pointer") pointerOver.current = false;
|
|
7412
|
+
else if (pointerOver.current) return;
|
|
7413
|
+
cancelClose();
|
|
7414
|
+
timer.current = setTimeout(() => {
|
|
7415
|
+
timer.current = void 0;
|
|
7416
|
+
if (!editing.current) close();
|
|
7417
|
+
}, FEEDBACK_COMMENT_CLOSE_DELAY_MS);
|
|
7418
|
+
},
|
|
7419
|
+
setEditing: (value) => {
|
|
7420
|
+
editing.current = value;
|
|
7421
|
+
},
|
|
7422
|
+
close,
|
|
7423
|
+
returnFocus: (target) => {
|
|
7424
|
+
returning.current = true;
|
|
7425
|
+
try {
|
|
7426
|
+
target?.focus();
|
|
7427
|
+
} finally {
|
|
7428
|
+
returning.current = false;
|
|
7429
|
+
}
|
|
7430
|
+
}
|
|
7431
|
+
};
|
|
7432
|
+
}
|
|
7433
|
+
|
|
7434
|
+
//#endregion
|
|
7435
|
+
//#region src/v2/components/chat/CopilotChatAssistantMessage.tsx
|
|
7436
|
+
/**
|
|
7437
|
+
* In the `"turn"` tool-call display, text in a reply's working phase was
|
|
7438
|
+
* narration: it fades to muted once a call follows it, and folds away with the
|
|
7439
|
+
* rest of the work when the reply is done. The wrapper is there for every
|
|
7440
|
+
* message in that display, so text that turns into narration keeps its node
|
|
7441
|
+
* (and its place) rather than remounting.
|
|
7442
|
+
*/
|
|
7443
|
+
function WorkText({ messageId, children }) {
|
|
7444
|
+
const context = (0, react.useContext)(ToolCallDisplayContext);
|
|
7445
|
+
if (context?.display !== "turn") return children;
|
|
7446
|
+
const open = context.workTextOpen.get(messageId);
|
|
7447
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Collapsible, {
|
|
7448
|
+
open: open ?? true,
|
|
7449
|
+
className: "cpk:-mx-2",
|
|
7450
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
7451
|
+
className: "cpk:px-2",
|
|
7452
|
+
"data-work-text": open === void 0 ? "reply" : "narration",
|
|
7453
|
+
children
|
|
7454
|
+
})
|
|
7455
|
+
});
|
|
7456
|
+
}
|
|
7457
|
+
/**
|
|
7458
|
+
* Binds the Inspector action to the active chat without making the full
|
|
7459
|
+
* assistant message subscribe to chat configuration changes.
|
|
7460
|
+
*/
|
|
7461
|
+
function BoundInspectorButton({ inspectorButton, messageId, openInspector, ...props }) {
|
|
7462
|
+
const chatConfiguration = useCopilotChatConfiguration();
|
|
7463
|
+
return renderSlot(inspectorButton, CopilotChatAssistantMessage.InspectorButton, {
|
|
7464
|
+
...props,
|
|
7465
|
+
onClick: () => openInspector({
|
|
7466
|
+
messageId,
|
|
7467
|
+
threadId: chatConfiguration?.threadId,
|
|
7468
|
+
agentId: chatConfiguration?.agentId
|
|
7469
|
+
})
|
|
7470
|
+
});
|
|
7471
|
+
}
|
|
7472
|
+
/** Whether focus came from the keyboard; a pointer click also focuses buttons. */
|
|
7473
|
+
function isFocusVisible(element) {
|
|
7474
|
+
try {
|
|
7475
|
+
return element.matches(":focus-visible");
|
|
7476
|
+
} catch {
|
|
7477
|
+
return false;
|
|
7478
|
+
}
|
|
7479
|
+
}
|
|
7480
|
+
const HIDDEN_TOO = {
|
|
7481
|
+
checkVisibilityCSS: true,
|
|
7482
|
+
visibilityProperty: true
|
|
7483
|
+
};
|
|
7484
|
+
const FOCUSABLE = [
|
|
7485
|
+
"a[href]",
|
|
7486
|
+
"button:not([disabled])",
|
|
7487
|
+
"input:not([disabled])",
|
|
7488
|
+
"select:not([disabled])",
|
|
7489
|
+
"textarea:not([disabled])",
|
|
7490
|
+
"[tabindex]"
|
|
7491
|
+
].map((selector) => `${selector}:not([tabindex="-1"]):not([data-radix-focus-guard])`).join(", ");
|
|
7492
|
+
/** Approximately the element Tab reaches after `element`, outside `skip`. */
|
|
7493
|
+
function nextFocusable(element, skip) {
|
|
7494
|
+
const all = Array.from(element.ownerDocument.querySelectorAll(FOCUSABLE)).filter((candidate) => candidate === element || !skip?.contains(candidate) && !candidate.closest("[hidden], [inert]"));
|
|
7495
|
+
const index = all.indexOf(element);
|
|
7496
|
+
return index === -1 ? null : all[index + 1] ?? null;
|
|
7497
|
+
}
|
|
7498
|
+
/**
|
|
7499
|
+
* The comment popover of a rated message, pointing at the chosen thumb. Kept
|
|
7500
|
+
* apart so only it, not the whole message, follows chat configuration.
|
|
7501
|
+
*
|
|
7502
|
+
* The popover lives in a portal, so it keeps keyboard order by hand: Shift+Tab
|
|
7503
|
+
* from its start returns to the thumb, Tab from its end moves on to the
|
|
7504
|
+
* control after the thumb, and Enter or Escape inside it returns to the thumb.
|
|
7505
|
+
*/
|
|
7506
|
+
function FeedbackCommentPopover({ feedbackComment, comment, savedComment, rating, anchor, messageId }) {
|
|
7507
|
+
const labels = useCopilotChatConfiguration()?.labels ?? CopilotChatDefaultLabels;
|
|
7508
|
+
const contentRef = (0, react.useRef)(null);
|
|
7509
|
+
const focusInside = () => contentRef.current?.contains(document.activeElement) ?? false;
|
|
7510
|
+
const { focusRequest, takeFocusRequest, inputRef } = comment;
|
|
7511
|
+
const focusField = (0, react.useCallback)(() => {
|
|
7512
|
+
if (inputRef.current && takeFocusRequest()) inputRef.current.focus();
|
|
7513
|
+
}, [inputRef, takeFocusRequest]);
|
|
7514
|
+
(0, react.useEffect)(() => focusField(), [focusRequest, focusField]);
|
|
7515
|
+
/** Whether `target` is a thumb of this message, whose click decides itself. */
|
|
7516
|
+
const isOwnThumb = (target) => {
|
|
7517
|
+
return (target instanceof Element ? target.closest("[data-copilotkit-rating]") : null)?.closest("[data-message-id]")?.getAttribute("data-message-id") === messageId;
|
|
7518
|
+
};
|
|
7519
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Popover, {
|
|
7520
|
+
open: comment.open,
|
|
7521
|
+
onOpenChange: (open) => {
|
|
7522
|
+
if (!open) comment.close();
|
|
7523
|
+
},
|
|
7524
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(PopoverAnchor, { virtualRef: anchor }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PopoverContent, {
|
|
7525
|
+
ref: contentRef,
|
|
7526
|
+
side: "bottom",
|
|
7527
|
+
collisionPadding: 8,
|
|
7528
|
+
hideWhenDetached: true,
|
|
7529
|
+
"aria-label": labels.assistantMessageFeedbackCommentPlaceholder,
|
|
7530
|
+
"data-copilotkit-ignore": true,
|
|
7531
|
+
onOpenAutoFocus: (event) => {
|
|
7532
|
+
event.preventDefault();
|
|
7533
|
+
focusField();
|
|
7534
|
+
},
|
|
7535
|
+
onCloseAutoFocus: (event) => event.preventDefault(),
|
|
7536
|
+
onInteractOutside: (event) => {
|
|
7537
|
+
if (isOwnThumb(event.target)) event.preventDefault();
|
|
7538
|
+
},
|
|
7539
|
+
onEscapeKeyDown: (event) => {
|
|
7540
|
+
const returnFocus = focusInside();
|
|
7541
|
+
if (returnFocus) event.stopPropagation();
|
|
7542
|
+
comment.close({ save: false });
|
|
7543
|
+
if (returnFocus) comment.returnFocus(anchor.current);
|
|
7544
|
+
},
|
|
7545
|
+
onKeyDown: (event) => {
|
|
7546
|
+
if (event.key !== "Tab") return;
|
|
7547
|
+
const focusables = Array.from(contentRef.current?.querySelectorAll(FOCUSABLE) ?? []);
|
|
7548
|
+
if (!(event.shiftKey ? document.activeElement === focusables[0] : document.activeElement === focusables[focusables.length - 1]) || !anchor.current?.isConnected) return;
|
|
7549
|
+
event.preventDefault();
|
|
7550
|
+
const target = event.shiftKey ? anchor.current : nextFocusable(anchor.current, contentRef.current) ?? anchor.current;
|
|
7551
|
+
comment.close();
|
|
7552
|
+
if (target === anchor.current) comment.returnFocus(target);
|
|
7553
|
+
else target.focus();
|
|
7554
|
+
},
|
|
7555
|
+
onPointerEnter: () => comment.enter("pointer"),
|
|
7556
|
+
onPointerLeave: () => comment.leave("pointer"),
|
|
7557
|
+
className: "cpk:z-[1300]",
|
|
7558
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react.Fragment, { children: renderSlot(feedbackComment, CopilotChatAssistantMessage.FeedbackComment, {
|
|
7559
|
+
value: comment.draft,
|
|
7560
|
+
savedComment,
|
|
7561
|
+
inputRef: comment.inputRef,
|
|
7562
|
+
onChange: comment.setDraft,
|
|
7563
|
+
onSubmit: () => {
|
|
7564
|
+
comment.close();
|
|
7565
|
+
comment.returnFocus(anchor.current);
|
|
7566
|
+
},
|
|
7567
|
+
onEditingChange: comment.setEditing,
|
|
7568
|
+
onLeave: (next) => {
|
|
7569
|
+
if (next && (contentRef.current?.contains(next) || isOwnThumb(next))) return;
|
|
7570
|
+
comment.leave();
|
|
7571
|
+
}
|
|
7572
|
+
}) }, rating)
|
|
7573
|
+
})]
|
|
7574
|
+
});
|
|
7575
|
+
}
|
|
7576
|
+
function CopilotChatAssistantMessage({ message, messages, isRunning, isLatest, onThumbsUp, onThumbsDown, onReadAloud, onRegenerate, additionalToolbarItems, toolbarVisible = true, markdownRenderer, toolbar, copyButton, inspectorButton, thumbsUpButton, thumbsDownButton, readAloudButton, regenerateButton, feedbackComment: feedbackCommentSlot, toolCallsView, children, className, ...props }) {
|
|
7577
|
+
useKatexStyles();
|
|
7578
|
+
const { isInspectorEnabled, openInspector } = useCopilotKitInspector();
|
|
7579
|
+
const shortcutsHidden = useInspectorShortcutsHidden();
|
|
7580
|
+
const showInspectorShortcut = isInspectorEnabled && !shortcutsHidden;
|
|
7581
|
+
const feedback = useMessageFeedback(message);
|
|
7582
|
+
const comment = useFeedbackComment(feedback);
|
|
7583
|
+
const rating = feedback?.feedback?.rating;
|
|
7584
|
+
const root = (0, react.useRef)(null);
|
|
7585
|
+
const commentAnchor = (0, react.useRef)(null);
|
|
7586
|
+
const commentRating = (0, react.useRef)(rating);
|
|
7587
|
+
(0, react.useLayoutEffect)(() => {
|
|
7588
|
+
if (comment.open && !commentAnchor.current?.isConnected && rating) commentAnchor.current = root.current?.querySelector(`[data-copilotkit-rating="${rating}"]`) ?? root.current?.querySelector("button[aria-pressed=\"true\"]") ?? null;
|
|
7589
|
+
});
|
|
7590
|
+
/**
|
|
7591
|
+
* Thumbs are toggles: a new rating is saved and opens its comment, and
|
|
7592
|
+
* clicking the chosen thumb again removes the rating. A keyboard click
|
|
7593
|
+
* (`detail` 0) moves focus into the comment, as there is no pointer.
|
|
7594
|
+
* Custom thumb slots may call `onClick` without an event.
|
|
7595
|
+
*
|
|
7596
|
+
* @returns Whether the app's handler should run: true for a new rating and
|
|
7597
|
+
* whenever this chat does not record ratings, false when one is removed.
|
|
7598
|
+
*/
|
|
7599
|
+
const rate = (value, event) => {
|
|
7600
|
+
if (!feedback) return true;
|
|
7601
|
+
if (rating === value) {
|
|
7602
|
+
comment.close({ save: false });
|
|
7603
|
+
feedback.clear();
|
|
7604
|
+
return false;
|
|
7605
|
+
}
|
|
7606
|
+
feedback.rate(value);
|
|
7607
|
+
commentRating.current = value;
|
|
7608
|
+
commentAnchor.current = event?.currentTarget ?? null;
|
|
7609
|
+
comment.show({
|
|
7610
|
+
comment: "",
|
|
7611
|
+
focus: event?.detail === 0
|
|
7612
|
+
});
|
|
7613
|
+
return true;
|
|
7614
|
+
};
|
|
7615
|
+
/** Props that let the chosen thumb open and point at its comment. */
|
|
7616
|
+
const thumbFeedbackProps = (value) => {
|
|
7617
|
+
if (!feedback) return {};
|
|
7618
|
+
const thumb = { "data-copilotkit-rating": value };
|
|
7619
|
+
if (rating !== value) return {
|
|
7620
|
+
...thumb,
|
|
7621
|
+
"aria-pressed": false
|
|
7622
|
+
};
|
|
7623
|
+
const enter = (target, via) => {
|
|
7624
|
+
if (!comment.open) commentRating.current = value;
|
|
7625
|
+
commentAnchor.current = target;
|
|
7626
|
+
comment.enter(via);
|
|
7627
|
+
};
|
|
7628
|
+
return {
|
|
7629
|
+
...thumb,
|
|
7630
|
+
"aria-pressed": true,
|
|
7631
|
+
"aria-haspopup": "dialog",
|
|
7632
|
+
"aria-expanded": comment.open,
|
|
7633
|
+
onPointerEnter: (event) => {
|
|
7634
|
+
if (event.pointerType !== "touch") enter(event.currentTarget, "pointer");
|
|
7635
|
+
},
|
|
7636
|
+
onPointerLeave: (event) => {
|
|
7637
|
+
if (event.pointerType !== "touch") comment.leave("pointer");
|
|
7638
|
+
},
|
|
7639
|
+
onFocus: (event) => {
|
|
7640
|
+
if (isFocusVisible(event.currentTarget)) enter(event.currentTarget, "focus");
|
|
7641
|
+
},
|
|
7642
|
+
onBlur: () => comment.leave(),
|
|
7643
|
+
onKeyDown: (event) => {
|
|
7644
|
+
const input = comment.inputRef.current;
|
|
7645
|
+
if (event.key === "Tab" && !event.shiftKey && comment.open && input && input.checkVisibility?.(HIDDEN_TOO) !== false) {
|
|
7646
|
+
event.preventDefault();
|
|
7647
|
+
input.focus();
|
|
7648
|
+
}
|
|
7649
|
+
}
|
|
7650
|
+
};
|
|
7651
|
+
};
|
|
7652
|
+
const boundMarkdownRenderer = renderSlot(markdownRenderer, CopilotChatAssistantMessage.MarkdownRenderer, { content: message.content || "" });
|
|
7653
|
+
const boundCopyButton = renderSlot(copyButton, CopilotChatAssistantMessage.CopyButton, { onClick: async () => {
|
|
7654
|
+
if (message.content) return await (0, _copilotkit_shared.copyToClipboard)(message.content);
|
|
7655
|
+
return false;
|
|
6455
7656
|
} });
|
|
6456
|
-
const boundThumbsUpButton = renderSlot(thumbsUpButton, CopilotChatAssistantMessage.ThumbsUpButton, {
|
|
7657
|
+
const boundThumbsUpButton = renderSlot(thumbsUpButton, CopilotChatAssistantMessage.ThumbsUpButton, {
|
|
7658
|
+
onClick: onThumbsUp || feedback ? (event) => {
|
|
7659
|
+
if (rate("up", event)) onThumbsUp?.(message);
|
|
7660
|
+
} : void 0,
|
|
7661
|
+
...thumbFeedbackProps("up")
|
|
7662
|
+
});
|
|
6457
7663
|
const boundInspectorButton = showInspectorShortcut ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BoundInspectorButton, {
|
|
6458
7664
|
inspectorButton,
|
|
6459
7665
|
messageId: message.id,
|
|
6460
7666
|
openInspector
|
|
6461
7667
|
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, {});
|
|
6462
|
-
const boundThumbsDownButton = renderSlot(thumbsDownButton, CopilotChatAssistantMessage.ThumbsDownButton, {
|
|
7668
|
+
const boundThumbsDownButton = renderSlot(thumbsDownButton, CopilotChatAssistantMessage.ThumbsDownButton, {
|
|
7669
|
+
onClick: onThumbsDown || feedback ? (event) => {
|
|
7670
|
+
if (rate("down", event)) onThumbsDown?.(message);
|
|
7671
|
+
} : void 0,
|
|
7672
|
+
...thumbFeedbackProps("down")
|
|
7673
|
+
});
|
|
6463
7674
|
const boundReadAloudButton = renderSlot(readAloudButton, CopilotChatAssistantMessage.ReadAloudButton, { onClick: onReadAloud ? () => onReadAloud(message) : void 0 });
|
|
6464
7675
|
const boundRegenerateButton = renderSlot(regenerateButton, CopilotChatAssistantMessage.RegenerateButton, { onClick: onRegenerate ? () => onRegenerate(message) : void 0 });
|
|
6465
7676
|
const boundToolbar = renderSlot(toolbar, CopilotChatAssistantMessage.Toolbar, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6466
7677
|
className: "cpk:flex cpk:w-full cpk:items-center cpk:gap-1",
|
|
6467
7678
|
children: [
|
|
6468
7679
|
boundCopyButton,
|
|
6469
|
-
(onThumbsUp || thumbsUpButton) && boundThumbsUpButton,
|
|
6470
|
-
(onThumbsDown || thumbsDownButton) && boundThumbsDownButton,
|
|
7680
|
+
(onThumbsUp || thumbsUpButton || feedback) && boundThumbsUpButton,
|
|
7681
|
+
(onThumbsDown || thumbsDownButton || feedback) && boundThumbsDownButton,
|
|
6471
7682
|
(onReadAloud || readAloudButton) && boundReadAloudButton,
|
|
6472
7683
|
(onRegenerate || regenerateButton) && boundRegenerateButton,
|
|
6473
7684
|
additionalToolbarItems,
|
|
@@ -6481,11 +7692,31 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
|
|
|
6481
7692
|
const hasContent = !!(message.content && message.content.trim().length > 0);
|
|
6482
7693
|
const isLatestAssistantMessage = message.role === "assistant" && (isLatest ?? messages?.[messages.length - 1]?.id === message.id);
|
|
6483
7694
|
const shouldShowToolbar = toolbarVisible && (hasContent || showInspectorShortcut) && !(isRunning && isLatestAssistantMessage);
|
|
6484
|
-
|
|
7695
|
+
const { open: commentOpen, close: closeComment } = comment;
|
|
7696
|
+
(0, react.useEffect)(() => {
|
|
7697
|
+
if (!commentOpen) return;
|
|
7698
|
+
if (rating !== commentRating.current) closeComment({ save: false });
|
|
7699
|
+
else if (!shouldShowToolbar) closeComment();
|
|
7700
|
+
}, [
|
|
7701
|
+
commentOpen,
|
|
7702
|
+
shouldShowToolbar,
|
|
7703
|
+
rating,
|
|
7704
|
+
closeComment
|
|
7705
|
+
]);
|
|
7706
|
+
const feedbackComment = feedback?.feedback && shouldShowToolbar && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FeedbackCommentPopover, {
|
|
7707
|
+
feedbackComment: feedbackCommentSlot,
|
|
7708
|
+
comment,
|
|
7709
|
+
savedComment: feedback.feedback.comment ?? "",
|
|
7710
|
+
rating: feedback.feedback.rating,
|
|
7711
|
+
anchor: commentAnchor,
|
|
7712
|
+
messageId: message.id
|
|
7713
|
+
});
|
|
7714
|
+
if (children) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
7715
|
+
ref: root,
|
|
6485
7716
|
"data-copilotkit": true,
|
|
6486
7717
|
"data-message-id": message.id,
|
|
6487
7718
|
style: { display: "contents" },
|
|
6488
|
-
children: children({
|
|
7719
|
+
children: [children({
|
|
6489
7720
|
markdownRenderer: boundMarkdownRenderer,
|
|
6490
7721
|
toolbar: boundToolbar,
|
|
6491
7722
|
toolCallsView: boundToolCallsView,
|
|
@@ -6504,21 +7735,26 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
|
|
|
6504
7735
|
onRegenerate,
|
|
6505
7736
|
additionalToolbarItems,
|
|
6506
7737
|
toolbarVisible: shouldShowToolbar
|
|
6507
|
-
})
|
|
7738
|
+
}), feedbackComment]
|
|
6508
7739
|
});
|
|
6509
7740
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
7741
|
+
ref: root,
|
|
6510
7742
|
"data-copilotkit": true,
|
|
6511
7743
|
"data-testid": "copilot-assistant-message",
|
|
6512
7744
|
className: (0, tailwind_merge.twMerge)("copilotKitMessage copilotKitAssistantMessage", className),
|
|
6513
7745
|
...props,
|
|
6514
7746
|
"data-message-id": message.id,
|
|
6515
7747
|
children: [
|
|
6516
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
6517
|
-
|
|
6518
|
-
children:
|
|
7748
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(WorkText, {
|
|
7749
|
+
messageId: message.id,
|
|
7750
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
7751
|
+
className: "cpk:prose cpk:max-w-full cpk:break-words cpk:dark:prose-invert",
|
|
7752
|
+
children: boundMarkdownRenderer
|
|
7753
|
+
})
|
|
6519
7754
|
}),
|
|
6520
7755
|
boundToolCallsView,
|
|
6521
|
-
shouldShowToolbar && boundToolbar
|
|
7756
|
+
shouldShowToolbar && boundToolbar,
|
|
7757
|
+
feedbackComment
|
|
6522
7758
|
]
|
|
6523
7759
|
});
|
|
6524
7760
|
}
|
|
@@ -6534,20 +7770,27 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
|
|
|
6534
7770
|
...props
|
|
6535
7771
|
});
|
|
6536
7772
|
const ToolbarButton = _CopilotChatAssistantMessage.ToolbarButton = ({ title, tooltip, tooltipClassName, children, ...props }) => {
|
|
6537
|
-
|
|
6538
|
-
|
|
6539
|
-
|
|
6540
|
-
|
|
6541
|
-
|
|
6542
|
-
|
|
6543
|
-
|
|
6544
|
-
|
|
6545
|
-
|
|
6546
|
-
|
|
6547
|
-
|
|
6548
|
-
|
|
6549
|
-
|
|
6550
|
-
|
|
7773
|
+
const [tooltipOpen, setTooltipOpen] = (0, react.useState)(false);
|
|
7774
|
+
const popupOpen = props["aria-expanded"] === true;
|
|
7775
|
+
if (popupOpen && tooltipOpen) setTooltipOpen(false);
|
|
7776
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Tooltip, {
|
|
7777
|
+
open: tooltipOpen && !popupOpen,
|
|
7778
|
+
onOpenChange: (open) => setTooltipOpen(open && !popupOpen),
|
|
7779
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(TooltipTrigger, {
|
|
7780
|
+
asChild: true,
|
|
7781
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
|
|
7782
|
+
type: "button",
|
|
7783
|
+
variant: "assistantMessageToolbarButton",
|
|
7784
|
+
"aria-label": title,
|
|
7785
|
+
...props,
|
|
7786
|
+
children
|
|
7787
|
+
})
|
|
7788
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TooltipContent, {
|
|
7789
|
+
side: "bottom",
|
|
7790
|
+
className: tooltipClassName,
|
|
7791
|
+
children: tooltip ?? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: title })
|
|
7792
|
+
})]
|
|
7793
|
+
});
|
|
6551
7794
|
};
|
|
6552
7795
|
_CopilotChatAssistantMessage.CopyButton = ({ className, title, onClick, ...props }) => {
|
|
6553
7796
|
const labels = useCopilotChatConfiguration()?.labels ?? CopilotChatDefaultLabels;
|
|
@@ -6586,7 +7829,10 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
|
|
|
6586
7829
|
"data-testid": "copilot-thumbs-up-button",
|
|
6587
7830
|
title: title || labels.assistantMessageToolbarThumbsUpLabel,
|
|
6588
7831
|
...props,
|
|
6589
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.ThumbsUp, {
|
|
7832
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.ThumbsUp, {
|
|
7833
|
+
className: "cpk:size-[18px]",
|
|
7834
|
+
fill: props["aria-pressed"] === true ? "currentColor" : "none"
|
|
7835
|
+
})
|
|
6590
7836
|
});
|
|
6591
7837
|
};
|
|
6592
7838
|
_CopilotChatAssistantMessage.ThumbsDownButton = ({ title, ...props }) => {
|
|
@@ -6595,7 +7841,45 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
|
|
|
6595
7841
|
"data-testid": "copilot-thumbs-down-button",
|
|
6596
7842
|
title: title || labels.assistantMessageToolbarThumbsDownLabel,
|
|
6597
7843
|
...props,
|
|
6598
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.ThumbsDown, {
|
|
7844
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.ThumbsDown, {
|
|
7845
|
+
className: "cpk:size-[18px]",
|
|
7846
|
+
fill: props["aria-pressed"] === true ? "currentColor" : "none"
|
|
7847
|
+
})
|
|
7848
|
+
});
|
|
7849
|
+
};
|
|
7850
|
+
_CopilotChatAssistantMessage.FeedbackComment = ({ value, savedComment, inputRef, onChange, onSubmit, onEditingChange, onLeave, className }) => {
|
|
7851
|
+
const labels = useCopilotChatConfiguration()?.labels ?? CopilotChatDefaultLabels;
|
|
7852
|
+
const changed = value.trim() !== savedComment;
|
|
7853
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("form", {
|
|
7854
|
+
"data-testid": "copilot-feedback-comment",
|
|
7855
|
+
className: (0, tailwind_merge.twMerge)("cpk:flex cpk:w-80 cpk:max-w-[calc(100vw-1rem)] cpk:items-center cpk:gap-1 cpk:rounded-full cpk:border cpk:border-border cpk:bg-background cpk:py-0.5 cpk:pl-3 cpk:pr-0.5 cpk:text-sm cpk:shadow-md", className),
|
|
7856
|
+
onSubmit: (event) => {
|
|
7857
|
+
event.preventDefault();
|
|
7858
|
+
onSubmit();
|
|
7859
|
+
},
|
|
7860
|
+
onFocus: () => onEditingChange?.(true),
|
|
7861
|
+
onBlur: (event) => {
|
|
7862
|
+
const next = event.relatedTarget instanceof Element ? event.relatedTarget : null;
|
|
7863
|
+
if (event.currentTarget.contains(next)) return;
|
|
7864
|
+
if (typeof document !== "undefined" && !document.hasFocus()) return;
|
|
7865
|
+
onEditingChange?.(false);
|
|
7866
|
+
onLeave?.(next);
|
|
7867
|
+
},
|
|
7868
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
7869
|
+
ref: inputRef,
|
|
7870
|
+
value,
|
|
7871
|
+
maxLength: MESSAGE_FEEDBACK_MAX_COMMENT_LENGTH,
|
|
7872
|
+
onChange: (event) => onChange(event.target.value),
|
|
7873
|
+
placeholder: labels.assistantMessageFeedbackCommentPlaceholder,
|
|
7874
|
+
"aria-label": labels.assistantMessageFeedbackCommentPlaceholder,
|
|
7875
|
+
className: "cpk:min-w-0 cpk:flex-1 cpk:bg-transparent cpk:py-1 cpk:text-foreground cpk:outline-none cpk:placeholder:text-muted-foreground"
|
|
7876
|
+
}), changed && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
|
|
7877
|
+
type: "submit",
|
|
7878
|
+
variant: "assistantMessageToolbarButton",
|
|
7879
|
+
"aria-label": labels.assistantMessageFeedbackCommentSubmitLabel,
|
|
7880
|
+
title: labels.assistantMessageFeedbackCommentSubmitLabel,
|
|
7881
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.ArrowUp, { className: "cpk:size-[16px]" })
|
|
7882
|
+
})]
|
|
6599
7883
|
});
|
|
6600
7884
|
};
|
|
6601
7885
|
_CopilotChatAssistantMessage.ReadAloudButton = ({ title, ...props }) => {
|
|
@@ -6623,6 +7907,7 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
|
|
|
6623
7907
|
CopilotChatAssistantMessage.InspectorButton.displayName = "CopilotChatAssistantMessage.InspectorButton";
|
|
6624
7908
|
CopilotChatAssistantMessage.ThumbsUpButton.displayName = "CopilotChatAssistantMessage.ThumbsUpButton";
|
|
6625
7909
|
CopilotChatAssistantMessage.ThumbsDownButton.displayName = "CopilotChatAssistantMessage.ThumbsDownButton";
|
|
7910
|
+
CopilotChatAssistantMessage.FeedbackComment.displayName = "CopilotChatAssistantMessage.FeedbackComment";
|
|
6626
7911
|
CopilotChatAssistantMessage.ReadAloudButton.displayName = "CopilotChatAssistantMessage.ReadAloudButton";
|
|
6627
7912
|
CopilotChatAssistantMessage.RegenerateButton.displayName = "CopilotChatAssistantMessage.RegenerateButton";
|
|
6628
7913
|
var CopilotChatAssistantMessage_default = CopilotChatAssistantMessage;
|
|
@@ -6928,6 +8213,7 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
|
|
|
6928
8213
|
});
|
|
6929
8214
|
};
|
|
6930
8215
|
_CopilotChatUserMessage.BranchNavigation = ({ className, currentBranch = 0, numberOfBranches = 1, onSwitchToBranch, message, ...props }) => {
|
|
8216
|
+
const labels = useCopilotChatConfiguration()?.labels ?? CopilotChatDefaultLabels;
|
|
6931
8217
|
if (!numberOfBranches || numberOfBranches <= 1 || !onSwitchToBranch) return null;
|
|
6932
8218
|
const canGoPrev = currentBranch > 0;
|
|
6933
8219
|
const canGoNext = currentBranch < numberOfBranches - 1;
|
|
@@ -6946,6 +8232,7 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
|
|
|
6946
8232
|
}),
|
|
6947
8233
|
disabled: !canGoPrev,
|
|
6948
8234
|
className: "cpk:h-6 cpk:w-6 cpk:p-0",
|
|
8235
|
+
"aria-label": labels.userMessageToolbarPreviousBranchLabel,
|
|
6949
8236
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.ChevronLeft, { className: "cpk:size-[20px]" })
|
|
6950
8237
|
}),
|
|
6951
8238
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
@@ -6966,6 +8253,7 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
|
|
|
6966
8253
|
}),
|
|
6967
8254
|
disabled: !canGoNext,
|
|
6968
8255
|
className: "cpk:h-6 cpk:w-6 cpk:p-0",
|
|
8256
|
+
"aria-label": labels.userMessageToolbarNextBranchLabel,
|
|
6969
8257
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.ChevronRight, { className: "cpk:size-[20px]" })
|
|
6970
8258
|
})
|
|
6971
8259
|
]
|
|
@@ -6986,7 +8274,7 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
|
|
|
6986
8274
|
/**
|
|
6987
8275
|
* Formats an elapsed duration (in seconds) to a human-readable string.
|
|
6988
8276
|
*/
|
|
6989
|
-
function formatDuration(seconds) {
|
|
8277
|
+
function formatDuration$1(seconds) {
|
|
6990
8278
|
if (seconds < 1) return "a few seconds";
|
|
6991
8279
|
if (seconds < 60) return `${Math.round(seconds)} seconds`;
|
|
6992
8280
|
const mins = Math.floor(seconds / 60);
|
|
@@ -7024,7 +8312,7 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
|
|
|
7024
8312
|
userToggledRef.current = true;
|
|
7025
8313
|
setIsOpen((prev) => !prev);
|
|
7026
8314
|
} : void 0;
|
|
7027
|
-
const label = isStreaming ? "Thinking…" : `Thought for ${formatDuration(elapsed)}`;
|
|
8315
|
+
const label = isStreaming ? "Thinking…" : `Thought for ${formatDuration$1(elapsed)}`;
|
|
7028
8316
|
const boundHeader = renderSlot(header, CopilotChatReasoningMessage.Header, {
|
|
7029
8317
|
isOpen,
|
|
7030
8318
|
label,
|
|
@@ -7246,6 +8534,71 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
|
|
|
7246
8534
|
*/
|
|
7247
8535
|
const ScrollPinnedContext = react.default.createContext(false);
|
|
7248
8536
|
|
|
8537
|
+
//#endregion
|
|
8538
|
+
//#region src/v2/components/chat/CopilotChatWorkSummary.tsx
|
|
8539
|
+
/** "45s", "1m 5s", "2m". Used for the live timer and the final duration. */
|
|
8540
|
+
function formatDuration(ms) {
|
|
8541
|
+
const seconds = Math.max(0, Math.floor(ms / 1e3));
|
|
8542
|
+
if (seconds < 60) return `${seconds}s`;
|
|
8543
|
+
const minutes = Math.floor(seconds / 60);
|
|
8544
|
+
const rest = seconds % 60;
|
|
8545
|
+
return rest ? `${minutes}m ${rest}s` : `${minutes}m`;
|
|
8546
|
+
}
|
|
8547
|
+
/** Re-renders every second while `active`, returning the current time. */
|
|
8548
|
+
function useNow(active) {
|
|
8549
|
+
const [now, setNow] = (0, react.useState)(() => Date.now());
|
|
8550
|
+
(0, react.useEffect)(() => {
|
|
8551
|
+
if (!active) return;
|
|
8552
|
+
setNow(Date.now());
|
|
8553
|
+
const timer = setInterval(() => setNow(Date.now()), 1e3);
|
|
8554
|
+
return () => clearInterval(timer);
|
|
8555
|
+
}, [active]);
|
|
8556
|
+
return now;
|
|
8557
|
+
}
|
|
8558
|
+
/**
|
|
8559
|
+
* The line at the top of a reply in the `"turn"` tool-call display. While the
|
|
8560
|
+
* agent works it reads "Working 4s"; once the reply is done it reads "Worked
|
|
8561
|
+
* for 9s · 7 tools" and toggles the work it folded away.
|
|
8562
|
+
*/
|
|
8563
|
+
function CopilotChatWorkSummary({ isWorking, isOpen, calls, elapsedMs, workingSince, className, ...props }) {
|
|
8564
|
+
const now = useNow(isWorking);
|
|
8565
|
+
const failed = calls.filter((call) => call.toolMessage?.error).length;
|
|
8566
|
+
const liveMs = elapsedMs !== void 0 && workingSince !== void 0 ? elapsedMs + Math.max(0, now - workingSince) : void 0;
|
|
8567
|
+
const duration = elapsedMs !== void 0 ? formatDuration(Math.max(1e3, elapsedMs)) : void 0;
|
|
8568
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
8569
|
+
type: "button",
|
|
8570
|
+
"data-copilotkit": true,
|
|
8571
|
+
"data-testid": "copilot-work-summary",
|
|
8572
|
+
"data-state": isWorking ? "working" : "done",
|
|
8573
|
+
"aria-expanded": isOpen,
|
|
8574
|
+
className: (0, tailwind_merge.twMerge)("cpk:m-0 cpk:inline-flex cpk:max-w-full cpk:cursor-pointer cpk:items-center cpk:gap-1.5 cpk:rounded-md cpk:border-none cpk:bg-transparent cpk:p-0 cpk:py-0.5 cpk:text-sm cpk:text-muted-foreground cpk:transition-colors cpk:hover:text-foreground cpk:focus-visible:outline-2 cpk:focus-visible:outline-ring", className),
|
|
8575
|
+
...props,
|
|
8576
|
+
children: [isWorking ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
8577
|
+
className: "cpk:font-medium cpk-shimmer",
|
|
8578
|
+
children: "Working"
|
|
8579
|
+
}), liveMs !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
8580
|
+
className: "cpk:text-xs cpk:tabular-nums cpk:opacity-70",
|
|
8581
|
+
children: formatDuration(liveMs)
|
|
8582
|
+
})] }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
8583
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
8584
|
+
className: "cpk:font-medium",
|
|
8585
|
+
children: duration ? `Worked for ${duration}` : `Used ${pluralize(calls.length, "tool")}`
|
|
8586
|
+
}),
|
|
8587
|
+
duration && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
8588
|
+
className: "cpk:text-xs cpk:opacity-70",
|
|
8589
|
+
children: pluralize(calls.length, "tool")
|
|
8590
|
+
}),
|
|
8591
|
+
failed > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
8592
|
+
className: "cpk:text-destructive",
|
|
8593
|
+
children: [failed, " failed"]
|
|
8594
|
+
})
|
|
8595
|
+
] }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.ChevronRight, {
|
|
8596
|
+
"aria-hidden": "true",
|
|
8597
|
+
className: (0, tailwind_merge.twMerge)("cpk:size-3.5 cpk:shrink-0 cpk:transition-transform cpk:duration-200", isOpen && "cpk:rotate-90")
|
|
8598
|
+
})]
|
|
8599
|
+
});
|
|
8600
|
+
}
|
|
8601
|
+
|
|
7249
8602
|
//#endregion
|
|
7250
8603
|
//#region src/v2/components/intelligence-indicator/IntelligenceIndicatorView.tsx
|
|
7251
8604
|
/**
|
|
@@ -7732,7 +9085,7 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
|
|
|
7732
9085
|
}
|
|
7733
9086
|
const GROUP_ROW_KEY_PREFIX = "copilotkit-group:";
|
|
7734
9087
|
const VIRTUALIZE_THRESHOLD = 50;
|
|
7735
|
-
function CopilotChatMessageView({ messages = [], assistantMessage, userMessage, reasoningMessage, cursor, intelligenceIndicator, isRunning = false, transformMessages, groupMessages, children, className, ...props }) {
|
|
9088
|
+
function CopilotChatMessageView({ messages = [], assistantMessage, userMessage, reasoningMessage, cursor, intelligenceIndicator, workSummary, isRunning = false, transformMessages, groupMessages, messageFeedback = true, toolCallDisplay = "grouped", children, className, ...props }) {
|
|
7736
9089
|
const isPinnedToBottom = (0, react.useContext)(ScrollPinnedContext);
|
|
7737
9090
|
const renderCustomMessage = useRenderCustomMessages();
|
|
7738
9091
|
const { renderActivityMessage } = useRenderActivityMessage();
|
|
@@ -7773,6 +9126,100 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
|
|
|
7773
9126
|
transformedMessages
|
|
7774
9127
|
]);
|
|
7775
9128
|
const latestRenderedId = renderedMessages[renderedMessages.length - 1]?.id;
|
|
9129
|
+
const rendererNames = useToolCallRendererNames();
|
|
9130
|
+
const toolCallLayouts = (0, react.useMemo)(() => toolCallDisplay === "separate" ? /* @__PURE__ */ new Map() : getToolCallLayouts(renderedMessages, messages, rendererNames), [
|
|
9131
|
+
toolCallDisplay,
|
|
9132
|
+
renderedMessages,
|
|
9133
|
+
messages,
|
|
9134
|
+
rendererNames
|
|
9135
|
+
]);
|
|
9136
|
+
const turnWork = (0, react.useMemo)(() => toolCallDisplay === "turn" ? getTurnWork(renderedMessages, toolCallLayouts) : void 0, [
|
|
9137
|
+
toolCallDisplay,
|
|
9138
|
+
renderedMessages,
|
|
9139
|
+
toolCallLayouts
|
|
9140
|
+
]);
|
|
9141
|
+
const turnByFirstMessage = (0, react.useMemo)(() => {
|
|
9142
|
+
const byFirst = /* @__PURE__ */ new Map();
|
|
9143
|
+
for (const turn of turnWork?.values() ?? []) byFirst.set(turn.firstMessageId, turn);
|
|
9144
|
+
return byFirst;
|
|
9145
|
+
}, [turnWork]);
|
|
9146
|
+
let latestTurnKey = "start";
|
|
9147
|
+
for (let i = renderedMessages.length - 1; i >= 0; i--) if (renderedMessages[i].role === "user") {
|
|
9148
|
+
latestTurnKey = renderedMessages[i].id;
|
|
9149
|
+
break;
|
|
9150
|
+
}
|
|
9151
|
+
const isWorkingOn = (turnKey) => isRunning && turnKey === latestTurnKey;
|
|
9152
|
+
const [toggledTurns, setToggledTurns] = (0, react.useState)(() => /* @__PURE__ */ new Map());
|
|
9153
|
+
const isWorkOpen = (turnKey) => toggledTurns.get(turnKey) ?? isWorkingOn(turnKey);
|
|
9154
|
+
const workTimesRef = (0, react.useRef)(/* @__PURE__ */ new Map());
|
|
9155
|
+
if (toolCallDisplay === "turn") {
|
|
9156
|
+
const now = Date.now();
|
|
9157
|
+
const workTimes = workTimesRef.current;
|
|
9158
|
+
if (isRunning) {
|
|
9159
|
+
const times = workTimes.get(latestTurnKey);
|
|
9160
|
+
if (times) times.workingSince ?? (times.workingSince = now);
|
|
9161
|
+
else if (renderedMessages[renderedMessages.length - 1]?.role === "user") workTimes.set(latestTurnKey, {
|
|
9162
|
+
elapsedMs: 0,
|
|
9163
|
+
workingSince: now
|
|
9164
|
+
});
|
|
9165
|
+
} else for (const times of workTimes.values()) {
|
|
9166
|
+
if (times.workingSince === void 0) continue;
|
|
9167
|
+
times.elapsedMs += now - times.workingSince;
|
|
9168
|
+
times.workingSince = void 0;
|
|
9169
|
+
}
|
|
9170
|
+
}
|
|
9171
|
+
const { workOpen, workTextOpen } = (0, react.useMemo)(() => {
|
|
9172
|
+
const open = /* @__PURE__ */ new Map();
|
|
9173
|
+
const textOpen = /* @__PURE__ */ new Map();
|
|
9174
|
+
for (const turn of turnWork?.values() ?? []) {
|
|
9175
|
+
const turnOpen = toggledTurns.get(turn.key) ?? (isRunning && turn.key === latestTurnKey);
|
|
9176
|
+
for (const id of turn.workMessageIds) {
|
|
9177
|
+
open.set(id, turnOpen);
|
|
9178
|
+
if (id !== turn.replyTextMessageId) textOpen.set(id, turnOpen);
|
|
9179
|
+
}
|
|
9180
|
+
}
|
|
9181
|
+
return {
|
|
9182
|
+
workOpen: open,
|
|
9183
|
+
workTextOpen: textOpen
|
|
9184
|
+
};
|
|
9185
|
+
}, [
|
|
9186
|
+
turnWork,
|
|
9187
|
+
toggledTurns,
|
|
9188
|
+
isRunning,
|
|
9189
|
+
latestTurnKey
|
|
9190
|
+
]);
|
|
9191
|
+
const toolCallDisplayContext = (0, react.useMemo)(() => ({
|
|
9192
|
+
display: toolCallDisplay,
|
|
9193
|
+
isRunning,
|
|
9194
|
+
layouts: toolCallLayouts,
|
|
9195
|
+
workOpen,
|
|
9196
|
+
workTextOpen
|
|
9197
|
+
}), [
|
|
9198
|
+
toolCallDisplay,
|
|
9199
|
+
isRunning,
|
|
9200
|
+
toolCallLayouts,
|
|
9201
|
+
workOpen,
|
|
9202
|
+
workTextOpen
|
|
9203
|
+
]);
|
|
9204
|
+
const renderWorkSummary = (turnKey, calls) => {
|
|
9205
|
+
const working = isWorkingOn(turnKey);
|
|
9206
|
+
const open = isWorkOpen(turnKey);
|
|
9207
|
+
const times = workTimesRef.current.get(turnKey);
|
|
9208
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Collapsible, {
|
|
9209
|
+
open: working || calls.length > 0,
|
|
9210
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
9211
|
+
className: "cpk:pt-1 cpk:pb-2",
|
|
9212
|
+
children: renderSlot(workSummary, CopilotChatWorkSummary, {
|
|
9213
|
+
isWorking: working,
|
|
9214
|
+
isOpen: open,
|
|
9215
|
+
calls,
|
|
9216
|
+
elapsedMs: times?.elapsedMs,
|
|
9217
|
+
workingSince: times?.workingSince,
|
|
9218
|
+
onClick: () => setToggledTurns((toggled) => new Map(toggled).set(turnKey, !open))
|
|
9219
|
+
})
|
|
9220
|
+
})
|
|
9221
|
+
}, `work-summary-${turnKey}`);
|
|
9222
|
+
};
|
|
7776
9223
|
const transformDuplicateId = (0, react.useMemo)(() => {
|
|
7777
9224
|
if (process.env.NODE_ENV === "production" || !transformMessages && !groupMessages) return;
|
|
7778
9225
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -7838,6 +9285,18 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
|
|
|
7838
9285
|
const { Component: AssistantComponent, slotProps: assistantSlotProps } = (0, react.useMemo)(() => resolveSlotComponent(assistantMessage, CopilotChatAssistantMessage_default), [assistantMessage]);
|
|
7839
9286
|
const agentId = config?.agentId;
|
|
7840
9287
|
const threadId = config?.threadId;
|
|
9288
|
+
const learningFeedbackEnabled = useLearningFeedbackEnabled(copilotkit);
|
|
9289
|
+
const feedbackScope = (0, react.useMemo)(() => messageFeedback && learningFeedbackEnabled && agentId !== void 0 && threadId !== void 0 ? {
|
|
9290
|
+
copilotkit,
|
|
9291
|
+
agentId,
|
|
9292
|
+
threadId
|
|
9293
|
+
} : null, [
|
|
9294
|
+
messageFeedback,
|
|
9295
|
+
learningFeedbackEnabled,
|
|
9296
|
+
copilotkit,
|
|
9297
|
+
agentId,
|
|
9298
|
+
threadId
|
|
9299
|
+
]);
|
|
7841
9300
|
const assistantSlotPropsWithFeedback = (0, react.useMemo)(() => {
|
|
7842
9301
|
const onThumbsUp = assistantSlotProps?.onThumbsUp;
|
|
7843
9302
|
const onThumbsDown = assistantSlotProps?.onThumbsDown;
|
|
@@ -7904,7 +9363,7 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
|
|
|
7904
9363
|
measuredRef.current.total = total - (sizes.get(index) ?? 0) + height;
|
|
7905
9364
|
sizes.set(index, height);
|
|
7906
9365
|
}
|
|
7907
|
-
return height;
|
|
9366
|
+
return height > 0 ? height : measuredRef.current.sizes.get(index) ?? 100;
|
|
7908
9367
|
}, []);
|
|
7909
9368
|
const isPinnedToBottomRef = react.default.useRef(isPinnedToBottom);
|
|
7910
9369
|
const shouldAdjustScrollOnResize = react.default.useCallback((item, _delta, instance) => {
|
|
@@ -7914,7 +9373,7 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
|
|
|
7914
9373
|
}, []);
|
|
7915
9374
|
const virtualizer = (0, _tanstack_react_virtual.useVirtualizer)({
|
|
7916
9375
|
count: shouldVirtualize ? rows.length : 0,
|
|
7917
|
-
getScrollElement: () => scrollElement,
|
|
9376
|
+
getScrollElement: () => shouldVirtualize ? scrollElement : null,
|
|
7918
9377
|
estimateSize: estimateRowSize,
|
|
7919
9378
|
overscan: 5,
|
|
7920
9379
|
measureElement: measureRowElement,
|
|
@@ -7925,8 +9384,11 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
|
|
|
7925
9384
|
});
|
|
7926
9385
|
isPinnedToBottomRef.current = isPinnedToBottom;
|
|
7927
9386
|
virtualizer.shouldAdjustScrollPositionOnItemSizeChange = shouldAdjustScrollOnResize;
|
|
9387
|
+
const lastEndAlignedFirstMessageRef = react.default.useRef(void 0);
|
|
7928
9388
|
(0, react.useLayoutEffect)(() => {
|
|
7929
9389
|
if (!shouldVirtualize || !rows.length) return;
|
|
9390
|
+
if (lastEndAlignedFirstMessageRef.current === firstMessageId) return;
|
|
9391
|
+
lastEndAlignedFirstMessageRef.current = firstMessageId;
|
|
7930
9392
|
virtualizer.scrollToIndex(rows.length - 1, { align: "end" });
|
|
7931
9393
|
}, [shouldVirtualize, firstMessageId]);
|
|
7932
9394
|
const intelligenceTurnAnchors = (0, react.useMemo)(() => getIntelligenceTurnAnchors(deduplicatedMessages, renderedMessages), [deduplicatedMessages, renderedMessages]);
|
|
@@ -7934,6 +9396,8 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
|
|
|
7934
9396
|
const elements = [];
|
|
7935
9397
|
const stateSnapshot = renderCustomMessage ? getStateSnapshotForMessage(message.id) : void 0;
|
|
7936
9398
|
const rowKey = rowRenderKeys.get(message.id) ?? message.id;
|
|
9399
|
+
const turn = turnByFirstMessage.get(message.id);
|
|
9400
|
+
if (turn) elements.push(renderWorkSummary(turn.key, turn.calls));
|
|
7937
9401
|
if (renderCustomMessage) elements.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(MemoizedCustomMessage, {
|
|
7938
9402
|
message,
|
|
7939
9403
|
position: "before",
|
|
@@ -7957,14 +9421,20 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
|
|
|
7957
9421
|
message,
|
|
7958
9422
|
renderActivityMessage
|
|
7959
9423
|
}, rowKey));
|
|
7960
|
-
else if (message.role === "reasoning")
|
|
7961
|
-
|
|
7962
|
-
|
|
7963
|
-
|
|
7964
|
-
|
|
7965
|
-
|
|
7966
|
-
|
|
7967
|
-
|
|
9424
|
+
else if (message.role === "reasoning") {
|
|
9425
|
+
const reasoning = /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MemoizedReasoningMessage, {
|
|
9426
|
+
message,
|
|
9427
|
+
messages,
|
|
9428
|
+
isRunning,
|
|
9429
|
+
isLatest: message.id === latestRenderedId,
|
|
9430
|
+
ReasoningMessageComponent: ReasoningComponent,
|
|
9431
|
+
slotProps: reasoningSlotProps
|
|
9432
|
+
}, rowKey);
|
|
9433
|
+
elements.push(toolCallDisplay === "turn" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Collapsible, {
|
|
9434
|
+
open: workOpen.get(message.id) ?? true,
|
|
9435
|
+
children: reasoning
|
|
9436
|
+
}, rowKey) : reasoning);
|
|
9437
|
+
}
|
|
7968
9438
|
if (renderCustomMessage) elements.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(MemoizedCustomMessage, {
|
|
7969
9439
|
message,
|
|
7970
9440
|
position: "after",
|
|
@@ -7992,52 +9462,157 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
|
|
|
7992
9462
|
children: row.messages.flatMap(renderMessageBlock)
|
|
7993
9463
|
}, rowKey(row))];
|
|
7994
9464
|
};
|
|
9465
|
+
const rowKeysRef = (0, react.useRef)([]);
|
|
9466
|
+
rowKeysRef.current = rows.map(rowKey);
|
|
9467
|
+
const virtualModeRef = (0, react.useRef)(shouldVirtualize);
|
|
9468
|
+
virtualModeRef.current = shouldVirtualize;
|
|
9469
|
+
(0, react.useEffect)(() => {
|
|
9470
|
+
const element = scrollElementFromCtx;
|
|
9471
|
+
if (!element) return;
|
|
9472
|
+
let anchor = null;
|
|
9473
|
+
let suspended = false;
|
|
9474
|
+
let frame = 0;
|
|
9475
|
+
const visibleRows = () => Array.from(element.querySelectorAll("[data-scroll-anchor]"));
|
|
9476
|
+
const remember = () => {
|
|
9477
|
+
if (suspended || element.clientHeight === 0 || !virtualModeRef.current) return;
|
|
9478
|
+
if (isPinnedToBottomRef.current) {
|
|
9479
|
+
anchor = null;
|
|
9480
|
+
return;
|
|
9481
|
+
}
|
|
9482
|
+
const viewport = element.getBoundingClientRect();
|
|
9483
|
+
const row = visibleRows().find((row) => {
|
|
9484
|
+
const bounds = row.getBoundingClientRect();
|
|
9485
|
+
return bounds.bottom > viewport.top && bounds.top < viewport.bottom;
|
|
9486
|
+
});
|
|
9487
|
+
if (row) anchor = {
|
|
9488
|
+
key: row.dataset.scrollAnchor,
|
|
9489
|
+
offset: row.getBoundingClientRect().top - viewport.top
|
|
9490
|
+
};
|
|
9491
|
+
};
|
|
9492
|
+
const observer = new ResizeObserver(() => {
|
|
9493
|
+
if (element.clientHeight === 0) {
|
|
9494
|
+
suspended = true;
|
|
9495
|
+
cancelAnimationFrame(frame);
|
|
9496
|
+
return;
|
|
9497
|
+
}
|
|
9498
|
+
if (!suspended || !anchor) {
|
|
9499
|
+
suspended = false;
|
|
9500
|
+
remember();
|
|
9501
|
+
return;
|
|
9502
|
+
}
|
|
9503
|
+
let attempts = 0;
|
|
9504
|
+
let stableFrames = 0;
|
|
9505
|
+
const restore = () => {
|
|
9506
|
+
if (!anchor || element.clientHeight === 0) return;
|
|
9507
|
+
const index = rowKeysRef.current.indexOf(anchor.key);
|
|
9508
|
+
if (index < 0) {
|
|
9509
|
+
anchor = null;
|
|
9510
|
+
suspended = false;
|
|
9511
|
+
return;
|
|
9512
|
+
}
|
|
9513
|
+
const row = visibleRows().find((row) => row.dataset.scrollAnchor === anchor.key);
|
|
9514
|
+
if (row) {
|
|
9515
|
+
const delta = row.getBoundingClientRect().top - element.getBoundingClientRect().top - anchor.offset;
|
|
9516
|
+
element.scrollTop += delta;
|
|
9517
|
+
stableFrames = Math.abs(delta) < 1 ? stableFrames + 1 : 0;
|
|
9518
|
+
} else {
|
|
9519
|
+
const offset = virtualizer.getOffsetForIndex(index, "start")?.[0];
|
|
9520
|
+
if (offset !== void 0) virtualizer.scrollToOffset(offset - anchor.offset);
|
|
9521
|
+
stableFrames = 0;
|
|
9522
|
+
}
|
|
9523
|
+
if (++attempts < 60 && stableFrames < 3) frame = requestAnimationFrame(restore);
|
|
9524
|
+
else {
|
|
9525
|
+
suspended = false;
|
|
9526
|
+
remember();
|
|
9527
|
+
}
|
|
9528
|
+
};
|
|
9529
|
+
frame = requestAnimationFrame(restore);
|
|
9530
|
+
});
|
|
9531
|
+
const interrupt = () => {
|
|
9532
|
+
cancelAnimationFrame(frame);
|
|
9533
|
+
anchor = null;
|
|
9534
|
+
suspended = false;
|
|
9535
|
+
};
|
|
9536
|
+
element.addEventListener("scroll", remember, { passive: true });
|
|
9537
|
+
element.addEventListener("wheel", interrupt, { passive: true });
|
|
9538
|
+
element.addEventListener("touchstart", interrupt, { passive: true });
|
|
9539
|
+
element.addEventListener("keydown", interrupt);
|
|
9540
|
+
observer.observe(element);
|
|
9541
|
+
remember();
|
|
9542
|
+
return () => {
|
|
9543
|
+
cancelAnimationFrame(frame);
|
|
9544
|
+
observer.disconnect();
|
|
9545
|
+
element.removeEventListener("scroll", remember);
|
|
9546
|
+
element.removeEventListener("wheel", interrupt);
|
|
9547
|
+
element.removeEventListener("touchstart", interrupt);
|
|
9548
|
+
element.removeEventListener("keydown", interrupt);
|
|
9549
|
+
};
|
|
9550
|
+
}, [
|
|
9551
|
+
scrollElementFromCtx,
|
|
9552
|
+
virtualizer,
|
|
9553
|
+
firstMessageId
|
|
9554
|
+
]);
|
|
7995
9555
|
const messageElements = shouldVirtualize ? [] : rows.flatMap(renderRow);
|
|
7996
|
-
if (children) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
7997
|
-
|
|
7998
|
-
|
|
7999
|
-
|
|
8000
|
-
|
|
8001
|
-
|
|
8002
|
-
|
|
8003
|
-
|
|
9556
|
+
if (children) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MessageFeedbackScopeContext.Provider, {
|
|
9557
|
+
value: feedbackScope,
|
|
9558
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ToolCallDisplayContext.Provider, {
|
|
9559
|
+
value: toolCallDisplayContext,
|
|
9560
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
9561
|
+
"data-copilotkit": true,
|
|
9562
|
+
style: { display: "contents" },
|
|
9563
|
+
children: children({
|
|
9564
|
+
messageElements,
|
|
9565
|
+
messages,
|
|
9566
|
+
isRunning,
|
|
9567
|
+
interruptElement
|
|
9568
|
+
})
|
|
9569
|
+
})
|
|
8004
9570
|
})
|
|
8005
9571
|
});
|
|
8006
9572
|
const lastMessage = renderedMessages[renderedMessages.length - 1];
|
|
8007
|
-
const showCursor = isRunning && lastMessage?.role !== "reasoning";
|
|
8008
|
-
|
|
8009
|
-
|
|
8010
|
-
|
|
8011
|
-
|
|
8012
|
-
|
|
8013
|
-
|
|
8014
|
-
|
|
8015
|
-
|
|
8016
|
-
|
|
8017
|
-
|
|
8018
|
-
|
|
8019
|
-
|
|
8020
|
-
const row = rows[virtualItem.index];
|
|
8021
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
8022
|
-
"data-index": virtualItem.index,
|
|
8023
|
-
ref: virtualizer.measureElement,
|
|
9573
|
+
const showCursor = isRunning && lastMessage?.role !== "reasoning" && toolCallDisplay !== "turn";
|
|
9574
|
+
const pendingWorkSummary = toolCallDisplay === "turn" && isRunning && lastMessage?.role === "user";
|
|
9575
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MessageFeedbackScopeContext.Provider, {
|
|
9576
|
+
value: feedbackScope,
|
|
9577
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ToolCallDisplayContext.Provider, {
|
|
9578
|
+
value: toolCallDisplayContext,
|
|
9579
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
9580
|
+
"data-copilotkit": true,
|
|
9581
|
+
"data-testid": "copilot-message-list",
|
|
9582
|
+
className: (0, tailwind_merge.twMerge)("copilotKitMessages cpk:flex cpk:flex-col", className),
|
|
9583
|
+
...props,
|
|
9584
|
+
children: [
|
|
9585
|
+
shouldVirtualize ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
8024
9586
|
style: {
|
|
8025
|
-
|
|
8026
|
-
|
|
8027
|
-
left: 0,
|
|
8028
|
-
width: "100%",
|
|
8029
|
-
transform: `translateY(${virtualItem.start}px)`
|
|
9587
|
+
height: virtualizer.getTotalSize(),
|
|
9588
|
+
position: "relative"
|
|
8030
9589
|
},
|
|
8031
|
-
children:
|
|
8032
|
-
|
|
8033
|
-
|
|
8034
|
-
|
|
8035
|
-
|
|
8036
|
-
|
|
8037
|
-
|
|
8038
|
-
|
|
9590
|
+
children: virtualizer.getVirtualItems().map((virtualItem) => {
|
|
9591
|
+
const row = rows[virtualItem.index];
|
|
9592
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
9593
|
+
"data-index": virtualItem.index,
|
|
9594
|
+
"data-scroll-anchor": rowKey(row),
|
|
9595
|
+
ref: virtualizer.measureElement,
|
|
9596
|
+
style: {
|
|
9597
|
+
position: "absolute",
|
|
9598
|
+
top: 0,
|
|
9599
|
+
left: 0,
|
|
9600
|
+
width: "100%",
|
|
9601
|
+
transform: `translateY(${virtualItem.start}px)`
|
|
9602
|
+
},
|
|
9603
|
+
children: renderRow(row)
|
|
9604
|
+
}, rowKey(row));
|
|
9605
|
+
})
|
|
9606
|
+
}) : messageElements,
|
|
9607
|
+
interruptElement,
|
|
9608
|
+
pendingWorkSummary && renderWorkSummary(latestTurnKey, []),
|
|
9609
|
+
showCursor && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
9610
|
+
className: "cpk:mt-2",
|
|
9611
|
+
children: renderSlot(cursor, CopilotChatMessageView.Cursor, {})
|
|
9612
|
+
})
|
|
9613
|
+
]
|
|
8039
9614
|
})
|
|
8040
|
-
|
|
9615
|
+
})
|
|
8041
9616
|
});
|
|
8042
9617
|
}
|
|
8043
9618
|
CopilotChatMessageView.Cursor = function Cursor({ className, ...props }) {
|
|
@@ -8422,6 +9997,16 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
|
|
|
8422
9997
|
});
|
|
8423
9998
|
}
|
|
8424
9999
|
function CopilotChatView({ messageView, input, scrollView, suggestionView, welcomeScreen, messages = [], autoScroll = true, isRunning = false, suggestions, suggestionLoadingIndexes, onSelectSuggestion, onSubmitMessage, onStop, inputMode, inputValue, onInputChange, onStartTranscribe, onCancelTranscribe, onFinishTranscribe, onFinishTranscribeWithAudio, attachments, onRemoveAttachment, onAddFile, dragOver, onDragOver, onDragLeave, onDrop, isConnecting = false, hasExplicitThreadId = false, disclaimer, intelligenceIndicator, children, className, ...props }) {
|
|
10000
|
+
const configuredThreadId = useCopilotChatConfiguration()?.threadId;
|
|
10001
|
+
const [fallbackThreadId, setFallbackThreadId] = (0, react.useState)(messages[0]?.id);
|
|
10002
|
+
const previousMessageIds = (0, react.useRef)(/* @__PURE__ */ new Set());
|
|
10003
|
+
(0, react.useEffect)(() => {
|
|
10004
|
+
if (messages.length === 0) return;
|
|
10005
|
+
const overlaps = messages.some((message) => previousMessageIds.current.has(message.id));
|
|
10006
|
+
previousMessageIds.current = new Set(messages.map((message) => message.id));
|
|
10007
|
+
if (!overlaps) setFallbackThreadId(messages[0].id);
|
|
10008
|
+
}, [messages]);
|
|
10009
|
+
const scrollThreadId = configuredThreadId ?? fallbackThreadId;
|
|
8425
10010
|
const [inputContainerEl, setInputContainerEl] = (0, react.useState)(null);
|
|
8426
10011
|
const [inputContainerHeight, setInputContainerHeight] = (0, react.useState)(0);
|
|
8427
10012
|
const [isResizing, setIsResizing] = (0, react.useState)(false);
|
|
@@ -8488,6 +10073,7 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
|
|
|
8488
10073
|
}) : null;
|
|
8489
10074
|
const BoundScrollView = renderSlot(scrollView, CopilotChatView.ScrollView, {
|
|
8490
10075
|
autoScroll,
|
|
10076
|
+
scrollThreadId,
|
|
8491
10077
|
inputContainerHeight,
|
|
8492
10078
|
isResizing,
|
|
8493
10079
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
@@ -8583,12 +10169,102 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
|
|
|
8583
10169
|
});
|
|
8584
10170
|
}
|
|
8585
10171
|
(function(_CopilotChatView) {
|
|
8586
|
-
const ScrollContent = ({ children, scrollToBottomButton, feather, inputContainerHeight, isResizing }) => {
|
|
8587
|
-
const { isAtBottom, scrollToBottom, scrollRef, state } = (0, use_stick_to_bottom.useStickToBottomContext)();
|
|
10172
|
+
const ScrollContent = ({ children, scrollToBottomButton, feather, inputContainerHeight, isResizing, scrollThreadId }) => {
|
|
10173
|
+
const { isAtBottom, scrollToBottom, stopScroll, scrollRef, state } = (0, use_stick_to_bottom.useStickToBottomContext)();
|
|
8588
10174
|
const [scrollEl, setScrollEl] = (0, react.useState)(null);
|
|
10175
|
+
const readingOffsetRef = (0, react.useRef)(null);
|
|
10176
|
+
const pinIntentRef = (0, react.useRef)(false);
|
|
10177
|
+
const stateRef = (0, react.useRef)(state);
|
|
10178
|
+
stateRef.current = state;
|
|
8589
10179
|
(0, react.useLayoutEffect)(() => {
|
|
8590
10180
|
setScrollEl(scrollRef.current ?? null);
|
|
8591
10181
|
}, []);
|
|
10182
|
+
(0, react.useEffect)(() => {
|
|
10183
|
+
if (!scrollEl) return;
|
|
10184
|
+
let hidden = false;
|
|
10185
|
+
let resumeBottom = false;
|
|
10186
|
+
let pendingFrame = 0;
|
|
10187
|
+
let resumeFrame = 0;
|
|
10188
|
+
let settleFrame = 0;
|
|
10189
|
+
readingOffsetRef.current = null;
|
|
10190
|
+
const rememberScroll = () => {
|
|
10191
|
+
if (hidden || scrollEl.clientHeight === 0) return;
|
|
10192
|
+
if (resumeBottom) {
|
|
10193
|
+
readingOffsetRef.current = null;
|
|
10194
|
+
return;
|
|
10195
|
+
}
|
|
10196
|
+
if (pinIntentRef.current) if (stateRef.current.escapedFromLock) pinIntentRef.current = false;
|
|
10197
|
+
else {
|
|
10198
|
+
readingOffsetRef.current = null;
|
|
10199
|
+
if (!stateRef.current.isNearBottom) return;
|
|
10200
|
+
pinIntentRef.current = false;
|
|
10201
|
+
}
|
|
10202
|
+
readingOffsetRef.current = !stateRef.current.isAtBottom && (stateRef.current.escapedFromLock || !stateRef.current.isNearBottom) ? scrollEl.scrollTop : null;
|
|
10203
|
+
};
|
|
10204
|
+
const onScroll = () => {
|
|
10205
|
+
rememberScroll();
|
|
10206
|
+
cancelAnimationFrame(pendingFrame);
|
|
10207
|
+
pendingFrame = requestAnimationFrame(rememberScroll);
|
|
10208
|
+
};
|
|
10209
|
+
const onWheel = (event) => {
|
|
10210
|
+
if (event.deltaY < 0) {
|
|
10211
|
+
pinIntentRef.current = false;
|
|
10212
|
+
resumeBottom = false;
|
|
10213
|
+
}
|
|
10214
|
+
};
|
|
10215
|
+
const resizeObserver = new ResizeObserver(() => {
|
|
10216
|
+
if (scrollEl.clientHeight === 0) {
|
|
10217
|
+
hidden = true;
|
|
10218
|
+
resumeBottom = pinIntentRef.current || readingOffsetRef.current === null;
|
|
10219
|
+
if (!resumeBottom) stopScroll();
|
|
10220
|
+
} else if (hidden) {
|
|
10221
|
+
hidden = false;
|
|
10222
|
+
if (resumeBottom) {
|
|
10223
|
+
stopScroll();
|
|
10224
|
+
resumeFrame = requestAnimationFrame(() => {
|
|
10225
|
+
settleFrame = requestAnimationFrame(() => {
|
|
10226
|
+
if (scrollEl.clientHeight > 0 && resumeBottom) {
|
|
10227
|
+
resumeBottom = false;
|
|
10228
|
+
pinIntentRef.current = true;
|
|
10229
|
+
scrollToBottom({ animation: "instant" });
|
|
10230
|
+
}
|
|
10231
|
+
});
|
|
10232
|
+
});
|
|
10233
|
+
} else if (readingOffsetRef.current !== null) {
|
|
10234
|
+
stopScroll();
|
|
10235
|
+
scrollEl.scrollTop = readingOffsetRef.current;
|
|
10236
|
+
}
|
|
10237
|
+
}
|
|
10238
|
+
});
|
|
10239
|
+
rememberScroll();
|
|
10240
|
+
scrollEl.addEventListener("scroll", onScroll);
|
|
10241
|
+
scrollEl.addEventListener("wheel", onWheel, { passive: true });
|
|
10242
|
+
resizeObserver.observe(scrollEl);
|
|
10243
|
+
return () => {
|
|
10244
|
+
scrollEl.removeEventListener("scroll", onScroll);
|
|
10245
|
+
scrollEl.removeEventListener("wheel", onWheel);
|
|
10246
|
+
cancelAnimationFrame(pendingFrame);
|
|
10247
|
+
cancelAnimationFrame(resumeFrame);
|
|
10248
|
+
cancelAnimationFrame(settleFrame);
|
|
10249
|
+
resizeObserver.disconnect();
|
|
10250
|
+
};
|
|
10251
|
+
}, [
|
|
10252
|
+
scrollEl,
|
|
10253
|
+
scrollToBottom,
|
|
10254
|
+
stopScroll,
|
|
10255
|
+
scrollThreadId
|
|
10256
|
+
]);
|
|
10257
|
+
const startBottomPin = (0, react.useCallback)((instant = false) => {
|
|
10258
|
+
readingOffsetRef.current = null;
|
|
10259
|
+
pinIntentRef.current = true;
|
|
10260
|
+
scrollToBottom(instant ? { animation: "instant" } : void 0);
|
|
10261
|
+
}, [scrollToBottom]);
|
|
10262
|
+
const previousScrollThreadId = (0, react.useRef)(scrollThreadId);
|
|
10263
|
+
(0, react.useEffect)(() => {
|
|
10264
|
+
if (previousScrollThreadId.current === scrollThreadId) return;
|
|
10265
|
+
previousScrollThreadId.current = scrollThreadId;
|
|
10266
|
+
startBottomPin(true);
|
|
10267
|
+
}, [scrollThreadId, startBottomPin]);
|
|
8592
10268
|
const BoundFeather = renderSlot(feather, CopilotChatView.Feather, {});
|
|
8593
10269
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ScrollElementContext.Provider, {
|
|
8594
10270
|
value: scrollEl,
|
|
@@ -8610,7 +10286,7 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
|
|
|
8610
10286
|
!isAtBottom && !isResizing && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
8611
10287
|
className: "cpk:absolute cpk:inset-x-0 cpk:flex cpk:justify-center cpk:z-30 cpk:pointer-events-none",
|
|
8612
10288
|
style: { bottom: `${inputContainerHeight + SCROLL_BUTTON_OFFSET}px` },
|
|
8613
|
-
children: renderSlot(scrollToBottomButton, CopilotChatView.ScrollToBottomButton, { onClick: () =>
|
|
10289
|
+
children: renderSlot(scrollToBottomButton, CopilotChatView.ScrollToBottomButton, { onClick: () => startBottomPin() })
|
|
8614
10290
|
})
|
|
8615
10291
|
] })
|
|
8616
10292
|
})
|
|
@@ -8658,7 +10334,7 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
|
|
|
8658
10334
|
})
|
|
8659
10335
|
});
|
|
8660
10336
|
};
|
|
8661
|
-
_CopilotChatView.ScrollView = ({ children, autoScroll = "pin-to-bottom", scrollToBottomButton, feather, inputContainerHeight = 0, isResizing = false, className, ...props }) => {
|
|
10337
|
+
_CopilotChatView.ScrollView = ({ children, autoScroll = "pin-to-bottom", scrollThreadId, scrollToBottomButton, feather, inputContainerHeight = 0, isResizing = false, className, ...props }) => {
|
|
8662
10338
|
const mode = normalizeAutoScroll(autoScroll);
|
|
8663
10339
|
const [hasMounted, setHasMounted] = (0, react.useState)(false);
|
|
8664
10340
|
const scrollRef = (0, react.useRef)(null);
|
|
@@ -8747,6 +10423,7 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
|
|
|
8747
10423
|
initial: "smooth",
|
|
8748
10424
|
...props,
|
|
8749
10425
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ScrollContent, {
|
|
10426
|
+
scrollThreadId,
|
|
8750
10427
|
scrollToBottomButton,
|
|
8751
10428
|
feather,
|
|
8752
10429
|
inputContainerHeight,
|
|
@@ -8755,14 +10432,18 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
|
|
|
8755
10432
|
})
|
|
8756
10433
|
});
|
|
8757
10434
|
};
|
|
8758
|
-
_CopilotChatView.ScrollToBottomButton = ({ className, ...props }) =>
|
|
8759
|
-
|
|
8760
|
-
|
|
8761
|
-
|
|
8762
|
-
|
|
8763
|
-
|
|
8764
|
-
|
|
8765
|
-
|
|
10435
|
+
_CopilotChatView.ScrollToBottomButton = ({ className, ...props }) => {
|
|
10436
|
+
const labels = useCopilotChatConfiguration()?.labels ?? CopilotChatDefaultLabels;
|
|
10437
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
|
|
10438
|
+
"data-testid": "copilot-scroll-to-bottom",
|
|
10439
|
+
variant: "outline",
|
|
10440
|
+
size: "sm",
|
|
10441
|
+
className: (0, tailwind_merge.twMerge)("cpk:rounded-full cpk:w-10 cpk:h-10 cpk:p-0 cpk:pointer-events-auto", "cpk:bg-white cpk:dark:bg-gray-900", "cpk:shadow-lg cpk:border cpk:border-gray-200 cpk:dark:border-gray-700", "cpk:hover:bg-gray-50 cpk:dark:hover:bg-gray-800", "cpk:flex cpk:items-center cpk:justify-center cpk:cursor-pointer", className),
|
|
10442
|
+
"aria-label": labels.chatScrollToBottomLabel,
|
|
10443
|
+
...props,
|
|
10444
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.ChevronDown, { className: "cpk:w-4 cpk:h-4 cpk:text-gray-600 cpk:dark:text-white" })
|
|
10445
|
+
});
|
|
10446
|
+
};
|
|
8766
10447
|
_CopilotChatView.Feather = ({ className, ...props }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
8767
10448
|
className,
|
|
8768
10449
|
...props
|
|
@@ -10145,6 +11826,7 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
|
|
|
10145
11826
|
if (containerRef.current?.contains(target)) return;
|
|
10146
11827
|
const toggleButton = document.querySelector("[data-slot='chat-toggle-button']");
|
|
10147
11828
|
if (toggleButton && toggleButton.contains(target)) return;
|
|
11829
|
+
if (target instanceof Element && target.closest("[data-copilotkit-popover]")) return;
|
|
10148
11830
|
setModalOpen?.(false);
|
|
10149
11831
|
};
|
|
10150
11832
|
document.addEventListener("pointerdown", handlePointerDown);
|
|
@@ -10655,62 +12337,14 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
|
|
|
10655
12337
|
|
|
10656
12338
|
//#endregion
|
|
10657
12339
|
//#region src/v2/components/WildcardToolCallRender.tsx
|
|
12340
|
+
/**
|
|
12341
|
+
* Catch-all (`"*"`) tool-call renderer that shows CopilotKit's default
|
|
12342
|
+
* tool-call card for any tool without a dedicated renderer.
|
|
12343
|
+
*/
|
|
10658
12344
|
const WildcardToolCallRender = defineToolCallRenderer({
|
|
10659
12345
|
name: "*",
|
|
10660
|
-
|
|
10661
|
-
|
|
10662
|
-
const statusString = String(status);
|
|
10663
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
10664
|
-
className: "cpk:mt-2 cpk:pb-2",
|
|
10665
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10666
|
-
className: "cpk:rounded-xl cpk:border cpk:border-zinc-200/60 cpk:dark:border-zinc-800/60 cpk:bg-white/70 cpk:dark:bg-zinc-900/50 cpk:shadow-sm cpk:backdrop-blur cpk:p-4",
|
|
10667
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10668
|
-
className: "cpk:flex cpk:items-center cpk:justify-between cpk:gap-3 cpk:cursor-pointer",
|
|
10669
|
-
onClick: () => setIsExpanded(!isExpanded),
|
|
10670
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10671
|
-
className: "cpk:flex cpk:items-center cpk:gap-2 cpk:min-w-0",
|
|
10672
|
-
children: [
|
|
10673
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
|
|
10674
|
-
className: `cpk:h-4 cpk:w-4 cpk:text-zinc-500 cpk:dark:text-zinc-400 cpk:transition-transform ${isExpanded ? "cpk:rotate-90" : ""}`,
|
|
10675
|
-
fill: "none",
|
|
10676
|
-
viewBox: "0 0 24 24",
|
|
10677
|
-
strokeWidth: 2,
|
|
10678
|
-
stroke: "currentColor",
|
|
10679
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
|
|
10680
|
-
strokeLinecap: "round",
|
|
10681
|
-
strokeLinejoin: "round",
|
|
10682
|
-
d: "M8.25 4.5l7.5 7.5-7.5 7.5"
|
|
10683
|
-
})
|
|
10684
|
-
}),
|
|
10685
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: "cpk:inline-block cpk:h-2 cpk:w-2 cpk:rounded-full cpk:bg-blue-500" }),
|
|
10686
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
10687
|
-
className: "cpk:truncate cpk:text-sm cpk:font-medium cpk:text-zinc-900 cpk:dark:text-zinc-100",
|
|
10688
|
-
children: name
|
|
10689
|
-
})
|
|
10690
|
-
]
|
|
10691
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
10692
|
-
className: `cpk:inline-flex cpk:items-center cpk:rounded-full cpk:px-2 cpk:py-1 cpk:text-xs cpk:font-medium ${statusString === "inProgress" || statusString === "executing" ? "cpk:bg-amber-100 cpk:text-amber-800 cpk:dark:bg-amber-500/15 cpk:dark:text-amber-400" : statusString === "complete" ? "cpk:bg-emerald-100 cpk:text-emerald-800 cpk:dark:bg-emerald-500/15 cpk:dark:text-emerald-400" : "cpk:bg-zinc-100 cpk:text-zinc-800 cpk:dark:bg-zinc-700/40 cpk:dark:text-zinc-300"}`,
|
|
10693
|
-
children: String(status)
|
|
10694
|
-
})]
|
|
10695
|
-
}), isExpanded && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10696
|
-
className: "cpk:mt-3 cpk:grid cpk:gap-4",
|
|
10697
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
10698
|
-
className: "cpk:text-xs cpk:uppercase cpk:tracking-wide cpk:text-zinc-500 cpk:dark:text-zinc-400",
|
|
10699
|
-
children: "Arguments"
|
|
10700
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", {
|
|
10701
|
-
className: "cpk:mt-2 cpk:max-h-64 cpk:overflow-auto cpk:rounded-md cpk:bg-zinc-50 cpk:dark:bg-zinc-800/60 cpk:p-3 cpk:text-xs cpk:leading-relaxed cpk:text-zinc-800 cpk:dark:text-zinc-200 cpk:whitespace-pre-wrap cpk:break-words",
|
|
10702
|
-
children: JSON.stringify(args ?? {}, null, 2)
|
|
10703
|
-
})] }), result !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
10704
|
-
className: "cpk:text-xs cpk:uppercase cpk:tracking-wide cpk:text-zinc-500 cpk:dark:text-zinc-400",
|
|
10705
|
-
children: "Result"
|
|
10706
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", {
|
|
10707
|
-
className: "cpk:mt-2 cpk:max-h-64 cpk:overflow-auto cpk:rounded-md cpk:bg-zinc-50 cpk:dark:bg-zinc-800/60 cpk:p-3 cpk:text-xs cpk:leading-relaxed cpk:text-zinc-800 cpk:dark:text-zinc-200 cpk:whitespace-pre-wrap cpk:break-words",
|
|
10708
|
-
children: typeof result === "string" ? result : JSON.stringify(result, null, 2)
|
|
10709
|
-
})] })]
|
|
10710
|
-
})]
|
|
10711
|
-
})
|
|
10712
|
-
});
|
|
10713
|
-
}
|
|
12346
|
+
group: true,
|
|
12347
|
+
render: (props) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DefaultToolCallRenderer, { ...adaptRendererProps(props) })
|
|
10714
12348
|
});
|
|
10715
12349
|
|
|
10716
12350
|
//#endregion
|
|
@@ -12955,9 +14589,11 @@ exports.CopilotChatSuggestionView = CopilotChatSuggestionView;
|
|
|
12955
14589
|
exports.CopilotChatToggleButton = CopilotChatToggleButton;
|
|
12956
14590
|
exports.CopilotChatToggleButtonCloseIcon = DefaultCloseIcon;
|
|
12957
14591
|
exports.CopilotChatToggleButtonOpenIcon = DefaultOpenIcon;
|
|
14592
|
+
exports.CopilotChatToolCallGroup = CopilotChatToolCallGroup;
|
|
12958
14593
|
exports.CopilotChatToolCallsView = CopilotChatToolCallsView;
|
|
12959
14594
|
exports.CopilotChatUserMessage = CopilotChatUserMessage_default;
|
|
12960
14595
|
exports.CopilotChatView = CopilotChatView_default;
|
|
14596
|
+
exports.CopilotChatWorkSummary = CopilotChatWorkSummary;
|
|
12961
14597
|
exports.CopilotKit = CopilotKit;
|
|
12962
14598
|
Object.defineProperty(exports, 'CopilotKitCore', {
|
|
12963
14599
|
enumerable: true,
|