Metadata-Version: 2.4
Name: memorysync
Version: 1.0.0
Summary: Official Python client for the MemorySync API.
Project-URL: Homepage, https://memorysync.dev
Project-URL: Documentation, https://memorysync.dev/docs
Author: MemorySync
License: MIT
License-File: LICENSE
Keywords: client,memory,memorysync,sdk
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.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Requires-Python: >=3.9
Requires-Dist: httpx<1.0,>=0.25
Requires-Dist: typing-extensions>=4.5; python_version < '3.11'
Description-Content-Type: text/markdown

# memorysync

Official Python client for the MemorySync API. Sync and async, no surprises.

```bash
pip install memorysync
```

## Quick start

```python
from memorysync import MemorySyncClient

ms = MemorySyncClient(
    api_key="...",
    base_url="https://api.memorysync.dev",
    project_id="proj_xxxxxxxxxxxxxxxx",   # optional
    end_user_id="user_42",                 # optional
)

ms.add("User prefers dark mode.")

result = ms.query("ui preferences", k=5)
for m in result.memories:
    print(m.id, m.text)
```

## Async usage

```python
import asyncio
from memorysync import AsyncMemorySyncClient

async def main():
    async with AsyncMemorySyncClient(api_key="...", base_url="...") as ms:
        result = await ms.query("ui preferences", k=5)
        print(result.memories)

asyncio.run(main())
```

Use `MemorySyncClient` as a context manager when you want deterministic
connection cleanup:

```python
with MemorySyncClient(api_key="...", base_url="...") as ms:
    ms.add("...")
```

## Configuration

| Argument        | Required | Description                                                                                  |
| --------------- | -------- | -------------------------------------------------------------------------------------------- |
| `api_key`       | yes      | Sent as `X-API-Key`. Provision in your MemorySync dashboard.                                 |
| `base_url`      | yes      | Deployment URL of your MemorySync instance.                                                  |
| `project_id`    | no       | Pin every request to a project (`X-Project-ID`). Format: `proj_` + 16 hex chars.             |
| `end_user_id`   | no       | Identify which of *your* users this client speaks for (`X-End-User-ID`).                     |
| `timeout`       | no       | Per-request timeout in seconds. Default `30.0`.                                              |
| `transport`     | no       | Inject a custom `httpx` transport (tests, retries, proxies).                                 |

`end_user_id` can also be passed per-call on `add()` to override the client default.

## Methods

Every method maps 1:1 to a real HTTP route. The two clients share the same
surface; only the call style differs (sync vs `await`).

| Method                                       | Route                                  |
| -------------------------------------------- | -------------------------------------- |
| `add(text, **opts)`                          | `POST /memory/add`                     |
| `bulk_add(items, *, deduplicate=True)`       | `POST /memory/bulk-add`                |
| `query(query, *, k=None, ...)`               | `POST /memory/query`                   |
| `get(memory_id)`                             | `GET /memory/{id}`                     |
| `update(memory_id, **fields)`                | `PATCH /memory/{id}`                   |
| `forget(memory_ids, *, reason=None)`         | `DELETE /memory/forget`                |
| `summarize(memory_ids, *, lossless=False)`   | `POST /memory/summarize`               |
| `compose(prompt_template, *, recall_k=None)` | `POST /memory/compose`                 |
| `export_all()`                               | `GET /memory/export`                   |
| `create_relation(from_id, **opts)`           | `POST /memory/{id}/relations`          |

### `add` returns one of two shapes

`add()` runs through MemorySync's extraction pipeline, so input that carries no
high-value content is intentionally skipped. Branch on the type of the result:

```python
from memorysync import AddSkippedResponse, Memory

result = ms.add("User prefers dark mode.")
if isinstance(result, AddSkippedResponse):
    print("skipped:", result.reason)
else:
    assert isinstance(result, Memory)
    print(result.id, result.text)
```

## Errors

Every non-2xx response raises a typed subclass of `MemorySyncError`:

| Class             | When                                        |
| ----------------- | ------------------------------------------- |
| `AuthError`       | `401` / `403` — bad key, missing scope.     |
| `ValidationError` | `400` / `409` / `422`.                      |
| `NotFoundError`   | `404` — record not visible to the caller.   |
| `RateLimitError`  | `429` — read `err.retry_after_seconds`.     |
| `ServerError`     | `5xx`.                                      |
| `MemorySyncError` | Network errors, timeouts, anything else.    |

Every error carries `status_code`, `response`, and the server-issued
`request_id` (when present) for support escalation.

```python
import time
from memorysync import RateLimitError

try:
    ms.add("...")
except RateLimitError as e:
    time.sleep(e.retry_after_seconds)
```

## License

MIT
