nexrall-code 0.5.199 → 0.5.200

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 (3) hide show
  1. package/README.md +1 -1
  2. package/dist/index.js +93 -19
  3. package/package.json +2 -2
package/README.md CHANGED
@@ -80,7 +80,7 @@ Run `nex --help` for the full list.
80
80
 
81
81
  ## Issues
82
82
 
83
- Bug reports and feature requests: **[github.com/Maxrall-Inc/nexrall-issue](https://github.com/Maxrall-Inc/nexrall-issue/issues)**.
83
+ Bug reports and feature requests: **[github.com/Maxrall-Inc/nexrall-issues](https://github.com/Maxrall-Inc/nexrall-issues/issues)**.
84
84
 
85
85
  ## License
86
86
 
package/dist/index.js CHANGED
@@ -10647,6 +10647,13 @@ var require_client = __commonJS({
10647
10647
  break;
10648
10648
  }
10649
10649
  case "context_warning": {
10650
+ const message = typeof evt.message === "string" ? evt.message : "";
10651
+ onEvent({
10652
+ type: "context_warning",
10653
+ message,
10654
+ ...typeof evt.reason === "string" ? { reason: evt.reason } : {},
10655
+ ...typeof evt.trimmed === "number" ? { trimmed: evt.trimmed } : {}
10656
+ });
10650
10657
  break;
10651
10658
  }
10652
10659
  case "notice": {
@@ -24553,8 +24560,10 @@ var require_compaction = __commonJS({
24553
24560
  "../core/dist/agent/compaction.js"(exports) {
24554
24561
  "use strict";
24555
24562
  Object.defineProperty(exports, "__esModule", { value: true });
24556
- exports.CompactionUnavailableError = exports.PRUNE_KEEP_RECENT = exports.VERIFY_CMD_RE = exports.WRITE_TOOL_NAMES = exports.MAX_BODY_BYTES = exports.COMPACT_MAX_FAILURES = exports.COMPACT_MIN_RECLAIM_BYTES = exports.COMPACT_KEEP_MIN = exports._lastApiCallEndedAt = exports.PRUNE_MIN_RECLAIM_BYTES = exports.MODEL_CONTEXT_TOKENS = void 0;
24563
+ exports.BYTES_PER_TOKEN_ESTIMATE = exports.CompactionUnavailableError = exports.PRUNE_KEEP_RECENT = exports.VERIFY_CMD_RE = exports.WRITE_TOOL_NAMES = exports.MAX_BODY_BYTES = exports.COMPACT_MAX_FAILURES = exports.COMPACT_MIN_RECLAIM_BYTES = exports.COMPACT_KEEP_MIN = exports._lastApiCallEndedAt = exports.PRUNE_MIN_RECLAIM_BYTES = exports.MODEL_CONTEXT_TOKENS = void 0;
24557
24564
  exports.contextWindowFor = contextWindowFor2;
24565
+ exports.outputReserveFor = outputReserveFor;
24566
+ exports.serverMessageBudgetFor = serverMessageBudgetFor;
24558
24567
  exports.compactionLimits = compactionLimits;
24559
24568
  exports.compactionThresholds = compactionThresholds2;
24560
24569
  exports.pruneReclaimFloor = pruneReclaimFloor;
@@ -24647,17 +24656,34 @@ var require_compaction = __commonJS({
24647
24656
  return fromSettings;
24648
24657
  return void 0;
24649
24658
  }
24650
- function compactionLimits(contextWindow, settingsRaw) {
24659
+ var SERVER_ESTIMATE_RATIO = 0.875;
24660
+ var SERVER_OVERHEAD_TOKENS = 4e4;
24661
+ var SERVER_BUDGET_SAFETY = 0.9;
24662
+ var MIN_SERVER_AWARE_COMPACT = 15e3;
24663
+ function outputReserveFor(contextWindow, model) {
24664
+ return (0, modelCatalogue_1.liveMaxOutputTokensFor)(model, Math.min(128e3, Math.max(16384, Math.floor(contextWindow * 0.2))));
24665
+ }
24666
+ function serverMessageBudgetFor(contextWindow, model) {
24667
+ const hard = contextWindow - outputReserveFor(contextWindow, model) - SERVER_OVERHEAD_TOKENS - Math.floor(contextWindow * 0.03);
24668
+ return Math.max(0, hard);
24669
+ }
24670
+ function serverAwareCompactLine(contextWindow, model) {
24671
+ const converted = Math.floor(serverMessageBudgetFor(contextWindow, model) * SERVER_ESTIMATE_RATIO * SERVER_BUDGET_SAFETY);
24672
+ return Math.max(MIN_SERVER_AWARE_COMPACT, converted);
24673
+ }
24674
+ function compactionLimits(contextWindow, settingsRaw, model) {
24651
24675
  const cap = compactWindowCap(settingsRaw);
24652
24676
  const eff = cap === void 0 ? contextWindow : Math.min(contextWindow, cap);
24653
24677
  const compactFrac = envFraction("NEXRALL_COMPACT_THRESHOLD", 0);
24654
24678
  const pruneFrac = envFraction("NEXRALL_PRUNE_THRESHOLD", 0);
24655
- const compact = compactFrac ? eff * compactFrac : Math.max(eff * 0.5, eff - Math.min(COMPACT_OUTPUT_RESERVE, eff * 0.1) - COMPACT_BUFFER_TOKENS);
24679
+ let compact = compactFrac ? eff * compactFrac : Math.max(eff * 0.5, eff - Math.min(COMPACT_OUTPUT_RESERVE, eff * 0.1) - COMPACT_BUFFER_TOKENS);
24680
+ if (model !== void 0)
24681
+ compact = Math.min(compact, serverAwareCompactLine(contextWindow, model));
24656
24682
  const prune = Math.min(pruneFrac ? eff * pruneFrac : eff * DEFAULT_PRUNE_FRACTION, compact * 0.9);
24657
24683
  return { prune: Math.floor(prune), compact: Math.floor(compact) };
24658
24684
  }
24659
- function compactionThresholds2(contextWindow = 1e6, settingsRaw) {
24660
- const { prune, compact } = compactionLimits(contextWindow, settingsRaw);
24685
+ function compactionThresholds2(contextWindow = 1e6, settingsRaw, model) {
24686
+ const { prune, compact } = compactionLimits(contextWindow, settingsRaw, model);
24661
24687
  return { prune: prune / contextWindow, compact: compact / contextWindow };
24662
24688
  }
24663
24689
  exports.PRUNE_MIN_RECLAIM_BYTES = 96 * 1024;
@@ -24900,11 +24926,22 @@ ${tail}`;
24900
24926
  }
24901
24927
  return reclaimed;
24902
24928
  }
24929
+ var ORIGINAL_TASK_MARKER = "ORIGINAL TASK (verbatim \u2014 keep working toward this, do not lose sight of it):\n";
24930
+ var COMPACT_PREAMBLE_PREFIX = "[Auto-compacted ";
24903
24931
  function originalTaskText(messages) {
24904
24932
  const first = messages.find((m2) => m2.role === "user");
24905
24933
  if (!first || !Array.isArray(first.content))
24906
24934
  return "";
24907
- return first.content.filter((b) => b.type === "text" && b.text && !(0, types_1.isRuntimeContextBlock)(b)).map((b) => b.text).join("\n").trim();
24935
+ const text = first.content.filter((b) => b.type === "text" && b.text && !(0, types_1.isRuntimeContextBlock)(b)).map((b) => b.text).join("\n").trim();
24936
+ if (text.startsWith(COMPACT_PREAMBLE_PREFIX)) {
24937
+ const at = text.indexOf(ORIGINAL_TASK_MARKER);
24938
+ if (at >= 0) {
24939
+ const rest = text.slice(at + ORIGINAL_TASK_MARKER.length);
24940
+ const end = rest.search(/\n\n(PROGRESS LEDGER|Summary of the earlier conversation so far:)/);
24941
+ return (end >= 0 ? rest.slice(0, end) : rest).trim();
24942
+ }
24943
+ }
24944
+ return text;
24908
24945
  }
24909
24946
  var CompactionUnavailableError = class extends Error {
24910
24947
  constructor() {
@@ -25003,8 +25040,7 @@ Do NOT call any tools and do NOT continue the task. Reply with text only: a conc
25003
25040
  }
25004
25041
  if (!summary)
25005
25042
  return false;
25006
- const taskBlock = originalTask ? `ORIGINAL TASK (verbatim \u2014 keep working toward this, do not lose sight of it):
25007
- ${originalTask}
25043
+ const taskBlock = originalTask ? `${ORIGINAL_TASK_MARKER}${originalTask}
25008
25044
 
25009
25045
  ` : "";
25010
25046
  const ledgerText = ledger ? ledgerSummary(ledger) : "";
@@ -25053,9 +25089,9 @@ Continue the work from here.`
25053
25089
  } catch {
25054
25090
  }
25055
25091
  }
25056
- var RESUME_CHARS_PER_TOKEN = 4;
25092
+ exports.BYTES_PER_TOKEN_ESTIMATE = 4;
25057
25093
  function estimateTokensRough3(messages) {
25058
- return Math.ceil(estimateBodyBytes2(messages) / RESUME_CHARS_PER_TOKEN);
25094
+ return Math.ceil(estimateBodyBytes2(messages) / exports.BYTES_PER_TOKEN_ESTIMATE);
25059
25095
  }
25060
25096
  async function compactMessagesForResume2(messages, opts) {
25061
25097
  if (messages.length <= exports.COMPACT_KEEP_MIN + 2)
@@ -25063,10 +25099,10 @@ Continue the work from here.`
25063
25099
  const settings = (0, rules_1.loadSettings)(opts.workDir);
25064
25100
  if (!resolveAutoCompact(void 0, settings.raw))
25065
25101
  return false;
25066
- const contextWindow = (0, modelCatalogue_1.liveContextWindowFor)(opts.model, exports.MODEL_CONTEXT_TOKENS[opts.model ?? "claude-sonnet-5-5"] ?? 1e6);
25102
+ const contextWindow = contextWindowFor2(opts.model);
25067
25103
  let bodyBytes = estimateBodyBytes2(messages);
25068
25104
  let tokenGuess = estimateTokensRough3(messages);
25069
- const limits = compactionLimits(contextWindow, settings.raw);
25105
+ const limits = compactionLimits(contextWindow, settings.raw, opts.model);
25070
25106
  const overPruneThreshold = () => tokenGuess > limits.prune || bodyBytes > exports.MAX_BODY_BYTES;
25071
25107
  const overCompactThreshold = () => tokenGuess > limits.compact || bodyBytes > exports.MAX_BODY_BYTES;
25072
25108
  if (!overPruneThreshold())
@@ -26596,8 +26632,8 @@ var require_loop = __commonJS({
26596
26632
  "../core/dist/agent/loop.js"(exports) {
26597
26633
  "use strict";
26598
26634
  Object.defineProperty(exports, "__esModule", { value: true });
26599
- exports.stopReasonNotice = exports.executeAgentMemoryWrite = exports.AGENT_MEMORY_TOOL_SCHEMA = exports.AGENT_MEMORY_TOOL = exports._stallLimits = exports.errorRoundSignature = exports._emptyTurnRetry = exports.shouldRetryEmptyTurn = exports.emptyTurnBackoffMs = exports.compactMessagesForResume = exports.estimateTokensRough = exports.makeCachedSummarizer = exports.pruneOldToolResults = exports.ledgerSummary = exports.ledgerRecord = exports.createLedger = exports.transcriptOf = exports.persistRuntimeContext = exports.findSafeCutIndex = exports.VERIFY_CMD_RE = exports.allowsTestOnlyWrite = exports.WRITE_TOOL_NAMES = exports.estimateBodyBytes = exports.pruneReclaimFloor = exports.compactionThresholds = exports.compactionLimits = exports.contextWindowFor = exports.runElicitationResultHooks = exports.runElicitationHooks = exports.hasHookEventListener = exports.setHookEventListener = exports.queueHookDelivery = exports.resetHookOnceState = exports.setHookMcpCaller = exports.setHookStatusListener = exports.setHookWakeListener = exports.formatHookDeliveries = exports.hasPendingHookWake = exports.takeHookWakes = exports.drainHookDeliveries = exports.fireObserverHook = exports.fireManualPreCompactHook = exports.fireManualPostCompactHook = exports.fireNotificationHooks = exports.runPermissionRequestHooks = exports.runLifecycleHooks = exports.classifyStopFailure = exports.parsePromptHookReply = exports.loadHooks = exports.bashNeedsRepoLock = void 0;
26600
- exports.lastToolResults = exports.summariseSubTaskProgress = exports.capSubTaskText = exports.extractSubTaskText = exports.ToolNotAllowedError = exports.resolveSubtaskTimeoutMs = exports.canSpawnSubAgents = exports.intersectAllowlists = exports.noSpawnReason = exports.resolveMaxSubagentDepth = exports._sessionSubAgentCount = exports.resetSessionSubAgentBudget = exports._resetSubTaskLimiter = exports.createLimiter = exports.resolveMaxSubagentsPerSession = exports.resolveMaxConcurrentSubtasks = exports.lockPathsFor = exports.resolveMaxIterations = void 0;
26635
+ exports.AGENT_MEMORY_TOOL = exports._stallLimits = exports.errorRoundSignature = exports._emptyTurnRetry = exports.shouldRetryEmptyTurn = exports.emptyTurnBackoffMs = exports.BYTES_PER_TOKEN_ESTIMATE = exports.outputReserveFor = exports.serverMessageBudgetFor = exports.compactMessagesForResume = exports.estimateTokensRough = exports.makeCachedSummarizer = exports.pruneOldToolResults = exports.ledgerSummary = exports.ledgerRecord = exports.createLedger = exports.transcriptOf = exports.persistRuntimeContext = exports.findSafeCutIndex = exports.VERIFY_CMD_RE = exports.allowsTestOnlyWrite = exports.WRITE_TOOL_NAMES = exports.estimateBodyBytes = exports.pruneReclaimFloor = exports.compactionThresholds = exports.compactionLimits = exports.contextWindowFor = exports.runElicitationResultHooks = exports.runElicitationHooks = exports.hasHookEventListener = exports.setHookEventListener = exports.queueHookDelivery = exports.resetHookOnceState = exports.setHookMcpCaller = exports.setHookStatusListener = exports.setHookWakeListener = exports.formatHookDeliveries = exports.hasPendingHookWake = exports.takeHookWakes = exports.drainHookDeliveries = exports.fireObserverHook = exports.fireManualPreCompactHook = exports.fireManualPostCompactHook = exports.fireNotificationHooks = exports.runPermissionRequestHooks = exports.runLifecycleHooks = exports.classifyStopFailure = exports.parsePromptHookReply = exports.loadHooks = exports.bashNeedsRepoLock = void 0;
26636
+ exports.lastToolResults = exports.summariseSubTaskProgress = exports.capSubTaskText = exports.extractSubTaskText = exports.ToolNotAllowedError = exports.resolveSubtaskTimeoutMs = exports.canSpawnSubAgents = exports.intersectAllowlists = exports.noSpawnReason = exports.resolveMaxSubagentDepth = exports._sessionSubAgentCount = exports.resetSessionSubAgentBudget = exports._resetSubTaskLimiter = exports.createLimiter = exports.resolveMaxSubagentsPerSession = exports.resolveMaxConcurrentSubtasks = exports.lockPathsFor = exports.resolveMaxIterations = exports.stopReasonNotice = exports.executeAgentMemoryWrite = exports.AGENT_MEMORY_TOOL_SCHEMA = void 0;
26601
26637
  exports.dispatchSubAgent = dispatchSubAgent;
26602
26638
  exports.dispatchBackgroundSubAgent = dispatchBackgroundSubAgent;
26603
26639
  exports.dispatchForkedSubAgent = dispatchForkedSubAgent2;
@@ -26756,6 +26792,15 @@ var require_loop = __commonJS({
26756
26792
  Object.defineProperty(exports, "compactMessagesForResume", { enumerable: true, get: function() {
26757
26793
  return compaction_2.compactMessagesForResume;
26758
26794
  } });
26795
+ Object.defineProperty(exports, "serverMessageBudgetFor", { enumerable: true, get: function() {
26796
+ return compaction_2.serverMessageBudgetFor;
26797
+ } });
26798
+ Object.defineProperty(exports, "outputReserveFor", { enumerable: true, get: function() {
26799
+ return compaction_2.outputReserveFor;
26800
+ } });
26801
+ Object.defineProperty(exports, "BYTES_PER_TOKEN_ESTIMATE", { enumerable: true, get: function() {
26802
+ return compaction_2.BYTES_PER_TOKEN_ESTIMATE;
26803
+ } });
26759
26804
  var iterationPolicy_1 = require_iterationPolicy();
26760
26805
  var iterationPolicy_2 = require_iterationPolicy();
26761
26806
  Object.defineProperty(exports, "emptyTurnBackoffMs", { enumerable: true, get: function() {
@@ -27176,7 +27221,7 @@ ${ctx}
27176
27221
  const autoCompact = (0, compaction_1.resolveAutoCompact)(options.autoCompact, settings.raw);
27177
27222
  const verifyNudgeOn = (0, compaction_1.resolveVerificationNudge)(settings.raw);
27178
27223
  const contextWindow = (0, modelCatalogue_1.liveContextWindowFor)(model, compaction_1.MODEL_CONTEXT_TOKENS[model] ?? 2e5);
27179
- const compactLimits = (0, compaction_1.compactionLimits)(contextWindow, settings.raw);
27224
+ const compactLimits = (0, compaction_1.compactionLimits)(contextWindow, settings.raw, model);
27180
27225
  const readDedupe = new readDedupe_1.ReadDedupe(options.workDir);
27181
27226
  const drainBackgroundNotifications = () => depth === 0 ? options.backgroundAgents?.takeNotifications() ?? [] : [];
27182
27227
  const collectTaskEventTexts = async () => {
@@ -27213,6 +27258,9 @@ ${extra}` : extra;
27213
27258
  return texts;
27214
27259
  };
27215
27260
  let lastPromptTokens2 = 0;
27261
+ let serverTrimmed = false;
27262
+ let serverTrimNoticeShown = false;
27263
+ let contextWarnNoticeShown = false;
27216
27264
  let compacting = false;
27217
27265
  const hardCap = autoContinue ? Math.max(maxIterations, iterationPolicy_1.MAX_ITERATIONS_CEILING) : maxIterations;
27218
27266
  let stopReason = "unknown";
@@ -27243,8 +27291,9 @@ ${extra}` : extra;
27243
27291
  break;
27244
27292
  }
27245
27293
  let bodyBytes = (0, compaction_1.estimateBodyBytes)(messages);
27246
- const prunePressure = lastPromptTokens2 > compactLimits.prune;
27247
- const tokenPressure = lastPromptTokens2 > compactLimits.compact;
27294
+ const localTokens = Math.ceil(bodyBytes / compaction_1.BYTES_PER_TOKEN_ESTIMATE);
27295
+ const prunePressure = lastPromptTokens2 > compactLimits.prune || localTokens > compactLimits.prune;
27296
+ const tokenPressure = lastPromptTokens2 > compactLimits.compact || localTokens > compactLimits.compact || serverTrimmed;
27248
27297
  let bytePressure = bodyBytes > compaction_1.MAX_BODY_BYTES;
27249
27298
  if (autoCompact && !compacting && (prunePressure || bytePressure) && messages.length > compaction_1.PRUNE_KEEP_RECENT + 2) {
27250
27299
  const floor = depth === 0 ? (0, compaction_1.pruneReclaimFloor)(compaction_1._lastApiCallEndedAt.get(options.sessionId || subAgentBudget_1.PROCESS_BUDGET_KEY)) : compaction_1.PRUNE_MIN_RECLAIM_BYTES;
@@ -27275,9 +27324,12 @@ ${extra}` : extra;
27275
27324
  const reclaimed = bytesBefore - bytesAfter;
27276
27325
  if (did) {
27277
27326
  lastPromptTokens2 = 0;
27278
- const reason = bytePressure ? `body ~${(bodyBytes / (1024 * 1024)).toFixed(1)}MB` : "context window";
27327
+ serverTrimmed = false;
27279
27328
  bodyBytes = bytesAfter;
27280
27329
  bytePressure = bodyBytes > compaction_1.MAX_BODY_BYTES;
27330
+ if (isMainAgent) {
27331
+ (options.onNotice ?? options.onText)(`\u267B\uFE0F Auto-compacted this chat's earlier history to keep it within the context budget.`);
27332
+ }
27281
27333
  }
27282
27334
  if (unavailable) {
27283
27335
  } else if (did && reclaimed >= compaction_1.COMPACT_MIN_RECLAIM_BYTES) {
@@ -27340,6 +27392,24 @@ ${extra}` : extra;
27340
27392
  case "runtime_context":
27341
27393
  pendingRuntimeContext = event.text;
27342
27394
  break;
27395
+ case "context_warning": {
27396
+ if (event.reason === "overflow")
27397
+ break;
27398
+ if (event.reason === "history-trim") {
27399
+ serverTrimmed = true;
27400
+ if (isMainAgent && !serverTrimNoticeShown) {
27401
+ serverTrimNoticeShown = true;
27402
+ const what = typeof event.trimmed === "number" && event.trimmed > 0 ? `${event.trimmed} oldest message(s)` : "the oldest turns";
27403
+ (options.onNotice ?? options.onText)(`\u26A0\uFE0F This chat exceeds what ${model} can carry alongside its output budget \u2014 the server dropped ${what} from what the model saw this turn. ` + (autoCompact ? "Auto-compaction will summarise the history at the next step so it stops recurring." : "Enable autoCompact or run /compact to re-summarise the history."));
27404
+ }
27405
+ break;
27406
+ }
27407
+ if (isMainAgent && !contextWarnNoticeShown && event.message) {
27408
+ contextWarnNoticeShown = true;
27409
+ (options.onNotice ?? options.onText)(`\u26A0\uFE0F ${event.message}`);
27410
+ }
27411
+ break;
27412
+ }
27343
27413
  case "notice":
27344
27414
  options.onNotice?.(event.message);
27345
27415
  break;
@@ -106651,6 +106721,8 @@ ${text}` : "");
106651
106721
  void (0, import_code_core65.getModelCatalogue)().then((cat) => {
106652
106722
  if (!cat || !cat.isFreeTier || !cat.defaultModel)
106653
106723
  return;
106724
+ if (!cat.models.some((m2) => m2.id === cat.defaultModel))
106725
+ return;
106654
106726
  if (modelAlias === cat.defaultModel)
106655
106727
  return;
106656
106728
  const prev = resolveModelLabel(modelAlias);
@@ -106666,6 +106738,8 @@ ${text}` : "");
106666
106738
  void (0, import_code_core65.getModelCatalogue)().then((cat) => {
106667
106739
  if (!cat || cat.isFreeTier || !cat.defaultModel)
106668
106740
  return;
106741
+ if (!cat.models.some((m2) => m2.id === cat.defaultModel))
106742
+ return;
106669
106743
  if (options.modelExplicit !== false)
106670
106744
  return;
106671
106745
  if (agentRunning)
@@ -109841,7 +109915,7 @@ ${text}
109841
109915
  }
109842
109916
  const measure = measureContext(messages, parsed.all ? TOP_ALL : TOP_DEFAULT);
109843
109917
  const window2 = (0, import_code_core65.contextWindowFor)(modelAlias);
109844
- const thresholds = (0, import_code_core65.compactionThresholds)(window2);
109918
+ const thresholds = (0, import_code_core65.compactionThresholds)(window2, (0, import_code_core67.loadSettings)(workDir).raw, modelAlias);
109845
109919
  for (const line of formatContextPanel({
109846
109920
  measure,
109847
109921
  window: window2,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nexrall-code",
3
- "version": "0.5.199",
3
+ "version": "0.5.200",
4
4
  "description": "Nexrall Code — AI coding assistant for your terminal (headless agent for scripts, CI and automation)",
5
5
  "keywords": [
6
6
  "ai",
@@ -13,7 +13,7 @@
13
13
  ],
14
14
  "homepage": "https://nexrall.com",
15
15
  "bugs": {
16
- "url": "https://github.com/Maxrall-Inc/nexrall-issue/issues"
16
+ "url": "https://github.com/Maxrall-Inc/nexrall-issues/issues"
17
17
  },
18
18
  "license": "MIT",
19
19
  "type": "module",