@tea-agent/loop-agent 0.25.5 → 0.26.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/AGENTS.md +2 -1
- package/CHANGELOG.md +1020 -986
- package/bin/loop-agent.js +21 -21
- package/dist/commands/cursor-prompt.js +6 -6
- package/dist/commands/init.js +68 -129
- package/dist/commands/loop-benchmark.js +11 -11
- package/dist/commands/pi-reuse-benchmark.js +16 -16
- package/dist/executors/dag-pi-executor.js +26 -20
- package/dist/executors/model-routing.js +34 -18
- package/dist/executors/shell-executor.js +1 -1
- package/dist/governance/manifest-types.js +33 -5
- package/dist/sidecars/cursor-prompt/executor.js +1 -1
- package/dist/task/task-demand-routing.js +3 -1
- package/dist/worker/console/chat/model-resolver.js +15 -3
- package/dist/worker/observe/static/constants.js +3 -2
- package/dist/worker/observe/static/copy.js +67 -67
- package/dist/worker/observe/static/dag-layout.d.ts +31 -31
- package/dist/worker/observe/static/dag-layout.js +83 -83
- package/dist/worker/observe/static/dag-model.js +1 -0
- package/dist/worker/observe/static/dom.js +220 -220
- package/dist/worker/observe/static/relations.js +133 -133
- package/dist/worker/observe/static/router.js +93 -93
- package/dist/worker/observe/static/run-processing.js +148 -148
- package/dist/worker/observe/static/styles.css +182 -42
- package/dist/worker/observe/static/views/batch.js +227 -227
- package/dist/worker/observe/static/views/dag-graph.js +172 -172
- package/dist/worker/observe/static/views/failures.js +143 -143
- package/dist/worker/observe/static/views/feature.js +492 -492
- package/dist/worker/observe/static/views/run.js +453 -453
- package/dist/worker/observe/static/views/shell.js +7 -7
- package/dist/worker/observe/static/views/timeline.js +163 -163
- package/dist/workflows/dag/backend-test-case-coverage-analysis.js +362 -45
- package/dist/workflows/dag/backend-test-case-manifest.js +20 -0
- package/dist/workflows/dag/backend-test-markdown-workflow.js +17 -0
- package/dist/workflows/dag/canvas-observer.js +275 -275
- package/dist/workflows/dag/init-hybrid.js +18 -15
- package/dist/workflows/dag/lifecycle.js +40 -30
- package/dist/workflows/dag/node-execution.js +13 -0
- package/dist/workflows/dag/types.js +59 -19
- package/docs/init-surface.manifest.json +3 -1
- package/docs/skills/README.md +7 -7
- package/docs/templates/README.md +1 -0
- package/docs/templates/adr.md +60 -60
- package/docs/templates/agent-dag-authority-surface-audit.prompt.md +94 -94
- package/docs/templates/agent-dag-decision-envelope.schema.json +213 -213
- package/docs/templates/agent-dag-decision-gate.prompt.md +246 -246
- package/docs/templates/agent-dag-process-supervisor.prompt.md +98 -98
- package/docs/templates/agent-dag-report.schema.json +473 -473
- package/docs/templates/agent-dag-review-verdict.prompt.md +68 -68
- package/docs/templates/backend-test-dag.json +9 -9
- package/docs/templates/backend-test-result.schema.json +99 -99
- package/docs/templates/feature-spec.md +53 -53
- package/docs/templates/frontend-design-contract.md +42 -42
- package/docs/templates/frontend-eval/fixtures/failures/01-type-build-error.md +17 -17
- package/docs/templates/frontend-eval/fixtures/failures/02-unit-component-test-fail.md +16 -16
- package/docs/templates/frontend-eval/fixtures/failures/03-fixture-schema-drift.md +16 -16
- package/docs/templates/frontend-eval/fixtures/failures/04-missing-loading-empty-error-state.md +16 -16
- package/docs/templates/frontend-eval/fixtures/failures/05-forbidden-write-writeset-expansion.md +16 -16
- package/docs/templates/frontend-eval/fixtures/failures/06-unapproved-dependency-add.md +16 -16
- package/docs/templates/frontend-eval/fixtures/failures/07-mock-production-on.md +21 -21
- package/docs/templates/frontend-eval/fixtures/functional/01-simple-component-style.md +29 -29
- package/docs/templates/frontend-eval/fixtures/functional/02-form-validation.md +28 -28
- package/docs/templates/frontend-eval/fixtures/functional/03-list-detail-page.md +28 -28
- package/docs/templates/frontend-eval/fixtures/functional/04-api-mock.md +29 -29
- package/docs/templates/frontend-eval/fixtures/functional/05-permission-auth-gated-ui.md +27 -27
- package/docs/templates/frontend-eval/fixtures/functional/06-ssr-server-client-boundary.md +28 -28
- package/docs/templates/frontend-eval/fixtures/functional/07-shared-public-component-api.md +28 -28
- package/docs/templates/frontend-eval/fixtures/functional/08-pure-local-no-remote.md +27 -27
- package/docs/templates/frontend-eval/metrics.md +138 -138
- package/docs/templates/frontend-eval/smoke-targets.md +53 -53
- package/docs/templates/frontend-task-constraints.md +35 -35
- package/docs/templates/frontend-task-requirement.md +70 -70
- package/docs/templates/harness.schema.json +29 -7
- package/docs/templates/init-evolution-review.md +35 -35
- package/docs/templates/init-managed-agents.md +137 -0
- package/docs/templates/interactive-ui-round2-experiment.md +66 -66
- package/docs/templates/knowledge-graph-bootstrap-dag.json +118 -118
- package/docs/templates/knowledge-sync-dag.json +178 -178
- package/docs/templates/knowledge-sync-draft.schema.json +71 -71
- package/docs/templates/product-line/closeout.yaml +9 -9
- package/docs/templates/product-line/design.md +13 -13
- package/docs/templates/product-line/links.md +10 -10
- package/docs/templates/product-line/requirement.md +17 -17
- package/docs/templates/product-line/test-plan.md +7 -7
- package/docs/templates/production-readiness-checklist.md +57 -57
- package/docs/templates/project-start-checklist.md +9 -9
- package/docs/templates/qa-report.md +48 -48
- package/docs/templates/sprint-contract.md +29 -29
- package/docs/templates/worker-dogfood-evidence.md +80 -80
- package/docs/templates/worker-dogfood-setup.md +68 -68
- package/harness.json +1 -2
- package/package.json +1 -1
- package/scripts/kb-bootstrap-init-skeleton.sh +0 -0
- package/scripts/kb-graph-incremental-prepare.mjs +386 -386
- package/scripts/kb-graph-materialize.mjs +105 -105
- package/scripts/kb-graph-promote.mjs +164 -164
- package/scripts/kb-query.mjs +554 -554
- package/skills/ai-engineering-context/SKILL.md +48 -48
- package/skills/analyze-product-dependencies/SKILL.md +67 -67
- package/skills/analyze-product-dependencies/agents/openai.yaml +4 -4
- package/skills/analyze-product-dependencies/references/api-documentation-schema.md +30 -30
- package/skills/analyze-product-dependencies/references/dependency-analysis-schema.md +28 -28
- package/skills/analyze-product-dependencies/references/example.md +76 -76
- package/skills/analyze-product-dependencies/references/forward-test-cases.md +35 -35
- package/skills/analyze-product-dependencies/references/input-contract.md +11 -11
- package/skills/analyze-product-dependencies/references/scouting-rules.md +61 -61
- package/skills/analyze-product-dependencies/scripts/test-validators.mjs +267 -267
- package/skills/analyze-product-dependencies/scripts/validate-api-documentation.mjs +101 -101
- package/skills/analyze-product-dependencies/scripts/validate-dependency-analysis.mjs +142 -142
- package/skills/analyze-product-dependencies/scripts/validate-product-requirement-input.mjs +76 -76
- package/skills/analyze-product-dependencies/scripts/validation-helpers.mjs +146 -146
- package/skills/analyze-product-requirements/SKILL.md +90 -90
- package/skills/analyze-product-requirements/agents/openai.yaml +4 -4
- package/skills/analyze-product-requirements/references/acceptance-criteria.md +91 -91
- package/skills/analyze-product-requirements/references/clarification-and-knowledge.md +56 -56
- package/skills/analyze-product-requirements/references/example.md +86 -86
- package/skills/analyze-product-requirements/references/forward-test-cases.md +66 -66
- package/skills/analyze-product-requirements/references/product-analysis-schema.md +32 -32
- package/skills/analyze-product-requirements/references/product-requirement-schema.md +33 -33
- package/skills/analyze-product-requirements/references/requirement-clarification-schema.md +35 -35
- package/skills/analyze-product-requirements/scripts/test-validators.mjs +193 -193
- package/skills/analyze-product-requirements/scripts/validate-product-analysis.mjs +69 -69
- package/skills/analyze-product-requirements/scripts/validate-product-requirement.mjs +97 -97
- package/skills/analyze-product-requirements/scripts/validate-requirement-clarification.mjs +98 -98
- package/skills/analyze-product-requirements/scripts/validation-helpers.mjs +156 -156
- package/skills/browser-tools/browser-content.js +103 -103
- package/skills/browser-tools/browser-cookies.js +35 -35
- package/skills/browser-tools/browser-eval.js +53 -53
- package/skills/browser-tools/browser-hn-scraper.js +108 -108
- package/skills/browser-tools/browser-nav.js +44 -44
- package/skills/browser-tools/browser-pick.js +162 -162
- package/skills/browser-tools/browser-screenshot.js +34 -34
- package/skills/browser-tools/browser-start.js +86 -86
- package/skills/browser-tools/package-lock.json +2556 -2556
- package/skills/browser-tools/package.json +19 -19
- package/skills/code-review-core/SKILL.md +20 -20
- package/skills/codebase-scout/SKILL.md +19 -19
- package/skills/grill-me/SKILL.md +10 -10
- package/skills/loop-agent/references/README.md +67 -67
- package/skills/loop-agent/references/command-reference.md +5 -4
- package/skills/loop-agent/references/docs-converge.md +126 -126
- package/skills/loop-agent/references/hybrid-dag.md +2 -2
- package/skills/loop-agent/references/learned/README.md +21 -21
- package/skills/loop-agent/references/long-running-loop.md +57 -57
- package/skills/loop-agent/references/model-routing.md +2 -0
- package/skills/loop-agent/references/one-shot-runs.md +85 -85
- package/skills/loop-agent/references/pi-prompt.md +23 -23
- package/skills/loop-agent/references/pi-subagent-assisted-mode.md +84 -84
- package/skills/playwright-cli/SKILL.md +420 -420
- package/skills/playwright-cli/references/element-attributes.md +23 -23
- package/skills/playwright-cli/references/playwright-tests.md +39 -39
- package/skills/playwright-cli/references/request-mocking.md +87 -87
- package/skills/playwright-cli/references/running-code.md +241 -241
- package/skills/playwright-cli/references/session-management.md +225 -225
- package/skills/playwright-cli/references/storage-state.md +275 -275
- package/skills/playwright-cli/references/test-generation.md +433 -433
- package/skills/playwright-cli/references/tracing.md +139 -139
- package/skills/playwright-cli/references/video-recording.md +143 -143
- package/skills/requesting-code-review/SKILL.md +101 -101
- package/skills/requesting-code-review/code-reviewer.md +168 -168
- package/skills/systematic-debugging/CREATION-LOG.md +119 -119
- package/skills/systematic-debugging/condition-based-waiting-example.ts +158 -158
- package/skills/systematic-debugging/condition-based-waiting.md +115 -115
- package/skills/systematic-debugging/defense-in-depth.md +122 -122
- package/skills/systematic-debugging/find-polluter.sh +63 -63
- package/skills/systematic-debugging/root-cause-tracing.md +169 -169
- package/skills/systematic-debugging/test-academic.md +14 -14
- package/skills/systematic-debugging/test-pressure-1.md +58 -58
- package/skills/systematic-debugging/test-pressure-2.md +68 -68
- package/skills/systematic-debugging/test-pressure-3.md +69 -69
- package/skills/using-git-worktrees/SKILL.md +215 -215
- package/skills/verification-before-completion/SKILL.md +154 -154
- package/skills/webapp-testing/SKILL.md +19 -19
package/bin/loop-agent.js
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { existsSync } from "node:fs";
|
|
3
|
-
import { dirname, join } from "node:path";
|
|
4
|
-
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
5
|
-
|
|
6
|
-
const packageRoot = dirname(dirname(fileURLToPath(import.meta.url)));
|
|
7
|
-
const cliEntry = join(packageRoot, "dist", "cli.js");
|
|
8
|
-
|
|
9
|
-
if (!existsSync(cliEntry)) {
|
|
10
|
-
console.error(
|
|
11
|
-
`loop-agent: cannot find built CLI at ${cliEntry}. Run \`npm run build\` before using the package bin.`,
|
|
12
|
-
);
|
|
13
|
-
process.exit(1);
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
try {
|
|
17
|
-
await import(pathToFileURL(cliEntry).href);
|
|
18
|
-
} catch (error) {
|
|
19
|
-
console.error(error instanceof Error ? error.message : String(error));
|
|
20
|
-
process.exit(1);
|
|
21
|
-
}
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
4
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
5
|
+
|
|
6
|
+
const packageRoot = dirname(dirname(fileURLToPath(import.meta.url)));
|
|
7
|
+
const cliEntry = join(packageRoot, "dist", "cli.js");
|
|
8
|
+
|
|
9
|
+
if (!existsSync(cliEntry)) {
|
|
10
|
+
console.error(
|
|
11
|
+
`loop-agent: cannot find built CLI at ${cliEntry}. Run \`npm run build\` before using the package bin.`,
|
|
12
|
+
);
|
|
13
|
+
process.exit(1);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
try {
|
|
17
|
+
await import(pathToFileURL(cliEntry).href);
|
|
18
|
+
} catch (error) {
|
|
19
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
20
|
+
process.exit(1);
|
|
21
|
+
}
|
|
@@ -141,7 +141,7 @@ async function runCursorPromptBatch(task, cwd, model, timeoutMs) {
|
|
|
141
141
|
}
|
|
142
142
|
async function runCursorPromptStreaming(task, cwd, model, timeoutMs) {
|
|
143
143
|
const startedAt = Date.now();
|
|
144
|
-
process.stderr.write(`[cursor-prompt] streaming (model=${model}, cwd=${cwd})
|
|
144
|
+
process.stderr.write(`[cursor-prompt] streaming (model=${model}, cwd=${cwd})
|
|
145
145
|
`);
|
|
146
146
|
const runDir = (await computeRunDir(cwd, task)) ?? undefined;
|
|
147
147
|
const result = await executeCursorPromptStream({
|
|
@@ -164,15 +164,15 @@ async function runCursorPromptStreaming(task, cwd, model, timeoutMs) {
|
|
|
164
164
|
});
|
|
165
165
|
const elapsed = ((Date.now() - startedAt) / 1000).toFixed(1);
|
|
166
166
|
if (result.ok) {
|
|
167
|
-
process.stderr.write(`
|
|
168
|
-
[cursor-prompt] done in ${elapsed}s, status=${result.status}
|
|
167
|
+
process.stderr.write(`
|
|
168
|
+
[cursor-prompt] done in ${elapsed}s, status=${result.status}
|
|
169
169
|
`);
|
|
170
170
|
}
|
|
171
171
|
else {
|
|
172
172
|
const stderr = result.stderr || "(no output)";
|
|
173
|
-
process.stderr.write(`
|
|
174
|
-
[cursor-prompt] FAILED in ${elapsed}s (${result.failureCategory}):
|
|
175
|
-
${stderr}
|
|
173
|
+
process.stderr.write(`
|
|
174
|
+
[cursor-prompt] FAILED in ${elapsed}s (${result.failureCategory}):
|
|
175
|
+
${stderr}
|
|
176
176
|
`);
|
|
177
177
|
process.exit(1);
|
|
178
178
|
}
|
package/dist/commands/init.js
CHANGED
|
@@ -4,7 +4,6 @@ import os from "node:os";
|
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { isDeepStrictEqual } from "node:util";
|
|
6
6
|
import { fileURLToPath } from "node:url";
|
|
7
|
-
import { copyDir } from "../shared/copy-dir.js";
|
|
8
7
|
import { isInitRuntimeActive, } from "../shared/runtime-activity.js";
|
|
9
8
|
import { loadHarnessManifest } from "../governance/harness.js";
|
|
10
9
|
import { OPENCODE_TRANSIENT_RETRY_PLUGIN_PATH, applyPiRetryMerge, buildOpenCodeTransientRetryPluginSource, inspectPiRetryConfig, parseClientRecoveryMode, runClientRecovery, } from "./client-recovery.js";
|
|
@@ -119,6 +118,12 @@ const COMPAT_PROMPTS = {
|
|
|
119
118
|
].join("\n"),
|
|
120
119
|
};
|
|
121
120
|
const GOVERNANCE_ROOT_TOKEN = "__LOOP_AGENT_GOVERNANCE_ROOT__";
|
|
121
|
+
const PROJECT_NAME_TOKEN = "__LOOP_AGENT_PROJECT_NAME__";
|
|
122
|
+
/** Package-shipped render source for AGENTS.md managed block; not projected to target repos. */
|
|
123
|
+
const MANAGED_AGENTS_TEMPLATE_PATH = "docs/templates/init-managed-agents.md";
|
|
124
|
+
/** Files under package assets that init must not copy into target projects. */
|
|
125
|
+
const PACKAGE_ONLY_SURFACE_FILES = new Set([MANAGED_AGENTS_TEMPLATE_PATH]);
|
|
126
|
+
let managedAgentsTemplateCache;
|
|
122
127
|
const INIT_CHECK_ENGINEERING_STRUCTURE_SH = `#!/usr/bin/env bash
|
|
123
128
|
set -euo pipefail
|
|
124
129
|
|
|
@@ -798,130 +803,28 @@ function mergeRecord(base, patch) {
|
|
|
798
803
|
...patch,
|
|
799
804
|
};
|
|
800
805
|
}
|
|
801
|
-
function
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
"| **允许** | 已发布 `loop-agent` / `agent-worker` CLI;只读 status/doctor/report/inspect/observe;准备 `source/*` 与 `task.json` 边界;human gate;shell 验证与 handoff。 |",
|
|
824
|
-
"| **禁止** | 绕过 CLI 用宿主 Edit/Write/ApplyPatch 直接改业务实现;CLI/DAG 失败后「救火改文件」;用聊天自述代替 shell 验证。 |",
|
|
825
|
-
"| **失败时** | `dag doctor` / `dag report` / `dag reconcile-run`(及适用 worker reconcile);修正任务源/`task.json`/DAG 后经 CLI 重跑。 |",
|
|
826
|
-
"| **实现写入** | 业务代码 **只** 经受治理 DAG writer(`implement-pi` / `repair-pi`)经 `dag run-task` / `run-dag`。 |",
|
|
827
|
-
"",
|
|
828
|
-
"**永远不要**:`loop-agent` / `agent-worker` 失败 ⇒ 主会话直接改仓库实现。",
|
|
829
|
-
"",
|
|
830
|
-
"### 自然语言入口路由",
|
|
831
|
-
"",
|
|
832
|
-
"| 用户表达 | 入口 | 执行动作 |",
|
|
833
|
-
"|---|---|---|",
|
|
834
|
-
"| loop-agent 初始化 / loop agent 初始化 / loop agent初始化 / 初始化 loop-agent | 初始化 | 完成确定性初始化闭环 |",
|
|
835
|
-
"| 初始化更新校验 / 检查初始化更新 / loop-agent 初始化更新校验 / loop agent初始化更新校验 | 更新校验 | 只读报告,不写入 |",
|
|
836
|
-
"| 初始化对齐 / 升级后对齐 / reconcile 初始化 / loop-agent 初始化对齐 | 升级对齐 | 自动应用确定性安全动作;活跃 DAG/Worker 或人工决策时零写入 |",
|
|
837
|
-
"| 初始化安全更新 / 应用初始化更新 / loop-agent 初始化安全更新 / loop agent初始化安全更新 | 安全更新 | 先 check-update,再只执行确定性安全动作 |",
|
|
838
|
-
"| loop-agent 帮我完成 / 帮我实现 / 帮我修复 / 帮我开发 <需求>;使用 loop-agent 完成 <X>;按 loop-agent 流程处理 <X> | 通用需求实现 | 先建任务源与 `task.json.allowedPaths` / `forbiddenPaths`,再 `new-task` → `dag run-task` → `dag validate` → `run-dag`;主会话不得直接修改业务实现 |",
|
|
839
|
-
"",
|
|
840
|
-
"**更新校验(只读)**:只读执行下面命令;**不得自动**执行 `apply-safe` 或模型合并。",
|
|
841
|
-
"",
|
|
842
|
-
"```bash",
|
|
843
|
-
"loop-agent init check-update --repo-root . --markdown",
|
|
844
|
-
"```",
|
|
845
|
-
"",
|
|
846
|
-
"**升级对齐**:`loop-agent init reconcile --repo-root .`;存在活跃 DAG/Worker、human decisions 时必须零写入。",
|
|
847
|
-
"",
|
|
848
|
-
"**安全更新**:先 check-update,再 `apply-safe`;surface 缺失才 `--bootstrap-surface`。完成后复查 `init doctor` / `inspect` / `docs audit` 与目标治理检查。",
|
|
849
|
-
"",
|
|
850
|
-
"```bash",
|
|
851
|
-
"loop-agent init check-update --repo-root . --markdown",
|
|
852
|
-
"loop-agent init update --repo-root . --apply-safe",
|
|
853
|
-
"```",
|
|
854
|
-
"",
|
|
855
|
-
"### 初始化闭环",
|
|
856
|
-
"",
|
|
857
|
-
`当用户要求初始化 loop-agent(“初始化 loop-agent”“loop agent 初始化”“loop agent初始化”“loop-agent 初始化”),或发现 \`README.md\` / \`${input.governanceRoot}/verification-matrix.md\` 仍停留在通用初始化状态时,模型应在同一轮工作中完成初始化闭环,不要把补全文档和验证矩阵留给用户交互。`,
|
|
858
|
-
"",
|
|
859
|
-
"1. 运行 `loop-agent init instructions --repo-root .`。",
|
|
860
|
-
"2. 运行 `loop-agent init --repo-root . --profile full --merge`。",
|
|
861
|
-
`3. 基于真实项目文件补全根 \`README.md\`、\`${input.governanceRoot}/verification-matrix.md\`,必要时适配 \`scripts/ci-tests.sh\`。`,
|
|
862
|
-
"4. 复查 `init doctor` / `inspect` / `docs audit` 与 quick verification。",
|
|
863
|
-
"",
|
|
864
|
-
"信息不足时写明尚未识别到的事实;不要留下泛化占位符。",
|
|
865
|
-
"",
|
|
866
|
-
"### 文档收敛",
|
|
867
|
-
"",
|
|
868
|
-
"完成实现和验证后,必须检查 `README.md`、`AGENTS.md`、`CHANGELOG.md`(如果目标项目维护)、治理文档、skills references、初始化模板和脚本说明是否仍与实际行为一致。只更新与本次变更相关的内容;如果决定不更新,应在交接里写明理由。",
|
|
869
|
-
"",
|
|
870
|
-
"### 开始顺序",
|
|
871
|
-
"",
|
|
872
|
-
`pwd → \`README.md\` → \`harness.json\` → \`${input.governanceRoot}/README.md\` → 实现类再读 principles/feature-workflow/verification-matrix;测试纪律读 harness-methodology-*;\`git status\`;最小基线验证。`,
|
|
873
|
-
"",
|
|
874
|
-
"### Agent DAG 路径",
|
|
875
|
-
"",
|
|
876
|
-
"```bash",
|
|
877
|
-
'loop-agent new-task <task-id> "任务标题"',
|
|
878
|
-
"# write .harness/tasks/<task-id>/source/需求.md",
|
|
879
|
-
"# write .harness/tasks/<task-id>/source/执行约束.md",
|
|
880
|
-
"loop-agent dag run-task <task-id> --profile auto --strict-models",
|
|
881
|
-
"loop-agent dag validate --dag .harness/tasks/<task-id>/dag.json --strict-models --strict-governance",
|
|
882
|
-
"loop-agent run-dag --dag .harness/tasks/<task-id>/dag.json --cwd .",
|
|
883
|
-
"```",
|
|
884
|
-
"",
|
|
885
|
-
"`source/需求.md` 与 `source/执行约束.md` 必需;写入前同步 `task.json.allowedPaths` / `task.json.forbiddenPaths` 并审查 writer `writeSet`。",
|
|
886
|
-
"",
|
|
887
|
-
"凡是影响项目公共契约、执行入口、交付流水线、自动化/治理、数据模型、安全或权限模型、跨模块行为、用户可见工作流的改动,都必须在编辑实现文件前先创建任务、写好两个 source 文件、生成 DAG,并审查 DAG/writeSet。",
|
|
888
|
-
"",
|
|
889
|
-
"### 任务类型路由(taskKind)",
|
|
890
|
-
"",
|
|
891
|
-
'- 用户明确提出后端测试、接口/API 测试、pytest,或语境明确为后端的自动化测试时,必须把 `.harness/tasks/<task-id>/task.json` 的 `taskKind` 设置为 `"backend-test"`,不得保留默认 `standard`。',
|
|
892
|
-
"- `backend-test` 是 `taskKind`,不是 `--profile` 的可选值;运行 `dag run-task` 时继续使用 `--profile auto`。",
|
|
893
|
-
"- 仅出现“自动化测试”且无法判断前后端时,先阅读任务源与目标项目技术栈再决定,禁止无条件路由到 `backend-test`。",
|
|
894
|
-
'- 用户提示词明确是前端实现需求(例如前端页面、UI、组件或交互开发)时,必须把 `.harness/tasks/<task-id>/task.json` 的 `taskKind` 设置为 `"frontend-implementation"`,不得保留默认 `standard`。',
|
|
895
|
-
"- `frontend-implementation` 是 `taskKind`,不是 `--profile` 的可选值;运行 `dag run-task` 时继续使用 `--profile auto`,也可按需显式选择 `minimal` / `standard` / `reviewed` / `supervised`,不要把业务模板名当作 profile。",
|
|
896
|
-
'- 前端自动化测试(浏览器/UI 自动化、Playwright、E2E)继续使用 `taskKind: "frontend-test"`,不得设置为 `frontend-implementation`。',
|
|
897
|
-
"",
|
|
898
|
-
"### 运行看板(只读)",
|
|
899
|
-
"",
|
|
900
|
-
"```bash",
|
|
901
|
-
"agent-worker console # 默认 repo=当前目录,port=8790",
|
|
902
|
-
"agent-worker console serve --repo . --port 8790 # 兼容入口,等价于上面裸入口",
|
|
903
|
-
"```",
|
|
904
|
-
"",
|
|
905
|
-
"浏览器打开 `http://127.0.0.1:8790/`;检视面为 `http://127.0.0.1:8790/inspect/`。默认绑定本机 `127.0.0.1`;不要直接暴露到公开网络。端口被占用时不会自动更换,请用 `--port <port>` 显式指定。`agent-worker observe serve` 仅为兼容入口。",
|
|
906
|
-
"",
|
|
907
|
-
"### DAG 诊断与收口",
|
|
908
|
-
"",
|
|
909
|
-
"用 `loop-agent dag report --run-id <run-id> --markdown` 读 facts;失败/paused 用 `loop-agent dag doctor --run-id <run-id> --markdown`;生命周期对齐用 `loop-agent dag reconcile-run`。失败 run 用 `dag closeout-draft` 生成 failure handoff,不要写成成功 closeout。",
|
|
910
|
-
"",
|
|
911
|
-
"恢复:doctor/report → classify → reconcile/replan → CLI 重跑 → shell verify。**禁止**把主会话直接 Edit 业务代码当作恢复手段。",
|
|
912
|
-
"",
|
|
913
|
-
"### 运行态与验证",
|
|
914
|
-
"",
|
|
915
|
-
"- `.harness/tasks/`、`.harness/dag-runs/`、`.harness/runs/` 保存运行事实;已完成事实只读。",
|
|
916
|
-
"- `.agents/skills/` 为本地 skills;缺失时可回退 npm 包内置。",
|
|
917
|
-
`- 验证命令选择:\`${input.governanceRoot}/verification-matrix.md\`。常用:\`bash scripts/check-repo.sh\`、\`bash scripts/ci.sh\`、\`loop-agent inspect\`、\`loop-agent doctor\`、\`loop-agent docs audit\`。`,
|
|
918
|
-
"- `scripts/ci-tests.sh` 必须反映目标项目真实工具链。Windows 脚本用 Git Bash;仓库引用用 `/`。",
|
|
919
|
-
"",
|
|
920
|
-
"### 交接",
|
|
921
|
-
"",
|
|
922
|
-
`交接写清变更、原因、验证证据、影响面、风险与下一步;长期结论进入 \`${input.governanceRoot}/progress\`、reports、exec-plans、decisions。`,
|
|
923
|
-
MANAGED_BLOCK_END,
|
|
924
|
-
].join("\n");
|
|
806
|
+
async function loadManagedAgentsTemplate(assetRoot) {
|
|
807
|
+
if (managedAgentsTemplateCache !== undefined)
|
|
808
|
+
return managedAgentsTemplateCache;
|
|
809
|
+
const templatePath = path.join(assetRoot, MANAGED_AGENTS_TEMPLATE_PATH);
|
|
810
|
+
const raw = await readFile(templatePath, "utf-8");
|
|
811
|
+
// Prefer a START marker on its own line so header notes mentioning the token are ignored.
|
|
812
|
+
const lines = raw.split(/\r?\n/);
|
|
813
|
+
const startLine = lines.findIndex((line) => line.trim() === MANAGED_BLOCK_START);
|
|
814
|
+
const endLine = startLine >= 0
|
|
815
|
+
? lines.findIndex((line, index) => index > startLine && line.trim() === MANAGED_BLOCK_END)
|
|
816
|
+
: -1;
|
|
817
|
+
if (startLine < 0 || endLine < 0) {
|
|
818
|
+
throw new Error(`managed agents template missing LOOP_AGENT_INIT markers: ${MANAGED_AGENTS_TEMPLATE_PATH}`);
|
|
819
|
+
}
|
|
820
|
+
managedAgentsTemplateCache = lines.slice(startLine, endLine + 1).join("\n");
|
|
821
|
+
return managedAgentsTemplateCache;
|
|
822
|
+
}
|
|
823
|
+
async function buildManagedAgentsBlock(input) {
|
|
824
|
+
const template = await loadManagedAgentsTemplate(input.assetRoot);
|
|
825
|
+
return template
|
|
826
|
+
.replaceAll(PROJECT_NAME_TOKEN, input.projectName)
|
|
827
|
+
.replaceAll(GOVERNANCE_ROOT_TOKEN, input.governanceRoot);
|
|
925
828
|
}
|
|
926
829
|
function mergeManagedBlock(existing, block) {
|
|
927
830
|
const start = existing.indexOf(MANAGED_BLOCK_START);
|
|
@@ -1137,11 +1040,39 @@ async function copyFileIfMissing(input) {
|
|
|
1137
1040
|
async function copyDirMerge(input) {
|
|
1138
1041
|
const source = path.join(input.assetRoot, input.sourceRelativePath);
|
|
1139
1042
|
const target = path.join(input.repoRoot, input.targetRelativePath);
|
|
1140
|
-
|
|
1043
|
+
const sourcePrefix = `${input.sourceRelativePath.replaceAll(path.sep, "/").replace(/\/$/, "")}/`;
|
|
1044
|
+
await copyDirSkippingPackageOnly({
|
|
1045
|
+
source,
|
|
1046
|
+
target,
|
|
1047
|
+
packageRelativePrefix: sourcePrefix,
|
|
1048
|
+
});
|
|
1141
1049
|
input.written.push(input.targetRelativePath.endsWith("/")
|
|
1142
1050
|
? input.targetRelativePath
|
|
1143
1051
|
: `${input.targetRelativePath}/`);
|
|
1144
1052
|
}
|
|
1053
|
+
/** Like copyDir, but skips package-only assets that must not land in target projects. */
|
|
1054
|
+
async function copyDirSkippingPackageOnly(input) {
|
|
1055
|
+
await mkdir(input.target, { recursive: true });
|
|
1056
|
+
const entries = await readdir(input.source, { withFileTypes: true });
|
|
1057
|
+
for (const entry of entries) {
|
|
1058
|
+
const srcPath = path.join(input.source, entry.name);
|
|
1059
|
+
const destPath = path.join(input.target, entry.name);
|
|
1060
|
+
const packageRelative = `${input.packageRelativePrefix}${entry.name}`;
|
|
1061
|
+
if (entry.isDirectory()) {
|
|
1062
|
+
await copyDirSkippingPackageOnly({
|
|
1063
|
+
source: srcPath,
|
|
1064
|
+
target: destPath,
|
|
1065
|
+
packageRelativePrefix: `${packageRelative}/`,
|
|
1066
|
+
});
|
|
1067
|
+
continue;
|
|
1068
|
+
}
|
|
1069
|
+
if (PACKAGE_ONLY_SURFACE_FILES.has(packageRelative))
|
|
1070
|
+
continue;
|
|
1071
|
+
if (entry.isFile() || entry.isSymbolicLink()) {
|
|
1072
|
+
await copyFile(srcPath, destPath);
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1075
|
+
}
|
|
1145
1076
|
async function ensureHarnessDirs(repoRoot, written) {
|
|
1146
1077
|
const dirs = [
|
|
1147
1078
|
".harness/prompts",
|
|
@@ -1289,7 +1220,10 @@ async function discoverCopiedSurfaceFiles(assetRoot) {
|
|
|
1289
1220
|
continue;
|
|
1290
1221
|
const files = await listRelativeFiles(rootPath);
|
|
1291
1222
|
for (const relativePath of files) {
|
|
1292
|
-
|
|
1223
|
+
const manifestPath = `${prefix}${relativePath}`;
|
|
1224
|
+
if (PACKAGE_ONLY_SURFACE_FILES.has(manifestPath))
|
|
1225
|
+
continue;
|
|
1226
|
+
discovered.push(manifestPath);
|
|
1293
1227
|
}
|
|
1294
1228
|
}
|
|
1295
1229
|
return discovered.sort();
|
|
@@ -1335,7 +1269,8 @@ async function buildDesiredSurfaceContent(input) {
|
|
|
1335
1269
|
}
|
|
1336
1270
|
if (manifestPath === "AGENTS.md") {
|
|
1337
1271
|
return {
|
|
1338
|
-
content: buildManagedAgentsBlock({
|
|
1272
|
+
content: await buildManagedAgentsBlock({
|
|
1273
|
+
assetRoot: input.assetRoot,
|
|
1339
1274
|
projectName: input.projectName,
|
|
1340
1275
|
governanceRoot: input.governanceRoot,
|
|
1341
1276
|
}),
|
|
@@ -2427,7 +2362,11 @@ export async function initializeLoopAgentProject(options) {
|
|
|
2427
2362
|
await writeText({
|
|
2428
2363
|
repoRoot,
|
|
2429
2364
|
relativePath: "AGENTS.md",
|
|
2430
|
-
content: mergeManagedBlock(existingAgents, buildManagedAgentsBlock({
|
|
2365
|
+
content: mergeManagedBlock(existingAgents, await buildManagedAgentsBlock({
|
|
2366
|
+
assetRoot,
|
|
2367
|
+
projectName,
|
|
2368
|
+
governanceRoot,
|
|
2369
|
+
})),
|
|
2431
2370
|
merge: true,
|
|
2432
2371
|
written,
|
|
2433
2372
|
skipped,
|
|
@@ -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) {
|
|
@@ -169,14 +169,25 @@ export function buildDagPiUserMessage(task, persona, step) {
|
|
|
169
169
|
"Do not wrap the output in code fences and do not add conversational preamble.",
|
|
170
170
|
].join(" ");
|
|
171
171
|
}
|
|
172
|
-
function resolveDagPiModelConfig(
|
|
173
|
-
const
|
|
172
|
+
export function resolveDagPiModelConfig(modelReference, options) {
|
|
173
|
+
const separatorIndex = modelReference.indexOf("/");
|
|
174
|
+
const qualified = separatorIndex >= 0;
|
|
175
|
+
const provider = qualified
|
|
176
|
+
? modelReference.slice(0, separatorIndex)
|
|
177
|
+
: (DAG_PI_MODEL_PROVIDERS[modelReference] ?? DEFAULT_DAG_PI_PROVIDER);
|
|
178
|
+
const model = qualified
|
|
179
|
+
? modelReference.slice(separatorIndex + 1)
|
|
180
|
+
: modelReference;
|
|
181
|
+
if (!provider || !model) {
|
|
182
|
+
throw new Error(`invalid DAG Pi model reference "${modelReference}": expected non-empty provider/model`);
|
|
183
|
+
}
|
|
184
|
+
const explicitThinking = options?.thinking?.trim();
|
|
185
|
+
const thinking = explicitThinking ??
|
|
186
|
+
(provider === "wizard-local" && model === "gpt-5.5" ? "low" : undefined);
|
|
174
187
|
return {
|
|
175
188
|
provider,
|
|
176
189
|
model,
|
|
177
|
-
...(
|
|
178
|
-
? { thinking: "low" }
|
|
179
|
-
: {}),
|
|
190
|
+
...(thinking ? { thinking } : {}),
|
|
180
191
|
};
|
|
181
192
|
}
|
|
182
193
|
const SUMMARY_STDOUT_MAX = 4_000;
|
|
@@ -291,7 +302,7 @@ export async function executeDagPiNode(input, meta, piStepFn = executePiStep) {
|
|
|
291
302
|
: undefined;
|
|
292
303
|
const result = await piStepFn({
|
|
293
304
|
attachedFiles: [],
|
|
294
|
-
modelConfig: resolveDagPiModelConfig(input.model),
|
|
305
|
+
modelConfig: resolveDagPiModelConfig(input.model, input.thinking ? { thinking: input.thinking } : undefined),
|
|
295
306
|
prompt: input.prompt,
|
|
296
307
|
repoRoot: input.cwd,
|
|
297
308
|
step,
|
|
@@ -304,8 +315,8 @@ export async function executeDagPiNode(input, meta, piStepFn = executePiStep) {
|
|
|
304
315
|
abortGraceMs: input.abortGraceMs,
|
|
305
316
|
onActivity: bridgeActivity
|
|
306
317
|
? (activity) => {
|
|
307
|
-
if (activity.kind === "lease"
|
|
308
|
-
|
|
318
|
+
if (activity.kind === "lease" ||
|
|
319
|
+
activity.kind === "synthetic-heartbeat") {
|
|
309
320
|
return;
|
|
310
321
|
}
|
|
311
322
|
bridgeActivity(activity.kind, activity.at);
|
|
@@ -372,7 +383,9 @@ export async function executeDagPiNode(input, meta, piStepFn = executePiStep) {
|
|
|
372
383
|
}
|
|
373
384
|
}
|
|
374
385
|
}
|
|
375
|
-
if (writeGuardOk &&
|
|
386
|
+
if (writeGuardOk &&
|
|
387
|
+
beforeStatus !== undefined &&
|
|
388
|
+
changeManifestChangedFiles !== undefined) {
|
|
376
389
|
await persistWriterChangeManifest({
|
|
377
390
|
runDir: meta.runDir,
|
|
378
391
|
nodeId: input.task.id,
|
|
@@ -445,12 +458,8 @@ function parseWriterImplementationOutcome(text) {
|
|
|
445
458
|
const normalized = normalizeProtocolLine(line, WRITER_OUTCOME_PROTOCOL_LINE, nextLine);
|
|
446
459
|
if (normalized === undefined)
|
|
447
460
|
continue;
|
|
448
|
-
const value = normalized
|
|
449
|
-
|
|
450
|
-
.trim();
|
|
451
|
-
const outcome = isWriterImplementationOutcome(value)
|
|
452
|
-
? value
|
|
453
|
-
: undefined;
|
|
461
|
+
const value = normalized.slice(WRITER_OUTCOME_PROTOCOL_LINE.length).trim();
|
|
462
|
+
const outcome = isWriterImplementationOutcome(value) ? value : undefined;
|
|
454
463
|
candidates.push({
|
|
455
464
|
lineIndex,
|
|
456
465
|
value,
|
|
@@ -474,9 +483,7 @@ function parseWriterImplementationOutcome(text) {
|
|
|
474
483
|
};
|
|
475
484
|
}
|
|
476
485
|
function isWriterImplementationOutcome(value) {
|
|
477
|
-
return (value === "changed" ||
|
|
478
|
-
value === "already-satisfied" ||
|
|
479
|
-
value === "blocked");
|
|
486
|
+
return (value === "changed" || value === "already-satisfied" || value === "blocked");
|
|
480
487
|
}
|
|
481
488
|
function writerOutcomeDiagnostics(text, parsed, changedFiles) {
|
|
482
489
|
const firstNonEmpty = text
|
|
@@ -543,8 +550,7 @@ function canonicalizeProtocolFirstLine(assistantText, firstProtocolLine) {
|
|
|
543
550
|
if (protocolNextLineIndex === protocolIndex + 1) {
|
|
544
551
|
after.shift();
|
|
545
552
|
}
|
|
546
|
-
while (before.at(-1)?.trim() === "" &&
|
|
547
|
-
after.at(0)?.trim() === "") {
|
|
553
|
+
while (before.at(-1)?.trim() === "" && after.at(0)?.trim() === "") {
|
|
548
554
|
after.shift();
|
|
549
555
|
}
|
|
550
556
|
const bodyLines = [...before, ...after];
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { DEFAULT_DAG_EXECUTOR_MODELS, } from
|
|
1
|
+
import { DEFAULT_DAG_EXECUTOR_MODELS, } from "../workflows/dag/types.js";
|
|
2
|
+
import { normalizeExecutorTierValue, } from "../governance/manifest-types.js";
|
|
2
3
|
export const DEFAULT_DAG_MODELS = {
|
|
3
4
|
HIGH: "gpt-5.5",
|
|
4
5
|
MED: "gpt-5.5",
|
|
@@ -8,6 +9,16 @@ export const DEFAULT_DAG_MODELS = {
|
|
|
8
9
|
* DAG executor model tier keys that may carry a per-complexity override.
|
|
9
10
|
*/
|
|
10
11
|
const EXECUTOR_MODEL_TIERS = ["LOW", "MED", "HIGH"];
|
|
12
|
+
/** Resolve one tier to a model and optional explicit thinking override. */
|
|
13
|
+
export function resolveExecutorTierSelection(execConfig, tier) {
|
|
14
|
+
const tierSelection = normalizeExecutorTierValue(execConfig?.[tier]);
|
|
15
|
+
if (tierSelection)
|
|
16
|
+
return tierSelection;
|
|
17
|
+
const defaultModel = execConfig?.defaultModel;
|
|
18
|
+
if (defaultModel && defaultModel !== "default")
|
|
19
|
+
return { model: defaultModel };
|
|
20
|
+
return { model: DEFAULT_DAG_EXECUTOR_MODELS.pi[tier] };
|
|
21
|
+
}
|
|
11
22
|
/**
|
|
12
23
|
* Resolve the DAG executor model matrix for Pi from harness `executors.pi`.
|
|
13
24
|
*
|
|
@@ -19,22 +30,23 @@ const EXECUTOR_MODEL_TIERS = ["LOW", "MED", "HIGH"];
|
|
|
19
30
|
* The "default" literal (injected by the schema `.default("default")`) and
|
|
20
31
|
* absent/undefined both mean "no override, fall through".
|
|
21
32
|
*/
|
|
22
|
-
export function resolveExecutorModelMatrix(
|
|
23
|
-
const tierValue = (tier) => {
|
|
24
|
-
const tierOverride = execConfig?.[tier];
|
|
25
|
-
if (tierOverride && tierOverride !== "default")
|
|
26
|
-
return tierOverride;
|
|
27
|
-
const defaultModel = execConfig?.defaultModel;
|
|
28
|
-
if (defaultModel && defaultModel !== "default")
|
|
29
|
-
return defaultModel;
|
|
30
|
-
return DEFAULT_DAG_EXECUTOR_MODELS[executor][tier];
|
|
31
|
-
};
|
|
33
|
+
export function resolveExecutorModelMatrix(_executor, execConfig) {
|
|
32
34
|
return {
|
|
33
|
-
LOW:
|
|
34
|
-
MED:
|
|
35
|
-
HIGH:
|
|
35
|
+
LOW: resolveExecutorTierSelection(execConfig, "LOW").model,
|
|
36
|
+
MED: resolveExecutorTierSelection(execConfig, "MED").model,
|
|
37
|
+
HIGH: resolveExecutorTierSelection(execConfig, "HIGH").model,
|
|
36
38
|
};
|
|
37
39
|
}
|
|
40
|
+
/** Resolve only explicitly configured per-tier thinking values. */
|
|
41
|
+
export function resolveExecutorThinkingMatrix(execConfig) {
|
|
42
|
+
const result = {};
|
|
43
|
+
for (const tier of EXECUTOR_MODEL_TIERS) {
|
|
44
|
+
const selection = normalizeExecutorTierValue(execConfig?.[tier]);
|
|
45
|
+
if (selection?.thinking)
|
|
46
|
+
result[tier] = selection.thinking;
|
|
47
|
+
}
|
|
48
|
+
return result;
|
|
49
|
+
}
|
|
38
50
|
/**
|
|
39
51
|
* Resolve the Pi DAG executor model matrix from a harness manifest.
|
|
40
52
|
*/
|
|
@@ -55,7 +67,9 @@ export function resolveModelSelection(manifest, taskConfig, step, options) {
|
|
|
55
67
|
};
|
|
56
68
|
}
|
|
57
69
|
const profileName = resolveProfileName(manifest, taskConfig.complexity, step, retryAttempt);
|
|
58
|
-
const profile = profileName
|
|
70
|
+
const profile = profileName
|
|
71
|
+
? manifest.modelProfiles?.[profileName]
|
|
72
|
+
: undefined;
|
|
59
73
|
if (!profile) {
|
|
60
74
|
return {
|
|
61
75
|
modelConfig: manifest.models?.[step],
|
|
@@ -74,7 +88,9 @@ export function resolveModelSelection(manifest, taskConfig, step, options) {
|
|
|
74
88
|
};
|
|
75
89
|
}
|
|
76
90
|
function resolveProfileName(manifest, complexity, step, retryAttempt) {
|
|
77
|
-
if (step ===
|
|
91
|
+
if (step === "implement" &&
|
|
92
|
+
retryAttempt > 0 &&
|
|
93
|
+
manifest.modelRouting?.implementRetry) {
|
|
78
94
|
return manifest.modelRouting.implementRetry;
|
|
79
95
|
}
|
|
80
96
|
const route = manifest.modelRouting?.[step];
|
|
@@ -85,11 +101,11 @@ function resolveProfileName(manifest, complexity, step, retryAttempt) {
|
|
|
85
101
|
}
|
|
86
102
|
export function formatModelSelectionLabel(modelConfig, profileName) {
|
|
87
103
|
if (!modelConfig) {
|
|
88
|
-
return profileName ? `${profileName}` :
|
|
104
|
+
return profileName ? `${profileName}` : "default";
|
|
89
105
|
}
|
|
90
106
|
const base = modelConfig.provider && modelConfig.model
|
|
91
107
|
? `${modelConfig.provider}/${modelConfig.model}`
|
|
92
|
-
: modelConfig.model ??
|
|
108
|
+
: (modelConfig.model ?? "default");
|
|
93
109
|
return profileName ? `${profileName}:${base}` : base;
|
|
94
110
|
}
|
|
95
111
|
export function formatFallbackLabel(profile) {
|
|
@@ -539,7 +539,7 @@ async function executeBackendTestPipeline(input, meta) {
|
|
|
539
539
|
});
|
|
540
540
|
const manifestPath = path.join(meta.runDir, "contracts", "backend-test-case-manifest.json");
|
|
541
541
|
const summary = manifest.coverageSummary;
|
|
542
|
-
outputs.push(`manifest=${manifestPath}`, `materializationStatus=${manifest.materializationStatus ?? "available"}`, `coverageSummary.explicitAcCount=${summary?.explicitAcCount ?? "unavailable"}`, `coverageSummary.coveredAcCount=${summary?.coveredAcCount ?? "unavailable"}`, `coverageSummary.caseCount=${summary?.caseCount ?? "unavailable"}`, `coverageSummary.generatedCount=${summary?.generatedCount ?? "unavailable"}`, `ruleCoverageSummary.ruleCount=${manifest.ruleCoverageSummary?.ruleCount ?? "unavailable"}`, `correspondenceSummary.exactCorrespondenceCount=${manifest.correspondenceSummary?.exactCorrespondenceCount ?? "unavailable"}`);
|
|
542
|
+
outputs.push(`manifest=${manifestPath}`, `materializationStatus=${manifest.materializationStatus ?? "available"}`, `coverageSummary.explicitAcCount=${summary?.explicitAcCount ?? "unavailable"}`, `coverageSummary.coveredAcCount=${summary?.coveredAcCount ?? "unavailable"}`, `coverageSummary.caseCount=${summary?.caseCount ?? "unavailable"}`, `coverageSummary.generatedCount=${summary?.generatedCount ?? "unavailable"}`, `ruleCoverageSummary.ruleCount=${manifest.ruleCoverageSummary?.ruleCount ?? "unavailable"}`, `correspondenceSummary.exactCorrespondenceCount=${manifest.correspondenceSummary?.exactCorrespondenceCount ?? "unavailable"}`, `correspondenceSummary.primarySymbolCount=${manifest.correspondenceSummary?.primarySymbolCount ?? "unavailable"}`, `correspondenceSummary.testPoints=${manifest.correspondenceSummary?.mappedTestPointCount ?? "unavailable"}/${manifest.correspondenceSummary?.testPointCount ?? "unavailable"}`, `correspondenceSummary.variantTestPointCount=${manifest.correspondenceSummary?.variantTestPointCount ?? "unavailable"}`, `correspondenceSummary.assertionTestPointCount=${manifest.correspondenceSummary?.assertionTestPointCount ?? "unavailable"}`, `correspondenceSummary.crossCuttingTestPointCount=${manifest.correspondenceSummary?.crossCuttingTestPointCount ?? "unavailable"}`, `correspondenceSummary.unclassifiedTestPointCount=${manifest.correspondenceSummary?.unclassifiedTestPointCount ?? "unavailable"}`, `correspondenceSummary.duplicateBindingTestPointCount=${manifest.correspondenceSummary?.duplicateBindingTestPointCount ?? "unavailable"}`);
|
|
543
543
|
}
|
|
544
544
|
else if (pipeline === "markdown-execute-html") {
|
|
545
545
|
const mappedScripts = await collectBackendTestMappedPytestScripts(input.cwd);
|