Skip to main content

anvil-sdk (Python)

Trace instrumentation for LLM apps. Spec: plan/sdk.md.

pip install anvil-sdk           # + [langchain] for the callback handler
import anvil_sdk as anvil

anvil.init(api_key="ak_...", base_url="http://localhost:8000")

with anvil.trace("answer_question", input=question) as t:
    with anvil.span("retrieve", type="retrieval") as s:
        s.output = search(question)
    with anvil.span("generate", type="llm") as s:
        s.end(output=answer, tokens_in=120, tokens_out=30)
    t.output = answer

LangChain apps need one line instead:

from anvil_sdk.langchain import AnvilCallbackHandler

chain.invoke(question, config={"callbacks": [AnvilCallbackHandler()]})

The guarantee

This SDK never blocks or crashes your app (ADR-0013). Traces go to a bounded in-memory queue and a background thread ships them. If Anvil is slow, down, or misconfigured: the queue sheds its oldest entries, counts them in anvil.stats(), and your request path never notices. Nothing in this package raises into your code except exceptions your own functions raised.

API

init(api_key, base_url, flush_interval=2.0, max_queue=1000, redact=None) Configure the global client
trace(name, input=…, metadata=…, session_id=…, user_ref=…) Context manager; root of a unit of work
span(name, type=…, input=…) Context manager; nests via contextvars
@observe(type="llm") Decorator sugar — args in, return value out, exceptions marked
start_trace(...) / start_span(...) Manual API for middleware and callbacks; call .end(output=…)
feedback(trace_id, rating, comment=None, user_ref=None) End-user thumbs up/down (-1 / +1)
flush() / shutdown() / stats() Lifecycle and counters

trace.id is a client-generated UUID exposed on the object — hand it to your frontend so a thumbs-down can be attached to that exact trace later.

Span types: llm, retrieval, tool, embedding, chain, custom.

feedback — closing the loop

Round-trip trace.id to your frontend, then send the vote back with it:

@app.post("/ask")
def ask(body: AskRequest):
    handler = AnvilCallbackHandler(trace_name="ask")
    answer = chain.invoke(body.question, config={"callbacks": [handler]})
    return {"answer": answer, "trace_id": handler.trace.id}

@app.post("/feedback")
def feedback(body: FeedbackRequest):
    anvil.feedback(body.trace_id, -1, comment=body.comment, user_ref=body.user_id)
    return {"ok": True}

Two things worth knowing:

  • Call it as soon as the user clicks. The vote routinely beats its own trace to Anvil's database; the server holds it and waits for the trace rather than rejecting the race. You never need to sleep first.
  • Pass user_ref if you have one. With it, repeat votes upsert — one user toggling 👎 → 👍 replaces their row instead of leaving two contradictory ones. Without it, every call is an independent anonymous vote.

Fire-and-forget like everything else here: feedback() never blocks or raises, and its own counters (feedback_queued/feedback_sent/feedback_dropped) are separate from the trace ones so a busy trace queue can't hide a lost vote.

Downvoted traces show up in the dashboard's failure inbox — thumbs-down traces not yet in any dataset — where one click turns a real failure into a test case.

redact — scrub PII before it leaves your process

anvil.init(api_key=..., redact=scrub)

def scrub(obj):          # called for every trace *and* every span
    obj.input = mask(obj.input)
    return obj           # or None to drop the object entirely

Payloads are usually dicts and lists, not flat strings — walk them recursively. examples/demo-rag-app/demo/app.py has a worked example. A hook that raises causes the object to be dropped rather than shipped un-scrubbed.

Fields over 100 KB are truncated to a preview before sending, mirroring the server-side policy so large payloads degrade instead of 413ing.

Tests

pip install -e .[dev] && python -m pytest -q

Keyless: LLM calls use LangChain's fake models and the transport is mocked with respx. Emitted payloads are validated against packages/shared/trace-schema.json, the same schema the ingest endpoint enforces.

Metadata

Release files for anvil-sdk 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for anvil-sdk 0.1.0
File Size Uploaded Provenance Actions
anvil_sdk-0.1.0.tar.gz 34.4 kB With provenance Details for anvil_sdk-0.1.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for anvil-sdk 0.1.0
File Interpreter ABI Platform Actions
anvil_sdk-0.1.0-py3-none-any.whl Python 3 none any Details for anvil_sdk-0.1.0-py3-none-any.whl

Total release size: 58.3 kB

Release files / anvil_sdk-0.1.0.tar.gz

Download URL anvil_sdk-0.1.0.tar.gz
Size 34.4 kB
Tags Source
SHA-256 checksum
How to use checksums
1b0090548941a5cb8196e9646d3767a6ec7cdaa683eece3cea8ecc0353c19af9
BLAKE2b-256 checksum
How to use checksums
f2cce142ab037f74e53dedeb6bb5de3f9905d1d2ab26dfae1e9f6a07bf9f33e5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 8, 2026.

Transparency log

Release files / anvil_sdk-0.1.0-py3-none-any.whl

Download URL anvil_sdk-0.1.0-py3-none-any.whl
Size 23.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
a7b91ef1ac55981feabe780dab3ced03412efb4ce28fb3eae7fd427e45414482
BLAKE2b-256 checksum
How to use checksums
afa9974ce1e936267fe2c9ae60ee91551d88bb46d5dfb5cdc50631c4c6e8f538
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 8, 2026.

Transparency log

Security for anvil-sdk 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

Both files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for anvil_sdk-0.1.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 8, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page