@b4run/postgres-storage

中文文档
0.15.8发布于 2026/10/31MITTypeScriptES Module构建来源已验证近 30 天下载 4047

Postgres persistence for B4.run checkpoints, threads, and permission decisions.

原始使用文档
文档目录7 节
  1. Install
  2. Example
  3. Runtime and stability
  4. Request-scoped run admission
  5. Related
  6. Maturity and support
  7. License

B4.run

@b4run/postgres-storage

Supported Postgres persistence for B4.run checkpoints, Agent Protocol threads, and permission grants across application instances.

Use this when: You are replacing B4.run's local durable stores with shared Postgres persistence.

Install

pnpm add @b4run/postgres-storage pg

Example

import { Pool } from "pg"
import { createPostgresThreadsStore } from "@b4run/postgres-storage"

const pool = new Pool({ connectionString: process.env.DATABASE_URL })
const threadsStore = createPostgresThreadsStore({ pool })

await threadsStore.ready()

// During application shutdown:
await threadsStore.close()
await pool.end()

Every store accepts schema (default public) and tablePrefix (default b4), so several applications or deployment environments can share one database. Both must be lowercase SQL identifiers matching ^[a-z_][a-z0-9_]*$; the migration pass creates the schema if needed. Pass the same values to the checkpointer, threads store and permissions store. Apps built with b4 build for the hono or vercel target set these through the B4_PG_SCHEMA and B4_PG_TABLE_PREFIX runtime bindings instead.

Runtime and stability

  • @b4run/postgres-storage is a supported edge-safe application surface that requires an injected structural pool. The tested edge path is local workerd with a Neon WebSocket pool; this is not a claim about every edge host.
  • @b4run/postgres-storage/node is a supported node-only application surface that can create a pg pool from a connection string.

Migrations are memoized per store instance. An injected pool remains caller-owned unless ownsPool: true; a pool created by the Node entry is store-owned. Close stores and caller-owned pools during application shutdown.

Request-scoped run admission

createPostgresRunAdmission({ pool }) coordinates ownership of one thread across replicas. Create one instance per request, initialize its ready() method, and pass its pool to every runtime store used by that request. Initialization and authorization queries may run before acquisition. Call tryAcquire(threadId) before reading the checkpoint that determines a run or accepting callback answers. A false result means another request owns the thread and may be retried. An acquired instance rejects a different thread; release and ownership loss are terminal. Await release() after graph work and final persistence finish, or use close() to also close a pool owned by this instance. Caller-supplied pools stay open unless ownsPool is set. The Node entry also accepts connectionString.

The default lease is 30 seconds, renewed every 10 seconds. leaseDurationMs and heartbeatIntervalMs accept positive integer milliseconds; the heartbeat must be shorter than the lease. Expiry and renewal use the database clock. Observe signal to stop work after ownership loss or release. An expired owner cannot renew or commit runtime storage writes, even after another request takes over. This coordination does not provide exactly-once external tool effects.

Once acquired, pool.query() executes one statement in a short fenced transaction. pool.connect() additionally supports explicit BEGIN (or START TRANSACTION), COMMIT (or END), and ROLLBACK, with an optional trailing semicolon. Nested transactions, savepoints, transaction-control modifiers, and multiple statements in a fenced query are rejected. SQL literals and comments may contain semicolons. Fenced SQL accepts positional parameters such as $1; pass data through these parameters. Dollar signs other than positional parameter markers and backslashes in the SQL text are rejected, including dollar-quoted strings and dollar-bearing identifiers. Bound values may contain these characters. This deliberately limited SQL subset serves the runtime stores; it is not an arbitrary SQL execution interface. Complete these transactions around individual storage operations; do not hold them through model generation. A synchronous client release() finishes rollback before making the underlying connection available for reuse. Released or lost admissions never resume unfenced access.

For a custom Node fetch embedding, return the admission with its fenced stores from requestStores. Migrate all stores before the first claim, because active fencing deliberately rejects multi-statement migration batches. The runtime then claims after authorization and finalizes ownership after actual execution cleanup. Generated Vercel/Hono output supplies this wiring automatically.

import {
  createPostgresClientToolCallStore,
  createPostgresPermissionsStore,
  createPostgresPool,
  createPostgresRunAdmission,
  createPostgresThreadsStore,
  postgresCheckpointer,
} from "@b4run/postgres-storage/node"

const requestStores = async () => {
  const pool = createPostgresPool({ connectionString: process.env.DATABASE_URL })
  try {
    const runAdmission = createPostgresRunAdmission({ pool })
    const naming = { pool: runAdmission.pool }
    const stores = {
      checkpointer: postgresCheckpointer(naming),
      clientToolStore: createPostgresClientToolCallStore(naming),
      permissionsStore: createPostgresPermissionsStore(naming),
      threadsStore: createPostgresThreadsStore(naming),
    }
    await Promise.all([runAdmission.ready(), ...Object.values(stores).map((store) => store.ready())])
    return {
      ...stores,
      runAdmission,
      dispose: async () => {
        try { await runAdmission.close() } finally { await pool.end() }
      },
    }
  } catch (error) {
    await pool.end()
    throw error
  }
}

This fences the injected checkpoint, thread, permission, and client-tool stores. Separately configured memory and boot-owned approval-grant stores are not wrapped. The existing managed-workspace restriction on requestStores remains in place. The process-local run registry remains the default for embeddings without shared admission; sharing Postgres data alone does not provide execution exclusion.

Maturity and support

B4.run is pre-1.0, and its public surface can change. All publishable B4.run packages release together as a fixed group; review the @b4run/postgres-storage changelog and upgrading guide before upgrading. For support, use GitHub Discussions; report defects in GitHub Issues.

License

MIT. See the repository license.

版本与发布记录

@b4run/postgres-storage 共发布 23 个版本,首次发布于 2026/09/09;过去 12 个月发布了 23 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
0.15.8latest2026/10/317 天前
0.15.72026/10/2810 天前
0.15.52026/10/2712 天前
0.15.42026/10/2612 天前
0.15.22026/10/2514 天前
0.15.12026/10/2414 天前

关于 @b4run/postgres-storage 的常见问题

@b4run/postgres-storage 是什么?

Postgres persistence for B4.run checkpoints, threads, and permission decisions.

如何安装 @b4run/postgres-storage?

在项目目录运行 npm install @b4run/postgres-storage,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:@langchain/core(^1.2.12)、@langchain/langgraph-checkpoint(^1.1.5)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@b4run/postgres-storage 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@b4run/postgres-storage 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@b4run/postgres-storage 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=24.0.0。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@b4run/postgres-storage 可以商用吗?

@b4run/postgres-storage 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@b4run/postgres-storage 的下载量有多少?

根据 npm 官方下载统计,@b4run/postgres-storage 在 2026/10/08 – 2026/11/06 这 30 天内被下载 4,047 次,日均约 135 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@b4run/postgres-storage 还在维护吗?

最新版本 0.15.8 发布于 2026/10/31(7 天前);至今共发布 23 个版本,其中过去 12 个月发布了 23 个;首次发布于 2026/09/09。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。