From 0717caa7dfe4501f122a7c338ffd04eb83224bcd Mon Sep 17 00:00:00 2001 From: "heum-ilgu.gim" Date: Tue, 21 Apr 2026 16:53:25 +0900 Subject: [PATCH] docs(sdk): add PostgreSQL-backed persistence guide and API reference Document PostgreSQLFileStore usage for environments where the local filesystem is not persistent (Cloud Run, serverless, containers without mounted volumes). Covers installation, usage with LocalConversation, schema, locking behaviour, and the file_store / persistence_dir mutually-exclusive semantics. Co-authored-by: openhands --- .../openhands.sdk.conversation.mdx | 5 ++ sdk/guides/convo-persistence.mdx | 66 +++++++++++++++++++ 2 files changed, 71 insertions(+) diff --git a/sdk/api-reference/openhands.sdk.conversation.mdx b/sdk/api-reference/openhands.sdk.conversation.mdx index b5e99911f..518429b39 100644 --- a/sdk/api-reference/openhands.sdk.conversation.mdx +++ b/sdk/api-reference/openhands.sdk.conversation.mdx @@ -566,6 +566,11 @@ Initialize the conversation. override by key (last wins), hooks concatenate (all run). * `persistence_dir` – Directory for persisting conversation state and events. Can be a string path or Path object. + * `file_store` – Optional custom FileStore for persisting conversation state + and events. Use this to supply a PostgreSQLFileStore (or any FileStore + implementation) instead of the default local-filesystem store. + Mutually exclusive with `persistence_dir`; when `file_store` is provided, + `persistence_dir` is ignored. * `conversation_id` – Optional ID for the conversation. If provided, will be used to identify the conversation. The user might want to suffix their persistent filestore with this ID. diff --git a/sdk/guides/convo-persistence.mdx b/sdk/guides/convo-persistence.mdx index d2f520f0c..4567e41fb 100644 --- a/sdk/guides/convo-persistence.mdx +++ b/sdk/guides/convo-persistence.mdx @@ -377,6 +377,72 @@ Events are appended incrementally (one file per event), while base state is over +## PostgreSQL-backed Persistence + +In environments where the local filesystem is not persistent across requests (Cloud Run, +containers without mounted volumes, serverless), `LocalFileStore` is unavailable. +`PostgreSQLFileStore` stores the full EventLog — including `tool_call` and `tool_result` +events — in a PostgreSQL table, enabling proper multi-turn resume without a shared filesystem. + +### Installation + +```bash +pip install "openhands-sdk[postgresql]" +``` + +### Usage + +```python focus={1,7-10,14} icon="python" +from openhands.sdk.io.postgresql import PostgreSQLFileStore + +dsn = "postgresql://user:pass@host:5432/db" + +# Each conversation gets its own namespace to isolate event logs. +for request in incoming_requests: + store = PostgreSQLFileStore( + dsn=dsn, + namespace=str(request.conversation_id), + ) + conv = LocalConversation( + agent=agent, + workspace=workspace, + file_store=store, + conversation_id=request.conversation_id, + ) + conv.send_message(request.message) + conv.run() +``` + +On the first call, `PostgreSQLFileStore` creates the `sdk_filestore` table if it doesn't exist +and persists all events. On subsequent calls with the same `namespace`, the SDK reads the +existing EventLog from PostgreSQL and resumes from the exact point where the conversation left off. + +### Schema + +`PostgreSQLFileStore` manages a single table: + +```sql +CREATE TABLE sdk_filestore ( + namespace TEXT NOT NULL, -- conversation_id + path TEXT NOT NULL, -- event file path (e.g. .events/event-0000000000-.json) + content TEXT NOT NULL, + updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + PRIMARY KEY (namespace, path) +); +``` + +### Locking + +`PostgreSQLFileStore` uses a per-path `threading.Lock` to serialize EventLog index assignment. +This is sufficient for single-process deployments. For multi-process deployments, subclass +`PostgreSQLFileStore` and override `lock()` with PostgreSQL advisory locks +(`pg_try_advisory_lock`). + + + `file_store` and `persistence_dir` are mutually exclusive. When `file_store` is provided, + `persistence_dir` is ignored. + + ## Next Steps - **[Pause and Resume](/sdk/guides/convo-pause-and-resume)** - Control execution flow