open-agents-ai 0.187.574 → 0.187.575

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
@@ -528111,6 +528111,10 @@ var init_agenticRunner = __esm({
528111
528111
  // can re-emit the same plan a second time (plan-replay) and execute
528112
528112
  // duplicate work because PROGRESS NUDGE alone is informational.
528113
528113
  _progressGateActive = false;
528114
+ // Consecutive gate blocks count. When the model ignores the gate and
528115
+ // retries a blocked tool, this counter increments. ≥2 triggers a system
528116
+ // message escalation to break pattern-lock loops.
528117
+ _consecutiveGateBlocks = 0;
528114
528118
  // REG-5: Rolling buffer of recent tool failures with their error output.
528115
528119
  // Surfaced before every LLM call so the agent can't ignore "I just ran this
528116
528120
  // and it errored". Detects same-fingerprint failure repetition and escalates
@@ -528360,15 +528364,19 @@ var init_agenticRunner = __esm({
528360
528364
  // DECOMP-2 (root-cause from batch531-midi-decomp, 2026-05-03): compelling
528361
528365
  // sub_agent delegation. DECOMP-1's informational directive was ignored
528362
528366
  // (0 sub_agent calls in 466 tool-call run despite directive at turn 1).
528363
- // Mirrors the BFC-61.G escalation arc: when the agent has edited
528364
- // ≥THRESHOLD distinct files in main context WITHOUT successful sub_agent,
528367
+ // Mirrors the BFC-61.G escalation arc, but must not deadlock delivery:
528368
+ // when the agent has edited adaptive-threshold distinct files in main context
528369
+ // WITHOUT successful sub_agent,
528365
528370
  // the dispatcher BLOCKS edits to NEW files (paths not yet edited) until
528366
528371
  // sub_agent succeeds. Edits to already-touched files are still allowed
528367
- // (current-module finishing work). Failed or malformed delegation does
528368
- // not clear the gate.
528372
+ // (current-module finishing work). Repeated failed delegation attempts
528373
+ // unlock a main-context fallback so the guardrail cannot become a hard
528374
+ // write-deadlock when sub_agent itself is broken or unavailable.
528369
528375
  // Kill switch: OA_DISABLE_DECOMP2=1.
528370
528376
  _decomp2MainContextFiles = /* @__PURE__ */ new Set();
528371
528377
  _decomp2SubAgentCalls = 0;
528378
+ _decomp2FailedDelegationCalls = 0;
528379
+ _decomp2FallbackAllowed = false;
528372
528380
  _decomp2GateActive = false;
528373
528381
  // MEM_PATH item #9: adaptive retrieval cache. When the (goalHash, recent-tool-sig)
528374
528382
  // hasn't changed since last retrieval, skip the PPR call entirely and reuse
@@ -528913,6 +528921,8 @@ Pick the SMALLEST concrete deliverable from the spec — typically the project e
528913
528921
  _maybeDecomp2Block(tc, turn) {
528914
528922
  if (!this._decomp2GateActive)
528915
528923
  return null;
528924
+ if (this._decomp2FallbackAllowed)
528925
+ return null;
528916
528926
  if (process.env["OA_DISABLE_DECOMP2"] === "1")
528917
528927
  return null;
528918
528928
  const _editTools = /* @__PURE__ */ new Set([
@@ -528933,7 +528943,7 @@ Pick the SMALLEST concrete deliverable from the spec — typically the project e
528933
528943
  const decomp2Msg = [
528934
528944
  `[BLOCKED — DECOMP-2 main-context exhaustion]`,
528935
528945
  ``,
528936
- `You have already edited ${this._decomp2MainContextFiles.size} distinct files in main context without invoking sub_agent. Continuing to edit ANOTHER new file ('${_editPath}') will keep your context window saturated and trigger compaction thrashing.`,
528946
+ `You have already edited ${this._decomp2MainContextFiles.size} distinct files in main context without a successful sub_agent. Continuing to edit another new file ('${_editPath}') may keep your context window saturated and trigger compaction thrashing.`,
528937
528947
  ``,
528938
528948
  `Files you've already edited (will accept further edits to these):`,
528939
528949
  _filesList,
@@ -528949,13 +528959,15 @@ Pick the SMALLEST concrete deliverable from the spec — typically the project e
528949
528959
  ` })`,
528950
528960
  ` 3. After sub_agent returns, mark the todo completed.`,
528951
528961
  ``,
528962
+ `If sub_agent keeps failing for reasons outside the module work, retry it once with corrected arguments. After repeated failed delegation attempts, OA will downgrade this from a hard block to an advisory fallback so file writes can continue.`,
528963
+ ``,
528952
528964
  `Why this matters: spreading edits across N files in main context burns ~N × file_size tokens. sub_agent gives the next module a focused context window.`,
528953
528965
  ``,
528954
528966
  `If you have ALREADY edited '${_editPath}' (this is a continuation), the orchestrator's set must have missed it — call file_read to verify, then re-edit. Otherwise, dispatch sub_agent now.`
528955
528967
  ].join("\n");
528956
528968
  this.emit({
528957
528969
  type: "status",
528958
- content: `DECOMP-2 NEW-FILE BLOCK — rejected ${tc.name}('${_editPath}') at turn ${turn}; gate stays active until sub_agent succeeds`,
528970
+ content: `DECOMP-2 NEW-FILE BLOCK — rejected ${tc.name}('${_editPath}') at turn ${turn}; gate stays active until sub_agent succeeds or repeated delegation failure unlocks fallback`,
528959
528971
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
528960
528972
  });
528961
528973
  this._tagSyntheticFailure({
@@ -528964,6 +528976,12 @@ Pick the SMALLEST concrete deliverable from the spec — typically the project e
528964
528976
  });
528965
528977
  return decomp2Msg;
528966
528978
  }
528979
+ _decomp2FileSpreadThreshold() {
528980
+ const ctx3 = this.options.contextWindowSize ?? 0;
528981
+ if (ctx3 <= 0)
528982
+ return 5;
528983
+ return Math.max(5, Math.min(30, Math.round(ctx3 / 6400)));
528984
+ }
528967
528985
  /**
528968
528986
  * DECOMP-2 post-dispatch tracking. Refactored from inline so both the
528969
528987
  * main turn loop AND the brute-force re-engagement inner loop record
@@ -528990,12 +529008,12 @@ Pick the SMALLEST concrete deliverable from the spec — typically the project e
528990
529008
  const _editPaths = this._extractToolTargetPaths(tc.name, tc.arguments, result);
528991
529009
  for (const _editPath of _editPaths) {
528992
529010
  this._decomp2MainContextFiles.add(_editPath);
528993
- const DECOMP2_FILE_SPREAD_THRESHOLD = 5;
528994
- if (!this._decomp2GateActive && this._decomp2MainContextFiles.size >= DECOMP2_FILE_SPREAD_THRESHOLD && this._decomp2SubAgentCalls === 0) {
529011
+ const DECOMP2_FILE_SPREAD_THRESHOLD = this._decomp2FileSpreadThreshold();
529012
+ if (!this._decomp2GateActive && !this._decomp2FallbackAllowed && this._decomp2MainContextFiles.size >= DECOMP2_FILE_SPREAD_THRESHOLD && this._decomp2SubAgentCalls === 0) {
528995
529013
  this._decomp2GateActive = true;
528996
529014
  this.emit({
528997
529015
  type: "status",
528998
- content: `DECOMP-2 NEW-FILE GATE ACTIVATED — ${this._decomp2MainContextFiles.size} distinct files edited in main context, 0 successful sub_agent calls; further edits to NEW files will be blocked until sub_agent succeeds`,
529016
+ content: `DECOMP-2 NEW-FILE GATE ACTIVATED — ${this._decomp2MainContextFiles.size} distinct files edited in main context, 0 successful sub_agent calls, threshold=${DECOMP2_FILE_SPREAD_THRESHOLD}; further edits to NEW files will be blocked until sub_agent succeeds or repeated delegation failure unlocks fallback`,
528999
529017
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
529000
529018
  });
529001
529019
  }
@@ -529004,15 +529022,27 @@ Pick the SMALLEST concrete deliverable from the spec — typically the project e
529004
529022
  if (tc.name === "sub_agent" || tc.name === "priority_delegate" || tc.name === "background_run") {
529005
529023
  if (result?.success !== true) {
529006
529024
  if (this._decomp2GateActive) {
529025
+ this._decomp2FailedDelegationCalls++;
529007
529026
  this.emit({
529008
529027
  type: "status",
529009
529028
  content: `DECOMP-2 DELEGATION FAILED — '${tc.name}' did not clear gate at turn ${turn}; fix delegation arguments/result before editing another new file`,
529010
529029
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
529011
529030
  });
529031
+ if (this._decomp2FailedDelegationCalls >= 2) {
529032
+ this._decomp2FallbackAllowed = true;
529033
+ this._decomp2GateActive = false;
529034
+ this.emit({
529035
+ type: "status",
529036
+ content: `DECOMP-2 FALLBACK UNLOCKED — ${this._decomp2FailedDelegationCalls} failed delegation attempts while gate was active; allowing main-context new-file edits so work can continue`,
529037
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
529038
+ });
529039
+ }
529012
529040
  }
529013
529041
  return;
529014
529042
  }
529015
529043
  this._decomp2SubAgentCalls++;
529044
+ this._decomp2FailedDelegationCalls = 0;
529045
+ this._decomp2FallbackAllowed = false;
529016
529046
  if (this._decomp2GateActive) {
529017
529047
  this._decomp2GateActive = false;
529018
529048
  this.emit({
@@ -531100,6 +531130,8 @@ Respond with your assessment, then take action.`;
531100
531130
  this._reg61PerpetualGateActive = false;
531101
531131
  this._decomp2MainContextFiles = /* @__PURE__ */ new Set();
531102
531132
  this._decomp2SubAgentCalls = 0;
531133
+ this._decomp2FailedDelegationCalls = 0;
531134
+ this._decomp2FallbackAllowed = false;
531103
531135
  this._decomp2GateActive = false;
531104
531136
  if (!globalThis.__oa_rca1_sigterm_installed) {
531105
531137
  globalThis.__oa_rca1_sigterm_installed = true;
@@ -533438,22 +533470,25 @@ ${memoryLines.join("\n")}`
533438
533470
  recentWrites.push({ path: path11, turn: info.lastWriteTurn ?? 0 });
533439
533471
  }
533440
533472
  }
533473
+ this._consecutiveGateBlocks++;
533441
533474
  recentWrites.sort((a2, b) => b.turn - a2.turn);
533442
533475
  const showWrites = recentWrites.slice(0, 16);
533476
+ const isRepeat = this._consecutiveGateBlocks >= 2;
533443
533477
  const gateMsg = [
533444
- `[PROGRESS GATE call todo_write FIRST before any other tool]`,
533478
+ `[BLOCKEDPROGRESS GATE active]`,
533445
533479
  ``,
533446
- `You have completed ${this._writesSinceLastTodoWrite} file modification${this._writesSinceLastTodoWrite === 1 ? "" : "s"} since your last todo_write call.`,
533447
- `The next tool call MUST be todo_write to mark progress. This is enforced — non-todo tool calls are intercepted until plan state is updated.`,
533480
+ `CAUSE: ${this._writesSinceLastTodoWrite} file writes since last todo_write call. Without progress tracking, the next turn re-plans the same work (plan-replay).`,
533481
+ `EFFECT: All non-todo tool calls are now blocked at the runtime level.`,
533482
+ `ACTION REQUIRED: Call todo_write with updated progress to release the gate.`,
533483
+ `CONSEQUENCE OF IGNORING: Retrying blocked tools does NOT work — only todo_write is accepted while the gate is active.`,
533484
+ isRepeat ? `
533485
+ [ESCALATION: This is block #${this._consecutiveGateBlocks}. You keep calling blocked tools instead of todo_write. The gate cannot be bypassed. You MUST call todo_write next.]` : "",
533448
533486
  ``,
533449
533487
  `Recent file modifications (use these to decide what's done):`,
533450
533488
  ...showWrites.map((w) => ` • ${w.path} (turn ${w.turn})`),
533451
533489
  recentWrites.length > showWrites.length ? ` • ... +${recentWrites.length - showWrites.length} more` : "",
533452
533490
  ``,
533453
- `Required action: call todo_write with the updated todo array — mark anything completed that these writes satisfy, advance the next item to in_progress, keep the rest pending.`,
533454
- `After todo_write succeeds, this gate releases and you can continue normal work.`,
533455
- ``,
533456
- `Why this exists: without the explicit progress update, your next turn will see the same in_progress todo, re-plan the same work, and re-emit identical tool calls (the "plan replay" failure mode that causes byte-identical writes to appear twice).`
533491
+ `Format: todo_write with todos array — mark items completed that these writes satisfy, advance next to in_progress. After todo_write succeeds, normal tools resume.`
533457
533492
  ].filter(Boolean).join("\n");
533458
533493
  this.emit({
533459
533494
  type: "tool_result",
@@ -533939,6 +533974,7 @@ Respond with EXACTLY this structure before your next tool call:
533939
533974
  }
533940
533975
  this._writesSinceLastTodoWrite = 0;
533941
533976
  this._progressGateActive = false;
533977
+ this._consecutiveGateBlocks = 0;
533942
533978
  }
533943
533979
  if (tc.name === "file_read") {
533944
533980
  const p2 = String(tc.arguments?.["path"] ?? tc.arguments?.["file"] ?? "");
@@ -534947,6 +534983,12 @@ Then use file_read on individual FILES inside it.`);
534947
534983
  const output = sr.result.success ? sr.result.output : `Error: ${sr.result.error || "unknown"}
534948
534984
  ${sr.result.output}`;
534949
534985
  messages2.push(this.buildToolMessage(output, matchTc.id, matchTc.name));
534986
+ if (this._consecutiveGateBlocks >= 2 && this._progressGateActive) {
534987
+ messages2.push({
534988
+ role: "system",
534989
+ content: `[PROGRESS GATE ESCALATION] You have made ${this._consecutiveGateBlocks} consecutive blocked tool calls without calling todo_write. The gate is enforced at the runtime level — retrying the same blocked tool will never work. Your NEXT call MUST be todo_write(todos=[...]) with updated progress. No other tool will be accepted until the gate is released.`
534990
+ });
534991
+ }
534950
534992
  if (matchTc.name === "task_complete") {
534951
534993
  const open2 = this.getOpenTodoItems();
534952
534994
  if (open2.length > 0) {
@@ -534987,6 +535029,12 @@ ${sr.result.output}`;
534987
535029
  const r2 = await executeSingle(tc);
534988
535030
  if (r2) {
534989
535031
  messages2.push(this.buildToolMessage(r2.output, r2.tc.id, r2.tc.name));
535032
+ if (this._consecutiveGateBlocks >= 2 && this._progressGateActive) {
535033
+ messages2.push({
535034
+ role: "system",
535035
+ content: `[PROGRESS GATE ESCALATION] You have made ${this._consecutiveGateBlocks} consecutive blocked tool calls without calling todo_write. The gate is enforced at the runtime level — retrying the same blocked tool will never work. Your NEXT call MUST be todo_write(todos=[...]) with updated progress. No other tool will be accepted until the gate is released.`
535036
+ });
535037
+ }
534990
535038
  if (r2.tc.name === "task_complete") {
534991
535039
  const open2 = this.getOpenTodoItems();
534992
535040
  if (open2.length > 0) {
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "open-agents-ai",
3
- "version": "0.187.574",
3
+ "version": "0.187.575",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "open-agents-ai",
9
- "version": "0.187.574",
9
+ "version": "0.187.575",
10
10
  "hasInstallScript": true,
11
11
  "license": "CC-BY-NC-4.0",
12
12
  "dependencies": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-agents-ai",
3
- "version": "0.187.574",
3
+ "version": "0.187.575",
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",