@tea-agent/loop-agent 0.36.3-beta.0 → 0.37.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. package/CHANGELOG.md +56 -55
  2. package/dist/build-stamp.json +3 -3
  3. package/dist/task/contract/project.js +4 -0
  4. package/dist/task/source-prepare/completeness.js +36 -0
  5. package/dist/task/source-prepare/parse-intent.js +67 -11
  6. package/dist/task/source-prepare/prepare.js +102 -5
  7. package/dist/worker/console/chat/chat-event-store.js +91 -0
  8. package/dist/worker/console/chat/pi-runtime.js +25 -0
  9. package/dist/worker/console/chat/routes.js +7 -2
  10. package/dist/worker/console/chat/semantic-activity.js +7 -1
  11. package/dist/worker/console/chat/session-store.js +6 -1
  12. package/dist/worker/console/chat/turn-process.js +119 -12
  13. package/dist/worker/console/operator-actions.js +18 -1
  14. package/dist/worker/console/static/assets/abnfDiagram-N423BO3Z-DSvF6RXQ.js +1 -0
  15. package/dist/worker/console/static/assets/arc-DuI4ogtJ.js +1 -0
  16. package/dist/worker/console/static/assets/architectureDiagram-T3A2C74G-DdBbgD4y.js +36 -0
  17. package/dist/worker/console/static/assets/blockDiagram-VBNYF7ZC-xQC2HELm.js +132 -0
  18. package/dist/worker/console/static/assets/c4Diagram-5PPSVZJV-DPMSgwIZ.js +10 -0
  19. package/dist/worker/console/static/assets/channel-DLVz9TYW.js +1 -0
  20. package/dist/worker/console/static/assets/chunk-2GRJ4B5K-WTEKTxin.js +1 -0
  21. package/dist/worker/console/static/assets/chunk-2Q5K7J3B-B6vZ0Pv_.js +1 -0
  22. package/dist/worker/console/static/assets/chunk-5RXB4S5H-BrerNAix.js +231 -0
  23. package/dist/worker/console/static/assets/chunk-5VM5RSS4-D_ch2aaI.js +15 -0
  24. package/dist/worker/console/static/assets/chunk-6Q2QTUOP-VvfacNrq.js +88 -0
  25. package/dist/worker/console/static/assets/chunk-GF5L2VYU-B-uGFIg2.js +206 -0
  26. package/dist/worker/console/static/assets/chunk-JWPE2WC7-BlysCtod.js +1 -0
  27. package/dist/worker/console/static/assets/chunk-KBJHAD2P-BjAUAfcT.js +1 -0
  28. package/dist/worker/console/static/assets/chunk-RYQCIY6F-BeZnBmb-.js +1 -0
  29. package/dist/worker/console/static/assets/chunk-XXDRQBXY-Bbfe3UJG.js +1 -0
  30. package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-BeAuGcO9.js +1 -0
  31. package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-BeAuGcO9.js +1 -0
  32. package/dist/worker/console/static/assets/cose-bilkent-JH36ORCC-BKJQnYVM.js +1 -0
  33. package/dist/worker/console/static/assets/cynefin-VYW2F7L2-B1wtI3hU.js +166 -0
  34. package/dist/worker/console/static/assets/cynefinDiagram-MW4NZA55-DCF6DBSu.js +62 -0
  35. package/dist/worker/console/static/assets/cytoscape.esm-yzknjiTM.js +321 -0
  36. package/dist/worker/console/static/assets/dagre-VZM6K2ZE-BJyNGRlP.js +4 -0
  37. package/dist/worker/console/static/assets/defaultLocale-DX6XiGOO.js +1 -0
  38. package/dist/worker/console/static/assets/diagram-7IWD3JNH-B7j1-VsZ.js +30 -0
  39. package/dist/worker/console/static/assets/diagram-B4RE2ZJO-BREJ140a.js +3 -0
  40. package/dist/worker/console/static/assets/diagram-LBJQPF4R-CDPHmHGH.js +24 -0
  41. package/dist/worker/console/static/assets/diagram-Q27KOJAE-BtZLrez1.js +24 -0
  42. package/dist/worker/console/static/assets/diagram-UB23O5K3-mzybu8oU.js +41 -0
  43. package/dist/worker/console/static/assets/ebnfDiagram-BXEA7PRR-Dk3I2uO6.js +1 -0
  44. package/dist/worker/console/static/assets/erDiagram-JOGREHBK-BT97u_tQ.js +85 -0
  45. package/dist/worker/console/static/assets/flowDiagram-UKHOOZJN-CMOtYzui.js +156 -0
  46. package/dist/worker/console/static/assets/ganttDiagram-PKOTCBZU-DiNydkuY.js +292 -0
  47. package/dist/worker/console/static/assets/gitGraphDiagram-DS77QQ5N-Cwt6fLkl.js +106 -0
  48. package/dist/worker/console/static/assets/graph-DOmOIIwC.js +1 -0
  49. package/dist/worker/console/static/assets/index-DQxiso1w.js +325 -0
  50. package/dist/worker/console/static/assets/index-_j0Hzo69.css +1 -0
  51. package/dist/worker/console/static/assets/infoDiagram-6WML65LV-AsGIGKKB.js +2 -0
  52. package/dist/worker/console/static/assets/init-Gi6I4Gst.js +1 -0
  53. package/dist/worker/console/static/assets/ishikawaDiagram-WSZJBQD7-BL8ITZh3.js +70 -0
  54. package/dist/worker/console/static/assets/journeyDiagram-NVQOT4AX-VPKAUX8M.js +139 -0
  55. package/dist/worker/console/static/assets/kanban-definition-27J2QSJJ-BL56hfGp.js +89 -0
  56. package/dist/worker/console/static/assets/layout-D-LzfAck.js +1 -0
  57. package/dist/worker/console/static/assets/linear-BmSG3nIZ.js +1 -0
  58. package/dist/worker/console/static/assets/map-DxJ2ADlA.js +1 -0
  59. package/dist/worker/console/static/assets/mermaid.core-DWGK9kwP.js +308 -0
  60. package/dist/worker/console/static/assets/mindmap-definition-FAOFIHXS--vvKLjo0.js +96 -0
  61. package/dist/worker/console/static/assets/ordinal-Cboi1Yqb.js +1 -0
  62. package/dist/worker/console/static/assets/pegDiagram-VL7TDLO6-B41mxb2-.js +1 -0
  63. package/dist/worker/console/static/assets/pieDiagram-7S7Q4E2Y-DTlu77sw.js +39 -0
  64. package/dist/worker/console/static/assets/quadrantDiagram-CIZ2JOQS-Bk5A7alv.js +7 -0
  65. package/dist/worker/console/static/assets/railroadDiagram-AXF67PYL-Csf9jzQy.js +1 -0
  66. package/dist/worker/console/static/assets/requirementDiagram-LRYGKXZP-CeptoSNx.js +84 -0
  67. package/dist/worker/console/static/assets/sankeyDiagram-W5VNT64P-A-DLCLer.js +40 -0
  68. package/dist/worker/console/static/assets/sequenceDiagram-SI44F4Z6-22VbPdOI.js +162 -0
  69. package/dist/worker/console/static/assets/sizeCapture-X5ZJPWSS-DWvAyBC9.js +1 -0
  70. package/dist/worker/console/static/assets/stateDiagram-OKZ733FA-qICZ75yT.js +1 -0
  71. package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-DzKvfHTX.js +1 -0
  72. package/dist/worker/console/static/assets/swimlanes-SLNWSIFB-xi7lcMyp.js +2 -0
  73. package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-Cxqr_qM1.js +8 -0
  74. package/dist/worker/console/static/assets/timeline-definition-Z64GVDOM-Bu6Nl6O2.js +120 -0
  75. package/dist/worker/console/static/assets/vennDiagram-T6HMQDX7-BzMz4Bn9.js +34 -0
  76. package/dist/worker/console/static/assets/wardleyDiagram-T6FBY63Y-CxaJnzc5.js +78 -0
  77. package/dist/worker/console/static/assets/xychartDiagram-ELKLHX3M-5JK-omQK.js +7 -0
  78. package/dist/worker/console/static/fonts/katex/KaTeX_AMS-Regular.woff2 +0 -0
  79. package/dist/worker/console/static/fonts/katex/KaTeX_Caligraphic-Bold.woff2 +0 -0
  80. package/dist/worker/console/static/fonts/katex/KaTeX_Caligraphic-Regular.woff2 +0 -0
  81. package/dist/worker/console/static/fonts/katex/KaTeX_Fraktur-Bold.woff2 +0 -0
  82. package/dist/worker/console/static/fonts/katex/KaTeX_Fraktur-Regular.woff2 +0 -0
  83. package/dist/worker/console/static/fonts/katex/KaTeX_Main-Bold.woff2 +0 -0
  84. package/dist/worker/console/static/fonts/katex/KaTeX_Main-BoldItalic.woff2 +0 -0
  85. package/dist/worker/console/static/fonts/katex/KaTeX_Main-Italic.woff2 +0 -0
  86. package/dist/worker/console/static/fonts/katex/KaTeX_Main-Regular.woff2 +0 -0
  87. package/dist/worker/console/static/fonts/katex/KaTeX_Math-BoldItalic.woff2 +0 -0
  88. package/dist/worker/console/static/fonts/katex/KaTeX_Math-Italic.woff2 +0 -0
  89. package/dist/worker/console/static/fonts/katex/KaTeX_SansSerif-Bold.woff2 +0 -0
  90. package/dist/worker/console/static/fonts/katex/KaTeX_SansSerif-Italic.woff2 +0 -0
  91. package/dist/worker/console/static/fonts/katex/KaTeX_SansSerif-Regular.woff2 +0 -0
  92. package/dist/worker/console/static/fonts/katex/KaTeX_Script-Regular.woff2 +0 -0
  93. package/dist/worker/console/static/fonts/katex/KaTeX_Size1-Regular.woff2 +0 -0
  94. package/dist/worker/console/static/fonts/katex/KaTeX_Size2-Regular.woff2 +0 -0
  95. package/dist/worker/console/static/fonts/katex/KaTeX_Size3-Regular.woff2 +0 -0
  96. package/dist/worker/console/static/fonts/katex/KaTeX_Size4-Regular.woff2 +0 -0
  97. package/dist/worker/console/static/fonts/katex/KaTeX_Typewriter-Regular.woff2 +0 -0
  98. package/dist/worker/console/static/index.html +2 -2
  99. package/dist/worker/console/static-src/operator-chat/chat-sse-events.js +25 -0
  100. package/dist/worker/console/static-src/operator-chat/useChatSessions.js +37 -2
  101. package/dist/worker/observe/static/operator-chrome.js +4 -2
  102. package/dist/workflows/dag/failure-routing.js +4 -9
  103. package/dist/workflows/dag/init-hybrid.js +2 -47
  104. package/dist/workflows/dag/lifecycle.js +0 -4
  105. package/dist/workflows/dag/node-execution.js +6 -16
  106. package/dist/workflows/dag/report.js +0 -6
  107. package/dist/workflows/dag/retry-policy.js +0 -11
  108. package/dist/workflows/dag/runner.js +19 -3
  109. package/dist/workflows/dag/types.js +0 -2
  110. package/dist/workflows/dag/validate.js +2 -7
  111. package/docs/templates/frontend-task-constraints.md +7 -13
  112. package/package.json +6 -1
  113. package/skills/loop-agent/references/command-reference.md +1 -0
  114. package/dist/worker/console/static/assets/index-D83DYAFG.css +0 -1
  115. package/dist/worker/console/static/assets/index-IXm7oYjL.js +0 -59
@@ -44,9 +44,7 @@ function routeToProductLine(input) {
44
44
  case "decision-envelope":
45
45
  return "NeedsHuman";
46
46
  case "skipped":
47
- return input.skippedReason === "frontend-prewrite-not-authorized"
48
- ? "ContractMismatch"
49
- : "DependencyFailure";
47
+ return "DependencyFailure";
50
48
  case "shell-command":
51
49
  if (/\b(ENOENT|PATH|command not found|No such file|not found in PATH|bash: .*: No such file)\b/i.test(raw)) {
52
50
  return "EnvFailure";
@@ -92,12 +90,9 @@ export function routeDagFailure(input) {
92
90
  if (!productLineFailureCategory)
93
91
  return {};
94
92
  const recommendedFollowUp = productLineFailureCategory === "ContractMismatch" &&
95
- input.skippedReason === "frontend-prewrite-not-authorized"
96
- ? "fix-frontend-task-contract-and-regenerate-dag"
97
- : productLineFailureCategory === "ContractMismatch" &&
98
- isFrontendDesignGateNode(input.nodeId ?? "")
99
- ? "frontend-plan-revision-and-rerun"
100
- : FOLLOW_UP_BY_PRODUCT_LINE[productLineFailureCategory];
93
+ isFrontendDesignGateNode(input.nodeId ?? "")
94
+ ? "frontend-plan-revision-and-rerun"
95
+ : FOLLOW_UP_BY_PRODUCT_LINE[productLineFailureCategory];
101
96
  return {
102
97
  productLineFailureCategory,
103
98
  recommendedFollowUp,
@@ -9,7 +9,7 @@ import { planMavenVerification, } from "../../verification/maven/index.js";
9
9
  import { pathMatchesPattern } from "../../shared/git-progress.js";
10
10
  import { BASELINE_FORBIDDEN_PATHS } from "./governance-constants.js";
11
11
  import { buildDecisionEnvelopePromptContract } from "./decision-envelope.js";
12
- import { DEFAULT_READ_ONLY_PI_RETRY_POLICY, PLANNER_OUTPUT_LIMIT_RETRY_POLICY, PROTOCOL_AWARE_PI_RETRY_POLICY, STRUCTURED_REQUIRED_PI_RETRY_POLICY, BACKEND_TEST_WRITER_COMPLETENESS_RETRY_POLICY, WRITER_TRANSPORT_RETRY_POLICY, isSafeReadOnlyPiRetryCandidate, isWriterTransportRetryCandidate, } from "./retry-policy.js";
12
+ import { DEFAULT_READ_ONLY_PI_RETRY_POLICY, PROTOCOL_AWARE_PI_RETRY_POLICY, STRUCTURED_REQUIRED_PI_RETRY_POLICY, BACKEND_TEST_WRITER_COMPLETENESS_RETRY_POLICY, WRITER_TRANSPORT_RETRY_POLICY, isSafeReadOnlyPiRetryCandidate, isWriterTransportRetryCandidate, } from "./retry-policy.js";
13
13
  import { REVIEW_JSON_VERDICT_OUTPUT_PROTOCOL, REVIEW_VERDICT_OUTPUT_PROTOCOL, } from "./output-protocol.js";
14
14
  import { resolveAdapter } from "../../adapters/index.js";
15
15
  import { loadHarnessManifest } from "../../governance/harness.js";
@@ -558,39 +558,6 @@ export function hasApiDependency(sources) {
558
558
  .some((clause) => !negationPatterns.some((pattern) => pattern.test(clause)) &&
559
559
  dependencyPatterns.some((pattern) => pattern.test(clause)));
560
560
  }
561
- /**
562
- * Generation-time heuristic: does the task source mention interface/API/Mock
563
- * needs anywhere (requirement or constraints)?
564
- *
565
- * Mirrors hasApiDependency's clause-level negation filtering so explicit
566
- * "not involved / not implementing" clauses and out-of-scope sections do not
567
- * become positive evidence. Used to emit a machine-visible advisory when auto
568
- * mode narrows Mock to not-needed despite the source mentioning such needs.
569
- */
570
- export function frontendSourceMentionsMock(sources) {
571
- const text = [sources.requirementMarkdown, sources.constraintMarkdown]
572
- .filter((entry) => typeof entry === "string" && entry.trim().length > 0)
573
- .map((entry) => normalizeTaskRequirementText(entry).replace(/`[^`\n]*`/g, " "))
574
- .join("\n");
575
- const signalPatterns = [
576
- /mock/i,
577
- /模拟服务/,
578
- /接口桩/,
579
- /\bmsw\b/i,
580
- /(?<![A-Za-z0-9_])API(?![A-Za-z0-9_])/i,
581
- /接口/,
582
- ];
583
- const negationPatterns = [
584
- /(?:不涉及|无需|不需要|不依赖|不调用|不请求|不实现|没有|禁止|不得).{0,16}(?:接口|后端|服务端|远程数据|异步数据|API|mock|模拟|桩)/i,
585
- /\b(?:no|without|does\s+not|do\s+not|must\s+not)\b.{0,24}\b(?:api|endpoint|request|backend|server|mock)\b/i,
586
- ];
587
- return text
588
- .split(/[。!?!?;;,,\r\n]+/)
589
- .map((clause) => clause.trim())
590
- .filter(Boolean)
591
- .some((clause) => !negationPatterns.some((pattern) => pattern.test(clause)) &&
592
- signalPatterns.some((pattern) => pattern.test(clause)));
593
- }
594
561
  /**
595
562
  * Resolve frontend Mock mode from capability seed, task config, and interface dependency analysis.
596
563
  *
@@ -2144,7 +2111,6 @@ function resolveFrontendMockContextBlock(sources) {
2144
2111
  parts.push("Generation-time evidence does not require Mock. The assessment must still use contract/scout evidence: select not-needed when Mock is intentionally skipped, or select a safe Mock strategy if project evidence supports one.");
2145
2112
  if (frontendMockStrategyMustBeNotNeeded(sources)) {
2146
2113
  parts.push('Auto mode has no confirmed project Mock capability or no deterministic Mock verification command. The structured contract must set mockApi.strategy to "not-needed". Do not add Mock files or dependencies; keep the real request path as default and record any unproved backend behavior as Real Integration Gap.');
2147
- parts.push('HARD CONSTRAINT (frozen at generation time): this DAG allows only mockApi.strategy "not-needed"; the prewrite gate rejects any other strategy. If project governance (openspec / ai_workspace / decision records, e.g. a DEC rule requiring native) demands Mock-backed verification, that is a generation-time contract gap, not a plan-revision defect: declare frontendMock.verifyCommands (or policy: "required") in task.json and regenerate the DAG. Do not emit any mockApi.strategy outside the allowlist and do not add Mock files or dependencies within this run.');
2148
2114
  }
2149
2115
  }
2150
2116
  if (mode === "blocked") {
@@ -2543,11 +2509,6 @@ async function buildFrontendHybridDagFromTask(sources) {
2543
2509
  `- Behavior command source: ${behaviorVerifyEvidence.commandSource}`,
2544
2510
  ...behaviorVerifyEvidence.commandLabels.map((command) => ` - ${JSON.stringify(command)}`),
2545
2511
  ].join("\n");
2546
- const advisories = [];
2547
- if (frontendSourceMentionsMock(frontendSources) &&
2548
- frontendMockStrategyMustBeNotNeeded(frontendSources)) {
2549
- advisories.push("auto 模式已将 Mock 策略收窄为 not-needed:任务源提到接口/API/Mock 需求,但仓库无确认 Mock 能力或无确定性 Mock 验证命令。若项目规范要求 Mock,请声明 frontendMock.verifyCommands 或 policy:required 后重新生成 DAG。");
2550
- }
2551
2512
  const spec = {
2552
2513
  version: 3,
2553
2514
  title: `Frontend implementation DAG: ${taskConfig.title}`,
@@ -2562,7 +2523,6 @@ async function buildFrontendHybridDagFromTask(sources) {
2562
2523
  skillsByRole: FRONTEND_SKILLS_BY_ROLE,
2563
2524
  executorModels: sources.executorModelMatrix ?? DEFAULT_DAG_EXECUTOR_MODELS,
2564
2525
  verifyStrategy: resolveDagVerifyStrategy(taskConfig),
2565
- advisories: advisories.length > 0 ? advisories : undefined,
2566
2526
  tasks: [
2567
2527
  {
2568
2528
  id: "frontend-contract-pi",
@@ -2657,7 +2617,6 @@ async function buildFrontendHybridDagFromTask(sources) {
2657
2617
  "Read-only: do not modify repository files.",
2658
2618
  fixedVerificationContext,
2659
2619
  sourceContext,
2660
- mockContextBlock,
2661
2620
  ].join("\n\n"),
2662
2621
  },
2663
2622
  {
@@ -2692,7 +2651,6 @@ async function buildFrontendHybridDagFromTask(sources) {
2692
2651
  fixedVerificationContext,
2693
2652
  sourceContext,
2694
2653
  frontendContractSchemaBlock,
2695
- mockContextBlock,
2696
2654
  ].join("\n\n"),
2697
2655
  },
2698
2656
  {
@@ -2723,7 +2681,6 @@ async function buildFrontendHybridDagFromTask(sources) {
2723
2681
  "Read-only: do not modify repository files.",
2724
2682
  fixedVerificationContext,
2725
2683
  sourceContext,
2726
- mockContextBlock,
2727
2684
  ].join("\n\n"),
2728
2685
  },
2729
2686
  {
@@ -5826,9 +5783,7 @@ function applyDefaultReadOnlyRetryPolicy(spec) {
5826
5783
  if (isSafeReadOnlyPiRetryCandidate(task)) {
5827
5784
  task.retryPolicy = task.outputProtocol
5828
5785
  ? PROTOCOL_AWARE_PI_RETRY_POLICY
5829
- : task.role === "planner"
5830
- ? PLANNER_OUTPUT_LIMIT_RETRY_POLICY
5831
- : DEFAULT_READ_ONLY_PI_RETRY_POLICY;
5786
+ : DEFAULT_READ_ONLY_PI_RETRY_POLICY;
5832
5787
  continue;
5833
5788
  }
5834
5789
  if (isWriterTransportRetryCandidate(task)) {
@@ -743,7 +743,6 @@ function findDoctorFailureNode(state) {
743
743
  nodeId: state.pausedByNodeId,
744
744
  status: node?.status,
745
745
  rawFailureCategory: node?.failureCategory,
746
- skippedReason: node?.skippedReason,
747
746
  };
748
747
  }
749
748
  const errorEntry = Object.entries(state.nodes).find(([, node]) => node.status === "ERROR");
@@ -759,7 +758,6 @@ function findDoctorFailureNode(state) {
759
758
  nodeId: selected[0],
760
759
  status: selected[1].status,
761
760
  rawFailureCategory: selected[1].failureCategory,
762
- skippedReason: selected[1].skippedReason,
763
761
  };
764
762
  }
765
763
  async function readRunOwnedBackendTestClassification(runDir) {
@@ -788,7 +786,6 @@ async function resolveDoctorFailureRouting(input) {
788
786
  normalizedFailureCategory: "unknown",
789
787
  nodeId: input.nodeId,
790
788
  productLineFailureCategory: classifiedCategory,
791
- skippedReason: input.skippedReason,
792
789
  });
793
790
  }
794
791
  return routeDagFailure(input);
@@ -810,7 +807,6 @@ async function formatDagDoctorMarkdown(repoRoot, runId) {
810
807
  rawFailureCategory,
811
808
  normalizedFailureCategory: normalizedCategory,
812
809
  nodeId: failure.nodeId,
813
- skippedReason: failure.skippedReason,
814
810
  });
815
811
  const evidence = failure.nodeId
816
812
  ? path.join(located.runDir, failure.nodeId, "result.summary.md")
@@ -216,28 +216,18 @@ function buildAttemptPrompt(task, basePrompt, attemptNumber, previousFailureCate
216
216
  "</retry_instruction>",
217
217
  ].join("\n");
218
218
  }
219
- if (previousFailureCategory !== "output-too-large") {
219
+ if (task.outputMode !== "structured-required" ||
220
+ previousFailureCategory !== "output-too-large") {
220
221
  return basePrompt;
221
222
  }
222
- if (task.outputMode === "structured-required") {
223
- return [
224
- basePrompt,
225
- "",
226
- "<retry_instruction>",
227
- "Previous attempt exceeded the structured output size limit.",
228
- "Return only the compact structured artifact required by this node's output contract.",
229
- "Do not include explanatory prose, duplicated upstream context, long evidence excerpts, or additional markdown sections.",
230
- "If a fenced JSON object is required, output exactly one fenced json block and nothing else.",
231
- "</retry_instruction>",
232
- ].join("\n");
233
- }
234
223
  return [
235
224
  basePrompt,
236
225
  "",
237
226
  "<retry_instruction>",
238
- "Previous attempt exceeded the output size limit.",
239
- "Return a minimal plan: ordered steps, narrow writeSet boundaries, and verification commands.",
240
- "Drop verbatim upstream quotes, long evidence excerpts, and repeated context.",
227
+ "Previous attempt exceeded the structured output size limit.",
228
+ "Return only the compact structured artifact required by this node's output contract.",
229
+ "Do not include explanatory prose, duplicated upstream context, long evidence excerpts, or additional markdown sections.",
230
+ "If a fenced JSON object is required, output exactly one fenced json block and nothing else.",
241
231
  "</retry_instruction>",
242
232
  ].join("\n");
243
233
  }
@@ -441,7 +441,6 @@ export async function buildDagRunReportEntry(input) {
441
441
  normalizedFailureCategory,
442
442
  nodeId,
443
443
  executor: node.executor,
444
- skippedReason: node.skippedReason,
445
444
  });
446
445
  const followUp = node.status === "ERROR" || node.status === "SKIPPED"
447
446
  ? recommendFollowUpForFailureCategory(node.failureCategory)
@@ -506,7 +505,6 @@ export async function buildDagRunReportEntry(input) {
506
505
  normalizedFailureCategory: normalizeDagFailureCategory(pausedNode.failureCategory, pausedNode.status),
507
506
  failureCategory: pausedNode.failureCategory,
508
507
  nodeId: input.state.pausedByNodeId,
509
- skippedReason: pausedNode.skippedReason,
510
508
  }
511
509
  : firstActionableNode
512
510
  ? {
@@ -515,7 +513,6 @@ export async function buildDagRunReportEntry(input) {
515
513
  normalizeDagFailureCategory(firstActionableNode.failureCategory, firstActionableNode.status),
516
514
  failureCategory: firstActionableNode.failureCategory,
517
515
  nodeId: firstActionableNode.nodeId,
518
- skippedReason: input.state.nodes[firstActionableNode.nodeId]?.skippedReason,
519
516
  }
520
517
  : {
521
518
  status: input.state.status,
@@ -532,9 +529,6 @@ export async function buildDagRunReportEntry(input) {
532
529
  rawFailureCategory: runRecoverySource.failureCategory,
533
530
  normalizedFailureCategory: runRecoverySource.normalizedFailureCategory,
534
531
  nodeId: "nodeId" in runRecoverySource ? runRecoverySource.nodeId : undefined,
535
- skippedReason: "skippedReason" in runRecoverySource
536
- ? runRecoverySource.skippedReason
537
- : undefined,
538
532
  });
539
533
  const runFollowUp = input.state.status === "failed" ||
540
534
  input.state.status === "partial_failed"
@@ -118,17 +118,6 @@ export const STRUCTURED_REQUIRED_PI_RETRY_POLICY = {
118
118
  ...DEFAULT_READ_ONLY_PI_RETRY_POLICY,
119
119
  retryCategories: [...STRUCTURED_REQUIRED_DAG_RETRY_CATEGORIES],
120
120
  };
121
- /**
122
- * Planner read-only nodes (standard DAG contract-pi / plan-pi) may retry with
123
- * a compact-output instruction when the model produced an oversized assistant
124
- * response. Only `output-too-large` is added on top of the default set;
125
- * report/review and other read-only roles keep the default set so they do not
126
- * silently learn new output semantics.
127
- */
128
- export const PLANNER_OUTPUT_LIMIT_RETRY_POLICY = {
129
- ...DEFAULT_READ_ONLY_PI_RETRY_POLICY,
130
- retryCategories: [...DEFAULT_DAG_RETRY_CATEGORIES, STRUCTURED_OUTPUT_RETRY_CATEGORY],
131
- };
132
121
  /**
133
122
  * Default retry for reviewer / recovery nodes that declare outputProtocol.
134
123
  * Includes protocol-invalid so missing VERDICT lines are corrected in-node.
@@ -115,6 +115,22 @@ export async function buildDagRunId(spec, options) {
115
115
  const existing = await listExistingDagRunIds(options.cwd);
116
116
  return collisionSafeDagRunId(baseId, existing, now);
117
117
  }
118
+ /**
119
+ * Append a human-readable round label to a run title when the runId carries
120
+ * a `-rN` collision suffix (2026-08-16): the sidebar / Inspect list showed
121
+ * identical titles for reruns and only the id hinted at the round.
122
+ */
123
+ export function titleWithRoundLabel(title, runId) {
124
+ const match = /-r(\d{1,2})$/.exec(runId);
125
+ if (!match)
126
+ return title;
127
+ const round = Number.parseInt(match[1], 10);
128
+ if (!Number.isFinite(round) || round < 2)
129
+ return title;
130
+ // Never stack labels on reruns of reruns.
131
+ const base = title.replace(/\s*(第\s*\d+\s*轮)$/u, "");
132
+ return `${base}(第 ${round} 轮)`;
133
+ }
118
134
  export function createInitialRunState(spec, opts, ranks, runId = opts.runId ?? "dag") {
119
135
  const nodes = {};
120
136
  for (const task of spec.tasks) {
@@ -136,7 +152,7 @@ export function createInitialRunState(spec, opts, ranks, runId = opts.runId ?? "
136
152
  : "execute";
137
153
  const state = {
138
154
  version: 1,
139
- title: spec.title,
155
+ title: titleWithRoundLabel(spec.title, runId),
140
156
  runId,
141
157
  cwd: opts.cwd,
142
158
  startedAt: new Date().toISOString(),
@@ -263,7 +279,7 @@ export async function runDag(spec, opts) {
263
279
  }
264
280
  if (opts.dryRun || opts.initOnly) {
265
281
  return {
266
- title: spec.title,
282
+ title: state.title,
267
283
  runId: state.runId,
268
284
  status: state.status,
269
285
  ranks,
@@ -717,7 +733,7 @@ async function executeDagCheckpoint(input) {
717
733
  await writeBudgetLedgerArtifacts(runDir, state.budgetLedger);
718
734
  await persistState({ allowCompletedFactsWrite: true });
719
735
  return {
720
- title: spec.title,
736
+ title: state.title,
721
737
  runId: state.runId,
722
738
  status: state.status,
723
739
  ranks,
@@ -822,8 +822,6 @@ export const dagSpecSchema = z
822
822
  defaults: dagDefaultsSchema,
823
823
  skillsByRole: z.record(z.string(), z.array(z.string())).optional(),
824
824
  executorModels: dagExecutorModelsSchema.optional(),
825
- /** Generation-time advisories surfaced as machine-visible warnings. */
826
- advisories: z.array(z.string()).optional(),
827
825
  tasks: z.array(dagTaskSchema).min(1),
828
826
  })
829
827
  .superRefine((spec, ctx) => {
@@ -14,7 +14,6 @@ const GOVERNANCE_WARNING_TYPES = new Set([
14
14
  "shell-verdict-gate-multi-command-state",
15
15
  "shell-verdict-gate-handwritten-inline",
16
16
  "orphan-writer-source-binding",
17
- "advisory",
18
17
  ]);
19
18
  const ROOT_ARTIFACT_PATH_PROBES = [
20
19
  "artifacts/修改记录.md",
@@ -33,11 +32,10 @@ export function collectGovernanceWarnings(issues) {
33
32
  return issues.filter(isGovernanceWarning);
34
33
  }
35
34
  function collectBlockingIssues(issues, options = {}) {
36
- const nonAdvisory = issues.filter((issue) => issue.type !== "advisory");
37
35
  if (options.strictGovernance) {
38
- return nonAdvisory;
36
+ return [...issues];
39
37
  }
40
- return nonAdvisory.filter((issue) => !isGovernanceWarning(issue));
38
+ return issues.filter((issue) => !isGovernanceWarning(issue));
41
39
  }
42
40
  function normalizePath(value) {
43
41
  return value.replace(/\\/g, "/").replace(/^\.\//, "");
@@ -958,9 +956,6 @@ export function validateDagSpec(spec) {
958
956
  validateSameRankWriteSetConflicts(spec, ranks, issues);
959
957
  validateSameRankAgentAttributionRisks(spec, ranks, issues);
960
958
  validateWriterSourceBinding(spec, issues);
961
- for (const advisory of spec.advisories ?? []) {
962
- issues.push({ type: "advisory", message: advisory });
963
- }
964
959
  return issues;
965
960
  }
966
961
  function validateProjectGovernanceTaskConfig(task, spec, issues) {
@@ -18,19 +18,13 @@ TODO
18
18
 
19
19
  ## Mock 约束(数据型任务)
20
20
 
21
- 本段决定生成期 `allowedMockStrategies` 与冻结的 Mock 验证命令。只有当生成期**能证明任务确实包含 Mock 且有确定性验证命令**时,DAG 才会放行 `native` / `browser-intercept` / `request-adapter`;否则自动收敛为 `not-needed`,design review 若按项目规范改选 `native`,会在 prewrite 被 `mock-strategy-outside-allowed` 拦截、`implement` 被跳过。
22
-
23
- - **何时必须填**:项目规范(`openspec/project-specs/**`、`ai_workspace/**`、mock 规则或类似 DEC-* 决策)要求/建议 Mock;或需求涉及远端接口且后端未就绪。规范要求 Mock 时,优先 `task.json.frontendMock.policy: "required"`。
24
- - **命令要探索、不要硬编码**:到项目 `package.json` scripts 里找实际存在的 Mock 相关脚本(如 `mock`、`mock:*`、`dev:mock`,或名字含 mock 的脚本),结合既有 service root 的 handler/fixture/bootstrap 启动方式,确定一条**真实存在、确定、可自终止**(启动→断言→退出 0)的验证命令。常驻 dev server 必须包装成自终止脚本(start→assert→stop),否则 verify shell 会超时 fail-closed。
25
- - **写入 task.json**:把探索到的命令原样写进 `frontendMock.verifyCommands`(`label` 唯一、`command` 与项目脚本一致)。`label` 会进入冻结命令集,implementation contract 的 `verificationTarget.commandLabel` 必须逐字引用它。
26
- - **命令来源白名单**:只允许项目 `package.json` 已有脚本、Mock capability seed、或本段声明的 `verifyCommands`;plan/design 阶段不能发明 shell 命令。
27
- - **Mock/API/schema 规范路径**:TODO
28
- - **既有 Mock service root、handler/fixture/bootstrap**:TODO
29
- - **既有 browser/e2e interception 或 request adapter/DI seam**:TODO
30
- - **production 禁用边界**:TODO
31
- - **真实请求默认路径与 Mock 显式启用方式**:TODO
32
- - **`task.json.frontendMock.policy`**:`auto | required | disabled`(规范强制 Mock 用 `required`)
33
- - **被拦截时怎么修**:`mock-strategy-outside-allowed` / `no authorized Mock verification commands` 是**生成期契约问题,不是 plan 问题**——补 `frontendMock.verifyCommands`(或 `policy: "required"` + 命令)后**重新生成 DAG** 再跑,plan-revision 无法修复它。
21
+ - Mock/API/schema 规范路径:TODO
22
+ - 既有 Mock service root、handler/fixture/bootstrap:TODO
23
+ - 既有 browser/e2e interception request adapter/DI seam:TODO
24
+ - 启动、健康检查和专项验证命令:TODO
25
+ - production 禁用边界:TODO
26
+ - 真实请求默认路径与 Mock 显式启用方式:TODO
27
+ - `task.json.frontendMock.policy`:`auto | required | disabled`
34
28
 
35
29
  ## allowedPaths
36
30
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tea-agent/loop-agent",
3
- "version": "0.36.3-beta.0",
3
+ "version": "0.37.0",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "loop-agent": "bin/loop-agent.js",
@@ -65,6 +65,11 @@
65
65
  },
66
66
  "dependencies": {
67
67
  "commander": "^12.1.0",
68
+ "katex": "^0.16.47",
69
+ "mermaid": "^11.16.1",
70
+ "rehype-highlight": "^7.0.2",
71
+ "rehype-katex": "^7.0.1",
72
+ "remark-math": "^6.0.0",
68
73
  "semver": "^7.8.5",
69
74
  "yaml": "^2.9.0",
70
75
  "zod": "^3.25.76"
@@ -325,6 +325,7 @@ loop-agent dag request-interrupt --run-id <run-id> --request-id <id> --target-op
325
325
  loop-agent dag rerun --run-id <run-id> --from-node <node-id> --plan [--json] # 从节点重跑资格预检(不执行)
326
326
  loop-agent dag rerun --run-id <run-id> --from-node <node-id> --plan-hash <sha256> --request-id <key> --reason "..." [--json] # 安全子图 continuation
327
327
  loop-agent dag rerun-task --run-id <run-id> --reason "..." --request-id <key> [--profile auto] [--task-id <id>] [--json] # standalone 完整任务重跑
328
+ loop-agent dag request-interrupt --run-id <run-id> --request-id <key> --target-operation-id <op-id> --reason-code <code> --reason "..." --expected-runner-pid <pid> --expected-runner-hostname <host> --expected-runner-started-at <ts> --expected-controller-fingerprint <fingerprint> # 协作式中止:经 Human Gate 登记 interrupt.json,runner 等当前节点安全收敛后再停调度,不直接 SIGKILL
328
329
  loop-agent dag reconcile-tasks --glob '<pattern>' # 仅报告的 task/run/artifact/verify drift audit
329
330
  loop-agent dag final-verification <task-id> # 生成 closeout DAG,closeout artifact 后再 final verify
330
331
  loop-agent dag decision inspect --run-id <run-id> [--node-id <node-id>] # dry-run envelope 重解析;除 run 缺失外 exit 0