@adecore/agents-react 0.41.1 → 0.42.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/dist/chat/actions.js +4 -0
  2. package/dist/chat/logic/lightbox.d.ts +31 -0
  3. package/dist/chat/logic/lightbox.js +61 -0
  4. package/dist/chat/logic/timeline.d.ts +1 -0
  5. package/dist/chat/logic/timeline.js +3 -0
  6. package/dist/chat/ui/AnsiOutput.d.ts +3 -2
  7. package/dist/chat/ui/AnsiOutput.js +26 -22
  8. package/dist/chat/ui/ImageView.d.ts +3 -0
  9. package/dist/chat/ui/ImageView.js +761 -437
  10. package/dist/chat/ui/intelligent-ui/renderers/content.js +4 -2
  11. package/dist/chat/ui/rows/MessageRows.js +10 -8
  12. package/dist/chat/ui/rows/Rows.js +42 -39
  13. package/dist/chat/ui/rows/WorkRows.d.ts +4 -2
  14. package/dist/chat/ui/rows/WorkRows.js +580 -211
  15. package/dist/chat/ui/rows/WorkflowRow.js +43 -41
  16. package/dist/host.d.ts +1 -0
  17. package/dist/locales/en/agent-chat.d.ts +9 -0
  18. package/dist/locales/en/agent-chat.js +11 -2
  19. package/dist/locales/nl/agent-chat.d.ts +9 -0
  20. package/dist/locales/nl/agent-chat.js +11 -2
  21. package/package.json +8 -8
  22. package/src/chat/actions.ts +1 -0
  23. package/src/chat/logic/lightbox.ts +88 -0
  24. package/src/chat/logic/timeline.ts +13 -2
  25. package/src/chat/ui/AnsiOutput.tsx +13 -2
  26. package/src/chat/ui/ImageView.tsx +255 -63
  27. package/src/chat/ui/intelligent-ui/renderers/content.tsx +4 -2
  28. package/src/chat/ui/rows/MessageRows.tsx +10 -8
  29. package/src/chat/ui/rows/Rows.tsx +9 -1
  30. package/src/chat/ui/rows/WorkRows.tsx +127 -27
  31. package/src/chat/ui/rows/WorkflowRow.tsx +1 -1
  32. package/src/host.ts +2 -0
  33. package/src/locales/en/agent-chat.ts +11 -2
  34. package/src/locales/nl/agent-chat.ts +11 -2
@@ -11,11 +11,12 @@ import { useChatHost } from '../../../host.js';
11
11
  import { useCommandNames } from '../../../host-hooks.js';
12
12
  import { lazyNamed } from '../../../lazy.js';
13
13
  import { useChatActions } from '../../actions.js';
14
+ import { formatBytes } from '../../attachments.js';
14
15
  import { ChatScopeContext, useChatScope } from '../../../scope.js';
15
16
  import { useAwaitsApproval, useCurrentItem } from '../../../state/chats.js';
16
17
  import { useTimelineFlash } from '../../timeline-flash.js';
17
18
  import { formatClockDuration, formatElapsedShort } from '@adecore/ui/format';
18
- import { Icon, LazyBoundary, MiddleTruncate, Spinner, useTickingText } from '@adecore/ui';
19
+ import { Button, Icon, LazyBoundary, MiddleTruncate, Spinner, useTickingText } from '@adecore/ui';
19
20
  import { ROW_GUTTER, toolIcon } from '../icons.js';
20
21
  import { AnsiOutput } from '../AnsiOutput.js';
21
22
  import { RowTime } from '../RowTime.js';
@@ -561,14 +562,257 @@ function ChangedFileLine(t0) {
561
562
  }
562
563
  return t8;
563
564
  }
565
+ /* The whole of what the thread keeps only the beginning of, loaded once a person asks; a failure can be tried again. */
566
+ function useWhole(fetch) {
567
+ const $ = _c(8);
568
+ let t0;
569
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
570
+ t0 = {
571
+ status: "idle"
572
+ };
573
+ $[0] = t0;
574
+ } else {
575
+ t0 = $[0];
576
+ }
577
+ const [state, setState] = useState(t0);
578
+ if (fetch === null) {
579
+ let t1;
580
+ if ($[1] !== state) {
581
+ t1 = {
582
+ state,
583
+ load: null
584
+ };
585
+ $[1] = state;
586
+ $[2] = t1;
587
+ } else {
588
+ t1 = $[2];
589
+ }
590
+ return t1;
591
+ }
592
+ let t1;
593
+ if ($[3] !== fetch) {
594
+ t1 = () => {
595
+ setState({
596
+ status: "loading"
597
+ });
598
+ fetch().then(value => setState({
599
+ status: "loaded",
600
+ value
601
+ }), () => setState({
602
+ status: "failed"
603
+ }));
604
+ };
605
+ $[3] = fetch;
606
+ $[4] = t1;
607
+ } else {
608
+ t1 = $[4];
609
+ }
610
+ const load = t1;
611
+ let t2;
612
+ if ($[5] !== load || $[6] !== state) {
613
+ t2 = {
614
+ state,
615
+ load
616
+ };
617
+ $[5] = load;
618
+ $[6] = state;
619
+ $[7] = t2;
620
+ } else {
621
+ t2 = $[7];
622
+ }
623
+ return t2;
624
+ }
625
+ /* The line under a beginning that offers the rest: its size when known, and a retry after a failure. */
626
+ function WholeBar(t0) {
627
+ const $ = _c(22);
628
+ const {
629
+ whole,
630
+ label,
631
+ failedLabel,
632
+ bytes
633
+ } = t0;
634
+ const {
635
+ t
636
+ } = useTranslation("agent-chat");
637
+ const {
638
+ state,
639
+ load
640
+ } = whole;
641
+ if (load === null || state.status === "loaded") {
642
+ return null;
643
+ }
644
+ const failed = state.status === "failed";
645
+ const loading = state.status === "loading";
646
+ let t1;
647
+ if ($[0] !== failed || $[1] !== failedLabel) {
648
+ t1 = failed && /*#__PURE__*/_jsx("span", {
649
+ className: "text-status-error",
650
+ children: failedLabel
651
+ });
652
+ $[0] = failed;
653
+ $[1] = failedLabel;
654
+ $[2] = t1;
655
+ } else {
656
+ t1 = $[2];
657
+ }
658
+ let t2;
659
+ if ($[3] !== bytes || $[4] !== failed || $[5] !== t) {
660
+ t2 = !failed && bytes !== undefined && /*#__PURE__*/_jsx("span", {
661
+ children: t("work.wholeSize", {
662
+ size: formatBytes(bytes)
663
+ })
664
+ });
665
+ $[3] = bytes;
666
+ $[4] = failed;
667
+ $[5] = t;
668
+ $[6] = t2;
669
+ } else {
670
+ t2 = $[6];
671
+ }
672
+ let t3;
673
+ if ($[7] !== loading) {
674
+ t3 = loading && /*#__PURE__*/_jsx(Spinner, {
675
+ size: 12
676
+ });
677
+ $[7] = loading;
678
+ $[8] = t3;
679
+ } else {
680
+ t3 = $[8];
681
+ }
682
+ let t4;
683
+ if ($[9] !== failed || $[10] !== label || $[11] !== t) {
684
+ t4 = failed ? t("work.retry") : label;
685
+ $[9] = failed;
686
+ $[10] = label;
687
+ $[11] = t;
688
+ $[12] = t4;
689
+ } else {
690
+ t4 = $[12];
691
+ }
692
+ let t5;
693
+ if ($[13] !== load || $[14] !== loading || $[15] !== t3 || $[16] !== t4) {
694
+ t5 = /*#__PURE__*/_jsxs(Button, {
695
+ size: "xs",
696
+ variant: "secondary",
697
+ disabled: loading,
698
+ onClick: load,
699
+ children: [t3, t4]
700
+ });
701
+ $[13] = load;
702
+ $[14] = loading;
703
+ $[15] = t3;
704
+ $[16] = t4;
705
+ $[17] = t5;
706
+ } else {
707
+ t5 = $[17];
708
+ }
709
+ let t6;
710
+ if ($[18] !== t1 || $[19] !== t2 || $[20] !== t5) {
711
+ t6 = /*#__PURE__*/_jsxs("div", {
712
+ className: "flex items-center gap-2 py-1.5 font-sans text-xs text-text-faint",
713
+ children: [t1, t2, t5]
714
+ });
715
+ $[18] = t1;
716
+ $[19] = t2;
717
+ $[20] = t5;
718
+ $[21] = t6;
719
+ } else {
720
+ t6 = $[21];
721
+ }
722
+ return t6;
723
+ }
724
+ /* What a call answered as far as the thread shows it, and the whole once a person asks: from the host when the item carries only the beginning. */
725
+ function useToolText(tool, chatId) {
726
+ const $ = _c(9);
727
+ const {
728
+ toolOutput
729
+ } = useChatActions();
730
+ const stored = tool.outputRef !== undefined;
731
+ let fetch = null;
732
+ if (stored && chatId !== undefined && toolOutput !== undefined) {
733
+ let t0;
734
+ if ($[0] !== chatId || $[1] !== tool.id || $[2] !== toolOutput) {
735
+ t0 = () => toolOutput(chatId, tool.id);
736
+ $[0] = chatId;
737
+ $[1] = tool.id;
738
+ $[2] = toolOutput;
739
+ $[3] = t0;
740
+ } else {
741
+ t0 = $[3];
742
+ }
743
+ fetch = t0;
744
+ } else {
745
+ if (!stored && (tool.output?.length ?? 0) > OUTPUT_LIMIT) {
746
+ let t0;
747
+ if ($[4] !== tool.output) {
748
+ t0 = () => Promise.resolve(tool.output);
749
+ $[4] = tool.output;
750
+ $[5] = t0;
751
+ } else {
752
+ t0 = $[5];
753
+ }
754
+ fetch = t0;
755
+ }
756
+ }
757
+ const whole = useWhole(fetch);
758
+ const t0 = whole.state.status === "loaded" ? whole.state.value : tool.output;
759
+ let t1;
760
+ if ($[6] !== t0 || $[7] !== whole) {
761
+ t1 = {
762
+ text: t0,
763
+ whole
764
+ };
765
+ $[6] = t0;
766
+ $[7] = whole;
767
+ $[8] = t1;
768
+ } else {
769
+ t1 = $[8];
770
+ }
771
+ return t1;
772
+ }
773
+ /* An output clipped while it is the beginning and whole once loaded. A beginning the host keeps the rest of counts no characters it cannot see. */
774
+ function OutputText(t0) {
775
+ const $ = _c(4);
776
+ const {
777
+ text,
778
+ whole,
779
+ stored
780
+ } = t0;
781
+ const loaded = whole.state.status === "loaded";
782
+ const t1 = loaded ? undefined : OUTPUT_LIMIT;
783
+ const t2 = loaded || !stored;
784
+ let t3;
785
+ if ($[0] !== t1 || $[1] !== t2 || $[2] !== text) {
786
+ t3 = /*#__PURE__*/_jsx(AnsiOutput, {
787
+ text: text,
788
+ limit: t1,
789
+ marksOmitted: t2
790
+ });
791
+ $[0] = t1;
792
+ $[1] = t2;
793
+ $[2] = text;
794
+ $[3] = t3;
795
+ } else {
796
+ t3 = $[3];
797
+ }
798
+ return t3;
799
+ }
564
800
  /* A diff keeps its card, with what the call answered under it. */
565
801
  function DiffBody(t0) {
566
- const $ = _c(9);
802
+ const $ = _c(11);
567
803
  const {
568
804
  tool,
569
805
  entries,
570
- patched
806
+ patched,
807
+ chatId
571
808
  } = t0;
809
+ const {
810
+ t
811
+ } = useTranslation("agent-chat");
812
+ const {
813
+ text,
814
+ whole
815
+ } = useToolText(tool, chatId);
572
816
  let t1;
573
817
  if ($[0] !== entries) {
574
818
  t1 = /*#__PURE__*/_jsx(DiffStack, {
@@ -580,111 +824,165 @@ function DiffBody(t0) {
580
824
  t1 = $[1];
581
825
  }
582
826
  let t2;
583
- if ($[2] !== patched || $[3] !== tool.output || $[4] !== tool.state) {
584
- t2 = hasOutput(tool.output) && !patched && /*#__PURE__*/_jsx("pre", {
585
- "data-find-field": "output",
586
- className: clsx("max-h-64 overflow-auto whitespace-pre-wrap border-t border-border px-3 py-2 font-mono text-code select-text", tool.state === "error" ? "text-chat-removed" : "text-chat-output"),
587
- children: /*#__PURE__*/_jsx(AnsiOutput, {
588
- text: tool.output,
589
- limit: OUTPUT_LIMIT
590
- })
827
+ if ($[2] !== patched || $[3] !== t || $[4] !== text || $[5] !== tool || $[6] !== whole) {
828
+ t2 = hasOutput(text) && !patched && /*#__PURE__*/_jsxs("div", {
829
+ className: "border-t border-border px-3 py-2",
830
+ children: [/*#__PURE__*/_jsx("pre", {
831
+ "data-find-field": "output",
832
+ className: clsx("max-h-64 overflow-auto whitespace-pre-wrap font-mono text-code select-text", tool.state === "error" ? "text-chat-removed" : "text-chat-output"),
833
+ children: /*#__PURE__*/_jsx(OutputText, {
834
+ text: text,
835
+ whole: whole,
836
+ stored: tool.outputRef !== undefined
837
+ })
838
+ }), /*#__PURE__*/_jsx(WholeBar, {
839
+ whole: whole,
840
+ label: t("work.showFullOutput"),
841
+ failedLabel: t("work.fullOutputFailed"),
842
+ bytes: tool.outputRef?.bytes
843
+ })]
591
844
  });
592
845
  $[2] = patched;
593
- $[3] = tool.output;
594
- $[4] = tool.state;
595
- $[5] = t2;
846
+ $[3] = t;
847
+ $[4] = text;
848
+ $[5] = tool;
849
+ $[6] = whole;
850
+ $[7] = t2;
596
851
  } else {
597
- t2 = $[5];
852
+ t2 = $[7];
598
853
  }
599
854
  let t3;
600
- if ($[6] !== t1 || $[7] !== t2) {
855
+ if ($[8] !== t1 || $[9] !== t2) {
601
856
  t3 = /*#__PURE__*/_jsxs("div", {
602
857
  className: "mt-1.5 mb-2 ml-6 overflow-hidden rounded-md border border-border bg-surface-raised",
603
858
  children: [t1, t2]
604
859
  });
605
- $[6] = t1;
606
- $[7] = t2;
607
- $[8] = t3;
860
+ $[8] = t1;
861
+ $[9] = t2;
862
+ $[10] = t3;
608
863
  } else {
609
- t3 = $[8];
864
+ t3 = $[10];
610
865
  }
611
866
  return t3;
612
867
  }
613
868
  /* What a call answered, muted under the call; a failure in the error color, or its exit code when the tool names one. */
614
869
  function ToolOutput(t0) {
615
- const $ = _c(10);
870
+ const $ = _c(22);
616
871
  const {
617
- tool
872
+ tool,
873
+ chatId
618
874
  } = t0;
619
875
  const {
620
876
  t
621
877
  } = useTranslation("agent-chat");
622
- if (!hasOutput(tool.output)) {
878
+ const {
879
+ text,
880
+ whole
881
+ } = useToolText(tool, chatId);
882
+ if (!hasOutput(text)) {
623
883
  return null;
624
884
  }
625
885
  const failed = tool.state === "error";
626
886
  let code;
627
887
  let t1;
628
- if ($[0] !== failed || $[1] !== tool.output) {
888
+ if ($[0] !== failed || $[1] !== text || $[2] !== tool.outputRef || $[3] !== whole) {
629
889
  const {
630
890
  code: t2,
631
891
  rest
632
- } = failed ? exitCodeOf(tool.output) : {
892
+ } = failed ? exitCodeOf(text) : {
633
893
  code: null,
634
- rest: tool.output
894
+ rest: text
635
895
  };
636
896
  code = t2;
637
897
  t1 = hasOutput(rest) && /*#__PURE__*/_jsx("pre", {
638
898
  "data-find-field": "output",
639
899
  className: clsx("max-h-64 overflow-auto whitespace-pre-wrap", failed && code === null ? "text-status-error" : "text-text-muted"),
640
- children: /*#__PURE__*/_jsx(AnsiOutput, {
900
+ children: /*#__PURE__*/_jsx(OutputText, {
641
901
  text: rest,
642
- limit: OUTPUT_LIMIT
902
+ whole: whole,
903
+ stored: tool.outputRef !== undefined
643
904
  })
644
905
  });
645
906
  $[0] = failed;
646
- $[1] = tool.output;
647
- $[2] = code;
648
- $[3] = t1;
907
+ $[1] = text;
908
+ $[2] = tool.outputRef;
909
+ $[3] = whole;
910
+ $[4] = code;
911
+ $[5] = t1;
649
912
  } else {
650
- code = $[2];
651
- t1 = $[3];
913
+ code = $[4];
914
+ t1 = $[5];
652
915
  }
653
916
  let t2;
654
- if ($[4] !== code || $[5] !== t) {
655
- t2 = code !== null && /*#__PURE__*/_jsx("div", {
917
+ if ($[6] !== t) {
918
+ t2 = t("work.showFullOutput");
919
+ $[6] = t;
920
+ $[7] = t2;
921
+ } else {
922
+ t2 = $[7];
923
+ }
924
+ let t3;
925
+ if ($[8] !== t) {
926
+ t3 = t("work.fullOutputFailed");
927
+ $[8] = t;
928
+ $[9] = t3;
929
+ } else {
930
+ t3 = $[9];
931
+ }
932
+ const t4 = tool.outputRef?.bytes;
933
+ let t5;
934
+ if ($[10] !== t2 || $[11] !== t3 || $[12] !== t4 || $[13] !== whole) {
935
+ t5 = /*#__PURE__*/_jsx(WholeBar, {
936
+ whole: whole,
937
+ label: t2,
938
+ failedLabel: t3,
939
+ bytes: t4
940
+ });
941
+ $[10] = t2;
942
+ $[11] = t3;
943
+ $[12] = t4;
944
+ $[13] = whole;
945
+ $[14] = t5;
946
+ } else {
947
+ t5 = $[14];
948
+ }
949
+ let t6;
950
+ if ($[15] !== code || $[16] !== t) {
951
+ t6 = code !== null && /*#__PURE__*/_jsx("div", {
656
952
  className: "text-status-error",
657
953
  children: t("work.exitCode", {
658
954
  code: String(code)
659
955
  })
660
956
  });
661
- $[4] = code;
662
- $[5] = t;
663
- $[6] = t2;
957
+ $[15] = code;
958
+ $[16] = t;
959
+ $[17] = t6;
664
960
  } else {
665
- t2 = $[6];
961
+ t6 = $[17];
666
962
  }
667
- let t3;
668
- if ($[7] !== t1 || $[8] !== t2) {
669
- t3 = /*#__PURE__*/_jsxs(_Fragment, {
670
- children: [t1, t2]
963
+ let t7;
964
+ if ($[18] !== t1 || $[19] !== t5 || $[20] !== t6) {
965
+ t7 = /*#__PURE__*/_jsxs(_Fragment, {
966
+ children: [t1, t5, t6]
671
967
  });
672
- $[7] = t1;
673
- $[8] = t2;
674
- $[9] = t3;
968
+ $[18] = t1;
969
+ $[19] = t5;
970
+ $[20] = t6;
971
+ $[21] = t7;
675
972
  } else {
676
- t3 = $[9];
973
+ t7 = $[21];
677
974
  }
678
- return t3;
975
+ return t7;
679
976
  }
680
- /* An opened call without a card: what it was asked in the foreground, what it answered muted below. */
977
+ /* An opened call without a card: what it was asked in the foreground, what it answered muted below. With `chatId` it can ask for an output the thread keeps only the beginning of. */
681
978
  export function ToolBody(t0) {
682
- const $ = _c(16);
979
+ const $ = _c(18);
683
980
  const {
684
- tool
981
+ tool,
982
+ chatId
685
983
  } = t0;
686
984
  let t1;
687
- if ($[0] !== tool) {
985
+ if ($[0] !== chatId || $[1] !== tool) {
688
986
  t1 = Symbol.for("react.early_return_sentinel");
689
987
  bb0: {
690
988
  const patches = unifiedChanges(tool);
@@ -693,15 +991,17 @@ export function ToolBody(t0) {
693
991
  t1 = /*#__PURE__*/_jsx(DiffBody, {
694
992
  tool: tool,
695
993
  entries: reviewEntries(patches, changes),
696
- patched: patches.length > 0
994
+ patched: patches.length > 0,
995
+ chatId: chatId
697
996
  });
698
997
  break bb0;
699
998
  }
700
999
  }
701
- $[0] = tool;
702
- $[1] = t1;
1000
+ $[0] = chatId;
1001
+ $[1] = tool;
1002
+ $[2] = t1;
703
1003
  } else {
704
- t1 = $[1];
1004
+ t1 = $[2];
705
1005
  }
706
1006
  if (t1 !== Symbol.for("react.early_return_sentinel")) {
707
1007
  return t1;
@@ -710,7 +1010,7 @@ export function ToolBody(t0) {
710
1010
  let t3;
711
1011
  let t4;
712
1012
  let t5;
713
- if ($[2] !== tool.input || $[3] !== tool.name) {
1013
+ if ($[3] !== tool.input || $[4] !== tool.name) {
714
1014
  const lines = toolCallLines(tool.name, tool.input);
715
1015
  t2 = "mt-0.5 mb-2 ml-6 flex flex-col gap-1.5 font-mono text-code select-text";
716
1016
  t3 = lines.command !== null && /*#__PURE__*/_jsxs("pre", {
@@ -727,42 +1027,44 @@ export function ToolBody(t0) {
727
1027
  className: "max-h-64 overflow-auto whitespace-pre-wrap wrap-anywhere text-text",
728
1028
  children: clip(lines.text)
729
1029
  });
730
- $[2] = tool.input;
731
- $[3] = tool.name;
732
- $[4] = t2;
733
- $[5] = t3;
734
- $[6] = t4;
735
- $[7] = t5;
1030
+ $[3] = tool.input;
1031
+ $[4] = tool.name;
1032
+ $[5] = t2;
1033
+ $[6] = t3;
1034
+ $[7] = t4;
1035
+ $[8] = t5;
736
1036
  } else {
737
- t2 = $[4];
738
- t3 = $[5];
739
- t4 = $[6];
740
- t5 = $[7];
1037
+ t2 = $[5];
1038
+ t3 = $[6];
1039
+ t4 = $[7];
1040
+ t5 = $[8];
741
1041
  }
742
1042
  let t6;
743
- if ($[8] !== tool) {
1043
+ if ($[9] !== chatId || $[10] !== tool) {
744
1044
  t6 = /*#__PURE__*/_jsx(ToolOutput, {
745
- tool: tool
1045
+ tool: tool,
1046
+ chatId: chatId
746
1047
  });
747
- $[8] = tool;
748
- $[9] = t6;
1048
+ $[9] = chatId;
1049
+ $[10] = tool;
1050
+ $[11] = t6;
749
1051
  } else {
750
- t6 = $[9];
1052
+ t6 = $[11];
751
1053
  }
752
1054
  let t7;
753
- if ($[10] !== t2 || $[11] !== t3 || $[12] !== t4 || $[13] !== t5 || $[14] !== t6) {
1055
+ if ($[12] !== t2 || $[13] !== t3 || $[14] !== t4 || $[15] !== t5 || $[16] !== t6) {
754
1056
  t7 = /*#__PURE__*/_jsxs("div", {
755
1057
  className: t2,
756
1058
  children: [t3, t4, t5, t6]
757
1059
  });
758
- $[10] = t2;
759
- $[11] = t3;
760
- $[12] = t4;
761
- $[13] = t5;
762
- $[14] = t6;
763
- $[15] = t7;
1060
+ $[12] = t2;
1061
+ $[13] = t3;
1062
+ $[14] = t4;
1063
+ $[15] = t5;
1064
+ $[16] = t6;
1065
+ $[17] = t7;
764
1066
  } else {
765
- t7 = $[15];
1067
+ t7 = $[17];
766
1068
  }
767
1069
  return t7;
768
1070
  }
@@ -783,7 +1085,7 @@ function _temp(t0) {
783
1085
  }, key);
784
1086
  }
785
1087
  export function WorkRow(t0) {
786
- const $ = _c(56);
1088
+ const $ = _c(57);
787
1089
  const {
788
1090
  tool,
789
1091
  chatId,
@@ -938,32 +1240,34 @@ export function WorkRow(t0) {
938
1240
  t16 = $[45];
939
1241
  }
940
1242
  let t17;
941
- if ($[46] !== open || $[47] !== opens || $[48] !== tool) {
1243
+ if ($[46] !== chatId || $[47] !== open || $[48] !== opens || $[49] !== tool) {
942
1244
  t17 = open && opens && /*#__PURE__*/_jsx(ToolBody, {
943
- tool: tool
1245
+ tool: tool,
1246
+ chatId: chatId
944
1247
  });
945
- $[46] = open;
946
- $[47] = opens;
947
- $[48] = tool;
948
- $[49] = t17;
1248
+ $[46] = chatId;
1249
+ $[47] = open;
1250
+ $[48] = opens;
1251
+ $[49] = tool;
1252
+ $[50] = t17;
949
1253
  } else {
950
- t17 = $[49];
1254
+ t17 = $[50];
951
1255
  }
952
1256
  let t18;
953
- if ($[50] !== t15 || $[51] !== t16 || $[52] !== t17 || $[53] !== t5 || $[54] !== tool.id) {
1257
+ if ($[51] !== t15 || $[52] !== t16 || $[53] !== t17 || $[54] !== t5 || $[55] !== tool.id) {
954
1258
  t18 = /*#__PURE__*/_jsxs("div", {
955
1259
  "data-find-item": tool.id,
956
1260
  className: t5,
957
1261
  children: [t15, t16, t17]
958
1262
  });
959
- $[50] = t15;
960
- $[51] = t16;
961
- $[52] = t17;
962
- $[53] = t5;
963
- $[54] = tool.id;
964
- $[55] = t18;
1263
+ $[51] = t15;
1264
+ $[52] = t16;
1265
+ $[53] = t17;
1266
+ $[54] = t5;
1267
+ $[55] = tool.id;
1268
+ $[56] = t18;
965
1269
  } else {
966
- t18 = $[55];
1270
+ t18 = $[56];
967
1271
  }
968
1272
  return t18;
969
1273
  }
@@ -1006,7 +1310,7 @@ export function RunningFor(t0) {
1006
1310
  }
1007
1311
  /* A call still running: its timer on the line, and for a provider that streams output, the last lines under it. */
1008
1312
  export function WorkLiveRow(t0) {
1009
- const $ = _c(49);
1313
+ const $ = _c(50);
1010
1314
  const {
1011
1315
  chatId,
1012
1316
  tool: derived
@@ -1150,19 +1454,21 @@ export function WorkLiveRow(t0) {
1150
1454
  t14 = $[37];
1151
1455
  }
1152
1456
  let t15;
1153
- if ($[38] !== open || $[39] !== opens || $[40] !== tool) {
1457
+ if ($[38] !== chatId || $[39] !== open || $[40] !== opens || $[41] !== tool) {
1154
1458
  t15 = open && opens && /*#__PURE__*/_jsx(ToolBody, {
1155
- tool: tool
1459
+ tool: tool,
1460
+ chatId: chatId
1156
1461
  });
1157
- $[38] = open;
1158
- $[39] = opens;
1159
- $[40] = tool;
1160
- $[41] = t15;
1462
+ $[38] = chatId;
1463
+ $[39] = open;
1464
+ $[40] = opens;
1465
+ $[41] = tool;
1466
+ $[42] = t15;
1161
1467
  } else {
1162
- t15 = $[41];
1468
+ t15 = $[42];
1163
1469
  }
1164
1470
  let t16;
1165
- if ($[42] !== open || $[43] !== tail) {
1471
+ if ($[43] !== open || $[44] !== tail) {
1166
1472
  t16 = tail !== null && !open && /*#__PURE__*/_jsx("pre", {
1167
1473
  className: "mt-1.5 mb-2 ml-6 max-h-48 overflow-auto rounded-md border border-border bg-surface-raised px-3 py-2 font-mono text-code whitespace-pre-wrap text-chat-output select-text",
1168
1474
  children: /*#__PURE__*/_jsx(AnsiOutput, {
@@ -1170,23 +1476,23 @@ export function WorkLiveRow(t0) {
1170
1476
  tailLines: 12
1171
1477
  })
1172
1478
  });
1173
- $[42] = open;
1174
- $[43] = tail;
1175
- $[44] = t16;
1479
+ $[43] = open;
1480
+ $[44] = tail;
1481
+ $[45] = t16;
1176
1482
  } else {
1177
- t16 = $[44];
1483
+ t16 = $[45];
1178
1484
  }
1179
1485
  let t17;
1180
- if ($[45] !== t14 || $[46] !== t15 || $[47] !== t16) {
1486
+ if ($[46] !== t14 || $[47] !== t15 || $[48] !== t16) {
1181
1487
  t17 = /*#__PURE__*/_jsxs("div", {
1182
1488
  children: [t14, t15, t16]
1183
1489
  });
1184
- $[45] = t14;
1185
- $[46] = t15;
1186
- $[47] = t16;
1187
- $[48] = t17;
1490
+ $[46] = t14;
1491
+ $[47] = t15;
1492
+ $[48] = t16;
1493
+ $[49] = t17;
1188
1494
  } else {
1189
- t17 = $[48];
1495
+ t17 = $[49];
1190
1496
  }
1191
1497
  return t17;
1192
1498
  }
@@ -1401,12 +1707,16 @@ function _temp5(t0) {
1401
1707
  function omittedLabel(reason) {
1402
1708
  return reason === 'binary' ? i18next.t('agent-chat:work.omitted.binary') : i18next.t('agent-chat:work.omitted.tooLarge');
1403
1709
  }
1404
- /* One file of a turn's checkpoint diff: its patch, or the reason there is none. */
1710
+ /* One file of a turn's checkpoint diff: its patch, the reason there is none, or the offer of the whole diff where the thread held this one back. */
1405
1711
  function CheckpointFileBody(t0) {
1406
- const $ = _c(6);
1712
+ const $ = _c(14);
1407
1713
  const {
1408
- file
1714
+ file,
1715
+ whole
1409
1716
  } = t0;
1717
+ const {
1718
+ t
1719
+ } = useTranslation("agent-chat");
1410
1720
  if (file.omitted) {
1411
1721
  let t1;
1412
1722
  if ($[0] !== file.omitted) {
@@ -1429,17 +1739,53 @@ function CheckpointFileBody(t0) {
1429
1739
  }
1430
1740
  return t2;
1431
1741
  }
1742
+ if (whole !== null && file.diff === "") {
1743
+ let t1;
1744
+ if ($[4] !== t) {
1745
+ t1 = t("work.showFullDiff");
1746
+ $[4] = t;
1747
+ $[5] = t1;
1748
+ } else {
1749
+ t1 = $[5];
1750
+ }
1751
+ let t2;
1752
+ if ($[6] !== t) {
1753
+ t2 = t("work.fullDiffFailed");
1754
+ $[6] = t;
1755
+ $[7] = t2;
1756
+ } else {
1757
+ t2 = $[7];
1758
+ }
1759
+ let t3;
1760
+ if ($[8] !== t1 || $[9] !== t2 || $[10] !== whole) {
1761
+ t3 = /*#__PURE__*/_jsx("div", {
1762
+ className: "px-3",
1763
+ children: /*#__PURE__*/_jsx(WholeBar, {
1764
+ whole: whole,
1765
+ label: t1,
1766
+ failedLabel: t2
1767
+ })
1768
+ });
1769
+ $[8] = t1;
1770
+ $[9] = t2;
1771
+ $[10] = whole;
1772
+ $[11] = t3;
1773
+ } else {
1774
+ t3 = $[11];
1775
+ }
1776
+ return t3;
1777
+ }
1432
1778
  let t1;
1433
- if ($[4] !== file) {
1779
+ if ($[12] !== file) {
1434
1780
  t1 = /*#__PURE__*/_jsx(DiffSuspense, {
1435
1781
  children: /*#__PURE__*/_jsx(UnifiedDiff, {
1436
1782
  change: file
1437
1783
  })
1438
1784
  });
1439
- $[4] = file;
1440
- $[5] = t1;
1785
+ $[12] = file;
1786
+ $[13] = t1;
1441
1787
  } else {
1442
- t1 = $[5];
1788
+ t1 = $[13];
1443
1789
  }
1444
1790
  return t1;
1445
1791
  }
@@ -1623,34 +1969,50 @@ function ChangedFilesCard(t0) {
1623
1969
  * checkpoint diff comes first (the working tree against the tree the turn started from), then the
1624
1970
  * unified diffs the CLI reported, then the before and after of its own edits. A turn that has a
1625
1971
  * checkpoint but no stored diff asks the host for one, which is also how a running turn gets it.
1972
+ * A diff the thread keeps only the first files of (`heldBack`) asks for the whole when a person does.
1626
1973
  */
1627
1974
  function _temp6(value) {
1628
1975
  return !value;
1629
1976
  }
1630
1977
  export function ChangedFilesRow(t0) {
1631
- const $ = _c(34);
1978
+ const $ = _c(45);
1632
1979
  const {
1633
1980
  tools,
1634
1981
  diff,
1635
1982
  checkpoint,
1636
1983
  baseMoved,
1637
1984
  chatId,
1638
- turnId
1985
+ turnId,
1986
+ heldBack: t1
1639
1987
  } = t0;
1640
- let t1;
1988
+ const heldBack = t1 === undefined ? false : t1;
1989
+ let t2;
1641
1990
  if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
1642
- t1 = {};
1643
- $[0] = t1;
1991
+ t2 = {};
1992
+ $[0] = t2;
1644
1993
  } else {
1645
- t1 = $[0];
1994
+ t2 = $[0];
1646
1995
  }
1647
- const [open, setOpen] = useState(t1);
1996
+ const [open, setOpen] = useState(t2);
1648
1997
  const [fetched, setFetched] = useState(null);
1649
1998
  const actions = useChatActions();
1650
- let t2;
1651
1999
  let t3;
1652
- if ($[1] !== actions || $[2] !== chatId || $[3] !== checkpoint || $[4] !== diff || $[5] !== turnId) {
1653
- t2 = () => {
2000
+ if ($[1] !== actions || $[2] !== chatId || $[3] !== heldBack || $[4] !== turnId) {
2001
+ t3 = heldBack ? () => actions.turnDiff(chatId, turnId) : null;
2002
+ $[1] = actions;
2003
+ $[2] = chatId;
2004
+ $[3] = heldBack;
2005
+ $[4] = turnId;
2006
+ $[5] = t3;
2007
+ } else {
2008
+ t3 = $[5];
2009
+ }
2010
+ const whole = useWhole(t3);
2011
+ const loaded = whole.state.status === "loaded" ? whole.state.value : null;
2012
+ let t4;
2013
+ let t5;
2014
+ if ($[6] !== actions || $[7] !== chatId || $[8] !== checkpoint || $[9] !== diff || $[10] !== turnId) {
2015
+ t4 = () => {
1654
2016
  if (diff !== null || !checkpoint) {
1655
2017
  return;
1656
2018
  }
@@ -1664,61 +2026,61 @@ export function ChangedFilesRow(t0) {
1664
2026
  alive = false;
1665
2027
  };
1666
2028
  };
1667
- t3 = [actions, chatId, turnId, diff, checkpoint];
1668
- $[1] = actions;
1669
- $[2] = chatId;
1670
- $[3] = checkpoint;
1671
- $[4] = diff;
1672
- $[5] = turnId;
1673
- $[6] = t2;
1674
- $[7] = t3;
1675
- } else {
1676
- t2 = $[6];
1677
- t3 = $[7];
1678
- }
1679
- useEffect(t2, t3);
1680
- const checkpointDiff = diff ?? fetched;
2029
+ t5 = [actions, chatId, turnId, diff, checkpoint];
2030
+ $[6] = actions;
2031
+ $[7] = chatId;
2032
+ $[8] = checkpoint;
2033
+ $[9] = diff;
2034
+ $[10] = turnId;
2035
+ $[11] = t4;
2036
+ $[12] = t5;
2037
+ } else {
2038
+ t4 = $[11];
2039
+ t5 = $[12];
2040
+ }
2041
+ useEffect(t4, t5);
2042
+ const checkpointDiff = loaded ?? diff ?? fetched;
1681
2043
  const {
1682
2044
  keyOf
1683
2045
  } = useChatScope();
1684
2046
  const flash = useTimelineFlash(_temp8);
1685
- let t4;
1686
- if ($[8] !== chatId || $[9] !== flash || $[10] !== keyOf || $[11] !== turnId) {
1687
- t4 = flash !== null && flash.opens && flash.key === keyOf(chatId) && flash.rowId === `files-${turnId}` ? flash.nonce : 0;
1688
- $[8] = chatId;
1689
- $[9] = flash;
1690
- $[10] = keyOf;
1691
- $[11] = turnId;
1692
- $[12] = t4;
2047
+ let t6;
2048
+ if ($[13] !== chatId || $[14] !== flash || $[15] !== keyOf || $[16] !== turnId) {
2049
+ t6 = flash !== null && flash.opens && flash.key === keyOf(chatId) && flash.rowId === `files-${turnId}` ? flash.nonce : 0;
2050
+ $[13] = chatId;
2051
+ $[14] = flash;
2052
+ $[15] = keyOf;
2053
+ $[16] = turnId;
2054
+ $[17] = t6;
1693
2055
  } else {
1694
- t4 = $[12];
2056
+ t6 = $[17];
1695
2057
  }
1696
- const revealNonce = t4;
2058
+ const revealNonce = t6;
1697
2059
  if (checkpointDiff !== null && checkpointDiff.files.length > 0) {
1698
2060
  const files = checkpointDiff.files;
1699
- const t5 = files.length;
1700
- const t6 = checkpointDiff.truncated;
1701
- let t7;
1702
- if ($[13] !== files) {
1703
- t7 = files.reduce(_temp9, 0);
1704
- $[13] = files;
1705
- $[14] = t7;
2061
+ const t7 = files.length;
2062
+ const t8 = checkpointDiff.truncated;
2063
+ let t9;
2064
+ if ($[18] !== files) {
2065
+ t9 = files.reduce(_temp9, 0);
2066
+ $[18] = files;
2067
+ $[19] = t9;
1706
2068
  } else {
1707
- t7 = $[14];
2069
+ t9 = $[19];
1708
2070
  }
1709
- let t8;
1710
- if ($[15] !== files) {
1711
- t8 = files.reduce(_temp0, 0);
1712
- $[15] = files;
1713
- $[16] = t8;
2071
+ let t10;
2072
+ if ($[20] !== files) {
2073
+ t10 = files.reduce(_temp0, 0);
2074
+ $[20] = files;
2075
+ $[21] = t10;
1714
2076
  } else {
1715
- t8 = $[16];
2077
+ t10 = $[21];
1716
2078
  }
1717
- let t9;
1718
- if ($[17] !== files || $[18] !== open) {
1719
- let t10;
1720
- if ($[20] !== open) {
1721
- t10 = file_1 => /*#__PURE__*/_jsx(ChangedFileLine, {
2079
+ let t11;
2080
+ if ($[22] !== files || $[23] !== heldBack || $[24] !== loaded || $[25] !== open || $[26] !== whole) {
2081
+ let t12;
2082
+ if ($[28] !== heldBack || $[29] !== loaded || $[30] !== open || $[31] !== whole) {
2083
+ t12 = file_1 => /*#__PURE__*/_jsx(ChangedFileLine, {
1722
2084
  path: file_1.path,
1723
2085
  open: open[file_1.path] === true,
1724
2086
  onToggle: () => setOpen(o => ({
@@ -1735,61 +2097,68 @@ export function ChangedFilesRow(t0) {
1735
2097
  })]
1736
2098
  }),
1737
2099
  children: /*#__PURE__*/_jsx(CheckpointFileBody, {
1738
- file: file_1
2100
+ file: file_1,
2101
+ whole: loaded === null && heldBack ? whole : null
1739
2102
  })
1740
2103
  }, file_1.path);
1741
- $[20] = open;
1742
- $[21] = t10;
2104
+ $[28] = heldBack;
2105
+ $[29] = loaded;
2106
+ $[30] = open;
2107
+ $[31] = whole;
2108
+ $[32] = t12;
1743
2109
  } else {
1744
- t10 = $[21];
2110
+ t12 = $[32];
1745
2111
  }
1746
- t9 = files.map(t10);
1747
- $[17] = files;
1748
- $[18] = open;
1749
- $[19] = t9;
2112
+ t11 = files.map(t12);
2113
+ $[22] = files;
2114
+ $[23] = heldBack;
2115
+ $[24] = loaded;
2116
+ $[25] = open;
2117
+ $[26] = whole;
2118
+ $[27] = t11;
1750
2119
  } else {
1751
- t9 = $[19];
2120
+ t11 = $[27];
1752
2121
  }
1753
- let t10;
1754
- if ($[22] !== baseMoved || $[23] !== checkpointDiff.truncated || $[24] !== files.length || $[25] !== revealNonce || $[26] !== t7 || $[27] !== t8 || $[28] !== t9) {
1755
- t10 = /*#__PURE__*/_jsx(ChangedFilesCard, {
2122
+ let t12;
2123
+ if ($[33] !== baseMoved || $[34] !== checkpointDiff.truncated || $[35] !== files.length || $[36] !== revealNonce || $[37] !== t10 || $[38] !== t11 || $[39] !== t9) {
2124
+ t12 = /*#__PURE__*/_jsx(ChangedFilesCard, {
1756
2125
  revealNonce: revealNonce,
1757
2126
  baseMoved: baseMoved,
1758
- count: t5,
1759
- truncated: t6,
1760
- added: t7,
1761
- deleted: t8,
1762
- children: t9
2127
+ count: t7,
2128
+ truncated: t8,
2129
+ added: t9,
2130
+ deleted: t10,
2131
+ children: t11
1763
2132
  });
1764
- $[22] = baseMoved;
1765
- $[23] = checkpointDiff.truncated;
1766
- $[24] = files.length;
1767
- $[25] = revealNonce;
1768
- $[26] = t7;
1769
- $[27] = t8;
1770
- $[28] = t9;
1771
- $[29] = t10;
2133
+ $[33] = baseMoved;
2134
+ $[34] = checkpointDiff.truncated;
2135
+ $[35] = files.length;
2136
+ $[36] = revealNonce;
2137
+ $[37] = t10;
2138
+ $[38] = t11;
2139
+ $[39] = t9;
2140
+ $[40] = t12;
1772
2141
  } else {
1773
- t10 = $[29];
2142
+ t12 = $[40];
1774
2143
  }
1775
- return t10;
2144
+ return t12;
1776
2145
  }
1777
- let t5;
1778
- if ($[30] !== open || $[31] !== revealNonce || $[32] !== tools) {
1779
- t5 = /*#__PURE__*/_jsx(ProviderChangedFiles, {
2146
+ let t7;
2147
+ if ($[41] !== open || $[42] !== revealNonce || $[43] !== tools) {
2148
+ t7 = /*#__PURE__*/_jsx(ProviderChangedFiles, {
1780
2149
  tools: tools,
1781
2150
  open: open,
1782
2151
  setOpen: setOpen,
1783
2152
  revealNonce: revealNonce
1784
2153
  });
1785
- $[30] = open;
1786
- $[31] = revealNonce;
1787
- $[32] = tools;
1788
- $[33] = t5;
2154
+ $[41] = open;
2155
+ $[42] = revealNonce;
2156
+ $[43] = tools;
2157
+ $[44] = t7;
1789
2158
  } else {
1790
- t5 = $[33];
2159
+ t7 = $[44];
1791
2160
  }
1792
- return t5;
2161
+ return t7;
1793
2162
  }
1794
2163
  function _temp0(sum_0, file_0) {
1795
2164
  return sum_0 + file_0.deleted;