@nathapp/nax 0.67.7 → 0.67.8

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.
Files changed (2) hide show
  1. package/dist/nax.js +119 -28
  2. package/package.json +1 -1
package/dist/nax.js CHANGED
@@ -21312,7 +21312,7 @@ class AgentManager {
21312
21312
  return { result, fallbacks, finalBundle: updatedBundle, finalPrompt, finalAgent: currentAgent };
21313
21313
  }
21314
21314
  const isFailStale = result.adapterFailure?.outcome === "fail-stale";
21315
- const maxStaleRetries = this._config.agent?.idleWatchdog?.maxRetryAttempts ?? 1;
21315
+ const maxStaleRetries = this._config.agent?.idleWatchdog?.maxRetryAttempts ?? 3;
21316
21316
  if (isFailStale && result.adapterFailure?.retriable && staleRetryAttempts < maxStaleRetries) {
21317
21317
  staleRetryAttempts++;
21318
21318
  const retryHop = {
@@ -21330,7 +21330,8 @@ class AgentManager {
21330
21330
  logger?.info("agent-manager", "fail-stale: immediate same-agent retry", {
21331
21331
  storyId: request.runOptions.storyId,
21332
21332
  attempt: staleRetryAttempts,
21333
- agent: currentAgent
21333
+ agent: currentAgent,
21334
+ reason: result.adapterFailure?.reason
21334
21335
  });
21335
21336
  currentHopKind = { kind: "stale-retry", attempt: staleRetryAttempts };
21336
21337
  continue;
@@ -21461,6 +21462,8 @@ class AgentManager {
21461
21462
  const primaryAgent = primaryAgentOverride ?? this.getDefault();
21462
21463
  let currentAgent = primaryAgent;
21463
21464
  let hopsSoFar = 0;
21465
+ let staleRetryAttempts = 0;
21466
+ const maxStaleRetries = this._config.agent?.idleWatchdog?.maxRetryAttempts ?? 3;
21464
21467
  const _opStartMs = Date.now();
21465
21468
  const _agentChain = [primaryAgent];
21466
21469
  let _finalStatus = "error";
@@ -21497,10 +21500,45 @@ class AgentManager {
21497
21500
  };
21498
21501
  }
21499
21502
  _totalCostUsd += result.estimatedCostUsd;
21503
+ if (!result.adapterFailure && !result.output?.trim()) {
21504
+ result = {
21505
+ ...result,
21506
+ adapterFailure: {
21507
+ outcome: "fail-stale",
21508
+ category: "availability",
21509
+ retriable: true,
21510
+ message: "[completeWithFallback] agent returned no output",
21511
+ reason: "empty-output"
21512
+ }
21513
+ };
21514
+ }
21500
21515
  if (!result.adapterFailure) {
21501
21516
  _finalStatus = "ok";
21502
21517
  return { result, fallbacks };
21503
21518
  }
21519
+ const isFailStale = result.adapterFailure.outcome === "fail-stale";
21520
+ if (isFailStale && result.adapterFailure.retriable && staleRetryAttempts < maxStaleRetries) {
21521
+ staleRetryAttempts++;
21522
+ const retryHop = {
21523
+ storyId: options.storyId,
21524
+ priorAgent: currentAgent,
21525
+ newAgent: currentAgent,
21526
+ hop: staleRetryAttempts,
21527
+ outcome: result.adapterFailure.outcome,
21528
+ category: result.adapterFailure.category,
21529
+ timestamp: new Date().toISOString(),
21530
+ costUsd: result.estimatedCostUsd
21531
+ };
21532
+ fallbacks.push(retryHop);
21533
+ this._emitter.emit("onSwapAttempt", retryHop);
21534
+ logger?.info("agent-manager", "completeWithFallback: fail-stale same-agent retry", {
21535
+ storyId: options.storyId,
21536
+ attempt: staleRetryAttempts,
21537
+ agent: currentAgent,
21538
+ reason: result.adapterFailure.reason
21539
+ });
21540
+ continue;
21541
+ }
21504
21542
  if (!this.shouldSwap(result.adapterFailure, hopsSoFar, true)) {
21505
21543
  _finalStatus = hopsSoFar > 0 ? "exhausted" : "error";
21506
21544
  return { result, fallbacks };
@@ -34951,6 +34989,53 @@ var init_acceptance_fix = __esm(() => {
34951
34989
  };
34952
34990
  });
34953
34991
 
34992
+ // src/review/requote-response.ts
34993
+ function parseRequoteResponse(output) {
34994
+ const parsed = tryParseLLMJson(output);
34995
+ if (!isRecord(parsed))
34996
+ return null;
34997
+ const canonical = extractCanonical(parsed);
34998
+ if (canonical)
34999
+ return canonical;
35000
+ const findings = parsed.findings;
35001
+ if (!Array.isArray(findings) || findings.length !== 1)
35002
+ return null;
35003
+ const finding = findings[0];
35004
+ if (!isRecord(finding))
35005
+ return null;
35006
+ return extractCanonical(finding.verifiedBy) ?? extractCanonical(finding);
35007
+ }
35008
+ function extractCanonical(value) {
35009
+ if (!isRecord(value))
35010
+ return null;
35011
+ if (typeof value.file !== "string" || typeof value.observed !== "string")
35012
+ return null;
35013
+ const file3 = value.file.trim();
35014
+ if (!file3)
35015
+ return null;
35016
+ const line = coerceLine(value.line);
35017
+ if (line === null)
35018
+ return null;
35019
+ return {
35020
+ file: file3,
35021
+ line: line === undefined ? undefined : line,
35022
+ observed: value.observed
35023
+ };
35024
+ }
35025
+ function coerceLine(value) {
35026
+ if (value == null)
35027
+ return;
35028
+ if (typeof value === "number")
35029
+ return value;
35030
+ if (typeof value === "string" && /^\d+$/.test(value))
35031
+ return Number.parseInt(value, 10);
35032
+ return null;
35033
+ }
35034
+ function isRecord(value) {
35035
+ return typeof value === "object" && value !== null && !Array.isArray(value);
35036
+ }
35037
+ var init_requote_response = () => {};
35038
+
34954
35039
  // src/operations/semantic-review.ts
34955
35040
  async function requoteBlockingFindings(findings, ctx) {
34956
35041
  const threshold = ctx.input.blockingThreshold ?? "error";
@@ -35021,18 +35106,6 @@ async function requoteBlockingFindings(findings, ctx) {
35021
35106
  }
35022
35107
  return { findings: next, changed, extraCostUsd };
35023
35108
  }
35024
- function parseRequoteResponse(output) {
35025
- const parsed = tryParseLLMJson(output);
35026
- if (!parsed || typeof parsed.file !== "string" || typeof parsed.observed !== "string")
35027
- return null;
35028
- if (parsed.line != null && typeof parsed.line !== "number")
35029
- return null;
35030
- return {
35031
- file: parsed.file,
35032
- line: typeof parsed.line === "number" ? parsed.line : undefined,
35033
- observed: parsed.observed
35034
- };
35035
- }
35036
35109
  var FAIL_OPEN2, SEMANTIC_REQUOTE_RECOVERED_EVENT = "review.semantic.finding.requote_recovered", SEMANTIC_REQUOTE_FAILED_EVENT = "review.semantic.finding.requote_failed", DEFAULT_MAX_REQUOTES = 5, semanticReviewHopBody = async (initialPrompt, ctx) => {
35037
35110
  const turn = await ctx.sendWithParseRetry(initialPrompt);
35038
35111
  const parsed = validateLLMShape(tryParseLLMJson(turn.output));
@@ -35041,9 +35114,10 @@ var FAIL_OPEN2, SEMANTIC_REQUOTE_RECOVERED_EVENT = "review.semantic.finding.requ
35041
35114
  const requoted = await requoteBlockingFindings(parsed.findings, ctx);
35042
35115
  if (!requoted.changed)
35043
35116
  return turn;
35117
+ const passed = !requoted.findings.some((finding) => isBlockingSeverity(finding.severity, ctx.input.blockingThreshold ?? "error"));
35044
35118
  return {
35045
35119
  ...turn,
35046
- output: JSON.stringify({ passed: parsed.passed, findings: requoted.findings }),
35120
+ output: JSON.stringify({ passed, findings: requoted.findings }),
35047
35121
  estimatedCostUsd: (turn.estimatedCostUsd ?? 0) + requoted.extraCostUsd
35048
35122
  };
35049
35123
  }, semanticReviewOp;
@@ -35052,6 +35126,7 @@ var init_semantic_review = __esm(() => {
35052
35126
  init_config();
35053
35127
  init_logger2();
35054
35128
  init_prompts();
35129
+ init_requote_response();
35055
35130
  init_semantic_evidence();
35056
35131
  init_semantic_helpers();
35057
35132
  FAIL_OPEN2 = { passed: true, findings: [], failOpen: true };
@@ -39743,6 +39818,7 @@ var init_review = __esm(() => {
39743
39818
  init_diff_utils();
39744
39819
  init_finding_projection();
39745
39820
  init_runner2();
39821
+ init_requote_response();
39746
39822
  init_severity();
39747
39823
  });
39748
39824
 
@@ -41251,8 +41327,8 @@ var init_prompts = __esm(() => {
41251
41327
  // src/operations/build-hop-callback.ts
41252
41328
  function turnResultToAgentResult(r) {
41253
41329
  return {
41254
- success: true,
41255
- exitCode: 0,
41330
+ success: !r.adapterFailure,
41331
+ exitCode: r.adapterFailure ? 1 : 0,
41256
41332
  output: r.output,
41257
41333
  rateLimited: false,
41258
41334
  durationMs: 0,
@@ -41260,7 +41336,8 @@ function turnResultToAgentResult(r) {
41260
41336
  exactCostUsd: r.exactCostUsd,
41261
41337
  tokenUsage: r.tokenUsage,
41262
41338
  protocolIds: r.protocolIds,
41263
- internalRoundTrips: r.internalRoundTrips
41339
+ internalRoundTrips: r.internalRoundTrips,
41340
+ ...r.adapterFailure ? { adapterFailure: r.adapterFailure } : {}
41264
41341
  };
41265
41342
  }
41266
41343
  function buildHopCallback(ctx, sessionId, _initialOptions) {
@@ -41629,13 +41706,26 @@ async function callOp(ctx, op, input) {
41629
41706
  let lastRetryTurn;
41630
41707
  const sendWithFileOutput = async (promptText, bodyCtx) => {
41631
41708
  const turn = await bodyCtx.send(promptText);
41632
- if (!fileOutputPath)
41633
- return turn;
41634
- const fileContent = await _callOpDeps.readFileOutput(fileOutputPath);
41635
- if (fileContent === null) {
41636
- return turn;
41709
+ let effective = turn;
41710
+ if (fileOutputPath) {
41711
+ const fileContent = await _callOpDeps.readFileOutput(fileOutputPath);
41712
+ if (fileContent !== null) {
41713
+ effective = { ...turn, output: fileContent };
41714
+ }
41715
+ }
41716
+ if (!effective.output?.trim() && !effective.adapterFailure) {
41717
+ return {
41718
+ ...effective,
41719
+ adapterFailure: {
41720
+ outcome: "fail-stale",
41721
+ category: "availability",
41722
+ retriable: true,
41723
+ message: `[${op.name}] agent returned no output`,
41724
+ reason: "empty-output"
41725
+ }
41726
+ };
41637
41727
  }
41638
- return { ...turn, output: fileContent };
41728
+ return effective;
41639
41729
  };
41640
41730
  const sendWithParseRetry = async (initialPrompt, bodyCtx) => {
41641
41731
  retryFallback = undefined;
@@ -43828,7 +43918,8 @@ class SessionManager {
43828
43918
  category: "availability",
43829
43919
  outcome: "fail-stale",
43830
43920
  retriable: true,
43831
- message: "idle watchdog cancelled session \u2014 no stream activity"
43921
+ message: "idle watchdog cancelled session \u2014 no stream activity",
43922
+ reason: "idle-watchdog"
43832
43923
  });
43833
43924
  }
43834
43925
  }
@@ -56753,7 +56844,7 @@ var package_default;
56753
56844
  var init_package = __esm(() => {
56754
56845
  package_default = {
56755
56846
  name: "@nathapp/nax",
56756
- version: "0.67.7",
56847
+ version: "0.67.8",
56757
56848
  description: "AI Coding Agent Orchestrator \u2014 loops until done",
56758
56849
  type: "module",
56759
56850
  bin: {
@@ -56848,8 +56939,8 @@ var init_version = __esm(() => {
56848
56939
  NAX_VERSION = package_default.version;
56849
56940
  NAX_COMMIT = (() => {
56850
56941
  try {
56851
- if (/^[0-9a-f]{6,10}$/.test("1c26c38d"))
56852
- return "1c26c38d";
56942
+ if (/^[0-9a-f]{6,10}$/.test("1e88267c"))
56943
+ return "1e88267c";
56853
56944
  } catch {}
56854
56945
  try {
56855
56946
  const result = Bun.spawnSync(["git", "rev-parse", "--short", "HEAD"], {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nathapp/nax",
3
- "version": "0.67.7",
3
+ "version": "0.67.8",
4
4
  "description": "AI Coding Agent Orchestrator — loops until done",
5
5
  "type": "module",
6
6
  "bin": {