Skip to content

[opentelemetry-util-genai] Add shared agent stream wrappers and migrate agent instrumentations - #1033

Open
eternalcuriouslearner wants to merge 17 commits into
open-telemetry:mainfrom
eternalcuriouslearner:feat/util-agent-stream-wrapper
Open

eternalcuriouslearner wants to merge 17 commits into
open-telemetry:mainfrom
eternalcuriouslearner:feat/util-agent-stream-wrapper

Conversation

@eternalcuriouslearner

@eternalcuriouslearner eternalcuriouslearner commented Nov 3, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #595, fixes #386. Adds SyncAgentStreamWrapper / AsyncAgentStreamWrapper and a public utils.content_to_text to util-genai, and moves the agno, qwenpaw, qwen-agent and smolagents agent/workflow stream wrappers onto them. Util and the migrations are in one PR on purpose, so the API can be reviewed alongside every consumer.

Why: each package hand-rolled output buffering, structured-content serialization and finalization. The ones that did not pass their invocation to the base wrapper also kept invoke_agent current in the caller's context while a stream was held unconsumed, so unrelated caller spans nested under it (#386). With #880 merged, agent invocations can use the base wrapper directly.

Behavior changes:

  • Stream spans are suspended between chunks in all four packages.
  • agno agent streams report gen_ai.response.finish_reasons instead of the deprecated per-message finish_reason.

Known gaps:

🤖 Generated with Claude Code

Add SyncAgentStreamWrapper and AsyncAgentStreamWrapper so agent
instrumentations share streamed output accumulation, structured content
serialization, context suspension and finalization.

Part of open-telemetry#595.

Assisted-by: Claude Opus 5.5
Copilot AI balanced review requested due to automatic review settings November 3, 2026 06:23
@eternalcuriouslearner
eternalcuriouslearner requested a review from a team as a code owner November 3, 2026 06:23
Assisted-by: Claude Opus 5.5
@opentelemetry-pr-dashboard

opentelemetry-pr-dashboard Bot commented Nov 3, 2026 •

Copy link
Copy Markdown

Pull request dashboard status

Waiting on reviewers · refreshed 2026-11-04 00:39 UTC

Review the latest changes.

Status above doesn't look right?
  • Just replied or pushed? Anything around or after the refresh time above may not be picked up yet — give it a few minutes.
  • 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.

🟡 Changes recommended

Unbounded output buffering can exhaust memory, while conversion, initialization, and cleanup failures can disrupt streams or leave invocations unfinished.

6 open issues
What changed in this PR

Adds shared synchronous and asynchronous agent/workflow stream wrappers to opentelemetry-util-genai, addressing the reusable stream-handling portion of #595. Consumer migrations remain separate.

Changes:

  • Adds output accumulation, structured-content serialization, and invocation lifecycle handling without inference-only streaming metrics.
  • Tests output handling, context isolation, errors, closure, and abandonment.
  • Documents the subclass API and adds a release note.
File Description
util/​opentelemetry-util-genai/​tests/​test_agent_stream.py Tests agent/workflow stream behavior and telemetry.
util/​opentelemetry-util-genai/​src/​opentelemetry/​util/​genai/​stream.py Adds sync/async wrappers with shared output handling.
util/​opentelemetry-util-genai/​README.rst Documents wrapper usage and output-reporting hooks.
util/​opentelemetry-util-genai/​.changelog/​1033.added Announces the new stream wrappers.

Review effort: Balanced

- Skip None and unserializable output instead of raising into the stream.
- Stop accumulating text once output messages take precedence.
- Fail the invocation and restore context if wrapping the stream raises.

Assisted-by: Claude Opus 5.5
- Use the base wrapper's invocation reference instead of a second copy.
- Share init-failure handling and output setup through the mixin.
- Drop a capture check that cannot change the result and unused test
  helpers.

Assisted-by: Claude Opus 5.5
Instrumentations serialize structured content to text on non-streamed
paths too, so make the helper public in utils instead of private to the
stream module.

Assisted-by: Claude Opus 5.5
Dropping the last reference at break finalizes the stream before the
caller's span starts, so the tests passed even without suspension.

Assisted-by: Claude Opus 5.5
…appers

Build the agent and workflow stream wrappers on util-genai's
SyncAgentStreamWrapper / AsyncAgentStreamWrapper and replace the local
format_content with util's content_to_text, dropping the duplicated
buffering, serialization and finalization. Stream spans are now
suspended between chunks, and agent streams report finish reasons on
gen_ai.response.finish_reasons.

Assisted-by: Claude Opus 5.5
Assisted-by: Claude Opus 5.5
… wrapper

Build QueryHandlerStreamWrapper on util-genai's AsyncAgentStreamWrapper,
so the invoke_agent invocation is passed to the base wrapper and
suspended between chunks instead of staying current in the caller's
context.

Fixes open-telemetry#386.

Assisted-by: Claude Opus 5.5
Assisted-by: Claude Opus 5.5
…eam wrapper

Build _AgentRunStreamWrapper on util-genai's SyncAgentStreamWrapper so
the invoke_agent invocation is suspended between chunks instead of
staying current in the caller's context.

Assisted-by: Claude Opus 5.5
…eam wrapper

Build the streamed agent run wrapper on util-genai's
SyncAgentStreamWrapper and drop its own finalize-once flag, destructor
and BaseException handling, which the base wrapper already provides.
The invoke_agent invocation is now suspended between steps.

Assisted-by: Claude Opus 5.5
@eternalcuriouslearner eternalcuriouslearner changed the title [opentelemetry-util-genai] Add shared agent and workflow stream wrappers [opentelemetry-util-genai] Add shared agent stream wrappers and migrate agent instrumentations Nov 3, 2026
Resolve smolagents conflicts with open-telemetry#1006: keep the shared agent stream
wrapper and carry over closing an abandoned run inside the agent span.

Assisted-by: Claude Opus 5.5

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.

- smolagents: close a held run generator even after the final answer
  ended the span, and always stop the invocation if recording the
  answer fails.
- agno: report no finish reason for a run the caller closed before it
  completed, using a new _self_exhausted flag on the base wrappers.
- qwen-agent: skip output conversion when content capture is off.
- util: return scalars such as Decimal and Path from content_to_text
  without JSON quoting.

Assisted-by: Claude Opus 5.5

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.

🟡 Changes recommended

Closing the stream immediately after a completed event without content can leave a completed run without its stop finish reason.

1 open issue
5 resolved since last review

Review effort: Balanced

A completion event marks the run as finished even when it carries no
content, so a caller closing right after it keeps the stop finish
reason.

Assisted-by: Claude Opus 5.5

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.

🔵 Needs a closer look

Human assessment is needed for edge cases involving disabled content capture, partial-output preservation, and workflow error reporting.

No open issues 🎉

1 resolved since last review

Review effort: Balanced

This branch has not been deployed

No deployments
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.

[util-genai] Investigate streaming helpers for agent and workflow invocations Stream wrappers cannot finalize telemetry for generator-backed streams

2 participants