feat: add OTel GenAI semantic conventions to agent span#28511
Conversation
|
@copilot review more GenAI otel attributes to determine whether they apply to the existing otel collection in the project. |
- Replace gh-aw.tokens.* with gen_ai.usage.* on the agent span - Replace gh-aw.model with gen_ai.request.model on the agent span - Add gen_ai.system (from engine_id) to the agent span - Change agent span kind to SPAN_KIND_CLIENT Resolves the gh-aw.agent.agent span not emitting standard OTel GenAI semantic convention attributes required by out-of-the-box LLM dashboards in Grafana, Datadog, and Honeycomb. Agent-Logs-Url: https://github.com/github/gh-aw/sessions/0cb5dbc8-7a44-478a-93be-8cb8a9ab1222 Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
- Fix cache token names: cache_read.input_tokens / cache_creation.input_tokens (dot separator, not underscore — per OTel registry) - Replace deprecated gen_ai.system with gen_ai.provider.name (Required) - Add gen_ai.operation.name = "chat" (Required by spec) - Add gen_ai.workflow.name = workflowName (spec: multi_agent_rag pattern) Agent-Logs-Url: https://github.com/github/gh-aw/sessions/fae7df36-dd28-47b3-a92a-eaa1130ad17a Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Reviewed the full OTel GenAI semantic conventions registry against all data available in the project. Updated in commit Corrections to initial PR:
New additions:
Attributes reviewed but not applicable (data not collected):
Warning 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:
If you need me to access, download, or install something from one of these locations, you can either:
|
🧪 Test Quality Sentinel ReportTest Quality Score: 77/100
Test Classification DetailsView all 7 tests
Suggestions (non-blocking)
|
There was a problem hiding this comment.
Pull request overview
Updates the dedicated gh-aw.agent.agent OTLP span to use OpenTelemetry GenAI semantic conventions so standard GenAI dashboards can recognize model/provider/workflow and token usage without custom attribute mappings.
Changes:
- Emit the agent span as
SPAN_KIND_CLIENTand attachgen_ai.*semantic convention attributes to that span. - Move per-type token breakdown from
gh-aw.tokens.*togen_ai.usage.*(agent span only) and removegh-aw.modelfrom span attributes. - Update/extend Vitest coverage to assert the new span kind and GenAI attributes on the agent span.
Show a summary per file
| File | Description |
|---|---|
| actions/setup/js/send_otlp_span.cjs | Adds gen_ai.* attributes + token usage to the agent span and changes its span kind to client. |
| actions/setup/js/send_otlp_span.test.cjs | Updates assertions to validate gen_ai.* attributes and the agent span kind, and moves token breakdown expectations to the agent span. |
Copilot's findings
Tip
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Files reviewed: 2/2 changed files
- Comments generated: 1
| // All gh-aw agent executions are chat-style LLM completions. | ||
| agentAttributes.push(buildAttr("gen_ai.operation.name", "chat")); | ||
| if (model) agentAttributes.push(buildAttr("gen_ai.request.model", model)); | ||
| // gen_ai.provider.name is the current Required attribute (replaces deprecated gen_ai.system). |
There was a problem hiding this comment.
The comment says gen_ai.provider.name is a Required attribute, but the code only sets it when engineId is present. Either make the attribute always present for agent spans (e.g., use a fallback like "unknown") or adjust the comment to reflect that it may be omitted when engine_id is unavailable (to avoid implying spec compliance that the implementation doesn't guarantee).
| // gen_ai.provider.name is the current Required attribute (replaces deprecated gen_ai.system). | |
| // Emit gen_ai.provider.name when engineId is available; it may be omitted when | |
| // engine metadata is unavailable, so this span does not guarantee full GenAI spec compliance. |
|
@copilot review all comments |
…e_id unavailable Agent-Logs-Url: https://github.com/github/gh-aw/sessions/ae987696-d9f6-41cb-9753-93ad59b563ea Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Addressed in |
- audit.md: document tokens-per-turn and tool calls/bash command breakdown in diff output (PR #28494) - frontmatter.md: add Observability section documenting observability.otlp configuration, object-form OTLP headers (PR #28524), and gen_ai.* span attribute conventions replacing gh-aw.* (PR #28511) - cli.md: update audit diff description to include new output fields (PR #28494) - cache-memory.md: document cache path misconfiguration detection via missing_data signal (PR #28516) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The
gh-aw.agent.agentspan stored model name and token counts under privategh-aw.*keys withSPAN_KIND_INTERNAL, making it invisible to standard GenAI dashboards in Grafana/Datadog/Honeycomb without custom attribute mappings.Changes
send_otlp_span.cjsSPAN_KIND_INTERNAL→SPAN_KIND_CLIENTgh-aw.model/gh-aw.tokens.*with standardgen_ai.*attributes, scoped exclusively to the agent span:gh-aw.modelgen_ai.request.modelgen_ai.operation.name="chat"(Required by spec)gen_ai.provider.name(fromengine_id)gen_ai.workflow.name(fromworkflow_name)gh-aw.tokens.inputgen_ai.usage.input_tokensgh-aw.tokens.outputgen_ai.usage.output_tokensgh-aw.tokens.cache_readgen_ai.usage.cache_read.input_tokensgh-aw.tokens.cache_writegen_ai.usage.cache_creation.input_tokensNo backward compatibility retained per issue guidance. The conclusion span is unaffected.
send_otlp_span.test.cjsgen_ai.usage.*on the agent spanSPAN_KIND_CLIENT,gen_ai.operation.name,gen_ai.request.model,gen_ai.provider.name, andgen_ai.workflow.name