Assistant: Circuit Breaker & Resilience
The circuit breaker pattern was extended across all adaptive planner LLM call sites in April 2026, providing graceful degradation when LLM providers experience failures, timeouts, or rate limits.
Motivation
The adaptive planner makes many sequential LLM calls (task decomposition, replanning, result evaluation). A single provider outage could cascade through the entire planning pipeline, wasting tokens on doomed requests and producing incoherent partial plans. The circuit breaker prevents this by:
- Fast-failing after consecutive errors (no waiting on a dead provider)
- Falling back to alternative models/providers automatically
- Self-healing by transitioning from open → half-open → closed after a cooldown
Circuit Breaker States
stateDiagram-v2
[*] --> Closed
Closed --> Open : N consecutive failures
Open --> HalfOpen : cooldown elapsed
HalfOpen --> Closed : success
HalfOpen --> Open : failure
| State | Behavior |
|---|---|
| Closed | Normal operation — all LLM requests proceed |
| Open | All requests immediately fail — no LLM calls attempted |
| Half-Open | One probe request allowed; if it succeeds → Closed, if it fails → Open |
Configuration
| Parameter | Default | Description |
|---|---|---|
FailureThreshold |
3 | Consecutive failures before opening |
CooldownDuration |
60s | Time in Open state before transitioning to Half-Open |
HalfOpenMaxProbes |
1 | Requests allowed in Half-Open state |
Integration Points
Adaptive Planner
The circuit breaker wraps every LLM call in the adaptive planner:
decomposeTask()— Task breakdown callsevaluateResult()— Result evaluation callsreplanIfNeeded()— Replanning calls
When a call hits an open circuit breaker, the planner falls back to:
- Alternative provider — If the primary model has a fallback configured (e.g.,
openrouter/z-ai/glm-4.5-air:freeas fallback forllama/qwen3:30b) - Reduced model — A cheaper/faster model that may produce less optimal but functional output
- Cached result — If the same query type was recently successful, reuse that approach
Session Counter Reset
On a new user message, session error counters are reset with a 2-second delay before LLM retries. This gives transient issues time to resolve without carrying over stale failure state:
// Reset on new user message
session.ErrorCount = 0
time.AfterFunc(2*time.Second, func() {
// Allow retries after brief cooldown
})
Error Classification
The circuit breaker distinguishes between error types to avoid opening on non-provider issues:
| Error Type | Counts as Failure | Example |
|---|---|---|
| Provider timeout | Yes | 5-minute HTTP timeout |
| Rate limit (429) | Yes | OpenRouter rate limit |
| Auth failure (401/403) | Yes | Invalid API key |
| Context length exceeded | No | Prompt too long (fix the prompt) |
| Invalid request (400) | No | Malformed request (fix the code) |
| Network DNS failure | Yes | Provider endpoint unreachable |
Monitoring
Circuit breaker state changes are logged with the [CIRCUIT] prefix:
[CIRCUIT] Open: provider=openrouter model=glm-4.5-air failures=3 last_error="429 rate limit"
[CIRCUIT] HalfOpen: provider=openrouter model=glm-4.5-air cooldown=60s
[CIRCUIT] Closed: provider=openrouter model=glm-4.5-air probe_success=true
Mission Control displays circuit breaker status in the agent health panel.
Key Files
| File | Purpose |
|---|---|
assistant/adaptive_planner.go |
Circuit breaker integration at all LLM call sites |
assistant/circuit_breaker.go |
Circuit breaker implementation (states, transitions, cooldown) |
assistant/assutils.go |
Fallback model configuration, session counter reset |
Cross-References
- Assistant Framework
- Context Optimization — Complementary token efficiency measures
- Planner & Adaptive Planning