@mastra/pg 1.26.0-alpha.3 → 1.26.0-alpha.5
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/reference-memory-memory-class.md +1 -1
- package/dist/index.cjs +212 -56
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +213 -57
- package/dist/index.js.map +1 -1
- package/dist/storage/db/constraint-utils.d.ts +11 -1
- package/dist/storage/db/constraint-utils.d.ts.map +1 -1
- package/dist/storage/domains/datasets/index.d.ts.map +1 -1
- package/dist/storage/domains/experiments/index.d.ts.map +1 -1
- package/dist/storage/domains/observability/v-next/index.d.ts.map +1 -1
- package/dist/storage/domains/observability/v-next/polling.d.ts +1 -1
- package/dist/storage/domains/observability/v-next/polling.d.ts.map +1 -1
- package/dist/storage/domains/observability/v-next/trace-query.d.ts +1 -1
- package/dist/storage/domains/observability/v-next/trace-query.d.ts.map +1 -1
- package/dist/storage/domains/workflows/index.d.ts +32 -1
- package/dist/storage/domains/workflows/index.d.ts.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createHash, randomUUID } from "crypto";
|
|
2
2
|
import { ErrorCategory, ErrorDomain, MastraError } from "@mastra/core/error";
|
|
3
3
|
import * as coreStorage from "@mastra/core/storage";
|
|
4
|
-
import { AgentsStorage, BRANCH_SPAN_TYPES, BackgroundTasksStorage, BlobStore, ChannelsStorage, DATASETS_SCHEMA, DATASET_ITEMS_SCHEMA, DATASET_VERSIONS_SCHEMA, DatasetsStorage, EXPERIMENTS_SCHEMA, EXPERIMENT_RESULTS_SCHEMA, EntityType, ExperimentsStorage, FactoryStorage, FavoritesStorage, KNOWLEDGE_ACTIVITY_SCHEMA, KNOWLEDGE_CURSORS_SCHEMA, KNOWLEDGE_MENTIONS_SCHEMA, KNOWLEDGE_NODES_SCHEMA, KNOWLEDGE_RECORDS_SCHEMA, KNOWLEDGE_SEMANTIC_OUTBOX_SCHEMA, KnowledgeConflictError, KnowledgeNotFoundError, KnowledgeStorage, MCPClientsStorage, MCPServersStorage, METRIC_DISTINCT_COLUMNS, MastraCompositeStore, MemoryStorage, NotificationsStorage, OBSERVATIONAL_MEMORY_TABLE_SCHEMA, ObservabilityStorage, PromptBlocksStorage, SchedulesStorage, ScorerDefinitionsStorage, ScoresStorage, SkillsStorage, TABLE_AGENTS, TABLE_AGENT_VERSIONS, TABLE_BACKGROUND_TASKS, TABLE_CHANNEL_CONFIG, TABLE_CHANNEL_INSTALLATIONS, TABLE_CONFIGS, TABLE_DATASETS, TABLE_DATASET_ITEMS, TABLE_DATASET_VERSIONS, TABLE_EXPERIMENTS, TABLE_EXPERIMENT_RESULTS, TABLE_FAVORITES, TABLE_KNOWLEDGE_ACTIVITY, TABLE_KNOWLEDGE_CURSORS, TABLE_KNOWLEDGE_MENTIONS, TABLE_KNOWLEDGE_NODES, TABLE_KNOWLEDGE_RECORDS, TABLE_KNOWLEDGE_SEMANTIC_OUTBOX, TABLE_MCP_CLIENTS, TABLE_MCP_CLIENT_VERSIONS, TABLE_MCP_SERVERS, TABLE_MCP_SERVER_VERSIONS, TABLE_MESSAGES, TABLE_NOTIFICATIONS, TABLE_PROMPT_BLOCKS, TABLE_PROMPT_BLOCK_VERSIONS, TABLE_RESOURCES, TABLE_SCHEDULES, TABLE_SCHEDULE_TRIGGERS, TABLE_SCHEMAS, TABLE_SCORERS, TABLE_SCORER_DEFINITIONS, TABLE_SCORER_DEFINITION_VERSIONS, TABLE_SKILLS, TABLE_SKILL_BLOBS, TABLE_SKILL_VERSIONS, TABLE_SPANS, TABLE_THREADS, TABLE_THREAD_STATE, TABLE_TOOL_PROVIDER_CONNECTIONS, TABLE_WORKFLOW_DEFINITIONS, TABLE_WORKFLOW_SNAPSHOT, TABLE_WORKSPACES, TABLE_WORKSPACE_VERSIONS, ThreadStateStorage, ToolProviderConnectionsStorage, TraceStatus, UniqueViolationError, WorkflowDefinitionsStorage, WorkflowsStorage, WorkspacesStorage, assertKnowledgeCeilingRaised, assertKnowledgeScopeWithinCeiling, calculatePagination, canonicalizeKnowledgeScope, createKnowledgeUlid, createStorageErrorId, createVectorErrorId, ensureDate, executeRetentionPrune, getDefaultValue, getSqlType, hasErrorCode, isKnowledgeScopeVisible, knowledgeScopeKey, knowledgeSemanticDocumentId, knowledgeSemanticIdempotencyKey, listBranchesArgsSchema, listFeedbackArgsSchema, listLogsArgsSchema, listMetricsArgsSchema, listScoresArgsSchema, listTracesArgsSchema, matchesExpectedWorkflowStatus, mergeWorkflowStepResult, normalizePerPage, normalizeScheduleTarget, parseDuration, parseKnowledgeNodeCursor, parseKnowledgeWikilinks, resolveRetentionTargets, retentionCutoffMs, runRetentionBatches, safelyParseJSON, storageMessageMatchesMetadataFilter, toTraceSpans, transformScoreRow, validateStorageMetadataFilter } from "@mastra/core/storage";
|
|
4
|
+
import { AgentsStorage, BRANCH_SPAN_TYPES, BackgroundTasksStorage, BlobStore, ChannelsStorage, DATASETS_SCHEMA, DATASET_ITEMS_SCHEMA, DATASET_VERSIONS_SCHEMA, DatasetsStorage, EXPERIMENTS_SCHEMA, EXPERIMENT_RESULTS_SCHEMA, EntityType, ExperimentsStorage, FactoryStorage, FavoritesStorage, KNOWLEDGE_ACTIVITY_SCHEMA, KNOWLEDGE_CURSORS_SCHEMA, KNOWLEDGE_MENTIONS_SCHEMA, KNOWLEDGE_NODES_SCHEMA, KNOWLEDGE_RECORDS_SCHEMA, KNOWLEDGE_SEMANTIC_OUTBOX_SCHEMA, KnowledgeConflictError, KnowledgeNotFoundError, KnowledgeStorage, MCPClientsStorage, MCPServersStorage, METRIC_DISTINCT_COLUMNS, MastraCompositeStore, MemoryStorage, NotificationsStorage, OBSERVATIONAL_MEMORY_TABLE_SCHEMA, ObservabilityStorage, PromptBlocksStorage, SchedulesStorage, ScorerDefinitionsStorage, ScoresStorage, SkillsStorage, TABLE_AGENTS, TABLE_AGENT_VERSIONS, TABLE_BACKGROUND_TASKS, TABLE_CHANNEL_CONFIG, TABLE_CHANNEL_INSTALLATIONS, TABLE_CONFIGS, TABLE_DATASETS, TABLE_DATASET_ITEMS, TABLE_DATASET_VERSIONS, TABLE_EXPERIMENTS, TABLE_EXPERIMENT_RESULTS, TABLE_FAVORITES, TABLE_KNOWLEDGE_ACTIVITY, TABLE_KNOWLEDGE_CURSORS, TABLE_KNOWLEDGE_MENTIONS, TABLE_KNOWLEDGE_NODES, TABLE_KNOWLEDGE_RECORDS, TABLE_KNOWLEDGE_SEMANTIC_OUTBOX, TABLE_MCP_CLIENTS, TABLE_MCP_CLIENT_VERSIONS, TABLE_MCP_SERVERS, TABLE_MCP_SERVER_VERSIONS, TABLE_MESSAGES, TABLE_NOTIFICATIONS, TABLE_PROMPT_BLOCKS, TABLE_PROMPT_BLOCK_VERSIONS, TABLE_RESOURCES, TABLE_SCHEDULES, TABLE_SCHEDULE_TRIGGERS, TABLE_SCHEMAS, TABLE_SCORERS, TABLE_SCORER_DEFINITIONS, TABLE_SCORER_DEFINITION_VERSIONS, TABLE_SKILLS, TABLE_SKILL_BLOBS, TABLE_SKILL_VERSIONS, TABLE_SPANS, TABLE_THREADS, TABLE_THREAD_STATE, TABLE_TOOL_PROVIDER_CONNECTIONS, TABLE_WORKFLOW_DEFINITIONS, TABLE_WORKFLOW_SNAPSHOT, TABLE_WORKSPACES, TABLE_WORKSPACE_VERSIONS, ThreadStateStorage, ToolProviderConnectionsStorage, TraceStatus, UniqueViolationError, WorkflowDefinitionsStorage, WorkflowsStorage, WorkspacesStorage, assertKnowledgeCeilingRaised, assertKnowledgeScopeWithinCeiling, calculatePagination, canonicalizeKnowledgeScope, createKnowledgeUlid, createStorageErrorId, createVectorErrorId, ensureDate, executeRetentionPrune, getDefaultValue, getSqlType, hasErrorCode, isKnowledgeScopeVisible, knowledgeScopeKey, knowledgeSemanticDocumentId, knowledgeSemanticIdempotencyKey, listBranchesArgsSchema, listFeedbackArgsSchema, listLogsArgsSchema, listMetricsArgsSchema, listScoresArgsSchema, listTracesArgsSchema, matchesExpectedWorkflowStatus, mergeWorkflowStepResult, normalizePerPage, normalizeScheduleTarget, parseDuration, parseKnowledgeNodeCursor, parseKnowledgeWikilinks, resolveListOrderBy, resolveRetentionTargets, retentionCutoffMs, runRetentionBatches, safelyParseJSON, storageMessageMatchesMetadataFilter, toTraceSpans, transformScoreRow, validateStorageMetadataFilter } from "@mastra/core/storage";
|
|
5
5
|
import { parseFieldKey, parseSqlIdentifier } from "@mastra/core/utils";
|
|
6
6
|
import { MastraVector, validateTopK, validateUpsertInput } from "@mastra/core/vector";
|
|
7
7
|
import { Mutex } from "async-mutex";
|
|
@@ -2336,6 +2336,8 @@ var RoutingDbClient = class {
|
|
|
2336
2336
|
return this.active.tx(callback);
|
|
2337
2337
|
}
|
|
2338
2338
|
};
|
|
2339
|
+
/** Bytes reserved for the `_xxxxxxxx` collision suffix when hashWhenTruncated applies. */
|
|
2340
|
+
const TRUNCATION_HASH_SUFFIX_LENGTH = 9;
|
|
2339
2341
|
function truncateIdentifier(value, maxLength = 63) {
|
|
2340
2342
|
if (maxLength <= 0) return "";
|
|
2341
2343
|
if (Buffer.byteLength(value, "utf-8") <= maxLength) return value;
|
|
@@ -2356,9 +2358,25 @@ function truncateIdentifier(value, maxLength = 63) {
|
|
|
2356
2358
|
* in system catalogs (pg_constraint.conname, pg_indexes.indexname, etc.).
|
|
2357
2359
|
* Without this normalisation, runtime lookups that compare a mixed-case name
|
|
2358
2360
|
* against the catalog would silently fail.
|
|
2361
|
+
*
|
|
2362
|
+
* With `hashWhenTruncated`, a name that exceeds the limit is truncated further
|
|
2363
|
+
* to make room for `_` + 8 hex chars of the full name's sha256. Plain
|
|
2364
|
+
* truncation cuts the tail, so two names sharing a long `<schema>_<prefix>`
|
|
2365
|
+
* collapse to the same identifier and `CREATE INDEX IF NOT EXISTS` (which
|
|
2366
|
+
* matches by name only) silently skips the second one. The suffix is
|
|
2367
|
+
* deterministic, so creation, warm-init snapshot checks, and DDL export all
|
|
2368
|
+
* agree on the same name. Opt-in because renaming already-released constraint
|
|
2369
|
+
* names would orphan the existing objects in deployed catalogs.
|
|
2359
2370
|
*/
|
|
2360
|
-
function buildConstraintName({ baseName, schemaName, maxLength = 63 }) {
|
|
2361
|
-
|
|
2371
|
+
function buildConstraintName({ baseName, schemaName, maxLength = 63, hashWhenTruncated = false }) {
|
|
2372
|
+
const fullName = `${schemaName ? `${schemaName}_` : ""}${baseName}`.toLowerCase();
|
|
2373
|
+
if (hashWhenTruncated && Buffer.byteLength(fullName, "utf-8") > maxLength) {
|
|
2374
|
+
const suffixLength = Math.min(TRUNCATION_HASH_SUFFIX_LENGTH, maxLength);
|
|
2375
|
+
if (suffixLength < 2) return truncateIdentifier(fullName, maxLength);
|
|
2376
|
+
const hash = createHash("sha256").update(fullName).digest("hex").slice(0, suffixLength - 1);
|
|
2377
|
+
return `${truncateIdentifier(fullName, maxLength - suffixLength)}_${hash}`;
|
|
2378
|
+
}
|
|
2379
|
+
return truncateIdentifier(fullName, maxLength);
|
|
2362
2380
|
}
|
|
2363
2381
|
//#endregion
|
|
2364
2382
|
//#region src/storage/db/pg-errors.ts
|
|
@@ -6094,6 +6112,14 @@ var DatasetsPG = class DatasetsPG extends DatasetsStorage {
|
|
|
6094
6112
|
}
|
|
6095
6113
|
async listDatasets(args) {
|
|
6096
6114
|
try {
|
|
6115
|
+
const orderBy = resolveListOrderBy(args.orderBy, [
|
|
6116
|
+
"createdAt",
|
|
6117
|
+
"updatedAt",
|
|
6118
|
+
"name"
|
|
6119
|
+
], {
|
|
6120
|
+
field: "createdAt",
|
|
6121
|
+
direction: "DESC"
|
|
6122
|
+
});
|
|
6097
6123
|
const { page, perPage: perPageInput } = args.pagination;
|
|
6098
6124
|
const tableName = getTableName$5({
|
|
6099
6125
|
indexName: TABLE_DATASETS,
|
|
@@ -6149,7 +6175,7 @@ var DatasetsPG = class DatasetsPG extends DatasetsStorage {
|
|
|
6149
6175
|
const { offset, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
|
|
6150
6176
|
const limitValue = perPageInput === false ? total : perPage;
|
|
6151
6177
|
return {
|
|
6152
|
-
datasets: (await this.#db.readClient.manyOrNone(`SELECT * FROM ${tableName} ${whereClause} ORDER BY "
|
|
6178
|
+
datasets: (await this.#db.readClient.manyOrNone(`SELECT * FROM ${tableName} ${whereClause} ORDER BY "${orderBy.field}" ${orderBy.direction}, "id" ASC LIMIT $${paramIndex} OFFSET $${paramIndex + 1}`, [
|
|
6153
6179
|
...queryParams,
|
|
6154
6180
|
limitValue,
|
|
6155
6181
|
offset
|
|
@@ -6716,6 +6742,10 @@ var DatasetsPG = class DatasetsPG extends DatasetsStorage {
|
|
|
6716
6742
|
*/
|
|
6717
6743
|
async #listItems(client, args) {
|
|
6718
6744
|
try {
|
|
6745
|
+
const orderBy = resolveListOrderBy(args.orderBy, ["createdAt", "updatedAt"], {
|
|
6746
|
+
field: "createdAt",
|
|
6747
|
+
direction: "DESC"
|
|
6748
|
+
});
|
|
6719
6749
|
const { page, perPage: perPageInput } = args.pagination;
|
|
6720
6750
|
const tableName = getTableName$5({
|
|
6721
6751
|
indexName: TABLE_DATASET_ITEMS,
|
|
@@ -6766,7 +6796,7 @@ var DatasetsPG = class DatasetsPG extends DatasetsStorage {
|
|
|
6766
6796
|
const { offset, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
|
|
6767
6797
|
const limitValue = perPageInput === false ? total : perPage;
|
|
6768
6798
|
return {
|
|
6769
|
-
items: (await client.manyOrNone(`SELECT * FROM ${tableName} ${whereClause} ORDER BY "
|
|
6799
|
+
items: (await client.manyOrNone(`SELECT * FROM ${tableName} ${whereClause} ORDER BY "${orderBy.field}" ${orderBy.direction}, "id" ASC LIMIT $${paramIndex} OFFSET $${paramIndex + 1}`, [
|
|
6770
6800
|
...queryParams,
|
|
6771
6801
|
limitValue,
|
|
6772
6802
|
offset
|
|
@@ -7326,6 +7356,10 @@ var ExperimentsPG = class ExperimentsPG extends ExperimentsStorage {
|
|
|
7326
7356
|
}
|
|
7327
7357
|
async listExperiments(args) {
|
|
7328
7358
|
try {
|
|
7359
|
+
const orderBy = resolveListOrderBy(args.orderBy, ["createdAt", "status"], {
|
|
7360
|
+
field: "createdAt",
|
|
7361
|
+
direction: "DESC"
|
|
7362
|
+
});
|
|
7329
7363
|
const { page, perPage: perPageInput } = args.pagination;
|
|
7330
7364
|
const tableName = getTableName$5({
|
|
7331
7365
|
indexName: TABLE_EXPERIMENTS,
|
|
@@ -7397,7 +7431,7 @@ var ExperimentsPG = class ExperimentsPG extends ExperimentsStorage {
|
|
|
7397
7431
|
const { offset, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
|
|
7398
7432
|
const limitValue = perPageInput === false ? total : perPage;
|
|
7399
7433
|
return {
|
|
7400
|
-
experiments: (await this.#db.readClient.manyOrNone(`SELECT * FROM ${tableName} ${whereClause} ORDER BY "
|
|
7434
|
+
experiments: (await this.#db.readClient.manyOrNone(`SELECT * FROM ${tableName} ${whereClause} ORDER BY "${orderBy.field}" ${orderBy.direction}, "id" ASC LIMIT $${paramIndex} OFFSET $${paramIndex + 1}`, [
|
|
7401
7435
|
...queryParams,
|
|
7402
7436
|
limitValue,
|
|
7403
7437
|
offset
|
|
@@ -7669,6 +7703,10 @@ var ExperimentsPG = class ExperimentsPG extends ExperimentsStorage {
|
|
|
7669
7703
|
}
|
|
7670
7704
|
async listExperimentResults(args) {
|
|
7671
7705
|
try {
|
|
7706
|
+
const orderBy = resolveListOrderBy(args.orderBy, ["startedAt", "createdAt"], {
|
|
7707
|
+
field: "startedAt",
|
|
7708
|
+
direction: "ASC"
|
|
7709
|
+
});
|
|
7672
7710
|
const { page, perPage: perPageInput } = args.pagination;
|
|
7673
7711
|
const tableName = getTableName$5({
|
|
7674
7712
|
indexName: TABLE_EXPERIMENT_RESULTS,
|
|
@@ -7716,7 +7754,7 @@ var ExperimentsPG = class ExperimentsPG extends ExperimentsStorage {
|
|
|
7716
7754
|
const { offset, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
|
|
7717
7755
|
const limitValue = perPageInput === false ? total : perPage;
|
|
7718
7756
|
return {
|
|
7719
|
-
results: (await this.#db.readClient.manyOrNone(`SELECT * FROM ${tableName} ${whereClause} ORDER BY "
|
|
7757
|
+
results: (await this.#db.readClient.manyOrNone(`SELECT * FROM ${tableName} ${whereClause} ORDER BY "${orderBy.field}" ${orderBy.direction}, "id" ASC LIMIT $${paramIndex} OFFSET $${paramIndex + 1}`, [
|
|
7720
7758
|
...queryParams,
|
|
7721
7759
|
limitValue,
|
|
7722
7760
|
offset
|
|
@@ -17255,7 +17293,7 @@ const TRACE_SELECT = `
|
|
|
17255
17293
|
r."name" AS "name",
|
|
17256
17294
|
r."entityId" AS "entityId",
|
|
17257
17295
|
r."parentSpanId" AS "parentSpanId",
|
|
17258
|
-
r."
|
|
17296
|
+
r."metadataRaw" AS "metadata",
|
|
17259
17297
|
r."input" AS "input",
|
|
17260
17298
|
r."threadId" AS "threadId",
|
|
17261
17299
|
r."resourceId" AS "resourceId",
|
|
@@ -17473,22 +17511,27 @@ function compileThreadPredicate(predicate, parameterOffset) {
|
|
|
17473
17511
|
values: compiled.values
|
|
17474
17512
|
};
|
|
17475
17513
|
}
|
|
17476
|
-
function compilePostgresTraceScope(schema, selection, relationCollections) {
|
|
17514
|
+
function compilePostgresTraceScope(schema, selection, relationCollections, deltaWindow) {
|
|
17477
17515
|
const spanTable = qualifiedTable(schema, TABLE_SPAN_EVENTS);
|
|
17478
17516
|
const scoreTable = qualifiedTable(schema, TABLE_SCORE_EVENTS);
|
|
17479
17517
|
const feedbackTable = qualifiedTable(schema, TABLE_FEEDBACK_EVENTS);
|
|
17480
17518
|
const values = [selection.timeRange.from, selection.timeRange.to];
|
|
17481
|
-
const
|
|
17482
|
-
SELECT *
|
|
17483
|
-
FROM ${spanTable} r
|
|
17484
|
-
WHERE ${[
|
|
17519
|
+
const rootConditions = [
|
|
17485
17520
|
`r."parentSpanId" IS NULL`,
|
|
17486
17521
|
latestRootPredicate$1(spanTable),
|
|
17487
17522
|
`NOT r."isPending"`,
|
|
17488
17523
|
`r."endedAt" IS NOT NULL`,
|
|
17489
17524
|
`r."startedAt" >= $1`,
|
|
17490
17525
|
`r."startedAt" < $2`
|
|
17491
|
-
]
|
|
17526
|
+
];
|
|
17527
|
+
if (deltaWindow) {
|
|
17528
|
+
values.push(deltaWindow.xactId, deltaWindow.cursorId, deltaWindow.safeHorizon);
|
|
17529
|
+
rootConditions.push(`(r."xactId", r."cursorId") > ($3::xid8, $4::bigint)`, `r."xactId" < $5::xid8`);
|
|
17530
|
+
}
|
|
17531
|
+
const ctes = [`root_scope AS MATERIALIZED (
|
|
17532
|
+
SELECT *
|
|
17533
|
+
FROM ${spanTable} r
|
|
17534
|
+
WHERE ${rootConditions.join("\n AND ")}
|
|
17492
17535
|
)`];
|
|
17493
17536
|
if (relationCollections.has("spans")) ctes.push(`current_spans AS MATERIALIZED (
|
|
17494
17537
|
SELECT
|
|
@@ -17557,8 +17600,18 @@ function compilePostgresTraceScope(schema, selection, relationCollections) {
|
|
|
17557
17600
|
values
|
|
17558
17601
|
};
|
|
17559
17602
|
}
|
|
17560
|
-
function compilePostgresTraceQuery(schema, plan, mode = "data") {
|
|
17561
|
-
const
|
|
17603
|
+
function compilePostgresTraceQuery(schema, plan, mode = "data", safeHorizon) {
|
|
17604
|
+
const relationCollections = collectRelationCollections(plan.where);
|
|
17605
|
+
let deltaWindow;
|
|
17606
|
+
if (plan.paginationMode === "delta") {
|
|
17607
|
+
const watermark = coreStorage.getTraceQueryDeltaWatermark(plan, "pg");
|
|
17608
|
+
if (watermark === void 0 || safeHorizon === void 0) throw new Error("Delta query requires a cursor and safe horizon");
|
|
17609
|
+
deltaWindow = {
|
|
17610
|
+
...decodeTraceDeltaWatermark(watermark),
|
|
17611
|
+
safeHorizon
|
|
17612
|
+
};
|
|
17613
|
+
}
|
|
17614
|
+
const { ctes, values } = compilePostgresTraceScope(schema, plan, relationCollections, deltaWindow);
|
|
17562
17615
|
let predicateSql = "TRUE";
|
|
17563
17616
|
if (plan.where) {
|
|
17564
17617
|
const predicate = compilePredicate(plan.where, values.length + 1);
|
|
@@ -17566,7 +17619,7 @@ function compilePostgresTraceQuery(schema, plan, mode = "data") {
|
|
|
17566
17619
|
values.push(...predicate.values);
|
|
17567
17620
|
}
|
|
17568
17621
|
ctes.push(`candidates AS (
|
|
17569
|
-
SELECT ${TRACE_SELECT}
|
|
17622
|
+
SELECT ${TRACE_SELECT}${plan.paginationMode === "delta" ? ", r.\"xactId\", r.\"cursorId\"" : ""}
|
|
17570
17623
|
FROM root_scope r
|
|
17571
17624
|
WHERE ${predicateSql}
|
|
17572
17625
|
)`);
|
|
@@ -17577,6 +17630,16 @@ SELECT COUNT(*)::text AS count
|
|
|
17577
17630
|
FROM candidates`,
|
|
17578
17631
|
values
|
|
17579
17632
|
};
|
|
17633
|
+
if (plan.paginationMode === "delta") {
|
|
17634
|
+
values.push(plan.limit + 1);
|
|
17635
|
+
return {
|
|
17636
|
+
text: `${candidates}
|
|
17637
|
+
SELECT * FROM candidates
|
|
17638
|
+
ORDER BY "xactId" ASC, "cursorId" ASC
|
|
17639
|
+
LIMIT $${values.length}`,
|
|
17640
|
+
values
|
|
17641
|
+
};
|
|
17642
|
+
}
|
|
17580
17643
|
if (plan.result === "groups") {
|
|
17581
17644
|
const pageCondition = plan.cursor ? `AND "threadId" > $${values.length + 1}` : "";
|
|
17582
17645
|
if (plan.cursor) values.push(plan.cursor.threadId);
|
|
@@ -17788,13 +17851,83 @@ async function getTraceQueryValues(client, schema, plan, timeoutMs) {
|
|
|
17788
17851
|
valuesTruncated: rows.length > plan.limit
|
|
17789
17852
|
});
|
|
17790
17853
|
}
|
|
17854
|
+
function decodeTraceDeltaWatermark(watermark) {
|
|
17855
|
+
try {
|
|
17856
|
+
return decodeDeltaCursor(watermark);
|
|
17857
|
+
} catch {
|
|
17858
|
+
throw new coreStorage.TraceQueryCursorError("TRACE_QUERY_CURSOR_MALFORMED");
|
|
17859
|
+
}
|
|
17860
|
+
}
|
|
17861
|
+
function emptyDeltaWatermark(horizon, watermark) {
|
|
17862
|
+
if (watermark !== void 0 && BigInt(decodeTraceDeltaWatermark(watermark).xactId) >= BigInt(horizon)) return watermark;
|
|
17863
|
+
return encodeDeltaCursor(horizon, 0);
|
|
17864
|
+
}
|
|
17865
|
+
async function setRemainingTimeout(transaction, deadline) {
|
|
17866
|
+
const remainingTimeoutMs = Math.floor(deadline - performance.now());
|
|
17867
|
+
if (remainingTimeoutMs <= 0) throw new coreStorage.TraceQueryExecutionError();
|
|
17868
|
+
await transaction.query(`SELECT set_config('statement_timeout', $1, true)`, [`${remainingTimeoutMs}ms`]);
|
|
17869
|
+
}
|
|
17870
|
+
function traceRowToResult(row) {
|
|
17871
|
+
return {
|
|
17872
|
+
traceId: String(row.traceId),
|
|
17873
|
+
rootSpanId: String(row.rootSpanId),
|
|
17874
|
+
name: row.name,
|
|
17875
|
+
entityId: row.entityId ?? null,
|
|
17876
|
+
parentSpanId: row.parentSpanId ?? null,
|
|
17877
|
+
createdAt: asIsoTimestamp$1(row.startedAt),
|
|
17878
|
+
metadata: row.metadata ?? null,
|
|
17879
|
+
inputPreview: coreStorage.buildInputPreview(row.input) ?? null,
|
|
17880
|
+
threadId: row.threadId == null ? null : String(row.threadId),
|
|
17881
|
+
resourceId: row.resourceId == null ? null : String(row.resourceId),
|
|
17882
|
+
startedAt: asIsoTimestamp$1(row.startedAt),
|
|
17883
|
+
endedAt: asIsoTimestamp$1(row.endedAt),
|
|
17884
|
+
entityName: row.entityName == null ? null : String(row.entityName),
|
|
17885
|
+
entityType: row.entityType == null ? null : String(row.entityType),
|
|
17886
|
+
environment: row.environment == null ? null : String(row.environment),
|
|
17887
|
+
status: row.status
|
|
17888
|
+
};
|
|
17889
|
+
}
|
|
17791
17890
|
async function queryTraces(client, schema, plan, timeoutMs) {
|
|
17891
|
+
if (plan.paginationMode === "delta") {
|
|
17892
|
+
assertDeltaPollingEnabled();
|
|
17893
|
+
const watermark = coreStorage.getTraceQueryDeltaWatermark(plan, "pg");
|
|
17894
|
+
if (watermark !== void 0) decodeTraceDeltaWatermark(watermark);
|
|
17895
|
+
const resolvedTimeoutMs = coreStorage.resolveTraceQueryTimeoutMs(timeoutMs);
|
|
17896
|
+
const deadline = performance.now() + resolvedTimeoutMs;
|
|
17897
|
+
return runWithPostgresTraceQueryTimeout(client, resolvedTimeoutMs, async (transaction) => {
|
|
17898
|
+
await setRemainingTimeout(transaction, deadline);
|
|
17899
|
+
const horizon = await readSafeXactHorizon(transaction);
|
|
17900
|
+
let rows = [];
|
|
17901
|
+
if (watermark !== void 0) {
|
|
17902
|
+
await setRemainingTimeout(transaction, deadline);
|
|
17903
|
+
const query = compilePostgresTraceQuery(schema, plan, "data", horizon);
|
|
17904
|
+
rows = await transaction.any(query.text, query.values);
|
|
17905
|
+
}
|
|
17906
|
+
const visible = rows.slice(0, plan.limit);
|
|
17907
|
+
const last = visible.at(-1);
|
|
17908
|
+
return coreStorage.traceQueryResponseSchema.parse({
|
|
17909
|
+
traces: visible.map(traceRowToResult),
|
|
17910
|
+
delta: {
|
|
17911
|
+
limit: plan.limit,
|
|
17912
|
+
hasMore: rows.length > plan.limit
|
|
17913
|
+
},
|
|
17914
|
+
deltaCursor: coreStorage.encodeTraceQueryDeltaCursor(plan, "pg", last ? encodeDeltaCursor(last.xactId, last.cursorId) : emptyDeltaWatermark(horizon, watermark))
|
|
17915
|
+
});
|
|
17916
|
+
}, { repeatableRead: true });
|
|
17917
|
+
}
|
|
17792
17918
|
if (plan.paginationMode === "page") {
|
|
17793
17919
|
const resolvedTimeoutMs = coreStorage.resolveTraceQueryTimeoutMs(timeoutMs);
|
|
17794
17920
|
const deadline = performance.now() + resolvedTimeoutMs;
|
|
17795
17921
|
const countQuery = compilePostgresTraceQuery(schema, plan, "count");
|
|
17796
17922
|
const dataQuery = compilePostgresTraceQuery(schema, plan);
|
|
17797
|
-
const { total, rows } = await runWithPostgresTraceQueryTimeout(client, resolvedTimeoutMs, async (transaction) => {
|
|
17923
|
+
const { total, rows, deltaCursor } = await runWithPostgresTraceQueryTimeout(client, resolvedTimeoutMs, async (transaction) => {
|
|
17924
|
+
let deltaCursor;
|
|
17925
|
+
if (deltaPollingFeatureEnabled() && typeof coreStorage.encodeTraceQueryDeltaCursor === "function") {
|
|
17926
|
+
await setRemainingTimeout(transaction, deadline);
|
|
17927
|
+
const horizon = await readSafeXactHorizon(transaction);
|
|
17928
|
+
deltaCursor = coreStorage.encodeTraceQueryDeltaCursor(plan, "pg", encodeDeltaCursor(horizon, 0));
|
|
17929
|
+
}
|
|
17930
|
+
if (deltaCursor !== void 0) await setRemainingTimeout(transaction, deadline);
|
|
17798
17931
|
const countRows = await transaction.any(countQuery.text, countQuery.values);
|
|
17799
17932
|
const remainingTimeoutMs = Math.floor(deadline - performance.now());
|
|
17800
17933
|
if (remainingTimeoutMs <= 0) throw new coreStorage.TraceQueryExecutionError();
|
|
@@ -17802,29 +17935,14 @@ async function queryTraces(client, schema, plan, timeoutMs) {
|
|
|
17802
17935
|
const rows = await transaction.any(dataQuery.text, dataQuery.values);
|
|
17803
17936
|
return {
|
|
17804
17937
|
total: Number(countRows[0]?.count ?? 0),
|
|
17805
|
-
rows
|
|
17938
|
+
rows,
|
|
17939
|
+
deltaCursor
|
|
17806
17940
|
};
|
|
17807
17941
|
}, { repeatableRead: true });
|
|
17808
|
-
const traces = rows.map(
|
|
17809
|
-
traceId: String(row.traceId),
|
|
17810
|
-
rootSpanId: String(row.rootSpanId),
|
|
17811
|
-
name: row.name,
|
|
17812
|
-
entityId: row.entityId ?? null,
|
|
17813
|
-
parentSpanId: row.parentSpanId ?? null,
|
|
17814
|
-
createdAt: asIsoTimestamp$1(row.startedAt),
|
|
17815
|
-
metadata: row.metadata ?? null,
|
|
17816
|
-
inputPreview: coreStorage.buildInputPreview(row.input) ?? null,
|
|
17817
|
-
threadId: row.threadId == null ? null : String(row.threadId),
|
|
17818
|
-
resourceId: row.resourceId == null ? null : String(row.resourceId),
|
|
17819
|
-
startedAt: asIsoTimestamp$1(row.startedAt),
|
|
17820
|
-
endedAt: asIsoTimestamp$1(row.endedAt),
|
|
17821
|
-
entityName: row.entityName == null ? null : String(row.entityName),
|
|
17822
|
-
entityType: row.entityType == null ? null : String(row.entityType),
|
|
17823
|
-
environment: row.environment == null ? null : String(row.environment),
|
|
17824
|
-
status: row.status
|
|
17825
|
-
}));
|
|
17942
|
+
const traces = rows.map(traceRowToResult);
|
|
17826
17943
|
return coreStorage.traceQueryResponseSchema.parse({
|
|
17827
17944
|
traces,
|
|
17945
|
+
...deltaCursor === void 0 ? {} : { deltaCursor },
|
|
17828
17946
|
pagination: {
|
|
17829
17947
|
total,
|
|
17830
17948
|
page: plan.page,
|
|
@@ -17847,24 +17965,7 @@ async function queryTraces(client, schema, plan, timeoutMs) {
|
|
|
17847
17965
|
}) : null }
|
|
17848
17966
|
});
|
|
17849
17967
|
}
|
|
17850
|
-
const traces = visibleRows.map(
|
|
17851
|
-
traceId: String(row.traceId),
|
|
17852
|
-
rootSpanId: String(row.rootSpanId),
|
|
17853
|
-
name: row.name,
|
|
17854
|
-
entityId: row.entityId ?? null,
|
|
17855
|
-
parentSpanId: row.parentSpanId ?? null,
|
|
17856
|
-
createdAt: asIsoTimestamp$1(row.startedAt),
|
|
17857
|
-
metadata: row.metadata ?? null,
|
|
17858
|
-
inputPreview: coreStorage.buildInputPreview(row.input) ?? null,
|
|
17859
|
-
threadId: row.threadId == null ? null : String(row.threadId),
|
|
17860
|
-
resourceId: row.resourceId == null ? null : String(row.resourceId),
|
|
17861
|
-
startedAt: asIsoTimestamp$1(row.startedAt),
|
|
17862
|
-
endedAt: asIsoTimestamp$1(row.endedAt),
|
|
17863
|
-
entityName: row.entityName == null ? null : String(row.entityName),
|
|
17864
|
-
entityType: row.entityType == null ? null : String(row.entityType),
|
|
17865
|
-
environment: row.environment == null ? null : String(row.environment),
|
|
17866
|
-
status: row.status
|
|
17867
|
-
}));
|
|
17968
|
+
const traces = visibleRows.map(traceRowToResult);
|
|
17868
17969
|
const last = traces.at(-1);
|
|
17869
17970
|
return coreStorage.traceQueryResponseSchema.parse({
|
|
17870
17971
|
traces,
|
|
@@ -18603,7 +18704,7 @@ async function dangerouslyClearTracing(client, schema) {
|
|
|
18603
18704
|
* Use it through `MastraCompositeStore` with a dedicated Postgres connection.
|
|
18604
18705
|
*/
|
|
18605
18706
|
function wrapError(op, error, details) {
|
|
18606
|
-
if (error instanceof MastraError || error instanceof coreStorage.TraceQueryExecutionError || error instanceof coreStorage.TraceQueryResourceLimitError) throw error;
|
|
18707
|
+
if (error instanceof MastraError || error instanceof coreStorage.TraceQueryCursorError || error instanceof coreStorage.TraceQueryExecutionError || error instanceof coreStorage.TraceQueryResourceLimitError) throw error;
|
|
18607
18708
|
throw new MastraError({
|
|
18608
18709
|
id: createStorageErrorId("PG", op, "FAILED"),
|
|
18609
18710
|
domain: ErrorDomain.STORAGE,
|
|
@@ -22293,6 +22394,7 @@ const WORKFLOW_SNAPSHOT_STATUS_INDEX = "mastra_workflow_snapshot_name_status_cre
|
|
|
22293
22394
|
* Schema-prefixed name of the status index, lowercased and truncated the same way Postgres
|
|
22294
22395
|
* stores it, so the init snapshot's index set answers "does it exist?" without a probe or a
|
|
22295
22396
|
* no-op `CREATE INDEX` (schema-prefixed names routinely exceed the 63-byte limit).
|
|
22397
|
+
* Exported for tests.
|
|
22296
22398
|
*/
|
|
22297
22399
|
function workflowSnapshotStatusIndexName(schemaName) {
|
|
22298
22400
|
return buildConstraintName({
|
|
@@ -22310,6 +22412,48 @@ function workflowSnapshotStatusIndexSQL(indexName, schemaName) {
|
|
|
22310
22412
|
schemaName: getSchemaName(schemaName)
|
|
22311
22413
|
})} (workflow_name, (snapshot ->> 'status'), "createdAt" DESC)`;
|
|
22312
22414
|
}
|
|
22415
|
+
/** Base name (before any schema prefix) of the expression index backing the threadId filter. */
|
|
22416
|
+
const WORKFLOW_SNAPSHOT_THREAD_ID_INDEX = "mastra_workflow_snapshot_threadid_idx";
|
|
22417
|
+
/**
|
|
22418
|
+
* Schema-prefixed name of the threadId index (see workflowSnapshotStatusIndexName).
|
|
22419
|
+
*
|
|
22420
|
+
* Unlike the status index, truncation appends a collision hash: both index names share the
|
|
22421
|
+
* long `<schema>_mastra_workflow_snapshot_` prefix, so with a schema name of 37+ bytes plain
|
|
22422
|
+
* truncation collapses them to the same 63-byte identifier and `CREATE INDEX IF NOT EXISTS`
|
|
22423
|
+
* silently skips this index. The status index keeps plain truncation because its truncated
|
|
22424
|
+
* name already exists in deployed catalogs; this index is new and free to adopt the rule.
|
|
22425
|
+
* Exported for tests.
|
|
22426
|
+
*/
|
|
22427
|
+
function workflowSnapshotThreadIdIndexName(schemaName) {
|
|
22428
|
+
return buildConstraintName({
|
|
22429
|
+
baseName: WORKFLOW_SNAPSHOT_THREAD_ID_INDEX,
|
|
22430
|
+
schemaName: schemaName && schemaName !== "public" ? schemaName : void 0,
|
|
22431
|
+
hashWhenTruncated: true
|
|
22432
|
+
});
|
|
22433
|
+
}
|
|
22434
|
+
/**
|
|
22435
|
+
* Expression extracting the thread id embedded in a snapshot (jsonb columns only). Mirrors
|
|
22436
|
+
* the canonical extraction in `@mastra/core` (`getSnapshotMemoryInfo`), which reads one of
|
|
22437
|
+
* two layouts:
|
|
22438
|
+
* 1. agentic-loop: `context.<suspended step>.suspendPayload.__streamState.messageList.memoryInfo.threadId`
|
|
22439
|
+
* 2. durable loop: `context.input.messageListState.memoryInfo.threadId`
|
|
22440
|
+
*
|
|
22441
|
+
* `jsonb_path_query_first(jsonb, jsonpath)` is IMMUTABLE, so the expression is valid in an
|
|
22442
|
+
* expression index. The WHERE clause in listWorkflowRuns() must use this exact expression
|
|
22443
|
+
* text so the planner can match it against the index. If the snapshot layout changes in
|
|
22444
|
+
* core, this expression must be updated in lockstep or it will wrongly exclude rows.
|
|
22445
|
+
*/
|
|
22446
|
+
const WORKFLOW_SNAPSHOT_THREAD_ID_EXPR = `COALESCE(jsonb_path_query_first(snapshot, '$.context.* ? (@.status == "suspended").suspendPayload.__streamState.messageList.memoryInfo.threadId') #>> '{}', snapshot #>> '{context,input,messageListState,memoryInfo,threadId}')`;
|
|
22447
|
+
/**
|
|
22448
|
+
* Expression index on the snapshot-embedded thread id so listWorkflowRuns() threadId filters
|
|
22449
|
+
* (Agent.listSuspendedRuns) can use an index instead of detoasting every snapshot.
|
|
22450
|
+
*/
|
|
22451
|
+
function workflowSnapshotThreadIdIndexSQL(indexName, schemaName) {
|
|
22452
|
+
return `CREATE INDEX IF NOT EXISTS "${indexName}" ON ${getTableName({
|
|
22453
|
+
indexName: TABLE_WORKFLOW_SNAPSHOT,
|
|
22454
|
+
schemaName: getSchemaName(schemaName)
|
|
22455
|
+
})} ((${WORKFLOW_SNAPSHOT_THREAD_ID_EXPR}))`;
|
|
22456
|
+
}
|
|
22313
22457
|
var WorkflowsPG = class WorkflowsPG extends WorkflowsStorage {
|
|
22314
22458
|
#db;
|
|
22315
22459
|
#schema;
|
|
@@ -22382,6 +22526,7 @@ var WorkflowsPG = class WorkflowsPG extends WorkflowsStorage {
|
|
|
22382
22526
|
}));
|
|
22383
22527
|
for (const idx of WorkflowsPG.getDefaultIndexDefs(schemaPrefix)) statements.push(generateIndexSQL(idx, schemaName));
|
|
22384
22528
|
statements.push(`${workflowSnapshotStatusIndexSQL(workflowSnapshotStatusIndexName(parsedSchema), schemaName)};`);
|
|
22529
|
+
statements.push(`${workflowSnapshotThreadIdIndexSQL(workflowSnapshotThreadIdIndexName(parsedSchema), schemaName)};`);
|
|
22385
22530
|
return statements;
|
|
22386
22531
|
}
|
|
22387
22532
|
/**
|
|
@@ -22408,6 +22553,12 @@ var WorkflowsPG = class WorkflowsPG extends WorkflowsStorage {
|
|
|
22408
22553
|
} catch (error) {
|
|
22409
22554
|
this.logger?.warn?.(`Failed to create index ${indexName}:`, error);
|
|
22410
22555
|
}
|
|
22556
|
+
const threadIdIndexName = workflowSnapshotThreadIdIndexName(this.#schema);
|
|
22557
|
+
try {
|
|
22558
|
+
await this.#db.createIndexFromStatement(threadIdIndexName, workflowSnapshotThreadIdIndexSQL(threadIdIndexName, this.#schema));
|
|
22559
|
+
} catch (error) {
|
|
22560
|
+
this.logger?.warn?.(`Failed to create index ${threadIdIndexName}:`, error);
|
|
22561
|
+
}
|
|
22411
22562
|
}
|
|
22412
22563
|
async init() {
|
|
22413
22564
|
await this.#db.createTable({
|
|
@@ -22688,7 +22839,7 @@ var WorkflowsPG = class WorkflowsPG extends WorkflowsStorage {
|
|
|
22688
22839
|
}, error);
|
|
22689
22840
|
}
|
|
22690
22841
|
}
|
|
22691
|
-
async listWorkflowRuns({ workflowName, fromDate, toDate, perPage, page, resourceId, status } = {}) {
|
|
22842
|
+
async listWorkflowRuns({ workflowName, fromDate, toDate, perPage, page, resourceId, threadId, status } = {}) {
|
|
22692
22843
|
try {
|
|
22693
22844
|
const conditions = [];
|
|
22694
22845
|
const values = [];
|
|
@@ -22709,6 +22860,11 @@ var WorkflowsPG = class WorkflowsPG extends WorkflowsStorage {
|
|
|
22709
22860
|
values.push(resourceId);
|
|
22710
22861
|
paramIndex++;
|
|
22711
22862
|
} else this.logger?.warn?.(`[${TABLE_WORKFLOW_SNAPSHOT}] resourceId column not found. Skipping resourceId filter.`);
|
|
22863
|
+
if (threadId) if (await this.#db.getColumnType(TABLE_WORKFLOW_SNAPSHOT, "snapshot") === "jsonb") {
|
|
22864
|
+
conditions.push(`${WORKFLOW_SNAPSHOT_THREAD_ID_EXPR} = $${paramIndex}`);
|
|
22865
|
+
values.push(threadId);
|
|
22866
|
+
paramIndex++;
|
|
22867
|
+
} else this.logger?.warn?.(`[${TABLE_WORKFLOW_SNAPSHOT}] snapshot column is not jsonb. Skipping threadId filter.`);
|
|
22712
22868
|
if (fromDate) {
|
|
22713
22869
|
conditions.push(`"createdAt" >= $${paramIndex}`);
|
|
22714
22870
|
values.push(fromDate);
|