Initial curated RAGcore source from c16667f0c9397e2bfc8dd0255b114fba23c8d05e
This commit is contained in:
commit
7ca726caf2
659 files changed
+98171
No files matched your search
@@ -0,0 +1,526 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
from types import SimpleNamespace
|
||||
from uuid import uuid4
|
||||
|
||||
import httpx
|
||||
import pytest
|
||||
from opentelemetry.sdk.metrics import MeterProvider
|
||||
from opentelemetry.sdk.metrics.export import InMemoryMetricReader
|
||||
from opentelemetry.sdk.resources import Resource
|
||||
from qdrant_client.http import models
|
||||
|
||||
from ragcore.api.v1.context.service import ContextExecutionRequest, ContextQuery
|
||||
from ragcore.api.v1.search.service import SearchExecutionRequest, SearchFilterData, SearchQuery
|
||||
from ragcore.application.models.selection import ResolvedEmbeddingSelection
|
||||
from ragcore.application.retrieval.authorization import AuthorizedRetrievalScope
|
||||
from ragcore.config import Settings
|
||||
from ragcore.domain.authorization import Principal, PrincipalType
|
||||
from ragcore.domain.control import DataPolicy
|
||||
from ragcore.domain.models import EmbeddingProfile, EmbeddingProvider, EmbeddingSelection
|
||||
from ragcore.infrastructure.models.embedding_factory import create_embedding_adapter_factory
|
||||
from ragcore.infrastructure.models.persistence import JsonEmbeddingProfileStore
|
||||
from ragcore.infrastructure.retrieval.production_executor import (
|
||||
PostgresDocumentTitleLookup,
|
||||
ProductionContextExecutor,
|
||||
ProductionSearchExecutor,
|
||||
RetrievalPipeline,
|
||||
)
|
||||
from ragcore.platform.telemetry import TelemetryMetrics
|
||||
|
||||
WORKSPACE_ID = uuid4()
|
||||
SPACE_ID = uuid4()
|
||||
DOCUMENT_ID = uuid4()
|
||||
DOCUMENT_VERSION_ID = uuid4()
|
||||
CHUNK_ID = uuid4()
|
||||
SOURCE_ID = uuid4()
|
||||
|
||||
EMBEDDING_PROFILE = EmbeddingProfile(
|
||||
id=uuid4(),
|
||||
profile="hybrid",
|
||||
version="v1",
|
||||
provider=EmbeddingProvider.OLLAMA,
|
||||
model_identifier="nomic-embed-text:v1",
|
||||
model_digest="0" * 64,
|
||||
dimensions=2,
|
||||
context_limit=2048,
|
||||
tokenizer="cl100k",
|
||||
data_policy=DataPolicy.LOCAL_ONLY,
|
||||
)
|
||||
|
||||
_PAYLOAD = {
|
||||
"workspace_id": str(WORKSPACE_ID),
|
||||
"space_id": str(SPACE_ID),
|
||||
"document_id": str(DOCUMENT_ID),
|
||||
"document_version_id": str(DOCUMENT_VERSION_ID),
|
||||
"chunk_id": str(CHUNK_ID),
|
||||
"source_id": str(SOURCE_ID),
|
||||
"parent_chunk_id": None,
|
||||
"status": "published",
|
||||
"content_type": "text/plain",
|
||||
"language": "en",
|
||||
"trust_level": "source",
|
||||
"embedding_model_digest": EMBEDDING_PROFILE.model_digest,
|
||||
"chunk_profile_version": EMBEDDING_PROFILE.version,
|
||||
"text": "The runbook says to restart the payment service after a failover.",
|
||||
"location": {"page": 1},
|
||||
}
|
||||
|
||||
|
||||
class FakeQdrantClient:
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
alias_target: str = "rag_dense_hybrid_v1",
|
||||
payload: dict[str, object] = _PAYLOAD,
|
||||
) -> None:
|
||||
self.alias_target = alias_target
|
||||
self.payload = payload
|
||||
self.query_collections: list[str] = []
|
||||
|
||||
async def get_aliases(self, **kwargs: object) -> SimpleNamespace:
|
||||
return SimpleNamespace(
|
||||
aliases=[
|
||||
SimpleNamespace(
|
||||
alias_name="rag_dense_hybrid_active", collection_name=self.alias_target
|
||||
)
|
||||
]
|
||||
)
|
||||
|
||||
async def get_collection(self, collection_name: str, **kwargs: object) -> SimpleNamespace:
|
||||
return SimpleNamespace(
|
||||
config=SimpleNamespace(
|
||||
params=SimpleNamespace(
|
||||
vectors={"dense": models.VectorParams(size=2, distance=models.Distance.COSINE)},
|
||||
sparse_vectors={"sparse": models.SparseVectorParams()},
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
async def query_points(self, **kwargs: object) -> models.QueryResponse:
|
||||
self.query_collections.append(str(kwargs.get("collection_name")))
|
||||
return models.QueryResponse(
|
||||
points=[
|
||||
models.ScoredPoint(id=str(CHUNK_ID), version=0, score=0.9, payload=self.payload)
|
||||
]
|
||||
)
|
||||
|
||||
async def retrieve(self, **kwargs: object) -> list[SimpleNamespace]:
|
||||
ids = kwargs.get("ids", [])
|
||||
return [SimpleNamespace(id=raw_id, payload=self.payload) for raw_id in ids]
|
||||
|
||||
|
||||
class PayloadlessQdrantClient(FakeQdrantClient):
|
||||
"""Ranks a point and then does not return its payload.
|
||||
|
||||
Qdrant answered the search with this point, so it is in the index -- but
|
||||
the follow-up ``retrieve`` gives nothing back for it. The pipeline cannot
|
||||
build a citation without the text, so the hit is dropped; the point of
|
||||
this double is that the caller must be *told* that happened.
|
||||
"""
|
||||
|
||||
async def retrieve(self, **kwargs: object) -> list[SimpleNamespace]:
|
||||
return []
|
||||
|
||||
|
||||
class FakeTitleLookup:
|
||||
def __init__(self, titles: dict | None = None) -> None: # type: ignore[type-arg]
|
||||
self._titles = {DOCUMENT_ID: "Restart Runbook"} if titles is None else titles
|
||||
|
||||
async def titles(self, document_ids: set) -> dict: # type: ignore[type-arg]
|
||||
return {doc_id: self._titles[doc_id] for doc_id in document_ids if doc_id in self._titles}
|
||||
|
||||
|
||||
def _embed_transport(vector: tuple = (0.1, 0.2)) -> httpx.MockTransport: # type: ignore[type-arg]
|
||||
def handler(request: httpx.Request) -> httpx.Response:
|
||||
return httpx.Response(200, json={"embeddings": [list(vector)]})
|
||||
|
||||
return httpx.MockTransport(handler)
|
||||
|
||||
|
||||
def _failing_transport(status_code: int = 503) -> httpx.MockTransport:
|
||||
def handler(request: httpx.Request) -> httpx.Response:
|
||||
return httpx.Response(status_code, json={"error": "unavailable"})
|
||||
|
||||
return httpx.MockTransport(handler)
|
||||
|
||||
|
||||
def _empty_store() -> JsonEmbeddingProfileStore:
|
||||
path = Path(tempfile.mkdtemp()) / "profiles.json"
|
||||
return JsonEmbeddingProfileStore(path)
|
||||
|
||||
|
||||
async def _activated_store() -> JsonEmbeddingProfileStore:
|
||||
store = _empty_store()
|
||||
await store.add(EMBEDDING_PROFILE)
|
||||
await store.activate(EMBEDDING_PROFILE.id)
|
||||
return store
|
||||
|
||||
|
||||
async def _activated_store_for(profile: EmbeddingProfile) -> JsonEmbeddingProfileStore:
|
||||
store = _empty_store()
|
||||
await store.add(profile)
|
||||
await store.activate(profile.id)
|
||||
return store
|
||||
|
||||
|
||||
class FixedSelectionResolver:
|
||||
def __init__(self, profile: EmbeddingProfile, *, route: str) -> None:
|
||||
self.selected = ResolvedEmbeddingSelection(
|
||||
generation=8,
|
||||
profile=profile,
|
||||
selection=EmbeddingSelection.from_profile(profile, experiment_route_key=route),
|
||||
)
|
||||
|
||||
async def resolve_active(self) -> ResolvedEmbeddingSelection:
|
||||
return self.selected
|
||||
|
||||
|
||||
def _pipeline(
|
||||
*,
|
||||
embedding_transport: httpx.MockTransport,
|
||||
store,
|
||||
metrics: TelemetryMetrics | None = None,
|
||||
) -> RetrievalPipeline:
|
||||
client = httpx.AsyncClient(transport=embedding_transport, follow_redirects=False)
|
||||
return RetrievalPipeline(
|
||||
qdrant_client=FakeQdrantClient(), # type: ignore[arg-type]
|
||||
embedding_profile_store=store,
|
||||
embedding_adapter_factory=create_embedding_adapter_factory(
|
||||
settings=Settings(env="test", ollama_url="http://localhost:11434"),
|
||||
http_client=client,
|
||||
),
|
||||
metrics=metrics,
|
||||
)
|
||||
|
||||
|
||||
def _scope() -> AuthorizedRetrievalScope:
|
||||
return AuthorizedRetrievalScope(WORKSPACE_ID, frozenset({SPACE_ID}))
|
||||
|
||||
|
||||
def _search_request(query: str = "how do I restart the payment service") -> SearchExecutionRequest:
|
||||
return SearchExecutionRequest(
|
||||
principal=Principal(uuid4(), WORKSPACE_ID, PrincipalType.HUMAN, frozenset()),
|
||||
query=SearchQuery(query=query, max_results=5, filters=SearchFilterData()),
|
||||
scope=_scope(),
|
||||
retrieval_run_id=uuid4(),
|
||||
)
|
||||
|
||||
|
||||
def _context_request(
|
||||
query: str = "how do I restart the payment service",
|
||||
) -> ContextExecutionRequest:
|
||||
return ContextExecutionRequest(
|
||||
principal=Principal(uuid4(), WORKSPACE_ID, PrincipalType.HUMAN, frozenset()),
|
||||
query=ContextQuery(
|
||||
query=SearchQuery(query=query, max_results=5, filters=SearchFilterData()),
|
||||
max_context_tokens=4000,
|
||||
),
|
||||
scope=_scope(),
|
||||
retrieval_run_id=uuid4(),
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_pipeline_degrades_when_no_active_embedding_profile() -> None:
|
||||
pipeline = _pipeline(embedding_transport=_embed_transport(), store=_empty_store())
|
||||
result = await pipeline.run(
|
||||
query_text="restart payment",
|
||||
content_types=(),
|
||||
languages=(),
|
||||
scope=_scope(),
|
||||
max_results=5,
|
||||
profile="hybrid-v1",
|
||||
retrieval_run_id=uuid4(),
|
||||
)
|
||||
assert result.hits == ()
|
||||
assert "no_active_embedding_profile" in result.degradation_codes
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_pipeline_records_retrieval_duration_and_zero_result() -> None:
|
||||
reader = InMemoryMetricReader()
|
||||
provider = MeterProvider(
|
||||
resource=Resource.create({"service.name": "test"}), metric_readers=[reader]
|
||||
)
|
||||
metrics = TelemetryMetrics(meter_provider=provider)
|
||||
pipeline = _pipeline(
|
||||
embedding_transport=_embed_transport(), store=_empty_store(), metrics=metrics
|
||||
)
|
||||
|
||||
await pipeline.run(
|
||||
query_text="restart payment",
|
||||
content_types=(),
|
||||
languages=(),
|
||||
scope=_scope(),
|
||||
max_results=5,
|
||||
profile="hybrid-v1",
|
||||
retrieval_run_id=uuid4(),
|
||||
)
|
||||
|
||||
data = reader.get_metrics_data()
|
||||
assert data is not None
|
||||
names = {
|
||||
metric.name
|
||||
for resource_metric in data.resource_metrics
|
||||
for scope_metric in resource_metric.scope_metrics
|
||||
for metric in scope_metric.metrics
|
||||
}
|
||||
assert "ragcore_retrieval_duration_seconds" in names
|
||||
assert "ragcore_retrieval_zero_result_total" in names
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_pipeline_degrades_when_embedding_provider_unavailable() -> None:
|
||||
pipeline = _pipeline(embedding_transport=_failing_transport(), store=await _activated_store())
|
||||
result = await pipeline.run(
|
||||
query_text="restart payment",
|
||||
content_types=(),
|
||||
languages=(),
|
||||
scope=_scope(),
|
||||
max_results=5,
|
||||
profile="hybrid-v1",
|
||||
retrieval_run_id=uuid4(),
|
||||
)
|
||||
assert result.hits == ()
|
||||
assert "embedding_provider_unavailable" in result.degradation_codes
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_search_executor_happy_path_returns_titled_hit_with_fused_candidate() -> None:
|
||||
"""M8-01: no reranking -- the fused RRF ranking is the ranking, not a
|
||||
degraded fallback, so this must not report degraded and rerank_score is
|
||||
always None (kept as a field for response-shape compatibility)."""
|
||||
|
||||
pipeline = _pipeline(embedding_transport=_embed_transport(), store=await _activated_store())
|
||||
executor = ProductionSearchExecutor(pipeline, FakeTitleLookup()) # type: ignore[arg-type]
|
||||
result = await executor.execute(_search_request())
|
||||
|
||||
assert result.degraded is False
|
||||
assert len(result.hits) == 1
|
||||
hit = result.hits[0]
|
||||
assert hit.title == "Restart Runbook"
|
||||
assert "restart the payment service" in hit.text
|
||||
assert hit.citation.document_id == DOCUMENT_ID
|
||||
assert hit.citation.workspace_id == WORKSPACE_ID
|
||||
assert hit.fused.candidate.provenance.chunk_id == CHUNK_ID
|
||||
assert hit.rerank_score is None
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_search_executor_falls_back_to_untitled_when_title_missing() -> None:
|
||||
pipeline = _pipeline(embedding_transport=_embed_transport(), store=await _activated_store())
|
||||
executor = ProductionSearchExecutor(pipeline, FakeTitleLookup(titles={})) # type: ignore[arg-type]
|
||||
result = await executor.execute(_search_request())
|
||||
assert result.hits[0].title == "Untitled document"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_context_executor_happy_path_returns_context_candidate() -> None:
|
||||
pipeline = _pipeline(embedding_transport=_embed_transport(), store=await _activated_store())
|
||||
executor = ProductionContextExecutor(pipeline, FakeQdrantClient()) # type: ignore[arg-type]
|
||||
result = await executor.execute(_context_request())
|
||||
|
||||
assert result.degraded is False
|
||||
assert len(result.candidates) == 1
|
||||
assert "restart the payment service" in result.candidates[0].text
|
||||
assert result.candidates[0].citation.document_id == DOCUMENT_ID
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_context_executor_returns_empty_tuple_when_degraded() -> None:
|
||||
pipeline = _pipeline(embedding_transport=_embed_transport(), store=_empty_store())
|
||||
executor = ProductionContextExecutor(pipeline, FakeQdrantClient()) # type: ignore[arg-type]
|
||||
result = await executor.execute(_context_request())
|
||||
assert result.candidates == ()
|
||||
assert result.degraded is True
|
||||
assert "no_active_embedding_profile" in result.degradation_codes
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_rest_search_uses_durable_route_and_collection_selection(
|
||||
tmp_path: Path,
|
||||
) -> None:
|
||||
profile = EmbeddingProfile(
|
||||
id=uuid4(),
|
||||
profile="hybrid",
|
||||
version="v1",
|
||||
provider=EmbeddingProvider.MODELFORGE,
|
||||
model_identifier="rag.embedding@1",
|
||||
model_digest="c" * 64,
|
||||
dimensions=2,
|
||||
context_limit=8192,
|
||||
tokenizer="capability-managed",
|
||||
data_policy=DataPolicy.LOCAL_ONLY,
|
||||
embedding_space_id=uuid4(),
|
||||
)
|
||||
credential_file = tmp_path / "credential"
|
||||
credential_file.write_text("mf_" + "x" * 48, encoding="utf-8")
|
||||
credential_file.chmod(0o600)
|
||||
seen: list[httpx.Request] = []
|
||||
|
||||
def respond(request: httpx.Request) -> httpx.Response:
|
||||
seen.append(request)
|
||||
return httpx.Response(
|
||||
200,
|
||||
json={
|
||||
"capability": "rag.embedding@1",
|
||||
"dimension": profile.dimensions,
|
||||
"normalized": True,
|
||||
"embedding_space_id": str(profile.embedding_space_id),
|
||||
"data": [[1.0, 0.0]],
|
||||
"request_id": str(uuid4()),
|
||||
},
|
||||
)
|
||||
|
||||
settings = Settings(
|
||||
env="test",
|
||||
ollama_url="http://localhost:11434",
|
||||
modelforge_base_url="http://modelforge:8000",
|
||||
modelforge_credential_file=credential_file,
|
||||
modelforge_embedding_experiment_route="stale-global-route",
|
||||
)
|
||||
payload = {
|
||||
**_PAYLOAD,
|
||||
"embedding_model_digest": profile.model_digest,
|
||||
"embedding_space_id": str(profile.embedding_space_id),
|
||||
}
|
||||
qdrant = FakeQdrantClient(alias_target="rag_dense_hybrid_stale", payload=payload)
|
||||
pipeline = RetrievalPipeline(
|
||||
qdrant_client=qdrant, # type: ignore[arg-type]
|
||||
embedding_profile_store=await _activated_store_for(profile),
|
||||
embedding_adapter_factory=create_embedding_adapter_factory(
|
||||
settings=settings,
|
||||
http_client=httpx.AsyncClient(
|
||||
transport=httpx.MockTransport(respond), follow_redirects=False
|
||||
),
|
||||
),
|
||||
embedding_selection_resolver=FixedSelectionResolver(profile, route="rc-canary-2026-09"),
|
||||
)
|
||||
executor = ProductionSearchExecutor(pipeline, FakeTitleLookup()) # type: ignore[arg-type]
|
||||
|
||||
result = await executor.execute(_search_request())
|
||||
|
||||
assert result.degraded is False
|
||||
assert len(result.hits) == 1
|
||||
assert qdrant.query_collections
|
||||
assert set(qdrant.query_collections) == {"rag_dense_hybrid_v1"}
|
||||
assert len(seen) == 1
|
||||
assert seen[0].url.path == "/api/v1/capability-experiments/rc-canary-2026-09/invoke"
|
||||
assert json.loads(seen[0].content) == {
|
||||
"input": ["how do I restart the payment service"],
|
||||
"input_type": "query",
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_document_title_lookup_returns_empty_dict_for_empty_input() -> None:
|
||||
lookup = PostgresDocumentTitleLookup(session_factory=None) # type: ignore[arg-type]
|
||||
assert await lookup.titles(set()) == {}
|
||||
|
||||
|
||||
class RecordingQdrantClient(FakeQdrantClient):
|
||||
"""Also records every query_points call so filter compilation is inspectable."""
|
||||
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
self.query_calls: list[dict] = [] # type: ignore[type-arg]
|
||||
|
||||
async def query_points(self, **kwargs: object) -> models.QueryResponse:
|
||||
self.query_calls.append(dict(kwargs))
|
||||
return await super().query_points(**kwargs)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_search_executor_compiles_every_accepted_filter_into_the_qdrant_query() -> None:
|
||||
"""Regression: source_ids/document_ids/trust_levels used to be accepted by
|
||||
the API and silently dropped before ever reaching Qdrant."""
|
||||
|
||||
client = RecordingQdrantClient()
|
||||
embedding_client = httpx.AsyncClient(transport=_embed_transport(), follow_redirects=False)
|
||||
pipeline = RetrievalPipeline(
|
||||
qdrant_client=client, # type: ignore[arg-type]
|
||||
embedding_profile_store=await _activated_store(),
|
||||
embedding_adapter_factory=create_embedding_adapter_factory(
|
||||
settings=Settings(env="test", ollama_url="http://localhost:11434"),
|
||||
http_client=embedding_client,
|
||||
),
|
||||
)
|
||||
executor = ProductionSearchExecutor(pipeline, FakeTitleLookup()) # type: ignore[arg-type]
|
||||
request = SearchExecutionRequest(
|
||||
principal=Principal(uuid4(), WORKSPACE_ID, PrincipalType.HUMAN, frozenset()),
|
||||
query=SearchQuery(
|
||||
query="restart",
|
||||
max_results=5,
|
||||
filters=SearchFilterData(
|
||||
source_ids=(SOURCE_ID,),
|
||||
document_ids=(DOCUMENT_ID,),
|
||||
trust_levels=("source",),
|
||||
),
|
||||
),
|
||||
scope=_scope(),
|
||||
retrieval_run_id=uuid4(),
|
||||
)
|
||||
await executor.execute(request)
|
||||
|
||||
assert client.query_calls
|
||||
for call in client.query_calls:
|
||||
compiled = str(call["query_filter"])
|
||||
assert str(SOURCE_ID) in compiled
|
||||
assert str(DOCUMENT_ID) in compiled
|
||||
assert "trust_level" in compiled
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_search_executor_reports_per_stage_timings() -> None:
|
||||
pipeline = _pipeline(embedding_transport=_embed_transport(), store=await _activated_store())
|
||||
executor = ProductionSearchExecutor(pipeline, FakeTitleLookup()) # type: ignore[arg-type]
|
||||
result = await executor.execute(_search_request())
|
||||
|
||||
timings = dict(result.timings_ms or {})
|
||||
for stage in (
|
||||
"query_embedding",
|
||||
"sparse_encoding",
|
||||
"dense_search",
|
||||
"sparse_search",
|
||||
"fusion",
|
||||
"payload_fetch",
|
||||
):
|
||||
assert stage in timings
|
||||
assert timings[stage] >= 0.0
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_pipeline_reports_when_a_ranked_hit_has_no_payload() -> None:
|
||||
"""A dropped hit is a degradation, not a quietly shorter answer.
|
||||
|
||||
Returning four results where the ranking found five, with nothing in the
|
||||
response to say so, is indistinguishable from "there were only four" --
|
||||
and the caller acts on it.
|
||||
"""
|
||||
|
||||
embedding_client = httpx.AsyncClient(transport=_embed_transport(), follow_redirects=False)
|
||||
pipeline = RetrievalPipeline(
|
||||
qdrant_client=PayloadlessQdrantClient(), # type: ignore[arg-type]
|
||||
embedding_profile_store=await _activated_store(),
|
||||
embedding_adapter_factory=create_embedding_adapter_factory(
|
||||
settings=Settings(env="test", ollama_url="http://localhost:11434"),
|
||||
http_client=embedding_client,
|
||||
),
|
||||
)
|
||||
|
||||
result = await pipeline.run(
|
||||
query_text="restart payment",
|
||||
content_types=(),
|
||||
languages=(),
|
||||
scope=_scope(),
|
||||
max_results=5,
|
||||
profile="hybrid-v1",
|
||||
retrieval_run_id=uuid4(),
|
||||
)
|
||||
|
||||
assert result.hits == ()
|
||||
assert "payload_unavailable" in result.degradation_codes
|
||||
Reference in new issue
Block a user