reasonix 0.5.2 → 0.5.3

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/cli/index.js CHANGED
@@ -1816,20 +1816,26 @@ var CacheFirstLoop = class {
1816
1816
  }
1817
1817
  /**
1818
1818
  * Shrink the log by re-truncating oversized tool results to a tighter
1819
- * cap, and persist the result back to disk so the next launch doesn't
1820
- * re-inherit a fat session file. Returns a summary the TUI can
1821
- * display.
1819
+ * token cap, and persist the result back to disk so the next launch
1820
+ * doesn't re-inherit a fat session file. Returns a summary the TUI
1821
+ * can display.
1822
+ *
1823
+ * The cap is in DeepSeek V3 tokens (not chars) — so CJK text gets
1824
+ * capped at the same effective context footprint as English instead
1825
+ * of slipping past a char cap at 2× the token cost. Default 4000
1826
+ * tokens, matching the token-aware dispatch cap from 0.5.2.
1822
1827
  *
1823
1828
  * Only tool-role messages are touched (same rationale as
1824
1829
  * {@link healLoadedMessages}). User and assistant messages carry
1825
1830
  * authored intent we can't mechanically shrink without losing
1826
1831
  * meaning.
1827
1832
  */
1828
- compact(tightCapChars = 4e3) {
1833
+ compact(maxTokens = 4e3) {
1829
1834
  const before = this.log.toMessages();
1830
- const { messages, healedCount, healedFrom } = shrinkOversizedToolResults(before, tightCapChars);
1831
- const afterBytes = messages.filter((m) => m.role === "tool").reduce((s, m) => s + (typeof m.content === "string" ? m.content.length : 0), 0);
1832
- const charsSaved = healedFrom - afterBytes;
1835
+ const { messages, healedCount, tokensSaved, charsSaved } = shrinkOversizedToolResultsByTokens(
1836
+ before,
1837
+ maxTokens
1838
+ );
1833
1839
  if (healedCount > 0) {
1834
1840
  this.log.compactInPlace(messages);
1835
1841
  if (this.sessionName) {
@@ -1839,7 +1845,7 @@ var CacheFirstLoop = class {
1839
1845
  }
1840
1846
  }
1841
1847
  }
1842
- return { healedCount, charsSaved };
1848
+ return { healedCount, tokensSaved, charsSaved };
1843
1849
  }
1844
1850
  appendAndPersist(message) {
1845
1851
  this.log.append(message);
@@ -2203,30 +2209,28 @@ var CacheFirstLoop = class {
2203
2209
  const ratio = usage.promptTokens / ctxMax;
2204
2210
  if (ratio > 0.6 && ratio <= 0.8) {
2205
2211
  const before = usage.promptTokens;
2206
- const soft = this.compact(16e3);
2212
+ const soft = this.compact(4e3);
2207
2213
  if (soft.healedCount > 0) {
2208
- const approxSaved = Math.round(soft.charsSaved / 4);
2209
- const after = Math.max(0, before - approxSaved);
2214
+ const after = Math.max(0, before - soft.tokensSaved);
2210
2215
  yield {
2211
2216
  turn: this._turn,
2212
2217
  role: "warning",
2213
2218
  content: `context ${before.toLocaleString()}/${ctxMax.toLocaleString()} (${Math.round(
2214
2219
  ratio * 100
2215
- )}%) \u2014 proactively compacted ${soft.healedCount} tool result(s) to 16k, saved ~${approxSaved.toLocaleString()} tokens (now ~${after.toLocaleString()}). Staying ahead of the 80% guard.`
2220
+ )}%) \u2014 proactively compacted ${soft.healedCount} tool result(s) to 4k tokens, saved ${soft.tokensSaved.toLocaleString()} tokens (now ~${after.toLocaleString()}). Staying ahead of the 80% guard.`
2216
2221
  };
2217
2222
  }
2218
2223
  }
2219
2224
  }
2220
2225
  if (usage && usage.promptTokens / ctxMax > 0.8) {
2221
2226
  const before = usage.promptTokens;
2222
- const compactResult = this.compact(4e3);
2227
+ const compactResult = this.compact(1e3);
2223
2228
  if (compactResult.healedCount > 0) {
2224
- const approxSaved = Math.round(compactResult.charsSaved / 4);
2225
- const after = before - approxSaved;
2229
+ const after = Math.max(0, before - compactResult.tokensSaved);
2226
2230
  yield {
2227
2231
  turn: this._turn,
2228
2232
  role: "warning",
2229
- content: `context ${before.toLocaleString()}/${ctxMax.toLocaleString()} \u2014 auto-compacted ${compactResult.healedCount} oversized tool result(s), saved ~${approxSaved.toLocaleString()} tokens (now ~${after.toLocaleString()}). Continuing.`
2233
+ content: `context ${before.toLocaleString()}/${ctxMax.toLocaleString()} \u2014 auto-compacted ${compactResult.healedCount} oversized tool result(s), saved ${compactResult.tokensSaved.toLocaleString()} tokens (now ~${after.toLocaleString()}). Continuing.`
2230
2234
  };
2231
2235
  } else {
2232
2236
  yield {
@@ -2427,6 +2431,25 @@ function shrinkOversizedToolResults(messages, maxChars) {
2427
2431
  });
2428
2432
  return { messages: out, healedCount, healedFrom };
2429
2433
  }
2434
+ function shrinkOversizedToolResultsByTokens(messages, maxTokens) {
2435
+ let healedCount = 0;
2436
+ let tokensSaved = 0;
2437
+ let charsSaved = 0;
2438
+ const out = messages.map((msg) => {
2439
+ if (msg.role !== "tool") return msg;
2440
+ const content = typeof msg.content === "string" ? msg.content : "";
2441
+ if (content.length <= maxTokens) return msg;
2442
+ const beforeTokens = countTokens(content);
2443
+ if (beforeTokens <= maxTokens) return msg;
2444
+ const truncated = truncateForModelByTokens(content, maxTokens);
2445
+ const afterTokens = countTokens(truncated);
2446
+ healedCount += 1;
2447
+ tokensSaved += Math.max(0, beforeTokens - afterTokens);
2448
+ charsSaved += Math.max(0, content.length - truncated.length);
2449
+ return { ...msg, content: truncated };
2450
+ });
2451
+ return { messages: out, healedCount, tokensSaved, charsSaved };
2452
+ }
2430
2453
  function healLoadedMessages(messages, maxChars) {
2431
2454
  const shrunk = shrinkOversizedToolResults(messages, maxChars);
2432
2455
  let healedCount = shrunk.healedCount;
@@ -6877,7 +6900,11 @@ var SLASH_COMMANDS = [
6877
6900
  summary: "break down where context tokens are going: system / tools / per-turn log"
6878
6901
  },
6879
6902
  { cmd: "retry", summary: "truncate & resend your last message (fresh sample)" },
6880
- { cmd: "compact", argsHint: "[cap]", summary: "shrink oversized tool results in the log" },
6903
+ {
6904
+ cmd: "compact",
6905
+ argsHint: "[tokens]",
6906
+ summary: "shrink oversized tool results in the log (cap in tokens, default 4000)"
6907
+ },
6881
6908
  { cmd: "sessions", summary: "list saved sessions (current marked with \u25B8)" },
6882
6909
  { cmd: "forget", summary: "delete the current session from disk" },
6883
6910
  { cmd: "setup", summary: "reminds you to exit and run `reasonix setup`" },
@@ -6951,7 +6978,7 @@ function handleSlash(cmd, args, loop, ctx = {}) {
6951
6978
  " /branch <N|off> run N parallel samples (N>=2), pick most confident",
6952
6979
  " /mcp list MCP servers + tools attached to this session",
6953
6980
  " /setup (exit + reconfigure) \u2192 run `reasonix setup`",
6954
- " /compact [cap] shrink large tool results in history (default 4k/result)",
6981
+ " /compact [tokens] shrink large tool results in history (default 4000 tokens/result)",
6955
6982
  " /think dump the most recent turn's full R1 reasoning (reasoner only)",
6956
6983
  " /tool [N] list tool calls (or dump full output of #N, 1=most recent)",
6957
6984
  " /memory [sub] show pinned memory (REASONIX.md + ~/.reasonix/memory).",
@@ -7179,15 +7206,15 @@ ${entry.text}`
7179
7206
  }
7180
7207
  case "compact": {
7181
7208
  const tight = Number.parseInt(args[0] ?? "", 10);
7182
- const cap = Number.isFinite(tight) && tight >= 500 ? tight : 4e3;
7183
- const { healedCount, charsSaved } = loop.compact(cap);
7209
+ const cap = Number.isFinite(tight) && tight >= 100 ? tight : 4e3;
7210
+ const { healedCount, tokensSaved, charsSaved } = loop.compact(cap);
7184
7211
  if (healedCount === 0) {
7185
7212
  return {
7186
- info: `\u25B8 nothing to compact \u2014 no tool result in history exceeds ${cap.toLocaleString()} chars.`
7213
+ info: `\u25B8 nothing to compact \u2014 no tool result in history exceeds ${cap.toLocaleString()} tokens.`
7187
7214
  };
7188
7215
  }
7189
7216
  return {
7190
- info: `\u25B8 compacted ${healedCount} tool result(s), saved ${charsSaved.toLocaleString()} chars (~${Math.round(charsSaved / 4).toLocaleString()} tokens). Session file rewritten.`
7217
+ info: `\u25B8 compacted ${healedCount} tool result(s) to ${cap.toLocaleString()} tokens each, saved ${tokensSaved.toLocaleString()} tokens (${charsSaved.toLocaleString()} chars). Session file rewritten.`
7191
7218
  };
7192
7219
  }
7193
7220
  case "sessions": {