Skip to content

Commit 3c8a0b1

Browse files
committed
summarize conversation - assistant to user role
1 parent a7ea053 commit 3c8a0b1

File tree

4 files changed

+45
-51
lines changed

4 files changed

+45
-51
lines changed

src/strands/agent/conversation_manager/summarizing_conversation_manager.py

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
"""Summarizing conversation history management with configurable options."""
22

33
import logging
4-
from typing import TYPE_CHECKING, Any, List, Optional
4+
from typing import TYPE_CHECKING, Any, List, Optional, cast
55

66
from typing_extensions import override
77

@@ -81,7 +81,6 @@ def __init__(
8181
self.summarization_agent = summarization_agent
8282
self.summarization_system_prompt = summarization_system_prompt
8383
self._summary_message: Optional[Message] = None
84-
self._summary_prompt: Message = {"content": [{"text": "Please summarize this conversation"}], "role": "user"}
8584

8685
@override
8786
def restore_from_session(self, state: dict[str, Any]) -> Optional[list[Message]]:
@@ -95,7 +94,7 @@ def restore_from_session(self, state: dict[str, Any]) -> Optional[list[Message]]
9594
"""
9695
super().restore_from_session(state)
9796
self._summary_message = state.get("summary_message")
98-
return [self._summary_prompt, self._summary_message] if self._summary_message else None
97+
return [self._summary_message] if self._summary_message else None
9998

10099
def get_state(self) -> dict[str, Any]:
101100
"""Returns a dictionary representation of the state for the Summarizing Conversation Manager."""
@@ -153,15 +152,15 @@ def reduce_context(self, agent: "Agent", e: Optional[Exception] = None, **kwargs
153152

154153
# Keep track of the number of messages that have been summarized thus far.
155154
self.removed_message_count += len(messages_to_summarize)
156-
# If there is a summary message, don't count it or the summary prompt in the removed_message_count.
155+
# If there is a summary message, don't count it in the removed_message_count.
157156
if self._summary_message:
158-
self.removed_message_count -= 2
157+
self.removed_message_count -= 1
159158

160159
# Generate summary
161160
self._summary_message = self._generate_summary(messages_to_summarize, agent)
162161

163162
# Replace the summarized messages with the summary
164-
agent.messages[:] = [self._summary_prompt, self._summary_message] + remaining_messages
163+
agent.messages[:] = [self._summary_message] + remaining_messages
165164

166165
except Exception as summarization_error:
167166
logger.error("Summarization failed: %s", summarization_error)
@@ -201,8 +200,8 @@ def _generate_summary(self, messages: List[Message], agent: "Agent") -> Message:
201200
summarization_agent.messages = messages
202201

203202
# Use the agent to generate summary with rich content (can use tools if needed)
204-
result = summarization_agent(self._summary_prompt["content"])
205-
return result.message
203+
result = summarization_agent("Please summarize this conversation")
204+
return cast(Message, {**result.message, "role": "user"})
206205

207206
finally:
208207
# Restore original agent state

tests/strands/agent/test_summarizing_conversation_manager.py

Lines changed: 26 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -95,16 +95,13 @@ def test_reduce_context_with_summarization(summarizing_manager, mock_agent):
9595

9696
summarizing_manager.reduce_context(mock_agent)
9797

98-
# Should have: 1 summary prompt + 1 summary message + 2 preserved recent messages + remaining from summarization
99-
assert len(mock_agent.messages) == 5
98+
# Should have: 1 summary message + 2 preserved recent messages + remaining from summarization
99+
assert len(mock_agent.messages) == 4
100100

101-
# First message should be the summary prompt
102-
assert mock_agent.messages[0] == {"content": [{"text": "Please summarize this conversation"}], "role": "user"}
103-
# Second message should be the summary
104-
assert mock_agent.messages[1] == {
105-
"content": [{"text": "This is a summary of the conversation."}],
106-
"role": "assistant",
107-
}
101+
# First message should be the summary
102+
assert mock_agent.messages[0]["role"] == "user"
103+
first_content = mock_agent.messages[0]["content"][0]
104+
assert "text" in first_content and "This is a summary of the conversation." in first_content["text"]
108105

109106
# Recent messages should be preserved
110107
assert "Message 3" in str(mock_agent.messages[-2]["content"])
@@ -437,18 +434,17 @@ def test_reduce_context_tool_pair_adjustment_works_with_forward_search():
437434
# messages_to_summarize_count = (3 - 1) * 0.5 = 1
438435
# But split point adjustment will move forward from the toolUse, potentially increasing count
439436
manager.reduce_context(mock_agent)
440-
# Should have summary prompt + summary + remaining messages
441-
assert len(mock_agent.messages) == 3
442-
443-
# First message should be the summary prompt
444-
assert mock_agent.messages[0] == {"content": [{"text": "Please summarize this conversation"}], "role": "user"}
445-
# Second message should be the summary
446-
assert mock_agent.messages[1] == {
447-
"content": [{"text": "This is a summary of the conversation."}],
448-
"role": "assistant",
449-
}
437+
# Should have summary + remaining messages
438+
assert len(mock_agent.messages) == 2
439+
440+
# First message should be the summary
441+
assert mock_agent.messages[0]["role"] == "user"
442+
summary_content = mock_agent.messages[0]["content"][0]
443+
assert "text" in summary_content and "This is a summary of the conversation." in summary_content["text"]
444+
450445
# Last message should be the preserved recent message
451-
assert mock_agent.messages[2] == {"content": [{"text": "Latest message"}], "role": "user"}
446+
assert mock_agent.messages[1]["role"] == "user"
447+
assert mock_agent.messages[1]["content"][0]["text"] == "Latest message"
452448

453449

454450
def test_adjust_split_point_exceeds_message_length(summarizing_manager):
@@ -594,19 +590,21 @@ def test_summarizing_conversation_manager_properly_records_removed_message_count
594590
assert manager.removed_message_count == 0
595591

596592
manager.reduce_context(agent)
593+
# Assert the oldest message is the sumamry message
597594
assert manager._summary_message["content"][0]["text"] == "Summary"
598595
# There are 8 messages in the agent messages array, since half will be summarized,
599-
# 4 will remain plus 1 summary prompt and 1 summary message = 6
600-
assert len(agent.messages) == 6
596+
# 4 will remain plus 1 summary message = 5
597+
assert (len(agent.messages)) == 5
601598
# Half of the messages were summarized and removed: 8/2 = 4
602599
assert manager.removed_message_count == 4
603600

604601
manager.reduce_context(agent)
605602
assert manager._summary_message["content"][0]["text"] == "Summary"
606-
# After the first summary, 6 messages remain. Summarizing again will lead to:
607-
# 6 - (6/2) (messages to be sumamrized) + 1 (summary prompt) + 1 (new summary message) = 6 - 3 + 1 + 1 = 5
608-
assert len(agent.messages) == 5
609-
# Half of the messages were summarized and removed: (6/2) = 3
610-
# However, the summary prompt and previous summary were also summarized but we don't count this in the total:
611-
# 4 (Previously removed messages) + 3 (removed messages) - 1 (summary prompt) - 1 (Previous summary message) = 5
603+
# After the first summary, 5 messages remain. Summarizing again will lead to:
604+
# 5 - (int(5/2)) (messages to be sumamrized) + 1 (new summary message) = 5 - 2 + 1 = 4
605+
assert (len(agent.messages)) == 4
606+
# Half of the messages were summarized and removed: int(5/2) = 2
607+
# However, one of the messages that was summarized was the previous summary message,
608+
# so we dont count this toward the total:
609+
# 4 (Previously removed messages) + 2 (removed messages) - 1 (Previous summary message) = 5
612610
assert manager.removed_message_count == 5

tests/strands/session/test_repository_session_manager.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -151,10 +151,10 @@ def test_initialize_restores_existing_agent_with_summarizing_conversation_manage
151151

152152
# Verify agent state restored
153153
assert agent.state.get("key") == "value"
154-
# The session message plus the summary prompt plus the summary message
155-
assert len(agent.messages) == 3
156-
assert agent.messages[2] == {"content": [{"text": "Hello"}], "role": "user"}
157-
assert agent.conversation_manager.removed_message_count == 1
154+
# The session message plus the summary message
155+
assert len(agent.messages) == 2
156+
assert agent.messages[1]["role"] == "user"
157+
assert agent.messages[1]["content"][0]["text"] == "Hello"
158158

159159

160160
def test_append_message(session_manager):

tests_integ/test_summarizing_conversation_manager_integration.py

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -151,19 +151,16 @@ def test_summarization_with_context_overflow(model):
151151

152152
# Verify summarization occurred
153153
assert len(agent.messages) < initial_message_count
154-
# Should have: 1 summary prompt + 1 summary + remaining messages
154+
# Should have: 1 summary + remaining messages
155155
# With 6 messages, summary_ratio=0.5, preserve_recent_messages=2:
156156
# messages_to_summarize = min(6 * 0.5, 6 - 2) = min(3, 4) = 3
157-
# So we summarize 3 messages, leaving 3 remaining + 1 summary prompt + 1 summary = 5 total
158-
expected_total_messages = 5
157+
# So we summarize 3 messages, leaving 3 remaining + 1 summary = 4 total
158+
expected_total_messages = 4
159159
assert len(agent.messages) == expected_total_messages
160160

161-
# First message should be the summary prompt
162-
summary_prompt = agent.messages[0]
163-
assert summary_prompt == {"content": [{"text": "Please summarize this conversation"}], "role": "user"}
164-
# Second message should be the summary
165-
summary_message = agent.messages[1]
166-
assert summary_message["role"] == "assistant"
161+
# First message should be the summary (assistant message)
162+
summary_message = agent.messages[0]
163+
assert summary_message["role"] == "user"
167164
assert len(summary_message["content"]) > 0
168165

169166
# Verify the summary contains actual text content
@@ -364,8 +361,8 @@ def test_dedicated_summarization_agent(model, summarization_model):
364361
assert len(agent.messages) < original_length
365362

366363
# Get the summary message
367-
summary_message = agent.messages[1]
368-
assert summary_message["role"] == "assistant"
364+
summary_message = agent.messages[0]
365+
assert summary_message["role"] == "user"
369366

370367
# Extract summary text
371368
summary_text = None

0 commit comments

Comments
 (0)