omnius 1.0.494 → 1.0.496

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/index.js CHANGED
@@ -584033,7 +584033,7 @@ Your hypotheses MUST address this specific error, not generic causes.
584033
584033
  * system prompt. Mutates `messages` in place.
584034
584034
  */
584035
584035
  gcSystemMessages(messages2) {
584036
- const ctxTokens = this.options.contextWindowSize ?? 0;
584036
+ const ctxTokens = this.effectiveContextWindow();
584037
584037
  const systemMaxChars = ctxTokens > 0 ? Math.max(24e3, Math.floor(ctxTokens * 4 * 0.45)) : 0;
584038
584038
  const beforeChars = messages2.reduce((sum2, m2) => sum2 + (m2.role === "system" && typeof m2.content === "string" ? m2.content.length : 0), 0);
584039
584039
  const result = this._signalExtractor.distillSystemMessages(messages2, {
@@ -586146,6 +586146,39 @@ ${body}`;
586146
586146
  * - Large models: compact at ~75% (plenty of room, let attention work)
586147
586147
  * - Deep context: compact at ~85% (trust the model's full attention window)
586148
586148
  */
586149
+ /**
586150
+ * Absolute working-context ceiling in TOKENS. Local models advertise a huge
586151
+ * n_ctx_train (qwen3 = 262144) but lose coherence far below it. Keying
586152
+ * compaction/pruning budgets off the raw window means Omnius never trims until
586153
+ * the model is already saturated and doom-looping (observed: a 35B run pinned
586154
+ * at 120K tokens with a 196K threshold that never fired). This caps the budget
586155
+ * denominator to a realistic, tier-aware working window so compaction actually
586156
+ * runs and the active context stays focused.
586157
+ *
586158
+ * Tier defaults (tokens): small 28K, medium 48K, large 72K. deepContext relaxes
586159
+ * ×1.4. Override with OMNIUS_MAX_CONTEXT_TOKENS. Cloud/large-context users who
586160
+ * want to use their full window set that env high (or per-tier via the option).
586161
+ */
586162
+ absoluteContextCeiling() {
586163
+ const env2 = Number(process.env["OMNIUS_MAX_CONTEXT_TOKENS"]);
586164
+ if (Number.isFinite(env2) && env2 > 0)
586165
+ return Math.floor(env2);
586166
+ const tier = this.options.modelTier ?? "large";
586167
+ const deep = this.options.deepContext ?? false;
586168
+ const base3 = tier === "small" ? 28e3 : tier === "medium" ? 48e3 : 72e3;
586169
+ return deep ? Math.floor(base3 * 1.4) : base3;
586170
+ }
586171
+ /**
586172
+ * Context window (tokens) used for compaction/pruning BUDGET math — the
586173
+ * smaller of the model's declared window and the effective working ceiling.
586174
+ * The raw declared window is still used for the backend num_ctx and the
586175
+ * generation-token budget; this only governs WHEN we compact/prune.
586176
+ */
586177
+ effectiveContextWindow() {
586178
+ const raw = this.options.contextWindowSize ?? 0;
586179
+ const ceiling = this.absoluteContextCeiling();
586180
+ return raw > 0 ? Math.min(raw, ceiling) : ceiling;
586181
+ }
586149
586182
  contextLimits() {
586150
586183
  const ctx3 = this.options.contextWindowSize;
586151
586184
  const tier = this.options.modelTier ?? "large";
@@ -586158,6 +586191,7 @@ ${body}`;
586158
586191
  } else {
586159
586192
  compactionThreshold = deep ? 8e4 : this.options.compactionThreshold;
586160
586193
  }
586194
+ compactionThreshold = Math.min(compactionThreshold, this.absoluteContextCeiling());
586161
586195
  const keepRecentMax = deep ? 24 : 12;
586162
586196
  let keepRecent;
586163
586197
  if (ctx3 > 0) {
@@ -587989,6 +588023,86 @@ ${this._lastPprMemoryLines.slice(0, 5).join("\n")}` : null;
587989
588023
  });
587990
588024
  return frame.content;
587991
588025
  }
588026
+ /**
588027
+ * Feed the ContextTree one tool call, detect phase transitions, and — on a
588028
+ * transition — capture the outgoing phase's message slice, contract inactive
588029
+ * phases (LLM-summarized via makePhaseSummarizer, anchors retained), and
588030
+ * archive the full message bodies to `.omnius/phases/<phase>-<id>-turnN.jsonl`,
588031
+ * leaving only a pointer + high-signal summary in the working context. This is
588032
+ * the core "offload large block → disk pointer + searchable signature"
588033
+ * mechanism; `contextTree.expand(phase)` re-hydrates on demand.
588034
+ *
588035
+ * Wired into BOTH the primary loop and the brute-force loop. The brute-force
588036
+ * path is the ACTIVE main-agent path on live 35B runs; omitting the feed here
588037
+ * is why the context tree "never kicked off" — it rendered an empty phase
588038
+ * status every turn while the raw history grew unbounded. Returns the
588039
+ * transition (so the primary loop can reset per-phase tool budgets) or null.
588040
+ */
588041
+ _advanceContextTreeOnToolCall(toolName, argsKey, turn, messages2) {
588042
+ if (!this._contextTree)
588043
+ return null;
588044
+ this._contextTree.observeToolCall(toolName, argsKey, turn);
588045
+ const transition = this._contextTree.maybeTransition(turn);
588046
+ if (!transition)
588047
+ return null;
588048
+ const startIdx = Math.min(this._phaseMessageStartIdx, messages2.length);
588049
+ const phaseSlice = messages2.slice(startIdx);
588050
+ if (phaseSlice.length > 0) {
588051
+ const fromNode = this._contextTree.getSnapshot().phases[transition.from];
588052
+ if (fromNode)
588053
+ fromNode.messages = phaseSlice;
588054
+ }
588055
+ this.emit({
588056
+ type: "status",
588057
+ content: `Phase: ${transition.from} → ${transition.to}`,
588058
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
588059
+ });
588060
+ const summarizer = this.makePhaseSummarizer();
588061
+ const contracted = this._contextTree.contractInactive(turn, summarizer ? (msgs) => summarizer(transition.from, msgs) : void 0);
588062
+ if (contracted.length > 0) {
588063
+ this.emit({
588064
+ type: "status",
588065
+ content: `Phase contraction: ${contracted.join(", ")} → contracted (${summarizer ? "LLM-summarized" : "stub-summarized"}, anchors retained)`,
588066
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
588067
+ });
588068
+ try {
588069
+ const archDir = _pathJoin(this.omniusStateDir(), "phases");
588070
+ _fsMkdirSync(archDir, { recursive: true });
588071
+ for (const phaseName of contracted) {
588072
+ const node = this._contextTree.getSnapshot().phases[phaseName];
588073
+ if (!node)
588074
+ continue;
588075
+ const stamp = `${phaseName}-${Date.now().toString(36)}-turn${turn}`;
588076
+ const archPath = _pathJoin(archDir, `${stamp}.jsonl`);
588077
+ const archived = {
588078
+ phase: phaseName,
588079
+ contractedAtTurn: turn,
588080
+ contractedAtIso: (/* @__PURE__ */ new Date()).toISOString(),
588081
+ anchors: node.anchors,
588082
+ summary: node.summary ?? null,
588083
+ messages: node.messages ?? []
588084
+ };
588085
+ _fsWriteFileSync(archPath, JSON.stringify(archived) + "\n", "utf-8");
588086
+ this._contextTree.archive(phaseName, archPath);
588087
+ }
588088
+ this.emit({
588089
+ type: "status",
588090
+ content: `Phase archive: ${contracted.length} phase(s) written to .omnius/phases/`,
588091
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
588092
+ });
588093
+ } catch (archErr) {
588094
+ this.emit({
588095
+ type: "status",
588096
+ content: `Phase archive failed (non-fatal): ${archErr instanceof Error ? archErr.message : String(archErr)}`,
588097
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
588098
+ });
588099
+ }
588100
+ }
588101
+ this._phaseMessageStartIdx = messages2.length;
588102
+ this._taskState.phase = transition.to;
588103
+ this._taskState.phaseSince = turn;
588104
+ return transition;
588105
+ }
587992
588106
  makePhaseSummarizer() {
587993
588107
  if (process.env["OMNIUS_DISABLE_PHASE_SUMMARIZER"] === "1")
587994
588108
  return null;
@@ -592316,77 +592430,18 @@ Corrective action: try a different approach first: read relevant files, adjust a
592316
592430
  return { tc, output: blockMsg, success: false };
592317
592431
  }
592318
592432
  this._toolLastUsedTurn.set(tc.name, turn);
592319
- if (this._contextTree) {
592320
- this._contextTree.observeToolCall(tc.name, argsKey, turn);
592321
- const transition = this._contextTree.maybeTransition(turn);
592322
- if (transition) {
592323
- const phaseSlice = messages2.slice(this._phaseMessageStartIdx);
592324
- if (phaseSlice.length > 0) {
592325
- const fromNode = this._contextTree.getSnapshot().phases[transition.from];
592326
- if (fromNode) {
592327
- fromNode.messages = phaseSlice;
592328
- }
592329
- }
592330
- this.emit({
592331
- type: "status",
592332
- content: `Phase: ${transition.from} → ${transition.to}`,
592333
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
592334
- });
592335
- const summarizer = this.makePhaseSummarizer();
592336
- const contracted = this._contextTree.contractInactive(turn, summarizer ? (msgs) => summarizer(transition.from, msgs) : void 0);
592337
- if (contracted.length > 0) {
592338
- this.emit({
592339
- type: "status",
592340
- content: `Phase contraction: ${contracted.join(", ")} → contracted (${summarizer ? "LLM-summarized" : "stub-summarized"}, anchors retained)`,
592341
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
592342
- });
592343
- try {
592344
- const archDir = _pathJoin(this.omniusStateDir(), "phases");
592345
- _fsMkdirSync(archDir, { recursive: true });
592346
- for (const phaseName of contracted) {
592347
- const node = this._contextTree.getSnapshot().phases[phaseName];
592348
- if (!node)
592349
- continue;
592350
- const stamp = `${phaseName}-${Date.now().toString(36)}-turn${turn}`;
592351
- const archPath = _pathJoin(archDir, `${stamp}.jsonl`);
592352
- const archived = {
592353
- phase: phaseName,
592354
- contractedAtTurn: turn,
592355
- contractedAtIso: (/* @__PURE__ */ new Date()).toISOString(),
592356
- anchors: node.anchors,
592357
- summary: node.summary ?? null,
592358
- messages: node.messages ?? []
592359
- };
592360
- _fsWriteFileSync(archPath, JSON.stringify(archived) + "\n", "utf-8");
592361
- this._contextTree.archive(phaseName, archPath);
592362
- }
592363
- this.emit({
592364
- type: "status",
592365
- content: `Phase archive: ${contracted.length} phase(s) written to .omnius/phases/`,
592366
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
592367
- });
592368
- } catch (archErr) {
592369
- this.emit({
592370
- type: "status",
592371
- content: `Phase archive failed (non-fatal): ${archErr instanceof Error ? archErr.message : String(archErr)}`,
592372
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
592373
- });
592374
- }
592375
- }
592376
- this._phaseMessageStartIdx = messages2.length;
592377
- this._taskState.phase = transition.to;
592378
- this._taskState.phaseSince = turn;
592379
- for (const [tool2, budget] of Object.entries(toolBudgets)) {
592380
- toolCallBudget.set(tool2, budget);
592381
- }
592382
- this._writesSinceLastTodoWrite = 0;
592383
- this._progressGateActive = false;
592384
- this.emit({
592385
- type: "status",
592386
- content: `Tool budgets reset for new phase (${Object.keys(toolBudgets).length} tools)`,
592387
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
592388
- });
592433
+ const _treeTransition = this._advanceContextTreeOnToolCall(tc.name, argsKey, turn, messages2);
592434
+ if (_treeTransition) {
592435
+ for (const [tool2, budget] of Object.entries(toolBudgets)) {
592436
+ toolCallBudget.set(tool2, budget);
592389
592437
  }
592438
+ this._writesSinceLastTodoWrite = 0;
592439
+ this._progressGateActive = false;
592440
+ this.emit({
592441
+ type: "status",
592442
+ content: `Tool budgets reset for new phase (${Object.keys(toolBudgets).length} tools)`,
592443
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
592444
+ });
592390
592445
  }
592391
592446
  const REG61_EDIT_TOOLS = /* @__PURE__ */ new Set([
592392
592447
  "file_write",
@@ -595757,6 +595812,7 @@ ${this.options.maxTurns && this.options.maxTurns > 0 ? `You have ${this.options.
595757
595812
  }
595758
595813
  this.proactivePrune(compactedMsgs, this._taskState.toolCallCount);
595759
595814
  this.microcompact(compactedMsgs);
595815
+ this._retireStaleEvidenceInPlace(compactedMsgs, this._taskState.toolCallCount);
595760
595816
  let bfEnvironmentBlock = null;
595761
595817
  if (this.options.environmentProvider) {
595762
595818
  try {
@@ -595922,6 +595978,8 @@ ${this.options.maxTurns && this.options.maxTurns > 0 ? `You have ${this.options.
595922
595978
  if (!r2)
595923
595979
  continue;
595924
595980
  messages2.push(this.buildModelFacingToolMessage(r2.output, r2.tc.id, r2.tc.name, r2.tc.arguments, r2.success));
595981
+ this._toolLastUsedTurn.set(r2.tc.name, turn);
595982
+ this._advanceContextTreeOnToolCall(r2.tc.name, this._buildExactArgsKey(r2.tc.arguments ?? {}), turn, messages2);
595925
595983
  if (r2.systemGuidance) {
595926
595984
  messages2.push({
595927
595985
  role: "system",
@@ -598896,7 +598954,7 @@ Describe what you see and integrate this into your current approach.` : "[User s
598896
598954
  const head = messages2.slice(0, headEndIdx);
598897
598955
  if (messages2.length <= headEndIdx + keepRecent)
598898
598956
  return messages2;
598899
- const tailTokenBudget = Math.max(4e3, Math.floor((this.options.contextWindowSize || 32e3) * 0.15));
598957
+ const tailTokenBudget = Math.max(4e3, Math.floor((this.effectiveContextWindow() || 32e3) * 0.15));
598900
598958
  let recentStart = messages2.length - keepRecent;
598901
598959
  {
598902
598960
  let accumulated = 0;
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "omnius",
3
- "version": "1.0.494",
3
+ "version": "1.0.496",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "omnius",
9
- "version": "1.0.494",
9
+ "version": "1.0.496",
10
10
  "bundleDependencies": [
11
11
  "image-to-ascii"
12
12
  ],
@@ -1077,14 +1077,14 @@
1077
1077
  }
1078
1078
  },
1079
1079
  "node_modules/@libp2p/peer-record": {
1080
- "version": "9.0.12",
1081
- "resolved": "https://registry.npmjs.org/@libp2p/peer-record/-/peer-record-9.0.12.tgz",
1082
- "integrity": "sha512-tYGHo9gSO1ZqQripsEtpzxMrWDnmCMgFe8c1TKcml8dZUBCAsM9k5js25RKb0HA1aqZ2VX54XPFazpbjVs3tow==",
1080
+ "version": "9.0.13",
1081
+ "resolved": "https://registry.npmjs.org/@libp2p/peer-record/-/peer-record-9.0.13.tgz",
1082
+ "integrity": "sha512-lkdZUNC6h86YECpRE3dB4GLYSiLLuXFBleiM01oEmWtAdTCfRd+vRqNkguSoC6R3tGk/YWRm7cfz39ATPuq7zQ==",
1083
1083
  "license": "Apache-2.0 OR MIT",
1084
1084
  "dependencies": {
1085
- "@libp2p/crypto": "^5.1.20",
1086
- "@libp2p/interface": "^3.2.4",
1087
- "@libp2p/peer-id": "^6.0.11",
1085
+ "@libp2p/crypto": "^5.1.21",
1086
+ "@libp2p/interface": "^3.2.5",
1087
+ "@libp2p/peer-id": "^6.0.12",
1088
1088
  "@multiformats/multiaddr": "^13.0.3",
1089
1089
  "multiformats": "^14.0.0",
1090
1090
  "protons-runtime": "^7.0.0",
@@ -1193,9 +1193,9 @@
1193
1193
  }
1194
1194
  },
1195
1195
  "node_modules/@libp2p/record": {
1196
- "version": "4.0.14",
1197
- "resolved": "https://registry.npmjs.org/@libp2p/record/-/record-4.0.14.tgz",
1198
- "integrity": "sha512-YObHdE1dkAiVDPR+YHIFcCD5YMppP0lj2shnMj0L5PgLka8lnZgaY5AjiQo+DMvLFhRvNIMHyxlE9WQUbrM1wA==",
1196
+ "version": "4.0.15",
1197
+ "resolved": "https://registry.npmjs.org/@libp2p/record/-/record-4.0.15.tgz",
1198
+ "integrity": "sha512-EaHFtQAlZuM9vCpd+0KnZhTVgV26Uzje7DkyUseGNKTy+Wit9Q94C/+wDThpZuRHnK1FH/CvPxJ4kLj7AoQ1WA==",
1199
1199
  "license": "Apache-2.0 OR MIT",
1200
1200
  "dependencies": {
1201
1201
  "protons-runtime": "^7.0.0",
@@ -1358,19 +1358,19 @@
1358
1358
  }
1359
1359
  },
1360
1360
  "node_modules/@libp2p/webrtc": {
1361
- "version": "6.0.25",
1362
- "resolved": "https://registry.npmjs.org/@libp2p/webrtc/-/webrtc-6.0.25.tgz",
1363
- "integrity": "sha512-c7QwXOjqBR+xgCIE8bv/A1NGQQMX3Sfrek+CD5n+XJur2TOoEmNjYyRX98Yt2h5YzbD083/bZK7ITZiu9xSdmQ==",
1361
+ "version": "6.0.26",
1362
+ "resolved": "https://registry.npmjs.org/@libp2p/webrtc/-/webrtc-6.0.26.tgz",
1363
+ "integrity": "sha512-6IXDWXyE+X/J7IQFBq8AkxWwTVIVjC/2tD17kny4u8p2VOkXmC1aOhQYtKQRv4TSolraiF+AVVGTyf9Rn+w4VQ==",
1364
1364
  "license": "Apache-2.0 OR MIT",
1365
1365
  "dependencies": {
1366
1366
  "@chainsafe/is-ip": "^2.1.0",
1367
1367
  "@chainsafe/libp2p-noise": "^17.0.0",
1368
- "@libp2p/crypto": "^5.1.20",
1369
- "@libp2p/interface": "^3.2.4",
1370
- "@libp2p/interface-internal": "^3.1.7",
1371
- "@libp2p/keychain": "^6.1.3",
1372
- "@libp2p/peer-id": "^6.0.11",
1373
- "@libp2p/utils": "^7.2.3",
1368
+ "@libp2p/crypto": "^5.1.21",
1369
+ "@libp2p/interface": "^3.2.5",
1370
+ "@libp2p/interface-internal": "^3.1.8",
1371
+ "@libp2p/keychain": "^6.1.4",
1372
+ "@libp2p/peer-id": "^6.0.12",
1373
+ "@libp2p/utils": "^7.2.4",
1374
1374
  "@multiformats/multiaddr": "^13.0.3",
1375
1375
  "@multiformats/multiaddr-matcher": "^3.0.2",
1376
1376
  "@peculiar/webcrypto": "^1.5.0",
@@ -2554,9 +2554,9 @@
2554
2554
  }
2555
2555
  },
2556
2556
  "node_modules/bare-fs": {
2557
- "version": "4.7.3",
2558
- "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-4.7.3.tgz",
2559
- "integrity": "sha512-xRgplks8SvcKkdlv2M6Z2LZmRsmqd+x0nXXGXeMEjwdibj1HSDrlnqBRLeYdMvsgCox7Bq0e+DHwfczOfsn6IA==",
2557
+ "version": "4.7.4",
2558
+ "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-4.7.4.tgz",
2559
+ "integrity": "sha512-y1kC+ffIx/tPLdTE693uNjHfzTfr+ravR5tvWlMXe25nELbkqV400S71qHDwbkAQ1FVEZobB1NFRzFbCCcyBCQ==",
2560
2560
  "license": "Apache-2.0",
2561
2561
  "optional": true,
2562
2562
  "dependencies": {
@@ -2578,25 +2578,12 @@
2578
2578
  }
2579
2579
  }
2580
2580
  },
2581
- "node_modules/bare-os": {
2582
- "version": "3.9.3",
2583
- "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-3.9.3.tgz",
2584
- "integrity": "sha512-fF4Q7QsyKVF5Rj0qvI8BgUNjqzC2JvQlpTaPLjVJVxYVUX5Zr9un+y3w1HmA4nNKdFmRBT8z/WmrjvXzXVerKQ==",
2585
- "license": "Apache-2.0",
2586
- "optional": true,
2587
- "engines": {
2588
- "bare": ">=1.14.0"
2589
- }
2590
- },
2591
2581
  "node_modules/bare-path": {
2592
- "version": "3.0.1",
2593
- "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-3.0.1.tgz",
2594
- "integrity": "sha512-ghj2DSK/2e99a1anTVPCV4m4YIYtrbXhfM7V3D7XZLOTsybnYyaJloymGqssQc8l/or0UoDyRtNQkmkEF/ysgQ==",
2582
+ "version": "3.1.0",
2583
+ "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-3.1.0.tgz",
2584
+ "integrity": "sha512-322oSBHOhMhOm2CVwn7b3+gWQqwzSgIY4gNpKKb+Ha5jx2dEl9ClOgz/SK57DwuDql8YQg8JRpb9U0o8K3pW9g==",
2595
2585
  "license": "Apache-2.0",
2596
- "optional": true,
2597
- "dependencies": {
2598
- "bare-os": "^3.0.1"
2599
- }
2586
+ "optional": true
2600
2587
  },
2601
2588
  "node_modules/bare-stream": {
2602
2589
  "version": "2.13.3",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "omnius",
3
- "version": "1.0.494",
3
+ "version": "1.0.496",
4
4
  "description": "AI coding agent powered by open-source models (Ollama/vLLM) — interactive TUI with agentic tool-calling loop",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",