Skip to content

Commit 84e2029

Browse files
committed
Fix ChromaDB compatibility for 1.5.8
- Adapts `select_collection` to ensure collection metadata is correctly applied for existing collections, addressing a change in `get_or_create_collection` behavior. - Standardizes embedding output by converting NumPy arrays to Python lists in `peek`, `get_data`, and `query` methods, maintaining consistent data types. - Refines raw data extraction for recovery by explicitly filtering for 'VECTOR' scope, preventing the inclusion of sparse vector definitions.
1 parent 093669f commit 84e2029

2 files changed

Lines changed: 42 additions & 6 deletions

File tree

src/agentforge/storage/chroma_recover.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,11 +111,12 @@ def extract_raw_data(db_path: str, collection_uuid: str) -> Dict[str, List[Any]]
111111
logger.info("Extracting data based on exact DB Schema...")
112112

113113
# 1. Map internal integer IDs to the user's string IDs
114+
# 1.5.8 Fix: Explicitly filter by scope = 'VECTOR' to avoid reading Sparse Vector definitions
114115
cursor.execute("""
115116
SELECT e.id, e.embedding_id
116117
FROM embeddings e
117118
JOIN segments s ON e.segment_id = s.id
118-
WHERE s.collection = ?
119+
WHERE s.collection = ? AND s.scope = 'VECTOR'
119120
""", (collection_uuid,))
120121

121122
id_map = {row[0]: row[1] for row in cursor.fetchall()}

src/agentforge/storage/chroma_storage.py

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -399,21 +399,34 @@ def collection_list(self):
399399
return self.client.list_collections()
400400

401401
@auto_recover
402-
def select_collection(self, collection_name: str):
402+
def select_collection(self, collection_name: str, metadata: dict = None):
403403
"""
404404
Selects (or creates if not existent) a collection within the storage by name.
405405
406406
Parameters:
407407
collection_name (str): The name of the collection to select or create.
408+
metadata (dict, optional): Metadata to apply to the collection. Defaults to {"hnsw:space": "cosine"}.
408409
409410
Raises:
410411
ValueError: If there's an error in getting or creating the collection.
411412
"""
412413
try:
413414
collection_name = validate_collection_name(collection_name)
414-
self.collection = self.client.get_or_create_collection(name=collection_name,
415-
embedding_function=self.embedding,
416-
metadata={"hnsw:space": "cosine"})
415+
# 1.5.8 Fix: allow metadata override, default to cosine space
416+
collection_metadata = metadata if metadata is not None else {"hnsw:space": "cosine"}
417+
418+
self.collection = self.client.get_or_create_collection(
419+
name=collection_name,
420+
embedding_function=self.embedding,
421+
metadata=collection_metadata
422+
)
423+
424+
# 1.5.8 Fix: get_or_create_collection no longer overwrites metadata for existing collections.
425+
# Explicitly modify it to guarantee enforcement if it already existed.
426+
try:
427+
self.collection.modify(metadata=collection_metadata)
428+
except Exception:
429+
pass # Silently ignore if collection doesn't permit metadata change
417430
except Exception as e:
418431
raise ValueError(f"\n\nError getting or creating collection. Error: {e}")
419432

@@ -463,6 +476,13 @@ def peek(self, collection_name: str):
463476

464477
if num_results > 0:
465478
result = self.collection.peek()
479+
480+
# 1.5.8 Fix: Convert numpy array embeddings back into standard Python lists
481+
if result and result.get('embeddings') is not None:
482+
result['embeddings'] = [
483+
e.tolist() if hasattr(e, 'tolist') else e
484+
for e in result['embeddings']
485+
]
466486
else:
467487
result = {'documents': "No Results!"}
468488

@@ -500,6 +520,14 @@ def load_collection(self, collection_name: str, include: list = None, where: dic
500520
try:
501521
self.select_collection(collection_name)
502522
data = self.collection.get(**params)
523+
524+
# 1.5.8 Fix: Convert numpy array embeddings back into standard Python lists
525+
if data and data.get('embeddings') is not None:
526+
data['embeddings'] = [
527+
e.tolist() if hasattr(e, 'tolist') else e
528+
for e in data['embeddings']
529+
]
530+
503531
logger.debug(
504532
f"\nCollection: {collection_name}"
505533
f"\nData: {data}",
@@ -609,7 +637,14 @@ def query_storage(self, collection_name: str, query: Optional[Union[str, list]]
609637
if unformatted_result:
610638
for key, value in unformatted_result.items():
611639
if value:
612-
result[key] = value[0]
640+
# 1.5.8 Fix: Convert nested numpy arrays inside value[0] back into standard Python lists
641+
if key == 'embeddings' and value[0] is not None:
642+
result[key] = [
643+
e.tolist() if hasattr(e, 'tolist') else e
644+
for e in value[0]
645+
]
646+
else:
647+
result[key] = value[0]
613648

614649
return result
615650

0 commit comments

Comments
 (0)