feat(bindings): expose BM25, RRF and vector-store knobs on RAG query options (#1019)
What
#1017 wired vector_store, bm25_k1, bm25_b and rrf_k through commons, but no binding could set them. This adds them to the per-query retrieval options and threads them into the generated RAGRetrievalOptions:
- Swift (source of truth):
RagQueryOptions.bm25K1 / bm25B / rrfK / vectorStore(+RagVectorStore.usearch), mapped inRagSession.queryOptions. - Kotlin:
RagRetrievalOptions.bm25K1 / bm25B / rrfK / vectorStore(+RagVectorStore), mapped inragQueryProto. - Web:
RagRetrievalOptions.bm25K1 / bm25B / rrfK / vectorStore, passed throughnormalizeQueryOptionsandmakeRAGQuery. - Python:
RagRetrievalOptions.bm25_k1 / bm25_b / rrf_k / vector_store(+RagVectorStore), serialized in_rag_bridge.build_query.
Unset values keep the session defaults; range validation (b in [0, 1], finite k1, rrf_k >= 0) lives in commons (#1017), not duplicated per SDK. Only the in-process store is exposed, since PGVECTOR has no on-device path.
Tests
- Kotlin:
RagSearchRequestMappingTest.queryProtoCarriesBm25RrfAndVectorStoreOverrides - Python:
test_query_threads_bm25_rrf_and_vector_store_into_the_proto
Not verified locally
I did not run these: the Swift/Kotlin toolchains aren't available on this Windows box, the Python tests need the generated _pb/_generated_errors modules, and the locally generated proto-ts predates #1017's rag.proto fields, so the Web typecheck needs a regenerate to pass. CI should be the first real check of all four.
Stacking
Stacked on #1017 (the proto fields it reads are not on main yet), so the diff includes that PR's commits until it merges.
Closes #1019
Summary by cubic
Exposes BM25, RRF, and vector-store knobs on per-query RAG retrieval options in the Swift, Kotlin, Web, and Python bindings, threading them into the generated RAGRetrievalOptions so sessions can tune scoring without changing config.
RagRetrievalOptions(Kotlin/Web/Python) andRagQueryOptions(Swift) now acceptbm25K1,bm25B,rrfK, andvectorStore(bm25_k1/bm25_b/rrf_k/vector_storein Python); unset values keep session defaults.- Range and presence validation lives in commons:
k1must be finite and>= 0,bin[0, 1],rrf_k >= 0, andVECTOR_STORE_PGVECTORis rejected on-device since only the in-process USearch store is supported. - The bindings reject out-of-range knobs up front: Swift narrows
rrfK/retrievalTopKviaInt32(exactly:)and throws, Python checksrrf_kfits int32 andvector_storeis aRagVectorStore, and Web throws on anyvectorStoreother than'usearch'. - The
retrieveoperator strictly parses these params (full-string consumption, classic locale, finite floats) and rejects malformed values, unknown vector stores,k < 1, and thresholds outside their ranges instead of silently falling back to defaults. - RRF now accumulates in double and breaks ties on id so a large
rrf_kcannot tie unrelated candidates, and converter-format float params use the classic locale withmax_digits10to round-trip exactly.
Summary by CodeRabbit
- New Features
- RAG queries can override BM25 ranking settings and reciprocal-rank-fusion tuning; omitted values use session defaults.
- Select the on-device USEARCH vector store in Kotlin, Python, Swift, and web APIs.
- Configure BM25 and reciprocal-rank-fusion defaults at the session level.
- Bug Fixes
- Equal-scoring retrieval results now have a consistent order.
- Compatibility
- PGVECTOR selection is not supported for on-device RAG sessions or queries.
- Validation
- Invalid retrieval tuning values and unsupported vector-store selections are rejected.