agent-autopsy 0.1.0__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.
- agent_autopsy-0.1.0/.gitignore +13 -0
- agent_autopsy-0.1.0/CHANGELOG.md +11 -0
- agent_autopsy-0.1.0/LICENSE +21 -0
- agent_autopsy-0.1.0/MANIFEST.in +4 -0
- agent_autopsy-0.1.0/MARKETING.md +107 -0
- agent_autopsy-0.1.0/PKG-INFO +176 -0
- agent_autopsy-0.1.0/README.md +146 -0
- agent_autopsy-0.1.0/agent_autopsy/__init__.py +9 -0
- agent_autopsy-0.1.0/agent_autopsy/_footer.py +12 -0
- agent_autopsy-0.1.0/agent_autopsy/capture.py +156 -0
- agent_autopsy-0.1.0/agent_autopsy/cli.py +108 -0
- agent_autopsy-0.1.0/agent_autopsy/langchain_handler.py +221 -0
- agent_autopsy-0.1.0/agent_autopsy/models.py +51 -0
- agent_autopsy-0.1.0/agent_autopsy/py.typed +0 -0
- agent_autopsy-0.1.0/agent_autopsy/renderer.py +243 -0
- agent_autopsy-0.1.0/pyproject.toml +47 -0
- agent_autopsy-0.1.0/tests/__init__.py +0 -0
- agent_autopsy-0.1.0/tests/fixtures/sample_trace.json +60 -0
- agent_autopsy-0.1.0/tests/test_capture.py +208 -0
- agent_autopsy-0.1.0/tests/test_cli.py +160 -0
- agent_autopsy-0.1.0/tests/test_langchain.py +143 -0
- agent_autopsy-0.1.0/tests/test_renderer.py +136 -0
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## [0.1.0] - 2026-03-05
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
- `Autopsy` context manager for zero-config error tracing
|
|
7
|
+
- `AutopsyLangChainHandler` for automatic LangChain event capture
|
|
8
|
+
- CLI tool (`autopsy view`) with terminal tree rendering and ANSI colors
|
|
9
|
+
- JSON trace file format with timestamps, durations, and error details
|
|
10
|
+
- Thread-safe trace capture
|
|
11
|
+
- 40 comprehensive tests
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Aegis Ledger
|
|
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,107 @@
|
|
|
1
|
+
# agent-autopsy Marketing Plan
|
|
2
|
+
|
|
3
|
+
## Awesome Lists
|
|
4
|
+
|
|
5
|
+
### awesome-langchain
|
|
6
|
+
|
|
7
|
+
**PR Title:** Add agent-autopsy -- debug tool for LangChain agent traces
|
|
8
|
+
|
|
9
|
+
**Category:** Tools / Debugging
|
|
10
|
+
|
|
11
|
+
**Entry:**
|
|
12
|
+
```markdown
|
|
13
|
+
- [agent-autopsy](https://github.com/VladislavRoss/agent-autopsy-sdk) - Debug tool that captures and visualizes LangChain agent execution traces with timeline, tool calls, and decision reasoning.
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
**Checklist before PR:**
|
|
17
|
+
- [ ] Package on PyPI
|
|
18
|
+
- [ ] README with usage examples
|
|
19
|
+
- [ ] At least 30 GitHub stars (soft requirement)
|
|
20
|
+
- [ ] Working demo/screenshot
|
|
21
|
+
|
|
22
|
+
### awesome-python
|
|
23
|
+
|
|
24
|
+
**PR Title:** Add agent-autopsy to Debugging Tools
|
|
25
|
+
|
|
26
|
+
**Category:** Debugging Tools
|
|
27
|
+
|
|
28
|
+
**Entry:**
|
|
29
|
+
```markdown
|
|
30
|
+
- [agent-autopsy](https://github.com/VladislavRoss/agent-autopsy-sdk) - Execution trace debugger for AI agents (LangChain, CrewAI, OpenAI Agents SDK).
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## Reddit Strategy
|
|
36
|
+
|
|
37
|
+
### r/LangChain
|
|
38
|
+
|
|
39
|
+
**Post Title:** "I built a free debugging tool for LangChain agents -- agent-autopsy"
|
|
40
|
+
|
|
41
|
+
**Body:**
|
|
42
|
+
- Problem: debugging multi-step agents is painful (print statements, manual logging)
|
|
43
|
+
- Solution: drop-in callback handler that captures the full execution trace
|
|
44
|
+
- Show: timeline visualization, tool call details, decision reasoning
|
|
45
|
+
- Free, MIT licensed, pip install agent-autopsy
|
|
46
|
+
- Upgrade path: for tamperproof traces, there's aegis-ledger-sdk (link in footer)
|
|
47
|
+
|
|
48
|
+
**Rules:** No hard sell. Genuine value first. Mention Aegis only in context of upgrade.
|
|
49
|
+
|
|
50
|
+
### r/MachineLearning
|
|
51
|
+
|
|
52
|
+
**Post Title:** "[P] agent-autopsy: Execution trace debugger for AI agents"
|
|
53
|
+
|
|
54
|
+
**Body:** Focus on the debugging problem. Technical audience. Link to GitHub.
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## Discord Communities
|
|
59
|
+
|
|
60
|
+
| Community | Channel | Approach |
|
|
61
|
+
|-----------|---------|----------|
|
|
62
|
+
| LangChain Discord | #showcase | Share with demo |
|
|
63
|
+
| CrewAI Discord | #showcase | Integration example |
|
|
64
|
+
| AI Engineer Discord | #tools | Technical deep-dive |
|
|
65
|
+
|
|
66
|
+
**Rule:** Always provide genuine value. Never spam. Answer questions. Be helpful.
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## Growth Funnel
|
|
71
|
+
|
|
72
|
+
```
|
|
73
|
+
agent-autopsy (free, OSS)
|
|
74
|
+
|
|
|
75
|
+
| Footer: "For tamperproof traces: aegis-ledger.com"
|
|
76
|
+
| upgrade_code: "from aegis.langchain import AegisCallbackHandler"
|
|
77
|
+
|
|
|
78
|
+
v
|
|
79
|
+
aegis-ledger-sdk (freemium)
|
|
80
|
+
|
|
|
81
|
+
| 10k free events/month
|
|
82
|
+
| Pro: CHF 39/mo (500k events)
|
|
83
|
+
| Business: CHF 149/mo (5M events)
|
|
84
|
+
|
|
|
85
|
+
v
|
|
86
|
+
Enterprise (custom)
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## PyPI Publication
|
|
90
|
+
|
|
91
|
+
**Package name:** `agent-autopsy`
|
|
92
|
+
|
|
93
|
+
**Steps:**
|
|
94
|
+
1. Ensure all 40 tests pass
|
|
95
|
+
2. Update version in pyproject.toml
|
|
96
|
+
3. `hatch build && hatch publish`
|
|
97
|
+
4. Verify: `pip install agent-autopsy`
|
|
98
|
+
|
|
99
|
+
## Success Metrics (First 30 Days)
|
|
100
|
+
|
|
101
|
+
| Metric | Target |
|
|
102
|
+
|--------|--------|
|
|
103
|
+
| PyPI installs | 200+ |
|
|
104
|
+
| GitHub stars | 25+ |
|
|
105
|
+
| Reddit post upvotes | 20+ |
|
|
106
|
+
| awesome-langchain PR merged | Yes |
|
|
107
|
+
| Users clicking upgrade link | 10+ |
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: agent-autopsy
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Debug AI agent failures with zero-config execution traces
|
|
5
|
+
Project-URL: Homepage, https://github.com/VladislavRoss/agent-autopsy-sdk
|
|
6
|
+
Project-URL: Documentation, https://github.com/VladislavRoss/agent-autopsy-sdk#readme
|
|
7
|
+
Project-URL: Production Tracing, https://www.aegis-ledger.com
|
|
8
|
+
Author-email: Aegis Ledger <info@aegis-ledger.com>
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: agents,ai-agents,debugging,langchain,tracing
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Topic :: Software Development :: Debuggers
|
|
21
|
+
Requires-Python: >=3.10
|
|
22
|
+
Provides-Extra: dev
|
|
23
|
+
Requires-Dist: mypy>=1.10; extra == 'dev'
|
|
24
|
+
Requires-Dist: pytest-cov>=5.0; extra == 'dev'
|
|
25
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
26
|
+
Requires-Dist: ruff>=0.4; extra == 'dev'
|
|
27
|
+
Provides-Extra: langchain
|
|
28
|
+
Requires-Dist: langchain-core>=0.1; extra == 'langchain'
|
|
29
|
+
Description-Content-Type: text/markdown
|
|
30
|
+
|
|
31
|
+
# agent-autopsy
|
|
32
|
+
|
|
33
|
+
[](https://opensource.org/licenses/MIT)
|
|
34
|
+
[](https://www.python.org/downloads/)
|
|
35
|
+
|
|
36
|
+
**Zero-dependency post-mortem traces for AI agent failures.**
|
|
37
|
+
|
|
38
|
+
Wrap your agent code in a single context manager. On success, nothing happens.
|
|
39
|
+
On error, a detailed JSON trace file is written automatically -- ready for
|
|
40
|
+
debugging, sharing, or replaying.
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
+======================================================+
|
|
44
|
+
| AGENT AUTOPSY -- sess_a7f3b2c |
|
|
45
|
+
| 2026-03-05 14:32:01 -> 14:32:08 (7.2s) |
|
|
46
|
+
+======================================================+
|
|
47
|
+
| |
|
|
48
|
+
| |- [tool_call] search_orders ........... v 340ms |
|
|
49
|
+
| |- [llm_call] gpt-4o .................. v 1.2s |
|
|
50
|
+
| |- [tool_call] stripe.create_refund .... x 89ms |
|
|
51
|
+
| | +-- ERROR: Card declined |
|
|
52
|
+
| +- [error] Unhandled exception ......... x 0ms |
|
|
53
|
+
| +-- ValueError: amount must be positive |
|
|
54
|
+
| |
|
|
55
|
+
+======================================================+
|
|
56
|
+
For tamperproof traces: https://www.aegis-ledger.com
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Install
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
pip install agent-autopsy
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
For LangChain integration:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
pip install agent-autopsy[langchain]
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Usage
|
|
72
|
+
|
|
73
|
+
### 1. Basic -- wrap any agent code
|
|
74
|
+
|
|
75
|
+
```python
|
|
76
|
+
from agent_autopsy import Autopsy
|
|
77
|
+
|
|
78
|
+
with Autopsy() as trace:
|
|
79
|
+
trace.log("tool_call", "search_web", input="refund policy", duration_ms=340)
|
|
80
|
+
trace.log("llm_call", "gpt-4o", input="Summarise results", duration_ms=1200)
|
|
81
|
+
# If an exception occurs here, a JSON trace file is written automatically.
|
|
82
|
+
result = my_agent.invoke({"input": "Process refund for order #9281"})
|
|
83
|
+
|
|
84
|
+
# Success -> nothing written (silent)
|
|
85
|
+
# Error -> ./autopsy_sess_<hash>.json created
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### 2. With LangChain -- automatic event capture
|
|
89
|
+
|
|
90
|
+
```python
|
|
91
|
+
from agent_autopsy import Autopsy
|
|
92
|
+
from agent_autopsy.langchain_handler import AutopsyLangChainHandler
|
|
93
|
+
|
|
94
|
+
handler = AutopsyLangChainHandler()
|
|
95
|
+
|
|
96
|
+
with Autopsy(handler=handler) as trace:
|
|
97
|
+
chain.invoke(
|
|
98
|
+
{"input": "Process refunds"},
|
|
99
|
+
config={"callbacks": [handler]},
|
|
100
|
+
)
|
|
101
|
+
# All LLM calls, tool calls, and chain steps are captured automatically.
|
|
102
|
+
# On error, everything is written to a single JSON file.
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### 3. CLI -- view a trace file
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
# Pretty-printed terminal tree (with colours)
|
|
109
|
+
autopsy view autopsy_sess_a7f3b2c.json
|
|
110
|
+
|
|
111
|
+
# Raw JSON output
|
|
112
|
+
autopsy view autopsy_sess_a7f3b2c.json --raw
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## How it works
|
|
116
|
+
|
|
117
|
+
1. `Autopsy()` creates a trace session with a unique ID
|
|
118
|
+
2. During the `with` block, call `trace.log()` to record events (or use the
|
|
119
|
+
LangChain handler for automatic capture)
|
|
120
|
+
3. On `__exit__`:
|
|
121
|
+
- **No exception** -- session is discarded, no file written, zero overhead
|
|
122
|
+
- **Exception** -- session + full traceback are written to a JSON file
|
|
123
|
+
|
|
124
|
+
Every JSON file includes all captured events with timestamps, durations,
|
|
125
|
+
input/output previews, and error messages.
|
|
126
|
+
|
|
127
|
+
## JSON output format
|
|
128
|
+
|
|
129
|
+
```json
|
|
130
|
+
{
|
|
131
|
+
"session_id": "a7f3b2c",
|
|
132
|
+
"start_time": "2026-03-05T14:32:01.000000+00:00",
|
|
133
|
+
"end_time": "2026-03-05T14:32:08.200000+00:00",
|
|
134
|
+
"error": "Traceback (most recent call last): ...",
|
|
135
|
+
"entries": [
|
|
136
|
+
{
|
|
137
|
+
"timestamp": "2026-03-05T14:32:01.500000+00:00",
|
|
138
|
+
"type": "tool_call",
|
|
139
|
+
"name": "search_orders",
|
|
140
|
+
"input_preview": "{\"order_id\": \"9281\"}",
|
|
141
|
+
"output_preview": "{\"order\": {\"id\": 9281}}",
|
|
142
|
+
"duration_ms": 340,
|
|
143
|
+
"status": "ok"
|
|
144
|
+
}
|
|
145
|
+
],
|
|
146
|
+
"_aegis_footer": {
|
|
147
|
+
"message": "For tamperproof, legally defensible traces: https://www.aegis-ledger.com",
|
|
148
|
+
"upgrade": "pip install aegis-ledger-sdk[langchain]"
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## Going to Production?
|
|
154
|
+
|
|
155
|
+
`agent-autopsy` is a **debugging tool** for local development. When you need
|
|
156
|
+
tamperproof, hash-chained, cryptographically signed traces for production --
|
|
157
|
+
upgrade to the full **Aegis Ledger SDK**:
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
pip install aegis-ledger-sdk[langchain]
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
```python
|
|
164
|
+
# 2 lines to upgrade from agent-autopsy to production tracing:
|
|
165
|
+
from aegis.langchain import AegisCallbackHandler
|
|
166
|
+
handler = AegisCallbackHandler(api_key="your-key")
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Every trace is hash-chained (SHA-256) and signed (Ed25519) on the Internet
|
|
170
|
+
Computer blockchain. Immutable. Auditable. Legally defensible.
|
|
171
|
+
|
|
172
|
+
Learn more at [aegis-ledger.com](https://www.aegis-ledger.com).
|
|
173
|
+
|
|
174
|
+
## License
|
|
175
|
+
|
|
176
|
+
MIT
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# agent-autopsy
|
|
2
|
+
|
|
3
|
+
[](https://opensource.org/licenses/MIT)
|
|
4
|
+
[](https://www.python.org/downloads/)
|
|
5
|
+
|
|
6
|
+
**Zero-dependency post-mortem traces for AI agent failures.**
|
|
7
|
+
|
|
8
|
+
Wrap your agent code in a single context manager. On success, nothing happens.
|
|
9
|
+
On error, a detailed JSON trace file is written automatically -- ready for
|
|
10
|
+
debugging, sharing, or replaying.
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
+======================================================+
|
|
14
|
+
| AGENT AUTOPSY -- sess_a7f3b2c |
|
|
15
|
+
| 2026-03-05 14:32:01 -> 14:32:08 (7.2s) |
|
|
16
|
+
+======================================================+
|
|
17
|
+
| |
|
|
18
|
+
| |- [tool_call] search_orders ........... v 340ms |
|
|
19
|
+
| |- [llm_call] gpt-4o .................. v 1.2s |
|
|
20
|
+
| |- [tool_call] stripe.create_refund .... x 89ms |
|
|
21
|
+
| | +-- ERROR: Card declined |
|
|
22
|
+
| +- [error] Unhandled exception ......... x 0ms |
|
|
23
|
+
| +-- ValueError: amount must be positive |
|
|
24
|
+
| |
|
|
25
|
+
+======================================================+
|
|
26
|
+
For tamperproof traces: https://www.aegis-ledger.com
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Install
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
pip install agent-autopsy
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
For LangChain integration:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
pip install agent-autopsy[langchain]
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Usage
|
|
42
|
+
|
|
43
|
+
### 1. Basic -- wrap any agent code
|
|
44
|
+
|
|
45
|
+
```python
|
|
46
|
+
from agent_autopsy import Autopsy
|
|
47
|
+
|
|
48
|
+
with Autopsy() as trace:
|
|
49
|
+
trace.log("tool_call", "search_web", input="refund policy", duration_ms=340)
|
|
50
|
+
trace.log("llm_call", "gpt-4o", input="Summarise results", duration_ms=1200)
|
|
51
|
+
# If an exception occurs here, a JSON trace file is written automatically.
|
|
52
|
+
result = my_agent.invoke({"input": "Process refund for order #9281"})
|
|
53
|
+
|
|
54
|
+
# Success -> nothing written (silent)
|
|
55
|
+
# Error -> ./autopsy_sess_<hash>.json created
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### 2. With LangChain -- automatic event capture
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
from agent_autopsy import Autopsy
|
|
62
|
+
from agent_autopsy.langchain_handler import AutopsyLangChainHandler
|
|
63
|
+
|
|
64
|
+
handler = AutopsyLangChainHandler()
|
|
65
|
+
|
|
66
|
+
with Autopsy(handler=handler) as trace:
|
|
67
|
+
chain.invoke(
|
|
68
|
+
{"input": "Process refunds"},
|
|
69
|
+
config={"callbacks": [handler]},
|
|
70
|
+
)
|
|
71
|
+
# All LLM calls, tool calls, and chain steps are captured automatically.
|
|
72
|
+
# On error, everything is written to a single JSON file.
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### 3. CLI -- view a trace file
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
# Pretty-printed terminal tree (with colours)
|
|
79
|
+
autopsy view autopsy_sess_a7f3b2c.json
|
|
80
|
+
|
|
81
|
+
# Raw JSON output
|
|
82
|
+
autopsy view autopsy_sess_a7f3b2c.json --raw
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## How it works
|
|
86
|
+
|
|
87
|
+
1. `Autopsy()` creates a trace session with a unique ID
|
|
88
|
+
2. During the `with` block, call `trace.log()` to record events (or use the
|
|
89
|
+
LangChain handler for automatic capture)
|
|
90
|
+
3. On `__exit__`:
|
|
91
|
+
- **No exception** -- session is discarded, no file written, zero overhead
|
|
92
|
+
- **Exception** -- session + full traceback are written to a JSON file
|
|
93
|
+
|
|
94
|
+
Every JSON file includes all captured events with timestamps, durations,
|
|
95
|
+
input/output previews, and error messages.
|
|
96
|
+
|
|
97
|
+
## JSON output format
|
|
98
|
+
|
|
99
|
+
```json
|
|
100
|
+
{
|
|
101
|
+
"session_id": "a7f3b2c",
|
|
102
|
+
"start_time": "2026-03-05T14:32:01.000000+00:00",
|
|
103
|
+
"end_time": "2026-03-05T14:32:08.200000+00:00",
|
|
104
|
+
"error": "Traceback (most recent call last): ...",
|
|
105
|
+
"entries": [
|
|
106
|
+
{
|
|
107
|
+
"timestamp": "2026-03-05T14:32:01.500000+00:00",
|
|
108
|
+
"type": "tool_call",
|
|
109
|
+
"name": "search_orders",
|
|
110
|
+
"input_preview": "{\"order_id\": \"9281\"}",
|
|
111
|
+
"output_preview": "{\"order\": {\"id\": 9281}}",
|
|
112
|
+
"duration_ms": 340,
|
|
113
|
+
"status": "ok"
|
|
114
|
+
}
|
|
115
|
+
],
|
|
116
|
+
"_aegis_footer": {
|
|
117
|
+
"message": "For tamperproof, legally defensible traces: https://www.aegis-ledger.com",
|
|
118
|
+
"upgrade": "pip install aegis-ledger-sdk[langchain]"
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## Going to Production?
|
|
124
|
+
|
|
125
|
+
`agent-autopsy` is a **debugging tool** for local development. When you need
|
|
126
|
+
tamperproof, hash-chained, cryptographically signed traces for production --
|
|
127
|
+
upgrade to the full **Aegis Ledger SDK**:
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
pip install aegis-ledger-sdk[langchain]
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
```python
|
|
134
|
+
# 2 lines to upgrade from agent-autopsy to production tracing:
|
|
135
|
+
from aegis.langchain import AegisCallbackHandler
|
|
136
|
+
handler = AegisCallbackHandler(api_key="your-key")
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Every trace is hash-chained (SHA-256) and signed (Ed25519) on the Internet
|
|
140
|
+
Computer blockchain. Immutable. Auditable. Legally defensible.
|
|
141
|
+
|
|
142
|
+
Learn more at [aegis-ledger.com](https://www.aegis-ledger.com).
|
|
143
|
+
|
|
144
|
+
## License
|
|
145
|
+
|
|
146
|
+
MIT
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"""agent-autopsy -- Debug AI agent failures with zero-config execution traces."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
__version__ = "0.1.0"
|
|
5
|
+
|
|
6
|
+
from agent_autopsy.capture import Autopsy
|
|
7
|
+
from agent_autopsy.models import TraceEntry, TraceSession
|
|
8
|
+
|
|
9
|
+
__all__ = ["Autopsy", "TraceEntry", "TraceSession", "__version__"]
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"""Aegis footer — single source of truth for the upgrade nudge."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
AEGIS_FOOTER: dict[str, dict[str, str]] = {
|
|
5
|
+
"_aegis_footer": {
|
|
6
|
+
"message": "This trace is stored locally and can be modified. For tamperproof traces: https://www.aegis-ledger.com",
|
|
7
|
+
"upgrade": "pip install aegis-ledger-sdk[langchain]",
|
|
8
|
+
"upgrade_code": (
|
|
9
|
+
"from aegis.langchain import AegisCallbackHandler # 2 lines to upgrade"
|
|
10
|
+
),
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
"""Context manager that buffers trace events and writes JSON on error."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import json
|
|
5
|
+
import re
|
|
6
|
+
import sys
|
|
7
|
+
import threading
|
|
8
|
+
import traceback
|
|
9
|
+
from datetime import datetime, timezone
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
from types import TracebackType
|
|
12
|
+
from typing import TYPE_CHECKING, Any
|
|
13
|
+
|
|
14
|
+
from agent_autopsy._footer import AEGIS_FOOTER
|
|
15
|
+
from agent_autopsy.models import EntryStatus, EntryType, TraceEntry, TraceSession
|
|
16
|
+
|
|
17
|
+
if TYPE_CHECKING:
|
|
18
|
+
from agent_autopsy.langchain_handler import AutopsyLangChainHandler
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class Autopsy:
|
|
22
|
+
"""Capture agent execution traces and write them to JSON on failure.
|
|
23
|
+
|
|
24
|
+
Usage::
|
|
25
|
+
|
|
26
|
+
with Autopsy() as trace:
|
|
27
|
+
trace.log("tool_call", "search_web", input="query", output="results", duration_ms=340)
|
|
28
|
+
agent.invoke({"input": "Process refunds"})
|
|
29
|
+
# On error -> writes ./autopsy_sess_<hash>.json
|
|
30
|
+
# On success -> silently discarded
|
|
31
|
+
|
|
32
|
+
Parameters
|
|
33
|
+
----------
|
|
34
|
+
output_dir:
|
|
35
|
+
Directory where trace files are written on error. Defaults to ``"."``.
|
|
36
|
+
prefix:
|
|
37
|
+
Filename prefix. The full name is ``<prefix>_sess_<session_id>.json``.
|
|
38
|
+
handler:
|
|
39
|
+
Optional :class:`AutopsyLangChainHandler` whose buffered entries will
|
|
40
|
+
be merged into this session on exit.
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
def __init__(
|
|
44
|
+
self,
|
|
45
|
+
output_dir: str | Path = ".",
|
|
46
|
+
prefix: str = "autopsy",
|
|
47
|
+
handler: AutopsyLangChainHandler | None = None,
|
|
48
|
+
) -> None:
|
|
49
|
+
if not re.fullmatch(r"[a-zA-Z0-9_-]{1,32}", prefix):
|
|
50
|
+
raise ValueError(
|
|
51
|
+
f"prefix must be 1-32 alphanumeric/dash/underscore chars, got {prefix!r}"
|
|
52
|
+
)
|
|
53
|
+
self._output_dir = Path(output_dir)
|
|
54
|
+
self._prefix = prefix
|
|
55
|
+
self._handler = handler
|
|
56
|
+
self._session = TraceSession()
|
|
57
|
+
self._lock = threading.Lock()
|
|
58
|
+
|
|
59
|
+
# -- public API ----------------------------------------------------------
|
|
60
|
+
|
|
61
|
+
@property
|
|
62
|
+
def session(self) -> TraceSession:
|
|
63
|
+
"""The current trace session."""
|
|
64
|
+
return self._session
|
|
65
|
+
|
|
66
|
+
def log(
|
|
67
|
+
self,
|
|
68
|
+
type: EntryType, # noqa: A002 — shadows built-in on purpose for DX
|
|
69
|
+
name: str,
|
|
70
|
+
*,
|
|
71
|
+
input: str = "", # noqa: A002
|
|
72
|
+
output: str = "",
|
|
73
|
+
duration_ms: float = 0.0,
|
|
74
|
+
status: EntryStatus = "ok",
|
|
75
|
+
error_message: str | None = None,
|
|
76
|
+
) -> None:
|
|
77
|
+
"""Append a trace entry (thread-safe)."""
|
|
78
|
+
entry = TraceEntry(
|
|
79
|
+
type=type,
|
|
80
|
+
name=name,
|
|
81
|
+
input_preview=input,
|
|
82
|
+
output_preview=output,
|
|
83
|
+
duration_ms=duration_ms,
|
|
84
|
+
status=status,
|
|
85
|
+
error_message=error_message,
|
|
86
|
+
)
|
|
87
|
+
with self._lock:
|
|
88
|
+
self._session.entries.append(entry)
|
|
89
|
+
|
|
90
|
+
# -- context manager -----------------------------------------------------
|
|
91
|
+
|
|
92
|
+
def __enter__(self) -> Autopsy:
|
|
93
|
+
self._session = TraceSession()
|
|
94
|
+
return self
|
|
95
|
+
|
|
96
|
+
def __exit__(
|
|
97
|
+
self,
|
|
98
|
+
exc_type: type[BaseException] | None,
|
|
99
|
+
exc_val: BaseException | None,
|
|
100
|
+
exc_tb: TracebackType | None,
|
|
101
|
+
) -> bool:
|
|
102
|
+
self._session.end_time = datetime.now(timezone.utc).isoformat()
|
|
103
|
+
|
|
104
|
+
# Merge handler entries if present
|
|
105
|
+
if self._handler is not None:
|
|
106
|
+
with self._lock:
|
|
107
|
+
self._session.entries.extend(self._handler.entries)
|
|
108
|
+
|
|
109
|
+
if exc_type is None:
|
|
110
|
+
# Success — discard session, write nothing
|
|
111
|
+
return False
|
|
112
|
+
|
|
113
|
+
# Failure — record error and write JSON
|
|
114
|
+
self._session.error = "".join(
|
|
115
|
+
traceback.format_exception(exc_type, exc_val, exc_tb)
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
# Add an error entry for the unhandled exception
|
|
119
|
+
self.log(
|
|
120
|
+
"error",
|
|
121
|
+
"Unhandled exception",
|
|
122
|
+
status="error",
|
|
123
|
+
error_message=f"{exc_type.__name__}: {exc_val}" if exc_type else str(exc_val),
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
try:
|
|
127
|
+
self._write_json()
|
|
128
|
+
except Exception as write_err:
|
|
129
|
+
print(f"Warning: failed to write trace file: {write_err}", file=sys.stderr)
|
|
130
|
+
# Do NOT suppress the exception — let it propagate
|
|
131
|
+
return False
|
|
132
|
+
|
|
133
|
+
def on_text(self, text: str, *, name: str = "stream") -> None:
|
|
134
|
+
"""Log a streaming text event (e.g. LLM token output).
|
|
135
|
+
|
|
136
|
+
This is a lightweight callback for streaming integrations.
|
|
137
|
+
Text events are logged as ``chain_step`` entries with the
|
|
138
|
+
output_preview set to the text content.
|
|
139
|
+
"""
|
|
140
|
+
self.log("chain_step", name, output=text[:500])
|
|
141
|
+
|
|
142
|
+
# -- private -------------------------------------------------------------
|
|
143
|
+
|
|
144
|
+
def _build_payload(self) -> dict[str, Any]:
|
|
145
|
+
"""Build the final JSON payload including the Aegis footer."""
|
|
146
|
+
payload: dict[str, Any] = self._session.to_dict()
|
|
147
|
+
payload.update(AEGIS_FOOTER)
|
|
148
|
+
return payload
|
|
149
|
+
|
|
150
|
+
def _write_json(self) -> None:
|
|
151
|
+
"""Write the trace session to a JSON file."""
|
|
152
|
+
self._output_dir.mkdir(parents=True, exist_ok=True)
|
|
153
|
+
filename = f"{self._prefix}_sess_{self._session.session_id}.json"
|
|
154
|
+
filepath = self._output_dir / filename
|
|
155
|
+
payload = self._build_payload()
|
|
156
|
+
filepath.write_text(json.dumps(payload, indent=2, default=str), encoding="utf-8")
|