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
2 changes: 1 addition & 1 deletion docs/approvals.md
Original file line number Diff line number Diff line change
Expand Up @@ -568,7 +568,7 @@ continued run as an `AgentRun` (see
| `InMemoryApprovalStore` | This process only; the default for `createAgent()`. |
| `StorageServiceApprovalStore(storage)` | JSON files through a `StorageService`. |
| `fileStore(dir)` | One JSON file per pause, `<dir>/approvals/<id>.json`, on one machine; an approval can be resolved by only one process (see [Choosing a store](./sessions.md#choosing-a-store)). |
| `SqliteStore.approvals` | One SQLite file, shared safely by several processes; an approval can be resolved by only one of them. |
| `SqliteStore.approvals` | One SQLite file, shared by several processes on one host ([details](./sessions.md#sharing-a-sqlite-file)); an approval can be resolved by only one of them. |

An `ApprovalStore` needs `save()` and `resolve()`. `load(id)` (read a pause
without claiming it) and `list()` (every pause not resolved yet, oldest first)
Expand Down
6 changes: 5 additions & 1 deletion docs/deployment.md
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,11 @@ directory's `auth.ts`, with `LOUSHO_API_TOKEN` appended to it: see
| `memory` (default) | `memoryStore()`: gone when the process restarts, and not shared between instances. |
| `sqlite:<path>` | A [`SqliteStore`](./sessions.md) file (created with its directory): sessions survive restarts. Needs Node 22 (`node:sqlite`); the `docker` image uses `node:22-slim`. Mount the file's directory as a volume (the `docker` image owns `/app/data` for this). |

SQLite is one file on one disk, so run a single instance per database file.
Several instances on one host may share one `sqlite:` file on a local disk (for
example two replicas on one Docker volume); a busy session answers `409` with
`Retry-After`. A network filesystem (NFS, EFS, SMB) or several hosts are not
supported: use a store you implement. See
[Sharing a SQLite file](./sessions.md#sharing-a-sqlite-file).

### Crash recovery

Expand Down
5 changes: 5 additions & 0 deletions docs/durable-execution.md
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,11 @@ before any tool runs or any model is called (a resolved approval stays
pending). Two replicas behind a load balancer therefore never run one turn's
tool calls twice.

This holds for replicas on one host sharing one SQLite file on a local disk, or
for a store you implement over a shared database; SQLite on a network
filesystem or across hosts is not supported. See
[Sharing a SQLite file](./sessions.md#sharing-a-sqlite-file).

A lease whose holder died is taken over once it expires. Expiry is judged by
the clock of the process that wants the lease against the expiry the holder
wrote with its own clock, so the file and SQLite stores wait one more lease
Expand Down
2 changes: 1 addition & 1 deletion docs/pause-and-resume.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ policies.

Pauses and checkpoints live in the agent's `store`. The default is in memory,
which a restart loses. Use a durable one: `SqliteStore` (one transactional file,
shared safely by several processes) or `fileStore(dir)` (plain JSON files). See
shared by several processes on one host) or `fileStore(dir)` (plain JSON files). See
[Choosing a store](./sessions.md#choosing-a-store).

## 3. Send: the run pauses
Expand Down
28 changes: 25 additions & 3 deletions docs/sessions.md
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,7 @@ implementation by where the process runs:
| --- | --- | --- | --- | --- |
| In memory (`memoryStore()`) | `MemorySessionStore` | in memory | `InMemoryApprovalStore` | Tests, scripts, one process that never restarts |
| Files (`fileStore(dir)`) | `<dir>/sessions/<id>.json` | `<dir>/checkpoints/`, `<dir>/checkpoint-history/` | `<dir>/approvals/<id>.json` | One machine, you want plain inspectable files |
| SQLite | `store.sessions` | `store.checkpoints` | `store.approvals` | A Node server: one durable, transactional file, shared safely by several processes |
| SQLite | `store.sessions` | `store.checkpoints` | `store.approvals` | A Node server: one durable, transactional file, shared by several processes on one host (see [Sharing a SQLite file](#sharing-a-sqlite-file)) |
| Cloudflare KV (`KVStore` from `@lousho/build-ai-agent/kv`) | `store.sessions` | `store.checkpoints` | `store.approvals` | Workers deployments (see [Deployment](deployment.md)) |

Each one is an `AgentStore` part: pass them together as
Expand Down Expand Up @@ -433,8 +433,9 @@ With the executor directly, pass `store.checkpoints` as `checkpointStore` and
- The directory is created if missing. The schema is versioned with
`PRAGMA user_version` and migrated on open; a database written by a newer
release is refused.
- WAL mode and a 5 s busy timeout let two processes share the file. An approval
can be resolved by only one of them.
- WAL mode and a short lock wait with retries (about 5 s in all, then
`LOUSHO_STORAGE_BUSY`) let several processes share the file. An approval can
be resolved by only one of them. See [Sharing a SQLite file](#sharing-a-sqlite-file).
- Checkpoints and approval snapshots are stored as opaque JSON, so new fields
round-trip unchanged.
- `prune()` removes sessions and checkpoints not updated within `olderThanMs`,
Expand All @@ -447,6 +448,27 @@ With the executor directly, pass `store.checkpoints` as `checkpointStore` and
- A file that is not a SQLite database fails with an error naming the path;
using the store after `close()` throws a clear error.

### Sharing a SQLite file

This is the one statement the other pages link to.

- **Supported:** several processes (for example two Docker replicas on one
named volume, or a server and a CLI) on **one host**, sharing one SQLite file
on a **local disk**. The file runs in WAL mode, and each session turn holds a
[run lease](./durable-execution.md#run-leases), so replicas can alternate
messages on one session. A write to a session another process is running
fails with `LOUSHO_SESSION_BUSY`; `POST /chat` and the channels answer that
with `409` and a `Retry-After` header, so retry.
- **Not supported:** a SQLite file on a network filesystem (NFS, EFS, SMB),
whose locking SQLite cannot rely on, and several hosts. For several hosts,
implement `SessionStore`, `CheckpointStore` and `ApprovalStore` over a shared
database such as Postgres or Redis. The SDK ships no network store.
- **Clocks and PIDs:** leases are judged by each process's own clock, so keep
replica clocks in sync (NTP). A crashed run is taken over early only when
its process is provably gone on the same host (boot id, PID namespace and
process start time are checked); otherwise it waits 30 to 60 seconds for the
lease to expire. See [Run leases](./durable-execution.md#run-leases).

## Project instructions

Not part of sessions, but often wanted together: see "Project instructions" in
Expand Down
43 changes: 37 additions & 6 deletions llms-full.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3015,7 +3015,7 @@ continued run as an `AgentRun` (see
| `InMemoryApprovalStore` | This process only; the default for `createAgent()`. |
| `StorageServiceApprovalStore(storage)` | JSON files through a `StorageService`. |
| `fileStore(dir)` | One JSON file per pause, `<dir>/approvals/<id>.json`, on one machine; an approval can be resolved by only one process (see [Choosing a store](https://github.com/LinuxDevil/agent-sdk/blob/main/docs/sessions.md#choosing-a-store)). |
| `SqliteStore.approvals` | One SQLite file, shared safely by several processes; an approval can be resolved by only one of them. |
| `SqliteStore.approvals` | One SQLite file, shared by several processes on one host ([details](https://github.com/LinuxDevil/agent-sdk/blob/main/docs/sessions.md#sharing-a-sqlite-file)); an approval can be resolved by only one of them. |

An `ApprovalStore` needs `save()` and `resolve()`. `load(id)` (read a pause
without claiming it) and `list()` (every pause not resolved yet, oldest first)
Expand Down Expand Up @@ -7274,7 +7274,11 @@ directory's `auth.ts`, with `LOUSHO_API_TOKEN` appended to it: see
| `memory` (default) | `memoryStore()`: gone when the process restarts, and not shared between instances. |
| `sqlite:<path>` | A [`SqliteStore`](https://github.com/LinuxDevil/agent-sdk/blob/main/docs/sessions.md) file (created with its directory): sessions survive restarts. Needs Node 22 (`node:sqlite`); the `docker` image uses `node:22-slim`. Mount the file's directory as a volume (the `docker` image owns `/app/data` for this). |

SQLite is one file on one disk, so run a single instance per database file.
Several instances on one host may share one `sqlite:` file on a local disk (for
example two replicas on one Docker volume); a busy session answers `409` with
`Retry-After`. A network filesystem (NFS, EFS, SMB) or several hosts are not
supported: use a store you implement. See
[Sharing a SQLite file](https://github.com/LinuxDevil/agent-sdk/blob/main/docs/sessions.md#sharing-a-sqlite-file).

### Crash recovery

Expand Down Expand Up @@ -7723,6 +7727,11 @@ before any tool runs or any model is called (a resolved approval stays
pending). Two replicas behind a load balancer therefore never run one turn's
tool calls twice.

This holds for replicas on one host sharing one SQLite file on a local disk, or
for a store you implement over a shared database; SQLite on a network
filesystem or across hosts is not supported. See
[Sharing a SQLite file](https://github.com/LinuxDevil/agent-sdk/blob/main/docs/sessions.md#sharing-a-sqlite-file).

A lease whose holder died is taken over once it expires. Expiry is judged by
the clock of the process that wants the lease against the expiry the holder
wrote with its own clock, so the file and SQLite stores wait one more lease
Expand Down Expand Up @@ -14181,7 +14190,7 @@ policies.

Pauses and checkpoints live in the agent's `store`. The default is in memory,
which a restart loses. Use a durable one: `SqliteStore` (one transactional file,
shared safely by several processes) or `fileStore(dir)` (plain JSON files). See
shared by several processes on one host) or `fileStore(dir)` (plain JSON files). See
[Choosing a store](https://github.com/LinuxDevil/agent-sdk/blob/main/docs/sessions.md#choosing-a-store).

## 3. Send: the run pauses
Expand Down Expand Up @@ -16766,7 +16775,7 @@ implementation by where the process runs:
| --- | --- | --- | --- | --- |
| In memory (`memoryStore()`) | `MemorySessionStore` | in memory | `InMemoryApprovalStore` | Tests, scripts, one process that never restarts |
| Files (`fileStore(dir)`) | `<dir>/sessions/<id>.json` | `<dir>/checkpoints/`, `<dir>/checkpoint-history/` | `<dir>/approvals/<id>.json` | One machine, you want plain inspectable files |
| SQLite | `store.sessions` | `store.checkpoints` | `store.approvals` | A Node server: one durable, transactional file, shared safely by several processes |
| SQLite | `store.sessions` | `store.checkpoints` | `store.approvals` | A Node server: one durable, transactional file, shared by several processes on one host (see [Sharing a SQLite file](#sharing-a-sqlite-file)) |
| Cloudflare KV (`KVStore` from `@lousho/build-ai-agent/kv`) | `store.sessions` | `store.checkpoints` | `store.approvals` | Workers deployments (see [Deployment](https://github.com/LinuxDevil/agent-sdk/blob/main/docs/deployment.md)) |

Each one is an `AgentStore` part: pass them together as
Expand Down Expand Up @@ -16850,8 +16859,9 @@ With the executor directly, pass `store.checkpoints` as `checkpointStore` and
- The directory is created if missing. The schema is versioned with
`PRAGMA user_version` and migrated on open; a database written by a newer
release is refused.
- WAL mode and a 5 s busy timeout let two processes share the file. An approval
can be resolved by only one of them.
- WAL mode and a short lock wait with retries (about 5 s in all, then
`LOUSHO_STORAGE_BUSY`) let several processes share the file. An approval can
be resolved by only one of them. See [Sharing a SQLite file](#sharing-a-sqlite-file).
- Checkpoints and approval snapshots are stored as opaque JSON, so new fields
round-trip unchanged.
- `prune()` removes sessions and checkpoints not updated within `olderThanMs`,
Expand All @@ -16864,6 +16874,27 @@ With the executor directly, pass `store.checkpoints` as `checkpointStore` and
- A file that is not a SQLite database fails with an error naming the path;
using the store after `close()` throws a clear error.

### Sharing a SQLite file

This is the one statement the other pages link to.

- **Supported:** several processes (for example two Docker replicas on one
named volume, or a server and a CLI) on **one host**, sharing one SQLite file
on a **local disk**. The file runs in WAL mode, and each session turn holds a
[run lease](https://github.com/LinuxDevil/agent-sdk/blob/main/docs/durable-execution.md#run-leases), so replicas can alternate
messages on one session. A write to a session another process is running
fails with `LOUSHO_SESSION_BUSY`; `POST /chat` and the channels answer that
with `409` and a `Retry-After` header, so retry.
- **Not supported:** a SQLite file on a network filesystem (NFS, EFS, SMB),
whose locking SQLite cannot rely on, and several hosts. For several hosts,
implement `SessionStore`, `CheckpointStore` and `ApprovalStore` over a shared
database such as Postgres or Redis. The SDK ships no network store.
- **Clocks and PIDs:** leases are judged by each process's own clock, so keep
replica clocks in sync (NTP). A crashed run is taken over early only when
its process is provably gone on the same host (boot id, PID namespace and
process start time are checked); otherwise it waits 30 to 60 seconds for the
lease to expire. See [Run leases](https://github.com/LinuxDevil/agent-sdk/blob/main/docs/durable-execution.md#run-leases).

## Project instructions

Not part of sessions, but often wanted together: see "Project instructions" in
Expand Down
Loading