@mastra/pg 0.0.0-a2a-20250421213654

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE.md ADDED
@@ -0,0 +1,7 @@
1
+ Copyright 2025 Mastra AI, Inc.
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
+
5
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
+
7
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,166 @@
1
+ # @mastra/pg
2
+
3
+ PostgreSQL implementation for Mastra, providing both vector similarity search (using pgvector) and general storage capabilities with connection pooling and transaction support.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @mastra/pg
9
+ ```
10
+
11
+ ## Prerequisites
12
+
13
+ - PostgreSQL server with pgvector extension installed (if using vector store)
14
+ - PostgreSQL 11 or higher
15
+
16
+ ## Usage
17
+
18
+ ### Vector Store
19
+
20
+ ```typescript
21
+ import { PgVector } from '@mastra/pg';
22
+
23
+ const vectorStore = new PgVector('postgresql://user:pass@localhost:5432/db');
24
+
25
+ // Create a new table with vector support
26
+ await vectorStore.createIndex({
27
+ indexName: 'my_vectors',
28
+ dimension: 1536,
29
+ metric: 'cosine',
30
+ });
31
+
32
+ // Add vectors
33
+ const ids = await vectorStore.upsert({
34
+ indexName: 'my_vectors',
35
+ vectors: [[0.1, 0.2, ...], [0.3, 0.4, ...]],
36
+ metadata: [{ text: 'doc1' }, { text: 'doc2' }],
37
+ });
38
+
39
+ // Query vectors
40
+ const results = await vectorStore.query({
41
+ indexName: 'my_vectors',
42
+ queryVector: [0.1, 0.2, ...],
43
+ topK: 10, // topK
44
+ filter: { text: 'doc1' }, // filter
45
+ includeVector: false, // includeVector
46
+ minScore: 0.5, // minScore
47
+ });
48
+
49
+ // Clean up
50
+ await vectorStore.disconnect();
51
+ ```
52
+
53
+ ### Storage
54
+
55
+ ```typescript
56
+ import { PostgresStore } from '@mastra/pg';
57
+
58
+ const store = new PostgresStore({
59
+ host: 'localhost',
60
+ port: 5432,
61
+ database: 'mastra',
62
+ user: 'postgres',
63
+ password: 'postgres',
64
+ });
65
+
66
+ // Create a thread
67
+ await store.saveThread({
68
+ id: 'thread-123',
69
+ resourceId: 'resource-456',
70
+ title: 'My Thread',
71
+ metadata: { key: 'value' },
72
+ });
73
+
74
+ // Add messages to thread
75
+ await store.saveMessages([
76
+ {
77
+ id: 'msg-789',
78
+ threadId: 'thread-123',
79
+ role: 'user',
80
+ type: 'text',
81
+ content: [{ type: 'text', text: 'Hello' }],
82
+ },
83
+ ]);
84
+
85
+ // Query threads and messages
86
+ const savedThread = await store.getThread('thread-123');
87
+ const messages = await store.getMessages('thread-123');
88
+ ```
89
+
90
+ ## Configuration
91
+
92
+ The PostgreSQL store can be initialized with either:
93
+
94
+ - `connectionString`: PostgreSQL connection string (for vector store)
95
+ - Configuration object with host, port, database, user, and password (for storage)
96
+
97
+ Connection pool settings:
98
+
99
+ - Maximum connections: 20
100
+ - Idle timeout: 30 seconds
101
+ - Connection timeout: 2 seconds
102
+
103
+ ## Features
104
+
105
+ ### Vector Store Features
106
+
107
+ - Vector similarity search with cosine, euclidean, and dot product metrics
108
+ - Advanced metadata filtering with MongoDB-like query syntax
109
+ - Minimum score threshold for queries
110
+ - Automatic UUID generation for vectors
111
+ - Table management (create, list, describe, delete, truncate)
112
+ - Uses pgvector's IVFFLAT indexing with 100 lists by default
113
+ - Supports HNSW indexing with configurable parameters
114
+ - Supports flat indexing
115
+
116
+ ### Storage Features
117
+
118
+ - Thread and message storage with JSON support
119
+ - Atomic transactions for data consistency
120
+ - Efficient batch operations
121
+ - Rich metadata support
122
+ - Timestamp tracking
123
+ - Cascading deletes
124
+
125
+ ## Supported Filter Operators
126
+
127
+ The following filter operators are supported for metadata queries:
128
+
129
+ - Comparison: `$eq`, `$ne`, `$gt`, `$gte`, `$lt`, `$lte`
130
+ - Logical: `$and`, `$or`
131
+ - Array: `$in`, `$nin`
132
+ - Text: `$regex`, `$like`
133
+
134
+ Example filter:
135
+
136
+ ```typescript
137
+ {
138
+ $and: [{ age: { $gt: 25 } }, { tags: { $in: ['tag1', 'tag2'] } }];
139
+ }
140
+ ```
141
+
142
+ ## Vector Store Methods
143
+
144
+ - `createIndex({indexName, dimension, metric?, indexConfig?, defineIndex?})`: Create a new table with vector support
145
+ - `upsert({indexName, vectors, metadata?, ids?})`: Add or update vectors
146
+ - `query({indexName, queryVector, topK?, filter?, includeVector?, minScore?})`: Search for similar vectors
147
+ - `defineIndex({indexName, metric?, indexConfig?})`: Define an index
148
+ - `listIndexes()`: List all vector-enabled tables
149
+ - `describeIndex(indexName)`: Get table statistics
150
+ - `deleteIndex(indexName)`: Delete a table
151
+ - `truncateIndex(indexName)`: Remove all data from a table
152
+ - `disconnect()`: Close all database connections
153
+
154
+ ## Storage Methods
155
+
156
+ - `saveThread(thread)`: Create or update a thread
157
+ - `getThread(threadId)`: Get a thread by ID
158
+ - `deleteThread(threadId)`: Delete a thread and its messages
159
+ - `saveMessages(messages)`: Save multiple messages in a transaction
160
+ - `getMessages(threadId)`: Get all messages for a thread
161
+ - `deleteMessages(messageIds)`: Delete specific messages
162
+
163
+ ## Related Links
164
+
165
+ - [pgvector Documentation](https://github.com/pgvector/pgvector)
166
+ - [PostgreSQL Documentation](https://www.postgresql.org/docs/)
@@ -0,0 +1,392 @@
1
+ import type { ArrayOperator } from '@mastra/core/vector/filter';
2
+ import { BaseFilterTranslator } from '@mastra/core/vector/filter';
3
+ import type { BasicOperator } from '@mastra/core/vector/filter';
4
+ import type { CreateIndexArgs } from '@mastra/core/vector';
5
+ import type { CreateIndexParams } from '@mastra/core/vector';
6
+ import type { ElementOperator } from '@mastra/core/vector/filter';
7
+ import type { EvalRow } from '@mastra/core/storage';
8
+ import type { IndexStats } from '@mastra/core/vector';
9
+ import type { ISSLConfig } from 'pg-promise/typescript/pg-subset';
10
+ import type { LogicalOperator } from '@mastra/core/vector/filter';
11
+ import { MastraStorage } from '@mastra/core/storage';
12
+ import { MastraVector } from '@mastra/core/vector';
13
+ import type { MessageType } from '@mastra/core/memory';
14
+ import type { NumericOperator } from '@mastra/core/vector/filter';
15
+ import type { OperatorSupport } from '@mastra/core/vector/filter';
16
+ import type { ParamsToArgs } from '@mastra/core/vector';
17
+ import type { QueryResult } from '@mastra/core/vector';
18
+ import type { QueryVectorArgs } from '@mastra/core/vector';
19
+ import type { QueryVectorParams } from '@mastra/core/vector';
20
+ import type { RegexOperator } from '@mastra/core/vector/filter';
21
+ import type { StorageColumn } from '@mastra/core/storage';
22
+ import type { StorageGetMessagesArg } from '@mastra/core/storage';
23
+ import type { StorageThreadType } from '@mastra/core/memory';
24
+ import type { TABLE_NAMES } from '@mastra/core/storage';
25
+ import type { UpsertVectorParams } from '@mastra/core/vector';
26
+ import type { VectorFilter } from '@mastra/core/vector/filter';
27
+ import type { WorkflowRunState } from '@mastra/core/workflows';
28
+
29
+ export declare const baseTestConfigs: {
30
+ smokeTests: {
31
+ dimension: number;
32
+ size: number;
33
+ k: number;
34
+ queryCount: number;
35
+ }[];
36
+ '64': {
37
+ dimension: number;
38
+ size: number;
39
+ k: number;
40
+ queryCount: number;
41
+ }[];
42
+ '384': {
43
+ dimension: number;
44
+ size: number;
45
+ k: number;
46
+ queryCount: number;
47
+ }[];
48
+ '1024': {
49
+ dimension: number;
50
+ size: number;
51
+ k: number;
52
+ queryCount: number;
53
+ }[];
54
+ stressTests: {
55
+ dimension: number;
56
+ size: number;
57
+ k: number;
58
+ queryCount: number;
59
+ }[];
60
+ };
61
+
62
+ export declare function buildFilterQuery(filter: VectorFilter, minScore: number): FilterResult;
63
+
64
+ export declare const calculateRecall: (actual: number[], expected: number[], k: number) => number;
65
+
66
+ export declare const calculateTimeout: (dimension: number, size: number, k: number) => number;
67
+
68
+ export declare function cosineSimilarity(a: number[], b: number[]): number;
69
+
70
+ export declare const FILTER_OPERATORS: Record<string, OperatorFn>;
71
+
72
+ declare type FilterOperator = {
73
+ sql: string;
74
+ needsValue: boolean;
75
+ transformValue?: () => any;
76
+ };
77
+
78
+ export declare interface FilterResult {
79
+ sql: string;
80
+ values: any[];
81
+ }
82
+
83
+ export declare const findNearestBruteForce: (query: number[], vectors: number[][], k: number) => number[];
84
+
85
+ export declare const formatTable: (data: any[], columns: string[]) => string;
86
+
87
+ export declare const generateClusteredVectors: (count: number, dim: number, numClusters?: number) => number[][];
88
+
89
+ export declare const generateRandomVectors: (count: number, dim: number) => number[][];
90
+
91
+ export declare const generateSkewedVectors: (count: number, dim: number) => number[][];
92
+
93
+ export declare const getHNSWConfig: (indexConfig: IndexConfig) => {
94
+ m: number;
95
+ efConstruction: number;
96
+ };
97
+
98
+ export declare function getIndexDescription({ type, hnsw, }: {
99
+ type: IndexType;
100
+ hnsw: {
101
+ m: number;
102
+ efConstruction: number;
103
+ };
104
+ }): string;
105
+
106
+ export declare const getListCount: (indexConfig: IndexConfig, size: number) => number | undefined;
107
+
108
+ export declare function getSearchEf(k: number, m: number): {
109
+ default: number;
110
+ lower: number;
111
+ higher: number;
112
+ };
113
+
114
+ export declare const groupBy: <T, K extends keyof T>(array: T[], key: K | ((item: T) => string), reducer?: (group: T[]) => any) => Record<string, any>;
115
+
116
+ export declare const handleKey: (key: string) => string;
117
+
118
+ declare interface HNSWConfig {
119
+ m?: number;
120
+ efConstruction?: number;
121
+ }
122
+
123
+ export declare interface IndexConfig {
124
+ type?: IndexType;
125
+ ivf?: IVFConfig;
126
+ hnsw?: HNSWConfig;
127
+ }
128
+
129
+ export declare type IndexType = 'ivfflat' | 'hnsw' | 'flat';
130
+
131
+ declare interface IVFConfig {
132
+ lists?: number;
133
+ }
134
+
135
+ export declare function measureLatency<T>(fn: () => Promise<T>): Promise<[number, T]>;
136
+
137
+ declare type OperatorFn = (key: string, paramIndex: number, value?: any) => FilterOperator;
138
+
139
+ export declare type OperatorType = BasicOperator | NumericOperator | ArrayOperator | ElementOperator | LogicalOperator | '$contains' | Exclude<RegexOperator, '$options'>;
140
+
141
+ declare type PgCreateIndexArgs = [...CreateIndexArgs, IndexConfig?, boolean?];
142
+
143
+ declare interface PgCreateIndexParams extends CreateIndexParams {
144
+ indexConfig?: IndexConfig;
145
+ buildIndex?: boolean;
146
+ }
147
+
148
+ declare type PgDefineIndexArgs = [string, 'cosine' | 'euclidean' | 'dotproduct', IndexConfig];
149
+
150
+ declare interface PgDefineIndexParams {
151
+ indexName: string;
152
+ metric: 'cosine' | 'euclidean' | 'dotproduct';
153
+ indexConfig: IndexConfig;
154
+ }
155
+
156
+ /**
157
+ * Translates MongoDB-style filters to PG compatible filters.
158
+ *
159
+ * Key differences from MongoDB:
160
+ *
161
+ * Logical Operators ($and, $or, $nor):
162
+ * - Can be used at the top level or nested within fields
163
+ * - Can take either a single condition or an array of conditions
164
+ *
165
+ */
166
+ export declare class PGFilterTranslator extends BaseFilterTranslator {
167
+ protected getSupportedOperators(): OperatorSupport;
168
+ translate(filter?: VectorFilter): VectorFilter;
169
+ private translateNode;
170
+ private translateRegexPattern;
171
+ }
172
+
173
+ declare interface PGIndexStats extends IndexStats {
174
+ type: IndexType;
175
+ config: {
176
+ m?: number;
177
+ efConstruction?: number;
178
+ lists?: number;
179
+ probes?: number;
180
+ };
181
+ }
182
+ export { PGIndexStats }
183
+ export { PGIndexStats as PGIndexStats_alias_1 }
184
+
185
+ declare type PgQueryVectorArgs = [...QueryVectorArgs, number?, number?, number?];
186
+
187
+ declare interface PgQueryVectorParams extends QueryVectorParams {
188
+ minScore?: number;
189
+ /**
190
+ * HNSW search parameter. Controls the size of the dynamic candidate
191
+ * list during search. Higher values improve accuracy at the cost of speed.
192
+ */
193
+ ef?: number;
194
+ /**
195
+ * IVFFlat probe parameter. Number of cells to visit during search.
196
+ * Higher values improve accuracy at the cost of speed.
197
+ */
198
+ probes?: number;
199
+ }
200
+
201
+ declare class PgVector extends MastraVector {
202
+ private pool;
203
+ private describeIndexCache;
204
+ private createdIndexes;
205
+ private mutexesByName;
206
+ private schema?;
207
+ private setupSchemaPromise;
208
+ private installVectorExtensionPromise;
209
+ private vectorExtensionInstalled;
210
+ private schemaSetupComplete;
211
+ constructor(connectionString: string);
212
+ constructor(config: {
213
+ connectionString: string;
214
+ schemaName?: string;
215
+ });
216
+ private getMutexByName;
217
+ private getTableName;
218
+ transformFilter(filter?: VectorFilter): VectorFilter;
219
+ getIndexInfo(indexName: string): Promise<PGIndexStats>;
220
+ query(...args: ParamsToArgs<PgQueryVectorParams> | PgQueryVectorArgs): Promise<QueryResult[]>;
221
+ upsert(...args: ParamsToArgs<UpsertVectorParams>): Promise<string[]>;
222
+ private hasher;
223
+ private getIndexCacheKey;
224
+ private cachedIndexExists;
225
+ private setupSchema;
226
+ createIndex(...args: ParamsToArgs<PgCreateIndexParams> | PgCreateIndexArgs): Promise<void>;
227
+ /**
228
+ * @deprecated This function is deprecated. Use buildIndex instead
229
+ */
230
+ defineIndex(indexName: string, metric: "cosine" | "euclidean" | "dotproduct" | undefined, indexConfig: IndexConfig): Promise<void>;
231
+ buildIndex(...args: ParamsToArgs<PgDefineIndexParams> | PgDefineIndexArgs): Promise<void>;
232
+ private setupIndex;
233
+ private installVectorExtension;
234
+ listIndexes(): Promise<string[]>;
235
+ describeIndex(indexName: string): Promise<PGIndexStats>;
236
+ deleteIndex(indexName: string): Promise<void>;
237
+ truncateIndex(indexName: string): Promise<void>;
238
+ disconnect(): Promise<void>;
239
+ updateIndexById(indexName: string, id: string, update: {
240
+ vector?: number[];
241
+ metadata?: Record<string, any>;
242
+ }): Promise<void>;
243
+ deleteIndexById(indexName: string, id: string): Promise<void>;
244
+ }
245
+ export { PgVector }
246
+ export { PgVector as PgVector_alias_1 }
247
+
248
+ declare type PostgresConfig = {
249
+ schemaName?: string;
250
+ /**
251
+ * @deprecated Use `schemaName` instead. Support for `schema` will be removed in a future release.
252
+ */
253
+ schema?: string;
254
+ } & ({
255
+ host: string;
256
+ port: number;
257
+ database: string;
258
+ user: string;
259
+ password: string;
260
+ ssl?: boolean | ISSLConfig;
261
+ } | {
262
+ connectionString: string;
263
+ });
264
+ export { PostgresConfig }
265
+ export { PostgresConfig as PostgresConfig_alias_1 }
266
+
267
+ declare class PostgresStore extends MastraStorage {
268
+ private db;
269
+ private pgp;
270
+ private schema?;
271
+ private setupSchemaPromise;
272
+ private schemaSetupComplete;
273
+ constructor(config: PostgresConfig);
274
+ private getTableName;
275
+ getEvalsByAgentName(agentName: string, type?: 'test' | 'live'): Promise<EvalRow[]>;
276
+ private transformEvalRow;
277
+ batchInsert({ tableName, records }: {
278
+ tableName: TABLE_NAMES;
279
+ records: Record<string, any>[];
280
+ }): Promise<void>;
281
+ getTraces({ name, scope, page, perPage, attributes, filters, }: {
282
+ name?: string;
283
+ scope?: string;
284
+ page: number;
285
+ perPage: number;
286
+ attributes?: Record<string, string>;
287
+ filters?: Record<string, any>;
288
+ }): Promise<any[]>;
289
+ private setupSchema;
290
+ createTable({ tableName, schema, }: {
291
+ tableName: TABLE_NAMES;
292
+ schema: Record<string, StorageColumn>;
293
+ }): Promise<void>;
294
+ clearTable({ tableName }: {
295
+ tableName: TABLE_NAMES;
296
+ }): Promise<void>;
297
+ insert({ tableName, record }: {
298
+ tableName: TABLE_NAMES;
299
+ record: Record<string, any>;
300
+ }): Promise<void>;
301
+ load<R>({ tableName, keys }: {
302
+ tableName: TABLE_NAMES;
303
+ keys: Record<string, string>;
304
+ }): Promise<R | null>;
305
+ getThreadById({ threadId }: {
306
+ threadId: string;
307
+ }): Promise<StorageThreadType | null>;
308
+ getThreadsByResourceId({ resourceId }: {
309
+ resourceId: string;
310
+ }): Promise<StorageThreadType[]>;
311
+ saveThread({ thread }: {
312
+ thread: StorageThreadType;
313
+ }): Promise<StorageThreadType>;
314
+ updateThread({ id, title, metadata, }: {
315
+ id: string;
316
+ title: string;
317
+ metadata: Record<string, unknown>;
318
+ }): Promise<StorageThreadType>;
319
+ deleteThread({ threadId }: {
320
+ threadId: string;
321
+ }): Promise<void>;
322
+ getMessages<T = unknown>({ threadId, selectBy }: StorageGetMessagesArg): Promise<T>;
323
+ saveMessages({ messages }: {
324
+ messages: MessageType[];
325
+ }): Promise<MessageType[]>;
326
+ persistWorkflowSnapshot({ workflowName, runId, snapshot, }: {
327
+ workflowName: string;
328
+ runId: string;
329
+ snapshot: WorkflowRunState;
330
+ }): Promise<void>;
331
+ loadWorkflowSnapshot({ workflowName, runId, }: {
332
+ workflowName: string;
333
+ runId: string;
334
+ }): Promise<WorkflowRunState | null>;
335
+ getWorkflowRuns({ workflowName, fromDate, toDate, limit, offset, }?: {
336
+ workflowName?: string;
337
+ fromDate?: Date;
338
+ toDate?: Date;
339
+ limit?: number;
340
+ offset?: number;
341
+ }): Promise<{
342
+ runs: Array<{
343
+ workflowName: string;
344
+ runId: string;
345
+ snapshot: WorkflowRunState | string;
346
+ createdAt: Date;
347
+ updatedAt: Date;
348
+ }>;
349
+ total: number;
350
+ }>;
351
+ close(): Promise<void>;
352
+ }
353
+ export { PostgresStore }
354
+ export { PostgresStore as PostgresStore_alias_1 }
355
+
356
+ export declare interface TestConfig {
357
+ dimension: number;
358
+ size: number;
359
+ k: number;
360
+ queryCount: number;
361
+ }
362
+
363
+ export declare interface TestResult {
364
+ distribution: string;
365
+ dimension: number;
366
+ type: IndexType;
367
+ size: number;
368
+ k?: number;
369
+ metrics: {
370
+ recall?: number;
371
+ minRecall?: number;
372
+ maxRecall?: number;
373
+ latency?: {
374
+ p50: number;
375
+ p95: number;
376
+ lists?: number;
377
+ vectorsPerList?: number;
378
+ m?: number;
379
+ ef?: number;
380
+ };
381
+ clustering?: {
382
+ numLists?: number;
383
+ avgVectorsPerList?: number;
384
+ recommendedLists?: number;
385
+ distribution?: string;
386
+ };
387
+ };
388
+ }
389
+
390
+ export declare function warmupQuery(vectorDB: PgVector, indexName: string, dimension: number, k: number): Promise<void>;
391
+
392
+ export { }