Repository navigation
Add gen_ai.agent.steps metric - #203
pvlsirotkin wants to merge 4 commits into
Conversation
|
|
7c3176b to
1d31b18
Compare
aefc0d6 to
d985496
Compare
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
Adds a new GenAI workflow metric (gen_ai.workflow.steps) to measure discrete step counts within a workflow execution, with corresponding schema snapshot, registry entry, and documentation updates.
Changes:
- Introduce
gen_ai.workflow.stepshistogram metric with agent/workflow dimensions. - Update generated schema snapshot to include the new metric.
- Extend GenAI metrics documentation and changelog to describe the new metric.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| schema-snapshot/registry.yaml | Adds the generated registry + refinements entries for gen_ai.workflow.steps. |
| model/gen-ai/metrics.yaml | Defines the new gen_ai.workflow.steps metric and its attributes. |
| docs/gen-ai/gen-ai-metrics.md | Documents gen_ai.workflow.steps and adds it to the TOC. |
| CHANGELOG.md | Notes addition of the new workflow steps metric. |
* Expand the `gen_ai.workflow.steps` 'step' definition with a list of what counts as a step in the most common frameworks (ADK events, LangGraph nodes, LangChain AgentAction/AgentFinish, CrewAI agent turns) and add a MUST-document requirement for instrumentations. Addresses trask's feedback that the original definition was too vague. * Standardize the conditionally_required phrasing for all three attributes on this metric (gen_ai.workflow.name, gen_ai.agent.name, gen_ai.agent.version) to 'If available.', matching the adjacent gen_ai.workflow.duration entry. Addresses Copilot's within-metric inconsistency comment.
* Expand the `gen_ai.workflow.steps` 'step' definition with a list of what counts as a step in the most common frameworks (ADK events, LangGraph nodes, LangChain AgentAction/AgentFinish, CrewAI agent turns) and add a MUST-document requirement for instrumentations. Addresses trask's feedback that the original definition was too vague. * Standardize the conditionally_required phrasing for all three attributes on this metric (gen_ai.workflow.name, gen_ai.agent.name, gen_ai.agent.version) to 'If available.', matching the adjacent gen_ai.workflow.duration entry. Addresses Copilot's within-metric inconsistency comment.
a5286d5 to
276a553
Compare
| code_generation: | ||
| metric_value_type: int | ||
| brief: 'Number of steps in a single GenAI workflow.' | ||
| note: | |
There was a problem hiding this comment.
Do we only count completed steps, or also include partial / failed steps too?
There was a problem hiding this comment.
New answer: tbc
Old answer: Both. The note now says: 'Steps are counted regardless of outcome: a step that errored or partially completed still consumed the agent's execution and SHOULD be counted.'
| This metric complements `gen_ai.workflow.duration` by giving operators | ||
| visibility into how "chatty" or compute-intensive a workflow is, and | ||
| is useful for capacity planning and regression detection across | ||
| versions. |
There was a problem hiding this comment.
assuming we were able to stamp workflow name on all nested spans and metrics emitted in the context of this workflow, we'd had
- count of agent invocations per workflow name
- count of tool calls per workflow name
- .. (any other metrics, e.g. if we instrumented transfers, we'd had a count of transfers)
Would this metric be still necessary?
In the current shape this metric seems to be an aggregation of multiple independent things which maybe also queried and sumed up individually, but then would provide better observability.
There was a problem hiding this comment.
With the refocus to per-agent scope (see summary) this is no longer a workflow-level aggregation. It's a per-invocation count of an agent's own steps — distinct from summing child signals because (a) not every event is independently traced, and (b) operators get a single histogram they can directly compute percentiles on rather than needing to sum multiple counters and join by attribute.
Adds a new GenAI semantic convention metric that measures the number of
discrete steps observed within a single GenAI workflow:
* gen_ai.workflow.steps (histogram, {step}): count of observable events
within one workflow execution. A 'step' is intentionally
framework-defined - it typically corresponds to one event (a tool
call, a tool result, a model response in ADK; a node execution in
LangGraph, etc.).
Dimensioned by gen_ai.workflow.name; when set, gen_ai.agent.name and
gen_ai.agent.version may be used to slice steps per-agent within a
workflow. In that case the count is restricted to events attributed to
that agent.
This metric is colocated with gen_ai.workflow.duration (added in open-telemetry#126)
in the model and docs so the two workflow-level metrics live together.
NOTE: docs/registry/ and schema-snapshot/ regeneration via 'make
generate-all' has NOT been run in this commit (no Docker available in
the authoring environment). Run it locally before pushing for review.
* Expand the `gen_ai.workflow.steps` 'step' definition with a list of what counts as a step in the most common frameworks (ADK events, LangGraph nodes, LangChain AgentAction/AgentFinish, CrewAI agent turns) and add a MUST-document requirement for instrumentations. Addresses trask's feedback that the original definition was too vague. * Standardize the conditionally_required phrasing for all three attributes on this metric (gen_ai.workflow.name, gen_ai.agent.name, gen_ai.agent.version) to 'If available.', matching the adjacent gen_ai.workflow.duration entry. Addresses Copilot's within-metric inconsistency comment.
The original RFC and the production ADK implementation always intended this metric to count steps a *specific agent* takes during a single invocation - not steps in some larger workflow. A previous revision of this PR moved the metric into the gen_ai.workflow.* namespace, which caused most of the confusion in the latest review round (multiple reviewers asked whether the metric is a per-invocation count or a cumulative workflow-level aggregation; whether nested sub-agent steps should be counted; whether workflow.name should be required given the name implies workflow scope). This commit refocuses the metric back on its intended scope: * Rename gen_ai.workflow.steps -> gen_ai.agent.steps. Lives in the gen_ai.agent.* namespace alongside gen_ai.agent.invocation.duration (open-telemetry#201). * Drop gen_ai.workflow.name and gen_ai.agent.version from the attribute list. The metric is now dimensioned only by gen_ai.agent.name (at 'recommended' level, matching open-telemetry#201/open-telemetry#202). * Add attributes.gen_ai.error ref_group (Mike's feedback). * Rewrite the metric note to spell out per-agent semantics: - Counts only events the agent itself authored (e.g. in ADK, events whose event.author equals the agent name). - Tool results are NOT counted (authored by tool, not agent). - Sub-agent steps are NOT counted (each step recorded once across the call tree - addresses aabmass' 'recorded exactly once' invariant). - Failed and partial steps still count (they consumed execution time - addresses Mike's question). - Step counts MUST NOT be compared across frameworks (addresses Mike's stronger-wording ask). - Concrete framework-specific definitions for ADK, LangGraph, LangChain agents, CrewAI, with a link to the adk.dev event-loop documentation (aabmass' suggestion). - Histogram bucket recommendation included in the YAML note (Mike's #M3 ask). * Restructure the docs/gen-ai/gen-ai-metrics.md page: remove gen_ai.agent.steps from the 'Generative AI workflow metrics' section and create a new 'Generative AI agent metrics' section. MD body kept thin; the metric note in YAML carries the full semantics and is rendered via the autogen block.
276a553 to
f4f0a4c
Compare
|
Big update on this PR after re-reading the original RFC and the production ADK implementation: the metric was always meant to count steps a specific agent takes during a single invocation, not steps in some larger workflow. An earlier revision of this PR pushed it into the Just pushed a commit that:
The MD page got a new Replying inline on each open thread. |
The bucket-boundaries recommendation was being rendered in two places: in the MD prose above the autogen block, and inside the YAML `note` (which gets rendered into the autogen block too). Other duration/usage metrics in this file keep ExplicitBucketBoundaries only in the MD prose by convention; aligned with that pattern. Net effect: the recommendation appears once, in the MD prose, like `gen_ai.workflow.duration`, `gen_ai.client.token.usage`, and the other existing metrics.
|
Hi! As part of #275, this repository switched to Towncrier changelog fragments to reduce merge conflicts in Please move this PR's changelog entry out of Create Add `gen_ai.agent.steps` metric to track the number of steps a GenAI agent takes during a single invocation.After adding the fragment, please remove this PR's direct edit to Thanks! |
| the workflow graph. | ||
| - **LangChain agents**: each `AgentAction` or `AgentFinish` step the | ||
| agent itself emitted. | ||
| - **CrewAI**: each agent turn the agent itself took within a task. |
There was a problem hiding this comment.
I did a bit of a research and I think this generalization would be confusing, it does not make sense to merge these things into one metric unless they are comparable:
- For ADK it would count LLM and tool calls, handoffs
- Langgraph has a notion of super-step which is "considered a single iteration over the graph nodes" (active ones). So by definition it's more than one node and
stepused in the metric name would be misleading. Langgraph also has configurablerecursion_limitfor number of super-steps andremaining_stepsin the step that provides number of remaining ones until limit is reached. This is a signal that these things could be meaningful to LangGraph users. - I can't find a term 'turn' in crewai, my AI found
iterationsin agent executor - https://github.com/crewAIInc/crewAI/blob/b6e5d632c111e098d883274f0a26f02836a2172e/lib/crewai/src/crewai/agents/crew_agent_executor.py#L218 and there is a corresponding config for max_interations, but iteration is a full ReAct loop. It has something calledstep_callbackbut does not clearly document when it's called.
I think this metric tries to capture something that's a proxy to number of loops / iterations within one agent, but tries to express it through internal frameowrk implementation details.
Some alternative approaches:
- Stamp agent name on the underlying llm and tool calls and derive average number of calls per agent from
gen_ai.inference | execute_tool.durationand invoke agent duration. This won't give outliers or percentiles, but arguably many loops / events also leads to long invoke_agent duration. - Measure
gen_ai.agent.inference_calls_per_invocation,gen_ai.agent.tool_calls_per_invocations,gen_ai.agent.transfers_per_invocation- these are understandable and generically applicable. The list can probably grow with retrievals and memory calls - Have specialized metrics for frameworks.
[gcp.]adk.event_loop.event.countwith attributes for author and type or[gcp].adk.event_loop.events_per_invocationwould be specific and understandable. Langgraph and crewai would have specialized metrics too
Approaches 1 and 2 can exist together: gen_ai.agent.inference_calls_per_invocation could be a common 'give me a sense of how long this agent invocation was' that shows up on common dashboards and [gcp].adk.event_loop.events_per_invocation can be a detailed breakdown. This would align with t-shaped signals approach.
|
Heads up — I'm OOO from today. @RKest will be taking this PR forward (he has push access to the branch on my fork). State of the PR:
Background context I'm leaving behind for @RKest:
Thanks everyone for the feedback so far. |
This comment has been minimized.
This comment has been minimized.
Following review feedback on open-telemetry#203, the single gen_ai.agent.steps metric conflated things that are not comparable across frameworks (LLM calls, tool calls, handoffs, framework-specific 'super-steps'/'iterations'), which made the 'step' unit misleading and framework-dependent. This replaces it with two understandable, generically-applicable per-invocation metrics: * gen_ai.agent.inference_calls_per_invocation (histogram, {inference_call}): number of inference (model) calls an agent makes during a single invocation. * gen_ai.agent.tool_calls_per_invocation (histogram, {tool_call}): number of tool calls an agent makes during a single invocation. Both are dimensioned by gen_ai.agent.name (recommended) and live in the gen_ai.agent.* namespace alongside gen_ai.invoke_agent.duration. Counts are scoped to a single invocation and counted exactly once across the call tree (sub-agent/transferred calls belong to those agents' invocations). Failed and partial calls still count. gen_ai.agent.transfers_per_invocation (also suggested in the review) is intentionally omitted: a transfer/handoff count is not a good measure of an agent's workflow complexity. The list can still grow later (e.g. retrievals, memory calls).
Following review feedback on open-telemetry#203, the single gen_ai.agent.steps metric conflated things that are not comparable across frameworks (LLM calls, tool calls, handoffs, framework-specific 'super-steps'/'iterations'), which made the 'step' unit misleading and framework-dependent. This replaces it with two understandable, generically-applicable per-invocation metrics: * gen_ai.agent.inference_calls_per_invocation (histogram, {inference_call}): number of inference (model) calls an agent makes during a single invocation. * gen_ai.agent.tool_calls_per_invocation (histogram, {tool_call}): number of tool calls an agent makes during a single invocation. Both are dimensioned by gen_ai.agent.name (recommended) and live in the gen_ai.agent.* namespace alongside gen_ai.invoke_agent.duration. Counts are scoped to a single invocation and counted exactly once across the call tree (sub-agent/transferred calls belong to those agents' invocations). Failed and partial calls still count. gen_ai.agent.transfers_per_invocation (also suggested in the review) is intentionally omitted: a transfer/handoff count is not a good measure of an agent's workflow complexity. The list can still grow later (e.g. retrievals, memory calls).
Following review feedback on open-telemetry#203, the single gen_ai.agent.steps metric conflated things that are not comparable across frameworks (LLM calls, tool calls, handoffs, framework-specific 'super-steps'/'iterations'), which made the 'step' unit misleading and framework-dependent. This replaces it with two understandable, generically-applicable per-invocation metrics: * gen_ai.agent.inference_calls_per_invocation (histogram, {inference_call}): number of inference (model) calls an agent makes during a single invocation. * gen_ai.agent.tool_calls_per_invocation (histogram, {tool_call}): number of tool calls an agent makes during a single invocation. Both are dimensioned by gen_ai.agent.name (recommended) and live in the gen_ai.agent.* namespace alongside gen_ai.invoke_agent.duration. Counts are scoped to a single invocation and counted exactly once across the call tree (sub-agent/transferred calls belong to those agents' invocations). Failed and partial calls still count. gen_ai.agent.transfers_per_invocation (also suggested in the review) is intentionally omitted: a transfer/handoff count is not a good measure of an agent's workflow complexity. The list can still grow later (e.g. retrievals, memory calls).
Following review feedback on open-telemetry#203, the single gen_ai.agent.steps metric conflated things that are not comparable across frameworks (LLM calls, tool calls, handoffs, framework-specific 'super-steps'/'iterations'), which made the 'step' unit misleading and framework-dependent. This replaces it with two understandable, generically-applicable per-invocation metrics: * gen_ai.agent.inference_calls_per_invocation (histogram, {inference_call}): number of inference (model) calls an agent makes during a single invocation. * gen_ai.agent.tool_calls_per_invocation (histogram, {tool_call}): number of tool calls an agent makes during a single invocation. Both are dimensioned by gen_ai.agent.name (recommended) and live in the gen_ai.agent.* namespace alongside gen_ai.invoke_agent.duration. Counts are scoped to a single invocation and counted exactly once across the call tree (sub-agent/transferred calls belong to those agents' invocations). Failed and partial calls still count. gen_ai.agent.transfers_per_invocation (also suggested in the review) is intentionally omitted: a transfer/handoff count is not a good measure of an agent's workflow complexity. The list can still grow later (e.g. retrievals, memory calls).
I went ahead and implemented this alternative in #336 |
|
I'm going to close this PR since it's continued in #336, feel free to reopen if necessary |
Following review feedback on open-telemetry#203, the single gen_ai.agent.steps metric conflated things that are not comparable across frameworks (LLM calls, tool calls, handoffs, framework-specific 'super-steps'/'iterations'), which made the 'step' unit misleading and framework-dependent. This replaces it with two understandable, generically-applicable per-invocation metrics: * gen_ai.invoke_agent.inference_calls (histogram, {inference_call}): number of inference (model) calls an agent makes during a single invocation. * gen_ai.invoke_agent.tool_calls (histogram, {tool_call}): number of tool calls an agent makes during a single invocation. Both are dimensioned by gen_ai.agent.name (recommended) and live in the gen_ai.invoke_agent.* namespace alongside gen_ai.invoke_agent.duration. Counts are scoped to a single invocation and counted exactly once across the call tree (sub-agent/transferred calls belong to those agents' invocations). Failed and partial calls still count. Both SHOULD be emitted together with the gen_ai.invoke_agent.internal span. A transfers/handoffs count (also suggested in the review) is intentionally omitted: it is not a good measure of an agent's workflow complexity. The list can still grow later (e.g. retrievals, memory calls).
Following review feedback on open-telemetry#203, the single gen_ai.agent.steps metric conflated things that are not comparable across frameworks (LLM calls, tool calls, handoffs, framework-specific 'super-steps'/'iterations'), which made the 'step' unit misleading and framework-dependent. This replaces it with two understandable, generically-applicable per-invocation metrics: * gen_ai.invoke_agent.inference_calls (histogram, {inference_call}): number of inference (model) calls an agent makes during a single invocation. * gen_ai.invoke_agent.tool_calls (histogram, {tool_call}): number of tool calls an agent makes during a single invocation. Both are dimensioned by gen_ai.agent.name (recommended) and live in the gen_ai.invoke_agent.* namespace alongside gen_ai.invoke_agent.duration. Counts are scoped to a single invocation and counted exactly once across the call tree (sub-agent/transferred calls belong to those agents' invocations). Failed and partial calls still count. Both SHOULD be emitted together with the gen_ai.invoke_agent.internal span. A transfers/handoffs count (also suggested in the review) is intentionally omitted: it is not a good measure of an agent's workflow complexity. The list can still grow later (e.g. retrievals, memory calls).
Following review feedback on open-telemetry#203, the single gen_ai.agent.steps metric conflated things that are not comparable across frameworks (LLM calls, tool calls, handoffs, framework-specific 'super-steps'/'iterations'), which made the 'step' unit misleading and framework-dependent. This replaces it with two understandable, generically-applicable per-invocation metrics: * gen_ai.invoke_agent.inference_calls (histogram, {inference_call}): number of inference (model) calls an agent makes during a single invocation. * gen_ai.invoke_agent.tool_calls (histogram, {tool_call}): number of tool calls an agent makes during a single invocation. Both are dimensioned by gen_ai.agent.name (recommended) and live in the gen_ai.invoke_agent.* namespace alongside gen_ai.invoke_agent.duration. Counts are scoped to a single invocation and counted exactly once across the call tree (sub-agent/transferred calls belong to those agents' invocations). Failed and partial calls still count. Both SHOULD be emitted together with the gen_ai.invoke_agent.internal span. A transfers/handoffs count (also suggested in the review) is intentionally omitted: it is not a good measure of an agent's workflow complexity. The list can still grow later (e.g. retrievals, memory calls).
Following review feedback on open-telemetry#203, the single gen_ai.agent.steps metric conflated things that are not comparable across frameworks (LLM calls, tool calls, handoffs, framework-specific 'super-steps'/'iterations'), which made the 'step' unit misleading and framework-dependent. This replaces it with two understandable, generically-applicable per-invocation metrics: * gen_ai.invoke_agent.inference_calls (histogram, {inference_call}): number of inference (model) calls an agent makes during a single invocation. * gen_ai.invoke_agent.tool_calls (histogram, {tool_call}): number of tool calls an agent makes during a single invocation. Both are dimensioned by gen_ai.agent.name (recommended) and live in the gen_ai.invoke_agent.* namespace alongside gen_ai.invoke_agent.duration. Counts are scoped to a single invocation and counted exactly once across the call tree (sub-agent/transferred calls belong to those agents' invocations). Failed and partial calls still count. Both SHOULD be emitted together with the gen_ai.invoke_agent.internal span. A transfers/handoffs count (also suggested in the review) is intentionally omitted: it is not a good measure of an agent's workflow complexity. The list can still grow later (e.g. retrievals, memory calls).
Specify explicit bucket boundaries for GenAI metrics histograms to align with OTel semconv updates: - open-telemetry/semantic-conventions-genai#201 - open-telemetry/semantic-conventions-genai#202 - open-telemetry/semantic-conventions-genai#203 PiperOrigin-RevId: 938553240
Semconv PR for this metric in: open-telemetry/semantic-conventions-genai#203 Was replaced by `gen_ai.invoke_agent.{inference,tool}_calls` metrics in: open-telemetry/semantic-conventions-genai#336 We're hence removing the non-standard and less defined `gen_ai.agent.workflow.steps` metric. Co-authored-by: Max Ind <maxind@google.com> PiperOrigin-RevId: 943154162
Following review feedback on open-telemetry#203, the single gen_ai.agent.steps metric conflated things that are not comparable across frameworks (LLM calls, tool calls, handoffs, framework-specific 'super-steps'/'iterations'), which made the 'step' unit misleading and framework-dependent. This replaces it with two understandable, generically-applicable per-invocation metrics: * gen_ai.invoke_agent.inference_calls (histogram, {inference_call}): number of inference (model) calls an agent makes during a single invocation. * gen_ai.invoke_agent.tool_calls (histogram, {tool_call}): number of tool calls an agent makes during a single invocation. Both are dimensioned by gen_ai.agent.name (recommended) and live in the gen_ai.invoke_agent.* namespace alongside gen_ai.invoke_agent.duration. Counts are scoped to a single invocation and counted exactly once across the call tree (sub-agent/transferred calls belong to those agents' invocations). Failed and partial calls still count. Both SHOULD be emitted together with the gen_ai.invoke_agent.internal span. A transfers/handoffs count (also suggested in the review) is intentionally omitted: it is not a good measure of an agent's workflow complexity. The list can still grow later (e.g. retrievals, memory calls).
…en-telemetry#336) Following review feedback on open-telemetry#203, the single gen_ai.agent.steps metric conflated things that are not comparable across frameworks (LLM calls, tool calls, handoffs, framework-specific 'super-steps'/'iterations'), which made the 'step' unit misleading and framework-dependent. This replaces it with two understandable, generically-applicable per-invocation metrics: * gen_ai.invoke_agent.inference_calls (histogram, {inference_call}): number of inference (model) calls an agent makes during a single invocation. * gen_ai.invoke_agent.tool_calls (histogram, {tool_call}): number of tool calls an agent makes during a single invocation. Both are dimensioned by gen_ai.agent.name (recommended) and live in the gen_ai.invoke_agent.* namespace alongside gen_ai.invoke_agent.duration. Counts are scoped to a single invocation and counted exactly once across the call tree (sub-agent/transferred calls belong to those agents' invocations). Failed and partial calls still count. Both SHOULD be emitted together with the gen_ai.invoke_agent.internal span. A transfers/handoffs count (also suggested in the review) is intentionally omitted: it is not a good measure of an agent's workflow complexity. The list can still grow later (e.g. retrievals, memory calls).
…en-telemetry#336) Following review feedback on open-telemetry#203, the single gen_ai.agent.steps metric conflated things that are not comparable across frameworks (LLM calls, tool calls, handoffs, framework-specific 'super-steps'/'iterations'), which made the 'step' unit misleading and framework-dependent. This replaces it with two understandable, generically-applicable per-invocation metrics: * gen_ai.invoke_agent.inference_calls (histogram, {inference_call}): number of inference (model) calls an agent makes during a single invocation. * gen_ai.invoke_agent.tool_calls (histogram, {tool_call}): number of tool calls an agent makes during a single invocation. Both are dimensioned by gen_ai.agent.name (recommended) and live in the gen_ai.invoke_agent.* namespace alongside gen_ai.invoke_agent.duration. Counts are scoped to a single invocation and counted exactly once across the call tree (sub-agent/transferred calls belong to those agents' invocations). Failed and partial calls still count. Both SHOULD be emitted together with the gen_ai.invoke_agent.internal span. A transfers/handoffs count (also suggested in the review) is intentionally omitted: it is not a good measure of an agent's workflow complexity. The list can still grow later (e.g. retrievals, memory calls).
Specify explicit bucket boundaries for GenAI metrics histograms to align with OTel semconv updates: - open-telemetry/semantic-conventions-genai#201 - open-telemetry/semantic-conventions-genai#202 - open-telemetry/semantic-conventions-genai#203 PiperOrigin-RevId: 938553240
Semconv PR for this metric in: open-telemetry/semantic-conventions-genai#203 Was replaced by `gen_ai.invoke_agent.{inference,tool}_calls` metrics in: open-telemetry/semantic-conventions-genai#336 We're hence removing the non-standard and less defined `gen_ai.agent.workflow.steps` metric. Co-authored-by: Max Ind <maxind@google.com> PiperOrigin-RevId: 943154162
Description
Adds a new GenAI semantic convention metric for the number of steps a GenAI
agent takes during a single invocation, modeled on the recently-merged
gen_ai.workflow.durationmetric(#126):
gen_ai.agent.steps(Histogram,{step}): number of discrete steps aGenAI agent takes during a single invocation.
The metric counts only steps the agent itself authored (e.g. in ADK, events
whose
event.authorequals the agent name). Tool results are not counted(authored by the tool, not the agent). Sub-agent steps are not counted (each
step is recorded exactly once across the full call tree). Failed and partial
steps still count — they consumed the agent's execution.
Step counts MUST NOT be compared across different frameworks; instrumentations
MUST document what counts as a step for their framework.
Motivation
The existing GenAI conventions describe agents and tools but offer no
standardized way to answer "how many steps did this agent take to produce
its response?" Operators today derive that figure ad-hoc from span counts,
which is fragile and depends on sampling configuration.
User journey: capacity planning, regression detection across agent versions,
and diagnosing pathological tool loops (an agent stuck calling tools without
making progress).
Checklist
changelog.d/(Towncrier fragment)See CONTRIBUTING.md.