Repository navigation
fix(telemetry): count a turn by its segment, not by its invoke_agent spans - #3324
Open
QuentinBisson wants to merge 3 commits into
Open
QuentinBisson wants to merge 3 commits into
QuentinBisson wants to merge 3 commits into
Conversation
…spans Claude Code 2.1.302 marks its claude_code.interaction span with gen_ai.operation.name=invoke_agent; 2.1.285 emits the same span without it. The span is a child of the invoke_agent span kagent opens for the harness, which it reaches through TRACEPARENT, so a Claude turn's trace now holds two invoke_agent spans and TestE2ECompletedChatFlushesTraces failed on every run of the Claude Code bump with "invoke_agent spans = 2, want exactly one". kagent keeps its own span for a native coding agent: only it carries the segment, the A2A identity, the capture and the duration metric. The contract states the case: kagent opens invoke_agent for a runtime whose own spans carry no invocation segment, a native agent may still mark a span of its own invoke_agent beneath it, and a consumer counts turns by kagent.invocation.segment, as the request-span notes already say. The test selects the invocation by operation and segment and requires Claude Code's interaction span under it. The trace diagnostic lists the expected trace's spans before the other traces' request spans, and with their operation: the parallel cases' request spans filled its twelve entries and hid the trace that failed. Signed-off-by: Timo Derstappen <teemow@gmail.com>
…'s native strip kagent also opens invoke_agent for LangGraph, CrewAI and BYO runtimes, not only native harnesses. Name the existing mechanism that keeps claude_code.interaction from counting as a second invocation: the reference collector removes the GenAI operation from kagent.genai.producer=runtime spans. Signed-off-by: QuentinBisson <quentin@giantswarm.io>
QuentinBisson
added a commit
to giantswarm/kagent-upstream
that referenced
this pull request
Oct 23, 2026
#881) U1 is kagent-dev#3324, U6 is kagent-dev#3327, the webhook end state of the controller binary is kagent-dev#3326, the egress ask is agent-substrate/substrate#3137 and the labels use case sits on substrate#186. kagent-dev#3299 took the Session create namespace at all three sites. The session label and the Dex display rows go back to to-file: the baggage coverage PR and the +15/-2 UI PR are the filings. Signed-off-by: QuentinBisson <quentin@giantswarm.io>
moezdil
reviewed
Oct 23, 2026
| // compiler owns this identity, so the assertion holds without any | ||
| // Invocations are selected by operation and segment, the way the | ||
| // contract tells a consumer to count turns: a native runtime's own | ||
| // invoke_agent span, such as Claude Code's interaction span, carries |
Contributor
There was a problem hiding this comment.
could we still assert no stray unsegmented invoke_agent spans?
Contributor
Author
There was a problem hiding this comment.
You're right, the segment selector lost that guard. The test now takes every invoke_agent span outside the native harness process (the ones carrying kagent.genai.producer=runtime, which the reference collector strips), requires exactly one, and checks its segment. Can you take another look?
…r keeps Selecting the invocation by segment let a second invoke_agent span pass unseen. Select every invoke_agent span outside the native harness process, whose GenAI operation the reference collector removes by kagent.genai.producer=runtime, require exactly one, and require its segment. Signed-off-by: QuentinBisson <quentin@giantswarm.io>
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.
Problem
Recent Claude Code releases (2.1.308 included; 2.1.285 does not) mark their
claude_code.interactionspan withgen_ai.operation.name=invoke_agent. The span sits beneath theinvoke_agentspan the harness opens (Claude Code reaches it throughTRACEPARENT), so the tracing e2e (go/core/test/e2e/tracing_test.go:417-426) sees twoinvoke_agentspans in one turn and fails. #3321 bumps Claude Code to 2.1.308, which hits it.Change
The e2e requires exactly one
invoke_agentspan outside the native harness process, whose spans the reference collector strips bykagent.genai.producer=runtime, requires itsinitialsegment, and requires Claude Code's interaction span directly beneath it. The contract and telemetry docs now say that Claude Code's span is a child of kagent'sinvoke_agent, and that the reference collector already removes its operation through thekagent.genai.producer=runtimestrip. Consumers of the reference pipeline therefore see one invocation per turn.