Metadata-Version: 2.5
Name: pydantic-ai-memorysync
Version: 1.0.0
Summary: MemorySync memory for Pydantic AI: a drop-in agent capability that injects recalled context every run and persists completed turns, plus typed memory tools and async helpers.
Project-URL: Homepage, https://memorysync.io
Project-URL: Documentation, https://docs.memorysync.io/guides/pydantic-ai
Project-URL: API Reference, https://docs.memorysync.io/api/overview
Project-URL: Changelog, https://docs.memorysync.io/release-notes
Project-URL: Support, https://docs.memorysync.io/debugging/support
Project-URL: Status, https://status.memorysync.io
Author: MemorySync
License: MIT
Keywords: agent-memory,ai,ai-agents,capability,llm,long-term-memory,memory,memorysync,pydantic,pydantic-ai
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
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 :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Requires-Python: >=3.10
Requires-Dist: httpx<1.0,>=0.25
Requires-Dist: memorysync>=1.9
Requires-Dist: pydantic-ai-slim<3,>=2
Requires-Dist: pydantic>=2.4
Description-Content-Type: text/markdown

# pydantic-ai-memorysync

Long-term memory for [Pydantic AI](https://ai.pydantic.dev), backed by [MemorySync](https://memorysync.io) — one capability in the `Agent(...)` constructor gives every run recalled context and automatic turn persistence.

- **`MemorySyncCapability`** — injects what MemorySync knows about the user before every run and persists completed turns after it, through the framework's own capability channels.
- **Five agent tools** — add, search, list, update, delete; they never raise.
- **`create_memory_search_tool`** — memory search returning **typed** `list[MemoryResult]` Pydantic models.
- **Async helpers** — `get_memory_context`, `search_memories`, `save_turn`.

```bash
pip install pydantic-ai-memorysync
```

Set `MEMORYSYNC_API_KEY` in the environment (create a key at [app.memorysync.io](https://app.memorysync.io)), or pass `api_key` explicitly. Python 3.10+, `pydantic-ai` 2.x.

## The capability

```python
from pydantic_ai import Agent
from pydantic_ai_memorysync import MemorySyncCapability

agent = Agent(
    "openai:gpt-5",
    instructions="You are a helpful assistant.",
    capabilities=[MemorySyncCapability(user_id="customer-7")],
)

result = await agent.run("What should I cook tonight?")
# The model saw "Relevant memories about this user..." — and this
# exchange is now remembered for every future run.
```

**Recall rides the instructions channel.** The capability contributes a dynamic instruction (the framework's `get_instructions` channel), so recalled memory lands in `ModelRequest.instructions` — visible to the model, but never a conversation *part*. Replaying `result.all_messages()` into the next run can never stack stale memory blocks into the transcript, the classic failure mode of message-mutation integrations. One recall per run, replayed identically across however many model requests a tool-calling run makes.

**Persistence is success-only, by construction.** Turns persist in `after_run`, which Pydantic AI fires **only when the run succeeds** — a failed run leaves no half-turn behind (no remembered question with no answer), with zero custom guard code to get wrong. Tool calls, retry prompts and thinking parts never persist; streaming runs persist the final streamed text.

**Identity comes from your deps.** In order: `user_id_resolver(ctx)` when provided, the static `user_id`, then a `user_id` attribute on `ctx.deps`:

```python
from dataclasses import dataclass

@dataclass
class MyDeps:
    user_id: str

agent = Agent(
    "openai:gpt-5",
    deps_type=MyDeps,
    capabilities=[MemorySyncCapability()],  # reads ctx.deps.user_id per run
)
await agent.run("hi", deps=MyDeps(user_id="customer-7"))
```

Without an identity the run proceeds memoryless and the miss is reported through `on_error` — guessing a shared namespace would mix users' memories, the one unforgivable failure for a memory layer.

**Failure discipline:** recall failures degrade to the agent's base instructions; persistence failures leave the run result untouched. Both report through `on_error` (default: a `logging` warning); neither ever breaks a run the model completed. `persist=False` gives read-only memory.

**Conversations group themselves.** Turns are keyed by the run's `conversation_id`, which Pydantic AI carries across `message_history` continuations — one conversation stays one conversation across processes and deploys. Pass `session_id="..."` to pin the grouping yourself.

## Agent tools

```python
from pydantic_ai import Agent
from pydantic_ai_memorysync import create_memorysync_tools

agent = Agent(
    "openai:gpt-5",
    instructions="Use the memory tools to remember durable facts.",
    tools=create_memorysync_tools(user_id="customer-7"),
)

# Untrusted agents: search + list only.
create_memorysync_tools(user_id="customer-7", read_only=True)
```

`add_memory`, `search_memory`, `list_memories`, `update_memory`, `delete_memory` — the same five operations, same response strings as the MemorySync LangChain, AI SDK, CrewAI, Mastra, OpenAI Agents, LlamaIndex and Google ADK tool sets. Plain async callables; failures return short readable strings, never exceptions — in Pydantic AI a tool exception fails the whole run, and a memory lookup is never worth that.

### Typed search results

```python
from pydantic_ai_memorysync import create_memory_search_tool, MemoryResult

agent = Agent(
    "openai:gpt-5",
    tools=[create_memory_search_tool(user_id="customer-7")],
)
# The tool returns list[MemoryResult]: validated id / text / score fields.
```

## Helpers

```python
from pydantic_ai_memorysync import get_memory_context, save_turn, search_memories

context = await get_memory_context("what should I cook?", user_id="customer-7")
hits = await search_memories("dietary preferences", user_id="customer-7")
await save_turn(user_id="customer-7", user="I'm vegetarian", assistant="Noted!")
```

All surfaces share the same idempotency seeds, so mixing styles cannot double-store a turn. `save_turn` raises on failure — an explicit persist call is owed the truth.

## Version support

| Package | Requires | Runtime |
| --- | --- | --- |
| `pydantic-ai-memorysync` 1.0.0 | `pydantic-ai` (or `-slim`) >=2,<3 | Python 3.10+ |

CI drives REAL agents — instruction-channel injection, replay safety, success-only persistence, streaming, typed tool results — against the latest `pydantic-ai` 2.x release on every push.

## Documentation

- [Pydantic AI Memory guide](https://docs.memorysync.io/guides/pydantic-ai)
- [MemorySync docs](https://docs.memorysync.io)
- [Get an API key](https://app.memorysync.io)
