@agents24/chat-react 0.5.4 → 0.5.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.
Files changed (34) hide show
  1. package/README.md +8 -2
  2. package/compatibility.json +4 -4
  3. package/dist/runtime/index.cjs +127 -18
  4. package/dist/runtime/index.cjs.map +1 -1
  5. package/dist/runtime/index.js +125 -18
  6. package/dist/runtime/index.js.map +1 -1
  7. package/dist/runtime/use-agent-chat-runtime.d.ts +17 -2
  8. package/dist/scaffold/app.d.ts +1 -0
  9. package/dist/scaffold/components/chat/chat-composer.d.ts +10 -2
  10. package/dist/scaffold/components/chat/chat-message.d.ts +3 -1
  11. package/dist/scaffold/components/chat/chat-shell.d.ts +3 -1
  12. package/dist/scaffold/index.cjs +415 -253
  13. package/dist/scaffold/index.cjs.map +1 -1
  14. package/dist/scaffold/index.js +408 -240
  15. package/dist/scaffold/index.js.map +1 -1
  16. package/dist/styles.css +18 -4
  17. package/dist/ui/adapters.d.ts +14 -2
  18. package/dist/ui/agent-chat-composer.d.ts +2 -9
  19. package/dist/ui/agent-chat-message.d.ts +3 -1
  20. package/dist/ui/composer-attachments.d.ts +11 -0
  21. package/dist/ui/index.cjs +653 -343
  22. package/dist/ui/index.cjs.map +1 -1
  23. package/dist/ui/index.d.ts +1 -0
  24. package/dist/ui/index.js +638 -328
  25. package/dist/ui/index.js.map +1 -1
  26. package/package.json +4 -3
  27. package/scaffold/src/app.tsx +2 -1
  28. package/scaffold/src/chat.css +13 -1
  29. package/scaffold/src/components/chat/chat-composer.tsx +107 -27
  30. package/scaffold/src/components/chat/chat-message.tsx +8 -9
  31. package/scaffold/src/components/chat/chat-shell.tsx +24 -11
  32. package/scaffold/src/components/ui/button.tsx +1 -1
  33. package/scaffold/src/components/ui/dropdown-menu.tsx +1 -1
  34. package/scaffold/src/components/ui/sidebar.tsx +4 -4
@@ -46,7 +46,7 @@ var import_runtime2 = require("@agents24/chat-react/runtime");
46
46
  var import_lucide_react12 = require("lucide-react");
47
47
 
48
48
  // scaffold/src/components/chat/chat-composer.tsx
49
- var import_lucide_react2 = require("lucide-react");
49
+ var import_lucide_react3 = require("lucide-react");
50
50
  var React2 = __toESM(require("react"), 1);
51
51
  var import_ui = require("@agents24/chat-react/ui");
52
52
  var import_runtime = require("@agents24/chat-react/runtime");
@@ -65,7 +65,7 @@ function cn(...inputs) {
65
65
  // scaffold/src/components/ui/button.tsx
66
66
  var import_jsx_runtime = require("react/jsx-runtime");
67
67
  var buttonVariants = (0, import_class_variance_authority.cva)(
68
- "group/button inline-flex shrink-0 items-center justify-center rounded-4xl border border-transparent bg-clip-padding text-sm font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/30 active:not-aria-[haspopup]:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
68
+ "group/button inline-flex shrink-0 items-center justify-center rounded-4xl border border-transparent bg-clip-padding text-sm font-medium whitespace-nowrap transition-all outline-none select-none active:not-aria-[haspopup]:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
69
69
  {
70
70
  variants: {
71
71
  variant: {
@@ -113,9 +113,9 @@ function Button({
113
113
  );
114
114
  }
115
115
 
116
- // scaffold/src/components/ui/select.tsx
117
- var import_lucide_react = require("lucide-react");
116
+ // scaffold/src/components/ui/dropdown-menu.tsx
118
117
  var import_radix_ui2 = require("radix-ui");
118
+ var import_lucide_react = require("lucide-react");
119
119
 
120
120
  // scaffold/src/components/theme-provider.tsx
121
121
  var React = __toESM(require("react"), 1);
@@ -185,21 +185,196 @@ function useThemePortalContainer() {
185
185
  return useTheme().portalContainer;
186
186
  }
187
187
 
188
- // scaffold/src/components/ui/select.tsx
188
+ // scaffold/src/components/ui/dropdown-menu.tsx
189
189
  var import_jsx_runtime3 = require("react/jsx-runtime");
190
+ function DropdownMenu({
191
+ ...props
192
+ }) {
193
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_radix_ui2.DropdownMenu.Root, { "data-slot": "dropdown-menu", ...props });
194
+ }
195
+ function DropdownMenuTrigger({
196
+ ...props
197
+ }) {
198
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
199
+ import_radix_ui2.DropdownMenu.Trigger,
200
+ {
201
+ "data-slot": "dropdown-menu-trigger",
202
+ ...props
203
+ }
204
+ );
205
+ }
206
+ function DropdownMenuContent({
207
+ className,
208
+ align = "start",
209
+ sideOffset = 4,
210
+ ...props
211
+ }) {
212
+ const themeContainer = useThemePortalContainer();
213
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_radix_ui2.DropdownMenu.Portal, { container: themeContainer || void 0, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
214
+ import_radix_ui2.DropdownMenu.Content,
215
+ {
216
+ "data-slot": "dropdown-menu-content",
217
+ sideOffset,
218
+ align,
219
+ className: cn("z-50 max-h-(--radix-dropdown-menu-content-available-height) w-(--radix-dropdown-menu-trigger-width) min-w-48 origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-3xl bg-popover p-1.5 text-popover-foreground shadow-lg ring-1 ring-foreground/5 duration-100 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=closed]:overflow-hidden dark:ring-foreground/10 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95", className),
220
+ ...props
221
+ }
222
+ ) });
223
+ }
224
+ function DropdownMenuItem({
225
+ className,
226
+ inset,
227
+ variant = "default",
228
+ ...props
229
+ }) {
230
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
231
+ import_radix_ui2.DropdownMenu.Item,
232
+ {
233
+ "data-slot": "dropdown-menu-item",
234
+ "data-inset": inset,
235
+ "data-variant": variant,
236
+ className: cn(
237
+ "group/dropdown-menu-item relative flex cursor-default items-center gap-2.5 rounded-2xl px-3 py-2 text-sm font-medium outline-hidden select-none focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground data-inset:pl-9.5 data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive dark:data-[variant=destructive]:focus:bg-destructive/20 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 data-[variant=destructive]:*:[svg]:text-destructive",
238
+ className
239
+ ),
240
+ ...props
241
+ }
242
+ );
243
+ }
244
+ function DropdownMenuRadioGroup({
245
+ ...props
246
+ }) {
247
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
248
+ import_radix_ui2.DropdownMenu.RadioGroup,
249
+ {
250
+ "data-slot": "dropdown-menu-radio-group",
251
+ ...props
252
+ }
253
+ );
254
+ }
255
+ function DropdownMenuRadioItem({
256
+ className,
257
+ children,
258
+ inset,
259
+ ...props
260
+ }) {
261
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
262
+ import_radix_ui2.DropdownMenu.RadioItem,
263
+ {
264
+ "data-slot": "dropdown-menu-radio-item",
265
+ "data-inset": inset,
266
+ className: cn(
267
+ "relative flex cursor-default items-center gap-2.5 rounded-2xl py-2 pr-8 pl-3 text-sm font-medium outline-hidden select-none focus:bg-accent focus:text-accent-foreground focus:**:text-accent-foreground data-inset:pl-9.5 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
268
+ className
269
+ ),
270
+ ...props,
271
+ children: [
272
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
273
+ "span",
274
+ {
275
+ className: "pointer-events-none absolute right-2 flex items-center justify-center",
276
+ "data-slot": "dropdown-menu-radio-item-indicator",
277
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_radix_ui2.DropdownMenu.ItemIndicator, { children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
278
+ import_lucide_react.CheckIcon,
279
+ {}
280
+ ) })
281
+ }
282
+ ),
283
+ children
284
+ ]
285
+ }
286
+ );
287
+ }
288
+ function DropdownMenuLabel({
289
+ className,
290
+ inset,
291
+ ...props
292
+ }) {
293
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
294
+ import_radix_ui2.DropdownMenu.Label,
295
+ {
296
+ "data-slot": "dropdown-menu-label",
297
+ "data-inset": inset,
298
+ className: cn(
299
+ "px-3 py-2.5 text-xs text-muted-foreground data-inset:pl-9.5",
300
+ className
301
+ ),
302
+ ...props
303
+ }
304
+ );
305
+ }
306
+ function DropdownMenuSeparator({
307
+ className,
308
+ ...props
309
+ }) {
310
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
311
+ import_radix_ui2.DropdownMenu.Separator,
312
+ {
313
+ "data-slot": "dropdown-menu-separator",
314
+ className: cn("-mx-1.5 my-1.5 h-px bg-border/50", className),
315
+ ...props
316
+ }
317
+ );
318
+ }
319
+ function DropdownMenuSub({
320
+ ...props
321
+ }) {
322
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_radix_ui2.DropdownMenu.Sub, { "data-slot": "dropdown-menu-sub", ...props });
323
+ }
324
+ function DropdownMenuSubTrigger({
325
+ className,
326
+ inset,
327
+ children,
328
+ ...props
329
+ }) {
330
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
331
+ import_radix_ui2.DropdownMenu.SubTrigger,
332
+ {
333
+ "data-slot": "dropdown-menu-sub-trigger",
334
+ "data-inset": inset,
335
+ className: cn(
336
+ "flex cursor-default items-center gap-2 rounded-2xl px-3 py-2 text-sm font-medium outline-hidden select-none focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground data-inset:pl-9.5 data-open:bg-accent data-open:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
337
+ className
338
+ ),
339
+ ...props,
340
+ children: [
341
+ children,
342
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_lucide_react.ChevronRightIcon, { className: "ml-auto" })
343
+ ]
344
+ }
345
+ );
346
+ }
347
+ function DropdownMenuSubContent({
348
+ className,
349
+ ...props
350
+ }) {
351
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
352
+ import_radix_ui2.DropdownMenu.SubContent,
353
+ {
354
+ "data-slot": "dropdown-menu-sub-content",
355
+ className: cn("z-50 max-h-(--radix-dropdown-menu-content-available-height) min-w-36 origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-3xl bg-popover p-1.5 text-popover-foreground shadow-lg ring-1 ring-foreground/5 duration-100 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 dark:ring-foreground/10 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95", className),
356
+ ...props
357
+ }
358
+ );
359
+ }
360
+
361
+ // scaffold/src/components/ui/select.tsx
362
+ var import_lucide_react2 = require("lucide-react");
363
+ var import_radix_ui3 = require("radix-ui");
364
+ var import_jsx_runtime4 = require("react/jsx-runtime");
190
365
  function Select(props) {
191
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_radix_ui2.Select.Root, { "data-slot": "select", ...props });
366
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_radix_ui3.Select.Root, { "data-slot": "select", ...props });
192
367
  }
193
368
  function SelectValue(props) {
194
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_radix_ui2.Select.Value, { "data-slot": "select-value", ...props });
369
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_radix_ui3.Select.Value, { "data-slot": "select-value", ...props });
195
370
  }
196
371
  function SelectTrigger({
197
372
  children,
198
373
  className,
199
374
  ...props
200
375
  }) {
201
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
202
- import_radix_ui2.Select.Trigger,
376
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
377
+ import_radix_ui3.Select.Trigger,
203
378
  {
204
379
  className: cn(
205
380
  "flex h-8 w-full items-center justify-between gap-2 rounded-lg bg-transparent px-2.5 text-xs text-foreground outline-none transition-colors hover:bg-muted/50 focus-visible:bg-muted/50 disabled:cursor-not-allowed disabled:opacity-50 data-[placeholder]:text-muted-foreground [&>span]:min-w-0 [&>span]:truncate",
@@ -209,7 +384,7 @@ function SelectTrigger({
209
384
  ...props,
210
385
  children: [
211
386
  children,
212
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_radix_ui2.Select.Icon, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_lucide_react.ChevronDownIcon, { className: "size-3.5 shrink-0 text-muted-foreground" }) })
387
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_radix_ui3.Select.Icon, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react2.ChevronDownIcon, { className: "size-3.5 shrink-0 text-muted-foreground" }) })
213
388
  ]
214
389
  }
215
390
  );
@@ -222,8 +397,8 @@ function SelectContent({
222
397
  ...props
223
398
  }) {
224
399
  const container = useThemePortalContainer();
225
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_radix_ui2.Select.Portal, { container: container || void 0, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
226
- import_radix_ui2.Select.Content,
400
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_radix_ui3.Select.Portal, { container: container || void 0, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
401
+ import_radix_ui3.Select.Content,
227
402
  {
228
403
  align,
229
404
  className: cn(
@@ -234,7 +409,7 @@ function SelectContent({
234
409
  position: "popper",
235
410
  sideOffset,
236
411
  ...props,
237
- children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_radix_ui2.Select.Viewport, { className: "max-h-60 overflow-y-auto p-0.5", children })
412
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_radix_ui3.Select.Viewport, { className: "max-h-60 overflow-y-auto p-0.5", children })
238
413
  }
239
414
  ) });
240
415
  }
@@ -243,8 +418,8 @@ function SelectItem({
243
418
  className,
244
419
  ...props
245
420
  }) {
246
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
247
- import_radix_ui2.Select.Item,
421
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
422
+ import_radix_ui3.Select.Item,
248
423
  {
249
424
  className: cn(
250
425
  "relative flex cursor-default select-none items-center rounded-lg py-1.5 pr-8 pl-2 text-sm outline-none data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
@@ -253,17 +428,17 @@ function SelectItem({
253
428
  "data-slot": "select-item",
254
429
  ...props,
255
430
  children: [
256
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_radix_ui2.Select.ItemText, { className: "min-w-0 truncate", children }),
257
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "absolute right-2 flex size-3.5 items-center justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_radix_ui2.Select.ItemIndicator, { children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_lucide_react.CheckIcon, { className: "size-3.5" }) }) })
431
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_radix_ui3.Select.ItemText, { className: "min-w-0 truncate", children }),
432
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "absolute right-2 flex size-3.5 items-center justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_radix_ui3.Select.ItemIndicator, { children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react2.CheckIcon, { className: "size-3.5" }) }) })
258
433
  ]
259
434
  }
260
435
  );
261
436
  }
262
437
 
263
438
  // scaffold/src/components/ui/textarea.tsx
264
- var import_jsx_runtime4 = require("react/jsx-runtime");
439
+ var import_jsx_runtime5 = require("react/jsx-runtime");
265
440
  function Textarea({ className, ...props }) {
266
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
441
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
267
442
  "textarea",
268
443
  {
269
444
  "data-slot": "textarea",
@@ -277,13 +452,13 @@ function Textarea({ className, ...props }) {
277
452
  }
278
453
 
279
454
  // scaffold/src/components/ui/tooltip.tsx
280
- var import_radix_ui3 = require("radix-ui");
281
- var import_jsx_runtime5 = require("react/jsx-runtime");
455
+ var import_radix_ui4 = require("radix-ui");
456
+ var import_jsx_runtime6 = require("react/jsx-runtime");
282
457
  function TooltipProvider({ children }) {
283
458
  return children;
284
459
  }
285
460
  function Tooltip({ className, ...props }) {
286
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
461
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
287
462
  "span",
288
463
  {
289
464
  "data-slot": "tooltip",
@@ -296,7 +471,7 @@ function TooltipTrigger({
296
471
  asChild: _asChild,
297
472
  ...props
298
473
  }) {
299
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_radix_ui3.Slot.Root, { "data-slot": "tooltip-trigger", ...props });
474
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_radix_ui4.Slot.Root, { "data-slot": "tooltip-trigger", ...props });
300
475
  }
301
476
  function TooltipContent({
302
477
  className,
@@ -305,7 +480,7 @@ function TooltipContent({
305
480
  sideOffset: _sideOffset,
306
481
  ...props
307
482
  }) {
308
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
483
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
309
484
  "span",
310
485
  {
311
486
  role: "tooltip",
@@ -325,17 +500,21 @@ function TooltipContent({
325
500
  }
326
501
 
327
502
  // scaffold/src/components/chat/chat-composer.tsx
328
- var import_jsx_runtime6 = require("react/jsx-runtime");
503
+ var import_jsx_runtime7 = require("react/jsx-runtime");
329
504
  function ChatComposer({
330
505
  inputContract,
331
506
  disabled,
332
507
  contextWindow,
508
+ focusKey,
333
509
  forceExpanded = false,
334
510
  isCancelling = false,
335
511
  isRunning,
512
+ agentId,
513
+ agents,
336
514
  modelId,
337
515
  models,
338
516
  onModelChange,
517
+ onAgentChange,
339
518
  onStop,
340
519
  onSubmit,
341
520
  utilityRow = "inline"
@@ -345,34 +524,73 @@ function ChatComposer({
345
524
  const [attachmentError, setAttachmentError] = React2.useState(null);
346
525
  const inputRef = React2.useRef(null);
347
526
  const textareaRef = React2.useRef(null);
527
+ const filesRef = React2.useRef([]);
528
+ const inFlightFilesRef = React2.useRef([]);
348
529
  const submittingRef = React2.useRef(false);
349
530
  const draftRevisionRef = React2.useRef(0);
350
531
  const attachmentMimeTypes = (0, import_runtime.inputMimeTypes)(inputContract);
351
532
  const allowAttachments = attachmentMimeTypes.length > 0;
352
533
  const recordingAllowed = inputContract.modalities.audio.recording_enabled;
534
+ React2.useEffect(() => {
535
+ filesRef.current = files;
536
+ }, [files]);
537
+ React2.useEffect(() => () => {
538
+ (0, import_ui.revokeAgentChatComposerFiles)(filesRef.current);
539
+ (0, import_ui.revokeAgentChatComposerFiles)(inFlightFilesRef.current);
540
+ }, []);
541
+ React2.useEffect(() => {
542
+ if (disabled || isRunning) return;
543
+ const frame = window.requestAnimationFrame(() => textareaRef.current?.focus({ preventScroll: true }));
544
+ return () => window.cancelAnimationFrame(frame);
545
+ }, [disabled, focusKey, isRunning]);
353
546
  const addRecording = React2.useCallback((file) => {
354
547
  draftRevisionRef.current += 1;
355
- setFiles((current) => [...current, file]);
548
+ setFiles((current) => [...current, (0, import_ui.createAgentChatComposerFile)(file)]);
356
549
  }, []);
357
550
  const recorder = (0, import_ui.useAudioRecorder)(addRecording);
358
551
  const isExpanded = forceExpanded || text.includes("\n") || text.length > 62;
359
552
  const validationError = (0, import_runtime.validateAgentChatSubmission)(
360
553
  inputContract,
361
554
  text,
362
- files.map((file) => ({ data: file, mediaType: file.type }))
555
+ files.map((file) => ({ data: file.source, mediaType: file.mediaType }))
363
556
  );
364
- const modelSelector = models.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "w-fit max-w-40", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
365
- Select,
366
- {
367
- disabled: disabled || isRunning,
368
- onValueChange: onModelChange,
369
- value: modelId || void 0,
370
- children: [
371
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(SelectTrigger, { "aria-label": "Runtime model", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(SelectValue, { placeholder: "Model" }) }),
372
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(SelectContent, { align: "start", children: models.map((model) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(SelectItem, { value: model.id, children: model.label }, model.id)) })
373
- ]
374
- }
375
- ) }) : null;
557
+ const selectedAgent = agents.find((item) => item.id === agentId);
558
+ const selectedModel = models.find((item) => item.id === modelId);
559
+ const modelSelector = models.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "w-fit max-w-40", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Select, { disabled: disabled || isRunning, onValueChange: onModelChange, value: modelId || void 0, children: [
560
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SelectTrigger, { "aria-label": "Runtime model", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SelectValue, { placeholder: "Model" }) }),
561
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SelectContent, { align: "start", children: models.map((model) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SelectItem, { value: model.id, children: model.label }, model.id)) })
562
+ ] }) }) : null;
563
+ const runtimeSelector = agents.length > 1 ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(DropdownMenu, { children: [
564
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
565
+ Button,
566
+ {
567
+ variant: "ghost",
568
+ className: "h-8 max-w-64 gap-1.5 bg-transparent px-2.5 text-xs font-normal hover:bg-muted/40 disabled:opacity-100",
569
+ disabled: disabled || isRunning,
570
+ "aria-label": "Runtime configuration",
571
+ children: [
572
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "truncate", children: [selectedAgent?.label, selectedModel?.label].filter(Boolean).join(" \xB7 ") || "Runtime" }),
573
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_lucide_react3.ChevronDown, { className: "size-3.5 text-muted-foreground" })
574
+ ]
575
+ }
576
+ ) }),
577
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(DropdownMenuContent, { align: "start", className: "w-64 rounded-lg", children: [
578
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(DropdownMenuSub, { children: [
579
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(DropdownMenuSubTrigger, { className: "rounded-lg", children: [
580
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: "Agent" }),
581
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "ml-auto max-w-32 truncate text-muted-foreground", children: selectedAgent?.label })
582
+ ] }),
583
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(DropdownMenuSubContent, { className: "w-56 rounded-lg", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(DropdownMenuRadioGroup, { value: agentId || void 0, onValueChange: onAgentChange, children: agents.map((agent) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(DropdownMenuRadioItem, { className: "rounded-lg", value: agent.id, children: agent.label }, agent.id)) }) })
584
+ ] }),
585
+ models.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(DropdownMenuSub, { children: [
586
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(DropdownMenuSubTrigger, { className: "rounded-lg", children: [
587
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: "Model" }),
588
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "ml-auto max-w-32 truncate text-muted-foreground", children: selectedModel?.label })
589
+ ] }),
590
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(DropdownMenuSubContent, { className: "max-h-64 w-56 rounded-lg", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(DropdownMenuRadioGroup, { value: modelId || void 0, onValueChange: onModelChange, children: models.map((model) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(DropdownMenuRadioItem, { className: "rounded-lg", value: model.id, children: model.label }, model.id)) }) })
591
+ ] }) : null
592
+ ] })
593
+ ] }) : modelSelector;
376
594
  const hasContextWindow = Number.isFinite(Number(contextWindow?.max_tokens)) && Number(contextWindow?.max_tokens) > 0;
377
595
  const showUtilityRow = utilityRow === "below";
378
596
  const submit = async () => {
@@ -382,36 +600,51 @@ function ChatComposer({
382
600
  const clearedRevision = draftRevisionRef.current + 1;
383
601
  draftRevisionRef.current = clearedRevision;
384
602
  submittingRef.current = true;
603
+ inFlightFilesRef.current = selectedFiles;
385
604
  setText("");
386
605
  setFiles([]);
387
606
  textareaRef.current?.focus();
388
607
  try {
389
608
  await onSubmit(value, selectedFiles);
609
+ (0, import_ui.revokeAgentChatComposerFiles)(selectedFiles);
610
+ inFlightFilesRef.current = [];
390
611
  } catch {
391
612
  if (draftRevisionRef.current === clearedRevision) {
392
613
  draftRevisionRef.current += 1;
393
614
  setText(value);
394
615
  setFiles(selectedFiles);
616
+ inFlightFilesRef.current = [];
617
+ } else {
618
+ (0, import_ui.revokeAgentChatComposerFiles)(selectedFiles);
619
+ inFlightFilesRef.current = [];
395
620
  }
396
621
  } finally {
397
622
  submittingRef.current = false;
398
623
  }
399
624
  };
400
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
625
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
401
626
  "div",
402
627
  {
403
628
  className: "mx-auto w-full max-w-3xl px-4 pb-[max(1rem,env(safe-area-inset-bottom))] sm:px-6",
404
629
  "data-agents24-chat-composer": "",
405
630
  children: [
406
- allowAttachments && files.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "mb-2 flex min-w-0 gap-2 overflow-x-auto", children: files.map((file, index) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex max-w-48 items-center gap-2 border bg-card px-2 py-1 text-xs", children: [
407
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "truncate", children: file.name }),
408
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Button, { variant: "ghost", size: "icon-xs", "aria-label": `Remove ${file.name}`, onClick: () => {
409
- draftRevisionRef.current += 1;
410
- setFiles((current) => current.filter((_, itemIndex) => itemIndex !== index));
411
- }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react2.X, {}) })
412
- ] }, `${file.name}-${index}`)) }),
413
- attachmentError || recorder.error ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "mb-2 text-xs text-destructive", role: "alert", children: attachmentError || recorder.error }) : null,
414
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
631
+ allowAttachments && files.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "mb-2 min-w-0", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
632
+ import_ui.ChatAttachmentRows,
633
+ {
634
+ attachments: files,
635
+ onRemove: (attachment) => {
636
+ if (!attachment.id) return;
637
+ draftRevisionRef.current += 1;
638
+ setFiles((current) => {
639
+ const removed = current.find((file) => file.id === attachment.id);
640
+ if (removed) (0, import_ui.revokeAgentChatComposerFiles)([removed]);
641
+ return current.filter((file) => file.id !== attachment.id);
642
+ });
643
+ }
644
+ }
645
+ ) }),
646
+ attachmentError || recorder.error ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "mb-2 text-xs text-destructive", role: "alert", children: attachmentError || recorder.error }) : null,
647
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
415
648
  "div",
416
649
  {
417
650
  "data-expanded": isExpanded || void 0,
@@ -420,8 +653,8 @@ function ChatComposer({
420
653
  isExpanded ? "p-2" : "p-1.5"
421
654
  ),
422
655
  children: [
423
- allowAttachments ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
424
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
656
+ allowAttachments ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
657
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
425
658
  "input",
426
659
  {
427
660
  ref: inputRef,
@@ -433,7 +666,7 @@ function ChatComposer({
433
666
  const selected = Array.from(event.target.files ?? []);
434
667
  const accepted = selected.filter((file) => attachmentMimeTypes.includes((0, import_runtime.canonicalInputMimeType)(file.type)));
435
668
  draftRevisionRef.current += 1;
436
- setFiles((current) => [...current, ...accepted]);
669
+ setFiles((current) => [...current, ...accepted.map(import_ui.createAgentChatComposerFile)]);
437
670
  setAttachmentError(
438
671
  accepted.length === selected.length ? null : "One or more selected file types are not supported by this Agent."
439
672
  );
@@ -441,9 +674,9 @@ function ChatComposer({
441
674
  }
442
675
  }
443
676
  ),
444
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "agents24-composer-attach flex min-w-0 items-center", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Button, { className: "bg-muted/50 text-muted-foreground hover:bg-muted hover:text-foreground", variant: "ghost", size: "icon", "aria-label": "Attach files", disabled: disabled || isRunning, onClick: () => inputRef.current?.click(), children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { "aria-hidden": true, children: "+" }) }) })
445
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { "aria-hidden": "true", className: "agents24-composer-attach" }),
446
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
677
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "agents24-composer-attach flex min-w-0 items-center", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Button, { className: "bg-muted/50 text-muted-foreground hover:bg-muted hover:text-foreground", variant: "ghost", size: "icon", "aria-label": "Attach files", disabled: disabled || isRunning, onClick: () => inputRef.current?.click(), children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { "aria-hidden": true, children: "+" }) }) })
678
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { "aria-hidden": "true", className: "agents24-composer-attach" }),
679
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
447
680
  Textarea,
448
681
  {
449
682
  ref: textareaRef,
@@ -468,10 +701,10 @@ function ChatComposer({
468
701
  }
469
702
  }
470
703
  ),
471
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "agents24-composer-actions flex items-center gap-1", children: [
472
- utilityRow === "inline" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_ui.AgentChatContextStatus, { contextWindow }) : null,
473
- utilityRow === "inline" ? modelSelector : null,
474
- recordingAllowed ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
704
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "agents24-composer-actions flex items-center gap-1", children: [
705
+ utilityRow === "inline" ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_ui.AgentChatContextStatus, { contextWindow }) : null,
706
+ utilityRow === "inline" ? runtimeSelector : null,
707
+ recordingAllowed ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
475
708
  Button,
476
709
  {
477
710
  variant: recorder.isRecording ? "default" : "ghost",
@@ -482,35 +715,35 @@ function ChatComposer({
482
715
  if (recorder.isRecording) recorder.stop();
483
716
  else void recorder.start();
484
717
  },
485
- children: recorder.isRecording ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react2.Square, { className: "fill-current" }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react2.Mic, {})
718
+ children: recorder.isRecording ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_lucide_react3.Square, { className: "fill-current" }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_lucide_react3.Mic, {})
486
719
  }
487
720
  ) : null,
488
- isRunning ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
721
+ isRunning ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
489
722
  Button,
490
723
  {
491
724
  size: "icon",
492
725
  "aria-label": isCancelling ? "Cancelling response" : "Stop response",
493
726
  disabled: disabled || isCancelling,
494
727
  onClick: onStop,
495
- children: isCancelling ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react2.LoaderCircle, { className: "animate-spin" }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react2.Square, { className: "fill-current" })
728
+ children: isCancelling ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_lucide_react3.LoaderCircle, { className: "animate-spin" }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_lucide_react3.Square, { className: "fill-current" })
496
729
  }
497
- ) : validationError ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Tooltip, { tabIndex: 0, children: [
498
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Button, { size: "icon", "aria-label": "Send message", disabled: true, onClick: () => void submit(), children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react2.ArrowUp, {}) }) }),
499
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(TooltipContent, { children: validationError })
500
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Button, { size: "icon", "aria-label": "Send message", disabled, onClick: () => void submit(), children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react2.ArrowUp, {}) })
730
+ ) : validationError ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Tooltip, { tabIndex: 0, children: [
731
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Button, { size: "icon", "aria-label": "Send message", disabled: true, onClick: () => void submit(), children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_lucide_react3.ArrowUp, {}) }) }),
732
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(TooltipContent, { children: validationError })
733
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Button, { size: "icon", "aria-label": "Send message", disabled, onClick: () => void submit(), children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_lucide_react3.ArrowUp, {}) })
501
734
  ] })
502
735
  ]
503
736
  }
504
737
  ),
505
- showUtilityRow ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
738
+ showUtilityRow ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
506
739
  "div",
507
740
  {
508
- "aria-hidden": !modelSelector && !hasContextWindow ? "true" : void 0,
741
+ "aria-hidden": !runtimeSelector && !hasContextWindow ? "true" : void 0,
509
742
  className: "mt-2 flex min-h-8 items-center justify-between gap-2 px-1",
510
743
  "data-agents24-chat-composer-utility": "",
511
744
  children: [
512
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "min-w-0", children: modelSelector }),
513
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_ui.AgentChatContextStatus, { contextWindow })
745
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "min-w-0", children: runtimeSelector }),
746
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_ui.AgentChatContextStatus, { contextWindow })
514
747
  ]
515
748
  }
516
749
  ) : null
@@ -526,17 +759,17 @@ var import_ui3 = require("@agents24/chat-react/ui");
526
759
  var import_ui2 = require("@agents24/chat-react/ui");
527
760
 
528
761
  // scaffold/src/components/chat/collapsible-user-message.tsx
529
- var import_lucide_react3 = require("lucide-react");
762
+ var import_lucide_react4 = require("lucide-react");
530
763
  var React3 = __toESM(require("react"), 1);
531
- var import_jsx_runtime7 = require("react/jsx-runtime");
764
+ var import_jsx_runtime8 = require("react/jsx-runtime");
532
765
  var collapseThreshold = 360;
533
766
  function CollapsibleUserMessage({ content }) {
534
767
  const [expanded, setExpanded] = React3.useState(false);
535
768
  const contentId = React3.useId();
536
769
  const collapsible = content.length > collapseThreshold;
537
- const Icon = expanded ? import_lucide_react3.ChevronUp : import_lucide_react3.ChevronDown;
538
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex min-w-0 flex-col gap-2", children: [
539
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
770
+ const Icon = expanded ? import_lucide_react4.ChevronUp : import_lucide_react4.ChevronDown;
771
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex min-w-0 flex-col gap-2", children: [
772
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
540
773
  "div",
541
774
  {
542
775
  id: contentId,
@@ -544,7 +777,7 @@ function CollapsibleUserMessage({ content }) {
544
777
  children: content
545
778
  }
546
779
  ),
547
- collapsible && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
780
+ collapsible && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
548
781
  Button,
549
782
  {
550
783
  variant: "ghost",
@@ -556,7 +789,7 @@ function CollapsibleUserMessage({ content }) {
556
789
  onClick: () => setExpanded((value) => !value),
557
790
  children: [
558
791
  expanded ? "Show less" : "Show more",
559
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Icon, {})
792
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Icon, {})
560
793
  ]
561
794
  }
562
795
  )
@@ -567,27 +800,27 @@ function CollapsibleUserMessage({ content }) {
567
800
  var React4 = __toESM(require("react"), 1);
568
801
 
569
802
  // scaffold/src/components/ui/dialog.tsx
570
- var import_radix_ui4 = require("radix-ui");
571
- var import_lucide_react4 = require("lucide-react");
572
- var import_jsx_runtime8 = require("react/jsx-runtime");
803
+ var import_radix_ui5 = require("radix-ui");
804
+ var import_lucide_react5 = require("lucide-react");
805
+ var import_jsx_runtime9 = require("react/jsx-runtime");
573
806
  function Dialog({
574
807
  ...props
575
808
  }) {
576
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_radix_ui4.Dialog.Root, { "data-slot": "dialog", ...props });
809
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_radix_ui5.Dialog.Root, { "data-slot": "dialog", ...props });
577
810
  }
578
811
  function DialogPortal({
579
812
  container,
580
813
  ...props
581
814
  }) {
582
815
  const themeContainer = useThemePortalContainer();
583
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_radix_ui4.Dialog.Portal, { container: container || themeContainer || void 0, "data-slot": "dialog-portal", ...props });
816
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_radix_ui5.Dialog.Portal, { container: container || themeContainer || void 0, "data-slot": "dialog-portal", ...props });
584
817
  }
585
818
  function DialogOverlay({
586
819
  className,
587
820
  ...props
588
821
  }) {
589
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
590
- import_radix_ui4.Dialog.Overlay,
822
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
823
+ import_radix_ui5.Dialog.Overlay,
591
824
  {
592
825
  "data-slot": "dialog-overlay",
593
826
  className: cn(
@@ -604,10 +837,10 @@ function DialogContent({
604
837
  showCloseButton = true,
605
838
  ...props
606
839
  }) {
607
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(DialogPortal, { children: [
608
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(DialogOverlay, {}),
609
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
610
- import_radix_ui4.Dialog.Content,
840
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(DialogPortal, { children: [
841
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(DialogOverlay, {}),
842
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
843
+ import_radix_ui5.Dialog.Content,
611
844
  {
612
845
  "data-slot": "dialog-content",
613
846
  className: cn(
@@ -617,18 +850,18 @@ function DialogContent({
617
850
  ...props,
618
851
  children: [
619
852
  children,
620
- showCloseButton && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_radix_ui4.Dialog.Close, { "data-slot": "dialog-close", asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
853
+ showCloseButton && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_radix_ui5.Dialog.Close, { "data-slot": "dialog-close", asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
621
854
  Button,
622
855
  {
623
856
  variant: "ghost",
624
857
  className: "absolute top-4 right-4 bg-secondary",
625
858
  size: "icon-sm",
626
859
  children: [
627
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
628
- import_lucide_react4.XIcon,
860
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
861
+ import_lucide_react5.XIcon,
629
862
  {}
630
863
  ),
631
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "sr-only", children: "Close" })
864
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "sr-only", children: "Close" })
632
865
  ]
633
866
  }
634
867
  ) })
@@ -638,7 +871,7 @@ function DialogContent({
638
871
  ] });
639
872
  }
640
873
  function DialogHeader({ className, ...props }) {
641
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
874
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
642
875
  "div",
643
876
  {
644
877
  "data-slot": "dialog-header",
@@ -653,7 +886,7 @@ function DialogFooter({
653
886
  children,
654
887
  ...props
655
888
  }) {
656
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
889
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
657
890
  "div",
658
891
  {
659
892
  "data-slot": "dialog-footer",
@@ -664,7 +897,7 @@ function DialogFooter({
664
897
  ...props,
665
898
  children: [
666
899
  children,
667
- showCloseButton && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_radix_ui4.Dialog.Close, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Button, { variant: "outline", children: "Close" }) })
900
+ showCloseButton && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_radix_ui5.Dialog.Close, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Button, { variant: "outline", children: "Close" }) })
668
901
  ]
669
902
  }
670
903
  );
@@ -673,8 +906,8 @@ function DialogTitle({
673
906
  className,
674
907
  ...props
675
908
  }) {
676
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
677
- import_radix_ui4.Dialog.Title,
909
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
910
+ import_radix_ui5.Dialog.Title,
678
911
  {
679
912
  "data-slot": "dialog-title",
680
913
  className: cn(
@@ -689,8 +922,8 @@ function DialogDescription({
689
922
  className,
690
923
  ...props
691
924
  }) {
692
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
693
- import_radix_ui4.Dialog.Description,
925
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
926
+ import_radix_ui5.Dialog.Description,
694
927
  {
695
928
  "data-slot": "dialog-description",
696
929
  className: cn(
@@ -703,7 +936,7 @@ function DialogDescription({
703
936
  }
704
937
 
705
938
  // scaffold/src/components/chat/external-link-dialog.tsx
706
- var import_jsx_runtime9 = require("react/jsx-runtime");
939
+ var import_jsx_runtime10 = require("react/jsx-runtime");
707
940
  function ExternalLinkDialog({ isOpen, onClose, onConfirm, url }) {
708
941
  const [copied, setCopied] = React4.useState(false);
709
942
  React4.useEffect(() => {
@@ -717,29 +950,29 @@ function ExternalLinkDialog({ isOpen, onClose, onConfirm, url }) {
717
950
  onConfirm();
718
951
  onClose();
719
952
  };
720
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Dialog, { open: isOpen, onOpenChange: (open) => {
953
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Dialog, { open: isOpen, onOpenChange: (open) => {
721
954
  if (!open) onClose();
722
- }, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(DialogContent, { className: "max-h-[calc(100dvh-2rem)] min-w-0 overflow-hidden sm:max-w-md", children: [
723
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(DialogHeader, { children: [
724
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(DialogTitle, { children: "Open external link?" }),
725
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(DialogDescription, { children: "You\u2019re about to visit an external website." })
955
+ }, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(DialogContent, { className: "max-h-[calc(100dvh-2rem)] min-w-0 overflow-hidden sm:max-w-md", children: [
956
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(DialogHeader, { children: [
957
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(DialogTitle, { children: "Open external link?" }),
958
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(DialogDescription, { children: "You\u2019re about to visit an external website." })
726
959
  ] }),
727
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "max-h-32 overflow-auto rounded-md bg-muted p-3 font-mono text-xs wrap-break-word", children: url }),
728
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(DialogFooter, { children: [
729
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Button, { variant: "outline", onClick: () => void copyUrl(), children: copied ? "Copied" : "Copy link" }),
730
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Button, { onClick: openUrl, children: "Open link" })
960
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "max-h-32 overflow-auto rounded-md bg-muted p-3 font-mono text-xs wrap-break-word", children: url }),
961
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(DialogFooter, { children: [
962
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Button, { variant: "outline", onClick: () => void copyUrl(), children: copied ? "Copied" : "Copy link" }),
963
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Button, { onClick: openUrl, children: "Open link" })
731
964
  ] })
732
965
  ] }) });
733
966
  }
734
967
 
735
968
  // scaffold/src/components/chat/message-parts.tsx
736
- var import_jsx_runtime10 = require("react/jsx-runtime");
969
+ var import_jsx_runtime11 = require("react/jsx-runtime");
737
970
  var linkSafety = {
738
971
  enabled: true,
739
- renderModal: (props) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ExternalLinkDialog, { ...props })
972
+ renderModal: (props) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(ExternalLinkDialog, { ...props })
740
973
  };
741
974
  function ScaffoldTimeline(props) {
742
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
975
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
743
976
  import_ui2.AgentResponseTimeline,
744
977
  {
745
978
  ...props,
@@ -758,7 +991,7 @@ function MessageParts({
758
991
  Timeline = ScaffoldTimeline
759
992
  }) {
760
993
  if (message.role === "assistant") {
761
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
994
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
762
995
  Timeline,
763
996
  {
764
997
  getHitlActionState,
@@ -773,8 +1006,8 @@ function MessageParts({
773
1006
  }
774
1007
  const text = message.parts.filter((part) => part.kind === "text").map((part) => part.kind === "text" ? part.text : "").join("") || message.content;
775
1008
  const supportingParts = message.parts.filter((part) => part.kind !== "text" && part.kind !== "data");
776
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
777
- supportingParts.map((part) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1009
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
1010
+ supportingParts.map((part) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
778
1011
  import_ui2.AgentChatPart,
779
1012
  {
780
1013
  getHitlActionState,
@@ -786,14 +1019,14 @@ function MessageParts({
786
1019
  },
787
1020
  part.id
788
1021
  )),
789
- text ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(CollapsibleUserMessage, { content: text }) : null
1022
+ text ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(CollapsibleUserMessage, { content: text }) : null
790
1023
  ] });
791
1024
  }
792
1025
 
793
1026
  // scaffold/src/components/ui/bubble.tsx
794
1027
  var import_class_variance_authority2 = require("class-variance-authority");
795
- var import_radix_ui5 = require("radix-ui");
796
- var import_jsx_runtime11 = require("react/jsx-runtime");
1028
+ var import_radix_ui6 = require("radix-ui");
1029
+ var import_jsx_runtime12 = require("react/jsx-runtime");
797
1030
  var bubbleVariants = (0, import_class_variance_authority2.cva)(
798
1031
  "group/bubble relative flex w-fit max-w-[80%] min-w-0 flex-col gap-1 group-data-[align=end]/message:self-end data-[align=end]:self-end data-[variant=ghost]:max-w-full",
799
1032
  {
@@ -819,7 +1052,7 @@ function Bubble({
819
1052
  className,
820
1053
  ...props
821
1054
  }) {
822
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1055
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
823
1056
  "div",
824
1057
  {
825
1058
  "data-slot": "bubble",
@@ -835,8 +1068,8 @@ function BubbleContent({
835
1068
  className,
836
1069
  ...props
837
1070
  }) {
838
- const Comp = asChild ? import_radix_ui5.Slot.Root : "div";
839
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1071
+ const Comp = asChild ? import_radix_ui6.Slot.Root : "div";
1072
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
840
1073
  Comp,
841
1074
  {
842
1075
  "data-slot": "bubble-content",
@@ -869,13 +1102,13 @@ var bubbleReactionsVariants = (0, import_class_variance_authority2.cva)(
869
1102
  );
870
1103
 
871
1104
  // scaffold/src/components/ui/message.tsx
872
- var import_jsx_runtime12 = require("react/jsx-runtime");
1105
+ var import_jsx_runtime13 = require("react/jsx-runtime");
873
1106
  function Message({
874
1107
  className,
875
1108
  align = "start",
876
1109
  ...props
877
1110
  }) {
878
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1111
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
879
1112
  "div",
880
1113
  {
881
1114
  "data-slot": "message",
@@ -889,7 +1122,7 @@ function Message({
889
1122
  );
890
1123
  }
891
1124
  function MessageContent({ className, ...props }) {
892
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1125
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
893
1126
  "div",
894
1127
  {
895
1128
  "data-slot": "message-content",
@@ -902,7 +1135,7 @@ function MessageContent({ className, ...props }) {
902
1135
  );
903
1136
  }
904
1137
  function MessageFooter({ className, ...props }) {
905
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1138
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
906
1139
  "div",
907
1140
  {
908
1141
  "data-slot": "message-footer",
@@ -916,7 +1149,7 @@ function MessageFooter({ className, ...props }) {
916
1149
  }
917
1150
 
918
1151
  // scaffold/src/components/chat/chat-message.tsx
919
- var import_jsx_runtime13 = require("react/jsx-runtime");
1152
+ var import_jsx_runtime14 = require("react/jsx-runtime");
920
1153
  function ChatMessage({
921
1154
  allowFeedback,
922
1155
  getHitlActionState,
@@ -925,18 +1158,20 @@ function ChatMessage({
925
1158
  onHitlAction,
926
1159
  onRegenerate,
927
1160
  onSetFeedback,
1161
+ resolveAttachmentContent,
928
1162
  Timeline
929
1163
  }) {
930
1164
  const isUser = message.role === "user";
931
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Message, { align: isUser ? "end" : "start", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(MessageContent, { children: [
932
- isUser && message.attachments?.length ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_ui3.ChatAttachments, { className: "mb-2 justify-end", children: message.attachments.map((attachment, index) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
933
- import_ui3.ChatAttachment,
1165
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Message, { align: isUser ? "end" : "start", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(MessageContent, { children: [
1166
+ isUser && message.attachments?.length ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1167
+ import_ui3.ChatAttachmentRows,
934
1168
  {
935
- data: attachment
936
- },
937
- String(attachment.id || attachment.url || attachment.filename || index)
938
- )) }) : null,
939
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Bubble, { variant: isUser ? "secondary" : "ghost", align: isUser ? "end" : "start", className: isUser ? "max-w-[min(75%,42rem)]" : "max-w-full overflow-visible", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(BubbleContent, { className: isUser ? "px-4 py-2.5" : "w-full overflow-visible", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1169
+ attachments: message.attachments,
1170
+ className: "mb-2",
1171
+ resolveContent: resolveAttachmentContent
1172
+ }
1173
+ ) : null,
1174
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Bubble, { variant: isUser ? "secondary" : "ghost", align: isUser ? "end" : "start", className: isUser ? "max-w-[min(75%,42rem)]" : "max-w-full overflow-visible", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(BubbleContent, { className: isUser ? "px-4 py-2.5" : "w-full overflow-visible", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
940
1175
  MessageParts,
941
1176
  {
942
1177
  getHitlActionState,
@@ -946,7 +1181,7 @@ function ChatMessage({
946
1181
  Timeline
947
1182
  }
948
1183
  ) }) }),
949
- !isUser && message.isFinal !== false && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(MessageFooter, { className: "gap-1 opacity-70 transition-opacity group-hover/message:opacity-100", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1184
+ !isUser && message.isFinal !== false && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(MessageFooter, { className: "gap-1 opacity-70 transition-opacity group-hover/message:opacity-100", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
950
1185
  import_ui3.AgentChatDefaultActions,
951
1186
  {
952
1187
  handlers: {
@@ -964,13 +1199,13 @@ function ChatMessage({
964
1199
  }
965
1200
 
966
1201
  // scaffold/src/components/chat/theme-menu.tsx
967
- var import_lucide_react5 = require("lucide-react");
1202
+ var import_lucide_react6 = require("lucide-react");
968
1203
  var React5 = __toESM(require("react"), 1);
969
- var import_jsx_runtime14 = require("react/jsx-runtime");
1204
+ var import_jsx_runtime15 = require("react/jsx-runtime");
970
1205
  var options = [
971
- { value: "system", label: "System", icon: import_lucide_react5.Laptop },
972
- { value: "light", label: "Light", icon: import_lucide_react5.Sun },
973
- { value: "dark", label: "Dark", icon: import_lucide_react5.Moon }
1206
+ { value: "system", label: "System", icon: import_lucide_react6.Laptop },
1207
+ { value: "light", label: "Light", icon: import_lucide_react6.Sun },
1208
+ { value: "dark", label: "Dark", icon: import_lucide_react6.Moon }
974
1209
  ];
975
1210
  function ThemeMenu() {
976
1211
  const { appearance, setAppearance } = useTheme();
@@ -978,7 +1213,7 @@ function ThemeMenu() {
978
1213
  const rootRef = React5.useRef(null);
979
1214
  const firstItemRef = React5.useRef(null);
980
1215
  const menuId = React5.useId();
981
- const ActiveIcon = options.find((item) => item.value === appearance)?.icon ?? import_lucide_react5.Laptop;
1216
+ const ActiveIcon = options.find((item) => item.value === appearance)?.icon ?? import_lucide_react6.Laptop;
982
1217
  React5.useEffect(() => {
983
1218
  if (!open) return;
984
1219
  firstItemRef.current?.focus();
@@ -996,8 +1231,8 @@ function ThemeMenu() {
996
1231
  };
997
1232
  }, [open]);
998
1233
  const label = appearance === "system" ? "System" : appearance === "light" ? "Light" : "Dark";
999
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { ref: rootRef, className: "relative", children: [
1000
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1234
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { ref: rootRef, className: "relative", children: [
1235
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1001
1236
  Button,
1002
1237
  {
1003
1238
  "aria-controls": menuId,
@@ -1007,16 +1242,16 @@ function ThemeMenu() {
1007
1242
  onClick: () => setOpen((value) => !value),
1008
1243
  size: "icon-sm",
1009
1244
  variant: "ghost",
1010
- children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(ActiveIcon, {})
1245
+ children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(ActiveIcon, {})
1011
1246
  }
1012
1247
  ),
1013
- open ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1248
+ open ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1014
1249
  "div",
1015
1250
  {
1016
1251
  id: menuId,
1017
1252
  className: "absolute end-0 top-full z-50 mt-1 flex min-w-44 flex-col rounded-xl border bg-popover p-1 text-popover-foreground shadow-md",
1018
1253
  role: "menu",
1019
- children: options.map(({ value, label: optionLabel, icon: Icon }, index) => /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
1254
+ children: options.map(({ value, label: optionLabel, icon: Icon }, index) => /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
1020
1255
  Button,
1021
1256
  {
1022
1257
  ref: index === 0 ? firstItemRef : void 0,
@@ -1030,7 +1265,7 @@ function ThemeMenu() {
1030
1265
  size: "sm",
1031
1266
  variant: "ghost",
1032
1267
  children: [
1033
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Icon, {}),
1268
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Icon, {}),
1034
1269
  " ",
1035
1270
  optionLabel
1036
1271
  ]
@@ -1049,96 +1284,6 @@ var import_lucide_react10 = require("lucide-react");
1049
1284
  // scaffold/src/components/chat/identity-control.tsx
1050
1285
  var import_lucide_react9 = require("lucide-react");
1051
1286
 
1052
- // scaffold/src/components/ui/dropdown-menu.tsx
1053
- var import_radix_ui6 = require("radix-ui");
1054
- var import_lucide_react6 = require("lucide-react");
1055
- var import_jsx_runtime15 = require("react/jsx-runtime");
1056
- function DropdownMenu({
1057
- ...props
1058
- }) {
1059
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_radix_ui6.DropdownMenu.Root, { "data-slot": "dropdown-menu", ...props });
1060
- }
1061
- function DropdownMenuTrigger({
1062
- ...props
1063
- }) {
1064
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1065
- import_radix_ui6.DropdownMenu.Trigger,
1066
- {
1067
- "data-slot": "dropdown-menu-trigger",
1068
- ...props
1069
- }
1070
- );
1071
- }
1072
- function DropdownMenuContent({
1073
- className,
1074
- align = "start",
1075
- sideOffset = 4,
1076
- ...props
1077
- }) {
1078
- const themeContainer = useThemePortalContainer();
1079
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_radix_ui6.DropdownMenu.Portal, { container: themeContainer || void 0, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1080
- import_radix_ui6.DropdownMenu.Content,
1081
- {
1082
- "data-slot": "dropdown-menu-content",
1083
- sideOffset,
1084
- align,
1085
- className: cn("z-50 max-h-(--radix-dropdown-menu-content-available-height) w-(--radix-dropdown-menu-trigger-width) min-w-48 origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-3xl bg-popover p-1.5 text-popover-foreground shadow-lg ring-1 ring-foreground/5 duration-100 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=closed]:overflow-hidden dark:ring-foreground/10 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95", className),
1086
- ...props
1087
- }
1088
- ) });
1089
- }
1090
- function DropdownMenuItem({
1091
- className,
1092
- inset,
1093
- variant = "default",
1094
- ...props
1095
- }) {
1096
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1097
- import_radix_ui6.DropdownMenu.Item,
1098
- {
1099
- "data-slot": "dropdown-menu-item",
1100
- "data-inset": inset,
1101
- "data-variant": variant,
1102
- className: cn(
1103
- "group/dropdown-menu-item relative flex cursor-default items-center gap-2.5 rounded-2xl px-3 py-2 text-sm font-medium outline-hidden select-none focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground data-inset:pl-9.5 data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive dark:data-[variant=destructive]:focus:bg-destructive/20 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 data-[variant=destructive]:*:[svg]:text-destructive",
1104
- className
1105
- ),
1106
- ...props
1107
- }
1108
- );
1109
- }
1110
- function DropdownMenuLabel({
1111
- className,
1112
- inset,
1113
- ...props
1114
- }) {
1115
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1116
- import_radix_ui6.DropdownMenu.Label,
1117
- {
1118
- "data-slot": "dropdown-menu-label",
1119
- "data-inset": inset,
1120
- className: cn(
1121
- "px-3 py-2.5 text-xs text-muted-foreground data-inset:pl-9.5",
1122
- className
1123
- ),
1124
- ...props
1125
- }
1126
- );
1127
- }
1128
- function DropdownMenuSeparator({
1129
- className,
1130
- ...props
1131
- }) {
1132
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1133
- import_radix_ui6.DropdownMenu.Separator,
1134
- {
1135
- "data-slot": "dropdown-menu-separator",
1136
- className: cn("-mx-1.5 my-1.5 h-px bg-border/50", className),
1137
- ...props
1138
- }
1139
- );
1140
- }
1141
-
1142
1287
  // scaffold/src/components/ui/sidebar.tsx
1143
1288
  var React7 = __toESM(require("react"), 1);
1144
1289
  var import_class_variance_authority3 = require("class-variance-authority");
@@ -1607,7 +1752,7 @@ function SidebarMenuItem({ className, ...props }) {
1607
1752
  );
1608
1753
  }
1609
1754
  var sidebarMenuButtonVariants = (0, import_class_variance_authority3.cva)(
1610
- "peer/menu-button group/menu-button flex w-full items-center gap-2 overflow-hidden rounded-xl px-3 py-2 text-left text-sm ring-sidebar-ring outline-hidden transition-[width,height,padding] group-has-data-[sidebar=menu-action]/menu-item:pr-8 group-data-[collapsible=icon]:size-8! group-data-[collapsible=icon]:p-2! hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-open:hover:bg-sidebar-accent data-open:hover:text-sidebar-accent-foreground data-active:bg-sidebar-accent data-active:font-medium data-active:text-sidebar-accent-foreground [&_svg]:size-4 [&_svg]:shrink-0 [&>span:last-child]:truncate",
1755
+ "peer/menu-button group/menu-button flex w-full items-center gap-2 overflow-hidden rounded-xl px-3 py-2 text-left text-sm ring-sidebar-ring outline-hidden transition-[width,height,padding] group-has-data-[sidebar=menu-action]/menu-item:pr-8 group-data-[collapsible=icon]:size-8! group-data-[collapsible=icon]:p-2! hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-open:hover:bg-sidebar-accent data-open:hover:text-sidebar-accent-foreground data-[active=true]:bg-sidebar-accent data-[active=true]:font-medium data-[active=true]:text-sidebar-accent-foreground [&_svg]:size-4 [&_svg]:shrink-0 [&>span:last-child]:truncate",
1611
1756
  {
1612
1757
  variants: {
1613
1758
  variant: {
@@ -1683,7 +1828,7 @@ function SidebarMenuAction({
1683
1828
  "data-sidebar": "menu-action",
1684
1829
  className: cn(
1685
1830
  "absolute top-1.5 right-1 flex aspect-square w-5 items-center justify-center rounded-xl p-0 text-sidebar-foreground ring-sidebar-ring outline-hidden transition-transform group-data-[collapsible=icon]:hidden peer-hover/menu-button:text-sidebar-accent-foreground peer-data-[size=default]/menu-button:top-2 peer-data-[size=lg]/menu-button:top-2.5 peer-data-[size=sm]/menu-button:top-1 after:absolute after:-inset-2 hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 md:after:hidden [&>svg]:size-4 [&>svg]:shrink-0",
1686
- showOnHover && "group-focus-within/menu-item:opacity-100 group-hover/menu-item:opacity-100 peer-data-active/menu-button:text-sidebar-accent-foreground aria-expanded:opacity-100 md:opacity-0",
1831
+ showOnHover && "group-focus-within/menu-item:opacity-100 group-hover/menu-item:opacity-100 peer-data-[active=true]/menu-button:text-sidebar-accent-foreground aria-expanded:opacity-100 md:opacity-0",
1687
1832
  className
1688
1833
  ),
1689
1834
  ...props
@@ -2056,10 +2201,12 @@ function OperationErrorNotice({ runtime }) {
2056
2201
  function ChatShell({
2057
2202
  components,
2058
2203
  identity,
2059
- runtime
2204
+ runtime,
2205
+ sidebar
2060
2206
  }) {
2061
2207
  const { controller } = runtime;
2062
- const isRunning = controller.runState === "streaming" || controller.runState === "reconnecting" || controller.runState === "paused" || controller.runState === "cancelling" || runtime.isSubmitting;
2208
+ const isRunning = controller.runState === "streaming" || controller.runState === "reconnecting" || controller.runState === "paused" || controller.runState === "cancelling";
2209
+ const isUploading = controller.runState === "uploading" || runtime.isUploading;
2063
2210
  const isCancelling = controller.runState === "cancelling";
2064
2211
  const activeTitle = controller.threads.find((thread) => thread.id === controller.activeThreadId)?.title;
2065
2212
  const hasBlockingError = Boolean(runtime.fatalError && controller.messages.length === 0);
@@ -2072,7 +2219,7 @@ function ChatShell({
2072
2219
  "data-agents24-chat-layout": "",
2073
2220
  children: [
2074
2221
  /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(PersistentSidebarTrigger, {}),
2075
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
2222
+ sidebar || /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
2076
2223
  ThreadSidebar,
2077
2224
  {
2078
2225
  activeThreadId: controller.activeThreadId,
@@ -2115,10 +2262,16 @@ function ChatShell({
2115
2262
  {
2116
2263
  inputContract: runtime.inputContract || LOADING_INPUT_CONTRACT,
2117
2264
  contextWindow: runtime.contextWindow,
2118
- disabled: runtime.isBootstrapping,
2265
+ disabled: runtime.isBootstrapping || runtime.isChangingAgent || isUploading,
2266
+ focusKey: controller.activeThreadId,
2119
2267
  forceExpanded: true,
2120
2268
  isCancelling,
2121
2269
  isRunning,
2270
+ agentId: runtime.agentId,
2271
+ agents: runtime.agents,
2272
+ onAgentChange: (agentId) => {
2273
+ void runtime.changeAgent(agentId);
2274
+ },
2122
2275
  onStop: () => {
2123
2276
  void controller.cancelRun().catch(() => void 0);
2124
2277
  },
@@ -2128,10 +2281,11 @@ function ChatShell({
2128
2281
  onSubmit: (text, files) => runtime.submit({
2129
2282
  text,
2130
2283
  files: files.map((file) => ({
2131
- data: file,
2132
- mediaType: file.type || "application/octet-stream",
2133
- name: file.name
2134
- }))
2284
+ data: file.source,
2285
+ mediaType: file.mediaType,
2286
+ name: file.filename
2287
+ })),
2288
+ attachments: files
2135
2289
  })
2136
2290
  }
2137
2291
  )
@@ -2184,6 +2338,7 @@ function ChatShell({
2184
2338
  onHitlAction: runtime.onHitlAction,
2185
2339
  onRegenerate: () => controller.regenerate(message),
2186
2340
  onSetFeedback: (input) => controller.setFeedback(message, input),
2341
+ resolveAttachmentContent: runtime.resolveAttachmentContent,
2187
2342
  Timeline: components?.Timeline
2188
2343
  }
2189
2344
  )
@@ -2203,9 +2358,15 @@ function ChatShell({
2203
2358
  {
2204
2359
  inputContract: runtime.inputContract || LOADING_INPUT_CONTRACT,
2205
2360
  contextWindow: runtime.contextWindow,
2206
- disabled: runtime.isBootstrapping || hasBlockingError,
2361
+ disabled: runtime.isBootstrapping || runtime.isChangingAgent || hasBlockingError || isUploading,
2362
+ focusKey: controller.activeThreadId,
2207
2363
  isCancelling,
2208
2364
  isRunning,
2365
+ agentId: runtime.agentId,
2366
+ agents: runtime.agents,
2367
+ onAgentChange: (agentId) => {
2368
+ void runtime.changeAgent(agentId);
2369
+ },
2209
2370
  onStop: () => {
2210
2371
  void controller.cancelRun().catch(() => void 0);
2211
2372
  },
@@ -2215,10 +2376,11 @@ function ChatShell({
2215
2376
  onSubmit: (text, files) => runtime.submit({
2216
2377
  text,
2217
2378
  files: files.map((file) => ({
2218
- data: file,
2219
- mediaType: file.type || "application/octet-stream",
2220
- name: file.name
2221
- }))
2379
+ data: file.source,
2380
+ mediaType: file.mediaType,
2381
+ name: file.filename
2382
+ })),
2383
+ attachments: files
2222
2384
  }),
2223
2385
  utilityRow: "below"
2224
2386
  }
@@ -2248,7 +2410,7 @@ function RuntimeChat({
2248
2410
  ...props,
2249
2411
  mcpRedirectUri: props.mcpRedirectUri || (typeof window === "undefined" ? void 0 : window.location.href)
2250
2412
  });
2251
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ChatShell, { components, identity, runtime });
2413
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ChatShell, { components, identity, runtime, sidebar: props.sidebar });
2252
2414
  }
2253
2415
  function App(props) {
2254
2416
  const identity = props.identity || GUEST_CHAT_IDENTITY;