@mastra/pg 1.31.0-alpha.2 → 1.31.0-alpha.4

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.
Files changed (32) hide show
  1. package/dist/_types/@internal_core/dist/knowledge-compat/index.d.ts +594 -0
  2. package/dist/_types/@internal_core/package.json +1 -0
  3. package/dist/docs/SKILL.md +1 -1
  4. package/dist/docs/assets/SOURCE_MAP.json +1 -1
  5. package/dist/docs/references/reference-storage-retention.md +21 -18
  6. package/dist/index.cjs +1749 -310
  7. package/dist/index.cjs.map +1 -1
  8. package/dist/index.js +1752 -313
  9. package/dist/index.js.map +1 -1
  10. package/dist/shared/config.d.ts +6 -0
  11. package/dist/shared/config.d.ts.map +1 -1
  12. package/dist/storage/db/index.d.ts +15 -9
  13. package/dist/storage/db/index.d.ts.map +1 -1
  14. package/dist/storage/db/run-fencing.d.ts +23 -0
  15. package/dist/storage/db/run-fencing.d.ts.map +1 -0
  16. package/dist/storage/domains/agents/index.d.ts.map +1 -1
  17. package/dist/storage/domains/knowledge/index.d.ts +38 -9
  18. package/dist/storage/domains/knowledge/index.d.ts.map +1 -1
  19. package/dist/storage/domains/mcp-clients/index.d.ts.map +1 -1
  20. package/dist/storage/domains/mcp-servers/index.d.ts.map +1 -1
  21. package/dist/storage/domains/memory/index.d.ts +21 -7
  22. package/dist/storage/domains/memory/index.d.ts.map +1 -1
  23. package/dist/storage/domains/prompt-blocks/index.d.ts.map +1 -1
  24. package/dist/storage/domains/scorer-definitions/index.d.ts.map +1 -1
  25. package/dist/storage/domains/skills/index.d.ts.map +1 -1
  26. package/dist/storage/domains/workflows/index.d.ts +21 -6
  27. package/dist/storage/domains/workflows/index.d.ts.map +1 -1
  28. package/dist/storage/domains/workspaces/index.d.ts.map +1 -1
  29. package/dist/storage/index.d.ts.map +1 -1
  30. package/dist/storage/retention.d.ts +3 -3
  31. package/dist/storage/retention.d.ts.map +1 -1
  32. package/package.json +5 -4
package/dist/index.cjs CHANGED
@@ -35,8 +35,8 @@ let pg_connection_string = require("pg-connection-string");
35
35
  let _mastra_core_vector_filter = require("@mastra/core/vector/filter");
36
36
  let _mastra_core_base = require("@mastra/core/base");
37
37
  let crypto$1 = require("crypto");
38
- let _mastra_core_agent = require("@mastra/core/agent");
39
38
  let _mastra_core_features = require("@mastra/core/features");
39
+ let _mastra_core_agent = require("@mastra/core/agent");
40
40
  let _mastra_core_evals = require("@mastra/core/evals");
41
41
  let _mastra_core_storage_domains_skills = require("@mastra/core/storage/domains/skills");
42
42
  let util = require("util");
@@ -3213,9 +3213,10 @@ var PgDB = class extends _mastra_core_base.MastraBase {
3213
3213
  }
3214
3214
  await flush();
3215
3215
  }
3216
- async insert({ tableName, record }) {
3216
+ /** `client` lets a caller run the insert inside its own transaction. */
3217
+ async insert({ tableName, record }, client = this.client) {
3217
3218
  try {
3218
- await this.executeInsert(this.client, {
3219
+ await this.executeInsert(client, {
3219
3220
  tableName,
3220
3221
  record
3221
3222
  });
@@ -4049,13 +4050,15 @@ MIGRATION REQUIRED: Duplicate spans detected in ${duplicateInfo.tableName}\n====
4049
4050
  indexName: tableName,
4050
4051
  schemaName: getSchemaName$6(this.schemaName)
4051
4052
  });
4053
+ const parsedColumn = `"${(0, _mastra_core_utils.parseSqlIdentifier)(column, "column name")}"`;
4052
4054
  const sql = `
4053
4055
  DELETE FROM ${fullTableName}
4054
4056
  WHERE ctid IN (
4055
4057
  SELECT ctid FROM ${fullTableName}
4056
- WHERE ${`"${(0, _mastra_core_utils.parseSqlIdentifier)(column, "column name")}"`} < $1
4058
+ WHERE ${parsedColumn} < $1
4057
4059
  LIMIT $2
4058
4060
  )
4061
+ AND ${parsedColumn} < $1
4059
4062
  `;
4060
4063
  return (await this.client.query(sql, [cutoff, limit])).rowCount ?? 0;
4061
4064
  }
@@ -4518,6 +4521,7 @@ var AgentsPG = class AgentsPG extends _mastra_core_storage.AgentsStorage {
4518
4521
  }
4519
4522
  async create(input) {
4520
4523
  const { agent } = input;
4524
+ let draftInserted = false;
4521
4525
  try {
4522
4526
  const agentsTable = getTableName$5({
4523
4527
  indexName: _mastra_core_storage.TABLE_AGENTS,
@@ -4544,6 +4548,7 @@ var AgentsPG = class AgentsPG extends _mastra_core_storage.AgentsStorage {
4544
4548
  nowIso,
4545
4549
  nowIso
4546
4550
  ]);
4551
+ draftInserted = true;
4547
4552
  const { id: _id, authorId: _authorId, visibility: _visibility, metadata: _metadata, ...snapshotConfig } = agent;
4548
4553
  const versionId = crypto.randomUUID();
4549
4554
  await this.createVersion({
@@ -4566,14 +4571,14 @@ var AgentsPG = class AgentsPG extends _mastra_core_storage.AgentsStorage {
4566
4571
  updatedAt: now
4567
4572
  };
4568
4573
  } catch (error) {
4569
- if (error instanceof _mastra_core_error.MastraError) throw error;
4570
- try {
4574
+ if (draftInserted) try {
4571
4575
  const agentsTable = getTableName$5({
4572
4576
  indexName: _mastra_core_storage.TABLE_AGENTS,
4573
4577
  schemaName: getSchemaName$5(this.#schema)
4574
4578
  });
4575
4579
  await this.#db.client.none(`DELETE FROM ${agentsTable} WHERE id = $1 AND status = 'draft' AND "activeVersionId" IS NULL`, [agent.id]);
4576
4580
  } catch {}
4581
+ if (error instanceof _mastra_core_error.MastraError) throw error;
4577
4582
  throw new _mastra_core_error.MastraError({
4578
4583
  id: (0, _mastra_core_storage.createStorageErrorId)("PG", "CREATE_AGENT", "FAILED"),
4579
4584
  domain: _mastra_core_error.ErrorDomain.STORAGE,
@@ -8301,18 +8306,650 @@ var FavoritesPG = class FavoritesPG extends _mastra_core_storage.FavoritesStorag
8301
8306
  }
8302
8307
  };
8303
8308
  //#endregion
8309
+ //#region ../../packages/_internal-core/dist/knowledge-compat/index.js
8310
+ const KNOWLEDGE_V2_CORE_FEATURE = "knowledge-v2";
8311
+ /** Hard cap on scope nodes returned by one `listScopeNodes` read. */
8312
+ const MAX_KNOWLEDGE_SCOPE_NODES = 1e3;
8313
+ function knowledgeScopeNodeFilterKey(input) {
8314
+ return JSON.stringify([
8315
+ input.withinAddress ?? null,
8316
+ input.addresses ? [...input.addresses].sort() : null,
8317
+ input.ids ? [...input.ids].sort() : null
8318
+ ]);
8319
+ }
8320
+ function createKnowledgeScopeNodeCursor(scope, input) {
8321
+ return encodeURIComponent(JSON.stringify({
8322
+ version: 1,
8323
+ type: "scope",
8324
+ name: scope.name,
8325
+ id: scope.id,
8326
+ filter: knowledgeScopeNodeFilterKey(input)
8327
+ }));
8328
+ }
8329
+ /** Validates the page size and cursor of a `listScopeNodes` query; throws on a cursor from a different query. */
8330
+ function parseListKnowledgeScopeNodesInput(input = {}) {
8331
+ const requested = Number.isFinite(input.limit) ? Math.trunc(input.limit) : MAX_KNOWLEDGE_SCOPE_NODES;
8332
+ const limit = Math.min(Math.max(requested, 1), MAX_KNOWLEDGE_SCOPE_NODES);
8333
+ if (!input.cursor) return {
8334
+ limit,
8335
+ after: null
8336
+ };
8337
+ let value;
8338
+ try {
8339
+ value = JSON.parse(decodeURIComponent(input.cursor));
8340
+ } catch {
8341
+ throw new Error("Invalid Knowledge scope node cursor.");
8342
+ }
8343
+ const parsed = value && typeof value === "object" ? value : {};
8344
+ if (parsed.version !== 1 || parsed.type !== "scope" || typeof parsed.name !== "string" || typeof parsed.id !== "string" || parsed.filter !== knowledgeScopeNodeFilterKey(input)) throw new Error("Knowledge scope node cursor does not match this query.");
8345
+ return {
8346
+ limit,
8347
+ after: {
8348
+ name: parsed.name,
8349
+ id: parsed.id
8350
+ }
8351
+ };
8352
+ }
8353
+ /** Builds a page from up to `limit + 1` name/id-ordered scope nodes. */
8354
+ function pageKnowledgeScopeNodes(rows, limit, input) {
8355
+ const scopes = rows.slice(0, limit);
8356
+ const last = scopes.at(-1);
8357
+ return {
8358
+ scopes,
8359
+ nextCursor: rows.length > limit && last ? createKnowledgeScopeNodeCursor(last, input) : null
8360
+ };
8361
+ }
8362
+ /** Clamps a requested member limit to 1–{@link MAX_KNOWLEDGE_SCOPE_MEMBERS_LIMIT}. */
8363
+ function knowledgeScopeMembersLimit(limit) {
8364
+ if (limit === void 0 || !Number.isFinite(limit)) return 500;
8365
+ return Math.min(Math.max(Math.trunc(limit), 1), 500);
8366
+ }
8367
+ /** Validates the page size and cursor of a `listScopeMembers` query; throws on a cursor from another scope. */
8368
+ function parseListKnowledgeScopeMembersInput(input) {
8369
+ const limit = knowledgeScopeMembersLimit(input.limit);
8370
+ if (!input.cursor) return {
8371
+ limit,
8372
+ after: null
8373
+ };
8374
+ let value;
8375
+ try {
8376
+ value = JSON.parse(decodeURIComponent(input.cursor));
8377
+ } catch {
8378
+ throw new Error("Invalid Knowledge scope member cursor.");
8379
+ }
8380
+ const parsed = value && typeof value === "object" ? value : {};
8381
+ const updatedAt = typeof parsed.updatedAt === "string" ? new Date(parsed.updatedAt) : /* @__PURE__ */ new Date(NaN);
8382
+ if (parsed.version !== 1 || parsed.type !== "scope-member" || parsed.scopeNodeId !== input.scopeNodeId || typeof parsed.name !== "string" || typeof parsed.id !== "string" || Number.isNaN(updatedAt.getTime())) throw new Error("Knowledge scope member cursor does not match this query.");
8383
+ return {
8384
+ limit,
8385
+ after: {
8386
+ updatedAt,
8387
+ name: parsed.name,
8388
+ id: parsed.id
8389
+ }
8390
+ };
8391
+ }
8392
+ /** Builds a page from up to `limit + 1` members in `listScopeMembers` order. */
8393
+ function pageKnowledgeScopeMembers(rows, limit, input) {
8394
+ const members = rows.slice(0, limit);
8395
+ const last = members.at(-1);
8396
+ const hasMore = rows.length > limit;
8397
+ return {
8398
+ members,
8399
+ hasMore,
8400
+ nextCursor: hasMore && last ? encodeURIComponent(JSON.stringify({
8401
+ version: 1,
8402
+ type: "scope-member",
8403
+ scopeNodeId: input.scopeNodeId,
8404
+ updatedAt: last.updatedAt.toISOString(),
8405
+ name: last.name,
8406
+ id: last.id
8407
+ })) : null
8408
+ };
8409
+ }
8410
+ const TABLE_KNOWLEDGE_NODES$1 = "mastra_knowledge_nodes";
8411
+ const TABLE_KNOWLEDGE_RECORDS$1 = "mastra_knowledge_records";
8412
+ const TABLE_KNOWLEDGE_MENTIONS$1 = "mastra_knowledge_mentions";
8413
+ const TABLE_KNOWLEDGE_ACTIVITY$1 = "mastra_knowledge_activity";
8414
+ const TABLE_KNOWLEDGE_SEMANTIC_OUTBOX$1 = "mastra_knowledge_semantic_outbox";
8415
+ const TABLE_KNOWLEDGE_NODE_SCOPES = "mastra_knowledge_node_scopes";
8416
+ const TABLE_KNOWLEDGE_RECORD_SCOPES = "mastra_knowledge_record_scopes";
8417
+ const TABLE_KNOWLEDGE_SCOPE_GRANTS = "mastra_knowledge_scope_grants";
8418
+ const TABLE_KNOWLEDGE_ACCESS_STATE = "mastra_knowledge_access_state";
8419
+ const TABLE_KNOWLEDGE_SCOPE_ADDRESSES = "mastra_knowledge_scope_addresses";
8420
+ const TABLE_KNOWLEDGE_NODE_ADDRESSES = "mastra_knowledge_node_addresses";
8421
+ const TABLE_KNOWLEDGE_IMPORT_STATE = "mastra_knowledge_import_state";
8422
+ const TABLE_KNOWLEDGE_IMPORT_RUNS = "mastra_knowledge_import_runs";
8423
+ const TABLE_KNOWLEDGE_PROPOSALS = "mastra_knowledge_proposals";
8424
+ const KNOWLEDGE_TABLE_NAMES = [
8425
+ TABLE_KNOWLEDGE_NODES$1,
8426
+ TABLE_KNOWLEDGE_RECORDS$1,
8427
+ TABLE_KNOWLEDGE_MENTIONS$1,
8428
+ TABLE_KNOWLEDGE_ACTIVITY$1,
8429
+ TABLE_KNOWLEDGE_SEMANTIC_OUTBOX$1,
8430
+ TABLE_KNOWLEDGE_NODE_SCOPES,
8431
+ TABLE_KNOWLEDGE_RECORD_SCOPES,
8432
+ TABLE_KNOWLEDGE_SCOPE_GRANTS,
8433
+ TABLE_KNOWLEDGE_ACCESS_STATE,
8434
+ TABLE_KNOWLEDGE_SCOPE_ADDRESSES,
8435
+ TABLE_KNOWLEDGE_NODE_ADDRESSES,
8436
+ TABLE_KNOWLEDGE_IMPORT_STATE,
8437
+ TABLE_KNOWLEDGE_IMPORT_RUNS,
8438
+ TABLE_KNOWLEDGE_PROPOSALS
8439
+ ];
8440
+ /** Knowledge v1 tables with no v2 equivalent; an explicit schema reset drops them. */
8441
+ const RETIRED_KNOWLEDGE_TABLE_NAMES = ["mastra_knowledge_cursors"];
8442
+ /** Tables and indexes published v1 adapters created for every app, whether or not it used Knowledge. */
8443
+ const PUBLISHED_KNOWLEDGE_V1_TABLE_NAMES = /* @__PURE__ */ new Set([
8444
+ TABLE_KNOWLEDGE_NODES$1,
8445
+ TABLE_KNOWLEDGE_RECORDS$1,
8446
+ TABLE_KNOWLEDGE_MENTIONS$1,
8447
+ TABLE_KNOWLEDGE_ACTIVITY$1,
8448
+ TABLE_KNOWLEDGE_SEMANTIC_OUTBOX$1,
8449
+ ...RETIRED_KNOWLEDGE_TABLE_NAMES
8450
+ ]);
8451
+ const PUBLISHED_KNOWLEDGE_V1_INDEX_NAMES = /* @__PURE__ */ new Set([
8452
+ "idx_knowledge_nodes_identity",
8453
+ "idx_knowledge_nodes_scope",
8454
+ "idx_knowledge_records_node_latest",
8455
+ "idx_knowledge_records_thread_latest",
8456
+ "idx_knowledge_mentions_record",
8457
+ "idx_knowledge_activity_latest",
8458
+ "idx_knowledge_outbox_idempotency",
8459
+ "idx_knowledge_outbox_claim"
8460
+ ]);
8461
+ const KNOWLEDGE_V2_NODES_SCHEMA = {
8462
+ id: {
8463
+ type: "text",
8464
+ nullable: false,
8465
+ primaryKey: true
8466
+ },
8467
+ name: {
8468
+ type: "text",
8469
+ nullable: false
8470
+ },
8471
+ kind: {
8472
+ type: "text",
8473
+ nullable: true
8474
+ },
8475
+ isScope: {
8476
+ type: "boolean",
8477
+ nullable: false
8478
+ },
8479
+ metadata: {
8480
+ type: "jsonb",
8481
+ nullable: true
8482
+ },
8483
+ version: {
8484
+ type: "integer",
8485
+ nullable: false
8486
+ },
8487
+ createdAt: {
8488
+ type: "timestamp",
8489
+ nullable: false
8490
+ },
8491
+ updatedAt: {
8492
+ type: "timestamp",
8493
+ nullable: false
8494
+ },
8495
+ deletedAt: {
8496
+ type: "timestamp",
8497
+ nullable: true
8498
+ },
8499
+ deletedBy: {
8500
+ type: "text",
8501
+ nullable: true
8502
+ },
8503
+ type: {
8504
+ type: "text",
8505
+ nullable: true
8506
+ },
8507
+ canonicalName: {
8508
+ type: "text",
8509
+ nullable: true
8510
+ },
8511
+ content: {
8512
+ type: "text",
8513
+ nullable: true
8514
+ },
8515
+ description: {
8516
+ type: "text",
8517
+ nullable: true
8518
+ },
8519
+ scope: {
8520
+ type: "jsonb",
8521
+ nullable: true
8522
+ },
8523
+ scopeKey: {
8524
+ type: "text",
8525
+ nullable: true
8526
+ },
8527
+ mergedInto: {
8528
+ type: "text",
8529
+ nullable: true
8530
+ }
8531
+ };
8532
+ const KNOWLEDGE_V2_RECORDS_SCHEMA = {
8533
+ id: {
8534
+ type: "text",
8535
+ nullable: false,
8536
+ primaryKey: true
8537
+ },
8538
+ node: {
8539
+ type: "text",
8540
+ nullable: false,
8541
+ references: {
8542
+ table: TABLE_KNOWLEDGE_NODES$1,
8543
+ column: "id"
8544
+ }
8545
+ },
8546
+ text: {
8547
+ type: "text",
8548
+ nullable: false
8549
+ },
8550
+ metadata: {
8551
+ type: "jsonb",
8552
+ nullable: true
8553
+ },
8554
+ version: {
8555
+ type: "integer",
8556
+ nullable: false
8557
+ },
8558
+ capturedAt: {
8559
+ type: "timestamp",
8560
+ nullable: false
8561
+ },
8562
+ updatedAt: {
8563
+ type: "timestamp",
8564
+ nullable: false
8565
+ },
8566
+ deletedAt: {
8567
+ type: "timestamp",
8568
+ nullable: true
8569
+ },
8570
+ deletedBy: {
8571
+ type: "text",
8572
+ nullable: true
8573
+ },
8574
+ scope: {
8575
+ type: "jsonb",
8576
+ nullable: true
8577
+ },
8578
+ scopeKey: {
8579
+ type: "text",
8580
+ nullable: true
8581
+ },
8582
+ sourceThreadId: {
8583
+ type: "text",
8584
+ nullable: true
8585
+ },
8586
+ when: {
8587
+ type: "timestamp",
8588
+ nullable: true
8589
+ }
8590
+ };
8591
+ const KNOWLEDGE_V2_MENTIONS_SCHEMA = {
8592
+ recordId: {
8593
+ type: "text",
8594
+ nullable: false,
8595
+ references: {
8596
+ table: TABLE_KNOWLEDGE_RECORDS$1,
8597
+ column: "id"
8598
+ }
8599
+ },
8600
+ targetNodeId: {
8601
+ type: "text",
8602
+ nullable: true,
8603
+ references: {
8604
+ table: TABLE_KNOWLEDGE_NODES$1,
8605
+ column: "id"
8606
+ }
8607
+ },
8608
+ sourceType: {
8609
+ type: "text",
8610
+ nullable: true
8611
+ },
8612
+ sourceId: {
8613
+ type: "text",
8614
+ nullable: true
8615
+ }
8616
+ };
8617
+ const KNOWLEDGE_NODE_SCOPES_SCHEMA = {
8618
+ nodeId: {
8619
+ type: "text",
8620
+ nullable: false,
8621
+ references: {
8622
+ table: TABLE_KNOWLEDGE_NODES$1,
8623
+ column: "id"
8624
+ }
8625
+ },
8626
+ scopeNodeId: {
8627
+ type: "text",
8628
+ nullable: false,
8629
+ references: {
8630
+ table: TABLE_KNOWLEDGE_NODES$1,
8631
+ column: "id"
8632
+ }
8633
+ },
8634
+ addedAt: {
8635
+ type: "timestamp",
8636
+ nullable: false
8637
+ }
8638
+ };
8639
+ const KNOWLEDGE_RECORD_SCOPES_SCHEMA = {
8640
+ recordId: {
8641
+ type: "text",
8642
+ nullable: false,
8643
+ references: {
8644
+ table: TABLE_KNOWLEDGE_RECORDS$1,
8645
+ column: "id"
8646
+ }
8647
+ },
8648
+ scopeNodeId: {
8649
+ type: "text",
8650
+ nullable: false,
8651
+ references: {
8652
+ table: TABLE_KNOWLEDGE_NODES$1,
8653
+ column: "id"
8654
+ }
8655
+ },
8656
+ addedAt: {
8657
+ type: "timestamp",
8658
+ nullable: false
8659
+ }
8660
+ };
8661
+ const KNOWLEDGE_SCOPE_GRANTS_SCHEMA = {
8662
+ scopeNodeId: {
8663
+ type: "text",
8664
+ nullable: false,
8665
+ references: {
8666
+ table: TABLE_KNOWLEDGE_NODES$1,
8667
+ column: "id"
8668
+ }
8669
+ },
8670
+ scopeRefId: {
8671
+ type: "text",
8672
+ nullable: false,
8673
+ references: {
8674
+ table: TABLE_KNOWLEDGE_NODES$1,
8675
+ column: "id"
8676
+ }
8677
+ },
8678
+ role: {
8679
+ type: "text",
8680
+ nullable: false
8681
+ },
8682
+ canSuggest: {
8683
+ type: "boolean",
8684
+ nullable: true
8685
+ }
8686
+ };
8687
+ const KNOWLEDGE_ACCESS_STATE_SCHEMA = {
8688
+ id: {
8689
+ type: "text",
8690
+ nullable: false,
8691
+ primaryKey: true
8692
+ },
8693
+ epoch: {
8694
+ type: "integer",
8695
+ nullable: false
8696
+ },
8697
+ schemaVersion: {
8698
+ type: "integer",
8699
+ nullable: false
8700
+ }
8701
+ };
8702
+ const KNOWLEDGE_SCOPE_ADDRESSES_SCHEMA = {
8703
+ address: {
8704
+ type: "text",
8705
+ nullable: false,
8706
+ primaryKey: true
8707
+ },
8708
+ scopeNodeId: {
8709
+ type: "text",
8710
+ nullable: false,
8711
+ references: {
8712
+ table: TABLE_KNOWLEDGE_NODES$1,
8713
+ column: "id"
8714
+ }
8715
+ }
8716
+ };
8717
+ const KNOWLEDGE_NODE_ADDRESSES_SCHEMA = {
8718
+ source: {
8719
+ type: "text",
8720
+ nullable: false
8721
+ },
8722
+ address: {
8723
+ type: "text",
8724
+ nullable: false
8725
+ },
8726
+ nodeId: {
8727
+ type: "text",
8728
+ nullable: false,
8729
+ references: {
8730
+ table: TABLE_KNOWLEDGE_NODES$1,
8731
+ column: "id"
8732
+ }
8733
+ }
8734
+ };
8735
+ const KNOWLEDGE_IMPORT_STATE_SCHEMA = {
8736
+ importerId: {
8737
+ type: "text",
8738
+ nullable: false
8739
+ },
8740
+ binding: {
8741
+ type: "text",
8742
+ nullable: false
8743
+ },
8744
+ key: {
8745
+ type: "text",
8746
+ nullable: false
8747
+ },
8748
+ value: {
8749
+ type: "text",
8750
+ nullable: false
8751
+ }
8752
+ };
8753
+ const KNOWLEDGE_IMPORT_RUNS_SCHEMA = {
8754
+ id: {
8755
+ type: "text",
8756
+ nullable: false,
8757
+ primaryKey: true
8758
+ },
8759
+ importerId: {
8760
+ type: "text",
8761
+ nullable: false
8762
+ },
8763
+ binding: {
8764
+ type: "text",
8765
+ nullable: false
8766
+ },
8767
+ importKind: {
8768
+ type: "text",
8769
+ nullable: false
8770
+ },
8771
+ triggerKind: {
8772
+ type: "text",
8773
+ nullable: false
8774
+ },
8775
+ status: {
8776
+ type: "text",
8777
+ nullable: false
8778
+ },
8779
+ error: {
8780
+ type: "text",
8781
+ nullable: true
8782
+ },
8783
+ transcriptThreadId: {
8784
+ type: "text",
8785
+ nullable: true
8786
+ },
8787
+ traceId: {
8788
+ type: "text",
8789
+ nullable: true
8790
+ },
8791
+ queuedAt: {
8792
+ type: "timestamp",
8793
+ nullable: false
8794
+ },
8795
+ startedAt: {
8796
+ type: "timestamp",
8797
+ nullable: true
8798
+ },
8799
+ completedAt: {
8800
+ type: "timestamp",
8801
+ nullable: true
8802
+ }
8803
+ };
8804
+ const KNOWLEDGE_V2_ACTIVITY_SCHEMA = {
8805
+ id: {
8806
+ type: "text",
8807
+ nullable: false,
8808
+ primaryKey: true
8809
+ },
8810
+ action: {
8811
+ type: "text",
8812
+ nullable: false
8813
+ },
8814
+ targetType: {
8815
+ type: "text",
8816
+ nullable: true
8817
+ },
8818
+ targetId: {
8819
+ type: "text",
8820
+ nullable: true
8821
+ },
8822
+ contextScopeId: {
8823
+ type: "text",
8824
+ nullable: true,
8825
+ references: {
8826
+ table: TABLE_KNOWLEDGE_NODES$1,
8827
+ column: "id"
8828
+ }
8829
+ },
8830
+ importRunId: {
8831
+ type: "text",
8832
+ nullable: true,
8833
+ references: {
8834
+ table: TABLE_KNOWLEDGE_IMPORT_RUNS,
8835
+ column: "id"
8836
+ }
8837
+ },
8838
+ details: {
8839
+ type: "jsonb",
8840
+ nullable: true
8841
+ },
8842
+ createdAt: {
8843
+ type: "timestamp",
8844
+ nullable: false
8845
+ },
8846
+ recordType: {
8847
+ type: "text",
8848
+ nullable: true
8849
+ },
8850
+ recordId: {
8851
+ type: "text",
8852
+ nullable: true
8853
+ },
8854
+ scope: {
8855
+ type: "jsonb",
8856
+ nullable: true
8857
+ },
8858
+ scopeKey: {
8859
+ type: "text",
8860
+ nullable: true
8861
+ },
8862
+ sourceThreadId: {
8863
+ type: "text",
8864
+ nullable: true
8865
+ }
8866
+ };
8867
+ const KNOWLEDGE_PROPOSALS_SCHEMA = {
8868
+ id: {
8869
+ type: "text",
8870
+ nullable: false,
8871
+ primaryKey: true
8872
+ },
8873
+ targetType: {
8874
+ type: "text",
8875
+ nullable: false
8876
+ },
8877
+ targetId: {
8878
+ type: "text",
8879
+ nullable: false
8880
+ },
8881
+ action: {
8882
+ type: "text",
8883
+ nullable: false
8884
+ },
8885
+ changes: {
8886
+ type: "jsonb",
8887
+ nullable: false
8888
+ },
8889
+ reason: {
8890
+ type: "text",
8891
+ nullable: true
8892
+ },
8893
+ proposerContextScopeId: {
8894
+ type: "text",
8895
+ nullable: false
8896
+ },
8897
+ expectedVersion: {
8898
+ type: "integer",
8899
+ nullable: false
8900
+ },
8901
+ status: {
8902
+ type: "text",
8903
+ nullable: false
8904
+ },
8905
+ reviewerContextScopeId: {
8906
+ type: "text",
8907
+ nullable: true
8908
+ },
8909
+ reviewedAt: {
8910
+ type: "timestamp",
8911
+ nullable: true
8912
+ },
8913
+ createdAt: {
8914
+ type: "timestamp",
8915
+ nullable: false
8916
+ }
8917
+ };
8918
+ function assertKnowledgeV2CoreSupport(features) {
8919
+ if (!features.has("knowledge-v2")) throw new Error(`Knowledge v2 requires a @mastra/core release with the "${KNOWLEDGE_V2_CORE_FEATURE}" feature. Upgrade @mastra/core to use Knowledge; other storage domains keep working on this version.`);
8920
+ }
8921
+ function resolveKnowledgeV2Core(storageModule) {
8922
+ if (typeof storageModule !== "object" || storageModule === null) throw new Error("@mastra/core advertises Knowledge v2 without the required storage API");
8923
+ const { assertKnowledgeDescriptionWithinBound: assertDescription, assertKnowledgeRecordTextWithinBound: assertRecordText, assertKnowledgeSchemaCompatible: assertCompatible, inspectKnowledgeSchema: inspectSchema } = storageModule;
8924
+ if (typeof assertDescription !== "function" || typeof assertRecordText !== "function" || typeof assertCompatible !== "function" || typeof inspectSchema !== "function") throw new Error("@mastra/core advertises Knowledge v2 without the required storage API");
8925
+ return {
8926
+ assertKnowledgeDescriptionWithinBound: (description) => assertDescription(description),
8927
+ assertKnowledgeRecordTextWithinBound: (text) => assertRecordText(text),
8928
+ assertKnowledgeSchemaCompatible: (inspection) => assertCompatible(inspection),
8929
+ inspectKnowledgeSchema: (snapshot) => inspectSchema(snapshot)
8930
+ };
8931
+ }
8932
+ function createKnowledgeV2CoreLoader(features, loadStorageModule) {
8933
+ let knowledgeV2Core;
8934
+ return async () => {
8935
+ assertKnowledgeV2CoreSupport(features);
8936
+ knowledgeV2Core ??= loadStorageModule().then(resolveKnowledgeV2Core).catch((error) => {
8937
+ knowledgeV2Core = void 0;
8938
+ throw error;
8939
+ });
8940
+ return knowledgeV2Core;
8941
+ };
8942
+ }
8943
+ //#endregion
8304
8944
  //#region src/storage/domains/knowledge/index.ts
8305
- let assertDescriptionWithinBound;
8945
+ const loadKnowledgeV2Core = createKnowledgeV2CoreLoader(_mastra_core_features.coreFeatures, () => import("@mastra/core/storage"));
8306
8946
  async function assertKnowledgeDescriptionWithinBoundCompat(description) {
8307
- let assertWithinBound = assertDescriptionWithinBound;
8308
- if (!assertWithinBound) {
8309
- const resolvedAssert = (await import("@mastra/core/storage")).assertKnowledgeDescriptionWithinBound ?? ((value) => {
8310
- if (value !== void 0 && value.length > 400) throw new Error("Knowledge node description exceeds the 400 UTF-16 code unit limit");
8311
- });
8312
- assertDescriptionWithinBound = resolvedAssert;
8313
- assertWithinBound = resolvedAssert;
8314
- }
8315
- assertWithinBound(description);
8947
+ const { assertKnowledgeDescriptionWithinBound } = await loadKnowledgeV2Core();
8948
+ assertKnowledgeDescriptionWithinBound(description);
8949
+ }
8950
+ async function assertKnowledgeRecordTextWithinBoundCompat(text) {
8951
+ const { assertKnowledgeRecordTextWithinBound } = await loadKnowledgeV2Core();
8952
+ assertKnowledgeRecordTextWithinBound(text);
8316
8953
  }
8317
8954
  const camelCaseColumns = [
8318
8955
  "canonicalName",
@@ -8323,7 +8960,6 @@ const camelCaseColumns = [
8323
8960
  "node",
8324
8961
  "sourceThreadId",
8325
8962
  "capturedAt",
8326
- "maxScope",
8327
8963
  "deletedAt",
8328
8964
  "deletedBy",
8329
8965
  "sourceType",
@@ -8337,7 +8973,30 @@ const camelCaseColumns = [
8337
8973
  "availableAt",
8338
8974
  "claimedAt",
8339
8975
  "claimedBy",
8340
- "completedAt"
8976
+ "completedAt",
8977
+ "isScope",
8978
+ "nodeId",
8979
+ "targetNodeId",
8980
+ "scopeNodeId",
8981
+ "scopeRefId",
8982
+ "canSuggest",
8983
+ "schemaVersion",
8984
+ "importerId",
8985
+ "importKind",
8986
+ "triggerKind",
8987
+ "transcriptThreadId",
8988
+ "traceId",
8989
+ "queuedAt",
8990
+ "startedAt",
8991
+ "targetType",
8992
+ "targetId",
8993
+ "contextScopeId",
8994
+ "importRunId",
8995
+ "proposerContextScopeId",
8996
+ "expectedVersion",
8997
+ "reviewerContextScopeId",
8998
+ "reviewedAt",
8999
+ "addedAt"
8341
9000
  ];
8342
9001
  function transformSqlCode(sql, transform) {
8343
9002
  return sql.split(/('(?:''|[^'])*')/g).map((part, index) => index % 2 === 0 ? transform(part) : part).join("");
@@ -8352,14 +9011,7 @@ function postgresSql(sql, schemaName) {
8352
9011
  const quotedSchema = `"${parseSchemaName(schemaName)}"`;
8353
9012
  normalized = transformSqlCode(normalized, (code) => {
8354
9013
  let transformed = code;
8355
- for (const table of [
8356
- _mastra_core_storage.TABLE_KNOWLEDGE_NODES,
8357
- _mastra_core_storage.TABLE_KNOWLEDGE_RECORDS,
8358
- _mastra_core_storage.TABLE_KNOWLEDGE_MENTIONS,
8359
- _mastra_core_storage.TABLE_KNOWLEDGE_CURSORS,
8360
- _mastra_core_storage.TABLE_KNOWLEDGE_ACTIVITY,
8361
- _mastra_core_storage.TABLE_KNOWLEDGE_SEMANTIC_OUTBOX
8362
- ]) transformed = transformed.replaceAll(`"${table}"`, `${quotedSchema}."${table}"`);
9014
+ for (const table of [...KNOWLEDGE_TABLE_NAMES, ...RETIRED_KNOWLEDGE_TABLE_NAMES]) transformed = transformed.replaceAll(`"${table}"`, `${quotedSchema}."${table}"`);
8363
9015
  return transformed;
8364
9016
  });
8365
9017
  }
@@ -8367,17 +9019,35 @@ function postgresSql(sql, schemaName) {
8367
9019
  return transformSqlCode(normalized, (code) => code.replace(/\?/g, () => `$${++index}`));
8368
9020
  }
8369
9021
  function createExecutor(client, schemaName) {
8370
- return { async execute(statement) {
9022
+ const execute = async (statement, qualifyWithSchema) => {
8371
9023
  const sql = typeof statement === "string" ? statement : statement.sql;
8372
9024
  const args = typeof statement === "string" ? [] : statement.args ?? [];
8373
- const result = await client.query(postgresSql(sql, schemaName), args);
9025
+ const result = await client.query(postgresSql(sql, qualifyWithSchema ? schemaName : void 0), args);
8374
9026
  return {
8375
9027
  rows: result.rows,
8376
9028
  rowsAffected: result.rowCount ?? 0
8377
9029
  };
8378
- } };
9030
+ };
9031
+ return {
9032
+ execute: (statement) => execute(statement, true),
9033
+ executeRaw: (statement) => execute(statement, false)
9034
+ };
8379
9035
  }
8380
- const visibleSql = `(scopeKey = ? OR LEFT(?, LENGTH(scopeKey) + 1) = scopeKey || chr(31))`;
9036
+ /**
9037
+ * Scope keys visible to a caller holding `scope`: a row is visible when its scope is a subset of the
9038
+ * caller's (companion entries such as `resource:x:uncurated` make this more than a prefix match).
9039
+ * Matching rows by `scopeKey` keeps visibility filters on an index; a caller scope has only a few
9040
+ * entries, so the list stays small.
9041
+ */
9042
+ function visibleScopeKeys(scope) {
9043
+ const canonical = (0, _mastra_core_storage.canonicalizeKnowledgeScope)(scope);
9044
+ const keys = /* @__PURE__ */ new Set();
9045
+ for (let mask = 1; mask < 1 << canonical.length; mask++) try {
9046
+ keys.add((0, _mastra_core_storage.knowledgeScopeKey)(canonical.filter((_, index) => mask & 1 << index)));
9047
+ } catch {}
9048
+ return [...keys];
9049
+ }
9050
+ const visibleSql = (keys, scopeKeyColumn = "scopeKey") => `${scopeKeyColumn} IN (${keys.map(() => "?").join(",")})`;
8381
9051
  function parseJson$1(value) {
8382
9052
  if (typeof value === "string") return JSON.parse(value);
8383
9053
  if (value instanceof Uint8Array) return JSON.parse(new TextDecoder().decode(value));
@@ -8417,9 +9087,10 @@ function parseNode(row) {
8417
9087
  id: String(row.id),
8418
9088
  type: "node",
8419
9089
  name: String(row.name),
8420
- kind: String(row.kind),
9090
+ kind: row.kind == null ? "" : String(row.kind),
8421
9091
  content: row.content == null ? void 0 : String(row.content),
8422
9092
  description: row.description == null ? void 0 : String(row.description),
9093
+ isScope: row.isScope === true || row.isScope === 1 ? true : void 0,
8423
9094
  scope: parseJson$1(row.scopeJson ?? row.scope),
8424
9095
  version: Number(row.version),
8425
9096
  mergedInto: row.mergedInto == null ? void 0 : String(row.mergedInto),
@@ -8436,7 +9107,6 @@ function parseKnowledge(row) {
8436
9107
  sourceThreadId: String(row.sourceThreadId),
8437
9108
  capturedAt: toDate$1(row.capturedAt),
8438
9109
  when: optionalDate(row.when),
8439
- maxScope: row.maxScope == null ? void 0 : String(row.maxScope),
8440
9110
  metadata: row.metadata == null ? void 0 : parseJson$1(row.metadata),
8441
9111
  deletedAt: optionalDate(row.deletedAt),
8442
9112
  deletedBy: row.deletedBy == null ? void 0 : String(row.deletedBy)
@@ -8473,6 +9143,10 @@ function knowledgeIndexes(schemaName) {
8473
9143
  name: "idx_knowledge_nodes_scope",
8474
9144
  sql: `CREATE INDEX IF NOT EXISTS idx_knowledge_nodes_scope ON ${table(_mastra_core_storage.TABLE_KNOWLEDGE_NODES)} ("scopeKey", "type");`
8475
9145
  },
9146
+ {
9147
+ name: "idx_knowledge_nodes_name",
9148
+ sql: `CREATE INDEX IF NOT EXISTS idx_knowledge_nodes_name ON ${table(_mastra_core_storage.TABLE_KNOWLEDGE_NODES)} ("type", "canonicalName");`
9149
+ },
8476
9150
  {
8477
9151
  name: "idx_knowledge_records_node_latest",
8478
9152
  sql: `CREATE INDEX IF NOT EXISTS idx_knowledge_records_node_latest ON ${table(_mastra_core_storage.TABLE_KNOWLEDGE_RECORDS)} ("node", "id" DESC);`
@@ -8489,6 +9163,14 @@ function knowledgeIndexes(schemaName) {
8489
9163
  name: "idx_knowledge_activity_latest",
8490
9164
  sql: `CREATE INDEX IF NOT EXISTS idx_knowledge_activity_latest ON ${table(_mastra_core_storage.TABLE_KNOWLEDGE_ACTIVITY)} ("id" DESC);`
8491
9165
  },
9166
+ {
9167
+ name: "idx_knowledge_records_scope",
9168
+ sql: `CREATE INDEX IF NOT EXISTS idx_knowledge_records_scope ON ${table(_mastra_core_storage.TABLE_KNOWLEDGE_RECORDS)} ("scopeKey", "id");`
9169
+ },
9170
+ {
9171
+ name: "idx_knowledge_activity_scope",
9172
+ sql: `CREATE INDEX IF NOT EXISTS idx_knowledge_activity_scope ON ${table(_mastra_core_storage.TABLE_KNOWLEDGE_ACTIVITY)} ("scopeKey", "id" DESC);`
9173
+ },
8492
9174
  {
8493
9175
  name: "idx_knowledge_outbox_idempotency",
8494
9176
  sql: `CREATE UNIQUE INDEX IF NOT EXISTS idx_knowledge_outbox_idempotency ON ${table(_mastra_core_storage.TABLE_KNOWLEDGE_SEMANTIC_OUTBOX)} ("idempotencyKey");`
@@ -8496,67 +9178,152 @@ function knowledgeIndexes(schemaName) {
8496
9178
  {
8497
9179
  name: "idx_knowledge_outbox_claim",
8498
9180
  sql: `CREATE INDEX IF NOT EXISTS idx_knowledge_outbox_claim ON ${table(_mastra_core_storage.TABLE_KNOWLEDGE_SEMANTIC_OUTBOX)} ("status", "availableAt", "createdAt");`
9181
+ },
9182
+ {
9183
+ name: "idx_knowledge_node_scopes_scope",
9184
+ sql: `CREATE INDEX IF NOT EXISTS idx_knowledge_node_scopes_scope ON ${table(TABLE_KNOWLEDGE_NODE_SCOPES)} ("scopeNodeId", "nodeId");`
9185
+ },
9186
+ {
9187
+ name: "idx_knowledge_record_scopes_scope",
9188
+ sql: `CREATE INDEX IF NOT EXISTS idx_knowledge_record_scopes_scope ON ${table(TABLE_KNOWLEDGE_RECORD_SCOPES)} ("scopeNodeId", "recordId");`
9189
+ },
9190
+ {
9191
+ name: "idx_knowledge_scope_grants_ref",
9192
+ sql: `CREATE INDEX IF NOT EXISTS idx_knowledge_scope_grants_ref ON ${table(TABLE_KNOWLEDGE_SCOPE_GRANTS)} ("scopeRefId", "scopeNodeId");`
9193
+ },
9194
+ {
9195
+ name: "idx_knowledge_node_addresses_node",
9196
+ sql: `CREATE INDEX IF NOT EXISTS idx_knowledge_node_addresses_node ON ${table(TABLE_KNOWLEDGE_NODE_ADDRESSES)} ("nodeId");`
9197
+ },
9198
+ {
9199
+ name: "idx_knowledge_import_runs_lookup",
9200
+ sql: `CREATE INDEX IF NOT EXISTS idx_knowledge_import_runs_lookup ON ${table(TABLE_KNOWLEDGE_IMPORT_RUNS)} ("importerId", "binding", "queuedAt" DESC);`
9201
+ },
9202
+ {
9203
+ name: "idx_knowledge_activity_import_run",
9204
+ sql: `CREATE INDEX IF NOT EXISTS idx_knowledge_activity_import_run ON ${table(_mastra_core_storage.TABLE_KNOWLEDGE_ACTIVITY)} ("importRunId", "id" DESC);`
8499
9205
  }
8500
9206
  ];
8501
9207
  }
8502
9208
  function knowledgeIndexDDL(schemaName) {
8503
9209
  return knowledgeIndexes(schemaName).map((index) => index.sql);
8504
9210
  }
9211
+ const KNOWLEDGE_CURATION_CURSOR_REMOVED_MESSAGE = "Knowledge curation cursors were removed: observation-time curate is the only Knowledge writer and needs no cursor.";
9212
+ const knowledgeTableDefinitions = [
9213
+ {
9214
+ tableName: _mastra_core_storage.TABLE_KNOWLEDGE_NODES,
9215
+ schema: KNOWLEDGE_V2_NODES_SCHEMA
9216
+ },
9217
+ {
9218
+ tableName: _mastra_core_storage.TABLE_KNOWLEDGE_RECORDS,
9219
+ schema: KNOWLEDGE_V2_RECORDS_SCHEMA
9220
+ },
9221
+ {
9222
+ tableName: _mastra_core_storage.TABLE_KNOWLEDGE_MENTIONS,
9223
+ schema: KNOWLEDGE_V2_MENTIONS_SCHEMA,
9224
+ compositePrimaryKey: ["recordId", "sourceId"]
9225
+ },
9226
+ {
9227
+ tableName: TABLE_KNOWLEDGE_NODE_SCOPES,
9228
+ schema: KNOWLEDGE_NODE_SCOPES_SCHEMA,
9229
+ compositePrimaryKey: ["nodeId", "scopeNodeId"]
9230
+ },
9231
+ {
9232
+ tableName: TABLE_KNOWLEDGE_RECORD_SCOPES,
9233
+ schema: KNOWLEDGE_RECORD_SCOPES_SCHEMA,
9234
+ compositePrimaryKey: ["recordId", "scopeNodeId"]
9235
+ },
9236
+ {
9237
+ tableName: TABLE_KNOWLEDGE_SCOPE_GRANTS,
9238
+ schema: KNOWLEDGE_SCOPE_GRANTS_SCHEMA,
9239
+ compositePrimaryKey: ["scopeNodeId", "scopeRefId"]
9240
+ },
9241
+ {
9242
+ tableName: TABLE_KNOWLEDGE_ACCESS_STATE,
9243
+ schema: KNOWLEDGE_ACCESS_STATE_SCHEMA
9244
+ },
9245
+ {
9246
+ tableName: TABLE_KNOWLEDGE_SCOPE_ADDRESSES,
9247
+ schema: KNOWLEDGE_SCOPE_ADDRESSES_SCHEMA
9248
+ },
9249
+ {
9250
+ tableName: TABLE_KNOWLEDGE_NODE_ADDRESSES,
9251
+ schema: KNOWLEDGE_NODE_ADDRESSES_SCHEMA,
9252
+ compositePrimaryKey: ["source", "address"]
9253
+ },
9254
+ {
9255
+ tableName: TABLE_KNOWLEDGE_IMPORT_STATE,
9256
+ schema: KNOWLEDGE_IMPORT_STATE_SCHEMA,
9257
+ compositePrimaryKey: [
9258
+ "importerId",
9259
+ "binding",
9260
+ "key"
9261
+ ]
9262
+ },
9263
+ {
9264
+ tableName: TABLE_KNOWLEDGE_IMPORT_RUNS,
9265
+ schema: KNOWLEDGE_IMPORT_RUNS_SCHEMA
9266
+ },
9267
+ {
9268
+ tableName: TABLE_KNOWLEDGE_PROPOSALS,
9269
+ schema: KNOWLEDGE_PROPOSALS_SCHEMA
9270
+ },
9271
+ {
9272
+ tableName: _mastra_core_storage.TABLE_KNOWLEDGE_ACTIVITY,
9273
+ schema: KNOWLEDGE_V2_ACTIVITY_SCHEMA
9274
+ },
9275
+ {
9276
+ tableName: _mastra_core_storage.TABLE_KNOWLEDGE_SEMANTIC_OUTBOX,
9277
+ schema: _mastra_core_storage.KNOWLEDGE_SEMANTIC_OUTBOX_SCHEMA
9278
+ }
9279
+ ];
9280
+ function pgSetting(config, key) {
9281
+ const value = config[key] || process.env[`PG${key.toUpperCase()}`] || pg.defaults[key];
9282
+ return value === void 0 || value === null || value === "" ? void 0 : String(value);
9283
+ }
9284
+ function effectivePgTarget(config) {
9285
+ const host = pgSetting(config, "host");
9286
+ const database = pgSetting(config, "database") ?? pgSetting(config, "user");
9287
+ if (!host || !database) return void 0;
9288
+ return `${host.startsWith("/") ? host : host.toLocaleLowerCase()}:${pgSetting(config, "port") ?? "5432"}/${database}`;
9289
+ }
9290
+ function canonicalPgTarget(config) {
9291
+ if (config.connectionString) try {
9292
+ const parsed = new URL(config.connectionString);
9293
+ return effectivePgTarget({
9294
+ host: decodeURIComponent(parsed.hostname) || config.host,
9295
+ port: parsed.port || config.port,
9296
+ database: decodeURIComponent(parsed.pathname.slice(1)) || config.database,
9297
+ user: decodeURIComponent(parsed.username) || config.user
9298
+ });
9299
+ } catch {
9300
+ return config.connectionString;
9301
+ }
9302
+ return effectivePgTarget(config);
9303
+ }
9304
+ function pgSourceConfig(source) {
9305
+ if (!source || !("options" in source)) return void 0;
9306
+ return source.options;
9307
+ }
9308
+ function pgClientPool(client) {
9309
+ if (!client || !("$pool" in client)) return void 0;
9310
+ return client.$pool;
9311
+ }
9312
+ function getPgKnowledgeIsolationKey(config) {
9313
+ const schema = config.schemaName ?? "public";
9314
+ const poolConfig = pgSourceConfig(config.pool ?? pgClientPool(config.client));
9315
+ const target = Boolean(config.connectionString || config.host || config.database) ? canonicalPgTarget(config) : poolConfig ? canonicalPgTarget(poolConfig) : void 0;
9316
+ if (target) return `pg:${target}:schema:${schema}`;
9317
+ return `pg:unidentified:schema:${schema}`;
9318
+ }
8505
9319
  var KnowledgePG = class extends _mastra_core_storage.KnowledgeStorage {
8506
- static MANAGED_TABLES = [
8507
- _mastra_core_storage.TABLE_KNOWLEDGE_NODES,
8508
- _mastra_core_storage.TABLE_KNOWLEDGE_RECORDS,
8509
- _mastra_core_storage.TABLE_KNOWLEDGE_MENTIONS,
8510
- _mastra_core_storage.TABLE_KNOWLEDGE_CURSORS,
8511
- _mastra_core_storage.TABLE_KNOWLEDGE_ACTIVITY,
8512
- _mastra_core_storage.TABLE_KNOWLEDGE_SEMANTIC_OUTBOX
8513
- ];
9320
+ static MANAGED_TABLES = KNOWLEDGE_TABLE_NAMES;
8514
9321
  static getExportDDL(schemaName) {
8515
- return [
8516
- generateTableSQL({
8517
- tableName: _mastra_core_storage.TABLE_KNOWLEDGE_NODES,
8518
- schema: _mastra_core_storage.KNOWLEDGE_NODES_SCHEMA,
8519
- schemaName,
8520
- includeAllConstraints: true
8521
- }),
8522
- generateTableSQL({
8523
- tableName: _mastra_core_storage.TABLE_KNOWLEDGE_RECORDS,
8524
- schema: _mastra_core_storage.KNOWLEDGE_RECORDS_SCHEMA,
8525
- schemaName,
8526
- includeAllConstraints: true
8527
- }),
8528
- generateTableSQL({
8529
- tableName: _mastra_core_storage.TABLE_KNOWLEDGE_MENTIONS,
8530
- schema: _mastra_core_storage.KNOWLEDGE_MENTIONS_SCHEMA,
8531
- schemaName,
8532
- compositePrimaryKey: [
8533
- "sourceType",
8534
- "sourceId",
8535
- "recordId"
8536
- ],
8537
- includeAllConstraints: true
8538
- }),
8539
- generateTableSQL({
8540
- tableName: _mastra_core_storage.TABLE_KNOWLEDGE_CURSORS,
8541
- schema: _mastra_core_storage.KNOWLEDGE_CURSORS_SCHEMA,
8542
- schemaName,
8543
- compositePrimaryKey: ["sourceThreadId", "agent"],
8544
- includeAllConstraints: true
8545
- }),
8546
- generateTableSQL({
8547
- tableName: _mastra_core_storage.TABLE_KNOWLEDGE_ACTIVITY,
8548
- schema: _mastra_core_storage.KNOWLEDGE_ACTIVITY_SCHEMA,
8549
- schemaName,
8550
- includeAllConstraints: true
8551
- }),
8552
- generateTableSQL({
8553
- tableName: _mastra_core_storage.TABLE_KNOWLEDGE_SEMANTIC_OUTBOX,
8554
- schema: _mastra_core_storage.KNOWLEDGE_SEMANTIC_OUTBOX_SCHEMA,
8555
- schemaName,
8556
- includeAllConstraints: true
8557
- }),
8558
- ...knowledgeIndexDDL(schemaName)
8559
- ];
9322
+ return [...knowledgeTableDefinitions.map((definition) => generateTableSQL({
9323
+ ...definition,
9324
+ schemaName,
9325
+ includeAllConstraints: true
9326
+ })), ...knowledgeIndexDDL(schemaName)];
8560
9327
  }
8561
9328
  #client;
8562
9329
  #executor;
@@ -8565,7 +9332,7 @@ var KnowledgePG = class extends _mastra_core_storage.KnowledgeStorage {
8565
9332
  #db;
8566
9333
  #schemaName;
8567
9334
  constructor(config) {
8568
- super();
9335
+ super({ storageIsolationKey: config.storageIsolationKey ?? getPgKnowledgeIsolationKey(config) });
8569
9336
  const { client, readClient, schemaName, skipDefaultIndexes } = resolvePgConfig(config);
8570
9337
  this.#client = client;
8571
9338
  this.#schemaName = schemaName;
@@ -8578,55 +9345,358 @@ var KnowledgePG = class extends _mastra_core_storage.KnowledgeStorage {
8578
9345
  skipDefaultIndexes
8579
9346
  });
8580
9347
  }
8581
- async init() {
8582
- await this.#db.createTable({
8583
- tableName: _mastra_core_storage.TABLE_KNOWLEDGE_NODES,
8584
- schema: _mastra_core_storage.KNOWLEDGE_NODES_SCHEMA
8585
- });
8586
- await this.#db.alterTable({
8587
- tableName: _mastra_core_storage.TABLE_KNOWLEDGE_NODES,
8588
- schema: _mastra_core_storage.KNOWLEDGE_NODES_SCHEMA,
8589
- ifNotExists: ["description"]
9348
+ getCapabilities() {
9349
+ return {
9350
+ contractVersion: 2,
9351
+ schemaVersion: 2,
9352
+ supportsV2: true,
9353
+ supportsSchemaInspection: true,
9354
+ supportsExplicitReset: true
9355
+ };
9356
+ }
9357
+ async inspectSchema() {
9358
+ const { inspectKnowledgeSchema } = await loadKnowledgeV2Core();
9359
+ try {
9360
+ const snapshot = getSchemaSnapshot(this.#client, this.#schemaName);
9361
+ if (snapshot) {
9362
+ const tableNames = KNOWLEDGE_TABLE_NAMES.filter((table) => snapshot.tables.has(table));
9363
+ return this.#classifySchema(this.#executor, tableNames, snapshot.columns);
9364
+ }
9365
+ return this.#inspectSchemaWithExecutor(this.#executor);
9366
+ } catch (error) {
9367
+ return inspectKnowledgeSchema({
9368
+ available: false,
9369
+ tableNames: [],
9370
+ reason: error instanceof Error ? error.message : String(error)
9371
+ });
9372
+ }
9373
+ }
9374
+ async #inspectSchemaWithExecutor(executor) {
9375
+ const tableNames = (await executor.execute({
9376
+ sql: `SELECT table_name FROM information_schema.tables WHERE table_schema = COALESCE(?, current_schema()) AND table_name = ANY(?::text[])`,
9377
+ args: [this.#schemaName ?? null, [...KNOWLEDGE_TABLE_NAMES]]
9378
+ })).rows.map((row) => String(row.table_name));
9379
+ const columnResult = await executor.execute({
9380
+ sql: `SELECT table_name, column_name FROM information_schema.columns WHERE table_schema = COALESCE(?, current_schema()) AND table_name = ANY(?::text[])`,
9381
+ args: [this.#schemaName ?? null, [...KNOWLEDGE_TABLE_NAMES]]
9382
+ });
9383
+ const columns = /* @__PURE__ */ new Map();
9384
+ for (const row of columnResult.rows) {
9385
+ const table = String(row.table_name);
9386
+ const names = columns.get(table) ?? /* @__PURE__ */ new Set();
9387
+ names.add(String(row.column_name));
9388
+ columns.set(table, names);
9389
+ }
9390
+ return this.#classifySchema(executor, tableNames, columns);
9391
+ }
9392
+ async #classifySchema(executor, tableNames, columns) {
9393
+ const { inspectKnowledgeSchema } = await loadKnowledgeV2Core();
9394
+ if (tableNames.length === 0) return inspectKnowledgeSchema({
9395
+ available: true,
9396
+ tableNames
9397
+ });
9398
+ const missingTables = KNOWLEDGE_TABLE_NAMES.filter((table) => !tableNames.includes(table));
9399
+ if (missingTables.length > 0) return inspectKnowledgeSchema({
9400
+ available: true,
9401
+ tableNames,
9402
+ reason: `Missing Knowledge v2 tables: ${missingTables.join(", ")}`
9403
+ });
9404
+ for (const { tableName: table, schema } of knowledgeTableDefinitions) {
9405
+ const actual = columns.get(table) ?? /* @__PURE__ */ new Set();
9406
+ const missing = Object.keys(schema).filter((column) => !actual.has(column));
9407
+ if (missing.length > 0) return inspectKnowledgeSchema({
9408
+ available: true,
9409
+ tableNames,
9410
+ reason: `Knowledge table ${table} is missing v2 columns: ${missing.join(", ")}`
9411
+ });
9412
+ }
9413
+ const accessState = await executor.execute(`SELECT schemaVersion FROM "${TABLE_KNOWLEDGE_ACCESS_STATE}" WHERE id='global'`);
9414
+ if (Number(accessState.rows[0]?.schemaVersion) !== 2) return inspectKnowledgeSchema({
9415
+ available: true,
9416
+ tableNames,
9417
+ reason: "Knowledge schema version marker is missing or incompatible"
9418
+ });
9419
+ return inspectKnowledgeSchema({
9420
+ available: true,
9421
+ tableNames,
9422
+ schemaVersion: 2
8590
9423
  });
8591
- await this.#db.createTable({
8592
- tableName: _mastra_core_storage.TABLE_KNOWLEDGE_RECORDS,
8593
- schema: _mastra_core_storage.KNOWLEDGE_RECORDS_SCHEMA
9424
+ }
9425
+ async init() {
9426
+ await this.#transaction(async (tx) => {
9427
+ await tx.execute({
9428
+ sql: "SELECT pg_advisory_xact_lock(hashtext(?))",
9429
+ args: [`mastra-knowledge-v2:${this.#schemaName ?? "current_schema"}`]
9430
+ });
9431
+ const { assertKnowledgeSchemaCompatible } = await loadKnowledgeV2Core();
9432
+ let inspection = await this.#inspectSchemaWithExecutor(tx);
9433
+ if (inspection.status === "incompatible-reset-required" && await this.#isPublishedV1Layout(tx)) {
9434
+ const tables = [...RETIRED_KNOWLEDGE_TABLE_NAMES, ...[...KNOWLEDGE_TABLE_NAMES].reverse()].map((table) => `"${table}"`).join(", ");
9435
+ await tx.execute(`DROP TABLE IF EXISTS ${tables}`);
9436
+ inspection = await this.#inspectSchemaWithExecutor(tx);
9437
+ }
9438
+ assertKnowledgeSchemaCompatible(inspection);
9439
+ for (const definition of knowledgeTableDefinitions) await tx.executeRaw(generateTableSQL({
9440
+ ...definition,
9441
+ schemaName: this.#schemaName,
9442
+ includeAllConstraints: true
9443
+ }));
9444
+ for (const index of knowledgeIndexes(this.#schemaName)) await tx.executeRaw(index.sql);
9445
+ await tx.execute({
9446
+ sql: `INSERT INTO "${TABLE_KNOWLEDGE_ACCESS_STATE}" (id, epoch, schemaVersion) VALUES ('global', 0, ?) ON CONFLICT (id) DO NOTHING`,
9447
+ args: [2]
9448
+ });
8594
9449
  });
8595
- await this.#db.createTable({
8596
- tableName: _mastra_core_storage.TABLE_KNOWLEDGE_MENTIONS,
8597
- schema: _mastra_core_storage.KNOWLEDGE_MENTIONS_SCHEMA,
8598
- compositePrimaryKey: [
8599
- "sourceType",
8600
- "sourceId",
8601
- "recordId"
9450
+ }
9451
+ /**
9452
+ * True when the only Knowledge objects are the tables and indexes published v1 adapters created,
9453
+ * with or without rows. Anything else (v2 tables, unknown tables, views, triggers, extra indexes)
9454
+ * needs an explicit reset.
9455
+ */
9456
+ async #isPublishedV1Layout(executor) {
9457
+ const schema = this.#schemaName ?? null;
9458
+ const relations = await executor.execute({
9459
+ sql: `SELECT table_name, table_type FROM information_schema.tables WHERE table_schema = COALESCE(?, current_schema()) AND table_name LIKE 'mastra\\_knowledge\\_%'`,
9460
+ args: [schema]
9461
+ });
9462
+ const tables = [];
9463
+ for (const row of relations.rows) {
9464
+ const name = String(row.table_name);
9465
+ if (row.table_type !== "BASE TABLE" || !PUBLISHED_KNOWLEDGE_V1_TABLE_NAMES.has(name)) return false;
9466
+ tables.push(name);
9467
+ }
9468
+ const indexes = await executor.execute({
9469
+ sql: `SELECT indexname FROM pg_indexes WHERE schemaname = COALESCE(?, current_schema()) AND tablename = ANY(?::text[])`,
9470
+ args: [schema, tables]
9471
+ });
9472
+ for (const row of indexes.rows) {
9473
+ const name = String(row.indexname);
9474
+ if (!PUBLISHED_KNOWLEDGE_V1_INDEX_NAMES.has(name) && !name.endsWith("_pkey")) return false;
9475
+ }
9476
+ if ((await executor.execute({
9477
+ sql: `SELECT 1 FROM information_schema.view_table_usage WHERE table_schema = COALESCE(?, current_schema()) AND table_name = ANY(?::text[]) UNION ALL SELECT 1 FROM information_schema.triggers WHERE event_object_schema = COALESCE(?, current_schema()) AND event_object_table = ANY(?::text[]) LIMIT 1`,
9478
+ args: [
9479
+ schema,
9480
+ tables,
9481
+ schema,
9482
+ tables
8602
9483
  ]
9484
+ })).rows.length > 0) return false;
9485
+ return true;
9486
+ }
9487
+ async dangerouslyClearAll() {
9488
+ await this.#transaction(async (tx) => {
9489
+ for (const table of [
9490
+ TABLE_KNOWLEDGE_RECORD_SCOPES,
9491
+ TABLE_KNOWLEDGE_NODE_SCOPES,
9492
+ TABLE_KNOWLEDGE_SCOPE_GRANTS,
9493
+ TABLE_KNOWLEDGE_SCOPE_ADDRESSES,
9494
+ TABLE_KNOWLEDGE_NODE_ADDRESSES,
9495
+ _mastra_core_storage.TABLE_KNOWLEDGE_MENTIONS,
9496
+ TABLE_KNOWLEDGE_PROPOSALS,
9497
+ _mastra_core_storage.TABLE_KNOWLEDGE_ACTIVITY,
9498
+ TABLE_KNOWLEDGE_IMPORT_STATE,
9499
+ TABLE_KNOWLEDGE_IMPORT_RUNS,
9500
+ _mastra_core_storage.TABLE_KNOWLEDGE_SEMANTIC_OUTBOX,
9501
+ _mastra_core_storage.TABLE_KNOWLEDGE_RECORDS,
9502
+ _mastra_core_storage.TABLE_KNOWLEDGE_NODES
9503
+ ]) await tx.execute(`DELETE FROM "${table}"`);
9504
+ await tx.execute(`UPDATE "${TABLE_KNOWLEDGE_ACCESS_STATE}" SET epoch = 0 WHERE id = 'global'`);
8603
9505
  });
8604
- await this.#db.createTable({
8605
- tableName: _mastra_core_storage.TABLE_KNOWLEDGE_CURSORS,
8606
- schema: _mastra_core_storage.KNOWLEDGE_CURSORS_SCHEMA,
8607
- compositePrimaryKey: ["sourceThreadId", "agent"]
8608
- });
8609
- await this.#db.createTable({
8610
- tableName: _mastra_core_storage.TABLE_KNOWLEDGE_ACTIVITY,
8611
- schema: _mastra_core_storage.KNOWLEDGE_ACTIVITY_SCHEMA
8612
- });
8613
- await this.#db.createTable({
8614
- tableName: _mastra_core_storage.TABLE_KNOWLEDGE_SEMANTIC_OUTBOX,
8615
- schema: _mastra_core_storage.KNOWLEDGE_SEMANTIC_OUTBOX_SCHEMA
9506
+ }
9507
+ async dangerouslyReset() {
9508
+ const tables = [...RETIRED_KNOWLEDGE_TABLE_NAMES, ...[...KNOWLEDGE_TABLE_NAMES].reverse()].map((table) => `"${table}"`).join(", ");
9509
+ await this.#executor.execute(`DROP TABLE IF EXISTS ${tables}`);
9510
+ await this.init();
9511
+ }
9512
+ async reconcileStructure(plan) {
9513
+ return this.#transaction(async (tx) => {
9514
+ await tx.execute({
9515
+ sql: `SELECT pg_advisory_xact_lock(hashtext(?))`,
9516
+ args: [`mastra-knowledge-reconcile:${this.#schemaName}`]
9517
+ });
9518
+ const scopes = {};
9519
+ const createdScopeIds = [];
9520
+ const createdAddresses = /* @__PURE__ */ new Set();
9521
+ const retrofit = plan.retrofit ?? true;
9522
+ let structureChanged = false;
9523
+ const deletedScopeAddresses = /* @__PURE__ */ new Set();
9524
+ const resolveAddress = async (address) => {
9525
+ if (scopes[address]) return scopes[address];
9526
+ const row = (await tx.execute({
9527
+ sql: `SELECT a."scopeNodeId",n."isScope",n."deletedAt" FROM "${TABLE_KNOWLEDGE_SCOPE_ADDRESSES}" a JOIN "${_mastra_core_storage.TABLE_KNOWLEDGE_NODES}" n ON n.id=a."scopeNodeId" WHERE a.address=?`,
9528
+ args: [address]
9529
+ })).rows[0];
9530
+ if (!row) return void 0;
9531
+ if (!row.isScope) throw new Error(`Knowledge address ${address} does not reference a scope`);
9532
+ if (row.deletedAt) deletedScopeAddresses.add(address);
9533
+ scopes[address] = String(row.scopeNodeId);
9534
+ return scopes[address];
9535
+ };
9536
+ for (const scope of plan.scopes) {
9537
+ if (await resolveAddress(scope.address)) continue;
9538
+ const id = (0, crypto$1.randomUUID)();
9539
+ const now = (/* @__PURE__ */ new Date()).toISOString();
9540
+ await tx.execute({
9541
+ sql: `INSERT INTO "${_mastra_core_storage.TABLE_KNOWLEDGE_NODES}" (id,type,name,"canonicalName",kind,description,"isScope",metadata,version,"createdAt","updatedAt") VALUES (?,'node',?,?,?,?,TRUE,?,1,?,?)`,
9542
+ args: [
9543
+ id,
9544
+ scope.name,
9545
+ canonicalName(scope.name),
9546
+ scope.kind ?? null,
9547
+ scope.description ?? null,
9548
+ scope.metadata ?? null,
9549
+ now,
9550
+ now
9551
+ ]
9552
+ });
9553
+ await tx.execute({
9554
+ sql: `INSERT INTO "${TABLE_KNOWLEDGE_SCOPE_ADDRESSES}" (address,"scopeNodeId") VALUES (?,?)`,
9555
+ args: [scope.address, id]
9556
+ });
9557
+ scopes[scope.address] = id;
9558
+ createdAddresses.add(scope.address);
9559
+ createdScopeIds.push(id);
9560
+ structureChanged = true;
9561
+ }
9562
+ for (const scope of plan.scopes) {
9563
+ if (!createdAddresses.has(scope.address) && (!retrofit || deletedScopeAddresses.has(scope.address))) continue;
9564
+ const scopeNodeId = scopes[scope.address];
9565
+ for (const parentAddress of scope.parentAddresses ?? []) {
9566
+ const parentId = await resolveAddress(parentAddress);
9567
+ if (!parentId || deletedScopeAddresses.has(parentAddress)) {
9568
+ const deletedParentId = scopes[parentAddress];
9569
+ if ((deletedParentId ? await tx.execute({
9570
+ sql: `SELECT 1 FROM "mastra_knowledge_node_scopes" WHERE "nodeId"=? AND "scopeNodeId"=?`,
9571
+ args: [scopeNodeId, deletedParentId]
9572
+ }) : void 0)?.rows.length) continue;
9573
+ throw new Error(`Knowledge parent scope does not exist: ${parentAddress}`);
9574
+ }
9575
+ if ((await tx.execute({
9576
+ sql: `SELECT 1 FROM "mastra_knowledge_node_scopes" WHERE "nodeId"=? AND "scopeNodeId"=?`,
9577
+ args: [scopeNodeId, parentId]
9578
+ })).rows.length) continue;
9579
+ if ((await tx.execute({
9580
+ sql: `SELECT n.id FROM "mastra_knowledge_node_scopes" ns JOIN "${_mastra_core_storage.TABLE_KNOWLEDGE_NODES}" n ON n.id=ns."nodeId" WHERE ns."scopeNodeId"=? AND n."isScope" AND n."canonicalName"=? AND n."deletedAt" IS NULL AND n.id<>? LIMIT 1`,
9581
+ args: [
9582
+ parentId,
9583
+ canonicalName(scope.name),
9584
+ scopeNodeId
9585
+ ]
9586
+ })).rows.length) throw new Error(`Knowledge scope name ${scope.name} already exists under ${parentAddress}`);
9587
+ const inserted = await tx.execute({
9588
+ sql: `INSERT INTO "${TABLE_KNOWLEDGE_NODE_SCOPES}" ("nodeId","scopeNodeId","addedAt") VALUES (?,?,?) ON CONFLICT DO NOTHING`,
9589
+ args: [
9590
+ scopeNodeId,
9591
+ parentId,
9592
+ (/* @__PURE__ */ new Date()).toISOString()
9593
+ ]
9594
+ });
9595
+ structureChanged ||= inserted.rowsAffected > 0;
9596
+ }
9597
+ for (const grant of scope.grants ?? []) {
9598
+ const scopeRefId = await resolveAddress(grant.scopeRefAddress);
9599
+ if (!scopeRefId || deletedScopeAddresses.has(grant.scopeRefAddress)) {
9600
+ const deletedScopeRefId = scopes[grant.scopeRefAddress];
9601
+ if ((deletedScopeRefId ? await tx.execute({
9602
+ sql: `SELECT 1 FROM "mastra_knowledge_scope_grants" WHERE "scopeNodeId"=? AND "scopeRefId"=?`,
9603
+ args: [scopeNodeId, deletedScopeRefId]
9604
+ }) : void 0)?.rows.length) continue;
9605
+ throw new Error(`Knowledge grant scope does not exist: ${grant.scopeRefAddress}`);
9606
+ }
9607
+ const inserted = await tx.execute({
9608
+ sql: `INSERT INTO "${TABLE_KNOWLEDGE_SCOPE_GRANTS}" ("scopeNodeId","scopeRefId",role,"canSuggest") VALUES (?,?,?,?) ON CONFLICT DO NOTHING`,
9609
+ args: [
9610
+ scopeNodeId,
9611
+ scopeRefId,
9612
+ grant.role,
9613
+ grant.canSuggest ?? null
9614
+ ]
9615
+ });
9616
+ structureChanged ||= inserted.rowsAffected > 0;
9617
+ }
9618
+ }
9619
+ if (structureChanged) await tx.execute(`UPDATE "${TABLE_KNOWLEDGE_ACCESS_STATE}" SET epoch=epoch+1 WHERE id='global'`);
9620
+ const state = await tx.execute(`SELECT epoch FROM "${TABLE_KNOWLEDGE_ACCESS_STATE}" WHERE id='global'`);
9621
+ return {
9622
+ scopes,
9623
+ createdScopeIds,
9624
+ deletedScopeAddresses: [...deletedScopeAddresses],
9625
+ changed: structureChanged,
9626
+ accessEpoch: Number(state.rows[0]?.epoch ?? 0)
9627
+ };
8616
9628
  });
8617
- await Promise.all(knowledgeIndexes(this.#schemaName).map((index) => this.#db.createIndexFromStatement(index.name, index.sql)));
8618
9629
  }
8619
- async dangerouslyClearAll() {
8620
- await this.#transaction(async (tx) => {
8621
- for (const table of [
8622
- _mastra_core_storage.TABLE_KNOWLEDGE_MENTIONS,
8623
- _mastra_core_storage.TABLE_KNOWLEDGE_RECORDS,
8624
- _mastra_core_storage.TABLE_KNOWLEDGE_NODES,
8625
- _mastra_core_storage.TABLE_KNOWLEDGE_CURSORS,
8626
- _mastra_core_storage.TABLE_KNOWLEDGE_ACTIVITY,
8627
- _mastra_core_storage.TABLE_KNOWLEDGE_SEMANTIC_OUTBOX
8628
- ]) await tx.execute(`DELETE FROM "${table}"`);
8629
- });
9630
+ async listScopeNodes(input = {}) {
9631
+ const { limit, after } = parseListKnowledgeScopeNodesInput(input);
9632
+ if (input.addresses?.length === 0 || input.ids?.length === 0) return {
9633
+ scopes: [],
9634
+ nextCursor: null
9635
+ };
9636
+ const args = [];
9637
+ const where = [`n."isScope"`, `n."deletedAt" IS NULL`];
9638
+ let within = "";
9639
+ if (input.withinAddress !== void 0) {
9640
+ within = `WITH RECURSIVE within_scope(id) AS (SELECT r.id FROM "${_mastra_core_storage.TABLE_KNOWLEDGE_NODES}" r JOIN "${TABLE_KNOWLEDGE_SCOPE_ADDRESSES}" ra ON ra."scopeNodeId"=r.id WHERE ra.address=? AND r."isScope" AND r."deletedAt" IS NULL UNION SELECT ns."nodeId" FROM "${TABLE_KNOWLEDGE_NODE_SCOPES}" ns JOIN within_scope w ON ns."scopeNodeId"=w.id JOIN "${_mastra_core_storage.TABLE_KNOWLEDGE_NODES}" c ON c.id=ns."nodeId" WHERE c."isScope" AND c."deletedAt" IS NULL) `;
9641
+ args.push(input.withinAddress);
9642
+ where.push("n.id IN (SELECT id FROM within_scope)");
9643
+ }
9644
+ if (input.addresses) {
9645
+ where.push(`a.address IN (${input.addresses.map(() => "?").join(",")})`);
9646
+ args.push(...input.addresses);
9647
+ }
9648
+ if (input.ids) {
9649
+ where.push(`n.id IN (${input.ids.map(() => "?").join(",")})`);
9650
+ args.push(...input.ids);
9651
+ }
9652
+ if (after) {
9653
+ where.push("(n.name COLLATE \"C\" > ? OR (n.name = ? AND n.id > ?))");
9654
+ args.push(after.name, after.name, after.id);
9655
+ }
9656
+ args.push(limit + 1);
9657
+ const rows = (await this.#readExecutor.execute({
9658
+ sql: `${within}SELECT n.id,n.name,n.kind,n.description,a.address FROM "${_mastra_core_storage.TABLE_KNOWLEDGE_NODES}" n LEFT JOIN "${TABLE_KNOWLEDGE_SCOPE_ADDRESSES}" a ON a."scopeNodeId"=n.id WHERE ${where.join(" AND ")} ORDER BY n.name COLLATE "C", n.id LIMIT ?`,
9659
+ args
9660
+ })).rows;
9661
+ if (rows.length === 0) return {
9662
+ scopes: [],
9663
+ nextCursor: null
9664
+ };
9665
+ const parents = await this.#readExecutor.execute({
9666
+ sql: `SELECT ns."nodeId",ns."scopeNodeId" FROM "${TABLE_KNOWLEDGE_NODE_SCOPES}" ns WHERE ns."nodeId" IN (${rows.map(() => "?").join(",")}) ORDER BY ns."scopeNodeId" COLLATE "C"`,
9667
+ args: rows.map((row) => String(row.id))
9668
+ });
9669
+ const parentsByScopeId = /* @__PURE__ */ new Map();
9670
+ for (const row of parents.rows) {
9671
+ const scopeId = String(row.nodeId);
9672
+ const parentId = String(row.scopeNodeId);
9673
+ const existing = parentsByScopeId.get(scopeId);
9674
+ if (existing) existing.push(parentId);
9675
+ else parentsByScopeId.set(scopeId, [parentId]);
9676
+ }
9677
+ return pageKnowledgeScopeNodes(rows.map((row) => ({
9678
+ id: String(row.id),
9679
+ address: String(row.address),
9680
+ name: String(row.name),
9681
+ ...row.kind == null ? {} : { kind: String(row.kind) },
9682
+ ...row.description == null ? {} : { description: String(row.description) },
9683
+ parentIds: parentsByScopeId.get(String(row.id)) ?? []
9684
+ })), limit, input);
9685
+ }
9686
+ async listScopeMembers(input) {
9687
+ const { limit, after } = parseListKnowledgeScopeMembersInput(input);
9688
+ const args = [input.scopeNodeId];
9689
+ let keyset = "";
9690
+ if (after) {
9691
+ const updatedAt = postgresTimestamp(after.updatedAt);
9692
+ keyset = ` AND (n."updatedAt" < ? OR (n."updatedAt" = ? AND (n.name > ? OR (n.name = ? AND n.id > ?))))`;
9693
+ args.push(updatedAt, updatedAt, after.name, after.name, after.id);
9694
+ }
9695
+ args.push(limit + 1);
9696
+ return pageKnowledgeScopeMembers((await this.#readExecutor.execute({
9697
+ sql: `SELECT *, scope AS "scopeJson" FROM "${_mastra_core_storage.TABLE_KNOWLEDGE_NODES}" n WHERE EXISTS (SELECT 1 FROM "${TABLE_KNOWLEDGE_NODE_SCOPES}" ns WHERE ns."nodeId"=n.id AND ns."scopeNodeId"=?) AND n."deletedAt" IS NULL AND n."mergedInto" IS NULL${keyset} ORDER BY n."updatedAt" DESC, n.name ASC, n.id ASC LIMIT ?`,
9698
+ args
9699
+ })).rows.map(parseNode), limit, input);
8630
9700
  }
8631
9701
  async createNode(input) {
8632
9702
  await assertKnowledgeDescriptionWithinBoundCompat(input.description);
@@ -8636,6 +9706,7 @@ var KnowledgePG = class extends _mastra_core_storage.KnowledgeStorage {
8636
9706
  if (existing) {
8637
9707
  const terminal = await this.#resolveTerminalNode(tx, existing.id);
8638
9708
  if (!(0, _mastra_core_storage.isKnowledgeScopeVisible)(terminal.scope, scope)) throw new Error(`Merged knowledge node is not visible from scope: ${input.name}`);
9709
+ await this.#placeNodeInScopes(tx, terminal.id, input.scopeAddresses, /* @__PURE__ */ new Date());
8639
9710
  return terminal;
8640
9711
  }
8641
9712
  const now = /* @__PURE__ */ new Date();
@@ -8652,7 +9723,7 @@ var KnowledgePG = class extends _mastra_core_storage.KnowledgeStorage {
8652
9723
  updatedAt: now
8653
9724
  };
8654
9725
  await tx.execute({
8655
- sql: `INSERT INTO "${_mastra_core_storage.TABLE_KNOWLEDGE_NODES}" (id,type,name,canonicalName,kind,content,description,scope,scopeKey,version,mergedInto,createdAt,updatedAt) VALUES (?,?,?,?,?,?,?,jsonb(?),?,?,NULL,?,?)`,
9726
+ sql: `INSERT INTO "${_mastra_core_storage.TABLE_KNOWLEDGE_NODES}" (id,type,name,canonicalName,kind,content,description,isScope,scope,scopeKey,version,mergedInto,createdAt,updatedAt) VALUES (?,?,?,?,?,?,?,FALSE,jsonb(?),?,?,NULL,?,?)`,
8656
9727
  args: [
8657
9728
  node.id,
8658
9729
  "node",
@@ -8668,6 +9739,8 @@ var KnowledgePG = class extends _mastra_core_storage.KnowledgeStorage {
8668
9739
  now.toISOString()
8669
9740
  ]
8670
9741
  });
9742
+ await this.#replaceNodeScopes(tx, node.id, scope, now);
9743
+ await this.#placeNodeInScopes(tx, node.id, input.scopeAddresses, now);
8671
9744
  await this.#replaceMentions(tx, "node", node.id, node.content ?? "", input.resolutionScope ?? scope, scope);
8672
9745
  await this.#activity(tx, "node-created", "node", node.id, scope);
8673
9746
  await this.#outbox(tx, "node", node.id, "upsert", node.version, scope);
@@ -8684,13 +9757,13 @@ var KnowledgePG = class extends _mastra_core_storage.KnowledgeStorage {
8684
9757
  return this.#resolveNode(this.#readExecutor, input.name, (0, _mastra_core_storage.canonicalizeKnowledgeScope)(input.scope));
8685
9758
  }
8686
9759
  async listNodes(input) {
8687
- const key = (0, _mastra_core_storage.knowledgeScopeKey)((0, _mastra_core_storage.canonicalizeKnowledgeScope)(input.scope));
9760
+ const keys = visibleScopeKeys((0, _mastra_core_storage.canonicalizeKnowledgeScope)(input.scope));
8688
9761
  const clauses = [
8689
9762
  `type = 'node'`,
8690
9763
  "mergedInto IS NULL",
8691
- visibleSql
9764
+ visibleSql(keys)
8692
9765
  ];
8693
- const args = [key, key];
9766
+ const args = [...keys];
8694
9767
  if (input.namePrefix) {
8695
9768
  clauses.push("canonicalName LIKE ? ESCAPE '='");
8696
9769
  args.push(`${escapeLikePattern(canonicalName(input.namePrefix))}%`);
@@ -8742,6 +9815,7 @@ var KnowledgePG = class extends _mastra_core_storage.KnowledgeStorage {
8742
9815
  input.version
8743
9816
  ]
8744
9817
  })).rowsAffected === 0) throw new _mastra_core_storage.KnowledgeConflictError(input.id);
9818
+ if ((0, _mastra_core_storage.knowledgeScopeKey)(existing.scope) !== (0, _mastra_core_storage.knowledgeScopeKey)(scope)) await this.#swapIdentityScopes(tx, input.id, existing.scope, scope, now);
8745
9819
  if (input.content !== void 0 || input.name !== void 0 || input.scope !== void 0) await this.#replaceMentions(tx, "node", input.id, content ?? "", input.resolutionScope ?? scope, scope);
8746
9820
  await this.#activity(tx, "node-updated", "node", input.id, scope);
8747
9821
  if ((0, _mastra_core_storage.knowledgeScopeKey)(existing.scope) !== (0, _mastra_core_storage.knowledgeScopeKey)(scope)) {
@@ -8796,8 +9870,12 @@ var KnowledgePG = class extends _mastra_core_storage.KnowledgeStorage {
8796
9870
  ]
8797
9871
  })).rowsAffected === 0) throw new _mastra_core_storage.KnowledgeConflictError(source.id);
8798
9872
  await tx.execute({
8799
- sql: `UPDATE "${_mastra_core_storage.TABLE_KNOWLEDGE_RECORDS}" SET node=? WHERE node=?`,
8800
- args: [target.id, source.id]
9873
+ sql: `UPDATE "${_mastra_core_storage.TABLE_KNOWLEDGE_RECORDS}" SET node=?,version=version+1,updatedAt=? WHERE node=?`,
9874
+ args: [
9875
+ target.id,
9876
+ (/* @__PURE__ */ new Date()).toISOString(),
9877
+ source.id
9878
+ ]
8801
9879
  });
8802
9880
  await tx.execute({
8803
9881
  sql: `DELETE FROM "${_mastra_core_storage.TABLE_KNOWLEDGE_MENTIONS}" WHERE recordId=? AND EXISTS (SELECT 1 FROM "${_mastra_core_storage.TABLE_KNOWLEDGE_MENTIONS}" target WHERE target.sourceType="${_mastra_core_storage.TABLE_KNOWLEDGE_MENTIONS}".sourceType AND target.sourceId="${_mastra_core_storage.TABLE_KNOWLEDGE_MENTIONS}".sourceId AND target.recordId=?)`,
@@ -8837,10 +9915,10 @@ var KnowledgePG = class extends _mastra_core_storage.KnowledgeStorage {
8837
9915
  });
8838
9916
  }
8839
9917
  async appendKnowledge(input) {
9918
+ await assertKnowledgeRecordTextWithinBoundCompat(input.text);
8840
9919
  const scope = (0, _mastra_core_storage.canonicalizeKnowledgeScope)(input.scope);
8841
9920
  const resolutionScope = (0, _mastra_core_storage.canonicalizeKnowledgeScope)(input.resolutionScope);
8842
9921
  const defaultScope = (0, _mastra_core_storage.canonicalizeKnowledgeScope)(input.defaultScope);
8843
- (0, _mastra_core_storage.assertKnowledgeScopeWithinCeiling)(scope, input.maxScope);
8844
9922
  return this.#transaction(async (tx) => {
8845
9923
  const parent = await this.#resolveTerminalNode(tx, nodeReferenceId(input.node));
8846
9924
  if (!parent) throw new _mastra_core_storage.KnowledgeNotFoundError("node", nodeReferenceId(input.node));
@@ -8853,11 +9931,10 @@ var KnowledgePG = class extends _mastra_core_storage.KnowledgeStorage {
8853
9931
  sourceThreadId: input.sourceThreadId,
8854
9932
  capturedAt: /* @__PURE__ */ new Date(),
8855
9933
  when: input.when ? new Date(input.when) : void 0,
8856
- maxScope: input.maxScope,
8857
9934
  metadata: input.metadata
8858
9935
  };
8859
9936
  await tx.execute({
8860
- sql: `INSERT INTO "${_mastra_core_storage.TABLE_KNOWLEDGE_RECORDS}" (id,node,text,scope,scopeKey,sourceThreadId,capturedAt,"when",maxScope,metadata,deletedAt,deletedBy) VALUES (?,?,?,jsonb(?),?,?,?,?,?,jsonb(?),NULL,NULL)`,
9937
+ sql: `INSERT INTO "${_mastra_core_storage.TABLE_KNOWLEDGE_RECORDS}" (id,node,text,scope,scopeKey,sourceThreadId,capturedAt,"when",metadata,version,updatedAt,deletedAt,deletedBy) VALUES (?,?,?,jsonb(?),?,?,?,?,jsonb(?),?,?,NULL,NULL)`,
8861
9938
  args: [
8862
9939
  record.id,
8863
9940
  record.node,
@@ -8867,10 +9944,12 @@ var KnowledgePG = class extends _mastra_core_storage.KnowledgeStorage {
8867
9944
  record.sourceThreadId,
8868
9945
  record.capturedAt.toISOString(),
8869
9946
  record.when?.toISOString() ?? null,
8870
- record.maxScope ?? null,
8871
- metadataJson
9947
+ metadataJson,
9948
+ 1,
9949
+ record.capturedAt.toISOString()
8872
9950
  ]
8873
9951
  });
9952
+ await this.#replaceRecordScopes(tx, record.id, scope, record.capturedAt);
8874
9953
  await this.#replaceMentions(tx, "record", record.id, record.text, resolutionScope, defaultScope);
8875
9954
  await this.#activity(tx, "record-created", "record", record.id, scope, record.sourceThreadId);
8876
9955
  await this.#outbox(tx, "record", record.id, "upsert", record.id, scope);
@@ -8897,17 +9976,13 @@ var KnowledgePG = class extends _mastra_core_storage.KnowledgeStorage {
8897
9976
  return this.#queryKnowledge(input, "related");
8898
9977
  }
8899
9978
  async knowledgeBySource(input) {
8900
- const key = (0, _mastra_core_storage.knowledgeScopeKey)((0, _mastra_core_storage.canonicalizeKnowledgeScope)(input.scope));
8901
- const args = [
8902
- input.sourceThreadId,
8903
- key,
8904
- key
8905
- ];
9979
+ const keys = visibleScopeKeys((0, _mastra_core_storage.canonicalizeKnowledgeScope)(input.scope));
9980
+ const args = [input.sourceThreadId, ...keys];
8906
9981
  if (input.after) args.push(input.after);
8907
9982
  const limit = input.limit ?? 100;
8908
9983
  args.push(limit + 1);
8909
9984
  const records = (await this.#readExecutor.execute({
8910
- sql: `SELECT *,scope AS "scopeJson" FROM "${_mastra_core_storage.TABLE_KNOWLEDGE_RECORDS}" WHERE sourceThreadId=? AND ${visibleSql}${input.includeDeleted ? "" : " AND deletedAt IS NULL"}${input.after ? " AND id > ?" : ""} ORDER BY id ASC LIMIT ?`,
9985
+ sql: `SELECT *,scope AS "scopeJson" FROM "${_mastra_core_storage.TABLE_KNOWLEDGE_RECORDS}" WHERE sourceThreadId=? AND ${visibleSql(keys)}${input.includeDeleted ? "" : " AND deletedAt IS NULL"}${input.after ? " AND id > ?" : ""} ORDER BY id ASC LIMIT ?`,
8911
9986
  args
8912
9987
  })).rows.map(parseKnowledge);
8913
9988
  return {
@@ -8922,10 +9997,11 @@ var KnowledgePG = class extends _mastra_core_storage.KnowledgeStorage {
8922
9997
  if (record.deletedAt) return record;
8923
9998
  const deletedAt = /* @__PURE__ */ new Date();
8924
9999
  await tx.execute({
8925
- sql: `UPDATE "${_mastra_core_storage.TABLE_KNOWLEDGE_RECORDS}" SET deletedAt=?,deletedBy=? WHERE id=? AND deletedAt IS NULL`,
10000
+ sql: `UPDATE "${_mastra_core_storage.TABLE_KNOWLEDGE_RECORDS}" SET deletedAt=?,deletedBy=?,version=version+1,updatedAt=? WHERE id=? AND deletedAt IS NULL`,
8926
10001
  args: [
8927
10002
  deletedAt.toISOString(),
8928
10003
  input.deletedBy,
10004
+ deletedAt.toISOString(),
8929
10005
  input.id
8930
10006
  ]
8931
10007
  });
@@ -8944,8 +10020,8 @@ var KnowledgePG = class extends _mastra_core_storage.KnowledgeStorage {
8944
10020
  if (!record) throw new _mastra_core_storage.KnowledgeNotFoundError("record", input.id);
8945
10021
  if (!record.deletedAt) return record;
8946
10022
  await tx.execute({
8947
- sql: `UPDATE "${_mastra_core_storage.TABLE_KNOWLEDGE_RECORDS}" SET deletedAt=NULL,deletedBy=NULL WHERE id=?`,
8948
- args: [input.id]
10023
+ sql: `UPDATE "${_mastra_core_storage.TABLE_KNOWLEDGE_RECORDS}" SET deletedAt=NULL,deletedBy=NULL,version=version+1,updatedAt=? WHERE id=?`,
10024
+ args: [(/* @__PURE__ */ new Date()).toISOString(), input.id]
8949
10025
  });
8950
10026
  await this.#activity(tx, "record-restored", "record", input.id, record.scope, record.sourceThreadId);
8951
10027
  await this.#outbox(tx, "record", input.id, "upsert", (0, _mastra_core_storage.createKnowledgeUlid)(), record.scope);
@@ -8961,15 +10037,17 @@ var KnowledgePG = class extends _mastra_core_storage.KnowledgeStorage {
8961
10037
  return this.#transaction(async (tx) => {
8962
10038
  const record = await this.#getKnowledge(tx, input.id, true);
8963
10039
  if (!record) throw new _mastra_core_storage.KnowledgeNotFoundError("record", input.id);
8964
- (0, _mastra_core_storage.assertKnowledgeScopeWithinCeiling)(scope, record.maxScope);
10040
+ const updatedAt = /* @__PURE__ */ new Date();
8965
10041
  await tx.execute({
8966
- sql: `UPDATE "${_mastra_core_storage.TABLE_KNOWLEDGE_RECORDS}" SET scope=jsonb(?),scopeKey=? WHERE id=?`,
10042
+ sql: `UPDATE "${_mastra_core_storage.TABLE_KNOWLEDGE_RECORDS}" SET scope=jsonb(?),scopeKey=?,version=version+1,updatedAt=? WHERE id=?`,
8967
10043
  args: [
8968
10044
  JSON.stringify(scope),
8969
10045
  (0, _mastra_core_storage.knowledgeScopeKey)(scope),
10046
+ updatedAt.toISOString(),
8970
10047
  input.id
8971
10048
  ]
8972
10049
  });
10050
+ await this.#replaceRecordScopes(tx, input.id, scope, updatedAt);
8973
10051
  await this.#activity(tx, "record-rescoped", "record", input.id, scope, record.sourceThreadId);
8974
10052
  if ((0, _mastra_core_storage.knowledgeScopeKey)(record.scope) !== (0, _mastra_core_storage.knowledgeScopeKey)(scope)) await this.#outbox(tx, "record", input.id, "delete", (0, _mastra_core_storage.createKnowledgeUlid)(), record.scope);
8975
10053
  if (!record.deletedAt) await this.#outbox(tx, "record", input.id, "upsert", (0, _mastra_core_storage.createKnowledgeUlid)(), scope);
@@ -8979,33 +10057,16 @@ var KnowledgePG = class extends _mastra_core_storage.KnowledgeStorage {
8979
10057
  };
8980
10058
  });
8981
10059
  }
8982
- async raiseKnowledgeCeiling(input) {
8983
- return this.#transaction(async (tx) => {
8984
- const record = await this.#getKnowledge(tx, input.id, true);
8985
- if (!record) throw new _mastra_core_storage.KnowledgeNotFoundError("record", input.id);
8986
- (0, _mastra_core_storage.assertKnowledgeScopeWithinCeiling)(record.scope, input.maxScope);
8987
- (0, _mastra_core_storage.assertKnowledgeCeilingRaised)(record.maxScope, input.maxScope);
8988
- await tx.execute({
8989
- sql: `UPDATE "${_mastra_core_storage.TABLE_KNOWLEDGE_RECORDS}" SET maxScope=? WHERE id=?`,
8990
- args: [input.maxScope ?? null, input.id]
8991
- });
8992
- return {
8993
- ...record,
8994
- maxScope: input.maxScope
8995
- };
8996
- });
8997
- }
8998
10060
  async search(input) {
8999
10061
  const scope = (0, _mastra_core_storage.canonicalizeKnowledgeScope)(input.scope);
9000
- const key = (0, _mastra_core_storage.knowledgeScopeKey)(scope);
10062
+ const keys = visibleScopeKeys(scope);
9001
10063
  const normalizedQuery = input.query.trim().toLocaleLowerCase();
9002
10064
  if (!normalizedQuery) return [];
9003
10065
  const query = `%${escapeLikePattern(normalizedQuery)}%`;
9004
10066
  const results = (await this.#readExecutor.execute({
9005
- sql: `SELECT *,scope AS "scopeJson" FROM "${_mastra_core_storage.TABLE_KNOWLEDGE_NODES}" WHERE mergedInto IS NULL AND ${visibleSql} AND (canonicalName LIKE ? ESCAPE '=' OR lower(COALESCE(kind,'')) LIKE ? ESCAPE '=' OR lower(COALESCE(content,'')) LIKE ? ESCAPE '=' OR lower(COALESCE(description,'')) LIKE ? ESCAPE '=') ORDER BY updatedAt DESC LIMIT ?`,
10067
+ sql: `SELECT *,scope AS "scopeJson" FROM "${_mastra_core_storage.TABLE_KNOWLEDGE_NODES}" WHERE mergedInto IS NULL AND ${visibleSql(keys)} AND (canonicalName LIKE ? ESCAPE '=' OR lower(COALESCE(kind,'')) LIKE ? ESCAPE '=' OR lower(COALESCE(content,'')) LIKE ? ESCAPE '=' OR lower(COALESCE(description,'')) LIKE ? ESCAPE '=') ORDER BY updatedAt DESC LIMIT ?`,
9006
10068
  args: [
9007
- key,
9008
- key,
10069
+ ...keys,
9009
10070
  query,
9010
10071
  query,
9011
10072
  query,
@@ -9026,10 +10087,9 @@ var KnowledgePG = class extends _mastra_core_storage.KnowledgeStorage {
9026
10087
  }));
9027
10088
  if (results.length < (input.limit ?? 20)) {
9028
10089
  const records = await this.#readExecutor.execute({
9029
- sql: `SELECT f.*,f.scope AS "scopeJson",r.name,r.scope AS "parentScopeJson" FROM "${_mastra_core_storage.TABLE_KNOWLEDGE_RECORDS}" f JOIN "${_mastra_core_storage.TABLE_KNOWLEDGE_NODES}" r ON r.id=f.node AND r.type='node' AND r.mergedInto IS NULL WHERE f.deletedAt IS NULL AND ${visibleSql.replaceAll("scopeKey", "f.scopeKey")} AND lower(f.text) LIKE ? ESCAPE '=' ORDER BY f.id DESC LIMIT ?`,
10090
+ sql: `SELECT f.*,f.scope AS "scopeJson",r.name,r.scope AS "parentScopeJson" FROM "${_mastra_core_storage.TABLE_KNOWLEDGE_RECORDS}" f JOIN "${_mastra_core_storage.TABLE_KNOWLEDGE_NODES}" r ON r.id=f.node AND r.type='node' AND r.mergedInto IS NULL WHERE f.deletedAt IS NULL AND ${visibleSql(keys, "f.scopeKey")} AND lower(f.text) LIKE ? ESCAPE '=' ORDER BY f.id DESC LIMIT ?`,
9030
10091
  args: [
9031
- key,
9032
- key,
10092
+ ...keys,
9033
10093
  query,
9034
10094
  (input.limit ?? 20) - results.length
9035
10095
  ]
@@ -9039,7 +10099,7 @@ var KnowledgePG = class extends _mastra_core_storage.KnowledgeStorage {
9039
10099
  return {
9040
10100
  type: "record",
9041
10101
  id: String(row.id),
9042
- recordId: String(row.node),
10102
+ recordId: parentVisible ? String(row.node) : String(row.id),
9043
10103
  name: parentVisible ? String(row.name) : "(private node)",
9044
10104
  text: String(row.text),
9045
10105
  scope: parseJson$1(row.scopeJson)
@@ -9048,41 +10108,26 @@ var KnowledgePG = class extends _mastra_core_storage.KnowledgeStorage {
9048
10108
  }
9049
10109
  return results;
9050
10110
  }
9051
- async getCurationCursor(input) {
9052
- const row = (await this.#executor.execute({
9053
- sql: `SELECT * FROM "${_mastra_core_storage.TABLE_KNOWLEDGE_CURSORS}" WHERE sourceThreadId=? AND agent=?`,
9054
- args: [input.sourceThreadId, input.agent]
9055
- })).rows[0];
9056
- return row ? {
9057
- sourceThreadId: String(row.sourceThreadId),
9058
- agent: String(row.agent),
9059
- lastKnowledgeId: String(row.lastKnowledgeId),
9060
- updatedAt: toDate$1(row.updatedAt)
9061
- } : null;
9062
- }
9063
- async advanceCurationCursor(input) {
9064
- const updatedAt = /* @__PURE__ */ new Date();
9065
- if ((await this.#executor.execute({
9066
- sql: `INSERT INTO "${_mastra_core_storage.TABLE_KNOWLEDGE_CURSORS}" (sourceThreadId,agent,lastKnowledgeId,updatedAt) VALUES (?,?,?,?) ON CONFLICT(sourceThreadId,agent) DO UPDATE SET lastKnowledgeId=excluded.lastKnowledgeId,updatedAt=excluded.updatedAt WHERE excluded.lastKnowledgeId >= "${_mastra_core_storage.TABLE_KNOWLEDGE_CURSORS}".lastKnowledgeId`,
9067
- args: [
9068
- input.sourceThreadId,
9069
- input.agent,
9070
- input.lastKnowledgeId,
9071
- updatedAt.toISOString()
9072
- ]
9073
- })).rowsAffected === 0) throw new Error("Knowledge curation cursor cannot move backwards");
9074
- return {
9075
- ...input,
9076
- updatedAt
9077
- };
10111
+ /**
10112
+ * @deprecated Curation cursors were removed. Observation-time curate is the only Knowledge writer and needs no
10113
+ * cursor. Always throws.
10114
+ */
10115
+ async getCurationCursor(_input) {
10116
+ throw new Error(KNOWLEDGE_CURATION_CURSOR_REMOVED_MESSAGE);
10117
+ }
10118
+ /**
10119
+ * @deprecated Curation cursors were removed. Observation-time curate is the only Knowledge writer and needs no
10120
+ * cursor. Always throws.
10121
+ */
10122
+ async advanceCurationCursor(_input) {
10123
+ throw new Error(KNOWLEDGE_CURATION_CURSOR_REMOVED_MESSAGE);
9078
10124
  }
9079
10125
  async listActivity(input) {
9080
- const key = (0, _mastra_core_storage.knowledgeScopeKey)((0, _mastra_core_storage.canonicalizeKnowledgeScope)(input.scope));
10126
+ const keys = visibleScopeKeys((0, _mastra_core_storage.canonicalizeKnowledgeScope)(input.scope));
9081
10127
  return (await this.#readExecutor.execute({
9082
- sql: `SELECT *,scope AS "scopeJson" FROM "${_mastra_core_storage.TABLE_KNOWLEDGE_ACTIVITY}" WHERE ${visibleSql}${input.after ? " AND id < ?" : ""} ORDER BY id DESC LIMIT ?`,
10128
+ sql: `SELECT *,scope AS "scopeJson" FROM "${_mastra_core_storage.TABLE_KNOWLEDGE_ACTIVITY}" WHERE ${visibleSql(keys)}${input.after ? " AND id < ?" : ""} ORDER BY id DESC LIMIT ?`,
9083
10129
  args: [
9084
- key,
9085
- key,
10130
+ ...keys,
9086
10131
  ...input.after ? [input.after] : [],
9087
10132
  input.limit ?? 100
9088
10133
  ]
@@ -9104,9 +10149,9 @@ var KnowledgePG = class extends _mastra_core_storage.KnowledgeStorage {
9104
10149
  args.push(input.status);
9105
10150
  }
9106
10151
  if (input.scope) {
9107
- const key = (0, _mastra_core_storage.knowledgeScopeKey)((0, _mastra_core_storage.canonicalizeKnowledgeScope)(input.scope));
9108
- clauses.push(visibleSql);
9109
- args.push(key, key);
10152
+ const keys = visibleScopeKeys(input.scope);
10153
+ clauses.push(visibleSql(keys));
10154
+ args.push(...keys);
9110
10155
  }
9111
10156
  args.push(input.limit ?? 100);
9112
10157
  return (await this.#executor.execute({
@@ -9125,9 +10170,9 @@ var KnowledgePG = class extends _mastra_core_storage.KnowledgeStorage {
9125
10170
  ];
9126
10171
  const args = [now.toISOString(), stale.toISOString()];
9127
10172
  if (input.scope) {
9128
- const key = (0, _mastra_core_storage.knowledgeScopeKey)((0, _mastra_core_storage.canonicalizeKnowledgeScope)(input.scope));
9129
- clauses.push(visibleSql);
9130
- args.push(key, key);
10173
+ const keys = visibleScopeKeys(input.scope);
10174
+ clauses.push(visibleSql(keys));
10175
+ args.push(...keys);
9131
10176
  }
9132
10177
  args.push(input.limit ?? 100);
9133
10178
  const ids = (await tx.execute({
@@ -9194,12 +10239,14 @@ var KnowledgePG = class extends _mastra_core_storage.KnowledgeStorage {
9194
10239
  return result.rows[0] ? parseNode(result.rows[0]) : null;
9195
10240
  }
9196
10241
  async #resolveNode(executor, name, scope) {
9197
- for (let length = scope.length; length > 0; length--) {
9198
- const node = await this.#getNodeByName(executor, name, scope.slice(0, length));
9199
- if (node) {
9200
- const terminal = await this.#resolveTerminalNode(executor, node.id);
9201
- if (terminal && (0, _mastra_core_storage.isKnowledgeScopeVisible)(terminal.scope, scope)) return terminal;
9202
- }
10242
+ const keys = visibleScopeKeys(scope);
10243
+ const candidates = (await executor.execute({
10244
+ sql: `SELECT *,scope AS "scopeJson" FROM "${_mastra_core_storage.TABLE_KNOWLEDGE_NODES}" WHERE type='node' AND canonicalName=? AND ("scopeKey" IN (${keys.map(() => "?").join(",")}) OR "mergedInto" IS NOT NULL)`,
10245
+ args: [canonicalName(name), ...keys]
10246
+ })).rows.map(parseNode).sort((left, right) => right.scope.length - left.scope.length);
10247
+ for (const candidate of candidates) {
10248
+ const terminal = await this.#resolveTerminalNode(executor, candidate.id);
10249
+ if (terminal && (0, _mastra_core_storage.isKnowledgeScopeVisible)(terminal.scope, scope)) return terminal;
9203
10250
  }
9204
10251
  return null;
9205
10252
  }
@@ -9224,17 +10271,16 @@ var KnowledgePG = class extends _mastra_core_storage.KnowledgeStorage {
9224
10271
  const scope = (0, _mastra_core_storage.canonicalizeKnowledgeScope)(input.scope);
9225
10272
  const node = await this.#resolveTerminalNode(this.#readExecutor, nodeReferenceId(input.node));
9226
10273
  if (!node) return { records: [] };
9227
- const key = (0, _mastra_core_storage.knowledgeScopeKey)(scope);
10274
+ const keys = visibleScopeKeys(scope);
9228
10275
  const args = [
9229
10276
  node.id,
9230
10277
  ...relationship === "related" ? [node.id] : [],
9231
- key,
9232
- key
10278
+ ...keys
9233
10279
  ];
9234
10280
  if (input.after) args.push(input.after);
9235
10281
  args.push((input.limit ?? 100) + 1);
9236
10282
  const records = (await this.#readExecutor.execute({
9237
- sql: `SELECT DISTINCT f.*,f.scope AS "scopeJson" FROM "${_mastra_core_storage.TABLE_KNOWLEDGE_RECORDS}" f${relationship === "about" ? "" : ` LEFT JOIN "${_mastra_core_storage.TABLE_KNOWLEDGE_MENTIONS}" m ON m.sourceType='record' AND m.sourceId=f.id`} WHERE ${relationship === "about" ? "f.node=?" : relationship === "mentioning" ? "m.recordId=?" : "(f.node=? OR m.recordId=?)"} AND ${visibleSql.replaceAll("scopeKey", "f.scopeKey")}${input.includeDeleted ? "" : " AND f.deletedAt IS NULL"}${input.after ? " AND f.id < ?" : ""} ORDER BY f.id DESC LIMIT ?`,
10283
+ sql: `SELECT DISTINCT f.*,f.scope AS "scopeJson" FROM "${_mastra_core_storage.TABLE_KNOWLEDGE_RECORDS}" f${relationship === "about" ? "" : ` LEFT JOIN "${_mastra_core_storage.TABLE_KNOWLEDGE_MENTIONS}" m ON m.sourceType='record' AND m.sourceId=f.id`} WHERE ${relationship === "about" ? "f.node=?" : relationship === "mentioning" ? "m.recordId=?" : "(f.node=? OR m.recordId=?)"} AND ${visibleSql(keys, "f.scopeKey")}${input.includeDeleted ? "" : " AND f.deletedAt IS NULL"}${input.after ? " AND f.id < ?" : ""} ORDER BY f.id DESC LIMIT ?`,
9238
10284
  args
9239
10285
  })).rows.map(parseKnowledge);
9240
10286
  const limit = input.limit ?? 100;
@@ -9243,6 +10289,90 @@ var KnowledgePG = class extends _mastra_core_storage.KnowledgeStorage {
9243
10289
  nextCursor: records.length > limit ? records[limit - 1]?.id : void 0
9244
10290
  };
9245
10291
  }
10292
+ async #resolveScopeNodeIds(executor, addresses) {
10293
+ const scopeNodeIds = /* @__PURE__ */ new Set();
10294
+ for (const address of addresses) {
10295
+ const result = await executor.execute({
10296
+ sql: `SELECT scopeNodeId FROM "${TABLE_KNOWLEDGE_SCOPE_ADDRESSES}" WHERE address=?`,
10297
+ args: [address]
10298
+ });
10299
+ if (result.rows[0]?.scopeNodeId != null) scopeNodeIds.add(String(result.rows[0].scopeNodeId));
10300
+ }
10301
+ return [...scopeNodeIds];
10302
+ }
10303
+ async #replaceNodeScopes(executor, nodeId, addresses, addedAt) {
10304
+ await executor.execute({
10305
+ sql: `DELETE FROM "${TABLE_KNOWLEDGE_NODE_SCOPES}" WHERE nodeId=?`,
10306
+ args: [nodeId]
10307
+ });
10308
+ for (const scopeNodeId of await this.#resolveScopeNodeIds(executor, addresses)) await executor.execute({
10309
+ sql: `INSERT INTO "${TABLE_KNOWLEDGE_NODE_SCOPES}" (nodeId,scopeNodeId,addedAt) VALUES (?,?,?) ON CONFLICT DO NOTHING`,
10310
+ args: [
10311
+ nodeId,
10312
+ scopeNodeId,
10313
+ addedAt.toISOString()
10314
+ ]
10315
+ });
10316
+ }
10317
+ /**
10318
+ * Move a node's identity memberships from `from` to `to` without touching structural
10319
+ * placements added by `#placeNodeInScopes`, which a scope change must not erase.
10320
+ */
10321
+ async #swapIdentityScopes(executor, nodeId, from, to, addedAt) {
10322
+ const next = await this.#resolveScopeNodeIds(executor, to);
10323
+ for (const scopeNodeId of await this.#resolveScopeNodeIds(executor, from)) {
10324
+ if (next.includes(scopeNodeId)) continue;
10325
+ await executor.execute({
10326
+ sql: `DELETE FROM "${TABLE_KNOWLEDGE_NODE_SCOPES}" WHERE nodeId=? AND scopeNodeId=?`,
10327
+ args: [nodeId, scopeNodeId]
10328
+ });
10329
+ }
10330
+ for (const scopeNodeId of next) await executor.execute({
10331
+ sql: `INSERT INTO "${TABLE_KNOWLEDGE_NODE_SCOPES}" (nodeId,scopeNodeId,addedAt) VALUES (?,?,?) ON CONFLICT DO NOTHING`,
10332
+ args: [
10333
+ nodeId,
10334
+ scopeNodeId,
10335
+ addedAt.toISOString()
10336
+ ]
10337
+ });
10338
+ }
10339
+ /**
10340
+ * Additive structural placement: every address must resolve to a live scope node
10341
+ * (unlike identity membership, an unknown address is a caller error, not a lazy
10342
+ * materialization miss). Runs inside the caller's transaction, so a throw aborts
10343
+ * the whole mutation.
10344
+ */
10345
+ async #placeNodeInScopes(executor, nodeId, addresses, addedAt) {
10346
+ for (const address of addresses ?? []) {
10347
+ const scopeNodeId = (await executor.execute({
10348
+ sql: `SELECT sa.scopeNodeId AS "scopeNodeId" FROM "${TABLE_KNOWLEDGE_SCOPE_ADDRESSES}" sa JOIN "${_mastra_core_storage.TABLE_KNOWLEDGE_NODES}" n ON n.id=sa."scopeNodeId" WHERE sa.address=? AND n."isScope" AND n."deletedAt" IS NULL`,
10349
+ args: [address]
10350
+ })).rows[0]?.scopeNodeId;
10351
+ if (scopeNodeId == null) throw new _mastra_core_storage.KnowledgeNotFoundError("scope", address);
10352
+ await executor.execute({
10353
+ sql: `INSERT INTO "${TABLE_KNOWLEDGE_NODE_SCOPES}" ("nodeId","scopeNodeId","addedAt") VALUES (?,?,?) ON CONFLICT DO NOTHING`,
10354
+ args: [
10355
+ nodeId,
10356
+ String(scopeNodeId),
10357
+ addedAt.toISOString()
10358
+ ]
10359
+ });
10360
+ }
10361
+ }
10362
+ async #replaceRecordScopes(executor, recordId, addresses, addedAt) {
10363
+ await executor.execute({
10364
+ sql: `DELETE FROM "${TABLE_KNOWLEDGE_RECORD_SCOPES}" WHERE recordId=?`,
10365
+ args: [recordId]
10366
+ });
10367
+ for (const scopeNodeId of await this.#resolveScopeNodeIds(executor, addresses)) await executor.execute({
10368
+ sql: `INSERT INTO "${TABLE_KNOWLEDGE_RECORD_SCOPES}" (recordId,scopeNodeId,addedAt) VALUES (?,?,?) ON CONFLICT DO NOTHING`,
10369
+ args: [
10370
+ recordId,
10371
+ scopeNodeId,
10372
+ addedAt.toISOString()
10373
+ ]
10374
+ });
10375
+ }
9246
10376
  async #replaceMentions(tx, sourceType, sourceId, text, resolutionScope, defaultScope) {
9247
10377
  await tx.execute({
9248
10378
  sql: `DELETE FROM "${_mastra_core_storage.TABLE_KNOWLEDGE_MENTIONS}" WHERE sourceType=? AND sourceId=?`,
@@ -9266,7 +10396,7 @@ var KnowledgePG = class extends _mastra_core_storage.KnowledgeStorage {
9266
10396
  updatedAt: now
9267
10397
  };
9268
10398
  await tx.execute({
9269
- sql: `INSERT INTO "${_mastra_core_storage.TABLE_KNOWLEDGE_NODES}" (id,type,name,canonicalName,kind,content,scope,scopeKey,version,mergedInto,createdAt,updatedAt) VALUES (?,?,?,?,?,NULL,jsonb(?),?,?,NULL,?,?)`,
10399
+ sql: `INSERT INTO "${_mastra_core_storage.TABLE_KNOWLEDGE_NODES}" (id,type,name,canonicalName,kind,content,isScope,scope,scopeKey,version,mergedInto,createdAt,updatedAt) VALUES (?,?,?,?,?,NULL,FALSE,jsonb(?),?,?,NULL,?,?)`,
9270
10400
  args: [
9271
10401
  node.id,
9272
10402
  "node",
@@ -9280,6 +10410,7 @@ var KnowledgePG = class extends _mastra_core_storage.KnowledgeStorage {
9280
10410
  now.toISOString()
9281
10411
  ]
9282
10412
  });
10413
+ await this.#replaceNodeScopes(tx, node.id, defaultScope, now);
9283
10414
  await this.#activity(tx, "node-created", "node", node.id, defaultScope);
9284
10415
  await this.#outbox(tx, "node", node.id, "upsert", 1, defaultScope);
9285
10416
  }
@@ -9296,13 +10427,17 @@ var KnowledgePG = class extends _mastra_core_storage.KnowledgeStorage {
9296
10427
  }
9297
10428
  async #activity(executor, action, recordType, recordId, scope, sourceThreadId) {
9298
10429
  const now = /* @__PURE__ */ new Date();
10430
+ const [contextScopeId] = await this.#resolveScopeNodeIds(executor, scope);
9299
10431
  await executor.execute({
9300
- sql: `INSERT INTO "${_mastra_core_storage.TABLE_KNOWLEDGE_ACTIVITY}" (id,action,recordType,recordId,scope,scopeKey,sourceThreadId,createdAt) VALUES (?,?,?,?,jsonb(?),?,?,?)`,
10432
+ sql: `INSERT INTO "${_mastra_core_storage.TABLE_KNOWLEDGE_ACTIVITY}" (id,action,targetType,targetId,contextScopeId,recordType,recordId,scope,scopeKey,sourceThreadId,createdAt) VALUES (?,?,?,?,?,?,?,jsonb(?),?,?,?)`,
9301
10433
  args: [
9302
10434
  (0, _mastra_core_storage.createKnowledgeUlid)(),
9303
10435
  action,
9304
10436
  recordType,
9305
10437
  recordId,
10438
+ contextScopeId ?? null,
10439
+ recordType,
10440
+ recordId,
9306
10441
  JSON.stringify(scope),
9307
10442
  (0, _mastra_core_storage.knowledgeScopeKey)(scope),
9308
10443
  sourceThreadId ?? null,
@@ -9439,6 +10574,7 @@ var MCPClientsPG = class MCPClientsPG extends _mastra_core_storage.MCPClientsSto
9439
10574
  }
9440
10575
  async create(input) {
9441
10576
  const { mcpClient } = input;
10577
+ let draftInserted = false;
9442
10578
  try {
9443
10579
  const tableName = getTableName$5({
9444
10580
  indexName: _mastra_core_storage.TABLE_MCP_CLIENTS,
@@ -9461,6 +10597,7 @@ var MCPClientsPG = class MCPClientsPG extends _mastra_core_storage.MCPClientsSto
9461
10597
  nowIso,
9462
10598
  nowIso
9463
10599
  ]);
10600
+ draftInserted = true;
9464
10601
  const { id: _id, authorId: _authorId, metadata: _metadata, ...snapshotConfig } = mcpClient;
9465
10602
  const versionId = crypto.randomUUID();
9466
10603
  await this.createVersion({
@@ -9481,7 +10618,7 @@ var MCPClientsPG = class MCPClientsPG extends _mastra_core_storage.MCPClientsSto
9481
10618
  updatedAt: now
9482
10619
  };
9483
10620
  } catch (error) {
9484
- try {
10621
+ if (draftInserted) try {
9485
10622
  const tableName = getTableName$5({
9486
10623
  indexName: _mastra_core_storage.TABLE_MCP_CLIENTS,
9487
10624
  schemaName: getSchemaName$5(this.#schema)
@@ -10007,6 +11144,7 @@ var MCPServersPG = class MCPServersPG extends _mastra_core_storage.MCPServersSto
10007
11144
  }
10008
11145
  async create(input) {
10009
11146
  const { mcpServer } = input;
11147
+ let draftInserted = false;
10010
11148
  try {
10011
11149
  const tableName = getTableName$5({
10012
11150
  indexName: _mastra_core_storage.TABLE_MCP_SERVERS,
@@ -10028,6 +11166,7 @@ var MCPServersPG = class MCPServersPG extends _mastra_core_storage.MCPServersSto
10028
11166
  nowIso,
10029
11167
  nowIso
10030
11168
  ]);
11169
+ draftInserted = true;
10031
11170
  const { id: _id, authorId: _authorId, metadata: _metadata, ...snapshotConfig } = mcpServer;
10032
11171
  const versionId = crypto.randomUUID();
10033
11172
  await this.createVersion({
@@ -10048,7 +11187,7 @@ var MCPServersPG = class MCPServersPG extends _mastra_core_storage.MCPServersSto
10048
11187
  updatedAt: now
10049
11188
  };
10050
11189
  } catch (error) {
10051
- try {
11190
+ if (draftInserted) try {
10052
11191
  const tableName = getTableName$5({
10053
11192
  indexName: _mastra_core_storage.TABLE_MCP_SERVERS,
10054
11193
  schemaName: getSchemaName$5(this.#schema)
@@ -10472,6 +11611,38 @@ var MCPServersPG = class MCPServersPG extends _mastra_core_storage.MCPServersSto
10472
11611
  }
10473
11612
  };
10474
11613
  //#endregion
11614
+ //#region src/storage/db/run-fencing.ts
11615
+ /**
11616
+ * Epoch milliseconds on the database clock. `clock_timestamp()` rather than
11617
+ * `now()`: a statement can wait on a row lock, and lease math must use the
11618
+ * time it actually runs, not when its transaction started.
11619
+ */
11620
+ const DB_NOW_MS = `(EXTRACT(EPOCH FROM clock_timestamp()) * 1000)::bigint`;
11621
+ /**
11622
+ * The check half of a fenced write; call it first inside the write's
11623
+ * transaction. `FOR SHARE` holds the claim row until commit, so a claim that
11624
+ * updates the row waits for the write to finish, and every later write sees
11625
+ * the new claim.
11626
+ */
11627
+ async function assertRunFence(t, claimsTable, fence, operation) {
11628
+ const row = await t.oneOrNone(`SELECT generation, "ownerId" FROM ${claimsTable} WHERE "runId" = $1 FOR SHARE`, [fence.runId]);
11629
+ if (!(0, _mastra_core_storage.matchesRunFence)(row && {
11630
+ generation: Number(row.generation),
11631
+ ownerId: row.ownerId
11632
+ }, fence)) throw new _mastra_core_storage.RunFenceConflictError(fence, operation);
11633
+ }
11634
+ /**
11635
+ * Runs `write` directly when it carries no fence, or in a transaction behind
11636
+ * the fence check when it does.
11637
+ */
11638
+ function withRunFence(client, claimsTable, fence, operation, write) {
11639
+ if (!fence) return write(client);
11640
+ return client.tx(async (t) => {
11641
+ await assertRunFence(t, claimsTable, fence, operation);
11642
+ return write(t);
11643
+ });
11644
+ }
11645
+ //#endregion
10475
11646
  //#region src/storage/domains/memory/index.ts
10476
11647
  /**
10477
11648
  * Local constant for the observational memory table name.
@@ -10572,6 +11743,10 @@ var MemoryPG = class MemoryPG extends _mastra_core_storage.MemoryStorage {
10572
11743
  * and are indexed for fast batched deletes. Cascade order is enforced in
10573
11744
  * `prune()` (children before threads), not here. Observational memory has no
10574
11745
  * timestamp anchor and is deliberately excluded.
11746
+ *
11747
+ * Run fences anchor on `retiredAt` (epoch ms), which stays NULL until the
11748
+ * execution holding the fence settles, so a running execution's fence is
11749
+ * never pruned.
10575
11750
  */
10576
11751
  static retentionTables = {
10577
11752
  messages: {
@@ -10588,6 +11763,12 @@ var MemoryPG = class MemoryPG extends _mastra_core_storage.MemoryStorage {
10588
11763
  table: _mastra_core_storage.TABLE_THREADS,
10589
11764
  column: "createdAtZ",
10590
11765
  indexed: true
11766
+ },
11767
+ runFences: {
11768
+ table: _mastra_core_storage.TABLE_MEMORY_RUN_FENCES,
11769
+ column: "retiredAt",
11770
+ indexed: true,
11771
+ anchorType: "epoch-ms"
10591
11772
  }
10592
11773
  };
10593
11774
  #db;
@@ -10651,6 +11832,10 @@ var MemoryPG = class MemoryPG extends _mastra_core_storage.MemoryStorage {
10651
11832
  });
10652
11833
  await this.#db.createIndexFromStatement("idx_om_lookup_key", `CREATE INDEX IF NOT EXISTS idx_om_lookup_key ON ${omTableName} ("lookupKey")`);
10653
11834
  }
11835
+ await this.#db.createTable({
11836
+ tableName: _mastra_core_storage.TABLE_MEMORY_RUN_FENCES,
11837
+ schema: _mastra_core_storage.RUN_FENCING_TABLE_SCHEMAS[_mastra_core_storage.TABLE_MEMORY_RUN_FENCES]
11838
+ });
10654
11839
  await this.createDefaultIndexes();
10655
11840
  await this.createCustomIndexes();
10656
11841
  }
@@ -10728,6 +11913,12 @@ var MemoryPG = class MemoryPG extends _mastra_core_storage.MemoryStorage {
10728
11913
  statements.push(`CREATE INDEX IF NOT EXISTS "${idxPrefix}idx_om_lookup_key" ON ${fullOmTableName} ("lookupKey");`);
10729
11914
  }
10730
11915
  for (const idx of MemoryPG.getDefaultIndexDefs(schemaPrefix)) statements.push(generateIndexSQL(idx, schemaName));
11916
+ statements.push(generateTableSQL({
11917
+ tableName: _mastra_core_storage.TABLE_MEMORY_RUN_FENCES,
11918
+ schema: _mastra_core_storage.RUN_FENCING_TABLE_SCHEMAS[_mastra_core_storage.TABLE_MEMORY_RUN_FENCES],
11919
+ schemaName,
11920
+ includeAllConstraints: true
11921
+ }));
10731
11922
  return statements;
10732
11923
  }
10733
11924
  /**
@@ -10763,6 +11954,61 @@ var MemoryPG = class MemoryPG extends _mastra_core_storage.MemoryStorage {
10763
11954
  await this.#db.clearTable({ tableName: _mastra_core_storage.TABLE_MESSAGES });
10764
11955
  await this.#db.clearTable({ tableName: _mastra_core_storage.TABLE_THREADS });
10765
11956
  await this.#db.clearTable({ tableName: _mastra_core_storage.TABLE_RESOURCES });
11957
+ await this.#db.clearTable({ tableName: _mastra_core_storage.TABLE_MEMORY_RUN_FENCES });
11958
+ }
11959
+ supportsRunFencing() {
11960
+ return true;
11961
+ }
11962
+ #runFencesTable() {
11963
+ return getTableName$3({
11964
+ indexName: _mastra_core_storage.TABLE_MEMORY_RUN_FENCES,
11965
+ schemaName: getSchemaName$3(this.#schema)
11966
+ });
11967
+ }
11968
+ /** Runs `write` behind the run's fence check when it carries a fence. */
11969
+ #fenced(fence, operation, write) {
11970
+ return withRunFence(this.#db.client, this.#runFencesTable(), (0, _mastra_core_storage.resolveRunFence)(this, fence), operation, write);
11971
+ }
11972
+ async raiseRunFence(fence) {
11973
+ try {
11974
+ return await this.#db.client.oneOrNone(`INSERT INTO ${this.#runFencesTable()} AS f ("runId", generation, "ownerId")
11975
+ VALUES ($1, $2, $3)
11976
+ ON CONFLICT ("runId") DO UPDATE
11977
+ SET generation = EXCLUDED.generation, "ownerId" = EXCLUDED."ownerId", "retiredAt" = NULL
11978
+ WHERE f.generation < EXCLUDED.generation
11979
+ OR (f.generation = EXCLUDED.generation AND f."ownerId" = EXCLUDED."ownerId")
11980
+ RETURNING "runId"`, [
11981
+ fence.runId,
11982
+ fence.generation,
11983
+ fence.ownerId
11984
+ ]) !== null;
11985
+ } catch (error) {
11986
+ throw new _mastra_core_error.MastraError({
11987
+ id: (0, _mastra_core_storage.createStorageErrorId)("PG", "RAISE_RUN_FENCE", "FAILED"),
11988
+ domain: _mastra_core_error.ErrorDomain.STORAGE,
11989
+ category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
11990
+ details: { runId: fence.runId }
11991
+ }, error);
11992
+ }
11993
+ }
11994
+ async retireRunFence(fence) {
11995
+ try {
11996
+ return await this.#db.client.oneOrNone(`UPDATE ${this.#runFencesTable()}
11997
+ SET "retiredAt" = ${DB_NOW_MS}
11998
+ WHERE "runId" = $1 AND generation = $2 AND "ownerId" = $3
11999
+ RETURNING "runId"`, [
12000
+ fence.runId,
12001
+ fence.generation,
12002
+ fence.ownerId
12003
+ ]) !== null;
12004
+ } catch (error) {
12005
+ throw new _mastra_core_error.MastraError({
12006
+ id: (0, _mastra_core_storage.createStorageErrorId)("PG", "RETIRE_RUN_FENCE", "FAILED"),
12007
+ domain: _mastra_core_error.ErrorDomain.STORAGE,
12008
+ category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
12009
+ details: { runId: fence.runId }
12010
+ }, error);
12011
+ }
10766
12012
  }
10767
12013
  /**
10768
12014
  * Deletes rows older than the configured `maxAge` per table, in bounded,
@@ -10783,7 +12029,8 @@ var MemoryPG = class MemoryPG extends _mastra_core_storage.MemoryStorage {
10783
12029
  order: [
10784
12030
  "messages",
10785
12031
  "resources",
10786
- "threads"
12032
+ "threads",
12033
+ "runFences"
10787
12034
  ]
10788
12035
  });
10789
12036
  const results = await runPrune({
@@ -11041,7 +12288,7 @@ var MemoryPG = class MemoryPG extends _mastra_core_storage.MemoryStorage {
11041
12288
  throw mastraError;
11042
12289
  }
11043
12290
  }
11044
- async saveThread({ thread }) {
12291
+ async saveThread({ thread, fence }) {
11045
12292
  try {
11046
12293
  const tableName = getTableName$3({
11047
12294
  indexName: _mastra_core_storage.TABLE_THREADS,
@@ -11050,7 +12297,7 @@ var MemoryPG = class MemoryPG extends _mastra_core_storage.MemoryStorage {
11050
12297
  const createdAt = toUtcISOString(thread.createdAt);
11051
12298
  const updatedAt = toUtcISOString(thread.updatedAt);
11052
12299
  const metadataJson = thread.metadata ? toPgJson(thread.metadata) : null;
11053
- await this.#db.client.none(`INSERT INTO ${tableName} (
12300
+ await this.#fenced(fence, "saveThread", (q) => q.none(`INSERT INTO ${tableName} (
11054
12301
  id,
11055
12302
  "resourceId",
11056
12303
  title,
@@ -11076,12 +12323,13 @@ var MemoryPG = class MemoryPG extends _mastra_core_storage.MemoryStorage {
11076
12323
  createdAt,
11077
12324
  updatedAt,
11078
12325
  updatedAt
11079
- ]);
12326
+ ]));
11080
12327
  return {
11081
12328
  ...thread,
11082
12329
  metadata: metadataJson ? JSON.parse(metadataJson) : thread.metadata
11083
12330
  };
11084
12331
  } catch (error) {
12332
+ if ((0, _mastra_core_storage.isRunFenceConflictError)(error)) throw error;
11085
12333
  throw new _mastra_core_error.MastraError({
11086
12334
  id: (0, _mastra_core_storage.createStorageErrorId)("PG", "SAVE_THREAD", "FAILED"),
11087
12335
  domain: _mastra_core_error.ErrorDomain.STORAGE,
@@ -11090,29 +12338,30 @@ var MemoryPG = class MemoryPG extends _mastra_core_storage.MemoryStorage {
11090
12338
  }, error);
11091
12339
  }
11092
12340
  }
11093
- async updateThread({ id, title, metadata }) {
12341
+ async updateThread({ id, title, metadata, fence }) {
11094
12342
  const threadTableName = getTableName$3({
11095
12343
  indexName: _mastra_core_storage.TABLE_THREADS,
11096
12344
  schemaName: getSchemaName$3(this.#schema)
11097
12345
  });
11098
- const existingThread = await this.#getThreadById(this.#db.client, { threadId: id });
11099
- if (!existingThread) throw new _mastra_core_error.MastraError({
11100
- id: (0, _mastra_core_storage.createStorageErrorId)("PG", "UPDATE_THREAD", "FAILED"),
11101
- domain: _mastra_core_error.ErrorDomain.STORAGE,
11102
- category: _mastra_core_error.ErrorCategory.USER,
11103
- text: `Thread ${id} not found`,
11104
- details: {
11105
- threadId: id,
11106
- title: title ?? null
11107
- }
11108
- });
11109
- const mergedMetadata = {
11110
- ...existingThread.metadata,
11111
- ...metadata
11112
- };
11113
12346
  try {
11114
- const nowStr = toUtcISOString(/* @__PURE__ */ new Date());
11115
- const thread = await this.#db.client.one(`UPDATE ${threadTableName}
12347
+ return await this.#fenced(fence, "updateThread", async (q) => {
12348
+ const existingThread = await this.#getThreadById(q, { threadId: id });
12349
+ if (!existingThread) throw new _mastra_core_error.MastraError({
12350
+ id: (0, _mastra_core_storage.createStorageErrorId)("PG", "UPDATE_THREAD", "FAILED"),
12351
+ domain: _mastra_core_error.ErrorDomain.STORAGE,
12352
+ category: _mastra_core_error.ErrorCategory.USER,
12353
+ text: `Thread ${id} not found`,
12354
+ details: {
12355
+ threadId: id,
12356
+ title: title ?? null
12357
+ }
12358
+ });
12359
+ const mergedMetadata = {
12360
+ ...existingThread.metadata,
12361
+ ...metadata
12362
+ };
12363
+ const nowStr = toUtcISOString(/* @__PURE__ */ new Date());
12364
+ const thread = await q.one(`UPDATE ${threadTableName}
11116
12365
  SET
11117
12366
  title = COALESCE($1, title),
11118
12367
  metadata = $2,
@@ -11121,21 +12370,23 @@ var MemoryPG = class MemoryPG extends _mastra_core_storage.MemoryStorage {
11121
12370
  WHERE id = $5
11122
12371
  RETURNING *
11123
12372
  `, [
11124
- title ?? null,
11125
- mergedMetadata,
11126
- nowStr,
11127
- nowStr,
11128
- id
11129
- ]);
11130
- return {
11131
- id: thread.id,
11132
- resourceId: thread.resourceId,
11133
- title: thread.title,
11134
- metadata: typeof thread.metadata === "string" ? JSON.parse(thread.metadata) : thread.metadata,
11135
- createdAt: thread.createdAtZ || thread.createdAt,
11136
- updatedAt: thread.updatedAtZ || thread.updatedAt
11137
- };
12373
+ title ?? null,
12374
+ mergedMetadata,
12375
+ nowStr,
12376
+ nowStr,
12377
+ id
12378
+ ]);
12379
+ return {
12380
+ id: thread.id,
12381
+ resourceId: thread.resourceId,
12382
+ title: thread.title,
12383
+ metadata: typeof thread.metadata === "string" ? JSON.parse(thread.metadata) : thread.metadata,
12384
+ createdAt: thread.createdAtZ || thread.createdAt,
12385
+ updatedAt: thread.updatedAtZ || thread.updatedAt
12386
+ };
12387
+ });
11138
12388
  } catch (error) {
12389
+ if (error instanceof _mastra_core_error.MastraError || (0, _mastra_core_storage.isRunFenceConflictError)(error)) throw error;
11139
12390
  throw new _mastra_core_error.MastraError({
11140
12391
  id: (0, _mastra_core_storage.createStorageErrorId)("PG", "UPDATE_THREAD", "FAILED"),
11141
12392
  domain: _mastra_core_error.ErrorDomain.STORAGE,
@@ -11688,8 +12939,9 @@ var MemoryPG = class MemoryPG extends _mastra_core_storage.MemoryStorage {
11688
12939
  throw mastraError;
11689
12940
  }
11690
12941
  }
11691
- async saveMessages({ messages }) {
12942
+ async saveMessages({ messages, fence: explicitFence }) {
11692
12943
  if (messages.length === 0) return { messages: [] };
12944
+ const fence = (0, _mastra_core_storage.resolveRunFence)(this, explicitFence);
11693
12945
  const threadId = messages[0]?.threadId;
11694
12946
  if (!threadId) throw new _mastra_core_error.MastraError({
11695
12947
  id: (0, _mastra_core_storage.createStorageErrorId)("PG", "SAVE_MESSAGES", "FAILED"),
@@ -11717,6 +12969,7 @@ var MemoryPG = class MemoryPG extends _mastra_core_storage.MemoryStorage {
11717
12969
  });
11718
12970
  const messagesToSave = dedupeMessagesForSave(messages);
11719
12971
  await this.#db.client.tx(async (t) => {
12972
+ if (fence) await assertRunFence(t, this.#runFencesTable(), fence, "saveMessages");
11720
12973
  for (let offset = 0; offset < messagesToSave.length; offset += MAX_MESSAGES_PER_INSERT) {
11721
12974
  const batch = messagesToSave.slice(offset, offset + MAX_MESSAGES_PER_INSERT);
11722
12975
  const values = [];
@@ -11763,7 +13016,7 @@ var MemoryPG = class MemoryPG extends _mastra_core_storage.MemoryStorage {
11763
13016
  });
11764
13017
  return { messages: new _mastra_core_agent.MessageList().add(messagesWithParsedContent, "memory").get.all.db() };
11765
13018
  } catch (error) {
11766
- if (error instanceof _mastra_core_error.MastraError) throw error;
13019
+ if (error instanceof _mastra_core_error.MastraError || (0, _mastra_core_storage.isRunFenceConflictError)(error)) throw error;
11767
13020
  throw new _mastra_core_error.MastraError({
11768
13021
  id: (0, _mastra_core_storage.createStorageErrorId)("PG", "SAVE_MESSAGES", "FAILED"),
11769
13022
  domain: _mastra_core_error.ErrorDomain.STORAGE,
@@ -11772,8 +13025,9 @@ var MemoryPG = class MemoryPG extends _mastra_core_storage.MemoryStorage {
11772
13025
  }, error);
11773
13026
  }
11774
13027
  }
11775
- async updateMessages({ messages }) {
13028
+ async updateMessages({ messages, fence: explicitFence }) {
11776
13029
  if (messages.length === 0) return [];
13030
+ const fence = (0, _mastra_core_storage.resolveRunFence)(this, explicitFence);
11777
13031
  const messageIds = messages.map((m) => m.id);
11778
13032
  const selectQuery = `SELECT id, content, role, type, "createdAt", "createdAtZ", thread_id AS "threadId", "resourceId" FROM ${getTableName$3({
11779
13033
  indexName: _mastra_core_storage.TABLE_MESSAGES,
@@ -11789,6 +13043,7 @@ var MemoryPG = class MemoryPG extends _mastra_core_storage.MemoryStorage {
11789
13043
  });
11790
13044
  const threadIdsToUpdate = /* @__PURE__ */ new Set();
11791
13045
  await this.#db.client.tx(async (t) => {
13046
+ if (fence) await assertRunFence(t, this.#runFencesTable(), fence, "updateMessages");
11792
13047
  const queries = [];
11793
13048
  const columnMapping = { threadId: "thread_id" };
11794
13049
  for (const existingMessage of existingMessages) {
@@ -11849,8 +13104,9 @@ var MemoryPG = class MemoryPG extends _mastra_core_storage.MemoryStorage {
11849
13104
  return message;
11850
13105
  });
11851
13106
  }
11852
- async deleteMessages(messageIds) {
13107
+ async deleteMessages(messageIds, options) {
11853
13108
  if (!messageIds || messageIds.length === 0) return;
13109
+ const fence = (0, _mastra_core_storage.resolveRunFence)(this, options?.fence);
11854
13110
  try {
11855
13111
  const messageTableName = getTableName$3({
11856
13112
  indexName: _mastra_core_storage.TABLE_MESSAGES,
@@ -11861,12 +13117,14 @@ var MemoryPG = class MemoryPG extends _mastra_core_storage.MemoryStorage {
11861
13117
  schemaName: getSchemaName$3(this.#schema)
11862
13118
  });
11863
13119
  await this.#db.client.tx(async (t) => {
13120
+ if (fence) await assertRunFence(t, this.#runFencesTable(), fence, "deleteMessages");
11864
13121
  const placeholders = messageIds.map((_, idx) => `$${idx + 1}`).join(",");
11865
13122
  const threadIds = (await t.manyOrNone(`SELECT DISTINCT thread_id FROM ${messageTableName} WHERE id IN (${placeholders})`, messageIds))?.map((msg) => msg.thread_id).filter(Boolean) || [];
11866
13123
  await t.none(`DELETE FROM ${messageTableName} WHERE id IN (${placeholders})`, messageIds);
11867
13124
  if (threadIds.length > 0) await t.none(`UPDATE ${threadTableName} SET "updatedAt" = NOW(), "updatedAtZ" = NOW() WHERE id IN (${inPlaceholders(threadIds.length)})`, threadIds);
11868
13125
  });
11869
13126
  } catch (error) {
13127
+ if ((0, _mastra_core_storage.isRunFenceConflictError)(error)) throw error;
11870
13128
  throw new _mastra_core_error.MastraError({
11871
13129
  id: (0, _mastra_core_storage.createStorageErrorId)("PG", "DELETE_MESSAGES", "FAILED"),
11872
13130
  domain: _mastra_core_error.ErrorDomain.STORAGE,
@@ -11894,6 +13152,9 @@ var MemoryPG = class MemoryPG extends _mastra_core_storage.MemoryStorage {
11894
13152
  };
11895
13153
  }
11896
13154
  async saveResource({ resource }) {
13155
+ return this.#insertResource(this.#db.client, resource);
13156
+ }
13157
+ async #insertResource(q, resource) {
11897
13158
  const createdAt = toUtcISOString(resource.createdAt);
11898
13159
  const updatedAt = toUtcISOString(resource.updatedAt);
11899
13160
  const metadataJson = toPgJson(resource.metadata);
@@ -11905,7 +13166,7 @@ var MemoryPG = class MemoryPG extends _mastra_core_storage.MemoryStorage {
11905
13166
  createdAt,
11906
13167
  updatedAt
11907
13168
  }
11908
- });
13169
+ }, q);
11909
13170
  return {
11910
13171
  ...resource,
11911
13172
  metadata: metadataJson ? JSON.parse(metadataJson) : resource.metadata
@@ -11916,9 +13177,11 @@ var MemoryPG = class MemoryPG extends _mastra_core_storage.MemoryStorage {
11916
13177
  indexName: _mastra_core_storage.TABLE_RESOURCES,
11917
13178
  schemaName: getSchemaName$3(this.#schema)
11918
13179
  });
13180
+ const fence = (0, _mastra_core_storage.resolveRunFence)(this, void 0);
11919
13181
  const callbackError = {};
11920
13182
  try {
11921
13183
  return await this.#db.client.tx(async (t) => {
13184
+ if (fence) await assertRunFence(t, this.#runFencesTable(), fence, "mergeResourceWorkingMemory");
11922
13185
  const now = (/* @__PURE__ */ new Date()).toISOString();
11923
13186
  await t.none(`INSERT INTO ${tableName} (id, metadata, "createdAt", "createdAtZ", "updatedAt", "updatedAtZ")
11924
13187
  VALUES ($1, $2, $3, $4, $5, $6) ON CONFLICT (id) DO NOTHING`, [
@@ -11962,8 +13225,15 @@ var MemoryPG = class MemoryPG extends _mastra_core_storage.MemoryStorage {
11962
13225
  }, error);
11963
13226
  }
11964
13227
  }
11965
- async updateResource({ resourceId, workingMemory, metadata }) {
11966
- const existingResource = await this.#getResourceById(this.#db.client, resourceId);
13228
+ async updateResource({ resourceId, workingMemory, metadata, fence }) {
13229
+ return this.#fenced(fence, "updateResource", (q) => this.#updateResource(q, {
13230
+ resourceId,
13231
+ workingMemory,
13232
+ metadata
13233
+ }));
13234
+ }
13235
+ async #updateResource(q, { resourceId, workingMemory, metadata }) {
13236
+ const existingResource = await this.#getResourceById(q, resourceId);
11967
13237
  if (!existingResource) {
11968
13238
  const newResource = {
11969
13239
  id: resourceId,
@@ -11972,7 +13242,7 @@ var MemoryPG = class MemoryPG extends _mastra_core_storage.MemoryStorage {
11972
13242
  createdAt: /* @__PURE__ */ new Date(),
11973
13243
  updatedAt: /* @__PURE__ */ new Date()
11974
13244
  };
11975
- return this.saveResource({ resource: newResource });
13245
+ return this.#insertResource(q, newResource);
11976
13246
  }
11977
13247
  const updatedResource = {
11978
13248
  ...existingResource,
@@ -12008,7 +13278,7 @@ var MemoryPG = class MemoryPG extends _mastra_core_storage.MemoryStorage {
12008
13278
  updates.push(`"updatedAtZ" = $${paramIndex++}`);
12009
13279
  values.push(updatedAtStr);
12010
13280
  values.push(resourceId);
12011
- await this.#db.client.none(`UPDATE ${tableName} SET ${updates.join(", ")} WHERE id = $${paramIndex}`, values);
13281
+ await q.none(`UPDATE ${tableName} SET ${updates.join(", ")} WHERE id = $${paramIndex}`, values);
12012
13282
  return metadataJson ? {
12013
13283
  ...updatedResource,
12014
13284
  metadata: JSON.parse(metadataJson)
@@ -12147,9 +13417,11 @@ var MemoryPG = class MemoryPG extends _mastra_core_storage.MemoryStorage {
12147
13417
  * serializes generation creation across processes instead. It is
12148
13418
  * transaction-scoped so it also works behind transaction-pooling proxies.
12149
13419
  */
12150
- async #withOMLookupKeyLock(tableName, lookupKey, fn) {
13420
+ async #withOMLookupKeyLock(tableName, lookupKey, fn, fencedOperation) {
13421
+ const fence = fencedOperation ? (0, _mastra_core_storage.resolveRunFence)(this, void 0) : void 0;
12151
13422
  return this.#db.client.tx(async (t) => {
12152
13423
  await t.query("SELECT pg_advisory_xact_lock(hashtextextended($1, 0))", [`${tableName}:${lookupKey}`]);
13424
+ if (fence && fencedOperation) await assertRunFence(t, this.#runFencesTable(), fence, fencedOperation);
12153
13425
  return fn(t);
12154
13426
  });
12155
13427
  }
@@ -12446,7 +13718,7 @@ var MemoryPG = class MemoryPG extends _mastra_core_storage.MemoryStorage {
12446
13718
  const lastObservedAtStr = input.lastObservedAt.toISOString();
12447
13719
  const nowStr = now.toISOString();
12448
13720
  const observedMessageIdsJson = input.observedMessageIds ? toPgJson(input.observedMessageIds) : null;
12449
- if ((await this.#db.client.query(`UPDATE ${tableName} SET
13721
+ if ((await this.#fenced(void 0, "updateActiveObservations", (q) => q.query(`UPDATE ${tableName} SET
12450
13722
  "activeObservations" = $1,
12451
13723
  "lastObservedAt" = $2,
12452
13724
  "lastObservedAtZ" = $3,
@@ -12466,7 +13738,7 @@ var MemoryPG = class MemoryPG extends _mastra_core_storage.MemoryStorage {
12466
13738
  nowStr,
12467
13739
  nowStr,
12468
13740
  input.id
12469
- ])).rowCount === 0) throw new _mastra_core_error.MastraError({
13741
+ ]))).rowCount === 0) throw new _mastra_core_error.MastraError({
12470
13742
  id: (0, _mastra_core_storage.createStorageErrorId)("PG", "UPDATE_ACTIVE_OBSERVATIONS", "NOT_FOUND"),
12471
13743
  text: `Observational memory record not found: ${input.id}`,
12472
13744
  domain: _mastra_core_error.ErrorDomain.STORAGE,
@@ -12474,7 +13746,7 @@ var MemoryPG = class MemoryPG extends _mastra_core_storage.MemoryStorage {
12474
13746
  details: { id: input.id }
12475
13747
  });
12476
13748
  } catch (error) {
12477
- if (error instanceof _mastra_core_error.MastraError) throw error;
13749
+ if (error instanceof _mastra_core_error.MastraError || (0, _mastra_core_storage.isRunFenceConflictError)(error)) throw error;
12478
13750
  throw new _mastra_core_error.MastraError({
12479
13751
  id: (0, _mastra_core_storage.createStorageErrorId)("PG", "UPDATE_ACTIVE_OBSERVATIONS", "FAILED"),
12480
13752
  domain: _mastra_core_error.ErrorDomain.STORAGE,
@@ -12494,8 +13766,9 @@ var MemoryPG = class MemoryPG extends _mastra_core_storage.MemoryStorage {
12494
13766
  const newer = await this.#getNewerOMGeneration(t, tableName, lookupKey, input.currentRecord.generationCount);
12495
13767
  if (newer) return newer;
12496
13768
  return this.#insertReflectionGeneration(t, tableName, lookupKey, input);
12497
- });
13769
+ }, "createReflectionGeneration");
12498
13770
  } catch (error) {
13771
+ if ((0, _mastra_core_storage.isRunFenceConflictError)(error)) throw error;
12499
13772
  throw new _mastra_core_error.MastraError({
12500
13773
  id: (0, _mastra_core_storage.createStorageErrorId)("PG", "CREATE_REFLECTION_GENERATION", "FAILED"),
12501
13774
  domain: _mastra_core_error.ErrorDomain.STORAGE,
@@ -12855,7 +14128,7 @@ var MemoryPG = class MemoryPG extends _mastra_core_storage.MemoryStorage {
12855
14128
  extractionFailures: input.chunk.extractionFailures
12856
14129
  };
12857
14130
  const lastBufferedAtTime = input.lastBufferedAtTime ? input.lastBufferedAtTime.toISOString() : null;
12858
- if ((await this.#db.client.query(`UPDATE ${tableName} SET
14131
+ if ((await this.#fenced(void 0, "updateBufferedObservations", (q) => q.query(`UPDATE ${tableName} SET
12859
14132
  "bufferedObservationChunks" = CASE
12860
14133
  WHEN EXISTS (
12861
14134
  SELECT 1
@@ -12874,7 +14147,7 @@ var MemoryPG = class MemoryPG extends _mastra_core_storage.MemoryStorage {
12874
14147
  nowStr,
12875
14148
  nowStr,
12876
14149
  input.id
12877
- ])).rowCount === 0) throw new _mastra_core_error.MastraError({
14150
+ ]))).rowCount === 0) throw new _mastra_core_error.MastraError({
12878
14151
  id: (0, _mastra_core_storage.createStorageErrorId)("PG", "UPDATE_BUFFERED_OBSERVATIONS", "NOT_FOUND"),
12879
14152
  text: `Observational memory record not found: ${input.id}`,
12880
14153
  domain: _mastra_core_error.ErrorDomain.STORAGE,
@@ -12882,7 +14155,7 @@ var MemoryPG = class MemoryPG extends _mastra_core_storage.MemoryStorage {
12882
14155
  details: { id: input.id }
12883
14156
  });
12884
14157
  } catch (error) {
12885
- if (error instanceof _mastra_core_error.MastraError) throw error;
14158
+ if (error instanceof _mastra_core_error.MastraError || (0, _mastra_core_storage.isRunFenceConflictError)(error)) throw error;
12886
14159
  throw new _mastra_core_error.MastraError({
12887
14160
  id: (0, _mastra_core_storage.createStorageErrorId)("PG", "UPDATE_BUFFERED_OBSERVATIONS", "FAILED"),
12888
14161
  domain: _mastra_core_error.ErrorDomain.STORAGE,
@@ -12964,7 +14237,7 @@ var MemoryPG = class MemoryPG extends _mastra_core_storage.MemoryStorage {
12964
14237
  const lastObservedAt = input.lastObservedAt ?? (latestChunk?.lastObservedAt ? new Date(latestChunk.lastObservedAt) : /* @__PURE__ */ new Date());
12965
14238
  const lastObservedAtStr = lastObservedAt.toISOString();
12966
14239
  const boundary = `\n\n--- message boundary (${lastObservedAt.toISOString()}) ---\n\n`;
12967
- if ((await this.#db.client.query(`UPDATE ${tableName} SET
14240
+ if ((await this.#fenced(void 0, "swapBufferedToActive", (q) => q.query(`UPDATE ${tableName} SET
12968
14241
  "activeObservations" = CASE
12969
14242
  WHEN "activeObservations" IS NOT NULL AND "activeObservations" != ''
12970
14243
  THEN "activeObservations" || $10 || $1
@@ -12990,7 +14263,7 @@ var MemoryPG = class MemoryPG extends _mastra_core_storage.MemoryStorage {
12990
14263
  nowStr,
12991
14264
  input.id,
12992
14265
  boundary
12993
- ])).rowCount === 0) return {
14266
+ ]))).rowCount === 0) return {
12994
14267
  chunksActivated: 0,
12995
14268
  messageTokensActivated: 0,
12996
14269
  observationTokensActivated: 0,
@@ -13018,7 +14291,7 @@ var MemoryPG = class MemoryPG extends _mastra_core_storage.MemoryStorage {
13018
14291
  currentTask: latestChunkHints?.currentTask ?? void 0
13019
14292
  };
13020
14293
  } catch (error) {
13021
- if (error instanceof _mastra_core_error.MastraError) throw error;
14294
+ if (error instanceof _mastra_core_error.MastraError || (0, _mastra_core_storage.isRunFenceConflictError)(error)) throw error;
13022
14295
  throw new _mastra_core_error.MastraError({
13023
14296
  id: (0, _mastra_core_storage.createStorageErrorId)("PG", "SWAP_BUFFERED_TO_ACTIVE", "FAILED"),
13024
14297
  domain: _mastra_core_error.ErrorDomain.STORAGE,
@@ -13034,7 +14307,7 @@ var MemoryPG = class MemoryPG extends _mastra_core_storage.MemoryStorage {
13034
14307
  schemaName: getSchemaName$3(this.#schema)
13035
14308
  });
13036
14309
  const nowStr = (/* @__PURE__ */ new Date()).toISOString();
13037
- if ((await this.#db.client.query(`UPDATE ${tableName} SET
14310
+ if ((await this.#fenced(void 0, "updateBufferedReflection", (q) => q.query(`UPDATE ${tableName} SET
13038
14311
  "bufferedReflection" = CASE
13039
14312
  WHEN "bufferedReflection" IS NOT NULL AND "bufferedReflection" != ''
13040
14313
  THEN "bufferedReflection" || E'\\n\\n' || $1
@@ -13053,7 +14326,7 @@ var MemoryPG = class MemoryPG extends _mastra_core_storage.MemoryStorage {
13053
14326
  nowStr,
13054
14327
  nowStr,
13055
14328
  input.id
13056
- ])).rowCount === 0) throw new _mastra_core_error.MastraError({
14329
+ ]))).rowCount === 0) throw new _mastra_core_error.MastraError({
13057
14330
  id: (0, _mastra_core_storage.createStorageErrorId)("PG", "UPDATE_BUFFERED_REFLECTION", "NOT_FOUND"),
13058
14331
  text: `Observational memory record not found: ${input.id}`,
13059
14332
  domain: _mastra_core_error.ErrorDomain.STORAGE,
@@ -13061,7 +14334,7 @@ var MemoryPG = class MemoryPG extends _mastra_core_storage.MemoryStorage {
13061
14334
  details: { id: input.id }
13062
14335
  });
13063
14336
  } catch (error) {
13064
- if (error instanceof _mastra_core_error.MastraError) throw error;
14337
+ if (error instanceof _mastra_core_error.MastraError || (0, _mastra_core_storage.isRunFenceConflictError)(error)) throw error;
13065
14338
  throw new _mastra_core_error.MastraError({
13066
14339
  id: (0, _mastra_core_storage.createStorageErrorId)("PG", "UPDATE_BUFFERED_REFLECTION", "FAILED"),
13067
14340
  domain: _mastra_core_error.ErrorDomain.STORAGE,
@@ -13118,9 +14391,9 @@ var MemoryPG = class MemoryPG extends _mastra_core_storage.MemoryStorage {
13118
14391
  input.currentRecord.id
13119
14392
  ]);
13120
14393
  return newRecord;
13121
- });
14394
+ }, "swapBufferedReflectionToActive");
13122
14395
  } catch (error) {
13123
- if (error instanceof _mastra_core_error.MastraError) throw error;
14396
+ if (error instanceof _mastra_core_error.MastraError || (0, _mastra_core_storage.isRunFenceConflictError)(error)) throw error;
13124
14397
  throw new _mastra_core_error.MastraError({
13125
14398
  id: (0, _mastra_core_storage.createStorageErrorId)("PG", "SWAP_BUFFERED_REFLECTION_TO_ACTIVE", "FAILED"),
13126
14399
  domain: _mastra_core_error.ErrorDomain.STORAGE,
@@ -20116,6 +21389,7 @@ var PromptBlocksPG = class PromptBlocksPG extends _mastra_core_storage.PromptBlo
20116
21389
  }
20117
21390
  async create(input) {
20118
21391
  const { promptBlock } = input;
21392
+ let draftInserted = false;
20119
21393
  try {
20120
21394
  const tableName = getTableName$5({
20121
21395
  indexName: _mastra_core_storage.TABLE_PROMPT_BLOCKS,
@@ -20137,6 +21411,7 @@ var PromptBlocksPG = class PromptBlocksPG extends _mastra_core_storage.PromptBlo
20137
21411
  nowIso,
20138
21412
  nowIso
20139
21413
  ]);
21414
+ draftInserted = true;
20140
21415
  const { id: _id, authorId: _authorId, metadata: _metadata, ...snapshotConfig } = promptBlock;
20141
21416
  const versionId = crypto.randomUUID();
20142
21417
  await this.createVersion({
@@ -20157,14 +21432,14 @@ var PromptBlocksPG = class PromptBlocksPG extends _mastra_core_storage.PromptBlo
20157
21432
  updatedAt: now
20158
21433
  };
20159
21434
  } catch (error) {
20160
- if (error instanceof _mastra_core_error.MastraError) throw error;
20161
- try {
21435
+ if (draftInserted) try {
20162
21436
  const tableName = getTableName$5({
20163
21437
  indexName: _mastra_core_storage.TABLE_PROMPT_BLOCKS,
20164
21438
  schemaName: getSchemaName$5(this.#schema)
20165
21439
  });
20166
21440
  await this.#db.client.none(`DELETE FROM ${tableName} WHERE id = $1 AND status = 'draft' AND "activeVersionId" IS NULL`, [promptBlock.id]);
20167
21441
  } catch {}
21442
+ if (error instanceof _mastra_core_error.MastraError) throw error;
20168
21443
  throw new _mastra_core_error.MastraError({
20169
21444
  id: (0, _mastra_core_storage.createStorageErrorId)("PG", "CREATE_PROMPT_BLOCK", "FAILED"),
20170
21445
  domain: _mastra_core_error.ErrorDomain.STORAGE,
@@ -21060,6 +22335,7 @@ var ScorerDefinitionsPG = class ScorerDefinitionsPG extends _mastra_core_storage
21060
22335
  }
21061
22336
  async create(input) {
21062
22337
  const { scorerDefinition } = input;
22338
+ let draftInserted = false;
21063
22339
  try {
21064
22340
  const tableName = getTableName$5({
21065
22341
  indexName: _mastra_core_storage.TABLE_SCORER_DEFINITIONS,
@@ -21083,6 +22359,7 @@ var ScorerDefinitionsPG = class ScorerDefinitionsPG extends _mastra_core_storage
21083
22359
  nowIso,
21084
22360
  nowIso
21085
22361
  ]);
22362
+ draftInserted = true;
21086
22363
  const { id: _id, authorId: _authorId, organizationId: _organizationId, projectId: _projectId, metadata: _metadata, ...snapshotConfig } = scorerDefinition;
21087
22364
  const versionId = crypto.randomUUID();
21088
22365
  await this.createVersion({
@@ -21105,7 +22382,7 @@ var ScorerDefinitionsPG = class ScorerDefinitionsPG extends _mastra_core_storage
21105
22382
  updatedAt: now
21106
22383
  };
21107
22384
  } catch (error) {
21108
- try {
22385
+ if (draftInserted) try {
21109
22386
  const tableName = getTableName$5({
21110
22387
  indexName: _mastra_core_storage.TABLE_SCORER_DEFINITIONS,
21111
22388
  schemaName: getSchemaName$5(this.#schema)
@@ -22123,6 +23400,7 @@ var SkillsPG = class SkillsPG extends _mastra_core_storage.SkillsStorage {
22123
23400
  }
22124
23401
  async create(input) {
22125
23402
  const { skill } = input;
23403
+ let draftInserted = false;
22126
23404
  try {
22127
23405
  const tableName = getTableName$5({
22128
23406
  indexName: _mastra_core_storage.TABLE_SKILLS,
@@ -22146,6 +23424,7 @@ var SkillsPG = class SkillsPG extends _mastra_core_storage.SkillsStorage {
22146
23424
  nowIso,
22147
23425
  nowIso
22148
23426
  ]);
23427
+ draftInserted = true;
22149
23428
  const { id: _id, authorId: _authorId, visibility: _visibility, ...snapshotConfig } = skill;
22150
23429
  const versionId = crypto.randomUUID();
22151
23430
  await this.createVersion({
@@ -22167,7 +23446,7 @@ var SkillsPG = class SkillsPG extends _mastra_core_storage.SkillsStorage {
22167
23446
  updatedAt: now
22168
23447
  };
22169
23448
  } catch (error) {
22170
- try {
23449
+ if (draftInserted) try {
22171
23450
  const tableName = getTableName$5({
22172
23451
  indexName: _mastra_core_storage.TABLE_SKILLS,
22173
23452
  schemaName: getSchemaName$5(this.#schema)
@@ -23312,6 +24591,17 @@ function getTableName({ indexName, schemaName }) {
23312
24591
  const quotedIndexName = `"${indexName}"`;
23313
24592
  return schemaName ? `${schemaName}.${quotedIndexName}` : quotedIndexName;
23314
24593
  }
24594
+ const RUN_OWNER_COLUMNS = `generation, "ownerId", "leaseExpiresAt", ${DB_NOW_MS} AS "nowMs"`;
24595
+ function toRunOwnershipRecord(runId, row) {
24596
+ const leaseExpiresAt = row.leaseExpiresAt === null ? null : Number(row.leaseExpiresAt);
24597
+ return {
24598
+ runId,
24599
+ generation: Number(row.generation),
24600
+ ownerId: row.ownerId,
24601
+ leaseExpiresAt: leaseExpiresAt === null ? null : new Date(leaseExpiresAt),
24602
+ live: leaseExpiresAt !== null && leaseExpiresAt > Number(row.nowMs)
24603
+ };
24604
+ }
23315
24605
  /** Base name (before any schema prefix) of the expression index backing the status filter. */
23316
24606
  const WORKFLOW_SNAPSHOT_STATUS_INDEX = "mastra_workflow_snapshot_name_status_createdat_idx";
23317
24607
  /**
@@ -23396,12 +24686,24 @@ var WorkflowsPG = class WorkflowsPG extends _mastra_core_storage.WorkflowsStorag
23396
24686
  * Workflow run snapshots accumulate as runs execute. Anchored on the
23397
24687
  * timezone-aware `updatedAtZ` mirror column (last activity) so suspended or
23398
24688
  * long-running runs are not pruned by start age.
24689
+ *
24690
+ * Run ownership rows are anchored on `updatedAt` (epoch ms), which every
24691
+ * claim, renewal and release refreshes, so a live execution's row is never
24692
+ * older than its renew interval.
23399
24693
  */
23400
- static retentionTables = { workflowSnapshot: {
23401
- table: _mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT,
23402
- column: "updatedAtZ",
23403
- indexed: true
23404
- } };
24694
+ static retentionTables = {
24695
+ workflowSnapshot: {
24696
+ table: _mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT,
24697
+ column: "updatedAtZ",
24698
+ indexed: true
24699
+ },
24700
+ runOwnership: {
24701
+ table: _mastra_core_storage.TABLE_WORKFLOW_RUN_OWNERS,
24702
+ column: "updatedAt",
24703
+ indexed: true,
24704
+ anchorType: "epoch-ms"
24705
+ }
24706
+ };
23405
24707
  constructor(config) {
23406
24708
  super();
23407
24709
  const { client, readClient, schemaName, skipDefaultIndexes, indexes } = resolvePgConfig(config);
@@ -23458,6 +24760,12 @@ var WorkflowsPG = class WorkflowsPG extends _mastra_core_storage.WorkflowsStorag
23458
24760
  for (const idx of WorkflowsPG.getDefaultIndexDefs(schemaPrefix)) statements.push(generateIndexSQL(idx, schemaName));
23459
24761
  statements.push(`${workflowSnapshotStatusIndexSQL(workflowSnapshotStatusIndexName(parsedSchema), schemaName)};`);
23460
24762
  statements.push(`${workflowSnapshotThreadIdIndexSQL(workflowSnapshotThreadIdIndexName(parsedSchema), schemaName)};`);
24763
+ statements.push(generateTableSQL({
24764
+ tableName: _mastra_core_storage.TABLE_WORKFLOW_RUN_OWNERS,
24765
+ schema: _mastra_core_storage.RUN_FENCING_TABLE_SCHEMAS[_mastra_core_storage.TABLE_WORKFLOW_RUN_OWNERS],
24766
+ schemaName,
24767
+ includeAllConstraints: true
24768
+ }));
23461
24769
  return statements;
23462
24770
  }
23463
24771
  /**
@@ -23501,6 +24809,10 @@ var WorkflowsPG = class WorkflowsPG extends _mastra_core_storage.WorkflowsStorag
23501
24809
  schema: _mastra_core_storage.TABLE_SCHEMAS[_mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT],
23502
24810
  ifNotExists: ["resourceId"]
23503
24811
  });
24812
+ await this.#db.createTable({
24813
+ tableName: _mastra_core_storage.TABLE_WORKFLOW_RUN_OWNERS,
24814
+ schema: _mastra_core_storage.RUN_FENCING_TABLE_SCHEMAS[_mastra_core_storage.TABLE_WORKFLOW_RUN_OWNERS]
24815
+ });
23504
24816
  await this.createDefaultIndexes();
23505
24817
  await this.createCustomIndexes();
23506
24818
  }
@@ -23528,13 +24840,13 @@ var WorkflowsPG = class WorkflowsPG extends _mastra_core_storage.WorkflowsStorag
23528
24840
  }
23529
24841
  }
23530
24842
  }
23531
- /** Delete workflow run snapshots older than the `workflowSnapshot` policy's `maxAge`, batched. */
24843
+ /** Delete workflow run snapshots and run ownership rows older than their policy's `maxAge`, batched. */
23532
24844
  async prune(policies, options) {
23533
24845
  await this.ensureRetentionIndexes(policies);
23534
24846
  const targets = resolveTargets({
23535
24847
  policies,
23536
24848
  descriptor: WorkflowsPG.retentionTables,
23537
- order: ["workflowSnapshot"]
24849
+ order: ["workflowSnapshot", "runOwnership"]
23538
24850
  });
23539
24851
  return runPrune({
23540
24852
  db: this.#db,
@@ -23556,10 +24868,126 @@ var WorkflowsPG = class WorkflowsPG extends _mastra_core_storage.WorkflowsStorag
23556
24868
  }
23557
24869
  async dangerouslyClearAll() {
23558
24870
  await this.#db.clearTable({ tableName: _mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT });
24871
+ await this.#db.clearTable({ tableName: _mastra_core_storage.TABLE_WORKFLOW_RUN_OWNERS });
24872
+ }
24873
+ supportsRunFencing() {
24874
+ return true;
24875
+ }
24876
+ #runOwnersTable() {
24877
+ return getTableName({
24878
+ indexName: _mastra_core_storage.TABLE_WORKFLOW_RUN_OWNERS,
24879
+ schemaName: getSchemaName(this.#schema)
24880
+ });
24881
+ }
24882
+ async #readRunOwner(q, runId) {
24883
+ const row = await q.oneOrNone(`SELECT ${RUN_OWNER_COLUMNS} FROM ${this.#runOwnersTable()} WHERE "runId" = $1`, [runId]);
24884
+ return row ? toRunOwnershipRecord(runId, row) : null;
24885
+ }
24886
+ #ownershipError(operation, runId, error) {
24887
+ return new _mastra_core_error.MastraError({
24888
+ id: (0, _mastra_core_storage.createStorageErrorId)("PG", operation, "FAILED"),
24889
+ domain: _mastra_core_error.ErrorDomain.STORAGE,
24890
+ category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
24891
+ details: { runId }
24892
+ }, error);
24893
+ }
24894
+ async claimRunOwnership({ runId, ownerId, leaseMs, force, expectedGeneration }) {
24895
+ const table = this.#runOwnersTable();
24896
+ try {
24897
+ return await this.#db.client.tx(async (t) => {
24898
+ if (!await t.oneOrNone(`SELECT 1 FROM ${table} WHERE "runId" = $1 FOR UPDATE`, [runId])) {
24899
+ if (expectedGeneration !== void 0 && expectedGeneration !== 0) return {
24900
+ acquired: false,
24901
+ record: null
24902
+ };
24903
+ const inserted = await t.oneOrNone(`INSERT INTO ${table} ("runId", generation, "ownerId", "leaseExpiresAt", "updatedAt")
24904
+ VALUES ($1, GREATEST(1, ${DB_NOW_MS}), $2, ${DB_NOW_MS} + $3, ${DB_NOW_MS})
24905
+ ON CONFLICT ("runId") DO NOTHING
24906
+ RETURNING ${RUN_OWNER_COLUMNS}`, [
24907
+ runId,
24908
+ ownerId,
24909
+ leaseMs
24910
+ ]);
24911
+ if (inserted) return {
24912
+ acquired: true,
24913
+ record: toRunOwnershipRecord(runId, inserted)
24914
+ };
24915
+ }
24916
+ const claimed = await t.oneOrNone(`UPDATE ${table}
24917
+ SET generation = generation + 1, "ownerId" = $2, "leaseExpiresAt" = ${DB_NOW_MS} + $3,
24918
+ "updatedAt" = ${DB_NOW_MS}
24919
+ WHERE "runId" = $1
24920
+ AND ($4::bigint IS NULL OR generation = $4)
24921
+ AND ($5::boolean OR "leaseExpiresAt" IS NULL OR "leaseExpiresAt" <= ${DB_NOW_MS})
24922
+ RETURNING ${RUN_OWNER_COLUMNS}`, [
24923
+ runId,
24924
+ ownerId,
24925
+ leaseMs,
24926
+ expectedGeneration ?? null,
24927
+ force === true
24928
+ ]);
24929
+ if (claimed) return {
24930
+ acquired: true,
24931
+ record: toRunOwnershipRecord(runId, claimed)
24932
+ };
24933
+ return {
24934
+ acquired: false,
24935
+ record: await this.#readRunOwner(t, runId)
24936
+ };
24937
+ });
24938
+ } catch (error) {
24939
+ throw this.#ownershipError("CLAIM_RUN_OWNERSHIP", runId, error);
24940
+ }
24941
+ }
24942
+ async renewRunOwnership({ leaseMs, ...fence }) {
24943
+ try {
24944
+ const renewed = await this.#db.client.oneOrNone(`UPDATE ${this.#runOwnersTable()}
24945
+ SET "leaseExpiresAt" = ${DB_NOW_MS} + $4, "updatedAt" = ${DB_NOW_MS}
24946
+ WHERE "runId" = $1 AND generation = $2 AND "ownerId" = $3 AND "leaseExpiresAt" IS NOT NULL
24947
+ RETURNING ${RUN_OWNER_COLUMNS}`, [
24948
+ fence.runId,
24949
+ fence.generation,
24950
+ fence.ownerId,
24951
+ leaseMs
24952
+ ]);
24953
+ if (renewed) return {
24954
+ renewed: true,
24955
+ record: toRunOwnershipRecord(fence.runId, renewed)
24956
+ };
24957
+ return {
24958
+ renewed: false,
24959
+ record: await this.#readRunOwner(this.#db.client, fence.runId)
24960
+ };
24961
+ } catch (error) {
24962
+ throw this.#ownershipError("RENEW_RUN_OWNERSHIP", fence.runId, error);
24963
+ }
24964
+ }
24965
+ async releaseRunOwnership(fence) {
24966
+ try {
24967
+ return await this.#db.client.oneOrNone(`UPDATE ${this.#runOwnersTable()}
24968
+ SET "leaseExpiresAt" = NULL, "updatedAt" = ${DB_NOW_MS}
24969
+ WHERE "runId" = $1 AND generation = $2 AND "ownerId" = $3
24970
+ RETURNING "runId"`, [
24971
+ fence.runId,
24972
+ fence.generation,
24973
+ fence.ownerId
24974
+ ]) !== null;
24975
+ } catch (error) {
24976
+ throw this.#ownershipError("RELEASE_RUN_OWNERSHIP", fence.runId, error);
24977
+ }
24978
+ }
24979
+ async getRunOwnership({ runId }) {
24980
+ try {
24981
+ return await this.#readRunOwner(this.#db.client, runId);
24982
+ } catch (error) {
24983
+ throw this.#ownershipError("GET_RUN_OWNERSHIP", runId, error);
24984
+ }
23559
24985
  }
23560
- async updateWorkflowResults({ workflowName, runId, stepId, result, requestContext, state }) {
24986
+ async updateWorkflowResults({ workflowName, runId, stepId, result, requestContext, state, fence: explicitFence }) {
24987
+ const fence = (0, _mastra_core_storage.resolveRunFence)(this, explicitFence, runId);
23561
24988
  try {
23562
24989
  return await this.#db.client.tx(async (t) => {
24990
+ if (fence) await assertRunFence(t, this.#runOwnersTable(), fence, "updateWorkflowResults");
23563
24991
  const tableName = getTableName({
23564
24992
  indexName: _mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT,
23565
24993
  schemaName: getSchemaName(this.#schema)
@@ -23609,6 +25037,7 @@ var WorkflowsPG = class WorkflowsPG extends _mastra_core_storage.WorkflowsStorag
23609
25037
  return snapshot.context;
23610
25038
  });
23611
25039
  } catch (error) {
25040
+ if ((0, _mastra_core_storage.isRunFenceConflictError)(error)) throw error;
23612
25041
  throw new _mastra_core_error.MastraError({
23613
25042
  id: (0, _mastra_core_storage.createStorageErrorId)("PG", "UPDATE_WORKFLOW_RESULTS", "FAILED"),
23614
25043
  domain: _mastra_core_error.ErrorDomain.STORAGE,
@@ -23621,9 +25050,11 @@ var WorkflowsPG = class WorkflowsPG extends _mastra_core_storage.WorkflowsStorag
23621
25050
  }, error);
23622
25051
  }
23623
25052
  }
23624
- async updateWorkflowState({ workflowName, runId, opts }) {
25053
+ async updateWorkflowState({ workflowName, runId, opts, fence: explicitFence }) {
25054
+ const fence = (0, _mastra_core_storage.resolveRunFence)(this, explicitFence, runId);
23625
25055
  try {
23626
25056
  return await this.#db.client.tx(async (t) => {
25057
+ if (fence) await assertRunFence(t, this.#runOwnersTable(), fence, "updateWorkflowState");
23627
25058
  const tableName = getTableName({
23628
25059
  indexName: _mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT,
23629
25060
  schemaName: getSchemaName(this.#schema)
@@ -23653,6 +25084,7 @@ var WorkflowsPG = class WorkflowsPG extends _mastra_core_storage.WorkflowsStorag
23653
25084
  return updatedSnapshot;
23654
25085
  });
23655
25086
  } catch (error) {
25087
+ if ((0, _mastra_core_storage.isRunFenceConflictError)(error)) throw error;
23656
25088
  throw new _mastra_core_error.MastraError({
23657
25089
  id: (0, _mastra_core_storage.createStorageErrorId)("PG", "UPDATE_WORKFLOW_STATE", "FAILED"),
23658
25090
  domain: _mastra_core_error.ErrorDomain.STORAGE,
@@ -23664,13 +25096,13 @@ var WorkflowsPG = class WorkflowsPG extends _mastra_core_storage.WorkflowsStorag
23664
25096
  }, error);
23665
25097
  }
23666
25098
  }
23667
- async persistWorkflowSnapshot({ workflowName, runId, resourceId, snapshot, createdAt, updatedAt }) {
25099
+ async persistWorkflowSnapshot({ workflowName, runId, resourceId, snapshot, createdAt, updatedAt, fence }) {
23668
25100
  try {
23669
25101
  const now = /* @__PURE__ */ new Date();
23670
25102
  const createdAtValue = createdAt ? createdAt : now;
23671
25103
  const updatedAtValue = updatedAt ? updatedAt : now;
23672
25104
  const sanitizedSnapshot = toPgJson(snapshot);
23673
- await this.#db.client.none(`INSERT INTO ${getTableName({
25105
+ await withRunFence(this.#db.client, this.#runOwnersTable(), (0, _mastra_core_storage.resolveRunFence)(this, fence, runId), "persistWorkflowSnapshot", (q) => q.none(`INSERT INTO ${getTableName({
23674
25106
  indexName: _mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT,
23675
25107
  schemaName: getSchemaName(this.#schema)
23676
25108
  })} AS t
@@ -23686,8 +25118,9 @@ var WorkflowsPG = class WorkflowsPG extends _mastra_core_storage.WorkflowsStorag
23686
25118
  updatedAtValue,
23687
25119
  createdAtValue,
23688
25120
  updatedAtValue
23689
- ]);
25121
+ ]));
23690
25122
  } catch (error) {
25123
+ if ((0, _mastra_core_storage.isRunFenceConflictError)(error)) throw error;
23691
25124
  throw new _mastra_core_error.MastraError({
23692
25125
  id: (0, _mastra_core_storage.createStorageErrorId)("PG", "PERSIST_WORKFLOW_SNAPSHOT", "FAILED"),
23693
25126
  domain: _mastra_core_error.ErrorDomain.STORAGE,
@@ -23753,13 +25186,14 @@ var WorkflowsPG = class WorkflowsPG extends _mastra_core_storage.WorkflowsStorag
23753
25186
  }, error);
23754
25187
  }
23755
25188
  }
23756
- async deleteWorkflowRunById({ runId, workflowName }) {
25189
+ async deleteWorkflowRunById({ runId, workflowName, fence }) {
23757
25190
  try {
23758
- await this.#db.client.none(`DELETE FROM ${getTableName({
25191
+ await withRunFence(this.#db.client, this.#runOwnersTable(), (0, _mastra_core_storage.resolveRunFence)(this, fence, runId), "deleteWorkflowRunById", (q) => q.none(`DELETE FROM ${getTableName({
23759
25192
  indexName: _mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT,
23760
25193
  schemaName: getSchemaName(this.#schema)
23761
- })} WHERE run_id = $1 AND workflow_name = $2`, [runId, workflowName]);
25194
+ })} WHERE run_id = $1 AND workflow_name = $2`, [runId, workflowName]));
23762
25195
  } catch (error) {
25196
+ if ((0, _mastra_core_storage.isRunFenceConflictError)(error)) throw error;
23763
25197
  throw new _mastra_core_error.MastraError({
23764
25198
  id: (0, _mastra_core_storage.createStorageErrorId)("PG", "DELETE_WORKFLOW_RUN_BY_ID", "FAILED"),
23765
25199
  domain: _mastra_core_error.ErrorDomain.STORAGE,
@@ -23971,6 +25405,7 @@ var WorkspacesPG = class WorkspacesPG extends _mastra_core_storage.WorkspacesSto
23971
25405
  }
23972
25406
  async create(input) {
23973
25407
  const { workspace } = input;
25408
+ let draftInserted = false;
23974
25409
  try {
23975
25410
  const tableName = getTableName$5({
23976
25411
  indexName: _mastra_core_storage.TABLE_WORKSPACES,
@@ -23992,6 +25427,7 @@ var WorkspacesPG = class WorkspacesPG extends _mastra_core_storage.WorkspacesSto
23992
25427
  nowIso,
23993
25428
  nowIso
23994
25429
  ]);
25430
+ draftInserted = true;
23995
25431
  const { id: _id, authorId: _authorId, metadata: _metadata, ...snapshotConfig } = workspace;
23996
25432
  const versionId = crypto.randomUUID();
23997
25433
  await this.createVersion({
@@ -24012,7 +25448,7 @@ var WorkspacesPG = class WorkspacesPG extends _mastra_core_storage.WorkspacesSto
24012
25448
  updatedAt: now
24013
25449
  };
24014
25450
  } catch (error) {
24015
- try {
25451
+ if (draftInserted) try {
24016
25452
  const tableName = getTableName$5({
24017
25453
  indexName: _mastra_core_storage.TABLE_WORKSPACES,
24018
25454
  schemaName: getSchemaName$5(this.#schema)
@@ -25062,7 +26498,10 @@ var PostgresStore = class extends _mastra_core_storage.MastraCompositeStore {
25062
26498
  workflows: new WorkflowsPG(domainConfig),
25063
26499
  workflowDefinitions: new WorkflowDefinitionsPG(domainConfig),
25064
26500
  memory: new MemoryPG(domainConfig),
25065
- knowledge: new KnowledgePG(domainConfig),
26501
+ knowledge: new KnowledgePG({
26502
+ ...domainConfig,
26503
+ storageIsolationKey: config.storageIsolationKey ?? getPgKnowledgeIsolationKey(config)
26504
+ }),
25066
26505
  notifications: new NotificationsPG(domainConfig),
25067
26506
  observability: new ObservabilityPG(domainConfig),
25068
26507
  agents: new AgentsPG(domainConfig),
@@ -25116,7 +26555,7 @@ var PostgresStore = class extends _mastra_core_storage.MastraCompositeStore {
25116
26555
  const pinned = new PinnedClientAdapter(this.#writePool, pinnedClient);
25117
26556
  this.#db.pin(pinned);
25118
26557
  this.#db.setSchemaSnapshot(await loadSchemaSnapshot(pinned, this.schema));
25119
- await super.init();
26558
+ await Promise.all(Object.entries(this.stores).filter(([name, store]) => name !== "knowledge" && store).map(([, store]) => store.init()));
25120
26559
  this.isInitialized = true;
25121
26560
  } catch (error) {
25122
26561
  this.#initPromise = null;