Skip to content

fix(api): map OpenInference tool definitions into real tool objects#4397

Open
mmabrouk wants to merge 2 commits into
mainfrom
fix/openinference-tool-parsing
Open

fix(api): map OpenInference tool definitions into real tool objects#4397
mmabrouk wants to merge 2 commits into
mainfrom
fix/openinference-tool-parsing

Conversation

@mmabrouk
Copy link
Copy Markdown
Member

@mmabrouk mmabrouk commented May 22, 2026

What was broken

When you open a trace span in the playground (for example a LangChain agent span that uses tools), the tools did not load. They showed up as raw, unreadable blobs instead of proper tool cards.

The cause is in how we ingest OpenInference traces. OpenInference sends each tool as llm.tools.{i}.tool.json_schema, where the value is the full OpenAI tool object encoded as a JSON string. Our adapter did a plain key rename and stored it almost as-is, so the span ended up like this:

"tools": [
  { "tool": { "json_schema": "{\"type\":\"function\",\"function\":{\"name\":\"HTTP_Request\",...}}" } }
]

The real tool object is still a string buried under tool.json_schema. The playground reads tool.type and tool.function.name, and neither exists at the top level here, so it has nothing to render.

The fix

I changed the OpenInference adapter to parse the json_schema string and store the actual tool object at ag.data.inputs.tools.{i}. Same data, correct shape:

"tools": [
  { "type": "function", "function": { "name": "HTTP_Request", "parameters": {...} } }
]

Now the playground reads tool.type and tool.function.name directly and renders the tools.

Two things worth noting:

The raw llm.tools.* attributes still stay on the span, so we lose no original data. If a json_schema ever fails to parse, we keep the raw string instead of dropping it.

This only changes how we map tools at ingestion time. Spans stored before this fix keep the old shape. You need a fresh trace to see the corrected one.

Tests

I added test_openinference_adapter.py. It covers one tool, multiple tools, the parsed {type, function} shape, the absence of the old wrapper, the unparseable fallback, and a full round trip through unmarshall_attributes (including an empty properties: {} and a two-tool list). The full OTLP unit suite (104 tests) passes and ruff is clean. I also verified it live: after restarting the API, new traces ingest tools in the correct shape and open in the playground.

@dosubot dosubot Bot added the size:M This PR changes 30-99 lines, ignoring generated files. label May 22, 2026
@vercel
Copy link
Copy Markdown

vercel Bot commented May 22, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
agenta-documentation Ready Ready Preview, Comment May 24, 2026 3:24pm

Request Review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 22, 2026

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: e6ee6ad7-8ff8-4eec-9b2b-aa6325dc269e

📥 Commits

Reviewing files that changed from the base of the PR and between b512ea4 and 1ad49e4.

📒 Files selected for processing (2)
  • api/oss/src/apis/fastapi/otlp/extractors/adapters/openinference_adapter.py
  • api/oss/tests/pytest/unit/otlp/test_openinference_adapter.py

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Tool definitions from OpenInference telemetry are now automatically parsed and structured in a standardized format.
    • Invalid tool schemas are gracefully handled and preserved.
  • Tests

    • Added comprehensive unit test suite validating tool definition extraction, parsing, and error scenarios.

Walkthrough

OpenInferenceAdapter now extracts tool definitions from JSON-encoded span attributes llm.tools.{i}.tool.json_schema and stores them as structured objects under ag.data.inputs.tools.{i}. A regex pattern detects matching attributes, parses the JSON, and falls back to the raw string on failure. The process() method runs tool extraction before generic attribute mapping and skips llm.tools.* keys during normal mapping to avoid duplication.

Changes

Tool Extraction Enhancement

Layer / File(s) Summary
Tool extraction implementation
api/oss/src/apis/fastapi/otlp/extractors/adapters/openinference_adapter.py
Imports updated to support JSON parsing; regex pattern and _extract_tools() method iterate span attributes, parse matched tool schema JSON values into structured objects (preserving raw strings on parse failure), and store under ag.data.inputs.tools.{i}; process() invokes tool extraction before generic mapping and filters out llm.tools.* keys during normal prefix mapping.
Tool extraction test coverage
api/oss/tests/pytest/unit/otlp/test_openinference_adapter.py
Establishes adapter fixture and helper functions to build test attributes and tool objects; TestToolParsing validates parsing of llm.tools.{i}.tool.json_schema into structured data and handles invalid JSON gracefully; TestSingularToolAttributes confirms standalone tool.json_schema routes to meta only; TestUnaffectedMappings verifies existing input message and invocation parameter mappings remain functional; TestRealisticSpan validates end-to-end extraction with type, inputs, prompt, and response fields; TestRegistryIntegration confirms tool parsing works through AdapterRegistry.

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: parsing OpenInference tool definitions from JSON strings into structured tool objects for correct playground rendering.
Description check ✅ Passed The description is directly related to the changeset, clearly explaining the problem (tools not loading in playground), the root cause (JSON strings not parsed), and the solution (parsing during ingestion to expose tool.type and tool.function.name).
Docstring Coverage ✅ Passed Docstring coverage is 72.22% which is sufficient. The required threshold is 60.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/openinference-tool-parsing

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@mmabrouk mmabrouk changed the title fix(api): parse OpenInference tool definitions into structured objects fix(api): map OpenInference tool definitions into real tool objects May 22, 2026
@junaway junaway changed the base branch from main to release/v0.100.1 May 22, 2026 14:34
Copy link
Copy Markdown
Contributor

@junaway junaway left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm @mmabrouk

@mmabrouk mmabrouk changed the base branch from release/v0.100.1 to main May 24, 2026 12:32
@github-actions
Copy link
Copy Markdown
Contributor

Railway Preview Environment

Preview URL https://gateway-production-fe17.up.railway.app/w
Project agenta-oss-pr-4397
Image tag pr-4397-1124a38
Status Deployed
Railway logs Open logs
Workflow logs View workflow run
Updated at 2026-05-24T15:33:30.561Z

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Backend size:M This PR changes 30-99 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants