Skip to content

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 turn

Sliding 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 history

Or 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:

  • SlidingWindowConversationManager
  • SummarizingConversationManager
  • NullConversationManager

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.

Copyright © 2026 elsai foundry.