PostHog / PostHog/posthog

Pydantic AI v3+ tool spans show blank input/output in Conversation: map gen_ai.tool.call.arguments/result

Open Beginner friendly
#95,068 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

ai-observability bug team/ai-observability
Dominant language
Python
Stars
39.9k
Forks
3.4k
Avg merge
7h 27m
Merged PRs (30d)
222

Description

Bug Description

Summary

  • Pydantic AI tool spans are successfully ingested by PostHog, but their input and output are blank in the Conversation tab.
  • The span’s Raw tab contains the current OpenTelemetry GenAI tool attributes:
    • gen_ai.tool.call.arguments
    • gen_ai.tool.call.result

However, Conversation displays which affects tool spans only. Model-generation spans in the same trace displaytheir input and output normally.

Image Image

Expected behavior

For Pydantic AI v3+ tool spans, PostHog should normalize:

  • gen_ai.tool.call.arguments$ai_input_state
  • gen_ai.tool.call.result$ai_output_state

The existing Conversation view should then render the tool arguments and tool result.

Legacy Pydantic AI v2 fields should continue to work:

  • tool_arguments
  • tool_response

Actual behavior

PostHog receives the dotted Pydantic AI / OpenTelemetry fields and leaves them visible in Raw, but does not create $ai_input_state or $ai_output_state.

The Conversation view reads those normalized state properties for $ai_span events, so it shows No input and No output.

Why this appears to be a compatibility gap

Pydantic AI defaults to instrumentation format v5. v3+ emits the current
OpenTelemetry-style names:

  • gen_ai.tool.call.arguments
  • gen_ai.tool.call.result

The Pydantic AI OTel middleware currently handles only the older flat
Pydantic v2 keys:

  • tool_arguments
  • tool_response

Relevant PostHog source:

How to reproduce

  1. Configure Pydantic AI instrumentation with a PostHog OpenTelemetry exporter. Do not set InstrumentationSettings.version, so Pydantic AI uses its default instrumentation format v5.
  2. Run an agent that calls a function tool with content capture enabled.
  3. Open the resulting trace in PostHog AI Observability.
  4. Select the tool span.
  5. In the Raw tab, observe both:
    • gen_ai.tool.call.arguments
    • gen_ai.tool.call.result
  6. Switch to the Conversation tab.
  7. Observe that the span shows:
    • Input: No input
    • Output: No output

Additional context

The raw attributes prove this is not an exporter or include_content problem:
the tool arguments and result have already reached PostHog.

Suggested mapper behavior:

const rawArgs =
    props['gen_ai.tool.call.arguments'] ?? props['tool_arguments']

const rawResult =
    props['gen_ai.tool.call.result'] ?? props['tool_response']

PostHog should preserve its existing JSON parsing and write the resolved values to $ai_input_state and $ai_output_state.

Suggested regression coverage:

  1. Legacy Pydantic AI v2:
    tool_arguments / tool_response
  2. Current Pydantic AI v3+ and default v5:
    gen_ai.tool.call.arguments / gen_ai.tool.call.result
  3. JSON-string arguments, JSON-string results, and plain-text results.

I did not find an existing public PostHog issue for this exact tool-span mapping problem.

Debug info
- [x] PostHog Cloud, region and project ID: EU, project ID: <fill in your project ID>
- [ ] PostHog Hobby self-hosted with `docker compose`, version/commit: N/A
- [ ] You’re self-hosted with Kubernetes: N/A

Client environment:
- posthog-python: 7.45.1
- pydantic-ai: 2.36.0
- opentelemetry-sdk: 1.44.0
- Pydantic AI instrumentation format: v5 default
- Event transport: OpenTelemetry to PostHog AI endpoint
- Tool arguments/results are visible in the PostHog Raw tab

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in nodejs/src/ingestion/pipelines/ai/otel/middleware/pydantic-ai.ts and inspect how tool_arguments and tool_response are mapped into normalized AI state properties. Add regression coverage for legacy and gen_ai.tool.call.arguments/result attributes, including JSON-string and plain-text values, then run the relevant middleware tests and confirm Conversation displays the tool input and output.

Written by the indexing model from the issue text.

Assessment

Tech stack
python, typescript
Domain
ai, backend, observability
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
84/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.