Skip to content

[BUG] Summarizing Conversation Manager throwing ValidationExceptionΒ #611

@flowconic

Description

@flowconic

Checks

  • I have updated to the lastest minor and patch version of Strands
  • I have checked the documentation and this is not expected behavior
  • I have searched ./issues and there are no duplicates of my issue

Strands Version

1.3.0

Python Version

3.13.5

Operating System

macOS 15.5 (24F74) (sequoia)

Installation Method

pip

Steps to Reproduce

  1. Install requirements
# Database
psycopg2-binary==2.9.*
asyncpg==0.30.*

# AI and chat related
requests==2.32.4
strands-agents[otel]>=1.3.0
strands-agents-tools>=0.2.1
  1. Create chat summarisation agent
#file chat_summarization_agent.py
from models.nova import NOVA_PRO_FOR_SUMMARISATION
from strands import Agent
from strands.agent.conversation_manager import SummarizingConversationManager

SUMMARISATION_SYSTEM_PROMPT = """
You are a conversation summarizer. Provide a concise summary of the conversation history.

Format Requirements:
- You MUST create a structured and concise summary in bullet-point format.
- You MUST capture decisions made, actions agreed or goals discussed.
- You MUST NOT respond conversationally.
- You MUST NOT address the user directly.

Task:
Your task is to create a structured summary document:
- It MUST contain bullet points with key topics and questions covered
- It MUST contain bullet points for all significant tools executed and their results
- It MUST contain bullet points for any code or technical information shared
- It MUST contain a section of key insights gained
- It MUST format the summary in the third person

Example format:

## Conversation Summary
* Topic 1: Key information
* Topic 2: Key information
*
## Tools Executed
* Tool X: Result Y
"""


def get_custom_summarization_manager_agent(
    chat_uuid: str, user_uuid: str
) -> SummarizingConversationManager:

    custom_summarization_agent = Agent(
        name="Custom Summarization Agent",
        agent_id="custom_summarization_agent",
        description="An agent specialized in summarizing chat conversations.",
        model=NOVA_PRO_FOR_SUMMARISATION,
        system_prompt=SUMMARISATION_SYSTEM_PROMPT,
        # tools=[save_chat_summary],
        callback_handler=None,
    )
    custom_summarization_agent.state.set("chat_uuid", chat_uuid)
    custom_summarization_agent.state.set("user_uuid", user_uuid)

    conversation_manager = SummarizingConversationManager(
        summary_ratio=0.1,  # ideally increase
        preserve_recent_messages=1,
        summarization_agent=custom_summarization_agent,
    )

    return conversation_manager
  1. Setup a coordinator agent (or any agent using this summarization agent)
# filename coordinator.agent.py

async def get_coordinator_agent(event_object):
    COORDINATOR_PROMPT_LOADED = ""
    agent_id = "coordinator_agent1"
    session_manager = get_session(event_object.user_uuid, event_object.chat_uuid)

    if session_manager.session_repository.is_new_session is True:
        # Parallel tasks to fetch initial memories and user profile
        COORDINATOR_PROMPT_LOADED = .....

    conversation_manager = get_custom_summarization_manager_agent(
        chat_uuid=event_object.chat_uuid, user_uuid=event_object.user_uuid
    )
    coordinator_agent = Agent(
        name="Coordinator Agent",
        model=ANTHROPIC_CLAUDE_SONNET_4,
        system_prompt=COORDINATOR_PROMPT_LOADED or COORDINATOR_PROMPT,
        tools=[
            http_request,
            calculator,
        agent_id=agent_id,
        trace_attributes={
            "user_uuid": event_object.user_uuid,
            "tenant_uuid": event_object.tenant_uuid,
            "chat_uuid": event_object.chat_uuid,
        },
        session_manager=session_manager,
        conversation_manager=conversation_manager,
    )

    # Set initial state values for the coordinator agent
    coordinator_agent.state.set("user_uuid", event_object.user_uuid)
    coordinator_agent.state.set("tenant_uuid", event_object.tenant_uuid)
    coordinator_agent.state.set("chat_uuid", event_object.chat_uuid)

    return coordinator_agent

Expected Behavior

When the summarization loads, it adds the previous summarisation from state without errors.

Actual Behavior

When Running the below errors come up

ERROR | strands.agent.conversation_manager.summarizing_conversation_manager | Summarization failed: An error occurred (ValidationException) when calling the ConverseStream operation: A conversation must start with a user message. Try again with a conversation that starts with a user message. | chat/.venv/lib/python3.13/site-packages/strands/agent/conversation_manager/summarizing_conversation_manager.py:166

The captured and loaded chat state from session manager:

{
  "state": {
    "chat_uuid": "5de0daca-b6a7-4b04-9247-c3d02fbb7ddf",
    "user_uuid": "00000000-0000-0000-0000-000000000000",
    "tenant_uuid": "00000000-0000-0000-0000-000000000000"
  },
  "agent_id": "coordinator_agent1",
  "created_at": "2025-08-05T05:43:11.538716+00:00",
  "updated_at": "2025-08-05T05:43:11.538724+00:00",
  "system_prompt": "You are a coordinator who is responsible for answering users chat questions across multiple domains",
  "conversation_manager_state": {
    "__name__": "SummarizingConversationManager",
    "summary_message": {
      "role": "assistant",
      "content": [
        {
          "text": "## Conversation Summary\n* Topic: User inquiry about assistance\n  * User asked how the assistant can help\n  * Assistant explained its role as a conversation summarizer\n* Decisions/Actions:\n  * Assistant committed to summarizing the conversation\n* Goals:\n  * Create a structured and concise summary document\n\n## Tools Executed\n* save_chat_summary: Summary of the conversation saved\n\n## Key Insights\n* The assistant's primary function is to provide structured and concise summaries of conversations.\n* The summary includes key topics, tools executed, code or technical information shared, and key insights gained."
        }
      ]
    },
    "removed_message_count": 1
  }
}

Additional Context

No response

Possible Solution

I believe the issue may be related to
strands/agent/conversation_manager/summarizing_conversation_manager.py and def reduce_context from line 117. which I added below with added comments.

Could the issue be that when the last line of code agent.messages[:] = [self._summary_message] + remaining_messages runs, it then loads the summarization. But as the summarisation state has captured role: assistant, this causes it to fail?

def reduce_context(self, agent: "Agent", e: Optional[Exception] = None, **kwargs: Any) -> None:
        """Reduce context using summarization.

        Args:
            agent: The agent whose conversation history will be reduced.
                The agent's messages list is modified in-place.
            e: The exception that triggered the context reduction, if any.
            **kwargs: Additional keyword arguments for future extensibility.

        Raises:
            ContextWindowOverflowException: If the context cannot be summarized.
        """
        try:
            # Calculate how many messages to summarize
            messages_to_summarize_count = max(1, int(len(agent.messages) * self.summary_ratio))

            # Ensure we don't summarize recent messages
            messages_to_summarize_count = min(
                messages_to_summarize_count, len(agent.messages) - self.preserve_recent_messages
            )

            if messages_to_summarize_count <= 0:
                raise ContextWindowOverflowException("Cannot summarize: insufficient messages for summarization")

            # Adjust split point to avoid breaking ToolUse/ToolResult pairs
            messages_to_summarize_count = self._adjust_split_point_for_tool_pairs(
                agent.messages, messages_to_summarize_count
            )

            if messages_to_summarize_count <= 0:
                raise ContextWindowOverflowException("Cannot summarize: insufficient messages for summarization")

            # Extract messages to summarize
            messages_to_summarize = agent.messages[:messages_to_summarize_count]
            remaining_messages = agent.messages[messages_to_summarize_count:]

            # Keep track of the number of messages that have been summarized thus far.
            self.removed_message_count += len(messages_to_summarize)
            # If there is a summary message, don't count it in the removed_message_count.
            if self._summary_message:
                self.removed_message_count -= 1

            # Generate summary

            # ******** NOTE that this returns return result.message which here would include the assistant role

            self._summary_message = self._generate_summary(messages_to_summarize, agent)

            # Replace the summarized messages with the summary

            # ********** NOTE As this creates the agent.messages, with the first message being what generate_summary returned, which has the role:assistant format. 
            agent.messages[:] = [self._summary_message] + remaining_messages

Related Issues

No response

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions