Trace your AI agent's LLM calls with one line of code
Project description
spantree
Trace your AI agent's LLM calls with one line of code.
Install
pip install spantree-sdk
Quick Start
from spantree import observe
from anthropic import Anthropic
client = observe(Anthropic())
# All calls are now automatically traced
response = client.messages.create(
model="claude-sonnet-4-20250514",
messages=[{"role": "user", "content": "Hello!"}],
max_tokens=1024,
)
That's it. Every LLM call is captured — model, tokens, latency, input/output — and sent to the Spantree dashboard in the background with zero latency impact.
Grouping Calls with trace()
By default, each LLM call creates its own trace. Use trace() to group multiple calls under a single trace — ideal for agent loops, multi-step workflows, and tool-use patterns.
from spantree import observe, trace
from anthropic import Anthropic
client = observe(Anthropic())
with trace("chat-session"):
messages = []
while True:
messages.append({"role": "user", "content": input("> ")})
response = client.messages.create(
model="claude-sonnet-4-20250514",
messages=messages,
max_tokens=1024,
)
messages.append({"role": "assistant", "content": response.content[0].text})
All LLM calls inside the with trace(...) block share the same trace_id and appear as spans within a single trace in the dashboard.
Tool use
with trace("agent-task"):
response = client.messages.create(...) # span 1
tool_result = run_tool(response) # not traced (your code)
response = client.messages.create(...) # span 2, same trace
Multi-agent
with trace("research-pipeline"):
plan = orchestrator.messages.create(...) # span 1
research = researcher.messages.create(...) # span 2
final = orchestrator.messages.create(...) # span 3
Nested traces
with trace("pipeline") as t:
print(t.trace_id) # access the trace ID
response = client.messages.create(...) # child of "pipeline"
with trace("sub-agent"):
response = client.messages.create(...) # child of "sub-agent"
response = client.messages.create(...) # child of "pipeline"
Without trace() — unchanged behavior
client = observe(Anthropic())
response = client.messages.create(...) # trace A
response = client.messages.create(...) # trace B (independent)
Custom Metadata
Attach arbitrary key-value data to spans for filtering and analysis in the dashboard.
Global metadata (all spans from a client)
client = observe(Anthropic(), metadata={"user_id": "u_123", "env": "prod"})
response = client.messages.create(...) # span gets {"user_id": "u_123", "env": "prod"}
Per-call metadata
client = observe(Anthropic(), metadata={"user_id": "u_123"})
response = client.messages.create(
model="claude-sonnet-4-20250514",
messages=[{"role": "user", "content": "Hello!"}],
max_tokens=1024,
spantree_metadata={"session_id": "sess_abc", "feature_flag": "new-flow"},
)
# span gets {"user_id": "u_123", "session_id": "sess_abc", "feature_flag": "new-flow"}
Per-call metadata merges with global metadata. Per-call values win on key conflicts.
On trace spans
with trace("my-workflow") as t:
t.metadata = {"pipeline": "v2", "run_id": "run_xyz"}
response = client.messages.create(...)
Configuration
Set your API key via environment variable:
export SPANTREE_API_KEY=sk_your_key_here
Or configure programmatically:
from spantree import configure
configure(
api_key="sk_your_key_here",
base_url="https://api.spantree.dev",
)
Supported Providers
| Provider | Wrapper | What's traced |
|---|---|---|
| Anthropic | observe(Anthropic()) |
messages.create() |
| OpenAI | observe(OpenAI()) |
chat.completions.create() |
How It Works
observe()detects your LLM client type- Wraps API methods to capture timing, tokens, and I/O
- Buffers spans in a background thread (zero latency impact)
- Flushes batches to the Spantree API every 5s or 100 spans
No monkey-patching. No import hooks. Just a thin wrapper around your existing client.
Requirements
- Python 3.9+
- Only runtime dependency:
httpx
Contributing
Contributions are welcome! Please open an issue or submit a pull request.
# Clone and install dev dependencies
git clone https://github.com/spantree-io/spantree-python.git
cd spantree-python
pip install -e ".[dev]"
# Run tests
pytest
# Lint
ruff check .
License
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file spantree_sdk-0.2.0.tar.gz.
File metadata
- Download URL: spantree_sdk-0.2.0.tar.gz
- Upload date:
- Size: 13.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
83adb300acb08a8dd093fcb05707ea72a71f12db7b12cad4b41416f037d06308
|
|
| MD5 |
70503f2312a94fbf24b30f89470e677d
|
|
| BLAKE2b-256 |
1a29ca1501bd3f4647ea25934434a13af3dab42e003d39eeaaa88baee8da5370
|
Provenance
The following attestation bundles were made for spantree_sdk-0.2.0.tar.gz:
Publisher:
publish.yml on spantree-io/spantree-python
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
spantree_sdk-0.2.0.tar.gz -
Subject digest:
83adb300acb08a8dd093fcb05707ea72a71f12db7b12cad4b41416f037d06308 - Sigstore transparency entry: 1605094322
- Sigstore integration time:
-
Permalink:
spantree-io/spantree-python@2fd37540c222f76381d667dd0c623bbf53e7d964 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/spantree-io
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@2fd37540c222f76381d667dd0c623bbf53e7d964 -
Trigger Event:
push
-
Statement type:
File details
Details for the file spantree_sdk-0.2.0-py3-none-any.whl.
File metadata
- Download URL: spantree_sdk-0.2.0-py3-none-any.whl
- Upload date:
- Size: 10.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ed4f16fc6ddb1839f98dd0b7e265e3180cbc1f5d4b905600bac1d0faa966cc98
|
|
| MD5 |
526a74177b26b3a806548a64aa28a1e0
|
|
| BLAKE2b-256 |
293a65b1f6746f1cefbe860471fcfd65eb9189e01a9fa91f92b7bb10bac4bbe4
|
Provenance
The following attestation bundles were made for spantree_sdk-0.2.0-py3-none-any.whl:
Publisher:
publish.yml on spantree-io/spantree-python
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
spantree_sdk-0.2.0-py3-none-any.whl -
Subject digest:
ed4f16fc6ddb1839f98dd0b7e265e3180cbc1f5d4b905600bac1d0faa966cc98 - Sigstore transparency entry: 1605094403
- Sigstore integration time:
-
Permalink:
spantree-io/spantree-python@2fd37540c222f76381d667dd0c623bbf53e7d964 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/spantree-io
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@2fd37540c222f76381d667dd0c623bbf53e7d964 -
Trigger Event:
push
-
Statement type: