verica-observability
Two-line LLM tracing for Verica: your OpenAI/Anthropic calls land as evaluable traces.
Install
pip install verica-observability
Use
import verica
verica.init(token=os.environ["VERICA_TOKEN"])
# Import the clients AFTER init so they are patched. OpenAI, Anthropic, and
# Gemini (the google-genai SDK) are all auto-traced, no extra code.
from openai import OpenAI
from anthropic import Anthropic
from google import genai
Sessions (multi-turn)
Traces sharing a conversation id reassemble into a Verica session. In a server handling many conversations, scope the id per request:
with verica.conversation(f"chat-{chat_id}"):
response = client.chat.completions.create(...)
Context-local (async- and thread-safe); it overrides the global
conversation_id from init(), and verica.conversation(None) suppresses the
attribute for the block. For a single-conversation script, passing
conversation_id="..." to init() is enough.
Resend history exactly as sent. Turns are stored as deltas: at ingest, Verica matches the history you resend against what previous turns already stored, and that match is exact (byte-identical text). If your app mutates prior messages between requests (for example, appending "Respond in JSON" to the last user message and stripping it from earlier turns when rebuilding the history), no prefix ever matches and every turn falls back to storing, and showing, the full conversation again. Keep injected instructions in the system prompt, or resend them exactly as originally sent.
Agent loops
By default each LLM call lands as its own single-span trace. Wrap a whole
agent run in verica.span so every auto-instrumented call inside it (and any
nested verica.span / verica.tool) becomes a child: one trace per run.
verica.tool does the same and marks the span as a tool execution (the GenAI
semconv gen_ai.operation.name = execute_tool + gen_ai.tool.name, which
Verica detects for tool-span counting and span_check).
with verica.span("agent.run"):
client.chat.completions.create(...) # child span
with verica.tool("lookup_weather"):
weather = lookup_weather("Cordoba")
client.chat.completions.create(...) # child span
Both take a name and are context managers. The span name is your string
verbatim. On a thrown error the span is marked with ERROR status and the
exception propagates unchanged. Fail-open: without init() (or if tracing is
broken) the block just runs and nothing is emitted. See examples/agent.py for
a full two-turn run with two tools.
Adopting in an agent app (e.g. Routina)
Wrap the loop once and each tool execution once; everything else is unchanged:
def run_agent(...):
with verica.span("agent.run"):
...existing loop: each client call lands as a child span...
# in the tool dispatcher:
with verica.tool(name):
result = agent_tools.execute(name, args, ...)
Tags
Tags land on each trace (traces.tags): filter the workbench by them, and bind
criteria to them so evaluation preselects the right criteria per tag.
verica.init(token=..., tags=["routina", "prod"]) # global, every trace
with verica.tags(["chat", "premium"]): # adds to the globals
client.chat.completions.create(...)
Per-request tags UNION with the globals (dedup, order preserved); nested scopes
accumulate. Context-local, async- and thread-safe. Values are coerced with
str(); the server caps at 20 tags x 120 chars.
Serverless
Call verica.flush() (or verica.shutdown()) before the runtime freezes so
the span batch is exported.
Options
| Option / env var | Default | Notes |
|---|---|---|
token / VERICA_TOKEN |
(required) | ingest-scoped API token |
capture_content / VERICA_CAPTURE_CONTENT |
true |
send prompt/response content |
conversation_id |
(none) | global gen_ai.conversation.id; per-request: verica.conversation(id) |
tags |
(none) | global tags; per-request: verica.tags([...]) |
service_name / OTEL_SERVICE_NAME |
app |
resource service.name |
debug / VERICA_DEBUG |
false |
log export errors |
Fail-open by design: if Verica is unreachable or the token is invalid, spans are
dropped and your app is never affected. Export errors are silent unless debug
is on.
Metadata
Release files for verica-observability 0.1.7
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| verica_observability-0.1.7.tar.gz | 9.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| verica_observability-0.1.7-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 17.1 kB
Release files / verica_observability-0.1.7.tar.gz
| Download URL | verica_observability-0.1.7.tar.gz |
|---|---|
| Size | 9.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
261daab83c460156e88bf964d55919a4f7bd234053856905331aeec928569886
|
|
BLAKE2b-256 checksum How to use checksums |
04f5d90af19a5a8a48735da04d6c39874cd597ae0a7797ad233fb0d81fcd5f7e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.13
|
Release files / verica_observability-0.1.7-py3-none-any.whl
| Download URL | verica_observability-0.1.7-py3-none-any.whl |
|---|---|
| Size | 7.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
57ed3641ae2ce0829588cedcf8834026f3f65eb7bf8a7d645e82162cac4a59ed
|
|
BLAKE2b-256 checksum How to use checksums |
bf4b098ce363638008018331059defa780fb403a1e4285938a7ec5a2dbe20570
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.13
|