How the Circuit Breaker Detects and Handles Runaway Agents or Infinite Loops in Munder Difflin
The Munder Difflin circuit breaker uses a periodic heartbeat to sample agent telemetry, evaluates usage against configurable thresholds for tool repetition, error storms, token velocity, and hop counts, then escalates through graduated states—steering, constraining, and finally stopping—to halt runaway agents before they consume excessive resources.
The chaitanyagiri/munder-difflin repository implements a robust circuit breaker safety mechanism designed to prevent autonomous agents from entering infinite loops or consuming runaway resources. By monitoring real-time metrics such as tool invocation patterns, error rates, and token velocity, the system can automatically detect anomalous behavior and intervene with escalating severity. This article examines the detection architecture, intervention strategies, and source code implementation that enable the circuit breaker to protect the multi-agent environment.
Architecture of the Circuit Breaker Detection System
The Circuit Breaker Beat (Heartbeat)
Detection begins with a periodic sampling mechanism known internally as the circuit-breaker beat. Scheduled within src/main/index.ts, this heartbeat runs at regular intervals to pull fresh usage snapshots for every active agent.
The beat invokes breakSample() in src/main/breaker.ts, which collects critical telemetry:
- Token consumption per agent per minute
- Tool invocation counts and repetition patterns
- Consecutive error counts (error streaks)
- Hop counts reflecting message routing depth between agents
This sampling strategy ensures that runaway behavior is caught within seconds rather than minutes, minimizing resource waste.
Threshold Policies and State Machine
Once sampled, data flows into the CircuitBreaker class defined in src/main/breaker.ts. The checkAgent() method evaluates four primary throttles against configuration values stored in CircuitBreakerConfig (src/main/config.ts):
- Repeated-tool limit: Flags agents calling the same tool excessively within a window
- Error-storm limit: Detects consecutive tool failures indicating a broken logic path
- Token-velocity ceiling: Monitors
tokenVelocityPerMinto catch agents generating text faster than budgeted - Hop-count cap: Prevents infinite ping-pong by limiting message routing hops between agents
When a threshold is breached, the breaker transitions the agent through a state machine:
healthy → steering → constrained → stopped
Each state represents an escalating intervention level, allowing the system to attempt gentle course correction before termination.
Intervention Strategies for Runaway Agents
Graduated Response States
The circuit breaker employs graduated interventions rather than immediate termination, giving agents opportunity to self-correct:
- Steering: When initial thresholds are crossed, the breaker sends a summarization prompt requesting the agent explain its recent actions. This often breaks loops by forcing reflection.
- Constrained: If behavior persists, the system injects token-limit hints and restricts tool availability, effectively throttling the agent's operational capacity.
- Stopped: Upon reaching critical thresholds (severe error storms or hop-count overflow), the breaker issues a hard STOP command and marks the agent as blocked.
These state transitions are handled internally within checkAgent() in src/main/breaker.ts, which maintains per-agent state maps tracking current status and violation history.
Message Injection and UI Feedback
Actual intervention delivery occurs through sendCircuitBreakerMessage() in src/main/realtimeActions.ts. This function:
- Injects control messages directly into the target agent's inbox
- Logs intervention reasons via
breakerToastfor audit trails - Signals the renderer process to update UI status indicators
The UI reflects intervention states through CSS tokens such as --cth-status-looping, rendering visual badges indicating "circuit-breaker armed (runaway)" when agents enter constrained or stopped states.
Configuration and Customization
Administrators configure breaker thresholds through the settings interface defined in src/renderer/src/components/SettingsModal.tsx. The configuration persists through the CircuitBreakerConfig interface:
// src/main/config.ts - Configuration shape
interface CircuitBreakerConfig {
enabled: boolean;
tokenVelocityPerMin?: number;
repeatedToolLimit?: number;
errorStormLimit?: number;
maxHopCount?: number;
}
The React settings modal exposes these controls:
// src/renderer/src/components/SettingsModal.tsx
const [brkEnabled, setBrkEnabled] = useState<boolean>(
breakerCfg.circuitBreaker?.enabled !== false
);
const [velocityCeiling, setVelocityCeiling] = useState(
breakerCfg.circuitBreaker?.tokenVelocityPerMin != null
? String(breakerCfg.circuitBreaker.tokenVelocityPerMin)
: ''
);
// Saving configuration updates the breaker parameters
const saveConfig = () => {
const newConfig = {
enabled: brkEnabled,
tokenVelocityPerMin: parseInt(velocityCeiling, 10),
// ... additional thresholds
};
updateBreakerConfig(newConfig);
};
Programmatic inspection of breaker status is available through the useHive hook, which queries per-agent circuit breaker states:
// Querying breaker status for a specific agent
const breakerStatus = agent.circuitBreaker?.enabled
? 'active monitoring'
: 'bypassed';
Implementation Details in Source Code
The core logic resides in three critical files:
src/main/breaker.ts contains the CircuitBreaker class with breakSample() and checkAgent() methods. The class maintains internal counters for tool repeats and error streaks, comparing them against configuration thresholds each heartbeat cycle.
src/main/index.ts schedules the circuit-breaker beat using Electron's main process timers, ensuring sampling continues regardless of renderer state.
src/main/realtimeActions.ts bridges detection to action, implementing sendCircuitBreakerMessage() to deliver stop commands and constraint notifications to agent processes.
Summary
- The circuit-breaker beat in
src/main/index.tsdrives periodic telemetry sampling viabreakSample(). - Four threshold policies—tool repetition, error storms, token velocity, and hop counts—detect runaway conditions in
src/main/breaker.ts. - Graduated state transitions (healthy → steering → constrained → stopped) allow escalating interventions before termination.
- Message injection through
sendCircuitBreakerMessage()insrc/main/realtimeActions.tshalts agents and logs interventions. - Configuration via
SettingsModal.tsxandCircuitBreakerConfigenables customization of sensitivity thresholds. - Visual feedback through CSS tokens like
--cth-status-loopingalerts users to breaker-triggered stops.
Frequently Asked Questions
What triggers the circuit breaker to stop an agent immediately?
An agent enters the stopped state immediately when it exceeds the error-storm limit (consecutive tool failures) or the hop-count cap (message routing depth), as implemented in checkAgent() within src/main/breaker.ts. These conditions indicate unrecoverable logic errors or infinite ping-pong between agents, prompting the system to issue a hard STOP command via sendCircuitBreakerMessage().
How does the circuit breaker distinguish between high activity and an infinite loop?
The system relies on pattern detection rather than absolute volume. By tracking toolRepeats (frequency of identical tool calls) and errorStreak (consecutive failures) in the CircuitBreaker class, the breaker identifies repetitive, cyclical behavior characteristic of infinite loops. High but varied activity across different tools without error accumulation typically does not trigger constraints.
Can developers customize the token velocity thresholds?
Yes. The token-velocity ceiling is configurable through the tokenVelocityPerMin property in CircuitBreakerConfig (src/main/config.ts). The settings interface in src/renderer/src/components/SettingsModal.tsx exposes this as a numeric input, allowing administrators to set site-specific limits based on expected agent workloads and API budget constraints.
Where is the circuit breaker state persistence handled?
While the breaker evaluates state in real-time within src/main/breaker.ts, configuration persistence is managed through the application's settings store, accessed via the useHive hook and saved through the settings modal. Current agent states (healthy, steering, constrained, stopped) are maintained in-memory during runtime but generate persistent audit logs via breakerToast in src/main/realtimeActions.ts for post-hoc analysis.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →