Observed since 20 Oct, 22:33 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
Official Python client for the Agent Ledger API
Official Python SDK for Agent Ledger. Instrument your AI agents with session telemetry, capture every LLM/tool call, and enforce budget guardrails with a single synchronous HTTP client.
Portal: https://agent-ledger.thabo.xyz/
httpx, so you stay in control of transports, retries, and proxies.BudgetGuardrailDetails) for precise guardrail reporting./v1/sessions, /v1/events).pip install agent-ledger-sdk
# or with uv
uv add agent-ledger-sdk
https://agent-ledger-api.azurewebsites.net.import os
import time
from agent_ledger_sdk import AgentLedgerClient, BudgetGuardrailError, run_session, instrument_tool
from openai import OpenAI
ledger = AgentLedgerClient(api_key=os.environ["AGENT_LEDGER_API_KEY"])
llm = OpenAI(api_key=os.environ["OPENAI_API_KEY"])
try:
with run_session(ledger, "support-bot") as (session_id, steps):
started = time.perf_counter()
completion = llm.responses.create(
model="gpt-4o-mini",
input=[{"role": "user", "content": "Draft a welcome email."}],
temperature=0.2,
)
latency_ms = int((time.perf_counter() - started) * 1000)
content = completion.output[0].content[0].text
ledger.log_llm_call(
session_id,
{
"stepIndex": steps.next(),
"provider": "openai",
"model": completion.model,
"prompt": "Draft a welcome email.",
"response": content,
"tokensIn": completion.usage.input_tokens,
"tokensOut": completion.usage.output_tokens,
"latencyMs": latency_ms,
},
)
# Tool wrapper example (logs tool_call + tool_result automatically)
instrument_tool(
ledger=ledger,
session_id=session_id,
step_index=steps.next(),
tool_name="weather",
tool_input={"city": "Boston"},
run=lambda: {"temp_f": 61},
)
except BudgetGuardrailError as exc:
print("Budget exceeded", exc.details)
raise
finally:
ledger.close()
ℹ️ The SDK never proxies your LLM/tool calls. You run them directly and forward the metadata (prompt, response, tokens, latency) to Agent Ledger for analytics, guardrails, and diffing.
ledger.start_session("agent-name").log_llm_call).log_tool_call).log_tool_result).log_events).ledger.end_session(...) so the dashboard can show the outcome next to cost metrics.Keep the session ID in scope (store it on the request context, job payload, or tracing span) so every downstream component can append telemetry.
The Agent Ledger API expects camelCase keys. The Python SDK forwards your dictionaries as-is, so be sure to match the schema exactly.
| Event | Required keys | Optional keys | Notes |
|---|---|---|---|
| LLM call | stepIndex, model, provider, prompt, response, tokensIn, tokensOut, latencyMs | — | Use log_llm_call. Agent Ledger prices the call automatically using provider/model/tokens. |
| Tool call | stepIndex, toolName, toolInput | — | Use log_tool_call right before invoking the tool. |
| Tool result | stepIndex, toolName, toolOutput, latencyMs | — | Use log_tool_result after receiving the output. |
| Custom | type, stepIndex, plus any attributes you want | Anything | Send via log_events for domain-specific signals. |
Conventions:
stepIndex is a monotonically increasing integer, making prompt/tool diffs straightforward.AgentLedgerClient(api_key, *, timeout=10.0, transport=None)| Parameter | Type | Description |
|---|---|---|
api_key | str (required) | Workspace API key. Raises ValueError if empty. |
timeout | float | Passed to the underlying httpx.Client. |
transport | `httpx.BaseTransport | None` |
The client can be used as a context manager:
from agent_ledger_sdk import AgentLedgerClient
with AgentLedgerClient(api_key="sk-...", timeout=5) as ledger:
session_id = ledger.start_session("batch-writer")
ledger.end_session(session_id, "success")
start_session(agent_name: str) -> strCreates a session row and returns its UUID.
end_session(session_id: str, status: Literal["success", "error"], *, error_message: Optional[str] = None) -> NoneMarks a session as finished. When status == "error", include an error_message so the dashboard can surface it.
log_events(session_id: str, events: Iterable[Mapping[str, Any]]) -> NoneLow-level ingestion helper. Accepts any iterable, clones each event into a list, and POSTs them to /v1/events. Each event must include a type field.
log_llm_call / log_tool_call / log_tool_resultThin wrappers that add the correct type and delegate to log_events. Use them to keep your instrumentation consistent.
BudgetGuardrailError — raised when the API returns HTTP 429 with guardrail metadata. The details attribute includes:
BudgetGuardrailDetails(
agent_name="support-bot",
daily_limit_usd=20.0,
spent_today_usd=18.4,
attempted_cost_usd=0.9,
projected_cost_usd=19.3,
remaining_budget_usd=0.7,
)
Use it to short-circuit further tool/LLM calls or trigger human intervention.
AgentLedgerError — raised for any other non-success HTTP response (network failures, 4xx/5xx). Contains the server-provided error field when available.
AGENT_LEDGER_API_KEY (or load it from your secrets manager) and the SDK targets the hosted API automatically.https://agent-ledger-api.azurewebsites.net.For local experimentation, leave the SDK untouched and proxy traffic through tools like pytest-httpserver or MSW if you need to inspect requests.
httpx.HTTPTransport or httpx_socks.SyncProxyTransport to route traffic through proxies or service meshes.tenacity) if you need resilience around transient network errors.httpx.Client is threadsafe; reuse a single AgentLedgerClient across worker threads or WSGI/ASGI processes.asyncio support today, instantiate the SDK inside an executor, or adapt it by swapping httpx.Client for httpx.AsyncClient (PRs welcome!).transport injections or libraries such as pytest-httpserver/MSW so you can assert payloads.BudgetGuardrailError to degrade gracefully.cd packages/sdk-py
python -m venv .venv && source .venv/bin/activate
pip install -e .[dev]
pytest
MIT
Download counts and popularity will appear here as the collector receives them.
| Version | Published | Direct dependencies | Open version |
|---|---|---|---|
| 0.0.6 | 1 Jan 2026 | 3 |
This describes our collected data; it is not a security assessment.
Observed since 20 Oct, 22:33 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
package:7e63213bc9ff258b4142436ca9c080fa67f14abcc1bda494001afc12bcdab6c5