feat(bindings): expose BM25, RRF and vector-store knobs on RAG query options (#1019)

AD
3d ago
+793-52

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 in RagSession.queryOptions.
  • Kotlin: RagRetrievalOptions.bm25K1 / bm25B / rrfK / vectorStore (+ RagVectorStore), mapped in ragQueryProto.
  • Web: RagRetrievalOptions.bm25K1 / bm25B / rrfK / vectorStore, passed through normalizeQueryOptions and makeRAGQuery.
  • 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) and RagQueryOptions (Swift) now accept bm25K1, bm25B, rrfK, and vectorStore (bm25_k1/bm25_b/rrf_k/vector_store in Python); unset values keep session defaults.
  • Range and presence validation lives in commons: k1 must be finite and >= 0, b in [0, 1], rrf_k >= 0, and VECTOR_STORE_PGVECTOR is rejected on-device since only the in-process USearch store is supported.
  • The bindings reject out-of-range knobs up front: Swift narrows rrfK/retrievalTopK via Int32(exactly:) and throws, Python checks rrf_k fits int32 and vector_store is a RagVectorStore, and Web throws on any vectorStore other than 'usearch'.
  • The retrieve operator 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_k cannot tie unrelated candidates, and converter-format float params use the classic locale with max_digits10 to 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.