@tea-agent/loop-agent 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. package/AGENTS.md +142 -142
  2. package/CHANGELOG.md +98 -106
  3. package/README.md +195 -195
  4. package/bin/agent-worker.js +22 -22
  5. package/bin/loop-agent.js +21 -21
  6. package/dist/application/dag/validate-dag.js +14 -1
  7. package/dist/commands/init.js +677 -489
  8. package/dist/commands/loop-benchmark.js +11 -11
  9. package/dist/commands/pi-reuse-benchmark.js +16 -16
  10. package/dist/executors/config-core.js +3 -2
  11. package/dist/executors/cursor-executor.js +1 -1
  12. package/dist/executors/model-routing.js +43 -0
  13. package/dist/governance/manifest-types.js +9 -1
  14. package/dist/task/runtime.js +27 -27
  15. package/dist/worker/pool/run-store.js +9 -1
  16. package/dist/workflows/dag/canvas-observer.js +275 -275
  17. package/dist/workflows/dag/init-hybrid.js +4 -13
  18. package/dist/workflows/dag/skill-instructions.js +4 -0
  19. package/dist/workflows/dag/types.js +1 -1
  20. package/dist/workflows/dag/validate.js +3 -2
  21. package/docs/README.md +72 -72
  22. package/docs/agent-dag-recovery-playbook.md +184 -184
  23. package/docs/agent-dag-runner.md +42 -42
  24. package/docs/architecture/runtime-boundaries.md +147 -147
  25. package/docs/cursor-executor-usage.md +25 -25
  26. package/docs/decisions/README.md +3 -3
  27. package/docs/design/README.md +36 -36
  28. package/docs/development-principles.md +73 -73
  29. package/docs/dynamic-workflow-dag-engine-roadmap.md +1749 -1749
  30. package/docs/exec-plans/README.md +6 -6
  31. package/docs/exec-plans/active/README.md +7 -7
  32. package/docs/exec-plans/completed/README.md +19 -19
  33. package/docs/feature-workflow.md +186 -186
  34. package/docs/harness-methodology-debugging.md +153 -153
  35. package/docs/harness-methodology-tdd.md +130 -130
  36. package/docs/harness-methodology-verification.md +27 -27
  37. package/docs/init-surface.manifest.json +199 -175
  38. package/docs/loop-agent-harness.md +42 -42
  39. package/docs/production-readiness.md +96 -96
  40. package/docs/progress/README.md +3 -3
  41. package/docs/reports/README.md +5 -5
  42. package/docs/skills/README.md +6 -6
  43. package/docs/skills/vetted-skill-registry.md +26 -26
  44. package/docs/templates/adr.md +60 -60
  45. package/docs/templates/agent-dag-authority-surface-audit.prompt.md +94 -94
  46. package/docs/templates/agent-dag-decision-envelope.schema.json +213 -213
  47. package/docs/templates/agent-dag-decision-gate-dogfood-report.md +117 -117
  48. package/docs/templates/agent-dag-decision-gate.prompt.md +246 -246
  49. package/docs/templates/agent-dag-process-supervisor.prompt.md +98 -98
  50. package/docs/templates/agent-dag-report.schema.json +454 -454
  51. package/docs/templates/agent-dag-review-verdict.prompt.md +68 -68
  52. package/docs/templates/agent-dag.base.json +195 -195
  53. package/docs/templates/agent-dag.final-verification.json +190 -190
  54. package/docs/templates/agent-dag.schema.json +316 -316
  55. package/docs/templates/agent-dag.supervised-implementation.json +500 -500
  56. package/docs/templates/exec-plan.md +64 -64
  57. package/docs/templates/feature-spec.md +53 -53
  58. package/docs/templates/hybrid-dag.json +193 -193
  59. package/docs/templates/init-evolution-review.md +33 -33
  60. package/docs/templates/production-readiness-checklist.md +57 -57
  61. package/docs/templates/progress-log.md +17 -17
  62. package/docs/templates/project-start-checklist.md +9 -9
  63. package/docs/templates/qa-report.md +48 -48
  64. package/docs/templates/sprint-contract.md +29 -29
  65. package/docs/verification-matrix.md +41 -41
  66. package/examples/decision-gate-agent-dag.json +123 -123
  67. package/examples/example-dag.json +51 -51
  68. package/examples/hybrid-loop-agent-dag.json +194 -194
  69. package/harness.json +69 -94
  70. package/package.json +66 -66
  71. package/skills/ai-engineering-context/SKILL.md +48 -48
  72. package/skills/code-review-core/SKILL.md +20 -20
  73. package/skills/codebase-scout/SKILL.md +19 -19
  74. package/skills/init-capability-evolution/SKILL.md +69 -69
  75. package/skills/loop-agent/SKILL.md +147 -147
  76. package/skills/loop-agent/references/README.md +67 -67
  77. package/skills/loop-agent/references/command-reference.md +403 -403
  78. package/skills/loop-agent/references/harness-policy.md +259 -259
  79. package/skills/loop-agent/references/hybrid-dag.md +216 -216
  80. package/skills/loop-agent/references/learned/README.md +21 -21
  81. package/skills/loop-agent/references/long-running-loop.md +59 -59
  82. package/skills/loop-agent/references/model-routing.md +36 -36
  83. package/skills/loop-agent/references/multi-worktree.md +54 -54
  84. package/skills/loop-agent/references/one-shot-runs.md +85 -85
  85. package/skills/loop-agent/references/orchestrator-and-interventions.md +169 -169
  86. package/skills/loop-agent/references/pi-prompt.md +23 -23
  87. package/skills/loop-agent/references/pi-subagent-assisted-mode.md +81 -81
  88. package/skills/loop-agent/references/post-implementation-and-patterns.md +44 -44
  89. package/skills/loop-agent/references/task-workflow.md +84 -84
  90. package/skills/loop-agent/references/verification-and-failure-handling.md +128 -128
  91. package/skills/requesting-code-review/SKILL.md +101 -101
  92. package/skills/requesting-code-review/code-reviewer.md +168 -168
  93. package/skills/systematic-debugging/CREATION-LOG.md +119 -119
  94. package/skills/systematic-debugging/SKILL.md +296 -296
  95. package/skills/systematic-debugging/condition-based-waiting-example.ts +158 -158
  96. package/skills/systematic-debugging/condition-based-waiting.md +115 -115
  97. package/skills/systematic-debugging/defense-in-depth.md +122 -122
  98. package/skills/systematic-debugging/find-polluter.sh +63 -63
  99. package/skills/systematic-debugging/root-cause-tracing.md +169 -169
  100. package/skills/systematic-debugging/test-academic.md +14 -14
  101. package/skills/systematic-debugging/test-pressure-1.md +58 -58
  102. package/skills/systematic-debugging/test-pressure-2.md +68 -68
  103. package/skills/systematic-debugging/test-pressure-3.md +69 -69
  104. package/skills/test-driven-development/SKILL.md +20 -20
  105. package/skills/verification-before-completion/SKILL.md +154 -154
  106. package/skills/webapp-testing/SKILL.md +19 -19
@@ -37,17 +37,17 @@ export function parseLoopBenchmarkArgs(args) {
37
37
  return { json, markdown, outputPath };
38
38
  }
39
39
  export function printLoopBenchmarkUsage() {
40
- console.log(`usage: loop-benchmark [options]
41
-
42
- Deterministic loop-agent loop benchmark baseline (no live Pi/Cursor calls).
43
-
44
- Options:
45
- --json Emit JSON (default when no format flag is set)
46
- --markdown Emit Markdown report
47
- --output <path> Write Markdown report to a repo-relative or absolute path
48
- -h, --help Show this help
49
-
50
- Control groups: single-repair, 3-pass-convergence, 3-pass-convergence+quota.
40
+ console.log(`usage: loop-benchmark [options]
41
+
42
+ Deterministic loop-agent loop benchmark baseline (no live Pi/Cursor calls).
43
+
44
+ Options:
45
+ --json Emit JSON (default when no format flag is set)
46
+ --markdown Emit Markdown report
47
+ --output <path> Write Markdown report to a repo-relative or absolute path
48
+ -h, --help Show this help
49
+
50
+ Control groups: single-repair, 3-pass-convergence, 3-pass-convergence+quota.
51
51
  Recommendation never changes convergence.enabled default.`);
52
52
  }
53
53
  export async function runLoopBenchmark(repoRoot, rawArgs) {
@@ -106,22 +106,22 @@ export function parsePiReuseBenchmarkArgs(args) {
106
106
  };
107
107
  }
108
108
  export function printPiReuseBenchmarkUsage() {
109
- console.log(`usage: pi-reuse-benchmark [options]
110
-
111
- Deterministic Pi runtime reuse benchmark/decision summary (no live Pi calls).
112
-
113
- Options:
114
- --report <path> Benchmark report markdown (approval status)
115
- --approval <path> Explicit approval JSON artifact
116
- --off-executor <path> Baseline executor.jsonl (reuse off)
117
- --on-executor <path> Treatment executor.jsonl (reuse on)
118
- --off-task <task-id> Resolve baseline from .harness/tasks/<id>/logs/executor.jsonl
119
- --on-task <task-id> Resolve treatment from .harness/tasks/<id>/logs/executor.jsonl
120
- --json Emit JSON (default when no format flag is set)
121
- --markdown Emit Markdown summary
122
- -h, --help Show this help
123
-
124
- Recommendations: defer | maintain-opt-in | eligible-for-human-review
109
+ console.log(`usage: pi-reuse-benchmark [options]
110
+
111
+ Deterministic Pi runtime reuse benchmark/decision summary (no live Pi calls).
112
+
113
+ Options:
114
+ --report <path> Benchmark report markdown (approval status)
115
+ --approval <path> Explicit approval JSON artifact
116
+ --off-executor <path> Baseline executor.jsonl (reuse off)
117
+ --on-executor <path> Treatment executor.jsonl (reuse on)
118
+ --off-task <task-id> Resolve baseline from .harness/tasks/<id>/logs/executor.jsonl
119
+ --on-task <task-id> Resolve treatment from .harness/tasks/<id>/logs/executor.jsonl
120
+ --json Emit JSON (default when no format flag is set)
121
+ --markdown Emit Markdown summary
122
+ -h, --help Show this help
123
+
124
+ Recommendations: defer | maintain-opt-in | eligible-for-human-review
125
125
  Never changes CODE_AGENT_PI_REUSE_RUNTIME default (off).`);
126
126
  }
127
127
  function resolveRepoRelative(repoRoot, filePath) {
@@ -1,5 +1,5 @@
1
1
  import { DEFAULT_CURSOR_MODEL } from './cursor-executor.js';
2
- import { DEFAULT_DAG_MODELS } from './model-routing.js';
2
+ import { resolveExecutorModelMatrix } from './model-routing.js';
3
3
  export const TASK_COMPLEXITY_TO_DAG = {
4
4
  small: 'LOW',
5
5
  medium: 'MED',
@@ -13,7 +13,8 @@ export function resolveCursorModelForTaskConfig(taskConfig, cursorConfig) {
13
13
  return taskConfig.cursorModel.trim();
14
14
  }
15
15
  const dagLevel = TASK_COMPLEXITY_TO_DAG[taskConfig.complexity ?? 'medium'];
16
- return DEFAULT_DAG_MODELS[dagLevel] ?? resolveCursorModel({}, cursorConfig);
16
+ const matrix = resolveExecutorModelMatrix('cursor', cursorConfig);
17
+ return matrix[dagLevel] ?? resolveCursorModel({}, cursorConfig);
17
18
  }
18
19
  export function resolveTaskExecutor(taskConfig, override) {
19
20
  if (override)
@@ -29,7 +29,7 @@ export function resolveArtifactWriteDir(options) {
29
29
  }
30
30
  export function buildArtifactPathPrompt(writeDir) {
31
31
  if (!writeDir)
32
- return `After changes, write artifacts/修改记录.md and artifacts/验证结果.md with verification evidence.
32
+ return `After changes, write artifacts/修改记录.md and artifacts/验证结果.md with verification evidence.
33
33
  ${ARTIFACT_INSTRUCTIONS}`;
34
34
  return [
35
35
  `After changes, write the following files:`,
@@ -1,9 +1,52 @@
1
+ import { DEFAULT_DAG_EXECUTOR_MODELS, } from '../workflows/dag/types.js';
1
2
  export const DEFAULT_DAG_CURSOR_MODEL = "composer-2.5";
2
3
  export const DEFAULT_DAG_MODELS = {
3
4
  HIGH: "gpt-5.5",
4
5
  MED: "composer-2.5",
5
6
  LOW: "composer-2.5",
6
7
  };
8
+ /**
9
+ * DAG executor model tier keys that may carry a per-complexity override.
10
+ */
11
+ const EXECUTOR_MODEL_TIERS = ["LOW", "MED", "HIGH"];
12
+ /**
13
+ * Resolve the DAG executor model matrix for a single executor from its harness
14
+ * `executors.<name>` config.
15
+ *
16
+ * Priority per tier (LOW/MED/HIGH):
17
+ * 1. execConfig[tier] (truthy and !== "default" sentinel)
18
+ * 2. execConfig.defaultModel (truthy and !== "default" sentinel)
19
+ * 3. DEFAULT_DAG_EXECUTOR_MODELS[executor][tier]
20
+ *
21
+ * The "default" literal (injected by the schema `.default("default")`) and
22
+ * absent/undefined both mean "no override, fall through".
23
+ */
24
+ export function resolveExecutorModelMatrix(executor, execConfig) {
25
+ const tierValue = (tier) => {
26
+ const tierOverride = execConfig?.[tier];
27
+ if (tierOverride && tierOverride !== "default")
28
+ return tierOverride;
29
+ const defaultModel = execConfig?.defaultModel;
30
+ if (defaultModel && defaultModel !== "default")
31
+ return defaultModel;
32
+ return DEFAULT_DAG_EXECUTOR_MODELS[executor][tier];
33
+ };
34
+ return {
35
+ LOW: tierValue("LOW"),
36
+ MED: tierValue("MED"),
37
+ HIGH: tierValue("HIGH"),
38
+ };
39
+ }
40
+ /**
41
+ * Resolve both pi and cursor DAG executor model matrices from a harness manifest.
42
+ * Single entry point for DAG generation and --strict-models baseline resolution.
43
+ */
44
+ export function resolveExecutorModelMatrices(manifest) {
45
+ return {
46
+ pi: resolveExecutorModelMatrix("pi", manifest.executors?.pi),
47
+ cursor: resolveExecutorModelMatrix("cursor", manifest.executors?.cursor),
48
+ };
49
+ }
7
50
  export function resolveModelSelection(manifest, taskConfig, step, options) {
8
51
  const retryAttempt = options?.retryAttempt ?? 0;
9
52
  if (Object.keys(manifest.modelProfiles ?? {}).length === 0) {
@@ -21,7 +21,15 @@ export const executorManifestSchema = z.object({
21
21
  description: z.string().optional(),
22
22
  enabled: z.boolean().optional(),
23
23
  defaultModel: z.string().optional().default("default"),
24
- requiresApiKey: z.string().optional().default("CURSOR_API_KEY"),
24
+ /**
25
+ * Per-complexity DAG model overrides. When set (and not the "default" sentinel),
26
+ * these take priority over defaultModel for the matching DAG executor tier.
27
+ * "default" literal and absent/undefined both mean "no override, fall through".
28
+ */
29
+ LOW: z.string().optional(),
30
+ MED: z.string().optional(),
31
+ HIGH: z.string().optional(),
32
+ requiresApiKey: z.string().optional(),
25
33
  });
26
34
  export const workflowPolicyProfileNameSchema = z.enum([
27
35
  "minimal",
@@ -236,35 +236,35 @@ export function shouldInjectSubagentGuidance(step, mode) {
236
236
  return false;
237
237
  }
238
238
  /** Advisory guidance for `analyze-plan` mode. */
239
- export const SUBAGENT_GUIDANCE_STANDARD = `<subagent_guidance>
240
- You have access to the \`subagent\` tool for lightweight delegation within this step.
241
- Use it only for read-only tasks:
242
- - Parallel scout: dispatch multiple subagents to search/read different areas simultaneously
243
- - Chain: scout -> planner (one subagent scouts, another plans based on findings)
244
- - Reviewer: have a subagent review your analysis/plan before finalizing
245
- Do NOT use subagent for writing, editing, or executing commands.
246
- Subagent output is advisory only; always verify and incorporate findings into your own output.
247
- Do NOT treat subagent results as authoritative state or artifact sources.
239
+ export const SUBAGENT_GUIDANCE_STANDARD = `<subagent_guidance>
240
+ You have access to the \`subagent\` tool for lightweight delegation within this step.
241
+ Use it only for read-only tasks:
242
+ - Parallel scout: dispatch multiple subagents to search/read different areas simultaneously
243
+ - Chain: scout -> planner (one subagent scouts, another plans based on findings)
244
+ - Reviewer: have a subagent review your analysis/plan before finalizing
245
+ Do NOT use subagent for writing, editing, or executing commands.
246
+ Subagent output is advisory only; always verify and incorporate findings into your own output.
247
+ Do NOT treat subagent results as authoritative state or artifact sources.
248
248
  </subagent_guidance>`;
249
249
  /** Strong guidance for `full` mode — prescriptive when to delegate. */
250
- export const SUBAGENT_GUIDANCE_STRONG = `<subagent_guidance>
251
- You have access to the \`subagent\` tool for lightweight delegation within this step.
252
-
253
- You SHOULD delegate to subagent scouts when:
254
- - The task requires scanning 3+ directories or comparing implementations across modules
255
- - You would otherwise need 5+ sequential read/grep calls to gather context
256
- - A reviewer subagent can independently catch scope drift before you finalize your output
257
-
258
- Delegation saves context tokens and produces better results.
259
-
260
- Allowed patterns:
261
- - Parallel scout: dispatch 2-3 subagents simultaneously to cover different file trees
262
- - Chain: scout -> planner (one subagent scouts, another plans based on findings)
263
- - Reviewer: have a subagent review your analysis/plan before finalizing
264
-
265
- Do NOT use subagent for writing, editing, or executing commands.
266
- Subagent output is advisory only; always verify and incorporate findings into your own output.
267
- Do NOT treat subagent results as authoritative state or artifact sources.
250
+ export const SUBAGENT_GUIDANCE_STRONG = `<subagent_guidance>
251
+ You have access to the \`subagent\` tool for lightweight delegation within this step.
252
+
253
+ You SHOULD delegate to subagent scouts when:
254
+ - The task requires scanning 3+ directories or comparing implementations across modules
255
+ - You would otherwise need 5+ sequential read/grep calls to gather context
256
+ - A reviewer subagent can independently catch scope drift before you finalize your output
257
+
258
+ Delegation saves context tokens and produces better results.
259
+
260
+ Allowed patterns:
261
+ - Parallel scout: dispatch 2-3 subagents simultaneously to cover different file trees
262
+ - Chain: scout -> planner (one subagent scouts, another plans based on findings)
263
+ - Reviewer: have a subagent review your analysis/plan before finalizing
264
+
265
+ Do NOT use subagent for writing, editing, or executing commands.
266
+ Subagent output is advisory only; always verify and incorporate findings into your own output.
267
+ Do NOT treat subagent results as authoritative state or artifact sources.
268
268
  </subagent_guidance>`;
269
269
  /** Preserved for backward compatibility (alias of STANDARD). */
270
270
  export const SUBAGENT_GUIDANCE = SUBAGENT_GUIDANCE_STANDARD;
@@ -74,7 +74,15 @@ export async function readJsonlFile(filePath) {
74
74
  }
75
75
  async function appendJsonlFile(filePath, value) {
76
76
  await mkdir(path.dirname(filePath), { recursive: true });
77
- await appendFile(filePath, `${JSON.stringify(value)}\n`, "utf-8");
77
+ try {
78
+ await appendFile(filePath, `${JSON.stringify(value)}\n`, "utf-8");
79
+ }
80
+ catch (error) {
81
+ const detail = error instanceof Error ? error.message : String(error);
82
+ // Include path so callers/tests can identify which JSONL file failed
83
+ // (Node EISDIR messages on Windows often omit the path).
84
+ throw new Error(`failed to append ${filePath}: ${detail}`, { cause: error });
85
+ }
78
86
  }
79
87
  async function ensurePoolDirs(repoRoot) {
80
88
  await mkdir(path.join(getTaskPoolRoot(repoRoot), "runs"), { recursive: true });