agentic-ledger 0.2.0__tar.gz → 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.
- {agentic_ledger-0.2.0 → agentic_ledger-0.3.0}/.gitignore +4 -0
- {agentic_ledger-0.2.0 → agentic_ledger-0.3.0}/PKG-INFO +150 -23
- {agentic_ledger-0.2.0 → agentic_ledger-0.3.0}/README.md +145 -18
- {agentic_ledger-0.2.0 → agentic_ledger-0.3.0}/agentledger/__init__.py +1 -1
- agentic_ledger-0.3.0/agentledger/cli.py +177 -0
- {agentic_ledger-0.2.0 → agentic_ledger-0.3.0}/agentledger/proxy/__main__.py +6 -1
- {agentic_ledger-0.2.0 → agentic_ledger-0.3.0}/agentledger/proxy/alerts.py +1 -1
- {agentic_ledger-0.2.0 → agentic_ledger-0.3.0}/agentledger/proxy/app.py +405 -41
- {agentic_ledger-0.2.0 → agentic_ledger-0.3.0}/agentledger/proxy/dashboard.py +12 -5
- agentic_ledger-0.3.0/agentledger/proxy/detect.py +123 -0
- {agentic_ledger-0.2.0 → agentic_ledger-0.3.0}/agentledger/proxy/export.py +4 -4
- agentic_ledger-0.3.0/agentledger/proxy/loops.py +402 -0
- {agentic_ledger-0.2.0 → agentic_ledger-0.3.0}/agentledger/proxy/mcp.py +65 -1
- {agentic_ledger-0.2.0 → agentic_ledger-0.3.0}/agentledger/proxy/normalize.py +61 -7
- {agentic_ledger-0.2.0 → agentic_ledger-0.3.0}/agentledger/proxy/otel.py +2 -2
- agentic_ledger-0.3.0/agentledger/proxy/otlp_ingest.py +223 -0
- agentic_ledger-0.3.0/agentledger/proxy/pricing.py +192 -0
- {agentic_ledger-0.2.0 → agentic_ledger-0.3.0}/agentledger/proxy/redact.py +4 -1
- agentic_ledger-0.3.0/agentledger/proxy/static/assets/index-DxRfHpqq.js +44 -0
- agentic_ledger-0.3.0/agentledger/proxy/static/assets/index-smCzfG8T.css +1 -0
- agentic_ledger-0.3.0/agentledger/proxy/static/index.html +14 -0
- {agentic_ledger-0.2.0 → agentic_ledger-0.3.0}/agentledger/proxy/store.py +376 -7
- agentic_ledger-0.3.0/agentledger/proxy/stream.py +254 -0
- {agentic_ledger-0.2.0 → agentic_ledger-0.3.0}/pyproject.toml +21 -5
- agentic_ledger-0.2.0/agentledger/proxy/pricing.py +0 -117
- agentic_ledger-0.2.0/agentledger/proxy/stream.py +0 -157
- {agentic_ledger-0.2.0 → agentic_ledger-0.3.0}/LICENSE +0 -0
- {agentic_ledger-0.2.0 → agentic_ledger-0.3.0}/agentledger/proxy/__init__.py +0 -0
- {agentic_ledger-0.2.0 → agentic_ledger-0.3.0}/agentledger/proxy/auth.py +0 -0
- {agentic_ledger-0.2.0 → agentic_ledger-0.3.0}/agentledger/proxy/mascot.jpg +0 -0
- {agentic_ledger-0.2.0 → agentic_ledger-0.3.0}/agentledger/proxy/ratelimit.py +0 -0
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agentic-ledger
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: Runtime observability for AI agents — see exactly what your agent did, why it did it, and what it cost.
|
|
5
|
-
Project-URL: Homepage, https://
|
|
6
|
-
Project-URL: Repository, https://github.com/ShekharBhardwaj/
|
|
7
|
-
Project-URL: Issues, https://github.com/ShekharBhardwaj/
|
|
5
|
+
Project-URL: Homepage, https://agentic-ledger.dev
|
|
6
|
+
Project-URL: Repository, https://github.com/ShekharBhardwaj/AgenticLedger
|
|
7
|
+
Project-URL: Issues, https://github.com/ShekharBhardwaj/AgenticLedger/issues
|
|
8
8
|
Author: Shekhar Bhardwaj
|
|
9
9
|
License-Expression: MIT
|
|
10
10
|
License-File: LICENSE
|
|
@@ -21,7 +21,7 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
|
21
21
|
Requires-Python: >=3.10
|
|
22
22
|
Requires-Dist: aiosqlite>=0.19
|
|
23
23
|
Requires-Dist: fastapi>=0.110
|
|
24
|
-
Requires-Dist: httpx
|
|
24
|
+
Requires-Dist: httpx<1.0.dev0,>=0.27
|
|
25
25
|
Requires-Dist: uvicorn[standard]>=0.29
|
|
26
26
|
Provides-Extra: dev
|
|
27
27
|
Requires-Dist: aiosqlite>=0.19; extra == 'dev'
|
|
@@ -40,10 +40,10 @@ Provides-Extra: postgres
|
|
|
40
40
|
Requires-Dist: asyncpg>=0.29; extra == 'postgres'
|
|
41
41
|
Description-Content-Type: text/markdown
|
|
42
42
|
|
|
43
|
-
#
|
|
43
|
+
# Agentic Ledger
|
|
44
44
|
|
|
45
|
-
[](https://github.com/ShekharBhardwaj/AgenticLedger/actions/workflows/ci.yml)
|
|
46
|
+
[](https://github.com/ShekharBhardwaj/AgenticLedger/actions/workflows/codeql.yml)
|
|
47
47
|
[](https://pypi.org/project/agentic-ledger/)
|
|
48
48
|
[](https://pypi.org/project/agentic-ledger/)
|
|
49
49
|
[](https://ghcr.io/shekharbhardwaj/agentledger)
|
|
@@ -51,16 +51,20 @@ Description-Content-Type: text/markdown
|
|
|
51
51
|
|
|
52
52
|
Runtime observability for AI agents — see exactly what your agent did, why it did it, and what it cost.
|
|
53
53
|
|
|
54
|
+
**Website:** [agentic-ledger.dev](https://agentic-ledger.dev)
|
|
55
|
+
|
|
56
|
+
> The numbers are meant to match your provider bill. If they don't, [that's a bug we want](https://github.com/ShekharBhardwaj/AgenticLedger/issues/new/choose).
|
|
57
|
+
|
|
54
58
|
Works with **any agent framework**, **any LLM provider**, **any model gateway**. Zero code changes required. Point your agent at the proxy and everything is captured automatically.
|
|
55
59
|
|
|
56
60
|
---
|
|
57
61
|
|
|
58
62
|
## How it works
|
|
59
63
|
|
|
60
|
-
|
|
64
|
+
Agentic Ledger runs as a transparent proxy between your agent and the LLM provider. It intercepts every request and response, assigns it an `action_id`, stores it, and returns the upstream response unmodified. Your agent never knows the proxy is there.
|
|
61
65
|
|
|
62
66
|
```
|
|
63
|
-
Your Agent →
|
|
67
|
+
Your Agent → Agentic Ledger Proxy → OpenAI / Anthropic / LiteLLM / any LLM
|
|
64
68
|
↓
|
|
65
69
|
SQLite or Postgres
|
|
66
70
|
↓
|
|
@@ -149,10 +153,10 @@ client = anthropic.Anthropic(
|
|
|
149
153
|
|
|
150
154
|
**LiteLLM / OpenRouter / any gateway:**
|
|
151
155
|
```bash
|
|
152
|
-
# Point
|
|
156
|
+
# Point Agentic Ledger at your gateway
|
|
153
157
|
AGENTLEDGER_UPSTREAM_URL=http://localhost:4000 uv run python -m agentledger.proxy
|
|
154
158
|
|
|
155
|
-
# Then point your agent at
|
|
159
|
+
# Then point your agent at Agentic Ledger
|
|
156
160
|
client = OpenAI(base_url="http://localhost:8000/v1", ...)
|
|
157
161
|
```
|
|
158
162
|
|
|
@@ -164,7 +168,13 @@ client = OpenAI(base_url="http://localhost:8000/v1", ...)
|
|
|
164
168
|
http://localhost:8000
|
|
165
169
|
```
|
|
166
170
|
|
|
167
|
-
The
|
|
171
|
+
The web app updates live via WebSocket as calls come in. No refresh needed.
|
|
172
|
+
|
|
173
|
+
- **Loop Lens** — every loop run with status (`running` / `flagged` / `complete`), a cost-per-iteration chart, per-iteration breakdowns, and plain-English explanations of every flag
|
|
174
|
+
- **Sessions** — every session with three views: expandable call cards (response, thinking, tool calls, cache tokens, interaction badges), a **Flow** DAG of agent handoffs, and a **Trace** waterfall with real parent links from the loop engine
|
|
175
|
+
- **Search** — full-text across prompts, outputs, and agents
|
|
176
|
+
|
|
177
|
+
The classic single-file dashboard remains at `http://localhost:8000/classic`:
|
|
168
178
|
|
|
169
179
|
- **Calls tab** — every LLM call with full prompt, system prompt, tool calls, tool results, output, tokens, cost, latency, and errors
|
|
170
180
|
- **Flow tab** — visual DAG of your multi-agent system. Each agent is a node with aggregated cost, latency, and call count. Edges represent handoffs. Click a node to highlight its calls.
|
|
@@ -173,6 +183,70 @@ The dashboard updates live via WebSocket as calls come in. No refresh needed.
|
|
|
173
183
|
|
|
174
184
|
---
|
|
175
185
|
|
|
186
|
+
## Coding agents — Claude Code, Ralph loops & friends
|
|
187
|
+
|
|
188
|
+
Claude Code (and most coding agents) can be pointed at the proxy with a single
|
|
189
|
+
environment variable — no headers, no code changes:
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
AGENTLEDGER_UPSTREAM_URL=https://api.anthropic.com uv run python -m agentledger.proxy
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
```bash
|
|
196
|
+
export ANTHROPIC_BASE_URL=http://localhost:8000
|
|
197
|
+
claude
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
Agentic Ledger fingerprints Claude Code traffic automatically: every call is
|
|
201
|
+
tagged `framework=claude-code`, and instead of one undifferentiated bucket,
|
|
202
|
+
each Claude Code session appears under its **real session UUID** (the same id
|
|
203
|
+
`claude --resume` shows), with prompt-cache reads/writes captured and priced
|
|
204
|
+
correctly — cache traffic is where most of a coding agent's real spend lives.
|
|
205
|
+
|
|
206
|
+
Running an overnight loop (Ralph-style `while :; do cat PROMPT.md | claude -p; done`)?
|
|
207
|
+
Use the built-in loop runner — it re-executes your command each iteration,
|
|
208
|
+
attributes every call to the run (via the base URL, no headers needed), and
|
|
209
|
+
stops on a completion promise, a budget ceiling, or the iteration cap:
|
|
210
|
+
|
|
211
|
+
```bash
|
|
212
|
+
AGENTLEDGER_UPSTREAM_URL=https://api.anthropic.com \
|
|
213
|
+
AGENTLEDGER_COMPLETION_PROMISE="ALL TASKS COMPLETE" \
|
|
214
|
+
uv run python -m agentledger.proxy
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
```bash
|
|
218
|
+
agentledger run --max-iterations 50 --budget 25 -- \
|
|
219
|
+
claude -p "$(cat PROMPT.md)" --dangerously-skip-permissions
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
Each iteration shows up as *iteration N of the run* in `/api/runs`; when the
|
|
223
|
+
agent prints the completion promise in a response, run status flips to
|
|
224
|
+
`complete` and the loop exits with a cost/token summary. Any existing loop
|
|
225
|
+
script works too — poll `GET /api/runs/{run_id}` yourself, or let the proxy's
|
|
226
|
+
budgets (`AGENTLEDGER_BUDGET_DAILY=25.00`) hard-stop a runaway loop.
|
|
227
|
+
|
|
228
|
+
The same recipe works for any client with a base-URL override (Codex CLI,
|
|
229
|
+
opencode, OpenClaw, LiteLLM-based stacks) — set the OpenAI/Anthropic base URL
|
|
230
|
+
to the proxy and traffic is captured; add `x-agentledger-*` headers when you
|
|
231
|
+
want explicit attribution.
|
|
232
|
+
|
|
233
|
+
**OTel-native tools** (Gemini CLI, Codex `[otel]`, AutoGen/AG2, Pydantic AI,
|
|
234
|
+
Vercel AI SDK) don't need the proxy at all — point their OTLP exporter at the
|
|
235
|
+
ledger and GenAI spans are ingested directly:
|
|
236
|
+
|
|
237
|
+
```bash
|
|
238
|
+
export OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:8000
|
|
239
|
+
export OTEL_EXPORTER_OTLP_PROTOCOL=http/json
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
**Framework guides** — one per integration in
|
|
243
|
+
[docs/integrations](docs/integrations/README.md): Claude Code, Codex CLI,
|
|
244
|
+
opencode, OpenClaw, BMAD-METHOD, LangGraph/LangChain, CrewAI, OpenAI Agents
|
|
245
|
+
SDK, Gemini CLI, AutoGen/AG2, Pydantic AI, Vercel AI SDK, LiteLLM, and
|
|
246
|
+
OpenRouter.
|
|
247
|
+
|
|
248
|
+
---
|
|
249
|
+
|
|
176
250
|
## What gets captured
|
|
177
251
|
|
|
178
252
|
Every LLM call is stored with:
|
|
@@ -192,11 +266,14 @@ Every LLM call is stored with:
|
|
|
192
266
|
| `content` | Model's text output |
|
|
193
267
|
| `stop_reason` | Why the model stopped |
|
|
194
268
|
| `tokens_in` / `tokens_out` | Token usage |
|
|
269
|
+
| `cache_read_tokens` / `cache_write_tokens` | Prompt-cache usage — reads and writes are priced correctly per provider |
|
|
270
|
+
| `thinking` | Extended-thinking output (Anthropic), captured separately from `content` |
|
|
195
271
|
| `cost_usd` | Estimated cost based on model pricing |
|
|
196
272
|
| `latency_ms` | End-to-end response time |
|
|
197
273
|
| `status_code` | HTTP status from upstream — errors are captured too |
|
|
198
274
|
| `error_detail` | Upstream error message for non-200 responses |
|
|
199
|
-
| `agent_name` | From `x-agentledger-agent-name` header |
|
|
275
|
+
| `agent_name` | From `x-agentledger-agent-name` header, or auto-detected (e.g. `claude-code`) |
|
|
276
|
+
| `framework` | From `x-agentledger-framework` header, or fingerprint-detected (e.g. `claude-code`, `litellm`) |
|
|
200
277
|
| `user_id` | From `x-agentledger-user-id` header |
|
|
201
278
|
| `app_id` | From `x-agentledger-app-id` header |
|
|
202
279
|
| `environment` | From `x-agentledger-environment` header |
|
|
@@ -217,13 +294,17 @@ Every LLM call is stored with:
|
|
|
217
294
|
| `GET` | `/` | Live dashboard |
|
|
218
295
|
| `WS` | `/ws` | WebSocket stream — powers live dashboard updates |
|
|
219
296
|
| `GET` | `/api/sessions` | List recent sessions with aggregated stats |
|
|
297
|
+
| `GET` | `/api/runs` | List loop runs (explicit or auto-inferred) with iterations, cost, status, and flagged-call counts |
|
|
298
|
+
| `GET` | `/api/runs/{run_id}` | One run's status (`running` / `flagged` / `complete`) — poll this from loop scripts |
|
|
299
|
+
| `GET` | `/api/sessions/{session_id}/tools` | Derived tool executions — each tool call paired with its result, latency, and error status |
|
|
220
300
|
| `DELETE` | `/api/sessions/{session_id}` | Delete a session and all its calls |
|
|
221
301
|
| `GET` | `/api/search?q=...` | Full-text search across all captured calls |
|
|
222
302
|
| `GET` | `/session/{session_id}` | All calls in a session, ordered by time |
|
|
223
303
|
| `GET` | `/explain/{action_id}` | Single call by action ID |
|
|
224
304
|
| `GET` | `/export/{session_id}` | JSON compliance export with SHA-256 integrity hash |
|
|
225
305
|
| `GET` | `/export/{session_id}/report` | Printable HTML audit report |
|
|
226
|
-
| `POST` | `/mcp` | MCP tool server — `list_sessions`, `explain`, `get_session`, `search` |
|
|
306
|
+
| `POST` | `/mcp` | MCP tool server — `list_sessions`, `explain`, `get_session`, `search`, `list_runs`, `get_run_status` |
|
|
307
|
+
| `POST` | `/v1/traces` | OTLP/HTTP JSON ingest — GenAI spans from OTel-native tools become ledger calls (`/v1/logs`, `/v1/metrics` acked) |
|
|
227
308
|
|
|
228
309
|
**Examples:**
|
|
229
310
|
```bash
|
|
@@ -244,7 +325,7 @@ open http://localhost:8000/export/run-1/report
|
|
|
244
325
|
|
|
245
326
|
## MCP server
|
|
246
327
|
|
|
247
|
-
|
|
328
|
+
Agentic Ledger exposes its captured data as an MCP (Model Context Protocol) tool server at `POST /mcp`. Point Claude Desktop, Cursor, or any MCP-compatible client at it to query traces directly from your AI assistant.
|
|
248
329
|
|
|
249
330
|
**Tools available:**
|
|
250
331
|
|
|
@@ -254,6 +335,8 @@ AgentLedger exposes its captured data as an MCP (Model Context Protocol) tool se
|
|
|
254
335
|
| `explain(action_id)` | Full trace for a single LLM call — prompt, tool calls, output, tokens, cost |
|
|
255
336
|
| `get_session(session_id)` | All calls in a session in chronological order |
|
|
256
337
|
| `search(query)` | Full-text search across all captured calls |
|
|
338
|
+
| `list_runs` | Loop runs with iterations, cost, and status |
|
|
339
|
+
| `get_run_status(run_id)` | One run's status — lets an agent inspect its own loop and decide whether to continue |
|
|
257
340
|
|
|
258
341
|
**Configure in `claude_desktop_config.json`:**
|
|
259
342
|
```json
|
|
@@ -300,7 +383,7 @@ Once connected, you can ask your assistant things like:
|
|
|
300
383
|
| `AGENTLEDGER_API_KEY` | No | _(none)_ | Master admin key. When set, the dashboard, read, and management endpoints require authentication; the key grants the `admin` role and bootstraps API tokens (below). Skip for local dev; set when the proxy is on a server — you choose the value. |
|
|
301
384
|
| `AGENTLEDGER_INGEST_KEY` | No | _(none)_ | When set, the proxy forwards a request only if it carries a matching `x-agentledger-ingest-key` header — closing the open relay. Off by default; a loud startup warning fires when unset. |
|
|
302
385
|
| `AGENTLEDGER_EXPORT_HMAC_KEY` | No | _(none)_ | When set, compliance exports carry a tamper-evident keyed `hmac-sha256` integrity tag instead of a plain `sha256` checksum. |
|
|
303
|
-
| `AGENTLEDGER_EXTRA_PATHS` | No | _(none)_ | Comma-separated additional request paths to capture, e.g. `v1/responses,v1/custom`. Built-in paths (`v1/chat/completions`, `v1/messages`, `v1/responses`) are always captured. |
|
|
386
|
+
| `AGENTLEDGER_EXTRA_PATHS` | No | _(none)_ | Comma-separated additional request paths to capture, e.g. `v1/responses,v1/custom`. Built-in paths (`v1/chat/completions`, `v1/messages`, `v1/responses`, plus `v1/messages/count_tokens` recorded as a free call) are always captured. |
|
|
304
387
|
| `AGENTLEDGER_ASYNC_CAPTURE` | No | `off` | Persist captures on a background worker so storage never adds latency to the agent's call. Trade-off: reads become **eventually consistent** (a just-captured call may not be queryable for a brief moment). Recommended for high throughput. |
|
|
305
388
|
| `AGENTLEDGER_CAPTURE_QUEUE_MAX` | No | `10000` | Max captures buffered in async mode before load is shed (drops are counted in `/metrics`). |
|
|
306
389
|
| `AGENTLEDGER_CAPTURE_LEVEL` | No | `full` | `full` stores everything; `metadata` stores only metrics/metadata (model, tokens, cost, latency, agent, status) and drops prompts, responses, and tools. |
|
|
@@ -327,6 +410,16 @@ Once connected, you can ask your assistant things like:
|
|
|
327
410
|
| `AGENTLEDGER_RATE_LIMIT_AGENT_RPM` | _(none)_ | Max requests per minute per `agent_name`. |
|
|
328
411
|
| `AGENTLEDGER_RATE_LIMIT_USER_RPM` | _(none)_ | Max requests per minute per `user_id`. |
|
|
329
412
|
|
|
413
|
+
**Loop engine** — every call is stitched into ReAct threads (`thread_id`, `step_index`, `prev_action_id`) and fresh-context loop iterations are grouped into runs, with stuck-loop detection:
|
|
414
|
+
|
|
415
|
+
| Variable | Default | Description |
|
|
416
|
+
|---|---|---|
|
|
417
|
+
| `AGENTLEDGER_LOOP_ACTION` | `warn` | `warn` records `loop_flags` and fires a `loop_flag` webhook alert; `block` additionally returns HTTP 429 (`loop_detected`) for a session that tripped a guard; `off` disables inference. |
|
|
418
|
+
| `AGENTLEDGER_LOOP_REPEAT_THRESHOLD` | `3` | Consecutive identical tool calls (same tool, same arguments) before a thread is flagged stuck. |
|
|
419
|
+
| `AGENTLEDGER_LOOP_MAX_STEPS` | _(none)_ | Flag (and in block mode, stop) threads that exceed this many ReAct steps. |
|
|
420
|
+
| `AGENTLEDGER_LOOP_RUN_GAP_SECONDS` | `900` | Max gap between fresh-context spawns (same system prompt) that still count as iterations of one run. |
|
|
421
|
+
| `AGENTLEDGER_COMPLETION_PROMISE` | _(none)_ | Regex matched against response text. On match the call is flagged `completion_promise` and the run's status becomes `complete` — loop runners poll `GET /api/runs/{run_id}` and stop. |
|
|
422
|
+
|
|
330
423
|
**Alerts** — POST to your webhook when a threshold is breached (does not block calls — see [Alerts](#alerts)):
|
|
331
424
|
|
|
332
425
|
| Variable | Default | Description |
|
|
@@ -417,7 +510,7 @@ curl -H "x-agentledger-api-key: my-secret" http://localhost:8000/api/tokens
|
|
|
417
510
|
curl -X DELETE -H "x-agentledger-api-key: my-secret" http://localhost:8000/api/tokens/<token_id>
|
|
418
511
|
```
|
|
419
512
|
|
|
420
|
-
> Auth is enforced only when `AGENTLEDGER_API_KEY` is set; the master key is the admin bootstrap for minting tokens.
|
|
513
|
+
> Auth is enforced only when `AGENTLEDGER_API_KEY` is set; the master key is the admin bootstrap for minting tokens. The live `/ws` feed accepts the same credentials (`?api_key=`, `?token=`, `Authorization: Bearer`, or `x-agentledger-token`) and rejects unauthenticated connects with close code 1008 — the dashboard forwards its page credential to the socket automatically.
|
|
421
514
|
|
|
422
515
|
---
|
|
423
516
|
|
|
@@ -435,6 +528,9 @@ Pass these from your agent on each LLM call. All optional. They enrich captured
|
|
|
435
528
|
| `x-agentledger-environment` | `development` | `production`, `staging`, or `development`. Shown in the dashboard. |
|
|
436
529
|
| `x-agentledger-handoff-from` | _(none)_ | Agent handing off control (e.g. `"orchestrator"`). Renders as a directed edge in the Flow DAG. |
|
|
437
530
|
| `x-agentledger-handoff-to` | _(none)_ | Agent receiving control (e.g. `"researcher"`). Renders as a directed edge in the Flow DAG. |
|
|
531
|
+
| `x-agentledger-framework` | _(auto-detected)_ | Framework/tool making the call (e.g. `"langgraph"`, `"bmad"`). When absent, well-known clients are fingerprinted automatically (Claude Code, LiteLLM). |
|
|
532
|
+
| `x-agentledger-run-id` | _(auto-inferred)_ | Groups sessions into a loop run (e.g. a Ralph overnight run). When absent, fresh-context sessions sharing a system prompt within `AGENTLEDGER_LOOP_RUN_GAP_SECONDS` are grouped automatically. |
|
|
533
|
+
| `x-agentledger-iteration` | _(auto-inferred)_ | Iteration number within the run. |
|
|
438
534
|
|
|
439
535
|
**Single agent — fully annotated:**
|
|
440
536
|
```python
|
|
@@ -484,7 +580,7 @@ The Flow tab renders `orchestrator → researcher` as a DAG with cost and latenc
|
|
|
484
580
|
|
|
485
581
|
**OpenAI Agents SDK (`openai-agents`) — per-agent clients:**
|
|
486
582
|
|
|
487
|
-
The `openai-agents` SDK uses its own internal OpenAI client. To pass
|
|
583
|
+
The `openai-agents` SDK uses its own internal OpenAI client. To pass Agentic Ledger headers you need to create a client per agent using `OpenAIResponsesModel` and set it as the agent's `model`.
|
|
488
584
|
|
|
489
585
|
```python
|
|
490
586
|
import uuid
|
|
@@ -498,7 +594,7 @@ BASE_URL = os.getenv("OPENAI_BASE_URL") # e.g. http://localhost:8000/v1
|
|
|
498
594
|
|
|
499
595
|
def al_model(agent_name: str, model: str = "gpt-4o-mini",
|
|
500
596
|
handoff_from: str | None = None, handoff_to: str | None = None):
|
|
501
|
-
"""Create a model instance that sends
|
|
597
|
+
"""Create a model instance that sends Agentic Ledger metadata headers."""
|
|
502
598
|
if not BASE_URL:
|
|
503
599
|
return model # proxy not configured — use default client
|
|
504
600
|
headers = {
|
|
@@ -527,7 +623,7 @@ Each agent's calls are tagged with its name and pipeline position. The Flow tab
|
|
|
527
623
|
|
|
528
624
|
## Alerts
|
|
529
625
|
|
|
530
|
-
|
|
626
|
+
Agentic Ledger fires a `POST` to your webhook URL when a threshold is breached. You connect it to whatever you already use — Slack, PagerDuty, Discord, email, or a custom endpoint. Agentic Ledger sends the payload; the integration is on your side.
|
|
531
627
|
|
|
532
628
|
**Payload format:**
|
|
533
629
|
```json
|
|
@@ -552,6 +648,8 @@ AgentLedger fires a `POST` to your webhook URL when a threshold is breached. You
|
|
|
552
648
|
| `high_error_rate` | Session error rate exceeds `AGENTLEDGER_ALERT_ERROR_RATE` |
|
|
553
649
|
| `daily_spend` | Daily total spend crosses `AGENTLEDGER_ALERT_DAILY_SPEND` |
|
|
554
650
|
| `budget_exceeded` | A budget limit is hit and `AGENTLEDGER_BUDGET_ACTION` is `warn` or `both` |
|
|
651
|
+
| `loop_flag` | The loop engine raised flags on a call (`repeat_tool_call`, `step_budget_exceeded`, `completion_promise`) |
|
|
652
|
+
| `run_complete` | A run's completion promise was seen — the payload carries the full run summary (iterations, cost, tokens, flagged calls) |
|
|
555
653
|
|
|
556
654
|
**Budgets vs alerts:**
|
|
557
655
|
- **Budgets** (`AGENTLEDGER_BUDGET_*`) — block the call before it reaches the LLM. Agent gets HTTP 429.
|
|
@@ -569,7 +667,7 @@ AgentLedger fires a `POST` to your webhook URL when a threshold is breached. You
|
|
|
569
667
|
|
|
570
668
|
## OpenTelemetry export
|
|
571
669
|
|
|
572
|
-
|
|
670
|
+
Agentic Ledger can emit every intercepted LLM call as an OTel span to any OTLP-compatible collector: Grafana Tempo, Jaeger, Honeycomb, Datadog, Dynatrace, or any vendor that supports OTLP/HTTP.
|
|
573
671
|
|
|
574
672
|
**Install the extra** (Docker image includes OTel — no extra step needed when using Docker):
|
|
575
673
|
```bash
|
|
@@ -663,7 +761,7 @@ This runs three jobs:
|
|
|
663
761
|
```
|
|
664
762
|
PyPI project name: agentic-ledger
|
|
665
763
|
Owner: ShekharBhardwaj
|
|
666
|
-
Repository:
|
|
764
|
+
Repository: AgenticLedger
|
|
667
765
|
Workflow name: release.yml
|
|
668
766
|
Environment name: pypi
|
|
669
767
|
```
|
|
@@ -672,6 +770,35 @@ This runs three jobs:
|
|
|
672
770
|
|
|
673
771
|
---
|
|
674
772
|
|
|
773
|
+
## Troubleshooting
|
|
774
|
+
|
|
775
|
+
**`incompatible architecture (have 'arm64', need 'x86_64')`** on macOS — your
|
|
776
|
+
terminal is running under Rosetta, so Python picks its x86_64 slice while pip
|
|
777
|
+
installed arm64 native wheels. Check with `arch` (should print `arm64` on
|
|
778
|
+
Apple Silicon). Quick fix: prefix the command with `arch -arm64`. Permanent
|
|
779
|
+
fix: uncheck "Open using Rosetta" on your terminal app, use an Apple Silicon
|
|
780
|
+
build of your editor, and restart any long-lived `tmux` server.
|
|
781
|
+
|
|
782
|
+
**`module 'httpx' has no attribute 'AsyncClient'`** — fixed in
|
|
783
|
+
`0.3.0-alpha.2`; upgrade with `pip install --upgrade agentic-ledger`.
|
|
784
|
+
|
|
785
|
+
**Port 8000 already in use** — another proxy instance (or app) is running;
|
|
786
|
+
stop it or set `AGENTLEDGER_PORT`.
|
|
787
|
+
|
|
788
|
+
**`401 OAuth access token has expired` from Claude Code** — the proxy passed
|
|
789
|
+
Anthropic's answer through unmodified; re-authenticate with `claude` →
|
|
790
|
+
`/login`. Errored calls are still captured, so you'll see the 401 in the
|
|
791
|
+
dashboard.
|
|
792
|
+
|
|
793
|
+
**`/` shows the classic dashboard instead of the web app** — you're running
|
|
794
|
+
from a source checkout without the web-app build. `cd dashboard-app && npm ci
|
|
795
|
+
&& npm run build` and restart. PyPI and Docker installs always include the app.
|
|
796
|
+
|
|
797
|
+
---
|
|
798
|
+
|
|
675
799
|
## License
|
|
676
800
|
|
|
677
801
|
MIT
|
|
802
|
+
|
|
803
|
+
<!-- MCP registry ownership verification -->
|
|
804
|
+
`mcp-name: io.github.shekharbhardwaj/agentic-ledger`
|