Agent Memory Management and Summarization in MathModelAgent: Implementation and Code
MathModelAgent implements a bounded memory system using a rolling window approach where older dialogue is automatically summarized via LLM calls when chat_history exceeds max_memory, while strictly preserving tool call/response pairs to prevent execution errors.
MathModelAgent provides a robust agent memory management and summarization architecture centered on the base Agent class in backend/app/core/agents/agent.py. The system maintains conversation context within configurable token limits by compressing historical messages into structured summaries, ensuring that critical tool interactions remain intact even during aggressive memory pruning.
How the Base Agent Class Handles Memory
The core mechanism resides in the Agent class, which orchestrates message storage, overflow detection, and safe truncation. Every agent instance maintains a self.chat_history list and a self.max_memory threshold that dictates when summarization must occur.
Appending Messages and Automatic Triggers
When new messages enter the system via Agent.append_chat_history, the method immediately evaluates whether memory management is required. The critical logic resides in backend/app/core/agents/agent.py:
async def append_chat_history(self, msg: dict) -> None:
self.chat_history.append(msg)
if msg.get("role") != "tool":
await self.clear_memory()
Key implementation detail: The clear_memory call is skipped only when the message role is "tool". This ensures that tool responses remain paired with their original requests, preventing orphaned context that could break the agent's execution flow.
Detecting Memory Overflow
The clear_memory method acts as the gatekeeper for the agent memory management and summarization pipeline. It first checks if the history length exceeds the instance's max_memory limit:
if len(self.chat_history) <= self.max_memory:
return
Standard agents default to max_memory=12, while the WriterAgent subclass extends this to 25 to accommodate longer writing sessions. If the threshold is not exceeded, the method returns immediately without invoking the LLM summarizer.
Finding Safe Cut-Points for Tool Calls
Because tool interactions consist of paired messages—a request containing tool_calls and a subsequent response with role="tool"—the system must never truncate between these pairs. The _find_safe_preserve_point method handles this by walking backwards from the last N messages (default N=3) and validating potential cut points via _is_safe_cut_point:
- Safe point criteria: No dangling
toolmessage can remain after truncation - Fallback behavior: If no valid cut point exists within the search window, the system defaults to preserving only the most recent message
- Implementation location:
backend/app/core/agents/agent.py
This protective logic ensures that the agent's ability to execute multi-step tool workflows remains unbroken even during aggressive memory compression.
LLM-Driven Summarization Process
Once a safe preservation point is identified, all messages preceding that index are fed to the summarization engine. The simple_chat helper function in backend/app/core/llm/llm.py handles the actual LLM call:
summary = await simple_chat(self.model, summarize_history)
The reconstructed chat_history follows a strict three-part structure:
- System message (if present in original history)
- Summary message with the label
[历史对话总结]followed by the compressed context - Preserved recent messages including any pending tool interactions
This architecture allows the agent to retain semantic context from earlier conversation turns while keeping the token count within operational limits.
Robust Fallback Mechanisms
If the LLM summarization call fails due to network errors or model unavailability, the system invokes _get_safe_fallback_history. This method guarantees continuity by preserving:
- The system message (if any)
- A minimal set of recent non-tool messages
- Any active tool call pairs
This fallback ensures that the agent remains functional even when the agent memory management and summarization pipeline encounters unexpected failures.
WriterAgent-Specific Implementation
The WriterAgent class in backend/app/core/agents/writer_agent.py extends the base memory architecture for long-form content generation tasks. It configures a larger memory window (max_memory=25) to maintain extended context during report writing.
Additionally, it exposes a public summarize method for task-level summarization:
async def summarize(self) -> str:
await self.append_chat_history(
{"role": "user", "content": "请简单总结以上完成什么任务取得什么结果:"}
)
response = await self.model.chat(...)
This method leverages the same append_chat_history → clear_memory pipeline, ensuring that even manual summarization requests respect the memory bounds. The Chinese prompt requests a brief summary of completed tasks and results, producing a final deliverable while the underlying system manages token limits automatically.
Practical Code Examples
Configuring a WriterAgent with Extended Memory
Instantiate a WriterAgent with custom memory limits to handle extended writing sessions without premature context loss:
from app.core.llm.llm import LLM
from app.core.agents.writer_agent import WriterAgent
from app.tools.openalex_scholar import OpenAlexScholar
# Initialize the underlying LLM
llm = LLM(
api_key="YOUR_API_KEY",
model="gpt-4o-mini",
base_url=None,
task_id="task-1234",
)
# Optional scholar helper for paper search
scholar = OpenAlexScholar()
writer = WriterAgent(
task_id="task-1234",
model=llm,
max_chat_turns=10,
max_memory=25, # Extended window for long writing sessions
scholar=scholar,
)
# Execute a writing turn—memory handling is automatic
response = await writer.run(
prompt="请撰写关于城市交通拥堵的建模思路。"
)
print(response.response_content)
Each call to run appends the user prompt and assistant response to chat_history, triggering clear_memory automatically if the history exceeds 25 messages.
Triggering Manual Task Summarization
Generate final task summaries before ending a session:
summary_text = await writer.summarize()
print("Task summary:", summary_text)
The summarize method injects a summary request into the history, generates the LLM response, and stores it—still protected by the standard memory-clearing routine.
Inspecting Internal Chat History
Debug the memory state to verify summarization behavior:
print("Current history length:", len(writer.chat_history))
for msg in writer.chat_history:
print(msg["role"], "→", msg["content"][:80])
When automatic summarization occurs, you will observe a message with the role assistant or system containing [历史对话总结], indicating that older context has been compressed.
Summary
- Bounded memory architecture: The
Agentclass enforces a strictmax_memorylimit (default 12, configurable per subclass) to prevent token overflow. - Tool-call safety: The
_find_safe_preserve_pointmechanism ensures that tool request/response pairs are never split during truncation, maintaining execution integrity. - LLM-driven compression: Historical messages are summarized via
simple_chatinbackend/app/core/llm/llm.py, with results prefixed by[历史对话总结]. - Automatic triggers: Every non-tool message appended via
append_chat_historyinvokesclear_memory, making memory management transparent to agent operations. - Robust fallbacks: The
_get_safe_fallback_historymethod preserves critical context if the summarization LLM call fails. - Subclass flexibility:
WriterAgentdemonstrates extended memory configuration (max_memory=25) and manual summarization capabilities for specialized workflows.
Frequently Asked Questions
How does MathModelAgent prevent tool call failures during memory summarization?
The system employs _is_safe_cut_point validation within _find_safe_preserve_point to ensure that truncation never occurs between a tool request and its corresponding response. Because append_chat_history skips clear_memory when the message role is "tool", active tool workflows remain intact even when the preceding dialogue is summarized.
What is the default memory limit for agents in MathModelAgent?
The base Agent class defaults to max_memory=12 conversation turns. The WriterAgent subclass overrides this default to 25 to accommodate longer content generation sessions without losing contextual continuity.
How does the WriterAgent differ from the base Agent in memory management?
According to the source code in backend/app/core/agents/writer_agent.py, WriterAgent sets a higher max_memory threshold and exposes a public summarize method for task-level summarization. However, it inherits the same core agent memory management and summarization logic, including the safe cut-point algorithms and fallback mechanisms defined in the base class.
What happens if the LLM summarization call fails?
If simple_chat raises an exception during the summarization phase, the agent falls back to _get_safe_fallback_history, which guarantees retention of the system message and the most recent non-tool messages. This ensures the agent remains operational with minimal context loss rather than crashing or corrupting the conversation state.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →