fix: make qdrant vector hit parsing total
This commit is contained in:
@@ -892,3 +892,73 @@ def test_scroll_accepts_null_or_missing_terminal_offset(next_page_offset):
|
||||
expected_dimension=1024, request=request,
|
||||
)
|
||||
assert store.existing_hashes("memory", ["memory"]) == {}
|
||||
|
||||
|
||||
_QUERY_PAYLOAD = {
|
||||
"record_key": "memory:1",
|
||||
"record_kind": "memory",
|
||||
"kind": "memory",
|
||||
"ref": "ref:memory:1",
|
||||
"title": "title:memory:1",
|
||||
"content": "content:memory:1",
|
||||
}
|
||||
|
||||
|
||||
def _query_response_store(points):
|
||||
fake = FakeQdrantHttp()
|
||||
fake.collection = {"vectors": {"size": 1024, "distance": "Cosine"}}
|
||||
fake.payload_indexes = set(_REQUIRED_INDEXES)
|
||||
original = fake.request
|
||||
|
||||
def request(method, url, **kwargs):
|
||||
if method == "POST" and url.endswith("/points/query"):
|
||||
return FakeResponse(200, {"result": {"points": points}})
|
||||
return original(method, url, **kwargs)
|
||||
|
||||
store = _store(fake)
|
||||
store._request = request
|
||||
return store
|
||||
|
||||
|
||||
@pytest.mark.parametrize("leaf", [
|
||||
"record_key", "record_kind", "kind", "ref", "title", "content",
|
||||
])
|
||||
def test_query_rejects_non_string_required_vector_hit_payload_leaves(leaf):
|
||||
payload = {**_QUERY_PAYLOAD, leaf: 1}
|
||||
store = _query_response_store([{"id": "p1", "score": 0.9, "payload": payload}])
|
||||
|
||||
with pytest.raises(VectorResponseError):
|
||||
store.search(["memory"], [0.2] * 1024, limit=1, kinds=["memory"])
|
||||
|
||||
|
||||
@pytest.mark.parametrize("leaf", [
|
||||
"record_key", "record_kind", "kind", "ref", "title", "content",
|
||||
])
|
||||
def test_query_rejects_missing_required_vector_hit_payload_leaves(leaf):
|
||||
payload = {key: value for key, value in _QUERY_PAYLOAD.items() if key != leaf}
|
||||
store = _query_response_store([{"id": "p1", "score": 0.9, "payload": payload}])
|
||||
|
||||
with pytest.raises(VectorResponseError):
|
||||
store.search(["memory"], [0.2] * 1024, limit=1, kinds=["memory"])
|
||||
|
||||
|
||||
def test_query_rejects_heterogeneous_record_keys_before_sorting_hits():
|
||||
store = _query_response_store([
|
||||
{"id": "p1", "score": 0.9, "payload": _QUERY_PAYLOAD},
|
||||
{
|
||||
"id": "p2",
|
||||
"score": 0.8,
|
||||
"payload": {**_QUERY_PAYLOAD, "record_key": 2},
|
||||
},
|
||||
])
|
||||
|
||||
with pytest.raises(VectorResponseError):
|
||||
store.search(["memory"], [0.2] * 1024, limit=2, kinds=["memory"])
|
||||
|
||||
|
||||
@pytest.mark.parametrize("score", [True, False, 10**1000, float("nan"), float("inf"), float("-inf")])
|
||||
def test_query_rejects_scores_that_cannot_be_finite_float(score):
|
||||
store = _query_response_store([{"id": "p1", "score": score, "payload": _QUERY_PAYLOAD}])
|
||||
|
||||
with pytest.raises(VectorResponseError):
|
||||
store.search(["memory"], [0.2] * 1024, limit=1, kinds=["memory"])
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
"""Qdrant-backed vector store for one workspace-owned semantic collection."""
|
||||
|
||||
import math
|
||||
import re
|
||||
from collections.abc import Callable
|
||||
from uuid import NAMESPACE_URL, uuid5
|
||||
@@ -477,16 +478,25 @@ class QdrantVectorStore:
|
||||
raise VectorResponseError("Qdrant returned malformed query response")
|
||||
payload = point.get("payload")
|
||||
score = point.get("score")
|
||||
required_payload_leaves = (
|
||||
"record_key", "record_kind", "kind", "ref", "title", "content"
|
||||
)
|
||||
if (
|
||||
not isinstance(payload, dict)
|
||||
or type(score) not in (int, float)
|
||||
or any(
|
||||
key in payload and not isinstance(payload[key], str)
|
||||
for key in ("record_key", "record_kind", "kind", "ref", "title", "content")
|
||||
key not in payload or not isinstance(payload[key], str)
|
||||
for key in required_payload_leaves
|
||||
)
|
||||
):
|
||||
raise VectorResponseError("Qdrant returned malformed query response")
|
||||
return hit_from_metadata(float(score), payload)
|
||||
try:
|
||||
similarity = float(score)
|
||||
except (OverflowError, ValueError) as exc:
|
||||
raise VectorResponseError("Qdrant returned malformed query response") from exc
|
||||
if not math.isfinite(similarity):
|
||||
raise VectorResponseError("Qdrant returned malformed query response")
|
||||
return hit_from_metadata(similarity, payload)
|
||||
|
||||
def _call(self, method: str, path: str, payload: dict | None, allow_missing: bool = False) -> dict | None:
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user