Overview
Long-term memory lets an agent store and retrieve durable information across sessions — user preferences, past decisions, and knowledge that should persist beyond a single conversation.
In AgentScope, memory extraction and storage services (such as mem0 and ReMe) serve as long-term memory backends, integrated into agents as middleware. Each memory middleware is a MiddlewareBase subclass that can hook into any position of the agent lifecycle as needed. For example:
on_reply — search the store before a reply and write the new exchange back afterward.
on_system_prompt — advertise memory tools to the model.
list_tools — contribute agent-callable memory tools, such as search_memory / add_memory.
Which positions a backend hooks is up to that backend.
This keeps the agent and model code untouched: you opt into long-term memory simply by passing a memory middleware into Agent(middlewares=[...]), and you can compose it with any other middleware.
AgentScope currently ships the following long-term memory backend, with more (e.g. ReMe) planned:
| Backend | Class | Status |
|---|
| mem0 | Mem0Middleware | Available |
Mem0
Mem0Middleware is a drop-in long-term memory backend powered by mem0. It works with both mem0.AsyncMemory (open-source) and mem0.AsyncMemoryClient (hosted Platform). With mem0.AsyncMemory (open-source), it can route mem0’s own memory extraction and embedding through your existing AgentScope models — so mem0 needs no separate provider key.
Installation
Mem0Middleware’s dependencies are available as an optional extra in AgentScope:
pip install "agentscope[mem0]"
Quick start
The fastest path is to pass your AgentScope chat and embedding models; the middleware builds an open-source mem0 store internally and wires both extraction and embedding through them.
import asyncio
from agentscope.agent import Agent
from agentscope.middleware import Mem0Middleware
from agentscope.tool import Toolkit
async def main():
mw = Mem0Middleware(
user_id="alice",
chat_model=my_chat_model,
embedding_model=my_embedding_model,
mode="both",
)
agent = Agent(
name="assistant",
system_prompt="You are a helpful assistant.",
model=my_chat_model,
toolkit=Toolkit(tools=await mw.list_tools()),
middlewares=[mw],
)
# Memories written in this session resurface in later sessions
# for the same ``user_id``.
await agent(...)
asyncio.run(main())
Mem0Middleware contributes its search_memory / add_memory tools through list_tools(), which the agent does not call automatically. To make the tools available to the agent, collect them yourself and pass them into the toolkit — Toolkit(tools=await mw.list_tools()). In static_control mode list_tools() returns an empty list.
Control modes
The mode parameter decides how the agent interacts with mem0. It defaults to "both", matching AgentScope 1.x’s ReActAgent.long_term_memory_mode.
| Mode | Behavior |
|---|
static_control | The middleware searches mem0 before each reply, injects the retrieved memories into the context as an AssistantMsg(name="memory"), and writes the new exchange back after the reply. The agent is unaware of mem0. |
agent_control | The middleware exposes search_memory / add_memory tools and appends a short usage nudge to the system prompt. The agent decides when to read from or write to memory; there is no automatic retrieval or write-back. |
both | Both patterns are active at once — automatic retrieval and on-demand tools. |
Construction paths
Mem0Middleware supports three ways to wire up the mem0 backend:
AgentScope models
Models + custom config
Pre-built client
Pass AgentScope models and let the middleware build an open-source AsyncMemory internally (mem0’s default Qdrant store). The embedding model’s dimensions must match the vector store (the default Qdrant expects 1536).Mem0Middleware(
user_id="alice",
chat_model=my_chat_model,
embedding_model=my_embedding_model,
)
Start from your own mem0.configs.base.MemoryConfig to customize the vector store, history DB, or reranker, while still routing the LLM and embedder through AgentScope. Only the .llm / .embedder slots are overridden; every other field is preserved.Mem0Middleware(
user_id="alice",
chat_model=my_chat_model,
embedding_model=my_embedding_model,
mem0_config=my_mem0_config,
)
Pass a pre-built mem0 client when you want full control (e.g. the hosted Platform, or sharing one store across agents). When client is given it takes absolute precedence, and chat_model / embedding_model / mem0_config are ignored.from mem0 import AsyncMemoryClient
Mem0Middleware(
user_id="alice",
client=AsyncMemoryClient(api_key="m0-..."),
)
Mem0Middleware requires an async mem0 client (mem0.AsyncMemory or mem0.AsyncMemoryClient). The synchronous Memory / MemoryClient are not supported.
Key parameters
| Parameter | Type | Default | Description |
|---|
user_id | str | (required) | mem0 namespace for the user’s memories. |
mode | "static_control" | "agent_control" | "both" | "both" | How the agent interacts with mem0 (see above). |
agent_id | str | None | None | Optional finer-grained namespace. |
top_k | int | 5 | Max memories retrieved per static-control search; also the default for the search_memory tool. |
threshold | float | None | None | Minimum similarity score; None lets mem0 decide. |
scope_search_by_agent | bool | True | When True, searches filter by both user_id and agent_id; when False, a user’s memories are shared across agents. |
await_write | bool | True | When True, the post-turn write is awaited inline; when False, it’s fire-and-forget (faster, but exceptions only surface in logs). |
In agent_control and both modes, the middleware contributes two tools the model can invoke on demand:
search_memory(keywords, limit=5) — retrieves memories using a list of short, targeted keywords. Each keyword is issued as an independent query; results are merged and deduplicated.
add_memory(thinking, content) — records durable facts. Only content (a list of standalone sentences) is persisted to mem0; thinking stays in the transcript for auditability.
Both tools auto-allow themselves and read user_id / agent_id directly from the middleware instance, so they require no extra wiring beyond adding them to the toolkit.