@dailephd/my-dev-kit-lab 0.8.2 → 0.9.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 +10 -0
- package/README.md +18 -3
- package/benchmarks/contracts/agent-success-rate-project-profiles.json +33 -0
- package/benchmarks/contracts/agent-success-rate-tasks.json +671 -0
- package/benchmarks/projects/agent-success-inventory-node/.gitattributes +2 -0
- package/benchmarks/projects/agent-success-inventory-node/README.md +74 -0
- package/benchmarks/projects/agent-success-inventory-node/package.json +14 -0
- package/benchmarks/projects/agent-success-inventory-node/src/fulfillmentReport.js +38 -0
- package/benchmarks/projects/agent-success-inventory-node/src/index.js +26 -0
- package/benchmarks/projects/agent-success-inventory-node/src/inventoryStore.js +114 -0
- package/benchmarks/projects/agent-success-inventory-node/src/quantity.js +19 -0
- package/benchmarks/projects/agent-success-inventory-node/src/reservationService.js +45 -0
- package/benchmarks/projects/agent-success-inventory-node/tests/quantity-edge.check.mjs +51 -0
- package/benchmarks/projects/agent-success-inventory-node/tests/quantity-primary.check.mjs +46 -0
- package/benchmarks/projects/agent-success-inventory-node/tests/regression.check.mjs +115 -0
- package/benchmarks/projects/agent-success-inventory-node/tests/report-edge.check.mjs +109 -0
- package/benchmarks/projects/agent-success-inventory-node/tests/report-primary.check.mjs +47 -0
- package/benchmarks/projects/agent-success-inventory-node/tests/reservation-edge.check.mjs +63 -0
- package/benchmarks/projects/agent-success-inventory-node/tests/reservation-primary.check.mjs +44 -0
- package/benchmarks/projects/agent-success-task-board-node/.gitattributes +2 -0
- package/benchmarks/projects/agent-success-task-board-node/README.md +77 -0
- package/benchmarks/projects/agent-success-task-board-node/package.json +14 -0
- package/benchmarks/projects/agent-success-task-board-node/src/index.js +24 -0
- package/benchmarks/projects/agent-success-task-board-node/src/projectSummary.js +15 -0
- package/benchmarks/projects/agent-success-task-board-node/src/taskService.js +58 -0
- package/benchmarks/projects/agent-success-task-board-node/src/taskStore.js +58 -0
- package/benchmarks/projects/agent-success-task-board-node/src/validation.js +31 -0
- package/benchmarks/projects/agent-success-task-board-node/tests/import-edge.check.mjs +65 -0
- package/benchmarks/projects/agent-success-task-board-node/tests/import-primary.check.mjs +31 -0
- package/benchmarks/projects/agent-success-task-board-node/tests/regression.check.mjs +107 -0
- package/benchmarks/projects/agent-success-task-board-node/tests/summary-edge.check.mjs +67 -0
- package/benchmarks/projects/agent-success-task-board-node/tests/summary-primary.check.mjs +54 -0
- package/benchmarks/projects/agent-success-task-board-node/tests/title-edge.check.mjs +39 -0
- package/benchmarks/projects/agent-success-task-board-node/tests/title-primary.check.mjs +29 -0
- package/dist/src/cli/help.js +38 -1
- package/dist/src/commands/runExperimentDescribeCommand.js +52 -1
- package/dist/src/commands/runExperimentRunCommand.js +118 -2
- package/dist/src/core/processTree.js +55 -0
- package/dist/src/core/runMeasuredCommand.js +104 -22
- package/dist/src/evaluation/agentSuccess/applyPatchToSandbox.js +37 -0
- package/dist/src/evaluation/agentSuccess/assessBaseline.js +23 -0
- package/dist/src/evaluation/agentSuccess/corpusTypes.js +74 -0
- package/dist/src/evaluation/agentSuccess/extractPatchCandidate.js +46 -0
- package/dist/src/evaluation/agentSuccess/index.js +14 -0
- package/dist/src/evaluation/agentSuccess/parseUnifiedDiff.js +210 -0
- package/dist/src/evaluation/agentSuccess/patchTypes.js +5 -0
- package/dist/src/evaluation/agentSuccess/readAgentSuccessCorpus.js +183 -0
- package/dist/src/evaluation/agentSuccess/runVerificationCheck.js +100 -0
- package/dist/src/evaluation/agentSuccess/taskPaths.js +34 -0
- package/dist/src/evaluation/agentSuccess/taskTypes.js +14 -0
- package/dist/src/evaluation/agentSuccess/validateAgentSuccessCorpus.js +307 -0
- package/dist/src/evaluation/agentSuccess/validateAgentSuccessTask.js +297 -0
- package/dist/src/evaluation/agentSuccess/validatePatchPolicy.js +66 -0
- package/dist/src/evaluation/agentSuccess/verificationTypes.js +1 -0
- package/dist/src/evaluation/benchmarkSandbox/createBenchmarkSandbox.js +127 -0
- package/dist/src/evaluation/benchmarkSandbox/errors.js +11 -0
- package/dist/src/evaluation/benchmarkSandbox/gitExecutor.js +60 -0
- package/dist/src/evaluation/benchmarkSandbox/index.js +8 -0
- package/dist/src/evaluation/benchmarkSandbox/minimalHostEnv.js +37 -0
- package/dist/src/evaluation/benchmarkSandbox/pathPolicy.js +49 -0
- package/dist/src/evaluation/benchmarkSandbox/removeBenchmarkSandbox.js +74 -0
- package/dist/src/evaluation/benchmarkSandbox/treeSnapshot.js +57 -0
- package/dist/src/evaluation/benchmarkSandbox/types.js +3 -0
- package/dist/src/evaluation/changeSet/captureChangeSet.js +98 -0
- package/dist/src/evaluation/changeSet/index.js +2 -0
- package/dist/src/evaluation/changeSet/types.js +9 -0
- package/dist/src/experiments/defaultRegistry.js +2 -0
- package/dist/src/experiments/plugins/agentSuccessRate/agentTaskProjection.js +12 -0
- package/dist/src/experiments/plugins/agentSuccessRate/analysis.js +425 -0
- package/dist/src/experiments/plugins/agentSuccessRate/analysisArtifact.js +155 -0
- package/dist/src/experiments/plugins/agentSuccessRate/analysisTypes.js +65 -0
- package/dist/src/experiments/plugins/agentSuccessRate/attemptEvidence.js +7 -0
- package/dist/src/experiments/plugins/agentSuccessRate/config.js +123 -0
- package/dist/src/experiments/plugins/agentSuccessRate/contextGeneration.js +497 -0
- package/dist/src/experiments/plugins/agentSuccessRate/execution.js +441 -0
- package/dist/src/experiments/plugins/agentSuccessRate/executionArtifact.js +126 -0
- package/dist/src/experiments/plugins/agentSuccessRate/executionTypes.js +2 -0
- package/dist/src/experiments/plugins/agentSuccessRate/index.js +20 -0
- package/dist/src/experiments/plugins/agentSuccessRate/metadata.js +28 -0
- package/dist/src/experiments/plugins/agentSuccessRate/metrics.js +76 -0
- package/dist/src/experiments/plugins/agentSuccessRate/plugin.js +507 -0
- package/dist/src/experiments/plugins/agentSuccessRate/realAgentExecution.js +250 -0
- package/dist/src/experiments/plugins/agentSuccessRate/realAgentPrompt.js +43 -0
- package/dist/src/experiments/plugins/agentSuccessRate/repairAnalysis.js +148 -0
- package/dist/src/experiments/plugins/agentSuccessRate/repairExecution.js +103 -0
- package/dist/src/experiments/plugins/agentSuccessRate/repairFeedback.js +91 -0
- package/dist/src/experiments/plugins/agentSuccessRate/repairPolicy.js +88 -0
- package/dist/src/experiments/plugins/agentSuccessRate/types.js +1 -0
- package/dist/src/experiments/plugins/warmIndexReuse/plugin.js +2 -3
- package/dist/src/report/experiments/agentSuccessRateReportModel.js +6 -0
- package/dist/src/report/experiments/buildAgentSuccessRateReport.js +255 -0
- package/dist/src/report/experiments/buildPluginExperimentReport.js +27 -2
- package/dist/src/report/experiments/index.js +4 -0
- package/dist/src/report/experiments/renderAgentSuccessRateHtml.js +169 -0
- package/dist/src/report/experiments/renderAgentSuccessRateText.js +139 -0
- package/dist/src/report/experiments/renderPluginExperimentReportHtml.js +3 -0
- package/dist/src/report/experiments/renderPluginExperimentReportText.js +5 -0
- package/docs/METRICS.md +70 -0
- package/package.json +1 -1
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import test from "node:test";
|
|
3
|
+
import { INVALID_PROJECT, createTaskBoard } from "../src/index.js";
|
|
4
|
+
|
|
5
|
+
test("a project's completed count never exceeds its total", () => {
|
|
6
|
+
const { service, summarize } = createTaskBoard();
|
|
7
|
+
service.createTask({ title: "Solo", projectId: "alpha" });
|
|
8
|
+
for (const title of ["x", "y", "z"]) {
|
|
9
|
+
const task = service.createTask({ title, projectId: "beta" });
|
|
10
|
+
service.completeTask(task.id);
|
|
11
|
+
}
|
|
12
|
+
const summary = summarize("alpha");
|
|
13
|
+
assert.equal(summary.total, 1);
|
|
14
|
+
assert.equal(summary.completed, 0);
|
|
15
|
+
assert.ok(summary.completed <= summary.total);
|
|
16
|
+
assert.equal(summary.open, 1);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
test("unrelated tasks in the store do not change a project's summary", () => {
|
|
20
|
+
const { service, summarize } = createTaskBoard();
|
|
21
|
+
const a = service.createTask({ title: "A", projectId: "core" });
|
|
22
|
+
service.createTask({ title: "B", projectId: "core" });
|
|
23
|
+
service.completeTask(a.id);
|
|
24
|
+
const before = summarize("core");
|
|
25
|
+
const noise = service.createTask({ title: "Noise", projectId: "core-extras" });
|
|
26
|
+
service.createTask({ title: "More noise", projectId: "CORE2" });
|
|
27
|
+
service.completeTask(noise.id);
|
|
28
|
+
service.importTasks([{ externalId: "n-1", title: "Imported noise", projectId: "c" }]);
|
|
29
|
+
assert.deepEqual(summarize("core"), before);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
test("an unknown project has an empty, consistent summary", () => {
|
|
33
|
+
const { service, summarize } = createTaskBoard();
|
|
34
|
+
service.createTask({ title: "A", projectId: "known" });
|
|
35
|
+
assert.deepEqual(summarize("missing"), { projectId: "missing", total: 0, completed: 0, open: 0, taskIds: [] });
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
test("blank project identities are rejected consistently", () => {
|
|
39
|
+
const { service, store, summarize } = createTaskBoard();
|
|
40
|
+
assert.throws(() => service.createTask({ title: "Task", projectId: " " }), { code: INVALID_PROJECT });
|
|
41
|
+
assert.throws(() => service.createTask({ title: "Task", projectId: "" }), { code: INVALID_PROJECT });
|
|
42
|
+
assert.throws(
|
|
43
|
+
() => service.importTasks([{ externalId: "ext-1", title: "Task", projectId: " " }]),
|
|
44
|
+
{ code: INVALID_PROJECT }
|
|
45
|
+
);
|
|
46
|
+
assert.throws(() => summarize(" "), { code: INVALID_PROJECT });
|
|
47
|
+
assert.equal(store.list().length, 0);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
test("summaries are deterministic and list ids in creation order", () => {
|
|
51
|
+
const build = () => {
|
|
52
|
+
const { service, summarize } = createTaskBoard();
|
|
53
|
+
service.createTask({ title: "1", projectId: "p" });
|
|
54
|
+
service.createTask({ title: "2", projectId: "q" });
|
|
55
|
+
service.createTask({ title: "3", projectId: "P" });
|
|
56
|
+
service.importTasks([{ externalId: "e-1", title: "4", projectId: "p " }]);
|
|
57
|
+
return summarize("p");
|
|
58
|
+
};
|
|
59
|
+
assert.deepEqual(build(), build());
|
|
60
|
+
assert.deepEqual(build().taskIds, ["task-1", "task-3", "task-4"]);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
test("the default project is used for tasks created without one", () => {
|
|
64
|
+
const { service, summarize } = createTaskBoard();
|
|
65
|
+
service.createTask({ title: "No project given" });
|
|
66
|
+
assert.equal(summarize("inbox").total, 1);
|
|
67
|
+
});
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import test from "node:test";
|
|
3
|
+
import { createTaskBoard } from "../src/index.js";
|
|
4
|
+
|
|
5
|
+
test("tasks created with differently written project names share one project identity", () => {
|
|
6
|
+
const { service, store, summarize } = createTaskBoard();
|
|
7
|
+
service.createTask({ title: "One", projectId: "web" });
|
|
8
|
+
service.createTask({ title: "Two", projectId: " WEB " });
|
|
9
|
+
service.createTask({ title: "Three", projectId: "Web" });
|
|
10
|
+
assert.deepEqual(
|
|
11
|
+
store.list().map((task) => task.projectId),
|
|
12
|
+
["web", "web", "web"]
|
|
13
|
+
);
|
|
14
|
+
const summary = summarize("web");
|
|
15
|
+
assert.equal(summary.projectId, "web");
|
|
16
|
+
assert.equal(summary.total, 3);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
test("a summary only counts tasks of the requested project", () => {
|
|
20
|
+
const { service, summarize } = createTaskBoard();
|
|
21
|
+
const web = service.createTask({ title: "Web task", projectId: "web" });
|
|
22
|
+
service.createTask({ title: "Web app task", projectId: "web-app" });
|
|
23
|
+
service.createTask({ title: "Webhook task", projectId: "webhooks" });
|
|
24
|
+
const other = service.createTask({ title: "Docs task", projectId: "docs" });
|
|
25
|
+
service.completeTask(other.id);
|
|
26
|
+
const summary = summarize("web");
|
|
27
|
+
assert.equal(summary.total, 1);
|
|
28
|
+
assert.equal(summary.completed, 0);
|
|
29
|
+
assert.equal(summary.open, 1);
|
|
30
|
+
assert.deepEqual(summary.taskIds, [web.id]);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
test("completed and open counts are correct for the requested project", () => {
|
|
34
|
+
const { service, summarize } = createTaskBoard();
|
|
35
|
+
const a = service.createTask({ title: "A", projectId: "ops" });
|
|
36
|
+
service.createTask({ title: "B", projectId: "ops" });
|
|
37
|
+
service.createTask({ title: "C", projectId: "ops" });
|
|
38
|
+
service.createTask({ title: "Elsewhere", projectId: "labs" });
|
|
39
|
+
service.completeTask(a.id);
|
|
40
|
+
assert.deepEqual(summarize(" OPS "), {
|
|
41
|
+
projectId: "ops",
|
|
42
|
+
total: 3,
|
|
43
|
+
completed: 1,
|
|
44
|
+
open: 2,
|
|
45
|
+
taskIds: ["task-1", "task-2", "task-3"]
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test("imported tasks join the same normalized project identity", () => {
|
|
50
|
+
const { service, summarize } = createTaskBoard();
|
|
51
|
+
service.createTask({ title: "Manual", projectId: "ops" });
|
|
52
|
+
service.importTasks([{ externalId: "ext-1", title: "Imported", projectId: " OPS" }]);
|
|
53
|
+
assert.equal(summarize("ops").total, 2);
|
|
54
|
+
});
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import test from "node:test";
|
|
3
|
+
import { INVALID_TITLE, ValidationError, createTaskBoard, validateTitle } from "../src/index.js";
|
|
4
|
+
|
|
5
|
+
test("rejected titles leave the store and id sequence untouched", () => {
|
|
6
|
+
const { service, store } = createTaskBoard();
|
|
7
|
+
assert.throws(() => service.createTask({ title: " \t " }), { code: INVALID_TITLE });
|
|
8
|
+
assert.throws(() => service.createTask({ title: "" }), { code: INVALID_TITLE });
|
|
9
|
+
assert.equal(store.list().length, 0);
|
|
10
|
+
const task = service.createTask({ title: "First" });
|
|
11
|
+
assert.equal(task.id, "task-1");
|
|
12
|
+
assert.equal(store.list().length, 1);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
test("interior whitespace is preserved while surrounding whitespace is removed", () => {
|
|
16
|
+
const { service } = createTaskBoard();
|
|
17
|
+
assert.equal(service.createTask({ title: " Fix the bug " }).title, "Fix the bug");
|
|
18
|
+
assert.equal(service.createTask({ title: "\n\tPlan sprint\t\n" }).title, "Plan sprint");
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
test("already-trimmed titles keep their meaning", () => {
|
|
22
|
+
const { service } = createTaskBoard();
|
|
23
|
+
assert.equal(service.createTask({ title: "Ship it" }).title, "Ship it");
|
|
24
|
+
assert.equal(service.createTask({ title: "a" }).title, "a");
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
test("validateTitle returns the normalized title and throws the documented error", () => {
|
|
28
|
+
assert.equal(validateTitle(" Triage "), "Triage");
|
|
29
|
+
assert.throws(
|
|
30
|
+
() => validateTitle(" "),
|
|
31
|
+
(error) => error instanceof ValidationError && error.code === INVALID_TITLE
|
|
32
|
+
);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
test("imported task titles are normalized the same way", () => {
|
|
36
|
+
const { service } = createTaskBoard();
|
|
37
|
+
const { imported } = service.importTasks([{ externalId: "ext-1", title: " Imported item " }]);
|
|
38
|
+
assert.equal(imported[0].title, "Imported item");
|
|
39
|
+
});
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import test from "node:test";
|
|
3
|
+
import { INVALID_TITLE, ValidationError, createTaskBoard } from "../src/index.js";
|
|
4
|
+
|
|
5
|
+
test("createTask trims surrounding whitespace from the title", () => {
|
|
6
|
+
const { service } = createTaskBoard();
|
|
7
|
+
const task = service.createTask({ title: " Write release notes " });
|
|
8
|
+
assert.equal(task.title, "Write release notes");
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
test("the stored task retains the normalized title", () => {
|
|
12
|
+
const { service, store } = createTaskBoard();
|
|
13
|
+
const task = service.createTask({ title: "\tReview backlog " });
|
|
14
|
+
assert.equal(store.get(task.id).title, "Review backlog");
|
|
15
|
+
assert.deepEqual(
|
|
16
|
+
store.list().map((entry) => entry.title),
|
|
17
|
+
["Review backlog"]
|
|
18
|
+
);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
test("a whitespace-only title is rejected with the invalid-title error", () => {
|
|
22
|
+
const { service } = createTaskBoard();
|
|
23
|
+
for (const title of [" ", "\t", "\n \r\n"]) {
|
|
24
|
+
assert.throws(
|
|
25
|
+
() => service.createTask({ title }),
|
|
26
|
+
(error) => error instanceof ValidationError && error.code === INVALID_TITLE
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
});
|
package/dist/src/cli/help.js
CHANGED
|
@@ -156,6 +156,10 @@ export function renderExperimentRunHelp() {
|
|
|
156
156
|
" --case <ids> Comma-separated case ids to run",
|
|
157
157
|
" --benchmark-project <ids> Comma-separated benchmark project ids to run",
|
|
158
158
|
"",
|
|
159
|
+
"Options are accepted per plugin: every plugin rejects the options it does not support instead of ignoring them. The",
|
|
160
|
+
"generic controlled-experiment options (such as --agents, --strategies, --complexities, --max-runs and the command",
|
|
161
|
+
"templates) belong to context-strategy-comparison and warm-index-reuse only.",
|
|
162
|
+
"",
|
|
159
163
|
"my-dev-kit command override (warm-index-reuse, incremental-change-staleness, context-window-scaling, retrieval-precision-recall, retrieval-query-strategy-comparison, and context-pack-generation):",
|
|
160
164
|
" --kit-command <command> my-dev-kit command used by the selected experiment plugin",
|
|
161
165
|
" (defaults: warm-index-reuse and context-window-scaling use",
|
|
@@ -273,7 +277,40 @@ export function renderExperimentRunHelp() {
|
|
|
273
277
|
" --command-template-codex <template> Command template used to invoke the codex agent",
|
|
274
278
|
" --command-template-claude <template> Command template used to invoke the claude agent",
|
|
275
279
|
" --no-screenshot Accepted for compatibility; the plugin-aware report",
|
|
276
|
-
" path does not capture screenshots yet"
|
|
280
|
+
" path does not capture screenshots yet",
|
|
281
|
+
"",
|
|
282
|
+
"agent-success-rate only:",
|
|
283
|
+
" Self-target only (the Lab itself); --target is rejected. Runs the",
|
|
284
|
+
" bundled six-task implementation corpus (two canonical benchmark",
|
|
285
|
+
" projects) with both source-context treatments, raw-full-file and",
|
|
286
|
+
" context-pack, for every selected task. The default is",
|
|
287
|
+
" deterministic-fixture mode, which validates the patch evaluation",
|
|
288
|
+
" pipeline, invokes no coding agent and needs no provider installed.",
|
|
289
|
+
" Accepted options: --out, --case, --benchmark-project,",
|
|
290
|
+
" --kit-command, --agent, --include-real-agents, --timeout-ms and",
|
|
291
|
+
" --repair-attempts; --case and --benchmark-project narrow the",
|
|
292
|
+
" catalog without reordering it.",
|
|
293
|
+
" --agent <codex|claude> Select exactly one real provider. Real-agent mode is entered only",
|
|
294
|
+
" when --agent is combined with --include-real-agents; neither flag",
|
|
295
|
+
" works alone. The provider receives source-only context and returns",
|
|
296
|
+
" a unified diff; it never edits files. The Lab applies the diff in a",
|
|
297
|
+
" disposable sandbox with a guarded patch policy and decides task",
|
|
298
|
+
" success from trusted checks on the changed state.",
|
|
299
|
+
" --include-real-agents Explicit authorization to invoke the selected provider. Without it",
|
|
300
|
+
" no provider is ever launched.",
|
|
301
|
+
" --timeout-ms <ms> Per provider attempt (real-agent mode only): a positive integer,",
|
|
302
|
+
" default 240000, maximum 1800000.",
|
|
303
|
+
" --repair-attempts <0|1|2> Repairs allowed after the initial attempt (real-agent mode only;",
|
|
304
|
+
" default 0). At most 3 attempts per treatment. A repair runs only",
|
|
305
|
+
" after an evaluable implementation failure, in a fresh sandbox,",
|
|
306
|
+
" with fixed-category feedback and the untrusted previous diff; it",
|
|
307
|
+
" never follows a provider, sandbox or verification infrastructure",
|
|
308
|
+
" problem.",
|
|
309
|
+
" Writes report.json, report.html and report.txt plus",
|
|
310
|
+
" agent-success-rate-execution.json and",
|
|
311
|
+
" agent-success-rate-analysis.json. Initial-attempt and final success",
|
|
312
|
+
" are reported separately. Results are descriptive for the finite",
|
|
313
|
+
" corpus: no winner, ranking, composite score or significance claim."
|
|
277
314
|
].join("\n");
|
|
278
315
|
}
|
|
279
316
|
export function renderExperimentControlledHelp() {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createDefaultExperimentPluginRegistry } from "../experiments/index.js";
|
|
2
|
+
import { AGENT_SUCCESS_RATE_DEFAULT_AGENT_TIMEOUT_MS, AGENT_SUCCESS_RATE_MAX_AGENT_TIMEOUT_MS, AGENT_SUCCESS_RATE_REAL_AGENT_IDS, AGENT_SUCCESS_RATE_REPAIR_ATTEMPT_VALUES, AGENT_SUCCESS_RATE_TREATMENT_IDS } from "../experiments/plugins/agentSuccessRate/index.js";
|
|
2
3
|
// ---------------------------------------------------------------------------
|
|
3
4
|
// v0.4.6 Batch 4 -- reusable experiment-describe command owner.
|
|
4
5
|
//
|
|
@@ -57,7 +58,27 @@ function buildDescription(plugin) {
|
|
|
57
58
|
optionalConfigFields: readConfigFields(plugin, false),
|
|
58
59
|
targetBehavior: describeTargetBehavior(plugin),
|
|
59
60
|
expectedReports: describeExpectedReports(plugin),
|
|
60
|
-
examples: describeExamples(plugin)
|
|
61
|
+
examples: describeExamples(plugin),
|
|
62
|
+
...(plugin.metadata.id === AGENT_SUCCESS_RATE_ID ? { agentSuccessRate: describeAgentSuccessRate() } : {})
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
const AGENT_SUCCESS_RATE_ID = "agent-success-rate";
|
|
66
|
+
/** Fixed, public description of the implemented behavior. It names no task check, fact, edit scope or reference patch. */
|
|
67
|
+
function describeAgentSuccessRate() {
|
|
68
|
+
return {
|
|
69
|
+
treatments: [...AGENT_SUCCESS_RATE_TREATMENT_IDS],
|
|
70
|
+
corpus: "Bundled six-task implementation corpus over two canonical benchmark projects (localized, cross-module and broad-change tasks), resolved from the installed package.",
|
|
71
|
+
defaultMode: "deterministic-fixture: validates the patch evaluation pipeline and the benchmark corpus; no coding agent runs and no provider is required.",
|
|
72
|
+
realAgentMode: "Opt-in only: --agent <codex|claude> together with --include-real-agents. Neither flag alone enables it; real execution is never the default.",
|
|
73
|
+
providers: [...AGENT_SUCCESS_RATE_REAL_AGENT_IDS],
|
|
74
|
+
timeoutMs: { default: AGENT_SUCCESS_RATE_DEFAULT_AGENT_TIMEOUT_MS, maximum: AGENT_SUCCESS_RATE_MAX_AGENT_TIMEOUT_MS, scope: "each provider attempt" },
|
|
75
|
+
repairAttempts: { allowed: [...AGENT_SUCCESS_RATE_REPAIR_ATTEMPT_VALUES], default: 0, maximumTotalAttemptsPerTreatment: 3, mode: "real-agent only" },
|
|
76
|
+
agentContext: "Source-only: the provider sees the public task text and the treatment's source context, never tests, trusted checks or reference patches, and runs in a neutral working directory.",
|
|
77
|
+
patchApplication: "Guarded: the provider returns a unified diff only. The Lab validates it against a patch policy and applies it in a fresh disposable sandbox; canonical benchmark projects are never modified.",
|
|
78
|
+
taskSuccess: "Decided by trusted checks on the actual changed repository state (required behavior, no regressions, protected files intact). A provider's claim of completion is never evidence. Initial-attempt success and final success are reported separately.",
|
|
79
|
+
reportOutputs: ["report.json", "report.html", "report.txt", "agent-success-rate-execution.json", "agent-success-rate-analysis.json"],
|
|
80
|
+
targetPolicy: "Self-target only; external-local targets are rejected.",
|
|
81
|
+
interpretation: "Descriptive matched comparison of two source-context treatments on a finite corpus: no winner, ranking, composite score, causal or statistical-significance claim."
|
|
61
82
|
};
|
|
62
83
|
}
|
|
63
84
|
function printDescription(plugin) {
|
|
@@ -84,6 +105,24 @@ function printDescription(plugin) {
|
|
|
84
105
|
for (const example of description.examples) {
|
|
85
106
|
console.log(` ${example}`);
|
|
86
107
|
}
|
|
108
|
+
const agentSuccessRate = description.agentSuccessRate; // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
109
|
+
if (agentSuccessRate) {
|
|
110
|
+
console.log("");
|
|
111
|
+
console.log("Agent success rate details:");
|
|
112
|
+
console.log(` Treatments: ${agentSuccessRate.treatments.join(", ")}`);
|
|
113
|
+
console.log(` Corpus: ${agentSuccessRate.corpus}`);
|
|
114
|
+
console.log(` Default mode: ${agentSuccessRate.defaultMode}`);
|
|
115
|
+
console.log(` Real-agent mode: ${agentSuccessRate.realAgentMode}`);
|
|
116
|
+
console.log(` Providers: ${agentSuccessRate.providers.join(", ")}`);
|
|
117
|
+
console.log(` Timeout per attempt: default ${agentSuccessRate.timeoutMs.default} ms, maximum ${agentSuccessRate.timeoutMs.maximum} ms`);
|
|
118
|
+
console.log(` Repair attempts: ${agentSuccessRate.repairAttempts.allowed.join(", ")} (default ${agentSuccessRate.repairAttempts.default}; at most ${agentSuccessRate.repairAttempts.maximumTotalAttemptsPerTreatment} attempts per treatment; real-agent mode only)`);
|
|
119
|
+
console.log(` Agent context: ${agentSuccessRate.agentContext}`);
|
|
120
|
+
console.log(` Patch application: ${agentSuccessRate.patchApplication}`);
|
|
121
|
+
console.log(` Task success: ${agentSuccessRate.taskSuccess}`);
|
|
122
|
+
console.log(` Report outputs: ${agentSuccessRate.reportOutputs.join(", ")}`);
|
|
123
|
+
console.log(` Target policy: ${agentSuccessRate.targetPolicy}`);
|
|
124
|
+
console.log(` Interpretation: ${agentSuccessRate.interpretation}`);
|
|
125
|
+
}
|
|
87
126
|
}
|
|
88
127
|
function printConfigSection(title, fields) {
|
|
89
128
|
console.log(`${title}:`);
|
|
@@ -123,12 +162,18 @@ function readArrayField(value, key) {
|
|
|
123
162
|
return Array.isArray(field) ? field : [];
|
|
124
163
|
}
|
|
125
164
|
function describePurpose(plugin) {
|
|
165
|
+
if (plugin.metadata.id === AGENT_SUCCESS_RATE_ID) {
|
|
166
|
+
return "Measure whether implementation patches resolve benchmark tasks under two source-context treatments (raw-full-file and context-pack) using trusted checks on disposable benchmark copies. Deterministic-fixture mode (default) validates the evaluation pipeline only; real-agent mode (opt-in) evaluates the patches a selected provider returns, with optional bounded repair.";
|
|
167
|
+
}
|
|
126
168
|
if (plugin.metadata.id === "context-strategy-comparison") {
|
|
127
169
|
return "Compare raw full-file prompts with my-dev-kit-guided retrieval prompts using the existing controlled experiment workflow.";
|
|
128
170
|
}
|
|
129
171
|
return plugin.metadata.description;
|
|
130
172
|
}
|
|
131
173
|
function describeTargetBehavior(plugin) {
|
|
174
|
+
if (plugin.metadata.id === AGENT_SUCCESS_RATE_ID) {
|
|
175
|
+
return "Self-target only: the bundled corpus is evaluated against the Lab itself and an explicit --target is rejected. Sandboxes and artifacts are written beneath the output directory (beneath the workspace when installed), never into the installed package or the canonical benchmark projects. Accepted options: --out, --case, --benchmark-project, --kit-command, --agent, --include-real-agents, --timeout-ms and --repair-attempts; every other option is rejected.";
|
|
176
|
+
}
|
|
132
177
|
const supportsExternal = plugin.metadata.supportedTargets.includes("external-local");
|
|
133
178
|
if (plugin.metadata.id === "context-window-scaling") {
|
|
134
179
|
return "Three subject modes. Bundled (default): the bundled fixed scaling corpus against the Lab itself. Synthetic: caller-supplied deterministic synthetic repositories via --synthetic-config <path> (a SyntheticRepositoryConfigV1 JSON file, mutually exclusive with --case) written beneath the experiment output directory. External local repository: an explicitly selected local Git worktree via --target <path> together with --local-subject-config <path> (a LocalRepositorySubjectConfigV1 JSON file); the repository is never modified, the output directory must be outside it, and durable output omits the repository path, source text, and file names. Operational context-fit measurement only; no retrieval precision, recall, or ranking quality is measured.";
|
|
@@ -151,6 +196,9 @@ function describeTargetBehavior(plugin) {
|
|
|
151
196
|
return "Runs against the current lab repository.";
|
|
152
197
|
}
|
|
153
198
|
function describeExpectedReports(plugin) {
|
|
199
|
+
if (plugin.metadata.id === AGENT_SUCCESS_RATE_ID) {
|
|
200
|
+
return "Writes plugin-aware report.json, report.html and report.txt with a typed agent-success-rate section (initial-attempt and final success, repair history, edit quality, provider duration and tokens, scientific limitations), plus the separate agent-success-rate-execution.json and agent-success-rate-analysis.json artifacts.";
|
|
201
|
+
}
|
|
154
202
|
if (plugin.metadata.supportedOutputs.includes("html") && plugin.metadata.supportedOutputs.includes("json")) {
|
|
155
203
|
return "Writes plugin-aware JSON and HTML reports with plugin, target, variant, case, metric, artifact, warning, skip, and failure metadata.";
|
|
156
204
|
}
|
|
@@ -185,6 +233,9 @@ function describeExamples(plugin) {
|
|
|
185
233
|
if (plugin.metadata.id === "context-pack-generation") {
|
|
186
234
|
examples.push(`my-dev-kit-lab experiment run --experiment ${plugin.metadata.id} --case <case-id> --out <run-dir>`, `my-dev-kit-lab experiment run --experiment ${plugin.metadata.id} --target <local-git-repository> --local-subject-config <path-to-local-subject-config.json> --out <run-dir-outside-the-repository>`);
|
|
187
235
|
}
|
|
236
|
+
if (plugin.metadata.id === AGENT_SUCCESS_RATE_ID) {
|
|
237
|
+
examples.push(`my-dev-kit-lab experiment run --experiment ${plugin.metadata.id} --case <case-id> --out <run-dir>`, `my-dev-kit-lab experiment run --experiment ${plugin.metadata.id} --agent codex --include-real-agents --repair-attempts 2 --out <run-dir>`);
|
|
238
|
+
}
|
|
188
239
|
if (plugin.metadata.id === "context-window-scaling") {
|
|
189
240
|
examples.push(`my-dev-kit-lab experiment run --experiment ${plugin.metadata.id} --synthetic-config <path-to-config.json> --out <run-dir>`, `my-dev-kit-lab experiment run --experiment ${plugin.metadata.id} --target <local-git-repository> --local-subject-config <path-to-local-subject-config.json> --out <run-dir-outside-the-repository>`);
|
|
190
241
|
}
|
|
@@ -3,10 +3,12 @@ import path from "node:path";
|
|
|
3
3
|
import { parseAgentCommandTemplate } from "../agents/index.js";
|
|
4
4
|
import { parseAgentId } from "../agents/agentRegistry.js";
|
|
5
5
|
import { readBenchmarkProjectProfiles, readEvaluationCases } from "../evaluation/index.js";
|
|
6
|
+
import { AGENT_SUCCESS_PROJECT_PROFILES_PATH, AGENT_SUCCESS_TASK_CATALOG_PATH, assertReadAgentSuccessCorpus } from "../evaluation/agentSuccess/index.js";
|
|
6
7
|
import { summarizeRetrievalGroundTruthIssuesSafely, validateRetrievalPrecisionRecallCorpus } from "../evaluation/retrievalQuality/index.js";
|
|
7
8
|
import { loadLocalRepositorySubject } from "../evaluation/localRepositorySubject/index.js";
|
|
8
9
|
import { contextStrategyComparisonPlugin, contextWindowScalingPlugin, createDefaultExperimentPluginRegistry, getWarmIndexCampaignPreset, incrementalChangeStalenessPlugin, parseContextBudgetsCliValue, parseWarmIndexCampaignPresetId, resolveExperimentTarget, retrievalPrecisionRecallPlugin, retrievalQueryStrategyComparisonPlugin, runExperiment, warmIndexReusePlugin } from "../experiments/index.js";
|
|
9
10
|
import { contextPackGenerationPlugin } from "../experiments/plugins/contextPackGeneration/index.js";
|
|
11
|
+
import { AGENT_SUCCESS_RATE_MAX_AGENT_TIMEOUT_MS, AGENT_SUCCESS_RATE_REAL_AGENT_IDS, agentSuccessRatePlugin, selectAgentSuccessTasks } from "../experiments/plugins/agentSuccessRate/index.js";
|
|
10
12
|
import { prepareSyntheticContextWindowScalingInputs } from "../experiments/plugins/contextWindowScaling/index.js";
|
|
11
13
|
import { projectExternalLocalTarget, projectRunForExternalLocalPersistence, } from "../experiments/plugins/contextWindowScaling/localSubjectPrivacy.js";
|
|
12
14
|
import { assertWorkRootOutsideTarget } from "../experiments/plugins/contextWindowScaling/localSubjectScratch.js";
|
|
@@ -71,6 +73,27 @@ const RETRIEVAL_QUERY_STRATEGY_COMPARISON_EXTERNAL_ALLOWED_FLAGS = ["--experimen
|
|
|
71
73
|
const CONTEXT_PACK_GENERATION_CASES_RESOURCE = "benchmarks/contracts/warm-index-benchmark-cases.json";
|
|
72
74
|
const CONTEXT_PACK_GENERATION_ALLOWED_FLAGS = ["--experiment", "--out", "--case", "--benchmark-project", "--kit-command"];
|
|
73
75
|
const CONTEXT_PACK_GENERATION_EXTERNAL_ALLOWED_FLAGS = ["--experiment", "--out", "--target", "--local-subject-config", "--kit-command"];
|
|
76
|
+
// agent-success-rate (v0.9.0) owns the bundled six-task implementation corpus (task catalog and project profiles), both
|
|
77
|
+
// resolved from the package root, never the cwd. It runs against the Lab itself only and accepts exactly these options;
|
|
78
|
+
// every other flag is rejected, not ignored. Real providers run only with --agent together with --include-real-agents.
|
|
79
|
+
const AGENT_SUCCESS_RATE_ALLOWED_FLAGS = [
|
|
80
|
+
"--experiment",
|
|
81
|
+
"--out",
|
|
82
|
+
"--case",
|
|
83
|
+
"--benchmark-project",
|
|
84
|
+
"--kit-command",
|
|
85
|
+
"--agent",
|
|
86
|
+
"--include-real-agents",
|
|
87
|
+
"--timeout-ms",
|
|
88
|
+
"--repair-attempts"
|
|
89
|
+
];
|
|
90
|
+
export function assertAgentSuccessRateFlags(argv) {
|
|
91
|
+
const flags = argv.filter((arg) => arg.startsWith("--"));
|
|
92
|
+
const unsupported = [...new Set(flags.filter((flag) => !AGENT_SUCCESS_RATE_ALLOWED_FLAGS.includes(flag)))];
|
|
93
|
+
if (unsupported.length > 0) {
|
|
94
|
+
throw new Error(`${unsupported.join(", ")} ${unsupported.length === 1 ? "is" : "are"} not supported for --experiment ${agentSuccessRatePlugin.metadata.id}; supported options: ${AGENT_SUCCESS_RATE_ALLOWED_FLAGS.join(", ")}.`);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
74
97
|
export async function runExperimentRunCommandFromArgs(argv, options = {}) {
|
|
75
98
|
try {
|
|
76
99
|
const args = parseRunExperimentArgs(argv);
|
|
@@ -151,7 +174,8 @@ export async function runExperimentRunCommandFromArgs(argv, options = {}) {
|
|
|
151
174
|
`Target root: ${result.target.targetRoot}`,
|
|
152
175
|
`Output: ${String(result.metadata?.outputRoot ?? "")}`,
|
|
153
176
|
`Report JSON: ${reports.outputPaths.jsonPath}`,
|
|
154
|
-
`Report HTML: ${reports.outputPaths.htmlPath}
|
|
177
|
+
`Report HTML: ${reports.outputPaths.htmlPath}`,
|
|
178
|
+
...(args.experimentId === agentSuccessRatePlugin.metadata.id ? agentSuccessRateSummaryLines(result, reports.outputPaths.textPath) : [])
|
|
155
179
|
];
|
|
156
180
|
// Automatic presentation (report already produced above) applies only to warm-index-reuse
|
|
157
181
|
// campaign runs; legacy fake-agent warm-index runs and context-strategy-comparison stay
|
|
@@ -225,8 +249,14 @@ export function parseRunExperimentArgs(argv) {
|
|
|
225
249
|
let contextBudgets;
|
|
226
250
|
let syntheticConfigPath;
|
|
227
251
|
let localSubjectConfigPath;
|
|
252
|
+
const agentFlagValues = [];
|
|
253
|
+
let repairAttempts;
|
|
228
254
|
const seenFlags = [];
|
|
229
255
|
const commandTemplates = {};
|
|
256
|
+
// The flag whitelist runs before any value is interpreted so an unsupported flag is reported as such.
|
|
257
|
+
const preScanIndex = argv.indexOf("--experiment");
|
|
258
|
+
if (preScanIndex >= 0 && argv[preScanIndex + 1] === agentSuccessRatePlugin.metadata.id)
|
|
259
|
+
assertAgentSuccessRateFlags(argv);
|
|
230
260
|
for (let index = 0; index < argv.length; index += 1) {
|
|
231
261
|
const arg = argv[index];
|
|
232
262
|
if (arg !== undefined && arg.startsWith("--"))
|
|
@@ -264,6 +294,12 @@ export function parseRunExperimentArgs(argv) {
|
|
|
264
294
|
else if (arg === "--benchmark-project") {
|
|
265
295
|
benchmarkProjects.push(...splitList(readRequiredValue(argv, ++index, "--benchmark-project")));
|
|
266
296
|
}
|
|
297
|
+
else if (arg === "--agent") {
|
|
298
|
+
agentFlagValues.push(readRequiredValue(argv, ++index, "--agent"));
|
|
299
|
+
}
|
|
300
|
+
else if (arg === "--repair-attempts") {
|
|
301
|
+
repairAttempts = parseRepairAttempts(readRequiredValue(argv, ++index, "--repair-attempts"));
|
|
302
|
+
}
|
|
267
303
|
else if (arg === "--agents") {
|
|
268
304
|
agents = splitList(readRequiredValue(argv, ++index, "--agents")).map((value) => parseAgentId(value));
|
|
269
305
|
}
|
|
@@ -399,6 +435,49 @@ export function parseRunExperimentArgs(argv) {
|
|
|
399
435
|
throw new Error("--benchmark-project must list at least one benchmark project id.");
|
|
400
436
|
}
|
|
401
437
|
}
|
|
438
|
+
if (experimentId === agentSuccessRatePlugin.metadata.id) {
|
|
439
|
+
// Mode matrix: no flags = deterministic-fixture (default); --agent together with --include-real-agents = real-agent mode.
|
|
440
|
+
// Everything else is rejected, never coerced: a provider needs both flags, and real-agent options need a provider.
|
|
441
|
+
if (agentFlagValues.length > 1) {
|
|
442
|
+
throw new Error("--agent may be supplied only once; agent-success-rate runs exactly one provider.");
|
|
443
|
+
}
|
|
444
|
+
const agentId = agentFlagValues[0];
|
|
445
|
+
if (agentId !== undefined && !AGENT_SUCCESS_RATE_REAL_AGENT_IDS.includes(agentId)) {
|
|
446
|
+
throw new Error(`--agent must be exactly one of: ${AGENT_SUCCESS_RATE_REAL_AGENT_IDS.join(", ")}.`);
|
|
447
|
+
}
|
|
448
|
+
if (agentId !== undefined && includeRealAgents !== true) {
|
|
449
|
+
throw new Error("--agent requires --include-real-agents; real providers are invoked only with explicit authorization.");
|
|
450
|
+
}
|
|
451
|
+
if (agentId === undefined && includeRealAgents === true) {
|
|
452
|
+
throw new Error("--include-real-agents requires --agent <codex|claude> for agent-success-rate.");
|
|
453
|
+
}
|
|
454
|
+
if (agentId === undefined && timeoutMs !== undefined) {
|
|
455
|
+
throw new Error("--timeout-ms is only supported together with --agent and --include-real-agents (real-agent mode).");
|
|
456
|
+
}
|
|
457
|
+
if (agentId === undefined && kitCommand !== undefined) {
|
|
458
|
+
throw new Error("--kit-command is only supported together with --agent and --include-real-agents (real-agent mode).");
|
|
459
|
+
}
|
|
460
|
+
if (agentId === undefined && repairAttempts !== undefined && repairAttempts > 0) {
|
|
461
|
+
throw new Error("--repair-attempts greater than 0 requires --agent and --include-real-agents (real-agent mode).");
|
|
462
|
+
}
|
|
463
|
+
if (timeoutMs !== undefined && timeoutMs > AGENT_SUCCESS_RATE_MAX_AGENT_TIMEOUT_MS) {
|
|
464
|
+
throw new Error(`--timeout-ms must be a positive integer no greater than ${AGENT_SUCCESS_RATE_MAX_AGENT_TIMEOUT_MS}.`);
|
|
465
|
+
}
|
|
466
|
+
if (seenFlags.includes("--case") && caseIds.length === 0) {
|
|
467
|
+
throw new Error("--case must list at least one case id.");
|
|
468
|
+
}
|
|
469
|
+
if (seenFlags.includes("--benchmark-project") && benchmarkProjects.length === 0) {
|
|
470
|
+
throw new Error("--benchmark-project must list at least one benchmark project id.");
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
else {
|
|
474
|
+
if (agentFlagValues.length > 0) {
|
|
475
|
+
throw new Error(`--agent is only supported for --experiment ${agentSuccessRatePlugin.metadata.id}.`);
|
|
476
|
+
}
|
|
477
|
+
if (repairAttempts !== undefined) {
|
|
478
|
+
throw new Error(`--repair-attempts is only supported for --experiment ${agentSuccessRatePlugin.metadata.id}.`);
|
|
479
|
+
}
|
|
480
|
+
}
|
|
402
481
|
if (contextBudgets !== undefined && experimentId !== contextWindowScalingPlugin.metadata.id) {
|
|
403
482
|
throw new Error(`--context-budgets is only supported for --experiment ${contextWindowScalingPlugin.metadata.id}.`);
|
|
404
483
|
}
|
|
@@ -441,7 +520,8 @@ export function parseRunExperimentArgs(argv) {
|
|
|
441
520
|
throw new Error(`External ${experimentId} targets require --local-subject-config.`);
|
|
442
521
|
}
|
|
443
522
|
}
|
|
444
|
-
|
|
523
|
+
// agent-success-rate accepts --kit-command in real-agent mode; its own validation above owns that rule and message.
|
|
524
|
+
if (kitCommand !== undefined && experimentId !== agentSuccessRatePlugin.metadata.id && !KIT_COMMAND_PLUGIN_IDS.includes(experimentId)) {
|
|
445
525
|
throw new Error(`--kit-command is only supported for --experiment ${KIT_COMMAND_PLUGIN_IDS.join(" or ")}.`);
|
|
446
526
|
}
|
|
447
527
|
if (campaignPreset !== undefined) {
|
|
@@ -478,6 +558,8 @@ export function parseRunExperimentArgs(argv) {
|
|
|
478
558
|
requireAgents,
|
|
479
559
|
includeRealAgents,
|
|
480
560
|
commandTemplates: Object.keys(commandTemplates).length > 0 ? commandTemplates : undefined,
|
|
561
|
+
agentId: agentFlagValues[0],
|
|
562
|
+
repairAttempts,
|
|
481
563
|
kitCommand,
|
|
482
564
|
campaignPreset,
|
|
483
565
|
contextBudgets
|
|
@@ -542,8 +624,27 @@ async function loadPluginInputs(args, toolRoot, context, outputRoot) {
|
|
|
542
624
|
? loadRetrievalQueryStrategyComparisonLocalSubjectInputs(args, toolRoot, context, outputRoot)
|
|
543
625
|
: loadRetrievalQueryStrategyComparisonInputs(args, toolRoot, context);
|
|
544
626
|
}
|
|
627
|
+
if (args.experimentId === agentSuccessRatePlugin.metadata.id) {
|
|
628
|
+
return loadAgentSuccessRateInputs(args, context);
|
|
629
|
+
}
|
|
545
630
|
return undefined;
|
|
546
631
|
}
|
|
632
|
+
// agent-success-rate: the bundled task catalog and project profiles are located through the established package-resource
|
|
633
|
+
// resolver (never the cwd) and validated by the corpus reader, which also checks the canonical projects on disk. The
|
|
634
|
+
// validated tasks reach the plugin through its existing programmatic input; the plugin applies --case/--benchmark-project
|
|
635
|
+
// selection in catalog order and owns execution, repair, science and artifacts. No task file is accepted from the CLI.
|
|
636
|
+
async function loadAgentSuccessRateInputs(args, context) {
|
|
637
|
+
const validation = agentSuccessRatePlugin.validateConfig(args.config);
|
|
638
|
+
if (!validation.valid || !validation.config) {
|
|
639
|
+
throw new Error(`Invalid agent success rate config: ${validation.errors.join("; ")}`);
|
|
640
|
+
}
|
|
641
|
+
resolvePackageResource(context, AGENT_SUCCESS_TASK_CATALOG_PATH);
|
|
642
|
+
resolvePackageResource(context, AGENT_SUCCESS_PROJECT_PROFILES_PATH);
|
|
643
|
+
const corpus = assertReadAgentSuccessCorpus(context.resourceRoot);
|
|
644
|
+
// Fail on unknown case or project ids before any output directory exists.
|
|
645
|
+
selectAgentSuccessTasks(corpus.tasks, validation.config);
|
|
646
|
+
return { agentSuccessTasks: corpus.tasks };
|
|
647
|
+
}
|
|
547
648
|
// context-pack-generation (bundled/self): the frozen warm-index corpus through the established resource resolver, profile
|
|
548
649
|
// and corpus validation. The plugin applies --case/--benchmark-project selection and owns execution, science and artifacts.
|
|
549
650
|
async function loadContextPackGenerationInputs(args, toolRoot, context) {
|
|
@@ -815,6 +916,12 @@ function readRequiredValue(argv, index, label) {
|
|
|
815
916
|
}
|
|
816
917
|
return value;
|
|
817
918
|
}
|
|
919
|
+
function parseRepairAttempts(value) {
|
|
920
|
+
if (!/^[0-2]$/.test(value)) {
|
|
921
|
+
throw new Error("--repair-attempts must be 0, 1 or 2.");
|
|
922
|
+
}
|
|
923
|
+
return Number(value);
|
|
924
|
+
}
|
|
818
925
|
function parsePositiveInteger(label, value) {
|
|
819
926
|
const parsed = Number(value);
|
|
820
927
|
if (!Number.isInteger(parsed) || parsed <= 0) {
|
|
@@ -822,6 +929,15 @@ function parsePositiveInteger(label, value) {
|
|
|
822
929
|
}
|
|
823
930
|
return parsed;
|
|
824
931
|
}
|
|
932
|
+
function agentSuccessRateSummaryLines(result, textPath) {
|
|
933
|
+
const mode = readMetadataString(result.metadata?.executionMode) ?? "deterministic-fixture";
|
|
934
|
+
const provider = readMetadataString(result.metadata?.providerId);
|
|
935
|
+
return [
|
|
936
|
+
`Report Text: ${textPath}`,
|
|
937
|
+
`Execution mode: ${mode}`,
|
|
938
|
+
...(provider ? [`Provider: ${provider} (invoked by explicit --include-real-agents authorization)`] : ["Provider: none (deterministic-fixture; no coding agent was invoked)"])
|
|
939
|
+
];
|
|
940
|
+
}
|
|
825
941
|
function readMetadataString(value) {
|
|
826
942
|
return typeof value === "string" && value.trim() ? value : undefined;
|
|
827
943
|
}
|
|
@@ -20,6 +20,61 @@ export function requestProcessTermination(pid) {
|
|
|
20
20
|
// The process may have exited between the liveness check and this signal.
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
|
+
/**
|
|
24
|
+
* Opt-in, awaitable descendant-tree termination for bounded execution
|
|
25
|
+
* (see `terminateProcessTree` in `runMeasuredCommand`). The legacy
|
|
26
|
+
* `forceTerminateProcess` above is intentionally unchanged: it stays
|
|
27
|
+
* fire-and-forget and, off Windows, signals one pid only.
|
|
28
|
+
*
|
|
29
|
+
* Windows: `taskkill /pid <pid> /T /F` (shell:false) is awaited, bounded by
|
|
30
|
+
* `waitTimeoutMs`, so the caller knows the tree was asked to die before it
|
|
31
|
+
* proceeds.
|
|
32
|
+
*
|
|
33
|
+
* Other platforms: the child must have been spawned `detached` so it leads its
|
|
34
|
+
* own process group; the whole group is signalled via the negative pid. If no
|
|
35
|
+
* group exists, the single pid is signalled as a fallback.
|
|
36
|
+
*
|
|
37
|
+
* Never throws: the target may already have exited.
|
|
38
|
+
*/
|
|
39
|
+
export async function terminateProcessTree(pid, options = {}) {
|
|
40
|
+
if (!pid) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
const platform = options.platform ?? process.platform;
|
|
44
|
+
if (platform === "win32") {
|
|
45
|
+
await new Promise((resolve) => {
|
|
46
|
+
let timer;
|
|
47
|
+
const finish = () => {
|
|
48
|
+
if (timer)
|
|
49
|
+
clearTimeout(timer);
|
|
50
|
+
resolve();
|
|
51
|
+
};
|
|
52
|
+
const killer = spawn("taskkill", ["/pid", String(pid), "/T", "/F"], {
|
|
53
|
+
shell: false,
|
|
54
|
+
stdio: "ignore",
|
|
55
|
+
windowsHide: true
|
|
56
|
+
});
|
|
57
|
+
timer = setTimeout(finish, options.waitTimeoutMs ?? 5000);
|
|
58
|
+
killer.on("error", finish);
|
|
59
|
+
killer.on("close", finish);
|
|
60
|
+
});
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
const signal = options.posixSignal ?? "SIGKILL";
|
|
64
|
+
try {
|
|
65
|
+
process.kill(-pid, signal);
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
// No process group for this pid (or it already exited); fall back to the single pid.
|
|
70
|
+
}
|
|
71
|
+
try {
|
|
72
|
+
process.kill(pid, signal);
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
// The process may have exited between the liveness check and this signal.
|
|
76
|
+
}
|
|
77
|
+
}
|
|
23
78
|
/**
|
|
24
79
|
* Forced cleanup for a process that did not stop on request.
|
|
25
80
|
*
|