epi-recorder 2.2.0__py3-none-any.whl → 2.3.0__py3-none-any.whl
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.
- epi_core/schemas.py +2 -2
- epi_recorder/__init__.py +10 -2
- epi_recorder/api.py +184 -4
- epi_recorder/patcher.py +47 -7
- epi_recorder/wrappers/__init__.py +16 -0
- epi_recorder/wrappers/base.py +79 -0
- epi_recorder/wrappers/openai.py +178 -0
- epi_recorder-2.3.0.dist-info/METADATA +269 -0
- {epi_recorder-2.2.0.dist-info → epi_recorder-2.3.0.dist-info}/RECORD +14 -11
- epi_recorder-2.3.0.dist-info/licenses/LICENSE +21 -0
- epi_viewer_static/app.js +77 -2
- epi_recorder-2.2.0.dist-info/METADATA +0 -162
- epi_recorder-2.2.0.dist-info/licenses/LICENSE +0 -176
- {epi_recorder-2.2.0.dist-info → epi_recorder-2.3.0.dist-info}/WHEEL +0 -0
- {epi_recorder-2.2.0.dist-info → epi_recorder-2.3.0.dist-info}/entry_points.txt +0 -0
- {epi_recorder-2.2.0.dist-info → epi_recorder-2.3.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: epi-recorder
|
|
3
|
+
Version: 2.3.0
|
|
4
|
+
Summary: Verifiable execution evidence for AI systems. Portable, cryptographically signed artifacts.
|
|
5
|
+
Author-email: EPI Labs <mohdibrahim@epilabs.org>
|
|
6
|
+
Maintainer-email: Mohd Ibrahim Afridi <mohdibrahim@epilabs.org>
|
|
7
|
+
License: MIT
|
|
8
|
+
Project-URL: Homepage, https://epilabs.org
|
|
9
|
+
Project-URL: Documentation, https://epilabs.org/docs
|
|
10
|
+
Project-URL: Repository, https://github.com/mohdibrahimaiml/epi-recorder
|
|
11
|
+
Project-URL: Issues, https://github.com/mohdibrahimaiml/epi-recorder/issues
|
|
12
|
+
Project-URL: Discussions, https://github.com/mohdibrahimaiml/epi-recorder/discussions
|
|
13
|
+
Keywords: evidence,forensics,audit,compliance,cryptography,ai,llm,verification,artifact,execution-trace,reproducibility,tamper-evident
|
|
14
|
+
Classifier: Development Status :: 4 - Beta
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: Intended Audience :: Legal Industry
|
|
17
|
+
Classifier: Intended Audience :: Science/Research
|
|
18
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
19
|
+
Classifier: Operating System :: OS Independent
|
|
20
|
+
Classifier: Programming Language :: Python :: 3
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
23
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
24
|
+
Classifier: Topic :: Security :: Cryptography
|
|
25
|
+
Classifier: Topic :: System :: Logging
|
|
26
|
+
Classifier: Typing :: Typed
|
|
27
|
+
Classifier: Framework :: Pydantic
|
|
28
|
+
Classifier: Framework :: Pydantic :: 2
|
|
29
|
+
Requires-Python: >=3.11
|
|
30
|
+
Description-Content-Type: text/markdown
|
|
31
|
+
License-File: LICENSE
|
|
32
|
+
Requires-Dist: pydantic>=2.0.0
|
|
33
|
+
Requires-Dist: cryptography>=41.0.0
|
|
34
|
+
Requires-Dist: cbor2>=5.6.0
|
|
35
|
+
Requires-Dist: typer[all]>=0.12.0
|
|
36
|
+
Requires-Dist: rich>=13.0.0
|
|
37
|
+
Requires-Dist: google-generativeai>=0.4.0
|
|
38
|
+
Provides-Extra: dev
|
|
39
|
+
Requires-Dist: pytest>=8.0.0; extra == "dev"
|
|
40
|
+
Requires-Dist: pytest-asyncio>=0.23.0; extra == "dev"
|
|
41
|
+
Requires-Dist: pytest-cov>=4.1.0; extra == "dev"
|
|
42
|
+
Requires-Dist: black>=24.0.0; extra == "dev"
|
|
43
|
+
Requires-Dist: ruff>=0.3.0; extra == "dev"
|
|
44
|
+
Dynamic: license-file
|
|
45
|
+
|
|
46
|
+
<p align="center">
|
|
47
|
+
<img src="https://raw.githubusercontent.com/mohdibrahimaiml/epi-recorder/main/docs/assets/logo.png" alt="EPI Logo" width="180"/>
|
|
48
|
+
<br>
|
|
49
|
+
<h1 align="center">EPI</h1>
|
|
50
|
+
<p align="center"><strong>Verifiable Execution Evidence for AI Systems / AI Agents</strong></p>
|
|
51
|
+
<p align="center">
|
|
52
|
+
<em>A portable, cryptographically sealed artifact format for AI execution records.</em>
|
|
53
|
+
</p>
|
|
54
|
+
</p>
|
|
55
|
+
|
|
56
|
+
<p align="center">
|
|
57
|
+
<a href="https://pypi.org/project/epi-recorder/"><img src="https://img.shields.io/pypi/v/epi-recorder?style=for-the-badge&color=00d4ff&label=PyPI" alt="PyPI"/></a>
|
|
58
|
+
<a href="https://github.com/mohdibrahimaiml/epi-recorder"><img src="https://img.shields.io/badge/python-3.11%2B-blue?style=for-the-badge&logo=python&logoColor=white" alt="Python"/></a>
|
|
59
|
+
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-green?style=for-the-badge" alt="License"/></a>
|
|
60
|
+
</p>
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## What is EPI?
|
|
65
|
+
|
|
66
|
+
EPI (Evidence Package for AI) is a **file format** for capturing and verifying AI execution evidence.
|
|
67
|
+
|
|
68
|
+
An `.epi` file is to AI execution what PDF is to documents:
|
|
69
|
+
- **Self-contained** — prompts, responses, environment, viewer — all in one file
|
|
70
|
+
- **Universally viewable** — opens in any browser, no software required
|
|
71
|
+
- **Tamper-evident** — Ed25519 signatures prove the record wasn't altered
|
|
72
|
+
|
|
73
|
+
EPI is designed for **adversarial review**: audits, incident response, compliance, litigation.
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## Design Guarantees
|
|
78
|
+
|
|
79
|
+
EPI artifacts provide the following guarantees:
|
|
80
|
+
|
|
81
|
+
| Guarantee | Implementation |
|
|
82
|
+
|:----------|:---------------|
|
|
83
|
+
| **Explicitness** | Evidence capture is intentional and reviewable in source code |
|
|
84
|
+
| **Portability** | Single file, no external dependencies, works offline |
|
|
85
|
+
| **Offline Verifiability** | Signature verification requires no network or cloud services |
|
|
86
|
+
| **Adversarial Review** | Format assumes the reviewer does not trust the producer |
|
|
87
|
+
|
|
88
|
+
These are not features. They are **constraints** that define what EPI is.
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## Quick Start
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
pip install epi-recorder
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Capture Evidence (Explicit API)
|
|
99
|
+
|
|
100
|
+
```python
|
|
101
|
+
from epi_recorder import record
|
|
102
|
+
|
|
103
|
+
with record("evidence.epi") as epi:
|
|
104
|
+
response = client.chat.completions.create(model="gpt-4", messages=[...])
|
|
105
|
+
epi.log_llm_call(response) # Explicit capture
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Capture Evidence (Wrapper Client)
|
|
109
|
+
|
|
110
|
+
```python
|
|
111
|
+
from epi_recorder import record, wrap_openai
|
|
112
|
+
from openai import OpenAI
|
|
113
|
+
|
|
114
|
+
client = wrap_openai(OpenAI())
|
|
115
|
+
|
|
116
|
+
with record("evidence.epi"):
|
|
117
|
+
response = client.chat.completions.create(...) # Captured via wrapper
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Verify Evidence
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
epi verify evidence.epi
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## The `.epi` Artifact Format
|
|
129
|
+
|
|
130
|
+
An `.epi` file is a ZIP archive with a defined structure. See [docs/EPI-SPEC.md](docs/EPI-SPEC.md) for the full specification.
|
|
131
|
+
|
|
132
|
+
```
|
|
133
|
+
evidence.epi
|
|
134
|
+
├── mimetype # "application/epi+zip"
|
|
135
|
+
├── manifest.json # Metadata + Ed25519 signature
|
|
136
|
+
├── steps.jsonl # Execution steps (NDJSON)
|
|
137
|
+
├── env.json # Runtime environment snapshot
|
|
138
|
+
└── viewer/
|
|
139
|
+
└── index.html # Self-contained offline viewer
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
The embedded viewer allows any recipient to:
|
|
143
|
+
- View the complete execution timeline
|
|
144
|
+
- Verify cryptographic integrity
|
|
145
|
+
- Inspect individual steps
|
|
146
|
+
|
|
147
|
+
No software installation required.
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
## CLI Reference
|
|
152
|
+
|
|
153
|
+
### Primary Commands
|
|
154
|
+
|
|
155
|
+
| Command | Purpose |
|
|
156
|
+
|:--------|:--------|
|
|
157
|
+
| `epi run <script.py>` | Capture execution evidence to `.epi` |
|
|
158
|
+
| `epi verify <file.epi>` | Verify artifact integrity and signature |
|
|
159
|
+
| `epi view <file.epi>` | Open artifact in browser viewer |
|
|
160
|
+
| `epi keys list` | Manage signing keys |
|
|
161
|
+
|
|
162
|
+
### Secondary Tools
|
|
163
|
+
|
|
164
|
+
These tools consume evidence artifacts for analysis:
|
|
165
|
+
|
|
166
|
+
| Command | Purpose |
|
|
167
|
+
|:--------|:--------|
|
|
168
|
+
| `epi debug <file.epi>` | Heuristic analysis (loops, errors, inefficiencies) |
|
|
169
|
+
| `epi chat <file.epi>` | Natural language querying via LLM |
|
|
170
|
+
|
|
171
|
+
> **Note:** `debug` and `chat` are convenience tools built on top of the evidence format.
|
|
172
|
+
> They are not part of the core specification.
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
## Cryptographic Properties
|
|
177
|
+
|
|
178
|
+
| Property | Implementation |
|
|
179
|
+
|:---------|:---------------|
|
|
180
|
+
| **Signatures** | Ed25519 (RFC 8032) |
|
|
181
|
+
| **Hashing** | SHA-256 content addressing |
|
|
182
|
+
| **Key Storage** | Local keyring, user-controlled |
|
|
183
|
+
| **Verification** | Client-side, zero external dependencies |
|
|
184
|
+
|
|
185
|
+
Signatures are **optional but recommended**. Unsigned artifacts are still valid but cannot prove origin.
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
## When to Use EPI
|
|
190
|
+
|
|
191
|
+
### Appropriate Use Cases
|
|
192
|
+
|
|
193
|
+
- Post-incident forensics
|
|
194
|
+
- Compliance documentation
|
|
195
|
+
- Audit trails for autonomous systems
|
|
196
|
+
- Reproducibility evidence for research
|
|
197
|
+
- Litigation-grade execution records
|
|
198
|
+
|
|
199
|
+
### Not Designed For
|
|
200
|
+
|
|
201
|
+
- Real-time monitoring dashboards
|
|
202
|
+
- High-frequency telemetry
|
|
203
|
+
- System health metrics
|
|
204
|
+
- Application performance monitoring
|
|
205
|
+
|
|
206
|
+
EPI produces **artifacts**, not **streams**.
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
## Supported Providers
|
|
211
|
+
|
|
212
|
+
| Provider | Capture Method |
|
|
213
|
+
|:---------|:---------------|
|
|
214
|
+
| OpenAI | Wrapper client or explicit API |
|
|
215
|
+
| Anthropic | Explicit API |
|
|
216
|
+
| Google Gemini | Explicit API |
|
|
217
|
+
| Any HTTP-based LLM | Explicit API via `log_llm_call()` |
|
|
218
|
+
|
|
219
|
+
EPI does not depend on provider-specific integrations. The explicit API works with any response format.
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
## v2.3.0 — Design Correction
|
|
224
|
+
|
|
225
|
+
This release corrects EPI's evidence capture model.
|
|
226
|
+
|
|
227
|
+
| Before (v2.2.x) | After (v2.3.0) |
|
|
228
|
+
|:----------------|:---------------|
|
|
229
|
+
| Implicit monkey-patching | Explicit capture |
|
|
230
|
+
| Fragile to SDK changes | Stable across versions |
|
|
231
|
+
| Hidden instrumentation | Reviewable in source |
|
|
232
|
+
|
|
233
|
+
**Rationale:** Evidence systems must be intentional. Implicit capture was convenient but violated the explicitness guarantee.
|
|
234
|
+
|
|
235
|
+
**Migration:** Replace implicit capture with `epi.log_llm_call(response)` or `wrap_openai()`.
|
|
236
|
+
|
|
237
|
+
**Legacy mode:** `record(legacy_patching=True)` is deprecated and will be removed in v3.0.
|
|
238
|
+
|
|
239
|
+
---
|
|
240
|
+
|
|
241
|
+
## Release History
|
|
242
|
+
|
|
243
|
+
| Version | Date | Summary |
|
|
244
|
+
|:--------|:-----|:--------|
|
|
245
|
+
| **2.3.0** | 2026-02-06 | Explicit capture, wrapper clients, design correction |
|
|
246
|
+
| **2.2.0** | 2026-01-30 | SQLite storage, async support, context isolation |
|
|
247
|
+
| **2.1.3** | 2026-01-24 | Gemini capture, evidence querying |
|
|
248
|
+
| **2.1.0** | 2025-12-15 | Initial release |
|
|
249
|
+
|
|
250
|
+
See [CHANGELOG.md](./CHANGELOG.md) for full details.
|
|
251
|
+
|
|
252
|
+
---
|
|
253
|
+
|
|
254
|
+
## Contributing
|
|
255
|
+
|
|
256
|
+
```bash
|
|
257
|
+
git clone https://github.com/mohdibrahimaiml/epi-recorder.git
|
|
258
|
+
cd epi-recorder
|
|
259
|
+
pip install -e ".[dev]"
|
|
260
|
+
pytest
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
See [CONTRIBUTING.md](./CONTRIBUTING.md) for guidelines.
|
|
264
|
+
|
|
265
|
+
---
|
|
266
|
+
|
|
267
|
+
## License
|
|
268
|
+
|
|
269
|
+
MIT License. See [LICENSE](./LICENSE).
|
|
@@ -14,25 +14,28 @@ epi_cli/view.py,sha256=EP9takENuZnRllBsxDze9Mm32TGsyxsQaUhlNmUNA_w,4027
|
|
|
14
14
|
epi_core/__init__.py,sha256=8CTVjxZDI6oy-MMqWTILY9h8rgSZXS8kVzgySympGJU,309
|
|
15
15
|
epi_core/container.py,sha256=Eop4CN3TgCoxRyEWorbjvVBnFaxS4zkccdDwgXQ4eIk,13344
|
|
16
16
|
epi_core/redactor.py,sha256=GAq6R9gkuAHyzgE9sxBXpbQvL_v_myEktxTWFNFnrbY,9892
|
|
17
|
-
epi_core/schemas.py,sha256=
|
|
17
|
+
epi_core/schemas.py,sha256=iVz6yqVnXEe_mG5wh6Y4ojGHyop_kB5igpKXRkK7fT8,4734
|
|
18
18
|
epi_core/serialize.py,sha256=KB7Z7dfDFh6qq0tlrwjWADOBUV4z32q29Dt2yiniGGg,5691
|
|
19
19
|
epi_core/storage.py,sha256=XEVbdr5xf00LDDJMqCdrZDFvVS-BZ1e1CWzDaJqG0jE,5374
|
|
20
20
|
epi_core/trust.py,sha256=_RgYABg0vVH3yBDeXJD7jEyq7WMm5Sli0DHFLmu7lkQ,7970
|
|
21
|
-
epi_recorder/__init__.py,sha256=
|
|
22
|
-
epi_recorder/api.py,sha256=
|
|
21
|
+
epi_recorder/__init__.py,sha256=tCq2jrJHLxOfO4FPJL3W7F9dRIiOmbNbOZ52cUnqa90,565
|
|
22
|
+
epi_recorder/api.py,sha256=HK10VkaOLxdi-QSw4Jb_NfW-_p0FtXqWQqTJT-rOvlQ,29820
|
|
23
23
|
epi_recorder/async_api.py,sha256=a2WQL8MnJ8uwnLD6unDZxASe5JbywP1V-8gcFyySFM8,4949
|
|
24
24
|
epi_recorder/bootstrap.py,sha256=vk6mKnaHcnanm8SB7dYGPDJ8E2iSBSX3OTQ3zyO-6b0,1851
|
|
25
25
|
epi_recorder/environment.py,sha256=09KuIb7GOxiSHu9OsacaxaHXFJy5e7ewbS3Jz4fX2Zk,6604
|
|
26
|
-
epi_recorder/patcher.py,sha256=
|
|
26
|
+
epi_recorder/patcher.py,sha256=U_1MRMhLtcdrYxDdD3Lt6MZ4nolkSiYIa93Vn1Go4yI,20981
|
|
27
27
|
epi_recorder/test_import.py,sha256=_wrlfu0BLtT21AINf1_NugJTvM-RVNKJOyzokMezjO0,462
|
|
28
28
|
epi_recorder/test_script.py,sha256=ot2vRtgvUdeqk6Oj_cz0TZyQN9fUFVHy2E82jdzZUOs,95
|
|
29
|
-
epi_recorder
|
|
30
|
-
|
|
29
|
+
epi_recorder/wrappers/__init__.py,sha256=uG0jSBjM_wYo2_lmEiHzDtJbSgF0XlguaNye-dzVjPY,409
|
|
30
|
+
epi_recorder/wrappers/base.py,sha256=uZNNMJSgkf50J_Z-VYO9HOPk-1A1J00BivvKET4opIk,2641
|
|
31
|
+
epi_recorder/wrappers/openai.py,sha256=Mc5LxUSBQtaFyCh7MG0kwe8Wt0VM17weOCRh0N3vjuY,5977
|
|
32
|
+
epi_recorder-2.3.0.dist-info/licenses/LICENSE,sha256=C9g69QrsraEzIORyleKkUeim8h49747brp68ZUf9_ms,1089
|
|
33
|
+
epi_viewer_static/app.js,sha256=2CkRO3iq4J0QTpFgpfAvzGQDrrAIXGp61cJfIC225Cc,20362
|
|
31
34
|
epi_viewer_static/crypto.js,sha256=2bdANR9tLCPRE9joOih4kKVtptpfRXxERNps4IEhjAQ,19082
|
|
32
35
|
epi_viewer_static/index.html,sha256=sPNXnDTnk0ArVLofdKB3hhd8q-NL1AUmjucytXoythk,3302
|
|
33
36
|
epi_viewer_static/viewer_lite.css,sha256=EGsbTiaSZcnep5GMXm6eKxsfr9oIg_IjEDDI94KI4vc,4695
|
|
34
|
-
epi_recorder-2.
|
|
35
|
-
epi_recorder-2.
|
|
36
|
-
epi_recorder-2.
|
|
37
|
-
epi_recorder-2.
|
|
38
|
-
epi_recorder-2.
|
|
37
|
+
epi_recorder-2.3.0.dist-info/METADATA,sha256=9ZGZtvoz7vNiy6e35cB9AQUqRWpNNDQGHPqEZ_bfl1Q,8761
|
|
38
|
+
epi_recorder-2.3.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
39
|
+
epi_recorder-2.3.0.dist-info/entry_points.txt,sha256=MfMwqVRx_yMGbuPpiyjz2f8fQp8TUbHmRC1H_bupoyM,41
|
|
40
|
+
epi_recorder-2.3.0.dist-info/top_level.txt,sha256=osrjwlhDfJZSucB-G1u-rF6o0L1OCx2d892gSWr8Iik,77
|
|
41
|
+
epi_recorder-2.3.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024-2026 EPI Labs
|
|
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.
|
epi_viewer_static/app.js
CHANGED
|
@@ -230,6 +230,14 @@ function renderStep(step) {
|
|
|
230
230
|
contentDiv.innerHTML = renderLLMRequest(content);
|
|
231
231
|
} else if (kind === 'llm.response') {
|
|
232
232
|
contentDiv.innerHTML = renderLLMResponse(content);
|
|
233
|
+
} else if (kind === 'llm.error') {
|
|
234
|
+
contentDiv.innerHTML = renderLLMError(content);
|
|
235
|
+
} else if (kind === 'http.request') {
|
|
236
|
+
contentDiv.innerHTML = renderHTTPRequest(content);
|
|
237
|
+
} else if (kind === 'http.response') {
|
|
238
|
+
contentDiv.innerHTML = renderHTTPResponse(content);
|
|
239
|
+
} else if (kind === 'http.error') {
|
|
240
|
+
contentDiv.innerHTML = renderHTTPError(content);
|
|
233
241
|
} else if (kind === 'security.redaction') {
|
|
234
242
|
contentDiv.innerHTML = renderRedaction(content);
|
|
235
243
|
} else {
|
|
@@ -328,6 +336,74 @@ function renderRedaction(content) {
|
|
|
328
336
|
`;
|
|
329
337
|
}
|
|
330
338
|
|
|
339
|
+
// Render LLM error
|
|
340
|
+
function renderLLMError(content) {
|
|
341
|
+
return `
|
|
342
|
+
<div class="bg-red-50 border border-red-200 rounded-lg p-3 text-sm">
|
|
343
|
+
<div class="flex items-center text-red-800">
|
|
344
|
+
<svg class="w-5 h-5 mr-2" fill="currentColor" viewBox="0 0 20 20">
|
|
345
|
+
<path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7 4a1 1 0 11-2 0 1 1 0 012 0zm-1-9a1 1 0 00-1 1v4a1 1 0 102 0V6a1 1 0 00-1-1z" clip-rule="evenodd"/>
|
|
346
|
+
</svg>
|
|
347
|
+
<span class="font-medium">LLM Error</span>
|
|
348
|
+
</div>
|
|
349
|
+
<div class="mt-2 text-red-700 font-mono text-xs">
|
|
350
|
+
${escapeHTML(content.error || content.message || JSON.stringify(content))}
|
|
351
|
+
</div>
|
|
352
|
+
${content.provider ? `<div class="mt-1 text-xs text-red-600">${content.provider} • ${content.model || 'unknown'}</div>` : ''}
|
|
353
|
+
</div>
|
|
354
|
+
`;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
// Render HTTP request
|
|
358
|
+
function renderHTTPRequest(content) {
|
|
359
|
+
return `
|
|
360
|
+
<div class="bg-indigo-50 border border-indigo-200 rounded-lg p-3 text-sm">
|
|
361
|
+
<div class="flex items-center text-indigo-800 mb-2">
|
|
362
|
+
<span class="font-medium px-2 py-0.5 bg-indigo-200 rounded text-xs">${content.method || 'GET'}</span>
|
|
363
|
+
<span class="ml-2 font-mono text-xs break-all">${escapeHTML(content.url || '')}</span>
|
|
364
|
+
</div>
|
|
365
|
+
${content.headers ? `<div class="text-xs text-indigo-600">Headers: ${Object.keys(content.headers).length}</div>` : ''}
|
|
366
|
+
${content.body ? `<pre class="mt-2 text-xs bg-indigo-100 p-2 rounded overflow-auto max-h-32">${escapeHTML(typeof content.body === 'string' ? content.body : JSON.stringify(content.body, null, 2))}</pre>` : ''}
|
|
367
|
+
</div>
|
|
368
|
+
`;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
// Render HTTP response
|
|
372
|
+
function renderHTTPResponse(content) {
|
|
373
|
+
const statusColor = (content.status_code >= 200 && content.status_code < 300) ? 'green' :
|
|
374
|
+
(content.status_code >= 400) ? 'red' : 'yellow';
|
|
375
|
+
return `
|
|
376
|
+
<div class="bg-${statusColor}-50 border border-${statusColor}-200 rounded-lg p-3 text-sm">
|
|
377
|
+
<div class="flex items-center text-${statusColor}-800 mb-2">
|
|
378
|
+
<span class="font-medium px-2 py-0.5 bg-${statusColor}-200 rounded text-xs">${content.status_code || '???'}</span>
|
|
379
|
+
<span class="ml-2 text-xs">${content.url || ''}</span>
|
|
380
|
+
${content.latency_seconds ? `<span class="ml-auto text-xs">⚡ ${content.latency_seconds}s</span>` : ''}
|
|
381
|
+
</div>
|
|
382
|
+
${content.body ? `<pre class="mt-2 text-xs bg-gray-100 p-2 rounded overflow-auto max-h-32">${escapeHTML(typeof content.body === 'string' ? content.body.slice(0, 500) : JSON.stringify(content.body, null, 2).slice(0, 500))}${(content.body.length > 500) ? '...' : ''}</pre>` : ''}
|
|
383
|
+
</div>
|
|
384
|
+
`;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
// Render HTTP error
|
|
388
|
+
function renderHTTPError(content) {
|
|
389
|
+
return `
|
|
390
|
+
<div class="bg-red-50 border border-red-200 rounded-lg p-3 text-sm">
|
|
391
|
+
<div class="flex items-center text-red-800">
|
|
392
|
+
<svg class="w-5 h-5 mr-2" fill="currentColor" viewBox="0 0 20 20">
|
|
393
|
+
<path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7 4a1 1 0 11-2 0 1 1 0 012 0zm-1-9a1 1 0 00-1 1v4a1 1 0 102 0V6a1 1 0 00-1-1z" clip-rule="evenodd"/>
|
|
394
|
+
</svg>
|
|
395
|
+
<span class="font-medium">HTTP Error</span>
|
|
396
|
+
</div>
|
|
397
|
+
<div class="mt-2 text-red-700">
|
|
398
|
+
<span class="font-mono text-xs">${escapeHTML(content.url || '')}</span>
|
|
399
|
+
</div>
|
|
400
|
+
<div class="mt-1 text-red-600 text-xs">
|
|
401
|
+
${escapeHTML(content.error || content.message || JSON.stringify(content))}
|
|
402
|
+
</div>
|
|
403
|
+
</div>
|
|
404
|
+
`;
|
|
405
|
+
}
|
|
406
|
+
|
|
331
407
|
// Escape HTML to prevent XSS
|
|
332
408
|
function escapeHTML(str) {
|
|
333
409
|
const div = document.createElement('div');
|
|
@@ -404,5 +480,4 @@ if (document.readyState === 'loading') {
|
|
|
404
480
|
} else {
|
|
405
481
|
init();
|
|
406
482
|
}
|
|
407
|
-
|
|
408
|
-
|
|
483
|
+
|
|
@@ -1,162 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: epi-recorder
|
|
3
|
-
Version: 2.2.0
|
|
4
|
-
Summary: The Flight Recorder for AI Agents. Debug LangChain & CrewAI with execution tracing.
|
|
5
|
-
Author-email: EPI Labs <mohdibrahim@epilabs.org>
|
|
6
|
-
Maintainer-email: Mohd Ibrahim Afridi <mohdibrahim@epilabs.org>
|
|
7
|
-
License: Apache-2.0
|
|
8
|
-
Project-URL: Homepage, https://epilabs.org
|
|
9
|
-
Project-URL: Documentation, https://epilabs.org/docs
|
|
10
|
-
Project-URL: Repository, https://github.com/mohdibrahimaiml/epi-recorder
|
|
11
|
-
Project-URL: Issues, https://github.com/mohdibrahimaiml/epi-recorder/issues
|
|
12
|
-
Project-URL: Discussions, https://github.com/mohdibrahimaiml/epi-recorder/discussions
|
|
13
|
-
Keywords: ai,debugging,agents,langchain,crewai,devtools,observability,llm,openai,gemini,tracing,flight-recorder
|
|
14
|
-
Classifier: Development Status :: 4 - Beta
|
|
15
|
-
Classifier: Intended Audience :: Developers
|
|
16
|
-
Classifier: License :: OSI Approved :: Apache Software License
|
|
17
|
-
Classifier: Operating System :: OS Independent
|
|
18
|
-
Classifier: Programming Language :: Python :: 3
|
|
19
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
-
Classifier: Topic :: Software Development :: Debuggers
|
|
22
|
-
Classifier: Topic :: Software Development :: Testing
|
|
23
|
-
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
24
|
-
Classifier: Topic :: System :: Logging
|
|
25
|
-
Classifier: Typing :: Typed
|
|
26
|
-
Classifier: Framework :: Pydantic
|
|
27
|
-
Classifier: Framework :: Pydantic :: 2
|
|
28
|
-
Requires-Python: >=3.11
|
|
29
|
-
Description-Content-Type: text/markdown
|
|
30
|
-
License-File: LICENSE
|
|
31
|
-
Requires-Dist: pydantic>=2.0.0
|
|
32
|
-
Requires-Dist: cryptography>=41.0.0
|
|
33
|
-
Requires-Dist: cbor2>=5.6.0
|
|
34
|
-
Requires-Dist: typer[all]>=0.12.0
|
|
35
|
-
Requires-Dist: rich>=13.0.0
|
|
36
|
-
Requires-Dist: google-generativeai>=0.4.0
|
|
37
|
-
Provides-Extra: dev
|
|
38
|
-
Requires-Dist: pytest>=8.0.0; extra == "dev"
|
|
39
|
-
Requires-Dist: pytest-asyncio>=0.23.0; extra == "dev"
|
|
40
|
-
Requires-Dist: pytest-cov>=4.1.0; extra == "dev"
|
|
41
|
-
Requires-Dist: black>=24.0.0; extra == "dev"
|
|
42
|
-
Requires-Dist: ruff>=0.3.0; extra == "dev"
|
|
43
|
-
Dynamic: license-file
|
|
44
|
-
|
|
45
|
-
<p align="center">
|
|
46
|
-
<img src="docs/assets/logo.png" alt="EPI Logo" width="200"/>
|
|
47
|
-
<br>
|
|
48
|
-
<h1 align="center">EPI Recorder</h1>
|
|
49
|
-
</p>
|
|
50
|
-
|
|
51
|
-
[](https://github.com/mohdibrahimaiml/epi-recorder/releases)
|
|
52
|
-
[](https://pypi.org/project/epi-recorder/)
|
|
53
|
-
[](LICENSE)
|
|
54
|
-
[](https://pypi.org/project/epi-recorder/)
|
|
55
|
-
[](#)
|
|
56
|
-
|
|
57
|
-
**The Flight Recorder for AI Agents**
|
|
58
|
-
|
|
59
|
-
Debug production failures in LangChain, CrewAI, and custom agents with one command.
|
|
60
|
-
Captures complete execution context—prompts, responses, tool calls—and cryptographically seals them for audit trails.
|
|
61
|
-
|
|
62
|
-
📖 [Documentation](https://epilabs.org) • 🚀 [Quick Start](#quick-start) • 🔐 [Security](#security-compliance)
|
|
63
|
-
|
|
64
|
-
> "EPI Recorder provides the missing observability layer we needed for our autonomous agents. The flight recorder approach is a game changer."
|
|
65
|
-
> — Lead AI Engineer, Early Adopter
|
|
66
|
-
|
|
67
|
-
---
|
|
68
|
-
|
|
69
|
-
## Traction
|
|
70
|
-
- **4,000+** developers using EPI for daily debugging
|
|
71
|
-
- **12,000+** agent executions recorded
|
|
72
|
-
- **99.9%** atomic capture rate (zero data loss on crashes)
|
|
73
|
-
|
|
74
|
-
---
|
|
75
|
-
|
|
76
|
-
## Why EPI?
|
|
77
|
-
|
|
78
|
-
Your AI agent failed in production. It hallucinated. It looped infinitely. It cost you $50 in API calls.
|
|
79
|
-
|
|
80
|
-
**You can't reproduce it.** LLMs are non-deterministic. Your logs don't show the full prompt context. You're taking screenshots and pasting JSON into Slack.
|
|
81
|
-
|
|
82
|
-
**EPI is the black box.** One command captures everything. Debug locally. Prove what happened.
|
|
83
|
-
|
|
84
|
-
---
|
|
85
|
-
|
|
86
|
-
## Quick Start
|
|
87
|
-
|
|
88
|
-
```bash
|
|
89
|
-
pip install epi-recorder
|
|
90
|
-
|
|
91
|
-
# Record your agent (zero config)
|
|
92
|
-
epi run agent.py
|
|
93
|
-
|
|
94
|
-
# Debug the failure (opens browser viewer)
|
|
95
|
-
epi view recording.epi
|
|
96
|
-
|
|
97
|
-
# Verify integrity (cryptographic proof)
|
|
98
|
-
epi verify recording.epi
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
---
|
|
104
|
-
|
|
105
|
-
## Features
|
|
106
|
-
|
|
107
|
-
- **⚡ Zero Config**: `epi run` intercepts OpenAI, LangChain, CrewAI automatically—no code changes.
|
|
108
|
-
- **🔍 AI Debugging**: Built-in heuristics detect infinite loops, hallucinations, and cost inefficiencies.
|
|
109
|
-
- **🛡️ Crash Safe**: Atomic SQLite storage survives OOM and power failures (99.9% capture rate).
|
|
110
|
-
- **🔐 Tamper Proof**: Ed25519 signatures prove logs weren't edited (for compliance/audits).
|
|
111
|
-
- **🌐 Framework Agnostic**: Works with any Python agent (LangChain, CrewAI, AutoGPT, or 100 lines of raw code).
|
|
112
|
-
|
|
113
|
-
---
|
|
114
|
-
|
|
115
|
-
## How It Works
|
|
116
|
-
|
|
117
|
-
EPI acts as a **Parasitic Observer**—injecting instrumentation at the Python runtime level via `sitecustomize.py`.
|
|
118
|
-
|
|
119
|
-
1. **Intercept**: Captures LLM calls at the HTTP layer (`requests.Session`) and library level.
|
|
120
|
-
2. **Store**: Atomic SQLite WAL ensures zero data loss on crashes.
|
|
121
|
-
3. **Analyze**: `epi debug` uses local heuristics + AI to find root causes.
|
|
122
|
-
4. **Seal**: Canonical JSON (RFC 8785) + Ed25519 signatures create forensically-valid evidence.
|
|
123
|
-
|
|
124
|
-
```mermaid
|
|
125
|
-
graph LR
|
|
126
|
-
Script[User Script] -->|Intercept| Patcher[EPI Patcher]
|
|
127
|
-
Patcher -->|Write| WAL[(Atomic SQLite)]
|
|
128
|
-
WAL -->|Package| File[.epi File]
|
|
129
|
-
File -->|Sign| Key[Ed25519 Key]
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
---
|
|
133
|
-
|
|
134
|
-
## Security & Compliance
|
|
135
|
-
|
|
136
|
-
While EPI is built for daily debugging, it provides the cryptographic infrastructure required for regulated environments:
|
|
137
|
-
|
|
138
|
-
- **Signatures**: Ed25519 with client-side verification (zero-knowledge).
|
|
139
|
-
- **Standards**: Supports EU AI Act Article 6 logging requirements.
|
|
140
|
-
- **Privacy**: Automatic PII redaction, air-gapped operation (no cloud required).
|
|
141
|
-
|
|
142
|
-
*[Enterprise support available](mailto:enterprise@epilabs.org) for SOC2/ISO27001 environments.*
|
|
143
|
-
|
|
144
|
-
---
|
|
145
|
-
|
|
146
|
-
## Contributing
|
|
147
|
-
|
|
148
|
-
We welcome contributions! Please see [CONTRIBUTING.md](./CONTRIBUTING.md) for details.
|
|
149
|
-
|
|
150
|
-
```bash
|
|
151
|
-
git clone https://github.com/mohdibrahimaiml/epi-recorder.git
|
|
152
|
-
cd epi-recorder
|
|
153
|
-
pip install -e ".[dev]"
|
|
154
|
-
pytest
|
|
155
|
-
```
|
|
156
|
-
|
|
157
|
-
## License
|
|
158
|
-
|
|
159
|
-
Apache-2.0 License. See [LICENSE](./LICENSE) for details.
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|