Metadata-Version: 2.4
Name: anansi-memory
Version: 0.3.0
Summary: The memory layer for AI apps — persistent, synthesized context for any LLM application
Project-URL: Homepage, https://github.com/jsuleiman-davis/anansi
Project-URL: Repository, https://github.com/jsuleiman-davis/anansi
Author: Anansi
License: MIT
Keywords: ai,anansi,context,llm,memory,rag,vector
Classifier: Development Status :: 4 - Beta
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 :: Scientific/Engineering :: Artificial Intelligence
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.9
Description-Content-Type: text/markdown

# anansi-memory

Persistent memory for AI apps, backed by a **bi-temporal knowledge graph** — every fact carries when it was true *and* when you learned it. Give any LLM app long-term memory in two API calls. MIT-licensed and self-hostable.

```bash
pip install anansi-memory
```

## Usage

```python
from anansi_memory import AnansiMemory

memory = AnansiMemory(api_key="ans_...")

# Store a conversation turn
memory.ingest(
    user_id="user_123",
    content="User is building a voice agent. Prefers TypeScript. Team of 4.",
    source_type="conversation",
)

# Before your next LLM call — inject synthesized context into the system prompt
ctx = memory.context(user_id="user_123", q="what is the user building?")
system_prompt = f"You are a helpful assistant.\n\n{ctx.format_for_prompt()}"
```

`context()` returns a synthesized profile — `static` facts and `dynamic` context that drop straight into a prompt, plus `relevant` chunks when you pass `q`. No chunks to dedupe, rank, or trim yourself.

## API

### `AnansiMemory(api_key, base_url=None)`

| Param | Type | Description |
|---|---|---|
| `api_key` | `str` | Your API key (`ans_...`) |
| `base_url` | `str` | Override API base URL (default: `https://anansimemory.com`) |

### `memory.ingest(user_id, content, source_type=None, source_id=None, metadata=None, embedding=None, session_id=None, agent_id=None)`

Store content in a user's memory. Returns `IngestResult(id, queued=True)`.

| Param | Type | Required | Description |
|---|---|---|---|
| `user_id` | `str` | ✓ | Your internal user ID |
| `content` | `str` | ✓ | Text to remember, max 100 KB |
| `source_type` | `str` | | `"conversation"`, `"document"`, `"note"`, `"meeting"`, `"custom"` |
| `source_id` | `str` | | Idempotency key — re-ingesting the same ID is a no-op |
| `metadata` | `dict` | | `title`, `author`, `timestamp`, any custom fields |

### `memory.context(user_id, q=None, as_of=None, as_of_knowledge=None)`

Retrieve synthesized memory for a user. Returns `ContextResult(static, dynamic, relevant, ...)`. Pass `as_of` / `as_of_knowledge` for a bi-temporal point-in-time view (Pro+).

### Also available

```python
results  = memory.search(user_id="user_123", query="dark mode", search_mode="hybrid")
chunks   = memory.list_memories("user_123", source_type="conversation")
entities = memory.list_entities("user_123", as_of="2026-05-01", as_of_knowledge="2026-05-01")
memory.delete_user("user_123")  # GDPR hard-delete

# LangChain-compatible retriever (no langchain dependency required)
from anansi_memory.langchain import AnansiRetriever
retriever = AnansiRetriever(api_key="ans_...", user_id="user_123")
docs = retriever.get_relevant_documents("what stack does the user prefer?")
```

`list_entities` accepts `as_of` (the graph as it was **valid** at an instant) and `as_of_knowledge` (the graph **as we knew it** at an instant). The entity graph is a Pro+ feature.

## Error handling

```python
from anansi_memory import AnansiMemory, AnansiError

try:
    memory.ingest(user_id=user_id, content=content)
except AnansiError as e:
    print(e.status_code, e.args[0])
    # 401 — invalid API key
    # 402 — monthly quota exceeded
    # 413 — content too large
    # 429 — rate limit (retry after 60s)
```

## Requirements

Python 3.9+. No external dependencies — uses stdlib `urllib` only.

## Links

- [Developer Portal](https://anansimemory.com/portal)
- [API Docs](https://anansimemory.com/docs)
- [GitHub](https://github.com/jsuleiman-davis/anansi)

MIT licensed.
