@tutti-os/agent-gui 0.0.111 → 0.0.113

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 (56) hide show
  1. package/dist/{AgentGUI-DXwtHJnv.d.ts → AgentGUI-D4jgPDg0.d.ts} +6 -3
  2. package/dist/{AgentRichTextReadonly-VKMTXBKA.js → AgentRichTextReadonly-KNPDB5ZJ.js} +5 -5
  3. package/dist/agent-conversation/index.d.ts +3 -3
  4. package/dist/agent-conversation/index.js +7 -7
  5. package/dist/agent-gui.d.ts +3 -3
  6. package/dist/agent-gui.js +14 -14
  7. package/dist/agent-message-center/index.d.ts +1 -1
  8. package/dist/agent-message-center/index.js +6 -6
  9. package/dist/{agentConversationVM-D3Dn2LqN.d.ts → agentConversationVM-BD0-gg6C.d.ts} +1 -0
  10. package/dist/{agentGuiNodeTypes-CR_l4HhU.d.ts → agentGuiNodeTypes-BebhwDeE.d.ts} +3 -1
  11. package/dist/app/renderer/agentactivity.css +1 -0
  12. package/dist/{chunk-QMU5KFPY.js → chunk-455YDWMS.js} +2 -2
  13. package/dist/{chunk-HGHNKOR2.js → chunk-BYE5CKEU.js} +3 -3
  14. package/dist/{chunk-HLSEVZCW.js → chunk-CTSKSYMM.js} +2 -2
  15. package/dist/{chunk-3QIE72RQ.js → chunk-CY45OZEY.js} +2 -2
  16. package/dist/{chunk-7D7L3JGA.js → chunk-DIFAX3KB.js} +4 -4
  17. package/dist/{chunk-HHQTW2VC.js → chunk-EM4RD5FQ.js} +687 -276
  18. package/dist/chunk-EM4RD5FQ.js.map +1 -0
  19. package/dist/{chunk-Z662JCRH.js → chunk-FBPZXKQC.js} +2 -2
  20. package/dist/{chunk-5O3KW33M.js → chunk-HFU3FYXP.js} +4 -4
  21. package/dist/{chunk-CVPI23GJ.js → chunk-PEOMUPWF.js} +40 -14
  22. package/dist/chunk-PEOMUPWF.js.map +1 -0
  23. package/dist/{chunk-RX6JAGC6.js → chunk-RATBQN2V.js} +2 -2
  24. package/dist/chunk-RATBQN2V.js.map +1 -0
  25. package/dist/{chunk-74ZOQONQ.js → chunk-SFYWL6FT.js} +2 -2
  26. package/dist/{chunk-2JPJLBER.js → chunk-W4KHK5HK.js} +19 -3
  27. package/dist/chunk-W4KHK5HK.js.map +1 -0
  28. package/dist/{chunk-HWMDMZPV.js → chunk-WA5LSG5S.js} +29 -5
  29. package/dist/chunk-WA5LSG5S.js.map +1 -0
  30. package/dist/{chunk-WGUEDMSP.js → chunk-YKQAOIF2.js} +3 -3
  31. package/dist/context-mention-palette/index.js +7 -7
  32. package/dist/i18n/index.d.ts +18 -2
  33. package/dist/i18n/index.js +2 -2
  34. package/dist/index.d.ts +5 -5
  35. package/dist/index.js +14 -14
  36. package/dist/mention-search.d.ts +12 -0
  37. package/dist/mention-search.js +5 -5
  38. package/dist/workbench/contribution.js +3 -3
  39. package/dist/workbench/index.js +3 -3
  40. package/dist/workbench/sessionTitle.js +2 -2
  41. package/package.json +14 -14
  42. package/dist/chunk-2JPJLBER.js.map +0 -1
  43. package/dist/chunk-CVPI23GJ.js.map +0 -1
  44. package/dist/chunk-HHQTW2VC.js.map +0 -1
  45. package/dist/chunk-HWMDMZPV.js.map +0 -1
  46. package/dist/chunk-RX6JAGC6.js.map +0 -1
  47. /package/dist/{AgentRichTextReadonly-VKMTXBKA.js.map → AgentRichTextReadonly-KNPDB5ZJ.js.map} +0 -0
  48. /package/dist/{chunk-QMU5KFPY.js.map → chunk-455YDWMS.js.map} +0 -0
  49. /package/dist/{chunk-HGHNKOR2.js.map → chunk-BYE5CKEU.js.map} +0 -0
  50. /package/dist/{chunk-HLSEVZCW.js.map → chunk-CTSKSYMM.js.map} +0 -0
  51. /package/dist/{chunk-3QIE72RQ.js.map → chunk-CY45OZEY.js.map} +0 -0
  52. /package/dist/{chunk-7D7L3JGA.js.map → chunk-DIFAX3KB.js.map} +0 -0
  53. /package/dist/{chunk-Z662JCRH.js.map → chunk-FBPZXKQC.js.map} +0 -0
  54. /package/dist/{chunk-5O3KW33M.js.map → chunk-HFU3FYXP.js.map} +0 -0
  55. /package/dist/{chunk-74ZOQONQ.js.map → chunk-SFYWL6FT.js.map} +0 -0
  56. /package/dist/{chunk-WGUEDMSP.js.map → chunk-YKQAOIF2.js.map} +0 -0
@@ -2,7 +2,7 @@ import {
2
2
  AgentRichTextReadonly,
3
3
  promptForProviderSkills,
4
4
  skillTriggerForPrefix
5
- } from "./chunk-QMU5KFPY.js";
5
+ } from "./chunk-455YDWMS.js";
6
6
  import {
7
7
  classifyRecoverableAgentMessage,
8
8
  isProviderPlanLimitMessage,
@@ -38,7 +38,7 @@ import {
38
38
  resolveWorkspaceFileLinkAction,
39
39
  resolveWorkspaceFilePathCandidate,
40
40
  resolveWorkspaceLinkAction
41
- } from "./chunk-WGUEDMSP.js";
41
+ } from "./chunk-YKQAOIF2.js";
42
42
  import {
43
43
  cn
44
44
  } from "./chunk-KPMQGPYU.js";
@@ -46,7 +46,7 @@ import {
46
46
  useOptionalAgentActivityRuntime,
47
47
  useOptionalAgentHostApi,
48
48
  workspaceAgentProviderLabel
49
- } from "./chunk-RX6JAGC6.js";
49
+ } from "./chunk-RATBQN2V.js";
50
50
  import {
51
51
  fileChangeCountFromChanges,
52
52
  fileChangeEntriesFromChanges,
@@ -57,8 +57,9 @@ import {
57
57
  } from "./chunk-MIJXEELH.js";
58
58
  import {
59
59
  getActiveUiLanguage,
60
- translate
61
- } from "./chunk-HLSEVZCW.js";
60
+ translate,
61
+ useTranslation
62
+ } from "./chunk-CTSKSYMM.js";
62
63
 
63
64
  // shared/workspaceAgentToolCallIdentifiers.ts
64
65
  function looksLikeOpaqueToolCallIdentifier(value) {
@@ -2275,6 +2276,94 @@ function buildWorkspaceAgentSessionDetailViewModel(input) {
2275
2276
  return buildCanonicalWorkspaceAgentDetailView(input);
2276
2277
  }
2277
2278
 
2279
+ // shared/agentConversation/projection/agentMessageFinalTextProjection.ts
2280
+ function projectAgentMessageFinalText(rows, detail) {
2281
+ const finalTextTargetKeys = findLatestAssistantFinalTextTargetKeys(
2282
+ rows,
2283
+ buildAssistantFinalTextEligibleTurnIds(detail)
2284
+ );
2285
+ return rows.map((row) => {
2286
+ if (row.kind !== "message") {
2287
+ return row;
2288
+ }
2289
+ let changed = false;
2290
+ const messages = row.messages.map((message) => {
2291
+ const isTurnFinalText = row.speaker === "assistant" && finalTextTargetKeys.has(messagePresentationTargetKey(row, message));
2292
+ const copyText = row.speaker === "user" ? copyTextForUserMessage(message) : isTurnFinalText ? message.body : null;
2293
+ if ((message.copyText ?? null) === copyText && message.isTurnFinalText === (isTurnFinalText ? true : void 0)) {
2294
+ return message;
2295
+ }
2296
+ changed = true;
2297
+ const nextMessage = isTurnFinalText ? { ...message, isTurnFinalText: true } : omitTurnFinalText(message);
2298
+ if (copyText) {
2299
+ return { ...nextMessage, copyText };
2300
+ }
2301
+ const { copyText: _copyText, ...withoutCopyText } = nextMessage;
2302
+ return withoutCopyText;
2303
+ });
2304
+ return changed ? { ...row, messages } : row;
2305
+ });
2306
+ }
2307
+ function omitTurnFinalText(message) {
2308
+ const { isTurnFinalText: _isTurnFinalText, ...withoutTurnFinalText } = message;
2309
+ return withoutTurnFinalText;
2310
+ }
2311
+ function buildAssistantFinalTextEligibleTurnIds(detail) {
2312
+ const ids = /* @__PURE__ */ new Set();
2313
+ detail.turns.forEach((turn, index) => {
2314
+ if (index < detail.turns.length - 1 || isLatestTranscriptTurnSettled(detail)) {
2315
+ ids.add(turn.id);
2316
+ }
2317
+ });
2318
+ return ids;
2319
+ }
2320
+ function isLatestTranscriptTurnSettled(detail) {
2321
+ const latestTranscriptTurnId = detail.turns.at(-1)?.id;
2322
+ const canonicalTurn = detail.sessionTurns?.find(
2323
+ (turn) => turn.turnId === latestTranscriptTurnId
2324
+ );
2325
+ const activeTurn = detail.session.activeTurn;
2326
+ if (activeTurn && activeTurn.turnId === latestTranscriptTurnId && activeTurn.phase !== "settled") {
2327
+ return false;
2328
+ }
2329
+ if (canonicalTurn) {
2330
+ return canonicalTurn.phase === "settled" && detail.showProcessingIndicator !== true;
2331
+ }
2332
+ const activePhase = activeTurn?.phase ?? "";
2333
+ return detail.showProcessingIndicator !== true && !["submitted", "running", "waiting", "settling"].includes(activePhase);
2334
+ }
2335
+ function findLatestAssistantFinalTextTargetKeys(rows, eligibleTurnIds) {
2336
+ const targetKeys = /* @__PURE__ */ new Set();
2337
+ const coveredTurnIds = /* @__PURE__ */ new Set();
2338
+ for (let rowIndex = rows.length - 1; rowIndex >= 0; rowIndex -= 1) {
2339
+ const row = rows[rowIndex];
2340
+ if (row?.kind !== "message" || row.speaker !== "assistant" || coveredTurnIds.has(row.turnId) || !eligibleTurnIds.has(row.turnId)) {
2341
+ continue;
2342
+ }
2343
+ for (let messageIndex = row.messages.length - 1; messageIndex >= 0; messageIndex -= 1) {
2344
+ const message = row.messages[messageIndex];
2345
+ if (message && isSettledAssistantFinalTextCandidate(message)) {
2346
+ targetKeys.add(messagePresentationTargetKey(row, message));
2347
+ coveredTurnIds.add(row.turnId);
2348
+ break;
2349
+ }
2350
+ }
2351
+ }
2352
+ return targetKeys;
2353
+ }
2354
+ function messagePresentationTargetKey(row, message) {
2355
+ return `${row.id}\0${message.id}`;
2356
+ }
2357
+ function copyTextForUserMessage(message) {
2358
+ return isVisibleTextMessage(message) ? message.body : null;
2359
+ }
2360
+ function isSettledAssistantFinalTextCandidate(message) {
2361
+ return isVisibleTextMessage(message) && message.statusKind !== "working" && message.statusKind !== "waiting";
2362
+ }
2363
+ function isVisibleTextMessage(message) {
2364
+ return message.body.trim() !== "" && message.contentKind !== "image-grid" && !message.visibleError && !message.systemNotice;
2365
+ }
2366
+
2278
2367
  // shared/agentConversation/projection/agentToolGroupingProjection.ts
2279
2368
  var AVOID_GROUPING_EDITS = false;
2280
2369
  function computeAgentToolGroups(sequence, {
@@ -3844,10 +3933,23 @@ function projectAgentProcessingRow(detail, rows) {
3844
3933
  if (!detail.showProcessingIndicator) {
3845
3934
  return null;
3846
3935
  }
3847
- const turnId = detail.turns.at(-1)?.id ?? null;
3848
- if (turnId && hasSpecificProgressRow(rows, turnId)) {
3936
+ const activeTurnId = detail.session.activeTurnId;
3937
+ const canonicalTurn = detail.sessionTurns?.find(
3938
+ (turn) => turn.turnId === activeTurnId
3939
+ );
3940
+ if (canonicalTurn && canonicalTurn.phase !== "settled" && Number.isFinite(canonicalTurn.startedAtUnixMs)) {
3941
+ if (activeTurnId && hasTurnTimingHostRow(rows, activeTurnId)) {
3942
+ return null;
3943
+ }
3944
+ return processingRow(detail, activeTurnId);
3945
+ }
3946
+ const fallbackTurnId = activeTurnId ?? detail.turns.at(-1)?.id ?? null;
3947
+ if (fallbackTurnId && hasSpecificProgressRow(rows, fallbackTurnId)) {
3849
3948
  return null;
3850
3949
  }
3950
+ return processingRow(detail, fallbackTurnId);
3951
+ }
3952
+ function processingRow(detail, turnId) {
3851
3953
  return {
3852
3954
  kind: "processing",
3853
3955
  id: `processing:${turnId ?? "session"}`,
@@ -3855,6 +3957,9 @@ function projectAgentProcessingRow(detail, rows) {
3855
3957
  occurredAtUnixMs: detail.session.updatedAtUnixMs ?? detail.session.createdAtUnixMs ?? null
3856
3958
  };
3857
3959
  }
3960
+ function hasTurnTimingHostRow(rows, activeTurnId) {
3961
+ return rows.some((row) => row.turnId === activeTurnId);
3962
+ }
3858
3963
  function hasSpecificProgressRow(rows, activeTurnId) {
3859
3964
  return rows.some((row) => {
3860
3965
  if (row.turnId !== activeTurnId) {
@@ -4377,29 +4482,25 @@ function projectAgentConversationVM(detail, options = {}) {
4377
4482
  const summary = summariesByTurnId.get(turn.id);
4378
4483
  if (summary) rows.push(summary);
4379
4484
  });
4380
- const processing = projectAgentProcessingRow(detail, rows);
4381
- if (processing) {
4382
- rows.push(processing);
4383
- }
4384
- const normalizedRows = projectMessageCopyText(
4385
- dropCodexRuntimeDiagnosticNotices(
4386
- dropRedundantErrorWarningNotices(
4387
- mergeAdjacentAssistantMessageRows(
4388
- dropRedundantCompactFailureEchoRows(
4389
- mergeAdjacentTransportRetryNoticeRows(rows)
4390
- )
4485
+ const normalizedRows = dropCodexRuntimeDiagnosticNotices(
4486
+ dropRedundantErrorWarningNotices(
4487
+ mergeAdjacentAssistantMessageRows(
4488
+ dropRedundantCompactFailureEchoRows(
4489
+ mergeAdjacentTransportRetryNoticeRows(rows)
4391
4490
  )
4392
4491
  )
4393
- ),
4394
- {
4395
- assistantCopyEligibleTurnIds: buildAssistantCopyEligibleTurnIds(detail)
4396
- }
4492
+ )
4493
+ );
4494
+ const processing = projectAgentProcessingRow(detail, normalizedRows);
4495
+ const projectedRows = projectAgentMessageFinalText(
4496
+ processing ? [...normalizedRows, processing] : normalizedRows,
4497
+ detail
4397
4498
  );
4398
4499
  return {
4399
4500
  activity: detail.activity,
4400
4501
  workspaceRoot: detail.workspaceRoot,
4401
4502
  sourceDetail: detail,
4402
- rows: normalizedRows
4503
+ rows: projectedRows
4403
4504
  };
4404
4505
  }
4405
4506
  function dropRedundantCompactFailureEchoRows(rows) {
@@ -4627,86 +4728,6 @@ function mergeSourceTimelineItems2(previous, next) {
4627
4728
  }
4628
4729
  return [...previous, ...next];
4629
4730
  }
4630
- function projectMessageCopyText(rows, options) {
4631
- const assistantCopyTargetKeys = findLatestAssistantCopyTargetKeys(
4632
- rows,
4633
- options.assistantCopyEligibleTurnIds
4634
- );
4635
- return rows.map((row) => {
4636
- if (row.kind !== "message") {
4637
- return row;
4638
- }
4639
- let changed = false;
4640
- const messages = row.messages.map((message) => {
4641
- const copyText = row.speaker === "user" ? copyTextForUserMessage(message) : assistantCopyTargetKeys.has(messageCopyTargetKey(row, message)) ? message.body : null;
4642
- if ((message.copyText ?? null) === copyText) {
4643
- return message;
4644
- }
4645
- changed = true;
4646
- if (copyText) {
4647
- return { ...message, copyText };
4648
- }
4649
- const { copyText: _copyText, ...withoutCopyText } = message;
4650
- return withoutCopyText;
4651
- });
4652
- return changed ? { ...row, messages } : row;
4653
- });
4654
- }
4655
- function buildAssistantCopyEligibleTurnIds(detail) {
4656
- const ids = /* @__PURE__ */ new Set();
4657
- detail.turns.forEach((turn, index) => {
4658
- if (index < detail.turns.length - 1 || isLatestTranscriptTurnSettled(detail)) {
4659
- ids.add(turn.id);
4660
- }
4661
- });
4662
- return ids;
4663
- }
4664
- function isLatestTranscriptTurnSettled(detail) {
4665
- const latestTranscriptTurnId = detail.turns.at(-1)?.id;
4666
- const canonicalTurn = detail.sessionTurns?.find(
4667
- (turn) => turn.turnId === latestTranscriptTurnId
4668
- );
4669
- const activeTurn = detail.session.activeTurn;
4670
- if (activeTurn && activeTurn.turnId === latestTranscriptTurnId && activeTurn.phase !== "settled") {
4671
- return false;
4672
- }
4673
- if (canonicalTurn) {
4674
- return canonicalTurn.phase === "settled" && detail.showProcessingIndicator !== true;
4675
- }
4676
- const activePhase = activeTurn?.phase ?? "";
4677
- return detail.showProcessingIndicator !== true && !["submitted", "running", "waiting", "settling"].includes(activePhase);
4678
- }
4679
- function findLatestAssistantCopyTargetKeys(rows, eligibleTurnIds) {
4680
- const targetKeys = /* @__PURE__ */ new Set();
4681
- const coveredTurnIds = /* @__PURE__ */ new Set();
4682
- for (let rowIndex = rows.length - 1; rowIndex >= 0; rowIndex -= 1) {
4683
- const row = rows[rowIndex];
4684
- if (row?.kind !== "message" || row.speaker !== "assistant" || coveredTurnIds.has(row.turnId) || !eligibleTurnIds.has(row.turnId)) {
4685
- continue;
4686
- }
4687
- for (let messageIndex = row.messages.length - 1; messageIndex >= 0; messageIndex -= 1) {
4688
- const message = row.messages[messageIndex];
4689
- if (message && isSettledTextMessageCopyCandidate(message)) {
4690
- targetKeys.add(messageCopyTargetKey(row, message));
4691
- coveredTurnIds.add(row.turnId);
4692
- break;
4693
- }
4694
- }
4695
- }
4696
- return targetKeys;
4697
- }
4698
- function messageCopyTargetKey(row, message) {
4699
- return `${row.id}\0${message.id}`;
4700
- }
4701
- function copyTextForUserMessage(message) {
4702
- return isTextMessageCopyCandidate(message) ? message.body : null;
4703
- }
4704
- function isSettledTextMessageCopyCandidate(message) {
4705
- return isTextMessageCopyCandidate(message) && message.statusKind !== "working" && message.statusKind !== "waiting";
4706
- }
4707
- function isTextMessageCopyCandidate(message) {
4708
- return message.body.trim() !== "" && message.contentKind !== "image-grid" && !message.visibleError && !message.systemNotice;
4709
- }
4710
4731
  function isMergeableAssistantMessageRow(row) {
4711
4732
  return Boolean(
4712
4733
  row && row.kind === "message" && row.speaker === "assistant" && row.thinking.length === 0 && !row.messages.some(isSpecialAssistantMessage)
@@ -4913,11 +4934,11 @@ function AgentTranscriptSkeleton({
4913
4934
  import {
4914
4935
  Fragment as Fragment7,
4915
4936
  memo as memo4,
4916
- useCallback as useCallback10,
4937
+ useCallback as useCallback11,
4917
4938
  useLayoutEffect as useLayoutEffect4,
4918
- useMemo as useMemo6,
4939
+ useMemo as useMemo7,
4919
4940
  useRef as useRef10,
4920
- useState as useState21
4941
+ useState as useState23
4921
4942
  } from "react";
4922
4943
  import { useVirtualizer } from "@tanstack/react-virtual";
4923
4944
 
@@ -5045,8 +5066,8 @@ function AgentGeneratedImageRow({
5045
5066
  import {
5046
5067
  Fragment as Fragment2,
5047
5068
  useCallback as useCallback4,
5048
- useEffect as useEffect5,
5049
- useState as useState8
5069
+ useEffect as useEffect6,
5070
+ useState as useState9
5050
5071
  } from "react";
5051
5072
  import { CheckIcon, CopyIcon } from "@tutti-os/ui-system/icons";
5052
5073
 
@@ -5352,6 +5373,7 @@ function CollapsibleReveal({
5352
5373
  expanded,
5353
5374
  children,
5354
5375
  className,
5376
+ innerClassName,
5355
5377
  preMountOnIdle = false
5356
5378
  }) {
5357
5379
  "use memo";
@@ -5411,7 +5433,7 @@ function CollapsibleReveal({
5411
5433
  setVisible(false);
5412
5434
  setRevealHeight("0px");
5413
5435
  const animationFrame2 = requestAnimationFrame(() => {
5414
- measuredHeightRef.current = measuredHeightRef.current ?? root.scrollHeight;
5436
+ measuredHeightRef.current = root.scrollHeight;
5415
5437
  setVisible(true);
5416
5438
  setRevealHeight(`${measuredHeightRef.current}px`);
5417
5439
  });
@@ -5422,7 +5444,9 @@ function CollapsibleReveal({
5422
5444
  setRevealHeight("0px");
5423
5445
  return void 0;
5424
5446
  }
5425
- const measuredHeight = measuredHeightRef.current ?? root.scrollHeight;
5447
+ const renderedHeight = root.getBoundingClientRect().height;
5448
+ const cachedHeight = measuredHeightRef.current;
5449
+ const measuredHeight = renderedHeight > 0 ? renderedHeight : cachedHeight ?? root.scrollHeight;
5426
5450
  measuredHeightRef.current = measuredHeight;
5427
5451
  setRevealHeight(`${measuredHeight}px`);
5428
5452
  setVisible(false);
@@ -5442,17 +5466,18 @@ function CollapsibleReveal({
5442
5466
  }
5443
5467
  let animationFrame = null;
5444
5468
  const resizeObserver = new ResizeObserver((entries) => {
5445
- if (heightRef.current === "auto") {
5446
- return;
5447
- }
5469
+ const innerScrollHeight = inner.scrollHeight;
5448
5470
  const nextHeight = Math.ceil(
5449
- entries[0]?.contentRect.height ?? inner.scrollHeight
5471
+ innerScrollHeight > 0 ? innerScrollHeight : entries[0]?.contentRect.height ?? 0
5450
5472
  );
5451
5473
  const previousHeight = measuredHeightRef.current;
5452
5474
  if (!nextHeight || previousHeight === nextHeight) {
5453
5475
  return;
5454
5476
  }
5455
5477
  measuredHeightRef.current = nextHeight;
5478
+ if (heightRef.current === "auto") {
5479
+ return;
5480
+ }
5456
5481
  setRevealHeight(
5457
5482
  `${previousHeight ?? root.getBoundingClientRect().height}px`
5458
5483
  );
@@ -5496,7 +5521,14 @@ function CollapsibleReveal({
5496
5521
  "aria-hidden": visible ? void 0 : true,
5497
5522
  style: rootStyle,
5498
5523
  onTransitionEnd: handleTransitionEnd,
5499
- children: /* @__PURE__ */ jsx5("div", { ref: innerRef, className: "agent-collapsible-reveal__inner", children })
5524
+ children: /* @__PURE__ */ jsx5(
5525
+ "div",
5526
+ {
5527
+ ref: innerRef,
5528
+ className: ["agent-collapsible-reveal__inner", innerClassName ?? ""].filter(Boolean).join(" "),
5529
+ children
5530
+ }
5531
+ )
5500
5532
  }
5501
5533
  );
5502
5534
  }
@@ -6371,6 +6403,23 @@ function AgentThinkingDisclosure({
6371
6403
  ] });
6372
6404
  }
6373
6405
 
6406
+ // shared/agentConversation/components/useElapsedSeconds.ts
6407
+ import { useEffect as useEffect4, useState as useState7 } from "react";
6408
+ function useElapsedSeconds(startUnixMs) {
6409
+ const [nowUnixMs, setNowUnixMs] = useState7(() => Date.now());
6410
+ useEffect4(() => {
6411
+ if (startUnixMs === null) {
6412
+ return;
6413
+ }
6414
+ const timer = setInterval(() => setNowUnixMs(Date.now()), 1e3);
6415
+ return () => clearInterval(timer);
6416
+ }, [startUnixMs]);
6417
+ if (startUnixMs === null) {
6418
+ return null;
6419
+ }
6420
+ return Math.max(0, Math.floor((nowUnixMs - startUnixMs) / 1e3));
6421
+ }
6422
+
6374
6423
  // contexts/workspace/presentation/renderer/components/shared/CanvasNodeGhostIconButton.tsx
6375
6424
  import { forwardRef as forwardRef3 } from "react";
6376
6425
  import { jsx as jsx14 } from "react/jsx-runtime";
@@ -6418,7 +6467,7 @@ var CanvasNodeGhostIconButton = forwardRef3(function CanvasNodeGhostIconButton2(
6418
6467
  });
6419
6468
 
6420
6469
  // shared/agentConversation/components/AgentMessageImages.tsx
6421
- import { useEffect as useEffect4, useMemo, useState as useState7 } from "react";
6470
+ import { useEffect as useEffect5, useMemo, useState as useState8 } from "react";
6422
6471
  import { LoaderCircle } from "lucide-react";
6423
6472
  import { jsx as jsx15 } from "react/jsx-runtime";
6424
6473
  function AgentUserImageGrid({
@@ -6469,15 +6518,15 @@ function AgentUserImageGrid({
6469
6518
  }
6470
6519
  function useAgentMessageImageSources(images) {
6471
6520
  const runtime = useOptionalAgentActivityRuntime();
6472
- const [sources, setSources] = useState7(() => /* @__PURE__ */ new Map());
6473
- const [loadingIds, setLoadingIds] = useState7(() => /* @__PURE__ */ new Set());
6521
+ const [sources, setSources] = useState8(() => /* @__PURE__ */ new Map());
6522
+ const [loadingIds, setLoadingIds] = useState8(() => /* @__PURE__ */ new Set());
6474
6523
  const missingImages = useMemo(
6475
6524
  () => images.filter(
6476
6525
  (image) => !imageSourceUrl(image) && !sources.has(image.id) && image.workspaceId && image.agentSessionId && (image.attachmentId || image.path)
6477
6526
  ),
6478
6527
  [images, sources]
6479
6528
  );
6480
- useEffect4(() => {
6529
+ useEffect5(() => {
6481
6530
  if (!runtime?.readSessionAttachment && !runtime?.readPromptAsset || missingImages.length === 0) {
6482
6531
  return;
6483
6532
  }
@@ -6733,8 +6782,8 @@ function AgentMessageCopyButton({
6733
6782
  onCopyMessageText
6734
6783
  }) {
6735
6784
  "use memo";
6736
- const [copied, setCopied] = useState8(false);
6737
- useEffect5(() => {
6785
+ const [copied, setCopied] = useState9(false);
6786
+ useEffect6(() => {
6738
6787
  if (!copied) {
6739
6788
  return;
6740
6789
  }
@@ -6892,20 +6941,6 @@ function ContextCompactionProgressDivider({
6892
6941
  const text = elapsedSeconds === null ? label : `${label} \xB7 ${formatElapsedSeconds(elapsedSeconds)}`;
6893
6942
  return /* @__PURE__ */ jsx16(ContextCompactionDivider, { text });
6894
6943
  }
6895
- function useElapsedSeconds(startUnixMs) {
6896
- const [nowUnixMs, setNowUnixMs] = useState8(() => Date.now());
6897
- useEffect5(() => {
6898
- if (startUnixMs === null) {
6899
- return;
6900
- }
6901
- const timer = setInterval(() => setNowUnixMs(Date.now()), 1e3);
6902
- return () => clearInterval(timer);
6903
- }, [startUnixMs]);
6904
- if (startUnixMs === null) {
6905
- return null;
6906
- }
6907
- return Math.max(0, Math.floor((nowUnixMs - startUnixMs) / 1e3));
6908
- }
6909
6944
  function formatElapsedSeconds(seconds) {
6910
6945
  if (seconds < 60) {
6911
6946
  return `${seconds}s`;
@@ -7002,11 +7037,11 @@ function LoadingEllipsis2() {
7002
7037
  }
7003
7038
 
7004
7039
  // shared/agentConversation/components/AgentToolGroupRow.tsx
7005
- import { memo as memo2, useState as useState18 } from "react";
7040
+ import { memo as memo2, useState as useState19 } from "react";
7006
7041
  import { ChevronDown as ChevronDown7, ChevronRight as ChevronRight7 } from "lucide-react";
7007
7042
 
7008
7043
  // shared/agentConversation/components/AgentAskUserQuestionCard.tsx
7009
- import { useState as useState14 } from "react";
7044
+ import { useState as useState15 } from "react";
7010
7045
 
7011
7046
  // shared/agentConversation/components/AgentToolCallHeader.tsx
7012
7047
  import { AlertCircle, ChevronDown as ChevronDown4, ChevronRight as ChevronRight4 } from "lucide-react";
@@ -7015,7 +7050,7 @@ import { AlertCircle, ChevronDown as ChevronDown4, ChevronRight as ChevronRight4
7015
7050
  import {
7016
7051
  forwardRef as forwardRef4,
7017
7052
  useCallback as useCallback5,
7018
- useEffect as useEffect6,
7053
+ useEffect as useEffect7,
7019
7054
  useImperativeHandle as useImperativeHandle2,
7020
7055
  useRef as useRef4
7021
7056
  } from "react";
@@ -7097,7 +7132,7 @@ var FilePenLineIcon = forwardRef4(
7097
7132
  stopAnimation
7098
7133
  };
7099
7134
  });
7100
- useEffect6(() => {
7135
+ useEffect7(() => {
7101
7136
  if (active) {
7102
7137
  startAnimation();
7103
7138
  return;
@@ -7176,7 +7211,7 @@ FilePenLineIcon.displayName = "FilePenLineIcon";
7176
7211
  import {
7177
7212
  forwardRef as forwardRef5,
7178
7213
  useCallback as useCallback6,
7179
- useEffect as useEffect7,
7214
+ useEffect as useEffect8,
7180
7215
  useImperativeHandle as useImperativeHandle3,
7181
7216
  useRef as useRef5
7182
7217
  } from "react";
@@ -7240,7 +7275,7 @@ var FileTextIcon = forwardRef5(
7240
7275
  stopAnimation
7241
7276
  };
7242
7277
  });
7243
- useEffect7(() => {
7278
+ useEffect8(() => {
7244
7279
  if (active) {
7245
7280
  startAnimation();
7246
7281
  return;
@@ -7350,7 +7385,7 @@ FileTextIcon.displayName = "FileTextIcon";
7350
7385
  import {
7351
7386
  forwardRef as forwardRef6,
7352
7387
  useCallback as useCallback7,
7353
- useEffect as useEffect8,
7388
+ useEffect as useEffect9,
7354
7389
  useImperativeHandle as useImperativeHandle4,
7355
7390
  useRef as useRef6
7356
7391
  } from "react";
@@ -7415,7 +7450,7 @@ var HammerIcon = forwardRef6(
7415
7450
  stopAnimation
7416
7451
  };
7417
7452
  });
7418
- useEffect8(() => {
7453
+ useEffect9(() => {
7419
7454
  if (active) {
7420
7455
  startAnimation();
7421
7456
  return;
@@ -8931,7 +8966,7 @@ function normalizeToolName7(value) {
8931
8966
  }
8932
8967
 
8933
8968
  // shared/agentConversation/components/tool-renderers/code/AgentCodeBlock.tsx
8934
- import { useMemo as useMemo2, useState as useState9 } from "react";
8969
+ import { useMemo as useMemo2, useState as useState10 } from "react";
8935
8970
 
8936
8971
  // shared/agentConversation/components/tool-renderers/AgentPathTailLabel.tsx
8937
8972
  import { jsx as jsx24, jsxs as jsxs15 } from "react/jsx-runtime";
@@ -8990,7 +9025,7 @@ function AgentCodeBlock({
8990
9025
  flat = false
8991
9026
  }) {
8992
9027
  "use memo";
8993
- const [expanded, setExpanded] = useState9(false);
9028
+ const [expanded, setExpanded] = useState10(false);
8994
9029
  const normalized = content.trimEnd();
8995
9030
  const lines = useMemo2(
8996
9031
  () => normalized ? normalized.split("\n") : [],
@@ -9099,7 +9134,7 @@ import { lazy, Suspense } from "react";
9099
9134
  import {
9100
9135
  forwardRef as forwardRef7,
9101
9136
  useCallback as useCallback8,
9102
- useEffect as useEffect9,
9137
+ useEffect as useEffect10,
9103
9138
  useImperativeHandle as useImperativeHandle5,
9104
9139
  useRef as useRef7
9105
9140
  } from "react";
@@ -9173,7 +9208,7 @@ var AtomIcon = forwardRef7(
9173
9208
  stopAnimation
9174
9209
  };
9175
9210
  });
9176
- useEffect9(() => {
9211
+ useEffect10(() => {
9177
9212
  if (active) {
9178
9213
  startAnimation();
9179
9214
  return;
@@ -9350,7 +9385,7 @@ function languageForPath2(path) {
9350
9385
  }
9351
9386
 
9352
9387
  // shared/agentConversation/components/tool-renderers/file-diff/AgentUnifiedPatchViewer.tsx
9353
- import { useMemo as useMemo3, useState as useState10 } from "react";
9388
+ import { useMemo as useMemo3, useState as useState11 } from "react";
9354
9389
 
9355
9390
  // shared/agentConversation/components/tool-renderers/AgentToolScrollArea.tsx
9356
9391
  import { jsx as jsx28 } from "react/jsx-runtime";
@@ -9477,7 +9512,7 @@ function AgentUnifiedPatchViewer({
9477
9512
  flat = false
9478
9513
  }) {
9479
9514
  "use memo";
9480
- const [expanded, setExpanded] = useState10(false);
9515
+ const [expanded, setExpanded] = useState11(false);
9481
9516
  const normalized = diffText.trimEnd();
9482
9517
  const lines = useMemo3(
9483
9518
  () => normalized ? visiblePatchLines(normalized, compact) : [],
@@ -9635,7 +9670,7 @@ function lineClassName(line) {
9635
9670
  import {
9636
9671
  createContext,
9637
9672
  useContext,
9638
- useState as useState11
9673
+ useState as useState12
9639
9674
  } from "react";
9640
9675
  import { ChevronDown as ChevronDown5, ChevronRight as ChevronRight5 } from "lucide-react";
9641
9676
 
@@ -9959,7 +9994,7 @@ function RawPayloadSection({
9959
9994
  payload
9960
9995
  }) {
9961
9996
  "use memo";
9962
- const [expanded, setExpanded] = useState11(false);
9997
+ const [expanded, setExpanded] = useState12(false);
9963
9998
  const rawJson = rawPayloadJson(payload);
9964
9999
  if (!rawJson) {
9965
10000
  return null;
@@ -10459,7 +10494,7 @@ function stringValue9(value) {
10459
10494
  }
10460
10495
 
10461
10496
  // shared/agentConversation/components/tool-renderers/terminal/AgentTerminalBlock.tsx
10462
- import { useMemo as useMemo4, useState as useState12 } from "react";
10497
+ import { useMemo as useMemo4, useState as useState13 } from "react";
10463
10498
  import { jsx as jsx37, jsxs as jsxs26 } from "react/jsx-runtime";
10464
10499
  var MAX_OUTPUT_LINES = 200;
10465
10500
  function AgentTerminalBlock({
@@ -10469,7 +10504,7 @@ function AgentTerminalBlock({
10469
10504
  status
10470
10505
  }) {
10471
10506
  "use memo";
10472
- const [expanded, setExpanded] = useState12(false);
10507
+ const [expanded, setExpanded] = useState13(false);
10473
10508
  const outputText = useMemo4(
10474
10509
  () => [stdout, stderr].filter(Boolean).join("\n"),
10475
10510
  [stdout, stderr]
@@ -10930,7 +10965,7 @@ ${skill.args}` : skill.skill,
10930
10965
  }
10931
10966
 
10932
10967
  // shared/agentConversation/components/AgentTaskStepList.tsx
10933
- import { useState as useState13 } from "react";
10968
+ import { useState as useState14 } from "react";
10934
10969
  import { jsx as jsx46, jsxs as jsxs32 } from "react/jsx-runtime";
10935
10970
  function AgentTaskStepList({
10936
10971
  steps,
@@ -10944,7 +10979,7 @@ function AgentTaskStepRow({
10944
10979
  onLinkClick
10945
10980
  }) {
10946
10981
  "use memo";
10947
- const [expanded, setExpanded] = useState13(false);
10982
+ const [expanded, setExpanded] = useState14(false);
10948
10983
  const call = step.tool ?? projectTaskStepCall(step);
10949
10984
  const hasDetail = hasAgentToolContent(call);
10950
10985
  const ariaLabel = taskStepAriaLabel(call);
@@ -11288,7 +11323,7 @@ function AgentAskUserQuestionCard({
11288
11323
  const waitingInput = (call.askUserQuestion?.status ?? call.status ?? "").trim().toLowerCase() === "waiting_input";
11289
11324
  const hasDetail = hasAgentToolContent(call);
11290
11325
  const pinned = nonCollapsible ?? waitingInput;
11291
- const [expanded, setExpanded] = useState14(defaultExpanded ?? waitingInput);
11326
+ const [expanded, setExpanded] = useState15(defaultExpanded ?? waitingInput);
11292
11327
  return /* @__PURE__ */ jsxs37("div", { className: "workspace-agents-status-panel__detail-tool-row workspace-agents-status-panel__detail-tool-row--ask-user", children: [
11293
11328
  hasDetail && !pinned ? /* @__PURE__ */ jsx52(
11294
11329
  "button",
@@ -11367,7 +11402,7 @@ function AgentExitPlanModeCard({
11367
11402
  }
11368
11403
 
11369
11404
  // shared/agentConversation/components/AgentTaskCallCard.tsx
11370
- import { useState as useState15 } from "react";
11405
+ import { useState as useState16 } from "react";
11371
11406
  import { jsx as jsx55, jsxs as jsxs40 } from "react/jsx-runtime";
11372
11407
  function AgentTaskCallCard({
11373
11408
  call,
@@ -11380,7 +11415,7 @@ function AgentTaskCallCard({
11380
11415
  const running = (call.task?.status ?? call.status ?? "").trim().toLowerCase() === "running";
11381
11416
  const hasDetail = hasAgentToolContent(call);
11382
11417
  const pinned = nonCollapsible ?? running;
11383
- const [expanded, setExpanded] = useState15(defaultExpanded ?? running);
11418
+ const [expanded, setExpanded] = useState16(defaultExpanded ?? running);
11384
11419
  const ariaLabel = taskCallAriaLabel(call);
11385
11420
  return /* @__PURE__ */ jsxs40("div", { className: "workspace-agents-status-panel__detail-tool-row workspace-agents-status-panel__detail-tool-row--task", children: [
11386
11421
  hasDetail && !pinned ? /* @__PURE__ */ jsx55(
@@ -11422,7 +11457,7 @@ function taskCallAriaLabel(call) {
11422
11457
  }
11423
11458
 
11424
11459
  // shared/agentConversation/components/AgentSubAgentCards.tsx
11425
- import { memo, useEffect as useEffect10, useState as useState16 } from "react";
11460
+ import { memo, useEffect as useEffect11, useState as useState17 } from "react";
11426
11461
  import { AlertCircle as AlertCircle2, ChevronDown as ChevronDown6, ChevronRight as ChevronRight6 } from "lucide-react";
11427
11462
 
11428
11463
  // app/renderer/components/icons/AgentLinedIcon.tsx
@@ -11479,7 +11514,7 @@ function AgentSubAgentCardImpl({
11479
11514
  onLinkClick
11480
11515
  }) {
11481
11516
  "use memo";
11482
- const [expanded, setExpanded] = useState16(subAgent.status === "running");
11517
+ const [expanded, setExpanded] = useState17(subAgent.status === "running");
11483
11518
  return /* @__PURE__ */ jsxs41(
11484
11519
  "div",
11485
11520
  {
@@ -11615,10 +11650,10 @@ function isSubAgentActivelyRunning(subAgent) {
11615
11650
  }
11616
11651
  function useRunningSubAgentNowUnixMs(subAgent) {
11617
11652
  const shouldTick = isSubAgentActivelyRunning(subAgent) && typeof subAgent.startedAtUnixMs === "number";
11618
- const [nowUnixMs, setNowUnixMs] = useState16(
11653
+ const [nowUnixMs, setNowUnixMs] = useState17(
11619
11654
  () => shouldTick ? Date.now() : null
11620
11655
  );
11621
- useEffect10(() => {
11656
+ useEffect11(() => {
11622
11657
  if (!shouldTick) {
11623
11658
  setNowUnixMs(null);
11624
11659
  return;
@@ -11645,7 +11680,7 @@ function subAgentElapsedText(subAgent, runningNowUnixMs) {
11645
11680
  }
11646
11681
 
11647
11682
  // shared/agentConversation/components/AgentToolCallCard.tsx
11648
- import { useState as useState17 } from "react";
11683
+ import { useState as useState18 } from "react";
11649
11684
  import { jsx as jsx58, jsxs as jsxs42 } from "react/jsx-runtime";
11650
11685
  function AgentToolCallCard({
11651
11686
  call,
@@ -11656,7 +11691,7 @@ function AgentToolCallCard({
11656
11691
  variantClassName
11657
11692
  }) {
11658
11693
  "use memo";
11659
- const [expanded, setExpanded] = useState17(defaultExpanded);
11694
+ const [expanded, setExpanded] = useState18(defaultExpanded);
11660
11695
  const hasDetail = hasAgentToolContent(call);
11661
11696
  const canCollapse = hasDetail && !nonCollapsible;
11662
11697
  const ariaLabel = toolCallAriaLabel(call);
@@ -11722,7 +11757,7 @@ var AgentToolGroupRow = memo2(function AgentToolGroupRow2({
11722
11757
  rawTimelineJsonLabel = ""
11723
11758
  }) {
11724
11759
  "use memo";
11725
- const [localExpanded, setLocalExpanded] = useState18(false);
11760
+ const [localExpanded, setLocalExpanded] = useState19(false);
11726
11761
  const hasDetail = row.entries.length > 0;
11727
11762
  const isExpanded = hasDetail && (expanded ?? localExpanded);
11728
11763
  const setNextExpanded = (nextExpanded) => {
@@ -11870,7 +11905,7 @@ function renderToolCard(call, onLinkClick, previewMode = false, showRawTimelineJ
11870
11905
  }
11871
11906
 
11872
11907
  // shared/agentConversation/components/AgentTurnSummaryRow.tsx
11873
- import { useEffect as useEffect11, useMemo as useMemo5, useState as useState19 } from "react";
11908
+ import { useEffect as useEffect12, useMemo as useMemo5, useState as useState20 } from "react";
11874
11909
  import {
11875
11910
  ChevronDown as ChevronDown8,
11876
11911
  ChevronRight as ChevronRight8,
@@ -12109,13 +12144,13 @@ function AgentTurnSummaryRow({
12109
12144
  onLinkAction
12110
12145
  }) {
12111
12146
  "use memo";
12112
- const [expandedFiles, setExpandedFiles] = useState19(
12147
+ const [expandedFiles, setExpandedFiles] = useState20(
12113
12148
  {}
12114
12149
  );
12115
- const [showAllFiles, setShowAllFiles] = useState19(false);
12116
- const [patchAction, setPatchAction] = useState19("undo");
12117
- const [patchPending, setPatchPending] = useState19(false);
12118
- const [patchSupportState, setPatchSupportState] = useState19(null);
12150
+ const [showAllFiles, setShowAllFiles] = useState20(false);
12151
+ const [patchAction, setPatchAction] = useState20("undo");
12152
+ const [patchPending, setPatchPending] = useState20(false);
12153
+ const [patchSupportState, setPatchSupportState] = useState20(null);
12119
12154
  const agentHostApi = useOptionalAgentHostApi();
12120
12155
  const aggregateStats = useMemo5(
12121
12156
  () => summarizeRowDiff(row.files),
@@ -12159,7 +12194,7 @@ function AgentTurnSummaryRow({
12159
12194
  );
12160
12195
  const patchSupportKey = patchSupportCwds.join("\n");
12161
12196
  const resolveGitPatchSupport = agentHostApi?.workspace.resolveGitPatchSupport;
12162
- useEffect11(() => {
12197
+ useEffect12(() => {
12163
12198
  if (!resolveGitPatchSupport || patchSupportCwds.length === 0) {
12164
12199
  setPatchSupportState(null);
12165
12200
  return;
@@ -12716,6 +12751,328 @@ var AgentTranscriptItemView = memo3(function AgentTranscriptItemView2({
12716
12751
  }
12717
12752
  });
12718
12753
 
12754
+ // shared/agentConversation/components/AgentTurnDisclosureContext.tsx
12755
+ import {
12756
+ createContext as createContext2,
12757
+ useCallback as useCallback10,
12758
+ useContext as useContext2,
12759
+ useMemo as useMemo6,
12760
+ useState as useState21
12761
+ } from "react";
12762
+ import { jsx as jsx63 } from "react/jsx-runtime";
12763
+ var AgentTurnDisclosureContext = createContext2(null);
12764
+ function AgentTurnDisclosureProvider({
12765
+ children
12766
+ }) {
12767
+ const store = useAgentTurnDisclosureStoreState();
12768
+ return /* @__PURE__ */ jsx63(AgentTurnDisclosureContext.Provider, { value: store, children });
12769
+ }
12770
+ function useAgentTurnDisclosureStore() {
12771
+ const contextStore = useContext2(AgentTurnDisclosureContext);
12772
+ const localStore = useAgentTurnDisclosureStoreState();
12773
+ return contextStore ?? localStore;
12774
+ }
12775
+ function useAgentTurnDisclosureStoreState() {
12776
+ const [expandedOverrides, setExpandedOverrides] = useState21({});
12777
+ const setExpandedOverride = useCallback10((key, expanded) => {
12778
+ setExpandedOverrides(
12779
+ (previous) => previous[key] === expanded ? previous : { ...previous, [key]: expanded }
12780
+ );
12781
+ }, []);
12782
+ return useMemo6(
12783
+ () => ({ expandedOverrides, setExpandedOverride }),
12784
+ [expandedOverrides, setExpandedOverride]
12785
+ );
12786
+ }
12787
+
12788
+ // shared/agentConversation/components/AgentTurnWorkSection.tsx
12789
+ import { BareIconButton } from "@tutti-os/ui-system/components";
12790
+ import { ChevronDownIcon } from "@tutti-os/ui-system/icons";
12791
+
12792
+ // shared/agentConversation/components/agentTurnWorkSectionModel.ts
12793
+ function resolveAgentTurnTiming(turn, isActiveTurn) {
12794
+ if (!turn || !Number.isFinite(turn.startedAtUnixMs)) {
12795
+ return null;
12796
+ }
12797
+ if (turn.phase !== "settled") {
12798
+ return isActiveTurn ? { kind: "live", startedAtUnixMs: turn.startedAtUnixMs } : null;
12799
+ }
12800
+ const endUnixMs = turn.settledAtUnixMs;
12801
+ if (!Number.isFinite(endUnixMs) || endUnixMs < turn.startedAtUnixMs) {
12802
+ return null;
12803
+ }
12804
+ return {
12805
+ kind: "settled",
12806
+ elapsedSeconds: Math.max(
12807
+ 0,
12808
+ Math.floor((endUnixMs - turn.startedAtUnixMs) / 1e3)
12809
+ )
12810
+ };
12811
+ }
12812
+ function formatAgentTurnDuration(elapsedSeconds) {
12813
+ const safeSeconds = Math.max(0, Math.floor(elapsedSeconds));
12814
+ if (safeSeconds < 60) {
12815
+ return { kind: "seconds", seconds: safeSeconds };
12816
+ }
12817
+ const minutes = Math.floor(safeSeconds / 60);
12818
+ const seconds = safeSeconds % 60;
12819
+ if (seconds === 0) {
12820
+ return { kind: "minutes", minutes };
12821
+ }
12822
+ return { kind: "minutes-seconds", minutes, seconds };
12823
+ }
12824
+ function buildAgentTurnWorkSectionModel(group, turn, isActiveTurn = false) {
12825
+ const timing = resolveAgentTurnTiming(turn, isActiveTurn);
12826
+ if (!timing) {
12827
+ return null;
12828
+ }
12829
+ const leadingRowCount = countLeadingUserRows(group.rows);
12830
+ const leadingRows = group.rows.slice(0, leadingRowCount);
12831
+ const finalTarget = findFinalAssistantTextTarget(group.rows);
12832
+ const sections = buildOrderedSections(group.rows, leadingRowCount);
12833
+ const hasHiddenWork = sections.some(
12834
+ (section) => section.kind === "work" && section.rows.length > 0
12835
+ );
12836
+ const collapseEligible = finalTarget !== null && turn?.phase === "settled" && turn.outcome === "completed" && hasHiddenWork && !groupContainsBlockingMessage(group) && !group.rows.some(({ row }) => row.kind === "generated-image");
12837
+ return {
12838
+ timing,
12839
+ leadingRows,
12840
+ sections,
12841
+ collapseEligible
12842
+ };
12843
+ }
12844
+ function countLeadingUserRows(rows) {
12845
+ let count = 0;
12846
+ while (isUserMessageRow(rows[count]?.row)) {
12847
+ count += 1;
12848
+ }
12849
+ return count;
12850
+ }
12851
+ function buildOrderedSections(rows, startIndex) {
12852
+ const sections = [];
12853
+ for (let rowIndex = startIndex; rowIndex < rows.length; rowIndex += 1) {
12854
+ const entry = rows[rowIndex];
12855
+ if (entry.row.kind === "message" && entry.row.speaker === "assistant") {
12856
+ appendAssistantMessageSections(sections, entry);
12857
+ continue;
12858
+ }
12859
+ appendSectionRow(
12860
+ sections,
12861
+ isExplicitWorkRow(entry.row) ? "work" : "visible",
12862
+ entry
12863
+ );
12864
+ }
12865
+ return sections;
12866
+ }
12867
+ function appendAssistantMessageSections(sections, sourceEntry) {
12868
+ const sourceRow = sourceEntry.row;
12869
+ const parts = [];
12870
+ if (sourceRow.thinking.length > 0) {
12871
+ parts.push({ kind: "work", messages: [], thinking: sourceRow.thinking });
12872
+ }
12873
+ for (const message of sourceRow.messages) {
12874
+ const kind = isExplicitWorkMessage(message) ? "work" : "visible";
12875
+ const previous = parts.at(-1);
12876
+ if (previous?.kind === kind && previous.thinking.length === 0) {
12877
+ previous.messages.push(message);
12878
+ continue;
12879
+ }
12880
+ parts.push({ kind, messages: [message], thinking: [] });
12881
+ }
12882
+ if (parts.length === 0) {
12883
+ appendSectionRow(sections, "visible", sourceEntry);
12884
+ return;
12885
+ }
12886
+ if (parts.length === 1 && sourceRow.thinking.length === 0) {
12887
+ appendSectionRow(sections, parts[0].kind, sourceEntry);
12888
+ return;
12889
+ }
12890
+ parts.forEach((part, partIndex) => {
12891
+ appendSectionRow(sections, part.kind, {
12892
+ ...sourceEntry,
12893
+ renderKey: `${sourceRow.id}:turn-${part.kind}-${partIndex}`,
12894
+ row: cloneAssistantRow(sourceRow, part.messages, part.thinking)
12895
+ });
12896
+ });
12897
+ }
12898
+ function appendSectionRow(sections, kind, row) {
12899
+ const previous = sections.at(-1);
12900
+ if (previous?.kind === kind) {
12901
+ previous.rows.push(row);
12902
+ return;
12903
+ }
12904
+ sections.push({ kind, rows: [row] });
12905
+ }
12906
+ function findFinalAssistantTextTarget(rows) {
12907
+ for (let rowIndex = rows.length - 1; rowIndex >= 0; rowIndex -= 1) {
12908
+ const row = rows[rowIndex]?.row;
12909
+ if (row?.kind !== "message" || row.speaker !== "assistant") {
12910
+ continue;
12911
+ }
12912
+ for (let messageIndex = row.messages.length - 1; messageIndex >= 0; messageIndex -= 1) {
12913
+ const message = row.messages[messageIndex];
12914
+ if (message?.isTurnFinalText && message.body.trim() && message.contentKind !== "image-grid" && !message.visibleError && !message.systemNotice) {
12915
+ return { rowIndex, messageIndex };
12916
+ }
12917
+ }
12918
+ }
12919
+ return null;
12920
+ }
12921
+ function groupContainsBlockingMessage(group) {
12922
+ return group.rows.some(
12923
+ ({ row }) => row.kind === "message" && row.messages.some(
12924
+ (message) => Boolean(
12925
+ message.visibleError || message.systemNotice && message.presentationKind === "content"
12926
+ )
12927
+ )
12928
+ );
12929
+ }
12930
+ function isExplicitWorkRow(row) {
12931
+ return row.kind === "tool-group" || row.kind === "turn-summary" || row.kind === "processing";
12932
+ }
12933
+ function isExplicitWorkMessage(message) {
12934
+ return message.presentationKind === "specific-progress" || message.presentationKind === "turn-boundary";
12935
+ }
12936
+ function isUserMessageRow(row) {
12937
+ return row?.kind === "message" && row.speaker === "user";
12938
+ }
12939
+ function cloneAssistantRow(source, messages, thinking) {
12940
+ return {
12941
+ ...source,
12942
+ messages,
12943
+ thinking
12944
+ };
12945
+ }
12946
+
12947
+ // shared/agentConversation/components/AgentTurnWorkSection.tsx
12948
+ import { jsx as jsx64, jsxs as jsxs45 } from "react/jsx-runtime";
12949
+ function AgentTurnWorkSection({
12950
+ model,
12951
+ sessionId,
12952
+ turnKey,
12953
+ showDivider = false,
12954
+ disclosureStore,
12955
+ renderRow
12956
+ }) {
12957
+ const { t } = useTranslation();
12958
+ const disclosureKey = `${sessionId}:${turnKey}`;
12959
+ const expanded = model.collapseEligible ? disclosureStore.expandedOverrides[disclosureKey] ?? false : true;
12960
+ const toggleLabel = expanded ? t("agentHost.agentGui.collapseTurnWork") : t("agentHost.agentGui.expandTurnWork");
12961
+ return /* @__PURE__ */ jsxs45("div", { className: "grid min-w-0", "data-agent-turn-work-section": turnKey, children: [
12962
+ showDivider ? /* @__PURE__ */ jsx64(
12963
+ "div",
12964
+ {
12965
+ className: "mb-4 h-px w-full flex-none bg-[var(--line-2,var(--tutti-line-2))]",
12966
+ "data-testid": "agent-transcript-turn-divider",
12967
+ "aria-hidden": "true"
12968
+ }
12969
+ ) : null,
12970
+ model.leadingRows.length > 0 ? /* @__PURE__ */ jsx64("div", { className: "mb-4 grid gap-4", children: renderRows(model.leadingRows, renderRow) }) : null,
12971
+ /* @__PURE__ */ jsxs45(
12972
+ "div",
12973
+ {
12974
+ className: "flex min-h-6 items-center gap-0.5 text-[12px] text-[var(--text-tertiary)]",
12975
+ "data-agent-turn-work-header": turnKey,
12976
+ children: [
12977
+ /* @__PURE__ */ jsx64(AgentTurnDurationLabel, { timing: model.timing }),
12978
+ model.collapseEligible ? /* @__PURE__ */ jsx64(
12979
+ BareIconButton,
12980
+ {
12981
+ size: "sm",
12982
+ "aria-label": toggleLabel,
12983
+ "aria-expanded": expanded,
12984
+ title: toggleLabel,
12985
+ onClick: () => disclosureStore.setExpandedOverride(disclosureKey, !expanded),
12986
+ children: /* @__PURE__ */ jsx64(
12987
+ ChevronDownIcon,
12988
+ {
12989
+ "aria-hidden": "true",
12990
+ className: `transition-transform duration-150 ${expanded ? "rotate-0" : "-rotate-90"}`
12991
+ }
12992
+ )
12993
+ }
12994
+ ) : null
12995
+ ]
12996
+ }
12997
+ ),
12998
+ model.sections.map((section, sectionIndex) => {
12999
+ const content = renderRows(section.rows, renderRow);
13000
+ if (section.kind !== "work" || !model.collapseEligible) {
13001
+ const firstRow2 = section.rows[0];
13002
+ return /* @__PURE__ */ jsx64(
13003
+ "div",
13004
+ {
13005
+ className: "grid gap-4 pt-4",
13006
+ children: content
13007
+ },
13008
+ `${section.kind}:${firstRow2?.renderKey ?? firstRow2?.row.id ?? sectionIndex}`
13009
+ );
13010
+ }
13011
+ const firstRow = section.rows[0];
13012
+ return /* @__PURE__ */ jsx64(
13013
+ CollapsibleReveal,
13014
+ {
13015
+ expanded,
13016
+ innerClassName: "grid gap-4 pt-4",
13017
+ children: content
13018
+ },
13019
+ `work:${firstRow?.renderKey ?? firstRow?.row.id ?? sectionIndex}`
13020
+ );
13021
+ })
13022
+ ] });
13023
+ }
13024
+ function renderRows(rows, renderRow) {
13025
+ return rows.map(
13026
+ ({ row, rowIndex, renderKey }) => renderRow(row, rowIndex, renderKey)
13027
+ );
13028
+ }
13029
+ function AgentTurnDurationLabel({
13030
+ timing
13031
+ }) {
13032
+ const { t } = useTranslation();
13033
+ const liveElapsedSeconds = useElapsedSeconds(
13034
+ timing.kind === "live" ? timing.startedAtUnixMs : null
13035
+ );
13036
+ const elapsedSeconds = timing.kind === "live" ? liveElapsedSeconds ?? 0 : timing.elapsedSeconds;
13037
+ return /* @__PURE__ */ jsx64("span", { children: translateDuration(t, timing.kind, elapsedSeconds) });
13038
+ }
13039
+ function translateDuration(t, kind, elapsedSeconds) {
13040
+ const duration = formatAgentTurnDuration(elapsedSeconds);
13041
+ return kind === "live" ? translateLiveDuration(t, duration) : translateSettledDuration(t, duration);
13042
+ }
13043
+ function translateLiveDuration(t, duration) {
13044
+ if (duration.kind === "seconds") {
13045
+ return t("agentHost.agentGui.turnProcessedSeconds", {
13046
+ seconds: duration.seconds
13047
+ });
13048
+ }
13049
+ if (duration.kind === "minutes") {
13050
+ return t("agentHost.agentGui.turnProcessedMinutes", {
13051
+ minutes: duration.minutes
13052
+ });
13053
+ }
13054
+ return t("agentHost.agentGui.turnProcessedMinutesSeconds", {
13055
+ minutes: duration.minutes,
13056
+ seconds: duration.seconds
13057
+ });
13058
+ }
13059
+ function translateSettledDuration(t, duration) {
13060
+ if (duration.kind === "seconds") {
13061
+ return t("agentHost.agentGui.turnTotalSeconds", {
13062
+ seconds: duration.seconds
13063
+ });
13064
+ }
13065
+ if (duration.kind === "minutes") {
13066
+ return t("agentHost.agentGui.turnTotalMinutes", {
13067
+ minutes: duration.minutes
13068
+ });
13069
+ }
13070
+ return t("agentHost.agentGui.turnTotalMinutesSeconds", {
13071
+ minutes: duration.minutes,
13072
+ seconds: duration.seconds
13073
+ });
13074
+ }
13075
+
12719
13076
  // shared/agentConversation/components/agentTranscriptComplexity.ts
12720
13077
  var AGENT_TRANSCRIPT_COMPLEXITY_VIRTUALIZATION_SCORE = 40;
12721
13078
  var AGENT_TRANSCRIPT_COMPLEXITY_SINGLE_TURN_SCORE = 24;
@@ -12842,10 +13199,10 @@ function looksLikeTableSeparator(line) {
12842
13199
 
12843
13200
  // shared/agentConversation/components/AgentMessageLocatorRail.tsx
12844
13201
  import {
12845
- useEffect as useEffect12,
13202
+ useEffect as useEffect13,
12846
13203
  useLayoutEffect as useLayoutEffect3,
12847
13204
  useRef as useRef9,
12848
- useState as useState20
13205
+ useState as useState22
12849
13206
  } from "react";
12850
13207
 
12851
13208
  // shared/agentConversation/components/agentTranscriptModel.ts
@@ -12978,7 +13335,7 @@ function findTurnDividerRowIndexes(turnIndexById, rows) {
12978
13335
  }
12979
13336
 
12980
13337
  // shared/agentConversation/components/AgentMessageLocatorRail.tsx
12981
- import { jsx as jsx63, jsxs as jsxs45 } from "react/jsx-runtime";
13338
+ import { jsx as jsx65, jsxs as jsxs46 } from "react/jsx-runtime";
12982
13339
  var AGENT_MESSAGE_LOCATOR_PANEL_FADE_MS = 160;
12983
13340
  var AGENT_MESSAGE_LOCATOR_ITEM_SPACING_PX = 30;
12984
13341
  var AGENT_MESSAGE_LOCATOR_HIT_SIZE_PX = 36;
@@ -12993,14 +13350,14 @@ function AgentMessageLocatorRail({
12993
13350
  const locatorRef = useRef9(null);
12994
13351
  const locatorViewportRef = useRef9(null);
12995
13352
  const closePanelTimeoutRef = useRef9(null);
12996
- const [isPanelOpen, setIsPanelOpen] = useState20(false);
12997
- const [shouldRenderPanel, setShouldRenderPanel] = useState20(false);
12998
- const [activeKey, setActiveKey] = useState20(null);
12999
- const [selectedKey, setSelectedKey] = useState20(null);
13353
+ const [isPanelOpen, setIsPanelOpen] = useState22(false);
13354
+ const [shouldRenderPanel, setShouldRenderPanel] = useState22(false);
13355
+ const [activeKey, setActiveKey] = useState22(null);
13356
+ const [selectedKey, setSelectedKey] = useState22(null);
13000
13357
  const previousAgentResponseByKeyRef = useRef9(null);
13001
- const [unreadAgentResponseKeys, setUnreadAgentResponseKeys] = useState20(/* @__PURE__ */ new Set());
13002
- const [visibleFrame, setVisibleFrame] = useState20(null);
13003
- useEffect12(() => {
13358
+ const [unreadAgentResponseKeys, setUnreadAgentResponseKeys] = useState22(/* @__PURE__ */ new Set());
13359
+ const [visibleFrame, setVisibleFrame] = useState22(null);
13360
+ useEffect13(() => {
13004
13361
  if (isPanelOpen) {
13005
13362
  setShouldRenderPanel(true);
13006
13363
  return;
@@ -13011,7 +13368,7 @@ function AgentMessageLocatorRail({
13011
13368
  );
13012
13369
  return () => window.clearTimeout(timeout);
13013
13370
  }, [isPanelOpen]);
13014
- useEffect12(
13371
+ useEffect13(
13015
13372
  () => () => {
13016
13373
  if (closePanelTimeoutRef.current !== null) {
13017
13374
  window.clearTimeout(closePanelTimeoutRef.current);
@@ -13019,12 +13376,12 @@ function AgentMessageLocatorRail({
13019
13376
  },
13020
13377
  []
13021
13378
  );
13022
- useEffect12(() => {
13379
+ useEffect13(() => {
13023
13380
  if (selectedKey && !items.some((item) => item.key === selectedKey)) {
13024
13381
  setSelectedKey(null);
13025
13382
  }
13026
13383
  }, [items, selectedKey]);
13027
- useEffect12(() => {
13384
+ useEffect13(() => {
13028
13385
  const previousAgentResponseByKey = previousAgentResponseByKeyRef.current;
13029
13386
  const currentKeys = new Set(items.map((item) => item.key));
13030
13387
  setUnreadAgentResponseKeys((currentUnreadKeys) => {
@@ -13054,7 +13411,7 @@ function AgentMessageLocatorRail({
13054
13411
  items.map((item) => [item.key, item.hasAgentResponse])
13055
13412
  );
13056
13413
  }, [items, selectedKey]);
13057
- useEffect12(() => {
13414
+ useEffect13(() => {
13058
13415
  if (!selectedKey) {
13059
13416
  return;
13060
13417
  }
@@ -13099,7 +13456,7 @@ function AgentMessageLocatorRail({
13099
13456
  }
13100
13457
  };
13101
13458
  }, [items.length]);
13102
- useEffect12(() => {
13459
+ useEffect13(() => {
13103
13460
  const locator = locatorRef.current;
13104
13461
  const scrollParent = locator ? findMessageLocatorScrollParent(locator) : null;
13105
13462
  if (!scrollParent) {
@@ -13226,7 +13583,7 @@ function AgentMessageLocatorRail({
13226
13583
  }
13227
13584
  closePanelNow();
13228
13585
  };
13229
- return /* @__PURE__ */ jsxs45(
13586
+ return /* @__PURE__ */ jsxs46(
13230
13587
  "nav",
13231
13588
  {
13232
13589
  ref: locatorRef,
@@ -13246,7 +13603,7 @@ function AgentMessageLocatorRail({
13246
13603
  } : {}
13247
13604
  },
13248
13605
  children: [
13249
- /* @__PURE__ */ jsx63(
13606
+ /* @__PURE__ */ jsx65(
13250
13607
  "div",
13251
13608
  {
13252
13609
  ref: locatorViewportRef,
@@ -13254,7 +13611,7 @@ function AgentMessageLocatorRail({
13254
13611
  "data-testid": "agent-message-locator-viewport",
13255
13612
  onClick: handleViewportClick,
13256
13613
  onMouseMove: handleViewportMouseMove,
13257
- children: /* @__PURE__ */ jsxs45(
13614
+ children: /* @__PURE__ */ jsxs46(
13258
13615
  "div",
13259
13616
  {
13260
13617
  className: "agent-gui-message-locator__content",
@@ -13262,7 +13619,7 @@ function AgentMessageLocatorRail({
13262
13619
  "--agent-message-locator-height": `${railHeight}px`
13263
13620
  },
13264
13621
  children: [
13265
- items.slice(0, -1).map((item, index) => /* @__PURE__ */ jsx63(
13622
+ items.slice(0, -1).map((item, index) => /* @__PURE__ */ jsx65(
13266
13623
  "div",
13267
13624
  {
13268
13625
  className: "agent-gui-message-locator__track-segment",
@@ -13273,7 +13630,7 @@ function AgentMessageLocatorRail({
13273
13630
  },
13274
13631
  `segment:${item.key}`
13275
13632
  )),
13276
- items.map((item, index) => /* @__PURE__ */ jsx63(
13633
+ items.map((item, index) => /* @__PURE__ */ jsx65(
13277
13634
  "button",
13278
13635
  {
13279
13636
  type: "button",
@@ -13288,7 +13645,7 @@ function AgentMessageLocatorRail({
13288
13645
  onClick: () => handleLocateItem(item),
13289
13646
  onFocus: () => setActiveKey(item.key),
13290
13647
  onMouseEnter: () => setActiveKey(item.key),
13291
- children: /* @__PURE__ */ jsx63(
13648
+ children: /* @__PURE__ */ jsx65(
13292
13649
  "span",
13293
13650
  {
13294
13651
  className: "agent-gui-message-locator__dot",
@@ -13303,7 +13660,7 @@ function AgentMessageLocatorRail({
13303
13660
  )
13304
13661
  }
13305
13662
  ),
13306
- shouldRenderPanel ? /* @__PURE__ */ jsx63(
13663
+ shouldRenderPanel ? /* @__PURE__ */ jsx65(
13307
13664
  "div",
13308
13665
  {
13309
13666
  className: "agent-gui-message-locator__panel",
@@ -13313,7 +13670,7 @@ function AgentMessageLocatorRail({
13313
13670
  onMouseEnter: openPanel,
13314
13671
  onMouseLeave: closePanelSoon,
13315
13672
  onWheel: containMessageLocatorPanelWheel,
13316
- children: items.map((item) => /* @__PURE__ */ jsx63(
13673
+ children: items.map((item) => /* @__PURE__ */ jsx65(
13317
13674
  "button",
13318
13675
  {
13319
13676
  type: "button",
@@ -13322,7 +13679,7 @@ function AgentMessageLocatorRail({
13322
13679
  onClick: () => handleLocateItem(item),
13323
13680
  onFocus: () => setActiveKey(item.key),
13324
13681
  onMouseEnter: () => setActiveKey(item.key),
13325
- children: /* @__PURE__ */ jsx63("span", { className: "agent-gui-message-locator__panel-item-text", children: item.summary })
13682
+ children: /* @__PURE__ */ jsx65("span", { className: "agent-gui-message-locator__panel-item-text", children: item.summary })
13326
13683
  },
13327
13684
  `panel:${item.key}`
13328
13685
  ))
@@ -13465,10 +13822,11 @@ function selectMessageLocatorItemAtViewportCenter(scrollParent, items) {
13465
13822
  }
13466
13823
 
13467
13824
  // shared/agentConversation/components/AgentTranscriptView.tsx
13468
- import { Fragment as Fragment8, jsx as jsx64, jsxs as jsxs46 } from "react/jsx-runtime";
13825
+ import { Fragment as Fragment8, jsx as jsx66, jsxs as jsxs47 } from "react/jsx-runtime";
13469
13826
  var AGENT_TRANSCRIPT_VIRTUALIZATION_OVERSCAN = 6;
13470
13827
  var AGENT_TRANSCRIPT_ESTIMATED_TURN_HEIGHT_PX = 280;
13471
- var AGENT_TRANSCRIPT_TURN_GAP_PX = 12;
13828
+ var AGENT_TRANSCRIPT_DISCLOSURE_TURN_GAP_PX = 24;
13829
+ var AGENT_TRANSCRIPT_LEGACY_TURN_GAP_PX = 12;
13472
13830
  var AGENT_TRANSCRIPT_FALLBACK_TURN_COUNT = 3;
13473
13831
  function transcriptLabelsEqual(previous, next) {
13474
13832
  return previous === next || previous.thinkingLabel === next.thinkingLabel && previous.processing === next.processing && previous.turnSummary === next.turnSummary && previous.rawTimelineJson === next.rawTimelineJson && previous.userMessageLocator === next.userMessageLocator && previous.toolCallsLabel === next.toolCallsLabel;
@@ -13476,10 +13834,19 @@ function transcriptLabelsEqual(previous, next) {
13476
13834
  function transcriptTurnIdentityEquals(previous, next) {
13477
13835
  return previous === next || previous.length === next.length && previous.every((turn, index) => turn.id === next[index]?.id);
13478
13836
  }
13837
+ function transcriptCanonicalTurnsEqual(previous, next) {
13838
+ return previous === next || previous?.length === next?.length && (previous?.every((turn, index) => {
13839
+ const nextTurn = next?.[index];
13840
+ return turn.turnId === nextTurn?.turnId && turn.phase === nextTurn.phase && turn.outcome === nextTurn.outcome && turn.startedAtUnixMs === nextTurn.startedAtUnixMs && turn.settledAtUnixMs === nextTurn.settledAtUnixMs;
13841
+ }) ?? true);
13842
+ }
13479
13843
  function transcriptConversationRenderInputEquals(previous, next) {
13480
- return previous === next || previous.rows === next.rows && previous.workspaceRoot === next.workspaceRoot && previous.sourceDetail.cwd === next.sourceDetail.cwd && transcriptTurnIdentityEquals(
13844
+ return previous === next || previous.rows === next.rows && previous.workspaceRoot === next.workspaceRoot && previous.sourceDetail.session.agentSessionId === next.sourceDetail.session.agentSessionId && previous.sourceDetail.session.activeTurnId === next.sourceDetail.session.activeTurnId && previous.sourceDetail.cwd === next.sourceDetail.cwd && transcriptTurnIdentityEquals(
13481
13845
  previous.sourceDetail.turns,
13482
13846
  next.sourceDetail.turns
13847
+ ) && transcriptCanonicalTurnsEqual(
13848
+ previous.sourceDetail.sessionTurns,
13849
+ next.sourceDetail.sessionTurns
13483
13850
  );
13484
13851
  }
13485
13852
  function areAgentTranscriptViewPropsEqual(previous, next) {
@@ -13499,22 +13866,23 @@ var AgentTranscriptView = memo4(function AgentTranscriptView2({
13499
13866
  labels
13500
13867
  }) {
13501
13868
  "use memo";
13502
- const [expandedToolRows, setExpandedToolRows] = useState21({});
13869
+ const [expandedToolRows, setExpandedToolRows] = useState23({});
13870
+ const turnDisclosureStore = useAgentTurnDisclosureStore();
13503
13871
  const virtualizerHostRef = useRef10(null);
13504
- const [virtualScrollElement, setVirtualScrollElement] = useState21(null);
13505
- const rowKeys = useMemo6(
13872
+ const [virtualScrollElement, setVirtualScrollElement] = useState23(null);
13873
+ const rowKeys = useMemo7(
13506
13874
  () => conversation.rows.map(transcriptRowKey),
13507
13875
  [conversation.rows]
13508
13876
  );
13509
- const turnGroups = useMemo6(
13877
+ const turnGroups = useMemo7(
13510
13878
  () => buildAgentTranscriptTurnGroups(conversation.rows, rowKeys),
13511
13879
  [conversation.rows, rowKeys]
13512
13880
  );
13513
- const turnGroupIndexByRowIndex = useMemo6(
13881
+ const turnGroupIndexByRowIndex = useMemo7(
13514
13882
  () => buildTurnGroupIndexByRowIndex(turnGroups),
13515
13883
  [turnGroups]
13516
13884
  );
13517
- const userMessageLocatorItems = useMemo6(
13885
+ const userMessageLocatorItems = useMemo7(
13518
13886
  () => buildUserMessageLocatorItems(
13519
13887
  conversation.rows,
13520
13888
  rowKeys,
@@ -13523,7 +13891,7 @@ var AgentTranscriptView = memo4(function AgentTranscriptView2({
13523
13891
  [conversation.rows, rowKeys, turnGroupIndexByRowIndex]
13524
13892
  );
13525
13893
  const enteringRowKeys = useEnteringTranscriptRows(rowKeys);
13526
- const handleToolGroupExpandedChange = useCallback10(
13894
+ const handleToolGroupExpandedChange = useCallback11(
13527
13895
  (key, expanded) => {
13528
13896
  setExpandedToolRows((previous) => {
13529
13897
  if (previous[key] === expanded) {
@@ -13537,20 +13905,39 @@ var AgentTranscriptView = memo4(function AgentTranscriptView2({
13537
13905
  },
13538
13906
  []
13539
13907
  );
13540
- const turnIndexById = useMemo6(
13908
+ const turnIndexById = useMemo7(
13541
13909
  () => new Map(
13542
13910
  conversation.sourceDetail.turns.map((turn, index) => [turn.id, index])
13543
13911
  ),
13544
13912
  [conversation.sourceDetail.turns]
13545
13913
  );
13546
- const dividerRowIndexes = useMemo6(
13914
+ const dividerRowIndexes = useMemo7(
13547
13915
  () => findTurnDividerRowIndexes(turnIndexById, conversation.rows),
13548
13916
  [conversation.rows, turnIndexById]
13549
13917
  );
13918
+ const canonicalTurnById = new Map(
13919
+ (conversation.sourceDetail.sessionTurns ?? []).map((turn) => [
13920
+ turn.turnId,
13921
+ turn
13922
+ ])
13923
+ );
13924
+ const turnWorkSectionModelByKey = new Map(
13925
+ turnGroups.map((group) => {
13926
+ const isActiveTurn = group.turnId !== null && group.turnId === conversation.sourceDetail.session.activeTurnId;
13927
+ return [
13928
+ group.key,
13929
+ buildAgentTurnWorkSectionModel(
13930
+ group,
13931
+ group.turnId ? canonicalTurnById.get(group.turnId) ?? null : null,
13932
+ isActiveTurn
13933
+ )
13934
+ ];
13935
+ })
13936
+ );
13550
13937
  const basePath = conversation.sourceDetail.cwd;
13551
13938
  const workspaceRoot = conversation.workspaceRoot;
13552
13939
  const provider = conversation.activity.agentProvider;
13553
- const shouldVirtualize = useMemo6(
13940
+ const shouldVirtualize = useMemo7(
13554
13941
  () => assessAgentTranscriptComplexity(turnGroups).shouldVirtualize,
13555
13942
  [turnGroups]
13556
13943
  );
@@ -13563,7 +13950,7 @@ var AgentTranscriptView = memo4(function AgentTranscriptView2({
13563
13950
  overscan: AGENT_TRANSCRIPT_VIRTUALIZATION_OVERSCAN,
13564
13951
  scrollEndThreshold: 24
13565
13952
  });
13566
- const handleLocateUserMessage = useCallback10(
13953
+ const handleLocateUserMessage = useCallback11(
13567
13954
  (item) => {
13568
13955
  const scrollParent = virtualizerHostRef.current ? findMessageLocatorScrollParent(virtualizerHostRef.current) : null;
13569
13956
  const scrollToRenderedRow = () => {
@@ -13599,12 +13986,44 @@ var AgentTranscriptView = memo4(function AgentTranscriptView2({
13599
13986
  virtualizerHostRef.current ? findMessageLocatorScrollParent(virtualizerHostRef.current) : null
13600
13987
  );
13601
13988
  }, [shouldVirtualize]);
13602
- const renderRow = (row, rowIndex) => {
13603
- const rowKey = rowKeys[rowIndex] ?? transcriptRowKey(row);
13604
- const showTurnDivider = dividerRowIndexes.has(rowIndex);
13989
+ const renderRow = (row, rowIndex, renderKey) => {
13990
+ const rowKey = renderKey ?? (conversation.rows[rowIndex] === row ? rowKeys[rowIndex] ?? transcriptRowKey(row) : transcriptRowKey(row));
13605
13991
  const shouldAnimateEnter = row.kind !== "processing" && enteringRowKeys.has(rowKey);
13606
- return /* @__PURE__ */ jsxs46(Fragment7, { children: [
13607
- showTurnDivider ? /* @__PURE__ */ jsx64(
13992
+ return /* @__PURE__ */ jsx66(
13993
+ "div",
13994
+ {
13995
+ className: "agent-gui-transcript-row",
13996
+ "data-agent-transcript-row": rowKey,
13997
+ "data-agent-transcript-row-kind": row.kind,
13998
+ "data-agent-transcript-row-index": rowIndex,
13999
+ "data-agent-transcript-row-enter": shouldAnimateEnter ? "true" : void 0,
14000
+ children: /* @__PURE__ */ jsx66(
14001
+ AgentTranscriptItemView,
14002
+ {
14003
+ workspaceRoot,
14004
+ basePath,
14005
+ row,
14006
+ labels,
14007
+ onLinkAction,
14008
+ onAuthLogin,
14009
+ provider,
14010
+ availableSkills,
14011
+ workspaceAppIcons,
14012
+ previewMode,
14013
+ showRawTimelineJson,
14014
+ toolGroupExpanded: row.kind === "tool-group" ? expandedToolRows[rowKey] === true : void 0,
14015
+ toolGroupExpansionKey: row.kind === "tool-group" ? rowKey : void 0,
14016
+ onToolGroupExpandedChange: handleToolGroupExpandedChange
14017
+ }
14018
+ )
14019
+ },
14020
+ rowKey
14021
+ );
14022
+ };
14023
+ const renderLegacyTurnGroup = (group) => /* @__PURE__ */ jsx66(Fragment7, { children: group.rows.map(({ row, rowIndex }) => {
14024
+ const rowKey = rowKeys[rowIndex] ?? transcriptRowKey(row);
14025
+ return /* @__PURE__ */ jsxs47(Fragment7, { children: [
14026
+ dividerRowIndexes.has(rowIndex) ? /* @__PURE__ */ jsx66(
13608
14027
  "div",
13609
14028
  {
13610
14029
  className: "h-px w-full flex-none bg-[var(--line-2,var(--tutti-line-2))]",
@@ -13612,36 +14031,28 @@ var AgentTranscriptView = memo4(function AgentTranscriptView2({
13612
14031
  "aria-hidden": "true"
13613
14032
  }
13614
14033
  ) : null,
13615
- /* @__PURE__ */ jsx64(
13616
- "div",
13617
- {
13618
- className: "agent-gui-transcript-row",
13619
- "data-agent-transcript-row": rowKey,
13620
- "data-agent-transcript-row-kind": row.kind,
13621
- "data-agent-transcript-row-index": rowIndex,
13622
- "data-agent-transcript-row-enter": shouldAnimateEnter ? "true" : void 0,
13623
- children: /* @__PURE__ */ jsx64(
13624
- AgentTranscriptItemView,
13625
- {
13626
- workspaceRoot,
13627
- basePath,
13628
- row,
13629
- labels,
13630
- onLinkAction,
13631
- onAuthLogin,
13632
- provider,
13633
- availableSkills,
13634
- workspaceAppIcons,
13635
- previewMode,
13636
- showRawTimelineJson,
13637
- toolGroupExpanded: row.kind === "tool-group" ? expandedToolRows[rowKey] === true : void 0,
13638
- toolGroupExpansionKey: row.kind === "tool-group" ? rowKey : void 0,
13639
- onToolGroupExpandedChange: handleToolGroupExpandedChange
13640
- }
13641
- )
13642
- }
13643
- )
14034
+ renderRow(row, rowIndex)
13644
14035
  ] }, rowKey);
14036
+ }) }, group.key);
14037
+ const renderTurnGroup = (group) => {
14038
+ const model = turnWorkSectionModelByKey.get(group.key) ?? null;
14039
+ if (!model) {
14040
+ return renderLegacyTurnGroup(group);
14041
+ }
14042
+ return /* @__PURE__ */ jsx66(
14043
+ AgentTurnWorkSection,
14044
+ {
14045
+ model,
14046
+ sessionId: conversation.sourceDetail.session.agentSessionId,
14047
+ turnKey: group.turnId ?? group.key,
14048
+ showDivider: group.rows.some(
14049
+ ({ rowIndex }) => dividerRowIndexes.has(rowIndex)
14050
+ ),
14051
+ disclosureStore: turnDisclosureStore,
14052
+ renderRow
14053
+ },
14054
+ group.key
14055
+ );
13645
14056
  };
13646
14057
  if (shouldVirtualize) {
13647
14058
  const virtualItems = virtualScrollElement === null ? turnGroups.slice(-AGENT_TRANSCRIPT_FALLBACK_TURN_COUNT).map((group, fallbackIndex) => ({
@@ -13655,8 +14066,8 @@ var AgentTranscriptView = memo4(function AgentTranscriptView2({
13655
14066
  AGENT_TRANSCRIPT_FALLBACK_TURN_COUNT
13656
14067
  ) + fallbackIndex) * AGENT_TRANSCRIPT_ESTIMATED_TURN_HEIGHT_PX
13657
14068
  })) : rowVirtualizer.getVirtualItems();
13658
- return /* @__PURE__ */ jsxs46(Fragment8, { children: [
13659
- /* @__PURE__ */ jsx64(
14069
+ return /* @__PURE__ */ jsxs47(Fragment8, { children: [
14070
+ /* @__PURE__ */ jsx66(
13660
14071
  AgentMessageLocatorRail,
13661
14072
  {
13662
14073
  items: userMessageLocatorItems,
@@ -13664,7 +14075,7 @@ var AgentTranscriptView = memo4(function AgentTranscriptView2({
13664
14075
  onLocate: handleLocateUserMessage
13665
14076
  }
13666
14077
  ),
13667
- /* @__PURE__ */ jsx64(
14078
+ /* @__PURE__ */ jsx66(
13668
14079
  "div",
13669
14080
  {
13670
14081
  ref: virtualizerHostRef,
@@ -13676,7 +14087,7 @@ var AgentTranscriptView = memo4(function AgentTranscriptView2({
13676
14087
  if (!group) {
13677
14088
  return null;
13678
14089
  }
13679
- return /* @__PURE__ */ jsx64(
14090
+ return /* @__PURE__ */ jsx66(
13680
14091
  "div",
13681
14092
  {
13682
14093
  ref: rowVirtualizer.measureElement,
@@ -13684,12 +14095,10 @@ var AgentTranscriptView = memo4(function AgentTranscriptView2({
13684
14095
  "data-index": virtualTurn.index,
13685
14096
  "data-agent-transcript-virtual-turn": group.key,
13686
14097
  style: {
13687
- paddingBottom: `${AGENT_TRANSCRIPT_TURN_GAP_PX}px`,
14098
+ paddingBottom: `${turnWorkSectionModelByKey.get(group.key) ? AGENT_TRANSCRIPT_DISCLOSURE_TURN_GAP_PX : AGENT_TRANSCRIPT_LEGACY_TURN_GAP_PX}px`,
13688
14099
  transform: `translateY(${virtualTurn.start}px)`
13689
14100
  },
13690
- children: group.rows.map(
13691
- ({ row, rowIndex }) => renderRow(row, rowIndex)
13692
- )
14101
+ children: renderTurnGroup(group)
13693
14102
  },
13694
14103
  virtualTurn.key
13695
14104
  );
@@ -13698,8 +14107,8 @@ var AgentTranscriptView = memo4(function AgentTranscriptView2({
13698
14107
  )
13699
14108
  ] });
13700
14109
  }
13701
- return /* @__PURE__ */ jsxs46(Fragment8, { children: [
13702
- /* @__PURE__ */ jsx64(
14110
+ return /* @__PURE__ */ jsxs47(Fragment8, { children: [
14111
+ /* @__PURE__ */ jsx66(
13703
14112
  AgentMessageLocatorRail,
13704
14113
  {
13705
14114
  items: userMessageLocatorItems,
@@ -13707,13 +14116,13 @@ var AgentTranscriptView = memo4(function AgentTranscriptView2({
13707
14116
  onLocate: handleLocateUserMessage
13708
14117
  }
13709
14118
  ),
13710
- conversation.rows.map(renderRow)
14119
+ turnGroups.map(renderTurnGroup)
13711
14120
  ] });
13712
14121
  }, areAgentTranscriptViewPropsEqual);
13713
14122
 
13714
14123
  // shared/agentConversation/components/AgentConversationFlow.tsx
13715
14124
  import { memo as memo5 } from "react";
13716
- import { Fragment as Fragment9, jsx as jsx65 } from "react/jsx-runtime";
14125
+ import { Fragment as Fragment9, jsx as jsx67 } from "react/jsx-runtime";
13717
14126
  var AgentConversationFlow = memo5(function AgentConversationFlow2({
13718
14127
  conversation,
13719
14128
  isLoading,
@@ -13729,36 +14138,38 @@ var AgentConversationFlow = memo5(function AgentConversationFlow2({
13729
14138
  labels
13730
14139
  }) {
13731
14140
  "use memo";
14141
+ let content;
13732
14142
  if (isLoading) {
13733
- return /* @__PURE__ */ jsx65(AgentTranscriptSkeleton, { label: loadingLabel, testId: loadingTestId });
13734
- }
13735
- if (!conversation || conversation.rows.length === 0) {
13736
- return /* @__PURE__ */ jsx65(Fragment9, { children: empty });
14143
+ content = /* @__PURE__ */ jsx67(AgentTranscriptSkeleton, { label: loadingLabel, testId: loadingTestId });
14144
+ } else if (!conversation || conversation.rows.length === 0) {
14145
+ content = /* @__PURE__ */ jsx67(Fragment9, { children: empty });
14146
+ } else {
14147
+ content = /* @__PURE__ */ jsx67(
14148
+ AgentTranscriptView,
14149
+ {
14150
+ conversation,
14151
+ onLinkAction,
14152
+ onAuthLogin,
14153
+ availableSkills,
14154
+ workspaceAppIcons,
14155
+ previewMode,
14156
+ labels,
14157
+ showRawTimelineJson
14158
+ }
14159
+ );
13737
14160
  }
13738
- return /* @__PURE__ */ jsx65(
13739
- AgentTranscriptView,
13740
- {
13741
- conversation,
13742
- onLinkAction,
13743
- onAuthLogin,
13744
- availableSkills,
13745
- workspaceAppIcons,
13746
- previewMode,
13747
- labels,
13748
- showRawTimelineJson
13749
- }
13750
- );
14161
+ return /* @__PURE__ */ jsx67(AgentTurnDisclosureProvider, { children: content });
13751
14162
  });
13752
14163
 
13753
14164
  // shared/agentConversation/projection/useProjectedAgentConversation.ts
13754
- import { useMemo as useMemo7, useRef as useRef11 } from "react";
14165
+ import { useMemo as useMemo8, useRef as useRef11 } from "react";
13755
14166
  function useProjectedAgentConversation({
13756
14167
  conversation,
13757
14168
  detail,
13758
14169
  avoidGroupingEdits = false
13759
14170
  }) {
13760
14171
  const previousConversationRef = useRef11(null);
13761
- return useMemo7(() => {
14172
+ return useMemo8(() => {
13762
14173
  if (!conversation && !detail) {
13763
14174
  previousConversationRef.current = null;
13764
14175
  return null;
@@ -13813,4 +14224,4 @@ export {
13813
14224
  AgentConversationFlow,
13814
14225
  useProjectedAgentConversation
13815
14226
  };
13816
- //# sourceMappingURL=chunk-HHQTW2VC.js.map
14227
+ //# sourceMappingURL=chunk-EM4RD5FQ.js.map