@truefoundry/agent-ui-sdk 0.0.3 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -84,9 +84,9 @@ import {
84
84
 
85
85
  // src/theme/defaultSlots.ts
86
86
  import {
87
- Accordion as Accordion2,
88
- AccordionDetails as AccordionDetails2,
89
- AccordionSummary as AccordionSummary2
87
+ Accordion as Accordion3,
88
+ AccordionDetails as AccordionDetails3,
89
+ AccordionSummary as AccordionSummary3
90
90
  } from "tfy-web-components/components/atoms/Accordion";
91
91
  import Button2 from "tfy-web-components/components/atoms/Button";
92
92
  import IconButton4 from "tfy-web-components/components/atoms/IconButton";
@@ -171,7 +171,7 @@ function UserMessageBubble({ text, attachments, editAction, className }) {
171
171
  className: cn("fade-in slide-in-from-bottom-1 animate-in duration-150", className),
172
172
  children: [
173
173
  attachments,
174
- /* @__PURE__ */ jsx11(UserMessage, { text, editAction, actionsAlwaysVisible: true })
174
+ /* @__PURE__ */ jsx11(UserMessage, { text, editAction })
175
175
  ]
176
176
  }
177
177
  );
@@ -379,11 +379,80 @@ function ToolGroupCard({
379
379
  );
380
380
  }
381
381
 
382
+ // src/atoms/AgentStepsCard.tsx
383
+ import { LoaderIcon as LoaderIcon2 } from "lucide-react";
384
+ import { Accordion as Accordion2, AccordionDetails as AccordionDetails2, AccordionSummary as AccordionSummary2 } from "tfy-web-components/components/atoms/Accordion";
385
+ import IconProvider from "tfy-web-components/components/atoms/IconProvider";
386
+ import { jsx as jsx19, jsxs as jsxs5 } from "react/jsx-runtime";
387
+ function AgentStepsCard({
388
+ toolCount,
389
+ thinkingCount,
390
+ expanded,
391
+ active = false,
392
+ onToggle,
393
+ children,
394
+ className
395
+ }) {
396
+ const toolLabel = `${toolCount} tool ${toolCount === 1 ? "call" : "calls"}`;
397
+ const thinkingLabel = thinkingCount > 0 ? ` \xB7 ${thinkingCount} thought${thinkingCount === 1 ? "" : "s"}` : "";
398
+ return /* @__PURE__ */ jsxs5(
399
+ Accordion2,
400
+ {
401
+ "data-slot": "agent-steps-card",
402
+ expanded,
403
+ onChange: () => onToggle(),
404
+ background: "transparent",
405
+ className: cn("aui-agent-steps-card rounded-lg border border-border/50 bg-secondary/20", className),
406
+ sx: { margin: 0, boxShadow: "none" },
407
+ children: [
408
+ /* @__PURE__ */ jsx19(
409
+ AccordionSummary2,
410
+ {
411
+ hideIcon: true,
412
+ disableRipple: true,
413
+ sx: {
414
+ padding: 0,
415
+ minHeight: 0,
416
+ "&.Mui-expanded": { minHeight: 0 },
417
+ "& .MuiAccordionSummary-content": { margin: 0, width: "100%" }
418
+ },
419
+ children: /* @__PURE__ */ jsxs5(
420
+ "button",
421
+ {
422
+ type: "button",
423
+ className: "flex w-full items-center gap-2 rounded-t-lg py-2 px-2.5 text-left text-xs transition-colors hover:bg-secondary/40",
424
+ children: [
425
+ /* @__PURE__ */ jsx19(
426
+ IconProvider,
427
+ {
428
+ icon: expanded ? "chevron-down" : "chevron-right",
429
+ size: 0.75,
430
+ className: "shrink-0 text-muted-foreground"
431
+ }
432
+ ),
433
+ /* @__PURE__ */ jsx19("span", { className: "font-semibold text-foreground/90", children: "Agent steps" }),
434
+ /* @__PURE__ */ jsxs5("span", { className: "text-muted-foreground", children: [
435
+ "\xB7 ",
436
+ toolLabel,
437
+ thinkingLabel
438
+ ] }),
439
+ active && /* @__PURE__ */ jsx19(LoaderIcon2, { className: "ml-auto size-3 shrink-0 animate-spin text-primary" })
440
+ ]
441
+ }
442
+ )
443
+ }
444
+ ),
445
+ /* @__PURE__ */ jsx19(AccordionDetails2, { sx: { padding: 0 }, children: /* @__PURE__ */ jsx19("div", { className: "space-y-3 border-t border-border/50 px-1.5 py-1.5 pt-3", children }) })
446
+ ]
447
+ }
448
+ );
449
+ }
450
+
382
451
  // src/atoms/Skeletons.tsx
383
452
  import Skeleton from "tfy-web-components/components/atoms/Skeleton";
384
- import { jsx as jsx19, jsxs as jsxs5 } from "react/jsx-runtime";
453
+ import { jsx as jsx20, jsxs as jsxs6 } from "react/jsx-runtime";
385
454
  function MessageListSkeleton({ className }) {
386
- return /* @__PURE__ */ jsxs5(
455
+ return /* @__PURE__ */ jsxs6(
387
456
  "div",
388
457
  {
389
458
  role: "status",
@@ -391,11 +460,11 @@ function MessageListSkeleton({ className }) {
391
460
  "data-slot": "aui_thread-history-skeleton",
392
461
  className: cn("mb-14 flex flex-col gap-y-6", className),
393
462
  children: [
394
- /* @__PURE__ */ jsx19("div", { className: "flex justify-end", children: /* @__PURE__ */ jsx19(Skeleton, { className: "h-10 w-[min(85%,20rem)] rounded-xl" }) }),
395
- /* @__PURE__ */ jsxs5("div", { className: "flex flex-col gap-2 px-2", children: [
396
- /* @__PURE__ */ jsx19(Skeleton, { className: "h-4 w-full max-w-md" }),
397
- /* @__PURE__ */ jsx19(Skeleton, { className: "h-4 w-full max-w-sm" }),
398
- /* @__PURE__ */ jsx19(Skeleton, { className: "h-4 w-2/3 max-w-xs" })
463
+ /* @__PURE__ */ jsx20("div", { className: "flex justify-end", children: /* @__PURE__ */ jsx20(Skeleton, { className: "h-10 w-[min(85%,20rem)] rounded-xl" }) }),
464
+ /* @__PURE__ */ jsxs6("div", { className: "flex flex-col gap-2 px-2", children: [
465
+ /* @__PURE__ */ jsx20(Skeleton, { className: "h-4 w-full max-w-md" }),
466
+ /* @__PURE__ */ jsx20(Skeleton, { className: "h-4 w-full max-w-sm" }),
467
+ /* @__PURE__ */ jsx20(Skeleton, { className: "h-4 w-2/3 max-w-xs" })
399
468
  ] })
400
469
  ]
401
470
  }
@@ -403,7 +472,7 @@ function MessageListSkeleton({ className }) {
403
472
  }
404
473
 
405
474
  // src/atoms/ComposerShell.tsx
406
- import { jsx as jsx20, jsxs as jsxs6 } from "react/jsx-runtime";
475
+ import { jsx as jsx21, jsxs as jsxs7 } from "react/jsx-runtime";
407
476
  function ComposerShell({
408
477
  value,
409
478
  placeholder,
@@ -422,7 +491,7 @@ function ComposerShell({
422
491
  const ComposerLeftSection2 = useSlot("ComposerLeftSection");
423
492
  const ComposerRightSection2 = useSlot("ComposerRightSection");
424
493
  const ComposerSendButton2 = useSlot("ComposerSendButton");
425
- return /* @__PURE__ */ jsxs6(
494
+ return /* @__PURE__ */ jsxs7(
426
495
  "div",
427
496
  {
428
497
  "data-slot": "aui_composer-shell",
@@ -432,7 +501,7 @@ function ComposerShell({
432
501
  ),
433
502
  children: [
434
503
  attachments,
435
- /* @__PURE__ */ jsx20(
504
+ /* @__PURE__ */ jsx21(
436
505
  "textarea",
437
506
  {
438
507
  value,
@@ -450,9 +519,9 @@ function ComposerShell({
450
519
  className: "placeholder:text-muted-foreground/80 max-h-32 min-h-10 w-full resize-none rounded-lg bg-transparent px-2.5 py-1 text-base outline-none"
451
520
  }
452
521
  ),
453
- /* @__PURE__ */ jsxs6("div", { className: "flex items-center justify-between px-1", children: [
454
- /* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-2", children: [
455
- /* @__PURE__ */ jsx20(
522
+ /* @__PURE__ */ jsxs7("div", { className: "flex items-center justify-between px-1", children: [
523
+ /* @__PURE__ */ jsxs7("div", { className: "flex items-center gap-2", children: [
524
+ /* @__PURE__ */ jsx21(
456
525
  ComposerLeftSection2,
457
526
  {
458
527
  disabled,
@@ -460,15 +529,15 @@ function ComposerShell({
460
529
  onAttach
461
530
  }
462
531
  ),
463
- connectorStatusLabel && /* @__PURE__ */ jsx20("span", { className: "text-muted-foreground text-xs", children: connectorStatusLabel })
532
+ connectorStatusLabel && /* @__PURE__ */ jsx21("span", { className: "text-muted-foreground text-xs", children: connectorStatusLabel })
464
533
  ] }),
465
- /* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-2", children: [
466
- modelLabel && /* @__PURE__ */ jsxs6("span", { className: "bg-muted text-muted-foreground flex items-center gap-1 rounded-full px-2 py-0.5 text-xs", children: [
534
+ /* @__PURE__ */ jsxs7("div", { className: "flex items-center gap-2", children: [
535
+ modelLabel && /* @__PURE__ */ jsxs7("span", { className: "bg-muted text-muted-foreground flex items-center gap-1 rounded-full px-2 py-0.5 text-xs", children: [
467
536
  modelIcon,
468
537
  modelLabel
469
538
  ] }),
470
- /* @__PURE__ */ jsx20(ComposerRightSection2, { disabled, isRunning }),
471
- /* @__PURE__ */ jsx20(
539
+ /* @__PURE__ */ jsx21(ComposerRightSection2, { disabled, isRunning }),
540
+ /* @__PURE__ */ jsx21(
472
541
  ComposerSendButton2,
473
542
  {
474
543
  disabled,
@@ -487,11 +556,11 @@ function ComposerShell({
487
556
 
488
557
  // src/atoms/ComposerSections.tsx
489
558
  import Spinner from "tfy-web-components/components/atoms/Spinner";
490
- import { Fragment, jsx as jsx21, jsxs as jsxs7 } from "react/jsx-runtime";
559
+ import { Fragment, jsx as jsx22, jsxs as jsxs8 } from "react/jsx-runtime";
491
560
  function ComposerLeftSection({ onAttach }) {
492
561
  const IconButton5 = useSlot("IconButton");
493
562
  if (!onAttach) return null;
494
- return /* @__PURE__ */ jsx21(IconButton5, { icon: "plus", tooltip: "Attach", onClick: onAttach });
563
+ return /* @__PURE__ */ jsx22(IconButton5, { icon: "plus", tooltip: "Attach", onClick: onAttach });
495
564
  }
496
565
  function ComposerRightSection(_) {
497
566
  return null;
@@ -504,19 +573,19 @@ function ComposerSendButton({
504
573
  }) {
505
574
  const Button4 = useSlot("Button");
506
575
  if (isRunning) {
507
- return /* @__PURE__ */ jsx21(
576
+ return /* @__PURE__ */ jsx22(
508
577
  Button4.Primary,
509
578
  {
510
579
  disabled: !onCancel,
511
580
  onClick: onCancel,
512
- text: /* @__PURE__ */ jsxs7(Fragment, { children: [
513
- /* @__PURE__ */ jsx21(Spinner, { small: true }),
581
+ text: /* @__PURE__ */ jsxs8(Fragment, { children: [
582
+ /* @__PURE__ */ jsx22(Spinner, { small: true }),
514
583
  "Cancel"
515
584
  ] })
516
585
  }
517
586
  );
518
587
  }
519
- return /* @__PURE__ */ jsx21(
588
+ return /* @__PURE__ */ jsx22(
520
589
  Button4.Primary,
521
590
  {
522
591
  disabled: !canSubmit,
@@ -537,7 +606,7 @@ import { FileTextIcon } from "lucide-react";
537
606
  var USER_MESSAGE_ATTACHMENT_PREVIEW_REM = 12;
538
607
 
539
608
  // src/atoms/AttachmentCard.tsx
540
- import { jsx as jsx22, jsxs as jsxs8 } from "react/jsx-runtime";
609
+ import { jsx as jsx23, jsxs as jsxs9 } from "react/jsx-runtime";
541
610
  function AttachmentCard({
542
611
  name,
543
612
  previewSrc,
@@ -553,7 +622,7 @@ function AttachmentCard({
553
622
  const AvatarFallback2 = useSlot("AvatarFallback");
554
623
  if (size === "preview" && isImage && previewSrc) {
555
624
  const previewSize = previewRem != null ? { width: `${previewRem}rem`, height: `${previewRem}rem` } : void 0;
556
- return /* @__PURE__ */ jsx22(
625
+ return /* @__PURE__ */ jsx23(
557
626
  "div",
558
627
  {
559
628
  "data-slot": "aui_attachment-preview",
@@ -563,11 +632,11 @@ function AttachmentCard({
563
632
  previewRem == null && "size-24",
564
633
  className
565
634
  ),
566
- children: /* @__PURE__ */ jsx22("img", { src: previewSrc, alt: name, className: "h-full w-full object-cover" })
635
+ children: /* @__PURE__ */ jsx23("img", { src: previewSrc, alt: name, className: "h-full w-full object-cover" })
567
636
  }
568
637
  );
569
638
  }
570
- return /* @__PURE__ */ jsxs8(
639
+ return /* @__PURE__ */ jsxs9(
571
640
  "div",
572
641
  {
573
642
  "data-slot": "aui_attachment-chip",
@@ -577,12 +646,12 @@ function AttachmentCard({
577
646
  className
578
647
  ),
579
648
  children: [
580
- /* @__PURE__ */ jsx22("div", { className: "bg-background flex size-7 shrink-0 items-center justify-center overflow-hidden rounded-md border", children: isImage && previewSrc ? /* @__PURE__ */ jsxs8(Avatar2, { className: "size-7 rounded-none", children: [
581
- /* @__PURE__ */ jsx22(AvatarImage2, { src: previewSrc, alt: name, className: "object-cover" }),
582
- /* @__PURE__ */ jsx22(AvatarFallback2, { children: /* @__PURE__ */ jsx22(FileTextIcon, { className: "text-muted-foreground size-4" }) })
583
- ] }) : /* @__PURE__ */ jsx22(FileTextIcon, { className: "text-muted-foreground size-4" }) }),
584
- /* @__PURE__ */ jsx22("span", { className: "text-foreground min-w-0 truncate text-sm", children: name }),
585
- onRemove && /* @__PURE__ */ jsx22(
649
+ /* @__PURE__ */ jsx23("div", { className: "bg-background flex size-7 shrink-0 items-center justify-center overflow-hidden rounded-md border", children: isImage && previewSrc ? /* @__PURE__ */ jsxs9(Avatar2, { className: "size-7 rounded-none", children: [
650
+ /* @__PURE__ */ jsx23(AvatarImage2, { src: previewSrc, alt: name, className: "object-cover" }),
651
+ /* @__PURE__ */ jsx23(AvatarFallback2, { children: /* @__PURE__ */ jsx23(FileTextIcon, { className: "text-muted-foreground size-4" }) })
652
+ ] }) : /* @__PURE__ */ jsx23(FileTextIcon, { className: "text-muted-foreground size-4" }) }),
653
+ /* @__PURE__ */ jsx23("span", { className: "text-foreground min-w-0 truncate text-sm", children: name }),
654
+ onRemove && /* @__PURE__ */ jsx23(
586
655
  IconButton5,
587
656
  {
588
657
  icon: "xmark",
@@ -598,9 +667,9 @@ function AttachmentCard({
598
667
 
599
668
  // src/atoms/AttachmentPickerButton.tsx
600
669
  import IconButton from "tfy-web-components/components/atoms/IconButton";
601
- import { jsx as jsx23 } from "react/jsx-runtime";
670
+ import { jsx as jsx24 } from "react/jsx-runtime";
602
671
  function AttachmentPickerButton(props) {
603
- return /* @__PURE__ */ jsx23(
672
+ return /* @__PURE__ */ jsx24(
604
673
  IconButton,
605
674
  {
606
675
  icon: "plus",
@@ -614,13 +683,13 @@ function AttachmentPickerButton(props) {
614
683
  // src/atoms/AttachmentPreviewDialog.tsx
615
684
  import { useState } from "react";
616
685
  import Modal from "tfy-web-components/components/atoms/Modal";
617
- import { Fragment as Fragment2, jsx as jsx24, jsxs as jsxs9 } from "react/jsx-runtime";
686
+ import { Fragment as Fragment2, jsx as jsx25, jsxs as jsxs10 } from "react/jsx-runtime";
618
687
  function AttachmentPreviewDialog({ previewSrc, children }) {
619
688
  const IconButton5 = useSlot("IconButton");
620
689
  const [open, setOpen] = useState(false);
621
- if (!previewSrc) return /* @__PURE__ */ jsx24(Fragment2, { children });
622
- return /* @__PURE__ */ jsxs9(Fragment2, { children: [
623
- /* @__PURE__ */ jsx24(
690
+ if (!previewSrc) return /* @__PURE__ */ jsx25(Fragment2, { children });
691
+ return /* @__PURE__ */ jsxs10(Fragment2, { children: [
692
+ /* @__PURE__ */ jsx25(
624
693
  "div",
625
694
  {
626
695
  role: "button",
@@ -636,9 +705,9 @@ function AttachmentPreviewDialog({ previewSrc, children }) {
636
705
  children
637
706
  }
638
707
  ),
639
- /* @__PURE__ */ jsx24(Modal, { open, onClose: () => setOpen(false), children: /* @__PURE__ */ jsxs9("div", { className: "bg-popover fixed top-1/2 left-1/2 z-50 w-full max-w-[calc(100%-2rem)] -translate-x-1/2 -translate-y-1/2 rounded-xl p-2 outline-none sm:max-w-3xl", children: [
640
- /* @__PURE__ */ jsx24("span", { className: "absolute top-2 right-2 z-10 inline-flex", children: /* @__PURE__ */ jsx24(IconButton5, { icon: "xmark", tooltip: "Close", onClick: () => setOpen(false) }) }),
641
- /* @__PURE__ */ jsx24("div", { className: "bg-background relative mx-auto flex max-h-[80dvh] w-full items-center justify-center overflow-hidden", children: /* @__PURE__ */ jsx24(
708
+ /* @__PURE__ */ jsx25(Modal, { open, onClose: () => setOpen(false), children: /* @__PURE__ */ jsxs10("div", { className: "bg-popover fixed top-1/2 left-1/2 z-50 w-full max-w-[calc(100%-2rem)] -translate-x-1/2 -translate-y-1/2 rounded-xl p-2 outline-none sm:max-w-3xl", children: [
709
+ /* @__PURE__ */ jsx25("span", { className: "absolute top-2 right-2 z-10 inline-flex", children: /* @__PURE__ */ jsx25(IconButton5, { icon: "xmark", tooltip: "Close", onClick: () => setOpen(false) }) }),
710
+ /* @__PURE__ */ jsx25("div", { className: "bg-background relative mx-auto flex max-h-[80dvh] w-full items-center justify-center overflow-hidden", children: /* @__PURE__ */ jsx25(
642
711
  "img",
643
712
  {
644
713
  src: previewSrc,
@@ -653,16 +722,16 @@ function AttachmentPreviewDialog({ previewSrc, children }) {
653
722
  // src/atoms/ScrollToBottomButton.tsx
654
723
  import { forwardRef as forwardRef2 } from "react";
655
724
  import IconButton2 from "tfy-web-components/components/atoms/IconButton";
656
- import { jsx as jsx25 } from "react/jsx-runtime";
725
+ import { jsx as jsx26 } from "react/jsx-runtime";
657
726
  var ScrollToBottomButton = forwardRef2(
658
727
  ({ className, disabled, ...rest }, ref) => {
659
728
  if (disabled) return null;
660
- return /* @__PURE__ */ jsx25(
729
+ return /* @__PURE__ */ jsx26(
661
730
  "span",
662
731
  {
663
732
  ref,
664
733
  className: cn("absolute -top-14 z-10 inline-flex self-center"),
665
- children: /* @__PURE__ */ jsx25(
734
+ children: /* @__PURE__ */ jsx26(
666
735
  IconButton2,
667
736
  {
668
737
  icon: "arrow-down",
@@ -682,12 +751,12 @@ var ScrollToBottomButton = forwardRef2(
682
751
  ScrollToBottomButton.displayName = "ScrollToBottomButton";
683
752
 
684
753
  // src/atoms/ThreadListRow.tsx
685
- import IconProvider from "tfy-web-components/components/atoms/IconProvider";
754
+ import IconProvider2 from "tfy-web-components/components/atoms/IconProvider";
686
755
  import IconButton3 from "tfy-web-components/components/atoms/IconButton";
687
756
  import DropdownMenu from "tfy-web-components/components/molecules/DropdownMenu";
688
- import { jsx as jsx26, jsxs as jsxs10 } from "react/jsx-runtime";
757
+ import { jsx as jsx27, jsxs as jsxs11 } from "react/jsx-runtime";
689
758
  function ThreadListRow({ title, active, onSelect, onArchive, onDelete, className }) {
690
- return /* @__PURE__ */ jsxs10(
759
+ return /* @__PURE__ */ jsxs11(
691
760
  "div",
692
761
  {
693
762
  "data-slot": "aui_thread-list-item",
@@ -697,20 +766,20 @@ function ThreadListRow({ title, active, onSelect, onArchive, onDelete, className
697
766
  className
698
767
  ),
699
768
  children: [
700
- /* @__PURE__ */ jsx26(
769
+ /* @__PURE__ */ jsx27(
701
770
  "button",
702
771
  {
703
772
  type: "button",
704
773
  onClick: onSelect,
705
774
  "data-slot": "aui_thread-list-item-trigger",
706
775
  className: "flex min-h-9 min-w-0 flex-1 items-center rounded-lg px-2.5 py-2 text-start text-sm outline-none group-hover:pe-9",
707
- children: /* @__PURE__ */ jsx26("span", { className: "min-w-0 flex-1 truncate", children: title })
776
+ children: /* @__PURE__ */ jsx27("span", { className: "min-w-0 flex-1 truncate", children: title })
708
777
  }
709
778
  ),
710
- (onArchive || onDelete) && /* @__PURE__ */ jsx26("div", { className: "absolute end-1.5 top-1/2 inline-flex -translate-y-1/2 opacity-0 group-hover:opacity-100", children: /* @__PURE__ */ jsxs10(
779
+ (onArchive || onDelete) && /* @__PURE__ */ jsx27("div", { className: "absolute end-1.5 top-1/2 inline-flex -translate-y-1/2 opacity-0 group-hover:opacity-100", children: /* @__PURE__ */ jsxs11(
711
780
  DropdownMenu,
712
781
  {
713
- trigger: /* @__PURE__ */ jsx26(
782
+ trigger: /* @__PURE__ */ jsx27(
714
783
  IconButton3,
715
784
  {
716
785
  icon: "ellipsis",
@@ -721,12 +790,12 @@ function ThreadListRow({ title, active, onSelect, onArchive, onDelete, className
721
790
  side: "right",
722
791
  align: "start",
723
792
  children: [
724
- onArchive && /* @__PURE__ */ jsxs10(DropdownMenu.Item, { onClick: onArchive, children: [
725
- /* @__PURE__ */ jsx26(IconProvider, { icon: "box-archive", size: 0.75 }),
793
+ onArchive && /* @__PURE__ */ jsxs11(DropdownMenu.Item, { onClick: onArchive, children: [
794
+ /* @__PURE__ */ jsx27(IconProvider2, { icon: "box-archive", size: 0.75 }),
726
795
  "Archive"
727
796
  ] }),
728
- onDelete && /* @__PURE__ */ jsxs10(DropdownMenu.Item, { onClick: onDelete, className: "text-destructive hover:bg-destructive/10", children: [
729
- /* @__PURE__ */ jsx26(IconProvider, { icon: "trash", size: 0.75 }),
797
+ onDelete && /* @__PURE__ */ jsxs11(DropdownMenu.Item, { onClick: onDelete, className: "text-destructive hover:bg-destructive/10", children: [
798
+ /* @__PURE__ */ jsx27(IconProvider2, { icon: "trash", size: 0.75 }),
730
799
  "Delete"
731
800
  ] })
732
801
  ]
@@ -740,9 +809,9 @@ function ThreadListRow({ title, active, onSelect, onArchive, onDelete, className
740
809
  // src/atoms/ThreadListMisc.tsx
741
810
  import Button from "tfy-web-components/components/atoms/Button";
742
811
  import Skeleton2 from "tfy-web-components/components/atoms/Skeleton";
743
- import { jsx as jsx27, jsxs as jsxs11 } from "react/jsx-runtime";
812
+ import { jsx as jsx28, jsxs as jsxs12 } from "react/jsx-runtime";
744
813
  function ThreadListNewButton({ className, ...rest }) {
745
- return /* @__PURE__ */ jsx27(
814
+ return /* @__PURE__ */ jsx28(
746
815
  Button.Ghost,
747
816
  {
748
817
  "data-slot": "aui_thread-list-new",
@@ -754,24 +823,24 @@ function ThreadListNewButton({ className, ...rest }) {
754
823
  );
755
824
  }
756
825
  function ThreadListRowSkeleton({ count = 5, className }) {
757
- return /* @__PURE__ */ jsx27("div", { className: cn("flex flex-col gap-1", className), role: "status", "aria-label": "Loading threads", children: Array.from({ length: count }, (_, i) => /* @__PURE__ */ jsx27("div", { className: "flex h-8 items-center px-2.5", children: /* @__PURE__ */ jsx27(Skeleton2, { className: "h-3.5 w-full" }) }, i)) });
826
+ return /* @__PURE__ */ jsx28("div", { className: cn("flex flex-col gap-1", className), role: "status", "aria-label": "Loading threads", children: Array.from({ length: count }, (_, i) => /* @__PURE__ */ jsx28("div", { className: "flex h-8 items-center px-2.5", children: /* @__PURE__ */ jsx28(Skeleton2, { className: "h-3.5 w-full" }) }, i)) });
758
827
  }
759
828
  function ThreadListEmptyState({ message = "No threads yet", className }) {
760
- return /* @__PURE__ */ jsx27("div", { className: cn("text-muted-foreground flex flex-1 items-center justify-center px-4 text-center text-sm", className), children: message });
829
+ return /* @__PURE__ */ jsx28("div", { className: cn("text-muted-foreground flex flex-1 items-center justify-center px-4 text-center text-sm", className), children: message });
761
830
  }
762
831
  function ThreadListShell({ header, children, className }) {
763
- return /* @__PURE__ */ jsxs11("div", { className: cn("font-sans-flex flex min-h-0 flex-1 flex-col gap-1 overflow-hidden p-3", className), children: [
832
+ return /* @__PURE__ */ jsxs12("div", { className: cn("font-sans-flex flex min-h-0 flex-1 flex-col gap-1 overflow-hidden p-3", className), children: [
764
833
  header,
765
- /* @__PURE__ */ jsx27("div", { className: "flex min-h-0 flex-1 flex-col gap-3 overflow-y-auto pb-1", children })
834
+ /* @__PURE__ */ jsx28("div", { className: "flex min-h-0 flex-1 flex-col gap-3 overflow-y-auto pb-1", children })
766
835
  ] });
767
836
  }
768
837
 
769
838
  // src/atoms/MessageActionBar.tsx
770
- import { jsx as jsx28, jsxs as jsxs12 } from "react/jsx-runtime";
839
+ import { jsx as jsx29, jsxs as jsxs13 } from "react/jsx-runtime";
771
840
  function MessageActionBar({ isCopied, onCopy, className }) {
772
841
  const MessageTimestamp2 = useSlot("MessageTimestamp");
773
842
  const IconButton5 = useSlot("IconButton");
774
- return /* @__PURE__ */ jsxs12(
843
+ return /* @__PURE__ */ jsxs13(
775
844
  "div",
776
845
  {
777
846
  className: cn(
@@ -779,8 +848,8 @@ function MessageActionBar({ isCopied, onCopy, className }) {
779
848
  className
780
849
  ),
781
850
  children: [
782
- /* @__PURE__ */ jsx28(MessageTimestamp2, {}),
783
- /* @__PURE__ */ jsx28(
851
+ /* @__PURE__ */ jsx29(MessageTimestamp2, {}),
852
+ /* @__PURE__ */ jsx29(
784
853
  IconButton5,
785
854
  {
786
855
  icon: isCopied ? "check" : ["far", "clone"],
@@ -795,7 +864,7 @@ function MessageActionBar({ isCopied, onCopy, className }) {
795
864
 
796
865
  // src/atoms/Markdown.tsx
797
866
  import { MarkdownWithOpenUI } from "tfy-web-components/components/molecules/Markdown";
798
- import { jsx as jsx29 } from "react/jsx-runtime";
867
+ import { jsx as jsx30 } from "react/jsx-runtime";
799
868
  function Markdown({
800
869
  content,
801
870
  isStreaming,
@@ -805,7 +874,7 @@ function Markdown({
805
874
  className
806
875
  }) {
807
876
  const mode = useThemeMode();
808
- return /* @__PURE__ */ jsx29(
877
+ return /* @__PURE__ */ jsx30(
809
878
  MarkdownWithOpenUI,
810
879
  {
811
880
  isStreaming,
@@ -821,14 +890,14 @@ function Markdown({
821
890
 
822
891
  // src/atoms/AssistantMessageBubble.tsx
823
892
  import { AssistantMessage } from "tfy-web-components/components/molecules/agent-chat";
824
- import { jsx as jsx30 } from "react/jsx-runtime";
893
+ import { jsx as jsx31 } from "react/jsx-runtime";
825
894
  function AssistantMessageBubble({
826
895
  children,
827
896
  error,
828
897
  actionBar,
829
898
  className
830
899
  }) {
831
- return /* @__PURE__ */ jsx30(
900
+ return /* @__PURE__ */ jsx31(
832
901
  "div",
833
902
  {
834
903
  "data-slot": "aui_assistant-message-root",
@@ -836,15 +905,36 @@ function AssistantMessageBubble({
836
905
  "group/assistant fade-in slide-in-from-bottom-1 animate-in relative duration-150",
837
906
  className
838
907
  ),
839
- children: /* @__PURE__ */ jsx30(AssistantMessage, { error, actionBar, children })
908
+ children: /* @__PURE__ */ jsx31(AssistantMessage, { error, actionBar, children })
840
909
  }
841
910
  );
842
911
  }
843
912
 
913
+ // src/atoms/HistoryLoader.tsx
914
+ import { forwardRef as forwardRef3 } from "react";
915
+ import Spinner2 from "tfy-web-components/components/atoms/Spinner";
916
+ import { jsx as jsx32 } from "react/jsx-runtime";
917
+ var HistoryLoader = forwardRef3(
918
+ ({ className, isLoading = false, ...rest }, ref) => /* @__PURE__ */ jsx32(
919
+ "div",
920
+ {
921
+ ref,
922
+ "data-slot": "aui_history-loader",
923
+ role: "status",
924
+ "aria-live": "polite",
925
+ "aria-label": isLoading ? "Loading older messages" : "Scroll up to load older messages",
926
+ className: cn("flex justify-center py-2", className),
927
+ ...rest,
928
+ children: isLoading && /* @__PURE__ */ jsx32(Spinner2, { small: true })
929
+ }
930
+ )
931
+ );
932
+ HistoryLoader.displayName = "HistoryLoader";
933
+
844
934
  // src/atoms/MessageErrorBanner.tsx
845
- import { jsx as jsx31 } from "react/jsx-runtime";
935
+ import { jsx as jsx33 } from "react/jsx-runtime";
846
936
  function MessageErrorBanner({ message, className }) {
847
- return /* @__PURE__ */ jsx31(
937
+ return /* @__PURE__ */ jsx33(
848
938
  "div",
849
939
  {
850
940
  role: "alert",
@@ -852,15 +942,15 @@ function MessageErrorBanner({ message, className }) {
852
942
  "aui-message-error-root border-destructive bg-destructive/10 text-destructive dark:bg-destructive/5 mt-2 rounded-md border p-3 text-sm dark:text-red-200",
853
943
  className
854
944
  ),
855
- children: /* @__PURE__ */ jsx31("span", { className: "aui-message-error-message line-clamp-2", children: message })
945
+ children: /* @__PURE__ */ jsx33("span", { className: "aui-message-error-message line-clamp-2", children: message })
856
946
  }
857
947
  );
858
948
  }
859
949
 
860
950
  // src/atoms/MessageIndicator.tsx
861
- import { jsx as jsx32 } from "react/jsx-runtime";
951
+ import { jsx as jsx34 } from "react/jsx-runtime";
862
952
  function MessageIndicator({ className }) {
863
- return /* @__PURE__ */ jsx32(
953
+ return /* @__PURE__ */ jsx34(
864
954
  "span",
865
955
  {
866
956
  "data-slot": "aui_assistant-message-indicator",
@@ -873,7 +963,7 @@ function MessageIndicator({ className }) {
873
963
 
874
964
  // src/atoms/MessageTimestamp.tsx
875
965
  import { useAuiState } from "@assistant-ui/react";
876
- import { jsx as jsx33 } from "react/jsx-runtime";
966
+ import { jsx as jsx35 } from "react/jsx-runtime";
877
967
  function toDate(createdAt) {
878
968
  if (createdAt == null) {
879
969
  return null;
@@ -906,7 +996,7 @@ function MessageTimestamp({ className }) {
906
996
  if (date == null) {
907
997
  return null;
908
998
  }
909
- return /* @__PURE__ */ jsx33(LightTooltip3, { title: formatFullDate(date), size: "fit", children: /* @__PURE__ */ jsx33(
999
+ return /* @__PURE__ */ jsx35(LightTooltip3, { title: formatFullDate(date), size: "fit", children: /* @__PURE__ */ jsx35(
910
1000
  "span",
911
1001
  {
912
1002
  className: cn(
@@ -922,7 +1012,7 @@ function MessageTimestamp({ className }) {
922
1012
  import { ActionBarPrimitive, useAuiState as useAuiState2 } from "@assistant-ui/react";
923
1013
  import { useActionBarCopy, useActionBarEdit } from "@assistant-ui/core/react";
924
1014
  import { useTrueFoundryResetFromTurn } from "@truefoundry/assistant-ui-runtime";
925
- import { jsx as jsx34, jsxs as jsxs13 } from "react/jsx-runtime";
1015
+ import { jsx as jsx36, jsxs as jsxs14 } from "react/jsx-runtime";
926
1016
  function parseTurnIdFromMessageId(messageId) {
927
1017
  return messageId.replace(/-user$/, "");
928
1018
  }
@@ -936,7 +1026,7 @@ function UserMessageActionBar({ className }) {
936
1026
  const { copy, isCopied } = useActionBarCopy({
937
1027
  copyToClipboard: (text) => navigator.clipboard.writeText(text)
938
1028
  });
939
- return /* @__PURE__ */ jsxs13(
1029
+ return /* @__PURE__ */ jsxs14(
940
1030
  ActionBarPrimitive.Root,
941
1031
  {
942
1032
  hideWhenRunning: true,
@@ -945,7 +1035,7 @@ function UserMessageActionBar({ className }) {
945
1035
  className
946
1036
  ),
947
1037
  children: [
948
- /* @__PURE__ */ jsx34(
1038
+ /* @__PURE__ */ jsx36(
949
1039
  IconButton5,
950
1040
  {
951
1041
  icon: "rotate-right",
@@ -953,7 +1043,7 @@ function UserMessageActionBar({ className }) {
953
1043
  onClick: () => void resetFromTurn(turnId)
954
1044
  }
955
1045
  ),
956
- /* @__PURE__ */ jsx34(
1046
+ /* @__PURE__ */ jsx36(
957
1047
  IconButton5,
958
1048
  {
959
1049
  icon: "pencil",
@@ -962,7 +1052,7 @@ function UserMessageActionBar({ className }) {
962
1052
  onClick: edit
963
1053
  }
964
1054
  ),
965
- /* @__PURE__ */ jsx34(
1055
+ /* @__PURE__ */ jsx36(
966
1056
  IconButton5,
967
1057
  {
968
1058
  icon: isCopied ? "check" : ["far", "clone"],
@@ -970,23 +1060,23 @@ function UserMessageActionBar({ className }) {
970
1060
  onClick: copy
971
1061
  }
972
1062
  ),
973
- /* @__PURE__ */ jsx34(MessageTimestamp2, {})
1063
+ /* @__PURE__ */ jsx36(MessageTimestamp2, {})
974
1064
  ]
975
1065
  }
976
1066
  );
977
1067
  }
978
1068
 
979
1069
  // src/atoms/ThreadShell.tsx
980
- import { forwardRef as forwardRef3 } from "react";
981
- import { jsx as jsx35 } from "react/jsx-runtime";
1070
+ import { forwardRef as forwardRef4 } from "react";
1071
+ import { jsx as jsx37 } from "react/jsx-runtime";
982
1072
  var THREAD_CSS_VARS = {
983
1073
  ["--thread-max-width"]: "44rem",
984
1074
  ["--composer-bg"]: "color-mix(in oklab, var(--color-muted) 30%, var(--color-background))",
985
1075
  ["--composer-radius"]: "1.5rem",
986
1076
  ["--composer-padding"]: "8px"
987
1077
  };
988
- var ThreadRootShell = forwardRef3(
989
- ({ className, style, ...rest }, ref) => /* @__PURE__ */ jsx35(
1078
+ var ThreadRootShell = forwardRef4(
1079
+ ({ className, style, ...rest }, ref) => /* @__PURE__ */ jsx37(
990
1080
  "div",
991
1081
  {
992
1082
  ref,
@@ -1000,15 +1090,15 @@ var ThreadRootShell = forwardRef3(
1000
1090
  )
1001
1091
  );
1002
1092
  ThreadRootShell.displayName = "ThreadRootShell";
1003
- var ThreadViewportShell = forwardRef3(
1004
- ({ className, isEmpty, children, ...rest }, ref) => /* @__PURE__ */ jsx35(
1093
+ var ThreadViewportShell = forwardRef4(
1094
+ ({ className, isEmpty, children, ...rest }, ref) => /* @__PURE__ */ jsx37(
1005
1095
  "div",
1006
1096
  {
1007
1097
  ref,
1008
1098
  "data-slot": "aui_thread-viewport",
1009
1099
  className: cn("relative flex min-h-0 flex-1 flex-col overflow-x-auto overflow-y-auto scroll-smooth", className),
1010
1100
  ...rest,
1011
- children: /* @__PURE__ */ jsx35(
1101
+ children: /* @__PURE__ */ jsx37(
1012
1102
  "div",
1013
1103
  {
1014
1104
  className: cn(
@@ -1022,8 +1112,8 @@ var ThreadViewportShell = forwardRef3(
1022
1112
  )
1023
1113
  );
1024
1114
  ThreadViewportShell.displayName = "ThreadViewportShell";
1025
- var ThreadComposerAreaShell = forwardRef3(
1026
- ({ className, isEmpty, ...rest }, ref) => /* @__PURE__ */ jsx35(
1115
+ var ThreadComposerAreaShell = forwardRef4(
1116
+ ({ className, isEmpty, ...rest }, ref) => /* @__PURE__ */ jsx37(
1027
1117
  "div",
1028
1118
  {
1029
1119
  ref,
@@ -1038,7 +1128,7 @@ var ThreadComposerAreaShell = forwardRef3(
1038
1128
  )
1039
1129
  );
1040
1130
  ThreadComposerAreaShell.displayName = "ThreadComposerAreaShell";
1041
- var MessageGroup = forwardRef3(({ className, ...rest }, ref) => /* @__PURE__ */ jsx35(
1131
+ var MessageGroup = forwardRef4(({ className, ...rest }, ref) => /* @__PURE__ */ jsx37(
1042
1132
  "div",
1043
1133
  {
1044
1134
  ref,
@@ -1050,17 +1140,17 @@ var MessageGroup = forwardRef3(({ className, ...rest }, ref) => /* @__PURE__ */
1050
1140
  MessageGroup.displayName = "MessageGroup";
1051
1141
 
1052
1142
  // src/atoms/WelcomeScreen.tsx
1053
- import { jsx as jsx36 } from "react/jsx-runtime";
1143
+ import { jsx as jsx38 } from "react/jsx-runtime";
1054
1144
  function WelcomeScreen({ heading = "How can I help you today?", className }) {
1055
- return /* @__PURE__ */ jsx36("div", { className: cn("aui-thread-welcome-root mb-6 flex flex-col items-center px-4 text-center", className), children: /* @__PURE__ */ jsx36("h1", { className: "aui-thread-welcome-message-inner fade-in slide-in-from-bottom-1 animate-in fill-mode-both text-2xl font-semibold duration-200", children: heading }) });
1145
+ return /* @__PURE__ */ jsx38("div", { className: cn("aui-thread-welcome-root mb-6 flex flex-col items-center px-4 text-center", className), children: /* @__PURE__ */ jsx38("h1", { className: "aui-thread-welcome-message-inner fade-in slide-in-from-bottom-1 animate-in fill-mode-both text-2xl font-semibold duration-200", children: heading }) });
1056
1146
  }
1057
1147
 
1058
1148
  // src/atoms/Toast.tsx
1059
1149
  import { XIcon } from "lucide-react";
1060
- import { jsx as jsx37, jsxs as jsxs14 } from "react/jsx-runtime";
1150
+ import { jsx as jsx39, jsxs as jsxs15 } from "react/jsx-runtime";
1061
1151
  function Toast({ title, description, open, onOpenChange, className }) {
1062
1152
  if (!open) return null;
1063
- return /* @__PURE__ */ jsxs14(
1153
+ return /* @__PURE__ */ jsxs15(
1064
1154
  "div",
1065
1155
  {
1066
1156
  className: cn(
@@ -1069,18 +1159,18 @@ function Toast({ title, description, open, onOpenChange, className }) {
1069
1159
  className
1070
1160
  ),
1071
1161
  children: [
1072
- /* @__PURE__ */ jsxs14("div", { className: "grid min-h-0 min-w-0 flex-1 gap-1 overflow-y-auto pe-6", children: [
1073
- /* @__PURE__ */ jsx37("div", { className: "text-sm leading-none font-semibold", children: title }),
1074
- /* @__PURE__ */ jsx37("div", { className: "font-mono text-sm break-words whitespace-pre-wrap", children: description })
1162
+ /* @__PURE__ */ jsxs15("div", { className: "grid min-h-0 min-w-0 flex-1 gap-1 overflow-y-auto pe-6", children: [
1163
+ /* @__PURE__ */ jsx39("div", { className: "text-sm leading-none font-semibold", children: title }),
1164
+ /* @__PURE__ */ jsx39("div", { className: "font-mono text-sm break-words whitespace-pre-wrap", children: description })
1075
1165
  ] }),
1076
- /* @__PURE__ */ jsxs14(
1166
+ /* @__PURE__ */ jsxs15(
1077
1167
  "button",
1078
1168
  {
1079
1169
  onClick: () => onOpenChange(false),
1080
1170
  className: "text-destructive hover:bg-muted focus-visible:ring-ring absolute top-3 right-3 rounded-md p-1 transition-colors focus:outline-none focus-visible:ring-2",
1081
1171
  children: [
1082
- /* @__PURE__ */ jsx37(XIcon, { className: "size-4" }),
1083
- /* @__PURE__ */ jsx37("span", { className: "sr-only", children: "Close" })
1172
+ /* @__PURE__ */ jsx39(XIcon, { className: "size-4" }),
1173
+ /* @__PURE__ */ jsx39("span", { className: "sr-only", children: "Close" })
1084
1174
  ]
1085
1175
  }
1086
1176
  )
@@ -1089,7 +1179,7 @@ function Toast({ title, description, open, onOpenChange, className }) {
1089
1179
  );
1090
1180
  }
1091
1181
  function ToastStack({ children, duration = Number.POSITIVE_INFINITY }) {
1092
- return /* @__PURE__ */ jsx37("div", { className: "pointer-events-none fixed bottom-4 left-1/2 z-50 flex h-full max-h-screen w-full max-w-2xl -translate-x-1/2 flex-col-reverse gap-2 px-4", children });
1182
+ return /* @__PURE__ */ jsx39("div", { className: "pointer-events-none fixed bottom-4 left-1/2 z-50 flex h-full max-h-screen w-full max-w-2xl -translate-x-1/2 flex-col-reverse gap-2 px-4", children });
1093
1183
  }
1094
1184
 
1095
1185
  // src/theme/defaultSlots.ts
@@ -1100,9 +1190,9 @@ var defaultSlots = {
1100
1190
  LightTooltip,
1101
1191
  Modal: Modal2,
1102
1192
  Dialog,
1103
- Accordion: Accordion2,
1104
- AccordionSummary: AccordionSummary2,
1105
- AccordionDetails: AccordionDetails2,
1193
+ Accordion: Accordion3,
1194
+ AccordionSummary: AccordionSummary3,
1195
+ AccordionDetails: AccordionDetails3,
1106
1196
  Skeleton: Skeleton3,
1107
1197
  ReasoningCard,
1108
1198
  AskUserPrompt,
@@ -1119,6 +1209,7 @@ var defaultSlots = {
1119
1209
  SandboxToolCallCard,
1120
1210
  ToolApprovalBar,
1121
1211
  ToolGroupCard,
1212
+ AgentStepsCard,
1122
1213
  MessageListSkeleton,
1123
1214
  ComposerShell,
1124
1215
  ComposerLeftSection,
@@ -1137,6 +1228,7 @@ var defaultSlots = {
1137
1228
  Markdown,
1138
1229
  // SDK atoms — SDK-owned (no tfy slot component)
1139
1230
  AssistantMessageBubble,
1231
+ HistoryLoader,
1140
1232
  MessageErrorBanner,
1141
1233
  MessageTimestamp,
1142
1234
  UserMessageActionBar,
@@ -1151,7 +1243,7 @@ var defaultSlots = {
1151
1243
  };
1152
1244
 
1153
1245
  // src/theme/SlotsProvider.tsx
1154
- import { jsx as jsx38 } from "react/jsx-runtime";
1246
+ import { jsx as jsx40 } from "react/jsx-runtime";
1155
1247
  var SlotsContext = createContext(defaultSlots);
1156
1248
  var ThemeModeContext = createContext(void 0);
1157
1249
  function SlotsProvider({
@@ -1165,14 +1257,14 @@ function SlotsProvider({
1165
1257
  () => ({ ...parentSlots, ...overrides }),
1166
1258
  [parentSlots, overrides]
1167
1259
  );
1168
- return /* @__PURE__ */ jsx38(TfyThemeProvider, { theme: theme ?? inheritedTheme, children: /* @__PURE__ */ jsx38(SlotsProviderContents, { slots: resolved, children }) });
1260
+ return /* @__PURE__ */ jsx40(TfyThemeProvider, { theme: theme ?? inheritedTheme, children: /* @__PURE__ */ jsx40(SlotsProviderContents, { slots: resolved, children }) });
1169
1261
  }
1170
1262
  function SlotsProviderContents({
1171
1263
  slots,
1172
1264
  children
1173
1265
  }) {
1174
1266
  const { mode } = useTfyTheme();
1175
- return /* @__PURE__ */ jsx38(ThemeModeContext.Provider, { value: mode, children: /* @__PURE__ */ jsx38(SlotsContext.Provider, { value: slots, children }) });
1267
+ return /* @__PURE__ */ jsx40(ThemeModeContext.Provider, { value: mode, children: /* @__PURE__ */ jsx40(SlotsContext.Provider, { value: slots, children }) });
1176
1268
  }
1177
1269
  function useSlot(name) {
1178
1270
  const slots = useContext(SlotsContext);
@@ -1252,14 +1344,14 @@ import { LightTooltip as LightTooltip2 } from "tfy-web-components/components/ato
1252
1344
  import { default as default4 } from "tfy-web-components/components/atoms/Modal";
1253
1345
  import { default as default5 } from "tfy-web-components/components/molecules/Dialog";
1254
1346
  import {
1255
- Accordion as Accordion3,
1256
- AccordionSummary as AccordionSummary3,
1257
- AccordionDetails as AccordionDetails3
1347
+ Accordion as Accordion4,
1348
+ AccordionSummary as AccordionSummary4,
1349
+ AccordionDetails as AccordionDetails4
1258
1350
  } from "tfy-web-components/components/atoms/Accordion";
1259
1351
  import { default as default6 } from "tfy-web-components/components/atoms/Skeleton";
1260
1352
 
1261
1353
  // src/containers/ThreadContainer.tsx
1262
- import { useEffect as useEffect4 } from "react";
1354
+ import { useEffect as useEffect6 } from "react";
1263
1355
  import { preloadMarkdownOpenUI } from "tfy-web-components/components/molecules/Markdown";
1264
1356
  import { ThreadPrimitive, useAuiState as useAuiState11 } from "@assistant-ui/react";
1265
1357
 
@@ -1307,9 +1399,51 @@ function useComposerBusyState() {
1307
1399
  }
1308
1400
 
1309
1401
  // src/containers/AssistantMessageContainer.tsx
1310
- import { groupPartByType, MessagePrimitive as MessagePrimitive2 } from "@assistant-ui/react";
1402
+ import { MessagePrimitive as MessagePrimitive2, useAuiState as useAuiState6 } from "@assistant-ui/react";
1311
1403
  import { useActionBarCopy as useActionBarCopy2, useMessageError, useThreadIsRunning as useThreadIsRunning2 } from "@assistant-ui/core/react";
1312
1404
 
1405
+ // src/utils/computeAgentStepsSplit.ts
1406
+ function computeAgentStepsSplit(parts, isRunning) {
1407
+ const finalTexts = [];
1408
+ let cutIdx = parts.length;
1409
+ for (let i = parts.length - 1; i >= 0; i--) {
1410
+ const part = parts[i];
1411
+ if (!part) continue;
1412
+ if (part.type === "text") {
1413
+ const text = part.text ?? "";
1414
+ const trimmed = text.trim();
1415
+ if (trimmed) {
1416
+ finalTexts.unshift({ index: i, content: text });
1417
+ cutIdx = i;
1418
+ } else {
1419
+ cutIdx = i;
1420
+ }
1421
+ } else {
1422
+ break;
1423
+ }
1424
+ }
1425
+ const trailingChars = finalTexts.reduce((sum, t) => sum + t.content.length, 0);
1426
+ const finalConfirmed = finalTexts.length > 0 && (!isRunning || trailingChars >= 500);
1427
+ const actualCutIndex = finalConfirmed ? cutIdx : parts.length;
1428
+ let toolCount = 0;
1429
+ let thinkingCount = 0;
1430
+ for (let i = 0; i < actualCutIndex; i++) {
1431
+ const part = parts[i];
1432
+ if (!part) continue;
1433
+ if (part.type === "tool-call") {
1434
+ toolCount++;
1435
+ } else if (part.type === "reasoning") {
1436
+ thinkingCount++;
1437
+ }
1438
+ }
1439
+ return {
1440
+ cutIndex: actualCutIndex,
1441
+ hasFinal: finalConfirmed,
1442
+ toolCount,
1443
+ thinkingCount
1444
+ };
1445
+ }
1446
+
1313
1447
  // src/containers/AssistantTextContainer.tsx
1314
1448
  import { useCallback as useCallback3 } from "react";
1315
1449
  import { useAuiState as useAuiState3 } from "@assistant-ui/react";
@@ -1318,7 +1452,7 @@ import { useTrueFoundryDownloadSandboxFile } from "@truefoundry/assistant-ui-run
1318
1452
  // src/containers/ErrorToasterContainer.tsx
1319
1453
  import { createContext as createContext4, useCallback as useCallback2, useContext as useContext4, useMemo as useMemo2, useState as useState3 } from "react";
1320
1454
  import { TrueFoundryGatewayError } from "truefoundry-gateway-sdk";
1321
- import { jsx as jsx39, jsxs as jsxs15 } from "react/jsx-runtime";
1455
+ import { jsx as jsx41, jsxs as jsxs16 } from "react/jsx-runtime";
1322
1456
  var ErrorToasterContext = createContext4(null);
1323
1457
  function formatErrorBody(body) {
1324
1458
  if (body == null) return void 0;
@@ -1351,9 +1485,9 @@ function ErrorToasterProvider({ children }) {
1351
1485
  setOpen(true);
1352
1486
  }, []);
1353
1487
  const value = useMemo2(() => ({ showError }), [showError]);
1354
- return /* @__PURE__ */ jsxs15(ErrorToasterContext.Provider, { value, children: [
1488
+ return /* @__PURE__ */ jsxs16(ErrorToasterContext.Provider, { value, children: [
1355
1489
  children,
1356
- /* @__PURE__ */ jsx39(ToastStack2, { children: toast != null && /* @__PURE__ */ jsx39(Toast2, { title: toast.title, description: toast.description, open, onOpenChange: setOpen }) })
1490
+ /* @__PURE__ */ jsx41(ToastStack2, { children: toast != null && /* @__PURE__ */ jsx41(Toast2, { title: toast.title, description: toast.description, open, onOpenChange: setOpen }) })
1357
1491
  ] });
1358
1492
  }
1359
1493
  function useErrorToaster() {
@@ -1368,7 +1502,7 @@ function useErrorToasterOptional() {
1368
1502
  }
1369
1503
 
1370
1504
  // src/containers/AssistantTextContainer.tsx
1371
- import { jsx as jsx40 } from "react/jsx-runtime";
1505
+ import { jsx as jsx42 } from "react/jsx-runtime";
1372
1506
  function filenameFromPath(path) {
1373
1507
  return path.split("/").pop() || "download";
1374
1508
  }
@@ -1405,12 +1539,12 @@ function AssistantTextContainer() {
1405
1539
  }),
1406
1540
  [downloadSandboxFile, errorToaster]
1407
1541
  );
1408
- return /* @__PURE__ */ jsx40(Markdown2, { content: text, isStreaming, onDownloadArtifact: handleDownloadArtifact });
1542
+ return /* @__PURE__ */ jsx42(Markdown2, { content: text, isStreaming, onDownloadArtifact: handleDownloadArtifact });
1409
1543
  }
1410
1544
 
1411
1545
  // src/containers/MessageImageContainer.tsx
1412
1546
  import { useAuiState as useAuiState4 } from "@assistant-ui/react";
1413
- import { jsx as jsx41 } from "react/jsx-runtime";
1547
+ import { jsx as jsx43 } from "react/jsx-runtime";
1414
1548
  function MessageImageContainer() {
1415
1549
  const AttachmentCard2 = useSlot("AttachmentCard");
1416
1550
  const AttachmentPreviewDialog2 = useSlot("AttachmentPreviewDialog");
@@ -1421,7 +1555,7 @@ function MessageImageContainer() {
1421
1555
  if (!image) {
1422
1556
  return null;
1423
1557
  }
1424
- const card = /* @__PURE__ */ jsx41(
1558
+ const card = /* @__PURE__ */ jsx43(
1425
1559
  AttachmentCard2,
1426
1560
  {
1427
1561
  name: filename ?? "image",
@@ -1431,13 +1565,13 @@ function MessageImageContainer() {
1431
1565
  previewRem: USER_MESSAGE_ATTACHMENT_PREVIEW_REM
1432
1566
  }
1433
1567
  );
1434
- return /* @__PURE__ */ jsx41(AttachmentPreviewDialog2, { previewSrc: image, children: /* @__PURE__ */ jsx41("div", { className: "aui-message-image", children: card }) });
1568
+ return /* @__PURE__ */ jsx43(AttachmentPreviewDialog2, { previewSrc: image, children: /* @__PURE__ */ jsx43("div", { className: "aui-message-image", children: card }) });
1435
1569
  }
1436
1570
 
1437
1571
  // src/containers/ReasoningContainer.tsx
1438
1572
  import { useCallback as useCallback4, useRef, useState as useState4 } from "react";
1439
1573
  import { useAuiState as useAuiState5 } from "@assistant-ui/react";
1440
- import { jsx as jsx42 } from "react/jsx-runtime";
1574
+ import { jsx as jsx44 } from "react/jsx-runtime";
1441
1575
  function ReasoningContainer({ group }) {
1442
1576
  const ReasoningCard2 = useSlot("ReasoningCard");
1443
1577
  const content = useAuiState5(
@@ -1478,7 +1612,7 @@ function ReasoningContainer({ group }) {
1478
1612
  const previewText = content.replace(/\s+/g, " ").trim();
1479
1613
  const isShortText = !streaming && content.length > 0 && !isMultiLine;
1480
1614
  const headingText = streaming && !content ? expanded ? "Reasoning" : "Show Reasoning" : reasoningTimeText ?? (expanded ? "Hide Reasoning" : "Show Reasoning");
1481
- return /* @__PURE__ */ jsx42(
1615
+ return /* @__PURE__ */ jsx44(
1482
1616
  ReasoningCard2,
1483
1617
  {
1484
1618
  content,
@@ -1514,7 +1648,7 @@ function useNestedApprovalBridge() {
1514
1648
 
1515
1649
  // src/containers/SandboxToolCallContainer.tsx
1516
1650
  import { useMemo as useMemo3, useState as useState5 } from "react";
1517
- import { jsx as jsx43 } from "react/jsx-runtime";
1651
+ import { jsx as jsx45 } from "react/jsx-runtime";
1518
1652
  function SandboxToolCallContainer(props) {
1519
1653
  const SandboxToolCallCard2 = useSlot("SandboxToolCallCard");
1520
1654
  const [viewMode, setViewMode] = useState5("terminal");
@@ -1528,7 +1662,7 @@ function SandboxToolCallContainer(props) {
1528
1662
  props.resultText,
1529
1663
  viewMode
1530
1664
  ]);
1531
- return /* @__PURE__ */ jsx43(
1665
+ return /* @__PURE__ */ jsx45(
1532
1666
  SandboxToolCallCard2,
1533
1667
  {
1534
1668
  ...props,
@@ -1541,7 +1675,7 @@ function SandboxToolCallContainer(props) {
1541
1675
 
1542
1676
  // src/containers/ToolApprovalContainer.tsx
1543
1677
  import { useCallback as useCallback5, useMemo as useMemo4, useState as useState6 } from "react";
1544
- import { jsx as jsx44 } from "react/jsx-runtime";
1678
+ import { jsx as jsx46 } from "react/jsx-runtime";
1545
1679
  function ToolApprovalContainer({
1546
1680
  toolName = "",
1547
1681
  options,
@@ -1590,7 +1724,7 @@ function ToolApprovalContainer({
1590
1724
  onDenyOptionChange(null);
1591
1725
  }
1592
1726
  }, [denialReason, onDenyOptionChange, onSelectOption, selectedDenyOptionId]);
1593
- return /* @__PURE__ */ jsx44(
1727
+ return /* @__PURE__ */ jsx46(
1594
1728
  ToolApprovalBar2,
1595
1729
  {
1596
1730
  toolName,
@@ -1609,7 +1743,7 @@ function ToolApprovalContainer({
1609
1743
 
1610
1744
  // src/containers/ToolCallContentBlockContainer.tsx
1611
1745
  import { useCallback as useCallback6, useEffect as useEffect2, useRef as useRef2, useState as useState7 } from "react";
1612
- import { jsx as jsx45 } from "react/jsx-runtime";
1746
+ import { jsx as jsx47 } from "react/jsx-runtime";
1613
1747
  function ToolCallContentBlockContainer(props) {
1614
1748
  const ToolCallContentBlock2 = useSlot("ToolCallContentBlock");
1615
1749
  const [fullscreen, setFullscreen] = useState7(false);
@@ -1633,7 +1767,7 @@ function ToolCallContentBlockContainer(props) {
1633
1767
  },
1634
1768
  []
1635
1769
  );
1636
- return /* @__PURE__ */ jsx45(
1770
+ return /* @__PURE__ */ jsx47(
1637
1771
  ToolCallContentBlock2,
1638
1772
  {
1639
1773
  ...props,
@@ -1646,12 +1780,12 @@ function ToolCallContentBlockContainer(props) {
1646
1780
  }
1647
1781
 
1648
1782
  // src/containers/ToolCallContainer.tsx
1649
- import { jsx as jsx46 } from "react/jsx-runtime";
1783
+ import { jsx as jsx48 } from "react/jsx-runtime";
1650
1784
  var SUB_AGENT_TOOL_NAME = "create_sub_agent";
1651
1785
  var ASK_USER_TOOL_NAME = "ask_user_question";
1652
1786
  function NestedSubAgentAssistantMessage() {
1653
1787
  const AssistantMessageBubble2 = useSlot("AssistantMessageBubble");
1654
- return /* @__PURE__ */ jsx46("div", { className: "mb-3 min-w-0", children: /* @__PURE__ */ jsx46(MessagePrimitive.Root, { "data-role": "assistant", children: /* @__PURE__ */ jsx46(AssistantMessageBubble2, { children: /* @__PURE__ */ jsx46(
1788
+ return /* @__PURE__ */ jsx48("div", { className: "mb-3 min-w-0", children: /* @__PURE__ */ jsx48(MessagePrimitive.Root, { "data-role": "assistant", children: /* @__PURE__ */ jsx48(AssistantMessageBubble2, { children: /* @__PURE__ */ jsx48(
1655
1789
  MessagePrimitive.Parts,
1656
1790
  {
1657
1791
  components: {
@@ -1831,7 +1965,7 @@ function ToolApprovalSlot({ part }) {
1831
1965
  if (optionId === "__deny") return respond({ approved: false, reason });
1832
1966
  return respond({ optionId, reason });
1833
1967
  };
1834
- return /* @__PURE__ */ jsx46(
1968
+ return /* @__PURE__ */ jsx48(
1835
1969
  ToolApprovalContainer,
1836
1970
  {
1837
1971
  toolName: part.toolName,
@@ -1849,7 +1983,7 @@ var ToolCallContainer = (part) => {
1849
1983
  const isRequiresAction = part.status?.type === "requires-action";
1850
1984
  const isSubAgent = part.toolName === SUB_AGENT_TOOL_NAME;
1851
1985
  const isSandbox = SANDBOX_TOOL_NAMES.has(part.toolName);
1852
- const [expanded, setExpanded] = useState8(isRequiresAction || isSubAgent);
1986
+ const [expanded, setExpanded] = useState8(isRequiresAction);
1853
1987
  const [prevRequiresAction, setPrevRequiresAction] = useState8(isRequiresAction);
1854
1988
  if (isRequiresAction !== prevRequiresAction) {
1855
1989
  setPrevRequiresAction(isRequiresAction);
@@ -1868,7 +2002,7 @@ var ToolCallContainer = (part) => {
1868
2002
  }
1869
2003
  const { question, options = [] } = parseAskUserQuestionArgs(part.argsText);
1870
2004
  const isCustom = options.length > 0 && !options.includes(answer);
1871
- return /* @__PURE__ */ jsx46(
2005
+ return /* @__PURE__ */ jsx48(
1872
2006
  AskUserPrompt2,
1873
2007
  {
1874
2008
  questions: [],
@@ -1900,13 +2034,13 @@ var ToolCallContainer = (part) => {
1900
2034
  if (approved === void 0) return;
1901
2035
  respondToNestedApproval({ approvalId: part.approval.id, approved });
1902
2036
  };
1903
- return /* @__PURE__ */ jsx46(
2037
+ return /* @__PURE__ */ jsx48(
1904
2038
  "div",
1905
2039
  {
1906
2040
  "data-slot": "tool-call-card",
1907
2041
  "data-variant": "sub-agent",
1908
- className: "w-full py-2",
1909
- children: /* @__PURE__ */ jsx46(
2042
+ className: "w-full",
2043
+ children: /* @__PURE__ */ jsx48(
1910
2044
  SubAgentCard2,
1911
2045
  {
1912
2046
  status,
@@ -1916,7 +2050,7 @@ var ToolCallContainer = (part) => {
1916
2050
  agentName,
1917
2051
  instruction,
1918
2052
  stepCount,
1919
- children: /* @__PURE__ */ jsx46(NestedApprovalBridgeContext.Provider, { value: bridge, children: /* @__PURE__ */ jsx46(
2053
+ children: /* @__PURE__ */ jsx48(NestedApprovalBridgeContext.Provider, { value: bridge, children: /* @__PURE__ */ jsx48(
1920
2054
  MessagePartPrimitive.Messages,
1921
2055
  {
1922
2056
  components: {
@@ -1934,7 +2068,7 @@ var ToolCallContainer = (part) => {
1934
2068
  if (isSandbox) {
1935
2069
  const { command, intent, argsJson } = parseSandboxArgs(part.argsText);
1936
2070
  const { exitCode, resultText, resultJson } = parseSandboxResult(resultString);
1937
- return /* @__PURE__ */ jsx46(
2071
+ return /* @__PURE__ */ jsx48(
1938
2072
  SandboxToolCallContainer,
1939
2073
  {
1940
2074
  name: part.toolName,
@@ -1957,7 +2091,7 @@ var ToolCallContainer = (part) => {
1957
2091
  const argsDisplay2 = getJsonDisplayValue(part.argsText);
1958
2092
  const resultDisplay2 = getToolResultContent(part.result);
1959
2093
  if (part.toolName === "list_tools" && mcpServer) {
1960
- return /* @__PURE__ */ jsx46(
2094
+ return /* @__PURE__ */ jsx48(
1961
2095
  ToolCallCard2,
1962
2096
  {
1963
2097
  toolName: `Listing tools \xB7 ${mcpServer}`,
@@ -1968,7 +2102,7 @@ var ToolCallContainer = (part) => {
1968
2102
  awaitingText: durationText ?? "Awaiting Response\u2026",
1969
2103
  showResponseLine: status !== "running" && !!resultDisplay2.data,
1970
2104
  mcpServerName: mcpServer,
1971
- requestSlot: argsDisplay2.value ? /* @__PURE__ */ jsx46(
2105
+ requestSlot: argsDisplay2.value ? /* @__PURE__ */ jsx48(
1972
2106
  ToolCallContentBlockContainer,
1973
2107
  {
1974
2108
  title: "Request",
@@ -1976,7 +2110,7 @@ var ToolCallContainer = (part) => {
1976
2110
  isJson: argsDisplay2.isJson,
1977
2111
  maxHeight: "10.5rem"
1978
2112
  }
1979
- ) : resultDisplay2.data ? /* @__PURE__ */ jsx46(
2113
+ ) : resultDisplay2.data ? /* @__PURE__ */ jsx48(
1980
2114
  ToolCallContentBlockContainer,
1981
2115
  {
1982
2116
  title: "Request",
@@ -1985,7 +2119,7 @@ var ToolCallContainer = (part) => {
1985
2119
  maxHeight: "10.5rem"
1986
2120
  }
1987
2121
  ) : void 0,
1988
- responseSlot: resultDisplay2.data ? /* @__PURE__ */ jsx46(
2122
+ responseSlot: resultDisplay2.data ? /* @__PURE__ */ jsx48(
1989
2123
  ToolCallContentBlockContainer,
1990
2124
  {
1991
2125
  title: "Response",
@@ -2004,7 +2138,7 @@ var ToolCallContainer = (part) => {
2004
2138
  displayName = `get_tool_info: ${innerToolName} (${mcpServer})`;
2005
2139
  }
2006
2140
  const inputDisplay = input !== void 0 ? getJsonDisplayValue(JSON.stringify(input, null, 2)) : argsDisplay2;
2007
- return /* @__PURE__ */ jsx46(
2141
+ return /* @__PURE__ */ jsx48(
2008
2142
  ToolCallCard2,
2009
2143
  {
2010
2144
  toolName: displayName,
@@ -2015,7 +2149,7 @@ var ToolCallContainer = (part) => {
2015
2149
  awaitingText: durationText ?? "Awaiting Response\u2026",
2016
2150
  showResponseLine: status !== "running" && resultDisplay2.data !== void 0,
2017
2151
  mcpServerName: mcpServer,
2018
- requestSlot: inputDisplay.value ? /* @__PURE__ */ jsx46(
2152
+ requestSlot: inputDisplay.value ? /* @__PURE__ */ jsx48(
2019
2153
  ToolCallContentBlockContainer,
2020
2154
  {
2021
2155
  title: "Request",
@@ -2023,7 +2157,7 @@ var ToolCallContainer = (part) => {
2023
2157
  isJson: inputDisplay.isJson,
2024
2158
  maxHeight: "10.5rem"
2025
2159
  }
2026
- ) : resultDisplay2.data !== void 0 ? /* @__PURE__ */ jsx46(
2160
+ ) : resultDisplay2.data !== void 0 ? /* @__PURE__ */ jsx48(
2027
2161
  ToolCallContentBlockContainer,
2028
2162
  {
2029
2163
  title: "Request",
@@ -2032,7 +2166,7 @@ var ToolCallContainer = (part) => {
2032
2166
  maxHeight: "10.5rem"
2033
2167
  }
2034
2168
  ) : void 0,
2035
- responseSlot: resultDisplay2.data !== void 0 ? /* @__PURE__ */ jsx46(
2169
+ responseSlot: resultDisplay2.data !== void 0 ? /* @__PURE__ */ jsx48(
2036
2170
  ToolCallContentBlockContainer,
2037
2171
  {
2038
2172
  title: "Response",
@@ -2041,13 +2175,13 @@ var ToolCallContainer = (part) => {
2041
2175
  resizable: true
2042
2176
  }
2043
2177
  ) : void 0,
2044
- approvalSlot: showApproval ? /* @__PURE__ */ jsx46(ToolApprovalSlot, { part }) : void 0
2178
+ approvalSlot: showApproval ? /* @__PURE__ */ jsx48(ToolApprovalSlot, { part }) : void 0
2045
2179
  }
2046
2180
  );
2047
2181
  }
2048
2182
  const argsDisplay = getJsonDisplayValue(part.argsText);
2049
2183
  const resultDisplay = getToolResultContent(part.result);
2050
- return /* @__PURE__ */ jsx46(
2184
+ return /* @__PURE__ */ jsx48(
2051
2185
  ToolCallCard2,
2052
2186
  {
2053
2187
  toolName: part.toolName,
@@ -2056,7 +2190,7 @@ var ToolCallContainer = (part) => {
2056
2190
  awaiting: status === "running",
2057
2191
  awaitingText: durationText ?? "Awaiting Response\u2026",
2058
2192
  showResponseLine: status !== "running" && resultDisplay.data !== void 0,
2059
- requestSlot: argsDisplay.value ? /* @__PURE__ */ jsx46(
2193
+ requestSlot: argsDisplay.value ? /* @__PURE__ */ jsx48(
2060
2194
  ToolCallContentBlockContainer,
2061
2195
  {
2062
2196
  title: "Request",
@@ -2064,7 +2198,7 @@ var ToolCallContainer = (part) => {
2064
2198
  isJson: argsDisplay.isJson,
2065
2199
  maxHeight: "10.5rem"
2066
2200
  }
2067
- ) : resultDisplay.data !== void 0 ? /* @__PURE__ */ jsx46(
2201
+ ) : resultDisplay.data !== void 0 ? /* @__PURE__ */ jsx48(
2068
2202
  ToolCallContentBlockContainer,
2069
2203
  {
2070
2204
  title: "Request",
@@ -2073,7 +2207,7 @@ var ToolCallContainer = (part) => {
2073
2207
  maxHeight: "10.5rem"
2074
2208
  }
2075
2209
  ) : void 0,
2076
- responseSlot: resultDisplay.data !== void 0 ? /* @__PURE__ */ jsx46(
2210
+ responseSlot: resultDisplay.data !== void 0 ? /* @__PURE__ */ jsx48(
2077
2211
  ToolCallContentBlockContainer,
2078
2212
  {
2079
2213
  title: "Response",
@@ -2082,39 +2216,35 @@ var ToolCallContainer = (part) => {
2082
2216
  resizable: true
2083
2217
  }
2084
2218
  ) : void 0,
2085
- approvalSlot: showApproval ? /* @__PURE__ */ jsx46(ToolApprovalSlot, { part }) : void 0
2219
+ approvalSlot: showApproval ? /* @__PURE__ */ jsx48(ToolApprovalSlot, { part }) : void 0
2086
2220
  }
2087
2221
  );
2088
2222
  };
2089
2223
 
2090
- // src/containers/ToolGroupContainer.tsx
2091
- import { useState as useState9 } from "react";
2092
- import { useAuiState as useAuiState6 } from "@assistant-ui/react";
2093
- import { jsx as jsx47 } from "react/jsx-runtime";
2094
- function ToolGroupContainer({
2224
+ // src/containers/AgentStepsContainer.tsx
2225
+ import { useState as useState9, useEffect as useEffect3, useRef as useRef3 } from "react";
2226
+ import { jsx as jsx49 } from "react/jsx-runtime";
2227
+ function AgentStepsContainer({
2095
2228
  children,
2096
- group
2229
+ toolCount,
2230
+ thinkingCount,
2231
+ hasFinal,
2232
+ active
2097
2233
  }) {
2098
- const ToolGroupCard2 = useSlot("ToolGroupCard");
2099
- const toolCallCount = group.indices.length;
2100
- const active = useAuiState6((s) => {
2101
- if (s.message.status?.type !== "running") return false;
2102
- const lastIndex = s.message.parts.length - 1;
2103
- if (lastIndex < 0) return false;
2104
- if (s.message.parts[lastIndex]?.type !== "tool-call") return false;
2105
- const lastGroupIndex = group.indices[group.indices.length - 1];
2106
- return lastGroupIndex !== void 0 && lastIndex >= group.indices[0] && lastIndex <= lastGroupIndex;
2107
- });
2234
+ const AgentStepsCard2 = useSlot("AgentStepsCard");
2108
2235
  const [expanded, setExpanded] = useState9(true);
2109
- const [prevActive, setPrevActive] = useState9(active);
2110
- if (active !== prevActive) {
2111
- setPrevActive(active);
2112
- if (active) setExpanded(true);
2113
- }
2114
- return /* @__PURE__ */ jsx47(
2115
- ToolGroupCard2,
2236
+ const collapsedByFinal = useRef3(false);
2237
+ useEffect3(() => {
2238
+ if (hasFinal && !collapsedByFinal.current) {
2239
+ collapsedByFinal.current = true;
2240
+ setExpanded(false);
2241
+ }
2242
+ }, [hasFinal]);
2243
+ return /* @__PURE__ */ jsx49(
2244
+ AgentStepsCard2,
2116
2245
  {
2117
- toolCallCount,
2246
+ toolCount,
2247
+ thinkingCount,
2118
2248
  expanded,
2119
2249
  active,
2120
2250
  onToggle: () => setExpanded((prev) => !prev),
@@ -2124,16 +2254,16 @@ function ToolGroupContainer({
2124
2254
  }
2125
2255
 
2126
2256
  // src/containers/AssistantMessageContainer.tsx
2127
- import { jsx as jsx48 } from "react/jsx-runtime";
2257
+ import { jsx as jsx50 } from "react/jsx-runtime";
2128
2258
  function AssistantLeafPartContainer({ part }) {
2129
2259
  switch (part.type) {
2130
2260
  case "text":
2131
2261
  case "reasoning":
2132
- return /* @__PURE__ */ jsx48(AssistantTextContainer, {});
2262
+ return /* @__PURE__ */ jsx50(AssistantTextContainer, {});
2133
2263
  case "image":
2134
- return /* @__PURE__ */ jsx48(MessageImageContainer, {});
2264
+ return /* @__PURE__ */ jsx50(MessageImageContainer, {});
2135
2265
  case "tool-call":
2136
- return /* @__PURE__ */ jsx48(ToolCallContainer, { ...part });
2266
+ return /* @__PURE__ */ jsx50(ToolCallContainer, { ...part });
2137
2267
  default:
2138
2268
  return null;
2139
2269
  }
@@ -2148,45 +2278,108 @@ function AssistantMessageContainer() {
2148
2278
  const { copy, isCopied } = useActionBarCopy2({
2149
2279
  copyToClipboard: (text) => navigator.clipboard.writeText(text)
2150
2280
  });
2151
- return /* @__PURE__ */ jsx48(MessagePrimitive2.Root, { "data-role": "assistant", children: /* @__PURE__ */ jsx48(
2281
+ const parts = useAuiState6((s) => s.message.parts);
2282
+ const { cutIndex, hasFinal, toolCount, thinkingCount } = computeAgentStepsSplit(parts, isRunning);
2283
+ const groupBy = (part, _context) => {
2284
+ const index = parts.findIndex((p) => p === part);
2285
+ if (index === -1) return null;
2286
+ if (part.type === "text" && index >= cutIndex) {
2287
+ return null;
2288
+ }
2289
+ if (index < cutIndex) {
2290
+ if (part.type === "reasoning") {
2291
+ return ["group-agentSteps", "group-reasoning"];
2292
+ }
2293
+ return ["group-agentSteps"];
2294
+ }
2295
+ return null;
2296
+ };
2297
+ const agentStepsActive = isRunning && !hasFinal;
2298
+ return /* @__PURE__ */ jsx50(MessagePrimitive2.Root, { "data-role": "assistant", children: /* @__PURE__ */ jsx50(
2152
2299
  AssistantMessageBubble2,
2153
2300
  {
2154
- error: error !== void 0 ? /* @__PURE__ */ jsx48(MessageErrorBanner2, { message: String(error) }) : void 0,
2155
- actionBar: !isRunning ? /* @__PURE__ */ jsx48(MessageActionBar2, { isCopied, onCopy: copy }) : void 0,
2156
- children: /* @__PURE__ */ jsx48(
2157
- MessagePrimitive2.GroupedParts,
2158
- {
2159
- groupBy: groupPartByType({
2160
- reasoning: ["group-chainOfThought", "group-reasoning"],
2161
- "tool-call": ["group-chainOfThought", "group-tool"],
2162
- "standalone-tool-call": []
2163
- }),
2164
- children: ({ part, children }) => {
2165
- switch (part.type) {
2166
- case "group-chainOfThought":
2167
- return /* @__PURE__ */ jsx48("div", { "data-slot": "aui_chain-of-thought", className: "flex flex-col gap-3", children });
2168
- case "group-tool":
2169
- return /* @__PURE__ */ jsx48(ToolGroupContainer, { group: part, children });
2170
- case "group-reasoning":
2171
- return /* @__PURE__ */ jsx48(ReasoningContainer, { group: part });
2172
- case "text":
2173
- case "reasoning":
2174
- case "tool-call":
2175
- case "image":
2176
- case "data":
2177
- return /* @__PURE__ */ jsx48(AssistantLeafPartContainer, { part });
2178
- case "indicator":
2179
- return /* @__PURE__ */ jsx48(MessageIndicator2, {});
2180
- default:
2181
- return null;
2182
- }
2183
- }
2301
+ error: error !== void 0 ? /* @__PURE__ */ jsx50(MessageErrorBanner2, { message: String(error) }) : void 0,
2302
+ actionBar: !isRunning ? /* @__PURE__ */ jsx50(MessageActionBar2, { isCopied, onCopy: copy }) : void 0,
2303
+ children: /* @__PURE__ */ jsx50(MessagePrimitive2.GroupedParts, { groupBy, children: ({ part, children }) => {
2304
+ switch (part.type) {
2305
+ case "group-agentSteps":
2306
+ return /* @__PURE__ */ jsx50(
2307
+ AgentStepsContainer,
2308
+ {
2309
+ toolCount,
2310
+ thinkingCount,
2311
+ hasFinal,
2312
+ active: agentStepsActive,
2313
+ children
2314
+ }
2315
+ );
2316
+ case "group-reasoning":
2317
+ return /* @__PURE__ */ jsx50(ReasoningContainer, { group: part });
2318
+ case "text":
2319
+ case "reasoning":
2320
+ case "tool-call":
2321
+ case "image":
2322
+ case "data":
2323
+ return /* @__PURE__ */ jsx50(AssistantLeafPartContainer, { part });
2324
+ case "indicator":
2325
+ return /* @__PURE__ */ jsx50(MessageIndicator2, {});
2326
+ default:
2327
+ return null;
2184
2328
  }
2185
- )
2329
+ } })
2186
2330
  }
2187
2331
  ) });
2188
2332
  }
2189
2333
 
2334
+ // src/containers/HistoryLoaderContainer.tsx
2335
+ import { useCallback as useCallback7, useEffect as useEffect4, useRef as useRef4, useState as useState10 } from "react";
2336
+ import { useTrueFoundryHistoryPagination } from "@truefoundry/assistant-ui-runtime";
2337
+ import { jsx as jsx51 } from "react/jsx-runtime";
2338
+ var TOP_THRESHOLD_PX = 200;
2339
+ var VIEWPORT_SELECTOR = '[data-slot="aui_thread-viewport"]';
2340
+ function HistoryLoaderContainer() {
2341
+ const HistoryLoader2 = useSlot("HistoryLoader");
2342
+ const { hasOlderHistory, isLoadingOlderHistory, loadOlderHistory } = useTrueFoundryHistoryPagination();
2343
+ const [sentinel, setSentinel] = useState10(null);
2344
+ const inflightRef = useRef4(false);
2345
+ const maybeLoadOlder = useCallback7(async () => {
2346
+ if (inflightRef.current) return;
2347
+ inflightRef.current = true;
2348
+ const viewport = sentinel?.closest(VIEWPORT_SELECTOR) ?? null;
2349
+ const prevScrollHeight = viewport?.scrollHeight ?? 0;
2350
+ const prevScrollTop = viewport?.scrollTop ?? 0;
2351
+ try {
2352
+ await loadOlderHistory();
2353
+ requestAnimationFrame(() => {
2354
+ if (viewport == null) return;
2355
+ const delta = viewport.scrollHeight - prevScrollHeight;
2356
+ if (delta > 0) {
2357
+ viewport.scrollTo({ top: prevScrollTop + delta, behavior: "instant" });
2358
+ }
2359
+ });
2360
+ } catch {
2361
+ } finally {
2362
+ inflightRef.current = false;
2363
+ }
2364
+ }, [sentinel, loadOlderHistory]);
2365
+ useEffect4(() => {
2366
+ if (sentinel == null || !hasOlderHistory) return;
2367
+ const viewport = sentinel.closest(VIEWPORT_SELECTOR);
2368
+ const observer = new IntersectionObserver(
2369
+ (entries) => {
2370
+ if (entries.some((entry) => entry.isIntersecting)) {
2371
+ void maybeLoadOlder();
2372
+ }
2373
+ },
2374
+ { root: viewport, rootMargin: `${TOP_THRESHOLD_PX}px 0px 0px 0px` }
2375
+ );
2376
+ observer.observe(sentinel);
2377
+ return () => observer.disconnect();
2378
+ }, [sentinel, hasOlderHistory, maybeLoadOlder]);
2379
+ if (!hasOlderHistory) return null;
2380
+ return /* @__PURE__ */ jsx51(HistoryLoader2, { ref: setSentinel, isLoading: isLoadingOlderHistory });
2381
+ }
2382
+
2190
2383
  // src/containers/UserEditComposerContainer.tsx
2191
2384
  import {
2192
2385
  ComposerPrimitive as ComposerPrimitive2,
@@ -2199,14 +2392,14 @@ import { useComposerCancel, useComposerSend, useThreadIsRunning as useThreadIsRu
2199
2392
  import { ComposerPrimitive, MessagePrimitive as MessagePrimitive3, useAui, useAuiState as useAuiState8 } from "@assistant-ui/react";
2200
2393
 
2201
2394
  // src/containers/useAttachmentPreviewSrc.ts
2202
- import { useEffect as useEffect3, useState as useState10 } from "react";
2395
+ import { useEffect as useEffect5, useState as useState11 } from "react";
2203
2396
  import { useAuiState as useAuiState7 } from "@assistant-ui/react";
2204
2397
  function isImageAttachment(type, contentType) {
2205
2398
  return type === "image" || (contentType?.startsWith("image/") ?? false);
2206
2399
  }
2207
2400
  function useFileObjectUrl(file) {
2208
- const [src, setSrc] = useState10(void 0);
2209
- useEffect3(() => {
2401
+ const [src, setSrc] = useState11(void 0);
2402
+ useEffect5(() => {
2210
2403
  if (!file) {
2211
2404
  setSrc(void 0);
2212
2405
  return;
@@ -2234,7 +2427,7 @@ function useAttachmentPreviewSrc() {
2234
2427
  }
2235
2428
 
2236
2429
  // src/containers/AttachmentsContainer.tsx
2237
- import { jsx as jsx49 } from "react/jsx-runtime";
2430
+ import { jsx as jsx52 } from "react/jsx-runtime";
2238
2431
  function ComposerAttachmentItem() {
2239
2432
  const AttachmentCard2 = useSlot("AttachmentCard");
2240
2433
  const AttachmentPreviewDialog2 = useSlot("AttachmentPreviewDialog");
@@ -2244,7 +2437,7 @@ function ComposerAttachmentItem() {
2244
2437
  const type = useAuiState8((s) => s.attachment.type);
2245
2438
  const isImage = isImageAttachment(type, contentType);
2246
2439
  const previewSrc = useAttachmentPreviewSrc();
2247
- return /* @__PURE__ */ jsx49(AttachmentPreviewDialog2, { previewSrc, children: /* @__PURE__ */ jsx49(
2440
+ return /* @__PURE__ */ jsx52(AttachmentPreviewDialog2, { previewSrc, children: /* @__PURE__ */ jsx52(
2248
2441
  AttachmentCard2,
2249
2442
  {
2250
2443
  name,
@@ -2264,7 +2457,7 @@ function MessageAttachmentItem() {
2264
2457
  const type = useAuiState8((s) => s.attachment.type);
2265
2458
  const isImage = isImageAttachment(type, contentType);
2266
2459
  const previewSrc = useAttachmentPreviewSrc();
2267
- const card = /* @__PURE__ */ jsx49(
2460
+ const card = /* @__PURE__ */ jsx52(
2268
2461
  AttachmentCard2,
2269
2462
  {
2270
2463
  name,
@@ -2276,23 +2469,23 @@ function MessageAttachmentItem() {
2276
2469
  }
2277
2470
  );
2278
2471
  if (isImage && previewSrc) {
2279
- return /* @__PURE__ */ jsx49(AttachmentPreviewDialog2, { previewSrc, children: card });
2472
+ return /* @__PURE__ */ jsx52(AttachmentPreviewDialog2, { previewSrc, children: card });
2280
2473
  }
2281
2474
  return card;
2282
2475
  }
2283
2476
  function ComposerAttachmentsContainer() {
2284
- return /* @__PURE__ */ jsx49("div", { className: "aui-composer-attachments flex w-full flex-row flex-wrap items-center gap-2 empty:hidden", children: /* @__PURE__ */ jsx49(ComposerPrimitive.Attachments, { children: () => /* @__PURE__ */ jsx49(ComposerAttachmentItem, {}) }) });
2477
+ return /* @__PURE__ */ jsx52("div", { className: "aui-composer-attachments flex w-full flex-row flex-wrap items-center gap-2 empty:hidden", children: /* @__PURE__ */ jsx52(ComposerPrimitive.Attachments, { children: () => /* @__PURE__ */ jsx52(ComposerAttachmentItem, {}) }) });
2285
2478
  }
2286
2479
  function MessageAttachmentsContainer() {
2287
- return /* @__PURE__ */ jsx49("div", { className: "aui-user-message-attachments-end col-span-full col-start-1 row-start-1 flex w-full flex-row justify-end gap-2", children: /* @__PURE__ */ jsx49(MessagePrimitive3.Attachments, { children: () => /* @__PURE__ */ jsx49(MessageAttachmentItem, {}) }) });
2480
+ return /* @__PURE__ */ jsx52("div", { className: "aui-user-message-attachments-end col-span-full col-start-1 row-start-1 flex w-full flex-row justify-end gap-2", children: /* @__PURE__ */ jsx52(MessagePrimitive3.Attachments, { children: () => /* @__PURE__ */ jsx52(MessageAttachmentItem, {}) }) });
2288
2481
  }
2289
2482
  function ComposerAttachmentPickerContainer() {
2290
2483
  const AttachmentPickerButton2 = useSlot("AttachmentPickerButton");
2291
- return /* @__PURE__ */ jsx49(ComposerPrimitive.AddAttachment, { asChild: true, children: /* @__PURE__ */ jsx49(AttachmentPickerButton2, {}) });
2484
+ return /* @__PURE__ */ jsx52(ComposerPrimitive.AddAttachment, { asChild: true, children: /* @__PURE__ */ jsx52(AttachmentPickerButton2, {}) });
2292
2485
  }
2293
2486
 
2294
2487
  // src/containers/UserEditComposerContainer.tsx
2295
- import { jsx as jsx50, jsxs as jsxs16 } from "react/jsx-runtime";
2488
+ import { jsx as jsx53, jsxs as jsxs17 } from "react/jsx-runtime";
2296
2489
  function ReadOnlyMessageAttachments() {
2297
2490
  const hasAttachments = useAuiState9(
2298
2491
  (s) => (s.message.attachments?.length ?? 0) > 0
@@ -2300,7 +2493,7 @@ function ReadOnlyMessageAttachments() {
2300
2493
  if (!hasAttachments) {
2301
2494
  return null;
2302
2495
  }
2303
- return /* @__PURE__ */ jsx50("div", { className: "pointer-events-none mb-2 opacity-90", children: /* @__PURE__ */ jsx50(MessageAttachmentsContainer, {}) });
2496
+ return /* @__PURE__ */ jsx53("div", { className: "pointer-events-none mb-2 opacity-90", children: /* @__PURE__ */ jsx53(MessageAttachmentsContainer, {}) });
2304
2497
  }
2305
2498
  function UserEditComposerContainer() {
2306
2499
  const Button4 = useSlot("Button");
@@ -2309,25 +2502,25 @@ function UserEditComposerContainer() {
2309
2502
  const isRunning = useThreadIsRunning3();
2310
2503
  const { cancel, disabled: cancelDisabled } = useComposerCancel();
2311
2504
  const { send, disabled: sendDisabled } = useComposerSend();
2312
- return /* @__PURE__ */ jsx50(MessagePrimitive4.Root, { "data-role": "user", children: /* @__PURE__ */ jsx50(
2505
+ return /* @__PURE__ */ jsx53(MessagePrimitive4.Root, { "data-role": "user", children: /* @__PURE__ */ jsx53(
2313
2506
  "div",
2314
2507
  {
2315
2508
  "data-slot": "aui_user-edit-composer-root",
2316
2509
  className: "fade-in slide-in-from-bottom-1 animate-in flex w-full justify-end px-2 duration-150",
2317
- children: /* @__PURE__ */ jsx50(ComposerPrimitive2.Root, { asChild: true, children: /* @__PURE__ */ jsx50(
2510
+ children: /* @__PURE__ */ jsx53(ComposerPrimitive2.Root, { asChild: true, children: /* @__PURE__ */ jsx53(
2318
2511
  UserMessageEdit3,
2319
2512
  {
2320
- timestamp: /* @__PURE__ */ jsx50(MessageTimestamp2, { className: "text-gray-500" }),
2321
- attachments: /* @__PURE__ */ jsx50(ReadOnlyMessageAttachments, {}),
2322
- input: /* @__PURE__ */ jsx50("div", { className: "mt-1 rounded border border-gray-250 bg-gray-100 p-2 text-gray-750 dark:border-gray-275 dark:bg-gray-275", children: /* @__PURE__ */ jsx50(
2513
+ timestamp: /* @__PURE__ */ jsx53(MessageTimestamp2, { className: "text-gray-500" }),
2514
+ attachments: /* @__PURE__ */ jsx53(ReadOnlyMessageAttachments, {}),
2515
+ input: /* @__PURE__ */ jsx53("div", { className: "mt-1 rounded border border-gray-250 bg-gray-100 p-2 text-gray-750 dark:border-gray-275 dark:bg-gray-275", children: /* @__PURE__ */ jsx53(
2323
2516
  ComposerPrimitive2.Input,
2324
2517
  {
2325
2518
  disabled: isRunning,
2326
2519
  className: "max-h-32 min-h-10 w-full resize-none border-none bg-transparent p-0 text-base leading-[1.34] outline-none focus:shadow-none"
2327
2520
  }
2328
2521
  ) }),
2329
- footer: /* @__PURE__ */ jsxs16("div", { className: "flex items-center justify-end gap-2", children: [
2330
- /* @__PURE__ */ jsx50(
2522
+ footer: /* @__PURE__ */ jsxs17("div", { className: "flex items-center justify-end gap-2", children: [
2523
+ /* @__PURE__ */ jsx53(
2331
2524
  Button4.Secondary,
2332
2525
  {
2333
2526
  type: "button",
@@ -2336,7 +2529,7 @@ function UserEditComposerContainer() {
2336
2529
  text: "Cancel"
2337
2530
  }
2338
2531
  ),
2339
- /* @__PURE__ */ jsx50(
2532
+ /* @__PURE__ */ jsx53(
2340
2533
  Button4.Primary,
2341
2534
  {
2342
2535
  type: "button",
@@ -2355,7 +2548,7 @@ function UserEditComposerContainer() {
2355
2548
  // src/containers/UserMessageContainer.tsx
2356
2549
  import { MessagePrimitive as MessagePrimitive5, useAuiState as useAuiState10 } from "@assistant-ui/react";
2357
2550
  import { useThreadIsRunning as useThreadIsRunning4 } from "@assistant-ui/core/react";
2358
- import { jsx as jsx51 } from "react/jsx-runtime";
2551
+ import { jsx as jsx54 } from "react/jsx-runtime";
2359
2552
  function UserMessageContainer() {
2360
2553
  const UserMessageBubble2 = useSlot("UserMessageBubble");
2361
2554
  const UserMessageActionBar2 = useSlot("UserMessageActionBar");
@@ -2363,31 +2556,31 @@ function UserMessageContainer() {
2363
2556
  const text = useAuiState10(
2364
2557
  (s) => s.message.content.filter((part) => part.type === "text").map((part) => part.text).join("\n")
2365
2558
  );
2366
- return /* @__PURE__ */ jsx51(MessagePrimitive5.Root, { "data-role": "user", children: /* @__PURE__ */ jsx51(
2559
+ return /* @__PURE__ */ jsx54(MessagePrimitive5.Root, { "data-role": "user", children: /* @__PURE__ */ jsx54(
2367
2560
  UserMessageBubble2,
2368
2561
  {
2369
2562
  text,
2370
- attachments: /* @__PURE__ */ jsx51(MessageAttachmentsContainer, {}),
2371
- editAction: !isRunning ? /* @__PURE__ */ jsx51(UserMessageActionBar2, {}) : void 0
2563
+ attachments: /* @__PURE__ */ jsx54(MessageAttachmentsContainer, {}),
2564
+ editAction: !isRunning ? /* @__PURE__ */ jsx54(UserMessageActionBar2, {}) : void 0
2372
2565
  }
2373
2566
  ) });
2374
2567
  }
2375
2568
 
2376
2569
  // src/containers/ThreadContainer.tsx
2377
- import { jsx as jsx52, jsxs as jsxs17 } from "react/jsx-runtime";
2570
+ import { Fragment as Fragment3, jsx as jsx55, jsxs as jsxs18 } from "react/jsx-runtime";
2378
2571
  var isNewChatView = (s) => s.thread.messages.length === 0 && (!s.thread.isLoading || s.threads.isLoading);
2379
2572
  function ThreadMessage({ isEditing }) {
2380
2573
  const role = useAuiState11((s) => s.message.role);
2381
2574
  if (role === "user") {
2382
2575
  if (isEditing) {
2383
- return /* @__PURE__ */ jsx52(UserEditComposerContainer, {});
2576
+ return /* @__PURE__ */ jsx55(UserEditComposerContainer, {});
2384
2577
  }
2385
- return /* @__PURE__ */ jsx52(UserMessageContainer, {});
2578
+ return /* @__PURE__ */ jsx55(UserMessageContainer, {});
2386
2579
  }
2387
- return /* @__PURE__ */ jsx52(AssistantMessageContainer, {});
2580
+ return /* @__PURE__ */ jsx55(AssistantMessageContainer, {});
2388
2581
  }
2389
2582
  function ThreadContainer({ composer }) {
2390
- useEffect4(() => {
2583
+ useEffect6(() => {
2391
2584
  void preloadMarkdownOpenUI();
2392
2585
  }, []);
2393
2586
  const ThreadRootShell2 = useSlot("ThreadRootShell");
@@ -2399,30 +2592,69 @@ function ThreadContainer({ composer }) {
2399
2592
  const ScrollToBottomButton2 = useSlot("ScrollToBottomButton");
2400
2593
  const isEmpty = useAuiState11(isNewChatView);
2401
2594
  const isLoading = useAuiState11((s) => s.thread.isLoading);
2402
- return /* @__PURE__ */ jsx52(ComposerBusyProvider, { children: /* @__PURE__ */ jsx52(ThreadPrimitive.Root, { asChild: true, children: /* @__PURE__ */ jsxs17(ThreadRootShell2, { children: [
2403
- /* @__PURE__ */ jsx52(ThreadPrimitive.Viewport, { asChild: true, turnAnchor: "top", autoScroll: true, children: /* @__PURE__ */ jsxs17(ThreadViewportShell2, { isEmpty, children: [
2404
- isEmpty && /* @__PURE__ */ jsx52(WelcomeScreen2, {}),
2405
- isLoading ? /* @__PURE__ */ jsx52(MessageListSkeleton2, {}) : /* @__PURE__ */ jsx52(MessageGroup2, { children: /* @__PURE__ */ jsx52(ThreadPrimitive.Messages, { children: ({ message }) => /* @__PURE__ */ jsx52(
2406
- ThreadMessage,
2407
- {
2408
- isEditing: message.role === "user" && message.composer.isEditing
2409
- }
2410
- ) }) })
2595
+ return /* @__PURE__ */ jsx55(ComposerBusyProvider, { children: /* @__PURE__ */ jsx55(ThreadPrimitive.Root, { asChild: true, children: /* @__PURE__ */ jsxs18(ThreadRootShell2, { children: [
2596
+ /* @__PURE__ */ jsx55(ThreadPrimitive.Viewport, { asChild: true, turnAnchor: "top", autoScroll: true, children: /* @__PURE__ */ jsxs18(ThreadViewportShell2, { isEmpty, children: [
2597
+ isEmpty && /* @__PURE__ */ jsx55(WelcomeScreen2, {}),
2598
+ isLoading ? /* @__PURE__ */ jsx55(MessageListSkeleton2, {}) : /* @__PURE__ */ jsxs18(Fragment3, { children: [
2599
+ /* @__PURE__ */ jsx55(HistoryLoaderContainer, {}),
2600
+ /* @__PURE__ */ jsx55(MessageGroup2, { children: /* @__PURE__ */ jsx55(ThreadPrimitive.Messages, { children: ({ message }) => /* @__PURE__ */ jsx55(
2601
+ ThreadMessage,
2602
+ {
2603
+ isEditing: message.role === "user" && message.composer.isEditing
2604
+ }
2605
+ ) }) })
2606
+ ] })
2411
2607
  ] }) }),
2412
- !isLoading && /* @__PURE__ */ jsxs17(ThreadComposerAreaShell2, { isEmpty, children: [
2413
- !isEmpty && /* @__PURE__ */ jsx52(ThreadPrimitive.ScrollToBottom, { asChild: true, children: /* @__PURE__ */ jsx52(ScrollToBottomButton2, {}) }),
2608
+ !isLoading && /* @__PURE__ */ jsxs18(ThreadComposerAreaShell2, { isEmpty, children: [
2609
+ !isEmpty && /* @__PURE__ */ jsx55(ThreadPrimitive.ScrollToBottom, { asChild: true, children: /* @__PURE__ */ jsx55(ScrollToBottomButton2, {}) }),
2414
2610
  composer
2415
2611
  ] })
2416
2612
  ] }) }) });
2417
2613
  }
2418
2614
 
2615
+ // src/containers/ToolGroupContainer.tsx
2616
+ import { useState as useState12 } from "react";
2617
+ import { useAuiState as useAuiState12 } from "@assistant-ui/react";
2618
+ import { jsx as jsx56 } from "react/jsx-runtime";
2619
+ function ToolGroupContainer({
2620
+ children,
2621
+ group
2622
+ }) {
2623
+ const ToolGroupCard2 = useSlot("ToolGroupCard");
2624
+ const toolCallCount = group.indices.length;
2625
+ const active = useAuiState12((s) => {
2626
+ if (s.message.status?.type !== "running") return false;
2627
+ const lastIndex = s.message.parts.length - 1;
2628
+ if (lastIndex < 0) return false;
2629
+ if (s.message.parts[lastIndex]?.type !== "tool-call") return false;
2630
+ const lastGroupIndex = group.indices[group.indices.length - 1];
2631
+ return lastGroupIndex !== void 0 && lastIndex >= group.indices[0] && lastIndex <= lastGroupIndex;
2632
+ });
2633
+ const [expanded, setExpanded] = useState12(true);
2634
+ const [prevActive, setPrevActive] = useState12(active);
2635
+ if (active !== prevActive) {
2636
+ setPrevActive(active);
2637
+ if (active) setExpanded(true);
2638
+ }
2639
+ return /* @__PURE__ */ jsx56(
2640
+ ToolGroupCard2,
2641
+ {
2642
+ toolCallCount,
2643
+ expanded,
2644
+ active,
2645
+ onToggle: () => setExpanded((prev) => !prev),
2646
+ children
2647
+ }
2648
+ );
2649
+ }
2650
+
2419
2651
  // src/containers/ComposerContainer.tsx
2420
- import { useRef as useRef3 } from "react";
2421
- import { useAui as useAui2, useAuiState as useAuiState13 } from "@assistant-ui/react";
2652
+ import { useRef as useRef5 } from "react";
2653
+ import { useAui as useAui2, useAuiState as useAuiState14 } from "@assistant-ui/react";
2422
2654
  import { useTrueFoundryCancel } from "@truefoundry/assistant-ui-runtime";
2423
2655
 
2424
2656
  // src/hooks/useComposerPauseView.ts
2425
- import { useAuiState as useAuiState12 } from "@assistant-ui/react";
2657
+ import { useAuiState as useAuiState13 } from "@assistant-ui/react";
2426
2658
  import { useTrueFoundryToolResponses } from "@truefoundry/assistant-ui-runtime";
2427
2659
  function threadHasPendingMcpAuth(s) {
2428
2660
  const messages = s.thread.messages;
@@ -2432,7 +2664,7 @@ function threadHasPendingMcpAuth(s) {
2432
2664
  return last.metadata?.custom?.pendingMcpAuth === true;
2433
2665
  }
2434
2666
  function useComposerPauseView() {
2435
- const mcpPending = useAuiState12(threadHasPendingMcpAuth);
2667
+ const mcpPending = useAuiState13(threadHasPendingMcpAuth);
2436
2668
  const { pending: toolResponsesPending } = useTrueFoundryToolResponses();
2437
2669
  if (mcpPending) {
2438
2670
  return { kind: "mcp" };
@@ -2446,11 +2678,11 @@ function useComposerPauseView() {
2446
2678
  // src/containers/AskUserContainer.tsx
2447
2679
  import { useTrueFoundryToolResponses as useTrueFoundryToolResponses2 } from "@truefoundry/assistant-ui-runtime";
2448
2680
  import { useThreadIsRunning as useThreadIsRunning5 } from "@assistant-ui/core/react";
2449
- import { useCallback as useCallback7, useEffect as useEffect5, useMemo as useMemo5, useState as useState11 } from "react";
2681
+ import { useCallback as useCallback8, useEffect as useEffect7, useMemo as useMemo5, useState as useState13 } from "react";
2450
2682
  import {
2451
2683
  ASK_USER_CUSTOM_OPTION
2452
2684
  } from "tfy-web-components/components/molecules/agent-chat";
2453
- import { jsx as jsx53 } from "react/jsx-runtime";
2685
+ import { jsx as jsx57 } from "react/jsx-runtime";
2454
2686
  var EMPTY_ANSWER = { radioValue: "", custom: "" };
2455
2687
  function AskUserContainer() {
2456
2688
  const AskUserPrompt2 = useSlot("AskUserPrompt");
@@ -2467,11 +2699,11 @@ function AskUserContainer() {
2467
2699
  ],
2468
2700
  [item]
2469
2701
  );
2470
- const [currentQuestionIndex, setCurrentQuestionIndex] = useState11(0);
2471
- const [answers, setAnswers] = useState11(
2702
+ const [currentQuestionIndex, setCurrentQuestionIndex] = useState13(0);
2703
+ const [answers, setAnswers] = useState13(
2472
2704
  {}
2473
2705
  );
2474
- useEffect5(() => {
2706
+ useEffect7(() => {
2475
2707
  setCurrentQuestionIndex(0);
2476
2708
  setAnswers({});
2477
2709
  }, [item?.toolCallId]);
@@ -2481,7 +2713,7 @@ function AskUserContainer() {
2481
2713
  );
2482
2714
  const currentQuestion = questions[safeIndex];
2483
2715
  const currentAnswer = currentQuestion == null ? EMPTY_ANSWER : answers[currentQuestion.id] ?? EMPTY_ANSWER;
2484
- const getResponseForQuestion = useCallback7(
2716
+ const getResponseForQuestion = useCallback8(
2485
2717
  (questionId) => {
2486
2718
  const answer = answers[questionId] ?? EMPTY_ANSWER;
2487
2719
  return answer.radioValue === ASK_USER_CUSTOM_OPTION ? answer.custom.trim() : answer.radioValue.trim();
@@ -2495,7 +2727,7 @@ function AskUserContainer() {
2495
2727
  const selectedResponse = currentAnswer.radioValue === ASK_USER_CUSTOM_OPTION ? currentAnswer.custom.trim() : currentAnswer.radioValue.trim();
2496
2728
  const isSubmitDisabled = isRunning || currentQuestion == null || selectedResponse.length === 0;
2497
2729
  const isSubmitAllDisabled = isSubmitDisabled || !allQuestionsAnswered;
2498
- const onCurrentAnswerChange = useCallback7(
2730
+ const onCurrentAnswerChange = useCallback8(
2499
2731
  (questionId, update) => {
2500
2732
  setAnswers((previous) => ({
2501
2733
  ...previous,
@@ -2507,14 +2739,14 @@ function AskUserContainer() {
2507
2739
  },
2508
2740
  []
2509
2741
  );
2510
- const onSubmit = useCallback7(() => {
2742
+ const onSubmit = useCallback8(() => {
2511
2743
  if (item == null || !allQuestionsAnswered) return;
2512
2744
  const content = getResponseForQuestion(item.toolCallId);
2513
2745
  if (!content) return;
2514
2746
  respond({ toolCallId: item.toolCallId, content });
2515
2747
  }, [allQuestionsAnswered, getResponseForQuestion, item, respond]);
2516
2748
  if (item == null || currentQuestion == null) return null;
2517
- return /* @__PURE__ */ jsx53(
2749
+ return /* @__PURE__ */ jsx57(
2518
2750
  AskUserPrompt2,
2519
2751
  {
2520
2752
  questions,
@@ -2538,7 +2770,7 @@ function AskUserContainer() {
2538
2770
  // src/containers/McpAuthContainer.tsx
2539
2771
  import { useTrueFoundryMcpAuth } from "@truefoundry/assistant-ui-runtime";
2540
2772
  import { useThreadIsRunning as useThreadIsRunning6 } from "@assistant-ui/core/react";
2541
- import { jsx as jsx54 } from "react/jsx-runtime";
2773
+ import { jsx as jsx58 } from "react/jsx-runtime";
2542
2774
  function McpAuthContainer() {
2543
2775
  const McpAuthPrompt2 = useSlot("McpAuthPrompt");
2544
2776
  const { pending, resume } = useTrueFoundryMcpAuth();
@@ -2550,7 +2782,7 @@ function McpAuthContainer() {
2550
2782
  window.open(server.authUrl, "_blank", "noopener,noreferrer");
2551
2783
  }
2552
2784
  };
2553
- return /* @__PURE__ */ jsx54(
2785
+ return /* @__PURE__ */ jsx58(
2554
2786
  McpAuthPrompt2,
2555
2787
  {
2556
2788
  servers: pending.mcpServers,
@@ -2562,25 +2794,25 @@ function McpAuthContainer() {
2562
2794
  }
2563
2795
 
2564
2796
  // src/containers/ComposerContainer.tsx
2565
- import { Fragment as Fragment3, jsx as jsx55, jsxs as jsxs18 } from "react/jsx-runtime";
2797
+ import { Fragment as Fragment4, jsx as jsx59, jsxs as jsxs19 } from "react/jsx-runtime";
2566
2798
  function ComposerContainer({
2567
2799
  placeholder = "Ask anything... (Shift+Enter for new line)"
2568
2800
  }) {
2569
2801
  const ComposerShell2 = useSlot("ComposerShell");
2570
2802
  const aui = useAui2();
2571
- const text = useAuiState13((s) => s.composer.text);
2803
+ const text = useAuiState14((s) => s.composer.text);
2572
2804
  const { isBusy, send, resetBusy } = useComposerBusyState();
2573
2805
  const pauseView = useComposerPauseView();
2574
2806
  const cancel = useTrueFoundryCancel();
2575
- const fileInputRef = useRef3(null);
2807
+ const fileInputRef = useRef5(null);
2576
2808
  if (pauseView.kind === "mcp") {
2577
- return /* @__PURE__ */ jsx55(McpAuthContainer, {});
2809
+ return /* @__PURE__ */ jsx59(McpAuthContainer, {});
2578
2810
  }
2579
2811
  if (pauseView.kind === "ask-user") {
2580
- return /* @__PURE__ */ jsx55(AskUserContainer, {});
2812
+ return /* @__PURE__ */ jsx59(AskUserContainer, {});
2581
2813
  }
2582
- return /* @__PURE__ */ jsxs18(Fragment3, { children: [
2583
- /* @__PURE__ */ jsx55(
2814
+ return /* @__PURE__ */ jsxs19(Fragment4, { children: [
2815
+ /* @__PURE__ */ jsx59(
2584
2816
  "input",
2585
2817
  {
2586
2818
  ref: fileInputRef,
@@ -2598,10 +2830,10 @@ function ComposerContainer({
2598
2830
  }
2599
2831
  }
2600
2832
  ),
2601
- /* @__PURE__ */ jsx55(
2833
+ /* @__PURE__ */ jsx59(
2602
2834
  ComposerShell2,
2603
2835
  {
2604
- attachments: /* @__PURE__ */ jsx55(ComposerAttachmentsContainer, {}),
2836
+ attachments: /* @__PURE__ */ jsx59(ComposerAttachmentsContainer, {}),
2605
2837
  value: text,
2606
2838
  placeholder,
2607
2839
  disabled: isBusy,
@@ -2619,9 +2851,9 @@ function ComposerContainer({
2619
2851
  }
2620
2852
 
2621
2853
  // src/containers/ThreadListContainer.tsx
2622
- import { useAui as useAui3, useAuiState as useAuiState14 } from "@assistant-ui/react";
2623
- import { useEffect as useEffect6, useRef as useRef4 } from "react";
2624
- import { Fragment as Fragment4, jsx as jsx56, jsxs as jsxs19 } from "react/jsx-runtime";
2854
+ import { useAui as useAui3, useAuiState as useAuiState15 } from "@assistant-ui/react";
2855
+ import { useEffect as useEffect8, useRef as useRef6 } from "react";
2856
+ import { Fragment as Fragment5, jsx as jsx60, jsxs as jsxs20 } from "react/jsx-runtime";
2625
2857
  function ThreadListContainer() {
2626
2858
  const ThreadListShell2 = useSlot("ThreadListShell");
2627
2859
  const ThreadListNewButton2 = useSlot("ThreadListNewButton");
@@ -2629,14 +2861,14 @@ function ThreadListContainer() {
2629
2861
  const ThreadListRowSkeleton2 = useSlot("ThreadListRowSkeleton");
2630
2862
  const ThreadListEmptyState2 = useSlot("ThreadListEmptyState");
2631
2863
  const aui = useAui3();
2632
- const isLoading = useAuiState14((s) => s.threads.isLoading);
2633
- const isLoadingMore = useAuiState14((s) => s.threads.isLoadingMore);
2634
- const hasMore = useAuiState14((s) => s.threads.hasMore);
2635
- const threadIds = useAuiState14((s) => s.threads.threadIds);
2636
- const threadItems = useAuiState14((s) => s.threads.threadItems);
2637
- const mainThreadId = useAuiState14((s) => s.threads.mainThreadId);
2638
- const sentinelRef = useRef4(null);
2639
- useEffect6(() => {
2864
+ const isLoading = useAuiState15((s) => s.threads.isLoading);
2865
+ const isLoadingMore = useAuiState15((s) => s.threads.isLoadingMore);
2866
+ const hasMore = useAuiState15((s) => s.threads.hasMore);
2867
+ const threadIds = useAuiState15((s) => s.threads.threadIds);
2868
+ const threadItems = useAuiState15((s) => s.threads.threadItems);
2869
+ const mainThreadId = useAuiState15((s) => s.threads.mainThreadId);
2870
+ const sentinelRef = useRef6(null);
2871
+ useEffect8(() => {
2640
2872
  const node = sentinelRef.current;
2641
2873
  if (!node || !hasMore) return;
2642
2874
  const observer = new IntersectionObserver((entries) => {
@@ -2648,10 +2880,10 @@ function ThreadListContainer() {
2648
2880
  return () => observer.disconnect();
2649
2881
  }, [aui, hasMore, isLoadingMore]);
2650
2882
  const itemsById = new Map(threadItems.map((item) => [item.id, item]));
2651
- return /* @__PURE__ */ jsxs19(ThreadListShell2, { header: /* @__PURE__ */ jsx56(ThreadListNewButton2, { onClick: () => aui.threads().switchToNewThread() }), children: [
2652
- isLoading ? /* @__PURE__ */ jsx56(ThreadListRowSkeleton2, {}) : threadIds.length === 0 ? /* @__PURE__ */ jsx56(ThreadListEmptyState2, {}) : threadIds.map((id) => {
2883
+ return /* @__PURE__ */ jsxs20(ThreadListShell2, { header: /* @__PURE__ */ jsx60(ThreadListNewButton2, { onClick: () => aui.threads().switchToNewThread() }), children: [
2884
+ isLoading ? /* @__PURE__ */ jsx60(ThreadListRowSkeleton2, {}) : threadIds.length === 0 ? /* @__PURE__ */ jsx60(ThreadListEmptyState2, {}) : threadIds.map((id) => {
2653
2885
  const item = itemsById.get(id);
2654
- return /* @__PURE__ */ jsx56(
2886
+ return /* @__PURE__ */ jsx60(
2655
2887
  ThreadListRow2,
2656
2888
  {
2657
2889
  title: item?.title ?? "New Chat",
@@ -2663,22 +2895,24 @@ function ThreadListContainer() {
2663
2895
  id
2664
2896
  );
2665
2897
  }),
2666
- !isLoading && hasMore && /* @__PURE__ */ jsxs19(Fragment4, { children: [
2667
- isLoadingMore && /* @__PURE__ */ jsx56(ThreadListRowSkeleton2, { count: 1 }),
2668
- /* @__PURE__ */ jsx56("div", { ref: sentinelRef, "aria-hidden": true })
2898
+ !isLoading && hasMore && /* @__PURE__ */ jsxs20(Fragment5, { children: [
2899
+ isLoadingMore && /* @__PURE__ */ jsx60(ThreadListRowSkeleton2, { count: 1 }),
2900
+ /* @__PURE__ */ jsx60("div", { ref: sentinelRef, "aria-hidden": true })
2669
2901
  ] })
2670
2902
  ] });
2671
2903
  }
2672
2904
 
2673
2905
  // src/containers/Thread.tsx
2674
- import { jsx as jsx57 } from "react/jsx-runtime";
2906
+ import { jsx as jsx61 } from "react/jsx-runtime";
2675
2907
  function Thread() {
2676
- return /* @__PURE__ */ jsx57(ThreadContainer, { composer: /* @__PURE__ */ jsx57(ComposerContainer, {}) });
2908
+ return /* @__PURE__ */ jsx61(ThreadContainer, { composer: /* @__PURE__ */ jsx61(ComposerContainer, {}) });
2677
2909
  }
2678
2910
  export {
2679
- Accordion3 as Accordion,
2680
- AccordionDetails3 as AccordionDetails,
2681
- AccordionSummary3 as AccordionSummary,
2911
+ Accordion4 as Accordion,
2912
+ AccordionDetails4 as AccordionDetails,
2913
+ AccordionSummary4 as AccordionSummary,
2914
+ AgentStepsCard,
2915
+ AgentStepsContainer,
2682
2916
  AskUserContainer,
2683
2917
  AssistantMessageBubble,
2684
2918
  AssistantMessageContainer,
@@ -2702,6 +2936,8 @@ export {
2702
2936
  default5 as Dialog,
2703
2937
  ErrorToasterProvider,
2704
2938
  GhostButton,
2939
+ HistoryLoader,
2940
+ HistoryLoaderContainer,
2705
2941
  default2 as IconButton,
2706
2942
  default3 as IconProvider,
2707
2943
  LightTooltip2 as LightTooltip,
@@ -2753,6 +2989,7 @@ export {
2753
2989
  UserMessageContainer,
2754
2990
  UserMessageEdit,
2755
2991
  WelcomeScreen,
2992
+ computeAgentStepsSplit,
2756
2993
  defaultSlots,
2757
2994
  defaultTokens,
2758
2995
  registerIcons2 as registerIcons,