langchain_agentx_stream_ui 0.3.3 → 0.3.5

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.
@@ -24,7 +24,7 @@ import {
24
24
  useSessionStatus,
25
25
  useSessionViewOptions,
26
26
  useToolDisplayOptions
27
- } from "./chunk-6ORA5RMV.js";
27
+ } from "./chunk-6PWGGGUK.js";
28
28
  import {
29
29
  createDefaultToolRegistry
30
30
  } from "./chunk-FL2G7SV3.js";
@@ -1897,4 +1897,4 @@ export {
1897
1897
  createActiveSessionBridge,
1898
1898
  MultiAgentSession
1899
1899
  };
1900
- //# sourceMappingURL=chunk-ISQ7JWGD.js.map
1900
+ //# sourceMappingURL=chunk-FT6UUKPS.js.map
package/dist/index.d.ts CHANGED
@@ -240,6 +240,7 @@ interface CachedStageDoneSummary {
240
240
  label: string;
241
241
  teaser: string;
242
242
  extraLines: number;
243
+ fullMarkdown?: string;
243
244
  }
244
245
  type WorkflowRunStatus = 'running' | 'done' | 'error';
245
246
  interface WorkflowStageProgress {
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-FT6UUKPS.js";
27
27
  import {
28
28
  DefaultToolBody,
29
29
  InteractionBusContext,
@@ -110,7 +110,7 @@ import {
110
110
  useSessionStatus,
111
111
  useSessionViewOptions,
112
112
  useTimeline
113
- } from "./chunk-6ORA5RMV.js";
113
+ } from "./chunk-6PWGGGUK.js";
114
114
  import {
115
115
  Agent,
116
116
  AgentToolBody,
@@ -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];
@@ -1455,6 +1461,17 @@ function sanitizeContainerTreeParentLinks(containersById) {
1455
1461
  }
1456
1462
  return next;
1457
1463
  }
1464
+ function normalizeSnapshotContainerContentBlocks(containersById) {
1465
+ const next = {};
1466
+ for (const [containerId, node] of Object.entries(containersById)) {
1467
+ const loopSessionId = node.loopSessionId ?? null;
1468
+ next[containerId] = {
1469
+ ...node,
1470
+ content_blocks: loopSessionId ? [] : node.content_blocks ?? []
1471
+ };
1472
+ }
1473
+ return next;
1474
+ }
1458
1475
  function resolveContentScopeKey(data) {
1459
1476
  for (const keyName of ["stage_key", "item_key", "branch_key", "aggregate_key", "debug_key"]) {
1460
1477
  const value = readString(data, keyName);
@@ -1754,9 +1771,12 @@ function resolveContentTargetFromSnapshot(snapshot, workflowPath, scopeKey) {
1754
1771
  function mergeRuntimeContainerNodes(prev, snapshot) {
1755
1772
  const out = {};
1756
1773
  for (const [containerId, node] of Object.entries(snapshot.containers)) {
1774
+ const loopSessionId = prev[containerId]?.loopSessionId ?? null;
1757
1775
  out[containerId] = {
1758
1776
  ...node,
1759
- loopSessionId: prev[containerId]?.loopSessionId ?? null
1777
+ loopSessionId,
1778
+ // D24:已绑定 loop 的容器不得保留 content_blocks 预览(过程层 SSOT 在 loop tree)。
1779
+ content_blocks: loopSessionId ? [] : node.content_blocks
1760
1780
  };
1761
1781
  }
1762
1782
  return out;
@@ -2530,7 +2550,7 @@ function bindLoopSessionToContainerTree(tree, event, activeLoopSessionId) {
2530
2550
  ...nextTree,
2531
2551
  containersById: {
2532
2552
  ...nextTree.containersById,
2533
- [targetId]: { ...node, loopSessionId: sessionId }
2553
+ [targetId]: { ...node, loopSessionId: sessionId, content_blocks: [] }
2534
2554
  }
2535
2555
  };
2536
2556
  }
@@ -2839,8 +2859,8 @@ function isAtOrBeforeProjectionCursor(projectionCursor, eventId) {
2839
2859
  function hydrateWorkflowFromSnapshot(state, snapshot, options = {}) {
2840
2860
  const authority = options.preserveAuthority ? state.authority : null;
2841
2861
  const containerTree = structuredClone(snapshot.containerTree);
2842
- containerTree.containersById = sanitizeContainerTreeParentLinks(
2843
- containerTree.containersById
2862
+ containerTree.containersById = normalizeSnapshotContainerContentBlocks(
2863
+ sanitizeContainerTreeParentLinks(containerTree.containersById)
2844
2864
  );
2845
2865
  return {
2846
2866
  ...createEmptyWorkflowSessionState(),
@@ -3263,6 +3283,7 @@ import { useMemo as useMemo7, useState as useState6 } from "react";
3263
3283
 
3264
3284
  // src/view/workflow/WorkflowAggregateContainer.tsx
3265
3285
  import { useCallback, useEffect as useEffect5, useMemo as useMemo2, useState, memo } from "react";
3286
+ import { useStore as useStore2 } from "zustand";
3266
3287
 
3267
3288
  // src/view/workflow/WorkflowContainerLine.tsx
3268
3289
  import { Fragment, jsx as jsx5, jsxs as jsxs2 } from "react/jsx-runtime";
@@ -3406,6 +3427,44 @@ function WorkflowMarkdownPreview({
3406
3427
  return /* @__PURE__ */ jsx7("div", { className, "data-testid": testId, children: /* @__PURE__ */ jsx7(RichMarkdown, { content, deferDiagrams: true }) });
3407
3428
  }
3408
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
+
3409
3468
  // src/view/workflow/workflowStageListUtils.ts
3410
3469
  var ACTIVE_CONTAINER_STATUSES = /* @__PURE__ */ new Set([
3411
3470
  "running",
@@ -3648,12 +3707,23 @@ function workflowContainerViewPropsEqual(prev, next) {
3648
3707
  }
3649
3708
 
3650
3709
  // src/view/workflow/WorkflowAggregateContainer.tsx
3651
- import { jsx as jsx8, jsxs as jsxs4 } from "react/jsx-runtime";
3710
+ import { jsx as jsx9, jsxs as jsxs4 } from "react/jsx-runtime";
3652
3711
  function mergeContentPreview(node) {
3653
3712
  const blocks = node.content_blocks;
3654
3713
  if (blocks.length === 0) return "";
3655
3714
  return blocks.map((block) => block.preview?.trim() ?? "").filter(Boolean).join("\n\n");
3656
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
+ }
3657
3727
  function WorkflowAggregateContainerInner({
3658
3728
  node,
3659
3729
  loopTree,
@@ -3663,11 +3733,34 @@ function WorkflowAggregateContainerInner({
3663
3733
  virtualizeThreshold,
3664
3734
  groupParallelTools
3665
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);
3666
3744
  const isRunning = node.status === "running" || node.status === "retrying";
3667
3745
  const isWaiting = node.status === "pending" || node.status === "blocked";
3668
3746
  const isDone = node.status === "completed" || node.status === "failed";
3669
- const contentPreview = useMemo2(() => mergeContentPreview(node), [node]);
3670
- 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;
3671
3764
  const testId = `lax-workflow-aggregate-${node.scope_key}`;
3672
3765
  const uiStatus = mapAggregateUiStatus(node);
3673
3766
  const statusLabel = buildAggregateStatusLabel(node, siblingItems);
@@ -3676,18 +3769,40 @@ function WorkflowAggregateContainerInner({
3676
3769
  if (isRunning) setExpanded(true);
3677
3770
  if (isDone) setExpanded(false);
3678
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]);
3679
3778
  const toggleExpanded = useCallback(() => {
3680
- setExpanded((prev) => !prev);
3681
- }, []);
3682
- const shellToggle = isRunning ? toggleExpanded : isDone && expanded ? toggleExpanded : void 0;
3683
- 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(
3684
3798
  WorkflowMarkdownPreview,
3685
3799
  {
3686
- content: contentPreview,
3800
+ content: bodyMarkdown,
3687
3801
  testId: `${testId}-markdown`,
3688
3802
  className: "lax-workflow-aggregate__markdown lax-workflow-markdown-preview"
3689
3803
  }
3690
3804
  ) : null;
3805
+ const canExpandDone = isDone && (Boolean(loopTree) || Boolean(bodyMarkdown) || Boolean(node.loopSessionId));
3691
3806
  return /* @__PURE__ */ jsxs4(
3692
3807
  "div",
3693
3808
  {
@@ -3696,7 +3811,7 @@ function WorkflowAggregateContainerInner({
3696
3811
  "data-container-scope": "aggregate",
3697
3812
  style: { "--lax-workflow-depth": depth },
3698
3813
  children: [
3699
- /* @__PURE__ */ jsx8(
3814
+ /* @__PURE__ */ jsx9(
3700
3815
  WorkflowContainerLine,
3701
3816
  {
3702
3817
  title: node.title,
@@ -3705,15 +3820,15 @@ function WorkflowAggregateContainerInner({
3705
3820
  meta: buildAggregateLineMeta(node),
3706
3821
  statusLabel,
3707
3822
  onToggle: shellToggle,
3708
- interactive: isRunning,
3823
+ interactive: isRunning || isDone,
3709
3824
  expanded,
3710
3825
  titleTestId: `${testId}-title`,
3711
3826
  descriptionTestId: `${testId}-desc`
3712
3827
  }
3713
3828
  ),
3714
3829
  isWaiting && waitingTeaser ? /* @__PURE__ */ jsxs4("div", { className: "lax-workflow-aggregate__waiting-teaser", "data-testid": `${testId}-waiting`, children: [
3715
- /* @__PURE__ */ jsx8("span", { className: "lax-workflow-aggregate__waiting-prefix", children: "\u23BF " }),
3716
- /* @__PURE__ */ jsx8(
3830
+ /* @__PURE__ */ jsx9("span", { className: "lax-workflow-aggregate__waiting-prefix", children: "\u23BF " }),
3831
+ /* @__PURE__ */ jsx9(
3717
3832
  WorkflowMarkdownPreview,
3718
3833
  {
3719
3834
  content: waitingTeaser,
@@ -3721,7 +3836,7 @@ function WorkflowAggregateContainerInner({
3721
3836
  }
3722
3837
  )
3723
3838
  ] }) : null,
3724
- 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(
3725
3840
  AgentLoopView,
3726
3841
  {
3727
3842
  tree: loopTree,
@@ -3731,7 +3846,7 @@ function WorkflowAggregateContainerInner({
3731
3846
  groupParallelTools
3732
3847
  }
3733
3848
  ) }) : null,
3734
- expanded && isRunning && !loopTree && contentPreview ? /* @__PURE__ */ jsx8(
3849
+ expanded && isRunning && !loopTree && bodyMarkdown ? /* @__PURE__ */ jsx9(
3735
3850
  "div",
3736
3851
  {
3737
3852
  className: "lax-workflow-stage-container__body lax-workflow-stage-container__content-preview",
@@ -3740,36 +3855,44 @@ function WorkflowAggregateContainerInner({
3740
3855
  }
3741
3856
  ) : null,
3742
3857
  isDone && !expanded ? /* @__PURE__ */ jsxs4("div", { className: "lax-workflow-aggregate__done", "data-testid": `${testId}-done`, children: [
3743
- /* @__PURE__ */ jsx8(
3858
+ canExpandDone ? /* @__PURE__ */ jsx9(
3744
3859
  WorkflowExpandTrigger,
3745
3860
  {
3746
3861
  summary: `${node.title} \xB7 done`,
3747
- onToggle: () => setExpanded(true),
3862
+ onToggle: toggleExpanded,
3748
3863
  expanded: false,
3749
- expandHint: contentPreview ? "(click to expand)" : void 0,
3864
+ expandHint: bodyMarkdown || expandHint ? "(click to expand)" : void 0,
3750
3865
  testId: `${testId}-done-trigger`
3751
3866
  }
3752
- ),
3753
- 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
3754
3870
  ] }) : null,
3755
- isDone && expanded && loopTree ? /* @__PURE__ */ jsx8("div", { className: "lax-workflow-stage-container__body", "data-testid": `${testId}-body`, children: /* @__PURE__ */ jsx8(
3756
- AgentLoopView,
3871
+ isDone && expanded ? loopTree ? /* @__PURE__ */ jsx9(
3872
+ WorkflowStageDoneBody,
3757
3873
  {
3758
- tree: loopTree,
3759
- showTaskListFooter: false,
3874
+ node,
3875
+ loopTree,
3876
+ testId: `${testId}-body`,
3760
3877
  virtualized,
3761
3878
  virtualizeThreshold,
3762
3879
  groupParallelTools
3763
3880
  }
3764
- ) }) : null,
3765
- isDone && expanded && !loopTree && contentPreview ? /* @__PURE__ */ jsx8(
3881
+ ) : bodyMarkdown ? /* @__PURE__ */ jsx9(
3766
3882
  "div",
3767
3883
  {
3768
3884
  className: "lax-workflow-stage-container__body lax-workflow-stage-container__content-preview",
3769
3885
  "data-testid": `${testId}-body`,
3770
3886
  children: markdownPreview
3771
3887
  }
3772
- ) : 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
3773
3896
  ]
3774
3897
  }
3775
3898
  );
@@ -3886,47 +4009,7 @@ function formatParallelGroupSummary(metrics) {
3886
4009
 
3887
4010
  // src/view/workflow/WorkflowStageContainer.tsx
3888
4011
  import { useCallback as useCallback2, useEffect as useEffect6, useMemo as useMemo3, useState as useState2, memo as memo2 } from "react";
3889
- import { useStore as useStore2 } from "zustand";
3890
-
3891
- // src/core/workflow/loopTreeUtils.ts
3892
- function hasTimelineNodes(tree) {
3893
- if (!tree) return false;
3894
- return tree.rootChildren.length > 0 || Object.keys(tree.byId).length > 0;
3895
- }
3896
-
3897
- // src/view/workflow/workflowStageDoneBody.tsx
3898
- import { jsx as jsx9 } from "react/jsx-runtime";
3899
- function WorkflowStageDoneBody({
3900
- loopTree,
3901
- testId,
3902
- virtualized,
3903
- virtualizeThreshold,
3904
- groupParallelTools,
3905
- bodyClassName = "lax-workflow-stage-container__body"
3906
- }) {
3907
- if (loopTree && hasTimelineNodes(loopTree)) {
3908
- return /* @__PURE__ */ jsx9("div", { className: bodyClassName, "data-testid": testId, children: /* @__PURE__ */ jsx9(
3909
- AgentLoopView,
3910
- {
3911
- tree: loopTree,
3912
- showTaskListFooter: false,
3913
- virtualized,
3914
- virtualizeThreshold,
3915
- groupParallelTools
3916
- }
3917
- ) });
3918
- }
3919
- return /* @__PURE__ */ jsx9(
3920
- "div",
3921
- {
3922
- className: `${bodyClassName} lax-workflow-stage-container__empty-hint`,
3923
- "data-testid": testId,
3924
- 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" })
3925
- }
3926
- );
3927
- }
3928
-
3929
- // src/view/workflow/WorkflowStageContainer.tsx
4012
+ import { useStore as useStore3 } from "zustand";
3930
4013
  import { jsx as jsx10, jsxs as jsxs5 } from "react/jsx-runtime";
3931
4014
  function containerTestId(node) {
3932
4015
  if (node.scope === "item") return `lax-workflow-parallel-${node.scope_key}`;
@@ -3950,13 +4033,13 @@ function WorkflowStageContainerInner({
3950
4033
  const { verbose } = useSessionViewOptions();
3951
4034
  const store = useWorkflowSessionStoreApi();
3952
4035
  const replayHandler = useWorkflowLoopReplayHandler();
3953
- const activeLoopSessionId = useStore2(store, (s) => s.state.activeLoopSessionId);
3954
- const activeContainerIds = useStore2(store, (s) => s.state.containerTree.activeContainerIds);
3955
- 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(
3956
4039
  store,
3957
4040
  (s) => s.state.stageDoneSummariesByContainerId[node.container_id]
3958
4041
  );
3959
- const pinLoopSession = useStore2(store, (s) => s.pinLoopSession);
4042
+ const pinLoopSession = useStore3(store, (s) => s.pinLoopSession);
3960
4043
  const isRunning = node.status === "running" || node.status === "retrying";
3961
4044
  const isDone = node.status === "completed" || node.status === "failed";
3962
4045
  const isSkipped = node.status === "skipped";
@@ -4050,12 +4133,21 @@ function WorkflowStageContainerInner({
4050
4133
  }
4051
4134
  ),
4052
4135
  effectivelyDone && !expanded && (teaserText || expandHint) ? /* @__PURE__ */ jsxs5("div", { className: "lax-workflow-stage-container__done-teaser", children: [
4053
- teaserText ? /* @__PURE__ */ jsx10(
4054
- "span",
4136
+ teaserText ? /* @__PURE__ */ jsxs5(
4137
+ "div",
4055
4138
  {
4056
4139
  className: "lax-workflow-stage-container__done-teaser-line",
4057
4140
  "data-testid": `${testId}-teaser`,
4058
- 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
+ ]
4059
4151
  }
4060
4152
  ) : null,
4061
4153
  expandHint ? /* @__PURE__ */ jsx10("span", { className: "lax-workflow-expand-trigger__hint", children: expandHint }) : null
@@ -4066,10 +4158,10 @@ function WorkflowStageContainerInner({
4066
4158
  className: "lax-workflow-stage-container__body lax-workflow-stage-container__content-preview",
4067
4159
  "data-testid": bodyTestId(node),
4068
4160
  children: node.content_blocks.map((block, index) => /* @__PURE__ */ jsx10(
4069
- "div",
4161
+ WorkflowMarkdownPreview,
4070
4162
  {
4071
- className: "lax-workflow-stage-container__teaser",
4072
- children: block.preview
4163
+ content: block.preview,
4164
+ className: "lax-workflow-stage-container__teaser"
4073
4165
  },
4074
4166
  `${block.kind}-${index}`
4075
4167
  ))
@@ -4109,7 +4201,14 @@ function WorkflowStageContainerInner({
4109
4201
  className: "lax-workflow-stage-container__body lax-workflow-loop-replay-pending",
4110
4202
  "data-testid": bodyTestId(node),
4111
4203
  children: [
4112
- 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,
4113
4212
  /* @__PURE__ */ jsx10("p", { className: "lax-workflow-loop-replay-pending__hint", children: replayHandler ? "Loading loop details\u2026" : "Loop details evicted from memory." })
4114
4213
  ]
4115
4214
  }
@@ -4755,11 +4854,11 @@ function WorkflowChrome({
4755
4854
  }
4756
4855
 
4757
4856
  // src/view/workflow/WorkflowGlobalSpinner.tsx
4758
- import { useStore as useStore3 } from "zustand";
4857
+ import { useStore as useStore4 } from "zustand";
4759
4858
  import { jsx as jsx16, jsxs as jsxs11 } from "react/jsx-runtime";
4760
4859
  function WorkflowGlobalSpinner() {
4761
4860
  const store = useWorkflowSessionStoreApi();
4762
- const show = useStore3(store, (s) => shouldShowGlobalSpinner(s.state));
4861
+ const show = useStore4(store, (s) => shouldShowGlobalSpinner(s.state));
4763
4862
  if (!show) return null;
4764
4863
  return /* @__PURE__ */ jsx16(
4765
4864
  "div",
@@ -4869,7 +4968,7 @@ function WorkflowSessionBanners({ state }) {
4869
4968
 
4870
4969
  // src/view/workflow/WorkflowTaskListFooter.tsx
4871
4970
  import { useMemo as useMemo8, useState as useState7 } from "react";
4872
- import { useStore as useStore4 } from "zustand";
4971
+ import { useStore as useStore5 } from "zustand";
4873
4972
 
4874
4973
  // src/view/workflow/workflowTaskListMerge.ts
4875
4974
  var STATUS_ORDER = {
@@ -4949,7 +5048,7 @@ function MessageResponse({ children }) {
4949
5048
  }
4950
5049
  function WorkflowTaskListFooter() {
4951
5050
  const store = useWorkflowSessionStoreApi();
4952
- const state = useStore4(store, (s) => s.state);
5051
+ const state = useStore5(store, (s) => s.state);
4953
5052
  const [expanded, setExpanded] = useState7(false);
4954
5053
  const footerState = useMemo8(() => deriveWorkflowTaskFooterState(state), [state]);
4955
5054
  const visible = shouldShowWorkflowTaskListFooter(state);
@@ -4989,7 +5088,7 @@ function WorkflowTaskListFooter() {
4989
5088
  }
4990
5089
 
4991
5090
  // src/view/workflow/WorkflowSession.tsx
4992
- import { useStore as useStore5 } from "zustand";
5091
+ import { useStore as useStore6 } from "zustand";
4993
5092
  import { jsx as jsx19, jsxs as jsxs14 } from "react/jsx-runtime";
4994
5093
  function WorkflowSession({
4995
5094
  source,
@@ -5031,8 +5130,8 @@ function WorkflowSession({
5031
5130
  }
5032
5131
  const store = storeRef.current;
5033
5132
  useWorkflowAuthorityBinding(store, authoritySource, { onAuthorityTerminal });
5034
- const streamEnded = useStore5(store, (s) => s.state.display.streamEnded);
5035
- 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);
5036
5135
  useWorkflowAwaitingAuthorityTimers(store, streamEnded, authorityStatus);
5037
5136
  useEffect10(() => {
5038
5137
  if (snapshotBootstrap) {
@@ -5081,7 +5180,7 @@ function WorkflowSession({
5081
5180
  workspaceRoot
5082
5181
  ]
5083
5182
  );
5084
- const sessionState = useStore5(store, (s) => s.state);
5183
+ const sessionState = useStore6(store, (s) => s.state);
5085
5184
  const containerTree = sessionState.containerTree;
5086
5185
  const loopTreesBySessionId = sessionState.loopTreesBySessionId;
5087
5186
  const onErrorRef = useRef4(onError);