memory-model 0.0.4
Official Python SDK for MemoryModel API
License: MIT
Requires Python: >=3.8
Keywords: agents, ai, memory, memory-model, sdk

# memory-model

Official Python SDK for [MemoryModel](https://memorymodel.dev).

## Installation

```bash
pip install memory-model
```

## Quick Start

```python
from memory_model import MemoryClient

client = MemoryClient(
    api_key="sk_live_...",
    default_end_user_id="user_123"
)

# Add a memory
client.add("Project deadline is Friday.")

# Search memories
results = client.search("When is the deadline?")
for memory in results:
    print(f"[{memory.similarity:.2f}] {memory.content}")
```

---

## API Reference

### Constructor

```python
MemoryClient(
    api_key: str,                      # Required
    base_url: str = "https://api.memorymodel.dev",
    default_end_user_id: str = None,
    timeout: int = 30,                 # Seconds
    max_retries: int = 3,              # Retries for 5xx/429
    api_version: str = "v1"            # API version prefix
)
```

### Methods

#### `add(content, *, user_context=None, end_user_id=None)`
```python
response = client.add("Meeting moved to 3pm.", user_context="Calendar update")
print(response.job_id)
```

#### `add_image(image_data, *, user_context=None, end_user_id=None)`
```python
import base64
with open("screenshot.png", "rb") as f:
    img_b64 = base64.b64encode(f.read()).decode()

response = client.add_image(img_b64, user_context="Error screenshot")
```

#### `search(query, *, limit=5, strategy="centroid_aware", end_user_id=None)`
```python
results = client.search("What time is the meeting?", limit=3)
```

#### `list(*, limit=50, memory_type=None, end_user_id=None)`
```python
memories = client.list(limit=10)
```

#### `delete(memory_id, *, end_user_id=None)`
```python
client.delete("mem_abc123")
```

#### `search_image(image_data, *, limit=5, end_user_id=None)` — Visual Similarity Search
```python
import base64

# Load and encode image
with open("query_image.jpg", "rb") as f:
    img_b64 = base64.b64encode(f.read()).decode()

# Find visually similar memories
results = client.search_image(img_b64, limit=5)
for memory in results:
    print(f"Found: {memory.id}")
    if hasattr(memory, 'source_doc'):
        print(f"  → From: {memory.source_doc}, Page: {memory.page_number}")
```

> **Note**: Image search finds memories visually similar to the input image. Only memories ingested via `add_image()` will be matched.

#### `add_document(storage_path, *, end_user_id=None)` — Ingest PDF Document
```python
# First, upload the PDF to your storage bucket
# Then trigger server-side processing

client.add_document("projects/my-project/docs/contract.pdf")
```

This method triggers server-side PDF processing that:
1. Extracts text from each page
2. Creates separate memories with `source_doc` and `page_number` metadata
3. Allows you to trace which page a memory came from

---

## Error Handling

```python
from memory_model import MemoryClient, MemoryClientError

try:
    client.search("test")
except MemoryClientError as e:
    print(e.message)       # Human-readable error
    print(e.status)        # HTTP status (401, 429, 500...)
    print(e.code)          # Error code from API
    print(e.is_retryable)  # True for 5xx/429
```

**Automatic Retry**: The SDK retries on 5xx/429 with exponential backoff (1s → 2s → 4s).

---

## Agent Integration

### LangChain / CrewAI Example

```python
from memory_model import MemoryClient
from langchain_openai import ChatOpenAI
from langchain.schema import SystemMessage, HumanMessage

memory = MemoryClient(api_key="sk_live_...", default_end_user_id="user_123")
llm = ChatOpenAI(model="gpt-4o")

def agent_respond(user_message: str) -> str:
    # 1. Store user message
    memory.add(user_message, user_context="User question")
    
    # 2. Retrieve context
    context = memory.search(user_message, limit=3)
    context_str = "\n".join([f"- {m.content}" for m in context])
    
    # 3. Generate response
    messages = [
        SystemMessage(content=f"Context:\n{context_str}"),
        HumanMessage(content=user_message)
    ]
    response = llm.invoke(messages)
    
    return response.content
```

---

### Image-Based Search Example

```python
import base64
from memory_model import MemoryClient

memory = MemoryClient(api_key="sk_live_...", default_end_user_id="user_123")

def find_similar_images(image_path: str):
    # 1. Load and encode query image
    with open(image_path, "rb") as f:
        img_b64 = base64.b64encode(f.read()).decode()
    
    # 2. Search for visually similar memories
    results = memory.search_image(img_b64, limit=5)
    
    # 3. Results may include source document info
    for mem in results:
        print(f"Found: {mem.id}")
        if hasattr(mem, 'source_doc'):
            print(f"  → From: {mem.source_doc}, Page: {mem.page_number}")
    
    return results
```