Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 42 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,30 +9,36 @@ pip install getmnemo
## Quickstart

```python
from mnemo import Mnemo
from getmnemo import Mnemo

memory = Mnemo(api_key="lk_live_...", workspace_id="ws_...")
memory = Mnemo(api_key="prfly_live_...", default_container_tag="user:jane")

# Store an atomic fact
memory.add("User prefers Japanese short-grain rice for onigiri.")

# Retrieve relevant facts
hits = memory.search("what kind of rice does the user like?")
for hit in hits.hits:
# Retrieve relevant facts — returns a list of ranked hits
results = memory.search("what kind of rice does the user like?")
for hit in results:
print(f"{hit.score:.2f} {hit.content}")
```

Every call is scoped to a **container** — a `"<type>:<id>"` string such as
`"user:jane"` or `"project:alpha"`. Set it once on the client
(`default_container_tag=`) or per call (`container_tag=`). Searching a
container that has never been written to returns an empty list.

Async variant:

```python
import asyncio
from mnemo import AsyncMnemo
from getmnemo import AsyncMnemo

async def main() -> None:
async with AsyncMnemo(api_key="...", workspace_id="...") as m:
async with AsyncMnemo(api_key="...", default_container_tag="user:jane") as m:
await m.add("Trip to Costa Rica was 5 days, brought 7 shirts.")
res = await m.search("how many shirts did I pack?")
print(res.hits[0].content)
results = await m.search("how many shirts did I pack?")
if results:
print(results[0].content)

asyncio.run(main())
```
Expand All @@ -44,22 +50,42 @@ The client reads from env vars when arguments are not passed explicitly:
| Env var | Default | Notes |
|---|---|---|
| `GETMNEMO_API_KEY` | (required) | from <https://app.mnemohq.com/settings/api-keys> |
| `GETMNEMO_WORKSPACE_ID` | (required) | from the dashboard URL |
| `GETMNEMO_ACTOR_ID` | none | optional — scopes calls to a single user |
| `GETMNEMO_CONTAINER_TAG` | none | default container, e.g. `user:jane` |
| `GETMNEMO_WORKSPACE_ID` | none | deprecated — identity comes from the API key |
| `GETMNEMO_API_URL` | `https://api.mnemohq.com` | override for self-hosted |

## API surface

| Method | Purpose |
|---|---|
| `search(query, *, limit=8, actor_id=None)` | Hybrid 7-strategy retrieval. Returns `SearchResponse`. |
| `add(content, *, metadata=None, actor_id=None)` | Store an atomic fact. Returns `Memory`. |
| `update(memory_id, *, content=None, metadata=None)` | Patch existing memory. |
| `delete(memory_id)` | Remove a memory. |
| `list(*, limit=20, cursor=None, actor_id=None)` | Cursor-paginated list. |
| `search(q, *, container_tag=None, limit=None)` | Hybrid retrieval. Returns `list[SearchHit]`. |
| `add(content, *, container_tag=None, metadata=None)` | Store an atomic fact. Returns `AddResponse`. |
| `add_many(items, *, container_tag=None)` | Store 1–100 memories in one request. Returns `AddResponse`. |
| `update(memory_id, *, content=None, metadata=None, container_tag=None)` | Patch existing memory. |
| `delete(memory_id, *, container_tag=None)` | Remove a memory. |
| `list(*, limit=20, cursor=None, container_tag=None)` | Cursor-paginated list. |

All methods exist on both `Mnemo` (sync) and `AsyncMnemo` (async).

`add_many` items are content strings or mappings:

```python
memory.add_many([
"Standup moved to 9:30.",
{"content": "Invoices are net-30.", "memory_type": "fact", "idempotency_key": "inv-policy-1"},
])
```

### Upgrading from 0.1.x

0.2.0 tracks the current Mnemo API; 0.1.x requests are rejected by it.

- `workspace_id` is no longer required (the API key carries identity); pass a
container instead: `Mnemo(api_key=..., default_container_tag="user:jane")`.
- `search("q")` now returns a `list[SearchHit]` (was `SearchResponse.hits`).
- `add(...)` now returns an `AddResponse` (was a single `Memory`).
- `actor_id` was removed — use per-user container tags.

## Development

```bash
Expand Down
8 changes: 4 additions & 4 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "hatchling.build"

[project]
name = "getmnemo"
version = "0.1.2"
version = "0.2.0"
description = "Python SDK for Mnemo Memory — long-term memory infrastructure for AI agents."
readme = "README.md"
license = { text = "MIT" }
Expand Down Expand Up @@ -45,11 +45,11 @@ dev = [
[project.urls]
Homepage = "https://mnemohq.com"
Documentation = "https://mnemohq.com/docs"
Repository = "https://github.com/getmnemo/getmnemo-python"
Issues = "https://github.com/getmnemo/getmnemo-python/issues"
Repository = "https://github.com/ledgermem/getmnemo-python"
Issues = "https://github.com/ledgermem/getmnemo-python/issues"

[tool.hatch.build.targets.wheel]
packages = ["src/mnemo"]
packages = ["src/getmnemo", "src/mnemo"]

[tool.ruff]
line-length = 100
Expand Down
54 changes: 54 additions & 0 deletions src/getmnemo/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
"""Mnemo Memory — Python SDK.

Quickstart:

from getmnemo import Mnemo

memory = Mnemo(api_key="prfly_live_...", default_container_tag="user:jane")
memory.add("User prefers Japanese short-grain rice for onigiri.")
results = memory.search("what kind of rice does the user like?")
for hit in results:
print(hit.score, hit.content)

Async variant:

import asyncio
from getmnemo import AsyncMnemo

async def main() -> None:
async with AsyncMnemo(api_key="...", default_container_tag="user:jane") as m:
await m.add("Trip to Costa Rica was 5 days, brought 7 shirts.")
results = await m.search("how many shirts did I pack for Costa Rica?")
if results:
print(results[0].content)

asyncio.run(main())
"""

from .client import AsyncMnemo, Mnemo
from .errors import MnemoError, MnemoHTTPError
from .models import (
AddResponse,
Memory,
MemoryWriteReceipt,
MemoryWriteReceiptItem,
MemoryWriteStats,
PaginatedMemories,
SearchHit,
)

__all__ = [
"AddResponse",
"AsyncMnemo",
"Memory",
"MemoryWriteReceipt",
"MemoryWriteReceiptItem",
"MemoryWriteStats",
"Mnemo",
"MnemoError",
"MnemoHTTPError",
"PaginatedMemories",
"SearchHit",
]

__version__ = "0.2.0"
Loading
Loading