@mastra/pg 1.31.0-alpha.0 → 1.31.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/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 -2
- package/dist/docs/references/docs-memory-working-memory.md +16 -0
- package/dist/docs/references/reference-memory-memory-class.md +2 -2
- package/dist/docs/references/reference-processors-message-history-processor.md +3 -2
- package/dist/docs/references/reference-processors-semantic-recall-processor.md +2 -3
- package/dist/docs/references/reference-processors-working-memory-processor.md +3 -2
- package/dist/docs/references/reference-rag-metadata-filters.md +1 -1
- package/dist/docs/references/reference-rag-vector-databases.md +1 -1
- package/dist/index.cjs +111 -25
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +111 -25
- package/dist/index.js.map +1 -1
- package/dist/storage/db/index.d.ts +9 -0
- package/dist/storage/db/index.d.ts.map +1 -1
- package/dist/storage/db/schema-snapshot.d.ts +7 -1
- package/dist/storage/db/schema-snapshot.d.ts.map +1 -1
- package/dist/storage/domains/memory/index.d.ts +5 -0
- package/dist/storage/domains/memory/index.d.ts.map +1 -1
- package/dist/storage/domains/workflows/index.d.ts.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -2483,7 +2483,7 @@ async function loadSchemaSnapshot(client, schemaName) {
|
|
|
2483
2483
|
AND c.relkind IN ('r', 'p')
|
|
2484
2484
|
AND a.attnum > 0
|
|
2485
2485
|
AND NOT a.attisdropped`, [schema]),
|
|
2486
|
-
client.manyOrNone(`SELECT c.relname AS indexname, i.indisreplident AS is_replica_identity, i.indisprimary AS is_primary
|
|
2486
|
+
client.manyOrNone(`SELECT c.relname AS indexname, i.indisreplident AS is_replica_identity, i.indisprimary AS is_primary, i.indisvalid AS is_valid
|
|
2487
2487
|
FROM pg_catalog.pg_index i
|
|
2488
2488
|
JOIN pg_catalog.pg_class c ON c.oid = i.indexrelid
|
|
2489
2489
|
JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
|
|
@@ -2508,8 +2508,10 @@ async function loadSchemaSnapshot(client, schemaName) {
|
|
|
2508
2508
|
const indexes = /* @__PURE__ */ new Set();
|
|
2509
2509
|
const replicaIdentityIndexes = /* @__PURE__ */ new Set();
|
|
2510
2510
|
const primaryKeyIndexes = /* @__PURE__ */ new Set();
|
|
2511
|
+
const invalidIndexes = /* @__PURE__ */ new Set();
|
|
2511
2512
|
for (const row of indexRows) {
|
|
2512
|
-
indexes.add(row.indexname);
|
|
2513
|
+
if (row.is_valid) indexes.add(row.indexname);
|
|
2514
|
+
else invalidIndexes.add(row.indexname);
|
|
2513
2515
|
if (row.is_replica_identity) replicaIdentityIndexes.add(row.indexname);
|
|
2514
2516
|
if (row.is_primary) primaryKeyIndexes.add(row.indexname.toLowerCase());
|
|
2515
2517
|
}
|
|
@@ -2520,7 +2522,8 @@ async function loadSchemaSnapshot(client, schemaName) {
|
|
|
2520
2522
|
columnTypes,
|
|
2521
2523
|
indexes,
|
|
2522
2524
|
replicaIdentityIndexes,
|
|
2523
|
-
primaryKeyIndexes
|
|
2525
|
+
primaryKeyIndexes,
|
|
2526
|
+
invalidIndexes
|
|
2524
2527
|
};
|
|
2525
2528
|
}
|
|
2526
2529
|
//#endregion
|
|
@@ -3668,11 +3671,8 @@ MIGRATION REQUIRED: Duplicate spans detected in ${duplicateInfo.tableName}\n====
|
|
|
3668
3671
|
schemaName: getSchemaName$6(this.schemaName)
|
|
3669
3672
|
});
|
|
3670
3673
|
const snapshot = this.schemaSnapshot;
|
|
3671
|
-
if (snapshot)
|
|
3672
|
-
|
|
3673
|
-
} else if (await this.client.oneOrNone(`SELECT 1 FROM pg_indexes
|
|
3674
|
-
WHERE indexname = $1
|
|
3675
|
-
AND schemaname = $2`, [name, schemaName])) return;
|
|
3674
|
+
if (snapshot?.indexes.has(name)) return;
|
|
3675
|
+
if (!await this.prepareIndexBuild(name, schemaName)) return;
|
|
3676
3676
|
const uniqueStr = unique ? "UNIQUE " : "";
|
|
3677
3677
|
const concurrentStr = concurrent ? "CONCURRENTLY " : "";
|
|
3678
3678
|
const methodStr = method !== "btree" ? `USING ${method} ` : "";
|
|
@@ -3691,16 +3691,9 @@ MIGRATION REQUIRED: Duplicate spans detected in ${duplicateInfo.tableName}\n====
|
|
|
3691
3691
|
let withStr = "";
|
|
3692
3692
|
if (storage && Object.keys(storage).length > 0) withStr = ` WITH (${Object.entries(storage).map(([key, value]) => `${key} = ${value}`).join(", ")})`;
|
|
3693
3693
|
const sql = `CREATE ${uniqueStr}INDEX ${concurrentStr}${`"${parseSqlIdentifier(name, "index name")}"`} ON ${fullTableName} ${methodStr}(${columnsStr})${withStr}${tablespaceStr}${whereStr}`;
|
|
3694
|
-
await this.
|
|
3694
|
+
await this.timedIndexBuild(name, sql);
|
|
3695
3695
|
snapshot?.indexes.add(name);
|
|
3696
3696
|
} catch (error) {
|
|
3697
|
-
if (error instanceof Error && error.message.includes("CONCURRENTLY")) {
|
|
3698
|
-
const retryOptions = {
|
|
3699
|
-
...options,
|
|
3700
|
-
concurrent: false
|
|
3701
|
-
};
|
|
3702
|
-
return this.createIndex(retryOptions);
|
|
3703
|
-
}
|
|
3704
3697
|
throw new MastraError({
|
|
3705
3698
|
id: createStorageErrorId("PG", "INDEX_CREATE", "FAILED"),
|
|
3706
3699
|
domain: ErrorDomain.STORAGE,
|
|
@@ -3724,9 +3717,43 @@ MIGRATION REQUIRED: Duplicate spans detected in ${duplicateInfo.tableName}\n====
|
|
|
3724
3717
|
async createIndexFromStatement(indexName, sql) {
|
|
3725
3718
|
const snapshot = this.schemaSnapshot;
|
|
3726
3719
|
if (snapshot?.indexes.has(indexName)) return;
|
|
3727
|
-
await this.
|
|
3720
|
+
if (!await this.prepareIndexBuild(indexName, this.schemaName || "public")) return;
|
|
3721
|
+
await this.timedIndexBuild(indexName, sql);
|
|
3728
3722
|
snapshot?.indexes.add(indexName);
|
|
3729
3723
|
}
|
|
3724
|
+
/**
|
|
3725
|
+
* Decides whether `indexName` still needs building. Returns false when a valid
|
|
3726
|
+
* index already exists, or when another session is currently building it.
|
|
3727
|
+
* An invalid index left by an interrupted `CREATE INDEX CONCURRENTLY` is
|
|
3728
|
+
* dropped (concurrently) so the caller rebuilds it — `IF NOT EXISTS` would
|
|
3729
|
+
* otherwise keep the broken index forever.
|
|
3730
|
+
*/
|
|
3731
|
+
async prepareIndexBuild(indexName, schemaName) {
|
|
3732
|
+
const snapshot = this.schemaSnapshot;
|
|
3733
|
+
if (snapshot && !snapshot.invalidIndexes.has(indexName)) return true;
|
|
3734
|
+
const existing = await this.client.oneOrNone(`SELECT i.indisvalid AS is_valid,
|
|
3735
|
+
EXISTS (SELECT 1 FROM pg_stat_progress_create_index p WHERE p.index_relid = c.oid) AS building
|
|
3736
|
+
FROM pg_catalog.pg_index i
|
|
3737
|
+
JOIN pg_catalog.pg_class c ON c.oid = i.indexrelid
|
|
3738
|
+
JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
|
|
3739
|
+
WHERE c.relname = $1 AND n.nspname = $2`, [indexName, schemaName]);
|
|
3740
|
+
if (!existing) return true;
|
|
3741
|
+
if (existing.is_valid) return false;
|
|
3742
|
+
if (existing.building) {
|
|
3743
|
+
this.logger.warn(`Index ${indexName} is being built by another session; skipping`);
|
|
3744
|
+
return false;
|
|
3745
|
+
}
|
|
3746
|
+
this.logger.warn(`Dropping invalid index ${indexName} left by an interrupted build; rebuilding it`);
|
|
3747
|
+
const quotedIndexName = `"${parseSqlIdentifier(indexName, "index name")}"`;
|
|
3748
|
+
await this.client.none(`DROP INDEX CONCURRENTLY IF EXISTS ${getSchemaName$6(this.schemaName)}.${quotedIndexName}`);
|
|
3749
|
+
return true;
|
|
3750
|
+
}
|
|
3751
|
+
async timedIndexBuild(indexName, sql) {
|
|
3752
|
+
const startedAt = Date.now();
|
|
3753
|
+
this.logger.info(`Creating index ${indexName}`);
|
|
3754
|
+
await this.client.none(sql);
|
|
3755
|
+
this.logger.info(`Created index ${indexName} in ${Date.now() - startedAt}ms`);
|
|
3756
|
+
}
|
|
3730
3757
|
async dropIndex(indexName) {
|
|
3731
3758
|
try {
|
|
3732
3759
|
const schemaName = this.schemaName || "public";
|
|
@@ -10471,6 +10498,7 @@ function dedupeMessagesForSave(messages) {
|
|
|
10471
10498
|
var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
10472
10499
|
supportsPartialThreadUpdate = true;
|
|
10473
10500
|
supportsObservationalMemory = true;
|
|
10501
|
+
supportsAtomicWorkingMemoryMerge = true;
|
|
10474
10502
|
supportsObservationalMemoryHistorySearch = true;
|
|
10475
10503
|
/**
|
|
10476
10504
|
* Retention-eligible tables. `threads`, `messages`, and `resources` all anchor
|
|
@@ -11817,6 +11845,57 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
11817
11845
|
metadata: metadataJson ? JSON.parse(metadataJson) : resource.metadata
|
|
11818
11846
|
};
|
|
11819
11847
|
}
|
|
11848
|
+
async mergeResourceWorkingMemory({ resourceId, merge }) {
|
|
11849
|
+
const tableName = getTableName$3({
|
|
11850
|
+
indexName: TABLE_RESOURCES,
|
|
11851
|
+
schemaName: getSchemaName$3(this.#schema)
|
|
11852
|
+
});
|
|
11853
|
+
const callbackError = {};
|
|
11854
|
+
try {
|
|
11855
|
+
return await this.#db.client.tx(async (t) => {
|
|
11856
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
11857
|
+
await t.none(`INSERT INTO ${tableName} (id, metadata, "createdAt", "createdAtZ", "updatedAt", "updatedAtZ")
|
|
11858
|
+
VALUES ($1, $2, $3, $4, $5, $6) ON CONFLICT (id) DO NOTHING`, [
|
|
11859
|
+
resourceId,
|
|
11860
|
+
toPgJson({}),
|
|
11861
|
+
now,
|
|
11862
|
+
now,
|
|
11863
|
+
now,
|
|
11864
|
+
now
|
|
11865
|
+
]);
|
|
11866
|
+
await t.one(`SELECT id FROM ${tableName} WHERE id = $1 FOR UPDATE`, [resourceId]);
|
|
11867
|
+
const existing = await this.#getResourceById(t, resourceId);
|
|
11868
|
+
let workingMemory;
|
|
11869
|
+
try {
|
|
11870
|
+
workingMemory = merge(existing.workingMemory ?? void 0);
|
|
11871
|
+
} catch (error) {
|
|
11872
|
+
callbackError.error = error;
|
|
11873
|
+
throw error;
|
|
11874
|
+
}
|
|
11875
|
+
const updatedAt = /* @__PURE__ */ new Date();
|
|
11876
|
+
const updatedAtStr = updatedAt.toISOString();
|
|
11877
|
+
await t.none(`UPDATE ${tableName} SET "workingMemory" = $1, "updatedAt" = $2, "updatedAtZ" = $3 WHERE id = $4`, [
|
|
11878
|
+
workingMemory,
|
|
11879
|
+
updatedAtStr,
|
|
11880
|
+
updatedAtStr,
|
|
11881
|
+
resourceId
|
|
11882
|
+
]);
|
|
11883
|
+
return {
|
|
11884
|
+
...existing,
|
|
11885
|
+
workingMemory,
|
|
11886
|
+
updatedAt
|
|
11887
|
+
};
|
|
11888
|
+
});
|
|
11889
|
+
} catch (error) {
|
|
11890
|
+
if (error === callbackError.error || error instanceof MastraError) throw error;
|
|
11891
|
+
throw new MastraError({
|
|
11892
|
+
id: createStorageErrorId("PG", "MERGE_RESOURCE_WORKING_MEMORY", "FAILED"),
|
|
11893
|
+
domain: ErrorDomain.STORAGE,
|
|
11894
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
11895
|
+
details: { resourceId }
|
|
11896
|
+
}, error);
|
|
11897
|
+
}
|
|
11898
|
+
}
|
|
11820
11899
|
async updateResource({ resourceId, workingMemory, metadata }) {
|
|
11821
11900
|
const existingResource = await this.#getResourceById(this.#db.client, resourceId);
|
|
11822
11901
|
if (!existingResource) {
|
|
@@ -23184,12 +23263,17 @@ function workflowSnapshotStatusIndexName(schemaName) {
|
|
|
23184
23263
|
/**
|
|
23185
23264
|
* Expression index on `(workflow_name, snapshot->>'status', "createdAt" DESC)` so
|
|
23186
23265
|
* listWorkflowRuns() status filters can use an index instead of scanning every snapshot.
|
|
23266
|
+
*
|
|
23267
|
+
* `concurrently` is set by init, which may build the index on a large existing table while
|
|
23268
|
+
* other processes keep writing to it. The exported DDL stays plain because migration
|
|
23269
|
+
* tooling often wraps statements in a transaction, where CONCURRENTLY is rejected.
|
|
23187
23270
|
*/
|
|
23188
|
-
function workflowSnapshotStatusIndexSQL(indexName, schemaName) {
|
|
23189
|
-
|
|
23271
|
+
function workflowSnapshotStatusIndexSQL(indexName, schemaName, concurrently = false) {
|
|
23272
|
+
const tableName = getTableName({
|
|
23190
23273
|
indexName: TABLE_WORKFLOW_SNAPSHOT,
|
|
23191
23274
|
schemaName: getSchemaName(schemaName)
|
|
23192
|
-
})
|
|
23275
|
+
});
|
|
23276
|
+
return `CREATE INDEX ${concurrently ? "CONCURRENTLY " : ""}IF NOT EXISTS "${indexName}" ON ${tableName} (workflow_name, (snapshot ->> 'status'), "createdAt" DESC)`;
|
|
23193
23277
|
}
|
|
23194
23278
|
/** Base name (before any schema prefix) of the expression index backing the threadId filter. */
|
|
23195
23279
|
const WORKFLOW_SNAPSHOT_THREAD_ID_INDEX = "mastra_workflow_snapshot_threadid_idx";
|
|
@@ -23226,12 +23310,14 @@ const WORKFLOW_SNAPSHOT_THREAD_ID_EXPR = `COALESCE(jsonb_path_query_first(snapsh
|
|
|
23226
23310
|
/**
|
|
23227
23311
|
* Expression index on the snapshot-embedded thread id so listWorkflowRuns() threadId filters
|
|
23228
23312
|
* (Agent.listSuspendedRuns) can use an index instead of detoasting every snapshot.
|
|
23313
|
+
* See {@link workflowSnapshotStatusIndexSQL} for `concurrently`.
|
|
23229
23314
|
*/
|
|
23230
|
-
function workflowSnapshotThreadIdIndexSQL(indexName, schemaName) {
|
|
23231
|
-
|
|
23315
|
+
function workflowSnapshotThreadIdIndexSQL(indexName, schemaName, concurrently = false) {
|
|
23316
|
+
const tableName = getTableName({
|
|
23232
23317
|
indexName: TABLE_WORKFLOW_SNAPSHOT,
|
|
23233
23318
|
schemaName: getSchemaName(schemaName)
|
|
23234
|
-
})
|
|
23319
|
+
});
|
|
23320
|
+
return `CREATE INDEX ${concurrently ? "CONCURRENTLY " : ""}IF NOT EXISTS "${indexName}" ON ${tableName} ((${WORKFLOW_SNAPSHOT_THREAD_ID_EXPR}))`;
|
|
23235
23321
|
}
|
|
23236
23322
|
var WorkflowsPG = class WorkflowsPG extends WorkflowsStorage {
|
|
23237
23323
|
#db;
|
|
@@ -23328,13 +23414,13 @@ var WorkflowsPG = class WorkflowsPG extends WorkflowsStorage {
|
|
|
23328
23414
|
if (await this.#db.getColumnType(TABLE_WORKFLOW_SNAPSHOT, "snapshot") !== "jsonb") return;
|
|
23329
23415
|
const indexName = workflowSnapshotStatusIndexName(this.#schema);
|
|
23330
23416
|
try {
|
|
23331
|
-
await this.#db.createIndexFromStatement(indexName, workflowSnapshotStatusIndexSQL(indexName, this.#schema));
|
|
23417
|
+
await this.#db.createIndexFromStatement(indexName, workflowSnapshotStatusIndexSQL(indexName, this.#schema, true));
|
|
23332
23418
|
} catch (error) {
|
|
23333
23419
|
this.logger?.warn?.(`Failed to create index ${indexName}:`, error);
|
|
23334
23420
|
}
|
|
23335
23421
|
const threadIdIndexName = workflowSnapshotThreadIdIndexName(this.#schema);
|
|
23336
23422
|
try {
|
|
23337
|
-
await this.#db.createIndexFromStatement(threadIdIndexName, workflowSnapshotThreadIdIndexSQL(threadIdIndexName, this.#schema));
|
|
23423
|
+
await this.#db.createIndexFromStatement(threadIdIndexName, workflowSnapshotThreadIdIndexSQL(threadIdIndexName, this.#schema, true));
|
|
23338
23424
|
} catch (error) {
|
|
23339
23425
|
this.logger?.warn?.(`Failed to create index ${threadIdIndexName}:`, error);
|
|
23340
23426
|
}
|