@mastra/libsql 1.29.0-alpha.0 → 1.29.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.
- package/dist/_types/{@internal_core → @internal_core@0.1.4}/dist/knowledge-compat/index.d.ts +17 -2
- package/dist/index.cjs +258 -42
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +258 -42
- package/dist/index.js.map +1 -1
- package/dist/storage/domains/agents/index.d.ts.map +1 -1
- package/dist/storage/domains/knowledge/index.d.ts +8 -1
- package/dist/storage/domains/knowledge/index.d.ts.map +1 -1
- package/dist/storage/domains/knowledge/pages.d.ts +28 -12
- package/dist/storage/domains/knowledge/pages.d.ts.map +1 -1
- package/dist/storage/domains/memory/index.d.ts +1 -1
- package/package.json +8 -8
- package/dist/docs/SKILL.md +0 -54
- package/dist/docs/assets/SOURCE_MAP.json +0 -6
- package/dist/docs/references/docs-agents-human-in-the-loop.md +0 -773
- package/dist/docs/references/docs-agents-networks.md +0 -186
- package/dist/docs/references/docs-deployment-workers.md +0 -404
- package/dist/docs/references/docs-memory-memory-processors.md +0 -442
- package/dist/docs/references/docs-memory-message-history.md +0 -424
- package/dist/docs/references/docs-memory-multi-user-threads.md +0 -210
- package/dist/docs/references/docs-memory-overview.md +0 -305
- package/dist/docs/references/docs-memory-semantic-recall.md +0 -485
- package/dist/docs/references/docs-memory-working-memory.md +0 -450
- package/dist/docs/references/docs-signals-overview.md +0 -94
- package/dist/docs/references/docs-storage.md +0 -224
- package/dist/docs/references/docs-studio-editor.md +0 -369
- package/dist/docs/references/docs-workflows-snapshots.md +0 -244
- package/dist/docs/references/integrations-channels-github.md +0 -156
- package/dist/docs/references/integrations-databases-dynamodb.md +0 -286
- package/dist/docs/references/integrations-databases-libsql.md +0 -161
- package/dist/docs/references/integrations-vectors-libsql.md +0 -325
- package/dist/docs/references/reference-ai-sdk-overview.md +0 -144
- package/dist/docs/references/reference-core-getMemory.md +0 -53
- package/dist/docs/references/reference-core-listMemory.md +0 -59
- package/dist/docs/references/reference-core-mastra-class.md +0 -177
- package/dist/docs/references/reference-file-based-agents-memory.md +0 -60
- package/dist/docs/references/reference-file-based-agents-storage.md +0 -32
- package/dist/docs/references/reference-memory-memory-class.md +0 -237
- package/dist/docs/references/reference-rag-retrieval.md +0 -672
- package/dist/docs/references/reference-storage-composite.md +0 -433
- package/dist/docs/references/reference-storage-retention.md +0 -310
- /package/dist/_types/{@internal_core → @internal_core@0.1.4}/dist/memory/index.d.ts +0 -0
- /package/dist/_types/{@internal_core → @internal_core@0.1.4}/package.json +0 -0
package/dist/_types/{@internal_core → @internal_core@0.1.4}/dist/knowledge-compat/index.d.ts
RENAMED
|
@@ -318,6 +318,7 @@ export interface KnowledgePagesCore {
|
|
|
318
318
|
MAX_KNOWLEDGE_MOVE_PAGES: number;
|
|
319
319
|
MAX_KNOWLEDGE_PAGE_DEPTH: number;
|
|
320
320
|
MAX_KNOWLEDGE_PAGE_LIST_LIMIT: number;
|
|
321
|
+
MAX_KNOWLEDGE_PAGE_LINKS: number;
|
|
321
322
|
KnowledgeMoveTooLargeError: new (pageId: string, pages: number) => Error;
|
|
322
323
|
KnowledgePageDepthError: new (pageId: string) => Error;
|
|
323
324
|
KnowledgePageHasChildrenError: new (pageId: string) => Error;
|
|
@@ -325,11 +326,25 @@ export interface KnowledgePagesCore {
|
|
|
325
326
|
}
|
|
326
327
|
/** Loads core's page-store runtime once, after checking core advertises `knowledge-pages`. */
|
|
327
328
|
export declare function createKnowledgePagesCoreLoader(features: ReadonlySet<string>, loadStorageModule: () => Promise<unknown>): () => Promise<KnowledgePagesCore>;
|
|
329
|
+
/** Most words one keyword search uses; every word adds a substring check per page in each store. */
|
|
330
|
+
export declare const KNOWLEDGE_SEARCH_MAX_WORDS = 16;
|
|
328
331
|
/**
|
|
329
|
-
* Keyword-search words: the query split on whitespace, lowercased, deduplicated
|
|
330
|
-
*
|
|
332
|
+
* Keyword-search words: the query split on whitespace, lowercased, deduplicated, keeping the first
|
|
333
|
+
* {@link KNOWLEDGE_SEARCH_MAX_WORDS}. A hit needs at least one of them (as a case-insensitive
|
|
334
|
+
* substring); an empty list means the search returns nothing.
|
|
331
335
|
*/
|
|
332
336
|
export declare function knowledgeSearchWords(query: string): string[];
|
|
337
|
+
/**
|
|
338
|
+
* Points one matched search word earns on a page, by the best field it appears in: name, then
|
|
339
|
+
* description, then body. A page whose name contains the whole query ranks first; below that, pages
|
|
340
|
+
* rank by how many query words they match, and these points only break ties between pages that
|
|
341
|
+
* match the same number of words.
|
|
342
|
+
*/
|
|
343
|
+
export declare const KNOWLEDGE_SEARCH_WEIGHTS: {
|
|
344
|
+
readonly name: 3;
|
|
345
|
+
readonly description: 2;
|
|
346
|
+
readonly body: 1;
|
|
347
|
+
};
|
|
333
348
|
/**
|
|
334
349
|
* Why `key` can't be a Knowledge page key, or undefined when it can. Keys are one path segment:
|
|
335
350
|
* non-empty, with no `/` (path separator), `#` (scope/path separator) or `%` (escape character).
|
package/dist/index.cjs
CHANGED
|
@@ -2644,7 +2644,8 @@ var AgentsLibSQL = class extends _mastra_core_storage.AgentsStorage {
|
|
|
2644
2644
|
"skillsFormat",
|
|
2645
2645
|
"durable",
|
|
2646
2646
|
"browser",
|
|
2647
|
-
"toolProviders"
|
|
2647
|
+
"toolProviders",
|
|
2648
|
+
"modelList"
|
|
2648
2649
|
]
|
|
2649
2650
|
});
|
|
2650
2651
|
await this.#migrateToolsToJsonbFormat();
|
|
@@ -3061,8 +3062,9 @@ var AgentsLibSQL = class extends _mastra_core_storage.AgentsStorage {
|
|
|
3061
3062
|
versionNumber: input.versionNumber,
|
|
3062
3063
|
name: input.name ?? null,
|
|
3063
3064
|
description: input.description ?? null,
|
|
3064
|
-
instructions: this.serializeInstructions(input.instructions),
|
|
3065
|
-
model: input.model,
|
|
3065
|
+
instructions: this.serializeInstructions(input.instructions ?? ""),
|
|
3066
|
+
model: input.model ?? {},
|
|
3067
|
+
modelList: input.modelList ?? null,
|
|
3066
3068
|
tools: input.tools ?? null,
|
|
3067
3069
|
defaultOptions: input.defaultOptions ?? null,
|
|
3068
3070
|
workflows: input.workflows ?? null,
|
|
@@ -3319,6 +3321,7 @@ var AgentsLibSQL = class extends _mastra_core_storage.AgentsStorage {
|
|
|
3319
3321
|
description: row.description,
|
|
3320
3322
|
instructions: this.deserializeInstructions(row.instructions),
|
|
3321
3323
|
model: this.parseJson(row.model, "model"),
|
|
3324
|
+
modelList: this.parseJson(row.modelList, "modelList"),
|
|
3322
3325
|
tools: this.parseJson(row.tools, "tools"),
|
|
3323
3326
|
defaultOptions: this.parseJson(row.defaultOptions, "defaultOptions"),
|
|
3324
3327
|
workflows: this.parseJson(row.workflows, "workflows"),
|
|
@@ -6647,7 +6650,8 @@ const KNOWLEDGE_PAGES_CORE_FUNCTIONS = [
|
|
|
6647
6650
|
const KNOWLEDGE_PAGES_CORE_NUMBERS = [
|
|
6648
6651
|
"MAX_KNOWLEDGE_MOVE_PAGES",
|
|
6649
6652
|
"MAX_KNOWLEDGE_PAGE_DEPTH",
|
|
6650
|
-
"MAX_KNOWLEDGE_PAGE_LIST_LIMIT"
|
|
6653
|
+
"MAX_KNOWLEDGE_PAGE_LIST_LIMIT",
|
|
6654
|
+
"MAX_KNOWLEDGE_PAGE_LINKS"
|
|
6651
6655
|
];
|
|
6652
6656
|
function resolveKnowledgePagesCore(storageModule) {
|
|
6653
6657
|
const module = typeof storageModule === "object" && storageModule !== null ? storageModule : {};
|
|
@@ -6668,13 +6672,25 @@ function createKnowledgePagesCoreLoader(features, loadStorageModule) {
|
|
|
6668
6672
|
};
|
|
6669
6673
|
}
|
|
6670
6674
|
/**
|
|
6671
|
-
* Keyword-search words: the query split on whitespace, lowercased, deduplicated
|
|
6672
|
-
*
|
|
6675
|
+
* Keyword-search words: the query split on whitespace, lowercased, deduplicated, keeping the first
|
|
6676
|
+
* {@link KNOWLEDGE_SEARCH_MAX_WORDS}. A hit needs at least one of them (as a case-insensitive
|
|
6677
|
+
* substring); an empty list means the search returns nothing.
|
|
6673
6678
|
*/
|
|
6674
6679
|
function knowledgeSearchWords(query) {
|
|
6675
|
-
return [...new Set(query.toLowerCase().split(/\s+/).filter(Boolean))];
|
|
6680
|
+
return [...new Set(query.toLowerCase().split(/\s+/).filter(Boolean))].slice(0, 16);
|
|
6676
6681
|
}
|
|
6677
6682
|
/**
|
|
6683
|
+
* Points one matched search word earns on a page, by the best field it appears in: name, then
|
|
6684
|
+
* description, then body. A page whose name contains the whole query ranks first; below that, pages
|
|
6685
|
+
* rank by how many query words they match, and these points only break ties between pages that
|
|
6686
|
+
* match the same number of words.
|
|
6687
|
+
*/
|
|
6688
|
+
const KNOWLEDGE_SEARCH_WEIGHTS = {
|
|
6689
|
+
name: 3,
|
|
6690
|
+
description: 2,
|
|
6691
|
+
body: 1
|
|
6692
|
+
};
|
|
6693
|
+
/**
|
|
6678
6694
|
* Why `key` can't be a Knowledge page key, or undefined when it can. Keys are one path segment:
|
|
6679
6695
|
* non-empty, with no `/` (path separator), `#` (scope/path separator) or `%` (escape character).
|
|
6680
6696
|
*/
|
|
@@ -6693,9 +6709,37 @@ const KNOWLEDGE_PAGE_TABLES = {
|
|
|
6693
6709
|
mentions: "mastra_knowledge_mentions",
|
|
6694
6710
|
pins: "mastra_knowledge_pins",
|
|
6695
6711
|
pinAudiences: "mastra_knowledge_pin_audiences",
|
|
6696
|
-
activity: "mastra_knowledge_activity"
|
|
6712
|
+
activity: "mastra_knowledge_activity",
|
|
6713
|
+
links: "mastra_knowledge_page_links"
|
|
6697
6714
|
};
|
|
6698
6715
|
const T = KNOWLEDGE_PAGE_TABLES;
|
|
6716
|
+
function pinsTableDDL(name) {
|
|
6717
|
+
return `CREATE TABLE IF NOT EXISTS "${name}" (
|
|
6718
|
+
id TEXT PRIMARY KEY,
|
|
6719
|
+
pageId TEXT NOT NULL,
|
|
6720
|
+
kind TEXT NOT NULL DEFAULT 'page',
|
|
6721
|
+
depth INTEGER,
|
|
6722
|
+
audience TEXT NOT NULL,
|
|
6723
|
+
createdBy TEXT NOT NULL,
|
|
6724
|
+
createdAt TEXT NOT NULL,
|
|
6725
|
+
updatedAt TEXT NOT NULL,
|
|
6726
|
+
UNIQUE (pageId, kind)
|
|
6727
|
+
)`;
|
|
6728
|
+
}
|
|
6729
|
+
/**
|
|
6730
|
+
* Pins tables from before pin kinds kept one pin per page (`pageId UNIQUE`). SQLite can't drop that
|
|
6731
|
+
* constraint in place, so the table is rebuilt with every existing pin as a `page` pin. Run after
|
|
6732
|
+
* {@link KNOWLEDGE_PAGE_DDL}, in the same transaction; a no-op once `kind` exists.
|
|
6733
|
+
*/
|
|
6734
|
+
async function upgradeKnowledgePinKinds(tx) {
|
|
6735
|
+
if ((await tx.execute(`SELECT name FROM pragma_table_info('${T.pins}')`)).rows.some((row) => String(row.name) === "kind")) return;
|
|
6736
|
+
const next = `${T.pins}_kinds`;
|
|
6737
|
+
await tx.execute(`DROP TABLE IF EXISTS "${next}"`);
|
|
6738
|
+
await tx.execute(pinsTableDDL(next));
|
|
6739
|
+
await tx.execute(`INSERT INTO "${next}" (id, pageId, kind, audience, createdBy, createdAt, updatedAt) SELECT id, pageId, 'page', audience, createdBy, createdAt, updatedAt FROM "${T.pins}"`);
|
|
6740
|
+
await tx.execute(`DROP TABLE "${T.pins}"`);
|
|
6741
|
+
await tx.execute(`ALTER TABLE "${next}" RENAME TO "${T.pins}"`);
|
|
6742
|
+
}
|
|
6699
6743
|
/** DDL for the schema-4 page tables, in creation order. Every statement is idempotent. */
|
|
6700
6744
|
const KNOWLEDGE_PAGE_DDL = [
|
|
6701
6745
|
`CREATE TABLE IF NOT EXISTS "mastra_knowledge_access_state" (
|
|
@@ -6759,14 +6803,7 @@ const KNOWLEDGE_PAGE_DDL = [
|
|
|
6759
6803
|
PRIMARY KEY (noteId, pageId)
|
|
6760
6804
|
)`,
|
|
6761
6805
|
`CREATE INDEX IF NOT EXISTS idx_kmentions_page ON "${T.mentions}" (pageId)`,
|
|
6762
|
-
|
|
6763
|
-
id TEXT PRIMARY KEY,
|
|
6764
|
-
pageId TEXT NOT NULL UNIQUE,
|
|
6765
|
-
audience TEXT NOT NULL,
|
|
6766
|
-
createdBy TEXT NOT NULL,
|
|
6767
|
-
createdAt TEXT NOT NULL,
|
|
6768
|
-
updatedAt TEXT NOT NULL
|
|
6769
|
-
)`,
|
|
6806
|
+
pinsTableDDL(T.pins),
|
|
6770
6807
|
`CREATE TABLE IF NOT EXISTS "${T.pinAudiences}" (
|
|
6771
6808
|
pinId TEXT NOT NULL,
|
|
6772
6809
|
audience TEXT NOT NULL,
|
|
@@ -6783,7 +6820,16 @@ const KNOWLEDGE_PAGE_DDL = [
|
|
|
6783
6820
|
provenance TEXT NOT NULL,
|
|
6784
6821
|
createdAt TEXT NOT NULL
|
|
6785
6822
|
)`,
|
|
6786
|
-
`CREATE INDEX IF NOT EXISTS idx_kactivity_page ON "${T.activity}" (pageId, id DESC)
|
|
6823
|
+
`CREATE INDEX IF NOT EXISTS idx_kactivity_page ON "${T.activity}" (pageId, id DESC)`,
|
|
6824
|
+
`CREATE TABLE IF NOT EXISTS "${T.links}" (
|
|
6825
|
+
fromPageId TEXT NOT NULL,
|
|
6826
|
+
ref TEXT NOT NULL,
|
|
6827
|
+
toPageId TEXT,
|
|
6828
|
+
count INTEGER NOT NULL,
|
|
6829
|
+
PRIMARY KEY (fromPageId, ref)
|
|
6830
|
+
) WITHOUT ROWID`,
|
|
6831
|
+
`CREATE INDEX IF NOT EXISTS idx_klinks_to ON "${T.links}" (toPageId) WHERE toPageId IS NOT NULL`,
|
|
6832
|
+
`CREATE INDEX IF NOT EXISTS idx_klinks_ref ON "${T.links}" (ref) WHERE toPageId IS NULL`
|
|
6787
6833
|
];
|
|
6788
6834
|
function str(value) {
|
|
6789
6835
|
return value === null || value === void 0 ? void 0 : String(value);
|
|
@@ -6838,6 +6884,8 @@ function toPin(row) {
|
|
|
6838
6884
|
return {
|
|
6839
6885
|
id: String(row.id),
|
|
6840
6886
|
pageId: String(row.pageId),
|
|
6887
|
+
kind: String(row.kind),
|
|
6888
|
+
...row.depth !== null && row.depth !== void 0 ? { depth: Number(row.depth) } : {},
|
|
6841
6889
|
audience: JSON.parse(String(row.audience)),
|
|
6842
6890
|
createdBy: String(row.createdBy),
|
|
6843
6891
|
createdAt: new Date(String(row.createdAt)),
|
|
@@ -6966,10 +7014,11 @@ var LibSQLKnowledgePages = class {
|
|
|
6966
7014
|
this.#read = config.read;
|
|
6967
7015
|
this.#transaction = config.transaction;
|
|
6968
7016
|
}
|
|
6969
|
-
/** Deletes every row from the page tables (scopes, pages, notes, pins, activity). */
|
|
7017
|
+
/** Deletes every row from the page tables (scopes, pages, notes, pins, activity, links). */
|
|
6970
7018
|
async clearAll() {
|
|
6971
7019
|
await this.#transaction(async (tx) => {
|
|
6972
7020
|
for (const table of [
|
|
7021
|
+
T.links,
|
|
6973
7022
|
T.activity,
|
|
6974
7023
|
T.pinAudiences,
|
|
6975
7024
|
T.pins,
|
|
@@ -7151,13 +7200,19 @@ var LibSQLKnowledgePages = class {
|
|
|
7151
7200
|
const limit = limitOf(input.limit, core.MAX_KNOWLEDGE_PAGE_LIST_LIMIT);
|
|
7152
7201
|
const cursor = decodeCursor(input.cursor, 2);
|
|
7153
7202
|
const args = [input.parentId];
|
|
7203
|
+
let filter = "";
|
|
7204
|
+
if (input.read) {
|
|
7205
|
+
const readable = readableScopes(input.read);
|
|
7206
|
+
filter = ` AND id IN (${readable.sql})`;
|
|
7207
|
+
args.push(...readable.args);
|
|
7208
|
+
}
|
|
7154
7209
|
let after = "";
|
|
7155
7210
|
if (cursor) {
|
|
7156
7211
|
after = ` AND (position > ? OR (position = ? AND id > ?))`;
|
|
7157
7212
|
args.push(cursor[0], cursor[0], cursor[1]);
|
|
7158
7213
|
}
|
|
7159
7214
|
args.push(limit + 1);
|
|
7160
|
-
const rows = await this.#query(this.#read, `SELECT * FROM "${T.pages}" WHERE isScope = 1 AND parentId IS ?${after} ORDER BY position, id LIMIT ?`, args);
|
|
7215
|
+
const rows = await this.#query(this.#read, `SELECT * FROM "${T.pages}" WHERE isScope = 1 AND parentId IS ?${filter}${after} ORDER BY position, id LIMIT ?`, args);
|
|
7161
7216
|
return this.#pageOutput(rows, limit, (row) => [String(row.position), String(row.id)]);
|
|
7162
7217
|
}
|
|
7163
7218
|
#pageOutput(rows, limit, cursorOf) {
|
|
@@ -7442,9 +7497,8 @@ var LibSQLKnowledgePages = class {
|
|
|
7442
7497
|
args: [input.sourceId]
|
|
7443
7498
|
});
|
|
7444
7499
|
const pins = await this.#query(tx, `SELECT * FROM "${T.pins}" WHERE pageId IN (?, ?)`, [input.sourceId, input.targetId]);
|
|
7445
|
-
const sourcePin
|
|
7446
|
-
|
|
7447
|
-
const targetPin = pins.find((pin) => String(pin.pageId) === input.targetId);
|
|
7500
|
+
for (const sourcePin of pins.filter((pin) => String(pin.pageId) === input.sourceId)) {
|
|
7501
|
+
const targetPin = pins.find((pin) => String(pin.pageId) === input.targetId && pin.kind === sourcePin.kind);
|
|
7448
7502
|
const audience = JSON.parse(String(sourcePin.audience));
|
|
7449
7503
|
if (targetPin) {
|
|
7450
7504
|
const merged = [.../* @__PURE__ */ new Set([...JSON.parse(String(targetPin.audience)), ...audience])];
|
|
@@ -7544,6 +7598,129 @@ var LibSQLKnowledgePages = class {
|
|
|
7544
7598
|
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);
|
|
7545
7599
|
return this.#noteOutput(rows, limit);
|
|
7546
7600
|
}
|
|
7601
|
+
async countChildScopes(input) {
|
|
7602
|
+
const ids = [...new Set(input.parentIds)];
|
|
7603
|
+
const counts = Object.fromEntries(ids.map((id) => [id, 0]));
|
|
7604
|
+
if (ids.length === 0) return counts;
|
|
7605
|
+
const readable = readableScopes(input.read);
|
|
7606
|
+
const rows = await this.#query(this.#read, `SELECT parentId, COUNT(*) AS total FROM "${T.pages}" WHERE parentId IN (SELECT value FROM json_each(?)) AND isScope = 1 AND id IN (${readable.sql}) GROUP BY parentId`, [jsonList(ids), ...readable.args]);
|
|
7607
|
+
for (const row of rows) counts[String(row.parentId)] = Number(row.total);
|
|
7608
|
+
return counts;
|
|
7609
|
+
}
|
|
7610
|
+
async countChildPages(input) {
|
|
7611
|
+
const ids = [...new Set(input.parentIds)];
|
|
7612
|
+
const counts = Object.fromEntries(ids.map((id) => [id, 0]));
|
|
7613
|
+
if (ids.length === 0) return counts;
|
|
7614
|
+
const readable = pageReadable("p", input.read);
|
|
7615
|
+
const rows = await this.#query(this.#read, `SELECT p.parentId AS parentId, COUNT(*) AS total FROM "${T.pages}" p WHERE p.parentId IN (SELECT value FROM json_each(?)) AND p.isScope = 0 AND p.deletedAt IS NULL AND ${readable.sql} GROUP BY p.parentId`, [jsonList(ids), ...readable.args]);
|
|
7616
|
+
for (const row of rows) counts[String(row.parentId)] = Number(row.total);
|
|
7617
|
+
return counts;
|
|
7618
|
+
}
|
|
7619
|
+
async replacePageBodyLinks(input) {
|
|
7620
|
+
await this.#transaction(async (tx) => {
|
|
7621
|
+
await tx.execute({
|
|
7622
|
+
sql: `DELETE FROM "${T.links}" WHERE fromPageId = ?`,
|
|
7623
|
+
args: [input.pageId]
|
|
7624
|
+
});
|
|
7625
|
+
if (input.links.length === 0) return;
|
|
7626
|
+
await tx.execute({
|
|
7627
|
+
sql: `INSERT INTO "${T.links}" (fromPageId, ref, toPageId, count) SELECT ?, json_extract(value, '$.ref'), json_extract(value, '$.toPageId'), json_extract(value, '$.count') FROM json_each(?)`,
|
|
7628
|
+
args: [input.pageId, JSON.stringify(input.links.map(({ ref, toPageId, count }) => ({
|
|
7629
|
+
ref,
|
|
7630
|
+
toPageId,
|
|
7631
|
+
count
|
|
7632
|
+
})))]
|
|
7633
|
+
});
|
|
7634
|
+
});
|
|
7635
|
+
}
|
|
7636
|
+
async listPageBodyLinkSources(input) {
|
|
7637
|
+
const refs = input.refs ?? [];
|
|
7638
|
+
const targets = input.toPageIds ?? [];
|
|
7639
|
+
if (refs.length === 0 && targets.length === 0) return [];
|
|
7640
|
+
return (await this.#query(this.#read, `SELECT DISTINCT fromPageId FROM "${T.links}" WHERE (toPageId IS NULL AND ref IN (SELECT value FROM json_each(?))) OR toPageId IN (SELECT value FROM json_each(?)) ORDER BY fromPageId`, [jsonList(refs), jsonList(targets)])).map((row) => String(row.fromPageId));
|
|
7641
|
+
}
|
|
7642
|
+
/**
|
|
7643
|
+
* Visible links touching `ids` (from them for `out`, to them for `in`): resolved, both ends live
|
|
7644
|
+
* and readable, not self-links; a note link also needs a visible live note. One row per
|
|
7645
|
+
* (from, to, kind), counts summed.
|
|
7646
|
+
*/
|
|
7647
|
+
async #links(read, kinds, ids, direction) {
|
|
7648
|
+
const wanted = new Set(kinds ?? ["body", "note"]);
|
|
7649
|
+
const touches = (from, to) => {
|
|
7650
|
+
const parts = [];
|
|
7651
|
+
const args = [];
|
|
7652
|
+
if (direction !== "in") {
|
|
7653
|
+
parts.push(`${from} IN (SELECT value FROM json_each(?))`);
|
|
7654
|
+
args.push(jsonList(ids));
|
|
7655
|
+
}
|
|
7656
|
+
if (direction !== "out") {
|
|
7657
|
+
parts.push(`${to} IN (SELECT value FROM json_each(?))`);
|
|
7658
|
+
args.push(jsonList(ids));
|
|
7659
|
+
}
|
|
7660
|
+
return {
|
|
7661
|
+
sql: `(${parts.join(" OR ")})`,
|
|
7662
|
+
args
|
|
7663
|
+
};
|
|
7664
|
+
};
|
|
7665
|
+
const sources = [];
|
|
7666
|
+
const args = [];
|
|
7667
|
+
if (wanted.has("body")) {
|
|
7668
|
+
const near = touches("l.fromPageId", "l.toPageId");
|
|
7669
|
+
sources.push(`SELECT l.fromPageId AS fromPageId, l.toPageId AS toPageId, 'body' AS kind, l.count AS count FROM "${T.links}" l WHERE l.toPageId IS NOT NULL AND ${near.sql}`);
|
|
7670
|
+
args.push(...near.args);
|
|
7671
|
+
}
|
|
7672
|
+
if (wanted.has("note")) {
|
|
7673
|
+
const near = touches("n.pageId", "m.pageId");
|
|
7674
|
+
const visible = noteReadable("n", read);
|
|
7675
|
+
sources.push(`SELECT n.pageId AS fromPageId, m.pageId AS toPageId, 'note' AS kind, 1 AS count FROM "${T.mentions}" m JOIN "${T.notes}" n ON n.id = m.noteId WHERE n.deletedAt IS NULL AND ${near.sql} AND ${visible.sql}`);
|
|
7676
|
+
args.push(...near.args, ...visible.args);
|
|
7677
|
+
}
|
|
7678
|
+
if (sources.length === 0) return [];
|
|
7679
|
+
const fromReadable = pageReadable("fp", read);
|
|
7680
|
+
const toReadable = pageReadable("tp", read);
|
|
7681
|
+
return this.#query(this.#read, `SELECT e.fromPageId AS fromPageId, e.toPageId AS toPageId, e.kind AS kind, SUM(e.count) AS count
|
|
7682
|
+
FROM (${sources.join(" UNION ALL ")}) e
|
|
7683
|
+
JOIN "${T.pages}" fp ON fp.id = e.fromPageId AND fp.deletedAt IS NULL AND ${fromReadable.sql}
|
|
7684
|
+
JOIN "${T.pages}" tp ON tp.id = e.toPageId AND tp.deletedAt IS NULL AND ${toReadable.sql}
|
|
7685
|
+
WHERE e.fromPageId <> e.toPageId
|
|
7686
|
+
GROUP BY e.fromPageId, e.toPageId, e.kind
|
|
7687
|
+
ORDER BY e.fromPageId, e.toPageId, CASE e.kind WHEN 'body' THEN 0 ELSE 1 END`, [
|
|
7688
|
+
...args,
|
|
7689
|
+
...fromReadable.args,
|
|
7690
|
+
...toReadable.args
|
|
7691
|
+
]);
|
|
7692
|
+
}
|
|
7693
|
+
async countPageLinks(input) {
|
|
7694
|
+
const ids = [...new Set(input.pageIds)];
|
|
7695
|
+
const linked = new Map(ids.map((id) => [id, {
|
|
7696
|
+
in: /* @__PURE__ */ new Set(),
|
|
7697
|
+
out: /* @__PURE__ */ new Set()
|
|
7698
|
+
}]));
|
|
7699
|
+
if (ids.length === 0) return {};
|
|
7700
|
+
for (const row of await this.#links(input.read, input.kinds, ids, "both")) {
|
|
7701
|
+
const from = String(row.fromPageId);
|
|
7702
|
+
const to = String(row.toPageId);
|
|
7703
|
+
linked.get(from)?.out.add(to);
|
|
7704
|
+
linked.get(to)?.in.add(from);
|
|
7705
|
+
}
|
|
7706
|
+
return Object.fromEntries([...linked].map(([id, sets]) => [id, {
|
|
7707
|
+
in: sets.in.size,
|
|
7708
|
+
out: sets.out.size
|
|
7709
|
+
}]));
|
|
7710
|
+
}
|
|
7711
|
+
async listPageLinks(input) {
|
|
7712
|
+
const limit = input.limit ?? 1e3;
|
|
7713
|
+
if (!Number.isInteger(limit) || limit < 1) throw new RangeError("Knowledge link limit must be a positive integer");
|
|
7714
|
+
const ids = [...new Set(input.pageIds)];
|
|
7715
|
+
if (ids.length === 0) return [];
|
|
7716
|
+
const core = await loadPagesCore();
|
|
7717
|
+
return (await this.#links(input.read, input.kinds, ids, input.direction ?? "both")).slice(0, Math.min(limit, core.MAX_KNOWLEDGE_PAGE_LINKS)).map((row) => ({
|
|
7718
|
+
fromPageId: String(row.fromPageId),
|
|
7719
|
+
toPageId: String(row.toPageId),
|
|
7720
|
+
kind: row.kind === "note" ? "note" : "body",
|
|
7721
|
+
count: Number(row.count)
|
|
7722
|
+
}));
|
|
7723
|
+
}
|
|
7547
7724
|
async countNotes(input) {
|
|
7548
7725
|
const ids = [...new Set(input.pageIds)];
|
|
7549
7726
|
const counts = Object.fromEntries(ids.map((id) => [id, 0]));
|
|
@@ -7715,18 +7892,22 @@ var LibSQLKnowledgePages = class {
|
|
|
7715
7892
|
const readable = pageReadable("p", input.read);
|
|
7716
7893
|
const scopeFilter = input.scopeIds ? ` AND p.scopeId IN (SELECT value FROM json_each(?))` : "";
|
|
7717
7894
|
const scopeArgs = input.scopeIds ? [jsonList(input.scopeIds)] : [];
|
|
7718
|
-
const
|
|
7719
|
-
const
|
|
7720
|
-
const
|
|
7895
|
+
const field = (column) => `lower(COALESCE(${column}, '')) LIKE ? ESCAPE '='`;
|
|
7896
|
+
const pageMatch = words.map(() => `(${field("p.name")} OR ${field("p.description")} OR ${field("p.body")})`).join(" OR ");
|
|
7897
|
+
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(" + ");
|
|
7898
|
+
const pageCount = words.map(() => `(CASE WHEN ${field("p.name")} OR ${field("p.description")} OR ${field("p.body")} THEN 1 ELSE 0 END)`).join(" + ");
|
|
7899
|
+
const triple = likes.flatMap((like) => [
|
|
7900
|
+
like,
|
|
7901
|
+
like,
|
|
7902
|
+
like
|
|
7903
|
+
]);
|
|
7904
|
+
const hits = (await this.#query(this.#read, `SELECT p.* FROM "${T.pages}" p WHERE p.deletedAt IS NULL AND p.isScope = 0 AND ${readable.sql}${scopeFilter} AND (${pageMatch}) ORDER BY CASE WHEN instr(p.canonicalName, ?) > 0 THEN 0 ELSE 1 END, (${pageCount}) DESC, (${pageScore}) DESC, p.updatedAt DESC, p.id ASC LIMIT ?`, [
|
|
7721
7905
|
...readable.args,
|
|
7722
7906
|
...scopeArgs,
|
|
7723
|
-
...
|
|
7724
|
-
like,
|
|
7725
|
-
like,
|
|
7726
|
-
like
|
|
7727
|
-
]),
|
|
7907
|
+
...triple,
|
|
7728
7908
|
phrase,
|
|
7729
|
-
...
|
|
7909
|
+
...triple,
|
|
7910
|
+
...triple,
|
|
7730
7911
|
limit
|
|
7731
7912
|
])).map((row) => ({
|
|
7732
7913
|
type: "page",
|
|
@@ -7734,11 +7915,12 @@ var LibSQLKnowledgePages = class {
|
|
|
7734
7915
|
}));
|
|
7735
7916
|
if (hits.length >= limit) return hits;
|
|
7736
7917
|
const noteVisible = noteReadable("n", input.read);
|
|
7737
|
-
const
|
|
7738
|
-
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 ${
|
|
7918
|
+
const noteHas = words.map(() => `lower(n.text) LIKE ? ESCAPE '='`);
|
|
7919
|
+
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 ?`, [
|
|
7739
7920
|
...scopeArgs,
|
|
7740
7921
|
...likes,
|
|
7741
7922
|
...noteVisible.args,
|
|
7923
|
+
...likes,
|
|
7742
7924
|
limit - hits.length
|
|
7743
7925
|
]);
|
|
7744
7926
|
const notes = await this.#hydrateNotes(this.#read, noteRows);
|
|
@@ -7800,17 +7982,21 @@ var LibSQLKnowledgePages = class {
|
|
|
7800
7982
|
});
|
|
7801
7983
|
}
|
|
7802
7984
|
addPinAudience(input) {
|
|
7985
|
+
const kind = input.kind ?? "page";
|
|
7986
|
+
const depth = kind === "list" ? input.depth ?? 1 : null;
|
|
7803
7987
|
return this.#transaction(async (tx) => {
|
|
7804
7988
|
const page = await this.#livePage(tx, input.pageId);
|
|
7805
7989
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
7806
|
-
const existing = (await this.#query(tx, `SELECT * FROM "${T.pins}" WHERE pageId = ?`, [input.pageId]))[0];
|
|
7990
|
+
const existing = (await this.#query(tx, `SELECT * FROM "${T.pins}" WHERE pageId = ? AND kind = ?`, [input.pageId, kind]))[0];
|
|
7807
7991
|
if (!existing) {
|
|
7808
7992
|
const id = (0, _mastra_core_storage.createKnowledgeUlid)();
|
|
7809
7993
|
await tx.execute({
|
|
7810
|
-
sql: `INSERT INTO "${T.pins}" (id, pageId, audience, createdBy, createdAt, updatedAt) VALUES (?, ?, ?, ?, ?, ?)`,
|
|
7994
|
+
sql: `INSERT INTO "${T.pins}" (id, pageId, kind, depth, audience, createdBy, createdAt, updatedAt) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
7811
7995
|
args: [
|
|
7812
7996
|
id,
|
|
7813
7997
|
input.pageId,
|
|
7998
|
+
kind,
|
|
7999
|
+
depth,
|
|
7814
8000
|
JSON.stringify([...new Set(input.audience)]),
|
|
7815
8001
|
input.createdBy,
|
|
7816
8002
|
now,
|
|
@@ -7827,11 +8013,13 @@ var LibSQLKnowledgePages = class {
|
|
|
7827
8013
|
}
|
|
7828
8014
|
const current = JSON.parse(String(existing.audience));
|
|
7829
8015
|
const merged = [.../* @__PURE__ */ new Set([...current, ...input.audience])];
|
|
7830
|
-
|
|
8016
|
+
const depthChanged = (existing.depth === null ? null : Number(existing.depth)) !== depth;
|
|
8017
|
+
if (merged.length !== current.length || depthChanged) {
|
|
7831
8018
|
await tx.execute({
|
|
7832
|
-
sql: `UPDATE "${T.pins}" SET audience = ?, updatedAt = ? WHERE id = ?`,
|
|
8019
|
+
sql: `UPDATE "${T.pins}" SET audience = ?, depth = ?, updatedAt = ? WHERE id = ?`,
|
|
7833
8020
|
args: [
|
|
7834
8021
|
JSON.stringify(merged),
|
|
8022
|
+
depth,
|
|
7835
8023
|
now,
|
|
7836
8024
|
String(existing.id)
|
|
7837
8025
|
]
|
|
@@ -7848,7 +8036,7 @@ var LibSQLKnowledgePages = class {
|
|
|
7848
8036
|
}
|
|
7849
8037
|
removePinAudience(input) {
|
|
7850
8038
|
return this.#transaction(async (tx) => {
|
|
7851
|
-
const existing = (await this.#query(tx, `SELECT * FROM "${T.pins}" WHERE pageId = ?`, [input.pageId]))[0];
|
|
8039
|
+
const existing = (await this.#query(tx, `SELECT * FROM "${T.pins}" WHERE pageId = ? AND kind = ?`, [input.pageId, input.kind ?? "page"]))[0];
|
|
7852
8040
|
if (!existing) return null;
|
|
7853
8041
|
const current = JSON.parse(String(existing.audience));
|
|
7854
8042
|
const remove = new Set(input.audience);
|
|
@@ -7892,15 +8080,19 @@ var LibSQLKnowledgePages = class {
|
|
|
7892
8080
|
filters += ` AND pin.id IN (SELECT pa.pinId FROM json_each(?) a JOIN "${T.pinAudiences}" pa ON pa.audience = a.value)`;
|
|
7893
8081
|
args.push(jsonList(input.audience));
|
|
7894
8082
|
}
|
|
8083
|
+
if (input.kind) {
|
|
8084
|
+
filters += ` AND pin.kind = ?`;
|
|
8085
|
+
args.push(input.kind);
|
|
8086
|
+
}
|
|
7895
8087
|
if (input.pageIds) {
|
|
7896
8088
|
filters += ` AND pin.pageId IN (SELECT value FROM json_each(?))`;
|
|
7897
8089
|
args.push(jsonList(input.pageIds));
|
|
7898
8090
|
}
|
|
7899
8091
|
if (input.excludePageIds?.length) {
|
|
7900
|
-
filters += ` AND pin.pageId NOT IN (SELECT value FROM json_each(?))`;
|
|
8092
|
+
filters += ` AND (pin.kind <> 'page' OR pin.pageId NOT IN (SELECT value FROM json_each(?)))`;
|
|
7901
8093
|
args.push(jsonList(input.excludePageIds));
|
|
7902
8094
|
}
|
|
7903
|
-
if (input.withBody) filters += ` AND p.body IS NOT NULL AND trim(p.body, char(32, 9, 10, 11, 12, 13)) <> ''`;
|
|
8095
|
+
if (input.withBody) filters += ` AND (pin.kind <> 'page' OR (p.body IS NOT NULL AND trim(p.body, char(32, 9, 10, 11, 12, 13)) <> ''))`;
|
|
7904
8096
|
const from = `FROM "${T.pins}" pin JOIN "${T.pages}" p ON p.id = pin.pageId WHERE p.deletedAt IS NULL AND ${readable.sql}${filters}`;
|
|
7905
8097
|
let total;
|
|
7906
8098
|
if (input.count) total = Number((await this.#query(this.#read, `SELECT COUNT(*) AS n ${from}`, args))[0].n);
|
|
@@ -7972,7 +8164,8 @@ var KnowledgeLibSQL = class extends _mastra_core_storage.KnowledgeStorage {
|
|
|
7972
8164
|
contractVersion: 4,
|
|
7973
8165
|
schemaVersion: 4,
|
|
7974
8166
|
supportsSchemaInspection: true,
|
|
7975
|
-
supportsExplicitReset: true
|
|
8167
|
+
supportsExplicitReset: true,
|
|
8168
|
+
supportsPinKinds: true
|
|
7976
8169
|
};
|
|
7977
8170
|
}
|
|
7978
8171
|
async dangerouslyClearAll() {
|
|
@@ -8002,6 +8195,7 @@ var KnowledgeLibSQL = class extends _mastra_core_storage.KnowledgeStorage {
|
|
|
8002
8195
|
const inspection = await this.#inspectPages(tx);
|
|
8003
8196
|
if (inspection.status === "incompatible-reset-required") throw new _mastra_core_storage.KnowledgeSchemaResetRequiredError(inspection);
|
|
8004
8197
|
for (const statement of KNOWLEDGE_PAGE_DDL) await tx.execute(statement);
|
|
8198
|
+
await upgradeKnowledgePinKinds(tx);
|
|
8005
8199
|
await tx.execute({
|
|
8006
8200
|
sql: `INSERT OR IGNORE INTO "${TABLE_KNOWLEDGE_PAGES_STATE}" (id, schemaVersion) VALUES ('knowledge', ?)`,
|
|
8007
8201
|
args: [4]
|
|
@@ -8010,7 +8204,11 @@ var KnowledgeLibSQL = class extends _mastra_core_storage.KnowledgeStorage {
|
|
|
8010
8204
|
}
|
|
8011
8205
|
async dangerouslyReset() {
|
|
8012
8206
|
await withClientWriteLock(this.#client, async () => {
|
|
8013
|
-
await this.#client.batch([
|
|
8207
|
+
await this.#client.batch([
|
|
8208
|
+
...KNOWLEDGE_RESETTABLE_TABLE_NAMES,
|
|
8209
|
+
KNOWLEDGE_PAGE_TABLES.pinAudiences,
|
|
8210
|
+
KNOWLEDGE_PAGE_TABLES.links
|
|
8211
|
+
].map((table) => ({
|
|
8014
8212
|
sql: `DROP TABLE IF EXISTS "${table}"`,
|
|
8015
8213
|
args: []
|
|
8016
8214
|
})), "write");
|
|
@@ -8032,6 +8230,9 @@ var KnowledgeLibSQL = class extends _mastra_core_storage.KnowledgeStorage {
|
|
|
8032
8230
|
listChildScopes(input) {
|
|
8033
8231
|
return this.#pages.listChildScopes(input);
|
|
8034
8232
|
}
|
|
8233
|
+
countChildScopes(input) {
|
|
8234
|
+
return this.#pages.countChildScopes(input);
|
|
8235
|
+
}
|
|
8035
8236
|
getPage(input) {
|
|
8036
8237
|
return this.#pages.getPage(input);
|
|
8037
8238
|
}
|
|
@@ -8068,6 +8269,21 @@ var KnowledgeLibSQL = class extends _mastra_core_storage.KnowledgeStorage {
|
|
|
8068
8269
|
listNotes(input) {
|
|
8069
8270
|
return this.#pages.listNotes(input);
|
|
8070
8271
|
}
|
|
8272
|
+
countChildPages(input) {
|
|
8273
|
+
return this.#pages.countChildPages(input);
|
|
8274
|
+
}
|
|
8275
|
+
replacePageBodyLinks(input) {
|
|
8276
|
+
return this.#pages.replacePageBodyLinks(input);
|
|
8277
|
+
}
|
|
8278
|
+
listPageBodyLinkSources(input) {
|
|
8279
|
+
return this.#pages.listPageBodyLinkSources(input);
|
|
8280
|
+
}
|
|
8281
|
+
countPageLinks(input) {
|
|
8282
|
+
return this.#pages.countPageLinks(input);
|
|
8283
|
+
}
|
|
8284
|
+
listPageLinks(input) {
|
|
8285
|
+
return this.#pages.listPageLinks(input);
|
|
8286
|
+
}
|
|
8071
8287
|
countNotes(input) {
|
|
8072
8288
|
return this.#pages.countNotes(input);
|
|
8073
8289
|
}
|