auto_instrument()¶
Automatically patches all installed LLM libraries to emit OpenInference-compatible spans. Libraries that are not installed are silently skipped.
Signature¶
interface AutoInstrumentOptions {
tracerProvider?: TracerProvider;
suppressErrors?: boolean;
includeLibraries?: string[];
excludeLibraries?: string[];
/** Where to look for the instrumentation packages (see below). */
resolveFrom?: string;
}
function autoInstrument(options?: AutoInstrumentOptions): Record<string, InstrumentationStatus>
The TypeScript SDK also provides an async variant:
async function autoInstrumentAsync(
options?: AutoInstrumentOptions,
): Promise<Record<string, InstrumentationStatus>>
Where the instrumentors are looked for. The SDK resolves each @arizeai/… package from its
own location first and then from the process's working directory, which covers both an ordinary
install and a strict pnpm store (where the SDK's node_modules cannot see the app's). If your
layout is stranger than that, pass resolveFrom — the directory of the project whose
dependencies should be used.
Versions before 1.22.0
autoInstrument() returned "not_installed" for every library, including installed
ones, and the agent then ran with no LLM spans at all — no model, no tokens, no cost, and
nothing for the judge to score. If you are on an older version and your traces show no model
calls, upgrade: nothing about your dependencies was wrong.
Parameters¶
| Parameter | Type | Default | Description |
|---|---|---|---|
tracer_provider |
TracerProvider \| None |
None |
Custom TracerProvider to use. When None, uses the global provider set by register(). |
suppress_errors |
bool |
True |
When True, instrumentation errors are logged as warnings instead of raising exceptions. |
include_libraries |
list[str] \| None |
None |
If provided, only instrument these libraries (allowlist). Library names must match the names in the Supported Libraries table. |
exclude_libraries |
list[str] \| None |
None |
If provided, skip these libraries (blocklist). |
All parameters are keyword-only (enforced by *).
include_libraries vs exclude_libraries
These parameters are mutually exclusive in practice. If include_libraries is set, libraries not in the list are simply not attempted (they do not appear in the results at all). If exclude_libraries is set, excluded libraries appear in results with status "excluded".
Returns¶
dict[str, str] -- A dictionary mapping each library name to its instrumentation status.
Status Values¶
| Status | Meaning |
|---|---|
"success" |
Library was found and successfully instrumented. |
"not_installed" |
The OpenInference instrumentor package for this library is not installed (for pydantic_ai and google_adk, the framework itself). |
"already_instrumented" |
Library was already instrumented (e.g., by a previous call). |
"error" |
Instrumentation was attempted but failed. Check logs for details. |
"excluded" |
Library was skipped because it is in exclude_libraries. |
Semantic conventions¶
By default, instrumented spans carry OpenInference attributes: LLM messages are emitted as
structured, indexed keys — llm.input_messages.{i}.message.role / .content, plus tool calls
under llm.output_messages.{i}.message.tool_calls.{j}.tool_call.*.
The SDK can additionally emit the same messages in the OTel GenAI latest experimental
shape — gen_ai.input.messages, gen_ai.output.messages, gen_ai.system_instructions — the
normalised, cross-vendor representation. This is opt-in and additive (OpenInference attributes
are preserved); enable it on register():
import coalex
# via argument…
coalex.register(endpoint="https://traces.coalex.ai", api_key="your-key", genai_semconv=True)
# …or via environment variable (no code change)
# COALEX_GENAI_SEMCONV=1
Each LLM span then also carries, for example:
{
"gen_ai.system_instructions": [{"type": "text", "content": "You are a concise assistant."}],
"gen_ai.input.messages": [{"role": "user", "parts": [{"type": "text", "content": "Weather in Lisbon?"}]}],
"gen_ai.output.messages": [{"role": "assistant", "parts": [
{"type": "tool_call", "id": "call_1", "name": "get_weather", "arguments": {"city": "Lisbon"}}
]}]
}
Why not OTEL_SEMCONV_STABILITY_OPT_IN?
The standard OTel opt-in OTEL_SEMCONV_STABILITY_OPT_IN=gen_ai_latest_experimental is read only
by native OTel instrumentations — it has no effect on OpenInference. genai_semconv derives
the gen_ai.* attributes from the OpenInference messages instead, so you get the new conventions
without changing instrumentation libraries.
Supported Libraries¶
auto_instrument() supports the following 16 frameworks: 14 through an OpenInference instrumentor,
and pydantic_ai and google_adk, which write their own spans.
| Library Name | Instrumentor Package | Description |
|---|---|---|
openai |
openinference-instrumentation-openai |
OpenAI SDK |
llamaindex |
openinference-instrumentation-llama-index |
LlamaIndex |
langchain |
openinference-instrumentation-langchain |
LangChain |
google_genai |
openinference-instrumentation-google-genai |
Google Generative AI (Gemini) |
vertexai |
openinference-instrumentation-vertexai |
Google Vertex AI |
bedrock |
openinference-instrumentation-bedrock |
AWS Bedrock |
anthropic |
openinference-instrumentation-anthropic |
Anthropic Claude |
mistralai |
openinference-instrumentation-mistralai |
Mistral AI |
groq |
openinference-instrumentation-groq |
Groq |
litellm |
openinference-instrumentation-litellm |
LiteLLM |
dspy |
openinference-instrumentation-dspy |
DSPy |
crewai |
openinference-instrumentation-crewai |
CrewAI |
haystack |
openinference-instrumentation-haystack |
Haystack |
instructor |
openinference-instrumentation-instructor |
Instructor |
guardrails |
openinference-instrumentation-guardrails |
Guardrails |
pydantic_ai |
none: Pydantic AI writes its own spans | Pydantic AI |
google_adk |
none: Google ADK writes its own spans | Google Agent Development Kit (ADK) |
pydantic_ai needs no instrumentor package and no extra: with pydantic-ai installed,
auto_instrument() calls Agent.instrument_all(...), and the agent run, every model request and
every tool call become spans. Their prompts, responses and tool arguments and results are exported
unless you pass capture_content=False to register(). A default you set yourself
with Agent.instrument_all(...) is kept and the status is "already_instrumented", and an agent
with its own instrument setting or Instrumentation capability keeps that too.
mistralai, groq, litellm, dspy and crewai are not declared as extras in
packages/sdk-python/pyproject.toml, so pip install "coalex[mistralai]" fails. Install only the
extras that package declares.
Google ADK¶
google_adk needs no instrumentor package and no extra, and the SDK does not import ADK. ADK
(google-adk) writes its own spans, with the model and the tokens, and auto_instrument() only sets
the environment variables that make ADK write its GenAI content on them (the messages, system
instructions, tool definitions and tool arguments and results). The status is "success" when
google-adk is installed and "not_installed" when it is not, and nothing is set in that case.
Call it before the agent runs: ADK reads the variables when it builds each run's telemetry config.
capture_content of register() |
Variable set | Value | When |
|---|---|---|---|
True (the default, also before register()) |
OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT |
SPAN_ONLY |
always |
True |
OTEL_SEMCONV_STABILITY_OPT_IN |
gen_ai_latest_experimental |
ADK older than 2.13.0 only |
False |
ADK_CAPTURE_MESSAGE_CONTENT_IN_SPANS |
false |
always; the two variables above are not set |
A variable you have set yourself is kept, whatever its value: OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT=NO_CONTENT
keeps ADK from writing content even with capture_content=True. Calling auto_instrument() again
changes nothing. A RunConfig(telemetry=...) passed to a run overrides the environment.
With capture_content=False, register() also removes the keys ADK's own tracing writes its content
under, whatever the variables say: gcp.vertex.agent.llm_request, llm_response, tool_call_args,
tool_response and data. The event, invocation and session ids under the same prefix stay.
ADK older than 1.28 has no GenAI content: nothing the call sets helps, and its spans still carry the model and the tokens.
Install Extras¶
The Coalex SDK provides install extras to pull in the correct OpenInference instrumentor packages:
# All supported frameworks
pip install coalex[auto-instrument]
# Individual frameworks
pip install coalex[openai]
pip install coalex[langchain]
pip install coalex[llamaindex]
pip install coalex[google-genai]
pip install coalex[vertexai]
pip install coalex[bedrock]
pip install coalex[anthropic]
# Multiple frameworks
pip install coalex[openai,langchain]
Install the OpenInference instrumentor packages alongside the SDK:
# OpenAI
npm install @coalex-ai/sdk @arizeai/openinference-instrumentation-openai
# LangChain
npm install @coalex-ai/sdk @arizeai/openinference-instrumentation-langchain
# Anthropic
npm install @coalex-ai/sdk @arizeai/openinference-instrumentation-anthropic
# Multiple frameworks
npm install @coalex-ai/sdk \
@arizeai/openinference-instrumentation-openai \
@arizeai/openinference-instrumentation-langchain
Minimal installs for production
In production, prefer installing only the extras you need. The auto-instrument extra pulls in instrumentors for OpenAI, LangChain, LlamaIndex, Vertex AI, Bedrock, and Anthropic -- which may be more than you use.
Examples¶
Instrument everything available¶
import coalex
coalex.register(endpoint="https://traces.coalex.ai", api_key="your-key")
results = coalex.auto_instrument()
print(results)
# {
# "openai": "success",
# "llamaindex": "not_installed",
# "langchain": "not_installed",
# "vertexai": "not_installed",
# "bedrock": "not_installed",
# "anthropic": "success",
# "mistralai": "not_installed",
# "groq": "not_installed",
# "litellm": "not_installed",
# "dspy": "not_installed",
# "crewai": "not_installed",
# "haystack": "not_installed",
# "instructor": "not_installed",
# "guardrails": "not_installed",
# }
Allowlist specific libraries¶
Exclude a library¶
Custom TracerProvider¶
Convenience Functions¶
For cases where you only want to instrument a single library, the SDK provides convenience functions. Each returns True on success and False on failure.
import coalex
coalex.instrument_openai() # -> bool
coalex.instrument_langchain() # -> bool
coalex.instrument_llamaindex() # -> bool
coalex.instrument_google_genai() # -> bool
coalex.instrument_vertexai() # -> bool
coalex.instrument_bedrock() # -> bool
coalex.instrument_anthropic() # -> bool
All convenience functions accept an optional tracer_provider parameter:
Notes¶
auto_instrument()should be called afterregister()so the globalTracerProvideris already configured. If called withoutregister()and without atracer_providerargument, instrumented libraries use the default no-op provider.- Calling
auto_instrument()multiple times is safe -- already-instrumented libraries return"already_instrumented", andgoogle_adkreturns"success"again with the environment as the first call left it. - Python: The function is synchronous and returns immediately after patching.
- TypeScript: Use
autoInstrumentAsync()in ESM projects whererequire()is not available. The syncautoInstrument()variant usesrequire()internally and may not work in pure ESM environments. - TypeScript and LangChain.js: both variants capture LangChain in a CommonJS app and in an ESM app, and report
langchainassuccesson the first call. LangChain.js versions lists the proven lines and the Node version the sync variant needs in an ESM app. - For custom pipeline steps that are not covered by auto-instrumentation (e.g., custom retrievers, rerankers), use the extension decorators.
API Reference¶
coalex.auto_instrument ¶
Auto-instrumentation for LLM frameworks: OpenInference instrumentors, and the own tracing of Pydantic AI and ADK.
Functions:¶
auto_instrument ¶
auto_instrument(
tracer_provider: TracerProvider | None = None,
suppress_errors: bool = True,
include_libraries: list[str] | None = None,
exclude_libraries: list[str] | None = None,
) -> dict[str, str]
Automatically instrument all available LLM libraries.
Only libraries actually installed are instrumented — missing libraries
are silently skipped. Most go through an OpenInference instrumentor. Pydantic AI writes its own
spans, so its tracing is switched on instead, with include_content following the
capture_content of :func:coalex.register. Google ADK writes its own spans too, and
google_adk sets the environment variables that make it write its GenAI content, again
following capture_content; no instrumentor is installed for it.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tracer_provider
|
TracerProvider | None
|
TracerProvider to use (defaults to global provider). |
None
|
suppress_errors
|
bool
|
If True, log errors instead of raising (default: True). |
True
|
include_libraries
|
list[str] | None
|
If provided, only instrument these libraries. |
None
|
exclude_libraries
|
list[str] | None
|
If provided, skip these libraries. |
None
|
Returns:
| Type | Description |
|---|---|
dict[str, str]
|
Dictionary mapping library name to instrumentation status |
dict[str, str]
|
("success", "not_installed", "already_instrumented", "error", "excluded"). |
Source code in coalex/auto_instrument.py
instrument_openai ¶
instrument_llamaindex ¶
instrument_langchain ¶
instrument_google_genai ¶
Instrument Google GenAI (google-genai SDK) specifically.