# Chapter 6: ChatCompletionContext - Remembering the Conversation
In [Chapter 5: ChatCompletionClient](05_chatcompletionclient.md), we learned how agents talk to Large Language Models (LLMs) using a `ChatCompletionClient`. We saw that we need to send a list of `messages` (the conversation history) to the LLM so it knows the context.
But conversations can get very long! Imagine talking on the phone for an hour. Can you remember *every single word* that was said? Probably not. You remember the main points, the beginning, and what was said most recently. LLMs have a similar limitation – they can only pay attention to a certain amount of text at once (called the "context window").
If we send the *entire* history of a very long chat, it might be too much for the LLM, lead to errors, be slow, or cost more money (since many LLMs charge based on the amount of text).
So, how do we smartly choose *which* parts of the conversation history to send? This is the problem that **`ChatCompletionContext`** solves.
## Motivation: Keeping LLM Conversations Focused
Let's say we have a helpful assistant agent chatting with a user:
1.**User:** "Hi! Can you tell me about AutoGen?"
2.**Assistant:** "Sure! AutoGen is a framework..." (provides details)
3.**User:** "Thanks! Now, can you draft an email to my team about our upcoming meeting?"
4.**Assistant:** "Okay, what's the meeting about?"
5.**User:** "It's about the project planning for Q3."
6.**Assistant:** (Needs to draft the email)
When the Assistant needs to draft the email (step 6), does it need the *exact* text from step 2 about what AutoGen is? Probably not. It definitely needs the instructions from step 3 and the topic from step 5. Maybe the initial greeting isn't super important either.
`ChatCompletionContext` acts like a **smart transcript editor**. Before sending the history to the LLM via the `ChatCompletionClient`, it reviews the full conversation log and prepares a shorter, focused version containing only the messages it thinks are most relevant for the LLM's next response.
## Key Concepts: Managing the Chat History
1.**The Full Transcript Holder:** A `ChatCompletionContext` object holds the *complete* list of messages (`LLMMessage` objects like `SystemMessage`, `UserMessage`, `AssistantMessage` from Chapter 5) that have occurred in a specific conversation thread. You add new messages using its `add_message` method.
2.**The Smart View Generator (`get_messages`):** The core job of `ChatCompletionContext` is done by its `get_messages` method. When called, it looks at the *full* transcript it holds, but returns only a *subset* of those messages based on its specific strategy. This subset is what you'll actually send to the `ChatCompletionClient`.
3.**Different Strategies for Remembering:** Because different situations require different focus, AutoGen Core provides several `ChatCompletionContext` implementations (strategies):
***`UnboundedChatCompletionContext`:** The simplest (and sometimes riskiest!). It doesn't edit anything; `get_messages` just returns the *entire* history. Good for short chats, but can break with long ones.
***`BufferedChatCompletionContext`:** Like remembering only the last few things someone said. It keeps the most recent `N` messages (where `N` is the `buffer_size` you set). Good for focusing on recent interactions.
***`HeadAndTailChatCompletionContext`:** Tries to get the best of both worlds. It keeps the first few messages (the "head", maybe containing initial instructions) and the last few messages (the "tail", the recent context). It skips the messages in the middle.
## Use Case Example: Chatting with Different Memory Strategies
Let's simulate adding messages to different context managers and see what `get_messages` returns.
--- Head & Tail Context (h=1, t=2, 4 messages) ---
1. [SystemMessage]: You are a helpful assistant....
2. [UserMessage]: Skipped 3 messages....
3. [AssistantMessage]: It can build complex LLM apps...
4. [UserMessage]: Thanks!...
```
It keeps the very first message (`SystemMessage`), then inserts a placeholder telling the LLM that some messages were skipped, and finally includes the last two messages. This preserves the initial instruction and the most recent context.
**Which one to choose?** It depends on your agent's task!
* Simple Q&A? `Buffered` might be fine.
* Following complex initial instructions? `HeadAndTail` or even `Unbounded` (if short) might be better.
## Under the Hood: How Context is Managed
The core idea is defined by the `ChatCompletionContext` abstract base class.
**Conceptual Flow:**
```mermaid
sequenceDiagram
participant Agent as Agent Logic
participant Context as ChatCompletionContext
participant FullHistory as Internal Message List
Agent->>+Context: add_message(newMessage)
Context->>+FullHistory: Append newMessage to list
FullHistory-->>-Context: List updated
Context-->>-Agent: Done
Agent->>+Context: get_messages()
Context->>+FullHistory: Read the full list
FullHistory-->>-Context: Return full list
Context->>Context: Apply Strategy (e.g., slice list for Buffered/HeadTail)
Context-->>-Agent: Return selected list of messages
```
1.**Adding:** When `add_message(message)` is called, the context simply appends the `message` to its internal list (`self._messages`).
2.**Getting:** When `get_messages()` is called:
* The context accesses its internal `self._messages` list.
* The specific implementation (`Unbounded`, `Buffered`, `HeadAndTail`) applies its logic to select which messages to return.
* It returns the selected list.
**Code Glimpse:**
***Base Class (`_chat_completion_context.py`):** Defines the structure and common methods.
These implementations provide different ways to manage the context window effectively.
## Putting it Together with ChatCompletionClient
How does an agent use `ChatCompletionContext` with the `ChatCompletionClient` from Chapter 5?
1. An agent has an instance of a `ChatCompletionContext` (e.g., `BufferedChatCompletionContext`) to store its conversation history.
2. When the agent receives a new message (e.g., a `UserMessage`), it calls `await context.add_message(new_user_message)`.
3. To prepare for calling the LLM, the agent calls `messages_to_send = await context.get_messages()`. This gets the strategically selected subset of the history.
4. The agent then passes this list to the `ChatCompletionClient`: `response = await llm_client.create(messages=messages_to_send, ...)`.
5. When the LLM replies (e.g., with an `AssistantMessage`), the agent adds it back to the context: `await context.add_message(llm_response_message)`.
This loop ensures that the history is continuously updated and intelligently trimmed before each call to the LLM.
## Next Steps
You've learned how `ChatCompletionContext` helps manage the conversation history sent to LLMs, preventing context window overflows and keeping the interaction focused using different strategies (`Unbounded`, `Buffered`, `HeadAndTail`).
This context management is a specific form of **memory**. Agents might need to remember things beyond just the chat history. How do they store general information, state, or knowledge over time?
* [Chapter 7: Memory](07_memory.md): Explore the broader concept of Memory in AutoGen Core, which provides more general ways for agents to store and retrieve information.
* [Chapter 8: Component](08_component.md): Understand how `ChatCompletionContext` fits into the general `Component` model, allowing configuration and integration within the AutoGen system.
---
Generated by [AI Codebase Knowledge Builder](https://github.com/The-Pocket/Tutorial-Codebase-Knowledge)