Describe the bug
When using the Langfuse integration with a Haystack Agent (which uses ToolInvoker internally), TOOL-type observations are created with the correct type but the Langfuse-native toolCalls, toolCallNames, and toolDefinitions fields are always null. This has two practical consequences:
-
Filtering by tool call name in the Langfuse UI does not work. The "Tool Call Name" filter reads from toolCallNames, which is never populated. The tool name only appears in the observation's name string (e.g. tool_invoker - ['read_pages']), which is not indexed for that filter.
-
The TOOL observation's input contains the entire conversation message history passed to the ToolInvoker, not just the arguments of the specific tool call that was executed. This makes individual tool observations noisy and hard to read.
Example observation from a real trace (fields trimmed for brevity):
{
"type": "TOOL",
"name": "tool_invoker - ['read_pages']",
"toolDefinitions": null,
"toolCalls": null,
"toolCallNames": null
}
The same null values appear on GENERATION observations even when the LLM response contained tool call requests, so the toolCalls field is also missing there.
Root cause
In tracer.py, LangfuseSpan.set_content_tag stores the ToolInvoker input via:
self._span.update(input=messages) # `messages` is the full ChatMessage list
This writes the entire message list as a generic input blob. The Langfuse SDK fields tool_calls, tool_definitions etc. are never passed to span.update(...), so Langfuse never indexes them.
DefaultSpanHandler.handle similarly never calls span.raw_span().update(tool_calls=..., tool_definitions=...) for either ToolInvoker or ChatGenerator components.
Expected behavior
- For
TOOL observations: input should contain only the arguments of the specific tool call(s) that were executed; output should contain only the corresponding tool result(s). toolCallNames should be populated so the Langfuse filter works.
- For
GENERATION observations: when the LLM reply contains tool call requests, toolCalls should be populated with the structured call data.
To Reproduce
- Set up a Haystack
Agent with at least one tool and wire up LangfuseConnector.
- Run the agent on a query that triggers at least one tool call.
- Open the resulting trace in the Langfuse UI.
- Try to filter observations by "Tool Call Name" (no results)
Describe your environment:
- OS: Linux (Ubuntu 24.04)
- Haystack version:
haystack-ai==2.30.1
- Integration version:
langfuse-haystack==5.2.0
Describe the bug
When using the Langfuse integration with a Haystack
Agent(which usesToolInvokerinternally),TOOL-type observations are created with the correcttypebut the Langfuse-nativetoolCalls,toolCallNames, andtoolDefinitionsfields are alwaysnull. This has two practical consequences:Filtering by tool call name in the Langfuse UI does not work. The "Tool Call Name" filter reads from
toolCallNames, which is never populated. The tool name only appears in the observation'snamestring (e.g.tool_invoker - ['read_pages']), which is not indexed for that filter.The TOOL observation's
inputcontains the entire conversation message history passed to theToolInvoker, not just the arguments of the specific tool call that was executed. This makes individual tool observations noisy and hard to read.Example observation from a real trace (fields trimmed for brevity):
{ "type": "TOOL", "name": "tool_invoker - ['read_pages']", "toolDefinitions": null, "toolCalls": null, "toolCallNames": null }The same
nullvalues appear onGENERATIONobservations even when the LLM response contained tool call requests, so thetoolCallsfield is also missing there.Root cause
In
tracer.py,LangfuseSpan.set_content_tagstores theToolInvokerinput via:This writes the entire message list as a generic
inputblob. The Langfuse SDK fieldstool_calls,tool_definitionsetc. are never passed tospan.update(...), so Langfuse never indexes them.DefaultSpanHandler.handlesimilarly never callsspan.raw_span().update(tool_calls=..., tool_definitions=...)for eitherToolInvokerorChatGeneratorcomponents.Expected behavior
TOOLobservations:inputshould contain only the arguments of the specific tool call(s) that were executed;outputshould contain only the corresponding tool result(s).toolCallNamesshould be populated so the Langfuse filter works.GENERATIONobservations: when the LLM reply contains tool call requests,toolCallsshould be populated with the structured call data.To Reproduce
Agentwith at least one tool and wire upLangfuseConnector.Describe your environment:
haystack-ai==2.30.1langfuse-haystack==5.2.0