@anvia/neo4j 1.1.6 → 1.1.8
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/graph-8BTZ0V9h.js +1145 -0
- package/dist/graph-8BTZ0V9h.js.map +1 -0
- package/dist/index.d.ts +240 -254
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -106
- package/dist/src-CxFXzoZ7.js +646 -0
- package/dist/src-CxFXzoZ7.js.map +1 -0
- package/package.json +7 -7
- package/dist/chunk-IVKNAFKG.js +0 -1607
- package/dist/chunk-IVKNAFKG.js.map +0 -1
- package/dist/chunk-QTIUFXDY.js +0 -527
- package/dist/chunk-QTIUFXDY.js.map +0 -1
- package/dist/chunk-V33PR5HS.js +0 -214
- package/dist/chunk-V33PR5HS.js.map +0 -1
- package/dist/explore-PNLRCONH.js +0 -8
- package/dist/explore-PNLRCONH.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/retrieve-A6UD55NM.js +0 -8
- package/dist/retrieve-A6UD55NM.js.map +0 -1
package/dist/chunk-QTIUFXDY.js
DELETED
|
@@ -1,527 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
ManagedNeo4jKnowledgeGraph,
|
|
3
|
-
Neo4jKnowledgeGraphBase,
|
|
4
|
-
finiteScore,
|
|
5
|
-
managedPathPredicate,
|
|
6
|
-
managedScopeParameters,
|
|
7
|
-
managedScopePredicate,
|
|
8
|
-
positiveInteger,
|
|
9
|
-
quoteIdentifier,
|
|
10
|
-
strictProperties,
|
|
11
|
-
tenantScopePredicate,
|
|
12
|
-
throwIfAborted
|
|
13
|
-
} from "./chunk-IVKNAFKG.js";
|
|
14
|
-
|
|
15
|
-
// src/retrieve.ts
|
|
16
|
-
import { embedText } from "@anvia/core/embeddings";
|
|
17
|
-
import { int, isInt } from "neo4j-driver";
|
|
18
|
-
async function retrieveGraphContext(options) {
|
|
19
|
-
if (!(options.graph instanceof Neo4jKnowledgeGraphBase)) {
|
|
20
|
-
throw new TypeError("retrieveGraphContext requires a Neo4j knowledge graph registration.");
|
|
21
|
-
}
|
|
22
|
-
if (typeof options.query !== "string" || options.query.trim().length === 0) {
|
|
23
|
-
throw new TypeError("Graph retrieval query must be a non-empty string.");
|
|
24
|
-
}
|
|
25
|
-
validateSearch(options.search);
|
|
26
|
-
validateTraversal(options.graph.schema, options.traversal);
|
|
27
|
-
validateEvidence(options.graph.evidenceCapability, options.evidence);
|
|
28
|
-
throwIfAborted(options.abortSignal);
|
|
29
|
-
const graph = options.graph;
|
|
30
|
-
const selectedSeeds = options.search.seeds.map((name) => ({ name, seed: graph.seed(name) }));
|
|
31
|
-
const expectedDimensions = selectedSeeds[0]?.seed.vectorIndex.dimensions;
|
|
32
|
-
if (expectedDimensions === void 0 || selectedSeeds.some((item) => item.seed.vectorIndex.dimensions !== expectedDimensions)) {
|
|
33
|
-
throw new TypeError("Selected Neo4j graph seeds must use the same vector dimensions.");
|
|
34
|
-
}
|
|
35
|
-
if (options.model.dimensions !== void 0 && options.model.dimensions !== expectedDimensions) {
|
|
36
|
-
throw new TypeError(
|
|
37
|
-
`Embedding model dimensions ${options.model.dimensions} do not match Neo4j graph dimensions ${expectedDimensions}.`
|
|
38
|
-
);
|
|
39
|
-
}
|
|
40
|
-
if (options.search.type === "hybrid") {
|
|
41
|
-
for (const { name, seed } of selectedSeeds) {
|
|
42
|
-
if (seed.fulltextIndex === void 0) {
|
|
43
|
-
throw new TypeError(`Neo4j graph seed ${name} does not declare a full-text index.`);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
const { embedding } = await embedText({
|
|
48
|
-
model: options.model,
|
|
49
|
-
text: options.query,
|
|
50
|
-
retries: options.retries,
|
|
51
|
-
abortSignal: options.abortSignal
|
|
52
|
-
});
|
|
53
|
-
if (embedding.vector.length !== expectedDimensions) {
|
|
54
|
-
throw new TypeError(
|
|
55
|
-
`Query embedding dimensions ${embedding.vector.length} do not match Neo4j graph dimensions ${expectedDimensions}.`
|
|
56
|
-
);
|
|
57
|
-
}
|
|
58
|
-
const resultLists = [];
|
|
59
|
-
for (const { seed } of selectedSeeds) {
|
|
60
|
-
const limit = options.search.type === "hybrid" ? options.search.candidatesPerSeed : options.search.topK;
|
|
61
|
-
resultLists.push(
|
|
62
|
-
await vectorSearch(
|
|
63
|
-
graph,
|
|
64
|
-
seed.labels,
|
|
65
|
-
seed.vectorIndex.name,
|
|
66
|
-
embedding.vector,
|
|
67
|
-
limit,
|
|
68
|
-
seed.entryRelationshipType,
|
|
69
|
-
options.abortSignal
|
|
70
|
-
)
|
|
71
|
-
);
|
|
72
|
-
if (options.search.type === "hybrid") {
|
|
73
|
-
const fulltextIndex = seed.fulltextIndex;
|
|
74
|
-
if (fulltextIndex === void 0) {
|
|
75
|
-
throw new TypeError("Hybrid Neo4j graph retrieval requires a full-text index.");
|
|
76
|
-
}
|
|
77
|
-
resultLists.push(
|
|
78
|
-
await fulltextSearch(
|
|
79
|
-
graph,
|
|
80
|
-
fulltextIndex.name,
|
|
81
|
-
options.query,
|
|
82
|
-
limit,
|
|
83
|
-
seed.entryRelationshipType,
|
|
84
|
-
options.abortSignal
|
|
85
|
-
)
|
|
86
|
-
);
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
const hits = options.search.type === "hybrid" ? fuseResults(resultLists, options.search.topK, options.search.rrfK) : vectorResults(resultLists[0] ?? [], options.search.topK, options.search.minScore);
|
|
90
|
-
throwIfAborted(options.abortSignal);
|
|
91
|
-
const seeds = hits.map((hit) => seedFromHit(hit, options.graph.schema));
|
|
92
|
-
const traversed = hits.length === 0 ? { nodes: [], relationships: [] } : await traverse(graph, hits, options.traversal, options.abortSignal);
|
|
93
|
-
const context = { seeds, ...traversed };
|
|
94
|
-
const evidence = await hydrateEvidence(graph, context, options.evidence, options.abortSignal);
|
|
95
|
-
return { ...context, evidence };
|
|
96
|
-
}
|
|
97
|
-
async function vectorSearch(graph, labels, indexName, vector, limit, entryRelationshipType, abortSignal) {
|
|
98
|
-
const labelExpression = labels.map(quoteIdentifier).join("|");
|
|
99
|
-
const vectorFilter = graph instanceof ManagedNeo4jKnowledgeGraph && graph.namespace !== void 0 ? ` WHERE seed.${quoteIdentifier("__anvia_namespace")} = $namespace` : "";
|
|
100
|
-
const postFilter = managedSearchPredicate(
|
|
101
|
-
graph,
|
|
102
|
-
"seed",
|
|
103
|
-
entryRelationshipType === "ANVIA_MENTIONS"
|
|
104
|
-
);
|
|
105
|
-
const result = await graph.query(
|
|
106
|
-
`CYPHER 25
|
|
107
|
-
MATCH (seed:${labelExpression})
|
|
108
|
-
SEARCH seed IN (VECTOR INDEX ${quoteIdentifier(indexName)} FOR $vector${vectorFilter} LIMIT $limit) SCORE AS score
|
|
109
|
-
${postFilter}
|
|
110
|
-
RETURN elementId(seed) AS elementId, labels(seed) AS labels, properties(seed) AS properties, score`,
|
|
111
|
-
managedQueryParameters(graph, { vector, limit: int(limit) }),
|
|
112
|
-
abortSignal
|
|
113
|
-
);
|
|
114
|
-
return result.records.map((record) => ({ ...parseSearchHit(record), entryRelationshipType }));
|
|
115
|
-
}
|
|
116
|
-
async function fulltextSearch(graph, indexName, query, limit, entryRelationshipType, abortSignal) {
|
|
117
|
-
const result = await graph.query(
|
|
118
|
-
`CALL db.index.fulltext.queryNodes($indexName, $query, {limit: $limit}) YIELD node AS seed, score
|
|
119
|
-
${managedSearchPredicate(graph, "seed", entryRelationshipType === "ANVIA_MENTIONS")}
|
|
120
|
-
RETURN elementId(seed) AS elementId, labels(seed) AS labels, properties(seed) AS properties, score`,
|
|
121
|
-
managedQueryParameters(graph, {
|
|
122
|
-
indexName,
|
|
123
|
-
query: scopedFulltextQuery(graph, query),
|
|
124
|
-
limit: int(limit)
|
|
125
|
-
}),
|
|
126
|
-
abortSignal
|
|
127
|
-
);
|
|
128
|
-
return result.records.map((record) => ({ ...parseSearchHit(record), entryRelationshipType }));
|
|
129
|
-
}
|
|
130
|
-
function parseSearchHit(record) {
|
|
131
|
-
const elementId = record.get("elementId");
|
|
132
|
-
const labels = record.get("labels");
|
|
133
|
-
const properties = record.get("properties");
|
|
134
|
-
const score = record.get("score");
|
|
135
|
-
if (typeof elementId !== "string" || !Array.isArray(labels) || !labels.every((label) => typeof label === "string") || typeof properties !== "object" || properties === null || typeof score !== "number" || !Number.isFinite(score)) {
|
|
136
|
-
throw new TypeError("Neo4j search returned a malformed result.");
|
|
137
|
-
}
|
|
138
|
-
return { elementId, labels, properties, score };
|
|
139
|
-
}
|
|
140
|
-
function seedFromHit(hit, schema) {
|
|
141
|
-
const application = applicationProperties(hit.properties, "Neo4j search seed");
|
|
142
|
-
const key = stringProperty(hit.properties, "__anvia_key") ?? stringProperty(hit.properties, "__anvia_id") ?? hit.elementId;
|
|
143
|
-
const type = hit.labels.find((label) => label in schema.nodes) ?? hit.labels[0] ?? "Node";
|
|
144
|
-
return {
|
|
145
|
-
key,
|
|
146
|
-
type,
|
|
147
|
-
score: hit.score,
|
|
148
|
-
properties: application,
|
|
149
|
-
sourceChunkIds: hit.entryRelationshipType === "ANVIA_MENTIONS" ? [key] : stringArrayProperty(hit.properties, "__anvia_source_chunk_ids")
|
|
150
|
-
};
|
|
151
|
-
}
|
|
152
|
-
async function hydrateEvidence(graph, context, options, abortSignal) {
|
|
153
|
-
if (options.type === "none") return [];
|
|
154
|
-
if (!(graph instanceof ManagedNeo4jKnowledgeGraph)) {
|
|
155
|
-
throw new TypeError("Chunk evidence requires a managed Neo4j knowledge graph.");
|
|
156
|
-
}
|
|
157
|
-
const chunkIds = [];
|
|
158
|
-
const seen = /* @__PURE__ */ new Set();
|
|
159
|
-
for (const sourceChunkIds of [
|
|
160
|
-
...context.seeds.map((seed) => seed.sourceChunkIds),
|
|
161
|
-
...context.nodes.map((node) => node.sourceChunkIds),
|
|
162
|
-
...context.relationships.map((relationship) => relationship.sourceChunkIds)
|
|
163
|
-
]) {
|
|
164
|
-
for (const chunkId of sourceChunkIds) {
|
|
165
|
-
if (seen.has(chunkId)) continue;
|
|
166
|
-
seen.add(chunkId);
|
|
167
|
-
chunkIds.push(chunkId);
|
|
168
|
-
if (chunkIds.length === options.maxChunks) break;
|
|
169
|
-
}
|
|
170
|
-
if (chunkIds.length === options.maxChunks) break;
|
|
171
|
-
}
|
|
172
|
-
if (chunkIds.length === 0) return [];
|
|
173
|
-
throwIfAborted(abortSignal);
|
|
174
|
-
const result = await graph.query(
|
|
175
|
-
`MATCH (d:${quoteIdentifier(graph.resources.labels.document)})-[:${quoteIdentifier("ANVIA_HAS_CHUNK")}]->(c:${quoteIdentifier(graph.resources.labels.chunk)})
|
|
176
|
-
WHERE c.${quoteIdentifier("__anvia_id")} IN $chunkIds
|
|
177
|
-
${tenantNodeAndPredicate(graph, "d")}${tenantNodeAndPredicate(graph, "c")}
|
|
178
|
-
RETURN c.${quoteIdentifier("__anvia_id")} AS chunkId,
|
|
179
|
-
d.${quoteIdentifier("__anvia_id")} AS documentId,
|
|
180
|
-
c.${quoteIdentifier("__anvia_index")} AS index,
|
|
181
|
-
c.${quoteIdentifier("__anvia_text")} AS text,
|
|
182
|
-
properties(c) AS properties`,
|
|
183
|
-
managedQueryParameters(graph, { chunkIds }),
|
|
184
|
-
abortSignal
|
|
185
|
-
);
|
|
186
|
-
const byId = /* @__PURE__ */ new Map();
|
|
187
|
-
for (const record of result.records) {
|
|
188
|
-
const evidence = evidenceFromRecord(record);
|
|
189
|
-
if (byId.has(evidence.chunkId)) {
|
|
190
|
-
throw new TypeError(`Neo4j evidence returned duplicate chunk ${evidence.chunkId}.`);
|
|
191
|
-
}
|
|
192
|
-
byId.set(evidence.chunkId, evidence);
|
|
193
|
-
}
|
|
194
|
-
return chunkIds.map((chunkId) => {
|
|
195
|
-
const evidence = byId.get(chunkId);
|
|
196
|
-
if (evidence === void 0) {
|
|
197
|
-
throw new Error(`Neo4j graph evidence references missing chunk ${chunkId}.`);
|
|
198
|
-
}
|
|
199
|
-
return evidence;
|
|
200
|
-
});
|
|
201
|
-
}
|
|
202
|
-
function evidenceFromRecord(record) {
|
|
203
|
-
const chunkId = stringValue(record.get("chunkId"), "Neo4j evidence chunk id");
|
|
204
|
-
const documentId = stringValue(record.get("documentId"), "Neo4j evidence document id");
|
|
205
|
-
const index = safeIntegerValue(record.get("index"), "Neo4j evidence chunk index");
|
|
206
|
-
const text = stringValue(record.get("text"), "Neo4j evidence text");
|
|
207
|
-
const raw = record.get("properties");
|
|
208
|
-
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
|
|
209
|
-
throw new TypeError("Neo4j evidence properties must be an object.");
|
|
210
|
-
}
|
|
211
|
-
return {
|
|
212
|
-
chunkId,
|
|
213
|
-
documentId,
|
|
214
|
-
index,
|
|
215
|
-
text,
|
|
216
|
-
metadata: applicationProperties(raw, "Neo4j evidence metadata")
|
|
217
|
-
};
|
|
218
|
-
}
|
|
219
|
-
function safeIntegerValue(value, label) {
|
|
220
|
-
let number = value;
|
|
221
|
-
if (isInt(value)) {
|
|
222
|
-
number = void 0;
|
|
223
|
-
if (value.inSafeRange()) {
|
|
224
|
-
number = value.toNumber();
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
if (typeof number !== "number" || !Number.isSafeInteger(number)) {
|
|
228
|
-
throw new TypeError(`${label} must be a safe integer.`);
|
|
229
|
-
}
|
|
230
|
-
return number;
|
|
231
|
-
}
|
|
232
|
-
function vectorResults(results, topK, minScore) {
|
|
233
|
-
return results.filter((item) => minScore === void 0 || item.score >= minScore).slice(0, topK);
|
|
234
|
-
}
|
|
235
|
-
async function traverse(graph, seeds, options, abortSignal) {
|
|
236
|
-
const traversalSeedIds = new Set(
|
|
237
|
-
seeds.filter((seed) => seed.entryRelationshipType === void 0).map((seed) => seed.elementId)
|
|
238
|
-
);
|
|
239
|
-
const entryGroups = groupBy(
|
|
240
|
-
seeds.filter(
|
|
241
|
-
(seed) => seed.entryRelationshipType !== void 0
|
|
242
|
-
),
|
|
243
|
-
(seed) => seed.entryRelationshipType
|
|
244
|
-
);
|
|
245
|
-
for (const [relationshipType, group] of entryGroups) {
|
|
246
|
-
const entries = await graph.query(
|
|
247
|
-
`MATCH (seed) WHERE elementId(seed) IN $seedIds
|
|
248
|
-
${tenantNodePredicate(graph, "seed", "AND")}
|
|
249
|
-
MATCH (seed)-[entryRelationship:${quoteIdentifier(relationshipType)}]->(entry)
|
|
250
|
-
WHERE true${managedNodeAndPredicate(graph, "entry")}${tenantNodeAndPredicate(graph, "entryRelationship")}
|
|
251
|
-
RETURN DISTINCT elementId(entry) AS elementId`,
|
|
252
|
-
managedQueryParameters(graph, { seedIds: group.map((seed) => seed.elementId) }),
|
|
253
|
-
abortSignal
|
|
254
|
-
);
|
|
255
|
-
for (const record of entries.records) {
|
|
256
|
-
traversalSeedIds.add(stringValue(record.get("elementId"), "Neo4j entry elementId"));
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
if (traversalSeedIds.size === 0) return { nodes: [], relationships: [] };
|
|
260
|
-
const limitedSeedIds = [...traversalSeedIds].slice(0, options.maxNodes);
|
|
261
|
-
const pattern = traversalPattern(options.direction, options.maxDepth);
|
|
262
|
-
const pathLimit = Math.max(options.maxNodes, options.maxRelationships);
|
|
263
|
-
const seedNodes = await graph.query(
|
|
264
|
-
`MATCH (node) WHERE elementId(node) IN $seedIds
|
|
265
|
-
${managedNodePredicate(graph, "node", "AND")}
|
|
266
|
-
RETURN {elementId: elementId(node), labels: labels(node), properties: properties(node)} AS node`,
|
|
267
|
-
managedQueryParameters(graph, { seedIds: limitedSeedIds }),
|
|
268
|
-
abortSignal
|
|
269
|
-
);
|
|
270
|
-
const result = await graph.query(
|
|
271
|
-
`MATCH (seed) WHERE elementId(seed) IN $seedIds
|
|
272
|
-
${managedNodePredicate(graph, "seed", "AND")}
|
|
273
|
-
MATCH path = ${pattern}
|
|
274
|
-
WHERE all(rel IN relationships(path) WHERE type(rel) IN $relationshipTypes${managedRelationshipAndPredicate(graph, "rel")})${managedPathAndPredicate(graph)}
|
|
275
|
-
RETURN [item IN nodes(path) | {elementId: elementId(item), labels: labels(item), properties: properties(item)}] AS nodes,
|
|
276
|
-
[item IN relationships(path) | {elementId: elementId(item), type: type(item), properties: properties(item), from: elementId(startNode(item)), to: elementId(endNode(item))}] AS relationships
|
|
277
|
-
LIMIT $pathLimit`,
|
|
278
|
-
managedQueryParameters(graph, {
|
|
279
|
-
seedIds: limitedSeedIds,
|
|
280
|
-
relationshipTypes: options.relationships,
|
|
281
|
-
pathLimit: int(pathLimit)
|
|
282
|
-
}),
|
|
283
|
-
abortSignal
|
|
284
|
-
);
|
|
285
|
-
const nodes = /* @__PURE__ */ new Map();
|
|
286
|
-
const nodeKeysByElementId = /* @__PURE__ */ new Map();
|
|
287
|
-
const relationships = /* @__PURE__ */ new Map();
|
|
288
|
-
const seedNodesByElementId = /* @__PURE__ */ new Map();
|
|
289
|
-
for (const record of seedNodes.records) {
|
|
290
|
-
const value = record.get("node");
|
|
291
|
-
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
292
|
-
throw new TypeError("Neo4j traversal returned a malformed seed node.");
|
|
293
|
-
}
|
|
294
|
-
const map = value;
|
|
295
|
-
seedNodesByElementId.set(stringValue(map.elementId, "Neo4j seed node elementId"), map);
|
|
296
|
-
}
|
|
297
|
-
const addNode = (value) => {
|
|
298
|
-
const parsed = contextNode(value, graph.schema);
|
|
299
|
-
const existing = nodes.get(parsed.node.key);
|
|
300
|
-
if (existing === void 0 && nodes.size >= options.maxNodes) return;
|
|
301
|
-
if (existing === void 0) nodes.set(parsed.node.key, parsed.node);
|
|
302
|
-
nodeKeysByElementId.set(parsed.elementId, parsed.node.key);
|
|
303
|
-
};
|
|
304
|
-
for (const elementId of limitedSeedIds) {
|
|
305
|
-
const value = seedNodesByElementId.get(elementId);
|
|
306
|
-
if (value !== void 0) addNode(value);
|
|
307
|
-
}
|
|
308
|
-
for (const record of result.records) {
|
|
309
|
-
for (const value of listOfMaps(record.get("nodes"), "Neo4j traversal nodes")) {
|
|
310
|
-
addNode(value);
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
for (const record of result.records) {
|
|
314
|
-
for (const value of listOfMaps(record.get("relationships"), "Neo4j traversal relationships")) {
|
|
315
|
-
const relationship = contextRelationship(value, nodeKeysByElementId);
|
|
316
|
-
if (relationship !== void 0 && !relationships.has(relationship.key) && relationships.size < options.maxRelationships) {
|
|
317
|
-
relationships.set(relationship.key, relationship);
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
return { nodes: [...nodes.values()], relationships: [...relationships.values()] };
|
|
322
|
-
}
|
|
323
|
-
function traversalPattern(direction, maxDepth) {
|
|
324
|
-
if (direction === "outgoing") {
|
|
325
|
-
return `(seed)-[*1..${maxDepth}]->(node)`;
|
|
326
|
-
}
|
|
327
|
-
if (direction === "incoming") {
|
|
328
|
-
return `(seed)<-[*1..${maxDepth}]-(node)`;
|
|
329
|
-
}
|
|
330
|
-
return `(seed)-[*1..${maxDepth}]-(node)`;
|
|
331
|
-
}
|
|
332
|
-
function managedQueryParameters(graph, parameters) {
|
|
333
|
-
return managedScopeParameters(managedScope(graph), parameters);
|
|
334
|
-
}
|
|
335
|
-
function managedNodePredicate(graph, variable, prefix) {
|
|
336
|
-
return managedScopePredicate(managedScope(graph), variable, prefix);
|
|
337
|
-
}
|
|
338
|
-
function managedSearchPredicate(graph, variable, chunkSeed) {
|
|
339
|
-
return chunkSeed && graph.namespace === void 0 ? "" : managedNodePredicate(graph, variable, "WHERE");
|
|
340
|
-
}
|
|
341
|
-
function managedNodeAndPredicate(graph, variable) {
|
|
342
|
-
return managedScopePredicate(managedScope(graph), variable, " AND");
|
|
343
|
-
}
|
|
344
|
-
function managedRelationshipAndPredicate(graph, variable) {
|
|
345
|
-
return managedNodeAndPredicate(graph, variable);
|
|
346
|
-
}
|
|
347
|
-
function tenantNodePredicate(graph, variable, prefix) {
|
|
348
|
-
const scope = managedScope(graph);
|
|
349
|
-
return scope === void 0 ? "" : tenantScopePredicate(scope, variable, prefix);
|
|
350
|
-
}
|
|
351
|
-
function tenantNodeAndPredicate(graph, variable) {
|
|
352
|
-
const predicate = tenantNodePredicate(graph, variable, "AND");
|
|
353
|
-
return predicate.length === 0 ? "" : ` ${predicate}`;
|
|
354
|
-
}
|
|
355
|
-
function managedPathAndPredicate(graph) {
|
|
356
|
-
return managedPathPredicate(managedScope(graph), false);
|
|
357
|
-
}
|
|
358
|
-
function managedScope(graph) {
|
|
359
|
-
return graph instanceof ManagedNeo4jKnowledgeGraph ? { graph: graph.name, namespace: graph.namespace } : void 0;
|
|
360
|
-
}
|
|
361
|
-
function contextNode(value, schema) {
|
|
362
|
-
const labels = value.labels;
|
|
363
|
-
const raw = value.properties;
|
|
364
|
-
if (!Array.isArray(labels) || !labels.every((label) => typeof label === "string")) {
|
|
365
|
-
throw new TypeError("Neo4j traversal returned malformed node labels.");
|
|
366
|
-
}
|
|
367
|
-
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
|
|
368
|
-
throw new TypeError("Neo4j traversal returned malformed node properties.");
|
|
369
|
-
}
|
|
370
|
-
const properties = applicationProperties(raw, "Neo4j graph node");
|
|
371
|
-
const type = labels.find((label) => label in schema.nodes) ?? labels[0] ?? "Node";
|
|
372
|
-
const definition = schema.nodes[type];
|
|
373
|
-
const identity = {};
|
|
374
|
-
if (definition !== void 0) {
|
|
375
|
-
for (const property of definition.identity) {
|
|
376
|
-
const item = properties[property];
|
|
377
|
-
if (typeof item === "string" || typeof item === "number" || typeof item === "boolean") {
|
|
378
|
-
identity[property] = item;
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
}
|
|
382
|
-
const elementId = stringValue(value.elementId, "Neo4j node elementId");
|
|
383
|
-
return {
|
|
384
|
-
elementId,
|
|
385
|
-
node: {
|
|
386
|
-
key: stringProperty(raw, "__anvia_key") ?? elementId,
|
|
387
|
-
type,
|
|
388
|
-
identity,
|
|
389
|
-
properties,
|
|
390
|
-
sourceChunkIds: stringArrayProperty(
|
|
391
|
-
raw,
|
|
392
|
-
"__anvia_source_chunk_ids"
|
|
393
|
-
)
|
|
394
|
-
}
|
|
395
|
-
};
|
|
396
|
-
}
|
|
397
|
-
function contextRelationship(value, nodeKeysByElementId) {
|
|
398
|
-
const raw = value.properties;
|
|
399
|
-
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
|
|
400
|
-
throw new TypeError("Neo4j traversal returned malformed relationship properties.");
|
|
401
|
-
}
|
|
402
|
-
const elementId = stringValue(value.elementId, "Neo4j relationship elementId");
|
|
403
|
-
const fromElementId = stringValue(value.from, "Neo4j relationship source");
|
|
404
|
-
const toElementId = stringValue(value.to, "Neo4j relationship target");
|
|
405
|
-
const from = nodeKeysByElementId.get(fromElementId);
|
|
406
|
-
const to = nodeKeysByElementId.get(toElementId);
|
|
407
|
-
if (from === void 0 || to === void 0) return void 0;
|
|
408
|
-
return {
|
|
409
|
-
key: stringProperty(raw, "__anvia_key") ?? elementId,
|
|
410
|
-
type: stringValue(value.type, "Neo4j relationship type"),
|
|
411
|
-
from,
|
|
412
|
-
to,
|
|
413
|
-
properties: applicationProperties(raw, "Neo4j graph relationship"),
|
|
414
|
-
sourceChunkIds: stringArrayProperty(raw, "__anvia_source_chunk_ids")
|
|
415
|
-
};
|
|
416
|
-
}
|
|
417
|
-
function fuseResults(lists, topK, rrfK) {
|
|
418
|
-
const fused = /* @__PURE__ */ new Map();
|
|
419
|
-
for (const list of lists) {
|
|
420
|
-
list.forEach((item, index) => {
|
|
421
|
-
const score = 1 / (rrfK + index + 1);
|
|
422
|
-
const current = fused.get(item.elementId);
|
|
423
|
-
fused.set(item.elementId, { ...item, score: (current?.score ?? 0) + score });
|
|
424
|
-
});
|
|
425
|
-
}
|
|
426
|
-
return [...fused.values()].sort((left, right) => right.score - left.score).slice(0, topK);
|
|
427
|
-
}
|
|
428
|
-
function validateSearch(search) {
|
|
429
|
-
positiveInteger(search.topK, "Neo4j graph search topK");
|
|
430
|
-
if (search.seeds.length === 0 || new Set(search.seeds).size !== search.seeds.length) {
|
|
431
|
-
throw new TypeError("Neo4j graph search requires unique seed names.");
|
|
432
|
-
}
|
|
433
|
-
if (search.type === "vector") {
|
|
434
|
-
if (search.seeds.length !== 1)
|
|
435
|
-
throw new TypeError(
|
|
436
|
-
"Vector graph search accepts exactly one seed; use hybrid search to fuse multiple seeds."
|
|
437
|
-
);
|
|
438
|
-
finiteScore(search.minScore, "Neo4j graph search minScore");
|
|
439
|
-
} else {
|
|
440
|
-
positiveInteger(search.candidatesPerSeed, "Neo4j hybrid candidatesPerSeed");
|
|
441
|
-
positiveInteger(search.rrfK, "Neo4j hybrid rrfK");
|
|
442
|
-
}
|
|
443
|
-
}
|
|
444
|
-
function validateEvidence(capability, evidence) {
|
|
445
|
-
if (typeof evidence !== "object" || evidence === null) {
|
|
446
|
-
throw new TypeError("Neo4j graph retrieval requires an explicit evidence mode.");
|
|
447
|
-
}
|
|
448
|
-
if (evidence.type === "none") return;
|
|
449
|
-
if (evidence.type !== "chunks") {
|
|
450
|
-
throw new TypeError("Unknown Neo4j graph evidence mode.");
|
|
451
|
-
}
|
|
452
|
-
positiveInteger(evidence.maxChunks, "Neo4j graph evidence maxChunks");
|
|
453
|
-
if (capability !== "chunks") {
|
|
454
|
-
throw new TypeError("Chunk evidence requires a managed Neo4j knowledge graph.");
|
|
455
|
-
}
|
|
456
|
-
}
|
|
457
|
-
function validateTraversal(schema, traversal) {
|
|
458
|
-
if (traversal.direction !== "outgoing" && traversal.direction !== "incoming" && traversal.direction !== "both") {
|
|
459
|
-
throw new TypeError("Neo4j traversal direction must be outgoing, incoming, or both.");
|
|
460
|
-
}
|
|
461
|
-
positiveInteger(traversal.maxDepth, "Neo4j traversal maxDepth", 8);
|
|
462
|
-
positiveInteger(traversal.maxNodes, "Neo4j traversal maxNodes");
|
|
463
|
-
positiveInteger(traversal.maxRelationships, "Neo4j traversal maxRelationships");
|
|
464
|
-
if (traversal.relationships.length === 0 || new Set(traversal.relationships).size !== traversal.relationships.length) {
|
|
465
|
-
throw new TypeError("Neo4j traversal requires unique relationship types.");
|
|
466
|
-
}
|
|
467
|
-
for (const type of traversal.relationships) {
|
|
468
|
-
if (!(type in schema.relationships))
|
|
469
|
-
throw new TypeError(`Neo4j traversal references unknown relationship type ${type}.`);
|
|
470
|
-
}
|
|
471
|
-
}
|
|
472
|
-
function applicationProperties(value, label) {
|
|
473
|
-
return strictProperties(
|
|
474
|
-
Object.fromEntries(Object.entries(value).filter(([key]) => !key.startsWith("__anvia_"))),
|
|
475
|
-
label
|
|
476
|
-
);
|
|
477
|
-
}
|
|
478
|
-
function stringProperty(value, property) {
|
|
479
|
-
const item = value[property];
|
|
480
|
-
if (item === void 0) return void 0;
|
|
481
|
-
return stringValue(item, `Neo4j property ${property}`);
|
|
482
|
-
}
|
|
483
|
-
function stringArrayProperty(value, property) {
|
|
484
|
-
const item = value[property];
|
|
485
|
-
if (item === void 0) return [];
|
|
486
|
-
if (!Array.isArray(item) || !item.every((entry) => typeof entry === "string")) {
|
|
487
|
-
throw new TypeError(`Neo4j property ${property} must be a string array.`);
|
|
488
|
-
}
|
|
489
|
-
return [...item];
|
|
490
|
-
}
|
|
491
|
-
function stringValue(value, label) {
|
|
492
|
-
if (typeof value !== "string") throw new TypeError(`${label} must be a string.`);
|
|
493
|
-
return value;
|
|
494
|
-
}
|
|
495
|
-
function listOfMaps(value, label) {
|
|
496
|
-
if (!Array.isArray(value) || !value.every((item) => typeof item === "object" && item !== null && !Array.isArray(item))) {
|
|
497
|
-
throw new TypeError(`${label} must be an array of objects.`);
|
|
498
|
-
}
|
|
499
|
-
return value;
|
|
500
|
-
}
|
|
501
|
-
function escapeLucene(value) {
|
|
502
|
-
const specialCharacters = new Set('+-&|!(){}[]^"~*?:\\/');
|
|
503
|
-
let escaped = "";
|
|
504
|
-
for (const character of value) {
|
|
505
|
-
escaped += specialCharacters.has(character) ? `\\${character}` : character;
|
|
506
|
-
}
|
|
507
|
-
return escaped;
|
|
508
|
-
}
|
|
509
|
-
function scopedFulltextQuery(graph, value) {
|
|
510
|
-
const query = escapeLucene(value);
|
|
511
|
-
return graph instanceof ManagedNeo4jKnowledgeGraph && graph.namespace !== void 0 ? `(${query}) AND __anvia_namespace:${escapeLucene(graph.namespace)}` : query;
|
|
512
|
-
}
|
|
513
|
-
function groupBy(values, keyFor) {
|
|
514
|
-
const groups = /* @__PURE__ */ new Map();
|
|
515
|
-
for (const value of values) {
|
|
516
|
-
const key = keyFor(value);
|
|
517
|
-
const group = groups.get(key);
|
|
518
|
-
if (group === void 0) groups.set(key, [value]);
|
|
519
|
-
else group.push(value);
|
|
520
|
-
}
|
|
521
|
-
return groups;
|
|
522
|
-
}
|
|
523
|
-
|
|
524
|
-
export {
|
|
525
|
-
retrieveGraphContext
|
|
526
|
-
};
|
|
527
|
-
//# sourceMappingURL=chunk-QTIUFXDY.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/retrieve.ts"],"sourcesContent":["import { embedText } from \"@anvia/core/embeddings\";\nimport { int, isInt, type Record as Neo4jRecord } from \"neo4j-driver\";\nimport { ManagedNeo4jKnowledgeGraph, Neo4jKnowledgeGraphBase } from \"./graph.js\";\nimport {\n finiteScore,\n positiveInteger,\n quoteIdentifier,\n strictProperties,\n throwIfAborted,\n} from \"./helpers.js\";\nimport {\n managedPathPredicate,\n managedScopeParameters,\n managedScopePredicate,\n tenantScopePredicate,\n type Neo4jManagedScope,\n} from \"./managed-scope.js\";\nimport type {\n Neo4jGraphContext,\n Neo4jGraphContextNode,\n Neo4jGraphContextRelationship,\n Neo4jGraphContextSeed,\n Neo4jGraphEvidence,\n Neo4jGraphEvidenceOptions,\n Neo4jGraphSchema,\n RetrieveGraphContextOptions,\n} from \"./types.js\";\n\ntype SearchHit = {\n elementId: string;\n labels: string[];\n properties: Record<string, unknown>;\n score: number;\n entryRelationshipType?: string | undefined;\n};\n\nexport async function retrieveGraphContext<Schema extends Neo4jGraphSchema>(\n options: RetrieveGraphContextOptions<Schema>,\n): Promise<Neo4jGraphContext> {\n if (!(options.graph instanceof Neo4jKnowledgeGraphBase)) {\n throw new TypeError(\"retrieveGraphContext requires a Neo4j knowledge graph registration.\");\n }\n if (typeof options.query !== \"string\" || options.query.trim().length === 0) {\n throw new TypeError(\"Graph retrieval query must be a non-empty string.\");\n }\n validateSearch(options.search);\n validateTraversal(options.graph.schema, options.traversal);\n validateEvidence(options.graph.evidenceCapability, options.evidence);\n throwIfAborted(options.abortSignal);\n const graph = options.graph as Neo4jKnowledgeGraphBase<Schema>;\n const selectedSeeds = options.search.seeds.map((name) => ({ name, seed: graph.seed(name) }));\n const expectedDimensions = selectedSeeds[0]?.seed.vectorIndex.dimensions;\n if (\n expectedDimensions === undefined ||\n selectedSeeds.some((item) => item.seed.vectorIndex.dimensions !== expectedDimensions)\n ) {\n throw new TypeError(\"Selected Neo4j graph seeds must use the same vector dimensions.\");\n }\n if (options.model.dimensions !== undefined && options.model.dimensions !== expectedDimensions) {\n throw new TypeError(\n `Embedding model dimensions ${options.model.dimensions} do not match Neo4j graph dimensions ${expectedDimensions}.`,\n );\n }\n if (options.search.type === \"hybrid\") {\n for (const { name, seed } of selectedSeeds) {\n if (seed.fulltextIndex === undefined) {\n throw new TypeError(`Neo4j graph seed ${name} does not declare a full-text index.`);\n }\n }\n }\n const { embedding } = await embedText({\n model: options.model,\n text: options.query,\n retries: options.retries,\n abortSignal: options.abortSignal,\n });\n if (embedding.vector.length !== expectedDimensions) {\n throw new TypeError(\n `Query embedding dimensions ${embedding.vector.length} do not match Neo4j graph dimensions ${expectedDimensions}.`,\n );\n }\n\n const resultLists: SearchHit[][] = [];\n for (const { seed } of selectedSeeds) {\n const limit =\n options.search.type === \"hybrid\" ? options.search.candidatesPerSeed : options.search.topK;\n resultLists.push(\n await vectorSearch(\n graph,\n seed.labels,\n seed.vectorIndex.name,\n embedding.vector,\n limit,\n seed.entryRelationshipType,\n options.abortSignal,\n ),\n );\n if (options.search.type === \"hybrid\") {\n const fulltextIndex = seed.fulltextIndex;\n if (fulltextIndex === undefined) {\n throw new TypeError(\"Hybrid Neo4j graph retrieval requires a full-text index.\");\n }\n resultLists.push(\n await fulltextSearch(\n graph,\n fulltextIndex.name,\n options.query,\n limit,\n seed.entryRelationshipType,\n options.abortSignal,\n ),\n );\n }\n }\n\n const hits =\n options.search.type === \"hybrid\"\n ? fuseResults(resultLists, options.search.topK, options.search.rrfK)\n : vectorResults(resultLists[0] ?? [], options.search.topK, options.search.minScore);\n throwIfAborted(options.abortSignal);\n const seeds = hits.map((hit) => seedFromHit(hit, options.graph.schema));\n const traversed =\n hits.length === 0\n ? { nodes: [], relationships: [] }\n : await traverse(graph, hits, options.traversal, options.abortSignal);\n const context = { seeds, ...traversed };\n const evidence = await hydrateEvidence(graph, context, options.evidence, options.abortSignal);\n return { ...context, evidence };\n}\n\nasync function vectorSearch(\n graph: Neo4jKnowledgeGraphBase,\n labels: readonly string[],\n indexName: string,\n vector: readonly number[],\n limit: number,\n entryRelationshipType?: string,\n abortSignal?: AbortSignal,\n): Promise<SearchHit[]> {\n const labelExpression = labels.map(quoteIdentifier).join(\"|\");\n const vectorFilter =\n graph instanceof ManagedNeo4jKnowledgeGraph && graph.namespace !== undefined\n ? ` WHERE seed.${quoteIdentifier(\"__anvia_namespace\")} = $namespace`\n : \"\";\n const postFilter = managedSearchPredicate(\n graph,\n \"seed\",\n entryRelationshipType === \"ANVIA_MENTIONS\",\n );\n const result = await graph.query(\n `CYPHER 25\nMATCH (seed:${labelExpression})\nSEARCH seed IN (VECTOR INDEX ${quoteIdentifier(indexName)} FOR $vector${vectorFilter} LIMIT $limit) SCORE AS score\n${postFilter}\nRETURN elementId(seed) AS elementId, labels(seed) AS labels, properties(seed) AS properties, score`,\n managedQueryParameters(graph, { vector, limit: int(limit) }),\n abortSignal,\n );\n return result.records.map((record) => ({ ...parseSearchHit(record), entryRelationshipType }));\n}\n\nasync function fulltextSearch(\n graph: Neo4jKnowledgeGraphBase,\n indexName: string,\n query: string,\n limit: number,\n entryRelationshipType?: string,\n abortSignal?: AbortSignal,\n): Promise<SearchHit[]> {\n const result = await graph.query(\n `CALL db.index.fulltext.queryNodes($indexName, $query, {limit: $limit}) YIELD node AS seed, score\n${managedSearchPredicate(graph, \"seed\", entryRelationshipType === \"ANVIA_MENTIONS\")}\nRETURN elementId(seed) AS elementId, labels(seed) AS labels, properties(seed) AS properties, score`,\n managedQueryParameters(graph, {\n indexName,\n query: scopedFulltextQuery(graph, query),\n limit: int(limit),\n }),\n abortSignal,\n );\n return result.records.map((record) => ({ ...parseSearchHit(record), entryRelationshipType }));\n}\n\nfunction parseSearchHit(record: Neo4jRecord): SearchHit {\n const elementId = record.get(\"elementId\");\n const labels = record.get(\"labels\");\n const properties = record.get(\"properties\");\n const score = record.get(\"score\");\n if (\n typeof elementId !== \"string\" ||\n !Array.isArray(labels) ||\n !labels.every((label) => typeof label === \"string\") ||\n typeof properties !== \"object\" ||\n properties === null ||\n typeof score !== \"number\" ||\n !Number.isFinite(score)\n ) {\n throw new TypeError(\"Neo4j search returned a malformed result.\");\n }\n return { elementId, labels, properties: properties as Record<string, unknown>, score };\n}\n\nfunction seedFromHit(hit: SearchHit, schema: Neo4jGraphSchema): Neo4jGraphContextSeed {\n const application = applicationProperties(hit.properties, \"Neo4j search seed\");\n const key =\n stringProperty(hit.properties, \"__anvia_key\") ??\n stringProperty(hit.properties, \"__anvia_id\") ??\n hit.elementId;\n const type = hit.labels.find((label) => label in schema.nodes) ?? hit.labels[0] ?? \"Node\";\n return {\n key,\n type,\n score: hit.score,\n properties: application,\n sourceChunkIds:\n hit.entryRelationshipType === \"ANVIA_MENTIONS\"\n ? [key]\n : stringArrayProperty(hit.properties, \"__anvia_source_chunk_ids\"),\n };\n}\n\nasync function hydrateEvidence(\n graph: Neo4jKnowledgeGraphBase,\n context: Pick<Neo4jGraphContext, \"seeds\" | \"nodes\" | \"relationships\">,\n options: Neo4jGraphEvidenceOptions,\n abortSignal?: AbortSignal,\n): Promise<Neo4jGraphEvidence[]> {\n if (options.type === \"none\") return [];\n if (!(graph instanceof ManagedNeo4jKnowledgeGraph)) {\n throw new TypeError(\"Chunk evidence requires a managed Neo4j knowledge graph.\");\n }\n const chunkIds: string[] = [];\n const seen = new Set<string>();\n for (const sourceChunkIds of [\n ...context.seeds.map((seed) => seed.sourceChunkIds),\n ...context.nodes.map((node) => node.sourceChunkIds),\n ...context.relationships.map((relationship) => relationship.sourceChunkIds),\n ]) {\n for (const chunkId of sourceChunkIds) {\n if (seen.has(chunkId)) continue;\n seen.add(chunkId);\n chunkIds.push(chunkId);\n if (chunkIds.length === options.maxChunks) break;\n }\n if (chunkIds.length === options.maxChunks) break;\n }\n if (chunkIds.length === 0) return [];\n throwIfAborted(abortSignal);\n const result = await graph.query(\n `MATCH (d:${quoteIdentifier(graph.resources.labels.document)})-[:${quoteIdentifier(\"ANVIA_HAS_CHUNK\")}]->(c:${quoteIdentifier(graph.resources.labels.chunk)})\nWHERE c.${quoteIdentifier(\"__anvia_id\")} IN $chunkIds\n ${tenantNodeAndPredicate(graph, \"d\")}${tenantNodeAndPredicate(graph, \"c\")}\nRETURN c.${quoteIdentifier(\"__anvia_id\")} AS chunkId,\n d.${quoteIdentifier(\"__anvia_id\")} AS documentId,\n c.${quoteIdentifier(\"__anvia_index\")} AS index,\n c.${quoteIdentifier(\"__anvia_text\")} AS text,\n properties(c) AS properties`,\n managedQueryParameters(graph, { chunkIds }),\n abortSignal,\n );\n const byId = new Map<string, Neo4jGraphEvidence>();\n for (const record of result.records) {\n const evidence = evidenceFromRecord(record);\n if (byId.has(evidence.chunkId)) {\n throw new TypeError(`Neo4j evidence returned duplicate chunk ${evidence.chunkId}.`);\n }\n byId.set(evidence.chunkId, evidence);\n }\n return chunkIds.map((chunkId) => {\n const evidence = byId.get(chunkId);\n if (evidence === undefined) {\n throw new Error(`Neo4j graph evidence references missing chunk ${chunkId}.`);\n }\n return evidence;\n });\n}\n\nfunction evidenceFromRecord(record: Neo4jRecord): Neo4jGraphEvidence {\n const chunkId = stringValue(record.get(\"chunkId\"), \"Neo4j evidence chunk id\");\n const documentId = stringValue(record.get(\"documentId\"), \"Neo4j evidence document id\");\n const index = safeIntegerValue(record.get(\"index\"), \"Neo4j evidence chunk index\");\n const text = stringValue(record.get(\"text\"), \"Neo4j evidence text\");\n const raw = record.get(\"properties\");\n if (typeof raw !== \"object\" || raw === null || Array.isArray(raw)) {\n throw new TypeError(\"Neo4j evidence properties must be an object.\");\n }\n return {\n chunkId,\n documentId,\n index,\n text,\n metadata: applicationProperties(raw as Record<string, unknown>, \"Neo4j evidence metadata\"),\n };\n}\n\nfunction safeIntegerValue(value: unknown, label: string): number {\n let number = value;\n if (isInt(value)) {\n number = undefined;\n if (value.inSafeRange()) {\n number = value.toNumber();\n }\n }\n if (typeof number !== \"number\" || !Number.isSafeInteger(number)) {\n throw new TypeError(`${label} must be a safe integer.`);\n }\n return number;\n}\n\nfunction vectorResults(\n results: SearchHit[],\n topK: number,\n minScore: number | undefined,\n): SearchHit[] {\n return results.filter((item) => minScore === undefined || item.score >= minScore).slice(0, topK);\n}\n\nasync function traverse<Schema extends Neo4jGraphSchema>(\n graph: Neo4jKnowledgeGraphBase<Schema>,\n seeds: readonly SearchHit[],\n options: RetrieveGraphContextOptions<Schema>[\"traversal\"],\n abortSignal?: AbortSignal,\n): Promise<{ nodes: Neo4jGraphContextNode[]; relationships: Neo4jGraphContextRelationship[] }> {\n const traversalSeedIds = new Set(\n seeds.filter((seed) => seed.entryRelationshipType === undefined).map((seed) => seed.elementId),\n );\n const entryGroups = groupBy(\n seeds.filter(\n (seed): seed is SearchHit & { entryRelationshipType: string } =>\n seed.entryRelationshipType !== undefined,\n ),\n (seed) => seed.entryRelationshipType,\n );\n for (const [relationshipType, group] of entryGroups) {\n const entries = await graph.query(\n `MATCH (seed) WHERE elementId(seed) IN $seedIds\n ${tenantNodePredicate(graph, \"seed\", \"AND\")}\nMATCH (seed)-[entryRelationship:${quoteIdentifier(relationshipType)}]->(entry)\nWHERE true${managedNodeAndPredicate(graph, \"entry\")}${tenantNodeAndPredicate(graph, \"entryRelationship\")}\nRETURN DISTINCT elementId(entry) AS elementId`,\n managedQueryParameters(graph, { seedIds: group.map((seed) => seed.elementId) }),\n abortSignal,\n );\n for (const record of entries.records) {\n traversalSeedIds.add(stringValue(record.get(\"elementId\"), \"Neo4j entry elementId\"));\n }\n }\n if (traversalSeedIds.size === 0) return { nodes: [], relationships: [] };\n const limitedSeedIds = [...traversalSeedIds].slice(0, options.maxNodes);\n const pattern = traversalPattern(options.direction, options.maxDepth);\n const pathLimit = Math.max(options.maxNodes, options.maxRelationships);\n const seedNodes = await graph.query(\n `MATCH (node) WHERE elementId(node) IN $seedIds\n ${managedNodePredicate(graph, \"node\", \"AND\")}\nRETURN {elementId: elementId(node), labels: labels(node), properties: properties(node)} AS node`,\n managedQueryParameters(graph, { seedIds: limitedSeedIds }),\n abortSignal,\n );\n const result = await graph.query(\n `MATCH (seed) WHERE elementId(seed) IN $seedIds\n ${managedNodePredicate(graph, \"seed\", \"AND\")}\nMATCH path = ${pattern}\nWHERE all(rel IN relationships(path) WHERE type(rel) IN $relationshipTypes${managedRelationshipAndPredicate(graph, \"rel\")})${managedPathAndPredicate(graph)}\nRETURN [item IN nodes(path) | {elementId: elementId(item), labels: labels(item), properties: properties(item)}] AS nodes,\n [item IN relationships(path) | {elementId: elementId(item), type: type(item), properties: properties(item), from: elementId(startNode(item)), to: elementId(endNode(item))}] AS relationships\nLIMIT $pathLimit`,\n managedQueryParameters(graph, {\n seedIds: limitedSeedIds,\n relationshipTypes: options.relationships,\n pathLimit: int(pathLimit),\n }),\n abortSignal,\n );\n const nodes = new Map<string, Neo4jGraphContextNode>();\n const nodeKeysByElementId = new Map<string, string>();\n const relationships = new Map<string, Neo4jGraphContextRelationship>();\n const seedNodesByElementId = new Map<string, Record<string, unknown>>();\n for (const record of seedNodes.records) {\n const value = record.get(\"node\");\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) {\n throw new TypeError(\"Neo4j traversal returned a malformed seed node.\");\n }\n const map = value as Record<string, unknown>;\n seedNodesByElementId.set(stringValue(map.elementId, \"Neo4j seed node elementId\"), map);\n }\n const addNode = (value: Record<string, unknown>) => {\n const parsed = contextNode(value, graph.schema);\n const existing = nodes.get(parsed.node.key);\n if (existing === undefined && nodes.size >= options.maxNodes) return;\n if (existing === undefined) nodes.set(parsed.node.key, parsed.node);\n nodeKeysByElementId.set(parsed.elementId, parsed.node.key);\n };\n for (const elementId of limitedSeedIds) {\n const value = seedNodesByElementId.get(elementId);\n if (value !== undefined) addNode(value);\n }\n for (const record of result.records) {\n for (const value of listOfMaps(record.get(\"nodes\"), \"Neo4j traversal nodes\")) {\n addNode(value);\n }\n }\n for (const record of result.records) {\n for (const value of listOfMaps(record.get(\"relationships\"), \"Neo4j traversal relationships\")) {\n const relationship = contextRelationship(value, nodeKeysByElementId);\n if (\n relationship !== undefined &&\n !relationships.has(relationship.key) &&\n relationships.size < options.maxRelationships\n ) {\n relationships.set(relationship.key, relationship);\n }\n }\n }\n return { nodes: [...nodes.values()], relationships: [...relationships.values()] };\n}\n\nfunction traversalPattern(direction: \"outgoing\" | \"incoming\" | \"both\", maxDepth: number): string {\n if (direction === \"outgoing\") {\n return `(seed)-[*1..${maxDepth}]->(node)`;\n }\n if (direction === \"incoming\") {\n return `(seed)<-[*1..${maxDepth}]-(node)`;\n }\n return `(seed)-[*1..${maxDepth}]-(node)`;\n}\n\nfunction managedQueryParameters(\n graph: Neo4jKnowledgeGraphBase,\n parameters: Record<string, unknown>,\n): Record<string, unknown> {\n return managedScopeParameters(managedScope(graph), parameters);\n}\n\nfunction managedNodePredicate(\n graph: Neo4jKnowledgeGraphBase,\n variable: string,\n prefix: \"WHERE\" | \"AND\",\n): string {\n return managedScopePredicate(managedScope(graph), variable, prefix);\n}\n\nfunction managedSearchPredicate(\n graph: Neo4jKnowledgeGraphBase,\n variable: string,\n chunkSeed: boolean,\n): string {\n return chunkSeed && graph.namespace === undefined\n ? \"\"\n : managedNodePredicate(graph, variable, \"WHERE\");\n}\n\nfunction managedNodeAndPredicate(graph: Neo4jKnowledgeGraphBase, variable: string): string {\n return managedScopePredicate(managedScope(graph), variable, \" AND\");\n}\n\nfunction managedRelationshipAndPredicate(graph: Neo4jKnowledgeGraphBase, variable: string): string {\n return managedNodeAndPredicate(graph, variable);\n}\n\nfunction tenantNodePredicate(\n graph: Neo4jKnowledgeGraphBase,\n variable: string,\n prefix: \"WHERE\" | \"AND\",\n): string {\n const scope = managedScope(graph);\n return scope === undefined ? \"\" : tenantScopePredicate(scope, variable, prefix);\n}\n\nfunction tenantNodeAndPredicate(graph: Neo4jKnowledgeGraphBase, variable: string): string {\n const predicate = tenantNodePredicate(graph, variable, \"AND\");\n return predicate.length === 0 ? \"\" : ` ${predicate}`;\n}\n\nfunction managedPathAndPredicate(graph: Neo4jKnowledgeGraphBase): string {\n return managedPathPredicate(managedScope(graph), false);\n}\n\nfunction managedScope(graph: Neo4jKnowledgeGraphBase): Neo4jManagedScope | undefined {\n return graph instanceof ManagedNeo4jKnowledgeGraph\n ? { graph: graph.name, namespace: graph.namespace }\n : undefined;\n}\n\nfunction contextNode(\n value: Record<string, unknown>,\n schema: Neo4jGraphSchema,\n): { elementId: string; node: Neo4jGraphContextNode } {\n const labels = value.labels;\n const raw = value.properties;\n if (!Array.isArray(labels) || !labels.every((label) => typeof label === \"string\")) {\n throw new TypeError(\"Neo4j traversal returned malformed node labels.\");\n }\n if (typeof raw !== \"object\" || raw === null || Array.isArray(raw)) {\n throw new TypeError(\"Neo4j traversal returned malformed node properties.\");\n }\n const properties = applicationProperties(raw as Record<string, unknown>, \"Neo4j graph node\");\n const type = labels.find((label) => label in schema.nodes) ?? labels[0] ?? \"Node\";\n const definition = schema.nodes[type];\n const identity: Record<string, string | number | boolean> = {};\n if (definition !== undefined) {\n for (const property of definition.identity) {\n const item = properties[property];\n if (typeof item === \"string\" || typeof item === \"number\" || typeof item === \"boolean\") {\n identity[property] = item;\n }\n }\n }\n const elementId = stringValue(value.elementId, \"Neo4j node elementId\");\n return {\n elementId,\n node: {\n key: stringProperty(raw as Record<string, unknown>, \"__anvia_key\") ?? elementId,\n type,\n identity,\n properties,\n sourceChunkIds: stringArrayProperty(\n raw as Record<string, unknown>,\n \"__anvia_source_chunk_ids\",\n ),\n },\n };\n}\n\nfunction contextRelationship(\n value: Record<string, unknown>,\n nodeKeysByElementId: ReadonlyMap<string, string>,\n): Neo4jGraphContextRelationship | undefined {\n const raw = value.properties;\n if (typeof raw !== \"object\" || raw === null || Array.isArray(raw)) {\n throw new TypeError(\"Neo4j traversal returned malformed relationship properties.\");\n }\n const elementId = stringValue(value.elementId, \"Neo4j relationship elementId\");\n const fromElementId = stringValue(value.from, \"Neo4j relationship source\");\n const toElementId = stringValue(value.to, \"Neo4j relationship target\");\n const from = nodeKeysByElementId.get(fromElementId);\n const to = nodeKeysByElementId.get(toElementId);\n if (from === undefined || to === undefined) return undefined;\n return {\n key: stringProperty(raw as Record<string, unknown>, \"__anvia_key\") ?? elementId,\n type: stringValue(value.type, \"Neo4j relationship type\"),\n from,\n to,\n properties: applicationProperties(raw as Record<string, unknown>, \"Neo4j graph relationship\"),\n sourceChunkIds: stringArrayProperty(raw as Record<string, unknown>, \"__anvia_source_chunk_ids\"),\n };\n}\n\nfunction fuseResults(lists: readonly SearchHit[][], topK: number, rrfK: number): SearchHit[] {\n const fused = new Map<string, SearchHit>();\n for (const list of lists) {\n list.forEach((item, index) => {\n const score = 1 / (rrfK + index + 1);\n const current = fused.get(item.elementId);\n fused.set(item.elementId, { ...item, score: (current?.score ?? 0) + score });\n });\n }\n return [...fused.values()].sort((left, right) => right.score - left.score).slice(0, topK);\n}\n\nfunction validateSearch(search: RetrieveGraphContextOptions<Neo4jGraphSchema>[\"search\"]): void {\n positiveInteger(search.topK, \"Neo4j graph search topK\");\n if (search.seeds.length === 0 || new Set(search.seeds).size !== search.seeds.length) {\n throw new TypeError(\"Neo4j graph search requires unique seed names.\");\n }\n if (search.type === \"vector\") {\n if (search.seeds.length !== 1)\n throw new TypeError(\n \"Vector graph search accepts exactly one seed; use hybrid search to fuse multiple seeds.\",\n );\n finiteScore(search.minScore, \"Neo4j graph search minScore\");\n } else {\n positiveInteger(search.candidatesPerSeed, \"Neo4j hybrid candidatesPerSeed\");\n positiveInteger(search.rrfK, \"Neo4j hybrid rrfK\");\n }\n}\n\nfunction validateEvidence(\n capability: \"none\" | \"chunks\",\n evidence: Neo4jGraphEvidenceOptions,\n): void {\n if (typeof evidence !== \"object\" || evidence === null) {\n throw new TypeError(\"Neo4j graph retrieval requires an explicit evidence mode.\");\n }\n if (evidence.type === \"none\") return;\n if (evidence.type !== \"chunks\") {\n throw new TypeError(\"Unknown Neo4j graph evidence mode.\");\n }\n positiveInteger(evidence.maxChunks, \"Neo4j graph evidence maxChunks\");\n if (capability !== \"chunks\") {\n throw new TypeError(\"Chunk evidence requires a managed Neo4j knowledge graph.\");\n }\n}\n\nfunction validateTraversal(\n schema: Neo4jGraphSchema,\n traversal: RetrieveGraphContextOptions<Neo4jGraphSchema>[\"traversal\"],\n): void {\n if (\n traversal.direction !== \"outgoing\" &&\n traversal.direction !== \"incoming\" &&\n traversal.direction !== \"both\"\n ) {\n throw new TypeError(\"Neo4j traversal direction must be outgoing, incoming, or both.\");\n }\n positiveInteger(traversal.maxDepth, \"Neo4j traversal maxDepth\", 8);\n positiveInteger(traversal.maxNodes, \"Neo4j traversal maxNodes\");\n positiveInteger(traversal.maxRelationships, \"Neo4j traversal maxRelationships\");\n if (\n traversal.relationships.length === 0 ||\n new Set(traversal.relationships).size !== traversal.relationships.length\n ) {\n throw new TypeError(\"Neo4j traversal requires unique relationship types.\");\n }\n for (const type of traversal.relationships) {\n if (!(type in schema.relationships))\n throw new TypeError(`Neo4j traversal references unknown relationship type ${type}.`);\n }\n}\n\nfunction applicationProperties(value: Record<string, unknown>, label: string) {\n return strictProperties(\n Object.fromEntries(Object.entries(value).filter(([key]) => !key.startsWith(\"__anvia_\"))),\n label,\n );\n}\n\nfunction stringProperty(value: Record<string, unknown>, property: string): string | undefined {\n const item = value[property];\n if (item === undefined) return undefined;\n return stringValue(item, `Neo4j property ${property}`);\n}\n\nfunction stringArrayProperty(value: Record<string, unknown>, property: string): string[] {\n const item = value[property];\n if (item === undefined) return [];\n if (!Array.isArray(item) || !item.every((entry) => typeof entry === \"string\")) {\n throw new TypeError(`Neo4j property ${property} must be a string array.`);\n }\n return [...item];\n}\n\nfunction stringValue(value: unknown, label: string): string {\n if (typeof value !== \"string\") throw new TypeError(`${label} must be a string.`);\n return value;\n}\n\nfunction listOfMaps(value: unknown, label: string): Record<string, unknown>[] {\n if (\n !Array.isArray(value) ||\n !value.every((item) => typeof item === \"object\" && item !== null && !Array.isArray(item))\n ) {\n throw new TypeError(`${label} must be an array of objects.`);\n }\n return value as Record<string, unknown>[];\n}\n\nfunction escapeLucene(value: string): string {\n const specialCharacters = new Set('+-&|!(){}[]^\"~*?:\\\\/');\n let escaped = \"\";\n for (const character of value) {\n escaped += specialCharacters.has(character) ? `\\\\${character}` : character;\n }\n return escaped;\n}\n\nfunction scopedFulltextQuery(graph: Neo4jKnowledgeGraphBase, value: string): string {\n const query = escapeLucene(value);\n return graph instanceof ManagedNeo4jKnowledgeGraph && graph.namespace !== undefined\n ? `(${query}) AND __anvia_namespace:${escapeLucene(graph.namespace)}`\n : query;\n}\n\nfunction groupBy<Value, Key>(\n values: readonly Value[],\n keyFor: (value: Value) => Key,\n): Map<Key, Value[]> {\n const groups = new Map<Key, Value[]>();\n for (const value of values) {\n const key = keyFor(value);\n const group = groups.get(key);\n if (group === undefined) groups.set(key, [value]);\n else group.push(value);\n }\n return groups;\n}\n"],"mappings":"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","names":[]}
|