@mastra/mysql 0.16.0-alpha.0 → 0.16.0-alpha.2

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.
@@ -326,10 +326,20 @@ export interface KnowledgePagesCore {
326
326
  /** Loads core's page-store runtime once, after checking core advertises `knowledge-pages`. */
327
327
  export declare function createKnowledgePagesCoreLoader(features: ReadonlySet<string>, loadStorageModule: () => Promise<unknown>): () => Promise<KnowledgePagesCore>;
328
328
  /**
329
- * Keyword-search words: the query split on whitespace, lowercased, deduplicated. Every word must
330
- * appear (as a case-insensitive substring) in a hit; an empty list means the search returns nothing.
329
+ * Keyword-search words: the query split on whitespace, lowercased, deduplicated. A hit needs at
330
+ * least one of them (as a case-insensitive substring); an empty list means the search returns nothing.
331
331
  */
332
332
  export declare function knowledgeSearchWords(query: string): string[];
333
+ /**
334
+ * Points one matched search word earns on a page, by the best field it appears in: name, then
335
+ * description, then body. Pages rank by how many query words they match first; these points only
336
+ * break ties between pages that match the same number of words.
337
+ */
338
+ export declare const KNOWLEDGE_SEARCH_WEIGHTS: {
339
+ readonly name: 3;
340
+ readonly description: 2;
341
+ readonly body: 1;
342
+ };
333
343
  /**
334
344
  * Why `key` can't be a Knowledge page key, or undefined when it can. Keys are one path segment:
335
345
  * non-empty, with no `/` (path separator), `#` (scope/path separator) or `%` (escape character).
@@ -3,7 +3,7 @@ name: mastra-mysql
3
3
  description: Documentation for @mastra/mysql. Use when working with @mastra/mysql APIs, configuration, or implementation.
4
4
  metadata:
5
5
  package: "@mastra/mysql"
6
- version: "0.16.0-alpha.0"
6
+ version: "0.16.0-alpha.2"
7
7
  ---
8
8
 
9
9
  ## When to use
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.16.0-alpha.0",
2
+ "version": "0.16.0-alpha.2",
3
3
  "package": "@mastra/mysql",
4
4
  "exports": {},
5
5
  "modules": {}
package/dist/index.cjs CHANGED
@@ -852,6 +852,7 @@ var AgentsMySQL = class AgentsMySQL extends _mastra_core_storage.AgentsStorage {
852
852
  tableName: _mastra_core_storage.TABLE_AGENT_VERSIONS,
853
853
  schema: _mastra_core_storage.AGENT_VERSIONS_SCHEMA,
854
854
  ifNotExists: [
855
+ "modelList",
855
856
  "mcpClients",
856
857
  "requestContextSchema",
857
858
  "workspace",
@@ -1133,8 +1134,9 @@ var AgentsMySQL = class AgentsMySQL extends _mastra_core_storage.AgentsStorage {
1133
1134
  versionNumber: input.versionNumber,
1134
1135
  name: input.name ?? null,
1135
1136
  description: input.description ?? null,
1136
- instructions: this.serializeInstructions(input.instructions),
1137
- model: input.model,
1137
+ instructions: this.serializeInstructions(input.instructions ?? ""),
1138
+ model: input.model ?? {},
1139
+ modelList: input.modelList ?? null,
1138
1140
  tools: input.tools ?? null,
1139
1141
  defaultOptions: input.defaultOptions ?? null,
1140
1142
  workflows: input.workflows ?? null,
@@ -1351,6 +1353,7 @@ var AgentsMySQL = class AgentsMySQL extends _mastra_core_storage.AgentsStorage {
1351
1353
  description: row.description ?? void 0,
1352
1354
  instructions: this.deserializeInstructions(row.instructions),
1353
1355
  model: this.safeParseJSON(row.model),
1356
+ modelList: this.safeParseJSON(row.modelList),
1354
1357
  tools: this.safeParseJSON(row.tools),
1355
1358
  defaultOptions: this.safeParseJSON(row.defaultOptions),
1356
1359
  workflows: this.safeParseJSON(row.workflows),
@@ -3155,7 +3158,7 @@ var ExperimentsMySQL = class ExperimentsMySQL extends _mastra_core_storage.Exper
3155
3158
  let purgeMetadata = null;
3156
3159
  if (datasetId) {
3157
3160
  await connection.execute(`SELECT ${quoteIdentifier("id", "column name")} FROM ${formatTableName(_mastra_core_storage.TABLE_DATASETS)} WHERE ${quoteIdentifier("id", "column name")} = ? FOR UPDATE`, [datasetId]);
3158
- const [itemRows] = await connection.execute(`SELECT ${quoteIdentifier("metadata", "column name")} FROM ${formatTableName(_mastra_core_storage.TABLE_DATASET_ITEMS)} WHERE ${quoteIdentifier("id", "column name")} = ? AND ${quoteIdentifier("datasetId", "column name")} = ?`, [itemId, datasetId]);
3161
+ const [itemRows] = await connection.execute(`SELECT ${quoteIdentifier("metadata", "column name")} FROM ${formatTableName(_mastra_core_storage.TABLE_DATASET_ITEMS)} WHERE ${quoteIdentifier("id", "column name")} = ? AND ${quoteIdentifier("datasetId", "column name")} = ? FOR UPDATE`, [itemId, datasetId]);
3159
3162
  if (Array.isArray(itemRows)) {
3160
3163
  const purgedRow = itemRows.find((row) => parseJSON$2(row.metadata)?.__purged === true);
3161
3164
  purgeMetadata = purgedRow ? parseJSON$2(purgedRow.metadata) ?? null : null;
@@ -4319,13 +4322,23 @@ function createKnowledgePagesCoreLoader(features, loadStorageModule) {
4319
4322
  };
4320
4323
  }
4321
4324
  /**
4322
- * Keyword-search words: the query split on whitespace, lowercased, deduplicated. Every word must
4323
- * appear (as a case-insensitive substring) in a hit; an empty list means the search returns nothing.
4325
+ * Keyword-search words: the query split on whitespace, lowercased, deduplicated. A hit needs at
4326
+ * least one of them (as a case-insensitive substring); an empty list means the search returns nothing.
4324
4327
  */
4325
4328
  function knowledgeSearchWords(query) {
4326
4329
  return [...new Set(query.toLowerCase().split(/\s+/).filter(Boolean))];
4327
4330
  }
4328
4331
  /**
4332
+ * Points one matched search word earns on a page, by the best field it appears in: name, then
4333
+ * description, then body. Pages rank by how many query words they match first; these points only
4334
+ * break ties between pages that match the same number of words.
4335
+ */
4336
+ const KNOWLEDGE_SEARCH_WEIGHTS = {
4337
+ name: 3,
4338
+ description: 2,
4339
+ body: 1
4340
+ };
4341
+ /**
4329
4342
  * Why `key` can't be a Knowledge page key, or undefined when it can. Keys are one path segment:
4330
4343
  * non-empty, with no `/` (path separator), `#` (scope/path separator) or `%` (escape character).
4331
4344
  */
@@ -4556,6 +4569,13 @@ function isRetryableRace(error) {
4556
4569
  }
4557
4570
  return false;
4558
4571
  }
4572
+ function isLiveKeyClash(error) {
4573
+ for (let current = error; current && typeof current === "object"; current = current.cause) {
4574
+ const { code, errno, message } = current;
4575
+ if ((code === "ER_DUP_ENTRY" || errno === 1062) && String(message).includes("idx_kpages_live_key")) return true;
4576
+ }
4577
+ return false;
4578
+ }
4559
4579
  function escapeLike(value) {
4560
4580
  return value.replace(/[=%_]/g, (match) => `=${match}`);
4561
4581
  }
@@ -5009,7 +5029,12 @@ var MySQLKnowledgePages = class {
5009
5029
  }
5010
5030
  async createPage(input) {
5011
5031
  await assertKnowledgePageDescriptionWithinBound(input.description);
5012
- return this.#transaction((tx) => this.#insertPage(tx, input));
5032
+ try {
5033
+ return await this.#transaction((tx) => this.#insertPage(tx, input));
5034
+ } catch (error) {
5035
+ if (input.key !== void 0 && isLiveKeyClash(error)) throw new (await (loadPagesCore())).KnowledgePageKeyConflictError(input.key, input.parentId);
5036
+ throw error;
5037
+ }
5013
5038
  }
5014
5039
  async updatePage(input) {
5015
5040
  const core = await loadPagesCore();
@@ -5262,6 +5287,15 @@ var MySQLKnowledgePages = class {
5262
5287
  const rows = await this.#query(this.#read, `SELECT n.* FROM ${T.notes} n WHERE n.pageId = ?${input.includeDeleted ? "" : " AND n.deletedAt IS NULL"} AND ${readable.sql}${after} ORDER BY n.createdAt, n.id LIMIT ?`, args);
5263
5288
  return this.#noteOutput(rows, limit);
5264
5289
  }
5290
+ async countChildPages(input) {
5291
+ const ids = [...new Set(input.parentIds)];
5292
+ const counts = Object.fromEntries(ids.map((id) => [id, 0]));
5293
+ if (ids.length === 0) return counts;
5294
+ const readable = pageReadable("p", input.read);
5295
+ const rows = await this.#query(this.#read, `SELECT p.parentId AS parentId, COUNT(*) AS total FROM ${T.pages} p WHERE p.parentId IN ${JV} AND p.isScope = 0 AND p.deletedAt IS NULL AND ${readable.sql} GROUP BY p.parentId`, [jsonList(ids), ...readable.args]);
5296
+ for (const row of rows) counts[String(row.parentId)] = Number(row.total);
5297
+ return counts;
5298
+ }
5265
5299
  async countNotes(input) {
5266
5300
  const ids = [...new Set(input.pageIds)];
5267
5301
  const counts = Object.fromEntries(ids.map((id) => [id, 0]));
@@ -5433,18 +5467,22 @@ var MySQLKnowledgePages = class {
5433
5467
  const readable = pagesInReadableScopes("p", input.read);
5434
5468
  const scopeFilter = input.scopeIds ? ` AND p.scopeId IN ${JV}` : "";
5435
5469
  const scopeArgs = input.scopeIds ? [jsonList(input.scopeIds)] : [];
5436
- const pageMatch = words.map(() => `(LOWER(p.name) LIKE ? ESCAPE '=' OR LOWER(COALESCE(p.description, '')) LIKE ? ESCAPE '=' OR LOWER(COALESCE(p.body, '')) LIKE ? ESCAPE '=')`).join(" AND ");
5437
- const nameMatch = words.map(() => `LOWER(p.name) LIKE ? ESCAPE '='`).join(" AND ");
5438
- const hits = (await this.#query(this.#read, `SELECT p.* ${readable.sql} WHERE p.deletedAt IS NULL AND p.isScope = 0${scopeFilter} AND ${pageMatch} ORDER BY CASE WHEN LOCATE(?, p.canonicalName) > 0 THEN 0 WHEN ${nameMatch} THEN 1 ELSE 2 END, p.updatedAt DESC, p.id ASC LIMIT ?`, [
5470
+ const field = (column) => `LOWER(COALESCE(${column}, '')) LIKE ? ESCAPE '='`;
5471
+ const pageMatch = words.map(() => `(${field("p.name")} OR ${field("p.description")} OR ${field("p.body")})`).join(" OR ");
5472
+ const pageScore = words.map(() => `(CASE WHEN ${field("p.name")} THEN ${KNOWLEDGE_SEARCH_WEIGHTS.name} WHEN ${field("p.description")} THEN ${KNOWLEDGE_SEARCH_WEIGHTS.description} WHEN ${field("p.body")} THEN ${KNOWLEDGE_SEARCH_WEIGHTS.body} ELSE 0 END)`).join(" + ");
5473
+ const pageCount = words.map(() => `(CASE WHEN ${field("p.name")} OR ${field("p.description")} OR ${field("p.body")} THEN 1 ELSE 0 END)`).join(" + ");
5474
+ const triple = likes.flatMap((like) => [
5475
+ like,
5476
+ like,
5477
+ like
5478
+ ]);
5479
+ const hits = (await this.#query(this.#read, `SELECT p.* ${readable.sql} WHERE p.deletedAt IS NULL AND p.isScope = 0${scopeFilter} AND (${pageMatch}) ORDER BY CASE WHEN LOCATE(?, p.canonicalName) > 0 THEN 0 ELSE 1 END, (${pageCount}) DESC, (${pageScore}) DESC, p.updatedAt DESC, p.id ASC LIMIT ?`, [
5439
5480
  ...readable.args,
5440
5481
  ...scopeArgs,
5441
- ...likes.flatMap((like) => [
5442
- like,
5443
- like,
5444
- like
5445
- ]),
5482
+ ...triple,
5446
5483
  phrase,
5447
- ...likes,
5484
+ ...triple,
5485
+ ...triple,
5448
5486
  limit
5449
5487
  ])).map((row) => ({
5450
5488
  type: "page",
@@ -5452,11 +5490,12 @@ var MySQLKnowledgePages = class {
5452
5490
  }));
5453
5491
  if (hits.length >= limit) return hits;
5454
5492
  const noteVisible = noteReadable("n", input.read);
5455
- const noteMatch = words.map(() => `LOWER(n.text) LIKE ? ESCAPE '='`).join(" AND ");
5456
- const noteRows = await this.#query(this.#read, `SELECT n.* FROM ${T.notes} n JOIN ${T.pages} p ON p.id = n.pageId WHERE n.deletedAt IS NULL AND p.deletedAt IS NULL${scopeFilter} AND ${noteMatch} AND ${noteVisible.sql} ORDER BY n.updatedAt DESC, n.id DESC LIMIT ?`, [
5493
+ const noteHas = words.map(() => `LOWER(n.text) LIKE ? ESCAPE '='`);
5494
+ const noteRows = await this.#query(this.#read, `SELECT n.* FROM ${T.notes} n JOIN ${T.pages} p ON p.id = n.pageId WHERE n.deletedAt IS NULL AND p.deletedAt IS NULL${scopeFilter} AND (${noteHas.join(" OR ")}) AND ${noteVisible.sql} ORDER BY (${noteHas.map((has) => `(CASE WHEN ${has} THEN 1 ELSE 0 END)`).join(" + ")}) DESC, n.updatedAt DESC, n.id DESC LIMIT ?`, [
5457
5495
  ...scopeArgs,
5458
5496
  ...likes,
5459
5497
  ...noteVisible.args,
5498
+ ...likes,
5460
5499
  limit - hits.length
5461
5500
  ]);
5462
5501
  const notes = await this.#hydrateNotes(this.#read, noteRows);
@@ -5789,6 +5828,9 @@ var KnowledgeMySQL = class extends _mastra_core_storage.KnowledgeStorage {
5789
5828
  listNotes(input) {
5790
5829
  return this.#pages.listNotes(input);
5791
5830
  }
5831
+ countChildPages(input) {
5832
+ return this.#pages.countChildPages(input);
5833
+ }
5792
5834
  countNotes(input) {
5793
5835
  return this.#pages.countNotes(input);
5794
5836
  }