@yourgpt/copilot-sdk 2.1.5-alpha.5 → 2.1.5-alpha.6

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/ui/index.js CHANGED
@@ -1,9 +1,9 @@
1
- import { useThreadManager } from '../chunk-ZAOTYA5L.js';
1
+ import { useThreadManager } from '../chunk-PURFAD2P.js';
2
2
  import { DEFAULT_MCP_UI_SANDBOX, parseMCPUIMessage } from '../chunk-G4SF2PNQ.js';
3
3
  import { cn, Loader, TextShimmerLoader } from '../chunk-TXQ37MAO.js';
4
4
  export { Loader, cn } from '../chunk-TXQ37MAO.js';
5
- import { useCopilot } from '../chunk-DH6EO6NW.js';
6
- import { createServerAdapter } from '../chunk-YLZCTR4O.js';
5
+ import { useCopilot } from '../chunk-I2XOCFHG.js';
6
+ import { createServerAdapter } from '../chunk-PSNLKMZH.js';
7
7
  import '../chunk-EWVQWTNV.js';
8
8
  import '../chunk-VNLLW3ZI.js';
9
9
  import '../chunk-533K2Z7C.js';
@@ -31,6 +31,7 @@ import * as AvatarPrimitive from '@radix-ui/react-avatar';
31
31
  import * as HoverCardPrimitive from '@radix-ui/react-hover-card';
32
32
  import { Globe, ChevronUp, ChevronDown, ExternalLink } from 'lucide-react';
33
33
  import { Popover as Popover$1 } from '@base-ui/react/popover';
34
+ import * as ReactDOM from 'react-dom';
34
35
 
35
36
  var createHeading = (Tag) => {
36
37
  const HeadingComponent = ({
@@ -4555,17 +4556,37 @@ function DefaultMessage({
4555
4556
  )
4556
4557
  ] })
4557
4558
  ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
4558
- message.content && /* @__PURE__ */ jsxs("div", { className: "relative", children: [
4559
- /* @__PURE__ */ jsx(
4560
- MessageContent,
4559
+ /* @__PURE__ */ jsxs("div", { className: "relative", children: [
4560
+ /* @__PURE__ */ jsxs(
4561
+ "div",
4561
4562
  {
4562
4563
  className: cn(
4563
- "csdk-message-user rounded-lg px-4 py-2 bg-primary text-primary-foreground",
4564
+ "csdk-message-user rounded-2xl overflow-hidden bg-primary text-primary-foreground",
4565
+ hasAttachments && "p-[3px]",
4566
+ hasAttachments && !message.content && "max-w-[260px]",
4567
+ hasAttachments && message.content && "max-w-[280px]",
4568
+ !hasAttachments && "",
4564
4569
  userMessageClassName
4565
4570
  ),
4566
- markdown: true,
4567
- size,
4568
- children: message.content
4571
+ children: [
4572
+ hasAttachments && /* @__PURE__ */ jsx(
4573
+ MessageMedia,
4574
+ {
4575
+ attachments: message.attachments,
4576
+ hasText: !!message.content,
4577
+ align: "end"
4578
+ }
4579
+ ),
4580
+ message.content && /* @__PURE__ */ jsx(
4581
+ MessageContent,
4582
+ {
4583
+ className: cn("px-4 py-2"),
4584
+ markdown: true,
4585
+ size,
4586
+ children: message.content
4587
+ }
4588
+ )
4589
+ ]
4569
4590
  }
4570
4591
  ),
4571
4592
  showEditBtn && /* @__PURE__ */ jsx(
@@ -4579,7 +4600,7 @@ function DefaultMessage({
4579
4600
  "size-6 flex items-center justify-center rounded-full",
4580
4601
  "text-muted-foreground bg-background border border-border shadow-sm",
4581
4602
  "opacity-0 group-hover/user-msg:opacity-100 transition-opacity",
4582
- "hover:text-foreground hover:bg-muted"
4603
+ "hover:text-foreground hover:bg-muted cursor-pointer"
4583
4604
  ),
4584
4605
  children: /* @__PURE__ */ jsxs(
4585
4606
  "svg",
@@ -4601,7 +4622,6 @@ function DefaultMessage({
4601
4622
  }
4602
4623
  )
4603
4624
  ] }),
4604
- hasAttachments && /* @__PURE__ */ jsx("div", { className: "mt-2 flex flex-wrap gap-2 justify-end", children: message.attachments.map((attachment, index) => /* @__PURE__ */ jsx(AttachmentPreview, { attachment }, index)) }),
4605
4625
  showBranchNav && /* @__PURE__ */ jsx(
4606
4626
  BranchNavigator,
4607
4627
  {
@@ -4873,7 +4893,14 @@ function DefaultMessage({
4873
4893
  tool.id
4874
4894
  );
4875
4895
  }) }),
4876
- message.attachments && message.attachments.length > 0 && /* @__PURE__ */ jsx("div", { className: "mt-2 flex flex-wrap gap-2", children: message.attachments.map((attachment, index) => /* @__PURE__ */ jsx(AttachmentPreview, { attachment }, index)) }),
4896
+ message.attachments && message.attachments.length > 0 && /* @__PURE__ */ jsx("div", { className: "csdk-assistant-attachments mt-2", children: /* @__PURE__ */ jsx(
4897
+ MessageMedia,
4898
+ {
4899
+ attachments: message.attachments,
4900
+ hasText: !!message.content,
4901
+ align: "start"
4902
+ }
4903
+ ) }),
4877
4904
  shouldShowSources && /* @__PURE__ */ jsx(
4878
4905
  SourceGroup,
4879
4906
  {
@@ -4900,83 +4927,379 @@ function DefaultMessage({
4900
4927
  ] })
4901
4928
  ] });
4902
4929
  }
4903
- function AttachmentPreview({ attachment }) {
4904
- const [expanded, setExpanded] = React19.useState(false);
4905
- if (attachment.type !== "image") {
4906
- return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 rounded-lg border bg-muted/50 px-3 py-2 text-sm", children: [
4907
- /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: attachment.type }),
4908
- /* @__PURE__ */ jsx("span", { children: attachment.filename || "Attachment" })
4909
- ] });
4910
- }
4911
- let src;
4912
- if (attachment.url) {
4913
- src = attachment.url;
4914
- } else if (attachment.data) {
4915
- src = attachment.data.startsWith("data:") ? attachment.data : `data:${attachment.mimeType};base64,${attachment.data}`;
4916
- } else {
4917
- return null;
4930
+ function getAttachmentSrc(attachment) {
4931
+ if (attachment.url) return attachment.url;
4932
+ if (attachment.data) {
4933
+ return attachment.data.startsWith("data:") ? attachment.data : `data:${attachment.mimeType};base64,${attachment.data}`;
4918
4934
  }
4935
+ return null;
4936
+ }
4937
+ function ImageLightbox({
4938
+ src,
4939
+ alt,
4940
+ onClose
4941
+ }) {
4942
+ const [closing, setClosing] = React19.useState(false);
4943
+ const backdropRef = React19.useRef(null);
4944
+ const handleClose = React19.useCallback(() => {
4945
+ setClosing(true);
4946
+ setTimeout(onClose, 180);
4947
+ }, [onClose]);
4948
+ React19.useEffect(() => {
4949
+ const handler = (e) => {
4950
+ if (e.key === "Escape") handleClose();
4951
+ };
4952
+ document.addEventListener("keydown", handler);
4953
+ return () => document.removeEventListener("keydown", handler);
4954
+ }, [handleClose]);
4955
+ React19.useEffect(() => {
4956
+ const prev = document.body.style.overflow;
4957
+ document.body.style.overflow = "hidden";
4958
+ return () => {
4959
+ document.body.style.overflow = prev;
4960
+ };
4961
+ }, []);
4962
+ const portal = /* @__PURE__ */ jsxs(
4963
+ "div",
4964
+ {
4965
+ ref: backdropRef,
4966
+ className: "csdk-lightbox csdk-lightbox-backdrop fixed inset-0 z-[9999] flex items-center justify-center cursor-zoom-out",
4967
+ onClick: handleClose,
4968
+ style: {
4969
+ animation: closing ? "csdk-lightbox-backdrop-out 180ms ease-in forwards" : "csdk-lightbox-backdrop-in 200ms ease-out forwards"
4970
+ },
4971
+ children: [
4972
+ /* @__PURE__ */ jsx(
4973
+ "div",
4974
+ {
4975
+ className: "csdk-lightbox-scrim absolute inset-0",
4976
+ style: {
4977
+ backgroundColor: "rgba(0, 0, 0, 0.88)",
4978
+ backdropFilter: "blur(12px)",
4979
+ WebkitBackdropFilter: "blur(12px)",
4980
+ animation: closing ? "csdk-lightbox-fade-out 180ms ease-in forwards" : "csdk-lightbox-fade-in 200ms ease-out forwards"
4981
+ }
4982
+ }
4983
+ ),
4984
+ /* @__PURE__ */ jsxs(
4985
+ "div",
4986
+ {
4987
+ className: "csdk-lightbox-content relative z-10 max-w-[90vw] max-h-[90vh]",
4988
+ style: {
4989
+ animation: closing ? "csdk-lightbox-img-out 180ms ease-in forwards" : "csdk-lightbox-img-in 220ms cubic-bezier(0.22, 1, 0.36, 1) forwards"
4990
+ },
4991
+ onClick: (e) => e.stopPropagation(),
4992
+ children: [
4993
+ /* @__PURE__ */ jsx(
4994
+ "img",
4995
+ {
4996
+ src,
4997
+ alt,
4998
+ className: "csdk-lightbox-image max-w-full max-h-[90vh] object-contain rounded-xl",
4999
+ style: { boxShadow: "0 25px 50px -12px rgba(0,0,0,0.5)" },
5000
+ draggable: false
5001
+ }
5002
+ ),
5003
+ /* @__PURE__ */ jsx(
5004
+ "button",
5005
+ {
5006
+ type: "button",
5007
+ className: "csdk-lightbox-close absolute -top-3 -right-3 size-8 flex items-center justify-center rounded-full shadow-lg transition-[background,transform] duration-150 cursor-pointer active:scale-95",
5008
+ style: { backgroundColor: "rgba(255,255,255,0.9)" },
5009
+ onMouseEnter: (e) => {
5010
+ e.currentTarget.style.backgroundColor = "rgba(255,255,255,1)";
5011
+ },
5012
+ onMouseLeave: (e) => {
5013
+ e.currentTarget.style.backgroundColor = "rgba(255,255,255,0.9)";
5014
+ },
5015
+ onClick: handleClose,
5016
+ children: /* @__PURE__ */ jsxs(
5017
+ "svg",
5018
+ {
5019
+ className: "size-4",
5020
+ style: { color: "#333" },
5021
+ fill: "none",
5022
+ viewBox: "0 0 24 24",
5023
+ stroke: "currentColor",
5024
+ strokeWidth: 2.5,
5025
+ strokeLinecap: "round",
5026
+ strokeLinejoin: "round",
5027
+ children: [
5028
+ /* @__PURE__ */ jsx("path", { d: "M18 6 6 18" }),
5029
+ /* @__PURE__ */ jsx("path", { d: "m6 6 12 12" })
5030
+ ]
5031
+ }
5032
+ )
5033
+ }
5034
+ )
5035
+ ]
5036
+ }
5037
+ ),
5038
+ /* @__PURE__ */ jsx("style", { children: `
5039
+ @keyframes csdk-lightbox-fade-in { from { opacity: 0; } to { opacity: 1; } }
5040
+ @keyframes csdk-lightbox-fade-out { from { opacity: 1; } to { opacity: 0; } }
5041
+ @keyframes csdk-lightbox-img-in { from { opacity: 0; transform: scale(0.92); } to { opacity: 1; transform: scale(1); } }
5042
+ @keyframes csdk-lightbox-img-out { from { opacity: 1; transform: scale(1); } to { opacity: 0; transform: scale(0.95); } }
5043
+ @keyframes csdk-lightbox-backdrop-in { from { opacity: 0; } to { opacity: 1; } }
5044
+ @keyframes csdk-lightbox-backdrop-out { from { opacity: 1; } to { opacity: 0; } }
5045
+ ` })
5046
+ ]
5047
+ }
5048
+ );
5049
+ return typeof document !== "undefined" ? ReactDOM.createPortal(portal, document.body) : null;
5050
+ }
5051
+ function ImageThumb({
5052
+ src,
5053
+ alt,
5054
+ className
5055
+ }) {
5056
+ const [expanded, setExpanded] = React19.useState(false);
4919
5057
  return /* @__PURE__ */ jsxs(Fragment, { children: [
4920
5058
  /* @__PURE__ */ jsx(
4921
5059
  "button",
4922
5060
  {
4923
5061
  type: "button",
4924
5062
  onClick: () => setExpanded(true),
4925
- className: "relative rounded-lg overflow-hidden border bg-muted/50 hover:opacity-90 transition-opacity",
5063
+ className: cn(
5064
+ "csdk-attachment-image relative overflow-hidden cursor-zoom-in",
5065
+ "transition-[opacity,transform] duration-150 hover:opacity-90 active:scale-[0.98]",
5066
+ className
5067
+ ),
5068
+ style: { backgroundColor: "#000" },
4926
5069
  children: /* @__PURE__ */ jsx(
4927
5070
  "img",
4928
5071
  {
4929
5072
  src,
4930
- alt: attachment.filename || "Image",
4931
- className: "max-w-[200px] max-h-[150px] object-cover"
5073
+ alt,
5074
+ className: "w-full h-full object-cover",
5075
+ loading: "lazy",
5076
+ draggable: false
4932
5077
  }
4933
5078
  )
4934
5079
  }
4935
5080
  ),
4936
- expanded && /* @__PURE__ */ jsx(
5081
+ expanded && /* @__PURE__ */ jsx(ImageLightbox, { src, alt, onClose: () => setExpanded(false) })
5082
+ ] });
5083
+ }
5084
+ function FileCard({ attachment }) {
5085
+ const isPdfFile = isPdf(attachment);
5086
+ const isAudio = attachment.type === "audio";
5087
+ const isVideo = attachment.type === "video";
5088
+ const accent = isPdfFile ? { color: "#ef4444", bg: "rgba(239,68,68,0.12)" } : isAudio ? { color: "#10b981", bg: "rgba(16,185,129,0.12)" } : isVideo ? { color: "#8b5cf6", bg: "rgba(139,92,246,0.12)" } : { color: "#3b82f6", bg: "rgba(59,130,246,0.12)" };
5089
+ const label = isPdfFile ? "PDF" : attachment.mimeType?.split("/")[1]?.toUpperCase() || attachment.type?.toUpperCase() || "FILE";
5090
+ const filename = attachment.filename || "Attachment";
5091
+ const href = attachment.url || (attachment.data?.startsWith("data:") ? attachment.data : null);
5092
+ const cssClass = isPdfFile ? "csdk-attachment-pdf" : "csdk-attachment-file";
5093
+ return /* @__PURE__ */ jsxs(
5094
+ "a",
5095
+ {
5096
+ href: href ?? void 0,
5097
+ target: "_blank",
5098
+ rel: "noopener noreferrer",
5099
+ download: isPdfFile ? void 0 : attachment.filename,
5100
+ className: cn(
5101
+ cssClass,
5102
+ "flex items-center gap-2 rounded-lg min-w-0 w-full",
5103
+ "px-2 py-1.5 cursor-pointer transition-opacity duration-150 hover:opacity-80",
5104
+ "no-underline"
5105
+ ),
5106
+ style: { backgroundColor: "rgba(255,255,255,0.92)", color: "#1a1a1a" },
5107
+ onClick: (e) => {
5108
+ if (!href) e.preventDefault();
5109
+ },
5110
+ children: [
5111
+ /* @__PURE__ */ jsx(
5112
+ "div",
5113
+ {
5114
+ className: "size-8 rounded-md flex items-center justify-center shrink-0",
5115
+ style: { backgroundColor: accent.bg },
5116
+ children: /* @__PURE__ */ jsx(
5117
+ "svg",
5118
+ {
5119
+ className: "size-4",
5120
+ viewBox: "0 0 24 24",
5121
+ fill: "none",
5122
+ stroke: accent.color,
5123
+ strokeWidth: 1.8,
5124
+ strokeLinecap: "round",
5125
+ strokeLinejoin: "round",
5126
+ children: isPdfFile || !isAudio && !isVideo ? /* @__PURE__ */ jsxs(Fragment, { children: [
5127
+ /* @__PURE__ */ jsx("path", { d: "M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z" }),
5128
+ /* @__PURE__ */ jsx("path", { d: "M14 2v4a2 2 0 0 0 2 2h4" })
5129
+ ] }) : isAudio ? /* @__PURE__ */ jsxs(Fragment, { children: [
5130
+ /* @__PURE__ */ jsx("path", { d: "M9 18V5l12-2v13" }),
5131
+ /* @__PURE__ */ jsx("circle", { cx: "6", cy: "18", r: "3" }),
5132
+ /* @__PURE__ */ jsx("circle", { cx: "18", cy: "16", r: "3" })
5133
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
5134
+ /* @__PURE__ */ jsx("path", { d: "m16 13 5.223 3.482a.5.5 0 0 0 .777-.416V7.934a.5.5 0 0 0-.777-.416L16 11" }),
5135
+ /* @__PURE__ */ jsx("rect", { width: "14", height: "12", x: "2", y: "6", rx: "2" })
5136
+ ] })
5137
+ }
5138
+ )
5139
+ }
5140
+ ),
5141
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
5142
+ /* @__PURE__ */ jsx("p", { className: "text-[11px] font-medium truncate leading-tight", children: filename }),
5143
+ /* @__PURE__ */ jsx(
5144
+ "p",
5145
+ {
5146
+ className: "text-[9px] font-semibold uppercase tracking-wider leading-tight mt-0.5",
5147
+ style: { color: accent.color },
5148
+ children: label
5149
+ }
5150
+ )
5151
+ ] }),
5152
+ href && /* @__PURE__ */ jsx(
5153
+ "div",
5154
+ {
5155
+ className: "size-6 rounded-md flex items-center justify-center shrink-0",
5156
+ style: { backgroundColor: "rgba(0,0,0,0.05)" },
5157
+ children: /* @__PURE__ */ jsxs(
5158
+ "svg",
5159
+ {
5160
+ className: "size-3",
5161
+ viewBox: "0 0 24 24",
5162
+ fill: "none",
5163
+ stroke: "currentColor",
5164
+ strokeWidth: 2.5,
5165
+ strokeLinecap: "round",
5166
+ strokeLinejoin: "round",
5167
+ style: { opacity: 0.35 },
5168
+ children: [
5169
+ /* @__PURE__ */ jsx("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }),
5170
+ /* @__PURE__ */ jsx("polyline", { points: "7 10 12 15 17 10" }),
5171
+ /* @__PURE__ */ jsx("line", { x1: "12", x2: "12", y1: "15", y2: "3" })
5172
+ ]
5173
+ }
5174
+ )
5175
+ }
5176
+ )
5177
+ ]
5178
+ }
5179
+ );
5180
+ }
5181
+ function ImageGrid({
5182
+ images,
5183
+ bubbleRadius
5184
+ }) {
5185
+ const srcs = images.map((img) => getAttachmentSrc(img)).filter(Boolean);
5186
+ if (srcs.length === 0) return null;
5187
+ const innerRadius = bubbleRadius ? `calc(${bubbleRadius} - 2px)` : "0.875rem";
5188
+ if (srcs.length === 1) {
5189
+ return /* @__PURE__ */ jsx(
5190
+ "div",
5191
+ {
5192
+ className: "csdk-attachment-grid",
5193
+ style: { borderRadius: innerRadius, overflow: "hidden" },
5194
+ children: /* @__PURE__ */ jsx(
5195
+ ImageThumb,
5196
+ {
5197
+ src: srcs[0],
5198
+ alt: images[0].filename || "Image",
5199
+ className: "w-full"
5200
+ }
5201
+ )
5202
+ }
5203
+ );
5204
+ }
5205
+ if (srcs.length === 2) {
5206
+ return /* @__PURE__ */ jsx(
4937
5207
  "div",
4938
5208
  {
4939
- className: "csdk-image-backdrop fixed inset-0 z-50 flex items-center justify-center bg-black/80",
4940
- onClick: () => setExpanded(false),
4941
- children: /* @__PURE__ */ jsxs("div", { className: "relative max-w-[90vw] max-h-[90vh]", children: [
5209
+ className: "csdk-attachment-grid grid grid-cols-2 gap-[2px]",
5210
+ style: { borderRadius: innerRadius, overflow: "hidden" },
5211
+ children: srcs.map((src, i) => /* @__PURE__ */ jsx(
5212
+ ImageThumb,
5213
+ {
5214
+ src,
5215
+ alt: images[i].filename || "Image",
5216
+ className: "aspect-square"
5217
+ },
5218
+ i
5219
+ ))
5220
+ }
5221
+ );
5222
+ }
5223
+ if (srcs.length === 3) {
5224
+ return /* @__PURE__ */ jsxs(
5225
+ "div",
5226
+ {
5227
+ className: "csdk-attachment-grid grid grid-cols-2 gap-[2px]",
5228
+ style: { borderRadius: innerRadius, overflow: "hidden" },
5229
+ children: [
4942
5230
  /* @__PURE__ */ jsx(
4943
- "img",
5231
+ ImageThumb,
4944
5232
  {
4945
- src,
4946
- alt: attachment.filename || "Image (expanded)",
4947
- className: "max-w-full max-h-full object-contain rounded-lg"
5233
+ src: srcs[0],
5234
+ alt: images[0].filename || "Image",
5235
+ className: "col-span-2 max-h-[180px] min-h-[100px]"
4948
5236
  }
4949
5237
  ),
4950
5238
  /* @__PURE__ */ jsx(
4951
- "button",
5239
+ ImageThumb,
4952
5240
  {
4953
- type: "button",
4954
- className: "csdk-image-close absolute top-2 right-2 bg-white/90 rounded-full p-2 hover:bg-white transition-colors",
4955
- onClick: (e) => {
4956
- e.stopPropagation();
4957
- setExpanded(false);
4958
- },
4959
- children: /* @__PURE__ */ jsx(
4960
- "svg",
4961
- {
4962
- className: "w-4 h-4",
4963
- fill: "none",
4964
- viewBox: "0 0 24 24",
4965
- stroke: "currentColor",
4966
- strokeWidth: 2,
4967
- children: /* @__PURE__ */ jsx(
4968
- "path",
4969
- {
4970
- strokeLinecap: "round",
4971
- strokeLinejoin: "round",
4972
- d: "M6 18L18 6M6 6l12 12"
4973
- }
4974
- )
4975
- }
4976
- )
5241
+ src: srcs[1],
5242
+ alt: images[1].filename || "Image",
5243
+ className: "aspect-square"
5244
+ }
5245
+ ),
5246
+ /* @__PURE__ */ jsx(
5247
+ ImageThumb,
5248
+ {
5249
+ src: srcs[2],
5250
+ alt: images[2].filename || "Image",
5251
+ className: "aspect-square"
4977
5252
  }
4978
5253
  )
4979
- ] })
5254
+ ]
5255
+ }
5256
+ );
5257
+ }
5258
+ const showOverlay = srcs.length > 4;
5259
+ const gridSrcs = srcs.slice(0, 4);
5260
+ return /* @__PURE__ */ jsx(
5261
+ "div",
5262
+ {
5263
+ className: "csdk-attachment-grid grid grid-cols-2 gap-[2px]",
5264
+ style: { borderRadius: innerRadius, overflow: "hidden" },
5265
+ children: gridSrcs.map((src, i) => /* @__PURE__ */ jsxs("div", { className: "relative aspect-square", children: [
5266
+ /* @__PURE__ */ jsx(
5267
+ ImageThumb,
5268
+ {
5269
+ src,
5270
+ alt: images[i].filename || "Image",
5271
+ className: "w-full h-full"
5272
+ }
5273
+ ),
5274
+ i === 3 && showOverlay && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-black/50 flex items-center justify-center pointer-events-none", children: /* @__PURE__ */ jsxs("span", { className: "text-white text-lg font-semibold", children: [
5275
+ "+",
5276
+ srcs.length - 4
5277
+ ] }) })
5278
+ ] }, i))
5279
+ }
5280
+ );
5281
+ }
5282
+ function isPdf(a) {
5283
+ return a.mimeType === "application/pdf" || a.filename?.toLowerCase().endsWith(".pdf") === true;
5284
+ }
5285
+ function MessageMedia({
5286
+ attachments,
5287
+ hasText,
5288
+ align = "end"
5289
+ }) {
5290
+ const images = attachments.filter((a) => a.type === "image");
5291
+ const pdfs = attachments.filter((a) => isPdf(a));
5292
+ const files = attachments.filter((a) => a.type !== "image" && !isPdf(a));
5293
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
5294
+ images.length > 0 && /* @__PURE__ */ jsx("div", { className: cn("csdk-attachment-images", hasText ? "mb-0" : ""), children: /* @__PURE__ */ jsx(ImageGrid, { images, bubbleRadius: "0.5rem" }) }),
5295
+ (pdfs.length > 0 || files.length > 0) && /* @__PURE__ */ jsx(
5296
+ "div",
5297
+ {
5298
+ className: cn(
5299
+ "csdk-attachment-files flex flex-col gap-1",
5300
+ hasText || images.length > 0 ? "px-1.5 pb-1.5 pt-1" : "p-1.5"
5301
+ ),
5302
+ children: [...pdfs, ...files].map((file, i) => /* @__PURE__ */ jsx(FileCard, { attachment: file }, i))
4980
5303
  }
4981
5304
  )
4982
5305
  ] });
@@ -5571,7 +5894,8 @@ function ChatComponent({
5571
5894
  allowedFileTypes = DEFAULT_ALLOWED_TYPES2,
5572
5895
  attachmentsEnabled = true,
5573
5896
  attachmentsDisabledTooltip = "Attachments not supported by this model",
5574
- processAttachment: processAttachmentProp,
5897
+ upload: uploadProp,
5898
+ processAttachment: deprecatedProcessAttachment,
5575
5899
  // Suggestions
5576
5900
  suggestions = [],
5577
5901
  onSuggestionClick,
@@ -5670,8 +5994,34 @@ function ChatComponent({
5670
5994
  ]);
5671
5995
  try {
5672
5996
  let attachment;
5673
- if (processAttachmentProp) {
5674
- attachment = await processAttachmentProp(file);
5997
+ const uploader = uploadProp ?? deprecatedProcessAttachment;
5998
+ if (typeof uploader === "function") {
5999
+ attachment = await uploader(file);
6000
+ } else if (uploader) {
6001
+ const config = typeof uploader === "string" ? { url: uploader } : uploader;
6002
+ const extraHeaders = typeof config.headers === "function" ? config.headers() : config.headers;
6003
+ const extraBody = typeof config.body === "function" ? config.body() : config.body;
6004
+ const data = await fileToBase642(file);
6005
+ const res = await fetch(config.url, {
6006
+ method: "POST",
6007
+ headers: { "Content-Type": "application/json", ...extraHeaders },
6008
+ body: JSON.stringify({
6009
+ data,
6010
+ mimeType: file.type,
6011
+ filename: file.name,
6012
+ ...extraBody
6013
+ })
6014
+ });
6015
+ if (!res.ok) throw new Error(`Upload failed: ${res.status}`);
6016
+ const result = await res.json();
6017
+ const url = result.url ?? result.data?.url;
6018
+ if (!url) throw new Error("Upload returned no URL");
6019
+ attachment = {
6020
+ type: getAttachmentType2(file.type),
6021
+ url,
6022
+ mimeType: file.type,
6023
+ filename: file.name
6024
+ };
5675
6025
  } else {
5676
6026
  const data = await fileToBase642(file);
5677
6027
  attachment = {
@@ -5699,7 +6049,13 @@ function ChatComponent({
5699
6049
  }
5700
6050
  }
5701
6051
  },
5702
- [attachmentsEnabled, maxFileSize, isFileTypeAllowed, processAttachmentProp]
6052
+ [
6053
+ attachmentsEnabled,
6054
+ maxFileSize,
6055
+ isFileTypeAllowed,
6056
+ uploadProp,
6057
+ deprecatedProcessAttachment
6058
+ ]
5703
6059
  );
5704
6060
  const handleInputChange = useCallback(
5705
6061
  (e) => {
@@ -5877,7 +6233,7 @@ function ChatComponent({
5877
6233
  attachmentsDisabledTooltip,
5878
6234
  maxFileSize,
5879
6235
  allowedFileTypes,
5880
- processAttachment: processAttachmentProp
6236
+ processAttachment: typeof uploadProp === "function" ? uploadProp : deprecatedProcessAttachment
5881
6237
  }
5882
6238
  )
5883
6239
  ) : null,
@@ -6345,7 +6701,8 @@ function useInternalThreadManager(config = {}) {
6345
6701
  status,
6346
6702
  isLoading,
6347
6703
  getAllMessages,
6348
- switchBranch
6704
+ switchBranch,
6705
+ threadId: sdkThreadId
6349
6706
  } = useCopilot();
6350
6707
  const isLoadingMessagesRef = useRef(false);
6351
6708
  const savingToThreadRef = useRef(null);
@@ -6495,8 +6852,16 @@ function useInternalThreadManager(config = {}) {
6495
6852
  );
6496
6853
  const activeLeafId = messages[messages.length - 1]?.id;
6497
6854
  if (!currentThreadId && !savingToThreadRef.current) {
6855
+ if (!sdkThreadId && status === "ready" && messages.length <= 2) {
6856
+ return;
6857
+ }
6498
6858
  savingToThreadRef.current = "creating";
6499
- createThread({ messages: coreMessages, activeLeafId }).then((thread) => {
6859
+ hasInitializedRef.current = true;
6860
+ createThread({
6861
+ id: sdkThreadId ?? void 0,
6862
+ messages: coreMessages,
6863
+ activeLeafId
6864
+ }).then((thread) => {
6500
6865
  lastSavedSnapshotRef.current = currentSnapshot;
6501
6866
  savingToThreadRef.current = thread.id;
6502
6867
  onThreadChange?.(thread.id);
@@ -6890,6 +7255,515 @@ function PoweredBy({ className, showLogo = true }) {
6890
7255
  }
6891
7256
  );
6892
7257
  }
7258
+ var DEFAULT_MAX_FILES = 5;
7259
+ var DEFAULT_MAX_FILE_SIZE3 = 10 * 1024 * 1024;
7260
+ var DEFAULT_ALLOWED_TYPES3 = [
7261
+ "image/*",
7262
+ "application/pdf",
7263
+ "text/csv",
7264
+ "text/plain",
7265
+ "text/markdown",
7266
+ "application/json",
7267
+ ".csv",
7268
+ ".txt",
7269
+ ".md",
7270
+ ".json"
7271
+ ];
7272
+ var TEXT_MIME_TYPES = /* @__PURE__ */ new Set([
7273
+ "text/csv",
7274
+ "text/plain",
7275
+ "text/markdown",
7276
+ "text/x-markdown",
7277
+ "application/json",
7278
+ "application/csv"
7279
+ ]);
7280
+ function isTextFile(file) {
7281
+ if (TEXT_MIME_TYPES.has(file.type)) return true;
7282
+ const ext = file.name.toLowerCase().split(".").pop();
7283
+ return ext === "csv" || ext === "txt" || ext === "md" || ext === "json";
7284
+ }
7285
+ function readFileAsText(file) {
7286
+ return new Promise((resolve, reject) => {
7287
+ const reader = new FileReader();
7288
+ reader.onload = () => resolve(reader.result);
7289
+ reader.onerror = () => reject(new Error("Failed to read file"));
7290
+ reader.readAsText(file);
7291
+ });
7292
+ }
7293
+ function generateId() {
7294
+ return `att_${Date.now()}_${Math.random().toString(36).slice(2, 7)}`;
7295
+ }
7296
+ function getAttachmentType3(mimeType) {
7297
+ if (mimeType.startsWith("image/")) return "image";
7298
+ if (mimeType.startsWith("audio/")) return "audio";
7299
+ if (mimeType.startsWith("video/")) return "video";
7300
+ return "file";
7301
+ }
7302
+ function isTypeAllowed(file, allowedTypes) {
7303
+ for (const type of allowedTypes) {
7304
+ if (type === file.type) return true;
7305
+ if (type.endsWith("/*") && file.type.startsWith(type.slice(0, -1)))
7306
+ return true;
7307
+ if (type.startsWith(".") && file.name.toLowerCase().endsWith(type))
7308
+ return true;
7309
+ }
7310
+ return false;
7311
+ }
7312
+ function fileToBase643(file) {
7313
+ return new Promise((resolve, reject) => {
7314
+ const reader = new FileReader();
7315
+ reader.onload = () => resolve(reader.result);
7316
+ reader.onerror = () => reject(new Error("Failed to read file"));
7317
+ reader.readAsDataURL(file);
7318
+ });
7319
+ }
7320
+ function createPreview(file) {
7321
+ if (file.type.startsWith("image/")) {
7322
+ return URL.createObjectURL(file);
7323
+ }
7324
+ return void 0;
7325
+ }
7326
+ function useAttachments(config = {}) {
7327
+ const {
7328
+ upload,
7329
+ maxFiles = DEFAULT_MAX_FILES,
7330
+ maxFileSize = DEFAULT_MAX_FILE_SIZE3,
7331
+ allowedFileTypes = DEFAULT_ALLOWED_TYPES3
7332
+ } = config;
7333
+ const [attachments, setAttachments] = useState([]);
7334
+ const [isDragging, setIsDragging] = useState(false);
7335
+ const abortControllers = useRef(/* @__PURE__ */ new Map());
7336
+ const fileInputRef = useRef(null);
7337
+ const dragCounter = useRef(0);
7338
+ const uploadFile = useCallback(
7339
+ async (id, file) => {
7340
+ const updateProgress = (progress) => {
7341
+ setAttachments(
7342
+ (prev) => prev.map((a) => a.id === id ? { ...a, progress } : a)
7343
+ );
7344
+ };
7345
+ const markReady = (attachment) => {
7346
+ setAttachments(
7347
+ (prev) => prev.map(
7348
+ (a) => a.id === id ? { ...a, status: "ready", progress: 100, attachment } : a
7349
+ )
7350
+ );
7351
+ };
7352
+ const markError = (error) => {
7353
+ setAttachments(
7354
+ (prev) => prev.map(
7355
+ (a) => a.id === id ? { ...a, status: "error", error } : a
7356
+ )
7357
+ );
7358
+ };
7359
+ try {
7360
+ const controller = new AbortController();
7361
+ abortControllers.current.set(id, controller);
7362
+ let result;
7363
+ if (isTextFile(file)) {
7364
+ updateProgress(50);
7365
+ const textContent = await readFileAsText(file);
7366
+ result = {
7367
+ type: "file",
7368
+ data: textContent,
7369
+ mimeType: file.type || "text/plain",
7370
+ filename: file.name
7371
+ };
7372
+ markReady(result);
7373
+ return;
7374
+ }
7375
+ if (typeof upload === "function") {
7376
+ updateProgress(50);
7377
+ result = await upload(file);
7378
+ } else if (upload) {
7379
+ const uploadConfig = typeof upload === "string" ? { url: upload } : upload;
7380
+ const extraHeaders = typeof uploadConfig.headers === "function" ? uploadConfig.headers() : uploadConfig.headers;
7381
+ const extraBody = typeof uploadConfig.body === "function" ? uploadConfig.body() : uploadConfig.body;
7382
+ const base64 = await fileToBase643(file);
7383
+ updateProgress(30);
7384
+ const body = JSON.stringify({
7385
+ data: base64,
7386
+ mimeType: file.type,
7387
+ filename: file.name,
7388
+ ...extraBody
7389
+ });
7390
+ const res = await fetch(uploadConfig.url, {
7391
+ method: "POST",
7392
+ headers: { "Content-Type": "application/json", ...extraHeaders },
7393
+ body,
7394
+ signal: controller.signal
7395
+ });
7396
+ updateProgress(90);
7397
+ if (!res.ok) throw new Error(`Upload failed: ${res.status}`);
7398
+ const json = await res.json();
7399
+ const url = json.url ?? json.data?.url;
7400
+ if (!url) throw new Error("Upload returned no URL");
7401
+ result = {
7402
+ type: getAttachmentType3(file.type),
7403
+ url,
7404
+ mimeType: file.type,
7405
+ filename: file.name
7406
+ };
7407
+ } else {
7408
+ updateProgress(50);
7409
+ const data = await fileToBase643(file);
7410
+ result = {
7411
+ type: getAttachmentType3(file.type),
7412
+ data,
7413
+ mimeType: file.type,
7414
+ filename: file.name
7415
+ };
7416
+ }
7417
+ markReady(result);
7418
+ } catch (err) {
7419
+ if (err?.name === "AbortError") return;
7420
+ markError(err?.message ?? "Upload failed");
7421
+ } finally {
7422
+ abortControllers.current.delete(id);
7423
+ }
7424
+ },
7425
+ [upload]
7426
+ );
7427
+ const addFiles = useCallback(
7428
+ (files) => {
7429
+ const fileArray = Array.from(files);
7430
+ const remaining = maxFiles - attachments.length;
7431
+ if (remaining <= 0) return;
7432
+ const toAdd = fileArray.slice(0, remaining);
7433
+ const newAttachments = [];
7434
+ for (const file of toAdd) {
7435
+ if (!isTypeAllowed(file, allowedFileTypes)) continue;
7436
+ if (file.size > maxFileSize) continue;
7437
+ const id = generateId();
7438
+ const preview = createPreview(file);
7439
+ newAttachments.push({
7440
+ id,
7441
+ file,
7442
+ preview,
7443
+ status: "uploading",
7444
+ progress: 0
7445
+ });
7446
+ }
7447
+ if (newAttachments.length === 0) return;
7448
+ setAttachments((prev) => [...prev, ...newAttachments]);
7449
+ for (const att of newAttachments) {
7450
+ uploadFile(att.id, att.file);
7451
+ }
7452
+ },
7453
+ [attachments.length, maxFiles, maxFileSize, allowedFileTypes, uploadFile]
7454
+ );
7455
+ const removeAttachment = useCallback((id) => {
7456
+ setAttachments((prev) => {
7457
+ const att = prev.find((a) => a.id === id);
7458
+ if (att?.preview) URL.revokeObjectURL(att.preview);
7459
+ return prev.filter((a) => a.id !== id);
7460
+ });
7461
+ const controller = abortControllers.current.get(id);
7462
+ if (controller) {
7463
+ controller.abort();
7464
+ abortControllers.current.delete(id);
7465
+ }
7466
+ }, []);
7467
+ const cancelUpload = useCallback(
7468
+ (id) => {
7469
+ removeAttachment(id);
7470
+ },
7471
+ [removeAttachment]
7472
+ );
7473
+ const retryUpload = useCallback(
7474
+ (id) => {
7475
+ setAttachments(
7476
+ (prev) => prev.map(
7477
+ (a) => a.id === id ? {
7478
+ ...a,
7479
+ status: "uploading",
7480
+ progress: 0,
7481
+ error: void 0
7482
+ } : a
7483
+ )
7484
+ );
7485
+ const att = attachments.find((a) => a.id === id);
7486
+ if (att) uploadFile(id, att.file);
7487
+ },
7488
+ [attachments, uploadFile]
7489
+ );
7490
+ const clearAll = useCallback(() => {
7491
+ for (const att of attachments) {
7492
+ if (att.preview) URL.revokeObjectURL(att.preview);
7493
+ }
7494
+ for (const controller of abortControllers.current.values()) {
7495
+ controller.abort();
7496
+ }
7497
+ abortControllers.current.clear();
7498
+ setAttachments([]);
7499
+ }, [attachments]);
7500
+ const getReadyAttachments = useCallback(() => {
7501
+ return attachments.filter((a) => a.status === "ready" && a.attachment).map((a) => a.attachment);
7502
+ }, [attachments]);
7503
+ const hasAttachments = attachments.length > 0;
7504
+ const isUploading = attachments.some((a) => a.status === "uploading");
7505
+ const canSend = hasAttachments && attachments.some((a) => a.status === "ready") && !isUploading;
7506
+ const dragHandlers = useMemo(
7507
+ () => ({
7508
+ onDragEnter: (e) => {
7509
+ e.preventDefault();
7510
+ e.stopPropagation();
7511
+ dragCounter.current++;
7512
+ if (e.dataTransfer.types.includes("Files")) {
7513
+ setIsDragging(true);
7514
+ }
7515
+ },
7516
+ onDragOver: (e) => {
7517
+ e.preventDefault();
7518
+ e.stopPropagation();
7519
+ },
7520
+ onDragLeave: (e) => {
7521
+ e.preventDefault();
7522
+ e.stopPropagation();
7523
+ dragCounter.current--;
7524
+ if (dragCounter.current === 0) {
7525
+ setIsDragging(false);
7526
+ }
7527
+ },
7528
+ onDrop: (e) => {
7529
+ e.preventDefault();
7530
+ e.stopPropagation();
7531
+ dragCounter.current = 0;
7532
+ setIsDragging(false);
7533
+ if (e.dataTransfer.files?.length) {
7534
+ addFiles(e.dataTransfer.files);
7535
+ }
7536
+ }
7537
+ }),
7538
+ [addFiles]
7539
+ );
7540
+ const openFilePicker = useCallback(() => {
7541
+ fileInputRef.current?.click();
7542
+ }, []);
7543
+ const onFileInputChange = useCallback(
7544
+ (e) => {
7545
+ if (e.target.files?.length) {
7546
+ addFiles(e.target.files);
7547
+ }
7548
+ if (fileInputRef.current) fileInputRef.current.value = "";
7549
+ },
7550
+ [addFiles]
7551
+ );
7552
+ return {
7553
+ attachments,
7554
+ isDragging,
7555
+ addFiles,
7556
+ removeAttachment,
7557
+ cancelUpload,
7558
+ retryUpload,
7559
+ clearAll,
7560
+ getReadyAttachments,
7561
+ hasAttachments,
7562
+ isUploading,
7563
+ canSend,
7564
+ dragHandlers,
7565
+ openFilePicker,
7566
+ fileInputRef,
7567
+ onFileInputChange
7568
+ };
7569
+ }
7570
+ var svgProps = {
7571
+ xmlns: "http://www.w3.org/2000/svg",
7572
+ viewBox: "0 0 24 24",
7573
+ fill: "none",
7574
+ stroke: "currentColor",
7575
+ strokeWidth: 2,
7576
+ strokeLinecap: "round",
7577
+ strokeLinejoin: "round"
7578
+ };
7579
+ function ImageIcon({ className }) {
7580
+ return /* @__PURE__ */ jsxs("svg", { ...svgProps, className, children: [
7581
+ /* @__PURE__ */ jsx("rect", { width: "18", height: "18", x: "3", y: "3", rx: "2", ry: "2" }),
7582
+ /* @__PURE__ */ jsx("circle", { cx: "9", cy: "9", r: "2" }),
7583
+ /* @__PURE__ */ jsx("path", { d: "m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21" })
7584
+ ] });
7585
+ }
7586
+ function FileTextIcon({ className }) {
7587
+ return /* @__PURE__ */ jsxs("svg", { ...svgProps, className, children: [
7588
+ /* @__PURE__ */ jsx("path", { d: "M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z" }),
7589
+ /* @__PURE__ */ jsx("path", { d: "M14 2v4a2 2 0 0 0 2 2h4" }),
7590
+ /* @__PURE__ */ jsx("path", { d: "M10 9H8" }),
7591
+ /* @__PURE__ */ jsx("path", { d: "M16 13H8" }),
7592
+ /* @__PURE__ */ jsx("path", { d: "M16 17H8" })
7593
+ ] });
7594
+ }
7595
+ function MusicIcon({ className }) {
7596
+ return /* @__PURE__ */ jsxs("svg", { ...svgProps, className, children: [
7597
+ /* @__PURE__ */ jsx("path", { d: "M9 18V5l12-2v13" }),
7598
+ /* @__PURE__ */ jsx("circle", { cx: "6", cy: "18", r: "3" }),
7599
+ /* @__PURE__ */ jsx("circle", { cx: "18", cy: "16", r: "3" })
7600
+ ] });
7601
+ }
7602
+ function VideoIcon({ className }) {
7603
+ return /* @__PURE__ */ jsxs("svg", { ...svgProps, className, children: [
7604
+ /* @__PURE__ */ jsx("path", { d: "m16 13 5.223 3.482a.5.5 0 0 0 .777-.416V7.934a.5.5 0 0 0-.777-.416L16 11" }),
7605
+ /* @__PURE__ */ jsx("rect", { width: "14", height: "12", x: "2", y: "6", rx: "2" })
7606
+ ] });
7607
+ }
7608
+ function XIcon3({ className }) {
7609
+ return /* @__PURE__ */ jsxs("svg", { ...svgProps, className, children: [
7610
+ /* @__PURE__ */ jsx("path", { d: "M18 6 6 18" }),
7611
+ /* @__PURE__ */ jsx("path", { d: "m6 6 12 12" })
7612
+ ] });
7613
+ }
7614
+ function RefreshCwIcon({ className }) {
7615
+ return /* @__PURE__ */ jsxs("svg", { ...svgProps, className, children: [
7616
+ /* @__PURE__ */ jsx("path", { d: "M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8" }),
7617
+ /* @__PURE__ */ jsx("path", { d: "M21 3v5h-5" }),
7618
+ /* @__PURE__ */ jsx("path", { d: "M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16" }),
7619
+ /* @__PURE__ */ jsx("path", { d: "M8 16H3v5" })
7620
+ ] });
7621
+ }
7622
+ function Loader2Icon({ className }) {
7623
+ return /* @__PURE__ */ jsx("svg", { ...svgProps, className, children: /* @__PURE__ */ jsx("path", { d: "M21 12a9 9 0 1 1-6.219-8.56" }) });
7624
+ }
7625
+ function CheckIcon4({ className }) {
7626
+ return /* @__PURE__ */ jsx("svg", { ...svgProps, className, children: /* @__PURE__ */ jsx("path", { d: "M20 6 9 17l-5-5" }) });
7627
+ }
7628
+ function FileTypeIcon({ mimeType }) {
7629
+ const cls = "size-3.5";
7630
+ if (mimeType.startsWith("image/")) return /* @__PURE__ */ jsx(ImageIcon, { className: cls });
7631
+ if (mimeType.startsWith("audio/")) return /* @__PURE__ */ jsx(MusicIcon, { className: cls });
7632
+ if (mimeType.startsWith("video/")) return /* @__PURE__ */ jsx(VideoIcon, { className: cls });
7633
+ return /* @__PURE__ */ jsx(FileTextIcon, { className: cls });
7634
+ }
7635
+ function StatusBadge2({ status }) {
7636
+ if (status === "uploading") {
7637
+ return /* @__PURE__ */ jsx(Loader2Icon, { className: "size-3 animate-spin text-blue-400" });
7638
+ }
7639
+ if (status === "ready") {
7640
+ return /* @__PURE__ */ jsx(CheckIcon4, { className: "size-3 text-emerald-400" });
7641
+ }
7642
+ return null;
7643
+ }
7644
+ function AttachmentCard({
7645
+ attachment,
7646
+ onRemove,
7647
+ onRetry
7648
+ }) {
7649
+ const { id, file, preview, status, progress, error } = attachment;
7650
+ const isError = status === "error";
7651
+ return /* @__PURE__ */ jsxs(
7652
+ "div",
7653
+ {
7654
+ className: `
7655
+ csdk-attachment-card group relative flex items-center gap-1.5
7656
+ rounded-lg border px-2 py-1.5 min-w-0 max-w-[160px]
7657
+ transition-colors duration-150
7658
+ ${isError ? "border-red-500/30 bg-red-500/5" : "border-border/60 bg-muted/40 hover:bg-muted/60"}
7659
+ `,
7660
+ children: [
7661
+ /* @__PURE__ */ jsx("div", { className: "size-7 rounded shrink-0 overflow-hidden bg-muted/60 flex items-center justify-center", children: preview ? /* @__PURE__ */ jsx(
7662
+ "img",
7663
+ {
7664
+ src: preview,
7665
+ alt: file.name,
7666
+ className: "size-full object-cover"
7667
+ }
7668
+ ) : /* @__PURE__ */ jsx(FileTypeIcon, { mimeType: file.type }) }),
7669
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
7670
+ /* @__PURE__ */ jsx("p", { className: "text-[10px] font-medium truncate leading-tight text-foreground/80", children: file.name }),
7671
+ /* @__PURE__ */ jsx("div", { className: "flex items-center gap-1 mt-0.5", children: isError ? /* @__PURE__ */ jsxs(
7672
+ "button",
7673
+ {
7674
+ onClick: () => onRetry(id),
7675
+ className: "flex items-center gap-0.5 text-[9px] text-red-400 hover:text-red-300 cursor-pointer",
7676
+ children: [
7677
+ /* @__PURE__ */ jsx(RefreshCwIcon, { className: "size-2.5" }),
7678
+ "Retry"
7679
+ ]
7680
+ }
7681
+ ) : /* @__PURE__ */ jsxs(Fragment, { children: [
7682
+ /* @__PURE__ */ jsx(StatusBadge2, { status }),
7683
+ /* @__PURE__ */ jsx("span", { className: "text-[9px] text-muted-foreground", children: status === "uploading" ? `${progress}%` : formatBytes(file.size) })
7684
+ ] }) })
7685
+ ] }),
7686
+ status === "uploading" && /* @__PURE__ */ jsx("div", { className: "absolute bottom-0 left-0 right-0 h-[2px] rounded-b-lg overflow-hidden bg-muted/40", children: /* @__PURE__ */ jsx(
7687
+ "div",
7688
+ {
7689
+ className: "h-full bg-blue-500 transition-[width] duration-300 ease-out",
7690
+ style: { width: `${progress}%` }
7691
+ }
7692
+ ) }),
7693
+ /* @__PURE__ */ jsx(
7694
+ "button",
7695
+ {
7696
+ onClick: () => onRemove(id),
7697
+ className: "\n size-4 rounded-full shrink-0 flex items-center justify-center\n text-muted-foreground/50 hover:text-foreground hover:bg-muted\n transition-colors cursor-pointer\n ",
7698
+ "aria-label": "Remove attachment",
7699
+ children: /* @__PURE__ */ jsx(XIcon3, { className: "size-2.5" })
7700
+ }
7701
+ )
7702
+ ]
7703
+ }
7704
+ );
7705
+ }
7706
+ function formatBytes(bytes) {
7707
+ if (bytes < 1024) return `${bytes}B`;
7708
+ if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(0)}KB`;
7709
+ return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
7710
+ }
7711
+ function AttachmentStrip({
7712
+ attachments,
7713
+ onRemove,
7714
+ onRetry,
7715
+ className = ""
7716
+ }) {
7717
+ if (attachments.length === 0) return null;
7718
+ return /* @__PURE__ */ jsx(
7719
+ "div",
7720
+ {
7721
+ className: `csdk-attachment-strip flex gap-1.5 overflow-x-auto px-1 py-1.5 scrollbar-none ${className}`,
7722
+ children: attachments.map((att) => /* @__PURE__ */ jsx(
7723
+ AttachmentCard,
7724
+ {
7725
+ attachment: att,
7726
+ onRemove,
7727
+ onRetry
7728
+ },
7729
+ att.id
7730
+ ))
7731
+ }
7732
+ );
7733
+ }
7734
+ var svgProps2 = {
7735
+ xmlns: "http://www.w3.org/2000/svg",
7736
+ viewBox: "0 0 24 24",
7737
+ fill: "none",
7738
+ stroke: "currentColor",
7739
+ strokeWidth: 2,
7740
+ strokeLinecap: "round",
7741
+ strokeLinejoin: "round"
7742
+ };
7743
+ function PaperclipIcon({ className }) {
7744
+ return /* @__PURE__ */ jsx("svg", { ...svgProps2, className, children: /* @__PURE__ */ jsx("path", { d: "m21.44 11.05-9.19 9.19a6 6 0 0 1-8.49-8.49l8.57-8.57A4 4 0 1 1 18 8.84l-8.59 8.57a2 2 0 0 1-2.83-2.83l8.49-8.48" }) });
7745
+ }
7746
+ function DropZoneOverlay({
7747
+ isDragging,
7748
+ className = ""
7749
+ }) {
7750
+ if (!isDragging) return null;
7751
+ return /* @__PURE__ */ jsx(
7752
+ "div",
7753
+ {
7754
+ className: `
7755
+ csdk-drop-zone absolute inset-0 z-50 flex items-center justify-center
7756
+ bg-background/80 backdrop-blur-sm border-2 border-dashed border-primary/40
7757
+ rounded-xl pointer-events-none
7758
+ ${className}
7759
+ `,
7760
+ children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-2 text-primary/70", children: [
7761
+ /* @__PURE__ */ jsx("div", { className: "size-10 rounded-xl bg-primary/10 flex items-center justify-center", children: /* @__PURE__ */ jsx(PaperclipIcon, { className: "size-5" }) }),
7762
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-medium", children: "Drop files to attach" })
7763
+ ] })
7764
+ }
7765
+ );
7766
+ }
6893
7767
 
6894
7768
  // src/ui/index.ts
6895
7769
  var ChatPrimitives = {
@@ -6923,6 +7797,6 @@ var ChatPrimitives = {
6923
7797
  Loader
6924
7798
  };
6925
7799
 
6926
- export { AlertTriangleIcon, BotIcon, BranchNavigator, Button, CapabilityBadge, CapabilityList, Chat, ChatContainerContent, ChatContainerRoot, ChatContainerScrollAnchor, ChatPrimitives, ChatWelcome, CheckIcon, ChevronDownIcon2 as ChevronDownIcon, ChevronLeftIcon, ChevronUpIcon, CitationBadge, CitationSuperscript, CloseIcon, CodeBlock, CompactPermissionConfirmation, Confirmation, ConfirmationActions, ConfirmationApproved, ConfirmationMessage, ConfirmationPending, ConfirmationRejected, ConnectedChat, CopilotChat, CopilotUIProvider, CopyIcon, DEFAULT_PERMISSION_OPTIONS, DevLogger, FeedbackBar, FollowUpQuestions, InlineToolSteps, MCPUIFrame, MCPUIFrameList, Markdown, MessageAvatar, MessageContent, Message as MessagePrimitive, MessageWithCitations, ModelSelector, PermissionConfirmation, PoweredBy, PromptInput, PromptInputAction, PromptInputActions, PromptInputTextarea, Reasoning, ReasoningContent, ReasoningTrigger, RefreshIcon, ScrollButton, SearchAnswer, SearchResults, SearchResultsWithAnswer, SendIcon, SimpleConfirmation, SimpleModelSelector, SimpleReasoning, SimpleSource, Source, SourceContent, SourceGroup, SourcePill, SourceTrigger, SourcesBar, SourcesCollapsible, SourcesList, StopIcon, ThreadCard, ThreadList, ThreadPicker, ThumbsDownIcon2 as ThumbsDownIcon, ThumbsUpIcon2 as ThumbsUpIcon, ToolExecutionMessage, ToolStep, ToolSteps, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, UserIcon, XIcon2 as XIcon, annotationsToCitations, parseFollowUps, resultsToCitations, useChatContainer, useCopilotChatContext, useCopilotUI };
7800
+ export { AlertTriangleIcon, AttachmentStrip, BotIcon, BranchNavigator, Button, CapabilityBadge, CapabilityList, Chat, ChatContainerContent, ChatContainerRoot, ChatContainerScrollAnchor, ChatPrimitives, ChatWelcome, CheckIcon, ChevronDownIcon2 as ChevronDownIcon, ChevronLeftIcon, ChevronUpIcon, CitationBadge, CitationSuperscript, CloseIcon, CodeBlock, CompactPermissionConfirmation, Confirmation, ConfirmationActions, ConfirmationApproved, ConfirmationMessage, ConfirmationPending, ConfirmationRejected, ConnectedChat, CopilotChat, CopilotUIProvider, CopyIcon, DEFAULT_PERMISSION_OPTIONS, DevLogger, DropZoneOverlay, FeedbackBar, FollowUpQuestions, InlineToolSteps, MCPUIFrame, MCPUIFrameList, Markdown, MessageAvatar, MessageContent, Message as MessagePrimitive, MessageWithCitations, ModelSelector, PermissionConfirmation, PoweredBy, PromptInput, PromptInputAction, PromptInputActions, PromptInputTextarea, Reasoning, ReasoningContent, ReasoningTrigger, RefreshIcon, ScrollButton, SearchAnswer, SearchResults, SearchResultsWithAnswer, SendIcon, SimpleConfirmation, SimpleModelSelector, SimpleReasoning, SimpleSource, Source, SourceContent, SourceGroup, SourcePill, SourceTrigger, SourcesBar, SourcesCollapsible, SourcesList, StopIcon, ThreadCard, ThreadList, ThreadPicker, ThumbsDownIcon2 as ThumbsDownIcon, ThumbsUpIcon2 as ThumbsUpIcon, ToolExecutionMessage, ToolStep, ToolSteps, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, UserIcon, XIcon2 as XIcon, annotationsToCitations, parseFollowUps, resultsToCitations, useAttachments, useChatContainer, useCopilotChatContext, useCopilotUI };
6927
7801
  //# sourceMappingURL=index.js.map
6928
7802
  //# sourceMappingURL=index.js.map