fix(otel): eliminate gen_ai.usage.* double-counting and gen_ai.request.model duplicate on agent span#30350
Merged
Merged
Conversation
13 tasks
Agent-Logs-Url: https://github.com/github/gh-aw/sessions/dd0c61dc-f073-4e18-a47a-0d77006c19e1 Co-authored-by: pelikhan <[email protected]>
… spans - Move gen_ai.usage.* token-count attributes to a separate usageAttrs array instead of pushing directly into the shared attributes (conclusion span) array. When an agent sub-span is emitted, usageAttrs are added exclusively to agentAttributes so the token counts appear only on the gh-aw.agent.agent span. When no agent span is emitted (non-agent jobs), usageAttrs fall through to the conclusion span so observability requires no extra join. - Remove the duplicate push of gen_ai.request.model to agentAttributes at line 1285; the attribute is already present via the [...attributes] spread. - Update conclusion-span tests to assert that token attrs are absent when an agent sub-span is emitted (they now live on the agent span only). - Add test verifying gen_ai.request.model appears exactly once on the agent span. Agent-Logs-Url: https://github.com/github/gh-aw/sessions/dd0c61dc-f073-4e18-a47a-0d77006c19e1 Co-authored-by: pelikhan <[email protected]>
Copilot
AI
changed the title
[WIP] Improve OTel instrumentation by removing duplicate token attributes
fix(otel): eliminate gen_ai.usage.* double-counting and gen_ai.request.model duplicate on agent span
May 5, 2026
Contributor
There was a problem hiding this comment.
Pull request overview
Fixes OpenTelemetry GenAI attribute duplication by ensuring gen_ai.usage.* token counters are only attached to the dedicated agent span (when emitted), and by preventing gen_ai.request.model from being added twice to the agent span.
Changes:
- Refactors token-usage attribute construction to avoid double-counting across conclusion + agent spans.
- Removes a redundant
gen_ai.request.modelpush that produced duplicate keys on the agent span. - Updates/adds tests to assert token attributes are absent from the conclusion span when an agent sub-span is emitted, and that
gen_ai.request.modelappears exactly once on the agent span.
Show a summary per file
| File | Description |
|---|---|
| actions/setup/js/send_otlp_span.cjs | Isolates gen_ai.usage.* into usageAttrs and attaches them only to the agent span when present; removes duplicate gen_ai.request.model push. |
| actions/setup/js/send_otlp_span.test.cjs | Updates assertions to prevent regression on token double-counting and model-key duplication. |
| .github/workflows/stale-pr-cleanup.lock.yml | Updates pinned firewall/AWF image/version references (auto-generated lockfile change). |
Copilot's findings
Tip
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Files reviewed: 3/3 changed files
- Comments generated: 1
Comment on lines
112
to
116
| GH_AW_INFO_STAGED: "false" | ||
| GH_AW_INFO_ALLOWED_DOMAINS: '["defaults"]' | ||
| GH_AW_INFO_FIREWALL_ENABLED: "true" | ||
| GH_AW_INFO_AWF_VERSION: "v0.25.38" | ||
| GH_AW_INFO_AWF_VERSION: "v0.25.39" | ||
| GH_AW_INFO_AWMG_VERSION: "" |
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.
gen_ai.usage.*token attributes were being added to the sharedattributesarray beforeagentAttributes = [...attributes]was constructed, landing the same four token counters on bothgh-aw.agent.conclusionandgh-aw.agent.agentspans. Any backend summing these across a trace returned 2× actual token counts. Additionally,gen_ai.request.modelwas pushed toattributesearly then pushed again explicitly intoagentAttributes, producing a duplicate key on the agent span.Changes
send_otlp_span.cjsgen_ai.usage.*attrs into a localusageAttrsarray instead of pushing directly intoattributesusageAttrsintoagentAttributesonly — conclusion span gets noneusageAttrsintoattributes(conclusion span) so single-span observability is preserved without a joingen_ai.request.modelpush intoagentAttributes(already present via the[...attributes]spread)send_otlp_span.test.cjsgen_ai.usage.*keys are absent when an agent sub-span is emittedgen_ai.request.modelappears exactly once on the agent spanWarning
Firewall rules blocked me from connecting to one or more addresses (expand for details)
I tried to connect to the following addresses, but was blocked by firewall rules:
https://api.github.com/graphql/usr/bin/gh gh repo view --json owner,name --jq .owner.login + "/" + .name k(http block)/usr/bin/gh /usr/bin/gh api graphql -f query=query($owner: String!, $name: String!) { repository(owner: $owner, name: $name) { hasDiscussionsEnabled } } -f owner=github -f name=gh-aw bagabas/go-udiffinit --end-of-options ache/go/1.25.8/x64/pkg/tool/linuremote.origin.url sRem�� SvuWvV_iU **/*.cjs ache/go/1.25.8/x64/pkg/tool/linux_amd64/vet **/*.json --ignore-path ../../../.pretti--show-toplevel ache/go/1.25.8/x64/pkg/tool/linux_amd64/vet(http block)/usr/bin/gh /usr/bin/gh api graphql -f query=query($owner: String!, $name: String!) { repository(owner: $owner, name: $name) { hasDiscussionsEnabled } } -f owner=github -f name=gh-aw er_test pkg/workflow/clauser.name ache/go/1.25.8/xTest User(http block)https://api.github.com/orgs/test-owner/actions/secrets/usr/bin/gh gh api /orgs/test-owner/actions/secrets --jq .secrets[].name on' --ignore-patgo1.25.8(http block)https://api.github.com/repos/actions/ai-inference/git/ref/tags/v1/usr/bin/gh gh api /repos/actions/ai-inference/git/ref/tags/v1 --jq [.object.sha, .object.type] | @tsv /ref/tags/v9 /opt/hostedtoolc--jq sv -bool -buildtags /tmp/go-build380--show-toplevel git rev-�� --show-toplevel /tmp/go-build3801829731/b421/fileutil.test /usr/bin/git -test.paniconexigh -test.v=true /usr/lib/git-cor/repos/actions/github-script/git/ref/tags/v9 git(http block)https://api.github.com/repos/actions/checkout/git/ref/tags/v3/usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v3 --jq [.object.sha, .object.type] | @tsv --show-toplevel x_amd64/compile er: String!, $name: String!) { repository(owner: $owner, name: $name) { hasDiscussionsEnabl--show-toplevel --local .cfg 64/pkg/tool/linu/repos/actions/github-script/git/ref/tags/v9 git conf�� user.name Test User /usr/bin/git ude_logs.go .cfg tartedAt,updated--show-toplevel /usr/bin/git(http block)https://api.github.com/repos/actions/checkout/git/ref/tags/v5/usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v5 --jq [.object.sha, .object.type] | @tsv -unreachable=false /tmp/go-build3801829731/b143/vet.cfg e/git(http block)/usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v5 --jq [.object.sha, .object.type] | @tsv --show-toplevel infocmp /usr/bin/git BHBh/Mm0ui0x2Iv4git -tests /opt/hostedtoolc--show-toplevel git rev-�� --show-toplevel node /usr/bin/git /tmp/TestHashCongit 1829731/b460/_terev-parse /usr/bin/infocmp--show-toplevel git(http block)/usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v5 --jq [.object.sha, .object.type] | @tsv k/_tool infocmp /usr/bin/infocmp tags/v6 64/pkg/tool/linurev-parse sv infocmp -1 xterm-color infocmp /home/REDACTED/.local/bin/node xterm-color /opt/hostedtoolcrev-parse /usr/bin/infocmp--show-toplevel node(http block)https://api.github.com/repos/actions/checkout/git/ref/tags/v6/usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v6 --jq [.object.sha, .object.type] | @tsv runs/20260505-125135-14164/test-3056747236 --jq(http block)/usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v6 --jq [.object.sha, .object.type] | @tsv -bool l /opt/hostedtoolcache/node/24.14.1/x64/bin/node -errorsas -ifaceassert -nilfunc node /tmp�� /tmp/TestHashStability_SameInputSameOutput287149578/001/stability-test.md -tests /usr/bin/git actions/setup/jsgit(http block)/usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v6 --jq [.object.sha, .object.type] | @tsv --show-toplevel x_amd64/vet /usr/bin/git --get-regexp --local x_amd64/vet git remo��(http block)https://api.github.com/repos/actions/github-script/git/ref/tags/v8/usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v8 --jq [.object.sha, .object.type] | @tsv /repos/actions/setup-node/git/ref/tags/v4 --jq /usr/bin/git /ref/tags/v9 remote.origin.urrev-parse sv git rev-�� --show-toplevel git /usr/bin/git /tmp/gh-aw-test-git resolved$(http block)https://api.github.com/repos/actions/github-script/git/ref/tags/v9/usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v9 --jq [.object.sha, .object.type] | @tsv /send_otlp_span.test.cjs(http block)/usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v9 --jq [.object.sha, .object.type] | @tsv(http block)/usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v9 --jq [.object.sha, .object.type] | @tsv path .prettierig-errorsas(http block)https://api.github.com/repos/actions/github-script/git/ref/tags/v9.0.0/usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v9.0.0 --jq [.object.sha, .object.type] | @tsv(http block)/usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v9.0.0 --jq [.object.sha, .object.type] | @tsv /send_otlp_span.test.cjs(http block)/usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v9.0.0 --jq [.object.sha, .object.type] | @tsv -c=4 -nolocalimports -importcfg /tmp/go-build3801829731/b398/importcfg -embedcfg /tmp/go-build3801829731/b398/embedcfg -pack(http block)https://api.github.com/repos/actions/setup-go/git/ref/tags/v4/usr/bin/gh gh api /repos/actions/setup-go/git/ref/tags/v4 --jq [.object.sha, .object.type] | @tsv --show-toplevel /opt/hostedtoolc--jq /usr/bin/git SameOutput287149git /tmp/go-build380rev-parse e/git-upload-pac--show-toplevel git rev-�� --show-toplevel /opt/hostedtoolc--jq /usr/bin/git -unreachable=falgit /tmp/go-build380rev-parse ache/node/24.14.--show-toplevel git(http block)https://api.github.com/repos/actions/setup-node/git/ref/tags/v4/usr/bin/gh gh api /repos/actions/setup-node/git/ref/tags/v4 --jq [.object.sha, .object.type] | @tsv /ref/tags/v9 remote.origin.url sv -c=4 -nolocalimports -importcfg git -C /tmp/gh-aw-test-runs/20260505-125135-14164/test-4139448571 resolved$(http block)/usr/bin/gh gh api /repos/actions/setup-node/git/ref/tags/v4 --jq [.object.sha, .object.type] | @tsv /ref/tags/v9 64/pkg/tool/linuconfig sv 4139448571(http block)/usr/bin/gh gh api /repos/actions/setup-node/git/ref/tags/v4 --jq [.object.sha, .object.type] | @tsv ithub-script/git/ref/tags/v9 ache/node/24.14.1/x64/bin/node bject.type] | @tsv ue.number(http block)https://api.github.com/repos/actions/setup-node/git/ref/tags/v6/usr/bin/gh gh api /repos/actions/setup-node/git/ref/tags/v6 --jq [.object.sha, .object.type] | @tsv xterm-color -tests t k/_temp/copilot-infocmp(http block)/usr/bin/gh gh api /repos/actions/setup-node/git/ref/tags/v6 --jq [.object.sha, .object.type] | @tsv /tmp/gh-aw-test-runs/20260505-125135-14164/test-2389925063/.github/workflows config /usr/bin/git remote.origin.urgit(http block)/usr/bin/gh gh api /repos/actions/setup-node/git/ref/tags/v6 --jq [.object.sha, .object.type] | @tsv ansitiveImports3822226293/001 x_amd64/vet /usr/bin/git --get-regexp --local x_amd64/vet git conf�� --get remote.origin.url /usr/bin/git 991165933/001 991165933/002/worev-parse x_amd64/vet git(http block)https://api.github.com/repos/actions/upload-artifact/git/ref/tags/v4/usr/bin/gh gh api /repos/actions/upload-artifact/git/ref/tags/v4 --jq [.object.sha, .object.type] | @tsv /repos/github/gh-aw/git/ref/tags/v3.0.0 --jq /usr/bin/git */*.ts' '**/*.jsgit --local x_amd64/vet git rev-�� --show-toplevel x_amd64/vet /usr/bin/git b/workflows --local x_amd64/compile git(http block)https://api.github.com/repos/aws-actions/configure-aws-credentials/git/ref/tags/v4/usr/bin/gh gh api /repos/aws-actions/configure-aws-credentials/git/ref/tags/v4 --jq [.object.sha, .object.type] | @tsv --show-toplevel git /usr/bin/git ons-test29275456git config /usr/bin/git git rev-�� --show-toplevel git /usr/bin/gh /tmp/gh-aw-test-gh l /opt/hostedtoolcstatus gh(http block)/usr/bin/gh gh api /repos/aws-actions/configure-aws-credentials/git/ref/tags/v4 --jq [.object.sha, .object.type] | @tsv --show-toplevel ache/node/24.14.1/x64/bin/node /usr/bin/git /tmp/TestGuardPogh config /usr/bin/git git rev-�� /ref/tags/v9 git sv mpleWorkflow2644git x_amd64/vet om/upstream/repo--show-toplevel gh(http block)https://api.github.com/repos/azure/login/git/ref/tags/v2/usr/bin/gh gh api /repos/azure/login/git/ref/tags/v2 --jq [.object.sha, .object.type] | @tsv --show-toplevel git /usr/bin/git --show-toplevel /home/REDACTED/worrev-parse /opt/hostedtoolc--show-toplevel git rev-�� --show-toplevel /opt/hostedtoolcache/go/1.25.8/x64/pkg/tool/linuowner/host-repo /usr/bin/infocmp -bool l /usr/bin/git infocmp(http block)https://api.github.com/repos/docker/login-action/git/ref/tags/v3/usr/bin/gh gh api /repos/docker/login-action/git/ref/tags/v3 --jq [.object.sha, .object.type] | @tsv --show-toplevel node /usr/bin/git /tmp/TestHashCongit 1829731/b460/_terev-parse /usr/bin/infocmp--show-toplevel git rev-�� --show-toplevel infocmp /usr/bin/git xterm-color x_amd64/vet ipts.test git(http block)https://api.github.com/repos/github/gh-aw-actions/git/ref/tags/v0.1.2/usr/bin/gh gh api /repos/github/gh-aw-actions/git/ref/tags/v0.1.2 --jq [.object.sha, .object.type] | @tsv --show-toplevel ache/go/1.25.8/x64/pkg/tool/linux_amd64/link /usr/bin/git vaScript36988311infocmp -trimpath e/git git rev-�� --show-toplevel e/git /usr/bin/git ithub/workflows -buildtags 1/x64/bin/node git(http block)https://api.github.com/repos/github/gh-aw-actions/git/ref/tags/v1.0.0/usr/bin/gh gh api /repos/github/gh-aw-actions/git/ref/tags/v1.0.0 --jq [.object.sha, .object.type] | @tsv --show-toplevel 02zfbN4/uSkbk2BocNu6uh6Xsdg3 /usr/bin/git it} --local x_amd64/vet git rev-�� --show-toplevel x_amd64/vet /usr/bin/git ions-build/main.git credential.helperev-parse x_amd64/vet git(http block)https://api.github.com/repos/github/gh-aw-actions/git/ref/tags/v1.2.3Agent-Logs-Urrev-parse 64/pkg/tool/linu--show-toplevel git` (http block)