@copilotkit/react-core 0.0.0-main-20260403195251 → 0.0.0-main-20260407163127
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +10 -6
- package/dist/{copilotkit-CDZGGOIB.cjs → copilotkit-B3Eeystj.cjs} +907 -153
- package/dist/copilotkit-B3Eeystj.cjs.map +1 -0
- package/dist/{copilotkit-BYNyIuE7.d.ts → copilotkit-B_nbOmBS.d.cts} +96 -13
- package/dist/copilotkit-B_nbOmBS.d.cts.map +1 -0
- package/dist/{copilotkit-rBCfdqIo.d.mts → copilotkit-Cs-8EAok.d.mts} +96 -13
- package/dist/copilotkit-Cs-8EAok.d.mts.map +1 -0
- package/dist/{copilotkit-BK_zLoVm.mjs → copilotkit-D3sdzqTz.mjs} +893 -157
- package/dist/copilotkit-D3sdzqTz.mjs.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.umd.js +4 -4
- package/dist/index.umd.js.map +1 -1
- package/dist/v2/index.cjs +4 -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 +913 -155
- package/dist/v2/index.umd.js.map +1 -1
- package/package.json +18 -10
- package/src/v2/__tests__/utils/test-helpers.tsx +64 -0
- package/src/v2/components/chat/CopilotChat.tsx +151 -31
- package/src/v2/components/chat/CopilotChatAssistantMessage.tsx +17 -2
- package/src/v2/components/chat/CopilotChatAttachmentQueue.tsx +481 -0
- package/src/v2/components/chat/CopilotChatAttachmentRenderer.tsx +139 -0
- package/src/v2/components/chat/CopilotChatInput.tsx +4 -20
- package/src/v2/components/chat/CopilotChatMessageView.tsx +253 -149
- package/src/v2/components/chat/CopilotChatUserMessage.tsx +54 -0
- package/src/v2/components/chat/CopilotChatView.tsx +179 -66
- package/src/v2/components/chat/__tests__/CopilotChat.attachments.test.tsx +168 -0
- package/src/v2/components/chat/__tests__/CopilotChatActivityRendering.e2e.test.tsx +63 -2
- package/src/v2/components/chat/__tests__/CopilotChatInput.test.tsx +47 -1
- package/src/v2/components/chat/__tests__/CopilotChatPerf.e2e.test.tsx +268 -0
- package/src/v2/components/chat/__tests__/MCPAppsActivityRenderer.e2e.test.tsx +43 -2
- package/src/v2/components/chat/index.ts +9 -0
- package/src/v2/components/chat/scroll-element-context.ts +13 -0
- package/src/v2/hooks/__tests__/use-attachments.test.tsx +169 -0
- package/src/v2/hooks/__tests__/use-threads.test.tsx +54 -0
- package/src/v2/hooks/index.ts +5 -0
- package/src/v2/hooks/use-attachments.tsx +269 -0
- package/src/v2/hooks/use-render-activity-message.tsx +9 -2
- package/src/v2/hooks/use-threads.tsx +35 -15
- package/src/v2/providers/CopilotChatConfigurationProvider.tsx +1 -1
- package/src/v2/providers/CopilotKitProvider.tsx +14 -3
- package/src/v2/providers/__tests__/CopilotKitProvider.test.tsx +70 -0
- package/dist/copilotkit-BK_zLoVm.mjs.map +0 -1
- package/dist/copilotkit-BYNyIuE7.d.cts +0 -2208
- package/dist/copilotkit-BYNyIuE7.d.cts.map +0 -1
- package/dist/copilotkit-BYNyIuE7.d.ts.map +0 -1
- package/dist/copilotkit-CDZGGOIB.cjs.map +0 -1
- package/dist/copilotkit-rBCfdqIo.d.mts.map +0 -1
- package/dist/index.d.ts +0 -667
- package/dist/index.d.ts.map +0 -1
- package/dist/v2/index.d.ts +0 -6
|
@@ -44,9 +44,10 @@ let streamdown = require("streamdown");
|
|
|
44
44
|
let zod = require("zod");
|
|
45
45
|
let _lit_labs_react = require("@lit-labs/react");
|
|
46
46
|
let _copilotkit_a2ui_renderer = require("@copilotkit/a2ui-renderer");
|
|
47
|
+
let _tanstack_react_virtual = require("@tanstack/react-virtual");
|
|
48
|
+
let react_dom = require("react-dom");
|
|
47
49
|
let use_stick_to_bottom = require("use-stick-to-bottom");
|
|
48
50
|
let ts_deepmerge = require("ts-deepmerge");
|
|
49
|
-
let react_dom = require("react-dom");
|
|
50
51
|
let react_markdown = require("react-markdown");
|
|
51
52
|
react_markdown = __toESM(react_markdown);
|
|
52
53
|
|
|
@@ -56,7 +57,7 @@ const CopilotChatDefaultLabels = {
|
|
|
56
57
|
chatInputToolbarStartTranscribeButtonLabel: "Transcribe",
|
|
57
58
|
chatInputToolbarCancelTranscribeButtonLabel: "Cancel",
|
|
58
59
|
chatInputToolbarFinishTranscribeButtonLabel: "Finish",
|
|
59
|
-
chatInputToolbarAddButtonLabel: "Add
|
|
60
|
+
chatInputToolbarAddButtonLabel: "Add attachments",
|
|
60
61
|
chatInputToolbarToolsButtonLabel: "Tools",
|
|
61
62
|
assistantMessageToolbarCopyCodeLabel: "Copy",
|
|
62
63
|
assistantMessageToolbarCopyCodeCopiedLabel: "Copied",
|
|
@@ -578,7 +579,7 @@ function renderSlot(slot, DefaultComponent, props) {
|
|
|
578
579
|
//#region src/v2/components/chat/CopilotChatInput.tsx
|
|
579
580
|
const SLASH_MENU_MAX_VISIBLE_ITEMS = 5;
|
|
580
581
|
const SLASH_MENU_ITEM_HEIGHT_PX = 40;
|
|
581
|
-
function CopilotChatInput({ mode = "input", onSubmitMessage, onStop, isRunning = false, onStartTranscribe, onCancelTranscribe, onFinishTranscribe, onFinishTranscribeWithAudio, onAddFile, onChange, value, toolsMenu, autoFocus =
|
|
582
|
+
function CopilotChatInput({ mode = "input", onSubmitMessage, onStop, isRunning = false, onStartTranscribe, onCancelTranscribe, onFinishTranscribe, onFinishTranscribeWithAudio, onAddFile, onChange, value, toolsMenu, autoFocus = false, positioning = "static", keyboardHeight = 0, containerRef, showDisclaimer, textArea, sendButton, startTranscribeButton, cancelTranscribeButton, finishTranscribeButton, addMenuButton, audioRecorder, disclaimer, children, className, ...props }) {
|
|
582
583
|
const isControlled = value !== void 0;
|
|
583
584
|
const [internalValue, setInternalValue] = (0, react.useState)(() => value ?? "");
|
|
584
585
|
(0, react.useEffect)(() => {
|
|
@@ -651,7 +652,7 @@ function CopilotChatInput({ mode = "input", onSubmitMessage, onStop, isRunning =
|
|
|
651
652
|
previousModalStateRef.current = config?.isModalOpen;
|
|
652
653
|
return;
|
|
653
654
|
}
|
|
654
|
-
if (config?.isModalOpen && !previousModalStateRef.current) inputRef.current?.focus();
|
|
655
|
+
if (config?.isModalOpen && !previousModalStateRef.current) inputRef.current?.focus({ preventScroll: true });
|
|
655
656
|
previousModalStateRef.current = config?.isModalOpen;
|
|
656
657
|
}, [config?.isModalOpen, autoFocus]);
|
|
657
658
|
(0, react.useEffect)(() => {
|
|
@@ -1175,7 +1176,7 @@ function CopilotChatInput({ mode = "input", onSubmitMessage, onStop, isRunning =
|
|
|
1175
1176
|
side: "bottom",
|
|
1176
1177
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
|
|
1177
1178
|
className: "cpk:flex cpk:items-center cpk:gap-1 cpk:text-xs cpk:font-medium",
|
|
1178
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "Add
|
|
1179
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "Add attachments" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", {
|
|
1179
1180
|
className: "cpk:rounded cpk:bg-[#4a4a4a] cpk:px-1 cpk:py-[1px] cpk:font-mono cpk:text-[11px] cpk:text-white cpk:dark:bg-[#e0e0e0] cpk:dark:text-black",
|
|
1180
1181
|
children: "/"
|
|
1181
1182
|
})]
|
|
@@ -1191,21 +1192,7 @@ function CopilotChatInput({ mode = "input", onSubmitMessage, onStop, isRunning =
|
|
|
1191
1192
|
const labels = useCopilotChatConfiguration()?.labels ?? CopilotChatDefaultLabels;
|
|
1192
1193
|
(0, react.useImperativeHandle)(ref, () => internalTextareaRef.current);
|
|
1193
1194
|
(0, react.useEffect)(() => {
|
|
1194
|
-
|
|
1195
|
-
if (!textarea) return;
|
|
1196
|
-
const handleFocus = () => {
|
|
1197
|
-
setTimeout(() => {
|
|
1198
|
-
textarea.scrollIntoView({
|
|
1199
|
-
behavior: "smooth",
|
|
1200
|
-
block: "nearest"
|
|
1201
|
-
});
|
|
1202
|
-
}, 300);
|
|
1203
|
-
};
|
|
1204
|
-
textarea.addEventListener("focus", handleFocus);
|
|
1205
|
-
return () => textarea.removeEventListener("focus", handleFocus);
|
|
1206
|
-
}, []);
|
|
1207
|
-
(0, react.useEffect)(() => {
|
|
1208
|
-
if (autoFocus) internalTextareaRef.current?.focus();
|
|
1195
|
+
if (autoFocus) internalTextareaRef.current?.focus({ preventScroll: true });
|
|
1209
1196
|
}, [autoFocus]);
|
|
1210
1197
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
|
|
1211
1198
|
ref: internalTextareaRef,
|
|
@@ -2149,7 +2136,7 @@ function useStableArrayProp(prop, warningMessage, isMeaningfulChange) {
|
|
|
2149
2136
|
}, [value, warningMessage]);
|
|
2150
2137
|
return value;
|
|
2151
2138
|
}
|
|
2152
|
-
const CopilotKitProvider = ({ children, runtimeUrl, headers = {}, credentials, publicApiKey, publicLicenseKey, licenseToken, properties = {}, agents__unsafe_dev_only: agents = {}, selfManagedAgents = {}, renderToolCalls, renderActivityMessages, renderCustomMessages, frontendTools, humanInTheLoop, showDevConsole = false, useSingleEndpoint
|
|
2139
|
+
const CopilotKitProvider = ({ children, runtimeUrl, headers = {}, credentials, publicApiKey, publicLicenseKey, licenseToken, properties = {}, agents__unsafe_dev_only: agents = {}, selfManagedAgents = {}, renderToolCalls, renderActivityMessages, renderCustomMessages, frontendTools, humanInTheLoop, showDevConsole = false, useSingleEndpoint, onError, a2ui }) => {
|
|
2153
2140
|
const [shouldRenderInspector, setShouldRenderInspector] = (0, react.useState)(false);
|
|
2154
2141
|
const [runtimeA2UIEnabled, setRuntimeA2UIEnabled] = (0, react.useState)(false);
|
|
2155
2142
|
const [runtimeLicenseStatus, setRuntimeLicenseStatus] = (0, react.useState)(void 0);
|
|
@@ -2263,7 +2250,7 @@ const CopilotKitProvider = ({ children, runtimeUrl, headers = {}, credentials, p
|
|
|
2263
2250
|
const copilotkitRef = (0, react.useRef)(null);
|
|
2264
2251
|
if (copilotkitRef.current === null) copilotkitRef.current = new CopilotKitCoreReact({
|
|
2265
2252
|
runtimeUrl: chatApiEndpoint,
|
|
2266
|
-
runtimeTransport: useSingleEndpoint ? "single" : "rest",
|
|
2253
|
+
runtimeTransport: useSingleEndpoint === true ? "single" : useSingleEndpoint === false ? "rest" : "auto",
|
|
2267
2254
|
headers: mergedHeaders,
|
|
2268
2255
|
credentials,
|
|
2269
2256
|
properties,
|
|
@@ -2335,7 +2322,7 @@ const CopilotKitProvider = ({ children, runtimeUrl, headers = {}, credentials, p
|
|
|
2335
2322
|
}, [copilotkit]);
|
|
2336
2323
|
(0, react.useEffect)(() => {
|
|
2337
2324
|
copilotkit.setRuntimeUrl(chatApiEndpoint);
|
|
2338
|
-
copilotkit.setRuntimeTransport(useSingleEndpoint ? "single" : "rest");
|
|
2325
|
+
copilotkit.setRuntimeTransport(useSingleEndpoint === true ? "single" : useSingleEndpoint === false ? "rest" : "auto");
|
|
2339
2326
|
copilotkit.setHeaders(mergedHeaders);
|
|
2340
2327
|
copilotkit.setCredentials(credentials);
|
|
2341
2328
|
copilotkit.setProperties(properties);
|
|
@@ -2701,7 +2688,8 @@ function useRenderCustomMessages() {
|
|
|
2701
2688
|
//#region src/v2/hooks/use-render-activity-message.tsx
|
|
2702
2689
|
function useRenderActivityMessage() {
|
|
2703
2690
|
const { copilotkit } = useCopilotKit();
|
|
2704
|
-
const
|
|
2691
|
+
const config = useCopilotChatConfiguration();
|
|
2692
|
+
const agentId = config?.agentId ?? _copilotkit_shared.DEFAULT_AGENT_ID;
|
|
2705
2693
|
const renderers = copilotkit.renderActivityMessages;
|
|
2706
2694
|
const findRenderer = (0, react.useCallback)((activityType) => {
|
|
2707
2695
|
if (!renderers.length) return null;
|
|
@@ -2717,7 +2705,8 @@ function useRenderActivityMessage() {
|
|
|
2717
2705
|
return null;
|
|
2718
2706
|
}
|
|
2719
2707
|
const Component = renderer.render;
|
|
2720
|
-
const
|
|
2708
|
+
const registryAgent = copilotkit.getAgent(agentId);
|
|
2709
|
+
const agent = getThreadClone(registryAgent, config?.threadId) ?? registryAgent;
|
|
2721
2710
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Component, {
|
|
2722
2711
|
activityType: message.activityType,
|
|
2723
2712
|
content: parseResult.data,
|
|
@@ -2726,6 +2715,7 @@ function useRenderActivityMessage() {
|
|
|
2726
2715
|
}, message.id);
|
|
2727
2716
|
}, [
|
|
2728
2717
|
agentId,
|
|
2718
|
+
config?.threadId,
|
|
2729
2719
|
copilotkit,
|
|
2730
2720
|
findRenderer
|
|
2731
2721
|
]);
|
|
@@ -3611,11 +3601,19 @@ function useThreadStoreSelector(store, selector) {
|
|
|
3611
3601
|
function useThreads$1({ agentId, includeArchived, limit }) {
|
|
3612
3602
|
const { copilotkit } = useCopilotKit();
|
|
3613
3603
|
const [store] = (0, react.useState)(() => (0, _copilotkit_core.ɵcreateThreadStore)({ fetch: globalThis.fetch }));
|
|
3614
|
-
const
|
|
3604
|
+
const coreThreads = useThreadStoreSelector(store, _copilotkit_core.ɵselectThreads);
|
|
3605
|
+
const threads = (0, react.useMemo)(() => coreThreads.map(({ id, agentId, name, archived, createdAt, updatedAt }) => ({
|
|
3606
|
+
id,
|
|
3607
|
+
agentId,
|
|
3608
|
+
name,
|
|
3609
|
+
archived,
|
|
3610
|
+
createdAt,
|
|
3611
|
+
updatedAt
|
|
3612
|
+
})), [coreThreads]);
|
|
3615
3613
|
const storeIsLoading = useThreadStoreSelector(store, _copilotkit_core.ɵselectThreadsIsLoading);
|
|
3616
3614
|
const storeError = useThreadStoreSelector(store, _copilotkit_core.ɵselectThreadsError);
|
|
3617
|
-
const
|
|
3618
|
-
const
|
|
3615
|
+
const hasMoreThreads = useThreadStoreSelector(store, _copilotkit_core.ɵselectHasNextPage);
|
|
3616
|
+
const isFetchingMoreThreads = useThreadStoreSelector(store, _copilotkit_core.ɵselectIsFetchingNextPage);
|
|
3619
3617
|
const headersKey = (0, react.useMemo)(() => {
|
|
3620
3618
|
return JSON.stringify(Object.entries(copilotkit.headers ?? {}).sort(([left], [right]) => left.localeCompare(right)));
|
|
3621
3619
|
}, [copilotkit.headers]);
|
|
@@ -3658,15 +3656,173 @@ function useThreads$1({ agentId, includeArchived, limit }) {
|
|
|
3658
3656
|
threads,
|
|
3659
3657
|
isLoading,
|
|
3660
3658
|
error,
|
|
3661
|
-
|
|
3662
|
-
|
|
3663
|
-
|
|
3659
|
+
hasMoreThreads,
|
|
3660
|
+
isFetchingMoreThreads,
|
|
3661
|
+
fetchMoreThreads: (0, react.useCallback)(() => store.fetchNextPage(), [store]),
|
|
3664
3662
|
renameThread,
|
|
3665
3663
|
archiveThread,
|
|
3666
3664
|
deleteThread
|
|
3667
3665
|
};
|
|
3668
3666
|
}
|
|
3669
3667
|
|
|
3668
|
+
//#endregion
|
|
3669
|
+
//#region src/v2/hooks/use-attachments.tsx
|
|
3670
|
+
/**
|
|
3671
|
+
* Hook that manages file attachment state — uploads, drag-and-drop, paste,
|
|
3672
|
+
* and lifecycle. All returned callbacks are referentially stable across
|
|
3673
|
+
* renders (via useCallback) to avoid destabilizing downstream memoization.
|
|
3674
|
+
*/
|
|
3675
|
+
function useAttachments({ config }) {
|
|
3676
|
+
const enabled = config?.enabled ?? false;
|
|
3677
|
+
const [attachments, setAttachments] = (0, react.useState)([]);
|
|
3678
|
+
const [dragOver, setDragOver] = (0, react.useState)(false);
|
|
3679
|
+
const fileInputRef = (0, react.useRef)(null);
|
|
3680
|
+
const containerRef = (0, react.useRef)(null);
|
|
3681
|
+
const configRef = (0, react.useRef)(config);
|
|
3682
|
+
configRef.current = config;
|
|
3683
|
+
const attachmentsRef = (0, react.useRef)([]);
|
|
3684
|
+
attachmentsRef.current = attachments;
|
|
3685
|
+
const processFiles = (0, react.useCallback)(async (files) => {
|
|
3686
|
+
const cfg = configRef.current;
|
|
3687
|
+
const accept = cfg?.accept ?? "*/*";
|
|
3688
|
+
const maxSize = cfg?.maxSize ?? 20 * 1024 * 1024;
|
|
3689
|
+
const rejectedFiles = files.filter((file) => !(0, _copilotkit_shared.matchesAcceptFilter)(file, accept));
|
|
3690
|
+
for (const file of rejectedFiles) cfg?.onUploadFailed?.({
|
|
3691
|
+
reason: "invalid-type",
|
|
3692
|
+
file,
|
|
3693
|
+
message: `File "${file.name}" is not accepted. Supported types: ${accept}`
|
|
3694
|
+
});
|
|
3695
|
+
const validFiles = files.filter((file) => (0, _copilotkit_shared.matchesAcceptFilter)(file, accept));
|
|
3696
|
+
for (const file of validFiles) {
|
|
3697
|
+
if ((0, _copilotkit_shared.exceedsMaxSize)(file, maxSize)) {
|
|
3698
|
+
cfg?.onUploadFailed?.({
|
|
3699
|
+
reason: "file-too-large",
|
|
3700
|
+
file,
|
|
3701
|
+
message: `File "${file.name}" exceeds the maximum size of ${(0, _copilotkit_shared.formatFileSize)(maxSize)}`
|
|
3702
|
+
});
|
|
3703
|
+
continue;
|
|
3704
|
+
}
|
|
3705
|
+
const modality = (0, _copilotkit_shared.getModalityFromMimeType)(file.type);
|
|
3706
|
+
const placeholderId = (0, _copilotkit_shared.randomUUID)();
|
|
3707
|
+
const placeholder = {
|
|
3708
|
+
id: placeholderId,
|
|
3709
|
+
type: modality,
|
|
3710
|
+
source: {
|
|
3711
|
+
type: "data",
|
|
3712
|
+
value: "",
|
|
3713
|
+
mimeType: file.type
|
|
3714
|
+
},
|
|
3715
|
+
filename: file.name,
|
|
3716
|
+
size: file.size,
|
|
3717
|
+
status: "uploading"
|
|
3718
|
+
};
|
|
3719
|
+
setAttachments((prev) => [...prev, placeholder]);
|
|
3720
|
+
try {
|
|
3721
|
+
let source;
|
|
3722
|
+
let uploadMetadata;
|
|
3723
|
+
if (cfg?.onUpload) {
|
|
3724
|
+
const { metadata: meta, ...uploadSource } = await cfg.onUpload(file);
|
|
3725
|
+
source = uploadSource;
|
|
3726
|
+
uploadMetadata = meta;
|
|
3727
|
+
} else source = {
|
|
3728
|
+
type: "data",
|
|
3729
|
+
value: await (0, _copilotkit_shared.readFileAsBase64)(file),
|
|
3730
|
+
mimeType: file.type
|
|
3731
|
+
};
|
|
3732
|
+
let thumbnail;
|
|
3733
|
+
if (modality === "video") thumbnail = await (0, _copilotkit_shared.generateVideoThumbnail)(file);
|
|
3734
|
+
setAttachments((prev) => prev.map((att) => att.id === placeholderId ? {
|
|
3735
|
+
...att,
|
|
3736
|
+
source,
|
|
3737
|
+
status: "ready",
|
|
3738
|
+
thumbnail,
|
|
3739
|
+
metadata: uploadMetadata
|
|
3740
|
+
} : att));
|
|
3741
|
+
} catch (error) {
|
|
3742
|
+
setAttachments((prev) => prev.filter((att) => att.id !== placeholderId));
|
|
3743
|
+
console.error(`[CopilotKit] Failed to upload "${file.name}":`, error);
|
|
3744
|
+
cfg?.onUploadFailed?.({
|
|
3745
|
+
reason: "upload-failed",
|
|
3746
|
+
file,
|
|
3747
|
+
message: error instanceof Error ? error.message : `Failed to upload "${file.name}"`
|
|
3748
|
+
});
|
|
3749
|
+
}
|
|
3750
|
+
}
|
|
3751
|
+
}, []);
|
|
3752
|
+
const handleFileUpload = (0, react.useCallback)(async (e) => {
|
|
3753
|
+
if (!e.target.files?.length) return;
|
|
3754
|
+
try {
|
|
3755
|
+
await processFiles(Array.from(e.target.files));
|
|
3756
|
+
} catch (error) {
|
|
3757
|
+
console.error("[CopilotKit] Upload error:", error);
|
|
3758
|
+
}
|
|
3759
|
+
}, [processFiles]);
|
|
3760
|
+
const handleDragOver = (0, react.useCallback)((e) => {
|
|
3761
|
+
if (!configRef.current?.enabled) return;
|
|
3762
|
+
e.preventDefault();
|
|
3763
|
+
e.stopPropagation();
|
|
3764
|
+
setDragOver(true);
|
|
3765
|
+
}, []);
|
|
3766
|
+
const handleDragLeave = (0, react.useCallback)((e) => {
|
|
3767
|
+
e.preventDefault();
|
|
3768
|
+
e.stopPropagation();
|
|
3769
|
+
setDragOver(false);
|
|
3770
|
+
}, []);
|
|
3771
|
+
const handleDrop = (0, react.useCallback)(async (e) => {
|
|
3772
|
+
e.preventDefault();
|
|
3773
|
+
e.stopPropagation();
|
|
3774
|
+
setDragOver(false);
|
|
3775
|
+
if (!configRef.current?.enabled) return;
|
|
3776
|
+
const files = Array.from(e.dataTransfer.files);
|
|
3777
|
+
if (files.length > 0) try {
|
|
3778
|
+
await processFiles(files);
|
|
3779
|
+
} catch (error) {
|
|
3780
|
+
console.error("[CopilotKit] Drop error:", error);
|
|
3781
|
+
}
|
|
3782
|
+
}, [processFiles]);
|
|
3783
|
+
(0, react.useEffect)(() => {
|
|
3784
|
+
if (!enabled) return;
|
|
3785
|
+
const handlePaste = async (e) => {
|
|
3786
|
+
const target = e.target;
|
|
3787
|
+
if (!target || !containerRef.current?.contains(target)) return;
|
|
3788
|
+
const accept = configRef.current?.accept ?? "*/*";
|
|
3789
|
+
const fileItems = Array.from(e.clipboardData?.items || []).filter((item) => item.kind === "file" && item.getAsFile() !== null && (0, _copilotkit_shared.matchesAcceptFilter)(item.getAsFile(), accept));
|
|
3790
|
+
if (fileItems.length === 0) return;
|
|
3791
|
+
e.preventDefault();
|
|
3792
|
+
const files = fileItems.map((item) => item.getAsFile()).filter((f) => f !== null);
|
|
3793
|
+
try {
|
|
3794
|
+
await processFiles(files);
|
|
3795
|
+
} catch (error) {
|
|
3796
|
+
console.error("[CopilotKit] Paste error:", error);
|
|
3797
|
+
}
|
|
3798
|
+
};
|
|
3799
|
+
document.addEventListener("paste", handlePaste);
|
|
3800
|
+
return () => document.removeEventListener("paste", handlePaste);
|
|
3801
|
+
}, [enabled, processFiles]);
|
|
3802
|
+
return {
|
|
3803
|
+
attachments,
|
|
3804
|
+
enabled,
|
|
3805
|
+
dragOver,
|
|
3806
|
+
fileInputRef,
|
|
3807
|
+
containerRef,
|
|
3808
|
+
processFiles,
|
|
3809
|
+
handleFileUpload,
|
|
3810
|
+
handleDragOver,
|
|
3811
|
+
handleDragLeave,
|
|
3812
|
+
handleDrop,
|
|
3813
|
+
removeAttachment: (0, react.useCallback)((id) => {
|
|
3814
|
+
setAttachments((prev) => prev.filter((a) => a.id !== id));
|
|
3815
|
+
}, []),
|
|
3816
|
+
consumeAttachments: (0, react.useCallback)(() => {
|
|
3817
|
+
const ready = attachmentsRef.current.filter((a) => a.status === "ready");
|
|
3818
|
+
if (ready.length === 0) return ready;
|
|
3819
|
+
setAttachments((prev) => prev.filter((a) => a.status !== "ready"));
|
|
3820
|
+
if (fileInputRef.current) fileInputRef.current.value = "";
|
|
3821
|
+
return ready;
|
|
3822
|
+
}, [])
|
|
3823
|
+
};
|
|
3824
|
+
}
|
|
3825
|
+
|
|
3670
3826
|
//#endregion
|
|
3671
3827
|
//#region src/v2/components/chat/CopilotChatToolCallsView.tsx
|
|
3672
3828
|
function CopilotChatToolCallsView({ message, messages = [] }) {
|
|
@@ -3783,9 +3939,19 @@ function CopilotChatAssistantMessage({ message, messages, isRunning, onThumbsUp,
|
|
|
3783
3939
|
_CopilotChatAssistantMessage.CopyButton = ({ className, title, onClick, ...props }) => {
|
|
3784
3940
|
const labels = useCopilotChatConfiguration()?.labels ?? CopilotChatDefaultLabels;
|
|
3785
3941
|
const [copied, setCopied] = (0, react.useState)(false);
|
|
3942
|
+
const timerRef = (0, react.useRef)(null);
|
|
3943
|
+
(0, react.useEffect)(() => {
|
|
3944
|
+
return () => {
|
|
3945
|
+
if (timerRef.current !== null) clearTimeout(timerRef.current);
|
|
3946
|
+
};
|
|
3947
|
+
}, []);
|
|
3786
3948
|
const handleClick = (event) => {
|
|
3787
3949
|
setCopied(true);
|
|
3788
|
-
|
|
3950
|
+
if (timerRef.current !== null) clearTimeout(timerRef.current);
|
|
3951
|
+
timerRef.current = setTimeout(() => {
|
|
3952
|
+
timerRef.current = null;
|
|
3953
|
+
setCopied(false);
|
|
3954
|
+
}, 2e3);
|
|
3789
3955
|
if (onClick) onClick(event);
|
|
3790
3956
|
};
|
|
3791
3957
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ToolbarButton, {
|
|
@@ -3843,6 +4009,79 @@ CopilotChatAssistantMessage.ReadAloudButton.displayName = "CopilotChatAssistantM
|
|
|
3843
4009
|
CopilotChatAssistantMessage.RegenerateButton.displayName = "CopilotChatAssistantMessage.RegenerateButton";
|
|
3844
4010
|
var CopilotChatAssistantMessage_default = CopilotChatAssistantMessage;
|
|
3845
4011
|
|
|
4012
|
+
//#endregion
|
|
4013
|
+
//#region src/v2/components/chat/CopilotChatAttachmentRenderer.tsx
|
|
4014
|
+
const ImageAttachment = (0, react.memo)(function ImageAttachment({ src, className }) {
|
|
4015
|
+
const [error, setError] = (0, react.useState)(false);
|
|
4016
|
+
if (error) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4017
|
+
className: cn("cpk:flex cpk:flex-col cpk:items-center cpk:justify-center cpk:rounded-lg cpk:bg-muted cpk:p-4 cpk:text-sm cpk:text-muted-foreground", className),
|
|
4018
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "Failed to load image" })
|
|
4019
|
+
});
|
|
4020
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
|
|
4021
|
+
src,
|
|
4022
|
+
alt: "Image attachment",
|
|
4023
|
+
className: cn("cpk:max-w-full cpk:h-auto cpk:rounded-lg", className),
|
|
4024
|
+
onError: () => setError(true)
|
|
4025
|
+
});
|
|
4026
|
+
});
|
|
4027
|
+
const AudioAttachment = (0, react.memo)(function AudioAttachment({ src, filename, className }) {
|
|
4028
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4029
|
+
className: cn("cpk:flex cpk:flex-col cpk:gap-1", className),
|
|
4030
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("audio", {
|
|
4031
|
+
src,
|
|
4032
|
+
controls: true,
|
|
4033
|
+
preload: "metadata",
|
|
4034
|
+
className: "cpk:max-w-[300px] cpk:w-full cpk:h-10"
|
|
4035
|
+
}), filename && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4036
|
+
className: "cpk:text-xs cpk:text-muted-foreground cpk:truncate cpk:max-w-[300px]",
|
|
4037
|
+
children: filename
|
|
4038
|
+
})]
|
|
4039
|
+
});
|
|
4040
|
+
});
|
|
4041
|
+
const VideoAttachment = (0, react.memo)(function VideoAttachment({ src, className }) {
|
|
4042
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("video", {
|
|
4043
|
+
src,
|
|
4044
|
+
controls: true,
|
|
4045
|
+
preload: "metadata",
|
|
4046
|
+
className: cn("cpk:max-w-[400px] cpk:w-full cpk:rounded-lg", className)
|
|
4047
|
+
});
|
|
4048
|
+
});
|
|
4049
|
+
const DocumentAttachment = (0, react.memo)(function DocumentAttachment({ source, filename, className }) {
|
|
4050
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4051
|
+
className: cn("cpk:inline-flex cpk:items-center cpk:gap-2 cpk:px-3 cpk:py-2 cpk:border cpk:border-border cpk:rounded-lg cpk:bg-muted", className),
|
|
4052
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4053
|
+
className: "cpk:text-xs cpk:font-bold cpk:uppercase",
|
|
4054
|
+
children: (0, _copilotkit_shared.getDocumentIcon)(source.mimeType ?? "")
|
|
4055
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4056
|
+
className: "cpk:text-sm cpk:text-muted-foreground cpk:truncate",
|
|
4057
|
+
children: filename || source.mimeType || "Unknown type"
|
|
4058
|
+
})]
|
|
4059
|
+
});
|
|
4060
|
+
});
|
|
4061
|
+
const CopilotChatAttachmentRenderer = ({ type, source, filename, className }) => {
|
|
4062
|
+
const src = (0, _copilotkit_shared.getSourceUrl)(source);
|
|
4063
|
+
switch (type) {
|
|
4064
|
+
case "image": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ImageAttachment, {
|
|
4065
|
+
src,
|
|
4066
|
+
className
|
|
4067
|
+
});
|
|
4068
|
+
case "audio": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AudioAttachment, {
|
|
4069
|
+
src,
|
|
4070
|
+
filename,
|
|
4071
|
+
className
|
|
4072
|
+
});
|
|
4073
|
+
case "video": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(VideoAttachment, {
|
|
4074
|
+
src,
|
|
4075
|
+
className
|
|
4076
|
+
});
|
|
4077
|
+
case "document": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DocumentAttachment, {
|
|
4078
|
+
source,
|
|
4079
|
+
filename,
|
|
4080
|
+
className
|
|
4081
|
+
});
|
|
4082
|
+
}
|
|
4083
|
+
};
|
|
4084
|
+
|
|
3846
4085
|
//#endregion
|
|
3847
4086
|
//#region src/v2/components/chat/CopilotChatUserMessage.tsx
|
|
3848
4087
|
function flattenUserMessageContent(content) {
|
|
@@ -3853,8 +4092,17 @@ function flattenUserMessageContent(content) {
|
|
|
3853
4092
|
return "";
|
|
3854
4093
|
}).filter((text) => text.length > 0).join("\n");
|
|
3855
4094
|
}
|
|
4095
|
+
function getMediaParts(content) {
|
|
4096
|
+
if (!content || typeof content === "string") return [];
|
|
4097
|
+
return content.filter((part) => part.type === "image" || part.type === "audio" || part.type === "video" || part.type === "document");
|
|
4098
|
+
}
|
|
4099
|
+
function getFilename(part) {
|
|
4100
|
+
const meta = part.metadata;
|
|
4101
|
+
if (meta != null && typeof meta === "object" && "filename" in meta && typeof meta.filename === "string") return meta.filename;
|
|
4102
|
+
}
|
|
3856
4103
|
function CopilotChatUserMessage({ message, onEditMessage, branchIndex, numberOfBranches, onSwitchToBranch, additionalToolbarItems, messageRenderer, toolbar, copyButton, editButton, branchNavigation, children, className, ...props }) {
|
|
3857
4104
|
const flattenedContent = (0, react.useMemo)(() => flattenUserMessageContent(message.content), [message.content]);
|
|
4105
|
+
const mediaParts = (0, react.useMemo)(() => getMediaParts(message.content), [message.content]);
|
|
3858
4106
|
const BoundMessageRenderer = renderSlot(messageRenderer, CopilotChatUserMessage.MessageRenderer, { content: flattenedContent });
|
|
3859
4107
|
const BoundCopyButton = renderSlot(copyButton, CopilotChatUserMessage.CopyButton, { onClick: async () => {
|
|
3860
4108
|
if (flattenedContent) try {
|
|
@@ -3901,7 +4149,18 @@ function CopilotChatUserMessage({ message, onEditMessage, branchIndex, numberOfB
|
|
|
3901
4149
|
className: (0, tailwind_merge.twMerge)("copilotKitMessage copilotKitUserMessage cpk:flex cpk:flex-col cpk:items-end cpk:group cpk:pt-10", className),
|
|
3902
4150
|
"data-message-id": message.id,
|
|
3903
4151
|
...props,
|
|
3904
|
-
children: [
|
|
4152
|
+
children: [
|
|
4153
|
+
BoundMessageRenderer,
|
|
4154
|
+
mediaParts.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4155
|
+
className: "cpk:flex cpk:flex-col cpk:items-end cpk:gap-2 cpk:mt-2",
|
|
4156
|
+
children: mediaParts.map((part, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopilotChatAttachmentRenderer, {
|
|
4157
|
+
type: part.type,
|
|
4158
|
+
source: part.source,
|
|
4159
|
+
filename: getFilename(part)
|
|
4160
|
+
}, index))
|
|
4161
|
+
}),
|
|
4162
|
+
BoundToolbar
|
|
4163
|
+
]
|
|
3905
4164
|
});
|
|
3906
4165
|
}
|
|
3907
4166
|
(function(_CopilotChatUserMessage) {
|
|
@@ -4235,9 +4494,43 @@ const CopilotChatSuggestionView = react.default.forwardRef(function CopilotChatS
|
|
|
4235
4494
|
});
|
|
4236
4495
|
CopilotChatSuggestionView.displayName = "CopilotChatSuggestionView";
|
|
4237
4496
|
|
|
4497
|
+
//#endregion
|
|
4498
|
+
//#region src/v2/components/chat/scroll-element-context.ts
|
|
4499
|
+
/**
|
|
4500
|
+
* Provides the scroll container element to child components that need it for
|
|
4501
|
+
* virtualization. Set by CopilotChatView.ScrollView; consumed by
|
|
4502
|
+
* CopilotChatMessageView to feed useVirtualizer's getScrollElement.
|
|
4503
|
+
*
|
|
4504
|
+
* Carries the element itself (not a ref) so that context consumers re-render
|
|
4505
|
+
* reactively when the scroll container is first mounted.
|
|
4506
|
+
*/
|
|
4507
|
+
const ScrollElementContext = react.default.createContext(null);
|
|
4508
|
+
|
|
4238
4509
|
//#endregion
|
|
4239
4510
|
//#region src/v2/components/chat/CopilotChatMessageView.tsx
|
|
4240
4511
|
/**
|
|
4512
|
+
* Resolves a slot value into a { Component, slotProps } pair, handling the three
|
|
4513
|
+
* slot forms: a component type, a className string, or a partial-props object.
|
|
4514
|
+
*/
|
|
4515
|
+
function resolveSlotComponent(slot, DefaultComponent) {
|
|
4516
|
+
if (isReactComponentType(slot)) return {
|
|
4517
|
+
Component: slot,
|
|
4518
|
+
slotProps: void 0
|
|
4519
|
+
};
|
|
4520
|
+
if (typeof slot === "string") return {
|
|
4521
|
+
Component: DefaultComponent,
|
|
4522
|
+
slotProps: { className: slot }
|
|
4523
|
+
};
|
|
4524
|
+
if (slot && typeof slot === "object") return {
|
|
4525
|
+
Component: DefaultComponent,
|
|
4526
|
+
slotProps: slot
|
|
4527
|
+
};
|
|
4528
|
+
return {
|
|
4529
|
+
Component: DefaultComponent,
|
|
4530
|
+
slotProps: void 0
|
|
4531
|
+
};
|
|
4532
|
+
}
|
|
4533
|
+
/**
|
|
4241
4534
|
* Memoized wrapper for assistant messages to prevent re-renders when other messages change.
|
|
4242
4535
|
*/
|
|
4243
4536
|
const MemoizedAssistantMessage = react.default.memo(function MemoizedAssistantMessage({ message, messages, isRunning, AssistantMessageComponent, slotProps }) {
|
|
@@ -4256,7 +4549,6 @@ const MemoizedAssistantMessage = react.default.memo(function MemoizedAssistantMe
|
|
|
4256
4549
|
if (prevToolCalls && nextToolCalls) for (let i = 0; i < prevToolCalls.length; i++) {
|
|
4257
4550
|
const prevTc = prevToolCalls[i];
|
|
4258
4551
|
const nextTc = nextToolCalls[i];
|
|
4259
|
-
if (!prevTc || !nextTc) return false;
|
|
4260
4552
|
if (prevTc.id !== nextTc.id) return false;
|
|
4261
4553
|
if (prevTc.function.arguments !== nextTc.function.arguments) return false;
|
|
4262
4554
|
}
|
|
@@ -4335,6 +4627,7 @@ const MemoizedCustomMessage = react.default.memo(function MemoizedCustomMessage(
|
|
|
4335
4627
|
if (JSON.stringify(prevProps.stateSnapshot) !== JSON.stringify(nextProps.stateSnapshot)) return false;
|
|
4336
4628
|
return true;
|
|
4337
4629
|
});
|
|
4630
|
+
const VIRTUALIZE_THRESHOLD = 50;
|
|
4338
4631
|
function CopilotChatMessageView({ messages = [], assistantMessage, userMessage, reasoningMessage, cursor, isRunning = false, children, className, ...props }) {
|
|
4339
4632
|
const renderCustomMessage = useRenderCustomMessages();
|
|
4340
4633
|
const { renderActivityMessage } = useRenderActivityMessage();
|
|
@@ -4368,9 +4661,34 @@ function CopilotChatMessageView({ messages = [], assistantMessage, userMessage,
|
|
|
4368
4661
|
if (!resolvedRunId) return void 0;
|
|
4369
4662
|
return copilotkit.getStateByRun(config.agentId, config.threadId, resolvedRunId);
|
|
4370
4663
|
};
|
|
4371
|
-
const deduplicatedMessages = [...new Map(messages.map((m) => [m.id, m])).values()];
|
|
4664
|
+
const deduplicatedMessages = (0, react.useMemo)(() => [...new Map(messages.map((m) => [m.id, m])).values()], [messages]);
|
|
4372
4665
|
if (process.env.NODE_ENV === "development" && deduplicatedMessages.length < messages.length) console.warn(`CopilotChatMessageView: Deduplicated ${messages.length - deduplicatedMessages.length} message(s) with duplicate IDs.`);
|
|
4373
|
-
const
|
|
4666
|
+
const { Component: AssistantComponent, slotProps: assistantSlotProps } = (0, react.useMemo)(() => resolveSlotComponent(assistantMessage, CopilotChatAssistantMessage_default), [assistantMessage]);
|
|
4667
|
+
const { Component: UserComponent, slotProps: userSlotProps } = (0, react.useMemo)(() => resolveSlotComponent(userMessage, CopilotChatUserMessage_default), [userMessage]);
|
|
4668
|
+
const { Component: ReasoningComponent, slotProps: reasoningSlotProps } = (0, react.useMemo)(() => resolveSlotComponent(reasoningMessage, CopilotChatReasoningMessage_default), [reasoningMessage]);
|
|
4669
|
+
const scrollElementFromCtx = (0, react.useContext)(ScrollElementContext);
|
|
4670
|
+
const scrollElement = scrollElementFromCtx && scrollElementFromCtx.clientHeight > 0 ? scrollElementFromCtx : null;
|
|
4671
|
+
(0, react.useEffect)(() => {
|
|
4672
|
+
if (process.env.NODE_ENV !== "production" && scrollElementFromCtx && scrollElementFromCtx.clientHeight === 0) console.warn("[CopilotKit] Chat scroll container has clientHeight=0 — virtualization disabled. Ensure the chat is rendered in a visible container with a non-zero height.");
|
|
4673
|
+
}, [scrollElementFromCtx]);
|
|
4674
|
+
const shouldVirtualize = !!scrollElement && !children && deduplicatedMessages.length > VIRTUALIZE_THRESHOLD;
|
|
4675
|
+
const virtualizer = (0, _tanstack_react_virtual.useVirtualizer)({
|
|
4676
|
+
count: shouldVirtualize ? deduplicatedMessages.length : 0,
|
|
4677
|
+
getScrollElement: () => scrollElement,
|
|
4678
|
+
estimateSize: () => 100,
|
|
4679
|
+
overscan: 5,
|
|
4680
|
+
measureElement: (el) => el?.getBoundingClientRect().height ?? 0,
|
|
4681
|
+
initialRect: {
|
|
4682
|
+
width: 0,
|
|
4683
|
+
height: 600
|
|
4684
|
+
}
|
|
4685
|
+
});
|
|
4686
|
+
const firstMessageId = deduplicatedMessages[0]?.id;
|
|
4687
|
+
(0, react.useLayoutEffect)(() => {
|
|
4688
|
+
if (!shouldVirtualize || !deduplicatedMessages.length) return;
|
|
4689
|
+
virtualizer.scrollToIndex(deduplicatedMessages.length - 1, { align: "end" });
|
|
4690
|
+
}, [shouldVirtualize, firstMessageId]);
|
|
4691
|
+
const renderMessageBlock = (message) => {
|
|
4374
4692
|
const elements = [];
|
|
4375
4693
|
const stateSnapshot = getStateSnapshotForMessage(message.id);
|
|
4376
4694
|
if (renderCustomMessage) elements.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(MemoizedCustomMessage, {
|
|
@@ -4379,58 +4697,38 @@ function CopilotChatMessageView({ messages = [], assistantMessage, userMessage,
|
|
|
4379
4697
|
renderCustomMessage,
|
|
4380
4698
|
stateSnapshot
|
|
4381
4699
|
}, `${message.id}-custom-before`));
|
|
4382
|
-
if (message.role === "assistant") {
|
|
4383
|
-
|
|
4384
|
-
|
|
4385
|
-
|
|
4386
|
-
|
|
4387
|
-
|
|
4388
|
-
|
|
4389
|
-
|
|
4390
|
-
|
|
4391
|
-
|
|
4392
|
-
|
|
4393
|
-
|
|
4394
|
-
|
|
4395
|
-
|
|
4396
|
-
|
|
4397
|
-
|
|
4398
|
-
|
|
4399
|
-
|
|
4400
|
-
|
|
4401
|
-
|
|
4402
|
-
|
|
4403
|
-
|
|
4404
|
-
|
|
4405
|
-
}, message.id));
|
|
4406
|
-
} else if (message.role === "activity") {
|
|
4407
|
-
const activityMsg = message;
|
|
4408
|
-
elements.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(MemoizedActivityMessage, {
|
|
4409
|
-
message: activityMsg,
|
|
4410
|
-
renderActivityMessage
|
|
4411
|
-
}, message.id));
|
|
4412
|
-
} else if (message.role === "reasoning") {
|
|
4413
|
-
let ReasoningComponent = CopilotChatReasoningMessage_default;
|
|
4414
|
-
let reasoningSlotProps;
|
|
4415
|
-
if (isReactComponentType(reasoningMessage)) ReasoningComponent = reasoningMessage;
|
|
4416
|
-
else if (typeof reasoningMessage === "string") reasoningSlotProps = { className: reasoningMessage };
|
|
4417
|
-
else if (reasoningMessage && typeof reasoningMessage === "object") reasoningSlotProps = reasoningMessage;
|
|
4418
|
-
elements.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(MemoizedReasoningMessage, {
|
|
4419
|
-
message,
|
|
4420
|
-
messages,
|
|
4421
|
-
isRunning,
|
|
4422
|
-
ReasoningMessageComponent: ReasoningComponent,
|
|
4423
|
-
slotProps: reasoningSlotProps
|
|
4424
|
-
}, message.id));
|
|
4425
|
-
}
|
|
4700
|
+
if (message.role === "assistant") elements.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(MemoizedAssistantMessage, {
|
|
4701
|
+
message,
|
|
4702
|
+
messages,
|
|
4703
|
+
isRunning,
|
|
4704
|
+
AssistantMessageComponent: AssistantComponent,
|
|
4705
|
+
slotProps: assistantSlotProps
|
|
4706
|
+
}, message.id));
|
|
4707
|
+
else if (message.role === "user") elements.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(MemoizedUserMessage, {
|
|
4708
|
+
message,
|
|
4709
|
+
UserMessageComponent: UserComponent,
|
|
4710
|
+
slotProps: userSlotProps
|
|
4711
|
+
}, message.id));
|
|
4712
|
+
else if (message.role === "activity") elements.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(MemoizedActivityMessage, {
|
|
4713
|
+
message,
|
|
4714
|
+
renderActivityMessage
|
|
4715
|
+
}, message.id));
|
|
4716
|
+
else if (message.role === "reasoning") elements.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(MemoizedReasoningMessage, {
|
|
4717
|
+
message,
|
|
4718
|
+
messages,
|
|
4719
|
+
isRunning,
|
|
4720
|
+
ReasoningMessageComponent: ReasoningComponent,
|
|
4721
|
+
slotProps: reasoningSlotProps
|
|
4722
|
+
}, message.id));
|
|
4426
4723
|
if (renderCustomMessage) elements.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(MemoizedCustomMessage, {
|
|
4427
4724
|
message,
|
|
4428
4725
|
position: "after",
|
|
4429
4726
|
renderCustomMessage,
|
|
4430
4727
|
stateSnapshot
|
|
4431
4728
|
}, `${message.id}-custom-after`));
|
|
4432
|
-
return elements;
|
|
4433
|
-
}
|
|
4729
|
+
return elements.filter(Boolean);
|
|
4730
|
+
};
|
|
4731
|
+
const messageElements = shouldVirtualize ? [] : deduplicatedMessages.flatMap(renderMessageBlock);
|
|
4434
4732
|
if (children) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4435
4733
|
"data-copilotkit": true,
|
|
4436
4734
|
style: { display: "contents" },
|
|
@@ -4449,7 +4747,27 @@ function CopilotChatMessageView({ messages = [], assistantMessage, userMessage,
|
|
|
4449
4747
|
className: (0, tailwind_merge.twMerge)("copilotKitMessages cpk:flex cpk:flex-col", className),
|
|
4450
4748
|
...props,
|
|
4451
4749
|
children: [
|
|
4452
|
-
|
|
4750
|
+
shouldVirtualize ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4751
|
+
style: {
|
|
4752
|
+
height: virtualizer.getTotalSize(),
|
|
4753
|
+
position: "relative"
|
|
4754
|
+
},
|
|
4755
|
+
children: virtualizer.getVirtualItems().map((virtualItem) => {
|
|
4756
|
+
const message = deduplicatedMessages[virtualItem.index];
|
|
4757
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4758
|
+
"data-index": virtualItem.index,
|
|
4759
|
+
ref: virtualizer.measureElement,
|
|
4760
|
+
style: {
|
|
4761
|
+
position: "absolute",
|
|
4762
|
+
top: 0,
|
|
4763
|
+
left: 0,
|
|
4764
|
+
width: "100%",
|
|
4765
|
+
transform: `translateY(${virtualItem.start}px)`
|
|
4766
|
+
},
|
|
4767
|
+
children: renderMessageBlock(message)
|
|
4768
|
+
}, message.id);
|
|
4769
|
+
})
|
|
4770
|
+
}) : messageElements,
|
|
4453
4771
|
interruptElement,
|
|
4454
4772
|
showCursor && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4455
4773
|
className: "cpk:mt-2",
|
|
@@ -4466,6 +4784,312 @@ CopilotChatMessageView.Cursor = function Cursor({ className, ...props }) {
|
|
|
4466
4784
|
});
|
|
4467
4785
|
};
|
|
4468
4786
|
|
|
4787
|
+
//#endregion
|
|
4788
|
+
//#region src/v2/components/chat/CopilotChatAttachmentQueue.tsx
|
|
4789
|
+
const CopilotChatAttachmentQueue = ({ attachments, onRemoveAttachment, className }) => {
|
|
4790
|
+
if (attachments.length === 0) return null;
|
|
4791
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4792
|
+
className: cn("cpk:flex cpk:flex-wrap cpk:gap-2 cpk:p-2", className),
|
|
4793
|
+
children: attachments.map((attachment) => {
|
|
4794
|
+
const isMedia = attachment.type === "image" || attachment.type === "video";
|
|
4795
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4796
|
+
className: cn("cpk:relative cpk:inline-flex cpk:rounded-lg cpk:overflow-hidden cpk:border cpk:border-border", isMedia ? "cpk:w-[72px] cpk:h-[72px]" : attachment.type === "audio" ? "cpk:min-w-[200px] cpk:max-w-[280px] cpk:flex-col cpk:p-1 cpk:pr-8" : "cpk:p-2 cpk:px-3 cpk:pr-8 cpk:max-w-[240px]"),
|
|
4797
|
+
children: [
|
|
4798
|
+
attachment.status === "uploading" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(UploadingOverlay, {}),
|
|
4799
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(AttachmentPreview, { attachment }),
|
|
4800
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
4801
|
+
onClick: () => onRemoveAttachment(attachment.id),
|
|
4802
|
+
className: cn("cpk:absolute cpk:bg-black/60 cpk:text-white cpk:border-none cpk:rounded-full cpk:w-5 cpk:h-5 cpk:flex cpk:items-center cpk:justify-center cpk:cursor-pointer cpk:text-[10px] cpk:z-20", isMedia ? "cpk:top-1 cpk:right-1" : "cpk:top-1.5 cpk:right-1.5"),
|
|
4803
|
+
"aria-label": "Remove attachment",
|
|
4804
|
+
children: "✕"
|
|
4805
|
+
})
|
|
4806
|
+
]
|
|
4807
|
+
}, attachment.id);
|
|
4808
|
+
})
|
|
4809
|
+
});
|
|
4810
|
+
};
|
|
4811
|
+
function UploadingOverlay() {
|
|
4812
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4813
|
+
className: "cpk:absolute cpk:inset-0 cpk:flex cpk:items-center cpk:justify-center cpk:bg-black/40 cpk:z-10",
|
|
4814
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: "cpk:w-5 cpk:h-5 cpk:border-2 cpk:border-white cpk:border-t-transparent cpk:rounded-full cpk:animate-spin" })
|
|
4815
|
+
});
|
|
4816
|
+
}
|
|
4817
|
+
function AttachmentPreview({ attachment }) {
|
|
4818
|
+
if (attachment.status === "uploading") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: "cpk:w-full cpk:h-full" });
|
|
4819
|
+
switch (attachment.type) {
|
|
4820
|
+
case "image": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ImagePreview, { attachment });
|
|
4821
|
+
case "audio": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AudioPreview, { attachment });
|
|
4822
|
+
case "video": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(VideoPreview, { attachment });
|
|
4823
|
+
case "document": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DocumentPreview, { attachment });
|
|
4824
|
+
}
|
|
4825
|
+
}
|
|
4826
|
+
function Lightbox({ onClose, children }) {
|
|
4827
|
+
(0, react.useEffect)(() => {
|
|
4828
|
+
const handleKey = (e) => {
|
|
4829
|
+
if (e.key === "Escape") onClose();
|
|
4830
|
+
};
|
|
4831
|
+
document.addEventListener("keydown", handleKey);
|
|
4832
|
+
return () => document.removeEventListener("keydown", handleKey);
|
|
4833
|
+
}, [onClose]);
|
|
4834
|
+
if (typeof document === "undefined") return null;
|
|
4835
|
+
return (0, react_dom.createPortal)(/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4836
|
+
className: "cpk:fixed cpk:inset-0 cpk:z-[9999] cpk:flex cpk:items-center cpk:justify-center cpk:bg-black/80 cpk:animate-fade-in",
|
|
4837
|
+
onClick: onClose,
|
|
4838
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
4839
|
+
onClick: onClose,
|
|
4840
|
+
className: "cpk:absolute cpk:top-4 cpk:right-4 cpk:text-white cpk:bg-white/10 cpk:hover:bg-white/20 cpk:rounded-full cpk:w-10 cpk:h-10 cpk:flex cpk:items-center cpk:justify-center cpk:cursor-pointer cpk:border-none cpk:z-10",
|
|
4841
|
+
"aria-label": "Close preview",
|
|
4842
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.X, { className: "cpk:w-5 cpk:h-5" })
|
|
4843
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4844
|
+
onClick: (e) => e.stopPropagation(),
|
|
4845
|
+
children
|
|
4846
|
+
})]
|
|
4847
|
+
}), document.body);
|
|
4848
|
+
}
|
|
4849
|
+
/**
|
|
4850
|
+
* Hook that manages lightbox open/close and uses the View Transition API to
|
|
4851
|
+
* morph the thumbnail into fullscreen content.
|
|
4852
|
+
*
|
|
4853
|
+
* The trick: `view-transition-name` must live on exactly ONE element at a time.
|
|
4854
|
+
* - Old state (thumbnail visible): name is on the thumbnail.
|
|
4855
|
+
* - New state (lightbox visible): name moves to the lightbox content.
|
|
4856
|
+
* `flushSync` ensures React commits the DOM change synchronously inside the
|
|
4857
|
+
* `startViewTransition` callback so the API can snapshot old → new correctly.
|
|
4858
|
+
*/
|
|
4859
|
+
function useLightbox() {
|
|
4860
|
+
const thumbnailRef = (0, react.useRef)(null);
|
|
4861
|
+
const [open, setOpen] = (0, react.useState)(false);
|
|
4862
|
+
const vtName = (0, react.useId)();
|
|
4863
|
+
return {
|
|
4864
|
+
thumbnailRef,
|
|
4865
|
+
vtName,
|
|
4866
|
+
open,
|
|
4867
|
+
openLightbox: (0, react.useCallback)(() => {
|
|
4868
|
+
const thumb = thumbnailRef.current;
|
|
4869
|
+
const doc = document;
|
|
4870
|
+
if (doc.startViewTransition && thumb) {
|
|
4871
|
+
thumb.style.viewTransitionName = vtName;
|
|
4872
|
+
doc.startViewTransition(() => {
|
|
4873
|
+
thumb.style.viewTransitionName = "";
|
|
4874
|
+
(0, react_dom.flushSync)(() => setOpen(true));
|
|
4875
|
+
});
|
|
4876
|
+
} else setOpen(true);
|
|
4877
|
+
}, []),
|
|
4878
|
+
closeLightbox: (0, react.useCallback)(() => {
|
|
4879
|
+
const thumb = thumbnailRef.current;
|
|
4880
|
+
const doc = document;
|
|
4881
|
+
if (doc.startViewTransition && thumb) doc.startViewTransition(() => {
|
|
4882
|
+
(0, react_dom.flushSync)(() => setOpen(false));
|
|
4883
|
+
thumb.style.viewTransitionName = vtName;
|
|
4884
|
+
}).finished.then(() => {
|
|
4885
|
+
thumb.style.viewTransitionName = "";
|
|
4886
|
+
}).catch(() => {
|
|
4887
|
+
thumb.style.viewTransitionName = "";
|
|
4888
|
+
});
|
|
4889
|
+
else setOpen(false);
|
|
4890
|
+
}, [])
|
|
4891
|
+
};
|
|
4892
|
+
}
|
|
4893
|
+
function ImagePreview({ attachment }) {
|
|
4894
|
+
const src = (0, _copilotkit_shared.getSourceUrl)(attachment.source);
|
|
4895
|
+
const { thumbnailRef, vtName, open, openLightbox, closeLightbox } = useLightbox();
|
|
4896
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
|
|
4897
|
+
ref: thumbnailRef,
|
|
4898
|
+
src,
|
|
4899
|
+
alt: attachment.filename || "Image attachment",
|
|
4900
|
+
className: "cpk:w-full cpk:h-full cpk:object-cover cpk:cursor-pointer",
|
|
4901
|
+
onClick: openLightbox
|
|
4902
|
+
}), open && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Lightbox, {
|
|
4903
|
+
onClose: closeLightbox,
|
|
4904
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
|
|
4905
|
+
style: { viewTransitionName: vtName },
|
|
4906
|
+
src,
|
|
4907
|
+
alt: attachment.filename || "Image attachment",
|
|
4908
|
+
className: "cpk:max-w-[90vw] cpk:max-h-[90vh] cpk:object-contain cpk:rounded-lg"
|
|
4909
|
+
})
|
|
4910
|
+
})] });
|
|
4911
|
+
}
|
|
4912
|
+
function AudioPreview({ attachment }) {
|
|
4913
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4914
|
+
className: "cpk:flex cpk:flex-col cpk:gap-1 cpk:w-full",
|
|
4915
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("audio", {
|
|
4916
|
+
src: (0, _copilotkit_shared.getSourceUrl)(attachment.source),
|
|
4917
|
+
controls: true,
|
|
4918
|
+
preload: "metadata",
|
|
4919
|
+
className: "cpk:w-full cpk:h-8"
|
|
4920
|
+
}), attachment.filename && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4921
|
+
className: "cpk:text-xs cpk:font-medium cpk:overflow-hidden cpk:text-ellipsis cpk:whitespace-nowrap",
|
|
4922
|
+
children: attachment.filename
|
|
4923
|
+
})]
|
|
4924
|
+
});
|
|
4925
|
+
}
|
|
4926
|
+
function VideoPreview({ attachment }) {
|
|
4927
|
+
const src = (0, _copilotkit_shared.getSourceUrl)(attachment.source);
|
|
4928
|
+
const { thumbnailRef, vtName, open, openLightbox, closeLightbox } = useLightbox();
|
|
4929
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
4930
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4931
|
+
ref: thumbnailRef,
|
|
4932
|
+
className: "cpk:w-full cpk:h-full",
|
|
4933
|
+
children: attachment.thumbnail ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
|
|
4934
|
+
src: attachment.thumbnail,
|
|
4935
|
+
alt: attachment.filename || "Video thumbnail",
|
|
4936
|
+
className: "cpk:w-full cpk:h-full cpk:object-cover"
|
|
4937
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("video", {
|
|
4938
|
+
src,
|
|
4939
|
+
preload: "metadata",
|
|
4940
|
+
muted: true,
|
|
4941
|
+
className: "cpk:w-full cpk:h-full cpk:object-cover"
|
|
4942
|
+
})
|
|
4943
|
+
}),
|
|
4944
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
4945
|
+
onClick: openLightbox,
|
|
4946
|
+
className: "cpk:absolute cpk:inset-0 cpk:flex cpk:items-center cpk:justify-center cpk:z-10 cpk:cursor-pointer cpk:bg-black/20 cpk:border-none cpk:p-0",
|
|
4947
|
+
"aria-label": "Play video",
|
|
4948
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4949
|
+
className: "cpk:w-8 cpk:h-8 cpk:rounded-full cpk:bg-black/60 cpk:flex cpk:items-center cpk:justify-center",
|
|
4950
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Play, { className: "cpk:w-4 cpk:h-4 cpk:text-white cpk:ml-0.5" })
|
|
4951
|
+
})
|
|
4952
|
+
}),
|
|
4953
|
+
open && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Lightbox, {
|
|
4954
|
+
onClose: closeLightbox,
|
|
4955
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("video", {
|
|
4956
|
+
style: { viewTransitionName: vtName },
|
|
4957
|
+
src,
|
|
4958
|
+
controls: true,
|
|
4959
|
+
autoPlay: true,
|
|
4960
|
+
className: "cpk:max-w-[90vw] cpk:max-h-[90vh] cpk:rounded-lg"
|
|
4961
|
+
})
|
|
4962
|
+
})
|
|
4963
|
+
] });
|
|
4964
|
+
}
|
|
4965
|
+
function isPdf(mimeType) {
|
|
4966
|
+
return !!mimeType && mimeType.includes("pdf");
|
|
4967
|
+
}
|
|
4968
|
+
function isText(mimeType) {
|
|
4969
|
+
return !!mimeType && mimeType.startsWith("text/");
|
|
4970
|
+
}
|
|
4971
|
+
function canPreviewInBrowser(mimeType) {
|
|
4972
|
+
return isPdf(mimeType) || isText(mimeType);
|
|
4973
|
+
}
|
|
4974
|
+
/**
|
|
4975
|
+
* Convert a base64-encoded data source to a blob: URL that browsers will
|
|
4976
|
+
* render inside an iframe (data: URLs are blocked for PDFs in most browsers).
|
|
4977
|
+
*/
|
|
4978
|
+
function useBlobUrl(attachment) {
|
|
4979
|
+
const [url, setUrl] = (0, react.useState)(null);
|
|
4980
|
+
(0, react.useEffect)(() => {
|
|
4981
|
+
if (attachment.source.type !== "data") return;
|
|
4982
|
+
try {
|
|
4983
|
+
const binary = atob(attachment.source.value);
|
|
4984
|
+
const bytes = new Uint8Array(binary.length);
|
|
4985
|
+
for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
|
|
4986
|
+
const blob = new Blob([bytes], { type: attachment.source.mimeType || "application/octet-stream" });
|
|
4987
|
+
const blobUrl = URL.createObjectURL(blob);
|
|
4988
|
+
setUrl(blobUrl);
|
|
4989
|
+
return () => URL.revokeObjectURL(blobUrl);
|
|
4990
|
+
} catch (error) {
|
|
4991
|
+
console.error("[CopilotKit] Failed to decode attachment data:", error);
|
|
4992
|
+
setUrl(null);
|
|
4993
|
+
}
|
|
4994
|
+
}, [
|
|
4995
|
+
attachment.source.type,
|
|
4996
|
+
attachment.source.value,
|
|
4997
|
+
attachment.source.mimeType
|
|
4998
|
+
]);
|
|
4999
|
+
if (attachment.source.type === "url") return attachment.source.value;
|
|
5000
|
+
return url;
|
|
5001
|
+
}
|
|
5002
|
+
function DocumentLightboxContent({ attachment, vtName }) {
|
|
5003
|
+
const mimeType = attachment.source.mimeType;
|
|
5004
|
+
const blobUrl = useBlobUrl(attachment);
|
|
5005
|
+
if (isPdf(mimeType)) {
|
|
5006
|
+
if (!blobUrl) return null;
|
|
5007
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("iframe", {
|
|
5008
|
+
style: { viewTransitionName: vtName },
|
|
5009
|
+
src: blobUrl,
|
|
5010
|
+
title: attachment.filename || "PDF preview",
|
|
5011
|
+
className: "cpk:w-[90vw] cpk:h-[90vh] cpk:max-w-[1000px] cpk:rounded-lg cpk:bg-white"
|
|
5012
|
+
});
|
|
5013
|
+
}
|
|
5014
|
+
if (isText(mimeType)) {
|
|
5015
|
+
const textContent = attachment.source.type === "data" ? (() => {
|
|
5016
|
+
try {
|
|
5017
|
+
return atob(attachment.source.value);
|
|
5018
|
+
} catch {
|
|
5019
|
+
return attachment.source.value;
|
|
5020
|
+
}
|
|
5021
|
+
})() : null;
|
|
5022
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
5023
|
+
style: { viewTransitionName: vtName },
|
|
5024
|
+
className: "cpk:w-[90vw] cpk:max-w-[800px] cpk:max-h-[90vh] cpk:overflow-auto cpk:rounded-lg cpk:bg-white cpk:dark:bg-gray-900 cpk:p-6",
|
|
5025
|
+
children: [attachment.filename && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
5026
|
+
className: "cpk:text-sm cpk:font-medium cpk:text-gray-500 cpk:dark:text-gray-400 cpk:mb-4 cpk:pb-2 cpk:border-b cpk:border-gray-200 cpk:dark:border-gray-700",
|
|
5027
|
+
children: attachment.filename
|
|
5028
|
+
}), textContent ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", {
|
|
5029
|
+
className: "cpk:text-sm cpk:whitespace-pre-wrap cpk:break-words cpk:text-gray-800 cpk:dark:text-gray-200 cpk:font-mono cpk:m-0",
|
|
5030
|
+
children: textContent
|
|
5031
|
+
}) : blobUrl ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("iframe", {
|
|
5032
|
+
src: blobUrl,
|
|
5033
|
+
title: attachment.filename || "Text preview",
|
|
5034
|
+
className: "cpk:w-full cpk:h-[80vh] cpk:border-none"
|
|
5035
|
+
}) : null]
|
|
5036
|
+
});
|
|
5037
|
+
}
|
|
5038
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
5039
|
+
style: { viewTransitionName: vtName },
|
|
5040
|
+
className: "cpk:flex cpk:flex-col cpk:items-center cpk:gap-4 cpk:p-8 cpk:rounded-lg cpk:bg-white cpk:dark:bg-gray-900",
|
|
5041
|
+
children: [
|
|
5042
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
5043
|
+
className: "cpk:w-16 cpk:h-16 cpk:rounded-xl cpk:bg-primary cpk:text-primary-foreground cpk:flex cpk:items-center cpk:justify-center cpk:text-xl cpk:font-bold",
|
|
5044
|
+
children: (0, _copilotkit_shared.getDocumentIcon)(mimeType ?? "")
|
|
5045
|
+
}),
|
|
5046
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
5047
|
+
className: "cpk:text-center",
|
|
5048
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
5049
|
+
className: "cpk:text-base cpk:font-medium cpk:text-gray-800 cpk:dark:text-gray-200",
|
|
5050
|
+
children: attachment.filename || "Document"
|
|
5051
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
5052
|
+
className: "cpk:text-sm cpk:text-gray-500 cpk:dark:text-gray-400 cpk:mt-1",
|
|
5053
|
+
children: [mimeType || "Unknown type", attachment.size != null && ` · ${(0, _copilotkit_shared.formatFileSize)(attachment.size)}`]
|
|
5054
|
+
})]
|
|
5055
|
+
}),
|
|
5056
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
5057
|
+
className: "cpk:text-xs cpk:text-gray-400 cpk:dark:text-gray-500",
|
|
5058
|
+
children: "No preview available for this file type"
|
|
5059
|
+
})
|
|
5060
|
+
]
|
|
5061
|
+
});
|
|
5062
|
+
}
|
|
5063
|
+
function DocumentPreview({ attachment }) {
|
|
5064
|
+
const { thumbnailRef, vtName, open, openLightbox, closeLightbox } = useLightbox();
|
|
5065
|
+
const mimeType = attachment.source.mimeType;
|
|
5066
|
+
const previewable = canPreviewInBrowser(mimeType);
|
|
5067
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
5068
|
+
ref: thumbnailRef,
|
|
5069
|
+
className: cn("cpk:flex cpk:items-center cpk:gap-2", previewable && "cpk:cursor-pointer"),
|
|
5070
|
+
onClick: previewable ? openLightbox : void 0,
|
|
5071
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
5072
|
+
className: "cpk:w-8 cpk:h-8 cpk:rounded-md cpk:bg-primary cpk:text-primary-foreground cpk:flex cpk:items-center cpk:justify-center cpk:text-[10px] cpk:font-semibold cpk:shrink-0",
|
|
5073
|
+
children: (0, _copilotkit_shared.getDocumentIcon)(mimeType ?? "")
|
|
5074
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
5075
|
+
className: "cpk:flex cpk:flex-col cpk:min-w-0",
|
|
5076
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
5077
|
+
className: "cpk:text-xs cpk:font-medium cpk:break-all cpk:leading-tight",
|
|
5078
|
+
children: attachment.filename || "Document"
|
|
5079
|
+
}), attachment.size != null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
5080
|
+
className: "cpk:text-[11px] cpk:text-muted-foreground",
|
|
5081
|
+
children: (0, _copilotkit_shared.formatFileSize)(attachment.size)
|
|
5082
|
+
})]
|
|
5083
|
+
})]
|
|
5084
|
+
}), open && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Lightbox, {
|
|
5085
|
+
onClose: closeLightbox,
|
|
5086
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DocumentLightboxContent, {
|
|
5087
|
+
attachment,
|
|
5088
|
+
vtName
|
|
5089
|
+
})
|
|
5090
|
+
})] });
|
|
5091
|
+
}
|
|
5092
|
+
|
|
4469
5093
|
//#endregion
|
|
4470
5094
|
//#region src/v2/hooks/use-keyboard-height.tsx
|
|
4471
5095
|
/**
|
|
@@ -4510,7 +5134,19 @@ function useKeyboardHeight() {
|
|
|
4510
5134
|
//#endregion
|
|
4511
5135
|
//#region src/v2/components/chat/CopilotChatView.tsx
|
|
4512
5136
|
const FEATHER_HEIGHT = 96;
|
|
4513
|
-
function
|
|
5137
|
+
function DropOverlay() {
|
|
5138
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
5139
|
+
className: cn("cpk:absolute cpk:inset-0 cpk:z-50 cpk:pointer-events-none", "cpk:flex cpk:items-center cpk:justify-center", "cpk:bg-primary/5 cpk:backdrop-blur-[2px]", "cpk:border-2 cpk:border-dashed cpk:border-primary/40 cpk:rounded-lg cpk:m-2"),
|
|
5140
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
5141
|
+
className: "cpk:flex cpk:flex-col cpk:items-center cpk:gap-2 cpk:text-primary/70",
|
|
5142
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Upload, { className: "cpk:w-8 cpk:h-8" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
5143
|
+
className: "cpk:text-sm cpk:font-medium",
|
|
5144
|
+
children: "Drop files here"
|
|
5145
|
+
})]
|
|
5146
|
+
})
|
|
5147
|
+
});
|
|
5148
|
+
}
|
|
5149
|
+
function CopilotChatView({ messageView, input, scrollView, suggestionView, welcomeScreen, messages = [], autoScroll = true, isRunning = false, suggestions, suggestionLoadingIndexes, onSelectSuggestion, onSubmitMessage, onStop, inputMode, inputValue, onInputChange, onStartTranscribe, onCancelTranscribe, onFinishTranscribe, onFinishTranscribeWithAudio, attachments, onRemoveAttachment, onAddFile, dragOver, onDragOver, onDragLeave, onDrop, disclaimer, children, className, ...props }) {
|
|
4514
5150
|
const inputContainerRef = (0, react.useRef)(null);
|
|
4515
5151
|
const [inputContainerHeight, setInputContainerHeight] = (0, react.useState)(0);
|
|
4516
5152
|
const [isResizing, setIsResizing] = (0, react.useState)(false);
|
|
@@ -4557,6 +5193,7 @@ function CopilotChatView({ messageView, input, scrollView, suggestionView, welco
|
|
|
4557
5193
|
onCancelTranscribe,
|
|
4558
5194
|
onFinishTranscribe,
|
|
4559
5195
|
onFinishTranscribeWithAudio,
|
|
5196
|
+
onAddFile,
|
|
4560
5197
|
positioning: "static",
|
|
4561
5198
|
keyboardHeight: isKeyboardOpen ? keyboardHeight : 0,
|
|
4562
5199
|
containerRef: inputContainerRef,
|
|
@@ -4597,21 +5234,34 @@ function CopilotChatView({ messageView, input, scrollView, suggestionView, welco
|
|
|
4597
5234
|
onCancelTranscribe,
|
|
4598
5235
|
onFinishTranscribe,
|
|
4599
5236
|
onFinishTranscribeWithAudio,
|
|
5237
|
+
onAddFile,
|
|
4600
5238
|
positioning: "static",
|
|
4601
5239
|
showDisclaimer: true,
|
|
4602
5240
|
...disclaimer !== void 0 ? { disclaimer } : {}
|
|
4603
5241
|
});
|
|
4604
|
-
const
|
|
4605
|
-
|
|
5242
|
+
const welcomeScreenSlot = welcomeScreen === true ? void 0 : welcomeScreen;
|
|
5243
|
+
const inputWithAttachments = /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
5244
|
+
className: "cpk:w-full",
|
|
5245
|
+
children: [attachments && attachments.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopilotChatAttachmentQueue, {
|
|
5246
|
+
attachments,
|
|
5247
|
+
onRemoveAttachment: (id) => onRemoveAttachment?.(id),
|
|
5248
|
+
className: "cpk:mb-2"
|
|
5249
|
+
}), BoundInputForWelcome]
|
|
5250
|
+
});
|
|
5251
|
+
const BoundWelcomeScreen = renderSlot(welcomeScreenSlot, CopilotChatView.WelcomeScreen, {
|
|
5252
|
+
input: inputWithAttachments,
|
|
4606
5253
|
suggestionView: BoundSuggestionView ?? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, {})
|
|
4607
5254
|
});
|
|
4608
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.
|
|
5255
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4609
5256
|
"data-copilotkit": true,
|
|
4610
5257
|
"data-testid": "copilot-chat",
|
|
4611
5258
|
"data-copilot-running": isRunning ? "true" : "false",
|
|
4612
|
-
|
|
5259
|
+
onDragOver,
|
|
5260
|
+
onDragLeave,
|
|
5261
|
+
onDrop,
|
|
5262
|
+
className: cn("copilotKitChat cpk:relative cpk:h-full cpk:flex cpk:flex-col", className),
|
|
4613
5263
|
...props,
|
|
4614
|
-
children: BoundWelcomeScreen
|
|
5264
|
+
children: [dragOver && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DropOverlay, {}), BoundWelcomeScreen]
|
|
4615
5265
|
});
|
|
4616
5266
|
}
|
|
4617
5267
|
if (children) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
@@ -4628,39 +5278,66 @@ function CopilotChatView({ messageView, input, scrollView, suggestionView, welco
|
|
|
4628
5278
|
"data-copilotkit": true,
|
|
4629
5279
|
"data-testid": "copilot-chat",
|
|
4630
5280
|
"data-copilot-running": isRunning ? "true" : "false",
|
|
4631
|
-
|
|
5281
|
+
onDragOver,
|
|
5282
|
+
onDragLeave,
|
|
5283
|
+
onDrop,
|
|
5284
|
+
className: cn("copilotKitChat cpk:relative cpk:h-full cpk:flex cpk:flex-col", className),
|
|
4632
5285
|
...props,
|
|
4633
|
-
children: [
|
|
5286
|
+
children: [
|
|
5287
|
+
dragOver && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DropOverlay, {}),
|
|
5288
|
+
BoundScrollView,
|
|
5289
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
5290
|
+
className: "cpk:max-w-3xl cpk:mx-auto cpk:w-full",
|
|
5291
|
+
children: attachments && attachments.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopilotChatAttachmentQueue, {
|
|
5292
|
+
attachments,
|
|
5293
|
+
onRemoveAttachment: (id) => onRemoveAttachment?.(id),
|
|
5294
|
+
className: "cpk:px-4"
|
|
5295
|
+
})
|
|
5296
|
+
}),
|
|
5297
|
+
BoundInput
|
|
5298
|
+
]
|
|
4634
5299
|
});
|
|
4635
5300
|
}
|
|
4636
5301
|
(function(_CopilotChatView) {
|
|
4637
5302
|
const ScrollContent = ({ children, scrollToBottomButton, feather, inputContainerHeight, isResizing }) => {
|
|
4638
|
-
const { isAtBottom, scrollToBottom } = (0, use_stick_to_bottom.useStickToBottomContext)();
|
|
5303
|
+
const { isAtBottom, scrollToBottom, scrollRef } = (0, use_stick_to_bottom.useStickToBottomContext)();
|
|
5304
|
+
const [scrollEl, setScrollEl] = (0, react.useState)(null);
|
|
5305
|
+
(0, react.useLayoutEffect)(() => {
|
|
5306
|
+
setScrollEl(scrollRef.current ?? null);
|
|
5307
|
+
}, []);
|
|
4639
5308
|
const BoundFeather = renderSlot(feather, CopilotChatView.Feather, {});
|
|
4640
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.
|
|
4641
|
-
|
|
4642
|
-
|
|
4643
|
-
|
|
4644
|
-
|
|
4645
|
-
|
|
4646
|
-
|
|
4647
|
-
|
|
4648
|
-
|
|
4649
|
-
children
|
|
5309
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ScrollElementContext.Provider, {
|
|
5310
|
+
value: scrollEl,
|
|
5311
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
5312
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(use_stick_to_bottom.StickToBottom.Content, {
|
|
5313
|
+
className: "cpk:overflow-y-auto cpk:overflow-x-hidden",
|
|
5314
|
+
style: {
|
|
5315
|
+
flex: "1 1 0%",
|
|
5316
|
+
minHeight: 0
|
|
5317
|
+
},
|
|
5318
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
5319
|
+
className: "cpk:px-4 cpk:sm:px-0 cpk:[div[data-sidebar-chat]_&]:px-8 cpk:[div[data-popup-chat]_&]:px-6",
|
|
5320
|
+
children
|
|
5321
|
+
})
|
|
5322
|
+
}),
|
|
5323
|
+
BoundFeather,
|
|
5324
|
+
!isAtBottom && !isResizing && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
5325
|
+
className: "cpk:absolute cpk:inset-x-0 cpk:flex cpk:justify-center cpk:z-30 cpk:pointer-events-none",
|
|
5326
|
+
style: { bottom: `${inputContainerHeight + FEATHER_HEIGHT + 16}px` },
|
|
5327
|
+
children: renderSlot(scrollToBottomButton, CopilotChatView.ScrollToBottomButton, { onClick: () => scrollToBottom() })
|
|
4650
5328
|
})
|
|
4651
|
-
})
|
|
4652
|
-
|
|
4653
|
-
!isAtBottom && !isResizing && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4654
|
-
className: "cpk:absolute cpk:inset-x-0 cpk:flex cpk:justify-center cpk:z-30 cpk:pointer-events-none",
|
|
4655
|
-
style: { bottom: `${inputContainerHeight + FEATHER_HEIGHT + 16}px` },
|
|
4656
|
-
children: renderSlot(scrollToBottomButton, CopilotChatView.ScrollToBottomButton, { onClick: () => scrollToBottom() })
|
|
4657
|
-
})
|
|
4658
|
-
] });
|
|
5329
|
+
] })
|
|
5330
|
+
});
|
|
4659
5331
|
};
|
|
4660
5332
|
_CopilotChatView.ScrollView = ({ children, autoScroll = true, scrollToBottomButton, feather, inputContainerHeight = 0, isResizing = false, className, ...props }) => {
|
|
4661
5333
|
const [hasMounted, setHasMounted] = (0, react.useState)(false);
|
|
4662
5334
|
const { scrollRef, contentRef, scrollToBottom } = (0, use_stick_to_bottom.useStickToBottom)();
|
|
4663
5335
|
const [showScrollButton, setShowScrollButton] = (0, react.useState)(false);
|
|
5336
|
+
const [nonAutoScrollEl, setNonAutoScrollEl] = (0, react.useState)(null);
|
|
5337
|
+
const nonAutoScrollRefCallback = (0, react.useCallback)((el) => {
|
|
5338
|
+
scrollRef.current = el;
|
|
5339
|
+
setNonAutoScrollEl(el);
|
|
5340
|
+
}, []);
|
|
4664
5341
|
(0, react.useEffect)(() => {
|
|
4665
5342
|
setHasMounted(true);
|
|
4666
5343
|
}, []);
|
|
@@ -4689,23 +5366,26 @@ function CopilotChatView({ messageView, input, scrollView, suggestionView, welco
|
|
|
4689
5366
|
});
|
|
4690
5367
|
if (!autoScroll) {
|
|
4691
5368
|
const BoundFeather = renderSlot(feather, CopilotChatView.Feather, {});
|
|
4692
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.
|
|
4693
|
-
|
|
4694
|
-
|
|
4695
|
-
|
|
4696
|
-
|
|
4697
|
-
|
|
4698
|
-
|
|
4699
|
-
|
|
4700
|
-
|
|
4701
|
-
|
|
4702
|
-
|
|
4703
|
-
|
|
4704
|
-
|
|
4705
|
-
|
|
4706
|
-
|
|
4707
|
-
|
|
4708
|
-
|
|
5369
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ScrollElementContext.Provider, {
|
|
5370
|
+
value: nonAutoScrollEl,
|
|
5371
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
5372
|
+
ref: nonAutoScrollRefCallback,
|
|
5373
|
+
className: cn("cpk:h-full cpk:max-h-full cpk:flex cpk:flex-col cpk:min-h-0 cpk:overflow-y-auto cpk:overflow-x-hidden cpk:relative", className),
|
|
5374
|
+
...props,
|
|
5375
|
+
children: [
|
|
5376
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
5377
|
+
ref: contentRef,
|
|
5378
|
+
className: "cpk:px-4 cpk:sm:px-0 cpk:[div[data-sidebar-chat]_&]:px-8 cpk:[div[data-popup-chat]_&]:px-6",
|
|
5379
|
+
children
|
|
5380
|
+
}),
|
|
5381
|
+
BoundFeather,
|
|
5382
|
+
showScrollButton && !isResizing && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
5383
|
+
className: "cpk:absolute cpk:inset-x-0 cpk:flex cpk:justify-center cpk:z-30 cpk:pointer-events-none",
|
|
5384
|
+
style: { bottom: `${inputContainerHeight + FEATHER_HEIGHT + 16}px` },
|
|
5385
|
+
children: renderSlot(scrollToBottomButton, CopilotChatView.ScrollToBottomButton, { onClick: () => scrollToBottom() })
|
|
5386
|
+
})
|
|
5387
|
+
]
|
|
5388
|
+
})
|
|
4709
5389
|
});
|
|
4710
5390
|
}
|
|
4711
5391
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(use_stick_to_bottom.StickToBottom, {
|
|
@@ -4897,7 +5577,7 @@ async function transcribeAudio(core, audioBlob, filename = "recording.webm") {
|
|
|
4897
5577
|
|
|
4898
5578
|
//#endregion
|
|
4899
5579
|
//#region src/v2/components/chat/CopilotChat.tsx
|
|
4900
|
-
function CopilotChat({ agentId, threadId, labels, chatView, isModalDefaultOpen, onError, ...props }) {
|
|
5580
|
+
function CopilotChat({ agentId, threadId, labels, chatView, isModalDefaultOpen, attachments: attachmentsConfig, onError, ...props }) {
|
|
4901
5581
|
const existingConfig = useCopilotChatConfiguration();
|
|
4902
5582
|
const resolvedAgentId = agentId ?? existingConfig?.agentId ?? _copilotkit_shared.DEFAULT_AGENT_ID;
|
|
4903
5583
|
const resolvedThreadId = (0, react.useMemo)(() => threadId ?? existingConfig?.threadId ?? (0, _copilotkit_shared.randomUUID)(), [threadId, existingConfig?.threadId]);
|
|
@@ -4933,6 +5613,7 @@ function CopilotChat({ agentId, threadId, labels, chatView, isModalDefaultOpen,
|
|
|
4933
5613
|
const [inputValue, setInputValue] = (0, react.useState)("");
|
|
4934
5614
|
const [transcriptionError, setTranscriptionError] = (0, react.useState)(null);
|
|
4935
5615
|
const [isTranscribing, setIsTranscribing] = (0, react.useState)(false);
|
|
5616
|
+
const { attachments: selectedAttachments, enabled: attachmentsEnabled, dragOver, fileInputRef, containerRef: chatContainerRef, handleFileUpload, handleDragOver, handleDragLeave, handleDrop, removeAttachment, consumeAttachments } = useAttachments({ config: attachmentsConfig });
|
|
4936
5617
|
const isTranscriptionEnabled = copilotkit.audioFileTranscriptionEnabled;
|
|
4937
5618
|
const isMediaRecorderSupported = typeof window !== "undefined" && typeof MediaRecorder !== "undefined";
|
|
4938
5619
|
const { messageView: providedMessageView, suggestionView: providedSuggestionView, onStop: providedStopHandler, ...restProps } = props;
|
|
@@ -4960,7 +5641,31 @@ function CopilotChat({ agentId, threadId, labels, chatView, isModalDefaultOpen,
|
|
|
4960
5641
|
resolvedAgentId
|
|
4961
5642
|
]);
|
|
4962
5643
|
const onSubmitInput = (0, react.useCallback)(async (value) => {
|
|
4963
|
-
|
|
5644
|
+
if (selectedAttachments.some((a) => a.status === "uploading")) {
|
|
5645
|
+
console.error("[CopilotKit] Cannot send while attachments are uploading");
|
|
5646
|
+
return;
|
|
5647
|
+
}
|
|
5648
|
+
const readyAttachments = consumeAttachments();
|
|
5649
|
+
if (readyAttachments.length > 0) {
|
|
5650
|
+
const contentParts = [];
|
|
5651
|
+
if (value.trim()) contentParts.push({
|
|
5652
|
+
type: "text",
|
|
5653
|
+
text: value
|
|
5654
|
+
});
|
|
5655
|
+
for (const att of readyAttachments) contentParts.push({
|
|
5656
|
+
type: att.type,
|
|
5657
|
+
source: att.source,
|
|
5658
|
+
metadata: {
|
|
5659
|
+
...att.filename ? { filename: att.filename } : {},
|
|
5660
|
+
...att.metadata
|
|
5661
|
+
}
|
|
5662
|
+
});
|
|
5663
|
+
agent.addMessage({
|
|
5664
|
+
id: (0, _copilotkit_shared.randomUUID)(),
|
|
5665
|
+
role: "user",
|
|
5666
|
+
content: contentParts
|
|
5667
|
+
});
|
|
5668
|
+
} else agent.addMessage({
|
|
4964
5669
|
id: (0, _copilotkit_shared.randomUUID)(),
|
|
4965
5670
|
role: "user",
|
|
4966
5671
|
content: value
|
|
@@ -4971,7 +5676,11 @@ function CopilotChat({ agentId, threadId, labels, chatView, isModalDefaultOpen,
|
|
|
4971
5676
|
} catch (error) {
|
|
4972
5677
|
console.error("CopilotChat: runAgent failed", error);
|
|
4973
5678
|
}
|
|
4974
|
-
}, [
|
|
5679
|
+
}, [
|
|
5680
|
+
agent,
|
|
5681
|
+
selectedAttachments,
|
|
5682
|
+
consumeAttachments
|
|
5683
|
+
]);
|
|
4975
5684
|
const handleSelectSuggestion = (0, react.useCallback)(async (suggestion) => {
|
|
4976
5685
|
agent.addMessage({
|
|
4977
5686
|
id: (0, _copilotkit_shared.randomUUID)(),
|
|
@@ -5072,7 +5781,11 @@ function CopilotChat({ agentId, threadId, labels, chatView, isModalDefaultOpen,
|
|
|
5072
5781
|
const showTranscription = isTranscriptionEnabled && isMediaRecorderSupported;
|
|
5073
5782
|
const effectiveMode = isTranscribing ? "processing" : transcribeMode;
|
|
5074
5783
|
const RenderedChatView = renderSlot(chatView, CopilotChatView, (0, ts_deepmerge.merge)(mergedProps, {
|
|
5075
|
-
messages: (0, react.useMemo)(() => [...agent.messages], [
|
|
5784
|
+
messages: (0, react.useMemo)(() => [...agent.messages], [agent.messages.map((m) => {
|
|
5785
|
+
const contentKey = typeof m.content === "string" ? m.content.length : Array.isArray(m.content) ? m.content.length : 0;
|
|
5786
|
+
const toolCallsKey = "toolCalls" in m && Array.isArray(m.toolCalls) ? m.toolCalls.map((tc) => `${tc.id}:${tc.function?.arguments?.length ?? 0}`).join(";") : "";
|
|
5787
|
+
return `${m.id}:${m.role}:${contentKey}:${toolCallsKey}`;
|
|
5788
|
+
}).join(",")]),
|
|
5076
5789
|
onSubmitMessage: onSubmitInput,
|
|
5077
5790
|
onStop: effectiveStopHandler,
|
|
5078
5791
|
inputMode: effectiveMode,
|
|
@@ -5081,32 +5794,55 @@ function CopilotChat({ agentId, threadId, labels, chatView, isModalDefaultOpen,
|
|
|
5081
5794
|
onStartTranscribe: showTranscription ? handleStartTranscribe : void 0,
|
|
5082
5795
|
onCancelTranscribe: showTranscription ? handleCancelTranscribe : void 0,
|
|
5083
5796
|
onFinishTranscribe: showTranscription ? handleFinishTranscribe : void 0,
|
|
5084
|
-
onFinishTranscribeWithAudio: showTranscription ? handleFinishTranscribeWithAudio : void 0
|
|
5797
|
+
onFinishTranscribeWithAudio: showTranscription ? handleFinishTranscribeWithAudio : void 0,
|
|
5798
|
+
attachments: selectedAttachments,
|
|
5799
|
+
onRemoveAttachment: removeAttachment,
|
|
5800
|
+
onAddFile: attachmentsEnabled ? () => {
|
|
5801
|
+
setTimeout(() => {
|
|
5802
|
+
fileInputRef.current?.click();
|
|
5803
|
+
}, 100);
|
|
5804
|
+
} : void 0,
|
|
5805
|
+
dragOver,
|
|
5806
|
+
onDragOver: handleDragOver,
|
|
5807
|
+
onDragLeave: handleDragLeave,
|
|
5808
|
+
onDrop: handleDrop
|
|
5085
5809
|
}));
|
|
5086
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.
|
|
5810
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopilotChatConfigurationProvider, {
|
|
5087
5811
|
agentId: resolvedAgentId,
|
|
5088
5812
|
threadId: resolvedThreadId,
|
|
5089
5813
|
labels,
|
|
5090
5814
|
isModalDefaultOpen,
|
|
5091
|
-
children:
|
|
5092
|
-
|
|
5093
|
-
|
|
5094
|
-
|
|
5095
|
-
|
|
5096
|
-
|
|
5097
|
-
|
|
5098
|
-
|
|
5099
|
-
|
|
5100
|
-
|
|
5101
|
-
|
|
5102
|
-
|
|
5103
|
-
|
|
5104
|
-
|
|
5105
|
-
|
|
5106
|
-
|
|
5107
|
-
|
|
5108
|
-
|
|
5109
|
-
|
|
5815
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
5816
|
+
ref: chatContainerRef,
|
|
5817
|
+
style: { display: "contents" },
|
|
5818
|
+
children: [
|
|
5819
|
+
attachmentsEnabled && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
5820
|
+
type: "file",
|
|
5821
|
+
multiple: true,
|
|
5822
|
+
ref: fileInputRef,
|
|
5823
|
+
onChange: handleFileUpload,
|
|
5824
|
+
accept: attachmentsConfig?.accept ?? "*/*",
|
|
5825
|
+
style: { display: "none" }
|
|
5826
|
+
}),
|
|
5827
|
+
!isChatLicensed && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InlineFeatureWarning, { featureName: "Chat" }),
|
|
5828
|
+
transcriptionError && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
5829
|
+
style: {
|
|
5830
|
+
position: "absolute",
|
|
5831
|
+
bottom: "100px",
|
|
5832
|
+
left: "50%",
|
|
5833
|
+
transform: "translateX(-50%)",
|
|
5834
|
+
backgroundColor: "#ef4444",
|
|
5835
|
+
color: "white",
|
|
5836
|
+
padding: "8px 16px",
|
|
5837
|
+
borderRadius: "8px",
|
|
5838
|
+
fontSize: "14px",
|
|
5839
|
+
zIndex: 50
|
|
5840
|
+
},
|
|
5841
|
+
children: transcriptionError
|
|
5842
|
+
}),
|
|
5843
|
+
RenderedChatView
|
|
5844
|
+
]
|
|
5845
|
+
})
|
|
5110
5846
|
});
|
|
5111
5847
|
}
|
|
5112
5848
|
(function(_CopilotChat) {
|
|
@@ -7723,6 +8459,18 @@ Object.defineProperty(exports, 'CopilotChatAssistantMessage_default', {
|
|
|
7723
8459
|
return CopilotChatAssistantMessage_default;
|
|
7724
8460
|
}
|
|
7725
8461
|
});
|
|
8462
|
+
Object.defineProperty(exports, 'CopilotChatAttachmentQueue', {
|
|
8463
|
+
enumerable: true,
|
|
8464
|
+
get: function () {
|
|
8465
|
+
return CopilotChatAttachmentQueue;
|
|
8466
|
+
}
|
|
8467
|
+
});
|
|
8468
|
+
Object.defineProperty(exports, 'CopilotChatAttachmentRenderer', {
|
|
8469
|
+
enumerable: true,
|
|
8470
|
+
get: function () {
|
|
8471
|
+
return CopilotChatAttachmentRenderer;
|
|
8472
|
+
}
|
|
8473
|
+
});
|
|
7726
8474
|
Object.defineProperty(exports, 'CopilotChatAudioRecorder', {
|
|
7727
8475
|
enumerable: true,
|
|
7728
8476
|
get: function () {
|
|
@@ -7957,6 +8705,12 @@ Object.defineProperty(exports, 'useAsyncCallback', {
|
|
|
7957
8705
|
return useAsyncCallback;
|
|
7958
8706
|
}
|
|
7959
8707
|
});
|
|
8708
|
+
Object.defineProperty(exports, 'useAttachments', {
|
|
8709
|
+
enumerable: true,
|
|
8710
|
+
get: function () {
|
|
8711
|
+
return useAttachments;
|
|
8712
|
+
}
|
|
8713
|
+
});
|
|
7960
8714
|
Object.defineProperty(exports, 'useCoAgentStateRenders', {
|
|
7961
8715
|
enumerable: true,
|
|
7962
8716
|
get: function () {
|
|
@@ -8071,4 +8825,4 @@ Object.defineProperty(exports, 'useToast', {
|
|
|
8071
8825
|
return useToast;
|
|
8072
8826
|
}
|
|
8073
8827
|
});
|
|
8074
|
-
//# sourceMappingURL=copilotkit-
|
|
8828
|
+
//# sourceMappingURL=copilotkit-B3Eeystj.cjs.map
|