@copilotkit/react-ui 1.55.0-next.9 → 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.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 imageMessage = message;
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: imageMessage.image,
938
- content
1024
+ image: legacyImage,
1025
+ content: getTextContent(content)
939
1026
  })
940
1027
  });
941
1028
  }
942
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
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: getTextContent(message?.content)
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
- * Default image rendering component that can be customized by users.
1415
- * Uses CSS classes for styling so users can override styles.
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
- const imageSrc = `data:image/${image.format};base64,${image.bytes}`;
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: handleImageError
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/ImageUploadQueue.tsx
1959
- const ImageUploadQueue = ({ images, onRemoveImage, className = "" }) => {
1960
- if (images.length === 0) return null;
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: `copilotKitImageUploadQueue ${className}`,
1963
- style: {
1964
- display: "flex",
1965
- flexWrap: "wrap",
1966
- gap: "8px",
1967
- margin: "8px",
1968
- padding: "8px"
1969
- },
1970
- children: images.map((image, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1971
- className: "copilotKitImageUploadQueueItem",
1972
- style: {
1973
- position: "relative",
1974
- display: "inline-block",
1975
- width: "60px",
1976
- height: "60px",
1977
- borderRadius: "4px",
1978
- overflow: "hidden"
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 [selectedImages, setSelectedImages] = (0, react.useState)([]);
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: error?.message || error?.toString() || "An error occurred",
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 (!imageUploadsEnabled) return;
2346
+ if (!attachmentsEnabled) return;
2192
2347
  const handlePaste = async (e) => {
2193
2348
  if (!e.target.parentElement?.classList.contains("copilotKitInput")) return;
2194
- const imageItems = Array.from(e.clipboardData?.items || []).filter((item) => item.type.startsWith("image/"));
2195
- if (imageItems.length === 0) return;
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 imagePromises = imageItems.map((item) => {
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
- const loadedImages = (await Promise.all(imagePromises)).filter((img) => img !== null);
2216
- setSelectedImages((prev) => [...prev, ...loadedImages]);
2354
+ await processFilesRef.current(files);
2217
2355
  } catch (error) {
2218
- triggerChatError(error, "processClipboardImages", 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
- }, [imageUploadsEnabled, triggerChatError]);
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
- setSelectedImages([]);
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 handleImageUpload = async (event) => {
2273
- if (!event.target.files || event.target.files.length === 0) return;
2274
- const files = Array.from(event.target.files).filter((file) => file.type.startsWith("image/"));
2275
- if (files.length === 0) return;
2276
- const fileReadPromises = files.map((file) => {
2277
- return new Promise((resolve, reject) => {
2278
- const reader = new FileReader();
2279
- reader.onload = (e) => {
2280
- const base64String = (e.target?.result)?.split(",")[1] || "";
2281
- if (base64String) resolve({
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
- const loadedImages = await Promise.all(fileReadPromises);
2292
- setSelectedImages((prev) => [...prev, ...loadedImages]);
2518
+ await processFiles(Array.from(event.target.files));
2293
2519
  } catch (error) {
2294
- triggerChatError(error, "processUploadedImages", error);
2295
- console.error("Error reading files:", error);
2520
+ triggerChatError(error, "fileUpload", error);
2296
2521
  }
2297
2522
  };
2298
- const removeSelectedImage = (index) => {
2299
- setSelectedImages((prev) => prev.filter((_, i) => i !== index));
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.jsxs)(WrappedCopilotChat, {
2562
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(WrappedCopilotChat, {
2318
2563
  icons,
2319
2564
  labels,
2320
2565
  className,
2321
- children: [
2322
- chatError && renderError && renderError({
2323
- ...chatError,
2324
- onDismiss: () => setChatError(null),
2325
- onRetry: () => {
2326
- setChatError(null);
2327
- }
2328
- }),
2329
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Messages$2, {
2330
- AssistantMessage: AssistantMessage$2,
2331
- UserMessage: UserMessage$2,
2332
- RenderMessage: RenderMessage$1,
2333
- messages,
2334
- inProgress: isLoading,
2335
- onRegenerate: handleRegenerate,
2336
- onCopy: handleCopy,
2337
- onThumbsUp: handleThumbsUp,
2338
- onThumbsDown: handleThumbsDown,
2339
- messageFeedback,
2340
- markdownTagRenderers,
2341
- ImageRenderer: ImageRenderer$1,
2342
- ErrorMessage,
2343
- chatError,
2344
- RenderTextMessage,
2345
- RenderActionExecutionMessage,
2346
- RenderAgentStateMessage,
2347
- RenderResultMessage,
2348
- RenderImageMessage,
2349
- children: currentSuggestions.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RenderSuggestionsList, {
2350
- onSuggestionClick: handleSendMessage,
2351
- suggestions: currentSuggestions,
2352
- isLoading: isLoadingSuggestions
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
- imageUploadsEnabled && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ImageUploadQueue, {
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: [(0, react.useMemo)(() => children, [children]), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
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