Skip to content

Commit fec6fc8

Browse files
committed
Rebased, solved conflicts
1 parent ac96399 commit fec6fc8

7 files changed

Lines changed: 58 additions & 131 deletions

File tree

src/app/endpoints/streaming_query.py

Lines changed: 6 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@
5656
UnauthorizedResponse,
5757
UnprocessableEntityResponse,
5858
)
59-
from utils.types import ReferencedDocument
6059
from utils.endpoints import (
6160
check_configuration_loaded,
6261
validate_and_retrieve_conversation,
@@ -186,29 +185,10 @@ async def streaming_query_endpoint_handler( # pylint: disable=too-many-locals
186185

187186
client = AsyncLlamaStackClientHolder().get_client()
188187

189-
<<<<<<< HEAD
190-
<<<<<<< HEAD
191-
_, _, doc_ids_from_chunks, pre_rag_chunks = await perform_vector_search(
192-
client, query_request.query, query_request.solr
193-
)
194-
195-
rag_context = format_rag_context_for_injection(pre_rag_chunks)
196-
if rag_context:
197-
=======
198-
# Build RAG context from BYOK and Solr sources
199-
rag_context = await build_rag_context(client, query_request, configuration)
200-
201-
# Inject RAG context into query
202-
if rag_context.context_text:
203-
# Mutate a local copy to avoid surprising other logic
204-
>>>>>>> 2ace88f7 (Add chunk prioritization and always RAG support)
205-
query_request = query_request.model_copy(deep=True)
206-
query_request.query = query_request.query + rag_context.context_text
207-
=======
208188
# Build RAG context from Inline RAG sources
209-
inline_rag_context = await build_rag_context(client, query_request, configuration)
210-
>>>>>>> a4075c6d (Address review: rename always RAG to inline RAG, Solr config to OKP, fix query mutation)
211-
189+
inline_rag_context = await build_rag_context(
190+
client, query_request.query, query_request.vector_store_ids, query_request.solr
191+
)
212192
# Prepare API request parameters
213193
responses_params = await prepare_responses_params(
214194
client=client,
@@ -291,15 +271,7 @@ async def retrieve_response_generator(
291271
Args:
292272
responses_params: The Responses API parameters
293273
context: The response generator context
294-
<<<<<<< HEAD
295-
<<<<<<< HEAD
296-
doc_ids_from_chunks: List of ReferencedDocument objects extracted from static RAG
297-
=======
298-
pre_rag_documents: Referenced documents from pre-query RAG (BYOK + Solr)
299-
>>>>>>> 2ace88f7 (Add chunk prioritization and always RAG support)
300-
=======
301-
inline_rag_documents: Referenced documents from pre-query RAG (BYOK + Solr)
302-
>>>>>>> a4075c6d (Address review: rename always RAG to inline RAG, Solr config to OKP, fix query mutation)
274+
inline_rag_documents: Referenced documents from inline RAG (BYOK + Solr)
303275
304276
Returns:
305277
tuple[AsyncIterator[str], TurnSummary]: The response generator and turn summary
@@ -771,25 +743,10 @@ async def response_generator( # pylint: disable=too-many-branches,too-many-stat
771743
rag_id_mapping=context.rag_id_mapping,
772744
)
773745

774-
<<<<<<< HEAD
746+
# Merge pre-RAG documents with tool-based documents and deduplicate
775747
turn_summary.referenced_documents = deduplicate_referenced_documents(
776-
tool_based_documents + turn_summary.pre_rag_documents
748+
turn_summary.inline_rag_documents + tool_based_documents
777749
)
778-
=======
779-
# Merge pre-RAG documents with tool-based documents (similar to query.py)
780-
if turn_summary.inline_rag_documents:
781-
all_documents = turn_summary.inline_rag_documents + tool_based_documents
782-
seen = set()
783-
deduplicated_documents = []
784-
for doc in all_documents:
785-
key = (doc.doc_url, doc.doc_title)
786-
if key not in seen:
787-
seen.add(key)
788-
deduplicated_documents.append(doc)
789-
turn_summary.referenced_documents = deduplicated_documents
790-
else:
791-
turn_summary.referenced_documents = tool_based_documents
792-
>>>>>>> a4075c6d (Address review: rename always RAG to inline RAG, Solr config to OKP, fix query mutation)
793750

794751

795752
def stream_http_error_event(

src/configuration.py

Lines changed: 0 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -427,63 +427,6 @@ def inline_solr_enabled(self) -> bool:
427427
raise LogicError("logic error: configuration is not loaded")
428428
return constants.OKP_RAG_ID in self._configuration.rag.inline
429429

430-
@property
431-
def inline_byok_vector_store_ids(self) -> list[str]:
432-
"""Return vector store IDs for the BYOK sources listed in rag.inline.
433-
434-
Maps non-okp rag_ids in rag.inline to their corresponding vector_db_ids
435-
from the byok_rag configuration. IDs that are not found in byok_rag are
436-
silently skipped.
437-
438-
Returns:
439-
list[str]: Ordered list of vector_db_ids for inline BYOK RAG.
440-
441-
Raises:
442-
LogicError: If the configuration has not been loaded.
443-
"""
444-
if self._configuration is None:
445-
raise LogicError("logic error: configuration is not loaded")
446-
inline_ids = [
447-
rid for rid in self._configuration.rag.inline if rid != constants.OKP_RAG_ID
448-
]
449-
rag_to_vdb = {
450-
brag.rag_id: brag.vector_db_id for brag in self._configuration.byok_rag
451-
}
452-
return [rag_to_vdb[rid] for rid in inline_ids if rid in rag_to_vdb]
453-
454-
@property
455-
def tool_vector_store_ids(self) -> Optional[list[str]]:
456-
"""Return vector store IDs for tool RAG, or None to use all registered stores.
457-
458-
When rag.tool is None (default), returns None to signal that all
459-
registered vector stores should be used (backward compatibility).
460-
461-
When rag.tool is an explicit list, maps rag_ids to vector_db_ids and
462-
includes the OKP vector store ID for the special 'okp-rag' entry.
463-
464-
Returns:
465-
Optional[list[str]]: List of vector_db_ids for tool RAG, or None
466-
when all registered stores should be used.
467-
468-
Raises:
469-
LogicError: If the configuration has not been loaded.
470-
"""
471-
if self._configuration is None:
472-
raise LogicError("logic error: configuration is not loaded")
473-
tool_ids = self._configuration.rag.tool
474-
if tool_ids is None:
475-
return None
476-
rag_to_vdb = {
477-
brag.rag_id: brag.vector_db_id for brag in self._configuration.byok_rag
478-
}
479-
result = []
480-
for rid in tool_ids:
481-
if rid == constants.OKP_RAG_ID:
482-
result.append(constants.SOLR_DEFAULT_VECTOR_STORE_ID)
483-
elif rid in rag_to_vdb:
484-
result.append(rag_to_vdb[rid])
485-
return result
486-
487430
def resolve_index_name(
488431
self, vector_store_id: str, rag_id_mapping: Optional[dict[str, str]] = None
489432
) -> str:

src/utils/responses.py

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -167,14 +167,19 @@ async def prepare_tools( # pylint: disable=too-many-arguments,too-many-position
167167
return None
168168

169169
toolgroups: list[InputTool] = []
170-
# Per-request vector_store_ids override takes priority.
171-
# When not provided, use config-based tool list (or None = all stores).
172-
effective_ids = (
173-
vector_store_ids
174-
if vector_store_ids is not None
175-
else configuration.tool_vector_store_ids
176-
)
177-
effective_ids = await get_vector_store_ids(client, effective_ids)
170+
171+
# Priority: per-request IDs > rag.tool config > all registered stores.
172+
# In all cases, customer-facing rag_ids are translated to internal vector_db_ids.
173+
# IDs fetched from llama-stack are already internal and need no translation.
174+
byok_rags = configuration.configuration.byok_rag
175+
if vector_store_ids is not None:
176+
effective_ids: list[str] = resolve_vector_store_ids(vector_store_ids, byok_rags)
177+
elif configuration.configuration.rag.tool is not None:
178+
effective_ids = resolve_vector_store_ids(
179+
configuration.configuration.rag.tool, byok_rags
180+
)
181+
else:
182+
effective_ids = await get_vector_store_ids(client, None)
178183

179184
# Add RAG tools if vector stores are available
180185
rag_tools = get_rag_tools(effective_ids)
@@ -350,10 +355,11 @@ def extract_vector_store_ids_from_tools(
350355
def resolve_vector_store_ids(
351356
vector_store_ids: list[str], byok_rags: list[ByokRag]
352357
) -> list[str]:
353-
"""Translate customer-facing BYOK rag_ids to llama-stack vector_db_ids.
358+
"""Translate customer-facing rag_ids to llama-stack vector_db_ids.
354359
355360
Each ID is looked up against the BYOK RAG configuration. If a matching
356361
``rag_id`` is found, the corresponding ``vector_db_id`` is returned.
362+
The special ``okp-rag`` ID is mapped to the Solr vector store ID.
357363
Otherwise the ID is passed through unchanged (assumed to already be a
358364
llama-stack vector store ID).
359365
@@ -366,6 +372,9 @@ def resolve_vector_store_ids(
366372
List of llama-stack vector_db_ids ready for the Llama Stack API.
367373
"""
368374
rag_id_to_vector_db_id = {brag.rag_id: brag.vector_db_id for brag in byok_rags}
375+
rag_id_to_vector_db_id[constants.OKP_RAG_ID] = (
376+
constants.SOLR_DEFAULT_VECTOR_STORE_ID
377+
)
369378
return [rag_id_to_vector_db_id.get(vs_id, vs_id) for vs_id in vector_store_ids]
370379

371380

src/utils/vector_search.py

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
from configuration import configuration
1717
from log import get_logger
1818
from models.responses import ReferencedDocument
19+
from utils.responses import resolve_vector_store_ids
1920
from utils.types import RAGChunk, RAGContext
2021

2122
logger = get_logger(__name__)
@@ -45,10 +46,10 @@ def _build_query_params(solr: Optional[dict[str, Any]] = None) -> dict[str, Any]
4546
"mode": constants.SOLR_VECTOR_SEARCH_DEFAULT_MODE,
4647
}
4748
logger.debug("Initial params: %s", params)
48-
logger.debug("query_request.solr: %s", query_request.solr)
49+
logger.debug("query_request.solr: %s", solr)
4950

50-
if query_request.solr:
51-
params["solr"] = query_request.solr
51+
if solr:
52+
params["solr"] = solr
5253
logger.debug("Final params with solr filters: %s", params)
5354
else:
5455
logger.debug("No solr filters provided")
@@ -316,7 +317,6 @@ def _process_solr_chunks_for_documents(
316317
async def _fetch_byok_rag(
317318
client: AsyncLlamaStackClient,
318319
query: str,
319-
configuration: AppConfig,
320320
vector_store_ids: Optional[list[str]] = None,
321321
) -> tuple[list[RAGChunk], list[ReferencedDocument]]:
322322
"""Fetch chunks and documents from BYOK RAG sources.
@@ -347,7 +347,14 @@ async def _fetch_byok_rag(
347347
if vs_id != constants.SOLR_DEFAULT_VECTOR_STORE_ID
348348
]
349349
else:
350-
vector_store_ids_to_query = configuration.inline_byok_vector_store_ids
350+
inline_rag_ids = [
351+
rid
352+
for rid in configuration.configuration.rag.inline
353+
if rid != constants.OKP_RAG_ID
354+
]
355+
vector_store_ids_to_query = resolve_vector_store_ids(
356+
inline_rag_ids, configuration.configuration.byok_rag
357+
)
351358

352359
# If inline byok stores are not defined, we disable the inline RAG for backward compatibility
353360
if not vector_store_ids_to_query:
@@ -410,8 +417,8 @@ async def _fetch_byok_rag(
410417

411418
async def _fetch_solr_rag(
412419
client: AsyncLlamaStackClient,
413-
query_request: QueryRequest,
414-
configuration: AppConfig,
420+
query: str,
421+
solr: Optional[dict[str, Any]] = None,
415422
) -> tuple[list[RAGChunk], list[ReferencedDocument]]:
416423
"""Fetch chunks and documents from Solr RAG source.
417424
@@ -486,8 +493,9 @@ async def _fetch_solr_rag(
486493

487494
async def build_rag_context(
488495
client: AsyncLlamaStackClient,
489-
query_request: QueryRequest,
490-
configuration: AppConfig,
496+
query: str,
497+
vector_store_ids: Optional[list[str]],
498+
solr: Optional[dict[str, Any]] = None,
491499
) -> RAGContext:
492500
"""Build RAG context by fetching and merging chunks from all enabled sources.
493501
@@ -512,7 +520,7 @@ async def build_rag_context(
512520
# Merge chunks from all sources (BYOK + Solr)
513521
context_chunks = byok_chunks + solr_chunks
514522

515-
context_text = _format_rag_context(context_chunks, query_request.query)
523+
context_text = _format_rag_context(context_chunks, query)
516524

517525
logger.debug(
518526
"Inline RAG context built: %d chunks, %d characters",

tests/unit/models/config/test_byok_rag.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ def test_byok_rag_configuration_default_values() -> None:
2828
assert byok_rag.embedding_model == DEFAULT_EMBEDDING_MODEL
2929
assert byok_rag.embedding_dimension == DEFAULT_EMBEDDING_DIMENSION
3030
assert byok_rag.vector_db_id == "vector_db_id"
31-
assert byok_rag.db_path == Path("tests/configuration/rag.txt")
31+
assert byok_rag.db_path == "tests/configuration/rag.txt"
3232
assert byok_rag.score_multiplier == DEFAULT_SCORE_MULTIPLIER
3333

3434

tests/unit/utils/test_responses.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
from pytest_mock import MockerFixture
2525

2626
import constants
27-
from configuration import AppConfig
2827
from models.config import ByokRag, ModelContextProtocolServer
2928
from models.requests import QueryRequest
3029
from utils.responses import (
@@ -1122,6 +1121,7 @@ async def test_does_not_translate_when_ids_fetched_from_llama_stack(
11221121
mock_byok_rag.vector_db_id = "vs-translated"
11231122
mock_config = mocker.Mock()
11241123
mock_config.configuration.byok_rag = [mock_byok_rag]
1124+
mock_config.configuration.rag.tool = None
11251125
mocker.patch("utils.responses.configuration", mock_config)
11261126

11271127
result = await prepare_tools(mock_client, None, False, "token")

tests/unit/utils/test_vector_search.py

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,8 @@ class TestFetchByokRag:
351351
async def test_byok_no_inline_ids(self, mocker) -> None: # type: ignore[no-untyped-def]
352352
"""Test when no inline BYOK sources are configured."""
353353
config_mock = mocker.Mock(spec=AppConfig)
354-
config_mock.inline_byok_vector_store_ids = []
354+
config_mock.configuration.rag.inline = []
355+
config_mock.configuration.byok_rag = []
355356
mocker.patch("utils.vector_search.configuration", config_mock)
356357

357358
client_mock = mocker.AsyncMock()
@@ -366,7 +367,11 @@ async def test_byok_enabled_success(self, mocker) -> None: # type: ignore[no-un
366367
"""Test successful BYOK RAG fetch when inline IDs are configured."""
367368
# Mock configuration
368369
config_mock = mocker.Mock(spec=AppConfig)
369-
config_mock.inline_byok_vector_store_ids = ["vs_1"]
370+
byok_rag_mock = mocker.Mock()
371+
byok_rag_mock.rag_id = "rag_1"
372+
byok_rag_mock.vector_db_id = "vs_1"
373+
config_mock.configuration.rag.inline = ["rag_1"]
374+
config_mock.configuration.byok_rag = [byok_rag_mock]
370375
config_mock.score_multiplier_mapping = {"vs_1": 1.5}
371376
config_mock.rag_id_mapping = {"vs_1": "rag_1"}
372377
mocker.patch("utils.vector_search.configuration", config_mock)
@@ -451,7 +456,8 @@ class TestBuildRagContext:
451456
async def test_both_sources_disabled(self, mocker) -> None: # type: ignore[no-untyped-def]
452457
"""Test when both BYOK inline and Solr inline are not configured."""
453458
config_mock = mocker.Mock(spec=AppConfig)
454-
config_mock.inline_byok_vector_store_ids = []
459+
config_mock.configuration.rag.inline = []
460+
config_mock.configuration.byok_rag = []
455461
config_mock.inline_solr_enabled = False
456462
mocker.patch("utils.vector_search.configuration", config_mock)
457463

@@ -467,7 +473,11 @@ async def test_byok_enabled_only(self, mocker) -> None: # type: ignore[no-untyp
467473
"""Test when only inline BYOK is configured."""
468474
# Mock configuration
469475
config_mock = mocker.Mock(spec=AppConfig)
470-
config_mock.inline_byok_vector_store_ids = ["vs_1"]
476+
byok_rag_mock = mocker.Mock()
477+
byok_rag_mock.rag_id = "rag_1"
478+
byok_rag_mock.vector_db_id = "vs_1"
479+
config_mock.configuration.rag.inline = ["rag_1"]
480+
config_mock.configuration.byok_rag = [byok_rag_mock]
471481
config_mock.inline_solr_enabled = False
472482
config_mock.score_multiplier_mapping = {"vs_1": 1.0}
473483
config_mock.rag_id_mapping = {"vs_1": "rag_1"}

0 commit comments

Comments
 (0)