Skip to content

Adopt shared Role enum across instrumentations - #575

Merged
lmolkova merged 4 commits into
open-telemetry:mainfrom
sfc-gh-zeningchen:feat/gh-534-shared-role-enum
Sep 3, 2026
Merged

Adopt shared Role enum across instrumentations#575
lmolkova merged 4 commits into
open-telemetry:mainfrom
sfc-gh-zeningchen:feat/gh-534-shared-role-enum

Conversation

@sfc-gh-zeningchen

@sfc-gh-zeningchen sfc-gh-zeningchen commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Description

The GenAI message schemas constrain role to system, user, assistant, and tool, but they are not code-generated into opentelemetry-semconv, so each instrumentation spelled the values out its own way: a private Role enum in google-genai, a local _ROLE_MAP in smolagents, bare literals elsewhere. The schemas accept any string, so an off-spec value passes weaver and only surfaces downstream, where role drives the role badge and the System/User/Assistant/Tool filter — that is how "role": "AIMessageChunk" reached langchain spans in #504.

#506 added a shared Role enum to opentelemetry-util-genai and adopted it in langchain. This PR adopts it in google-genai (deleting its private copy), smolagents, openai, agno, qwen-agent, bedrock, portkey, and llama-index; anthropic is passthrough-only and is unchanged. Only roles an instrumentation picks itself change — provider-supplied roles still pass through, and the enum values are identical to the literals they replace, so there is no behaviour change.

Portkey's opentelemetry-util-genai floor moves to 1.2b0.dev, where Role was added, matching every other package that depends on it; its oldest tox env gains the same -e util/opentelemetry-util-genai workaround the others already carry.

Fixes #534.

Type of change

  • Maintenance (non-breaking refactor, no behaviour change)

How has this been tested?

No new tests: the change is a literal-for-enum substitution, and the existing suites already assert the emitted role values, so they are the regression check.

  • latest suites pass for google-genai, smolagents, agno, qwen-agent, portkey, openai, and llama-index
  • bedrock's latest suite fails identically on main and on this branch (15 pre-existing VCR failures), so it is unaffected
  • tox -e ruff clean
  • tox -e changelog-preview renders the portkey entry

Checklist

  • Followed the style guidelines of this project
  • Changelog updated if the change requires an entry

Replace hardcoded role literals and google-genai's private `Role` enum with
`opentelemetry.util.genai.types.Role` in every instrumentation that emits a
role it controls: google-genai, smolagents, openai, agno, qwen-agent, bedrock,
portkey, and llama-index. Anthropic is passthrough-only and unchanged.

Bump portkey's `opentelemetry-util-genai` floor to 1.2b0.dev, where `Role` was
added, matching every other package that uses it; its `oldest` test env gains
the same `-e util/opentelemetry-util-genai` workaround the others already
carry.

No behaviour change: the enum values are identical to the literals they
replace.

Assisted-by: Claude Opus 5
@opentelemetry-pr-dashboard

opentelemetry-pr-dashboard Bot commented Sep 2, 2026

Copy link
Copy Markdown

Pull request dashboard status

Merged · refreshed 2026-09-03 20:22 UTC

Status above doesn't look right?
  • Anything look wrong? Report it with what you expected; it helps us improve the dashboard.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟢 Approval recommended

The changes consistently adopt the shared Role enum as intended, with only a minor comment/doc mismatch noted in Portkey’s oldest requirements file.

Pull request overview

This PR standardizes GenAI message role values produced by instrumentations by replacing local/hardcoded role literals (including google-genai’s private enum) with the shared opentelemetry.util.genai.types.Role enum, keeping provider-supplied roles as passthrough.

Changes:

  • Replace synthesized role literals ("user", "assistant", etc.) with Role.<...>.value across multiple instrumentations.
  • Remove google-genai’s private Role enum in favor of the shared util enum.
  • Bump Portkey’s opentelemetry-util-genai dependency floor and align its oldest-test env with the repo’s existing “install util from workspace” pattern.
File summaries
File Description
instrumentation/opentelemetry-instrumentation-google-genai/src/opentelemetry/instrumentation/google_genai/message.py Drops local Role enum and maps SDK roles to shared Role values.
instrumentation/opentelemetry-instrumentation-google-genai/src/opentelemetry/instrumentation/google_genai/interactions.py Uses shared Role for synthesized input/output messages.
instrumentation/opentelemetry-instrumentation-genai-smolagents/src/opentelemetry/instrumentation/genai/smolagents/patch.py Uses shared Role for streamed output message role default.
instrumentation/opentelemetry-instrumentation-genai-smolagents/src/opentelemetry/instrumentation/genai/smolagents/_messages.py Uses shared Role in role normalization/defaults and mapping.
instrumentation/opentelemetry-instrumentation-genai-qwen-agent/src/opentelemetry/instrumentation/genai/qwen_agent/utils.py Uses shared Role for default input role and output role.
instrumentation/opentelemetry-instrumentation-genai-portkey/tests/requirements.oldest.txt Adds editable util install for oldest env until util release is published.
instrumentation/opentelemetry-instrumentation-genai-portkey/src/opentelemetry/instrumentation/genai/portkey/wrappers.py Uses shared Role for synthesized assistant output messages.
instrumentation/opentelemetry-instrumentation-genai-portkey/src/opentelemetry/instrumentation/genai/portkey/utils.py Uses shared Role for synthesized assistant role defaults.
instrumentation/opentelemetry-instrumentation-genai-portkey/pyproject.toml Raises opentelemetry-util-genai floor to include Role.
instrumentation/opentelemetry-instrumentation-genai-openai/src/opentelemetry/instrumentation/genai/openai/response_extractors.py Uses shared Role for synthesized input/output messages.
instrumentation/opentelemetry-instrumentation-genai-openai/src/opentelemetry/instrumentation/genai/openai/chat_wrappers.py Uses shared Role for synthesized assistant output messages.
instrumentation/opentelemetry-instrumentation-genai-llama-index/src/opentelemetry/instrumentation/genai/llama_index/_handler.py Uses shared Role for synthesized user input message.
instrumentation/opentelemetry-instrumentation-genai-bedrock/src/opentelemetry/instrumentation/genai/bedrock/stream.py Uses shared Role for stream wrapper role default.
instrumentation/opentelemetry-instrumentation-genai-bedrock/src/opentelemetry/instrumentation/genai/bedrock/extractors.py Uses shared Role for default role values when extracting.
instrumentation/opentelemetry-instrumentation-genai-agno/src/opentelemetry/instrumentation/genai/agno/patch.py Uses shared Role for synthesized input/output messages.
Review details
  • Files reviewed: 16/16 changed files
  • Comments generated: 1
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

The file said there was nothing to pin, directly above an editable
util-genai install. That line is a temporary workaround, not a pin.

Assisted-by: Claude Opus 5

@lmolkova lmolkova left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

thank you!

@@ -217,7 +218,7 @@ def convert_to_output_messages(

output_messages.append(
OutputMessage(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nit: one bare literal is left in this file - convert_to_final_output_messages (line 250) still defaults role to "assistant". It only feeds the local filter and is never emitted, but it is the last one left in the repo, so converting it keeps the sweep complete.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

thanks for catching that, switched to use enum there as well

convert_to_final_output_messages still defaulted role to "assistant",
the last bare literal left after the initial sweep. Extend the same
treatment to the role literals the instrumentations compare against, so
every role in the repo that has an enum member goes through it. Values
with no member stay literals: Google's "model" and qwen-agent's
"function", neither of which is a spec role.

Assisted-by: Claude Opus 5
@lmolkova
lmolkova added this pull request to the merge queue Sep 3, 2026
Merged via the queue into open-telemetry:main with commit 8ed589c Sep 3, 2026
73 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

Adopt the shared Role enum across instrumentations

4 participants