@mastra/mysql 0.12.2-alpha.0 → 0.13.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { ErrorCategory, ErrorDomain, MastraError } from "@mastra/core/error";
2
- import { AGENTS_SCHEMA, AGENT_VERSIONS_SCHEMA, AgentsStorage, BackgroundTasksStorage, BlobStore, ChannelsStorage, DATASETS_SCHEMA, DATASET_ITEMS_SCHEMA, DATASET_VERSIONS_SCHEMA, DatasetsStorage, EXPERIMENTS_SCHEMA, EXPERIMENT_RESULTS_SCHEMA, ExperimentsStorage, FAVORITES_SCHEMA, FavoritesStorage, KNOWLEDGE_ACTIVITY_SCHEMA, KNOWLEDGE_CURSORS_SCHEMA, KNOWLEDGE_MENTIONS_SCHEMA, KNOWLEDGE_NODES_SCHEMA, KNOWLEDGE_RECORDS_SCHEMA, KNOWLEDGE_SEMANTIC_OUTBOX_SCHEMA, KnowledgeConflictError, KnowledgeNotFoundError, KnowledgeStorage, MCPClientsStorage, MCPServersStorage, MCP_CLIENTS_SCHEMA, MCP_CLIENT_VERSIONS_SCHEMA, MCP_SERVERS_SCHEMA, MCP_SERVER_VERSIONS_SCHEMA, MastraCompositeStore, MemoryStorage, OBSERVATIONAL_MEMORY_TABLE_SCHEMA, ObservabilityStorage, PROMPT_BLOCKS_SCHEMA, PROMPT_BLOCK_VERSIONS_SCHEMA, PromptBlocksStorage, SCORERS_SCHEMA, SCORER_DEFINITIONS_SCHEMA, SCORER_DEFINITION_VERSIONS_SCHEMA, SKILLS_SCHEMA, SKILL_BLOBS_SCHEMA, SKILL_VERSIONS_SCHEMA, SPAN_SCHEMA, SchedulesStorage, ScorerDefinitionsStorage, ScoresStorage, SkillsStorage, StoreOperations, TABLE_AGENTS, TABLE_AGENT_VERSIONS, TABLE_BACKGROUND_TASKS, TABLE_CHANNEL_CONFIG, TABLE_CHANNEL_INSTALLATIONS, TABLE_CONFIGS, TABLE_DATASETS, TABLE_DATASET_ITEMS, TABLE_DATASET_VERSIONS, TABLE_EXPERIMENTS, TABLE_EXPERIMENT_RESULTS, TABLE_FAVORITES, TABLE_KNOWLEDGE_ACTIVITY, TABLE_KNOWLEDGE_CURSORS, TABLE_KNOWLEDGE_MENTIONS, TABLE_KNOWLEDGE_NODES, TABLE_KNOWLEDGE_RECORDS, TABLE_KNOWLEDGE_SEMANTIC_OUTBOX, TABLE_MCP_CLIENTS, TABLE_MCP_CLIENT_VERSIONS, TABLE_MCP_SERVERS, TABLE_MCP_SERVER_VERSIONS, TABLE_MESSAGES, TABLE_PROMPT_BLOCKS, TABLE_PROMPT_BLOCK_VERSIONS, TABLE_RESOURCES, TABLE_SCHEDULES, TABLE_SCHEDULE_TRIGGERS, TABLE_SCHEMAS, TABLE_SCORERS, TABLE_SCORER_DEFINITIONS, TABLE_SCORER_DEFINITION_VERSIONS, TABLE_SKILLS, TABLE_SKILL_BLOBS, TABLE_SKILL_VERSIONS, TABLE_SPANS, TABLE_THREADS, TABLE_TOOL_PROVIDER_CONNECTIONS, TABLE_WORKFLOW_DEFINITIONS, TABLE_WORKFLOW_SNAPSHOT, TABLE_WORKSPACES, TABLE_WORKSPACE_VERSIONS, TOOL_PROVIDER_CONNECTIONS_SCHEMA, ToolProviderConnectionsStorage, TraceStatus, WORKFLOW_DEFINITIONS_SCHEMA, WORKSPACES_SCHEMA, WORKSPACE_VERSIONS_SCHEMA, WorkflowDefinitionsStorage, WorkflowsStorage, WorkspacesStorage, assertKnowledgeCeilingRaised, assertKnowledgeScopeWithinCeiling, calculatePagination, canonicalizeKnowledgeScope, createKnowledgeUlid, createStorageErrorId, executeRetentionPrune, hasErrorCode, isKnowledgeScopeVisible, knowledgeScopeKey, knowledgeSemanticDocumentId, knowledgeSemanticIdempotencyKey, listTracesArgsSchema, matchesExpectedWorkflowStatus, normalizePerPage, normalizeScheduleTarget, parseKnowledgeNodeCursor, parseKnowledgeWikilinks, resolveListOrderBy, resolveRetentionTargets, retentionCutoffMs, toTraceSpans, validateStorageMetadataFilter } from "@mastra/core/storage";
2
+ import { AGENTS_SCHEMA, AGENT_VERSIONS_SCHEMA, AgentsStorage, BackgroundTasksStorage, BlobStore, ChannelsStorage, DATASETS_SCHEMA, DATASET_ITEMS_SCHEMA, DATASET_VERSIONS_SCHEMA, DatasetsStorage, EXPERIMENTS_SCHEMA, EXPERIMENT_RESULTS_SCHEMA, ExperimentsStorage, FAVORITES_SCHEMA, FavoritesStorage, KNOWLEDGE_ACTIVITY_SCHEMA, KNOWLEDGE_MENTIONS_SCHEMA, KNOWLEDGE_NODES_SCHEMA, KNOWLEDGE_RECORDS_SCHEMA, KNOWLEDGE_SEMANTIC_OUTBOX_SCHEMA, KnowledgeConflictError, KnowledgeNotFoundError, KnowledgeStorage, MCPClientsStorage, MCPServersStorage, MCP_CLIENTS_SCHEMA, MCP_CLIENT_VERSIONS_SCHEMA, MCP_SERVERS_SCHEMA, MCP_SERVER_VERSIONS_SCHEMA, MastraCompositeStore, MemoryStorage, OBSERVATIONAL_MEMORY_TABLE_SCHEMA, ObservabilityStorage, PROMPT_BLOCKS_SCHEMA, PROMPT_BLOCK_VERSIONS_SCHEMA, PromptBlocksStorage, SCORERS_SCHEMA, SCORER_DEFINITIONS_SCHEMA, SCORER_DEFINITION_VERSIONS_SCHEMA, SKILLS_SCHEMA, SKILL_BLOBS_SCHEMA, SKILL_VERSIONS_SCHEMA, SPAN_SCHEMA, SchedulesStorage, ScorerDefinitionsStorage, ScoresStorage, SkillsStorage, StoreOperations, TABLE_AGENTS, TABLE_AGENT_VERSIONS, TABLE_BACKGROUND_TASKS, TABLE_CHANNEL_CONFIG, TABLE_CHANNEL_INSTALLATIONS, TABLE_CONFIGS, TABLE_DATASETS, TABLE_DATASET_ITEMS, TABLE_DATASET_VERSIONS, TABLE_EXPERIMENTS, TABLE_EXPERIMENT_RESULTS, TABLE_FAVORITES, TABLE_KNOWLEDGE_ACTIVITY, TABLE_KNOWLEDGE_MENTIONS, TABLE_KNOWLEDGE_NODES, TABLE_KNOWLEDGE_RECORDS, TABLE_KNOWLEDGE_SEMANTIC_OUTBOX, TABLE_MCP_CLIENTS, TABLE_MCP_CLIENT_VERSIONS, TABLE_MCP_SERVERS, TABLE_MCP_SERVER_VERSIONS, TABLE_MESSAGES, TABLE_PROMPT_BLOCKS, TABLE_PROMPT_BLOCK_VERSIONS, TABLE_RESOURCES, TABLE_SCHEDULES, TABLE_SCHEDULE_TRIGGERS, TABLE_SCHEMAS, TABLE_SCORERS, TABLE_SCORER_DEFINITIONS, TABLE_SCORER_DEFINITION_VERSIONS, TABLE_SKILLS, TABLE_SKILL_BLOBS, TABLE_SKILL_VERSIONS, TABLE_SPANS, TABLE_THREADS, TABLE_TOOL_PROVIDER_CONNECTIONS, TABLE_WORKFLOW_DEFINITIONS, TABLE_WORKFLOW_SNAPSHOT, TABLE_WORKSPACES, TABLE_WORKSPACE_VERSIONS, TOOL_PROVIDER_CONNECTIONS_SCHEMA, ToolProviderConnectionsStorage, TraceStatus, WORKFLOW_DEFINITIONS_SCHEMA, WORKSPACES_SCHEMA, WORKSPACE_VERSIONS_SCHEMA, WorkflowDefinitionsStorage, WorkflowsStorage, WorkspacesStorage, calculatePagination, canonicalizeKnowledgeScope, createKnowledgeUlid, createStorageErrorId, executeRetentionPrune, hasErrorCode, isKnowledgeScopeVisible, knowledgeScopeKey, knowledgeSemanticDocumentId, knowledgeSemanticIdempotencyKey, listTracesArgsSchema, matchesExpectedWorkflowStatus, normalizePerPage, normalizeScheduleTarget, parseKnowledgeNodeCursor, parseKnowledgeWikilinks, resolveListOrderBy, resolveRetentionTargets, retentionCutoffMs, toTraceSpans, validateStorageMetadataFilter } from "@mastra/core/storage";
3
3
  import { createPool } from "mysql2/promise";
4
4
  import { parseSqlIdentifier } from "@mastra/core/utils";
5
5
  import { MessageList } from "@mastra/core/agent";
@@ -4174,6 +4174,13 @@ async function assertKnowledgeDescriptionWithinBoundCompat(description) {
4174
4174
  }
4175
4175
  assertWithinBound(description);
4176
4176
  }
4177
+ let assertRecordTextWithinBound;
4178
+ async function assertKnowledgeRecordTextWithinBoundCompat(text) {
4179
+ if (!assertRecordTextWithinBound) assertRecordTextWithinBound = (await import("@mastra/core/storage")).assertKnowledgeRecordTextWithinBound ?? ((value) => {
4180
+ if (value.length > 1e3) throw new Error("Knowledge record text exceeds the 1000 UTF-16 code unit limit; split it into separate facts or summarize it");
4181
+ });
4182
+ assertRecordTextWithinBound(text);
4183
+ }
4177
4184
  function mysqlSql(sql) {
4178
4185
  return sql.replaceAll("jsonb(?)", "CAST(? AS JSON)").replaceAll("INSERT OR IGNORE", "INSERT IGNORE").replaceAll("\"", "`");
4179
4186
  }
@@ -4192,7 +4199,21 @@ function createExecutor(client) {
4192
4199
  };
4193
4200
  } };
4194
4201
  }
4195
- const visibleSql = `(scopeKey = ? OR LEFT(?, CHAR_LENGTH(scopeKey) + 1) = CONCAT(scopeKey, char(31)))`;
4202
+ /**
4203
+ * Scope keys visible to a caller holding `scope`: a row is visible when its scope is a subset of the
4204
+ * caller's (companion entries such as `resource:x:uncurated` make this more than a prefix match).
4205
+ * Matching rows by `scopeKey` keeps visibility filters on an index; a caller scope has only a few
4206
+ * entries, so the list stays small.
4207
+ */
4208
+ function visibleScopeKeys(scope) {
4209
+ const canonical = canonicalizeKnowledgeScope(scope);
4210
+ const keys = /* @__PURE__ */ new Set();
4211
+ for (let mask = 1; mask < 1 << canonical.length; mask++) try {
4212
+ keys.add(knowledgeScopeKey(canonical.filter((_, index) => mask & 1 << index)));
4213
+ } catch {}
4214
+ return [...keys];
4215
+ }
4216
+ const visibleSql = (keys, scopeKeyColumn = "scopeKey") => `${scopeKeyColumn} IN (${keys.map(() => "?").join(",")})`;
4196
4217
  function parseJson$1(value) {
4197
4218
  if (typeof value === "string") return JSON.parse(value);
4198
4219
  if (value instanceof Uint8Array) return JSON.parse(new TextDecoder().decode(value));
@@ -4242,7 +4263,6 @@ function parseKnowledge(row) {
4242
4263
  sourceThreadId: String(row.sourceThreadId),
4243
4264
  capturedAt: toDate(row.capturedAt),
4244
4265
  when: optionalDate(row.when),
4245
- maxScope: row.maxScope == null ? void 0 : String(row.maxScope),
4246
4266
  metadata: row.metadata == null ? void 0 : parseJson$1(row.metadata),
4247
4267
  deletedAt: optionalDate(row.deletedAt),
4248
4268
  deletedBy: row.deletedBy == null ? void 0 : String(row.deletedBy)
@@ -4268,13 +4288,17 @@ function parseOutbox(row) {
4268
4288
  const KNOWLEDGE_INDEX_DDL = [
4269
4289
  `CREATE UNIQUE INDEX idx_knowledge_nodes_identity ON "${TABLE_KNOWLEDGE_NODES}" (type(32), scopeKey(255), canonicalName(255))`,
4270
4290
  `CREATE INDEX idx_knowledge_nodes_scope ON "${TABLE_KNOWLEDGE_NODES}" (scopeKey(255), type(32))`,
4291
+ `CREATE INDEX idx_knowledge_nodes_name ON "${TABLE_KNOWLEDGE_NODES}" (type(32), canonicalName(255))`,
4271
4292
  `CREATE INDEX idx_knowledge_records_node_latest ON "${TABLE_KNOWLEDGE_RECORDS}" (node(191), id(26) DESC)`,
4272
4293
  `CREATE INDEX idx_knowledge_records_thread_latest ON "${TABLE_KNOWLEDGE_RECORDS}" (sourceThreadId(191), id(26) DESC)`,
4273
4294
  `CREATE INDEX idx_knowledge_mentions_record ON "${TABLE_KNOWLEDGE_MENTIONS}" (recordId(191), sourceType(32), sourceId(191))`,
4274
4295
  `CREATE INDEX idx_knowledge_activity_latest ON "${TABLE_KNOWLEDGE_ACTIVITY}" (id(26) DESC)`,
4296
+ `CREATE INDEX idx_knowledge_records_scope ON "${TABLE_KNOWLEDGE_RECORDS}" (scopeKey(255), id(26))`,
4297
+ `CREATE INDEX idx_knowledge_activity_scope ON "${TABLE_KNOWLEDGE_ACTIVITY}" (scopeKey(255), id(26) DESC)`,
4275
4298
  `CREATE UNIQUE INDEX idx_knowledge_outbox_idempotency ON "${TABLE_KNOWLEDGE_SEMANTIC_OUTBOX}" (idempotencyKey(255))`,
4276
4299
  `CREATE INDEX idx_knowledge_outbox_claim ON "${TABLE_KNOWLEDGE_SEMANTIC_OUTBOX}" (status(32), availableAt, createdAt)`
4277
4300
  ];
4301
+ const KNOWLEDGE_CURATION_CURSOR_REMOVED_MESSAGE = "Knowledge curation cursors were removed: observation-time curate is the only Knowledge writer and needs no cursor.";
4278
4302
  var KnowledgeMySQL = class extends KnowledgeStorage {
4279
4303
  static getExportDDL() {
4280
4304
  return [
@@ -4295,11 +4319,6 @@ var KnowledgeMySQL = class extends KnowledgeStorage {
4295
4319
  "recordId"
4296
4320
  ]
4297
4321
  }),
4298
- generateTableSQL({
4299
- tableName: TABLE_KNOWLEDGE_CURSORS,
4300
- schema: KNOWLEDGE_CURSORS_SCHEMA,
4301
- compositePrimaryKey: ["sourceThreadId", "agent"]
4302
- }),
4303
4322
  generateTableSQL({
4304
4323
  tableName: TABLE_KNOWLEDGE_ACTIVITY,
4305
4324
  schema: KNOWLEDGE_ACTIVITY_SCHEMA
@@ -4338,10 +4357,6 @@ var KnowledgeMySQL = class extends KnowledgeStorage {
4338
4357
  tableName: TABLE_KNOWLEDGE_MENTIONS,
4339
4358
  schema: KNOWLEDGE_MENTIONS_SCHEMA
4340
4359
  });
4341
- await this.#operations.createTable({
4342
- tableName: TABLE_KNOWLEDGE_CURSORS,
4343
- schema: KNOWLEDGE_CURSORS_SCHEMA
4344
- });
4345
4360
  await this.#operations.createTable({
4346
4361
  tableName: TABLE_KNOWLEDGE_ACTIVITY,
4347
4362
  schema: KNOWLEDGE_ACTIVITY_SCHEMA
@@ -4362,7 +4377,6 @@ var KnowledgeMySQL = class extends KnowledgeStorage {
4362
4377
  TABLE_KNOWLEDGE_MENTIONS,
4363
4378
  TABLE_KNOWLEDGE_RECORDS,
4364
4379
  TABLE_KNOWLEDGE_NODES,
4365
- TABLE_KNOWLEDGE_CURSORS,
4366
4380
  TABLE_KNOWLEDGE_ACTIVITY,
4367
4381
  TABLE_KNOWLEDGE_SEMANTIC_OUTBOX
4368
4382
  ]) await tx.execute(`DELETE FROM "${table}"`);
@@ -4370,6 +4384,11 @@ var KnowledgeMySQL = class extends KnowledgeStorage {
4370
4384
  }
4371
4385
  async createNode(input) {
4372
4386
  await assertKnowledgeDescriptionWithinBoundCompat(input.description);
4387
+ if (input.scopeAddresses?.length) {
4388
+ const error = /* @__PURE__ */ new Error("This Knowledge storage adapter does not expose structural scope placement.");
4389
+ error.name = "KnowledgeUnsupportedCapabilityError";
4390
+ throw error;
4391
+ }
4373
4392
  const scope = canonicalizeKnowledgeScope(input.scope);
4374
4393
  return this.#transaction(async (tx) => {
4375
4394
  const existing = await this.#getNodeByName(tx, input.name, scope);
@@ -4424,13 +4443,13 @@ var KnowledgeMySQL = class extends KnowledgeStorage {
4424
4443
  return this.#resolveNode(this.#client, input.name, canonicalizeKnowledgeScope(input.scope));
4425
4444
  }
4426
4445
  async listNodes(input) {
4427
- const key = knowledgeScopeKey(canonicalizeKnowledgeScope(input.scope));
4446
+ const keys = visibleScopeKeys(canonicalizeKnowledgeScope(input.scope));
4428
4447
  const clauses = [
4429
4448
  `type = 'node'`,
4430
4449
  "mergedInto IS NULL",
4431
- visibleSql
4450
+ visibleSql(keys)
4432
4451
  ];
4433
- const args = [key, key];
4452
+ const args = [...keys];
4434
4453
  if (input.namePrefix) {
4435
4454
  clauses.push("canonicalName LIKE ? ESCAPE '='");
4436
4455
  args.push(`${escapeLikePattern(canonicalName(input.namePrefix))}%`);
@@ -4577,10 +4596,10 @@ var KnowledgeMySQL = class extends KnowledgeStorage {
4577
4596
  });
4578
4597
  }
4579
4598
  async appendKnowledge(input) {
4599
+ await assertKnowledgeRecordTextWithinBoundCompat(input.text);
4580
4600
  const scope = canonicalizeKnowledgeScope(input.scope);
4581
4601
  const resolutionScope = canonicalizeKnowledgeScope(input.resolutionScope);
4582
4602
  const defaultScope = canonicalizeKnowledgeScope(input.defaultScope);
4583
- assertKnowledgeScopeWithinCeiling(scope, input.maxScope);
4584
4603
  return this.#transaction(async (tx) => {
4585
4604
  const parent = await this.#resolveTerminalNode(tx, nodeReferenceId(input.node));
4586
4605
  if (!parent) throw new KnowledgeNotFoundError("node", nodeReferenceId(input.node));
@@ -4592,11 +4611,10 @@ var KnowledgeMySQL = class extends KnowledgeStorage {
4592
4611
  sourceThreadId: input.sourceThreadId,
4593
4612
  capturedAt: /* @__PURE__ */ new Date(),
4594
4613
  when: input.when ? new Date(input.when) : void 0,
4595
- maxScope: input.maxScope,
4596
4614
  metadata: input.metadata
4597
4615
  };
4598
4616
  await tx.execute({
4599
- sql: `INSERT INTO "${TABLE_KNOWLEDGE_RECORDS}" (id,node,text,scope,scopeKey,sourceThreadId,capturedAt,"when",maxScope,metadata,deletedAt,deletedBy) VALUES (?,?,?,jsonb(?),?,?,?,?,?,jsonb(?),NULL,NULL)`,
4617
+ sql: `INSERT INTO "${TABLE_KNOWLEDGE_RECORDS}" (id,node,text,scope,scopeKey,sourceThreadId,capturedAt,"when",metadata,deletedAt,deletedBy) VALUES (?,?,?,jsonb(?),?,?,?,?,jsonb(?),NULL,NULL)`,
4600
4618
  args: [
4601
4619
  record.id,
4602
4620
  record.node,
@@ -4606,7 +4624,6 @@ var KnowledgeMySQL = class extends KnowledgeStorage {
4606
4624
  record.sourceThreadId,
4607
4625
  record.capturedAt.toISOString(),
4608
4626
  record.when?.toISOString() ?? null,
4609
- record.maxScope ?? null,
4610
4627
  record.metadata ? JSON.stringify(record.metadata) : null
4611
4628
  ]
4612
4629
  });
@@ -4633,17 +4650,13 @@ var KnowledgeMySQL = class extends KnowledgeStorage {
4633
4650
  return this.#queryKnowledge(input, "related");
4634
4651
  }
4635
4652
  async knowledgeBySource(input) {
4636
- const key = knowledgeScopeKey(canonicalizeKnowledgeScope(input.scope));
4637
- const args = [
4638
- input.sourceThreadId,
4639
- key,
4640
- key
4641
- ];
4653
+ const keys = visibleScopeKeys(canonicalizeKnowledgeScope(input.scope));
4654
+ const args = [input.sourceThreadId, ...keys];
4642
4655
  if (input.after) args.push(input.after);
4643
4656
  const limit = input.limit ?? 100;
4644
4657
  args.push(limit + 1);
4645
4658
  const records = (await this.#client.execute({
4646
- sql: `SELECT *,scope AS scopeJson FROM "${TABLE_KNOWLEDGE_RECORDS}" WHERE sourceThreadId=? AND ${visibleSql}${input.includeDeleted ? "" : " AND deletedAt IS NULL"}${input.after ? " AND id > ?" : ""} ORDER BY id ASC LIMIT ?`,
4659
+ sql: `SELECT *,scope AS scopeJson FROM "${TABLE_KNOWLEDGE_RECORDS}" WHERE sourceThreadId=? AND ${visibleSql(keys)}${input.includeDeleted ? "" : " AND deletedAt IS NULL"}${input.after ? " AND id > ?" : ""} ORDER BY id ASC LIMIT ?`,
4647
4660
  args
4648
4661
  })).rows.map(parseKnowledge);
4649
4662
  return {
@@ -4697,7 +4710,6 @@ var KnowledgeMySQL = class extends KnowledgeStorage {
4697
4710
  return this.#transaction(async (tx) => {
4698
4711
  const record = await this.#getKnowledge(tx, input.id, true);
4699
4712
  if (!record) throw new KnowledgeNotFoundError("record", input.id);
4700
- assertKnowledgeScopeWithinCeiling(scope, record.maxScope);
4701
4713
  await tx.execute({
4702
4714
  sql: `UPDATE "${TABLE_KNOWLEDGE_RECORDS}" SET scope=jsonb(?),scopeKey=? WHERE id=?`,
4703
4715
  args: [
@@ -4715,33 +4727,16 @@ var KnowledgeMySQL = class extends KnowledgeStorage {
4715
4727
  };
4716
4728
  });
4717
4729
  }
4718
- async raiseKnowledgeCeiling(input) {
4719
- return this.#transaction(async (tx) => {
4720
- const record = await this.#getKnowledge(tx, input.id, true);
4721
- if (!record) throw new KnowledgeNotFoundError("record", input.id);
4722
- assertKnowledgeScopeWithinCeiling(record.scope, input.maxScope);
4723
- assertKnowledgeCeilingRaised(record.maxScope, input.maxScope);
4724
- await tx.execute({
4725
- sql: `UPDATE "${TABLE_KNOWLEDGE_RECORDS}" SET maxScope=? WHERE id=?`,
4726
- args: [input.maxScope ?? null, input.id]
4727
- });
4728
- return {
4729
- ...record,
4730
- maxScope: input.maxScope
4731
- };
4732
- });
4733
- }
4734
4730
  async search(input) {
4735
4731
  const scope = canonicalizeKnowledgeScope(input.scope);
4736
- const key = knowledgeScopeKey(scope);
4732
+ const keys = visibleScopeKeys(scope);
4737
4733
  const normalizedQuery = input.query.trim().toLocaleLowerCase();
4738
4734
  if (!normalizedQuery) return [];
4739
4735
  const query = `%${escapeLikePattern(normalizedQuery)}%`;
4740
4736
  const results = (await this.#client.execute({
4741
- sql: `SELECT *,scope AS scopeJson FROM "${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 ?`,
4737
+ sql: `SELECT *,scope AS scopeJson FROM "${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 ?`,
4742
4738
  args: [
4743
- key,
4744
- key,
4739
+ ...keys,
4745
4740
  query,
4746
4741
  query,
4747
4742
  query,
@@ -4762,10 +4757,9 @@ var KnowledgeMySQL = class extends KnowledgeStorage {
4762
4757
  }));
4763
4758
  if (results.length < (input.limit ?? 20)) {
4764
4759
  const records = await this.#client.execute({
4765
- sql: `SELECT f.*,f.scope AS scopeJson,r.name,r.scope AS parentScopeJson FROM "${TABLE_KNOWLEDGE_RECORDS}" f JOIN "${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 ?`,
4760
+ sql: `SELECT f.*,f.scope AS scopeJson,r.name,r.scope AS parentScopeJson FROM "${TABLE_KNOWLEDGE_RECORDS}" f JOIN "${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 ?`,
4766
4761
  args: [
4767
- key,
4768
- key,
4762
+ ...keys,
4769
4763
  query,
4770
4764
  (input.limit ?? 20) - results.length
4771
4765
  ]
@@ -4775,7 +4769,7 @@ var KnowledgeMySQL = class extends KnowledgeStorage {
4775
4769
  return {
4776
4770
  type: "record",
4777
4771
  id: String(row.id),
4778
- recordId: String(row.node),
4772
+ recordId: parentVisible ? String(row.node) : String(row.id),
4779
4773
  name: parentVisible ? String(row.name) : "(private node)",
4780
4774
  text: String(row.text),
4781
4775
  scope: parseJson$1(row.scopeJson)
@@ -4784,41 +4778,26 @@ var KnowledgeMySQL = class extends KnowledgeStorage {
4784
4778
  }
4785
4779
  return results;
4786
4780
  }
4787
- async getCurationCursor(input) {
4788
- const row = (await this.#client.execute({
4789
- sql: `SELECT * FROM "${TABLE_KNOWLEDGE_CURSORS}" WHERE sourceThreadId=? AND agent=?`,
4790
- args: [input.sourceThreadId, input.agent]
4791
- })).rows[0];
4792
- return row ? {
4793
- sourceThreadId: String(row.sourceThreadId),
4794
- agent: String(row.agent),
4795
- lastKnowledgeId: String(row.lastKnowledgeId),
4796
- updatedAt: toDate(row.updatedAt)
4797
- } : null;
4798
- }
4799
- async advanceCurationCursor(input) {
4800
- const updatedAt = /* @__PURE__ */ new Date();
4801
- if ((await this.#client.execute({
4802
- sql: `INSERT INTO "${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)`,
4803
- args: [
4804
- input.sourceThreadId,
4805
- input.agent,
4806
- input.lastKnowledgeId,
4807
- updatedAt.toISOString()
4808
- ]
4809
- })).rowsAffected === 0) throw new Error("Knowledge curation cursor cannot move backwards");
4810
- return {
4811
- ...input,
4812
- updatedAt
4813
- };
4781
+ /**
4782
+ * @deprecated Curation cursors were removed. Observation-time curate is the only Knowledge writer and needs no
4783
+ * cursor. Always throws.
4784
+ */
4785
+ async getCurationCursor(_input) {
4786
+ throw new Error(KNOWLEDGE_CURATION_CURSOR_REMOVED_MESSAGE);
4787
+ }
4788
+ /**
4789
+ * @deprecated Curation cursors were removed. Observation-time curate is the only Knowledge writer and needs no
4790
+ * cursor. Always throws.
4791
+ */
4792
+ async advanceCurationCursor(_input) {
4793
+ throw new Error(KNOWLEDGE_CURATION_CURSOR_REMOVED_MESSAGE);
4814
4794
  }
4815
4795
  async listActivity(input) {
4816
- const key = knowledgeScopeKey(canonicalizeKnowledgeScope(input.scope));
4796
+ const keys = visibleScopeKeys(canonicalizeKnowledgeScope(input.scope));
4817
4797
  return (await this.#client.execute({
4818
- sql: `SELECT *,scope AS scopeJson FROM "${TABLE_KNOWLEDGE_ACTIVITY}" WHERE ${visibleSql}${input.after ? " AND id < ?" : ""} ORDER BY id DESC LIMIT ?`,
4798
+ sql: `SELECT *,scope AS scopeJson FROM "${TABLE_KNOWLEDGE_ACTIVITY}" WHERE ${visibleSql(keys)}${input.after ? " AND id < ?" : ""} ORDER BY id DESC LIMIT ?`,
4819
4799
  args: [
4820
- key,
4821
- key,
4800
+ ...keys,
4822
4801
  ...input.after ? [input.after] : [],
4823
4802
  input.limit ?? 100
4824
4803
  ]
@@ -4840,9 +4819,9 @@ var KnowledgeMySQL = class extends KnowledgeStorage {
4840
4819
  args.push(input.status);
4841
4820
  }
4842
4821
  if (input.scope) {
4843
- const key = knowledgeScopeKey(canonicalizeKnowledgeScope(input.scope));
4844
- clauses.push(visibleSql);
4845
- args.push(key, key);
4822
+ const keys = visibleScopeKeys(input.scope);
4823
+ clauses.push(visibleSql(keys));
4824
+ args.push(...keys);
4846
4825
  }
4847
4826
  args.push(input.limit ?? 100);
4848
4827
  return (await this.#client.execute({
@@ -4861,9 +4840,9 @@ var KnowledgeMySQL = class extends KnowledgeStorage {
4861
4840
  ];
4862
4841
  const args = [now.toISOString(), stale.toISOString()];
4863
4842
  if (input.scope) {
4864
- const key = knowledgeScopeKey(canonicalizeKnowledgeScope(input.scope));
4865
- clauses.push(visibleSql);
4866
- args.push(key, key);
4843
+ const keys = visibleScopeKeys(input.scope);
4844
+ clauses.push(visibleSql(keys));
4845
+ args.push(...keys);
4867
4846
  }
4868
4847
  args.push(input.limit ?? 100);
4869
4848
  const ids = (await tx.execute({
@@ -4941,12 +4920,14 @@ var KnowledgeMySQL = class extends KnowledgeStorage {
4941
4920
  return result.rows[0] ? parseNode(result.rows[0]) : null;
4942
4921
  }
4943
4922
  async #resolveNode(executor, name, scope) {
4944
- for (let length = scope.length; length > 0; length--) {
4945
- const node = await this.#getNodeByName(executor, name, scope.slice(0, length));
4946
- if (node) {
4947
- const terminal = await this.#resolveTerminalNode(executor, node.id);
4948
- if (terminal && isKnowledgeScopeVisible(terminal.scope, scope)) return terminal;
4949
- }
4923
+ const keys = visibleScopeKeys(scope);
4924
+ const candidates = (await executor.execute({
4925
+ sql: `SELECT *,scope AS scopeJson FROM "${TABLE_KNOWLEDGE_NODES}" WHERE type='node' AND canonicalName=? AND (scopeKey IN (${keys.map(() => "?").join(",")}) OR mergedInto IS NOT NULL)`,
4926
+ args: [canonicalName(name), ...keys]
4927
+ })).rows.map(parseNode).sort((left, right) => right.scope.length - left.scope.length);
4928
+ for (const candidate of candidates) {
4929
+ const terminal = await this.#resolveTerminalNode(executor, candidate.id);
4930
+ if (terminal && isKnowledgeScopeVisible(terminal.scope, scope)) return terminal;
4950
4931
  }
4951
4932
  return null;
4952
4933
  }
@@ -4971,17 +4952,16 @@ var KnowledgeMySQL = class extends KnowledgeStorage {
4971
4952
  const scope = canonicalizeKnowledgeScope(input.scope);
4972
4953
  const node = await this.#resolveTerminalNode(this.#client, nodeReferenceId(input.node));
4973
4954
  if (!node) return { records: [] };
4974
- const key = knowledgeScopeKey(scope);
4955
+ const keys = visibleScopeKeys(scope);
4975
4956
  const args = [
4976
4957
  node.id,
4977
4958
  ...relationship === "related" ? [node.id] : [],
4978
- key,
4979
- key
4959
+ ...keys
4980
4960
  ];
4981
4961
  if (input.after) args.push(input.after);
4982
4962
  args.push((input.limit ?? 100) + 1);
4983
4963
  const records = (await this.#client.execute({
4984
- sql: `SELECT DISTINCT f.*,f.scope AS scopeJson FROM "${TABLE_KNOWLEDGE_RECORDS}" f${relationship === "about" ? "" : ` LEFT JOIN "${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 ?`,
4964
+ sql: `SELECT DISTINCT f.*,f.scope AS scopeJson FROM "${TABLE_KNOWLEDGE_RECORDS}" f${relationship === "about" ? "" : ` LEFT JOIN "${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 ?`,
4985
4965
  args
4986
4966
  })).rows.map(parseKnowledge);
4987
4967
  const limit = input.limit ?? 100;