Appearance
Conversation Management
Every agent maintains a message history (agent.messages). Conversation managers control how that history grows and is trimmed to stay within the model's context window.
Default behaviour
The default SlidingWindowConversationManager keeps the last N message pairs:
python
from elsai import Agent
agent = Agent() # Uses SlidingWindowConversationManager by default
agent("Message 1")
agent("Message 2")
agent("Message 3")
# agent.messages grows with each turnSliding window
Keep only the most recent messages:
python
from elsai import Agent
from elsai.agent.conversation_manager import SlidingWindowConversationManager
manager = SlidingWindowConversationManager(
window_size=20, # Keep last 20 messages
)
agent = Agent(conversation_manager=manager)Summarising
Automatically summarise old messages instead of discarding them:
python
from elsai import Agent
from elsai.agent.conversation_manager import SummarizingConversationManager
manager = SummarizingConversationManager(
summary_ratio=0.3, # Summarise oldest 30% when context overflows
preserve_recent_messages=10, # Always keep at least 10 recent messages
)
agent = Agent(conversation_manager=manager)When the context grows too large, the manager uses the LLM to produce a summary of the earlier conversation, replacing the old messages with the summary.
No management
For stateful models that manage conversation history server-side (like OpenAI's stateful APIs), omit conversation_manager — the agent applies a no-op manager internally:
python
from elsai import Agent
agent = Agent(model=stateful_model)For non-stateful models where you want to disable local history trimming:
python
from elsai import Agent
from elsai.agent.conversation_manager import NullConversationManager
agent = Agent(conversation_manager=NullConversationManager())Inspecting conversation history
python
agent("Tell me your name")
agent("What did I just ask?")
for msg in agent.messages:
role = msg["role"]
text = "".join(
block.get("text", "") for block in msg["content"]
if "text" in block
)
print(f"[{role}] {text[:80]}")Resetting conversation history
python
agent.messages = [] # Clear all historyOr start a fresh turn with a system prompt:
python
agent.messages = []
agent.system_prompt = "New instructions here."
agent("Fresh start!")Pre-loading messages
Inject conversation history at agent creation time:
python
agent = Agent(
messages=[
{"role": "user", "content": [{"text": "My name is Alice."}]},
{"role": "assistant", "content": [{"text": "Nice to meet you, Alice!"}]},
]
)
result = agent("What is my name?")
# → "Your name is Alice."Custom conversation manager
Implement ConversationManager for custom behaviour:
python
from elsai.agent import ConversationManager, AgentBase
class DatabaseConversationManager(ConversationManager):
def __init__(self, db_url: str):
self.db_url = db_url
def apply_management(self, agent: AgentBase) -> None:
# Called after each turn; trim or persist messages
self._save_to_db(agent.messages)
def reduce_context(self, agent: AgentBase, e=None) -> None:
# Called when context window overflows; remove old messages
agent.messages = agent.messages[-10:]
def get_state(self) -> dict:
return {}
def restore_from_session(self, state: dict) -> None:
pass
def clone_for_spawn(self) -> "DatabaseConversationManager":
"""Fresh manager per spawn worker — same config, isolated instance."""
return DatabaseConversationManager(db_url=self.db_url)Spawn cloning
Custom ConversationManager subclasses used with as_tool(mode="spawn") must implement clone_for_spawn() so each spawn worker gets an isolated manager instance. The example above mirrors built-in managers such as SlidingWindowConversationManager, which copy configuration into a new instance:
python
def clone_for_spawn(self) -> "SlidingWindowConversationManager":
return SlidingWindowConversationManager(window_size=self.window_size, ...)Built-in managers that already support spawn:
SlidingWindowConversationManagerSummarizingConversationManagerNullConversationManager
If your manager connects to shared external state (for example, a database), decide whether each worker should share that connection or use an isolated client — clone_for_spawn() should return a manager appropriate for parallel workers.
elsai memory integration managers do not support spawn cloning today — use mode="queue" with those agents instead. See Plugins — Spawn compatibility for custom plugin requirements.