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,246 @@
|
||||
"""Query Lab productization: selector-first form, no stale capability copy,
|
||||
reranking shown only when active, fused-stage explainability."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from uuid import uuid4
|
||||
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from ragcore.api.v1.control.dependencies import get_principal
|
||||
from ragcore.domain.authorization import Principal, PrincipalType
|
||||
from ragcore.domain.control import Role
|
||||
from ragcore.main import create_app
|
||||
from ragcore.web.query_lab.dependencies import get_query_lab_service
|
||||
from ragcore.web.query_lab.models import (
|
||||
AnswerabilityTrace,
|
||||
CandidateBackendLabel,
|
||||
CandidateTrace,
|
||||
CitationTrace,
|
||||
ContextTrace,
|
||||
EffectiveFilterTrace,
|
||||
FusionTrace,
|
||||
InclusionState,
|
||||
ParentExpansionTrace,
|
||||
QueryLabQuery,
|
||||
QueryLabTrace,
|
||||
RerankTrace,
|
||||
RevisionTrace,
|
||||
)
|
||||
from ragcore.web.query_lab.routes import QueryLabCatalog, get_query_lab_catalog
|
||||
|
||||
WORKSPACE_ID = uuid4()
|
||||
SPACE_ID = uuid4()
|
||||
SOURCE_ID = uuid4()
|
||||
DOCUMENT_ID = uuid4()
|
||||
|
||||
|
||||
class StubService:
|
||||
def __init__(self, trace: QueryLabTrace) -> None:
|
||||
self.trace = trace
|
||||
self.calls: list[QueryLabQuery] = []
|
||||
|
||||
def can_use(self, principal: Principal) -> bool:
|
||||
return True
|
||||
|
||||
async def run(self, principal: Principal, query: QueryLabQuery) -> QueryLabTrace:
|
||||
self.calls.append(query)
|
||||
return self.trace
|
||||
|
||||
|
||||
def _fused_candidate() -> CandidateTrace:
|
||||
return CandidateTrace(
|
||||
rank=1,
|
||||
chunk_id=uuid4(),
|
||||
document_id=DOCUMENT_ID,
|
||||
space_id=SPACE_ID,
|
||||
backend=CandidateBackendLabel.FUSED,
|
||||
score=0.0325,
|
||||
score_label="rrf_score_not_a_probability",
|
||||
content_type="text/markdown",
|
||||
trust_level="trusted_internal",
|
||||
language="en",
|
||||
text_preview="restart the service after the breaker",
|
||||
text_truncated=False,
|
||||
inclusion=InclusionState.INCLUDED,
|
||||
reason="fused_rank",
|
||||
dense_rank=2,
|
||||
dense_score=0.87,
|
||||
sparse_rank=1,
|
||||
sparse_score=12.5,
|
||||
rrf_dense=1 / 62,
|
||||
rrf_sparse=1 / 61,
|
||||
document_title="Gateway runbook",
|
||||
source_name="Infra runbooks",
|
||||
)
|
||||
|
||||
|
||||
def _trace(*, rerank_state: str = "skipped") -> QueryLabTrace:
|
||||
return QueryLabTrace(
|
||||
retrieval_run_id=uuid4(),
|
||||
query="restart breaker",
|
||||
profile="hybrid-v1",
|
||||
effective_filters=EffectiveFilterTrace(
|
||||
requested_space_ids=(SPACE_ID,),
|
||||
effective_space_ids=(SPACE_ID,),
|
||||
denied_space_ids=(),
|
||||
trust_required_space_ids=(),
|
||||
requested_content_types=(),
|
||||
applied_content_types=(),
|
||||
requested_languages=("en",),
|
||||
applied_languages=("en",),
|
||||
unsupported_filter_fields=(),
|
||||
),
|
||||
dense_candidates=(),
|
||||
sparse_candidates=(),
|
||||
fusion=FusionTrace(candidates=(_fused_candidate(),), suppressed_count=1),
|
||||
rerank=RerankTrace(
|
||||
state=rerank_state, degradation_code=None, candidates=(), elapsed_ms=0.0
|
||||
),
|
||||
parent_expansion=ParentExpansionTrace(1, 0, 40),
|
||||
context=ContextTrace(
|
||||
token_count=120, max_context_tokens=4000, block_count=1, citation_ids=()
|
||||
),
|
||||
answerability=AnswerabilityTrace(
|
||||
status="answerable",
|
||||
reasons=("sufficient_evidence",),
|
||||
evidence_count=1,
|
||||
document_diversity=1,
|
||||
source_independence=1,
|
||||
facet_coverage_ratio=1.0,
|
||||
thresholds_version="v1",
|
||||
),
|
||||
citations=(
|
||||
CitationTrace(
|
||||
id=uuid4(),
|
||||
document_id=DOCUMENT_ID,
|
||||
chunk_id=uuid4(),
|
||||
excerpt_preview="restart the service after the breaker",
|
||||
excerpt_truncated=False,
|
||||
location={"section": "Failover", "line_start": 12, "line_end": 14},
|
||||
source_uri=f"ragcore://source/{SOURCE_ID}",
|
||||
document_title="Gateway runbook",
|
||||
source_name="Infra runbooks",
|
||||
display="Gateway runbook · Failover · lines 12-14",
|
||||
),
|
||||
),
|
||||
timings_ms={"embed_query": 18.0, "dense_search": 8.0, "sparse_search": 6.0, "fusion": 1.0},
|
||||
revisions=RevisionTrace("hybrid/v1", None, "technical/v1", "rag_dense_hybrid_active", "v1"),
|
||||
degraded=False,
|
||||
degradation_codes=(),
|
||||
)
|
||||
|
||||
|
||||
def _catalog() -> QueryLabCatalog:
|
||||
return QueryLabCatalog(
|
||||
spaces=((SPACE_ID, "Production Knowledge Base"),),
|
||||
sources=((SOURCE_ID, "Infra runbooks", "Production Knowledge Base"),),
|
||||
documents=((DOCUMENT_ID, "Gateway runbook", "Production Knowledge Base"),),
|
||||
languages=("de", "en", "fr", "nl"),
|
||||
content_types=("text/markdown", "text/plain"),
|
||||
trust_levels=("trusted_internal", "user_uploaded"),
|
||||
)
|
||||
|
||||
|
||||
def _client(service: StubService, catalog: QueryLabCatalog | None = None) -> TestClient:
|
||||
app = create_app()
|
||||
principal = Principal(
|
||||
uuid4(), WORKSPACE_ID, PrincipalType.HUMAN, frozenset({Role.SPACE_MANAGER})
|
||||
)
|
||||
app.dependency_overrides[get_principal] = lambda: principal
|
||||
app.dependency_overrides[get_query_lab_service] = lambda: service
|
||||
app.dependency_overrides[get_query_lab_catalog] = lambda: catalog or _catalog()
|
||||
return TestClient(app)
|
||||
|
||||
|
||||
def test_form_offers_selectors_from_the_catalog_and_an_advanced_section() -> None:
|
||||
client = _client(StubService(_trace()))
|
||||
body = client.get("/admin/query-lab").text
|
||||
assert "Production Knowledge Base" in body
|
||||
assert "Infra runbooks" in body
|
||||
assert "Gateway runbook" in body
|
||||
assert '<select id="space_ids" name="space_ids" multiple' in body
|
||||
assert '<select id="source_ids" name="source_ids" multiple' in body
|
||||
assert '<select id="document_ids" name="document_ids" multiple' in body
|
||||
assert '<select id="languages" name="languages" multiple' in body
|
||||
assert '<select id="trust_levels" name="trust_levels" multiple' in body
|
||||
assert '<select id="profile" name="profile"' in body
|
||||
assert "Advanced: raw identifiers" in body
|
||||
# Stale copy is gone.
|
||||
assert "Narrowing only" not in body
|
||||
assert "not yet applied server-side" not in body
|
||||
assert "not yet supported by the filter compiler" not in body
|
||||
|
||||
|
||||
def test_selected_values_become_server_side_filters() -> None:
|
||||
service = StubService(_trace())
|
||||
client = _client(service)
|
||||
response = client.post(
|
||||
"/admin/query-lab/run",
|
||||
data={
|
||||
"query": "restart breaker",
|
||||
"profile": "hybrid-v1",
|
||||
"max_results": 5,
|
||||
"space_ids": [str(SPACE_ID)],
|
||||
"source_ids": [str(SOURCE_ID)],
|
||||
"document_ids": [str(DOCUMENT_ID)],
|
||||
"languages": ["en", "nl"],
|
||||
"trust_levels": ["trusted_internal"],
|
||||
},
|
||||
)
|
||||
assert response.status_code == 200
|
||||
[query] = service.calls
|
||||
assert query.requested_space_ids == (SPACE_ID,)
|
||||
assert query.filters.source_ids == (SOURCE_ID,)
|
||||
assert query.filters.document_ids == (DOCUMENT_ID,)
|
||||
assert query.filters.languages == ("en", "nl")
|
||||
assert query.filters.trust_levels == ("trusted_internal",)
|
||||
|
||||
|
||||
def test_advanced_raw_ids_merge_with_selectors() -> None:
|
||||
service = StubService(_trace())
|
||||
client = _client(service)
|
||||
extra_source = uuid4()
|
||||
response = client.post(
|
||||
"/admin/query-lab/run",
|
||||
data={
|
||||
"query": "restart breaker",
|
||||
"source_ids": [str(SOURCE_ID)],
|
||||
"raw_source_ids": f"{extra_source}, {SOURCE_ID}",
|
||||
},
|
||||
)
|
||||
assert response.status_code == 200
|
||||
[query] = service.calls
|
||||
assert set(query.filters.source_ids) == {SOURCE_ID, extra_source}
|
||||
assert len(query.filters.source_ids) == 2
|
||||
|
||||
|
||||
def test_inspector_explains_fused_ranking_and_hides_inactive_reranking() -> None:
|
||||
client = _client(StubService(_trace()))
|
||||
body = client.post("/admin/query-lab/run", data={"query": "restart breaker"}).text
|
||||
assert "Retrieval inspector" in body
|
||||
assert "Fusion — RRF ranking" in body
|
||||
assert "Final rank" in body
|
||||
assert "#2 · 0.870" in body # dense rank + score
|
||||
assert "#1 · 12.500" in body # sparse rank + score
|
||||
assert "+0.0161" in body # RRF contribution 1/62
|
||||
assert "Gateway runbook" in body and "Infra runbooks" in body
|
||||
assert "Gateway runbook · Failover · lines 12-14" in body
|
||||
assert "no reranker is active" in body
|
||||
assert "Reranking (" not in body
|
||||
assert "Reranker profile" not in body
|
||||
assert "Generation is not run by Query Lab" in body
|
||||
assert "18.0 ms" in body and "embed_query" in body
|
||||
|
||||
|
||||
def test_reranking_section_appears_only_when_the_stage_is_active() -> None:
|
||||
client = _client(StubService(_trace(rerank_state="reranked")))
|
||||
body = client.post("/admin/query-lab/run", data={"query": "restart breaker"}).text
|
||||
assert "Reranking (reranked)" in body
|
||||
|
||||
|
||||
def test_unavailable_catalog_degrades_to_advanced_fields() -> None:
|
||||
client = _client(StubService(_trace()), QueryLabCatalog(available=False, languages=("en",)))
|
||||
body = client.get("/admin/query-lab").text
|
||||
assert "Selector lists could not be loaded" in body
|
||||
assert 'name="requested_space_ids"' in body
|
||||
@@ -0,0 +1,306 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from uuid import uuid4
|
||||
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from ragcore.api.v1.control.dependencies import get_principal
|
||||
from ragcore.api.v1.search.service import AuthorizationInputs
|
||||
from ragcore.application.authorization import AuthorizationService
|
||||
from ragcore.application.retrieval.authorization import RetrievalAuthorizationService
|
||||
from ragcore.domain.authorization import Principal, PrincipalType
|
||||
from ragcore.domain.control import Role
|
||||
from ragcore.main import create_app
|
||||
from ragcore.web.query_lab.dependencies import get_query_lab_service
|
||||
from ragcore.web.query_lab.models import (
|
||||
AnswerabilityTrace,
|
||||
CandidateBackendLabel,
|
||||
CandidateTrace,
|
||||
CitationTrace,
|
||||
ContextTrace,
|
||||
EffectiveFilterTrace,
|
||||
FusionTrace,
|
||||
InclusionState,
|
||||
ParentExpansionTrace,
|
||||
QueryLabQuery,
|
||||
QueryLabTrace,
|
||||
RerankTrace,
|
||||
RevisionTrace,
|
||||
)
|
||||
from ragcore.web.query_lab.service import QueryLabService
|
||||
|
||||
WORKSPACE_ID = uuid4()
|
||||
SPACE_ID = uuid4()
|
||||
DOCUMENT_ID = uuid4()
|
||||
|
||||
|
||||
class StubQueryLabService:
|
||||
def __init__(self, trace: QueryLabTrace | None = None, error: Exception | None = None) -> None:
|
||||
self._trace = trace
|
||||
self._error = error
|
||||
self.calls: list[QueryLabQuery] = []
|
||||
|
||||
def can_use(self, principal: Principal) -> bool:
|
||||
return True
|
||||
|
||||
async def run(self, principal: Principal, query: QueryLabQuery) -> QueryLabTrace:
|
||||
self.calls.append(query)
|
||||
if self._error is not None:
|
||||
raise self._error
|
||||
assert self._trace is not None
|
||||
return self._trace
|
||||
|
||||
|
||||
def _principal(role: Role) -> Principal:
|
||||
return Principal(uuid4(), WORKSPACE_ID, PrincipalType.HUMAN, frozenset({role}))
|
||||
|
||||
|
||||
def _candidate(text_preview: str = "hello world", **overrides: object) -> CandidateTrace:
|
||||
values: dict[str, object] = {
|
||||
"rank": 1,
|
||||
"chunk_id": uuid4(),
|
||||
"document_id": DOCUMENT_ID,
|
||||
"space_id": SPACE_ID,
|
||||
"backend": CandidateBackendLabel.DENSE,
|
||||
"score": 0.42,
|
||||
"score_label": "similarity_score",
|
||||
"content_type": "text/plain",
|
||||
"trust_level": "source",
|
||||
"language": "en",
|
||||
"text_preview": text_preview,
|
||||
"text_truncated": False,
|
||||
"inclusion": InclusionState.INCLUDED,
|
||||
"reason": "selected_for_fusion",
|
||||
}
|
||||
values.update(overrides)
|
||||
return CandidateTrace(**values)
|
||||
|
||||
|
||||
def _trace(**overrides: object) -> QueryLabTrace:
|
||||
values: dict[str, object] = {
|
||||
"retrieval_run_id": uuid4(),
|
||||
"query": "what does the runbook say",
|
||||
"profile": "hybrid-v1",
|
||||
"effective_filters": EffectiveFilterTrace(
|
||||
requested_space_ids=(SPACE_ID,),
|
||||
effective_space_ids=(SPACE_ID,),
|
||||
denied_space_ids=(),
|
||||
trust_required_space_ids=(),
|
||||
requested_content_types=(),
|
||||
applied_content_types=(),
|
||||
requested_languages=(),
|
||||
applied_languages=(),
|
||||
unsupported_filter_fields=(),
|
||||
),
|
||||
"dense_candidates": (_candidate(),),
|
||||
"sparse_candidates": (),
|
||||
"fusion": FusionTrace(
|
||||
candidates=(_candidate(backend=CandidateBackendLabel.FUSED),), suppressed_count=0
|
||||
),
|
||||
"rerank": RerankTrace(
|
||||
state="reranked", degradation_code=None, candidates=(), elapsed_ms=12.0
|
||||
),
|
||||
"parent_expansion": ParentExpansionTrace(0, 0, 0),
|
||||
"context": ContextTrace(
|
||||
token_count=10, max_context_tokens=4000, block_count=1, citation_ids=()
|
||||
),
|
||||
"answerability": AnswerabilityTrace(
|
||||
status="answerable",
|
||||
reasons=("sufficient_evidence",),
|
||||
evidence_count=2,
|
||||
document_diversity=2,
|
||||
source_independence=2,
|
||||
facet_coverage_ratio=1.0,
|
||||
thresholds_version="v1",
|
||||
),
|
||||
"citations": (
|
||||
CitationTrace(
|
||||
id=uuid4(),
|
||||
document_id=DOCUMENT_ID,
|
||||
chunk_id=uuid4(),
|
||||
excerpt_preview="the runbook says to restart the service",
|
||||
excerpt_truncated=False,
|
||||
location={"page": 1},
|
||||
source_uri="ragcore://source/abc",
|
||||
),
|
||||
),
|
||||
"timings_ms": {"embed_query": 5.0, "dense_search": 3.0},
|
||||
"revisions": RevisionTrace(
|
||||
"hybrid/v1", "query-lab/v1", "technical/v1", "rag_dense_hybrid_active", "v1"
|
||||
),
|
||||
"degraded": False,
|
||||
"degradation_codes": (),
|
||||
}
|
||||
values.update(overrides)
|
||||
return QueryLabTrace(**values)
|
||||
|
||||
|
||||
def _app(service: StubQueryLabService, principal: Principal) -> TestClient:
|
||||
app = create_app()
|
||||
app.dependency_overrides[get_principal] = lambda: principal
|
||||
app.dependency_overrides[get_query_lab_service] = lambda: service
|
||||
return TestClient(app, raise_server_exceptions=False)
|
||||
|
||||
|
||||
def test_unauthenticated_request_is_rejected_without_reaching_the_service() -> None:
|
||||
service = StubQueryLabService(_trace())
|
||||
app = create_app()
|
||||
app.dependency_overrides[get_query_lab_service] = lambda: service
|
||||
client = TestClient(app, raise_server_exceptions=False)
|
||||
response = client.post(
|
||||
"/admin/query-lab/run",
|
||||
data={"query": "test", "profile": "hybrid-v1", "max_results": 10},
|
||||
)
|
||||
assert response.status_code == 401
|
||||
assert service.calls == []
|
||||
|
||||
|
||||
def test_page_loads_with_accessible_landmarks_and_empty_state() -> None:
|
||||
client = _app(StubQueryLabService(), _principal(Role.SPACE_MANAGER))
|
||||
response = client.get("/admin/query-lab")
|
||||
assert response.status_code == 200
|
||||
assert 'href="#main-content"' in response.text
|
||||
assert '<nav aria-label="Primary navigation">' in response.text
|
||||
assert "Run a query above" in response.text
|
||||
|
||||
|
||||
class UnusableStubQueryLabService(StubQueryLabService):
|
||||
def can_use(self, principal: Principal) -> bool:
|
||||
return False
|
||||
|
||||
|
||||
def test_get_page_is_also_forbidden_for_an_unprivileged_principal() -> None:
|
||||
client = _app(UnusableStubQueryLabService(), _principal(Role.VIEWER))
|
||||
response = client.get("/admin/query-lab")
|
||||
assert response.status_code == 403
|
||||
assert "Access denied" in response.text
|
||||
|
||||
|
||||
class DenyingInputsProvider:
|
||||
async def load(self, principal: Principal) -> AuthorizationInputs:
|
||||
return AuthorizationInputs(spaces=(), grants=(), user_grants=(), application=None)
|
||||
|
||||
|
||||
class ExplodingExecutor:
|
||||
async def execute(self, request): # pragma: no cover - must never be reached
|
||||
raise AssertionError("executor must not run for a denied principal")
|
||||
|
||||
|
||||
def test_viewer_role_is_forbidden_and_leaks_nothing() -> None:
|
||||
real_service = QueryLabService(
|
||||
authorization=AuthorizationService(),
|
||||
retrieval_authorization=RetrievalAuthorizationService(),
|
||||
inputs=DenyingInputsProvider(),
|
||||
executor=ExplodingExecutor(),
|
||||
)
|
||||
client = _app(real_service, _principal(Role.VIEWER))
|
||||
response = client.post(
|
||||
"/admin/query-lab/run",
|
||||
data={"query": "secret question", "profile": "hybrid-v1", "max_results": 10},
|
||||
)
|
||||
assert response.status_code == 403
|
||||
assert "Access denied" in response.text
|
||||
assert "secret question" not in response.text
|
||||
assert "runbook" not in response.text
|
||||
|
||||
|
||||
def test_happy_path_shows_all_pipeline_phases() -> None:
|
||||
service = StubQueryLabService(_trace())
|
||||
client = _app(service, _principal(Role.SPACE_MANAGER))
|
||||
response = client.post(
|
||||
"/admin/query-lab/run",
|
||||
data={"query": "what does the runbook say", "profile": "hybrid-v1", "max_results": 10},
|
||||
)
|
||||
assert response.status_code == 200
|
||||
body = response.text
|
||||
assert "Effective authorization" in body
|
||||
assert "Answer & answerability" in body or "Answer" in body
|
||||
assert "answerable" in body
|
||||
assert "a category, not a confidence percentage" in body
|
||||
assert "not a probability" in body or "similarity_score" in body
|
||||
assert "the runbook says to restart the service" in body
|
||||
assert service.calls[0].query == "what does the runbook say"
|
||||
assert 'aria-label="Run summary"' in body
|
||||
assert "Evidence count" in body
|
||||
assert "8.0 ms" in body # sum of the fixture's real embed_query + dense_search timings
|
||||
|
||||
|
||||
def test_malicious_candidate_text_is_escaped_not_executed() -> None:
|
||||
malicious = "<script>alert('xss')</script>"
|
||||
trace = _trace(dense_candidates=(_candidate(text_preview=malicious),))
|
||||
client = _app(StubQueryLabService(trace), _principal(Role.SPACE_MANAGER))
|
||||
response = client.post(
|
||||
"/admin/query-lab/run",
|
||||
data={"query": "test", "profile": "hybrid-v1", "max_results": 10},
|
||||
)
|
||||
assert response.status_code == 200
|
||||
assert "<script>alert" not in response.text
|
||||
assert "<script>" in response.text
|
||||
|
||||
|
||||
def test_degraded_run_shows_a_visible_non_color_only_banner() -> None:
|
||||
trace = _trace(degraded=True, degradation_codes=("no_active_embedding_profile",))
|
||||
client = _app(StubQueryLabService(trace), _principal(Role.SPACE_MANAGER))
|
||||
response = client.post(
|
||||
"/admin/query-lab/run",
|
||||
data={"query": "test", "profile": "hybrid-v1", "max_results": 10},
|
||||
)
|
||||
assert response.status_code == 200
|
||||
assert "Degraded run" in response.text
|
||||
assert "no_active_embedding_profile" in response.text
|
||||
assert 'role="alert"' in response.text
|
||||
|
||||
|
||||
def test_oversized_query_is_rejected_before_reaching_the_service() -> None:
|
||||
service = StubQueryLabService(_trace())
|
||||
client = _app(service, _principal(Role.SPACE_MANAGER))
|
||||
response = client.post(
|
||||
"/admin/query-lab/run",
|
||||
data={"query": "x" * 8001, "profile": "hybrid-v1", "max_results": 10},
|
||||
)
|
||||
assert response.status_code == 422
|
||||
assert service.calls == []
|
||||
|
||||
|
||||
def test_invalid_requested_space_id_is_a_stable_bad_request() -> None:
|
||||
service = StubQueryLabService(_trace())
|
||||
client = _app(service, _principal(Role.SPACE_MANAGER))
|
||||
response = client.post(
|
||||
"/admin/query-lab/run",
|
||||
data={
|
||||
"query": "test",
|
||||
"profile": "hybrid-v1",
|
||||
"max_results": 10,
|
||||
"requested_space_ids": "not-a-uuid",
|
||||
},
|
||||
)
|
||||
assert response.status_code == 400
|
||||
assert service.calls == []
|
||||
|
||||
|
||||
def test_response_never_contains_secret_or_credential_markers() -> None:
|
||||
client = _app(StubQueryLabService(_trace()), _principal(Role.SPACE_MANAGER))
|
||||
response = client.post(
|
||||
"/admin/query-lab/run",
|
||||
data={"query": "test", "profile": "hybrid-v1", "max_results": 10},
|
||||
)
|
||||
body_lower = response.text.lower()
|
||||
markers = (
|
||||
"api_key",
|
||||
"api_token_pepper",
|
||||
"secret_key",
|
||||
"authorization: bearer",
|
||||
"qdrant_api_key",
|
||||
)
|
||||
for marker in markers:
|
||||
assert marker not in body_lower
|
||||
|
||||
|
||||
def test_response_never_contains_a_raw_embedding_vector_shape() -> None:
|
||||
client = _app(StubQueryLabService(_trace()), _principal(Role.SPACE_MANAGER))
|
||||
response = client.post(
|
||||
"/admin/query-lab/run",
|
||||
data={"query": "test", "profile": "hybrid-v1", "max_results": 10},
|
||||
)
|
||||
assert "dense_vector" not in response.text
|
||||
assert "sparse_indices" not in response.text
|
||||
Reference in new issue
Block a user