@adecore/agents-react 0.37.1 → 0.37.3

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 (105) hide show
  1. package/dist/chat/chat-client.d.ts +1 -0
  2. package/dist/chat/chat-client.js +2 -1
  3. package/dist/chat/chat-references.d.ts +16 -1
  4. package/dist/chat/chat-references.js +29 -3
  5. package/dist/chat/drafts.d.ts +2 -0
  6. package/dist/chat/drafts.js +21 -5
  7. package/dist/chat/index.d.ts +1 -1
  8. package/dist/chat/logic/picker-entries.d.ts +6 -1
  9. package/dist/chat/logic/picker-entries.js +10 -0
  10. package/dist/chat/mentions.d.ts +31 -14
  11. package/dist/chat/mentions.js +186 -41
  12. package/dist/chat/stash.d.ts +1 -0
  13. package/dist/chat/stash.js +4 -2
  14. package/dist/chat/ui/Composer.js +438 -429
  15. package/dist/chat/ui/ComposerInput.d.ts +1 -0
  16. package/dist/chat/ui/ComposerInput.js +2 -0
  17. package/dist/chat/ui/Markdown.d.ts +3 -1
  18. package/dist/chat/ui/Markdown.js +194 -120
  19. package/dist/chat/ui/MessageActions.js +70 -66
  20. package/dist/chat/ui/Pickers.js +151 -207
  21. package/dist/chat/ui/ReferenceChip.d.ts +15 -0
  22. package/dist/chat/ui/ReferenceChip.js +255 -0
  23. package/dist/chat/ui/RunSettings.js +25 -21
  24. package/dist/chat/ui/Timeline.js +52 -29
  25. package/dist/chat/ui/TimelineMenu.js +84 -78
  26. package/dist/chat/ui/chip-clipboard.d.ts +9 -0
  27. package/dist/chat/ui/chip-clipboard.js +105 -0
  28. package/dist/chat/ui/chips.d.ts +5 -0
  29. package/dist/chat/ui/chips.js +15 -1
  30. package/dist/chat/ui/composer/ComposerMenu.js +140 -79
  31. package/dist/chat/ui/composer/DraftParts.d.ts +0 -4
  32. package/dist/chat/ui/composer/DraftParts.js +0 -41
  33. package/dist/chat/ui/composer/chip-paste.d.ts +15 -0
  34. package/dist/chat/ui/composer/chip-paste.js +104 -0
  35. package/dist/chat/ui/composer/chips.d.ts +5 -0
  36. package/dist/chat/ui/composer/chips.js +59 -9
  37. package/dist/chat/ui/composer/key-handler.js +9 -0
  38. package/dist/chat/ui/composer/use-composer-draft.d.ts +0 -1
  39. package/dist/chat/ui/composer/use-composer-draft.js +2 -10
  40. package/dist/chat/ui/composer/use-composer-menus.d.ts +12 -2
  41. package/dist/chat/ui/composer/use-composer-menus.js +192 -149
  42. package/dist/chat/ui/composer/use-composer-submit.js +17 -12
  43. package/dist/chat/ui/composer/use-draft-files.d.ts +7 -1
  44. package/dist/chat/ui/composer/use-draft-files.js +90 -58
  45. package/dist/chat/ui/composer/use-take-back.js +2 -1
  46. package/dist/chat/ui/index.d.ts +0 -1
  47. package/dist/chat/ui/index.js +0 -1
  48. package/dist/chat/ui/reference-icons.d.ts +3 -0
  49. package/dist/chat/ui/reference-icons.js +15 -0
  50. package/dist/chat/ui/reference-lookup.d.ts +7 -0
  51. package/dist/chat/ui/reference-lookup.js +6 -0
  52. package/dist/chat/ui/rehype-chips.d.ts +8 -1
  53. package/dist/chat/ui/rehype-chips.js +35 -11
  54. package/dist/chat/ui/rows/MessageRows.js +218 -158
  55. package/dist/chat/ui/thread-references.d.ts +4 -0
  56. package/dist/chat/ui/thread-references.js +78 -0
  57. package/dist/host-hooks.d.ts +2 -0
  58. package/dist/host-hooks.js +7 -0
  59. package/dist/host.d.ts +3 -0
  60. package/dist/locales/en/agent-chat.d.ts +20 -3
  61. package/dist/locales/en/agent-chat.js +24 -7
  62. package/dist/locales/nl/agent-chat.d.ts +20 -3
  63. package/dist/locales/nl/agent-chat.js +24 -7
  64. package/package.json +8 -8
  65. package/src/chat/chat-client.ts +4 -1
  66. package/src/chat/chat-references.ts +44 -3
  67. package/src/chat/drafts.ts +24 -6
  68. package/src/chat/index.ts +1 -1
  69. package/src/chat/logic/picker-entries.ts +12 -1
  70. package/src/chat/mentions.ts +202 -36
  71. package/src/chat/stash.ts +6 -2
  72. package/src/chat/ui/Composer.tsx +14 -4
  73. package/src/chat/ui/ComposerInput.tsx +4 -0
  74. package/src/chat/ui/Markdown.tsx +57 -25
  75. package/src/chat/ui/MessageActions.tsx +5 -2
  76. package/src/chat/ui/Pickers.tsx +8 -2
  77. package/src/chat/ui/ReferenceChip.tsx +74 -0
  78. package/src/chat/ui/RunSettings.tsx +29 -23
  79. package/src/chat/ui/Timeline.tsx +24 -2
  80. package/src/chat/ui/TimelineMenu.tsx +7 -3
  81. package/src/chat/ui/chip-clipboard.ts +115 -0
  82. package/src/chat/ui/chips.ts +20 -1
  83. package/src/chat/ui/composer/ComposerMenu.tsx +53 -37
  84. package/src/chat/ui/composer/DraftParts.tsx +0 -12
  85. package/src/chat/ui/composer/chip-paste.ts +122 -0
  86. package/src/chat/ui/composer/chips.ts +60 -10
  87. package/src/chat/ui/composer/key-handler.ts +9 -0
  88. package/src/chat/ui/composer/use-composer-draft.ts +1 -7
  89. package/src/chat/ui/composer/use-composer-menus.ts +68 -29
  90. package/src/chat/ui/composer/use-composer-submit.ts +13 -6
  91. package/src/chat/ui/composer/use-draft-files.ts +39 -5
  92. package/src/chat/ui/composer/use-take-back.ts +2 -1
  93. package/src/chat/ui/index.ts +0 -1
  94. package/src/chat/ui/reference-icons.ts +17 -0
  95. package/src/chat/ui/reference-lookup.ts +13 -0
  96. package/src/chat/ui/rehype-chips.ts +38 -13
  97. package/src/chat/ui/rows/MessageRows.tsx +88 -64
  98. package/src/chat/ui/thread-references.ts +47 -0
  99. package/src/host-hooks.ts +9 -0
  100. package/src/host.ts +6 -1
  101. package/src/locales/en/agent-chat.ts +24 -7
  102. package/src/locales/nl/agent-chat.ts +24 -7
  103. package/dist/chat/ui/ChatReferenceChip.d.ts +0 -4
  104. package/dist/chat/ui/ChatReferenceChip.js +0 -110
  105. package/src/chat/ui/ChatReferenceChip.tsx +0 -26
@@ -0,0 +1,255 @@
1
+ import { c as _c } from "react/compiler-runtime";
2
+ import { useContext } from 'react';
3
+ import clsx from 'clsx';
4
+ import { useTranslation } from 'react-i18next';
5
+ import { CircleOff } from 'lucide-react';
6
+ import { Icon } from '@adecore/ui';
7
+ import { REFERENCE_GONE_TONE, REFERENCE_TONE, TOKEN_ICON, TOKEN_IN_MESSAGE } from './chips.js';
8
+ import { REFERENCE_ICONS } from './reference-icons.js';
9
+ import { ReferenceLookupContext } from './reference-lookup.js';
10
+ /*
11
+ * One token in the transcript. One that opens is a span with a button's role rather than a button,
12
+ * since a button is a box with a baseline of its own and would not sit on the line the others sit on.
13
+ */
14
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
15
+ export function TokenChip(t0) {
16
+ const $ = _c(30);
17
+ let className;
18
+ let icon;
19
+ let kind;
20
+ let label;
21
+ let onOpen;
22
+ let rest;
23
+ let sigil;
24
+ let t1;
25
+ let tone;
26
+ let value;
27
+ if ($[0] !== t0) {
28
+ ({
29
+ kind,
30
+ value,
31
+ sigil,
32
+ icon,
33
+ label,
34
+ tone,
35
+ onOpen,
36
+ className,
37
+ ...rest
38
+ } = t0);
39
+ t1 = e => {
40
+ if (onOpen !== undefined && (e.key === "Enter" || e.key === " ")) {
41
+ e.preventDefault();
42
+ onOpen();
43
+ }
44
+ };
45
+ $[0] = t0;
46
+ $[1] = className;
47
+ $[2] = icon;
48
+ $[3] = kind;
49
+ $[4] = label;
50
+ $[5] = onOpen;
51
+ $[6] = rest;
52
+ $[7] = sigil;
53
+ $[8] = t1;
54
+ $[9] = tone;
55
+ $[10] = value;
56
+ } else {
57
+ className = $[1];
58
+ icon = $[2];
59
+ kind = $[3];
60
+ label = $[4];
61
+ onOpen = $[5];
62
+ rest = $[6];
63
+ sigil = $[7];
64
+ t1 = $[8];
65
+ tone = $[9];
66
+ value = $[10];
67
+ }
68
+ const onKeyDown = t1;
69
+ const t2 = onOpen !== undefined && "cursor-pointer focus-visible:outline-2 focus-visible:outline-accent";
70
+ let t3;
71
+ if ($[11] !== className || $[12] !== t2 || $[13] !== tone) {
72
+ t3 = clsx(TOKEN_IN_MESSAGE, tone, t2, className);
73
+ $[11] = className;
74
+ $[12] = t2;
75
+ $[13] = tone;
76
+ $[14] = t3;
77
+ } else {
78
+ t3 = $[14];
79
+ }
80
+ const t4 = kind === "reference" ? label : undefined;
81
+ const t5 = onOpen === undefined ? undefined : "button";
82
+ const t6 = onOpen === undefined ? undefined : 0;
83
+ const t7 = onOpen === undefined ? undefined : onKeyDown;
84
+ let t8;
85
+ if ($[15] !== sigil) {
86
+ t8 = sigil !== undefined && /*#__PURE__*/_jsx("span", {
87
+ className: "sr-only",
88
+ children: sigil
89
+ });
90
+ $[15] = sigil;
91
+ $[16] = t8;
92
+ } else {
93
+ t8 = $[16];
94
+ }
95
+ let t9;
96
+ if ($[17] !== icon || $[18] !== kind || $[19] !== label || $[20] !== onOpen || $[21] !== rest || $[22] !== t3 || $[23] !== t4 || $[24] !== t5 || $[25] !== t6 || $[26] !== t7 || $[27] !== t8 || $[28] !== value) {
97
+ t9 = /*#__PURE__*/_jsxs("span", {
98
+ ...rest,
99
+ className: t3,
100
+ "data-chip": kind,
101
+ "data-chip-value": value,
102
+ "data-chip-name": t4,
103
+ role: t5,
104
+ tabIndex: t6,
105
+ onClick: onOpen,
106
+ onKeyDown: t7,
107
+ children: [icon, t8, label]
108
+ });
109
+ $[17] = icon;
110
+ $[18] = kind;
111
+ $[19] = label;
112
+ $[20] = onOpen;
113
+ $[21] = rest;
114
+ $[22] = t3;
115
+ $[23] = t4;
116
+ $[24] = t5;
117
+ $[25] = t6;
118
+ $[26] = t7;
119
+ $[27] = t8;
120
+ $[28] = value;
121
+ $[29] = t9;
122
+ } else {
123
+ t9 = $[29];
124
+ }
125
+ return t9;
126
+ }
127
+ /* A view, node or chat a message points at, under the name it has now; one that went says so. */
128
+ export function ReferenceChip(t0) {
129
+ const $ = _c(26);
130
+ const {
131
+ id
132
+ } = t0;
133
+ const {
134
+ t
135
+ } = useTranslation("agent-chat");
136
+ const {
137
+ items,
138
+ open
139
+ } = useContext(ReferenceLookupContext);
140
+ let t1;
141
+ if ($[0] !== id || $[1] !== items) {
142
+ let t2;
143
+ if ($[3] !== id) {
144
+ t2 = candidate => candidate.id === id;
145
+ $[3] = id;
146
+ $[4] = t2;
147
+ } else {
148
+ t2 = $[4];
149
+ }
150
+ t1 = items.find(t2);
151
+ $[0] = id;
152
+ $[1] = items;
153
+ $[2] = t1;
154
+ } else {
155
+ t1 = $[2];
156
+ }
157
+ const item = t1;
158
+ if (item === undefined) {
159
+ let t2;
160
+ if ($[5] === Symbol.for("react.memo_cache_sentinel")) {
161
+ t2 = /*#__PURE__*/_jsx(Icon, {
162
+ icon: CircleOff,
163
+ size: 14,
164
+ className: TOKEN_ICON
165
+ });
166
+ $[5] = t2;
167
+ } else {
168
+ t2 = $[5];
169
+ }
170
+ let t3;
171
+ if ($[6] !== t) {
172
+ t3 = t("references.gone");
173
+ $[6] = t;
174
+ $[7] = t3;
175
+ } else {
176
+ t3 = $[7];
177
+ }
178
+ let t4;
179
+ if ($[8] !== t3) {
180
+ t4 = /*#__PURE__*/_jsx(TokenChip, {
181
+ kind: "gone",
182
+ icon: t2,
183
+ label: t3,
184
+ tone: REFERENCE_GONE_TONE
185
+ });
186
+ $[8] = t3;
187
+ $[9] = t4;
188
+ } else {
189
+ t4 = $[9];
190
+ }
191
+ return t4;
192
+ }
193
+ const t2 = item.id;
194
+ const t3 = REFERENCE_ICONS[item.kind];
195
+ let t4;
196
+ if ($[10] !== t3) {
197
+ t4 = /*#__PURE__*/_jsx(Icon, {
198
+ icon: t3,
199
+ size: 14,
200
+ className: TOKEN_ICON
201
+ });
202
+ $[10] = t3;
203
+ $[11] = t4;
204
+ } else {
205
+ t4 = $[11];
206
+ }
207
+ let t5;
208
+ if ($[12] !== item.name || $[13] !== t) {
209
+ t5 = item.name || t("references.untitled");
210
+ $[12] = item.name;
211
+ $[13] = t;
212
+ $[14] = t5;
213
+ } else {
214
+ t5 = $[14];
215
+ }
216
+ const t6 = open !== null && "hover:bg-text/12";
217
+ let t7;
218
+ if ($[15] !== t6) {
219
+ t7 = clsx(REFERENCE_TONE, t6);
220
+ $[15] = t6;
221
+ $[16] = t7;
222
+ } else {
223
+ t7 = $[16];
224
+ }
225
+ let t8;
226
+ if ($[17] !== item.id || $[18] !== open) {
227
+ t8 = open === null ? undefined : () => open(item.id);
228
+ $[17] = item.id;
229
+ $[18] = open;
230
+ $[19] = t8;
231
+ } else {
232
+ t8 = $[19];
233
+ }
234
+ let t9;
235
+ if ($[20] !== item.id || $[21] !== t4 || $[22] !== t5 || $[23] !== t7 || $[24] !== t8) {
236
+ t9 = /*#__PURE__*/_jsx(TokenChip, {
237
+ kind: "reference",
238
+ value: t2,
239
+ sigil: "#",
240
+ icon: t4,
241
+ label: t5,
242
+ tone: t7,
243
+ onOpen: t8
244
+ });
245
+ $[20] = item.id;
246
+ $[21] = t4;
247
+ $[22] = t5;
248
+ $[23] = t7;
249
+ $[24] = t8;
250
+ $[25] = t9;
251
+ } else {
252
+ t9 = $[25];
253
+ }
254
+ return t9;
255
+ }
@@ -10,7 +10,7 @@ import { AgentIcon } from '../../agents/AgentIcon.js';
10
10
  import { modelName, shortModelName } from '../../agents/model-name.js';
11
11
  import { ModelMarks } from './ModelMarks.js';
12
12
  import { SessionLine } from './SessionLine.js';
13
- import { favoritesFirst, searchModels, shortlistOf, wantsModelSearch } from '../logic/picker-entries.js';
13
+ import { favoritesFirst, inPickerOrder, searchModels, separatesGroups, shortlistOf, wantsModelSearch } from '../logic/picker-entries.js';
14
14
  import { favoriteModelsOf, toggleFavoriteModel, useChatPreferences } from '../preferences.js';
15
15
  import { CONTEXT_OPTION, contextFraction, contextSegments, orderOptions } from '../logic/context-usage.js';
16
16
  import { RUNTIME_MODES } from '../runtime-modes.js';
@@ -56,7 +56,7 @@ function modelValue(provider, slug) {
56
56
  }
57
57
  /* Each provider's current or legacy models; a provider with none of them is left out. */
58
58
  function modelGroupsOf(providers, legacy) {
59
- return providers.map(entry => ({
59
+ return inPickerOrder(providers).map(entry => ({
60
60
  entry,
61
61
  models: entry.models.filter(row => row.legacy === true === legacy)
62
62
  })).filter(group => group.models.length > 0);
@@ -196,7 +196,7 @@ export function RunSettings(t0) {
196
196
  const favoritesOf = t8;
197
197
  let t9;
198
198
  if ($[19] !== favoritesOf || $[20] !== providers || $[21] !== query) {
199
- t9 = query.trim() === "" ? null : searchModels(providers, query, favoritesOf);
199
+ t9 = query.trim() === "" ? null : searchModels(inPickerOrder(providers), query, favoritesOf);
200
200
  $[19] = favoritesOf;
201
201
  $[20] = providers;
202
202
  $[21] = query;
@@ -391,19 +391,21 @@ export function RunSettings(t0) {
391
391
  const providerModels = t17;
392
392
  let t18;
393
393
  if ($[51] !== grouped || $[52] !== providerModels) {
394
- t18 = groups => groups.map(t19 => {
394
+ t18 = groups => groups.map((t19, i_0) => {
395
395
  const {
396
396
  entry: entry_3,
397
397
  models: models_1
398
398
  } = t19;
399
- return /*#__PURE__*/_jsxs(Menu.Group, {
400
- children: [grouped && /*#__PURE__*/_jsxs(Menu.GroupLabel, {
401
- className: "flex items-center gap-1.5",
402
- children: [/*#__PURE__*/_jsx(AgentIcon, {
403
- kind: entry_3.kind,
404
- size: 12
405
- }), entry_3.name]
406
- }), providerModels(entry_3, models_1)]
399
+ return /*#__PURE__*/_jsxs(Fragment, {
400
+ children: [separatesGroups(groups[i_0 - 1]?.entry.kind, entry_3.kind) && /*#__PURE__*/_jsx(Menu.Separator, {}), /*#__PURE__*/_jsxs(Menu.Group, {
401
+ children: [grouped && /*#__PURE__*/_jsxs(Menu.GroupLabel, {
402
+ className: "flex items-center gap-1.5",
403
+ children: [/*#__PURE__*/_jsx(AgentIcon, {
404
+ kind: entry_3.kind,
405
+ size: 12
406
+ }), entry_3.name]
407
+ }), providerModels(entry_3, models_1)]
408
+ })]
407
409
  }, entry_3.kind);
408
410
  });
409
411
  $[51] = grouped;
@@ -657,19 +659,21 @@ export function RunSettings(t0) {
657
659
  t47 = found !== null && found.length > 0 && /*#__PURE__*/_jsx(Menu.RadioGroup, {
658
660
  value: chosenModel,
659
661
  onValueChange: chooseModel,
660
- children: found.map(t48 => {
662
+ children: found.map((t48, i_1) => {
661
663
  const {
662
664
  entry: entry_5,
663
665
  models: models_2
664
666
  } = t48;
665
- return /*#__PURE__*/_jsxs(Menu.Group, {
666
- children: [grouped && /*#__PURE__*/_jsxs(Menu.GroupLabel, {
667
- className: "flex items-center gap-1.5",
668
- children: [/*#__PURE__*/_jsx(AgentIcon, {
669
- kind: entry_5.kind,
670
- size: 12
671
- }), entry_5.name]
672
- }), byMaker(entry_5, models_2)]
667
+ return /*#__PURE__*/_jsxs(Fragment, {
668
+ children: [separatesGroups(found[i_1 - 1]?.entry.kind, entry_5.kind) && /*#__PURE__*/_jsx(Menu.Separator, {}), /*#__PURE__*/_jsxs(Menu.Group, {
669
+ children: [grouped && /*#__PURE__*/_jsxs(Menu.GroupLabel, {
670
+ className: "flex items-center gap-1.5",
671
+ children: [/*#__PURE__*/_jsx(AgentIcon, {
672
+ kind: entry_5.kind,
673
+ size: 12
674
+ }), entry_5.name]
675
+ }), byMaker(entry_5, models_2)]
676
+ })]
673
677
  }, entry_5.kind);
674
678
  })
675
679
  });
@@ -457,6 +457,8 @@ export function Timeline({
457
457
  });
458
458
  const [loadingEarlier, setLoadingEarlier] = useState(false);
459
459
  const loadingEarlierRef = useRef(false);
460
+ const anchorRef = useRef(null);
461
+ const headRef = useRef(undefined);
460
462
  const loadEarlier = useCallback(() => {
461
463
  if (cursor === null || loadingEarlierRef.current) {
462
464
  return;
@@ -559,7 +561,7 @@ export function Timeline({
559
561
  const [, settleLayout] = useReducer(count => count + 1, 0);
560
562
  // Changing this callback invalidates every cached measurement, including on a scroll.
561
563
  const getItemKey = useCallback(index => rows[index].id, [rows]);
562
- // Nothing here builds with the React Compiler, so its memoization rule has nothing to break.
564
+ // Follow the browser's actual end below. Virtual end anchoring drifts when growth still fits without scrolling.
563
565
  // oxlint-disable-next-line react/incompatible-library
564
566
  const virtualizer = useVirtualizer({
565
567
  count: loadingHistory ? 0 : rows.length,
@@ -567,7 +569,6 @@ export function Timeline({
567
569
  estimateSize: () => ESTIMATED_ROW_PX,
568
570
  getItemKey,
569
571
  overscan: 8,
570
- anchorTo: 'end',
571
572
  // Include the end before the first pin, so its actual heights are known before revealing it.
572
573
  rangeExtractor: range => {
573
574
  const indexes = defaultRangeExtractor(range);
@@ -617,10 +618,32 @@ export function Timeline({
617
618
  viewport: element_2.clientHeight
618
619
  };
619
620
  }, [rows.length, totalSize, composerHeight, frame.height]);
621
+ // Prepending history moves rows; keep the reader on the same row at the same height.
622
+ useLayoutEffect(() => {
623
+ const element_3 = scrollRef.current;
624
+ const head = order?.[0];
625
+ const moved = head !== headRef.current;
626
+ headRef.current = head;
627
+ if (element_3 === null) {
628
+ return;
629
+ }
630
+ const anchor = anchorRef.current;
631
+ const index_2 = moved && anchor !== null && !followRef.current ? rows.findIndex(row_8 => row_8.id === anchor.id) : -1;
632
+ if (anchor !== null && index_2 !== -1) {
633
+ virtualizer.getTotalSize();
634
+ element_3.scrollTop = virtualizer.measurementsCache[index_2].start - anchor.offset;
635
+ return;
636
+ }
637
+ const row_9 = virtualizer.getVirtualItemForOffset(element_3.scrollTop);
638
+ anchorRef.current = row_9 === undefined ? null : {
639
+ id: String(row_9.key),
640
+ offset: row_9.start - element_3.scrollTop
641
+ };
642
+ });
620
643
  // Close to the top, the page before goes in; again after each page that left too little above the reader.
621
644
  useEffect(() => {
622
- const element_3 = scrollRef.current;
623
- if (element_3 !== null && wantsEarlier(element_3)) {
645
+ const element_4 = scrollRef.current;
646
+ if (element_4 !== null && wantsEarlier(element_4)) {
624
647
  loadEarlier();
625
648
  }
626
649
  }, [rows, loadEarlier, frame.height]);
@@ -634,8 +657,8 @@ export function Timeline({
634
657
  const measurements = virtualizer.measurementsCache;
635
658
  const starts = {
636
659
  length: ticks.length,
637
- at: index_2 => {
638
- const tick = ticks.at(index_2);
660
+ at: index_3 => {
661
+ const tick = ticks.at(index_3);
639
662
  return tick === undefined ? undefined : measurements[tick.rowIndex]?.start ?? tick.rowIndex * ESTIMATED_ROW_PX;
640
663
  }
641
664
  };
@@ -662,7 +685,7 @@ export function Timeline({
662
685
  starts,
663
686
  inView
664
687
  };
665
- const followStrip = element_4 => {
688
+ const followStrip = element_5 => {
666
689
  const {
667
690
  starts: current_0,
668
691
  inView: shown
@@ -672,7 +695,7 @@ export function Timeline({
672
695
  }
673
696
  const next = messagesInView({
674
697
  starts: current_0,
675
- scrollTop: element_4.scrollTop,
698
+ scrollTop: element_5.scrollTop,
676
699
  visibleHeight: visibleHeightRef.current
677
700
  });
678
701
  if (next?.first !== shown.first || next?.last !== shown.last) {
@@ -697,11 +720,11 @@ export function Timeline({
697
720
  openGroup: groups.add,
698
721
  openSubagent: subagents.add,
699
722
  // A row already on screen stays put; the find scrolls to the match itself once it is drawn.
700
- scrollToRow: index_3 => {
723
+ scrollToRow: index_4 => {
701
724
  const top_0 = scrollRef.current?.scrollTop ?? 0;
702
725
  const bottom = top_0 + visibleHeightRef.current;
703
- if (!virtualizer.getVirtualItems().some(virtualRow_0 => virtualRow_0.index === index_3 && virtualRow_0.end > top_0 && virtualRow_0.start < bottom)) {
704
- virtualizer.scrollToIndex(index_3, {
726
+ if (!virtualizer.getVirtualItems().some(virtualRow_0 => virtualRow_0.index === index_4 && virtualRow_0.end > top_0 && virtualRow_0.start < bottom)) {
727
+ virtualizer.scrollToIndex(index_4, {
705
728
  align: 'center'
706
729
  });
707
730
  }
@@ -719,8 +742,8 @@ export function Timeline({
719
742
  }, [searching, loadEarlier]);
720
743
  const found = useMemo(() => searching ? ticksWithHits(ticks, chatFind.hitRows) : [], [searching, ticks, chatFind.hitRows]);
721
744
  const foundCurrent = chatFind.currentRow === null ? null : tickOfRow(ticks, chatFind.currentRow);
722
- const jumpTo = index_4 => {
723
- const tick_0 = ticks[index_4];
745
+ const jumpTo = index_5 => {
746
+ const tick_0 = ticks[index_5];
724
747
  if (!tick_0) {
725
748
  return;
726
749
  }
@@ -763,10 +786,10 @@ export function Timeline({
763
786
  }
764
787
  return;
765
788
  }
766
- const index_5 = rows.findIndex(row_8 => row_8.id === seeking.itemId);
767
- if (index_5 !== -1) {
789
+ const index_6 = rows.findIndex(row_10 => row_10.id === seeking.itemId);
790
+ if (index_6 !== -1) {
768
791
  setSeeking(null);
769
- showRowAtTop(virtualizer, followRef, index_5);
792
+ showRowAtTop(virtualizer, followRef, index_6);
770
793
  if (seeking.options?.flash) {
771
794
  useTimelineFlash.getState().flash(seeking.key, seeking.itemId, false);
772
795
  }
@@ -837,9 +860,9 @@ export function Timeline({
837
860
  turnId: turnId_0,
838
861
  target: target_0
839
862
  } = revealing;
840
- const changes = target_0 === 'changes' ? rows.findIndex(row_9 => row_9.kind === 'changed-files' && row_9.turnId === turnId_0) : -1;
863
+ const changes = target_0 === 'changes' ? rows.findIndex(row_11 => row_11.kind === 'changed-files' && row_11.turnId === turnId_0) : -1;
841
864
  const opening = order?.map(id_0 => items?.[id_0]).find(item_0 => item_0?.kind === 'user' && item_0.turnId === turnId_0);
842
- const found_0 = changes !== -1 ? changes : rows.findIndex(row_10 => row_10.id === opening?.id || row_10.id === `start-${turnId_0}` || row_10.id === `fold-${turnId_0}`);
865
+ const found_0 = changes !== -1 ? changes : rows.findIndex(row_12 => row_12.id === opening?.id || row_12.id === `start-${turnId_0}` || row_12.id === `fold-${turnId_0}`);
843
866
  if (found_0 !== -1) {
844
867
  setRevealing(null);
845
868
  showRowAtTop(virtualizer, followRef, found_0);
@@ -860,7 +883,7 @@ export function Timeline({
860
883
  // The strip is memoized and draws on every scroll, so it gets one callback for its life.
861
884
  const jumpRef = useRef(jumpTo);
862
885
  jumpRef.current = jumpTo;
863
- const pick = useCallback(index_6 => jumpRef.current(index_6), []);
886
+ const pick = useCallback(index_7 => jumpRef.current(index_7), []);
864
887
  // Read when the card asks rather than on every render, so the strip's memo holds while the thread streams.
865
888
  const cardChat = useMemo(() => ({
866
889
  chatId,
@@ -868,8 +891,8 @@ export function Timeline({
868
891
  if (fork === null) {
869
892
  return false;
870
893
  }
871
- const row_11 = useChats.getState().byKey[keyOf(chatId)];
872
- return forkRefusal(row_11?.info ?? null, row_11?.structure[turnId_2]) === null;
894
+ const row_13 = useChats.getState().byKey[keyOf(chatId)];
895
+ return forkRefusal(row_13?.info ?? null, row_13?.structure[turnId_2]) === null;
873
896
  },
874
897
  fork: turnId_3 => fork?.(chatId, turnId_3)
875
898
  }), [keyOf, chatId, fork]);
@@ -878,11 +901,11 @@ export function Timeline({
878
901
  if (!onMainAgent) {
879
902
  return false;
880
903
  }
881
- const index_7 = stepMessage(starts, i => ticks[i].kind === 'person', scrollTop, direction);
882
- if (index_7 === null) {
904
+ const index_8 = stepMessage(starts, i => ticks[i].kind === 'person', scrollTop, direction);
905
+ if (index_8 === null) {
883
906
  return false;
884
907
  }
885
- jumpTo(index_7);
908
+ jumpTo(index_8);
886
909
  return true;
887
910
  };
888
911
  useEffect(() => registerMessageStepper(keyOf(chatId), direction_0 => stepRef.current(direction_0)), [keyOf, chatId]);
@@ -993,22 +1016,22 @@ export function Timeline({
993
1016
  children: /*#__PURE__*/_jsx(FindRevealContext.Provider, {
994
1017
  value: chatFind.reveal,
995
1018
  children: virtualRows.map(virtualRow_1 => {
996
- const row_12 = rows[virtualRow_1.index];
1019
+ const row_14 = rows[virtualRow_1.index];
997
1020
  return /*#__PURE__*/_jsx(ThreadRow, {
998
- row: row_12,
1021
+ row: row_14,
999
1022
  previous: virtualRow_1.index > 0 ? rows[virtualRow_1.index - 1] : null,
1000
1023
  index: virtualRow_1.index,
1001
1024
  top: virtualRow_1.start,
1002
1025
  measure: virtualizer.measureElement,
1003
1026
  chatId: chatId,
1004
- flashNonce: flash !== null && flashedRow === row_12.id ? flash.nonce : null,
1005
- bookmark: marks.get(row_12.id) ?? null,
1027
+ flashNonce: flash !== null && flashedRow === row_14.id ? flash.nonce : null,
1028
+ bookmark: marks.get(row_14.id) ?? null,
1006
1029
  toggleGroup: groups.toggle,
1007
1030
  toggleTurn: turns.toggle,
1008
1031
  toggleSubagent: subagents.toggle,
1009
1032
  openSubagent: openSubagent,
1010
1033
  openConversation: openConversation
1011
- }, row_12.id);
1034
+ }, row_14.id);
1012
1035
  })
1013
1036
  })
1014
1037
  })