Skip to main content

Battle-hardened safety wrapper for AI agents

Project description

๐Ÿ›ก๏ธ agent_safety_box

Battle-hardened safety wrapper for AI agents โ€” zero external dependencies, production-grade, fully tested.

pip install agent-safety-box

##The Problem AI agents are powerful, but they fail unpredictably in production. They hallucinate, get stuck in loops, blow through budgets, and crash silently. As one developer put it, "we're spending 40% of our budget on garbage output." Debugging becomes guesswork. agent_safety_box is the answer .

Features

Feature AgentWrapper AgentWrapperV2
Budget enforcement (thread-safe) โœ… โœ…
Per-run cost ceiling โœ… โœ…
Timeout (sync & async) โœ… โœ…
Retry + exponential backoff + jitter โœ… โœ…
Circuit Breaker โœ… โœ…
Rate Limiter (token-bucket) โœ… โœ…
Output validation โœ… โœ…
JSONL audit logging + rotation โœ… โœ…
Dry-run mode โœ… โœ…
Tags & metadata โœ… โœ…
Context manager โœ… โœ…
Lifecycle hooks (before/after/error) โ€” โœ…
Bulkhead (concurrency limiter) โ€” โœ…
Adaptive timeout (auto p95-tuned) โ€” โœ…
Rolling metrics (p50/p95/p99) โ€” โœ…
Cost forecaster โ€” โœ…
Plugin registry โ€” โœ…
Budget warning callback โ€” โœ…
Graceful shutdown โ€” โœ…
Fallback chain (multi-agent failover) โ€” โœ…

Quick Start

from agent_safety_box import AgentWrapper, CircuitBreaker, RateLimiter

cb = CircuitBreaker(failure_threshold=3, reset_timeout=60)
rl = RateLimiter(rate=5.0)

wrapper = AgentWrapper(
    agent=my_agent,
    budget=100.0,
    max_runtime=10.0,
    max_cost_per_run=5.0,
    max_retries=2,
    retry_delay=1.0,
    circuit_breaker=cb,
    rate_limiter=rl,
    output_validator=lambda o: isinstance(o, str) and len(o) > 0,
    tags={"env": "prod", "model": "gpt-4o"},
    log_path="logs/audit.jsonl",
)

with wrapper:
    result = wrapper.run("Summarise this document", cost=1.5)

AgentWrapperV2 โ€” Advanced Pipeline

from agent_safety_box.wrapper_v2 import AgentWrapperV2
from agent_safety_box.middleware import HookManager, Bulkhead, AdaptiveTimeout

hooks = HookManager()
hooks.on_before(lambda ctx: print(f"โ†’ {ctx['task']}"))
hooks.on_after(lambda ctx: print(f"โœ“ done"))
hooks.on_error(lambda ctx, exc: print(f"โœ— {exc}"))

w = AgentWrapperV2(
    agent=my_agent,
    budget=500.0,
    hooks=hooks,
    bulkhead=Bulkhead(max_concurrent=10),
    adaptive_timeout=AdaptiveTimeout(initial=5.0),
    on_budget_warning=lambda rem, bud: print(f"โš  Only {rem:.2f} left!"),
    budget_warning_pct=0.20,
    plugins={"logger": lambda ctx: my_logger.info(ctx)},
)

result = w.run("task", cost=1.0)
print(w.metrics)
# {
#   'total_runs': 1, 'successes': 1, 'errors': 0,
#   'spent': 1.0, 'remaining': 499.0,
#   'rolling': {'p50_s': 0.003, 'p95_s': 0.003, 'p99_s': 0.003,
#               'error_rate': 0.0, 'throughput_rps': 312.5, 'sample_size': 1},
#   'avg_cost_forecast': 1.0,
#   'bulkhead_active': 0, 'bulkhead_max': 10,
#   'adaptive_timeout_s': 5.0,
# }

Fallback Chain

from agent_safety_box.middleware import FallbackChain

chain = FallbackChain(
    primary=gpt4_agent,
    fallbacks=[gpt35_agent, local_llm_agent],
)
result = chain.run("task")
print(f"Used: {chain.last_used}")
print(chain.stats)

Async Support

from agent_safety_box import AsyncAgentWrapper

wrapper = AsyncAgentWrapper(agent=my_async_agent, budget=50.0)

async def main():
    result = await wrapper.run("Classify this text", cost=0.5)

asyncio.run(main())

Exceptions

All exceptions inherit from AgentSafetyBoxError:

Exception When raised
BudgetExceededError Total budget would be breached
MaxCostExceededError Per-run cost ceiling exceeded
TimeoutExceededError Agent exceeded max_runtime
RetryExhaustedError All retry attempts failed
AgentValidationError output_validator rejected output
CircuitOpenError Circuit breaker is OPEN
RateLimitError Rate limiter rejected (non-blocking mode)

Safety Pipeline (per run)

1. max_cost_per_run check
2. budget check  (thread/async-safe lock)
3. rate_limiter.acquire()
4. circuit_breaker.allow_request()
5. agent.run(task)  [with timeout]
6. output_validator(result)
7. actual_cost adjustment (if agent returns {"actual_cost": X})
8. budget commit
9. circuit_breaker.record_success/failure()
10. audit log write

Running Tests

# All 263 tests
python -m unittest discover -s agent_safety_box/tests -p "test_*.py" -v

# Single module
python -m unittest agent_safety_box.tests.test_ultimate -v

Architecture

agent_safety_box/
โ”œโ”€โ”€ __init__.py          # Public API
โ”œโ”€โ”€ wrapper.py           # AgentWrapper + AsyncAgentWrapper (v1)
โ”œโ”€โ”€ wrapper_v2.py        # AgentWrapperV2 + AsyncAgentWrapperV2 (v2)
โ”œโ”€โ”€ middleware.py        # HookManager, RollingMetrics, Bulkhead,
โ”‚                        # AdaptiveTimeout, CostForecaster, FallbackChain
โ”œโ”€โ”€ safety.py            # CircuitBreaker + RateLimiter
โ”œโ”€โ”€ exceptions.py        # All custom exceptions
โ”œโ”€โ”€ logger.py            # AuditLogger (JSONL + rotation)
โ””โ”€โ”€ tests/
    โ”œโ”€โ”€ conftest.py      # Shared stubs and base class
    โ”œโ”€โ”€ test_budget.py   # Budget enforcement (31 tests)
    โ”œโ”€โ”€ test_execution.py# Timeout + retry (30 tests)
    โ”œโ”€โ”€ test_logger.py   # Audit logging (21 tests)
    โ”œโ”€โ”€ test_safety.py   # Circuit + rate limiter (31 tests)
    โ”œโ”€โ”€ test_stress.py   # Concurrency + chaos (18 tests)
    โ””โ”€โ”€ test_ultimate.py # Deep edge cases (132 tests)

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

agent_safety_box-1.1.0.tar.gz (40.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

agent_safety_box-1.1.0-py3-none-any.whl (45.4 kB view details)

Uploaded Python 3

File details

Details for the file agent_safety_box-1.1.0.tar.gz.

File metadata

  • Download URL: agent_safety_box-1.1.0.tar.gz
  • Upload date:
  • Size: 40.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for agent_safety_box-1.1.0.tar.gz
Algorithm Hash digest
SHA256 89558ba67bb66be47884b31e29a1eeec4e004160394dbfbedd889696f44e25d7
MD5 b83ec22afacd1fa7f087ed45fd838f89
BLAKE2b-256 1bba2d0dbcaf6d3b57c2958c27611bc437506546f7f57ef3a083a0e4c2cc5354

See more details on using hashes here.

File details

Details for the file agent_safety_box-1.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for agent_safety_box-1.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 2e136fda897438390603456a759769a2221e55bb1f20123d2908b00c6d3ffa28
MD5 b601fd1670b3945ed458836735587a05
BLAKE2b-256 15433d72afcf7418f2bc949b3f7ecc606cc9df082ce0f01f3833f71a16b06c16

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page