Skip to content

Commit 10555be

Browse files
authored
refactor: Remove _remove_dangling_messages from SlidingWindowConversationManager (#418)
1 parent bd15b04 commit 10555be

File tree

2 files changed

+9
-44
lines changed

2 files changed

+9
-44
lines changed

src/strands/agent/conversation_manager/sliding_window_conversation_manager.py

Lines changed: 2 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -58,21 +58,15 @@ def __init__(self, window_size: int = 40, should_truncate_results: bool = True):
5858
def apply_management(self, agent: "Agent", **kwargs: Any) -> None:
5959
"""Apply the sliding window to the agent's messages array to maintain a manageable history size.
6060
61-
This method is called after every event loop cycle, as the messages array may have been modified with tool
62-
results and assistant responses. It first removes any dangling messages that might create an invalid
63-
conversation state, then applies the sliding window if the message count exceeds the window size.
64-
65-
Special handling is implemented to ensure we don't leave a user message with toolResult
66-
as the first message in the array. It also ensures that all toolUse blocks have corresponding toolResult
67-
blocks to maintain conversation coherence.
61+
This method is called after every event loop cycle to apply a sliding window if the message count
62+
exceeds the window size.
6863
6964
Args:
7065
agent: The agent whose messages will be managed.
7166
This list is modified in-place.
7267
**kwargs: Additional keyword arguments for future extensibility.
7368
"""
7469
messages = agent.messages
75-
self._remove_dangling_messages(messages)
7670

7771
if len(messages) <= self.window_size:
7872
logger.debug(
@@ -81,37 +75,6 @@ def apply_management(self, agent: "Agent", **kwargs: Any) -> None:
8175
return
8276
self.reduce_context(agent)
8377

84-
def _remove_dangling_messages(self, messages: Messages) -> None:
85-
"""Remove dangling messages that would create an invalid conversation state.
86-
87-
After the event loop cycle is executed, we expect the messages array to end with either an assistant tool use
88-
request followed by the pairing user tool result or an assistant response with no tool use request. If the
89-
event loop cycle fails, we may end up in an invalid message state, and so this method will remove problematic
90-
messages from the end of the array.
91-
92-
This method handles two specific cases:
93-
94-
- User with no tool result: Indicates that event loop failed to generate an assistant tool use request
95-
- Assistant with tool use request: Indicates that event loop failed to generate a pairing user tool result
96-
97-
Args:
98-
messages: The messages to clean up.
99-
This list is modified in-place.
100-
"""
101-
# remove any dangling user messages with no ToolResult
102-
if len(messages) > 0 and is_user_message(messages[-1]):
103-
if not any("toolResult" in content for content in messages[-1]["content"]):
104-
messages.pop()
105-
106-
# remove any dangling assistant messages with ToolUse
107-
if len(messages) > 0 and is_assistant_message(messages[-1]):
108-
if any("toolUse" in content for content in messages[-1]["content"]):
109-
messages.pop()
110-
# remove remaining dangling user messages with no ToolResult after we popped off an assistant message
111-
if len(messages) > 0 and is_user_message(messages[-1]):
112-
if not any("toolResult" in content for content in messages[-1]["content"]):
113-
messages.pop()
114-
11578
def reduce_context(self, agent: "Agent", e: Optional[Exception] = None, **kwargs: Any) -> None:
11679
"""Trim the oldest messages to reduce the conversation context size.
11780

tests/strands/agent/test_conversation_manager.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -58,21 +58,21 @@ def conversation_manager(request):
5858
{"role": "user", "content": [{"toolResult": {"toolUseId": "123", "content": [], "status": "success"}}]},
5959
],
6060
),
61-
# 2 - Remove dangling user message with no tool result
61+
# 2 - Keep user message
6262
(
6363
{"window_size": 2},
6464
[
6565
{"role": "user", "content": [{"text": "Hello"}]},
6666
],
67-
[],
67+
[{"role": "user", "content": [{"text": "Hello"}]}],
6868
),
69-
# 3 - Remove dangling assistant message with tool use
69+
# 3 - Keep dangling assistant message with tool use
7070
(
7171
{"window_size": 3},
7272
[
7373
{"role": "assistant", "content": [{"toolUse": {"toolUseId": "123", "name": "tool1", "input": {}}}]},
7474
],
75-
[],
75+
[{"role": "assistant", "content": [{"toolUse": {"toolUseId": "123", "name": "tool1", "input": {}}}]}],
7676
),
7777
# 4 - Remove dangling assistant message with tool use - User tool result remains
7878
(
@@ -83,6 +83,7 @@ def conversation_manager(request):
8383
],
8484
[
8585
{"role": "user", "content": [{"toolResult": {"toolUseId": "123", "content": [], "status": "success"}}]},
86+
{"role": "assistant", "content": [{"toolUse": {"toolUseId": "123", "name": "tool1", "input": {}}}]},
8687
],
8788
),
8889
# 5 - Remove dangling assistant message with tool use and user message without tool result
@@ -95,8 +96,9 @@ def conversation_manager(request):
9596
{"role": "assistant", "content": [{"toolUse": {"toolUseId": "123", "name": "tool1", "input": {}}}]},
9697
],
9798
[
98-
{"role": "user", "content": [{"text": "First"}]},
9999
{"role": "assistant", "content": [{"text": "First response"}]},
100+
{"role": "user", "content": [{"text": "Use a tool"}]},
101+
{"role": "assistant", "content": [{"toolUse": {"toolUseId": "123", "name": "tool1", "input": {}}}]},
100102
],
101103
),
102104
# 6 - Message count above max window size - Basic drop

0 commit comments

Comments
 (0)