{"version":3,"file":"pg-vector-store.mjs","names":[],"sources":["../../../../../../../../ai/src/rag/store/pg-vector-store.ts"],"sourcesContent":["import type { VectorStore } from \"./vector-store.contract\";\n\n/**\n * Minimal `pg`-compatible client surface the Postgres {@link VectorStore}\n * depends on. Both `pg.Pool` and `pg.Client` satisfy it — the store only\n * ever calls `query`.\n *\n * `@warlock.js/ai` takes **no** hard dependency on `pg`; the dev installs\n * it (an optional peer) and passes the client in. Structurally identical\n * to the snapshot / human-interrupt stores' `PgClientLike`, so a single\n * pool can back the orchestrator checkpoint/snapshot tables, the\n * interrupt table, and this vectors table alike.\n */\nexport interface PgClientLike {\n  query(text: string, params?: unknown[]): Promise<{ rows: unknown[] }>;\n}\n\n/**\n * Options for the Postgres {@link VectorStore}.\n *\n * Two mutually-supportive ways to supply the connection (mirroring\n * `ai.human.interrupt.pg`):\n * - **`client`** — pass an already-built `pg.Pool` / `pg.Client` (anything\n *   satisfying {@link PgClientLike}). The store only ever calls `query`\n *   and never opens or closes it; one pool can back several stores.\n * - **`connectionString`** — let the store lazily `import(\"pg\")` and build\n *   its own `Pool`. `@warlock.js/ai` takes **no** hard dependency on\n *   `pg` (an optional peer); when it is absent the store throws a curated\n *   install string at first use, never a raw module-resolution stack trace\n *   at import.\n *\n * Exactly one of the two must be present.\n */\nexport interface PgVectorStoreOptions {\n  /** An already-built `pg.Pool` / `pg.Client` — anything matching {@link PgClientLike}. */\n  client?: PgClientLike;\n\n  /** Connection string the store passes to a lazily-imported `pg.Pool`. */\n  connectionString?: string;\n\n  /**\n   * Backing table name. Defaults to `warlock_ai_rag_vectors`. Must be a\n   * safe SQL identifier — it is interpolated into DDL/DML.\n   */\n  table?: string;\n\n  /**\n   * Embedding dimensionality used in the `CREATE TABLE` DDL emitted by\n   * {@link VectorStore.schema | ensureSchema}. Defaults to `1536`\n   * (OpenAI `text-embedding-3-small`). The column is declared\n   * `vector(N)`; queries and upserts never re-state it, so an existing\n   * table provisioned at a different size is unaffected — only the DDL\n   * helper reads this.\n   */\n  dimensions?: number;\n\n  /**\n   * Approximate-nearest-neighbour index strategy baked into the DDL\n   * emitted by {@link VectorStore.schema | ensureSchema}. Defaults to\n   * `\"hnsw\"` (better recall/latency on modern pgvector). Use `\"ivfflat\"`\n   * for the classic list-partitioned index, or `\"none\"` to emit no ANN\n   * index (exact scan — correct, but linear in row count).\n   */\n  index?: \"hnsw\" | \"ivfflat\" | \"none\";\n\n  /**\n   * `lists` parameter for an `ivfflat` index (ignored for `hnsw` / `none`).\n   * Defaults to `100`. Tune toward `rows / 1000` for large tables.\n   */\n  ivfflatLists?: number;\n}\n\n/**\n * Default backing table — provisions the store with no extra config when\n * the dev runs {@link VectorStore.schema | ensureSchema} through their\n * migration tool.\n */\nconst DEFAULT_TABLE = \"warlock_ai_rag_vectors\";\n\n/** Default embedding width baked into the DDL (OpenAI `text-embedding-3-small`). */\nconst DEFAULT_DIMENSIONS = 1536;\n\n/** Default `ivfflat` list count when that index strategy is chosen. */\nconst DEFAULT_IVFFLAT_LISTS = 100;\n\n/**\n * Allowed characters in a Postgres identifier (table name). The table name\n * is interpolated into DDL/DML, so anything outside this conservative\n * ASCII subset is rejected — interpolating an arbitrary string would be a\n * SQL-injection footgun (mirrors the snapshot / human-interrupt pg stores\n * and `@warlock.js/cache`'s `PgCacheDriver`).\n */\nconst SAFE_IDENTIFIER = /^[A-Za-z_][A-Za-z0-9_]*$/;\n\n/**\n * Module specifier for the optional `pg` driver. Held in a `string`\n * variable so the dynamic `import()` is not statically resolved at compile\n * time — `pg` is an optional peer that need not be installed for this\n * package to type-check or for a cache-only consumer to run.\n */\nconst PG_MODULE = \"pg\";\n\n/**\n * Curated install string surfaced (at use time) when a `connectionString`\n * is configured but the optional `pg` driver is absent. Never thrown at\n * import — a cache-only consumer must be able to load this module.\n */\nconst PG_INSTALL_INSTRUCTIONS = `\nThe @warlock.js/ai Postgres vector store requires the pg package and a\nPostgres database with the pgvector extension. Install the driver with:\n\n  npm install pg\n\nOr with your preferred package manager:\n\n  pnpm add pg\n  yarn add pg\n`.trim();\n\n/**\n * Minimal structural view of a `pg.Pool` constructor — just enough of the\n * `pg` module surface for the store to build a client when handed a\n * `connectionString`. Declared locally (rather than `typeof import(\"pg\")`)\n * so this module type-checks even when `pg` is not installed.\n */\ninterface PgModuleLike {\n  Pool: new (config: { connectionString: string }) => PgClientLike;\n}\n\n/**\n * Lazily import `pg` and return a `Pool` built from `connectionString`. A\n * bare `catch` rethrows the curated install string — a missing optional\n * peer surfaces as actionable guidance, never a raw resolution error.\n */\nasync function buildPgClient(connectionString: string): Promise<PgClientLike> {\n  let sdk: PgModuleLike;\n\n  try {\n    sdk = (await import(PG_MODULE)) as unknown as PgModuleLike;\n  } catch {\n    throw new Error(PG_INSTALL_INSTRUCTIONS);\n  }\n\n  return new sdk.Pool({ connectionString });\n}\n\n/**\n * Serialize a JS `number[]` to the pgvector text literal: `[1,2,3]`.\n * pgvector accepts a vector either as this bracketed literal or via a\n * typed parameter; passing the literal string + an explicit `::vector`\n * cast keeps the store driver-agnostic (no dependency on a registered\n * `pg` type parser).\n *\n * Non-finite components (`NaN` / `±Infinity`) are rejected — pgvector\n * stores only finite floats, and silently coercing them would corrupt the\n * index. The check is cheap relative to the embed call that produced the\n * vector.\n *\n * @example\n * vectorLiteral([1, 0.5, -2]); // \"[1,0.5,-2]\"\n */\nexport function vectorLiteral(vector: number[]): string {\n  let literal = \"[\";\n\n  for (let index = 0; index < vector.length; index++) {\n    const component = vector[index];\n\n    if (!Number.isFinite(component)) {\n      throw new TypeError(\n        `pgVectorStore: embedding component at index ${index} is not finite (${component}); pgvector stores only finite floats.`,\n      );\n    }\n\n    if (index > 0) {\n      literal += \",\";\n    }\n\n    literal += String(component);\n  }\n\n  return literal + \"]\";\n}\n\n/**\n * Coerce a `value` JSONB column back into the stored payload. node-postgres\n * parses `JSONB` into a JS value already, but some pool wrappers hand back\n * the raw string — be defensive across both (mirrors the snapshot store's\n * `parsePayload`).\n */\nfunction parseValue<T>(value: unknown): T {\n  if (typeof value === \"string\") {\n    return JSON.parse(value) as T;\n  }\n\n  return value as T;\n}\n\n/**\n * Coerce a pgvector cosine **distance** (`<=>`, in `[0, 2]`, 0 = identical)\n * into the cosine **similarity** score the {@link VectorStore} contract\n * declares (`[0, 1]`, 1 = identical). `pg` returns the computed distance\n * column as a string for `double precision`; parse then map `1 - distance`,\n * clamped to `[0, 1]` so a tiny floating-point overshoot never yields a\n * score just outside the contract's range.\n */\nfunction distanceToScore(distance: unknown): number {\n  const value = typeof distance === \"string\" ? Number(distance) : (distance as number);\n  const score = 1 - value;\n\n  if (score < 0) {\n    return 0;\n  }\n\n  if (score > 1) {\n    return 1;\n  }\n\n  return score;\n}\n\n/**\n * Postgres + pgvector-backed {@link VectorStore} — one durable row per\n * indexed chunk, keyed by the RAG pipeline's dotted `key`\n * (`ai.rag.<name>.<sourceId>.<chunkIndex>`), with the chunk payload in a\n * `value` JSONB column and the embedding in a `vector` column.\n *\n * Owns: the three RAG vector operations against a pgvector index —\n * `upsert` (INSERT … ON CONFLICT DO UPDATE), `query` (cosine\n * `ORDER BY embedding <=> $vec` with a `threshold` floor + optional `tags`\n * overlap filter, capped at `topK`), and `removeNamespace` (prefix DELETE).\n * Also emits the reference DDL via {@link PgVectorStore.schema} (alias\n * {@link PgVectorStore.ensureSchema}).\n *\n * Does NOT own: the connection lifecycle (a dev-supplied `client` is never\n * closed; a store-built `Pool` from a `connectionString` is also left open\n * for the process to reuse) or schema migration — the dev runs the DDL\n * through their own tool; the framework never auto-migrates.\n *\n * Front it with the {@link pgVectorStore} factory — callers never `new` it.\n */\nclass PgVectorStore implements VectorStore {\n  /** Validated backing table name, safe to interpolate into SQL. */\n  private readonly table: string;\n\n  /** Embedding width baked into the DDL. */\n  private readonly dimensions: number;\n\n  /** ANN index strategy baked into the DDL. */\n  private readonly index: \"hnsw\" | \"ivfflat\" | \"none\";\n\n  /** `lists` parameter for an `ivfflat` index. */\n  private readonly ivfflatLists: number;\n\n  /**\n   * A ready client, or a promise resolving to one the store builds lazily\n   * from a `connectionString`. Resolved once and memoized so the optional\n   * `pg` import happens at most once.\n   */\n  private readonly clientPromise: Promise<PgClientLike>;\n\n  public constructor(options: PgVectorStoreOptions) {\n    const table = options.table ?? DEFAULT_TABLE;\n\n    if (!SAFE_IDENTIFIER.test(table)) {\n      throw new TypeError(\n        `pgVectorStore: invalid table name '${table}'. Allowed: [A-Za-z_][A-Za-z0-9_]*.`,\n      );\n    }\n\n    this.table = table;\n    this.dimensions = options.dimensions ?? DEFAULT_DIMENSIONS;\n    this.index = options.index ?? \"hnsw\";\n    this.ivfflatLists = options.ivfflatLists ?? DEFAULT_IVFFLAT_LISTS;\n\n    if (options.client) {\n      if (typeof options.client.query !== \"function\") {\n        throw new TypeError(\n          \"pgVectorStore requires a 'client' option implementing { query(text, params) } — pass a pg.Pool or pg.Client.\",\n        );\n      }\n\n      this.clientPromise = Promise.resolve(options.client);\n\n      return;\n    }\n\n    if (options.connectionString) {\n      // Defer the optional `pg` import to first use — a curated install\n      // string surfaces from `buildPgClient`, not at construction.\n      this.clientPromise = buildPgClient(options.connectionString);\n\n      return;\n    }\n\n    throw new TypeError(\n      \"pgVectorStore requires either a 'client' or a 'connectionString' option.\",\n    );\n  }\n\n  /**\n   * Resolve the backing client, surfacing the lazy `pg` import's curated\n   * install string on the first call that needs it.\n   */\n  private client(): Promise<PgClientLike> {\n    return this.clientPromise;\n  }\n\n  /**\n   * Index `value` under `key` with its embedding `vector`. Upserts on the\n   * `key` primary key — re-indexing the same chunk overwrites its payload,\n   * embedding, and tags rather than appending a duplicate row. Optional\n   * `tags` ride a `text[]` column so {@link query} can restrict the\n   * candidate set with an array-overlap filter.\n   *\n   * The embedding is sent as a pgvector text literal (`$3`) cast to\n   * `::vector`, so the store needs no registered `pg` type parser. `tags`\n   * defaults to an empty array (never `NULL`) to keep the overlap filter's\n   * `&&` semantics simple.\n   */\n  public async upsert(\n    key: string,\n    value: unknown,\n    vector: number[],\n    tags?: string[],\n  ): Promise<void> {\n    const client = await this.client();\n\n    await client.query(\n      `INSERT INTO ${this.table} (key, value, embedding, tags)\n       VALUES ($1, $2::jsonb, $3::vector, $4::text[])\n       ON CONFLICT (key) DO UPDATE\n         SET value = EXCLUDED.value,\n             embedding = EXCLUDED.embedding,\n             tags = EXCLUDED.tags`,\n      [key, JSON.stringify(value), vectorLiteral(vector), tags ?? []],\n    );\n  }\n\n  /**\n   * Return the cosine-nearest rows to `vector`, mapped to the contract's\n   * `{ key, value, score }` shape. The SQL:\n   *\n   * - computes `embedding <=> $1::vector` (cosine **distance**) once, aliased\n   *   `distance`, and `ORDER BY` it ascending (nearest first);\n   * - applies the `threshold` floor as `distance <= 1 - threshold`\n   *   (similarity `>=` threshold), so the default `0.5` floor maps to a\n   *   `<= 0.5` distance bound — the filter runs in SQL, not in JS, so a\n   *   below-floor row never crosses the wire;\n   * - when `tags` are given, restricts to rows whose `tags` array overlaps\n   *   the requested set via `tags && $tags::text[]` (one-of semantics,\n   *   matching the cache store);\n   * - caps the result at `topK` with `LIMIT`.\n   *\n   * The returned `score` is `1 - distance`, clamped to `[0, 1]`, so callers\n   * see the same cosine-similarity scale the cache store emits.\n   */\n  public async query<T>(\n    vector: number[],\n    options: { topK: number; threshold?: number; tags?: string[] },\n  ): Promise<{ key: string; value: T; score: number }[]> {\n    const client = await this.client();\n    const queryVector = vectorLiteral(vector);\n\n    // $1 = query vector, $2 = topK. Optional threshold + tags are appended\n    // as $3 / $4 only when present, so the prepared statement carries no\n    // unused placeholders.\n    const params: unknown[] = [queryVector, options.topK];\n    const conditions: string[] = [];\n\n    if (options.threshold !== undefined) {\n      params.push(1 - options.threshold);\n      conditions.push(`(embedding <=> $1::vector) <= $${params.length}`);\n    }\n\n    if (options.tags !== undefined && options.tags.length > 0) {\n      params.push(options.tags);\n      conditions.push(`tags && $${params.length}::text[]`);\n    }\n\n    const where = conditions.length > 0 ? `WHERE ${conditions.join(\" AND \")}` : \"\";\n\n    const { rows } = await client.query(\n      `SELECT key, value, (embedding <=> $1::vector) AS distance\n       FROM ${this.table}\n       ${where}\n       ORDER BY embedding <=> $1::vector\n       LIMIT $2`,\n      params,\n    );\n\n    return (rows as Record<string, unknown>[]).map((row) => ({\n      key: row.key as string,\n      value: parseValue<T>(row.value),\n      score: distanceToScore(row.distance),\n    }));\n  }\n\n  /**\n   * Drop every entry written under `namespace`. The RAG pipeline keys\n   * chunks as `<namespace>.<sourceId>.<chunkIndex>`, so a row belongs to\n   * the namespace when its `key` equals it OR begins with `<namespace>.`\n   * — deleting `ai.rag.docs` must not also catch `ai.rag.docs2`. The `_`\n   * and `%` LIKE wildcards in the namespace are escaped so a namespace\n   * that happens to contain them is matched literally.\n   */\n  public async removeNamespace(namespace: string): Promise<void> {\n    const client = await this.client();\n\n    const escaped = namespace\n      .replace(/\\\\/g, \"\\\\\\\\\")\n      .replace(/_/g, \"\\\\_\")\n      .replace(/%/g, \"\\\\%\");\n\n    await client.query(\n      `DELETE FROM ${this.table}\n       WHERE key = $1 OR key LIKE $2 ESCAPE '\\\\'`,\n      [namespace, `${escaped}.%`],\n    );\n  }\n\n  /**\n   * Return the reference migration DDL for this store's backing table,\n   * interpolating the configured table name, embedding width, and ANN\n   * index strategy. The dev runs it once through their migration tool —\n   * the framework never auto-migrates.\n   *\n   * The emitted statements:\n   * 1. `CREATE EXTENSION IF NOT EXISTS vector;` — enables pgvector (needs\n   *    a superuser or a role with `CREATE` on the database the first time).\n   * 2. `CREATE TABLE IF NOT EXISTS <table> (key TEXT PRIMARY KEY, value\n   *    JSONB NOT NULL, embedding vector(<dimensions>) NOT NULL, tags\n   *    text[] NOT NULL DEFAULT '{}');`\n   * 3. A GIN index on `tags` so the array-overlap filter stays sargable.\n   * 4. The chosen ANN index over `embedding` using `vector_cosine_ops`:\n   *    - `\"hnsw\"` → `USING hnsw (embedding vector_cosine_ops)`;\n   *    - `\"ivfflat\"` → `USING ivfflat (embedding vector_cosine_ops)\n   *      WITH (lists = <ivfflatLists>)`;\n   *    - `\"none\"` → emitted as a comment (exact scan, no ANN index).\n   *\n   * @example\n   * const store = pgVectorStore({ client: pool, dimensions: 1536 });\n   * await pool.query(store.ensureSchema());\n   */\n  public schema(): string {\n    const lines = [\n      `CREATE EXTENSION IF NOT EXISTS vector;`,\n      `CREATE TABLE IF NOT EXISTS ${this.table} (`,\n      `  key        TEXT PRIMARY KEY,`,\n      `  value      JSONB NOT NULL,`,\n      `  embedding  vector(${this.dimensions}) NOT NULL,`,\n      `  tags       TEXT[] NOT NULL DEFAULT '{}'`,\n      `);`,\n      `CREATE INDEX IF NOT EXISTS idx_${this.table}_tags`,\n      `  ON ${this.table} USING gin (tags);`,\n    ];\n\n    if (this.index === \"hnsw\") {\n      lines.push(\n        `CREATE INDEX IF NOT EXISTS idx_${this.table}_embedding`,\n        `  ON ${this.table} USING hnsw (embedding vector_cosine_ops);`,\n      );\n    } else if (this.index === \"ivfflat\") {\n      lines.push(\n        `CREATE INDEX IF NOT EXISTS idx_${this.table}_embedding`,\n        `  ON ${this.table} USING ivfflat (embedding vector_cosine_ops)`,\n        `  WITH (lists = ${this.ivfflatLists});`,\n      );\n    } else {\n      lines.push(\n        `-- No ANN index requested (index: \"none\"): cosine queries fall back`,\n        `-- to an exact sequential scan, which is correct but linear in rows.`,\n      );\n    }\n\n    return lines.join(\"\\n\");\n  }\n\n  /**\n   * Alias for {@link PgVectorStore.schema} — reads more naturally in a\n   * migration script (`await pool.query(store.ensureSchema())`). Returns\n   * the identical DDL string; it does NOT execute anything against the\n   * database (the store never auto-migrates).\n   */\n  public ensureSchema(): string {\n    return this.schema();\n  }\n}\n\n/**\n * The {@link VectorStore} surface plus the pg store's extra DDL helpers.\n * `schema()` / `ensureSchema()` are not part of the base contract (the\n * cache store has no backing table), so the factory's return type widens\n * it for callers that want the migration SQL.\n */\nexport interface PgVectorStoreInstance extends VectorStore {\n  /** Reference migration DDL (extension + table + indexes). Never executed. */\n  schema(): string;\n  /** Alias for {@link PgVectorStoreInstance.schema} — reads better in a migration script. */\n  ensureSchema(): string;\n}\n\n/**\n * Create a Postgres + pgvector-backed {@link VectorStore} for the RAG\n * pipeline. Either pass a live `pg.Pool` / `pg.Client` (`{ client }`) —\n * `@warlock.js/ai` never imports `pg` in that case — or a\n * `{ connectionString }` and let the store lazily `import(\"pg\")` to build\n * its own pool. When `pg` is not installed, a curated install string\n * surfaces on first use, never at import.\n *\n * Run {@link PgVectorStoreInstance.ensureSchema} through your migration\n * tool once before use (it enables the `vector` extension, creates the\n * table, and builds the tag + ANN indexes); the store never auto-migrates.\n *\n * Index and query MUST use the same embedding model — the `vector(N)`\n * column width is fixed at table-creation time from `dimensions`.\n *\n * @example\n * import { Pool } from \"pg\";\n * import { ai } from \"@warlock.js/ai\";\n *\n * const pool = new Pool({ connectionString: process.env.DATABASE_URL });\n * const store = ai.rag.pgVectorStore({ client: pool, dimensions: 1536 });\n *\n * // Once, via your migration tooling:\n * // await pool.query(store.ensureSchema());\n *\n * const kb = ai.rag({\n *   name: \"docs\",\n *   embedder: openai.embedder({ name: \"text-embedding-3-small\" }),\n *   store,\n * });\n *\n * @example\n * // Let the store build its own pool from a connection string:\n * const store = ai.rag.pgVectorStore({\n *   connectionString: process.env.DATABASE_URL,\n *   index: \"ivfflat\",\n *   ivfflatLists: 200,\n * });\n */\nexport function pgVectorStore(options: PgVectorStoreOptions): PgVectorStoreInstance {\n  return new PgVectorStore(options);\n}\n"],"mappings":"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"}