@mastra/pg 1.33.0-alpha.2 → 1.33.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/dist/docs/SKILL.md +1 -1
- package/dist/docs/assets/SOURCE_MAP.json +1 -1
- package/dist/docs/references/docs-memory-semantic-recall.md +4 -2
- package/dist/docs/references/reference-memory-memory-class.md +8 -6
- package/dist/index.cjs +221 -70
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +222 -71
- package/dist/index.js.map +1 -1
- package/dist/storage/db/index.d.ts +14 -0
- package/dist/storage/db/index.d.ts.map +1 -1
- package/dist/storage/domains/observability/index.d.ts +2 -1
- package/dist/storage/domains/observability/index.d.ts.map +1 -1
- package/dist/storage/domains/observability/v-next/ddl.d.ts +6 -0
- 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/signal-schema.d.ts +37 -1
- package/dist/storage/domains/observability/v-next/signal-schema.d.ts.map +1 -1
- package/dist/storage/domains/observability/v-next/thread-query.d.ts +0 -2
- package/dist/storage/domains/observability/v-next/thread-query.d.ts.map +1 -1
- package/dist/storage/domains/workflows/index.d.ts +9 -3
- package/dist/storage/domains/workflows/index.d.ts.map +1 -1
- package/dist/vector/sql-builder.d.ts.map +1 -1
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ErrorCategory, ErrorDomain, MastraError } from "@mastra/core/error";
|
|
2
2
|
import * as coreStorage from "@mastra/core/storage";
|
|
3
|
-
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_SEMANTIC_OUTBOX_SCHEMA, KnowledgeConflictError, KnowledgeNotFoundError, KnowledgeStorage, MCPClientsStorage, MCPServersStorage, METRIC_DISTINCT_COLUMNS, MastraCompositeStore, MemoryStorage, NotificationsStorage, OBSERVATIONAL_MEMORY_TABLE_SCHEMA, ObservabilityStorage, PromptBlocksStorage, RUN_FENCING_TABLE_SCHEMAS, RunFenceConflictError, 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_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_MEMORY_RUN_FENCES, 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_RUN_OWNERS, TABLE_WORKFLOW_SNAPSHOT, TABLE_WORKSPACES, TABLE_WORKSPACE_VERSIONS, ThreadStateStorage, ToolProviderConnectionsStorage, TraceStatus, UniqueViolationError, WorkflowDefinitionsStorage, WorkflowsStorage, WorkspacesStorage, assertWorkflowStepGuard, calculatePagination, canonicalizeKnowledgeScope, computeTraceStatus, createKnowledgeUlid, createStorageErrorId, createVectorErrorId, ensureDate, executeRetentionPrune, getDefaultValue, getSqlType, hasErrorCode, isKnowledgeScopeVisible, isRunFenceConflictError, isWorkflowStepConflictError, knowledgeScopeKey, knowledgeSemanticDocumentId, knowledgeSemanticIdempotencyKey, listBranchesArgsSchema, listFeedbackArgsSchema, listLogsArgsSchema, listMetricsArgsSchema, listScoresArgsSchema, listTracesArgsSchema, matchesExpectedWorkflowStatus, matchesRunFence, mergeWorkflowStepResult, normalizePerPage, normalizeScheduleTarget, parseDuration, parseKnowledgeNodeCursor, parseKnowledgeWikilinks, resolveListOrderBy, resolveRetentionTargets, resolveRunFence, retentionCutoffMs, runRetentionBatches, safelyParseJSON, storageMessageMatchesMetadataFilter, toTraceSpans, transformScoreRow, validateStorageMetadataFilter } from "@mastra/core/storage";
|
|
3
|
+
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_SEMANTIC_OUTBOX_SCHEMA, KnowledgeConflictError, KnowledgeNotFoundError, KnowledgeStorage, MCPClientsStorage, MCPServersStorage, METRIC_DISTINCT_COLUMNS, MastraCompositeStore, MemoryStorage, NotificationsStorage, OBSERVATIONAL_MEMORY_TABLE_SCHEMA, ObservabilityStorage, PromptBlocksStorage, RUN_FENCING_TABLE_SCHEMAS, RunFenceConflictError, 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_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_MEMORY_RUN_FENCES, 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_RUN_OWNERS, TABLE_WORKFLOW_SNAPSHOT, TABLE_WORKSPACES, TABLE_WORKSPACE_VERSIONS, ThreadStateStorage, ToolProviderConnectionsStorage, TraceStatus, UniqueViolationError, WorkflowDefinitionsStorage, WorkflowsStorage, WorkspacesStorage, assertWorkflowStepGuard, calculatePagination, canonicalizeKnowledgeScope, computeTraceStatus, createKnowledgeUlid, createStorageErrorId, createVectorErrorId, ensureDate, executeRetentionPrune, getDefaultValue, getSqlType, getStringAttribute, hasErrorCode, isKnowledgeScopeVisible, isRunFenceConflictError, isWorkflowStepConflictError, knowledgeScopeKey, knowledgeSemanticDocumentId, knowledgeSemanticIdempotencyKey, listBranchesArgsSchema, listFeedbackArgsSchema, listLogsArgsSchema, listMetricsArgsSchema, listScoresArgsSchema, listTracesArgsSchema, matchesExpectedWorkflowStatus, matchesRunFence, mergeWorkflowStepResult, normalizePerPage, normalizeScheduleTarget, parseDuration, parseKnowledgeNodeCursor, parseKnowledgeWikilinks, resolveListOrderBy, resolveRetentionTargets, resolveRunFence, retentionCutoffMs, runRetentionBatches, safelyParseJSON, storageMessageMatchesMetadataFilter, toTraceSpans, transformScoreRow, validateStorageMetadataFilter } from "@mastra/core/storage";
|
|
4
4
|
import { parseFieldKey, parseSqlIdentifier } from "@mastra/core/utils";
|
|
5
5
|
import { MastraVector, validateTopK, validateUpsertInput } from "@mastra/core/vector";
|
|
6
6
|
import { Mutex } from "async-mutex";
|
|
@@ -239,7 +239,7 @@ const createNumericOperator = (symbol) => {
|
|
|
239
239
|
sql: `(CASE WHEN jsonb_typeof(${jsonExtract}) = 'number' THEN (${textExtract})::numeric ${symbol} $${paramIndex}::numeric ELSE NULL END)`,
|
|
240
240
|
needsValue: true
|
|
241
241
|
};
|
|
242
|
-
|
|
242
|
+
return {
|
|
243
243
|
sql: `${textExtract} ${symbol} $${paramIndex}::text`,
|
|
244
244
|
needsValue: true
|
|
245
245
|
};
|
|
@@ -3996,6 +3996,42 @@ MIGRATION REQUIRED: Duplicate spans detected in ${duplicateInfo.tableName}\n====
|
|
|
3996
3996
|
}, error);
|
|
3997
3997
|
}
|
|
3998
3998
|
}
|
|
3999
|
+
/**
|
|
4000
|
+
* Runs one UPDATE per record in a transaction, changing a row only while every
|
|
4001
|
+
* column in `nullColumns` is still NULL. Never inserts. Returns, in input order,
|
|
4002
|
+
* whether each update changed a row.
|
|
4003
|
+
*/
|
|
4004
|
+
async batchUpdateWhereNull({ tableName, updates, nullColumns }) {
|
|
4005
|
+
const nullConditions = nullColumns.map((column) => ` AND "${parseSqlIdentifier(column, "column name")}" IS NULL`).join("");
|
|
4006
|
+
try {
|
|
4007
|
+
return await this.client.tx(async (tx) => {
|
|
4008
|
+
const applied = [];
|
|
4009
|
+
for (const update of updates) {
|
|
4010
|
+
const query = await this.buildUpdateQuery({
|
|
4011
|
+
tableName,
|
|
4012
|
+
...update
|
|
4013
|
+
});
|
|
4014
|
+
if (!query) {
|
|
4015
|
+
applied.push(false);
|
|
4016
|
+
continue;
|
|
4017
|
+
}
|
|
4018
|
+
const rows = await tx.any(`${query.sql}${nullConditions} RETURNING 1`, query.values);
|
|
4019
|
+
applied.push(rows.length > 0);
|
|
4020
|
+
}
|
|
4021
|
+
return applied;
|
|
4022
|
+
});
|
|
4023
|
+
} catch (error) {
|
|
4024
|
+
throw new MastraError({
|
|
4025
|
+
id: createStorageErrorId("PG", "BATCH_UPDATE_WHERE_NULL", "FAILED"),
|
|
4026
|
+
domain: ErrorDomain.STORAGE,
|
|
4027
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
4028
|
+
details: {
|
|
4029
|
+
tableName,
|
|
4030
|
+
numberOfRecords: updates.length
|
|
4031
|
+
}
|
|
4032
|
+
}, error);
|
|
4033
|
+
}
|
|
4034
|
+
}
|
|
3999
4035
|
async batchDelete({ tableName, keys }) {
|
|
4000
4036
|
try {
|
|
4001
4037
|
if (keys.length === 0) return;
|
|
@@ -4116,9 +4152,14 @@ MIGRATION REQUIRED: Duplicate spans detected in ${duplicateInfo.tableName}\n====
|
|
|
4116
4152
|
columns: [column]
|
|
4117
4153
|
});
|
|
4118
4154
|
}
|
|
4119
|
-
async executeUpdate(client,
|
|
4155
|
+
async executeUpdate(client, args) {
|
|
4156
|
+
const query = await this.buildUpdateQuery(args);
|
|
4157
|
+
if (!query) return;
|
|
4158
|
+
await client.none(query.sql, query.values);
|
|
4159
|
+
}
|
|
4160
|
+
async buildUpdateQuery({ tableName, keys, data }) {
|
|
4120
4161
|
const filteredData = await this.filterRecordToKnownColumns(tableName, data);
|
|
4121
|
-
if (Object.keys(filteredData).length === 0) return;
|
|
4162
|
+
if (Object.keys(filteredData).length === 0) return null;
|
|
4122
4163
|
const setColumns = [];
|
|
4123
4164
|
const setValues = [];
|
|
4124
4165
|
let paramIndex = 1;
|
|
@@ -4134,12 +4175,13 @@ MIGRATION REQUIRED: Duplicate spans detected in ${duplicateInfo.tableName}\n====
|
|
|
4134
4175
|
whereConditions.push(`"${parsedKey}" = $${paramIndex++}`);
|
|
4135
4176
|
whereValues.push(this.prepareValue(value, key, tableName));
|
|
4136
4177
|
});
|
|
4137
|
-
|
|
4138
|
-
|
|
4139
|
-
|
|
4140
|
-
|
|
4141
|
-
|
|
4142
|
-
|
|
4178
|
+
return {
|
|
4179
|
+
sql: `UPDATE ${getTableName$6({
|
|
4180
|
+
indexName: tableName,
|
|
4181
|
+
schemaName: getSchemaName$6(this.schemaName)
|
|
4182
|
+
})} SET ${setColumns.join(", ")} WHERE ${whereConditions.join(" AND ")}`,
|
|
4183
|
+
values: [...setValues, ...whereValues]
|
|
4184
|
+
};
|
|
4143
4185
|
}
|
|
4144
4186
|
};
|
|
4145
4187
|
// src/storage/domains/utils.ts
|
|
@@ -12015,7 +12057,7 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
12015
12057
|
indexName: OM_TABLE,
|
|
12016
12058
|
schemaName: quotedSchemaName
|
|
12017
12059
|
});
|
|
12018
|
-
const idxPrefix = schemaPrefix ?
|
|
12060
|
+
const idxPrefix = schemaPrefix ? schemaPrefix : "";
|
|
12019
12061
|
statements.push(`CREATE INDEX IF NOT EXISTS "${idxPrefix}idx_om_lookup_key" ON ${fullOmTableName} ("lookupKey");`);
|
|
12020
12062
|
}
|
|
12021
12063
|
for (const idx of MemoryPG.getDefaultIndexDefs(schemaPrefix)) statements.push(generateIndexSQL(idx, schemaName));
|
|
@@ -15689,30 +15731,33 @@ var ObservabilityPG = class ObservabilityPG extends ObservabilityStorage {
|
|
|
15689
15731
|
}, error);
|
|
15690
15732
|
}
|
|
15691
15733
|
}
|
|
15734
|
+
#toSpanUpdates(records) {
|
|
15735
|
+
return records.map((record) => {
|
|
15736
|
+
const data = { ...record.updates };
|
|
15737
|
+
if (data.endedAt instanceof Date) {
|
|
15738
|
+
const endedAt = data.endedAt.toISOString();
|
|
15739
|
+
data.endedAt = endedAt;
|
|
15740
|
+
data.endedAtZ = endedAt;
|
|
15741
|
+
}
|
|
15742
|
+
if (data.startedAt instanceof Date) {
|
|
15743
|
+
const startedAt = data.startedAt.toISOString();
|
|
15744
|
+
data.startedAt = startedAt;
|
|
15745
|
+
data.startedAtZ = startedAt;
|
|
15746
|
+
}
|
|
15747
|
+
return {
|
|
15748
|
+
keys: {
|
|
15749
|
+
spanId: record.spanId,
|
|
15750
|
+
traceId: record.traceId
|
|
15751
|
+
},
|
|
15752
|
+
data
|
|
15753
|
+
};
|
|
15754
|
+
});
|
|
15755
|
+
}
|
|
15692
15756
|
async batchUpdateSpans(args) {
|
|
15693
15757
|
try {
|
|
15694
15758
|
return this.#db.batchUpdate({
|
|
15695
15759
|
tableName: TABLE_SPANS,
|
|
15696
|
-
updates: args.records
|
|
15697
|
-
const data = { ...record.updates };
|
|
15698
|
-
if (data.endedAt instanceof Date) {
|
|
15699
|
-
const endedAt = data.endedAt.toISOString();
|
|
15700
|
-
data.endedAt = endedAt;
|
|
15701
|
-
data.endedAtZ = endedAt;
|
|
15702
|
-
}
|
|
15703
|
-
if (data.startedAt instanceof Date) {
|
|
15704
|
-
const startedAt = data.startedAt.toISOString();
|
|
15705
|
-
data.startedAt = startedAt;
|
|
15706
|
-
data.startedAtZ = startedAt;
|
|
15707
|
-
}
|
|
15708
|
-
return {
|
|
15709
|
-
keys: {
|
|
15710
|
-
spanId: record.spanId,
|
|
15711
|
-
traceId: record.traceId
|
|
15712
|
-
},
|
|
15713
|
-
data
|
|
15714
|
-
};
|
|
15715
|
-
})
|
|
15760
|
+
updates: this.#toSpanUpdates(args.records)
|
|
15716
15761
|
});
|
|
15717
15762
|
} catch (error) {
|
|
15718
15763
|
throw new MastraError({
|
|
@@ -15722,6 +15767,25 @@ var ObservabilityPG = class ObservabilityPG extends ObservabilityStorage {
|
|
|
15722
15767
|
}, error);
|
|
15723
15768
|
}
|
|
15724
15769
|
}
|
|
15770
|
+
async batchUpdateUnendedSpans(args) {
|
|
15771
|
+
try {
|
|
15772
|
+
const applied = await this.#db.batchUpdateWhereNull({
|
|
15773
|
+
tableName: TABLE_SPANS,
|
|
15774
|
+
updates: this.#toSpanUpdates(args.records),
|
|
15775
|
+
nullColumns: ["endedAt"]
|
|
15776
|
+
});
|
|
15777
|
+
return { updated: args.records.filter((_, index) => applied[index]).map(({ traceId, spanId }) => ({
|
|
15778
|
+
traceId,
|
|
15779
|
+
spanId
|
|
15780
|
+
})) };
|
|
15781
|
+
} catch (error) {
|
|
15782
|
+
throw new MastraError({
|
|
15783
|
+
id: createStorageErrorId("PG", "BATCH_UPDATE_UNENDED_SPANS", "FAILED"),
|
|
15784
|
+
domain: ErrorDomain.STORAGE,
|
|
15785
|
+
category: ErrorCategory.USER
|
|
15786
|
+
}, error);
|
|
15787
|
+
}
|
|
15788
|
+
}
|
|
15725
15789
|
async batchDeleteTraces(args) {
|
|
15726
15790
|
this.assertUnscopedBatchDeleteTraces(args);
|
|
15727
15791
|
try {
|
|
@@ -16039,6 +16103,51 @@ const SPAN_EVENT_COLUMNS = [
|
|
|
16039
16103
|
type: "double precision",
|
|
16040
16104
|
nullable: true
|
|
16041
16105
|
},
|
|
16106
|
+
{
|
|
16107
|
+
name: "externalParentSpanId",
|
|
16108
|
+
type: "text",
|
|
16109
|
+
nullable: true
|
|
16110
|
+
},
|
|
16111
|
+
{
|
|
16112
|
+
name: "resumedFromSpanId",
|
|
16113
|
+
type: "text",
|
|
16114
|
+
nullable: true
|
|
16115
|
+
},
|
|
16116
|
+
{
|
|
16117
|
+
name: "model",
|
|
16118
|
+
type: "text",
|
|
16119
|
+
nullable: true
|
|
16120
|
+
},
|
|
16121
|
+
{
|
|
16122
|
+
name: "provider",
|
|
16123
|
+
type: "text",
|
|
16124
|
+
nullable: true
|
|
16125
|
+
},
|
|
16126
|
+
{
|
|
16127
|
+
name: "outcome",
|
|
16128
|
+
type: "text",
|
|
16129
|
+
nullable: true
|
|
16130
|
+
},
|
|
16131
|
+
{
|
|
16132
|
+
name: "stopReason",
|
|
16133
|
+
type: "text",
|
|
16134
|
+
nullable: true
|
|
16135
|
+
},
|
|
16136
|
+
{
|
|
16137
|
+
name: "timeToFirstTokenMs",
|
|
16138
|
+
type: "double precision",
|
|
16139
|
+
nullable: true
|
|
16140
|
+
},
|
|
16141
|
+
{
|
|
16142
|
+
name: "errorCount",
|
|
16143
|
+
type: "integer",
|
|
16144
|
+
nullable: true
|
|
16145
|
+
},
|
|
16146
|
+
{
|
|
16147
|
+
name: "stopReasonContext",
|
|
16148
|
+
type: "jsonb",
|
|
16149
|
+
nullable: true
|
|
16150
|
+
},
|
|
16042
16151
|
{
|
|
16043
16152
|
name: "tags",
|
|
16044
16153
|
type: "text[]",
|
|
@@ -16747,6 +16856,26 @@ function allTableDDL(schema, mode) {
|
|
|
16747
16856
|
];
|
|
16748
16857
|
}
|
|
16749
16858
|
/**
|
|
16859
|
+
* Span event columns added after the table first shipped, with their types. All
|
|
16860
|
+
* nullable with no default, so each ALTER is a catalog-only change; rows written
|
|
16861
|
+
* before it read NULL and readers fall back to the payload or attributes.
|
|
16862
|
+
*/
|
|
16863
|
+
const ADDED_SPAN_COLUMNS = [
|
|
16864
|
+
["inputPreview", "text"],
|
|
16865
|
+
["outputPreview", "text"],
|
|
16866
|
+
["errorPreview", "text"],
|
|
16867
|
+
["timeToFirstChunkMs", "double precision"],
|
|
16868
|
+
["externalParentSpanId", "text"],
|
|
16869
|
+
["resumedFromSpanId", "text"],
|
|
16870
|
+
["model", "text"],
|
|
16871
|
+
["provider", "text"],
|
|
16872
|
+
["outcome", "text"],
|
|
16873
|
+
["stopReason", "text"],
|
|
16874
|
+
["timeToFirstTokenMs", "double precision"],
|
|
16875
|
+
["errorCount", "integer"],
|
|
16876
|
+
["stopReasonContext", "jsonb"]
|
|
16877
|
+
];
|
|
16878
|
+
/**
|
|
16750
16879
|
* Additive column migrations for tables created by an older version of this
|
|
16751
16880
|
* schema. `CREATE TABLE IF NOT EXISTS` is a no-op on an existing table, so new
|
|
16752
16881
|
* columns have to be added out of band.
|
|
@@ -16763,20 +16892,11 @@ function additiveColumns(schema) {
|
|
|
16763
16892
|
column: "isPending",
|
|
16764
16893
|
ddl: `ALTER TABLE ${qualifiedTable(schema, TABLE_SPAN_EVENTS)} ADD COLUMN IF NOT EXISTS "isPending" boolean NOT NULL DEFAULT false`
|
|
16765
16894
|
},
|
|
16766
|
-
...[
|
|
16767
|
-
"inputPreview",
|
|
16768
|
-
"outputPreview",
|
|
16769
|
-
"errorPreview"
|
|
16770
|
-
].map((column) => ({
|
|
16895
|
+
...ADDED_SPAN_COLUMNS.map(([column, type]) => ({
|
|
16771
16896
|
table: TABLE_SPAN_EVENTS,
|
|
16772
16897
|
column,
|
|
16773
|
-
ddl: `ALTER TABLE ${qualifiedTable(schema, TABLE_SPAN_EVENTS)} ADD COLUMN IF NOT EXISTS "${column}"
|
|
16898
|
+
ddl: `ALTER TABLE ${qualifiedTable(schema, TABLE_SPAN_EVENTS)} ADD COLUMN IF NOT EXISTS "${column}" ${type}`
|
|
16774
16899
|
})),
|
|
16775
|
-
{
|
|
16776
|
-
table: TABLE_SPAN_EVENTS,
|
|
16777
|
-
column: "timeToFirstChunkMs",
|
|
16778
|
-
ddl: `ALTER TABLE ${qualifiedTable(schema, TABLE_SPAN_EVENTS)} ADD COLUMN IF NOT EXISTS "timeToFirstChunkMs" double precision`
|
|
16779
|
-
},
|
|
16780
16900
|
{
|
|
16781
16901
|
table: TABLE_FEEDBACK_EVENTS,
|
|
16782
16902
|
column: "reviewStatus",
|
|
@@ -17329,6 +17449,11 @@ const PROMOTED_KEYS = /* @__PURE__ */ new Set([
|
|
|
17329
17449
|
"executionSource",
|
|
17330
17450
|
"serviceName"
|
|
17331
17451
|
]);
|
|
17452
|
+
function nullableNumber$1(value) {
|
|
17453
|
+
if (value == null || value === "") return null;
|
|
17454
|
+
const n = Number(value);
|
|
17455
|
+
return Number.isNaN(n) ? null : n;
|
|
17456
|
+
}
|
|
17332
17457
|
function nullableString(value) {
|
|
17333
17458
|
if (typeof value === "string") return value === "" ? null : value;
|
|
17334
17459
|
if (value == null) return null;
|
|
@@ -17490,6 +17615,15 @@ function spanRecordToRow(span) {
|
|
|
17490
17615
|
startedAt: toIsoOrDate(span.startedAt),
|
|
17491
17616
|
endedAt: toIsoOrDate(endedAt),
|
|
17492
17617
|
timeToFirstChunkMs: span.timeToFirstChunkMs ?? null,
|
|
17618
|
+
externalParentSpanId: span.externalParentSpanId ?? null,
|
|
17619
|
+
resumedFromSpanId: span.resumedFromSpanId ?? null,
|
|
17620
|
+
model: span.model ?? null,
|
|
17621
|
+
provider: span.provider ?? null,
|
|
17622
|
+
outcome: span.outcome ?? null,
|
|
17623
|
+
stopReason: span.stopReason ?? null,
|
|
17624
|
+
stopReasonContext: jsonField(span.stopReasonContext),
|
|
17625
|
+
timeToFirstTokenMs: span.timeToFirstTokenMs ?? null,
|
|
17626
|
+
errorCount: span.errorCount ?? null,
|
|
17493
17627
|
tags: normalizeTags(span.tags),
|
|
17494
17628
|
metadataSearch: buildMetadataSearch(metadata),
|
|
17495
17629
|
metadataRaw: jsonField(metadata),
|
|
@@ -17519,6 +17653,7 @@ function rowToSpanRecord(row) {
|
|
|
17519
17653
|
const startedAt = toDate(row.startedAt);
|
|
17520
17654
|
const endedAt = spanRowEndedAt(row, startedAt);
|
|
17521
17655
|
const error = parsedJson(row.error);
|
|
17656
|
+
const attributes = parsedJson(row.attributes);
|
|
17522
17657
|
const { executionSource, ...ctx } = rowToCommonContext(row);
|
|
17523
17658
|
return {
|
|
17524
17659
|
...ctx,
|
|
@@ -17531,10 +17666,19 @@ function rowToSpanRecord(row) {
|
|
|
17531
17666
|
isEvent: Boolean(row.isEvent),
|
|
17532
17667
|
startedAt,
|
|
17533
17668
|
endedAt,
|
|
17669
|
+
externalParentSpanId: nullableString(row.externalParentSpanId),
|
|
17670
|
+
resumedFromSpanId: nullableString(row.resumedFromSpanId),
|
|
17671
|
+
model: nullableString(row.model) ?? getStringAttribute(attributes, "model"),
|
|
17672
|
+
provider: nullableString(row.provider) ?? getStringAttribute(attributes, "provider"),
|
|
17673
|
+
outcome: nullableString(row.outcome),
|
|
17674
|
+
stopReason: nullableString(row.stopReason),
|
|
17675
|
+
stopReasonContext: parsedJson(row.stopReasonContext) ?? null,
|
|
17676
|
+
timeToFirstTokenMs: nullableNumber$1(row.timeToFirstTokenMs),
|
|
17677
|
+
errorCount: nullableNumber$1(row.errorCount),
|
|
17534
17678
|
tags: normalizeTags(row.tags),
|
|
17535
17679
|
metadata: parsedJson(row.metadataRaw) ?? void 0,
|
|
17536
17680
|
scope: parsedJson(row.scope) ?? void 0,
|
|
17537
|
-
attributes:
|
|
17681
|
+
attributes: attributes ?? void 0,
|
|
17538
17682
|
links: parsedJson(row.links) ?? void 0,
|
|
17539
17683
|
input: parsedJson(row.input) ?? void 0,
|
|
17540
17684
|
output: parsedJson(row.output) ?? void 0,
|
|
@@ -20560,7 +20704,7 @@ async function queryThreadRows(client, schema, plan, timeoutMs, strategy = "auto
|
|
|
20560
20704
|
return `"${field}" ${field === "organizationId" || field === "resourceId" ? "IS NOT DISTINCT FROM" : "="} $${values.length}`;
|
|
20561
20705
|
}).join(" AND ")})`;
|
|
20562
20706
|
}));
|
|
20563
|
-
const payloads = await run(`SELECT "organizationId", "traceId", "cursorId",
|
|
20707
|
+
const payloads = await run(`SELECT "organizationId", "traceId", "cursorId", ${contextFields.map((field) => `"${field}"`).join(", ")},
|
|
20564
20708
|
CASE WHEN "spanType" = 'agent_run' THEN "timeToFirstChunkMs" END AS "timeToFirstChunkMs",
|
|
20565
20709
|
CASE WHEN error IS NULL THEN 'success' ELSE 'error' END AS status,
|
|
20566
20710
|
${[
|
|
@@ -20575,30 +20719,10 @@ async function queryThreadRows(client, schema, plan, timeoutMs, strategy = "auto
|
|
|
20575
20719
|
String(version)
|
|
20576
20720
|
]);
|
|
20577
20721
|
const byRoot = new Map(payloads.map((row) => [key(row.organizationId, row.traceId, row.cursorId), row]));
|
|
20578
|
-
const agents = page.filter((row) => byRoot.get(key(row.organizationId, row.firstTraceId, row.firstCursorId))?.spanType === "agent_run");
|
|
20579
|
-
const models = /* @__PURE__ */ new Map();
|
|
20580
|
-
if (agents.length) {
|
|
20581
|
-
const modelValues = [];
|
|
20582
|
-
const rows = await run(`SELECT DISTINCT ON ("organizationId", "traceId") "organizationId", "traceId",
|
|
20583
|
-
CASE WHEN jsonb_typeof(attributes -> 'model') = 'string' THEN attributes ->> 'model' END AS model,
|
|
20584
|
-
CASE WHEN jsonb_typeof(attributes -> 'provider') = 'string' THEN attributes ->> 'provider' END AS provider
|
|
20585
|
-
FROM ${table} WHERE "spanType" = 'model_generation' AND NOT "isPending" AND (${agents.map((row) => `(${Object.entries({
|
|
20586
|
-
organizationId: row.organizationId,
|
|
20587
|
-
resourceId: row.resourceId,
|
|
20588
|
-
traceId: row.firstTraceId,
|
|
20589
|
-
parentSpanId: row.firstSpanId
|
|
20590
|
-
}).map(([field, value]) => {
|
|
20591
|
-
modelValues.push(value);
|
|
20592
|
-
return `"${field}" ${field === "organizationId" || field === "resourceId" ? "IS NOT DISTINCT FROM" : "="} $${modelValues.length}`;
|
|
20593
|
-
}).join(" AND ")})`).join(" OR ")})
|
|
20594
|
-
ORDER BY "organizationId", "traceId", "startedAt", "spanId" COLLATE "C", "cursorId" DESC`, modelValues);
|
|
20595
|
-
for (const row of rows) models.set(JSON.stringify([row.organizationId, row.traceId]), row);
|
|
20596
|
-
}
|
|
20597
20722
|
const threads = page.flatMap((row) => {
|
|
20598
20723
|
const first = byRoot.get(key(row.organizationId, row.firstTraceId, row.firstCursorId));
|
|
20599
20724
|
const last = byRoot.get(key(row.organizationId, row.lastTraceId, row.lastCursorId));
|
|
20600
20725
|
if (!first || !last) return [];
|
|
20601
|
-
const model = models.get(JSON.stringify([row.organizationId, row.firstTraceId]));
|
|
20602
20726
|
return [coreStorage.threadQueryRowSchema.parse({
|
|
20603
20727
|
organizationId: row.organizationId,
|
|
20604
20728
|
threadId: row.threadId,
|
|
@@ -20610,8 +20734,6 @@ async function queryThreadRows(client, schema, plan, timeoutMs, strategy = "auto
|
|
|
20610
20734
|
endedAt: row.endedAt.toISOString(),
|
|
20611
20735
|
traceCount: Number(row.traceCount),
|
|
20612
20736
|
timeToFirstChunkMs: first.timeToFirstChunkMs,
|
|
20613
|
-
model: model?.model ?? null,
|
|
20614
|
-
provider: model?.provider ?? null,
|
|
20615
20737
|
inputPreview: readPreview(first.inputPreview, first.input),
|
|
20616
20738
|
outputPreview: readPreview(last.outputPreview, last.output),
|
|
20617
20739
|
errorPreview: readPreview(last.errorPreview, last.error)
|
|
@@ -25595,6 +25717,13 @@ var WorkflowsPG = class WorkflowsPG extends WorkflowsStorage {
|
|
|
25595
25717
|
supportsConcurrentUpdates() {
|
|
25596
25718
|
return true;
|
|
25597
25719
|
}
|
|
25720
|
+
supportsGuardedSnapshotWrites() {
|
|
25721
|
+
return true;
|
|
25722
|
+
}
|
|
25723
|
+
/** SQL for a snapshot's status. Legacy json/text columns can hold escapes that fail a jsonb cast (#11563). */
|
|
25724
|
+
async #statusExpression(column) {
|
|
25725
|
+
return await this.#db.getColumnType(TABLE_WORKFLOW_SNAPSHOT, "snapshot") === "jsonb" ? `${column} ->> 'status'` : `regexp_replace(${column}::text, '\\\\u(0000|[Dd][89A-Fa-f][0-9A-Fa-f]{2})', '', 'g')::jsonb ->> 'status'`;
|
|
25726
|
+
}
|
|
25598
25727
|
parseWorkflowRun(row) {
|
|
25599
25728
|
let parsedSnapshot = row.snapshot;
|
|
25600
25729
|
if (typeof parsedSnapshot === "string") try {
|
|
@@ -25990,20 +26119,22 @@ var WorkflowsPG = class WorkflowsPG extends WorkflowsStorage {
|
|
|
25990
26119
|
}, error);
|
|
25991
26120
|
}
|
|
25992
26121
|
}
|
|
25993
|
-
async persistWorkflowSnapshot({ workflowName, runId, resourceId, snapshot, createdAt, updatedAt, fence }) {
|
|
26122
|
+
async persistWorkflowSnapshot({ workflowName, runId, resourceId, snapshot, createdAt, updatedAt, fence, expectedStatus }) {
|
|
25994
26123
|
try {
|
|
25995
26124
|
const now = /* @__PURE__ */ new Date();
|
|
25996
26125
|
const createdAtValue = createdAt ? createdAt : now;
|
|
25997
26126
|
const updatedAtValue = updatedAt ? updatedAt : now;
|
|
25998
26127
|
const sanitizedSnapshot = toPgJson(snapshot);
|
|
25999
|
-
|
|
26128
|
+
const guard = expectedStatus === void 0 ? "" : ` WHERE ${await this.#statusExpression("t.snapshot")} = ANY($9::text[])`;
|
|
26129
|
+
return await withRunFence(this.#db.client, this.#runOwnersTable(), resolveRunFence(this, fence, runId), "persistWorkflowSnapshot", (q) => q.oneOrNone(`INSERT INTO ${getTableName({
|
|
26000
26130
|
indexName: TABLE_WORKFLOW_SNAPSHOT,
|
|
26001
26131
|
schemaName: getSchemaName(this.#schema)
|
|
26002
26132
|
})} AS t
|
|
26003
26133
|
(workflow_name, run_id, "resourceId", snapshot, "createdAt", "updatedAt", "createdAtZ", "updatedAtZ")
|
|
26004
26134
|
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
|
|
26005
26135
|
ON CONFLICT (workflow_name, run_id) DO UPDATE
|
|
26006
|
-
SET "resourceId" = COALESCE($3, t."resourceId"), snapshot = $4, "updatedAt" = $6, "updatedAtZ" = $8
|
|
26136
|
+
SET "resourceId" = COALESCE($3, t."resourceId"), snapshot = $4, "updatedAt" = $6, "updatedAtZ" = $8${guard}
|
|
26137
|
+
RETURNING 1 AS written`, [
|
|
26007
26138
|
workflowName,
|
|
26008
26139
|
runId,
|
|
26009
26140
|
resourceId,
|
|
@@ -26011,8 +26142,9 @@ var WorkflowsPG = class WorkflowsPG extends WorkflowsStorage {
|
|
|
26011
26142
|
createdAtValue,
|
|
26012
26143
|
updatedAtValue,
|
|
26013
26144
|
createdAtValue,
|
|
26014
|
-
updatedAtValue
|
|
26015
|
-
|
|
26145
|
+
updatedAtValue,
|
|
26146
|
+
...expectedStatus === void 0 ? [] : [Array.isArray(expectedStatus) ? expectedStatus : [expectedStatus]]
|
|
26147
|
+
])) !== null;
|
|
26016
26148
|
} catch (error) {
|
|
26017
26149
|
if (isRunFenceConflictError(error)) throw error;
|
|
26018
26150
|
throw new MastraError({
|
|
@@ -26022,6 +26154,25 @@ var WorkflowsPG = class WorkflowsPG extends WorkflowsStorage {
|
|
|
26022
26154
|
}, error);
|
|
26023
26155
|
}
|
|
26024
26156
|
}
|
|
26157
|
+
async loadWorkflowRunStatus({ workflowName, runId }) {
|
|
26158
|
+
try {
|
|
26159
|
+
const statusExpr = await this.#statusExpression("snapshot");
|
|
26160
|
+
return (await this.#db.client.oneOrNone(`SELECT ${statusExpr} AS status FROM ${getTableName({
|
|
26161
|
+
indexName: TABLE_WORKFLOW_SNAPSHOT,
|
|
26162
|
+
schemaName: getSchemaName(this.#schema)
|
|
26163
|
+
})} WHERE "workflow_name" = $1 AND "run_id" = $2 ORDER BY "createdAt" DESC LIMIT 1`, [workflowName, runId]))?.status ?? null;
|
|
26164
|
+
} catch (error) {
|
|
26165
|
+
throw new MastraError({
|
|
26166
|
+
id: createStorageErrorId("PG", "LOAD_WORKFLOW_RUN_STATUS", "FAILED"),
|
|
26167
|
+
domain: ErrorDomain.STORAGE,
|
|
26168
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
26169
|
+
details: {
|
|
26170
|
+
workflowName,
|
|
26171
|
+
runId
|
|
26172
|
+
}
|
|
26173
|
+
}, error);
|
|
26174
|
+
}
|
|
26175
|
+
}
|
|
26025
26176
|
async loadWorkflowSnapshot({ workflowName, runId }) {
|
|
26026
26177
|
try {
|
|
26027
26178
|
const result = await this.#db.load({
|