@mastra/mysql 0.7.1-alpha.2 → 0.8.0
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/CHANGELOG.md +40 -0
- package/dist/index.cjs +878 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +879 -9
- package/dist/index.js.map +1 -1
- package/dist/storage/domains/knowledge/index.d.ts +86 -0
- package/dist/storage/domains/knowledge/index.d.ts.map +1 -0
- package/dist/storage/index.d.ts +2 -1
- package/dist/storage/index.d.ts.map +1 -1
- package/package.json +5 -5
package/dist/index.cjs
CHANGED
|
@@ -731,7 +731,7 @@ function generateTableSQL({ tableName, schema, compositePrimaryKey }) {
|
|
|
731
731
|
const constraints = [];
|
|
732
732
|
if (def.primaryKey && !compositePrimaryKey?.includes(name)) constraints.push("PRIMARY KEY");
|
|
733
733
|
if (!def.nullable) constraints.push("NOT NULL");
|
|
734
|
-
return `${colName} ${mapToMySqlType(def.type)} ${constraints.join(" ")}`;
|
|
734
|
+
return `${colName} ${mapToMySqlType(def.type, Boolean(def.primaryKey || compositePrimaryKey?.includes(name)))} ${constraints.join(" ")}`;
|
|
735
735
|
});
|
|
736
736
|
const tableConstraints = [];
|
|
737
737
|
if (compositePrimaryKey) {
|
|
@@ -755,9 +755,9 @@ function generateIndexSQL(options) {
|
|
|
755
755
|
return quoteIdentifier(col, "column name");
|
|
756
756
|
}).join(", ")});`;
|
|
757
757
|
}
|
|
758
|
-
function mapToMySqlType(type) {
|
|
758
|
+
function mapToMySqlType(type, isKey = false) {
|
|
759
759
|
switch (type) {
|
|
760
|
-
case "text": return "TEXT";
|
|
760
|
+
case "text": return isKey ? "VARCHAR(191)" : "TEXT";
|
|
761
761
|
case "timestamp": return "DATETIME(3)";
|
|
762
762
|
case "bigint": return "BIGINT";
|
|
763
763
|
case "integer": return "INT";
|
|
@@ -1372,7 +1372,7 @@ function serializeJson(v) {
|
|
|
1372
1372
|
if (typeof v === "object" && v != null) return JSON.stringify(v);
|
|
1373
1373
|
return v ?? null;
|
|
1374
1374
|
}
|
|
1375
|
-
function parseJson$
|
|
1375
|
+
function parseJson$2(val) {
|
|
1376
1376
|
if (val == null) return void 0;
|
|
1377
1377
|
if (typeof val === "string") try {
|
|
1378
1378
|
return JSON.parse(val);
|
|
@@ -1387,14 +1387,14 @@ function rowToTask(row) {
|
|
|
1387
1387
|
status: String(row.status),
|
|
1388
1388
|
toolName: String(row.tool_name),
|
|
1389
1389
|
toolCallId: String(row.tool_call_id),
|
|
1390
|
-
args: parseJson$
|
|
1390
|
+
args: parseJson$2(row.args) ?? {},
|
|
1391
1391
|
agentId: String(row.agent_id),
|
|
1392
1392
|
threadId: row.thread_id != null ? String(row.thread_id) : void 0,
|
|
1393
1393
|
resourceId: row.resource_id != null ? String(row.resource_id) : void 0,
|
|
1394
1394
|
runId: String(row.run_id),
|
|
1395
|
-
result: parseJson$
|
|
1396
|
-
error: parseJson$
|
|
1397
|
-
suspendPayload: parseJson$
|
|
1395
|
+
result: parseJson$2(row.result),
|
|
1396
|
+
error: parseJson$2(row.error),
|
|
1397
|
+
suspendPayload: parseJson$2(row.suspend_payload),
|
|
1398
1398
|
retryCount: Number(row.retry_count),
|
|
1399
1399
|
maxRetries: Number(row.max_retries),
|
|
1400
1400
|
timeoutMs: Number(row.timeout_ms),
|
|
@@ -3822,6 +3822,871 @@ var FavoritesMySQL = class FavoritesMySQL extends _mastra_core_storage.Favorites
|
|
|
3822
3822
|
}
|
|
3823
3823
|
};
|
|
3824
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
|
|
3825
4690
|
//#region src/storage/domains/mcp-clients/index.ts
|
|
3826
4691
|
var MCPClientsMySQL = class MCPClientsMySQL extends _mastra_core_storage.MCPClientsStorage {
|
|
3827
4692
|
pool;
|
|
@@ -10474,6 +11339,10 @@ var MySQLStore = class extends _mastra_core_storage.MastraCompositeStore {
|
|
|
10474
11339
|
skipDefaultIndexes: config.skipDefaultIndexes,
|
|
10475
11340
|
indexes: config.indexes
|
|
10476
11341
|
});
|
|
11342
|
+
const knowledge = new KnowledgeMySQL({
|
|
11343
|
+
pool: this.pool,
|
|
11344
|
+
operations
|
|
11345
|
+
});
|
|
10477
11346
|
const workflows = new WorkflowsMySQL({
|
|
10478
11347
|
operations,
|
|
10479
11348
|
pool: this.pool,
|
|
@@ -10586,6 +11455,7 @@ var MySQLStore = class extends _mastra_core_storage.MastraCompositeStore {
|
|
|
10586
11455
|
});
|
|
10587
11456
|
this.stores = {
|
|
10588
11457
|
memory,
|
|
11458
|
+
knowledge,
|
|
10589
11459
|
workflows,
|
|
10590
11460
|
scores,
|
|
10591
11461
|
observability,
|