@nathapp/nax 0.67.0-canary.3 → 0.67.0-canary.5
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/dist/nax.js +709 -612
- package/package.json +6 -4
package/dist/nax.js
CHANGED
|
@@ -17904,7 +17904,7 @@ function formatConsole(entry) {
|
|
|
17904
17904
|
const timestamp = new Date(entry.timestamp).toLocaleTimeString("en-US", {
|
|
17905
17905
|
hour12: false
|
|
17906
17906
|
});
|
|
17907
|
-
let levelColor;
|
|
17907
|
+
let levelColor = source_default.gray;
|
|
17908
17908
|
switch (entry.level) {
|
|
17909
17909
|
case "error":
|
|
17910
17910
|
levelColor = source_default.red;
|
|
@@ -17916,6 +17916,7 @@ function formatConsole(entry) {
|
|
|
17916
17916
|
levelColor = source_default.blue;
|
|
17917
17917
|
break;
|
|
17918
17918
|
case "debug":
|
|
17919
|
+
case "silent":
|
|
17919
17920
|
levelColor = source_default.gray;
|
|
17920
17921
|
break;
|
|
17921
17922
|
}
|
|
@@ -18064,7 +18065,7 @@ ${JSON.stringify(entry.data, null, 2)}`;
|
|
|
18064
18065
|
}
|
|
18065
18066
|
close() {}
|
|
18066
18067
|
}
|
|
18067
|
-
function initLogger(options = { level: "
|
|
18068
|
+
function initLogger(options = { level: "silent" }) {
|
|
18068
18069
|
if (instance) {
|
|
18069
18070
|
throw new Error("Logger already initialized. Call getLogger() to access existing instance.");
|
|
18070
18071
|
}
|
|
@@ -18095,12 +18096,13 @@ var init_logger = __esm(() => {
|
|
|
18095
18096
|
init_logging();
|
|
18096
18097
|
init_formatters();
|
|
18097
18098
|
LOG_LEVEL_PRIORITY = {
|
|
18099
|
+
silent: -1,
|
|
18098
18100
|
error: 0,
|
|
18099
18101
|
warn: 1,
|
|
18100
18102
|
info: 2,
|
|
18101
18103
|
debug: 3
|
|
18102
18104
|
};
|
|
18103
|
-
noopLogger = new Logger({ level: "
|
|
18105
|
+
noopLogger = new Logger({ level: "silent", useChalk: false, headless: false });
|
|
18104
18106
|
});
|
|
18105
18107
|
|
|
18106
18108
|
// src/logger/index.ts
|
|
@@ -34139,7 +34141,7 @@ var init_autofix_implementer = __esm(() => {
|
|
|
34139
34141
|
kind: "run",
|
|
34140
34142
|
name: "autofix-implementer",
|
|
34141
34143
|
stage: "rectification",
|
|
34142
|
-
session: { role: "implementer", lifetime: "
|
|
34144
|
+
session: { role: "implementer", lifetime: "warm" },
|
|
34143
34145
|
config: autofixConfigSelector,
|
|
34144
34146
|
build(input, _ctx) {
|
|
34145
34147
|
const prompt = RectifierPromptBuilder.reviewRectification(input.failedChecks, input.story);
|
|
@@ -34213,6 +34215,7 @@ var init_debate_propose = __esm(() => {
|
|
|
34213
34215
|
return "fast";
|
|
34214
34216
|
return { agent: debater.agent, model: debater.model ?? "fast" };
|
|
34215
34217
|
},
|
|
34218
|
+
timeoutMs: (_input, ctx) => (ctx.config.debate?.stages?.review?.timeoutSeconds ?? 600) * 1000,
|
|
34216
34219
|
build(input, _ctx) {
|
|
34217
34220
|
const builder = new DebatePromptBuilder({ taskContext: input.taskContext, outputFormat: input.outputFormat, stage: input.stage }, { debaters: input.debaters, sessionMode: "one-shot", proposers: input.stageConfig?.proposers });
|
|
34218
34221
|
return builder.proposeSlot(input.debaterIndex);
|
|
@@ -34235,6 +34238,7 @@ var init_debate_judge = __esm(() => {
|
|
|
34235
34238
|
jsonMode: false,
|
|
34236
34239
|
config: debateConfigSelector,
|
|
34237
34240
|
model: (input) => ({ agent: input.resolverAgent, model: input.resolverModel }),
|
|
34241
|
+
timeoutMs: (input, ctx) => (input.timeoutSeconds ?? ctx.config.debate?.stages?.review?.timeoutSeconds ?? 600) * 1000,
|
|
34238
34242
|
build(input, _ctx) {
|
|
34239
34243
|
const prompt = DebatePromptBuilder.resolverJudgePrompt(input.proposals, input.critiques, input.debaters);
|
|
34240
34244
|
return {
|
|
@@ -34260,6 +34264,7 @@ var init_debate_synthesis = __esm(() => {
|
|
|
34260
34264
|
jsonMode: false,
|
|
34261
34265
|
config: debateConfigSelector,
|
|
34262
34266
|
model: (input) => ({ agent: input.resolverAgent, model: input.resolverModel }),
|
|
34267
|
+
timeoutMs: (input, ctx) => (input.timeoutSeconds ?? ctx.config.debate?.stages?.review?.timeoutSeconds ?? 600) * 1000,
|
|
34263
34268
|
build(input, _ctx) {
|
|
34264
34269
|
const base = DebatePromptBuilder.resolverSynthesisPrompt(input.proposals, input.critiques, input.debaters);
|
|
34265
34270
|
const content = input.promptSuffix ? `${base}
|
|
@@ -34293,6 +34298,7 @@ var init_debate_rebut = __esm(() => {
|
|
|
34293
34298
|
return "fast";
|
|
34294
34299
|
return { agent: debater.agent, model: debater.model ?? "fast" };
|
|
34295
34300
|
},
|
|
34301
|
+
timeoutMs: (_input, ctx) => (ctx.config.debate?.stages?.review?.timeoutSeconds ?? 600) * 1000,
|
|
34296
34302
|
build(input, _ctx) {
|
|
34297
34303
|
const builder = new DebatePromptBuilder({ taskContext: input.taskContext, outputFormat: "", stage: input.stage }, { debaters: input.debaters, sessionMode: "one-shot" });
|
|
34298
34304
|
return builder.rebutSlot(input.debaterIndex, input.proposals);
|
|
@@ -34339,6 +34345,7 @@ var init_debate_stateful = __esm(() => {
|
|
|
34339
34345
|
session: { role: "debate-stateful", lifetime: "fresh" },
|
|
34340
34346
|
config: debateConfigSelector,
|
|
34341
34347
|
model: (input) => ({ agent: input.debater.agent, model: input.debater.model ?? "fast" }),
|
|
34348
|
+
timeoutMs: (_input, ctx) => (ctx.config.debate?.stages?.review?.timeoutSeconds ?? 600) * 1000,
|
|
34342
34349
|
async hopBody(initialPrompt, ctx) {
|
|
34343
34350
|
const proposal = ctx.input.turnSemaphore ? await ctx.input.turnSemaphore.run(() => ctx.send(initialPrompt)) : await ctx.send(initialPrompt);
|
|
34344
34351
|
ctx.input.proposalBarriers[ctx.input.index].resolve(proposal.output);
|
|
@@ -34510,7 +34517,8 @@ var RESOLVER_FALLBACK_AGENT = "synthesis", RESOLVER_FALLBACK_MODEL = "fast", jud
|
|
|
34510
34517
|
critiques: ctx.critiques,
|
|
34511
34518
|
debaters: ctx.debaters,
|
|
34512
34519
|
resolverAgent,
|
|
34513
|
-
resolverModel
|
|
34520
|
+
resolverModel,
|
|
34521
|
+
timeoutSeconds: ctx.stageConfig.timeoutSeconds
|
|
34514
34522
|
});
|
|
34515
34523
|
return {
|
|
34516
34524
|
outcome: output.trim() ? "passed" : "failed",
|
|
@@ -34533,7 +34541,8 @@ var RESOLVER_FALLBACK_AGENT2 = "synthesis", RESOLVER_FALLBACK_MODEL2 = "fast", s
|
|
|
34533
34541
|
debaters: ctx.debaters,
|
|
34534
34542
|
resolverAgent,
|
|
34535
34543
|
resolverModel,
|
|
34536
|
-
promptSuffix: ctx.promptSuffix
|
|
34544
|
+
promptSuffix: ctx.promptSuffix,
|
|
34545
|
+
timeoutSeconds: ctx.stageConfig.timeoutSeconds
|
|
34537
34546
|
});
|
|
34538
34547
|
return {
|
|
34539
34548
|
outcome: output.trim() ? "passed" : "failed",
|
|
@@ -34846,6 +34855,7 @@ var init_debate_hybrid = __esm(() => {
|
|
|
34846
34855
|
session: { role: "debate-hybrid", lifetime: "fresh" },
|
|
34847
34856
|
config: debateConfigSelector,
|
|
34848
34857
|
model: (input) => ({ agent: input.debater.agent, model: input.debater.model ?? "fast" }),
|
|
34858
|
+
timeoutMs: (_input, ctx) => (ctx.config.debate?.stages?.review?.timeoutSeconds ?? 600) * 1000,
|
|
34849
34859
|
async hopBody(initialPrompt, ctx) {
|
|
34850
34860
|
const logger = _debateSessionDeps.getSafeLogger();
|
|
34851
34861
|
let totalCostUsd = 0;
|
|
@@ -34909,6 +34919,7 @@ var init_debate_plan = __esm(() => {
|
|
|
34909
34919
|
session: { role: "debate-plan", lifetime: "fresh" },
|
|
34910
34920
|
config: debateConfigSelector,
|
|
34911
34921
|
model: (input) => ({ agent: input.debater.agent, model: input.debater.model ?? "fast" }),
|
|
34922
|
+
timeoutMs: (_input, ctx) => (ctx.config.debate?.stages?.plan?.timeoutSeconds ?? 600) * 1000,
|
|
34912
34923
|
fileOutput: (input) => input.outputPath,
|
|
34913
34924
|
async hopBody(initialPrompt, ctx) {
|
|
34914
34925
|
const proposal = ctx.input.turnSemaphore ? await ctx.input.turnSemaphore.run(() => ctx.send(initialPrompt)) : await ctx.send(initialPrompt);
|
|
@@ -36848,7 +36859,7 @@ function countTotalAttempts(iterations) {
|
|
|
36848
36859
|
return iterations.reduce((sum, iter) => sum + iter.fixesApplied.length, 0);
|
|
36849
36860
|
}
|
|
36850
36861
|
async function runFixCycle(cycle, ctx, cycleName, _deps = {}) {
|
|
36851
|
-
const logger = getSafeLogger();
|
|
36862
|
+
const logger = _deps.logger !== undefined ? _deps.logger : getSafeLogger();
|
|
36852
36863
|
const doCallOp = _deps.callOp ?? _cycleDeps.callOp;
|
|
36853
36864
|
const now = _deps.now ?? _cycleDeps.now;
|
|
36854
36865
|
const storyId = ctx.storyId;
|
|
@@ -36978,29 +36989,77 @@ async function runFixCycle(cycle, ctx, cycleName, _deps = {}) {
|
|
|
36978
36989
|
costUsd: totalCostUsd
|
|
36979
36990
|
};
|
|
36980
36991
|
}
|
|
36981
|
-
const
|
|
36982
|
-
|
|
36992
|
+
const allExhausted = group.every((s) => {
|
|
36993
|
+
const prior = countStrategyAttempts(cycle.iterations, s.name);
|
|
36994
|
+
const current = fixesApplied.filter((fa) => fa.strategyName === s.name).length;
|
|
36995
|
+
return prior + current >= s.maxAttempts;
|
|
36996
|
+
});
|
|
36983
36997
|
if (allExhausted) {
|
|
36998
|
+
let liteFindingsAfter;
|
|
36999
|
+
try {
|
|
37000
|
+
liteFindingsAfter = await cycle.validate(ctx, { mode: "lite" });
|
|
37001
|
+
} catch (err) {
|
|
37002
|
+
const finishedAt3 = now();
|
|
37003
|
+
cycle.iterations.push({
|
|
37004
|
+
iterationNum: cycle.iterations.length + 1,
|
|
37005
|
+
findingsBefore,
|
|
37006
|
+
fixesApplied,
|
|
37007
|
+
findingsAfter: cycle.findings,
|
|
37008
|
+
outcome: "unchanged",
|
|
37009
|
+
startedAt,
|
|
37010
|
+
finishedAt: finishedAt3
|
|
37011
|
+
});
|
|
37012
|
+
logger?.warn("findings.cycle", "lite validate failed on terminal exhausted branch", {
|
|
37013
|
+
storyId,
|
|
37014
|
+
packageDir,
|
|
37015
|
+
cycleName,
|
|
37016
|
+
error: errorMessage(err)
|
|
37017
|
+
});
|
|
37018
|
+
return {
|
|
37019
|
+
iterations: cycle.iterations,
|
|
37020
|
+
finalFindings: cycle.findings,
|
|
37021
|
+
exitReason: "max-attempts-per-strategy",
|
|
37022
|
+
exhaustedStrategy: group[0]?.name,
|
|
37023
|
+
costUsd: totalCostUsd
|
|
37024
|
+
};
|
|
37025
|
+
}
|
|
37026
|
+
const outcome2 = classifyOutcome(findingsBefore, liteFindingsAfter);
|
|
36984
37027
|
const finishedAt2 = now();
|
|
36985
37028
|
cycle.iterations.push({
|
|
36986
37029
|
iterationNum: cycle.iterations.length + 1,
|
|
36987
37030
|
findingsBefore,
|
|
36988
37031
|
fixesApplied,
|
|
36989
|
-
findingsAfter:
|
|
36990
|
-
outcome:
|
|
37032
|
+
findingsAfter: liteFindingsAfter,
|
|
37033
|
+
outcome: outcome2,
|
|
36991
37034
|
startedAt,
|
|
36992
37035
|
finishedAt: finishedAt2
|
|
36993
37036
|
});
|
|
36994
|
-
|
|
37037
|
+
cycle.findings = liteFindingsAfter;
|
|
37038
|
+
if (liteFindingsAfter.length === 0) {
|
|
37039
|
+
logger?.info("findings.cycle", "cycle exited \u2014 resolved after terminal lite validate", {
|
|
37040
|
+
storyId,
|
|
37041
|
+
packageDir,
|
|
37042
|
+
cycleName,
|
|
37043
|
+
reason: "resolved"
|
|
37044
|
+
});
|
|
37045
|
+
return {
|
|
37046
|
+
iterations: cycle.iterations,
|
|
37047
|
+
finalFindings: [],
|
|
37048
|
+
exitReason: "resolved",
|
|
37049
|
+
costUsd: totalCostUsd
|
|
37050
|
+
};
|
|
37051
|
+
}
|
|
37052
|
+
logger?.info("findings.cycle", "cycle exited \u2014 strategy attempt cap reached (lite validate)", {
|
|
36995
37053
|
storyId,
|
|
36996
37054
|
packageDir,
|
|
36997
37055
|
cycleName,
|
|
36998
37056
|
reason: "max-attempts-per-strategy",
|
|
36999
|
-
exhaustedStrategy: group[0]?.name
|
|
37057
|
+
exhaustedStrategy: group[0]?.name,
|
|
37058
|
+
liteFindingsAfterCount: liteFindingsAfter.length
|
|
37000
37059
|
});
|
|
37001
37060
|
return {
|
|
37002
37061
|
iterations: cycle.iterations,
|
|
37003
|
-
finalFindings:
|
|
37062
|
+
finalFindings: liteFindingsAfter,
|
|
37004
37063
|
exitReason: "max-attempts-per-strategy",
|
|
37005
37064
|
exhaustedStrategy: group[0]?.name,
|
|
37006
37065
|
costUsd: totalCostUsd
|
|
@@ -37010,7 +37069,7 @@ async function runFixCycle(cycle, ctx, cycleName, _deps = {}) {
|
|
|
37010
37069
|
let validatorAttempt = 0;
|
|
37011
37070
|
for (;; ) {
|
|
37012
37071
|
try {
|
|
37013
|
-
findingsAfter = await cycle.validate(ctx);
|
|
37072
|
+
findingsAfter = await cycle.validate(ctx, { mode: "full" });
|
|
37014
37073
|
break;
|
|
37015
37074
|
} catch (err) {
|
|
37016
37075
|
if (validatorAttempt >= cycle.config.validatorRetries) {
|
|
@@ -39290,8 +39349,486 @@ async function runRetryLoop(input) {
|
|
|
39290
39349
|
return { outcome: "exhausted", attempts: input.maxAttempts, finalFailure: currentFailure };
|
|
39291
39350
|
}
|
|
39292
39351
|
|
|
39352
|
+
// src/execution/escalation/escalation.ts
|
|
39353
|
+
function escalateTier(currentTier, tierOrder) {
|
|
39354
|
+
const getName = (t) => t.tier ?? t.name ?? null;
|
|
39355
|
+
const currentIndex = tierOrder.findIndex((t) => getName(t) === currentTier);
|
|
39356
|
+
if (currentIndex === -1 || currentIndex === tierOrder.length - 1) {
|
|
39357
|
+
return null;
|
|
39358
|
+
}
|
|
39359
|
+
const next = tierOrder[currentIndex + 1];
|
|
39360
|
+
const nextName = getName(next);
|
|
39361
|
+
if (!nextName)
|
|
39362
|
+
return null;
|
|
39363
|
+
return { tier: nextName, agent: next.agent };
|
|
39364
|
+
}
|
|
39365
|
+
function calculateMaxIterations(tierOrder) {
|
|
39366
|
+
return tierOrder.reduce((sum, t) => sum + t.attempts, 0);
|
|
39367
|
+
}
|
|
39368
|
+
|
|
39369
|
+
// src/session/naming.ts
|
|
39370
|
+
var exports_naming = {};
|
|
39371
|
+
__export(exports_naming, {
|
|
39372
|
+
formatSessionName: () => formatSessionName
|
|
39373
|
+
});
|
|
39374
|
+
var init_naming = __esm(() => {
|
|
39375
|
+
init_session_name();
|
|
39376
|
+
});
|
|
39377
|
+
|
|
39378
|
+
// src/verification/failure-records.ts
|
|
39379
|
+
function truncateUnmappedFailureOutput(output) {
|
|
39380
|
+
const tailLines = output.split(`
|
|
39381
|
+
`).slice(-UNMAPPED_FAILURE_OUTPUT_MAX_LINES).join(`
|
|
39382
|
+
`);
|
|
39383
|
+
if (tailLines.length <= UNMAPPED_FAILURE_OUTPUT_MAX_CHARS) {
|
|
39384
|
+
return tailLines;
|
|
39385
|
+
}
|
|
39386
|
+
return `... (truncated)
|
|
39387
|
+
${tailLines.slice(-UNMAPPED_FAILURE_OUTPUT_MAX_CHARS)}`;
|
|
39388
|
+
}
|
|
39389
|
+
function buildFailureRecords(testSummary, rawOutput) {
|
|
39390
|
+
if (testSummary.failures.length > 0) {
|
|
39391
|
+
return testSummary.failures.map((failure) => ({
|
|
39392
|
+
test: failure.testName,
|
|
39393
|
+
file: failure.file,
|
|
39394
|
+
message: failure.error,
|
|
39395
|
+
output: failure.stackTrace.length > 0 ? failure.stackTrace.join(`
|
|
39396
|
+
`) : undefined
|
|
39397
|
+
}));
|
|
39398
|
+
}
|
|
39399
|
+
if (testSummary.failed === 0) {
|
|
39400
|
+
return [];
|
|
39401
|
+
}
|
|
39402
|
+
return [
|
|
39403
|
+
{
|
|
39404
|
+
test: `Unmapped test failures (${testSummary.failed} detected)`,
|
|
39405
|
+
message: "Structured test failure parsing returned no failure records. Diagnose the regression from the raw test output.",
|
|
39406
|
+
output: rawOutput?.trim() ? truncateUnmappedFailureOutput(rawOutput.trim()) : undefined
|
|
39407
|
+
}
|
|
39408
|
+
];
|
|
39409
|
+
}
|
|
39410
|
+
var UNMAPPED_FAILURE_OUTPUT_MAX_LINES = 200, UNMAPPED_FAILURE_OUTPUT_MAX_CHARS = 8000;
|
|
39411
|
+
|
|
39412
|
+
// src/verification/rectification-loop.ts
|
|
39413
|
+
async function _defaultRunDebate(storyId, stageConfig, prompt, config2, agentManager) {
|
|
39414
|
+
const logger = getSafeLogger();
|
|
39415
|
+
const debaters = stageConfig.debaters ?? [];
|
|
39416
|
+
const manager = agentManager;
|
|
39417
|
+
const resolved = [];
|
|
39418
|
+
for (const debater of debaters) {
|
|
39419
|
+
if (manager.getAgent(debater.agent)) {
|
|
39420
|
+
resolved.push({ debater, agentName: debater.agent });
|
|
39421
|
+
}
|
|
39422
|
+
}
|
|
39423
|
+
if (resolved.length === 0) {
|
|
39424
|
+
return { output: null, totalCostUsd: 0 };
|
|
39425
|
+
}
|
|
39426
|
+
const timeoutMs = (config2.execution?.sessionTimeoutSeconds ?? 600) * 1000;
|
|
39427
|
+
const defaultAgentName = resolveDefaultAgent(config2);
|
|
39428
|
+
const resolvedDebaters = resolved.map(({ debater, agentName }) => {
|
|
39429
|
+
let modelDef;
|
|
39430
|
+
try {
|
|
39431
|
+
modelDef = resolveConfiguredModel(config2.models, agentName, debater.model ?? "balanced", defaultAgentName).modelDef;
|
|
39432
|
+
} catch {
|
|
39433
|
+
modelDef = { provider: "unknown", model: debater.model ?? "default" };
|
|
39434
|
+
}
|
|
39435
|
+
return { debater, agentName, modelDef };
|
|
39436
|
+
});
|
|
39437
|
+
const startMs = Date.now();
|
|
39438
|
+
const proposalSettled = await Promise.allSettled(resolvedDebaters.map(({ agentName, modelDef }) => manager.completeAs(agentName, prompt, {
|
|
39439
|
+
modelDef,
|
|
39440
|
+
workdir: "",
|
|
39441
|
+
storyId,
|
|
39442
|
+
sessionRole: "debate-proposal",
|
|
39443
|
+
timeoutMs
|
|
39444
|
+
}).then((out) => typeof out === "string" ? out : out.output)));
|
|
39445
|
+
const durationMs = Date.now() - startMs;
|
|
39446
|
+
const successful = proposalSettled.filter((r) => r.status === "fulfilled").map((r) => r.value);
|
|
39447
|
+
if (successful.length === 0) {
|
|
39448
|
+
return { output: null, totalCostUsd: 0 };
|
|
39449
|
+
}
|
|
39450
|
+
const successCount = successful.length;
|
|
39451
|
+
const costPerDebater = estimateCostByDuration("balanced", durationMs / successCount);
|
|
39452
|
+
const totalCostUsd = costPerDebater.cost * successCount;
|
|
39453
|
+
logger?.debug("rectification", "debate diagnosis complete", { storyId, successCount, totalCostUsd });
|
|
39454
|
+
const output = successful.join(`
|
|
39455
|
+
|
|
39456
|
+
`);
|
|
39457
|
+
return { output, totalCostUsd };
|
|
39458
|
+
}
|
|
39459
|
+
async function runRectificationLoop(opts) {
|
|
39460
|
+
const loopStartMs = Date.now();
|
|
39461
|
+
const {
|
|
39462
|
+
config: config2,
|
|
39463
|
+
workdir,
|
|
39464
|
+
story,
|
|
39465
|
+
testCommand,
|
|
39466
|
+
timeoutSeconds,
|
|
39467
|
+
testOutput,
|
|
39468
|
+
promptPrefix,
|
|
39469
|
+
featureName,
|
|
39470
|
+
projectDir,
|
|
39471
|
+
testScopedTemplate,
|
|
39472
|
+
sessionId,
|
|
39473
|
+
runtime
|
|
39474
|
+
} = opts;
|
|
39475
|
+
const logger = getSafeLogger();
|
|
39476
|
+
const agentManager = opts.agentManager ?? _rectificationDeps.agentManager;
|
|
39477
|
+
if (!agentManager) {
|
|
39478
|
+
logger?.warn("rectification", "No agentManager threaded \u2014 skipping rectification loop", {
|
|
39479
|
+
storyId: story.id
|
|
39480
|
+
});
|
|
39481
|
+
return { succeeded: false, cost: 0, durationMs: 0 };
|
|
39482
|
+
}
|
|
39483
|
+
const rectificationConfig = config2.execution.rectification;
|
|
39484
|
+
const testSummary = parseTestOutput(testOutput);
|
|
39485
|
+
const label = promptPrefix ? "regression rectification" : "rectification";
|
|
39486
|
+
const rectificationSessionName = formatSessionName({
|
|
39487
|
+
workdir,
|
|
39488
|
+
featureName,
|
|
39489
|
+
storyId: story.id,
|
|
39490
|
+
role: "implementer"
|
|
39491
|
+
});
|
|
39492
|
+
let costAccum = 0;
|
|
39493
|
+
let currentAttempt = 0;
|
|
39494
|
+
let heldHandle;
|
|
39495
|
+
const initialFailure = {
|
|
39496
|
+
testOutput,
|
|
39497
|
+
testSummary
|
|
39498
|
+
};
|
|
39499
|
+
const outcome = await runRetryLoop({
|
|
39500
|
+
stage: "rectification",
|
|
39501
|
+
storyId: story.id,
|
|
39502
|
+
packageDir: workdir,
|
|
39503
|
+
maxAttempts: rectificationConfig.maxRetries,
|
|
39504
|
+
failure: initialFailure,
|
|
39505
|
+
previousAttempts: [],
|
|
39506
|
+
buildPrompt: (failure) => {
|
|
39507
|
+
currentAttempt++;
|
|
39508
|
+
const diagnosisPrefix = null;
|
|
39509
|
+
const debateStageConfig = config2.debate?.stages?.rectification;
|
|
39510
|
+
let debatePromise = Promise.resolve(null);
|
|
39511
|
+
if (debateStageConfig?.enabled) {
|
|
39512
|
+
const failureSummary = formatFailureSummary(failure.testSummary.failures);
|
|
39513
|
+
const diagnosisPrompt = `Analyze the following test failures and identify the root cause:
|
|
39514
|
+
|
|
39515
|
+
${failureSummary}`;
|
|
39516
|
+
debatePromise = (async () => {
|
|
39517
|
+
try {
|
|
39518
|
+
const debateResult = await _rectificationDeps.runDebate(story.id, debateStageConfig, diagnosisPrompt, config2, agentManager);
|
|
39519
|
+
if (debateResult.totalCostUsd > 0 && story.routing) {
|
|
39520
|
+
story.routing.estimatedCostUsd = (story.routing.estimatedCostUsd ?? 0) + debateResult.totalCostUsd;
|
|
39521
|
+
}
|
|
39522
|
+
if (debateResult.output !== null) {
|
|
39523
|
+
return `## Root Cause Analysis
|
|
39524
|
+
|
|
39525
|
+
${debateResult.output}`;
|
|
39526
|
+
}
|
|
39527
|
+
logger?.info("rectification", "debate diagnosis fallback \u2014 all debaters failed", {
|
|
39528
|
+
storyId: story.id,
|
|
39529
|
+
event: "fallback"
|
|
39530
|
+
});
|
|
39531
|
+
return null;
|
|
39532
|
+
} catch (_error) {
|
|
39533
|
+
logger?.info("rectification", "debate diagnosis fallback \u2014 debate threw error", {
|
|
39534
|
+
storyId: story.id,
|
|
39535
|
+
event: "fallback"
|
|
39536
|
+
});
|
|
39537
|
+
return null;
|
|
39538
|
+
}
|
|
39539
|
+
})();
|
|
39540
|
+
}
|
|
39541
|
+
const failureRecords = buildFailureRecords(failure.testSummary, failure.testOutput);
|
|
39542
|
+
const rectPrompt = RectifierPromptBuilder.regressionFailure({
|
|
39543
|
+
story,
|
|
39544
|
+
failures: failureRecords,
|
|
39545
|
+
testCommand,
|
|
39546
|
+
conventions: true
|
|
39547
|
+
});
|
|
39548
|
+
const rectPromise = Promise.resolve(rectPrompt);
|
|
39549
|
+
return (async () => {
|
|
39550
|
+
const [diagnosis, rectificationPrompt] = await Promise.all([debatePromise, rectPromise]);
|
|
39551
|
+
let finalPrompt = rectificationPrompt;
|
|
39552
|
+
if (diagnosis) {
|
|
39553
|
+
finalPrompt = `${diagnosis}
|
|
39554
|
+
|
|
39555
|
+
${finalPrompt}`;
|
|
39556
|
+
}
|
|
39557
|
+
if (promptPrefix) {
|
|
39558
|
+
finalPrompt = `${promptPrefix}
|
|
39559
|
+
|
|
39560
|
+
${finalPrompt}`;
|
|
39561
|
+
}
|
|
39562
|
+
return finalPrompt;
|
|
39563
|
+
})();
|
|
39564
|
+
},
|
|
39565
|
+
execute: async (prompt) => {
|
|
39566
|
+
const defaultAgent = agentManager.getDefault();
|
|
39567
|
+
const complexity = story.routing?.complexity ?? "medium";
|
|
39568
|
+
const modelTier = config2.autoMode.complexityRouting?.[complexity] || config2.autoMode.escalation.tierOrder[0]?.tier || "balanced";
|
|
39569
|
+
const modelDef = resolveModelForAgent(config2.models, story.routing?.agent ?? defaultAgent, modelTier, defaultAgent);
|
|
39570
|
+
let agentResult;
|
|
39571
|
+
{
|
|
39572
|
+
let transportRetries = 0;
|
|
39573
|
+
const maxTransportRetries = config2.execution?.sessionErrorRetryableMaxRetries ?? 3;
|
|
39574
|
+
while (true) {
|
|
39575
|
+
if (!heldHandle) {
|
|
39576
|
+
const existingHandle = runtime.sessionManager.getLiveHandle(rectificationSessionName);
|
|
39577
|
+
if (existingHandle && existingHandle.agentName === defaultAgent) {
|
|
39578
|
+
heldHandle = existingHandle;
|
|
39579
|
+
} else {
|
|
39580
|
+
heldHandle = await runtime.sessionManager.openSession(rectificationSessionName, {
|
|
39581
|
+
agentName: defaultAgent,
|
|
39582
|
+
role: "implementer",
|
|
39583
|
+
workdir,
|
|
39584
|
+
pipelineStage: "rectification",
|
|
39585
|
+
modelDef,
|
|
39586
|
+
timeoutSeconds: config2.execution.sessionTimeoutSeconds,
|
|
39587
|
+
featureName,
|
|
39588
|
+
storyId: story.id,
|
|
39589
|
+
signal: runtime.signal
|
|
39590
|
+
});
|
|
39591
|
+
}
|
|
39592
|
+
}
|
|
39593
|
+
try {
|
|
39594
|
+
const turn = await agentManager.runAsSession(defaultAgent, heldHandle, prompt, {
|
|
39595
|
+
storyId: story.id,
|
|
39596
|
+
featureName,
|
|
39597
|
+
workdir,
|
|
39598
|
+
projectDir,
|
|
39599
|
+
pipelineStage: "rectification",
|
|
39600
|
+
sessionRole: "implementer",
|
|
39601
|
+
signal: runtime.signal,
|
|
39602
|
+
maxTurns: config2.agent?.maxInteractionTurns
|
|
39603
|
+
});
|
|
39604
|
+
agentResult = {
|
|
39605
|
+
success: true,
|
|
39606
|
+
exitCode: 0,
|
|
39607
|
+
output: turn.output,
|
|
39608
|
+
rateLimited: false,
|
|
39609
|
+
durationMs: 0,
|
|
39610
|
+
estimatedCostUsd: turn.estimatedCostUsd,
|
|
39611
|
+
...turn.exactCostUsd !== undefined && { exactCostUsd: turn.exactCostUsd },
|
|
39612
|
+
...turn.tokenUsage && { tokenUsage: turn.tokenUsage },
|
|
39613
|
+
...heldHandle.protocolIds && { protocolIds: heldHandle.protocolIds }
|
|
39614
|
+
};
|
|
39615
|
+
break;
|
|
39616
|
+
} catch (err) {
|
|
39617
|
+
const stale = heldHandle;
|
|
39618
|
+
heldHandle = undefined;
|
|
39619
|
+
await runtime.sessionManager.closeSession(stale).catch(() => {});
|
|
39620
|
+
if (err instanceof SessionTurnError && err.retryable && transportRetries < maxTransportRetries) {
|
|
39621
|
+
transportRetries++;
|
|
39622
|
+
getSafeLogger()?.warn("rectification", "fail-adapter-error: same-agent retry with fresh session", {
|
|
39623
|
+
storyId: story.id,
|
|
39624
|
+
attempt: transportRetries,
|
|
39625
|
+
maxAttempts: maxTransportRetries,
|
|
39626
|
+
retriable: true
|
|
39627
|
+
});
|
|
39628
|
+
continue;
|
|
39629
|
+
}
|
|
39630
|
+
throw err;
|
|
39631
|
+
}
|
|
39632
|
+
}
|
|
39633
|
+
}
|
|
39634
|
+
costAccum += agentResult.estimatedCostUsd ?? 0;
|
|
39635
|
+
if (sessionId && agentResult.protocolIds) {
|
|
39636
|
+
try {
|
|
39637
|
+
runtime.sessionManager.bindHandle(sessionId, rectificationSessionName, agentResult.protocolIds);
|
|
39638
|
+
} catch {}
|
|
39639
|
+
}
|
|
39640
|
+
if (agentResult.success) {
|
|
39641
|
+
logger?.info("rectification", `Agent ${label} session complete`, {
|
|
39642
|
+
storyId: story.id,
|
|
39643
|
+
cost: agentResult.estimatedCostUsd
|
|
39644
|
+
});
|
|
39645
|
+
} else {
|
|
39646
|
+
logger?.warn("rectification", `Agent ${label} session failed`, {
|
|
39647
|
+
storyId: story.id,
|
|
39648
|
+
exitCode: agentResult.exitCode
|
|
39649
|
+
});
|
|
39650
|
+
}
|
|
39651
|
+
return {
|
|
39652
|
+
agentSuccess: agentResult.success,
|
|
39653
|
+
cost: agentResult.estimatedCostUsd ?? 0,
|
|
39654
|
+
protocolIds: agentResult.protocolIds
|
|
39655
|
+
};
|
|
39656
|
+
},
|
|
39657
|
+
shouldAbort: (failure) => {
|
|
39658
|
+
if (rectificationConfig.abortOnIncreasingFailures) {
|
|
39659
|
+
return failure.testSummary.failed > initialFailure.testSummary.failed;
|
|
39660
|
+
}
|
|
39661
|
+
return false;
|
|
39662
|
+
},
|
|
39663
|
+
verify: async (result) => {
|
|
39664
|
+
const retryVerification = await _rectificationDeps.runVerification({
|
|
39665
|
+
workdir,
|
|
39666
|
+
expectedFiles: getExpectedFiles(story),
|
|
39667
|
+
command: testCommand,
|
|
39668
|
+
timeoutSeconds,
|
|
39669
|
+
forceExit: config2.quality.forceExit,
|
|
39670
|
+
detectOpenHandles: config2.quality.detectOpenHandles,
|
|
39671
|
+
detectOpenHandlesRetries: config2.quality.detectOpenHandlesRetries,
|
|
39672
|
+
timeoutRetryCount: 0,
|
|
39673
|
+
gracePeriodMs: config2.quality.gracePeriodMs,
|
|
39674
|
+
drainTimeoutMs: config2.quality.drainTimeoutMs,
|
|
39675
|
+
shell: config2.quality.shell,
|
|
39676
|
+
stripEnvVars: config2.quality.stripEnvVars
|
|
39677
|
+
});
|
|
39678
|
+
if (retryVerification.success) {
|
|
39679
|
+
logger?.info("rectification", `[OK] ${label} succeeded!`, {
|
|
39680
|
+
storyId: story.id,
|
|
39681
|
+
attempt: currentAttempt,
|
|
39682
|
+
initialFailures: initialFailure.testSummary.failed
|
|
39683
|
+
});
|
|
39684
|
+
return { passed: true };
|
|
39685
|
+
}
|
|
39686
|
+
if (retryVerification.output) {
|
|
39687
|
+
const newTestSummary = parseTestOutput(retryVerification.output);
|
|
39688
|
+
if (newTestSummary.failed === 0 && retryVerification.status !== "ENVIRONMENTAL_FAILURE" && (retryVerification.status === "SUCCESS" || newTestSummary.passed > 0)) {
|
|
39689
|
+
logger?.info("rectification", `[OK] ${label} succeeded after parsing retry output`, {
|
|
39690
|
+
storyId: story.id,
|
|
39691
|
+
attempt: currentAttempt,
|
|
39692
|
+
initialFailures: initialFailure.testSummary.failed
|
|
39693
|
+
});
|
|
39694
|
+
return { passed: true };
|
|
39695
|
+
}
|
|
39696
|
+
const failingTests = newTestSummary.failures.slice(0, 10).map((failure) => failure.testName);
|
|
39697
|
+
const logData = {
|
|
39698
|
+
storyId: story.id,
|
|
39699
|
+
attempt: currentAttempt,
|
|
39700
|
+
remainingFailures: newTestSummary.failed,
|
|
39701
|
+
failingTests
|
|
39702
|
+
};
|
|
39703
|
+
if (newTestSummary.failures.length > 10 || newTestSummary.failures.length === 0 && newTestSummary.failed > 0) {
|
|
39704
|
+
logData.totalFailingTests = newTestSummary.failed;
|
|
39705
|
+
}
|
|
39706
|
+
logger?.warn("rectification", `${label} still failing after attempt`, logData);
|
|
39707
|
+
return {
|
|
39708
|
+
passed: false,
|
|
39709
|
+
newFailure: {
|
|
39710
|
+
testOutput: retryVerification.output,
|
|
39711
|
+
testSummary: newTestSummary
|
|
39712
|
+
}
|
|
39713
|
+
};
|
|
39714
|
+
}
|
|
39715
|
+
return {
|
|
39716
|
+
passed: false,
|
|
39717
|
+
newFailure: {
|
|
39718
|
+
testOutput: retryVerification.output ?? "",
|
|
39719
|
+
testSummary: initialFailure.testSummary
|
|
39720
|
+
}
|
|
39721
|
+
};
|
|
39722
|
+
}
|
|
39723
|
+
}).finally(async () => {
|
|
39724
|
+
if (heldHandle) {
|
|
39725
|
+
const stale = heldHandle;
|
|
39726
|
+
heldHandle = undefined;
|
|
39727
|
+
await runtime.sessionManager.closeSession(stale).catch(() => {});
|
|
39728
|
+
}
|
|
39729
|
+
});
|
|
39730
|
+
const succeeded = outcome.outcome === "fixed";
|
|
39731
|
+
if (outcome.outcome === "exhausted") {
|
|
39732
|
+
const finalFailure = outcome.finalFailure;
|
|
39733
|
+
const shouldEscalate = rectificationConfig.escalateOnExhaustion !== false && config2.autoMode?.escalation?.enabled === true && finalFailure.testSummary.failed > 0;
|
|
39734
|
+
if (shouldEscalate) {
|
|
39735
|
+
const complexity = story.routing?.complexity ?? "medium";
|
|
39736
|
+
const currentTier = config2.autoMode.complexityRouting?.[complexity] || config2.autoMode.escalation.tierOrder[0]?.tier || "balanced";
|
|
39737
|
+
const tierOrder = config2.autoMode.escalation.tierOrder;
|
|
39738
|
+
const escalationResult = _rectificationDeps.escalateTier(currentTier, tierOrder);
|
|
39739
|
+
const escalatedTier = escalationResult?.tier ?? null;
|
|
39740
|
+
const escalatedAgent = escalationResult?.agent;
|
|
39741
|
+
if (escalatedTier !== null) {
|
|
39742
|
+
const escalationManager = agentManager;
|
|
39743
|
+
const agentName = escalatedAgent ?? story.routing?.agent ?? escalationManager.getDefault();
|
|
39744
|
+
if (escalationManager.getAgent(agentName)) {
|
|
39745
|
+
const escalatedModelDef = resolveModelForAgent(config2.models, agentName, escalatedTier, escalationManager.getDefault());
|
|
39746
|
+
let escalationPrompt = RectifierPromptBuilder.escalated(finalFailure.testSummary.failures, story, outcome.attempts, currentTier, escalatedTier, rectificationConfig, testCommand, testScopedTemplate);
|
|
39747
|
+
if (promptPrefix) {
|
|
39748
|
+
escalationPrompt = `${promptPrefix}
|
|
39749
|
+
|
|
39750
|
+
${escalationPrompt}`;
|
|
39751
|
+
}
|
|
39752
|
+
const escalationRunResult = await escalationManager.runAs(agentName, {
|
|
39753
|
+
runOptions: {
|
|
39754
|
+
prompt: escalationPrompt,
|
|
39755
|
+
workdir,
|
|
39756
|
+
modelTier: escalatedTier,
|
|
39757
|
+
modelDef: escalatedModelDef,
|
|
39758
|
+
timeoutSeconds: config2.execution.sessionTimeoutSeconds,
|
|
39759
|
+
pipelineStage: "rectification",
|
|
39760
|
+
config: config2,
|
|
39761
|
+
projectDir,
|
|
39762
|
+
maxInteractionTurns: config2.agent?.maxInteractionTurns,
|
|
39763
|
+
featureName,
|
|
39764
|
+
storyId: story.id,
|
|
39765
|
+
sessionRole: "implementer"
|
|
39766
|
+
}
|
|
39767
|
+
});
|
|
39768
|
+
costAccum += escalationRunResult.estimatedCostUsd ?? 0;
|
|
39769
|
+
logger?.info("rectification", "escalated rectification attempt cost", {
|
|
39770
|
+
storyId: story.id,
|
|
39771
|
+
escalatedTier,
|
|
39772
|
+
cost: escalationRunResult.estimatedCostUsd
|
|
39773
|
+
});
|
|
39774
|
+
const escalationVerification = await _rectificationDeps.runVerification({
|
|
39775
|
+
workdir,
|
|
39776
|
+
expectedFiles: getExpectedFiles(story),
|
|
39777
|
+
command: testCommand,
|
|
39778
|
+
timeoutSeconds,
|
|
39779
|
+
forceExit: config2.quality.forceExit,
|
|
39780
|
+
detectOpenHandles: config2.quality.detectOpenHandles,
|
|
39781
|
+
detectOpenHandlesRetries: config2.quality.detectOpenHandlesRetries,
|
|
39782
|
+
timeoutRetryCount: 0,
|
|
39783
|
+
gracePeriodMs: config2.quality.gracePeriodMs,
|
|
39784
|
+
drainTimeoutMs: config2.quality.drainTimeoutMs,
|
|
39785
|
+
shell: config2.quality.shell,
|
|
39786
|
+
stripEnvVars: config2.quality.stripEnvVars
|
|
39787
|
+
});
|
|
39788
|
+
if (escalationVerification.success) {
|
|
39789
|
+
logger?.info("rectification", `${label} escalated from ${currentTier} to ${escalatedTier} and succeeded`, {
|
|
39790
|
+
storyId: story.id,
|
|
39791
|
+
currentTier,
|
|
39792
|
+
escalatedTier
|
|
39793
|
+
});
|
|
39794
|
+
return { succeeded: true, cost: costAccum, durationMs: Date.now() - loopStartMs };
|
|
39795
|
+
}
|
|
39796
|
+
logger?.warn("rectification", "escalated rectification also failed", { storyId: story.id, escalatedTier });
|
|
39797
|
+
}
|
|
39798
|
+
}
|
|
39799
|
+
}
|
|
39800
|
+
logger?.warn("rectification", `${label} exhausted max retries`, {
|
|
39801
|
+
storyId: story.id,
|
|
39802
|
+
attempts: outcome.attempts,
|
|
39803
|
+
remainingFailures: initialFailure.testSummary.failed
|
|
39804
|
+
});
|
|
39805
|
+
}
|
|
39806
|
+
return { succeeded, cost: costAccum, durationMs: Date.now() - loopStartMs };
|
|
39807
|
+
}
|
|
39808
|
+
var _rectificationDeps;
|
|
39809
|
+
var init_rectification_loop = __esm(() => {
|
|
39810
|
+
init_agents();
|
|
39811
|
+
init_cost();
|
|
39812
|
+
init_types3();
|
|
39813
|
+
init_config();
|
|
39814
|
+
init_logger2();
|
|
39815
|
+
init_prd();
|
|
39816
|
+
init_prompts();
|
|
39817
|
+
init_naming();
|
|
39818
|
+
init_parser2();
|
|
39819
|
+
init_parser2();
|
|
39820
|
+
init_runners();
|
|
39821
|
+
_rectificationDeps = {
|
|
39822
|
+
agentManager: undefined,
|
|
39823
|
+
runVerification: fullSuite,
|
|
39824
|
+
escalateTier,
|
|
39825
|
+
runDebate: _defaultRunDebate
|
|
39826
|
+
};
|
|
39827
|
+
});
|
|
39828
|
+
|
|
39293
39829
|
// src/verification/index.ts
|
|
39294
39830
|
var init_verification = __esm(() => {
|
|
39831
|
+
init_rectification_loop();
|
|
39295
39832
|
init_executor();
|
|
39296
39833
|
init_parser2();
|
|
39297
39834
|
init_runners();
|
|
@@ -40856,7 +41393,7 @@ function buildHopCallback(ctx, sessionId, _initialOptions) {
|
|
|
40856
41393
|
prompt
|
|
40857
41394
|
};
|
|
40858
41395
|
} finally {
|
|
40859
|
-
if (hopKind.kind !== "stale-retry") {
|
|
41396
|
+
if (hopKind.kind !== "stale-retry" && !resolvedRunOptions.keepOpen) {
|
|
40860
41397
|
await sessionManager.closeSession(handle);
|
|
40861
41398
|
}
|
|
40862
41399
|
}
|
|
@@ -41044,6 +41581,7 @@ async function callOp(ctx, op, input) {
|
|
|
41044
41581
|
featureName: ctx.featureName,
|
|
41045
41582
|
storyId: ctx.storyId,
|
|
41046
41583
|
callId,
|
|
41584
|
+
...runOp.session.lifetime === "warm" ? { keepOpen: true } : {},
|
|
41047
41585
|
...ctx.scopeId !== undefined ? { scopeId: ctx.scopeId } : {},
|
|
41048
41586
|
...ctx.interactionBridge ? { interactionBridge: ctx.interactionBridge } : {},
|
|
41049
41587
|
...ctx.maxInteractionTurns !== undefined ? { maxInteractionTurns: ctx.maxInteractionTurns } : {}
|
|
@@ -42861,15 +43399,6 @@ var init_manager_sweep = __esm(() => {
|
|
|
42861
43399
|
DEFAULT_ORPHAN_TTL_MS = 4 * 60 * 60 * 1000;
|
|
42862
43400
|
});
|
|
42863
43401
|
|
|
42864
|
-
// src/session/naming.ts
|
|
42865
|
-
var exports_naming = {};
|
|
42866
|
-
__export(exports_naming, {
|
|
42867
|
-
formatSessionName: () => formatSessionName
|
|
42868
|
-
});
|
|
42869
|
-
var init_naming = __esm(() => {
|
|
42870
|
-
init_session_name();
|
|
42871
|
-
});
|
|
42872
|
-
|
|
42873
43402
|
// src/session/types.ts
|
|
42874
43403
|
var SESSION_TRANSITIONS;
|
|
42875
43404
|
var init_types7 = __esm(() => {
|
|
@@ -45211,7 +45740,11 @@ async function runPlan(ctx, taskContext, outputFormat, opts) {
|
|
|
45211
45740
|
const proposalBarriers = resolved.map(() => Promise.withResolvers());
|
|
45212
45741
|
const rebutBuilder = new DebatePromptBuilder({ taskContext, outputFormat: "", stage: "plan" }, { debaters: resolved.map((e) => e.debater), sessionMode: "stateful" });
|
|
45213
45742
|
const callOpPromises = resolved.map(({ debater, agentName }, index) => {
|
|
45214
|
-
const debaterCtx = {
|
|
45743
|
+
const debaterCtx = {
|
|
45744
|
+
...ctx.callContext,
|
|
45745
|
+
agentName,
|
|
45746
|
+
sessionOverride: { role: `debate-plan-${index}` }
|
|
45747
|
+
};
|
|
45215
45748
|
return callOp(debaterCtx, planDebaterOp, {
|
|
45216
45749
|
debater,
|
|
45217
45750
|
index,
|
|
@@ -45276,7 +45809,11 @@ async function runPlan(ctx, taskContext, outputFormat, opts) {
|
|
|
45276
45809
|
const rebuttalBarriers = resolved.map(() => Promise.withResolvers());
|
|
45277
45810
|
const rebutBuilder = new DebatePromptBuilder({ taskContext, outputFormat: "", stage: "plan" }, { debaters: resolved.map((e) => e.debater), sessionMode: "stateful" });
|
|
45278
45811
|
const callOpPromisesB = resolved.map(({ debater, agentName }, index) => {
|
|
45279
|
-
const debaterCtx = {
|
|
45812
|
+
const debaterCtx = {
|
|
45813
|
+
...ctx.callContext,
|
|
45814
|
+
agentName,
|
|
45815
|
+
sessionOverride: { role: `debate-plan-${index}` }
|
|
45816
|
+
};
|
|
45280
45817
|
return callOp(debaterCtx, planDebaterOp, {
|
|
45281
45818
|
debater,
|
|
45282
45819
|
index,
|
|
@@ -45335,7 +45872,11 @@ async function runPlan(ctx, taskContext, outputFormat, opts) {
|
|
|
45335
45872
|
for (const barrier of rebuttalBarriersC)
|
|
45336
45873
|
barrier.resolve("");
|
|
45337
45874
|
const settled = await allSettledBounded(resolved.map(({ debater, agentName }, index) => async () => {
|
|
45338
|
-
const debaterCtx = {
|
|
45875
|
+
const debaterCtx = {
|
|
45876
|
+
...ctx.callContext,
|
|
45877
|
+
agentName,
|
|
45878
|
+
sessionOverride: { role: `debate-plan-${index}` }
|
|
45879
|
+
};
|
|
45339
45880
|
const result = await callOp(debaterCtx, planDebaterOp, {
|
|
45340
45881
|
debater,
|
|
45341
45882
|
index,
|
|
@@ -50459,42 +51000,8 @@ var init_greenfield = __esm(() => {
|
|
|
50459
51000
|
]);
|
|
50460
51001
|
});
|
|
50461
51002
|
|
|
50462
|
-
// src/verification/failure-records.ts
|
|
50463
|
-
function truncateUnmappedFailureOutput(output) {
|
|
50464
|
-
const tailLines = output.split(`
|
|
50465
|
-
`).slice(-UNMAPPED_FAILURE_OUTPUT_MAX_LINES).join(`
|
|
50466
|
-
`);
|
|
50467
|
-
if (tailLines.length <= UNMAPPED_FAILURE_OUTPUT_MAX_CHARS) {
|
|
50468
|
-
return tailLines;
|
|
50469
|
-
}
|
|
50470
|
-
return `... (truncated)
|
|
50471
|
-
${tailLines.slice(-UNMAPPED_FAILURE_OUTPUT_MAX_CHARS)}`;
|
|
50472
|
-
}
|
|
50473
|
-
function buildFailureRecords(testSummary, rawOutput) {
|
|
50474
|
-
if (testSummary.failures.length > 0) {
|
|
50475
|
-
return testSummary.failures.map((failure) => ({
|
|
50476
|
-
test: failure.testName,
|
|
50477
|
-
file: failure.file,
|
|
50478
|
-
message: failure.error,
|
|
50479
|
-
output: failure.stackTrace.length > 0 ? failure.stackTrace.join(`
|
|
50480
|
-
`) : undefined
|
|
50481
|
-
}));
|
|
50482
|
-
}
|
|
50483
|
-
if (testSummary.failed === 0) {
|
|
50484
|
-
return [];
|
|
50485
|
-
}
|
|
50486
|
-
return [
|
|
50487
|
-
{
|
|
50488
|
-
test: `Unmapped test failures (${testSummary.failed} detected)`,
|
|
50489
|
-
message: "Structured test failure parsing returned no failure records. Diagnose the regression from the raw test output.",
|
|
50490
|
-
output: rawOutput?.trim() ? truncateUnmappedFailureOutput(rawOutput.trim()) : undefined
|
|
50491
|
-
}
|
|
50492
|
-
];
|
|
50493
|
-
}
|
|
50494
|
-
var UNMAPPED_FAILURE_OUTPUT_MAX_LINES = 200, UNMAPPED_FAILURE_OUTPUT_MAX_CHARS = 8000;
|
|
50495
|
-
|
|
50496
51003
|
// src/tdd/rectification-gate.ts
|
|
50497
|
-
async function runFullSuiteGate(story, config2, workdir, agentManager, implementerTier, lite, logger, featureName, projectDir, sessionManager,
|
|
51004
|
+
async function runFullSuiteGate(story, config2, workdir, agentManager, implementerTier, lite, logger, featureName, projectDir, sessionManager, runtime) {
|
|
50498
51005
|
const rectificationEnabled = config2.execution.rectification?.enabled ?? false;
|
|
50499
51006
|
if (!rectificationEnabled) {
|
|
50500
51007
|
return { passed: false, cost: 0, fullSuiteGatePassed: false, status: "disabled" };
|
|
@@ -50522,16 +51029,16 @@ async function runFullSuiteGate(story, config2, workdir, agentManager, implement
|
|
|
50522
51029
|
});
|
|
50523
51030
|
return { passed: true, cost: 0, fullSuiteGatePassed: false, status: "deferred-unattributable" };
|
|
50524
51031
|
}
|
|
50525
|
-
return await
|
|
51032
|
+
return await runRectificationLoop2(story, config2, workdir, agentManager, implementerTier, lite, logger, testSummary, rectificationConfig, effectiveTestCmd, fullSuiteTimeout, fullSuiteResult.output, runtime, featureName, projectDir, sessionManager);
|
|
50526
51033
|
}
|
|
50527
51034
|
if (testSummary.failures.length > 0) {
|
|
50528
|
-
logger.warn("tdd", "Full suite gate: parser counter mismatch \u2014
|
|
51035
|
+
logger.warn("tdd", "Full suite gate: parser counter mismatch \u2014 failing gate (unreliable failure count)", {
|
|
50529
51036
|
storyId: story.id,
|
|
50530
51037
|
failedCounter: testSummary.failed,
|
|
50531
51038
|
failuresLength: testSummary.failures.length,
|
|
50532
51039
|
exitCode: fullSuiteResult.exitCode
|
|
50533
51040
|
});
|
|
50534
|
-
return
|
|
51041
|
+
return { passed: false, cost: 0, fullSuiteGatePassed: false, status: "execution-failed" };
|
|
50535
51042
|
}
|
|
50536
51043
|
if (testSummary.passed > 0) {
|
|
50537
51044
|
logger.info("tdd", "Full suite gate passed (non-zero exit, 0 failures, tests detected)", {
|
|
@@ -50559,7 +51066,7 @@ async function runFullSuiteGate(story, config2, workdir, agentManager, implement
|
|
|
50559
51066
|
});
|
|
50560
51067
|
return { passed: false, cost: 0, fullSuiteGatePassed: false, status: "execution-failed" };
|
|
50561
51068
|
}
|
|
50562
|
-
async function
|
|
51069
|
+
async function runRectificationLoop2(story, config2, workdir, agentManager, implementerTier, lite, logger, testSummary, rectificationConfig, testCmd, fullSuiteTimeout, testOutput, runtime, featureName, projectDir, sessionManager) {
|
|
50563
51070
|
logger.warn("tdd", "Full suite gate detected regressions", {
|
|
50564
51071
|
storyId: story.id,
|
|
50565
51072
|
failedTests: testSummary.failed,
|
|
@@ -50597,7 +51104,6 @@ async function runRectificationLoop(story, config2, workdir, agentManager, imple
|
|
|
50597
51104
|
},
|
|
50598
51105
|
execute: async (prompt) => {
|
|
50599
51106
|
currentAttempt++;
|
|
50600
|
-
const isLastAttempt = currentAttempt >= rectificationConfig.maxRetries;
|
|
50601
51107
|
const rectifyBeforeRef = await captureGitRef(workdir) ?? "HEAD";
|
|
50602
51108
|
const defaultAgent = agentManager.getDefault();
|
|
50603
51109
|
const runOptions = {
|
|
@@ -50615,11 +51121,14 @@ async function runRectificationLoop(story, config2, workdir, agentManager, imple
|
|
|
50615
51121
|
sessionRole: "implementer"
|
|
50616
51122
|
};
|
|
50617
51123
|
let rectifyResult;
|
|
50618
|
-
|
|
50619
|
-
|
|
50620
|
-
|
|
50621
|
-
|
|
50622
|
-
|
|
51124
|
+
let transportRetries = 0;
|
|
51125
|
+
const maxTransportRetries = config2.execution?.sessionErrorRetryableMaxRetries ?? 3;
|
|
51126
|
+
while (true) {
|
|
51127
|
+
if (!heldHandle) {
|
|
51128
|
+
const existingHandle = sessionManager?.getLiveHandle(rectificationSessionName);
|
|
51129
|
+
if (existingHandle && existingHandle.agentName === defaultAgent) {
|
|
51130
|
+
heldHandle = existingHandle;
|
|
51131
|
+
} else {
|
|
50623
51132
|
heldHandle = await runtime.sessionManager.openSession(rectificationSessionName, {
|
|
50624
51133
|
agentName: defaultAgent,
|
|
50625
51134
|
role: "implementer",
|
|
@@ -50632,54 +51141,50 @@ async function runRectificationLoop(story, config2, workdir, agentManager, imple
|
|
|
50632
51141
|
signal: runtime.signal
|
|
50633
51142
|
});
|
|
50634
51143
|
}
|
|
50635
|
-
|
|
50636
|
-
|
|
51144
|
+
}
|
|
51145
|
+
try {
|
|
51146
|
+
const turn = await agentManager.runAsSession(defaultAgent, heldHandle, prompt, {
|
|
51147
|
+
storyId: story.id,
|
|
51148
|
+
featureName,
|
|
51149
|
+
workdir,
|
|
51150
|
+
projectDir,
|
|
51151
|
+
pipelineStage: "rectification",
|
|
51152
|
+
sessionRole: "implementer",
|
|
51153
|
+
signal: runtime.signal,
|
|
51154
|
+
maxTurns: config2.agent?.maxInteractionTurns
|
|
51155
|
+
});
|
|
51156
|
+
rectifyResult = {
|
|
51157
|
+
success: true,
|
|
51158
|
+
exitCode: 0,
|
|
51159
|
+
output: turn.output,
|
|
51160
|
+
rateLimited: false,
|
|
51161
|
+
durationMs: 0,
|
|
51162
|
+
estimatedCostUsd: turn.estimatedCostUsd,
|
|
51163
|
+
...turn.exactCostUsd !== undefined && { exactCostUsd: turn.exactCostUsd },
|
|
51164
|
+
...turn.tokenUsage && { tokenUsage: turn.tokenUsage },
|
|
51165
|
+
...heldHandle.protocolIds && { protocolIds: heldHandle.protocolIds }
|
|
51166
|
+
};
|
|
51167
|
+
break;
|
|
51168
|
+
} catch (err) {
|
|
51169
|
+
const stale = heldHandle;
|
|
51170
|
+
heldHandle = undefined;
|
|
51171
|
+
await runtime.sessionManager.closeSession(stale).catch(() => {});
|
|
51172
|
+
if (err instanceof SessionTurnError && err.retryable && transportRetries < maxTransportRetries) {
|
|
51173
|
+
transportRetries++;
|
|
51174
|
+
getSafeLogger()?.warn("tdd", "fail-adapter-error: same-agent retry with fresh session", {
|
|
50637
51175
|
storyId: story.id,
|
|
50638
|
-
|
|
50639
|
-
|
|
50640
|
-
|
|
50641
|
-
pipelineStage: "rectification",
|
|
50642
|
-
sessionRole: "implementer",
|
|
50643
|
-
signal: runtime.signal,
|
|
50644
|
-
maxTurns: config2.agent?.maxInteractionTurns
|
|
51176
|
+
attempt: transportRetries,
|
|
51177
|
+
maxAttempts: maxTransportRetries,
|
|
51178
|
+
retriable: true
|
|
50645
51179
|
});
|
|
50646
|
-
|
|
50647
|
-
success: true,
|
|
50648
|
-
exitCode: 0,
|
|
50649
|
-
output: turn.output,
|
|
50650
|
-
rateLimited: false,
|
|
50651
|
-
durationMs: 0,
|
|
50652
|
-
estimatedCostUsd: turn.estimatedCostUsd,
|
|
50653
|
-
...turn.exactCostUsd !== undefined && { exactCostUsd: turn.exactCostUsd },
|
|
50654
|
-
...turn.tokenUsage && { tokenUsage: turn.tokenUsage },
|
|
50655
|
-
...heldHandle.protocolIds && { protocolIds: heldHandle.protocolIds }
|
|
50656
|
-
};
|
|
50657
|
-
break;
|
|
50658
|
-
} catch (err) {
|
|
50659
|
-
const stale = heldHandle;
|
|
50660
|
-
heldHandle = undefined;
|
|
50661
|
-
await runtime.sessionManager.closeSession(stale).catch(() => {});
|
|
50662
|
-
if (err instanceof SessionTurnError && err.retryable && transportRetries < maxTransportRetries) {
|
|
50663
|
-
transportRetries++;
|
|
50664
|
-
getSafeLogger()?.warn("tdd", "fail-adapter-error: same-agent retry with fresh session", {
|
|
50665
|
-
storyId: story.id,
|
|
50666
|
-
attempt: transportRetries,
|
|
50667
|
-
maxAttempts: maxTransportRetries,
|
|
50668
|
-
retriable: true
|
|
50669
|
-
});
|
|
50670
|
-
continue;
|
|
50671
|
-
}
|
|
50672
|
-
throw err;
|
|
51180
|
+
continue;
|
|
50673
51181
|
}
|
|
51182
|
+
throw err;
|
|
50674
51183
|
}
|
|
50675
|
-
} else {
|
|
50676
|
-
rectifyResult = await agentManager.run({
|
|
50677
|
-
runOptions: { ...runOptions, keepOpen: !isLastAttempt }
|
|
50678
|
-
});
|
|
50679
51184
|
}
|
|
50680
|
-
if (sessionManager &&
|
|
51185
|
+
if (sessionManager && heldHandle && rectifyResult.protocolIds) {
|
|
50681
51186
|
try {
|
|
50682
|
-
sessionManager.bindHandle(
|
|
51187
|
+
sessionManager.bindHandle(heldHandle.id, rectificationSessionName, rectifyResult.protocolIds);
|
|
50683
51188
|
} catch {}
|
|
50684
51189
|
}
|
|
50685
51190
|
if (!rectifyResult.success && rectifyResult.pid) {
|
|
@@ -50745,7 +51250,7 @@ async function runRectificationLoop(story, config2, workdir, agentManager, imple
|
|
|
50745
51250
|
};
|
|
50746
51251
|
}
|
|
50747
51252
|
}).finally(async () => {
|
|
50748
|
-
if (heldHandle
|
|
51253
|
+
if (heldHandle) {
|
|
50749
51254
|
const stale = heldHandle;
|
|
50750
51255
|
heldHandle = undefined;
|
|
50751
51256
|
await runtime.sessionManager.closeSession(stale).catch(() => {});
|
|
@@ -51236,7 +51741,7 @@ async function runThreeSessionTdd(options) {
|
|
|
51236
51741
|
};
|
|
51237
51742
|
}
|
|
51238
51743
|
const implementerBinding = getTddSessionBinding?.("implementer");
|
|
51239
|
-
const fullSuiteGate = await runFullSuiteGate(story, config2, workdir, agentManager, implementerTier, lite, logger, featureName, projectDir, implementerBinding?.sessionManager,
|
|
51744
|
+
const fullSuiteGate = await runFullSuiteGate(story, config2, workdir, agentManager, implementerTier, lite, logger, featureName, projectDir, implementerBinding?.sessionManager, runtime);
|
|
51240
51745
|
const { cost: fullSuiteGateCost, fullSuiteGatePassed } = fullSuiteGate;
|
|
51241
51746
|
if (fullSuiteGate.status === "rectification-exhausted") {
|
|
51242
51747
|
const failureCategory = "full-suite-gate-exhausted";
|
|
@@ -51522,6 +52027,7 @@ var init_tdd = __esm(() => {
|
|
|
51522
52027
|
init_isolation();
|
|
51523
52028
|
init_orchestrator3();
|
|
51524
52029
|
init_orchestrator_ctx();
|
|
52030
|
+
init_rectification_gate();
|
|
51525
52031
|
init_session_op();
|
|
51526
52032
|
init_cleanup();
|
|
51527
52033
|
init_verdict();
|
|
@@ -51936,9 +52442,9 @@ async function runAgentRectificationV2(ctx, _lintFixCmd, _formatFixCmd, _effecti
|
|
|
51936
52442
|
maxAttemptsTotal: maxTotalAttempts,
|
|
51937
52443
|
validatorRetries: 1
|
|
51938
52444
|
},
|
|
51939
|
-
async validate(_cycleCtx) {
|
|
52445
|
+
async validate(_cycleCtx, _opts) {
|
|
51940
52446
|
iterationBeforeRef = await _autofixCycleGuardDeps.captureGitRef(ctx.workdir) ?? iterationBeforeRef;
|
|
51941
|
-
await _autofixDeps.recheckReview(ctx);
|
|
52447
|
+
await _autofixDeps.recheckReview(ctx, { lite: _opts.mode === "lite" });
|
|
51942
52448
|
const fresh = collectCurrentFindings(ctx);
|
|
51943
52449
|
const pending = ctx.testEditDeclarations ?? [];
|
|
51944
52450
|
if (pending.length === 0)
|
|
@@ -52734,7 +53240,7 @@ var init_review2 = __esm(() => {
|
|
|
52734
53240
|
const reviewDebateEnabled = ctx.rootConfig?.debate?.enabled && ctx.rootConfig?.debate?.stages?.review?.enabled;
|
|
52735
53241
|
const dialogueEnabled = ctx.config.review?.dialogue?.enabled ?? false;
|
|
52736
53242
|
logger.info("review", "Running review phase", { storyId: ctx.story.id });
|
|
52737
|
-
if (dialogueEnabled && !reviewDebateEnabled && ctx.reviewerSession) {
|
|
53243
|
+
if (dialogueEnabled && !reviewDebateEnabled && ctx.reviewerSession && !ctx.skipLLMReviewers) {
|
|
52738
53244
|
try {
|
|
52739
53245
|
const diff = ctx.storyGitRef ?? "";
|
|
52740
53246
|
const reReviewResult = await ctx.reviewerSession.reReview(diff);
|
|
@@ -52769,7 +53275,7 @@ var init_review2 = __esm(() => {
|
|
|
52769
53275
|
});
|
|
52770
53276
|
}
|
|
52771
53277
|
}
|
|
52772
|
-
if (dialogueEnabled && !ctx.reviewerSession && ctx.agentManager && ctx.sessionManager) {
|
|
53278
|
+
if (dialogueEnabled && !ctx.reviewerSession && ctx.agentManager && ctx.sessionManager && !ctx.skipLLMReviewers) {
|
|
52773
53279
|
ctx.reviewerSession = _reviewDeps.createReviewerSession(ctx.agentManager, ctx.sessionManager, ctx.story.id, ctx.workdir, ctx.prd.feature ?? "", ctx.config);
|
|
52774
53280
|
if (!reviewDebateEnabled) {
|
|
52775
53281
|
const semanticConfig = ctx.config.review?.semantic;
|
|
@@ -52873,16 +53379,36 @@ var init_review2 = __esm(() => {
|
|
|
52873
53379
|
});
|
|
52874
53380
|
|
|
52875
53381
|
// src/pipeline/stages/autofix.ts
|
|
52876
|
-
async function recheckReview(ctx) {
|
|
53382
|
+
async function recheckReview(ctx, opts) {
|
|
53383
|
+
const lite = opts?.lite === true;
|
|
53384
|
+
if (lite) {
|
|
53385
|
+
const origSkipChecks = ctx.retrySkipChecks;
|
|
53386
|
+
const origSkipLLMReviewers = ctx.skipLLMReviewers;
|
|
53387
|
+
ctx.retrySkipChecks = new Set([...ctx.retrySkipChecks ?? [], "adversarial", "semantic"]);
|
|
53388
|
+
ctx.skipLLMReviewers = true;
|
|
53389
|
+
try {
|
|
53390
|
+
await _autofixDeps.runReviewStage(ctx);
|
|
53391
|
+
} finally {
|
|
53392
|
+
ctx.retrySkipChecks = origSkipChecks;
|
|
53393
|
+
ctx.skipLLMReviewers = origSkipLLMReviewers;
|
|
53394
|
+
}
|
|
53395
|
+
return ctx.reviewResult?.success === true;
|
|
53396
|
+
}
|
|
52877
53397
|
const { reviewStage: reviewStage2 } = await Promise.resolve().then(() => (init_review2(), exports_review));
|
|
52878
53398
|
if (!reviewStage2.enabled(ctx))
|
|
52879
53399
|
return true;
|
|
52880
|
-
await
|
|
53400
|
+
await _autofixDeps.runReviewStage(ctx);
|
|
52881
53401
|
const hasFailOpen = (ctx.reviewResult?.checks ?? []).some((c) => c.failOpen);
|
|
52882
53402
|
if (hasFailOpen)
|
|
52883
53403
|
return false;
|
|
52884
53404
|
return ctx.reviewResult?.success === true;
|
|
52885
53405
|
}
|
|
53406
|
+
async function runReviewStage(ctx) {
|
|
53407
|
+
const { reviewStage: reviewStage2 } = await Promise.resolve().then(() => (init_review2(), exports_review));
|
|
53408
|
+
if (!reviewStage2.enabled(ctx))
|
|
53409
|
+
return;
|
|
53410
|
+
await reviewStage2.execute(ctx);
|
|
53411
|
+
}
|
|
52886
53412
|
async function runMechanicalFixes(ctx, failedCheckNames) {
|
|
52887
53413
|
const commands = resolveMechanicalFixCommands(ctx, failedCheckNames);
|
|
52888
53414
|
for (const resolved of commands) {
|
|
@@ -53146,6 +53672,7 @@ var init_autofix = __esm(() => {
|
|
|
53146
53672
|
runQualityCommand,
|
|
53147
53673
|
recheckReview,
|
|
53148
53674
|
runAgentRectification: runAgentRectificationV2,
|
|
53675
|
+
runReviewStage,
|
|
53149
53676
|
runTestWriterRectification: (ctx, testWriterChecks, story, agentManager) => runTestWriterRectification(ctx, testWriterChecks, story, agentManager)
|
|
53150
53677
|
};
|
|
53151
53678
|
});
|
|
@@ -54780,455 +55307,6 @@ var init_queue_check = __esm(() => {
|
|
|
54780
55307
|
};
|
|
54781
55308
|
});
|
|
54782
55309
|
|
|
54783
|
-
// src/execution/escalation/escalation.ts
|
|
54784
|
-
function escalateTier(currentTier, tierOrder) {
|
|
54785
|
-
const getName = (t) => t.tier ?? t.name ?? null;
|
|
54786
|
-
const currentIndex = tierOrder.findIndex((t) => getName(t) === currentTier);
|
|
54787
|
-
if (currentIndex === -1 || currentIndex === tierOrder.length - 1) {
|
|
54788
|
-
return null;
|
|
54789
|
-
}
|
|
54790
|
-
const next = tierOrder[currentIndex + 1];
|
|
54791
|
-
const nextName = getName(next);
|
|
54792
|
-
if (!nextName)
|
|
54793
|
-
return null;
|
|
54794
|
-
return { tier: nextName, agent: next.agent };
|
|
54795
|
-
}
|
|
54796
|
-
function calculateMaxIterations(tierOrder) {
|
|
54797
|
-
return tierOrder.reduce((sum, t) => sum + t.attempts, 0);
|
|
54798
|
-
}
|
|
54799
|
-
|
|
54800
|
-
// src/verification/rectification-loop.ts
|
|
54801
|
-
async function _defaultRunDebate(storyId, stageConfig, prompt, config2, agentManager) {
|
|
54802
|
-
const logger = getSafeLogger();
|
|
54803
|
-
const debaters = stageConfig.debaters ?? [];
|
|
54804
|
-
const manager = agentManager;
|
|
54805
|
-
const resolved = [];
|
|
54806
|
-
for (const debater of debaters) {
|
|
54807
|
-
if (manager.getAgent(debater.agent)) {
|
|
54808
|
-
resolved.push({ debater, agentName: debater.agent });
|
|
54809
|
-
}
|
|
54810
|
-
}
|
|
54811
|
-
if (resolved.length === 0) {
|
|
54812
|
-
return { output: null, totalCostUsd: 0 };
|
|
54813
|
-
}
|
|
54814
|
-
const timeoutMs = (config2.execution?.sessionTimeoutSeconds ?? 600) * 1000;
|
|
54815
|
-
const defaultAgentName = resolveDefaultAgent(config2);
|
|
54816
|
-
const resolvedDebaters = resolved.map(({ debater, agentName }) => {
|
|
54817
|
-
let modelDef;
|
|
54818
|
-
try {
|
|
54819
|
-
modelDef = resolveConfiguredModel(config2.models, agentName, debater.model ?? "balanced", defaultAgentName).modelDef;
|
|
54820
|
-
} catch {
|
|
54821
|
-
modelDef = { provider: "unknown", model: debater.model ?? "default" };
|
|
54822
|
-
}
|
|
54823
|
-
return { debater, agentName, modelDef };
|
|
54824
|
-
});
|
|
54825
|
-
const startMs = Date.now();
|
|
54826
|
-
const proposalSettled = await Promise.allSettled(resolvedDebaters.map(({ agentName, modelDef }) => manager.completeAs(agentName, prompt, {
|
|
54827
|
-
modelDef,
|
|
54828
|
-
workdir: "",
|
|
54829
|
-
storyId,
|
|
54830
|
-
sessionRole: "debate-proposal",
|
|
54831
|
-
timeoutMs
|
|
54832
|
-
}).then((out) => typeof out === "string" ? out : out.output)));
|
|
54833
|
-
const durationMs = Date.now() - startMs;
|
|
54834
|
-
const successful = proposalSettled.filter((r) => r.status === "fulfilled").map((r) => r.value);
|
|
54835
|
-
if (successful.length === 0) {
|
|
54836
|
-
return { output: null, totalCostUsd: 0 };
|
|
54837
|
-
}
|
|
54838
|
-
const successCount = successful.length;
|
|
54839
|
-
const costPerDebater = estimateCostByDuration("balanced", durationMs / successCount);
|
|
54840
|
-
const totalCostUsd = costPerDebater.cost * successCount;
|
|
54841
|
-
logger?.debug("rectification", "debate diagnosis complete", { storyId, successCount, totalCostUsd });
|
|
54842
|
-
const output = successful.join(`
|
|
54843
|
-
|
|
54844
|
-
`);
|
|
54845
|
-
return { output, totalCostUsd };
|
|
54846
|
-
}
|
|
54847
|
-
async function runRectificationLoop2(opts) {
|
|
54848
|
-
const loopStartMs = Date.now();
|
|
54849
|
-
const {
|
|
54850
|
-
config: config2,
|
|
54851
|
-
workdir,
|
|
54852
|
-
story,
|
|
54853
|
-
testCommand,
|
|
54854
|
-
timeoutSeconds,
|
|
54855
|
-
testOutput,
|
|
54856
|
-
promptPrefix,
|
|
54857
|
-
featureName,
|
|
54858
|
-
projectDir,
|
|
54859
|
-
testScopedTemplate,
|
|
54860
|
-
sessionManager,
|
|
54861
|
-
sessionId,
|
|
54862
|
-
runtime
|
|
54863
|
-
} = opts;
|
|
54864
|
-
const logger = getSafeLogger();
|
|
54865
|
-
const agentManager = opts.agentManager ?? _rectificationDeps.agentManager;
|
|
54866
|
-
if (!agentManager) {
|
|
54867
|
-
logger?.warn("rectification", "No agentManager threaded \u2014 skipping rectification loop", {
|
|
54868
|
-
storyId: story.id
|
|
54869
|
-
});
|
|
54870
|
-
return { succeeded: false, cost: 0, durationMs: 0 };
|
|
54871
|
-
}
|
|
54872
|
-
const rectificationConfig = config2.execution.rectification;
|
|
54873
|
-
const testSummary = parseTestOutput(testOutput);
|
|
54874
|
-
const label = promptPrefix ? "regression rectification" : "rectification";
|
|
54875
|
-
const rectificationSessionName = formatSessionName({
|
|
54876
|
-
workdir,
|
|
54877
|
-
featureName,
|
|
54878
|
-
storyId: story.id,
|
|
54879
|
-
role: "implementer"
|
|
54880
|
-
});
|
|
54881
|
-
let costAccum = 0;
|
|
54882
|
-
let currentAttempt = 0;
|
|
54883
|
-
let heldHandle;
|
|
54884
|
-
const initialFailure = {
|
|
54885
|
-
testOutput,
|
|
54886
|
-
testSummary
|
|
54887
|
-
};
|
|
54888
|
-
const outcome = await runRetryLoop({
|
|
54889
|
-
stage: "rectification",
|
|
54890
|
-
storyId: story.id,
|
|
54891
|
-
packageDir: workdir,
|
|
54892
|
-
maxAttempts: rectificationConfig.maxRetries,
|
|
54893
|
-
failure: initialFailure,
|
|
54894
|
-
previousAttempts: [],
|
|
54895
|
-
buildPrompt: (failure) => {
|
|
54896
|
-
currentAttempt++;
|
|
54897
|
-
const diagnosisPrefix = null;
|
|
54898
|
-
const debateStageConfig = config2.debate?.stages?.rectification;
|
|
54899
|
-
let debatePromise = Promise.resolve(null);
|
|
54900
|
-
if (debateStageConfig?.enabled) {
|
|
54901
|
-
const failureSummary = formatFailureSummary(failure.testSummary.failures);
|
|
54902
|
-
const diagnosisPrompt = `Analyze the following test failures and identify the root cause:
|
|
54903
|
-
|
|
54904
|
-
${failureSummary}`;
|
|
54905
|
-
debatePromise = (async () => {
|
|
54906
|
-
try {
|
|
54907
|
-
const debateResult = await _rectificationDeps.runDebate(story.id, debateStageConfig, diagnosisPrompt, config2, agentManager);
|
|
54908
|
-
if (debateResult.totalCostUsd > 0 && story.routing) {
|
|
54909
|
-
story.routing.estimatedCostUsd = (story.routing.estimatedCostUsd ?? 0) + debateResult.totalCostUsd;
|
|
54910
|
-
}
|
|
54911
|
-
if (debateResult.output !== null) {
|
|
54912
|
-
return `## Root Cause Analysis
|
|
54913
|
-
|
|
54914
|
-
${debateResult.output}`;
|
|
54915
|
-
}
|
|
54916
|
-
logger?.info("rectification", "debate diagnosis fallback \u2014 all debaters failed", {
|
|
54917
|
-
storyId: story.id,
|
|
54918
|
-
event: "fallback"
|
|
54919
|
-
});
|
|
54920
|
-
return null;
|
|
54921
|
-
} catch (_error) {
|
|
54922
|
-
logger?.info("rectification", "debate diagnosis fallback \u2014 debate threw error", {
|
|
54923
|
-
storyId: story.id,
|
|
54924
|
-
event: "fallback"
|
|
54925
|
-
});
|
|
54926
|
-
return null;
|
|
54927
|
-
}
|
|
54928
|
-
})();
|
|
54929
|
-
}
|
|
54930
|
-
const failureRecords = buildFailureRecords(failure.testSummary, failure.testOutput);
|
|
54931
|
-
const rectPrompt = RectifierPromptBuilder.regressionFailure({
|
|
54932
|
-
story,
|
|
54933
|
-
failures: failureRecords,
|
|
54934
|
-
testCommand,
|
|
54935
|
-
conventions: true
|
|
54936
|
-
});
|
|
54937
|
-
const rectPromise = Promise.resolve(rectPrompt);
|
|
54938
|
-
return (async () => {
|
|
54939
|
-
const [diagnosis, rectificationPrompt] = await Promise.all([debatePromise, rectPromise]);
|
|
54940
|
-
let finalPrompt = rectificationPrompt;
|
|
54941
|
-
if (diagnosis) {
|
|
54942
|
-
finalPrompt = `${diagnosis}
|
|
54943
|
-
|
|
54944
|
-
${finalPrompt}`;
|
|
54945
|
-
}
|
|
54946
|
-
if (promptPrefix) {
|
|
54947
|
-
finalPrompt = `${promptPrefix}
|
|
54948
|
-
|
|
54949
|
-
${finalPrompt}`;
|
|
54950
|
-
}
|
|
54951
|
-
return finalPrompt;
|
|
54952
|
-
})();
|
|
54953
|
-
},
|
|
54954
|
-
execute: async (prompt) => {
|
|
54955
|
-
const defaultAgent = agentManager.getDefault();
|
|
54956
|
-
const complexity = story.routing?.complexity ?? "medium";
|
|
54957
|
-
const modelTier = config2.autoMode.complexityRouting?.[complexity] || config2.autoMode.escalation.tierOrder[0]?.tier || "balanced";
|
|
54958
|
-
const modelDef = resolveModelForAgent(config2.models, story.routing?.agent ?? defaultAgent, modelTier, defaultAgent);
|
|
54959
|
-
const isLastAttempt = currentAttempt >= rectificationConfig.maxRetries;
|
|
54960
|
-
const runOptions = {
|
|
54961
|
-
prompt,
|
|
54962
|
-
workdir,
|
|
54963
|
-
modelTier,
|
|
54964
|
-
modelDef,
|
|
54965
|
-
timeoutSeconds: config2.execution.sessionTimeoutSeconds,
|
|
54966
|
-
pipelineStage: "rectification",
|
|
54967
|
-
config: config2,
|
|
54968
|
-
projectDir,
|
|
54969
|
-
maxInteractionTurns: config2.agent?.maxInteractionTurns,
|
|
54970
|
-
featureName,
|
|
54971
|
-
storyId: story.id,
|
|
54972
|
-
sessionRole: "implementer"
|
|
54973
|
-
};
|
|
54974
|
-
let agentResult;
|
|
54975
|
-
if (runtime) {
|
|
54976
|
-
let transportRetries = 0;
|
|
54977
|
-
const maxTransportRetries = config2.execution?.sessionErrorRetryableMaxRetries ?? 3;
|
|
54978
|
-
while (true) {
|
|
54979
|
-
if (!heldHandle) {
|
|
54980
|
-
heldHandle = await runtime.sessionManager.openSession(rectificationSessionName, {
|
|
54981
|
-
agentName: defaultAgent,
|
|
54982
|
-
role: "implementer",
|
|
54983
|
-
workdir,
|
|
54984
|
-
pipelineStage: "rectification",
|
|
54985
|
-
modelDef,
|
|
54986
|
-
timeoutSeconds: config2.execution.sessionTimeoutSeconds,
|
|
54987
|
-
featureName,
|
|
54988
|
-
storyId: story.id,
|
|
54989
|
-
signal: runtime.signal
|
|
54990
|
-
});
|
|
54991
|
-
}
|
|
54992
|
-
try {
|
|
54993
|
-
const turn = await agentManager.runAsSession(defaultAgent, heldHandle, prompt, {
|
|
54994
|
-
storyId: story.id,
|
|
54995
|
-
featureName,
|
|
54996
|
-
workdir,
|
|
54997
|
-
projectDir,
|
|
54998
|
-
pipelineStage: "rectification",
|
|
54999
|
-
sessionRole: "implementer",
|
|
55000
|
-
signal: runtime.signal,
|
|
55001
|
-
maxTurns: config2.agent?.maxInteractionTurns
|
|
55002
|
-
});
|
|
55003
|
-
agentResult = {
|
|
55004
|
-
success: true,
|
|
55005
|
-
exitCode: 0,
|
|
55006
|
-
output: turn.output,
|
|
55007
|
-
rateLimited: false,
|
|
55008
|
-
durationMs: 0,
|
|
55009
|
-
estimatedCostUsd: turn.estimatedCostUsd,
|
|
55010
|
-
...turn.exactCostUsd !== undefined && { exactCostUsd: turn.exactCostUsd },
|
|
55011
|
-
...turn.tokenUsage && { tokenUsage: turn.tokenUsage },
|
|
55012
|
-
...heldHandle.protocolIds && { protocolIds: heldHandle.protocolIds }
|
|
55013
|
-
};
|
|
55014
|
-
break;
|
|
55015
|
-
} catch (err) {
|
|
55016
|
-
const stale = heldHandle;
|
|
55017
|
-
heldHandle = undefined;
|
|
55018
|
-
await runtime.sessionManager.closeSession(stale).catch(() => {});
|
|
55019
|
-
if (err instanceof SessionTurnError && err.retryable && transportRetries < maxTransportRetries) {
|
|
55020
|
-
transportRetries++;
|
|
55021
|
-
getSafeLogger()?.warn("rectification", "fail-adapter-error: same-agent retry with fresh session", {
|
|
55022
|
-
storyId: story.id,
|
|
55023
|
-
attempt: transportRetries,
|
|
55024
|
-
maxAttempts: maxTransportRetries,
|
|
55025
|
-
retriable: true
|
|
55026
|
-
});
|
|
55027
|
-
continue;
|
|
55028
|
-
}
|
|
55029
|
-
throw err;
|
|
55030
|
-
}
|
|
55031
|
-
}
|
|
55032
|
-
} else {
|
|
55033
|
-
agentResult = await agentManager.run({
|
|
55034
|
-
runOptions: { ...runOptions, keepOpen: !isLastAttempt }
|
|
55035
|
-
});
|
|
55036
|
-
}
|
|
55037
|
-
costAccum += agentResult.estimatedCostUsd ?? 0;
|
|
55038
|
-
if (sessionManager && sessionId && agentResult.protocolIds) {
|
|
55039
|
-
try {
|
|
55040
|
-
sessionManager.bindHandle(sessionId, rectificationSessionName, agentResult.protocolIds);
|
|
55041
|
-
} catch {}
|
|
55042
|
-
}
|
|
55043
|
-
if (agentResult.success) {
|
|
55044
|
-
logger?.info("rectification", `Agent ${label} session complete`, {
|
|
55045
|
-
storyId: story.id,
|
|
55046
|
-
cost: agentResult.estimatedCostUsd
|
|
55047
|
-
});
|
|
55048
|
-
} else {
|
|
55049
|
-
logger?.warn("rectification", `Agent ${label} session failed`, {
|
|
55050
|
-
storyId: story.id,
|
|
55051
|
-
exitCode: agentResult.exitCode
|
|
55052
|
-
});
|
|
55053
|
-
}
|
|
55054
|
-
return {
|
|
55055
|
-
agentSuccess: agentResult.success,
|
|
55056
|
-
cost: agentResult.estimatedCostUsd ?? 0,
|
|
55057
|
-
protocolIds: agentResult.protocolIds
|
|
55058
|
-
};
|
|
55059
|
-
},
|
|
55060
|
-
shouldAbort: (failure) => {
|
|
55061
|
-
if (rectificationConfig.abortOnIncreasingFailures) {
|
|
55062
|
-
return failure.testSummary.failed > initialFailure.testSummary.failed;
|
|
55063
|
-
}
|
|
55064
|
-
return false;
|
|
55065
|
-
},
|
|
55066
|
-
verify: async (result) => {
|
|
55067
|
-
const retryVerification = await _rectificationDeps.runVerification({
|
|
55068
|
-
workdir,
|
|
55069
|
-
expectedFiles: getExpectedFiles(story),
|
|
55070
|
-
command: testCommand,
|
|
55071
|
-
timeoutSeconds,
|
|
55072
|
-
forceExit: config2.quality.forceExit,
|
|
55073
|
-
detectOpenHandles: config2.quality.detectOpenHandles,
|
|
55074
|
-
detectOpenHandlesRetries: config2.quality.detectOpenHandlesRetries,
|
|
55075
|
-
timeoutRetryCount: 0,
|
|
55076
|
-
gracePeriodMs: config2.quality.gracePeriodMs,
|
|
55077
|
-
drainTimeoutMs: config2.quality.drainTimeoutMs,
|
|
55078
|
-
shell: config2.quality.shell,
|
|
55079
|
-
stripEnvVars: config2.quality.stripEnvVars
|
|
55080
|
-
});
|
|
55081
|
-
if (retryVerification.success) {
|
|
55082
|
-
logger?.info("rectification", `[OK] ${label} succeeded!`, {
|
|
55083
|
-
storyId: story.id,
|
|
55084
|
-
attempt: currentAttempt,
|
|
55085
|
-
initialFailures: initialFailure.testSummary.failed
|
|
55086
|
-
});
|
|
55087
|
-
return { passed: true };
|
|
55088
|
-
}
|
|
55089
|
-
if (retryVerification.output) {
|
|
55090
|
-
const newTestSummary = parseTestOutput(retryVerification.output);
|
|
55091
|
-
if (newTestSummary.failed === 0 && retryVerification.status !== "ENVIRONMENTAL_FAILURE" && (retryVerification.status === "SUCCESS" || newTestSummary.passed > 0)) {
|
|
55092
|
-
logger?.info("rectification", `[OK] ${label} succeeded after parsing retry output`, {
|
|
55093
|
-
storyId: story.id,
|
|
55094
|
-
attempt: currentAttempt,
|
|
55095
|
-
initialFailures: initialFailure.testSummary.failed
|
|
55096
|
-
});
|
|
55097
|
-
return { passed: true };
|
|
55098
|
-
}
|
|
55099
|
-
const failingTests = newTestSummary.failures.slice(0, 10).map((failure) => failure.testName);
|
|
55100
|
-
const logData = {
|
|
55101
|
-
storyId: story.id,
|
|
55102
|
-
attempt: currentAttempt,
|
|
55103
|
-
remainingFailures: newTestSummary.failed,
|
|
55104
|
-
failingTests
|
|
55105
|
-
};
|
|
55106
|
-
if (newTestSummary.failures.length > 10 || newTestSummary.failures.length === 0 && newTestSummary.failed > 0) {
|
|
55107
|
-
logData.totalFailingTests = newTestSummary.failed;
|
|
55108
|
-
}
|
|
55109
|
-
logger?.warn("rectification", `${label} still failing after attempt`, logData);
|
|
55110
|
-
return {
|
|
55111
|
-
passed: false,
|
|
55112
|
-
newFailure: {
|
|
55113
|
-
testOutput: retryVerification.output,
|
|
55114
|
-
testSummary: newTestSummary
|
|
55115
|
-
}
|
|
55116
|
-
};
|
|
55117
|
-
}
|
|
55118
|
-
return {
|
|
55119
|
-
passed: false,
|
|
55120
|
-
newFailure: {
|
|
55121
|
-
testOutput: retryVerification.output ?? "",
|
|
55122
|
-
testSummary: initialFailure.testSummary
|
|
55123
|
-
}
|
|
55124
|
-
};
|
|
55125
|
-
}
|
|
55126
|
-
}).finally(async () => {
|
|
55127
|
-
if (heldHandle && runtime) {
|
|
55128
|
-
const stale = heldHandle;
|
|
55129
|
-
heldHandle = undefined;
|
|
55130
|
-
await runtime.sessionManager.closeSession(stale).catch(() => {});
|
|
55131
|
-
}
|
|
55132
|
-
});
|
|
55133
|
-
const succeeded = outcome.outcome === "fixed";
|
|
55134
|
-
if (outcome.outcome === "exhausted") {
|
|
55135
|
-
const finalFailure = outcome.finalFailure;
|
|
55136
|
-
const shouldEscalate = rectificationConfig.escalateOnExhaustion !== false && config2.autoMode?.escalation?.enabled === true && finalFailure.testSummary.failed > 0;
|
|
55137
|
-
if (shouldEscalate) {
|
|
55138
|
-
const complexity = story.routing?.complexity ?? "medium";
|
|
55139
|
-
const currentTier = config2.autoMode.complexityRouting?.[complexity] || config2.autoMode.escalation.tierOrder[0]?.tier || "balanced";
|
|
55140
|
-
const tierOrder = config2.autoMode.escalation.tierOrder;
|
|
55141
|
-
const escalationResult = _rectificationDeps.escalateTier(currentTier, tierOrder);
|
|
55142
|
-
const escalatedTier = escalationResult?.tier ?? null;
|
|
55143
|
-
const escalatedAgent = escalationResult?.agent;
|
|
55144
|
-
if (escalatedTier !== null) {
|
|
55145
|
-
const escalationManager = agentManager;
|
|
55146
|
-
const agentName = escalatedAgent ?? story.routing?.agent ?? escalationManager.getDefault();
|
|
55147
|
-
if (escalationManager.getAgent(agentName)) {
|
|
55148
|
-
const escalatedModelDef = resolveModelForAgent(config2.models, agentName, escalatedTier, escalationManager.getDefault());
|
|
55149
|
-
let escalationPrompt = RectifierPromptBuilder.escalated(finalFailure.testSummary.failures, story, outcome.attempts, currentTier, escalatedTier, rectificationConfig, testCommand, testScopedTemplate);
|
|
55150
|
-
if (promptPrefix) {
|
|
55151
|
-
escalationPrompt = `${promptPrefix}
|
|
55152
|
-
|
|
55153
|
-
${escalationPrompt}`;
|
|
55154
|
-
}
|
|
55155
|
-
const escalationRunResult = await escalationManager.runAs(agentName, {
|
|
55156
|
-
runOptions: {
|
|
55157
|
-
prompt: escalationPrompt,
|
|
55158
|
-
workdir,
|
|
55159
|
-
modelTier: escalatedTier,
|
|
55160
|
-
modelDef: escalatedModelDef,
|
|
55161
|
-
timeoutSeconds: config2.execution.sessionTimeoutSeconds,
|
|
55162
|
-
pipelineStage: "rectification",
|
|
55163
|
-
config: config2,
|
|
55164
|
-
projectDir,
|
|
55165
|
-
maxInteractionTurns: config2.agent?.maxInteractionTurns,
|
|
55166
|
-
featureName,
|
|
55167
|
-
storyId: story.id,
|
|
55168
|
-
sessionRole: "implementer"
|
|
55169
|
-
}
|
|
55170
|
-
});
|
|
55171
|
-
costAccum += escalationRunResult.estimatedCostUsd ?? 0;
|
|
55172
|
-
logger?.info("rectification", "escalated rectification attempt cost", {
|
|
55173
|
-
storyId: story.id,
|
|
55174
|
-
escalatedTier,
|
|
55175
|
-
cost: escalationRunResult.estimatedCostUsd
|
|
55176
|
-
});
|
|
55177
|
-
const escalationVerification = await _rectificationDeps.runVerification({
|
|
55178
|
-
workdir,
|
|
55179
|
-
expectedFiles: getExpectedFiles(story),
|
|
55180
|
-
command: testCommand,
|
|
55181
|
-
timeoutSeconds,
|
|
55182
|
-
forceExit: config2.quality.forceExit,
|
|
55183
|
-
detectOpenHandles: config2.quality.detectOpenHandles,
|
|
55184
|
-
detectOpenHandlesRetries: config2.quality.detectOpenHandlesRetries,
|
|
55185
|
-
timeoutRetryCount: 0,
|
|
55186
|
-
gracePeriodMs: config2.quality.gracePeriodMs,
|
|
55187
|
-
drainTimeoutMs: config2.quality.drainTimeoutMs,
|
|
55188
|
-
shell: config2.quality.shell,
|
|
55189
|
-
stripEnvVars: config2.quality.stripEnvVars
|
|
55190
|
-
});
|
|
55191
|
-
if (escalationVerification.success) {
|
|
55192
|
-
logger?.info("rectification", `${label} escalated from ${currentTier} to ${escalatedTier} and succeeded`, {
|
|
55193
|
-
storyId: story.id,
|
|
55194
|
-
currentTier,
|
|
55195
|
-
escalatedTier
|
|
55196
|
-
});
|
|
55197
|
-
return { succeeded: true, cost: costAccum, durationMs: Date.now() - loopStartMs };
|
|
55198
|
-
}
|
|
55199
|
-
logger?.warn("rectification", "escalated rectification also failed", { storyId: story.id, escalatedTier });
|
|
55200
|
-
}
|
|
55201
|
-
}
|
|
55202
|
-
}
|
|
55203
|
-
logger?.warn("rectification", `${label} exhausted max retries`, {
|
|
55204
|
-
storyId: story.id,
|
|
55205
|
-
attempts: outcome.attempts,
|
|
55206
|
-
remainingFailures: initialFailure.testSummary.failed
|
|
55207
|
-
});
|
|
55208
|
-
}
|
|
55209
|
-
return { succeeded, cost: costAccum, durationMs: Date.now() - loopStartMs };
|
|
55210
|
-
}
|
|
55211
|
-
var _rectificationDeps;
|
|
55212
|
-
var init_rectification_loop = __esm(() => {
|
|
55213
|
-
init_agents();
|
|
55214
|
-
init_cost();
|
|
55215
|
-
init_types3();
|
|
55216
|
-
init_config();
|
|
55217
|
-
init_logger2();
|
|
55218
|
-
init_prd();
|
|
55219
|
-
init_prompts();
|
|
55220
|
-
init_naming();
|
|
55221
|
-
init_parser2();
|
|
55222
|
-
init_parser2();
|
|
55223
|
-
init_runners();
|
|
55224
|
-
_rectificationDeps = {
|
|
55225
|
-
agentManager: undefined,
|
|
55226
|
-
runVerification: fullSuite,
|
|
55227
|
-
escalateTier,
|
|
55228
|
-
runDebate: _defaultRunDebate
|
|
55229
|
-
};
|
|
55230
|
-
});
|
|
55231
|
-
|
|
55232
55310
|
// src/pipeline/stages/rectify.ts
|
|
55233
55311
|
var rectifyStage, _rectifyDeps;
|
|
55234
55312
|
var init_rectify2 = __esm(() => {
|
|
@@ -55327,7 +55405,7 @@ var init_rectify2 = __esm(() => {
|
|
|
55327
55405
|
}
|
|
55328
55406
|
};
|
|
55329
55407
|
_rectifyDeps = {
|
|
55330
|
-
runRectificationLoop: (ctx, opts) =>
|
|
55408
|
+
runRectificationLoop: (ctx, opts) => runRectificationLoop({
|
|
55331
55409
|
config: ctx.config,
|
|
55332
55410
|
workdir: ctx.workdir,
|
|
55333
55411
|
story: ctx.story,
|
|
@@ -55339,7 +55417,7 @@ var init_rectify2 = __esm(() => {
|
|
|
55339
55417
|
agentManager: ctx.agentManager,
|
|
55340
55418
|
projectDir: ctx.projectDir,
|
|
55341
55419
|
testScopedTemplate: opts.testScopedTemplate,
|
|
55342
|
-
|
|
55420
|
+
runtime: ctx.runtime,
|
|
55343
55421
|
sessionId: ctx.sessionId
|
|
55344
55422
|
}),
|
|
55345
55423
|
resolveTestCommands: resolveQualityTestCommands,
|
|
@@ -56190,7 +56268,7 @@ async function promptsInitCommand(options) {
|
|
|
56190
56268
|
mkdirSync4(templatesDir, { recursive: true });
|
|
56191
56269
|
const existingFiles = TEMPLATE_ROLES.map((t) => t.file).filter((f) => existsSync21(join50(templatesDir, f)));
|
|
56192
56270
|
if (existingFiles.length > 0 && !force) {
|
|
56193
|
-
|
|
56271
|
+
_promptsInitDeps.warn(`[WARN] nax/templates/ already contains files: ${existingFiles.join(", ")}. No files overwritten.
|
|
56194
56272
|
Pass --force to overwrite existing templates.`);
|
|
56195
56273
|
return [];
|
|
56196
56274
|
}
|
|
@@ -56202,9 +56280,9 @@ async function promptsInitCommand(options) {
|
|
|
56202
56280
|
await Bun.write(filePath, content);
|
|
56203
56281
|
written.push(filePath);
|
|
56204
56282
|
}
|
|
56205
|
-
|
|
56283
|
+
_promptsInitDeps.log(`[OK] Written ${written.length} template files to nax/templates/:`);
|
|
56206
56284
|
for (const filePath of written) {
|
|
56207
|
-
|
|
56285
|
+
_promptsInitDeps.log(` - ${filePath.replace(`${workdir}/`, "")}`);
|
|
56208
56286
|
}
|
|
56209
56287
|
if (autoWireConfig) {
|
|
56210
56288
|
await autoWirePromptsConfig(workdir);
|
|
@@ -56225,7 +56303,7 @@ async function autoWirePromptsConfig(workdir) {
|
|
|
56225
56303
|
}
|
|
56226
56304
|
}
|
|
56227
56305
|
}, null, 2);
|
|
56228
|
-
|
|
56306
|
+
_promptsInitDeps.log(`
|
|
56229
56307
|
No nax.config.json found. To activate overrides, create nax/config.json with:
|
|
56230
56308
|
${exampleConfig}`);
|
|
56231
56309
|
return;
|
|
@@ -56234,7 +56312,7 @@ ${exampleConfig}`);
|
|
|
56234
56312
|
const configContent = await configFile.text();
|
|
56235
56313
|
const config2 = JSON.parse(configContent);
|
|
56236
56314
|
if (config2.prompts?.overrides && Object.keys(config2.prompts.overrides).length > 0) {
|
|
56237
|
-
|
|
56315
|
+
_promptsInitDeps.log(`[INFO] prompts.overrides already configured in nax.config.json. Skipping auto-wiring.
|
|
56238
56316
|
` + " To reset overrides, remove the prompts.overrides section and re-run this command.");
|
|
56239
56317
|
return;
|
|
56240
56318
|
}
|
|
@@ -56251,7 +56329,7 @@ ${exampleConfig}`);
|
|
|
56251
56329
|
config2.prompts.overrides = overrides;
|
|
56252
56330
|
const updatedConfig = formatConfigJson(config2);
|
|
56253
56331
|
await Bun.write(configPath, updatedConfig);
|
|
56254
|
-
|
|
56332
|
+
_promptsInitDeps.log("[OK] Auto-wired prompts.overrides in nax.config.json");
|
|
56255
56333
|
}
|
|
56256
56334
|
function formatConfigJson(config2) {
|
|
56257
56335
|
const lines = ["{"];
|
|
@@ -56276,7 +56354,7 @@ function formatConfigJson(config2) {
|
|
|
56276
56354
|
return lines.join(`
|
|
56277
56355
|
`);
|
|
56278
56356
|
}
|
|
56279
|
-
var TEMPLATE_ROLES, TEMPLATE_HEADER = `<!--
|
|
56357
|
+
var _promptsInitDeps, TEMPLATE_ROLES, TEMPLATE_HEADER = `<!--
|
|
56280
56358
|
This file controls the role-body section of the nax prompt for this role.
|
|
56281
56359
|
Edit the content below to customize the task instructions given to the agent.
|
|
56282
56360
|
|
|
@@ -56292,6 +56370,10 @@ var TEMPLATE_ROLES, TEMPLATE_HEADER = `<!--
|
|
|
56292
56370
|
`;
|
|
56293
56371
|
var init_prompts_init = __esm(() => {
|
|
56294
56372
|
init_role_task();
|
|
56373
|
+
_promptsInitDeps = {
|
|
56374
|
+
log: console.log.bind(console),
|
|
56375
|
+
warn: console.warn.bind(console)
|
|
56376
|
+
};
|
|
56295
56377
|
TEMPLATE_ROLES = [
|
|
56296
56378
|
{ file: "test-writer.md", role: "test-writer" },
|
|
56297
56379
|
{ file: "implementer.md", role: "implementer", variant: "standard" },
|
|
@@ -56878,7 +56960,8 @@ __export(exports_init, {
|
|
|
56878
56960
|
validateProjectName: () => validateProjectName,
|
|
56879
56961
|
initProject: () => initProject,
|
|
56880
56962
|
initCommand: () => initCommand,
|
|
56881
|
-
checkInitCollision: () => checkInitCollision
|
|
56963
|
+
checkInitCollision: () => checkInitCollision,
|
|
56964
|
+
_initDeps: () => _initDeps
|
|
56882
56965
|
});
|
|
56883
56966
|
import { existsSync as existsSync24 } from "fs";
|
|
56884
56967
|
import { mkdir as mkdir10 } from "fs/promises";
|
|
@@ -57105,20 +57188,20 @@ async function initProject(projectRoot, options) {
|
|
|
57105
57188
|
}
|
|
57106
57189
|
await updateGitignore(projectRoot);
|
|
57107
57190
|
await promptsInitCommand({ workdir: projectRoot, force: false, autoWireConfig: false });
|
|
57108
|
-
|
|
57191
|
+
_initDeps.log(`
|
|
57109
57192
|
[OK] nax init complete. Created files:`);
|
|
57110
|
-
|
|
57111
|
-
|
|
57112
|
-
|
|
57113
|
-
|
|
57114
|
-
|
|
57115
|
-
|
|
57193
|
+
_initDeps.log(" - .nax/config.json");
|
|
57194
|
+
_initDeps.log(" - .nax/context.md");
|
|
57195
|
+
_initDeps.log(" - .nax/constitution.md");
|
|
57196
|
+
_initDeps.log(" - .nax/hooks/");
|
|
57197
|
+
_initDeps.log(" - .nax/templates/");
|
|
57198
|
+
_initDeps.log(`
|
|
57116
57199
|
Next steps:`);
|
|
57117
|
-
|
|
57118
|
-
|
|
57119
|
-
|
|
57120
|
-
|
|
57121
|
-
|
|
57200
|
+
_initDeps.log(" 1. Review .nax/context.md and fill in TODOs");
|
|
57201
|
+
_initDeps.log(" 2. Review .nax/config.json and adjust quality commands");
|
|
57202
|
+
_initDeps.log(" 3. Run: nax generate");
|
|
57203
|
+
_initDeps.log(" 4. Run: nax plan");
|
|
57204
|
+
_initDeps.log(" 5. Run: nax run");
|
|
57122
57205
|
logger.info("init", "Project config initialized successfully", { path: projectDir });
|
|
57123
57206
|
}
|
|
57124
57207
|
async function initCommand(options = {}) {
|
|
@@ -57127,19 +57210,19 @@ async function initCommand(options = {}) {
|
|
|
57127
57210
|
} else if (options.package) {
|
|
57128
57211
|
const projectRoot = options.projectRoot ?? process.cwd();
|
|
57129
57212
|
await initPackage(projectRoot, options.package);
|
|
57130
|
-
|
|
57213
|
+
_initDeps.log(`
|
|
57131
57214
|
[OK] Package scaffold created.`);
|
|
57132
|
-
|
|
57133
|
-
|
|
57215
|
+
_initDeps.log(` Created: .nax/mono/${options.package}/context.md`);
|
|
57216
|
+
_initDeps.log(`
|
|
57134
57217
|
Next steps:`);
|
|
57135
|
-
|
|
57136
|
-
|
|
57218
|
+
_initDeps.log(` 1. Review .nax/mono/${options.package}/context.md and fill in TODOs`);
|
|
57219
|
+
_initDeps.log(` 2. Run: nax generate --package ${options.package}`);
|
|
57137
57220
|
} else {
|
|
57138
57221
|
const projectRoot = options.projectRoot ?? process.cwd();
|
|
57139
57222
|
await initProject(projectRoot, { name: options.name, force: options.force });
|
|
57140
57223
|
}
|
|
57141
57224
|
}
|
|
57142
|
-
var MINIMAL_GLOBAL_CONFIG;
|
|
57225
|
+
var _initDeps, MINIMAL_GLOBAL_CONFIG;
|
|
57143
57226
|
var init_init2 = __esm(() => {
|
|
57144
57227
|
init_paths();
|
|
57145
57228
|
init_errors();
|
|
@@ -57149,6 +57232,9 @@ var init_init2 = __esm(() => {
|
|
|
57149
57232
|
init_init_context();
|
|
57150
57233
|
init_init_detect();
|
|
57151
57234
|
init_prompts2();
|
|
57235
|
+
_initDeps = {
|
|
57236
|
+
log: console.log.bind(console)
|
|
57237
|
+
};
|
|
57152
57238
|
MINIMAL_GLOBAL_CONFIG = {
|
|
57153
57239
|
version: 1
|
|
57154
57240
|
};
|
|
@@ -58789,7 +58875,7 @@ var package_default;
|
|
|
58789
58875
|
var init_package = __esm(() => {
|
|
58790
58876
|
package_default = {
|
|
58791
58877
|
name: "@nathapp/nax",
|
|
58792
|
-
version: "0.67.0-canary.
|
|
58878
|
+
version: "0.67.0-canary.5",
|
|
58793
58879
|
description: "AI Coding Agent Orchestrator \u2014 loops until done",
|
|
58794
58880
|
type: "module",
|
|
58795
58881
|
bin: {
|
|
@@ -58799,7 +58885,7 @@ var init_package = __esm(() => {
|
|
|
58799
58885
|
prepare: "git config core.hooksPath .githooks",
|
|
58800
58886
|
dev: "bun run bin/nax.ts",
|
|
58801
58887
|
build: 'bun build bin/nax.ts --outdir dist --target bun --define "GIT_COMMIT=\\"$(git rev-parse --short HEAD)\\""',
|
|
58802
|
-
typecheck: "bun x tsc --noEmit",
|
|
58888
|
+
typecheck: "bun x tsc --noEmit && bun x tsc --noEmit -p tsconfig.contracts.json",
|
|
58803
58889
|
lint: "bun x biome check src/ bin/ && bun run check:no-real-global-nax && bun run check:alias-internals && bun run check:deep-relatives && bun run check:nax-error && bun run check:logger-storyid",
|
|
58804
58890
|
"lint:json": "bun x biome check src/ bin/ --reporter json && bun run check:nax-error 1>&2 && bun run check:logger-storyid 1>&2",
|
|
58805
58891
|
"lint:fix": "bun x biome check --write src/ bin/",
|
|
@@ -58812,8 +58898,10 @@ var init_package = __esm(() => {
|
|
|
58812
58898
|
"check:logger-storyid": "bun run scripts/check-logger-storyid.ts",
|
|
58813
58899
|
"check:logger-storyid:update": "bun run scripts/check-logger-storyid.ts --update-baseline",
|
|
58814
58900
|
release: "bun scripts/release.ts",
|
|
58815
|
-
test: "bun run scripts/run-tests.ts",
|
|
58816
|
-
"test:
|
|
58901
|
+
test: "AGENT=1 bun run scripts/run-tests.ts",
|
|
58902
|
+
"test:verbose": "bun run scripts/run-tests.ts",
|
|
58903
|
+
"test:bail": "AGENT=1 bun run scripts/run-tests.ts --bail",
|
|
58904
|
+
"test:bail-verbose": "bun run scripts/run-tests.ts --bail",
|
|
58817
58905
|
"test:no-wrap": "bun test test/unit/ --timeout=5000 && bun test test/integration/ --timeout=5000 && bun test test/ui/ --timeout=5000",
|
|
58818
58906
|
"test:watch": "bun test --watch",
|
|
58819
58907
|
"test:unit": "bun test ./test/unit/ --timeout=60000",
|
|
@@ -58882,8 +58970,8 @@ var init_version = __esm(() => {
|
|
|
58882
58970
|
NAX_VERSION = package_default.version;
|
|
58883
58971
|
NAX_COMMIT = (() => {
|
|
58884
58972
|
try {
|
|
58885
|
-
if (/^[0-9a-f]{6,10}$/.test("
|
|
58886
|
-
return "
|
|
58973
|
+
if (/^[0-9a-f]{6,10}$/.test("9cf63261"))
|
|
58974
|
+
return "9cf63261";
|
|
58887
58975
|
} catch {}
|
|
58888
58976
|
try {
|
|
58889
58977
|
const result = Bun.spawnSync(["git", "rev-parse", "--short", "HEAD"], {
|
|
@@ -59607,7 +59695,7 @@ async function runAcceptanceFixCycle(ctx, prd, initialFailures, diagnosis, accep
|
|
|
59607
59695
|
coRun: "co-run-sequential"
|
|
59608
59696
|
}
|
|
59609
59697
|
],
|
|
59610
|
-
validate: async (_ctx) => {
|
|
59698
|
+
validate: async (_ctx, _opts) => {
|
|
59611
59699
|
const result = await runAcceptanceTestsOnce(ctx, prd);
|
|
59612
59700
|
if (result.passed)
|
|
59613
59701
|
return [];
|
|
@@ -59825,7 +59913,7 @@ async function findResponsibleStory(testFile, workdir, passedStories) {
|
|
|
59825
59913
|
}
|
|
59826
59914
|
async function runDeferredRegression(options) {
|
|
59827
59915
|
const logger = getSafeLogger();
|
|
59828
|
-
const { config: config2, prd, workdir,
|
|
59916
|
+
const { config: config2, prd, workdir, runtime } = options;
|
|
59829
59917
|
const regressionMode = config2.execution.regressionGate?.mode ?? "deferred";
|
|
59830
59918
|
if (regressionMode === "disabled") {
|
|
59831
59919
|
logger?.info("regression", "Deferred regression gate disabled");
|
|
@@ -60015,8 +60103,9 @@ async function runDeferredRegression(options) {
|
|
|
60015
60103
|
promptPrefix: `# DEFERRED REGRESSION: Full-Suite Failures
|
|
60016
60104
|
|
|
60017
60105
|
Your story ${story.id} broke tests in the full suite. Fix these regressions.`,
|
|
60018
|
-
agentManager,
|
|
60019
|
-
featureName: prd.feature
|
|
60106
|
+
agentManager: runtime.agentManager,
|
|
60107
|
+
featureName: prd.feature,
|
|
60108
|
+
runtime
|
|
60020
60109
|
});
|
|
60021
60110
|
storyCostAccum[story.id] = (storyCostAccum[story.id] ?? 0) + rectResult.cost;
|
|
60022
60111
|
storyDurationAccum[story.id] = (storyDurationAccum[story.id] ?? 0) + rectResult.durationMs;
|
|
@@ -60095,7 +60184,7 @@ var init_run_regression = __esm(() => {
|
|
|
60095
60184
|
init_runners();
|
|
60096
60185
|
_regressionDeps = {
|
|
60097
60186
|
runVerification: fullSuite,
|
|
60098
|
-
runRectificationLoop
|
|
60187
|
+
runRectificationLoop,
|
|
60099
60188
|
parseTestOutput
|
|
60100
60189
|
};
|
|
60101
60190
|
});
|
|
@@ -60149,7 +60238,7 @@ async function handleRunCompletion(options) {
|
|
|
60149
60238
|
config: config2,
|
|
60150
60239
|
prd,
|
|
60151
60240
|
workdir,
|
|
60152
|
-
|
|
60241
|
+
runtime: options.runtime
|
|
60153
60242
|
});
|
|
60154
60243
|
const lastRunAt = new Date().toISOString();
|
|
60155
60244
|
logger?.info("regression", "Deferred regression gate completed", {
|
|
@@ -98394,6 +98483,7 @@ async function extractRunSummary(filePath) {
|
|
|
98394
98483
|
|
|
98395
98484
|
// src/commands/logs-formatter.ts
|
|
98396
98485
|
var LOG_LEVEL_PRIORITY2 = {
|
|
98486
|
+
silent: -1,
|
|
98397
98487
|
debug: 0,
|
|
98398
98488
|
info: 1,
|
|
98399
98489
|
warn: 2,
|
|
@@ -99277,6 +99367,13 @@ init_helpers();
|
|
|
99277
99367
|
init_crash_recovery();
|
|
99278
99368
|
init_pid_registry();
|
|
99279
99369
|
|
|
99370
|
+
// src/execution/lifecycle/index.ts
|
|
99371
|
+
init_acceptance_loop();
|
|
99372
|
+
init_headless_formatter();
|
|
99373
|
+
init_run_completion();
|
|
99374
|
+
init_run_cleanup();
|
|
99375
|
+
init_run_setup();
|
|
99376
|
+
init_run_regression();
|
|
99280
99377
|
// bin/nax.ts
|
|
99281
99378
|
init_hooks();
|
|
99282
99379
|
init_logger2();
|