@@ -25,6 +25,7 @@ export interface TraversalOptions {
2525 summaryOnly ?: boolean ;
2626 title ?: string ;
2727 snippetLength ?: number ;
28+ useWeightedTraversal ?: boolean ;
2829}
2930
3031interface Connection {
@@ -38,7 +39,11 @@ export class TraversalHandler {
3839
3940 constructor ( private neo4jService : Neo4jService ) { }
4041
41- async traverseFromNode ( nodeId : string , options : TraversalOptions = { } ) : Promise < TraversalResult > {
42+ async traverseFromNode (
43+ nodeId : string ,
44+ embedding : number [ ] ,
45+ options : TraversalOptions = { } ,
46+ ) : Promise < TraversalResult > {
4247 const {
4348 maxDepth = DEFAULTS . traversalDepth ,
4449 skip = DEFAULTS . skipOffset ,
@@ -50,6 +55,7 @@ export class TraversalHandler {
5055 summaryOnly = false ,
5156 title = `Node Traversal from: ${ nodeId } ` ,
5257 snippetLength = DEFAULTS . codeSnippetLength ,
58+ useWeightedTraversal = false ,
5359 } = options ;
5460
5561 try {
@@ -60,7 +66,18 @@ export class TraversalHandler {
6066 return createErrorResponse ( `Node with ID "${ nodeId } " not found.` ) ;
6167 }
6268
63- const traversalData = await this . performTraversal ( nodeId , maxDepth , skip , direction , relationshipTypes ) ;
69+ const maxNodesPerDepth = Math . ceil ( maxNodesPerChain * 1.5 ) ;
70+ const traversalData = useWeightedTraversal
71+ ? await this . performTraversalByDepth (
72+ nodeId ,
73+ embedding ,
74+ maxDepth ,
75+ maxNodesPerDepth ,
76+ direction ,
77+ relationshipTypes ,
78+ )
79+ : await this . performTraversal ( nodeId , embedding , maxDepth , skip , direction , relationshipTypes ) ;
80+
6481 if ( ! traversalData ) {
6582 return createSuccessResponse ( `No connections found for node "${ nodeId } ".` ) ;
6683 }
@@ -100,6 +117,7 @@ export class TraversalHandler {
100117
101118 private async performTraversal (
102119 nodeId : string ,
120+ embedding : number [ ] ,
103121 maxDepth : number ,
104122 skip : number ,
105123 direction : 'OUTGOING' | 'INCOMING' | 'BOTH' = 'BOTH' ,
@@ -124,6 +142,98 @@ export class TraversalHandler {
124142 } ;
125143 }
126144
145+ private async performTraversalByDepth (
146+ nodeId : string ,
147+ embedding : number [ ] ,
148+ maxDepth : number ,
149+ maxNodesPerDepth : number ,
150+ direction : 'OUTGOING' | 'INCOMING' | 'BOTH' = 'BOTH' ,
151+ relationshipTypes ?: string [ ] ,
152+ ) {
153+ // Track visited nodes to avoid cycles
154+ const visitedNodeIds = new Set < string > ( [ nodeId ] ) ;
155+
156+ // Track the path (chain of relationships) to reach each node
157+ // Key: nodeId, Value: array of relationships from start node to this node
158+ const pathsToNode = new Map < string , any [ ] > ( ) ;
159+ pathsToNode . set ( nodeId , [ ] ) ; // Start node has empty path
160+
161+ // Track which nodes to explore at each depth
162+ let currentSourceIds = [ nodeId ] ;
163+
164+ // Result accumulators
165+ const allConnections : Connection [ ] = [ ] ;
166+ const nodeMap = new Map < string , Neo4jNode > ( ) ; // Dedupe nodes
167+
168+ for ( let depth = 1 ; depth <= maxDepth ; depth ++ ) {
169+ if ( currentSourceIds . length === 0 ) {
170+ console . log ( `No source nodes to explore at depth ${ depth } ` ) ;
171+ break ;
172+ }
173+
174+ const traversalResults = await this . neo4jService . run ( QUERIES . EXPLORE_DEPTH_LEVEL ( direction , maxNodesPerDepth ) , {
175+ sourceNodeIds : currentSourceIds ,
176+ visitedNodeIds : Array . from ( visitedNodeIds ) ,
177+ currentDepth : parseInt ( depth . toString ( ) ) ,
178+ queryEmbedding : embedding ,
179+ depthDecay : 0.85 ,
180+ } ) ;
181+
182+ if ( traversalResults . length === 0 ) {
183+ console . log ( `No connections found at depth ${ depth } ` ) ;
184+ break ;
185+ }
186+
187+ // Collect node IDs for next depth exploration
188+ const nextSourceIds : string [ ] = [ ] ;
189+
190+ for ( const row of traversalResults ) {
191+ const { node, relationship, sourceNodeId, scoring } = row . result ;
192+ const neighborId = node . id ;
193+
194+ // Skip if already visited (safety check)
195+ if ( visitedNodeIds . has ( neighborId ) ) continue ;
196+
197+ // Mark as visited
198+ visitedNodeIds . add ( neighborId ) ;
199+ nextSourceIds . push ( neighborId ) ;
200+
201+ // Build the relationship chain:
202+ // This node's chain = parent's chain + this relationship
203+ const parentPath = pathsToNode . get ( sourceNodeId ) ?? [ ] ;
204+ const thisPath = [
205+ ...parentPath ,
206+ {
207+ type : relationship . type ,
208+ start : relationship . startNodeId ,
209+ end : relationship . endNodeId ,
210+ properties : relationship . properties ,
211+ score : scoring . combinedScore ,
212+ } ,
213+ ] ;
214+ pathsToNode . set ( neighborId , thisPath ) ;
215+
216+ // Create connection with full relationship chain
217+ const connection : Connection = {
218+ depth,
219+ node : node as Neo4jNode ,
220+ relationshipChain : thisPath ,
221+ } ;
222+ allConnections . push ( connection ) ;
223+
224+ // Accumulate unique nodes
225+ nodeMap . set ( neighborId , node as Neo4jNode ) ;
226+ }
227+
228+ // Move to next depth with the newly discovered nodes
229+ currentSourceIds = nextSourceIds ;
230+ }
231+
232+ return {
233+ connections : allConnections ,
234+ } ;
235+ }
236+
127237 private groupConnectionsByDepth ( connections : Connection [ ] ) : Record < number , Connection [ ] > {
128238 return connections . reduce (
129239 ( acc , conn ) => {
@@ -160,7 +270,7 @@ export class TraversalHandler {
160270
161271 private formatTraversalJSON (
162272 startNode : Neo4jNode ,
163- traversalData : { connections : Connection [ ] ; graph : any } ,
273+ traversalData : { connections : Connection [ ] ; graph ? : any } ,
164274 title : string ,
165275 includeStartNodeDetails : boolean ,
166276 includeCode : boolean ,
@@ -203,7 +313,7 @@ export class TraversalHandler {
203313
204314 private formatSummaryOnlyJSON (
205315 startNode : Neo4jNode ,
206- traversalData : { connections : Connection [ ] ; graph : any } ,
316+ traversalData : { connections : Connection [ ] ; graph ? : any } ,
207317 title : string ,
208318 ) : any {
209319 const byDepth = this . groupConnectionsByDepth ( traversalData . connections ) ;
0 commit comments