Fix microsoft.gen_ai.main_agent.* propagation and self-promotion issues#196
Open
hectorhdzg wants to merge 1 commit into
Open
Fix microsoft.gen_ai.main_agent.* propagation and self-promotion issues#196hectorhdzg wants to merge 1 commit into
hectorhdzg wants to merge 1 commit into
Conversation
Fix three issues with main_agent attribute handling identified during MAF Python and LangChain Python testing: 1. on_end self-promotion never fired: ReadableSpan lacks set_attribute(), so the hasattr guard always bailed out. Fixed by writing directly to the internal _attributes (BoundedAttributes) mapping. 2. on_start inheritance missed late-set parent attributes: When a child span was created before the parent's gen_ai.agent.* attributes were set, on_start propagation silently skipped them. Fixed by storing the parent Span reference in on_start and re-reading from it during on_end as a fallback. 3. Nested LangChain agents had gen_ai.agent.name overwritten by the top-level agent's config: _resolve_agent_name() unconditionally read from the shared _agent_config, clobbering sub-agent identity. Fixed by adding a use_config flag and skipping config-based identity for nested agents (detected via _find_agent_ancestor).
Performance comparisonThreshold: regressions >15.0% on gating scenarios fail the build. Higher ops/s is better; positive Δ means the PR is slower.
|
Contributor
There was a problem hiding this comment.
Pull request overview
This PR updates the GenAI main-agent attribution flow so microsoft.gen_ai.main_agent.* attributes are reliably populated across SDK spans (including timing edge-cases) and LangChain nested-agent runs (avoiding top-level config overriding nested agent identity).
Changes:
- Fix
GenAIMainAgentSpanProcessor.on_end()to self-promote by mutating the underlying span attributes mapping and add an on-end fallback propagation path for late-set parent attributes. - Expand real-SDK tests to cover on-end fallback propagation and root-span self-promotion behavior.
- Adjust LangChain tracer agent-name resolution so nested agents don’t inherit identity from shared top-level
_agent_config.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
src/microsoft/opentelemetry/_genai/main_agent/_processor.py |
Adds parent tracking for on-end fallback propagation and switches on-end enrichment to mutate internal attributes. |
src/microsoft/opentelemetry/_genai/_langchain/_tracer.py |
Prevents nested agents from using top-level config overrides for agent identity fields. |
tests/genai/main_agent/test_span_processor.py |
Updates unit tests to validate on-end enrichment via internal attributes mutation. |
tests/genai/main_agent/test_sdk_propagation.py |
Adds/updates real-SDK regression tests for timing recovery and self-promotion scenarios. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+131
to
+135
| if has_internal_attrs: | ||
| span._attributes = dict(attributes) | ||
| else: | ||
| del span._attributes | ||
| return span |
rads-1996
approved these changes
Jun 8, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes three issues identified during MAF Python and LangChain Python testing:
Issue 1: on_end self-promotion never fires (MAF + LC Python)
Symptom: Root invoke_agent spans never get microsoft.gen_ai.main_agent.* attributes. They have gen_ai.agent.name but self-promotion to microsoft.gen_ai.main_agent.name never happens.
Root cause: The OTel SDK's SpanProcessor.on_end() receives a ReadableSpan, not a Span. ReadableSpan does NOT have set_attribute(). The old code had:
This guard silently aborted self-promotion for every span.
Fix: Write directly to span._attributes (the internal BoundedAttributes dict) instead of calling set_attribute(). Mutations are visible to downstream SpanExporters since they read from the same object.
Issue 2: on_start inheritance misses late-set parent attributes (MAF Python)
Symptom: Some chat, execute_tool, and HTTP spans inside a trace whose invoke_agent ancestor has gen_ai.agent.name end up with no microsoft.gen_ai.main_agent.name.
Root cause: on_start reads parent.attributes at child-creation time. If the parent's gen_ai.agent.* attributes are set AFTER the child span is created (timing issue in some MAF SDK flows), on_start sees an empty parent and propagates nothing. No fallback existed.
Fix: Store a reference to the parent Span during on_start. During on_end, if the span still lacks microsoft.gen_ai.main_agent.* and is not an invoke_agent span, re-read from the stored parent. By on_end time the parent attributes have been set, so the fallback succeeds. References are cleaned up in on_end and shutdown().
Issue 3: Nested LangChain agent gen_ai.agent.name overwritten by parent (LC Python)
Symptom: A nested invoke_agent span for a sub-agent (e.g. "Data agent") shows the parent agent's name (e.g. "Main agent") in gen_ai.agent.name, while gen_ai.agent.id and gen_ai.agent.description correctly show the sub-agent's values.
Root cause: _resolve_agent_name() always checked self._agent_config.get("agent_name") first - the shared top-level config. For nested sub-agents, this override clobbered the sub-agent's own name from run metadata. agent_id/description were correct because extract_agent_metadata(run) via set_attributes() ran after config values, but agent_name from config won because _resolve_agent_name checked it first.
Fix: Added use_config parameter to _resolve_agent_name(). Nested agents (detected via _find_agent_ancestor()) pass use_config=False so they derive identity solely from run metadata. Config-based agent_id, agent_description, and agent_version are also skipped for nested agents.