Metadata-Version: 2.5
Name: agent-framework-memorysync
Version: 1.1.0
Summary: MemorySync for Microsoft Agent Framework: a ContextProvider with budgeted instruction-layer recall, per-run identity, once-per-turn duplicate-proof capture, and fail-open everything.
Project-URL: Homepage, https://docs.memorysync.io/guides/agent-framework
Project-URL: Documentation, https://docs.memorysync.io/guides/agent-framework
Project-URL: Repository, https://github.com/memorysyncio/memorysync-plugins
Author-email: MemorySync <support@memorysync.io>
License-Expression: MIT
Keywords: agent-framework,agents,context-provider,long-term-memory,memory,memorysync,microsoft
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: agent-framework-core<2,>=1.8
Requires-Dist: httpx<1,>=0.25
Description-Content-Type: text/markdown

# agent-framework-memorysync

[MemorySync](https://memorysync.io) for the
[Microsoft Agent Framework](https://github.com/microsoft/agent-framework):
agents that remember users across sessions — without ever stalling a run.

```bash
pip install agent-framework-memorysync
```

## Quick start

```python
from agent_framework import Agent
from agent_framework_memorysync import MemorySyncContextProvider

provider = MemorySyncContextProvider(
    api_key="ms_...",          # or MEMORYSYNC_API_KEY
    user_id="customer-42",     # required — who these memories belong to
    session_id="support",      # tags the facts from this conversation
)

agent = Agent(client=..., context_providers=[provider])
result = await agent.run("which seat should I book?")
```

Every run recalls relevant memories into the **instructions layer** under
a hard budget, and after the run the user's messages are sent to
MemorySync, which extracts the durable facts they contain — no extra code
per turn. The agent's replies are not sent: assistant replies are not
stored as memories.

## Why this one

| | Mem0 (`agent-framework-mem0`, in-repo) | Zep (`zep-ms-agent-framework`) | **MemorySync** |
| --- | --- | --- | --- |
| Injection layer | ✗ fabricates a `role="user"` message | ✓ instructions | ✓ instructions |
| Recall latency budget | ✗ none | ✗ none | ✓ hard 1.2s default — a slow backend means an unenriched run, never a late one |
| Capture failure behaviour | ✗ **`after_run` errors crash the agent** | swallowed | ✓ entirely fail-open, logged |
| Scope model | ✗ storage ≠ retrieval scopes — forget `search_user_id` and the agent is silently memoryless | single | ✓ one `user_id` drives both — the bug cannot exist |
| Per-run identity | ✗ construction-only | ✗ construction-only (documented) | ✓ `agent.run(..., options={"memorysync_user_id": ...})` or a `user_id_resolver` |
| Write dedup | ✗ re-adds every turn | ✗ | ✓ deterministic idempotency seeds — a retried turn is recognised and not extracted twice |
| Tool-loop double-capture | ✗ | — | ✓ `after_run_once_per_turn = True` |
| Release status | beta (`1.0.0b…`) | 0.2.1 | ✓ stable 1.1.0 |
| Python | ≥3.10 | ✗ ≥3.11 only | ✓ ≥3.10 (matches the framework) |

## Semantics worth knowing

- **User messages are sent to fact extraction; only durable facts are
  stored.** After each run, every user input message goes to MemorySync
  as plain text with `role: "user"` under the
  `agent-framework::<session>` session scope. The server extracts the
  durable facts it contains and stores only those, tagged with
  `session_id: "agent-framework::<session>"` — the same shared user
  memories as every other MemorySync surface. Filler such as "ok" or
  "thanks" yields none, and the message text itself is not stored. The
  agent's replies are not sent: assistant replies are not stored as
  memories.
- The resolved run identity is pinned in the provider's session-state
  slice, so recall and capture can never diverge within a run — and the
  slice stays JSON-native, so `AgentSession` serialization keeps working.
- `expose_search_tool=True` adds `search_memory` + `save_memory` tools
  via `context.extend_tools`.
- Free-tier quota exhaustion is silent by design (adds accepted-without-
  storing, reads empty); evaluation keys surface strict `429`s.

## Configuration

| Parameter | Default | Meaning |
| --- | --- | --- |
| `user_id` | — (required) | End user the memories belong to |
| `session_id` | `"default"` | Session scope: the `session_id` (`agent-framework::<session>`) carried by the facts from this conversation |
| `top_k` | `5` | Memories considered per run |
| `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 |
| `capture` | `True` | Send the run's user messages for fact extraction after each run |
| `expose_search_tool` | `False` | Register memory tools on every run |
| `user_id_resolver` | `None` | `Callable[[AgentSession], str]` for dynamic identity |

## Development

```bash
pip install -e . agent-framework-core pytest pytest-asyncio "httpx>=0.25,<1"
python -m pytest tests -q     # 26 tests incl. a REAL Agent run (stub chat client)
```

## License

MIT
