import { MastraVector } from '@mastra/core/vector'; import type { IndexStats, QueryResult, QueryVectorParams, CreateIndexParams, UpsertVectorParams, DescribeIndexParams, DeleteIndexParams, DeleteVectorParams, DeleteVectorsParams, UpdateVectorParams } from '@mastra/core/vector'; import * as pg from 'pg'; import type { PgVectorConfig } from '../shared/config.js'; import type { PGVectorFilter } from './filter.js'; import type { IndexConfig, IndexType, PgMetric, VectorType } from './types.js'; export type { PgMetric, VectorOps, VectorType, IndexConfig, IndexType } from './types.js'; export interface PGIndexStats extends IndexStats { type: IndexType; /** * The pgvector storage type used for this index. * - 'vector': Full precision (4 bytes per dimension) * - 'halfvec': Half precision (2 bytes per dimension) * - 'bit': Binary vectors (1 bit per dimension) * - 'sparsevec': Sparse vectors (only non-zero elements stored) */ vectorType: VectorType; config: { m?: number; efConstruction?: number; lists?: number; probes?: number; }; } interface PgQueryVectorParams extends QueryVectorParams { namespace?: string; minScore?: number; /** * HNSW search parameter. Controls the size of the dynamic candidate * list during search. Higher values improve accuracy at the cost of speed. */ ef?: number; /** * IVFFlat probe parameter. Number of cells to visit during search. * Higher values improve accuracy at the cost of speed. */ probes?: number; } interface PgCreateIndexParams extends Omit { /** * Distance metric for the index. * Standard: 'cosine', 'euclidean', 'dotproduct' (work with all vector types) * Bit-specific: 'hamming' (count differing bits), 'jaccard' (1 - intersection/union) * * For 'bit' vectorType, defaults to 'hamming' if not specified. * 'jaccard' requires HNSW index (IVFFlat does not support Jaccard distance). */ metric?: PgMetric; indexConfig?: IndexConfig; buildIndex?: boolean; /** * The pgvector storage type for embeddings. * - 'vector': Full precision (4 bytes per dimension), max 2000 dimensions for indexes (default) * - 'halfvec': Half precision (2 bytes per dimension), max 4000 dimensions for indexes * - 'bit': Binary vectors (1 bit per dimension), up to 64,000 dimensions for indexes * - 'sparsevec': Sparse vectors (only non-zero elements), up to 1,000 non-zero elements for indexes * * Use 'halfvec' for large dimension models like text-embedding-3-large (3072 dimensions) * Use 'bit' for binary quantization (reduced storage, faster search) * Use 'sparsevec' for BM25/TF-IDF and other sparse embeddings */ vectorType?: VectorType; /** * Metadata fields to create btree indexes for. * This improves query performance when filtering vectors by these metadata fields. * * Each entry creates a btree index on `metadata->>'field_name'`. * * Example: `['thread_id', 'resource_id']` creates indexes that speed up * queries filtering by `thread_id` or `resource_id` in the metadata JSONB column. */ metadataIndexes?: string[]; } interface PgDefineIndexParams { indexName: string; metric: PgMetric; indexConfig: IndexConfig; vectorType?: VectorType; } type PgUpsertVectorParams = UpsertVectorParams & { namespace?: string; }; type PgUpdateVectorParams = UpdateVectorParams & { namespace?: string; }; type PgDeleteVectorParams = DeleteVectorParams & { namespace?: string; }; type PgDeleteVectorsParams = DeleteVectorsParams & { namespace?: string; }; export declare class PgVector extends MastraVector { pool: pg.Pool; /** * Cache for the public `getIndexInfo()`. Holds the in-flight promise rather than the * resolved value so concurrent callers on a cold cache share a single round trip. */ private describeIndexCache; /** * Cache for the catalog-only index metadata used by the internal hot paths * (cache warmup, query, upsert, updateVector, setupIndex). Also memoizes the promise. */ private indexMetadataCache; private createdIndexes; private namespaceReadyIndexes; /** In-flight lazy namespace migrations, keyed by index name (see {@link ensureNamespaceReady}). */ private namespaceReadyCache; private indexVectorTypes; private mutexesByName; private schema?; private setupSchemaPromise; private installVectorExtensionPromise; private vectorExtensionInstalled; private vectorExtensionSchema; private vectorExtensionVersion; private schemaSetupComplete; private cacheWarmupPromise; constructor(config: PgVectorConfig & { id: string; }); private getMutexByName; /** * Detects which schema contains the vector extension and its version */ private detectVectorExtensionSchema; /** * Sets search_path on the client connection so that vector operators (e.g. <=>, vector_cosine_ops) * are resolvable when the pgvector extension is installed in a non-default schema. * * PostgreSQL's default search_path is ("$user", public). If the extension lives in a custom schema * (e.g. "myapp"), operator classes and distance operators won't resolve without this. */ private ensureSearchPath; /** * Checks if the installed pgvector version supports halfvec type. * halfvec was introduced in pgvector 0.7.0. */ private supportsHalfvec; /** Checks if pgvector >= 0.7.0 (required for bit type). */ private supportsBit; /** Checks if pgvector >= 0.7.0 (required for sparsevec type). */ private supportsSparsevec; /** * Gets the properly qualified vector type name * @param vectorType - The type of vector storage */ private getVectorTypeName; /** * Returns the operator class, distance operator, and score expression for a * standard (non-bit) vector type prefix and metric. */ private getMetricOps; /** * Returns all vector-type-specific operations for the given vectorType and metric. */ private getVectorOps; private getTableName; private getSchemaName; private ensureNamespaceSchema; private getNamespaceIndexName; private getNamespaceSchemaState; private reconcileNamespace; /** * Every data path filters on `namespace`, but tables created before that column existed are * only migrated by `createIndex()`, which callers are not required to invoke before reading. * Run the migration lazily instead, once per index per process. */ private ensureNamespaceReady; transformFilter(filter?: PGVectorFilter): PGVectorFilter; /** * Cached variant of {@link describeIndex}, including the row count. * * Internal code paths do not use this - they use the catalog-only * {@link getIndexMetadata}, which never scans the table. */ getIndexInfo({ indexName }: DescribeIndexParams): Promise; /** * Cached index metadata read from the Postgres catalog only. * * This is what every internal caller needs: none of them read `count`, and paying for * `SELECT COUNT(*)` on a large index costs a full heap scan per call. */ private getIndexMetadata; /** * Stores the in-flight promise in `cache` so concurrent callers on a cold cache share one * round trip, and drops the entry if it rejects so a transient failure is not cached forever. */ private memoize; /** Drops every cached view of an index, e.g. after its index definition or table changed. */ private invalidateIndexCaches; query({ indexName, queryVector, topK, filter, includeVector, minScore, ef, probes, namespace, }: PgQueryVectorParams): Promise; upsert({ indexName, vectors, metadata, ids, deleteFilter, namespace, }: PgUpsertVectorParams): Promise; private hasher; private getIndexCacheKey; private cachedIndexExists; private setupSchema; createIndex({ indexName, dimension, metric: rawMetric, indexConfig, buildIndex, vectorType, metadataIndexes, }: PgCreateIndexParams): Promise; buildIndex({ indexName, metric, indexConfig, vectorType }: PgDefineIndexParams): Promise; private setupIndex; private createMetadataIndexes; private installVectorExtension; listIndexes(): Promise; /** * Retrieves statistics about a vector index. * * @param {string} indexName - The name of the index to describe * @returns A promise that resolves to the index statistics including dimension, count and metric */ describeIndex({ indexName }: DescribeIndexParams): Promise; /** * Reads the index metadata that lives in the Postgres catalog. Unlike * {@link describeIndex} it issues no `COUNT(*)`, so its cost does not grow with the * number of rows in the table. */ private describeIndexMetadata; /** * Exact row count for an index. This is a full scan of the table, so it is only issued * for the public {@link describeIndex}, never from an internal code path. */ private countIndexRows; deleteIndex({ indexName }: DeleteIndexParams): Promise; truncateIndex({ indexName }: DeleteIndexParams): Promise; disconnect(): Promise; /** * Updates a vector by its ID with the provided vector and/or metadata. * @param indexName - The name of the index containing the vector. * @param id - The ID of the vector to update. * @param update - An object containing the vector and/or metadata to update. * @param update.vector - An optional array of numbers representing the new vector. * @param update.metadata - An optional record containing the new metadata. * @returns A promise that resolves when the update is complete. * @throws Will throw an error if no updates are provided or if the update operation fails. */ updateVector({ indexName, id, filter, update, namespace, }: PgUpdateVectorParams): Promise; /** * Deletes a vector by its ID. * @param indexName - The name of the index containing the vector. * @param id - The ID of the vector to delete. * @returns A promise that resolves when the deletion is complete. * @throws Will throw an error if the deletion operation fails. */ deleteVector({ indexName, id, namespace }: PgDeleteVectorParams): Promise; /** * Delete vectors matching a metadata filter. * @param indexName - The name of the index containing the vectors. * @param filter - The filter to match vectors for deletion. * @returns A promise that resolves when the deletion is complete. * @throws Will throw an error if the deletion operation fails. */ deleteVectors({ indexName, filter, ids, namespace }: PgDeleteVectorsParams): Promise; } //# sourceMappingURL=index.d.ts.map