Self-Healing
Self-healing is one of Anvil’s most powerful features. When a tool fails, Anvil automatically regenerates it with the error context, often fixing the issue without any manual intervention.
How It Works
Section titled “How It Works”┌─────────────┐ ┌─────────────┐ ┌─────────────┐│ Execute │────▶│ Failed │────▶│ Capture ││ Tool │ │ │ │ Context │└─────────────┘ └─────────────┘ └─────────────┘ │ ▼┌─────────────┐ ┌─────────────┐ ┌─────────────┐│ Retry │◀────│ Regenerate │◀────│ LLM with ││ Execute │ │ Code │ │ Error │└─────────────┘ └─────────────┘ └─────────────┘Step 1: Failure Detection
Section titled “Step 1: Failure Detection”When tool.run() raises an exception, Anvil catches it:
result = tool.run(query="test")# RuntimeError: API returned 401 UnauthorizedStep 2: Context Gathering
Section titled “Step 2: Context Gathering”Anvil collects:
- The original intent
- The current (failing) code
- The full error message and traceback
- The arguments that caused the failure
Step 3: Regeneration
Section titled “Step 3: Regeneration”The LLM receives a specialized prompt:
The following tool code is failing with this error:[error message]
Original intent: [intent]Current code: [code]Arguments: [args]
Please fix the code to handle this error.Step 4: Retry
Section titled “Step 4: Retry”The new code is saved and the tool is re-executed with the same arguments.
Configuration
Section titled “Configuration”Enable or disable self-healing when initializing Anvil:
# Enabled by defaultanvil = Anvil(self_healing=True)
# Disable self-healinganvil = Anvil(self_healing=False)
# Limit healing attemptsanvil = Anvil(self_healing=True, max_heal_attempts=3)Parameters
Section titled “Parameters”| Parameter | Default | Description |
|---|---|---|
self_healing | True | Enable automatic healing |
max_heal_attempts | 2 | Maximum regeneration attempts per tool |
Healing Attempts
Section titled “Healing Attempts”Anvil tracks healing attempts per tool to prevent infinite loops:
# First failure → Heal attempt 1# Second failure → Heal attempt 2# Third failure → Raise exception (max attempts reached)Reset the counter manually:
# Reset specific toolanvil.reset_heal_attempts("search_tool")
# Reset all toolsanvil.reset_heal_attempts()What Gets Fixed
Section titled “What Gets Fixed”Self-healing works best for:
- API errors - Authentication issues, endpoint changes
- Import errors - Missing dependencies
- Type errors - Wrong argument types
- Response parsing - Changed API response formats
Example: API Change
Section titled “Example: API Change”Imagine an API changes its authentication method:
# Original generated code (v1.0)def run(query): response = requests.get( "https://api.example.com/search", headers={"X-API-Key": os.environ["API_KEY"]} ) return response.json()The API now requires Bearer tokens. When the tool fails with 401 Unauthorized, Anvil regenerates:
# Self-healed code (v1.1)def run(query): response = requests.get( "https://api.example.com/search", headers={"Authorization": f"Bearer {os.environ['API_KEY']}"} ) return response.json()Version Tracking
Section titled “Version Tracking”Each healing increments the minor version:
1.0 → Initial generation1.1 → First healing1.2 → Second healingView version history:
info = anvil.get_tool_info("search_tool")print(info["version"]) # "1.2"Logging Healed Events
Section titled “Logging Healed Events”Self-healing events are logged for observability:
anvil = Anvil(log_file="anvil.log")
# After a healing eventevents = anvil.logger.get_history(event_type="tool_healed")for event in events: print(f"{event.tool_name}: healed at {event.timestamp}")When Self-Healing Won’t Work
Section titled “When Self-Healing Won’t Work”Self-healing has limitations:
- Logic errors - The LLM may repeat the same mistake
- Missing credentials - Can’t fix missing API keys
- External service down - Network issues aren’t code problems
- Complex state - Issues requiring broader context
For these cases, the error is raised after max attempts.
Disabling for Specific Tools
Section titled “Disabling for Specific Tools”For critical tools, you might want manual control:
# Disable self-healing globallyanvil = Anvil(self_healing=False)
# Or use run_safe() to handle errors yourselfresult = tool.run_safe(query="test")if not result.success: # Handle manually print(f"Error: {result.error}")