Renders a Mimir.Event as OpenTelemetry attributes. This is the one place
Mimir's events meet the OpenTelemetry GenAI vocabulary.
render/1 returns %{type: String.t(), attributes: %{optional(String.t()) => term()}}. type is the domain string ("llm", "agent" or "workflow").
Conventions
The gen_ai.* attribute names follow the OpenTelemetry GenAI semantic conventions as read at
open-telemetry/semantic-conventions-genai@4f85037:
docs/gen-ai/gen-ai-agent-spans.md, and the gen_ai.operation.name
registry in model/gen-ai/registry.yaml. The conventions have Development
status. At that commit, gen_ai.operation.name takes eighteen values, grouped
here for reading:
- inference:
chat,generate_content,text_completion,embeddings,retrieval,fetch_response - agents:
create_agent,invoke_agent,plan,execute_tool - workflows:
invoke_workflow, with the workflow named bygen_ai.workflow.name - memory:
search_memory,create_memory,update_memory,upsert_memory,delete_memory,create_memory_store,delete_memory_store
render/1 itself sets only invoke_agent.
llm
:usage with a usage map, :tool_call with a tool map, and :reasoning
render exactly what the retired Mimir.TurnEvents.GenAI builders produced:
gen_ai.usage.input_tokens and gen_ai.usage.output_tokens; gen_ai.tool.name
and gen_ai.tool.call.id, with the call-id key present even when the id is
nil; and a bare milestone key, with no gen_ai. prefix, defaulting to "".
test/support/fixtures/gen_ai_compat/ holds those shapes as captured from
the old builders.
Every other llm event, :tool_result included and :usage or :tool_call
without its map, exports raw with its keys stringified.
agent
Every agent event renders gen_ai.operation.name as invoke_agent, and
session_id, when set, as gen_ai.conversation.id. :session_open and
:session_reattach both invoke an agent that exists or is brokered for the
session; create_agent describes agent creation, usually in a remote agent
service, which neither event records.
:turn_start, :turn_end, :terminal and :error are moments within one
invocation and have no operation name of their own. They add
mimir.agent.event, holding the event type.
workflow
Workflow events render mimir.workflow.event (the event type) and, when set,
mimir.workflow.id and mimir.workflow.step_id. They carry no gen_ai.*
attribute. That is a choice, not a gap in the conventions, which define
invoke_workflow and gen_ai.workflow.name: workflow events stay on
mimir.workflow.* until an ingest consumes them, so that the emitter changes
alongside a consumer it can be tested against.
mimir.path
An event with a non-empty path adds mimir.path to any domain's
attributes: its frames joined with /, for example
"workflow:wf_123/workflow_step:step_5/agent:sess_9". An event with an empty
path renders without it.
Summary
Functions
@spec render(Mimir.Event.t()) :: %{ type: String.t(), attributes: %{optional(String.t()) => term()} }