Repository navigation
LOU-D9: OpenTelemetry GenAI semantic conventions and traced flows - #57
Merged
Merged
Conversation
Spans used ad-hoc names (agent.run, llm.generate, tool.call, model,
promptTokens, ...), so GenAI-aware backends could not recognise them, and
flows were not traced at all.
- Agent runs are now `invoke_agent {name}` (INTERNAL), model calls
`chat {model}` (CLIENT), tool calls `execute_tool {tool}` (INTERNAL), with
the gen_ai.* attributes from the current spec (gen_ai.provider.name,
gen_ai.request.*, gen_ai.response.*, gen_ai.usage.*, gen_ai.tool.*,
gen_ai.agent.*, gen_ai.conversation.id) plus error.type and span status.
- All names live in src/execution/semconv.ts (spec URL, retrieval date and
Development stability noted there); span construction in genAiSpans.ts.
- The previous attribute names are still emitted (dual-emit) and documented
as deprecated in docs/observability.md. Span names changed, as the spec
requires; agent-forge's trace panel now keys off gen_ai.operation.name.
- Content (gen_ai.input/output.messages, system_instructions,
tool.call.arguments/result) is never recorded unless `captureContent: true`
(or OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT=true).
- Span gains optional `kind` and `status`; createOtelTraceExporter maps them
to OTel SpanKind/ERROR status and passes string[] attributes through.
- FlowExecutor wraps a run (`invoke_workflow {name}`) and every node
(`flow.node {type}`) in spans, parents the chat/execute_tool spans under
their node, and nests under `parentSpanId` when given.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
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.
What
Spans now follow the OpenTelemetry GenAI semantic conventions, and flows are traced.
invoke_agent {name}(INTERNAL) >chat {model}(CLIENT) /execute_tool {tool}(INTERNAL), withgen_ai.operation.name,gen_ai.provider.name,gen_ai.agent.*,gen_ai.conversation.id,gen_ai.request.model|temperature|max_tokens,gen_ai.response.model|finish_reasons,gen_ai.usage.input_tokens|output_tokens,gen_ai.tool.name|call.id|description|type, pluserror.typeand span ERROR status.gen_ai.input.messages,gen_ai.output.messages,gen_ai.system_instructions,gen_ai.tool.call.arguments|result) is only recorded withcaptureContent: true(orOTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT=true).docs/observability.mdwith an old -> new table.FlowExecutor:invoke_workflow {flow}run span,flow.node {type}per node, chat/execute_tool spans parented under their node;parentSpanIdnests a run under an agent span.src/execution/semconv.ts(spec URL, retrieval 2026-10-01, Development stability).Spangains optionalkind/status;createOtelTraceExportermaps them to OTel SpanKind and ERROR status and passesstring[]attributes through.Why
Ad-hoc attribute names did not light up GenAI-aware backends; flows were invisible.
How verified
npx tsc --noEmit: cleannpm run lint: 0 errors (433 warnings, all pre-existing categories; none added in new files)npm run buildand create-loushy-agent build: successnpm run test:coverage: Test Files 105 passed, Tests 1420 passed | 3 skippednpm run fallow: exit 0, no issues, no duplicationnpm run docs:verify-snippets: all 44 snippets type-check, 6 also runnpm run example:tracing:console: runs, emits the new span treeNotes for reviewer
gen_ai.operation.name.input,prompt,args,result) keep their previous behavior (recorded unlessredactContent), since existing tests encode it. Only the newgen_ai.*content is opt-in. Flipping the legacy default would be a breaking change worth its own ticket.AgentExecutor.tsare limited to theexecute()span wrapper andrunToolCallInSpan;generateStep.tsholds the model-call span.gen_ai.response.modelis only set when the provider'srawResponseexposes a model id.🤖 Generated with Claude Code