nexrall-code 0.5.103 → 0.5.105

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/index.js +47 -6
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -9973,6 +9973,11 @@ var require_client = __commonJS({
9973
9973
  var MAX_RETRIES = 5;
9974
9974
  var RETRY_BASE_MS = 1e3;
9975
9975
  var RETRY_MAX_MS = 3e4;
9976
+ var HOUSEKEEPING_FRAMES = /* @__PURE__ */ new Set([
9977
+ "resumable",
9978
+ "context_warning",
9979
+ "tool_progress"
9980
+ ]);
9976
9981
  var MAX_TOTAL_RETRY_MS = (() => {
9977
9982
  const raw = Number(process.env.NEXRALL_MAX_RETRY_MS);
9978
9983
  return Number.isFinite(raw) && raw > 0 ? raw : 5 * 6e4;
@@ -10063,7 +10068,12 @@ var require_client = __commonJS({
10063
10068
  }
10064
10069
  ];
10065
10070
  };
10066
- const isRetryableStreamMsg = (m2) => /overloaded|rate.?limit|temporarily|unavailable|try again|internal server error/i.test(String(m2 ?? ""));
10071
+ const isRetryableStreamMsg = (m2) => {
10072
+ const s2 = String(m2 ?? "");
10073
+ if (/403[\s\S]*"type"\s*:\s*"forbidden"/i.test(s2))
10074
+ return true;
10075
+ return /overloaded|rate.?limit|temporarily|unavailable|try again|internal server error/i.test(s2);
10076
+ };
10067
10077
  let didRetry = false;
10068
10078
  let totalAttemptsMade = 0;
10069
10079
  let retryDeadline = 0;
@@ -10335,7 +10345,8 @@ var require_client = __commonJS({
10335
10345
  }
10336
10346
  const evt = parsed;
10337
10347
  lastProgressAt = Date.now();
10338
- sawModelEvent = true;
10348
+ if (!HOUSEKEEPING_FRAMES.has(evt.type))
10349
+ sawModelEvent = true;
10339
10350
  clearRetryIfNeeded();
10340
10351
  switch (evt.type) {
10341
10352
  case "text": {
@@ -10461,6 +10472,7 @@ var require_client = __commonJS({
10461
10472
  case "error": {
10462
10473
  const message = typeof evt.message === "string" ? evt.message : typeof evt.error === "string" ? evt.error : "Unknown SSE error";
10463
10474
  const notResumable = evt.notResumable === true;
10475
+ const serverSaysRetryable = evt.retryable === true;
10464
10476
  if (haveCompleteMessage()) {
10465
10477
  clearInterval(heartbeatWatchdog);
10466
10478
  onEvent({ type: "error", message });
@@ -10469,7 +10481,7 @@ var require_client = __commonJS({
10469
10481
  clearInterval(heartbeatWatchdog);
10470
10482
  stream.destroy?.();
10471
10483
  reject(Object.assign(tagTransient(new Error(message)), { forceRestart: true }));
10472
- } else if (isRetryableStreamMsg(message) && (!emittedToCaller || allowRestartAfterRender)) {
10484
+ } else if ((serverSaysRetryable || isRetryableStreamMsg(message)) && (!emittedToCaller || allowRestartAfterRender)) {
10473
10485
  clearInterval(heartbeatWatchdog);
10474
10486
  stream.destroy?.();
10475
10487
  reject(tagTransient(new Error(message)));
@@ -10494,7 +10506,8 @@ var require_client = __commonJS({
10494
10506
  });
10495
10507
  stream.on("end", () => {
10496
10508
  clearInterval(heartbeatWatchdog);
10497
- if (!sawModelEvent && !completedMessage) {
10509
+ const producedNothing = !completedMessage && textParts.length === 0 && toolUseBlocks.length === 0;
10510
+ if (producedNothing) {
10498
10511
  reject(Object.assign(new Error("Connection closed before the model responded. Retrying\u2026"), { retryable: true }));
10499
10512
  return;
10500
10513
  }
@@ -103387,7 +103400,9 @@ var require_loop = __commonJS({
103387
103400
  };
103388
103401
  }();
103389
103402
  Object.defineProperty(exports2, "__esModule", { value: true });
103390
- exports2.VERIFY_CMD_RE = exports2.WRITE_TOOL_NAMES = exports2.ToolNotAllowedError = exports2.AGENT_MEMORY_TOOL_SCHEMA = exports2.AGENT_MEMORY_TOOL = exports2._stallLimits = exports2.bashNeedsRepoLock = void 0;
103403
+ exports2.VERIFY_CMD_RE = exports2.WRITE_TOOL_NAMES = exports2.ToolNotAllowedError = exports2.AGENT_MEMORY_TOOL_SCHEMA = exports2.AGENT_MEMORY_TOOL = exports2._stallLimits = exports2._emptyTurnRetry = exports2.bashNeedsRepoLock = void 0;
103404
+ exports2.emptyTurnBackoffMs = emptyTurnBackoffMs;
103405
+ exports2.shouldRetryEmptyTurn = shouldRetryEmptyTurn;
103391
103406
  exports2.errorRoundSignature = errorRoundSignature;
103392
103407
  exports2.executeAgentMemoryWrite = executeAgentMemoryWrite;
103393
103408
  exports2.stopReasonNotice = stopReasonNotice;
@@ -103544,6 +103559,17 @@ var require_loop = __commonJS({
103544
103559
  var HARD_ITERATIONS_CAP = Infinity;
103545
103560
  var STALL_LIMIT = 8;
103546
103561
  var REPEAT_STALL_LIMIT = 12;
103562
+ var EMPTY_TURN_RETRY_LIMIT = 3;
103563
+ var EMPTY_TURN_RETRY_BASE_MS = 1e3;
103564
+ function emptyTurnBackoffMs(attempt) {
103565
+ return EMPTY_TURN_RETRY_BASE_MS * Math.pow(2, Math.max(0, attempt));
103566
+ }
103567
+ function shouldRetryEmptyTurn(stopReason, attemptsSoFar) {
103568
+ if (stopReason === "max_tokens")
103569
+ return false;
103570
+ return attemptsSoFar < EMPTY_TURN_RETRY_LIMIT;
103571
+ }
103572
+ exports2._emptyTurnRetry = { EMPTY_TURN_RETRY_LIMIT, EMPTY_TURN_RETRY_BASE_MS };
103547
103573
  function errorRoundSignature(errored) {
103548
103574
  return errored.map(({ name, error }) => `${name}:${String(error).slice(0, 200)}`).sort().join("|");
103549
103575
  }
@@ -103587,7 +103613,7 @@ var require_loop = __commonJS({
103587
103613
  return null;
103588
103614
  case "empty-response":
103589
103615
  return `
103590
- \u26A0\uFE0F The model returned an empty response, so nothing was done. This is usually a transient upstream hiccup \u2014 send "continue" to retry.
103616
+ \u26A0\uFE0F The model returned an empty response ${EMPTY_TURN_RETRY_LIMIT} times in a row, so nothing was done. This is usually a transient upstream hiccup that the agent retries by itself; it did not clear this time. Send "continue" to try again, or switch model with /model if it persists.
103591
103617
  `;
103592
103618
  case "output-limit":
103593
103619
  return `
@@ -104750,6 +104776,7 @@ ${options.nexrallMd}` : "") : options.nexrallMd;
104750
104776
  let stalledRepeatError = null;
104751
104777
  let budget = maxIterations;
104752
104778
  let iteration = 0;
104779
+ let emptyTurnRetries = 0;
104753
104780
  let filesMutatedSinceVerify = false;
104754
104781
  let ranVerificationCmd = false;
104755
104782
  let verificationNudgeSent = false;
@@ -104941,10 +104968,24 @@ ${options.nexrallMd}` : "") : options.nexrallMd;
104941
104968
  messages.push({ role: "user", content: [{ type: "text", text }] });
104942
104969
  continue;
104943
104970
  }
104971
+ if (shouldRetryEmptyTurn(assistantMessage.stopReason, emptyTurnRetries)) {
104972
+ const waitMs = emptyTurnBackoffMs(emptyTurnRetries);
104973
+ emptyTurnRetries++;
104974
+ options.onRetry?.(emptyTurnRetries, EMPTY_TURN_RETRY_LIMIT, "The model returned an empty response \u2014 retrying automatically");
104975
+ await new Promise((r2) => setTimeout(r2, waitMs));
104976
+ if (options.abortSignal?.aborted) {
104977
+ stopReason = "aborted";
104978
+ break;
104979
+ }
104980
+ options.onRetryResolved?.();
104981
+ iteration--;
104982
+ continue;
104983
+ }
104944
104984
  runSimpleHooks(hooks.PostMessageComplete, options.workDir);
104945
104985
  stopReason = assistantMessage.stopReason === "max_tokens" ? "output-limit" : "empty-response";
104946
104986
  break;
104947
104987
  }
104988
+ emptyTurnRetries = 0;
104948
104989
  const { stopReason: _stopReason, ...historyMessage } = assistantMessage;
104949
104990
  messages.push(historyMessage);
104950
104991
  const serverSideResultIds = new Set(assistantMessage.content.filter((b) => b.type === "tool_result").map((b) => b.tool_use_id).filter((id) => !!id));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nexrall-code",
3
- "version": "0.5.103",
3
+ "version": "0.5.105",
4
4
  "description": "Nexrall Code — AI coding assistant for your terminal (headless agent for scripts, CI and automation)",
5
5
  "keywords": [
6
6
  "ai",