@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
@@ -10,12 +10,18 @@ import {
10
10
  import {
11
11
  agentChatRuntimeErrorMessage
12
12
  } from "@agents24/chat-react/runtime";
13
- import { CircleAlert, LoaderCircle as LoaderCircle3, SquarePen as SquarePen2, X as X2 } from "lucide-react";
13
+ import { CircleAlert, LoaderCircle as LoaderCircle3, SquarePen as SquarePen2, X } from "lucide-react";
14
14
 
15
15
  // scaffold/src/components/chat/chat-composer.tsx
16
- import { ArrowUp, LoaderCircle, Mic, Square, X } from "lucide-react";
16
+ import { ArrowUp, ChevronDown, LoaderCircle, Mic, Square } from "lucide-react";
17
17
  import * as React2 from "react";
18
- import { AgentChatContextStatus, useAudioRecorder } from "@agents24/chat-react/ui";
18
+ import {
19
+ AgentChatContextStatus,
20
+ ChatAttachmentRows,
21
+ createAgentChatComposerFile,
22
+ revokeAgentChatComposerFiles,
23
+ useAudioRecorder
24
+ } from "@agents24/chat-react/ui";
19
25
  import { canonicalInputMimeType, inputMimeTypes, validateAgentChatSubmission } from "@agents24/chat-react/runtime";
20
26
 
21
27
  // scaffold/src/components/ui/button.tsx
@@ -32,7 +38,7 @@ function cn(...inputs) {
32
38
  // scaffold/src/components/ui/button.tsx
33
39
  import { jsx } from "react/jsx-runtime";
34
40
  var buttonVariants = cva(
35
- "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",
41
+ "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",
36
42
  {
37
43
  variants: {
38
44
  variant: {
@@ -80,9 +86,9 @@ function Button({
80
86
  );
81
87
  }
82
88
 
83
- // scaffold/src/components/ui/select.tsx
84
- import { CheckIcon, ChevronDownIcon } from "lucide-react";
85
- import { Select as SelectPrimitive } from "radix-ui";
89
+ // scaffold/src/components/ui/dropdown-menu.tsx
90
+ import { DropdownMenu as DropdownMenuPrimitive } from "radix-ui";
91
+ import { CheckIcon, ChevronRightIcon } from "lucide-react";
86
92
 
87
93
  // scaffold/src/components/theme-provider.tsx
88
94
  import * as React from "react";
@@ -152,20 +158,195 @@ function useThemePortalContainer() {
152
158
  return useTheme().portalContainer;
153
159
  }
154
160
 
155
- // scaffold/src/components/ui/select.tsx
161
+ // scaffold/src/components/ui/dropdown-menu.tsx
156
162
  import { jsx as jsx3, jsxs } from "react/jsx-runtime";
163
+ function DropdownMenu({
164
+ ...props
165
+ }) {
166
+ return /* @__PURE__ */ jsx3(DropdownMenuPrimitive.Root, { "data-slot": "dropdown-menu", ...props });
167
+ }
168
+ function DropdownMenuTrigger({
169
+ ...props
170
+ }) {
171
+ return /* @__PURE__ */ jsx3(
172
+ DropdownMenuPrimitive.Trigger,
173
+ {
174
+ "data-slot": "dropdown-menu-trigger",
175
+ ...props
176
+ }
177
+ );
178
+ }
179
+ function DropdownMenuContent({
180
+ className,
181
+ align = "start",
182
+ sideOffset = 4,
183
+ ...props
184
+ }) {
185
+ const themeContainer = useThemePortalContainer();
186
+ return /* @__PURE__ */ jsx3(DropdownMenuPrimitive.Portal, { container: themeContainer || void 0, children: /* @__PURE__ */ jsx3(
187
+ DropdownMenuPrimitive.Content,
188
+ {
189
+ "data-slot": "dropdown-menu-content",
190
+ sideOffset,
191
+ align,
192
+ 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),
193
+ ...props
194
+ }
195
+ ) });
196
+ }
197
+ function DropdownMenuItem({
198
+ className,
199
+ inset,
200
+ variant = "default",
201
+ ...props
202
+ }) {
203
+ return /* @__PURE__ */ jsx3(
204
+ DropdownMenuPrimitive.Item,
205
+ {
206
+ "data-slot": "dropdown-menu-item",
207
+ "data-inset": inset,
208
+ "data-variant": variant,
209
+ className: cn(
210
+ "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",
211
+ className
212
+ ),
213
+ ...props
214
+ }
215
+ );
216
+ }
217
+ function DropdownMenuRadioGroup({
218
+ ...props
219
+ }) {
220
+ return /* @__PURE__ */ jsx3(
221
+ DropdownMenuPrimitive.RadioGroup,
222
+ {
223
+ "data-slot": "dropdown-menu-radio-group",
224
+ ...props
225
+ }
226
+ );
227
+ }
228
+ function DropdownMenuRadioItem({
229
+ className,
230
+ children,
231
+ inset,
232
+ ...props
233
+ }) {
234
+ return /* @__PURE__ */ jsxs(
235
+ DropdownMenuPrimitive.RadioItem,
236
+ {
237
+ "data-slot": "dropdown-menu-radio-item",
238
+ "data-inset": inset,
239
+ className: cn(
240
+ "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",
241
+ className
242
+ ),
243
+ ...props,
244
+ children: [
245
+ /* @__PURE__ */ jsx3(
246
+ "span",
247
+ {
248
+ className: "pointer-events-none absolute right-2 flex items-center justify-center",
249
+ "data-slot": "dropdown-menu-radio-item-indicator",
250
+ children: /* @__PURE__ */ jsx3(DropdownMenuPrimitive.ItemIndicator, { children: /* @__PURE__ */ jsx3(
251
+ CheckIcon,
252
+ {}
253
+ ) })
254
+ }
255
+ ),
256
+ children
257
+ ]
258
+ }
259
+ );
260
+ }
261
+ function DropdownMenuLabel({
262
+ className,
263
+ inset,
264
+ ...props
265
+ }) {
266
+ return /* @__PURE__ */ jsx3(
267
+ DropdownMenuPrimitive.Label,
268
+ {
269
+ "data-slot": "dropdown-menu-label",
270
+ "data-inset": inset,
271
+ className: cn(
272
+ "px-3 py-2.5 text-xs text-muted-foreground data-inset:pl-9.5",
273
+ className
274
+ ),
275
+ ...props
276
+ }
277
+ );
278
+ }
279
+ function DropdownMenuSeparator({
280
+ className,
281
+ ...props
282
+ }) {
283
+ return /* @__PURE__ */ jsx3(
284
+ DropdownMenuPrimitive.Separator,
285
+ {
286
+ "data-slot": "dropdown-menu-separator",
287
+ className: cn("-mx-1.5 my-1.5 h-px bg-border/50", className),
288
+ ...props
289
+ }
290
+ );
291
+ }
292
+ function DropdownMenuSub({
293
+ ...props
294
+ }) {
295
+ return /* @__PURE__ */ jsx3(DropdownMenuPrimitive.Sub, { "data-slot": "dropdown-menu-sub", ...props });
296
+ }
297
+ function DropdownMenuSubTrigger({
298
+ className,
299
+ inset,
300
+ children,
301
+ ...props
302
+ }) {
303
+ return /* @__PURE__ */ jsxs(
304
+ DropdownMenuPrimitive.SubTrigger,
305
+ {
306
+ "data-slot": "dropdown-menu-sub-trigger",
307
+ "data-inset": inset,
308
+ className: cn(
309
+ "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",
310
+ className
311
+ ),
312
+ ...props,
313
+ children: [
314
+ children,
315
+ /* @__PURE__ */ jsx3(ChevronRightIcon, { className: "ml-auto" })
316
+ ]
317
+ }
318
+ );
319
+ }
320
+ function DropdownMenuSubContent({
321
+ className,
322
+ ...props
323
+ }) {
324
+ return /* @__PURE__ */ jsx3(
325
+ DropdownMenuPrimitive.SubContent,
326
+ {
327
+ "data-slot": "dropdown-menu-sub-content",
328
+ 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),
329
+ ...props
330
+ }
331
+ );
332
+ }
333
+
334
+ // scaffold/src/components/ui/select.tsx
335
+ import { CheckIcon as CheckIcon2, ChevronDownIcon } from "lucide-react";
336
+ import { Select as SelectPrimitive } from "radix-ui";
337
+ import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
157
338
  function Select(props) {
158
- return /* @__PURE__ */ jsx3(SelectPrimitive.Root, { "data-slot": "select", ...props });
339
+ return /* @__PURE__ */ jsx4(SelectPrimitive.Root, { "data-slot": "select", ...props });
159
340
  }
160
341
  function SelectValue(props) {
161
- return /* @__PURE__ */ jsx3(SelectPrimitive.Value, { "data-slot": "select-value", ...props });
342
+ return /* @__PURE__ */ jsx4(SelectPrimitive.Value, { "data-slot": "select-value", ...props });
162
343
  }
163
344
  function SelectTrigger({
164
345
  children,
165
346
  className,
166
347
  ...props
167
348
  }) {
168
- return /* @__PURE__ */ jsxs(
349
+ return /* @__PURE__ */ jsxs2(
169
350
  SelectPrimitive.Trigger,
170
351
  {
171
352
  className: cn(
@@ -176,7 +357,7 @@ function SelectTrigger({
176
357
  ...props,
177
358
  children: [
178
359
  children,
179
- /* @__PURE__ */ jsx3(SelectPrimitive.Icon, { asChild: true, children: /* @__PURE__ */ jsx3(ChevronDownIcon, { className: "size-3.5 shrink-0 text-muted-foreground" }) })
360
+ /* @__PURE__ */ jsx4(SelectPrimitive.Icon, { asChild: true, children: /* @__PURE__ */ jsx4(ChevronDownIcon, { className: "size-3.5 shrink-0 text-muted-foreground" }) })
180
361
  ]
181
362
  }
182
363
  );
@@ -189,7 +370,7 @@ function SelectContent({
189
370
  ...props
190
371
  }) {
191
372
  const container = useThemePortalContainer();
192
- return /* @__PURE__ */ jsx3(SelectPrimitive.Portal, { container: container || void 0, children: /* @__PURE__ */ jsx3(
373
+ return /* @__PURE__ */ jsx4(SelectPrimitive.Portal, { container: container || void 0, children: /* @__PURE__ */ jsx4(
193
374
  SelectPrimitive.Content,
194
375
  {
195
376
  align,
@@ -201,7 +382,7 @@ function SelectContent({
201
382
  position: "popper",
202
383
  sideOffset,
203
384
  ...props,
204
- children: /* @__PURE__ */ jsx3(SelectPrimitive.Viewport, { className: "max-h-60 overflow-y-auto p-0.5", children })
385
+ children: /* @__PURE__ */ jsx4(SelectPrimitive.Viewport, { className: "max-h-60 overflow-y-auto p-0.5", children })
205
386
  }
206
387
  ) });
207
388
  }
@@ -210,7 +391,7 @@ function SelectItem({
210
391
  className,
211
392
  ...props
212
393
  }) {
213
- return /* @__PURE__ */ jsxs(
394
+ return /* @__PURE__ */ jsxs2(
214
395
  SelectPrimitive.Item,
215
396
  {
216
397
  className: cn(
@@ -220,17 +401,17 @@ function SelectItem({
220
401
  "data-slot": "select-item",
221
402
  ...props,
222
403
  children: [
223
- /* @__PURE__ */ jsx3(SelectPrimitive.ItemText, { className: "min-w-0 truncate", children }),
224
- /* @__PURE__ */ jsx3("span", { className: "absolute right-2 flex size-3.5 items-center justify-center", children: /* @__PURE__ */ jsx3(SelectPrimitive.ItemIndicator, { children: /* @__PURE__ */ jsx3(CheckIcon, { className: "size-3.5" }) }) })
404
+ /* @__PURE__ */ jsx4(SelectPrimitive.ItemText, { className: "min-w-0 truncate", children }),
405
+ /* @__PURE__ */ jsx4("span", { className: "absolute right-2 flex size-3.5 items-center justify-center", children: /* @__PURE__ */ jsx4(SelectPrimitive.ItemIndicator, { children: /* @__PURE__ */ jsx4(CheckIcon2, { className: "size-3.5" }) }) })
225
406
  ]
226
407
  }
227
408
  );
228
409
  }
229
410
 
230
411
  // scaffold/src/components/ui/textarea.tsx
231
- import { jsx as jsx4 } from "react/jsx-runtime";
412
+ import { jsx as jsx5 } from "react/jsx-runtime";
232
413
  function Textarea({ className, ...props }) {
233
- return /* @__PURE__ */ jsx4(
414
+ return /* @__PURE__ */ jsx5(
234
415
  "textarea",
235
416
  {
236
417
  "data-slot": "textarea",
@@ -245,12 +426,12 @@ function Textarea({ className, ...props }) {
245
426
 
246
427
  // scaffold/src/components/ui/tooltip.tsx
247
428
  import { Slot as Slot2 } from "radix-ui";
248
- import { jsx as jsx5 } from "react/jsx-runtime";
429
+ import { jsx as jsx6 } from "react/jsx-runtime";
249
430
  function TooltipProvider({ children }) {
250
431
  return children;
251
432
  }
252
433
  function Tooltip({ className, ...props }) {
253
- return /* @__PURE__ */ jsx5(
434
+ return /* @__PURE__ */ jsx6(
254
435
  "span",
255
436
  {
256
437
  "data-slot": "tooltip",
@@ -263,7 +444,7 @@ function TooltipTrigger({
263
444
  asChild: _asChild,
264
445
  ...props
265
446
  }) {
266
- return /* @__PURE__ */ jsx5(Slot2.Root, { "data-slot": "tooltip-trigger", ...props });
447
+ return /* @__PURE__ */ jsx6(Slot2.Root, { "data-slot": "tooltip-trigger", ...props });
267
448
  }
268
449
  function TooltipContent({
269
450
  className,
@@ -272,7 +453,7 @@ function TooltipContent({
272
453
  sideOffset: _sideOffset,
273
454
  ...props
274
455
  }) {
275
- return /* @__PURE__ */ jsx5(
456
+ return /* @__PURE__ */ jsx6(
276
457
  "span",
277
458
  {
278
459
  role: "tooltip",
@@ -292,17 +473,21 @@ function TooltipContent({
292
473
  }
293
474
 
294
475
  // scaffold/src/components/chat/chat-composer.tsx
295
- import { Fragment, jsx as jsx6, jsxs as jsxs2 } from "react/jsx-runtime";
476
+ import { Fragment, jsx as jsx7, jsxs as jsxs3 } from "react/jsx-runtime";
296
477
  function ChatComposer({
297
478
  inputContract,
298
479
  disabled,
299
480
  contextWindow,
481
+ focusKey,
300
482
  forceExpanded = false,
301
483
  isCancelling = false,
302
484
  isRunning,
485
+ agentId,
486
+ agents,
303
487
  modelId,
304
488
  models,
305
489
  onModelChange,
490
+ onAgentChange,
306
491
  onStop,
307
492
  onSubmit,
308
493
  utilityRow = "inline"
@@ -312,34 +497,73 @@ function ChatComposer({
312
497
  const [attachmentError, setAttachmentError] = React2.useState(null);
313
498
  const inputRef = React2.useRef(null);
314
499
  const textareaRef = React2.useRef(null);
500
+ const filesRef = React2.useRef([]);
501
+ const inFlightFilesRef = React2.useRef([]);
315
502
  const submittingRef = React2.useRef(false);
316
503
  const draftRevisionRef = React2.useRef(0);
317
504
  const attachmentMimeTypes = inputMimeTypes(inputContract);
318
505
  const allowAttachments = attachmentMimeTypes.length > 0;
319
506
  const recordingAllowed = inputContract.modalities.audio.recording_enabled;
507
+ React2.useEffect(() => {
508
+ filesRef.current = files;
509
+ }, [files]);
510
+ React2.useEffect(() => () => {
511
+ revokeAgentChatComposerFiles(filesRef.current);
512
+ revokeAgentChatComposerFiles(inFlightFilesRef.current);
513
+ }, []);
514
+ React2.useEffect(() => {
515
+ if (disabled || isRunning) return;
516
+ const frame = window.requestAnimationFrame(() => textareaRef.current?.focus({ preventScroll: true }));
517
+ return () => window.cancelAnimationFrame(frame);
518
+ }, [disabled, focusKey, isRunning]);
320
519
  const addRecording = React2.useCallback((file) => {
321
520
  draftRevisionRef.current += 1;
322
- setFiles((current) => [...current, file]);
521
+ setFiles((current) => [...current, createAgentChatComposerFile(file)]);
323
522
  }, []);
324
523
  const recorder = useAudioRecorder(addRecording);
325
524
  const isExpanded = forceExpanded || text.includes("\n") || text.length > 62;
326
525
  const validationError = validateAgentChatSubmission(
327
526
  inputContract,
328
527
  text,
329
- files.map((file) => ({ data: file, mediaType: file.type }))
528
+ files.map((file) => ({ data: file.source, mediaType: file.mediaType }))
330
529
  );
331
- const modelSelector = models.length > 0 ? /* @__PURE__ */ jsx6("div", { className: "w-fit max-w-40", children: /* @__PURE__ */ jsxs2(
332
- Select,
333
- {
334
- disabled: disabled || isRunning,
335
- onValueChange: onModelChange,
336
- value: modelId || void 0,
337
- children: [
338
- /* @__PURE__ */ jsx6(SelectTrigger, { "aria-label": "Runtime model", children: /* @__PURE__ */ jsx6(SelectValue, { placeholder: "Model" }) }),
339
- /* @__PURE__ */ jsx6(SelectContent, { align: "start", children: models.map((model) => /* @__PURE__ */ jsx6(SelectItem, { value: model.id, children: model.label }, model.id)) })
340
- ]
341
- }
342
- ) }) : null;
530
+ const selectedAgent = agents.find((item) => item.id === agentId);
531
+ const selectedModel = models.find((item) => item.id === modelId);
532
+ const modelSelector = models.length > 0 ? /* @__PURE__ */ jsx7("div", { className: "w-fit max-w-40", children: /* @__PURE__ */ jsxs3(Select, { disabled: disabled || isRunning, onValueChange: onModelChange, value: modelId || void 0, children: [
533
+ /* @__PURE__ */ jsx7(SelectTrigger, { "aria-label": "Runtime model", children: /* @__PURE__ */ jsx7(SelectValue, { placeholder: "Model" }) }),
534
+ /* @__PURE__ */ jsx7(SelectContent, { align: "start", children: models.map((model) => /* @__PURE__ */ jsx7(SelectItem, { value: model.id, children: model.label }, model.id)) })
535
+ ] }) }) : null;
536
+ const runtimeSelector = agents.length > 1 ? /* @__PURE__ */ jsxs3(DropdownMenu, { children: [
537
+ /* @__PURE__ */ jsx7(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxs3(
538
+ Button,
539
+ {
540
+ variant: "ghost",
541
+ 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",
542
+ disabled: disabled || isRunning,
543
+ "aria-label": "Runtime configuration",
544
+ children: [
545
+ /* @__PURE__ */ jsx7("span", { className: "truncate", children: [selectedAgent?.label, selectedModel?.label].filter(Boolean).join(" \xB7 ") || "Runtime" }),
546
+ /* @__PURE__ */ jsx7(ChevronDown, { className: "size-3.5 text-muted-foreground" })
547
+ ]
548
+ }
549
+ ) }),
550
+ /* @__PURE__ */ jsxs3(DropdownMenuContent, { align: "start", className: "w-64 rounded-lg", children: [
551
+ /* @__PURE__ */ jsxs3(DropdownMenuSub, { children: [
552
+ /* @__PURE__ */ jsxs3(DropdownMenuSubTrigger, { className: "rounded-lg", children: [
553
+ /* @__PURE__ */ jsx7("span", { children: "Agent" }),
554
+ /* @__PURE__ */ jsx7("span", { className: "ml-auto max-w-32 truncate text-muted-foreground", children: selectedAgent?.label })
555
+ ] }),
556
+ /* @__PURE__ */ jsx7(DropdownMenuSubContent, { className: "w-56 rounded-lg", children: /* @__PURE__ */ jsx7(DropdownMenuRadioGroup, { value: agentId || void 0, onValueChange: onAgentChange, children: agents.map((agent) => /* @__PURE__ */ jsx7(DropdownMenuRadioItem, { className: "rounded-lg", value: agent.id, children: agent.label }, agent.id)) }) })
557
+ ] }),
558
+ models.length > 0 ? /* @__PURE__ */ jsxs3(DropdownMenuSub, { children: [
559
+ /* @__PURE__ */ jsxs3(DropdownMenuSubTrigger, { className: "rounded-lg", children: [
560
+ /* @__PURE__ */ jsx7("span", { children: "Model" }),
561
+ /* @__PURE__ */ jsx7("span", { className: "ml-auto max-w-32 truncate text-muted-foreground", children: selectedModel?.label })
562
+ ] }),
563
+ /* @__PURE__ */ jsx7(DropdownMenuSubContent, { className: "max-h-64 w-56 rounded-lg", children: /* @__PURE__ */ jsx7(DropdownMenuRadioGroup, { value: modelId || void 0, onValueChange: onModelChange, children: models.map((model) => /* @__PURE__ */ jsx7(DropdownMenuRadioItem, { className: "rounded-lg", value: model.id, children: model.label }, model.id)) }) })
564
+ ] }) : null
565
+ ] })
566
+ ] }) : modelSelector;
343
567
  const hasContextWindow = Number.isFinite(Number(contextWindow?.max_tokens)) && Number(contextWindow?.max_tokens) > 0;
344
568
  const showUtilityRow = utilityRow === "below";
345
569
  const submit = async () => {
@@ -349,36 +573,51 @@ function ChatComposer({
349
573
  const clearedRevision = draftRevisionRef.current + 1;
350
574
  draftRevisionRef.current = clearedRevision;
351
575
  submittingRef.current = true;
576
+ inFlightFilesRef.current = selectedFiles;
352
577
  setText("");
353
578
  setFiles([]);
354
579
  textareaRef.current?.focus();
355
580
  try {
356
581
  await onSubmit(value, selectedFiles);
582
+ revokeAgentChatComposerFiles(selectedFiles);
583
+ inFlightFilesRef.current = [];
357
584
  } catch {
358
585
  if (draftRevisionRef.current === clearedRevision) {
359
586
  draftRevisionRef.current += 1;
360
587
  setText(value);
361
588
  setFiles(selectedFiles);
589
+ inFlightFilesRef.current = [];
590
+ } else {
591
+ revokeAgentChatComposerFiles(selectedFiles);
592
+ inFlightFilesRef.current = [];
362
593
  }
363
594
  } finally {
364
595
  submittingRef.current = false;
365
596
  }
366
597
  };
367
- return /* @__PURE__ */ jsxs2(
598
+ return /* @__PURE__ */ jsxs3(
368
599
  "div",
369
600
  {
370
601
  className: "mx-auto w-full max-w-3xl px-4 pb-[max(1rem,env(safe-area-inset-bottom))] sm:px-6",
371
602
  "data-agents24-chat-composer": "",
372
603
  children: [
373
- allowAttachments && files.length > 0 && /* @__PURE__ */ jsx6("div", { className: "mb-2 flex min-w-0 gap-2 overflow-x-auto", children: files.map((file, index) => /* @__PURE__ */ jsxs2("div", { className: "flex max-w-48 items-center gap-2 border bg-card px-2 py-1 text-xs", children: [
374
- /* @__PURE__ */ jsx6("span", { className: "truncate", children: file.name }),
375
- /* @__PURE__ */ jsx6(Button, { variant: "ghost", size: "icon-xs", "aria-label": `Remove ${file.name}`, onClick: () => {
376
- draftRevisionRef.current += 1;
377
- setFiles((current) => current.filter((_, itemIndex) => itemIndex !== index));
378
- }, children: /* @__PURE__ */ jsx6(X, {}) })
379
- ] }, `${file.name}-${index}`)) }),
380
- attachmentError || recorder.error ? /* @__PURE__ */ jsx6("p", { className: "mb-2 text-xs text-destructive", role: "alert", children: attachmentError || recorder.error }) : null,
381
- /* @__PURE__ */ jsxs2(
604
+ allowAttachments && files.length > 0 && /* @__PURE__ */ jsx7("div", { className: "mb-2 min-w-0", children: /* @__PURE__ */ jsx7(
605
+ ChatAttachmentRows,
606
+ {
607
+ attachments: files,
608
+ onRemove: (attachment) => {
609
+ if (!attachment.id) return;
610
+ draftRevisionRef.current += 1;
611
+ setFiles((current) => {
612
+ const removed = current.find((file) => file.id === attachment.id);
613
+ if (removed) revokeAgentChatComposerFiles([removed]);
614
+ return current.filter((file) => file.id !== attachment.id);
615
+ });
616
+ }
617
+ }
618
+ ) }),
619
+ attachmentError || recorder.error ? /* @__PURE__ */ jsx7("p", { className: "mb-2 text-xs text-destructive", role: "alert", children: attachmentError || recorder.error }) : null,
620
+ /* @__PURE__ */ jsxs3(
382
621
  "div",
383
622
  {
384
623
  "data-expanded": isExpanded || void 0,
@@ -387,8 +626,8 @@ function ChatComposer({
387
626
  isExpanded ? "p-2" : "p-1.5"
388
627
  ),
389
628
  children: [
390
- allowAttachments ? /* @__PURE__ */ jsxs2(Fragment, { children: [
391
- /* @__PURE__ */ jsx6(
629
+ allowAttachments ? /* @__PURE__ */ jsxs3(Fragment, { children: [
630
+ /* @__PURE__ */ jsx7(
392
631
  "input",
393
632
  {
394
633
  ref: inputRef,
@@ -400,7 +639,7 @@ function ChatComposer({
400
639
  const selected = Array.from(event.target.files ?? []);
401
640
  const accepted = selected.filter((file) => attachmentMimeTypes.includes(canonicalInputMimeType(file.type)));
402
641
  draftRevisionRef.current += 1;
403
- setFiles((current) => [...current, ...accepted]);
642
+ setFiles((current) => [...current, ...accepted.map(createAgentChatComposerFile)]);
404
643
  setAttachmentError(
405
644
  accepted.length === selected.length ? null : "One or more selected file types are not supported by this Agent."
406
645
  );
@@ -408,9 +647,9 @@ function ChatComposer({
408
647
  }
409
648
  }
410
649
  ),
411
- /* @__PURE__ */ jsx6("div", { className: "agents24-composer-attach flex min-w-0 items-center", children: /* @__PURE__ */ jsx6(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__ */ jsx6("span", { "aria-hidden": true, children: "+" }) }) })
412
- ] }) : /* @__PURE__ */ jsx6("span", { "aria-hidden": "true", className: "agents24-composer-attach" }),
413
- /* @__PURE__ */ jsx6(
650
+ /* @__PURE__ */ jsx7("div", { className: "agents24-composer-attach flex min-w-0 items-center", children: /* @__PURE__ */ jsx7(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__ */ jsx7("span", { "aria-hidden": true, children: "+" }) }) })
651
+ ] }) : /* @__PURE__ */ jsx7("span", { "aria-hidden": "true", className: "agents24-composer-attach" }),
652
+ /* @__PURE__ */ jsx7(
414
653
  Textarea,
415
654
  {
416
655
  ref: textareaRef,
@@ -435,10 +674,10 @@ function ChatComposer({
435
674
  }
436
675
  }
437
676
  ),
438
- /* @__PURE__ */ jsxs2("div", { className: "agents24-composer-actions flex items-center gap-1", children: [
439
- utilityRow === "inline" ? /* @__PURE__ */ jsx6(AgentChatContextStatus, { contextWindow }) : null,
440
- utilityRow === "inline" ? modelSelector : null,
441
- recordingAllowed ? /* @__PURE__ */ jsx6(
677
+ /* @__PURE__ */ jsxs3("div", { className: "agents24-composer-actions flex items-center gap-1", children: [
678
+ utilityRow === "inline" ? /* @__PURE__ */ jsx7(AgentChatContextStatus, { contextWindow }) : null,
679
+ utilityRow === "inline" ? runtimeSelector : null,
680
+ recordingAllowed ? /* @__PURE__ */ jsx7(
442
681
  Button,
443
682
  {
444
683
  variant: recorder.isRecording ? "default" : "ghost",
@@ -449,35 +688,35 @@ function ChatComposer({
449
688
  if (recorder.isRecording) recorder.stop();
450
689
  else void recorder.start();
451
690
  },
452
- children: recorder.isRecording ? /* @__PURE__ */ jsx6(Square, { className: "fill-current" }) : /* @__PURE__ */ jsx6(Mic, {})
691
+ children: recorder.isRecording ? /* @__PURE__ */ jsx7(Square, { className: "fill-current" }) : /* @__PURE__ */ jsx7(Mic, {})
453
692
  }
454
693
  ) : null,
455
- isRunning ? /* @__PURE__ */ jsx6(
694
+ isRunning ? /* @__PURE__ */ jsx7(
456
695
  Button,
457
696
  {
458
697
  size: "icon",
459
698
  "aria-label": isCancelling ? "Cancelling response" : "Stop response",
460
699
  disabled: disabled || isCancelling,
461
700
  onClick: onStop,
462
- children: isCancelling ? /* @__PURE__ */ jsx6(LoaderCircle, { className: "animate-spin" }) : /* @__PURE__ */ jsx6(Square, { className: "fill-current" })
701
+ children: isCancelling ? /* @__PURE__ */ jsx7(LoaderCircle, { className: "animate-spin" }) : /* @__PURE__ */ jsx7(Square, { className: "fill-current" })
463
702
  }
464
- ) : validationError ? /* @__PURE__ */ jsxs2(Tooltip, { tabIndex: 0, children: [
465
- /* @__PURE__ */ jsx6(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx6(Button, { size: "icon", "aria-label": "Send message", disabled: true, onClick: () => void submit(), children: /* @__PURE__ */ jsx6(ArrowUp, {}) }) }),
466
- /* @__PURE__ */ jsx6(TooltipContent, { children: validationError })
467
- ] }) : /* @__PURE__ */ jsx6(Button, { size: "icon", "aria-label": "Send message", disabled, onClick: () => void submit(), children: /* @__PURE__ */ jsx6(ArrowUp, {}) })
703
+ ) : validationError ? /* @__PURE__ */ jsxs3(Tooltip, { tabIndex: 0, children: [
704
+ /* @__PURE__ */ jsx7(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx7(Button, { size: "icon", "aria-label": "Send message", disabled: true, onClick: () => void submit(), children: /* @__PURE__ */ jsx7(ArrowUp, {}) }) }),
705
+ /* @__PURE__ */ jsx7(TooltipContent, { children: validationError })
706
+ ] }) : /* @__PURE__ */ jsx7(Button, { size: "icon", "aria-label": "Send message", disabled, onClick: () => void submit(), children: /* @__PURE__ */ jsx7(ArrowUp, {}) })
468
707
  ] })
469
708
  ]
470
709
  }
471
710
  ),
472
- showUtilityRow ? /* @__PURE__ */ jsxs2(
711
+ showUtilityRow ? /* @__PURE__ */ jsxs3(
473
712
  "div",
474
713
  {
475
- "aria-hidden": !modelSelector && !hasContextWindow ? "true" : void 0,
714
+ "aria-hidden": !runtimeSelector && !hasContextWindow ? "true" : void 0,
476
715
  className: "mt-2 flex min-h-8 items-center justify-between gap-2 px-1",
477
716
  "data-agents24-chat-composer-utility": "",
478
717
  children: [
479
- /* @__PURE__ */ jsx6("div", { className: "min-w-0", children: modelSelector }),
480
- /* @__PURE__ */ jsx6(AgentChatContextStatus, { contextWindow })
718
+ /* @__PURE__ */ jsx7("div", { className: "min-w-0", children: runtimeSelector }),
719
+ /* @__PURE__ */ jsx7(AgentChatContextStatus, { contextWindow })
481
720
  ]
482
721
  }
483
722
  ) : null
@@ -487,7 +726,7 @@ function ChatComposer({
487
726
  }
488
727
 
489
728
  // scaffold/src/components/chat/chat-message.tsx
490
- import { AgentChatDefaultActions, ChatAttachment, ChatAttachments } from "@agents24/chat-react/ui";
729
+ import { AgentChatDefaultActions, ChatAttachmentRows as ChatAttachmentRows2 } from "@agents24/chat-react/ui";
491
730
 
492
731
  // scaffold/src/components/chat/message-parts.tsx
493
732
  import {
@@ -496,17 +735,17 @@ import {
496
735
  } from "@agents24/chat-react/ui";
497
736
 
498
737
  // scaffold/src/components/chat/collapsible-user-message.tsx
499
- import { ChevronDown, ChevronUp } from "lucide-react";
738
+ import { ChevronDown as ChevronDown2, ChevronUp } from "lucide-react";
500
739
  import * as React3 from "react";
501
- import { jsx as jsx7, jsxs as jsxs3 } from "react/jsx-runtime";
740
+ import { jsx as jsx8, jsxs as jsxs4 } from "react/jsx-runtime";
502
741
  var collapseThreshold = 360;
503
742
  function CollapsibleUserMessage({ content }) {
504
743
  const [expanded, setExpanded] = React3.useState(false);
505
744
  const contentId = React3.useId();
506
745
  const collapsible = content.length > collapseThreshold;
507
- const Icon = expanded ? ChevronUp : ChevronDown;
508
- return /* @__PURE__ */ jsxs3("div", { className: "flex min-w-0 flex-col gap-2", children: [
509
- /* @__PURE__ */ jsx7(
746
+ const Icon = expanded ? ChevronUp : ChevronDown2;
747
+ return /* @__PURE__ */ jsxs4("div", { className: "flex min-w-0 flex-col gap-2", children: [
748
+ /* @__PURE__ */ jsx8(
510
749
  "div",
511
750
  {
512
751
  id: contentId,
@@ -514,7 +753,7 @@ function CollapsibleUserMessage({ content }) {
514
753
  children: content
515
754
  }
516
755
  ),
517
- collapsible && /* @__PURE__ */ jsxs3(
756
+ collapsible && /* @__PURE__ */ jsxs4(
518
757
  Button,
519
758
  {
520
759
  variant: "ghost",
@@ -526,7 +765,7 @@ function CollapsibleUserMessage({ content }) {
526
765
  onClick: () => setExpanded((value) => !value),
527
766
  children: [
528
767
  expanded ? "Show less" : "Show more",
529
- /* @__PURE__ */ jsx7(Icon, {})
768
+ /* @__PURE__ */ jsx8(Icon, {})
530
769
  ]
531
770
  }
532
771
  )
@@ -539,24 +778,24 @@ import * as React4 from "react";
539
778
  // scaffold/src/components/ui/dialog.tsx
540
779
  import { Dialog as DialogPrimitive } from "radix-ui";
541
780
  import { XIcon } from "lucide-react";
542
- import { jsx as jsx8, jsxs as jsxs4 } from "react/jsx-runtime";
781
+ import { jsx as jsx9, jsxs as jsxs5 } from "react/jsx-runtime";
543
782
  function Dialog({
544
783
  ...props
545
784
  }) {
546
- return /* @__PURE__ */ jsx8(DialogPrimitive.Root, { "data-slot": "dialog", ...props });
785
+ return /* @__PURE__ */ jsx9(DialogPrimitive.Root, { "data-slot": "dialog", ...props });
547
786
  }
548
787
  function DialogPortal({
549
788
  container,
550
789
  ...props
551
790
  }) {
552
791
  const themeContainer = useThemePortalContainer();
553
- return /* @__PURE__ */ jsx8(DialogPrimitive.Portal, { container: container || themeContainer || void 0, "data-slot": "dialog-portal", ...props });
792
+ return /* @__PURE__ */ jsx9(DialogPrimitive.Portal, { container: container || themeContainer || void 0, "data-slot": "dialog-portal", ...props });
554
793
  }
555
794
  function DialogOverlay({
556
795
  className,
557
796
  ...props
558
797
  }) {
559
- return /* @__PURE__ */ jsx8(
798
+ return /* @__PURE__ */ jsx9(
560
799
  DialogPrimitive.Overlay,
561
800
  {
562
801
  "data-slot": "dialog-overlay",
@@ -574,9 +813,9 @@ function DialogContent({
574
813
  showCloseButton = true,
575
814
  ...props
576
815
  }) {
577
- return /* @__PURE__ */ jsxs4(DialogPortal, { children: [
578
- /* @__PURE__ */ jsx8(DialogOverlay, {}),
579
- /* @__PURE__ */ jsxs4(
816
+ return /* @__PURE__ */ jsxs5(DialogPortal, { children: [
817
+ /* @__PURE__ */ jsx9(DialogOverlay, {}),
818
+ /* @__PURE__ */ jsxs5(
580
819
  DialogPrimitive.Content,
581
820
  {
582
821
  "data-slot": "dialog-content",
@@ -587,18 +826,18 @@ function DialogContent({
587
826
  ...props,
588
827
  children: [
589
828
  children,
590
- showCloseButton && /* @__PURE__ */ jsx8(DialogPrimitive.Close, { "data-slot": "dialog-close", asChild: true, children: /* @__PURE__ */ jsxs4(
829
+ showCloseButton && /* @__PURE__ */ jsx9(DialogPrimitive.Close, { "data-slot": "dialog-close", asChild: true, children: /* @__PURE__ */ jsxs5(
591
830
  Button,
592
831
  {
593
832
  variant: "ghost",
594
833
  className: "absolute top-4 right-4 bg-secondary",
595
834
  size: "icon-sm",
596
835
  children: [
597
- /* @__PURE__ */ jsx8(
836
+ /* @__PURE__ */ jsx9(
598
837
  XIcon,
599
838
  {}
600
839
  ),
601
- /* @__PURE__ */ jsx8("span", { className: "sr-only", children: "Close" })
840
+ /* @__PURE__ */ jsx9("span", { className: "sr-only", children: "Close" })
602
841
  ]
603
842
  }
604
843
  ) })
@@ -608,7 +847,7 @@ function DialogContent({
608
847
  ] });
609
848
  }
610
849
  function DialogHeader({ className, ...props }) {
611
- return /* @__PURE__ */ jsx8(
850
+ return /* @__PURE__ */ jsx9(
612
851
  "div",
613
852
  {
614
853
  "data-slot": "dialog-header",
@@ -623,7 +862,7 @@ function DialogFooter({
623
862
  children,
624
863
  ...props
625
864
  }) {
626
- return /* @__PURE__ */ jsxs4(
865
+ return /* @__PURE__ */ jsxs5(
627
866
  "div",
628
867
  {
629
868
  "data-slot": "dialog-footer",
@@ -634,7 +873,7 @@ function DialogFooter({
634
873
  ...props,
635
874
  children: [
636
875
  children,
637
- showCloseButton && /* @__PURE__ */ jsx8(DialogPrimitive.Close, { asChild: true, children: /* @__PURE__ */ jsx8(Button, { variant: "outline", children: "Close" }) })
876
+ showCloseButton && /* @__PURE__ */ jsx9(DialogPrimitive.Close, { asChild: true, children: /* @__PURE__ */ jsx9(Button, { variant: "outline", children: "Close" }) })
638
877
  ]
639
878
  }
640
879
  );
@@ -643,7 +882,7 @@ function DialogTitle({
643
882
  className,
644
883
  ...props
645
884
  }) {
646
- return /* @__PURE__ */ jsx8(
885
+ return /* @__PURE__ */ jsx9(
647
886
  DialogPrimitive.Title,
648
887
  {
649
888
  "data-slot": "dialog-title",
@@ -659,7 +898,7 @@ function DialogDescription({
659
898
  className,
660
899
  ...props
661
900
  }) {
662
- return /* @__PURE__ */ jsx8(
901
+ return /* @__PURE__ */ jsx9(
663
902
  DialogPrimitive.Description,
664
903
  {
665
904
  "data-slot": "dialog-description",
@@ -673,7 +912,7 @@ function DialogDescription({
673
912
  }
674
913
 
675
914
  // scaffold/src/components/chat/external-link-dialog.tsx
676
- import { jsx as jsx9, jsxs as jsxs5 } from "react/jsx-runtime";
915
+ import { jsx as jsx10, jsxs as jsxs6 } from "react/jsx-runtime";
677
916
  function ExternalLinkDialog({ isOpen, onClose, onConfirm, url }) {
678
917
  const [copied, setCopied] = React4.useState(false);
679
918
  React4.useEffect(() => {
@@ -687,29 +926,29 @@ function ExternalLinkDialog({ isOpen, onClose, onConfirm, url }) {
687
926
  onConfirm();
688
927
  onClose();
689
928
  };
690
- return /* @__PURE__ */ jsx9(Dialog, { open: isOpen, onOpenChange: (open) => {
929
+ return /* @__PURE__ */ jsx10(Dialog, { open: isOpen, onOpenChange: (open) => {
691
930
  if (!open) onClose();
692
- }, children: /* @__PURE__ */ jsxs5(DialogContent, { className: "max-h-[calc(100dvh-2rem)] min-w-0 overflow-hidden sm:max-w-md", children: [
693
- /* @__PURE__ */ jsxs5(DialogHeader, { children: [
694
- /* @__PURE__ */ jsx9(DialogTitle, { children: "Open external link?" }),
695
- /* @__PURE__ */ jsx9(DialogDescription, { children: "You\u2019re about to visit an external website." })
931
+ }, children: /* @__PURE__ */ jsxs6(DialogContent, { className: "max-h-[calc(100dvh-2rem)] min-w-0 overflow-hidden sm:max-w-md", children: [
932
+ /* @__PURE__ */ jsxs6(DialogHeader, { children: [
933
+ /* @__PURE__ */ jsx10(DialogTitle, { children: "Open external link?" }),
934
+ /* @__PURE__ */ jsx10(DialogDescription, { children: "You\u2019re about to visit an external website." })
696
935
  ] }),
697
- /* @__PURE__ */ jsx9("div", { className: "max-h-32 overflow-auto rounded-md bg-muted p-3 font-mono text-xs wrap-break-word", children: url }),
698
- /* @__PURE__ */ jsxs5(DialogFooter, { children: [
699
- /* @__PURE__ */ jsx9(Button, { variant: "outline", onClick: () => void copyUrl(), children: copied ? "Copied" : "Copy link" }),
700
- /* @__PURE__ */ jsx9(Button, { onClick: openUrl, children: "Open link" })
936
+ /* @__PURE__ */ jsx10("div", { className: "max-h-32 overflow-auto rounded-md bg-muted p-3 font-mono text-xs wrap-break-word", children: url }),
937
+ /* @__PURE__ */ jsxs6(DialogFooter, { children: [
938
+ /* @__PURE__ */ jsx10(Button, { variant: "outline", onClick: () => void copyUrl(), children: copied ? "Copied" : "Copy link" }),
939
+ /* @__PURE__ */ jsx10(Button, { onClick: openUrl, children: "Open link" })
701
940
  ] })
702
941
  ] }) });
703
942
  }
704
943
 
705
944
  // scaffold/src/components/chat/message-parts.tsx
706
- import { Fragment as Fragment2, jsx as jsx10, jsxs as jsxs6 } from "react/jsx-runtime";
945
+ import { Fragment as Fragment2, jsx as jsx11, jsxs as jsxs7 } from "react/jsx-runtime";
707
946
  var linkSafety = {
708
947
  enabled: true,
709
- renderModal: (props) => /* @__PURE__ */ jsx10(ExternalLinkDialog, { ...props })
948
+ renderModal: (props) => /* @__PURE__ */ jsx11(ExternalLinkDialog, { ...props })
710
949
  };
711
950
  function ScaffoldTimeline(props) {
712
- return /* @__PURE__ */ jsx10(
951
+ return /* @__PURE__ */ jsx11(
713
952
  AgentResponseTimeline,
714
953
  {
715
954
  ...props,
@@ -728,7 +967,7 @@ function MessageParts({
728
967
  Timeline = ScaffoldTimeline
729
968
  }) {
730
969
  if (message.role === "assistant") {
731
- return /* @__PURE__ */ jsx10(
970
+ return /* @__PURE__ */ jsx11(
732
971
  Timeline,
733
972
  {
734
973
  getHitlActionState,
@@ -743,8 +982,8 @@ function MessageParts({
743
982
  }
744
983
  const text = message.parts.filter((part) => part.kind === "text").map((part) => part.kind === "text" ? part.text : "").join("") || message.content;
745
984
  const supportingParts = message.parts.filter((part) => part.kind !== "text" && part.kind !== "data");
746
- return /* @__PURE__ */ jsxs6(Fragment2, { children: [
747
- supportingParts.map((part) => /* @__PURE__ */ jsx10(
985
+ return /* @__PURE__ */ jsxs7(Fragment2, { children: [
986
+ supportingParts.map((part) => /* @__PURE__ */ jsx11(
748
987
  AgentChatPart,
749
988
  {
750
989
  getHitlActionState,
@@ -756,14 +995,14 @@ function MessageParts({
756
995
  },
757
996
  part.id
758
997
  )),
759
- text ? /* @__PURE__ */ jsx10(CollapsibleUserMessage, { content: text }) : null
998
+ text ? /* @__PURE__ */ jsx11(CollapsibleUserMessage, { content: text }) : null
760
999
  ] });
761
1000
  }
762
1001
 
763
1002
  // scaffold/src/components/ui/bubble.tsx
764
1003
  import { cva as cva2 } from "class-variance-authority";
765
1004
  import { Slot as Slot3 } from "radix-ui";
766
- import { jsx as jsx11 } from "react/jsx-runtime";
1005
+ import { jsx as jsx12 } from "react/jsx-runtime";
767
1006
  var bubbleVariants = cva2(
768
1007
  "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",
769
1008
  {
@@ -789,7 +1028,7 @@ function Bubble({
789
1028
  className,
790
1029
  ...props
791
1030
  }) {
792
- return /* @__PURE__ */ jsx11(
1031
+ return /* @__PURE__ */ jsx12(
793
1032
  "div",
794
1033
  {
795
1034
  "data-slot": "bubble",
@@ -806,7 +1045,7 @@ function BubbleContent({
806
1045
  ...props
807
1046
  }) {
808
1047
  const Comp = asChild ? Slot3.Root : "div";
809
- return /* @__PURE__ */ jsx11(
1048
+ return /* @__PURE__ */ jsx12(
810
1049
  Comp,
811
1050
  {
812
1051
  "data-slot": "bubble-content",
@@ -839,13 +1078,13 @@ var bubbleReactionsVariants = cva2(
839
1078
  );
840
1079
 
841
1080
  // scaffold/src/components/ui/message.tsx
842
- import { jsx as jsx12 } from "react/jsx-runtime";
1081
+ import { jsx as jsx13 } from "react/jsx-runtime";
843
1082
  function Message({
844
1083
  className,
845
1084
  align = "start",
846
1085
  ...props
847
1086
  }) {
848
- return /* @__PURE__ */ jsx12(
1087
+ return /* @__PURE__ */ jsx13(
849
1088
  "div",
850
1089
  {
851
1090
  "data-slot": "message",
@@ -859,7 +1098,7 @@ function Message({
859
1098
  );
860
1099
  }
861
1100
  function MessageContent({ className, ...props }) {
862
- return /* @__PURE__ */ jsx12(
1101
+ return /* @__PURE__ */ jsx13(
863
1102
  "div",
864
1103
  {
865
1104
  "data-slot": "message-content",
@@ -872,7 +1111,7 @@ function MessageContent({ className, ...props }) {
872
1111
  );
873
1112
  }
874
1113
  function MessageFooter({ className, ...props }) {
875
- return /* @__PURE__ */ jsx12(
1114
+ return /* @__PURE__ */ jsx13(
876
1115
  "div",
877
1116
  {
878
1117
  "data-slot": "message-footer",
@@ -886,7 +1125,7 @@ function MessageFooter({ className, ...props }) {
886
1125
  }
887
1126
 
888
1127
  // scaffold/src/components/chat/chat-message.tsx
889
- import { jsx as jsx13, jsxs as jsxs7 } from "react/jsx-runtime";
1128
+ import { jsx as jsx14, jsxs as jsxs8 } from "react/jsx-runtime";
890
1129
  function ChatMessage({
891
1130
  allowFeedback,
892
1131
  getHitlActionState,
@@ -895,18 +1134,20 @@ function ChatMessage({
895
1134
  onHitlAction,
896
1135
  onRegenerate,
897
1136
  onSetFeedback,
1137
+ resolveAttachmentContent,
898
1138
  Timeline
899
1139
  }) {
900
1140
  const isUser = message.role === "user";
901
- return /* @__PURE__ */ jsx13(Message, { align: isUser ? "end" : "start", children: /* @__PURE__ */ jsxs7(MessageContent, { children: [
902
- isUser && message.attachments?.length ? /* @__PURE__ */ jsx13(ChatAttachments, { className: "mb-2 justify-end", children: message.attachments.map((attachment, index) => /* @__PURE__ */ jsx13(
903
- ChatAttachment,
1141
+ return /* @__PURE__ */ jsx14(Message, { align: isUser ? "end" : "start", children: /* @__PURE__ */ jsxs8(MessageContent, { children: [
1142
+ isUser && message.attachments?.length ? /* @__PURE__ */ jsx14(
1143
+ ChatAttachmentRows2,
904
1144
  {
905
- data: attachment
906
- },
907
- String(attachment.id || attachment.url || attachment.filename || index)
908
- )) }) : null,
909
- /* @__PURE__ */ jsx13(Bubble, { variant: isUser ? "secondary" : "ghost", align: isUser ? "end" : "start", className: isUser ? "max-w-[min(75%,42rem)]" : "max-w-full overflow-visible", children: /* @__PURE__ */ jsx13(BubbleContent, { className: isUser ? "px-4 py-2.5" : "w-full overflow-visible", children: /* @__PURE__ */ jsx13(
1145
+ attachments: message.attachments,
1146
+ className: "mb-2",
1147
+ resolveContent: resolveAttachmentContent
1148
+ }
1149
+ ) : null,
1150
+ /* @__PURE__ */ jsx14(Bubble, { variant: isUser ? "secondary" : "ghost", align: isUser ? "end" : "start", className: isUser ? "max-w-[min(75%,42rem)]" : "max-w-full overflow-visible", children: /* @__PURE__ */ jsx14(BubbleContent, { className: isUser ? "px-4 py-2.5" : "w-full overflow-visible", children: /* @__PURE__ */ jsx14(
910
1151
  MessageParts,
911
1152
  {
912
1153
  getHitlActionState,
@@ -916,7 +1157,7 @@ function ChatMessage({
916
1157
  Timeline
917
1158
  }
918
1159
  ) }) }),
919
- !isUser && message.isFinal !== false && /* @__PURE__ */ jsx13(MessageFooter, { className: "gap-1 opacity-70 transition-opacity group-hover/message:opacity-100", children: /* @__PURE__ */ jsx13(
1160
+ !isUser && message.isFinal !== false && /* @__PURE__ */ jsx14(MessageFooter, { className: "gap-1 opacity-70 transition-opacity group-hover/message:opacity-100", children: /* @__PURE__ */ jsx14(
920
1161
  AgentChatDefaultActions,
921
1162
  {
922
1163
  handlers: {
@@ -936,7 +1177,7 @@ function ChatMessage({
936
1177
  // scaffold/src/components/chat/theme-menu.tsx
937
1178
  import { Laptop, Moon, Sun } from "lucide-react";
938
1179
  import * as React5 from "react";
939
- import { jsx as jsx14, jsxs as jsxs8 } from "react/jsx-runtime";
1180
+ import { jsx as jsx15, jsxs as jsxs9 } from "react/jsx-runtime";
940
1181
  var options = [
941
1182
  { value: "system", label: "System", icon: Laptop },
942
1183
  { value: "light", label: "Light", icon: Sun },
@@ -966,8 +1207,8 @@ function ThemeMenu() {
966
1207
  };
967
1208
  }, [open]);
968
1209
  const label = appearance === "system" ? "System" : appearance === "light" ? "Light" : "Dark";
969
- return /* @__PURE__ */ jsxs8("div", { ref: rootRef, className: "relative", children: [
970
- /* @__PURE__ */ jsx14(
1210
+ return /* @__PURE__ */ jsxs9("div", { ref: rootRef, className: "relative", children: [
1211
+ /* @__PURE__ */ jsx15(
971
1212
  Button,
972
1213
  {
973
1214
  "aria-controls": menuId,
@@ -977,16 +1218,16 @@ function ThemeMenu() {
977
1218
  onClick: () => setOpen((value) => !value),
978
1219
  size: "icon-sm",
979
1220
  variant: "ghost",
980
- children: /* @__PURE__ */ jsx14(ActiveIcon, {})
1221
+ children: /* @__PURE__ */ jsx15(ActiveIcon, {})
981
1222
  }
982
1223
  ),
983
- open ? /* @__PURE__ */ jsx14(
1224
+ open ? /* @__PURE__ */ jsx15(
984
1225
  "div",
985
1226
  {
986
1227
  id: menuId,
987
1228
  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",
988
1229
  role: "menu",
989
- children: options.map(({ value, label: optionLabel, icon: Icon }, index) => /* @__PURE__ */ jsxs8(
1230
+ children: options.map(({ value, label: optionLabel, icon: Icon }, index) => /* @__PURE__ */ jsxs9(
990
1231
  Button,
991
1232
  {
992
1233
  ref: index === 0 ? firstItemRef : void 0,
@@ -1000,7 +1241,7 @@ function ThemeMenu() {
1000
1241
  size: "sm",
1001
1242
  variant: "ghost",
1002
1243
  children: [
1003
- /* @__PURE__ */ jsx14(Icon, {}),
1244
+ /* @__PURE__ */ jsx15(Icon, {}),
1004
1245
  " ",
1005
1246
  optionLabel
1006
1247
  ]
@@ -1019,96 +1260,6 @@ import { LoaderCircle as LoaderCircle2, SquarePen, Trash2 } from "lucide-react";
1019
1260
  // scaffold/src/components/chat/identity-control.tsx
1020
1261
  import { LogIn, LogOut, UserRound } from "lucide-react";
1021
1262
 
1022
- // scaffold/src/components/ui/dropdown-menu.tsx
1023
- import { DropdownMenu as DropdownMenuPrimitive } from "radix-ui";
1024
- import { CheckIcon as CheckIcon2, ChevronRightIcon } from "lucide-react";
1025
- import { jsx as jsx15, jsxs as jsxs9 } from "react/jsx-runtime";
1026
- function DropdownMenu({
1027
- ...props
1028
- }) {
1029
- return /* @__PURE__ */ jsx15(DropdownMenuPrimitive.Root, { "data-slot": "dropdown-menu", ...props });
1030
- }
1031
- function DropdownMenuTrigger({
1032
- ...props
1033
- }) {
1034
- return /* @__PURE__ */ jsx15(
1035
- DropdownMenuPrimitive.Trigger,
1036
- {
1037
- "data-slot": "dropdown-menu-trigger",
1038
- ...props
1039
- }
1040
- );
1041
- }
1042
- function DropdownMenuContent({
1043
- className,
1044
- align = "start",
1045
- sideOffset = 4,
1046
- ...props
1047
- }) {
1048
- const themeContainer = useThemePortalContainer();
1049
- return /* @__PURE__ */ jsx15(DropdownMenuPrimitive.Portal, { container: themeContainer || void 0, children: /* @__PURE__ */ jsx15(
1050
- DropdownMenuPrimitive.Content,
1051
- {
1052
- "data-slot": "dropdown-menu-content",
1053
- sideOffset,
1054
- align,
1055
- 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),
1056
- ...props
1057
- }
1058
- ) });
1059
- }
1060
- function DropdownMenuItem({
1061
- className,
1062
- inset,
1063
- variant = "default",
1064
- ...props
1065
- }) {
1066
- return /* @__PURE__ */ jsx15(
1067
- DropdownMenuPrimitive.Item,
1068
- {
1069
- "data-slot": "dropdown-menu-item",
1070
- "data-inset": inset,
1071
- "data-variant": variant,
1072
- className: cn(
1073
- "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",
1074
- className
1075
- ),
1076
- ...props
1077
- }
1078
- );
1079
- }
1080
- function DropdownMenuLabel({
1081
- className,
1082
- inset,
1083
- ...props
1084
- }) {
1085
- return /* @__PURE__ */ jsx15(
1086
- DropdownMenuPrimitive.Label,
1087
- {
1088
- "data-slot": "dropdown-menu-label",
1089
- "data-inset": inset,
1090
- className: cn(
1091
- "px-3 py-2.5 text-xs text-muted-foreground data-inset:pl-9.5",
1092
- className
1093
- ),
1094
- ...props
1095
- }
1096
- );
1097
- }
1098
- function DropdownMenuSeparator({
1099
- className,
1100
- ...props
1101
- }) {
1102
- return /* @__PURE__ */ jsx15(
1103
- DropdownMenuPrimitive.Separator,
1104
- {
1105
- "data-slot": "dropdown-menu-separator",
1106
- className: cn("-mx-1.5 my-1.5 h-px bg-border/50", className),
1107
- ...props
1108
- }
1109
- );
1110
- }
1111
-
1112
1263
  // scaffold/src/components/ui/sidebar.tsx
1113
1264
  import * as React7 from "react";
1114
1265
  import { cva as cva3 } from "class-variance-authority";
@@ -1577,7 +1728,7 @@ function SidebarMenuItem({ className, ...props }) {
1577
1728
  );
1578
1729
  }
1579
1730
  var sidebarMenuButtonVariants = cva3(
1580
- "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",
1731
+ "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",
1581
1732
  {
1582
1733
  variants: {
1583
1734
  variant: {
@@ -1653,7 +1804,7 @@ function SidebarMenuAction({
1653
1804
  "data-sidebar": "menu-action",
1654
1805
  className: cn(
1655
1806
  "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",
1656
- 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",
1807
+ 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",
1657
1808
  className
1658
1809
  ),
1659
1810
  ...props
@@ -2023,7 +2174,7 @@ function OperationErrorNotice({ runtime }) {
2023
2174
  onClick: runtime.operationError ? runtime.clearOperationError : runtime.controller.clearBackgroundError,
2024
2175
  size: "icon-xs",
2025
2176
  variant: "ghost",
2026
- children: /* @__PURE__ */ jsx25(X2, {})
2177
+ children: /* @__PURE__ */ jsx25(X, {})
2027
2178
  }
2028
2179
  )
2029
2180
  ] }) });
@@ -2031,10 +2182,12 @@ function OperationErrorNotice({ runtime }) {
2031
2182
  function ChatShell({
2032
2183
  components,
2033
2184
  identity,
2034
- runtime
2185
+ runtime,
2186
+ sidebar
2035
2187
  }) {
2036
2188
  const { controller } = runtime;
2037
- const isRunning = controller.runState === "streaming" || controller.runState === "reconnecting" || controller.runState === "paused" || controller.runState === "cancelling" || runtime.isSubmitting;
2189
+ const isRunning = controller.runState === "streaming" || controller.runState === "reconnecting" || controller.runState === "paused" || controller.runState === "cancelling";
2190
+ const isUploading = controller.runState === "uploading" || runtime.isUploading;
2038
2191
  const isCancelling = controller.runState === "cancelling";
2039
2192
  const activeTitle = controller.threads.find((thread) => thread.id === controller.activeThreadId)?.title;
2040
2193
  const hasBlockingError = Boolean(runtime.fatalError && controller.messages.length === 0);
@@ -2047,7 +2200,7 @@ function ChatShell({
2047
2200
  "data-agents24-chat-layout": "",
2048
2201
  children: [
2049
2202
  /* @__PURE__ */ jsx25(PersistentSidebarTrigger, {}),
2050
- /* @__PURE__ */ jsx25(
2203
+ sidebar || /* @__PURE__ */ jsx25(
2051
2204
  ThreadSidebar,
2052
2205
  {
2053
2206
  activeThreadId: controller.activeThreadId,
@@ -2090,10 +2243,16 @@ function ChatShell({
2090
2243
  {
2091
2244
  inputContract: runtime.inputContract || LOADING_INPUT_CONTRACT,
2092
2245
  contextWindow: runtime.contextWindow,
2093
- disabled: runtime.isBootstrapping,
2246
+ disabled: runtime.isBootstrapping || runtime.isChangingAgent || isUploading,
2247
+ focusKey: controller.activeThreadId,
2094
2248
  forceExpanded: true,
2095
2249
  isCancelling,
2096
2250
  isRunning,
2251
+ agentId: runtime.agentId,
2252
+ agents: runtime.agents,
2253
+ onAgentChange: (agentId) => {
2254
+ void runtime.changeAgent(agentId);
2255
+ },
2097
2256
  onStop: () => {
2098
2257
  void controller.cancelRun().catch(() => void 0);
2099
2258
  },
@@ -2103,10 +2262,11 @@ function ChatShell({
2103
2262
  onSubmit: (text, files) => runtime.submit({
2104
2263
  text,
2105
2264
  files: files.map((file) => ({
2106
- data: file,
2107
- mediaType: file.type || "application/octet-stream",
2108
- name: file.name
2109
- }))
2265
+ data: file.source,
2266
+ mediaType: file.mediaType,
2267
+ name: file.filename
2268
+ })),
2269
+ attachments: files
2110
2270
  })
2111
2271
  }
2112
2272
  )
@@ -2159,6 +2319,7 @@ function ChatShell({
2159
2319
  onHitlAction: runtime.onHitlAction,
2160
2320
  onRegenerate: () => controller.regenerate(message),
2161
2321
  onSetFeedback: (input) => controller.setFeedback(message, input),
2322
+ resolveAttachmentContent: runtime.resolveAttachmentContent,
2162
2323
  Timeline: components?.Timeline
2163
2324
  }
2164
2325
  )
@@ -2178,9 +2339,15 @@ function ChatShell({
2178
2339
  {
2179
2340
  inputContract: runtime.inputContract || LOADING_INPUT_CONTRACT,
2180
2341
  contextWindow: runtime.contextWindow,
2181
- disabled: runtime.isBootstrapping || hasBlockingError,
2342
+ disabled: runtime.isBootstrapping || runtime.isChangingAgent || hasBlockingError || isUploading,
2343
+ focusKey: controller.activeThreadId,
2182
2344
  isCancelling,
2183
2345
  isRunning,
2346
+ agentId: runtime.agentId,
2347
+ agents: runtime.agents,
2348
+ onAgentChange: (agentId) => {
2349
+ void runtime.changeAgent(agentId);
2350
+ },
2184
2351
  onStop: () => {
2185
2352
  void controller.cancelRun().catch(() => void 0);
2186
2353
  },
@@ -2190,10 +2357,11 @@ function ChatShell({
2190
2357
  onSubmit: (text, files) => runtime.submit({
2191
2358
  text,
2192
2359
  files: files.map((file) => ({
2193
- data: file,
2194
- mediaType: file.type || "application/octet-stream",
2195
- name: file.name
2196
- }))
2360
+ data: file.source,
2361
+ mediaType: file.mediaType,
2362
+ name: file.filename
2363
+ })),
2364
+ attachments: files
2197
2365
  }),
2198
2366
  utilityRow: "below"
2199
2367
  }
@@ -2223,7 +2391,7 @@ function RuntimeChat({
2223
2391
  ...props,
2224
2392
  mcpRedirectUri: props.mcpRedirectUri || (typeof window === "undefined" ? void 0 : window.location.href)
2225
2393
  });
2226
- return /* @__PURE__ */ jsx26(ChatShell, { components, identity, runtime });
2394
+ return /* @__PURE__ */ jsx26(ChatShell, { components, identity, runtime, sidebar: props.sidebar });
2227
2395
  }
2228
2396
  function App(props) {
2229
2397
  const identity = props.identity || GUEST_CHAT_IDENTITY;