@rubytech/create-maxy 1.0.693 → 1.0.694

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.
Files changed (59) hide show
  1. package/package.json +1 -1
  2. package/payload/platform/lib/graph-search/dist/index.d.ts +127 -0
  3. package/payload/platform/lib/graph-search/dist/index.d.ts.map +1 -0
  4. package/payload/platform/lib/graph-search/dist/index.js +393 -0
  5. package/payload/platform/lib/graph-search/dist/index.js.map +1 -0
  6. package/payload/platform/lib/graph-search/src/__tests__/bm25-only.test.ts +129 -0
  7. package/payload/platform/lib/graph-search/src/__tests__/escape-and-normalise.test.ts +53 -0
  8. package/payload/platform/lib/graph-search/src/__tests__/hybrid.test.ts +190 -0
  9. package/payload/platform/lib/graph-search/src/index.ts +498 -0
  10. package/payload/platform/lib/graph-search/tsconfig.json +9 -0
  11. package/payload/platform/lib/graph-search/vitest.config.ts +9 -0
  12. package/payload/platform/lib/graph-write/dist/index.d.ts +61 -0
  13. package/payload/platform/lib/graph-write/dist/index.d.ts.map +1 -0
  14. package/payload/platform/lib/graph-write/dist/index.js +97 -0
  15. package/payload/platform/lib/graph-write/dist/index.js.map +1 -0
  16. package/payload/platform/lib/graph-write/src/index.ts +167 -0
  17. package/payload/platform/lib/graph-write/tsconfig.json +8 -0
  18. package/payload/platform/package.json +2 -2
  19. package/payload/platform/plugins/admin/mcp/dist/index.js +19 -8
  20. package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
  21. package/payload/platform/plugins/contacts/mcp/dist/index.js +27 -3
  22. package/payload/platform/plugins/contacts/mcp/dist/index.js.map +1 -1
  23. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-create.d.ts +4 -0
  24. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-create.d.ts.map +1 -1
  25. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-create.js +10 -6
  26. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-create.js.map +1 -1
  27. package/payload/platform/plugins/contacts/mcp/dist/tools/group-create.d.ts +2 -0
  28. package/payload/platform/plugins/contacts/mcp/dist/tools/group-create.d.ts.map +1 -1
  29. package/payload/platform/plugins/contacts/mcp/dist/tools/group-create.js +43 -36
  30. package/payload/platform/plugins/contacts/mcp/dist/tools/group-create.js.map +1 -1
  31. package/payload/platform/plugins/docs/references/memory-guide.md +6 -0
  32. package/payload/platform/plugins/memory/mcp/dist/index.js +44 -3
  33. package/payload/platform/plugins/memory/mcp/dist/index.js.map +1 -1
  34. package/payload/platform/plugins/memory/mcp/dist/tools/memory-search.d.ts +3 -32
  35. package/payload/platform/plugins/memory/mcp/dist/tools/memory-search.d.ts.map +1 -1
  36. package/payload/platform/plugins/memory/mcp/dist/tools/memory-search.js +18 -381
  37. package/payload/platform/plugins/memory/mcp/dist/tools/memory-search.js.map +1 -1
  38. package/payload/platform/plugins/memory/mcp/dist/tools/memory-write.d.ts +9 -5
  39. package/payload/platform/plugins/memory/mcp/dist/tools/memory-write.d.ts.map +1 -1
  40. package/payload/platform/plugins/memory/mcp/dist/tools/memory-write.js +10 -23
  41. package/payload/platform/plugins/memory/mcp/dist/tools/memory-write.js.map +1 -1
  42. package/payload/platform/plugins/memory/references/graph-primitives.md +1 -1
  43. package/payload/platform/plugins/scheduling/mcp/dist/index.js +8 -1
  44. package/payload/platform/plugins/scheduling/mcp/dist/index.js.map +1 -1
  45. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-event.d.ts +2 -0
  46. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-event.d.ts.map +1 -1
  47. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-event.js +24 -10
  48. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-event.js.map +1 -1
  49. package/payload/platform/plugins/tasks/mcp/dist/index.js +8 -2
  50. package/payload/platform/plugins/tasks/mcp/dist/index.js.map +1 -1
  51. package/payload/platform/plugins/tasks/mcp/dist/tools/task-create.d.ts +2 -0
  52. package/payload/platform/plugins/tasks/mcp/dist/tools/task-create.d.ts.map +1 -1
  53. package/payload/platform/plugins/tasks/mcp/dist/tools/task-create.js +45 -18
  54. package/payload/platform/plugins/tasks/mcp/dist/tools/task-create.js.map +1 -1
  55. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-execute.js +12 -2
  56. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-execute.js.map +1 -1
  57. package/payload/server/chunk-IAIGB5WN.js +11406 -0
  58. package/payload/server/maxy-edge.js +1 -1
  59. package/payload/server/server.js +656 -21
@@ -1,405 +1,42 @@
1
- import { int } from "neo4j-driver";
2
1
  import { getSession } from "../lib/neo4j.js";
3
2
  import { embed } from "../lib/embeddings.js";
4
- import { notTrashed } from "../../../../../lib/graph-trash/dist/index.js";
3
+ import { hybrid } from "../../../../../lib/graph-search/dist/index.js";
5
4
  // ---------------------------------------------------------------------------
6
- // Hybrid search pipeline:
5
+ // Memory search — thin adapter over the shared `graph-search` lib (Task 675).
6
+ // The hybrid pipeline, Lucene escape, BM25 normalisation, and graph expand
7
+ // all live in platform/lib/graph-search; this file threads the MCP tool
8
+ // parameters through and applies the trash-census observability log.
7
9
  //
8
- // QUERY --> EMBED --> VECTOR SEARCH (per index) -->
9
- // │ ├--> MERGE --> EXPAND --> RESULTS
10
- // └────────--> BM25 FULL-TEXT SEARCH ────────-->
11
- //
12
- // Merge: normalise BM25 scores to [0,1] via min-max, then combine:
13
- // combined = 0.7 * vector_score + 0.3 * normalised_bm25_score
14
- // Deduplicate by nodeId, taking the higher combined score.
15
- // Fall back to vector-only if the full-text index doesn't exist.
16
- //
17
- // Trashed nodes (Task 576 :Trashed label) and legacy soft-deleted nodes
18
- // (pre-Task-576 deletedAt property) are excluded from ALL query paths via
19
- // the shared notTrashed() helper: vector search, BM25, property keyword
20
- // search, and graph expand. The filter is unconditional — no parameter
21
- // controls it. When the filter drops results, [trash:read-filter-skipped]
22
- // is emitted so silent over-filtering is observable.
10
+ // Trash filter visibility: when the account holds `:Trashed` nodes we emit
11
+ // `[trash:read-filter-skipped]` so silent over-filtering stays observable.
12
+ // The census lives here (not in the shared lib) because it is MCP-tool-
13
+ // specific context the admin route doesn't share.
23
14
  // ---------------------------------------------------------------------------
24
- const VECTOR_WEIGHT = 0.7;
25
- const BM25_WEIGHT = 0.3;
26
- const FULLTEXT_INDEX_NAME = "knowledge_fulltext";
27
- // Cached vector index map — discovered from Neo4j at first query.
28
- let indexCache = null;
29
- /**
30
- * Discover all vector indexes from Neo4j.
31
- * Returns a map of label → index name.
32
- */
33
- async function discoverIndexes() {
34
- if (indexCache)
35
- return indexCache;
36
- const session = getSession();
37
- try {
38
- const result = await session.run(`SHOW INDEXES YIELD name, labelsOrTypes, type WHERE type = 'VECTOR' RETURN name, labelsOrTypes`);
39
- indexCache = new Map();
40
- for (const record of result.records) {
41
- const name = record.get("name");
42
- const labels = record.get("labelsOrTypes");
43
- for (const label of labels) {
44
- indexCache.set(label, name);
45
- }
46
- }
47
- return indexCache;
48
- }
49
- finally {
50
- await session.close();
51
- }
52
- }
53
- /** Clear the index cache — call after schema changes. */
54
- export function clearIndexCache() {
55
- indexCache = null;
56
- }
57
- /**
58
- * Run BM25 full-text search against the knowledge_fulltext index.
59
- * Returns empty array if the index doesn't exist (graceful fallback).
60
- */
61
- async function bm25Search(queryText, accountId, limit, allowedScopes, keywordFilter, agentSlug) {
62
- const session = getSession();
63
- try {
64
- const scopeClause = allowedScopes
65
- ? "AND (node.scope IS NULL OR node.scope IN $allowedScopes)"
66
- : "";
67
- const agentClause = agentSlug
68
- ? "AND node.agents IS NOT NULL AND $agentSlug IN node.agents"
69
- : "";
70
- const kwClause = keywordFilter?.clause ?? "";
71
- // Escape Lucene special characters in the query
72
- const escaped = queryText.replace(/[+\-&|!(){}[\]^"~*?:\\/]/g, "\\$&");
73
- const result = await session.run(`CALL db.index.fulltext.queryNodes($indexName, $query)
74
- YIELD node, score
75
- WHERE node.accountId = $accountId
76
- ${scopeClause}
77
- ${agentClause}
78
- AND ${notTrashed("node")}
79
- ${kwClause}
80
- RETURN node, score, labels(node) AS nodeLabels, elementId(node) AS nodeId
81
- ORDER BY score DESC
82
- LIMIT $limit`, {
83
- indexName: FULLTEXT_INDEX_NAME,
84
- query: escaped,
85
- accountId,
86
- limit: int(limit),
87
- ...(allowedScopes ? { allowedScopes } : {}),
88
- ...(agentSlug ? { agentSlug } : {}),
89
- ...(keywordFilter?.params ?? {}),
90
- });
91
- return result.records.map((r) => ({
92
- nodeId: r.get("nodeId"),
93
- labels: r.get("nodeLabels"),
94
- properties: nodeToPlain(r.get("node").properties),
95
- score: typeof r.get("score") === "number" ? r.get("score") : Number(r.get("score")),
96
- }));
97
- }
98
- catch (err) {
99
- // Full-text index may not exist yet — fall back to vector-only
100
- const msg = err instanceof Error ? err.message : String(err);
101
- if (msg.includes("index") || msg.includes("fulltext") || msg.includes("not found")) {
102
- return [];
103
- }
104
- throw err;
105
- }
106
- finally {
107
- await session.close();
108
- }
109
- }
110
- /**
111
- * Normalise BM25 scores to [0, 1] using min-max within the result set.
112
- * If all scores are equal (or single result), returns 1.0 for all.
113
- */
114
- function normaliseBm25Scores(scores) {
115
- if (scores.length === 0)
116
- return [];
117
- const min = Math.min(...scores);
118
- const max = Math.max(...scores);
119
- const range = max - min;
120
- if (range === 0)
121
- return scores.map(() => 1.0);
122
- return scores.map((s) => (s - min) / range);
123
- }
124
15
  export async function memorySearch(params) {
125
- const { query: queryText, labels, accountId, limit = 10, expandHops = 1, allowedScopes, keywords, keywordMatch = "any", agentSlug, keywordSubscriptions, } = params;
126
- const queryEmbedding = await embed(queryText);
127
- const labelToIndex = await discoverIndexes();
128
16
  const session = getSession();
129
- // Build the keyword filter clause (applied inside vector + BM25 queries).
130
- // When keywords are provided, nodes WITH a `keywords` property must match;
131
- // nodes WITHOUT the property (e.g. Email) pass through unfiltered.
132
- const keywordFn = keywordMatch === "all" ? "ALL" : "ANY";
133
- const keywordClause = keywords && keywords.length > 0
134
- ? `AND (node.keywords IS NULL OR ${keywordFn}(kw IN $keywords WHERE kw IN node.keywords))`
135
- : "";
136
- const keywordParams = keywords && keywords.length > 0
137
- ? { keywords: keywords.map((k) => k.toLowerCase().trim()) }
138
- : {};
17
+ const limit = params.limit ?? 10;
139
18
  try {
140
- // --- Vector search ---
141
- let indexesToQuery;
142
- if (labels && labels.length > 0) {
143
- indexesToQuery = labels
144
- .map((l) => labelToIndex.get(l))
145
- .filter((idx) => idx !== undefined);
146
- if (indexesToQuery.length === 0) {
147
- return [];
148
- }
149
- }
150
- else {
151
- indexesToQuery = [...new Set(labelToIndex.values())];
152
- }
153
- const scoredMap = new Map();
154
- // Build scope clause — omit for admin (unrestricted), filter for scoped agents.
155
- // IS NULL handles legacy nodes that predate the scope migration.
156
- const scopeClause = allowedScopes
157
- ? "AND (node.scope IS NULL OR node.scope IN $allowedScopes)"
158
- : "";
159
- const scopeParams = allowedScopes ? { allowedScopes } : {};
160
- // Build per-agent tag clause — when set, only nodes explicitly tagged for this agent.
161
- // Both agentSlug AND allowedScopes must pass (defense in depth).
162
- const agentClause = agentSlug
163
- ? "AND node.agents IS NOT NULL AND $agentSlug IN node.agents"
164
- : "";
165
- const agentParams = agentSlug ? { agentSlug } : {};
166
- // Unconditional soft-delete filter — :Trashed nodes (Task 576) and legacy
167
- // deletedAt-marked nodes are never returned. notTrashed() centralises the
168
- // predicate so a future migration drops the legacy arm in one place.
169
- for (const indexName of indexesToQuery) {
170
- const vectorQuery = `
171
- CALL db.index.vector.queryNodes($indexName, $limit, $embedding)
172
- YIELD node, score
173
- WHERE node.accountId = $accountId
174
- ${scopeClause}
175
- ${agentClause}
176
- AND ${notTrashed("node")}
177
- ${keywordClause}
178
- RETURN node, score, labels(node) AS nodeLabels, elementId(node) AS nodeId
179
- ORDER BY score DESC
180
- LIMIT $limit
181
- `;
182
- const vectorResult = await session.run(vectorQuery, {
183
- indexName,
184
- embedding: queryEmbedding,
185
- limit: int(limit),
186
- accountId,
187
- ...scopeParams,
188
- ...agentParams,
189
- ...keywordParams,
190
- });
191
- for (const record of vectorResult.records) {
192
- const nodeId = record.get("nodeId");
193
- const score = typeof record.get("score") === "number"
194
- ? record.get("score")
195
- : Number(record.get("score"));
196
- const existing = scoredMap.get(nodeId);
197
- if (existing) {
198
- existing.vectorScore = Math.max(existing.vectorScore, score);
199
- }
200
- else {
201
- scoredMap.set(nodeId, {
202
- nodeId,
203
- labels: record.get("nodeLabels"),
204
- properties: nodeToPlain(record.get("node").properties),
205
- vectorScore: score,
206
- bm25Score: 0,
207
- });
208
- }
209
- }
210
- }
211
- // --- BM25 search (knowledge documents only, graceful fallback) ---
212
- const bm25KeywordFilter = keywordClause
213
- ? { clause: keywordClause, params: keywordParams }
214
- : undefined;
215
- const bm25Results = await bm25Search(queryText, accountId, limit, allowedScopes, bm25KeywordFilter, agentSlug);
216
- if (bm25Results.length > 0) {
217
- const rawScores = bm25Results.map((r) => r.score);
218
- const normalised = normaliseBm25Scores(rawScores);
219
- for (let i = 0; i < bm25Results.length; i++) {
220
- const r = bm25Results[i];
221
- const existing = scoredMap.get(r.nodeId);
222
- if (existing) {
223
- existing.bm25Score = Math.max(existing.bm25Score, normalised[i]);
224
- }
225
- else {
226
- scoredMap.set(r.nodeId, {
227
- nodeId: r.nodeId,
228
- labels: r.labels,
229
- properties: r.properties,
230
- vectorScore: 0,
231
- bm25Score: normalised[i],
232
- });
233
- }
234
- }
235
- }
236
- // --- Keyword subscription queries (per-agent reactive knowledge) ---
237
- // When keywordSubscriptions are configured, two complementary searches run:
238
- // 1. BM25 full-text search per keyword (catches content matches)
239
- // 2. Property-based search on the node `keywords` array (catches tagged nodes)
240
- // Both run WITHOUT the agentSlug clause — keyword matches are scope-inclusive
241
- // by design. ALLOWED_SCOPES still applies (defense in depth).
242
- //
243
- // QUERY --> BM25 per keyword ────────────────--> ┐
244
- // └--> Property match (node.keywords) ──--> ├--> scoredMap (union)
245
- // ┘
246
- if (keywordSubscriptions && keywordSubscriptions.length > 0) {
247
- // 1. BM25 full-text search per keyword (case-insensitive via analyzer)
248
- for (const kw of keywordSubscriptions) {
249
- const kwResults = await bm25Search(kw, accountId, limit, allowedScopes);
250
- if (kwResults.length > 0) {
251
- const rawScores = kwResults.map((r) => r.score);
252
- const normalised = normaliseBm25Scores(rawScores);
253
- for (let i = 0; i < kwResults.length; i++) {
254
- const r = kwResults[i];
255
- const existing = scoredMap.get(r.nodeId);
256
- if (existing) {
257
- existing.bm25Score = Math.max(existing.bm25Score, normalised[i]);
258
- }
259
- else {
260
- scoredMap.set(r.nodeId, {
261
- nodeId: r.nodeId,
262
- labels: r.labels,
263
- properties: r.properties,
264
- vectorScore: 0,
265
- bm25Score: normalised[i],
266
- });
267
- }
268
- }
269
- }
270
- }
271
- // 2. Property-based search: find nodes whose `keywords` array contains
272
- // any of the subscription keywords. Runs against ALL node labels (not
273
- // just KnowledgeDocument) since knowledge may be stored as DefinedTerm,
274
- // Question, Service, etc. Uses toLower() on both sides as a transitional
275
- // measure for existing mixed-case data.
276
- const propScopeClause = allowedScopes
277
- ? "AND (node.scope IS NULL OR node.scope IN $allowedScopes)"
278
- : "";
279
- const propResult = await session.run(`MATCH (node)
280
- WHERE node.accountId = $accountId
281
- AND ${notTrashed("node")}
282
- AND node.keywords IS NOT NULL
283
- AND ANY(kw IN $kwSubs WHERE ANY(nk IN node.keywords WHERE toLower(nk) = kw))
284
- ${propScopeClause}
285
- RETURN node, labels(node) AS nodeLabels, elementId(node) AS nodeId
286
- LIMIT $limit`, {
287
- accountId,
288
- kwSubs: keywordSubscriptions,
289
- limit: int(limit),
290
- ...(allowedScopes ? { allowedScopes } : {}),
291
- });
292
- for (const record of propResult.records) {
293
- const nodeId = record.get("nodeId");
294
- const existing = scoredMap.get(nodeId);
295
- if (existing) {
296
- // Property match is exact — boost bm25Score to maximum
297
- existing.bm25Score = Math.max(existing.bm25Score, 1.0);
298
- }
299
- else {
300
- scoredMap.set(nodeId, {
301
- nodeId,
302
- labels: record.get("nodeLabels"),
303
- properties: nodeToPlain(record.get("node").properties),
304
- vectorScore: 0,
305
- bm25Score: 1.0,
306
- });
307
- }
308
- }
309
- }
310
- // --- Merge: combine vector + BM25 scores ---
311
- const merged = [...scoredMap.values()].map((node) => ({
312
- ...node,
313
- combinedScore: VECTOR_WEIGHT * node.vectorScore + BM25_WEIGHT * node.bm25Score,
314
- }));
315
- merged.sort((a, b) => b.combinedScore - a.combinedScore);
316
- const topResults = merged.slice(0, limit);
317
- // --- Graph expand ---
318
- const allResults = [];
319
- for (const node of topResults) {
320
- const result = {
321
- nodeId: node.nodeId,
322
- labels: node.labels,
323
- properties: node.properties,
324
- score: node.combinedScore,
325
- related: [],
326
- };
327
- if (expandHops > 0) {
328
- const expandScopeClause = allowedScopes
329
- ? "AND (related.scope IS NULL OR related.scope IN $allowedScopes)"
330
- : "";
331
- // Per-agent expand filter: related nodes must be untagged or tagged for this agent.
332
- // Prevents cross-agent content leakage via graph traversal.
333
- const expandAgentClause = agentSlug
334
- ? "AND (related.agents IS NULL OR $agentSlug IN related.agents)"
335
- : "";
336
- const expandQuery = `
337
- MATCH (n)-[r]-(related)
338
- WHERE elementId(n) = $nodeId
339
- AND ${notTrashed("related")}
340
- ${expandScopeClause}
341
- ${expandAgentClause}
342
- RETURN type(r) AS relType,
343
- CASE WHEN startNode(r) = n THEN 'outgoing' ELSE 'incoming' END AS direction,
344
- labels(related) AS relatedLabels,
345
- related
346
- LIMIT 20
347
- `;
348
- const expandResult = await session.run(expandQuery, {
349
- nodeId: node.nodeId,
350
- ...scopeParams,
351
- ...agentParams,
352
- });
353
- for (const relRecord of expandResult.records) {
354
- result.related.push({
355
- relationship: relRecord.get("relType"),
356
- direction: relRecord.get("direction"),
357
- labels: relRecord.get("relatedLabels"),
358
- properties: nodeToPlain(relRecord.get("related").properties),
359
- });
360
- }
361
- }
362
- allResults.push(result);
363
- }
364
- // Trash filter visibility: emit when the account holds any :Trashed nodes,
365
- // so silent over-filtering is observable. Cheap single-row aggregate;
366
- // accountId-as-unique-key labels (LocalBusiness/OnboardingState) have
367
- // their accountId nulled and are missed here — acceptable, those labels
368
- // are 1-per-account and rare in trash.
19
+ const res = await hybrid(session, embed, { ...params, limit });
369
20
  try {
370
- const trashCensus = await session.run(`MATCH (n:Trashed) WHERE n.accountId = $accountId RETURN count(n) AS c`, { accountId });
21
+ const trashCensus = await session.run(`MATCH (n:Trashed) WHERE n.accountId = $accountId RETURN count(n) AS c`, { accountId: params.accountId });
371
22
  const skipped = trashCensus.records[0]?.get("c");
372
23
  const skippedCount = typeof skipped === "number"
373
24
  ? skipped
374
25
  : skipped?.toNumber?.() ?? 0;
375
26
  if (skippedCount > 0) {
376
- const fingerprint = (labels && labels.length > 0)
377
- ? `labels=${labels.join(",")}`
378
- : `query=${queryText.slice(0, 40).replace(/\s+/g, " ")}`;
379
- process.stderr.write(`[trash:read-filter-skipped] accountId=${accountId} ${fingerprint} skippedCount=${skippedCount}\n`);
27
+ const fingerprint = (params.labels && params.labels.length > 0)
28
+ ? `labels=${params.labels.join(",")}`
29
+ : `query=${params.query.slice(0, 40).replace(/\s+/g, " ")}`;
30
+ process.stderr.write(`[trash:read-filter-skipped] accountId=${params.accountId} ${fingerprint} skippedCount=${skippedCount}\n`);
380
31
  }
381
32
  }
382
33
  catch {
383
- // Census is observability-only never break a search on its failure.
34
+ // observability-only; never break a search on census failure.
384
35
  }
385
- return allResults;
36
+ return res.results;
386
37
  }
387
38
  finally {
388
39
  await session.close();
389
40
  }
390
41
  }
391
- function nodeToPlain(properties) {
392
- const plain = {};
393
- for (const [key, value] of Object.entries(properties)) {
394
- if (key === "embedding")
395
- continue;
396
- if (value && typeof value === "object" && "toNumber" in value) {
397
- plain[key] = value.toNumber();
398
- }
399
- else {
400
- plain[key] = value;
401
- }
402
- }
403
- return plain;
404
- }
405
42
  //# sourceMappingURL=memory-search.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"memory-search.js","sourceRoot":"","sources":["../../src/tools/memory-search.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"memory-search.js","sourceRoot":"","sources":["../../src/tools/memory-search.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAC7C,OAAO,EAAE,MAAM,EAAwC,MAAM,+CAA+C,CAAC;AAE7G,8EAA8E;AAC9E,8EAA8E;AAC9E,2EAA2E;AAC3E,wEAAwE;AACxE,qEAAqE;AACrE,EAAE;AACF,2EAA2E;AAC3E,2EAA2E;AAC3E,wEAAwE;AACxE,kDAAkD;AAClD,8EAA8E;AAE9E,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,MAAwD;IAExD,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;IAC7B,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC;IACjC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE,GAAG,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;QAE/D,IAAI,CAAC;YACH,MAAM,WAAW,GAAG,MAAM,OAAO,CAAC,GAAG,CACnC,uEAAuE,EACvE,EAAE,SAAS,EAAE,MAAM,CAAC,SAAS,EAAE,CAChC,CAAC;YACF,MAAM,OAAO,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,CAGlC,CAAC;YACd,MAAM,YAAY,GAAG,OAAO,OAAO,KAAK,QAAQ;gBAC9C,CAAC,CAAC,OAAO;gBACT,CAAC,CAAC,OAAO,EAAE,QAAQ,EAAE,EAAE,IAAI,CAAC,CAAC;YAC/B,IAAI,YAAY,GAAG,CAAC,EAAE,CAAC;gBACrB,MAAM,WAAW,GAAG,CAAC,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;oBAC7D,CAAC,CAAC,UAAU,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE;oBACrC,CAAC,CAAC,SAAS,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,CAAC;gBAC9D,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,yCAAyC,MAAM,CAAC,SAAS,IAAI,WAAW,iBAAiB,YAAY,IAAI,CAC1G,CAAC;YACJ,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,8DAA8D;QAChE,CAAC;QAED,OAAO,GAAG,CAAC,OAAO,CAAC;IACrB,CAAC;YAAS,CAAC;QACT,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;IACxB,CAAC;AACH,CAAC"}
@@ -1,15 +1,19 @@
1
1
  import type { LoadedSchema } from "../lib/schema-loader.js";
2
+ import { type GraphRelationship, type CreatedBy } from "../../../../../lib/graph-write/dist/index.js";
2
3
  interface WriteParams {
3
4
  labels: string[];
4
5
  properties: Record<string, unknown>;
5
6
  accountId?: string;
6
7
  /** Visibility scope for the node (e.g. "public", "shared", "admin", "user:phone:+44..."). Required — caller must specify. */
7
8
  scope: string;
8
- relationships?: Array<{
9
- type: string;
10
- direction: "outgoing" | "incoming";
11
- targetNodeId: string;
12
- }>;
9
+ /**
10
+ * At least one relationship required — enforced by writeNodeWithEdges.
11
+ * The doctrine: a node without at least one adjacency is noise, not
12
+ * knowledge. See .docs/neo4j.md (Write doctrine).
13
+ */
14
+ relationships: GraphRelationship[];
15
+ /** Provenance stamp — sourced from the MCP server env vars (agent/session). */
16
+ createdBy: CreatedBy;
13
17
  /**
14
18
  * Loaded schema used to validate the write before any Neo4j or embedding
15
19
  * work is done. Required — the caller (index.ts) loads this once at
@@ -1 +1 @@
1
- {"version":3,"file":"memory-write.d.ts","sourceRoot":"","sources":["../../src/tools/memory-write.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAG5D,UAAU,WAAW;IACnB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,6HAA6H;IAC7H,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,CAAC,EAAE,KAAK,CAAC;QACpB,IAAI,EAAE,MAAM,CAAC;QACb,SAAS,EAAE,UAAU,GAAG,UAAU,CAAC;QACnC,YAAY,EAAE,MAAM,CAAC;KACtB,CAAC,CAAC;IACH;;;;OAIG;IACH,MAAM,EAAE,YAAY,CAAC;CACtB;AAED,UAAU,WAAW;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,wBAAsB,WAAW,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC,CAqI3E;AAED,wFAAwF;AACxF,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,MAAM,GACd;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAKhD;AAED,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,MAAM,EAAE,EAChB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAClC,MAAM,CAUR"}
1
+ {"version":3,"file":"memory-write.d.ts","sourceRoot":"","sources":["../../src/tools/memory-write.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAE5D,OAAO,EAEL,KAAK,iBAAiB,EACtB,KAAK,SAAS,EACf,MAAM,8CAA8C,CAAC;AAEtD,UAAU,WAAW;IACnB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,6HAA6H;IAC7H,KAAK,EAAE,MAAM,CAAC;IACd;;;;OAIG;IACH,aAAa,EAAE,iBAAiB,EAAE,CAAC;IACnC,+EAA+E;IAC/E,SAAS,EAAE,SAAS,CAAC;IACrB;;;;OAIG;IACH,MAAM,EAAE,YAAY,CAAC;CACtB;AAED,UAAU,WAAW;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,wBAAsB,WAAW,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC,CAkH3E;AAED,wFAAwF;AACxF,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,MAAM,GACd;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAKhD;AAED,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,MAAM,EAAE,EAChB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAClC,MAAM,CAUR"}
@@ -1,8 +1,9 @@
1
1
  import { getSession } from "../lib/neo4j.js";
2
2
  import { embed } from "../lib/embeddings.js";
3
3
  import { validateWrite } from "../lib/schema-validator.js";
4
+ import { writeNodeWithEdges, } from "../../../../../lib/graph-write/dist/index.js";
4
5
  export async function memoryWrite(params) {
5
- const { labels, properties, accountId, scope, relationships, schema } = params;
6
+ const { labels, properties, accountId, scope, relationships, createdBy, schema } = params;
6
7
  if (!scope) {
7
8
  throw new Error("scope is required — valid values: 'public', 'shared', 'admin', 'user:{identifier}'");
8
9
  }
@@ -20,7 +21,6 @@ export async function memoryWrite(params) {
20
21
  const session = getSession();
21
22
  const labelStr = labels.map((l) => `\`${l}\``).join(":");
22
23
  try {
23
- // Compute embedding from a text representation of the node
24
24
  const textForEmbedding = buildTextRepresentation(labels, properties);
25
25
  const embedding = await embed(textForEmbedding);
26
26
  const nodeProps = {
@@ -33,27 +33,14 @@ export async function memoryWrite(params) {
33
33
  if (!properties.createdOn && !properties.createdAt) {
34
34
  nodeProps.createdAt = new Date().toISOString();
35
35
  }
36
- const createQuery = `
37
- CREATE (n:${labelStr} $props)
38
- RETURN elementId(n) AS nodeId, labels(n) AS nodeLabels
39
- `;
40
- const result = await session.run(createQuery, { props: nodeProps });
41
- const record = result.records[0];
42
- const nodeId = record.get("nodeId");
43
- const nodeLabels = record.get("nodeLabels");
44
- // Create relationships if specified
45
- if (relationships && relationships.length > 0) {
46
- for (const rel of relationships) {
47
- const relQuery = rel.direction === "outgoing"
48
- ? `MATCH (a), (b) WHERE elementId(a) = $fromId AND elementId(b) = $toId CREATE (a)-[:${rel.type}]->(b)`
49
- : `MATCH (a), (b) WHERE elementId(a) = $fromId AND elementId(b) = $toId CREATE (b)-[:${rel.type}]->(a)`;
50
- await session.run(relQuery, {
51
- fromId: nodeId,
52
- toId: rel.targetNodeId,
53
- });
54
- }
55
- }
56
- return { nodeId, labels: nodeLabels, created: true };
36
+ const result = await writeNodeWithEdges({
37
+ session,
38
+ labels,
39
+ props: nodeProps,
40
+ relationships,
41
+ createdBy,
42
+ });
43
+ return { nodeId: result.nodeId, labels: result.labels, created: true };
57
44
  }
58
45
  catch (error) {
59
46
  // Constraint violations include an unusable internal ID (e.g. "Node(219)").
@@ -1 +1 @@
1
- {"version":3,"file":"memory-write.js","sourceRoot":"","sources":["../../src/tools/memory-write.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"memory-write.js","sourceRoot":"","sources":["../../src/tools/memory-write.ts"],"names":[],"mappings":"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"}
@@ -57,7 +57,7 @@ graph as a single action.
57
57
  | User intent | Tool | When to pick this, not the next row |
58
58
  |---|---|---|
59
59
  | "remove admin X", "take away their admin access", "revoke admin" | `mcp__admin__admin-remove` | Device-level admin offboarding — detaches the `(AdminUser)-[:ADMIN_OF]->(LocalBusiness)` edge and updates `platform/config/users.json`. Not for scrubbing personal data — use the GDPR contact-erase tools for that. |
60
- | "delete this specific node", "remove this entry by its id", "get rid of node X", "remove orphans", "prune", "clean up" | `mcp__memory__memory-delete` | Soft-deletes a single node by `elementId` (adds `:Trashed`, preserves relationships, snapshots unique keys, invisible to `memory-search` and any `notTrashed`-filtered read). For KnowledgeDocument, cascades to Sections and Chunks. Enumerate candidates first with a Cypher read, confirm with the user, then delete each by `elementId`. There is no bulk "delete everything without relationships" tool — standalone nodes are legitimate for many labels (OnboardingState, configuration nodes, freshly-discovered Persons before edges land). |
60
+ | "delete this specific node", "remove this entry by its id", "get rid of node X", "remove orphans", "prune", "clean up" | `mcp__memory__memory-delete` | Soft-deletes a single node by `elementId` (adds `:Trashed`, preserves relationships, snapshots unique keys, invisible to `memory-search` and any `notTrashed`-filtered read). For KnowledgeDocument, cascades to Sections and Chunks. Enumerate candidates first with a Cypher read, confirm with the user, then delete each by `elementId`. There is no bulk "delete everything without relationships" tool. Per the Task 673 write doctrine (`.docs/neo4j.md` § Write doctrine), **new** orphans should be impossible every writer now rejects zero-edge calls at the MCP tool-surface. Existing orphans from pre-Task-673 data are legitimate backfill candidates (see Task 677) but are not produced by any live writer; if you see a freshly-created orphan, it is a bug in a writer that bypassed `writeNodeWithEdges`, not expected state. |
61
61
  | "undo that delete", "I deleted X by mistake, bring it back", "restore the contact I just trashed" | `mcp__memory__memory-restore` | Removes `:Trashed`, restores snapshotted unique-key properties. Fails loudly when an active node already holds the unique slot (e.g. a fresh `OnboardingState` was created while the old one was in trash) — the error names the conflicting `elementId` so you can ask the user how to resolve. |
62
62
  | "empty the trash", "purge old soft-deletes", "what's been sitting in trash and ready to clear" | `mcp__memory__memory-empty-trash` | Hard-deletes trashed nodes whose `trashedAt` is older than `graceDays` (default 30); `dryRun=true` lists candidates without mutating. Use `dryRun` first, show the list to the user, then run for real. For KnowledgeDocument candidates, the on-disk attachment directory is removed too. |
63
63
  | "scrub this conversation's memory", "remove this claim the bot picked up", "forget what we said in that thread" | `mcp__memory__conversation-memory-expunge` | Removes deny-listable content from `:Memory` nodes scoped to one conversation. Requires an explicit pattern and conversationId. Not for deleting individual nodes — use `memory-delete`. |
@@ -24,6 +24,8 @@ const accountId = process.env.ACCOUNT_ID;
24
24
  if (!accountId) {
25
25
  throw new Error("ACCOUNT_ID environment variable is required");
26
26
  }
27
+ const sessionId = process.env.SESSION_ID || undefined;
28
+ const agentSlug = process.env.AGENT_SLUG || undefined;
27
29
  // ---------------------------------------------------------------------------
28
30
  // Shared schema fragments
29
31
  // ---------------------------------------------------------------------------
@@ -52,7 +54,12 @@ server.tool("schedule-event", "Create a scheduled event or appointment. For one-
52
54
  try {
53
55
  const timezone = await getUserTimezone(accountId);
54
56
  console.error(`[schedule-event] formatted for timezone: ${timezone}`);
55
- const result = await scheduleEvent({ ...params, accountId });
57
+ const result = await scheduleEvent({
58
+ ...params,
59
+ accountId,
60
+ sessionKey: params.sessionKey ?? sessionId,
61
+ createdBy: { agent: agentSlug, session: sessionId, tool: "schedule-event" },
62
+ });
56
63
  const parts = [`Event created: "${params.name}" (ID: ${result.eventId})`];
57
64
  parts.push(`starts: ${formatCombined(params.startDate, timezone)}`);
58
65
  if (params.recurrence)