@mastra/pg 1.31.0-alpha.1 → 1.31.0-alpha.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/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");
@@ -2499,7 +2499,8 @@ async function loadSchemaSnapshot(client, schemaName) {
2499
2499
  const schema = schemaName || "public";
2500
2500
  const [tableRows, columnRows, indexRows] = await Promise.all([
2501
2501
  client.manyOrNone(`SELECT tablename FROM pg_catalog.pg_tables WHERE schemaname = $1`, [schema]),
2502
- client.manyOrNone(`SELECT c.relname AS table_name, a.attname AS column_name, format_type(a.atttypid, a.atttypmod) AS data_type
2502
+ client.manyOrNone(`SELECT c.relname AS table_name, a.attname AS column_name, format_type(a.atttypid, a.atttypmod) AS data_type,
2503
+ a.attnotnull AS not_null
2503
2504
  FROM pg_catalog.pg_class c
2504
2505
  JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
2505
2506
  JOIN pg_catalog.pg_attribute a ON a.attrelid = c.oid
@@ -2515,6 +2516,7 @@ async function loadSchemaSnapshot(client, schemaName) {
2515
2516
  ]);
2516
2517
  const columns = /* @__PURE__ */ new Map();
2517
2518
  const columnTypes = /* @__PURE__ */ new Map();
2519
+ const notNullColumns = /* @__PURE__ */ new Map();
2518
2520
  for (const row of columnRows) {
2519
2521
  let set = columns.get(row.table_name);
2520
2522
  if (!set) {
@@ -2528,6 +2530,14 @@ async function loadSchemaSnapshot(client, schemaName) {
2528
2530
  columnTypes.set(row.table_name, types);
2529
2531
  }
2530
2532
  types.set(row.column_name, row.data_type);
2533
+ if (row.not_null) {
2534
+ let notNull = notNullColumns.get(row.table_name);
2535
+ if (!notNull) {
2536
+ notNull = /* @__PURE__ */ new Set();
2537
+ notNullColumns.set(row.table_name, notNull);
2538
+ }
2539
+ notNull.add(row.column_name);
2540
+ }
2531
2541
  }
2532
2542
  const indexes = /* @__PURE__ */ new Set();
2533
2543
  const replicaIdentityIndexes = /* @__PURE__ */ new Set();
@@ -2544,6 +2554,7 @@ async function loadSchemaSnapshot(client, schemaName) {
2544
2554
  tables: new Set(tableRows.map((r) => r.tablename)),
2545
2555
  columns,
2546
2556
  columnTypes,
2557
+ notNullColumns,
2547
2558
  indexes,
2548
2559
  replicaIdentityIndexes,
2549
2560
  primaryKeyIndexes,
@@ -3622,6 +3633,33 @@ MIGRATION REQUIRED: Duplicate spans detected in ${duplicateInfo.tableName}\n====
3622
3633
  this.columnTypeCache.delete(tableName);
3623
3634
  }
3624
3635
  }
3636
+ /**
3637
+ * Drops NOT NULL from `columns` on `tableName` where it is still set. Answered
3638
+ * from the init snapshot when one is installed, so a converged schema issues
3639
+ * no query and never takes the ACCESS EXCLUSIVE lock.
3640
+ */
3641
+ async dropNotNull({ tableName, columns }) {
3642
+ const parsedColumns = columns.map((c) => (0, _mastra_core_utils.parseSqlIdentifier)(c, "column name"));
3643
+ const snapshot = this.schemaSnapshot;
3644
+ let toAlter;
3645
+ if (snapshot) {
3646
+ const notNull = snapshot.notNullColumns.get(tableName);
3647
+ toAlter = parsedColumns.filter((c) => notNull?.has(c));
3648
+ } else toAlter = (await this.client.any(`SELECT column_name FROM information_schema.columns
3649
+ WHERE table_schema = $1 AND table_name = $2 AND column_name = ANY($3) AND is_nullable = 'NO'`, [
3650
+ this.schemaName || "public",
3651
+ tableName,
3652
+ parsedColumns
3653
+ ])).map((r) => r.column_name);
3654
+ if (toAlter.length === 0) return;
3655
+ const fullTableName = getTableName$6({
3656
+ indexName: tableName,
3657
+ schemaName: getSchemaName$6(this.schemaName)
3658
+ });
3659
+ await this.client.none(`ALTER TABLE ${fullTableName} ${toAlter.map((c) => `ALTER COLUMN "${c}" DROP NOT NULL`).join(", ")}`);
3660
+ const notNull = snapshot?.notNullColumns.get(tableName);
3661
+ for (const c of toAlter) notNull?.delete(c);
3662
+ }
3625
3663
  async load({ tableName, keys }) {
3626
3664
  try {
3627
3665
  const keyEntries = Object.entries(keys).map(([key, value]) => [(0, _mastra_core_utils.parseSqlIdentifier)(key, "column name"), value]);
@@ -7112,6 +7150,10 @@ var ExperimentsPG = class ExperimentsPG extends _mastra_core_storage.Experiments
7112
7150
  "scorerIds"
7113
7151
  ]
7114
7152
  });
7153
+ await this.#db.dropNotNull({
7154
+ tableName: _mastra_core_storage.TABLE_EXPERIMENTS,
7155
+ columns: ["targetType", "targetId"]
7156
+ });
7115
7157
  await this.#db.alterTable({
7116
7158
  tableName: _mastra_core_storage.TABLE_EXPERIMENT_RESULTS,
7117
7159
  schema: _mastra_core_storage.EXPERIMENT_RESULTS_SCHEMA,
@@ -8259,18 +8301,650 @@ var FavoritesPG = class FavoritesPG extends _mastra_core_storage.FavoritesStorag
8259
8301
  }
8260
8302
  };
8261
8303
  //#endregion
8304
+ //#region ../../packages/_internal-core/dist/knowledge-compat/index.js
8305
+ const KNOWLEDGE_V2_CORE_FEATURE = "knowledge-v2";
8306
+ /** Hard cap on scope nodes returned by one `listScopeNodes` read. */
8307
+ const MAX_KNOWLEDGE_SCOPE_NODES = 1e3;
8308
+ function knowledgeScopeNodeFilterKey(input) {
8309
+ return JSON.stringify([
8310
+ input.withinAddress ?? null,
8311
+ input.addresses ? [...input.addresses].sort() : null,
8312
+ input.ids ? [...input.ids].sort() : null
8313
+ ]);
8314
+ }
8315
+ function createKnowledgeScopeNodeCursor(scope, input) {
8316
+ return encodeURIComponent(JSON.stringify({
8317
+ version: 1,
8318
+ type: "scope",
8319
+ name: scope.name,
8320
+ id: scope.id,
8321
+ filter: knowledgeScopeNodeFilterKey(input)
8322
+ }));
8323
+ }
8324
+ /** Validates the page size and cursor of a `listScopeNodes` query; throws on a cursor from a different query. */
8325
+ function parseListKnowledgeScopeNodesInput(input = {}) {
8326
+ const requested = Number.isFinite(input.limit) ? Math.trunc(input.limit) : MAX_KNOWLEDGE_SCOPE_NODES;
8327
+ const limit = Math.min(Math.max(requested, 1), MAX_KNOWLEDGE_SCOPE_NODES);
8328
+ if (!input.cursor) return {
8329
+ limit,
8330
+ after: null
8331
+ };
8332
+ let value;
8333
+ try {
8334
+ value = JSON.parse(decodeURIComponent(input.cursor));
8335
+ } catch {
8336
+ throw new Error("Invalid Knowledge scope node cursor.");
8337
+ }
8338
+ const parsed = value && typeof value === "object" ? value : {};
8339
+ 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.");
8340
+ return {
8341
+ limit,
8342
+ after: {
8343
+ name: parsed.name,
8344
+ id: parsed.id
8345
+ }
8346
+ };
8347
+ }
8348
+ /** Builds a page from up to `limit + 1` name/id-ordered scope nodes. */
8349
+ function pageKnowledgeScopeNodes(rows, limit, input) {
8350
+ const scopes = rows.slice(0, limit);
8351
+ const last = scopes.at(-1);
8352
+ return {
8353
+ scopes,
8354
+ nextCursor: rows.length > limit && last ? createKnowledgeScopeNodeCursor(last, input) : null
8355
+ };
8356
+ }
8357
+ /** Clamps a requested member limit to 1–{@link MAX_KNOWLEDGE_SCOPE_MEMBERS_LIMIT}. */
8358
+ function knowledgeScopeMembersLimit(limit) {
8359
+ if (limit === void 0 || !Number.isFinite(limit)) return 500;
8360
+ return Math.min(Math.max(Math.trunc(limit), 1), 500);
8361
+ }
8362
+ /** Validates the page size and cursor of a `listScopeMembers` query; throws on a cursor from another scope. */
8363
+ function parseListKnowledgeScopeMembersInput(input) {
8364
+ const limit = knowledgeScopeMembersLimit(input.limit);
8365
+ if (!input.cursor) return {
8366
+ limit,
8367
+ after: null
8368
+ };
8369
+ let value;
8370
+ try {
8371
+ value = JSON.parse(decodeURIComponent(input.cursor));
8372
+ } catch {
8373
+ throw new Error("Invalid Knowledge scope member cursor.");
8374
+ }
8375
+ const parsed = value && typeof value === "object" ? value : {};
8376
+ const updatedAt = typeof parsed.updatedAt === "string" ? new Date(parsed.updatedAt) : /* @__PURE__ */ new Date(NaN);
8377
+ 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.");
8378
+ return {
8379
+ limit,
8380
+ after: {
8381
+ updatedAt,
8382
+ name: parsed.name,
8383
+ id: parsed.id
8384
+ }
8385
+ };
8386
+ }
8387
+ /** Builds a page from up to `limit + 1` members in `listScopeMembers` order. */
8388
+ function pageKnowledgeScopeMembers(rows, limit, input) {
8389
+ const members = rows.slice(0, limit);
8390
+ const last = members.at(-1);
8391
+ const hasMore = rows.length > limit;
8392
+ return {
8393
+ members,
8394
+ hasMore,
8395
+ nextCursor: hasMore && last ? encodeURIComponent(JSON.stringify({
8396
+ version: 1,
8397
+ type: "scope-member",
8398
+ scopeNodeId: input.scopeNodeId,
8399
+ updatedAt: last.updatedAt.toISOString(),
8400
+ name: last.name,
8401
+ id: last.id
8402
+ })) : null
8403
+ };
8404
+ }
8405
+ const TABLE_KNOWLEDGE_NODES$1 = "mastra_knowledge_nodes";
8406
+ const TABLE_KNOWLEDGE_RECORDS$1 = "mastra_knowledge_records";
8407
+ const TABLE_KNOWLEDGE_MENTIONS$1 = "mastra_knowledge_mentions";
8408
+ const TABLE_KNOWLEDGE_ACTIVITY$1 = "mastra_knowledge_activity";
8409
+ const TABLE_KNOWLEDGE_SEMANTIC_OUTBOX$1 = "mastra_knowledge_semantic_outbox";
8410
+ const TABLE_KNOWLEDGE_NODE_SCOPES = "mastra_knowledge_node_scopes";
8411
+ const TABLE_KNOWLEDGE_RECORD_SCOPES = "mastra_knowledge_record_scopes";
8412
+ const TABLE_KNOWLEDGE_SCOPE_GRANTS = "mastra_knowledge_scope_grants";
8413
+ const TABLE_KNOWLEDGE_ACCESS_STATE = "mastra_knowledge_access_state";
8414
+ const TABLE_KNOWLEDGE_SCOPE_ADDRESSES = "mastra_knowledge_scope_addresses";
8415
+ const TABLE_KNOWLEDGE_NODE_ADDRESSES = "mastra_knowledge_node_addresses";
8416
+ const TABLE_KNOWLEDGE_IMPORT_STATE = "mastra_knowledge_import_state";
8417
+ const TABLE_KNOWLEDGE_IMPORT_RUNS = "mastra_knowledge_import_runs";
8418
+ const TABLE_KNOWLEDGE_PROPOSALS = "mastra_knowledge_proposals";
8419
+ const KNOWLEDGE_TABLE_NAMES = [
8420
+ TABLE_KNOWLEDGE_NODES$1,
8421
+ TABLE_KNOWLEDGE_RECORDS$1,
8422
+ TABLE_KNOWLEDGE_MENTIONS$1,
8423
+ TABLE_KNOWLEDGE_ACTIVITY$1,
8424
+ TABLE_KNOWLEDGE_SEMANTIC_OUTBOX$1,
8425
+ TABLE_KNOWLEDGE_NODE_SCOPES,
8426
+ TABLE_KNOWLEDGE_RECORD_SCOPES,
8427
+ TABLE_KNOWLEDGE_SCOPE_GRANTS,
8428
+ TABLE_KNOWLEDGE_ACCESS_STATE,
8429
+ TABLE_KNOWLEDGE_SCOPE_ADDRESSES,
8430
+ TABLE_KNOWLEDGE_NODE_ADDRESSES,
8431
+ TABLE_KNOWLEDGE_IMPORT_STATE,
8432
+ TABLE_KNOWLEDGE_IMPORT_RUNS,
8433
+ TABLE_KNOWLEDGE_PROPOSALS
8434
+ ];
8435
+ /** Knowledge v1 tables with no v2 equivalent; an explicit schema reset drops them. */
8436
+ const RETIRED_KNOWLEDGE_TABLE_NAMES = ["mastra_knowledge_cursors"];
8437
+ /** Tables and indexes published v1 adapters created for every app, whether or not it used Knowledge. */
8438
+ const PUBLISHED_KNOWLEDGE_V1_TABLE_NAMES = /* @__PURE__ */ new Set([
8439
+ TABLE_KNOWLEDGE_NODES$1,
8440
+ TABLE_KNOWLEDGE_RECORDS$1,
8441
+ TABLE_KNOWLEDGE_MENTIONS$1,
8442
+ TABLE_KNOWLEDGE_ACTIVITY$1,
8443
+ TABLE_KNOWLEDGE_SEMANTIC_OUTBOX$1,
8444
+ ...RETIRED_KNOWLEDGE_TABLE_NAMES
8445
+ ]);
8446
+ const PUBLISHED_KNOWLEDGE_V1_INDEX_NAMES = /* @__PURE__ */ new Set([
8447
+ "idx_knowledge_nodes_identity",
8448
+ "idx_knowledge_nodes_scope",
8449
+ "idx_knowledge_records_node_latest",
8450
+ "idx_knowledge_records_thread_latest",
8451
+ "idx_knowledge_mentions_record",
8452
+ "idx_knowledge_activity_latest",
8453
+ "idx_knowledge_outbox_idempotency",
8454
+ "idx_knowledge_outbox_claim"
8455
+ ]);
8456
+ const KNOWLEDGE_V2_NODES_SCHEMA = {
8457
+ id: {
8458
+ type: "text",
8459
+ nullable: false,
8460
+ primaryKey: true
8461
+ },
8462
+ name: {
8463
+ type: "text",
8464
+ nullable: false
8465
+ },
8466
+ kind: {
8467
+ type: "text",
8468
+ nullable: true
8469
+ },
8470
+ isScope: {
8471
+ type: "boolean",
8472
+ nullable: false
8473
+ },
8474
+ metadata: {
8475
+ type: "jsonb",
8476
+ nullable: true
8477
+ },
8478
+ version: {
8479
+ type: "integer",
8480
+ nullable: false
8481
+ },
8482
+ createdAt: {
8483
+ type: "timestamp",
8484
+ nullable: false
8485
+ },
8486
+ updatedAt: {
8487
+ type: "timestamp",
8488
+ nullable: false
8489
+ },
8490
+ deletedAt: {
8491
+ type: "timestamp",
8492
+ nullable: true
8493
+ },
8494
+ deletedBy: {
8495
+ type: "text",
8496
+ nullable: true
8497
+ },
8498
+ type: {
8499
+ type: "text",
8500
+ nullable: true
8501
+ },
8502
+ canonicalName: {
8503
+ type: "text",
8504
+ nullable: true
8505
+ },
8506
+ content: {
8507
+ type: "text",
8508
+ nullable: true
8509
+ },
8510
+ description: {
8511
+ type: "text",
8512
+ nullable: true
8513
+ },
8514
+ scope: {
8515
+ type: "jsonb",
8516
+ nullable: true
8517
+ },
8518
+ scopeKey: {
8519
+ type: "text",
8520
+ nullable: true
8521
+ },
8522
+ mergedInto: {
8523
+ type: "text",
8524
+ nullable: true
8525
+ }
8526
+ };
8527
+ const KNOWLEDGE_V2_RECORDS_SCHEMA = {
8528
+ id: {
8529
+ type: "text",
8530
+ nullable: false,
8531
+ primaryKey: true
8532
+ },
8533
+ node: {
8534
+ type: "text",
8535
+ nullable: false,
8536
+ references: {
8537
+ table: TABLE_KNOWLEDGE_NODES$1,
8538
+ column: "id"
8539
+ }
8540
+ },
8541
+ text: {
8542
+ type: "text",
8543
+ nullable: false
8544
+ },
8545
+ metadata: {
8546
+ type: "jsonb",
8547
+ nullable: true
8548
+ },
8549
+ version: {
8550
+ type: "integer",
8551
+ nullable: false
8552
+ },
8553
+ capturedAt: {
8554
+ type: "timestamp",
8555
+ nullable: false
8556
+ },
8557
+ updatedAt: {
8558
+ type: "timestamp",
8559
+ nullable: false
8560
+ },
8561
+ deletedAt: {
8562
+ type: "timestamp",
8563
+ nullable: true
8564
+ },
8565
+ deletedBy: {
8566
+ type: "text",
8567
+ nullable: true
8568
+ },
8569
+ scope: {
8570
+ type: "jsonb",
8571
+ nullable: true
8572
+ },
8573
+ scopeKey: {
8574
+ type: "text",
8575
+ nullable: true
8576
+ },
8577
+ sourceThreadId: {
8578
+ type: "text",
8579
+ nullable: true
8580
+ },
8581
+ when: {
8582
+ type: "timestamp",
8583
+ nullable: true
8584
+ }
8585
+ };
8586
+ const KNOWLEDGE_V2_MENTIONS_SCHEMA = {
8587
+ recordId: {
8588
+ type: "text",
8589
+ nullable: false,
8590
+ references: {
8591
+ table: TABLE_KNOWLEDGE_RECORDS$1,
8592
+ column: "id"
8593
+ }
8594
+ },
8595
+ targetNodeId: {
8596
+ type: "text",
8597
+ nullable: true,
8598
+ references: {
8599
+ table: TABLE_KNOWLEDGE_NODES$1,
8600
+ column: "id"
8601
+ }
8602
+ },
8603
+ sourceType: {
8604
+ type: "text",
8605
+ nullable: true
8606
+ },
8607
+ sourceId: {
8608
+ type: "text",
8609
+ nullable: true
8610
+ }
8611
+ };
8612
+ const KNOWLEDGE_NODE_SCOPES_SCHEMA = {
8613
+ nodeId: {
8614
+ type: "text",
8615
+ nullable: false,
8616
+ references: {
8617
+ table: TABLE_KNOWLEDGE_NODES$1,
8618
+ column: "id"
8619
+ }
8620
+ },
8621
+ scopeNodeId: {
8622
+ type: "text",
8623
+ nullable: false,
8624
+ references: {
8625
+ table: TABLE_KNOWLEDGE_NODES$1,
8626
+ column: "id"
8627
+ }
8628
+ },
8629
+ addedAt: {
8630
+ type: "timestamp",
8631
+ nullable: false
8632
+ }
8633
+ };
8634
+ const KNOWLEDGE_RECORD_SCOPES_SCHEMA = {
8635
+ recordId: {
8636
+ type: "text",
8637
+ nullable: false,
8638
+ references: {
8639
+ table: TABLE_KNOWLEDGE_RECORDS$1,
8640
+ column: "id"
8641
+ }
8642
+ },
8643
+ scopeNodeId: {
8644
+ type: "text",
8645
+ nullable: false,
8646
+ references: {
8647
+ table: TABLE_KNOWLEDGE_NODES$1,
8648
+ column: "id"
8649
+ }
8650
+ },
8651
+ addedAt: {
8652
+ type: "timestamp",
8653
+ nullable: false
8654
+ }
8655
+ };
8656
+ const KNOWLEDGE_SCOPE_GRANTS_SCHEMA = {
8657
+ scopeNodeId: {
8658
+ type: "text",
8659
+ nullable: false,
8660
+ references: {
8661
+ table: TABLE_KNOWLEDGE_NODES$1,
8662
+ column: "id"
8663
+ }
8664
+ },
8665
+ scopeRefId: {
8666
+ type: "text",
8667
+ nullable: false,
8668
+ references: {
8669
+ table: TABLE_KNOWLEDGE_NODES$1,
8670
+ column: "id"
8671
+ }
8672
+ },
8673
+ role: {
8674
+ type: "text",
8675
+ nullable: false
8676
+ },
8677
+ canSuggest: {
8678
+ type: "boolean",
8679
+ nullable: true
8680
+ }
8681
+ };
8682
+ const KNOWLEDGE_ACCESS_STATE_SCHEMA = {
8683
+ id: {
8684
+ type: "text",
8685
+ nullable: false,
8686
+ primaryKey: true
8687
+ },
8688
+ epoch: {
8689
+ type: "integer",
8690
+ nullable: false
8691
+ },
8692
+ schemaVersion: {
8693
+ type: "integer",
8694
+ nullable: false
8695
+ }
8696
+ };
8697
+ const KNOWLEDGE_SCOPE_ADDRESSES_SCHEMA = {
8698
+ address: {
8699
+ type: "text",
8700
+ nullable: false,
8701
+ primaryKey: true
8702
+ },
8703
+ scopeNodeId: {
8704
+ type: "text",
8705
+ nullable: false,
8706
+ references: {
8707
+ table: TABLE_KNOWLEDGE_NODES$1,
8708
+ column: "id"
8709
+ }
8710
+ }
8711
+ };
8712
+ const KNOWLEDGE_NODE_ADDRESSES_SCHEMA = {
8713
+ source: {
8714
+ type: "text",
8715
+ nullable: false
8716
+ },
8717
+ address: {
8718
+ type: "text",
8719
+ nullable: false
8720
+ },
8721
+ nodeId: {
8722
+ type: "text",
8723
+ nullable: false,
8724
+ references: {
8725
+ table: TABLE_KNOWLEDGE_NODES$1,
8726
+ column: "id"
8727
+ }
8728
+ }
8729
+ };
8730
+ const KNOWLEDGE_IMPORT_STATE_SCHEMA = {
8731
+ importerId: {
8732
+ type: "text",
8733
+ nullable: false
8734
+ },
8735
+ binding: {
8736
+ type: "text",
8737
+ nullable: false
8738
+ },
8739
+ key: {
8740
+ type: "text",
8741
+ nullable: false
8742
+ },
8743
+ value: {
8744
+ type: "text",
8745
+ nullable: false
8746
+ }
8747
+ };
8748
+ const KNOWLEDGE_IMPORT_RUNS_SCHEMA = {
8749
+ id: {
8750
+ type: "text",
8751
+ nullable: false,
8752
+ primaryKey: true
8753
+ },
8754
+ importerId: {
8755
+ type: "text",
8756
+ nullable: false
8757
+ },
8758
+ binding: {
8759
+ type: "text",
8760
+ nullable: false
8761
+ },
8762
+ importKind: {
8763
+ type: "text",
8764
+ nullable: false
8765
+ },
8766
+ triggerKind: {
8767
+ type: "text",
8768
+ nullable: false
8769
+ },
8770
+ status: {
8771
+ type: "text",
8772
+ nullable: false
8773
+ },
8774
+ error: {
8775
+ type: "text",
8776
+ nullable: true
8777
+ },
8778
+ transcriptThreadId: {
8779
+ type: "text",
8780
+ nullable: true
8781
+ },
8782
+ traceId: {
8783
+ type: "text",
8784
+ nullable: true
8785
+ },
8786
+ queuedAt: {
8787
+ type: "timestamp",
8788
+ nullable: false
8789
+ },
8790
+ startedAt: {
8791
+ type: "timestamp",
8792
+ nullable: true
8793
+ },
8794
+ completedAt: {
8795
+ type: "timestamp",
8796
+ nullable: true
8797
+ }
8798
+ };
8799
+ const KNOWLEDGE_V2_ACTIVITY_SCHEMA = {
8800
+ id: {
8801
+ type: "text",
8802
+ nullable: false,
8803
+ primaryKey: true
8804
+ },
8805
+ action: {
8806
+ type: "text",
8807
+ nullable: false
8808
+ },
8809
+ targetType: {
8810
+ type: "text",
8811
+ nullable: true
8812
+ },
8813
+ targetId: {
8814
+ type: "text",
8815
+ nullable: true
8816
+ },
8817
+ contextScopeId: {
8818
+ type: "text",
8819
+ nullable: true,
8820
+ references: {
8821
+ table: TABLE_KNOWLEDGE_NODES$1,
8822
+ column: "id"
8823
+ }
8824
+ },
8825
+ importRunId: {
8826
+ type: "text",
8827
+ nullable: true,
8828
+ references: {
8829
+ table: TABLE_KNOWLEDGE_IMPORT_RUNS,
8830
+ column: "id"
8831
+ }
8832
+ },
8833
+ details: {
8834
+ type: "jsonb",
8835
+ nullable: true
8836
+ },
8837
+ createdAt: {
8838
+ type: "timestamp",
8839
+ nullable: false
8840
+ },
8841
+ recordType: {
8842
+ type: "text",
8843
+ nullable: true
8844
+ },
8845
+ recordId: {
8846
+ type: "text",
8847
+ nullable: true
8848
+ },
8849
+ scope: {
8850
+ type: "jsonb",
8851
+ nullable: true
8852
+ },
8853
+ scopeKey: {
8854
+ type: "text",
8855
+ nullable: true
8856
+ },
8857
+ sourceThreadId: {
8858
+ type: "text",
8859
+ nullable: true
8860
+ }
8861
+ };
8862
+ const KNOWLEDGE_PROPOSALS_SCHEMA = {
8863
+ id: {
8864
+ type: "text",
8865
+ nullable: false,
8866
+ primaryKey: true
8867
+ },
8868
+ targetType: {
8869
+ type: "text",
8870
+ nullable: false
8871
+ },
8872
+ targetId: {
8873
+ type: "text",
8874
+ nullable: false
8875
+ },
8876
+ action: {
8877
+ type: "text",
8878
+ nullable: false
8879
+ },
8880
+ changes: {
8881
+ type: "jsonb",
8882
+ nullable: false
8883
+ },
8884
+ reason: {
8885
+ type: "text",
8886
+ nullable: true
8887
+ },
8888
+ proposerContextScopeId: {
8889
+ type: "text",
8890
+ nullable: false
8891
+ },
8892
+ expectedVersion: {
8893
+ type: "integer",
8894
+ nullable: false
8895
+ },
8896
+ status: {
8897
+ type: "text",
8898
+ nullable: false
8899
+ },
8900
+ reviewerContextScopeId: {
8901
+ type: "text",
8902
+ nullable: true
8903
+ },
8904
+ reviewedAt: {
8905
+ type: "timestamp",
8906
+ nullable: true
8907
+ },
8908
+ createdAt: {
8909
+ type: "timestamp",
8910
+ nullable: false
8911
+ }
8912
+ };
8913
+ function assertKnowledgeV2CoreSupport(features) {
8914
+ 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.`);
8915
+ }
8916
+ function resolveKnowledgeV2Core(storageModule) {
8917
+ if (typeof storageModule !== "object" || storageModule === null) throw new Error("@mastra/core advertises Knowledge v2 without the required storage API");
8918
+ const { assertKnowledgeDescriptionWithinBound: assertDescription, assertKnowledgeRecordTextWithinBound: assertRecordText, assertKnowledgeSchemaCompatible: assertCompatible, inspectKnowledgeSchema: inspectSchema } = storageModule;
8919
+ 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");
8920
+ return {
8921
+ assertKnowledgeDescriptionWithinBound: (description) => assertDescription(description),
8922
+ assertKnowledgeRecordTextWithinBound: (text) => assertRecordText(text),
8923
+ assertKnowledgeSchemaCompatible: (inspection) => assertCompatible(inspection),
8924
+ inspectKnowledgeSchema: (snapshot) => inspectSchema(snapshot)
8925
+ };
8926
+ }
8927
+ function createKnowledgeV2CoreLoader(features, loadStorageModule) {
8928
+ let knowledgeV2Core;
8929
+ return async () => {
8930
+ assertKnowledgeV2CoreSupport(features);
8931
+ knowledgeV2Core ??= loadStorageModule().then(resolveKnowledgeV2Core).catch((error) => {
8932
+ knowledgeV2Core = void 0;
8933
+ throw error;
8934
+ });
8935
+ return knowledgeV2Core;
8936
+ };
8937
+ }
8938
+ //#endregion
8262
8939
  //#region src/storage/domains/knowledge/index.ts
8263
- let assertDescriptionWithinBound;
8940
+ const loadKnowledgeV2Core = createKnowledgeV2CoreLoader(_mastra_core_features.coreFeatures, () => import("@mastra/core/storage"));
8264
8941
  async function assertKnowledgeDescriptionWithinBoundCompat(description) {
8265
- let assertWithinBound = assertDescriptionWithinBound;
8266
- if (!assertWithinBound) {
8267
- const resolvedAssert = (await import("@mastra/core/storage")).assertKnowledgeDescriptionWithinBound ?? ((value) => {
8268
- if (value !== void 0 && value.length > 400) throw new Error("Knowledge node description exceeds the 400 UTF-16 code unit limit");
8269
- });
8270
- assertDescriptionWithinBound = resolvedAssert;
8271
- assertWithinBound = resolvedAssert;
8272
- }
8273
- assertWithinBound(description);
8942
+ const { assertKnowledgeDescriptionWithinBound } = await loadKnowledgeV2Core();
8943
+ assertKnowledgeDescriptionWithinBound(description);
8944
+ }
8945
+ async function assertKnowledgeRecordTextWithinBoundCompat(text) {
8946
+ const { assertKnowledgeRecordTextWithinBound } = await loadKnowledgeV2Core();
8947
+ assertKnowledgeRecordTextWithinBound(text);
8274
8948
  }
8275
8949
  const camelCaseColumns = [
8276
8950
  "canonicalName",
@@ -8281,7 +8955,6 @@ const camelCaseColumns = [
8281
8955
  "node",
8282
8956
  "sourceThreadId",
8283
8957
  "capturedAt",
8284
- "maxScope",
8285
8958
  "deletedAt",
8286
8959
  "deletedBy",
8287
8960
  "sourceType",
@@ -8295,7 +8968,30 @@ const camelCaseColumns = [
8295
8968
  "availableAt",
8296
8969
  "claimedAt",
8297
8970
  "claimedBy",
8298
- "completedAt"
8971
+ "completedAt",
8972
+ "isScope",
8973
+ "nodeId",
8974
+ "targetNodeId",
8975
+ "scopeNodeId",
8976
+ "scopeRefId",
8977
+ "canSuggest",
8978
+ "schemaVersion",
8979
+ "importerId",
8980
+ "importKind",
8981
+ "triggerKind",
8982
+ "transcriptThreadId",
8983
+ "traceId",
8984
+ "queuedAt",
8985
+ "startedAt",
8986
+ "targetType",
8987
+ "targetId",
8988
+ "contextScopeId",
8989
+ "importRunId",
8990
+ "proposerContextScopeId",
8991
+ "expectedVersion",
8992
+ "reviewerContextScopeId",
8993
+ "reviewedAt",
8994
+ "addedAt"
8299
8995
  ];
8300
8996
  function transformSqlCode(sql, transform) {
8301
8997
  return sql.split(/('(?:''|[^'])*')/g).map((part, index) => index % 2 === 0 ? transform(part) : part).join("");
@@ -8310,14 +9006,7 @@ function postgresSql(sql, schemaName) {
8310
9006
  const quotedSchema = `"${parseSchemaName(schemaName)}"`;
8311
9007
  normalized = transformSqlCode(normalized, (code) => {
8312
9008
  let transformed = code;
8313
- for (const table of [
8314
- _mastra_core_storage.TABLE_KNOWLEDGE_NODES,
8315
- _mastra_core_storage.TABLE_KNOWLEDGE_RECORDS,
8316
- _mastra_core_storage.TABLE_KNOWLEDGE_MENTIONS,
8317
- _mastra_core_storage.TABLE_KNOWLEDGE_CURSORS,
8318
- _mastra_core_storage.TABLE_KNOWLEDGE_ACTIVITY,
8319
- _mastra_core_storage.TABLE_KNOWLEDGE_SEMANTIC_OUTBOX
8320
- ]) transformed = transformed.replaceAll(`"${table}"`, `${quotedSchema}."${table}"`);
9009
+ for (const table of [...KNOWLEDGE_TABLE_NAMES, ...RETIRED_KNOWLEDGE_TABLE_NAMES]) transformed = transformed.replaceAll(`"${table}"`, `${quotedSchema}."${table}"`);
8321
9010
  return transformed;
8322
9011
  });
8323
9012
  }
@@ -8325,17 +9014,35 @@ function postgresSql(sql, schemaName) {
8325
9014
  return transformSqlCode(normalized, (code) => code.replace(/\?/g, () => `$${++index}`));
8326
9015
  }
8327
9016
  function createExecutor(client, schemaName) {
8328
- return { async execute(statement) {
9017
+ const execute = async (statement, qualifyWithSchema) => {
8329
9018
  const sql = typeof statement === "string" ? statement : statement.sql;
8330
9019
  const args = typeof statement === "string" ? [] : statement.args ?? [];
8331
- const result = await client.query(postgresSql(sql, schemaName), args);
9020
+ const result = await client.query(postgresSql(sql, qualifyWithSchema ? schemaName : void 0), args);
8332
9021
  return {
8333
9022
  rows: result.rows,
8334
9023
  rowsAffected: result.rowCount ?? 0
8335
9024
  };
8336
- } };
9025
+ };
9026
+ return {
9027
+ execute: (statement) => execute(statement, true),
9028
+ executeRaw: (statement) => execute(statement, false)
9029
+ };
9030
+ }
9031
+ /**
9032
+ * Scope keys visible to a caller holding `scope`: a row is visible when its scope is a subset of the
9033
+ * caller's (companion entries such as `resource:x:uncurated` make this more than a prefix match).
9034
+ * Matching rows by `scopeKey` keeps visibility filters on an index; a caller scope has only a few
9035
+ * entries, so the list stays small.
9036
+ */
9037
+ function visibleScopeKeys(scope) {
9038
+ const canonical = (0, _mastra_core_storage.canonicalizeKnowledgeScope)(scope);
9039
+ const keys = /* @__PURE__ */ new Set();
9040
+ for (let mask = 1; mask < 1 << canonical.length; mask++) try {
9041
+ keys.add((0, _mastra_core_storage.knowledgeScopeKey)(canonical.filter((_, index) => mask & 1 << index)));
9042
+ } catch {}
9043
+ return [...keys];
8337
9044
  }
8338
- const visibleSql = `(scopeKey = ? OR LEFT(?, LENGTH(scopeKey) + 1) = scopeKey || chr(31))`;
9045
+ const visibleSql = (keys, scopeKeyColumn = "scopeKey") => `${scopeKeyColumn} IN (${keys.map(() => "?").join(",")})`;
8339
9046
  function parseJson$1(value) {
8340
9047
  if (typeof value === "string") return JSON.parse(value);
8341
9048
  if (value instanceof Uint8Array) return JSON.parse(new TextDecoder().decode(value));
@@ -8375,9 +9082,10 @@ function parseNode(row) {
8375
9082
  id: String(row.id),
8376
9083
  type: "node",
8377
9084
  name: String(row.name),
8378
- kind: String(row.kind),
9085
+ kind: row.kind == null ? "" : String(row.kind),
8379
9086
  content: row.content == null ? void 0 : String(row.content),
8380
9087
  description: row.description == null ? void 0 : String(row.description),
9088
+ isScope: row.isScope === true || row.isScope === 1 ? true : void 0,
8381
9089
  scope: parseJson$1(row.scopeJson ?? row.scope),
8382
9090
  version: Number(row.version),
8383
9091
  mergedInto: row.mergedInto == null ? void 0 : String(row.mergedInto),
@@ -8394,7 +9102,6 @@ function parseKnowledge(row) {
8394
9102
  sourceThreadId: String(row.sourceThreadId),
8395
9103
  capturedAt: toDate$1(row.capturedAt),
8396
9104
  when: optionalDate(row.when),
8397
- maxScope: row.maxScope == null ? void 0 : String(row.maxScope),
8398
9105
  metadata: row.metadata == null ? void 0 : parseJson$1(row.metadata),
8399
9106
  deletedAt: optionalDate(row.deletedAt),
8400
9107
  deletedBy: row.deletedBy == null ? void 0 : String(row.deletedBy)
@@ -8431,6 +9138,10 @@ function knowledgeIndexes(schemaName) {
8431
9138
  name: "idx_knowledge_nodes_scope",
8432
9139
  sql: `CREATE INDEX IF NOT EXISTS idx_knowledge_nodes_scope ON ${table(_mastra_core_storage.TABLE_KNOWLEDGE_NODES)} ("scopeKey", "type");`
8433
9140
  },
9141
+ {
9142
+ name: "idx_knowledge_nodes_name",
9143
+ sql: `CREATE INDEX IF NOT EXISTS idx_knowledge_nodes_name ON ${table(_mastra_core_storage.TABLE_KNOWLEDGE_NODES)} ("type", "canonicalName");`
9144
+ },
8434
9145
  {
8435
9146
  name: "idx_knowledge_records_node_latest",
8436
9147
  sql: `CREATE INDEX IF NOT EXISTS idx_knowledge_records_node_latest ON ${table(_mastra_core_storage.TABLE_KNOWLEDGE_RECORDS)} ("node", "id" DESC);`
@@ -8447,6 +9158,14 @@ function knowledgeIndexes(schemaName) {
8447
9158
  name: "idx_knowledge_activity_latest",
8448
9159
  sql: `CREATE INDEX IF NOT EXISTS idx_knowledge_activity_latest ON ${table(_mastra_core_storage.TABLE_KNOWLEDGE_ACTIVITY)} ("id" DESC);`
8449
9160
  },
9161
+ {
9162
+ name: "idx_knowledge_records_scope",
9163
+ sql: `CREATE INDEX IF NOT EXISTS idx_knowledge_records_scope ON ${table(_mastra_core_storage.TABLE_KNOWLEDGE_RECORDS)} ("scopeKey", "id");`
9164
+ },
9165
+ {
9166
+ name: "idx_knowledge_activity_scope",
9167
+ sql: `CREATE INDEX IF NOT EXISTS idx_knowledge_activity_scope ON ${table(_mastra_core_storage.TABLE_KNOWLEDGE_ACTIVITY)} ("scopeKey", "id" DESC);`
9168
+ },
8450
9169
  {
8451
9170
  name: "idx_knowledge_outbox_idempotency",
8452
9171
  sql: `CREATE UNIQUE INDEX IF NOT EXISTS idx_knowledge_outbox_idempotency ON ${table(_mastra_core_storage.TABLE_KNOWLEDGE_SEMANTIC_OUTBOX)} ("idempotencyKey");`
@@ -8454,67 +9173,152 @@ function knowledgeIndexes(schemaName) {
8454
9173
  {
8455
9174
  name: "idx_knowledge_outbox_claim",
8456
9175
  sql: `CREATE INDEX IF NOT EXISTS idx_knowledge_outbox_claim ON ${table(_mastra_core_storage.TABLE_KNOWLEDGE_SEMANTIC_OUTBOX)} ("status", "availableAt", "createdAt");`
9176
+ },
9177
+ {
9178
+ name: "idx_knowledge_node_scopes_scope",
9179
+ sql: `CREATE INDEX IF NOT EXISTS idx_knowledge_node_scopes_scope ON ${table(TABLE_KNOWLEDGE_NODE_SCOPES)} ("scopeNodeId", "nodeId");`
9180
+ },
9181
+ {
9182
+ name: "idx_knowledge_record_scopes_scope",
9183
+ sql: `CREATE INDEX IF NOT EXISTS idx_knowledge_record_scopes_scope ON ${table(TABLE_KNOWLEDGE_RECORD_SCOPES)} ("scopeNodeId", "recordId");`
9184
+ },
9185
+ {
9186
+ name: "idx_knowledge_scope_grants_ref",
9187
+ sql: `CREATE INDEX IF NOT EXISTS idx_knowledge_scope_grants_ref ON ${table(TABLE_KNOWLEDGE_SCOPE_GRANTS)} ("scopeRefId", "scopeNodeId");`
9188
+ },
9189
+ {
9190
+ name: "idx_knowledge_node_addresses_node",
9191
+ sql: `CREATE INDEX IF NOT EXISTS idx_knowledge_node_addresses_node ON ${table(TABLE_KNOWLEDGE_NODE_ADDRESSES)} ("nodeId");`
9192
+ },
9193
+ {
9194
+ name: "idx_knowledge_import_runs_lookup",
9195
+ sql: `CREATE INDEX IF NOT EXISTS idx_knowledge_import_runs_lookup ON ${table(TABLE_KNOWLEDGE_IMPORT_RUNS)} ("importerId", "binding", "queuedAt" DESC);`
9196
+ },
9197
+ {
9198
+ name: "idx_knowledge_activity_import_run",
9199
+ sql: `CREATE INDEX IF NOT EXISTS idx_knowledge_activity_import_run ON ${table(_mastra_core_storage.TABLE_KNOWLEDGE_ACTIVITY)} ("importRunId", "id" DESC);`
8457
9200
  }
8458
9201
  ];
8459
9202
  }
8460
9203
  function knowledgeIndexDDL(schemaName) {
8461
9204
  return knowledgeIndexes(schemaName).map((index) => index.sql);
8462
9205
  }
9206
+ const KNOWLEDGE_CURATION_CURSOR_REMOVED_MESSAGE = "Knowledge curation cursors were removed: observation-time curate is the only Knowledge writer and needs no cursor.";
9207
+ const knowledgeTableDefinitions = [
9208
+ {
9209
+ tableName: _mastra_core_storage.TABLE_KNOWLEDGE_NODES,
9210
+ schema: KNOWLEDGE_V2_NODES_SCHEMA
9211
+ },
9212
+ {
9213
+ tableName: _mastra_core_storage.TABLE_KNOWLEDGE_RECORDS,
9214
+ schema: KNOWLEDGE_V2_RECORDS_SCHEMA
9215
+ },
9216
+ {
9217
+ tableName: _mastra_core_storage.TABLE_KNOWLEDGE_MENTIONS,
9218
+ schema: KNOWLEDGE_V2_MENTIONS_SCHEMA,
9219
+ compositePrimaryKey: ["recordId", "sourceId"]
9220
+ },
9221
+ {
9222
+ tableName: TABLE_KNOWLEDGE_NODE_SCOPES,
9223
+ schema: KNOWLEDGE_NODE_SCOPES_SCHEMA,
9224
+ compositePrimaryKey: ["nodeId", "scopeNodeId"]
9225
+ },
9226
+ {
9227
+ tableName: TABLE_KNOWLEDGE_RECORD_SCOPES,
9228
+ schema: KNOWLEDGE_RECORD_SCOPES_SCHEMA,
9229
+ compositePrimaryKey: ["recordId", "scopeNodeId"]
9230
+ },
9231
+ {
9232
+ tableName: TABLE_KNOWLEDGE_SCOPE_GRANTS,
9233
+ schema: KNOWLEDGE_SCOPE_GRANTS_SCHEMA,
9234
+ compositePrimaryKey: ["scopeNodeId", "scopeRefId"]
9235
+ },
9236
+ {
9237
+ tableName: TABLE_KNOWLEDGE_ACCESS_STATE,
9238
+ schema: KNOWLEDGE_ACCESS_STATE_SCHEMA
9239
+ },
9240
+ {
9241
+ tableName: TABLE_KNOWLEDGE_SCOPE_ADDRESSES,
9242
+ schema: KNOWLEDGE_SCOPE_ADDRESSES_SCHEMA
9243
+ },
9244
+ {
9245
+ tableName: TABLE_KNOWLEDGE_NODE_ADDRESSES,
9246
+ schema: KNOWLEDGE_NODE_ADDRESSES_SCHEMA,
9247
+ compositePrimaryKey: ["source", "address"]
9248
+ },
9249
+ {
9250
+ tableName: TABLE_KNOWLEDGE_IMPORT_STATE,
9251
+ schema: KNOWLEDGE_IMPORT_STATE_SCHEMA,
9252
+ compositePrimaryKey: [
9253
+ "importerId",
9254
+ "binding",
9255
+ "key"
9256
+ ]
9257
+ },
9258
+ {
9259
+ tableName: TABLE_KNOWLEDGE_IMPORT_RUNS,
9260
+ schema: KNOWLEDGE_IMPORT_RUNS_SCHEMA
9261
+ },
9262
+ {
9263
+ tableName: TABLE_KNOWLEDGE_PROPOSALS,
9264
+ schema: KNOWLEDGE_PROPOSALS_SCHEMA
9265
+ },
9266
+ {
9267
+ tableName: _mastra_core_storage.TABLE_KNOWLEDGE_ACTIVITY,
9268
+ schema: KNOWLEDGE_V2_ACTIVITY_SCHEMA
9269
+ },
9270
+ {
9271
+ tableName: _mastra_core_storage.TABLE_KNOWLEDGE_SEMANTIC_OUTBOX,
9272
+ schema: _mastra_core_storage.KNOWLEDGE_SEMANTIC_OUTBOX_SCHEMA
9273
+ }
9274
+ ];
9275
+ function pgSetting(config, key) {
9276
+ const value = config[key] || process.env[`PG${key.toUpperCase()}`] || pg.defaults[key];
9277
+ return value === void 0 || value === null || value === "" ? void 0 : String(value);
9278
+ }
9279
+ function effectivePgTarget(config) {
9280
+ const host = pgSetting(config, "host");
9281
+ const database = pgSetting(config, "database") ?? pgSetting(config, "user");
9282
+ if (!host || !database) return void 0;
9283
+ return `${host.startsWith("/") ? host : host.toLocaleLowerCase()}:${pgSetting(config, "port") ?? "5432"}/${database}`;
9284
+ }
9285
+ function canonicalPgTarget(config) {
9286
+ if (config.connectionString) try {
9287
+ const parsed = new URL(config.connectionString);
9288
+ return effectivePgTarget({
9289
+ host: decodeURIComponent(parsed.hostname) || config.host,
9290
+ port: parsed.port || config.port,
9291
+ database: decodeURIComponent(parsed.pathname.slice(1)) || config.database,
9292
+ user: decodeURIComponent(parsed.username) || config.user
9293
+ });
9294
+ } catch {
9295
+ return config.connectionString;
9296
+ }
9297
+ return effectivePgTarget(config);
9298
+ }
9299
+ function pgSourceConfig(source) {
9300
+ if (!source || !("options" in source)) return void 0;
9301
+ return source.options;
9302
+ }
9303
+ function pgClientPool(client) {
9304
+ if (!client || !("$pool" in client)) return void 0;
9305
+ return client.$pool;
9306
+ }
9307
+ function getPgKnowledgeIsolationKey(config) {
9308
+ const schema = config.schemaName ?? "public";
9309
+ const poolConfig = pgSourceConfig(config.pool ?? pgClientPool(config.client));
9310
+ const target = Boolean(config.connectionString || config.host || config.database) ? canonicalPgTarget(config) : poolConfig ? canonicalPgTarget(poolConfig) : void 0;
9311
+ if (target) return `pg:${target}:schema:${schema}`;
9312
+ return `pg:unidentified:schema:${schema}`;
9313
+ }
8463
9314
  var KnowledgePG = class extends _mastra_core_storage.KnowledgeStorage {
8464
- static MANAGED_TABLES = [
8465
- _mastra_core_storage.TABLE_KNOWLEDGE_NODES,
8466
- _mastra_core_storage.TABLE_KNOWLEDGE_RECORDS,
8467
- _mastra_core_storage.TABLE_KNOWLEDGE_MENTIONS,
8468
- _mastra_core_storage.TABLE_KNOWLEDGE_CURSORS,
8469
- _mastra_core_storage.TABLE_KNOWLEDGE_ACTIVITY,
8470
- _mastra_core_storage.TABLE_KNOWLEDGE_SEMANTIC_OUTBOX
8471
- ];
9315
+ static MANAGED_TABLES = KNOWLEDGE_TABLE_NAMES;
8472
9316
  static getExportDDL(schemaName) {
8473
- return [
8474
- generateTableSQL({
8475
- tableName: _mastra_core_storage.TABLE_KNOWLEDGE_NODES,
8476
- schema: _mastra_core_storage.KNOWLEDGE_NODES_SCHEMA,
8477
- schemaName,
8478
- includeAllConstraints: true
8479
- }),
8480
- generateTableSQL({
8481
- tableName: _mastra_core_storage.TABLE_KNOWLEDGE_RECORDS,
8482
- schema: _mastra_core_storage.KNOWLEDGE_RECORDS_SCHEMA,
8483
- schemaName,
8484
- includeAllConstraints: true
8485
- }),
8486
- generateTableSQL({
8487
- tableName: _mastra_core_storage.TABLE_KNOWLEDGE_MENTIONS,
8488
- schema: _mastra_core_storage.KNOWLEDGE_MENTIONS_SCHEMA,
8489
- schemaName,
8490
- compositePrimaryKey: [
8491
- "sourceType",
8492
- "sourceId",
8493
- "recordId"
8494
- ],
8495
- includeAllConstraints: true
8496
- }),
8497
- generateTableSQL({
8498
- tableName: _mastra_core_storage.TABLE_KNOWLEDGE_CURSORS,
8499
- schema: _mastra_core_storage.KNOWLEDGE_CURSORS_SCHEMA,
8500
- schemaName,
8501
- compositePrimaryKey: ["sourceThreadId", "agent"],
8502
- includeAllConstraints: true
8503
- }),
8504
- generateTableSQL({
8505
- tableName: _mastra_core_storage.TABLE_KNOWLEDGE_ACTIVITY,
8506
- schema: _mastra_core_storage.KNOWLEDGE_ACTIVITY_SCHEMA,
8507
- schemaName,
8508
- includeAllConstraints: true
8509
- }),
8510
- generateTableSQL({
8511
- tableName: _mastra_core_storage.TABLE_KNOWLEDGE_SEMANTIC_OUTBOX,
8512
- schema: _mastra_core_storage.KNOWLEDGE_SEMANTIC_OUTBOX_SCHEMA,
8513
- schemaName,
8514
- includeAllConstraints: true
8515
- }),
8516
- ...knowledgeIndexDDL(schemaName)
8517
- ];
9317
+ return [...knowledgeTableDefinitions.map((definition) => generateTableSQL({
9318
+ ...definition,
9319
+ schemaName,
9320
+ includeAllConstraints: true
9321
+ })), ...knowledgeIndexDDL(schemaName)];
8518
9322
  }
8519
9323
  #client;
8520
9324
  #executor;
@@ -8523,7 +9327,7 @@ var KnowledgePG = class extends _mastra_core_storage.KnowledgeStorage {
8523
9327
  #db;
8524
9328
  #schemaName;
8525
9329
  constructor(config) {
8526
- super();
9330
+ super({ storageIsolationKey: config.storageIsolationKey ?? getPgKnowledgeIsolationKey(config) });
8527
9331
  const { client, readClient, schemaName, skipDefaultIndexes } = resolvePgConfig(config);
8528
9332
  this.#client = client;
8529
9333
  this.#schemaName = schemaName;
@@ -8536,56 +9340,359 @@ var KnowledgePG = class extends _mastra_core_storage.KnowledgeStorage {
8536
9340
  skipDefaultIndexes
8537
9341
  });
8538
9342
  }
8539
- async init() {
8540
- await this.#db.createTable({
8541
- tableName: _mastra_core_storage.TABLE_KNOWLEDGE_NODES,
8542
- schema: _mastra_core_storage.KNOWLEDGE_NODES_SCHEMA
8543
- });
8544
- await this.#db.alterTable({
8545
- tableName: _mastra_core_storage.TABLE_KNOWLEDGE_NODES,
8546
- schema: _mastra_core_storage.KNOWLEDGE_NODES_SCHEMA,
8547
- ifNotExists: ["description"]
9343
+ getCapabilities() {
9344
+ return {
9345
+ contractVersion: 2,
9346
+ schemaVersion: 2,
9347
+ supportsV2: true,
9348
+ supportsSchemaInspection: true,
9349
+ supportsExplicitReset: true
9350
+ };
9351
+ }
9352
+ async inspectSchema() {
9353
+ const { inspectKnowledgeSchema } = await loadKnowledgeV2Core();
9354
+ try {
9355
+ const snapshot = getSchemaSnapshot(this.#client, this.#schemaName);
9356
+ if (snapshot) {
9357
+ const tableNames = KNOWLEDGE_TABLE_NAMES.filter((table) => snapshot.tables.has(table));
9358
+ return this.#classifySchema(this.#executor, tableNames, snapshot.columns);
9359
+ }
9360
+ return this.#inspectSchemaWithExecutor(this.#executor);
9361
+ } catch (error) {
9362
+ return inspectKnowledgeSchema({
9363
+ available: false,
9364
+ tableNames: [],
9365
+ reason: error instanceof Error ? error.message : String(error)
9366
+ });
9367
+ }
9368
+ }
9369
+ async #inspectSchemaWithExecutor(executor) {
9370
+ const tableNames = (await executor.execute({
9371
+ sql: `SELECT table_name FROM information_schema.tables WHERE table_schema = COALESCE(?, current_schema()) AND table_name = ANY(?::text[])`,
9372
+ args: [this.#schemaName ?? null, [...KNOWLEDGE_TABLE_NAMES]]
9373
+ })).rows.map((row) => String(row.table_name));
9374
+ const columnResult = await executor.execute({
9375
+ sql: `SELECT table_name, column_name FROM information_schema.columns WHERE table_schema = COALESCE(?, current_schema()) AND table_name = ANY(?::text[])`,
9376
+ args: [this.#schemaName ?? null, [...KNOWLEDGE_TABLE_NAMES]]
9377
+ });
9378
+ const columns = /* @__PURE__ */ new Map();
9379
+ for (const row of columnResult.rows) {
9380
+ const table = String(row.table_name);
9381
+ const names = columns.get(table) ?? /* @__PURE__ */ new Set();
9382
+ names.add(String(row.column_name));
9383
+ columns.set(table, names);
9384
+ }
9385
+ return this.#classifySchema(executor, tableNames, columns);
9386
+ }
9387
+ async #classifySchema(executor, tableNames, columns) {
9388
+ const { inspectKnowledgeSchema } = await loadKnowledgeV2Core();
9389
+ if (tableNames.length === 0) return inspectKnowledgeSchema({
9390
+ available: true,
9391
+ tableNames
9392
+ });
9393
+ const missingTables = KNOWLEDGE_TABLE_NAMES.filter((table) => !tableNames.includes(table));
9394
+ if (missingTables.length > 0) return inspectKnowledgeSchema({
9395
+ available: true,
9396
+ tableNames,
9397
+ reason: `Missing Knowledge v2 tables: ${missingTables.join(", ")}`
9398
+ });
9399
+ for (const { tableName: table, schema } of knowledgeTableDefinitions) {
9400
+ const actual = columns.get(table) ?? /* @__PURE__ */ new Set();
9401
+ const missing = Object.keys(schema).filter((column) => !actual.has(column));
9402
+ if (missing.length > 0) return inspectKnowledgeSchema({
9403
+ available: true,
9404
+ tableNames,
9405
+ reason: `Knowledge table ${table} is missing v2 columns: ${missing.join(", ")}`
9406
+ });
9407
+ }
9408
+ const accessState = await executor.execute(`SELECT schemaVersion FROM "${TABLE_KNOWLEDGE_ACCESS_STATE}" WHERE id='global'`);
9409
+ if (Number(accessState.rows[0]?.schemaVersion) !== 2) return inspectKnowledgeSchema({
9410
+ available: true,
9411
+ tableNames,
9412
+ reason: "Knowledge schema version marker is missing or incompatible"
9413
+ });
9414
+ return inspectKnowledgeSchema({
9415
+ available: true,
9416
+ tableNames,
9417
+ schemaVersion: 2
8548
9418
  });
8549
- await this.#db.createTable({
8550
- tableName: _mastra_core_storage.TABLE_KNOWLEDGE_RECORDS,
8551
- schema: _mastra_core_storage.KNOWLEDGE_RECORDS_SCHEMA
9419
+ }
9420
+ async init() {
9421
+ await this.#transaction(async (tx) => {
9422
+ await tx.execute({
9423
+ sql: "SELECT pg_advisory_xact_lock(hashtext(?))",
9424
+ args: [`mastra-knowledge-v2:${this.#schemaName ?? "current_schema"}`]
9425
+ });
9426
+ const { assertKnowledgeSchemaCompatible } = await loadKnowledgeV2Core();
9427
+ let inspection = await this.#inspectSchemaWithExecutor(tx);
9428
+ if (inspection.status === "incompatible-reset-required" && await this.#isPublishedV1Layout(tx)) {
9429
+ const tables = [...RETIRED_KNOWLEDGE_TABLE_NAMES, ...[...KNOWLEDGE_TABLE_NAMES].reverse()].map((table) => `"${table}"`).join(", ");
9430
+ await tx.execute(`DROP TABLE IF EXISTS ${tables}`);
9431
+ inspection = await this.#inspectSchemaWithExecutor(tx);
9432
+ }
9433
+ assertKnowledgeSchemaCompatible(inspection);
9434
+ for (const definition of knowledgeTableDefinitions) await tx.executeRaw(generateTableSQL({
9435
+ ...definition,
9436
+ schemaName: this.#schemaName,
9437
+ includeAllConstraints: true
9438
+ }));
9439
+ for (const index of knowledgeIndexes(this.#schemaName)) await tx.executeRaw(index.sql);
9440
+ await tx.execute({
9441
+ sql: `INSERT INTO "${TABLE_KNOWLEDGE_ACCESS_STATE}" (id, epoch, schemaVersion) VALUES ('global', 0, ?) ON CONFLICT (id) DO NOTHING`,
9442
+ args: [2]
9443
+ });
8552
9444
  });
8553
- await this.#db.createTable({
8554
- tableName: _mastra_core_storage.TABLE_KNOWLEDGE_MENTIONS,
8555
- schema: _mastra_core_storage.KNOWLEDGE_MENTIONS_SCHEMA,
8556
- compositePrimaryKey: [
8557
- "sourceType",
8558
- "sourceId",
8559
- "recordId"
9445
+ }
9446
+ /**
9447
+ * True when the only Knowledge objects are the tables and indexes published v1 adapters created,
9448
+ * with or without rows. Anything else (v2 tables, unknown tables, views, triggers, extra indexes)
9449
+ * needs an explicit reset.
9450
+ */
9451
+ async #isPublishedV1Layout(executor) {
9452
+ const schema = this.#schemaName ?? null;
9453
+ const relations = await executor.execute({
9454
+ sql: `SELECT table_name, table_type FROM information_schema.tables WHERE table_schema = COALESCE(?, current_schema()) AND table_name LIKE 'mastra\\_knowledge\\_%'`,
9455
+ args: [schema]
9456
+ });
9457
+ const tables = [];
9458
+ for (const row of relations.rows) {
9459
+ const name = String(row.table_name);
9460
+ if (row.table_type !== "BASE TABLE" || !PUBLISHED_KNOWLEDGE_V1_TABLE_NAMES.has(name)) return false;
9461
+ tables.push(name);
9462
+ }
9463
+ const indexes = await executor.execute({
9464
+ sql: `SELECT indexname FROM pg_indexes WHERE schemaname = COALESCE(?, current_schema()) AND tablename = ANY(?::text[])`,
9465
+ args: [schema, tables]
9466
+ });
9467
+ for (const row of indexes.rows) {
9468
+ const name = String(row.indexname);
9469
+ if (!PUBLISHED_KNOWLEDGE_V1_INDEX_NAMES.has(name) && !name.endsWith("_pkey")) return false;
9470
+ }
9471
+ if ((await executor.execute({
9472
+ 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`,
9473
+ args: [
9474
+ schema,
9475
+ tables,
9476
+ schema,
9477
+ tables
8560
9478
  ]
8561
- });
8562
- await this.#db.createTable({
8563
- tableName: _mastra_core_storage.TABLE_KNOWLEDGE_CURSORS,
8564
- schema: _mastra_core_storage.KNOWLEDGE_CURSORS_SCHEMA,
8565
- compositePrimaryKey: ["sourceThreadId", "agent"]
8566
- });
8567
- await this.#db.createTable({
8568
- tableName: _mastra_core_storage.TABLE_KNOWLEDGE_ACTIVITY,
8569
- schema: _mastra_core_storage.KNOWLEDGE_ACTIVITY_SCHEMA
8570
- });
8571
- await this.#db.createTable({
8572
- tableName: _mastra_core_storage.TABLE_KNOWLEDGE_SEMANTIC_OUTBOX,
8573
- schema: _mastra_core_storage.KNOWLEDGE_SEMANTIC_OUTBOX_SCHEMA
8574
- });
8575
- await Promise.all(knowledgeIndexes(this.#schemaName).map((index) => this.#db.createIndexFromStatement(index.name, index.sql)));
9479
+ })).rows.length > 0) return false;
9480
+ return true;
8576
9481
  }
8577
9482
  async dangerouslyClearAll() {
8578
9483
  await this.#transaction(async (tx) => {
8579
9484
  for (const table of [
9485
+ TABLE_KNOWLEDGE_RECORD_SCOPES,
9486
+ TABLE_KNOWLEDGE_NODE_SCOPES,
9487
+ TABLE_KNOWLEDGE_SCOPE_GRANTS,
9488
+ TABLE_KNOWLEDGE_SCOPE_ADDRESSES,
9489
+ TABLE_KNOWLEDGE_NODE_ADDRESSES,
8580
9490
  _mastra_core_storage.TABLE_KNOWLEDGE_MENTIONS,
8581
- _mastra_core_storage.TABLE_KNOWLEDGE_RECORDS,
8582
- _mastra_core_storage.TABLE_KNOWLEDGE_NODES,
8583
- _mastra_core_storage.TABLE_KNOWLEDGE_CURSORS,
9491
+ TABLE_KNOWLEDGE_PROPOSALS,
8584
9492
  _mastra_core_storage.TABLE_KNOWLEDGE_ACTIVITY,
8585
- _mastra_core_storage.TABLE_KNOWLEDGE_SEMANTIC_OUTBOX
9493
+ TABLE_KNOWLEDGE_IMPORT_STATE,
9494
+ TABLE_KNOWLEDGE_IMPORT_RUNS,
9495
+ _mastra_core_storage.TABLE_KNOWLEDGE_SEMANTIC_OUTBOX,
9496
+ _mastra_core_storage.TABLE_KNOWLEDGE_RECORDS,
9497
+ _mastra_core_storage.TABLE_KNOWLEDGE_NODES
8586
9498
  ]) await tx.execute(`DELETE FROM "${table}"`);
9499
+ await tx.execute(`UPDATE "${TABLE_KNOWLEDGE_ACCESS_STATE}" SET epoch = 0 WHERE id = 'global'`);
9500
+ });
9501
+ }
9502
+ async dangerouslyReset() {
9503
+ const tables = [...RETIRED_KNOWLEDGE_TABLE_NAMES, ...[...KNOWLEDGE_TABLE_NAMES].reverse()].map((table) => `"${table}"`).join(", ");
9504
+ await this.#executor.execute(`DROP TABLE IF EXISTS ${tables}`);
9505
+ await this.init();
9506
+ }
9507
+ async reconcileStructure(plan) {
9508
+ return this.#transaction(async (tx) => {
9509
+ await tx.execute({
9510
+ sql: `SELECT pg_advisory_xact_lock(hashtext(?))`,
9511
+ args: [`mastra-knowledge-reconcile:${this.#schemaName}`]
9512
+ });
9513
+ const scopes = {};
9514
+ const createdScopeIds = [];
9515
+ const createdAddresses = /* @__PURE__ */ new Set();
9516
+ const retrofit = plan.retrofit ?? true;
9517
+ let structureChanged = false;
9518
+ const deletedScopeAddresses = /* @__PURE__ */ new Set();
9519
+ const resolveAddress = async (address) => {
9520
+ if (scopes[address]) return scopes[address];
9521
+ const row = (await tx.execute({
9522
+ 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=?`,
9523
+ args: [address]
9524
+ })).rows[0];
9525
+ if (!row) return void 0;
9526
+ if (!row.isScope) throw new Error(`Knowledge address ${address} does not reference a scope`);
9527
+ if (row.deletedAt) deletedScopeAddresses.add(address);
9528
+ scopes[address] = String(row.scopeNodeId);
9529
+ return scopes[address];
9530
+ };
9531
+ for (const scope of plan.scopes) {
9532
+ if (await resolveAddress(scope.address)) continue;
9533
+ const id = (0, crypto$1.randomUUID)();
9534
+ const now = (/* @__PURE__ */ new Date()).toISOString();
9535
+ await tx.execute({
9536
+ sql: `INSERT INTO "${_mastra_core_storage.TABLE_KNOWLEDGE_NODES}" (id,type,name,"canonicalName",kind,description,"isScope",metadata,version,"createdAt","updatedAt") VALUES (?,'node',?,?,?,?,TRUE,?,1,?,?)`,
9537
+ args: [
9538
+ id,
9539
+ scope.name,
9540
+ canonicalName(scope.name),
9541
+ scope.kind ?? null,
9542
+ scope.description ?? null,
9543
+ scope.metadata ?? null,
9544
+ now,
9545
+ now
9546
+ ]
9547
+ });
9548
+ await tx.execute({
9549
+ sql: `INSERT INTO "${TABLE_KNOWLEDGE_SCOPE_ADDRESSES}" (address,"scopeNodeId") VALUES (?,?)`,
9550
+ args: [scope.address, id]
9551
+ });
9552
+ scopes[scope.address] = id;
9553
+ createdAddresses.add(scope.address);
9554
+ createdScopeIds.push(id);
9555
+ structureChanged = true;
9556
+ }
9557
+ for (const scope of plan.scopes) {
9558
+ if (!createdAddresses.has(scope.address) && (!retrofit || deletedScopeAddresses.has(scope.address))) continue;
9559
+ const scopeNodeId = scopes[scope.address];
9560
+ for (const parentAddress of scope.parentAddresses ?? []) {
9561
+ const parentId = await resolveAddress(parentAddress);
9562
+ if (!parentId || deletedScopeAddresses.has(parentAddress)) {
9563
+ const deletedParentId = scopes[parentAddress];
9564
+ if ((deletedParentId ? await tx.execute({
9565
+ sql: `SELECT 1 FROM "mastra_knowledge_node_scopes" WHERE "nodeId"=? AND "scopeNodeId"=?`,
9566
+ args: [scopeNodeId, deletedParentId]
9567
+ }) : void 0)?.rows.length) continue;
9568
+ throw new Error(`Knowledge parent scope does not exist: ${parentAddress}`);
9569
+ }
9570
+ if ((await tx.execute({
9571
+ sql: `SELECT 1 FROM "mastra_knowledge_node_scopes" WHERE "nodeId"=? AND "scopeNodeId"=?`,
9572
+ args: [scopeNodeId, parentId]
9573
+ })).rows.length) continue;
9574
+ if ((await tx.execute({
9575
+ 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`,
9576
+ args: [
9577
+ parentId,
9578
+ canonicalName(scope.name),
9579
+ scopeNodeId
9580
+ ]
9581
+ })).rows.length) throw new Error(`Knowledge scope name ${scope.name} already exists under ${parentAddress}`);
9582
+ const inserted = await tx.execute({
9583
+ sql: `INSERT INTO "${TABLE_KNOWLEDGE_NODE_SCOPES}" ("nodeId","scopeNodeId","addedAt") VALUES (?,?,?) ON CONFLICT DO NOTHING`,
9584
+ args: [
9585
+ scopeNodeId,
9586
+ parentId,
9587
+ (/* @__PURE__ */ new Date()).toISOString()
9588
+ ]
9589
+ });
9590
+ structureChanged ||= inserted.rowsAffected > 0;
9591
+ }
9592
+ for (const grant of scope.grants ?? []) {
9593
+ const scopeRefId = await resolveAddress(grant.scopeRefAddress);
9594
+ if (!scopeRefId || deletedScopeAddresses.has(grant.scopeRefAddress)) {
9595
+ const deletedScopeRefId = scopes[grant.scopeRefAddress];
9596
+ if ((deletedScopeRefId ? await tx.execute({
9597
+ sql: `SELECT 1 FROM "mastra_knowledge_scope_grants" WHERE "scopeNodeId"=? AND "scopeRefId"=?`,
9598
+ args: [scopeNodeId, deletedScopeRefId]
9599
+ }) : void 0)?.rows.length) continue;
9600
+ throw new Error(`Knowledge grant scope does not exist: ${grant.scopeRefAddress}`);
9601
+ }
9602
+ const inserted = await tx.execute({
9603
+ sql: `INSERT INTO "${TABLE_KNOWLEDGE_SCOPE_GRANTS}" ("scopeNodeId","scopeRefId",role,"canSuggest") VALUES (?,?,?,?) ON CONFLICT DO NOTHING`,
9604
+ args: [
9605
+ scopeNodeId,
9606
+ scopeRefId,
9607
+ grant.role,
9608
+ grant.canSuggest ?? null
9609
+ ]
9610
+ });
9611
+ structureChanged ||= inserted.rowsAffected > 0;
9612
+ }
9613
+ }
9614
+ if (structureChanged) await tx.execute(`UPDATE "${TABLE_KNOWLEDGE_ACCESS_STATE}" SET epoch=epoch+1 WHERE id='global'`);
9615
+ const state = await tx.execute(`SELECT epoch FROM "${TABLE_KNOWLEDGE_ACCESS_STATE}" WHERE id='global'`);
9616
+ return {
9617
+ scopes,
9618
+ createdScopeIds,
9619
+ deletedScopeAddresses: [...deletedScopeAddresses],
9620
+ changed: structureChanged,
9621
+ accessEpoch: Number(state.rows[0]?.epoch ?? 0)
9622
+ };
8587
9623
  });
8588
9624
  }
9625
+ async listScopeNodes(input = {}) {
9626
+ const { limit, after } = parseListKnowledgeScopeNodesInput(input);
9627
+ if (input.addresses?.length === 0 || input.ids?.length === 0) return {
9628
+ scopes: [],
9629
+ nextCursor: null
9630
+ };
9631
+ const args = [];
9632
+ const where = [`n."isScope"`, `n."deletedAt" IS NULL`];
9633
+ let within = "";
9634
+ if (input.withinAddress !== void 0) {
9635
+ 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) `;
9636
+ args.push(input.withinAddress);
9637
+ where.push("n.id IN (SELECT id FROM within_scope)");
9638
+ }
9639
+ if (input.addresses) {
9640
+ where.push(`a.address IN (${input.addresses.map(() => "?").join(",")})`);
9641
+ args.push(...input.addresses);
9642
+ }
9643
+ if (input.ids) {
9644
+ where.push(`n.id IN (${input.ids.map(() => "?").join(",")})`);
9645
+ args.push(...input.ids);
9646
+ }
9647
+ if (after) {
9648
+ where.push("(n.name COLLATE \"C\" > ? OR (n.name = ? AND n.id > ?))");
9649
+ args.push(after.name, after.name, after.id);
9650
+ }
9651
+ args.push(limit + 1);
9652
+ const rows = (await this.#readExecutor.execute({
9653
+ 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 ?`,
9654
+ args
9655
+ })).rows;
9656
+ if (rows.length === 0) return {
9657
+ scopes: [],
9658
+ nextCursor: null
9659
+ };
9660
+ const parents = await this.#readExecutor.execute({
9661
+ 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"`,
9662
+ args: rows.map((row) => String(row.id))
9663
+ });
9664
+ const parentsByScopeId = /* @__PURE__ */ new Map();
9665
+ for (const row of parents.rows) {
9666
+ const scopeId = String(row.nodeId);
9667
+ const parentId = String(row.scopeNodeId);
9668
+ const existing = parentsByScopeId.get(scopeId);
9669
+ if (existing) existing.push(parentId);
9670
+ else parentsByScopeId.set(scopeId, [parentId]);
9671
+ }
9672
+ return pageKnowledgeScopeNodes(rows.map((row) => ({
9673
+ id: String(row.id),
9674
+ address: String(row.address),
9675
+ name: String(row.name),
9676
+ ...row.kind == null ? {} : { kind: String(row.kind) },
9677
+ ...row.description == null ? {} : { description: String(row.description) },
9678
+ parentIds: parentsByScopeId.get(String(row.id)) ?? []
9679
+ })), limit, input);
9680
+ }
9681
+ async listScopeMembers(input) {
9682
+ const { limit, after } = parseListKnowledgeScopeMembersInput(input);
9683
+ const args = [input.scopeNodeId];
9684
+ let keyset = "";
9685
+ if (after) {
9686
+ const updatedAt = postgresTimestamp(after.updatedAt);
9687
+ keyset = ` AND (n."updatedAt" < ? OR (n."updatedAt" = ? AND (n.name > ? OR (n.name = ? AND n.id > ?))))`;
9688
+ args.push(updatedAt, updatedAt, after.name, after.name, after.id);
9689
+ }
9690
+ args.push(limit + 1);
9691
+ return pageKnowledgeScopeMembers((await this.#readExecutor.execute({
9692
+ 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 ?`,
9693
+ args
9694
+ })).rows.map(parseNode), limit, input);
9695
+ }
8589
9696
  async createNode(input) {
8590
9697
  await assertKnowledgeDescriptionWithinBoundCompat(input.description);
8591
9698
  const scope = (0, _mastra_core_storage.canonicalizeKnowledgeScope)(input.scope);
@@ -8594,6 +9701,7 @@ var KnowledgePG = class extends _mastra_core_storage.KnowledgeStorage {
8594
9701
  if (existing) {
8595
9702
  const terminal = await this.#resolveTerminalNode(tx, existing.id);
8596
9703
  if (!(0, _mastra_core_storage.isKnowledgeScopeVisible)(terminal.scope, scope)) throw new Error(`Merged knowledge node is not visible from scope: ${input.name}`);
9704
+ await this.#placeNodeInScopes(tx, terminal.id, input.scopeAddresses, /* @__PURE__ */ new Date());
8597
9705
  return terminal;
8598
9706
  }
8599
9707
  const now = /* @__PURE__ */ new Date();
@@ -8610,7 +9718,7 @@ var KnowledgePG = class extends _mastra_core_storage.KnowledgeStorage {
8610
9718
  updatedAt: now
8611
9719
  };
8612
9720
  await tx.execute({
8613
- 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,?,?)`,
9721
+ 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,?,?)`,
8614
9722
  args: [
8615
9723
  node.id,
8616
9724
  "node",
@@ -8626,6 +9734,8 @@ var KnowledgePG = class extends _mastra_core_storage.KnowledgeStorage {
8626
9734
  now.toISOString()
8627
9735
  ]
8628
9736
  });
9737
+ await this.#replaceNodeScopes(tx, node.id, scope, now);
9738
+ await this.#placeNodeInScopes(tx, node.id, input.scopeAddresses, now);
8629
9739
  await this.#replaceMentions(tx, "node", node.id, node.content ?? "", input.resolutionScope ?? scope, scope);
8630
9740
  await this.#activity(tx, "node-created", "node", node.id, scope);
8631
9741
  await this.#outbox(tx, "node", node.id, "upsert", node.version, scope);
@@ -8642,13 +9752,13 @@ var KnowledgePG = class extends _mastra_core_storage.KnowledgeStorage {
8642
9752
  return this.#resolveNode(this.#readExecutor, input.name, (0, _mastra_core_storage.canonicalizeKnowledgeScope)(input.scope));
8643
9753
  }
8644
9754
  async listNodes(input) {
8645
- const key = (0, _mastra_core_storage.knowledgeScopeKey)((0, _mastra_core_storage.canonicalizeKnowledgeScope)(input.scope));
9755
+ const keys = visibleScopeKeys((0, _mastra_core_storage.canonicalizeKnowledgeScope)(input.scope));
8646
9756
  const clauses = [
8647
9757
  `type = 'node'`,
8648
9758
  "mergedInto IS NULL",
8649
- visibleSql
9759
+ visibleSql(keys)
8650
9760
  ];
8651
- const args = [key, key];
9761
+ const args = [...keys];
8652
9762
  if (input.namePrefix) {
8653
9763
  clauses.push("canonicalName LIKE ? ESCAPE '='");
8654
9764
  args.push(`${escapeLikePattern(canonicalName(input.namePrefix))}%`);
@@ -8700,6 +9810,7 @@ var KnowledgePG = class extends _mastra_core_storage.KnowledgeStorage {
8700
9810
  input.version
8701
9811
  ]
8702
9812
  })).rowsAffected === 0) throw new _mastra_core_storage.KnowledgeConflictError(input.id);
9813
+ if ((0, _mastra_core_storage.knowledgeScopeKey)(existing.scope) !== (0, _mastra_core_storage.knowledgeScopeKey)(scope)) await this.#swapIdentityScopes(tx, input.id, existing.scope, scope, now);
8703
9814
  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);
8704
9815
  await this.#activity(tx, "node-updated", "node", input.id, scope);
8705
9816
  if ((0, _mastra_core_storage.knowledgeScopeKey)(existing.scope) !== (0, _mastra_core_storage.knowledgeScopeKey)(scope)) {
@@ -8754,8 +9865,12 @@ var KnowledgePG = class extends _mastra_core_storage.KnowledgeStorage {
8754
9865
  ]
8755
9866
  })).rowsAffected === 0) throw new _mastra_core_storage.KnowledgeConflictError(source.id);
8756
9867
  await tx.execute({
8757
- sql: `UPDATE "${_mastra_core_storage.TABLE_KNOWLEDGE_RECORDS}" SET node=? WHERE node=?`,
8758
- args: [target.id, source.id]
9868
+ sql: `UPDATE "${_mastra_core_storage.TABLE_KNOWLEDGE_RECORDS}" SET node=?,version=version+1,updatedAt=? WHERE node=?`,
9869
+ args: [
9870
+ target.id,
9871
+ (/* @__PURE__ */ new Date()).toISOString(),
9872
+ source.id
9873
+ ]
8759
9874
  });
8760
9875
  await tx.execute({
8761
9876
  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=?)`,
@@ -8795,10 +9910,10 @@ var KnowledgePG = class extends _mastra_core_storage.KnowledgeStorage {
8795
9910
  });
8796
9911
  }
8797
9912
  async appendKnowledge(input) {
9913
+ await assertKnowledgeRecordTextWithinBoundCompat(input.text);
8798
9914
  const scope = (0, _mastra_core_storage.canonicalizeKnowledgeScope)(input.scope);
8799
9915
  const resolutionScope = (0, _mastra_core_storage.canonicalizeKnowledgeScope)(input.resolutionScope);
8800
9916
  const defaultScope = (0, _mastra_core_storage.canonicalizeKnowledgeScope)(input.defaultScope);
8801
- (0, _mastra_core_storage.assertKnowledgeScopeWithinCeiling)(scope, input.maxScope);
8802
9917
  return this.#transaction(async (tx) => {
8803
9918
  const parent = await this.#resolveTerminalNode(tx, nodeReferenceId(input.node));
8804
9919
  if (!parent) throw new _mastra_core_storage.KnowledgeNotFoundError("node", nodeReferenceId(input.node));
@@ -8811,11 +9926,10 @@ var KnowledgePG = class extends _mastra_core_storage.KnowledgeStorage {
8811
9926
  sourceThreadId: input.sourceThreadId,
8812
9927
  capturedAt: /* @__PURE__ */ new Date(),
8813
9928
  when: input.when ? new Date(input.when) : void 0,
8814
- maxScope: input.maxScope,
8815
9929
  metadata: input.metadata
8816
9930
  };
8817
9931
  await tx.execute({
8818
- 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)`,
9932
+ 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)`,
8819
9933
  args: [
8820
9934
  record.id,
8821
9935
  record.node,
@@ -8825,10 +9939,12 @@ var KnowledgePG = class extends _mastra_core_storage.KnowledgeStorage {
8825
9939
  record.sourceThreadId,
8826
9940
  record.capturedAt.toISOString(),
8827
9941
  record.when?.toISOString() ?? null,
8828
- record.maxScope ?? null,
8829
- metadataJson
9942
+ metadataJson,
9943
+ 1,
9944
+ record.capturedAt.toISOString()
8830
9945
  ]
8831
9946
  });
9947
+ await this.#replaceRecordScopes(tx, record.id, scope, record.capturedAt);
8832
9948
  await this.#replaceMentions(tx, "record", record.id, record.text, resolutionScope, defaultScope);
8833
9949
  await this.#activity(tx, "record-created", "record", record.id, scope, record.sourceThreadId);
8834
9950
  await this.#outbox(tx, "record", record.id, "upsert", record.id, scope);
@@ -8855,17 +9971,13 @@ var KnowledgePG = class extends _mastra_core_storage.KnowledgeStorage {
8855
9971
  return this.#queryKnowledge(input, "related");
8856
9972
  }
8857
9973
  async knowledgeBySource(input) {
8858
- const key = (0, _mastra_core_storage.knowledgeScopeKey)((0, _mastra_core_storage.canonicalizeKnowledgeScope)(input.scope));
8859
- const args = [
8860
- input.sourceThreadId,
8861
- key,
8862
- key
8863
- ];
9974
+ const keys = visibleScopeKeys((0, _mastra_core_storage.canonicalizeKnowledgeScope)(input.scope));
9975
+ const args = [input.sourceThreadId, ...keys];
8864
9976
  if (input.after) args.push(input.after);
8865
9977
  const limit = input.limit ?? 100;
8866
9978
  args.push(limit + 1);
8867
9979
  const records = (await this.#readExecutor.execute({
8868
- 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 ?`,
9980
+ 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 ?`,
8869
9981
  args
8870
9982
  })).rows.map(parseKnowledge);
8871
9983
  return {
@@ -8880,10 +9992,11 @@ var KnowledgePG = class extends _mastra_core_storage.KnowledgeStorage {
8880
9992
  if (record.deletedAt) return record;
8881
9993
  const deletedAt = /* @__PURE__ */ new Date();
8882
9994
  await tx.execute({
8883
- sql: `UPDATE "${_mastra_core_storage.TABLE_KNOWLEDGE_RECORDS}" SET deletedAt=?,deletedBy=? WHERE id=? AND deletedAt IS NULL`,
9995
+ sql: `UPDATE "${_mastra_core_storage.TABLE_KNOWLEDGE_RECORDS}" SET deletedAt=?,deletedBy=?,version=version+1,updatedAt=? WHERE id=? AND deletedAt IS NULL`,
8884
9996
  args: [
8885
9997
  deletedAt.toISOString(),
8886
9998
  input.deletedBy,
9999
+ deletedAt.toISOString(),
8887
10000
  input.id
8888
10001
  ]
8889
10002
  });
@@ -8902,8 +10015,8 @@ var KnowledgePG = class extends _mastra_core_storage.KnowledgeStorage {
8902
10015
  if (!record) throw new _mastra_core_storage.KnowledgeNotFoundError("record", input.id);
8903
10016
  if (!record.deletedAt) return record;
8904
10017
  await tx.execute({
8905
- sql: `UPDATE "${_mastra_core_storage.TABLE_KNOWLEDGE_RECORDS}" SET deletedAt=NULL,deletedBy=NULL WHERE id=?`,
8906
- args: [input.id]
10018
+ sql: `UPDATE "${_mastra_core_storage.TABLE_KNOWLEDGE_RECORDS}" SET deletedAt=NULL,deletedBy=NULL,version=version+1,updatedAt=? WHERE id=?`,
10019
+ args: [(/* @__PURE__ */ new Date()).toISOString(), input.id]
8907
10020
  });
8908
10021
  await this.#activity(tx, "record-restored", "record", input.id, record.scope, record.sourceThreadId);
8909
10022
  await this.#outbox(tx, "record", input.id, "upsert", (0, _mastra_core_storage.createKnowledgeUlid)(), record.scope);
@@ -8919,15 +10032,17 @@ var KnowledgePG = class extends _mastra_core_storage.KnowledgeStorage {
8919
10032
  return this.#transaction(async (tx) => {
8920
10033
  const record = await this.#getKnowledge(tx, input.id, true);
8921
10034
  if (!record) throw new _mastra_core_storage.KnowledgeNotFoundError("record", input.id);
8922
- (0, _mastra_core_storage.assertKnowledgeScopeWithinCeiling)(scope, record.maxScope);
10035
+ const updatedAt = /* @__PURE__ */ new Date();
8923
10036
  await tx.execute({
8924
- sql: `UPDATE "${_mastra_core_storage.TABLE_KNOWLEDGE_RECORDS}" SET scope=jsonb(?),scopeKey=? WHERE id=?`,
10037
+ sql: `UPDATE "${_mastra_core_storage.TABLE_KNOWLEDGE_RECORDS}" SET scope=jsonb(?),scopeKey=?,version=version+1,updatedAt=? WHERE id=?`,
8925
10038
  args: [
8926
10039
  JSON.stringify(scope),
8927
10040
  (0, _mastra_core_storage.knowledgeScopeKey)(scope),
10041
+ updatedAt.toISOString(),
8928
10042
  input.id
8929
10043
  ]
8930
10044
  });
10045
+ await this.#replaceRecordScopes(tx, input.id, scope, updatedAt);
8931
10046
  await this.#activity(tx, "record-rescoped", "record", input.id, scope, record.sourceThreadId);
8932
10047
  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);
8933
10048
  if (!record.deletedAt) await this.#outbox(tx, "record", input.id, "upsert", (0, _mastra_core_storage.createKnowledgeUlid)(), scope);
@@ -8937,33 +10052,16 @@ var KnowledgePG = class extends _mastra_core_storage.KnowledgeStorage {
8937
10052
  };
8938
10053
  });
8939
10054
  }
8940
- async raiseKnowledgeCeiling(input) {
8941
- return this.#transaction(async (tx) => {
8942
- const record = await this.#getKnowledge(tx, input.id, true);
8943
- if (!record) throw new _mastra_core_storage.KnowledgeNotFoundError("record", input.id);
8944
- (0, _mastra_core_storage.assertKnowledgeScopeWithinCeiling)(record.scope, input.maxScope);
8945
- (0, _mastra_core_storage.assertKnowledgeCeilingRaised)(record.maxScope, input.maxScope);
8946
- await tx.execute({
8947
- sql: `UPDATE "${_mastra_core_storage.TABLE_KNOWLEDGE_RECORDS}" SET maxScope=? WHERE id=?`,
8948
- args: [input.maxScope ?? null, input.id]
8949
- });
8950
- return {
8951
- ...record,
8952
- maxScope: input.maxScope
8953
- };
8954
- });
8955
- }
8956
10055
  async search(input) {
8957
10056
  const scope = (0, _mastra_core_storage.canonicalizeKnowledgeScope)(input.scope);
8958
- const key = (0, _mastra_core_storage.knowledgeScopeKey)(scope);
10057
+ const keys = visibleScopeKeys(scope);
8959
10058
  const normalizedQuery = input.query.trim().toLocaleLowerCase();
8960
10059
  if (!normalizedQuery) return [];
8961
10060
  const query = `%${escapeLikePattern(normalizedQuery)}%`;
8962
10061
  const results = (await this.#readExecutor.execute({
8963
- 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 ?`,
10062
+ 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 ?`,
8964
10063
  args: [
8965
- key,
8966
- key,
10064
+ ...keys,
8967
10065
  query,
8968
10066
  query,
8969
10067
  query,
@@ -8984,10 +10082,9 @@ var KnowledgePG = class extends _mastra_core_storage.KnowledgeStorage {
8984
10082
  }));
8985
10083
  if (results.length < (input.limit ?? 20)) {
8986
10084
  const records = await this.#readExecutor.execute({
8987
- 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 ?`,
10085
+ 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 ?`,
8988
10086
  args: [
8989
- key,
8990
- key,
10087
+ ...keys,
8991
10088
  query,
8992
10089
  (input.limit ?? 20) - results.length
8993
10090
  ]
@@ -8997,7 +10094,7 @@ var KnowledgePG = class extends _mastra_core_storage.KnowledgeStorage {
8997
10094
  return {
8998
10095
  type: "record",
8999
10096
  id: String(row.id),
9000
- recordId: String(row.node),
10097
+ recordId: parentVisible ? String(row.node) : String(row.id),
9001
10098
  name: parentVisible ? String(row.name) : "(private node)",
9002
10099
  text: String(row.text),
9003
10100
  scope: parseJson$1(row.scopeJson)
@@ -9006,41 +10103,26 @@ var KnowledgePG = class extends _mastra_core_storage.KnowledgeStorage {
9006
10103
  }
9007
10104
  return results;
9008
10105
  }
9009
- async getCurationCursor(input) {
9010
- const row = (await this.#executor.execute({
9011
- sql: `SELECT * FROM "${_mastra_core_storage.TABLE_KNOWLEDGE_CURSORS}" WHERE sourceThreadId=? AND agent=?`,
9012
- args: [input.sourceThreadId, input.agent]
9013
- })).rows[0];
9014
- return row ? {
9015
- sourceThreadId: String(row.sourceThreadId),
9016
- agent: String(row.agent),
9017
- lastKnowledgeId: String(row.lastKnowledgeId),
9018
- updatedAt: toDate$1(row.updatedAt)
9019
- } : null;
9020
- }
9021
- async advanceCurationCursor(input) {
9022
- const updatedAt = /* @__PURE__ */ new Date();
9023
- if ((await this.#executor.execute({
9024
- 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`,
9025
- args: [
9026
- input.sourceThreadId,
9027
- input.agent,
9028
- input.lastKnowledgeId,
9029
- updatedAt.toISOString()
9030
- ]
9031
- })).rowsAffected === 0) throw new Error("Knowledge curation cursor cannot move backwards");
9032
- return {
9033
- ...input,
9034
- updatedAt
9035
- };
10106
+ /**
10107
+ * @deprecated Curation cursors were removed. Observation-time curate is the only Knowledge writer and needs no
10108
+ * cursor. Always throws.
10109
+ */
10110
+ async getCurationCursor(_input) {
10111
+ throw new Error(KNOWLEDGE_CURATION_CURSOR_REMOVED_MESSAGE);
10112
+ }
10113
+ /**
10114
+ * @deprecated Curation cursors were removed. Observation-time curate is the only Knowledge writer and needs no
10115
+ * cursor. Always throws.
10116
+ */
10117
+ async advanceCurationCursor(_input) {
10118
+ throw new Error(KNOWLEDGE_CURATION_CURSOR_REMOVED_MESSAGE);
9036
10119
  }
9037
10120
  async listActivity(input) {
9038
- const key = (0, _mastra_core_storage.knowledgeScopeKey)((0, _mastra_core_storage.canonicalizeKnowledgeScope)(input.scope));
10121
+ const keys = visibleScopeKeys((0, _mastra_core_storage.canonicalizeKnowledgeScope)(input.scope));
9039
10122
  return (await this.#readExecutor.execute({
9040
- sql: `SELECT *,scope AS "scopeJson" FROM "${_mastra_core_storage.TABLE_KNOWLEDGE_ACTIVITY}" WHERE ${visibleSql}${input.after ? " AND id < ?" : ""} ORDER BY id DESC LIMIT ?`,
10123
+ sql: `SELECT *,scope AS "scopeJson" FROM "${_mastra_core_storage.TABLE_KNOWLEDGE_ACTIVITY}" WHERE ${visibleSql(keys)}${input.after ? " AND id < ?" : ""} ORDER BY id DESC LIMIT ?`,
9041
10124
  args: [
9042
- key,
9043
- key,
10125
+ ...keys,
9044
10126
  ...input.after ? [input.after] : [],
9045
10127
  input.limit ?? 100
9046
10128
  ]
@@ -9062,9 +10144,9 @@ var KnowledgePG = class extends _mastra_core_storage.KnowledgeStorage {
9062
10144
  args.push(input.status);
9063
10145
  }
9064
10146
  if (input.scope) {
9065
- const key = (0, _mastra_core_storage.knowledgeScopeKey)((0, _mastra_core_storage.canonicalizeKnowledgeScope)(input.scope));
9066
- clauses.push(visibleSql);
9067
- args.push(key, key);
10147
+ const keys = visibleScopeKeys(input.scope);
10148
+ clauses.push(visibleSql(keys));
10149
+ args.push(...keys);
9068
10150
  }
9069
10151
  args.push(input.limit ?? 100);
9070
10152
  return (await this.#executor.execute({
@@ -9083,9 +10165,9 @@ var KnowledgePG = class extends _mastra_core_storage.KnowledgeStorage {
9083
10165
  ];
9084
10166
  const args = [now.toISOString(), stale.toISOString()];
9085
10167
  if (input.scope) {
9086
- const key = (0, _mastra_core_storage.knowledgeScopeKey)((0, _mastra_core_storage.canonicalizeKnowledgeScope)(input.scope));
9087
- clauses.push(visibleSql);
9088
- args.push(key, key);
10168
+ const keys = visibleScopeKeys(input.scope);
10169
+ clauses.push(visibleSql(keys));
10170
+ args.push(...keys);
9089
10171
  }
9090
10172
  args.push(input.limit ?? 100);
9091
10173
  const ids = (await tx.execute({
@@ -9152,12 +10234,14 @@ var KnowledgePG = class extends _mastra_core_storage.KnowledgeStorage {
9152
10234
  return result.rows[0] ? parseNode(result.rows[0]) : null;
9153
10235
  }
9154
10236
  async #resolveNode(executor, name, scope) {
9155
- for (let length = scope.length; length > 0; length--) {
9156
- const node = await this.#getNodeByName(executor, name, scope.slice(0, length));
9157
- if (node) {
9158
- const terminal = await this.#resolveTerminalNode(executor, node.id);
9159
- if (terminal && (0, _mastra_core_storage.isKnowledgeScopeVisible)(terminal.scope, scope)) return terminal;
9160
- }
10237
+ const keys = visibleScopeKeys(scope);
10238
+ const candidates = (await executor.execute({
10239
+ 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)`,
10240
+ args: [canonicalName(name), ...keys]
10241
+ })).rows.map(parseNode).sort((left, right) => right.scope.length - left.scope.length);
10242
+ for (const candidate of candidates) {
10243
+ const terminal = await this.#resolveTerminalNode(executor, candidate.id);
10244
+ if (terminal && (0, _mastra_core_storage.isKnowledgeScopeVisible)(terminal.scope, scope)) return terminal;
9161
10245
  }
9162
10246
  return null;
9163
10247
  }
@@ -9182,17 +10266,16 @@ var KnowledgePG = class extends _mastra_core_storage.KnowledgeStorage {
9182
10266
  const scope = (0, _mastra_core_storage.canonicalizeKnowledgeScope)(input.scope);
9183
10267
  const node = await this.#resolveTerminalNode(this.#readExecutor, nodeReferenceId(input.node));
9184
10268
  if (!node) return { records: [] };
9185
- const key = (0, _mastra_core_storage.knowledgeScopeKey)(scope);
10269
+ const keys = visibleScopeKeys(scope);
9186
10270
  const args = [
9187
10271
  node.id,
9188
10272
  ...relationship === "related" ? [node.id] : [],
9189
- key,
9190
- key
10273
+ ...keys
9191
10274
  ];
9192
10275
  if (input.after) args.push(input.after);
9193
10276
  args.push((input.limit ?? 100) + 1);
9194
10277
  const records = (await this.#readExecutor.execute({
9195
- 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 ?`,
10278
+ 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 ?`,
9196
10279
  args
9197
10280
  })).rows.map(parseKnowledge);
9198
10281
  const limit = input.limit ?? 100;
@@ -9201,6 +10284,90 @@ var KnowledgePG = class extends _mastra_core_storage.KnowledgeStorage {
9201
10284
  nextCursor: records.length > limit ? records[limit - 1]?.id : void 0
9202
10285
  };
9203
10286
  }
10287
+ async #resolveScopeNodeIds(executor, addresses) {
10288
+ const scopeNodeIds = /* @__PURE__ */ new Set();
10289
+ for (const address of addresses) {
10290
+ const result = await executor.execute({
10291
+ sql: `SELECT scopeNodeId FROM "${TABLE_KNOWLEDGE_SCOPE_ADDRESSES}" WHERE address=?`,
10292
+ args: [address]
10293
+ });
10294
+ if (result.rows[0]?.scopeNodeId != null) scopeNodeIds.add(String(result.rows[0].scopeNodeId));
10295
+ }
10296
+ return [...scopeNodeIds];
10297
+ }
10298
+ async #replaceNodeScopes(executor, nodeId, addresses, addedAt) {
10299
+ await executor.execute({
10300
+ sql: `DELETE FROM "${TABLE_KNOWLEDGE_NODE_SCOPES}" WHERE nodeId=?`,
10301
+ args: [nodeId]
10302
+ });
10303
+ for (const scopeNodeId of await this.#resolveScopeNodeIds(executor, addresses)) await executor.execute({
10304
+ sql: `INSERT INTO "${TABLE_KNOWLEDGE_NODE_SCOPES}" (nodeId,scopeNodeId,addedAt) VALUES (?,?,?) ON CONFLICT DO NOTHING`,
10305
+ args: [
10306
+ nodeId,
10307
+ scopeNodeId,
10308
+ addedAt.toISOString()
10309
+ ]
10310
+ });
10311
+ }
10312
+ /**
10313
+ * Move a node's identity memberships from `from` to `to` without touching structural
10314
+ * placements added by `#placeNodeInScopes`, which a scope change must not erase.
10315
+ */
10316
+ async #swapIdentityScopes(executor, nodeId, from, to, addedAt) {
10317
+ const next = await this.#resolveScopeNodeIds(executor, to);
10318
+ for (const scopeNodeId of await this.#resolveScopeNodeIds(executor, from)) {
10319
+ if (next.includes(scopeNodeId)) continue;
10320
+ await executor.execute({
10321
+ sql: `DELETE FROM "${TABLE_KNOWLEDGE_NODE_SCOPES}" WHERE nodeId=? AND scopeNodeId=?`,
10322
+ args: [nodeId, scopeNodeId]
10323
+ });
10324
+ }
10325
+ for (const scopeNodeId of next) await executor.execute({
10326
+ sql: `INSERT INTO "${TABLE_KNOWLEDGE_NODE_SCOPES}" (nodeId,scopeNodeId,addedAt) VALUES (?,?,?) ON CONFLICT DO NOTHING`,
10327
+ args: [
10328
+ nodeId,
10329
+ scopeNodeId,
10330
+ addedAt.toISOString()
10331
+ ]
10332
+ });
10333
+ }
10334
+ /**
10335
+ * Additive structural placement: every address must resolve to a live scope node
10336
+ * (unlike identity membership, an unknown address is a caller error, not a lazy
10337
+ * materialization miss). Runs inside the caller's transaction, so a throw aborts
10338
+ * the whole mutation.
10339
+ */
10340
+ async #placeNodeInScopes(executor, nodeId, addresses, addedAt) {
10341
+ for (const address of addresses ?? []) {
10342
+ const scopeNodeId = (await executor.execute({
10343
+ 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`,
10344
+ args: [address]
10345
+ })).rows[0]?.scopeNodeId;
10346
+ if (scopeNodeId == null) throw new _mastra_core_storage.KnowledgeNotFoundError("scope", address);
10347
+ await executor.execute({
10348
+ sql: `INSERT INTO "${TABLE_KNOWLEDGE_NODE_SCOPES}" ("nodeId","scopeNodeId","addedAt") VALUES (?,?,?) ON CONFLICT DO NOTHING`,
10349
+ args: [
10350
+ nodeId,
10351
+ String(scopeNodeId),
10352
+ addedAt.toISOString()
10353
+ ]
10354
+ });
10355
+ }
10356
+ }
10357
+ async #replaceRecordScopes(executor, recordId, addresses, addedAt) {
10358
+ await executor.execute({
10359
+ sql: `DELETE FROM "${TABLE_KNOWLEDGE_RECORD_SCOPES}" WHERE recordId=?`,
10360
+ args: [recordId]
10361
+ });
10362
+ for (const scopeNodeId of await this.#resolveScopeNodeIds(executor, addresses)) await executor.execute({
10363
+ sql: `INSERT INTO "${TABLE_KNOWLEDGE_RECORD_SCOPES}" (recordId,scopeNodeId,addedAt) VALUES (?,?,?) ON CONFLICT DO NOTHING`,
10364
+ args: [
10365
+ recordId,
10366
+ scopeNodeId,
10367
+ addedAt.toISOString()
10368
+ ]
10369
+ });
10370
+ }
9204
10371
  async #replaceMentions(tx, sourceType, sourceId, text, resolutionScope, defaultScope) {
9205
10372
  await tx.execute({
9206
10373
  sql: `DELETE FROM "${_mastra_core_storage.TABLE_KNOWLEDGE_MENTIONS}" WHERE sourceType=? AND sourceId=?`,
@@ -9224,7 +10391,7 @@ var KnowledgePG = class extends _mastra_core_storage.KnowledgeStorage {
9224
10391
  updatedAt: now
9225
10392
  };
9226
10393
  await tx.execute({
9227
- 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,?,?)`,
10394
+ 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,?,?)`,
9228
10395
  args: [
9229
10396
  node.id,
9230
10397
  "node",
@@ -9238,6 +10405,7 @@ var KnowledgePG = class extends _mastra_core_storage.KnowledgeStorage {
9238
10405
  now.toISOString()
9239
10406
  ]
9240
10407
  });
10408
+ await this.#replaceNodeScopes(tx, node.id, defaultScope, now);
9241
10409
  await this.#activity(tx, "node-created", "node", node.id, defaultScope);
9242
10410
  await this.#outbox(tx, "node", node.id, "upsert", 1, defaultScope);
9243
10411
  }
@@ -9254,13 +10422,17 @@ var KnowledgePG = class extends _mastra_core_storage.KnowledgeStorage {
9254
10422
  }
9255
10423
  async #activity(executor, action, recordType, recordId, scope, sourceThreadId) {
9256
10424
  const now = /* @__PURE__ */ new Date();
10425
+ const [contextScopeId] = await this.#resolveScopeNodeIds(executor, scope);
9257
10426
  await executor.execute({
9258
- sql: `INSERT INTO "${_mastra_core_storage.TABLE_KNOWLEDGE_ACTIVITY}" (id,action,recordType,recordId,scope,scopeKey,sourceThreadId,createdAt) VALUES (?,?,?,?,jsonb(?),?,?,?)`,
10427
+ sql: `INSERT INTO "${_mastra_core_storage.TABLE_KNOWLEDGE_ACTIVITY}" (id,action,targetType,targetId,contextScopeId,recordType,recordId,scope,scopeKey,sourceThreadId,createdAt) VALUES (?,?,?,?,?,?,?,jsonb(?),?,?,?)`,
9259
10428
  args: [
9260
10429
  (0, _mastra_core_storage.createKnowledgeUlid)(),
9261
10430
  action,
9262
10431
  recordType,
9263
10432
  recordId,
10433
+ contextScopeId ?? null,
10434
+ recordType,
10435
+ recordId,
9264
10436
  JSON.stringify(scope),
9265
10437
  (0, _mastra_core_storage.knowledgeScopeKey)(scope),
9266
10438
  sourceThreadId ?? null,
@@ -23515,7 +24687,7 @@ var WorkflowsPG = class WorkflowsPG extends _mastra_core_storage.WorkflowsStorag
23515
24687
  async dangerouslyClearAll() {
23516
24688
  await this.#db.clearTable({ tableName: _mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT });
23517
24689
  }
23518
- async updateWorkflowResults({ workflowName, runId, stepId, result, requestContext }) {
24690
+ async updateWorkflowResults({ workflowName, runId, stepId, result, requestContext, state }) {
23519
24691
  try {
23520
24692
  return await this.#db.client.tx(async (t) => {
23521
24693
  const tableName = getTableName({
@@ -23546,7 +24718,8 @@ var WorkflowsPG = class WorkflowsPG extends _mastra_core_storage.WorkflowsStorag
23546
24718
  snapshot,
23547
24719
  stepId,
23548
24720
  result,
23549
- requestContext
24721
+ requestContext,
24722
+ state
23550
24723
  });
23551
24724
  const now = /* @__PURE__ */ new Date();
23552
24725
  const sanitizedSnapshot = toPgJson(snapshot);
@@ -25019,7 +26192,10 @@ var PostgresStore = class extends _mastra_core_storage.MastraCompositeStore {
25019
26192
  workflows: new WorkflowsPG(domainConfig),
25020
26193
  workflowDefinitions: new WorkflowDefinitionsPG(domainConfig),
25021
26194
  memory: new MemoryPG(domainConfig),
25022
- knowledge: new KnowledgePG(domainConfig),
26195
+ knowledge: new KnowledgePG({
26196
+ ...domainConfig,
26197
+ storageIsolationKey: config.storageIsolationKey ?? getPgKnowledgeIsolationKey(config)
26198
+ }),
25023
26199
  notifications: new NotificationsPG(domainConfig),
25024
26200
  observability: new ObservabilityPG(domainConfig),
25025
26201
  agents: new AgentsPG(domainConfig),
@@ -25073,7 +26249,7 @@ var PostgresStore = class extends _mastra_core_storage.MastraCompositeStore {
25073
26249
  const pinned = new PinnedClientAdapter(this.#writePool, pinnedClient);
25074
26250
  this.#db.pin(pinned);
25075
26251
  this.#db.setSchemaSnapshot(await loadSchemaSnapshot(pinned, this.schema));
25076
- await super.init();
26252
+ await Promise.all(Object.entries(this.stores).filter(([name, store]) => name !== "knowledge" && store).map(([, store]) => store.init()));
25077
26253
  this.isInitialized = true;
25078
26254
  } catch (error) {
25079
26255
  this.#initPromise = null;