Commit ae4a23a
committed
feat(api): /v1/answer/pageindex endpoint with reasoning + streaming
Wire the PageIndex strategy through a dedicated answer endpoint
on the existing /v1 router. The endpoint:
- Owns the full RAG round-trip in one request: retrieval +
answer + citations come back from a single agentic loop.
No separate synthesis call — the model emits its answer
inside the done action and we surface it as `answer` on
the response.
- Emits page-grounded citations. One citation per page range
the agent fetched (deduplicated), each carrying
start_page / end_page / section_ids plus an answer-span
quote pulled via the existing SpanExtractor over the cited
content. Falls back gracefully when the LLM declines a
quote.
- Persists every successful response to the existing replay
store under the strategy's deterministic trace_token. The
token's input set is sorted cited page ranges (not section
IDs), and the strategy name is folded into the hash so
page-based and section-based tokens for the same doc/model
never collide.
- Supports an opt-in reasoning trace (body field
`reasoning:true` or query param `?reasoning=true`) that
surfaces per-hop tool calls + args + tool-result chars +
sections touched, captured via a new OnEvent hook on
PageIndexStrategy.
- Streams via Server-Sent Events when `stream:true` is set
on the body. One event per tool call (get_document_structure,
get_pages, done) so callers WATCH the navigation in real
time, terminated by an `answer` event carrying the full
JSON response payload.
- Honors per-request overrides for max_hops and
max_pages_per_fetch without mutating shared Deps. Disabled
deployments (retrieval.pageindex.enabled=false or no LLM
client) return 501; missing documents 404; bad bodies 400.
Adds `RetrievalConfig.PageIndex` (PageIndexBlock) with defaults
(Enabled=true, MaxHops=8, PageContentLimit=16000) and matching
VLE_RETRIEVAL_PAGEINDEX_* env overrides. Validation rejects
negative knobs and accepts "pageindex" as a retrieval strategy.
cmd/engine/main.go registers the strategy via buildStrategy
when retrieval.strategy=pageindex, AND wires a standalone
PageIndexStrategy instance into the api.Deps used by the
answer endpoint — so the endpoint is available regardless of
which selection strategy the deployment runs by default.
Test coverage: 12 end-to-end handler tests (happy path,
reasoning trace via body field + query param, bad request,
not found, disabled in two modes, no LLM, replay persistence
verifying byte-equal response bytes, SSE event stream shape,
per-request override caps the loop, TOC fallback). Plus 5
config tests for defaults + env overrides + validation.
A PageIndexTreeLoader function field on Deps acts as a test
seam so handler tests can run end-to-end via httptest with
an in-memory tree, without a real Postgres backend.1 parent a7cab8d commit ae4a23a
7 files changed
Lines changed: 1425 additions & 20 deletions
File tree
- cmd/engine
- internal/api
- pkg
- config
- retrieval
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
196 | 196 | | |
197 | 197 | | |
198 | 198 | | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
199 | 214 | | |
200 | | - | |
201 | | - | |
202 | | - | |
203 | | - | |
204 | | - | |
205 | | - | |
206 | | - | |
207 | | - | |
208 | | - | |
209 | | - | |
210 | | - | |
211 | | - | |
212 | | - | |
213 | | - | |
214 | | - | |
215 | | - | |
216 | | - | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
217 | 234 | | |
218 | 235 | | |
219 | 236 | | |
| |||
365 | 382 | | |
366 | 383 | | |
367 | 384 | | |
| 385 | + | |
| 386 | + | |
368 | 387 | | |
369 | 388 | | |
370 | 389 | | |
371 | 390 | | |
372 | 391 | | |
| 392 | + | |
| 393 | + | |
| 394 | + | |
| 395 | + | |
| 396 | + | |
| 397 | + | |
| 398 | + | |
| 399 | + | |
| 400 | + | |
| 401 | + | |
| 402 | + | |
| 403 | + | |
| 404 | + | |
| 405 | + | |
| 406 | + | |
| 407 | + | |
| 408 | + | |
| 409 | + | |
| 410 | + | |
| 411 | + | |
| 412 | + | |
| 413 | + | |
| 414 | + | |
373 | 415 | | |
374 | 416 | | |
375 | 417 | | |
| |||
385 | 427 | | |
386 | 428 | | |
387 | 429 | | |
| 430 | + | |
| 431 | + | |
| 432 | + | |
| 433 | + | |
| 434 | + | |
| 435 | + | |
| 436 | + | |
| 437 | + | |
| 438 | + | |
| 439 | + | |
| 440 | + | |
| 441 | + | |
| 442 | + | |
| 443 | + | |
| 444 | + | |
| 445 | + | |
| 446 | + | |
388 | 447 | | |
389 | 448 | | |
390 | 449 | | |
| |||
0 commit comments