fix: enforce that the first message is a user message in the sliding window conversation manager#2087
fix: enforce that the first message is a user message in the sliding window conversation manager#2087JackYPCOnline wants to merge 1 commit intostrands-agents:mainfrom
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
|
Issue: This PR includes unrelated changes beyond the sliding window fix. The branch diff against
Suggestion: Split these into separate PRs — one per logical change. Bundling unrelated changes makes it harder to review, bisect regressions, and revert individual fixes if needed. |
src/strands/agent/conversation_manager/sliding_window_conversation_manager.py
Show resolved
Hide resolved
src/strands/agent/conversation_manager/sliding_window_conversation_manager.py
Show resolved
Hide resolved
|
Assessment: Comment The core sliding window fix is solid — the role guard, short-circuit logic correction, and graceful no-op path are all correct and well-tested. The PR description is excellent with clear root cause analysis. Review Categories
The bug fix logic itself is clean and aligns with the TypeScript SDK. Nice work identifying and fixing both the primary role-check bug and the secondary short-circuit issue. |
dd30607 to
9b9f372
Compare
|
Assessment: Approve All feedback from the previous review has been addressed. The fix is correct, well-tested, and cleanly documented. Changes Since Last Review
|
Description
SlidingWindowConversationManager can produce a trimmed conversation that starts with an assistant message instead of a user message. Many model providers (including Amazon Bedrock with Nova) require conversations to begin with a user message, causing ValidationException: A conversation must start with a user message.
Root cause: The trim-point validation loop checked for orphaned toolResult and toolUse constraints but never verified that the first remaining message has role == "user".
Secondary bug: A short-circuit evaluation in the toolUse guard let an orphaned toolUse at the last message slip through as a valid trim point:
This matches the fix already applied in the TypeScript SDK.
###Changes:
Added role != "user" check as the first condition in the trim-point validation loop
Fixed the toolUse short-circuit logic to match the TypeScript SDK behavior
When no valid trim point exists during routine window management (e=None), log a warning and return instead of raising ContextWindowOverflowException — the exception is now only raised when triggered by an actual context overflow error
Why existing tests changed:
Several parametrized test_apply_management cases (5, 7, 8, 9) expected trimmed conversations starting with an assistant message — this was the bug itself. Updated expected outputs to reflect valid user-first trim points, which may keep fewer messages than window_size when no closer valid trim point exists.
test_sliding_window_conversation_manager_with_untrimmable_history_raises_context_window_overflow_exception called apply_management (routine path, e=None) and expected ContextWindowOverflowException. Updated to call reduce_context with an explicit error to test the overflow path. Added a companion test verifying apply_management gracefully no-ops in the same scenario.
test_agent_with_session_and_conversation_manager used window_size=1 with a [user, assistant] conversation. With the fix, there is no valid trim point that preserves a user-first start, so the messages are left unchanged. Updated to use window_size=2 with multiple invocations to properly exercise trimming with session persistence.
Related Issues
#2085
Documentation PR
Type of Change
Bug fix
New feature
Breaking change
Documentation update
Other (please describe):
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 prepareChecklist
By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.