@mastra/pg 0.16.1 → 0.17.0
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 +34 -0
- package/dist/index.cjs +784 -42
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +785 -43
- package/dist/index.js.map +1 -1
- package/dist/storage/domains/observability/index.d.ts +44 -0
- package/dist/storage/domains/observability/index.d.ts.map +1 -0
- package/dist/storage/domains/operations/index.d.ts +41 -0
- package/dist/storage/domains/operations/index.d.ts.map +1 -1
- package/dist/storage/domains/scores/index.d.ts +8 -0
- package/dist/storage/domains/scores/index.d.ts.map +1 -1
- package/dist/storage/domains/utils.d.ts +19 -0
- package/dist/storage/domains/utils.d.ts.map +1 -1
- package/dist/storage/index.d.ts +42 -5
- package/dist/storage/index.d.ts.map +1 -1
- package/package.json +6 -6
package/dist/index.js
CHANGED
|
@@ -5,9 +5,10 @@ import { Mutex } from 'async-mutex';
|
|
|
5
5
|
import pg from 'pg';
|
|
6
6
|
import xxhash from 'xxhash-wasm';
|
|
7
7
|
import { BaseFilterTranslator } from '@mastra/core/vector/filter';
|
|
8
|
-
import { MastraStorage, StoreOperations, TABLE_WORKFLOW_SNAPSHOT, TABLE_THREADS, TABLE_MESSAGES, TABLE_TRACES, TABLE_EVALS,
|
|
8
|
+
import { MastraStorage, StoreOperations, TABLE_SCHEMAS, TABLE_WORKFLOW_SNAPSHOT, TABLE_AI_SPANS, TABLE_THREADS, TABLE_MESSAGES, TABLE_TRACES, TABLE_EVALS, TABLE_SCORERS, ScoresStorage, TracesStorage, safelyParseJSON, WorkflowsStorage, LegacyEvalsStorage, MemoryStorage, resolveMessageLimit, TABLE_RESOURCES, ObservabilityStorage } from '@mastra/core/storage';
|
|
9
9
|
import pgPromise from 'pg-promise';
|
|
10
10
|
import { MessageList } from '@mastra/core/agent';
|
|
11
|
+
import { saveScorePayloadSchema } from '@mastra/core/scores';
|
|
11
12
|
|
|
12
13
|
// src/vector/index.ts
|
|
13
14
|
var PGFilterTranslator = class extends BaseFilterTranslator {
|
|
@@ -1258,6 +1259,68 @@ function getTableName({ indexName, schemaName }) {
|
|
|
1258
1259
|
const quotedSchemaName = schemaName;
|
|
1259
1260
|
return quotedSchemaName ? `${quotedSchemaName}.${quotedIndexName}` : quotedIndexName;
|
|
1260
1261
|
}
|
|
1262
|
+
function buildDateRangeFilter(dateRange, fieldName) {
|
|
1263
|
+
const filters = {};
|
|
1264
|
+
if (dateRange?.start) {
|
|
1265
|
+
filters[`${fieldName}_gte`] = dateRange.start;
|
|
1266
|
+
}
|
|
1267
|
+
if (dateRange?.end) {
|
|
1268
|
+
filters[`${fieldName}_lte`] = dateRange.end;
|
|
1269
|
+
}
|
|
1270
|
+
return filters;
|
|
1271
|
+
}
|
|
1272
|
+
function prepareWhereClause(filters, _schema) {
|
|
1273
|
+
const conditions = [];
|
|
1274
|
+
const args = [];
|
|
1275
|
+
let paramIndex = 1;
|
|
1276
|
+
Object.entries(filters).forEach(([key, value]) => {
|
|
1277
|
+
if (value === void 0) return;
|
|
1278
|
+
if (key.endsWith("_gte")) {
|
|
1279
|
+
const fieldName = key.slice(0, -4);
|
|
1280
|
+
conditions.push(`"${parseSqlIdentifier(fieldName, "field name")}" >= $${paramIndex++}`);
|
|
1281
|
+
args.push(value instanceof Date ? value.toISOString() : value);
|
|
1282
|
+
} else if (key.endsWith("_lte")) {
|
|
1283
|
+
const fieldName = key.slice(0, -4);
|
|
1284
|
+
conditions.push(`"${parseSqlIdentifier(fieldName, "field name")}" <= $${paramIndex++}`);
|
|
1285
|
+
args.push(value instanceof Date ? value.toISOString() : value);
|
|
1286
|
+
} else if (value === null) {
|
|
1287
|
+
conditions.push(`"${parseSqlIdentifier(key, "field name")}" IS NULL`);
|
|
1288
|
+
} else {
|
|
1289
|
+
conditions.push(`"${parseSqlIdentifier(key, "field name")}" = $${paramIndex++}`);
|
|
1290
|
+
args.push(value instanceof Date ? value.toISOString() : value);
|
|
1291
|
+
}
|
|
1292
|
+
});
|
|
1293
|
+
return {
|
|
1294
|
+
sql: conditions.length > 0 ? ` WHERE ${conditions.join(" AND ")}` : "",
|
|
1295
|
+
args
|
|
1296
|
+
};
|
|
1297
|
+
}
|
|
1298
|
+
function transformFromSqlRow({
|
|
1299
|
+
tableName,
|
|
1300
|
+
sqlRow
|
|
1301
|
+
}) {
|
|
1302
|
+
const schema = TABLE_SCHEMAS[tableName];
|
|
1303
|
+
const result = {};
|
|
1304
|
+
Object.entries(sqlRow).forEach(([key, value]) => {
|
|
1305
|
+
const columnSchema = schema?.[key];
|
|
1306
|
+
if (columnSchema?.type === "jsonb" && typeof value === "string") {
|
|
1307
|
+
try {
|
|
1308
|
+
result[key] = JSON.parse(value);
|
|
1309
|
+
} catch {
|
|
1310
|
+
result[key] = value;
|
|
1311
|
+
}
|
|
1312
|
+
} else if (columnSchema?.type === "timestamp" && value && typeof value === "string") {
|
|
1313
|
+
result[key] = new Date(value);
|
|
1314
|
+
} else if (columnSchema?.type === "timestamp" && value instanceof Date) {
|
|
1315
|
+
result[key] = value;
|
|
1316
|
+
} else if (columnSchema?.type === "boolean") {
|
|
1317
|
+
result[key] = Boolean(value);
|
|
1318
|
+
} else {
|
|
1319
|
+
result[key] = value;
|
|
1320
|
+
}
|
|
1321
|
+
});
|
|
1322
|
+
return result;
|
|
1323
|
+
}
|
|
1261
1324
|
|
|
1262
1325
|
// src/storage/domains/legacy-evals/index.ts
|
|
1263
1326
|
function transformEvalRow(row) {
|
|
@@ -2193,6 +2256,316 @@ var MemoryPG = class extends MemoryStorage {
|
|
|
2193
2256
|
return updatedResource;
|
|
2194
2257
|
}
|
|
2195
2258
|
};
|
|
2259
|
+
var ObservabilityPG = class extends ObservabilityStorage {
|
|
2260
|
+
client;
|
|
2261
|
+
operations;
|
|
2262
|
+
schema;
|
|
2263
|
+
constructor({
|
|
2264
|
+
client,
|
|
2265
|
+
operations,
|
|
2266
|
+
schema
|
|
2267
|
+
}) {
|
|
2268
|
+
super();
|
|
2269
|
+
this.client = client;
|
|
2270
|
+
this.operations = operations;
|
|
2271
|
+
this.schema = schema;
|
|
2272
|
+
}
|
|
2273
|
+
get aiTracingStrategy() {
|
|
2274
|
+
return {
|
|
2275
|
+
preferred: "batch-with-updates",
|
|
2276
|
+
supported: ["batch-with-updates", "insert-only"]
|
|
2277
|
+
};
|
|
2278
|
+
}
|
|
2279
|
+
async createAISpan(span) {
|
|
2280
|
+
try {
|
|
2281
|
+
const startedAt = span.startedAt instanceof Date ? span.startedAt.toISOString() : span.startedAt;
|
|
2282
|
+
const endedAt = span.endedAt instanceof Date ? span.endedAt.toISOString() : span.endedAt;
|
|
2283
|
+
const record = {
|
|
2284
|
+
...span,
|
|
2285
|
+
startedAt,
|
|
2286
|
+
endedAt,
|
|
2287
|
+
startedAtZ: startedAt,
|
|
2288
|
+
endedAtZ: endedAt
|
|
2289
|
+
// Note: createdAt/updatedAt will be set by database triggers
|
|
2290
|
+
};
|
|
2291
|
+
return this.operations.insert({ tableName: TABLE_AI_SPANS, record });
|
|
2292
|
+
} catch (error) {
|
|
2293
|
+
throw new MastraError(
|
|
2294
|
+
{
|
|
2295
|
+
id: "PG_STORE_CREATE_AI_SPAN_FAILED",
|
|
2296
|
+
domain: ErrorDomain.STORAGE,
|
|
2297
|
+
category: ErrorCategory.USER,
|
|
2298
|
+
details: {
|
|
2299
|
+
spanId: span.spanId,
|
|
2300
|
+
traceId: span.traceId,
|
|
2301
|
+
spanType: span.spanType,
|
|
2302
|
+
spanName: span.name
|
|
2303
|
+
}
|
|
2304
|
+
},
|
|
2305
|
+
error
|
|
2306
|
+
);
|
|
2307
|
+
}
|
|
2308
|
+
}
|
|
2309
|
+
async getAITrace(traceId) {
|
|
2310
|
+
try {
|
|
2311
|
+
const tableName = getTableName({
|
|
2312
|
+
indexName: TABLE_AI_SPANS,
|
|
2313
|
+
schemaName: getSchemaName(this.schema)
|
|
2314
|
+
});
|
|
2315
|
+
const spans = await this.client.manyOrNone(
|
|
2316
|
+
`SELECT
|
|
2317
|
+
"traceId", "spanId", "parentSpanId", "name", "scope", "spanType",
|
|
2318
|
+
"attributes", "metadata", "links", "input", "output", "error", "isEvent",
|
|
2319
|
+
"startedAtZ" as "startedAt", "endedAtZ" as "endedAt",
|
|
2320
|
+
"createdAtZ" as "createdAt", "updatedAtZ" as "updatedAt"
|
|
2321
|
+
FROM ${tableName}
|
|
2322
|
+
WHERE "traceId" = $1
|
|
2323
|
+
ORDER BY "startedAtZ" DESC`,
|
|
2324
|
+
[traceId]
|
|
2325
|
+
);
|
|
2326
|
+
if (!spans || spans.length === 0) {
|
|
2327
|
+
return null;
|
|
2328
|
+
}
|
|
2329
|
+
return {
|
|
2330
|
+
traceId,
|
|
2331
|
+
spans: spans.map(
|
|
2332
|
+
(span) => transformFromSqlRow({
|
|
2333
|
+
tableName: TABLE_AI_SPANS,
|
|
2334
|
+
sqlRow: span
|
|
2335
|
+
})
|
|
2336
|
+
)
|
|
2337
|
+
};
|
|
2338
|
+
} catch (error) {
|
|
2339
|
+
throw new MastraError(
|
|
2340
|
+
{
|
|
2341
|
+
id: "PG_STORE_GET_AI_TRACE_FAILED",
|
|
2342
|
+
domain: ErrorDomain.STORAGE,
|
|
2343
|
+
category: ErrorCategory.USER,
|
|
2344
|
+
details: {
|
|
2345
|
+
traceId
|
|
2346
|
+
}
|
|
2347
|
+
},
|
|
2348
|
+
error
|
|
2349
|
+
);
|
|
2350
|
+
}
|
|
2351
|
+
}
|
|
2352
|
+
async updateAISpan({
|
|
2353
|
+
spanId,
|
|
2354
|
+
traceId,
|
|
2355
|
+
updates
|
|
2356
|
+
}) {
|
|
2357
|
+
try {
|
|
2358
|
+
const data = { ...updates };
|
|
2359
|
+
if (data.endedAt instanceof Date) {
|
|
2360
|
+
data.endedAt = data.endedAt.toISOString();
|
|
2361
|
+
}
|
|
2362
|
+
if (data.startedAt instanceof Date) {
|
|
2363
|
+
data.startedAt = data.startedAt.toISOString();
|
|
2364
|
+
}
|
|
2365
|
+
await this.operations.update({
|
|
2366
|
+
tableName: TABLE_AI_SPANS,
|
|
2367
|
+
keys: { spanId, traceId },
|
|
2368
|
+
data
|
|
2369
|
+
});
|
|
2370
|
+
} catch (error) {
|
|
2371
|
+
throw new MastraError(
|
|
2372
|
+
{
|
|
2373
|
+
id: "PG_STORE_UPDATE_AI_SPAN_FAILED",
|
|
2374
|
+
domain: ErrorDomain.STORAGE,
|
|
2375
|
+
category: ErrorCategory.USER,
|
|
2376
|
+
details: {
|
|
2377
|
+
spanId,
|
|
2378
|
+
traceId
|
|
2379
|
+
}
|
|
2380
|
+
},
|
|
2381
|
+
error
|
|
2382
|
+
);
|
|
2383
|
+
}
|
|
2384
|
+
}
|
|
2385
|
+
async getAITracesPaginated({
|
|
2386
|
+
filters,
|
|
2387
|
+
pagination
|
|
2388
|
+
}) {
|
|
2389
|
+
const page = pagination?.page ?? 0;
|
|
2390
|
+
const perPage = pagination?.perPage ?? 10;
|
|
2391
|
+
const { entityId, entityType, ...actualFilters } = filters || {};
|
|
2392
|
+
const filtersWithDateRange = {
|
|
2393
|
+
...actualFilters,
|
|
2394
|
+
...buildDateRangeFilter(pagination?.dateRange, "startedAtZ"),
|
|
2395
|
+
parentSpanId: null
|
|
2396
|
+
// Only get root spans for traces
|
|
2397
|
+
};
|
|
2398
|
+
const whereClause = prepareWhereClause(filtersWithDateRange);
|
|
2399
|
+
let actualWhereClause = whereClause.sql;
|
|
2400
|
+
let currentParamIndex = whereClause.args.length + 1;
|
|
2401
|
+
if (entityId && entityType) {
|
|
2402
|
+
let name = "";
|
|
2403
|
+
if (entityType === "workflow") {
|
|
2404
|
+
name = `workflow run: '${entityId}'`;
|
|
2405
|
+
} else if (entityType === "agent") {
|
|
2406
|
+
name = `agent run: '${entityId}'`;
|
|
2407
|
+
} else {
|
|
2408
|
+
const error = new MastraError({
|
|
2409
|
+
id: "PG_STORE_GET_AI_TRACES_PAGINATED_FAILED",
|
|
2410
|
+
domain: ErrorDomain.STORAGE,
|
|
2411
|
+
category: ErrorCategory.USER,
|
|
2412
|
+
details: {
|
|
2413
|
+
entityType
|
|
2414
|
+
},
|
|
2415
|
+
text: `Cannot filter by entity type: ${entityType}`
|
|
2416
|
+
});
|
|
2417
|
+
this.logger?.trackException(error);
|
|
2418
|
+
throw error;
|
|
2419
|
+
}
|
|
2420
|
+
whereClause.args.push(name);
|
|
2421
|
+
const statement = `"name" = $${currentParamIndex++}`;
|
|
2422
|
+
if (actualWhereClause) {
|
|
2423
|
+
actualWhereClause += ` AND ${statement}`;
|
|
2424
|
+
} else {
|
|
2425
|
+
actualWhereClause = ` WHERE ${statement}`;
|
|
2426
|
+
}
|
|
2427
|
+
}
|
|
2428
|
+
const tableName = getTableName({
|
|
2429
|
+
indexName: TABLE_AI_SPANS,
|
|
2430
|
+
schemaName: getSchemaName(this.schema)
|
|
2431
|
+
});
|
|
2432
|
+
try {
|
|
2433
|
+
const countResult = await this.client.oneOrNone(
|
|
2434
|
+
`SELECT COUNT(*) FROM ${tableName}${actualWhereClause}`,
|
|
2435
|
+
whereClause.args
|
|
2436
|
+
);
|
|
2437
|
+
const count = Number(countResult?.count ?? 0);
|
|
2438
|
+
if (count === 0) {
|
|
2439
|
+
return {
|
|
2440
|
+
pagination: {
|
|
2441
|
+
total: 0,
|
|
2442
|
+
page,
|
|
2443
|
+
perPage,
|
|
2444
|
+
hasMore: false
|
|
2445
|
+
},
|
|
2446
|
+
spans: []
|
|
2447
|
+
};
|
|
2448
|
+
}
|
|
2449
|
+
const spans = await this.client.manyOrNone(
|
|
2450
|
+
`SELECT
|
|
2451
|
+
"traceId", "spanId", "parentSpanId", "name", "scope", "spanType",
|
|
2452
|
+
"attributes", "metadata", "links", "input", "output", "error", "isEvent",
|
|
2453
|
+
"startedAtZ" as "startedAt", "endedAtZ" as "endedAt",
|
|
2454
|
+
"createdAtZ" as "createdAt", "updatedAtZ" as "updatedAt"
|
|
2455
|
+
FROM ${tableName}${actualWhereClause}
|
|
2456
|
+
ORDER BY "startedAtZ" DESC
|
|
2457
|
+
LIMIT $${currentParamIndex} OFFSET $${currentParamIndex + 1}`,
|
|
2458
|
+
[...whereClause.args, perPage, page * perPage]
|
|
2459
|
+
);
|
|
2460
|
+
return {
|
|
2461
|
+
pagination: {
|
|
2462
|
+
total: count,
|
|
2463
|
+
page,
|
|
2464
|
+
perPage,
|
|
2465
|
+
hasMore: spans.length === perPage
|
|
2466
|
+
},
|
|
2467
|
+
spans: spans.map(
|
|
2468
|
+
(span) => transformFromSqlRow({
|
|
2469
|
+
tableName: TABLE_AI_SPANS,
|
|
2470
|
+
sqlRow: span
|
|
2471
|
+
})
|
|
2472
|
+
)
|
|
2473
|
+
};
|
|
2474
|
+
} catch (error) {
|
|
2475
|
+
throw new MastraError(
|
|
2476
|
+
{
|
|
2477
|
+
id: "PG_STORE_GET_AI_TRACES_PAGINATED_FAILED",
|
|
2478
|
+
domain: ErrorDomain.STORAGE,
|
|
2479
|
+
category: ErrorCategory.USER
|
|
2480
|
+
},
|
|
2481
|
+
error
|
|
2482
|
+
);
|
|
2483
|
+
}
|
|
2484
|
+
}
|
|
2485
|
+
async batchCreateAISpans(args) {
|
|
2486
|
+
try {
|
|
2487
|
+
const records = args.records.map((record) => {
|
|
2488
|
+
const startedAt = record.startedAt instanceof Date ? record.startedAt.toISOString() : record.startedAt;
|
|
2489
|
+
const endedAt = record.endedAt instanceof Date ? record.endedAt.toISOString() : record.endedAt;
|
|
2490
|
+
return {
|
|
2491
|
+
...record,
|
|
2492
|
+
startedAt,
|
|
2493
|
+
endedAt,
|
|
2494
|
+
startedAtZ: startedAt,
|
|
2495
|
+
endedAtZ: endedAt
|
|
2496
|
+
// Note: createdAt/updatedAt will be set by database triggers
|
|
2497
|
+
};
|
|
2498
|
+
});
|
|
2499
|
+
return this.operations.batchInsert({
|
|
2500
|
+
tableName: TABLE_AI_SPANS,
|
|
2501
|
+
records
|
|
2502
|
+
});
|
|
2503
|
+
} catch (error) {
|
|
2504
|
+
throw new MastraError(
|
|
2505
|
+
{
|
|
2506
|
+
id: "PG_STORE_BATCH_CREATE_AI_SPANS_FAILED",
|
|
2507
|
+
domain: ErrorDomain.STORAGE,
|
|
2508
|
+
category: ErrorCategory.USER
|
|
2509
|
+
},
|
|
2510
|
+
error
|
|
2511
|
+
);
|
|
2512
|
+
}
|
|
2513
|
+
}
|
|
2514
|
+
async batchUpdateAISpans(args) {
|
|
2515
|
+
try {
|
|
2516
|
+
return this.operations.batchUpdate({
|
|
2517
|
+
tableName: TABLE_AI_SPANS,
|
|
2518
|
+
updates: args.records.map((record) => {
|
|
2519
|
+
const data = {
|
|
2520
|
+
...record.updates
|
|
2521
|
+
};
|
|
2522
|
+
if (data.endedAt instanceof Date) {
|
|
2523
|
+
const endedAt = data.endedAt.toISOString();
|
|
2524
|
+
data.endedAt = endedAt;
|
|
2525
|
+
data.endedAtZ = endedAt;
|
|
2526
|
+
}
|
|
2527
|
+
if (data.startedAt instanceof Date) {
|
|
2528
|
+
const startedAt = data.startedAt.toISOString();
|
|
2529
|
+
data.startedAt = startedAt;
|
|
2530
|
+
data.startedAtZ = startedAt;
|
|
2531
|
+
}
|
|
2532
|
+
return {
|
|
2533
|
+
keys: { spanId: record.spanId, traceId: record.traceId },
|
|
2534
|
+
data
|
|
2535
|
+
};
|
|
2536
|
+
})
|
|
2537
|
+
});
|
|
2538
|
+
} catch (error) {
|
|
2539
|
+
throw new MastraError(
|
|
2540
|
+
{
|
|
2541
|
+
id: "PG_STORE_BATCH_UPDATE_AI_SPANS_FAILED",
|
|
2542
|
+
domain: ErrorDomain.STORAGE,
|
|
2543
|
+
category: ErrorCategory.USER
|
|
2544
|
+
},
|
|
2545
|
+
error
|
|
2546
|
+
);
|
|
2547
|
+
}
|
|
2548
|
+
}
|
|
2549
|
+
async batchDeleteAITraces(args) {
|
|
2550
|
+
try {
|
|
2551
|
+
const tableName = getTableName({
|
|
2552
|
+
indexName: TABLE_AI_SPANS,
|
|
2553
|
+
schemaName: getSchemaName(this.schema)
|
|
2554
|
+
});
|
|
2555
|
+
const placeholders = args.traceIds.map((_, i) => `$${i + 1}`).join(", ");
|
|
2556
|
+
await this.client.none(`DELETE FROM ${tableName} WHERE "traceId" IN (${placeholders})`, args.traceIds);
|
|
2557
|
+
} catch (error) {
|
|
2558
|
+
throw new MastraError(
|
|
2559
|
+
{
|
|
2560
|
+
id: "PG_STORE_BATCH_DELETE_AI_TRACES_FAILED",
|
|
2561
|
+
domain: ErrorDomain.STORAGE,
|
|
2562
|
+
category: ErrorCategory.USER
|
|
2563
|
+
},
|
|
2564
|
+
error
|
|
2565
|
+
);
|
|
2566
|
+
}
|
|
2567
|
+
}
|
|
2568
|
+
};
|
|
2196
2569
|
var StoreOperationsPG = class extends StoreOperations {
|
|
2197
2570
|
client;
|
|
2198
2571
|
schemaName;
|
|
@@ -2211,6 +2584,45 @@ var StoreOperationsPG = class extends StoreOperations {
|
|
|
2211
2584
|
);
|
|
2212
2585
|
return !!result;
|
|
2213
2586
|
}
|
|
2587
|
+
/**
|
|
2588
|
+
* Prepares values for insertion, handling JSONB columns by stringifying them
|
|
2589
|
+
*/
|
|
2590
|
+
prepareValuesForInsert(record, tableName) {
|
|
2591
|
+
return Object.entries(record).map(([key, value]) => {
|
|
2592
|
+
const schema = TABLE_SCHEMAS[tableName];
|
|
2593
|
+
const columnSchema = schema?.[key];
|
|
2594
|
+
if (columnSchema?.type === "jsonb" && value !== null && typeof value === "object") {
|
|
2595
|
+
return JSON.stringify(value);
|
|
2596
|
+
}
|
|
2597
|
+
return value;
|
|
2598
|
+
});
|
|
2599
|
+
}
|
|
2600
|
+
/**
|
|
2601
|
+
* Adds timestamp Z columns to a record if timestamp columns exist
|
|
2602
|
+
*/
|
|
2603
|
+
addTimestampZColumns(record) {
|
|
2604
|
+
if (record.createdAt) {
|
|
2605
|
+
record.createdAtZ = record.createdAt;
|
|
2606
|
+
}
|
|
2607
|
+
if (record.created_at) {
|
|
2608
|
+
record.created_atZ = record.created_at;
|
|
2609
|
+
}
|
|
2610
|
+
if (record.updatedAt) {
|
|
2611
|
+
record.updatedAtZ = record.updatedAt;
|
|
2612
|
+
}
|
|
2613
|
+
}
|
|
2614
|
+
/**
|
|
2615
|
+
* Prepares a value for database operations, handling Date objects and JSON serialization
|
|
2616
|
+
*/
|
|
2617
|
+
prepareValue(value) {
|
|
2618
|
+
if (value instanceof Date) {
|
|
2619
|
+
return value.toISOString();
|
|
2620
|
+
} else if (typeof value === "object" && value !== null) {
|
|
2621
|
+
return JSON.stringify(value);
|
|
2622
|
+
} else {
|
|
2623
|
+
return value;
|
|
2624
|
+
}
|
|
2625
|
+
}
|
|
2214
2626
|
async setupSchema() {
|
|
2215
2627
|
if (!this.schemaName || this.schemaSetupComplete) {
|
|
2216
2628
|
return;
|
|
@@ -2254,18 +2666,10 @@ var StoreOperationsPG = class extends StoreOperations {
|
|
|
2254
2666
|
}
|
|
2255
2667
|
async insert({ tableName, record }) {
|
|
2256
2668
|
try {
|
|
2257
|
-
|
|
2258
|
-
record.createdAtZ = record.createdAt;
|
|
2259
|
-
}
|
|
2260
|
-
if (record.created_at) {
|
|
2261
|
-
record.created_atZ = record.created_at;
|
|
2262
|
-
}
|
|
2263
|
-
if (record.updatedAt) {
|
|
2264
|
-
record.updatedAtZ = record.updatedAt;
|
|
2265
|
-
}
|
|
2669
|
+
this.addTimestampZColumns(record);
|
|
2266
2670
|
const schemaName = getSchemaName(this.schemaName);
|
|
2267
2671
|
const columns = Object.keys(record).map((col) => parseSqlIdentifier(col, "column name"));
|
|
2268
|
-
const values =
|
|
2672
|
+
const values = this.prepareValuesForInsert(record, tableName);
|
|
2269
2673
|
const placeholders = values.map((_, i) => `$${i + 1}`).join(", ");
|
|
2270
2674
|
await this.client.none(
|
|
2271
2675
|
`INSERT INTO ${getTableName({ indexName: tableName, schemaName })} (${columns.map((c) => `"${c}"`).join(", ")}) VALUES (${placeholders})`,
|
|
@@ -2360,6 +2764,9 @@ var StoreOperationsPG = class extends StoreOperations {
|
|
|
2360
2764
|
schema,
|
|
2361
2765
|
ifNotExists: timeZColumnNames
|
|
2362
2766
|
});
|
|
2767
|
+
if (tableName === TABLE_AI_SPANS) {
|
|
2768
|
+
await this.setupTimestampTriggers(tableName);
|
|
2769
|
+
}
|
|
2363
2770
|
} catch (error) {
|
|
2364
2771
|
throw new MastraError(
|
|
2365
2772
|
{
|
|
@@ -2374,6 +2781,48 @@ var StoreOperationsPG = class extends StoreOperations {
|
|
|
2374
2781
|
);
|
|
2375
2782
|
}
|
|
2376
2783
|
}
|
|
2784
|
+
/**
|
|
2785
|
+
* Set up timestamp triggers for a table to automatically manage createdAt/updatedAt
|
|
2786
|
+
*/
|
|
2787
|
+
async setupTimestampTriggers(tableName) {
|
|
2788
|
+
const fullTableName = getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) });
|
|
2789
|
+
try {
|
|
2790
|
+
const triggerSQL = `
|
|
2791
|
+
-- Create or replace the trigger function
|
|
2792
|
+
CREATE OR REPLACE FUNCTION trigger_set_timestamps()
|
|
2793
|
+
RETURNS TRIGGER AS $$
|
|
2794
|
+
BEGIN
|
|
2795
|
+
IF TG_OP = 'INSERT' THEN
|
|
2796
|
+
NEW."createdAt" = NOW();
|
|
2797
|
+
NEW."updatedAt" = NOW();
|
|
2798
|
+
NEW."createdAtZ" = NOW();
|
|
2799
|
+
NEW."updatedAtZ" = NOW();
|
|
2800
|
+
ELSIF TG_OP = 'UPDATE' THEN
|
|
2801
|
+
NEW."updatedAt" = NOW();
|
|
2802
|
+
NEW."updatedAtZ" = NOW();
|
|
2803
|
+
-- Prevent createdAt from being changed
|
|
2804
|
+
NEW."createdAt" = OLD."createdAt";
|
|
2805
|
+
NEW."createdAtZ" = OLD."createdAtZ";
|
|
2806
|
+
END IF;
|
|
2807
|
+
RETURN NEW;
|
|
2808
|
+
END;
|
|
2809
|
+
$$ LANGUAGE plpgsql;
|
|
2810
|
+
|
|
2811
|
+
-- Drop existing trigger if it exists
|
|
2812
|
+
DROP TRIGGER IF EXISTS ${tableName}_timestamps ON ${fullTableName};
|
|
2813
|
+
|
|
2814
|
+
-- Create the trigger
|
|
2815
|
+
CREATE TRIGGER ${tableName}_timestamps
|
|
2816
|
+
BEFORE INSERT OR UPDATE ON ${fullTableName}
|
|
2817
|
+
FOR EACH ROW
|
|
2818
|
+
EXECUTE FUNCTION trigger_set_timestamps();
|
|
2819
|
+
`;
|
|
2820
|
+
await this.client.none(triggerSQL);
|
|
2821
|
+
this.logger?.debug?.(`Set up timestamp triggers for table ${fullTableName}`);
|
|
2822
|
+
} catch (error) {
|
|
2823
|
+
this.logger?.warn?.(`Failed to set up timestamp triggers for ${fullTableName}:`, error);
|
|
2824
|
+
}
|
|
2825
|
+
}
|
|
2377
2826
|
/**
|
|
2378
2827
|
* Alters table schema to add columns if they don't exist
|
|
2379
2828
|
* @param tableName Name of the table
|
|
@@ -2516,8 +2965,8 @@ var StoreOperationsPG = class extends StoreOperations {
|
|
|
2516
2965
|
schemaName: getSchemaName(this.schemaName)
|
|
2517
2966
|
});
|
|
2518
2967
|
const indexExists = await this.client.oneOrNone(
|
|
2519
|
-
`SELECT 1 FROM pg_indexes
|
|
2520
|
-
WHERE indexname = $1
|
|
2968
|
+
`SELECT 1 FROM pg_indexes
|
|
2969
|
+
WHERE indexname = $1
|
|
2521
2970
|
AND schemaname = $2`,
|
|
2522
2971
|
[name, schemaName]
|
|
2523
2972
|
);
|
|
@@ -2574,8 +3023,8 @@ var StoreOperationsPG = class extends StoreOperations {
|
|
|
2574
3023
|
try {
|
|
2575
3024
|
const schemaName = this.schemaName || "public";
|
|
2576
3025
|
const indexExists = await this.client.oneOrNone(
|
|
2577
|
-
`SELECT 1 FROM pg_indexes
|
|
2578
|
-
WHERE indexname = $1
|
|
3026
|
+
`SELECT 1 FROM pg_indexes
|
|
3027
|
+
WHERE indexname = $1
|
|
2579
3028
|
AND schemaname = $2`,
|
|
2580
3029
|
[indexName, schemaName]
|
|
2581
3030
|
);
|
|
@@ -2608,7 +3057,7 @@ var StoreOperationsPG = class extends StoreOperations {
|
|
|
2608
3057
|
let params;
|
|
2609
3058
|
if (tableName) {
|
|
2610
3059
|
query = `
|
|
2611
|
-
SELECT
|
|
3060
|
+
SELECT
|
|
2612
3061
|
i.indexname as name,
|
|
2613
3062
|
i.tablename as table,
|
|
2614
3063
|
i.indexdef as definition,
|
|
@@ -2619,14 +3068,14 @@ var StoreOperationsPG = class extends StoreOperations {
|
|
|
2619
3068
|
JOIN pg_class c ON c.relname = i.indexname AND c.relnamespace = (SELECT oid FROM pg_namespace WHERE nspname = i.schemaname)
|
|
2620
3069
|
JOIN pg_index ix ON ix.indexrelid = c.oid
|
|
2621
3070
|
JOIN pg_attribute a ON a.attrelid = ix.indrelid AND a.attnum = ANY(ix.indkey)
|
|
2622
|
-
WHERE i.schemaname = $1
|
|
3071
|
+
WHERE i.schemaname = $1
|
|
2623
3072
|
AND i.tablename = $2
|
|
2624
3073
|
GROUP BY i.indexname, i.tablename, i.indexdef, ix.indisunique, c.oid
|
|
2625
3074
|
`;
|
|
2626
3075
|
params = [schemaName, tableName];
|
|
2627
3076
|
} else {
|
|
2628
3077
|
query = `
|
|
2629
|
-
SELECT
|
|
3078
|
+
SELECT
|
|
2630
3079
|
i.indexname as name,
|
|
2631
3080
|
i.tablename as table,
|
|
2632
3081
|
i.indexdef as definition,
|
|
@@ -2705,6 +3154,33 @@ var StoreOperationsPG = class extends StoreOperations {
|
|
|
2705
3154
|
name: `${schemaPrefix}mastra_evals_agent_name_created_at_idx`,
|
|
2706
3155
|
table: TABLE_EVALS,
|
|
2707
3156
|
columns: ["agent_name", "created_at DESC"]
|
|
3157
|
+
},
|
|
3158
|
+
// Composite index for scores (filter + sort)
|
|
3159
|
+
{
|
|
3160
|
+
name: `${schemaPrefix}mastra_scores_trace_id_span_id_created_at_idx`,
|
|
3161
|
+
table: TABLE_SCORERS,
|
|
3162
|
+
columns: ["trace_id", "span_id", "created_at DESC"]
|
|
3163
|
+
},
|
|
3164
|
+
// AI Spans indexes for optimal trace querying
|
|
3165
|
+
{
|
|
3166
|
+
name: `${schemaPrefix}mastra_ai_spans_traceid_startedat_idx`,
|
|
3167
|
+
table: TABLE_AI_SPANS,
|
|
3168
|
+
columns: ["traceId", "startedAt DESC"]
|
|
3169
|
+
},
|
|
3170
|
+
{
|
|
3171
|
+
name: `${schemaPrefix}mastra_ai_spans_parentspanid_startedat_idx`,
|
|
3172
|
+
table: TABLE_AI_SPANS,
|
|
3173
|
+
columns: ["parentSpanId", "startedAt DESC"]
|
|
3174
|
+
},
|
|
3175
|
+
{
|
|
3176
|
+
name: `${schemaPrefix}mastra_ai_spans_name_idx`,
|
|
3177
|
+
table: TABLE_AI_SPANS,
|
|
3178
|
+
columns: ["name"]
|
|
3179
|
+
},
|
|
3180
|
+
{
|
|
3181
|
+
name: `${schemaPrefix}mastra_ai_spans_spantype_startedat_idx`,
|
|
3182
|
+
table: TABLE_AI_SPANS,
|
|
3183
|
+
columns: ["spanType", "startedAt DESC"]
|
|
2708
3184
|
}
|
|
2709
3185
|
];
|
|
2710
3186
|
for (const indexOptions of indexes) {
|
|
@@ -2732,7 +3208,7 @@ var StoreOperationsPG = class extends StoreOperations {
|
|
|
2732
3208
|
try {
|
|
2733
3209
|
const schemaName = this.schemaName || "public";
|
|
2734
3210
|
const query = `
|
|
2735
|
-
SELECT
|
|
3211
|
+
SELECT
|
|
2736
3212
|
i.indexname as name,
|
|
2737
3213
|
i.tablename as table,
|
|
2738
3214
|
i.indexdef as definition,
|
|
@@ -2749,7 +3225,7 @@ var StoreOperationsPG = class extends StoreOperations {
|
|
|
2749
3225
|
JOIN pg_attribute a ON a.attrelid = ix.indrelid AND a.attnum = ANY(ix.indkey)
|
|
2750
3226
|
JOIN pg_am am ON c.relam = am.oid
|
|
2751
3227
|
LEFT JOIN pg_stat_user_indexes s ON s.indexrelname = i.indexname AND s.schemaname = i.schemaname
|
|
2752
|
-
WHERE i.schemaname = $1
|
|
3228
|
+
WHERE i.schemaname = $1
|
|
2753
3229
|
AND i.indexname = $2
|
|
2754
3230
|
GROUP BY i.indexname, i.tablename, i.indexdef, ix.indisunique, c.oid, am.amname, s.idx_scan, s.idx_tup_read, s.idx_tup_fetch
|
|
2755
3231
|
`;
|
|
@@ -2790,6 +3266,121 @@ var StoreOperationsPG = class extends StoreOperations {
|
|
|
2790
3266
|
);
|
|
2791
3267
|
}
|
|
2792
3268
|
}
|
|
3269
|
+
/**
|
|
3270
|
+
* Update a single record in the database
|
|
3271
|
+
*/
|
|
3272
|
+
async update({
|
|
3273
|
+
tableName,
|
|
3274
|
+
keys,
|
|
3275
|
+
data
|
|
3276
|
+
}) {
|
|
3277
|
+
try {
|
|
3278
|
+
const setColumns = [];
|
|
3279
|
+
const setValues = [];
|
|
3280
|
+
let paramIndex = 1;
|
|
3281
|
+
Object.entries(data).forEach(([key, value]) => {
|
|
3282
|
+
const parsedKey = parseSqlIdentifier(key, "column name");
|
|
3283
|
+
setColumns.push(`"${parsedKey}" = $${paramIndex++}`);
|
|
3284
|
+
setValues.push(this.prepareValue(value));
|
|
3285
|
+
});
|
|
3286
|
+
const whereConditions = [];
|
|
3287
|
+
const whereValues = [];
|
|
3288
|
+
Object.entries(keys).forEach(([key, value]) => {
|
|
3289
|
+
const parsedKey = parseSqlIdentifier(key, "column name");
|
|
3290
|
+
whereConditions.push(`"${parsedKey}" = $${paramIndex++}`);
|
|
3291
|
+
whereValues.push(this.prepareValue(value));
|
|
3292
|
+
});
|
|
3293
|
+
const tableName_ = getTableName({
|
|
3294
|
+
indexName: tableName,
|
|
3295
|
+
schemaName: getSchemaName(this.schemaName)
|
|
3296
|
+
});
|
|
3297
|
+
const sql = `UPDATE ${tableName_} SET ${setColumns.join(", ")} WHERE ${whereConditions.join(" AND ")}`;
|
|
3298
|
+
const values = [...setValues, ...whereValues];
|
|
3299
|
+
await this.client.none(sql, values);
|
|
3300
|
+
} catch (error) {
|
|
3301
|
+
throw new MastraError(
|
|
3302
|
+
{
|
|
3303
|
+
id: "MASTRA_STORAGE_PG_STORE_UPDATE_FAILED",
|
|
3304
|
+
domain: ErrorDomain.STORAGE,
|
|
3305
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
3306
|
+
details: {
|
|
3307
|
+
tableName
|
|
3308
|
+
}
|
|
3309
|
+
},
|
|
3310
|
+
error
|
|
3311
|
+
);
|
|
3312
|
+
}
|
|
3313
|
+
}
|
|
3314
|
+
/**
|
|
3315
|
+
* Update multiple records in a single batch transaction
|
|
3316
|
+
*/
|
|
3317
|
+
async batchUpdate({
|
|
3318
|
+
tableName,
|
|
3319
|
+
updates
|
|
3320
|
+
}) {
|
|
3321
|
+
try {
|
|
3322
|
+
await this.client.query("BEGIN");
|
|
3323
|
+
for (const { keys, data } of updates) {
|
|
3324
|
+
await this.update({ tableName, keys, data });
|
|
3325
|
+
}
|
|
3326
|
+
await this.client.query("COMMIT");
|
|
3327
|
+
} catch (error) {
|
|
3328
|
+
await this.client.query("ROLLBACK");
|
|
3329
|
+
throw new MastraError(
|
|
3330
|
+
{
|
|
3331
|
+
id: "MASTRA_STORAGE_PG_STORE_BATCH_UPDATE_FAILED",
|
|
3332
|
+
domain: ErrorDomain.STORAGE,
|
|
3333
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
3334
|
+
details: {
|
|
3335
|
+
tableName,
|
|
3336
|
+
numberOfRecords: updates.length
|
|
3337
|
+
}
|
|
3338
|
+
},
|
|
3339
|
+
error
|
|
3340
|
+
);
|
|
3341
|
+
}
|
|
3342
|
+
}
|
|
3343
|
+
/**
|
|
3344
|
+
* Delete multiple records by keys
|
|
3345
|
+
*/
|
|
3346
|
+
async batchDelete({ tableName, keys }) {
|
|
3347
|
+
try {
|
|
3348
|
+
if (keys.length === 0) {
|
|
3349
|
+
return;
|
|
3350
|
+
}
|
|
3351
|
+
const tableName_ = getTableName({
|
|
3352
|
+
indexName: tableName,
|
|
3353
|
+
schemaName: getSchemaName(this.schemaName)
|
|
3354
|
+
});
|
|
3355
|
+
await this.client.tx(async (t) => {
|
|
3356
|
+
for (const keySet of keys) {
|
|
3357
|
+
const conditions = [];
|
|
3358
|
+
const values = [];
|
|
3359
|
+
let paramIndex = 1;
|
|
3360
|
+
Object.entries(keySet).forEach(([key, value]) => {
|
|
3361
|
+
const parsedKey = parseSqlIdentifier(key, "column name");
|
|
3362
|
+
conditions.push(`"${parsedKey}" = $${paramIndex++}`);
|
|
3363
|
+
values.push(value);
|
|
3364
|
+
});
|
|
3365
|
+
const sql = `DELETE FROM ${tableName_} WHERE ${conditions.join(" AND ")}`;
|
|
3366
|
+
await t.none(sql, values);
|
|
3367
|
+
}
|
|
3368
|
+
});
|
|
3369
|
+
} catch (error) {
|
|
3370
|
+
throw new MastraError(
|
|
3371
|
+
{
|
|
3372
|
+
id: "MASTRA_STORAGE_PG_STORE_BATCH_DELETE_FAILED",
|
|
3373
|
+
domain: ErrorDomain.STORAGE,
|
|
3374
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
3375
|
+
details: {
|
|
3376
|
+
tableName,
|
|
3377
|
+
numberOfRecords: keys.length
|
|
3378
|
+
}
|
|
3379
|
+
},
|
|
3380
|
+
error
|
|
3381
|
+
);
|
|
3382
|
+
}
|
|
3383
|
+
}
|
|
2793
3384
|
};
|
|
2794
3385
|
function transformScoreRow(row) {
|
|
2795
3386
|
return {
|
|
@@ -2903,6 +3494,26 @@ var ScoresPG = class extends ScoresStorage {
|
|
|
2903
3494
|
}
|
|
2904
3495
|
}
|
|
2905
3496
|
async saveScore(score) {
|
|
3497
|
+
let parsedScore;
|
|
3498
|
+
try {
|
|
3499
|
+
parsedScore = saveScorePayloadSchema.parse(score);
|
|
3500
|
+
} catch (error) {
|
|
3501
|
+
throw new MastraError(
|
|
3502
|
+
{
|
|
3503
|
+
id: "MASTRA_STORAGE_PG_STORE_SAVE_SCORE_FAILED_INVALID_SCORE_PAYLOAD",
|
|
3504
|
+
domain: ErrorDomain.STORAGE,
|
|
3505
|
+
category: ErrorCategory.USER,
|
|
3506
|
+
details: {
|
|
3507
|
+
scorer: score.scorer.name,
|
|
3508
|
+
entityId: score.entityId,
|
|
3509
|
+
entityType: score.entityType,
|
|
3510
|
+
traceId: score.traceId || "",
|
|
3511
|
+
spanId: score.spanId || ""
|
|
3512
|
+
}
|
|
3513
|
+
},
|
|
3514
|
+
error
|
|
3515
|
+
);
|
|
3516
|
+
}
|
|
2906
3517
|
try {
|
|
2907
3518
|
const id = crypto.randomUUID();
|
|
2908
3519
|
const {
|
|
@@ -2916,7 +3527,7 @@ var ScoresPG = class extends ScoresStorage {
|
|
|
2916
3527
|
runtimeContext,
|
|
2917
3528
|
entity,
|
|
2918
3529
|
...rest
|
|
2919
|
-
} =
|
|
3530
|
+
} = parsedScore;
|
|
2920
3531
|
await this.operations.insert({
|
|
2921
3532
|
tableName: TABLE_SCORERS,
|
|
2922
3533
|
record: {
|
|
@@ -3037,6 +3648,44 @@ var ScoresPG = class extends ScoresStorage {
|
|
|
3037
3648
|
);
|
|
3038
3649
|
}
|
|
3039
3650
|
}
|
|
3651
|
+
async getScoresBySpan({
|
|
3652
|
+
traceId,
|
|
3653
|
+
spanId,
|
|
3654
|
+
pagination
|
|
3655
|
+
}) {
|
|
3656
|
+
try {
|
|
3657
|
+
const tableName = getTableName({ indexName: TABLE_SCORERS, schemaName: this.schema });
|
|
3658
|
+
const countSQLResult = await this.client.oneOrNone(
|
|
3659
|
+
`SELECT COUNT(*) as count FROM ${tableName} WHERE "traceId" = $1 AND "spanId" = $2`,
|
|
3660
|
+
[traceId, spanId]
|
|
3661
|
+
);
|
|
3662
|
+
const total = Number(countSQLResult?.count ?? 0);
|
|
3663
|
+
const result = await this.client.manyOrNone(
|
|
3664
|
+
`SELECT * FROM ${tableName} WHERE "traceId" = $1 AND "spanId" = $2 ORDER BY "createdAt" DESC LIMIT $3 OFFSET $4`,
|
|
3665
|
+
[traceId, spanId, pagination.perPage + 1, pagination.page * pagination.perPage]
|
|
3666
|
+
);
|
|
3667
|
+
const hasMore = result.length > pagination.perPage;
|
|
3668
|
+
const scores = result.slice(0, pagination.perPage).map((row) => transformScoreRow(row)) ?? [];
|
|
3669
|
+
return {
|
|
3670
|
+
scores,
|
|
3671
|
+
pagination: {
|
|
3672
|
+
total,
|
|
3673
|
+
page: pagination.page,
|
|
3674
|
+
perPage: pagination.perPage,
|
|
3675
|
+
hasMore
|
|
3676
|
+
}
|
|
3677
|
+
};
|
|
3678
|
+
} catch (error) {
|
|
3679
|
+
throw new MastraError(
|
|
3680
|
+
{
|
|
3681
|
+
id: "MASTRA_STORAGE_PG_STORE_GET_SCORES_BY_SPAN_FAILED",
|
|
3682
|
+
domain: ErrorDomain.STORAGE,
|
|
3683
|
+
category: ErrorCategory.THIRD_PARTY
|
|
3684
|
+
},
|
|
3685
|
+
error
|
|
3686
|
+
);
|
|
3687
|
+
}
|
|
3688
|
+
}
|
|
3040
3689
|
};
|
|
3041
3690
|
var TracesPG = class extends TracesStorage {
|
|
3042
3691
|
client;
|
|
@@ -3432,7 +4081,8 @@ var PostgresStore = class extends MastraStorage {
|
|
|
3432
4081
|
this.#config = {
|
|
3433
4082
|
connectionString: config.connectionString,
|
|
3434
4083
|
max: config.max,
|
|
3435
|
-
idleTimeoutMillis: config.idleTimeoutMillis
|
|
4084
|
+
idleTimeoutMillis: config.idleTimeoutMillis,
|
|
4085
|
+
ssl: config.ssl
|
|
3436
4086
|
};
|
|
3437
4087
|
} else if (isCloudSqlConfig(config)) {
|
|
3438
4088
|
this.#config = {
|
|
@@ -3452,11 +4102,9 @@ var PostgresStore = class extends MastraStorage {
|
|
|
3452
4102
|
idleTimeoutMillis: config.idleTimeoutMillis
|
|
3453
4103
|
};
|
|
3454
4104
|
} else {
|
|
3455
|
-
|
|
3456
|
-
|
|
3457
|
-
|
|
3458
|
-
idleTimeoutMillis: config.idleTimeoutMillis
|
|
3459
|
-
};
|
|
4105
|
+
throw new Error(
|
|
4106
|
+
"PostgresStore: invalid config. Provide either {connectionString}, {host,port,database,user,password}, or a pg ClientConfig (e.g., Cloud SQL connector with `stream`)."
|
|
4107
|
+
);
|
|
3460
4108
|
}
|
|
3461
4109
|
this.stores = {};
|
|
3462
4110
|
} catch (e) {
|
|
@@ -3484,13 +4132,15 @@ var PostgresStore = class extends MastraStorage {
|
|
|
3484
4132
|
const workflows = new WorkflowsPG({ client: this.#db, operations, schema: this.schema });
|
|
3485
4133
|
const legacyEvals = new LegacyEvalsPG({ client: this.#db, schema: this.schema });
|
|
3486
4134
|
const memory = new MemoryPG({ client: this.#db, schema: this.schema, operations });
|
|
4135
|
+
const observability = new ObservabilityPG({ client: this.#db, operations, schema: this.schema });
|
|
3487
4136
|
this.stores = {
|
|
3488
4137
|
operations,
|
|
3489
4138
|
scores,
|
|
3490
4139
|
traces,
|
|
3491
4140
|
workflows,
|
|
3492
4141
|
legacyEvals,
|
|
3493
|
-
memory
|
|
4142
|
+
memory,
|
|
4143
|
+
observability
|
|
3494
4144
|
};
|
|
3495
4145
|
await super.init();
|
|
3496
4146
|
try {
|
|
@@ -3529,8 +4179,9 @@ var PostgresStore = class extends MastraStorage {
|
|
|
3529
4179
|
hasColumn: true,
|
|
3530
4180
|
createTable: true,
|
|
3531
4181
|
deleteMessages: true,
|
|
3532
|
-
aiTracing:
|
|
3533
|
-
indexManagement: true
|
|
4182
|
+
aiTracing: true,
|
|
4183
|
+
indexManagement: true,
|
|
4184
|
+
getScoresBySpan: true
|
|
3534
4185
|
};
|
|
3535
4186
|
}
|
|
3536
4187
|
/** @deprecated use getEvals instead */
|
|
@@ -3696,11 +4347,95 @@ var PostgresStore = class extends MastraStorage {
|
|
|
3696
4347
|
async close() {
|
|
3697
4348
|
this.pgp.end();
|
|
3698
4349
|
}
|
|
4350
|
+
/**
|
|
4351
|
+
* AI Tracing / Observability
|
|
4352
|
+
*/
|
|
4353
|
+
async createAISpan(span) {
|
|
4354
|
+
if (!this.stores.observability) {
|
|
4355
|
+
throw new MastraError({
|
|
4356
|
+
id: "PG_STORE_OBSERVABILITY_NOT_INITIALIZED",
|
|
4357
|
+
domain: ErrorDomain.STORAGE,
|
|
4358
|
+
category: ErrorCategory.SYSTEM,
|
|
4359
|
+
text: "Observability storage is not initialized"
|
|
4360
|
+
});
|
|
4361
|
+
}
|
|
4362
|
+
return this.stores.observability.createAISpan(span);
|
|
4363
|
+
}
|
|
4364
|
+
async updateAISpan({
|
|
4365
|
+
spanId,
|
|
4366
|
+
traceId,
|
|
4367
|
+
updates
|
|
4368
|
+
}) {
|
|
4369
|
+
if (!this.stores.observability) {
|
|
4370
|
+
throw new MastraError({
|
|
4371
|
+
id: "PG_STORE_OBSERVABILITY_NOT_INITIALIZED",
|
|
4372
|
+
domain: ErrorDomain.STORAGE,
|
|
4373
|
+
category: ErrorCategory.SYSTEM,
|
|
4374
|
+
text: "Observability storage is not initialized"
|
|
4375
|
+
});
|
|
4376
|
+
}
|
|
4377
|
+
return this.stores.observability.updateAISpan({ spanId, traceId, updates });
|
|
4378
|
+
}
|
|
4379
|
+
async getAITrace(traceId) {
|
|
4380
|
+
if (!this.stores.observability) {
|
|
4381
|
+
throw new MastraError({
|
|
4382
|
+
id: "PG_STORE_OBSERVABILITY_NOT_INITIALIZED",
|
|
4383
|
+
domain: ErrorDomain.STORAGE,
|
|
4384
|
+
category: ErrorCategory.SYSTEM,
|
|
4385
|
+
text: "Observability storage is not initialized"
|
|
4386
|
+
});
|
|
4387
|
+
}
|
|
4388
|
+
return this.stores.observability.getAITrace(traceId);
|
|
4389
|
+
}
|
|
4390
|
+
async getAITracesPaginated(args) {
|
|
4391
|
+
if (!this.stores.observability) {
|
|
4392
|
+
throw new MastraError({
|
|
4393
|
+
id: "PG_STORE_OBSERVABILITY_NOT_INITIALIZED",
|
|
4394
|
+
domain: ErrorDomain.STORAGE,
|
|
4395
|
+
category: ErrorCategory.SYSTEM,
|
|
4396
|
+
text: "Observability storage is not initialized"
|
|
4397
|
+
});
|
|
4398
|
+
}
|
|
4399
|
+
return this.stores.observability.getAITracesPaginated(args);
|
|
4400
|
+
}
|
|
4401
|
+
async batchCreateAISpans(args) {
|
|
4402
|
+
if (!this.stores.observability) {
|
|
4403
|
+
throw new MastraError({
|
|
4404
|
+
id: "PG_STORE_OBSERVABILITY_NOT_INITIALIZED",
|
|
4405
|
+
domain: ErrorDomain.STORAGE,
|
|
4406
|
+
category: ErrorCategory.SYSTEM,
|
|
4407
|
+
text: "Observability storage is not initialized"
|
|
4408
|
+
});
|
|
4409
|
+
}
|
|
4410
|
+
return this.stores.observability.batchCreateAISpans(args);
|
|
4411
|
+
}
|
|
4412
|
+
async batchUpdateAISpans(args) {
|
|
4413
|
+
if (!this.stores.observability) {
|
|
4414
|
+
throw new MastraError({
|
|
4415
|
+
id: "PG_STORE_OBSERVABILITY_NOT_INITIALIZED",
|
|
4416
|
+
domain: ErrorDomain.STORAGE,
|
|
4417
|
+
category: ErrorCategory.SYSTEM,
|
|
4418
|
+
text: "Observability storage is not initialized"
|
|
4419
|
+
});
|
|
4420
|
+
}
|
|
4421
|
+
return this.stores.observability.batchUpdateAISpans(args);
|
|
4422
|
+
}
|
|
4423
|
+
async batchDeleteAITraces(args) {
|
|
4424
|
+
if (!this.stores.observability) {
|
|
4425
|
+
throw new MastraError({
|
|
4426
|
+
id: "PG_STORE_OBSERVABILITY_NOT_INITIALIZED",
|
|
4427
|
+
domain: ErrorDomain.STORAGE,
|
|
4428
|
+
category: ErrorCategory.SYSTEM,
|
|
4429
|
+
text: "Observability storage is not initialized"
|
|
4430
|
+
});
|
|
4431
|
+
}
|
|
4432
|
+
return this.stores.observability.batchDeleteAITraces(args);
|
|
4433
|
+
}
|
|
3699
4434
|
/**
|
|
3700
4435
|
* Scorers
|
|
3701
4436
|
*/
|
|
3702
|
-
async getScoreById({ id
|
|
3703
|
-
return this.stores.scores.getScoreById({ id
|
|
4437
|
+
async getScoreById({ id }) {
|
|
4438
|
+
return this.stores.scores.getScoreById({ id });
|
|
3704
4439
|
}
|
|
3705
4440
|
async getScoresByScorerId({
|
|
3706
4441
|
scorerId,
|
|
@@ -3711,26 +4446,33 @@ var PostgresStore = class extends MastraStorage {
|
|
|
3711
4446
|
}) {
|
|
3712
4447
|
return this.stores.scores.getScoresByScorerId({ scorerId, pagination, entityId, entityType, source });
|
|
3713
4448
|
}
|
|
3714
|
-
async saveScore(
|
|
3715
|
-
return this.stores.scores.saveScore(
|
|
4449
|
+
async saveScore(score) {
|
|
4450
|
+
return this.stores.scores.saveScore(score);
|
|
3716
4451
|
}
|
|
3717
4452
|
async getScoresByRunId({
|
|
3718
|
-
runId
|
|
3719
|
-
pagination
|
|
4453
|
+
runId,
|
|
4454
|
+
pagination
|
|
3720
4455
|
}) {
|
|
3721
|
-
return this.stores.scores.getScoresByRunId({ runId
|
|
4456
|
+
return this.stores.scores.getScoresByRunId({ runId, pagination });
|
|
3722
4457
|
}
|
|
3723
4458
|
async getScoresByEntityId({
|
|
3724
|
-
entityId
|
|
3725
|
-
entityType
|
|
3726
|
-
pagination
|
|
4459
|
+
entityId,
|
|
4460
|
+
entityType,
|
|
4461
|
+
pagination
|
|
3727
4462
|
}) {
|
|
3728
4463
|
return this.stores.scores.getScoresByEntityId({
|
|
3729
|
-
entityId
|
|
3730
|
-
entityType
|
|
3731
|
-
pagination
|
|
4464
|
+
entityId,
|
|
4465
|
+
entityType,
|
|
4466
|
+
pagination
|
|
3732
4467
|
});
|
|
3733
4468
|
}
|
|
4469
|
+
async getScoresBySpan({
|
|
4470
|
+
traceId,
|
|
4471
|
+
spanId,
|
|
4472
|
+
pagination
|
|
4473
|
+
}) {
|
|
4474
|
+
return this.stores.scores.getScoresBySpan({ traceId, spanId, pagination });
|
|
4475
|
+
}
|
|
3734
4476
|
};
|
|
3735
4477
|
|
|
3736
4478
|
// src/vector/prompt.ts
|