langchain_agentx_stream_ui 0.4.2 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -23,7 +23,7 @@ import {
23
23
  fixDiagramSvg,
24
24
  markEventIdSeen,
25
25
  shouldSkipDuplicateEvent
26
- } from "./chunk-7X7IF2A4.js";
26
+ } from "./chunk-ME5T6YSV.js";
27
27
  import {
28
28
  DefaultToolBody,
29
29
  InteractionBusContext,
@@ -32,8 +32,8 @@ import {
32
32
  getNoopInteractionBus,
33
33
  resolveToolBody,
34
34
  useInteractionBus
35
- } from "./chunk-MRGHYRSV.js";
36
- import "./chunk-DP7V33X7.js";
35
+ } from "./chunk-TCKOXX7O.js";
36
+ import "./chunk-6Z4ZF36Z.js";
37
37
  import {
38
38
  CollapseKind,
39
39
  CollapsedExploreNode,
@@ -119,7 +119,7 @@ import {
119
119
  useSessionStatus,
120
120
  useSessionViewOptions,
121
121
  useTimeline
122
- } from "./chunk-AY7QLXFB.js";
122
+ } from "./chunk-JAOJAGMM.js";
123
123
  import {
124
124
  Agent,
125
125
  AgentToolBody,
@@ -147,7 +147,7 @@ import {
147
147
  createDefaultToolRegistry,
148
148
  formatAgentTitle,
149
149
  formatExploreSummaryText
150
- } from "./chunk-QL3DIGFI.js";
150
+ } from "./chunk-FL2G7SV3.js";
151
151
  import {
152
152
  BodyBlockList,
153
153
  DiffView,
@@ -163,7 +163,7 @@ import {
163
163
  formatTimeoutFooter,
164
164
  parseDiffText,
165
165
  truncateCommand
166
- } from "./chunk-4RIOBLGB.js";
166
+ } from "./chunk-GBY5DJ7L.js";
167
167
 
168
168
  // src/view/AgentSession.tsx
169
169
  import { useEffect as useEffect3, useMemo, useRef as useRef3 } from "react";
@@ -740,6 +740,32 @@ function mergeRuntimeContainerNodes(prev, snapshot) {
740
740
  }
741
741
 
742
742
  // src/core/workflow/hydrateWorkflowSnapshot.ts
743
+ function resolveStageDoneSummariesFromSnapshot(snapshot, containersById) {
744
+ if (!snapshot.loopSummaries?.length) {
745
+ return {};
746
+ }
747
+ const containerIdByLoopSessionId = /* @__PURE__ */ new Map();
748
+ for (const [containerId, node] of Object.entries(containersById)) {
749
+ const loopSessionId = node.loopSessionId;
750
+ if (loopSessionId) {
751
+ containerIdByLoopSessionId.set(loopSessionId, containerId);
752
+ }
753
+ }
754
+ const out = {};
755
+ for (const summary of snapshot.loopSummaries) {
756
+ const containerId = containerIdByLoopSessionId.get(summary.loopSessionId);
757
+ if (!containerId) {
758
+ continue;
759
+ }
760
+ const node = containersById[containerId];
761
+ out[containerId] = {
762
+ label: summary.label ?? node?.title ?? "",
763
+ teaser: summary.teaser ?? "",
764
+ extraLines: 0
765
+ };
766
+ }
767
+ return out;
768
+ }
743
769
  function isAtOrBeforeProjectionCursor(projectionCursor, eventId) {
744
770
  if (!projectionCursor || !eventId) return false;
745
771
  const parseSeq = (id) => {
@@ -761,6 +787,10 @@ function hydrateWorkflowFromSnapshot(state, snapshot, options = {}) {
761
787
  containerTree.containersById = normalizeSnapshotContainerContentBlocks(
762
788
  sanitizeContainerTreeParentLinks(containerTree.containersById)
763
789
  );
790
+ const stageDoneSummariesByContainerId = resolveStageDoneSummariesFromSnapshot(
791
+ snapshot,
792
+ containerTree.containersById
793
+ );
764
794
  return {
765
795
  ...createEmptyWorkflowSessionState(),
766
796
  authority,
@@ -771,6 +801,7 @@ function hydrateWorkflowFromSnapshot(state, snapshot, options = {}) {
771
801
  containerTree,
772
802
  projectionCursor: snapshot.cursor,
773
803
  snapshotVersion: snapshot.snapshotVersion,
804
+ stageDoneSummariesByContainerId,
774
805
  meta: {
775
806
  ...state.meta,
776
807
  workflowRunId: snapshot.taskId,
@@ -1725,24 +1756,8 @@ function useWorkflowSessionStatus() {
1725
1756
  return useStore2(store, (s) => getDisplayProjectionStatus(s.state));
1726
1757
  }
1727
1758
 
1728
- // src/core/context/WorkflowLoopReplayContext.tsx
1729
- import { createContext as createContext2, useContext as useContext2 } from "react";
1730
- import { jsx as jsx5 } from "react/jsx-runtime";
1731
- var WorkflowLoopReplayContext = createContext2(
1732
- void 0
1733
- );
1734
- function WorkflowLoopReplayProvider({
1735
- onRequestLoopReplay,
1736
- children
1737
- }) {
1738
- return /* @__PURE__ */ jsx5(WorkflowLoopReplayContext.Provider, { value: onRequestLoopReplay, children });
1739
- }
1740
- function useWorkflowLoopReplayHandler() {
1741
- return useContext2(WorkflowLoopReplayContext);
1742
- }
1743
-
1744
1759
  // src/core/context/WorkflowScaleContext.tsx
1745
- import { createContext as createContext3, useContext as useContext3 } from "react";
1760
+ import { createContext as createContext2, useContext as useContext2 } from "react";
1746
1761
 
1747
1762
  // src/view/workflow/workflowScaleOptions.ts
1748
1763
  var DEFAULT_WORKFLOW_SCALE_OPTIONS = {
@@ -1751,15 +1766,37 @@ var DEFAULT_WORKFLOW_SCALE_OPTIONS = {
1751
1766
  evictCompletedLoops: true,
1752
1767
  onlyExpandActiveRunning: true,
1753
1768
  parallelItemVirtualizeThreshold: 40,
1754
- maxHydratedCompletedLoops: 4
1769
+ maxHydratedCompletedLoops: 4,
1770
+ softEvictThreshold: 4,
1771
+ containerCountTier2: 60,
1772
+ containerCountTier3: 120,
1773
+ tierEvalMinFrames: 30,
1774
+ hydrateChunkSize: 50,
1775
+ aggressiveMemoryTier3: true
1755
1776
  };
1777
+ function resolveWorkflowScale(storeOptions) {
1778
+ const scale = {
1779
+ ...DEFAULT_WORKFLOW_SCALE_OPTIONS,
1780
+ ...storeOptions?.workflowScale
1781
+ };
1782
+ if (storeOptions?.evictCompletedLoops !== void 0) {
1783
+ scale.evictCompletedLoops = storeOptions.evictCompletedLoops;
1784
+ }
1785
+ if (storeOptions?.maxHydratedCompletedLoops !== void 0) {
1786
+ scale.maxHydratedCompletedLoops = storeOptions.maxHydratedCompletedLoops;
1787
+ }
1788
+ scale.deferEvictionUntil ??= "immediate";
1789
+ scale.recentCompletedRetainCount ??= scale.softEvictThreshold;
1790
+ scale.protectExpandedLoops ??= false;
1791
+ return scale;
1792
+ }
1756
1793
 
1757
1794
  // src/core/context/WorkflowScaleContext.tsx
1758
- var WorkflowScaleContext = createContext3(
1795
+ var WorkflowScaleContext = createContext2(
1759
1796
  DEFAULT_WORKFLOW_SCALE_OPTIONS
1760
1797
  );
1761
1798
  function useWorkflowScaleOptions() {
1762
- return useContext3(WorkflowScaleContext);
1799
+ return useContext2(WorkflowScaleContext);
1763
1800
  }
1764
1801
 
1765
1802
  // src/core/workflowSessionStore.ts
@@ -1801,6 +1838,7 @@ function finalizeWorkflowLoopTree(tree, terminalStatus = "done") {
1801
1838
  }
1802
1839
 
1803
1840
  // src/core/workflow/stageDoneSummary.ts
1841
+ var WORKFLOW_STAGE_EMPTY_SUMMARY_HINT = "\uFF08\u6682\u65E0\u6B63\u6587\u6458\u8981\uFF09";
1804
1842
  function countToolUses(tree) {
1805
1843
  return Object.values(tree.byId).filter((node) => node.kind === "tool_call").length;
1806
1844
  }
@@ -1824,6 +1862,25 @@ function lastLoopTextContent(tree) {
1824
1862
  if (textNodes.length === 0) return "";
1825
1863
  return textNodes[textNodes.length - 1].accumulated.trim();
1826
1864
  }
1865
+ function lastLoopReasoningContent(tree) {
1866
+ const nodes = Object.values(tree.byId).filter((node) => node.kind === "reasoning");
1867
+ if (nodes.length === 0) return "";
1868
+ return nodes[nodes.length - 1].accumulated.trim();
1869
+ }
1870
+ function lastToolName(tree) {
1871
+ const tools = Object.values(tree.byId).filter((node) => node.kind === "tool_call");
1872
+ if (tools.length === 0) return null;
1873
+ return tools[tools.length - 1].toolName ?? null;
1874
+ }
1875
+ function pickContentTeaser(tree) {
1876
+ const text = lastLoopTextContent(tree);
1877
+ if (text) return pickTeaserLine(text);
1878
+ const reasoning = lastLoopReasoningContent(tree);
1879
+ if (reasoning) return pickTeaserLine(reasoning);
1880
+ const toolName = lastToolName(tree);
1881
+ if (toolName) return `Used ${toolName}`;
1882
+ return "";
1883
+ }
1827
1884
  function pickTeaserLine(fullText) {
1828
1885
  const lines = fullText.split("\n").map((line) => line.trim()).filter(Boolean);
1829
1886
  if (lines.length === 0) return "";
@@ -1836,11 +1893,12 @@ function buildStageDoneSummary(tree) {
1836
1893
  const duration = computeDurationSeconds(tree);
1837
1894
  const durationSuffix = duration != null ? ` \xB7 ${duration}s` : "";
1838
1895
  const label = toolUses > 0 ? `Done (${toolUses} tool use${toolUses === 1 ? "" : "s"}${durationSuffix})` : `Done (1 agent turn${durationSuffix})`;
1839
- const fullText = lastLoopTextContent(tree);
1896
+ const teaser = pickContentTeaser(tree);
1897
+ const fullText = lastLoopTextContent(tree) || lastLoopReasoningContent(tree);
1840
1898
  const lines = fullText.split("\n").map((line) => line.trim()).filter(Boolean);
1841
- const teaser = pickTeaserLine(fullText);
1842
1899
  const extraLines = Math.max(0, lines.length - 1);
1843
- return { label, teaser, extraLines };
1900
+ const fullMarkdown = fullText.trim() || void 0;
1901
+ return { label, teaser, extraLines, ...fullMarkdown ? { fullMarkdown } : {} };
1844
1902
  }
1845
1903
  function formatTeaserExpandHint(extraLines, verbose) {
1846
1904
  if (extraLines <= 0) return null;
@@ -1946,6 +2004,12 @@ function evictCompletedLoopOverflow(state, maxHydratedCompletedLoops) {
1946
2004
  const tree = nextLoops[id];
1947
2005
  if (!tree) continue;
1948
2006
  const container = byLoop.get(id);
2007
+ if (container && (container.status === "running" || container.status === "retrying")) {
2008
+ if (!trimmedIds.includes(id)) {
2009
+ trimmedIds = [id, ...trimmedIds];
2010
+ }
2011
+ continue;
2012
+ }
1949
2013
  if (container && hasRunningParallelSibling(container, state.containerTree)) {
1950
2014
  if (!trimmedIds.includes(id)) {
1951
2015
  trimmedIds = [id, ...trimmedIds];
@@ -2037,6 +2101,10 @@ function isWorkflowStructureEventType(eventType) {
2037
2101
  if (WORKFLOW_STRUCTURE_EVENT_TYPES.has(eventType)) return true;
2038
2102
  return WORKFLOW_STRUCTURE_EVENT_PREFIXES.some((prefix) => eventType.startsWith(prefix));
2039
2103
  }
2104
+ function isWorkflowStructureCloseEventType(eventType) {
2105
+ if (!isWorkflowStructureEventType(eventType)) return false;
2106
+ return eventType.endsWith("-done") || eventType.endsWith("-failed") || eventType.endsWith("-end");
2107
+ }
2040
2108
  function isAgentLoopReplayEventType(eventType) {
2041
2109
  return AGENT_LOOP_REPLAY_EVENT_TYPES.has(eventType);
2042
2110
  }
@@ -3032,8 +3100,71 @@ function reduceWorkflowEvents(events, options) {
3032
3100
  );
3033
3101
  }
3034
3102
 
3103
+ // src/core/workflow/workflowMemoryPressureTier.ts
3104
+ function countCompletedLoops(state) {
3105
+ let count = 0;
3106
+ for (const node of Object.values(state.containerTree.containersById)) {
3107
+ if (!node.loopSessionId) continue;
3108
+ if (node.status === "completed" || node.status === "failed") {
3109
+ count += 1;
3110
+ }
3111
+ }
3112
+ return count;
3113
+ }
3114
+ function computeMemoryPressureTier(state, scale) {
3115
+ if (!scale.aggressiveMemoryTier3) {
3116
+ return { tier: 0, forceLruEviction: false };
3117
+ }
3118
+ const containerCount = Object.keys(state.containerTree.containersById).length;
3119
+ const hydratedLoopCount = Object.keys(state.loopTreesBySessionId).length;
3120
+ let tier = 0;
3121
+ if (containerCount > scale.containerCountTier3) {
3122
+ tier = 3;
3123
+ } else if (containerCount > scale.containerCountTier2) {
3124
+ tier = 2;
3125
+ } else if (countCompletedLoops(state) > scale.softEvictThreshold) {
3126
+ tier = 1;
3127
+ }
3128
+ const forceLruEviction = hydratedLoopCount > scale.maxHydratedCompletedLoops;
3129
+ return { tier, forceLruEviction };
3130
+ }
3131
+ function applyMemoryPressureTier(state, scale, ctx) {
3132
+ if (!scale.aggressiveMemoryTier3) {
3133
+ return { state, lastTierEvalFrame: ctx.lastTierEvalFrame };
3134
+ }
3135
+ if (!ctx.force && ctx.frameCounter - ctx.lastTierEvalFrame < scale.tierEvalMinFrames) {
3136
+ return { state, lastTierEvalFrame: ctx.lastTierEvalFrame };
3137
+ }
3138
+ const { tier, forceLruEviction } = computeMemoryPressureTier(state, scale);
3139
+ return {
3140
+ state: {
3141
+ ...state,
3142
+ meta: {
3143
+ ...state.meta,
3144
+ memoryPressureTier: tier,
3145
+ forceLruEviction
3146
+ }
3147
+ },
3148
+ lastTierEvalFrame: ctx.frameCounter
3149
+ };
3150
+ }
3151
+
3152
+ // src/core/workflow/workflowEvictionDefer.ts
3153
+ function shouldDeferEviction(state, scale, _ctx) {
3154
+ const mode = scale.deferEvictionUntil ?? "immediate";
3155
+ if (mode === "host-reset") return true;
3156
+ if (mode === "run-idle") return !state.display.streamEnded;
3157
+ return false;
3158
+ }
3159
+
3035
3160
  // src/core/workflowSessionStore.ts
3036
- var DEFAULT_HYDRATE_CHUNK_SIZE = 50;
3161
+ function resolveStoreWorkflowScale(storeOptions) {
3162
+ return resolveWorkflowScale({
3163
+ workflowScale: storeOptions?.workflowScale,
3164
+ evictCompletedLoops: storeOptions?.evictCompletedLoops,
3165
+ maxHydratedCompletedLoops: storeOptions?.maxHydratedCompletedLoops
3166
+ });
3167
+ }
3037
3168
  function nextAnimationFrame() {
3038
3169
  return new Promise((resolve) => {
3039
3170
  requestAnimationFrame(() => resolve());
@@ -3107,12 +3238,34 @@ function createWorkflowSessionStore(initialState = createEmptyWorkflowSessionSta
3107
3238
  };
3108
3239
  const initialEventCount = storeOptions?.initialEventCount ?? 0;
3109
3240
  const seenEventIds = new Set(storeOptions?.initialSeenEventIds);
3110
- const evictCompletedLoops = storeOptions?.evictCompletedLoops ?? true;
3111
- const maxHydratedCompletedLoops = storeOptions?.maxHydratedCompletedLoops ?? 4;
3241
+ const scale = resolveStoreWorkflowScale(storeOptions);
3112
3242
  const pinnedLoopSessionIds = {};
3113
- const finalizeState = (reduced) => {
3114
- if (!evictCompletedLoops) return reduced;
3115
- return evictInactiveLoopTrees(reduced, pinnedLoopSessionIds);
3243
+ let frameCounter = initialEventCount;
3244
+ let lastTierEvalFrame = 0;
3245
+ const finalizeState = (reduced, options) => {
3246
+ if (!scale.evictCompletedLoops) {
3247
+ return reduced;
3248
+ }
3249
+ frameCounter += 1;
3250
+ let next = reduced;
3251
+ ({ state: next, lastTierEvalFrame } = applyMemoryPressureTier(next, scale, {
3252
+ frameCounter,
3253
+ lastTierEvalFrame,
3254
+ force: options?.immediateTierEval
3255
+ }));
3256
+ if (shouldDeferEviction(next, scale, { immediateTierEval: options?.immediateTierEval })) {
3257
+ return next;
3258
+ }
3259
+ const tier = next.meta.memoryPressureTier ?? 0;
3260
+ const forceLru = next.meta.forceLruEviction ?? false;
3261
+ if (tier >= 1) {
3262
+ next = evictInactiveLoopTrees(next, pinnedLoopSessionIds);
3263
+ }
3264
+ if (tier >= 2 || forceLru) {
3265
+ const maxHydrated = tier >= 3 ? 0 : scale.maxHydratedCompletedLoops;
3266
+ next = evictCompletedLoopOverflow(next, maxHydrated);
3267
+ }
3268
+ return next;
3116
3269
  };
3117
3270
  return createStore2((set, get) => ({
3118
3271
  state: initialState,
@@ -3127,7 +3280,8 @@ function createWorkflowSessionStore(initialState = createEmptyWorkflowSessionSta
3127
3280
  }
3128
3281
  if (shouldSkipDuplicateEvent(seenEventIds, sseEventId)) return;
3129
3282
  const { state: reduced } = safeReduceWorkflow(state, event, eventCount, reduceOpts);
3130
- const evicted = finalizeState(reduced);
3283
+ const immediateTierEval = isWorkflowStructureCloseEventType(event.event_type);
3284
+ const evicted = finalizeState(reduced, { immediateTierEval });
3131
3285
  const nextMeta = sseEventId ? { ...evicted.meta, lastEventId: sseEventId } : evicted.meta;
3132
3286
  markEventIdSeen(seenEventIds, sseEventId);
3133
3287
  set({
@@ -3149,6 +3303,9 @@ function createWorkflowSessionStore(initialState = createEmptyWorkflowSessionSta
3149
3303
  },
3150
3304
  reset() {
3151
3305
  seenEventIds.clear();
3306
+ for (const loopSessionId of Object.keys(pinnedLoopSessionIds)) {
3307
+ delete pinnedLoopSessionIds[loopSessionId];
3308
+ }
3152
3309
  set({
3153
3310
  state: createEmptyWorkflowSessionState(),
3154
3311
  eventCount: 0,
@@ -3221,17 +3378,22 @@ function createWorkflowSessionStore(initialState = createEmptyWorkflowSessionSta
3221
3378
  }));
3222
3379
  },
3223
3380
  /**
3224
- * P2:将 completed loop 加入 LRU 热缓存并淘汰溢出。
3225
- * running 保护由 collectProtectedLoopSessionIds 按状态自动覆盖,不再依赖永久 pin。
3381
+ * P2 / D41 P2a:pin 保护 + LRU touch;completed loop 免于 Tier 1 evictInactive。
3226
3382
  */
3227
3383
  pinLoopSession(loopSessionId) {
3384
+ pinnedLoopSessionIds[loopSessionId] = true;
3228
3385
  set((current) => {
3229
3386
  let next = touchCompletedLoopSession(current.state, loopSessionId);
3230
- next = evictCompletedLoopOverflow(next, maxHydratedCompletedLoops);
3231
- next = finalizeState(next);
3387
+ next = finalizeState(next, { immediateTierEval: true });
3232
3388
  return { state: next };
3233
3389
  });
3234
3390
  },
3391
+ unpinLoopSession(loopSessionId) {
3392
+ delete pinnedLoopSessionIds[loopSessionId];
3393
+ set((current) => ({
3394
+ state: finalizeState(current.state, { immediateTierEval: true })
3395
+ }));
3396
+ },
3235
3397
  /**
3236
3398
  * P2:宿主 replay 后灌入 loop 树,touch LRU 并淘汰溢出。
3237
3399
  * completed loop 受 hotCompletedLoopSessionIds 保护,不再永久 pin。
@@ -3253,8 +3415,7 @@ function createWorkflowSessionStore(initialState = createEmptyWorkflowSessionSta
3253
3415
  }
3254
3416
  };
3255
3417
  next = touchCompletedLoopSession(next, loopSessionId);
3256
- next = evictCompletedLoopOverflow(next, maxHydratedCompletedLoops);
3257
- next = finalizeState(next);
3418
+ next = finalizeState(next, { immediateTierEval: true });
3258
3419
  return { state: next };
3259
3420
  });
3260
3421
  },
@@ -3263,7 +3424,7 @@ function createWorkflowSessionStore(initialState = createEmptyWorkflowSessionSta
3263
3424
  if (hydratingLoopSessionIds[loopSessionId]) return;
3264
3425
  const filtered = filterAgentLoopReplayEvents(events);
3265
3426
  if (filtered.length === 0) return;
3266
- const chunkSize = options?.chunkSize ?? DEFAULT_HYDRATE_CHUNK_SIZE;
3427
+ const chunkSize = options?.chunkSize ?? scale.hydrateChunkSize;
3267
3428
  const signal = options?.signal;
3268
3429
  set((current) => ({
3269
3430
  hydratingLoopSessionIds: {
@@ -3294,9 +3455,8 @@ function createWorkflowSessionStore(initialState = createEmptyWorkflowSessionSta
3294
3455
  };
3295
3456
  if (isLastChunk) {
3296
3457
  next = touchCompletedLoopSession(next, loopSessionId);
3297
- next = evictCompletedLoopOverflow(next, maxHydratedCompletedLoops);
3298
3458
  }
3299
- next = finalizeState(next);
3459
+ next = finalizeState(next, isLastChunk ? { immediateTierEval: true } : void 0);
3300
3460
  return { state: next };
3301
3461
  });
3302
3462
  if (!isLastChunk) {
@@ -3410,7 +3570,7 @@ import { useCallback, useEffect as useEffect6, useMemo as useMemo2, useState, me
3410
3570
  import { useStore as useStore3 } from "zustand";
3411
3571
 
3412
3572
  // src/view/workflow/WorkflowContainerLine.tsx
3413
- import { Fragment, jsx as jsx6, jsxs as jsxs2 } from "react/jsx-runtime";
3573
+ import { Fragment, jsx as jsx5, jsxs as jsxs2 } from "react/jsx-runtime";
3414
3574
  function WorkflowContainerLine({
3415
3575
  title,
3416
3576
  description,
@@ -3437,7 +3597,7 @@ function WorkflowContainerLine({
3437
3597
  className
3438
3598
  ].filter(Boolean).join(" ");
3439
3599
  const content = /* @__PURE__ */ jsxs2(Fragment, { children: [
3440
- showDot ? /* @__PURE__ */ jsx6(
3600
+ showDot ? /* @__PURE__ */ jsx5(
3441
3601
  "span",
3442
3602
  {
3443
3603
  className: "lax-workflow-container-line__status-dot lax-workflow-stage-container__status-dot",
@@ -3445,7 +3605,7 @@ function WorkflowContainerLine({
3445
3605
  "aria-hidden": true
3446
3606
  }
3447
3607
  ) : null,
3448
- /* @__PURE__ */ jsx6("span", { className: "lax-workflow-container-line__title", "data-testid": titleTestId, children: title }),
3608
+ /* @__PURE__ */ jsx5("span", { className: "lax-workflow-container-line__title", "data-testid": titleTestId, children: title }),
3449
3609
  description ? /* @__PURE__ */ jsxs2(
3450
3610
  "span",
3451
3611
  {
@@ -3458,12 +3618,12 @@ function WorkflowContainerLine({
3458
3618
  ]
3459
3619
  }
3460
3620
  ) : null,
3461
- meta.length > 0 ? /* @__PURE__ */ jsx6("span", { className: "lax-workflow-container-line__meta", "data-testid": titleTestId ? `${titleTestId}-meta` : void 0, children: meta.join(" \xB7 ") }) : null,
3462
- verbose && debugScopeKey ? /* @__PURE__ */ jsx6("span", { className: "lax-workflow-container-line__debug", "data-testid": "lax-workflow-id", children: debugScopeKey }) : null,
3463
- /* @__PURE__ */ jsx6("span", { className: "lax-workflow-container-line__status", children: statusLabel })
3621
+ meta.length > 0 ? /* @__PURE__ */ jsx5("span", { className: "lax-workflow-container-line__meta", "data-testid": titleTestId ? `${titleTestId}-meta` : void 0, children: meta.join(" \xB7 ") }) : null,
3622
+ verbose && debugScopeKey ? /* @__PURE__ */ jsx5("span", { className: "lax-workflow-container-line__debug", "data-testid": "lax-workflow-id", children: debugScopeKey }) : null,
3623
+ /* @__PURE__ */ jsx5("span", { className: "lax-workflow-container-line__status", children: statusLabel })
3464
3624
  ] });
3465
3625
  if (onToggle && interactive !== false) {
3466
- return /* @__PURE__ */ jsx6(
3626
+ return /* @__PURE__ */ jsx5(
3467
3627
  "button",
3468
3628
  {
3469
3629
  type: "button",
@@ -3477,7 +3637,7 @@ function WorkflowContainerLine({
3477
3637
  );
3478
3638
  }
3479
3639
  if (onToggle) {
3480
- return /* @__PURE__ */ jsx6(
3640
+ return /* @__PURE__ */ jsx5(
3481
3641
  "div",
3482
3642
  {
3483
3643
  className: `${lineClass} lax-workflow-container-line--static-toggle`,
@@ -3497,11 +3657,11 @@ function WorkflowContainerLine({
3497
3657
  }
3498
3658
  );
3499
3659
  }
3500
- return /* @__PURE__ */ jsx6("div", { className: lineClass, style, children: content });
3660
+ return /* @__PURE__ */ jsx5("div", { className: lineClass, style, children: content });
3501
3661
  }
3502
3662
 
3503
3663
  // src/view/workflow/WorkflowExpandTrigger.tsx
3504
- import { jsx as jsx7, jsxs as jsxs3 } from "react/jsx-runtime";
3664
+ import { jsx as jsx6, jsxs as jsxs3 } from "react/jsx-runtime";
3505
3665
  function WorkflowExpandTrigger({
3506
3666
  summary,
3507
3667
  summaryTestId,
@@ -3526,7 +3686,7 @@ function WorkflowExpandTrigger({
3526
3686
  "\u23BF ",
3527
3687
  summary
3528
3688
  ] }),
3529
- teaser ? /* @__PURE__ */ jsx7(
3689
+ teaser ? /* @__PURE__ */ jsx6(
3530
3690
  "span",
3531
3691
  {
3532
3692
  className: "lax-workflow-expand-trigger__teaser",
@@ -3534,21 +3694,21 @@ function WorkflowExpandTrigger({
3534
3694
  children: teaser
3535
3695
  }
3536
3696
  ) : null,
3537
- expandHint ? /* @__PURE__ */ jsx7("span", { className: "lax-workflow-expand-trigger__hint", children: expandHint }) : null
3697
+ expandHint ? /* @__PURE__ */ jsx6("span", { className: "lax-workflow-expand-trigger__hint", children: expandHint }) : null
3538
3698
  ]
3539
3699
  }
3540
3700
  );
3541
3701
  }
3542
3702
 
3543
3703
  // src/view/workflow/WorkflowMarkdownPreview.tsx
3544
- import { jsx as jsx8 } from "react/jsx-runtime";
3704
+ import { jsx as jsx7 } from "react/jsx-runtime";
3545
3705
  function WorkflowMarkdownPreview({
3546
3706
  content,
3547
3707
  testId,
3548
3708
  className = "lax-workflow-markdown-preview"
3549
3709
  }) {
3550
3710
  if (!content.trim()) return null;
3551
- return /* @__PURE__ */ jsx8("div", { className, "data-testid": testId, children: /* @__PURE__ */ jsx8(RichMarkdown, { content, deferDiagrams: true }) });
3711
+ return /* @__PURE__ */ jsx7("div", { className, "data-testid": testId, children: /* @__PURE__ */ jsx7(RichMarkdown, { content, deferDiagrams: true }) });
3552
3712
  }
3553
3713
 
3554
3714
  // src/core/workflow/loopTreeUtils.ts
@@ -3558,7 +3718,7 @@ function hasTimelineNodes(tree) {
3558
3718
  }
3559
3719
 
3560
3720
  // src/view/workflow/workflowStageDoneBody.tsx
3561
- import { jsx as jsx9 } from "react/jsx-runtime";
3721
+ import { jsx as jsx8, jsxs as jsxs4 } from "react/jsx-runtime";
3562
3722
  function WorkflowStageDoneBody({
3563
3723
  loopTree,
3564
3724
  testId,
@@ -3568,7 +3728,7 @@ function WorkflowStageDoneBody({
3568
3728
  bodyClassName = "lax-workflow-stage-container__body"
3569
3729
  }) {
3570
3730
  if (loopTree && hasTimelineNodes(loopTree)) {
3571
- return /* @__PURE__ */ jsx9("div", { className: bodyClassName, "data-testid": testId, children: /* @__PURE__ */ jsx9(
3731
+ return /* @__PURE__ */ jsx8("div", { className: bodyClassName, "data-testid": testId, "data-loop-display": "full", children: /* @__PURE__ */ jsx8(
3572
3732
  AgentLoopView,
3573
3733
  {
3574
3734
  tree: loopTree,
@@ -3579,12 +3739,39 @@ function WorkflowStageDoneBody({
3579
3739
  }
3580
3740
  ) });
3581
3741
  }
3582
- return /* @__PURE__ */ jsx9(
3742
+ return /* @__PURE__ */ jsx8(
3583
3743
  "div",
3584
3744
  {
3585
3745
  className: `${bodyClassName} lax-workflow-stage-container__empty-hint`,
3586
3746
  "data-testid": testId,
3587
- children: /* @__PURE__ */ jsx9("span", { className: "lax-workflow-stage-container__empty-hint-text", children: "\uFF08\u6B64\u9636\u6BB5\u6682\u65E0 Agent \u65F6\u95F4\u7EBF\u5185\u5BB9\uFF09" })
3747
+ children: /* @__PURE__ */ jsx8("span", { className: "lax-workflow-stage-container__empty-hint-text", children: "\uFF08\u6B64\u9636\u6BB5\u6682\u65E0 Agent \u65F6\u95F4\u7EBF\u5185\u5BB9\uFF09" })
3748
+ }
3749
+ );
3750
+ }
3751
+ function WorkflowStageSummaryOnlyBody({
3752
+ summary,
3753
+ testId,
3754
+ verbose = false,
3755
+ bodyClassName = "lax-workflow-stage-container__body lax-workflow-stage-container__body--summary-only"
3756
+ }) {
3757
+ const expandHint = formatTeaserExpandHint(summary.extraLines, verbose);
3758
+ return /* @__PURE__ */ jsxs4(
3759
+ "div",
3760
+ {
3761
+ className: bodyClassName,
3762
+ "data-testid": testId,
3763
+ "data-loop-display": "summary",
3764
+ children: [
3765
+ summary.teaser ? /* @__PURE__ */ jsx8(
3766
+ WorkflowMarkdownPreview,
3767
+ {
3768
+ content: summary.teaser,
3769
+ className: "lax-workflow-stage-container__teaser",
3770
+ testId: `${testId}-summary-teaser`
3771
+ }
3772
+ ) : /* @__PURE__ */ jsx8("span", { className: "lax-workflow-stage-container__empty-hint-text", children: WORKFLOW_STAGE_EMPTY_SUMMARY_HINT }),
3773
+ expandHint ? /* @__PURE__ */ jsx8("span", { className: "lax-workflow-expand-trigger__hint", children: expandHint }) : null
3774
+ ]
3588
3775
  }
3589
3776
  );
3590
3777
  }
@@ -3831,7 +4018,7 @@ function workflowContainerViewPropsEqual(prev, next) {
3831
4018
  }
3832
4019
 
3833
4020
  // src/view/workflow/WorkflowAggregateContainer.tsx
3834
- import { jsx as jsx10, jsxs as jsxs4 } from "react/jsx-runtime";
4021
+ import { jsx as jsx9, jsxs as jsxs5 } from "react/jsx-runtime";
3835
4022
  function mergeContentPreview(node) {
3836
4023
  const blocks = node.content_blocks;
3837
4024
  if (blocks.length === 0) return "";
@@ -3859,12 +4046,10 @@ function WorkflowAggregateContainerInner({
3859
4046
  }) {
3860
4047
  const { verbose } = useSessionViewOptions();
3861
4048
  const store = useWorkflowSessionStoreApi();
3862
- const replayHandler = useWorkflowLoopReplayHandler();
3863
4049
  const cachedSummary = useStore3(
3864
4050
  store,
3865
4051
  (s) => s.state.stageDoneSummariesByContainerId[node.container_id]
3866
4052
  );
3867
- const pinLoopSession = useStore3(store, (s) => s.pinLoopSession);
3868
4053
  const isRunning = node.status === "running" || node.status === "retrying";
3869
4054
  const isWaiting = node.status === "pending" || node.status === "blocked";
3870
4055
  const isDone = node.status === "completed" || node.status === "failed";
@@ -3893,32 +4078,11 @@ function WorkflowAggregateContainerInner({
3893
4078
  if (isRunning) setExpanded(true);
3894
4079
  if (isDone) setExpanded(false);
3895
4080
  }, [isRunning, isDone]);
3896
- const requestLoopHydration = useCallback(() => {
3897
- const loopSessionId = node.loopSessionId;
3898
- if (!loopSessionId || loopTree) return;
3899
- pinLoopSession(loopSessionId);
3900
- void replayHandler?.(loopSessionId);
3901
- }, [node.loopSessionId, loopTree, pinLoopSession, replayHandler]);
3902
4081
  const toggleExpanded = useCallback(() => {
3903
- setExpanded((prev) => {
3904
- const next = !prev;
3905
- if (next && isDone && node.loopSessionId && !loopTree) {
3906
- requestLoopHydration();
3907
- }
3908
- return next;
3909
- });
3910
- }, [isDone, node.loopSessionId, loopTree, requestLoopHydration]);
3911
- useEffect6(() => {
3912
- const onKeyDown = (event) => {
3913
- if (!(event.ctrlKey || event.metaKey) || event.key.toLowerCase() !== "o") return;
3914
- setExpanded(true);
3915
- requestLoopHydration();
3916
- };
3917
- window.addEventListener("keydown", onKeyDown);
3918
- return () => window.removeEventListener("keydown", onKeyDown);
3919
- }, [requestLoopHydration]);
4082
+ setExpanded((prev) => !prev);
4083
+ }, []);
3920
4084
  const shellToggle = isRunning ? toggleExpanded : isDone ? toggleExpanded : void 0;
3921
- const markdownPreview = bodyMarkdown ? /* @__PURE__ */ jsx10(
4085
+ const markdownPreview = bodyMarkdown ? /* @__PURE__ */ jsx9(
3922
4086
  WorkflowMarkdownPreview,
3923
4087
  {
3924
4088
  content: bodyMarkdown,
@@ -3927,7 +4091,7 @@ function WorkflowAggregateContainerInner({
3927
4091
  }
3928
4092
  ) : null;
3929
4093
  const canExpandDone = isDone && (Boolean(loopTree) || Boolean(bodyMarkdown) || Boolean(node.loopSessionId));
3930
- return /* @__PURE__ */ jsxs4(
4094
+ return /* @__PURE__ */ jsxs5(
3931
4095
  "div",
3932
4096
  {
3933
4097
  className: `lax-workflow-aggregate lax-workflow-stage-container lax-workflow-stage-container--${isWaiting ? "pending" : isDone ? "done" : "running"}`,
@@ -3935,7 +4099,7 @@ function WorkflowAggregateContainerInner({
3935
4099
  "data-container-scope": "aggregate",
3936
4100
  style: { "--lax-workflow-depth": depth },
3937
4101
  children: [
3938
- /* @__PURE__ */ jsx10(
4102
+ /* @__PURE__ */ jsx9(
3939
4103
  WorkflowContainerLine,
3940
4104
  {
3941
4105
  title: node.title,
@@ -3950,9 +4114,9 @@ function WorkflowAggregateContainerInner({
3950
4114
  descriptionTestId: `${testId}-desc`
3951
4115
  }
3952
4116
  ),
3953
- isWaiting && waitingTeaser ? /* @__PURE__ */ jsxs4("div", { className: "lax-workflow-aggregate__waiting-teaser", "data-testid": `${testId}-waiting`, children: [
3954
- /* @__PURE__ */ jsx10("span", { className: "lax-workflow-aggregate__waiting-prefix", children: "\u23BF " }),
3955
- /* @__PURE__ */ jsx10(
4117
+ isWaiting && waitingTeaser ? /* @__PURE__ */ jsxs5("div", { className: "lax-workflow-aggregate__waiting-teaser", "data-testid": `${testId}-waiting`, children: [
4118
+ /* @__PURE__ */ jsx9("span", { className: "lax-workflow-aggregate__waiting-prefix", children: "\u23BF " }),
4119
+ /* @__PURE__ */ jsx9(
3956
4120
  WorkflowMarkdownPreview,
3957
4121
  {
3958
4122
  content: waitingTeaser,
@@ -3960,7 +4124,7 @@ function WorkflowAggregateContainerInner({
3960
4124
  }
3961
4125
  )
3962
4126
  ] }) : null,
3963
- expanded && isRunning && loopTree ? /* @__PURE__ */ jsx10("div", { className: "lax-workflow-stage-container__body", "data-testid": `${testId}-body`, children: /* @__PURE__ */ jsx10(
4127
+ expanded && isRunning && loopTree ? /* @__PURE__ */ jsx9("div", { className: "lax-workflow-stage-container__body", "data-testid": `${testId}-body`, children: /* @__PURE__ */ jsx9(
3964
4128
  AgentLoopView,
3965
4129
  {
3966
4130
  tree: loopTree,
@@ -3970,7 +4134,7 @@ function WorkflowAggregateContainerInner({
3970
4134
  groupParallelTools
3971
4135
  }
3972
4136
  ) }) : null,
3973
- expanded && isRunning && !loopTree && bodyMarkdown ? /* @__PURE__ */ jsx10(
4137
+ expanded && isRunning && !loopTree && bodyMarkdown ? /* @__PURE__ */ jsx9(
3974
4138
  "div",
3975
4139
  {
3976
4140
  className: "lax-workflow-stage-container__body lax-workflow-stage-container__content-preview",
@@ -3978,8 +4142,8 @@ function WorkflowAggregateContainerInner({
3978
4142
  children: markdownPreview
3979
4143
  }
3980
4144
  ) : null,
3981
- isDone && !expanded ? /* @__PURE__ */ jsxs4("div", { className: "lax-workflow-aggregate__done", "data-testid": `${testId}-done`, children: [
3982
- canExpandDone ? /* @__PURE__ */ jsx10(
4145
+ isDone && !expanded ? /* @__PURE__ */ jsxs5("div", { className: "lax-workflow-aggregate__done", "data-testid": `${testId}-done`, children: [
4146
+ canExpandDone ? /* @__PURE__ */ jsx9(
3983
4147
  WorkflowExpandTrigger,
3984
4148
  {
3985
4149
  summary: `${node.title} \xB7 done`,
@@ -3989,10 +4153,10 @@ function WorkflowAggregateContainerInner({
3989
4153
  testId: `${testId}-done-trigger`
3990
4154
  }
3991
4155
  ) : null,
3992
- markdownPreview ? /* @__PURE__ */ jsx10("div", { className: "lax-workflow-aggregate__done-preview", "data-testid": `${testId}-teaser`, children: markdownPreview }) : null,
3993
- !bodyMarkdown && expandHint ? /* @__PURE__ */ jsx10("span", { className: "lax-workflow-expand-trigger__hint", children: expandHint }) : null
4156
+ markdownPreview ? /* @__PURE__ */ jsx9("div", { className: "lax-workflow-aggregate__done-preview", "data-testid": `${testId}-teaser`, children: markdownPreview }) : null,
4157
+ !bodyMarkdown && expandHint ? /* @__PURE__ */ jsx9("span", { className: "lax-workflow-expand-trigger__hint", children: expandHint }) : null
3994
4158
  ] }) : null,
3995
- isDone && expanded ? loopTree ? /* @__PURE__ */ jsx10(
4159
+ isDone && expanded ? loopTree ? /* @__PURE__ */ jsx9(
3996
4160
  WorkflowStageDoneBody,
3997
4161
  {
3998
4162
  node,
@@ -4002,19 +4166,19 @@ function WorkflowAggregateContainerInner({
4002
4166
  virtualizeThreshold,
4003
4167
  groupParallelTools
4004
4168
  }
4005
- ) : bodyMarkdown ? /* @__PURE__ */ jsx10(
4169
+ ) : bodyMarkdown ? /* @__PURE__ */ jsx9(
4006
4170
  "div",
4007
4171
  {
4008
4172
  className: "lax-workflow-stage-container__body lax-workflow-stage-container__content-preview",
4009
4173
  "data-testid": `${testId}-body`,
4010
4174
  children: markdownPreview
4011
4175
  }
4012
- ) : usesScopedLoop ? /* @__PURE__ */ jsx10(
4176
+ ) : usesScopedLoop ? /* @__PURE__ */ jsx9(
4013
4177
  "div",
4014
4178
  {
4015
4179
  className: "lax-workflow-stage-container__body lax-workflow-loop-replay-pending",
4016
4180
  "data-testid": `${testId}-body`,
4017
- children: /* @__PURE__ */ jsx10("p", { className: "lax-workflow-loop-replay-pending__hint", children: replayHandler ? "Loading loop details\u2026" : "Loop details evicted from memory." })
4181
+ children: /* @__PURE__ */ jsx9("p", { className: "lax-workflow-loop-replay-pending__hint", children: "Loop details evicted from memory." })
4018
4182
  }
4019
4183
  ) : null : null
4020
4184
  ]
@@ -4134,7 +4298,7 @@ function formatParallelGroupSummary(metrics) {
4134
4298
  // src/view/workflow/WorkflowStageContainer.tsx
4135
4299
  import { useCallback as useCallback2, useEffect as useEffect7, useMemo as useMemo3, useState as useState2, memo as memo2 } from "react";
4136
4300
  import { useStore as useStore4 } from "zustand";
4137
- import { jsx as jsx11, jsxs as jsxs5 } from "react/jsx-runtime";
4301
+ import { jsx as jsx10, jsxs as jsxs6 } from "react/jsx-runtime";
4138
4302
  function containerTestId(node) {
4139
4303
  if (node.scope === "item") return `lax-workflow-parallel-${node.scope_key}`;
4140
4304
  if (node.scope === "stage") return `lax-workflow-stage-${node.scope_key}`;
@@ -4155,15 +4319,14 @@ function WorkflowStageContainerInner({
4155
4319
  subtreeHasActiveWork: subtreeHasActiveWork2 = false
4156
4320
  }) {
4157
4321
  const { verbose } = useSessionViewOptions();
4322
+ const scale = useWorkflowScaleOptions();
4158
4323
  const store = useWorkflowSessionStoreApi();
4159
- const replayHandler = useWorkflowLoopReplayHandler();
4160
4324
  const activeLoopSessionId = useStore4(store, (s) => s.state.activeLoopSessionId);
4161
4325
  const activeContainerIds = useStore4(store, (s) => s.state.containerTree.activeContainerIds);
4162
4326
  const cachedSummary = useStore4(
4163
4327
  store,
4164
4328
  (s) => s.state.stageDoneSummariesByContainerId[node.container_id]
4165
4329
  );
4166
- const pinLoopSession = useStore4(store, (s) => s.pinLoopSession);
4167
4330
  const isRunning = node.status === "running" || node.status === "retrying";
4168
4331
  const isDone = node.status === "completed" || node.status === "failed";
4169
4332
  const isSkipped = node.status === "skipped";
@@ -4177,6 +4340,7 @@ function WorkflowStageContainerInner({
4177
4340
  [loopTree, isDone]
4178
4341
  );
4179
4342
  const doneSummary = doneSummaryFromTree ?? (isDone ? cachedSummary : null);
4343
+ const loopDisplayMode = !effectivelyDone ? "none" : loopTree ? "full" : doneSummary ? "summary" : "evicted";
4180
4344
  const shouldAutoExpandRunning = effectivelyRunning && !isSkipped;
4181
4345
  const [expanded, setExpanded] = useState2(shouldAutoExpandRunning);
4182
4346
  useEffect7(() => {
@@ -4188,31 +4352,20 @@ function WorkflowStageContainerInner({
4188
4352
  setExpanded(false);
4189
4353
  }
4190
4354
  }, [shouldAutoExpandRunning, effectivelyDone, isSkipped]);
4191
- const requestLoopHydration = useCallback2(() => {
4192
- if (suppressHostScopedLoop) return;
4193
- const loopSessionId = node.loopSessionId;
4194
- if (!loopSessionId || loopTree) return;
4195
- pinLoopSession(loopSessionId);
4196
- void replayHandler?.(loopSessionId);
4197
- }, [suppressHostScopedLoop, node.loopSessionId, loopTree, pinLoopSession, replayHandler]);
4198
- const toggleExpanded = useCallback2(() => {
4199
- setExpanded((prev) => {
4200
- const next = !prev;
4201
- if (next && isDone && node.loopSessionId && !loopTree) {
4202
- requestLoopHydration();
4203
- }
4204
- return next;
4205
- });
4206
- }, [isDone, node.loopSessionId, loopTree, requestLoopHydration]);
4355
+ const protectExpandedLoops = scale.protectExpandedLoops ?? false;
4356
+ const loopSessionId = node.loopSessionId;
4207
4357
  useEffect7(() => {
4208
- const onKeyDown = (event) => {
4209
- if (!(event.ctrlKey || event.metaKey) || event.key.toLowerCase() !== "o") return;
4210
- setExpanded(true);
4211
- requestLoopHydration();
4358
+ if (!protectExpandedLoops || !effectivelyDone || !loopSessionId || !expanded) return;
4359
+ const loopInMemory = Boolean(store.getState().state.loopTreesBySessionId[loopSessionId]);
4360
+ if (!loopInMemory) return;
4361
+ store.getState().pinLoopSession(loopSessionId);
4362
+ return () => {
4363
+ store.getState().unpinLoopSession(loopSessionId);
4212
4364
  };
4213
- window.addEventListener("keydown", onKeyDown);
4214
- return () => window.removeEventListener("keydown", onKeyDown);
4215
- }, [requestLoopHydration]);
4365
+ }, [protectExpandedLoops, effectivelyDone, loopSessionId, expanded, store]);
4366
+ const toggleExpanded = useCallback2(() => {
4367
+ setExpanded((prev) => !prev);
4368
+ }, []);
4216
4369
  const testId = containerTestId(node);
4217
4370
  const isItem = node.scope === "item";
4218
4371
  const displayTitle = node.title;
@@ -4226,7 +4379,7 @@ function WorkflowStageContainerInner({
4226
4379
  const statusLabel = effectivelyDone ? doneLabel : suppressHostScopedLoop && effectivelyRunning ? "running" : mapContainerStatusLabel(effectivelyRunning ? "running" : node.status);
4227
4380
  const canToggleShell = effectivelyRunning && !isSkipped || effectivelyDone;
4228
4381
  const shellToggle = canToggleShell ? toggleExpanded : void 0;
4229
- return /* @__PURE__ */ jsxs5(
4382
+ return /* @__PURE__ */ jsxs6(
4230
4383
  "div",
4231
4384
  {
4232
4385
  className: `lax-workflow-stage-container lax-workflow-stage-container--${uiStatus}${isSkipped ? " lax-workflow-stage-container--skipped" : ""}${isItem ? " lax-workflow-parallel-item" : " lax-workflow-stage"}`,
@@ -4234,12 +4387,13 @@ function WorkflowStageContainerInner({
4234
4387
  "data-stage-status": uiStatus,
4235
4388
  "data-container-scope": node.scope,
4236
4389
  "data-active": isActive ? "true" : void 0,
4390
+ "data-loop-display": loopDisplayMode !== "none" ? loopDisplayMode : void 0,
4237
4391
  style: {
4238
4392
  "--lax-workflow-depth": depth,
4239
4393
  "--lax-workflow-indent-unit": workflowIndentUnit(depth)
4240
4394
  },
4241
4395
  children: [
4242
- /* @__PURE__ */ jsx11(
4396
+ /* @__PURE__ */ jsx10(
4243
4397
  WorkflowContainerLine,
4244
4398
  {
4245
4399
  title: displayTitle,
@@ -4256,15 +4410,15 @@ function WorkflowStageContainerInner({
4256
4410
  className: isItem ? "lax-workflow-parallel-item__header" : void 0
4257
4411
  }
4258
4412
  ),
4259
- effectivelyDone && !expanded && (teaserText || expandHint) ? /* @__PURE__ */ jsxs5("div", { className: "lax-workflow-stage-container__done-teaser", children: [
4260
- teaserText ? /* @__PURE__ */ jsxs5(
4413
+ effectivelyDone && !expanded && (teaserText || expandHint) ? /* @__PURE__ */ jsxs6("div", { className: "lax-workflow-stage-container__done-teaser", children: [
4414
+ teaserText ? /* @__PURE__ */ jsxs6(
4261
4415
  "div",
4262
4416
  {
4263
4417
  className: "lax-workflow-stage-container__done-teaser-line",
4264
4418
  "data-testid": `${testId}-teaser`,
4265
4419
  children: [
4266
- /* @__PURE__ */ jsx11("span", { className: "lax-workflow-stage-container__done-teaser-prefix", children: "\u23BF" }),
4267
- /* @__PURE__ */ jsx11(
4420
+ /* @__PURE__ */ jsx10("span", { className: "lax-workflow-stage-container__done-teaser-prefix", children: "\u23BF" }),
4421
+ /* @__PURE__ */ jsx10(
4268
4422
  WorkflowMarkdownPreview,
4269
4423
  {
4270
4424
  content: teaserText,
@@ -4274,14 +4428,14 @@ function WorkflowStageContainerInner({
4274
4428
  ]
4275
4429
  }
4276
4430
  ) : null,
4277
- expandHint ? /* @__PURE__ */ jsx11("span", { className: "lax-workflow-expand-trigger__hint", children: expandHint }) : null
4431
+ expandHint ? /* @__PURE__ */ jsx10("span", { className: "lax-workflow-expand-trigger__hint", children: expandHint }) : null
4278
4432
  ] }) : null,
4279
- expanded && isRunning && !usesScopedLoop && node.content_blocks.length > 0 ? /* @__PURE__ */ jsx11(
4433
+ expanded && isRunning && !usesScopedLoop && node.content_blocks.length > 0 ? /* @__PURE__ */ jsx10(
4280
4434
  "div",
4281
4435
  {
4282
4436
  className: "lax-workflow-stage-container__body lax-workflow-stage-container__content-preview",
4283
4437
  "data-testid": bodyTestId(node),
4284
- children: node.content_blocks.map((block, index) => /* @__PURE__ */ jsx11(
4438
+ children: node.content_blocks.map((block, index) => /* @__PURE__ */ jsx10(
4285
4439
  WorkflowMarkdownPreview,
4286
4440
  {
4287
4441
  content: block.preview,
@@ -4291,12 +4445,12 @@ function WorkflowStageContainerInner({
4291
4445
  ))
4292
4446
  }
4293
4447
  ) : null,
4294
- expanded && effectivelyRunning && runningLoopTree ? /* @__PURE__ */ jsx11(
4448
+ expanded && effectivelyRunning && runningLoopTree ? /* @__PURE__ */ jsx10(
4295
4449
  "div",
4296
4450
  {
4297
4451
  className: isItem ? "lax-workflow-parallel-item__body lax-workflow-stage-container__body" : "lax-workflow-stage-container__body",
4298
4452
  "data-testid": bodyTestId(node),
4299
- children: /* @__PURE__ */ jsx11(
4453
+ children: /* @__PURE__ */ jsx10(
4300
4454
  AgentLoopView,
4301
4455
  {
4302
4456
  tree: runningLoopTree,
@@ -4308,7 +4462,7 @@ function WorkflowStageContainerInner({
4308
4462
  )
4309
4463
  }
4310
4464
  ) : null,
4311
- effectivelyDone && expanded ? loopTree ? /* @__PURE__ */ jsx11(
4465
+ effectivelyDone && expanded ? loopTree ? /* @__PURE__ */ jsx10(
4312
4466
  WorkflowStageDoneBody,
4313
4467
  {
4314
4468
  node,
@@ -4319,22 +4473,21 @@ function WorkflowStageContainerInner({
4319
4473
  groupParallelTools,
4320
4474
  bodyClassName: isItem ? "lax-workflow-parallel-item__body lax-workflow-stage-container__body" : "lax-workflow-stage-container__body"
4321
4475
  }
4322
- ) : suppressHostScopedLoop ? null : /* @__PURE__ */ jsxs5(
4476
+ ) : doneSummary ? /* @__PURE__ */ jsx10(
4477
+ WorkflowStageSummaryOnlyBody,
4478
+ {
4479
+ summary: doneSummary,
4480
+ testId: bodyTestId(node),
4481
+ verbose,
4482
+ bodyClassName: isItem ? "lax-workflow-parallel-item__body lax-workflow-stage-container__body" : "lax-workflow-stage-container__body"
4483
+ }
4484
+ ) : suppressHostScopedLoop ? null : /* @__PURE__ */ jsx10(
4323
4485
  "div",
4324
4486
  {
4325
- className: "lax-workflow-stage-container__body lax-workflow-loop-replay-pending",
4487
+ className: "lax-workflow-stage-container__body lax-workflow-stage-container__body--evicted",
4326
4488
  "data-testid": bodyTestId(node),
4327
- children: [
4328
- teaserText ? /* @__PURE__ */ jsx11(
4329
- WorkflowMarkdownPreview,
4330
- {
4331
- content: teaserText,
4332
- className: "lax-workflow-stage-container__teaser",
4333
- testId: `${testId}-replay-teaser`
4334
- }
4335
- ) : null,
4336
- /* @__PURE__ */ jsx11("p", { className: "lax-workflow-loop-replay-pending__hint", children: replayHandler ? "Loading loop details\u2026" : "Loop details evicted from memory." })
4337
- ]
4489
+ "data-loop-display": "evicted",
4490
+ children: /* @__PURE__ */ jsx10("p", { className: "lax-workflow-loop-replay-pending__hint", children: WORKFLOW_STAGE_EMPTY_SUMMARY_HINT })
4338
4491
  }
4339
4492
  ) : null
4340
4493
  ]
@@ -4351,7 +4504,7 @@ function workflowStageContainerPropsEqual(prev, next) {
4351
4504
  var WorkflowStageContainer = memo2(WorkflowStageContainerInner, workflowStageContainerPropsEqual);
4352
4505
 
4353
4506
  // src/view/workflow/WorkflowParallelGroup.tsx
4354
- import { jsx as jsx12, jsxs as jsxs6 } from "react/jsx-runtime";
4507
+ import { jsx as jsx11, jsxs as jsxs7 } from "react/jsx-runtime";
4355
4508
  function resolveLoopTree(node, loopTreesBySessionId) {
4356
4509
  if (!node.loopSessionId) return void 0;
4357
4510
  return loopTreesBySessionId[node.loopSessionId];
@@ -4395,7 +4548,7 @@ function WorkflowParallelGroupInner({
4395
4548
  }, []);
4396
4549
  const renderItem = (index) => {
4397
4550
  const item = items[index];
4398
- return /* @__PURE__ */ jsx12(
4551
+ return /* @__PURE__ */ jsx11(
4399
4552
  WorkflowStageContainer,
4400
4553
  {
4401
4554
  node: item,
@@ -4408,13 +4561,13 @@ function WorkflowParallelGroupInner({
4408
4561
  item.container_id
4409
4562
  );
4410
4563
  };
4411
- return /* @__PURE__ */ jsxs6(
4564
+ return /* @__PURE__ */ jsxs7(
4412
4565
  "div",
4413
4566
  {
4414
4567
  className: "lax-workflow-parallel-group",
4415
4568
  "data-testid": `lax-workflow-parallel-group-${groupKey}`,
4416
4569
  children: [
4417
- /* @__PURE__ */ jsx12(
4570
+ /* @__PURE__ */ jsx11(
4418
4571
  WorkflowExpandTrigger,
4419
4572
  {
4420
4573
  summary,
@@ -4425,7 +4578,7 @@ function WorkflowParallelGroupInner({
4425
4578
  className: "lax-workflow-parallel-group__summary"
4426
4579
  }
4427
4580
  ),
4428
- expanded ? /* @__PURE__ */ jsx12("div", { className: "lax-workflow-parallel-list", "data-testid": "lax-workflow-parallel-list", children: items.map((_, index) => renderItem(index)) }) : null
4581
+ expanded ? /* @__PURE__ */ jsx11("div", { className: "lax-workflow-parallel-list", "data-testid": "lax-workflow-parallel-list", children: items.map((_, index) => renderItem(index)) }) : null
4429
4582
  ]
4430
4583
  }
4431
4584
  );
@@ -4450,7 +4603,7 @@ function workflowParallelGroupPropsEqual(prev, next) {
4450
4603
  var WorkflowParallelGroup = memo3(WorkflowParallelGroupInner, workflowParallelGroupPropsEqual);
4451
4604
 
4452
4605
  // src/view/workflow/WorkflowRootContainer.tsx
4453
- import { jsx as jsx13, jsxs as jsxs7 } from "react/jsx-runtime";
4606
+ import { jsx as jsx12, jsxs as jsxs8 } from "react/jsx-runtime";
4454
4607
  function WorkflowRootContainer({
4455
4608
  node,
4456
4609
  children,
@@ -4464,8 +4617,8 @@ function WorkflowRootContainer({
4464
4617
  const uiStatus = forcedCloseout ? "warning" : mapContainerUiStatus(nodeStatus);
4465
4618
  const statusLabel = mapWorkflowRootStatusLabel(nodeStatus, sessionStatus);
4466
4619
  const meta = containersById ? buildEffectiveWorkflowRootMeta(node, containersById) : buildWorkflowRootMeta(node);
4467
- return /* @__PURE__ */ jsxs7("div", { className: "lax-workflow-root", "data-testid": "lax-workflow-root", children: [
4468
- /* @__PURE__ */ jsx13(
4620
+ return /* @__PURE__ */ jsxs8("div", { className: "lax-workflow-root", "data-testid": "lax-workflow-root", children: [
4621
+ /* @__PURE__ */ jsx12(
4469
4622
  WorkflowContainerLine,
4470
4623
  {
4471
4624
  variant: "root",
@@ -4480,13 +4633,13 @@ function WorkflowRootContainer({
4480
4633
  verbose
4481
4634
  }
4482
4635
  ),
4483
- children ? /* @__PURE__ */ jsx13("div", { className: "lax-workflow-container-tree", children }) : null
4636
+ children ? /* @__PURE__ */ jsx12("div", { className: "lax-workflow-container-tree", children }) : null
4484
4637
  ] });
4485
4638
  }
4486
4639
 
4487
4640
  // src/view/workflow/WorkflowRouteContainer.tsx
4488
4641
  import { useCallback as useCallback4, useEffect as useEffect9, useMemo as useMemo5, useState as useState4 } from "react";
4489
- import { jsx as jsx14, jsxs as jsxs8 } from "react/jsx-runtime";
4642
+ import { jsx as jsx13, jsxs as jsxs9 } from "react/jsx-runtime";
4490
4643
  function WorkflowRouteContainer({
4491
4644
  node,
4492
4645
  loopTree,
@@ -4523,7 +4676,7 @@ function WorkflowRouteContainer({
4523
4676
  "--lax-workflow-depth": depth,
4524
4677
  "--lax-workflow-indent-unit": workflowIndentUnit(depth)
4525
4678
  };
4526
- return /* @__PURE__ */ jsxs8(
4679
+ return /* @__PURE__ */ jsxs9(
4527
4680
  "div",
4528
4681
  {
4529
4682
  className: `lax-workflow-route-branch lax-workflow-stage-container lax-workflow-stage-container--${uiStatus}${isSkipped ? " lax-workflow-route-branch--skipped" : ""}`,
@@ -4532,7 +4685,7 @@ function WorkflowRouteContainer({
4532
4685
  "data-container-scope": "branch",
4533
4686
  style: depthStyle,
4534
4687
  children: [
4535
- /* @__PURE__ */ jsx14(
4688
+ /* @__PURE__ */ jsx13(
4536
4689
  WorkflowContainerLine,
4537
4690
  {
4538
4691
  title: node.title,
@@ -4547,7 +4700,7 @@ function WorkflowRouteContainer({
4547
4700
  descriptionTestId: `${testId}-desc`
4548
4701
  }
4549
4702
  ),
4550
- !isSkipped && expanded && isRunning && loopTree ? /* @__PURE__ */ jsx14("div", { className: "lax-workflow-stage-container__body", "data-testid": `${testId}-body`, children: /* @__PURE__ */ jsx14(
4703
+ !isSkipped && expanded && isRunning && loopTree ? /* @__PURE__ */ jsx13("div", { className: "lax-workflow-stage-container__body", "data-testid": `${testId}-body`, children: /* @__PURE__ */ jsx13(
4551
4704
  AgentLoopView,
4552
4705
  {
4553
4706
  tree: loopTree,
@@ -4557,7 +4710,7 @@ function WorkflowRouteContainer({
4557
4710
  groupParallelTools
4558
4711
  }
4559
4712
  ) }) : null,
4560
- !isSkipped && isDone && !expanded ? /* @__PURE__ */ jsx14(
4713
+ !isSkipped && isDone && !expanded ? /* @__PURE__ */ jsx13(
4561
4714
  WorkflowExpandTrigger,
4562
4715
  {
4563
4716
  summary: `${node.title} \xB7 ${doneLabel}`,
@@ -4569,7 +4722,7 @@ function WorkflowRouteContainer({
4569
4722
  teaserTestId: teaserText ? `${testId}-teaser` : void 0
4570
4723
  }
4571
4724
  ) : null,
4572
- !isSkipped && isDone && expanded ? /* @__PURE__ */ jsx14(
4725
+ !isSkipped && isDone && expanded ? /* @__PURE__ */ jsx13(
4573
4726
  WorkflowStageDoneBody,
4574
4727
  {
4575
4728
  node,
@@ -4587,7 +4740,7 @@ function WorkflowRouteContainer({
4587
4740
 
4588
4741
  // src/view/workflow/WorkflowSubworkflowContainer.tsx
4589
4742
  import { useCallback as useCallback5, useEffect as useEffect10, useMemo as useMemo6, useState as useState5 } from "react";
4590
- import { jsx as jsx15, jsxs as jsxs9 } from "react/jsx-runtime";
4743
+ import { jsx as jsx14, jsxs as jsxs10 } from "react/jsx-runtime";
4591
4744
  function buildDoneSummary(node) {
4592
4745
  const display = node.display;
4593
4746
  if (display?.progress_total != null) {
@@ -4630,7 +4783,7 @@ function WorkflowSubworkflowContainer({
4630
4783
  "--lax-workflow-indent-unit": workflowIndentUnit(depth)
4631
4784
  };
4632
4785
  const showShellLine = !(effectivelyDone && !expanded);
4633
- return /* @__PURE__ */ jsxs9(
4786
+ return /* @__PURE__ */ jsxs10(
4634
4787
  "div",
4635
4788
  {
4636
4789
  className: "lax-workflow-subworkflow",
@@ -4638,7 +4791,7 @@ function WorkflowSubworkflowContainer({
4638
4791
  "data-container-scope": "subworkflow",
4639
4792
  style: depthStyle,
4640
4793
  children: [
4641
- showShellLine ? /* @__PURE__ */ jsx15(
4794
+ showShellLine ? /* @__PURE__ */ jsx14(
4642
4795
  WorkflowContainerLine,
4643
4796
  {
4644
4797
  variant: "root",
@@ -4658,7 +4811,7 @@ function WorkflowSubworkflowContainer({
4658
4811
  verbose
4659
4812
  }
4660
4813
  ) : null,
4661
- expanded && children ? /* @__PURE__ */ jsx15(
4814
+ expanded && children ? /* @__PURE__ */ jsx14(
4662
4815
  "div",
4663
4816
  {
4664
4817
  className: "lax-workflow-subworkflow-boundary",
@@ -4667,7 +4820,7 @@ function WorkflowSubworkflowContainer({
4667
4820
  children
4668
4821
  }
4669
4822
  ) : null,
4670
- !expanded && children ? /* @__PURE__ */ jsx15(
4823
+ !expanded && children ? /* @__PURE__ */ jsx14(
4671
4824
  WorkflowExpandTrigger,
4672
4825
  {
4673
4826
  summary: `${node.title} \xB7 ${effectivelyDone ? buildDoneSummary(node) : "running"}`,
@@ -4686,7 +4839,7 @@ function WorkflowSubworkflowContainer({
4686
4839
  }
4687
4840
 
4688
4841
  // src/view/workflow/WorkflowChrome.tsx
4689
- import { Fragment as Fragment2, jsx as jsx16, jsxs as jsxs10 } from "react/jsx-runtime";
4842
+ import { Fragment as Fragment2, jsx as jsx15, jsxs as jsxs11 } from "react/jsx-runtime";
4690
4843
  function collectChildContainers(containersById, parentId) {
4691
4844
  return Object.values(containersById).filter((node) => node.parent_container_id === parentId).sort((a, b) => a.scope_key.localeCompare(b.scope_key));
4692
4845
  }
@@ -4705,7 +4858,7 @@ function renderLeafContainer(node, depth, containerTree, loopTreesBySessionId, v
4705
4858
  const subtreeActive = options?.subtreeHasActiveWork ?? subtreeHasActiveWork(containerTree.containersById, node.container_id);
4706
4859
  switch (node.scope) {
4707
4860
  case "aggregate":
4708
- return /* @__PURE__ */ jsx16(
4861
+ return /* @__PURE__ */ jsx15(
4709
4862
  WorkflowAggregateContainer,
4710
4863
  {
4711
4864
  node,
@@ -4717,7 +4870,7 @@ function renderLeafContainer(node, depth, containerTree, loopTreesBySessionId, v
4717
4870
  node.container_id
4718
4871
  );
4719
4872
  case "branch":
4720
- return /* @__PURE__ */ jsx16(
4873
+ return /* @__PURE__ */ jsx15(
4721
4874
  WorkflowRouteContainer,
4722
4875
  {
4723
4876
  node,
@@ -4728,7 +4881,7 @@ function renderLeafContainer(node, depth, containerTree, loopTreesBySessionId, v
4728
4881
  node.container_id
4729
4882
  );
4730
4883
  default:
4731
- return /* @__PURE__ */ jsx16(
4884
+ return /* @__PURE__ */ jsx15(
4732
4885
  WorkflowStageContainer,
4733
4886
  {
4734
4887
  node,
@@ -4744,7 +4897,7 @@ function renderLeafContainer(node, depth, containerTree, loopTreesBySessionId, v
4744
4897
  }
4745
4898
  function renderItemSiblings(items, groupKey, depth, containerTree, loopTreesBySessionId, viewProps) {
4746
4899
  if (items.length >= 2) {
4747
- return /* @__PURE__ */ jsx16(
4900
+ return /* @__PURE__ */ jsx15(
4748
4901
  WorkflowParallelGroup,
4749
4902
  {
4750
4903
  groupKey,
@@ -4769,7 +4922,7 @@ function renderContainerChildren(parentId, containerTree, loopTreesBySessionId,
4769
4922
  const children = collectChildContainers(containerTree.containersById, parentId);
4770
4923
  const items = children.filter((node) => node.scope === "item");
4771
4924
  const rest = children.filter((node) => node.scope !== "item");
4772
- return /* @__PURE__ */ jsxs10(Fragment2, { children: [
4925
+ return /* @__PURE__ */ jsxs11(Fragment2, { children: [
4773
4926
  renderItemSiblings(items, parentId, depth, containerTree, loopTreesBySessionId, viewProps),
4774
4927
  rest.map(
4775
4928
  (node) => renderContainerNode(node, containerTree, loopTreesBySessionId, viewProps, depth, ancestorVisited)
@@ -4792,7 +4945,7 @@ function renderContainerNode(node, containerTree, loopTreesBySessionId, viewProp
4792
4945
  );
4793
4946
  const hasNested = collectChildContainers(containerTree.containersById, node.container_id).length > 0;
4794
4947
  if (node.scope === "subworkflow") {
4795
- return /* @__PURE__ */ jsx16(
4948
+ return /* @__PURE__ */ jsx15(
4796
4949
  WorkflowSubworkflowContainer,
4797
4950
  {
4798
4951
  node,
@@ -4808,7 +4961,7 @@ function renderContainerNode(node, containerTree, loopTreesBySessionId, viewProp
4808
4961
  }
4809
4962
  if (node.scope === "stage") {
4810
4963
  const suppressHostScopedLoop = stageHasSubworkflowChild(node.container_id, containerTree);
4811
- return /* @__PURE__ */ jsxs10(
4964
+ return /* @__PURE__ */ jsxs11(
4812
4965
  "div",
4813
4966
  {
4814
4967
  className: "lax-workflow-nested-block",
@@ -4822,14 +4975,14 @@ function renderContainerNode(node, containerTree, loopTreesBySessionId, viewProp
4822
4975
  viewProps,
4823
4976
  { suppressHostScopedLoop }
4824
4977
  ),
4825
- hasNested ? /* @__PURE__ */ jsx16("div", { className: "lax-workflow-container-children", children: nested }) : null
4978
+ hasNested ? /* @__PURE__ */ jsx15("div", { className: "lax-workflow-container-children", children: nested }) : null
4826
4979
  ]
4827
4980
  },
4828
4981
  node.container_id
4829
4982
  );
4830
4983
  }
4831
4984
  if (node.scope === "aggregate" || node.scope === "branch") {
4832
- return /* @__PURE__ */ jsxs10("div", { className: "lax-workflow-container-children", children: [
4985
+ return /* @__PURE__ */ jsxs11("div", { className: "lax-workflow-container-children", children: [
4833
4986
  renderLeafContainer(node, depth, containerTree, loopTreesBySessionId, viewProps),
4834
4987
  hasNested ? nested : null
4835
4988
  ] }, node.container_id);
@@ -4848,9 +5001,9 @@ function renderWorkflowStageRow(node, containerTree, loopTreesBySessionId, viewP
4848
5001
  viewProps
4849
5002
  );
4850
5003
  if (as === "div") {
4851
- return /* @__PURE__ */ jsx16("div", { className, role: "listitem", children: content }, node.container_id);
5004
+ return /* @__PURE__ */ jsx15("div", { className, role: "listitem", children: content }, node.container_id);
4852
5005
  }
4853
- return /* @__PURE__ */ jsx16("li", { className, children: content }, node.container_id);
5006
+ return /* @__PURE__ */ jsx15("li", { className, children: content }, node.container_id);
4854
5007
  }
4855
5008
  function WorkflowStageListPanel({
4856
5009
  stages,
@@ -4870,11 +5023,11 @@ function WorkflowStageListPanel({
4870
5023
  scale.completedStagePageSize,
4871
5024
  partition.totalDoneCount - partition.visibleDoneCount
4872
5025
  );
4873
- return /* @__PURE__ */ jsxs10(Fragment2, { children: [
4874
- /* @__PURE__ */ jsx16("ol", { className: "lax-workflow-stage-list", "data-testid": "lax-workflow-stage-list", children: partition.visible.map(
5026
+ return /* @__PURE__ */ jsxs11(Fragment2, { children: [
5027
+ /* @__PURE__ */ jsx15("ol", { className: "lax-workflow-stage-list", "data-testid": "lax-workflow-stage-list", children: partition.visible.map(
4875
5028
  (node) => renderWorkflowStageRow(node, containerTree, loopTreesBySessionId, viewProps)
4876
5029
  ) }),
4877
- partition.hiddenCount > 0 ? /* @__PURE__ */ jsxs10(
5030
+ partition.hiddenCount > 0 ? /* @__PURE__ */ jsxs11(
4878
5031
  "button",
4879
5032
  {
4880
5033
  type: "button",
@@ -4890,7 +5043,7 @@ function WorkflowStageListPanel({
4890
5043
  ]
4891
5044
  }
4892
5045
  ) : null,
4893
- extraCompletedPages > 0 && partition.hiddenCount === 0 ? /* @__PURE__ */ jsx16(
5046
+ extraCompletedPages > 0 && partition.hiddenCount === 0 ? /* @__PURE__ */ jsx15(
4894
5047
  "button",
4895
5048
  {
4896
5049
  type: "button",
@@ -4900,7 +5053,7 @@ function WorkflowStageListPanel({
4900
5053
  children: "Show fewer completed stages"
4901
5054
  }
4902
5055
  ) : null,
4903
- partition.hiddenCount > 0 ? /* @__PURE__ */ jsxs10(
5056
+ partition.hiddenCount > 0 ? /* @__PURE__ */ jsxs11(
4904
5057
  "p",
4905
5058
  {
4906
5059
  className: "lax-workflow-stage-list__hidden-hint",
@@ -4925,8 +5078,8 @@ function renderWorkflowChildren(workflowNode, containerTree, loopTreesBySessionI
4925
5078
  const other = children.filter(
4926
5079
  (node) => node.scope !== "stage" && node.scope !== "item"
4927
5080
  );
4928
- return /* @__PURE__ */ jsxs10(Fragment2, { children: [
4929
- stages.length > 0 ? /* @__PURE__ */ jsx16(
5081
+ return /* @__PURE__ */ jsxs11(Fragment2, { children: [
5082
+ stages.length > 0 ? /* @__PURE__ */ jsx15(
4930
5083
  WorkflowStageListPanel,
4931
5084
  {
4932
5085
  stages,
@@ -4951,7 +5104,7 @@ function WorkflowChrome({
4951
5104
  const viewProps = { virtualized, virtualizeThreshold, groupParallelTools };
4952
5105
  const rootNodes = containerTree.rootContainerIds.map((id) => containerTree.containersById[id]).filter((node) => node != null);
4953
5106
  if (rootNodes.length === 0) {
4954
- return /* @__PURE__ */ jsx16("div", { className: "lax-workflow-chrome", "data-testid": "lax-workflow-chrome", children: /* @__PURE__ */ jsx16(
5107
+ return /* @__PURE__ */ jsx15("div", { className: "lax-workflow-chrome", "data-testid": "lax-workflow-chrome", children: /* @__PURE__ */ jsx15(
4955
5108
  WorkflowContainerLine,
4956
5109
  {
4957
5110
  variant: "root",
@@ -4961,7 +5114,7 @@ function WorkflowChrome({
4961
5114
  }
4962
5115
  ) });
4963
5116
  }
4964
- return /* @__PURE__ */ jsx16("div", { className: "lax-workflow-chrome", "data-testid": "lax-workflow-chrome", children: rootNodes.map((workflowNode) => /* @__PURE__ */ jsx16(
5117
+ return /* @__PURE__ */ jsx15("div", { className: "lax-workflow-chrome", "data-testid": "lax-workflow-chrome", children: rootNodes.map((workflowNode) => /* @__PURE__ */ jsx15(
4965
5118
  WorkflowRootContainer,
4966
5119
  {
4967
5120
  node: workflowNode,
@@ -4979,27 +5132,27 @@ function WorkflowChrome({
4979
5132
 
4980
5133
  // src/view/workflow/WorkflowGlobalSpinner.tsx
4981
5134
  import { useStore as useStore5 } from "zustand";
4982
- import { jsx as jsx17, jsxs as jsxs11 } from "react/jsx-runtime";
5135
+ import { jsx as jsx16, jsxs as jsxs12 } from "react/jsx-runtime";
4983
5136
  function WorkflowGlobalSpinner() {
4984
5137
  const store = useWorkflowSessionStoreApi();
4985
5138
  const show = useStore5(store, (s) => shouldShowGlobalSpinner(s.state));
4986
5139
  if (!show) return null;
4987
- return /* @__PURE__ */ jsx17(
5140
+ return /* @__PURE__ */ jsx16(
4988
5141
  "div",
4989
5142
  {
4990
5143
  className: "lax-workflow-global-spinner lax-spinner-container",
4991
5144
  "data-testid": "lax-workflow-global-spinner",
4992
5145
  role: "status",
4993
- children: /* @__PURE__ */ jsxs11("span", { className: "lax-spinner lax-workflow-global-spinner__inner", children: [
4994
- /* @__PURE__ */ jsx17("span", { className: "lax-spinner-frame", children: "\u280B" }),
4995
- /* @__PURE__ */ jsx17("span", { className: "lax-spinner-verb lax-spinner-verb--shimmer", children: "Workflow" })
5146
+ children: /* @__PURE__ */ jsxs12("span", { className: "lax-spinner lax-workflow-global-spinner__inner", children: [
5147
+ /* @__PURE__ */ jsx16("span", { className: "lax-spinner-frame", children: "\u280B" }),
5148
+ /* @__PURE__ */ jsx16("span", { className: "lax-spinner-verb lax-spinner-verb--shimmer", children: "Workflow" })
4996
5149
  ] })
4997
5150
  }
4998
5151
  );
4999
5152
  }
5000
5153
 
5001
5154
  // src/view/workflow/WorkflowSessionBanners.tsx
5002
- import { Fragment as Fragment3, jsx as jsx18, jsxs as jsxs12 } from "react/jsx-runtime";
5155
+ import { Fragment as Fragment3, jsx as jsx17, jsxs as jsxs13 } from "react/jsx-runtime";
5003
5156
  function WorkflowSessionBanners({ state }) {
5004
5157
  const banner = resolveWorkflowBanner(state);
5005
5158
  const { display } = state;
@@ -5007,8 +5160,8 @@ function WorkflowSessionBanners({ state }) {
5007
5160
  return null;
5008
5161
  }
5009
5162
  const showTransportError = (display.projectionStatus === "error" || state.internalErrors.length > 0) && banner.kind !== "projection_degraded" && banner.kind !== "authority_error";
5010
- return /* @__PURE__ */ jsxs12(Fragment3, { children: [
5011
- banner.kind === "authority_error" ? /* @__PURE__ */ jsx18(
5163
+ return /* @__PURE__ */ jsxs13(Fragment3, { children: [
5164
+ banner.kind === "authority_error" ? /* @__PURE__ */ jsx17(
5012
5165
  "div",
5013
5166
  {
5014
5167
  className: "lax-workflow-banner lax-workflow-banner--authority-error",
@@ -5017,7 +5170,7 @@ function WorkflowSessionBanners({ state }) {
5017
5170
  children: banner.message
5018
5171
  }
5019
5172
  ) : null,
5020
- banner.kind === "projection_degraded" ? /* @__PURE__ */ jsx18(
5173
+ banner.kind === "projection_degraded" ? /* @__PURE__ */ jsx17(
5021
5174
  "div",
5022
5175
  {
5023
5176
  className: "lax-workflow-banner lax-workflow-banner--projection-degraded",
@@ -5026,7 +5179,7 @@ function WorkflowSessionBanners({ state }) {
5026
5179
  children: banner.message
5027
5180
  }
5028
5181
  ) : null,
5029
- banner.kind === "snapshot_unavailable" ? /* @__PURE__ */ jsx18(
5182
+ banner.kind === "snapshot_unavailable" ? /* @__PURE__ */ jsx17(
5030
5183
  "div",
5031
5184
  {
5032
5185
  className: "lax-workflow-banner lax-workflow-banner--snapshot-unavailable",
@@ -5035,7 +5188,7 @@ function WorkflowSessionBanners({ state }) {
5035
5188
  children: banner.message
5036
5189
  }
5037
5190
  ) : null,
5038
- banner.kind === "partial_success" ? /* @__PURE__ */ jsx18(
5191
+ banner.kind === "partial_success" ? /* @__PURE__ */ jsx17(
5039
5192
  "div",
5040
5193
  {
5041
5194
  className: "lax-workflow-banner lax-workflow-banner--partial-success",
@@ -5044,23 +5197,23 @@ function WorkflowSessionBanners({ state }) {
5044
5197
  children: banner.message
5045
5198
  }
5046
5199
  ) : null,
5047
- banner.kind === "forced_closeout" || display.projectionStatus === "done_with_warning" ? /* @__PURE__ */ jsxs12(
5200
+ banner.kind === "forced_closeout" || display.projectionStatus === "done_with_warning" ? /* @__PURE__ */ jsxs13(
5048
5201
  "div",
5049
5202
  {
5050
5203
  className: "lax-workflow-closeout-warning",
5051
5204
  "data-testid": "lax-workflow-closeout-warning",
5052
5205
  role: "status",
5053
5206
  children: [
5054
- /* @__PURE__ */ jsx18("strong", { children: "Workflow forced closeout" }),
5055
- /* @__PURE__ */ jsxs12("span", { children: [
5207
+ /* @__PURE__ */ jsx17("strong", { children: "Workflow forced closeout" }),
5208
+ /* @__PURE__ */ jsxs13("span", { children: [
5056
5209
  " ",
5057
5210
  "\u2014 stream ended with unresolved child scopes; not a healthy completion."
5058
5211
  ] }),
5059
- display.openChildIdentities.length > 0 ? /* @__PURE__ */ jsx18("ul", { className: "lax-workflow-closeout-warning__scopes", children: display.openChildIdentities.map((identity) => /* @__PURE__ */ jsx18("li", { children: identity }, identity)) }) : null
5212
+ display.openChildIdentities.length > 0 ? /* @__PURE__ */ jsx17("ul", { className: "lax-workflow-closeout-warning__scopes", children: display.openChildIdentities.map((identity) => /* @__PURE__ */ jsx17("li", { children: identity }, identity)) }) : null
5060
5213
  ]
5061
5214
  }
5062
5215
  ) : null,
5063
- banner.kind === "awaiting_authority" ? /* @__PURE__ */ jsx18(
5216
+ banner.kind === "awaiting_authority" ? /* @__PURE__ */ jsx17(
5064
5217
  "div",
5065
5218
  {
5066
5219
  className: "lax-workflow-banner lax-workflow-banner--awaiting",
@@ -5069,7 +5222,7 @@ function WorkflowSessionBanners({ state }) {
5069
5222
  children: banner.message
5070
5223
  }
5071
5224
  ) : null,
5072
- banner.kind === "sync_failed" ? /* @__PURE__ */ jsx18(
5225
+ banner.kind === "sync_failed" ? /* @__PURE__ */ jsx17(
5073
5226
  "div",
5074
5227
  {
5075
5228
  className: "lax-workflow-banner lax-workflow-banner--sync-failed",
@@ -5078,7 +5231,7 @@ function WorkflowSessionBanners({ state }) {
5078
5231
  children: banner.message
5079
5232
  }
5080
5233
  ) : null,
5081
- showTransportError ? /* @__PURE__ */ jsx18(
5234
+ showTransportError ? /* @__PURE__ */ jsx17(
5082
5235
  "div",
5083
5236
  {
5084
5237
  className: "lax-workflow-error",
@@ -5163,11 +5316,11 @@ function loopSessionDisplayLabel(loopSessionId) {
5163
5316
  }
5164
5317
 
5165
5318
  // src/view/workflow/WorkflowTaskListFooter.tsx
5166
- import { jsx as jsx19, jsxs as jsxs13 } from "react/jsx-runtime";
5319
+ import { jsx as jsx18, jsxs as jsxs14 } from "react/jsx-runtime";
5167
5320
  function MessageResponse({ children }) {
5168
- return /* @__PURE__ */ jsxs13("div", { className: "lax-message-response", children: [
5169
- /* @__PURE__ */ jsx19("span", { className: "lax-message-response__marker", children: "\u23BF " }),
5170
- /* @__PURE__ */ jsx19("span", { className: "lax-message-response__content", children })
5321
+ return /* @__PURE__ */ jsxs14("div", { className: "lax-message-response", children: [
5322
+ /* @__PURE__ */ jsx18("span", { className: "lax-message-response__marker", children: "\u23BF " }),
5323
+ /* @__PURE__ */ jsx18("span", { className: "lax-message-response__content", children })
5171
5324
  ] });
5172
5325
  }
5173
5326
  function WorkflowTaskListFooter() {
@@ -5181,8 +5334,8 @@ function WorkflowTaskListFooter() {
5181
5334
  }
5182
5335
  const label = formatWorkflowTaskFooterLabel(state);
5183
5336
  const groups = groupWorkflowTasksByLoop(footerState.tasks);
5184
- return /* @__PURE__ */ jsxs13("div", { className: "lax-workflow-task-list-footer", "data-testid": "lax-workflow-task-list-footer", children: [
5185
- /* @__PURE__ */ jsxs13(
5337
+ return /* @__PURE__ */ jsxs14("div", { className: "lax-workflow-task-list-footer", "data-testid": "lax-workflow-task-list-footer", children: [
5338
+ /* @__PURE__ */ jsxs14(
5186
5339
  "button",
5187
5340
  {
5188
5341
  type: "button",
@@ -5192,18 +5345,18 @@ function WorkflowTaskListFooter() {
5192
5345
  onClick: () => setExpanded((v) => !v),
5193
5346
  children: [
5194
5347
  label,
5195
- /* @__PURE__ */ jsx19("span", { className: "lax-task-list-footer__hint", children: expanded ? " \xB7 \u2191 to hide" : " \xB7 \u2193 to view" })
5348
+ /* @__PURE__ */ jsx18("span", { className: "lax-task-list-footer__hint", children: expanded ? " \xB7 \u2191 to hide" : " \xB7 \u2193 to view" })
5196
5349
  ]
5197
5350
  }
5198
5351
  ),
5199
- expanded ? /* @__PURE__ */ jsx19(MessageResponse, { children: /* @__PURE__ */ jsx19("div", { className: "lax-workflow-task-list-groups", children: groups.map((group) => /* @__PURE__ */ jsxs13(
5352
+ expanded ? /* @__PURE__ */ jsx18(MessageResponse, { children: /* @__PURE__ */ jsx18("div", { className: "lax-workflow-task-list-groups", children: groups.map((group) => /* @__PURE__ */ jsxs14(
5200
5353
  "div",
5201
5354
  {
5202
5355
  className: "lax-workflow-task-list-group",
5203
5356
  "data-testid": `lax-workflow-task-group-${group.loopSessionId}`,
5204
5357
  children: [
5205
- /* @__PURE__ */ jsx19("div", { className: "lax-workflow-task-list-group-title", children: loopSessionDisplayLabel(group.loopSessionId) }),
5206
- /* @__PURE__ */ jsx19(TaskList, { tasks: group.tasks })
5358
+ /* @__PURE__ */ jsx18("div", { className: "lax-workflow-task-list-group-title", children: loopSessionDisplayLabel(group.loopSessionId) }),
5359
+ /* @__PURE__ */ jsx18(TaskList, { tasks: group.tasks })
5207
5360
  ]
5208
5361
  },
5209
5362
  group.loopSessionId
@@ -5213,7 +5366,7 @@ function WorkflowTaskListFooter() {
5213
5366
 
5214
5367
  // src/view/workflow/WorkflowSession.tsx
5215
5368
  import { useStore as useStore7 } from "zustand";
5216
- import { jsx as jsx20, jsxs as jsxs14 } from "react/jsx-runtime";
5369
+ import { jsx as jsx19, jsxs as jsxs15 } from "react/jsx-runtime";
5217
5370
  function WorkflowSession({
5218
5371
  source,
5219
5372
  authoritySource,
@@ -5237,7 +5390,6 @@ function WorkflowSession({
5237
5390
  virtualizeThreshold,
5238
5391
  groupParallelTools = false,
5239
5392
  workflowScale,
5240
- onRequestLoopReplay,
5241
5393
  onAuthorityTerminal,
5242
5394
  onDisplayStreamEnded,
5243
5395
  children
@@ -5248,8 +5400,7 @@ function WorkflowSession({
5248
5400
  storeRef.current = createWorkflowSessionStore(initialState, {
5249
5401
  tierOverrides,
5250
5402
  initialEventCount: initialEvents?.length ?? 0,
5251
- evictCompletedLoops: workflowScale?.evictCompletedLoops ?? DEFAULT_WORKFLOW_SCALE_OPTIONS.evictCompletedLoops,
5252
- maxHydratedCompletedLoops: workflowScale?.maxHydratedCompletedLoops ?? DEFAULT_WORKFLOW_SCALE_OPTIONS.maxHydratedCompletedLoops
5403
+ workflowScale: { ...DEFAULT_WORKFLOW_SCALE_OPTIONS, ...workflowScale }
5253
5404
  });
5254
5405
  }
5255
5406
  const store = storeRef.current;
@@ -5339,15 +5490,15 @@ function WorkflowSession({
5339
5490
  streamAbortRef.current?.abort();
5340
5491
  }
5341
5492
  }, [authorityStatus]);
5342
- return /* @__PURE__ */ jsx20(WorkflowSessionStoreContext.Provider, { value: store, children: /* @__PURE__ */ jsx20(WorkflowScaleContext.Provider, { value: scaleOptions, children: /* @__PURE__ */ jsx20(WorkflowLoopReplayProvider, { onRequestLoopReplay, children: /* @__PURE__ */ jsx20(InteractionBusContext.Provider, { value: busRef, children: /* @__PURE__ */ jsx20(NodeRegistryContext.Provider, { value: registryRef, children: /* @__PURE__ */ jsx20(MarkdownRendererContext.Provider, { value: markdownRenderer, children: /* @__PURE__ */ jsx20(ToolDisplayOptionsContext.Provider, { value: toolDisplayRef, children: /* @__PURE__ */ jsx20(SessionViewOptionsContext.Provider, { value: sessionViewRef, children: /* @__PURE__ */ jsxs14(
5493
+ return /* @__PURE__ */ jsx19(WorkflowSessionStoreContext.Provider, { value: store, children: /* @__PURE__ */ jsx19(WorkflowScaleContext.Provider, { value: scaleOptions, children: /* @__PURE__ */ jsx19(InteractionBusContext.Provider, { value: busRef, children: /* @__PURE__ */ jsx19(NodeRegistryContext.Provider, { value: registryRef, children: /* @__PURE__ */ jsx19(MarkdownRendererContext.Provider, { value: markdownRenderer, children: /* @__PURE__ */ jsx19(ToolDisplayOptionsContext.Provider, { value: toolDisplayRef, children: /* @__PURE__ */ jsx19(SessionViewOptionsContext.Provider, { value: sessionViewRef, children: /* @__PURE__ */ jsxs15(
5343
5494
  "div",
5344
5495
  {
5345
5496
  className: "lax-agent-session lax-workflow-session",
5346
5497
  "data-testid": "lax-workflow-session",
5347
5498
  children: [
5348
- /* @__PURE__ */ jsx20(WorkflowSessionBanners, { state: sessionState }),
5349
- /* @__PURE__ */ jsx20(WorkflowGlobalSpinner, {}),
5350
- /* @__PURE__ */ jsx20(
5499
+ /* @__PURE__ */ jsx19(WorkflowSessionBanners, { state: sessionState }),
5500
+ /* @__PURE__ */ jsx19(WorkflowGlobalSpinner, {}),
5501
+ /* @__PURE__ */ jsx19(
5351
5502
  WorkflowChrome,
5352
5503
  {
5353
5504
  containerTree,
@@ -5357,11 +5508,11 @@ function WorkflowSession({
5357
5508
  groupParallelTools
5358
5509
  }
5359
5510
  ),
5360
- /* @__PURE__ */ jsx20(WorkflowTaskListFooter, {}),
5511
+ /* @__PURE__ */ jsx19(WorkflowTaskListFooter, {}),
5361
5512
  children
5362
5513
  ]
5363
5514
  }
5364
- ) }) }) }) }) }) }) }) });
5515
+ ) }) }) }) }) }) }) });
5365
5516
  }
5366
5517
 
5367
5518
  // src/core/workflow/createMockAuthoritySource.ts
@@ -5524,6 +5675,21 @@ function createPollingAuthoritySource(taskId, fetchFn, options) {
5524
5675
  };
5525
5676
  }
5526
5677
 
5678
+ // src/view/workflow/workflowScalePresets.ts
5679
+ var SCALE_WORKFLOW_SCALE = {
5680
+ ...DEFAULT_WORKFLOW_SCALE_OPTIONS,
5681
+ deferEvictionUntil: "immediate"
5682
+ };
5683
+ var DEMO_WORKFLOW_SCALE = {
5684
+ ...DEFAULT_WORKFLOW_SCALE_OPTIONS,
5685
+ softEvictThreshold: 8,
5686
+ maxHydratedCompletedLoops: 8,
5687
+ deferEvictionUntil: "host-reset",
5688
+ protectExpandedLoops: true,
5689
+ onlyExpandActiveRunning: false,
5690
+ evictCompletedLoops: true
5691
+ };
5692
+
5527
5693
  // src/view/tools/groupParallelTools.ts
5528
5694
  function buildTimelineEntries(rootIds, byId, options = {}) {
5529
5695
  const filtered = options.hideStandalonePermissions ? rootIds.filter((id) => byId[id]?.kind !== "permission") : [...rootIds];
@@ -5561,18 +5727,18 @@ function buildTimelineEntries(rootIds, byId, options = {}) {
5561
5727
  }
5562
5728
 
5563
5729
  // src/view/nodes/SubAgentNode.tsx
5564
- import { jsx as jsx21, jsxs as jsxs15 } from "react/jsx-runtime";
5730
+ import { jsx as jsx20, jsxs as jsxs16 } from "react/jsx-runtime";
5565
5731
  function SubAgentBlock({ nodeId }) {
5566
5732
  const node = useNodeTyped(nodeId, "subagent");
5567
5733
  const childIds = useChildren(nodeId);
5568
5734
  const registry = useNodeRegistry();
5569
5735
  if (!node) return null;
5570
- return /* @__PURE__ */ jsxs15("div", { className: "lax-subagent-block", "data-status": node.status, children: [
5571
- /* @__PURE__ */ jsxs15("div", { className: "lax-subagent-block__header", children: [
5736
+ return /* @__PURE__ */ jsxs16("div", { className: "lax-subagent-block", "data-status": node.status, children: [
5737
+ /* @__PURE__ */ jsxs16("div", { className: "lax-subagent-block__header", children: [
5572
5738
  "SubAgent: ",
5573
5739
  node.subagentId
5574
5740
  ] }),
5575
- /* @__PURE__ */ jsx21("div", { className: "lax-subagent-block__children", children: childIds.map((childId) => /* @__PURE__ */ jsx21(TimelineItem, { nodeId: childId, registry }, childId)) })
5741
+ /* @__PURE__ */ jsx20("div", { className: "lax-subagent-block__children", children: childIds.map((childId) => /* @__PURE__ */ jsx20(TimelineItem, { nodeId: childId, registry }, childId)) })
5576
5742
  ] });
5577
5743
  }
5578
5744
 
@@ -5626,6 +5792,7 @@ export {
5626
5792
  DEFAULT_SESSION_VIEW_OPTIONS,
5627
5793
  DEFAULT_VIRTUALIZE_THRESHOLD,
5628
5794
  DEFAULT_WORKFLOW_SCALE_OPTIONS,
5795
+ DEMO_WORKFLOW_SCALE,
5629
5796
  DefaultToolBody,
5630
5797
  DiagramZoomShell,
5631
5798
  DiagramZoomView,
@@ -5659,6 +5826,7 @@ export {
5659
5826
  ReconnectBudget,
5660
5827
  RenderableTimelineProjector,
5661
5828
  RichMarkdown,
5829
+ SCALE_WORKFLOW_SCALE,
5662
5830
  SHELL_PROGRESS_MIN_ELAPSED_SECONDS,
5663
5831
  SessionTimeline,
5664
5832
  Skill,
@@ -5687,7 +5855,6 @@ export {
5687
5855
  WebSearch,
5688
5856
  WebSearchToolBody,
5689
5857
  WorkflowChrome,
5690
- WorkflowLoopReplayProvider,
5691
5858
  WorkflowScaleContext,
5692
5859
  WorkflowSession,
5693
5860
  WorkflowTaskListFooter,
@@ -5776,8 +5943,10 @@ export {
5776
5943
  resolveSseTransportPolicy,
5777
5944
  resolveToolBody,
5778
5945
  resolveWorkflowBanner,
5946
+ resolveWorkflowScale,
5779
5947
  sessionTreeSnapshotToTree,
5780
5948
  shouldApplyGrouping,
5949
+ shouldDeferEviction,
5781
5950
  shouldShowAgentSpinner,
5782
5951
  shouldShowExploreDetail,
5783
5952
  shouldShowGlobalSpinner,