fix(server): wire PageIndex strategy + answer endpoints into the DEPLOYED cmd/server binary#26
Conversation
The deployed cmd/server binary's buildStrategy only knew single-pass, chunked-tree, and agentic — so retrieval.strategy=pageindex silently fell through to chunked-tree, leaving the page-based strategy unreachable in production even though cmd/engine already supported it. Thread the DB pool through buildStrategy and port buildPageIndexStrategy from cmd/engine, wiring the storage-backed PageLoader plus a DB-backed TOC provider that reads documents.toc_tree (degrading to the synthesised view when the column is NULL).
Add an optional "strategy" field to the /v1/query body so a caller can A/B retrieval strategies (e.g. chunked-tree vs pageindex) against the SAME running engine without a redeploy — exactly what the benchmark needs. Strategies are pre-built once at boot into a name-keyed map, so per-request selection is a map lookup, not a rebuild on the hot path. An absent or empty field uses the configured default, keeping every existing caller unchanged. An unknown name returns 400 rather than silently falling back. A test seam (treeLoader) lets the handler run end-to-end without a live Postgres backend.
…d router Both answer endpoints existed only on the standalone cmd/engine binary (internal/api), so they were unreachable on the deployed cmd/server binary (internal/handler) that production runs. Port them, adapting the standalone single-tenant org to the deployed server's multi-tenant model (org + store resolved from the X-Vectorless-Org / X-Vectorless-Store headers). - /v1/answer runs retrieval + per-section answer-span extraction + a synthesis LLM call, returning a quote-grounded answer with citations. - /v1/answer/pageindex runs the PageIndex agentic loop end-to-end (structure -> get_pages -> done), with an opt-in reasoning trace and an SSE streaming variant. Its per-request strategy copy gets an org-scoped TOC provider so get_document_structure reads only the requesting tenant's documents.toc_tree. Extend handler.Deps with the LLM client, default model, answer-span / answer config, the replay store, and the dedicated PageIndex strategy, and wire them at boot in cmd/server. Replay capture is shared with the existing /v1/replay endpoint via byte-identical response storage.
Add a parity test that walks the mounted chi router and fails if /v1/answer or /v1/answer/pageindex (or the /v1/query mount) is missing. The deployed cmd/server and standalone cmd/engine binaries serve overlapping APIs from two separate routers and have silently diverged before — this is the regression that left the PageIndex answer endpoints unreachable in production. The guard makes any future drop of a required route fail loudly instead of shipping a half-wired binary.
|
Caution Review failedPull request was closed or merged during review 📝 WalkthroughWalkthroughThe PR introduces POST ChangesAnswer Generation with Strategy Overrides
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
The gap
Production deploys
cmd/server(built fromDockerfile.server), which serves its API frominternal/handler/router.go. But this cycle's redesign work — thepageindexretrieval strategy and the/v1/answer+/v1/answer/pageindexendpoints — landed only on the OTHER binary,cmd/engine(internal/api), which does not deploy. The redesign was therefore unreachable in production:cmd/server::buildStrategyknew onlysingle-pass | chunked-tree | agentic, soretrieval.strategy=pageindexsilently fell through tochunked-tree.internal/handler/router.gomounted no/v1/answeror/v1/answer/pageindexroutes at all.This PR makes all of it reachable on the deployed binary, adapting the standalone (single-tenant, nil-UUID org) implementations to
cmd/server's multi-tenant model (org + store resolved fromX-Vectorless-Org/X-Vectorless-Store).What's now reachable in production
pageindexas a selection strategy —buildStrategygains thepageindexcase.buildPageIndexStrategyis ported fromcmd/engine, wiring the storage-backedPageLoaderplus a DB-backed TOC provider that readsdocuments.toc_tree(degrading to the synthesised view when the column is NULL). The DB pool is threaded throughbuildStrategy.POST /v1/answer— retrieval + per-section answer-span extraction + a synthesis LLM call → a quote-grounded answer with citations.POST /v1/answer/pageindex— the PageIndex agentic loop end-to-end (structure → get_pages → done), with an opt-inreasoningtrace and an SSEstream=truevariant. Its per-request strategy copy gets an org-scoped TOC provider soget_document_structurereads only the requesting tenant'sdocuments.toc_tree.Per-request strategy override on
/v1/query/v1/queryaccepts an optional"strategy"field. When present it selects from a name-keyed map of strategies pre-built once at boot (chunked-tree,pageindex,agentic,single-pass), so selection is a map lookup, not a hot-path rebuild. Absent/empty → the configured default (every existing caller unchanged); unknown name → 400. This lets the benchmark A/Bchunked-treevspageindexagainst the same running engine with no redeploy.Divergence guard
router_parity_test.gowalks the mounted chi router and fails if/v1/answer,/v1/answer/pageindex, or the/v1/querymount goes missing — so the two binaries can't silently diverge like this again.handler.Deps additions
Strategies(override map),LLM,LLMModel,AnswerSpan,Answer,Replay,PageIndexStrategy,PageIndex— all wired at boot incmd/server. Replay capture is shared with the existing/v1/replayendpoint via byte-identical response storage.Test plan
go build ./...clean (bothcmd/serverandcmd/engine)go vet ./...cleango test ./...all green/v1/querywith{"strategy":"pageindex"}routes to the page-based strategy (and the default/unknown/nil-set paths)Default
retrieval.strategyis left atchunked-tree; the bench drivespageindexper-request via the override. Does not touchpkg/ingest/orpkg/parser/.Summary by CodeRabbit