The SDK is small on purpose. The data model is shaped after your product, not after the call stack.
Two context managers, and you are instrumented.
pip install agentsightEvery OpenAI, Anthropic, LangChain and LlamaIndex call inside the turn is captured with no extra code.
Six lines. Your agent unchanged.
init() reads your key from the environment. Wrap a conversation, wrap a turn, and record the two messages. Tools and tasks are decorators; other providers work through wrap() and model_hint().
Every model call made inside a turn is captured, including the evaluator, router and classifier calls nobody hand-tracks, exactly which providers and how is on the next page.
import agentsight
agentsight.init()
with agentsight.conversation("wa-3859"):
with agentsight.turn():
agentsight.user_message("Where is my order?")
response = agent.run(…) # unchanged
agentsight.agent_message(str(response))
Directly patched beats framework-routed beats wrap(): each tier gets more, not less, of the accounting.
What is captured without you writing a line for it.
OpenAI and Anthropic calls are patched directly. LangChain and LlamaIndex catch whatever they route through, whichever provider is behind them. Anything else, Gemini, Bedrock, Vertex, Ollama, a self-hosted model, is covered once it passes through a framework integration or an explicit wrap() / model_hint() call.
| Provider or framework | How | What you get |
|---|---|---|
| OpenAI | Patched directly | Full: tokens, model id, cache and reasoning counters |
| Anthropic | Patched directly | Full: tokens, model id, cache and reasoning counters |
| LangChain | Registered with the callback system | Whatever the framework routes through it |
| LlamaIndex | Registered with the dispatcher | Whatever the framework routes through it |
| Gemini, Bedrock, Vertex, Ollama, LiteLLM, self-hosted | Via a framework, or wrap() / model_hint() | Captured if the provider reports it; unpriced unless we carry a rate |
A model with no known rate is reported as unpriced, never as free. A zero you cannot trust is worse than a gap you can see.
Every model call, priced without a rate table in your code.
The SDK only records tokens. Pricing is applied server-side from our own table, so a rate change or a correction restates your history instead of staying frozen at whatever shipped in the SDK version you deployed with.
| Field | What it means |
|---|---|
| Priced today | OpenAI and Anthropic model families, roughly 130 rows including Bedrock and Vertex id variants |
| Matching | Longest seeded prefix, so a dated snapshot id like gpt-4o-2024-08-06 still resolves |
| Versioned | By effective date, so a rate change restates history instead of freezing it |
| Unknown model | Reported as unpriced, never as free |
| Counted, priced separately | Input, output, embedding, cache read, cache write tokens |
| Counted, never double-billed | Reasoning and audio tokens, already inside input/output |
All three ship together. The workflow skills reference the base skill's files, so install the set, not one of them.
Three Claude Code skills, for setup, migration and everyday reference.
/agentsight-integration
Sets up a codebase with no recording yet: reads your code, asks only what it cannot answer, and verifies the result against AGENTSIGHT_FILE_EXPORTER.
/agentsight-migration
Inspects a legacy export, asks about field mappings and timezones, and produces the JSON file for the dashboard's migrate page. It writes the file; you still upload it.
/agentsight
The ongoing reference: the full tracking and API surface, when to reach for wrap(), and how to debug a chart reading zero.
Skills CLI
npx skills add agentsightio/agentsightioClaude Code plugin marketplace
/plugin marketplace add agentsightio/agentsightio/plugin install agentsight@agentsightA conversation is not a trace. A trace lives as long as a request; a conversation lives as long as your customer's problem.
Answer latency is measured from the turn, not inferred from message timestamps.
The router call is an LLM call too. AgentSight counts it, most teams never hand-track it, and it is usually where surprising cost hides.
Everything the agent did during a turn nests inside that turn, which is why the turn's duration is the answer latency.
Seven things, shaped after your product.
- conversationwith agentsight.conversation("chat-123")
Lasts hours or days. Keyed by your own id, survives restarts and deploys.
- └turnwith agentsight.turn():
One exchange. Its duration is your answer latency, measured not inferred.
- └messageuser_message() / agent_message()
Explicit by design, so transcripts show what the human typed.
- └tool@agentsight.tool
Work the agent calls out to. Timed, with arguments, response and errors.
- └task@agentsight.task
Internal work, parsing, reranking. Same capture as tools.
- └llm callautomatic
Every model call, including the evaluator, router and classifier ones.
- buttonagentsight.button()
A click happens in the browser; no server decorator can see it.
- attachmentrecord_ / upload_attachments()
Record that files exist and move no bytes, or send the contents.
A conversation is not a trace. A trace lives as long as a request; a conversation lives as long as your customer’s problem.
Cost is priced server-side, so when a provider changes its rates your history can be restated. A model with no known rate is reported as unpriced, never as free.
What you pass with the conversation, context only your application has.
| Field | Becomes |
|---|---|
| customer_ip_address | geolocated server-side to city, country, region, timezone |
| customer_id | unique per user, drives Individual Users |
| device | desktop · tablet · mobile |
| language | drives the Agent Language chart |
| source | web, WhatsApp, Viber, recorded, not yet charted |
| metadata | free-form JSON, updatable as the conversation unfolds |


There is no setting that turns prompt capture on, because the SDK never reads them.
You can read the payload before we ever see it.
Set AGENTSIGHT_FILE_EXPORTER and spans are written to a directory instead of being transmitted. Run your own application, open the files, and see exactly what would have been sent.
| Limit | |
|---|---|
| 16,384 | chars, message content, tool responses, error strings truncate |
| 255 | chars, conversation string fields clamp |
| 16 | KB, metadata budget; oversized entries dropped largest-first |
- provider
- "openai"
- requested_model
- "gpt-4o"
- resolved_model
- "gpt-4o-2024-08-06"
- input_tokens
- 1284
- output_tokens
- 312
- cache_read_tokens
- 1024
- operation
- "chat"
- streaming
- true
- duration_ms
- 700
- status
- "ok"
Never transmitted
- prompt
- completion
- messages[]
- system
LLM spans carry the accounting only. There is no setting that turns prompt capture on, because the SDK never reads them.
No lock-in and no export ticket. API keys are scoped read-only or full, per agent, revocable, with expiry and last-used tracking.
Your data is yours.
Conversations, messages, action logs and usage rows are projections. The raw OpenTelemetry spans are kept and readable through the API, exact parent/child structure, per-call durations and status, tool arguments and responses, and any attribute a newer SDK emits that has no projection rule yet.
- conversationspaginated
- feedbackspaginated
- actionspaginated
- usagepaginated
- spansraw OTel
Your test runs never reach your client’s report.
Every agent is seeded with Production and Development. Analytics reports cover production only, by decision. Development mode gets a lightweight “is this actually tracking?” probe instead, so you can confirm the wiring works without inventing metrics from test data.
Instrument it in an afternoon. Hand it over the same day.
- Full dashboard on the free plan
- No card required
- Model spans never carry prompts