Skip to content

Self-Healing Execution

Four layers, each independent. A failure at one layer is caught by the next.

graph TB L1[Layer 1 · Provider Failover<br/>Switch LLM providers on failure] --> L2 L2[Layer 2 · Stream Error Recovery<br/>Classify + retry with backoff] --> L3 L3[Layer 3 · Agent Safety Guard<br/>Hard caps on events, tools, time, loops] --> L4 L4[Layer 4 · Context Compaction<br/>Prevent context overflow]

ProviderFailoverService classifies every provider error and picks the next candidate from the configured chain.

ReasonCooldownTriggers
auth10 minHTTP 401/403, “invalid API key”
rate_limit1 minHTTP 429, “quota exceeded”
billing30 minHTTP 402, billing errors
timeout30 sHTTP 408, ETIMEDOUT, network timeout
overloaded2 minHTTP 502/503/529, “overloaded”
model_not_found1 hrHTTP 404
formatParse errors (don’t failover; the model itself is fine)
unknown30 sEverything else

Classification walks the error cause chain up to 5 levels deep. Probe recovery attempts fire 30 s before cooldown expires.

Failover chain: configured via codebuddy.failover.providers (empty = auto-detect from configured keys). When the primary trips, the next non-cooldown provider takes over. Response carries isFallback: true so callers know a switch happened.

ErrorRecoveryService classifies individual stream errors:

ClassBehaviorPatterns
TransientRetry with exponential backofftimeout, ECONNRESET, 429, 502, 503, overloaded, socket hang up
PermanentFail immediatelyloop detected, safety limit, authentication, invalid api key, quota exceeded

Retry: max 2 attempts per stream, base delay 1500 ms, exponential (1.5s → 3s → 6s). Each retry includes a nudge message to the agent explaining the failure so it can adjust.

Safety-guard errors are NEVER retried — that would circumvent Layer 3’s guarantees.

Hard caps. Not overridable by the agent.

GuardrailLimitSetting
Max stream events15000codebuddy.agent.maxEventCount
Max tool calls2000codebuddy.agent.maxToolInvocations
Wall-clock timeout60 mincodebuddy.agent.maxDurationMinutes
edit_file invocations75codebuddy.agent.limits.editFile
delete_file invocations30codebuddy.agent.limits.deleteFile
run_command100codebuddy.agent.limits.runCommand
run_terminal_command500codebuddy.agent.limits.runTerminalCommand
web_search60codebuddy.agent.limits.webSearch

Loop detection:

  • Tool loops — same tool called repetitively without progress → force stop after N in a row.
  • File edit loops — same file edited more than codebuddy.agent.fileEditLoopThreshold (default 20) → force stop with a “file loop” reason.

Stop messages are human-readable and include the counters:

Forced stop: reached maximum of 2000 tool invocations.
Events: 6247 · Tool calls: 2000 · Elapsed: 34m 23s.
Please review the work completed so far.

The LangChainTool layer also enforces a per-tool sliding-window rate limit (600/min global, 200/min per-tool) via ToolRateLimiter. That’s belt-and-suspenders with the safety guard’s total-count limits.

ContextWindowCompactionService keeps message history within the active model’s context window.

Tiers, escalating:

TierNameApproachLLM used?
0NoneNo action
1Tool stripStrip tool results > 200 chars from older messagesNo
2Multi-chunkSummarize message batches with overlapping windowsYes
3PartialSummarize the oldest halfYes
4Plain fallbackPlain-text description when LLM summarization itself failsNo

Thresholds:

  • Warning at 80% of the window — log + prepare.
  • Auto-compact at 90% — run Tier 1 immediately.
  • Higher tiers kick in as needed until usage is back under threshold.

Protected: most recent 4 messages are never summarized. A minimum of 6 messages must exist before any summarization runs.

Known context windows:

ModelWindow
Claude Sonnet 4/5200 K
Claude Opus 4200 K
GPT-4o128 K
GPT-48 K
Gemini 1.5 Pro2.1 M
DeepSeek Chat64 K
Qwen Plus131 K

Unknown models fall back to 8 K conservatively.

sequenceDiagram participant Agent participant L4 as L4 Compaction participant L3 as L3 Safety Guard participant L2 as L2 Recovery participant L1 as L1 Failover participant LLM Note over Agent, LLM: Rate-limited then recovered Agent->>LLM: request LLM-->>L2: HTTP 429 L2->>L2: transient → retry L2->>LLM: retry after 1.5s LLM-->>L2: HTTP 429 L2->>LLM: retry after 3s LLM-->>L2: HTTP 429 L2->>L1: give up → failover L1->>LLM: switch to backup provider LLM-->>L1: success L1-->>Agent: continue (isFallback: true) Note over Agent, LLM: Hit tool cap Agent->>L3: tool call #401 L3-->>Agent: stop — max 400 Note over Agent, LLM: Context near cap Agent->>L4: at 85% L4->>L4: Tier 1 strip → 88% L4->>L4: Tier 3 summarize → 62% L4-->>Agent: continue
  • Architecture — where the safety guard sits in the request flow
  • Providers — the failover chain configuration
  • Security — permission profiles + catastrophic-command denies