langchain_agentx_stream_ui 0.3.4 → 0.3.7

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-ISQ7JWGD.js";
26
+ } from "./chunk-7QYE5PN5.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-TCKOXX7O.js";
36
- import "./chunk-6Z4ZF36Z.js";
35
+ } from "./chunk-MRGHYRSV.js";
36
+ import "./chunk-DP7V33X7.js";
37
37
  import {
38
38
  CollapseKind,
39
39
  CollapsedExploreNode,
@@ -110,7 +110,7 @@ import {
110
110
  useSessionStatus,
111
111
  useSessionViewOptions,
112
112
  useTimeline
113
- } from "./chunk-6ORA5RMV.js";
113
+ } from "./chunk-24FLS4TF.js";
114
114
  import {
115
115
  Agent,
116
116
  AgentToolBody,
@@ -138,7 +138,7 @@ import {
138
138
  createDefaultToolRegistry,
139
139
  formatAgentTitle,
140
140
  formatExploreSummaryText
141
- } from "./chunk-FL2G7SV3.js";
141
+ } from "./chunk-QL3DIGFI.js";
142
142
  import {
143
143
  BodyBlockList,
144
144
  DiffView,
@@ -154,7 +154,7 @@ import {
154
154
  formatTimeoutFooter,
155
155
  parseDiffText,
156
156
  truncateCommand
157
- } from "./chunk-GBY5DJ7L.js";
157
+ } from "./chunk-4RIOBLGB.js";
158
158
 
159
159
  // src/view/AgentSession.tsx
160
160
  import { useEffect as useEffect2, useMemo, useRef as useRef2 } from "react";
@@ -1127,20 +1127,26 @@ function computeDurationSeconds(tree) {
1127
1127
  const seconds = Math.round((maxTs - started) / 1e3);
1128
1128
  return seconds > 0 ? seconds : null;
1129
1129
  }
1130
- function lastTextContent(tree) {
1130
+ function lastLoopTextContent(tree) {
1131
1131
  const textNodes = Object.values(tree.byId).filter((node) => node.kind === "text");
1132
1132
  if (textNodes.length === 0) return "";
1133
1133
  return textNodes[textNodes.length - 1].accumulated.trim();
1134
1134
  }
1135
+ function pickTeaserLine(fullText) {
1136
+ const lines = fullText.split("\n").map((line) => line.trim()).filter(Boolean);
1137
+ if (lines.length === 0) return "";
1138
+ const nonTableLine = lines.find((line) => !line.startsWith("|"));
1139
+ return nonTableLine ?? lines[0] ?? "";
1140
+ }
1135
1141
  function buildStageDoneSummary(tree) {
1136
1142
  if (tree.status !== "done" && tree.status !== "error") return null;
1137
1143
  const toolUses = countToolUses(tree);
1138
1144
  const duration = computeDurationSeconds(tree);
1139
1145
  const durationSuffix = duration != null ? ` \xB7 ${duration}s` : "";
1140
1146
  const label = toolUses > 0 ? `Done (${toolUses} tool use${toolUses === 1 ? "" : "s"}${durationSuffix})` : `Done (1 agent turn${durationSuffix})`;
1141
- const fullText = lastTextContent(tree);
1147
+ const fullText = lastLoopTextContent(tree);
1142
1148
  const lines = fullText.split("\n").map((line) => line.trim()).filter(Boolean);
1143
- const teaser = lines[0] ?? "";
1149
+ const teaser = pickTeaserLine(fullText);
1144
1150
  const extraLines = Math.max(0, lines.length - 1);
1145
1151
  return { label, teaser, extraLines };
1146
1152
  }
@@ -1214,7 +1220,7 @@ function evictInactiveLoopTrees(state, pinnedLoopSessionIds) {
1214
1220
  if (container.status !== "completed" && container.status !== "failed") continue;
1215
1221
  const summary = buildStageDoneSummary(tree);
1216
1222
  if (summary) {
1217
- nextSummaries[container.container_id] = summary;
1223
+ nextSummaries[container.container_id] = container.scope === "aggregate" ? { ...summary, fullMarkdown: lastLoopTextContent(tree) } : summary;
1218
1224
  }
1219
1225
  delete nextLoops[loopSessionId];
1220
1226
  }
@@ -1257,7 +1263,7 @@ function evictCompletedLoopOverflow(state, maxHydratedCompletedLoops) {
1257
1263
  if (container) {
1258
1264
  const summary = buildStageDoneSummary(tree);
1259
1265
  if (summary) {
1260
- nextSummaries[container.container_id] = summary;
1266
+ nextSummaries[container.container_id] = container.scope === "aggregate" ? { ...summary, fullMarkdown: lastLoopTextContent(tree) } : summary;
1261
1267
  }
1262
1268
  }
1263
1269
  delete nextLoops[id];
@@ -1458,7 +1464,11 @@ function sanitizeContainerTreeParentLinks(containersById) {
1458
1464
  function normalizeSnapshotContainerContentBlocks(containersById) {
1459
1465
  const next = {};
1460
1466
  for (const [containerId, node] of Object.entries(containersById)) {
1461
- next[containerId] = { ...node, content_blocks: node.content_blocks ?? [] };
1467
+ const loopSessionId = node.loopSessionId ?? null;
1468
+ next[containerId] = {
1469
+ ...node,
1470
+ content_blocks: loopSessionId ? [] : node.content_blocks ?? []
1471
+ };
1462
1472
  }
1463
1473
  return next;
1464
1474
  }
@@ -1761,9 +1771,12 @@ function resolveContentTargetFromSnapshot(snapshot, workflowPath, scopeKey) {
1761
1771
  function mergeRuntimeContainerNodes(prev, snapshot) {
1762
1772
  const out = {};
1763
1773
  for (const [containerId, node] of Object.entries(snapshot.containers)) {
1774
+ const loopSessionId = prev[containerId]?.loopSessionId ?? null;
1764
1775
  out[containerId] = {
1765
1776
  ...node,
1766
- loopSessionId: prev[containerId]?.loopSessionId ?? null
1777
+ loopSessionId,
1778
+ // D24:已绑定 loop 的容器不得保留 content_blocks 预览(过程层 SSOT 在 loop tree)。
1779
+ content_blocks: loopSessionId ? [] : node.content_blocks
1767
1780
  };
1768
1781
  }
1769
1782
  return out;
@@ -2537,7 +2550,7 @@ function bindLoopSessionToContainerTree(tree, event, activeLoopSessionId) {
2537
2550
  ...nextTree,
2538
2551
  containersById: {
2539
2552
  ...nextTree.containersById,
2540
- [targetId]: { ...node, loopSessionId: sessionId }
2553
+ [targetId]: { ...node, loopSessionId: sessionId, content_blocks: [] }
2541
2554
  }
2542
2555
  };
2543
2556
  }
@@ -3270,6 +3283,7 @@ import { useMemo as useMemo7, useState as useState6 } from "react";
3270
3283
 
3271
3284
  // src/view/workflow/WorkflowAggregateContainer.tsx
3272
3285
  import { useCallback, useEffect as useEffect5, useMemo as useMemo2, useState, memo } from "react";
3286
+ import { useStore as useStore2 } from "zustand";
3273
3287
 
3274
3288
  // src/view/workflow/WorkflowContainerLine.tsx
3275
3289
  import { Fragment, jsx as jsx5, jsxs as jsxs2 } from "react/jsx-runtime";
@@ -3413,6 +3427,44 @@ function WorkflowMarkdownPreview({
3413
3427
  return /* @__PURE__ */ jsx7("div", { className, "data-testid": testId, children: /* @__PURE__ */ jsx7(RichMarkdown, { content, deferDiagrams: true }) });
3414
3428
  }
3415
3429
 
3430
+ // src/core/workflow/loopTreeUtils.ts
3431
+ function hasTimelineNodes(tree) {
3432
+ if (!tree) return false;
3433
+ return tree.rootChildren.length > 0 || Object.keys(tree.byId).length > 0;
3434
+ }
3435
+
3436
+ // src/view/workflow/workflowStageDoneBody.tsx
3437
+ import { jsx as jsx8 } from "react/jsx-runtime";
3438
+ function WorkflowStageDoneBody({
3439
+ loopTree,
3440
+ testId,
3441
+ virtualized,
3442
+ virtualizeThreshold,
3443
+ groupParallelTools,
3444
+ bodyClassName = "lax-workflow-stage-container__body"
3445
+ }) {
3446
+ if (loopTree && hasTimelineNodes(loopTree)) {
3447
+ return /* @__PURE__ */ jsx8("div", { className: bodyClassName, "data-testid": testId, children: /* @__PURE__ */ jsx8(
3448
+ AgentLoopView,
3449
+ {
3450
+ tree: loopTree,
3451
+ showTaskListFooter: false,
3452
+ virtualized,
3453
+ virtualizeThreshold,
3454
+ groupParallelTools
3455
+ }
3456
+ ) });
3457
+ }
3458
+ return /* @__PURE__ */ jsx8(
3459
+ "div",
3460
+ {
3461
+ className: `${bodyClassName} lax-workflow-stage-container__empty-hint`,
3462
+ "data-testid": testId,
3463
+ 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" })
3464
+ }
3465
+ );
3466
+ }
3467
+
3416
3468
  // src/view/workflow/workflowStageListUtils.ts
3417
3469
  var ACTIVE_CONTAINER_STATUSES = /* @__PURE__ */ new Set([
3418
3470
  "running",
@@ -3655,12 +3707,23 @@ function workflowContainerViewPropsEqual(prev, next) {
3655
3707
  }
3656
3708
 
3657
3709
  // src/view/workflow/WorkflowAggregateContainer.tsx
3658
- import { jsx as jsx8, jsxs as jsxs4 } from "react/jsx-runtime";
3710
+ import { jsx as jsx9, jsxs as jsxs4 } from "react/jsx-runtime";
3659
3711
  function mergeContentPreview(node) {
3660
3712
  const blocks = node.content_blocks;
3661
3713
  if (blocks.length === 0) return "";
3662
3714
  return blocks.map((block) => block.preview?.trim() ?? "").filter(Boolean).join("\n\n");
3663
3715
  }
3716
+ function resolveAggregateBodyMarkdown(node, loopTree, isDone, cachedFullMarkdown) {
3717
+ const staticPreview = mergeContentPreview(node);
3718
+ if (loopTree) {
3719
+ if (isDone) {
3720
+ return lastLoopTextContent(loopTree) || staticPreview;
3721
+ }
3722
+ return lastLoopTextContent(loopTree) || staticPreview;
3723
+ }
3724
+ if (isDone && cachedFullMarkdown) return cachedFullMarkdown;
3725
+ return staticPreview;
3726
+ }
3664
3727
  function WorkflowAggregateContainerInner({
3665
3728
  node,
3666
3729
  loopTree,
@@ -3670,11 +3733,34 @@ function WorkflowAggregateContainerInner({
3670
3733
  virtualizeThreshold,
3671
3734
  groupParallelTools
3672
3735
  }) {
3736
+ const { verbose } = useSessionViewOptions();
3737
+ const store = useWorkflowSessionStoreApi();
3738
+ const replayHandler = useWorkflowLoopReplayHandler();
3739
+ const cachedSummary = useStore2(
3740
+ store,
3741
+ (s) => s.state.stageDoneSummariesByContainerId[node.container_id]
3742
+ );
3743
+ const pinLoopSession = useStore2(store, (s) => s.pinLoopSession);
3673
3744
  const isRunning = node.status === "running" || node.status === "retrying";
3674
3745
  const isWaiting = node.status === "pending" || node.status === "blocked";
3675
3746
  const isDone = node.status === "completed" || node.status === "failed";
3676
- const contentPreview = useMemo2(() => mergeContentPreview(node), [node]);
3677
- const waitingTeaser = isWaiting ? contentPreview || node.subtitle || "" : "";
3747
+ const usesScopedLoop = Boolean(node.loopSessionId);
3748
+ const bodyMarkdown = useMemo2(
3749
+ () => resolveAggregateBodyMarkdown(
3750
+ node,
3751
+ loopTree,
3752
+ isDone,
3753
+ cachedSummary?.fullMarkdown
3754
+ ),
3755
+ [node, loopTree, isDone, cachedSummary?.fullMarkdown]
3756
+ );
3757
+ const waitingTeaser = isWaiting ? node.subtitle || bodyMarkdown || "" : "";
3758
+ const doneSummaryFromTree = useMemo2(
3759
+ () => loopTree && isDone ? buildStageDoneSummary(loopTree) : null,
3760
+ [loopTree, isDone]
3761
+ );
3762
+ const doneSummary = doneSummaryFromTree ?? (isDone ? cachedSummary : null);
3763
+ const expandHint = doneSummary ? formatTeaserExpandHint(doneSummary.extraLines, verbose) : null;
3678
3764
  const testId = `lax-workflow-aggregate-${node.scope_key}`;
3679
3765
  const uiStatus = mapAggregateUiStatus(node);
3680
3766
  const statusLabel = buildAggregateStatusLabel(node, siblingItems);
@@ -3683,18 +3769,40 @@ function WorkflowAggregateContainerInner({
3683
3769
  if (isRunning) setExpanded(true);
3684
3770
  if (isDone) setExpanded(false);
3685
3771
  }, [isRunning, isDone]);
3772
+ const requestLoopHydration = useCallback(() => {
3773
+ const loopSessionId = node.loopSessionId;
3774
+ if (!loopSessionId || loopTree) return;
3775
+ pinLoopSession(loopSessionId);
3776
+ void replayHandler?.(loopSessionId);
3777
+ }, [node.loopSessionId, loopTree, pinLoopSession, replayHandler]);
3686
3778
  const toggleExpanded = useCallback(() => {
3687
- setExpanded((prev) => !prev);
3688
- }, []);
3689
- const shellToggle = isRunning ? toggleExpanded : isDone && expanded ? toggleExpanded : void 0;
3690
- const markdownPreview = contentPreview ? /* @__PURE__ */ jsx8(
3779
+ setExpanded((prev) => {
3780
+ const next = !prev;
3781
+ if (next && isDone && node.loopSessionId && !loopTree) {
3782
+ requestLoopHydration();
3783
+ }
3784
+ return next;
3785
+ });
3786
+ }, [isDone, node.loopSessionId, loopTree, requestLoopHydration]);
3787
+ useEffect5(() => {
3788
+ const onKeyDown = (event) => {
3789
+ if (!(event.ctrlKey || event.metaKey) || event.key.toLowerCase() !== "o") return;
3790
+ setExpanded(true);
3791
+ requestLoopHydration();
3792
+ };
3793
+ window.addEventListener("keydown", onKeyDown);
3794
+ return () => window.removeEventListener("keydown", onKeyDown);
3795
+ }, [requestLoopHydration]);
3796
+ const shellToggle = isRunning ? toggleExpanded : isDone ? toggleExpanded : void 0;
3797
+ const markdownPreview = bodyMarkdown ? /* @__PURE__ */ jsx9(
3691
3798
  WorkflowMarkdownPreview,
3692
3799
  {
3693
- content: contentPreview,
3800
+ content: bodyMarkdown,
3694
3801
  testId: `${testId}-markdown`,
3695
3802
  className: "lax-workflow-aggregate__markdown lax-workflow-markdown-preview"
3696
3803
  }
3697
3804
  ) : null;
3805
+ const canExpandDone = isDone && (Boolean(loopTree) || Boolean(bodyMarkdown) || Boolean(node.loopSessionId));
3698
3806
  return /* @__PURE__ */ jsxs4(
3699
3807
  "div",
3700
3808
  {
@@ -3703,7 +3811,7 @@ function WorkflowAggregateContainerInner({
3703
3811
  "data-container-scope": "aggregate",
3704
3812
  style: { "--lax-workflow-depth": depth },
3705
3813
  children: [
3706
- /* @__PURE__ */ jsx8(
3814
+ /* @__PURE__ */ jsx9(
3707
3815
  WorkflowContainerLine,
3708
3816
  {
3709
3817
  title: node.title,
@@ -3712,15 +3820,15 @@ function WorkflowAggregateContainerInner({
3712
3820
  meta: buildAggregateLineMeta(node),
3713
3821
  statusLabel,
3714
3822
  onToggle: shellToggle,
3715
- interactive: isRunning,
3823
+ interactive: isRunning || isDone,
3716
3824
  expanded,
3717
3825
  titleTestId: `${testId}-title`,
3718
3826
  descriptionTestId: `${testId}-desc`
3719
3827
  }
3720
3828
  ),
3721
3829
  isWaiting && waitingTeaser ? /* @__PURE__ */ jsxs4("div", { className: "lax-workflow-aggregate__waiting-teaser", "data-testid": `${testId}-waiting`, children: [
3722
- /* @__PURE__ */ jsx8("span", { className: "lax-workflow-aggregate__waiting-prefix", children: "\u23BF " }),
3723
- /* @__PURE__ */ jsx8(
3830
+ /* @__PURE__ */ jsx9("span", { className: "lax-workflow-aggregate__waiting-prefix", children: "\u23BF " }),
3831
+ /* @__PURE__ */ jsx9(
3724
3832
  WorkflowMarkdownPreview,
3725
3833
  {
3726
3834
  content: waitingTeaser,
@@ -3728,7 +3836,7 @@ function WorkflowAggregateContainerInner({
3728
3836
  }
3729
3837
  )
3730
3838
  ] }) : null,
3731
- expanded && isRunning && loopTree ? /* @__PURE__ */ jsx8("div", { className: "lax-workflow-stage-container__body", "data-testid": `${testId}-body`, children: /* @__PURE__ */ jsx8(
3839
+ expanded && isRunning && loopTree ? /* @__PURE__ */ jsx9("div", { className: "lax-workflow-stage-container__body", "data-testid": `${testId}-body`, children: /* @__PURE__ */ jsx9(
3732
3840
  AgentLoopView,
3733
3841
  {
3734
3842
  tree: loopTree,
@@ -3738,7 +3846,7 @@ function WorkflowAggregateContainerInner({
3738
3846
  groupParallelTools
3739
3847
  }
3740
3848
  ) }) : null,
3741
- expanded && isRunning && !loopTree && contentPreview ? /* @__PURE__ */ jsx8(
3849
+ expanded && isRunning && !loopTree && bodyMarkdown ? /* @__PURE__ */ jsx9(
3742
3850
  "div",
3743
3851
  {
3744
3852
  className: "lax-workflow-stage-container__body lax-workflow-stage-container__content-preview",
@@ -3747,36 +3855,44 @@ function WorkflowAggregateContainerInner({
3747
3855
  }
3748
3856
  ) : null,
3749
3857
  isDone && !expanded ? /* @__PURE__ */ jsxs4("div", { className: "lax-workflow-aggregate__done", "data-testid": `${testId}-done`, children: [
3750
- /* @__PURE__ */ jsx8(
3858
+ canExpandDone ? /* @__PURE__ */ jsx9(
3751
3859
  WorkflowExpandTrigger,
3752
3860
  {
3753
3861
  summary: `${node.title} \xB7 done`,
3754
- onToggle: () => setExpanded(true),
3862
+ onToggle: toggleExpanded,
3755
3863
  expanded: false,
3756
- expandHint: contentPreview ? "(click to expand)" : void 0,
3864
+ expandHint: bodyMarkdown || expandHint ? "(click to expand)" : void 0,
3757
3865
  testId: `${testId}-done-trigger`
3758
3866
  }
3759
- ),
3760
- markdownPreview ? /* @__PURE__ */ jsx8("div", { className: "lax-workflow-aggregate__done-preview", "data-testid": `${testId}-teaser`, children: markdownPreview }) : null
3867
+ ) : null,
3868
+ markdownPreview ? /* @__PURE__ */ jsx9("div", { className: "lax-workflow-aggregate__done-preview", "data-testid": `${testId}-teaser`, children: markdownPreview }) : null,
3869
+ !bodyMarkdown && expandHint ? /* @__PURE__ */ jsx9("span", { className: "lax-workflow-expand-trigger__hint", children: expandHint }) : null
3761
3870
  ] }) : null,
3762
- isDone && expanded && loopTree ? /* @__PURE__ */ jsx8("div", { className: "lax-workflow-stage-container__body", "data-testid": `${testId}-body`, children: /* @__PURE__ */ jsx8(
3763
- AgentLoopView,
3871
+ isDone && expanded ? loopTree ? /* @__PURE__ */ jsx9(
3872
+ WorkflowStageDoneBody,
3764
3873
  {
3765
- tree: loopTree,
3766
- showTaskListFooter: false,
3874
+ node,
3875
+ loopTree,
3876
+ testId: `${testId}-body`,
3767
3877
  virtualized,
3768
3878
  virtualizeThreshold,
3769
3879
  groupParallelTools
3770
3880
  }
3771
- ) }) : null,
3772
- isDone && expanded && !loopTree && contentPreview ? /* @__PURE__ */ jsx8(
3881
+ ) : bodyMarkdown ? /* @__PURE__ */ jsx9(
3773
3882
  "div",
3774
3883
  {
3775
3884
  className: "lax-workflow-stage-container__body lax-workflow-stage-container__content-preview",
3776
3885
  "data-testid": `${testId}-body`,
3777
3886
  children: markdownPreview
3778
3887
  }
3779
- ) : null
3888
+ ) : usesScopedLoop ? /* @__PURE__ */ jsx9(
3889
+ "div",
3890
+ {
3891
+ className: "lax-workflow-stage-container__body lax-workflow-loop-replay-pending",
3892
+ "data-testid": `${testId}-body`,
3893
+ children: /* @__PURE__ */ jsx9("p", { className: "lax-workflow-loop-replay-pending__hint", children: replayHandler ? "Loading loop details\u2026" : "Loop details evicted from memory." })
3894
+ }
3895
+ ) : null : null
3780
3896
  ]
3781
3897
  }
3782
3898
  );
@@ -3893,47 +4009,7 @@ function formatParallelGroupSummary(metrics) {
3893
4009
 
3894
4010
  // src/view/workflow/WorkflowStageContainer.tsx
3895
4011
  import { useCallback as useCallback2, useEffect as useEffect6, useMemo as useMemo3, useState as useState2, memo as memo2 } from "react";
3896
- import { useStore as useStore2 } from "zustand";
3897
-
3898
- // src/core/workflow/loopTreeUtils.ts
3899
- function hasTimelineNodes(tree) {
3900
- if (!tree) return false;
3901
- return tree.rootChildren.length > 0 || Object.keys(tree.byId).length > 0;
3902
- }
3903
-
3904
- // src/view/workflow/workflowStageDoneBody.tsx
3905
- import { jsx as jsx9 } from "react/jsx-runtime";
3906
- function WorkflowStageDoneBody({
3907
- loopTree,
3908
- testId,
3909
- virtualized,
3910
- virtualizeThreshold,
3911
- groupParallelTools,
3912
- bodyClassName = "lax-workflow-stage-container__body"
3913
- }) {
3914
- if (loopTree && hasTimelineNodes(loopTree)) {
3915
- return /* @__PURE__ */ jsx9("div", { className: bodyClassName, "data-testid": testId, children: /* @__PURE__ */ jsx9(
3916
- AgentLoopView,
3917
- {
3918
- tree: loopTree,
3919
- showTaskListFooter: false,
3920
- virtualized,
3921
- virtualizeThreshold,
3922
- groupParallelTools
3923
- }
3924
- ) });
3925
- }
3926
- return /* @__PURE__ */ jsx9(
3927
- "div",
3928
- {
3929
- className: `${bodyClassName} lax-workflow-stage-container__empty-hint`,
3930
- "data-testid": testId,
3931
- 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" })
3932
- }
3933
- );
3934
- }
3935
-
3936
- // src/view/workflow/WorkflowStageContainer.tsx
4012
+ import { useStore as useStore3 } from "zustand";
3937
4013
  import { jsx as jsx10, jsxs as jsxs5 } from "react/jsx-runtime";
3938
4014
  function containerTestId(node) {
3939
4015
  if (node.scope === "item") return `lax-workflow-parallel-${node.scope_key}`;
@@ -3957,13 +4033,13 @@ function WorkflowStageContainerInner({
3957
4033
  const { verbose } = useSessionViewOptions();
3958
4034
  const store = useWorkflowSessionStoreApi();
3959
4035
  const replayHandler = useWorkflowLoopReplayHandler();
3960
- const activeLoopSessionId = useStore2(store, (s) => s.state.activeLoopSessionId);
3961
- const activeContainerIds = useStore2(store, (s) => s.state.containerTree.activeContainerIds);
3962
- const cachedSummary = useStore2(
4036
+ const activeLoopSessionId = useStore3(store, (s) => s.state.activeLoopSessionId);
4037
+ const activeContainerIds = useStore3(store, (s) => s.state.containerTree.activeContainerIds);
4038
+ const cachedSummary = useStore3(
3963
4039
  store,
3964
4040
  (s) => s.state.stageDoneSummariesByContainerId[node.container_id]
3965
4041
  );
3966
- const pinLoopSession = useStore2(store, (s) => s.pinLoopSession);
4042
+ const pinLoopSession = useStore3(store, (s) => s.pinLoopSession);
3967
4043
  const isRunning = node.status === "running" || node.status === "retrying";
3968
4044
  const isDone = node.status === "completed" || node.status === "failed";
3969
4045
  const isSkipped = node.status === "skipped";
@@ -4057,12 +4133,21 @@ function WorkflowStageContainerInner({
4057
4133
  }
4058
4134
  ),
4059
4135
  effectivelyDone && !expanded && (teaserText || expandHint) ? /* @__PURE__ */ jsxs5("div", { className: "lax-workflow-stage-container__done-teaser", children: [
4060
- teaserText ? /* @__PURE__ */ jsx10(
4061
- "span",
4136
+ teaserText ? /* @__PURE__ */ jsxs5(
4137
+ "div",
4062
4138
  {
4063
4139
  className: "lax-workflow-stage-container__done-teaser-line",
4064
4140
  "data-testid": `${testId}-teaser`,
4065
- children: `\u23BF ${teaserText}`
4141
+ children: [
4142
+ /* @__PURE__ */ jsx10("span", { className: "lax-workflow-stage-container__done-teaser-prefix", children: "\u23BF" }),
4143
+ /* @__PURE__ */ jsx10(
4144
+ WorkflowMarkdownPreview,
4145
+ {
4146
+ content: teaserText,
4147
+ className: "lax-workflow-stage-container__done-teaser-markdown"
4148
+ }
4149
+ )
4150
+ ]
4066
4151
  }
4067
4152
  ) : null,
4068
4153
  expandHint ? /* @__PURE__ */ jsx10("span", { className: "lax-workflow-expand-trigger__hint", children: expandHint }) : null
@@ -4073,10 +4158,10 @@ function WorkflowStageContainerInner({
4073
4158
  className: "lax-workflow-stage-container__body lax-workflow-stage-container__content-preview",
4074
4159
  "data-testid": bodyTestId(node),
4075
4160
  children: node.content_blocks.map((block, index) => /* @__PURE__ */ jsx10(
4076
- "div",
4161
+ WorkflowMarkdownPreview,
4077
4162
  {
4078
- className: "lax-workflow-stage-container__teaser",
4079
- children: block.preview
4163
+ content: block.preview,
4164
+ className: "lax-workflow-stage-container__teaser"
4080
4165
  },
4081
4166
  `${block.kind}-${index}`
4082
4167
  ))
@@ -4116,7 +4201,14 @@ function WorkflowStageContainerInner({
4116
4201
  className: "lax-workflow-stage-container__body lax-workflow-loop-replay-pending",
4117
4202
  "data-testid": bodyTestId(node),
4118
4203
  children: [
4119
- teaserText ? /* @__PURE__ */ jsx10("p", { className: "lax-workflow-stage-container__teaser", children: teaserText }) : null,
4204
+ teaserText ? /* @__PURE__ */ jsx10(
4205
+ WorkflowMarkdownPreview,
4206
+ {
4207
+ content: teaserText,
4208
+ className: "lax-workflow-stage-container__teaser",
4209
+ testId: `${testId}-replay-teaser`
4210
+ }
4211
+ ) : null,
4120
4212
  /* @__PURE__ */ jsx10("p", { className: "lax-workflow-loop-replay-pending__hint", children: replayHandler ? "Loading loop details\u2026" : "Loop details evicted from memory." })
4121
4213
  ]
4122
4214
  }
@@ -4762,11 +4854,11 @@ function WorkflowChrome({
4762
4854
  }
4763
4855
 
4764
4856
  // src/view/workflow/WorkflowGlobalSpinner.tsx
4765
- import { useStore as useStore3 } from "zustand";
4857
+ import { useStore as useStore4 } from "zustand";
4766
4858
  import { jsx as jsx16, jsxs as jsxs11 } from "react/jsx-runtime";
4767
4859
  function WorkflowGlobalSpinner() {
4768
4860
  const store = useWorkflowSessionStoreApi();
4769
- const show = useStore3(store, (s) => shouldShowGlobalSpinner(s.state));
4861
+ const show = useStore4(store, (s) => shouldShowGlobalSpinner(s.state));
4770
4862
  if (!show) return null;
4771
4863
  return /* @__PURE__ */ jsx16(
4772
4864
  "div",
@@ -4876,7 +4968,7 @@ function WorkflowSessionBanners({ state }) {
4876
4968
 
4877
4969
  // src/view/workflow/WorkflowTaskListFooter.tsx
4878
4970
  import { useMemo as useMemo8, useState as useState7 } from "react";
4879
- import { useStore as useStore4 } from "zustand";
4971
+ import { useStore as useStore5 } from "zustand";
4880
4972
 
4881
4973
  // src/view/workflow/workflowTaskListMerge.ts
4882
4974
  var STATUS_ORDER = {
@@ -4956,7 +5048,7 @@ function MessageResponse({ children }) {
4956
5048
  }
4957
5049
  function WorkflowTaskListFooter() {
4958
5050
  const store = useWorkflowSessionStoreApi();
4959
- const state = useStore4(store, (s) => s.state);
5051
+ const state = useStore5(store, (s) => s.state);
4960
5052
  const [expanded, setExpanded] = useState7(false);
4961
5053
  const footerState = useMemo8(() => deriveWorkflowTaskFooterState(state), [state]);
4962
5054
  const visible = shouldShowWorkflowTaskListFooter(state);
@@ -4996,7 +5088,7 @@ function WorkflowTaskListFooter() {
4996
5088
  }
4997
5089
 
4998
5090
  // src/view/workflow/WorkflowSession.tsx
4999
- import { useStore as useStore5 } from "zustand";
5091
+ import { useStore as useStore6 } from "zustand";
5000
5092
  import { jsx as jsx19, jsxs as jsxs14 } from "react/jsx-runtime";
5001
5093
  function WorkflowSession({
5002
5094
  source,
@@ -5038,8 +5130,8 @@ function WorkflowSession({
5038
5130
  }
5039
5131
  const store = storeRef.current;
5040
5132
  useWorkflowAuthorityBinding(store, authoritySource, { onAuthorityTerminal });
5041
- const streamEnded = useStore5(store, (s) => s.state.display.streamEnded);
5042
- const authorityStatus = useStore5(store, (s) => s.state.authority?.status);
5133
+ const streamEnded = useStore6(store, (s) => s.state.display.streamEnded);
5134
+ const authorityStatus = useStore6(store, (s) => s.state.authority?.status);
5043
5135
  useWorkflowAwaitingAuthorityTimers(store, streamEnded, authorityStatus);
5044
5136
  useEffect10(() => {
5045
5137
  if (snapshotBootstrap) {
@@ -5088,7 +5180,7 @@ function WorkflowSession({
5088
5180
  workspaceRoot
5089
5181
  ]
5090
5182
  );
5091
- const sessionState = useStore5(store, (s) => s.state);
5183
+ const sessionState = useStore6(store, (s) => s.state);
5092
5184
  const containerTree = sessionState.containerTree;
5093
5185
  const loopTreesBySessionId = sessionState.loopTreesBySessionId;
5094
5186
  const onErrorRef = useRef4(onError);