@mastra/pg 1.12.0 → 1.12.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/CHANGELOG.md CHANGED
@@ -1,5 +1,39 @@
1
1
  # @mastra/pg
2
2
 
3
+ ## 1.12.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Added notification inbox storage support for Postgres stores. ([#17241](https://github.com/mastra-ai/mastra/pull/17241))
8
+
9
+ ```ts
10
+ import { PostgresStore } from '@mastra/pg';
11
+
12
+ const storage = new PostgresStore({ connectionString: process.env.POSTGRES_URL! });
13
+ ```
14
+
15
+ Agents using this store can persist thread-scoped notification inbox records for notification signals.
16
+
17
+ - Updated dependencies [[`c973db4`](https://github.com/mastra-ai/mastra/commit/c973db428df1b564ff0c35d4b2a90e8f4f1e13fd), [`552285e`](https://github.com/mastra-ai/mastra/commit/552285e5af43cfc680a0972032cab8de8776c6a0), [`77e686c`](https://github.com/mastra-ai/mastra/commit/77e686c264e493e99ae5024e4dfe3ea5d5a09718), [`ece8dba`](https://github.com/mastra-ai/mastra/commit/ece8dba7ec1a5089eee8c33167cd762bfa91e509), [`e751af2`](https://github.com/mastra-ai/mastra/commit/e751af219433fbf4c7035b2d771b4c9ec8813b05), [`e2a8380`](https://github.com/mastra-ai/mastra/commit/e2a838017a7657850404c1e94c70d79ffdc6f14a), [`be3f1cd`](https://github.com/mastra-ai/mastra/commit/be3f1cd81f0e2a649e8eac15a024d542d814aef8), [`a34d9db`](https://github.com/mastra-ai/mastra/commit/a34d9dbc39fedb722f271318e9355ecee70489ab)]:
18
+ - @mastra/core@1.39.0
19
+
20
+ ## 1.12.1-alpha.0
21
+
22
+ ### Patch Changes
23
+
24
+ - Added notification inbox storage support for Postgres stores. ([#17241](https://github.com/mastra-ai/mastra/pull/17241))
25
+
26
+ ```ts
27
+ import { PostgresStore } from '@mastra/pg';
28
+
29
+ const storage = new PostgresStore({ connectionString: process.env.POSTGRES_URL! });
30
+ ```
31
+
32
+ Agents using this store can persist thread-scoped notification inbox records for notification signals.
33
+
34
+ - Updated dependencies [[`c973db4`](https://github.com/mastra-ai/mastra/commit/c973db428df1b564ff0c35d4b2a90e8f4f1e13fd), [`552285e`](https://github.com/mastra-ai/mastra/commit/552285e5af43cfc680a0972032cab8de8776c6a0), [`77e686c`](https://github.com/mastra-ai/mastra/commit/77e686c264e493e99ae5024e4dfe3ea5d5a09718), [`ece8dba`](https://github.com/mastra-ai/mastra/commit/ece8dba7ec1a5089eee8c33167cd762bfa91e509), [`e751af2`](https://github.com/mastra-ai/mastra/commit/e751af219433fbf4c7035b2d771b4c9ec8813b05), [`e2a8380`](https://github.com/mastra-ai/mastra/commit/e2a838017a7657850404c1e94c70d79ffdc6f14a), [`be3f1cd`](https://github.com/mastra-ai/mastra/commit/be3f1cd81f0e2a649e8eac15a024d542d814aef8), [`a34d9db`](https://github.com/mastra-ai/mastra/commit/a34d9dbc39fedb722f271318e9355ecee70489ab)]:
35
+ - @mastra/core@1.39.0-alpha.0
36
+
3
37
  ## 1.12.0
4
38
 
5
39
  ### Minor Changes
@@ -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.12.0"
6
+ version: "1.12.1"
7
7
  ---
8
8
 
9
9
  ## When to use
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.12.0",
2
+ "version": "1.12.1",
3
3
  "package": "@mastra/pg",
4
4
  "exports": {},
5
5
  "modules": {}
@@ -393,6 +393,33 @@ const response = await agent.generate('What do you know about me?', {
393
393
  })
394
394
  ```
395
395
 
396
+ ## Opt in to state signals (experimental)
397
+
398
+ By default, working memory reaches the model as part of the system message. You can opt into delivering it as a [state signal](https://mastra.ai/docs/agents/signals) instead by setting `useStateSignals: true`:
399
+
400
+ ```typescript
401
+ const memory = new Memory({
402
+ storage: new LibSQLStore({ url: 'file:./mastra.db' }),
403
+ options: {
404
+ workingMemory: {
405
+ enabled: true,
406
+ template: '# User\n- name:\n- location:',
407
+ useStateSignals: true, // experimental: deliver as state signal
408
+ },
409
+ },
410
+ })
411
+ ```
412
+
413
+ What changes:
414
+
415
+ - **Storage is identical.** The same resource/thread `workingMemory` field is read and written.
416
+ - **The tool is the same shape, exposed under a new name.** Writes still flow through the same underlying tool; on this path it is registered as `setWorkingMemory` (instead of `updateWorkingMemory`). The rename keeps legacy strip filters from removing tool-call parts so they persist as a normal audit trail and the next model step picks the new value up automatically.
417
+ - **Delivery only.** Instead of folding into the system prompt, `Memory` auto-attaches a `WorkingMemoryStateProcessor` that emits the current working memory as a `state` signal with `stateId: 'working-memory'`.
418
+
419
+ You inherit the standard state-signal benefits: thread-scoped tracking metadata, `cacheKey` dedup so identical snapshots are only emitted once, and `contextWindow.hasSnapshot` re-injection when an older snapshot rolls out of the window.
420
+
421
+ The default (`useStateSignals: false`) keeps the existing system-message behavior unchanged. `useStateSignals` is not supported with template working memory `version: 'vnext'`.
422
+
396
423
  ## Examples
397
424
 
398
425
  - [Working memory with template](https://github.com/mastra-ai/mastra/tree/main/examples/memory-with-template)
@@ -132,6 +132,9 @@ The storage implementation handles schema creation and updates automatically. It
132
132
  - `mastra_traces`: Stores telemetry and tracing data
133
133
  - `mastra_scorers`: Stores scoring and evaluation data
134
134
  - `mastra_resources`: Stores resource working memory data
135
+ - `mastra_notifications`: Stores notification inbox records and delivery metadata
136
+
137
+ `PostgresStore` exposes notification storage through `getStore('notifications')`.
135
138
 
136
139
  ### Observability
137
140
 
package/dist/index.cjs CHANGED
@@ -10426,6 +10426,348 @@ ${unreflectedContent}` : bufferedReflection;
10426
10426
  }
10427
10427
  }
10428
10428
  };
10429
+ var statusTimestamp = (status, now) => {
10430
+ if (status === "delivered") return { deliveredAt: now };
10431
+ if (status === "seen") return { seenAt: now };
10432
+ if (status === "dismissed") return { dismissedAt: now };
10433
+ if (status === "archived") return { archivedAt: now };
10434
+ if (status === "discarded") return { discardedAt: now };
10435
+ return {};
10436
+ };
10437
+ var parseDate = (value) => {
10438
+ if (value == null) return void 0;
10439
+ return value instanceof Date ? value : new Date(String(value));
10440
+ };
10441
+ var cloneValue = (value) => value === void 0 ? void 0 : structuredClone(value);
10442
+ function rowToNotification(row) {
10443
+ return {
10444
+ id: String(row.id),
10445
+ threadId: String(row.threadId),
10446
+ source: String(row.source),
10447
+ kind: String(row.kind),
10448
+ priority: String(row.priority),
10449
+ status: String(row.status),
10450
+ summary: String(row.summary),
10451
+ payload: parseJsonResilient(row.payload),
10452
+ resourceId: row.resourceId == null ? void 0 : String(row.resourceId),
10453
+ agentId: row.agentId == null ? void 0 : String(row.agentId),
10454
+ sourceId: row.sourceId == null ? void 0 : String(row.sourceId),
10455
+ dedupeKey: row.dedupeKey == null ? void 0 : String(row.dedupeKey),
10456
+ coalesceKey: row.coalesceKey == null ? void 0 : String(row.coalesceKey),
10457
+ coalescedCount: Number(row.coalescedCount ?? 1),
10458
+ attributes: parseJsonResilient(row.attributes),
10459
+ createdAt: parseDate(row.createdAt) ?? /* @__PURE__ */ new Date(),
10460
+ updatedAt: parseDate(row.updatedAt) ?? /* @__PURE__ */ new Date(),
10461
+ deliveredAt: parseDate(row.deliveredAt),
10462
+ seenAt: parseDate(row.seenAt),
10463
+ dismissedAt: parseDate(row.dismissedAt),
10464
+ archivedAt: parseDate(row.archivedAt),
10465
+ discardedAt: parseDate(row.discardedAt),
10466
+ deliverAt: parseDate(row.deliverAt),
10467
+ summaryAt: parseDate(row.summaryAt),
10468
+ deliveryReason: row.deliveryReason == null ? void 0 : String(row.deliveryReason),
10469
+ deliveryAttempts: Number(row.deliveryAttempts ?? 0),
10470
+ lastDeliveryAttemptAt: parseDate(row.lastDeliveryAttemptAt),
10471
+ lastDeliveryError: row.lastDeliveryError == null ? void 0 : String(row.lastDeliveryError),
10472
+ deliveredSignalId: row.deliveredSignalId == null ? void 0 : String(row.deliveredSignalId),
10473
+ summarySignalId: row.summarySignalId == null ? void 0 : String(row.summarySignalId),
10474
+ metadata: parseJsonResilient(row.metadata)
10475
+ };
10476
+ }
10477
+ function addArrayFilter(conditions, args, column, value) {
10478
+ if (!value) return;
10479
+ const values = Array.isArray(value) ? value : [value];
10480
+ const start = args.length + 1;
10481
+ conditions.push(`"${column}" IN (${values.map((_, index) => `$${start + index}`).join(", ")})`);
10482
+ args.push(...values);
10483
+ }
10484
+ function normalizeRecordForInsert(record) {
10485
+ return {
10486
+ ...record,
10487
+ payload: record.payload ?? null,
10488
+ attributes: record.attributes ?? null,
10489
+ metadata: record.metadata ?? null,
10490
+ resourceId: record.resourceId ?? null,
10491
+ agentId: record.agentId ?? null,
10492
+ sourceId: record.sourceId ?? null,
10493
+ dedupeKey: record.dedupeKey ?? null,
10494
+ coalesceKey: record.coalesceKey ?? null,
10495
+ deliveredAt: record.deliveredAt ?? null,
10496
+ seenAt: record.seenAt ?? null,
10497
+ dismissedAt: record.dismissedAt ?? null,
10498
+ archivedAt: record.archivedAt ?? null,
10499
+ discardedAt: record.discardedAt ?? null,
10500
+ deliverAt: record.deliverAt ?? null,
10501
+ summaryAt: record.summaryAt ?? null,
10502
+ deliveryReason: record.deliveryReason ?? null,
10503
+ lastDeliveryAttemptAt: record.lastDeliveryAttemptAt ?? null,
10504
+ lastDeliveryError: record.lastDeliveryError ?? null,
10505
+ deliveredSignalId: record.deliveredSignalId ?? null,
10506
+ summarySignalId: record.summarySignalId ?? null
10507
+ };
10508
+ }
10509
+ var NotificationsPG = class _NotificationsPG extends storage.NotificationsStorage {
10510
+ #db;
10511
+ #schema;
10512
+ #skipDefaultIndexes;
10513
+ #indexes;
10514
+ static MANAGED_TABLES = [storage.TABLE_NOTIFICATIONS];
10515
+ constructor(config) {
10516
+ super();
10517
+ const { client, schemaName, skipDefaultIndexes, indexes } = resolvePgConfig(config);
10518
+ this.#db = new PgDB({ client, schemaName, skipDefaultIndexes });
10519
+ this.#schema = schemaName || "public";
10520
+ this.#skipDefaultIndexes = skipDefaultIndexes;
10521
+ this.#indexes = indexes?.filter((idx) => _NotificationsPG.MANAGED_TABLES.includes(idx.table));
10522
+ }
10523
+ async init() {
10524
+ await this.#db.createTable({
10525
+ tableName: storage.TABLE_NOTIFICATIONS,
10526
+ schema: storage.TABLE_SCHEMAS[storage.TABLE_NOTIFICATIONS]
10527
+ });
10528
+ await this.createDefaultIndexes();
10529
+ await this.createCustomIndexes();
10530
+ }
10531
+ static getDefaultIndexDefs(schemaPrefix) {
10532
+ return [
10533
+ {
10534
+ name: `${schemaPrefix}idx_notifications_thread_status_updated`,
10535
+ table: storage.TABLE_NOTIFICATIONS,
10536
+ columns: ["threadId", "status", "updatedAt"]
10537
+ },
10538
+ {
10539
+ name: `${schemaPrefix}idx_notifications_coalescing`,
10540
+ table: storage.TABLE_NOTIFICATIONS,
10541
+ columns: ["threadId", "source", "kind", "status", "agentId", "resourceId", "dedupeKey", "coalesceKey"]
10542
+ },
10543
+ {
10544
+ name: `${schemaPrefix}idx_notifications_due`,
10545
+ table: storage.TABLE_NOTIFICATIONS,
10546
+ columns: ["status", "deliverAt", "summaryAt"]
10547
+ }
10548
+ ];
10549
+ }
10550
+ static getExportDDL(schemaName) {
10551
+ const statements = [];
10552
+ const parsedSchema = schemaName ? utils.parseSqlIdentifier(schemaName, "schema name") : "";
10553
+ const schemaPrefix = parsedSchema && parsedSchema !== "public" ? `${parsedSchema}_` : "";
10554
+ statements.push(
10555
+ generateTableSQL({
10556
+ tableName: storage.TABLE_NOTIFICATIONS,
10557
+ schema: storage.TABLE_SCHEMAS[storage.TABLE_NOTIFICATIONS],
10558
+ schemaName,
10559
+ includeAllConstraints: true
10560
+ })
10561
+ );
10562
+ for (const idx of _NotificationsPG.getDefaultIndexDefs(schemaPrefix)) {
10563
+ statements.push(generateIndexSQL(idx, schemaName));
10564
+ }
10565
+ return statements;
10566
+ }
10567
+ getDefaultIndexDefinitions() {
10568
+ const schemaPrefix = this.#schema !== "public" ? `${this.#schema}_` : "";
10569
+ return _NotificationsPG.getDefaultIndexDefs(schemaPrefix);
10570
+ }
10571
+ async createDefaultIndexes() {
10572
+ if (this.#skipDefaultIndexes) return;
10573
+ for (const indexDef of this.getDefaultIndexDefinitions()) {
10574
+ try {
10575
+ await this.#db.createIndex(indexDef);
10576
+ } catch (error) {
10577
+ this.logger?.warn?.(`Failed to create index ${indexDef.name}:`, error);
10578
+ }
10579
+ }
10580
+ }
10581
+ async createCustomIndexes() {
10582
+ if (!this.#indexes || this.#indexes.length === 0) return;
10583
+ for (const indexDef of this.#indexes) {
10584
+ try {
10585
+ await this.#db.createIndex(indexDef);
10586
+ } catch (error) {
10587
+ this.logger?.warn?.(`Failed to create custom index ${indexDef.name}:`, error);
10588
+ }
10589
+ }
10590
+ }
10591
+ async dangerouslyClearAll() {
10592
+ await this.#db.clearTable({ tableName: storage.TABLE_NOTIFICATIONS });
10593
+ }
10594
+ async updateNotificationRow(threadId, id, data) {
10595
+ const entries = Object.entries(data).filter(([, value]) => value !== void 0);
10596
+ if (entries.length === 0) return;
10597
+ const schemaName = getSchemaName2(this.#schema);
10598
+ const tableName = getTableName2({ indexName: storage.TABLE_NOTIFICATIONS, schemaName });
10599
+ const setColumns = entries.map(([key], index) => `"${utils.parseSqlIdentifier(key, "column name")}" = $${index + 1}`);
10600
+ const values = entries.map(([key, value]) => {
10601
+ const columnSchema = storage.TABLE_SCHEMAS[storage.TABLE_NOTIFICATIONS][key];
10602
+ if (columnSchema?.type === "jsonb" && value !== null) return JSON.stringify(value);
10603
+ return value;
10604
+ });
10605
+ await this.#db.client.none(
10606
+ `UPDATE ${tableName} SET ${setColumns.join(", ")} WHERE "threadId" = $${values.length + 1} AND "id" = $${values.length + 2}`,
10607
+ [...values, threadId, id]
10608
+ );
10609
+ }
10610
+ async createNotification(input) {
10611
+ const existing = await this.findCoalescable(input);
10612
+ if (existing) {
10613
+ const now2 = /* @__PURE__ */ new Date();
10614
+ const attributes = input.attributes ? { ...cloneValue(existing.attributes), ...cloneValue(input.attributes) } : cloneValue(existing.attributes);
10615
+ const metadata = input.metadata ? { ...cloneValue(existing.metadata), ...cloneValue(input.metadata) } : cloneValue(existing.metadata);
10616
+ await this.updateNotificationRow(existing.threadId, existing.id, {
10617
+ summary: input.summary,
10618
+ payload: cloneValue(input.payload ?? existing.payload) ?? null,
10619
+ priority: input.priority ?? existing.priority,
10620
+ attributes: attributes ?? null,
10621
+ updatedAt: now2,
10622
+ deliverAt: input.deliverAt ?? existing.deliverAt ?? null,
10623
+ summaryAt: input.summaryAt ?? existing.summaryAt ?? null,
10624
+ deliveryReason: input.deliveryReason ?? existing.deliveryReason ?? null,
10625
+ coalescedCount: (existing.coalescedCount ?? 1) + 1,
10626
+ metadata: metadata ?? null
10627
+ });
10628
+ const updated = await this.getNotification({ threadId: existing.threadId, id: existing.id });
10629
+ if (!updated) throw new Error(`Notification ${existing.id} was not found for thread ${existing.threadId}`);
10630
+ return updated;
10631
+ }
10632
+ const now = input.createdAt ?? /* @__PURE__ */ new Date();
10633
+ const record = {
10634
+ id: input.id ?? crypto$1.randomUUID(),
10635
+ threadId: input.threadId,
10636
+ source: input.source,
10637
+ kind: input.kind,
10638
+ priority: input.priority ?? "medium",
10639
+ status: "pending",
10640
+ summary: input.summary,
10641
+ payload: cloneValue(input.payload),
10642
+ resourceId: input.resourceId,
10643
+ agentId: input.agentId,
10644
+ sourceId: input.sourceId,
10645
+ dedupeKey: input.dedupeKey,
10646
+ coalesceKey: input.coalesceKey,
10647
+ coalescedCount: 1,
10648
+ attributes: cloneValue(input.attributes),
10649
+ createdAt: now,
10650
+ updatedAt: now,
10651
+ deliverAt: input.deliverAt,
10652
+ summaryAt: input.summaryAt,
10653
+ deliveryReason: input.deliveryReason,
10654
+ deliveryAttempts: 0,
10655
+ metadata: cloneValue(input.metadata)
10656
+ };
10657
+ await this.#db.insert({ tableName: storage.TABLE_NOTIFICATIONS, record: normalizeRecordForInsert(record) });
10658
+ return record;
10659
+ }
10660
+ async listNotifications(input) {
10661
+ const conditions = ['"threadId" = $1'];
10662
+ const args = [input.threadId];
10663
+ addArrayFilter(conditions, args, "status", input.status);
10664
+ addArrayFilter(conditions, args, "priority", input.priority);
10665
+ if (input.source) {
10666
+ args.push(input.source);
10667
+ conditions.push(`"source" = $${args.length}`);
10668
+ }
10669
+ if (input.resourceId) {
10670
+ args.push(input.resourceId);
10671
+ conditions.push(`"resourceId" = $${args.length}`);
10672
+ }
10673
+ if (input.agentId) {
10674
+ args.push(input.agentId);
10675
+ conditions.push(`"agentId" = $${args.length}`);
10676
+ }
10677
+ if (input.search) {
10678
+ const search = `%${input.search.toLowerCase()}%`;
10679
+ args.push(search, search);
10680
+ conditions.push(`(LOWER("summary") LIKE $${args.length - 1} OR LOWER("kind") LIKE $${args.length})`);
10681
+ }
10682
+ const limit = input.limit ? ` LIMIT $${args.length + 1}` : "";
10683
+ if (input.limit) args.push(input.limit);
10684
+ const schemaName = getSchemaName2(this.#schema);
10685
+ const tableName = getTableName2({ indexName: storage.TABLE_NOTIFICATIONS, schemaName });
10686
+ const rows = await this.#db.client.manyOrNone(
10687
+ `SELECT * FROM ${tableName} WHERE ${conditions.join(" AND ")} ORDER BY "updatedAt" DESC${limit}`,
10688
+ args
10689
+ );
10690
+ return rows.map((row) => rowToNotification(row));
10691
+ }
10692
+ async listDueNotifications(input) {
10693
+ const conditions = [
10694
+ '"status" = $1',
10695
+ '(("deliverAt" IS NOT NULL AND "deliverAt" <= $2) OR ("summaryAt" IS NOT NULL AND "summaryAt" <= $3))'
10696
+ ];
10697
+ const args = ["pending", input.now, input.now];
10698
+ if (input.agentId) {
10699
+ args.push(input.agentId);
10700
+ conditions.push(`"agentId" = $${args.length}`);
10701
+ }
10702
+ if (input.resourceId) {
10703
+ args.push(input.resourceId);
10704
+ conditions.push(`"resourceId" = $${args.length}`);
10705
+ }
10706
+ const limit = input.limit ? ` LIMIT $${args.length + 1}` : "";
10707
+ if (input.limit) args.push(input.limit);
10708
+ const schemaName = getSchemaName2(this.#schema);
10709
+ const tableName = getTableName2({ indexName: storage.TABLE_NOTIFICATIONS, schemaName });
10710
+ const rows = await this.#db.client.manyOrNone(
10711
+ `SELECT * FROM ${tableName} WHERE ${conditions.join(" AND ")} ORDER BY CASE WHEN "deliverAt" IS NULL THEN "summaryAt" WHEN "summaryAt" IS NULL THEN "deliverAt" WHEN "deliverAt" <= "summaryAt" THEN "deliverAt" ELSE "summaryAt" END ASC, "updatedAt" ASC${limit}`,
10712
+ args
10713
+ );
10714
+ return rows.map((row) => rowToNotification(row));
10715
+ }
10716
+ async getNotification(input) {
10717
+ const schemaName = getSchemaName2(this.#schema);
10718
+ const tableName = getTableName2({ indexName: storage.TABLE_NOTIFICATIONS, schemaName });
10719
+ const row = await this.#db.client.oneOrNone(
10720
+ `SELECT * FROM ${tableName} WHERE "threadId" = $1 AND "id" = $2 LIMIT 1`,
10721
+ [input.threadId, input.id]
10722
+ );
10723
+ return row ? rowToNotification(row) : null;
10724
+ }
10725
+ async updateNotification(input) {
10726
+ const existing = await this.getNotification({ threadId: input.threadId, id: input.id });
10727
+ if (!existing) {
10728
+ throw new Error(`Notification ${input.id} was not found for thread ${input.threadId}`);
10729
+ }
10730
+ const now = /* @__PURE__ */ new Date();
10731
+ await this.updateNotificationRow(input.threadId, input.id, {
10732
+ ...input.status ? { status: input.status, ...statusTimestamp(input.status, now) } : {},
10733
+ ...input.summary !== void 0 ? { summary: input.summary } : {},
10734
+ ...input.payload !== void 0 ? { payload: cloneValue(input.payload) } : {},
10735
+ ...input.attributes !== void 0 ? { attributes: cloneValue(input.attributes) } : {},
10736
+ ...input.metadata !== void 0 ? { metadata: cloneValue(input.metadata) } : {},
10737
+ ...input.deliverAt !== void 0 ? { deliverAt: input.deliverAt } : {},
10738
+ ...input.summaryAt !== void 0 ? { summaryAt: input.summaryAt } : {},
10739
+ ...input.deliveryReason !== void 0 ? { deliveryReason: input.deliveryReason } : {},
10740
+ ...input.deliveryAttempts !== void 0 ? { deliveryAttempts: input.deliveryAttempts } : {},
10741
+ ...input.lastDeliveryAttemptAt !== void 0 ? { lastDeliveryAttemptAt: input.lastDeliveryAttemptAt } : {},
10742
+ ...input.lastDeliveryError !== void 0 ? { lastDeliveryError: input.lastDeliveryError } : {},
10743
+ ...input.deliveredSignalId !== void 0 ? { deliveredSignalId: input.deliveredSignalId } : {},
10744
+ ...input.summarySignalId !== void 0 ? { summarySignalId: input.summarySignalId } : {},
10745
+ updatedAt: now
10746
+ });
10747
+ const updated = await this.getNotification({ threadId: input.threadId, id: input.id });
10748
+ if (!updated) throw new Error(`Notification ${input.id} was not found for thread ${input.threadId}`);
10749
+ return updated;
10750
+ }
10751
+ async findCoalescable(input) {
10752
+ if (!input.dedupeKey && !input.coalesceKey) return void 0;
10753
+ const schemaName = getSchemaName2(this.#schema);
10754
+ const tableName = getTableName2({ indexName: storage.TABLE_NOTIFICATIONS, schemaName });
10755
+ const row = await this.#db.client.oneOrNone(
10756
+ `SELECT * FROM ${tableName} WHERE "threadId" = $1 AND "source" = $2 AND "kind" = $3 AND "status" = $4 AND (("agentId" = $5::text) OR ("agentId" IS NULL AND $5::text IS NULL)) AND (("resourceId" = $6::text) OR ("resourceId" IS NULL AND $6::text IS NULL)) AND (($7::text IS NOT NULL AND "dedupeKey" = $7::text) OR ($8::text IS NOT NULL AND "coalesceKey" = $8::text)) ORDER BY "updatedAt" DESC LIMIT 1`,
10757
+ [
10758
+ input.threadId,
10759
+ input.source,
10760
+ input.kind,
10761
+ "pending",
10762
+ input.agentId ?? null,
10763
+ input.resourceId ?? null,
10764
+ input.dedupeKey ?? null,
10765
+ input.coalesceKey ?? null
10766
+ ]
10767
+ );
10768
+ return row ? rowToNotification(row) : void 0;
10769
+ }
10770
+ };
10429
10771
  var ObservabilityPG = class _ObservabilityPG extends storage.ObservabilityStorage {
10430
10772
  #db;
10431
10773
  #schema;
@@ -15005,6 +15347,7 @@ var DEFAULT_MAX_CONNECTIONS = 20;
15005
15347
  var DEFAULT_IDLE_TIMEOUT_MS = 3e4;
15006
15348
  var ALL_DOMAINS = [
15007
15349
  MemoryPG,
15350
+ NotificationsPG,
15008
15351
  ObservabilityPG,
15009
15352
  ScoresPG,
15010
15353
  ScorerDefinitionsPG,
@@ -15060,6 +15403,7 @@ var PostgresStore = class extends storage.MastraCompositeStore {
15060
15403
  scores: new ScoresPG(domainConfig),
15061
15404
  workflows: new WorkflowsPG(domainConfig),
15062
15405
  memory: new MemoryPG(domainConfig),
15406
+ notifications: new NotificationsPG(domainConfig),
15063
15407
  observability: new ObservabilityPG(domainConfig),
15064
15408
  agents: new AgentsPG(domainConfig),
15065
15409
  promptBlocks: new PromptBlocksPG(domainConfig),
@@ -15273,6 +15617,7 @@ exports.FavoritesPG = FavoritesPG;
15273
15617
  exports.MCPClientsPG = MCPClientsPG;
15274
15618
  exports.MCPServersPG = MCPServersPG;
15275
15619
  exports.MemoryPG = MemoryPG;
15620
+ exports.NotificationsPG = NotificationsPG;
15276
15621
  exports.ObservabilityPG = ObservabilityPG;
15277
15622
  exports.PGVECTOR_PROMPT = PGVECTOR_PROMPT;
15278
15623
  exports.PgVector = PgVector;