@mastra/pg 1.19.0 → 1.20.0-alpha.1
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/CHANGELOG.md +60 -0
- package/dist/docs/SKILL.md +1 -1
- package/dist/docs/assets/SOURCE_MAP.json +1 -1
- package/dist/docs/references/docs-storage-overview.md +2 -2
- package/dist/docs/references/reference-storage-composite.md +58 -0
- package/dist/index.cjs +285 -127
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +285 -127
- package/dist/index.js.map +1 -1
- package/dist/storage/client.d.ts +5 -1
- package/dist/storage/client.d.ts.map +1 -1
- package/dist/storage/domains/experiments/index.d.ts.map +1 -1
- package/dist/storage/domains/memory/index.d.ts.map +1 -1
- package/dist/storage/domains/memory/test-utils.d.ts +30 -0
- package/dist/storage/domains/memory/test-utils.d.ts.map +1 -0
- package/dist/vector/sql-builder.d.ts.map +1 -1
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -146,13 +146,23 @@ var PGFilterTranslator = class extends BaseFilterTranslator {
|
|
|
146
146
|
};
|
|
147
147
|
//#endregion
|
|
148
148
|
//#region src/vector/sql-builder.ts
|
|
149
|
+
const getTextExtractExpr = (key) => {
|
|
150
|
+
const jsonPathKey = parseJsonPathKey(key);
|
|
151
|
+
if (!key.includes(".")) return `metadata->>'${jsonPathKey}'`;
|
|
152
|
+
return `metadata#>>'{${jsonPathKey}}'`;
|
|
153
|
+
};
|
|
154
|
+
const getJsonExtractExpr = (key) => {
|
|
155
|
+
const jsonPathKey = parseJsonPathKey(key);
|
|
156
|
+
if (!key.includes(".")) return `metadata->'${jsonPathKey}'`;
|
|
157
|
+
return `metadata#>'{${jsonPathKey}}'`;
|
|
158
|
+
};
|
|
149
159
|
const createBasicOperator = (symbol) => {
|
|
150
160
|
return (key, paramIndex) => {
|
|
151
|
-
const
|
|
161
|
+
const textExtract = getTextExtractExpr(key);
|
|
152
162
|
return {
|
|
153
|
-
sql: `CASE
|
|
154
|
-
WHEN $${paramIndex}::text IS NULL THEN
|
|
155
|
-
ELSE
|
|
163
|
+
sql: `CASE
|
|
164
|
+
WHEN $${paramIndex}::text IS NULL THEN ${textExtract} IS ${symbol === "=" ? "" : "NOT"} NULL
|
|
165
|
+
ELSE ${textExtract} ${symbol} $${paramIndex}::text
|
|
156
166
|
END`,
|
|
157
167
|
needsValue: true
|
|
158
168
|
};
|
|
@@ -160,13 +170,14 @@ const createBasicOperator = (symbol) => {
|
|
|
160
170
|
};
|
|
161
171
|
const createNumericOperator = (symbol) => {
|
|
162
172
|
return (key, paramIndex, value) => {
|
|
163
|
-
const
|
|
173
|
+
const textExtract = getTextExtractExpr(key);
|
|
174
|
+
const jsonExtract = getJsonExtractExpr(key);
|
|
164
175
|
if (typeof value === "number" || typeof value === "string" && !isNaN(Number(value)) && value.trim() !== "") return {
|
|
165
|
-
sql: `(CASE WHEN jsonb_typeof(
|
|
176
|
+
sql: `(CASE WHEN jsonb_typeof(${jsonExtract}) = 'number' THEN (${textExtract})::numeric ${symbol} $${paramIndex}::numeric ELSE NULL END)`,
|
|
166
177
|
needsValue: true
|
|
167
178
|
};
|
|
168
179
|
else return {
|
|
169
|
-
sql:
|
|
180
|
+
sql: `${textExtract} ${symbol} $${paramIndex}::text`,
|
|
170
181
|
needsValue: true
|
|
171
182
|
};
|
|
172
183
|
};
|
|
@@ -197,7 +208,7 @@ function buildElemMatchConditions(value, paramIndex) {
|
|
|
197
208
|
const operatorFn = FILTER_OPERATORS[paramOperator];
|
|
198
209
|
if (!operatorFn) throw new Error(`Invalid operator: ${paramOperator}`);
|
|
199
210
|
const result = operatorFn(paramKey, nextParamIndex, paramValue);
|
|
200
|
-
const sql = result.sql.replaceAll("metadata#>>", "elem#>>").replaceAll("metadata#>", "elem#>");
|
|
211
|
+
const sql = result.sql.replaceAll("metadata->>", "elem->>").replaceAll("metadata->", "elem->").replaceAll("metadata#>>", "elem#>>").replaceAll("metadata#>", "elem#>");
|
|
201
212
|
conditions.push(sql);
|
|
202
213
|
if (result.needsValue) values.push(paramValue);
|
|
203
214
|
});
|
|
@@ -214,32 +225,34 @@ const FILTER_OPERATORS = {
|
|
|
214
225
|
$lt: createNumericOperator("<"),
|
|
215
226
|
$lte: createNumericOperator("<="),
|
|
216
227
|
$in: (key, paramIndex) => {
|
|
217
|
-
const
|
|
228
|
+
const textExtract = getTextExtractExpr(key);
|
|
229
|
+
const jsonExtract = getJsonExtractExpr(key);
|
|
218
230
|
return {
|
|
219
231
|
sql: `(
|
|
220
232
|
CASE
|
|
221
|
-
WHEN jsonb_typeof(
|
|
233
|
+
WHEN jsonb_typeof(${jsonExtract}) = 'array' THEN
|
|
222
234
|
EXISTS (
|
|
223
|
-
SELECT 1 FROM jsonb_array_elements_text(
|
|
235
|
+
SELECT 1 FROM jsonb_array_elements_text(${jsonExtract}) as elem
|
|
224
236
|
WHERE elem = ANY($${paramIndex}::text[])
|
|
225
237
|
)
|
|
226
|
-
ELSE
|
|
238
|
+
ELSE ${textExtract} = ANY($${paramIndex}::text[])
|
|
227
239
|
END
|
|
228
240
|
)`,
|
|
229
241
|
needsValue: true
|
|
230
242
|
};
|
|
231
243
|
},
|
|
232
244
|
$nin: (key, paramIndex) => {
|
|
233
|
-
const
|
|
245
|
+
const textExtract = getTextExtractExpr(key);
|
|
246
|
+
const jsonExtract = getJsonExtractExpr(key);
|
|
234
247
|
return {
|
|
235
248
|
sql: `(
|
|
236
249
|
CASE
|
|
237
|
-
WHEN jsonb_typeof(
|
|
250
|
+
WHEN jsonb_typeof(${jsonExtract}) = 'array' THEN
|
|
238
251
|
NOT EXISTS (
|
|
239
|
-
SELECT 1 FROM jsonb_array_elements_text(
|
|
252
|
+
SELECT 1 FROM jsonb_array_elements_text(${jsonExtract}) as elem
|
|
240
253
|
WHERE elem = ANY($${paramIndex}::text[])
|
|
241
254
|
)
|
|
242
|
-
ELSE
|
|
255
|
+
ELSE ${textExtract} != ALL($${paramIndex}::text[])
|
|
243
256
|
END
|
|
244
257
|
)`,
|
|
245
258
|
needsValue: true
|
|
@@ -247,21 +260,21 @@ const FILTER_OPERATORS = {
|
|
|
247
260
|
},
|
|
248
261
|
$all: (key, paramIndex) => {
|
|
249
262
|
return {
|
|
250
|
-
sql: `CASE WHEN array_length($${paramIndex}::text[], 1) IS NULL THEN false
|
|
251
|
-
ELSE (
|
|
263
|
+
sql: `CASE WHEN array_length($${paramIndex}::text[], 1) IS NULL THEN false
|
|
264
|
+
ELSE (${getJsonExtractExpr(key)})::jsonb ?& $${paramIndex}::text[] END`,
|
|
252
265
|
needsValue: true
|
|
253
266
|
};
|
|
254
267
|
},
|
|
255
268
|
$elemMatch: (key, paramIndex, value) => {
|
|
256
269
|
const { sql, values } = buildElemMatchConditions(value, paramIndex);
|
|
257
|
-
const
|
|
270
|
+
const jsonExtract = getJsonExtractExpr(key);
|
|
258
271
|
return {
|
|
259
272
|
sql: `(
|
|
260
273
|
CASE
|
|
261
|
-
WHEN jsonb_typeof(
|
|
274
|
+
WHEN jsonb_typeof(${jsonExtract}) = 'array' THEN
|
|
262
275
|
EXISTS (
|
|
263
|
-
SELECT 1
|
|
264
|
-
FROM jsonb_array_elements(
|
|
276
|
+
SELECT 1
|
|
277
|
+
FROM jsonb_array_elements(${jsonExtract}) as elem
|
|
265
278
|
WHERE ${sql}
|
|
266
279
|
)
|
|
267
280
|
ELSE FALSE
|
|
@@ -291,7 +304,7 @@ const FILTER_OPERATORS = {
|
|
|
291
304
|
needsValue: false
|
|
292
305
|
}),
|
|
293
306
|
$not: (key) => ({
|
|
294
|
-
sql: `
|
|
307
|
+
sql: `(${key})`,
|
|
295
308
|
needsValue: false
|
|
296
309
|
}),
|
|
297
310
|
$nor: (key) => ({
|
|
@@ -300,16 +313,17 @@ const FILTER_OPERATORS = {
|
|
|
300
313
|
}),
|
|
301
314
|
$regex: (key, paramIndex) => {
|
|
302
315
|
return {
|
|
303
|
-
sql:
|
|
316
|
+
sql: `${getTextExtractExpr(key)} ~ $${paramIndex}`,
|
|
304
317
|
needsValue: true
|
|
305
318
|
};
|
|
306
319
|
},
|
|
307
320
|
$contains: (key, paramIndex, value) => {
|
|
308
|
-
const
|
|
321
|
+
const textExtract = getTextExtractExpr(key);
|
|
322
|
+
const jsonExtract = getJsonExtractExpr(key);
|
|
309
323
|
let sql;
|
|
310
|
-
if (Array.isArray(value)) sql = `(
|
|
311
|
-
else if (typeof value === "string") sql =
|
|
312
|
-
else sql =
|
|
324
|
+
if (Array.isArray(value)) sql = `(${jsonExtract}) ?& $${paramIndex}`;
|
|
325
|
+
else if (typeof value === "string") sql = `${textExtract} ILIKE '%' || $${paramIndex} || '%' ESCAPE '\\'`;
|
|
326
|
+
else sql = `${textExtract} = $${paramIndex}`;
|
|
313
327
|
return {
|
|
314
328
|
sql,
|
|
315
329
|
needsValue: true,
|
|
@@ -321,12 +335,12 @@ const FILTER_OPERATORS = {
|
|
|
321
335
|
* Usage: { field: { $objectContains: { ...subobject } } }
|
|
322
336
|
*/
|
|
323
337
|
$size: (key, paramIndex) => {
|
|
324
|
-
const
|
|
338
|
+
const jsonExtract = getJsonExtractExpr(key);
|
|
325
339
|
return {
|
|
326
340
|
sql: `(
|
|
327
341
|
CASE
|
|
328
|
-
WHEN jsonb_typeof(
|
|
329
|
-
jsonb_array_length(
|
|
342
|
+
WHEN jsonb_typeof(${jsonExtract}) = 'array' THEN
|
|
343
|
+
jsonb_array_length(${jsonExtract}) = $${paramIndex}
|
|
330
344
|
ELSE FALSE
|
|
331
345
|
END
|
|
332
346
|
)`,
|
|
@@ -354,7 +368,7 @@ function buildDeleteFilterQuery(filter) {
|
|
|
354
368
|
].includes(key)) return handleLogicalOperator(key, value, parentPath);
|
|
355
369
|
if (!value || typeof value !== "object") {
|
|
356
370
|
values.push(value);
|
|
357
|
-
return
|
|
371
|
+
return `${getTextExtractExpr(key)} = $${values.length}`;
|
|
358
372
|
}
|
|
359
373
|
const entries = Object.entries(value);
|
|
360
374
|
if (entries.length > 1) return entries.map(([operator, operatorValue]) => {
|
|
@@ -445,7 +459,7 @@ function buildFilterQuery(filter, minScore, topK) {
|
|
|
445
459
|
].includes(key)) return handleLogicalOperator(key, value, parentPath);
|
|
446
460
|
if (!value || typeof value !== "object") {
|
|
447
461
|
values.push(value);
|
|
448
|
-
return
|
|
462
|
+
return `${getTextExtractExpr(key)} = $${values.length}`;
|
|
449
463
|
}
|
|
450
464
|
const entries = Object.entries(value);
|
|
451
465
|
if (entries.length > 1) return entries.map(([operator, operatorValue]) => {
|
|
@@ -1778,16 +1792,21 @@ var PoolAdapter = class {
|
|
|
1778
1792
|
const client = await this.$pool.connect();
|
|
1779
1793
|
try {
|
|
1780
1794
|
await client.query("BEGIN");
|
|
1781
|
-
const
|
|
1782
|
-
await client.query("COMMIT");
|
|
1783
|
-
return result;
|
|
1784
|
-
} catch (error) {
|
|
1795
|
+
const txClient = new TransactionClient(client);
|
|
1785
1796
|
try {
|
|
1786
|
-
await
|
|
1787
|
-
|
|
1788
|
-
|
|
1797
|
+
const result = await callback(txClient);
|
|
1798
|
+
await txClient.drain();
|
|
1799
|
+
await client.query("COMMIT");
|
|
1800
|
+
return result;
|
|
1801
|
+
} catch (error) {
|
|
1802
|
+
await txClient.drain().catch(() => void 0);
|
|
1803
|
+
try {
|
|
1804
|
+
await client.query("ROLLBACK");
|
|
1805
|
+
} catch (rollbackError) {
|
|
1806
|
+
console.error("Transaction rollback failed:", rollbackError);
|
|
1807
|
+
}
|
|
1808
|
+
throw error;
|
|
1789
1809
|
}
|
|
1790
|
-
throw error;
|
|
1791
1810
|
} finally {
|
|
1792
1811
|
client.release();
|
|
1793
1812
|
}
|
|
@@ -1795,41 +1814,85 @@ var PoolAdapter = class {
|
|
|
1795
1814
|
};
|
|
1796
1815
|
/**
|
|
1797
1816
|
* Transaction client that wraps a PoolClient for executing queries within a transaction.
|
|
1817
|
+
*
|
|
1818
|
+
* Query methods are serialized through a tail promise (same pattern as
|
|
1819
|
+
* PinnedClientAdapter). Callers such as memory.updateMessages historically
|
|
1820
|
+
* did `queries.push(t.none(...))` then `await t.batch(queries)` — each
|
|
1821
|
+
* `t.none()` is async and starts `client.query` immediately, so by the time
|
|
1822
|
+
* batch runs, N queries are already in flight on one PoolClient. pg@8 queues
|
|
1823
|
+
* those internally and emits a DeprecationWarning; pg@9 will throw.
|
|
1824
|
+
* (#20820)
|
|
1798
1825
|
*/
|
|
1799
1826
|
var TransactionClient = class {
|
|
1800
1827
|
client;
|
|
1828
|
+
/**
|
|
1829
|
+
* Serialization tail. Without this gate, concurrent t.none()/t.query()
|
|
1830
|
+
* from Promise.all / batch land on the same PoolClient at once.
|
|
1831
|
+
*/
|
|
1832
|
+
#tail = Promise.resolve();
|
|
1833
|
+
#error;
|
|
1801
1834
|
constructor(client) {
|
|
1802
1835
|
this.client = client;
|
|
1803
1836
|
}
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1837
|
+
#enqueue(fn) {
|
|
1838
|
+
const next = this.#tail.then(fn);
|
|
1839
|
+
this.#tail = next.then(() => void 0, (error) => {
|
|
1840
|
+
this.#error ??= { value: error };
|
|
1841
|
+
});
|
|
1842
|
+
return next;
|
|
1807
1843
|
}
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1844
|
+
/**
|
|
1845
|
+
* Wait until every enqueued query has settled and surface the first failure.
|
|
1846
|
+
* PoolAdapter / PinnedClientAdapter call this before COMMIT/ROLLBACK so
|
|
1847
|
+
* those control statements never overlap in-flight work on the same client.
|
|
1848
|
+
*/
|
|
1849
|
+
async drain() {
|
|
1850
|
+
await this.#tail;
|
|
1851
|
+
if (this.#error) {
|
|
1852
|
+
const { value } = this.#error;
|
|
1853
|
+
this.#error = void 0;
|
|
1854
|
+
throw value;
|
|
1855
|
+
}
|
|
1813
1856
|
}
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1857
|
+
none(query, values) {
|
|
1858
|
+
return this.#enqueue(async () => {
|
|
1859
|
+
await this.client.query(query, values);
|
|
1860
|
+
return null;
|
|
1861
|
+
});
|
|
1819
1862
|
}
|
|
1820
|
-
|
|
1821
|
-
return (
|
|
1863
|
+
one(query, values) {
|
|
1864
|
+
return this.#enqueue(async () => {
|
|
1865
|
+
const result = await this.client.query(query, values);
|
|
1866
|
+
if (result.rows.length === 0) throw new Error(`No data returned from query: ${truncateQuery(query)}`);
|
|
1867
|
+
if (result.rows.length > 1) throw new Error(`Multiple rows returned when one was expected: ${truncateQuery(query)}`);
|
|
1868
|
+
return result.rows[0];
|
|
1869
|
+
});
|
|
1822
1870
|
}
|
|
1823
|
-
|
|
1871
|
+
oneOrNone(query, values) {
|
|
1872
|
+
return this.#enqueue(async () => {
|
|
1873
|
+
const result = await this.client.query(query, values);
|
|
1874
|
+
if (result.rows.length === 0) return null;
|
|
1875
|
+
if (result.rows.length > 1) throw new Error(`Multiple rows returned when one or none was expected: ${truncateQuery(query)}`);
|
|
1876
|
+
return result.rows[0];
|
|
1877
|
+
});
|
|
1878
|
+
}
|
|
1879
|
+
any(query, values) {
|
|
1880
|
+
return this.#enqueue(async () => {
|
|
1881
|
+
return (await this.client.query(query, values)).rows;
|
|
1882
|
+
});
|
|
1883
|
+
}
|
|
1884
|
+
manyOrNone(query, values) {
|
|
1824
1885
|
return this.any(query, values);
|
|
1825
1886
|
}
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1887
|
+
many(query, values) {
|
|
1888
|
+
return this.#enqueue(async () => {
|
|
1889
|
+
const result = await this.client.query(query, values);
|
|
1890
|
+
if (result.rows.length === 0) throw new Error(`No data returned from query: ${truncateQuery(query)}`);
|
|
1891
|
+
return result.rows;
|
|
1892
|
+
});
|
|
1830
1893
|
}
|
|
1831
|
-
|
|
1832
|
-
return this.client.query(query, values);
|
|
1894
|
+
query(query, values) {
|
|
1895
|
+
return this.#enqueue(() => this.client.query(query, values));
|
|
1833
1896
|
}
|
|
1834
1897
|
async batch(promises) {
|
|
1835
1898
|
return Promise.all(promises);
|
|
@@ -1922,11 +1985,14 @@ var PinnedClientAdapter = class {
|
|
|
1922
1985
|
tx(callback) {
|
|
1923
1986
|
return this.#enqueue(async () => {
|
|
1924
1987
|
await this.pinnedClient.query("BEGIN");
|
|
1988
|
+
const txClient = new TransactionClient(this.pinnedClient);
|
|
1925
1989
|
try {
|
|
1926
|
-
const result = await callback(
|
|
1990
|
+
const result = await callback(txClient);
|
|
1991
|
+
await txClient.drain();
|
|
1927
1992
|
await this.pinnedClient.query("COMMIT");
|
|
1928
1993
|
return result;
|
|
1929
1994
|
} catch (error) {
|
|
1995
|
+
await txClient.drain().catch(() => void 0);
|
|
1930
1996
|
try {
|
|
1931
1997
|
await this.pinnedClient.query("ROLLBACK");
|
|
1932
1998
|
} catch (rollbackError) {
|
|
@@ -6416,7 +6482,13 @@ var ExperimentsPG = class ExperimentsPG extends ExperimentsStorage {
|
|
|
6416
6482
|
ifNotExists: [
|
|
6417
6483
|
"agentVersion",
|
|
6418
6484
|
"organizationId",
|
|
6419
|
-
"projectId"
|
|
6485
|
+
"projectId",
|
|
6486
|
+
"provenance",
|
|
6487
|
+
"runnerAttestation",
|
|
6488
|
+
"experimentSetId",
|
|
6489
|
+
"comparisonId",
|
|
6490
|
+
"variantId",
|
|
6491
|
+
"trialIndex"
|
|
6420
6492
|
]
|
|
6421
6493
|
});
|
|
6422
6494
|
await this.#db.alterTable({
|
|
@@ -6522,6 +6594,16 @@ var ExperimentsPG = class ExperimentsPG extends ExperimentsStorage {
|
|
|
6522
6594
|
table: TABLE_EXPERIMENTS,
|
|
6523
6595
|
columns: ["datasetId"]
|
|
6524
6596
|
},
|
|
6597
|
+
{
|
|
6598
|
+
name: "idx_experiments_grouping",
|
|
6599
|
+
table: TABLE_EXPERIMENTS,
|
|
6600
|
+
columns: [
|
|
6601
|
+
"experimentSetId",
|
|
6602
|
+
"comparisonId",
|
|
6603
|
+
"variantId",
|
|
6604
|
+
"trialIndex"
|
|
6605
|
+
]
|
|
6606
|
+
},
|
|
6525
6607
|
{
|
|
6526
6608
|
name: "idx_experiment_results_experimentid",
|
|
6527
6609
|
table: TABLE_EXPERIMENT_RESULTS,
|
|
@@ -6567,6 +6649,12 @@ var ExperimentsPG = class ExperimentsPG extends ExperimentsStorage {
|
|
|
6567
6649
|
name: row.name ?? void 0,
|
|
6568
6650
|
description: row.description ?? void 0,
|
|
6569
6651
|
metadata: row.metadata ? safelyParseJSON(row.metadata) : void 0,
|
|
6652
|
+
provenance: row.provenance ? safelyParseJSON(row.provenance) : null,
|
|
6653
|
+
runnerAttestation: row.runnerAttestation ? safelyParseJSON(row.runnerAttestation) : null,
|
|
6654
|
+
experimentSetId: row.experimentSetId ?? null,
|
|
6655
|
+
comparisonId: row.comparisonId ?? null,
|
|
6656
|
+
variantId: row.variantId ?? null,
|
|
6657
|
+
trialIndex: row.trialIndex != null ? row.trialIndex : null,
|
|
6570
6658
|
datasetId: row.datasetId ?? null,
|
|
6571
6659
|
datasetVersion: row.datasetVersion != null ? row.datasetVersion : null,
|
|
6572
6660
|
agentVersion: row.agentVersion ?? null,
|
|
@@ -6620,6 +6708,12 @@ var ExperimentsPG = class ExperimentsPG extends ExperimentsStorage {
|
|
|
6620
6708
|
name: input.name ?? null,
|
|
6621
6709
|
description: input.description ?? null,
|
|
6622
6710
|
metadata: input.metadata ?? null,
|
|
6711
|
+
provenance: input.provenance ?? null,
|
|
6712
|
+
runnerAttestation: input.runnerAttestation ?? null,
|
|
6713
|
+
experimentSetId: input.experimentSetId ?? null,
|
|
6714
|
+
comparisonId: input.comparisonId ?? null,
|
|
6715
|
+
variantId: input.variantId ?? null,
|
|
6716
|
+
trialIndex: input.trialIndex ?? null,
|
|
6623
6717
|
datasetId: input.datasetId ?? null,
|
|
6624
6718
|
datasetVersion: input.datasetVersion ?? null,
|
|
6625
6719
|
agentVersion: input.agentVersion ?? null,
|
|
@@ -6643,6 +6737,12 @@ var ExperimentsPG = class ExperimentsPG extends ExperimentsStorage {
|
|
|
6643
6737
|
name: input.name,
|
|
6644
6738
|
description: input.description,
|
|
6645
6739
|
metadata: input.metadata,
|
|
6740
|
+
provenance: input.provenance ?? null,
|
|
6741
|
+
runnerAttestation: input.runnerAttestation ?? null,
|
|
6742
|
+
experimentSetId: input.experimentSetId ?? null,
|
|
6743
|
+
comparisonId: input.comparisonId ?? null,
|
|
6744
|
+
variantId: input.variantId ?? null,
|
|
6745
|
+
trialIndex: input.trialIndex ?? null,
|
|
6646
6746
|
datasetId: input.datasetId ?? null,
|
|
6647
6747
|
datasetVersion: input.datasetVersion ?? null,
|
|
6648
6748
|
agentVersion: input.agentVersion ?? null,
|
|
@@ -6784,6 +6884,22 @@ var ExperimentsPG = class ExperimentsPG extends ExperimentsStorage {
|
|
|
6784
6884
|
conditions.push(`"status" = $${paramIndex++}`);
|
|
6785
6885
|
queryParams.push(args.status);
|
|
6786
6886
|
}
|
|
6887
|
+
if (args.experimentSetId !== void 0) {
|
|
6888
|
+
conditions.push(`"experimentSetId" = $${paramIndex++}`);
|
|
6889
|
+
queryParams.push(args.experimentSetId);
|
|
6890
|
+
}
|
|
6891
|
+
if (args.comparisonId !== void 0) {
|
|
6892
|
+
conditions.push(`"comparisonId" = $${paramIndex++}`);
|
|
6893
|
+
queryParams.push(args.comparisonId);
|
|
6894
|
+
}
|
|
6895
|
+
if (args.variantId !== void 0) {
|
|
6896
|
+
conditions.push(`"variantId" = $${paramIndex++}`);
|
|
6897
|
+
queryParams.push(args.variantId);
|
|
6898
|
+
}
|
|
6899
|
+
if (args.trialIndex !== void 0) {
|
|
6900
|
+
conditions.push(`"trialIndex" = $${paramIndex++}`);
|
|
6901
|
+
queryParams.push(args.trialIndex);
|
|
6902
|
+
}
|
|
6787
6903
|
if (args.filters) {
|
|
6788
6904
|
const { organizationId, projectId } = args.filters;
|
|
6789
6905
|
if (organizationId !== void 0) {
|
|
@@ -8565,6 +8681,13 @@ function getTableName$3({ indexName, schemaName }) {
|
|
|
8565
8681
|
function inPlaceholders(count, startIndex = 1) {
|
|
8566
8682
|
return Array.from({ length: count }, (_, i) => `$${i + startIndex}`).join(", ");
|
|
8567
8683
|
}
|
|
8684
|
+
/**
|
|
8685
|
+
* Bind dates as UTC strings because node-postgres serializes Date parameters
|
|
8686
|
+
* for TIMESTAMP columns using the process's local timezone.
|
|
8687
|
+
*/
|
|
8688
|
+
function toUtcISOString(date) {
|
|
8689
|
+
return date.toISOString();
|
|
8690
|
+
}
|
|
8568
8691
|
function dedupeMessagesForSave(messages) {
|
|
8569
8692
|
const deduped = /* @__PURE__ */ new Map();
|
|
8570
8693
|
for (const message of messages) {
|
|
@@ -8979,6 +9102,7 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
8979
9102
|
hasMore: perPageInput === false ? false : offset + perPage < total
|
|
8980
9103
|
};
|
|
8981
9104
|
} catch (error) {
|
|
9105
|
+
if (error instanceof MastraError && error.category === ErrorCategory.USER) throw error;
|
|
8982
9106
|
const mastraError = new MastraError({
|
|
8983
9107
|
id: createStorageErrorId("PG", "LIST_THREADS", "FAILED"),
|
|
8984
9108
|
domain: ErrorDomain.STORAGE,
|
|
@@ -8991,13 +9115,7 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
8991
9115
|
}, error);
|
|
8992
9116
|
this.logger?.error?.(mastraError.toString());
|
|
8993
9117
|
this.logger?.trackException(mastraError);
|
|
8994
|
-
|
|
8995
|
-
threads: [],
|
|
8996
|
-
total: 0,
|
|
8997
|
-
page,
|
|
8998
|
-
perPage: perPageForResponse,
|
|
8999
|
-
hasMore: false
|
|
9000
|
-
};
|
|
9118
|
+
throw mastraError;
|
|
9001
9119
|
}
|
|
9002
9120
|
}
|
|
9003
9121
|
async saveThread({ thread }) {
|
|
@@ -9006,6 +9124,8 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
9006
9124
|
indexName: TABLE_THREADS,
|
|
9007
9125
|
schemaName: getSchemaName$3(this.#schema)
|
|
9008
9126
|
});
|
|
9127
|
+
const createdAt = toUtcISOString(thread.createdAt);
|
|
9128
|
+
const updatedAt = toUtcISOString(thread.updatedAt);
|
|
9009
9129
|
await this.#db.client.none(`INSERT INTO ${tableName} (
|
|
9010
9130
|
id,
|
|
9011
9131
|
"resourceId",
|
|
@@ -9028,10 +9148,10 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
9028
9148
|
thread.resourceId,
|
|
9029
9149
|
thread.title,
|
|
9030
9150
|
thread.metadata ? JSON.stringify(thread.metadata) : null,
|
|
9031
|
-
|
|
9032
|
-
|
|
9033
|
-
|
|
9034
|
-
|
|
9151
|
+
createdAt,
|
|
9152
|
+
createdAt,
|
|
9153
|
+
updatedAt,
|
|
9154
|
+
updatedAt
|
|
9035
9155
|
]);
|
|
9036
9156
|
return thread;
|
|
9037
9157
|
} catch (error) {
|
|
@@ -9064,7 +9184,7 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
9064
9184
|
...metadata
|
|
9065
9185
|
};
|
|
9066
9186
|
try {
|
|
9067
|
-
const
|
|
9187
|
+
const nowStr = toUtcISOString(/* @__PURE__ */ new Date());
|
|
9068
9188
|
const thread = await this.#db.client.one(`UPDATE ${threadTableName}
|
|
9069
9189
|
SET
|
|
9070
9190
|
title = $1,
|
|
@@ -9076,8 +9196,8 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
9076
9196
|
`, [
|
|
9077
9197
|
title,
|
|
9078
9198
|
mergedMetadata,
|
|
9079
|
-
|
|
9080
|
-
|
|
9199
|
+
nowStr,
|
|
9200
|
+
nowStr,
|
|
9081
9201
|
id
|
|
9082
9202
|
]);
|
|
9083
9203
|
return {
|
|
@@ -9266,9 +9386,41 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
9266
9386
|
}, error);
|
|
9267
9387
|
this.logger?.error?.(mastraError.toString());
|
|
9268
9388
|
this.logger?.trackException(mastraError);
|
|
9269
|
-
|
|
9389
|
+
throw mastraError;
|
|
9270
9390
|
}
|
|
9271
9391
|
}
|
|
9392
|
+
/**
|
|
9393
|
+
* Reads one page of messages together with the total row count.
|
|
9394
|
+
*
|
|
9395
|
+
* `COUNT(*) OVER ()` reports the count over the whole WHERE result on the same
|
|
9396
|
+
* statement as the page, so the page costs one database round-trip instead of
|
|
9397
|
+
* two. The page and the count also come from one snapshot, so the count always
|
|
9398
|
+
* describes the returned rows. A separate `COUNT(*)` runs only when the page is
|
|
9399
|
+
* empty and the caller asked for a page after the last row, because a window
|
|
9400
|
+
* function has no row to carry the count on.
|
|
9401
|
+
*/
|
|
9402
|
+
async #fetchMessagePage({ selectStatement, tableName, whereClause, orderByStatement, queryParams, perPageInput, perPage, offset }) {
|
|
9403
|
+
const limitClause = perPageInput === false ? "" : ` LIMIT $${queryParams.length + 1} OFFSET $${queryParams.length + 2}`;
|
|
9404
|
+
const dataParams = perPageInput === false ? queryParams : [
|
|
9405
|
+
...queryParams,
|
|
9406
|
+
perPage,
|
|
9407
|
+
offset
|
|
9408
|
+
];
|
|
9409
|
+
const rows = await this.#db.client.manyOrNone(`${selectStatement}, COUNT(*) OVER () AS "__total" FROM ${tableName} ${whereClause} ${orderByStatement}${limitClause}`, dataParams) || [];
|
|
9410
|
+
if (rows.length > 0) return {
|
|
9411
|
+
total: Number(rows[0].__total),
|
|
9412
|
+
messages: rows
|
|
9413
|
+
};
|
|
9414
|
+
if (offset === 0) return {
|
|
9415
|
+
total: 0,
|
|
9416
|
+
messages: []
|
|
9417
|
+
};
|
|
9418
|
+
const countResult = await this.#db.client.one(`SELECT COUNT(*) FROM ${tableName} ${whereClause}`, queryParams);
|
|
9419
|
+
return {
|
|
9420
|
+
total: parseInt(countResult.count, 10),
|
|
9421
|
+
messages: []
|
|
9422
|
+
};
|
|
9423
|
+
}
|
|
9272
9424
|
async listMessages(args) {
|
|
9273
9425
|
const { threadId, resourceId, include, filter, perPage: perPageInput, page = 0, orderBy } = args;
|
|
9274
9426
|
const threadIds = (Array.isArray(threadId) ? threadId : [threadId]).filter((id) => typeof id === "string");
|
|
@@ -9343,23 +9495,27 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
9343
9495
|
hasMore: false
|
|
9344
9496
|
};
|
|
9345
9497
|
}
|
|
9498
|
+
let includeFailure;
|
|
9499
|
+
const includePromise = include && include.length > 0 ? this._getIncludedMessages({ include }).catch((error) => {
|
|
9500
|
+
includeFailure = error;
|
|
9501
|
+
return null;
|
|
9502
|
+
}) : null;
|
|
9346
9503
|
let total;
|
|
9347
9504
|
let messages;
|
|
9348
9505
|
if (metadataFilter) {
|
|
9349
9506
|
const filteredRows = (await this.#db.client.manyOrNone(`${selectStatement} FROM ${tableName} ${whereClause} ${orderByStatement}`, queryParams) || []).filter((row) => storageMessageMatchesMetadataFilter(row.content, metadataFilter));
|
|
9350
9507
|
total = filteredRows.length;
|
|
9351
9508
|
messages = perPageInput === false ? filteredRows : filteredRows.slice(offset, offset + perPage);
|
|
9352
|
-
} else {
|
|
9353
|
-
|
|
9354
|
-
|
|
9355
|
-
|
|
9356
|
-
|
|
9357
|
-
|
|
9358
|
-
|
|
9359
|
-
|
|
9360
|
-
|
|
9361
|
-
|
|
9362
|
-
}
|
|
9509
|
+
} else ({total, messages} = await this.#fetchMessagePage({
|
|
9510
|
+
selectStatement,
|
|
9511
|
+
tableName,
|
|
9512
|
+
whereClause,
|
|
9513
|
+
orderByStatement,
|
|
9514
|
+
queryParams,
|
|
9515
|
+
perPageInput,
|
|
9516
|
+
perPage,
|
|
9517
|
+
offset
|
|
9518
|
+
}));
|
|
9363
9519
|
const primaryPageCount = messages.length;
|
|
9364
9520
|
if (total === 0 && messages.length === 0 && (!include || include.length === 0)) return {
|
|
9365
9521
|
messages: [],
|
|
@@ -9370,7 +9526,8 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
9370
9526
|
};
|
|
9371
9527
|
const messageIds = new Set(messages.map((m) => m.id));
|
|
9372
9528
|
if (include && include.length > 0) {
|
|
9373
|
-
const includeMessages = await
|
|
9529
|
+
const includeMessages = await includePromise;
|
|
9530
|
+
if (includeFailure) throw includeFailure;
|
|
9374
9531
|
if (includeMessages) {
|
|
9375
9532
|
for (const includeMsg of includeMessages) if (!messageIds.has(includeMsg.id)) {
|
|
9376
9533
|
messages.push(includeMsg);
|
|
@@ -9392,6 +9549,7 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
9392
9549
|
hasMore
|
|
9393
9550
|
};
|
|
9394
9551
|
} catch (error) {
|
|
9552
|
+
if (error instanceof MastraError && error.category === ErrorCategory.USER) throw error;
|
|
9395
9553
|
const mastraError = new MastraError({
|
|
9396
9554
|
id: createStorageErrorId("PG", "LIST_MESSAGES", "FAILED"),
|
|
9397
9555
|
domain: ErrorDomain.STORAGE,
|
|
@@ -9403,13 +9561,7 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
9403
9561
|
}, error);
|
|
9404
9562
|
this.logger?.error?.(mastraError.toString());
|
|
9405
9563
|
this.logger?.trackException(mastraError);
|
|
9406
|
-
|
|
9407
|
-
messages: [],
|
|
9408
|
-
total: 0,
|
|
9409
|
-
page,
|
|
9410
|
-
perPage: perPageForResponse,
|
|
9411
|
-
hasMore: false
|
|
9412
|
-
};
|
|
9564
|
+
throw mastraError;
|
|
9413
9565
|
}
|
|
9414
9566
|
}
|
|
9415
9567
|
async listMessagesByResourceId(args) {
|
|
@@ -9483,23 +9635,27 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
9483
9635
|
hasMore: false
|
|
9484
9636
|
};
|
|
9485
9637
|
}
|
|
9638
|
+
let includeFailure;
|
|
9639
|
+
const includePromise = include && include.length > 0 ? this._getIncludedMessages({ include }).catch((error) => {
|
|
9640
|
+
includeFailure = error;
|
|
9641
|
+
return null;
|
|
9642
|
+
}) : null;
|
|
9486
9643
|
let total;
|
|
9487
9644
|
let messages;
|
|
9488
9645
|
if (metadataFilter) {
|
|
9489
9646
|
const filteredRows = (await this.#db.client.manyOrNone(`${selectStatement} FROM ${tableName} ${whereClause} ${orderByStatement}`, queryParams) || []).filter((row) => storageMessageMatchesMetadataFilter(row.content, metadataFilter));
|
|
9490
9647
|
total = filteredRows.length;
|
|
9491
9648
|
messages = perPageInput === false ? filteredRows : filteredRows.slice(offset, offset + perPage);
|
|
9492
|
-
} else {
|
|
9493
|
-
|
|
9494
|
-
|
|
9495
|
-
|
|
9496
|
-
|
|
9497
|
-
|
|
9498
|
-
|
|
9499
|
-
|
|
9500
|
-
|
|
9501
|
-
|
|
9502
|
-
}
|
|
9649
|
+
} else ({total, messages} = await this.#fetchMessagePage({
|
|
9650
|
+
selectStatement,
|
|
9651
|
+
tableName,
|
|
9652
|
+
whereClause,
|
|
9653
|
+
orderByStatement,
|
|
9654
|
+
queryParams,
|
|
9655
|
+
perPageInput,
|
|
9656
|
+
perPage,
|
|
9657
|
+
offset
|
|
9658
|
+
}));
|
|
9503
9659
|
if (total === 0 && messages.length === 0 && (!include || include.length === 0)) return {
|
|
9504
9660
|
messages: [],
|
|
9505
9661
|
total: 0,
|
|
@@ -9509,7 +9665,8 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
9509
9665
|
};
|
|
9510
9666
|
const messageIds = new Set(messages.map((m) => m.id));
|
|
9511
9667
|
if (include && include.length > 0) {
|
|
9512
|
-
const includeMessages = await
|
|
9668
|
+
const includeMessages = await includePromise;
|
|
9669
|
+
if (includeFailure) throw includeFailure;
|
|
9513
9670
|
if (includeMessages) {
|
|
9514
9671
|
for (const includeMsg of includeMessages) if (!messageIds.has(includeMsg.id)) {
|
|
9515
9672
|
messages.push(includeMsg);
|
|
@@ -9529,6 +9686,7 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
9529
9686
|
hasMore
|
|
9530
9687
|
};
|
|
9531
9688
|
} catch (error) {
|
|
9689
|
+
if (error instanceof MastraError && error.category === ErrorCategory.USER) throw error;
|
|
9532
9690
|
const mastraError = new MastraError({
|
|
9533
9691
|
id: createStorageErrorId("PG", "LIST_MESSAGES_BY_RESOURCE_ID", "FAILED"),
|
|
9534
9692
|
domain: ErrorDomain.STORAGE,
|
|
@@ -9537,13 +9695,7 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
9537
9695
|
}, error);
|
|
9538
9696
|
this.logger?.error?.(mastraError.toString());
|
|
9539
9697
|
this.logger?.trackException(mastraError);
|
|
9540
|
-
|
|
9541
|
-
messages: [],
|
|
9542
|
-
total: 0,
|
|
9543
|
-
page,
|
|
9544
|
-
perPage: perPageForResponse,
|
|
9545
|
-
hasMore: false
|
|
9546
|
-
};
|
|
9698
|
+
throw mastraError;
|
|
9547
9699
|
}
|
|
9548
9700
|
}
|
|
9549
9701
|
async saveMessages({ messages }) {
|
|
@@ -9579,7 +9731,7 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
9579
9731
|
const batch = messagesToSave.slice(offset, offset + MAX_MESSAGES_PER_INSERT);
|
|
9580
9732
|
const values = [];
|
|
9581
9733
|
const valuePlaceholders = batch.map((message, messageIndex) => {
|
|
9582
|
-
const createdAt = message.createdAt || /* @__PURE__ */ new Date();
|
|
9734
|
+
const createdAt = toUtcISOString(message.createdAt || /* @__PURE__ */ new Date());
|
|
9583
9735
|
values.push(message.id, message.threadId, typeof message.content === "string" ? message.content : JSON.stringify(message.content), createdAt, createdAt, message.role, message.type || "v2", message.resourceId);
|
|
9584
9736
|
const paramOffset = messageIndex * MESSAGE_INSERT_BIND_PARAMETERS;
|
|
9585
9737
|
return `(${Array.from({ length: MESSAGE_INSERT_BIND_PARAMETERS }, (_, paramIndex) => `$${paramOffset + paramIndex + 1}`).join(", ")})`;
|
|
@@ -9597,7 +9749,7 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
9597
9749
|
indexName: TABLE_THREADS,
|
|
9598
9750
|
schemaName: getSchemaName$3(this.#schema)
|
|
9599
9751
|
});
|
|
9600
|
-
const now = /* @__PURE__ */ new Date();
|
|
9752
|
+
const now = toUtcISOString(/* @__PURE__ */ new Date());
|
|
9601
9753
|
for (const threadIdToUpdate of threadIds) await t.none(`UPDATE ${threadTableName}
|
|
9602
9754
|
SET
|
|
9603
9755
|
"updatedAt" = $1,
|
|
@@ -9749,11 +9901,15 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
9749
9901
|
};
|
|
9750
9902
|
}
|
|
9751
9903
|
async saveResource({ resource }) {
|
|
9904
|
+
const createdAt = toUtcISOString(resource.createdAt);
|
|
9905
|
+
const updatedAt = toUtcISOString(resource.updatedAt);
|
|
9752
9906
|
await this.#db.insert({
|
|
9753
9907
|
tableName: TABLE_RESOURCES,
|
|
9754
9908
|
record: {
|
|
9755
9909
|
...resource,
|
|
9756
|
-
metadata: JSON.stringify(resource.metadata)
|
|
9910
|
+
metadata: JSON.stringify(resource.metadata),
|
|
9911
|
+
createdAt,
|
|
9912
|
+
updatedAt
|
|
9757
9913
|
}
|
|
9758
9914
|
});
|
|
9759
9915
|
return resource;
|
|
@@ -9857,6 +10013,7 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
9857
10013
|
}
|
|
9858
10014
|
const sourceMessages = await t.manyOrNone(messageQuery, messageParams);
|
|
9859
10015
|
const now = /* @__PURE__ */ new Date();
|
|
10016
|
+
const nowStr = toUtcISOString(now);
|
|
9860
10017
|
const lastMessageId = sourceMessages.length > 0 ? sourceMessages[sourceMessages.length - 1].id : void 0;
|
|
9861
10018
|
const cloneMetadata = {
|
|
9862
10019
|
sourceThreadId,
|
|
@@ -9888,10 +10045,10 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
9888
10045
|
newThread.resourceId,
|
|
9889
10046
|
newThread.title,
|
|
9890
10047
|
newThread.metadata ? JSON.stringify(newThread.metadata) : null,
|
|
9891
|
-
|
|
9892
|
-
|
|
9893
|
-
|
|
9894
|
-
|
|
10048
|
+
nowStr,
|
|
10049
|
+
nowStr,
|
|
10050
|
+
nowStr,
|
|
10051
|
+
nowStr
|
|
9895
10052
|
]);
|
|
9896
10053
|
const clonedMessages = [];
|
|
9897
10054
|
const messageIdMap = {};
|
|
@@ -9904,13 +10061,14 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
9904
10061
|
try {
|
|
9905
10062
|
parsedContent = JSON.parse(normalizedMsg.content);
|
|
9906
10063
|
} catch {}
|
|
10064
|
+
const createdAt = toUtcISOString(new Date(normalizedMsg.createdAt));
|
|
9907
10065
|
await t.none(`INSERT INTO ${messageTableName} (id, thread_id, content, "createdAt", "createdAtZ", role, type, "resourceId")
|
|
9908
10066
|
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)`, [
|
|
9909
10067
|
newMessageId,
|
|
9910
10068
|
newThreadId,
|
|
9911
10069
|
typeof normalizedMsg.content === "string" ? normalizedMsg.content : JSON.stringify(normalizedMsg.content),
|
|
9912
|
-
|
|
9913
|
-
|
|
10070
|
+
createdAt,
|
|
10071
|
+
createdAt,
|
|
9914
10072
|
normalizedMsg.role,
|
|
9915
10073
|
normalizedMsg.type || "v2",
|
|
9916
10074
|
targetResourceId
|