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