# memoralabs

Python SDK for [MemoraLabs](https://memoralabs.io) — persistent, self-improving memory for AI agents.

Store and recall memories in 5 lines of Python. Memory retrieval improves over time using Q-learning and temporal decay, so your agents get smarter, not just bigger.

## Installation

```bash
pip install memoralabs
```

Requires Python 3.9+ and installs only one dependency: [httpx](https://www.python-httpx.org/).

## Quick start

```python
from memoralabs import MemoraLabs
client = MemoraLabs(api_key="ml_your_key")
memory = client.add("User prefers dark mode", user_id="user_42")
results = client.search("display preferences", user_id="user_42")
print(results.results[0].text)
```

Get an API key at [memoralabs-api.onrender.com/docs](https://memoralabs-api.onrender.com/docs).

## All methods

| Method | Description | Returns |
|--------|-------------|---------|
| `signup(name, email, plan)` | Register a new developer account | `SignupResponse` |
| `rotate_key()` | Rotate your API key (revokes old key) | `KeyRotateResponse` |
| `add(text, *, user_id, agent_id, session_id, metadata)` | Store a new memory | `MemoryResponse` |
| `get(memory_id)` | Retrieve a memory by ID | `MemoryResponse` |
| `list(*, page, per_page, user_id, agent_id, session_id)` | Paginated list of memories | `MemoryListResponse` |
| `update(memory_id, *, text, metadata)` | Update a memory's text or metadata | `MemoryResponse` |
| `delete(memory_id)` | Delete a memory | `bool` |
| `search(query, *, user_id, agent_id, session_id, limit, min_score)` | Semantic search | `SearchResponse` |
| `gaps()` | Detect knowledge gaps in stored memories | `GapResponse` |
| `billing_status()` | Current plan, usage counts, billing dates | `BillingStatusResponse` |
| `checkout(*, success_url, cancel_url)` | Create a Stripe Checkout session for Pro | `CheckoutResponse` |

All optional keyword arguments default to `None` and are omitted from requests when not provided.

## Error handling

```python
from memoralabs import MemoraLabs, AuthError, PlanLimitError, NotFoundError

client = MemoraLabs(api_key="ml_your_key")

try:
    results = client.search("user preferences", user_id="user_42")
except AuthError:
    print("Invalid API key — check your credentials")
except PlanLimitError as e:
    print(f"Plan limit reached. Upgrade at: {e.upgrade_url}")
except NotFoundError:
    print("Memory not found")
```

All SDK exceptions inherit from `MemoraLabsError` and expose:
- `status_code` — HTTP status returned by the API
- `error_code` — Machine-readable error string (e.g. `"PLAN_LIMIT_EXCEEDED"`)
- `message` — Human-readable description

Type errors are raised **before** any HTTP request is made, so you catch mistakes at call time rather than from network responses.

## Context manager

```python
with MemoraLabs(api_key="ml_your_key") as client:
    client.add("Session started", user_id="user_42")
# Connection pool released automatically
```

## Namespacing memories

Use `user_id`, `agent_id`, and `session_id` to isolate memories across users, agents, and conversations:

```python
# Store memory for a specific user and agent
client.add(
    "Prefers Python over JavaScript",
    user_id="user_42",
    agent_id="coding-assistant",
    session_id="session_101",
)

# Search only within that user's memories
results = client.search("language preference", user_id="user_42")
```

## Full API reference

[memoralabs-api.onrender.com/docs](https://memoralabs-api.onrender.com/docs)
