omnius 1.0.534 → 1.0.536

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
@@ -6981,14 +6981,14 @@ var init_file_write = __esm({
6981
6981
  init_text_encoding();
6982
6982
  FileWriteTool = class {
6983
6983
  name = "file_write";
6984
- description = "Write UTF-8 text to a file, creating directories as needed. For content with heavy quoting, raw JSON, control characters, or large full-file payloads, pass content_base64 instead of shell heredocs/cat/tee.";
6984
+ description = "Create new files or deliberately replace small, empty, or placeholder files; use file_edit/file_patch for local changes. For content with heavy quoting, raw JSON, control characters, or large full-file payloads, pass content_base64 instead of shell heredocs/cat/tee.";
6985
6985
  parameters = {
6986
6986
  type: "object",
6987
6987
  properties: {
6988
6988
  path: { type: "string", description: "Absolute or relative file path" },
6989
6989
  content: {
6990
6990
  type: "string",
6991
- description: "UTF-8 text content to write. Use content_base64 when JSON escaping is fragile."
6991
+ description: "Complete UTF-8 file content. Do not send an existing large file merely to change one region; use file_edit/file_patch."
6992
6992
  },
6993
6993
  content_base64: {
6994
6994
  type: "string",
@@ -567114,13 +567114,103 @@ function normalizeShellCommand(command) {
567114
567114
  function splitConjunctiveVerifyCommand(command) {
567115
567115
  return normalizeShellCommand(command).split(/\s+&&\s+/).map((part) => part.trim()).filter(Boolean);
567116
567116
  }
567117
+ function stripVerifierFallbackSuffix(command) {
567118
+ let quote2 = null;
567119
+ for (let i2 = 0; i2 < command.length - 1; i2++) {
567120
+ const ch = command[i2];
567121
+ if (quote2) {
567122
+ if (ch === quote2 && command[i2 - 1] !== "\\")
567123
+ quote2 = null;
567124
+ continue;
567125
+ }
567126
+ if (ch === "'" || ch === '"') {
567127
+ quote2 = ch;
567128
+ continue;
567129
+ }
567130
+ if (ch === "|" && command[i2 + 1] === "|") {
567131
+ return command.slice(0, i2).trim();
567132
+ }
567133
+ }
567134
+ return command.trim();
567135
+ }
567136
+ function stageHeadProgram(stage2) {
567137
+ const tokens = stage2.trim().split(/\s+/);
567138
+ let i2 = 0;
567139
+ while (i2 < tokens.length) {
567140
+ const token = tokens[i2];
567141
+ if (/^[A-Za-z_][A-Za-z0-9_]*=/.test(token)) {
567142
+ i2++;
567143
+ continue;
567144
+ }
567145
+ const base3 = token.replace(/^["']|["']$/g, "").split("/").pop() ?? token;
567146
+ if (STAGE_PREFIX_PROGRAMS.has(base3)) {
567147
+ i2++;
567148
+ if (base3 === "timeout" && /^[0-9]+[smhd]?$/.test(tokens[i2] ?? ""))
567149
+ i2++;
567150
+ continue;
567151
+ }
567152
+ return base3.toLowerCase();
567153
+ }
567154
+ return null;
567155
+ }
567156
+ function commandIsPureReadOnlyPipeline(command) {
567157
+ const stages = [];
567158
+ let current = "";
567159
+ let quote2 = null;
567160
+ const raw = command.trim();
567161
+ if (!raw)
567162
+ return false;
567163
+ for (let i2 = 0; i2 < raw.length; i2++) {
567164
+ const ch = raw[i2];
567165
+ if (quote2) {
567166
+ current += ch;
567167
+ if (ch === quote2 && raw[i2 - 1] !== "\\")
567168
+ quote2 = null;
567169
+ continue;
567170
+ }
567171
+ if (ch === "'" || ch === '"') {
567172
+ quote2 = ch;
567173
+ current += ch;
567174
+ continue;
567175
+ }
567176
+ if (ch === "&" && raw[i2 + 1] === "&") {
567177
+ stages.push(current);
567178
+ current = "";
567179
+ i2++;
567180
+ continue;
567181
+ }
567182
+ if (ch === "|") {
567183
+ stages.push(current);
567184
+ current = "";
567185
+ if (raw[i2 + 1] === "|")
567186
+ i2++;
567187
+ continue;
567188
+ }
567189
+ if (ch === ";") {
567190
+ stages.push(current);
567191
+ current = "";
567192
+ continue;
567193
+ }
567194
+ if (ch === "$" && raw[i2 + 1] === "(")
567195
+ return false;
567196
+ if (ch === "`")
567197
+ return false;
567198
+ current += ch;
567199
+ }
567200
+ stages.push(current);
567201
+ const meaningful = stages.map((s2) => s2.trim()).filter(Boolean);
567202
+ if (meaningful.length === 0)
567203
+ return false;
567204
+ return meaningful.every((stage2) => {
567205
+ const head = stageHeadProgram(stage2);
567206
+ return head !== null && PURE_READER_PROGRAMS.has(head);
567207
+ });
567208
+ }
567117
567209
  function commandReliablySatisfiesVerifyCommand(observedCommand, verifyCommand) {
567118
567210
  const observed = normalizeShellCommand(observedCommand);
567119
- const expected = normalizeShellCommand(verifyCommand);
567211
+ const expected = normalizeShellCommand(stripVerifierFallbackSuffix(verifyCommand));
567120
567212
  if (!observed || !expected)
567121
567213
  return false;
567122
- if (expected.includes(" || "))
567123
- return false;
567124
567214
  if (observed === expected)
567125
567215
  return true;
567126
567216
  if (observed.startsWith(`${expected} && `) && !observed.includes(" || ")) {
@@ -567141,9 +567231,93 @@ function verifyCommandSatisfiedByShellHistory(verifyCommand, history) {
567141
567231
  return false;
567142
567232
  return parts.every((part) => successful.some((entry) => commandReliablySatisfiesVerifyCommand(entry.command, part)));
567143
567233
  }
567234
+ var PURE_READER_PROGRAMS, STAGE_PREFIX_PROGRAMS;
567144
567235
  var init_verificationCommand = __esm({
567145
567236
  "packages/orchestrator/dist/verificationCommand.js"() {
567146
567237
  "use strict";
567238
+ PURE_READER_PROGRAMS = /* @__PURE__ */ new Set([
567239
+ "cat",
567240
+ "tac",
567241
+ "tail",
567242
+ "head",
567243
+ "less",
567244
+ "more",
567245
+ "grep",
567246
+ "egrep",
567247
+ "fgrep",
567248
+ "rg",
567249
+ "ag",
567250
+ "awk",
567251
+ "gawk",
567252
+ "sed",
567253
+ "gsed",
567254
+ "sort",
567255
+ "uniq",
567256
+ "wc",
567257
+ "cut",
567258
+ "tr",
567259
+ "column",
567260
+ "echo",
567261
+ "printf",
567262
+ "ls",
567263
+ "dir",
567264
+ "find",
567265
+ "fd",
567266
+ "stat",
567267
+ "file",
567268
+ "strings",
567269
+ "hexdump",
567270
+ "xxd",
567271
+ "od",
567272
+ "jq",
567273
+ "yq",
567274
+ "tee",
567275
+ "dirname",
567276
+ "basename",
567277
+ "readlink",
567278
+ "realpath",
567279
+ "pwd",
567280
+ "date",
567281
+ "true",
567282
+ "false",
567283
+ "test",
567284
+ "type",
567285
+ "which",
567286
+ "whoami",
567287
+ "env",
567288
+ "printenv",
567289
+ "sleep",
567290
+ "cd",
567291
+ "diff",
567292
+ "cmp",
567293
+ "md5sum",
567294
+ "sha1sum",
567295
+ "sha256sum",
567296
+ "du",
567297
+ "df",
567298
+ "nl",
567299
+ "paste",
567300
+ "join",
567301
+ "comm",
567302
+ "expand",
567303
+ "unexpand",
567304
+ "fold",
567305
+ "rev",
567306
+ "seq",
567307
+ "xargs"
567308
+ ]);
567309
+ STAGE_PREFIX_PROGRAMS = /* @__PURE__ */ new Set([
567310
+ "sudo",
567311
+ "command",
567312
+ "builtin",
567313
+ "nice",
567314
+ "ionice",
567315
+ "time",
567316
+ "timeout",
567317
+ "nohup",
567318
+ "stdbuf",
567319
+ "unbuffer"
567320
+ ]);
567147
567321
  }
567148
567322
  });
567149
567323
 
@@ -569322,11 +569496,6 @@ var init_personality = __esm({
569322
569496
  // packages/orchestrator/dist/critic.js
569323
569497
  function buildCriticGuidanceMessage(call, hits, opts = {}) {
569324
569498
  const argPreview = JSON.stringify(call.args ?? {}).slice(0, 200);
569325
- const actionReason = call.actionReason ? [
569326
- call.actionReason.scope ? `scope=${call.actionReason.scope}` : "",
569327
- call.actionReason.intent ? `intent=${call.actionReason.intent}` : "",
569328
- call.actionReason.evidence ? `evidence=${call.actionReason.evidence}` : ""
569329
- ].filter(Boolean).join("; ").slice(0, 500) : "";
569330
569499
  const cached = opts.cachedResult ? `
569331
569500
  Prior evidence preview:
569332
569501
  ${opts.cachedResult.slice(0, 700)}` : "";
@@ -569334,8 +569503,7 @@ ${opts.cachedResult.slice(0, 700)}` : "";
569334
569503
  return `[RUNTIME EVIDENCE CACHE — non-blocking]
569335
569504
  Observation: ${source}
569336
569505
  Call: ${call.tool}(${argPreview})
569337
- ` + (actionReason ? `Action reason: ${actionReason}
569338
- ` : "") + `State: exact prior evidence exists for these arguments in the current state version.
569506
+ State: exact prior evidence exists for these arguments in the current state version.
569339
569507
  Next action contract: let this result inform the next step once, then pivot to a concrete action.
569340
569508
  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}`;
569341
569509
  }
@@ -569344,10 +569512,13 @@ function buildCachedResultEnvelope(result) {
569344
569512
  ${result}`;
569345
569513
  }
569346
569514
  function evaluate2(inputs) {
569347
- const { proposedCall, fingerprint, isReadLike, recentToolResults, dedupHitCount, adversaryRedundantSignal } = inputs;
569348
- if (adversaryRedundantSignal) {
569515
+ const { proposedCall, fingerprint, recentToolResults, dedupHitCount, adversaryRedundantSignal } = inputs;
569516
+ const cacheEligible = proposedCall.tool === "memory_write" || NOOP_WRITE_CACHE_TOOLS.has(proposedCall.tool);
569517
+ if (adversaryRedundantSignal && cacheEligible) {
569349
569518
  const cached = recentToolResults.get(fingerprint);
569350
- const cachedResult = cached ? buildCachedResultEnvelope(cached.result) : void 0;
569519
+ if (!cached)
569520
+ return { decision: "pass" };
569521
+ const cachedResult = buildCachedResultEnvelope(cached.result);
569351
569522
  return {
569352
569523
  decision: "guidance",
569353
569524
  reason: "Adversary flagged this fingerprint as redundant",
@@ -569360,7 +569531,6 @@ function evaluate2(inputs) {
569360
569531
  compacted: cached?.compacted
569361
569532
  };
569362
569533
  }
569363
- const cacheEligible = isReadLike || proposedCall.tool === "shell" || proposedCall.tool === "memory_write" || NOOP_WRITE_CACHE_TOOLS.has(proposedCall.tool);
569364
569534
  if (cacheEligible) {
569365
569535
  const cached = recentToolResults.get(fingerprint);
569366
569536
  if (cached !== void 0) {
@@ -573004,13 +573174,13 @@ var init_reflectionBuffer = __esm({
573004
573174
  case "tool_misuse":
573005
573175
  return {
573006
573176
  whatFailed: `Wrong tool or arguments for the task. Tool ${lastFailedTool?.tool ?? "unknown"} failed: ${lastFailedTool?.error?.slice(0, 60) ?? lastError.slice(0, 60)}`,
573007
- whatToDoDifferently: `Try a different tool. If file_edit failed, try file_write. If shell failed with a complex command, break it into simpler steps. Read the file first before editing.`,
573177
+ whatToDoDifferently: `Correct the tool contract without broadening mutation scope. If file_edit failed, read the current target and use exact text or a line-range file_patch; do not fall back to file_write. If shell failed with a complex command, break it into simpler diagnostic steps.`,
573008
573178
  confidence: 0.8
573009
573179
  };
573010
573180
  case "repetition":
573011
573181
  return {
573012
573182
  whatFailed: `Got stuck in a loop after ${turnsSpent} turns trying ${failedApproaches.length} approaches. The same tools kept failing with similar errors.`,
573013
- whatToDoDifferently: "Stop and try a completely different strategy. If you were editing, try rewriting from scratch. If searching failed, try a broader or narrower query. Ask yourself: what assumption am I making that might be wrong?",
573183
+ whatToDoDifferently: "Stop and change the diagnosis, not the mutation radius. If you were editing, refresh the implicated range and patch only the verified fault; never rewrite an existing file from scratch as loop recovery. If searching failed, try a broader or narrower query. Ask which assumption is wrong.",
573014
573184
  confidence: 0.9
573015
573185
  };
573016
573186
  case "timeout":
@@ -576293,9 +576463,6 @@ function classifyFailureKind(text2, args) {
576293
576463
  }
576294
576464
  if (/Unknown tool\b|Unknown tool ['"`]/i.test(text2))
576295
576465
  return "missing_tool";
576296
- if (/\[TOOL ACTION REASON CONTRACT\]|must include action_reason|action_reason must/i.test(text2)) {
576297
- return "action_reason_missing";
576298
- }
576299
576466
  if (/\bexpected_hash\b|hash mismatch|fresh file_read|stale edit|stale target|FULL FILE REWRITE CONTRACT|old_string (?:not found|does not match|must be unique|appears \d+)/i.test(text2)) {
576300
576467
  return "stale_hash";
576301
576468
  }
@@ -576536,16 +576703,6 @@ var init_failure_taxonomy = __esm({
576536
576703
  ],
576537
576704
  createRecoveryCard: true
576538
576705
  },
576539
- action_reason_missing: {
576540
- severity: "warning",
576541
- retryable: true,
576542
- guidance: "A side-effectful tool call lacked the required public action_reason envelope. Retry only with compact task-state metadata, or use a read-only/control-plane tool if no mutation is intended.",
576543
- workboardEvidenceRequirements: [
576544
- "corrected action_reason envelope",
576545
- "same intended operation through the right tool"
576546
- ],
576547
- createRecoveryCard: false
576548
- },
576549
576706
  workboard_noop: {
576550
576707
  severity: "warning",
576551
576708
  retryable: true,
@@ -577277,7 +577434,7 @@ var init_context_fabric = __esm({
577277
577434
  const header = [
577278
577435
  "[ACTIVE CONTEXT FRAME]",
577279
577436
  options2.turn !== void 0 ? `turn: ${options2.turn}` : null,
577280
- "Scope: runtime state for the next action. Treat this as the single merged context intake; do not re-read or re-emit it unless state changes."
577437
+ "Scope: runtime state for the next action. Do not quote or re-emit this frame. Prior evidence is orientation; execute a narrow file_read or the declared verifier whenever current text/hash or post-mutation proof is required."
577281
577438
  ].filter(Boolean);
577282
577439
  let content = [...header, "", ...sectionLines].join("\n").trim();
577283
577440
  const controlChars = included.filter(isControlSignal).reduce((sum2, signal) => sum2 + signal.content.length, 0);
@@ -577471,7 +577628,7 @@ function retireDuplicateToolFailures(messages2) {
577471
577628
  }
577472
577629
  out[index] = {
577473
577630
  ...message2,
577474
- content: "[retired_duplicate_tool_failure] newer matching result appears later; do not repeat the same call."
577631
+ content: "[retired_duplicate_tool_failure] a newer matching failure appears later. Use that latest diagnostic; retry only after refreshing prerequisite evidence or correcting the arguments."
577475
577632
  };
577476
577633
  }
577477
577634
  return out;
@@ -577777,8 +577934,8 @@ var init_evidenceLedger = __esm({
577777
577934
  return null;
577778
577935
  const sorted = [...this.entries.values()].sort((a2, b) => b.lastReadTurn - a2.lastReadTurn);
577779
577936
  const lines = [
577780
- "Evidence already gathered this run you ALREADY have the content below.",
577781
- "Do NOT re-read a FRESH file; use this. Re-read ONLY entries marked STALE.",
577937
+ "Earlier file evidence from this run is shown below for orientation.",
577938
+ "Use a displayed full-fidelity snapshot when it is sufficient, but file_read is allowed and required when an edit/hash guard asks for current text, a displayed body is elided, or external state may have changed.",
577782
577939
  ""
577783
577940
  ];
577784
577941
  let used = lines.join("\n").length;
@@ -578253,8 +578410,6 @@ ${obs.stateDigest.slice(0, 1800)}
578253
578410
  `This is a loop. Reason about WHY — for THIS specific call, not generically.`,
578254
578411
  ls2.alreadyHave ? `Evidence the agent ALREADY obtained from a prior identical call:
578255
578412
  ${ls2.alreadyHave.slice(0, 900)}` : `(No cached result available for the repeated call.)`,
578256
- ls2.actionReason ? `Agent's stated action reason:
578257
- scope=${ls2.actionReason.scope ?? ""}; intent=${ls2.actionReason.intent ?? ""}; evidence=${ls2.actionReason.evidence ?? ""}; expected=${ls2.actionReason.expected_result ?? ""}`.slice(0, 700) : "",
578258
578413
  "",
578259
578414
  stateDigest.trim(),
578260
578415
  "",
@@ -578658,7 +578813,6 @@ function recordDebugToolEvent(input) {
578658
578813
  },
578659
578814
  ...input.focusSupervisor ? { focusSupervisor: input.focusSupervisor } : {},
578660
578815
  ...input.focusDecision ? { focusDecision: input.focusDecision } : {},
578661
- ...input.actionReason ? { actionReason: compactDebugValue(input.actionReason) } : {},
578662
578816
  ...input.repeatShortCircuit !== void 0 ? { repeatShortCircuit: input.repeatShortCircuit } : {},
578663
578817
  ...input.runtimeAuthored !== void 0 ? { runtimeAuthored: input.runtimeAuthored } : {},
578664
578818
  ...input.runtimeGuidance ? { runtimeGuidancePreview: trim(input.runtimeGuidance, 1200) } : {},
@@ -579347,30 +579501,6 @@ function trim(value2, max) {
579347
579501
  return `${value2.slice(0, max)}
579348
579502
  [truncated ${value2.length - max} chars]`;
579349
579503
  }
579350
- function compactDebugValue(value2, depth = 0) {
579351
- if (value2 == null)
579352
- return value2;
579353
- if (typeof value2 === "string") {
579354
- return value2.length > 500 ? `${value2.slice(0, 497)}...` : value2;
579355
- }
579356
- if (typeof value2 === "number" || typeof value2 === "boolean")
579357
- return value2;
579358
- if (Array.isArray(value2)) {
579359
- if (depth >= 2)
579360
- return `[array:${value2.length}]`;
579361
- return value2.slice(0, 8).map((entry) => compactDebugValue(entry, depth + 1));
579362
- }
579363
- if (typeof value2 === "object") {
579364
- if (depth >= 2)
579365
- return "[object]";
579366
- const out = {};
579367
- for (const [key, entry] of Object.entries(value2).slice(0, 12)) {
579368
- out[key] = compactDebugValue(entry, depth + 1);
579369
- }
579370
- return out;
579371
- }
579372
- return String(value2);
579373
- }
579374
579504
  function safeId2(value2) {
579375
579505
  return String(value2 || "unknown").replace(/[^a-zA-Z0-9_.:-]/g, "_").slice(0, 160);
579376
579506
  }
@@ -579554,17 +579684,6 @@ function meaningfulCachedEvidencePreview(text2) {
579554
579684
  }
579555
579685
  return preview.join(" | ").slice(0, 700);
579556
579686
  }
579557
- function actionReasonSummary(actionReason) {
579558
- if (!actionReason)
579559
- return "";
579560
- const parts = [
579561
- actionReason.scope ? `scope=${actionReason.scope}` : "",
579562
- actionReason.intent ? `intent=${actionReason.intent}` : "",
579563
- actionReason.evidence ? `evidence=${actionReason.evidence}` : "",
579564
- actionReason.expected_result ? `expected=${actionReason.expected_result}` : ""
579565
- ].filter(Boolean);
579566
- return parts.length > 0 ? `Action reason observed: ${parts.join("; ").slice(0, 700)}` : "";
579567
- }
579568
579687
  function normalizeShellForFamily(command, cwd4) {
579569
579688
  let s2 = String(command || "").replace(/\\\r?\n/g, " ").replace(/\s+/g, " ").trim();
579570
579689
  if (cwd4 && cwd4.length > 1) {
@@ -579875,7 +579994,6 @@ var init_focusSupervisor = __esm({
579875
579994
  `${reason}.`,
579876
579995
  `Required next action: ${prior.requiredNextAction}.`,
579877
579996
  `Blocked action family: ${family}.`,
579878
- actionReasonSummary(input.actionReason),
579879
579997
  "This block is not counted as a new ignored directive."
579880
579998
  ].filter(Boolean).join("\n"), false);
579881
579999
  }
@@ -579902,7 +580020,6 @@ var init_focusSupervisor = __esm({
579902
580020
  "[FOCUS SUPERVISOR BLOCK: LOOP CONTROL]",
579903
580021
  `Directive ${prior.id} was repeatedly ignored with ${family}.`,
579904
580022
  `Required next action: ${directive.requiredNextAction}.`,
579905
- actionReasonSummary(input.actionReason),
579906
580023
  "Stop trying this action-family repeatedly. Pivot to a materially different approach or web_search the blocker, then continue."
579907
580024
  ].filter(Boolean).join("\n"), false);
579908
580025
  }
@@ -579942,7 +580059,6 @@ var init_focusSupervisor = __esm({
579942
580059
  `[FOCUS SUPERVISOR BLOCK] The previous directive was ignored: ${prior.reason}`,
579943
580060
  `Required next action: ${directive.requiredNextAction}.`,
579944
580061
  `Blocked action family: ${family}.`,
579945
- actionReasonSummary(input.actionReason),
579946
580062
  directive.requiredNextAction === "creative_pivot_or_research" ? "Stop trying variants of what failed. The task is NOT over — pivot to a fundamentally different approach or web_search the exact blocker, then act." : "Take the required next action before trying another variant."
579947
580063
  ].filter(Boolean).join("\n"), false);
579948
580064
  }
@@ -579958,7 +580074,6 @@ var init_focusSupervisor = __esm({
579958
580074
  return this.block(directive, [
579959
580075
  input.stalePreflightMessage,
579960
580076
  "",
579961
- actionReasonSummary(input.actionReason),
579962
580077
  "[FOCUS SUPERVISOR] Required next action: file_read the authoritative current target once, then build a new edit from current evidence or report incomplete."
579963
580078
  ].filter(Boolean).join("\n"), false);
579964
580079
  }
@@ -579980,7 +580095,6 @@ var init_focusSupervisor = __esm({
579980
580095
  input.cachedResultFailed ? "[FOCUS SUPERVISOR: CACHED FAILURE]" : "[FOCUS SUPERVISOR: CACHED EVIDENCE]",
579981
580096
  `This ${input.toolName} action family has already produced evidence and should not be re-executed unchanged.`,
579982
580097
  `Required next action: ${directive.requiredNextAction}.`,
579983
- actionReasonSummary(input.actionReason),
579984
580098
  "",
579985
580099
  compactCachedEvidence(input.cachedResult)
579986
580100
  ].filter(Boolean).join("\n"), !input.cachedResultFailed);
@@ -585241,9 +585355,6 @@ import { join as _pathJoin, relative as _pathRelative, resolve as _pathResolve }
585241
585355
  import { tmpdir as _osTmpdir } from "node:os";
585242
585356
  import { homedir as _osHomedir } from "node:os";
585243
585357
  import { z as z17 } from "zod";
585244
- function cleanToolActionReasonField(value2) {
585245
- return String(value2 ?? "").replace(/\s+/g, " ").trim();
585246
- }
585247
585358
  function stripShellQuotedSegments(command) {
585248
585359
  let out = "";
585249
585360
  let quote2 = null;
@@ -585982,7 +586093,7 @@ function classifyThinkOutcome(raw) {
585982
586093
  }
585983
586094
  return null;
585984
586095
  }
585985
- var TOOL_SUBSETS, TOOL_AUTO_DEMOTE_TURNS, TOOL_ACTION_REASON_KEYS, TOOL_ACTION_REASON_SCOPES, READ_ONLY_ACTION_REASON_OPTIONAL_TOOLS, STATE_UPDATE_ACTION_REASON_SYNTHESIS_TOOLS, TOOL_ACTION_REASON_SCHEMA, SYSTEM_PROMPT, SYSTEM_PROMPT_MEDIUM, SYSTEM_PROMPT_SMALL, VISUAL_TOOLS, AUDIO_TOOLS, SOCIAL_TOOLS, SPATIAL_TOOLS, CODE_TOOLS, AgenticRunner, OllamaAgenticBackend;
586096
+ var TOOL_SUBSETS, TOOL_AUTO_DEMOTE_TURNS, LEGACY_ACTION_REASON_KEYS, SYSTEM_PROMPT, SYSTEM_PROMPT_MEDIUM, SYSTEM_PROMPT_SMALL, VISUAL_TOOLS, AUDIO_TOOLS, SOCIAL_TOOLS, SPATIAL_TOOLS, CODE_TOOLS, AgenticRunner, OllamaAgenticBackend;
585986
586097
  var init_agenticRunner = __esm({
585987
586098
  "packages/orchestrator/dist/agenticRunner.js"() {
585988
586099
  "use strict";
@@ -586080,75 +586191,7 @@ var init_agenticRunner = __esm({
586080
586191
  skill: ["skill_list", "skill_extract", "skill_execute", "skill_search"]
586081
586192
  };
586082
586193
  TOOL_AUTO_DEMOTE_TURNS = 10;
586083
- TOOL_ACTION_REASON_KEYS = /* @__PURE__ */ new Set([
586084
- "action_reason",
586085
- "actionReason",
586086
- "justification"
586087
- ]);
586088
- TOOL_ACTION_REASON_SCOPES = /* @__PURE__ */ new Set([
586089
- "discovery",
586090
- "targeted_patch",
586091
- "new_file",
586092
- "full_file_rewrite",
586093
- "verification",
586094
- "state_update",
586095
- "delegation",
586096
- "completion",
586097
- "other"
586098
- ]);
586099
- READ_ONLY_ACTION_REASON_OPTIONAL_TOOLS = /* @__PURE__ */ new Set([
586100
- "file_read",
586101
- "file_explore",
586102
- "list_directory",
586103
- "grep_search",
586104
- "grep",
586105
- "glob_find",
586106
- "find_files",
586107
- "todo_read",
586108
- "memory_read",
586109
- "memory_search",
586110
- "semantic_map",
586111
- "code_graph",
586112
- "graph_query",
586113
- "graph_traverse",
586114
- "web_search",
586115
- "web_fetch",
586116
- "tool_search",
586117
- "task_status",
586118
- "task_output"
586119
- ]);
586120
- STATE_UPDATE_ACTION_REASON_SYNTHESIS_TOOLS = /* @__PURE__ */ new Set([
586121
- "todo_write",
586122
- "working_notes"
586123
- ]);
586124
- TOOL_ACTION_REASON_SCHEMA = {
586125
- type: "object",
586126
- description: "Compact public action contract for this exact tool call. Do not include hidden chain-of-thought; use concise task-state facts.",
586127
- properties: {
586128
- task_anchor: {
586129
- type: "string",
586130
- description: "One compact phrase tying this call to the active user goal/current focus."
586131
- },
586132
- intent: {
586133
- type: "string",
586134
- description: "One sentence explaining why this tool is the next action."
586135
- },
586136
- evidence: {
586137
- type: "string",
586138
- description: "Fresh evidence or contract authorizing the action: file hash, focus directive, cached evidence, user request, or explicit absence."
586139
- },
586140
- expected_result: {
586141
- type: "string",
586142
- description: "The concrete new state or information expected from this call."
586143
- },
586144
- scope: {
586145
- type: "string",
586146
- enum: Array.from(TOOL_ACTION_REASON_SCOPES),
586147
- description: "Classify the action scope. Use targeted_patch for constrained edits; full_file_rewrite only for deliberate whole-file replacement."
586148
- }
586149
- },
586150
- required: ["task_anchor", "intent", "evidence", "expected_result", "scope"]
586151
- };
586194
+ LEGACY_ACTION_REASON_KEYS = /* @__PURE__ */ new Set(["action_reason", "actionReason"]);
586152
586195
  SYSTEM_PROMPT = loadPrompt("agentic/system-large.md");
586153
586196
  SYSTEM_PROMPT_MEDIUM = loadPrompt("agentic/system-medium.md");
586154
586197
  SYSTEM_PROMPT_SMALL = loadPrompt("agentic/system-small.md");
@@ -587365,10 +587408,8 @@ ${parts.join("\n")}
587365
587408
  if (ts.failedApproaches.length > 0) {
587366
587409
  lines.push(`recent_failed_approaches=${ts.failedApproaches.slice(-3).join(" | ").replace(/\s+/g, " ").slice(0, 420)}`);
587367
587410
  }
587368
- lines.push("tool_call_contract=Mutating/side-effectful tool calls require action_reason {task_anchor,intent,evidence,expected_result,scope}; read-only evidence tools may include it but must never be blocked only for missing metadata. Compact public facts only, no hidden chain-of-thought.");
587369
587411
  lines.push("edit_transport_contract=file_edit is for exact unique current text copied from file_read; file_patch is for line-range delete/replace/insert using file_read line numbers and expected_hash/current target evidence. A failed file_edit invalidates the edit premise; rebuild from current evidence instead of broadening into file_write unless the task is truly whole-file replacement.");
587370
587412
  lines.push("range_patch_contract=If patch_ready=true or current path+start_line+end_line+expected_hash are known, call file_patch. If read_required=true or a stale exact edit lacks current range/hash, call file_read once. Do not call file_read when patch_ready=true.");
587371
- 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.`);
587372
587413
  const gitContract = renderGitProgressActionContract(this._gitProgress);
587373
587414
  if (gitContract)
587374
587415
  lines.push(gitContract);
@@ -588238,7 +588279,8 @@ Emit AT MOST 6 tool calls per response. Smaller batches receive better feedback
588238
588279
  };
588239
588280
  const batchGuidance = _BATCH_GUIDANCE[this.options.modelTier ?? "large"] ?? _BATCH_GUIDANCE.large;
588240
588281
  const shellGuidance = "\n\n## Shell command patterns\n\nWhen investigating a build/test/install failure, RUN THE COMMAND WITHOUT TRUNCATION FIRST to see the full error.\nAvoid `| tail -N` / `| head -N` / `| sed -n '1,Np'` on commands you don't yet trust — they drop the part of the output where errors usually appear.\nPipefail is on by default in this orchestrator: a pipeline's exit code reflects the FIRST failing stage, not just the last. So `<cmd> | tail -80` returns non-zero if `<cmd>` failed.\nWhen you DO want to limit context (after diagnosis), prefer `<cmd> 2>&1 | tail -300` (or larger) so you keep enough output to see the actual error block.\nIf your command exited 0 but produced suspiciously short output (~< 800 chars), the orchestrator will inject a [HINT — pipe-to-truncator detected] block telling you to re-run without truncation.";
588241
- const basePromptWithBatching = basePrompt + batchGuidance + shellGuidance;
588282
+ const editTransportGuidance = "\n\n## Existing-file edit loop\n\nFor an existing non-trivial file, use this loop: (1) file_read the implicated range or whole small file, (2) file_patch a contiguous line range or file_edit exact current text, (3) inspect the resulting diff/changed range, and (4) run the declared verifier live. Use batch_edit only for multiple exact replacements built from one fresh read.\nfile_write is for new files, empty/placeholder files, and deliberate replacement of a genuinely small file. Never use file_write as a fallback for stale hashes, old_string mismatches, malformed patch arguments, or repeated edit failures. A 'different approach' means refresh evidence or change the diagnostic/patch shape; it does not mean broaden a local repair into a whole-file rewrite.\nPreviously observed or compacted results are orientation only. Re-run file_read whenever a freshness/hash guard asks for current text, and re-run the exact verifier after every relevant mutation; cached output never proves current file state or completion.";
588283
+ const basePromptWithBatching = basePrompt + batchGuidance + shellGuidance + editTransportGuidance;
588242
588284
  sections.push({
588243
588285
  label: "c_instr",
588244
588286
  content: basePromptWithBatching,
@@ -589415,8 +589457,9 @@ Pick the SMALLEST concrete deliverable from the spec — typically the project e
589415
589457
  return this._declaredVerifierCommand;
589416
589458
  }
589417
589459
  const diagnostics = parseCompilerDiagnostics(output);
589418
- if (diagnostics.length > 0 && this._shellResultLooksLikeVerification({ command: trimmed }, { success: false, output })) {
589419
- return trimmed;
589460
+ if (diagnostics.length > 0 && !commandIsPureReadOnlyPipeline(trimmed)) {
589461
+ const latched = stripVerifierFallbackSuffix(trimmed);
589462
+ return latched || trimmed;
589420
589463
  }
589421
589464
  return null;
589422
589465
  }
@@ -589426,19 +589469,68 @@ Pick the SMALLEST concrete deliverable from the spec — typically the project e
589426
589469
  return false;
589427
589470
  return commandReliablySatisfiesVerifyCommand(command.trim(), state.verifierCommand);
589428
589471
  }
589472
+ /**
589473
+ * When a tool result was triaged for size (full payload saved to
589474
+ * `.omnius/tool-results/<hash>.txt`), append the saved payload so
589475
+ * diagnostics parsing sees the complete output. Without this, a large
589476
+ * failed build's `file:line:col: error:` lines can be cut out of the
589477
+ * triage envelope and the run never registers as a verifier run.
589478
+ * Best effort and bounded — never throws into the loop.
589479
+ */
589480
+ _expandTriagedPayloadForDiagnostics(text2) {
589481
+ if (!text2 || !text2.includes(TRIAGE_SAVED_PATH_MARKER))
589482
+ return text2;
589483
+ const MAX_PAYLOAD_BYTES = 1e6;
589484
+ const MAX_FILES2 = 2;
589485
+ const extras = [];
589486
+ let searchFrom = 0;
589487
+ for (let i2 = 0; i2 < MAX_FILES2; i2++) {
589488
+ const markerAt = text2.indexOf(TRIAGE_SAVED_PATH_MARKER, searchFrom);
589489
+ if (markerAt === -1)
589490
+ break;
589491
+ const pathStart = markerAt + TRIAGE_SAVED_PATH_MARKER.length;
589492
+ const restOfLine = text2.slice(pathStart, text2.indexOf("\n", pathStart) === -1 ? void 0 : text2.indexOf("\n", pathStart));
589493
+ searchFrom = pathStart;
589494
+ const endIdx = (() => {
589495
+ const emDash = restOfLine.indexOf(" — ");
589496
+ if (emDash !== -1)
589497
+ return emDash;
589498
+ const bracket = restOfLine.indexOf("]");
589499
+ return bracket !== -1 ? bracket : restOfLine.length;
589500
+ })();
589501
+ const savedPath = restOfLine.slice(0, endIdx).trim();
589502
+ if (!savedPath)
589503
+ continue;
589504
+ try {
589505
+ if (!_fsExistsSync(savedPath))
589506
+ continue;
589507
+ const stat9 = _fsStatSync(savedPath);
589508
+ if (!stat9.isFile())
589509
+ continue;
589510
+ const raw = _fsReadFileSync(savedPath, "utf8");
589511
+ extras.push(raw.length > MAX_PAYLOAD_BYTES ? raw.slice(0, MAX_PAYLOAD_BYTES) : raw);
589512
+ } catch {
589513
+ }
589514
+ }
589515
+ if (extras.length === 0)
589516
+ return text2;
589517
+ return `${text2}
589518
+ ${extras.join("\n")}`;
589519
+ }
589429
589520
  _observeCompileVerifierResult(input) {
589430
589521
  const diagnostics = rankCompilerDiagnostics(parseCompilerDiagnostics(input.output));
589522
+ const verifierCommand = stripVerifierFallbackSuffix(input.verifierCommand) || input.verifierCommand.trim();
589431
589523
  const previousDiagnostics = this._lastDeclaredVerifierDiagnostics;
589432
- this._declaredVerifierCommand = input.verifierCommand;
589524
+ this._declaredVerifierCommand = verifierCommand;
589433
589525
  this._lastDeclaredVerifierOutput = input.output;
589434
589526
  this._lastDeclaredVerifierDiagnostics = diagnostics;
589435
589527
  if (!this._compileFixLoop && diagnostics.length === 0)
589436
589528
  return null;
589437
- const verifierFingerprint = compileFixVerifierFingerprint(input.verifierCommand);
589529
+ const verifierFingerprint = compileFixVerifierFingerprint(verifierCommand);
589438
589530
  const existingCards = this._compileFixLoop?.cards ?? [];
589439
589531
  const cards = diagnostics.length > 0 ? buildCompileFixCards({
589440
589532
  diagnostics,
589441
- verifierCommand: input.verifierCommand,
589533
+ verifierCommand,
589442
589534
  turn: input.turn,
589443
589535
  existingCards
589444
589536
  }) : existingCards;
@@ -589447,22 +589539,25 @@ Pick the SMALLEST concrete deliverable from the spec — typically the project e
589447
589539
  existingCards,
589448
589540
  observedCards: cards,
589449
589541
  diagnostics,
589450
- verifierCommand: input.verifierCommand,
589542
+ verifierCommand,
589451
589543
  turn: input.turn,
589452
589544
  verifierPassed: input.success && diagnostics.length === 0
589453
589545
  });
589454
589546
  this._compileFixLoop = {
589455
589547
  active: diagnostics.length > 0 || nextCards.some((card) => card.status !== "verified"),
589456
- verifierCommand: input.verifierCommand,
589548
+ verifierCommand,
589457
589549
  verifierFingerprint,
589458
589550
  verifierDirtySinceTurn: null,
589459
589551
  lastVerifierRunTurn: input.turn,
589460
589552
  lastVerifierPassedTurn: input.success && diagnostics.length === 0 ? input.turn : null,
589461
589553
  lastMutationTurn: this._compileFixLoop?.lastMutationTurn ?? null,
589462
- cards: nextCards
589554
+ cards: nextCards,
589555
+ // A live verifier run resolves the gate's demand — the block streak
589556
+ // is over regardless of pass/fail.
589557
+ preflightBlockStreak: 0
589463
589558
  };
589464
589559
  this._mirrorCompileFixCardsToWorkboard(nextCards, {
589465
- command: input.verifierCommand,
589560
+ command: verifierCommand,
589466
589561
  success: input.success && diagnostics.length === 0,
589467
589562
  turn: input.turn,
589468
589563
  beforeDiagnosticCount: previousDiagnostics.length,
@@ -589474,7 +589569,7 @@ Pick the SMALLEST concrete deliverable from the spec — typically the project e
589474
589569
  if (input.success && diagnostics.length === 0) {
589475
589570
  this.emit({
589476
589571
  type: "status",
589477
- content: `compile_error_fix_loop: verifier passed (${input.verifierCommand}); compile cards verified`,
589572
+ content: `compile_error_fix_loop: verifier passed (${verifierCommand}); compile cards verified`,
589478
589573
  turn: input.turn,
589479
589574
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
589480
589575
  });
@@ -589493,7 +589588,7 @@ Pick the SMALLEST concrete deliverable from the spec — typically the project e
589493
589588
  }
589494
589589
  this.emit({
589495
589590
  type: "status",
589496
- content: `compile_error_fix_loop_started: verifierCommand=${input.verifierCommand}; cardId=${top.id}; diagnosticFingerprint=${top.diagnostic.fingerprint}; afterDiagnosticCount=${diagnostics.length}`,
589591
+ content: `compile_error_fix_loop_started: verifierCommand=${verifierCommand}; cardId=${top.id}; diagnosticFingerprint=${top.diagnostic.fingerprint}; afterDiagnosticCount=${diagnostics.length}`,
589497
589592
  turn: input.turn,
589498
589593
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
589499
589594
  });
@@ -589693,14 +589788,7 @@ Pick the SMALLEST concrete deliverable from the spec — typically the project e
589693
589788
  if (!state?.active)
589694
589789
  return;
589695
589790
  const normalized = paths.map((p2) => this._normalizeEvidencePath(p2)).filter(Boolean);
589696
- const owned = state.cards.flatMap((card) => card.ownedFiles);
589697
- const todos = this.readSessionTodos() || [];
589698
- const artifacts = todos.flatMap((todo) => Array.isArray(todo.declaredArtifacts) ? todo.declaredArtifacts.filter((p2) => typeof p2 === "string") : []);
589699
- const relevant = normalized.length === 0 || normalized.some((pathValue) => {
589700
- if (pathValue.startsWith(".omnius/"))
589701
- return false;
589702
- return owned.some((ownedPath) => this._pathsOverlapForVerifier(pathValue, ownedPath)) || artifacts.some((artifactPath) => this._pathsOverlapForVerifier(pathValue, artifactPath)) || /\.(ts|tsx|js|jsx|mjs|cjs|py|go|rs|java|kt|c|cc|cpp|cxx|h|hpp|hh|hxx|ino)$/i.test(pathValue);
589703
- });
589791
+ const relevant = normalized.length === 0 || this._compileFixPathsTouchProjectSources(normalized, state);
589704
589792
  if (!relevant)
589705
589793
  return;
589706
589794
  state.verifierDirtySinceTurn = turn;
@@ -589727,6 +589815,24 @@ Pick the SMALLEST concrete deliverable from the spec — typically the project e
589727
589815
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
589728
589816
  });
589729
589817
  }
589818
+ /**
589819
+ * True when any of the given normalized paths touches project source:
589820
+ * files owned by compile-fix cards, declared todo artifacts, or files
589821
+ * with a source-code extension. Build side effects (logs, artifacts,
589822
+ * `.omnius/` bookkeeping) do not count.
589823
+ */
589824
+ _compileFixPathsTouchProjectSources(normalizedPaths, state) {
589825
+ const owned = state.cards.flatMap((card) => card.ownedFiles);
589826
+ const todos = this.readSessionTodos() || [];
589827
+ const artifacts = todos.flatMap((todo) => Array.isArray(todo.declaredArtifacts) ? todo.declaredArtifacts.filter((p2) => typeof p2 === "string") : []);
589828
+ return normalizedPaths.some((pathValue) => {
589829
+ if (pathValue.startsWith(".omnius/"))
589830
+ return false;
589831
+ return owned.some((ownedPath) => this._pathsOverlapForVerifier(pathValue, ownedPath)) || artifacts.some((artifactPath) => this._pathsOverlapForVerifier(pathValue, artifactPath)) || /\.(ts|tsx|js|jsx|mjs|cjs|py|go|rs|java|kt|c|cc|cpp|cxx|h|hpp|hh|hxx|ino)$/i.test(pathValue);
589832
+ });
589833
+ }
589834
+ /** Consecutive preflight blocks before the gate yields instead of blocking. */
589835
+ static COMPILE_FIX_GATE_YIELD_AFTER = 3;
589730
589836
  _compileFixLoopPreflightBlock(toolName, args, turn, shellLikelyMutatesFilesystem) {
589731
589837
  const state = this._compileFixLoop;
589732
589838
  if (!state?.active)
@@ -589737,29 +589843,62 @@ Pick the SMALLEST concrete deliverable from the spec — typically the project e
589737
589843
  if (toolName === "shell") {
589738
589844
  const command = String(args["command"] ?? args["cmd"] ?? "").trim();
589739
589845
  if (commandReliablySatisfiesVerifyCommand(command, state.verifierCommand)) {
589846
+ state.preflightBlockStreak = 0;
589740
589847
  return null;
589741
589848
  }
589742
589849
  if (!shellLikelyMutatesFilesystem)
589743
589850
  return null;
589851
+ const extraction = extractShellMutationPaths(command, {
589852
+ workingDir: this.authoritativeWorkingDirectory()
589853
+ });
589854
+ const mutationPaths = extraction.paths.map((p2) => this._normalizeEvidencePath(p2)).filter(Boolean);
589855
+ if (mutationPaths.length === 0 || !this._compileFixPathsTouchProjectSources(mutationPaths, state)) {
589856
+ return null;
589857
+ }
589744
589858
  } else if (!this._isProjectEditTool(toolName)) {
589745
589859
  return null;
589746
589860
  }
589861
+ const yieldAfter = _AgenticRunner.COMPILE_FIX_GATE_YIELD_AFTER;
589862
+ const streak = (state.preflightBlockStreak ?? 0) + 1;
589863
+ if (streak > yieldAfter) {
589864
+ state.preflightBlockStreak = 0;
589865
+ this.emit({
589866
+ type: "status",
589867
+ content: `compile_error_verifier_dirty: gate yielded to ${toolName} after ${yieldAfter} consecutive blocks at turn ${turn}`,
589868
+ turn,
589869
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
589870
+ });
589871
+ return {
589872
+ kind: "yield",
589873
+ notice: [
589874
+ `[COMPILE FIX GATE YIELDED — verifier still required]`,
589875
+ `The verifier-required gate blocked ${yieldAfter} consecutive tool calls and is yielding so work can continue.`,
589876
+ `Verifier evidence is still stale. Run the verifier as your next evidence step:`,
589877
+ ` ${state.verifierCommand}`,
589878
+ `Any real build/test command whose output shows current compiler diagnostics is also accepted as the live verifier.`,
589879
+ `task_complete remains blocked until a verifier run passes after the last mutation.`
589880
+ ].join("\n")
589881
+ };
589882
+ }
589883
+ state.preflightBlockStreak = streak;
589747
589884
  const message2 = [
589748
589885
  `[COMPILE ERROR FIX LOOP BLOCKED — declared verifier required]`,
589749
589886
  `A compile-fix card was patched, so the next mutation/evidence step must be the live verifier.`,
589750
- `verifierCommand: ${state.verifierCommand}`,
589887
+ `Run this now: ${state.verifierCommand}`,
589888
+ `Any real build/test command whose output shows current compiler diagnostics is also accepted.`,
589751
589889
  `dirtySinceTurn: ${state.verifierDirtySinceTurn}`,
589752
589890
  `lastMutationTurn: ${state.lastMutationTurn}`,
589753
589891
  `lastVerifierRunTurn: ${state.lastVerifierRunTurn}`,
589754
- `blockedTool: ${toolName}`
589892
+ `blockedTool: ${toolName}`,
589893
+ `consecutiveBlocks: ${streak}/${yieldAfter} (gate yields after ${yieldAfter})`
589755
589894
  ].join("\n");
589756
589895
  this.emit({
589757
589896
  type: "status",
589758
- content: `compile_error_verifier_dirty: blocked ${toolName} at turn ${turn}`,
589897
+ content: `compile_error_verifier_dirty: blocked ${toolName} at turn ${turn} (${streak}/${yieldAfter})`,
589759
589898
  turn,
589760
589899
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
589761
589900
  });
589762
- return message2;
589901
+ return { kind: "block", message: message2 };
589763
589902
  }
589764
589903
  _compileFixLoopCompletionBlocker(turn) {
589765
589904
  const state = this._compileFixLoop;
@@ -590072,11 +590211,8 @@ ${modelVisible}` : modelVisible || result.error || displayOutput || "";
590072
590211
  const realFileMutation = input.realFileMutation ?? this._isRealProjectMutation(input.toolName, input.result);
590073
590212
  const attemptedTargetPaths = this._extractToolTargetPaths(input.toolName, input.args, input.result);
590074
590213
  const realMutationPaths = input.realMutationPaths ?? (realFileMutation ? attemptedTargetPaths : []);
590075
- const shellActionReasonScope = input.toolName === "shell" ? input.actionReason?.scope : void 0;
590076
- const shellActionReasonDeclaresVerification = shellActionReasonScope === "verification";
590077
- const shellActionReasonDeclaresNonVerification = typeof shellActionReasonScope === "string" && shellActionReasonScope.length > 0 && shellActionReasonScope !== "verification";
590078
- const shellVerification = input.toolName === "shell" && (shellActionReasonDeclaresVerification || !shellActionReasonDeclaresNonVerification && input.result.runtimeAuthored !== true && this._shellResultLooksLikeVerification(input.args, input.result));
590079
- const shellVerificationFamily = shellVerification ? this._shellVerificationFamily(input.args, input.actionReason) : "";
590214
+ const shellVerification = input.toolName === "shell" && input.result.runtimeAuthored !== true && this._shellResultLooksLikeVerification(input.args, input.result);
590215
+ const shellVerificationFamily = shellVerification ? this._shellVerificationFamily(input.args) : "";
590080
590216
  if (input.result.success === true && this._isProjectEditTool(input.toolName) && !realFileMutation && input.result.alreadyApplied !== true) {
590081
590217
  return;
590082
590218
  }
@@ -590110,17 +590246,7 @@ ${modelVisible}` : modelVisible || result.error || displayOutput || "";
590110
590246
  }
590111
590247
  this._saveCompletionLedgerSafe();
590112
590248
  }
590113
- _shellVerificationFamily(args, actionReason) {
590114
- if (actionReason?.scope === "verification") {
590115
- const stableParts = [
590116
- actionReason.task_anchor,
590117
- actionReason.expected_result
590118
- ].map((part) => String(part ?? "").trim()).filter(Boolean);
590119
- const semanticKey = (stableParts.length > 0 ? stableParts : [String(actionReason.intent ?? "").trim()].filter(Boolean)).join(" | ");
590120
- const normalized2 = normalizeCompletionKey(semanticKey || "shell verification", "shell_verification").slice(0, 140);
590121
- if (normalized2)
590122
- return `shell-action:${normalized2}`;
590123
- }
590249
+ _shellVerificationFamily(args) {
590124
590250
  const command = String(args?.["command"] ?? args?.["cmd"] ?? "").trim();
590125
590251
  const normalized = normalizeShellCommand(command);
590126
590252
  return `shell:${(normalized || command || "verification").slice(0, 160)}`;
@@ -590130,6 +590256,8 @@ ${modelVisible}` : modelVisible || result.error || displayOutput || "";
590130
590256
  if (!command.trim())
590131
590257
  return false;
590132
590258
  void result;
590259
+ if (commandIsPureReadOnlyPipeline(command))
590260
+ return false;
590133
590261
  return /\b(test|tests|vitest|jest|pytest|go test|cargo test|npm test|pnpm test|yarn test|typecheck|tsc|build|verify|verification|check)\b/i.test(command);
590134
590262
  }
590135
590263
  _shouldSuppressCompletionDiscoveryEvidence(toolName, result, targetPaths) {
@@ -592443,13 +592571,11 @@ ${latest.output || ""}`.trim();
592443
592571
  success: item.succeeded,
592444
592572
  path: item.path,
592445
592573
  stateVersion: item.stateVersion,
592446
- preview: item.preview.slice(0, 240),
592447
- actionReason: item.actionReason ?? void 0
592574
+ preview: item.preview.slice(0, 240)
592448
592575
  }));
592449
592576
  const recentActionLines = recentActions.slice(-6).map((item) => {
592450
592577
  const path16 = item.path ? ` path=${item.path}` : "";
592451
- const reason = item.actionReason ? ` reason=${[item.actionReason.scope, item.actionReason.intent].filter(Boolean).join(":").replace(/\s+/g, " ").slice(0, 120)}` : "";
592452
- return `- turn=${item.turn} ${item.tool} ${item.success ? "ok" : "err"}${path16}${reason}: ${item.preview.replace(/\s+/g, " ").slice(0, 160)}`;
592578
+ return `- turn=${item.turn} ${item.tool} ${item.success ? "ok" : "err"}${path16}: ${item.preview.replace(/\s+/g, " ").slice(0, 160)}`;
592453
592579
  });
592454
592580
  const treeDir = _pathJoin(this.omniusStateDir(), "world-state", "tree");
592455
592581
  const turnName = `turn-${String(turn).padStart(4, "0")}`;
@@ -592751,10 +592877,10 @@ ${sections.join("\n")}` : sections.join("\n");
592751
592877
  }
592752
592878
  }
592753
592879
  const sections = [
592754
- "[KNOWLEDGE — recent tool results for reference. Re-reading a file after an edit is encouraged to capture the latest content; exact re-reads are NOT blocked and always return fresh, up-to-date data.]"
592880
+ "[KNOWLEDGE — prior observations for orientation only. A file_read requested for current text/hash and a verifier requested after mutation execute live; this history is never substituted for fresh evidence.]"
592755
592881
  ];
592756
592882
  if (compactedCount > 0) {
592757
- sections.push(`Compacted cached entries still count as already-known results (${compactedCount}); an exact repeat will be served from cache or skipped, not produce new information.`);
592883
+ sections.push(`Compacted historical entries: ${compactedCount}. They show what was observed earlier, not what is currently on disk. Re-run the narrow read or verifier when freshness matters.`);
592758
592884
  }
592759
592885
  if (filesRead.length > 0) {
592760
592886
  const unique2 = [...new Set(filesRead)].slice(0, 30);
@@ -593597,11 +593723,11 @@ ${blob}
593597
593723
  const meta = metaForResult(idx);
593598
593724
  let stub;
593599
593725
  if (p2) {
593600
- stub = `[Earlier read of ${p2} cleared its content is preserved in your ACTIVE CONTEXT FRAME (Evidence already gathered). Do NOT re-read it; use the frame.]`;
593726
+ stub = `[Earlier read of ${p2} compacted. A snapshot may appear in the ACTIVE CONTEXT FRAME; file_read the narrow current range again whenever exact text/hash or unelided content is needed.]`;
593601
593727
  } else {
593602
593728
  const firstLine = content.split("\n").find((l2) => l2.trim())?.trim().slice(0, 140) ?? "";
593603
593729
  const failed = /\berror\b|\bfail|✗|exit code [1-9]|traceback/i.test(content);
593604
- stub = `[${meta?.name ?? "tool"}(${meta?.argsPreview ?? ""}) result compacted to save context — ${failed ? "FAILED" : "ok"}${firstLine ? `: ${firstLine}` : ""}. Re-run ONLY if the underlying state has since changed.]`;
593730
+ stub = `[${meta?.name ?? "tool"}(${meta?.argsPreview ?? ""}) result compacted to save context — ${failed ? "FAILED" : "ok"}${firstLine ? `: ${firstLine}` : ""}. This is historical orientation, not current-state proof; re-run a verifier or narrow state read when freshness matters.]`;
593605
593731
  }
593606
593732
  messages2[idx] = { ...msg, content: stub };
593607
593733
  cleared++;
@@ -593688,7 +593814,7 @@ ${blob}
593688
593814
  * size. The hash is computed over the full canonical value.
593689
593815
  */
593690
593816
  _buildExactArgsKey(args) {
593691
- return Object.entries(args ?? {}).filter(([key]) => !TOOL_ACTION_REASON_KEYS.has(key)).sort(([a2], [b]) => a2.localeCompare(b)).map(([k, v]) => `${k}=${this._formatExactArgValue(v)}`).join(",");
593817
+ return Object.entries(args ?? {}).filter(([key]) => !LEGACY_ACTION_REASON_KEYS.has(key)).sort(([a2], [b]) => a2.localeCompare(b)).map(([k, v]) => `${k}=${this._formatExactArgValue(v)}`).join(",");
593692
593818
  }
593693
593819
  _buildToolFingerprint(name10, args) {
593694
593820
  const canonical = this.lookupRegisteredTool(name10)?.name ?? name10;
@@ -593980,7 +594106,7 @@ ${blob}
593980
594106
  if (seen.has(value2))
593981
594107
  return "#cycle";
593982
594108
  seen.add(value2);
593983
- 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)}`);
594109
+ const entries = Object.entries(value2).filter(([key]) => !LEGACY_ACTION_REASON_KEYS.has(key)).sort(([a2], [b]) => a2.localeCompare(b)).map(([k, v]) => `${JSON.stringify(k)}:${this._canonicalArgValue(v, seen)}`);
593984
594110
  return `#object:{${entries.join(",")}}`;
593985
594111
  }
593986
594112
  return String(value2);
@@ -594170,8 +594296,7 @@ Rewrite it now for ${ctx3.model}.`;
594170
594296
  const unknownKeys = providedKeys.filter((key) => !props.has(key));
594171
594297
  const aliases = this.suggestArgumentAliases(missingRequired, providedKeys, args, props);
594172
594298
  const corrected = this.buildCorrectedArgsPreview(args, props, aliases);
594173
- const actionReasonOnlyFailure = validationError.includes("[TOOL ACTION REASON CONTRACT]");
594174
- const siblingMatches = actionReasonOnlyFailure ? [] : this.findSiblingToolSchemaMatches(toolName, providedKeys);
594299
+ const siblingMatches = this.findSiblingToolSchemaMatches(toolName, providedKeys);
594175
594300
  const lines = [
594176
594301
  `[RUNTIME TOOL ARGUMENT REPAIR]`,
594177
594302
  `Tool call failed before execution: ${toolName}`,
@@ -596480,7 +596605,7 @@ ${_staleSamples.join("\n")}` : ``,
596480
596605
  ``,
596481
596606
  ` (a) RUN-AND-READ: Run the EXACT command that fails (test/typecheck/build) and READ THE FULL ERROR MESSAGE LITERALLY. Do not summarize it from memory; paste it back into context. The current write hasn't been validated against any error.`,
596482
596607
  ``,
596483
- ` (b) DELETE-AND-RESTART: If the file has been rewritten ${_wtWorstCount} times, the current approach is wrong. Either delete the file and try a fundamentally different design, OR revert to a known-good earlier version (use git, working_notes, or memory_search to find one).`,
596608
+ ` (b) DIFF-AND-RESET-THE-PREMISE: Inspect git diff for ${_wtWorstPath}, then file_read only the implicated current range. Keep correct changes, identify the first wrong hunk, and repair that hunk with file_patch/file_edit. Do not delete or regenerate the file.`,
596484
596609
  ``,
596485
596610
  ` (c) ERROR-INFORMED LOCAL TRIAGE: use the exact failing local command and error line to identify one implicated path/symbol/config key, then inspect or change only that target. Do not search online for a codebase-local failure.`,
596486
596611
  ``,
@@ -597113,6 +597238,8 @@ If you're stuck, try a completely different approach. Do NOT repeat what failed
597113
597238
  };
597114
597239
  const ceCompactOutput = await this._contextEngine.compact(ceCompactInput);
597115
597240
  if (ceCompactOutput.compacted && ceCompactOutput.compactedMessages.length > 0 && ceCompactOutput.compactedMessages.length < compacted.length) {
597241
+ const beforeCount = compacted.length;
597242
+ const afterCount = ceCompactOutput.compactedMessages.length;
597116
597243
  messages2.length = 0;
597117
597244
  messages2.push(...ceCompactOutput.compactedMessages.map((m2) => ({
597118
597245
  role: m2.role,
@@ -597120,6 +597247,11 @@ If you're stuck, try a completely different approach. Do NOT repeat what failed
597120
597247
  ...m2.name ? { name: m2.name } : {}
597121
597248
  })));
597122
597249
  compacted = messages2;
597250
+ this.emit({
597251
+ type: "compaction",
597252
+ content: `Compacted ${beforeCount - afterCount} messages (context engine) | ${beforeCount} -> ${afterCount} messages retained`,
597253
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
597254
+ });
597123
597255
  }
597124
597256
  } catch {
597125
597257
  }
@@ -597746,7 +597878,6 @@ ${memoryLines.join("\n")}`
597746
597878
  executeSingle = async (tc) => {
597747
597879
  if (this.aborted)
597748
597880
  return null;
597749
- const actionReasonForAdvisory = this._toolActionReasonForCall(tc.name, tc.arguments ?? {});
597750
597881
  const cohortKey = this.buildArgCohortKey(tc.name, tc.arguments);
597751
597882
  const cohort = this._argCohorts.get(cohortKey);
597752
597883
  if (cohort && cohort.failure >= 3 && cohort.success === 0) {
@@ -598107,7 +598238,6 @@ Read the current file if needed, make a different concrete edit, or move to veri
598107
598238
  turn,
598108
598239
  toolName: tc.name,
598109
598240
  args: tc.arguments ?? {},
598110
- actionReason: actionReasonForAdvisory,
598111
598241
  fingerprint: toolFingerprint,
598112
598242
  isReadLike: false,
598113
598243
  stalePreflightMessage: staleEditBlock,
@@ -598173,7 +598303,6 @@ Read the current file if needed, make a different concrete edit, or move to veri
598173
598303
  turn,
598174
598304
  toolName: tc.name,
598175
598305
  args: tc.arguments ?? {},
598176
- actionReason: actionReasonForAdvisory,
598177
598306
  fingerprint: toolFingerprint,
598178
598307
  isReadLike: false,
598179
598308
  stalePreflightMessage: staleRewriteBlock,
@@ -598239,7 +598368,6 @@ Read the current file if needed, make a different concrete edit, or move to veri
598239
598368
  turn,
598240
598369
  toolName: tc.name,
598241
598370
  args: tc.arguments ?? {},
598242
- actionReason: actionReasonForAdvisory,
598243
598371
  fingerprint: toolFingerprint,
598244
598372
  isReadLike: false,
598245
598373
  stalePreflightMessage: editReversalBlock,
@@ -598373,8 +598501,7 @@ Read the current file if needed, make a different concrete edit, or move to veri
598373
598501
  } : evaluate2({
598374
598502
  proposedCall: {
598375
598503
  tool: tc.name,
598376
- args: tc.arguments ?? {},
598377
- actionReason: actionReasonForAdvisory ?? void 0
598504
+ args: tc.arguments ?? {}
598378
598505
  },
598379
598506
  fingerprint: toolFingerprint,
598380
598507
  isReadLike,
@@ -598424,7 +598551,6 @@ Read the current file if needed, make a different concrete edit, or move to veri
598424
598551
  tool: tc.name,
598425
598552
  target: _target,
598426
598553
  count: criticDecision.hitNumber,
598427
- actionReason: actionReasonForAdvisory ?? void 0,
598428
598554
  alreadyHave: _existingFp?.result
598429
598555
  }
598430
598556
  });
@@ -598529,7 +598655,6 @@ ${cachedResult}`,
598529
598655
  turn,
598530
598656
  toolName: tc.name,
598531
598657
  args: tc.arguments ?? {},
598532
- actionReason: actionReasonForAdvisory,
598533
598658
  completionStatus: completionStatusFromTaskCompleteArgs(tc.arguments),
598534
598659
  fingerprint: toolFingerprint,
598535
598660
  isReadLike,
@@ -598568,8 +598693,10 @@ ${cachedResult}`,
598568
598693
  };
598569
598694
  }
598570
598695
  }
598571
- const compileLoopPreflightBlock = !repeatShortCircuit ? this._compileFixLoopPreflightBlock(tc.name, tc.arguments ?? {}, turn, shellLikelyMutatesFilesystem) : null;
598572
- if (compileLoopPreflightBlock) {
598696
+ const compileLoopPreflight = !repeatShortCircuit ? this._compileFixLoopPreflightBlock(tc.name, tc.arguments ?? {}, turn, shellLikelyMutatesFilesystem) : null;
598697
+ if (compileLoopPreflight?.kind === "yield") {
598698
+ pushSoftInjection("system", compileLoopPreflight.notice);
598699
+ } else if (compileLoopPreflight) {
598573
598700
  this.emit({
598574
598701
  type: "tool_call",
598575
598702
  toolName: tc.name,
@@ -598581,7 +598708,7 @@ ${cachedResult}`,
598581
598708
  type: "tool_result",
598582
598709
  toolName: tc.name,
598583
598710
  success: false,
598584
- content: compileLoopPreflightBlock.slice(0, 120),
598711
+ content: compileLoopPreflight.message.slice(0, 120),
598585
598712
  turn,
598586
598713
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
598587
598714
  });
@@ -598591,9 +598718,9 @@ ${cachedResult}`,
598591
598718
  });
598592
598719
  return {
598593
598720
  tc,
598594
- output: compileLoopPreflightBlock,
598721
+ output: compileLoopPreflight.message,
598595
598722
  success: false,
598596
- systemGuidance: compileLoopPreflightBlock
598723
+ systemGuidance: compileLoopPreflight.message
598597
598724
  };
598598
598725
  }
598599
598726
  this.emit({
@@ -598607,7 +598734,6 @@ ${cachedResult}`,
598607
598734
  const tool = resolvedTool?.tool;
598608
598735
  let result;
598609
598736
  let runtimeSystemGuidance = null;
598610
- let toolActionReason = actionReasonForAdvisory;
598611
598737
  if (repeatShortCircuit) {
598612
598738
  result = repeatShortCircuit;
598613
598739
  } else if (tc.arguments && "_raw" in tc.arguments) {
@@ -598623,12 +598749,12 @@ ${cachedResult}`,
598623
598749
  error: this.unknownToolError(tc.name)
598624
598750
  };
598625
598751
  } else {
598626
- let validationError = this._validateToolActionReason(resolvedTool?.name ?? tc.name, tc.arguments ?? {});
598752
+ let validationError = null;
598627
598753
  if (!validationError) {
598628
- tc.arguments = this._stripToolActionReasonArgs(tc.arguments ?? {});
598754
+ tc.arguments = this._stripLegacyActionReasonArgs(tc.arguments ?? {});
598629
598755
  tc.arguments = this._normalizeToolArgsForExecution(resolvedTool?.name ?? tc.name, tc.arguments ?? {});
598630
598756
  tc.arguments = this._autoDeriveDelegationMutationScope(resolvedTool?.name ?? tc.name, tc.arguments ?? {}, turn);
598631
- validationError = this._validateFileWriteOverwriteContract(resolvedTool?.name ?? tc.name, tc.arguments ?? {}, toolActionReason);
598757
+ validationError = this._validateFileWriteOverwriteContract(resolvedTool?.name ?? tc.name, tc.arguments ?? {});
598632
598758
  }
598633
598759
  if (!validationError) {
598634
598760
  validationError = this._validateFreshExpectedHashesForEdit(resolvedTool?.name ?? tc.name, tc.arguments ?? {});
@@ -598881,8 +599007,7 @@ Respond with EXACTLY this structure before your next tool call:
598881
599007
  toolName: resolvedTool?.name ?? tc.name,
598882
599008
  toolCallId: tc.id,
598883
599009
  args: tc.arguments,
598884
- result,
598885
- actionReason: toolActionReason
599010
+ result
598886
599011
  });
598887
599012
  if (observedStateMutation) {
598888
599013
  this._markAdversaryObservedStateMutation();
@@ -599634,24 +599759,12 @@ Respond with EXACTLY this structure before your next tool call:
599634
599759
  }
599635
599760
  const cacheableMemoryNoop = tc.name === "memory_write" && result.success && result.noop;
599636
599761
  const cacheableProjectWriteNoop = this._isProjectEditTool(tc.name) && result.success && !this._isRealProjectMutation(tc.name, result) && (result.noop === true || result.mutated === false);
599637
- const cacheableShellResult = tc.name === "shell" && result.runtimeAuthored !== true && !shellLikelyMutatesFilesystem;
599638
- if (isReadLike && result.success && result.runtimeAuthored !== true || cacheableShellResult || cacheableMemoryNoop || cacheableProjectWriteNoop) {
599762
+ if (cacheableMemoryNoop || cacheableProjectWriteNoop) {
599639
599763
  recentToolResults.set(toolFingerprint, {
599640
- result: tc.name === "shell" ? this._buildShellCacheResult(tc.arguments, result) : (
599641
- // Read-like results are SERVED BACK to the model when the
599642
- // repeat gate fires, so they must stay complete enough to
599643
- // edit against — truncating to 2KB cut the tail off normal
599644
- // source files (the "old_string not found" cascade). Large
599645
- // files are handled by branch-extract upstream, so 16KB
599646
- // here covers ordinary files without bloating the cache.
599647
- isReadLike ? this.sanitizeCachedToolResult(tc.name, result.output ?? "").slice(0, 16e3) : (result.output ?? "").slice(0, 2e3)
599648
- ),
599764
+ result: (result.output ?? "").slice(0, 2e3),
599649
599765
  compacted: false,
599650
599766
  mutationEpoch: fileMutationEpoch
599651
599767
  });
599652
- if (isReadLike && result.success) {
599653
- this._registerReadCoverage(tc.name, tc.arguments ?? {}, toolFingerprint);
599654
- }
599655
599768
  if (recentToolResults.size > 500) {
599656
599769
  const firstKey = recentToolResults.keys().next().value;
599657
599770
  if (firstKey !== void 0) {
@@ -600164,7 +600277,6 @@ Evidence: ${evidencePreview}`.slice(0, 500);
600164
600277
  turn,
600165
600278
  toolName: tc.name,
600166
600279
  args: tc.arguments ?? {},
600167
- actionReason: toolActionReason,
600168
600280
  fingerprint: toolFingerprint,
600169
600281
  success: result.success,
600170
600282
  output: result.output ?? result.llmContent ?? "",
@@ -600200,8 +600312,7 @@ ${structuralGuardGuidance}` : structuralGuardGuidance;
600200
600312
  }
600201
600313
  if (tc.name === "shell" && result.runtimeAuthored !== true) {
600202
600314
  const shellCommand = String(tc.arguments?.["command"] ?? tc.arguments?.["cmd"] ?? "");
600203
- const compileOutput = `${result.output ?? ""}
600204
- ${result.error ?? ""}`;
600315
+ const compileOutput = this._expandTriagedPayloadForDiagnostics([result.output, result.llmContent, result.error].filter((part) => typeof part === "string" && part.length > 0).join("\n"));
600205
600316
  const verifierCommand = this._declaredVerifierCommandForShell(shellCommand, compileOutput);
600206
600317
  if (verifierCommand) {
600207
600318
  const compileGuidance = this._observeCompileVerifierResult({
@@ -600377,7 +600488,6 @@ ${delegateDir}` : delegateDir;
600377
600488
  reason: focusDecision.directive.reason,
600378
600489
  requiredNextAction: focusDecision.directive.requiredNextAction
600379
600490
  },
600380
- actionReason: toolActionReason ?? void 0,
600381
600491
  repeatShortCircuit: Boolean(repeatShortCircuit),
600382
600492
  runtimeAuthored: result.runtimeAuthored === true,
600383
600493
  runtimeGuidance: runtimeSystemGuidance,
@@ -600415,20 +600525,20 @@ ${delegateDir}` : delegateDir;
600415
600525
  if (sameToolFailStreak >= 5 && (this.options.modelTier === "small" || this.options.modelTier === "medium")) {
600416
600526
  this.enqueueRuntimeGuidance(`[BRANCH — evaluate alternatives before acting]
600417
600527
  Tool "${tc.name}" has failed ${sameToolFailStreak} times. STOP and enumerate:
600418
- Option A: [describe a completely different approach]
600419
- Option B: [describe another alternative]
600420
- Option C: [the simplest possible fallback]
600421
- Pick the BEST option and explain why, then execute it. Do NOT retry ${tc.name} with similar arguments.`);
600528
+ Option A: refresh the exact evidence or correct the current tool arguments
600529
+ Option B: use a different narrow diagnostic or targeted edit transport
600530
+ Option C: verify whether the desired change is already present
600531
+ Pick the BEST option and explain why, then execute it. Do NOT retry ${tc.name} with similar arguments, and do not broaden a local edit into file_write.`);
600422
600532
  sameToolFailStreak = 0;
600423
600533
  sameToolFailName = null;
600424
600534
  }
600425
600535
  if (consecutiveSameTool >= 2 && (this.options.modelTier === "small" || this.options.modelTier === "medium")) {
600426
600536
  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:
600427
- - If file_edit keeps failing: re-read the file first, then use the EXACT text from the file
600537
+ - If file_edit/file_patch keeps failing: re-read the implicated current range, then correct the exact text/range/hash or inspect git diff
600428
600538
  - If shell keeps failing: try a different command or check prerequisites
600429
600539
  - If grep_search finds nothing: try broader patterns or list_directory
600430
- - Consider using a completely different tool or strategy
600431
- Do NOT retry ${tc.name} with similar arguments.`);
600540
+ - A different strategy means a different diagnosis or narrow transport, never a whole-file rewrite fallback
600541
+ Do NOT retry ${tc.name} with similar arguments and do NOT use file_write to escape a targeted-edit failure.`);
600432
600542
  }
600433
600543
  if (!this._taskState.failedApproaches.includes(failDesc)) {
600434
600544
  this._taskState.failedApproaches.push(failDesc);
@@ -600602,7 +600712,6 @@ Then use file_read on individual FILES inside it.`);
600602
600712
  toolName: tc.name,
600603
600713
  argsKey: tc.arguments ? JSON.stringify(tc.arguments) : "",
600604
600714
  args: tc.arguments,
600605
- actionReason: toolActionReason,
600606
600715
  result,
600607
600716
  outputPreview: this._toolEvidencePreview(result, output, 1200, tc.name),
600608
600717
  realFileMutation,
@@ -603052,200 +603161,24 @@ ${marker}` : marker);
603052
603161
  }
603053
603162
  return matchesFresh(args);
603054
603163
  }
603055
- _toolActionReasonPolicy(toolName, args) {
603056
- if (process.env["OMNIUS_DISABLE_TOOL_ACTION_REASON"] === "1") {
603057
- return "disabled";
603058
- }
603059
- if ((process.env["VITEST"] || process.env["NODE_ENV"] === "test") && process.env["OMNIUS_REQUIRE_TOOL_ACTION_REASON"] !== "1") {
603060
- return "disabled";
603061
- }
603062
- if (this.options.artifactMode === "internal")
603063
- return "disabled";
603064
- if (toolName.startsWith("__"))
603065
- return "disabled";
603066
- return this._toolActionReasonIsOptional(toolName, args) ? "optional" : "required";
603067
- }
603068
- _requiresToolActionReason(toolName, args) {
603069
- return this._toolActionReasonPolicy(toolName, args) === "required";
603070
- }
603071
- _toolActionReasonIsOptional(toolName, args) {
603072
- const resolved = this.lookupRegisteredTool(toolName);
603073
- const canonical = resolved?.name ?? toolName;
603074
- if (READ_ONLY_ACTION_REASON_OPTIONAL_TOOLS.has(canonical))
603075
- return true;
603076
- const tool = resolved?.tool;
603077
- if (typeof tool?.isReadOnly === "function") {
603078
- try {
603079
- if (tool.isReadOnly(args ?? {}))
603080
- return true;
603081
- } catch {
603082
- }
603083
- }
603084
- return false;
603085
- }
603086
- _withToolActionReasonSchema(toolName, parameters) {
603087
- const policy = this._toolActionReasonPolicy(toolName);
603088
- if (policy === "disabled") {
603089
- return parameters ?? { type: "object", properties: {} };
603090
- }
603164
+ _publicToolParameters(parameters) {
603091
603165
  const base3 = parameters && typeof parameters === "object" && !Array.isArray(parameters) ? { ...parameters } : { type: "object" };
603092
603166
  const properties = base3["properties"] && typeof base3["properties"] === "object" && !Array.isArray(base3["properties"]) ? { ...base3["properties"] } : {};
603093
- properties["action_reason"] = TOOL_ACTION_REASON_SCHEMA;
603094
- const required = Array.isArray(base3["required"]) ? base3["required"].map(String) : [];
603167
+ for (const key of LEGACY_ACTION_REASON_KEYS)
603168
+ delete properties[key];
603169
+ const required = Array.isArray(base3["required"]) ? base3["required"].map(String).filter((key) => !LEGACY_ACTION_REASON_KEYS.has(key)) : [];
603095
603170
  return {
603096
603171
  ...base3,
603097
603172
  type: "object",
603098
603173
  properties,
603099
- required: policy === "required" ? [.../* @__PURE__ */ new Set([...required, "action_reason"])] : required
603100
- };
603101
- }
603102
- _extractToolActionReason(args) {
603103
- let raw = args["action_reason"] ?? args["actionReason"] ?? args["justification"];
603104
- if (typeof raw === "string") {
603105
- const trimmed = raw.trim();
603106
- if (!trimmed)
603107
- return null;
603108
- try {
603109
- raw = JSON.parse(trimmed);
603110
- } catch {
603111
- return { intent: trimmed };
603112
- }
603113
- }
603114
- if (!raw || typeof raw !== "object" || Array.isArray(raw))
603115
- return null;
603116
- const rec = raw;
603117
- const reason = {
603118
- task_anchor: String(rec["task_anchor"] ?? rec["taskAnchor"] ?? "").trim(),
603119
- intent: String(rec["intent"] ?? "").trim(),
603120
- evidence: String(rec["evidence"] ?? "").trim(),
603121
- expected_result: String(rec["expected_result"] ?? rec["expectedResult"] ?? "").trim(),
603122
- scope: String(rec["scope"] ?? "").trim()
603123
- };
603124
- return reason;
603125
- }
603126
- _toolActionReasonForCall(toolName, args) {
603127
- const explicit = this._extractToolActionReason(args);
603128
- if (explicit) {
603129
- return this._completeToolActionReason(toolName, args, explicit);
603130
- }
603131
- if (this._shouldSynthesizeMissingToolActionReason(toolName, args)) {
603132
- return this._synthesizeStateUpdateToolActionReason(toolName, args);
603133
- }
603134
- if (this._toolActionReasonPolicy(toolName, args) !== "optional")
603135
- return null;
603136
- return this._synthesizeReadOnlyToolActionReason(toolName, args);
603137
- }
603138
- _completeToolActionReason(toolName, args, partial) {
603139
- const canonical = this.lookupRegisteredTool(toolName)?.name ?? toolName;
603140
- const goal = this._taskState.currentStep || this._taskState.nextAction || this._taskState.goal || this._taskState.originalGoal || "current task";
603141
- const targetPaths = this._extractToolTargetPaths(canonical, args).slice(0, 3);
603142
- const targetText = targetPaths.length > 0 ? ` for ${targetPaths.join(", ")}` : "";
603143
- const scope = TOOL_ACTION_REASON_SCOPES.has(String(partial.scope ?? "")) ? String(partial.scope) : this._defaultToolActionReasonScope(canonical);
603144
- return {
603145
- task_anchor: cleanToolActionReasonField(partial.task_anchor) || String(goal).replace(/\s+/g, " ").trim().slice(0, 160),
603146
- intent: cleanToolActionReasonField(partial.intent) || `Run ${canonical}${targetText} for the active task.`,
603147
- evidence: cleanToolActionReasonField(partial.evidence) || "Runtime completed partial public action metadata from the tool call contract before execution.",
603148
- expected_result: cleanToolActionReasonField(partial.expected_result) || this._defaultToolActionExpectedResult(canonical, targetText),
603149
- scope
603150
- };
603151
- }
603152
- _defaultToolActionReasonScope(toolName) {
603153
- if (toolName === "file_edit" || toolName === "file_patch" || toolName === "batch_edit") {
603154
- return "targeted_patch";
603155
- }
603156
- if (toolName === "create_structured_file")
603157
- return "new_file";
603158
- if (toolName === "task_complete")
603159
- return "completion";
603160
- if (READ_ONLY_ACTION_REASON_OPTIONAL_TOOLS.has(toolName))
603161
- return "discovery";
603162
- return "other";
603163
- }
603164
- _defaultToolActionExpectedResult(toolName, targetText) {
603165
- switch (toolName) {
603166
- case "file_edit":
603167
- return `Requested exact edit is applied${targetText}, or a precise edit error is returned.`;
603168
- case "file_patch":
603169
- return `Requested line patch is applied${targetText}, or a precise patch error is returned.`;
603170
- case "batch_edit":
603171
- return `Requested edit batch is applied${targetText}, or per-edit failure evidence is returned.`;
603172
- case "file_write":
603173
- return `Requested file content is written${targetText}, or a precise write error is returned.`;
603174
- case "shell":
603175
- return "Command exits with output evidence for the next decision.";
603176
- default:
603177
- return `${toolName} completes and returns success or failure evidence.`;
603178
- }
603179
- }
603180
- _shouldSynthesizeMissingToolActionReason(toolName, _args) {
603181
- if (this._toolActionReasonPolicy(toolName, _args) === "disabled") {
603182
- return false;
603183
- }
603184
- const canonical = this.lookupRegisteredTool(toolName)?.name ?? toolName;
603185
- return STATE_UPDATE_ACTION_REASON_SYNTHESIS_TOOLS.has(canonical);
603186
- }
603187
- _synthesizeStateUpdateToolActionReason(toolName, args) {
603188
- const canonical = this.lookupRegisteredTool(toolName)?.name ?? toolName;
603189
- const goal = this._taskState.currentStep || this._taskState.nextAction || this._taskState.goal || this._taskState.originalGoal || "current task";
603190
- const todoCount = Array.isArray(args["todos"]) ? args["todos"].length : null;
603191
- return {
603192
- task_anchor: String(goal).replace(/\s+/g, " ").trim().slice(0, 160),
603193
- intent: `Update visible task state with ${canonical}.`,
603194
- evidence: todoCount === null ? "Model omitted public action_reason; runtime synthesized bookkeeping metadata without authorizing project mutation." : `Model supplied ${todoCount} todo item(s); runtime synthesized bookkeeping metadata without authorizing project mutation.`,
603195
- expected_result: "Session checklist reflects the current task state.",
603196
- scope: "state_update"
603197
- };
603198
- }
603199
- _synthesizeReadOnlyToolActionReason(toolName, args) {
603200
- const canonical = this.lookupRegisteredTool(toolName)?.name ?? toolName;
603201
- const goal = this._taskState.currentStep || this._taskState.nextAction || this._taskState.goal || this._taskState.originalGoal || "current task";
603202
- const targets = this._extractToolTargetPaths(canonical, args).slice(0, 3);
603203
- const targetText = targets.length > 0 ? ` for ${targets.join(", ")}` : "";
603204
- return {
603205
- task_anchor: String(goal).replace(/\s+/g, " ").trim().slice(0, 160),
603206
- intent: `Run read-only ${canonical}${targetText} to gather current evidence.`,
603207
- evidence: "Read-only metadata fallback; no project mutation is authorized by this action.",
603208
- expected_result: `Current ${canonical} evidence for the next decision.`,
603209
- scope: "discovery"
603174
+ required
603210
603175
  };
603211
603176
  }
603212
- _validateToolActionReason(toolName, args) {
603213
- const policy = this._toolActionReasonPolicy(toolName, args);
603214
- if (policy === "disabled")
603215
- return null;
603216
- const raw = args["action_reason"] ?? args["actionReason"] ?? args["justification"];
603217
- if (!raw || typeof raw === "string" && !raw.trim()) {
603218
- if (policy === "optional")
603219
- return null;
603220
- if (this._shouldSynthesizeMissingToolActionReason(toolName, args)) {
603221
- return null;
603222
- }
603223
- return [
603224
- "[TOOL ACTION REASON CONTRACT]",
603225
- `This side-effectful tool call must include action_reason: { task_anchor, intent, evidence, expected_result, scope }.`,
603226
- `Use compact public facts only; do not include hidden chain-of-thought.`,
603227
- `scope must be one of: ${Array.from(TOOL_ACTION_REASON_SCOPES).join(", ")}.`
603228
- ].join("\n");
603229
- }
603230
- const partialReason = this._extractToolActionReason(args);
603231
- if (!partialReason) {
603232
- if (policy === "optional")
603233
- return null;
603234
- return "[TOOL ACTION REASON CONTRACT] action_reason must be an object with compact public task-state fields.";
603235
- }
603236
- const reason = this._completeToolActionReason(toolName, args, partialReason);
603237
- if (!TOOL_ACTION_REASON_SCOPES.has(reason.scope)) {
603238
- if (policy === "optional")
603239
- return null;
603240
- return `[TOOL ACTION REASON CONTRACT] action_reason.scope="${reason.scope}" is invalid. Use one of: ${Array.from(TOOL_ACTION_REASON_SCOPES).join(", ")}.`;
603241
- }
603242
- return null;
603243
- }
603244
- _stripToolActionReasonArgs(args) {
603177
+ _stripLegacyActionReasonArgs(args) {
603245
603178
  let changed = false;
603246
603179
  const next = {};
603247
603180
  for (const [key, value2] of Object.entries(args)) {
603248
- if (TOOL_ACTION_REASON_KEYS.has(key)) {
603181
+ if (LEGACY_ACTION_REASON_KEYS.has(key)) {
603249
603182
  changed = true;
603250
603183
  continue;
603251
603184
  }
@@ -603362,7 +603295,7 @@ ${marker}` : marker);
603362
603295
  }
603363
603296
  return next;
603364
603297
  }
603365
- _validateFileWriteOverwriteContract(toolName, args, actionReason) {
603298
+ _validateFileWriteOverwriteContract(toolName, args) {
603366
603299
  if (toolName !== "file_write")
603367
603300
  return null;
603368
603301
  if (process.env["OMNIUS_ALLOW_UNVERIFIED_FILE_WRITE_OVERWRITE"] === "1") {
@@ -603384,20 +603317,13 @@ ${marker}` : marker);
603384
603317
  }
603385
603318
  if (!exists2)
603386
603319
  return null;
603387
- if (actionReason && actionReason.scope !== "full_file_rewrite") {
603388
- return [
603389
- "[FULL FILE REWRITE CONTRACT]",
603390
- `file_write targets an existing file: ${path16}.`,
603391
- `For constrained repairs, use file_patch, batch_edit, or file_edit instead of rewriting the full file.`,
603392
- `If a whole-file replacement is truly intended, set action_reason.scope="full_file_rewrite" and use expected_hash from a fresh file_read.`
603393
- ].join("\n");
603394
- }
603395
603320
  if (!this._toolCallUsesFreshFileReadEvidence(toolName, args)) {
603396
603321
  const fresh = this._freshReadHashForEditPath(path16);
603397
603322
  return [
603398
603323
  "[FULL FILE REWRITE CONTRACT]",
603399
603324
  `file_write would overwrite existing file ${path16}, but it is not anchored to fresh file_read evidence.`,
603400
- fresh ? `Use expected_hash=${fresh.hash} from the current active evidence, or prefer file_patch/batch_edit for a constrained change.` : `First file_read ${path16}, then prefer file_patch/batch_edit; only retry file_write with expected_hash if a whole-file rewrite is necessary.`
603325
+ "file_write is reserved for new, empty/placeholder, or genuinely small files needing deliberate total replacement; it is never recovery for a failed local edit.",
603326
+ fresh ? `Use expected_hash=${fresh.hash} from the current active evidence, or prefer file_patch/batch_edit for a constrained change.` : `First file_read ${path16}, then prefer file_patch/batch_edit; only retry file_write with expected_hash if a whole-file replacement is necessary.`
603401
603327
  ].join("\n");
603402
603328
  }
603403
603329
  return null;
@@ -605157,9 +605083,9 @@ ${postCompactRestore.join("\n")}`);
605157
605083
 
605158
605084
  **IMPORTANT:** You MUST invoke tools through the function calling interface. Do NOT write tool names as text, markdown, or code blocks — that does nothing. Call tools using the structured tool/function API.` : "";
605159
605085
  const readFilesList = Array.from(this._fileRegistry.entries()).filter(([, e2]) => e2.accessCount > 0).map(([p2]) => p2).slice(0, 10);
605160
- const antiRepetitionReminder = (tier === "small" || tier === "medium") && readFilesList.length > 0 ? `
605086
+ const fileFreshnessReminder = (tier === "small" || tier === "medium") && readFilesList.length > 0 ? `
605161
605087
 
605162
- **DO NOT RE-READ THESE FILES** (you already have their contents): ${readFilesList.join(", ")}. Use the information above to make progress. Reading the same file again wastes a turn.` : "";
605088
+ **PREVIOUSLY OBSERVED FILES:** ${readFilesList.join(", ")}. Treat restored or summarized text as orientation, not guaranteed current bytes. Before editing, make a narrow live read when the body is elided/truncated, the file may have changed, a hash or edit anchor is stale, or exact current text is otherwise required. Avoid only redundant reads when the latest complete authoritative content is still visible and unchanged.` : "";
605163
605089
  const ephemeralSkillPackReminder = this._ephemeralSkillPackContext ? `
605164
605090
 
605165
605091
  [Ephemeral skill-pack restore — current run only, do not persist]
@@ -605177,11 +605103,11 @@ ${scopedStickyDynamicContext}` : "";
605177
605103
  ${fullSummary}
605178
605104
  </compaction-summary>
605179
605105
 
605180
- [Continue from the recent context below. Do not repeat work already completed above.]${goalReminder}${nextActionDirective}${antiRepetitionReminder}${stickyDynamicContextReminder}${ephemeralSkillPackReminder}${toolCallingReminder}` : `[Context compacted${strategyLabel} — summary of earlier work]
605106
+ [Continue from the recent context below. Do not repeat work already completed above.]${goalReminder}${nextActionDirective}${fileFreshnessReminder}${stickyDynamicContextReminder}${ephemeralSkillPackReminder}${toolCallingReminder}` : `[Context compacted${strategyLabel} — summary of earlier work]
605181
605107
 
605182
605108
  ${fullSummary}
605183
605109
 
605184
- [Continue from the recent context below. Do not repeat work already completed above.]${goalReminder}${nextActionDirective}${antiRepetitionReminder}${stickyDynamicContextReminder}${ephemeralSkillPackReminder}${toolCallingReminder}`
605110
+ [Continue from the recent context below. Do not repeat work already completed above.]${goalReminder}${nextActionDirective}${fileFreshnessReminder}${stickyDynamicContextReminder}${ephemeralSkillPackReminder}${toolCallingReminder}`
605185
605111
  };
605186
605112
  this.persistCheckpoint(fullSummary);
605187
605113
  let narrowedHead = [...head];
@@ -605242,10 +605168,11 @@ ${telegramPersonaHead}` : stripped
605242
605168
  const tokenEst = Math.ceil(content.length / 4);
605243
605169
  if (recoveredTokens + tokenEst > fileRecoveryBudget)
605244
605170
  break;
605171
+ const truncated = content.length > 8e3;
605245
605172
  result.push({
605246
605173
  role: "system",
605247
- content: `<recovered-file path="${filePath}" status="${entry.modified ? "modified" : "read"}">
605248
- ${content.slice(0, 8e3)}
605174
+ content: `<recovered-file path="${filePath}" status="${entry.modified ? "modified" : "read"}" truncated="${truncated}">
605175
+ ${content.slice(0, 8e3)}${truncated ? "\n[truncated recovery; use a narrow live read for omitted/current text]" : ""}
605249
605176
  </recovered-file>`
605250
605177
  });
605251
605178
  recoveredFiles.push(filePath);
@@ -605532,7 +605459,6 @@ ${trimmedNew}`;
605532
605459
  fingerprint,
605533
605460
  stateVersion: this._adversaryStateVersion,
605534
605461
  succeeded: input.result.success === true,
605535
- actionReason: input.actionReason,
605536
605462
  ...outcomeEvidence
605537
605463
  });
605538
605464
  while (this._recentToolOutcomes.length > 40) {
@@ -605678,7 +605604,6 @@ ${trimmedNew}`;
605678
605604
  args = JSON.parse(tc.function.arguments);
605679
605605
  } catch {
605680
605606
  }
605681
- const actionReason = this._toolActionReasonForCall(name10, args);
605682
605607
  const argsKey = this._buildExactArgsKey(args);
605683
605608
  const fingerprint = this._buildToolFingerprint(name10, args);
605684
605609
  const prior = this._adversaryToolOutcomes.find((o2) => o2.succeeded && o2.tool === name10 && o2.fingerprint === fingerprint && o2.stateVersion === this._adversaryStateVersion && o2.turn < turn);
@@ -605692,7 +605617,6 @@ ${trimmedNew}`;
605692
605617
  tool: name10,
605693
605618
  target: argsKey.slice(0, 180),
605694
605619
  count: repeatCount,
605695
- actionReason: actionReason ?? void 0,
605696
605620
  alreadyHave: prior.preview
605697
605621
  }
605698
605622
  }, `possible repeated action ${name10} after prior same-state success`);
@@ -606926,7 +606850,7 @@ Example: ${tool.name}(${JSON.stringify(meta.examples[0].args ?? {})})` : "";
606926
606850
  function: {
606927
606851
  name: tool.name,
606928
606852
  description: compressDesc ? (desc.split(/\.\s/)[0]?.slice(0, 120) ?? desc.slice(0, 120)) + "." : desc,
606929
- parameters: this._withToolActionReasonSchema(tool.name, tool.parameters)
606853
+ parameters: this._publicToolParameters(tool.parameters)
606930
606854
  }
606931
606855
  };
606932
606856
  });
@@ -606948,7 +606872,7 @@ Example: ${tool.name}(${JSON.stringify(meta.examples[0].args ?? {})})` : "";
606948
606872
 
606949
606873
  Available tools (${deferred.length}):
606950
606874
  ${catalog}`,
606951
- parameters: this._withToolActionReasonSchema("tool_search", {
606875
+ parameters: this._publicToolParameters({
606952
606876
  type: "object",
606953
606877
  properties: {
606954
606878
  query: {
@@ -606999,7 +606923,7 @@ ${catalog}`,
606999
606923
  lines.push(`Aliases: ${tool.aliases.join(", ")}`);
607000
606924
  }
607001
606925
  lines.push(`${getDesc(tool)}${customToolDetails(tool)}`);
607002
- lines.push(`Parameters: ${JSON.stringify(this._withToolActionReasonSchema(tool.name, tool.parameters))}`);
606926
+ lines.push(`Parameters: ${JSON.stringify(this._publicToolParameters(tool.parameters))}`);
607003
606927
  }
607004
606928
  }
607005
606929
  if (alreadyAvailable.length > 0) {
@@ -607051,7 +606975,7 @@ ${catalog}`,
607051
606975
  for (const t2 of matches)
607052
606976
  activatedToolsRef.add(t2.name);
607053
606977
  const result = matches.map((t2) => {
607054
- const paramsStr = JSON.stringify(this._withToolActionReasonSchema(t2.name, t2.parameters), null, 2);
606978
+ const paramsStr = JSON.stringify(this._publicToolParameters(t2.parameters), null, 2);
607055
606979
  const aliases = t2.aliases?.length ? `
607056
606980
  Aliases: ${t2.aliases.join(", ")}` : "";
607057
606981
  return `## ${t2.name}${aliases}