open-agents-ai 0.187.476 → 0.187.477

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
@@ -282094,14 +282094,14 @@ ${lanes.join("\n")}
282094
282094
  return { value: value2, isSyntacticallyString, resolvedOtherFiles, hasExternalReferences };
282095
282095
  }
282096
282096
  function createEvaluator({ evaluateElementAccessExpression, evaluateEntityNameExpression }) {
282097
- function evaluate2(expr, location) {
282097
+ function evaluate3(expr, location) {
282098
282098
  let isSyntacticallyString = false;
282099
282099
  let resolvedOtherFiles = false;
282100
282100
  let hasExternalReferences = false;
282101
282101
  expr = skipParentheses(expr);
282102
282102
  switch (expr.kind) {
282103
282103
  case 225:
282104
- const result = evaluate2(expr.operand, location);
282104
+ const result = evaluate3(expr.operand, location);
282105
282105
  resolvedOtherFiles = result.resolvedOtherFiles;
282106
282106
  hasExternalReferences = result.hasExternalReferences;
282107
282107
  if (typeof result.value === "number") {
@@ -282116,8 +282116,8 @@ ${lanes.join("\n")}
282116
282116
  }
282117
282117
  break;
282118
282118
  case 227: {
282119
- const left = evaluate2(expr.left, location);
282120
- const right = evaluate2(expr.right, location);
282119
+ const left = evaluate3(expr.left, location);
282120
+ const right = evaluate3(expr.right, location);
282121
282121
  isSyntacticallyString = (left.isSyntacticallyString || right.isSyntacticallyString) && expr.operatorToken.kind === 40;
282122
282122
  resolvedOtherFiles = left.resolvedOtherFiles || right.resolvedOtherFiles;
282123
282123
  hasExternalReferences = left.hasExternalReferences || right.hasExternalReferences;
@@ -282192,7 +282192,7 @@ ${lanes.join("\n")}
282192
282192
  let resolvedOtherFiles = false;
282193
282193
  let hasExternalReferences = false;
282194
282194
  for (const span of expr.templateSpans) {
282195
- const spanResult = evaluate2(span.expression, location);
282195
+ const spanResult = evaluate3(span.expression, location);
282196
282196
  if (spanResult.value === void 0) {
282197
282197
  return evaluatorResult(
282198
282198
  /*value*/
@@ -282214,7 +282214,7 @@ ${lanes.join("\n")}
282214
282214
  hasExternalReferences
282215
282215
  );
282216
282216
  }
282217
- return evaluate2;
282217
+ return evaluate3;
282218
282218
  }
282219
282219
  function isConstAssertion(location) {
282220
282220
  return isAssertionExpression(location) && isConstTypeReference(location.type) || isJSDocTypeTag(location) && isConstTypeReference(location.typeExpression);
@@ -312752,7 +312752,7 @@ ${lanes.join("\n")}
312752
312752
  var emitResolver = createResolver();
312753
312753
  var nodeBuilder = createNodeBuilder();
312754
312754
  var syntacticNodeBuilder = createSyntacticTypeNodeBuilder(compilerOptions, nodeBuilder.syntacticBuilderResolver);
312755
- var evaluate2 = createEvaluator({
312755
+ var evaluate3 = createEvaluator({
312756
312756
  evaluateElementAccessExpression,
312757
312757
  evaluateEntityNameExpression
312758
312758
  });
@@ -348722,7 +348722,7 @@ ${lanes.join("\n")}
348722
348722
  case 72:
348723
348723
  case 50:
348724
348724
  case 73:
348725
- const rhsEval = evaluate2(right);
348725
+ const rhsEval = evaluate3(right);
348726
348726
  if (typeof rhsEval.value === "number" && Math.abs(rhsEval.value) >= 32) {
348727
348727
  errorOrSuggestion(
348728
348728
  isEnumMember(walkUpParenthesizedExpressions(right.parent.parent)),
@@ -349225,7 +349225,7 @@ ${lanes.join("\n")}
349225
349225
  texts.push(span.literal.text);
349226
349226
  types2.push(isTypeAssignableTo(type, templateConstraintType) ? type : stringType);
349227
349227
  }
349228
- const evaluated = node.parent.kind !== 216 && evaluate2(node).value;
349228
+ const evaluated = node.parent.kind !== 216 && evaluate3(node).value;
349229
349229
  if (evaluated) {
349230
349230
  return getFreshTypeOfLiteralType(getStringLiteralType(evaluated));
349231
349231
  }
@@ -354706,7 +354706,7 @@ ${lanes.join("\n")}
354706
354706
  function computeConstantEnumMemberValue(member) {
354707
354707
  const isConstEnum = isEnumConst(member.parent);
354708
354708
  const initializer = member.initializer;
354709
- const result = evaluate2(initializer, member);
354709
+ const result = evaluate3(initializer, member);
354710
354710
  if (result.value !== void 0) {
354711
354711
  if (isConstEnum && typeof result.value === "number" && !isFinite(result.value)) {
354712
354712
  error2(
@@ -354761,7 +354761,7 @@ ${lanes.join("\n")}
354761
354761
  if (isConstantVariable(symbol3)) {
354762
354762
  const declaration = symbol3.valueDeclaration;
354763
354763
  if (declaration && isVariableDeclaration(declaration) && !declaration.type && declaration.initializer && (!location || declaration !== location && isBlockScopedNameDeclaredBeforeUse(declaration, location))) {
354764
- const result = evaluate2(declaration.initializer, declaration);
354764
+ const result = evaluate3(declaration.initializer, declaration);
354765
354765
  if (location && getSourceFileOfNode(location) !== getSourceFileOfNode(declaration)) {
354766
354766
  return evaluatorResult(
354767
354767
  result.value,
@@ -512128,6 +512128,106 @@ var init_personality = __esm({
512128
512128
  }
512129
512129
  });
512130
512130
 
512131
+ // packages/orchestrator/dist/critic.js
512132
+ function buildForceProgressBlockMessage(call, hits) {
512133
+ const argPreview = JSON.stringify(call.args ?? {}).slice(0, 200);
512134
+ return `[FORCED PROGRESS BLOCK — you have called ${call.tool}(${argPreview}) ${hits} times with identical arguments and received the cached result each time. The data is not changing. You are stuck in a read-only loop instead of advancing the plan.
512135
+
512136
+ REQUIRED before this tool will run again with these arguments:
512137
+ • file_write or file_edit, OR
512138
+ • todo_write that advances the plan, OR
512139
+ • task_complete (if all phases are done).
512140
+
512141
+ If you genuinely need this same data again, call a DIFFERENT tool first (one of the three above). Until then, refer to your conversation history — the result of this exact call is already there.]`;
512142
+ }
512143
+ function evaluate(inputs) {
512144
+ const { proposedCall, fingerprint, isReadLike, recentToolResults, dedupHitCount, observerRedundantBlock } = inputs;
512145
+ if (observerRedundantBlock) {
512146
+ const cached = recentToolResults.get(fingerprint);
512147
+ return {
512148
+ decision: "observer_block",
512149
+ reason: "Littleman observer flagged this fingerprint as redundant",
512150
+ cachedResult: cached ? cached.result : null
512151
+ };
512152
+ }
512153
+ if (isReadLike) {
512154
+ const cached = recentToolResults.get(fingerprint);
512155
+ if (cached !== void 0) {
512156
+ const hits = (dedupHitCount.get(fingerprint) ?? 0) + 1;
512157
+ const threshold = proposedCall.tool === "shell" ? SHELL_THRESHOLD : FS_THRESHOLD;
512158
+ if (hits >= threshold) {
512159
+ return {
512160
+ decision: "force_progress_block",
512161
+ reason: `${proposedCall.tool} fingerprint hit count ${hits} >= ${threshold}`,
512162
+ hitNumber: hits,
512163
+ blockMessage: buildForceProgressBlockMessage(proposedCall, hits)
512164
+ };
512165
+ }
512166
+ return {
512167
+ decision: "serve_cached",
512168
+ reason: cached.compacted ? "post-compaction cache re-serve" : `duplicate call #${hits} (still under ${threshold}-hit gate)`,
512169
+ cachedResult: cached.result,
512170
+ compacted: cached.compacted,
512171
+ hitNumber: hits
512172
+ };
512173
+ }
512174
+ }
512175
+ return { decision: "pass" };
512176
+ }
512177
+ function buildStagnationDiagnostic(signals) {
512178
+ const variantList = signals.variantList.slice(0, 8).map((v) => ` • ${v}`).join("\n");
512179
+ return [
512180
+ `[STAGNATION DETECTED — DIAGNOSTIC MODE REQUIRED]`,
512181
+ ``,
512182
+ `Over the last ${signals.windowSamples} turns you have:`,
512183
+ ` • Completed 0 new todos`,
512184
+ ` • Written/edited only ${signals.filesDelta} unique file(s) (need ≥3 for healthy progress)`,
512185
+ ` • Accumulated ${signals.failureSum} failures`,
512186
+ ` • Tried ${signals.variantCount} different shell-command variants:`,
512187
+ variantList,
512188
+ ``,
512189
+ `You are not making progress — you are trying surface-level variants of the same approach without diagnosing root cause. This is the failure mode that prevents real completion.`,
512190
+ ``,
512191
+ `MANDATORY NEXT ACTIONS (do NOT call task_complete; do NOT try another variant):`,
512192
+ ``,
512193
+ `1. READ THE FULL ERROR — re-read your most recent failure output ENTIRELY. If it's in a log packet, call log_explore({op:"errors"}) then log_explore({op:"lines", start:..., end:...}) for context. Do not skim.`,
512194
+ ``,
512195
+ `2. STATE A HYPOTHESIS in writing — what specifically is wrong? "I think X is failing because Y." Be concrete. Do NOT propose a fix yet.`,
512196
+ ``,
512197
+ `3. VERIFY ONE ASSUMPTION — pick the ONE thing you most BELIEVE to be true and test it with the smallest possible command:`,
512198
+ ` • If you think a package is installed: ls node_modules/<name>/package.json`,
512199
+ ` • If you think an env var is set: printenv <NAME>`,
512200
+ ` • If you think a file imports correctly: head -5 <file>`,
512201
+ ` • If you don't know what an error means: web_search("<exact error string>")`,
512202
+ ``,
512203
+ `4. CHECK SILENT FAILURES — npm install reporting "added N packages" does NOT mean ALL declared deps installed; npm sometimes drops packages with peer-dep conflicts without erroring. Verify each expected dep individually.`,
512204
+ ``,
512205
+ `DO NOT in your next response:`,
512206
+ ` • Try another version, flag, or variant of any command in the list above`,
512207
+ ` • Wipe node_modules / re-install — that hides the original error`,
512208
+ ` • Call task_complete — being stuck on a debug problem is NEVER grounds for task_complete`,
512209
+ ``,
512210
+ `task_complete is ONLY for actual completion or unrecoverable hardware/permission errors. You are stuck on a fixable problem; diagnose it.`
512211
+ ].join("\n");
512212
+ }
512213
+ function isStagnant(signals, opts) {
512214
+ const failureThreshold = opts?.failureThreshold ?? 5;
512215
+ const variantThreshold = opts?.variantThreshold ?? 4;
512216
+ const filesDeltaMin = opts?.filesDeltaMin ?? 3;
512217
+ const minSamples = opts?.minSamples ?? 30;
512218
+ if (signals.windowSamples < minSamples)
512219
+ return false;
512220
+ return signals.completedDelta === 0 && signals.filesDelta < filesDeltaMin && signals.failureSum >= failureThreshold && signals.variantCount >= variantThreshold;
512221
+ }
512222
+ var SHELL_THRESHOLD, FS_THRESHOLD;
512223
+ var init_critic = __esm({
512224
+ "packages/orchestrator/dist/critic.js"() {
512225
+ "use strict";
512226
+ SHELL_THRESHOLD = 2;
512227
+ FS_THRESHOLD = 3;
512228
+ }
512229
+ });
512230
+
512131
512231
  // packages/orchestrator/dist/pressure-gate.js
512132
512232
  function detectPressure(message2) {
512133
512233
  const hasProfanity = PRESSURE_SIGNALS.test(message2);
@@ -514455,7 +514555,7 @@ function h10(t2) {
514455
514555
  function h11(t2) {
514456
514556
  return t2 * t2 * (t2 - 1);
514457
514557
  }
514458
- function evaluate(controls, r2) {
514558
+ function evaluate2(controls, r2) {
514459
514559
  const { K: K2, N, P: P2, E: Eb, Pd, Ed, expansion, epsSigma, deltaMax } = controls;
514460
514560
  const eps2 = epsSigma * epsSigma;
514461
514561
  const u = new Float64Array(K2);
@@ -514731,7 +514831,7 @@ function deserialize(obj) {
514731
514831
  function rmse(controls, samples) {
514732
514832
  let sumSq = 0;
514733
514833
  for (const s2 of samples) {
514734
- const pred = evaluate(controls, s2.input);
514834
+ const pred = evaluate2(controls, s2.input);
514735
514835
  for (let n2 = 0; n2 < controls.N; n2++) {
514736
514836
  const diff = pred[n2] - s2.output[n2];
514737
514837
  sumSq += diff * diff;
@@ -514906,7 +515006,7 @@ var init_embeddingAligner = __esm({
514906
515006
  const range = max - min;
514907
515007
  normalized[k] = range > 1e-10 ? Math.max(0, Math.min(1, (projected[k] - min) / range)) : 0.5;
514908
515008
  }
514909
- const aligned64 = evaluate(this.state.controls, normalized);
515009
+ const aligned64 = evaluate2(this.state.controls, normalized);
514910
515010
  const result = new Float32Array(this.state.dstDim);
514911
515011
  for (let n2 = 0; n2 < this.state.dstDim; n2++)
514912
515012
  result[n2] = aligned64[n2];
@@ -514993,7 +515093,7 @@ var init_embeddingAligner = __esm({
514993
515093
  let avgCosine = 0;
514994
515094
  if (testSamples.length > 0) {
514995
515095
  for (const s2 of testSamples) {
514996
- const pred = evaluate(controls, s2.input);
515096
+ const pred = evaluate2(controls, s2.input);
514997
515097
  avgCosine += cosine(pred, s2.output);
514998
515098
  }
514999
515099
  avgCosine /= testSamples.length;
@@ -516500,7 +516600,7 @@ __export(dist_exports2, {
516500
516600
  retrieveByPPR: () => retrieveByPPR,
516501
516601
  splanifoldCosine: () => cosine,
516502
516602
  splanifoldDeserialize: () => deserialize,
516503
- splanifoldEvaluate: () => evaluate,
516603
+ splanifoldEvaluate: () => evaluate2,
516504
516604
  splanifoldFit: () => fit,
516505
516605
  splanifoldRmse: () => rmse,
516506
516606
  splanifoldSerialize: () => serialize
@@ -518372,6 +518472,7 @@ var init_agenticRunner = __esm({
518372
518472
  init_dist();
518373
518473
  init_personality();
518374
518474
  init_promptLoader();
518475
+ init_critic();
518375
518476
  init_pressure_gate();
518376
518477
  init_dist5();
518377
518478
  init_dist7();
@@ -520658,53 +520759,30 @@ TASK: ${task}` : task;
520658
520759
  for (const s2 of stagnationWindow)
520659
520760
  for (const p2 of s2.filesTouchedThisTurn)
520660
520761
  fileSet.add(p2);
520661
- const filesDelta = fileSet.size;
520662
- const failureSum = stagnationWindow.reduce((a2, s2) => a2 + s2.failuresThisTurn, 0);
520663
520762
  const variantSet = /* @__PURE__ */ new Set();
520664
520763
  for (const s2 of stagnationWindow)
520665
520764
  for (const p2 of s2.shellPrefixesThisTurn)
520666
520765
  variantSet.add(p2);
520667
- const variantCount = variantSet.size;
520668
- if (completedDelta === 0 && filesDelta < STAG_FILES_DELTA_MIN && failureSum >= STAG_FAILURE_THRESHOLD && variantCount >= STAG_VARIANT_THRESHOLD) {
520669
- const variantList = [...variantSet].slice(0, 8).map((v) => ` • ${v}`).join("\n");
520670
- const stagMsg = [
520671
- `[STAGNATION DETECTED — DIAGNOSTIC MODE REQUIRED]`,
520672
- ``,
520673
- `Over the last ${stagnationWindow.length} turns you have:`,
520674
- ` • Completed 0 new todos`,
520675
- ` • Written/edited only ${filesDelta} unique file(s) (need ≥${STAG_FILES_DELTA_MIN} for healthy progress)`,
520676
- ` • Accumulated ${failureSum} failures`,
520677
- ` • Tried ${variantCount} different shell-command variants:`,
520678
- variantList,
520679
- ``,
520680
- `You are not making progress — you are trying surface-level variants of the same approach without diagnosing root cause. This is the failure mode that prevents real completion.`,
520681
- ``,
520682
- `MANDATORY NEXT ACTIONS (do NOT call task_complete; do NOT try another variant):`,
520683
- ``,
520684
- `1. READ THE FULL ERROR — re-read your most recent failure output ENTIRELY. If it's in a log packet, call log_explore({op:"errors"}) then log_explore({op:"lines", start:..., end:...}) for context. Do not skim.`,
520685
- ``,
520686
- `2. STATE A HYPOTHESIS in writing — what specifically is wrong? "I think X is failing because Y." Be concrete. Do NOT propose a fix yet.`,
520687
- ``,
520688
- `3. VERIFY ONE ASSUMPTION — pick the ONE thing you most BELIEVE to be true and test it with the smallest possible command:`,
520689
- ` • If you think a package is installed: ls node_modules/<name>/package.json`,
520690
- ` • If you think an env var is set: printenv <NAME>`,
520691
- ` • If you think a file imports correctly: head -5 <file>`,
520692
- ` • If you don't know what an error means: web_search("<exact error string>")`,
520693
- ``,
520694
- `4. CHECK SILENT FAILURES — npm install reporting "added N packages" does NOT mean ALL declared deps installed; npm sometimes drops packages with peer-dep conflicts without erroring. Verify each expected dep individually.`,
520695
- ``,
520696
- `DO NOT in your next response:`,
520697
- ` • Try another version, flag, or variant of any command in the list above`,
520698
- ` • Wipe node_modules / re-install — that hides the original error`,
520699
- ` • Call task_complete — being stuck on a debug problem is NEVER grounds for task_complete`,
520700
- ``,
520701
- `task_complete is ONLY for actual completion or unrecoverable hardware/permission errors. You are stuck on a fixable problem; diagnose it.`
520702
- ].join("\n");
520703
- messages2.push({ role: "system", content: stagMsg });
520766
+ const failureSum = stagnationWindow.reduce((a2, s2) => a2 + s2.failuresThisTurn, 0);
520767
+ const signals = {
520768
+ completedDelta,
520769
+ filesDelta: fileSet.size,
520770
+ failureSum,
520771
+ variantCount: variantSet.size,
520772
+ windowSamples: stagnationWindow.length,
520773
+ variantList: [...variantSet]
520774
+ };
520775
+ if (isStagnant(signals, {
520776
+ failureThreshold: STAG_FAILURE_THRESHOLD,
520777
+ variantThreshold: STAG_VARIANT_THRESHOLD,
520778
+ filesDeltaMin: STAG_FILES_DELTA_MIN,
520779
+ minSamples: STAG_MIN_SAMPLES
520780
+ })) {
520781
+ messages2.push({ role: "system", content: buildStagnationDiagnostic(signals) });
520704
520782
  stagnationCooldownUntilTurn = turn + 5;
520705
520783
  this.emit({
520706
520784
  type: "status",
520707
- content: `STAGNATION DETECTED — injected diagnostic mode at turn ${turn} (${variantCount} variants, ${failureSum} failures, ${filesDelta} files in window)`,
520785
+ content: `STAGNATION DETECTED — injected diagnostic mode at turn ${turn} (${signals.variantCount} variants, ${signals.failureSum} failures, ${signals.filesDelta} files in window)`,
520708
520786
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
520709
520787
  });
520710
520788
  }
@@ -521509,16 +521587,6 @@ ${memoryLines.join("\n")}`
521509
521587
  toolCallBudget.set(tc.name, budgetRemaining - 1);
521510
521588
  }
521511
521589
  const toolFingerprint = `${tc.name}:${argsKey}`;
521512
- if (this._littlemanRedundantBlocks.has(toolFingerprint)) {
521513
- this._littlemanRedundantBlocks.delete(toolFingerprint);
521514
- const cachedEntry2 = recentToolResults.get(toolFingerprint);
521515
- this.emit({ type: "tool_call", toolName: tc.name, toolArgs: tc.arguments, turn, timestamp: (/* @__PURE__ */ new Date()).toISOString() });
521516
- const blockMsg = cachedEntry2 ? `[BLOCKED — this tool+args already succeeded. Re-served from cache:]
521517
-
521518
- ${cachedEntry2.result.slice(0, 500)}` : `[BLOCKED — the observer confirmed this tool already succeeded with these arguments on a prior turn. Do NOT re-run. Use your prior findings to proceed.]`;
521519
- this.emit({ type: "tool_result", toolName: tc.name, success: true, content: blockMsg.slice(0, 100), turn, timestamp: (/* @__PURE__ */ new Date()).toISOString() });
521520
- return { tc, output: blockMsg };
521521
- }
521522
521590
  const baseIsReadLike = ![
521523
521591
  "file_write",
521524
521592
  "file_edit",
@@ -521535,22 +521603,53 @@ ${cachedEntry2.result.slice(0, 500)}` : `[BLOCKED — the observer confirmed thi
521535
521603
  "sub_agent",
521536
521604
  "priority_delegate",
521537
521605
  "ask_user",
521538
- // WO-TASK-02 — todo_write is a state-write tool. Calling it twice
521539
- // with the same args is idempotent (it just re-stores the same
521540
- // list) but the dedup detector was flagging it as a wasted call
521541
- // and blocking the planning workflow. The agent uses todo_write
521542
- // as its primary checkpoint mechanism so it MUST always execute.
521543
521606
  "todo_write",
521544
- // nexus is also a state tool — connect is idempotent but the
521545
- // dedup warning was causing confused agents to bail out to
521546
- // shell workarounds (npm install, find /bin, etc.) when they
521547
- // saw "DUPLICATE CALL" after their first connect. Let the
521548
- // tool see every call and return the cached state itself.
521549
521607
  "nexus"
521550
521608
  ].includes(tc.name);
521551
521609
  const isReadLike = baseIsReadLike || tc.name === "shell" && this._isShellCommandReadOnly(tc.arguments?.["command"] ?? tc.arguments?.["cmd"] ?? "");
521552
- const cachedEntry = recentToolResults.get(toolFingerprint);
521553
- if (isReadLike && cachedEntry !== void 0) {
521610
+ const observerRedundantBlock = this._littlemanRedundantBlocks.has(toolFingerprint);
521611
+ if (observerRedundantBlock) {
521612
+ this._littlemanRedundantBlocks.delete(toolFingerprint);
521613
+ }
521614
+ const criticDecision = evaluate({
521615
+ proposedCall: { tool: tc.name, args: tc.arguments ?? {} },
521616
+ fingerprint: toolFingerprint,
521617
+ isReadLike,
521618
+ recentToolResults,
521619
+ dedupHitCount,
521620
+ recentFailures: this._recentFailures.map((f2) => ({
521621
+ fingerprint: f2.fingerprint,
521622
+ toolName: f2.tool,
521623
+ errorPreview: (f2.error || f2.output || "").slice(0, 200)
521624
+ })),
521625
+ stagnationSignals: null,
521626
+ // stagnation gate handled at top-of-turn
521627
+ stagnationGateActive: false,
521628
+ observerRedundantBlock
521629
+ });
521630
+ if (criticDecision.decision === "observer_block") {
521631
+ this.emit({ type: "tool_call", toolName: tc.name, toolArgs: tc.arguments, turn, timestamp: (/* @__PURE__ */ new Date()).toISOString() });
521632
+ const blockMsg = criticDecision.cachedResult ? `[BLOCKED — this tool+args already succeeded. Re-served from cache:]
521633
+
521634
+ ${criticDecision.cachedResult.slice(0, 500)}` : `[BLOCKED — the observer confirmed this tool already succeeded with these arguments on a prior turn. Do NOT re-run. Use your prior findings to proceed.]`;
521635
+ this.emit({ type: "tool_result", toolName: tc.name, success: true, content: blockMsg.slice(0, 100), turn, timestamp: (/* @__PURE__ */ new Date()).toISOString() });
521636
+ return { tc, output: blockMsg };
521637
+ }
521638
+ if (criticDecision.decision === "force_progress_block") {
521639
+ dedupHitCount.set(toolFingerprint, criticDecision.hitNumber);
521640
+ this.emit({ type: "tool_call", toolName: tc.name, toolArgs: tc.arguments, turn, timestamp: (/* @__PURE__ */ new Date()).toISOString() });
521641
+ this.emit({
521642
+ type: "tool_result",
521643
+ toolName: tc.name,
521644
+ success: false,
521645
+ content: criticDecision.blockMessage.slice(0, 120),
521646
+ turn,
521647
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
521648
+ });
521649
+ return { tc, output: criticDecision.blockMessage };
521650
+ }
521651
+ if (criticDecision.decision === "serve_cached") {
521652
+ dedupHitCount.set(toolFingerprint, criticDecision.hitNumber);
521554
521653
  this.emit({
521555
521654
  type: "tool_call",
521556
521655
  toolName: tc.name,
@@ -521558,36 +521657,13 @@ ${cachedEntry2.result.slice(0, 500)}` : `[BLOCKED — the observer confirmed thi
521558
521657
  turn,
521559
521658
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
521560
521659
  });
521561
- const hits = (dedupHitCount.get(toolFingerprint) ?? 0) + 1;
521562
- dedupHitCount.set(toolFingerprint, hits);
521563
- const threshold = tc.name === "shell" ? 2 : DEDUP_ESCALATION_THRESHOLD;
521564
- if (hits >= threshold) {
521565
- const argPreview = JSON.stringify(tc.arguments ?? {}).slice(0, 200);
521566
- const blockMsg = `[FORCED PROGRESS BLOCK — you have called ${tc.name}(${argPreview}) ${hits} times with identical arguments and received the cached result each time. The data is not changing. You are stuck in a read-only loop instead of advancing the plan.
521567
-
521568
- REQUIRED before this tool will run again with these arguments:
521569
- • file_write or file_edit, OR
521570
- • todo_write that advances the plan, OR
521571
- • task_complete (if all phases are done).
521572
-
521573
- If you genuinely need this same data again, call a DIFFERENT tool first (one of the three above). Until then, refer to your conversation history — the result of this exact call is already there.]`;
521574
- this.emit({
521575
- type: "tool_result",
521576
- toolName: tc.name,
521577
- success: false,
521578
- content: blockMsg.slice(0, 120),
521579
- turn,
521580
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
521581
- });
521582
- return { tc, output: blockMsg };
521583
- }
521584
- const header = cachedEntry.compacted ? `[RE-SERVED FROM CACHE — the original result was compacted from context. Here is the data again. No need to call this tool again.]
521660
+ const header = criticDecision.compacted ? `[RE-SERVED FROM CACHE — the original result was compacted from context. Here is the data again. No need to call this tool again.]
521585
521661
 
521586
- ` : `[DUPLICATE CALL #${hits} — you already called ${tc.name} with these exact arguments. The result is identical. Do NOT call this again. Use the data you already have to make progress. One more identical call will trigger a hard progress block.]
521662
+ ` : `[DUPLICATE CALL #${criticDecision.hitNumber} — you already called ${tc.name} with these exact arguments. The result is identical. Do NOT call this again. Use the data you already have to make progress. One more identical call will trigger a hard progress block.]
521587
521663
 
521588
521664
  `;
521589
- const truncatedCache = cachedEntry.result.length > 500 ? cachedEntry.result.slice(0, 500) + `
521590
- ... [${cachedEntry.result.length - 500} chars omitted — same as before]` : cachedEntry.result;
521665
+ const truncatedCache = criticDecision.cachedResult.length > 500 ? criticDecision.cachedResult.slice(0, 500) + `
521666
+ ... [${criticDecision.cachedResult.length - 500} chars omitted — same as before]` : criticDecision.cachedResult;
521591
521667
  const dedupOutput = header + truncatedCache;
521592
521668
  this.emit({
521593
521669
  type: "tool_result",
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "open-agents-ai",
3
- "version": "0.187.476",
3
+ "version": "0.187.477",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "open-agents-ai",
9
- "version": "0.187.476",
9
+ "version": "0.187.477",
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.476",
3
+ "version": "0.187.477",
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",