@cosmicstack/mercury-agent 1.0.3 → 1.0.4

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
@@ -3438,8 +3438,10 @@ var ToolCallLoopDetector = class _ToolCallLoopDetector {
3438
3438
  totalCalls = 0;
3439
3439
  hardAborted = false;
3440
3440
  recentStepTexts = [];
3441
+ consecutiveNoActionSteps = 0;
3441
3442
  static ABSOLUTE_MAX = 25;
3442
3443
  static FAILED_ABSOLUTE_MAX = 12;
3444
+ static NO_ACTION_MAX = 5;
3443
3445
  static HIGH_TOLERANCE_TOOLS = /* @__PURE__ */ new Set([
3444
3446
  "fetch_url",
3445
3447
  "read_file",
@@ -3465,10 +3467,15 @@ var ToolCallLoopDetector = class _ToolCallLoopDetector {
3465
3467
  const paramsKey = JSON.stringify(params).slice(0, 200);
3466
3468
  this.recentCalls.push({ tool: toolName, params: paramsKey, failed });
3467
3469
  this.totalCalls++;
3470
+ this.consecutiveNoActionSteps = 0;
3468
3471
  if (this.recentCalls.length > 30) {
3469
3472
  this.recentCalls.shift();
3470
3473
  }
3471
3474
  }
3475
+ recordNoActionResult() {
3476
+ this.consecutiveNoActionSteps++;
3477
+ return this.consecutiveNoActionSteps >= _ToolCallLoopDetector.NO_ACTION_MAX;
3478
+ }
3472
3479
  recordStepText(text) {
3473
3480
  if (!text || text.length < 10) return;
3474
3481
  const normalized = text.toLowerCase().replace(/\s+/g, " ").trim().slice(0, 200);
@@ -3597,6 +3604,7 @@ var ToolCallLoopDetector = class _ToolCallLoopDetector {
3597
3604
  this.totalCalls = 0;
3598
3605
  this.hardAborted = false;
3599
3606
  this.recentStepTexts = [];
3607
+ this.consecutiveNoActionSteps = 0;
3600
3608
  }
3601
3609
  };
3602
3610
  var MAX_STEPS = 10;
@@ -3965,6 +3973,17 @@ You can override this:
3965
3973
  if (stepText) {
3966
3974
  loopDetector.recordStepText(String(stepText));
3967
3975
  }
3976
+ const noActionLoop = loopDetector.recordNoActionResult();
3977
+ if (noActionLoop) {
3978
+ logger.warn("Reasoning loop detected \u2014 model keeps thinking without acting, aborting");
3979
+ if (!loopWarningSent && channel && msg.channelType !== "internal") {
3980
+ loopWarningSent = true;
3981
+ await channel.send("\u26A0 I'm stuck in a reasoning loop (thinking without taking action). Stopping.", msg.channelId).catch(() => {
3982
+ });
3983
+ }
3984
+ loopAbortController.abort();
3985
+ return;
3986
+ }
3968
3987
  const textRepeat = loopDetector.detectTextRepetition();
3969
3988
  if (textRepeat) {
3970
3989
  logger.warn({ pattern: textRepeat.pattern, count: textRepeat.count }, "Text repetition loop detected \u2014 aborting");
@@ -4113,6 +4132,17 @@ You can override this:
4113
4132
  if (stepText) {
4114
4133
  loopDetector.recordStepText(String(stepText));
4115
4134
  }
4135
+ const noActionLoop = loopDetector.recordNoActionResult();
4136
+ if (noActionLoop) {
4137
+ logger.warn("Reasoning loop detected \u2014 model keeps thinking without acting, aborting");
4138
+ if (!loopWarningSent && channel && msg.channelType !== "internal") {
4139
+ loopWarningSent = true;
4140
+ await channel.send("\u26A0 I'm stuck in a reasoning loop (thinking without taking action). Stopping.", msg.channelId).catch(() => {
4141
+ });
4142
+ }
4143
+ loopAbortController.abort();
4144
+ return;
4145
+ }
4116
4146
  const textRepeat = loopDetector.detectTextRepetition();
4117
4147
  if (textRepeat) {
4118
4148
  logger.warn({ pattern: textRepeat.pattern, count: textRepeat.count }, "Text repetition loop detected \u2014 aborting");