Skip to content

Commit 1a4ea2a

Browse files
committed
docs: add package documentation
1 parent 14fe748 commit 1a4ea2a

33 files changed

+3868
-98
lines changed

.github/workflows/docs.yml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
name: Publish Docs
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
paths:
8+
- "docs/**"
9+
- "mkdocs.yml"
10+
- "memstate/**"
11+
- ".github/workflows/docs.yml"
12+
13+
permissions:
14+
contents: write
15+
16+
jobs:
17+
deploy:
18+
runs-on: ubuntu-latest
19+
steps:
20+
- uses: actions/checkout@v6
21+
22+
- name: Install uv
23+
uses: astral-sh/setup-uv@v7
24+
25+
- name: Set up Python
26+
run: uv python install
27+
28+
- name: Install dependencies
29+
run: uv sync --all-extras --dev
30+
31+
- name: Build and Deploy
32+
run: uv run mkdocs gh-deploy --force

docs/api/backends.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
::: memstate.backends
2+
options:
3+
show_submodules: true

docs/api/index.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# API Reference
2+
3+
Here's the reference or code API, the classes, functions, parameters, attributes, and
4+
all the MemState parts you can use in your applications.

docs/api/integrations.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
::: memstate.integrations
2+
options:
3+
show_submodules: true

docs/api/memstate.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
::: memstate.storage
2+
options:
3+
show_submodules: true

docs/changelog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
--8<-- "CHANGELOG.md"

docs/documentation/backends.md

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
# Backends
2+
3+
MemState separates logic from storage. You can start with `InMemoryStorage` for testing and switch to `PostgresStorage` or `RedisStorage` for production without changing your agent logic.
4+
5+
**Pro Tip: Dependency Injection**
6+
7+
MemState fully supports **Dependency Injection**. For all backends (Postgres, Redis, SQLite), you can pass an existing connection object instead of a connection string.
8+
9+
## PostgreSQL
10+
11+
Uses `SQLAlchemy` + `psycopg`. It supports JSONB for efficient querying.
12+
13+
### Install the requirements
14+
15+
=== "uv"
16+
```bash
17+
uv add memstate[postgres]
18+
```
19+
20+
=== "pip"
21+
```bash
22+
pip install memstate[postgres]
23+
```
24+
25+
### Initialize the storage
26+
27+
=== "sync"
28+
```python
29+
from memstate import MemoryStore
30+
from memstate.backends.postgres import PostgresStorage
31+
32+
url = "postgresql+psycopg://user:pass@localhost:5432/db_name"
33+
storage = PostgresStorage(url)
34+
store = MemoryStore(storage=storage)
35+
```
36+
37+
=== "async"
38+
```python
39+
import asyncio
40+
from memstate import AsyncMemoryStore
41+
from memstate.backends.postgres import AsyncPostgresStorage
42+
43+
async def main():
44+
url = "postgresql+psycopg://user:pass@localhost:5432/db_name"
45+
storage = AsyncPostgresStorage(url)
46+
# Important: You must create tables explicitly in async mode
47+
await store.create_tables()
48+
49+
store = AsyncMemoryStore(storage=storage)
50+
51+
if __name__ == "__main__":
52+
asyncio.run(main())
53+
```
54+
55+
## Redis
56+
57+
Stores facts as JSON strings and maintains sets for efficient indexing.
58+
59+
### Install the requirements
60+
61+
=== "uv"
62+
```bash
63+
uv add memstate[redis]
64+
```
65+
66+
=== "pip"
67+
```bash
68+
pip install memstate[redis]
69+
```
70+
71+
### Initialize the storage
72+
73+
=== "sync"
74+
```python
75+
from memstate import MemoryStore
76+
from memstate.backends.redis import RedisStorage
77+
78+
storage = RedisStorage("redis://localhost:6379/0")
79+
store = MemoryStore(storage=storage)
80+
```
81+
82+
=== "async"
83+
```python
84+
import asyncio
85+
from memstate import AsyncMemoryStore
86+
from memstate.backends.redis import AsyncRedisStorage
87+
88+
async def main():
89+
storage = AsyncRedisStorage("redis://localhost:6379/0")
90+
store = AsyncMemoryStore(storage=storage)
91+
92+
if __name__ == "__main__":
93+
asyncio.run(main())
94+
```
95+
96+
## SQLite
97+
98+
The default, zero-config backend. Uses the JSON1 extension for querying.
99+
100+
### Install the requirements
101+
102+
For synchronous use, SQLite is built-in.
103+
104+
For **async** use, you need `aiosqlite`.
105+
106+
=== "uv"
107+
```bash
108+
uv add memstate[sqlite-async]
109+
```
110+
111+
=== "pip"
112+
```bash
113+
pip install memstate[sqlite-async]
114+
```
115+
116+
### Initialize the storage
117+
118+
=== "sync"
119+
```python
120+
from memstate import MemoryStore, SQLiteStorage
121+
122+
storage = SQLiteStorage("memory.db")
123+
store = MemoryStore(storage=storage)
124+
```
125+
126+
=== "async"
127+
```python
128+
import asyncio
129+
from memstate import AsyncMemoryStore, AsyncSQLiteStorage
130+
131+
async def main():
132+
storage = AsyncSQLiteStorage("memory.db")
133+
# Important: Connect explicitly
134+
await storage.connect()
135+
136+
store = AsyncMemoryStore(storage=storage)
137+
138+
if __name__ == "__main__":
139+
asyncio.run(main())
140+
```
141+
142+
## In-memory
143+
144+
Non-persistent storage. Best for testing and prototyping.
145+
146+
### Initialize the storage
147+
148+
=== "sync"
149+
```python
150+
from memstate import MemoryStore, InMemoryStorage
151+
152+
storage = InMemoryStorage()
153+
store = MemoryStore(storage=storage)
154+
```
155+
156+
=== "async"
157+
```python
158+
import asyncio
159+
from memstate import AsyncMemoryStore, AsyncInMemoryStorage
160+
161+
async def main():
162+
storage = AsyncInMemoryStorage()
163+
store = AsyncMemoryStore(storage=storage)
164+
165+
if __name__ == "__main__":
166+
asyncio.run(main())
167+
```

docs/documentation/exceptions.md

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
# Exceptions & Error Handling
2+
3+
MemState uses a hierarchy of custom exceptions to help you handle failures gracefully. All exceptions inherit from `MemStateError`.
4+
5+
## Hierarchy
6+
7+
```text
8+
MemStateError
9+
├── ValidationFailed (Schema mismatch)
10+
├── ConflictError (Constraint violation)
11+
├── HookError (Vector DB sync failure)
12+
└── MemoryStoreError (Storage issues, not found, etc.)
13+
```
14+
15+
## HookError (The ACID Signal)
16+
17+
This is the most important exception in MemState. It is raised when a **Sync Hook** (e.g., ChromaDB, Qdrant) fails during a commit.
18+
19+
**What it means:**
20+
21+
* The Vector DB write failed (network timeout, auth error).
22+
* **Crucial:** MemState has **already automatically rolled back** the SQL change.
23+
* Your data is consistent (nothing saved), but the operation failed.
24+
25+
**How to handle:**
26+
27+
=== "Sync"
28+
```python
29+
from memstate import HookError
30+
31+
try:
32+
store.commit_model(user_pref)
33+
except HookError as e:
34+
# The transaction was rolled back.
35+
# You can retry, or ask the user to try again.
36+
print(f"Sync failed: {e}. Changes rolled back.")
37+
```
38+
39+
=== "Async"
40+
```python
41+
from memstate import HookError
42+
43+
try:
44+
await store.commit_model(user_pref)
45+
except HookError as e:
46+
print(f"Sync failed: {e}. Changes rolled back.")
47+
```
48+
49+
## ValidationFailed
50+
51+
Raised when the data provided (usually from an LLM) does not match the registered Pydantic schema.
52+
53+
**What it means:**
54+
55+
* The LLM generated a string for an `int` field, or missed a required field.
56+
* The transaction was **rejected** before touching the database.
57+
58+
**How to handle:**
59+
Usually, you catch this and feed the error message back to the LLM so it can "Self-Correct".
60+
61+
```python
62+
from memstate import ValidationFailed
63+
64+
try:
65+
store.commit_model(model_from_llm)
66+
except ValidationFailed as e:
67+
# Feedback loop for the Agent
68+
prompt_to_llm = f"You provided invalid data: {e}. Please fix and retry."
69+
retry_llm(prompt_to_llm)
70+
```
71+
72+
## ConflictError
73+
74+
Raised when a write violates a defined `Constraint` (specifically `immutable=True`).
75+
76+
**What it means:**
77+
78+
* You tried to update a fact that was marked as immutable.
79+
* Example: Trying to change a signed "User Agreement" fact.
80+
81+
```python
82+
from memstate import Constraint, ConflictError
83+
84+
store.register_schema("policy", PolicyModel, constraint=Constraint(singleton_key="id", immutable=True))
85+
86+
try:
87+
store.commit_model(new_policy)
88+
except ConflictError:
89+
print("Cannot overwrite immutable policy!")
90+
```

0 commit comments

Comments
 (0)