omnius 1.0.344 → 1.0.346

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
@@ -568855,7 +568855,7 @@ RECOVERY: cd to the directory containing '${file}', run a plain install with no
568855
568855
  });
568856
568856
 
568857
568857
  // packages/orchestrator/dist/agenticRunner.js
568858
- import { existsSync as _fsExistsSync, readFileSync as _fsReadFileSync, writeFileSync as _fsWriteFileSync, appendFileSync as _fsAppendFileSync, unlinkSync as _fsUnlinkSync, mkdirSync as _fsMkdirSync } from "node:fs";
568858
+ import { existsSync as _fsExistsSync, readFileSync as _fsReadFileSync, writeFileSync as _fsWriteFileSync, appendFileSync as _fsAppendFileSync, unlinkSync as _fsUnlinkSync, mkdirSync as _fsMkdirSync, statSync as _fsStatSync } from "node:fs";
568859
568859
  import { execFile as _execFile, spawn as _spawn } from "node:child_process";
568860
568860
  import { createHash as _createHash } from "node:crypto";
568861
568861
  import { join as _pathJoin, resolve as _pathResolve } from "node:path";
@@ -570582,6 +570582,91 @@ Your hypotheses MUST address this specific error, not generic causes.
570582
570582
  return null;
570583
570583
  }
570584
570584
  }
570585
+ // ── Failing-approach detector (the "stop retrying variants" reflex) ───────
570586
+ // Encodes the behavior an effective agent uses and the dropbear 27× loop
570587
+ // lacked: when the SAME error recurs ~3× — especially while the same target
570588
+ // is edited again and again — the error is telling you the CHANGE is wrong
570589
+ // (an unsupported attribute, a wrong API/signature, a missing dep), not that
570590
+ // you haven't found the right value yet. Stop, diagnose the root cause from
570591
+ // the full error, verify the correct contract, then act — do NOT re-apply a
570592
+ // variant. Distinct from REG-58/60 (no-write / slow-write): this fires while
570593
+ // edits ARE landing but verification keeps failing the same way.
570594
+ _failingApproachCooldownUntil = -1;
570595
+ /**
570596
+ * Most-common normalized failure signature in the recent window, or null if
570597
+ * no signature recurs ≥3×. Normalization drops the VARYING tokens (quoted
570598
+ * names, paths, numbers) so "unrecognized attribute: 'nstack'" and
570599
+ * "...: 'narena'" collapse to one signature. Transient/network failures are
570600
+ * excluded — retrying those is legitimate, not a failing approach.
570601
+ */
570602
+ _recurringFailureSignature(turn, window2 = 10) {
570603
+ const recent = this._recentFailures.filter((f2) => turn - f2.turn <= window2);
570604
+ if (recent.length < 3)
570605
+ return null;
570606
+ const TRANSIENT = /timed? ?out|timeout|econnreset|econnrefused|etimedout|rate.?limit|503|502|temporarily|try again|socket hang|network|fetch failed/i;
570607
+ const norm = (s2) => s2.toLowerCase().replace(/['"`][^'"`]*['"`]/g, " ").replace(/\/[^\s:]+/g, " ").replace(/\d+/g, " ").replace(/\s+/g, " ").trim().slice(0, 80);
570608
+ const groups = /* @__PURE__ */ new Map();
570609
+ for (const f2 of recent) {
570610
+ const raw = (f2.error || f2.output || "").slice(0, 200);
570611
+ if (!raw || TRANSIENT.test(raw))
570612
+ continue;
570613
+ const sig = norm(raw);
570614
+ if (!sig)
570615
+ continue;
570616
+ const g = groups.get(sig) ?? { count: 0, sample: raw };
570617
+ g.count++;
570618
+ groups.set(sig, g);
570619
+ }
570620
+ let best = null;
570621
+ for (const [signature, g] of groups) {
570622
+ if (!best || g.count > best.count)
570623
+ best = { signature, count: g.count, sample: g.sample };
570624
+ }
570625
+ return best && best.count >= 3 ? best : null;
570626
+ }
570627
+ /**
570628
+ * Detect a failing approach and return a decisive root-cause directive, or
570629
+ * null. Fires when a non-transient error recurs ≥3× in the recent window
570630
+ * (optionally corroborated by the error-cluster tracker), self-cooldown 8
570631
+ * turns. OMNIUS_DISABLE_FAILING_APPROACH=1 disables.
570632
+ */
570633
+ _detectFailingApproach(turn) {
570634
+ if (process.env["OMNIUS_DISABLE_FAILING_APPROACH"] === "1")
570635
+ return null;
570636
+ if (turn <= this._failingApproachCooldownUntil)
570637
+ return null;
570638
+ const recurring = this._recurringFailureSignature(turn);
570639
+ if (!recurring)
570640
+ return null;
570641
+ let churnPath = null;
570642
+ let churnWrites = 0;
570643
+ const wf = this._worldFacts;
570644
+ if (wf) {
570645
+ for (const [p2, info] of wf.files) {
570646
+ const writes = info.writeCount ?? 0;
570647
+ const age = turn - (info.lastWriteTurn ?? -999);
570648
+ if (writes >= 3 && age <= 8 && writes > churnWrites) {
570649
+ churnWrites = writes;
570650
+ churnPath = p2;
570651
+ }
570652
+ }
570653
+ }
570654
+ this._failingApproachCooldownUntil = turn + 8;
570655
+ const target = churnPath ? `${churnPath} (edited ${churnWrites}× recently)` : "the same target";
570656
+ return [
570657
+ `[FAILING APPROACH DETECTED — stop retrying variants]`,
570658
+ `The SAME error has recurred ${recurring.count}× in your recent attempts while you keep changing ${target}:`,
570659
+ ` ${recurring.sample}`,
570660
+ ``,
570661
+ `Trying another variant of the same change is not converging. A repeating error means the CHANGE ITSELF is wrong — an unsupported attribute/option, a wrong API or signature, or a missing prerequisite — not that you haven't hit the right value yet.`,
570662
+ `MANDATORY before your next edit:`,
570663
+ ` 1. Re-read the FULL error above and name the EXACT token it rejects (attribute / symbol / flag / path).`,
570664
+ ` 2. VERIFY the correct contract for that token from an authoritative source — read the defining file, the schema, or the API/docs. Do NOT guess.`,
570665
+ ` 3. State the root cause in one sentence: "<token> fails because <reason>."`,
570666
+ ` 4. Then make ONE change that step 2 supports. If the thing you want is genuinely unsupported, REMOVE it and choose a supported alternative — do not re-add a variant.`,
570667
+ `Do NOT re-apply another variant of the rejected change.`
570668
+ ].join("\n");
570669
+ }
570585
570670
  /**
570586
570671
  * REG-61 sliding-window first-edit / sustained-edit nudge.
570587
570672
  *
@@ -575516,6 +575601,28 @@ TASK: ${scrubbedTask}` : scrubbedTask;
575516
575601
  });
575517
575602
  }
575518
575603
  this._runReg61Check(turn, toolCallLog, messages2);
575604
+ if (turn > stagnationCooldownUntilTurn) {
575605
+ const failingApproach = this._detectFailingApproach(turn);
575606
+ if (failingApproach) {
575607
+ messages2.push({ role: "system", content: failingApproach });
575608
+ stagnationCooldownUntilTurn = turn + 4;
575609
+ this.emit({
575610
+ type: "adversary_reaction",
575611
+ adversary: {
575612
+ class: "guidance",
575613
+ shortText: "Failing approach — same error recurring; diagnose root cause",
575614
+ confidence: 0.9,
575615
+ details: failingApproach
575616
+ },
575617
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
575618
+ });
575619
+ this.emit({
575620
+ type: "status",
575621
+ content: `FAILING-APPROACH detected at turn ${turn} — injected root-cause directive`,
575622
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
575623
+ });
575624
+ }
575625
+ }
575519
575626
  const REG58_NO_WRITE_BUDGET = 30;
575520
575627
  if (turn > stagnationCooldownUntilTurn && this._lastFileWriteTurn >= 0 && turn - this._lastFileWriteTurn >= REG58_NO_WRITE_BUDGET && process.env["OMNIUS_DISABLE_REG58"] !== "1") {
575521
575628
  const gap = turn - this._lastFileWriteTurn;
@@ -578723,41 +578830,63 @@ Respond with EXACTLY this structure before your next tool call:
578723
578830
  result = await this.offloadEmbeddedImageResult(result, tc.name, turn);
578724
578831
  }
578725
578832
  let output = this.normalizeToolOutput(result, tc.name, tc.arguments, turn);
578726
- if (process.env["OMNIUS_DISABLE_BRANCH_EXTRACT"] !== "1" && this.lookupRegisteredTool(tc.name)?.name === "file_read" && result.success && typeof result.output === "string" && this.backend && typeof this.backend.chatCompletion === "function") {
578833
+ if (process.env["OMNIUS_DISABLE_BRANCH_EXTRACT"] !== "1" && this.lookupRegisteredTool(tc.name)?.name === "file_read" && result.success && this.backend && typeof this.backend.chatCompletion === "function") {
578727
578834
  const a2 = tc.arguments ?? {};
578728
- const hasSmallRange = typeof a2["limit"] === "number" && a2["limit"] <= 80;
578729
- const lineCount = result.output.split("\n").length;
578730
- if (shouldBranchRead(result.output.length, lineCount, hasSmallRange)) {
578731
- const p2 = String(a2["path"] ?? a2["file"] ?? a2["file_path"] ?? "");
578732
- const lastAssistant = [...messages2].reverse().find((m2) => m2.role === "assistant" && typeof m2.content === "string");
578733
- const query = [
578734
- this._taskState.goal ?? "",
578735
- typeof lastAssistant?.content === "string" ? lastAssistant.content : ""
578736
- ].join(" ").trim().slice(0, 400) || "key facts, configuration, and structure";
578737
- try {
578738
- const ev = await extractEvidence({
578739
- path: p2,
578740
- query,
578741
- content: result.output,
578742
- fileVersion: this._worldFacts.files.get(p2)?.writeCount ?? 0,
578743
- backend: this.backend,
578744
- timeoutMs: 3e4
578745
- });
578746
- output = [
578747
- `[BRANCH-EXTRACT] ${p2} is large (${lineCount} lines, ${result.output.length} chars) — read in an isolated branch so it does not flood your context.`,
578748
- `Distilled for: "${query.slice(0, 160)}"`,
578749
- `Relevant evidence (lines ${ev.sourceStart ?? "?"}-${ev.sourceEnd ?? "?"}, confidence ${ev.confidence.toFixed(2)}):`,
578750
- ev.claim,
578751
- `If you need a different region, call file_read with a specific offset+limit, or extract_evidence(path, query) with a sharper question.`
578752
- ].join("\n");
578753
- this.emit({
578754
- type: "status",
578755
- toolName: tc.name,
578756
- content: `Branch-extract: ${p2} (${lineCount} lines) → ${ev.injectedChars} chars to context (${(result.output.length / Math.max(1, ev.injectedChars)).toFixed(0)}× smaller)`,
578757
- turn,
578758
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
578759
- });
578760
- } catch {
578835
+ const hasExplicitRange = typeof a2["offset"] === "number" || typeof a2["limit"] === "number";
578836
+ const pRaw = String(a2["path"] ?? a2["file"] ?? a2["file_path"] ?? "");
578837
+ if (!hasExplicitRange && pRaw) {
578838
+ let fullContent = null;
578839
+ let trueLines = 0;
578840
+ let trueBytes = 0;
578841
+ for (const cand of [
578842
+ pRaw,
578843
+ _pathResolve(this._workingDirectory || process.cwd(), pRaw)
578844
+ ]) {
578845
+ try {
578846
+ const st = _fsStatSync(cand);
578847
+ if (st.isFile()) {
578848
+ trueBytes = st.size;
578849
+ if (trueBytes > 8e3) {
578850
+ fullContent = _fsReadFileSync(cand, "utf-8");
578851
+ trueLines = fullContent.split("\n").length;
578852
+ }
578853
+ break;
578854
+ }
578855
+ } catch {
578856
+ }
578857
+ }
578858
+ if (fullContent && shouldBranchRead(trueBytes, trueLines, false)) {
578859
+ const lastAssistant = [...messages2].reverse().find((m2) => m2.role === "assistant" && typeof m2.content === "string");
578860
+ const query = [
578861
+ this._taskState.goal ?? "",
578862
+ typeof lastAssistant?.content === "string" ? lastAssistant.content : ""
578863
+ ].join(" ").trim().slice(0, 400) || "key facts, configuration, and structure";
578864
+ try {
578865
+ const ev = await extractEvidence({
578866
+ path: pRaw,
578867
+ query,
578868
+ content: fullContent,
578869
+ // the REAL body, not the preview
578870
+ fileVersion: this._worldFacts.files.get(pRaw)?.writeCount ?? 0,
578871
+ backend: this.backend,
578872
+ timeoutMs: 3e4
578873
+ });
578874
+ output = [
578875
+ `[BRANCH-EXTRACT] ${pRaw} is large (${trueLines} lines, ${trueBytes} bytes); a whole-file read only returns a preview, so it was read in an isolated branch and distilled.`,
578876
+ `Distilled for: "${query.slice(0, 160)}"`,
578877
+ `Relevant evidence (lines ${ev.sourceStart ?? "?"}-${ev.sourceEnd ?? "?"}, confidence ${ev.confidence.toFixed(2)}):`,
578878
+ ev.claim,
578879
+ `If you need a different region, call file_read with a specific offset+limit. Do NOT re-read the whole file — you already have the relevant content above.`
578880
+ ].join("\n");
578881
+ this.emit({
578882
+ type: "status",
578883
+ toolName: tc.name,
578884
+ content: `Branch-extract: ${pRaw} (${trueLines} lines / ${trueBytes}B) → ${ev.injectedChars} chars to context (${(trueBytes / Math.max(1, ev.injectedChars)).toFixed(0)}× smaller)`,
578885
+ turn,
578886
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
578887
+ });
578888
+ } catch {
578889
+ }
578761
578890
  }
578762
578891
  }
578763
578892
  }
@@ -584252,6 +584381,8 @@ ${result}`
584252
584381
  return true;
584253
584382
  if (/fetch failed|ECONNREFUSED|ECONNRESET|ETIMEDOUT|EPIPE|socket hang up|UND_ERR|other side closed/i.test(msg))
584254
584383
  return true;
584384
+ if (/stream timeout|no response or chunk within|no response within \d+\s*s|stream stalled/i.test(msg))
584385
+ return true;
584255
584386
  if (/received HTML error page/i.test(msg))
584256
584387
  return true;
584257
584388
  if (/model is loading|server busy|overloaded/i.test(msg))
@@ -584495,7 +584626,7 @@ ${description}`
584495
584626
  if (!this.isTransientError(initialErr))
584496
584627
  return null;
584497
584628
  const errMsg = flattenErrorText(initialErr);
584498
- const isNetworkError2 = /fetch failed|ECONNREFUSED|ECONNRESET|ETIMEDOUT|socket hang up|UND_ERR|other side closed/i.test(errMsg);
584629
+ const isNetworkError2 = /fetch failed|ECONNREFUSED|ECONNRESET|ETIMEDOUT|socket hang up|UND_ERR|other side closed|stream timeout|no response or chunk within|no response within \d+\s*s|stream stalled/i.test(errMsg);
584499
584630
  const isAuthError = this.isRecoverableAuthError(initialErr);
584500
584631
  const isGpuSlotUnavailable = this.isGpuSlotUnavailableError(initialErr);
584501
584632
  const maxRetries = isNetworkError2 || isGpuSlotUnavailable || isAuthError ? Infinity : 3;
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "omnius",
3
- "version": "1.0.344",
3
+ "version": "1.0.346",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "omnius",
9
- "version": "1.0.344",
9
+ "version": "1.0.346",
10
10
  "bundleDependencies": [
11
11
  "image-to-ascii"
12
12
  ],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "omnius",
3
- "version": "1.0.344",
3
+ "version": "1.0.346",
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",