Skip to main content
Knowing which tools a model could have called is as important as knowing which ones it did call: it is what lets you tell “the agent never had a refund tool” from “the agent had it and chose not to use it”. Raindrop records that list on every model-call span under one attribute, ai.prompt.tools, with the same shape across every SDK and integration.

The attribute

ai.prompt.tools is an OpenTelemetry string array. Each element is one JSON document describing one tool the model was given for that call:
  • Function tools carry name, description and the JSON Schema the model saw as inputSchema — properties, types, enums, required and per-field descriptions are recorded as given, never trimmed or invented. Framework schemas (Zod, TypeBox, Pydantic, …) are converted to JSON Schema the same way the framework converts them for the provider.
  • Provider-defined tools (web search, code execution, MCP toolsets, computer use, …) are recorded as {"type": "provider-defined", "id": ..., "name": ..., "args": {...}}. The provider owns their schema, so none is invented.
Three states are distinguishable downstream:

Exact capture vs. catalogs

Most integrations sit on the request path and record the exact list the model received on that call. A few only see a registry or agent definition that may overstate what one particular request carried. Those record the list they can see and add a second attribute, ai.prompt.tools.source, naming where it came from (for example "opencode.tool.list", "mastra.agent.tools", "agent.config", "agno.agent.tools", "crewai.agent.tools"), so a catalog is never mistaken for exact capture. An explicit override (below) never carries source.

Content gating

Tool definitions are prompt content. They follow the same switch as ai.prompt.messages in every SDK: recordInputs: false / captureContent: false in the TypeScript integrations that expose one, TRACELOOP_TRACE_CONTENT=false in Python. With content capture off, the attribute is never recorded — it is absent, not []. The managed-agents packages (@raindrop-ai/claude-managed-agents, @raindrop-ai/openai-managed-agents) have no prompt-content switch of their own: they record the agent catalog whenever tracing is enabled, and the only way to withhold it is a tools: [] override.

Size

The full catalog is recorded on every model span, uncapped, because a truncated tool list defeats the purpose. Agents with very large MCP tool sets add a few tens of KB per model call; turn content capture off, or pass a smaller tools override, if that matters for you.

Overriding the list

Every integration accepts a tools option that replaces whatever it would have inferred (there is no merging). Use it when the integration cannot see the tool list, or when you want to record a different one; tools: [] records an explicitly empty catalog. Declarations may be passed in any shape the SDK recognizes — the canonical document above, OpenAI {"type": "function", "function": {...}}, Anthropic {"name", "description", "input_schema"}, plain {name, description, parameters}, or the framework’s own tool objects where the integration accepts them.
The override is stamped only on model spans (spans that carry llm.request.type, gen_ai.request.model, llm.request.model or ai.model.id), never on tool-call, task or interaction spans.

What each integration captures

“Exact” means the integration sees the request the model received on every call. “Catalog” means it records a registry or agent definition and marks the span with ai.prompt.tools.source. “Override only” means the integration never sees the model request, so the attribute is absent unless you pass tools.

TypeScript

Python

Sending OTLP directly

If you export spans to Raindrop yourself, set ai.prompt.tools on your model spans as a string array of the documents above (one JSON string per tool). Add ai.prompt.tools.source when the list is a catalog rather than the exact per-request set. See OpenTelemetry.

Reading it back

The attribute is stored on the span as sent. It is available on every model span in the trace view and through the Query API trace endpoints, and agent replays use it to reconstruct the tools an agent had available. Replay reads the list as recorded and does not consult ai.prompt.tools.source, so for catalog-based integrations it may offer tools the model never received on that particular call.