wrap()
The one integration point. Wrap the LLM client your agent already uses;
wrap() returns the same client object, instrumented:
str
required
A stable name for this agent (for example
"support-bot"). Everything Visceral
shows you — traffic, stats, findings — is organized under it. Required.str | None
Workspace API key. Falls back to
VISCERAL_API_KEY. If no key is available,
wrap() logs a warning and returns the client uninstrumented — your agent
is never blocked on Visceral configuration.str | None
Backend URL. Falls back to
VISCERAL_BASE_URL, then
https://api.visceralai.dev.str | dict | None
Override provider auto-detection. Pass
"openai", "anthropic", "google",
or "custom" for a client Visceral doesn’t recognize (recorded metadata-only).bool
default:"False"
Opt in to applying proven cache-layout optimizations to outbound requests. Off
by default — observation only. See Optimization.
Supported providers
The provider is detected from the client type; sync and async clients are both supported.
Under the hood Visceral binds an OpenInference
instrumentor to a private tracer provider. It never touches the global
OpenTelemetry provider, so it coexists cleanly with any APM or tracing you
already run.
Calling a provider through an OpenAI-compatible endpoint (or a client Visceral
doesn’t recognize) still works with
provider_hint="custom" — calls are
recorded as metadata-only events.
Instrumenting a framework with instrument()
If your agent is built on a framework, you don’t have a single provider client
to wrap — the framework drives the model for you. instrument() is the
client-less counterpart to wrap(): name the framework and Visceral installs
its instrumentor, capturing the agent’s structure (chains, LLM calls, tools,
agents) so it flows through the same private, redacting pipeline.
bool
default:"False"
Opt in to the apply path, mirroring
wrap(apply=True): the SDK fetches your
workspace’s active optimization rules and arms the tool serve executor. Off
by default (observation only). See Optimization.dict | None
Per-tool attestations for tools the framework runs, for example
{"rag_search": {"readonly": True, "replay_safe": True}}. Same vocabulary as
@tool, plus version and freshness_seconds. Declared tools
get the visceral.tool.* contract stamped on their tool spans and, with
apply=True, become servable; undeclared tools stay observe-only.
Attestation is never inferred.
An unknown framework name raises
ValueError (a typo should be loud). Every
other failure path is fail-open, exactly as with wrap().
Annotating steps with node()
Give Visceral the shape of your agent by naming its steps. node() opens a
span around a function — sync or async:
wrap() runs, node() is a no-op.
Fail open
However you integrate, the guarantee is the same:- No API key configured → the client is returned uninstrumented, with a warning.
- Backend unreachable → calls fall through to the provider unchanged; telemetry is dropped, never queued into your latency.
- Anything in Visceral’s pipeline fails → your call proceeds as if Visceral weren’t there.