You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
OpenTelemetry: export a sparse set of model-routing attributes and document them #67237
Export a small, fixed set of model-routing attributes to OpenTelemetry and document every gh-aw.model_routing.* attribute, as requested by @pelikhan ("save some model-routing data into OTEL, sparingly").
Current state (main)
actions/setup/js/send_otlp_span.cjs calls resolveEffectiveModel (from actions/setup/js/model_attribution.cjs) against aw_info.json and adds these attributes to job conclusion spans: gen_ai.request.model, gh-aw.model.requested, gh-aw.model.effort, gh-aw.model_routing.status, gh-aw.model_routing.mode and gh-aw.model_routing.router_version.
None of the gh-aw.model_routing.* attributes are documented in docs/src/content/docs/reference/open-telemetry-attributes.mdx.
The Go audit/logs code (pkg/cli/model_routing.go, pkg/cli/model_routing_session.go) already derives failure code, degraded classification, classifier cost and deviated request counts from the same records.
Proposal
Emit one set of values per run, only on the agent job's conclusion span, and never per request. All values must be low-cardinality, with no free text derived from the prompt.
New attributes:
Attribute
Type
When emitted
Source
gh-aw.model_routing.failure_code
string
Only when status is not selected
model_routing.outcome failure code, or the routing failure in aw_info.json
gh-aw.model_routing.objective
string
When present, for example cost
Selection record objective goal
gh-aw.model_routing.task_type
string (enum)
When classified
Selection record labels
gh-aw.model_routing.scope
string (enum)
When classified
Selection record labels
gh-aw.model_routing.complexity
string (enum)
When classified
Selection record task_complexity label
gh-aw.model_routing.degraded
boolean
When a selection record exists
Selection record degraded-classification flag
gh-aw.model_routing.classifier_aic
double
When classifier usage is attributable
Classifier credits, kept separate from gh-aw.aic
gh-aw.model_routing.deviated_requests
integer
When request records exist
Count of request records not served as selected
Explicitly excluded: ranked choices, selected ids, conversation hashes, classifier rationale or degraded reason text, and any per-request data.
gh-aw.model_routing.classifier_aic depends on the classifier-cost fix in #67092 (fixes #67079), which is not merged yet. On main, classifier cost for routed runs currently comes out as 0.
Either way, do not re-implement classifier detection or cost bucketing in send_otlp_span.cjs or model_attribution.cjs.
Implementation plan
Session reader. In actions/setup/js/model_attribution.cjs, add a helper that reads usage/aw_session.jsonl once and returns a compact routing summary from the workflow.info, model_routing.outcome and firewall.model_routing events. Only events with agent provenance should count, matching how pkg/cli/model_routing_session.go filters them. The helper returns only the allow-listed fields above. Enum labels are passed through the existing identifier validation (validateModelIdentifier) and dropped if they fail it.
Fallbacks. If the session file or a record is missing, fall back to aw_info.json through resolveEffectiveModel / getModelRouting. Then use the proxy's model-routing log (sandbox/firewall/logs/api-proxy-logs/model-routing.jsonl and the alternate paths already listed in actions/setup/js/parse_token_usage.cjs) for selection labels, degraded flag and request counts.
Parity with audit. Classifier AIC and deviated-request counting must match pkg/cli/model_routing.go, so OTEL and gh aw audit / gh aw logs report the same numbers. That includes classifier cost bucketing and the endpoint-only deviation handling. Classifier AIC must not be added to or subtracted from gh-aw.aic.
Span emission. In send_otlp_span.cjs, in the conclusion-span attribute block that already emits gh-aw.model_routing.status, add the new attributes only when the conclusion span is for the agent job (jobName === "agent") and routing is active. Non-routed runs must emit no gh-aw.model_routing.* attributes. Keep the existing attributes unchanged, and give the session file precedence over aw_info.json for status, mode and router version when both are present.
Ordering check. Confirm that usage/aw_session.jsonl is written before the agent job's conclusion span is sent. If it isn't, rely on the fallbacks above and note this in a code comment.
Docs. In docs/src/content/docs/reference/open-telemetry-attributes.mdx, document all gh-aw.model_routing.* attributes (existing status, mode, router_version, plus the new ones). Also cover gh-aw.model.requested and gh-aw.model.effort if they are not already listed. Include a short note on the emission scope (agent conclusion span only, once per run), the exclusions, and the fact that classifier_aic is separate from gh-aw.aic.
Tests
In actions/setup/js/send_otlp_span.test.cjs, add:
Routed run. Given a session file with a selected outcome, a selection record and request records (including one deviated), the agent conclusion span carries status, mode, router version, objective, task type, scope, complexity, degraded, classifier AIC and deviated requests. It has no failure_code, and none of the excluded fields appear.
Failed routing. With a non-selected outcome, gh-aw.model_routing.failure_code is present alongside the status.
Non-routed run. No gh-aw.model_routing.* attributes are emitted.
Also add coverage for the aw_info.json / proxy-log fallback when the session file is absent, and for the rule that non-agent conclusion spans do not carry the new attributes. Add unit tests for the new helper in actions/setup/js/model_attribution.test.cjs.
Acceptance criteria
At most one set of routing values per run, only on the agent conclusion span.
No prompt-derived text, ranked choices, selected ids, conversation hashes or per-request data in any span.
Summary
Export a small, fixed set of model-routing attributes to OpenTelemetry and document every
gh-aw.model_routing.*attribute, as requested by @pelikhan ("save some model-routing data into OTEL, sparingly").Current state (main)
actions/setup/js/send_otlp_span.cjscallsresolveEffectiveModel(fromactions/setup/js/model_attribution.cjs) againstaw_info.jsonand adds these attributes to job conclusion spans:gen_ai.request.model,gh-aw.model.requested,gh-aw.model.effort,gh-aw.model_routing.status,gh-aw.model_routing.modeandgh-aw.model_routing.router_version.gh-aw.model_routing.*attributes are documented indocs/src/content/docs/reference/open-telemetry-attributes.mdx.usage/aw_session.jsonl) carriesworkflow.info,model_routing.outcomeand thefirewall.model_routingselection and request records. @pelikhan's rule is that consumers read routing data from that file.pkg/cli/model_routing.go,pkg/cli/model_routing_session.go) already derives failure code, degraded classification, classifier cost and deviated request counts from the same records.Proposal
Emit one set of values per run, only on the agent job's conclusion span, and never per request. All values must be low-cardinality, with no free text derived from the prompt.
New attributes:
gh-aw.model_routing.failure_codeselectedmodel_routing.outcomefailure code, or the routing failure inaw_info.jsongh-aw.model_routing.objectivecostgh-aw.model_routing.task_typegh-aw.model_routing.scopegh-aw.model_routing.complexitytask_complexitylabelgh-aw.model_routing.degradedgh-aw.model_routing.classifier_aicgh-aw.aicgh-aw.model_routing.deviated_requestsExplicitly excluded: ranked choices, selected ids, conversation hashes, classifier rationale or degraded reason text, and any per-request data.
Dependency: classifier cost fix (#67092)
gh-aw.model_routing.classifier_aicdepends on the classifier-cost fix in #67092 (fixes #67079), which is not merged yet. On main, classifier cost for routed runs currently comes out as 0.classifier_aicfrom its corrected classifier-cost attribution.classifier_aicfor a follow-up.send_otlp_span.cjsormodel_attribution.cjs.Implementation plan
actions/setup/js/model_attribution.cjs, add a helper that readsusage/aw_session.jsonlonce and returns a compact routing summary from theworkflow.info,model_routing.outcomeandfirewall.model_routingevents. Only events with agent provenance should count, matching howpkg/cli/model_routing_session.gofilters them. The helper returns only the allow-listed fields above. Enum labels are passed through the existing identifier validation (validateModelIdentifier) and dropped if they fail it.aw_info.jsonthroughresolveEffectiveModel/getModelRouting. Then use the proxy's model-routing log (sandbox/firewall/logs/api-proxy-logs/model-routing.jsonland the alternate paths already listed inactions/setup/js/parse_token_usage.cjs) for selection labels, degraded flag and request counts.pkg/cli/model_routing.go, so OTEL andgh aw audit/gh aw logsreport the same numbers. That includes classifier cost bucketing and the endpoint-only deviation handling. Classifier AIC must not be added to or subtracted fromgh-aw.aic.send_otlp_span.cjs, in the conclusion-span attribute block that already emitsgh-aw.model_routing.status, add the new attributes only when the conclusion span is for the agent job (jobName === "agent") and routing is active. Non-routed runs must emit nogh-aw.model_routing.*attributes. Keep the existing attributes unchanged, and give the session file precedence overaw_info.jsonfor status, mode and router version when both are present.usage/aw_session.jsonlis written before the agent job's conclusion span is sent. If it isn't, rely on the fallbacks above and note this in a code comment.docs/src/content/docs/reference/open-telemetry-attributes.mdx, document allgh-aw.model_routing.*attributes (existingstatus,mode,router_version, plus the new ones). Also covergh-aw.model.requestedandgh-aw.model.effortif they are not already listed. Include a short note on the emission scope (agent conclusion span only, once per run), the exclusions, and the fact thatclassifier_aicis separate fromgh-aw.aic.Tests
In
actions/setup/js/send_otlp_span.test.cjs, add:failure_code, and none of the excluded fields appear.selectedoutcome,gh-aw.model_routing.failure_codeis present alongside the status.gh-aw.model_routing.*attributes are emitted.Also add coverage for the
aw_info.json/ proxy-log fallback when the session file is absent, and for the rule that non-agent conclusion spans do not carry the new attributes. Add unit tests for the new helper inactions/setup/js/model_attribution.test.cjs.Acceptance criteria
classifier_aic(once Restore classifier cost attribution in routed-run audits #67092 is in) anddeviated_requestsmatchgh aw auditfor the same run.gh-aw.model_routing.*attributes are documented inopen-telemetry-attributes.mdx.make fmt,make lintand the targeted JS tests pass.