@copilotkit/react-ui 1.55.0-next.8 → 1.55.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.umd.js CHANGED
@@ -913,6 +913,90 @@ rehype_raw = __toESM(rehype_raw);
913
913
  });
914
914
  };
915
915
 
916
+ //#endregion
917
+ //#region src/components/chat/AttachmentRenderer.tsx
918
+ const ImageAttachment = (0, react.memo)(function ImageAttachment({ src, className }) {
919
+ const [error, setError] = (0, react.useState)(false);
920
+ if (error) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
921
+ className: `copilotKitImageRendering copilotKitImageRenderingError ${className !== null && className !== void 0 ? className : ""}`,
922
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
923
+ className: "copilotKitImageRenderingErrorMessage",
924
+ children: "Failed to load image"
925
+ })
926
+ });
927
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
928
+ className: `copilotKitImageRendering ${className !== null && className !== void 0 ? className : ""}`,
929
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
930
+ src,
931
+ alt: "Image attachment",
932
+ className: "copilotKitImageRenderingImage",
933
+ onError: () => setError(true)
934
+ })
935
+ });
936
+ });
937
+ const AudioAttachment = (0, react.memo)(function AudioAttachment({ src, filename, className }) {
938
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
939
+ className: `copilotKitAttachment copilotKitAttachmentAudio ${className !== null && className !== void 0 ? className : ""}`,
940
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("audio", {
941
+ src,
942
+ controls: true,
943
+ preload: "metadata"
944
+ }), filename && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
945
+ className: "copilotKitAttachmentFilename",
946
+ children: filename
947
+ })]
948
+ });
949
+ });
950
+ const VideoAttachment = (0, react.memo)(function VideoAttachment({ src, className }) {
951
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
952
+ className: `copilotKitAttachment copilotKitAttachmentVideo ${className !== null && className !== void 0 ? className : ""}`,
953
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("video", {
954
+ src,
955
+ controls: true,
956
+ preload: "metadata"
957
+ })
958
+ });
959
+ });
960
+ const DocumentAttachment = (0, react.memo)(function DocumentAttachment({ source, filename, className }) {
961
+ var _source$mimeType;
962
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
963
+ className: `copilotKitAttachment copilotKitAttachmentDocument ${className !== null && className !== void 0 ? className : ""}`,
964
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
965
+ className: "copilotKitAttachmentDocIcon",
966
+ children: (0, _copilotkit_shared.getDocumentIcon)((_source$mimeType = source.mimeType) !== null && _source$mimeType !== void 0 ? _source$mimeType : "")
967
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
968
+ className: "copilotKitAttachmentDocInfo",
969
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
970
+ className: "copilotKitAttachmentDocName",
971
+ children: filename || source.mimeType || "Unknown type"
972
+ })
973
+ })]
974
+ });
975
+ });
976
+ const AttachmentRenderer = ({ type, source, filename, className }) => {
977
+ const src = (0, _copilotkit_shared.getSourceUrl)(source);
978
+ switch (type) {
979
+ case "image": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ImageAttachment, {
980
+ src,
981
+ className
982
+ });
983
+ case "audio": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AudioAttachment, {
984
+ src,
985
+ filename,
986
+ className
987
+ });
988
+ case "video": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(VideoAttachment, {
989
+ src,
990
+ className
991
+ });
992
+ case "document": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DocumentAttachment, {
993
+ source,
994
+ filename,
995
+ className
996
+ });
997
+ }
998
+ };
999
+
916
1000
  //#endregion
917
1001
  //#region src/components/chat/messages/UserMessage.tsx
918
1002
  const getTextContent = (content) => {
@@ -922,22 +1006,35 @@ rehype_raw = __toESM(rehype_raw);
922
1006
  if (part.type === "text") return part.text;
923
1007
  }).filter((value) => typeof value === "string" && value.length > 0).join(" ").trim() || void 0;
924
1008
  };
1009
+ const getMediaParts = (content) => {
1010
+ if (!content || typeof content === "string") return [];
1011
+ return content.filter((part) => part.type === "image" || part.type === "audio" || part.type === "video" || part.type === "document");
1012
+ };
925
1013
  const UserMessage = (props) => {
926
1014
  const { message, ImageRenderer } = props;
1015
+ const content = message === null || message === void 0 ? void 0 : message.content;
927
1016
  if (message && "image" in message && Boolean(message.image)) {
928
- const imageMessage = message;
929
- const content = getTextContent(imageMessage === null || imageMessage === void 0 ? void 0 : imageMessage.content);
1017
+ const legacyImage = message.image;
930
1018
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
931
1019
  className: "copilotKitMessage copilotKitUserMessage",
932
1020
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ImageRenderer, {
933
- image: imageMessage.image,
934
- content
1021
+ image: legacyImage,
1022
+ content: getTextContent(content)
935
1023
  })
936
1024
  });
937
1025
  }
938
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1026
+ const textContent = getTextContent(content);
1027
+ const mediaParts = getMediaParts(content);
1028
+ if (mediaParts.length === 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1029
+ className: "copilotKitMessage copilotKitUserMessage",
1030
+ children: textContent
1031
+ });
1032
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
939
1033
  className: "copilotKitMessage copilotKitUserMessage",
940
- children: getTextContent(message === null || message === void 0 ? void 0 : message.content)
1034
+ children: [textContent && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { children: textContent }), mediaParts.map((part, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AttachmentRenderer, {
1035
+ type: part.type,
1036
+ source: part.source
1037
+ }, index))]
941
1038
  });
942
1039
  };
943
1040
 
@@ -1409,16 +1506,18 @@ rehype_raw = __toESM(rehype_raw);
1409
1506
  //#endregion
1410
1507
  //#region src/components/chat/messages/ImageRenderer.tsx
1411
1508
  /**
1412
- * Default image rendering component that can be customized by users.
1413
- * Uses CSS classes for styling so users can override styles.
1509
+ * @deprecated Use `CopilotChatAttachmentRenderer` from `@copilotkit/react-core/v2` instead.
1510
+ * `ImageRenderer` only handles images. The v2 attachment renderer supports images, audio, video, and documents.
1511
+ * See https://docs.copilotkit.ai/migration-guides/migrate-attachments
1512
+ * @since 1.56.0
1414
1513
  */
1415
- const ImageRenderer = ({ image, content, className = "" }) => {
1514
+ const ImageRenderer = ({ image, source, content, className = "" }) => {
1416
1515
  const [imageError, setImageError] = (0, react.useState)(false);
1417
- const imageSrc = `data:image/${image.format};base64,${image.bytes}`;
1516
+ let imageSrc;
1517
+ if (source) imageSrc = source.type === "url" ? source.value : `data:${source.mimeType};base64,${source.value}`;
1518
+ else if (image) imageSrc = `data:image/${image.format};base64,${image.bytes}`;
1519
+ else return null;
1418
1520
  const altText = content || "User uploaded image";
1419
- const handleImageError = () => {
1420
- setImageError(true);
1421
- };
1422
1521
  if (imageError) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1423
1522
  className: `copilotKitImageRendering copilotKitImageRenderingError ${className}`,
1424
1523
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
@@ -1435,7 +1534,7 @@ rehype_raw = __toESM(rehype_raw);
1435
1534
  src: imageSrc,
1436
1535
  alt: altText,
1437
1536
  className: "copilotKitImageRenderingImage",
1438
- onError: handleImageError
1537
+ onError: () => setImageError(true)
1439
1538
  }), content && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1440
1539
  className: "copilotKitImageRenderingContent",
1441
1540
  children: content
@@ -1960,61 +2059,104 @@ rehype_raw = __toESM(rehype_raw);
1960
2059
  };
1961
2060
 
1962
2061
  //#endregion
1963
- //#region src/components/chat/ImageUploadQueue.tsx
1964
- const ImageUploadQueue = ({ images, onRemoveImage, className = "" }) => {
1965
- if (images.length === 0) return null;
2062
+ //#region src/components/chat/AttachmentQueue.tsx
2063
+ const AttachmentQueue = ({ attachments, onRemoveAttachment, className = "" }) => {
2064
+ if (attachments.length === 0) return null;
1966
2065
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1967
- className: `copilotKitImageUploadQueue ${className}`,
1968
- style: {
1969
- display: "flex",
1970
- flexWrap: "wrap",
1971
- gap: "8px",
1972
- margin: "8px",
1973
- padding: "8px"
1974
- },
1975
- children: images.map((image, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1976
- className: "copilotKitImageUploadQueueItem",
1977
- style: {
1978
- position: "relative",
1979
- display: "inline-block",
1980
- width: "60px",
1981
- height: "60px",
1982
- borderRadius: "4px",
1983
- overflow: "hidden"
1984
- },
1985
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
1986
- src: `data:${image.contentType};base64,${image.bytes}`,
1987
- alt: `Selected image ${index + 1}`,
1988
- style: {
1989
- width: "100%",
1990
- height: "100%",
1991
- objectFit: "cover"
1992
- }
1993
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1994
- onClick: () => onRemoveImage(index),
1995
- className: "copilotKitImageUploadQueueRemoveButton",
1996
- style: {
1997
- position: "absolute",
1998
- top: "2px",
1999
- right: "2px",
2000
- background: "rgba(0,0,0,0.6)",
2001
- color: "white",
2002
- border: "none",
2003
- borderRadius: "50%",
2004
- width: "18px",
2005
- height: "18px",
2006
- display: "flex",
2007
- alignItems: "center",
2008
- justifyContent: "center",
2009
- cursor: "pointer",
2010
- fontSize: "10px",
2011
- padding: 0
2012
- },
2013
- children: "✕"
2014
- })]
2015
- }, index))
2066
+ className: `copilotKitAttachmentQueue ${className}`,
2067
+ children: attachments.map((attachment) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2068
+ className: `copilotKitAttachmentQueueItem copilotKitAttachmentQueueItem--${attachment.type}`,
2069
+ children: [
2070
+ attachment.status === "uploading" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2071
+ className: "copilotKitAttachmentQueueOverlay",
2072
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: "copilotKitAttachmentQueueSpinner" })
2073
+ }),
2074
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AttachmentPreview, { attachment }),
2075
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2076
+ onClick: () => onRemoveAttachment(attachment.id),
2077
+ className: "copilotKitAttachmentQueueRemoveButton",
2078
+ "aria-label": "Remove attachment",
2079
+ children: ""
2080
+ })
2081
+ ]
2082
+ }, attachment.id))
2016
2083
  });
2017
2084
  };
2085
+ function AttachmentPreview({ attachment }) {
2086
+ if (attachment.status === "uploading") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: "copilotKitAttachmentQueuePreviewPlaceholder" });
2087
+ const src = (0, _copilotkit_shared.getSourceUrl)(attachment.source);
2088
+ switch (attachment.type) {
2089
+ case "image": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
2090
+ src,
2091
+ alt: attachment.filename || "Image attachment",
2092
+ className: "copilotKitAttachmentQueuePreviewImage"
2093
+ });
2094
+ case "audio": return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2095
+ className: "copilotKitAttachmentQueuePreviewAudio",
2096
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("audio", {
2097
+ src,
2098
+ controls: true,
2099
+ preload: "metadata"
2100
+ }), attachment.filename && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2101
+ className: "copilotKitAttachmentQueueFilename",
2102
+ children: attachment.filename
2103
+ })]
2104
+ });
2105
+ case "video": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2106
+ className: "copilotKitAttachmentQueuePreviewVideo",
2107
+ children: attachment.thumbnail ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
2108
+ src: attachment.thumbnail,
2109
+ alt: attachment.filename || "Video thumbnail",
2110
+ className: "copilotKitAttachmentQueuePreviewImage"
2111
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("video", {
2112
+ src,
2113
+ preload: "metadata",
2114
+ muted: true,
2115
+ className: "copilotKitAttachmentQueuePreviewImage"
2116
+ })
2117
+ });
2118
+ case "document":
2119
+ var _attachment$source$mi;
2120
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2121
+ className: "copilotKitAttachmentQueuePreviewDocument",
2122
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2123
+ className: "copilotKitAttachmentQueueDocIcon",
2124
+ children: (0, _copilotkit_shared.getDocumentIcon)((_attachment$source$mi = attachment.source.mimeType) !== null && _attachment$source$mi !== void 0 ? _attachment$source$mi : "")
2125
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2126
+ className: "copilotKitAttachmentQueueDocInfo",
2127
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2128
+ className: "copilotKitAttachmentQueueFilename",
2129
+ children: attachment.filename || "Document"
2130
+ }), attachment.size != null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2131
+ className: "copilotKitAttachmentQueueFileSize",
2132
+ children: (0, _copilotkit_shared.formatFileSize)(attachment.size)
2133
+ })]
2134
+ })]
2135
+ });
2136
+ }
2137
+ }
2138
+
2139
+ //#endregion
2140
+ //#region src/components/chat/attachment-utils.ts
2141
+ const suppressedWarnings = /* @__PURE__ */ new Set();
2142
+ let globalSuppress = false;
2143
+ /**
2144
+ * Issue a deprecation warning once per key per session.
2145
+ * Suppressed entirely if the user calls suppressDeprecationWarnings().
2146
+ */
2147
+ function deprecationWarning(key, message) {
2148
+ var _process$env;
2149
+ if (globalSuppress || suppressedWarnings.has(key)) return;
2150
+ if (typeof process !== "undefined" && ((_process$env = process.env) === null || _process$env === void 0 ? void 0 : _process$env.NODE_ENV) === "production") return;
2151
+ suppressedWarnings.add(key);
2152
+ console.warn(`[CopilotKit] Deprecation: ${message}`);
2153
+ }
2154
+ /**
2155
+ * Suppress all CopilotKit deprecation warnings.
2156
+ */
2157
+ function suppressDeprecationWarnings() {
2158
+ globalSuppress = true;
2159
+ }
2018
2160
 
2019
2161
  //#endregion
2020
2162
  //#region src/components/chat/Suggestion.tsx
@@ -2117,10 +2259,26 @@ rehype_raw = __toESM(rehype_raw);
2117
2259
  * ```
2118
2260
  * 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.
2119
2261
  */
2120
- 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 }) {
2262
+ 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 }) {
2263
+ var _resolvedAttachments$, _resolvedAttachments$2, _resolvedAttachments$3;
2121
2264
  const { additionalInstructions, setChatInstructions, copilotApiConfig, setBannerError, setInternalErrorHandler, removeInternalErrorHandler } = (0, _copilotkit_react_core.useCopilotContext)();
2122
2265
  const { publicApiKey, chatApiEndpoint } = copilotApiConfig;
2123
- const [selectedImages, setSelectedImages] = (0, react.useState)([]);
2266
+ const resolvedAttachments = (() => {
2267
+ if (attachments) return attachments;
2268
+ if (imageUploadsEnabled) {
2269
+ deprecationWarning("imageUploadsEnabled", "imageUploadsEnabled is deprecated. Use attachments={{ enabled: true }} instead. See https://docs.copilotkit.ai/migration-guides/migrate-attachments");
2270
+ return {
2271
+ enabled: true,
2272
+ accept: inputFileAccept || "image/*"
2273
+ };
2274
+ }
2275
+ })();
2276
+ const attachmentsEnabled = (_resolvedAttachments$ = resolvedAttachments === null || resolvedAttachments === void 0 ? void 0 : resolvedAttachments.enabled) !== null && _resolvedAttachments$ !== void 0 ? _resolvedAttachments$ : false;
2277
+ const attachmentsAccept = (_resolvedAttachments$2 = resolvedAttachments === null || resolvedAttachments === void 0 ? void 0 : resolvedAttachments.accept) !== null && _resolvedAttachments$2 !== void 0 ? _resolvedAttachments$2 : "*/*";
2278
+ const attachmentsMaxSize = (_resolvedAttachments$3 = resolvedAttachments === null || resolvedAttachments === void 0 ? void 0 : resolvedAttachments.maxSize) !== null && _resolvedAttachments$3 !== void 0 ? _resolvedAttachments$3 : 20 * 1024 * 1024;
2279
+ const [selectedAttachments, setSelectedAttachments] = (0, react.useState)([]);
2280
+ const [dragOver, setDragOver] = (0, react.useState)(false);
2281
+ const processFilesRef = (0, react.useRef)(async () => {});
2124
2282
  const [chatError, setChatError] = (0, react.useState)(null);
2125
2283
  const [messageFeedback, setMessageFeedback] = (0, react.useState)({});
2126
2284
  const fileInputRef = (0, react.useRef)(null);
@@ -2141,8 +2299,10 @@ rehype_raw = __toESM(rehype_raw);
2141
2299
  setBannerError
2142
2300
  ]);
2143
2301
  const triggerChatError = (0, react.useCallback)((error, operation, originalError) => {
2302
+ const errorMessage = (error === null || error === void 0 ? void 0 : error.message) || (error === null || error === void 0 ? void 0 : error.toString()) || "An error occurred";
2303
+ console.error(`[CopilotKit] ${operation} error:`, errorMessage, originalError !== null && originalError !== void 0 ? originalError : error);
2144
2304
  setChatError({
2145
- message: (error === null || error === void 0 ? void 0 : error.message) || (error === null || error === void 0 ? void 0 : error.toString()) || "An error occurred",
2305
+ message: errorMessage,
2146
2306
  operation,
2147
2307
  timestamp: Date.now()
2148
2308
  });
@@ -2196,42 +2356,28 @@ rehype_raw = __toESM(rehype_raw);
2196
2356
  removeInternalErrorHandler
2197
2357
  ]);
2198
2358
  (0, react.useEffect)(() => {
2199
- if (!imageUploadsEnabled) return;
2359
+ if (!attachmentsEnabled) return;
2200
2360
  const handlePaste = async (e) => {
2201
2361
  var _target$parentElement, _e$clipboardData;
2202
2362
  if (!((_target$parentElement = e.target.parentElement) === null || _target$parentElement === void 0 ? void 0 : _target$parentElement.classList.contains("copilotKitInput"))) return;
2203
- const imageItems = Array.from(((_e$clipboardData = e.clipboardData) === null || _e$clipboardData === void 0 ? void 0 : _e$clipboardData.items) || []).filter((item) => item.type.startsWith("image/"));
2204
- if (imageItems.length === 0) return;
2363
+ const fileItems = Array.from(((_e$clipboardData = e.clipboardData) === null || _e$clipboardData === void 0 ? void 0 : _e$clipboardData.items) || []).filter((item) => item.kind === "file" && item.getAsFile() !== null && (0, _copilotkit_shared.matchesAcceptFilter)(item.getAsFile(), attachmentsAccept));
2364
+ if (fileItems.length === 0) return;
2205
2365
  e.preventDefault();
2206
- const imagePromises = imageItems.map((item) => {
2207
- const file = item.getAsFile();
2208
- if (!file) return Promise.resolve(null);
2209
- return new Promise((resolve, reject) => {
2210
- const reader = new FileReader();
2211
- reader.onload = (e) => {
2212
- var _e$target;
2213
- const base64String = (_e$target = e.target) === null || _e$target === void 0 || (_e$target = _e$target.result) === null || _e$target === void 0 ? void 0 : _e$target.split(",")[1];
2214
- if (base64String) resolve({
2215
- contentType: file.type,
2216
- bytes: base64String
2217
- });
2218
- else resolve(null);
2219
- };
2220
- reader.onerror = reject;
2221
- reader.readAsDataURL(file);
2222
- });
2223
- });
2366
+ const files = fileItems.map((item) => item.getAsFile()).filter((f) => f !== null);
2224
2367
  try {
2225
- const loadedImages = (await Promise.all(imagePromises)).filter((img) => img !== null);
2226
- setSelectedImages((prev) => [...prev, ...loadedImages]);
2368
+ await processFilesRef.current(files);
2227
2369
  } catch (error) {
2228
- triggerChatError(error, "processClipboardImages", error);
2229
- console.error("Error processing pasted images:", error);
2370
+ triggerChatError(error, "pasteUpload", error);
2230
2371
  }
2231
2372
  };
2232
2373
  document.addEventListener("paste", handlePaste);
2233
2374
  return () => document.removeEventListener("paste", handlePaste);
2234
- }, [imageUploadsEnabled, triggerChatError]);
2375
+ }, [
2376
+ attachmentsEnabled,
2377
+ attachmentsAccept,
2378
+ attachmentsMaxSize,
2379
+ triggerChatError
2380
+ ]);
2235
2381
  (0, react.useEffect)(() => {
2236
2382
  if (!(additionalInstructions === null || additionalInstructions === void 0 ? void 0 : additionalInstructions.length)) {
2237
2383
  setChatInstructions(instructions || "");
@@ -2259,9 +2405,38 @@ rehype_raw = __toESM(rehype_raw);
2259
2405
  }
2260
2406
  }, [isLoading, triggerObservabilityHook]);
2261
2407
  const handleSendMessage = (text) => {
2262
- setSelectedImages([]);
2408
+ if (selectedAttachments.some((a) => a.status === "uploading")) {
2409
+ triggerChatError(/* @__PURE__ */ new Error("Attachment(s) still uploading. Please wait."), "sendMessage");
2410
+ return Promise.resolve({
2411
+ id: (0, _copilotkit_shared.randomUUID)(),
2412
+ content: text,
2413
+ role: "user"
2414
+ });
2415
+ }
2416
+ const currentAttachments = selectedAttachments.filter((a) => a.status === "ready");
2417
+ setSelectedAttachments([]);
2263
2418
  if (fileInputRef.current) fileInputRef.current.value = "";
2264
2419
  triggerObservabilityHook("onMessageSent", text);
2420
+ if (currentAttachments.length > 0) {
2421
+ const contentParts = [];
2422
+ if (text.trim()) contentParts.push({
2423
+ type: "text",
2424
+ text
2425
+ });
2426
+ for (const attachment of currentAttachments) contentParts.push({
2427
+ type: attachment.type,
2428
+ source: attachment.source,
2429
+ metadata: {
2430
+ ...attachment.filename ? { filename: attachment.filename } : {},
2431
+ ...attachment.metadata
2432
+ }
2433
+ });
2434
+ return sendMessage({
2435
+ id: (0, _copilotkit_shared.randomUUID)(),
2436
+ content: contentParts,
2437
+ role: "user"
2438
+ });
2439
+ }
2265
2440
  return sendMessage({
2266
2441
  id: (0, _copilotkit_shared.randomUUID)(),
2267
2442
  content: text,
@@ -2279,35 +2454,111 @@ rehype_raw = __toESM(rehype_raw);
2279
2454
  if (onCopy) onCopy(message);
2280
2455
  triggerObservabilityHook("onMessageCopied", message);
2281
2456
  };
2282
- const handleImageUpload = async (event) => {
2283
- if (!event.target.files || event.target.files.length === 0) return;
2284
- const files = Array.from(event.target.files).filter((file) => file.type.startsWith("image/"));
2285
- if (files.length === 0) return;
2286
- const fileReadPromises = files.map((file) => {
2287
- return new Promise((resolve, reject) => {
2288
- const reader = new FileReader();
2289
- reader.onload = (e) => {
2290
- var _e$target2;
2291
- const base64String = ((_e$target2 = e.target) === null || _e$target2 === void 0 || (_e$target2 = _e$target2.result) === null || _e$target2 === void 0 ? void 0 : _e$target2.split(",")[1]) || "";
2292
- if (base64String) resolve({
2293
- contentType: file.type,
2294
- bytes: base64String
2295
- });
2296
- };
2297
- reader.onerror = reject;
2298
- reader.readAsDataURL(file);
2457
+ const processFiles = async (files) => {
2458
+ const validFiles = files.filter((file) => (0, _copilotkit_shared.matchesAcceptFilter)(file, attachmentsAccept));
2459
+ const rejectedFiles = files.filter((file) => !(0, _copilotkit_shared.matchesAcceptFilter)(file, attachmentsAccept));
2460
+ for (const file of rejectedFiles) {
2461
+ var _resolvedAttachments$4;
2462
+ const message = `File "${file.name}" is not accepted. Supported types: ${attachmentsAccept}`;
2463
+ triggerChatError(new Error(message), "fileUpload");
2464
+ resolvedAttachments === null || resolvedAttachments === void 0 || (_resolvedAttachments$4 = resolvedAttachments.onUploadFailed) === null || _resolvedAttachments$4 === void 0 || _resolvedAttachments$4.call(resolvedAttachments, {
2465
+ reason: "invalid-type",
2466
+ file,
2467
+ message
2299
2468
  });
2300
- });
2469
+ }
2470
+ for (const file of validFiles) {
2471
+ if ((0, _copilotkit_shared.exceedsMaxSize)(file, attachmentsMaxSize)) {
2472
+ var _resolvedAttachments$5;
2473
+ const message = `File "${file.name}" exceeds the maximum size of ${(0, _copilotkit_shared.formatFileSize)(attachmentsMaxSize)}`;
2474
+ triggerChatError(new Error(message), "fileUpload");
2475
+ resolvedAttachments === null || resolvedAttachments === void 0 || (_resolvedAttachments$5 = resolvedAttachments.onUploadFailed) === null || _resolvedAttachments$5 === void 0 || _resolvedAttachments$5.call(resolvedAttachments, {
2476
+ reason: "file-too-large",
2477
+ file,
2478
+ message
2479
+ });
2480
+ continue;
2481
+ }
2482
+ const modality = (0, _copilotkit_shared.getModalityFromMimeType)(file.type);
2483
+ const placeholderId = (0, _copilotkit_shared.randomUUID)();
2484
+ const placeholder = {
2485
+ id: placeholderId,
2486
+ type: modality,
2487
+ source: {
2488
+ type: "data",
2489
+ value: "",
2490
+ mimeType: file.type
2491
+ },
2492
+ filename: file.name,
2493
+ size: file.size,
2494
+ status: "uploading"
2495
+ };
2496
+ setSelectedAttachments((prev) => [...prev, placeholder]);
2497
+ try {
2498
+ let source;
2499
+ let uploadMetadata;
2500
+ if (resolvedAttachments === null || resolvedAttachments === void 0 ? void 0 : resolvedAttachments.onUpload) {
2501
+ const { metadata: meta, ...uploadSource } = await resolvedAttachments.onUpload(file);
2502
+ source = uploadSource;
2503
+ uploadMetadata = meta;
2504
+ } else source = {
2505
+ type: "data",
2506
+ value: await (0, _copilotkit_shared.readFileAsBase64)(file),
2507
+ mimeType: file.type
2508
+ };
2509
+ let thumbnail;
2510
+ if (modality === "video") thumbnail = await (0, _copilotkit_shared.generateVideoThumbnail)(file);
2511
+ setSelectedAttachments((prev) => prev.map((att) => att.id === placeholderId ? {
2512
+ ...att,
2513
+ source,
2514
+ status: "ready",
2515
+ thumbnail,
2516
+ metadata: uploadMetadata
2517
+ } : att));
2518
+ } catch (error) {
2519
+ var _resolvedAttachments$6;
2520
+ setSelectedAttachments((prev) => prev.filter((att) => att.id !== placeholderId));
2521
+ const message = error instanceof Error ? error.message : String(error);
2522
+ triggerChatError(/* @__PURE__ */ new Error(`Failed to upload "${file.name}": ${message}`), "fileUpload", error);
2523
+ resolvedAttachments === null || resolvedAttachments === void 0 || (_resolvedAttachments$6 = resolvedAttachments.onUploadFailed) === null || _resolvedAttachments$6 === void 0 || _resolvedAttachments$6.call(resolvedAttachments, {
2524
+ reason: "upload-failed",
2525
+ file,
2526
+ message: `Failed to upload "${file.name}": ${message}`
2527
+ });
2528
+ }
2529
+ }
2530
+ };
2531
+ processFilesRef.current = processFiles;
2532
+ const handleFileUpload = async (event) => {
2533
+ if (!event.target.files || event.target.files.length === 0) return;
2301
2534
  try {
2302
- const loadedImages = await Promise.all(fileReadPromises);
2303
- setSelectedImages((prev) => [...prev, ...loadedImages]);
2535
+ await processFiles(Array.from(event.target.files));
2304
2536
  } catch (error) {
2305
- triggerChatError(error, "processUploadedImages", error);
2306
- console.error("Error reading files:", error);
2537
+ triggerChatError(error, "fileUpload", error);
2307
2538
  }
2308
2539
  };
2309
- const removeSelectedImage = (index) => {
2310
- setSelectedImages((prev) => prev.filter((_, i) => i !== index));
2540
+ const handleDragOver = (e) => {
2541
+ if (!attachmentsEnabled) return;
2542
+ e.preventDefault();
2543
+ e.stopPropagation();
2544
+ setDragOver(true);
2545
+ };
2546
+ const handleDragLeave = (e) => {
2547
+ e.preventDefault();
2548
+ e.stopPropagation();
2549
+ setDragOver(false);
2550
+ };
2551
+ const handleDrop = async (e) => {
2552
+ e.preventDefault();
2553
+ e.stopPropagation();
2554
+ setDragOver(false);
2555
+ if (!attachmentsEnabled) return;
2556
+ const files = Array.from(e.dataTransfer.files);
2557
+ if (files.length > 0) try {
2558
+ await processFiles(files);
2559
+ } catch (error) {
2560
+ triggerChatError(error, "dropUpload", error);
2561
+ }
2311
2562
  };
2312
2563
  const handleThumbsUp = (message) => {
2313
2564
  if (onThumbsUp) onThumbsUp(message);
@@ -2325,68 +2576,74 @@ rehype_raw = __toESM(rehype_raw);
2325
2576
  }));
2326
2577
  triggerObservabilityHook("onFeedbackGiven", message.id, "thumbsDown");
2327
2578
  };
2328
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(WrappedCopilotChat, {
2579
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(WrappedCopilotChat, {
2329
2580
  icons,
2330
2581
  labels,
2331
2582
  className,
2332
- children: [
2333
- chatError && renderError && renderError({
2334
- ...chatError,
2335
- onDismiss: () => setChatError(null),
2336
- onRetry: () => {
2337
- setChatError(null);
2338
- }
2339
- }),
2340
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Messages$2, {
2341
- AssistantMessage: AssistantMessage$2,
2342
- UserMessage: UserMessage$2,
2343
- RenderMessage: RenderMessage$1,
2344
- messages,
2345
- inProgress: isLoading,
2346
- onRegenerate: handleRegenerate,
2347
- onCopy: handleCopy,
2348
- onThumbsUp: handleThumbsUp,
2349
- onThumbsDown: handleThumbsDown,
2350
- messageFeedback,
2351
- markdownTagRenderers,
2352
- ImageRenderer: ImageRenderer$1,
2353
- ErrorMessage,
2354
- chatError,
2355
- RenderTextMessage,
2356
- RenderActionExecutionMessage,
2357
- RenderAgentStateMessage,
2358
- RenderResultMessage,
2359
- RenderImageMessage,
2360
- children: currentSuggestions.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RenderSuggestionsList, {
2361
- onSuggestionClick: handleSendMessage,
2362
- suggestions: currentSuggestions,
2363
- isLoading: isLoadingSuggestions
2583
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2584
+ onDragOver: handleDragOver,
2585
+ onDragLeave: handleDragLeave,
2586
+ onDrop: handleDrop,
2587
+ className: dragOver ? "copilotKitDragOver" : "",
2588
+ children: [
2589
+ chatError && renderError && renderError({
2590
+ ...chatError,
2591
+ onDismiss: () => setChatError(null),
2592
+ onRetry: () => {
2593
+ setChatError(null);
2594
+ }
2595
+ }),
2596
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Messages$2, {
2597
+ AssistantMessage: AssistantMessage$2,
2598
+ UserMessage: UserMessage$2,
2599
+ RenderMessage: RenderMessage$1,
2600
+ messages,
2601
+ inProgress: isLoading,
2602
+ onRegenerate: handleRegenerate,
2603
+ onCopy: handleCopy,
2604
+ onThumbsUp: handleThumbsUp,
2605
+ onThumbsDown: handleThumbsDown,
2606
+ messageFeedback,
2607
+ markdownTagRenderers,
2608
+ ImageRenderer: ImageRenderer$1,
2609
+ ErrorMessage,
2610
+ chatError,
2611
+ RenderTextMessage,
2612
+ RenderActionExecutionMessage,
2613
+ RenderAgentStateMessage,
2614
+ RenderResultMessage,
2615
+ RenderImageMessage,
2616
+ children: currentSuggestions.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RenderSuggestionsList, {
2617
+ onSuggestionClick: handleSendMessage,
2618
+ suggestions: currentSuggestions,
2619
+ isLoading: isLoadingSuggestions
2620
+ })
2621
+ }),
2622
+ attachmentsEnabled && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(AttachmentQueue, {
2623
+ attachments: selectedAttachments,
2624
+ onRemoveAttachment: (id) => setSelectedAttachments((prev) => prev.filter((att) => att.id !== id))
2625
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
2626
+ type: "file",
2627
+ multiple: true,
2628
+ ref: fileInputRef,
2629
+ onChange: handleFileUpload,
2630
+ accept: attachmentsAccept,
2631
+ style: { display: "none" }
2632
+ })] }),
2633
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Input$2, {
2634
+ inProgress: isLoading,
2635
+ chatReady: Boolean(agent),
2636
+ onSend: handleSendMessage,
2637
+ isVisible,
2638
+ onStop: stopGeneration,
2639
+ onUpload: attachmentsEnabled ? () => {
2640
+ var _fileInputRef$current;
2641
+ return (_fileInputRef$current = fileInputRef.current) === null || _fileInputRef$current === void 0 ? void 0 : _fileInputRef$current.click();
2642
+ } : void 0,
2643
+ hideStopButton
2364
2644
  })
2365
- }),
2366
- imageUploadsEnabled && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ImageUploadQueue, {
2367
- images: selectedImages,
2368
- onRemoveImage: removeSelectedImage
2369
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
2370
- type: "file",
2371
- multiple: true,
2372
- ref: fileInputRef,
2373
- onChange: handleImageUpload,
2374
- accept: inputFileAccept,
2375
- style: { display: "none" }
2376
- })] }),
2377
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Input$2, {
2378
- inProgress: isLoading,
2379
- chatReady: Boolean(agent),
2380
- onSend: handleSendMessage,
2381
- isVisible,
2382
- onStop: stopGeneration,
2383
- onUpload: imageUploadsEnabled ? () => {
2384
- var _fileInputRef$current;
2385
- return (_fileInputRef$current = fileInputRef.current) === null || _fileInputRef$current === void 0 ? void 0 : _fileInputRef$current.click();
2386
- } : void 0,
2387
- hideStopButton
2388
- })
2389
- ]
2645
+ ]
2646
+ })
2390
2647
  });
2391
2648
  }
2392
2649
  function WrappedCopilotChat({ children, icons, labels, className }) {
@@ -2439,7 +2696,10 @@ rehype_raw = __toESM(rehype_raw);
2439
2696
  triggerObservabilityHook
2440
2697
  ]);
2441
2698
  const memoizedHeader = (0, react.useMemo)(() => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Header, {}), [Header]);
2442
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react.useMemo)(() => children, [children]), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2699
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2700
+ className: "copilotKitModalChildrenWrapper",
2701
+ children: (0, react.useMemo)(() => children, [children])
2702
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2443
2703
  className,
2444
2704
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Window, {
2445
2705
  clickOutsideToClose,
@@ -2747,6 +3007,7 @@ Object.defineProperty(exports, 'shouldShowDevConsole', {
2747
3007
  return _copilotkit_react_core.shouldShowDevConsole;
2748
3008
  }
2749
3009
  });
3010
+ exports.suppressDeprecationWarnings = suppressDeprecationWarnings;
2750
3011
  exports.useChatContext = useChatContext;
2751
3012
  exports.useCopilotChatSuggestions = useCopilotChatSuggestions;
2752
3013
  });