agentic-exception-sdk 1.1.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- agentic_exception_sdk-1.1.3/LICENSE +21 -0
- agentic_exception_sdk-1.1.3/PKG-INFO +291 -0
- agentic_exception_sdk-1.1.3/README.md +225 -0
- agentic_exception_sdk-1.1.3/pyproject.toml +187 -0
- agentic_exception_sdk-1.1.3/setup.cfg +4 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/__init__.py +308 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/__init__.pyi +38 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/budget/__init__.py +14 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/budget/__init__.pyi +5 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/budget/models.py +48 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/budget/models.pyi +14 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/budget/streaming.py +144 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/budget/streaming.pyi +27 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/budget/watchdog.py +285 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/budget/watchdog.pyi +24 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/bundle.py +102 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/bundle.pyi +37 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/config/__init__.py +10 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/config/__init__.pyi +3 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/config/validate.py +74 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/config/validate.pyi +11 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/escalation/__init__.py +22 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/escalation/__init__.pyi +5 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/escalation/checkpoint.py +116 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/escalation/checkpoint.pyi +13 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/escalation/handlers.py +27 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/escalation/handlers.pyi +7 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/escalation/router.py +137 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/escalation/router.pyi +22 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/multi_agent/__init__.py +32 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/multi_agent/__init__.pyi +6 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/multi_agent/consensus.py +139 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/multi_agent/consensus.pyi +18 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/multi_agent/parallel.py +204 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/multi_agent/parallel.pyi +35 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/multi_agent/router.py +131 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/multi_agent/router.pyi +14 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/multi_agent/sla.py +63 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/multi_agent/sla.pyi +10 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/noop.py +27 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/noop.pyi +5 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/observability/__init__.py +24 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/observability/__init__.pyi +6 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/observability/metrics.py +189 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/observability/metrics.pyi +36 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/observability/otel.py +211 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/observability/otel.pyi +9 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/observability/sink.py +68 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/observability/sink.pyi +12 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/observability/structured_log.py +110 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/observability/structured_log.pyi +8 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/persistence/__init__.py +27 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/persistence/__init__.pyi +35 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/persistence/attestation.py +36 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/persistence/attestation.pyi +8 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/persistence/availability.py +14 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/persistence/availability.pyi +7 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/persistence/null_provider.py +71 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/persistence/null_provider.pyi +19 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/persistence/provider.py +70 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/persistence/provider.pyi +33 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/propagation/__init__.py +39 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/propagation/__init__.pyi +5 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/propagation/bus.py +162 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/propagation/bus.pyi +30 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/propagation/dlq.py +173 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/propagation/dlq.pyi +28 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/propagation/protocol.py +129 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/propagation/protocol.pyi +10 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/py.typed +0 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/resilience/__init__.py +59 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/resilience/__init__.pyi +7 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/resilience/circuit_breaker.py +650 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/resilience/circuit_breaker.pyi +58 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/resilience/compensating.py +97 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/resilience/compensating.pyi +9 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/resilience/fallback.py +88 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/resilience/fallback.pyi +16 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/resilience/recovery.py +50 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/resilience/recovery.pyi +11 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/resilience/retry.py +455 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/resilience/retry.pyi +62 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/resilience/wrap.py +1073 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/resilience/wrap.pyi +28 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/taxonomy/__init__.py +56 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/taxonomy/__init__.pyi +7 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/taxonomy/classifier.py +216 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/taxonomy/classifier.pyi +8 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/taxonomy/enums.py +77 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/taxonomy/enums.pyi +22 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/taxonomy/envelope.py +223 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/taxonomy/envelope.pyi +29 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/taxonomy/errors.py +173 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/taxonomy/errors.pyi +34 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/taxonomy/owasp.py +55 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/taxonomy/owasp.pyi +19 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/validation/__init__.py +27 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/validation/__init__.pyi +6 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/validation/gates.py +93 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/validation/gates.pyi +16 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/validation/guard_rails.py +114 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/validation/guard_rails.pyi +18 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/validation/rules_version.py +5 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/validation/rules_version.pyi +3 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/validation/trust_boundary.py +420 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk/validation/trust_boundary.pyi +18 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk.egg-info/PKG-INFO +291 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk.egg-info/SOURCES.txt +109 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk.egg-info/dependency_links.txt +1 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk.egg-info/requires.txt +48 -0
- agentic_exception_sdk-1.1.3/src/agentic_exception_sdk.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 29monsankye
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: agentic-exception-sdk
|
|
3
|
+
Version: 1.1.3
|
|
4
|
+
Summary: Domain-agnostic exception management SDK for agentic systems
|
|
5
|
+
Author-email: 29monsankye <29monsank@gmail.com>
|
|
6
|
+
Maintainer-email: 29monsankye <29monsank@gmail.com>
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
Project-URL: Homepage, https://github.com/29monsankye/agentic-exception-sdk
|
|
9
|
+
Project-URL: Repository, https://github.com/29monsankye/agentic-exception-sdk
|
|
10
|
+
Project-URL: Issues, https://github.com/29monsankye/agentic-exception-sdk/issues
|
|
11
|
+
Keywords: agentic,agents,llm,exception-handling,resilience,circuit-breaker,observability,sdk
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
20
|
+
Classifier: Typing :: Typed
|
|
21
|
+
Requires-Python: >=3.11
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
License-File: LICENSE
|
|
24
|
+
Requires-Dist: jcs>=0.2.1
|
|
25
|
+
Requires-Dist: pydantic>=2.0.0
|
|
26
|
+
Requires-Dist: uuid-utils>=0.10.0
|
|
27
|
+
Provides-Extra: otel
|
|
28
|
+
Requires-Dist: opentelemetry-api>=1.29.0; extra == "otel"
|
|
29
|
+
Requires-Dist: opentelemetry-sdk>=1.29.0; extra == "otel"
|
|
30
|
+
Provides-Extra: redis
|
|
31
|
+
Requires-Dist: redis>=5.0.0; extra == "redis"
|
|
32
|
+
Provides-Extra: prometheus
|
|
33
|
+
Requires-Dist: prometheus-client>=0.20.0; extra == "prometheus"
|
|
34
|
+
Provides-Extra: structlog
|
|
35
|
+
Requires-Dist: structlog>=24.0.0; extra == "structlog"
|
|
36
|
+
Provides-Extra: re2
|
|
37
|
+
Requires-Dist: google-re2>=1.1; extra == "re2"
|
|
38
|
+
Provides-Extra: all
|
|
39
|
+
Requires-Dist: opentelemetry-api>=1.29.0; extra == "all"
|
|
40
|
+
Requires-Dist: opentelemetry-sdk>=1.29.0; extra == "all"
|
|
41
|
+
Requires-Dist: redis>=5.0.0; extra == "all"
|
|
42
|
+
Requires-Dist: prometheus-client>=0.20.0; extra == "all"
|
|
43
|
+
Requires-Dist: structlog>=24.0.0; extra == "all"
|
|
44
|
+
Requires-Dist: google-re2>=1.1; extra == "all"
|
|
45
|
+
Provides-Extra: dev
|
|
46
|
+
Requires-Dist: setuptools>=68; extra == "dev"
|
|
47
|
+
Requires-Dist: wheel; extra == "dev"
|
|
48
|
+
Requires-Dist: pytest>=8.0.0; extra == "dev"
|
|
49
|
+
Requires-Dist: pytest-asyncio>=0.23.0; extra == "dev"
|
|
50
|
+
Requires-Dist: pytest-mock>=3.14.0; extra == "dev"
|
|
51
|
+
Requires-Dist: pytest-cov>=5.0.0; extra == "dev"
|
|
52
|
+
Requires-Dist: pytest-randomly>=3.15.0; extra == "dev"
|
|
53
|
+
Requires-Dist: pytest-timeout>=2.3.0; extra == "dev"
|
|
54
|
+
Requires-Dist: pytest-benchmark>=4.0.0; extra == "dev"
|
|
55
|
+
Requires-Dist: freezegun>=1.5.0; extra == "dev"
|
|
56
|
+
Requires-Dist: hypothesis>=6.100.0; extra == "dev"
|
|
57
|
+
Requires-Dist: mypy>=1.10.0; extra == "dev"
|
|
58
|
+
Requires-Dist: ruff>=0.4.0; extra == "dev"
|
|
59
|
+
Requires-Dist: uv>=0.5.0; extra == "dev"
|
|
60
|
+
Requires-Dist: build>=1.2.0; extra == "dev"
|
|
61
|
+
Requires-Dist: bandit>=1.7.0; extra == "dev"
|
|
62
|
+
Requires-Dist: mutmut>=2.0; extra == "dev"
|
|
63
|
+
Requires-Dist: pip-audit>=2.7.0; extra == "dev"
|
|
64
|
+
Requires-Dist: types-redis; extra == "dev"
|
|
65
|
+
Dynamic: license-file
|
|
66
|
+
|
|
67
|
+
# agentic-exception-sdk
|
|
68
|
+
|
|
69
|
+
A domain-agnostic exception management SDK for agentic systems. Classifies
|
|
70
|
+
failures into three tiers, routes them through pluggable handlers, wraps tool
|
|
71
|
+
boundaries with resilient call wrappers, and provides safe no-op defaults for
|
|
72
|
+
zero-config adoption.
|
|
73
|
+
|
|
74
|
+
Designed as a **standalone Python package** installed and wired into host
|
|
75
|
+
projects via constructor injection. Contains no host-specific imports, no global
|
|
76
|
+
state, and no module-level singletons.
|
|
77
|
+
|
|
78
|
+
**Python 3.11+** — no `exceptiongroup` backport required.
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## Three-Tier Classification
|
|
83
|
+
|
|
84
|
+
Every failure is assigned to exactly one class:
|
|
85
|
+
|
|
86
|
+
| Class | Meaning | Action |
|
|
87
|
+
|---|---|---|
|
|
88
|
+
| `EXCEPTION` | Gracefully resolvable | Automatic retry or fallback — no human involved |
|
|
89
|
+
| `ISSUE` | Requires intervention | Agent pauses; checkpoint handoff or human escalation |
|
|
90
|
+
| `HARD_KILL` | Not resolvable | Agent terminates immediately; envelope written to DLQ |
|
|
91
|
+
|
|
92
|
+
`HARD_KILL` raises `AgentHardKillError(BaseException)` — it is never caught by
|
|
93
|
+
`except Exception` anywhere in the call stack.
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## Install
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
# Core only (pydantic + RFC 8785 JCS canonicalization)
|
|
101
|
+
pip install agentic-exception-sdk
|
|
102
|
+
|
|
103
|
+
# With OpenTelemetry export
|
|
104
|
+
pip install agentic-exception-sdk[otel]
|
|
105
|
+
|
|
106
|
+
# With Redis circuit-breaker state
|
|
107
|
+
pip install agentic-exception-sdk[redis]
|
|
108
|
+
|
|
109
|
+
# With Prometheus metrics
|
|
110
|
+
pip install agentic-exception-sdk[prometheus]
|
|
111
|
+
|
|
112
|
+
# With structlog JSON renderer
|
|
113
|
+
pip install agentic-exception-sdk[structlog]
|
|
114
|
+
|
|
115
|
+
# Everything
|
|
116
|
+
pip install agentic-exception-sdk[all]
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
> **ReDoS protection:** Install with `pip install "agentic-exception-sdk[re2]"` to
|
|
120
|
+
> enable linear-time google-re2 redaction. Without it the SDK falls back to stdlib
|
|
121
|
+
> `re` with patterns designed to avoid catastrophic backtracking.
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## Quick Start
|
|
126
|
+
|
|
127
|
+
```python
|
|
128
|
+
from agentic_exception_sdk import (
|
|
129
|
+
AgentHardKillError,
|
|
130
|
+
NoOpResilienceBundle,
|
|
131
|
+
SafeContextSnapshot,
|
|
132
|
+
resilient,
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
# Zero-config: every component is a safe no-op
|
|
136
|
+
bundle = NoOpResilienceBundle()
|
|
137
|
+
|
|
138
|
+
# Wrap any tool boundary with the curried factory:
|
|
139
|
+
# resilient(bundle, ...)(fn)(*args, **kwargs)
|
|
140
|
+
result = resilient(
|
|
141
|
+
bundle,
|
|
142
|
+
tool_name="search_flights",
|
|
143
|
+
agent_id="booking-agent",
|
|
144
|
+
correlation_id="req-abc123",
|
|
145
|
+
context_snapshot=SafeContextSnapshot({"booking_id": "BK-001"}),
|
|
146
|
+
fallback_value=[], # returned on EXCEPTION or ISSUE if set
|
|
147
|
+
)(flight_client.search)(origin, destination, dates)
|
|
148
|
+
|
|
149
|
+
# Catch HARD_KILL only at the outermost executor boundary
|
|
150
|
+
try:
|
|
151
|
+
executor.run(booking_request)
|
|
152
|
+
except AgentHardKillError as hk:
|
|
153
|
+
audit.emit(hk.envelope.exception_id)
|
|
154
|
+
raise
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Wire a real `ResilienceBundle` in the composition root when you need retries,
|
|
158
|
+
circuit breaking, budget enforcement, or escalation routing:
|
|
159
|
+
|
|
160
|
+
```python
|
|
161
|
+
from agentic_exception_sdk import (
|
|
162
|
+
AgentBudget,
|
|
163
|
+
BudgetWatchdog,
|
|
164
|
+
ExponentialBackoffRetry,
|
|
165
|
+
InMemoryCircuitBreaker,
|
|
166
|
+
InMemoryMetricsCollector,
|
|
167
|
+
ResilienceBundle,
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
bundle = ResilienceBundle(
|
|
171
|
+
retry_policy=ExponentialBackoffRetry(
|
|
172
|
+
max_attempts=3,
|
|
173
|
+
base_delay_seconds=0.5,
|
|
174
|
+
jitter=True,
|
|
175
|
+
retryable_exceptions=(TimeoutError, ConnectionError),
|
|
176
|
+
),
|
|
177
|
+
circuit_breaker=InMemoryCircuitBreaker(
|
|
178
|
+
failure_threshold=5,
|
|
179
|
+
cooldown_seconds=30,
|
|
180
|
+
),
|
|
181
|
+
agent_budget=BudgetWatchdog(AgentBudget(
|
|
182
|
+
max_seconds=45.0,
|
|
183
|
+
max_tool_calls=10,
|
|
184
|
+
failure_budget=3,
|
|
185
|
+
max_total_cost_micros_usd=2_000_000, # $2.00
|
|
186
|
+
)),
|
|
187
|
+
metrics_collector=InMemoryMetricsCollector(), # swap for PrometheusMetricsCollector
|
|
188
|
+
)
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
## Key Concepts
|
|
194
|
+
|
|
195
|
+
- **`ResilienceBundle`** — the single injection object. Every field defaults to
|
|
196
|
+
a safe no-op. Inject only what you need.
|
|
197
|
+
- **`NoOpResilienceBundle()`** — returns a fully defaulted bundle. Use as the
|
|
198
|
+
default when no bundle is injected.
|
|
199
|
+
- **`resilient()` / `async_resilient()`** — curried factory wrappers. Preserve
|
|
200
|
+
wrapped callable parameter types via `ParamSpec`. Use `async_resilient()` with
|
|
201
|
+
`asyncio.timeout()` for async tool calls and LLM calls with timeouts.
|
|
202
|
+
- **`AgentHardKillError(BaseException)`** — raised on `HARD_KILL`. Propagates
|
|
203
|
+
past all `except Exception` handlers. Catch only at the outermost executor
|
|
204
|
+
boundary.
|
|
205
|
+
- **`SafeContextSnapshot`** — frozen Pydantic `RootModel` for agent state.
|
|
206
|
+
Enforces JSON-safe values, max depth 5, max 100 keys per dict, and rejects
|
|
207
|
+
non-finite floats.
|
|
208
|
+
- **`extend_lineage()`** — validated factory for multi-agent envelope
|
|
209
|
+
propagation. Caps lineage at 64 hops; exceeding the cap auto-promotes to
|
|
210
|
+
`HARD_KILL`.
|
|
211
|
+
- **`TrustBoundaryValidator`** — runs pattern-based redaction (secrets, tokens,
|
|
212
|
+
PANs, bidi controls) over exception **messages** and over **string values in
|
|
213
|
+
context snapshots**. Snapshot handling redacts values under sensitively-named
|
|
214
|
+
keys (`password`, `token`, `secret`, …) outright, and pattern-scans every
|
|
215
|
+
other string value — including nested and list elements — so a secret embedded
|
|
216
|
+
in an otherwise-benign field (`{"note": "token is sk-…"}`) is still redacted,
|
|
217
|
+
not merely length-bounded. A single ReDoS budget spans the walk and fails
|
|
218
|
+
closed. Redaction remains best-effort — see **Limitations & Scope**.
|
|
219
|
+
- **`ResilienceBundle.metrics_collector`** — optional `MetricsCollector`
|
|
220
|
+
(protocol). `PrometheusMetricsCollector` emits `agent_exceptions_total`,
|
|
221
|
+
`agent_hard_kills_total`, `agent_retries_total`, `agent_budget_exhausted_total`.
|
|
222
|
+
- **`ResilienceBundle.meter_provider`** — optional OTel `MeterProvider`. When
|
|
223
|
+
set, creates an `agent_tool_call_duration_seconds` histogram per call.
|
|
224
|
+
- **`ResilienceBundle.dlq`** — `DeadLetterQueue` for HARD_KILL envelopes.
|
|
225
|
+
Defaults to `InMemoryDLQ` (ring buffer, drop-oldest). Swap for `AsyncInMemoryDLQ`
|
|
226
|
+
in async contexts, or a satellite-package adapter (SQS, Pub/Sub, Redis).
|
|
227
|
+
- **`ResilienceBundle.recovery_policy`** — optional post-classification recovery
|
|
228
|
+
hook called before the default fallback/escalation path on EXCEPTION and ISSUE
|
|
229
|
+
tiers. Satellite package `agentic-exception-retry` supplies `AdaptiveRetryPolicy`
|
|
230
|
+
and `CircuitAwareRetryPolicy`.
|
|
231
|
+
- **`ResilienceBundle.async_circuit_breaker`** — optional async circuit breaker
|
|
232
|
+
used by `async_resilient()`. Falls back to sync `circuit_breaker` when not set.
|
|
233
|
+
- **`allow_sync_llm_timeout`** — opt-in flag on `resilient()` that runs `fn` in
|
|
234
|
+
a bounded `ThreadPoolExecutor` with the given `timeout_seconds`. The leaked
|
|
235
|
+
thread cannot be cancelled and may continue spending tokens after the wrapper
|
|
236
|
+
returns; prefer `async_resilient()` with `asyncio.timeout()` for LLM calls.
|
|
237
|
+
- **`PersistenceProvider` / `NullProvider`** — the audit-persistence boundary.
|
|
238
|
+
Every envelope carries a full-envelope integrity leaf hash (`envelope_leaf_hash()`),
|
|
239
|
+
distinct from the `envelope_canonical_sha256()` dedup key. The default in-process
|
|
240
|
+
`NullProvider` computes real leaf hashes and in-memory Merkle roots but emits
|
|
241
|
+
unsigned, non-durable checkpoints. `sentirock.attestation()` reports the active
|
|
242
|
+
provider's capabilities (`durable`, `checkpoint_signing`, `worm`).
|
|
243
|
+
|
|
244
|
+
## Integrity & audit status
|
|
245
|
+
|
|
246
|
+
Every governed call emits a leaf hash over the redacted envelope and participates
|
|
247
|
+
in an in-memory Merkle log. In the default (in-process) provider these checkpoints
|
|
248
|
+
are unsigned and non-durable — the SDK's attestation API and span attributes
|
|
249
|
+
(`sentirock.provider.durable`, `sentirock.audit.degraded`) report this explicitly.
|
|
250
|
+
Durable, signed, WORM-retained audit trails are delivered by the persistence
|
|
251
|
+
substrate on our enterprise roadmap; the `PersistenceProvider` interface it plugs
|
|
252
|
+
into is already published in this repo (the conformance suite that will gate full
|
|
253
|
+
attestation is planned).
|
|
254
|
+
|
|
255
|
+
## Streaming Budget Enforcement
|
|
256
|
+
|
|
257
|
+
```python
|
|
258
|
+
from agentic_exception_sdk import AgentBudget, BudgetWatchdog
|
|
259
|
+
from agentic_exception_sdk.budget import StreamingBudgetGuard
|
|
260
|
+
|
|
261
|
+
watchdog = BudgetWatchdog(AgentBudget(max_output_tokens=100))
|
|
262
|
+
stream = [{"text": "hi", "tokens": 1}, {"text": " there", "tokens": 2}]
|
|
263
|
+
|
|
264
|
+
for chunk in StreamingBudgetGuard.wrap_sync_stream(
|
|
265
|
+
stream,
|
|
266
|
+
watchdog,
|
|
267
|
+
tool_name="openai-chat",
|
|
268
|
+
agent_id="agent-1",
|
|
269
|
+
token_extractor=lambda c: c["tokens"],
|
|
270
|
+
):
|
|
271
|
+
print(chunk["text"])
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
---
|
|
275
|
+
|
|
276
|
+
## Limitations & Scope
|
|
277
|
+
|
|
278
|
+
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:
|
|
279
|
+
|
|
280
|
+
- **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.
|
|
281
|
+
- **`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.
|
|
282
|
+
- **`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.
|
|
283
|
+
- **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.
|
|
284
|
+
- **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.
|
|
285
|
+
- **No warranty.** Provided under the MIT License, **"AS IS," without warranty of any kind** (see [LICENSE](LICENSE)). You are responsible for validating its behavior in your own environment.
|
|
286
|
+
|
|
287
|
+
---
|
|
288
|
+
|
|
289
|
+
## License
|
|
290
|
+
|
|
291
|
+
MIT License — see [LICENSE](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.
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
# agentic-exception-sdk
|
|
2
|
+
|
|
3
|
+
A domain-agnostic exception management SDK for agentic systems. Classifies
|
|
4
|
+
failures into three tiers, routes them through pluggable handlers, wraps tool
|
|
5
|
+
boundaries with resilient call wrappers, and provides safe no-op defaults for
|
|
6
|
+
zero-config adoption.
|
|
7
|
+
|
|
8
|
+
Designed as a **standalone Python package** installed and wired into host
|
|
9
|
+
projects via constructor injection. Contains no host-specific imports, no global
|
|
10
|
+
state, and no module-level singletons.
|
|
11
|
+
|
|
12
|
+
**Python 3.11+** — no `exceptiongroup` backport required.
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Three-Tier Classification
|
|
17
|
+
|
|
18
|
+
Every failure is assigned to exactly one class:
|
|
19
|
+
|
|
20
|
+
| Class | Meaning | Action |
|
|
21
|
+
|---|---|---|
|
|
22
|
+
| `EXCEPTION` | Gracefully resolvable | Automatic retry or fallback — no human involved |
|
|
23
|
+
| `ISSUE` | Requires intervention | Agent pauses; checkpoint handoff or human escalation |
|
|
24
|
+
| `HARD_KILL` | Not resolvable | Agent terminates immediately; envelope written to DLQ |
|
|
25
|
+
|
|
26
|
+
`HARD_KILL` raises `AgentHardKillError(BaseException)` — it is never caught by
|
|
27
|
+
`except Exception` anywhere in the call stack.
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Install
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
# Core only (pydantic + RFC 8785 JCS canonicalization)
|
|
35
|
+
pip install agentic-exception-sdk
|
|
36
|
+
|
|
37
|
+
# With OpenTelemetry export
|
|
38
|
+
pip install agentic-exception-sdk[otel]
|
|
39
|
+
|
|
40
|
+
# With Redis circuit-breaker state
|
|
41
|
+
pip install agentic-exception-sdk[redis]
|
|
42
|
+
|
|
43
|
+
# With Prometheus metrics
|
|
44
|
+
pip install agentic-exception-sdk[prometheus]
|
|
45
|
+
|
|
46
|
+
# With structlog JSON renderer
|
|
47
|
+
pip install agentic-exception-sdk[structlog]
|
|
48
|
+
|
|
49
|
+
# Everything
|
|
50
|
+
pip install agentic-exception-sdk[all]
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
> **ReDoS protection:** Install with `pip install "agentic-exception-sdk[re2]"` to
|
|
54
|
+
> enable linear-time google-re2 redaction. Without it the SDK falls back to stdlib
|
|
55
|
+
> `re` with patterns designed to avoid catastrophic backtracking.
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## Quick Start
|
|
60
|
+
|
|
61
|
+
```python
|
|
62
|
+
from agentic_exception_sdk import (
|
|
63
|
+
AgentHardKillError,
|
|
64
|
+
NoOpResilienceBundle,
|
|
65
|
+
SafeContextSnapshot,
|
|
66
|
+
resilient,
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
# Zero-config: every component is a safe no-op
|
|
70
|
+
bundle = NoOpResilienceBundle()
|
|
71
|
+
|
|
72
|
+
# Wrap any tool boundary with the curried factory:
|
|
73
|
+
# resilient(bundle, ...)(fn)(*args, **kwargs)
|
|
74
|
+
result = resilient(
|
|
75
|
+
bundle,
|
|
76
|
+
tool_name="search_flights",
|
|
77
|
+
agent_id="booking-agent",
|
|
78
|
+
correlation_id="req-abc123",
|
|
79
|
+
context_snapshot=SafeContextSnapshot({"booking_id": "BK-001"}),
|
|
80
|
+
fallback_value=[], # returned on EXCEPTION or ISSUE if set
|
|
81
|
+
)(flight_client.search)(origin, destination, dates)
|
|
82
|
+
|
|
83
|
+
# Catch HARD_KILL only at the outermost executor boundary
|
|
84
|
+
try:
|
|
85
|
+
executor.run(booking_request)
|
|
86
|
+
except AgentHardKillError as hk:
|
|
87
|
+
audit.emit(hk.envelope.exception_id)
|
|
88
|
+
raise
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Wire a real `ResilienceBundle` in the composition root when you need retries,
|
|
92
|
+
circuit breaking, budget enforcement, or escalation routing:
|
|
93
|
+
|
|
94
|
+
```python
|
|
95
|
+
from agentic_exception_sdk import (
|
|
96
|
+
AgentBudget,
|
|
97
|
+
BudgetWatchdog,
|
|
98
|
+
ExponentialBackoffRetry,
|
|
99
|
+
InMemoryCircuitBreaker,
|
|
100
|
+
InMemoryMetricsCollector,
|
|
101
|
+
ResilienceBundle,
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
bundle = ResilienceBundle(
|
|
105
|
+
retry_policy=ExponentialBackoffRetry(
|
|
106
|
+
max_attempts=3,
|
|
107
|
+
base_delay_seconds=0.5,
|
|
108
|
+
jitter=True,
|
|
109
|
+
retryable_exceptions=(TimeoutError, ConnectionError),
|
|
110
|
+
),
|
|
111
|
+
circuit_breaker=InMemoryCircuitBreaker(
|
|
112
|
+
failure_threshold=5,
|
|
113
|
+
cooldown_seconds=30,
|
|
114
|
+
),
|
|
115
|
+
agent_budget=BudgetWatchdog(AgentBudget(
|
|
116
|
+
max_seconds=45.0,
|
|
117
|
+
max_tool_calls=10,
|
|
118
|
+
failure_budget=3,
|
|
119
|
+
max_total_cost_micros_usd=2_000_000, # $2.00
|
|
120
|
+
)),
|
|
121
|
+
metrics_collector=InMemoryMetricsCollector(), # swap for PrometheusMetricsCollector
|
|
122
|
+
)
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## Key Concepts
|
|
128
|
+
|
|
129
|
+
- **`ResilienceBundle`** — the single injection object. Every field defaults to
|
|
130
|
+
a safe no-op. Inject only what you need.
|
|
131
|
+
- **`NoOpResilienceBundle()`** — returns a fully defaulted bundle. Use as the
|
|
132
|
+
default when no bundle is injected.
|
|
133
|
+
- **`resilient()` / `async_resilient()`** — curried factory wrappers. Preserve
|
|
134
|
+
wrapped callable parameter types via `ParamSpec`. Use `async_resilient()` with
|
|
135
|
+
`asyncio.timeout()` for async tool calls and LLM calls with timeouts.
|
|
136
|
+
- **`AgentHardKillError(BaseException)`** — raised on `HARD_KILL`. Propagates
|
|
137
|
+
past all `except Exception` handlers. Catch only at the outermost executor
|
|
138
|
+
boundary.
|
|
139
|
+
- **`SafeContextSnapshot`** — frozen Pydantic `RootModel` for agent state.
|
|
140
|
+
Enforces JSON-safe values, max depth 5, max 100 keys per dict, and rejects
|
|
141
|
+
non-finite floats.
|
|
142
|
+
- **`extend_lineage()`** — validated factory for multi-agent envelope
|
|
143
|
+
propagation. Caps lineage at 64 hops; exceeding the cap auto-promotes to
|
|
144
|
+
`HARD_KILL`.
|
|
145
|
+
- **`TrustBoundaryValidator`** — runs pattern-based redaction (secrets, tokens,
|
|
146
|
+
PANs, bidi controls) over exception **messages** and over **string values in
|
|
147
|
+
context snapshots**. Snapshot handling redacts values under sensitively-named
|
|
148
|
+
keys (`password`, `token`, `secret`, …) outright, and pattern-scans every
|
|
149
|
+
other string value — including nested and list elements — so a secret embedded
|
|
150
|
+
in an otherwise-benign field (`{"note": "token is sk-…"}`) is still redacted,
|
|
151
|
+
not merely length-bounded. A single ReDoS budget spans the walk and fails
|
|
152
|
+
closed. Redaction remains best-effort — see **Limitations & Scope**.
|
|
153
|
+
- **`ResilienceBundle.metrics_collector`** — optional `MetricsCollector`
|
|
154
|
+
(protocol). `PrometheusMetricsCollector` emits `agent_exceptions_total`,
|
|
155
|
+
`agent_hard_kills_total`, `agent_retries_total`, `agent_budget_exhausted_total`.
|
|
156
|
+
- **`ResilienceBundle.meter_provider`** — optional OTel `MeterProvider`. When
|
|
157
|
+
set, creates an `agent_tool_call_duration_seconds` histogram per call.
|
|
158
|
+
- **`ResilienceBundle.dlq`** — `DeadLetterQueue` for HARD_KILL envelopes.
|
|
159
|
+
Defaults to `InMemoryDLQ` (ring buffer, drop-oldest). Swap for `AsyncInMemoryDLQ`
|
|
160
|
+
in async contexts, or a satellite-package adapter (SQS, Pub/Sub, Redis).
|
|
161
|
+
- **`ResilienceBundle.recovery_policy`** — optional post-classification recovery
|
|
162
|
+
hook called before the default fallback/escalation path on EXCEPTION and ISSUE
|
|
163
|
+
tiers. Satellite package `agentic-exception-retry` supplies `AdaptiveRetryPolicy`
|
|
164
|
+
and `CircuitAwareRetryPolicy`.
|
|
165
|
+
- **`ResilienceBundle.async_circuit_breaker`** — optional async circuit breaker
|
|
166
|
+
used by `async_resilient()`. Falls back to sync `circuit_breaker` when not set.
|
|
167
|
+
- **`allow_sync_llm_timeout`** — opt-in flag on `resilient()` that runs `fn` in
|
|
168
|
+
a bounded `ThreadPoolExecutor` with the given `timeout_seconds`. The leaked
|
|
169
|
+
thread cannot be cancelled and may continue spending tokens after the wrapper
|
|
170
|
+
returns; prefer `async_resilient()` with `asyncio.timeout()` for LLM calls.
|
|
171
|
+
- **`PersistenceProvider` / `NullProvider`** — the audit-persistence boundary.
|
|
172
|
+
Every envelope carries a full-envelope integrity leaf hash (`envelope_leaf_hash()`),
|
|
173
|
+
distinct from the `envelope_canonical_sha256()` dedup key. The default in-process
|
|
174
|
+
`NullProvider` computes real leaf hashes and in-memory Merkle roots but emits
|
|
175
|
+
unsigned, non-durable checkpoints. `sentirock.attestation()` reports the active
|
|
176
|
+
provider's capabilities (`durable`, `checkpoint_signing`, `worm`).
|
|
177
|
+
|
|
178
|
+
## Integrity & audit status
|
|
179
|
+
|
|
180
|
+
Every governed call emits a leaf hash over the redacted envelope and participates
|
|
181
|
+
in an in-memory Merkle log. In the default (in-process) provider these checkpoints
|
|
182
|
+
are unsigned and non-durable — the SDK's attestation API and span attributes
|
|
183
|
+
(`sentirock.provider.durable`, `sentirock.audit.degraded`) report this explicitly.
|
|
184
|
+
Durable, signed, WORM-retained audit trails are delivered by the persistence
|
|
185
|
+
substrate on our enterprise roadmap; the `PersistenceProvider` interface it plugs
|
|
186
|
+
into is already published in this repo (the conformance suite that will gate full
|
|
187
|
+
attestation is planned).
|
|
188
|
+
|
|
189
|
+
## Streaming Budget Enforcement
|
|
190
|
+
|
|
191
|
+
```python
|
|
192
|
+
from agentic_exception_sdk import AgentBudget, BudgetWatchdog
|
|
193
|
+
from agentic_exception_sdk.budget import StreamingBudgetGuard
|
|
194
|
+
|
|
195
|
+
watchdog = BudgetWatchdog(AgentBudget(max_output_tokens=100))
|
|
196
|
+
stream = [{"text": "hi", "tokens": 1}, {"text": " there", "tokens": 2}]
|
|
197
|
+
|
|
198
|
+
for chunk in StreamingBudgetGuard.wrap_sync_stream(
|
|
199
|
+
stream,
|
|
200
|
+
watchdog,
|
|
201
|
+
tool_name="openai-chat",
|
|
202
|
+
agent_id="agent-1",
|
|
203
|
+
token_extractor=lambda c: c["tokens"],
|
|
204
|
+
):
|
|
205
|
+
print(chunk["text"])
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
## Limitations & Scope
|
|
211
|
+
|
|
212
|
+
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:
|
|
213
|
+
|
|
214
|
+
- **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.
|
|
215
|
+
- **`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.
|
|
216
|
+
- **`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.
|
|
217
|
+
- **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.
|
|
218
|
+
- **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.
|
|
219
|
+
- **No warranty.** Provided under the MIT License, **"AS IS," without warranty of any kind** (see [LICENSE](LICENSE)). You are responsible for validating its behavior in your own environment.
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
## License
|
|
224
|
+
|
|
225
|
+
MIT License — see [LICENSE](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.
|