omnius 1.0.459 → 1.0.460

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
@@ -573220,6 +573220,7 @@ var init_context_fabric = __esm({
573220
573220
  GOAL: 100,
573221
573221
  ACTION_CONTRACT: 98,
573222
573222
  USER_STEERING: 95,
573223
+ RUNTIME_GUIDANCE: 94,
573223
573224
  TASK_STATE: 80,
573224
573225
  KNOWN_FILES: 70,
573225
573226
  RECENT_FAILURE: 65,
@@ -573236,6 +573237,7 @@ var init_context_fabric = __esm({
573236
573237
  KIND_ORDER = [
573237
573238
  "goal",
573238
573239
  "user_steering",
573240
+ "runtime_guidance",
573239
573241
  "action_contract",
573240
573242
  "task_state",
573241
573243
  "known_files",
@@ -573253,6 +573255,7 @@ var init_context_fabric = __esm({
573253
573255
  KIND_LABELS = {
573254
573256
  goal: "Goal",
573255
573257
  user_steering: "User Steering",
573258
+ runtime_guidance: "Runtime Guidance",
573256
573259
  action_contract: "Next Action Contract",
573257
573260
  task_state: "Task State",
573258
573261
  known_files: "Known Files",
@@ -573270,6 +573273,7 @@ var init_context_fabric = __esm({
573270
573273
  DEFAULT_KIND_CHAR_BUDGET = {
573271
573274
  goal: 900,
573272
573275
  user_steering: 1400,
573276
+ runtime_guidance: 1800,
573273
573277
  action_contract: 1800,
573274
573278
  task_state: 1800,
573275
573279
  known_files: 2400,
@@ -578219,7 +578223,9 @@ function sanitizeHistoryThink(messages2) {
578219
578223
  const stripped = messages2.map((m2) => {
578220
578224
  if (m2.role !== "assistant" || typeof m2.content !== "string")
578221
578225
  return m2;
578222
- return { ...m2, content: stripThinkBlocks(m2.content) };
578226
+ const withoutThink = stripThinkBlocks(m2.content);
578227
+ const collapsed = collapseDegenerateAssistantRepetition(withoutThink);
578228
+ return { ...m2, content: collapsed ?? withoutThink };
578223
578229
  });
578224
578230
  const sanitized = [];
578225
578231
  for (let i2 = 0; i2 < stripped.length; i2++) {
@@ -578231,6 +578237,35 @@ function sanitizeHistoryThink(messages2) {
578231
578237
  }
578232
578238
  return sanitized;
578233
578239
  }
578240
+ function collapseDegenerateAssistantRepetition(content) {
578241
+ const trimmed = content.trim();
578242
+ if (trimmed.length < 160)
578243
+ return null;
578244
+ const lineUnits = trimmed.split(/\n+/).map((line) => line.trim()).filter((line) => line.length >= 12);
578245
+ const sentenceUnits = lineUnits.length >= 3 ? lineUnits : trimmed.split(/(?<=[.!?])\s+/).map((part) => part.trim()).filter((part) => part.length >= 12);
578246
+ if (sentenceUnits.length < 3)
578247
+ return null;
578248
+ const counts = /* @__PURE__ */ new Map();
578249
+ for (const unit of sentenceUnits) {
578250
+ const key = unit.toLowerCase().replace(/\s+/g, " ").slice(0, 220);
578251
+ const current = counts.get(key) ?? { count: 0, chars: 0, sample: unit };
578252
+ current.count++;
578253
+ current.chars += unit.length;
578254
+ counts.set(key, current);
578255
+ }
578256
+ let best = null;
578257
+ for (const value2 of counts.values()) {
578258
+ if (!best || value2.count > best.count || value2.count === best.count && value2.chars > best.chars) {
578259
+ best = value2;
578260
+ }
578261
+ }
578262
+ if (!best || best.count < 3)
578263
+ return null;
578264
+ const repeatedRatio = best.chars / Math.max(1, trimmed.length);
578265
+ if (repeatedRatio < 0.55)
578266
+ return null;
578267
+ return `[assistant repetitive text suppressed: repeated ${best.count}x "${best.sample.slice(0, 180)}"]`;
578268
+ }
578234
578269
  function isOrphanDuplicateAssistantToolAnchor(messages2, index, referencedToolCallIds) {
578235
578270
  const current = messages2[index];
578236
578271
  if (!current)
@@ -578529,6 +578564,7 @@ var init_agenticRunner = __esm({
578529
578564
  _onTypedEvent;
578530
578565
  handlers = [];
578531
578566
  pendingUserMessages = [];
578567
+ pendingRuntimeGuidanceMessages = [];
578532
578568
  aborted = false;
578533
578569
  _abortController = new AbortController();
578534
578570
  _paused = false;
@@ -578908,6 +578944,7 @@ var init_agenticRunner = __esm({
578908
578944
  //
578909
578945
  // Kill switch: OMNIUS_DISABLE_REG61_COERCE=1 disables BOTH set and enforce.
578910
578946
  _reg61PerpetualGateActive = false;
578947
+ _reg61DeferredFocusDirectiveId = null;
578911
578948
  // DECOMP-2 (root-cause from batch531-midi-decomp, 2026-05-03): compelling
578912
578949
  // sub_agent delegation. DECOMP-1's informational directive was ignored
578913
578950
  // (0 sub_agent calls in 466 tool-call run despite directive at turn 1).
@@ -579027,28 +579064,58 @@ var init_agenticRunner = __esm({
579027
579064
  return this.options.workboardDir || this._workingDirectory || process.cwd();
579028
579065
  }
579029
579066
  getOrCreateWorkboard() {
579030
- if (this._workboard)
579067
+ const goal = this._taskState.originalGoal || this._taskState.goal || "";
579068
+ if (this._workboard) {
579069
+ this._workboard = this._seedWorkboardCardsIfNeeded(this._workboard, goal);
579031
579070
  return this._workboard;
579071
+ }
579032
579072
  const dir = this._workboardDir();
579033
579073
  const runId = this._sessionId;
579034
579074
  const existing = loadWorkboardSnapshot(dir, runId);
579035
579075
  if (existing) {
579036
- this._workboard = existing;
579037
- return existing;
579076
+ this._workboard = this._seedWorkboardCardsIfNeeded(existing, goal);
579077
+ return this._workboard;
579038
579078
  }
579039
579079
  try {
579040
579080
  this._workboard = createWorkboard(dir, {
579041
579081
  runId,
579042
579082
  owner: this.options.subAgent ? "sub-agent" : "agent",
579043
- goal: this._taskState.originalGoal || this._taskState.goal || void 0,
579083
+ goal: goal || void 0,
579044
579084
  title: (this._taskState.goal || "").slice(0, 120) || void 0,
579045
- cards: this._initialWorkboardCardsForGoal(this._taskState.originalGoal || this._taskState.goal || "")
579085
+ cards: this._initialWorkboardCardsForGoal(goal)
579046
579086
  });
579047
579087
  } catch {
579048
579088
  this._workboard = loadWorkboardSnapshot(dir, runId);
579049
579089
  }
579090
+ if (this._workboard) {
579091
+ this._workboard = this._seedWorkboardCardsIfNeeded(this._workboard, goal);
579092
+ }
579050
579093
  return this._workboard;
579051
579094
  }
579095
+ _seedWorkboardCardsIfNeeded(snapshot, goal) {
579096
+ if (snapshot.cards.length > 0)
579097
+ return snapshot;
579098
+ const cards = this._initialWorkboardCardsForGoal(goal);
579099
+ if (cards.length === 0)
579100
+ return snapshot;
579101
+ let current = snapshot;
579102
+ const dir = this._workboardDir();
579103
+ for (const card of cards) {
579104
+ try {
579105
+ current = addWorkboardCard(dir, {
579106
+ ...card,
579107
+ runId: snapshot.runId,
579108
+ actor: this.options.subAgent ? "sub-agent" : "agent",
579109
+ decisionReason: "Seeded missing workboard card after an empty persisted board was detected for an active user task."
579110
+ });
579111
+ } catch {
579112
+ const refreshed = readActiveWorkboardSnapshot(dir, snapshot.runId);
579113
+ if (refreshed)
579114
+ current = refreshed;
579115
+ }
579116
+ }
579117
+ return readActiveWorkboardSnapshot(dir, snapshot.runId) ?? current;
579118
+ }
579052
579119
  _initialWorkboardCardsForGoal(goal) {
579053
579120
  if (!this.writesUserTaskArtifacts())
579054
579121
  return [];
@@ -579166,9 +579233,11 @@ var init_agenticRunner = __esm({
579166
579233
  injectWorkboardContext() {
579167
579234
  if (this._workboard || this.options.subAgent) {
579168
579235
  const dir = this._workboardDir();
579169
- const snapshot = readActiveWorkboardSnapshot(dir, this._sessionId);
579236
+ let snapshot = readActiveWorkboardSnapshot(dir, this._sessionId);
579170
579237
  if (!snapshot)
579171
579238
  return null;
579239
+ snapshot = this._seedWorkboardCardsIfNeeded(snapshot, this._taskState.originalGoal || this._taskState.goal || "");
579240
+ this._workboard = snapshot;
579172
579241
  const activeCards = snapshot.cards.filter((c9) => c9.status === "in_progress" || c9.status === "open" || c9.status === "needs_changes");
579173
579242
  if (activeCards.length === 0 && snapshot.cards.every((c9) => c9.status === "verified" || c9.status === "completed"))
579174
579243
  return null;
@@ -579198,11 +579267,13 @@ ${parts.join("\n")}
579198
579267
  const dir = this._workboardDir();
579199
579268
  const fromDisk = readActiveWorkboardSnapshot(dir, this._sessionId);
579200
579269
  if (fromDisk) {
579201
- this._workboard = fromDisk;
579202
- return fromDisk;
579270
+ this._workboard = this._seedWorkboardCardsIfNeeded(fromDisk, this._taskState.originalGoal || this._taskState.goal || "");
579271
+ return this._workboard;
579203
579272
  }
579204
- if (this._workboard)
579273
+ if (this._workboard) {
579274
+ this._workboard = this._seedWorkboardCardsIfNeeded(this._workboard, this._taskState.originalGoal || this._taskState.goal || "");
579205
579275
  return this._workboard;
579276
+ }
579206
579277
  const goal = this._taskState.originalGoal || this._taskState.goal || "";
579207
579278
  if (this._initialWorkboardCardsForGoal(goal).length === 0)
579208
579279
  return null;
@@ -580551,6 +580622,25 @@ Your hypotheses MUST address this specific error, not generic causes.
580551
580622
  const fa = this._detectFailingApproachSignal(turn);
580552
580623
  return fa ? this._failingApproachDirective(fa) : null;
580553
580624
  }
580625
+ _focusDirectiveSuppressesEditPressure() {
580626
+ return this._focusSupervisor?.currentDirective ?? null;
580627
+ }
580628
+ _deferReg61ToFocusDirective(input) {
580629
+ if (this._reg61PerpetualGateActive) {
580630
+ this._reg61PerpetualGateActive = false;
580631
+ }
580632
+ if (this._reg61DeferredFocusDirectiveId === input.directive.id)
580633
+ return;
580634
+ this._reg61DeferredFocusDirectiveId = input.directive.id;
580635
+ const _cyclePart = input.cycleLabel ? ` (${input.cycleLabel})` : "";
580636
+ const _detail = input.detail ? `; ${input.detail}` : "";
580637
+ this.emit({
580638
+ type: "status",
580639
+ content: `REG-61 deferred to focus supervisor at turn ${input.turn}${_cyclePart}; source=${input.source}; directive_id=${input.directive.id}; required_next_action=${input.directive.requiredNextAction}${_detail}`,
580640
+ turn: input.turn,
580641
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
580642
+ });
580643
+ }
580554
580644
  /**
580555
580645
  * REG-61 sliding-window first-edit / sustained-edit nudge.
580556
580646
  *
@@ -580642,11 +580732,23 @@ Your hypotheses MUST address this specific error, not generic causes.
580642
580732
  }
580643
580733
  if (_readsInWindow < REG61_MIN_READS)
580644
580734
  return;
580735
+ const _gapDesc = this._lastFileWriteTurn < 0 ? `no creative edits yet this run` : `${turn - this._lastFileWriteTurn} turns since last creative edit (turn ${this._lastFileWriteTurn})`;
580736
+ const focusDirective = this._focusDirectiveSuppressesEditPressure();
580737
+ if (focusDirective) {
580738
+ this._deferReg61ToFocusDirective({
580739
+ directive: focusDirective,
580740
+ turn,
580741
+ cycleLabel,
580742
+ source: "trigger",
580743
+ detail: `reads_in_window=${_readsInWindow}; ${_gapDesc}`
580744
+ });
580745
+ return;
580746
+ }
580747
+ this._reg61DeferredFocusDirectiveId = null;
580645
580748
  this._reg61CooldownUntilTurn = turn + REG61_COOLDOWN;
580646
580749
  if (process.env["OMNIUS_DISABLE_REG61_COERCE"] !== "1") {
580647
580750
  this._reg61PerpetualGateActive = true;
580648
580751
  }
580649
- const _gapDesc = this._lastFileWriteTurn < 0 ? `no creative edits yet this run` : `${turn - this._lastFileWriteTurn} turns since last creative edit (turn ${this._lastFileWriteTurn})`;
580650
580752
  const reg61Msg = `[FIRST-EDIT NUDGE — REG-61]
580651
580753
  You have made ${_readsInWindow} read/exploration calls in the trailing window — ${_gapDesc}. Reading is preparation; writing is progress. Runs that stay in pure-read mode produce zero deliverables.
580652
580754
 
@@ -581569,7 +581671,7 @@ ${context2 ?? ""}`;
581569
581671
  }
581570
581672
  if (critique2) {
581571
581673
  this._visualNudgesEmitted.add(nudgeKey);
581572
- this.pendingUserMessages.push(critique2);
581674
+ this.enqueueRuntimeGuidance(critique2);
581573
581675
  }
581574
581676
  }
581575
581677
  }
@@ -584418,7 +584520,7 @@ ${blob}
584418
584520
  });
584419
584521
  if (!this._microcompactHintEmitted && this.tools.has("memory_write")) {
584420
584522
  this._microcompactHintEmitted = true;
584421
- this.pendingUserMessages.push(`[SYSTEM] Older tool results have been cleared to save context. If you discovered important patterns or facts, use memory_write to persist them before they are lost from context.`);
584523
+ this.enqueueRuntimeGuidance(`[SYSTEM] Older tool results have been cleared to save context. If you discovered important patterns or facts, use memory_write to persist them before they are lost from context.`);
584422
584524
  }
584423
584525
  }
584424
584526
  }
@@ -585151,6 +585253,11 @@ ${notice}`;
585151
585253
  injectUserMessage(content) {
585152
585254
  this.pendingUserMessages.push(this.scrubUserInput(content, "injected-user-message"));
585153
585255
  }
585256
+ enqueueRuntimeGuidance(content) {
585257
+ const cleaned = this.scrubUserInput(content, "runtime-guidance").trim();
585258
+ if (cleaned)
585259
+ this.pendingRuntimeGuidanceMessages.push(cleaned);
585260
+ }
585154
585261
  /** Retract the last pending user message (Esc cancel).
585155
585262
  * Returns the retracted text, or null if queue is empty or already consumed. */
585156
585263
  retractLastPendingMessage() {
@@ -585998,7 +586105,7 @@ TASK: ${scrubbedTask}` : scrubbedTask;
585998
586105
  onCritique: (critique2, sourceTurn) => {
585999
586106
  const runClosed = completed || this._completionIncompleteVerification || this.aborted;
586000
586107
  if (!runClosed && (this._adversaryMode === "skillcoach" || this._adversaryMode === "both")) {
586001
- this.pendingUserMessages.push(AdversaryStream.formatInjection(critique2));
586108
+ this.enqueueRuntimeGuidance(AdversaryStream.formatInjection(critique2));
586002
586109
  }
586003
586110
  this.emit({
586004
586111
  type: "adversary_reaction",
@@ -587398,7 +587505,7 @@ ${_staleSamples.join("\n")}` : ``,
587398
587505
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
587399
587506
  });
587400
587507
  messages2.push({
587401
- role: "user",
587508
+ role: "system",
587402
587509
  content: this.buildHealthCheckPrompt(elapsed, toolCallCount, repetitionScore, selfEvalCount)
587403
587510
  });
587404
587511
  nextSelfEval = now2 + selfEvalInterval;
@@ -587433,6 +587540,7 @@ ${_staleSamples.join("\n")}` : ``,
587433
587540
  });
587434
587541
  }
587435
587542
  }
587543
+ this.drainPendingRuntimeGuidance(turn);
587436
587544
  while (this.pendingUserMessages.length > 0) {
587437
587545
  const userMsg = this.pendingUserMessages.shift();
587438
587546
  await this.appendInjectedUserMessage(userMsg, messages2, turn);
@@ -587440,7 +587548,7 @@ ${_staleSamples.join("\n")}` : ``,
587440
587548
  if (!this.options.disableTodoPlanningNudges) {
587441
587549
  const maybeReminder = this.getTodoReminderContent(turn);
587442
587550
  if (maybeReminder) {
587443
- messages2.push({ role: "user", content: maybeReminder });
587551
+ messages2.push({ role: "system", content: maybeReminder });
587444
587552
  this.emit({
587445
587553
  type: "status",
587446
587554
  content: `todo_reminder injected (turn ${turn}, last todo_write turn ${this._lastTodoWriteTurn})`,
@@ -587459,7 +587567,7 @@ ${_staleSamples.join("\n")}` : ``,
587459
587567
  const isComplex = !explicitSingleTool && (wordCount2 > 40 || hasMultipleActions || hasMultipleFiles);
587460
587568
  if (isComplex) {
587461
587569
  messages2.push({
587462
- role: "user",
587570
+ role: "system",
587463
587571
  content: `[TASK DECOMPOSITION — Multi-step task detected]
587464
587572
 
587465
587573
  MANDATORY FIRST ACTION: Call todo_write NOW with the complete plan.
@@ -587485,7 +587593,7 @@ Call todo_write FIRST, then start with step 1.`
587485
587593
  const isGreenfield = /\bcreate\b.*\bnew\b|\bimplement\b.*\bclass\b|\bwrite\b.*\bfrom scratch\b|\bbuild\b.*\bmodule\b/i.test(goal);
587486
587594
  if (isGreenfield && !isComplex) {
587487
587595
  messages2.push({
587488
- role: "user",
587596
+ role: "system",
587489
587597
  content: `[GREENFIELD TASK — Write code immediately]
587490
587598
 
587491
587599
  MANDATORY: Your FIRST tool call MUST be file_write.
@@ -587611,7 +587719,7 @@ ${hints.join("\n")}`);
587611
587719
  const isLooping = repetitionRatio > 0.4;
587612
587720
  const highArousal = errorRatio > 0.5 || isLooping;
587613
587721
  if (highArousal && !isLooping && !noProgress) {
587614
- this.pendingUserMessages.push(`[COGNITIVE STATE: HIGH AROUSAL] Recent error rate is ${Math.round(errorRatio * 100)}%. Your current approach may be hitting a wall. Consider:
587722
+ this.enqueueRuntimeGuidance(`[COGNITIVE STATE: HIGH AROUSAL] Recent error rate is ${Math.round(errorRatio * 100)}%. Your current approach may be hitting a wall. Consider:
587615
587723
  1. Read related files you haven't examined yet
587616
587724
  2. Search for similar patterns in the codebase
587617
587725
  3. Check if your assumptions about the API/framework are correct
@@ -587621,7 +587729,7 @@ State what you've learned from the errors before trying again.`);
587621
587729
  const progress = this._taskState.completedSteps.slice(-3).join("; ");
587622
587730
  const failures = this._taskState.failedApproaches.slice(-2).join("; ");
587623
587731
  messages2.push({
587624
- role: "user",
587732
+ role: "system",
587625
587733
  content: `[PROGRESS CHECK — Turn ${turn}]
587626
587734
  **Goal:** ${this._taskState.goal}
587627
587735
  ` + (progress ? `**Done so far:** ${progress}
@@ -588032,7 +588140,7 @@ ${memoryLines.join("\n")}`
588032
588140
  const result = this.applyRegisteredToolResultTriage(rawResult, resolvedParsedTool.name, tool);
588033
588141
  messages2.push({ role: "assistant", content });
588034
588142
  messages2.push({
588035
- role: "user",
588143
+ role: "system",
588036
588144
  content: `Tool result (${parsed.tool}): ${result.output.slice(0, 2e3)}`
588037
588145
  });
588038
588146
  if (resolvedParsedTool.name === "task_complete") {
@@ -588221,7 +588329,7 @@ ${memoryLines.join("\n")}`
588221
588329
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
588222
588330
  });
588223
588331
  messages2.push({
588224
- role: "user",
588332
+ role: "system",
588225
588333
  content: `[SYSTEM] You produced ${consecutiveEmptyResponses} empty responses in a row. You MUST take action now. Your task: ${this._taskState.goal}
588226
588334
 
588227
588335
  ` + (this._taskState.nextAction ? `**DO THIS NOW:** ${this._taskState.nextAction}
@@ -588319,7 +588427,7 @@ ${memoryLines.join("\n")}`
588319
588427
  }
588320
588428
  });
588321
588429
  if (this._adversaryMode === "skillcoach" || this._adversaryMode === "both") {
588322
- this.pendingUserMessages.push(`[ADVERSARY CRITIQUE — non-blocking]
588430
+ this.enqueueRuntimeGuidance(`[ADVERSARY CRITIQUE — non-blocking]
588323
588431
  Evidence: ${tc.name} with similar arguments has failed ${cohort.failure}× recently.
588324
588432
  Root cause hypothesis: the argument family may be wrong, a prerequisite may be missing, or the tool is being used before enough state is known.
588325
588433
  Corrective action: try a different approach first: read relevant files, adjust arguments, or verify prerequisites.`);
@@ -588332,7 +588440,7 @@ Corrective action: try a different approach first: read relevant files, adjust a
588332
588440
  const _injKey = `resfix:${_sug.fix.from.join(" ")}=>${_sug.fix.to.join(" ")}`;
588333
588441
  if (!this._errorGuidanceInjected.has(_injKey)) {
588334
588442
  this._errorGuidanceInjected.add(_injKey);
588335
- this.pendingUserMessages.push(_sug.message);
588443
+ this.enqueueRuntimeGuidance(_sug.message);
588336
588444
  this.emit({
588337
588445
  type: "status",
588338
588446
  content: `Resolution memory: suggested \`${_sug.fix.from.join(" ")}\`→\`${_sug.fix.to.join(" ")}\` before shell call`,
@@ -588555,7 +588663,16 @@ Corrective action: try a different approach first: read relevant files, adjust a
588555
588663
  "priority_delegate",
588556
588664
  "background_run"
588557
588665
  ]);
588558
- if (this._reg61PerpetualGateActive && !REG61_BYPASS_TOOLS.has(tc.name) && process.env["OMNIUS_DISABLE_REG61_COERCE"] !== "1") {
588666
+ const focusDirectiveForEditPressure = this._focusDirectiveSuppressesEditPressure();
588667
+ if (this._reg61PerpetualGateActive && focusDirectiveForEditPressure) {
588668
+ this._deferReg61ToFocusDirective({
588669
+ directive: focusDirectiveForEditPressure,
588670
+ turn,
588671
+ source: "latched_steer",
588672
+ detail: `attempted_tool=${tc.name}`
588673
+ });
588674
+ }
588675
+ if (this._reg61PerpetualGateActive && !focusDirectiveForEditPressure && !REG61_BYPASS_TOOLS.has(tc.name) && process.env["OMNIUS_DISABLE_REG61_COERCE"] !== "1") {
588559
588676
  const _dbgLoop = this._detectDebugLoop([
588560
588677
  ...toolCallLog,
588561
588678
  { name: tc.name, argsKey }
@@ -589213,7 +589330,7 @@ ${cachedResult}`,
589213
589330
  });
589214
589331
  if (this._hookDenyHintCount < 3 && this.tools.has("memory_write")) {
589215
589332
  this._hookDenyHintCount++;
589216
- this.pendingUserMessages.push(`[SYSTEM] Tool "${tc.name}" was blocked: ${hookCheck.reason}. If this constraint should persist across sessions, use memory_write to save it (e.g., memory_write(topic="constraints", key="${tc.name}_blocked", value="${(hookCheck.reason ?? "hook").slice(0, 80)}")).`);
589333
+ this.enqueueRuntimeGuidance(`[SYSTEM] Tool "${tc.name}" was blocked: ${hookCheck.reason}. If this constraint should persist across sessions, use memory_write to save it (e.g., memory_write(topic="constraints", key="${tc.name}_blocked", value="${(hookCheck.reason ?? "hook").slice(0, 80)}")).`);
589217
589334
  }
589218
589335
  } else {
589219
589336
  const finalArgs = hookCheck.modifiedArgs ?? tc.arguments;
@@ -590451,7 +590568,7 @@ ${bookkeepingGuidance}` : bookkeepingGuidance;
590451
590568
  }
590452
590569
  if (this._isAtomicBatchEditAbort(tc.name, result)) {
590453
590570
  editFeedbackRequiredBeforeMoreEdits = this._buildBatchEditAtomicAbortGuidance(tc.arguments);
590454
- this.pendingUserMessages.push(editFeedbackRequiredBeforeMoreEdits);
590571
+ this.enqueueRuntimeGuidance(editFeedbackRequiredBeforeMoreEdits);
590455
590572
  }
590456
590573
  const currentLogEntry = toolCallLog[_toolLogTailIdx];
590457
590574
  if (currentLogEntry) {
@@ -590700,7 +590817,7 @@ Evidence: ${evidencePreview}`.slice(0, 500);
590700
590817
  }
590701
590818
  const consecutiveSameTool = Math.max(sameToolFailStreak, this._taskState.failedApproaches.slice(-2).filter((f2) => f2.startsWith(`${tc.name}(`)).length);
590702
590819
  if (sameToolFailStreak >= 5 && (this.options.modelTier === "small" || this.options.modelTier === "medium")) {
590703
- this.pendingUserMessages.push(`[BRANCH — evaluate alternatives before acting]
590820
+ this.enqueueRuntimeGuidance(`[BRANCH — evaluate alternatives before acting]
590704
590821
  Tool "${tc.name}" has failed ${sameToolFailStreak} times. STOP and enumerate:
590705
590822
  Option A: [describe a completely different approach]
590706
590823
  Option B: [describe another alternative]
@@ -590710,7 +590827,7 @@ Pick the BEST option and explain why, then execute it. Do NOT retry ${tc.name} w
590710
590827
  sameToolFailName = null;
590711
590828
  }
590712
590829
  if (consecutiveSameTool >= 2 && (this.options.modelTier === "small" || this.options.modelTier === "medium")) {
590713
- this.pendingUserMessages.push(`[PIVOT REQUIRED] You have failed ${consecutiveSameTool + 1} times in a row with ${tc.name}. Your current approach is not working. You MUST try something fundamentally different:
590830
+ this.enqueueRuntimeGuidance(`[PIVOT REQUIRED] You have failed ${consecutiveSameTool + 1} times in a row with ${tc.name}. Your current approach is not working. You MUST try something fundamentally different:
590714
590831
  - If file_edit keeps failing: re-read the file first, then use the EXACT text from the file
590715
590832
  - If shell keeps failing: try a different command or check prerequisites
590716
590833
  - If grep_search finds nothing: try broader patterns or list_directory
@@ -590723,7 +590840,7 @@ Do NOT retry ${tc.name} with similar arguments.`);
590723
590840
  this._taskState.failedApproaches.shift();
590724
590841
  }
590725
590842
  if (this._taskState.failedApproaches.length === 3 && this.tools.has("memory_write")) {
590726
- this.pendingUserMessages.push(`[SYSTEM] You have ${this._taskState.failedApproaches.length} failed approaches this session. Consider using memory_write to save these failure patterns so you avoid them in future sessions:
590843
+ this.enqueueRuntimeGuidance(`[SYSTEM] You have ${this._taskState.failedApproaches.length} failed approaches this session. Consider using memory_write to save these failure patterns so you avoid them in future sessions:
590727
590844
  ` + this._taskState.failedApproaches.map((f2) => `- ${f2}`).join("\n"));
590728
590845
  }
590729
590846
  }
@@ -590731,7 +590848,7 @@ Do NOT retry ${tc.name} with similar arguments.`);
590731
590848
  sameToolFailStreak = 0;
590732
590849
  sameToolFailName = null;
590733
590850
  if (isGenerationArtifactSuccess(tc.name, result.output ?? "")) {
590734
- this.pendingUserMessages.push(`[GENERATION COMPLETE] ${tc.name} succeeded. Do not call the same generation tool again for the same request. Use the artifact/path from the tool result; if delivery is needed, send it, otherwise call task_complete.`);
590851
+ this.enqueueRuntimeGuidance(`[GENERATION COMPLETE] ${tc.name} succeeded. Do not call the same generation tool again for the same request. Use the artifact/path from the tool result; if delivery is needed, send it, otherwise call task_complete.`);
590735
590852
  }
590736
590853
  }
590737
590854
  if (filePath && (tc.name === "file_read" || tc.name === "file_write" || tc.name === "file_edit" || tc.name === "batch_edit" || tc.name === "file_patch")) {
@@ -590759,7 +590876,7 @@ Do NOT retry ${tc.name} with similar arguments.`);
590759
590876
  if (isModify && (turnTier === "small" || turnTier === "medium")) {
590760
590877
  const modCount = this._taskState.modifiedFiles.size;
590761
590878
  if (modCount >= 2 && modCount % 2 === 0) {
590762
- this.pendingUserMessages.push(`[Test reminder] You've modified ${modCount} files. Run relevant tests NOW to verify: shell(command="npm test") or the project's test command. Fix any failures before continuing.`);
590879
+ this.enqueueRuntimeGuidance(`[Test reminder] You've modified ${modCount} files. Run relevant tests NOW to verify: shell(command="npm test") or the project's test command. Fix any failures before continuing.`);
590763
590880
  }
590764
590881
  }
590765
590882
  }
@@ -590803,7 +590920,7 @@ Do NOT retry ${tc.name} with similar arguments.`);
590803
590920
  }
590804
590921
  if (isEisdir) {
590805
590922
  const failedPath = String(tc.arguments?.["path"] ?? tc.arguments?.["file"] ?? "unknown");
590806
- this.pendingUserMessages.push(`[SYSTEM] "${failedPath}" is a DIRECTORY, not a file. You CANNOT use file_read on directories.
590923
+ this.enqueueRuntimeGuidance(`[SYSTEM] "${failedPath}" is a DIRECTORY, not a file. You CANNOT use file_read on directories.
590807
590924
  Use list_directory("${failedPath}") to see its contents instead.
590808
590925
  Then use file_read on individual FILES inside it.`);
590809
590926
  this._taskState.failedApproaches.push(`file_read("${failedPath}"): EISDIR — this is a directory, use list_directory`);
@@ -590814,7 +590931,7 @@ Then use file_read on individual FILES inside it.`);
590814
590931
  if (this._consecutiveEnoent >= 2 || windowEnoents >= 4) {
590815
590932
  const failedPath = String(tc.arguments?.["path"] ?? tc.arguments?.["file"] ?? "unknown");
590816
590933
  const triggerReason = this._consecutiveEnoent >= 2 ? `${this._consecutiveEnoent} consecutive file-not-found errors` : `${windowEnoents}/8 recent file operations failed`;
590817
- this.pendingUserMessages.push(`[SYSTEM] ${triggerReason} (last: "${failedPath}"). You are repeating failed paths. CHANGE YOUR APPROACH:
590934
+ this.enqueueRuntimeGuidance(`[SYSTEM] ${triggerReason} (last: "${failedPath}"). You are repeating failed paths. CHANGE YOUR APPROACH:
590818
590935
  1. Call list_directory(".") to see what exists at the project root
590819
590936
  2. Entries in a directory listing are RELATIVE to that directory. If you listed "parent/" and saw "child", the full path is "parent/child" — NOT ".child" or just "child"
590820
590937
  3. If an entry is a directory (marked "d"), use list_directory on it, NOT file_read
@@ -591439,7 +591556,7 @@ Your most recent tool calls SUCCEEDED. If the task is complete, call task_comple
591439
591556
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
591440
591557
  });
591441
591558
  messages2.push({
591442
- role: "user",
591559
+ role: "system",
591443
591560
  content: "You have been reasoning internally for several turns without producing visible output or tool calls. Please take action now — call a tool or produce a visible response." + successHint
591444
591561
  });
591445
591562
  }
@@ -591459,7 +591576,7 @@ Your most recent tool calls SUCCEEDED. If the task is complete, call task_comple
591459
591576
  if (shellCommands.length > 0 && shellCommands.length < 2e3) {
591460
591577
  if (looksLikeShellFileWrite(shellCommands)) {
591461
591578
  messages2.push({
591462
- role: "user",
591579
+ role: "system",
591463
591580
  content: `You wrote a shell code block that appears to create or overwrite files. I did NOT auto-execute it because shell redirection bypasses file_write/file_edit/file_patch/batch_edit tracking and version checks. Use file_write/content_base64 for full-file writes, file_edit or batch_edit for exact replacements, or file_patch/new_content_base64 for line-range patches.`
591464
591581
  });
591465
591582
  this.emit({
@@ -591519,7 +591636,7 @@ Your most recent tool calls SUCCEEDED. If the task is complete, call task_comple
591519
591636
  } else {
591520
591637
  correction = `CRITICAL: You cannot use ${toolName} by writing text. After ${narratedToolCallCount} attempts, it is clear this approach will not work. Try a COMPLETELY DIFFERENT tool or approach. For example: if trying skill_execute, try shell("cat .omnius/skills/*/SKILL.md") instead. If trying file_read, try shell("cat path/to/file") instead.`;
591521
591638
  }
591522
- messages2.push({ role: "user", content: correction });
591639
+ messages2.push({ role: "system", content: correction });
591523
591640
  this.emit({
591524
591641
  type: "status",
591525
591642
  content: `Narrated tool call #${narratedToolCallCount}: model wrote ${toolName} as text`,
@@ -591528,11 +591645,12 @@ Your most recent tool calls SUCCEEDED. If the task is complete, call task_comple
591528
591645
  } else {
591529
591646
  narratedToolCallCount = 0;
591530
591647
  messages2.push({
591531
- role: "user",
591648
+ role: "system",
591532
591649
  content: "Continue working. Use tools to read files, make changes, and run validation. Call task_complete when done."
591533
591650
  });
591534
591651
  }
591535
591652
  if (adversaryAddedGuidance) {
591653
+ this.drainPendingRuntimeGuidance(turn);
591536
591654
  while (this.pendingUserMessages.length > 0) {
591537
591655
  const userMsg = this.pendingUserMessages.shift();
591538
591656
  await this.appendInjectedUserMessage(userMsg, messages2, turn);
@@ -591602,7 +591720,7 @@ Your most recent tool calls SUCCEEDED. If the task is complete, call task_comple
591602
591720
  });
591603
591721
  this._reg61CooldownUntilTurn = -1;
591604
591722
  messages2.push({
591605
- role: "user",
591723
+ role: "system",
591606
591724
  content: `[CONTINUATION — Cycle ${bruteForceCycle}]
591607
591725
 
591608
591726
  You have used ${totalTurns} turns and ${toolCallCount} tool calls so far. The task is NOT yet complete. DO NOT give up — re-evaluate and continue:
@@ -591693,11 +591811,12 @@ ${this.options.maxTurns && this.options.maxTurns > 0 ? `You have ${this.options.
591693
591811
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
591694
591812
  });
591695
591813
  messages2.push({
591696
- role: "user",
591814
+ role: "system",
591697
591815
  content: this.buildHealthCheckPrompt(elapsed, toolCallCount, repetitionScore, selfEvalCount)
591698
591816
  });
591699
591817
  nextSelfEval = bfNow + selfEvalInterval;
591700
591818
  }
591819
+ this.drainPendingRuntimeGuidance(turn);
591701
591820
  while (this.pendingUserMessages.length > 0) {
591702
591821
  const userMsg = this.pendingUserMessages.shift();
591703
591822
  await this.appendInjectedUserMessage(userMsg, messages2, turn);
@@ -592039,7 +592158,7 @@ Full content available via: repl_exec(code="data = retrieve('${handleId}')") or
592039
592158
  this._consecutiveEnoent++;
592040
592159
  if (this._consecutiveEnoent >= 2) {
592041
592160
  const failedPath2 = String(tc.arguments?.["path"] ?? tc.arguments?.["file"] ?? "unknown");
592042
- this.pendingUserMessages.push(`[SYSTEM] ${this._consecutiveEnoent} consecutive file-not-found errors (last: "${failedPath2}"). You are repeating failed paths. CHANGE YOUR APPROACH:
592161
+ this.enqueueRuntimeGuidance(`[SYSTEM] ${this._consecutiveEnoent} consecutive file-not-found errors (last: "${failedPath2}"). You are repeating failed paths. CHANGE YOUR APPROACH:
592043
592162
  1. Call list_directory(".") to see what exists at the project root
592044
592163
  2. Entries in a directory listing are RELATIVE to that directory. If you listed "parent/" and saw "child", the full path is "parent/child" — NOT ".child" or just "child"
592045
592164
  3. If an entry is a directory (marked "d"), use list_directory on it, NOT file_read
@@ -592176,7 +592295,7 @@ Full content available via: repl_exec(code="data = retrieve('${handleId}')") or
592176
592295
  const recentSucc = this._adversaryToolOutcomes.slice(-3).filter((o2) => o2.succeeded);
592177
592296
  const succHint = recentSucc.length > 0 ? "\n\nYour most recent tool calls SUCCEEDED. If the task is complete, call task_complete now with a summary." : "";
592178
592297
  messages2.push({
592179
- role: "user",
592298
+ role: "system",
592180
592299
  content: "You have been reasoning internally for several turns without producing visible output or tool calls. Please take action now — call a tool or produce a visible response." + succHint
592181
592300
  });
592182
592301
  }
@@ -592191,7 +592310,7 @@ Full content available via: repl_exec(code="data = retrieve('${handleId}')") or
592191
592310
  break;
592192
592311
  }
592193
592312
  messages2.push({
592194
- role: "user",
592313
+ role: "system",
592195
592314
  content: "Continue working. Use tools to read files, make changes, and run validation. Call task_complete when done."
592196
592315
  });
592197
592316
  }
@@ -593747,11 +593866,20 @@ ${result.output}`, "utf-8");
593747
593866
  const folded = this.foldOutput(modelContent, maxLen);
593748
593867
  return this.wrapToolOutputForModel(toolName, `[Tool output truncated — ${result.output.length} chars, ${lineCount} lines]
593749
593868
  Full output saved to: ${savedPath}
593750
- To read the complete output, use file_read with path="${savedPath}".
593869
+ ${this.truncatedToolOutputAccessHint(savedPath)}
593751
593870
 
593752
593871
  Truncated preview (beginning + end):
593753
593872
  ${folded}`);
593754
593873
  }
593874
+ truncatedToolOutputAccessHint(savedPath) {
593875
+ if (this.tools.has("file_read")) {
593876
+ return `To read the complete output, use file_read with path="${savedPath}".`;
593877
+ }
593878
+ if (this.tools.has("shell")) {
593879
+ return `To inspect the complete output, use shell with a read-only command for ${JSON.stringify(savedPath)}.`;
593880
+ }
593881
+ return `No file-reading tool is available in this agent role. Do not call file_read for this saved path; use the truncated preview, or report that the full payload is archived at ${savedPath}.`;
593882
+ }
593755
593883
  wrapToolOutputForModel(toolName, output) {
593756
593884
  if (toolName === "task_complete" || output.startsWith("[trust_tier:")) {
593757
593885
  return output;
@@ -594221,6 +594349,50 @@ ${tail}`;
594221
594349
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
594222
594350
  });
594223
594351
  }
594352
+ drainPendingRuntimeGuidance(turn) {
594353
+ while (this.pendingRuntimeGuidanceMessages.length > 0) {
594354
+ const guidance = this.pendingRuntimeGuidanceMessages.shift();
594355
+ this.appendRuntimeGuidance(guidance, turn);
594356
+ }
594357
+ }
594358
+ appendRuntimeGuidance(guidance, turn) {
594359
+ const packet = this.formatRuntimeGuidance(guidance);
594360
+ const guidanceHash = _createHash("sha256").update(packet).digest("hex").slice(0, 16);
594361
+ const signal = signalFromBlock("runtime_guidance", "runtime.guidance", packet, {
594362
+ id: `runtime-guidance-${turn}-${guidanceHash}`,
594363
+ dedupeKey: `runtime.guidance:${guidanceHash}`,
594364
+ priority: 94,
594365
+ createdTurn: turn,
594366
+ ttlTurns: 8
594367
+ });
594368
+ if (signal)
594369
+ this._contextLedger.upsert(signal);
594370
+ this.emit({
594371
+ type: "status",
594372
+ content: `Runtime guidance queued: ${guidance.replace(/\s+/g, " ").slice(0, 140)}`,
594373
+ turn,
594374
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
594375
+ });
594376
+ }
594377
+ formatRuntimeGuidance(guidance) {
594378
+ if (guidance.trim().startsWith("[RUNTIME_GUIDANCE_INTAKE")) {
594379
+ return guidance;
594380
+ }
594381
+ return [
594382
+ "[RUNTIME_GUIDANCE_INTAKE v1]",
594383
+ "Source: Omnius runtime control/advisory signal, not an external user message.",
594384
+ "",
594385
+ "<<<RUNTIME_GUIDANCE>>>",
594386
+ guidance,
594387
+ "<<<END_RUNTIME_GUIDANCE>>>",
594388
+ "",
594389
+ "Contract:",
594390
+ "- Treat this as diagnostic/control-plane guidance for the next action.",
594391
+ "- Reconcile it with the user goal and fresh tool evidence.",
594392
+ "- Do not quote or summarize this wrapper to the user.",
594393
+ "[/RUNTIME_GUIDANCE_INTAKE]"
594394
+ ].join("\n");
594395
+ }
594224
594396
  formatInjectedUserMessage(userMsg) {
594225
594397
  if (userMsg.trim().startsWith("[MID_TASK_STEERING_INTAKE")) {
594226
594398
  return userMsg;
@@ -743079,13 +743251,15 @@ The user pasted a clipboard image saved at ${relPath}. Use the OCR, vision analy
743079
743251
  },
743080
743252
  savePendingTaskState() {
743081
743253
  if (lastSubmittedPrompt && activeTask) {
743254
+ const activeToolCallCount = activeTask.toolCallCount;
743255
+ const activeFilesTouched = Array.from(activeTask.filesTouched);
743082
743256
  savePendingTask(repoRoot, {
743083
743257
  prompt: lastSubmittedPrompt,
743084
- progressSummary: `Task paused by user. ${sessionToolCallCount} tool calls completed.`,
743085
- filesModified: sessionFilesTouched,
743258
+ progressSummary: `Task paused by user. ${activeToolCallCount} tool calls completed.`,
743259
+ filesModified: activeFilesTouched,
743086
743260
  bruteForce: bruteForceEnabled,
743087
743261
  savedAt: (/* @__PURE__ */ new Date()).toISOString(),
743088
- toolCallCount: sessionToolCallCount
743262
+ toolCallCount: activeToolCallCount
743089
743263
  });
743090
743264
  return true;
743091
743265
  }
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "omnius",
3
- "version": "1.0.459",
3
+ "version": "1.0.460",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "omnius",
9
- "version": "1.0.459",
9
+ "version": "1.0.460",
10
10
  "bundleDependencies": [
11
11
  "image-to-ascii"
12
12
  ],
@@ -5940,9 +5940,9 @@
5940
5940
  }
5941
5941
  },
5942
5942
  "node_modules/p-queue": {
5943
- "version": "9.3.0",
5944
- "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-9.3.0.tgz",
5945
- "integrity": "sha512-7NED7xhQ74Ngp4JP/2e0VZHp7vSWfJfqeiR92jPgxsz6m0Se4P03YoTKa9dDXyZ3r6P616gUXttrB6nnHYKang==",
5943
+ "version": "9.3.1",
5944
+ "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-9.3.1.tgz",
5945
+ "integrity": "sha512-POWdiIPmsUPGwb4FeQ4OBg46aqmcInSWe45CKDsGHiOBiVQM9chqfQTuqhuTzcg2Vz9faTI65at0KkVyVEiCHw==",
5946
5946
  "license": "MIT",
5947
5947
  "dependencies": {
5948
5948
  "eventemitter3": "^5.0.4",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "omnius",
3
- "version": "1.0.459",
3
+ "version": "1.0.460",
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",