@@ -82,6 +82,13 @@ async def run(self) -> WorkerOutput:
8282 pass
8383 logger .info ("Worker starting: doc=%s max_rounds=%d" , doc_name , max_rounds )
8484
85+ # Phase 0.5: try intent routes for direct jump
86+ intent_hint = ""
87+ try :
88+ intent_hint = await self ._build_intent_hint (doc , query )
89+ except Exception :
90+ pass
91+
8592 try :
8693 children = await doc .ls ()
8794 if children :
@@ -104,9 +111,15 @@ async def run(self) -> WorkerOutput:
104111 except Exception :
105112 pass
106113
114+ combined_hints = ""
115+ if intent_hint :
116+ combined_hints += intent_hint
107117 if keyword_hints :
108- logger .info ("Phase 1.5: keyword hints available, generating plan" )
109- await self ._generate_plan (doc , query , task , state , keyword_hints , llm )
118+ combined_hints += keyword_hints
119+
120+ if combined_hints :
121+ logger .info ("Phase 1.5: hints available, generating plan" )
122+ await self ._generate_plan (doc , query , task , state , combined_hints , llm )
110123 if state .plan :
111124 logger .info ("Phase 1.5: plan generated — %s" , state .plan [:150 ])
112125
@@ -142,7 +155,7 @@ async def run(self) -> WorkerOutput:
142155 visited_titles = visited_titles ,
143156 plan = state .plan ,
144157 intent_context = intent_context ,
145- keyword_hints = keyword_hints ,
158+ keyword_hints = combined_hints ,
146159 shared_context = shared_context ,
147160 ))
148161
@@ -172,7 +185,7 @@ async def run(self) -> WorkerOutput:
172185 f'"{ raw_preview } "\n \n '
173186 f"Please output exactly one command "
174187 f"(ls, cd, cat, head, find, grep, toc, stats, similar, overview, "
175- f"siblings, ancestors, doc_card, concepts, find_section, "
188+ f"siblings, ancestors, doc_card, concepts, find_section, chain, "
176189 f"compare, trace, summarize, wc, pwd, check, or done)."
177190 )
178191 state .push_history ("(unrecognized) \u2192 parse failure" )
@@ -239,6 +252,39 @@ async def run(self) -> WorkerOutput:
239252
240253 return state .into_worker_output (doc_name )
241254
255+ async def _build_intent_hint (self , doc : NavigableDocument , query : str ) -> str :
256+ """Build navigation hints from pre-computed intent routes.
257+
258+ If the query routing table has routes for this document's structure,
259+ we can suggest direct jumps instead of root-level exploration.
260+ """
261+ try :
262+ routes = await doc .intent_routes ()
263+ except Exception :
264+ return ""
265+
266+ if not routes :
267+ return ""
268+
269+ lines = ["Intent routes (pre-computed shortcuts — use cd to jump directly):" ]
270+ for route in routes [:5 ]:
271+ targets = getattr (route , "targets" , [])
272+ if not targets :
273+ continue
274+ for target in targets [:3 ]:
275+ title = await doc .node_title (target .node_id )
276+ relevance = getattr (target , "relevance" , 0.0 )
277+ reason = getattr (target , "reason" , "" )
278+ lines .append (
279+ f" - { title } (relevance { relevance :.2f} : { reason } )"
280+ )
281+
282+ if len (lines ) == 1 :
283+ return ""
284+
285+ logger .info ("Intent routes: %d routes found" , len (routes ))
286+ return "\n " .join (lines ) + "\n "
287+
242288 async def _build_keyword_hints (self , doc : NavigableDocument , query : str ) -> str :
243289 """Build keyword hints from the document's reasoning index and acceleration data."""
244290 keywords = extract_keywords (query )
@@ -276,15 +322,23 @@ async def _build_keyword_hints(self, doc: NavigableDocument, query: str) -> str:
276322 pass
277323
278324 # Top evidence scores (pre-computed by ScorePass)
325+ # Filter to nodes whose titles overlap with query keywords for relevance
279326 score_hints = []
280327 try :
281328 scores = await doc .evidence_scores_ranked ()
282- for s in scores [:5 ]:
329+ kw_lower = {kw .lower () for kw in keywords }
330+ for s in scores [:20 ]:
283331 title = await doc .node_title (s .node_id )
284- score_hints .append (
285- f" - { title } (score { s .composite :.2f} : "
286- f"density={ s .density :.2f} richness={ s .data_richness :.2f} )"
287- )
332+ title_lower = title .lower ()
333+ # Include if title contains any query keyword or is top-3 by score
334+ is_keyword_match = any (kw in title_lower for kw in kw_lower )
335+ if is_keyword_match or len (score_hints ) < 3 :
336+ score_hints .append (
337+ f" - { title } (score { s .composite :.2f} : "
338+ f"density={ s .density :.2f} richness={ s .data_richness :.2f} )"
339+ )
340+ if len (score_hints ) >= 8 :
341+ break
288342 except Exception :
289343 pass
290344
0 commit comments