Domain-agnostic exception management SDK for agentic systems
Project description
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 stdlibrewith 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 viaParamSpec. Useasync_resilient()withasyncio.timeout()for async tool calls and LLM calls with timeouts.AgentHardKillError(BaseException)— raised onHARD_KILL. Propagates past allexcept Exceptionhandlers. Catch only at the outermost executor boundary.SafeContextSnapshot— frozen PydanticRootModelfor 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 toHARD_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— optionalMetricsCollector(protocol).PrometheusMetricsCollectoremitsagent_exceptions_total,agent_hard_kills_total,agent_retries_total,agent_budget_exhausted_total.ResilienceBundle.meter_provider— optional OTelMeterProvider. When set, creates anagent_tool_call_duration_secondshistogram per call.ResilienceBundle.dlq—DeadLetterQueuefor HARD_KILL envelopes. Defaults toInMemoryDLQ(ring buffer, drop-oldest). Swap forAsyncInMemoryDLQin 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 packageagentic-exception-retrysuppliesAdaptiveRetryPolicyandCircuitAwareRetryPolicy.ResilienceBundle.async_circuit_breaker— optional async circuit breaker used byasync_resilient(). Falls back to synccircuit_breakerwhen not set.allow_sync_llm_timeout— opt-in flag onresilient()that runsfnin a boundedThreadPoolExecutorwith the giventimeout_seconds. The leaked thread cannot be cancelled and may continue spending tokens after the wrapper returns; preferasync_resilient()withasyncio.timeout()for LLM calls.PersistenceProvider/NullProvider— the audit-persistence boundary. Every envelope carries a full-envelope integrity leaf hash (envelope_leaf_hash()), distinct from theenvelope_canonical_sha256()dedup key. The default in-processNullProvidercomputes 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_KILLis in-execution termination, not an operator kill switch.AgentHardKillErrorstops 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.AgentHardKillErrorextendsBaseException— mind your runtime. This is deliberate (it survivesexcept Exception), but runtimes that treatBaseExceptionas 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.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file agentic_exception_sdk-1.1.3.tar.gz.
File metadata
- Download URL: agentic_exception_sdk-1.1.3.tar.gz
- Upload date:
- Size: 80.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e870c3c4fe9fe181f4b7f3a3c8313c9c6a1568e3121d897dc45a64b6e4927c8d
|
|
| MD5 |
194b88693f082317040d7467e712d831
|
|
| BLAKE2b-256 |
5b5ff0a0c7f909a1b841ae65f789969728925ec0cba8d55430714dd30ee2ee47
|
Provenance
The following attestation bundles were made for agentic_exception_sdk-1.1.3.tar.gz:
Publisher:
publish.yml on 29monsankye/agentic-exception-sdk
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
agentic_exception_sdk-1.1.3.tar.gz -
Subject digest:
e870c3c4fe9fe181f4b7f3a3c8313c9c6a1568e3121d897dc45a64b6e4927c8d - Sigstore transparency entry: 2187843444
- Sigstore integration time:
-
Permalink:
29monsankye/agentic-exception-sdk@f6a19f72643892386d11fcd34a4c040a263c36f1 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/29monsankye
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@f6a19f72643892386d11fcd34a4c040a263c36f1 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file agentic_exception_sdk-1.1.3-py3-none-any.whl.
File metadata
- Download URL: agentic_exception_sdk-1.1.3-py3-none-any.whl
- Upload date:
- Size: 114.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0ade83581ed005f3c1f44d7934ab661ee528d2d4e79a00054f2c9b0a9f571f24
|
|
| MD5 |
4568c9a2647a3d9c8b374b79e58b9984
|
|
| BLAKE2b-256 |
e2a90bdf219667863d8b6cb198329a47fdbba334123b89285736dec2bb247694
|
Provenance
The following attestation bundles were made for agentic_exception_sdk-1.1.3-py3-none-any.whl:
Publisher:
publish.yml on 29monsankye/agentic-exception-sdk
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
agentic_exception_sdk-1.1.3-py3-none-any.whl -
Subject digest:
0ade83581ed005f3c1f44d7934ab661ee528d2d4e79a00054f2c9b0a9f571f24 - Sigstore transparency entry: 2187843466
- Sigstore integration time:
-
Permalink:
29monsankye/agentic-exception-sdk@f6a19f72643892386d11fcd34a4c040a263c36f1 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/29monsankye
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@f6a19f72643892386d11fcd34a4c040a263c36f1 -
Trigger Event:
workflow_dispatch
-
Statement type: