Skip to content

feat(background-agent): add smart circuit breaker for repeated tool calls#2639

Merged
code-yeongyu merged 3 commits intodevfrom
feature/2635-smart-circuit-breaker
Mar 17, 2026
Merged

feat(background-agent): add smart circuit breaker for repeated tool calls#2639
code-yeongyu merged 3 commits intodevfrom
feature/2635-smart-circuit-breaker

Conversation

@code-yeongyu
Copy link
Copy Markdown
Owner

@code-yeongyu code-yeongyu commented Mar 17, 2026

Summary

  • add a sliding-window circuit breaker that cancels subagents when the same tool dominates recent tool calls
  • keep the raw maxToolCalls limit as a backstop and add schema coverage for the new nested circuit breaker settings
  • dedupe repeated message.part.updated events for the same running tool part so one invocation is only counted once

Testing

  • bun test src/config/schema/background-task.test.ts src/config/schema/background-task-circuit-breaker.test.ts src/features/background-agent/loop-detector.test.ts src/features/background-agent/manager-circuit-breaker.test.ts src/features/background-agent/manager.test.ts
  • bun run typecheck
  • bun run build
  • manual QA: exercised loop-detector and BackgroundManager with Bun scripts to verify repetition detection and duplicate tool-part dedupe

Related Issues


Summary by cubic

Add a smart, sliding‑window circuit breaker to BackgroundManager that cancels tasks when one tool dominates recent calls, while keeping maxToolCalls as a backstop. Addresses #2635 by preventing infinite tool loops and reducing wasted tokens.

  • New Features

    • Sliding‑window repetition detector with defaults (window: 20, threshold: 80%) and a backstop cap (default maxToolCalls: 200); cancels early with a clear reason.
    • New nested circuitBreaker config (maxToolCalls, windowSize, repetitionThresholdPercent) in BackgroundTaskConfig and JSON schema; added loop‑detector helpers and tests.
  • Bug Fixes

    • Dedupes repeated message.part.updated events for the same running tool part so a single invocation is counted once.

Written for commit ae3befb. Summary will update on new commits.

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 9 files

Confidence score: 2/5

  • There is a high-confidence, high-severity logic issue in src/features/background-agent/manager.ts: deduplication skips certain status updates (like "completed"), so the same tool call can be counted multiple times, which can directly skew agent behavior.
  • Because this affects core counting logic rather than just test quality, merge risk is elevated despite the rest of the PR being limited in size.
  • src/features/background-agent/loop-detector.test.ts also has a validity gap: the "diverse tools" case passes due to early exit from windowSize, so it may not catch regressions in diversity evaluation.
  • Pay close attention to src/features/background-agent/manager.ts and src/features/background-agent/loop-detector.test.ts - fix deduplication handling and make sure the test actually exercises tool-diversity logic.
Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src/features/background-agent/manager.ts">

<violation number="1" location="src/features/background-agent/manager.ts:902">
P1: Custom agent: **Opencode Compatibility**

The deduplication logic fails for status updates like "completed", causing the same tool call to be counted multiple times. Remove the status check to correctly count each unique tool ID exactly once.</violation>
</file>

<file name="src/features/background-agent/loop-detector.test.ts">

<violation number="1" location="src/features/background-agent/loop-detector.test.ts:56">
P2: The 'diverse tools' test passes for the wrong reason: it exits early due to the default `windowSize` (20) being larger than the sample size (10). It never actually evaluates tool diversity.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment on lines +902 to +912
!partInfo.id ||
partInfo.state?.status !== "running" ||
!countedToolPartIDs.includes(partInfo.id)

if (!shouldCountToolCall) {
return
}

if (partInfo.id && partInfo.state?.status === "running") {
task.progress.countedToolPartIDs = [...countedToolPartIDs, partInfo.id]
}
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai bot Mar 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Custom agent: Opencode Compatibility

The deduplication logic fails for status updates like "completed", causing the same tool call to be counted multiple times. Remove the status check to correctly count each unique tool ID exactly once.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/features/background-agent/manager.ts, line 902:

<comment>The deduplication logic fails for status updates like "completed", causing the same tool call to be counted multiple times. Remove the status check to correctly count each unique tool ID exactly once.</comment>

<file context>
@@ -876,10 +897,50 @@ export class BackgroundManager {
       if (partInfo?.type === "tool" || partInfo?.tool) {
+        const countedToolPartIDs = task.progress.countedToolPartIDs ?? []
+        const shouldCountToolCall =
+          !partInfo.id ||
+          partInfo.state?.status !== "running" ||
+          !countedToolPartIDs.includes(partInfo.id)
</file context>
Suggested change
!partInfo.id ||
partInfo.state?.status !== "running" ||
!countedToolPartIDs.includes(partInfo.id)
if (!shouldCountToolCall) {
return
}
if (partInfo.id && partInfo.state?.status === "running") {
task.progress.countedToolPartIDs = [...countedToolPartIDs, partInfo.id]
}
!partInfo.id ||
!countedToolPartIDs.includes(partInfo.id)
if (!shouldCountToolCall) {
return
}
if (partInfo.id) {
task.progress.countedToolPartIDs = [...countedToolPartIDs, partInfo.id]
}
Fix with Cubic

"read",
"grep",
"edit",
])
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai bot Mar 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: The 'diverse tools' test passes for the wrong reason: it exits early due to the default windowSize (20) being larger than the sample size (10). It never actually evaluates tool diversity.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/features/background-agent/loop-detector.test.ts, line 56:

<comment>The 'diverse tools' test passes for the wrong reason: it exits early due to the default `windowSize` (20) being larger than the sample size (10). It never actually evaluates tool diversity.</comment>

<file context>
@@ -0,0 +1,117 @@
+          "read",
+          "grep",
+          "edit",
+        ])
+
+        const result = detectRepetitiveToolUse(window)
</file context>
Fix with Cubic

@code-yeongyu code-yeongyu merged commit 0b4d092 into dev Mar 17, 2026
7 of 8 checks passed
@code-yeongyu code-yeongyu deleted the feature/2635-smart-circuit-breaker branch March 17, 2026 07:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(background-agent): smart circuit breaker with same-tool repetition detection

1 participant