omnius 1.0.365 → 1.0.366

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
@@ -558574,6 +558574,73 @@ function buildCriticPacketFromLedger(ledger) {
558574
558574
  }
558575
558575
  return lines.join("\n");
558576
558576
  }
558577
+ function appendUnresolved(items, text2, source) {
558578
+ const clean5 = cleanText(text2, 500);
558579
+ if (!clean5)
558580
+ return items;
558581
+ if (items.some((item) => item.text === clean5 && item.source === source)) {
558582
+ return items;
558583
+ }
558584
+ return [
558585
+ ...items,
558586
+ {
558587
+ id: nextId2("unresolved", items.length),
558588
+ text: clean5,
558589
+ source,
558590
+ recordedAtIso: nowIso2()
558591
+ }
558592
+ ];
558593
+ }
558594
+ function isMutationEvidence(entry) {
558595
+ if (entry.kind === "file_change")
558596
+ return true;
558597
+ return entry.success === true && /^(file_write|file_edit|file_patch|batch_edit)$/.test(entry.toolName ?? "");
558598
+ }
558599
+ function isSuccessfulVerificationEvidence(entry) {
558600
+ if (entry.success !== true)
558601
+ return false;
558602
+ const text2 = `${entry.toolName ?? ""} ${entry.summary}`.toLowerCase();
558603
+ return /\b(test|tests|tested|verify|verified|verification|build|built|compile|compiled|tsc|vitest|jest|pytest|go test|cargo test|pass|passed|success)\b/.test(text2);
558604
+ }
558605
+ function isFailedVerificationEvidence(entry) {
558606
+ if (entry.success !== false)
558607
+ return false;
558608
+ const text2 = `${entry.toolName ?? ""} ${entry.summary}`.toLowerCase();
558609
+ return /\b(test|tests|verify|verification|build|compile|tsc|vitest|jest|pytest|go test|cargo test)\b/.test(text2);
558610
+ }
558611
+ function isStaleEditEvidence(entry) {
558612
+ if (entry.success !== false)
558613
+ return false;
558614
+ const text2 = entry.summary.toLowerCase();
558615
+ return /stale edit loop blocked|old[_ -]?string|old text|expected[_ -]?hash|context mismatch|no occurrences|could not find/.test(text2);
558616
+ }
558617
+ function finalizeCompletionLedgerTruth(ledger) {
558618
+ let unresolved = [...ledger.unresolved];
558619
+ let lastMutation = -1;
558620
+ let lastVerification = -1;
558621
+ ledger.evidence.forEach((entry, index) => {
558622
+ if (isMutationEvidence(entry))
558623
+ lastMutation = index;
558624
+ if (isSuccessfulVerificationEvidence(entry))
558625
+ lastVerification = index;
558626
+ if (isFailedVerificationEvidence(entry)) {
558627
+ unresolved = appendUnresolved(unresolved, `Verification failed or did not prove success: ${entry.summary}`, entry.id);
558628
+ }
558629
+ if (isStaleEditEvidence(entry)) {
558630
+ unresolved = appendUnresolved(unresolved, `Stale edit failure remains unresolved: ${entry.summary}`, entry.id);
558631
+ }
558632
+ });
558633
+ if (lastVerification >= 0 && lastMutation > lastVerification) {
558634
+ unresolved = appendUnresolved(unresolved, "File changes occurred after the last successful verification; final verification is stale.", "verification_freshness");
558635
+ }
558636
+ const status = ledger.status === "blocked" || ledger.status === "request_changes" ? ledger.status : unresolved.length > 0 ? "incomplete_verification" : ledger.status;
558637
+ return {
558638
+ ...ledger,
558639
+ unresolved,
558640
+ status,
558641
+ updatedAtIso: nowIso2()
558642
+ };
558643
+ }
558577
558644
  function saveCompletionLedger(filePath, ledger) {
558578
558645
  mkdirSync49(dirname28(filePath), { recursive: true });
558579
558646
  writeFileSync40(filePath, `${JSON.stringify(ledger, null, 2)}
@@ -563850,11 +563917,59 @@ ${text2}` : SUMMARY_PREFIX;
563850
563917
  }
563851
563918
  });
563852
563919
 
563920
+ // packages/orchestrator/dist/artifactQuality.js
563921
+ function isInternalArtifactPrompt(text2) {
563922
+ const raw = String(text2 ?? "");
563923
+ if (!raw.trim())
563924
+ return false;
563925
+ return INTERNAL_PROMPT_PATTERNS.some((pattern) => pattern.test(raw));
563926
+ }
563927
+ function assessTaskArtifactQuality(input) {
563928
+ if (input.artifactMode === "internal") {
563929
+ return { eligible: false, reason: "internal artifact mode" };
563930
+ }
563931
+ const goal = String(input.goal ?? "");
563932
+ const summary = String(input.summary ?? "");
563933
+ if (isInternalArtifactPrompt(goal) || isInternalArtifactPrompt(summary)) {
563934
+ return { eligible: false, reason: "internal helper prompt" };
563935
+ }
563936
+ const toolsUsed = input.toolsUsed ?? [];
563937
+ const filesTouched = input.filesTouched ?? [];
563938
+ const turns = input.turns ?? 0;
563939
+ if (turns <= 0 && toolsUsed.length === 0) {
563940
+ return { eligible: false, reason: "zero-turn no-tool artifact" };
563941
+ }
563942
+ if (!summary.trim() && toolsUsed.length === 0 && filesTouched.length === 0) {
563943
+ return { eligible: false, reason: "empty no-evidence artifact" };
563944
+ }
563945
+ return { eligible: true };
563946
+ }
563947
+ var INTERNAL_PROMPT_PATTERNS;
563948
+ var init_artifactQuality = __esm({
563949
+ "packages/orchestrator/dist/artifactQuality.js"() {
563950
+ "use strict";
563951
+ INTERNAL_PROMPT_PATTERNS = [
563952
+ /\byou are an emotion center\b/i,
563953
+ /\bemotion center\b.*\brespond with one emoji\b/i,
563954
+ /\byou are the agent's private reflection process\b/i,
563955
+ /\bprefrontal cortex gating evaluator\b/i,
563956
+ /\bdentate gyrus pattern separation evaluator\b/i,
563957
+ /\bsnr evaluator\b/i,
563958
+ /\byou are the prefrontal cortex\b/i,
563959
+ /\byou are the hippocampus\b/i,
563960
+ /\byou are the amygdala\b/i,
563961
+ /\byou are the inner critic\b/i,
563962
+ /\byou are the basal ganglia\b/i
563963
+ ];
563964
+ }
563965
+ });
563966
+
563853
563967
  // packages/orchestrator/dist/reflectionBuffer.js
563854
563968
  var MAX_REFLECTIONS, MAX_TOTAL, TaskReflectionBuffer;
563855
563969
  var init_reflectionBuffer = __esm({
563856
563970
  "packages/orchestrator/dist/reflectionBuffer.js"() {
563857
563971
  "use strict";
563972
+ init_artifactQuality();
563858
563973
  MAX_REFLECTIONS = 5;
563859
563974
  MAX_TOTAL = 50;
563860
563975
  TaskReflectionBuffer = class {
@@ -563905,6 +564020,18 @@ var init_reflectionBuffer = __esm({
563905
564020
  */
563906
564021
  addReflection(params) {
563907
564022
  const { taskGoal, sessionId, turnsSpent, failedApproaches, toolCallLog, lastError, failedPaths } = params;
564023
+ const goalCoreForQuality = this.extractUserGoalCore(taskGoal) || taskGoal;
564024
+ const quality = assessTaskArtifactQuality({
564025
+ goal: goalCoreForQuality,
564026
+ summary: lastError,
564027
+ toolsUsed: toolCallLog.map((entry) => entry.tool),
564028
+ filesTouched: failedPaths || [],
564029
+ turns: turnsSpent
564030
+ });
564031
+ if (!quality.eligible) {
564032
+ const reason = quality.reason || "low-quality artifact";
564033
+ throw new Error("Reflection rejected: " + reason);
564034
+ }
563908
564035
  const taskFingerprint = this.computeFingerprint(taskGoal);
563909
564036
  const errorType = this.classifyError(toolCallLog, failedApproaches, lastError, turnsSpent);
563910
564037
  const failedTools = [...new Set(toolCallLog.filter((t2) => !t2.success).map((t2) => t2.tool))].slice(0, 5);
@@ -563953,23 +564080,26 @@ var init_reflectionBuffer = __esm({
563953
564080
  const fingerprint = this.computeFingerprint(taskGoal);
563954
564081
  const goalLower = goalCore.toLowerCase();
563955
564082
  const goalWords = new Set(goalLower.split(/\s+/).filter((w) => w.length > 3));
563956
- const scored = this.state.reflections.map((r2) => {
563957
- let score = 0;
564083
+ const scored = this.state.reflections.filter((r2) => !isInternalArtifactPrompt(r2.taskGoal) && !isInternalArtifactPrompt(r2.whatFailed) && !isInternalArtifactPrompt(r2.whatToDoDifferently)).map((r2) => {
564084
+ let baseScore = 0;
563958
564085
  if (r2.taskFingerprint === fingerprint)
563959
- score += 5;
564086
+ baseScore += 5;
563960
564087
  const rWords = new Set(r2.taskGoal.toLowerCase().split(/\s+/).filter((w) => w.length > 3));
563961
564088
  let overlap = 0;
563962
564089
  for (const w of goalWords)
563963
564090
  if (rWords.has(w))
563964
564091
  overlap++;
563965
- score += overlap;
564092
+ baseScore += overlap;
564093
+ if (baseScore <= 0)
564094
+ return { reflection: r2, score: 0, relevant: false };
564095
+ let score = baseScore;
563966
564096
  const hoursAgo = (Date.now() - r2.timestamp) / 36e5;
563967
564097
  score += Math.max(0, 2 - hoursAgo * 0.1);
563968
564098
  score += r2.confidence * 2;
563969
- return { reflection: r2, score };
564099
+ return { reflection: r2, score, relevant: true };
563970
564100
  });
563971
564101
  scored.sort((a2, b) => b.score - a2.score);
563972
- const results = scored.slice(0, maxResults).filter((s2) => s2.score > 1).map((s2) => s2.reflection);
564102
+ const results = scored.filter((s2) => s2.relevant && s2.score > 1).slice(0, maxResults).map((s2) => s2.reflection);
563973
564103
  this.state.totalConsumed += results.length;
563974
564104
  this.persist();
563975
564105
  return results;
@@ -564182,23 +564312,50 @@ function buildTaskHandoff(params) {
564182
564312
  const argHint = tc.argsKey ? ` ${tc.argsKey.slice(0, 80)}` : "";
564183
564313
  return `${tc.name}${argHint}`;
564184
564314
  });
564315
+ const artifactMode = params.artifactMode ?? "user-task";
564316
+ const filesTouched = [...new Set(params.filesModified)].slice(0, MAX_FILES);
564317
+ const toolsUsed = [...new Set(params.toolsUsed)].slice(0, MAX_TOOLS);
564318
+ const quality = assessTaskArtifactQuality({
564319
+ artifactMode,
564320
+ goal: params.goal,
564321
+ summary: params.summary,
564322
+ filesTouched,
564323
+ toolsUsed,
564324
+ turns: params.turns
564325
+ });
564185
564326
  return {
564186
564327
  v: 2,
564187
564328
  sessionId: params.sessionId,
564188
564329
  priorGoal: params.goal.slice(0, 500),
564189
564330
  priorOutcome: params.outcome,
564190
564331
  priorSummary: (params.summary || "").slice(0, MAX_SUMMARY_CHARS),
564191
- filesTouched: [...new Set(params.filesModified)].slice(0, MAX_FILES),
564192
- toolsUsed: [...new Set(params.toolsUsed)].slice(0, MAX_TOOLS),
564332
+ filesTouched,
564333
+ toolsUsed,
564193
564334
  lastActions,
564194
564335
  turns: params.turns,
564195
564336
  endedAt: Date.now(),
564337
+ artifactMode,
564338
+ quality,
564196
564339
  ...params.transcriptPath ? { transcriptPath: params.transcriptPath } : {}
564197
564340
  };
564198
564341
  }
564342
+ function shouldPersistTaskHandoff(handoff) {
564343
+ if (handoff.quality && handoff.quality.eligible === false)
564344
+ return false;
564345
+ return assessTaskArtifactQuality({
564346
+ artifactMode: handoff.artifactMode,
564347
+ goal: handoff.priorGoal,
564348
+ summary: handoff.priorSummary,
564349
+ toolsUsed: handoff.toolsUsed,
564350
+ filesTouched: handoff.filesTouched,
564351
+ turns: handoff.turns
564352
+ }).eligible;
564353
+ }
564199
564354
  function writeTaskHandoff(omniusDir, handoff) {
564200
564355
  if (!handoffEnabled())
564201
564356
  return;
564357
+ if (!shouldPersistTaskHandoff(handoff))
564358
+ return;
564202
564359
  try {
564203
564360
  const file = handoffPath(omniusDir);
564204
564361
  fs4.mkdirSync(path5.dirname(file), { recursive: true });
@@ -564219,6 +564376,8 @@ function readTaskHandoff(omniusDir, opts) {
564219
564376
  return null;
564220
564377
  }
564221
564378
  const handoff = parsed;
564379
+ if (!shouldPersistTaskHandoff(handoff))
564380
+ return null;
564222
564381
  const sameSession = handoff.sessionId === opts.currentSessionId;
564223
564382
  if (!sameSession) {
564224
564383
  const age = Date.now() - handoff.endedAt;
@@ -564287,6 +564446,7 @@ var DEFAULT_TTL_MS2, MAX_SUMMARY_CHARS, MAX_FILES, MAX_TOOLS, MAX_LAST_ACTIONS;
564287
564446
  var init_taskHandoff = __esm({
564288
564447
  "packages/orchestrator/dist/taskHandoff.js"() {
564289
564448
  "use strict";
564449
+ init_artifactQuality();
564290
564450
  DEFAULT_TTL_MS2 = 24 * 60 * 60 * 1e3;
564291
564451
  MAX_SUMMARY_CHARS = 8e3;
564292
564452
  MAX_FILES = 30;
@@ -564317,6 +564477,8 @@ function logPath2(omniusDir, sessionLogId) {
564317
564477
  function appendBoundaryToLog(omniusDir, handoff) {
564318
564478
  if (!logEnabled())
564319
564479
  return;
564480
+ if (!shouldPersistTaskHandoff(handoff))
564481
+ return;
564320
564482
  const id = tuiSessionLogId();
564321
564483
  if (!id)
564322
564484
  return;
@@ -564345,7 +564507,9 @@ function loadBoundaryRecords(omniusDir) {
564345
564507
  try {
564346
564508
  const parsed = JSON.parse(lines[i2]);
564347
564509
  if (parsed && parsed.v === 1 && parsed.handoff && typeof parsed.recordedAt === "number") {
564348
- records.push(parsed);
564510
+ const record = parsed;
564511
+ if (shouldPersistTaskHandoff(record.handoff))
564512
+ records.push(record);
564349
564513
  }
564350
564514
  } catch {
564351
564515
  }
@@ -565896,7 +566060,7 @@ function heuristicSummarize(inputs) {
565896
566060
  }
565897
566061
  }
565898
566062
  return {
565899
- functionalSummary: `Completed: ${inputs.todoContent.slice(0, 120)} (heuristic summary — use memex_retrieve(expand=true) for full context)`,
566063
+ functionalSummary: `Work recorded: ${inputs.todoContent.slice(0, 120)} (heuristic summary — use memex_retrieve(expand=true) for full context)`,
565900
566064
  keyFiles: [...files].slice(0, 30),
565901
566065
  criticalSymbols: {
565902
566066
  defined: [...new Set(symbolsDefined)].slice(0, 50),
@@ -565914,6 +566078,31 @@ function heuristicSummarize(inputs) {
565914
566078
  ].join("\n")
565915
566079
  };
565916
566080
  }
566081
+ function hasExplicitVerification(text2) {
566082
+ const raw = String(text2 || "").trim();
566083
+ if (!raw)
566084
+ return false;
566085
+ if (/^\(?no verification detected\)?$/i.test(raw))
566086
+ return false;
566087
+ if (/\b(no verification|not verified|not run|missing verification|none detected)\b/i.test(raw))
566088
+ return false;
566089
+ return /\b(pass|passed|success|succeeded|verified|tests?|build|compile|tsc|vitest|jest|pytest|go test|cargo test)\b/i.test(raw);
566090
+ }
566091
+ function deriveChunkStatus(verdict, toolCalls) {
566092
+ if ((verdict.unresolved || []).length > 0)
566093
+ return "blocked";
566094
+ if (toolCalls.some((tc) => !tc.success))
566095
+ return "partial";
566096
+ if (!hasExplicitVerification(verdict.verification || ""))
566097
+ return "unverified";
566098
+ return "completed";
566099
+ }
566100
+ function statusAwareFunctionalSummary(summary, status, fallback) {
566101
+ const raw = (summary || fallback).trim();
566102
+ if (status === "completed")
566103
+ return raw;
566104
+ return raw.replace(/^completed\s*:?/i, "Work recorded:");
566105
+ }
565917
566106
  async function runTodoChunker(opts) {
565918
566107
  const startMs = Date.now();
565919
566108
  const memexId = `todo-ctx-${sanitizeId(opts.inputs.todoId).slice(0, 20)}`;
@@ -565932,11 +566121,12 @@ async function runTodoChunker(opts) {
565932
566121
  usedFallback = true;
565933
566122
  }
565934
566123
  const estimatedTokens = Math.round(opts.inputs.transcript.length / 4);
566124
+ const status = deriveChunkStatus(verdict, opts.inputs.toolCalls);
565935
566125
  const chunk = {
565936
566126
  todoId: opts.inputs.todoId,
565937
566127
  todoContent: opts.inputs.todoContent,
565938
- status: "completed",
565939
- functionalSummary: verdict.functionalSummary || `Completed: ${opts.inputs.todoContent.slice(0, 120)}`,
566128
+ status,
566129
+ functionalSummary: statusAwareFunctionalSummary(verdict.functionalSummary, status, `Work recorded: ${opts.inputs.todoContent.slice(0, 120)}`),
565940
566130
  detailSummary: verdict.detailSummary || "",
565941
566131
  keyFiles: verdict.keyFiles || [],
565942
566132
  criticalSymbols: verdict.criticalSymbols || { defined: [], modified: [] },
@@ -570272,6 +570462,7 @@ var init_agenticRunner = __esm({
570272
570462
  */
570273
570463
  _completionCaveat = null;
570274
570464
  _completionLedger = null;
570465
+ _staleEditFamilies = /* @__PURE__ */ new Map();
570275
570466
  // ── WO-AM-01/04/10: Associative memory stores ──
570276
570467
  // Episode store: every tool call → persistent episode with importance + decay
570277
570468
  // Temporal KG: entities + relations with temporal validity (valid_from/valid_until)
@@ -570620,6 +570811,7 @@ ${parts.join("\n")}
570620
570811
  memoryPrefix: options2?.memoryPrefix ?? "",
570621
570812
  memoryPrefixHash: options2?.memoryPrefixHash ?? "",
570622
570813
  stateDir: options2?.stateDir ?? "",
570814
+ artifactMode: options2?.artifactMode ?? "user-task",
570623
570815
  disablePersistentMemory: options2?.disablePersistentMemory ?? false,
570624
570816
  disableCodebaseMap: options2?.disableCodebaseMap ?? false,
570625
570817
  sessionId: options2?.sessionId ?? "",
@@ -570671,7 +570863,12 @@ ${parts.join("\n")}
570671
570863
  const configured = (this.options.stateDir || "").trim();
570672
570864
  return configured ? _pathResolve(configured) : _pathJoin(process.cwd(), ".omnius");
570673
570865
  }
570866
+ writesUserTaskArtifacts() {
570867
+ return this.options.artifactMode === "user-task" && !this.options.subAgent;
570868
+ }
570674
570869
  _persistCompletionContract(contract) {
570870
+ if (!this.writesUserTaskArtifacts())
570871
+ return;
570675
570872
  try {
570676
570873
  const dir = _pathJoin(this.omniusStateDir(), "completion-contracts");
570677
570874
  _fsMkdirSync(dir, { recursive: true });
@@ -570684,6 +570881,8 @@ ${parts.join("\n")}
570684
570881
  }
570685
570882
  }
570686
570883
  _saveCompletionLedgerSafe() {
570884
+ if (!this.writesUserTaskArtifacts())
570885
+ return;
570687
570886
  if (!this._completionLedger)
570688
570887
  return;
570689
570888
  try {
@@ -575456,6 +575655,7 @@ Respond with your assessment, then take action.`;
575456
575655
  this._completionIncompleteVerification = null;
575457
575656
  this._completionCaveat = null;
575458
575657
  this._completionLedger = null;
575658
+ this._staleEditFamilies.clear();
575459
575659
  this._lastWorldStateTurn = -1;
575460
575660
  this._fileWritesSinceLastWorldState = 0;
575461
575661
  this._resetVisualEvidenceState();
@@ -575598,11 +575798,16 @@ Respond with your assessment, then take action.`;
575598
575798
  verbose: false
575599
575799
  });
575600
575800
  this._hookManager.runSessionHook("session_start", this._sessionId);
575601
- this._initializeCompletionContract(task, context2, actualUserGoal);
575602
- this._completionLedger = createCompletionLedger({
575603
- runId: this._sessionId,
575604
- goal: userGoal
575605
- });
575801
+ if (this.writesUserTaskArtifacts()) {
575802
+ this._initializeCompletionContract(task, context2, actualUserGoal);
575803
+ this._completionLedger = createCompletionLedger({
575804
+ runId: this._sessionId,
575805
+ goal: userGoal
575806
+ });
575807
+ } else {
575808
+ this._completionContract = null;
575809
+ this._completionLedger = null;
575810
+ }
575606
575811
  this._sessionStartMs = Date.now();
575607
575812
  if (process.env["OMNIUS_DISABLE_PREFLIGHT"] !== "1") {
575608
575813
  try {
@@ -575878,6 +576083,8 @@ TASK: ${scrubbedTask}` : scrubbedTask;
575878
576083
  try {
575879
576084
  if (this.options.subAgent)
575880
576085
  throw "skip-handoff-subagent";
576086
+ if (!this.writesUserTaskArtifacts())
576087
+ throw "skip-handoff-artifact-mode";
575881
576088
  if (this.options.skipCrossTaskHandoff)
575882
576089
  throw "skip-handoff-caller-optout";
575883
576090
  if (/<task-handoff>|<session-recap>/.test(task))
@@ -575914,6 +576121,8 @@ TASK: ${scrubbedTask}` : scrubbedTask;
575914
576121
  } catch {
575915
576122
  }
575916
576123
  try {
576124
+ if (!this.writesUserTaskArtifacts())
576125
+ throw "skip-reflection-artifact-mode";
575917
576126
  if (!this._reflectionBuffer) {
575918
576127
  const omniusDir = this.options.stateDir ? _pathJoin(this.omniusStateDir(), "memory") : this._workingDirectory ? _pathJoin(this._workingDirectory, ".omnius", "memory") : null;
575919
576128
  if (omniusDir) {
@@ -578512,6 +578721,43 @@ Use the saved fact to continue the promised synthesis or next concrete step, or
578512
578721
  systemGuidance: repeatNoopMsg
578513
578722
  };
578514
578723
  }
578724
+ const staleEditBlock = this.staleEditPreflightBlock(tc.name, tc.arguments ?? {});
578725
+ if (staleEditBlock) {
578726
+ this.emit({
578727
+ type: "tool_call",
578728
+ toolName: tc.name,
578729
+ toolArgs: tc.arguments,
578730
+ turn,
578731
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
578732
+ });
578733
+ this.emit({
578734
+ type: "tool_result",
578735
+ toolName: tc.name,
578736
+ success: false,
578737
+ content: staleEditBlock.slice(0, 120),
578738
+ turn,
578739
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
578740
+ });
578741
+ this._tagSyntheticFailure({
578742
+ mode: "step_repetition",
578743
+ rationale: "stale edit family retried without fresh read or mutation"
578744
+ });
578745
+ if (this._completionLedger) {
578746
+ this._completionLedger = recordToolEvidence(this._completionLedger, {
578747
+ name: tc.name,
578748
+ success: false,
578749
+ outputPreview: staleEditBlock.slice(0, 500),
578750
+ argsKey: tc.arguments ? JSON.stringify(tc.arguments).slice(0, 300) : ""
578751
+ });
578752
+ this._saveCompletionLedgerSafe();
578753
+ }
578754
+ return {
578755
+ tc,
578756
+ output: staleEditBlock,
578757
+ success: false,
578758
+ systemGuidance: staleEditBlock
578759
+ };
578760
+ }
578515
578761
  const baseIsReadLike = ![
578516
578762
  "file_write",
578517
578763
  "file_edit",
@@ -579992,6 +580238,7 @@ Evidence: ${evidencePreview}`.slice(0, 500);
579992
580238
  }
579993
580239
  const filePath = typeof tc.arguments?.path === "string" ? tc.arguments.path : "";
579994
580240
  recordToolExecution(this._appState, tc.name, performance.now() - toolStart, result.success, filePath || void 0);
580241
+ this.noteStaleEditGuardOutcome(tc.name, tc.arguments ?? {}, result, turn);
579995
580242
  if (tc.name === "todo_write") {
579996
580243
  this._lastTodoWriteTurn = turn;
579997
580244
  }
@@ -580546,7 +580793,10 @@ ${sr.result.output}`;
580546
580793
  loopInterventionCount++;
580547
580794
  const loopTier2 = this.options.modelTier ?? "large";
580548
580795
  const maxInterventions = loopTier2 === "small" ? 3 : loopTier2 === "medium" ? 5 : 8;
580796
+ let loopCircuitBreakerFired = false;
580797
+ const loopInterventionOrdinal = loopInterventionCount;
580549
580798
  if (loopInterventionCount >= maxInterventions) {
580799
+ loopCircuitBreakerFired = true;
580550
580800
  this.emit({
580551
580801
  type: "status",
580552
580802
  content: `Loop circuit breaker: ${loopInterventionCount} interventions — requesting user guidance`,
@@ -580557,15 +580807,16 @@ ${sr.result.output}`;
580557
580807
  role: "system",
580558
580808
  content: `LOOP CIRCUIT BREAKER: ${loopInterventionCount} interventions attempted but repetition continues.
580559
580809
 
580560
- MANDATORY: You MUST call ask_user to request guidance from the user. Present your options:
580810
+ MANDATORY: Change state before taking another action. Choose one:
580561
580811
  1. Try a completely different approach
580562
- 2. Provide more context or clarification
580563
- 3. Accept partial results and pivot to a related task
580564
- 4. Abort this specific subtask and move on
580812
+ 2. Re-read the exact current target once if the loop is caused by a stale edit
580813
+ 3. Run verification if files changed since the last successful check
580814
+ 4. Call ask_user if user input is the real blocker
580815
+ 5. Report blocked/incomplete with the concrete blocker if no safe progress path remains
580565
580816
 
580566
580817
  Your partial progress: ${partialResults}
580567
580818
 
580568
- Call ask_user(question="I've hit a repetitive loop. How would you like me to proceed?", options=[...]) NOW.`
580819
+ Do not call task_complete solely because this circuit breaker fired.`
580569
580820
  });
580570
580821
  loopInterventionCount = 0;
580571
580822
  }
@@ -580583,19 +580834,19 @@ Call ask_user(question="I've hit a repetitive loop. How would you like me to pro
580583
580834
  }
580584
580835
  const findingsSummary = findings.length > 0 ? `
580585
580836
 
580586
- Here is what you ALREADY found (use this for your summary):
580587
- ${findings.slice(0, 8).map((f2, i2) => `${i2 + 1}. ${f2}`).join("\n")}` : "\n\nYou found no actionable results. Report that the information could not be found.";
580837
+ Here is what you ALREADY found. Use this to choose the next non-repetitive action:
580838
+ ${findings.slice(0, 8).map((f2, i2) => `${i2 + 1}. ${f2}`).join("\n")}` : "\n\nYou found no actionable results. Ask for guidance or report the specific blocker; do not invent completion.";
580588
580839
  messages2.push({
580589
580840
  role: "system",
580590
- content: `LOOP DETECTED (intervention ${loopInterventionCount}/${maxInterventions}). The last ${repetitionWindow} tool calls are ${Math.round(currentRepScore * 100)}% repetitive: ${topRepeated}.
580841
+ content: `LOOP DETECTED (intervention ${loopInterventionOrdinal}/${maxInterventions}). The last ${repetitionWindow} tool calls are ${Math.round(currentRepScore * 100)}% repetitive: ${topRepeated}.
580591
580842
 
580592
- MANDATORY: You MUST call task_complete on your next response. Do NOT call ${[...freqMap.keys()].map((k) => k.split("(")[0]).filter((v, i2, a2) => a2.indexOf(v) === i2).join(", ")} again. These tools have returned the same results multiple times.` + findingsSummary + `
580843
+ RECOVERY REQUIRED: Do not call task_complete just because repetition was detected. Do NOT call ${[...freqMap.keys()].map((k) => k.split("(")[0]).filter((v, i2, a2) => a2.indexOf(v) === i2).join(", ")} again with the same arguments. These tools have returned the same results multiple times. Choose a different concrete action: read the exact current target once if an edit failed, run verification if files changed, use a different tool or target, or call ask_user when user input is the real blocker.` + findingsSummary + `
580593
580844
 
580594
- Call task_complete(summary="...") NOW with whatever you have.`
580845
+ Only call task_complete when the task is actually complete and the evidence is fresh. If work is partial, report the blocker explicitly instead of completing.`
580595
580846
  });
580596
580847
  this.emit({
580597
580848
  type: "status",
580598
- content: `Loop intervention ${loopInterventionCount}/${maxInterventions}: ${Math.round(currentRepScore * 100)}% repetitive (${topRepeated})`,
580849
+ content: `Loop intervention ${loopInterventionOrdinal}/${maxInterventions}: ${Math.round(currentRepScore * 100)}% repetitive (${topRepeated})${loopCircuitBreakerFired ? " (circuit breaker advisory)" : ""}`,
580599
580850
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
580600
580851
  });
580601
580852
  try {
@@ -581497,7 +581748,19 @@ Full content available via: repl_exec(code="data = retrieve('${handleId}')") or
581497
581748
 
581498
581749
  ${this._completionCaveat}` : this._completionCaveat;
581499
581750
  }
581500
- const runStatus = completed ? "completed" : this._completionLedger?.status === "blocked" || this._completionLedger?.status === "request_changes" ? "incomplete_verification" : this._completionIncompleteVerification ? "incomplete_verification" : "incomplete";
581751
+ if (this._completionLedger) {
581752
+ this._completionLedger = finalizeCompletionLedgerTruth(this._completionLedger);
581753
+ this._saveCompletionLedgerSafe();
581754
+ if (completed && this._completionLedger.status === "incomplete_verification") {
581755
+ completed = false;
581756
+ const unresolvedSummary = this._completionLedger.unresolved.slice(-3).map((item) => item.text).join("; ");
581757
+ const caveat = unresolvedSummary ? `Incomplete verification: ${unresolvedSummary}` : "Incomplete verification: unresolved evidence remains in the completion ledger.";
581758
+ summary = summary ? `${summary}
581759
+
581760
+ ${caveat}` : caveat;
581761
+ }
581762
+ }
581763
+ const runStatus = completed ? "completed" : this._completionLedger?.status === "blocked" || this._completionLedger?.status === "request_changes" || this._completionLedger?.status === "incomplete_verification" ? "incomplete_verification" : this._completionIncompleteVerification ? "incomplete_verification" : "incomplete";
581501
581764
  this._emitMASTSummary("run-end");
581502
581765
  this.emit({
581503
581766
  type: "complete",
@@ -581545,6 +581808,8 @@ ${this._completionCaveat}` : this._completionCaveat;
581545
581808
  }
581546
581809
  }
581547
581810
  try {
581811
+ if (!this.writesUserTaskArtifacts())
581812
+ throw "skip-user-task-consolidation";
581548
581813
  const extractPaths = (entries, toolNames) => {
581549
581814
  return [
581550
581815
  ...new Set(entries.filter((tc) => toolNames.includes(tc.name)).map((tc) => {
@@ -581655,8 +581920,11 @@ ${this._completionCaveat}` : this._completionCaveat;
581655
581920
  toolsUsed: consolidation.toolsUsed,
581656
581921
  toolCallLog,
581657
581922
  turns: consolidation.turns,
581658
- transcriptPath
581923
+ transcriptPath,
581924
+ artifactMode: this.options.artifactMode
581659
581925
  });
581926
+ if (!shouldPersistTaskHandoff(handoff))
581927
+ throw "skip-low-quality-handoff";
581660
581928
  writeTaskHandoff(omniusDir, handoff);
581661
581929
  appendBoundaryToLog(omniusDir, handoff);
581662
581930
  trimLog(omniusDir);
@@ -581669,7 +581937,7 @@ ${this._completionCaveat}` : this._completionCaveat;
581669
581937
  });
581670
581938
  } catch {
581671
581939
  }
581672
- if (this._reflectionBuffer && !completed) {
581940
+ if (this._reflectionBuffer && !completed && this.writesUserTaskArtifacts()) {
581673
581941
  try {
581674
581942
  const reflection = this._reflectionBuffer.addReflection({
581675
581943
  taskGoal: persistentTaskGoal,
@@ -581692,7 +581960,7 @@ ${this._completionCaveat}` : this._completionCaveat;
581692
581960
  } catch {
581693
581961
  }
581694
581962
  }
581695
- if (this._episodeStore) {
581963
+ if (this._episodeStore && this.writesUserTaskArtifacts()) {
581696
581964
  try {
581697
581965
  const taskSummaryContent = `Task "${persistentTaskGoal.slice(0, 200)}" ${completed ? "completed" : "ended"}: ${cleanForStorage(summary).slice(0, 300)}`;
581698
581966
  if (this._crlMemoryStore) {
@@ -582305,6 +582573,150 @@ ${marker}` : marker);
582305
582573
  // -------------------------------------------------------------------------
582306
582574
  // Output folding — keep head + tail, omit middle (preserves errors at end)
582307
582575
  // -------------------------------------------------------------------------
582576
+ isEditToolName(name10) {
582577
+ return name10 === "file_edit" || name10 === "file_patch" || name10 === "batch_edit";
582578
+ }
582579
+ extractPrimaryToolPath(args) {
582580
+ if (!args)
582581
+ return "";
582582
+ const direct = args["path"] ?? args["file"] ?? args["filePath"] ?? args["file_path"];
582583
+ if (typeof direct === "string" && direct.trim())
582584
+ return direct.trim();
582585
+ const edits = args["edits"];
582586
+ if (Array.isArray(edits)) {
582587
+ for (const edit of edits) {
582588
+ if (!edit || typeof edit !== "object")
582589
+ continue;
582590
+ const rec = edit;
582591
+ const editPath = rec["path"] ?? rec["file"] ?? rec["filePath"] ?? rec["file_path"];
582592
+ if (typeof editPath === "string" && editPath.trim())
582593
+ return editPath.trim();
582594
+ }
582595
+ }
582596
+ return "";
582597
+ }
582598
+ staleEditTarget(toolName, args) {
582599
+ if (!this.isEditToolName(toolName) || !args)
582600
+ return null;
582601
+ const path12 = this.extractPrimaryToolPath(args);
582602
+ const parts = [];
582603
+ const directKeys = [
582604
+ "old_string",
582605
+ "oldString",
582606
+ "oldText",
582607
+ "search",
582608
+ "expected_old_string",
582609
+ "expectedHash",
582610
+ "expected_hash",
582611
+ "start_line"
582612
+ ];
582613
+ for (const key of directKeys) {
582614
+ const value2 = args[key];
582615
+ if (typeof value2 === "string" || typeof value2 === "number") {
582616
+ parts.push(key + "=" + String(value2));
582617
+ }
582618
+ }
582619
+ const edits = args["edits"];
582620
+ if (Array.isArray(edits)) {
582621
+ for (const edit of edits.slice(0, 6)) {
582622
+ if (!edit || typeof edit !== "object")
582623
+ continue;
582624
+ const rec = edit;
582625
+ const oldValue = rec["old_string"] ?? rec["oldString"] ?? rec["oldText"] ?? rec["search"] ?? rec["expected_old_string"];
582626
+ const editPath = rec["path"] ?? rec["file"] ?? rec["filePath"] ?? rec["file_path"];
582627
+ if (typeof editPath === "string" || typeof oldValue === "string") {
582628
+ parts.push(String(editPath ?? path12) + "=" + String(oldValue ?? ""));
582629
+ }
582630
+ }
582631
+ }
582632
+ if (!path12 && parts.length === 0)
582633
+ return null;
582634
+ const normalized = parts.join("\n").replace(/\s+/g, " ").trim() || JSON.stringify(args).slice(0, 1e3);
582635
+ return {
582636
+ path: path12 || "(unknown)",
582637
+ targetHash: this.quickHash(normalized),
582638
+ preview: normalized.slice(0, 160)
582639
+ };
582640
+ }
582641
+ classifyStaleEditFailure(toolName, result) {
582642
+ if (!this.isEditToolName(toolName) || result.success)
582643
+ return null;
582644
+ const text2 = String((result.error ?? "") + "\n" + (result.output ?? "")).toLowerCase();
582645
+ if (/ambiguous|multiple occurrences|matches more than once/.test(text2))
582646
+ return "ambiguous_old_string";
582647
+ if (/expected[_ -]?hash|hash mismatch|stale hash|beforehash|afterhash/.test(text2))
582648
+ return "stale_expected_hash";
582649
+ if (/expected.*content|content.*did not match|context mismatch|patch failed|hunk failed/.test(text2))
582650
+ return "stale_expected_content";
582651
+ if (/atomic.*abort|batch.*abort|skipped/.test(text2) && toolName === "batch_edit")
582652
+ return "atomic_batch_abort";
582653
+ if (/old[_ -]?string|old text|old content|not found|no occurrences|0 occurrences|could not find/.test(text2))
582654
+ return "stale_old_string";
582655
+ return null;
582656
+ }
582657
+ staleEditFamilyKey(toolName, path12, errorKind, targetHash) {
582658
+ return toolName + ":" + path12 + ":" + errorKind + ":" + targetHash;
582659
+ }
582660
+ staleEditPreflightBlock(toolName, args) {
582661
+ const target = this.staleEditTarget(toolName, args);
582662
+ if (!target)
582663
+ return null;
582664
+ for (const entry of this._staleEditFamilies.values()) {
582665
+ if (entry.tool !== toolName || entry.path !== target.path || entry.targetHash !== target.targetHash)
582666
+ continue;
582667
+ const hasFreshRead = entry.lastReadTurn > entry.lastFailureTurn;
582668
+ const hasFreshMutation = entry.lastMutationTurn > entry.lastFailureTurn;
582669
+ if (entry.count >= 2 && !hasFreshRead && !hasFreshMutation) {
582670
+ return [
582671
+ "[STALE EDIT LOOP BLOCKED] " + toolName + " has already failed " + entry.count + " times for " + entry.path + " (" + entry.errorKind + ").",
582672
+ "Do not retry the same stale edit target again. First file_read the current file content once, then either:",
582673
+ "1. confirm the desired change is already present and run verification,",
582674
+ "2. build a new edit from the exact current text, or",
582675
+ "3. choose a different target if this edit is no longer relevant.",
582676
+ "Previous stale target preview: " + entry.preview
582677
+ ].join("\n");
582678
+ }
582679
+ }
582680
+ return null;
582681
+ }
582682
+ noteStaleEditGuardOutcome(toolName, args, result, turn) {
582683
+ const path12 = this.extractPrimaryToolPath(args);
582684
+ if (toolName === "file_read" && path12 && result.success) {
582685
+ for (const entry of this._staleEditFamilies.values()) {
582686
+ if (entry.path === path12)
582687
+ entry.lastReadTurn = turn;
582688
+ }
582689
+ return;
582690
+ }
582691
+ if (!this.isEditToolName(toolName))
582692
+ return;
582693
+ const target = this.staleEditTarget(toolName, args);
582694
+ if (!target)
582695
+ return;
582696
+ if (result.success && result.mutated !== false) {
582697
+ for (const [key2, entry] of this._staleEditFamilies) {
582698
+ if (entry.path === target.path)
582699
+ this._staleEditFamilies.delete(key2);
582700
+ }
582701
+ return;
582702
+ }
582703
+ const errorKind = this.classifyStaleEditFailure(toolName, result);
582704
+ if (!errorKind)
582705
+ return;
582706
+ const key = this.staleEditFamilyKey(toolName, target.path, errorKind, target.targetHash);
582707
+ const existing = this._staleEditFamilies.get(key);
582708
+ this._staleEditFamilies.set(key, {
582709
+ count: (existing?.count ?? 0) + 1,
582710
+ path: target.path,
582711
+ tool: toolName,
582712
+ errorKind,
582713
+ targetHash: target.targetHash,
582714
+ lastFailureTurn: turn,
582715
+ lastReadTurn: existing?.lastReadTurn ?? -1,
582716
+ lastMutationTurn: existing?.lastMutationTurn ?? -1,
582717
+ preview: target.preview
582718
+ });
582719
+ }
582308
582720
  /**
582309
582721
  * Quick non-cryptographic hash for Memex experience IDs.
582310
582722
  * Produces a short hex string (8 chars) from input.
@@ -654414,6 +654826,7 @@ Call task_complete with the JSON array when done.`,
654414
654826
  const runner = new AgenticRunner(backend, {
654415
654827
  maxTurns: 5,
654416
654828
  // Evaluators are very focused — 5 turns max
654829
+ artifactMode: "internal",
654417
654830
  maxTokens: 4096,
654418
654831
  temperature: 0,
654419
654832
  // Deterministic scoring
@@ -656923,6 +657336,7 @@ var init_dmn_engine = __esm({
656923
657336
  const runner = new AgenticRunner(backend, {
656924
657337
  maxTurns: 15,
656925
657338
  // DMN is lightweight — don't burn too many turns
657339
+ artifactMode: "internal",
656926
657340
  maxTokens: 8192,
656927
657341
  temperature: 0.4,
656928
657342
  // Slightly creative for exploratory reasoning
@@ -657220,6 +657634,7 @@ If decision is GO, selectedTask MUST be a fully-populated object (NEVER null)
657220
657634
  const runner = new AgenticRunner(backend, {
657221
657635
  maxTurns: 8,
657222
657636
  // Brain regions are fast, focused
657637
+ artifactMode: "internal",
657223
657638
  maxTokens: 4096,
657224
657639
  temperature: role === "amygdala" ? 0.2 : role === "pfc_planner" ? 0.5 : 0.3,
657225
657640
  requestTimeoutMs: this.config.timeoutMs,
@@ -657806,6 +658221,7 @@ var init_emotion_engine = __esm({
657806
658221
  );
657807
658222
  const runner = new AgenticRunner(backend, {
657808
658223
  maxTurns: 1,
658224
+ artifactMode: "internal",
657809
658225
  maxTokens: 64,
657810
658226
  temperature: 0.9,
657811
658227
  // High temperature for creative expression
@@ -657889,6 +658305,7 @@ var init_emotion_engine = __esm({
657889
658305
  );
657890
658306
  const runner = new AgenticRunner(backend, {
657891
658307
  maxTurns: 3,
658308
+ artifactMode: "internal",
657892
658309
  maxTokens: 512,
657893
658310
  temperature: 0.35,
657894
658311
  requestTimeoutMs: 2e4,
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "omnius",
3
- "version": "1.0.365",
3
+ "version": "1.0.366",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "omnius",
9
- "version": "1.0.365",
9
+ "version": "1.0.366",
10
10
  "bundleDependencies": [
11
11
  "image-to-ascii"
12
12
  ],
@@ -430,9 +430,9 @@
430
430
  }
431
431
  },
432
432
  "node_modules/@helia/utils/node_modules/cborg": {
433
- "version": "5.1.4",
434
- "resolved": "https://registry.npmjs.org/cborg/-/cborg-5.1.4.tgz",
435
- "integrity": "sha512-EDoD59RBV51H5ar6i29ut7AyOJi0BUIEhtbnJJac3qYcMG74Db6eVce/dIh+Wh6tVwBi7cRWDXmdms+fKPQvcQ==",
433
+ "version": "5.1.5",
434
+ "resolved": "https://registry.npmjs.org/cborg/-/cborg-5.1.5.tgz",
435
+ "integrity": "sha512-1qJ/E8jF1dmJlBm6V1z91iWTWfCK9SuCxPDLod+Ne7CMCASOQh346b+487oFt/zoBQW+XS5wNvMgV+7gs5sJJA==",
436
436
  "license": "Apache-2.0",
437
437
  "bin": {
438
438
  "cborg": "lib/bin.js"
@@ -461,9 +461,9 @@
461
461
  }
462
462
  },
463
463
  "node_modules/@ipld/dag-cbor/node_modules/cborg": {
464
- "version": "5.1.4",
465
- "resolved": "https://registry.npmjs.org/cborg/-/cborg-5.1.4.tgz",
466
- "integrity": "sha512-EDoD59RBV51H5ar6i29ut7AyOJi0BUIEhtbnJJac3qYcMG74Db6eVce/dIh+Wh6tVwBi7cRWDXmdms+fKPQvcQ==",
464
+ "version": "5.1.5",
465
+ "resolved": "https://registry.npmjs.org/cborg/-/cborg-5.1.5.tgz",
466
+ "integrity": "sha512-1qJ/E8jF1dmJlBm6V1z91iWTWfCK9SuCxPDLod+Ne7CMCASOQh346b+487oFt/zoBQW+XS5wNvMgV+7gs5sJJA==",
467
467
  "license": "Apache-2.0",
468
468
  "bin": {
469
469
  "cborg": "lib/bin.js"
@@ -480,9 +480,9 @@
480
480
  }
481
481
  },
482
482
  "node_modules/@ipld/dag-json/node_modules/cborg": {
483
- "version": "5.1.4",
484
- "resolved": "https://registry.npmjs.org/cborg/-/cborg-5.1.4.tgz",
485
- "integrity": "sha512-EDoD59RBV51H5ar6i29ut7AyOJi0BUIEhtbnJJac3qYcMG74Db6eVce/dIh+Wh6tVwBi7cRWDXmdms+fKPQvcQ==",
483
+ "version": "5.1.5",
484
+ "resolved": "https://registry.npmjs.org/cborg/-/cborg-5.1.5.tgz",
485
+ "integrity": "sha512-1qJ/E8jF1dmJlBm6V1z91iWTWfCK9SuCxPDLod+Ne7CMCASOQh346b+487oFt/zoBQW+XS5wNvMgV+7gs5sJJA==",
486
486
  "license": "Apache-2.0",
487
487
  "bin": {
488
488
  "cborg": "lib/bin.js"
@@ -4293,9 +4293,9 @@
4293
4293
  }
4294
4294
  },
4295
4295
  "node_modules/ipns/node_modules/cborg": {
4296
- "version": "5.1.4",
4297
- "resolved": "https://registry.npmjs.org/cborg/-/cborg-5.1.4.tgz",
4298
- "integrity": "sha512-EDoD59RBV51H5ar6i29ut7AyOJi0BUIEhtbnJJac3qYcMG74Db6eVce/dIh+Wh6tVwBi7cRWDXmdms+fKPQvcQ==",
4296
+ "version": "5.1.5",
4297
+ "resolved": "https://registry.npmjs.org/cborg/-/cborg-5.1.5.tgz",
4298
+ "integrity": "sha512-1qJ/E8jF1dmJlBm6V1z91iWTWfCK9SuCxPDLod+Ne7CMCASOQh346b+487oFt/zoBQW+XS5wNvMgV+7gs5sJJA==",
4299
4299
  "license": "Apache-2.0",
4300
4300
  "bin": {
4301
4301
  "cborg": "lib/bin.js"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "omnius",
3
- "version": "1.0.365",
3
+ "version": "1.0.366",
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",