@nathapp/nax 0.56.1 → 0.56.2
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 +162 -68
- package/package.json +1 -1
package/dist/nax.js
CHANGED
|
@@ -22056,7 +22056,7 @@ var package_default;
|
|
|
22056
22056
|
var init_package = __esm(() => {
|
|
22057
22057
|
package_default = {
|
|
22058
22058
|
name: "@nathapp/nax",
|
|
22059
|
-
version: "0.56.
|
|
22059
|
+
version: "0.56.2",
|
|
22060
22060
|
description: "AI Coding Agent Orchestrator \u2014 loops until done",
|
|
22061
22061
|
type: "module",
|
|
22062
22062
|
bin: {
|
|
@@ -22135,8 +22135,8 @@ var init_version = __esm(() => {
|
|
|
22135
22135
|
NAX_VERSION = package_default.version;
|
|
22136
22136
|
NAX_COMMIT = (() => {
|
|
22137
22137
|
try {
|
|
22138
|
-
if (/^[0-9a-f]{6,10}$/.test("
|
|
22139
|
-
return "
|
|
22138
|
+
if (/^[0-9a-f]{6,10}$/.test("b590070f"))
|
|
22139
|
+
return "b590070f";
|
|
22140
22140
|
} catch {}
|
|
22141
22141
|
try {
|
|
22142
22142
|
const result = Bun.spawnSync(["git", "rev-parse", "--short", "HEAD"], {
|
|
@@ -22389,6 +22389,18 @@ var DEFAULT_FALLBACK_AGENT = "claude";
|
|
|
22389
22389
|
var init_resolvers = () => {};
|
|
22390
22390
|
|
|
22391
22391
|
// src/debate/session.ts
|
|
22392
|
+
function resolveDebaterModel(debater, config2) {
|
|
22393
|
+
const tier = debater.model ?? "fast";
|
|
22394
|
+
if (!config2?.models)
|
|
22395
|
+
return debater.model;
|
|
22396
|
+
try {
|
|
22397
|
+
const defaultAgent = config2.autoMode?.defaultAgent ?? debater.agent;
|
|
22398
|
+
const modelDef = resolveModelForAgent(config2.models, debater.agent, tier, defaultAgent);
|
|
22399
|
+
return modelDef.model;
|
|
22400
|
+
} catch {
|
|
22401
|
+
return debater.model;
|
|
22402
|
+
}
|
|
22403
|
+
}
|
|
22392
22404
|
function buildFailedResult(storyId, stage, stageConfig, totalCostUsd = 0) {
|
|
22393
22405
|
return {
|
|
22394
22406
|
storyId,
|
|
@@ -22411,10 +22423,12 @@ class DebateSession {
|
|
|
22411
22423
|
storyId;
|
|
22412
22424
|
stage;
|
|
22413
22425
|
stageConfig;
|
|
22426
|
+
config;
|
|
22414
22427
|
constructor(opts) {
|
|
22415
22428
|
this.storyId = opts.storyId;
|
|
22416
22429
|
this.stage = opts.stage;
|
|
22417
22430
|
this.stageConfig = opts.stageConfig;
|
|
22431
|
+
this.config = opts.config;
|
|
22418
22432
|
}
|
|
22419
22433
|
async run(prompt) {
|
|
22420
22434
|
const sessionMode = this.stageConfig.sessionMode ?? "one-shot";
|
|
@@ -22437,11 +22451,17 @@ class DebateSession {
|
|
|
22437
22451
|
}
|
|
22438
22452
|
resolved.push({ debater, adapter });
|
|
22439
22453
|
}
|
|
22454
|
+
logger?.info("debate", "debate:start", {
|
|
22455
|
+
storyId: this.storyId,
|
|
22456
|
+
stage: this.stage,
|
|
22457
|
+
debaters: resolved.map((r) => r.debater.agent)
|
|
22458
|
+
});
|
|
22440
22459
|
const sessions = [];
|
|
22441
22460
|
try {
|
|
22442
22461
|
for (let i = 0;i < resolved.length; i++) {
|
|
22443
22462
|
const { debater, adapter } = resolved[i];
|
|
22444
|
-
const
|
|
22463
|
+
const resolvedModel = resolveDebaterModel(debater, this.config);
|
|
22464
|
+
const cmdStr = resolvedModel ? `acpx --model ${resolvedModel} ${debater.agent}` : `acpx ${debater.agent}`;
|
|
22445
22465
|
const client = _debateSessionDeps.createSpawnAcpClient(cmdStr);
|
|
22446
22466
|
const sessionName = `nax-debate-${this.storyId}-${i}`;
|
|
22447
22467
|
try {
|
|
@@ -22457,9 +22477,19 @@ class DebateSession {
|
|
|
22457
22477
|
}
|
|
22458
22478
|
if (sessions.length < 2) {
|
|
22459
22479
|
if (sessions.length === 1) {
|
|
22480
|
+
logger?.warn("debate", "debate:fallback", {
|
|
22481
|
+
storyId: this.storyId,
|
|
22482
|
+
stage: this.stage,
|
|
22483
|
+
reason: "only 1 session created"
|
|
22484
|
+
});
|
|
22460
22485
|
const solo = sessions[0];
|
|
22461
22486
|
const response = await solo.session.prompt(prompt);
|
|
22462
22487
|
const output = extractSessionOutput(response);
|
|
22488
|
+
logger?.info("debate", "debate:result", {
|
|
22489
|
+
storyId: this.storyId,
|
|
22490
|
+
stage: this.stage,
|
|
22491
|
+
outcome: "passed"
|
|
22492
|
+
});
|
|
22463
22493
|
return {
|
|
22464
22494
|
storyId: this.storyId,
|
|
22465
22495
|
stage: this.stage,
|
|
@@ -22471,6 +22501,11 @@ class DebateSession {
|
|
|
22471
22501
|
totalCostUsd
|
|
22472
22502
|
};
|
|
22473
22503
|
}
|
|
22504
|
+
logger?.warn("debate", "debate:fallback", {
|
|
22505
|
+
storyId: this.storyId,
|
|
22506
|
+
stage: this.stage,
|
|
22507
|
+
reason: "no sessions created"
|
|
22508
|
+
});
|
|
22474
22509
|
return buildFailedResult(this.storyId, this.stage, config2, totalCostUsd);
|
|
22475
22510
|
}
|
|
22476
22511
|
const proposalSettled = await Promise.allSettled(sessions.map(({ session }) => session.prompt(prompt)));
|
|
@@ -22486,8 +22521,22 @@ class DebateSession {
|
|
|
22486
22521
|
}
|
|
22487
22522
|
}
|
|
22488
22523
|
if (successfulSessions.length < 2) {
|
|
22524
|
+
logger?.warn("debate", "debate:fallback", {
|
|
22525
|
+
storyId: this.storyId,
|
|
22526
|
+
stage: this.stage,
|
|
22527
|
+
reason: "fewer than 2 proposal rounds succeeded"
|
|
22528
|
+
});
|
|
22489
22529
|
return buildFailedResult(this.storyId, this.stage, config2, totalCostUsd);
|
|
22490
22530
|
}
|
|
22531
|
+
for (let i = 0;i < successfulSessions.length; i++) {
|
|
22532
|
+
const s = successfulSessions[i];
|
|
22533
|
+
logger?.info("debate", "debate:proposal", {
|
|
22534
|
+
storyId: this.storyId,
|
|
22535
|
+
stage: this.stage,
|
|
22536
|
+
debaterIndex: i,
|
|
22537
|
+
agent: s.entry.debater.agent
|
|
22538
|
+
});
|
|
22539
|
+
}
|
|
22491
22540
|
let critiqueOutputs = [];
|
|
22492
22541
|
if (config2.rounds > 1) {
|
|
22493
22542
|
const proposalOutputs2 = successfulSessions.map((s) => s.output);
|
|
@@ -22506,6 +22555,11 @@ class DebateSession {
|
|
|
22506
22555
|
debater: s.entry.debater,
|
|
22507
22556
|
output: s.output
|
|
22508
22557
|
}));
|
|
22558
|
+
logger?.info("debate", "debate:result", {
|
|
22559
|
+
storyId: this.storyId,
|
|
22560
|
+
stage: this.stage,
|
|
22561
|
+
outcome
|
|
22562
|
+
});
|
|
22509
22563
|
return {
|
|
22510
22564
|
storyId: this.storyId,
|
|
22511
22565
|
stage: this.stage,
|
|
@@ -22534,16 +22588,40 @@ class DebateSession {
|
|
|
22534
22588
|
}
|
|
22535
22589
|
resolved.push({ debater, adapter });
|
|
22536
22590
|
}
|
|
22537
|
-
|
|
22591
|
+
logger?.info("debate", "debate:start", {
|
|
22592
|
+
storyId: this.storyId,
|
|
22593
|
+
stage: this.stage,
|
|
22594
|
+
debaters: resolved.map((r) => r.debater.agent)
|
|
22595
|
+
});
|
|
22596
|
+
const proposalSettled = await Promise.allSettled(resolved.map(({ debater, adapter }) => adapter.complete(prompt, { model: resolveDebaterModel(debater, this.config) }).then((output) => ({ debater, adapter, output, cost: 0 }))));
|
|
22538
22597
|
const successful = proposalSettled.filter((r) => r.status === "fulfilled").map((r) => r.value);
|
|
22539
22598
|
for (const r of proposalSettled) {
|
|
22540
22599
|
if (r.status === "fulfilled") {
|
|
22541
22600
|
totalCostUsd += r.value.cost;
|
|
22542
22601
|
}
|
|
22543
22602
|
}
|
|
22603
|
+
for (let i = 0;i < successful.length; i++) {
|
|
22604
|
+
logger?.info("debate", "debate:proposal", {
|
|
22605
|
+
storyId: this.storyId,
|
|
22606
|
+
stage: this.stage,
|
|
22607
|
+
debaterIndex: i,
|
|
22608
|
+
agent: successful[i].debater.agent,
|
|
22609
|
+
model: resolveDebaterModel(successful[i].debater, this.config)
|
|
22610
|
+
});
|
|
22611
|
+
}
|
|
22544
22612
|
if (successful.length < 2) {
|
|
22545
22613
|
if (successful.length === 1) {
|
|
22614
|
+
logger?.warn("debate", "debate:fallback", {
|
|
22615
|
+
storyId: this.storyId,
|
|
22616
|
+
stage: this.stage,
|
|
22617
|
+
reason: "only 1 debater succeeded"
|
|
22618
|
+
});
|
|
22546
22619
|
const solo = successful[0];
|
|
22620
|
+
logger?.info("debate", "debate:result", {
|
|
22621
|
+
storyId: this.storyId,
|
|
22622
|
+
stage: this.stage,
|
|
22623
|
+
outcome: "passed"
|
|
22624
|
+
});
|
|
22547
22625
|
return {
|
|
22548
22626
|
storyId: this.storyId,
|
|
22549
22627
|
stage: this.stage,
|
|
@@ -22557,8 +22635,20 @@ class DebateSession {
|
|
|
22557
22635
|
}
|
|
22558
22636
|
if (resolved.length > 0) {
|
|
22559
22637
|
const { adapter: fallbackAdapter, debater: fallbackDebater } = resolved[0];
|
|
22638
|
+
logger?.warn("debate", "debate:fallback", {
|
|
22639
|
+
storyId: this.storyId,
|
|
22640
|
+
stage: this.stage,
|
|
22641
|
+
reason: "all debaters failed \u2014 retrying with first adapter"
|
|
22642
|
+
});
|
|
22560
22643
|
try {
|
|
22561
|
-
const fallbackOutput = await fallbackAdapter.complete(prompt, {
|
|
22644
|
+
const fallbackOutput = await fallbackAdapter.complete(prompt, {
|
|
22645
|
+
model: resolveDebaterModel(fallbackDebater, this.config)
|
|
22646
|
+
});
|
|
22647
|
+
logger?.info("debate", "debate:result", {
|
|
22648
|
+
storyId: this.storyId,
|
|
22649
|
+
stage: this.stage,
|
|
22650
|
+
outcome: "passed"
|
|
22651
|
+
});
|
|
22562
22652
|
return {
|
|
22563
22653
|
storyId: this.storyId,
|
|
22564
22654
|
stage: this.stage,
|
|
@@ -22577,7 +22667,7 @@ class DebateSession {
|
|
|
22577
22667
|
if (config2.rounds > 1) {
|
|
22578
22668
|
const proposalOutputs2 = successful.map((p) => p.output);
|
|
22579
22669
|
const critiqueSettled = await Promise.allSettled(successful.map(({ debater, adapter }, i) => adapter.complete(buildCritiquePrompt(prompt, proposalOutputs2, i), {
|
|
22580
|
-
model: debater.
|
|
22670
|
+
model: resolveDebaterModel(debater, this.config)
|
|
22581
22671
|
})));
|
|
22582
22672
|
for (const r of critiqueSettled) {
|
|
22583
22673
|
if (r.status === "fulfilled") {
|
|
@@ -22593,6 +22683,11 @@ class DebateSession {
|
|
|
22593
22683
|
debater: p.debater,
|
|
22594
22684
|
output: p.output
|
|
22595
22685
|
}));
|
|
22686
|
+
logger?.info("debate", "debate:result", {
|
|
22687
|
+
storyId: this.storyId,
|
|
22688
|
+
stage: this.stage,
|
|
22689
|
+
outcome
|
|
22690
|
+
});
|
|
22596
22691
|
return {
|
|
22597
22692
|
storyId: this.storyId,
|
|
22598
22693
|
stage: this.stage,
|
|
@@ -22604,7 +22699,7 @@ class DebateSession {
|
|
|
22604
22699
|
totalCostUsd
|
|
22605
22700
|
};
|
|
22606
22701
|
}
|
|
22607
|
-
async resolve(proposalOutputs, critiqueOutputs,
|
|
22702
|
+
async resolve(proposalOutputs, critiqueOutputs, _successful) {
|
|
22608
22703
|
const resolverConfig = this.stageConfig.resolver;
|
|
22609
22704
|
if (resolverConfig.type === "majority-fail-closed" || resolverConfig.type === "majority-fail-open") {
|
|
22610
22705
|
return majorityResolver(proposalOutputs, resolverConfig.type === "majority-fail-open");
|
|
@@ -22631,6 +22726,7 @@ var RESOLVER_FALLBACK_AGENT = "synthesis", _debateSessionDeps;
|
|
|
22631
22726
|
var init_session = __esm(() => {
|
|
22632
22727
|
init_spawn_client();
|
|
22633
22728
|
init_registry();
|
|
22729
|
+
init_config();
|
|
22634
22730
|
init_logger2();
|
|
22635
22731
|
init_resolvers();
|
|
22636
22732
|
_debateSessionDeps = {
|
|
@@ -26276,7 +26372,8 @@ async function runSemanticReview(workdir, storyGitRef, story, semanticConfig, mo
|
|
|
26276
26372
|
const debateSession = _semanticDeps.createDebateSession({
|
|
26277
26373
|
storyId: story.id,
|
|
26278
26374
|
stage: "review",
|
|
26279
|
-
stageConfig: reviewStageConfig
|
|
26375
|
+
stageConfig: reviewStageConfig,
|
|
26376
|
+
config: naxConfig
|
|
26280
26377
|
});
|
|
26281
26378
|
const debateResult = await debateSession.run(prompt);
|
|
26282
26379
|
let passCount = 0;
|
|
@@ -69453,78 +69550,75 @@ async function planCommand(workdir, config2, options) {
|
|
|
69453
69550
|
autoModel = resolveModelForAgent2(config2.models, defaultAgent, planTier, defaultAgent).model;
|
|
69454
69551
|
}
|
|
69455
69552
|
} catch {}
|
|
69456
|
-
|
|
69457
|
-
|
|
69458
|
-
|
|
69459
|
-
|
|
69460
|
-
|
|
69461
|
-
feature: options.feature,
|
|
69462
|
-
timeoutSeconds
|
|
69463
|
-
});
|
|
69464
|
-
const pidRegistry = new PidRegistry(workdir);
|
|
69465
|
-
try {
|
|
69466
|
-
await adapter.plan({
|
|
69467
|
-
prompt,
|
|
69553
|
+
const runSingleAgentPlan = async () => {
|
|
69554
|
+
if (isAcp) {
|
|
69555
|
+
logger?.info("plan", "Starting ACP auto planning session", {
|
|
69556
|
+
agent: agentName,
|
|
69557
|
+
model: autoModel ?? config2?.plan?.model ?? "balanced",
|
|
69468
69558
|
workdir,
|
|
69469
|
-
|
|
69470
|
-
timeoutSeconds
|
|
69471
|
-
config: config2,
|
|
69472
|
-
modelTier: config2?.plan?.model ?? "balanced",
|
|
69473
|
-
dangerouslySkipPermissions: resolvePermissions(config2, "plan").skipPermissions,
|
|
69474
|
-
maxInteractionTurns: config2?.agent?.maxInteractionTurns,
|
|
69475
|
-
featureName: options.feature,
|
|
69476
|
-
pidRegistry,
|
|
69477
|
-
sessionRole: "plan"
|
|
69478
|
-
});
|
|
69479
|
-
} finally {
|
|
69480
|
-
await pidRegistry.killAll().catch(() => {});
|
|
69481
|
-
}
|
|
69482
|
-
if (!_planDeps.existsSync(outputPath)) {
|
|
69483
|
-
throw new Error(`[plan] ACP agent did not write PRD to ${outputPath}. Check agent logs for errors.`);
|
|
69484
|
-
}
|
|
69485
|
-
rawResponse = await _planDeps.readFile(outputPath);
|
|
69486
|
-
} else {
|
|
69487
|
-
const debateEnabled = config2?.debate?.enabled && config2?.debate?.stages?.plan?.enabled;
|
|
69488
|
-
if (debateEnabled) {
|
|
69489
|
-
const planStageConfig = config2.debate?.stages.plan;
|
|
69490
|
-
const debateSession = _planDeps.createDebateSession({
|
|
69491
|
-
storyId: options.feature,
|
|
69492
|
-
stage: "plan",
|
|
69493
|
-
stageConfig: planStageConfig
|
|
69559
|
+
feature: options.feature,
|
|
69560
|
+
timeoutSeconds
|
|
69494
69561
|
});
|
|
69495
|
-
const
|
|
69496
|
-
|
|
69497
|
-
|
|
69498
|
-
|
|
69499
|
-
logger?.warn("debate", "All debaters failed \u2014 falling back to single agent", {
|
|
69500
|
-
stage: "debate",
|
|
69501
|
-
event: "fallback"
|
|
69502
|
-
});
|
|
69503
|
-
rawResponse = await adapter.complete(prompt, {
|
|
69504
|
-
model: autoModel,
|
|
69505
|
-
jsonMode: true,
|
|
69562
|
+
const pidRegistry = new PidRegistry(workdir);
|
|
69563
|
+
try {
|
|
69564
|
+
await adapter.plan({
|
|
69565
|
+
prompt,
|
|
69506
69566
|
workdir,
|
|
69567
|
+
interactive: false,
|
|
69568
|
+
timeoutSeconds,
|
|
69507
69569
|
config: config2,
|
|
69570
|
+
modelTier: config2?.plan?.model ?? "balanced",
|
|
69571
|
+
dangerouslySkipPermissions: resolvePermissions(config2, "plan").skipPermissions,
|
|
69572
|
+
maxInteractionTurns: config2?.agent?.maxInteractionTurns,
|
|
69508
69573
|
featureName: options.feature,
|
|
69574
|
+
pidRegistry,
|
|
69509
69575
|
sessionRole: "plan"
|
|
69510
69576
|
});
|
|
69577
|
+
} finally {
|
|
69578
|
+
await pidRegistry.killAll().catch(() => {});
|
|
69511
69579
|
}
|
|
69512
|
-
|
|
69513
|
-
|
|
69514
|
-
|
|
69515
|
-
|
|
69516
|
-
workdir,
|
|
69517
|
-
config: config2,
|
|
69518
|
-
featureName: options.feature,
|
|
69519
|
-
sessionRole: "plan"
|
|
69520
|
-
});
|
|
69580
|
+
if (!_planDeps.existsSync(outputPath)) {
|
|
69581
|
+
throw new Error(`[plan] ACP agent did not write PRD to ${outputPath}. Check agent logs for errors.`);
|
|
69582
|
+
}
|
|
69583
|
+
return await _planDeps.readFile(outputPath);
|
|
69521
69584
|
}
|
|
69585
|
+
let result = await adapter.complete(prompt, {
|
|
69586
|
+
model: autoModel,
|
|
69587
|
+
jsonMode: true,
|
|
69588
|
+
workdir,
|
|
69589
|
+
config: config2,
|
|
69590
|
+
featureName: options.feature,
|
|
69591
|
+
sessionRole: "plan"
|
|
69592
|
+
});
|
|
69522
69593
|
try {
|
|
69523
|
-
const envelope = JSON.parse(
|
|
69594
|
+
const envelope = JSON.parse(result);
|
|
69524
69595
|
if (envelope?.type === "result" && typeof envelope?.result === "string") {
|
|
69525
|
-
|
|
69596
|
+
result = envelope.result;
|
|
69526
69597
|
}
|
|
69527
69598
|
} catch {}
|
|
69599
|
+
return result;
|
|
69600
|
+
};
|
|
69601
|
+
const debateEnabled = config2?.debate?.enabled && config2?.debate?.stages?.plan?.enabled;
|
|
69602
|
+
if (debateEnabled) {
|
|
69603
|
+
const planStageConfig = config2?.debate?.stages.plan;
|
|
69604
|
+
const debateSession = _planDeps.createDebateSession({
|
|
69605
|
+
storyId: options.feature,
|
|
69606
|
+
stage: "plan",
|
|
69607
|
+
stageConfig: planStageConfig,
|
|
69608
|
+
config: config2
|
|
69609
|
+
});
|
|
69610
|
+
const debateResult = await debateSession.run(prompt);
|
|
69611
|
+
if (debateResult.outcome !== "failed" && debateResult.output) {
|
|
69612
|
+
rawResponse = debateResult.output;
|
|
69613
|
+
} else {
|
|
69614
|
+
logger?.warn("debate", "All debaters failed \u2014 falling back to single agent", {
|
|
69615
|
+
stage: "debate",
|
|
69616
|
+
event: "fallback"
|
|
69617
|
+
});
|
|
69618
|
+
rawResponse = await runSingleAgentPlan();
|
|
69619
|
+
}
|
|
69620
|
+
} else {
|
|
69621
|
+
rawResponse = await runSingleAgentPlan();
|
|
69528
69622
|
}
|
|
69529
69623
|
} else {
|
|
69530
69624
|
const prompt = buildPlanningPrompt(specContent, codebaseContext, outputPath, relativePackages, packageDetails, config2?.project);
|