@mastra/pg 1.27.1 → 1.27.2-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.
@@ -3,7 +3,7 @@ name: mastra-pg
3
3
  description: Documentation for @mastra/pg. Use when working with @mastra/pg APIs, configuration, or implementation.
4
4
  metadata:
5
5
  package: "@mastra/pg"
6
- version: "1.27.1"
6
+ version: "1.27.2-alpha.1"
7
7
  ---
8
8
 
9
9
  ## When to use
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.27.1",
2
+ "version": "1.27.2-alpha.1",
3
3
  "package": "@mastra/pg",
4
4
  "exports": {},
5
5
  "modules": {}
package/dist/index.cjs CHANGED
@@ -10373,6 +10373,12 @@ var MCPServersPG = class MCPServersPG extends _mastra_core_storage.MCPServersSto
10373
10373
  * versions that don't export TABLE_OBSERVATIONAL_MEMORY.
10374
10374
  */
10375
10375
  const OM_TABLE = "mastra_observational_memory";
10376
+ /**
10377
+ * Newest generation first. Databases written before generation creation was
10378
+ * serialized can hold several rows with the same generation; the earliest-created
10379
+ * one wins so the active record stays stable across reads.
10380
+ */
10381
+ const OM_GENERATION_ORDER = `"generationCount" DESC, "createdAt" ASC, id ASC`;
10376
10382
  const POSTGRES_MAX_BIND_PARAMETERS = 65535;
10377
10383
  const MESSAGE_INSERT_BIND_PARAMETERS = 8;
10378
10384
  const MAX_MESSAGES_PER_INSERT = Math.floor(POSTGRES_MAX_BIND_PARAMETERS / MESSAGE_INSERT_BIND_PARAMETERS);
@@ -11974,6 +11980,23 @@ var MemoryPG = class MemoryPG extends _mastra_core_storage.MemoryStorage {
11974
11980
  getOMKey(threadId, resourceId) {
11975
11981
  return threadId ? `thread:${threadId}` : `resource:${resourceId}`;
11976
11982
  }
11983
+ /**
11984
+ * Runs `fn` in a transaction that holds an advisory lock for one OM lookup key.
11985
+ *
11986
+ * The table has no unique constraint on ("lookupKey", "generationCount"), and
11987
+ * adding one would fail on databases that already contain duplicates. The lock
11988
+ * serializes generation creation across processes instead. It is
11989
+ * transaction-scoped so it also works behind transaction-pooling proxies.
11990
+ */
11991
+ async #withOMLookupKeyLock(tableName, lookupKey, fn) {
11992
+ return this.#db.client.tx(async (t) => {
11993
+ await t.query("SELECT pg_advisory_xact_lock(hashtextextended($1, 0))", [`${tableName}:${lookupKey}`]);
11994
+ return fn(t);
11995
+ });
11996
+ }
11997
+ async #getLatestOMRow(client, tableName, lookupKey) {
11998
+ return client.oneOrNone(`SELECT * FROM ${tableName} WHERE "lookupKey" = $1 ORDER BY ${OM_GENERATION_ORDER} LIMIT 1`, [lookupKey]);
11999
+ }
11977
12000
  parseOMRow(row) {
11978
12001
  return {
11979
12002
  id: row.id,
@@ -12016,7 +12039,7 @@ var MemoryPG = class MemoryPG extends _mastra_core_storage.MemoryStorage {
12016
12039
  indexName: OM_TABLE,
12017
12040
  schemaName: getSchemaName$3(this.#schema)
12018
12041
  });
12019
- const result = await this.#db.readClient.oneOrNone(`SELECT * FROM ${tableName} WHERE "lookupKey" = $1 ORDER BY "generationCount" DESC LIMIT 1`, [lookupKey]);
12042
+ const result = await this.#getLatestOMRow(this.#db.readClient, tableName, lookupKey);
12020
12043
  if (!result) return null;
12021
12044
  return this.parseOMRow(result);
12022
12045
  } catch (error) {
@@ -12052,7 +12075,7 @@ var MemoryPG = class MemoryPG extends _mastra_core_storage.MemoryStorage {
12052
12075
  paramIndex++;
12053
12076
  }
12054
12077
  params.push(limit);
12055
- let sql = `SELECT * FROM ${tableName} WHERE ${conditions.join(" AND ")} ORDER BY "generationCount" DESC LIMIT $${paramIndex}`;
12078
+ let sql = `SELECT * FROM ${tableName} WHERE ${conditions.join(" AND ")} ORDER BY ${OM_GENERATION_ORDER} LIMIT $${paramIndex}`;
12056
12079
  paramIndex++;
12057
12080
  if (options?.offset != null) {
12058
12081
  params.push(options.offset);
@@ -12107,7 +12130,10 @@ var MemoryPG = class MemoryPG extends _mastra_core_storage.MemoryStorage {
12107
12130
  schemaName: getSchemaName$3(this.#schema)
12108
12131
  });
12109
12132
  const nowStr = now.toISOString();
12110
- await this.#db.client.none(`INSERT INTO ${tableName} (
12133
+ return await this.#withOMLookupKeyLock(tableName, lookupKey, async (t) => {
12134
+ const existing = await this.#getLatestOMRow(t, tableName, lookupKey);
12135
+ if (existing) return this.parseOMRow(existing);
12136
+ await t.none(`INSERT INTO ${tableName} (
12111
12137
  id, "lookupKey", scope, "resourceId", "threadId",
12112
12138
  "activeObservations", "activeObservationsPendingUpdate",
12113
12139
  "originType", config, "generationCount", "lastObservedAt", "lastObservedAtZ", "lastReflectionAt", "lastReflectionAtZ",
@@ -12115,36 +12141,37 @@ var MemoryPG = class MemoryPG extends _mastra_core_storage.MemoryStorage {
12115
12141
  "isObserving", "isReflecting", "isBufferingObservation", "isBufferingReflection", "lastBufferedAtTokens", "lastBufferedAtTime",
12116
12142
  "observedTimezone", "createdAt", "createdAtZ", "updatedAt", "updatedAtZ"
12117
12143
  ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25, $26, $27, $28)`, [
12118
- id,
12119
- lookupKey,
12120
- input.scope,
12121
- input.resourceId,
12122
- input.threadId || null,
12123
- "",
12124
- null,
12125
- "initial",
12126
- toPgJson(input.config),
12127
- 0,
12128
- null,
12129
- null,
12130
- null,
12131
- null,
12132
- 0,
12133
- 0,
12134
- 0,
12135
- false,
12136
- false,
12137
- false,
12138
- false,
12139
- 0,
12140
- null,
12141
- input.observedTimezone || null,
12142
- nowStr,
12143
- nowStr,
12144
- nowStr,
12145
- nowStr
12146
- ]);
12147
- return record;
12144
+ id,
12145
+ lookupKey,
12146
+ input.scope,
12147
+ input.resourceId,
12148
+ input.threadId || null,
12149
+ "",
12150
+ null,
12151
+ "initial",
12152
+ toPgJson(input.config),
12153
+ 0,
12154
+ null,
12155
+ null,
12156
+ null,
12157
+ null,
12158
+ 0,
12159
+ 0,
12160
+ 0,
12161
+ false,
12162
+ false,
12163
+ false,
12164
+ false,
12165
+ 0,
12166
+ null,
12167
+ input.observedTimezone || null,
12168
+ nowStr,
12169
+ nowStr,
12170
+ nowStr,
12171
+ nowStr
12172
+ ]);
12173
+ return record;
12174
+ });
12148
12175
  } catch (error) {
12149
12176
  throw new _mastra_core_error.MastraError({
12150
12177
  id: (0, _mastra_core_storage.createStorageErrorId)("PG", "INITIALIZE_OBSERVATIONAL_MEMORY", "FAILED"),
@@ -12276,78 +12303,16 @@ var MemoryPG = class MemoryPG extends _mastra_core_storage.MemoryStorage {
12276
12303
  }
12277
12304
  async createReflectionGeneration(input) {
12278
12305
  try {
12279
- const id = crypto.randomUUID();
12280
- const now = /* @__PURE__ */ new Date();
12281
12306
  const lookupKey = this.getOMKey(input.currentRecord.threadId, input.currentRecord.resourceId);
12282
- const record = {
12283
- id,
12284
- scope: input.currentRecord.scope,
12285
- threadId: input.currentRecord.threadId,
12286
- resourceId: input.currentRecord.resourceId,
12287
- createdAt: now,
12288
- updatedAt: now,
12289
- lastObservedAt: input.currentRecord.lastObservedAt,
12290
- originType: "reflection",
12291
- generationCount: input.currentRecord.generationCount + 1,
12292
- activeObservations: input.reflection,
12293
- totalTokensObserved: input.currentRecord.totalTokensObserved,
12294
- observationTokenCount: input.tokenCount,
12295
- pendingMessageTokens: 0,
12296
- isReflecting: false,
12297
- isObserving: false,
12298
- isBufferingObservation: false,
12299
- isBufferingReflection: false,
12300
- lastBufferedAtTokens: 0,
12301
- lastBufferedAtTime: null,
12302
- config: input.currentRecord.config,
12303
- metadata: input.currentRecord.metadata,
12304
- observedTimezone: input.currentRecord.observedTimezone
12305
- };
12306
12307
  const tableName = getTableName$3({
12307
12308
  indexName: OM_TABLE,
12308
12309
  schemaName: getSchemaName$3(this.#schema)
12309
12310
  });
12310
- const nowStr = now.toISOString();
12311
- const lastObservedAtStr = record.lastObservedAt?.toISOString() || null;
12312
- await this.#db.client.none(`INSERT INTO ${tableName} (
12313
- id, "lookupKey", scope, "resourceId", "threadId",
12314
- "activeObservations", "activeObservationsPendingUpdate",
12315
- "originType", config, "generationCount", "lastObservedAt", "lastObservedAtZ", "lastReflectionAt", "lastReflectionAtZ",
12316
- "pendingMessageTokens", "totalTokensObserved", "observationTokenCount",
12317
- "isObserving", "isReflecting", "isBufferingObservation", "isBufferingReflection", "lastBufferedAtTokens", "lastBufferedAtTime",
12318
- "observedTimezone", metadata, "createdAt", "createdAtZ", "updatedAt", "updatedAtZ"
12319
- ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25, $26, $27, $28, $29)`, [
12320
- id,
12321
- lookupKey,
12322
- record.scope,
12323
- record.resourceId,
12324
- record.threadId || null,
12325
- input.reflection,
12326
- null,
12327
- "reflection",
12328
- toPgJson(record.config),
12329
- input.currentRecord.generationCount + 1,
12330
- lastObservedAtStr,
12331
- lastObservedAtStr,
12332
- nowStr,
12333
- nowStr,
12334
- record.pendingMessageTokens,
12335
- Math.round(record.totalTokensObserved),
12336
- Math.round(record.observationTokenCount),
12337
- false,
12338
- false,
12339
- false,
12340
- false,
12341
- 0,
12342
- null,
12343
- record.observedTimezone || null,
12344
- record.metadata ? toPgJson(record.metadata) : null,
12345
- nowStr,
12346
- nowStr,
12347
- nowStr,
12348
- nowStr
12349
- ]);
12350
- return record;
12311
+ return await this.#withOMLookupKeyLock(tableName, lookupKey, async (t) => {
12312
+ const newer = await this.#getNewerOMGeneration(t, tableName, lookupKey, input.currentRecord.generationCount);
12313
+ if (newer) return newer;
12314
+ return this.#insertReflectionGeneration(t, tableName, lookupKey, input);
12315
+ });
12351
12316
  } catch (error) {
12352
12317
  throw new _mastra_core_error.MastraError({
12353
12318
  id: (0, _mastra_core_storage.createStorageErrorId)("PG", "CREATE_REFLECTION_GENERATION", "FAILED"),
@@ -12357,6 +12322,84 @@ var MemoryPG = class MemoryPG extends _mastra_core_storage.MemoryStorage {
12357
12322
  }, error);
12358
12323
  }
12359
12324
  }
12325
+ /**
12326
+ * Returns the active record when another writer already created a generation
12327
+ * after `generationCount`. Reflecting from the older generation again would
12328
+ * add a second record with the same generation.
12329
+ */
12330
+ async #getNewerOMGeneration(t, tableName, lookupKey, generationCount) {
12331
+ const latest = await this.#getLatestOMRow(t, tableName, lookupKey);
12332
+ return latest && Number(latest.generationCount) > generationCount ? this.parseOMRow(latest) : null;
12333
+ }
12334
+ async #insertReflectionGeneration(t, tableName, lookupKey, input) {
12335
+ const id = crypto.randomUUID();
12336
+ const now = /* @__PURE__ */ new Date();
12337
+ const record = {
12338
+ id,
12339
+ scope: input.currentRecord.scope,
12340
+ threadId: input.currentRecord.threadId,
12341
+ resourceId: input.currentRecord.resourceId,
12342
+ createdAt: now,
12343
+ updatedAt: now,
12344
+ lastObservedAt: input.currentRecord.lastObservedAt,
12345
+ originType: "reflection",
12346
+ generationCount: input.currentRecord.generationCount + 1,
12347
+ activeObservations: input.reflection,
12348
+ totalTokensObserved: input.currentRecord.totalTokensObserved,
12349
+ observationTokenCount: input.tokenCount,
12350
+ pendingMessageTokens: 0,
12351
+ isReflecting: false,
12352
+ isObserving: false,
12353
+ isBufferingObservation: false,
12354
+ isBufferingReflection: false,
12355
+ lastBufferedAtTokens: 0,
12356
+ lastBufferedAtTime: null,
12357
+ config: input.currentRecord.config,
12358
+ metadata: input.currentRecord.metadata,
12359
+ observedTimezone: input.currentRecord.observedTimezone
12360
+ };
12361
+ const nowStr = now.toISOString();
12362
+ const lastObservedAtStr = record.lastObservedAt?.toISOString() || null;
12363
+ await t.none(`INSERT INTO ${tableName} (
12364
+ id, "lookupKey", scope, "resourceId", "threadId",
12365
+ "activeObservations", "activeObservationsPendingUpdate",
12366
+ "originType", config, "generationCount", "lastObservedAt", "lastObservedAtZ", "lastReflectionAt", "lastReflectionAtZ",
12367
+ "pendingMessageTokens", "totalTokensObserved", "observationTokenCount",
12368
+ "isObserving", "isReflecting", "isBufferingObservation", "isBufferingReflection", "lastBufferedAtTokens", "lastBufferedAtTime",
12369
+ "observedTimezone", metadata, "createdAt", "createdAtZ", "updatedAt", "updatedAtZ"
12370
+ ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25, $26, $27, $28, $29)`, [
12371
+ id,
12372
+ lookupKey,
12373
+ record.scope,
12374
+ record.resourceId,
12375
+ record.threadId || null,
12376
+ input.reflection,
12377
+ null,
12378
+ "reflection",
12379
+ toPgJson(record.config),
12380
+ input.currentRecord.generationCount + 1,
12381
+ lastObservedAtStr,
12382
+ lastObservedAtStr,
12383
+ nowStr,
12384
+ nowStr,
12385
+ record.pendingMessageTokens,
12386
+ Math.round(record.totalTokensObserved),
12387
+ Math.round(record.observationTokenCount),
12388
+ false,
12389
+ false,
12390
+ false,
12391
+ false,
12392
+ 0,
12393
+ null,
12394
+ record.observedTimezone || null,
12395
+ record.metadata ? toPgJson(record.metadata) : null,
12396
+ nowStr,
12397
+ nowStr,
12398
+ nowStr,
12399
+ nowStr
12400
+ ]);
12401
+ return record;
12402
+ }
12360
12403
  async setReflectingFlag(id, isReflecting) {
12361
12404
  try {
12362
12405
  const tableName = getTableName$3({
@@ -12851,32 +12894,36 @@ var MemoryPG = class MemoryPG extends _mastra_core_storage.MemoryStorage {
12851
12894
  indexName: OM_TABLE,
12852
12895
  schemaName: getSchemaName$3(this.#schema)
12853
12896
  });
12854
- const record = await this.#db.client.oneOrNone(`SELECT * FROM ${tableName} WHERE id = $1`, [input.currentRecord.id]);
12855
- if (!record) throw new _mastra_core_error.MastraError({
12856
- id: (0, _mastra_core_storage.createStorageErrorId)("PG", "SWAP_BUFFERED_REFLECTION_TO_ACTIVE", "NOT_FOUND"),
12857
- text: `Observational memory record not found: ${input.currentRecord.id}`,
12858
- domain: _mastra_core_error.ErrorDomain.STORAGE,
12859
- category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
12860
- details: { id: input.currentRecord.id }
12861
- });
12862
- const bufferedReflection = record.bufferedReflection || "";
12863
- const reflectedLineCount = Number(record.reflectedObservationLineCount || 0);
12864
- if (!bufferedReflection) throw new _mastra_core_error.MastraError({
12865
- id: (0, _mastra_core_storage.createStorageErrorId)("PG", "SWAP_BUFFERED_REFLECTION_TO_ACTIVE", "NO_CONTENT"),
12866
- text: "No buffered reflection to swap",
12867
- domain: _mastra_core_error.ErrorDomain.STORAGE,
12868
- category: _mastra_core_error.ErrorCategory.USER,
12869
- details: { id: input.currentRecord.id }
12870
- });
12871
- const unreflectedContent = (record.activeObservations || "").split("\n").slice(reflectedLineCount).join("\n").trim();
12872
- const newObservations = unreflectedContent ? `${bufferedReflection}\n\n${unreflectedContent}` : bufferedReflection;
12873
- const newRecord = await this.createReflectionGeneration({
12874
- currentRecord: input.currentRecord,
12875
- reflection: newObservations,
12876
- tokenCount: input.tokenCount
12877
- });
12878
- const nowStr = (/* @__PURE__ */ new Date()).toISOString();
12879
- await this.#db.client.query(`UPDATE ${tableName} SET
12897
+ const lookupKey = this.getOMKey(input.currentRecord.threadId, input.currentRecord.resourceId);
12898
+ return await this.#withOMLookupKeyLock(tableName, lookupKey, async (t) => {
12899
+ const newer = await this.#getNewerOMGeneration(t, tableName, lookupKey, input.currentRecord.generationCount);
12900
+ if (newer) return newer;
12901
+ const record = await t.oneOrNone(`SELECT * FROM ${tableName} WHERE id = $1`, [input.currentRecord.id]);
12902
+ if (!record) throw new _mastra_core_error.MastraError({
12903
+ id: (0, _mastra_core_storage.createStorageErrorId)("PG", "SWAP_BUFFERED_REFLECTION_TO_ACTIVE", "NOT_FOUND"),
12904
+ text: `Observational memory record not found: ${input.currentRecord.id}`,
12905
+ domain: _mastra_core_error.ErrorDomain.STORAGE,
12906
+ category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
12907
+ details: { id: input.currentRecord.id }
12908
+ });
12909
+ const bufferedReflection = record.bufferedReflection || "";
12910
+ const reflectedLineCount = Number(record.reflectedObservationLineCount || 0);
12911
+ if (!bufferedReflection) throw new _mastra_core_error.MastraError({
12912
+ id: (0, _mastra_core_storage.createStorageErrorId)("PG", "SWAP_BUFFERED_REFLECTION_TO_ACTIVE", "NO_CONTENT"),
12913
+ text: "No buffered reflection to swap",
12914
+ domain: _mastra_core_error.ErrorDomain.STORAGE,
12915
+ category: _mastra_core_error.ErrorCategory.USER,
12916
+ details: { id: input.currentRecord.id }
12917
+ });
12918
+ const unreflectedContent = (record.activeObservations || "").split("\n").slice(reflectedLineCount).join("\n").trim();
12919
+ const newObservations = unreflectedContent ? `${bufferedReflection}\n\n${unreflectedContent}` : bufferedReflection;
12920
+ const newRecord = await this.#insertReflectionGeneration(t, tableName, lookupKey, {
12921
+ currentRecord: input.currentRecord,
12922
+ reflection: newObservations,
12923
+ tokenCount: input.tokenCount
12924
+ });
12925
+ const nowStr = (/* @__PURE__ */ new Date()).toISOString();
12926
+ await t.query(`UPDATE ${tableName} SET
12880
12927
  "bufferedReflection" = NULL,
12881
12928
  "bufferedReflectionTokens" = NULL,
12882
12929
  "bufferedReflectionInputTokens" = NULL,
@@ -12884,11 +12931,12 @@ var MemoryPG = class MemoryPG extends _mastra_core_storage.MemoryStorage {
12884
12931
  "updatedAt" = $1,
12885
12932
  "updatedAtZ" = $2
12886
12933
  WHERE id = $3`, [
12887
- nowStr,
12888
- nowStr,
12889
- input.currentRecord.id
12890
- ]);
12891
- return newRecord;
12934
+ nowStr,
12935
+ nowStr,
12936
+ input.currentRecord.id
12937
+ ]);
12938
+ return newRecord;
12939
+ });
12892
12940
  } catch (error) {
12893
12941
  if (error instanceof _mastra_core_error.MastraError) throw error;
12894
12942
  throw new _mastra_core_error.MastraError({
@@ -22983,7 +23031,7 @@ var WorkflowsPG = class WorkflowsPG extends _mastra_core_storage.WorkflowsStorag
22983
23031
  }, error);
22984
23032
  }
22985
23033
  }
22986
- async listWorkflowRuns({ workflowName, fromDate, toDate, perPage, page, resourceId, threadId, status } = {}) {
23034
+ async listWorkflowRuns({ workflowName, fromDate, toDate, perPage, page, resourceId, threadId, status, summary } = {}) {
22987
23035
  try {
22988
23036
  const conditions = [];
22989
23037
  const values = [];
@@ -23031,8 +23079,13 @@ var WorkflowsPG = class WorkflowsPG extends _mastra_core_storage.WorkflowsStorag
23031
23079
  }
23032
23080
  const normalizedPerPage = usePagination ? (0, _mastra_core_storage.normalizePerPage)(perPage, Number.MAX_SAFE_INTEGER) : 0;
23033
23081
  const offset = usePagination ? page * normalizedPerPage : void 0;
23082
+ let selectList = "*";
23083
+ if (summary) {
23084
+ const snapshotJson = await this.#db.getColumnType(_mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT, "snapshot") === "jsonb" ? "snapshot" : `regexp_replace(snapshot::text, '\\\\u(0000|[Dd][89A-Fa-f][0-9A-Fa-f]{2})', '', 'g')::jsonb`;
23085
+ selectList = `workflow_name, run_id, "resourceId", "createdAt", "createdAtZ", "updatedAt", "updatedAtZ", jsonb_build_object('status', ${snapshotJson} -> 'status', 'timestamp', ${snapshotJson} -> 'timestamp') AS snapshot`;
23086
+ }
23034
23087
  const query = `
23035
- SELECT * FROM ${getTableName({
23088
+ SELECT ${selectList} FROM ${getTableName({
23036
23089
  indexName: _mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT,
23037
23090
  schemaName: getSchemaName(this.#schema)
23038
23091
  })}