fix(event-loop): ensure all cycle metrics include end time and duration#1903
Open
stephentreacy wants to merge 1 commit intostrands-agents:mainfrom
Open
fix(event-loop): ensure all cycle metrics include end time and duration#1903stephentreacy wants to merge 1 commit intostrands-agents:mainfrom
stephentreacy wants to merge 1 commit intostrands-agents:mainfrom
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
Fixes inaccurate event-loop cycle timing metrics when a cycle ends by recursing into another event_loop_cycle (e.g., after tool execution), ensuring cycle traces get end_time/duration recorded so aggregate response metrics (like total/average duration) are correct for multi-cycle invocations.
Changes:
- End tool-execution cycles’ metrics before deciding to stop or recurse, ensuring recursive paths still record
end_timeandduration. - Add a regression test covering the recursive-call scenario and asserting
end_cycleis invoked for both the tool cycle and the subsequent text cycle.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
src/strands/event_loop/event_loop.py |
Moves end_cycle so tool cycles are always finalized before recursion/stop logic. |
tests/strands/event_loop/test_event_loop.py |
Adds an async test to verify cycle-metrics finalization occurs in recursive tool-use flows. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
561
to
565
| tracer.end_event_loop_cycle_span(span=cycle_span, message=message, tool_result_message=tool_result_message) | ||
|
|
||
| agent.event_loop_metrics.end_cycle(cycle_start_time, cycle_trace) | ||
|
|
||
| if invocation_state["request_state"].get("stop_event_loop", False) or structured_output_context.stop_loop: |
Comment on lines
+1122
to
+1134
| with unittest.mock.patch.object(agent.event_loop_metrics, "end_cycle") as mock_end_cycle: | ||
| stream = strands.event_loop.event_loop.event_loop_cycle( | ||
| agent=agent, | ||
| invocation_state={"request_state": {}}, | ||
| ) | ||
| events = await alist(stream) | ||
|
|
||
| # Verify end_cycle was called once for tool cycle, once for text cycle | ||
| assert mock_end_cycle.call_count == 2 | ||
|
|
||
| # Verify the event loop completed successfully | ||
| tru_stop_reason, _, _, _, _, _ = events[-1]["stop"] | ||
| assert tru_stop_reason == "end_turn" |
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.
Description
Event loop cycle metrics (
end_timeandduration) were not being recorded for cycles that ended with a recursive call. This causedtotal_durationandaverage_cycle_timein the response metrics to be inaccurate, making it difficult to monitor agent performance in multi-cycle invocations.Response metric traces would like like this, where
total_durationis only including the Cycle 2 duration:{ "total_cycles": 2, "total_duration": 2.97, "traces": [ { "name": "Cycle 1", "start_time": 1772822921.485906, "end_time": null, "duration": null, "children": [ { "name": "stream_messages", "start_time": 1772822921.486195, "end_time": 1772822924.446701, "duration": 2.96 }, { "name": "Tool: tool_name", "start_time": 1772822924.447283, "end_time": 1772822931.842052, "duration": 7.39 }, { "name": "Recursive call", "start_time": 1772822931.842254, "end_time": 1772822934.810739, "duration": 2.97 } ] }, { "name": "Cycle 2", "start_time": 1772822931.842278, "end_time": 1772822934.810579, "duration": 2.97, "children": [ { "name": "stream_messages", "start_time": 1772822931.842385, "end_time": 1772822934.810402, "duration": 2.97 } ] } ] }Related Issues
Documentation PR
Type of Change
Bug fix
Testing
How have you tested the change? Verify that the changes do not break functionality or introduce warnings in consuming repositories: agents-docs, agents-tools, agents-cli
hatch run prepareTested locally with recursive call scenarios, verified cycle metrics now include accurate
end_timeanddurationvaluesCycle 1 duration includes all child durations except the recursive call.
{ "total_cycles": 2, "total_duration": 14.80, "traces": [ { "name": "Cycle 1", "start_time": 1772825264.482746, "end_time": 1772825275.644092, "duration": 11.16, "children": [ { "name": "stream_messages", "start_time": 1772825264.483011, "end_time": 1772825267.999054, "duration": 3.52 }, { "name": "Tool: tool_name", "start_time": 1772825268.000930, "end_time": 1772825275.643905, "duration": 7.64 }, { "name": "Recursive call", "start_time": 1772825275.644141, "end_time": 1772825279.281506, "duration": 3.64 } ] }, { "name": "Cycle 2", "start_time": 1772825275.644161, "end_time": 1772825279.281480, "duration": 3.64, "children": [ { "name": "stream_messages", "start_time": 1772825275.644274, "end_time": 1772825279.281442, "duration": 3.64 } ] } ] }Checklist
By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.