Tool calls in imported runs
Make the runs you import show their tool calls, so Agent health can read them.
Agent health reads the tools your agent calls. When imported runs show no tool call, the page gives a partial reading: runs, steps, timing, errors and models.
This page tells you how to make your tool calls visible in each source, then import again.
Why tool calls matter
Issues, tasks and the health score come from tool calls. Without them:
- Agent health shows a partial reading only.
- It infers tool calls from span shape. A step that holds no other span in at least half of its calls is marked Likely tool. A guess is not a reading.
How Ratel finds a tool call
Each import turns a run into spans. A step becomes a tool call when one of these is true:
- The source marks it as a tool. A tool span type, run type or observation type.
- A model call asked for it. A model call in the same run asked for a tool with the step's name. Ratel reads this from the model output.
Anything else is a generic step.
What to check in any source
- Tool calls are recorded, as tool spans or as tool calls in the model output.
- Content capture is on, where Ratel reads tool calls from the model output.
- Each tool span has a name and a parent. The name is the tool's name. The parent is the turn or model call that ran it.
PostHog
PostHog has no tool-call event. An $ai_span is a tool call when:
$ai_span_typeis"tool"or"mcp_tools".- Or an
$ai_generationin the same trace asked for a tool with the span's$ai_span_name. Ratel reads this from$ai_output_choices.
A trace with no tool span gets its tool calls from the model output.
Ratel infers tool calls from leaf spans, the spans that hold no other span, only when no tool is marked and the run carries no content, as in privacy mode. Agent health then says that the tool calls are inferred. A run with content and no tool call gets no inferred tool calls: its agent may call no tool.
Privacy mode removes $ai_input and $ai_output_choices. The tool calls in the model output are lost. Two fixes:
Turn privacy mode off in the client that captures your LLM calls:
posthog = Posthog(
"<ph_project_token>",
host="https://eu.i.posthog.com",
privacy_mode=False,
)const phClient = new PostHog("<ph_project_token>", {
host: "https://eu.i.posthog.com",
privacyMode: false,
});Or mark tool spans. Privacy mode keeps custom properties:
posthog.capture(
distinct_id="user_123",
event="$ai_span",
properties={
"$ai_trace_id": trace_id,
"$ai_span_id": span_id,
"$ai_parent_id": parent_id,
"$ai_span_name": tool_name,
"$ai_span_type": "tool",
"$ai_latency": latency_s,
"$ai_is_error": failed,
},
)PostHog keeps $ai_input and $ai_output_choices for 30 days only. Import a window of 30 days or less to read them.
Langfuse
An observation is a tool call when:
- Its type is
TOOLorRETRIEVER. - Or it is a
SPANwhose name matches a tool aGENERATIONin the same trace asked for, in its output.
Set the type when you create the observation: as_type="tool" in Python, asType: "tool" in TypeScript. Framework integrations set it for you. See Observation types.
LangSmith
A run is a tool call when its run_type is tool or retriever. LangChain tools set it for you. With @traceable, set run_type="tool". See Run types.
Braintrust
A span is a tool call when its span_attributes.type is tool. Ratel reads the arguments from the span input. Scorer spans are not read.
Postgres
Every row your query returns is a tool call. It needs tool_name, with run_id and started_at.
OpenTelemetry
Sending spans to Ratel, not importing them? Tool calls are execute_tool spans. See Send telemetry.
Import again
- Ship the change and let your agent run for a few days.
- Open Agent health and click Import past runs.
- Pick your source and a window that starts after the change.
Imports are idempotent: runs that are already stored are written again, not duplicated.