Skip to content

Commit bf1f28a

Browse files
Asaif AliAsaif Ali
authored andcommitted
Qdrant fixes
1 parent 7e10f82 commit bf1f28a

1 file changed

Lines changed: 26 additions & 30 deletions

File tree

agent_service/app/infrastructure/agents_backend/qdrant_knowledge.py

Lines changed: 26 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
from typing import Any, Iterable
2222

2323
from qdrant_client import QdrantClient, models
24-
from agno.knowledge.document import Document
2524

2625
from app.infrastructure.utils.migration_context import migration_name_ctx
2726
from app.infrastructure.utils.user_context import current_user
@@ -78,6 +77,25 @@ def _collection_name(scope: str) -> str:
7877
return f"{QDRANT_COLLECTION_PREFIX}-{digest}-{safe_scope}"
7978

8079

80+
class QdrantRecord(dict):
81+
"""Hybrid Qdrant record compatible with both dict-style and Agno Document-style access.
82+
83+
LegacyLens has two existing access patterns: some helpers index records as
84+
dictionaries while planning/conversion helpers access ``record.meta_data``
85+
and ``record.content``. A plain dict or plain Agno Document cannot satisfy
86+
both contracts, so this adapter intentionally supports both.
87+
"""
88+
89+
def __init__(self, payload: dict[str, Any], *, score: float | None = None):
90+
super().__init__(payload)
91+
self.id = str(payload.get("id") or "")
92+
self.name = str(payload.get("name") or "")
93+
self.content = str(payload.get("text_content") or payload.get("content") or "")
94+
metadata = payload.get("metadata")
95+
self.meta_data = dict(metadata) if isinstance(metadata, dict) else {}
96+
self.score = score
97+
98+
8199
class QdrantKnowledgeBase:
82100
"""Small sync knowledge-base facade used by the existing agent code."""
83101

@@ -246,31 +264,9 @@ def insert_many(self, contents: Iterable[dict[str, Any]]) -> int:
246264
return len(points)
247265

248266
@staticmethod
249-
def _as_document(payload: dict[str, Any], *, score: float | None = None) -> Document:
250-
"""Convert a Qdrant payload into the Agno Document contract expected by LegacyLens.
251-
252-
The original LanceDB/Agno path returned Document instances. Keeping that
253-
contract here avoids leaking Qdrant payload dictionaries into existing
254-
planning/conversion code that accesses ``doc.content`` and
255-
``doc.meta_data`` attributes.
256-
"""
257-
metadata = payload.get("metadata")
258-
if not isinstance(metadata, dict):
259-
metadata = {}
260-
doc = Document(
261-
id=str(payload.get("id") or ""),
262-
name=str(payload.get("name") or ""),
263-
content=str(payload.get("text_content") or payload.get("content") or ""),
264-
meta_data=metadata,
265-
)
266-
if score is not None:
267-
# Agno versions used by LegacyLens expose score on search results;
268-
# set it defensively so this adapter remains compatible across versions.
269-
try:
270-
doc.score = score
271-
except Exception:
272-
pass
273-
return doc
267+
def _as_document(payload: dict[str, Any], *, score: float | None = None) -> QdrantRecord:
268+
"""Return a hybrid record preserving both LegacyLens result contracts."""
269+
return QdrantRecord(payload, score=score)
274270

275271
def search(
276272
self,
@@ -280,7 +276,7 @@ def search(
280276
limit: int | None = None,
281277
max_results: int | None = None,
282278
**_: Any,
283-
) -> list[dict[str, Any]]:
279+
) -> list[QdrantRecord]:
284280
top_k = int(max_results or limit or QDRANT_TOP_K)
285281
if not query:
286282
return []
@@ -311,22 +307,22 @@ def search(
311307
with_payload=True,
312308
)
313309

314-
results: list[Document] = []
310+
results: list[QdrantRecord] = []
315311
for point in response.points:
316312
payload = point.payload or {}
317313
doc = self._as_document(payload, score=float(point.score or 0.0))
318314
results.append(doc)
319315
return results
320316

321-
def scroll(self, *, filters: dict[str, Any] | None = None, limit: int = 1000) -> list[dict[str, Any]]:
317+
def scroll(self, *, filters: dict[str, Any] | None = None, limit: int = 1000) -> list[QdrantRecord]:
322318
records, _ = self.client.scroll(
323319
collection_name=self.collection_name,
324320
scroll_filter=self._scoped_filter(filters),
325321
limit=limit,
326322
with_payload=True,
327323
with_vectors=False,
328324
)
329-
return [record.payload or {} for record in records]
325+
return [QdrantRecord(record.payload or {}) for record in records]
330326

331327
def delete(self, *, filters: dict[str, Any] | None = None) -> None:
332328
self.client.delete(

0 commit comments

Comments
 (0)