Skip to content

feat: add rebased telemetry implementation#579

Open
lizradway wants to merge 5 commits intostrands-agents:mainfrom
lizradway:rebase
Open

feat: add rebased telemetry implementation#579
lizradway wants to merge 5 commits intostrands-agents:mainfrom
lizradway:rebase

Conversation

@lizradway
Copy link
Member

@lizradway lizradway commented Feb 26, 2026

Description

  • Add approved telemetry implementation from /liz/otel branch rebased with structured output changes
  • The only rebasing with real ramifications was done under agent.ts

Differences between /liz/otel branch :

Structural: _executeAgentLoop inlined into _stream

  • The original branch extracted the agent loop into a separate _executeAgentLoop method, with _stream handling the agent span lifecycle around it.
  • After rebase, structured output's context.registerTool() / context.cleanup() must wrap the loop, and the agent span must wrap both.
  • Keeping them as separate methods would require threading the structured output context through or modifying scoping.
  • Inlining the loop into _stream keeps a single try/finally that handles both telemetry span cleanup and structured output cleanup.
  • Structured output logic and telemetry logic should be extracted out in a follow up as we consider modularization of the agent loop similarly to Python

Similarly:

  • The original branch returned result from _executeAgentLoop and passed it to endAgentSpan in _stream's finally.
  • With the loop inlined, result is declared as let result: AgentResult | undefined at the top of _stream so the finally block can reference it for the agent span's response/stopReason attributes.

Force tool continue

  • Structured output introduces a continue path (when forcing the model to use the structured output tool see line 473).
  • The inner try/catch around each cycle only catches errors, so continue would skip endAgentLoopSpan. Added an explicit endAgentLoopSpan(cycleSpan) before the continue to prevent span leaks.
  • Added test coverage for this interaction and other structured output interactions

_appendMessage is synchronous/ returns event for yielding

  • The original /liz/otel branch had async _appendMessage that invoked hooks directly.
  • Main's event wrapper PR changed this to a synchronous method that returns a MessageAddedEvent for yielding — hooks are invoked centrally in stream(). The rebase uses the current synchronous pattern.

Related Issues

#69

Documentation PR

strands-agents/docs#557

Type of Change

New feature

Testing

How have you tested the change?

  • I ran npm run check

Checklist

  • I have read the CONTRIBUTING document
  • I have added any necessary tests that prove my fix is effective or my feature works
  • I have updated the documentation accordingly
  • I have added an appropriate example to the documentation to outline the feature, or no new docs are needed
  • My changes generate no new warnings
  • Any dependent changes have been merged and published

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

@lizradway lizradway marked this pull request as draft February 26, 2026 21:29
@lizradway lizradway marked this pull request as ready for review February 27, 2026 17:28
Comment on lines +437 to +447
private _setAttributes(span: Span, attributes: Record<string, AttributeValue>): void {
for (const [key, value] of Object.entries(attributes)) {
if (value !== undefined && value !== null) {
try {
span.setAttribute(key, value)
} catch (err) {
logger.warn(`error=<${err}>, key=<${key}> | failed to set span attribute`)
}
}
}
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can remove this and use setAttributes from the span API.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants