# AIMemory Client

A lightweight Python client for interacting with self-hosted AIMemory Servers.

## Features

- **Lightweight** - Only depends on `httpx` (~1MB)
- **Simple API** - Easy-to-use sync and async clients
- **Type Hints** - Full type annotations for IDE support
- **Context Managers** - Automatic connection cleanup

## Installation

```bash
pip install aimemory-client
```

## Quick Start

### Synchronous Client

```python
from aimemory_client import AIMemoryClient

# Initialize client
client = AIMemoryClient(host="http://localhost:8080")

# Add a memory
client.add("I love pizza", user_id="user123")

# Search memories
results = client.search("What food do I like?", user_id="user123")
print(results)

# Get all memories for a user
memories = client.get_all(user_id="user123")

# Update a memory
client.update(memory_id="mem_abc123", text="I love sushi now")

# Delete a memory
client.delete(memory_id="mem_abc123")

# Close the client when done
client.close()
```

### Using Context Manager (Recommended)

```python
from aimemory_client import AIMemoryClient

with AIMemoryClient(host="http://localhost:8080") as client:
    client.add("I love pizza", user_id="user123")
    results = client.search("What food do I like?", user_id="user123")
```

### Asynchronous Client

```python
import asyncio
from aimemory_client import AsyncAIMemoryClient

async def main():
    async with AsyncAIMemoryClient(host="http://localhost:8080") as client:
        await client.add("I love pizza", user_id="user123")
        results = await client.search("What food do I like?", user_id="user123")
        print(results)

asyncio.run(main())
```

## API Reference

### AIMemoryClient / AsyncAIMemoryClient

#### Constructor

```python
AIMemoryClient(
    host: str = "http://localhost:8080",  # AIMemory server URL
    timeout: int = 300,                    # Request timeout in seconds
    client: Optional[httpx.Client] = None  # Custom httpx client
)
```

#### Methods

| Method | Description |
|--------|-------------|
| `add(messages, user_id, agent_id, run_id, metadata)` | Create new memories |
| `get(memory_id)` | Get a specific memory by ID |
| `get_all(user_id, agent_id, run_id)` | Get all memories for an identifier |
| `search(query, user_id, agent_id, run_id, filters)` | Search memories |
| `update(memory_id, text)` | Update a memory |
| `delete(memory_id)` | Delete a specific memory |
| `delete_all(user_id, agent_id, run_id)` | Delete all memories for an identifier |
| `history(memory_id)` | Get memory change history |
| `reset()` | Reset all memories (use with caution!) |
| `close()` | Close the HTTP client connection |

### Adding Memories

The `add` method accepts messages in multiple formats:

```python
# Simple string
client.add("I love pizza", user_id="user123")

# Single message dict
client.add({"role": "user", "content": "I love pizza"}, user_id="user123")

# List of messages (conversation)
client.add([
    {"role": "user", "content": "What's my favorite food?"},
    {"role": "assistant", "content": "You mentioned you love pizza!"}
], user_id="user123")

# With metadata
client.add(
    "I love pizza",
    user_id="user123",
    metadata={"source": "conversation", "topic": "food"}
)
```

### Identifiers

At least one identifier is required for most operations:

- `user_id` - Identify memories by user
- `agent_id` - Identify memories by AI agent
- `run_id` - Identify memories by conversation/session run

```python
# User memories
client.add("I love pizza", user_id="user123")

# Agent memories
client.add("User prefers formal tone", agent_id="agent456")

# Session memories
client.add("Current topic: travel", run_id="session789")

# Combined
client.add("Planning trip to Italy", user_id="user123", agent_id="agent456")
```

## Error Handling

```python
import httpx
from aimemory_client import AIMemoryClient

client = AIMemoryClient(host="http://localhost:8080")

try:
    result = client.get("nonexistent_id")
except httpx.HTTPStatusError as e:
    if e.response.status_code == 404:
        print("Memory not found")
    else:
        print(f"API error: {e.response.status_code}")
except httpx.ConnectError:
    print("Could not connect to AIMemory server")
```

## Custom HTTP Client

You can provide your own httpx client for advanced configuration:

```python
import httpx
from aimemory_client import AIMemoryClient

# Custom client with authentication, retries, etc.
custom_client = httpx.Client(
    timeout=60,
    headers={"Authorization": "Bearer your-token"},
    limits=httpx.Limits(max_connections=100),
)

client = AIMemoryClient(host="http://localhost:8080", client=custom_client)
```

## Requirements

- Python 3.9+
- httpx >= 0.24.0

## License

Apache 2.0
