fix(agno): split tool-call loops into react steps#240
Conversation
ralf0131
left a comment
There was a problem hiding this comment.
Summary
Refactors Agno instrumentation to split tool-call loops into individual ReAct step spans (one LLM span per provider request), with contextvar-based run-state tracking and token-usage fallback from child LLM spans. Well-structured, follows existing patterns, and includes comprehensive test coverage (sync/async, stream/non-stream, direct model call).
Findings
- [Info]
_wrapper.py:643— Dead code in_response_for_llm_finish: theifcondition is redundant since both branches returnassistant_message. See inline comment.
Suggestions
The dead conditional in _response_for_llm_finish can be simplified. If the original intent was to validate assistant_message attributes before returning it, consider returning None in the else branch or removing the conditional entirely.
Automated review by github-manager-bot
ralf0131
left a comment
There was a problem hiding this comment.
Summary
Re-review after new commit fbc32a18 (latency test coverage). The added latency tests correctly validate that LLM spans cover provider latency (≥25ms for 30ms delay) and that direct Model.response calls without agent context do not emit ReAct step spans. The 5-layer span tree assertion (session > turn > step > {llm, tool}) is well-structured.
The previously noted [Info] finding in _response_for_llm_finish (redundant conditional — both branches return assistant_message) is still present. This is non-blocking; recommend cleaning up in a follow-up.
Overall the implementation is solid: ContextVar-based state coordination is clean, the fallback to outer Model.response wrappers for older Agno versions is well-handled, and test coverage is comprehensive.
Automated review by github-manager-bot
ralf0131
left a comment
There was a problem hiding this comment.
Summary
Refactors Agno 2.x tool-call loop instrumentation to emit one chat span per provider request under a ReAct step, instead of wrapping the entire model response loop as a single LLM span. Uses Agno's per-request processing hooks (_process_model_response, process_response_stream, etc.) when available, with a clean fallback to outer Model.response wrappers for older versions. Streaming agent token totals now fall back to summing child LLM spans when Agno doesn't expose final run metrics.
Findings
No issues found. The implementation is solid:
_wrap_model_methodsfeature detection cleanly prefers inner hooks, falling back with a warning when unavailable_AgnoRunState+ContextVarproperly tracks react round, active step, and accumulated token usage per run- State lifecycle is correctly managed in try/except/finally across sync, async, and streaming paths
_is_stream_closecheck correctly handles the edge case where stream closure triggers finally without a real error- Token fallback (
_apply_agent_token_fallback) only activates when Agno metrics are None, avoiding double-counting _uninstrumentproperly unwraps both inner and fallback wrappers via_unwrap_if_present- Excellent test coverage: sync/async/stream/async-stream tool-call loops, latency coverage verification, direct model call (no react step), token aggregation from child spans
CI: all checks passing. Changelog updated. CLA: signed.
Automated review by github-manager-bot
Description
This fixes Agno 2.x tool-call loop instrumentation so every real model provider request is emitted as its own
chatspan under a ReAct step, instead of wrapping the whole Agno model response loop as one LLM span.The change keeps direct
Model.responseusage covered through a fallback wrapper, but uses Agno's per-request processing hooks when they are available. Streaming agent token totals now fall back to the sum of child LLM spans when Agno does not expose final run metrics.Fixes no existing issue.
Type of change
How Has This Been Tested?
Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration
tox -c tox-loongsuite.ini -e py311-test-loongsuite-instrumentation-agno -- -qtox -c tox-loongsuite.ini -e py39-test-loongsuite-instrumentation-agno,py313-test-loongsuite-instrumentation-agno -- -qtox -c tox-loongsuite.ini -e lint-loongsuite-instrumentation-agnotox -e precommitpython "$PIPELINE_SKILL_DIR/scripts/check_loongsuite_pr_readiness.py" --repo .Validation Evidence
Spec and Scope
loongsuite-instrumentation-agnoinstrumentation hooks, span/token aggregation logic, and focused Agno testsLocal Checks
python "$PIPELINE_SKILL_DIR/scripts/check_loongsuite_pr_readiness.py" --repo .tox -e precommittox -c tox-loongsuite.ini -e py311-test-loongsuite-instrumentation-agno -- -qtox -c tox-loongsuite.ini -e py39-test-loongsuite-instrumentation-agno,py313-test-loongsuite-instrumentation-agno -- -qtox -c tox-loongsuite.ini -e lint-loongsuite-instrumentation-agnoReal E2E Matrix
Agent.arun(stream=True)smokeTelemetry and Weaver
weaver registry live-check --advice-profile loongsuite-genai ...CI
Does This PR Require a Core Repo Change?
Checklist:
See contributing.md for styleguide, changelog guidelines, and more.