Skip to main content

agentic-exception-sdk

A domain-agnostic exception management SDK for agentic systems. Classifies failures into three tiers, routes them through pluggable handlers, wraps tool boundaries with resilient call wrappers, and provides safe no-op defaults for zero-config adoption.

Designed as a standalone Python package installed and wired into host projects via constructor injection. Contains no host-specific imports, no global state, and no module-level singletons.

Python 3.11+ — no exceptiongroup backport required.


Three-Tier Classification

Every failure is assigned to exactly one class:

Class Meaning Action
EXCEPTION Gracefully resolvable Automatic retry or fallback — no human involved
ISSUE Requires intervention Agent pauses; checkpoint handoff or human escalation
HARD_KILL Not resolvable Agent terminates immediately; envelope written to DLQ

HARD_KILL raises AgentHardKillError(BaseException) — it is never caught by except Exception anywhere in the call stack.


Install

# Core only (pydantic + RFC 8785 JCS canonicalization)
pip install agentic-exception-sdk

# With OpenTelemetry export
pip install agentic-exception-sdk[otel]

# With Redis circuit-breaker state
pip install agentic-exception-sdk[redis]

# With Prometheus metrics
pip install agentic-exception-sdk[prometheus]

# With structlog JSON renderer
pip install agentic-exception-sdk[structlog]

# Everything
pip install agentic-exception-sdk[all]

ReDoS protection: Install with pip install "agentic-exception-sdk[re2]" to enable linear-time google-re2 redaction. Without it the SDK falls back to stdlib re with patterns designed to avoid catastrophic backtracking.


Quick Start

from agentic_exception_sdk import (
    AgentHardKillError,
    NoOpResilienceBundle,
    SafeContextSnapshot,
    resilient,
)

# Zero-config: every component is a safe no-op
bundle = NoOpResilienceBundle()

# Wrap any tool boundary with the curried factory:
#   resilient(bundle, ...)(fn)(*args, **kwargs)
result = resilient(
    bundle,
    tool_name="search_flights",
    agent_id="booking-agent",
    correlation_id="req-abc123",
    context_snapshot=SafeContextSnapshot({"booking_id": "BK-001"}),
    fallback_value=[],          # returned on EXCEPTION or ISSUE if set
)(flight_client.search)(origin, destination, dates)

# Catch HARD_KILL only at the outermost executor boundary
try:
    executor.run(booking_request)
except AgentHardKillError as hk:
    audit.emit(hk.envelope.exception_id)
    raise

Wire a real ResilienceBundle in the composition root when you need retries, circuit breaking, budget enforcement, or escalation routing:

from agentic_exception_sdk import (
    AgentBudget,
    BudgetWatchdog,
    ExponentialBackoffRetry,
    InMemoryCircuitBreaker,
    InMemoryMetricsCollector,
    ResilienceBundle,
)

bundle = ResilienceBundle(
    retry_policy=ExponentialBackoffRetry(
        max_attempts=3,
        base_delay_seconds=0.5,
        jitter=True,
        retryable_exceptions=(TimeoutError, ConnectionError),
    ),
    circuit_breaker=InMemoryCircuitBreaker(
        failure_threshold=5,
        cooldown_seconds=30,
    ),
    agent_budget=BudgetWatchdog(AgentBudget(
        max_seconds=45.0,
        max_tool_calls=10,
        failure_budget=3,
        max_total_cost_micros_usd=2_000_000,  # $2.00
    )),
    metrics_collector=InMemoryMetricsCollector(),  # swap for PrometheusMetricsCollector
)

Key Concepts

  • ResilienceBundle — the single injection object. Every field defaults to a safe no-op. Inject only what you need.
  • NoOpResilienceBundle() — returns a fully defaulted bundle. Use as the default when no bundle is injected.
  • resilient() / async_resilient() — curried factory wrappers. Preserve wrapped callable parameter types via ParamSpec. Use async_resilient() with asyncio.timeout() for async tool calls and LLM calls with timeouts.
  • AgentHardKillError(BaseException) — raised on HARD_KILL. Propagates past all except Exception handlers. Catch only at the outermost executor boundary.
  • SafeContextSnapshot — frozen Pydantic RootModel for agent state. Enforces JSON-safe values, max depth 5, max 100 keys per dict, and rejects non-finite floats.
  • extend_lineage() — validated factory for multi-agent envelope propagation. Caps lineage at 64 hops; exceeding the cap auto-promotes to HARD_KILL.
  • TrustBoundaryValidator — runs pattern-based redaction (secrets, tokens, PANs, bidi controls) over exception messages and over string values in context snapshots. Snapshot handling redacts values under sensitively-named keys (password, token, secret, …) outright, and pattern-scans every other string value — including nested and list elements — so a secret embedded in an otherwise-benign field ({"note": "token is sk-…"}) is still redacted, not merely length-bounded. A single ReDoS budget spans the walk and fails closed. Redaction remains best-effort — see Limitations & Scope.
  • ResilienceBundle.metrics_collector — optional MetricsCollector (protocol). PrometheusMetricsCollector emits agent_exceptions_total, agent_hard_kills_total, agent_retries_total, agent_budget_exhausted_total.
  • ResilienceBundle.meter_provider — optional OTel MeterProvider. When set, creates an agent_tool_call_duration_seconds histogram per call.
  • ResilienceBundle.dlq — DeadLetterQueue for HARD_KILL envelopes. Defaults to InMemoryDLQ (ring buffer, drop-oldest). Swap for AsyncInMemoryDLQ in async contexts, or a satellite-package adapter (SQS, Pub/Sub, Redis).
  • ResilienceBundle.recovery_policy — optional post-classification recovery hook called before the default fallback/escalation path on EXCEPTION and ISSUE tiers. Satellite package agentic-exception-retry supplies AdaptiveRetryPolicy and CircuitAwareRetryPolicy.
  • ResilienceBundle.async_circuit_breaker — optional async circuit breaker used by async_resilient(). Falls back to sync circuit_breaker when not set.
  • allow_sync_llm_timeout — opt-in flag on resilient() that runs fn in a bounded ThreadPoolExecutor with the given timeout_seconds. The leaked thread cannot be cancelled and may continue spending tokens after the wrapper returns; prefer async_resilient() with asyncio.timeout() for LLM calls.
  • PersistenceProvider / NullProvider — the audit-persistence boundary. Every envelope carries a full-envelope integrity leaf hash (envelope_leaf_hash()), distinct from the envelope_canonical_sha256() dedup key. The default in-process NullProvider computes real leaf hashes and in-memory Merkle roots but emits unsigned, non-durable checkpoints. sentirock.attestation() reports the active provider's capabilities (durable, checkpoint_signing, worm).

Integrity & audit status

Every governed call emits a leaf hash over the redacted envelope and participates in an in-memory Merkle log. In the default (in-process) provider these checkpoints are unsigned and non-durable — the SDK's attestation API and span attributes (sentirock.provider.durable, sentirock.audit.degraded) report this explicitly. Durable, signed, WORM-retained audit trails are delivered by the persistence substrate on our enterprise roadmap; the PersistenceProvider interface it plugs into is already published in this repo (the conformance suite that will gate full attestation is planned).

Streaming Budget Enforcement

from agentic_exception_sdk import AgentBudget, BudgetWatchdog
from agentic_exception_sdk.budget import StreamingBudgetGuard

watchdog = BudgetWatchdog(AgentBudget(max_output_tokens=100))
stream = [{"text": "hi", "tokens": 1}, {"text": " there", "tokens": 2}]

for chunk in StreamingBudgetGuard.wrap_sync_stream(
    stream,
    watchdog,
    tool_name="openai-chat",
    agent_id="agent-1",
    token_extractor=lambda c: c["tokens"],
):
    print(chunk["text"])

Limitations & Scope

The SDK's controls are mitigations, not guarantees, and are not a substitute for defense-in-depth. Please read this before relying on the SDK for a security- or compliance-critical outcome:

  • Redaction is best-effort. The trust-boundary sanitizer is pattern-based; novel, split, or obfuscated secrets can pass through. It is not a substitute for a dedicated DLP control, and should not be your sole barrier against secret exposure.
  • HARD_KILL is in-execution termination, not an operator kill switch. AgentHardKillError stops the agent's own run when a tripwire fires. It is not an out-of-band control that deactivates a running agent, agent type, or fleet on demand — that capability is on the roadmap. Do not represent it as a fleet-wide or human-pullable deactivation switch.
  • AgentHardKillError extends BaseException — mind your runtime. This is deliberate (it survives except Exception), but runtimes that treat BaseException as fatal (Celery workers, some ASGI/thread-pool executors) may tear down the worker when it propagates. Catch it at your outermost executor boundary and translate it to your runtime's shutdown/abort convention; do not let it escape uncaught into a shared worker pool.
  • Integrity hashing is not a durable audit trail by default. The in-process provider emits unsigned, non-durable checkpoints and attests this via sentirock.attestation() (durable=false). Durable, signed, WORM-retained audit is delivered by the enterprise substrate on the roadmap.
  • Not a compliance certification. Any coverage mapping (e.g. to the OWASP LLM Top 10) documents what the SDK does; it does not make your system compliant with any regulation. Compliance is a property of your overall system and processes.
  • No warranty. Provided under the MIT License, "AS IS," without warranty of any kind (see LICENSE). You are responsible for validating its behavior in your own environment.

License

MIT License — see LICENSE. The SDK is provided "AS IS", without warranty of any kind; the authors are not liable for any claim or damages arising from its use. See Limitations & Scope above.

Metadata

Release files for agentic-exception-sdk 1.1.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for agentic-exception-sdk 1.1.3
File Size Uploaded Provenance
agentic_exception_sdk-1.1.3.tar.gz 80.3 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for agentic-exception-sdk 1.1.3
File Interpreter ABI Platform
agentic_exception_sdk-1.1.3-py3-none-any.whl Python 3 none any Details

Total release size: 194.4 kB

Release files / agentic_exception_sdk-1.1.3.tar.gz

Download URL agentic_exception_sdk-1.1.3.tar.gz
Size 80.3 kB
Tags Source
SHA-256 checksum
How to use checksums
e870c3c4fe9fe181f4b7f3a3c8313c9c6a1568e3121d897dc45a64b6e4927c8d
BLAKE2b-256 checksum
How to use checksums
5b5ff0a0c7f909a1b841ae65f789969728925ec0cba8d55430714dd30ee2ee47
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 16, 2026.

Transparency log

Release files / agentic_exception_sdk-1.1.3-py3-none-any.whl

Download URL agentic_exception_sdk-1.1.3-py3-none-any.whl
Size 114.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
0ade83581ed005f3c1f44d7934ab661ee528d2d4e79a00054f2c9b0a9f571f24
BLAKE2b-256 checksum
How to use checksums
e2a90bdf219667863d8b6cb198329a47fdbba334123b89285736dec2bb247694
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 16, 2026.

Transparency log

Security for agentic-exception-sdk 1.1.3

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for agentic_exception_sdk-1.1.3.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 16, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

1.1.3 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page