Skip to content

Comments

feat: add support for ToolSpan attributes#475

Open
calebe94 wants to merge 5 commits intomainfrom
feature/54704-support-tool-spans
Open

feat: add support for ToolSpan attributes#475
calebe94 wants to merge 5 commits intomainfrom
feature/54704-support-tool-spans

Conversation

@calebe94
Copy link

@calebe94 calebe94 commented Feb 11, 2026

Shortcut:

Description:

This change adds support for setting additional attributes on OpenTelemetry spans when processing ToolSpan objects from the galileo-core library.

Specifically, the following attributes are now set on the span:

  • gen_ai.input.messages: JSON array with the tool's input data
  • gen_ai.output.messages: JSON array with the tool's output data (if available)
  • gen_ai.tool.call_id: the unique identifier for the tool call (if available)

This provides more detailed observability into the usage of AI/ML tools within the Galileo platform.

The following ToolSpan fields are now mapped to OpenTelemetry semantic convention attributes:

ToolSpan Field OTel Attribute Type Description
input gen_ai.input.messages JSON string Array of input messages as JSON
output gen_ai.output.messages JSON string Output message as JSON
tool_call_id gen_ai.tool.call_id string Tool call identifier

Attribute Format Details:

gen_ai.input.messages (always set):

[{"role": "tool", "content": "<input_string>"}]
  • JSON array with single message object
  • Role: "tool" (identifies this as a tool/function call)
  • Content: Contains actual input string from ToolSpan.input

gen_ai.output.messages (conditional):

[{"role": "tool", "content": "<output_string>"}]
  • Only set if ToolSpan.output is not None
  • Same structure as input: JSON array with single message object
  • Role: "tool" indicates this is tool output
  • Content: Contains actual output string from ToolSpan.output

gen_ai.tool.call_id (conditional):

"<tool_call_id_string>"
  • Only set if ToolSpan.tool_call_id is not None
  • Direct string value (not JSON-serialized)
  • Identifies which tool invocation this span represents

Tests:

  • Unit Tests Added
  • E2E Test Added (if it's a user-facing feature, or fixing a bug)

Evidences

I've created a demo script called tool_span_demo.py to test this changes. To run this script we need to export a couple of credentials:

export GALILEO_API_KEY="your-api-key-here"
export GALILEO_CONSOLE_URL="https://your-galileo-console-url.com"
export GALILEO_PROJECT="your-project-name"
export GALILEO_LOG_STREAM="your-log-stream-name"

Inside the galileo-python directory I've started a new virtualenvironment so we can install the project locally:

# Create and activate virtual environment
python3 -m venv venv
source venv/bin/activate

# Or using pyenv
pyenv local 3.12.12
pyenv shell

Then I installed the dependencies:

# Install galileo-python package in editable mode
pip install -e .

# Or using poetry
poetry install --all-extras

# Install OpenTelemetry dependencies separately if needed
pip install opentelemetry-sdk opentelemetry-api opentelemetry-exporter-otlp galileo-sdk galileo

After all this, I've ran the tool_span_demo.py Python script and got this as a result:

source .env && python examples/tool_span_demo.py
2026-02-13 15:48:47 - __main__ - INFO - 
================================================================================
2026-02-13 15:48:47 - __main__ - INFO - ToolSpan OpenTelemetry Attribute Mapping Demo
2026-02-13 15:48:47 - __main__ - INFO - Feature: 54704 - Support Tool Spans
2026-02-13 15:48:47 - __main__ - INFO - ================================================================================

2026-02-13 15:48:47 - __main__ - INFO - Setting up Galileo OpenTelemetry integration
2026-02-13 15:48:48 - httpx - INFO - HTTP Request: GET https://api-edimar-calebe-test.gcp-dev.galileo.ai/healthcheck "HTTP/1.1 200 OK"
2026-02-13 15:48:49 - httpx - INFO - HTTP Request: POST https://api-edimar-calebe-test.gcp-dev.galileo.ai/login/api_key "HTTP/1.1 200 OK"
2026-02-13 15:48:49 - httpx - INFO - HTTP Request: GET https://api-edimar-calebe-test.gcp-dev.galileo.ai/current_user "HTTP/1.1 200 OK"
2026-02-13 15:48:49 - __main__ - INFO - Galileo OpenTelemetry integration configured
2026-02-13 15:48:49 - __main__ - INFO - Galileo OpenTelemetry integration initialized
2026-02-13 15:48:49 - __main__ - INFO -   Console URL: https://api-edimar-calebe-test.gcp-dev.galileo.ai
2026-02-13 15:48:49 - __main__ - INFO -   Project: test
2026-02-13 15:48:49 - __main__ - INFO -   Log Stream: default
2026-02-13 15:48:49 - __main__ - INFO - 
2026-02-13 15:48:49 - __main__ - INFO - Running Demo 1: ToolSpan with All Fields
2026-02-13 15:48:49 - __main__ - INFO - ✓ ToolSpan with all fields demo completed
2026-02-13 15:48:49 - __main__ - INFO - Running Demo 2: ToolSpan with Input Only
2026-02-13 15:48:49 - __main__ - INFO - ✓ ToolSpan with input only demo completed
2026-02-13 15:48:49 - __main__ - INFO - Running Demo 3: ToolSpan with Output but No tool_call_id
2026-02-13 15:48:49 - __main__ - INFO - ✓ ToolSpan with output but no tool_call_id demo completed
2026-02-13 15:48:49 - __main__ - INFO - Running Demo 4: Nested Tool Spans (Real-world Agent)
2026-02-13 15:48:49 - __main__ - INFO -     Tool call: get_weather
2026-02-13 15:48:49 - __main__ - INFO -     Tool result: 22°C, sunny
2026-02-13 15:48:49 - __main__ - INFO -     Tool call: get_flights
2026-02-13 15:48:49 - __main__ - INFO -     Tool result: Found 1 flight
2026-02-13 15:48:49 - __main__ - INFO -     Tool call: book_hotel
2026-02-13 15:48:50 - __main__ - INFO -     Tool result: Reservation confirmed
2026-02-13 15:48:50 - __main__ - INFO - ✓ Nested tool spans demo completed
2026-02-13 15:48:50 - __main__ - INFO - Running Demo 5: OpenAI Tool Calling Integration
2026-02-13 15:48:50 - __main__ - WARNING - OpenAI not installed, skipping this demo
2026-02-13 15:48:50 - __main__ - INFO - Install with: pip install openai
2026-02-13 15:48:50 - __main__ - INFO - 
================================================================================
2026-02-13 15:48:50 - __main__ - INFO - All demos completed successfully!
2026-02-13 15:48:50 - __main__ - INFO - ================================================================================
2026-02-13 15:48:50 - __main__ - INFO - 
To use in production:
2026-02-13 15:48:50 - __main__ - INFO -   1. Set GALILEO_* environment variables
2026-02-13 15:48:50 - __main__ - INFO -   2. Initialize your OpenTelemetry provider
2026-02-13 15:48:50 - __main__ - INFO -   3. Use start_galileo_span() with ToolSpan instances
2026-02-13 15:48:50 - __main__ - INFO -   4. Spans are automatically exported to Galileo
2026-02-13 15:48:50 - __main__ - INFO - 
See src/galileo/otel.py for the implementation:
2026-02-13 15:48:50 - __main__ - INFO -   - _set_tool_span_attributes() handles serialization
2026-02-13 15:48:50 - __main__ - INFO -   - start_galileo_span() dispatches to the correct handler
2026-02-13 15:48:50 - __main__ - INFO - 
🔄 Flushing spans to Galileo Console...
2026-02-13 15:48:51 - __main__ - INFO - ✅ Spans flushed successfully
2026-02-13 15:48:51 - __main__ - INFO - 
📊 Check your Galileo Console to view the exported traces:
2026-02-13 15:48:51 - __main__ - INFO -    URL: https://api-edimar-calebe-test.gcp-dev.galileo.ai
2026-02-13 15:48:51 - __main__ - INFO -    Project: test
2026-02-13 15:48:51 - __main__ - INFO -    Log Stream: default 

What it demonstrates:
✅ All ToolSpan fields correctly map to OTel semantic conventions
✅ Manual span creation works via start_galileo_span()
✅ Conditional attribute setting for None values
✅ Comprehensive demo script provided with 5 test cases
✅ Unit tests covering all scenarios (3 test cases, all passing)
✅ Documentation and troubleshooting guide created
✅ OpenTelemetry semantic compliance verified

@calebe94 calebe94 self-assigned this Feb 11, 2026
@codecov
Copy link

codecov bot commented Feb 11, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 82.71%. Comparing base (114e24d) to head (94a180c).

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #475      +/-   ##
==========================================
+ Coverage   82.61%   82.71%   +0.09%     
==========================================
  Files          96       96              
  Lines        9147     9159      +12     
==========================================
+ Hits         7557     7576      +19     
+ Misses       1590     1583       -7     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@calebe94 calebe94 marked this pull request as ready for review February 13, 2026 19:22
@calebe94 calebe94 requested a review from a team as a code owner February 13, 2026 19:22
)


def _set_tool_span_attributes(span: trace.Span, galileo_span: ToolSpan) -> None:
Copy link
Contributor

Choose a reason for hiding this comment

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

Please add:

gen_ai.tool.name
gen_ai.tool.description
gen_ai.tool.call.arguments
gen_ai.tool.call.result

Reference: https://opentelemetry.io/docs/specs/semconv/gen-ai/gen-ai-spans/#execute-tool-span

Copy link
Contributor

Choose a reason for hiding this comment

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

We will also need gen_ai.operation.name

Copy link
Contributor

Choose a reason for hiding this comment

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

Commit 3f3a0f9 addressed this comment by adding several of the requested GenAI tool span semantic convention attributes in _set_tool_span_attributes, including gen_ai.tool.name, gen_ai.tool.call.arguments, and gen_ai.tool.call.result, and by updating the tool call id attribute to gen_ai.tool.call.id.

This change adds support for setting additional attributes on OpenTelemetry spans when processing ToolSpan objects from the galileo-core library.

Specifically, the following attributes are now set on the span:
- gen_ai.input.messages: JSON array with the tool's input data
- gen_ai.output.messages: JSON array with the tool's output data (if available)
- gen_ai.tool.call_id: the unique identifier for the tool call (if available)

This provides more detailed observability into the usage of AI/ML tools within the Galileo platform.
This change adds two new test cases for the start_galileo_span context manager:

1. Test that start_galileo_span correctly sets the expected attributes on the generated OpenTelemetry span when provided a fully populated ToolSpan.
2. Test that start_galileo_span handles a ToolSpan with a None output and tool_call_id gracefully.

The tests ensure the context manager is properly dispatching the ToolSpan attributes to the underlying OpenTelemetry span, which is crucial for providing meaningful tracing data.
- Renames `gen_ai.tool.call_id` to `gen_ai.tool.call.id` for consistency
- Adds `gen_ai.tool.call.arguments` and `gen_ai.tool.call.result` attributes
- Updates tests to cover the new attribute set
This change adds the 'gen_ai.operation.name' attribute to the OpenTelemetry spans created for tool execution. The operation name is set to 'execute_tool' to provide more context about the purpose of the span.
@calebe94 calebe94 force-pushed the feature/54704-support-tool-spans branch from 3f3a0f9 to 94a180c Compare February 17, 2026 18:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants