@mastra/mysql 0.7.1-alpha.1 → 0.8.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
@@ -6,6 +6,46 @@ let _mastra_core_utils = require("@mastra/core/utils");
6
6
  let crypto$1 = require("crypto");
7
7
  let _mastra_core_agent = require("@mastra/core/agent");
8
8
  let _mastra_core_storage_domains_skills = require("@mastra/core/storage/domains/skills");
9
+ //#region src/storage/db/schema-snapshot.ts
10
+ /** Builds the `table.index` presence key the snapshot uses. */
11
+ function indexKey(table, index) {
12
+ return `${table.toLowerCase()}.${index.toLowerCase()}`;
13
+ }
14
+ const lower = (value) => String(value).toLowerCase();
15
+ /**
16
+ * Reads the catalog for `schemaName` in three queries. Returns null when no
17
+ * schema name is available (a pool with no default database): correctness over
18
+ * optimization, callers fall back to today's per-probe behavior.
19
+ */
20
+ async function loadSchemaSnapshot(pool, schemaName) {
21
+ if (!schemaName) return null;
22
+ const [[tableRows], [columnRows], [indexRows]] = await Promise.all([
23
+ pool.execute(`SELECT table_name FROM information_schema.tables WHERE table_schema = ?`, [schemaName]),
24
+ pool.execute(`SELECT table_name, column_name FROM information_schema.columns WHERE table_schema = ?`, [schemaName]),
25
+ pool.execute(`SELECT DISTINCT table_name, index_name FROM information_schema.statistics WHERE table_schema = ?`, [schemaName])
26
+ ]);
27
+ const tables = /* @__PURE__ */ new Set();
28
+ for (const row of tableRows ?? []) tables.add(lower(row.table_name ?? row.TABLE_NAME));
29
+ const columns = /* @__PURE__ */ new Map();
30
+ for (const row of columnRows ?? []) {
31
+ const table = lower(row.table_name ?? row.TABLE_NAME);
32
+ let set = columns.get(table);
33
+ if (!set) {
34
+ set = /* @__PURE__ */ new Set();
35
+ columns.set(table, set);
36
+ }
37
+ set.add(lower(row.column_name ?? row.COLUMN_NAME));
38
+ }
39
+ const indexes = /* @__PURE__ */ new Set();
40
+ for (const row of indexRows ?? []) indexes.add(indexKey(lower(row.table_name ?? row.TABLE_NAME), lower(row.index_name ?? row.INDEX_NAME)));
41
+ return {
42
+ schemaName,
43
+ tables,
44
+ columns,
45
+ indexes
46
+ };
47
+ }
48
+ //#endregion
9
49
  //#region src/storage/domains/utils.ts
10
50
  function quoteIdentifier(value, context) {
11
51
  return `\`${(0, _mastra_core_utils.parseSqlIdentifier)(value, context)}\``;
@@ -145,12 +185,38 @@ var StoreOperationsMySQL = class extends _mastra_core_storage.StoreOperations {
145
185
  pool;
146
186
  database;
147
187
  resolvedDatabase;
188
+ /**
189
+ * Init-scoped catalog snapshot (see db/schema-snapshot.ts). Installed by
190
+ * MySQLStore.init() for exactly the init window and cleared in its finally;
191
+ * null at runtime so non-init callers keep probing the live catalog.
192
+ */
193
+ schemaSnapshot = null;
148
194
  constructor({ pool, database }) {
149
195
  super();
150
196
  this.pool = pool;
151
197
  this.database = database;
152
198
  this.resolvedDatabase = database ?? null;
153
199
  }
200
+ /**
201
+ * Loads and installs the init-scoped snapshot. A null load (no default
202
+ * database) or a failed load leaves the snapshot uninstalled, so init
203
+ * proceeds with today's per-probe behavior: correctness over optimization.
204
+ */
205
+ async loadInitSchemaSnapshot() {
206
+ try {
207
+ this.schemaSnapshot = await loadSchemaSnapshot(this.pool, await this.getDatabase());
208
+ } catch (error) {
209
+ console.warn("Failed to load init schema snapshot, falling back to per-object probing:", error);
210
+ this.schemaSnapshot = null;
211
+ }
212
+ }
213
+ clearInitSchemaSnapshot() {
214
+ this.schemaSnapshot = null;
215
+ }
216
+ /** Read by sibling domains (memory's raw index DDL) so snapshot state lives in exactly one place. */
217
+ getInitSchemaSnapshot() {
218
+ return this.schemaSnapshot;
219
+ }
154
220
  getPool() {
155
221
  return this.pool;
156
222
  }
@@ -166,6 +232,8 @@ var StoreOperationsMySQL = class extends _mastra_core_storage.StoreOperations {
166
232
  return this.resolvedDatabase ?? void 0;
167
233
  }
168
234
  async hasColumn(table, column) {
235
+ const snapshotColumns = this.schemaSnapshot?.columns.get(table.toLowerCase());
236
+ if (snapshotColumns) return snapshotColumns.has(column.toLowerCase());
169
237
  const db = await this.getDatabase();
170
238
  const params = [table, column];
171
239
  let sql = "SELECT COUNT(*) as count FROM information_schema.columns WHERE table_name = ? AND (column_name = ? OR column_name = ? )";
@@ -243,13 +311,23 @@ var StoreOperationsMySQL = class extends _mastra_core_storage.StoreOperations {
243
311
  return false;
244
312
  }
245
313
  async createTable({ tableName, schema }) {
314
+ const snapshot = this.schemaSnapshot;
315
+ if (snapshot?.tables.has(tableName.toLowerCase())) return;
246
316
  const connection = await this.pool.getConnection();
247
317
  try {
248
- const db = await this.getDatabase();
249
- const [t_rows] = await connection.query("SELECT COUNT(*) AS count FROM information_schema.tables WHERE table_schema = ? AND table_name = ?", [db ?? "", tableName]);
250
- if (Array.isArray(t_rows) && t_rows.length > 0 && t_rows[0].count > 0) return;
318
+ if (!snapshot) {
319
+ const db = await this.getDatabase();
320
+ const [t_rows] = await connection.query("SELECT COUNT(*) AS count FROM information_schema.tables WHERE table_schema = ? AND table_name = ?", [db ?? "", tableName]);
321
+ if (Array.isArray(t_rows) && t_rows.length > 0 && t_rows[0].count > 0) return;
322
+ }
251
323
  const sql = this.getCreateTableSQL(tableName, schema);
252
- await connection.execute(sql);
324
+ const [result] = await connection.execute(sql);
325
+ const created = result?.warningStatus === 0;
326
+ if (snapshot && created) {
327
+ const table = tableName.toLowerCase();
328
+ snapshot.tables.add(table);
329
+ snapshot.columns.set(table, new Set(Object.keys(schema).map((column) => column.toLowerCase())));
330
+ }
253
331
  } catch (error) {
254
332
  throw new _mastra_core_error.MastraError({
255
333
  id: "MYSQL_STORE_CREATE_TABLE_FAILED",
@@ -305,17 +383,22 @@ var StoreOperationsMySQL = class extends _mastra_core_storage.StoreOperations {
305
383
  const tableName = formatTableName(table, this.database);
306
384
  const indexName = quoteIdentifier(name, "index name");
307
385
  try {
308
- const db = await this.getDatabase() ?? "";
309
- const [existing] = await this.pool.execute(`SELECT 1 FROM information_schema.STATISTICS
386
+ const snapshot = this.schemaSnapshot;
387
+ if (snapshot) {
388
+ if (snapshot.indexes.has(indexKey(table, name))) return;
389
+ } else {
390
+ const db = await this.getDatabase() ?? "";
391
+ const [existing] = await this.pool.execute(`SELECT 1 FROM information_schema.STATISTICS
310
392
  WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ? AND INDEX_NAME = ?
311
393
  LIMIT 1`, [
312
- db,
313
- table,
314
- name
315
- ]);
316
- if (existing.length > 0) return;
394
+ db,
395
+ table,
396
+ name
397
+ ]);
398
+ if (existing.length > 0) return;
399
+ }
317
400
  const [columnMeta] = await this.pool.execute(`SELECT COLUMN_NAME, DATA_TYPE FROM information_schema.COLUMNS
318
- WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ?`, [db, table]);
401
+ WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ?`, [await this.getDatabase() ?? "", table]);
319
402
  const dataTypeByColumn = new Map(columnMeta.map((row) => [String(row.COLUMN_NAME).toLowerCase(), String(row.DATA_TYPE).toLowerCase()]));
320
403
  const PREFIX_TYPES = /* @__PURE__ */ new Set([
321
404
  "tinytext",
@@ -341,6 +424,7 @@ var StoreOperationsMySQL = class extends _mastra_core_storage.StoreOperations {
341
424
  }).join(", ");
342
425
  const sql = `CREATE ${unique ? "UNIQUE " : ""}INDEX ${indexName} ON ${tableName} (${columnsStr})`;
343
426
  await this.pool.execute(sql);
427
+ this.schemaSnapshot?.indexes.add(indexKey(table, name));
344
428
  } catch (error) {
345
429
  console.warn(`Failed to create index ${name}:`, error);
346
430
  }
@@ -572,17 +656,22 @@ var StoreOperationsMySQL = class extends _mastra_core_storage.StoreOperations {
572
656
  }
573
657
  async alterTable({ tableName, schema, ifNotExists }) {
574
658
  if (!ifNotExists.length) return;
575
- const db = await this.getDatabase();
576
- const [tableRows] = await this.pool.execute("SELECT COUNT(*) AS count FROM information_schema.tables WHERE table_schema = ? AND table_name = ?", [db ?? "", tableName]);
577
- if (!(Array.isArray(tableRows) && tableRows.length > 0 && tableRows[0].count > 0)) return;
578
- const params = [tableName];
579
- let sql = "SELECT column_name FROM information_schema.columns WHERE table_name = ?";
580
- if (db) {
581
- sql += " AND table_schema = ?";
582
- params.push(db);
659
+ const snapshotColumns = this.schemaSnapshot?.columns.get(tableName.toLowerCase());
660
+ let existing;
661
+ if (snapshotColumns) existing = snapshotColumns;
662
+ else {
663
+ const db = await this.getDatabase();
664
+ const [tableRows] = await this.pool.execute("SELECT COUNT(*) AS count FROM information_schema.tables WHERE table_schema = ? AND table_name = ?", [db ?? "", tableName]);
665
+ if (!(Array.isArray(tableRows) && tableRows.length > 0 && tableRows[0].count > 0)) return;
666
+ const params = [tableName];
667
+ let sql = "SELECT column_name FROM information_schema.columns WHERE table_name = ?";
668
+ if (db) {
669
+ sql += " AND table_schema = ?";
670
+ params.push(db);
671
+ }
672
+ const [rows] = await this.pool.execute(sql, params);
673
+ existing = new Set((rows || []).map((row) => String(row.column_name ?? row.COLUMN_NAME).toLowerCase()));
583
674
  }
584
- const [rows] = await this.pool.execute(sql, params);
585
- const existing = new Set((rows || []).map((row) => String(row.column_name ?? row.COLUMN_NAME).toLowerCase()));
586
675
  for (const columnName of ifNotExists) {
587
676
  if (existing.has(columnName.toLowerCase())) continue;
588
677
  const column = schema[columnName];
@@ -604,6 +693,7 @@ var StoreOperationsMySQL = class extends _mastra_core_storage.StoreOperations {
604
693
  const alterSql = `ALTER TABLE ${formatTableName(tableName, this.database)} ADD COLUMN ${parts.join(" ")}`;
605
694
  try {
606
695
  await this.pool.execute(alterSql);
696
+ existing.add(columnName.toLowerCase());
607
697
  } catch (error) {
608
698
  if (error?.code === "ER_DUP_FIELDNAME") continue;
609
699
  throw new _mastra_core_error.MastraError({
@@ -641,7 +731,7 @@ function generateTableSQL({ tableName, schema, compositePrimaryKey }) {
641
731
  const constraints = [];
642
732
  if (def.primaryKey && !compositePrimaryKey?.includes(name)) constraints.push("PRIMARY KEY");
643
733
  if (!def.nullable) constraints.push("NOT NULL");
644
- return `${colName} ${mapToMySqlType(def.type)} ${constraints.join(" ")}`;
734
+ return `${colName} ${mapToMySqlType(def.type, Boolean(def.primaryKey || compositePrimaryKey?.includes(name)))} ${constraints.join(" ")}`;
645
735
  });
646
736
  const tableConstraints = [];
647
737
  if (compositePrimaryKey) {
@@ -665,9 +755,9 @@ function generateIndexSQL(options) {
665
755
  return quoteIdentifier(col, "column name");
666
756
  }).join(", ")});`;
667
757
  }
668
- function mapToMySqlType(type) {
758
+ function mapToMySqlType(type, isKey = false) {
669
759
  switch (type) {
670
- case "text": return "TEXT";
760
+ case "text": return isKey ? "VARCHAR(191)" : "TEXT";
671
761
  case "timestamp": return "DATETIME(3)";
672
762
  case "bigint": return "BIGINT";
673
763
  case "integer": return "INT";
@@ -1282,7 +1372,7 @@ function serializeJson(v) {
1282
1372
  if (typeof v === "object" && v != null) return JSON.stringify(v);
1283
1373
  return v ?? null;
1284
1374
  }
1285
- function parseJson$1(val) {
1375
+ function parseJson$2(val) {
1286
1376
  if (val == null) return void 0;
1287
1377
  if (typeof val === "string") try {
1288
1378
  return JSON.parse(val);
@@ -1297,14 +1387,14 @@ function rowToTask(row) {
1297
1387
  status: String(row.status),
1298
1388
  toolName: String(row.tool_name),
1299
1389
  toolCallId: String(row.tool_call_id),
1300
- args: parseJson$1(row.args) ?? {},
1390
+ args: parseJson$2(row.args) ?? {},
1301
1391
  agentId: String(row.agent_id),
1302
1392
  threadId: row.thread_id != null ? String(row.thread_id) : void 0,
1303
1393
  resourceId: row.resource_id != null ? String(row.resource_id) : void 0,
1304
1394
  runId: String(row.run_id),
1305
- result: parseJson$1(row.result),
1306
- error: parseJson$1(row.error),
1307
- suspendPayload: parseJson$1(row.suspend_payload),
1395
+ result: parseJson$2(row.result),
1396
+ error: parseJson$2(row.error),
1397
+ suspendPayload: parseJson$2(row.suspend_payload),
1308
1398
  retryCount: Number(row.retry_count),
1309
1399
  maxRetries: Number(row.max_retries),
1310
1400
  timeoutMs: Number(row.timeout_ms),
@@ -3732,6 +3822,871 @@ var FavoritesMySQL = class FavoritesMySQL extends _mastra_core_storage.Favorites
3732
3822
  }
3733
3823
  };
3734
3824
  //#endregion
3825
+ //#region src/storage/domains/knowledge/index.ts
3826
+ function mysqlSql(sql) {
3827
+ return sql.replaceAll("jsonb(?)", "CAST(? AS JSON)").replaceAll("INSERT OR IGNORE", "INSERT IGNORE").replaceAll("\"", "`");
3828
+ }
3829
+ function createExecutor(client) {
3830
+ return { async execute(statement) {
3831
+ const sql = typeof statement === "string" ? statement : statement.sql;
3832
+ const args = (typeof statement === "string" ? [] : statement.args ?? []).map((value) => typeof value === "string" && /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/.test(value) ? value.replace("T", " ").replace("Z", "") : value);
3833
+ const [result] = await client.query(mysqlSql(sql), args);
3834
+ if (Array.isArray(result)) return {
3835
+ rows: result,
3836
+ rowsAffected: 0
3837
+ };
3838
+ return {
3839
+ rows: [],
3840
+ rowsAffected: result.affectedRows
3841
+ };
3842
+ } };
3843
+ }
3844
+ const visibleSql = `(scopeKey = ? OR LEFT(?, CHAR_LENGTH(scopeKey) + 1) = CONCAT(scopeKey, char(31)))`;
3845
+ function parseJson$1(value) {
3846
+ if (typeof value === "string") return JSON.parse(value);
3847
+ if (value instanceof Uint8Array) return JSON.parse(new TextDecoder().decode(value));
3848
+ if (value instanceof ArrayBuffer) return JSON.parse(new TextDecoder().decode(value));
3849
+ return value;
3850
+ }
3851
+ function toDate(value) {
3852
+ return value instanceof Date ? new Date(value) : new Date(String(value));
3853
+ }
3854
+ function optionalDate(value) {
3855
+ return value == null ? void 0 : toDate(value);
3856
+ }
3857
+ function databaseTimestamp(value) {
3858
+ const pad = (part, width = 2) => String(part).padStart(width, "0");
3859
+ return `${value.getFullYear()}-${pad(value.getMonth() + 1)}-${pad(value.getDate())} ${pad(value.getHours())}:${pad(value.getMinutes())}:${pad(value.getSeconds())}.${pad(value.getMilliseconds(), 3)}`;
3860
+ }
3861
+ function canonicalName(name) {
3862
+ return name.trim().toLocaleLowerCase();
3863
+ }
3864
+ function nodeReferenceId(node) {
3865
+ return typeof node === "string" ? node : node.id;
3866
+ }
3867
+ function escapeLikePattern(value) {
3868
+ return value.replaceAll("=", "==").replaceAll("%", "=%").replaceAll("_", "=_");
3869
+ }
3870
+ function parseNode(row) {
3871
+ return {
3872
+ id: String(row.id),
3873
+ type: "node",
3874
+ name: String(row.name),
3875
+ kind: String(row.kind),
3876
+ content: row.content == null ? void 0 : String(row.content),
3877
+ scope: parseJson$1(row.scopeJson ?? row.scope),
3878
+ version: Number(row.version),
3879
+ mergedInto: row.mergedInto == null ? void 0 : String(row.mergedInto),
3880
+ createdAt: toDate(row.createdAt),
3881
+ updatedAt: toDate(row.updatedAt)
3882
+ };
3883
+ }
3884
+ function parseKnowledge(row) {
3885
+ return {
3886
+ id: String(row.id),
3887
+ node: String(row.node),
3888
+ text: String(row.text),
3889
+ scope: parseJson$1(row.scopeJson ?? row.scope),
3890
+ sourceThreadId: String(row.sourceThreadId),
3891
+ capturedAt: toDate(row.capturedAt),
3892
+ when: optionalDate(row.when),
3893
+ maxScope: row.maxScope == null ? void 0 : String(row.maxScope),
3894
+ metadata: row.metadata == null ? void 0 : parseJson$1(row.metadata),
3895
+ deletedAt: optionalDate(row.deletedAt),
3896
+ deletedBy: row.deletedBy == null ? void 0 : String(row.deletedBy)
3897
+ };
3898
+ }
3899
+ function parseOutbox(row) {
3900
+ return {
3901
+ id: String(row.id),
3902
+ idempotencyKey: String(row.idempotencyKey),
3903
+ documentId: String(row.documentId),
3904
+ documentType: String(row.documentType),
3905
+ operation: String(row.operation),
3906
+ scope: parseJson$1(row.scopeJson ?? row.scope),
3907
+ status: String(row.status),
3908
+ attempts: Number(row.attempts),
3909
+ availableAt: toDate(row.availableAt),
3910
+ claimedAt: optionalDate(row.claimedAt),
3911
+ claimedBy: row.claimedBy == null ? void 0 : String(row.claimedBy),
3912
+ createdAt: toDate(row.createdAt),
3913
+ completedAt: optionalDate(row.completedAt)
3914
+ };
3915
+ }
3916
+ const KNOWLEDGE_INDEX_DDL = [
3917
+ `CREATE UNIQUE INDEX idx_knowledge_nodes_identity ON "${_mastra_core_storage.TABLE_KNOWLEDGE_NODES}" (type(32), scopeKey(255), canonicalName(255))`,
3918
+ `CREATE INDEX idx_knowledge_nodes_scope ON "${_mastra_core_storage.TABLE_KNOWLEDGE_NODES}" (scopeKey(255), type(32))`,
3919
+ `CREATE INDEX idx_knowledge_records_node_latest ON "${_mastra_core_storage.TABLE_KNOWLEDGE_RECORDS}" (node(191), id(26) DESC)`,
3920
+ `CREATE INDEX idx_knowledge_records_thread_latest ON "${_mastra_core_storage.TABLE_KNOWLEDGE_RECORDS}" (sourceThreadId(191), id(26) DESC)`,
3921
+ `CREATE INDEX idx_knowledge_mentions_record ON "${_mastra_core_storage.TABLE_KNOWLEDGE_MENTIONS}" (recordId(191), sourceType(32), sourceId(191))`,
3922
+ `CREATE INDEX idx_knowledge_activity_latest ON "${_mastra_core_storage.TABLE_KNOWLEDGE_ACTIVITY}" (id(26) DESC)`,
3923
+ `CREATE UNIQUE INDEX idx_knowledge_outbox_idempotency ON "${_mastra_core_storage.TABLE_KNOWLEDGE_SEMANTIC_OUTBOX}" (idempotencyKey(255))`,
3924
+ `CREATE INDEX idx_knowledge_outbox_claim ON "${_mastra_core_storage.TABLE_KNOWLEDGE_SEMANTIC_OUTBOX}" (status(32), availableAt, createdAt)`
3925
+ ];
3926
+ var KnowledgeMySQL = class extends _mastra_core_storage.KnowledgeStorage {
3927
+ static getExportDDL() {
3928
+ return [
3929
+ generateTableSQL({
3930
+ tableName: _mastra_core_storage.TABLE_KNOWLEDGE_NODES,
3931
+ schema: _mastra_core_storage.KNOWLEDGE_NODES_SCHEMA
3932
+ }),
3933
+ generateTableSQL({
3934
+ tableName: _mastra_core_storage.TABLE_KNOWLEDGE_RECORDS,
3935
+ schema: _mastra_core_storage.KNOWLEDGE_RECORDS_SCHEMA
3936
+ }),
3937
+ generateTableSQL({
3938
+ tableName: _mastra_core_storage.TABLE_KNOWLEDGE_MENTIONS,
3939
+ schema: _mastra_core_storage.KNOWLEDGE_MENTIONS_SCHEMA,
3940
+ compositePrimaryKey: [
3941
+ "sourceType",
3942
+ "sourceId",
3943
+ "recordId"
3944
+ ]
3945
+ }),
3946
+ generateTableSQL({
3947
+ tableName: _mastra_core_storage.TABLE_KNOWLEDGE_CURSORS,
3948
+ schema: _mastra_core_storage.KNOWLEDGE_CURSORS_SCHEMA,
3949
+ compositePrimaryKey: ["sourceThreadId", "agent"]
3950
+ }),
3951
+ generateTableSQL({
3952
+ tableName: _mastra_core_storage.TABLE_KNOWLEDGE_ACTIVITY,
3953
+ schema: _mastra_core_storage.KNOWLEDGE_ACTIVITY_SCHEMA
3954
+ }),
3955
+ generateTableSQL({
3956
+ tableName: _mastra_core_storage.TABLE_KNOWLEDGE_SEMANTIC_OUTBOX,
3957
+ schema: _mastra_core_storage.KNOWLEDGE_SEMANTIC_OUTBOX_SCHEMA
3958
+ }),
3959
+ ...KNOWLEDGE_INDEX_DDL.map(mysqlSql)
3960
+ ];
3961
+ }
3962
+ #pool;
3963
+ #client;
3964
+ #operations;
3965
+ constructor({ pool, operations }) {
3966
+ super();
3967
+ this.#pool = pool;
3968
+ this.#client = createExecutor(pool);
3969
+ this.#operations = operations;
3970
+ }
3971
+ async init() {
3972
+ await this.#operations.createTable({
3973
+ tableName: _mastra_core_storage.TABLE_KNOWLEDGE_NODES,
3974
+ schema: _mastra_core_storage.KNOWLEDGE_NODES_SCHEMA
3975
+ });
3976
+ await this.#operations.createTable({
3977
+ tableName: _mastra_core_storage.TABLE_KNOWLEDGE_RECORDS,
3978
+ schema: _mastra_core_storage.KNOWLEDGE_RECORDS_SCHEMA
3979
+ });
3980
+ await this.#operations.createTable({
3981
+ tableName: _mastra_core_storage.TABLE_KNOWLEDGE_MENTIONS,
3982
+ schema: _mastra_core_storage.KNOWLEDGE_MENTIONS_SCHEMA
3983
+ });
3984
+ await this.#operations.createTable({
3985
+ tableName: _mastra_core_storage.TABLE_KNOWLEDGE_CURSORS,
3986
+ schema: _mastra_core_storage.KNOWLEDGE_CURSORS_SCHEMA
3987
+ });
3988
+ await this.#operations.createTable({
3989
+ tableName: _mastra_core_storage.TABLE_KNOWLEDGE_ACTIVITY,
3990
+ schema: _mastra_core_storage.KNOWLEDGE_ACTIVITY_SCHEMA
3991
+ });
3992
+ await this.#operations.createTable({
3993
+ tableName: _mastra_core_storage.TABLE_KNOWLEDGE_SEMANTIC_OUTBOX,
3994
+ schema: _mastra_core_storage.KNOWLEDGE_SEMANTIC_OUTBOX_SCHEMA
3995
+ });
3996
+ for (const sql of KNOWLEDGE_INDEX_DDL) try {
3997
+ await this.#client.execute(sql);
3998
+ } catch (error) {
3999
+ if (error.code !== "ER_DUP_KEYNAME") throw error;
4000
+ }
4001
+ }
4002
+ async dangerouslyClearAll() {
4003
+ await this.#transaction(async (tx) => {
4004
+ for (const table of [
4005
+ _mastra_core_storage.TABLE_KNOWLEDGE_MENTIONS,
4006
+ _mastra_core_storage.TABLE_KNOWLEDGE_RECORDS,
4007
+ _mastra_core_storage.TABLE_KNOWLEDGE_NODES,
4008
+ _mastra_core_storage.TABLE_KNOWLEDGE_CURSORS,
4009
+ _mastra_core_storage.TABLE_KNOWLEDGE_ACTIVITY,
4010
+ _mastra_core_storage.TABLE_KNOWLEDGE_SEMANTIC_OUTBOX
4011
+ ]) await tx.execute(`DELETE FROM "${table}"`);
4012
+ });
4013
+ }
4014
+ async createNode(input) {
4015
+ const scope = (0, _mastra_core_storage.canonicalizeKnowledgeScope)(input.scope);
4016
+ return this.#transaction(async (tx) => {
4017
+ const existing = await this.#getNodeByName(tx, input.name, scope);
4018
+ if (existing) {
4019
+ const terminal = await this.#resolveTerminalNode(tx, existing.id);
4020
+ if (!(0, _mastra_core_storage.isKnowledgeScopeVisible)(terminal.scope, scope)) throw new Error(`Merged knowledge node is not visible from scope: ${input.name}`);
4021
+ return terminal;
4022
+ }
4023
+ const now = /* @__PURE__ */ new Date();
4024
+ const node = {
4025
+ id: input.id ?? crypto.randomUUID(),
4026
+ type: "node",
4027
+ name: input.name.trim(),
4028
+ kind: input.kind,
4029
+ content: input.content,
4030
+ scope,
4031
+ version: 1,
4032
+ createdAt: now,
4033
+ updatedAt: now
4034
+ };
4035
+ await tx.execute({
4036
+ sql: `INSERT INTO "${_mastra_core_storage.TABLE_KNOWLEDGE_NODES}" (id,type,name,canonicalName,kind,content,scope,scopeKey,version,mergedInto,createdAt,updatedAt) VALUES (?,?,?,?,?,?,jsonb(?),?,?,NULL,?,?)`,
4037
+ args: [
4038
+ node.id,
4039
+ "node",
4040
+ node.name,
4041
+ canonicalName(node.name),
4042
+ node.kind,
4043
+ node.content ?? null,
4044
+ JSON.stringify(scope),
4045
+ (0, _mastra_core_storage.knowledgeScopeKey)(scope),
4046
+ node.version,
4047
+ now.toISOString(),
4048
+ now.toISOString()
4049
+ ]
4050
+ });
4051
+ await this.#replaceMentions(tx, "node", node.id, node.content ?? "", input.resolutionScope ?? scope, scope);
4052
+ await this.#activity(tx, "node-created", "node", node.id, scope);
4053
+ await this.#outbox(tx, "node", node.id, "upsert", node.version, scope);
4054
+ return node;
4055
+ });
4056
+ }
4057
+ async getNode(id) {
4058
+ return this.#getNode(this.#client, id);
4059
+ }
4060
+ async getNodeByName(input) {
4061
+ return this.#getNodeByName(this.#client, input.name, (0, _mastra_core_storage.canonicalizeKnowledgeScope)(input.scope));
4062
+ }
4063
+ async resolveNode(input) {
4064
+ return this.#resolveNode(this.#client, input.name, (0, _mastra_core_storage.canonicalizeKnowledgeScope)(input.scope));
4065
+ }
4066
+ async listNodes(input) {
4067
+ const key = (0, _mastra_core_storage.knowledgeScopeKey)((0, _mastra_core_storage.canonicalizeKnowledgeScope)(input.scope));
4068
+ const clauses = [
4069
+ `type = 'node'`,
4070
+ "mergedInto IS NULL",
4071
+ visibleSql
4072
+ ];
4073
+ const args = [key, key];
4074
+ if (input.namePrefix) {
4075
+ clauses.push("canonicalName LIKE ? ESCAPE '='");
4076
+ args.push(`${escapeLikePattern(canonicalName(input.namePrefix))}%`);
4077
+ }
4078
+ if (input.kind) {
4079
+ clauses.push("kind = ?");
4080
+ args.push(input.kind);
4081
+ }
4082
+ if (input.hasContent !== void 0) clauses.push(input.hasContent ? "content IS NOT NULL AND content <> ''" : "(content IS NULL OR content = '')");
4083
+ if (input.cursor) {
4084
+ const cursor = (0, _mastra_core_storage.parseKnowledgeNodeCursor)(input.cursor, {
4085
+ namePrefix: input.namePrefix,
4086
+ kind: input.kind,
4087
+ hasContent: input.hasContent
4088
+ });
4089
+ const updatedAt = databaseTimestamp(cursor.updatedAt);
4090
+ clauses.push("(updatedAt < ? OR (updatedAt = ? AND (name > ? OR (name = ? AND id > ?))))");
4091
+ args.push(updatedAt, updatedAt, cursor.name, cursor.name, cursor.id);
4092
+ }
4093
+ args.push(input.limit ?? 100);
4094
+ return (await this.#client.execute({
4095
+ sql: `SELECT *, scope AS scopeJson FROM "${_mastra_core_storage.TABLE_KNOWLEDGE_NODES}" WHERE ${clauses.join(" AND ")} ORDER BY updatedAt DESC, name ASC, id ASC LIMIT ?`,
4096
+ args
4097
+ })).rows.map(parseNode);
4098
+ }
4099
+ async updateNode(input) {
4100
+ return this.#transaction(async (tx) => {
4101
+ const existing = await this.#getNode(tx, input.id);
4102
+ if (!existing) throw new _mastra_core_storage.KnowledgeNotFoundError("node", input.id);
4103
+ if (existing.mergedInto) throw new Error(`Cannot update merged knowledge node: ${input.id}`);
4104
+ const scope = (0, _mastra_core_storage.canonicalizeKnowledgeScope)(input.scope ?? existing.scope);
4105
+ const name = (input.name ?? existing.name).trim();
4106
+ const content = input.content ?? existing.content;
4107
+ const now = /* @__PURE__ */ new Date();
4108
+ if ((await tx.execute({
4109
+ sql: `UPDATE "${_mastra_core_storage.TABLE_KNOWLEDGE_NODES}" SET name=?,canonicalName=?,kind=?,content=?,scope=jsonb(?),scopeKey=?,version=version+1,updatedAt=? WHERE id=? AND type='node' AND version=?`,
4110
+ args: [
4111
+ name,
4112
+ canonicalName(name),
4113
+ input.kind ?? existing.kind,
4114
+ content ?? null,
4115
+ JSON.stringify(scope),
4116
+ (0, _mastra_core_storage.knowledgeScopeKey)(scope),
4117
+ now.toISOString(),
4118
+ input.id,
4119
+ input.version
4120
+ ]
4121
+ })).rowsAffected === 0) throw new _mastra_core_storage.KnowledgeConflictError(input.id);
4122
+ 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);
4123
+ await this.#activity(tx, "node-updated", "node", input.id, scope);
4124
+ if ((0, _mastra_core_storage.knowledgeScopeKey)(existing.scope) !== (0, _mastra_core_storage.knowledgeScopeKey)(scope)) {
4125
+ await this.#outbox(tx, "node", input.id, "delete", (0, _mastra_core_storage.createKnowledgeUlid)(), existing.scope);
4126
+ const records = await tx.execute({
4127
+ sql: `SELECT id,scope AS scopeJson,deletedAt FROM "${_mastra_core_storage.TABLE_KNOWLEDGE_RECORDS}" WHERE node=?`,
4128
+ args: [input.id]
4129
+ });
4130
+ for (const row of records.rows) {
4131
+ const factScope = parseJson$1(row.scopeJson);
4132
+ await this.#outbox(tx, "record", String(row.id), "delete", (0, _mastra_core_storage.createKnowledgeUlid)(), factScope);
4133
+ if (row.deletedAt == null) await this.#outbox(tx, "record", String(row.id), "upsert", (0, _mastra_core_storage.createKnowledgeUlid)(), factScope);
4134
+ }
4135
+ }
4136
+ await this.#outbox(tx, "node", input.id, "upsert", input.version + 1, scope);
4137
+ return {
4138
+ ...existing,
4139
+ name,
4140
+ kind: input.kind ?? existing.kind,
4141
+ content,
4142
+ scope,
4143
+ version: input.version + 1,
4144
+ updatedAt: now
4145
+ };
4146
+ });
4147
+ }
4148
+ async mergeNodes(input) {
4149
+ if (input.sourceId === input.targetId) throw new Error("Cannot merge a knowledge node into itself");
4150
+ return this.#transaction(async (tx) => {
4151
+ const source = await this.#getNode(tx, input.sourceId);
4152
+ if (!source) throw new _mastra_core_storage.KnowledgeNotFoundError("node", input.sourceId);
4153
+ const target = await this.#resolveTerminalNode(tx, input.targetId);
4154
+ if (!target) throw new _mastra_core_storage.KnowledgeNotFoundError("node", input.targetId);
4155
+ if (target.id === source.id) throw new Error("Cannot create a knowledge merge cycle");
4156
+ if (!(0, _mastra_core_storage.isKnowledgeScopeVisible)(target.scope, source.scope)) throw new Error("Cannot merge a knowledge node into a target that is narrower than its source scope");
4157
+ const affected = await tx.execute({
4158
+ sql: `SELECT DISTINCT m.sourceType,m.sourceId,COALESCE(f.scope,r.scope) AS scopeJson,CASE WHEN f.deletedAt IS NULL THEN 0 ELSE 1 END AS deleted FROM "${_mastra_core_storage.TABLE_KNOWLEDGE_MENTIONS}" m LEFT JOIN "${_mastra_core_storage.TABLE_KNOWLEDGE_RECORDS}" f ON m.sourceType='record' AND f.id=m.sourceId LEFT JOIN "${_mastra_core_storage.TABLE_KNOWLEDGE_NODES}" r ON m.sourceType='node' AND r.id=m.sourceId WHERE m.recordId=?`,
4159
+ args: [source.id]
4160
+ });
4161
+ const movedFacts = await tx.execute({
4162
+ sql: `SELECT id,scope AS scopeJson,deletedAt FROM "${_mastra_core_storage.TABLE_KNOWLEDGE_RECORDS}" WHERE node=?`,
4163
+ args: [source.id]
4164
+ });
4165
+ if ((await tx.execute({
4166
+ sql: `UPDATE "${_mastra_core_storage.TABLE_KNOWLEDGE_NODES}" SET mergedInto=?,version=version+1,updatedAt=? WHERE id=? AND type='node' AND version=? AND mergedInto IS NULL`,
4167
+ args: [
4168
+ target.id,
4169
+ (/* @__PURE__ */ new Date()).toISOString(),
4170
+ source.id,
4171
+ input.sourceVersion
4172
+ ]
4173
+ })).rowsAffected === 0) throw new _mastra_core_storage.KnowledgeConflictError(source.id);
4174
+ await tx.execute({
4175
+ sql: `UPDATE "${_mastra_core_storage.TABLE_KNOWLEDGE_RECORDS}" SET node=? WHERE node=?`,
4176
+ args: [target.id, source.id]
4177
+ });
4178
+ await tx.execute({
4179
+ sql: `DELETE source FROM "${_mastra_core_storage.TABLE_KNOWLEDGE_MENTIONS}" source JOIN "${_mastra_core_storage.TABLE_KNOWLEDGE_MENTIONS}" target ON target.sourceType=source.sourceType AND target.sourceId=source.sourceId WHERE source.recordId=? AND target.recordId=?`,
4180
+ args: [source.id, target.id]
4181
+ });
4182
+ await tx.execute({
4183
+ sql: `UPDATE "${_mastra_core_storage.TABLE_KNOWLEDGE_MENTIONS}" SET recordId=? WHERE recordId=?`,
4184
+ args: [target.id, source.id]
4185
+ });
4186
+ for (const row of movedFacts.rows) await this.#outbox(tx, "record", String(row.id), row.deletedAt == null ? "upsert" : "delete", (0, _mastra_core_storage.createKnowledgeUlid)(), parseJson$1(row.scopeJson));
4187
+ for (const row of affected.rows) await this.#outbox(tx, String(row.sourceType), String(row.sourceId), Number(row.deleted) ? "delete" : "upsert", (0, _mastra_core_storage.createKnowledgeUlid)(), parseJson$1(row.scopeJson));
4188
+ await this.#activity(tx, "node-merged", "node", source.id, source.scope);
4189
+ await this.#outbox(tx, "node", source.id, "delete", input.sourceVersion + 1, source.scope);
4190
+ await this.#outbox(tx, "node", target.id, "upsert", (0, _mastra_core_storage.createKnowledgeUlid)(), target.scope);
4191
+ return target;
4192
+ });
4193
+ }
4194
+ async appendKnowledge(input) {
4195
+ const scope = (0, _mastra_core_storage.canonicalizeKnowledgeScope)(input.scope);
4196
+ const resolutionScope = (0, _mastra_core_storage.canonicalizeKnowledgeScope)(input.resolutionScope);
4197
+ const defaultScope = (0, _mastra_core_storage.canonicalizeKnowledgeScope)(input.defaultScope);
4198
+ (0, _mastra_core_storage.assertKnowledgeScopeWithinCeiling)(scope, input.maxScope);
4199
+ return this.#transaction(async (tx) => {
4200
+ const parent = await this.#resolveTerminalNode(tx, nodeReferenceId(input.node));
4201
+ if (!parent) throw new _mastra_core_storage.KnowledgeNotFoundError("node", nodeReferenceId(input.node));
4202
+ const record = {
4203
+ id: input.id ?? (0, _mastra_core_storage.createKnowledgeUlid)(),
4204
+ node: parent.id,
4205
+ text: input.text,
4206
+ scope,
4207
+ sourceThreadId: input.sourceThreadId,
4208
+ capturedAt: /* @__PURE__ */ new Date(),
4209
+ when: input.when ? new Date(input.when) : void 0,
4210
+ maxScope: input.maxScope,
4211
+ metadata: input.metadata
4212
+ };
4213
+ await tx.execute({
4214
+ 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)`,
4215
+ args: [
4216
+ record.id,
4217
+ record.node,
4218
+ record.text,
4219
+ JSON.stringify(scope),
4220
+ (0, _mastra_core_storage.knowledgeScopeKey)(scope),
4221
+ record.sourceThreadId,
4222
+ record.capturedAt.toISOString(),
4223
+ record.when?.toISOString() ?? null,
4224
+ record.maxScope ?? null,
4225
+ record.metadata ? JSON.stringify(record.metadata) : null
4226
+ ]
4227
+ });
4228
+ await this.#replaceMentions(tx, "record", record.id, record.text, resolutionScope, defaultScope);
4229
+ await this.#activity(tx, "record-created", "record", record.id, scope, record.sourceThreadId);
4230
+ await this.#outbox(tx, "record", record.id, "upsert", record.id, scope);
4231
+ return record;
4232
+ });
4233
+ }
4234
+ async getKnowledge(input) {
4235
+ const result = await this.#client.execute({
4236
+ sql: `SELECT *,scope AS scopeJson FROM "${_mastra_core_storage.TABLE_KNOWLEDGE_RECORDS}" WHERE id=?${input.includeDeleted ? "" : " AND deletedAt IS NULL"}`,
4237
+ args: [input.id]
4238
+ });
4239
+ return result.rows[0] ? parseKnowledge(result.rows[0]) : null;
4240
+ }
4241
+ async listKnowledgeAbout(input) {
4242
+ return this.#queryKnowledge(input, "about");
4243
+ }
4244
+ async listKnowledgeMentioning(input) {
4245
+ return this.#queryKnowledge(input, "mentioning");
4246
+ }
4247
+ async listKnowledgeRelatedTo(input) {
4248
+ return this.#queryKnowledge(input, "related");
4249
+ }
4250
+ async knowledgeBySource(input) {
4251
+ const key = (0, _mastra_core_storage.knowledgeScopeKey)((0, _mastra_core_storage.canonicalizeKnowledgeScope)(input.scope));
4252
+ const args = [
4253
+ input.sourceThreadId,
4254
+ key,
4255
+ key
4256
+ ];
4257
+ if (input.after) args.push(input.after);
4258
+ const limit = input.limit ?? 100;
4259
+ args.push(limit + 1);
4260
+ const records = (await this.#client.execute({
4261
+ 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 ?`,
4262
+ args
4263
+ })).rows.map(parseKnowledge);
4264
+ return {
4265
+ records: records.slice(0, limit),
4266
+ nextCursor: records.length > limit ? records[limit - 1]?.id : void 0
4267
+ };
4268
+ }
4269
+ async removeKnowledge(input) {
4270
+ return this.#transaction(async (tx) => {
4271
+ const record = await this.#getKnowledge(tx, input.id, true);
4272
+ if (!record) throw new _mastra_core_storage.KnowledgeNotFoundError("record", input.id);
4273
+ if (record.deletedAt) return record;
4274
+ const deletedAt = /* @__PURE__ */ new Date();
4275
+ await tx.execute({
4276
+ sql: `UPDATE "${_mastra_core_storage.TABLE_KNOWLEDGE_RECORDS}" SET deletedAt=?,deletedBy=? WHERE id=? AND deletedAt IS NULL`,
4277
+ args: [
4278
+ deletedAt.toISOString(),
4279
+ input.deletedBy,
4280
+ input.id
4281
+ ]
4282
+ });
4283
+ await this.#activity(tx, "record-deleted", "record", input.id, record.scope, record.sourceThreadId);
4284
+ await this.#outbox(tx, "record", input.id, "delete", deletedAt.toISOString(), record.scope);
4285
+ return {
4286
+ ...record,
4287
+ deletedAt,
4288
+ deletedBy: input.deletedBy
4289
+ };
4290
+ });
4291
+ }
4292
+ async restoreKnowledge(input) {
4293
+ return this.#transaction(async (tx) => {
4294
+ const record = await this.#getKnowledge(tx, input.id, true);
4295
+ if (!record) throw new _mastra_core_storage.KnowledgeNotFoundError("record", input.id);
4296
+ if (!record.deletedAt) return record;
4297
+ await tx.execute({
4298
+ sql: `UPDATE "${_mastra_core_storage.TABLE_KNOWLEDGE_RECORDS}" SET deletedAt=NULL,deletedBy=NULL WHERE id=?`,
4299
+ args: [input.id]
4300
+ });
4301
+ await this.#activity(tx, "record-restored", "record", input.id, record.scope, record.sourceThreadId);
4302
+ await this.#outbox(tx, "record", input.id, "upsert", (0, _mastra_core_storage.createKnowledgeUlid)(), record.scope);
4303
+ return {
4304
+ ...record,
4305
+ deletedAt: void 0,
4306
+ deletedBy: void 0
4307
+ };
4308
+ });
4309
+ }
4310
+ async rescopeKnowledge(input) {
4311
+ const scope = (0, _mastra_core_storage.canonicalizeKnowledgeScope)(input.scope);
4312
+ return this.#transaction(async (tx) => {
4313
+ const record = await this.#getKnowledge(tx, input.id, true);
4314
+ if (!record) throw new _mastra_core_storage.KnowledgeNotFoundError("record", input.id);
4315
+ (0, _mastra_core_storage.assertKnowledgeScopeWithinCeiling)(scope, record.maxScope);
4316
+ await tx.execute({
4317
+ sql: `UPDATE "${_mastra_core_storage.TABLE_KNOWLEDGE_RECORDS}" SET scope=jsonb(?),scopeKey=? WHERE id=?`,
4318
+ args: [
4319
+ JSON.stringify(scope),
4320
+ (0, _mastra_core_storage.knowledgeScopeKey)(scope),
4321
+ input.id
4322
+ ]
4323
+ });
4324
+ await this.#activity(tx, "record-rescoped", "record", input.id, scope, record.sourceThreadId);
4325
+ 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);
4326
+ if (!record.deletedAt) await this.#outbox(tx, "record", input.id, "upsert", (0, _mastra_core_storage.createKnowledgeUlid)(), scope);
4327
+ return {
4328
+ ...record,
4329
+ scope
4330
+ };
4331
+ });
4332
+ }
4333
+ async raiseKnowledgeCeiling(input) {
4334
+ return this.#transaction(async (tx) => {
4335
+ const record = await this.#getKnowledge(tx, input.id, true);
4336
+ if (!record) throw new _mastra_core_storage.KnowledgeNotFoundError("record", input.id);
4337
+ (0, _mastra_core_storage.assertKnowledgeScopeWithinCeiling)(record.scope, input.maxScope);
4338
+ (0, _mastra_core_storage.assertKnowledgeCeilingRaised)(record.maxScope, input.maxScope);
4339
+ await tx.execute({
4340
+ sql: `UPDATE "${_mastra_core_storage.TABLE_KNOWLEDGE_RECORDS}" SET maxScope=? WHERE id=?`,
4341
+ args: [input.maxScope ?? null, input.id]
4342
+ });
4343
+ return {
4344
+ ...record,
4345
+ maxScope: input.maxScope
4346
+ };
4347
+ });
4348
+ }
4349
+ async search(input) {
4350
+ const scope = (0, _mastra_core_storage.canonicalizeKnowledgeScope)(input.scope);
4351
+ const key = (0, _mastra_core_storage.knowledgeScopeKey)(scope);
4352
+ const normalizedQuery = input.query.trim().toLocaleLowerCase();
4353
+ if (!normalizedQuery) return [];
4354
+ const query = `%${escapeLikePattern(normalizedQuery)}%`;
4355
+ const results = (await this.#client.execute({
4356
+ 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 '=') ORDER BY updatedAt DESC LIMIT ?`,
4357
+ args: [
4358
+ key,
4359
+ key,
4360
+ query,
4361
+ query,
4362
+ query,
4363
+ input.limit ?? 20
4364
+ ]
4365
+ })).rows.map((row) => ({
4366
+ type: String(row.type),
4367
+ id: String(row.id),
4368
+ recordId: String(row.id),
4369
+ name: String(row.name),
4370
+ text: row.content ? `${String(row.name)}\n${String(row.content)}` : String(row.name),
4371
+ scope: parseJson$1(row.scopeJson)
4372
+ }));
4373
+ if (results.length < (input.limit ?? 20)) {
4374
+ const records = await this.#client.execute({
4375
+ 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 ?`,
4376
+ args: [
4377
+ key,
4378
+ key,
4379
+ query,
4380
+ (input.limit ?? 20) - results.length
4381
+ ]
4382
+ });
4383
+ results.push(...records.rows.map((row) => {
4384
+ const parentVisible = (0, _mastra_core_storage.isKnowledgeScopeVisible)(parseJson$1(row.parentScopeJson), scope);
4385
+ return {
4386
+ type: "record",
4387
+ id: String(row.id),
4388
+ recordId: String(row.node),
4389
+ name: parentVisible ? String(row.name) : "(private node)",
4390
+ text: String(row.text),
4391
+ scope: parseJson$1(row.scopeJson)
4392
+ };
4393
+ }));
4394
+ }
4395
+ return results;
4396
+ }
4397
+ async getCurationCursor(input) {
4398
+ const row = (await this.#client.execute({
4399
+ sql: `SELECT * FROM "${_mastra_core_storage.TABLE_KNOWLEDGE_CURSORS}" WHERE sourceThreadId=? AND agent=?`,
4400
+ args: [input.sourceThreadId, input.agent]
4401
+ })).rows[0];
4402
+ return row ? {
4403
+ sourceThreadId: String(row.sourceThreadId),
4404
+ agent: String(row.agent),
4405
+ lastKnowledgeId: String(row.lastKnowledgeId),
4406
+ updatedAt: toDate(row.updatedAt)
4407
+ } : null;
4408
+ }
4409
+ async advanceCurationCursor(input) {
4410
+ const updatedAt = /* @__PURE__ */ new Date();
4411
+ if ((await this.#client.execute({
4412
+ sql: `INSERT INTO "${_mastra_core_storage.TABLE_KNOWLEDGE_CURSORS}" (sourceThreadId,agent,lastKnowledgeId,updatedAt) VALUES (?,?,?,?) ON DUPLICATE KEY UPDATE lastKnowledgeId=IF(VALUES(lastKnowledgeId) >= lastKnowledgeId, VALUES(lastKnowledgeId), lastKnowledgeId),updatedAt=IF(VALUES(lastKnowledgeId) >= lastKnowledgeId, VALUES(updatedAt), updatedAt)`,
4413
+ args: [
4414
+ input.sourceThreadId,
4415
+ input.agent,
4416
+ input.lastKnowledgeId,
4417
+ updatedAt.toISOString()
4418
+ ]
4419
+ })).rowsAffected === 0) throw new Error("Knowledge curation cursor cannot move backwards");
4420
+ return {
4421
+ ...input,
4422
+ updatedAt
4423
+ };
4424
+ }
4425
+ async listActivity(input) {
4426
+ const key = (0, _mastra_core_storage.knowledgeScopeKey)((0, _mastra_core_storage.canonicalizeKnowledgeScope)(input.scope));
4427
+ return (await this.#client.execute({
4428
+ sql: `SELECT *,scope AS scopeJson FROM "${_mastra_core_storage.TABLE_KNOWLEDGE_ACTIVITY}" WHERE ${visibleSql}${input.after ? " AND id < ?" : ""} ORDER BY id DESC LIMIT ?`,
4429
+ args: [
4430
+ key,
4431
+ key,
4432
+ ...input.after ? [input.after] : [],
4433
+ input.limit ?? 100
4434
+ ]
4435
+ })).rows.map((row) => ({
4436
+ id: String(row.id),
4437
+ action: String(row.action),
4438
+ recordType: String(row.recordType),
4439
+ recordId: String(row.recordId),
4440
+ scope: parseJson$1(row.scopeJson),
4441
+ sourceThreadId: row.sourceThreadId == null ? void 0 : String(row.sourceThreadId),
4442
+ createdAt: toDate(row.createdAt)
4443
+ }));
4444
+ }
4445
+ async listSemanticOutbox(input = {}) {
4446
+ const clauses = [];
4447
+ const args = [];
4448
+ if (input.status) {
4449
+ clauses.push("status=?");
4450
+ args.push(input.status);
4451
+ }
4452
+ if (input.scope) {
4453
+ const key = (0, _mastra_core_storage.knowledgeScopeKey)((0, _mastra_core_storage.canonicalizeKnowledgeScope)(input.scope));
4454
+ clauses.push(visibleSql);
4455
+ args.push(key, key);
4456
+ }
4457
+ args.push(input.limit ?? 100);
4458
+ return (await this.#client.execute({
4459
+ sql: `SELECT *,scope AS scopeJson FROM "${_mastra_core_storage.TABLE_KNOWLEDGE_SEMANTIC_OUTBOX}"${clauses.length ? ` WHERE ${clauses.join(" AND ")}` : ""} ORDER BY createdAt ASC,id ASC LIMIT ?`,
4460
+ args
4461
+ })).rows.map(parseOutbox);
4462
+ }
4463
+ async claimSemanticOutbox(input) {
4464
+ const now = input.now ?? /* @__PURE__ */ new Date();
4465
+ const stale = new Date(now.getTime() - (input.claimTimeoutMs ?? 6e4));
4466
+ return this.#transaction(async (tx) => {
4467
+ const clauses = [
4468
+ `availableAt <= ?`,
4469
+ `(status='pending' OR (status='processing' AND claimedAt <= ?))`,
4470
+ `NOT EXISTS (SELECT 1 FROM "${_mastra_core_storage.TABLE_KNOWLEDGE_SEMANTIC_OUTBOX}" AS earlier WHERE earlier.documentId = "${_mastra_core_storage.TABLE_KNOWLEDGE_SEMANTIC_OUTBOX}".documentId AND earlier.status != 'completed' AND (earlier.createdAt < "${_mastra_core_storage.TABLE_KNOWLEDGE_SEMANTIC_OUTBOX}".createdAt OR (earlier.createdAt = "${_mastra_core_storage.TABLE_KNOWLEDGE_SEMANTIC_OUTBOX}".createdAt AND earlier.id < "${_mastra_core_storage.TABLE_KNOWLEDGE_SEMANTIC_OUTBOX}".id)))`
4471
+ ];
4472
+ const args = [now.toISOString(), stale.toISOString()];
4473
+ if (input.scope) {
4474
+ const key = (0, _mastra_core_storage.knowledgeScopeKey)((0, _mastra_core_storage.canonicalizeKnowledgeScope)(input.scope));
4475
+ clauses.push(visibleSql);
4476
+ args.push(key, key);
4477
+ }
4478
+ args.push(input.limit ?? 100);
4479
+ const ids = (await tx.execute({
4480
+ sql: `SELECT id FROM "${_mastra_core_storage.TABLE_KNOWLEDGE_SEMANTIC_OUTBOX}" WHERE ${clauses.join(" AND ")} ORDER BY createdAt ASC,id ASC LIMIT ? FOR UPDATE SKIP LOCKED`,
4481
+ args
4482
+ })).rows.map((row) => String(row.id));
4483
+ for (const id of ids) await tx.execute({
4484
+ sql: `UPDATE "${_mastra_core_storage.TABLE_KNOWLEDGE_SEMANTIC_OUTBOX}" SET status='processing',attempts=attempts+1,claimedAt=?,claimedBy=? WHERE id=?`,
4485
+ args: [
4486
+ now.toISOString(),
4487
+ input.workerId,
4488
+ id
4489
+ ]
4490
+ });
4491
+ if (!ids.length) return [];
4492
+ return (await tx.execute({
4493
+ sql: `SELECT *,scope AS scopeJson FROM "${_mastra_core_storage.TABLE_KNOWLEDGE_SEMANTIC_OUTBOX}" WHERE id IN (${ids.map(() => "?").join(",")}) ORDER BY createdAt ASC,id ASC`,
4494
+ args: ids
4495
+ })).rows.map(parseOutbox);
4496
+ });
4497
+ }
4498
+ async completeSemanticOutbox(input) {
4499
+ if (!input.ids.length) return;
4500
+ const now = (/* @__PURE__ */ new Date()).toISOString();
4501
+ await this.#transaction(async (tx) => {
4502
+ for (const id of input.ids) await tx.execute({
4503
+ sql: `UPDATE "${_mastra_core_storage.TABLE_KNOWLEDGE_SEMANTIC_OUTBOX}" SET status='completed',completedAt=? WHERE id=? AND status='processing' AND claimedBy=?`,
4504
+ args: [
4505
+ now,
4506
+ id,
4507
+ input.workerId
4508
+ ]
4509
+ });
4510
+ });
4511
+ }
4512
+ async releaseSemanticOutbox(input) {
4513
+ if (!input.ids.length) return;
4514
+ await this.#transaction(async (tx) => {
4515
+ for (const id of input.ids) await tx.execute({
4516
+ sql: `UPDATE "${_mastra_core_storage.TABLE_KNOWLEDGE_SEMANTIC_OUTBOX}" SET status='pending',availableAt=?,claimedAt=NULL,claimedBy=NULL WHERE id=? AND status='processing' AND claimedBy=?`,
4517
+ args: [
4518
+ (input.retryAt ?? /* @__PURE__ */ new Date()).toISOString(),
4519
+ id,
4520
+ input.workerId
4521
+ ]
4522
+ });
4523
+ });
4524
+ }
4525
+ async #transaction(operation) {
4526
+ const connection = await this.#pool.getConnection();
4527
+ try {
4528
+ await connection.beginTransaction();
4529
+ const result = await operation(createExecutor(connection));
4530
+ await connection.commit();
4531
+ return result;
4532
+ } catch (error) {
4533
+ await connection.rollback();
4534
+ throw error;
4535
+ } finally {
4536
+ connection.release();
4537
+ }
4538
+ }
4539
+ async #getNode(executor, id) {
4540
+ const result = await executor.execute({
4541
+ sql: `SELECT *,scope AS scopeJson FROM "${_mastra_core_storage.TABLE_KNOWLEDGE_NODES}" WHERE id=? AND type='node'`,
4542
+ args: [id]
4543
+ });
4544
+ return result.rows[0] ? parseNode(result.rows[0]) : null;
4545
+ }
4546
+ async #getNodeByName(executor, name, scope) {
4547
+ const result = await executor.execute({
4548
+ sql: `SELECT *,scope AS scopeJson FROM "${_mastra_core_storage.TABLE_KNOWLEDGE_NODES}" WHERE type='node' AND scopeKey=? AND canonicalName=?`,
4549
+ args: [(0, _mastra_core_storage.knowledgeScopeKey)(scope), canonicalName(name)]
4550
+ });
4551
+ return result.rows[0] ? parseNode(result.rows[0]) : null;
4552
+ }
4553
+ async #resolveNode(executor, name, scope) {
4554
+ for (let length = scope.length; length > 0; length--) {
4555
+ const node = await this.#getNodeByName(executor, name, scope.slice(0, length));
4556
+ if (node) {
4557
+ const terminal = await this.#resolveTerminalNode(executor, node.id);
4558
+ if (terminal && (0, _mastra_core_storage.isKnowledgeScopeVisible)(terminal.scope, scope)) return terminal;
4559
+ }
4560
+ }
4561
+ return null;
4562
+ }
4563
+ async #resolveTerminalNode(executor, id) {
4564
+ let node = await this.#getNode(executor, id);
4565
+ const seen = /* @__PURE__ */ new Set();
4566
+ while (node?.mergedInto) {
4567
+ if (seen.has(node.id)) throw new Error(`Knowledge merge cycle detected at ${node.id}`);
4568
+ seen.add(node.id);
4569
+ node = await this.#getNode(executor, node.mergedInto);
4570
+ }
4571
+ return node;
4572
+ }
4573
+ async #getKnowledge(executor, id, includeDeleted) {
4574
+ const result = await executor.execute({
4575
+ sql: `SELECT *,scope AS scopeJson FROM "${_mastra_core_storage.TABLE_KNOWLEDGE_RECORDS}" WHERE id=?${includeDeleted ? "" : " AND deletedAt IS NULL"}`,
4576
+ args: [id]
4577
+ });
4578
+ return result.rows[0] ? parseKnowledge(result.rows[0]) : null;
4579
+ }
4580
+ async #queryKnowledge(input, relationship) {
4581
+ const scope = (0, _mastra_core_storage.canonicalizeKnowledgeScope)(input.scope);
4582
+ const node = await this.#resolveTerminalNode(this.#client, nodeReferenceId(input.node));
4583
+ if (!node) return { records: [] };
4584
+ const key = (0, _mastra_core_storage.knowledgeScopeKey)(scope);
4585
+ const args = [
4586
+ node.id,
4587
+ ...relationship === "related" ? [node.id] : [],
4588
+ key,
4589
+ key
4590
+ ];
4591
+ if (input.after) args.push(input.after);
4592
+ args.push((input.limit ?? 100) + 1);
4593
+ const records = (await this.#client.execute({
4594
+ 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 ?`,
4595
+ args
4596
+ })).rows.map(parseKnowledge);
4597
+ const limit = input.limit ?? 100;
4598
+ return {
4599
+ records: records.slice(0, limit),
4600
+ nextCursor: records.length > limit ? records[limit - 1]?.id : void 0
4601
+ };
4602
+ }
4603
+ async #replaceMentions(tx, sourceType, sourceId, text, resolutionScope, defaultScope) {
4604
+ await tx.execute({
4605
+ sql: `DELETE FROM "${_mastra_core_storage.TABLE_KNOWLEDGE_MENTIONS}" WHERE sourceType=? AND sourceId=?`,
4606
+ args: [sourceType, sourceId]
4607
+ });
4608
+ for (const name of (0, _mastra_core_storage.parseKnowledgeWikilinks)(text)) {
4609
+ let node = await this.#resolveNode(tx, name, resolutionScope);
4610
+ if (!node) {
4611
+ node = await this.#getNodeByName(tx, name, defaultScope);
4612
+ if (node) node = await this.#resolveTerminalNode(tx, node.id);
4613
+ if (!node) {
4614
+ const now = /* @__PURE__ */ new Date();
4615
+ node = {
4616
+ id: crypto.randomUUID(),
4617
+ type: "node",
4618
+ name,
4619
+ kind: "node",
4620
+ scope: defaultScope,
4621
+ version: 1,
4622
+ createdAt: now,
4623
+ updatedAt: now
4624
+ };
4625
+ await tx.execute({
4626
+ 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,?,?)`,
4627
+ args: [
4628
+ node.id,
4629
+ "node",
4630
+ node.name,
4631
+ canonicalName(node.name),
4632
+ node.kind,
4633
+ JSON.stringify(defaultScope),
4634
+ (0, _mastra_core_storage.knowledgeScopeKey)(defaultScope),
4635
+ 1,
4636
+ now.toISOString()
4637
+ ]
4638
+ });
4639
+ await this.#activity(tx, "node-created", "node", node.id, defaultScope);
4640
+ await this.#outbox(tx, "node", node.id, "upsert", 1, defaultScope);
4641
+ }
4642
+ }
4643
+ await tx.execute({
4644
+ sql: `INSERT OR IGNORE INTO "${_mastra_core_storage.TABLE_KNOWLEDGE_MENTIONS}" (sourceType,sourceId,recordId) VALUES (?,?,?)`,
4645
+ args: [
4646
+ sourceType,
4647
+ sourceId,
4648
+ node.id
4649
+ ]
4650
+ });
4651
+ }
4652
+ }
4653
+ async #activity(executor, action, recordType, recordId, scope, sourceThreadId) {
4654
+ const now = /* @__PURE__ */ new Date();
4655
+ await executor.execute({
4656
+ sql: `INSERT INTO "${_mastra_core_storage.TABLE_KNOWLEDGE_ACTIVITY}" (id,action,recordType,recordId,scope,scopeKey,sourceThreadId,createdAt) VALUES (?,?,?,?,jsonb(?),?,?,?)`,
4657
+ args: [
4658
+ (0, _mastra_core_storage.createKnowledgeUlid)(),
4659
+ action,
4660
+ recordType,
4661
+ recordId,
4662
+ JSON.stringify(scope),
4663
+ (0, _mastra_core_storage.knowledgeScopeKey)(scope),
4664
+ sourceThreadId ?? null,
4665
+ now.toISOString()
4666
+ ]
4667
+ });
4668
+ }
4669
+ async #outbox(executor, documentType, id, operation, version, scope) {
4670
+ const documentId = (0, _mastra_core_storage.knowledgeSemanticDocumentId)(documentType, id);
4671
+ const idempotencyKey = (0, _mastra_core_storage.knowledgeSemanticIdempotencyKey)(documentId, operation, version);
4672
+ const now = /* @__PURE__ */ new Date();
4673
+ await executor.execute({
4674
+ sql: `INSERT OR IGNORE INTO "${_mastra_core_storage.TABLE_KNOWLEDGE_SEMANTIC_OUTBOX}" (id,idempotencyKey,documentId,documentType,operation,scope,scopeKey,status,attempts,availableAt,claimedAt,claimedBy,createdAt,completedAt) VALUES (?,?,?,?,?,jsonb(?),?,'pending',0,?,NULL,NULL,?,NULL)`,
4675
+ args: [
4676
+ (0, _mastra_core_storage.createKnowledgeUlid)(),
4677
+ idempotencyKey,
4678
+ documentId,
4679
+ documentType,
4680
+ operation,
4681
+ JSON.stringify(scope),
4682
+ (0, _mastra_core_storage.knowledgeScopeKey)(scope),
4683
+ now.toISOString(),
4684
+ now.toISOString()
4685
+ ]
4686
+ });
4687
+ }
4688
+ };
4689
+ //#endregion
3735
4690
  //#region src/storage/domains/mcp-clients/index.ts
3736
4691
  var MCPClientsMySQL = class MCPClientsMySQL extends _mastra_core_storage.MCPClientsStorage {
3737
4692
  pool;
@@ -4836,10 +5791,14 @@ var MemoryMySQL = class MemoryMySQL extends _mastra_core_storage.MemoryStorage {
4836
5791
  schema: _mastra_core_storage.TABLE_SCHEMAS[_mastra_core_storage.TABLE_MESSAGES],
4837
5792
  ifNotExists: ["resourceId"]
4838
5793
  });
4839
- if (omSchema) try {
4840
- await this.pool.execute(`CREATE INDEX idx_om_lookup_key ON ${OM_TABLE_QUOTED} (${quoteIdentifier("lookupKey", "column name")}(191))`);
4841
- } catch (err) {
4842
- if (err?.errno !== 1061) throw err;
5794
+ if (omSchema) {
5795
+ const snapshot = this.operations.getInitSchemaSnapshot();
5796
+ if (!snapshot?.indexes.has(indexKey(OM_TABLE, "idx_om_lookup_key"))) try {
5797
+ await this.pool.execute(`CREATE INDEX idx_om_lookup_key ON ${OM_TABLE_QUOTED} (${quoteIdentifier("lookupKey", "column name")}(191))`);
5798
+ snapshot?.indexes.add(indexKey(OM_TABLE, "idx_om_lookup_key"));
5799
+ } catch (err) {
5800
+ if (err?.errno !== 1061) throw err;
5801
+ }
4843
5802
  }
4844
5803
  await this.createDefaultIndexes();
4845
5804
  await this.createCustomIndexes();
@@ -10358,6 +11317,7 @@ function parseConnectionString(connectionString, overrides) {
10358
11317
  }
10359
11318
  var MySQLStore = class extends _mastra_core_storage.MastraCompositeStore {
10360
11319
  pool;
11320
+ operations;
10361
11321
  stores;
10362
11322
  constructor(config) {
10363
11323
  super({
@@ -10372,12 +11332,17 @@ var MySQLStore = class extends _mastra_core_storage.MastraCompositeStore {
10372
11332
  pool: this.pool,
10373
11333
  database
10374
11334
  });
11335
+ this.operations = operations;
10375
11336
  const memory = new MemoryMySQL({
10376
11337
  pool: this.pool,
10377
11338
  operations,
10378
11339
  skipDefaultIndexes: config.skipDefaultIndexes,
10379
11340
  indexes: config.indexes
10380
11341
  });
11342
+ const knowledge = new KnowledgeMySQL({
11343
+ pool: this.pool,
11344
+ operations
11345
+ });
10381
11346
  const workflows = new WorkflowsMySQL({
10382
11347
  operations,
10383
11348
  pool: this.pool,
@@ -10490,6 +11455,7 @@ var MySQLStore = class extends _mastra_core_storage.MastraCompositeStore {
10490
11455
  });
10491
11456
  this.stores = {
10492
11457
  memory,
11458
+ knowledge,
10493
11459
  workflows,
10494
11460
  scores,
10495
11461
  observability,
@@ -10514,6 +11480,7 @@ var MySQLStore = class extends _mastra_core_storage.MastraCompositeStore {
10514
11480
  async init() {
10515
11481
  try {
10516
11482
  (await this.pool.getConnection()).release();
11483
+ await this.operations.loadInitSchemaSnapshot();
10517
11484
  await super.init();
10518
11485
  } catch (error) {
10519
11486
  throw new _mastra_core_error.MastraError({
@@ -10521,6 +11488,8 @@ var MySQLStore = class extends _mastra_core_storage.MastraCompositeStore {
10521
11488
  domain: _mastra_core_error.ErrorDomain.STORAGE,
10522
11489
  category: _mastra_core_error.ErrorCategory.THIRD_PARTY
10523
11490
  }, error);
11491
+ } finally {
11492
+ this.operations.clearInitSchemaSnapshot();
10524
11493
  }
10525
11494
  }
10526
11495
  async close() {