@agents24/chat-react 0.5.4 → 0.5.5

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.
@@ -13,7 +13,7 @@ import {
13
13
  import { CircleAlert, LoaderCircle as LoaderCircle3, SquarePen as SquarePen2, X as X2 } 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, X } from "lucide-react";
17
17
  import * as React2 from "react";
18
18
  import { AgentChatContextStatus, useAudioRecorder } from "@agents24/chat-react/ui";
19
19
  import { canonicalInputMimeType, inputMimeTypes, validateAgentChatSubmission } from "@agents24/chat-react/runtime";
@@ -32,7 +32,7 @@ function cn(...inputs) {
32
32
  // scaffold/src/components/ui/button.tsx
33
33
  import { jsx } from "react/jsx-runtime";
34
34
  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",
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 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
36
  {
37
37
  variants: {
38
38
  variant: {
@@ -80,9 +80,9 @@ function Button({
80
80
  );
81
81
  }
82
82
 
83
- // scaffold/src/components/ui/select.tsx
84
- import { CheckIcon, ChevronDownIcon } from "lucide-react";
85
- import { Select as SelectPrimitive } from "radix-ui";
83
+ // scaffold/src/components/ui/dropdown-menu.tsx
84
+ import { DropdownMenu as DropdownMenuPrimitive } from "radix-ui";
85
+ import { CheckIcon, ChevronRightIcon } from "lucide-react";
86
86
 
87
87
  // scaffold/src/components/theme-provider.tsx
88
88
  import * as React from "react";
@@ -152,20 +152,195 @@ function useThemePortalContainer() {
152
152
  return useTheme().portalContainer;
153
153
  }
154
154
 
155
- // scaffold/src/components/ui/select.tsx
155
+ // scaffold/src/components/ui/dropdown-menu.tsx
156
156
  import { jsx as jsx3, jsxs } from "react/jsx-runtime";
157
+ function DropdownMenu({
158
+ ...props
159
+ }) {
160
+ return /* @__PURE__ */ jsx3(DropdownMenuPrimitive.Root, { "data-slot": "dropdown-menu", ...props });
161
+ }
162
+ function DropdownMenuTrigger({
163
+ ...props
164
+ }) {
165
+ return /* @__PURE__ */ jsx3(
166
+ DropdownMenuPrimitive.Trigger,
167
+ {
168
+ "data-slot": "dropdown-menu-trigger",
169
+ ...props
170
+ }
171
+ );
172
+ }
173
+ function DropdownMenuContent({
174
+ className,
175
+ align = "start",
176
+ sideOffset = 4,
177
+ ...props
178
+ }) {
179
+ const themeContainer = useThemePortalContainer();
180
+ return /* @__PURE__ */ jsx3(DropdownMenuPrimitive.Portal, { container: themeContainer || void 0, children: /* @__PURE__ */ jsx3(
181
+ DropdownMenuPrimitive.Content,
182
+ {
183
+ "data-slot": "dropdown-menu-content",
184
+ sideOffset,
185
+ align,
186
+ 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),
187
+ ...props
188
+ }
189
+ ) });
190
+ }
191
+ function DropdownMenuItem({
192
+ className,
193
+ inset,
194
+ variant = "default",
195
+ ...props
196
+ }) {
197
+ return /* @__PURE__ */ jsx3(
198
+ DropdownMenuPrimitive.Item,
199
+ {
200
+ "data-slot": "dropdown-menu-item",
201
+ "data-inset": inset,
202
+ "data-variant": variant,
203
+ className: cn(
204
+ "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",
205
+ className
206
+ ),
207
+ ...props
208
+ }
209
+ );
210
+ }
211
+ function DropdownMenuRadioGroup({
212
+ ...props
213
+ }) {
214
+ return /* @__PURE__ */ jsx3(
215
+ DropdownMenuPrimitive.RadioGroup,
216
+ {
217
+ "data-slot": "dropdown-menu-radio-group",
218
+ ...props
219
+ }
220
+ );
221
+ }
222
+ function DropdownMenuRadioItem({
223
+ className,
224
+ children,
225
+ inset,
226
+ ...props
227
+ }) {
228
+ return /* @__PURE__ */ jsxs(
229
+ DropdownMenuPrimitive.RadioItem,
230
+ {
231
+ "data-slot": "dropdown-menu-radio-item",
232
+ "data-inset": inset,
233
+ className: cn(
234
+ "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",
235
+ className
236
+ ),
237
+ ...props,
238
+ children: [
239
+ /* @__PURE__ */ jsx3(
240
+ "span",
241
+ {
242
+ className: "pointer-events-none absolute right-2 flex items-center justify-center",
243
+ "data-slot": "dropdown-menu-radio-item-indicator",
244
+ children: /* @__PURE__ */ jsx3(DropdownMenuPrimitive.ItemIndicator, { children: /* @__PURE__ */ jsx3(
245
+ CheckIcon,
246
+ {}
247
+ ) })
248
+ }
249
+ ),
250
+ children
251
+ ]
252
+ }
253
+ );
254
+ }
255
+ function DropdownMenuLabel({
256
+ className,
257
+ inset,
258
+ ...props
259
+ }) {
260
+ return /* @__PURE__ */ jsx3(
261
+ DropdownMenuPrimitive.Label,
262
+ {
263
+ "data-slot": "dropdown-menu-label",
264
+ "data-inset": inset,
265
+ className: cn(
266
+ "px-3 py-2.5 text-xs text-muted-foreground data-inset:pl-9.5",
267
+ className
268
+ ),
269
+ ...props
270
+ }
271
+ );
272
+ }
273
+ function DropdownMenuSeparator({
274
+ className,
275
+ ...props
276
+ }) {
277
+ return /* @__PURE__ */ jsx3(
278
+ DropdownMenuPrimitive.Separator,
279
+ {
280
+ "data-slot": "dropdown-menu-separator",
281
+ className: cn("-mx-1.5 my-1.5 h-px bg-border/50", className),
282
+ ...props
283
+ }
284
+ );
285
+ }
286
+ function DropdownMenuSub({
287
+ ...props
288
+ }) {
289
+ return /* @__PURE__ */ jsx3(DropdownMenuPrimitive.Sub, { "data-slot": "dropdown-menu-sub", ...props });
290
+ }
291
+ function DropdownMenuSubTrigger({
292
+ className,
293
+ inset,
294
+ children,
295
+ ...props
296
+ }) {
297
+ return /* @__PURE__ */ jsxs(
298
+ DropdownMenuPrimitive.SubTrigger,
299
+ {
300
+ "data-slot": "dropdown-menu-sub-trigger",
301
+ "data-inset": inset,
302
+ className: cn(
303
+ "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",
304
+ className
305
+ ),
306
+ ...props,
307
+ children: [
308
+ children,
309
+ /* @__PURE__ */ jsx3(ChevronRightIcon, { className: "ml-auto" })
310
+ ]
311
+ }
312
+ );
313
+ }
314
+ function DropdownMenuSubContent({
315
+ className,
316
+ ...props
317
+ }) {
318
+ return /* @__PURE__ */ jsx3(
319
+ DropdownMenuPrimitive.SubContent,
320
+ {
321
+ "data-slot": "dropdown-menu-sub-content",
322
+ 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),
323
+ ...props
324
+ }
325
+ );
326
+ }
327
+
328
+ // scaffold/src/components/ui/select.tsx
329
+ import { CheckIcon as CheckIcon2, ChevronDownIcon } from "lucide-react";
330
+ import { Select as SelectPrimitive } from "radix-ui";
331
+ import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
157
332
  function Select(props) {
158
- return /* @__PURE__ */ jsx3(SelectPrimitive.Root, { "data-slot": "select", ...props });
333
+ return /* @__PURE__ */ jsx4(SelectPrimitive.Root, { "data-slot": "select", ...props });
159
334
  }
160
335
  function SelectValue(props) {
161
- return /* @__PURE__ */ jsx3(SelectPrimitive.Value, { "data-slot": "select-value", ...props });
336
+ return /* @__PURE__ */ jsx4(SelectPrimitive.Value, { "data-slot": "select-value", ...props });
162
337
  }
163
338
  function SelectTrigger({
164
339
  children,
165
340
  className,
166
341
  ...props
167
342
  }) {
168
- return /* @__PURE__ */ jsxs(
343
+ return /* @__PURE__ */ jsxs2(
169
344
  SelectPrimitive.Trigger,
170
345
  {
171
346
  className: cn(
@@ -176,7 +351,7 @@ function SelectTrigger({
176
351
  ...props,
177
352
  children: [
178
353
  children,
179
- /* @__PURE__ */ jsx3(SelectPrimitive.Icon, { asChild: true, children: /* @__PURE__ */ jsx3(ChevronDownIcon, { className: "size-3.5 shrink-0 text-muted-foreground" }) })
354
+ /* @__PURE__ */ jsx4(SelectPrimitive.Icon, { asChild: true, children: /* @__PURE__ */ jsx4(ChevronDownIcon, { className: "size-3.5 shrink-0 text-muted-foreground" }) })
180
355
  ]
181
356
  }
182
357
  );
@@ -189,7 +364,7 @@ function SelectContent({
189
364
  ...props
190
365
  }) {
191
366
  const container = useThemePortalContainer();
192
- return /* @__PURE__ */ jsx3(SelectPrimitive.Portal, { container: container || void 0, children: /* @__PURE__ */ jsx3(
367
+ return /* @__PURE__ */ jsx4(SelectPrimitive.Portal, { container: container || void 0, children: /* @__PURE__ */ jsx4(
193
368
  SelectPrimitive.Content,
194
369
  {
195
370
  align,
@@ -201,7 +376,7 @@ function SelectContent({
201
376
  position: "popper",
202
377
  sideOffset,
203
378
  ...props,
204
- children: /* @__PURE__ */ jsx3(SelectPrimitive.Viewport, { className: "max-h-60 overflow-y-auto p-0.5", children })
379
+ children: /* @__PURE__ */ jsx4(SelectPrimitive.Viewport, { className: "max-h-60 overflow-y-auto p-0.5", children })
205
380
  }
206
381
  ) });
207
382
  }
@@ -210,7 +385,7 @@ function SelectItem({
210
385
  className,
211
386
  ...props
212
387
  }) {
213
- return /* @__PURE__ */ jsxs(
388
+ return /* @__PURE__ */ jsxs2(
214
389
  SelectPrimitive.Item,
215
390
  {
216
391
  className: cn(
@@ -220,17 +395,17 @@ function SelectItem({
220
395
  "data-slot": "select-item",
221
396
  ...props,
222
397
  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" }) }) })
398
+ /* @__PURE__ */ jsx4(SelectPrimitive.ItemText, { className: "min-w-0 truncate", children }),
399
+ /* @__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
400
  ]
226
401
  }
227
402
  );
228
403
  }
229
404
 
230
405
  // scaffold/src/components/ui/textarea.tsx
231
- import { jsx as jsx4 } from "react/jsx-runtime";
406
+ import { jsx as jsx5 } from "react/jsx-runtime";
232
407
  function Textarea({ className, ...props }) {
233
- return /* @__PURE__ */ jsx4(
408
+ return /* @__PURE__ */ jsx5(
234
409
  "textarea",
235
410
  {
236
411
  "data-slot": "textarea",
@@ -245,12 +420,12 @@ function Textarea({ className, ...props }) {
245
420
 
246
421
  // scaffold/src/components/ui/tooltip.tsx
247
422
  import { Slot as Slot2 } from "radix-ui";
248
- import { jsx as jsx5 } from "react/jsx-runtime";
423
+ import { jsx as jsx6 } from "react/jsx-runtime";
249
424
  function TooltipProvider({ children }) {
250
425
  return children;
251
426
  }
252
427
  function Tooltip({ className, ...props }) {
253
- return /* @__PURE__ */ jsx5(
428
+ return /* @__PURE__ */ jsx6(
254
429
  "span",
255
430
  {
256
431
  "data-slot": "tooltip",
@@ -263,7 +438,7 @@ function TooltipTrigger({
263
438
  asChild: _asChild,
264
439
  ...props
265
440
  }) {
266
- return /* @__PURE__ */ jsx5(Slot2.Root, { "data-slot": "tooltip-trigger", ...props });
441
+ return /* @__PURE__ */ jsx6(Slot2.Root, { "data-slot": "tooltip-trigger", ...props });
267
442
  }
268
443
  function TooltipContent({
269
444
  className,
@@ -272,7 +447,7 @@ function TooltipContent({
272
447
  sideOffset: _sideOffset,
273
448
  ...props
274
449
  }) {
275
- return /* @__PURE__ */ jsx5(
450
+ return /* @__PURE__ */ jsx6(
276
451
  "span",
277
452
  {
278
453
  role: "tooltip",
@@ -292,17 +467,21 @@ function TooltipContent({
292
467
  }
293
468
 
294
469
  // scaffold/src/components/chat/chat-composer.tsx
295
- import { Fragment, jsx as jsx6, jsxs as jsxs2 } from "react/jsx-runtime";
470
+ import { Fragment, jsx as jsx7, jsxs as jsxs3 } from "react/jsx-runtime";
296
471
  function ChatComposer({
297
472
  inputContract,
298
473
  disabled,
299
474
  contextWindow,
475
+ focusKey,
300
476
  forceExpanded = false,
301
477
  isCancelling = false,
302
478
  isRunning,
479
+ agentId,
480
+ agents,
303
481
  modelId,
304
482
  models,
305
483
  onModelChange,
484
+ onAgentChange,
306
485
  onStop,
307
486
  onSubmit,
308
487
  utilityRow = "inline"
@@ -317,6 +496,11 @@ function ChatComposer({
317
496
  const attachmentMimeTypes = inputMimeTypes(inputContract);
318
497
  const allowAttachments = attachmentMimeTypes.length > 0;
319
498
  const recordingAllowed = inputContract.modalities.audio.recording_enabled;
499
+ React2.useEffect(() => {
500
+ if (disabled || isRunning) return;
501
+ const frame = window.requestAnimationFrame(() => textareaRef.current?.focus({ preventScroll: true }));
502
+ return () => window.cancelAnimationFrame(frame);
503
+ }, [disabled, focusKey, isRunning]);
320
504
  const addRecording = React2.useCallback((file) => {
321
505
  draftRevisionRef.current += 1;
322
506
  setFiles((current) => [...current, file]);
@@ -328,18 +512,43 @@ function ChatComposer({
328
512
  text,
329
513
  files.map((file) => ({ data: file, mediaType: file.type }))
330
514
  );
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;
515
+ const selectedAgent = agents.find((item) => item.id === agentId);
516
+ const selectedModel = models.find((item) => item.id === modelId);
517
+ 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: [
518
+ /* @__PURE__ */ jsx7(SelectTrigger, { "aria-label": "Runtime model", children: /* @__PURE__ */ jsx7(SelectValue, { placeholder: "Model" }) }),
519
+ /* @__PURE__ */ jsx7(SelectContent, { align: "start", children: models.map((model) => /* @__PURE__ */ jsx7(SelectItem, { value: model.id, children: model.label }, model.id)) })
520
+ ] }) }) : null;
521
+ const runtimeSelector = agents.length > 1 ? /* @__PURE__ */ jsxs3(DropdownMenu, { children: [
522
+ /* @__PURE__ */ jsx7(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxs3(
523
+ Button,
524
+ {
525
+ variant: "ghost",
526
+ 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",
527
+ disabled: disabled || isRunning,
528
+ "aria-label": "Runtime configuration",
529
+ children: [
530
+ /* @__PURE__ */ jsx7("span", { className: "truncate", children: [selectedAgent?.label, selectedModel?.label].filter(Boolean).join(" \xB7 ") || "Runtime" }),
531
+ /* @__PURE__ */ jsx7(ChevronDown, { className: "size-3.5 text-muted-foreground" })
532
+ ]
533
+ }
534
+ ) }),
535
+ /* @__PURE__ */ jsxs3(DropdownMenuContent, { align: "start", className: "w-64 rounded-lg", children: [
536
+ /* @__PURE__ */ jsxs3(DropdownMenuSub, { children: [
537
+ /* @__PURE__ */ jsxs3(DropdownMenuSubTrigger, { className: "rounded-lg", children: [
538
+ /* @__PURE__ */ jsx7("span", { children: "Agent" }),
539
+ /* @__PURE__ */ jsx7("span", { className: "ml-auto max-w-32 truncate text-muted-foreground", children: selectedAgent?.label })
540
+ ] }),
541
+ /* @__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)) }) })
542
+ ] }),
543
+ models.length > 0 ? /* @__PURE__ */ jsxs3(DropdownMenuSub, { children: [
544
+ /* @__PURE__ */ jsxs3(DropdownMenuSubTrigger, { className: "rounded-lg", children: [
545
+ /* @__PURE__ */ jsx7("span", { children: "Model" }),
546
+ /* @__PURE__ */ jsx7("span", { className: "ml-auto max-w-32 truncate text-muted-foreground", children: selectedModel?.label })
547
+ ] }),
548
+ /* @__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)) }) })
549
+ ] }) : null
550
+ ] })
551
+ ] }) : modelSelector;
343
552
  const hasContextWindow = Number.isFinite(Number(contextWindow?.max_tokens)) && Number(contextWindow?.max_tokens) > 0;
344
553
  const showUtilityRow = utilityRow === "below";
345
554
  const submit = async () => {
@@ -364,21 +573,21 @@ function ChatComposer({
364
573
  submittingRef.current = false;
365
574
  }
366
575
  };
367
- return /* @__PURE__ */ jsxs2(
576
+ return /* @__PURE__ */ jsxs3(
368
577
  "div",
369
578
  {
370
579
  className: "mx-auto w-full max-w-3xl px-4 pb-[max(1rem,env(safe-area-inset-bottom))] sm:px-6",
371
580
  "data-agents24-chat-composer": "",
372
581
  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: () => {
582
+ allowAttachments && files.length > 0 && /* @__PURE__ */ jsx7("div", { className: "mb-2 flex min-w-0 gap-2 overflow-x-auto", children: files.map((file, index) => /* @__PURE__ */ jsxs3("div", { className: "flex max-w-48 items-center gap-2 border bg-card px-2 py-1 text-xs", children: [
583
+ /* @__PURE__ */ jsx7("span", { className: "truncate", children: file.name }),
584
+ /* @__PURE__ */ jsx7(Button, { variant: "ghost", size: "icon-xs", "aria-label": `Remove ${file.name}`, onClick: () => {
376
585
  draftRevisionRef.current += 1;
377
586
  setFiles((current) => current.filter((_, itemIndex) => itemIndex !== index));
378
- }, children: /* @__PURE__ */ jsx6(X, {}) })
587
+ }, children: /* @__PURE__ */ jsx7(X, {}) })
379
588
  ] }, `${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(
589
+ attachmentError || recorder.error ? /* @__PURE__ */ jsx7("p", { className: "mb-2 text-xs text-destructive", role: "alert", children: attachmentError || recorder.error }) : null,
590
+ /* @__PURE__ */ jsxs3(
382
591
  "div",
383
592
  {
384
593
  "data-expanded": isExpanded || void 0,
@@ -387,8 +596,8 @@ function ChatComposer({
387
596
  isExpanded ? "p-2" : "p-1.5"
388
597
  ),
389
598
  children: [
390
- allowAttachments ? /* @__PURE__ */ jsxs2(Fragment, { children: [
391
- /* @__PURE__ */ jsx6(
599
+ allowAttachments ? /* @__PURE__ */ jsxs3(Fragment, { children: [
600
+ /* @__PURE__ */ jsx7(
392
601
  "input",
393
602
  {
394
603
  ref: inputRef,
@@ -408,9 +617,9 @@ function ChatComposer({
408
617
  }
409
618
  }
410
619
  ),
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(
620
+ /* @__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: "+" }) }) })
621
+ ] }) : /* @__PURE__ */ jsx7("span", { "aria-hidden": "true", className: "agents24-composer-attach" }),
622
+ /* @__PURE__ */ jsx7(
414
623
  Textarea,
415
624
  {
416
625
  ref: textareaRef,
@@ -435,10 +644,10 @@ function ChatComposer({
435
644
  }
436
645
  }
437
646
  ),
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(
647
+ /* @__PURE__ */ jsxs3("div", { className: "agents24-composer-actions flex items-center gap-1", children: [
648
+ utilityRow === "inline" ? /* @__PURE__ */ jsx7(AgentChatContextStatus, { contextWindow }) : null,
649
+ utilityRow === "inline" ? runtimeSelector : null,
650
+ recordingAllowed ? /* @__PURE__ */ jsx7(
442
651
  Button,
443
652
  {
444
653
  variant: recorder.isRecording ? "default" : "ghost",
@@ -449,35 +658,35 @@ function ChatComposer({
449
658
  if (recorder.isRecording) recorder.stop();
450
659
  else void recorder.start();
451
660
  },
452
- children: recorder.isRecording ? /* @__PURE__ */ jsx6(Square, { className: "fill-current" }) : /* @__PURE__ */ jsx6(Mic, {})
661
+ children: recorder.isRecording ? /* @__PURE__ */ jsx7(Square, { className: "fill-current" }) : /* @__PURE__ */ jsx7(Mic, {})
453
662
  }
454
663
  ) : null,
455
- isRunning ? /* @__PURE__ */ jsx6(
664
+ isRunning ? /* @__PURE__ */ jsx7(
456
665
  Button,
457
666
  {
458
667
  size: "icon",
459
668
  "aria-label": isCancelling ? "Cancelling response" : "Stop response",
460
669
  disabled: disabled || isCancelling,
461
670
  onClick: onStop,
462
- children: isCancelling ? /* @__PURE__ */ jsx6(LoaderCircle, { className: "animate-spin" }) : /* @__PURE__ */ jsx6(Square, { className: "fill-current" })
671
+ children: isCancelling ? /* @__PURE__ */ jsx7(LoaderCircle, { className: "animate-spin" }) : /* @__PURE__ */ jsx7(Square, { className: "fill-current" })
463
672
  }
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, {}) })
673
+ ) : validationError ? /* @__PURE__ */ jsxs3(Tooltip, { tabIndex: 0, children: [
674
+ /* @__PURE__ */ jsx7(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx7(Button, { size: "icon", "aria-label": "Send message", disabled: true, onClick: () => void submit(), children: /* @__PURE__ */ jsx7(ArrowUp, {}) }) }),
675
+ /* @__PURE__ */ jsx7(TooltipContent, { children: validationError })
676
+ ] }) : /* @__PURE__ */ jsx7(Button, { size: "icon", "aria-label": "Send message", disabled, onClick: () => void submit(), children: /* @__PURE__ */ jsx7(ArrowUp, {}) })
468
677
  ] })
469
678
  ]
470
679
  }
471
680
  ),
472
- showUtilityRow ? /* @__PURE__ */ jsxs2(
681
+ showUtilityRow ? /* @__PURE__ */ jsxs3(
473
682
  "div",
474
683
  {
475
- "aria-hidden": !modelSelector && !hasContextWindow ? "true" : void 0,
684
+ "aria-hidden": !runtimeSelector && !hasContextWindow ? "true" : void 0,
476
685
  className: "mt-2 flex min-h-8 items-center justify-between gap-2 px-1",
477
686
  "data-agents24-chat-composer-utility": "",
478
687
  children: [
479
- /* @__PURE__ */ jsx6("div", { className: "min-w-0", children: modelSelector }),
480
- /* @__PURE__ */ jsx6(AgentChatContextStatus, { contextWindow })
688
+ /* @__PURE__ */ jsx7("div", { className: "min-w-0", children: runtimeSelector }),
689
+ /* @__PURE__ */ jsx7(AgentChatContextStatus, { contextWindow })
481
690
  ]
482
691
  }
483
692
  ) : null
@@ -496,17 +705,17 @@ import {
496
705
  } from "@agents24/chat-react/ui";
497
706
 
498
707
  // scaffold/src/components/chat/collapsible-user-message.tsx
499
- import { ChevronDown, ChevronUp } from "lucide-react";
708
+ import { ChevronDown as ChevronDown2, ChevronUp } from "lucide-react";
500
709
  import * as React3 from "react";
501
- import { jsx as jsx7, jsxs as jsxs3 } from "react/jsx-runtime";
710
+ import { jsx as jsx8, jsxs as jsxs4 } from "react/jsx-runtime";
502
711
  var collapseThreshold = 360;
503
712
  function CollapsibleUserMessage({ content }) {
504
713
  const [expanded, setExpanded] = React3.useState(false);
505
714
  const contentId = React3.useId();
506
715
  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(
716
+ const Icon = expanded ? ChevronUp : ChevronDown2;
717
+ return /* @__PURE__ */ jsxs4("div", { className: "flex min-w-0 flex-col gap-2", children: [
718
+ /* @__PURE__ */ jsx8(
510
719
  "div",
511
720
  {
512
721
  id: contentId,
@@ -514,7 +723,7 @@ function CollapsibleUserMessage({ content }) {
514
723
  children: content
515
724
  }
516
725
  ),
517
- collapsible && /* @__PURE__ */ jsxs3(
726
+ collapsible && /* @__PURE__ */ jsxs4(
518
727
  Button,
519
728
  {
520
729
  variant: "ghost",
@@ -526,7 +735,7 @@ function CollapsibleUserMessage({ content }) {
526
735
  onClick: () => setExpanded((value) => !value),
527
736
  children: [
528
737
  expanded ? "Show less" : "Show more",
529
- /* @__PURE__ */ jsx7(Icon, {})
738
+ /* @__PURE__ */ jsx8(Icon, {})
530
739
  ]
531
740
  }
532
741
  )
@@ -539,24 +748,24 @@ import * as React4 from "react";
539
748
  // scaffold/src/components/ui/dialog.tsx
540
749
  import { Dialog as DialogPrimitive } from "radix-ui";
541
750
  import { XIcon } from "lucide-react";
542
- import { jsx as jsx8, jsxs as jsxs4 } from "react/jsx-runtime";
751
+ import { jsx as jsx9, jsxs as jsxs5 } from "react/jsx-runtime";
543
752
  function Dialog({
544
753
  ...props
545
754
  }) {
546
- return /* @__PURE__ */ jsx8(DialogPrimitive.Root, { "data-slot": "dialog", ...props });
755
+ return /* @__PURE__ */ jsx9(DialogPrimitive.Root, { "data-slot": "dialog", ...props });
547
756
  }
548
757
  function DialogPortal({
549
758
  container,
550
759
  ...props
551
760
  }) {
552
761
  const themeContainer = useThemePortalContainer();
553
- return /* @__PURE__ */ jsx8(DialogPrimitive.Portal, { container: container || themeContainer || void 0, "data-slot": "dialog-portal", ...props });
762
+ return /* @__PURE__ */ jsx9(DialogPrimitive.Portal, { container: container || themeContainer || void 0, "data-slot": "dialog-portal", ...props });
554
763
  }
555
764
  function DialogOverlay({
556
765
  className,
557
766
  ...props
558
767
  }) {
559
- return /* @__PURE__ */ jsx8(
768
+ return /* @__PURE__ */ jsx9(
560
769
  DialogPrimitive.Overlay,
561
770
  {
562
771
  "data-slot": "dialog-overlay",
@@ -574,9 +783,9 @@ function DialogContent({
574
783
  showCloseButton = true,
575
784
  ...props
576
785
  }) {
577
- return /* @__PURE__ */ jsxs4(DialogPortal, { children: [
578
- /* @__PURE__ */ jsx8(DialogOverlay, {}),
579
- /* @__PURE__ */ jsxs4(
786
+ return /* @__PURE__ */ jsxs5(DialogPortal, { children: [
787
+ /* @__PURE__ */ jsx9(DialogOverlay, {}),
788
+ /* @__PURE__ */ jsxs5(
580
789
  DialogPrimitive.Content,
581
790
  {
582
791
  "data-slot": "dialog-content",
@@ -587,18 +796,18 @@ function DialogContent({
587
796
  ...props,
588
797
  children: [
589
798
  children,
590
- showCloseButton && /* @__PURE__ */ jsx8(DialogPrimitive.Close, { "data-slot": "dialog-close", asChild: true, children: /* @__PURE__ */ jsxs4(
799
+ showCloseButton && /* @__PURE__ */ jsx9(DialogPrimitive.Close, { "data-slot": "dialog-close", asChild: true, children: /* @__PURE__ */ jsxs5(
591
800
  Button,
592
801
  {
593
802
  variant: "ghost",
594
803
  className: "absolute top-4 right-4 bg-secondary",
595
804
  size: "icon-sm",
596
805
  children: [
597
- /* @__PURE__ */ jsx8(
806
+ /* @__PURE__ */ jsx9(
598
807
  XIcon,
599
808
  {}
600
809
  ),
601
- /* @__PURE__ */ jsx8("span", { className: "sr-only", children: "Close" })
810
+ /* @__PURE__ */ jsx9("span", { className: "sr-only", children: "Close" })
602
811
  ]
603
812
  }
604
813
  ) })
@@ -608,7 +817,7 @@ function DialogContent({
608
817
  ] });
609
818
  }
610
819
  function DialogHeader({ className, ...props }) {
611
- return /* @__PURE__ */ jsx8(
820
+ return /* @__PURE__ */ jsx9(
612
821
  "div",
613
822
  {
614
823
  "data-slot": "dialog-header",
@@ -623,7 +832,7 @@ function DialogFooter({
623
832
  children,
624
833
  ...props
625
834
  }) {
626
- return /* @__PURE__ */ jsxs4(
835
+ return /* @__PURE__ */ jsxs5(
627
836
  "div",
628
837
  {
629
838
  "data-slot": "dialog-footer",
@@ -634,7 +843,7 @@ function DialogFooter({
634
843
  ...props,
635
844
  children: [
636
845
  children,
637
- showCloseButton && /* @__PURE__ */ jsx8(DialogPrimitive.Close, { asChild: true, children: /* @__PURE__ */ jsx8(Button, { variant: "outline", children: "Close" }) })
846
+ showCloseButton && /* @__PURE__ */ jsx9(DialogPrimitive.Close, { asChild: true, children: /* @__PURE__ */ jsx9(Button, { variant: "outline", children: "Close" }) })
638
847
  ]
639
848
  }
640
849
  );
@@ -643,7 +852,7 @@ function DialogTitle({
643
852
  className,
644
853
  ...props
645
854
  }) {
646
- return /* @__PURE__ */ jsx8(
855
+ return /* @__PURE__ */ jsx9(
647
856
  DialogPrimitive.Title,
648
857
  {
649
858
  "data-slot": "dialog-title",
@@ -659,7 +868,7 @@ function DialogDescription({
659
868
  className,
660
869
  ...props
661
870
  }) {
662
- return /* @__PURE__ */ jsx8(
871
+ return /* @__PURE__ */ jsx9(
663
872
  DialogPrimitive.Description,
664
873
  {
665
874
  "data-slot": "dialog-description",
@@ -673,7 +882,7 @@ function DialogDescription({
673
882
  }
674
883
 
675
884
  // scaffold/src/components/chat/external-link-dialog.tsx
676
- import { jsx as jsx9, jsxs as jsxs5 } from "react/jsx-runtime";
885
+ import { jsx as jsx10, jsxs as jsxs6 } from "react/jsx-runtime";
677
886
  function ExternalLinkDialog({ isOpen, onClose, onConfirm, url }) {
678
887
  const [copied, setCopied] = React4.useState(false);
679
888
  React4.useEffect(() => {
@@ -687,29 +896,29 @@ function ExternalLinkDialog({ isOpen, onClose, onConfirm, url }) {
687
896
  onConfirm();
688
897
  onClose();
689
898
  };
690
- return /* @__PURE__ */ jsx9(Dialog, { open: isOpen, onOpenChange: (open) => {
899
+ return /* @__PURE__ */ jsx10(Dialog, { open: isOpen, onOpenChange: (open) => {
691
900
  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." })
901
+ }, children: /* @__PURE__ */ jsxs6(DialogContent, { className: "max-h-[calc(100dvh-2rem)] min-w-0 overflow-hidden sm:max-w-md", children: [
902
+ /* @__PURE__ */ jsxs6(DialogHeader, { children: [
903
+ /* @__PURE__ */ jsx10(DialogTitle, { children: "Open external link?" }),
904
+ /* @__PURE__ */ jsx10(DialogDescription, { children: "You\u2019re about to visit an external website." })
696
905
  ] }),
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" })
906
+ /* @__PURE__ */ jsx10("div", { className: "max-h-32 overflow-auto rounded-md bg-muted p-3 font-mono text-xs wrap-break-word", children: url }),
907
+ /* @__PURE__ */ jsxs6(DialogFooter, { children: [
908
+ /* @__PURE__ */ jsx10(Button, { variant: "outline", onClick: () => void copyUrl(), children: copied ? "Copied" : "Copy link" }),
909
+ /* @__PURE__ */ jsx10(Button, { onClick: openUrl, children: "Open link" })
701
910
  ] })
702
911
  ] }) });
703
912
  }
704
913
 
705
914
  // scaffold/src/components/chat/message-parts.tsx
706
- import { Fragment as Fragment2, jsx as jsx10, jsxs as jsxs6 } from "react/jsx-runtime";
915
+ import { Fragment as Fragment2, jsx as jsx11, jsxs as jsxs7 } from "react/jsx-runtime";
707
916
  var linkSafety = {
708
917
  enabled: true,
709
- renderModal: (props) => /* @__PURE__ */ jsx10(ExternalLinkDialog, { ...props })
918
+ renderModal: (props) => /* @__PURE__ */ jsx11(ExternalLinkDialog, { ...props })
710
919
  };
711
920
  function ScaffoldTimeline(props) {
712
- return /* @__PURE__ */ jsx10(
921
+ return /* @__PURE__ */ jsx11(
713
922
  AgentResponseTimeline,
714
923
  {
715
924
  ...props,
@@ -728,7 +937,7 @@ function MessageParts({
728
937
  Timeline = ScaffoldTimeline
729
938
  }) {
730
939
  if (message.role === "assistant") {
731
- return /* @__PURE__ */ jsx10(
940
+ return /* @__PURE__ */ jsx11(
732
941
  Timeline,
733
942
  {
734
943
  getHitlActionState,
@@ -743,8 +952,8 @@ function MessageParts({
743
952
  }
744
953
  const text = message.parts.filter((part) => part.kind === "text").map((part) => part.kind === "text" ? part.text : "").join("") || message.content;
745
954
  const supportingParts = message.parts.filter((part) => part.kind !== "text" && part.kind !== "data");
746
- return /* @__PURE__ */ jsxs6(Fragment2, { children: [
747
- supportingParts.map((part) => /* @__PURE__ */ jsx10(
955
+ return /* @__PURE__ */ jsxs7(Fragment2, { children: [
956
+ supportingParts.map((part) => /* @__PURE__ */ jsx11(
748
957
  AgentChatPart,
749
958
  {
750
959
  getHitlActionState,
@@ -756,14 +965,14 @@ function MessageParts({
756
965
  },
757
966
  part.id
758
967
  )),
759
- text ? /* @__PURE__ */ jsx10(CollapsibleUserMessage, { content: text }) : null
968
+ text ? /* @__PURE__ */ jsx11(CollapsibleUserMessage, { content: text }) : null
760
969
  ] });
761
970
  }
762
971
 
763
972
  // scaffold/src/components/ui/bubble.tsx
764
973
  import { cva as cva2 } from "class-variance-authority";
765
974
  import { Slot as Slot3 } from "radix-ui";
766
- import { jsx as jsx11 } from "react/jsx-runtime";
975
+ import { jsx as jsx12 } from "react/jsx-runtime";
767
976
  var bubbleVariants = cva2(
768
977
  "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
978
  {
@@ -789,7 +998,7 @@ function Bubble({
789
998
  className,
790
999
  ...props
791
1000
  }) {
792
- return /* @__PURE__ */ jsx11(
1001
+ return /* @__PURE__ */ jsx12(
793
1002
  "div",
794
1003
  {
795
1004
  "data-slot": "bubble",
@@ -806,7 +1015,7 @@ function BubbleContent({
806
1015
  ...props
807
1016
  }) {
808
1017
  const Comp = asChild ? Slot3.Root : "div";
809
- return /* @__PURE__ */ jsx11(
1018
+ return /* @__PURE__ */ jsx12(
810
1019
  Comp,
811
1020
  {
812
1021
  "data-slot": "bubble-content",
@@ -839,13 +1048,13 @@ var bubbleReactionsVariants = cva2(
839
1048
  );
840
1049
 
841
1050
  // scaffold/src/components/ui/message.tsx
842
- import { jsx as jsx12 } from "react/jsx-runtime";
1051
+ import { jsx as jsx13 } from "react/jsx-runtime";
843
1052
  function Message({
844
1053
  className,
845
1054
  align = "start",
846
1055
  ...props
847
1056
  }) {
848
- return /* @__PURE__ */ jsx12(
1057
+ return /* @__PURE__ */ jsx13(
849
1058
  "div",
850
1059
  {
851
1060
  "data-slot": "message",
@@ -859,7 +1068,7 @@ function Message({
859
1068
  );
860
1069
  }
861
1070
  function MessageContent({ className, ...props }) {
862
- return /* @__PURE__ */ jsx12(
1071
+ return /* @__PURE__ */ jsx13(
863
1072
  "div",
864
1073
  {
865
1074
  "data-slot": "message-content",
@@ -872,7 +1081,7 @@ function MessageContent({ className, ...props }) {
872
1081
  );
873
1082
  }
874
1083
  function MessageFooter({ className, ...props }) {
875
- return /* @__PURE__ */ jsx12(
1084
+ return /* @__PURE__ */ jsx13(
876
1085
  "div",
877
1086
  {
878
1087
  "data-slot": "message-footer",
@@ -886,7 +1095,7 @@ function MessageFooter({ className, ...props }) {
886
1095
  }
887
1096
 
888
1097
  // scaffold/src/components/chat/chat-message.tsx
889
- import { jsx as jsx13, jsxs as jsxs7 } from "react/jsx-runtime";
1098
+ import { jsx as jsx14, jsxs as jsxs8 } from "react/jsx-runtime";
890
1099
  function ChatMessage({
891
1100
  allowFeedback,
892
1101
  getHitlActionState,
@@ -898,15 +1107,15 @@ function ChatMessage({
898
1107
  Timeline
899
1108
  }) {
900
1109
  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(
1110
+ return /* @__PURE__ */ jsx14(Message, { align: isUser ? "end" : "start", children: /* @__PURE__ */ jsxs8(MessageContent, { children: [
1111
+ isUser && message.attachments?.length ? /* @__PURE__ */ jsx14(ChatAttachments, { className: "mb-2 justify-end", children: message.attachments.map((attachment, index) => /* @__PURE__ */ jsx14(
903
1112
  ChatAttachment,
904
1113
  {
905
1114
  data: attachment
906
1115
  },
907
1116
  String(attachment.id || attachment.url || attachment.filename || index)
908
1117
  )) }) : 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(
1118
+ /* @__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
1119
  MessageParts,
911
1120
  {
912
1121
  getHitlActionState,
@@ -916,7 +1125,7 @@ function ChatMessage({
916
1125
  Timeline
917
1126
  }
918
1127
  ) }) }),
919
- !isUser && message.isFinal !== false && /* @__PURE__ */ jsx13(MessageFooter, { className: "gap-1 opacity-70 transition-opacity group-hover/message:opacity-100", children: /* @__PURE__ */ jsx13(
1128
+ !isUser && message.isFinal !== false && /* @__PURE__ */ jsx14(MessageFooter, { className: "gap-1 opacity-70 transition-opacity group-hover/message:opacity-100", children: /* @__PURE__ */ jsx14(
920
1129
  AgentChatDefaultActions,
921
1130
  {
922
1131
  handlers: {
@@ -936,7 +1145,7 @@ function ChatMessage({
936
1145
  // scaffold/src/components/chat/theme-menu.tsx
937
1146
  import { Laptop, Moon, Sun } from "lucide-react";
938
1147
  import * as React5 from "react";
939
- import { jsx as jsx14, jsxs as jsxs8 } from "react/jsx-runtime";
1148
+ import { jsx as jsx15, jsxs as jsxs9 } from "react/jsx-runtime";
940
1149
  var options = [
941
1150
  { value: "system", label: "System", icon: Laptop },
942
1151
  { value: "light", label: "Light", icon: Sun },
@@ -966,8 +1175,8 @@ function ThemeMenu() {
966
1175
  };
967
1176
  }, [open]);
968
1177
  const label = appearance === "system" ? "System" : appearance === "light" ? "Light" : "Dark";
969
- return /* @__PURE__ */ jsxs8("div", { ref: rootRef, className: "relative", children: [
970
- /* @__PURE__ */ jsx14(
1178
+ return /* @__PURE__ */ jsxs9("div", { ref: rootRef, className: "relative", children: [
1179
+ /* @__PURE__ */ jsx15(
971
1180
  Button,
972
1181
  {
973
1182
  "aria-controls": menuId,
@@ -977,16 +1186,16 @@ function ThemeMenu() {
977
1186
  onClick: () => setOpen((value) => !value),
978
1187
  size: "icon-sm",
979
1188
  variant: "ghost",
980
- children: /* @__PURE__ */ jsx14(ActiveIcon, {})
1189
+ children: /* @__PURE__ */ jsx15(ActiveIcon, {})
981
1190
  }
982
1191
  ),
983
- open ? /* @__PURE__ */ jsx14(
1192
+ open ? /* @__PURE__ */ jsx15(
984
1193
  "div",
985
1194
  {
986
1195
  id: menuId,
987
1196
  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
1197
  role: "menu",
989
- children: options.map(({ value, label: optionLabel, icon: Icon }, index) => /* @__PURE__ */ jsxs8(
1198
+ children: options.map(({ value, label: optionLabel, icon: Icon }, index) => /* @__PURE__ */ jsxs9(
990
1199
  Button,
991
1200
  {
992
1201
  ref: index === 0 ? firstItemRef : void 0,
@@ -1000,7 +1209,7 @@ function ThemeMenu() {
1000
1209
  size: "sm",
1001
1210
  variant: "ghost",
1002
1211
  children: [
1003
- /* @__PURE__ */ jsx14(Icon, {}),
1212
+ /* @__PURE__ */ jsx15(Icon, {}),
1004
1213
  " ",
1005
1214
  optionLabel
1006
1215
  ]
@@ -1019,96 +1228,6 @@ import { LoaderCircle as LoaderCircle2, SquarePen, Trash2 } from "lucide-react";
1019
1228
  // scaffold/src/components/chat/identity-control.tsx
1020
1229
  import { LogIn, LogOut, UserRound } from "lucide-react";
1021
1230
 
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
1231
  // scaffold/src/components/ui/sidebar.tsx
1113
1232
  import * as React7 from "react";
1114
1233
  import { cva as cva3 } from "class-variance-authority";
@@ -1577,7 +1696,7 @@ function SidebarMenuItem({ className, ...props }) {
1577
1696
  );
1578
1697
  }
1579
1698
  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",
1699
+ "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
1700
  {
1582
1701
  variants: {
1583
1702
  variant: {
@@ -1653,7 +1772,7 @@ function SidebarMenuAction({
1653
1772
  "data-sidebar": "menu-action",
1654
1773
  className: cn(
1655
1774
  "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",
1775
+ 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
1776
  className
1658
1777
  ),
1659
1778
  ...props
@@ -2031,7 +2150,8 @@ function OperationErrorNotice({ runtime }) {
2031
2150
  function ChatShell({
2032
2151
  components,
2033
2152
  identity,
2034
- runtime
2153
+ runtime,
2154
+ sidebar
2035
2155
  }) {
2036
2156
  const { controller } = runtime;
2037
2157
  const isRunning = controller.runState === "streaming" || controller.runState === "reconnecting" || controller.runState === "paused" || controller.runState === "cancelling" || runtime.isSubmitting;
@@ -2047,7 +2167,7 @@ function ChatShell({
2047
2167
  "data-agents24-chat-layout": "",
2048
2168
  children: [
2049
2169
  /* @__PURE__ */ jsx25(PersistentSidebarTrigger, {}),
2050
- /* @__PURE__ */ jsx25(
2170
+ sidebar || /* @__PURE__ */ jsx25(
2051
2171
  ThreadSidebar,
2052
2172
  {
2053
2173
  activeThreadId: controller.activeThreadId,
@@ -2090,10 +2210,16 @@ function ChatShell({
2090
2210
  {
2091
2211
  inputContract: runtime.inputContract || LOADING_INPUT_CONTRACT,
2092
2212
  contextWindow: runtime.contextWindow,
2093
- disabled: runtime.isBootstrapping,
2213
+ disabled: runtime.isBootstrapping || runtime.isChangingAgent,
2214
+ focusKey: controller.activeThreadId,
2094
2215
  forceExpanded: true,
2095
2216
  isCancelling,
2096
2217
  isRunning,
2218
+ agentId: runtime.agentId,
2219
+ agents: runtime.agents,
2220
+ onAgentChange: (agentId) => {
2221
+ void runtime.changeAgent(agentId);
2222
+ },
2097
2223
  onStop: () => {
2098
2224
  void controller.cancelRun().catch(() => void 0);
2099
2225
  },
@@ -2178,9 +2304,15 @@ function ChatShell({
2178
2304
  {
2179
2305
  inputContract: runtime.inputContract || LOADING_INPUT_CONTRACT,
2180
2306
  contextWindow: runtime.contextWindow,
2181
- disabled: runtime.isBootstrapping || hasBlockingError,
2307
+ disabled: runtime.isBootstrapping || runtime.isChangingAgent || hasBlockingError,
2308
+ focusKey: controller.activeThreadId,
2182
2309
  isCancelling,
2183
2310
  isRunning,
2311
+ agentId: runtime.agentId,
2312
+ agents: runtime.agents,
2313
+ onAgentChange: (agentId) => {
2314
+ void runtime.changeAgent(agentId);
2315
+ },
2184
2316
  onStop: () => {
2185
2317
  void controller.cancelRun().catch(() => void 0);
2186
2318
  },
@@ -2223,7 +2355,7 @@ function RuntimeChat({
2223
2355
  ...props,
2224
2356
  mcpRedirectUri: props.mcpRedirectUri || (typeof window === "undefined" ? void 0 : window.location.href)
2225
2357
  });
2226
- return /* @__PURE__ */ jsx26(ChatShell, { components, identity, runtime });
2358
+ return /* @__PURE__ */ jsx26(ChatShell, { components, identity, runtime, sidebar: props.sidebar });
2227
2359
  }
2228
2360
  function App(props) {
2229
2361
  const identity = props.identity || GUEST_CHAT_IDENTITY;