ag2-memorysync
MemorySync for AG2
(the classic AutoGen ConversableAgent framework, pip install autogen):
an automatic memory loop — recall injected before every reply, the user's
turns captured for fact extraction, zero extra code per turn.
pip install ag2-memorysync
Quick start
from autogen import ConversableAgent
from ag2_memorysync import MemorySyncCapability
assistant = ConversableAgent("assistant", llm_config=...)
memory = MemorySyncCapability(
api_key="ms_...", # or MEMORYSYNC_API_KEY
user_id="customer-42", # required — who these memories belong to
session_id="support-chat", # tags the facts from this chat
)
memory.add_to_agent(assistant) # that's the whole integration
From then on every incoming user message is enriched with recalled
context and sent to MemorySync, which extracts the durable facts it
contains — through AG2's own hook system (process_last_received_message
process_message_before_send). The agent's own replies are not sent: assistant replies are not stored as memories.
Why this one
| Mem0 | Zep (zep-ag2) |
MemorySync | |
|---|---|---|---|
| AG2 adapter exists | ✗ docs show an AutoGen-0.2 recipe with placeholder model names | ✓ | ✓ |
| Multi-agent duplication | — | ✗ documented bug: two attached agents store every utterance twice with conflicting roles | ✓ cross-hook dedup registry + idempotency seeds — each utterance handled once; an agent's reply is never sent as the person's words (by test) |
| Sync→async bridge | — | per-call event-loop spin; documented deadlock caveat under asyncio | ✓ one persistent background loop; never touches the caller's loop (asyncio-driven chats pass, by test) |
| Recall latency budget | — | ✗ none | ✓ hard 1.2s default — the reply is never late |
| Framework pin | — | ✗ ag2<1 — breaks on the v1 rewrite |
✓ zero framework dependency (duck-typed attach; works with whichever classic distribution you installed) |
| Injected context re-captured? | — | system-message mutation, last-write-wins | ✓ hook output feeds the LLM only; the ORIGINAL text is what is sent |
Semantics worth knowing
- The reply is never stalled and never broken. Recall blocks at most
recall_timeout(default 1.2s); sending a turn is fire-and-forget off the hot path. Outages and quota exhaustion degrade to "no memories this turn". - User turns are sent to fact extraction; only durable facts are
stored. Each user turn goes to MemorySync as plain text with
role: "user"under theag2::<session>session scope. The server extracts the durable facts it contains and stores only those, tagged withsession_id: "ag2::<session>"; filler such as "ok" or "thanks" yields none, and the turn text itself is not stored. Deterministic idempotency seeds let the server recognise a retry of the same turn and not extract it twice. - Roles follow the speaker, not the hook. A message sent by an agent
that speaks for a person — a
UserProxyAgent, an agent whosehuman_input_modeis"ALWAYS", or a"TERMINATE"-mode agent with no model — is the user's turn, even when the capability is attached to that agent too. Every other agent's outgoing message is an assistant reply and is not sent. That includes a plainConversableAgent(..., llm_config=...): its defaulthuman_input_mode="TERMINATE"only asks a person when the chat ends, so its messages come from the model. - Attach it to both sides if you like. A process-wide registry records what each attached agent just handled, so the person's words are sent once — not again by the receiving side — and an assistant's reply arriving at the person's proxy is never sent as theirs.
- Tool/function messages are never sent.
register_memory_tools(memory, caller=..., executor=...)addssearch_memory+save_memorytools (the caller needs anllm_config, as usual for AG2 tools).memory.flush()waits for in-flight sends (shutdown/tests);memory.close()flushes and releases the HTTP client.
Configuration
| Parameter | Default | Meaning |
|---|---|---|
user_id |
— (required) | End user the memories belong to |
session_id |
"default" |
Session scope: the session_id (ag2::<session>) carried by the facts from this chat |
top_k |
5 |
Memories considered per turn |
recall_timeout |
1.2 |
Hard recall budget, seconds |
min_prompt_chars |
8 |
Skip recall for trivial messages |
context_template |
built-in | {context} placeholder, brace-safe .replace rendering |
capture |
"both" |
"received" / "sent" to capture one side only. The sent side carries only what an agent speaking for a person says, so "sent" belongs on the person's UserProxyAgent; on an assistant it sends nothing |
Development
pip install -e . "autogen[openai]" pytest "httpx>=0.25,<1"
python -m pytest tests -q # 31 tests through REAL ConversableAgent chats
The suite includes a reproduction of zep-ag2's documented multi-agent
double-store scenario (each utterance handled once), a UserProxyAgent +
assistant chat with the capability on both sides (the person's words are
sent once; the assistant's replies are not sent), and a chat driven from
inside asyncio.run() (no deadlock).
License
MIT
Metadata
Release files for ag2-memorysync 1.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| ag2_memorysync-1.1.0.tar.gz | 22.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| ag2_memorysync-1.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 39.8 kB
Release files / ag2_memorysync-1.1.0.tar.gz
| Download URL | ag2_memorysync-1.1.0.tar.gz |
|---|---|
| Size | 22.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
a0566422a6ec179daa744a2a729b5485af62fa2ff888078a3b2bfd4b91af6060
|
|
BLAKE2b-256 checksum How to use checksums |
982c6fdb9f6c483951a91943703e8d229b551a0303d6ed79ad00336c7c319387
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.5
|
Release files / ag2_memorysync-1.1.0-py3-none-any.whl
| Download URL | ag2_memorysync-1.1.0-py3-none-any.whl |
|---|---|
| Size | 16.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
0eea61b7af887258ad99542099ebeb25ada3ab55021733ef560db248c3eeacd4
|
|
BLAKE2b-256 checksum How to use checksums |
6e8cf38f90e8123a2a2bc5489a3c58585cae7cdd476bb808964e300ef87d4456
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.5
|