@nathapp/nax 0.59.3 → 0.60.0-canary.1
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 +37 -23
- package/package.json +1 -1
package/dist/nax.js
CHANGED
|
@@ -21444,14 +21444,20 @@ function tryParseLLMJson(text) {
|
|
|
21444
21444
|
}
|
|
21445
21445
|
|
|
21446
21446
|
// src/debate/resolvers.ts
|
|
21447
|
-
function
|
|
21448
|
-
return
|
|
21449
|
-
|
|
21447
|
+
function buildDebaterLabel(debater) {
|
|
21448
|
+
return debater.persona ? `${debater.agent} (${debater.persona})` : debater.agent;
|
|
21449
|
+
}
|
|
21450
|
+
function buildProposalsSection(proposals, debaters) {
|
|
21451
|
+
return proposals.map((p, i) => {
|
|
21452
|
+
const label = debaters?.[i] ? buildDebaterLabel(debaters[i]) : String(i + 1);
|
|
21453
|
+
return `### Proposal ${label}
|
|
21454
|
+
${p}`;
|
|
21455
|
+
}).join(`
|
|
21450
21456
|
|
|
21451
21457
|
`);
|
|
21452
21458
|
}
|
|
21453
|
-
function buildSynthesisPrompt(proposals, critiques) {
|
|
21454
|
-
const proposalsSection = buildProposalsSection(proposals);
|
|
21459
|
+
function buildSynthesisPrompt(proposals, critiques, debaters) {
|
|
21460
|
+
const proposalsSection = buildProposalsSection(proposals, debaters);
|
|
21455
21461
|
const critiquesSection = critiques.length > 0 ? `
|
|
21456
21462
|
|
|
21457
21463
|
## Critiques
|
|
@@ -21466,8 +21472,8 @@ ${proposalsSection}${critiquesSection}
|
|
|
21466
21472
|
|
|
21467
21473
|
Please synthesize these into the best possible unified response, incorporating the strongest elements from each proposal.`;
|
|
21468
21474
|
}
|
|
21469
|
-
function buildJudgePrompt(proposals, critiques) {
|
|
21470
|
-
const proposalsSection = buildProposalsSection(proposals);
|
|
21475
|
+
function buildJudgePrompt(proposals, critiques, debaters) {
|
|
21476
|
+
const proposalsSection = buildProposalsSection(proposals, debaters);
|
|
21471
21477
|
const critiquesSection = critiques.length > 0 ? `
|
|
21472
21478
|
|
|
21473
21479
|
## Critiques
|
|
@@ -21515,7 +21521,7 @@ function majorityResolver(proposals, failOpen) {
|
|
|
21515
21521
|
return passCount > failCount ? "passed" : "failed";
|
|
21516
21522
|
}
|
|
21517
21523
|
async function synthesisResolver(proposals, critiques, opts) {
|
|
21518
|
-
const base = buildSynthesisPrompt(proposals, critiques);
|
|
21524
|
+
const base = buildSynthesisPrompt(proposals, critiques, opts.debaters);
|
|
21519
21525
|
const prompt = opts.promptSuffix ? `${base}
|
|
21520
21526
|
|
|
21521
21527
|
${opts.promptSuffix}` : base;
|
|
@@ -21527,7 +21533,7 @@ async function judgeResolver(proposals, critiques, resolverConfig, opts) {
|
|
|
21527
21533
|
if (!adapter) {
|
|
21528
21534
|
throw new Error(`[debate] Judge agent '${agentName}' not found`);
|
|
21529
21535
|
}
|
|
21530
|
-
const prompt = buildJudgePrompt(proposals, critiques);
|
|
21536
|
+
const prompt = buildJudgePrompt(proposals, critiques, opts.debaters);
|
|
21531
21537
|
return adapter.complete(prompt, opts.completeOptions);
|
|
21532
21538
|
}
|
|
21533
21539
|
var DEFAULT_FALLBACK_AGENT = "claude";
|
|
@@ -21606,7 +21612,7 @@ function resolveModelDefForDebater(debater, tier, config2) {
|
|
|
21606
21612
|
return resolveModelForAgent(configModels, debater.agent, "fast", configDefaultAgent);
|
|
21607
21613
|
}
|
|
21608
21614
|
}
|
|
21609
|
-
async function resolveOutcome(proposalOutputs, critiqueOutputs, stageConfig, config2, storyId, timeoutMs, workdir, featureName, reviewerSession, resolverContext, promptSuffix) {
|
|
21615
|
+
async function resolveOutcome(proposalOutputs, critiqueOutputs, stageConfig, config2, storyId, timeoutMs, workdir, featureName, reviewerSession, resolverContext, promptSuffix, debaters) {
|
|
21610
21616
|
const resolverConfig = stageConfig.resolver;
|
|
21611
21617
|
const logger = _debateSessionDeps.getSafeLogger();
|
|
21612
21618
|
if (reviewerSession && resolverContext) {
|
|
@@ -21675,6 +21681,7 @@ async function resolveOutcome(proposalOutputs, critiqueOutputs, stageConfig, con
|
|
|
21675
21681
|
const resolverResult = await synthesisResolver(proposalOutputs, critiqueOutputs, {
|
|
21676
21682
|
adapter,
|
|
21677
21683
|
promptSuffix,
|
|
21684
|
+
debaters,
|
|
21678
21685
|
completeOptions: {
|
|
21679
21686
|
model: resolveDebaterModel({ agent: agentName }, config2),
|
|
21680
21687
|
config: config2,
|
|
@@ -21700,6 +21707,7 @@ async function resolveOutcome(proposalOutputs, critiqueOutputs, stageConfig, con
|
|
|
21700
21707
|
const resolverResult = await judgeResolver(proposalOutputs, critiqueOutputs, resolverConfig, {
|
|
21701
21708
|
getAgent: (name) => _debateSessionDeps.getAgent(name, config2),
|
|
21702
21709
|
defaultAgentName: RESOLVER_FALLBACK_AGENT,
|
|
21710
|
+
debaters,
|
|
21703
21711
|
completeOptions: {
|
|
21704
21712
|
model: resolveDebaterModel({ agent: agentName }, config2),
|
|
21705
21713
|
config: config2,
|
|
@@ -21772,6 +21780,9 @@ function resolvePersonas(debaters, stage, autoPersona) {
|
|
|
21772
21780
|
return { ...d, persona: assigned };
|
|
21773
21781
|
});
|
|
21774
21782
|
}
|
|
21783
|
+
function buildDebaterLabel2(debater) {
|
|
21784
|
+
return debater.persona ? `${debater.agent} (${debater.persona})` : debater.agent;
|
|
21785
|
+
}
|
|
21775
21786
|
var PERSONA_FRAGMENTS, PLAN_ROTATION, REVIEW_ROTATION;
|
|
21776
21787
|
var init_personas = __esm(() => {
|
|
21777
21788
|
PERSONA_FRAGMENTS = {
|
|
@@ -21998,7 +22009,8 @@ async function runStateful(ctx, prompt) {
|
|
|
21998
22009
|
});
|
|
21999
22010
|
const debate = ctx.config?.debate;
|
|
22000
22011
|
const concurrencyLimit = debate?.maxConcurrentDebaters ?? 2;
|
|
22001
|
-
const
|
|
22012
|
+
const proposalBuilder = new DebatePromptBuilder({ taskContext: prompt, outputFormat: "", stage: ctx.stage }, { debaters: resolved.map((r) => r.debater), sessionMode: "stateful" });
|
|
22013
|
+
const proposalSettled = await allSettledBounded(resolved.map(({ debater, adapter }, debaterIdx) => () => runStatefulTurn(ctx, adapter, debater, proposalBuilder.buildProposalPrompt(debaterIdx), `debate-${ctx.stage}-${debaterIdx}`, config2.rounds > 1)), concurrencyLimit);
|
|
22002
22014
|
const successfulProposals = proposalSettled.filter((r) => r.status === "fulfilled").map((r) => r.value);
|
|
22003
22015
|
for (const r of proposalSettled) {
|
|
22004
22016
|
if (r.status === "fulfilled") {
|
|
@@ -22090,9 +22102,9 @@ async function runStateful(ctx, prompt) {
|
|
|
22090
22102
|
const proposalOutputs = successfulProposals.map((s) => s.output);
|
|
22091
22103
|
const fullResolverContext = ctx.resolverContextInput ? {
|
|
22092
22104
|
...ctx.resolverContextInput,
|
|
22093
|
-
labeledProposals: successfulProposals.map((s) => ({ debater: s.debater
|
|
22105
|
+
labeledProposals: successfulProposals.map((s) => ({ debater: buildDebaterLabel2(s.debater), output: s.output }))
|
|
22094
22106
|
} : undefined;
|
|
22095
|
-
const outcome = await resolveOutcome(proposalOutputs, critiqueOutputs, ctx.stageConfig, ctx.config, ctx.storyId, ctx.timeoutSeconds * 1000, ctx.workdir, ctx.featureName, ctx.reviewerSession, fullResolverContext);
|
|
22107
|
+
const outcome = await resolveOutcome(proposalOutputs, critiqueOutputs, ctx.stageConfig, ctx.config, ctx.storyId, ctx.timeoutSeconds * 1000, ctx.workdir, ctx.featureName, ctx.reviewerSession, fullResolverContext, undefined, successfulProposals.map((s) => s.debater));
|
|
22096
22108
|
totalCostUsd += outcome.resolverCostUsd;
|
|
22097
22109
|
const proposals = successfulProposals.map((s) => ({
|
|
22098
22110
|
debater: s.debater,
|
|
@@ -22241,9 +22253,9 @@ async function runHybrid(ctx, prompt) {
|
|
|
22241
22253
|
const critiqueOutputs = rebuttals.map((r) => r.output);
|
|
22242
22254
|
const fullResolverContext = ctx.resolverContextInput ? {
|
|
22243
22255
|
...ctx.resolverContextInput,
|
|
22244
|
-
labeledProposals: successfulProposals.map((s) => ({ debater: s.debater
|
|
22256
|
+
labeledProposals: successfulProposals.map((s) => ({ debater: buildDebaterLabel2(s.debater), output: s.output }))
|
|
22245
22257
|
} : undefined;
|
|
22246
|
-
const resolveResult = await resolveOutcome(proposalOutputs, critiqueOutputs, ctx.stageConfig, ctx.config, ctx.storyId, ctx.timeoutSeconds * 1000, ctx.workdir, ctx.featureName, ctx.reviewerSession, fullResolverContext);
|
|
22258
|
+
const resolveResult = await resolveOutcome(proposalOutputs, critiqueOutputs, ctx.stageConfig, ctx.config, ctx.storyId, ctx.timeoutSeconds * 1000, ctx.workdir, ctx.featureName, ctx.reviewerSession, fullResolverContext, undefined, successfulProposals.map((s) => s.debater));
|
|
22247
22259
|
totalCostUsd += resolveResult.resolverCostUsd;
|
|
22248
22260
|
return {
|
|
22249
22261
|
storyId: ctx.storyId,
|
|
@@ -22288,7 +22300,8 @@ async function runOneShot(ctx, prompt) {
|
|
|
22288
22300
|
});
|
|
22289
22301
|
const debate = ctx.config?.debate;
|
|
22290
22302
|
const concurrencyLimit = debate?.maxConcurrentDebaters ?? 2;
|
|
22291
|
-
const
|
|
22303
|
+
const proposalBuilder = new DebatePromptBuilder({ taskContext: prompt, outputFormat: "", stage: ctx.stage }, { debaters: resolved.map((r) => r.debater), sessionMode: "one-shot" });
|
|
22304
|
+
const proposalSettled = await allSettledBounded(resolved.map(({ debater, adapter }, i) => () => runComplete(adapter, proposalBuilder.buildProposalPrompt(i), {
|
|
22292
22305
|
model: resolveDebaterModel(debater, ctx.config),
|
|
22293
22306
|
featureName: ctx.stage,
|
|
22294
22307
|
config: ctx.config,
|
|
@@ -22393,9 +22406,9 @@ async function runOneShot(ctx, prompt) {
|
|
|
22393
22406
|
const proposalOutputs = successful.map((p) => p.output);
|
|
22394
22407
|
const fullResolverContext = ctx.resolverContextInput ? {
|
|
22395
22408
|
...ctx.resolverContextInput,
|
|
22396
|
-
labeledProposals: successful.map((p) => ({ debater: p.debater
|
|
22409
|
+
labeledProposals: successful.map((p) => ({ debater: buildDebaterLabel2(p.debater), output: p.output }))
|
|
22397
22410
|
} : undefined;
|
|
22398
|
-
const outcome = await resolveOutcome(proposalOutputs, critiqueOutputs, ctx.stageConfig, ctx.config, ctx.storyId, ctx.timeoutMs, ctx.workdir, ctx.featureName, ctx.reviewerSession, fullResolverContext);
|
|
22411
|
+
const outcome = await resolveOutcome(proposalOutputs, critiqueOutputs, ctx.stageConfig, ctx.config, ctx.storyId, ctx.timeoutMs, ctx.workdir, ctx.featureName, ctx.reviewerSession, fullResolverContext, undefined, successful.map((p) => p.debater));
|
|
22399
22412
|
totalCostUsd += outcome.resolverCostUsd;
|
|
22400
22413
|
const proposals = successful.map((p) => ({
|
|
22401
22414
|
debater: p.debater,
|
|
@@ -22554,7 +22567,7 @@ Do NOT output the JSON to the conversation. Write the file, then reply with a br
|
|
|
22554
22567
|
}
|
|
22555
22568
|
const resolverTimeoutMs = (ctx.stageConfig.timeoutSeconds ?? 600) * 1000;
|
|
22556
22569
|
const planSynthesisSuffix = "IMPORTANT: Your response must be a single valid JSON object in PRD format (with project, feature, branchName, userStories array, etc.). Do NOT wrap it in markdown fences. Output raw JSON only.";
|
|
22557
|
-
const outcome = await resolveOutcome(proposalOutputs, critiqueOutputs, ctx.stageConfig, ctx.config, ctx.storyId, resolverTimeoutMs, opts.workdir, opts.feature, undefined, undefined, planSynthesisSuffix);
|
|
22570
|
+
const outcome = await resolveOutcome(proposalOutputs, critiqueOutputs, ctx.stageConfig, ctx.config, ctx.storyId, resolverTimeoutMs, opts.workdir, opts.feature, undefined, undefined, planSynthesisSuffix, successful.map((p) => p.debater));
|
|
22558
22571
|
const winningOutput = outcome.output ?? successful[0].output;
|
|
22559
22572
|
const proposals = successful.map((p) => ({ debater: p.debater, output: p.output }));
|
|
22560
22573
|
logger?.info("debate", "debate:result", {
|
|
@@ -25782,7 +25795,8 @@ Rules:
|
|
|
25782
25795
|
- Every test MUST have real assertions that PASS when the feature is correctly implemented and FAIL when it is broken
|
|
25783
25796
|
- **Prefer behavioral tests** \u2014 import functions and call them rather than reading source files. For example, to verify "getPostRunActions() returns empty array", import PluginRegistry and call getPostRunActions(), don't grep the source file for the method name.
|
|
25784
25797
|
- **File output (REQUIRED)**: Write the acceptance test file DIRECTLY to the path shown below. Do NOT output the test code in your response. After writing the file, reply with a brief confirmation.
|
|
25785
|
-
- **Path anchor (CRITICAL)**: Write the test file to this exact path: \`${join16(options.workdir, ".nax", "features", options.featureName, resolveAcceptanceTestFile2(options.language, options.config?.acceptance?.testPath))}\`. Import from package sources using relative paths like \`../../../src/...\` (3 levels up from \`.nax/features/<name>/\` to the package root)
|
|
25798
|
+
- **Path anchor (CRITICAL)**: Write the test file to this exact path: \`${join16(options.workdir, ".nax", "features", options.featureName, resolveAcceptanceTestFile2(options.language, options.config?.acceptance?.testPath))}\`. Import from package sources using relative paths like \`../../../src/...\` (3 levels up from \`.nax/features/<name>/\` to the package root).
|
|
25799
|
+
- **Process cwd**: When spawning child processes to invoke a CLI or binary, set the working directory to the **package root** (\`join(import.meta.dir, "../../..")\`) as your default \u2014 unless your Step 2 exploration reveals the CLI uses a different working directory convention (e.g. reads config from \`~/.config/\`, or resolves paths relative to a flag value). Always check how the CLI resolves file paths before assuming.`;
|
|
25786
25800
|
const implementationSection = options.implementationContext && options.implementationContext.length > 0 ? `
|
|
25787
25801
|
|
|
25788
25802
|
## Implementation (already exists)
|
|
@@ -36362,7 +36376,7 @@ var package_default;
|
|
|
36362
36376
|
var init_package = __esm(() => {
|
|
36363
36377
|
package_default = {
|
|
36364
36378
|
name: "@nathapp/nax",
|
|
36365
|
-
version: "0.
|
|
36379
|
+
version: "0.60.0-canary.1",
|
|
36366
36380
|
description: "AI Coding Agent Orchestrator \u2014 loops until done",
|
|
36367
36381
|
type: "module",
|
|
36368
36382
|
bin: {
|
|
@@ -36442,8 +36456,8 @@ var init_version = __esm(() => {
|
|
|
36442
36456
|
NAX_VERSION = package_default.version;
|
|
36443
36457
|
NAX_COMMIT = (() => {
|
|
36444
36458
|
try {
|
|
36445
|
-
if (/^[0-9a-f]{6,10}$/.test("
|
|
36446
|
-
return "
|
|
36459
|
+
if (/^[0-9a-f]{6,10}$/.test("1de1f9cc"))
|
|
36460
|
+
return "1de1f9cc";
|
|
36447
36461
|
} catch {}
|
|
36448
36462
|
try {
|
|
36449
36463
|
const result = Bun.spawnSync(["git", "rev-parse", "--short", "HEAD"], {
|