Metadata-Version: 2.4
Name: langgraph-checkpoint-persql
Version: 0.2.0
Summary: LangGraph checkpointer backed by PerSQL — durable agent state in an isolated SQLite database per agent.
Project-URL: Homepage, https://persql.com
Project-URL: Documentation, https://docs.persql.com
Project-URL: Console, https://console.persql.com
Project-URL: Issues, https://persql.com/support
Author-email: PerSQL <support@persql.com>
License: MIT
License-File: LICENSE
Keywords: agents,checkpointer,langgraph,memory,persistence,sqlite
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Database
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Requires-Python: >=3.10
Requires-Dist: langgraph-checkpoint<5,>=4.1
Requires-Dist: persql>=0.4
Provides-Extra: dev
Requires-Dist: mypy>=1.8; extra == 'dev'
Requires-Dist: ruff>=0.5; extra == 'dev'
Provides-Extra: test
Requires-Dist: anyio>=3; extra == 'test'
Requires-Dist: langgraph<2,>=1; extra == 'test'
Requires-Dist: pytest-asyncio>=0.21; extra == 'test'
Requires-Dist: pytest>=7; extra == 'test'
Description-Content-Type: text/markdown

# langgraph-checkpoint-persql

LangGraph checkpointer backed by [PerSQL](https://persql.com) — durable
agent state in an isolated SQLite database per agent, provisioned
instantly.

```
pip install langgraph-checkpoint-persql
```

## Usage

```python
import os
from persql import PerSQL
from langgraph.checkpoint.persql import PerSQLSaver

client = PerSQL(token=os.environ["PERSQL_TOKEN"])
checkpointer = PerSQLSaver(client.database("acme/agent-state"))

graph = builder.compile(checkpointer=checkpointer)
config = {"configurable": {"thread_id": "session-42"}}
graph.invoke({"messages": [("user", "hi")]}, config)
graph.invoke({"messages": [("user", "remember me?")]}, config)  # state persists
```

Async:

```python
from persql import AsyncPerSQL
from langgraph.checkpoint.persql.aio import AsyncPerSQLSaver

async with AsyncPerSQL(token=os.environ["PERSQL_TOKEN"]) as client:
    checkpointer = AsyncPerSQLSaver(client.database("acme/agent-state"))
    graph = builder.compile(checkpointer=checkpointer)
    await graph.ainvoke(inputs, {"configurable": {"thread_id": "session-42"}})
```

Or let the saver own the client:

```python
with PerSQLSaver.from_token(os.environ["PERSQL_TOKEN"], "acme/agent-state") as cp:
    graph = builder.compile(checkpointer=cp)
```

Tests run against the SDK's local mode — in-process SQLite, no network,
no token:

```python
checkpointer = PerSQLSaver(PerSQL(local=":memory:").database("test/db"))
```

## Cross-thread memory (BaseStore)

The package also ships `PerSQLStore` / `AsyncPerSQLStore`, a LangGraph
`BaseStore` for long-term memory shared across threads:

```python
from langgraph.store.persql import PerSQLStore

store = PerSQLStore(client.database("acme/agent-state"))
graph = builder.compile(checkpointer=checkpointer, store=store)

store.put(("users", "u1"), "prefs", {"theme": "dark"})
store.search(("users",), filter={"theme": "dark"})
```

One `store_items` table; a whole `batch()` of operations rides one HTTP
round-trip. Items are plain JSON, so the same database can serve the JS
`@persql/langgraph` store too. Not supported (raise
`NotImplementedError`): natural-language `query=` search — PerSQL is a
structured SQL substrate; pair it with a vector layer for semantic
recall — and item TTLs. Filtered searches fetch the whole namespace
prefix before paginating, so keep filtered prefixes to bounded
collections.

## Per-agent isolation

The saver keys state by `thread_id` inside one database, like every
LangGraph checkpointer. PerSQL's shape lets you go one step further and
give each agent (or each run) its own *database*: provision with
`client.databases.create(...)` or lease a schema-only branch with a
scoped token via `db.branches`. See the
[PerSQL docs](https://docs.persql.com) for the per-agent patterns.

## Storage and limits

- Two tables, created lazily on first use: `checkpoints` and
  `checkpoint_writes`, the same layout as the official SQLite saver
  (serialized values are base64 text rather than blobs).
- Every saver call is one HTTP round-trip to the database. LangGraph
  checkpoints once per super-step, so a remote checkpointer adds wire
  latency per step — the same trade-off as the official Postgres saver.
- Checkpoint rows land on PerSQL's usage meters like any other write.
  A typical graph step writes one checkpoint row plus a few pending
  writes; see [persql.com/pricing](https://persql.com/pricing) for rates.
- `delete_for_runs`, `copy_thread`, and `prune` are not implemented
  (the official SQLite saver doesn't implement them either) and raise
  `NotImplementedError`.

## License

MIT © PerSQL
