@mastra/pg 1.32.0-alpha.1 → 1.32.0-alpha.3
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/dist/docs/SKILL.md +1 -1
- package/dist/docs/assets/SOURCE_MAP.json +1 -1
- package/dist/docs/references/docs-memory-semantic-recall.md +2 -0
- package/dist/index.cjs +286 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +286 -8
- package/dist/index.js.map +1 -1
- package/dist/storage/domains/memory/index.d.ts +1 -1
- package/dist/storage/domains/memory/index.d.ts.map +1 -1
- package/dist/storage/domains/observability/v-next/ddl.d.ts.map +1 -1
- package/dist/storage/domains/observability/v-next/helpers.d.ts.map +1 -1
- package/dist/storage/domains/observability/v-next/index.d.ts +4 -1
- package/dist/storage/domains/observability/v-next/index.d.ts.map +1 -1
- package/dist/storage/domains/observability/v-next/preview-compat.d.ts +1 -0
- package/dist/storage/domains/observability/v-next/preview-compat.d.ts.map +1 -1
- package/dist/storage/domains/observability/v-next/signal-schema.d.ts +4 -0
- package/dist/storage/domains/observability/v-next/signal-schema.d.ts.map +1 -1
- package/dist/storage/domains/observability/v-next/span-query.d.ts +1 -0
- package/dist/storage/domains/observability/v-next/span-query.d.ts.map +1 -1
- package/dist/storage/domains/observability/v-next/thread-query.d.ts +49 -0
- package/dist/storage/domains/observability/v-next/thread-query.d.ts.map +1 -0
- package/dist/storage/domains/observability/v-next/trace-aggregate.d.ts.map +1 -1
- package/dist/storage/domains/observability/v-next/trace-query.d.ts +4 -0
- package/dist/storage/domains/observability/v-next/trace-query.d.ts.map +1 -1
- package/dist/storage/domains/skills/index.d.ts.map +1 -1
- package/package.json +9 -10
package/dist/index.js
CHANGED
|
@@ -16010,6 +16010,11 @@ const SPAN_EVENT_COLUMNS = [
|
|
|
16010
16010
|
name: "endedAt",
|
|
16011
16011
|
type: "timestamptz"
|
|
16012
16012
|
},
|
|
16013
|
+
{
|
|
16014
|
+
name: "timeToFirstChunkMs",
|
|
16015
|
+
type: "double precision",
|
|
16016
|
+
nullable: true
|
|
16017
|
+
},
|
|
16013
16018
|
{
|
|
16014
16019
|
name: "tags",
|
|
16015
16020
|
type: "text[]",
|
|
@@ -16744,6 +16749,11 @@ function additiveColumns(schema) {
|
|
|
16744
16749
|
column,
|
|
16745
16750
|
ddl: `ALTER TABLE ${qualifiedTable(schema, TABLE_SPAN_EVENTS)} ADD COLUMN IF NOT EXISTS "${column}" text`
|
|
16746
16751
|
})),
|
|
16752
|
+
{
|
|
16753
|
+
table: TABLE_SPAN_EVENTS,
|
|
16754
|
+
column: "timeToFirstChunkMs",
|
|
16755
|
+
ddl: `ALTER TABLE ${qualifiedTable(schema, TABLE_SPAN_EVENTS)} ADD COLUMN IF NOT EXISTS "timeToFirstChunkMs" double precision`
|
|
16756
|
+
},
|
|
16747
16757
|
{
|
|
16748
16758
|
table: TABLE_FEEDBACK_EVENTS,
|
|
16749
16759
|
column: "reviewStatus",
|
|
@@ -17465,6 +17475,7 @@ function spanRecordToRow(span) {
|
|
|
17465
17475
|
isPending,
|
|
17466
17476
|
startedAt: toIsoOrDate(span.startedAt),
|
|
17467
17477
|
endedAt: toIsoOrDate(endedAt),
|
|
17478
|
+
timeToFirstChunkMs: span.timeToFirstChunkMs ?? null,
|
|
17468
17479
|
tags: normalizeTags(span.tags),
|
|
17469
17480
|
metadataSearch: buildMetadataSearch(metadata),
|
|
17470
17481
|
metadataRaw: jsonField(metadata),
|
|
@@ -19174,6 +19185,9 @@ async function getScorePercentiles(client, schema, args) {
|
|
|
19174
19185
|
//#endregion
|
|
19175
19186
|
//#region src/storage/domains/observability/v-next/trace-query.ts
|
|
19176
19187
|
const TRACE_STATUS_SQL = `CASE WHEN r."error" IS NOT NULL THEN 'error' ELSE 'success' END`;
|
|
19188
|
+
/** Core versions without the field reject it in strict query results, so it is only returned when core knows it. */
|
|
19189
|
+
const timeToFirstChunkSupported = "timeToFirstChunkMs" in coreStorage.TRACE_QUERY_FIELD_REGISTRY.trace;
|
|
19190
|
+
const timeToFirstChunkFeatures = timeToFirstChunkSupported ? ["trace-query-time-to-first-chunk"] : [];
|
|
19177
19191
|
function durationMsSql(startedAt, endedAt) {
|
|
19178
19192
|
return `EXTRACT(EPOCH FROM (${endedAt} - ${startedAt}))::numeric * 1000`;
|
|
19179
19193
|
}
|
|
@@ -19188,8 +19202,11 @@ const TRACE_FIELDS = {
|
|
|
19188
19202
|
startedAt: "r.\"startedAt\"",
|
|
19189
19203
|
endedAt: "r.\"endedAt\"",
|
|
19190
19204
|
durationMs: durationMsSql("r.\"startedAt\"", "r.\"endedAt\""),
|
|
19205
|
+
timeToFirstChunkMs: "r.\"timeToFirstChunkMs\"",
|
|
19191
19206
|
entityName: "r.\"entityName\"",
|
|
19192
19207
|
entityType: "r.\"entityType\"",
|
|
19208
|
+
name: "r.\"name\"",
|
|
19209
|
+
spanType: "r.\"spanType\"",
|
|
19193
19210
|
environment: "r.\"environment\"",
|
|
19194
19211
|
status: TRACE_STATUS_SQL,
|
|
19195
19212
|
tags: "r.\"tags\""
|
|
@@ -19202,6 +19219,7 @@ const SPAN_FIELDS = {
|
|
|
19202
19219
|
startedAt: "s.\"startedAt\"",
|
|
19203
19220
|
endedAt: "s.\"endedAt\"",
|
|
19204
19221
|
durationMs: "s.\"durationMs\"",
|
|
19222
|
+
timeToFirstChunkMs: "s.\"timeToFirstChunkMs\"",
|
|
19205
19223
|
status: "s.\"status\"",
|
|
19206
19224
|
error: "s.\"error\"",
|
|
19207
19225
|
entityType: "s.\"entityType\"",
|
|
@@ -19271,6 +19289,7 @@ const TRACE_SELECT = `
|
|
|
19271
19289
|
r."resourceId" AS "resourceId",
|
|
19272
19290
|
r."startedAt" AS "startedAt",
|
|
19273
19291
|
r."endedAt" AS "endedAt",
|
|
19292
|
+
r."timeToFirstChunkMs" AS "timeToFirstChunkMs",
|
|
19274
19293
|
r."entityName" AS "entityName",
|
|
19275
19294
|
r."entityType" AS "entityType",
|
|
19276
19295
|
r."environment" AS "environment",
|
|
@@ -19394,11 +19413,11 @@ function compileScalarPredicate(predicate, registry, parameterOffset, allowMetad
|
|
|
19394
19413
|
gte: ">="
|
|
19395
19414
|
};
|
|
19396
19415
|
if (predicate.operator === "eq") return {
|
|
19397
|
-
sql: `${field} IS NOT
|
|
19416
|
+
sql: `${field} IS NOT NULL AND ${field} = ${parameter}`,
|
|
19398
19417
|
values: [...fieldValues, predicate.value]
|
|
19399
19418
|
};
|
|
19400
19419
|
if (predicate.operator === "ne") return {
|
|
19401
|
-
sql: `${field} IS
|
|
19420
|
+
sql: `${field} IS NULL OR ${field} <> ${parameter}`,
|
|
19402
19421
|
values: [...fieldValues, predicate.value]
|
|
19403
19422
|
};
|
|
19404
19423
|
const operator = operators[predicate.operator];
|
|
@@ -19487,6 +19506,8 @@ const ROOT_PUSHDOWN_FIELDS = /* @__PURE__ */ new Set([
|
|
|
19487
19506
|
"endedAt",
|
|
19488
19507
|
"entityName",
|
|
19489
19508
|
"entityType",
|
|
19509
|
+
"name",
|
|
19510
|
+
"spanType",
|
|
19490
19511
|
"environment"
|
|
19491
19512
|
]);
|
|
19492
19513
|
function isRootPushdownPredicate(predicate) {
|
|
@@ -19636,6 +19657,7 @@ function compilePostgresTraceScope(schema, selection, relationCollections, scope
|
|
|
19636
19657
|
WHEN s."isPending" THEN NULL
|
|
19637
19658
|
ELSE ${durationMsSql("s.\"startedAt\"", "s.\"endedAt\"")}
|
|
19638
19659
|
END AS "durationMs",
|
|
19660
|
+
s."timeToFirstChunkMs",
|
|
19639
19661
|
CASE WHEN s."error" IS NOT NULL THEN 'error' ELSE 'success' END AS "status",
|
|
19640
19662
|
s."error",
|
|
19641
19663
|
s."entityType",
|
|
@@ -20010,6 +20032,7 @@ function traceRowToResult(row) {
|
|
|
20010
20032
|
resourceId: row.resourceId == null ? null : String(row.resourceId),
|
|
20011
20033
|
startedAt: asIsoTimestamp$1(row.startedAt),
|
|
20012
20034
|
endedAt: asIsoTimestamp$1(row.endedAt),
|
|
20035
|
+
...timeToFirstChunkSupported && { timeToFirstChunkMs: row.timeToFirstChunkMs == null ? null : Number(row.timeToFirstChunkMs) },
|
|
20013
20036
|
entityName: row.entityName == null ? null : String(row.entityName),
|
|
20014
20037
|
entityType: row.entityType == null ? null : String(row.entityType),
|
|
20015
20038
|
environment: row.environment == null ? null : String(row.environment),
|
|
@@ -20129,6 +20152,9 @@ async function queryThreads(client, schema, plan, timeoutMs) {
|
|
|
20129
20152
|
function compileSpanQueryPredicate(predicate, offset) {
|
|
20130
20153
|
return compileScalarPredicate(predicate, SPAN_QUERY_FIELDS, offset);
|
|
20131
20154
|
}
|
|
20155
|
+
function compileThreadQueryPredicate(predicate, offset) {
|
|
20156
|
+
return compileScalarPredicate(predicate, Object.fromEntries(Object.keys(coreStorage.THREAD_QUERY_FIELD_REGISTRY).map((field) => [field, `s."${field}"`])), offset);
|
|
20157
|
+
}
|
|
20132
20158
|
//#endregion
|
|
20133
20159
|
//#region src/storage/domains/observability/v-next/span-query.ts
|
|
20134
20160
|
const identityFields = [
|
|
@@ -20162,7 +20188,8 @@ const fields = [
|
|
|
20162
20188
|
"serviceName",
|
|
20163
20189
|
"experimentId",
|
|
20164
20190
|
"environment",
|
|
20165
|
-
"executionSource"
|
|
20191
|
+
"executionSource",
|
|
20192
|
+
"timeToFirstChunkMs"
|
|
20166
20193
|
];
|
|
20167
20194
|
const identities = identityFields.map((field) => `"${field}"`).join(", ");
|
|
20168
20195
|
const identityOrder = identityFields.map((field) => `"${field}" COLLATE "C" ASC NULLS LAST`).join(", ");
|
|
@@ -20278,8 +20305,9 @@ async function querySpans(client, schema, plan, timeoutMs) {
|
|
|
20278
20305
|
return runWithPostgresTraceQueryTimeout(client, timeoutMs, async (tx) => {
|
|
20279
20306
|
const query = compilePostgresSpanQuery(schema, plan);
|
|
20280
20307
|
const rows = await tx.any(query.text, query.values);
|
|
20281
|
-
const selected = rows.map(({ version: _version, startedAt, endedAt, ...row }) => ({
|
|
20308
|
+
const selected = rows.map(({ version: _version, startedAt, endedAt, timeToFirstChunkMs, ...row }) => ({
|
|
20282
20309
|
...row,
|
|
20310
|
+
...timeToFirstChunkSupported && { timeToFirstChunkMs },
|
|
20283
20311
|
startedAt: startedAt.toISOString(),
|
|
20284
20312
|
endedAt: endedAt.toISOString()
|
|
20285
20313
|
}));
|
|
@@ -20326,11 +20354,245 @@ async function querySpans(client, schema, plan, timeoutMs) {
|
|
|
20326
20354
|
}, { repeatableRead: true });
|
|
20327
20355
|
}
|
|
20328
20356
|
//#endregion
|
|
20357
|
+
//#region src/storage/domains/observability/v-next/thread-query.ts
|
|
20358
|
+
const contextFields = [
|
|
20359
|
+
"resourceId",
|
|
20360
|
+
"userId",
|
|
20361
|
+
"entityType",
|
|
20362
|
+
"entityId",
|
|
20363
|
+
"entityName",
|
|
20364
|
+
"entityVersionId",
|
|
20365
|
+
"runId",
|
|
20366
|
+
"sessionId",
|
|
20367
|
+
"requestId",
|
|
20368
|
+
"serviceName",
|
|
20369
|
+
"experimentId",
|
|
20370
|
+
"environment",
|
|
20371
|
+
"executionSource"
|
|
20372
|
+
];
|
|
20373
|
+
function predicateFields(predicate, fields = /* @__PURE__ */ new Set()) {
|
|
20374
|
+
if (!predicate) return fields;
|
|
20375
|
+
if (predicate.type === "boolean") for (const arg of predicate.args) predicateFields(arg, fields);
|
|
20376
|
+
else if (predicate.type === "not") predicateFields(predicate.arg, fields);
|
|
20377
|
+
else fields.add(predicate.field);
|
|
20378
|
+
return fields;
|
|
20379
|
+
}
|
|
20380
|
+
function canUseThreadCandidates(probe) {
|
|
20381
|
+
return Number(probe.threadCount) <= 16384 && Number(probe.traceCount) <= 1e5 && Number(probe.threadBytes) + Number(probe.traceBytes) <= 4 * 1024 * 1024;
|
|
20382
|
+
}
|
|
20383
|
+
function compilePostgresThreadRowsQuery(schema, plan, strategy = "full") {
|
|
20384
|
+
const values = [plan.timeRange.from, plan.timeRange.to];
|
|
20385
|
+
const scope = [];
|
|
20386
|
+
if (plan.scope) {
|
|
20387
|
+
values.push(plan.scope.organizationId);
|
|
20388
|
+
scope.push(`"organizationId" = $${values.length}`);
|
|
20389
|
+
if (plan.scope.resourceId !== void 0) {
|
|
20390
|
+
values.push(plan.scope.resourceId);
|
|
20391
|
+
scope.push(`"resourceId" = $${values.length}`);
|
|
20392
|
+
}
|
|
20393
|
+
}
|
|
20394
|
+
const table = qualifiedTable(schema, TABLE_SPAN_EVENTS);
|
|
20395
|
+
const timestamp = plan.timeRange.mode === "threads" ? plan.timeRange.field : "startedAt";
|
|
20396
|
+
const identity = (field) => `"organizationId" IS NULL, COALESCE("organizationId", ''), "${field}"`;
|
|
20397
|
+
const threadFilter = `(${identity("threadId")}) IN (SELECT ${identity("threadId")} FROM candidate_threads)`;
|
|
20398
|
+
const scopedRoots = `scoped_roots AS NOT MATERIALIZED (
|
|
20399
|
+
SELECT * FROM ${table} WHERE "parentSpanId" IS NULL ${scope.length ? `AND ${scope.join(" AND ")}` : ""}
|
|
20400
|
+
)`;
|
|
20401
|
+
const candidates = `candidate_threads AS MATERIALIZED (
|
|
20402
|
+
SELECT DISTINCT "organizationId", "threadId" FROM scoped_roots
|
|
20403
|
+
WHERE "threadId" IS NOT NULL AND "${timestamp}" >= $1 AND "${timestamp}" < $2
|
|
20404
|
+
${strategy === "probe" ? "LIMIT 16385" : ""}
|
|
20405
|
+
), candidate_traces AS MATERIALIZED (
|
|
20406
|
+
SELECT DISTINCT "organizationId", "traceId" FROM scoped_roots WHERE ${threadFilter}
|
|
20407
|
+
${strategy === "probe" ? "LIMIT 100001" : ""}
|
|
20408
|
+
)`;
|
|
20409
|
+
if (strategy === "probe") return {
|
|
20410
|
+
text: `WITH ${scopedRoots}, ${candidates}
|
|
20411
|
+
SELECT (SELECT count(*) FROM candidate_threads) AS "threadCount",
|
|
20412
|
+
(SELECT COALESCE(sum(octet_length(COALESCE("organizationId", '')) + octet_length("threadId")), 0) FROM candidate_threads) AS "threadBytes",
|
|
20413
|
+
count(*) AS "traceCount", COALESCE(sum(octet_length(COALESCE("organizationId", '')) + octet_length("traceId")), 0) AS "traceBytes"
|
|
20414
|
+
FROM candidate_traces`,
|
|
20415
|
+
values
|
|
20416
|
+
};
|
|
20417
|
+
const predicate = plan.where ? compileThreadQueryPredicate(plan.where, values.length + 1) : {
|
|
20418
|
+
sql: "TRUE",
|
|
20419
|
+
values: []
|
|
20420
|
+
};
|
|
20421
|
+
values.push(...predicate.values);
|
|
20422
|
+
let after = "TRUE";
|
|
20423
|
+
if (plan.cursor) {
|
|
20424
|
+
values.push(plan.cursor.sortValue);
|
|
20425
|
+
const stamp = `$${values.length}::timestamptz`;
|
|
20426
|
+
const field = `s."${plan.orderBy.field}"`;
|
|
20427
|
+
const terms = [`${field} ${plan.orderBy.direction === "asc" ? ">" : "<"} ${stamp}`];
|
|
20428
|
+
const equal = [`${field} = ${stamp}`];
|
|
20429
|
+
for (const key of ["organizationId", "threadId"]) {
|
|
20430
|
+
const ref = `s."${key}" COLLATE "C"`;
|
|
20431
|
+
if (plan.cursor[key] === null) equal.push(`${ref} IS NULL`);
|
|
20432
|
+
else {
|
|
20433
|
+
values.push(plan.cursor[key]);
|
|
20434
|
+
const value = `$${values.length}::text COLLATE "C"`;
|
|
20435
|
+
terms.push(`(${equal.join(" AND ")} AND (${ref} > ${value} OR ${ref} IS NULL))`);
|
|
20436
|
+
equal.push(`${ref} = ${value}`);
|
|
20437
|
+
}
|
|
20438
|
+
}
|
|
20439
|
+
after = `(${terms.join(" OR ")})`;
|
|
20440
|
+
}
|
|
20441
|
+
const qualify = plan.timeRange.mode === "traces" ? "s.\"inWindow\"" : `s."${plan.timeRange.field}" >= $1 AND s."${plan.timeRange.field}" < $2`;
|
|
20442
|
+
const filtered = predicateFields(plan.where);
|
|
20443
|
+
const firstContext = [...contextFields, "timeToFirstChunkMs"].filter((field) => field === "resourceId" || filtered.has(field));
|
|
20444
|
+
const lastFields = [
|
|
20445
|
+
"traceId",
|
|
20446
|
+
"spanId",
|
|
20447
|
+
"cursorId",
|
|
20448
|
+
"resourceId",
|
|
20449
|
+
"endedAt",
|
|
20450
|
+
...filtered.has("status") ? ["status"] : []
|
|
20451
|
+
];
|
|
20452
|
+
values.push(plan.limit + 1);
|
|
20453
|
+
return {
|
|
20454
|
+
text: `WITH ${scopedRoots}, ${strategy === "candidates" ? `${candidates}, ` : ""}current_roots AS (
|
|
20455
|
+
SELECT DISTINCT ON ("organizationId", "traceId")
|
|
20456
|
+
"organizationId", "threadId", "traceId", "spanId", "cursorId", "startedAt", "endedAt", "isPending",
|
|
20457
|
+
${firstContext.map((field) => field === "timeToFirstChunkMs" ? `CASE WHEN "spanType" = 'agent_run' THEN "timeToFirstChunkMs" END AS "timeToFirstChunkMs"` : `"${field}"`).join(", ")}
|
|
20458
|
+
${filtered.has("status") ? ", CASE WHEN error IS NULL THEN 'success' ELSE 'error' END AS status" : ""}
|
|
20459
|
+
FROM scoped_roots ${strategy === "candidates" ? `WHERE (${identity("traceId")}) IN (SELECT ${identity("traceId")} FROM candidate_traces)` : ""}
|
|
20460
|
+
ORDER BY "organizationId", "traceId", "startedAt" ASC, "spanId" COLLATE "C", "cursorId" DESC
|
|
20461
|
+
), ranked AS (
|
|
20462
|
+
SELECT *, row_number() OVER first_order AS rank,
|
|
20463
|
+
max("endedAt") OVER population AS "lastActivity", count(*) OVER population AS "traceCount",
|
|
20464
|
+
bool_or("startedAt" >= $1 AND "startedAt" < $2) OVER population AS "inWindow",
|
|
20465
|
+
${lastFields.map((field) => `first_value("${field}") OVER last_order AS "last${field[0].toUpperCase()}${field.slice(1)}"`).join(", ")}
|
|
20466
|
+
FROM current_roots WHERE NOT "isPending" AND "endedAt" IS NOT NULL AND "threadId" IS NOT NULL ${strategy === "candidates" ? `AND ${threadFilter}` : ""}
|
|
20467
|
+
WINDOW population AS (PARTITION BY "organizationId", "threadId"),
|
|
20468
|
+
first_order AS (PARTITION BY "organizationId", "threadId" ORDER BY "startedAt", "traceId" COLLATE "C"),
|
|
20469
|
+
last_order AS (PARTITION BY "organizationId", "threadId" ORDER BY "startedAt" DESC, "traceId" COLLATE "C" DESC)
|
|
20470
|
+
), rows AS (
|
|
20471
|
+
SELECT "organizationId", "threadId", "traceId" AS "firstTraceId", "spanId" AS "firstSpanId", "cursorId" AS "firstCursorId",
|
|
20472
|
+
"endedAt" AS "firstEndedAt", "startedAt", "lastActivity" AS "endedAt", "traceCount", "inWindow",
|
|
20473
|
+
${firstContext.map((field) => `"${field}"`).join(", ")},
|
|
20474
|
+
${lastFields.map((field) => `"last${field[0].toUpperCase()}${field.slice(1)}"${field === "status" ? " AS status" : ""}`).join(", ")}
|
|
20475
|
+
FROM ranked WHERE rank = 1
|
|
20476
|
+
) SELECT * FROM rows s WHERE ${qualify} AND (${predicate.sql}) AND ${after}
|
|
20477
|
+
ORDER BY s."${plan.orderBy.field}" ${plan.orderBy.direction === "asc" ? "ASC" : "DESC"},
|
|
20478
|
+
s."organizationId" COLLATE "C" ASC NULLS LAST, s."threadId" COLLATE "C" ASC LIMIT $${values.length}`,
|
|
20479
|
+
values
|
|
20480
|
+
};
|
|
20481
|
+
}
|
|
20482
|
+
async function queryThreadRows(client, schema, plan, timeoutMs, strategy = "auto") {
|
|
20483
|
+
const deadline = performance.now() + coreStorage.resolveTraceQueryTimeoutMs(timeoutMs);
|
|
20484
|
+
const run = async (text, values) => {
|
|
20485
|
+
const remaining = Math.floor(deadline - performance.now());
|
|
20486
|
+
if (remaining <= 0) throw new coreStorage.TraceQueryExecutionError();
|
|
20487
|
+
return await runWithPostgresTraceQueryTimeout(client, remaining, (tx) => tx.any(text, values));
|
|
20488
|
+
};
|
|
20489
|
+
if (strategy === "auto") {
|
|
20490
|
+
const probeQuery = compilePostgresThreadRowsQuery(schema, plan, "probe");
|
|
20491
|
+
const [probe] = await run(probeQuery.text, probeQuery.values);
|
|
20492
|
+
if (Number(probe.threadCount) === 0) return {
|
|
20493
|
+
threads: [],
|
|
20494
|
+
page: { next: null }
|
|
20495
|
+
};
|
|
20496
|
+
strategy = canUseThreadCandidates(probe) ? "candidates" : "full";
|
|
20497
|
+
}
|
|
20498
|
+
const compiled = compilePostgresThreadRowsQuery(schema, plan, strategy);
|
|
20499
|
+
const selected = await run(compiled.text, compiled.values);
|
|
20500
|
+
const page = selected.slice(0, plan.limit);
|
|
20501
|
+
if (!page.length) return {
|
|
20502
|
+
threads: [],
|
|
20503
|
+
page: { next: null }
|
|
20504
|
+
};
|
|
20505
|
+
const table = qualifiedTable(schema, TABLE_SPAN_EVENTS);
|
|
20506
|
+
const values = [];
|
|
20507
|
+
const keys = page.flatMap((row) => ["first", "last"].map((which) => {
|
|
20508
|
+
const entries = {
|
|
20509
|
+
organizationId: row.organizationId,
|
|
20510
|
+
resourceId: which === "first" ? row.resourceId : row.lastResourceId,
|
|
20511
|
+
traceId: row[`${which}TraceId`],
|
|
20512
|
+
spanId: row[`${which}SpanId`],
|
|
20513
|
+
cursorId: row[`${which}CursorId`],
|
|
20514
|
+
endedAt: row[`${which}EndedAt`]
|
|
20515
|
+
};
|
|
20516
|
+
return `(${Object.entries(entries).map(([field, value]) => {
|
|
20517
|
+
values.push(value);
|
|
20518
|
+
return `"${field}" ${field === "organizationId" || field === "resourceId" ? "IS NOT DISTINCT FROM" : "="} $${values.length}`;
|
|
20519
|
+
}).join(" AND ")})`;
|
|
20520
|
+
}));
|
|
20521
|
+
const payloads = await run(`SELECT "organizationId", "traceId", "cursorId", "spanType", ${contextFields.map((field) => `"${field}"`).join(", ")},
|
|
20522
|
+
CASE WHEN "spanType" = 'agent_run' THEN "timeToFirstChunkMs" END AS "timeToFirstChunkMs",
|
|
20523
|
+
CASE WHEN error IS NULL THEN 'success' ELSE 'error' END AS status,
|
|
20524
|
+
${[
|
|
20525
|
+
"input",
|
|
20526
|
+
"output",
|
|
20527
|
+
"error"
|
|
20528
|
+
].map((field) => `"${field}Preview", CASE WHEN ${missingPreviewSql(`"${field}Preview"`)} THEN "${field}" END AS "${field}"`).join(", ")}
|
|
20529
|
+
FROM ${table} WHERE ${keys.join(" OR ")}`, values);
|
|
20530
|
+
const key = (org, trace, version) => JSON.stringify([
|
|
20531
|
+
org,
|
|
20532
|
+
trace,
|
|
20533
|
+
String(version)
|
|
20534
|
+
]);
|
|
20535
|
+
const byRoot = new Map(payloads.map((row) => [key(row.organizationId, row.traceId, row.cursorId), row]));
|
|
20536
|
+
const agents = page.filter((row) => byRoot.get(key(row.organizationId, row.firstTraceId, row.firstCursorId))?.spanType === "agent_run");
|
|
20537
|
+
const models = /* @__PURE__ */ new Map();
|
|
20538
|
+
if (agents.length) {
|
|
20539
|
+
const modelValues = [];
|
|
20540
|
+
const rows = await run(`SELECT DISTINCT ON ("organizationId", "traceId") "organizationId", "traceId",
|
|
20541
|
+
CASE WHEN jsonb_typeof(attributes -> 'model') = 'string' THEN attributes ->> 'model' END AS model,
|
|
20542
|
+
CASE WHEN jsonb_typeof(attributes -> 'provider') = 'string' THEN attributes ->> 'provider' END AS provider
|
|
20543
|
+
FROM ${table} WHERE "spanType" = 'model_generation' AND NOT "isPending" AND (${agents.map((row) => `(${Object.entries({
|
|
20544
|
+
organizationId: row.organizationId,
|
|
20545
|
+
resourceId: row.resourceId,
|
|
20546
|
+
traceId: row.firstTraceId,
|
|
20547
|
+
parentSpanId: row.firstSpanId
|
|
20548
|
+
}).map(([field, value]) => {
|
|
20549
|
+
modelValues.push(value);
|
|
20550
|
+
return `"${field}" ${field === "organizationId" || field === "resourceId" ? "IS NOT DISTINCT FROM" : "="} $${modelValues.length}`;
|
|
20551
|
+
}).join(" AND ")})`).join(" OR ")})
|
|
20552
|
+
ORDER BY "organizationId", "traceId", "startedAt", "spanId" COLLATE "C", "cursorId" DESC`, modelValues);
|
|
20553
|
+
for (const row of rows) models.set(JSON.stringify([row.organizationId, row.traceId]), row);
|
|
20554
|
+
}
|
|
20555
|
+
const threads = page.flatMap((row) => {
|
|
20556
|
+
const first = byRoot.get(key(row.organizationId, row.firstTraceId, row.firstCursorId));
|
|
20557
|
+
const last = byRoot.get(key(row.organizationId, row.lastTraceId, row.lastCursorId));
|
|
20558
|
+
if (!first || !last) return [];
|
|
20559
|
+
const model = models.get(JSON.stringify([row.organizationId, row.firstTraceId]));
|
|
20560
|
+
return [coreStorage.threadQueryRowSchema.parse({
|
|
20561
|
+
organizationId: row.organizationId,
|
|
20562
|
+
threadId: row.threadId,
|
|
20563
|
+
firstTraceId: row.firstTraceId,
|
|
20564
|
+
lastTraceId: row.lastTraceId,
|
|
20565
|
+
...Object.fromEntries(contextFields.map((field) => [field, first[field]])),
|
|
20566
|
+
status: last.status,
|
|
20567
|
+
startedAt: row.startedAt.toISOString(),
|
|
20568
|
+
endedAt: row.endedAt.toISOString(),
|
|
20569
|
+
traceCount: Number(row.traceCount),
|
|
20570
|
+
timeToFirstChunkMs: first.timeToFirstChunkMs,
|
|
20571
|
+
model: model?.model ?? null,
|
|
20572
|
+
provider: model?.provider ?? null,
|
|
20573
|
+
inputPreview: readPreview(first.inputPreview, first.input),
|
|
20574
|
+
outputPreview: readPreview(last.outputPreview, last.output),
|
|
20575
|
+
errorPreview: readPreview(last.errorPreview, last.error)
|
|
20576
|
+
})];
|
|
20577
|
+
});
|
|
20578
|
+
const last = page.at(-1);
|
|
20579
|
+
return {
|
|
20580
|
+
threads,
|
|
20581
|
+
page: { next: selected.length > plan.limit ? coreStorage.encodeThreadQueryCursor(plan, {
|
|
20582
|
+
organizationId: last.organizationId,
|
|
20583
|
+
threadId: last.threadId,
|
|
20584
|
+
sortValue: last[plan.orderBy.field].toISOString()
|
|
20585
|
+
}) : null }
|
|
20586
|
+
};
|
|
20587
|
+
}
|
|
20588
|
+
//#endregion
|
|
20329
20589
|
//#region src/storage/domains/observability/v-next/trace-aggregate.ts
|
|
20330
20590
|
/** Trace-root column expressions (alias `r`) for each groupable dimension; same values `where` sees. */
|
|
20331
20591
|
const DIMENSION_SQL = {
|
|
20332
20592
|
entityType: "r.\"entityType\"",
|
|
20333
20593
|
entityName: "r.\"entityName\"",
|
|
20594
|
+
name: "r.\"name\"",
|
|
20595
|
+
spanType: "r.\"spanType\"",
|
|
20334
20596
|
environment: "r.\"environment\"",
|
|
20335
20597
|
status: TRACE_STATUS_SQL,
|
|
20336
20598
|
serviceName: "r.\"serviceName\"",
|
|
@@ -21557,12 +21819,15 @@ var ObservabilityStoragePostgresVNext = class ObservabilityStoragePostgresVNext
|
|
|
21557
21819
|
"trace-query",
|
|
21558
21820
|
"trace-aggregate",
|
|
21559
21821
|
...spanQueryFeatures,
|
|
21822
|
+
...typeof coreStorage.planThreadRowsQuery === "function" ? ["thread-query-rows"] : [],
|
|
21560
21823
|
"trace-query-root-duration",
|
|
21561
21824
|
"trace-query-discovery",
|
|
21562
21825
|
"thread-query",
|
|
21563
21826
|
"trace-query-tenant-scope",
|
|
21564
21827
|
"feedback",
|
|
21565
|
-
"trace-query-context-ids"
|
|
21828
|
+
"trace-query-context-ids",
|
|
21829
|
+
...timeToFirstChunkFeatures,
|
|
21830
|
+
"trace-query-root-span-fields"
|
|
21566
21831
|
];
|
|
21567
21832
|
return [
|
|
21568
21833
|
"metrics",
|
|
@@ -21577,12 +21842,15 @@ var ObservabilityStoragePostgresVNext = class ObservabilityStoragePostgresVNext
|
|
|
21577
21842
|
"trace-query",
|
|
21578
21843
|
"trace-aggregate",
|
|
21579
21844
|
...spanQueryFeatures,
|
|
21845
|
+
...typeof coreStorage.planThreadRowsQuery === "function" ? ["thread-query-rows"] : [],
|
|
21580
21846
|
"trace-query-root-duration",
|
|
21581
21847
|
"trace-query-discovery",
|
|
21582
21848
|
"thread-query",
|
|
21583
21849
|
"trace-query-tenant-scope",
|
|
21584
21850
|
"feedback",
|
|
21585
|
-
"trace-query-context-ids"
|
|
21851
|
+
"trace-query-context-ids",
|
|
21852
|
+
...timeToFirstChunkFeatures,
|
|
21853
|
+
"trace-query-root-span-fields"
|
|
21586
21854
|
];
|
|
21587
21855
|
}
|
|
21588
21856
|
async #run(op, fn, details) {
|
|
@@ -21644,7 +21912,7 @@ var ObservabilityStoragePostgresVNext = class ObservabilityStoragePostgresVNext
|
|
|
21644
21912
|
return this.#run("GET_TRACE_QUERY_VALUES", () => getTraceQueryValues(this.#readClient, this.#schema, plan, this.#traceQueryTimeoutMs));
|
|
21645
21913
|
}
|
|
21646
21914
|
async queryThreads(plan) {
|
|
21647
|
-
return this.#run("QUERY_THREADS", () => queryThreads(this.#readClient, this.#schema, plan, this.#traceQueryTimeoutMs));
|
|
21915
|
+
return this.#run("QUERY_THREADS", () => plan.result === "threadRows" ? queryThreadRows(this.#readClient, this.#schema, plan, this.#traceQueryTimeoutMs) : queryThreads(this.#readClient, this.#schema, plan, this.#traceQueryTimeoutMs));
|
|
21648
21916
|
}
|
|
21649
21917
|
async listBranches(args) {
|
|
21650
21918
|
return this.#run("LIST_BRANCHES", () => listBranches(this.#readClient, this.#schema, args));
|
|
@@ -24076,7 +24344,7 @@ var SkillsPG = class SkillsPG extends SkillsStorage {
|
|
|
24076
24344
|
}
|
|
24077
24345
|
}
|
|
24078
24346
|
async list(args) {
|
|
24079
|
-
const { page = 0, perPage: perPageInput, orderBy, authorId, visibility, status, entityIds, pinFavoritedFor, favoritedOnly } = args || {};
|
|
24347
|
+
const { page = 0, perPage: perPageInput, orderBy, authorId, visibility, status, entityIds, pinFavoritedFor, favoritedOnly, metadata } = args || {};
|
|
24080
24348
|
const { field, direction } = this.parseOrderBy(orderBy);
|
|
24081
24349
|
if (page < 0) throw new MastraError({
|
|
24082
24350
|
id: createStorageErrorId("PG", "LIST_SKILLS", "INVALID_PAGE"),
|
|
@@ -24121,6 +24389,16 @@ var SkillsPG = class SkillsPG extends SkillsStorage {
|
|
|
24121
24389
|
conditions.push(`s.visibility = $${paramIdx++}`);
|
|
24122
24390
|
queryParams.push(visibility);
|
|
24123
24391
|
}
|
|
24392
|
+
if (metadata && Object.keys(metadata).length > 0) {
|
|
24393
|
+
const versionsTable = getTableName$5({
|
|
24394
|
+
indexName: TABLE_SKILL_VERSIONS,
|
|
24395
|
+
schemaName: getSchemaName$5(this.#schema)
|
|
24396
|
+
});
|
|
24397
|
+
const latestVersionId = `(SELECT lv.id FROM ${versionsTable} lv WHERE lv."skillId" = s.id ORDER BY lv."versionNumber" DESC LIMIT 1)`;
|
|
24398
|
+
const resolvedVersionId = status === "draft" ? latestVersionId : `COALESCE(s."activeVersionId", ${latestVersionId})`;
|
|
24399
|
+
conditions.push(`EXISTS (SELECT 1 FROM ${versionsTable} mv WHERE mv."skillId" = s.id AND mv.id = ${resolvedVersionId} AND mv.metadata @> $${paramIdx++}::jsonb)`);
|
|
24400
|
+
queryParams.push(toPgJson(metadata));
|
|
24401
|
+
}
|
|
24124
24402
|
if (entityIds && entityIds.length > 0) {
|
|
24125
24403
|
const placeholders = entityIds.map(() => `$${paramIdx++}`).join(", ");
|
|
24126
24404
|
conditions.push(`s.id IN (${placeholders})`);
|