@tea-agent/loop-agent 0.6.0 → 0.7.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.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,22 @@
2
2
 
3
3
  这里记录每个版本面向使用者的主要变化。保持简短即可:新增、修改、修复或删除了什么,不需要展开实现细节。
4
4
 
5
+ ## [Unreleased]
6
+
7
+ ## [0.7.0] - 2026-07-11
8
+
9
+ ### 新增
10
+
11
+ - TaskSpec 新增可选 `capabilities: [interactive-ui]`:在不改变 `risk_level` / governance profile 的前提下,仅将 implement/repair writer 路由到 HIGH canonical model,并注入真实 UI component、integration 与 DOM interaction test 交付契约。
12
+ - Round-2 FE dogfood 新增真实 React/ReactDOM + Testing Library/user-event/jsdom fixture、AC-FE-001 DOM 验收,以及 prompt-only MED / default-prompt HIGH / UI-prompt HIGH 的 A/B/C DAG 变体生成脚本与实验记录模板。
13
+ - dogfood Feature `F-2026-001` 新增第二个前端任务 `FE-002`(frontend session store,独立于 FE-001)与对应验收项 `AC-FE-002`,补齐“第二个 FE”覆盖。
14
+
15
+ ### 修复
16
+
17
+ - 修复 `scripts-local/setup-drill-round1.sh` 在 `.task-pool/` 已忽略时仍尝试提交 state、覆盖 init 生成的 `.gitignore` managed block、依赖版本漂移及危险目标路径缺少保护的问题。
18
+ - 新增首轮夜间演练报告 `docs/reports/2026-07-10-nightly-drill-round-1.md`:记录 0.6.0 已发布控制器下的 batch/晨报/决策闭环、review-gated 失败与人工接管证据。
19
+ - 新增可复现演练目标仓库 setup 脚本 `scripts-local/setup-drill-round1.sh`。
20
+
5
21
  ## [0.6.0] - 2026-07-10
6
22
 
7
23
  ### 新增
@@ -19,6 +19,7 @@ export const referenceDocConfigSchema = z.object({
19
19
  path: z.string().min(1),
20
20
  });
21
21
  export const taskComplexitySchema = z.enum(["small", "medium", "large"]);
22
+ export const taskCapabilitySchema = z.enum(["interactive-ui"]);
22
23
  export const contextProfileSchema = z.enum(["full", "slim"]);
23
24
  export const piSubagentModeSchema = z.enum(["off", "analyze-plan", "full"]);
24
25
  export const verifyModeSchema = z.enum(["parallel", "serial"]);
@@ -68,6 +69,8 @@ export const taskConfigSchema = z.object({
68
69
  timeoutMs: z.number().int().positive().optional(),
69
70
  flow: taskFlowSchema.optional().default("auto"),
70
71
  complexity: taskComplexitySchema.optional().default("medium"),
72
+ /** Explicit delivery capabilities that affect writer contracts/model tier without changing risk. */
73
+ capabilities: z.array(taskCapabilitySchema).optional(),
71
74
  verifyMode: verifyModeSchema.optional().default("parallel"),
72
75
  verifyPreset: verifyPresetSchema.optional().default("auto"),
73
76
  /** Verification selection policy. Intermediate loops may use quota; final gates still run full required verification. */
@@ -40,6 +40,7 @@ export async function materializeTaskSpec(options) {
40
40
  forbiddenPaths: options.taskSpec.constraints.forbidden_paths,
41
41
  hardConstraints: options.taskSpec.constraints.hard_constraints,
42
42
  complexity: mapRiskLevelToComplexity(options.taskSpec.risk_level),
43
+ capabilities: options.taskSpec.capabilities ?? [],
43
44
  verifyMode: options.taskSpec.verify.mode,
44
45
  verifyPreset: options.taskSpec.verify.preset,
45
46
  verifyQuota: options.taskSpec.verify.quota,
@@ -135,6 +136,9 @@ export function renderRequirementMarkdown(taskSpec, options = {}) {
135
136
  `Risk level: ${taskSpec.risk_level}`,
136
137
  "",
137
138
  ];
139
+ if ((taskSpec.capabilities?.length ?? 0) > 0) {
140
+ lines.push("## Capabilities", "", ...bulletLines(taskSpec.capabilities ?? []), "");
141
+ }
138
142
  if (taskSpec.description) {
139
143
  lines.push("## Description", "", taskSpec.description, "");
140
144
  }
@@ -1,5 +1,5 @@
1
1
  import { z } from "zod";
2
- import { verifyModeSchema, verifyPresetSchema, verifyQuotaSchema, } from "../../task/config-types.js";
2
+ import { taskCapabilitySchema, verifyModeSchema, verifyPresetSchema, verifyQuotaSchema, } from "../../task/config-types.js";
3
3
  export const taskSpecTypeSchema = z.enum([
4
4
  "architecture",
5
5
  "backend-feature",
@@ -42,6 +42,7 @@ export const taskSpecSchema = z
42
42
  type: taskSpecTypeSchema,
43
43
  priority: z.enum(["P0", "P1", "P2", "P3"]).optional().default("P2"),
44
44
  risk_level: taskSpecRiskLevelSchema,
45
+ capabilities: z.array(taskCapabilitySchema).optional(),
45
46
  depends_on: z.array(z.string().min(1)).optional().default([]),
46
47
  source_docs: z
47
48
  .object({
@@ -17,6 +17,32 @@ const CONSTRAINT_FILE = "执行约束.md";
17
17
  const REFERENCE_DIRECTORY = "references";
18
18
  const MAX_SOURCE_EXCERPT_CHARS = 2000;
19
19
  const MAX_SOURCE_REFERENCE_DOCUMENTS = 8;
20
+ const INTERACTIVE_UI_DELIVERY_CONTRACT = [
21
+ "[INTERACTIVE_UI_DELIVERY_CONTRACT]",
22
+ "This is an interactive UI delivery task.",
23
+ "A helper-only, data-only, validation-only, or serializable-view implementation does not satisfy the task.",
24
+ "Before editing: identify the existing UI framework and component conventions, the real render/integration point, and the user-interaction test seam.",
25
+ "Required delivery: a framework-native visible component; integration into the declared route or parent; user interaction and visible error rendering; component-level tests using the repository's UI test stack.",
26
+ "The completion summary must list the component path, integration path, interaction test path, and DOM assertions mapped to acceptance criteria. If any item is missing, do not claim completion.",
27
+ "[/INTERACTIVE_UI_DELIVERY_CONTRACT]",
28
+ ].join("\n");
29
+ function isInteractiveUiTask(taskConfig) {
30
+ return taskConfig.capabilities?.includes("interactive-ui") ?? false;
31
+ }
32
+ function writerDeliveryContract(taskConfig) {
33
+ return isInteractiveUiTask(taskConfig)
34
+ ? INTERACTIVE_UI_DELIVERY_CONTRACT
35
+ : null;
36
+ }
37
+ function resolveWriterComplexity(taskConfig) {
38
+ if (isInteractiveUiTask(taskConfig))
39
+ return "HIGH";
40
+ if (taskConfig.complexity === "small")
41
+ return "MED";
42
+ if (taskConfig.complexity === "large")
43
+ return "HIGH";
44
+ return "MED";
45
+ }
20
46
  const HYBRID_DEFAULTS = {
21
47
  executor: "pi",
22
48
  piBackend: "sdk-first",
@@ -437,11 +463,7 @@ export function buildStandardHybridDagFromTask(sources) {
437
463
  const implementPaths = resolveImplementPaths(taskConfig);
438
464
  const scoutPaths = deriveParallelScoutPaths(taskConfig);
439
465
  const scoutComplexity = mapTaskComplexity(taskConfig.complexity);
440
- const implementComplexity = taskConfig.complexity === "small"
441
- ? "MED"
442
- : taskConfig.complexity === "large"
443
- ? "HIGH"
444
- : "MED";
466
+ const implementComplexity = resolveWriterComplexity(taskConfig);
445
467
  const writerExecutor = resolveImplementationExecutor(sources);
446
468
  const implementId = implementationNodeId(writerExecutor);
447
469
  const sourceContext = buildSourceContextBlock(sources);
@@ -543,8 +565,9 @@ export function buildStandardHybridDagFromTask(sources) {
543
565
  subtask_prompt: [
544
566
  "Implement the approved plan with minimal focused changes.",
545
567
  "Stay within writeSet. Do not write root artifacts/** unless artifacts paths are explicitly declared in writeSet.",
568
+ writerDeliveryContract(taskConfig),
546
569
  sourceContext,
547
- ].join("\n\n"),
570
+ ].filter((value) => Boolean(value)).join("\n\n"),
548
571
  },
549
572
  {
550
573
  id: "verify-pi",
@@ -828,7 +851,11 @@ function buildRepairNode(sources) {
828
851
  role: "implementer",
829
852
  executor: writerExecutor,
830
853
  toolProfile: "write",
831
- complexity: sources.taskConfig.complexity === "small" ? "MED" : "HIGH",
854
+ complexity: isInteractiveUiTask(sources.taskConfig)
855
+ ? "HIGH"
856
+ : sources.taskConfig.complexity === "small"
857
+ ? "MED"
858
+ : "HIGH",
832
859
  writePolicy: "exclusive",
833
860
  writeSet: implement.writeSet,
834
861
  allowedPaths: implement.allowedPaths,
@@ -838,8 +865,9 @@ function buildRepairNode(sources) {
838
865
  "If process-supervisor-pi returned VERDICT: request-revision, apply bounded fixes within writeSet addressing its REPAIR_ARTIFACT_JSON.fixScope and preserving REPAIR_ARTIFACT_JSON.invariant.",
839
866
  "Use REPAIR_ARTIFACT_JSON.failureClass and rootCause to choose the smallest repair strategy. Raw log is fallback evidence only when rawLogFallbackAllowed is true.",
840
867
  "If VERDICT: pass, return no-op with evidence. Re-run focused tests when you change code.",
868
+ writerDeliveryContract(sources.taskConfig),
841
869
  buildSourceContextBlock(sources),
842
- ].join("\n\n"),
870
+ ].filter((value) => Boolean(value)).join("\n\n"),
843
871
  };
844
872
  }
845
873
  function buildHardVerifyNode(sources) {
package/docs/README.md CHANGED
@@ -53,6 +53,7 @@
53
53
  - `templates/qa-report.md` — 验证与 QA 证据
54
54
  - `templates/worker-dogfood-setup.md` — 发布控制器下的真实 Worker sample setup 与 retry 纪律
55
55
  - `templates/worker-dogfood-evidence.md` — BE/FE/QA sample、Observe、morning report 与 coverage evidence 模板
56
+ - `templates/interactive-ui-round2-experiment.md` — interactive UI prompt/model A/B/C 对照实验与统一指标模板
56
57
  - `templates/production-readiness-checklist.md` — 低/中风险单仓库 DAG readiness 检查清单
57
58
  - `templates/init-evolution-review.md` — 初始化能力演化审查报告模板
58
59
  - `templates/adr.md` — 架构决策记录(ADR)
@@ -4,9 +4,9 @@
4
4
 
5
5
  源码仓库可在本 README 旁保留具体 active plan 文件。npm 包只携带本 README 作为目录契约,不复制 loop-agent 源码历史的 active plan;目标仓库自行生成 active plan。
6
6
 
7
- `2026-07-08-taskspec-worker-master.md` 7 个 step 已全部完成并归档到 `../completed/`。
7
+ 当前 active execution plan:
8
8
 
9
- 当前没有 active execution plan 以外的进行中项。
9
+ - `2026-07-10-release-0.6.0-nightly-drill.md` 技术演练已完成;等待 0.6.0 发布 owner 对 Day-1 provisional remediation 作明确 ratify / revise / reject。
10
+ - `2026-07-11-round-2-interactive-ui-productization.md` — 补齐 Round-1 owner gate,发布 interactive-ui controller,完成 React A/B/C、Round 2/3 扩量、CI/cron 和产品线模板/docs CI。
10
11
 
11
- - active:`2026-07-10-release-0.6.0-nightly-drill.md` — 发布 0.6.0,并用已发布控制器完成第 4 周首轮夜间 batch + 次日 morning report 决策闭环。
12
- - 已归档:`../completed/2026-07-10-next-stage-worker-evidence.md` 及更早的 TaskSpec/OBS 计划。
12
+ - 已归档:`../completed/2026-07-11-interactive-ui-writer-routing.md`、`../completed/2026-07-10-next-stage-worker-evidence.md` 及更早计划。
@@ -8,6 +8,7 @@ npm 包携带本 README 作为目录契约。具体 completed plan 属于目标
8
8
  - [`2026-07-04-remove-level1-fallback.md`](2026-07-04-remove-level1-fallback.md) — 移除历史顺序 Level 1 fallback,runtime、文档与 command surface 收敛到 DAG 执行
9
9
  - [`2026-07-04-runtime-boundary-remediation.md`](2026-07-04-runtime-boundary-remediation.md) — 整合 CLI/skill/runtime 边界,抽出 DAG/Loop runtime seam,集中 harness store/guard 策略
10
10
  - [`2026-07-10-next-stage-worker-evidence.md`](2026-07-10-next-stage-worker-evidence.md) — Worker retry、EnvFailure、边界治理、初始化投影与真实 BE/FE/QA dogfood evidence 闭环
11
+ - [`2026-07-11-interactive-ui-writer-routing.md`](2026-07-11-interactive-ui-writer-routing.md) — 新增 interactive-ui writer-only HIGH 路由、UI 交付契约、真实 React dogfood fixture 与 Round-2 A/B/C 实验入口
11
12
  - [`2026-07-04-dag-role-skill-alignment.md`](2026-07-04-dag-role-skill-alignment.md) — 对齐 DAG/Dynamic Workflow role 与 repo-local vetted skills,新增 strict skill audit
12
13
  - [`2026-07-06-production-readiness-hardening.md`](2026-07-06-production-readiness-hardening.md) — 冻结 Production Readiness v0.1,打磨 DAG 主路径 next steps、failure routing、doctor/report/failure handoff 与 dogfood 验证
13
14
  - [`2026-07-08-taskspec-schema-validate.md`](2026-07-08-taskspec-schema-validate.md) — 新增 TaskSpec v0.1 schema、三层校验器、risk→complexity 映射和 5 个 dogfood TaskSpec 样例
@@ -16,6 +16,7 @@
16
16
  "docs/templates/production-readiness-checklist.md",
17
17
  "docs/templates/worker-dogfood-setup.md",
18
18
  "docs/templates/worker-dogfood-evidence.md",
19
+ "docs/templates/interactive-ui-round2-experiment.md",
19
20
  "docs/templates/agent-dag.schema.json",
20
21
  "examples/example-dag.json",
21
22
  "skills/loop-agent/SKILL.md",
@@ -44,6 +45,7 @@
44
45
  "docs/templates/production-readiness-checklist.md",
45
46
  "docs/templates/worker-dogfood-setup.md",
46
47
  "docs/templates/worker-dogfood-evidence.md",
48
+ "docs/templates/interactive-ui-round2-experiment.md",
47
49
  "scripts/check-repo.sh",
48
50
  "scripts/ci-governance.sh",
49
51
  "scripts/ci-tests.sh",
@@ -88,6 +90,7 @@
88
90
  "docs/templates/production-readiness-checklist.md": "copied",
89
91
  "docs/templates/worker-dogfood-setup.md": "copied",
90
92
  "docs/templates/worker-dogfood-evidence.md": "copied",
93
+ "docs/templates/interactive-ui-round2-experiment.md": "copied",
91
94
  "scripts/check-repo.sh": "generated",
92
95
  "scripts/ci-governance.sh": "generated",
93
96
  "scripts/ci-tests.sh": "generated",
@@ -0,0 +1,66 @@
1
+ # Interactive UI Round-2 A/B/C Experiment
2
+
3
+ ## Frozen inputs
4
+
5
+ - Target repo / commit:
6
+ - Controller version:
7
+ - TaskSpec / acceptance hash:
8
+ - Base DAG:
9
+ - Model matrix:
10
+
11
+ Prepare the fixture and three DAGs after installing a published controller that contains `interactive-ui` support:
12
+
13
+ ```bash
14
+ bash scripts-local/setup-drill-round2-react.sh /tmp/drill-round2-react-target
15
+ npm run build
16
+ node scripts-local/prepare-round2-ui-experiment.mjs \
17
+ /tmp/drill-round2-react-target \
18
+ dogfood/features/F-2026-001/tasks/FE-001.yaml \
19
+ /tmp/round2-ui-experiment \
20
+ loop-agent
21
+ node scripts-local/build-round2-ui-variants.mjs \
22
+ /tmp/round2-ui-experiment/round2-ui-base.json \
23
+ /tmp/round2-ui-experiment/variants
24
+ ```
25
+
26
+ Validate every generated variant with the same frozen controller before running it. Use a unique run ID for A, B, and C; do not rewrite `executorModels`.
27
+
28
+ ## Variants
29
+
30
+ | Variant | Writer prompt | Writer tier | Run ID | Result |
31
+ | --- | --- | --- | --- | --- |
32
+ | A | interactive-ui contract | MED | | |
33
+ | B | default contract | HIGH | | |
34
+ | C | interactive-ui contract | HIGH | | |
35
+
36
+ ## Metrics
37
+
38
+ | Metric | A | B | C |
39
+ | --- | --- | --- | --- |
40
+ | First-pass review gate pass | | | |
41
+ | Framework-native `.tsx` component | | | |
42
+ | Route/parent integration | | | |
43
+ | DOM interaction tests | | | |
44
+ | Helper-only escape | | | |
45
+ | Duration | | | |
46
+ | Tokens | | | |
47
+
48
+ ## Required evidence per run
49
+
50
+ - DAG JSON and run ID
51
+ - implement/repair writer model and prompt profile
52
+ - changed component path
53
+ - integration path
54
+ - interaction test path
55
+ - DOM assertions mapped to AC-FE-001
56
+ - review verdict and deterministic test output
57
+ - diff boundary audit
58
+
59
+ ## Decision
60
+
61
+ - Production default:
62
+ - Evidence:
63
+ - Cost/quality trade-off:
64
+ - Follow-up:
65
+
66
+ Do not conclude from a single run when provider or environment failures occurred. Re-run the affected variant with the same frozen inputs and a new run ID.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tea-agent/loop-agent",
3
- "version": "0.6.0",
3
+ "version": "0.7.0",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "loop-agent": "bin/loop-agent.js",
@@ -377,7 +377,7 @@ agent-worker report morning --repo <repo-root> [--batch-run-id <id>] [--output <
377
377
 
378
378
  语义要点:
379
379
 
380
- - TaskSpec 声明单个任务的业务上下文、`risk_level`、验收与 verify 边界;`risk_level` 被确定性映射到 task complexityAcceptanceSpec / TaskGraphSpec 声明跨任务验收引用与依赖图,ready queue 决定可运行任务并检测未知依赖/环/文件一致性。
380
+ - TaskSpec 声明单个任务的业务上下文、`risk_level`、可选 `capabilities`、验收与 verify 边界;`risk_level` 被确定性映射到 task complexity。`capabilities: [interactive-ui]` 不改变风险或治理 profile,只把 implement/repair writer 路由到 HIGH,并注入禁止 helper-only 逃逸的真实 UI 交付契约。AcceptanceSpec / TaskGraphSpec 声明跨任务验收引用与依赖图,ready queue 决定可运行任务并检测未知依赖/环/文件一致性。
381
381
  - 业务 type(`backend-feature`/`frontend-feature`/`qa-testcode` 等)是产品线 profile,不能直接传给 `loop-agent dag run-task --profile`;Worker 会映射到 `auto`/`minimal`/`standard`/`reviewed`/`supervised`。
382
382
  - materializer 把 TaskSpec 物化为 `.harness/tasks/<task-id>`:`source_docs` 原样进入 `source/references/`,派生 `需求.md` 带权威声明、Source Docs/hash 追溯,以及 `acceptance_refs` 短摘要;随后 Worker 调用 `dag run-task` / `dag validate` / `run-dag` / `dag report`。review 节点须对照 references + 派生契约 + 实现。成功路径走 `promote-run` + `closeout task`;失败路径收集 `dag doctor` / `dag closeout-draft` evidence,写入目标 repo 的 `.task-pool/failure-handoffs/`(不写 `.harness/`,因为 `dag closeout-draft` 会拒绝在 completed facts 之外写入)。
383
383
  - Worker runtime state 落在目标 repo 的 `.task-pool/`(artifacts、JSONL/state、晨报、failure handoffs),与 `.harness/` 分离;`.task-pool/` 默认被 `.gitignore` 忽略。