Metadata-Version: 2.5
Name: autogen-memorysync
Version: 1.1.0
Summary: MemorySync for Microsoft AutoGen: an async-native Memory implementation with a hard recall budget, role-aware retrieval, duplicate-proof fact capture, and session-scoped clear.
Project-URL: Homepage, https://docs.memorysync.io/guides/autogen
Project-URL: Documentation, https://docs.memorysync.io/guides/autogen
Project-URL: Repository, https://github.com/memorysyncio/memorysync-plugins
Author-email: MemorySync <support@memorysync.io>
License-Expression: MIT
Keywords: agents,autogen,autogen-agentchat,long-term-memory,memory,memorysync
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Requires-Python: >=3.10
Requires-Dist: autogen-core<0.8,>=0.4.0
Requires-Dist: httpx<1,>=0.25
Description-Content-Type: text/markdown

# autogen-memorysync

[MemorySync](https://memorysync.io) for [Microsoft AutoGen](https://github.com/microsoft/autogen)
(`autogen-agentchat` 0.4+): agents that remember users across sessions —
without ever stalling a turn.

```bash
pip install autogen-memorysync
```

## Quick start

```python
from autogen_agentchat.agents import AssistantAgent
from autogen_memorysync import MemorySyncMemory

memory = MemorySyncMemory(
    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
)

agent = AssistantAgent("assistant", model_client=..., memory=[memory])

result = await agent.run(task=user_text)
# AutoGen never captures turns itself — capture the exchange in one call
# (the user's text is sent for fact extraction; the reply is not stored):
await memory.add_turn_pair(user_text, result.messages[-1].content)
```

`update_context` runs automatically before every model call: relevant
memories are recalled and injected as a `SystemMessage`, and the
retrieval surfaces to observers as a `MemoryQueryEvent`.

## Why this one

| | Mem0 (`autogen-ext[mem0]`) | Zep (`zep-autogen`) | **MemorySync** |
| --- | --- | --- | --- |
| Async correctness | ✗ sync client inside `async def` — blocks the event loop | ✓ | ✓ `httpx.AsyncClient` throughout |
| Recall latency budget | ✗ none | ✗ none | ✓ hard 1.2s default — a slow backend means an unenriched turn, never a late one |
| Retrieval query | ✗ `messages[-1]` even when it's assistant/tool text | last context message | ✓ last **user** message, role-aware |
| Query errors | ✗ swallowed — outage looks like amnesia | logged | ✓ explicit `query()` raises; only the hot path fails open |
| `clear()` blast radius | ✗ entire user | ✗ entire user | ✓ **session-scoped by default**; whole-user wipe is an explicit opt-in |
| Retry safety | ✗ | ✗ | ✓ deterministic idempotency seeds — a retried turn is recognised and not extracted twice |
| Caller's metadata dict | ✗ mutated (`pop`) | — | ✓ copied, never touched |
| `close()` | `pass` | ✓ | ✓ releases the HTTP client |

## Semantics worth knowing

- **The turn is never stalled and never broken.** Recall waits at most
  `recall_timeout` (default 1.2s); on timeout, outage, or quota
  exhaustion the agent simply answers without memories.
- **`user_id` is required.** No silent auto-generated UUID namespaces
  where stored memories can never be found again.
- **User turns are sent to fact extraction; only durable facts are
  stored.** `add()` sends a user turn to MemorySync as plain text with
  `role: "user"` under the `autogen::<session>` session scope. The server
  extracts the durable facts it contains and stores only those, tagged
  with `session_id: "autogen::<session>"` and your other metadata — the
  same shared user memories as every other MemorySync surface. 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.
- **Assistant replies are not stored as memories.** Content whose
  `metadata["role"]` is `"assistant"` (or `"system"`, `"tool"`, ...) is
  not sent, and `add_turn_pair(user_text, assistant_text)` sends only
  `user_text`. A `MemoryContent` without a role is the user's turn.
- By default `clear()` deletes the facts carrying this session's
  `session_id` and leaves the rest of the user's memories alone.
- Free-tier quota exhaustion is silent by design (adds accepted-without-
  storing, reads empty); evaluation keys surface strict `429`s.
- `create_memory_tools(memory)` returns `search_memory` + `save_memory`
  `FunctionTool`s for tool-equipped agents.

## Configuration

| Parameter | Default | Meaning |
| --- | --- | --- |
| `user_id` | — (required) | End user the memories belong to |
| `session_id` | `"default"` | Session scope: the `session_id` (`autogen::<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 prompts |
| `context_template` | built-in | `{context}` placeholder, brace-safe `.replace` rendering |
| `clear_scope` | `"session"` | `clear()` blast radius; `"user"` opt-in wipes everything |

## Development

```bash
pip install -e . autogen-agentchat autogen-ext pytest pytest-asyncio "httpx>=0.25,<1"
python -m pytest tests -q      # 43 tests incl. a REAL AssistantAgent drive
```

Note: `autogen-agentchat` is in maintenance mode (Microsoft's successor
is the Microsoft Agent Framework — a separate MemorySync adapter target).
Maintenance mode means the `Memory` protocol this package implements is
frozen and stable.

## License

MIT
