@copilotkit/react-ui 1.55.0-next.9 → 1.55.1-next.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +29 -4
- package/dist/index.cjs +429 -174
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +334 -25
- package/dist/index.css.map +1 -1
- package/dist/index.d.cts +62 -6
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +62 -6
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +430 -176
- package/dist/index.mjs.map +1 -1
- package/dist/index.umd.js +440 -179
- package/dist/index.umd.js.map +1 -1
- package/oxlint-rules/copilotkit-plugin.mjs +10 -0
- package/oxlint-rules/require-cpk-prefix.mjs +547 -0
- package/package.json +33 -34
- package/src/components/chat/AttachmentQueue.tsx +125 -0
- package/src/components/chat/AttachmentRenderer.tsx +133 -0
- package/src/components/chat/Chat.tsx +367 -149
- package/src/components/chat/Modal.tsx +1 -1
- package/src/components/chat/attachment-utils.ts +32 -0
- package/src/components/chat/index.tsx +1 -0
- package/src/components/chat/messages/ImageRenderer.tsx +20 -8
- package/src/components/chat/messages/UserMessage.tsx +42 -8
- package/src/components/chat/props.ts +25 -2
- package/src/css/attachments.css +227 -0
- package/src/css/colors.css +8 -4
- package/src/css/console.css +34 -9
- package/src/css/input.css +5 -2
- package/src/css/markdown.css +1 -1
- package/src/css/messages.css +11 -4
- package/src/css/popup.css +15 -3
- package/src/css/sidebar.css +28 -3
- package/src/css/suggestions.css +4 -2
- package/src/styles.css +2 -1
package/dist/index.cjs
CHANGED
|
@@ -917,6 +917,89 @@ const Header = ({}) => {
|
|
|
917
917
|
});
|
|
918
918
|
};
|
|
919
919
|
|
|
920
|
+
//#endregion
|
|
921
|
+
//#region src/components/chat/AttachmentRenderer.tsx
|
|
922
|
+
const ImageAttachment = (0, react.memo)(function ImageAttachment({ src, className }) {
|
|
923
|
+
const [error, setError] = (0, react.useState)(false);
|
|
924
|
+
if (error) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
925
|
+
className: `copilotKitImageRendering copilotKitImageRenderingError ${className ?? ""}`,
|
|
926
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
927
|
+
className: "copilotKitImageRenderingErrorMessage",
|
|
928
|
+
children: "Failed to load image"
|
|
929
|
+
})
|
|
930
|
+
});
|
|
931
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
932
|
+
className: `copilotKitImageRendering ${className ?? ""}`,
|
|
933
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
|
|
934
|
+
src,
|
|
935
|
+
alt: "Image attachment",
|
|
936
|
+
className: "copilotKitImageRenderingImage",
|
|
937
|
+
onError: () => setError(true)
|
|
938
|
+
})
|
|
939
|
+
});
|
|
940
|
+
});
|
|
941
|
+
const AudioAttachment = (0, react.memo)(function AudioAttachment({ src, filename, className }) {
|
|
942
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
943
|
+
className: `copilotKitAttachment copilotKitAttachmentAudio ${className ?? ""}`,
|
|
944
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("audio", {
|
|
945
|
+
src,
|
|
946
|
+
controls: true,
|
|
947
|
+
preload: "metadata"
|
|
948
|
+
}), filename && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
949
|
+
className: "copilotKitAttachmentFilename",
|
|
950
|
+
children: filename
|
|
951
|
+
})]
|
|
952
|
+
});
|
|
953
|
+
});
|
|
954
|
+
const VideoAttachment = (0, react.memo)(function VideoAttachment({ src, className }) {
|
|
955
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
956
|
+
className: `copilotKitAttachment copilotKitAttachmentVideo ${className ?? ""}`,
|
|
957
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("video", {
|
|
958
|
+
src,
|
|
959
|
+
controls: true,
|
|
960
|
+
preload: "metadata"
|
|
961
|
+
})
|
|
962
|
+
});
|
|
963
|
+
});
|
|
964
|
+
const DocumentAttachment = (0, react.memo)(function DocumentAttachment({ source, filename, className }) {
|
|
965
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
966
|
+
className: `copilotKitAttachment copilotKitAttachmentDocument ${className ?? ""}`,
|
|
967
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
968
|
+
className: "copilotKitAttachmentDocIcon",
|
|
969
|
+
children: (0, _copilotkit_shared.getDocumentIcon)(source.mimeType ?? "")
|
|
970
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
971
|
+
className: "copilotKitAttachmentDocInfo",
|
|
972
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
973
|
+
className: "copilotKitAttachmentDocName",
|
|
974
|
+
children: filename || source.mimeType || "Unknown type"
|
|
975
|
+
})
|
|
976
|
+
})]
|
|
977
|
+
});
|
|
978
|
+
});
|
|
979
|
+
const AttachmentRenderer = ({ type, source, filename, className }) => {
|
|
980
|
+
const src = (0, _copilotkit_shared.getSourceUrl)(source);
|
|
981
|
+
switch (type) {
|
|
982
|
+
case "image": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ImageAttachment, {
|
|
983
|
+
src,
|
|
984
|
+
className
|
|
985
|
+
});
|
|
986
|
+
case "audio": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AudioAttachment, {
|
|
987
|
+
src,
|
|
988
|
+
filename,
|
|
989
|
+
className
|
|
990
|
+
});
|
|
991
|
+
case "video": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(VideoAttachment, {
|
|
992
|
+
src,
|
|
993
|
+
className
|
|
994
|
+
});
|
|
995
|
+
case "document": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DocumentAttachment, {
|
|
996
|
+
source,
|
|
997
|
+
filename,
|
|
998
|
+
className
|
|
999
|
+
});
|
|
1000
|
+
}
|
|
1001
|
+
};
|
|
1002
|
+
|
|
920
1003
|
//#endregion
|
|
921
1004
|
//#region src/components/chat/messages/UserMessage.tsx
|
|
922
1005
|
const getTextContent = (content) => {
|
|
@@ -926,22 +1009,35 @@ const getTextContent = (content) => {
|
|
|
926
1009
|
if (part.type === "text") return part.text;
|
|
927
1010
|
}).filter((value) => typeof value === "string" && value.length > 0).join(" ").trim() || void 0;
|
|
928
1011
|
};
|
|
1012
|
+
const getMediaParts = (content) => {
|
|
1013
|
+
if (!content || typeof content === "string") return [];
|
|
1014
|
+
return content.filter((part) => part.type === "image" || part.type === "audio" || part.type === "video" || part.type === "document");
|
|
1015
|
+
};
|
|
929
1016
|
const UserMessage = (props) => {
|
|
930
1017
|
const { message, ImageRenderer } = props;
|
|
1018
|
+
const content = message?.content;
|
|
931
1019
|
if (message && "image" in message && Boolean(message.image)) {
|
|
932
|
-
const
|
|
933
|
-
const content = getTextContent(imageMessage?.content);
|
|
1020
|
+
const legacyImage = message.image;
|
|
934
1021
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
935
1022
|
className: "copilotKitMessage copilotKitUserMessage",
|
|
936
1023
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ImageRenderer, {
|
|
937
|
-
image:
|
|
938
|
-
content
|
|
1024
|
+
image: legacyImage,
|
|
1025
|
+
content: getTextContent(content)
|
|
939
1026
|
})
|
|
940
1027
|
});
|
|
941
1028
|
}
|
|
942
|
-
|
|
1029
|
+
const textContent = getTextContent(content);
|
|
1030
|
+
const mediaParts = getMediaParts(content);
|
|
1031
|
+
if (mediaParts.length === 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1032
|
+
className: "copilotKitMessage copilotKitUserMessage",
|
|
1033
|
+
children: textContent
|
|
1034
|
+
});
|
|
1035
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
943
1036
|
className: "copilotKitMessage copilotKitUserMessage",
|
|
944
|
-
children:
|
|
1037
|
+
children: [textContent && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { children: textContent }), mediaParts.map((part, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AttachmentRenderer, {
|
|
1038
|
+
type: part.type,
|
|
1039
|
+
source: part.source
|
|
1040
|
+
}, index))]
|
|
945
1041
|
});
|
|
946
1042
|
};
|
|
947
1043
|
|
|
@@ -1411,16 +1507,18 @@ const AssistantMessage = (props) => {
|
|
|
1411
1507
|
//#endregion
|
|
1412
1508
|
//#region src/components/chat/messages/ImageRenderer.tsx
|
|
1413
1509
|
/**
|
|
1414
|
-
*
|
|
1415
|
-
*
|
|
1510
|
+
* @deprecated Use `CopilotChatAttachmentRenderer` from `@copilotkit/react-core/v2` instead.
|
|
1511
|
+
* `ImageRenderer` only handles images. The v2 attachment renderer supports images, audio, video, and documents.
|
|
1512
|
+
* See https://docs.copilotkit.ai/migration-guides/migrate-attachments
|
|
1513
|
+
* @since 1.56.0
|
|
1416
1514
|
*/
|
|
1417
|
-
const ImageRenderer = ({ image, content, className = "" }) => {
|
|
1515
|
+
const ImageRenderer = ({ image, source, content, className = "" }) => {
|
|
1418
1516
|
const [imageError, setImageError] = (0, react.useState)(false);
|
|
1419
|
-
|
|
1517
|
+
let imageSrc;
|
|
1518
|
+
if (source) imageSrc = source.type === "url" ? source.value : `data:${source.mimeType};base64,${source.value}`;
|
|
1519
|
+
else if (image) imageSrc = `data:image/${image.format};base64,${image.bytes}`;
|
|
1520
|
+
else return null;
|
|
1420
1521
|
const altText = content || "User uploaded image";
|
|
1421
|
-
const handleImageError = () => {
|
|
1422
|
-
setImageError(true);
|
|
1423
|
-
};
|
|
1424
1522
|
if (imageError) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1425
1523
|
className: `copilotKitImageRendering copilotKitImageRenderingError ${className}`,
|
|
1426
1524
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
@@ -1437,7 +1535,7 @@ const ImageRenderer = ({ image, content, className = "" }) => {
|
|
|
1437
1535
|
src: imageSrc,
|
|
1438
1536
|
alt: altText,
|
|
1439
1537
|
className: "copilotKitImageRenderingImage",
|
|
1440
|
-
onError:
|
|
1538
|
+
onError: () => setImageError(true)
|
|
1441
1539
|
}), content && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1442
1540
|
className: "copilotKitImageRenderingContent",
|
|
1443
1541
|
children: content
|
|
@@ -1955,61 +2053,101 @@ const Input = ({ inProgress, onSend, chatReady = false, onStop, onUpload, hideSt
|
|
|
1955
2053
|
};
|
|
1956
2054
|
|
|
1957
2055
|
//#endregion
|
|
1958
|
-
//#region src/components/chat/
|
|
1959
|
-
const
|
|
1960
|
-
if (
|
|
2056
|
+
//#region src/components/chat/AttachmentQueue.tsx
|
|
2057
|
+
const AttachmentQueue = ({ attachments, onRemoveAttachment, className = "" }) => {
|
|
2058
|
+
if (attachments.length === 0) return null;
|
|
1961
2059
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1962
|
-
className: `
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
},
|
|
1980
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
|
|
1981
|
-
src: `data:${image.contentType};base64,${image.bytes}`,
|
|
1982
|
-
alt: `Selected image ${index + 1}`,
|
|
1983
|
-
style: {
|
|
1984
|
-
width: "100%",
|
|
1985
|
-
height: "100%",
|
|
1986
|
-
objectFit: "cover"
|
|
1987
|
-
}
|
|
1988
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1989
|
-
onClick: () => onRemoveImage(index),
|
|
1990
|
-
className: "copilotKitImageUploadQueueRemoveButton",
|
|
1991
|
-
style: {
|
|
1992
|
-
position: "absolute",
|
|
1993
|
-
top: "2px",
|
|
1994
|
-
right: "2px",
|
|
1995
|
-
background: "rgba(0,0,0,0.6)",
|
|
1996
|
-
color: "white",
|
|
1997
|
-
border: "none",
|
|
1998
|
-
borderRadius: "50%",
|
|
1999
|
-
width: "18px",
|
|
2000
|
-
height: "18px",
|
|
2001
|
-
display: "flex",
|
|
2002
|
-
alignItems: "center",
|
|
2003
|
-
justifyContent: "center",
|
|
2004
|
-
cursor: "pointer",
|
|
2005
|
-
fontSize: "10px",
|
|
2006
|
-
padding: 0
|
|
2007
|
-
},
|
|
2008
|
-
children: "✕"
|
|
2009
|
-
})]
|
|
2010
|
-
}, index))
|
|
2060
|
+
className: `copilotKitAttachmentQueue ${className}`,
|
|
2061
|
+
children: attachments.map((attachment) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2062
|
+
className: `copilotKitAttachmentQueueItem copilotKitAttachmentQueueItem--${attachment.type}`,
|
|
2063
|
+
children: [
|
|
2064
|
+
attachment.status === "uploading" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2065
|
+
className: "copilotKitAttachmentQueueOverlay",
|
|
2066
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: "copilotKitAttachmentQueueSpinner" })
|
|
2067
|
+
}),
|
|
2068
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(AttachmentPreview, { attachment }),
|
|
2069
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2070
|
+
onClick: () => onRemoveAttachment(attachment.id),
|
|
2071
|
+
className: "copilotKitAttachmentQueueRemoveButton",
|
|
2072
|
+
"aria-label": "Remove attachment",
|
|
2073
|
+
children: "✕"
|
|
2074
|
+
})
|
|
2075
|
+
]
|
|
2076
|
+
}, attachment.id))
|
|
2011
2077
|
});
|
|
2012
2078
|
};
|
|
2079
|
+
function AttachmentPreview({ attachment }) {
|
|
2080
|
+
if (attachment.status === "uploading") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: "copilotKitAttachmentQueuePreviewPlaceholder" });
|
|
2081
|
+
const src = (0, _copilotkit_shared.getSourceUrl)(attachment.source);
|
|
2082
|
+
switch (attachment.type) {
|
|
2083
|
+
case "image": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
|
|
2084
|
+
src,
|
|
2085
|
+
alt: attachment.filename || "Image attachment",
|
|
2086
|
+
className: "copilotKitAttachmentQueuePreviewImage"
|
|
2087
|
+
});
|
|
2088
|
+
case "audio": return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2089
|
+
className: "copilotKitAttachmentQueuePreviewAudio",
|
|
2090
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("audio", {
|
|
2091
|
+
src,
|
|
2092
|
+
controls: true,
|
|
2093
|
+
preload: "metadata"
|
|
2094
|
+
}), attachment.filename && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2095
|
+
className: "copilotKitAttachmentQueueFilename",
|
|
2096
|
+
children: attachment.filename
|
|
2097
|
+
})]
|
|
2098
|
+
});
|
|
2099
|
+
case "video": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2100
|
+
className: "copilotKitAttachmentQueuePreviewVideo",
|
|
2101
|
+
children: attachment.thumbnail ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
|
|
2102
|
+
src: attachment.thumbnail,
|
|
2103
|
+
alt: attachment.filename || "Video thumbnail",
|
|
2104
|
+
className: "copilotKitAttachmentQueuePreviewImage"
|
|
2105
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("video", {
|
|
2106
|
+
src,
|
|
2107
|
+
preload: "metadata",
|
|
2108
|
+
muted: true,
|
|
2109
|
+
className: "copilotKitAttachmentQueuePreviewImage"
|
|
2110
|
+
})
|
|
2111
|
+
});
|
|
2112
|
+
case "document": return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2113
|
+
className: "copilotKitAttachmentQueuePreviewDocument",
|
|
2114
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2115
|
+
className: "copilotKitAttachmentQueueDocIcon",
|
|
2116
|
+
children: (0, _copilotkit_shared.getDocumentIcon)(attachment.source.mimeType ?? "")
|
|
2117
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2118
|
+
className: "copilotKitAttachmentQueueDocInfo",
|
|
2119
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2120
|
+
className: "copilotKitAttachmentQueueFilename",
|
|
2121
|
+
children: attachment.filename || "Document"
|
|
2122
|
+
}), attachment.size != null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2123
|
+
className: "copilotKitAttachmentQueueFileSize",
|
|
2124
|
+
children: (0, _copilotkit_shared.formatFileSize)(attachment.size)
|
|
2125
|
+
})]
|
|
2126
|
+
})]
|
|
2127
|
+
});
|
|
2128
|
+
}
|
|
2129
|
+
}
|
|
2130
|
+
|
|
2131
|
+
//#endregion
|
|
2132
|
+
//#region src/components/chat/attachment-utils.ts
|
|
2133
|
+
const suppressedWarnings = /* @__PURE__ */ new Set();
|
|
2134
|
+
let globalSuppress = false;
|
|
2135
|
+
/**
|
|
2136
|
+
* Issue a deprecation warning once per key per session.
|
|
2137
|
+
* Suppressed entirely if the user calls suppressDeprecationWarnings().
|
|
2138
|
+
*/
|
|
2139
|
+
function deprecationWarning(key, message) {
|
|
2140
|
+
if (globalSuppress || suppressedWarnings.has(key)) return;
|
|
2141
|
+
if (typeof process !== "undefined" && process.env?.NODE_ENV === "production") return;
|
|
2142
|
+
suppressedWarnings.add(key);
|
|
2143
|
+
console.warn(`[CopilotKit] Deprecation: ${message}`);
|
|
2144
|
+
}
|
|
2145
|
+
/**
|
|
2146
|
+
* Suppress all CopilotKit deprecation warnings.
|
|
2147
|
+
*/
|
|
2148
|
+
function suppressDeprecationWarnings() {
|
|
2149
|
+
globalSuppress = true;
|
|
2150
|
+
}
|
|
2013
2151
|
|
|
2014
2152
|
//#endregion
|
|
2015
2153
|
//#region src/components/chat/Suggestion.tsx
|
|
@@ -2109,10 +2247,25 @@ function Suggestions({ suggestions, onSuggestionClick, isLoading }) {
|
|
|
2109
2247
|
* ```
|
|
2110
2248
|
* For more information about how to customize the styles, check out the [Customize Look & Feel](/guides/custom-look-and-feel/customize-built-in-ui-components) guide.
|
|
2111
2249
|
*/
|
|
2112
|
-
function CopilotChat({ instructions, suggestions = "auto", onSubmitMessage, makeSystemMessage, disableSystemMessage, onInProgress, onStopGeneration, onReloadMessages, onRegenerate, onCopy, onThumbsUp, onThumbsDown, markdownTagRenderers, Messages: Messages$2 = Messages, RenderMessage: RenderMessage$1 = RenderMessage, RenderSuggestionsList = Suggestions, Input: Input$2 = Input, className, icons, labels, AssistantMessage: AssistantMessage$2 = AssistantMessage, UserMessage: UserMessage$2 = UserMessage, ImageRenderer: ImageRenderer$1 = ImageRenderer, ErrorMessage, imageUploadsEnabled, inputFileAccept = "image/*", hideStopButton, observabilityHooks, renderError, onError, RenderTextMessage, RenderActionExecutionMessage, RenderAgentStateMessage, RenderResultMessage, RenderImageMessage }) {
|
|
2250
|
+
function CopilotChat({ instructions, suggestions = "auto", onSubmitMessage, makeSystemMessage, disableSystemMessage, onInProgress, onStopGeneration, onReloadMessages, onRegenerate, onCopy, onThumbsUp, onThumbsDown, markdownTagRenderers, Messages: Messages$2 = Messages, RenderMessage: RenderMessage$1 = RenderMessage, RenderSuggestionsList = Suggestions, Input: Input$2 = Input, className, icons, labels, AssistantMessage: AssistantMessage$2 = AssistantMessage, UserMessage: UserMessage$2 = UserMessage, ImageRenderer: ImageRenderer$1 = ImageRenderer, ErrorMessage, imageUploadsEnabled, inputFileAccept = "image/*", attachments, hideStopButton, observabilityHooks, renderError, onError, RenderTextMessage, RenderActionExecutionMessage, RenderAgentStateMessage, RenderResultMessage, RenderImageMessage }) {
|
|
2113
2251
|
const { additionalInstructions, setChatInstructions, copilotApiConfig, setBannerError, setInternalErrorHandler, removeInternalErrorHandler } = (0, _copilotkit_react_core.useCopilotContext)();
|
|
2114
2252
|
const { publicApiKey, chatApiEndpoint } = copilotApiConfig;
|
|
2115
|
-
const
|
|
2253
|
+
const resolvedAttachments = (() => {
|
|
2254
|
+
if (attachments) return attachments;
|
|
2255
|
+
if (imageUploadsEnabled) {
|
|
2256
|
+
deprecationWarning("imageUploadsEnabled", "imageUploadsEnabled is deprecated. Use attachments={{ enabled: true }} instead. See https://docs.copilotkit.ai/migration-guides/migrate-attachments");
|
|
2257
|
+
return {
|
|
2258
|
+
enabled: true,
|
|
2259
|
+
accept: inputFileAccept || "image/*"
|
|
2260
|
+
};
|
|
2261
|
+
}
|
|
2262
|
+
})();
|
|
2263
|
+
const attachmentsEnabled = resolvedAttachments?.enabled ?? false;
|
|
2264
|
+
const attachmentsAccept = resolvedAttachments?.accept ?? "*/*";
|
|
2265
|
+
const attachmentsMaxSize = resolvedAttachments?.maxSize ?? 20 * 1024 * 1024;
|
|
2266
|
+
const [selectedAttachments, setSelectedAttachments] = (0, react.useState)([]);
|
|
2267
|
+
const [dragOver, setDragOver] = (0, react.useState)(false);
|
|
2268
|
+
const processFilesRef = (0, react.useRef)(async () => {});
|
|
2116
2269
|
const [chatError, setChatError] = (0, react.useState)(null);
|
|
2117
2270
|
const [messageFeedback, setMessageFeedback] = (0, react.useState)({});
|
|
2118
2271
|
const fileInputRef = (0, react.useRef)(null);
|
|
@@ -2133,8 +2286,10 @@ function CopilotChat({ instructions, suggestions = "auto", onSubmitMessage, make
|
|
|
2133
2286
|
setBannerError
|
|
2134
2287
|
]);
|
|
2135
2288
|
const triggerChatError = (0, react.useCallback)((error, operation, originalError) => {
|
|
2289
|
+
const errorMessage = error?.message || error?.toString() || "An error occurred";
|
|
2290
|
+
console.error(`[CopilotKit] ${operation} error:`, errorMessage, originalError ?? error);
|
|
2136
2291
|
setChatError({
|
|
2137
|
-
message:
|
|
2292
|
+
message: errorMessage,
|
|
2138
2293
|
operation,
|
|
2139
2294
|
timestamp: Date.now()
|
|
2140
2295
|
});
|
|
@@ -2188,40 +2343,27 @@ function CopilotChat({ instructions, suggestions = "auto", onSubmitMessage, make
|
|
|
2188
2343
|
removeInternalErrorHandler
|
|
2189
2344
|
]);
|
|
2190
2345
|
(0, react.useEffect)(() => {
|
|
2191
|
-
if (!
|
|
2346
|
+
if (!attachmentsEnabled) return;
|
|
2192
2347
|
const handlePaste = async (e) => {
|
|
2193
2348
|
if (!e.target.parentElement?.classList.contains("copilotKitInput")) return;
|
|
2194
|
-
const
|
|
2195
|
-
if (
|
|
2349
|
+
const fileItems = Array.from(e.clipboardData?.items || []).filter((item) => item.kind === "file" && item.getAsFile() !== null && (0, _copilotkit_shared.matchesAcceptFilter)(item.getAsFile(), attachmentsAccept));
|
|
2350
|
+
if (fileItems.length === 0) return;
|
|
2196
2351
|
e.preventDefault();
|
|
2197
|
-
const
|
|
2198
|
-
const file = item.getAsFile();
|
|
2199
|
-
if (!file) return Promise.resolve(null);
|
|
2200
|
-
return new Promise((resolve, reject) => {
|
|
2201
|
-
const reader = new FileReader();
|
|
2202
|
-
reader.onload = (e) => {
|
|
2203
|
-
const base64String = (e.target?.result)?.split(",")[1];
|
|
2204
|
-
if (base64String) resolve({
|
|
2205
|
-
contentType: file.type,
|
|
2206
|
-
bytes: base64String
|
|
2207
|
-
});
|
|
2208
|
-
else resolve(null);
|
|
2209
|
-
};
|
|
2210
|
-
reader.onerror = reject;
|
|
2211
|
-
reader.readAsDataURL(file);
|
|
2212
|
-
});
|
|
2213
|
-
});
|
|
2352
|
+
const files = fileItems.map((item) => item.getAsFile()).filter((f) => f !== null);
|
|
2214
2353
|
try {
|
|
2215
|
-
|
|
2216
|
-
setSelectedImages((prev) => [...prev, ...loadedImages]);
|
|
2354
|
+
await processFilesRef.current(files);
|
|
2217
2355
|
} catch (error) {
|
|
2218
|
-
triggerChatError(error, "
|
|
2219
|
-
console.error("Error processing pasted images:", error);
|
|
2356
|
+
triggerChatError(error, "pasteUpload", error);
|
|
2220
2357
|
}
|
|
2221
2358
|
};
|
|
2222
2359
|
document.addEventListener("paste", handlePaste);
|
|
2223
2360
|
return () => document.removeEventListener("paste", handlePaste);
|
|
2224
|
-
}, [
|
|
2361
|
+
}, [
|
|
2362
|
+
attachmentsEnabled,
|
|
2363
|
+
attachmentsAccept,
|
|
2364
|
+
attachmentsMaxSize,
|
|
2365
|
+
triggerChatError
|
|
2366
|
+
]);
|
|
2225
2367
|
(0, react.useEffect)(() => {
|
|
2226
2368
|
if (!additionalInstructions?.length) {
|
|
2227
2369
|
setChatInstructions(instructions || "");
|
|
@@ -2249,9 +2391,38 @@ function CopilotChat({ instructions, suggestions = "auto", onSubmitMessage, make
|
|
|
2249
2391
|
}
|
|
2250
2392
|
}, [isLoading, triggerObservabilityHook]);
|
|
2251
2393
|
const handleSendMessage = (text) => {
|
|
2252
|
-
|
|
2394
|
+
if (selectedAttachments.some((a) => a.status === "uploading")) {
|
|
2395
|
+
triggerChatError(/* @__PURE__ */ new Error("Attachment(s) still uploading. Please wait."), "sendMessage");
|
|
2396
|
+
return Promise.resolve({
|
|
2397
|
+
id: (0, _copilotkit_shared.randomUUID)(),
|
|
2398
|
+
content: text,
|
|
2399
|
+
role: "user"
|
|
2400
|
+
});
|
|
2401
|
+
}
|
|
2402
|
+
const currentAttachments = selectedAttachments.filter((a) => a.status === "ready");
|
|
2403
|
+
setSelectedAttachments([]);
|
|
2253
2404
|
if (fileInputRef.current) fileInputRef.current.value = "";
|
|
2254
2405
|
triggerObservabilityHook("onMessageSent", text);
|
|
2406
|
+
if (currentAttachments.length > 0) {
|
|
2407
|
+
const contentParts = [];
|
|
2408
|
+
if (text.trim()) contentParts.push({
|
|
2409
|
+
type: "text",
|
|
2410
|
+
text
|
|
2411
|
+
});
|
|
2412
|
+
for (const attachment of currentAttachments) contentParts.push({
|
|
2413
|
+
type: attachment.type,
|
|
2414
|
+
source: attachment.source,
|
|
2415
|
+
metadata: {
|
|
2416
|
+
...attachment.filename ? { filename: attachment.filename } : {},
|
|
2417
|
+
...attachment.metadata
|
|
2418
|
+
}
|
|
2419
|
+
});
|
|
2420
|
+
return sendMessage({
|
|
2421
|
+
id: (0, _copilotkit_shared.randomUUID)(),
|
|
2422
|
+
content: contentParts,
|
|
2423
|
+
role: "user"
|
|
2424
|
+
});
|
|
2425
|
+
}
|
|
2255
2426
|
return sendMessage({
|
|
2256
2427
|
id: (0, _copilotkit_shared.randomUUID)(),
|
|
2257
2428
|
content: text,
|
|
@@ -2269,34 +2440,108 @@ function CopilotChat({ instructions, suggestions = "auto", onSubmitMessage, make
|
|
|
2269
2440
|
if (onCopy) onCopy(message);
|
|
2270
2441
|
triggerObservabilityHook("onMessageCopied", message);
|
|
2271
2442
|
};
|
|
2272
|
-
const
|
|
2273
|
-
|
|
2274
|
-
const
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
contentType: file.type,
|
|
2283
|
-
bytes: base64String
|
|
2284
|
-
});
|
|
2285
|
-
};
|
|
2286
|
-
reader.onerror = reject;
|
|
2287
|
-
reader.readAsDataURL(file);
|
|
2443
|
+
const processFiles = async (files) => {
|
|
2444
|
+
const validFiles = files.filter((file) => (0, _copilotkit_shared.matchesAcceptFilter)(file, attachmentsAccept));
|
|
2445
|
+
const rejectedFiles = files.filter((file) => !(0, _copilotkit_shared.matchesAcceptFilter)(file, attachmentsAccept));
|
|
2446
|
+
for (const file of rejectedFiles) {
|
|
2447
|
+
const message = `File "${file.name}" is not accepted. Supported types: ${attachmentsAccept}`;
|
|
2448
|
+
triggerChatError(new Error(message), "fileUpload");
|
|
2449
|
+
resolvedAttachments?.onUploadFailed?.({
|
|
2450
|
+
reason: "invalid-type",
|
|
2451
|
+
file,
|
|
2452
|
+
message
|
|
2288
2453
|
});
|
|
2289
|
-
}
|
|
2454
|
+
}
|
|
2455
|
+
for (const file of validFiles) {
|
|
2456
|
+
if ((0, _copilotkit_shared.exceedsMaxSize)(file, attachmentsMaxSize)) {
|
|
2457
|
+
const message = `File "${file.name}" exceeds the maximum size of ${(0, _copilotkit_shared.formatFileSize)(attachmentsMaxSize)}`;
|
|
2458
|
+
triggerChatError(new Error(message), "fileUpload");
|
|
2459
|
+
resolvedAttachments?.onUploadFailed?.({
|
|
2460
|
+
reason: "file-too-large",
|
|
2461
|
+
file,
|
|
2462
|
+
message
|
|
2463
|
+
});
|
|
2464
|
+
continue;
|
|
2465
|
+
}
|
|
2466
|
+
const modality = (0, _copilotkit_shared.getModalityFromMimeType)(file.type);
|
|
2467
|
+
const placeholderId = (0, _copilotkit_shared.randomUUID)();
|
|
2468
|
+
const placeholder = {
|
|
2469
|
+
id: placeholderId,
|
|
2470
|
+
type: modality,
|
|
2471
|
+
source: {
|
|
2472
|
+
type: "data",
|
|
2473
|
+
value: "",
|
|
2474
|
+
mimeType: file.type
|
|
2475
|
+
},
|
|
2476
|
+
filename: file.name,
|
|
2477
|
+
size: file.size,
|
|
2478
|
+
status: "uploading"
|
|
2479
|
+
};
|
|
2480
|
+
setSelectedAttachments((prev) => [...prev, placeholder]);
|
|
2481
|
+
try {
|
|
2482
|
+
let source;
|
|
2483
|
+
let uploadMetadata;
|
|
2484
|
+
if (resolvedAttachments?.onUpload) {
|
|
2485
|
+
const { metadata: meta, ...uploadSource } = await resolvedAttachments.onUpload(file);
|
|
2486
|
+
source = uploadSource;
|
|
2487
|
+
uploadMetadata = meta;
|
|
2488
|
+
} else source = {
|
|
2489
|
+
type: "data",
|
|
2490
|
+
value: await (0, _copilotkit_shared.readFileAsBase64)(file),
|
|
2491
|
+
mimeType: file.type
|
|
2492
|
+
};
|
|
2493
|
+
let thumbnail;
|
|
2494
|
+
if (modality === "video") thumbnail = await (0, _copilotkit_shared.generateVideoThumbnail)(file);
|
|
2495
|
+
setSelectedAttachments((prev) => prev.map((att) => att.id === placeholderId ? {
|
|
2496
|
+
...att,
|
|
2497
|
+
source,
|
|
2498
|
+
status: "ready",
|
|
2499
|
+
thumbnail,
|
|
2500
|
+
metadata: uploadMetadata
|
|
2501
|
+
} : att));
|
|
2502
|
+
} catch (error) {
|
|
2503
|
+
setSelectedAttachments((prev) => prev.filter((att) => att.id !== placeholderId));
|
|
2504
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2505
|
+
triggerChatError(/* @__PURE__ */ new Error(`Failed to upload "${file.name}": ${message}`), "fileUpload", error);
|
|
2506
|
+
resolvedAttachments?.onUploadFailed?.({
|
|
2507
|
+
reason: "upload-failed",
|
|
2508
|
+
file,
|
|
2509
|
+
message: `Failed to upload "${file.name}": ${message}`
|
|
2510
|
+
});
|
|
2511
|
+
}
|
|
2512
|
+
}
|
|
2513
|
+
};
|
|
2514
|
+
processFilesRef.current = processFiles;
|
|
2515
|
+
const handleFileUpload = async (event) => {
|
|
2516
|
+
if (!event.target.files || event.target.files.length === 0) return;
|
|
2290
2517
|
try {
|
|
2291
|
-
|
|
2292
|
-
setSelectedImages((prev) => [...prev, ...loadedImages]);
|
|
2518
|
+
await processFiles(Array.from(event.target.files));
|
|
2293
2519
|
} catch (error) {
|
|
2294
|
-
triggerChatError(error, "
|
|
2295
|
-
console.error("Error reading files:", error);
|
|
2520
|
+
triggerChatError(error, "fileUpload", error);
|
|
2296
2521
|
}
|
|
2297
2522
|
};
|
|
2298
|
-
const
|
|
2299
|
-
|
|
2523
|
+
const handleDragOver = (e) => {
|
|
2524
|
+
if (!attachmentsEnabled) return;
|
|
2525
|
+
e.preventDefault();
|
|
2526
|
+
e.stopPropagation();
|
|
2527
|
+
setDragOver(true);
|
|
2528
|
+
};
|
|
2529
|
+
const handleDragLeave = (e) => {
|
|
2530
|
+
e.preventDefault();
|
|
2531
|
+
e.stopPropagation();
|
|
2532
|
+
setDragOver(false);
|
|
2533
|
+
};
|
|
2534
|
+
const handleDrop = async (e) => {
|
|
2535
|
+
e.preventDefault();
|
|
2536
|
+
e.stopPropagation();
|
|
2537
|
+
setDragOver(false);
|
|
2538
|
+
if (!attachmentsEnabled) return;
|
|
2539
|
+
const files = Array.from(e.dataTransfer.files);
|
|
2540
|
+
if (files.length > 0) try {
|
|
2541
|
+
await processFiles(files);
|
|
2542
|
+
} catch (error) {
|
|
2543
|
+
triggerChatError(error, "dropUpload", error);
|
|
2544
|
+
}
|
|
2300
2545
|
};
|
|
2301
2546
|
const handleThumbsUp = (message) => {
|
|
2302
2547
|
if (onThumbsUp) onThumbsUp(message);
|
|
@@ -2314,65 +2559,71 @@ function CopilotChat({ instructions, suggestions = "auto", onSubmitMessage, make
|
|
|
2314
2559
|
}));
|
|
2315
2560
|
triggerObservabilityHook("onFeedbackGiven", message.id, "thumbsDown");
|
|
2316
2561
|
};
|
|
2317
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.
|
|
2562
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(WrappedCopilotChat, {
|
|
2318
2563
|
icons,
|
|
2319
2564
|
labels,
|
|
2320
2565
|
className,
|
|
2321
|
-
children:
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2566
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2567
|
+
onDragOver: handleDragOver,
|
|
2568
|
+
onDragLeave: handleDragLeave,
|
|
2569
|
+
onDrop: handleDrop,
|
|
2570
|
+
className: dragOver ? "copilotKitDragOver" : "",
|
|
2571
|
+
children: [
|
|
2572
|
+
chatError && renderError && renderError({
|
|
2573
|
+
...chatError,
|
|
2574
|
+
onDismiss: () => setChatError(null),
|
|
2575
|
+
onRetry: () => {
|
|
2576
|
+
setChatError(null);
|
|
2577
|
+
}
|
|
2578
|
+
}),
|
|
2579
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Messages$2, {
|
|
2580
|
+
AssistantMessage: AssistantMessage$2,
|
|
2581
|
+
UserMessage: UserMessage$2,
|
|
2582
|
+
RenderMessage: RenderMessage$1,
|
|
2583
|
+
messages,
|
|
2584
|
+
inProgress: isLoading,
|
|
2585
|
+
onRegenerate: handleRegenerate,
|
|
2586
|
+
onCopy: handleCopy,
|
|
2587
|
+
onThumbsUp: handleThumbsUp,
|
|
2588
|
+
onThumbsDown: handleThumbsDown,
|
|
2589
|
+
messageFeedback,
|
|
2590
|
+
markdownTagRenderers,
|
|
2591
|
+
ImageRenderer: ImageRenderer$1,
|
|
2592
|
+
ErrorMessage,
|
|
2593
|
+
chatError,
|
|
2594
|
+
RenderTextMessage,
|
|
2595
|
+
RenderActionExecutionMessage,
|
|
2596
|
+
RenderAgentStateMessage,
|
|
2597
|
+
RenderResultMessage,
|
|
2598
|
+
RenderImageMessage,
|
|
2599
|
+
children: currentSuggestions.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RenderSuggestionsList, {
|
|
2600
|
+
onSuggestionClick: handleSendMessage,
|
|
2601
|
+
suggestions: currentSuggestions,
|
|
2602
|
+
isLoading: isLoadingSuggestions
|
|
2603
|
+
})
|
|
2604
|
+
}),
|
|
2605
|
+
attachmentsEnabled && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(AttachmentQueue, {
|
|
2606
|
+
attachments: selectedAttachments,
|
|
2607
|
+
onRemoveAttachment: (id) => setSelectedAttachments((prev) => prev.filter((att) => att.id !== id))
|
|
2608
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
2609
|
+
type: "file",
|
|
2610
|
+
multiple: true,
|
|
2611
|
+
ref: fileInputRef,
|
|
2612
|
+
onChange: handleFileUpload,
|
|
2613
|
+
accept: attachmentsAccept,
|
|
2614
|
+
style: { display: "none" }
|
|
2615
|
+
})] }),
|
|
2616
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Input$2, {
|
|
2617
|
+
inProgress: isLoading,
|
|
2618
|
+
chatReady: Boolean(agent),
|
|
2619
|
+
onSend: handleSendMessage,
|
|
2620
|
+
isVisible,
|
|
2621
|
+
onStop: stopGeneration,
|
|
2622
|
+
onUpload: attachmentsEnabled ? () => fileInputRef.current?.click() : void 0,
|
|
2623
|
+
hideStopButton
|
|
2353
2624
|
})
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
images: selectedImages,
|
|
2357
|
-
onRemoveImage: removeSelectedImage
|
|
2358
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
2359
|
-
type: "file",
|
|
2360
|
-
multiple: true,
|
|
2361
|
-
ref: fileInputRef,
|
|
2362
|
-
onChange: handleImageUpload,
|
|
2363
|
-
accept: inputFileAccept,
|
|
2364
|
-
style: { display: "none" }
|
|
2365
|
-
})] }),
|
|
2366
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Input$2, {
|
|
2367
|
-
inProgress: isLoading,
|
|
2368
|
-
chatReady: Boolean(agent),
|
|
2369
|
-
onSend: handleSendMessage,
|
|
2370
|
-
isVisible,
|
|
2371
|
-
onStop: stopGeneration,
|
|
2372
|
-
onUpload: imageUploadsEnabled ? () => fileInputRef.current?.click() : void 0,
|
|
2373
|
-
hideStopButton
|
|
2374
|
-
})
|
|
2375
|
-
]
|
|
2625
|
+
]
|
|
2626
|
+
})
|
|
2376
2627
|
});
|
|
2377
2628
|
}
|
|
2378
2629
|
function WrappedCopilotChat({ children, icons, labels, className }) {
|
|
@@ -2425,7 +2676,10 @@ const CopilotModalInner = ({ observabilityHooks, onSetOpen, clickOutsideToClose,
|
|
|
2425
2676
|
triggerObservabilityHook
|
|
2426
2677
|
]);
|
|
2427
2678
|
const memoizedHeader = (0, react.useMemo)(() => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Header, {}), [Header]);
|
|
2428
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
2679
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2680
|
+
className: "copilotKitModalChildrenWrapper",
|
|
2681
|
+
children: (0, react.useMemo)(() => children, [children])
|
|
2682
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2429
2683
|
className,
|
|
2430
2684
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Window, {
|
|
2431
2685
|
clickOutsideToClose,
|
|
@@ -2732,6 +2986,7 @@ Object.defineProperty(exports, 'shouldShowDevConsole', {
|
|
|
2732
2986
|
return _copilotkit_react_core.shouldShowDevConsole;
|
|
2733
2987
|
}
|
|
2734
2988
|
});
|
|
2989
|
+
exports.suppressDeprecationWarnings = suppressDeprecationWarnings;
|
|
2735
2990
|
exports.useChatContext = useChatContext;
|
|
2736
2991
|
exports.useCopilotChatSuggestions = useCopilotChatSuggestions;
|
|
2737
2992
|
//# sourceMappingURL=index.cjs.map
|