@b4run/memory-pgvector

Use this whenCopy link to section: Use this when

Use this package when multiple B4.run application instances need shared long-term memory with Postgres and pgvector. Keep SQLite for local or single-instance use. Choose this backend when shared durability and vector retrieval are worth running Postgres.

Install and importCopy link to section: Install and import

bash
npm install @b4run/memory-pgvector pg
ts
import { pgvectorMemoryStore } from "@b4run/memory-pgvector"

Compatibility and audienceCopy link to section: Compatibility and audience

SurfaceRuntimePurityAudienceStability
@b4run/memory-pgvectornode-onlynot-claimedapplicationsupported

The store uses pg, initializes the pgvector extension and its tables lazily, and requires database credentials with the needed DDL and extension privileges.

Public exportsCopy link to section: Public exports

@b4run/memory-pgvectorCopy link to section: @b4run/memory-pgvector

ExportResponsibility
PgvectorMemoryStoreExtend MemoryStore with pool lifecycle.
pgvectorMemoryStoreCreate a Postgres and pgvector memory store.
assertIdentifierReject unsafe SQL identifiers.
IDENTIFIER_PATTERNExpose the lowercase identifier pattern assertIdentifier enforces.
initSchemaInitialize pgvector storage schema.
vectorColumnDefSelect vector storage and operator class by dimensions.

Key contractsCopy link to section: Key contracts

PgvectorMemoryStoreCopy link to section: PgvectorMemoryStore

ts
export interface PgvectorMemoryStore extends MemoryStore {
  close(): Promise<void>
}

An injected pool remains caller-owned: close() is a no-op, and the caller owns pool error handling. A store-created pool receives an error listener and is ended by close().

ts
export declare function pgvectorMemoryStore(opts: {
  /** Postgres connection string; used to build an owned pool. */
  connectionString?: string
  /** An existing pool to use instead of building one from `connectionString`. */
  pool?: Pool
  /** Embedding dimensions (≤2000 → `vector`, ≤4000 → `halfvec`). */
  dimensions: number
  /** HNSW index/search tuning; all fields defaulted. */
  index?: { m?: number; efConstruction?: number; efSearch?: number }
  /** Postgres schema to place tables in; must match `IDENTIFIER_PATTERN`. */
  schema?: string
  /** Table name prefix (isolates multiple stores in one database); must match `IDENTIFIER_PATTERN`. */
  tablePrefix?: string
  /** Recall ranking tuning; all fields defaulted. See @b4run/memory score.ts. */
  recall?: RecallRankingOptions
  /** Store-level hybrid tuning; used when a query omits `vector`. All fields defaulted. */
  vector?: VectorRankingOptions
}): PgvectorMemoryStore

Behavior contract memory-pgvector.schema.identifier-validation

pgvector schema and table-prefix identifiers reject unsafe characters before B4.run interpolates them into DDL.

Behavior contract memory-pgvector.dimension-branches

The store rejects invalid dimensions at construction: 1–2000 use vector cosine indexes, 2001–4000 use halfvec cosine indexes, and larger, nonpositive, or noninteger values throw.

Behavior contract memory-pgvector.update-preserves-embedding

update() preserves the row's stored embedding. Content or data updates do not recompute that embedding, so after changing semantic content, compute a replacement and call put(updatedRecord, { embedding, embeddingModel }) to avoid stale vector results.

Initialization and retrievalCopy link to section: Initialization and retrieval

Initialization is memoized per store instance. CREATE IF NOT EXISTS does not migrate an existing vector dimension or HNSW tuning, so treat those as schema decisions.

Both queryEmbedding and embedderId are required to activate hybrid retrieval. Keyword and vector candidates are fused in application code. schema and tablePrefix organize tables, but they are not tenant authorization boundaries. Both are interpolated unquoted, so both must be lowercase identifiers matching IDENTIFIER_PATTERN. A mixed-case value is rejected at construction rather than silently folded to lowercase by Postgres. Stored memory is plaintext unless your database and infrastructure provide encryption.

ts
import { pgvectorMemoryStore } from "@b4run/memory-pgvector"
 
const connectionString = process.env.DATABASE_URL
if (!connectionString) {
  throw new Error("DATABASE_URL is required")
}
 
const store = pgvectorMemoryStore({
  connectionString,
  dimensions: 1536,
  tablePrefix: "support_memory",
})
 
try {
  await store.search({ namespace: "workspace=acme", query: "shipping" })
} finally {
  await store.close()
}

Continue with Long-term Memory, Recall and Retrieval, and Persistence and Tenancy.