Skip to main content

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.

PyPI License: MIT Python 3.9+

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

  1. observe() detects your LLM client type
  2. Wraps API methods to capture timing, tokens, and I/O
  3. Buffers spans in a background thread (zero latency impact)
  4. 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

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

spantree_sdk-0.2.0.tar.gz (13.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

spantree_sdk-0.2.0-py3-none-any.whl (10.3 kB view details)

Uploaded Python 3

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

Hashes for spantree_sdk-0.2.0.tar.gz
Algorithm Hash digest
SHA256 83adb300acb08a8dd093fcb05707ea72a71f12db7b12cad4b41416f037d06308
MD5 70503f2312a94fbf24b30f89470e677d
BLAKE2b-256 1a29ca1501bd3f4647ea25934434a13af3dab42e003d39eeaaa88baee8da5370

See more details on using hashes here.

Provenance

The following attestation bundles were made for spantree_sdk-0.2.0.tar.gz:

Publisher: publish.yml on spantree-io/spantree-python

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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

Hashes for spantree_sdk-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 ed4f16fc6ddb1839f98dd0b7e265e3180cbc1f5d4b905600bac1d0faa966cc98
MD5 526a74177b26b3a806548a64aa28a1e0
BLAKE2b-256 293a65b1f6746f1cefbe860471fcfd65eb9189e01a9fa91f92b7bb10bac4bbe4

See more details on using hashes here.

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

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page