agentlens-xray 0.3.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.
Files changed (76) hide show
  1. agentlens_xray-0.3.0/.gitignore +42 -0
  2. agentlens_xray-0.3.0/LICENSE +21 -0
  3. agentlens_xray-0.3.0/PKG-INFO +304 -0
  4. agentlens_xray-0.3.0/README.md +251 -0
  5. agentlens_xray-0.3.0/examples/basic_agent.py +66 -0
  6. agentlens_xray-0.3.0/examples/langchain_agent.py +89 -0
  7. agentlens_xray-0.3.0/examples/raw_openai_client.py +78 -0
  8. agentlens_xray-0.3.0/examples/trip_planner_agent.py +347 -0
  9. agentlens_xray-0.3.0/frontend/.gitignore +24 -0
  10. agentlens_xray-0.3.0/frontend/README.md +73 -0
  11. agentlens_xray-0.3.0/frontend/eslint.config.js +23 -0
  12. agentlens_xray-0.3.0/frontend/index.html +16 -0
  13. agentlens_xray-0.3.0/frontend/package-lock.json +3895 -0
  14. agentlens_xray-0.3.0/frontend/package.json +38 -0
  15. agentlens_xray-0.3.0/frontend/public/favicon.svg +9 -0
  16. agentlens_xray-0.3.0/frontend/src/App.tsx +21 -0
  17. agentlens_xray-0.3.0/frontend/src/api/client.ts +78 -0
  18. agentlens_xray-0.3.0/frontend/src/components/DurationBar.tsx +17 -0
  19. agentlens_xray-0.3.0/frontend/src/components/JsonViewer.tsx +34 -0
  20. agentlens_xray-0.3.0/frontend/src/components/Layout.tsx +27 -0
  21. agentlens_xray-0.3.0/frontend/src/components/Modal.tsx +43 -0
  22. agentlens_xray-0.3.0/frontend/src/components/ReplaySpanDiff.tsx +93 -0
  23. agentlens_xray-0.3.0/frontend/src/components/ReplayView.tsx +163 -0
  24. agentlens_xray-0.3.0/frontend/src/components/SpanDetailPanel.tsx +96 -0
  25. agentlens_xray-0.3.0/frontend/src/components/SpanEditor.tsx +145 -0
  26. agentlens_xray-0.3.0/frontend/src/components/SpanKindIcon.tsx +14 -0
  27. agentlens_xray-0.3.0/frontend/src/components/SpanTimeline.tsx +41 -0
  28. agentlens_xray-0.3.0/frontend/src/components/SpanTimelineItem.tsx +64 -0
  29. agentlens_xray-0.3.0/frontend/src/components/StatusBadge.tsx +18 -0
  30. agentlens_xray-0.3.0/frontend/src/components/TraceDetail.tsx +163 -0
  31. agentlens_xray-0.3.0/frontend/src/components/TraceList.tsx +89 -0
  32. agentlens_xray-0.3.0/frontend/src/components/TraceListRow.tsx +37 -0
  33. agentlens_xray-0.3.0/frontend/src/context/TraceDetailContext.tsx +49 -0
  34. agentlens_xray-0.3.0/frontend/src/hooks/useKeyboardNav.ts +56 -0
  35. agentlens_xray-0.3.0/frontend/src/hooks/useReplay.ts +29 -0
  36. agentlens_xray-0.3.0/frontend/src/hooks/useTrace.ts +29 -0
  37. agentlens_xray-0.3.0/frontend/src/hooks/useTraces.ts +39 -0
  38. agentlens_xray-0.3.0/frontend/src/index.css +26 -0
  39. agentlens_xray-0.3.0/frontend/src/lib/format.ts +37 -0
  40. agentlens_xray-0.3.0/frontend/src/lib/spans.ts +48 -0
  41. agentlens_xray-0.3.0/frontend/src/main.tsx +10 -0
  42. agentlens_xray-0.3.0/frontend/src/types/index.ts +76 -0
  43. agentlens_xray-0.3.0/frontend/tsconfig.app.json +28 -0
  44. agentlens_xray-0.3.0/frontend/tsconfig.json +7 -0
  45. agentlens_xray-0.3.0/frontend/tsconfig.node.json +26 -0
  46. agentlens_xray-0.3.0/frontend/vite.config.ts +24 -0
  47. agentlens_xray-0.3.0/pyproject.toml +89 -0
  48. agentlens_xray-0.3.0/src/agentlens/__init__.py +35 -0
  49. agentlens_xray-0.3.0/src/agentlens/cli.py +69 -0
  50. agentlens_xray-0.3.0/src/agentlens/integrations/__init__.py +34 -0
  51. agentlens_xray-0.3.0/src/agentlens/integrations/_base.py +141 -0
  52. agentlens_xray-0.3.0/src/agentlens/integrations/clients.py +253 -0
  53. agentlens_xray-0.3.0/src/agentlens/integrations/crewai.py +85 -0
  54. agentlens_xray-0.3.0/src/agentlens/integrations/langchain.py +320 -0
  55. agentlens_xray-0.3.0/src/agentlens/integrations/openai_agents.py +177 -0
  56. agentlens_xray-0.3.0/src/agentlens/py.typed +0 -0
  57. agentlens_xray-0.3.0/src/agentlens/replay/__init__.py +0 -0
  58. agentlens_xray-0.3.0/src/agentlens/replay/context.py +84 -0
  59. agentlens_xray-0.3.0/src/agentlens/replay/engine.py +76 -0
  60. agentlens_xray-0.3.0/src/agentlens/replay/live.py +113 -0
  61. agentlens_xray-0.3.0/src/agentlens/replay/span_replay.py +303 -0
  62. agentlens_xray-0.3.0/src/agentlens/sdk/__init__.py +0 -0
  63. agentlens_xray-0.3.0/src/agentlens/sdk/decorators.py +241 -0
  64. agentlens_xray-0.3.0/src/agentlens/sdk/models.py +105 -0
  65. agentlens_xray-0.3.0/src/agentlens/sdk/recorder.py +227 -0
  66. agentlens_xray-0.3.0/src/agentlens/sdk/tracer.py +289 -0
  67. agentlens_xray-0.3.0/src/agentlens/server/__init__.py +0 -0
  68. agentlens_xray-0.3.0/src/agentlens/server/app.py +49 -0
  69. agentlens_xray-0.3.0/src/agentlens/server/db.py +221 -0
  70. agentlens_xray-0.3.0/src/agentlens/server/routes/__init__.py +0 -0
  71. agentlens_xray-0.3.0/src/agentlens/server/routes/replay.py +22 -0
  72. agentlens_xray-0.3.0/src/agentlens/server/routes/traces.py +35 -0
  73. agentlens_xray-0.3.0/src/agentlens/server/static/assets/index-1on5bs8e.js +31 -0
  74. agentlens_xray-0.3.0/src/agentlens/server/static/assets/index-D3nyU__9.css +2 -0
  75. agentlens_xray-0.3.0/src/agentlens/server/static/favicon.svg +9 -0
  76. agentlens_xray-0.3.0/src/agentlens/server/static/index.html +17 -0
@@ -0,0 +1,42 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.egg-info/
6
+ dist/
7
+ build/
8
+ *.egg
9
+
10
+ # Virtual environments
11
+ .venv/
12
+ venv/
13
+
14
+ # IDE
15
+ .vscode/
16
+ .idea/
17
+ *.swp
18
+ *.swo
19
+
20
+ # OS
21
+ .DS_Store
22
+ Thumbs.db
23
+
24
+ # Node
25
+ frontend/node_modules/
26
+ frontend/dist/
27
+
28
+ # Built frontend (served by FastAPI)
29
+ src/agentlens/server/static/
30
+
31
+ # AgentLens data
32
+ .agentlens/
33
+
34
+ # Test
35
+ .pytest_cache/
36
+ .mypy_cache/
37
+ htmlcov/
38
+ .coverage
39
+
40
+ # Claude Code
41
+ .claude/
42
+ CLAUDE.md
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Saswat Ray
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,304 @@
1
+ Metadata-Version: 2.4
2
+ Name: agentlens-xray
3
+ Version: 0.3.0
4
+ Summary: Local-first AI agent debugger with fork & replay
5
+ Project-URL: Homepage, https://github.com/BugsBunnyWanders/agentlens
6
+ Project-URL: Repository, https://github.com/BugsBunnyWanders/agentlens
7
+ Project-URL: Issues, https://github.com/BugsBunnyWanders/agentlens/issues
8
+ Author-email: Saswat Ray <saswatray2505@gmail.com>
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: agents,ai,debugging,llm,observability,replay,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
+ Classifier: Topic :: Software Development :: Testing
22
+ Classifier: Typing :: Typed
23
+ Requires-Python: >=3.10
24
+ Requires-Dist: aiosqlite>=0.19
25
+ Requires-Dist: click>=8.0
26
+ Requires-Dist: fastapi>=0.104
27
+ Requires-Dist: pydantic>=2.0
28
+ Requires-Dist: uvicorn[standard]>=0.24
29
+ Provides-Extra: all-integrations
30
+ Requires-Dist: anthropic>=0.20.0; extra == 'all-integrations'
31
+ Requires-Dist: langchain-core>=0.1.0; extra == 'all-integrations'
32
+ Requires-Dist: openai>=1.0.0; extra == 'all-integrations'
33
+ Provides-Extra: anthropic
34
+ Requires-Dist: anthropic>=0.20.0; extra == 'anthropic'
35
+ Provides-Extra: crewai
36
+ Requires-Dist: crewai>=0.30.0; extra == 'crewai'
37
+ Requires-Dist: langchain-core>=0.1.0; extra == 'crewai'
38
+ Provides-Extra: dev
39
+ Requires-Dist: build; extra == 'dev'
40
+ Requires-Dist: httpx; extra == 'dev'
41
+ Requires-Dist: mypy; extra == 'dev'
42
+ Requires-Dist: pytest; extra == 'dev'
43
+ Requires-Dist: pytest-asyncio; extra == 'dev'
44
+ Requires-Dist: ruff; extra == 'dev'
45
+ Requires-Dist: twine; extra == 'dev'
46
+ Provides-Extra: langchain
47
+ Requires-Dist: langchain-core>=0.1.0; extra == 'langchain'
48
+ Provides-Extra: openai
49
+ Requires-Dist: openai>=1.0.0; extra == 'openai'
50
+ Provides-Extra: openai-agents
51
+ Requires-Dist: openai-agents>=0.1.0; extra == 'openai-agents'
52
+ Description-Content-Type: text/markdown
53
+
54
+ # AgentLens
55
+
56
+ **Local-first AI agent debugger with fork & replay.**
57
+
58
+ AgentLens captures execution traces from multi-step AI agent workflows, visualizes them in a local web UI, and lets you fork a trace at any step, edit its output, and **re-execute downstream steps with real API calls** to see what would have happened differently.
59
+
60
+ Think of it as **Chrome DevTools for AI agents** — the Network tab + time-travel debugging, but for LLM agent workflows.
61
+
62
+ > **Install:** `pip install agentlens-xray` — the import name is `agentlens`.
63
+
64
+ ## The Problem
65
+
66
+ AI agents are non-deterministic. When a multi-step agent fails at step 7 of 12, developers currently have no way to:
67
+
68
+ 1. See exactly what happened at each step (tool calls, LLM reasoning, intermediate state)
69
+ 2. Reproduce the failure deterministically
70
+ 3. Test a fix by replaying from the failure point without re-running the entire chain
71
+
72
+ ## Quick Start
73
+
74
+ ```bash
75
+ pip install agentlens-xray
76
+ python examples/basic_agent.py # creates a sample trace (no API keys needed)
77
+ agentlens serve # opens the UI at localhost:7600
78
+ ```
79
+
80
+ For a real agent with OpenAI:
81
+
82
+ ```bash
83
+ export OPENAI_API_KEY="sk-..."
84
+ python examples/trip_planner_agent.py
85
+ agentlens serve
86
+ ```
87
+
88
+ ## Usage
89
+
90
+ ### 1. Instrument Your Code
91
+
92
+ Add decorators to your existing agent functions — zero logic changes:
93
+
94
+ ```python
95
+ import agentlens
96
+
97
+ @agentlens.trace(name="my_agent")
98
+ async def my_agent(query: str):
99
+ data = await fetch_data(query)
100
+ result = await analyze(data)
101
+ return result
102
+
103
+ @agentlens.wrap_tool(name="fetch_data")
104
+ async def fetch_data(query: str) -> dict:
105
+ return await api.search(query)
106
+
107
+ @agentlens.wrap_llm(name="analyze", model="gpt-4o-mini")
108
+ async def analyze(data: dict) -> str:
109
+ response = await openai.chat.completions.create(...)
110
+ return response.choices[0].message.content
111
+ ```
112
+
113
+ There's also a context manager API:
114
+
115
+ ```python
116
+ async with agentlens.start_trace_async("my_agent") as t:
117
+ with t.span("fetch_data", kind="tool") as s:
118
+ data = await fetch(...)
119
+ s.record_output(data)
120
+ with t.span("analyze", kind="llm", model="gpt-4o") as s:
121
+ s.record_input({"messages": [...]})
122
+ result = await llm.complete(...)
123
+ s.record_output(result)
124
+ ```
125
+
126
+ ### 2. View Traces
127
+
128
+ ```bash
129
+ agentlens serve # Web UI at localhost:7600
130
+ agentlens serve --port 8080 # Custom port
131
+ agentlens traces # List recent traces in terminal
132
+ agentlens traces --last 5 # Show last 5
133
+ ```
134
+
135
+ ### 3. Fork & Replay
136
+
137
+ In the web UI:
138
+
139
+ 1. Click a trace to see its span timeline
140
+ 2. Select a span and click **Fork & Replay**
141
+ 3. Edit the span's output in the code editor
142
+ 4. Choose a **replay mode**
143
+ 5. Click **Replay from here** to create a forked trace
144
+ 6. View the side-by-side comparison with diff highlighting
145
+
146
+ ### Replay Modes
147
+
148
+ | Mode | What happens | Cost | Use case |
149
+ |------|-------------|------|----------|
150
+ | **Deterministic** | Only the edited span changes. Downstream spans are marked stale. | Free | Quick data annotation, bookmarking bugs |
151
+ | **Live** | All downstream spans re-execute with real API calls. | Token costs | "What would the LLM say if the tool returned different data?" |
152
+ | **Hybrid** | LLM spans re-execute live, tool spans return recorded data. | Lower token costs | Test LLM behavior with changed context, no tool side effects |
153
+
154
+ **Example:** Your weather tool returned "sunny" but the real weather is a blizzard. Fork the weather span, change it to blizzard, select **Live** mode. The LLM re-generates the itinerary accounting for severe weather — with real API calls, producing genuinely different output.
155
+
156
+ ## Framework Integrations
157
+
158
+ AgentLens works with popular frameworks out of the box — no decorators needed.
159
+
160
+ ### OpenAI / Anthropic SDK (wrap your client)
161
+
162
+ ```bash
163
+ pip install agentlens-xray[openai] # or agentlens-xray[anthropic]
164
+ ```
165
+
166
+ ```python
167
+ from openai import OpenAI
168
+ from agentlens import wrap_openai
169
+
170
+ client = wrap_openai(OpenAI())
171
+ # All chat.completions.create() calls are now traced automatically
172
+ response = client.chat.completions.create(model="gpt-4o", messages=[...])
173
+ ```
174
+
175
+ ### LangChain / LangGraph
176
+
177
+ ```bash
178
+ pip install agentlens-xray[langchain]
179
+ ```
180
+
181
+ ```python
182
+ from agentlens.integrations.langchain import AgentLensCallbackHandler
183
+
184
+ with AgentLensCallbackHandler(trace_name="my_agent") as handler:
185
+ chain.invoke(input, config={"callbacks": [handler]})
186
+ # Full trace with LLM, tool, retrieval, and chain spans
187
+ ```
188
+
189
+ ### OpenAI Agents SDK
190
+
191
+ ```bash
192
+ pip install agentlens-xray[openai-agents]
193
+ ```
194
+
195
+ ```python
196
+ from agentlens.integrations.openai_agents import install_agentlens_tracing
197
+
198
+ install_agentlens_tracing() # One line — all agent runs traced automatically
199
+ result = await Runner.run(agent, input="Process this refund")
200
+ ```
201
+
202
+ ### CrewAI
203
+
204
+ ```bash
205
+ pip install agentlens-xray[crewai]
206
+ ```
207
+
208
+ ```python
209
+ from agentlens.integrations.crewai import CrewAIHandler
210
+
211
+ handler = CrewAIHandler(trace_name="my_crew")
212
+ crew = Crew(agents=[...], tasks=[...], callbacks=[handler])
213
+ crew.kickoff() # Crew, agent, and task spans captured
214
+ ```
215
+
216
+ ## Features
217
+
218
+ - **Zero-config tracing** — `pip install agentlens-xray` and add decorators or use framework integrations
219
+ - **Framework integrations** — LangChain, LangGraph, OpenAI Agents SDK, CrewAI, raw SDKs
220
+ - **Live replay** — re-execute downstream spans with real API calls after editing a span's output
221
+ - **Hybrid replay** — LLM calls go live, tool calls use recorded data (no side effects)
222
+ - **Async-first** — non-blocking trace capture, works in both sync and async code
223
+ - **Local-first** — no cloud accounts, no telemetry, everything stays on your machine
224
+ - **Keyboard navigable** — arrow keys / j/k to browse spans, `e` to edit
225
+
226
+ ## Architecture
227
+
228
+ ```
229
+ Your Agent Code
230
+ --> @trace, @wrap_tool, @wrap_llm decorators capture spans
231
+ --> Async queue --> SQLite (~/.agentlens/traces.db)
232
+ --> FastAPI serves JSON API + bundled React frontend
233
+ --> localhost:7600
234
+
235
+ Fork & Replay (Live mode):
236
+ --> Load original trace, apply mutations
237
+ --> Re-import user's function, set ReplayContext
238
+ --> Decorators intercept each span:
239
+ Before mutation: execute normally
240
+ At mutation: return edited output
241
+ After mutation: execute live (real API calls)
242
+ --> Save new trace for side-by-side comparison
243
+ ```
244
+
245
+ ## Web UI Pages
246
+
247
+ - **Trace List** — all captured traces with status, duration, token count, cost
248
+ - **Trace Detail** — span timeline (left) + selected span I/O (right), keyboard navigable
249
+ - **Replay Comparison** — side-by-side original vs forked trace, with RE-EXECUTED / EDITED / STALE badges
250
+
251
+ ## Configuration
252
+
253
+ | Variable | Default | Description |
254
+ |----------|---------|-------------|
255
+ | `AGENTLENS_DB_PATH` | `~/.agentlens/traces.db` | SQLite database path |
256
+ | `AGENTLENS_PORT` | `7600` | Default server port |
257
+ | `AGENTLENS_ENABLED` | `true` | Set `false` to disable tracing (decorators become no-ops) |
258
+
259
+ ## Development
260
+
261
+ ```bash
262
+ # Install with dev dependencies
263
+ pip install -e ".[dev]"
264
+
265
+ # Frontend development (hot reload)
266
+ cd frontend && npm install && npm run dev
267
+
268
+ # Build frontend for production
269
+ cd frontend && npm run build
270
+
271
+ # Run tests
272
+ pytest
273
+
274
+ # Type checking
275
+ mypy src/agentlens
276
+ cd frontend && npx tsc --noEmit
277
+ ```
278
+
279
+ ## Project Structure
280
+
281
+ ```
282
+ src/agentlens/
283
+ sdk/ # Tracing SDK (decorators, context management, SQLite writer)
284
+ server/ # FastAPI API + static file serving
285
+ replay/
286
+ engine.py # Replay dispatcher (deterministic vs live)
287
+ live.py # Live replay engine (re-executes user functions)
288
+ context.py # ReplayContext (decorators check this at runtime)
289
+ cli.py # CLI entry point
290
+
291
+ frontend/ # React + TypeScript + Tailwind UI (Vite)
292
+ examples/ # Working examples (basic + OpenAI trip planner)
293
+ ```
294
+
295
+ ## Tech Stack
296
+
297
+ - **SDK**: Python 3.10+, Pydantic v2, aiosqlite, contextvars
298
+ - **Server**: FastAPI, Uvicorn
299
+ - **Frontend**: React 18, TypeScript, Tailwind CSS, CodeMirror, Vite
300
+ - **Storage**: SQLite (WAL mode, zero-config)
301
+
302
+ ## License
303
+
304
+ MIT
@@ -0,0 +1,251 @@
1
+ # AgentLens
2
+
3
+ **Local-first AI agent debugger with fork & replay.**
4
+
5
+ AgentLens captures execution traces from multi-step AI agent workflows, visualizes them in a local web UI, and lets you fork a trace at any step, edit its output, and **re-execute downstream steps with real API calls** to see what would have happened differently.
6
+
7
+ Think of it as **Chrome DevTools for AI agents** — the Network tab + time-travel debugging, but for LLM agent workflows.
8
+
9
+ > **Install:** `pip install agentlens-xray` — the import name is `agentlens`.
10
+
11
+ ## The Problem
12
+
13
+ AI agents are non-deterministic. When a multi-step agent fails at step 7 of 12, developers currently have no way to:
14
+
15
+ 1. See exactly what happened at each step (tool calls, LLM reasoning, intermediate state)
16
+ 2. Reproduce the failure deterministically
17
+ 3. Test a fix by replaying from the failure point without re-running the entire chain
18
+
19
+ ## Quick Start
20
+
21
+ ```bash
22
+ pip install agentlens-xray
23
+ python examples/basic_agent.py # creates a sample trace (no API keys needed)
24
+ agentlens serve # opens the UI at localhost:7600
25
+ ```
26
+
27
+ For a real agent with OpenAI:
28
+
29
+ ```bash
30
+ export OPENAI_API_KEY="sk-..."
31
+ python examples/trip_planner_agent.py
32
+ agentlens serve
33
+ ```
34
+
35
+ ## Usage
36
+
37
+ ### 1. Instrument Your Code
38
+
39
+ Add decorators to your existing agent functions — zero logic changes:
40
+
41
+ ```python
42
+ import agentlens
43
+
44
+ @agentlens.trace(name="my_agent")
45
+ async def my_agent(query: str):
46
+ data = await fetch_data(query)
47
+ result = await analyze(data)
48
+ return result
49
+
50
+ @agentlens.wrap_tool(name="fetch_data")
51
+ async def fetch_data(query: str) -> dict:
52
+ return await api.search(query)
53
+
54
+ @agentlens.wrap_llm(name="analyze", model="gpt-4o-mini")
55
+ async def analyze(data: dict) -> str:
56
+ response = await openai.chat.completions.create(...)
57
+ return response.choices[0].message.content
58
+ ```
59
+
60
+ There's also a context manager API:
61
+
62
+ ```python
63
+ async with agentlens.start_trace_async("my_agent") as t:
64
+ with t.span("fetch_data", kind="tool") as s:
65
+ data = await fetch(...)
66
+ s.record_output(data)
67
+ with t.span("analyze", kind="llm", model="gpt-4o") as s:
68
+ s.record_input({"messages": [...]})
69
+ result = await llm.complete(...)
70
+ s.record_output(result)
71
+ ```
72
+
73
+ ### 2. View Traces
74
+
75
+ ```bash
76
+ agentlens serve # Web UI at localhost:7600
77
+ agentlens serve --port 8080 # Custom port
78
+ agentlens traces # List recent traces in terminal
79
+ agentlens traces --last 5 # Show last 5
80
+ ```
81
+
82
+ ### 3. Fork & Replay
83
+
84
+ In the web UI:
85
+
86
+ 1. Click a trace to see its span timeline
87
+ 2. Select a span and click **Fork & Replay**
88
+ 3. Edit the span's output in the code editor
89
+ 4. Choose a **replay mode**
90
+ 5. Click **Replay from here** to create a forked trace
91
+ 6. View the side-by-side comparison with diff highlighting
92
+
93
+ ### Replay Modes
94
+
95
+ | Mode | What happens | Cost | Use case |
96
+ |------|-------------|------|----------|
97
+ | **Deterministic** | Only the edited span changes. Downstream spans are marked stale. | Free | Quick data annotation, bookmarking bugs |
98
+ | **Live** | All downstream spans re-execute with real API calls. | Token costs | "What would the LLM say if the tool returned different data?" |
99
+ | **Hybrid** | LLM spans re-execute live, tool spans return recorded data. | Lower token costs | Test LLM behavior with changed context, no tool side effects |
100
+
101
+ **Example:** Your weather tool returned "sunny" but the real weather is a blizzard. Fork the weather span, change it to blizzard, select **Live** mode. The LLM re-generates the itinerary accounting for severe weather — with real API calls, producing genuinely different output.
102
+
103
+ ## Framework Integrations
104
+
105
+ AgentLens works with popular frameworks out of the box — no decorators needed.
106
+
107
+ ### OpenAI / Anthropic SDK (wrap your client)
108
+
109
+ ```bash
110
+ pip install agentlens-xray[openai] # or agentlens-xray[anthropic]
111
+ ```
112
+
113
+ ```python
114
+ from openai import OpenAI
115
+ from agentlens import wrap_openai
116
+
117
+ client = wrap_openai(OpenAI())
118
+ # All chat.completions.create() calls are now traced automatically
119
+ response = client.chat.completions.create(model="gpt-4o", messages=[...])
120
+ ```
121
+
122
+ ### LangChain / LangGraph
123
+
124
+ ```bash
125
+ pip install agentlens-xray[langchain]
126
+ ```
127
+
128
+ ```python
129
+ from agentlens.integrations.langchain import AgentLensCallbackHandler
130
+
131
+ with AgentLensCallbackHandler(trace_name="my_agent") as handler:
132
+ chain.invoke(input, config={"callbacks": [handler]})
133
+ # Full trace with LLM, tool, retrieval, and chain spans
134
+ ```
135
+
136
+ ### OpenAI Agents SDK
137
+
138
+ ```bash
139
+ pip install agentlens-xray[openai-agents]
140
+ ```
141
+
142
+ ```python
143
+ from agentlens.integrations.openai_agents import install_agentlens_tracing
144
+
145
+ install_agentlens_tracing() # One line — all agent runs traced automatically
146
+ result = await Runner.run(agent, input="Process this refund")
147
+ ```
148
+
149
+ ### CrewAI
150
+
151
+ ```bash
152
+ pip install agentlens-xray[crewai]
153
+ ```
154
+
155
+ ```python
156
+ from agentlens.integrations.crewai import CrewAIHandler
157
+
158
+ handler = CrewAIHandler(trace_name="my_crew")
159
+ crew = Crew(agents=[...], tasks=[...], callbacks=[handler])
160
+ crew.kickoff() # Crew, agent, and task spans captured
161
+ ```
162
+
163
+ ## Features
164
+
165
+ - **Zero-config tracing** — `pip install agentlens-xray` and add decorators or use framework integrations
166
+ - **Framework integrations** — LangChain, LangGraph, OpenAI Agents SDK, CrewAI, raw SDKs
167
+ - **Live replay** — re-execute downstream spans with real API calls after editing a span's output
168
+ - **Hybrid replay** — LLM calls go live, tool calls use recorded data (no side effects)
169
+ - **Async-first** — non-blocking trace capture, works in both sync and async code
170
+ - **Local-first** — no cloud accounts, no telemetry, everything stays on your machine
171
+ - **Keyboard navigable** — arrow keys / j/k to browse spans, `e` to edit
172
+
173
+ ## Architecture
174
+
175
+ ```
176
+ Your Agent Code
177
+ --> @trace, @wrap_tool, @wrap_llm decorators capture spans
178
+ --> Async queue --> SQLite (~/.agentlens/traces.db)
179
+ --> FastAPI serves JSON API + bundled React frontend
180
+ --> localhost:7600
181
+
182
+ Fork & Replay (Live mode):
183
+ --> Load original trace, apply mutations
184
+ --> Re-import user's function, set ReplayContext
185
+ --> Decorators intercept each span:
186
+ Before mutation: execute normally
187
+ At mutation: return edited output
188
+ After mutation: execute live (real API calls)
189
+ --> Save new trace for side-by-side comparison
190
+ ```
191
+
192
+ ## Web UI Pages
193
+
194
+ - **Trace List** — all captured traces with status, duration, token count, cost
195
+ - **Trace Detail** — span timeline (left) + selected span I/O (right), keyboard navigable
196
+ - **Replay Comparison** — side-by-side original vs forked trace, with RE-EXECUTED / EDITED / STALE badges
197
+
198
+ ## Configuration
199
+
200
+ | Variable | Default | Description |
201
+ |----------|---------|-------------|
202
+ | `AGENTLENS_DB_PATH` | `~/.agentlens/traces.db` | SQLite database path |
203
+ | `AGENTLENS_PORT` | `7600` | Default server port |
204
+ | `AGENTLENS_ENABLED` | `true` | Set `false` to disable tracing (decorators become no-ops) |
205
+
206
+ ## Development
207
+
208
+ ```bash
209
+ # Install with dev dependencies
210
+ pip install -e ".[dev]"
211
+
212
+ # Frontend development (hot reload)
213
+ cd frontend && npm install && npm run dev
214
+
215
+ # Build frontend for production
216
+ cd frontend && npm run build
217
+
218
+ # Run tests
219
+ pytest
220
+
221
+ # Type checking
222
+ mypy src/agentlens
223
+ cd frontend && npx tsc --noEmit
224
+ ```
225
+
226
+ ## Project Structure
227
+
228
+ ```
229
+ src/agentlens/
230
+ sdk/ # Tracing SDK (decorators, context management, SQLite writer)
231
+ server/ # FastAPI API + static file serving
232
+ replay/
233
+ engine.py # Replay dispatcher (deterministic vs live)
234
+ live.py # Live replay engine (re-executes user functions)
235
+ context.py # ReplayContext (decorators check this at runtime)
236
+ cli.py # CLI entry point
237
+
238
+ frontend/ # React + TypeScript + Tailwind UI (Vite)
239
+ examples/ # Working examples (basic + OpenAI trip planner)
240
+ ```
241
+
242
+ ## Tech Stack
243
+
244
+ - **SDK**: Python 3.10+, Pydantic v2, aiosqlite, contextvars
245
+ - **Server**: FastAPI, Uvicorn
246
+ - **Frontend**: React 18, TypeScript, Tailwind CSS, CodeMirror, Vite
247
+ - **Storage**: SQLite (WAL mode, zero-config)
248
+
249
+ ## License
250
+
251
+ MIT
@@ -0,0 +1,66 @@
1
+ """Basic agent example — demonstrates AgentLens tracing with simulated tool/LLM calls.
2
+
3
+ No API keys required. Run this, then `agentlens serve` to view the trace.
4
+ """
5
+
6
+ import asyncio
7
+
8
+ import agentlens
9
+
10
+
11
+ @agentlens.trace(name="weather_agent")
12
+ async def weather_agent(city: str) -> str:
13
+ weather = await get_weather(city)
14
+ forecast = await get_forecast(city)
15
+ recommendation = await get_recommendation(weather, forecast)
16
+ return recommendation
17
+
18
+
19
+ @agentlens.wrap_tool(name="get_weather")
20
+ async def get_weather(city: str) -> dict:
21
+ """Simulated weather API call."""
22
+ await asyncio.sleep(0.1)
23
+ return {"city": city, "temp_f": 72, "condition": "sunny", "humidity": 45}
24
+
25
+
26
+ @agentlens.wrap_tool(name="get_forecast")
27
+ async def get_forecast(city: str) -> dict:
28
+ """Simulated forecast API call."""
29
+ await asyncio.sleep(0.15)
30
+ return {
31
+ "city": city,
32
+ "next_3_days": [
33
+ {"day": "Tomorrow", "high": 75, "low": 60, "condition": "partly cloudy"},
34
+ {"day": "Day 2", "high": 78, "low": 62, "condition": "sunny"},
35
+ {"day": "Day 3", "high": 70, "low": 55, "condition": "rainy"},
36
+ ],
37
+ }
38
+
39
+
40
+ @agentlens.wrap_llm(name="get_recommendation", model="simulated-llm")
41
+ async def get_recommendation(weather: dict, forecast: dict) -> str:
42
+ """Simulated LLM call that generates a recommendation."""
43
+ await asyncio.sleep(0.2)
44
+ city = weather["city"]
45
+ temp = weather["temp_f"]
46
+ condition = weather["condition"]
47
+ return (
48
+ f"It's currently {condition} and {temp}F in {city}. "
49
+ f"Great day for outdoor activities! "
50
+ f"Note: rain expected in {forecast['next_3_days'][2]['day'].lower()}, "
51
+ f"so plan accordingly."
52
+ )
53
+
54
+
55
+ async def main():
56
+ print("Running weather agent...")
57
+ result = await weather_agent("San Francisco")
58
+ print(f"\nAgent result: {result}")
59
+ print("\nTrace saved! Run 'agentlens serve' to view it in the UI.")
60
+
61
+ # Give the recorder time to flush
62
+ await asyncio.sleep(0.5)
63
+
64
+
65
+ if __name__ == "__main__":
66
+ asyncio.run(main())