# Chapter 2: Message / Memory - Remembering the Conversation
In [Chapter 1: The LLM - Your Agent's Brainpower](01_llm.md), we learned how our agent uses the `LLM` class to access its "thinking" capabilities. But just like humans, an agent needs to remember what was said earlier in a conversation to make sense of new requests and respond appropriately.
Imagine asking a friend: "What was the first thing I asked you?". If they have no memory, they can't answer! Agents face the same problem. They need a way to store the conversation history.
This is where `Message` and `Memory` come in.
## What Problem Do They Solve?
Think about a simple chat:
1.**You:** "What's the weather like in London?"
2.**Agent:** "It's currently cloudy and 15°C in London."
3.**You:** "What about Paris?"
For the agent to answer your *second* question ("What about Paris?"), it needs to remember that the *topic* of the conversation is "weather". Without remembering the first question, the second question is meaningless.
`Message` and `Memory` provide the structure to:
1. Represent each individual turn (like your question or the agent's answer) clearly.
2. Store these turns in order, creating a log of the conversation.
## The Key Concepts: Message and Memory
Let's break these down:
### 1. Message: A Single Turn in the Chat
A `Message` object is like a single speech bubble in a chat interface. It represents one specific thing said by someone (or something) at a particular point in the conversation.
Every `Message` has two main ingredients:
***`role`**: *Who* sent this message? This is crucial for the LLM to understand the flow. Common roles are:
*`user`: A message from the end-user interacting with the agent. (e.g., "What's the weather?")
*`assistant`: A message *from* the agent/LLM. (e.g., "The weather is sunny.")
*`system`: An initial instruction to guide the agent's overall behavior. (e.g., "You are a helpful weather assistant.")
*`tool`: The output or result from a [Tool / ToolCollection](04_tool___toolcollection.md) that the agent used. (e.g., The raw data returned by a weather API tool).
***`content`**: *What* was said? This is the actual text of the message. (e.g., "What's the weather like in London?")
There are also optional parts for more advanced uses, like `tool_calls` (when the assistant decides to use a tool) or `base64_image` (if an image is included in the message), but `role` and `content` are the basics.
### 2. Memory: The Conversation Log
The `Memory` object is simply a container, like a list or a notebook, that holds a sequence of `Message` objects.
* It keeps track of the entire conversation history (or at least the recent parts).
* It stores messages in the order they occurred.
* Agents look at the `Memory` before deciding what to do next, giving them context.
Think of `Memory` as the agent's short-term memory for the current interaction.
## How Do We Use Them?
Let's see how you'd typically work with `Message` and `Memory` in OpenManus (often, the agent framework handles some of this automatically, but it's good to understand the pieces).
**1. Creating Messages:**
The `Message` class in `app/schema.py` provides handy shortcuts to create messages with the correct role:
```python
# Import the Message class
fromapp.schemaimportMessage
# Create a message from the user
user_q=Message.user_message("What's the capital of France?")
# Create a message from the assistant (agent's response)
assistant_a=Message.assistant_message("The capital of France is Paris.")
# Create a system instruction
system_instruction=Message.system_message("You are a helpful geography expert.")
*`conversation_memory = Memory()` creates an empty memory store.
*`conversation_memory.add_message(...)` adds a `Message` object to the end of the internal list.
*`conversation_memory.messages` gives you access to the list of `Message` objects currently stored.
*`message.to_dict()` converts a `Message` object into a simple dictionary format, which is often needed for APIs.
**Example Output:**
```
Number of messages in memory: 4
Last message: {'role': 'user', 'content': 'What about Spain?'}
```
**3. Using Memory for Context:**
Now, how does the agent use this? Before calling the [LLM](01_llm.md) to figure out the answer to "What about Spain?", the agent would grab the messages from its `Memory`.
# print(f"LLM would likely respond about the capital of Spain, e.g., 'The capital of Spain is Madrid.'")
```
**Explanation:**
*`conversation_memory.to_dict_list()` converts all stored `Message` objects into the list-of-dictionaries format that the `llm.ask` method expects (as we saw in Chapter 1).
* By sending this *entire history*, the LLM sees:
1. Its instructions ("You are a helpful geography expert.")
2. The first question ("What's the capital of France?")
3. Its previous answer ("The capital of France is Paris.")
4. The *new* question ("What about Spain?")
* With this context, the LLM can correctly infer that "What about Spain?" means "What is the capital of Spain?".
## Under the Hood: How It Works
`Memory` is conceptually simple. It's primarily a wrapper around a standard Python list, ensuring messages are stored correctly and providing convenient methods.
Here's a simplified flow of how an agent uses memory:
```mermaid
sequenceDiagram
participant User
participant Agent as BaseAgent (app/agent/base.py)
participant Mem as Memory (app/schema.py)
participant LLM as LLM Class (app/llm.py)
participant LLM_API as Actual LLM API
User->>+Agent: Sends message ("What about Spain?")
Agent->>+Mem: update_memory(role="user", content="What about Spain?")
Mem->>Mem: Adds Message(role='user', ...) to internal list
Mem-->>-Agent: Memory updated
Agent->>Agent: Needs to generate response
Agent->>+Mem: Get all messages (memory.messages)
Mem-->>-Agent: Returns list of Message objects
Agent->>Agent: Formats messages to dict list (memory.to_dict_list())
Agent->>+LLM: ask(messages=formatted_list)
LLM->>LLM_API: Sends request with history
LLM_API-->>LLM: Receives response ("The capital is Madrid.")
LLM-->>-Agent: Returns text response
Agent->>+Mem: update_memory(role="assistant", content="The capital is Madrid.")
Mem->>Mem: Adds Message(role='assistant', ...) to internal list
Mem-->>-Agent: Memory updated
Agent->>-User: Sends response ("The capital is Madrid.")
```
**Code Glimpse:**
Let's look at the core parts in `app/schema.py`:
```python
# Simplified snippet from app/schema.py
fromtypingimportList,Optional
frompydanticimportBaseModel,Field
# (Role enum and other definitions are here)
classMessage(BaseModel):
role:str# Simplified: In reality uses ROLE_TYPE Literal
content:Optional[str]=None
# ... other optional fields like tool_calls, name, etc.
defto_dict(self)->dict:
# Creates a dictionary representation, skipping None values
"""Convert all stored messages to dictionaries."""
return[msg.to_dict()formsginself.messages]
# ... other methods like clear(), get_recent_messages() ...
```
**Explanation:**
* The `Message` class uses Pydantic `BaseModel` for structure and validation. It clearly defines `role` and `content`. The classmethods (`user_message`, etc.) are just convenient ways to create instances with the role pre-filled. `to_dict` prepares it for API calls.
* The `Memory` class also uses `BaseModel`. Its main part is `messages: List[Message]`, which holds the conversation history. `add_message` simply appends to this list (and optionally trims it). `to_dict_list` iterates through the stored messages and converts each one using its `to_dict` method.
And here's how an agent might use its memory attribute (simplified from `app/agent/base.py`):
```python
# Simplified conceptual snippet inspired by app/agent/base.py
* When input arrives (`add_user_input`), it creates a `Message` and adds it using `self.memory.add_message`.
* When generating a response (`generate_response`), it retrieves the history using `self.memory.to_dict_list()` and passes it to `self.llm.ask`.
* It then adds the LLM's response back into memory as an `assistant` message.
## Wrapping Up Chapter 2
You've now learned about `Message` (a single conversational turn with a role and content) and `Memory` (the ordered list storing these messages). Together, they provide the crucial context agents need to understand conversations and respond coherently. They act as the agent's short-term memory or chat log.
We have the brain ([LLM](01_llm.md)) and the memory (`Message`/`Memory`). Now we need something to orchestrate the process – to receive input, consult memory, use the LLM, potentially use tools, and manage its state. That's the job of the Agent itself.
Let's move on to [Chapter 3: BaseAgent](03_baseagent.md) to see how agents are structured and how they use these core components.
---
Generated by [AI Codebase Knowledge Builder](https://github.com/The-Pocket/Tutorial-Codebase-Knowledge)