langchain_agentx_stream_ui 0.1.8 → 0.1.9

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-WPW3TQQF.js";
26
+ } from "./chunk-2T26L3VT.js";
27
27
  import {
28
28
  DefaultToolBody,
29
29
  InteractionBusContext,
@@ -111,7 +111,7 @@ import {
111
111
  useSessionStatus,
112
112
  useSessionViewOptions,
113
113
  useTimeline
114
- } from "./chunk-LBJFJF22.js";
114
+ } from "./chunk-ZNXAQ4ZZ.js";
115
115
  import {
116
116
  Agent,
117
117
  AgentToolBody,
@@ -768,6 +768,30 @@ function createWorkflowRunningLoopTree(seedMs = Date.now()) {
768
768
  tree.meta.startedAt = seedMs;
769
769
  return tree;
770
770
  }
771
+ function finalizeWorkflowLoopTree(tree, terminalStatus = "done") {
772
+ if (tree.status === "done" || tree.status === "error") {
773
+ return tree;
774
+ }
775
+ const byId = { ...tree.byId };
776
+ for (const [id, node] of Object.entries(byId)) {
777
+ if (!node) continue;
778
+ if ((node.kind === "text" || node.kind === "reasoning") && node.status === "streaming") {
779
+ byId[id] = { ...node, status: "done" };
780
+ }
781
+ if (node.kind === "tool_call" && node.status === "running") {
782
+ byId[id] = {
783
+ ...node,
784
+ status: terminalStatus === "error" ? "failed" : "done"
785
+ };
786
+ }
787
+ }
788
+ return {
789
+ ...tree,
790
+ byId,
791
+ activeRoundId: null,
792
+ status: terminalStatus
793
+ };
794
+ }
771
795
 
772
796
  // src/types/workflowDisplay.ts
773
797
  function readDisplayPayload(data) {
@@ -926,7 +950,7 @@ function contentBlockFromEvent(event) {
926
950
  return null;
927
951
  }
928
952
  function resolveContentScopeKey(data) {
929
- for (const keyName of ["stage_key", "item_key", "branch_key", "debug_key"]) {
953
+ for (const keyName of ["stage_key", "item_key", "branch_key", "aggregate_key", "debug_key"]) {
930
954
  const value = readString(data, keyName);
931
955
  if (value) return value;
932
956
  }
@@ -1226,6 +1250,7 @@ function readString2(data, key) {
1226
1250
  var LOOP_TASK_OPEN_SCOPES = {
1227
1251
  "stage-start": "stage",
1228
1252
  "parallel-item-start": "item",
1253
+ "parallel-aggregate-start": "aggregate",
1229
1254
  "route-branch-start": "branch"
1230
1255
  };
1231
1256
  function buildLoopSessionId(workflowId, taskKey) {
@@ -1244,7 +1269,7 @@ function deriveLoopSessionIdFromAgentEvent(event) {
1244
1269
  const data = event.data ?? {};
1245
1270
  const workflowId = readString2(data, "workflow_id") ?? readString2(data, "workflow_path");
1246
1271
  if (!workflowId) return null;
1247
- const taskKey = readString2(data, "stage_key") ?? readString2(data, "item_key") ?? readString2(data, "branch_key");
1272
+ const taskKey = readString2(data, "stage_key") ?? readString2(data, "item_key") ?? readString2(data, "branch_key") ?? readString2(data, "aggregate_key");
1248
1273
  if (!taskKey) return null;
1249
1274
  return buildLoopSessionId(workflowId, taskKey);
1250
1275
  }
@@ -1252,6 +1277,259 @@ function loopTaskScopeForStructureOpen(eventType) {
1252
1277
  return LOOP_TASK_OPEN_SCOPES[eventType];
1253
1278
  }
1254
1279
 
1280
+ // src/core/workflow/embeddedSubworkflowUtils.ts
1281
+ function parseLoopSessionParts(sessionId) {
1282
+ const trimmed = sessionId.trim();
1283
+ const dash = trimmed.lastIndexOf("-");
1284
+ if (dash <= 0 || dash >= trimmed.length - 1) return null;
1285
+ return {
1286
+ workflowId: trimmed.slice(0, dash),
1287
+ taskKey: trimmed.slice(dash + 1)
1288
+ };
1289
+ }
1290
+ function isEmbeddedChildLoopSession(sessionId, rootWorkflowId) {
1291
+ const parts = parseLoopSessionParts(sessionId);
1292
+ if (!parts) return false;
1293
+ if (parts.workflowId === rootWorkflowId) return false;
1294
+ if (parts.workflowId.startsWith(`${rootWorkflowId}-`)) return false;
1295
+ if (rootWorkflowId.startsWith(`${parts.workflowId}-`)) return false;
1296
+ return parts.workflowId.split("-").length >= 3;
1297
+ }
1298
+ function readWorkflowIdFromData(data) {
1299
+ const value = data.workflow_id;
1300
+ return typeof value === "string" ? value : void 0;
1301
+ }
1302
+ function readStageKeyFromData(data) {
1303
+ const value = data.stage_key;
1304
+ return typeof value === "string" ? value : void 0;
1305
+ }
1306
+ function shouldPrebindLoopSessionFromStructureOpen(eventType, eventSessionId, derivedLoopSessionId, data = {}) {
1307
+ if (!eventSessionId) return true;
1308
+ if (eventType !== "stage-start") return true;
1309
+ if (eventSessionId === derivedLoopSessionId) return true;
1310
+ const rootWorkflowId = readWorkflowIdFromData(data);
1311
+ const stageKey = readStageKeyFromData(data);
1312
+ const parsed = parseLoopSessionParts(eventSessionId);
1313
+ if (rootWorkflowId && stageKey && parsed) {
1314
+ if (parsed.workflowId === rootWorkflowId && parsed.taskKey !== stageKey) {
1315
+ return false;
1316
+ }
1317
+ }
1318
+ return true;
1319
+ }
1320
+ function resolveRootWorkflow(tree) {
1321
+ const rootId = tree.rootContainerIds[0];
1322
+ if (!rootId) return null;
1323
+ const root = tree.containersById[rootId];
1324
+ if (!root || root.scope !== "workflow") return null;
1325
+ return {
1326
+ workflowId: root.scope_key,
1327
+ workflowPath: root.workflow_path
1328
+ };
1329
+ }
1330
+ function humanizeTaskTitle(taskKey) {
1331
+ if (taskKey === "aggregate") return "Merge Perspectives";
1332
+ if (taskKey === "architecture") return "Architecture Path";
1333
+ if (taskKey === "implementation") return "Implementation Path";
1334
+ return taskKey.split("_").map((part) => part ? part[0].toUpperCase() + part.slice(1) : part).join(" ");
1335
+ }
1336
+ function findEmbeddedHostStage(tree, rootWorkflowPath, childWorkflowId) {
1337
+ const childPath = `${rootWorkflowPath}>${childWorkflowId}`;
1338
+ const subId = buildContainerId(childPath, "subworkflow", childWorkflowId);
1339
+ const existingSub = tree.containersById[subId];
1340
+ if (existingSub?.parent_container_id) {
1341
+ return tree.containersById[existingSub.parent_container_id] ?? null;
1342
+ }
1343
+ const runningStages = tree.activeContainerIds.map((id) => tree.containersById[id]).filter(
1344
+ (node) => node != null && node.scope === "stage" && node.workflow_path === rootWorkflowPath && node.is_open
1345
+ );
1346
+ if (runningStages.length === 0) return null;
1347
+ return runningStages.reduce(
1348
+ (best, node) => (node.display?.progress_current ?? 0) >= (best.display?.progress_current ?? 0) ? node : best
1349
+ );
1350
+ }
1351
+ function upsertRuntimeNode(tree, node) {
1352
+ const activeContainerIds = tree.activeContainerIds.includes(node.container_id) ? tree.activeContainerIds : node.is_open ? [...tree.activeContainerIds, node.container_id] : tree.activeContainerIds;
1353
+ return {
1354
+ ...tree,
1355
+ activeContainerIds,
1356
+ containersById: {
1357
+ ...tree.containersById,
1358
+ [node.container_id]: node
1359
+ }
1360
+ };
1361
+ }
1362
+ function completeOpenItemsUnderSubworkflow(tree, subworkflowId) {
1363
+ let next = tree;
1364
+ for (const node of Object.values(tree.containersById)) {
1365
+ if (node.parent_container_id === subworkflowId && node.scope === "item" && node.status === "running") {
1366
+ next = upsertRuntimeNode(next, {
1367
+ ...node,
1368
+ status: "completed",
1369
+ is_open: false
1370
+ });
1371
+ }
1372
+ }
1373
+ const activeContainerIds = next.activeContainerIds.filter(
1374
+ (id) => next.containersById[id]?.is_open
1375
+ );
1376
+ return { ...next, activeContainerIds };
1377
+ }
1378
+ function resolveLeafScope(taskKey) {
1379
+ return taskKey === "aggregate" ? "aggregate" : "item";
1380
+ }
1381
+ function ensureEmbeddedSubworkflowContainers(tree, loopSessionId) {
1382
+ const root = resolveRootWorkflow(tree);
1383
+ const parts = parseLoopSessionParts(loopSessionId);
1384
+ if (!root || !parts || !isEmbeddedChildLoopSession(loopSessionId, root.workflowId)) {
1385
+ return tree;
1386
+ }
1387
+ const hostStage = findEmbeddedHostStage(tree, root.workflowPath, parts.workflowId);
1388
+ if (!hostStage) return tree;
1389
+ let next = tree;
1390
+ if (hostStage.loopSessionId) {
1391
+ next = upsertRuntimeNode(next, { ...hostStage, loopSessionId: null });
1392
+ }
1393
+ const childPath = `${root.workflowPath}>${parts.workflowId}`;
1394
+ const subId = buildContainerId(childPath, "subworkflow", parts.workflowId);
1395
+ let subNode = next.containersById[subId];
1396
+ if (!subNode) {
1397
+ subNode = {
1398
+ container_id: subId,
1399
+ scope: "subworkflow",
1400
+ workflow_path: childPath,
1401
+ workflow_depth: hostStage.workflow_depth + 1,
1402
+ scope_key: parts.workflowId,
1403
+ title: "Dual-Perspective Review",
1404
+ subtitle: "Nested parallel sub-workflow",
1405
+ status: "running",
1406
+ pattern: "parallelization",
1407
+ parent_container_id: hostStage.container_id,
1408
+ display: {
1409
+ title: "Dual-Perspective Review",
1410
+ description: "Nested parallel sub-workflow",
1411
+ pattern: "parallelization",
1412
+ status: "running"
1413
+ },
1414
+ content_blocks: [],
1415
+ is_open: true,
1416
+ loopSessionId: null
1417
+ };
1418
+ next = upsertRuntimeNode(next, subNode);
1419
+ }
1420
+ const leafScope = resolveLeafScope(parts.taskKey);
1421
+ const leafId = buildContainerId(childPath, leafScope, parts.taskKey);
1422
+ let leafNode = next.containersById[leafId];
1423
+ if (!leafNode) {
1424
+ leafNode = {
1425
+ container_id: leafId,
1426
+ scope: leafScope,
1427
+ workflow_path: childPath,
1428
+ workflow_depth: hostStage.workflow_depth + 1,
1429
+ scope_key: parts.taskKey,
1430
+ title: humanizeTaskTitle(parts.taskKey),
1431
+ subtitle: "",
1432
+ status: "running",
1433
+ pattern: "parallelization",
1434
+ parent_container_id: subId,
1435
+ display: {
1436
+ title: humanizeTaskTitle(parts.taskKey),
1437
+ pattern: "parallelization",
1438
+ status: "running"
1439
+ },
1440
+ content_blocks: [],
1441
+ is_open: true,
1442
+ loopSessionId: null
1443
+ };
1444
+ next = upsertRuntimeNode(next, leafNode);
1445
+ }
1446
+ if (leafScope === "aggregate") {
1447
+ next = completeOpenItemsUnderSubworkflow(next, subId);
1448
+ }
1449
+ if (leafNode.loopSessionId !== loopSessionId) {
1450
+ next = upsertRuntimeNode(next, {
1451
+ ...leafNode,
1452
+ loopSessionId,
1453
+ content_blocks: []
1454
+ });
1455
+ }
1456
+ return next;
1457
+ }
1458
+ function findContainerIdByLoopSession(tree, loopSessionId) {
1459
+ for (const [containerId, node] of Object.entries(tree.containersById)) {
1460
+ if (node.loopSessionId === loopSessionId) return containerId;
1461
+ }
1462
+ return null;
1463
+ }
1464
+ function resolveStructureOpenLoopSessionId(eventType, eventSessionId, derivedLoopSessionId, data) {
1465
+ const rootWorkflowId = readWorkflowId(data) ?? "";
1466
+ if ((eventType === "parallel-aggregate-start" || eventType === "parallel-aggregate-done" || eventType === "parallel-aggregate-failed") && eventSessionId && isEmbeddedChildLoopSession(eventSessionId, rootWorkflowId)) {
1467
+ return eventSessionId;
1468
+ }
1469
+ return derivedLoopSessionId;
1470
+ }
1471
+ var EMBEDDED_AGGREGATE_STRUCTURE_EVENTS = /* @__PURE__ */ new Set([
1472
+ "parallel-aggregate-start",
1473
+ "parallel-aggregate-done",
1474
+ "parallel-aggregate-failed"
1475
+ ]);
1476
+ function patchEmbeddedStructureEvent(event, rootWorkflowId) {
1477
+ if (!EMBEDDED_AGGREGATE_STRUCTURE_EVENTS.has(event.event_type)) {
1478
+ return event;
1479
+ }
1480
+ if (!event.session_id || !isEmbeddedChildLoopSession(event.session_id, rootWorkflowId)) {
1481
+ return event;
1482
+ }
1483
+ const parts = parseLoopSessionParts(event.session_id);
1484
+ if (!parts) return event;
1485
+ const data = event.data ?? {};
1486
+ const rootPath = readString3(data, "workflow_path") ?? rootWorkflowId;
1487
+ const childPath = `${rootPath}>${parts.workflowId}`;
1488
+ const workflowDepth = typeof data.workflow_depth === "number" ? data.workflow_depth + 1 : 1;
1489
+ return {
1490
+ ...event,
1491
+ data: {
1492
+ ...data,
1493
+ workflow_path: childPath,
1494
+ workflow_depth: workflowDepth
1495
+ }
1496
+ };
1497
+ }
1498
+ function readString3(data, key) {
1499
+ const value = data[key];
1500
+ return typeof value === "string" ? value : void 0;
1501
+ }
1502
+ function isDescendantOf(containersById, ancestorId, nodeId) {
1503
+ let current = containersById[nodeId]?.parent_container_id ?? null;
1504
+ while (current) {
1505
+ if (current === ancestorId) return true;
1506
+ current = containersById[current]?.parent_container_id ?? null;
1507
+ }
1508
+ return false;
1509
+ }
1510
+ function settleCompletedStageSubtree(tree, stageContainerId) {
1511
+ let next = tree;
1512
+ for (const node of Object.values(tree.containersById)) {
1513
+ if (node.container_id !== stageContainerId && !isDescendantOf(tree.containersById, stageContainerId, node.container_id)) {
1514
+ continue;
1515
+ }
1516
+ if (node.container_id === stageContainerId) continue;
1517
+ if (node.status === "completed" || node.status === "failed") continue;
1518
+ next = upsertRuntimeNode(next, {
1519
+ ...node,
1520
+ status: "completed",
1521
+ is_open: false
1522
+ });
1523
+ }
1524
+ const activeContainerIds = next.activeContainerIds.filter(
1525
+ (id) => next.containersById[id]?.is_open
1526
+ );
1527
+ return { ...next, activeContainerIds };
1528
+ }
1529
+ function readWorkflowId(data) {
1530
+ return readWorkflowIdFromData(data);
1531
+ }
1532
+
1255
1533
  // src/core/workflowStructureEvents.ts
1256
1534
  var WORKFLOW_STRUCTURE_EVENT_PREFIXES = [
1257
1535
  "workflow-",
@@ -1296,7 +1574,7 @@ function filterAgentLoopReplayEvents(events) {
1296
1574
  }
1297
1575
 
1298
1576
  // src/core/workflowReducer.ts
1299
- function readString3(data, key) {
1577
+ function readString4(data, key) {
1300
1578
  const value = data[key];
1301
1579
  return typeof value === "string" ? value : void 0;
1302
1580
  }
@@ -1376,23 +1654,43 @@ function applyStructureToContainerTree(tree, event) {
1376
1654
  };
1377
1655
  }
1378
1656
  function prebindLoopSessionFromStructureOpen(tree, event) {
1379
- const loopSessionId = deriveLoopSessionIdFromStructureOpen(event);
1657
+ const derivedLoopSessionId = deriveLoopSessionIdFromStructureOpen(event);
1380
1658
  const scope = loopTaskScopeForStructureOpen(event.event_type);
1381
- if (!loopSessionId || !scope) return tree;
1659
+ if (!derivedLoopSessionId || !scope) return tree;
1382
1660
  const data = event.data ?? {};
1383
- const workflowPath = readString3(data, "workflow_path") ?? "";
1661
+ let loopSessionId = resolveStructureOpenLoopSessionId(
1662
+ event.event_type,
1663
+ event.session_id,
1664
+ derivedLoopSessionId,
1665
+ data
1666
+ );
1667
+ if (!shouldPrebindLoopSessionFromStructureOpen(
1668
+ event.event_type,
1669
+ event.session_id,
1670
+ derivedLoopSessionId,
1671
+ data
1672
+ )) {
1673
+ loopSessionId = derivedLoopSessionId;
1674
+ }
1675
+ let nextTree = event.event_type === "parallel-aggregate-start" ? ensureEmbeddedSubworkflowContainers(tree, loopSessionId) : tree;
1676
+ const workflowPath = readString4(data, "workflow_path") ?? "";
1384
1677
  const scopeKey = resolveScopeKey(event.event_type, data);
1385
1678
  const containerId = buildContainerId(workflowPath, scope, scopeKey);
1386
- const node = tree.containersById[containerId];
1387
- if (!node) return tree;
1679
+ let targetId = containerId;
1680
+ const embeddedTargetId = findContainerIdByLoopSession(nextTree, loopSessionId);
1681
+ if (embeddedTargetId) {
1682
+ targetId = embeddedTargetId;
1683
+ }
1684
+ const node = nextTree.containersById[targetId];
1685
+ if (!node) return nextTree;
1388
1686
  if (node.loopSessionId === loopSessionId && node.content_blocks.length === 0) {
1389
- return tree;
1687
+ return nextTree;
1390
1688
  }
1391
1689
  return {
1392
- ...tree,
1690
+ ...nextTree,
1393
1691
  containersById: {
1394
- ...tree.containersById,
1395
- [containerId]: {
1692
+ ...nextTree.containersById,
1693
+ [targetId]: {
1396
1694
  ...node,
1397
1695
  loopSessionId,
1398
1696
  content_blocks: []
@@ -1438,10 +1736,7 @@ function enrichWorkflowRootFromStages(containersById, rootContainerIds) {
1438
1736
  };
1439
1737
  }
1440
1738
  function findContainerByLoopSession(tree, loopSessionId) {
1441
- for (const [containerId, node] of Object.entries(tree.containersById)) {
1442
- if (node.loopSessionId === loopSessionId) return containerId;
1443
- }
1444
- return null;
1739
+ return findContainerIdByLoopSession(tree, loopSessionId);
1445
1740
  }
1446
1741
  var WORKFLOW_DEFAULT_LOOP_SESSION_ID = "workflow-loop-default";
1447
1742
  function resolveAgentLoopSessionId(event, activeLoopSessionId) {
@@ -1456,22 +1751,23 @@ function resolveAgentLoopSessionId(event, activeLoopSessionId) {
1456
1751
  function bindLoopSessionToContainerTree(tree, event, activeLoopSessionId) {
1457
1752
  const sessionId = resolveAgentLoopSessionId(event, activeLoopSessionId);
1458
1753
  if (!sessionId) return tree;
1459
- if (findContainerByLoopSession(tree, sessionId)) return tree;
1754
+ let nextTree = ensureEmbeddedSubworkflowContainers(tree, sessionId);
1755
+ if (findContainerByLoopSession(nextTree, sessionId)) return nextTree;
1460
1756
  const data = event.data ?? {};
1461
- const workflowPath = readString3(data, "workflow_path") ?? null;
1757
+ const workflowPath = readString4(data, "workflow_path") ?? null;
1462
1758
  const scopeKey = resolveContentScopeKey(data);
1463
- let targetId = null;
1464
- if (scopeKey) {
1759
+ let targetId = findContainerByLoopSession(nextTree, sessionId);
1760
+ if (!targetId && scopeKey) {
1465
1761
  targetId = resolveContentTargetFromSnapshot(
1466
- containerTreeToSnapshot(tree),
1762
+ containerTreeToSnapshot(nextTree),
1467
1763
  workflowPath,
1468
1764
  scopeKey
1469
1765
  );
1470
1766
  }
1471
1767
  if (!targetId) {
1472
- for (const containerId of tree.activeContainerIds) {
1473
- const node2 = tree.containersById[containerId];
1474
- if ((node2?.scope === "item" || node2?.scope === "stage") && !node2.loopSessionId) {
1768
+ for (const containerId of nextTree.activeContainerIds) {
1769
+ const node2 = nextTree.containersById[containerId];
1770
+ if ((node2?.scope === "item" || node2?.scope === "stage" || node2?.scope === "aggregate") && !node2.loopSessionId) {
1475
1771
  targetId = containerId;
1476
1772
  break;
1477
1773
  }
@@ -1479,33 +1775,145 @@ function bindLoopSessionToContainerTree(tree, event, activeLoopSessionId) {
1479
1775
  }
1480
1776
  if (!targetId) {
1481
1777
  targetId = resolveContentTargetFromSnapshot(
1482
- containerTreeToSnapshot(tree),
1778
+ containerTreeToSnapshot(nextTree),
1483
1779
  workflowPath,
1484
1780
  null
1485
1781
  );
1486
1782
  }
1487
- if (!targetId) return tree;
1488
- const node = tree.containersById[targetId];
1489
- if (!node || node.loopSessionId) return tree;
1490
- if (node.scope !== "stage" && node.scope !== "item" && node.scope !== "branch") {
1491
- return tree;
1783
+ if (!targetId) return nextTree;
1784
+ const node = nextTree.containersById[targetId];
1785
+ if (!node || node.loopSessionId) return nextTree;
1786
+ if (node.scope !== "stage" && node.scope !== "item" && node.scope !== "branch" && node.scope !== "aggregate") {
1787
+ return nextTree;
1492
1788
  }
1493
1789
  return {
1494
- ...tree,
1790
+ ...nextTree,
1495
1791
  containersById: {
1496
- ...tree.containersById,
1792
+ ...nextTree.containersById,
1497
1793
  [targetId]: { ...node, loopSessionId: sessionId }
1498
1794
  }
1499
1795
  };
1500
1796
  }
1797
+ var LOOP_TASK_STRUCTURE_CLOSE_EVENTS = /* @__PURE__ */ new Set([
1798
+ "stage-done",
1799
+ "stage-failed",
1800
+ "parallel-item-done",
1801
+ "parallel-item-failed",
1802
+ "parallel-aggregate-done",
1803
+ "parallel-aggregate-failed",
1804
+ "route-branch-done",
1805
+ "route-branch-failed"
1806
+ ]);
1807
+ function resolveStructureCloseLoopSessionId(event) {
1808
+ const data = event.data ?? {};
1809
+ const derived = deriveLoopSessionIdFromStructureOpen(event) ?? deriveLoopSessionIdFromAgentEvent(event);
1810
+ if (!derived && !event.session_id) return null;
1811
+ if (!derived) return event.session_id ?? null;
1812
+ return resolveStructureOpenLoopSessionId(
1813
+ event.event_type,
1814
+ event.session_id,
1815
+ derived,
1816
+ data
1817
+ );
1818
+ }
1819
+ function finalizeLoopTreesForCompletedContainers(state, containerTree) {
1820
+ let loopTreesBySessionId = state.loopTreesBySessionId;
1821
+ for (const node of Object.values(containerTree.containersById)) {
1822
+ if (!node.loopSessionId) continue;
1823
+ if (node.status !== "completed" && node.status !== "failed") continue;
1824
+ const loopTree = loopTreesBySessionId[node.loopSessionId];
1825
+ if (!loopTree || loopTree.status === "done" || loopTree.status === "error") continue;
1826
+ loopTreesBySessionId = {
1827
+ ...loopTreesBySessionId,
1828
+ [node.loopSessionId]: finalizeWorkflowLoopTree(
1829
+ loopTree,
1830
+ node.status === "failed" ? "error" : "done"
1831
+ )
1832
+ };
1833
+ }
1834
+ return { ...state, loopTreesBySessionId };
1835
+ }
1836
+ function clearActiveLoopIfFinalized(state) {
1837
+ const activeId = state.activeLoopSessionId;
1838
+ if (!activeId) return state;
1839
+ const loop = state.loopTreesBySessionId[activeId];
1840
+ if (loop && (loop.status === "done" || loop.status === "error")) {
1841
+ return { ...state, activeLoopSessionId: null };
1842
+ }
1843
+ return state;
1844
+ }
1845
+ function resolveRootWorkflowId(containerTree) {
1846
+ const rootId = containerTree.rootContainerIds[0];
1847
+ const root = rootId ? containerTree.containersById[rootId] : void 0;
1848
+ return root?.scope === "workflow" ? root.scope_key : null;
1849
+ }
1850
+ function findContainerForLoopSession(tree, loopSessionId) {
1851
+ return Object.values(tree.containersById).find(
1852
+ (node) => node.loopSessionId === loopSessionId
1853
+ );
1854
+ }
1855
+ function reconcileLoopTreeWithContainerStatus(containerTree, loopSessionId, loopTree) {
1856
+ const container = findContainerForLoopSession(containerTree, loopSessionId);
1857
+ if (!container) return loopTree;
1858
+ if (container.status === "completed") {
1859
+ return finalizeWorkflowLoopTree(loopTree, "done");
1860
+ }
1861
+ if (container.status === "failed") {
1862
+ return finalizeWorkflowLoopTree(loopTree, "error");
1863
+ }
1864
+ return loopTree;
1865
+ }
1866
+ function finalizeLoopTreeOnStructureClose(state, event) {
1867
+ if (!LOOP_TASK_STRUCTURE_CLOSE_EVENTS.has(event.event_type)) {
1868
+ return state;
1869
+ }
1870
+ const loopSessionId = resolveStructureCloseLoopSessionId(event);
1871
+ if (!loopSessionId) return state;
1872
+ const loopTree = state.loopTreesBySessionId[loopSessionId];
1873
+ if (!loopTree) return state;
1874
+ const terminalStatus = event.event_type.endsWith("-failed") ? "error" : "done";
1875
+ return {
1876
+ ...state,
1877
+ loopTreesBySessionId: {
1878
+ ...state.loopTreesBySessionId,
1879
+ [loopSessionId]: finalizeWorkflowLoopTree(loopTree, terminalStatus)
1880
+ }
1881
+ };
1882
+ }
1501
1883
  function applyStructureEvent(state, event) {
1502
- let containerTree = applyStructureToContainerTree(state.containerTree, event);
1503
- containerTree = prebindLoopSessionFromStructureOpen(containerTree, event);
1504
- const loopSessionId = deriveLoopSessionIdFromStructureOpen(event);
1884
+ const rootWorkflowId = resolveRootWorkflowId(state.containerTree);
1885
+ const projectedEvent = rootWorkflowId != null ? patchEmbeddedStructureEvent(event, rootWorkflowId) : event;
1886
+ let containerTree = applyStructureToContainerTree(state.containerTree, projectedEvent);
1887
+ const derivedLoopSessionId = deriveLoopSessionIdFromStructureOpen(projectedEvent);
1888
+ const structureData = projectedEvent.data ?? {};
1889
+ const structureLoopSessionId = derivedLoopSessionId ? resolveStructureOpenLoopSessionId(
1890
+ projectedEvent.event_type,
1891
+ projectedEvent.session_id,
1892
+ derivedLoopSessionId,
1893
+ structureData
1894
+ ) : null;
1895
+ if (structureLoopSessionId) {
1896
+ containerTree = ensureEmbeddedSubworkflowContainers(containerTree, structureLoopSessionId);
1897
+ }
1898
+ containerTree = prebindLoopSessionFromStructureOpen(containerTree, projectedEvent);
1899
+ if (projectedEvent.event_type === "stage-done" || projectedEvent.event_type === "stage-failed") {
1900
+ const stageKey = readString4(structureData, "stage_key");
1901
+ const workflowPath = readString4(structureData, "workflow_path") ?? "";
1902
+ if (stageKey) {
1903
+ const stageId = buildContainerId(workflowPath, "stage", stageKey);
1904
+ if (containerTree.containersById[stageId]) {
1905
+ containerTree = settleCompletedStageSubtree(containerTree, stageId);
1906
+ }
1907
+ }
1908
+ }
1909
+ const loopSessionId = structureLoopSessionId ?? derivedLoopSessionId;
1505
1910
  let nextState = { ...state, containerTree };
1506
1911
  if (loopSessionId) {
1507
1912
  nextState = ensureLoopTree(nextState, loopSessionId);
1508
1913
  }
1914
+ nextState = finalizeLoopTreeOnStructureClose(nextState, projectedEvent);
1915
+ nextState = finalizeLoopTreesForCompletedContainers(nextState, containerTree);
1916
+ nextState = clearActiveLoopIfFinalized(nextState);
1509
1917
  const workflowProgress = syncWorkflowProgressFromContainerTree(
1510
1918
  containerTree,
1511
1919
  state.workflowProgress
@@ -1547,7 +1955,12 @@ function reduceWorkflowSession(state, event, eventIndex, options) {
1547
1955
  const loopSessionId2 = taskListId ?? event.session_id ?? "workflow-loop-default";
1548
1956
  let next2 = ensureLoopTree(state, loopSessionId2);
1549
1957
  const loopTree2 = next2.loopTreesBySessionId[loopSessionId2];
1550
- const reducedLoop2 = reduceTree(loopTree2, event, eventIndex, options);
1958
+ let reducedLoop2 = reduceTree(loopTree2, event, eventIndex, options);
1959
+ reducedLoop2 = reconcileLoopTreeWithContainerStatus(
1960
+ next2.containerTree,
1961
+ loopSessionId2,
1962
+ reducedLoop2
1963
+ );
1551
1964
  return {
1552
1965
  ...next2,
1553
1966
  loopTreesBySessionId: {
@@ -1569,7 +1982,12 @@ function reduceWorkflowSession(state, event, eventIndex, options) {
1569
1982
  containerTree = applyStructureToContainerTree(containerTree, event);
1570
1983
  let next = ensureLoopTree({ ...state, containerTree }, loopSessionId);
1571
1984
  const loopTree = next.loopTreesBySessionId[loopSessionId];
1572
- const reducedLoop = reduceTree(loopTree, event, eventIndex, options);
1985
+ let reducedLoop = reduceTree(loopTree, event, eventIndex, options);
1986
+ reducedLoop = reconcileLoopTreeWithContainerStatus(
1987
+ next.containerTree,
1988
+ loopSessionId,
1989
+ reducedLoop
1990
+ );
1573
1991
  const workflowProgress = syncWorkflowProgressFromContainerTree(
1574
1992
  next.containerTree,
1575
1993
  next.workflowProgress
@@ -1998,6 +2416,17 @@ function WorkflowExpandTrigger({
1998
2416
  );
1999
2417
  }
2000
2418
 
2419
+ // src/view/workflow/WorkflowMarkdownPreview.tsx
2420
+ import { jsx as jsx7 } from "react/jsx-runtime";
2421
+ function WorkflowMarkdownPreview({
2422
+ content,
2423
+ testId,
2424
+ className = "lax-workflow-markdown-preview"
2425
+ }) {
2426
+ if (!content.trim()) return null;
2427
+ return /* @__PURE__ */ jsx7("div", { className, "data-testid": testId, children: /* @__PURE__ */ jsx7(RichMarkdown, { content, deferDiagrams: true }) });
2428
+ }
2429
+
2001
2430
  // src/view/workflow/workflowContainerLineUtils.ts
2002
2431
  function formatContainerScopeMetaLabel(scope) {
2003
2432
  return scope;
@@ -2123,12 +2552,11 @@ function mapAggregateUiStatus(node) {
2123
2552
  }
2124
2553
 
2125
2554
  // src/view/workflow/WorkflowAggregateContainer.tsx
2126
- import { jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
2127
- function mergeTeaser(node) {
2555
+ import { jsx as jsx8, jsxs as jsxs4 } from "react/jsx-runtime";
2556
+ function mergeContentPreview(node) {
2128
2557
  const blocks = node.content_blocks;
2129
2558
  if (blocks.length === 0) return "";
2130
- const last = blocks[blocks.length - 1];
2131
- return last?.preview ?? "";
2559
+ return blocks.map((block) => block.preview?.trim() ?? "").filter(Boolean).join("\n\n");
2132
2560
  }
2133
2561
  function WorkflowAggregateContainer({
2134
2562
  node,
@@ -2142,8 +2570,8 @@ function WorkflowAggregateContainer({
2142
2570
  const isRunning = node.status === "running" || node.status === "retrying";
2143
2571
  const isWaiting = node.status === "pending" || node.status === "blocked";
2144
2572
  const isDone = node.status === "completed" || node.status === "failed";
2145
- const teaser = useMemo2(() => mergeTeaser(node), [node]);
2146
- const waitingTeaser = isWaiting ? teaser || node.subtitle || "" : "";
2573
+ const contentPreview = useMemo2(() => mergeContentPreview(node), [node]);
2574
+ const waitingTeaser = isWaiting ? contentPreview || node.subtitle || "" : "";
2147
2575
  const testId = `lax-workflow-aggregate-${node.scope_key}`;
2148
2576
  const uiStatus = mapAggregateUiStatus(node);
2149
2577
  const statusLabel = buildAggregateStatusLabel(node, siblingItems);
@@ -2156,6 +2584,14 @@ function WorkflowAggregateContainer({
2156
2584
  setExpanded((prev) => !prev);
2157
2585
  }, []);
2158
2586
  const shellToggle = isRunning ? toggleExpanded : isDone && expanded ? toggleExpanded : void 0;
2587
+ const markdownPreview = contentPreview ? /* @__PURE__ */ jsx8(
2588
+ WorkflowMarkdownPreview,
2589
+ {
2590
+ content: contentPreview,
2591
+ testId: `${testId}-markdown`,
2592
+ className: "lax-workflow-aggregate__markdown lax-workflow-markdown-preview"
2593
+ }
2594
+ ) : null;
2159
2595
  return /* @__PURE__ */ jsxs4(
2160
2596
  "div",
2161
2597
  {
@@ -2164,7 +2600,7 @@ function WorkflowAggregateContainer({
2164
2600
  "data-container-scope": "aggregate",
2165
2601
  style: { "--lax-workflow-depth": depth },
2166
2602
  children: [
2167
- /* @__PURE__ */ jsx7(
2603
+ /* @__PURE__ */ jsx8(
2168
2604
  WorkflowContainerLine,
2169
2605
  {
2170
2606
  title: node.title,
@@ -2180,10 +2616,16 @@ function WorkflowAggregateContainer({
2180
2616
  }
2181
2617
  ),
2182
2618
  isWaiting && waitingTeaser ? /* @__PURE__ */ jsxs4("div", { className: "lax-workflow-aggregate__waiting-teaser", "data-testid": `${testId}-waiting`, children: [
2183
- "\u23BF ",
2184
- waitingTeaser
2619
+ /* @__PURE__ */ jsx8("span", { className: "lax-workflow-aggregate__waiting-prefix", children: "\u23BF " }),
2620
+ /* @__PURE__ */ jsx8(
2621
+ WorkflowMarkdownPreview,
2622
+ {
2623
+ content: waitingTeaser,
2624
+ className: "lax-workflow-aggregate__markdown lax-workflow-markdown-preview"
2625
+ }
2626
+ )
2185
2627
  ] }) : null,
2186
- expanded && isRunning && loopTree ? /* @__PURE__ */ jsx7("div", { className: "lax-workflow-stage-container__body", "data-testid": `${testId}-body`, children: /* @__PURE__ */ jsx7(
2628
+ expanded && isRunning && loopTree ? /* @__PURE__ */ jsx8("div", { className: "lax-workflow-stage-container__body", "data-testid": `${testId}-body`, children: /* @__PURE__ */ jsx8(
2187
2629
  AgentLoopView,
2188
2630
  {
2189
2631
  tree: loopTree,
@@ -2193,18 +2635,28 @@ function WorkflowAggregateContainer({
2193
2635
  groupParallelTools
2194
2636
  }
2195
2637
  ) }) : null,
2196
- isDone && !expanded ? /* @__PURE__ */ jsx7(
2197
- WorkflowExpandTrigger,
2638
+ expanded && isRunning && !loopTree && contentPreview ? /* @__PURE__ */ jsx8(
2639
+ "div",
2198
2640
  {
2199
- summary: `${node.title} \xB7 done`,
2200
- teaser: teaser || void 0,
2201
- onToggle: () => setExpanded(true),
2202
- expanded: false,
2203
- testId: `${testId}-done`,
2204
- teaserTestId: `${testId}-teaser`
2641
+ className: "lax-workflow-stage-container__body lax-workflow-stage-container__content-preview",
2642
+ "data-testid": `${testId}-body`,
2643
+ children: markdownPreview
2205
2644
  }
2206
2645
  ) : null,
2207
- isDone && expanded && loopTree ? /* @__PURE__ */ jsx7("div", { className: "lax-workflow-stage-container__body", "data-testid": `${testId}-body`, children: /* @__PURE__ */ jsx7(
2646
+ isDone && !expanded ? /* @__PURE__ */ jsxs4("div", { className: "lax-workflow-aggregate__done", "data-testid": `${testId}-done`, children: [
2647
+ /* @__PURE__ */ jsx8(
2648
+ WorkflowExpandTrigger,
2649
+ {
2650
+ summary: `${node.title} \xB7 done`,
2651
+ onToggle: () => setExpanded(true),
2652
+ expanded: false,
2653
+ expandHint: contentPreview ? "(click to expand)" : void 0,
2654
+ testId: `${testId}-done-trigger`
2655
+ }
2656
+ ),
2657
+ markdownPreview ? /* @__PURE__ */ jsx8("div", { className: "lax-workflow-aggregate__done-preview", "data-testid": `${testId}-teaser`, children: markdownPreview }) : null
2658
+ ] }) : null,
2659
+ isDone && expanded && loopTree ? /* @__PURE__ */ jsx8("div", { className: "lax-workflow-stage-container__body", "data-testid": `${testId}-body`, children: /* @__PURE__ */ jsx8(
2208
2660
  AgentLoopView,
2209
2661
  {
2210
2662
  tree: loopTree,
@@ -2213,7 +2665,15 @@ function WorkflowAggregateContainer({
2213
2665
  virtualizeThreshold,
2214
2666
  groupParallelTools
2215
2667
  }
2216
- ) }) : null
2668
+ ) }) : null,
2669
+ isDone && expanded && !loopTree && contentPreview ? /* @__PURE__ */ jsx8(
2670
+ "div",
2671
+ {
2672
+ className: "lax-workflow-stage-container__body lax-workflow-stage-container__content-preview",
2673
+ "data-testid": `${testId}-body`,
2674
+ children: markdownPreview
2675
+ }
2676
+ ) : null
2217
2677
  ]
2218
2678
  }
2219
2679
  );
@@ -2297,7 +2757,7 @@ function hasTimelineNodes(tree) {
2297
2757
  }
2298
2758
 
2299
2759
  // src/view/workflow/workflowStageDoneBody.tsx
2300
- import { jsx as jsx8 } from "react/jsx-runtime";
2760
+ import { jsx as jsx9 } from "react/jsx-runtime";
2301
2761
  function WorkflowStageDoneBody({
2302
2762
  loopTree,
2303
2763
  testId,
@@ -2307,7 +2767,7 @@ function WorkflowStageDoneBody({
2307
2767
  bodyClassName = "lax-workflow-stage-container__body"
2308
2768
  }) {
2309
2769
  if (loopTree && hasTimelineNodes(loopTree)) {
2310
- return /* @__PURE__ */ jsx8("div", { className: bodyClassName, "data-testid": testId, children: /* @__PURE__ */ jsx8(
2770
+ return /* @__PURE__ */ jsx9("div", { className: bodyClassName, "data-testid": testId, children: /* @__PURE__ */ jsx9(
2311
2771
  AgentLoopView,
2312
2772
  {
2313
2773
  tree: loopTree,
@@ -2318,12 +2778,12 @@ function WorkflowStageDoneBody({
2318
2778
  }
2319
2779
  ) });
2320
2780
  }
2321
- return /* @__PURE__ */ jsx8(
2781
+ return /* @__PURE__ */ jsx9(
2322
2782
  "div",
2323
2783
  {
2324
2784
  className: `${bodyClassName} lax-workflow-stage-container__empty-hint`,
2325
2785
  "data-testid": testId,
2326
- 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" })
2786
+ 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" })
2327
2787
  }
2328
2788
  );
2329
2789
  }
@@ -2367,7 +2827,7 @@ function isActiveWorkflowContainer(node, activeLoopSessionId, activeContainerIds
2367
2827
  }
2368
2828
 
2369
2829
  // src/view/workflow/WorkflowStageContainer.tsx
2370
- import { jsx as jsx9, jsxs as jsxs5 } from "react/jsx-runtime";
2830
+ import { jsx as jsx10, jsxs as jsxs5 } from "react/jsx-runtime";
2371
2831
  function containerTestId(node) {
2372
2832
  if (node.scope === "item") return `lax-workflow-parallel-${node.scope_key}`;
2373
2833
  if (node.scope === "stage") return `lax-workflow-stage-${node.scope_key}`;
@@ -2470,7 +2930,7 @@ function WorkflowStageContainer({
2470
2930
  "--lax-workflow-indent-unit": workflowIndentUnit(depth)
2471
2931
  },
2472
2932
  children: [
2473
- /* @__PURE__ */ jsx9(
2933
+ /* @__PURE__ */ jsx10(
2474
2934
  WorkflowContainerLine,
2475
2935
  {
2476
2936
  title: displayTitle,
@@ -2488,7 +2948,7 @@ function WorkflowStageContainer({
2488
2948
  }
2489
2949
  ),
2490
2950
  isDone && !expanded && (teaserText || expandHint) ? /* @__PURE__ */ jsxs5("div", { className: "lax-workflow-stage-container__done-teaser", children: [
2491
- teaserText ? /* @__PURE__ */ jsx9(
2951
+ teaserText ? /* @__PURE__ */ jsx10(
2492
2952
  "span",
2493
2953
  {
2494
2954
  className: "lax-workflow-stage-container__done-teaser-line",
@@ -2496,14 +2956,14 @@ function WorkflowStageContainer({
2496
2956
  children: `\u23BF ${teaserText}`
2497
2957
  }
2498
2958
  ) : null,
2499
- expandHint ? /* @__PURE__ */ jsx9("span", { className: "lax-workflow-expand-trigger__hint", children: expandHint }) : null
2959
+ expandHint ? /* @__PURE__ */ jsx10("span", { className: "lax-workflow-expand-trigger__hint", children: expandHint }) : null
2500
2960
  ] }) : null,
2501
- expanded && isRunning && !usesScopedLoop && node.content_blocks.length > 0 ? /* @__PURE__ */ jsx9(
2961
+ expanded && isRunning && !usesScopedLoop && node.content_blocks.length > 0 ? /* @__PURE__ */ jsx10(
2502
2962
  "div",
2503
2963
  {
2504
2964
  className: "lax-workflow-stage-container__body lax-workflow-stage-container__content-preview",
2505
2965
  "data-testid": bodyTestId(node),
2506
- children: node.content_blocks.map((block, index) => /* @__PURE__ */ jsx9(
2966
+ children: node.content_blocks.map((block, index) => /* @__PURE__ */ jsx10(
2507
2967
  "div",
2508
2968
  {
2509
2969
  className: "lax-workflow-stage-container__teaser",
@@ -2513,12 +2973,12 @@ function WorkflowStageContainer({
2513
2973
  ))
2514
2974
  }
2515
2975
  ) : null,
2516
- expanded && isRunning && runningLoopTree ? /* @__PURE__ */ jsx9(
2976
+ expanded && isRunning && runningLoopTree ? /* @__PURE__ */ jsx10(
2517
2977
  "div",
2518
2978
  {
2519
2979
  className: isItem ? "lax-workflow-parallel-item__body lax-workflow-stage-container__body" : "lax-workflow-stage-container__body",
2520
2980
  "data-testid": bodyTestId(node),
2521
- children: /* @__PURE__ */ jsx9(
2981
+ children: /* @__PURE__ */ jsx10(
2522
2982
  AgentLoopView,
2523
2983
  {
2524
2984
  tree: runningLoopTree,
@@ -2530,7 +2990,7 @@ function WorkflowStageContainer({
2530
2990
  )
2531
2991
  }
2532
2992
  ) : null,
2533
- isDone && expanded ? loopTree ? /* @__PURE__ */ jsx9(
2993
+ isDone && expanded ? loopTree ? /* @__PURE__ */ jsx10(
2534
2994
  WorkflowStageDoneBody,
2535
2995
  {
2536
2996
  node,
@@ -2547,8 +3007,8 @@ function WorkflowStageContainer({
2547
3007
  className: "lax-workflow-stage-container__body lax-workflow-loop-replay-pending",
2548
3008
  "data-testid": bodyTestId(node),
2549
3009
  children: [
2550
- teaserText ? /* @__PURE__ */ jsx9("p", { className: "lax-workflow-stage-container__teaser", children: teaserText }) : null,
2551
- /* @__PURE__ */ jsx9("p", { className: "lax-workflow-loop-replay-pending__hint", children: replayHandler ? "Loading loop details\u2026" : "Loop details evicted from memory." })
3010
+ teaserText ? /* @__PURE__ */ jsx10("p", { className: "lax-workflow-stage-container__teaser", children: teaserText }) : null,
3011
+ /* @__PURE__ */ jsx10("p", { className: "lax-workflow-loop-replay-pending__hint", children: replayHandler ? "Loading loop details\u2026" : "Loop details evicted from memory." })
2552
3012
  ]
2553
3013
  }
2554
3014
  ) : null
@@ -2558,7 +3018,7 @@ function WorkflowStageContainer({
2558
3018
  }
2559
3019
 
2560
3020
  // src/view/workflow/WorkflowParallelGroup.tsx
2561
- import { jsx as jsx10, jsxs as jsxs6 } from "react/jsx-runtime";
3021
+ import { jsx as jsx11, jsxs as jsxs6 } from "react/jsx-runtime";
2562
3022
  function resolveLoopTree(node, loopTreesBySessionId) {
2563
3023
  if (!node.loopSessionId) return void 0;
2564
3024
  return loopTreesBySessionId[node.loopSessionId];
@@ -2612,7 +3072,7 @@ function WorkflowParallelGroup({
2612
3072
  }, []);
2613
3073
  const renderItem = (index) => {
2614
3074
  const item = items[index];
2615
- return /* @__PURE__ */ jsx10(
3075
+ return /* @__PURE__ */ jsx11(
2616
3076
  WorkflowStageContainer,
2617
3077
  {
2618
3078
  node: item,
@@ -2631,7 +3091,7 @@ function WorkflowParallelGroup({
2631
3091
  className: "lax-workflow-parallel-group",
2632
3092
  "data-testid": `lax-workflow-parallel-group-${groupKey}`,
2633
3093
  children: [
2634
- /* @__PURE__ */ jsx10(
3094
+ /* @__PURE__ */ jsx11(
2635
3095
  WorkflowExpandTrigger,
2636
3096
  {
2637
3097
  summary,
@@ -2642,14 +3102,14 @@ function WorkflowParallelGroup({
2642
3102
  className: "lax-workflow-parallel-group__summary"
2643
3103
  }
2644
3104
  ),
2645
- expanded ? /* @__PURE__ */ jsx10("div", { className: "lax-workflow-parallel-list", "data-testid": "lax-workflow-parallel-list", children: items.map((_, index) => renderItem(index)) }) : null
3105
+ expanded ? /* @__PURE__ */ jsx11("div", { className: "lax-workflow-parallel-list", "data-testid": "lax-workflow-parallel-list", children: items.map((_, index) => renderItem(index)) }) : null
2646
3106
  ]
2647
3107
  }
2648
3108
  );
2649
3109
  }
2650
3110
 
2651
3111
  // src/view/workflow/WorkflowRootContainer.tsx
2652
- import { jsx as jsx11, jsxs as jsxs7 } from "react/jsx-runtime";
3112
+ import { jsx as jsx12, jsxs as jsxs7 } from "react/jsx-runtime";
2653
3113
  function WorkflowRootContainer({
2654
3114
  node,
2655
3115
  children
@@ -2658,7 +3118,7 @@ function WorkflowRootContainer({
2658
3118
  const uiStatus = mapContainerUiStatus(node.status);
2659
3119
  const statusLabel = mapWorkflowRootStatusLabel(node.status);
2660
3120
  return /* @__PURE__ */ jsxs7("div", { className: "lax-workflow-root", "data-testid": "lax-workflow-root", children: [
2661
- /* @__PURE__ */ jsx11(
3121
+ /* @__PURE__ */ jsx12(
2662
3122
  WorkflowContainerLine,
2663
3123
  {
2664
3124
  variant: "root",
@@ -2673,13 +3133,13 @@ function WorkflowRootContainer({
2673
3133
  verbose
2674
3134
  }
2675
3135
  ),
2676
- children ? /* @__PURE__ */ jsx11("div", { className: "lax-workflow-container-tree", children }) : null
3136
+ children ? /* @__PURE__ */ jsx12("div", { className: "lax-workflow-container-tree", children }) : null
2677
3137
  ] });
2678
3138
  }
2679
3139
 
2680
3140
  // src/view/workflow/WorkflowRouteContainer.tsx
2681
3141
  import { useCallback as useCallback4, useEffect as useEffect6, useMemo as useMemo5, useState as useState4 } from "react";
2682
- import { jsx as jsx12, jsxs as jsxs8 } from "react/jsx-runtime";
3142
+ import { jsx as jsx13, jsxs as jsxs8 } from "react/jsx-runtime";
2683
3143
  function WorkflowRouteContainer({
2684
3144
  node,
2685
3145
  loopTree,
@@ -2725,7 +3185,7 @@ function WorkflowRouteContainer({
2725
3185
  "data-container-scope": "branch",
2726
3186
  style: depthStyle,
2727
3187
  children: [
2728
- /* @__PURE__ */ jsx12(
3188
+ /* @__PURE__ */ jsx13(
2729
3189
  WorkflowContainerLine,
2730
3190
  {
2731
3191
  title: node.title,
@@ -2740,7 +3200,7 @@ function WorkflowRouteContainer({
2740
3200
  descriptionTestId: `${testId}-desc`
2741
3201
  }
2742
3202
  ),
2743
- !isSkipped && expanded && isRunning && loopTree ? /* @__PURE__ */ jsx12("div", { className: "lax-workflow-stage-container__body", "data-testid": `${testId}-body`, children: /* @__PURE__ */ jsx12(
3203
+ !isSkipped && expanded && isRunning && loopTree ? /* @__PURE__ */ jsx13("div", { className: "lax-workflow-stage-container__body", "data-testid": `${testId}-body`, children: /* @__PURE__ */ jsx13(
2744
3204
  AgentLoopView,
2745
3205
  {
2746
3206
  tree: loopTree,
@@ -2750,7 +3210,7 @@ function WorkflowRouteContainer({
2750
3210
  groupParallelTools
2751
3211
  }
2752
3212
  ) }) : null,
2753
- !isSkipped && isDone && !expanded ? /* @__PURE__ */ jsx12(
3213
+ !isSkipped && isDone && !expanded ? /* @__PURE__ */ jsx13(
2754
3214
  WorkflowExpandTrigger,
2755
3215
  {
2756
3216
  summary: `${node.title} \xB7 ${doneLabel}`,
@@ -2762,7 +3222,7 @@ function WorkflowRouteContainer({
2762
3222
  teaserTestId: teaserText ? `${testId}-teaser` : void 0
2763
3223
  }
2764
3224
  ) : null,
2765
- !isSkipped && isDone && expanded ? /* @__PURE__ */ jsx12(
3225
+ !isSkipped && isDone && expanded ? /* @__PURE__ */ jsx13(
2766
3226
  WorkflowStageDoneBody,
2767
3227
  {
2768
3228
  node,
@@ -2780,7 +3240,7 @@ function WorkflowRouteContainer({
2780
3240
 
2781
3241
  // src/view/workflow/WorkflowSubworkflowContainer.tsx
2782
3242
  import { useCallback as useCallback5, useEffect as useEffect7, useMemo as useMemo6, useState as useState5 } from "react";
2783
- import { jsx as jsx13, jsxs as jsxs9 } from "react/jsx-runtime";
3243
+ import { jsx as jsx14, jsxs as jsxs9 } from "react/jsx-runtime";
2784
3244
  function buildDoneSummary(node) {
2785
3245
  const display = node.display;
2786
3246
  if (display?.progress_total != null) {
@@ -2826,7 +3286,7 @@ function WorkflowSubworkflowContainer({
2826
3286
  "data-container-scope": "subworkflow",
2827
3287
  style: depthStyle,
2828
3288
  children: [
2829
- showShellLine ? /* @__PURE__ */ jsx13(
3289
+ showShellLine ? /* @__PURE__ */ jsx14(
2830
3290
  WorkflowContainerLine,
2831
3291
  {
2832
3292
  variant: "root",
@@ -2844,7 +3304,7 @@ function WorkflowSubworkflowContainer({
2844
3304
  verbose
2845
3305
  }
2846
3306
  ) : null,
2847
- expanded && children ? /* @__PURE__ */ jsx13(
3307
+ expanded && children ? /* @__PURE__ */ jsx14(
2848
3308
  "div",
2849
3309
  {
2850
3310
  className: "lax-workflow-subworkflow-boundary",
@@ -2853,7 +3313,7 @@ function WorkflowSubworkflowContainer({
2853
3313
  children
2854
3314
  }
2855
3315
  ) : null,
2856
- isDone && !expanded ? /* @__PURE__ */ jsx13(
3316
+ isDone && !expanded ? /* @__PURE__ */ jsx14(
2857
3317
  WorkflowExpandTrigger,
2858
3318
  {
2859
3319
  summary: `${node.title} \xB7 ${buildDoneSummary(node)}`,
@@ -2871,7 +3331,7 @@ function WorkflowSubworkflowContainer({
2871
3331
  }
2872
3332
 
2873
3333
  // src/view/workflow/WorkflowChrome.tsx
2874
- import { Fragment as Fragment2, jsx as jsx14, jsxs as jsxs10 } from "react/jsx-runtime";
3334
+ import { Fragment as Fragment2, jsx as jsx15, jsxs as jsxs10 } from "react/jsx-runtime";
2875
3335
  function collectChildContainers(containersById, parentId) {
2876
3336
  return Object.values(containersById).filter((node) => node.parent_container_id === parentId).sort((a, b) => a.scope_key.localeCompare(b.scope_key));
2877
3337
  }
@@ -2889,7 +3349,7 @@ function renderLeafContainer(node, depth, containerTree, loopTreesBySessionId, v
2889
3349
  const loopTree = resolveLoopTree2(node, loopTreesBySessionId);
2890
3350
  switch (node.scope) {
2891
3351
  case "aggregate":
2892
- return /* @__PURE__ */ jsx14(
3352
+ return /* @__PURE__ */ jsx15(
2893
3353
  WorkflowAggregateContainer,
2894
3354
  {
2895
3355
  node,
@@ -2901,7 +3361,7 @@ function renderLeafContainer(node, depth, containerTree, loopTreesBySessionId, v
2901
3361
  node.container_id
2902
3362
  );
2903
3363
  case "branch":
2904
- return /* @__PURE__ */ jsx14(
3364
+ return /* @__PURE__ */ jsx15(
2905
3365
  WorkflowRouteContainer,
2906
3366
  {
2907
3367
  node,
@@ -2912,7 +3372,7 @@ function renderLeafContainer(node, depth, containerTree, loopTreesBySessionId, v
2912
3372
  node.container_id
2913
3373
  );
2914
3374
  default:
2915
- return /* @__PURE__ */ jsx14(
3375
+ return /* @__PURE__ */ jsx15(
2916
3376
  WorkflowStageContainer,
2917
3377
  {
2918
3378
  node,
@@ -2926,7 +3386,7 @@ function renderLeafContainer(node, depth, containerTree, loopTreesBySessionId, v
2926
3386
  }
2927
3387
  function renderItemSiblings(items, groupKey, depth, containerTree, loopTreesBySessionId, viewProps) {
2928
3388
  if (items.length >= 2) {
2929
- return /* @__PURE__ */ jsx14(
3389
+ return /* @__PURE__ */ jsx15(
2930
3390
  WorkflowParallelGroup,
2931
3391
  {
2932
3392
  groupKey,
@@ -2961,7 +3421,7 @@ function renderContainerNode(node, containerTree, loopTreesBySessionId, viewProp
2961
3421
  );
2962
3422
  const hasNested = collectChildContainers(containerTree.containersById, node.container_id).length > 0;
2963
3423
  if (node.scope === "subworkflow") {
2964
- return /* @__PURE__ */ jsx14(
3424
+ return /* @__PURE__ */ jsx15(
2965
3425
  WorkflowSubworkflowContainer,
2966
3426
  {
2967
3427
  node,
@@ -2979,7 +3439,7 @@ function renderContainerNode(node, containerTree, loopTreesBySessionId, viewProp
2979
3439
  "data-testid": `lax-workflow-nested-${node.scope}-${node.scope_key}`,
2980
3440
  children: [
2981
3441
  renderLeafContainer(node, depth, containerTree, loopTreesBySessionId, viewProps),
2982
- hasNested ? /* @__PURE__ */ jsx14("div", { className: "lax-workflow-container-children", children: nested }) : null
3442
+ hasNested ? /* @__PURE__ */ jsx15("div", { className: "lax-workflow-container-children", children: nested }) : null
2983
3443
  ]
2984
3444
  },
2985
3445
  node.container_id
@@ -3005,9 +3465,9 @@ function renderWorkflowStageRow(node, containerTree, loopTreesBySessionId, viewP
3005
3465
  viewProps
3006
3466
  );
3007
3467
  if (as === "div") {
3008
- return /* @__PURE__ */ jsx14("div", { className, role: "listitem", children: content }, node.container_id);
3468
+ return /* @__PURE__ */ jsx15("div", { className, role: "listitem", children: content }, node.container_id);
3009
3469
  }
3010
- return /* @__PURE__ */ jsx14("li", { className, children: content }, node.container_id);
3470
+ return /* @__PURE__ */ jsx15("li", { className, children: content }, node.container_id);
3011
3471
  }
3012
3472
  function WorkflowStageListPanel({
3013
3473
  stages,
@@ -3028,7 +3488,7 @@ function WorkflowStageListPanel({
3028
3488
  partition.totalDoneCount - partition.visibleDoneCount
3029
3489
  );
3030
3490
  return /* @__PURE__ */ jsxs10(Fragment2, { children: [
3031
- /* @__PURE__ */ jsx14("ol", { className: "lax-workflow-stage-list", "data-testid": "lax-workflow-stage-list", children: partition.visible.map(
3491
+ /* @__PURE__ */ jsx15("ol", { className: "lax-workflow-stage-list", "data-testid": "lax-workflow-stage-list", children: partition.visible.map(
3032
3492
  (node) => renderWorkflowStageRow(node, containerTree, loopTreesBySessionId, viewProps)
3033
3493
  ) }),
3034
3494
  partition.hiddenCount > 0 ? /* @__PURE__ */ jsxs10(
@@ -3047,7 +3507,7 @@ function WorkflowStageListPanel({
3047
3507
  ]
3048
3508
  }
3049
3509
  ) : null,
3050
- extraCompletedPages > 0 && partition.hiddenCount === 0 ? /* @__PURE__ */ jsx14(
3510
+ extraCompletedPages > 0 && partition.hiddenCount === 0 ? /* @__PURE__ */ jsx15(
3051
3511
  "button",
3052
3512
  {
3053
3513
  type: "button",
@@ -3083,7 +3543,7 @@ function renderWorkflowChildren(workflowNode, containerTree, loopTreesBySessionI
3083
3543
  (node) => node.scope !== "stage" && node.scope !== "item"
3084
3544
  );
3085
3545
  return /* @__PURE__ */ jsxs10(Fragment2, { children: [
3086
- stages.length > 0 ? /* @__PURE__ */ jsx14(
3546
+ stages.length > 0 ? /* @__PURE__ */ jsx15(
3087
3547
  WorkflowStageListPanel,
3088
3548
  {
3089
3549
  stages,
@@ -3108,7 +3568,7 @@ function WorkflowChrome({
3108
3568
  const viewProps = { virtualized, virtualizeThreshold, groupParallelTools };
3109
3569
  const rootNodes = containerTree.rootContainerIds.map((id) => containerTree.containersById[id]).filter((node) => node != null);
3110
3570
  if (rootNodes.length === 0) {
3111
- return /* @__PURE__ */ jsx14("div", { className: "lax-workflow-chrome", "data-testid": "lax-workflow-chrome", children: /* @__PURE__ */ jsx14(
3571
+ return /* @__PURE__ */ jsx15("div", { className: "lax-workflow-chrome", "data-testid": "lax-workflow-chrome", children: /* @__PURE__ */ jsx15(
3112
3572
  WorkflowContainerLine,
3113
3573
  {
3114
3574
  variant: "root",
@@ -3118,7 +3578,7 @@ function WorkflowChrome({
3118
3578
  }
3119
3579
  ) });
3120
3580
  }
3121
- return /* @__PURE__ */ jsx14("div", { className: "lax-workflow-chrome", "data-testid": "lax-workflow-chrome", children: rootNodes.map((workflowNode) => /* @__PURE__ */ jsx14(WorkflowRootContainer, { node: workflowNode, children: renderWorkflowChildren(
3581
+ return /* @__PURE__ */ jsx15("div", { className: "lax-workflow-chrome", "data-testid": "lax-workflow-chrome", children: rootNodes.map((workflowNode) => /* @__PURE__ */ jsx15(WorkflowRootContainer, { node: workflowNode, children: renderWorkflowChildren(
3122
3582
  workflowNode,
3123
3583
  containerTree,
3124
3584
  loopTreesBySessionId,
@@ -3199,11 +3659,11 @@ function loopSessionDisplayLabel(loopSessionId) {
3199
3659
  }
3200
3660
 
3201
3661
  // src/view/workflow/WorkflowTaskListFooter.tsx
3202
- import { jsx as jsx15, jsxs as jsxs11 } from "react/jsx-runtime";
3662
+ import { jsx as jsx16, jsxs as jsxs11 } from "react/jsx-runtime";
3203
3663
  function MessageResponse({ children }) {
3204
3664
  return /* @__PURE__ */ jsxs11("div", { className: "lax-message-response", children: [
3205
- /* @__PURE__ */ jsx15("span", { className: "lax-message-response__marker", children: "\u23BF " }),
3206
- /* @__PURE__ */ jsx15("span", { className: "lax-message-response__content", children })
3665
+ /* @__PURE__ */ jsx16("span", { className: "lax-message-response__marker", children: "\u23BF " }),
3666
+ /* @__PURE__ */ jsx16("span", { className: "lax-message-response__content", children })
3207
3667
  ] });
3208
3668
  }
3209
3669
  function WorkflowTaskListFooter() {
@@ -3228,18 +3688,18 @@ function WorkflowTaskListFooter() {
3228
3688
  onClick: () => setExpanded((v) => !v),
3229
3689
  children: [
3230
3690
  label,
3231
- /* @__PURE__ */ jsx15("span", { className: "lax-task-list-footer__hint", children: expanded ? " \xB7 \u2191 to hide" : " \xB7 \u2193 to view" })
3691
+ /* @__PURE__ */ jsx16("span", { className: "lax-task-list-footer__hint", children: expanded ? " \xB7 \u2191 to hide" : " \xB7 \u2193 to view" })
3232
3692
  ]
3233
3693
  }
3234
3694
  ),
3235
- expanded ? /* @__PURE__ */ jsx15(MessageResponse, { children: /* @__PURE__ */ jsx15("div", { className: "lax-workflow-task-list-groups", children: groups.map((group) => /* @__PURE__ */ jsxs11(
3695
+ expanded ? /* @__PURE__ */ jsx16(MessageResponse, { children: /* @__PURE__ */ jsx16("div", { className: "lax-workflow-task-list-groups", children: groups.map((group) => /* @__PURE__ */ jsxs11(
3236
3696
  "div",
3237
3697
  {
3238
3698
  className: "lax-workflow-task-list-group",
3239
3699
  "data-testid": `lax-workflow-task-group-${group.loopSessionId}`,
3240
3700
  children: [
3241
- /* @__PURE__ */ jsx15("div", { className: "lax-workflow-task-list-group-title", children: loopSessionDisplayLabel(group.loopSessionId) }),
3242
- /* @__PURE__ */ jsx15(TaskList, { tasks: group.tasks })
3701
+ /* @__PURE__ */ jsx16("div", { className: "lax-workflow-task-list-group-title", children: loopSessionDisplayLabel(group.loopSessionId) }),
3702
+ /* @__PURE__ */ jsx16(TaskList, { tasks: group.tasks })
3243
3703
  ]
3244
3704
  },
3245
3705
  group.loopSessionId
@@ -3249,7 +3709,7 @@ function WorkflowTaskListFooter() {
3249
3709
 
3250
3710
  // src/view/workflow/WorkflowSession.tsx
3251
3711
  import { useStore as useStore5 } from "zustand";
3252
- import { jsx as jsx16, jsxs as jsxs12 } from "react/jsx-runtime";
3712
+ import { jsx as jsx17, jsxs as jsxs12 } from "react/jsx-runtime";
3253
3713
  function WorkflowSession({
3254
3714
  source,
3255
3715
  initialEvents,
@@ -3345,13 +3805,13 @@ function WorkflowSession({
3345
3805
  controller.abort();
3346
3806
  };
3347
3807
  }, [source, onError]);
3348
- return /* @__PURE__ */ jsx16(WorkflowSessionStoreContext.Provider, { value: storeRef.current, children: /* @__PURE__ */ jsx16(WorkflowScaleContext.Provider, { value: scaleOptions, children: /* @__PURE__ */ jsx16(WorkflowLoopReplayProvider, { onRequestLoopReplay, children: /* @__PURE__ */ jsx16(InteractionBusContext.Provider, { value: busRef, children: /* @__PURE__ */ jsx16(NodeRegistryContext.Provider, { value: registryRef, children: /* @__PURE__ */ jsx16(MarkdownRendererContext.Provider, { value: markdownRenderer, children: /* @__PURE__ */ jsx16(ToolDisplayOptionsContext.Provider, { value: toolDisplayRef, children: /* @__PURE__ */ jsx16(SessionViewOptionsContext.Provider, { value: sessionViewRef, children: /* @__PURE__ */ jsxs12(
3808
+ return /* @__PURE__ */ jsx17(WorkflowSessionStoreContext.Provider, { value: storeRef.current, children: /* @__PURE__ */ jsx17(WorkflowScaleContext.Provider, { value: scaleOptions, children: /* @__PURE__ */ jsx17(WorkflowLoopReplayProvider, { onRequestLoopReplay, children: /* @__PURE__ */ jsx17(InteractionBusContext.Provider, { value: busRef, children: /* @__PURE__ */ jsx17(NodeRegistryContext.Provider, { value: registryRef, children: /* @__PURE__ */ jsx17(MarkdownRendererContext.Provider, { value: markdownRenderer, children: /* @__PURE__ */ jsx17(ToolDisplayOptionsContext.Provider, { value: toolDisplayRef, children: /* @__PURE__ */ jsx17(SessionViewOptionsContext.Provider, { value: sessionViewRef, children: /* @__PURE__ */ jsxs12(
3349
3809
  "div",
3350
3810
  {
3351
3811
  className: "lax-agent-session lax-workflow-session",
3352
3812
  "data-testid": "lax-workflow-session",
3353
3813
  children: [
3354
- /* @__PURE__ */ jsx16(
3814
+ /* @__PURE__ */ jsx17(
3355
3815
  WorkflowChrome,
3356
3816
  {
3357
3817
  containerTree,
@@ -3361,7 +3821,7 @@ function WorkflowSession({
3361
3821
  groupParallelTools
3362
3822
  }
3363
3823
  ),
3364
- /* @__PURE__ */ jsx16(WorkflowTaskListFooter, {}),
3824
+ /* @__PURE__ */ jsx17(WorkflowTaskListFooter, {}),
3365
3825
  children
3366
3826
  ]
3367
3827
  }
@@ -3405,7 +3865,7 @@ function buildTimelineEntries(rootIds, byId, options = {}) {
3405
3865
  }
3406
3866
 
3407
3867
  // src/view/nodes/SubAgentNode.tsx
3408
- import { jsx as jsx17, jsxs as jsxs13 } from "react/jsx-runtime";
3868
+ import { jsx as jsx18, jsxs as jsxs13 } from "react/jsx-runtime";
3409
3869
  function SubAgentBlock({ nodeId }) {
3410
3870
  const node = useNodeTyped(nodeId, "subagent");
3411
3871
  const childIds = useChildren(nodeId);
@@ -3416,7 +3876,7 @@ function SubAgentBlock({ nodeId }) {
3416
3876
  "SubAgent: ",
3417
3877
  node.subagentId
3418
3878
  ] }),
3419
- /* @__PURE__ */ jsx17("div", { className: "lax-subagent-block__children", children: childIds.map((childId) => /* @__PURE__ */ jsx17(TimelineItem, { nodeId: childId, registry }, childId)) })
3879
+ /* @__PURE__ */ jsx18("div", { className: "lax-subagent-block__children", children: childIds.map((childId) => /* @__PURE__ */ jsx18(TimelineItem, { nodeId: childId, registry }, childId)) })
3420
3880
  ] });
3421
3881
  }
3422
3882