@mastra/mongodb 1.17.1-alpha.0 → 1.18.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 +36 -0
- package/dist/docs/SKILL.md +1 -1
- package/dist/docs/assets/SOURCE_MAP.json +1 -1
- package/dist/docs/references/docs-storage.md +1 -0
- package/dist/docs/references/reference-rag-retrieval.md +26 -18
- package/dist/index.cjs +807 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +808 -3
- package/dist/index.js.map +1 -1
- package/dist/storage/domains/knowledge/index.d.ts +82 -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.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { v4 } from "@lukeed/uuid";
|
|
2
2
|
import { ErrorCategory, ErrorDomain, MastraError } from "@mastra/core/error";
|
|
3
|
-
import { AgentsStorage, BackgroundTasksStorage, BlobStore, DatasetsStorage, ExperimentsStorage, MCPClientsStorage, MCPServersStorage, MastraCompositeStore, MemoryStorage, NotificationsStorage, ObservabilityStorage, PromptBlocksStorage, SchedulesStorage, ScorerDefinitionsStorage, ScoresStorage, SkillsStorage, TABLE_AGENTS, TABLE_AGENT_VERSIONS, TABLE_BACKGROUND_TASKS, TABLE_DATASETS, TABLE_DATASET_ITEMS, TABLE_DATASET_VERSIONS, TABLE_EXPERIMENTS, TABLE_EXPERIMENT_RESULTS, TABLE_MCP_CLIENTS, TABLE_MCP_CLIENT_VERSIONS, TABLE_MCP_SERVERS, TABLE_MCP_SERVER_VERSIONS, TABLE_MESSAGES, TABLE_NOTIFICATIONS, TABLE_PROMPT_BLOCKS, TABLE_PROMPT_BLOCK_VERSIONS, TABLE_RESOURCES, TABLE_SCHEDULES, TABLE_SCHEDULE_TRIGGERS, TABLE_SCORERS, TABLE_SCORER_DEFINITIONS, TABLE_SCORER_DEFINITION_VERSIONS, TABLE_SKILLS, TABLE_SKILL_BLOBS, TABLE_SKILL_VERSIONS, TABLE_SPANS, TABLE_THREADS, TABLE_WORKFLOW_DEFINITIONS, TABLE_WORKFLOW_SNAPSHOT, TABLE_WORKSPACES, TABLE_WORKSPACE_VERSIONS, TraceStatus, WorkflowDefinitionsStorage, WorkflowsStorage, WorkspacesStorage, calculatePagination, createStorageErrorId, createVectorErrorId, ensureDate, hasErrorCode, listTracesArgsSchema, normalizePerPage, normalizeScheduleTarget, parseDuration, safelyParseJSON, storageMessageMatchesMetadataFilter, toTraceSpans, transformScoreRow, validateStorageMetadataFilter } from "@mastra/core/storage";
|
|
3
|
+
import { AgentsStorage, BackgroundTasksStorage, BlobStore, DatasetsStorage, ExperimentsStorage, KnowledgeConflictError, KnowledgeNotFoundError, KnowledgeStorage, MCPClientsStorage, MCPServersStorage, MastraCompositeStore, MemoryStorage, NotificationsStorage, ObservabilityStorage, PromptBlocksStorage, SchedulesStorage, ScorerDefinitionsStorage, ScoresStorage, SkillsStorage, TABLE_AGENTS, TABLE_AGENT_VERSIONS, TABLE_BACKGROUND_TASKS, TABLE_DATASETS, TABLE_DATASET_ITEMS, TABLE_DATASET_VERSIONS, TABLE_EXPERIMENTS, TABLE_EXPERIMENT_RESULTS, 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_NOTIFICATIONS, TABLE_PROMPT_BLOCKS, TABLE_PROMPT_BLOCK_VERSIONS, TABLE_RESOURCES, TABLE_SCHEDULES, TABLE_SCHEDULE_TRIGGERS, TABLE_SCORERS, TABLE_SCORER_DEFINITIONS, TABLE_SCORER_DEFINITION_VERSIONS, TABLE_SKILLS, TABLE_SKILL_BLOBS, TABLE_SKILL_VERSIONS, TABLE_SPANS, TABLE_THREADS, TABLE_WORKFLOW_DEFINITIONS, TABLE_WORKFLOW_SNAPSHOT, TABLE_WORKSPACES, TABLE_WORKSPACE_VERSIONS, TraceStatus, WorkflowDefinitionsStorage, WorkflowsStorage, WorkspacesStorage, assertKnowledgeCeilingRaised, assertKnowledgeScopeWithinCeiling, calculatePagination, canonicalizeKnowledgeScope, createKnowledgeUlid, createStorageErrorId, createVectorErrorId, ensureDate, hasErrorCode, isKnowledgeScopeVisible, knowledgeScopeKey, knowledgeSemanticDocumentId, knowledgeSemanticIdempotencyKey, listTracesArgsSchema, normalizePerPage, normalizeScheduleTarget, parseDuration, parseKnowledgeNodeCursor, parseKnowledgeWikilinks, safelyParseJSON, storageMessageMatchesMetadataFilter, toTraceSpans, transformScoreRow, validateStorageMetadataFilter } from "@mastra/core/storage";
|
|
4
4
|
import { MastraVector, validateUpsertInput, validateVectorValues } from "@mastra/core/vector";
|
|
5
5
|
import { MongoBulkWriteError, MongoClient, ObjectId } from "mongodb";
|
|
6
6
|
import { BaseFilterTranslator } from "@mastra/core/vector/filter";
|
|
@@ -9,7 +9,7 @@ import { MessageList } from "@mastra/core/agent";
|
|
|
9
9
|
import { saveScorePayloadSchema } from "@mastra/core/evals";
|
|
10
10
|
import { skillSnapshotFieldValuesEqual } from "@mastra/core/storage/domains/skills";
|
|
11
11
|
//#region package.json
|
|
12
|
-
var version = "1.
|
|
12
|
+
var version = "1.18.0";
|
|
13
13
|
//#endregion
|
|
14
14
|
//#region src/vector/filter.ts
|
|
15
15
|
/**
|
|
@@ -4292,6 +4292,809 @@ var MongoDBExperimentsStorage = class MongoDBExperimentsStorage extends Experime
|
|
|
4292
4292
|
}
|
|
4293
4293
|
};
|
|
4294
4294
|
//#endregion
|
|
4295
|
+
//#region src/storage/domains/knowledge/index.ts
|
|
4296
|
+
const cloneScope = (scope) => [...scope];
|
|
4297
|
+
const canonicalName = (name) => name.trim().toLocaleLowerCase();
|
|
4298
|
+
const nodeReferenceId = (node) => typeof node === "string" ? node : node.id;
|
|
4299
|
+
const sessionOptions = (session) => session ? { session } : {};
|
|
4300
|
+
function visibleScopeKeys(scope) {
|
|
4301
|
+
const canonical = canonicalizeKnowledgeScope(scope);
|
|
4302
|
+
return canonical.map((_, index) => knowledgeScopeKey(canonical.slice(0, index + 1)));
|
|
4303
|
+
}
|
|
4304
|
+
function recordCursorFilter(cursor, expected) {
|
|
4305
|
+
const parsed = parseKnowledgeNodeCursor(cursor, expected);
|
|
4306
|
+
return { $or: [{ updatedAt: { $lt: parsed.updatedAt } }, {
|
|
4307
|
+
updatedAt: parsed.updatedAt,
|
|
4308
|
+
$or: [{ name: { $gt: parsed.name } }, {
|
|
4309
|
+
name: parsed.name,
|
|
4310
|
+
id: { $gt: parsed.id }
|
|
4311
|
+
}]
|
|
4312
|
+
}] };
|
|
4313
|
+
}
|
|
4314
|
+
function nodeFromDocument(row) {
|
|
4315
|
+
return {
|
|
4316
|
+
id: String(row.id),
|
|
4317
|
+
type: "node",
|
|
4318
|
+
name: String(row.name),
|
|
4319
|
+
kind: String(row.kind),
|
|
4320
|
+
content: row.content == null ? void 0 : String(row.content),
|
|
4321
|
+
scope: cloneScope(row.scope),
|
|
4322
|
+
version: Number(row.version),
|
|
4323
|
+
mergedInto: row.mergedInto ?? void 0,
|
|
4324
|
+
createdAt: new Date(row.createdAt),
|
|
4325
|
+
updatedAt: new Date(row.updatedAt)
|
|
4326
|
+
};
|
|
4327
|
+
}
|
|
4328
|
+
function recordFromDocument(row) {
|
|
4329
|
+
return {
|
|
4330
|
+
id: String(row.id),
|
|
4331
|
+
node: String(row.node),
|
|
4332
|
+
text: String(row.text),
|
|
4333
|
+
scope: cloneScope(row.scope),
|
|
4334
|
+
sourceThreadId: String(row.sourceThreadId),
|
|
4335
|
+
capturedAt: new Date(row.capturedAt),
|
|
4336
|
+
when: row.when ? new Date(row.when) : void 0,
|
|
4337
|
+
maxScope: row.maxScope ?? void 0,
|
|
4338
|
+
metadata: row.metadata ?? void 0,
|
|
4339
|
+
deletedAt: row.deletedAt ? new Date(row.deletedAt) : void 0,
|
|
4340
|
+
deletedBy: row.deletedBy ?? void 0
|
|
4341
|
+
};
|
|
4342
|
+
}
|
|
4343
|
+
function outboxFromDocument(row) {
|
|
4344
|
+
return {
|
|
4345
|
+
id: String(row.id),
|
|
4346
|
+
idempotencyKey: String(row.idempotencyKey),
|
|
4347
|
+
documentId: String(row.documentId),
|
|
4348
|
+
documentType: row.documentType,
|
|
4349
|
+
operation: row.operation,
|
|
4350
|
+
scope: cloneScope(row.scope),
|
|
4351
|
+
status: row.status,
|
|
4352
|
+
attempts: Number(row.attempts),
|
|
4353
|
+
availableAt: new Date(row.availableAt),
|
|
4354
|
+
claimedAt: row.claimedAt ? new Date(row.claimedAt) : void 0,
|
|
4355
|
+
claimedBy: row.claimedBy ?? void 0,
|
|
4356
|
+
createdAt: new Date(row.createdAt),
|
|
4357
|
+
completedAt: row.completedAt ? new Date(row.completedAt) : void 0
|
|
4358
|
+
};
|
|
4359
|
+
}
|
|
4360
|
+
var KnowledgeMongoDB = class KnowledgeMongoDB extends KnowledgeStorage {
|
|
4361
|
+
static MANAGED_COLLECTIONS = [
|
|
4362
|
+
TABLE_KNOWLEDGE_NODES,
|
|
4363
|
+
TABLE_KNOWLEDGE_RECORDS,
|
|
4364
|
+
TABLE_KNOWLEDGE_MENTIONS,
|
|
4365
|
+
TABLE_KNOWLEDGE_CURSORS,
|
|
4366
|
+
TABLE_KNOWLEDGE_ACTIVITY,
|
|
4367
|
+
TABLE_KNOWLEDGE_SEMANTIC_OUTBOX
|
|
4368
|
+
];
|
|
4369
|
+
#connector;
|
|
4370
|
+
constructor(config) {
|
|
4371
|
+
super();
|
|
4372
|
+
this.#connector = resolveMongoDBConfig(config);
|
|
4373
|
+
}
|
|
4374
|
+
async init() {
|
|
4375
|
+
const nodes = await this.#collection(TABLE_KNOWLEDGE_NODES);
|
|
4376
|
+
const knowledge = await this.#collection(TABLE_KNOWLEDGE_RECORDS);
|
|
4377
|
+
const mentions = await this.#collection(TABLE_KNOWLEDGE_MENTIONS);
|
|
4378
|
+
const cursors = await this.#collection(TABLE_KNOWLEDGE_CURSORS);
|
|
4379
|
+
const activity = await this.#collection(TABLE_KNOWLEDGE_ACTIVITY);
|
|
4380
|
+
const outbox = await this.#collection(TABLE_KNOWLEDGE_SEMANTIC_OUTBOX);
|
|
4381
|
+
await Promise.all([
|
|
4382
|
+
nodes.createIndex({
|
|
4383
|
+
type: 1,
|
|
4384
|
+
scopeKey: 1,
|
|
4385
|
+
canonicalName: 1
|
|
4386
|
+
}, { unique: true }),
|
|
4387
|
+
nodes.createIndex({
|
|
4388
|
+
scopeKey: 1,
|
|
4389
|
+
type: 1
|
|
4390
|
+
}),
|
|
4391
|
+
knowledge.createIndex({
|
|
4392
|
+
node: 1,
|
|
4393
|
+
id: -1
|
|
4394
|
+
}),
|
|
4395
|
+
knowledge.createIndex({
|
|
4396
|
+
sourceThreadId: 1,
|
|
4397
|
+
id: -1
|
|
4398
|
+
}),
|
|
4399
|
+
mentions.createIndex({
|
|
4400
|
+
sourceType: 1,
|
|
4401
|
+
sourceId: 1,
|
|
4402
|
+
recordId: 1
|
|
4403
|
+
}, { unique: true }),
|
|
4404
|
+
mentions.createIndex({
|
|
4405
|
+
recordId: 1,
|
|
4406
|
+
sourceType: 1,
|
|
4407
|
+
sourceId: 1
|
|
4408
|
+
}),
|
|
4409
|
+
cursors.createIndex({
|
|
4410
|
+
sourceThreadId: 1,
|
|
4411
|
+
agent: 1
|
|
4412
|
+
}, { unique: true }),
|
|
4413
|
+
activity.createIndex({ id: -1 }),
|
|
4414
|
+
outbox.createIndex({ idempotencyKey: 1 }, { unique: true }),
|
|
4415
|
+
outbox.createIndex({
|
|
4416
|
+
status: 1,
|
|
4417
|
+
availableAt: 1,
|
|
4418
|
+
createdAt: 1
|
|
4419
|
+
})
|
|
4420
|
+
]);
|
|
4421
|
+
}
|
|
4422
|
+
async dangerouslyClearAll() {
|
|
4423
|
+
await this.#connector.withTransaction(async (session) => {
|
|
4424
|
+
for (const name of KnowledgeMongoDB.MANAGED_COLLECTIONS) await (await this.#collection(name)).deleteMany({}, sessionOptions(session));
|
|
4425
|
+
});
|
|
4426
|
+
}
|
|
4427
|
+
async createNode(input) {
|
|
4428
|
+
const scope = canonicalizeKnowledgeScope(input.scope);
|
|
4429
|
+
return this.#connector.withTransaction(async (session) => {
|
|
4430
|
+
const existing = await this.#getNodeByName(input.name, scope, session);
|
|
4431
|
+
if (existing) {
|
|
4432
|
+
const terminal = await this.#resolveTerminalNode(existing.id, session);
|
|
4433
|
+
if (!isKnowledgeScopeVisible(terminal.scope, scope)) throw new Error(`Merged knowledge node is not visible from scope: ${input.name}`);
|
|
4434
|
+
return terminal;
|
|
4435
|
+
}
|
|
4436
|
+
const now = /* @__PURE__ */ new Date();
|
|
4437
|
+
const node = {
|
|
4438
|
+
id: input.id ?? crypto.randomUUID(),
|
|
4439
|
+
type: "node",
|
|
4440
|
+
name: input.name.trim(),
|
|
4441
|
+
kind: input.kind,
|
|
4442
|
+
content: input.content,
|
|
4443
|
+
scope,
|
|
4444
|
+
version: 1,
|
|
4445
|
+
createdAt: now,
|
|
4446
|
+
updatedAt: now
|
|
4447
|
+
};
|
|
4448
|
+
try {
|
|
4449
|
+
await (await this.#nodes()).insertOne({
|
|
4450
|
+
...node,
|
|
4451
|
+
canonicalName: canonicalName(node.name),
|
|
4452
|
+
scopeKey: knowledgeScopeKey(scope),
|
|
4453
|
+
mergedInto: null
|
|
4454
|
+
}, sessionOptions(session));
|
|
4455
|
+
} catch (error) {
|
|
4456
|
+
if (error.code !== 11e3) throw error;
|
|
4457
|
+
const concurrent = await this.#getNodeByName(input.name, scope, session);
|
|
4458
|
+
if (!concurrent) throw error;
|
|
4459
|
+
return await this.#resolveTerminalNode(concurrent.id, session);
|
|
4460
|
+
}
|
|
4461
|
+
await this.#replaceMentions("node", node.id, node.content ?? "", input.resolutionScope ?? scope, scope, session);
|
|
4462
|
+
await this.#activity("node-created", "node", node.id, scope, void 0, session);
|
|
4463
|
+
await this.#outbox("node", node.id, "upsert", 1, scope, session);
|
|
4464
|
+
return node;
|
|
4465
|
+
});
|
|
4466
|
+
}
|
|
4467
|
+
async getNode(id) {
|
|
4468
|
+
return this.#getNode(id);
|
|
4469
|
+
}
|
|
4470
|
+
async getNodeByName(input) {
|
|
4471
|
+
return this.#getNodeByName(input.name, canonicalizeKnowledgeScope(input.scope));
|
|
4472
|
+
}
|
|
4473
|
+
async resolveNode(input) {
|
|
4474
|
+
return this.#resolveNode(input.name, canonicalizeKnowledgeScope(input.scope));
|
|
4475
|
+
}
|
|
4476
|
+
async listNodes(input) {
|
|
4477
|
+
const filter = {
|
|
4478
|
+
type: "node",
|
|
4479
|
+
mergedInto: null,
|
|
4480
|
+
scopeKey: { $in: visibleScopeKeys(canonicalizeKnowledgeScope(input.scope)) },
|
|
4481
|
+
...input.namePrefix ? { canonicalName: { $regex: `^${this.#escapeRegex(canonicalName(input.namePrefix))}` } } : {},
|
|
4482
|
+
...input.kind ? { kind: input.kind } : {},
|
|
4483
|
+
...input.hasContent === void 0 ? {} : input.hasContent ? { content: {
|
|
4484
|
+
$exists: true,
|
|
4485
|
+
$nin: [null, ""]
|
|
4486
|
+
} } : { $or: [
|
|
4487
|
+
{ content: { $exists: false } },
|
|
4488
|
+
{ content: null },
|
|
4489
|
+
{ content: "" }
|
|
4490
|
+
] },
|
|
4491
|
+
...input.cursor ? recordCursorFilter(input.cursor, {
|
|
4492
|
+
namePrefix: input.namePrefix,
|
|
4493
|
+
kind: input.kind,
|
|
4494
|
+
hasContent: input.hasContent
|
|
4495
|
+
}) : {}
|
|
4496
|
+
};
|
|
4497
|
+
return (await (await this.#nodes()).find(filter).sort({
|
|
4498
|
+
updatedAt: -1,
|
|
4499
|
+
name: 1,
|
|
4500
|
+
id: 1
|
|
4501
|
+
}).limit(input.limit ?? 100).toArray()).map(nodeFromDocument);
|
|
4502
|
+
}
|
|
4503
|
+
async updateNode(input) {
|
|
4504
|
+
return this.#connector.withTransaction(async (session) => {
|
|
4505
|
+
const existing = await this.#getNode(input.id, session);
|
|
4506
|
+
if (!existing) throw new KnowledgeNotFoundError("node", input.id);
|
|
4507
|
+
if (existing.mergedInto) throw new Error(`Cannot update merged knowledge node: ${input.id}`);
|
|
4508
|
+
const scope = input.scope ? canonicalizeKnowledgeScope(input.scope) : existing.scope;
|
|
4509
|
+
const name = input.name?.trim() ?? existing.name;
|
|
4510
|
+
const content = input.content ?? existing.content;
|
|
4511
|
+
const now = /* @__PURE__ */ new Date();
|
|
4512
|
+
const result = await (await this.#nodes()).findOneAndUpdate({
|
|
4513
|
+
id: input.id,
|
|
4514
|
+
type: "node",
|
|
4515
|
+
version: input.version
|
|
4516
|
+
}, {
|
|
4517
|
+
$set: {
|
|
4518
|
+
name,
|
|
4519
|
+
canonicalName: canonicalName(name),
|
|
4520
|
+
kind: input.kind ?? existing.kind,
|
|
4521
|
+
content: content ?? null,
|
|
4522
|
+
scope,
|
|
4523
|
+
scopeKey: knowledgeScopeKey(scope),
|
|
4524
|
+
updatedAt: now
|
|
4525
|
+
},
|
|
4526
|
+
$inc: { version: 1 }
|
|
4527
|
+
}, {
|
|
4528
|
+
...sessionOptions(session),
|
|
4529
|
+
returnDocument: "after"
|
|
4530
|
+
});
|
|
4531
|
+
if (!result) throw new KnowledgeConflictError(input.id);
|
|
4532
|
+
if (input.content !== void 0 || input.name !== void 0 || input.scope !== void 0) await this.#replaceMentions("node", input.id, content ?? "", input.resolutionScope ?? scope, scope, session);
|
|
4533
|
+
if (knowledgeScopeKey(scope) !== knowledgeScopeKey(existing.scope)) {
|
|
4534
|
+
await this.#outbox("node", input.id, "delete", createKnowledgeUlid(), existing.scope, session);
|
|
4535
|
+
const records = await (await this.#knowledge()).find({ node: input.id }, sessionOptions(session)).toArray();
|
|
4536
|
+
for (const record of records) {
|
|
4537
|
+
await this.#outbox("record", record.id, "delete", createKnowledgeUlid(), record.scope, session);
|
|
4538
|
+
if (!record.deletedAt) await this.#outbox("record", record.id, "upsert", createKnowledgeUlid(), record.scope, session);
|
|
4539
|
+
}
|
|
4540
|
+
}
|
|
4541
|
+
await this.#activity("node-updated", "node", input.id, scope, void 0, session);
|
|
4542
|
+
await this.#outbox("node", input.id, "upsert", Number(result.version), scope, session);
|
|
4543
|
+
return nodeFromDocument(result);
|
|
4544
|
+
});
|
|
4545
|
+
}
|
|
4546
|
+
async mergeNodes(input) {
|
|
4547
|
+
if (input.sourceId === input.targetId) throw new Error("Cannot merge a knowledge node into itself");
|
|
4548
|
+
return this.#connector.withTransaction(async (session) => {
|
|
4549
|
+
const source = await this.#getNode(input.sourceId, session);
|
|
4550
|
+
if (!source) throw new KnowledgeNotFoundError("node", input.sourceId);
|
|
4551
|
+
const target = await this.#resolveTerminalNode(input.targetId, session);
|
|
4552
|
+
if (!target) throw new KnowledgeNotFoundError("node", input.targetId);
|
|
4553
|
+
if (target.id === source.id) throw new Error("Cannot create a knowledge merge cycle");
|
|
4554
|
+
if (!isKnowledgeScopeVisible(target.scope, source.scope)) throw new Error("Cannot merge a knowledge node into a target that is narrower than its source scope");
|
|
4555
|
+
const mentions = await this.#mentions();
|
|
4556
|
+
const affected = await mentions.find({ recordId: source.id }, sessionOptions(session)).toArray();
|
|
4557
|
+
const movedFacts = await (await this.#knowledge()).find({ node: source.id }, sessionOptions(session)).toArray();
|
|
4558
|
+
if ((await (await this.#nodes()).updateOne({
|
|
4559
|
+
id: source.id,
|
|
4560
|
+
type: "node",
|
|
4561
|
+
version: input.sourceVersion,
|
|
4562
|
+
mergedInto: null
|
|
4563
|
+
}, {
|
|
4564
|
+
$set: {
|
|
4565
|
+
mergedInto: target.id,
|
|
4566
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
4567
|
+
},
|
|
4568
|
+
$inc: { version: 1 }
|
|
4569
|
+
}, sessionOptions(session))).modifiedCount === 0) throw new KnowledgeConflictError(source.id);
|
|
4570
|
+
await (await this.#knowledge()).updateMany({ node: source.id }, { $set: { node: target.id } }, sessionOptions(session));
|
|
4571
|
+
for (const mention of affected) if (await mentions.findOne({
|
|
4572
|
+
sourceType: mention.sourceType,
|
|
4573
|
+
sourceId: mention.sourceId,
|
|
4574
|
+
recordId: target.id
|
|
4575
|
+
}, sessionOptions(session))) await mentions.deleteOne({ _id: mention._id }, sessionOptions(session));
|
|
4576
|
+
else await mentions.updateOne({ _id: mention._id }, { $set: { recordId: target.id } }, sessionOptions(session));
|
|
4577
|
+
for (const record of movedFacts) if (!record.deletedAt) await this.#outbox("record", record.id, "upsert", createKnowledgeUlid(), record.scope, session);
|
|
4578
|
+
for (const mention of affected) {
|
|
4579
|
+
const scope = mention.sourceType === "record" ? (await (await this.#knowledge()).findOne({ id: mention.sourceId }, sessionOptions(session)))?.scope : (await (await this.#nodes()).findOne({
|
|
4580
|
+
id: mention.sourceId,
|
|
4581
|
+
type: "node"
|
|
4582
|
+
}, sessionOptions(session)))?.scope;
|
|
4583
|
+
if (scope) await this.#outbox(mention.sourceType, mention.sourceId, "upsert", createKnowledgeUlid(), scope, session);
|
|
4584
|
+
}
|
|
4585
|
+
await this.#activity("node-merged", "node", source.id, source.scope, void 0, session);
|
|
4586
|
+
await this.#outbox("node", source.id, "delete", input.sourceVersion + 1, source.scope, session);
|
|
4587
|
+
await this.#outbox("node", target.id, "upsert", createKnowledgeUlid(), target.scope, session);
|
|
4588
|
+
return target;
|
|
4589
|
+
});
|
|
4590
|
+
}
|
|
4591
|
+
async appendKnowledge(input) {
|
|
4592
|
+
const scope = canonicalizeKnowledgeScope(input.scope);
|
|
4593
|
+
const defaultScope = canonicalizeKnowledgeScope(input.defaultScope);
|
|
4594
|
+
assertKnowledgeScopeWithinCeiling(scope, input.maxScope);
|
|
4595
|
+
return this.#connector.withTransaction(async (session) => {
|
|
4596
|
+
const parent = await this.#resolveTerminalNode(nodeReferenceId(input.node), session);
|
|
4597
|
+
if (!parent) throw new KnowledgeNotFoundError("node", nodeReferenceId(input.node));
|
|
4598
|
+
const id = input.id ?? createKnowledgeUlid();
|
|
4599
|
+
const existing = await (await this.#knowledge()).findOne({ id }, sessionOptions(session));
|
|
4600
|
+
if (existing) return recordFromDocument(existing);
|
|
4601
|
+
const record = {
|
|
4602
|
+
id,
|
|
4603
|
+
node: parent.id,
|
|
4604
|
+
text: input.text,
|
|
4605
|
+
scope,
|
|
4606
|
+
sourceThreadId: input.sourceThreadId,
|
|
4607
|
+
capturedAt: /* @__PURE__ */ new Date(),
|
|
4608
|
+
when: input.when,
|
|
4609
|
+
maxScope: input.maxScope,
|
|
4610
|
+
metadata: input.metadata
|
|
4611
|
+
};
|
|
4612
|
+
await (await this.#knowledge()).insertOne({
|
|
4613
|
+
...record,
|
|
4614
|
+
scopeKey: knowledgeScopeKey(scope),
|
|
4615
|
+
when: record.when ?? null,
|
|
4616
|
+
maxScope: record.maxScope ?? null,
|
|
4617
|
+
deletedAt: null,
|
|
4618
|
+
deletedBy: null
|
|
4619
|
+
}, sessionOptions(session));
|
|
4620
|
+
await this.#replaceMentions("record", id, record.text, input.resolutionScope, defaultScope, session);
|
|
4621
|
+
await this.#activity("record-created", "record", id, scope, input.sourceThreadId, session);
|
|
4622
|
+
await this.#outbox("record", id, "upsert", createKnowledgeUlid(), scope, session);
|
|
4623
|
+
return record;
|
|
4624
|
+
});
|
|
4625
|
+
}
|
|
4626
|
+
async getKnowledge(input) {
|
|
4627
|
+
const row = await (await this.#knowledge()).findOne({
|
|
4628
|
+
id: input.id,
|
|
4629
|
+
...input.includeDeleted ? {} : { deletedAt: null }
|
|
4630
|
+
});
|
|
4631
|
+
return row ? recordFromDocument(row) : null;
|
|
4632
|
+
}
|
|
4633
|
+
async listKnowledgeAbout(input) {
|
|
4634
|
+
return this.#queryKnowledge(input, "about");
|
|
4635
|
+
}
|
|
4636
|
+
async listKnowledgeMentioning(input) {
|
|
4637
|
+
return this.#queryKnowledge(input, "mentioning");
|
|
4638
|
+
}
|
|
4639
|
+
async listKnowledgeRelatedTo(input) {
|
|
4640
|
+
return this.#queryKnowledge(input, "related");
|
|
4641
|
+
}
|
|
4642
|
+
async knowledgeBySource(input) {
|
|
4643
|
+
const scope = canonicalizeKnowledgeScope(input.scope);
|
|
4644
|
+
const limit = input.limit ?? 100;
|
|
4645
|
+
const rows = await (await this.#knowledge()).find({
|
|
4646
|
+
sourceThreadId: input.sourceThreadId,
|
|
4647
|
+
scopeKey: { $in: visibleScopeKeys(scope) },
|
|
4648
|
+
...input.includeDeleted ? {} : { deletedAt: null },
|
|
4649
|
+
...input.after ? { id: { $gt: input.after } } : {}
|
|
4650
|
+
}).sort({ id: 1 }).limit(limit + 1).toArray();
|
|
4651
|
+
return {
|
|
4652
|
+
records: rows.slice(0, limit).map(recordFromDocument),
|
|
4653
|
+
nextCursor: rows.length > limit ? rows[limit - 1]?.id : void 0
|
|
4654
|
+
};
|
|
4655
|
+
}
|
|
4656
|
+
async removeKnowledge(input) {
|
|
4657
|
+
return this.#connector.withTransaction(async (session) => {
|
|
4658
|
+
const record = await this.#getKnowledge(input.id, true, session);
|
|
4659
|
+
if (!record) throw new KnowledgeNotFoundError("record", input.id);
|
|
4660
|
+
if (record.deletedAt) return record;
|
|
4661
|
+
const deletedAt = /* @__PURE__ */ new Date();
|
|
4662
|
+
await (await this.#knowledge()).updateOne({
|
|
4663
|
+
id: input.id,
|
|
4664
|
+
deletedAt: null
|
|
4665
|
+
}, { $set: {
|
|
4666
|
+
deletedAt,
|
|
4667
|
+
deletedBy: input.deletedBy
|
|
4668
|
+
} }, sessionOptions(session));
|
|
4669
|
+
await this.#activity("record-deleted", "record", input.id, record.scope, record.sourceThreadId, session);
|
|
4670
|
+
await this.#outbox("record", input.id, "delete", createKnowledgeUlid(), record.scope, session);
|
|
4671
|
+
return {
|
|
4672
|
+
...record,
|
|
4673
|
+
deletedAt,
|
|
4674
|
+
deletedBy: input.deletedBy
|
|
4675
|
+
};
|
|
4676
|
+
});
|
|
4677
|
+
}
|
|
4678
|
+
async restoreKnowledge(input) {
|
|
4679
|
+
return this.#connector.withTransaction(async (session) => {
|
|
4680
|
+
const record = await this.#getKnowledge(input.id, true, session);
|
|
4681
|
+
if (!record) throw new KnowledgeNotFoundError("record", input.id);
|
|
4682
|
+
if (!record.deletedAt) return record;
|
|
4683
|
+
await (await this.#knowledge()).updateOne({ id: input.id }, { $set: {
|
|
4684
|
+
deletedAt: null,
|
|
4685
|
+
deletedBy: null
|
|
4686
|
+
} }, sessionOptions(session));
|
|
4687
|
+
await this.#activity("record-restored", "record", input.id, record.scope, record.sourceThreadId, session);
|
|
4688
|
+
await this.#outbox("record", input.id, "upsert", createKnowledgeUlid(), record.scope, session);
|
|
4689
|
+
return {
|
|
4690
|
+
...record,
|
|
4691
|
+
deletedAt: void 0,
|
|
4692
|
+
deletedBy: void 0
|
|
4693
|
+
};
|
|
4694
|
+
});
|
|
4695
|
+
}
|
|
4696
|
+
async rescopeKnowledge(input) {
|
|
4697
|
+
const scope = canonicalizeKnowledgeScope(input.scope);
|
|
4698
|
+
return this.#connector.withTransaction(async (session) => {
|
|
4699
|
+
const record = await this.#getKnowledge(input.id, true, session);
|
|
4700
|
+
if (!record) throw new KnowledgeNotFoundError("record", input.id);
|
|
4701
|
+
assertKnowledgeScopeWithinCeiling(scope, record.maxScope);
|
|
4702
|
+
await (await this.#knowledge()).updateOne({ id: input.id }, { $set: {
|
|
4703
|
+
scope,
|
|
4704
|
+
scopeKey: knowledgeScopeKey(scope)
|
|
4705
|
+
} }, sessionOptions(session));
|
|
4706
|
+
await this.#activity("record-rescoped", "record", input.id, scope, record.sourceThreadId, session);
|
|
4707
|
+
await this.#outbox("record", input.id, "delete", createKnowledgeUlid(), record.scope, session);
|
|
4708
|
+
if (!record.deletedAt) await this.#outbox("record", input.id, "upsert", createKnowledgeUlid(), scope, session);
|
|
4709
|
+
return {
|
|
4710
|
+
...record,
|
|
4711
|
+
scope
|
|
4712
|
+
};
|
|
4713
|
+
});
|
|
4714
|
+
}
|
|
4715
|
+
async raiseKnowledgeCeiling(input) {
|
|
4716
|
+
const record = await this.#getKnowledge(input.id, true);
|
|
4717
|
+
if (!record) throw new KnowledgeNotFoundError("record", input.id);
|
|
4718
|
+
assertKnowledgeScopeWithinCeiling(record.scope, input.maxScope);
|
|
4719
|
+
assertKnowledgeCeilingRaised(record.maxScope, input.maxScope);
|
|
4720
|
+
await (await this.#knowledge()).updateOne({ id: input.id }, { $set: { maxScope: input.maxScope ?? null } });
|
|
4721
|
+
return {
|
|
4722
|
+
...record,
|
|
4723
|
+
maxScope: input.maxScope
|
|
4724
|
+
};
|
|
4725
|
+
}
|
|
4726
|
+
async search(input) {
|
|
4727
|
+
const scope = canonicalizeKnowledgeScope(input.scope);
|
|
4728
|
+
const query = input.query.trim();
|
|
4729
|
+
if (!query) return [];
|
|
4730
|
+
const regex = new RegExp(this.#escapeRegex(query), "i");
|
|
4731
|
+
const limit = input.limit ?? 20;
|
|
4732
|
+
const results = (await (await this.#nodes()).find({
|
|
4733
|
+
mergedInto: null,
|
|
4734
|
+
scopeKey: { $in: visibleScopeKeys(scope) },
|
|
4735
|
+
$or: [
|
|
4736
|
+
{ name: regex },
|
|
4737
|
+
{ kind: regex },
|
|
4738
|
+
{ content: regex }
|
|
4739
|
+
]
|
|
4740
|
+
}).sort({ updatedAt: -1 }).limit(limit).toArray()).map((row) => ({
|
|
4741
|
+
type: "node",
|
|
4742
|
+
id: row.id,
|
|
4743
|
+
recordId: row.id,
|
|
4744
|
+
name: row.name,
|
|
4745
|
+
text: row.content ? `${row.name}\n${row.content}` : row.name,
|
|
4746
|
+
scope: cloneScope(row.scope)
|
|
4747
|
+
}));
|
|
4748
|
+
if (results.length < limit) {
|
|
4749
|
+
const records = await (await this.#knowledge()).find({
|
|
4750
|
+
deletedAt: null,
|
|
4751
|
+
scopeKey: { $in: visibleScopeKeys(scope) },
|
|
4752
|
+
text: regex
|
|
4753
|
+
}).sort({ id: -1 }).limit(limit - results.length).toArray();
|
|
4754
|
+
for (const record of records) {
|
|
4755
|
+
const parent = await this.#resolveTerminalNode(record.node);
|
|
4756
|
+
const parentVisible = parent && isKnowledgeScopeVisible(parent.scope, scope);
|
|
4757
|
+
results.push({
|
|
4758
|
+
type: "record",
|
|
4759
|
+
id: record.id,
|
|
4760
|
+
recordId: record.node,
|
|
4761
|
+
name: parentVisible ? parent.name : "(private node)",
|
|
4762
|
+
text: record.text,
|
|
4763
|
+
scope: cloneScope(record.scope)
|
|
4764
|
+
});
|
|
4765
|
+
}
|
|
4766
|
+
}
|
|
4767
|
+
return results.slice(0, limit);
|
|
4768
|
+
}
|
|
4769
|
+
async getCurationCursor(input) {
|
|
4770
|
+
const row = await (await this.#cursors()).findOne(input);
|
|
4771
|
+
return row ? {
|
|
4772
|
+
sourceThreadId: row.sourceThreadId,
|
|
4773
|
+
agent: row.agent,
|
|
4774
|
+
lastKnowledgeId: row.lastKnowledgeId,
|
|
4775
|
+
updatedAt: new Date(row.updatedAt)
|
|
4776
|
+
} : null;
|
|
4777
|
+
}
|
|
4778
|
+
async advanceCurationCursor(input) {
|
|
4779
|
+
const row = await (await this.#cursors()).findOneAndUpdate({
|
|
4780
|
+
sourceThreadId: input.sourceThreadId,
|
|
4781
|
+
agent: input.agent
|
|
4782
|
+
}, {
|
|
4783
|
+
$max: { lastKnowledgeId: input.lastKnowledgeId },
|
|
4784
|
+
$set: { updatedAt: /* @__PURE__ */ new Date() },
|
|
4785
|
+
$setOnInsert: {
|
|
4786
|
+
sourceThreadId: input.sourceThreadId,
|
|
4787
|
+
agent: input.agent
|
|
4788
|
+
}
|
|
4789
|
+
}, {
|
|
4790
|
+
upsert: true,
|
|
4791
|
+
returnDocument: "after"
|
|
4792
|
+
});
|
|
4793
|
+
return {
|
|
4794
|
+
sourceThreadId: row.sourceThreadId,
|
|
4795
|
+
agent: row.agent,
|
|
4796
|
+
lastKnowledgeId: row.lastKnowledgeId,
|
|
4797
|
+
updatedAt: new Date(row.updatedAt)
|
|
4798
|
+
};
|
|
4799
|
+
}
|
|
4800
|
+
async listActivity(input) {
|
|
4801
|
+
const scope = canonicalizeKnowledgeScope(input.scope);
|
|
4802
|
+
return (await (await this.#activityCollection()).find({
|
|
4803
|
+
scopeKey: { $in: visibleScopeKeys(scope) },
|
|
4804
|
+
...input.after ? { id: { $lt: input.after } } : {}
|
|
4805
|
+
}).sort({ id: -1 }).limit(input.limit ?? 100).toArray()).map((row) => ({
|
|
4806
|
+
id: row.id,
|
|
4807
|
+
action: row.action,
|
|
4808
|
+
recordType: row.recordType,
|
|
4809
|
+
recordId: row.recordId,
|
|
4810
|
+
scope: cloneScope(row.scope),
|
|
4811
|
+
sourceThreadId: row.sourceThreadId ?? void 0,
|
|
4812
|
+
createdAt: new Date(row.createdAt)
|
|
4813
|
+
}));
|
|
4814
|
+
}
|
|
4815
|
+
async listSemanticOutbox(input = {}) {
|
|
4816
|
+
const filter = {
|
|
4817
|
+
...input.status ? { status: input.status } : {},
|
|
4818
|
+
...input.scope ? { scopeKey: { $in: visibleScopeKeys(input.scope) } } : {}
|
|
4819
|
+
};
|
|
4820
|
+
return (await (await this.#outboxCollection()).find(filter).sort({
|
|
4821
|
+
createdAt: 1,
|
|
4822
|
+
id: 1
|
|
4823
|
+
}).limit(input.limit ?? 100).toArray()).map(outboxFromDocument);
|
|
4824
|
+
}
|
|
4825
|
+
async claimSemanticOutbox(input) {
|
|
4826
|
+
return this.#connector.withTransaction(async (session) => {
|
|
4827
|
+
const collection = await this.#outboxCollection();
|
|
4828
|
+
const now = input.now ?? /* @__PURE__ */ new Date();
|
|
4829
|
+
const staleBefore = new Date(now.getTime() - (input.claimTimeoutMs ?? 6e4));
|
|
4830
|
+
const filter = {
|
|
4831
|
+
$or: [{
|
|
4832
|
+
status: "pending",
|
|
4833
|
+
availableAt: { $lte: now }
|
|
4834
|
+
}, {
|
|
4835
|
+
status: "processing",
|
|
4836
|
+
claimedAt: { $lte: staleBefore }
|
|
4837
|
+
}],
|
|
4838
|
+
...input.scope ? { scopeKey: { $in: visibleScopeKeys(input.scope) } } : {}
|
|
4839
|
+
};
|
|
4840
|
+
const limit = input.limit ?? 100;
|
|
4841
|
+
const candidates = await collection.find(filter, sessionOptions(session)).sort({
|
|
4842
|
+
createdAt: 1,
|
|
4843
|
+
id: 1
|
|
4844
|
+
}).limit(Math.max(limit * 10, 100)).toArray();
|
|
4845
|
+
const claimed = [];
|
|
4846
|
+
for (const candidate of candidates) {
|
|
4847
|
+
if (claimed.length >= limit) break;
|
|
4848
|
+
if (await collection.findOne({
|
|
4849
|
+
documentId: candidate.documentId,
|
|
4850
|
+
status: { $ne: "completed" },
|
|
4851
|
+
$or: [{ createdAt: { $lt: candidate.createdAt } }, {
|
|
4852
|
+
createdAt: candidate.createdAt,
|
|
4853
|
+
id: { $lt: candidate.id }
|
|
4854
|
+
}]
|
|
4855
|
+
}, sessionOptions(session))) continue;
|
|
4856
|
+
const result = await collection.findOneAndUpdate({
|
|
4857
|
+
id: candidate.id,
|
|
4858
|
+
$or: [{
|
|
4859
|
+
status: "pending",
|
|
4860
|
+
availableAt: { $lte: now }
|
|
4861
|
+
}, {
|
|
4862
|
+
status: "processing",
|
|
4863
|
+
claimedAt: { $lte: staleBefore }
|
|
4864
|
+
}]
|
|
4865
|
+
}, {
|
|
4866
|
+
$set: {
|
|
4867
|
+
status: "processing",
|
|
4868
|
+
claimedAt: now,
|
|
4869
|
+
claimedBy: input.workerId
|
|
4870
|
+
},
|
|
4871
|
+
$inc: { attempts: 1 }
|
|
4872
|
+
}, {
|
|
4873
|
+
...sessionOptions(session),
|
|
4874
|
+
returnDocument: "after"
|
|
4875
|
+
});
|
|
4876
|
+
if (result) claimed.push(result);
|
|
4877
|
+
}
|
|
4878
|
+
return claimed.map(outboxFromDocument);
|
|
4879
|
+
});
|
|
4880
|
+
}
|
|
4881
|
+
async completeSemanticOutbox(input) {
|
|
4882
|
+
if (!input.ids.length) return;
|
|
4883
|
+
await (await this.#outboxCollection()).updateMany({
|
|
4884
|
+
id: { $in: input.ids },
|
|
4885
|
+
status: "processing",
|
|
4886
|
+
claimedBy: input.workerId
|
|
4887
|
+
}, { $set: {
|
|
4888
|
+
status: "completed",
|
|
4889
|
+
completedAt: /* @__PURE__ */ new Date(),
|
|
4890
|
+
claimedAt: null,
|
|
4891
|
+
claimedBy: null
|
|
4892
|
+
} });
|
|
4893
|
+
}
|
|
4894
|
+
async releaseSemanticOutbox(input) {
|
|
4895
|
+
if (!input.ids.length) return;
|
|
4896
|
+
await (await this.#outboxCollection()).updateMany({
|
|
4897
|
+
id: { $in: input.ids },
|
|
4898
|
+
status: "processing",
|
|
4899
|
+
claimedBy: input.workerId
|
|
4900
|
+
}, { $set: {
|
|
4901
|
+
status: "pending",
|
|
4902
|
+
availableAt: input.retryAt ?? /* @__PURE__ */ new Date(),
|
|
4903
|
+
claimedAt: null,
|
|
4904
|
+
claimedBy: null
|
|
4905
|
+
} });
|
|
4906
|
+
}
|
|
4907
|
+
async #collection(name) {
|
|
4908
|
+
return this.#connector.getCollection(name);
|
|
4909
|
+
}
|
|
4910
|
+
#nodes() {
|
|
4911
|
+
return this.#collection(TABLE_KNOWLEDGE_NODES);
|
|
4912
|
+
}
|
|
4913
|
+
#knowledge() {
|
|
4914
|
+
return this.#collection(TABLE_KNOWLEDGE_RECORDS);
|
|
4915
|
+
}
|
|
4916
|
+
#mentions() {
|
|
4917
|
+
return this.#collection(TABLE_KNOWLEDGE_MENTIONS);
|
|
4918
|
+
}
|
|
4919
|
+
#cursors() {
|
|
4920
|
+
return this.#collection(TABLE_KNOWLEDGE_CURSORS);
|
|
4921
|
+
}
|
|
4922
|
+
#activityCollection() {
|
|
4923
|
+
return this.#collection(TABLE_KNOWLEDGE_ACTIVITY);
|
|
4924
|
+
}
|
|
4925
|
+
#outboxCollection() {
|
|
4926
|
+
return this.#collection(TABLE_KNOWLEDGE_SEMANTIC_OUTBOX);
|
|
4927
|
+
}
|
|
4928
|
+
async #getNode(id, session) {
|
|
4929
|
+
const row = await (await this.#nodes()).findOne({
|
|
4930
|
+
id,
|
|
4931
|
+
type: "node"
|
|
4932
|
+
}, sessionOptions(session));
|
|
4933
|
+
return row ? nodeFromDocument(row) : null;
|
|
4934
|
+
}
|
|
4935
|
+
async #getNodeByName(name, scope, session) {
|
|
4936
|
+
const row = await (await this.#nodes()).findOne({
|
|
4937
|
+
type: "node",
|
|
4938
|
+
scopeKey: knowledgeScopeKey(scope),
|
|
4939
|
+
canonicalName: canonicalName(name)
|
|
4940
|
+
}, sessionOptions(session));
|
|
4941
|
+
return row ? nodeFromDocument(row) : null;
|
|
4942
|
+
}
|
|
4943
|
+
async #resolveNode(name, scope, session) {
|
|
4944
|
+
for (let length = scope.length; length > 0; length--) {
|
|
4945
|
+
const node = await this.#getNodeByName(name, scope.slice(0, length), session);
|
|
4946
|
+
if (node) {
|
|
4947
|
+
const terminal = await this.#resolveTerminalNode(node.id, session);
|
|
4948
|
+
if (terminal && isKnowledgeScopeVisible(terminal.scope, scope)) return terminal;
|
|
4949
|
+
}
|
|
4950
|
+
}
|
|
4951
|
+
return null;
|
|
4952
|
+
}
|
|
4953
|
+
async #resolveTerminalNode(id, session) {
|
|
4954
|
+
let node = await this.#getNode(id, session);
|
|
4955
|
+
const seen = /* @__PURE__ */ new Set();
|
|
4956
|
+
while (node?.mergedInto) {
|
|
4957
|
+
if (seen.has(node.id)) throw new Error(`Knowledge merge cycle detected at ${node.id}`);
|
|
4958
|
+
seen.add(node.id);
|
|
4959
|
+
node = await this.#getNode(node.mergedInto, session);
|
|
4960
|
+
}
|
|
4961
|
+
return node;
|
|
4962
|
+
}
|
|
4963
|
+
async #getPageByExactName(name, scope, session) {
|
|
4964
|
+
const row = await (await this.#nodes()).findOne({
|
|
4965
|
+
type: "page",
|
|
4966
|
+
scopeKey: knowledgeScopeKey(scope),
|
|
4967
|
+
canonicalName: canonicalName(name)
|
|
4968
|
+
}, sessionOptions(session));
|
|
4969
|
+
return row ? nodeFromDocument(row) : null;
|
|
4970
|
+
}
|
|
4971
|
+
async #getKnowledge(id, includeDeleted, session) {
|
|
4972
|
+
const row = await (await this.#knowledge()).findOne({
|
|
4973
|
+
id,
|
|
4974
|
+
...includeDeleted ? {} : { deletedAt: null }
|
|
4975
|
+
}, sessionOptions(session));
|
|
4976
|
+
return row ? recordFromDocument(row) : null;
|
|
4977
|
+
}
|
|
4978
|
+
async #queryKnowledge(input, relationship) {
|
|
4979
|
+
const scope = canonicalizeKnowledgeScope(input.scope);
|
|
4980
|
+
const node = await this.#resolveTerminalNode(nodeReferenceId(input.node));
|
|
4981
|
+
if (!node) return { records: [] };
|
|
4982
|
+
const nodeIds = [node.id];
|
|
4983
|
+
if (relationship !== "about") {
|
|
4984
|
+
const mentions = await (await this.#mentions()).find({
|
|
4985
|
+
recordId: node.id,
|
|
4986
|
+
sourceType: "record"
|
|
4987
|
+
}).toArray();
|
|
4988
|
+
nodeIds.push(...mentions.map((row) => row.sourceId));
|
|
4989
|
+
}
|
|
4990
|
+
const limit = input.limit ?? 100;
|
|
4991
|
+
const filter = relationship === "about" ? { node: node.id } : relationship === "mentioning" ? { id: { $in: nodeIds.slice(1) } } : { $or: [{ node: node.id }, { id: { $in: nodeIds.slice(1) } }] };
|
|
4992
|
+
Object.assign(filter, {
|
|
4993
|
+
scopeKey: { $in: visibleScopeKeys(scope) },
|
|
4994
|
+
...input.includeDeleted ? {} : { deletedAt: null },
|
|
4995
|
+
...input.after ? { id: { $lt: input.after } } : {}
|
|
4996
|
+
});
|
|
4997
|
+
const rows = await (await this.#knowledge()).find(filter).sort({ id: -1 }).limit(limit + 1).toArray();
|
|
4998
|
+
return {
|
|
4999
|
+
records: rows.slice(0, limit).map(recordFromDocument),
|
|
5000
|
+
nextCursor: rows.length > limit ? rows[limit - 1]?.id : void 0
|
|
5001
|
+
};
|
|
5002
|
+
}
|
|
5003
|
+
async #replaceMentions(sourceType, sourceId, text, resolutionScope, defaultScope, session) {
|
|
5004
|
+
const mentions = await this.#mentions();
|
|
5005
|
+
await mentions.deleteMany({
|
|
5006
|
+
sourceType,
|
|
5007
|
+
sourceId
|
|
5008
|
+
}, sessionOptions(session));
|
|
5009
|
+
for (const name of parseKnowledgeWikilinks(text)) {
|
|
5010
|
+
let node = await this.#resolveNode(name, resolutionScope, session);
|
|
5011
|
+
if (!node) {
|
|
5012
|
+
const existing = await this.#getNodeByName(name, defaultScope, session);
|
|
5013
|
+
node = existing ? await this.#resolveTerminalNode(existing.id, session) : null;
|
|
5014
|
+
}
|
|
5015
|
+
if (!node) {
|
|
5016
|
+
const now = /* @__PURE__ */ new Date();
|
|
5017
|
+
node = {
|
|
5018
|
+
id: crypto.randomUUID(),
|
|
5019
|
+
type: "node",
|
|
5020
|
+
name,
|
|
5021
|
+
kind: "node",
|
|
5022
|
+
scope: defaultScope,
|
|
5023
|
+
version: 1,
|
|
5024
|
+
createdAt: now,
|
|
5025
|
+
updatedAt: now
|
|
5026
|
+
};
|
|
5027
|
+
try {
|
|
5028
|
+
await (await this.#nodes()).insertOne({
|
|
5029
|
+
...node,
|
|
5030
|
+
canonicalName: canonicalName(name),
|
|
5031
|
+
scopeKey: knowledgeScopeKey(defaultScope),
|
|
5032
|
+
mergedInto: null
|
|
5033
|
+
}, sessionOptions(session));
|
|
5034
|
+
await this.#activity("node-created", "node", node.id, defaultScope, void 0, session);
|
|
5035
|
+
await this.#outbox("node", node.id, "upsert", 1, defaultScope, session);
|
|
5036
|
+
} catch (error) {
|
|
5037
|
+
if (error.code !== 11e3) throw error;
|
|
5038
|
+
node = await this.#getNodeByName(name, defaultScope, session);
|
|
5039
|
+
if (!node) throw error;
|
|
5040
|
+
}
|
|
5041
|
+
}
|
|
5042
|
+
await mentions.updateOne({
|
|
5043
|
+
sourceType,
|
|
5044
|
+
sourceId,
|
|
5045
|
+
recordId: node.id
|
|
5046
|
+
}, { $setOnInsert: {
|
|
5047
|
+
sourceType,
|
|
5048
|
+
sourceId,
|
|
5049
|
+
recordId: node.id
|
|
5050
|
+
} }, {
|
|
5051
|
+
...sessionOptions(session),
|
|
5052
|
+
upsert: true
|
|
5053
|
+
});
|
|
5054
|
+
}
|
|
5055
|
+
}
|
|
5056
|
+
async #activity(action, recordType, recordId, scope, sourceThreadId, session) {
|
|
5057
|
+
await (await this.#activityCollection()).insertOne({
|
|
5058
|
+
id: createKnowledgeUlid(),
|
|
5059
|
+
action,
|
|
5060
|
+
recordType,
|
|
5061
|
+
recordId,
|
|
5062
|
+
scope,
|
|
5063
|
+
scopeKey: knowledgeScopeKey(scope),
|
|
5064
|
+
sourceThreadId: sourceThreadId ?? null,
|
|
5065
|
+
createdAt: /* @__PURE__ */ new Date()
|
|
5066
|
+
}, sessionOptions(session));
|
|
5067
|
+
}
|
|
5068
|
+
async #outbox(documentType, id, operation, version, scope, session) {
|
|
5069
|
+
const documentId = knowledgeSemanticDocumentId(documentType, id);
|
|
5070
|
+
const idempotencyKey = knowledgeSemanticIdempotencyKey(documentId, operation, version);
|
|
5071
|
+
const now = /* @__PURE__ */ new Date();
|
|
5072
|
+
try {
|
|
5073
|
+
await (await this.#outboxCollection()).insertOne({
|
|
5074
|
+
id: createKnowledgeUlid(),
|
|
5075
|
+
idempotencyKey,
|
|
5076
|
+
documentId,
|
|
5077
|
+
documentType,
|
|
5078
|
+
operation,
|
|
5079
|
+
scope,
|
|
5080
|
+
scopeKey: knowledgeScopeKey(scope),
|
|
5081
|
+
status: "pending",
|
|
5082
|
+
attempts: 0,
|
|
5083
|
+
availableAt: now,
|
|
5084
|
+
claimedAt: null,
|
|
5085
|
+
claimedBy: null,
|
|
5086
|
+
createdAt: now,
|
|
5087
|
+
completedAt: null
|
|
5088
|
+
}, sessionOptions(session));
|
|
5089
|
+
} catch (error) {
|
|
5090
|
+
if (error.code !== 11e3) throw error;
|
|
5091
|
+
}
|
|
5092
|
+
}
|
|
5093
|
+
#escapeRegex(value) {
|
|
5094
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
5095
|
+
}
|
|
5096
|
+
};
|
|
5097
|
+
//#endregion
|
|
4295
5098
|
//#region src/storage/domains/mcp-clients/index.ts
|
|
4296
5099
|
/**
|
|
4297
5100
|
* Snapshot config fields that live on MCP client version documents.
|
|
@@ -10976,6 +11779,7 @@ var MongoDBStore = class extends MastraCompositeStore {
|
|
|
10976
11779
|
indexes: config.indexes
|
|
10977
11780
|
};
|
|
10978
11781
|
const memory = new MemoryStorageMongoDB(domainConfig);
|
|
11782
|
+
const knowledge = new KnowledgeMongoDB(domainConfig);
|
|
10979
11783
|
const notifications = new NotificationsMongoDB(domainConfig);
|
|
10980
11784
|
const scores = new ScoresStorageMongoDB(domainConfig);
|
|
10981
11785
|
const workflows = new WorkflowsStorageMongoDB(domainConfig);
|
|
@@ -10995,6 +11799,7 @@ var MongoDBStore = class extends MastraCompositeStore {
|
|
|
10995
11799
|
const workflowDefinitions = new MongoDBWorkflowDefinitionsStore(domainConfig);
|
|
10996
11800
|
this.stores = {
|
|
10997
11801
|
memory,
|
|
11802
|
+
knowledge,
|
|
10998
11803
|
notifications,
|
|
10999
11804
|
scores,
|
|
11000
11805
|
workflows,
|
|
@@ -11131,6 +11936,6 @@ Example Complex Query:
|
|
|
11131
11936
|
]
|
|
11132
11937
|
}`;
|
|
11133
11938
|
//#endregion
|
|
11134
|
-
export { BackgroundTasksStorageMongoDB, MONGODB_PROMPT, MemoryStorageMongoDB, MongoDBAgentsStorage, MongoDBBlobStore, MongoDBDatasetsStorage, MongoDBExperimentsStorage, MongoDBMCPClientsStorage, MongoDBMCPServersStorage, MongoDBPromptBlocksStorage, MongoDBScorerDefinitionsStorage, MongoDBSkillsStorage, MongoDBStore, MongoDBVector, MongoDBWorkflowDefinitionsStore, MongoDBWorkspacesStorage, NotificationsMongoDB, ObservabilityMongoDB, SchedulesMongoDB, ScoresStorageMongoDB, WorkflowsStorageMongoDB };
|
|
11939
|
+
export { BackgroundTasksStorageMongoDB, KnowledgeMongoDB, MONGODB_PROMPT, MemoryStorageMongoDB, MongoDBAgentsStorage, MongoDBBlobStore, MongoDBDatasetsStorage, MongoDBExperimentsStorage, MongoDBMCPClientsStorage, MongoDBMCPServersStorage, MongoDBPromptBlocksStorage, MongoDBScorerDefinitionsStorage, MongoDBSkillsStorage, MongoDBStore, MongoDBVector, MongoDBWorkflowDefinitionsStore, MongoDBWorkspacesStorage, NotificationsMongoDB, ObservabilityMongoDB, SchedulesMongoDB, ScoresStorageMongoDB, WorkflowsStorageMongoDB };
|
|
11135
11940
|
|
|
11136
11941
|
//# sourceMappingURL=index.js.map
|