Metadata-Version: 2.5
Name: strands-memorysync
Version: 1.1.0
Summary: MemorySync for Strands Agents: a MemoryStore with budgeted automatic recall before every model call, turn-by-turn duplicate-proof extraction, and a crash-proof initialize — zero framework dependencies.
Project-URL: Homepage, https://docs.memorysync.io/guides/strands
Project-URL: Documentation, https://docs.memorysync.io/guides/strands
Project-URL: Repository, https://github.com/memorysyncio/memorysync-plugins
Author-email: MemorySync <support@memorysync.io>
License-Expression: MIT
Keywords: agents,aws,long-term-memory,memory,memorysync,strands,strands-agents
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: httpx<1,>=0.25
Description-Content-Type: text/markdown

# strands-memorysync

[MemorySync](https://memorysync.io) for
[Strands Agents](https://github.com/strands-agents) (AWS's agent SDK):
automatic memory injection before every model call, duplicate-proof
turn-by-turn extraction, and a crash-proof lifecycle — with **zero
framework dependencies**.

```bash
pip install strands-memorysync
```

## Quick start

```python
from strands import Agent
from strands.memory import MemoryManager
from strands_memorysync import MemorySyncStore

store = MemorySyncStore(
    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(memory_manager=MemoryManager(stores=[store]))
agent("which seat should I book?")
```

The `MemoryManager` consults the store before **every** model call
(automatic injection — not tool-gated), and the extraction sink sends the
user's messages to MemorySync, which extracts the durable facts they
contain. The agent's replies are not sent: assistant replies are not
stored as memories.

## Why this one

| | Mem0 (`mem0_memory` tool in strands-tools) | Zep (`zep-strands` 0.1.0) | **MemorySync** |
| --- | --- | --- | --- |
| Automatic injection | ✗ tool-gated — the LLM must decide to recall | ✓ | ✓ |
| `initialize()` safety | — | ✗ **shipped an event-loop crash** (`RuntimeError: bound to a different event loop`; fix unreleased) | ✓ deliberately inert — a test asserts zero network calls |
| First-turn recall | — | ✗ 5-turn extraction lag: early recalls return nothing | ✓ turn-by-turn extraction works from the first exchange (idempotent writes make it safe) |
| Failure blast radius | sync client blocks the loop | ✗ store errors surface as unhandled `AggregateMemoryError` | ✓ search and extraction fail open; only explicit `add()` raises |
| Model-facing danger | ✗ exposes a **`delete` action** — one prompt injection wipes memories | — | ✓ search + save tools only; identity never model-facing |
| Data at rest | ✗ default FAISS path in `/tmp` — wiped on restart | cloud | ✓ MemorySync cloud |
| Framework pin | — | ✗ `strands-agents>=1.45` | ✓ **zero dependencies** (Protocol duck-typing) |
| Retry safety | ✗ duplicates | — | ✓ deterministic idempotency seeds — a retried turn is recognised and not extracted twice |
| Python | — | ✗ ≥3.11 | ✓ ≥3.10 (matches the framework) |

## Semantics worth knowing

- **User messages are sent to fact extraction; only durable facts are
  stored.** Each user message in a batch goes to MemorySync as plain text
  with `role: "user"` under the `strands::<session>` session scope. The
  server extracts the durable facts it contains and stores only those,
  tagged with `session_id: "strands::<session>"`; filler such as "ok" or
  "thanks" yields none, and the message text itself is not stored.
  Deterministic seeds let the server recognise manager retries and batch
  overlaps as the same turn and not extract it twice.
- Assistant replies are not sent (they are not stored as memories);
  tool and system messages never are. A batch with nothing the user said
  makes no request at all.
- **Turn-by-turn extraction.** With the default `extraction=True`,
  Strands extracts every 5 invocations (the synchronous `agent(...)`
  entry point also flushes after each call; `invoke_async` does not).
  For turn-by-turn extraction on every path, pass an invocation trigger:

  ```python
  from strands.memory import InvocationTrigger

  store = MemorySyncStore(user_id="customer-42",
                          extraction={"trigger": InvocationTrigger()})
  ```

  MemorySync's writes are cheap and idempotent, so this is safe, and
  memories are recallable from the very first exchange.
- `AddMessagesContext.sequence_numbers` travel as each user turn's
  `sequence` metadata, which its facts carry.
- Free-tier quota exhaustion is silent by design (adds accepted-without-
  storing, reads empty); evaluation keys surface strict `429`s.
- `store.get_tools()` returns `memorysync_search` + `memorysync_save`
  (`@tool`-decorated) — enabled via the MemoryManager's tool config.

## Configuration

| Parameter | Default | Meaning |
| --- | --- | --- |
| `user_id` | — (required) | End user the memories belong to |
| `session_id` | `"default"` | Session scope: the `session_id` (`strands::<session>`) carried by the facts from this conversation |
| `top_k` | `5` | Memories considered per model call |
| `recall_timeout` | `1.2` | Hard recall budget, seconds |
| `min_prompt_chars` | `8` | Skip recall for trivial queries |
| `writable` | `True` | Allow the extraction sink to send user messages for fact extraction |
| `extraction` | `True` | Strands extraction wiring; `{"trigger": InvocationTrigger()}` recommended (see above) |
| `expose_tools` | `True` | Return tools from `get_tools()` |

## Development

```bash
pip install -e . strands-agents pytest pytest-asyncio "httpx>=0.25,<1"
python -m pytest tests -q     # 26 tests incl. a REAL Agent turn (stub Model)
```

## License

MIT
