omnius 1.0.460 → 1.0.461

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
@@ -566100,6 +566100,11 @@ var init_personality = __esm({
566100
566100
  // packages/orchestrator/dist/critic.js
566101
566101
  function buildCriticGuidanceMessage(call, hits, opts = {}) {
566102
566102
  const argPreview = JSON.stringify(call.args ?? {}).slice(0, 200);
566103
+ const actionReason = call.actionReason ? [
566104
+ call.actionReason.scope ? `scope=${call.actionReason.scope}` : "",
566105
+ call.actionReason.intent ? `intent=${call.actionReason.intent}` : "",
566106
+ call.actionReason.evidence ? `evidence=${call.actionReason.evidence}` : ""
566107
+ ].filter(Boolean).join("; ").slice(0, 500) : "";
566103
566108
  const cached = opts.cachedResult ? `
566104
566109
  Prior evidence preview:
566105
566110
  ${opts.cachedResult.slice(0, 700)}` : "";
@@ -566107,7 +566112,8 @@ ${opts.cachedResult.slice(0, 700)}` : "";
566107
566112
  return `[RUNTIME EVIDENCE CACHE — non-blocking]
566108
566113
  Observation: ${source}
566109
566114
  Call: ${call.tool}(${argPreview})
566110
- State: exact prior evidence exists for these arguments in the current state version.
566115
+ ` + (actionReason ? `Action reason: ${actionReason}
566116
+ ` : "") + `State: exact prior evidence exists for these arguments in the current state version.
566111
566117
  Next action contract: let this result inform the next step once, then pivot to a concrete action.
566112
566118
  Suggested next actions: edit/write the implicated file, run verification, read a different specific file, or complete with evidence. Prefer not to repeat this exact call again unless the filesystem, browser, or page state changed.${cached}`;
566113
566119
  }
@@ -573987,6 +573993,8 @@ ${obs.stateDigest.slice(0, 1800)}
573987
573993
  `This is a loop. Reason about WHY — for THIS specific call, not generically.`,
573988
573994
  ls2.alreadyHave ? `Evidence the agent ALREADY obtained from a prior identical call:
573989
573995
  ${ls2.alreadyHave.slice(0, 900)}` : `(No cached result available for the repeated call.)`,
573996
+ ls2.actionReason ? `Agent's stated action reason:
573997
+ scope=${ls2.actionReason.scope ?? ""}; intent=${ls2.actionReason.intent ?? ""}; evidence=${ls2.actionReason.evidence ?? ""}; expected=${ls2.actionReason.expected_result ?? ""}`.slice(0, 700) : "",
573990
573998
  "",
573991
573999
  stateDigest.trim(),
573992
574000
  "",
@@ -574388,6 +574396,7 @@ function recordDebugToolEvent(input) {
574388
574396
  },
574389
574397
  ...input.focusSupervisor ? { focusSupervisor: input.focusSupervisor } : {},
574390
574398
  ...input.focusDecision ? { focusDecision: input.focusDecision } : {},
574399
+ ...input.actionReason ? { actionReason: compactDebugValue(input.actionReason) } : {},
574391
574400
  ...input.repeatShortCircuit !== void 0 ? { repeatShortCircuit: input.repeatShortCircuit } : {},
574392
574401
  ...input.runtimeAuthored !== void 0 ? { runtimeAuthored: input.runtimeAuthored } : {},
574393
574402
  ...input.runtimeGuidance ? { runtimeGuidancePreview: trim(input.runtimeGuidance, 1200) } : {},
@@ -575057,6 +575066,30 @@ function trim(value2, max) {
575057
575066
  return `${value2.slice(0, max)}
575058
575067
  [truncated ${value2.length - max} chars]`;
575059
575068
  }
575069
+ function compactDebugValue(value2, depth = 0) {
575070
+ if (value2 == null)
575071
+ return value2;
575072
+ if (typeof value2 === "string") {
575073
+ return value2.length > 500 ? `${value2.slice(0, 497)}...` : value2;
575074
+ }
575075
+ if (typeof value2 === "number" || typeof value2 === "boolean")
575076
+ return value2;
575077
+ if (Array.isArray(value2)) {
575078
+ if (depth >= 2)
575079
+ return `[array:${value2.length}]`;
575080
+ return value2.slice(0, 8).map((entry) => compactDebugValue(entry, depth + 1));
575081
+ }
575082
+ if (typeof value2 === "object") {
575083
+ if (depth >= 2)
575084
+ return "[object]";
575085
+ const out = {};
575086
+ for (const [key, entry] of Object.entries(value2).slice(0, 12)) {
575087
+ out[key] = compactDebugValue(entry, depth + 1);
575088
+ }
575089
+ return out;
575090
+ }
575091
+ return String(value2);
575092
+ }
575060
575093
  function safeId2(value2) {
575061
575094
  return String(value2 || "unknown").replace(/[^a-zA-Z0-9_.:-]/g, "_").slice(0, 160);
575062
575095
  }
@@ -575098,6 +575131,9 @@ function violatesDirective(directive, input) {
575098
575131
  }
575099
575132
  if (input.toolName === "ask_user")
575100
575133
  return false;
575134
+ if (directive.requiredNextAction === "read_authoritative_target" && input.usesAuthoritativeTargetEvidence && isEditTool(input.toolName)) {
575135
+ return false;
575136
+ }
575101
575137
  const family = actionFamily(input.toolName, input.args);
575102
575138
  if (directive.requiredNextAction !== "update_todos") {
575103
575139
  if (directive.forbiddenActionFamilies.includes(family))
@@ -575185,6 +575221,17 @@ function compactCachedEvidence(text2) {
575185
575221
  "Use the cached evidence now, or request a distinct offset/limit/query if genuinely needed."
575186
575222
  ].filter(Boolean).join("\n");
575187
575223
  }
575224
+ function actionReasonSummary(actionReason) {
575225
+ if (!actionReason)
575226
+ return "";
575227
+ const parts = [
575228
+ actionReason.scope ? `scope=${actionReason.scope}` : "",
575229
+ actionReason.intent ? `intent=${actionReason.intent}` : "",
575230
+ actionReason.evidence ? `evidence=${actionReason.evidence}` : "",
575231
+ actionReason.expected_result ? `expected=${actionReason.expected_result}` : ""
575232
+ ].filter(Boolean);
575233
+ return parts.length > 0 ? `Action reason observed: ${parts.join("; ").slice(0, 700)}` : "";
575234
+ }
575188
575235
  function actionFamily(toolName, args) {
575189
575236
  if (isEditTool(toolName)) {
575190
575237
  const path12 = primaryPath(args);
@@ -575408,8 +575455,9 @@ var init_focusSupervisor = __esm({
575408
575455
  `${reason}.`,
575409
575456
  `Required next action: ${prior.requiredNextAction}.`,
575410
575457
  `Blocked action family: ${family}.`,
575458
+ actionReasonSummary(input.actionReason),
575411
575459
  "This block is not counted as a new ignored directive."
575412
- ].join("\n"), false);
575460
+ ].filter(Boolean).join("\n"), false);
575413
575461
  }
575414
575462
  return this.pass();
575415
575463
  }
@@ -575450,8 +575498,9 @@ var init_focusSupervisor = __esm({
575450
575498
  `[FOCUS SUPERVISOR BLOCK] The previous directive was ignored: ${prior.reason}`,
575451
575499
  `Required next action: ${directive.requiredNextAction}.`,
575452
575500
  `Blocked action family: ${family}.`,
575501
+ actionReasonSummary(input.actionReason),
575453
575502
  directive.requiredNextAction === "report_incomplete" ? "Stop trying tool variants. Report incomplete/blocked with the concrete evidence." : "Take the required next action before trying another variant."
575454
- ].join("\n"), false);
575503
+ ].filter(Boolean).join("\n"), false);
575455
575504
  }
575456
575505
  }
575457
575506
  if (input.stalePreflightMessage) {
@@ -575462,9 +575511,12 @@ var init_focusSupervisor = __esm({
575462
575511
  requiredNextAction: "read_authoritative_target",
575463
575512
  forbiddenActionFamilies: [family]
575464
575513
  });
575465
- return this.block(directive, `${input.stalePreflightMessage}
575466
-
575467
- [FOCUS SUPERVISOR] Required next action: file_read the authoritative current target once, then build a new edit from current evidence or report incomplete.`, false);
575514
+ return this.block(directive, [
575515
+ input.stalePreflightMessage,
575516
+ "",
575517
+ actionReasonSummary(input.actionReason),
575518
+ "[FOCUS SUPERVISOR] Required next action: file_read the authoritative current target once, then build a new edit from current evidence or report incomplete."
575519
+ ].filter(Boolean).join("\n"), false);
575468
575520
  }
575469
575521
  const duplicateHitCount = input.duplicateHitCount ?? 0;
575470
575522
  if (input.cachedResult && duplicateHitCount > 0) {
@@ -575484,9 +575536,10 @@ var init_focusSupervisor = __esm({
575484
575536
  input.cachedResultFailed ? "[FOCUS SUPERVISOR: CACHED FAILURE]" : "[FOCUS SUPERVISOR: CACHED EVIDENCE]",
575485
575537
  `This ${input.toolName} action family has already produced evidence and should not be re-executed unchanged.`,
575486
575538
  `Required next action: ${directive.requiredNextAction}.`,
575539
+ actionReasonSummary(input.actionReason),
575487
575540
  "",
575488
575541
  compactCachedEvidence(input.cachedResult)
575489
- ].join("\n"), !input.cachedResultFailed);
575542
+ ].filter(Boolean).join("\n"), !input.cachedResultFailed);
575490
575543
  }
575491
575544
  return this.inject(directive, `[FOCUS SUPERVISOR] ${directive.reason}. Required next action: ${directive.requiredNextAction}.`);
575492
575545
  }
@@ -575540,6 +575593,10 @@ var init_focusSupervisor = __esm({
575540
575593
  this.lastReason = "cached/no-op tool result did not perform the required recovery action";
575541
575594
  return;
575542
575595
  }
575596
+ if (input.success && input.usedAuthoritativeTargetEvidence && isEditTool(input.toolName) && this.directive?.requiredNextAction === "read_authoritative_target") {
575597
+ this.clearSatisfiedDirective("verified edit used authoritative target evidence", input.turn);
575598
+ return;
575599
+ }
575543
575600
  if (input.toolName === "file_read" && input.success) {
575544
575601
  if (this.directive?.requiredNextAction === "read_authoritative_target") {
575545
575602
  this.clearSatisfiedDirective("authoritative evidence refreshed", input.turn);
@@ -578420,7 +578477,7 @@ function classifyThinkOutcome(raw) {
578420
578477
  }
578421
578478
  return null;
578422
578479
  }
578423
- var TOOL_SUBSETS, TOOL_AUTO_DEMOTE_TURNS, SYSTEM_PROMPT, SYSTEM_PROMPT_MEDIUM, SYSTEM_PROMPT_SMALL, VISUAL_TOOLS, AUDIO_TOOLS, SOCIAL_TOOLS, SPATIAL_TOOLS, CODE_TOOLS, AgenticRunner, OllamaAgenticBackend;
578480
+ var TOOL_SUBSETS, TOOL_AUTO_DEMOTE_TURNS, TOOL_ACTION_REASON_KEYS, TOOL_ACTION_REASON_SCOPES, TOOL_ACTION_REASON_SCHEMA, SYSTEM_PROMPT, SYSTEM_PROMPT_MEDIUM, SYSTEM_PROMPT_SMALL, VISUAL_TOOLS, AUDIO_TOOLS, SOCIAL_TOOLS, SPATIAL_TOOLS, CODE_TOOLS, AgenticRunner, OllamaAgenticBackend;
578424
578481
  var init_agenticRunner = __esm({
578425
578482
  "packages/orchestrator/dist/agenticRunner.js"() {
578426
578483
  "use strict";
@@ -578509,6 +578566,56 @@ var init_agenticRunner = __esm({
578509
578566
  skill: ["skill_list", "skill_extract", "skill_execute", "skill_search"]
578510
578567
  };
578511
578568
  TOOL_AUTO_DEMOTE_TURNS = 10;
578569
+ TOOL_ACTION_REASON_KEYS = /* @__PURE__ */ new Set([
578570
+ "action_reason",
578571
+ "actionReason",
578572
+ "justification"
578573
+ ]);
578574
+ TOOL_ACTION_REASON_SCOPES = /* @__PURE__ */ new Set([
578575
+ "discovery",
578576
+ "targeted_patch",
578577
+ "new_file",
578578
+ "full_file_rewrite",
578579
+ "verification",
578580
+ "state_update",
578581
+ "delegation",
578582
+ "completion",
578583
+ "other"
578584
+ ]);
578585
+ TOOL_ACTION_REASON_SCHEMA = {
578586
+ type: "object",
578587
+ description: "Compact public action contract for this exact tool call. Do not include hidden chain-of-thought; use concise task-state facts.",
578588
+ properties: {
578589
+ task_anchor: {
578590
+ type: "string",
578591
+ description: "One compact phrase tying this call to the active user goal/current focus."
578592
+ },
578593
+ intent: {
578594
+ type: "string",
578595
+ description: "One sentence explaining why this tool is the next action."
578596
+ },
578597
+ evidence: {
578598
+ type: "string",
578599
+ description: "Fresh evidence or contract authorizing the action: file hash, focus directive, cached evidence, user request, or explicit absence."
578600
+ },
578601
+ expected_result: {
578602
+ type: "string",
578603
+ description: "The concrete new state or information expected from this call."
578604
+ },
578605
+ scope: {
578606
+ type: "string",
578607
+ enum: Array.from(TOOL_ACTION_REASON_SCOPES),
578608
+ description: "Classify the action scope. Use targeted_patch for constrained edits; full_file_rewrite only for deliberate whole-file replacement."
578609
+ }
578610
+ },
578611
+ required: [
578612
+ "task_anchor",
578613
+ "intent",
578614
+ "evidence",
578615
+ "expected_result",
578616
+ "scope"
578617
+ ]
578618
+ };
578512
578619
  SYSTEM_PROMPT = loadPrompt("agentic/system-large.md");
578513
578620
  SYSTEM_PROMPT_MEDIUM = loadPrompt("agentic/system-medium.md");
578514
578621
  SYSTEM_PROMPT_SMALL = loadPrompt("agentic/system-small.md");
@@ -579334,7 +579441,7 @@ ${parts.join("\n")}
579334
579441
  cardId: implementation2.id,
579335
579442
  title: implementation2.title,
579336
579443
  reason: "discovery evidence is already present; land the smallest concrete repair",
579337
- preferredTools: ["file_write", "file_edit", "batch_edit", "file_patch"]
579444
+ preferredTools: ["file_patch", "batch_edit", "file_edit", "file_write"]
579338
579445
  };
579339
579446
  }
579340
579447
  const active = snapshot.cards.find((card) => card.status === "in_progress") ?? snapshot.cards.find((card) => card.status === "needs_changes") ?? snapshot.cards.find((card) => card.status === "open") ?? discovery;
@@ -579344,7 +579451,7 @@ ${parts.join("\n")}
579344
579451
  cardId: active.id,
579345
579452
  title: active.title,
579346
579453
  reason: active.id === "discover-current-state" ? "no authoritative target evidence is recorded yet" : "workboard card is the next unresolved card",
579347
- preferredTools: active.id === "discover-current-state" ? ["file_read", "grep_search", "list_directory", "shell"] : ["file_write", "file_edit", "batch_edit", "file_patch", "shell"]
579454
+ preferredTools: active.id === "discover-current-state" ? ["file_read", "grep_search", "list_directory", "shell"] : ["file_patch", "batch_edit", "file_edit", "file_write", "shell"]
579348
579455
  };
579349
579456
  }
579350
579457
  _focusToolsForRequiredAction(action) {
@@ -579358,7 +579465,7 @@ ${parts.join("\n")}
579358
579465
  case "disambiguate_edit_match":
579359
579466
  return "file_edit or batch_edit with replace_all=true for identical global changes, or with a more unique old_string copied from current file context";
579360
579467
  case "edit_different_target":
579361
- return "file_write, file_edit, batch_edit, or file_patch on a different supported target";
579468
+ return "file_patch, batch_edit, file_edit, or hash-guarded file_write on a different supported target";
579362
579469
  case "run_verification":
579363
579470
  return "shell running the verification/runtime command";
579364
579471
  case "report_blocked":
@@ -579370,6 +579477,25 @@ ${parts.join("\n")}
579370
579477
  }
579371
579478
  _renderNextActionContract(turn) {
579372
579479
  const lines = ["[NEXT ACTION CONTRACT]", `turn=${turn}`];
579480
+ const ts = this._taskState;
579481
+ const goal = (ts.originalGoal || ts.goal || "").replace(/\s+/g, " ").trim();
579482
+ if (goal)
579483
+ lines.push(`goal_anchor=${goal.slice(0, 360)}`);
579484
+ if (ts.currentStep) {
579485
+ lines.push(`current_focus=${ts.currentStep.replace(/\s+/g, " ").slice(0, 220)}`);
579486
+ }
579487
+ if (ts.nextAction) {
579488
+ lines.push(`declared_next_action=${ts.nextAction.replace(/\s+/g, " ").slice(0, 220)}`);
579489
+ }
579490
+ lines.push(`progress_anchor=completed_steps:${ts.completedSteps.length} failed_approaches:${ts.failedApproaches.length} modified_files:${ts.modifiedFiles.size} tool_calls:${ts.toolCallCount}`);
579491
+ if (ts.completedSteps.length > 0) {
579492
+ lines.push(`recent_completed=${ts.completedSteps.slice(-3).join(" | ").replace(/\s+/g, " ").slice(0, 420)}`);
579493
+ }
579494
+ if (ts.failedApproaches.length > 0) {
579495
+ lines.push(`recent_failed_approaches=${ts.failedApproaches.slice(-3).join(" | ").replace(/\s+/g, " ").slice(0, 420)}`);
579496
+ }
579497
+ lines.push("tool_call_contract=Each tool call must include action_reason {task_anchor,intent,evidence,expected_result,scope}; compact public facts only, no hidden chain-of-thought.");
579498
+ lines.push(`scope_contract=${Array.from(TOOL_ACTION_REASON_SCOPES).join("|")}; use targeted_patch for constrained code edits and full_file_rewrite only for deliberate whole-file replacement.`);
579373
579499
  const focus = this._focusSupervisor?.snapshot().directive ?? null;
579374
579500
  if (focus) {
579375
579501
  lines.push(`focus_required_next_action=${focus.requiredNextAction}`);
@@ -584840,7 +584966,7 @@ ${blob}
584840
584966
  if (seen.has(value2))
584841
584967
  return "#cycle";
584842
584968
  seen.add(value2);
584843
- const entries = Object.entries(value2).sort(([a2], [b]) => a2.localeCompare(b)).map(([k, v]) => `${JSON.stringify(k)}:${this._canonicalArgValue(v, seen)}`);
584969
+ const entries = Object.entries(value2).filter(([key]) => !TOOL_ACTION_REASON_KEYS.has(key)).sort(([a2], [b]) => a2.localeCompare(b)).map(([k, v]) => `${JSON.stringify(k)}:${this._canonicalArgValue(v, seen)}`);
584844
584970
  return `#object:{${entries.join(",")}}`;
584845
584971
  }
584846
584972
  return String(value2);
@@ -587310,7 +587436,7 @@ ${_staleSamples.join("\n")}` : ``,
587310
587436
  ``,
587311
587437
  ` (c) REPLACE_ALL: If you want a global rename, set replace_all=true and the uniqueness check is bypassed.`,
587312
587438
  ``,
587313
- ` (d) FILE_WRITE: If the changes are extensive, rewrite the whole file with file_write instead of patching it. Faster than 6 failed edits.`,
587439
+ ` (d) CONSTRAINED PATCH: If the exact replacement is too brittle, use file_patch with expected_old_content or batch_edit/file_edit against fresh current text. Use file_write only for new files, dry-run proposals, or deliberate hash-guarded full_file_rewrite actions.`,
587314
587440
  ``,
587315
587441
  `Do NOT in your next response: call file_edit or batch_edit on ${_efWorstPath} again with another guess at old_string.`
587316
587442
  ].join("\n")
@@ -588414,6 +588540,7 @@ ${memoryLines.join("\n")}`
588414
588540
  const executeSingle = async (tc) => {
588415
588541
  if (this.aborted)
588416
588542
  return null;
588543
+ const actionReasonForAdvisory = this._extractToolActionReason(tc.arguments ?? {});
588417
588544
  const cohortKey = this.buildArgCohortKey(tc.name, tc.arguments);
588418
588545
  const cohort = this._argCohorts.get(cohortKey);
588419
588546
  if (cohort && cohort.failure >= 3 && cohort.success === 0) {
@@ -588805,6 +588932,7 @@ Read the current file if needed, make a different concrete edit, or move to veri
588805
588932
  turn,
588806
588933
  toolName: tc.name,
588807
588934
  args: tc.arguments ?? {},
588935
+ actionReason: actionReasonForAdvisory,
588808
588936
  fingerprint: toolFingerprint,
588809
588937
  isReadLike: false,
588810
588938
  stalePreflightMessage: staleEditBlock,
@@ -588870,6 +588998,7 @@ Read the current file if needed, make a different concrete edit, or move to veri
588870
588998
  turn,
588871
588999
  toolName: tc.name,
588872
589000
  args: tc.arguments ?? {},
589001
+ actionReason: actionReasonForAdvisory,
588873
589002
  fingerprint: toolFingerprint,
588874
589003
  isReadLike: false,
588875
589004
  stalePreflightMessage: staleRewriteBlock,
@@ -588935,6 +589064,7 @@ Read the current file if needed, make a different concrete edit, or move to veri
588935
589064
  turn,
588936
589065
  toolName: tc.name,
588937
589066
  args: tc.arguments ?? {},
589067
+ actionReason: actionReasonForAdvisory,
588938
589068
  fingerprint: toolFingerprint,
588939
589069
  isReadLike: false,
588940
589070
  stalePreflightMessage: editReversalBlock,
@@ -589066,7 +589196,11 @@ Read the current file if needed, make a different concrete edit, or move to veri
589066
589196
  decision: "pass",
589067
589197
  reason: "adversary critic disabled for isolated evaluation"
589068
589198
  } : evaluate2({
589069
- proposedCall: { tool: tc.name, args: tc.arguments ?? {} },
589199
+ proposedCall: {
589200
+ tool: tc.name,
589201
+ args: tc.arguments ?? {},
589202
+ actionReason: actionReasonForAdvisory ?? void 0
589203
+ },
589070
589204
  fingerprint: toolFingerprint,
589071
589205
  isReadLike,
589072
589206
  recentToolResults,
@@ -589115,6 +589249,7 @@ Read the current file if needed, make a different concrete edit, or move to veri
589115
589249
  tool: tc.name,
589116
589250
  target: _target,
589117
589251
  count: criticDecision.hitNumber,
589252
+ actionReason: actionReasonForAdvisory ?? void 0,
589118
589253
  alreadyHave: _existingFp?.result
589119
589254
  }
589120
589255
  });
@@ -589196,10 +589331,12 @@ ${cachedResult}`,
589196
589331
  }
589197
589332
  const focusCachedEntry = recentToolResults.get(toolFingerprint);
589198
589333
  const focusDuplicateHits = criticDecision.decision === "guidance" ? criticDecision.hitNumber : dedupHitCount.get(toolFingerprint) ?? 0;
589334
+ const usesAuthoritativeTargetEvidence = this._toolCallUsesFreshFileReadEvidence(tc.name, tc.arguments ?? {});
589199
589335
  const focusDecision = this._focusSupervisor?.evaluateProposedCall({
589200
589336
  turn,
589201
589337
  toolName: tc.name,
589202
589338
  args: tc.arguments ?? {},
589339
+ actionReason: actionReasonForAdvisory,
589203
589340
  completionStatus: completionStatusFromTaskCompleteArgs(tc.arguments),
589204
589341
  fingerprint: toolFingerprint,
589205
589342
  isReadLike,
@@ -589207,7 +589344,8 @@ ${cachedResult}`,
589207
589344
  cachedResult: focusCachedEntry?.result,
589208
589345
  cachedResultFailed: tc.name === "shell" && typeof focusCachedEntry?.result === "string" && focusCachedEntry.result.includes("status: failure"),
589209
589346
  duplicateHitCount: focusDuplicateHits,
589210
- context: this._buildFocusContextSnapshot()
589347
+ context: this._buildFocusContextSnapshot(),
589348
+ usesAuthoritativeTargetEvidence
589211
589349
  });
589212
589350
  if (focusDecision && focusDecision.kind !== "pass") {
589213
589351
  this._emitFocusSupervisorEvent({
@@ -589247,6 +589385,7 @@ ${cachedResult}`,
589247
589385
  const tool = resolvedTool?.tool;
589248
589386
  let result;
589249
589387
  let runtimeSystemGuidance = null;
589388
+ let toolActionReason = actionReasonForAdvisory;
589250
589389
  if (repeatShortCircuit) {
589251
589390
  result = repeatShortCircuit;
589252
589391
  } else if (tc.arguments && "_raw" in tc.arguments) {
@@ -589262,7 +589401,14 @@ ${cachedResult}`,
589262
589401
  error: this.unknownToolError(tc.name)
589263
589402
  };
589264
589403
  } else {
589265
- let validationError = this._validateFreshExpectedHashesForEdit(resolvedTool?.name ?? tc.name, tc.arguments ?? {});
589404
+ let validationError = this._validateToolActionReason(resolvedTool?.name ?? tc.name, tc.arguments ?? {});
589405
+ if (!validationError) {
589406
+ tc.arguments = this._stripToolActionReasonArgs(tc.arguments ?? {});
589407
+ validationError = this._validateFileWriteOverwriteContract(resolvedTool?.name ?? tc.name, tc.arguments ?? {}, toolActionReason);
589408
+ }
589409
+ if (!validationError) {
589410
+ validationError = this._validateFreshExpectedHashesForEdit(resolvedTool?.name ?? tc.name, tc.arguments ?? {});
589411
+ }
589266
589412
  if (!validationError && tool.inputSchema) {
589267
589413
  const parseResult = tool.inputSchema.safeParse(tc.arguments);
589268
589414
  if (!parseResult.success) {
@@ -590733,6 +590879,7 @@ Evidence: ${evidencePreview}`.slice(0, 500);
590733
590879
  turn,
590734
590880
  toolName: tc.name,
590735
590881
  args: tc.arguments ?? {},
590882
+ actionReason: toolActionReason,
590736
590883
  fingerprint: toolFingerprint,
590737
590884
  success: result.success,
590738
590885
  output: result.output ?? result.llmContent ?? "",
@@ -590741,7 +590888,8 @@ Evidence: ${evidencePreview}`.slice(0, 500);
590741
590888
  isReadLike,
590742
590889
  noop: tc.name === "todo_write" ? this._isTodoWriteNoopResult(result) : result.noop,
590743
590890
  alreadyApplied: result.alreadyApplied === true,
590744
- runtimeAuthored: result.runtimeAuthored === true
590891
+ runtimeAuthored: result.runtimeAuthored === true,
590892
+ usedAuthoritativeTargetEvidence: usesAuthoritativeTargetEvidence
590745
590893
  });
590746
590894
  const focusSnapshotAfter = this._focusSupervisor?.snapshot();
590747
590895
  focusAfterToolResult = focusSnapshotAfter ?? void 0;
@@ -590784,6 +590932,7 @@ Evidence: ${evidencePreview}`.slice(0, 500);
590784
590932
  reason: focusDecision.directive.reason,
590785
590933
  requiredNextAction: focusDecision.directive.requiredNextAction
590786
590934
  },
590935
+ actionReason: toolActionReason ?? void 0,
590787
590936
  repeatShortCircuit: Boolean(repeatShortCircuit),
590788
590937
  runtimeAuthored: result.runtimeAuthored === true,
590789
590938
  runtimeGuidance: runtimeSystemGuidance
@@ -593490,6 +593639,16 @@ ${marker}` : marker);
593490
593639
  return { args, patchedCount: 0 };
593491
593640
  return { args: { ...args, expected_hash: fresh.hash }, patchedCount: 1 };
593492
593641
  }
593642
+ if (toolName === "file_write" || toolName === "file_patch") {
593643
+ if (this._normalizeExpectedHashValue(this._rawExpectedHashValue(args))) {
593644
+ return { args, patchedCount: 0 };
593645
+ }
593646
+ const path12 = this.extractPrimaryToolPath(args);
593647
+ const fresh = path12 ? this._freshReadHashForEditPath(path12) : null;
593648
+ if (!fresh)
593649
+ return { args, patchedCount: 0 };
593650
+ return { args: { ...args, expected_hash: fresh.hash }, patchedCount: 1 };
593651
+ }
593493
593652
  if (toolName !== "batch_edit" || !Array.isArray(args["edits"])) {
593494
593653
  return { args, patchedCount: 0 };
593495
593654
  }
@@ -593510,6 +593669,151 @@ ${marker}` : marker);
593510
593669
  });
593511
593670
  return patchedCount > 0 ? { args: { ...args, edits }, patchedCount } : { args, patchedCount: 0 };
593512
593671
  }
593672
+ _toolCallUsesFreshFileReadEvidence(toolName, args) {
593673
+ if (toolName !== "file_write" && toolName !== "file_edit" && toolName !== "file_patch" && toolName !== "batch_edit") {
593674
+ return false;
593675
+ }
593676
+ const matchesFresh = (rec) => {
593677
+ const path12 = typeof rec["path"] === "string" ? rec["path"] : typeof rec["file"] === "string" ? rec["file"] : "";
593678
+ if (!path12)
593679
+ return false;
593680
+ const expectedHash = this._normalizeExpectedHashValue(this._rawExpectedHashValue(rec));
593681
+ if (!expectedHash)
593682
+ return false;
593683
+ const fresh = this._freshReadHashForEditPath(path12);
593684
+ return fresh?.hash === expectedHash;
593685
+ };
593686
+ if (toolName === "batch_edit") {
593687
+ const edits = args["edits"];
593688
+ return Array.isArray(edits) && edits.length > 0 && edits.every((edit) => !!edit && typeof edit === "object" && !Array.isArray(edit) && matchesFresh(edit));
593689
+ }
593690
+ return matchesFresh(args);
593691
+ }
593692
+ _requiresToolActionReason(toolName) {
593693
+ if (process.env["OMNIUS_DISABLE_TOOL_ACTION_REASON"] === "1") {
593694
+ return false;
593695
+ }
593696
+ if ((process.env["VITEST"] || process.env["NODE_ENV"] === "test") && process.env["OMNIUS_REQUIRE_TOOL_ACTION_REASON"] !== "1") {
593697
+ return false;
593698
+ }
593699
+ if (this.options.artifactMode === "internal")
593700
+ return false;
593701
+ if (toolName.startsWith("__"))
593702
+ return false;
593703
+ return true;
593704
+ }
593705
+ _withToolActionReasonSchema(toolName, parameters) {
593706
+ if (!this._requiresToolActionReason(toolName)) {
593707
+ return parameters ?? { type: "object", properties: {} };
593708
+ }
593709
+ const base3 = parameters && typeof parameters === "object" && !Array.isArray(parameters) ? { ...parameters } : { type: "object" };
593710
+ const properties = base3["properties"] && typeof base3["properties"] === "object" && !Array.isArray(base3["properties"]) ? { ...base3["properties"] } : {};
593711
+ properties["action_reason"] = TOOL_ACTION_REASON_SCHEMA;
593712
+ const required = Array.isArray(base3["required"]) ? base3["required"].map(String) : [];
593713
+ return {
593714
+ ...base3,
593715
+ type: "object",
593716
+ properties,
593717
+ required: [.../* @__PURE__ */ new Set([...required, "action_reason"])]
593718
+ };
593719
+ }
593720
+ _extractToolActionReason(args) {
593721
+ const raw = args["action_reason"] ?? args["actionReason"] ?? args["justification"];
593722
+ if (!raw || typeof raw !== "object" || Array.isArray(raw))
593723
+ return null;
593724
+ const rec = raw;
593725
+ const reason = {
593726
+ task_anchor: String(rec["task_anchor"] ?? rec["taskAnchor"] ?? "").trim(),
593727
+ intent: String(rec["intent"] ?? "").trim(),
593728
+ evidence: String(rec["evidence"] ?? "").trim(),
593729
+ expected_result: String(rec["expected_result"] ?? rec["expectedResult"] ?? "").trim(),
593730
+ scope: String(rec["scope"] ?? "").trim()
593731
+ };
593732
+ return reason;
593733
+ }
593734
+ _validateToolActionReason(toolName, args) {
593735
+ if (!this._requiresToolActionReason(toolName))
593736
+ return null;
593737
+ const raw = args["action_reason"] ?? args["actionReason"] ?? args["justification"];
593738
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
593739
+ return [
593740
+ "[TOOL ACTION REASON CONTRACT]",
593741
+ `Every tool call must include action_reason: { task_anchor, intent, evidence, expected_result, scope }.`,
593742
+ `Use compact public facts only; do not include hidden chain-of-thought.`,
593743
+ `scope must be one of: ${Array.from(TOOL_ACTION_REASON_SCOPES).join(", ")}.`
593744
+ ].join("\n");
593745
+ }
593746
+ const reason = this._extractToolActionReason(args);
593747
+ if (!reason) {
593748
+ return "[TOOL ACTION REASON CONTRACT] action_reason must be an object with compact public task-state fields.";
593749
+ }
593750
+ const missing = [
593751
+ "task_anchor",
593752
+ "intent",
593753
+ "evidence",
593754
+ "expected_result",
593755
+ "scope"
593756
+ ].filter((key) => reason[key].length < 3);
593757
+ if (missing.length > 0) {
593758
+ return `[TOOL ACTION REASON CONTRACT] action_reason missing non-empty field(s): ${missing.join(", ")}.`;
593759
+ }
593760
+ if (!TOOL_ACTION_REASON_SCOPES.has(reason.scope)) {
593761
+ return `[TOOL ACTION REASON CONTRACT] action_reason.scope="${reason.scope}" is invalid. Use one of: ${Array.from(TOOL_ACTION_REASON_SCOPES).join(", ")}.`;
593762
+ }
593763
+ return null;
593764
+ }
593765
+ _stripToolActionReasonArgs(args) {
593766
+ let changed = false;
593767
+ const next = {};
593768
+ for (const [key, value2] of Object.entries(args)) {
593769
+ if (TOOL_ACTION_REASON_KEYS.has(key)) {
593770
+ changed = true;
593771
+ continue;
593772
+ }
593773
+ next[key] = value2;
593774
+ }
593775
+ return changed ? next : args;
593776
+ }
593777
+ _validateFileWriteOverwriteContract(toolName, args, actionReason) {
593778
+ if (toolName !== "file_write")
593779
+ return null;
593780
+ if (process.env["OMNIUS_ALLOW_UNVERIFIED_FILE_WRITE_OVERWRITE"] === "1") {
593781
+ return null;
593782
+ }
593783
+ if (args["dry_run"] === true || args["dryRun"] === true)
593784
+ return null;
593785
+ const path12 = this.extractPrimaryToolPath(args);
593786
+ if (!path12)
593787
+ return null;
593788
+ let exists2 = false;
593789
+ try {
593790
+ const st = _fsStatSync(this._absoluteToolPath(path12), {
593791
+ throwIfNoEntry: false
593792
+ });
593793
+ exists2 = !!st && st.isFile();
593794
+ } catch {
593795
+ exists2 = false;
593796
+ }
593797
+ if (!exists2)
593798
+ return null;
593799
+ if (actionReason && actionReason.scope !== "full_file_rewrite") {
593800
+ return [
593801
+ "[FULL FILE REWRITE CONTRACT]",
593802
+ `file_write targets an existing file: ${path12}.`,
593803
+ `For constrained repairs, use file_patch, batch_edit, or file_edit instead of rewriting the full file.`,
593804
+ `If a whole-file replacement is truly intended, set action_reason.scope="full_file_rewrite" and use expected_hash from a fresh file_read.`
593805
+ ].join("\n");
593806
+ }
593807
+ if (!this._toolCallUsesFreshFileReadEvidence(toolName, args)) {
593808
+ const fresh = this._freshReadHashForEditPath(path12);
593809
+ return [
593810
+ "[FULL FILE REWRITE CONTRACT]",
593811
+ `file_write would overwrite existing file ${path12}, but it is not anchored to fresh file_read evidence.`,
593812
+ fresh ? `Use expected_hash=${fresh.hash} from the current active evidence, or prefer file_patch/batch_edit for a constrained change.` : `First file_read ${path12}, then prefer file_patch/batch_edit; only retry file_write with expected_hash if a whole-file rewrite is necessary.`
593813
+ ].join("\n");
593814
+ }
593815
+ return null;
593816
+ }
593513
593817
  _validateFreshExpectedHashesForEdit(toolName, args) {
593514
593818
  if (process.env["OMNIUS_ALLOW_UNVERIFIED_OLD_STRING_EDIT"] === "1") {
593515
593819
  return null;
@@ -595478,6 +595782,7 @@ ${trimmedNew}`;
595478
595782
  args = JSON.parse(tc.function.arguments);
595479
595783
  } catch {
595480
595784
  }
595785
+ const actionReason = this._extractToolActionReason(args);
595481
595786
  const argsKey = this._buildExactArgsKey(args);
595482
595787
  const fingerprint = this._buildToolFingerprint(name10, args);
595483
595788
  const prior = this._adversaryToolOutcomes.find((o2) => o2.succeeded && o2.tool === name10 && o2.fingerprint === fingerprint && o2.stateVersion === this._adversaryStateVersion && o2.turn < turn);
@@ -595491,6 +595796,7 @@ ${trimmedNew}`;
595491
595796
  tool: name10,
595492
595797
  target: argsKey.slice(0, 180),
595493
595798
  count: repeatCount,
595799
+ actionReason: actionReason ?? void 0,
595494
595800
  alreadyHave: prior.preview
595495
595801
  }
595496
595802
  }, `possible repeated action ${name10} after prior same-state success`);
@@ -596724,7 +597030,7 @@ Example: ${tool.name}(${JSON.stringify(meta.examples[0].args ?? {})})` : "";
596724
597030
  function: {
596725
597031
  name: tool.name,
596726
597032
  description: compressDesc ? (desc.split(/\.\s/)[0]?.slice(0, 120) ?? desc.slice(0, 120)) + "." : desc,
596727
- parameters: tool.parameters
597033
+ parameters: this._withToolActionReasonSchema(tool.name, tool.parameters)
596728
597034
  }
596729
597035
  };
596730
597036
  });
@@ -596746,7 +597052,7 @@ Example: ${tool.name}(${JSON.stringify(meta.examples[0].args ?? {})})` : "";
596746
597052
 
596747
597053
  Available tools (${deferred.length}):
596748
597054
  ${catalog}`,
596749
- parameters: {
597055
+ parameters: this._withToolActionReasonSchema("tool_search", {
596750
597056
  type: "object",
596751
597057
  properties: {
596752
597058
  query: {
@@ -596755,7 +597061,7 @@ ${catalog}`,
596755
597061
  }
596756
597062
  },
596757
597063
  required: ["query"]
596758
- }
597064
+ })
596759
597065
  }
596760
597066
  });
596761
597067
  const activatedToolsRef = this._activatedTools;
@@ -596797,7 +597103,7 @@ ${catalog}`,
596797
597103
  lines.push(`Aliases: ${tool.aliases.join(", ")}`);
596798
597104
  }
596799
597105
  lines.push(`${getDesc(tool)}${customToolDetails(tool)}`);
596800
- lines.push(`Parameters: ${JSON.stringify(tool.parameters)}`);
597106
+ lines.push(`Parameters: ${JSON.stringify(this._withToolActionReasonSchema(tool.name, tool.parameters))}`);
596801
597107
  }
596802
597108
  }
596803
597109
  if (alreadyAvailable.length > 0) {
@@ -596849,7 +597155,7 @@ ${catalog}`,
596849
597155
  for (const t2 of matches)
596850
597156
  activatedToolsRef.add(t2.name);
596851
597157
  const result = matches.map((t2) => {
596852
- const paramsStr = JSON.stringify(t2.parameters, null, 2);
597158
+ const paramsStr = JSON.stringify(this._withToolActionReasonSchema(t2.name, t2.parameters), null, 2);
596853
597159
  const aliases = t2.aliases?.length ? `
596854
597160
  Aliases: ${t2.aliases.join(", ")}` : "";
596855
597161
  return `## ${t2.name}${aliases}
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "omnius",
3
- "version": "1.0.460",
3
+ "version": "1.0.461",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "omnius",
9
- "version": "1.0.460",
9
+ "version": "1.0.461",
10
10
  "bundleDependencies": [
11
11
  "image-to-ascii"
12
12
  ],
@@ -1662,9 +1662,9 @@
1662
1662
  }
1663
1663
  },
1664
1664
  "node_modules/@multiformats/murmur3": {
1665
- "version": "2.2.5",
1666
- "resolved": "https://registry.npmjs.org/@multiformats/murmur3/-/murmur3-2.2.5.tgz",
1667
- "integrity": "sha512-M+VwV8hEx5qB8i7b8fljMwZETJsqyLo8RAXA+JAn+QF9NnH46ZWvGErNukJVlxXSR2KQpuOtHIYIzZlbhhdFvw==",
1665
+ "version": "2.2.6",
1666
+ "resolved": "https://registry.npmjs.org/@multiformats/murmur3/-/murmur3-2.2.6.tgz",
1667
+ "integrity": "sha512-SPovNpXC6BQpYkCy2IpN58t4BFx2dnwmo5ppWk3z5/DjD2syV/Na1fAPkBKjk6iualm6qpoTp55cX1UE0jIRlQ==",
1668
1668
  "license": "Apache-2.0 OR MIT",
1669
1669
  "dependencies": {
1670
1670
  "multiformats": "^14.0.0"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "omnius",
3
- "version": "1.0.460",
3
+ "version": "1.0.461",
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",