hammad-python 0.0.19__py3-none-any.whl → 0.0.20__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. hammad/__init__.py +7 -137
  2. hammad/_internal.py +1 -0
  3. hammad/cli/_runner.py +8 -8
  4. hammad/cli/plugins.py +55 -26
  5. hammad/cli/styles/utils.py +16 -8
  6. hammad/data/__init__.py +1 -5
  7. hammad/data/collections/__init__.py +2 -3
  8. hammad/data/collections/collection.py +41 -22
  9. hammad/data/collections/indexes/__init__.py +1 -1
  10. hammad/data/collections/indexes/qdrant/__init__.py +1 -1
  11. hammad/data/collections/indexes/qdrant/index.py +106 -118
  12. hammad/data/collections/indexes/qdrant/settings.py +14 -14
  13. hammad/data/collections/indexes/qdrant/utils.py +28 -38
  14. hammad/data/collections/indexes/tantivy/__init__.py +1 -1
  15. hammad/data/collections/indexes/tantivy/index.py +57 -59
  16. hammad/data/collections/indexes/tantivy/settings.py +8 -19
  17. hammad/data/collections/indexes/tantivy/utils.py +28 -52
  18. hammad/data/models/__init__.py +2 -7
  19. hammad/data/sql/__init__.py +1 -1
  20. hammad/data/sql/database.py +71 -73
  21. hammad/data/sql/types.py +37 -51
  22. hammad/formatting/__init__.py +2 -1
  23. hammad/formatting/json/converters.py +2 -2
  24. hammad/genai/__init__.py +96 -36
  25. hammad/genai/agents/__init__.py +47 -1
  26. hammad/genai/agents/agent.py +1022 -0
  27. hammad/genai/agents/run.py +615 -0
  28. hammad/genai/agents/types/__init__.py +29 -22
  29. hammad/genai/agents/types/agent_context.py +13 -0
  30. hammad/genai/agents/types/agent_event.py +128 -0
  31. hammad/genai/agents/types/agent_hooks.py +220 -0
  32. hammad/genai/agents/types/agent_messages.py +31 -0
  33. hammad/genai/agents/types/agent_response.py +90 -0
  34. hammad/genai/agents/types/agent_stream.py +242 -0
  35. hammad/genai/models/__init__.py +1 -0
  36. hammad/genai/models/embeddings/__init__.py +39 -0
  37. hammad/genai/{embedding_models/embedding_model.py → models/embeddings/model.py} +45 -41
  38. hammad/genai/{embedding_models → models/embeddings}/run.py +10 -8
  39. hammad/genai/models/embeddings/types/__init__.py +37 -0
  40. hammad/genai/{embedding_models → models/embeddings/types}/embedding_model_name.py +2 -4
  41. hammad/genai/{embedding_models → models/embeddings/types}/embedding_model_response.py +11 -4
  42. hammad/genai/{embedding_models/embedding_model_request.py → models/embeddings/types/embedding_model_run_params.py} +4 -3
  43. hammad/genai/models/embeddings/types/embedding_model_settings.py +47 -0
  44. hammad/genai/models/language/__init__.py +48 -0
  45. hammad/genai/{language_models/language_model.py → models/language/model.py} +481 -204
  46. hammad/genai/{language_models → models/language}/run.py +80 -57
  47. hammad/genai/models/language/types/__init__.py +40 -0
  48. hammad/genai/models/language/types/language_model_instructor_mode.py +47 -0
  49. hammad/genai/models/language/types/language_model_messages.py +28 -0
  50. hammad/genai/{language_models/_types.py → models/language/types/language_model_name.py} +3 -40
  51. hammad/genai/{language_models → models/language/types}/language_model_request.py +17 -25
  52. hammad/genai/{language_models → models/language/types}/language_model_response.py +61 -68
  53. hammad/genai/{language_models → models/language/types}/language_model_response_chunk.py +8 -5
  54. hammad/genai/models/language/types/language_model_settings.py +89 -0
  55. hammad/genai/{language_models/_streaming.py → models/language/types/language_model_stream.py} +221 -243
  56. hammad/genai/{language_models/_utils → models/language/utils}/__init__.py +8 -11
  57. hammad/genai/models/language/utils/requests.py +421 -0
  58. hammad/genai/{language_models/_utils/_structured_outputs.py → models/language/utils/structured_outputs.py} +31 -20
  59. hammad/genai/models/model_provider.py +4 -0
  60. hammad/genai/{multimodal_models.py → models/multimodal.py} +4 -5
  61. hammad/genai/models/reranking.py +26 -0
  62. hammad/genai/types/__init__.py +1 -0
  63. hammad/genai/types/base.py +215 -0
  64. hammad/genai/{agents/types → types}/history.py +101 -88
  65. hammad/genai/{agents/types/tool.py → types/tools.py} +156 -141
  66. hammad/logging/logger.py +1 -1
  67. hammad/mcp/client/__init__.py +2 -3
  68. hammad/mcp/client/client.py +10 -10
  69. hammad/mcp/servers/__init__.py +2 -1
  70. hammad/service/decorators.py +1 -3
  71. hammad/web/models.py +1 -3
  72. hammad/web/search/client.py +10 -22
  73. {hammad_python-0.0.19.dist-info → hammad_python-0.0.20.dist-info}/METADATA +10 -2
  74. hammad_python-0.0.20.dist-info/RECORD +127 -0
  75. hammad/genai/embedding_models/__init__.py +0 -41
  76. hammad/genai/language_models/__init__.py +0 -35
  77. hammad/genai/language_models/_utils/_completions.py +0 -131
  78. hammad/genai/language_models/_utils/_messages.py +0 -89
  79. hammad/genai/language_models/_utils/_requests.py +0 -202
  80. hammad/genai/rerank_models.py +0 -26
  81. hammad_python-0.0.19.dist-info/RECORD +0 -111
  82. {hammad_python-0.0.19.dist-info → hammad_python-0.0.20.dist-info}/WHEEL +0 -0
  83. {hammad_python-0.0.19.dist-info → hammad_python-0.0.20.dist-info}/licenses/LICENSE +0 -0
@@ -12,11 +12,11 @@ from typing import (
12
12
  final,
13
13
  TYPE_CHECKING,
14
14
  Tuple,
15
- NamedTuple
15
+ NamedTuple,
16
16
  )
17
17
 
18
18
  if TYPE_CHECKING:
19
- from .....genai.embedding_models.embedding_model_name import EmbeddingModelName
19
+ from .....genai.models.embeddings.types import EmbeddingModelName
20
20
  # import uuid # Unused import
21
21
  from pathlib import Path
22
22
  import json
@@ -34,9 +34,11 @@ from .settings import (
34
34
  DistanceMetric,
35
35
  )
36
36
 
37
+
37
38
  class VectorSearchResult(NamedTuple):
38
39
  """Result from vector search containing item and similarity score."""
39
- item: 'DatabaseItem[DatabaseItemType]'
40
+
41
+ item: "DatabaseItem[DatabaseItemType]"
40
42
  score: float
41
43
 
42
44
 
@@ -50,7 +52,7 @@ __all__ = (
50
52
  class QdrantCollectionIndex:
51
53
  """A vector collection index that uses Qdrant for vector storage
52
54
  and similarity search, with SQL Database as the primary storage backend.
53
-
55
+
54
56
  This collection index provides vector-based functionality for storing
55
57
  embeddings and performing semantic similarity searches while using
56
58
  the Database class for reliable data persistence.
@@ -77,7 +79,7 @@ class QdrantCollectionIndex:
77
79
  ) -> None:
78
80
  """
79
81
  Initialize a new QdrantCollectionIndex.
80
-
82
+
81
83
  Args:
82
84
  name: The name of the index.
83
85
  vector_size: Size/dimension of the vectors to store.
@@ -105,7 +107,7 @@ class QdrantCollectionIndex:
105
107
  self.embedding_api_key = embedding_api_key
106
108
  self.embedding_base_url = embedding_base_url
107
109
  self._embedding_function = None
108
-
110
+
109
111
  # Rerank model configuration
110
112
  self.rerank_model = rerank_model
111
113
  self.rerank_api_key = rerank_api_key
@@ -121,7 +123,7 @@ class QdrantCollectionIndex:
121
123
  qdrant_path = None
122
124
  if self.path is not None:
123
125
  qdrant_path = str(self.path / f"{name}_qdrant")
124
-
126
+
125
127
  settings = QdrantCollectionIndexSettings(
126
128
  vector_size=vector_size or 768, # Default fallback
127
129
  distance_metric=distance_metric,
@@ -138,13 +140,13 @@ class QdrantCollectionIndex:
138
140
  database_path = None
139
141
  if self.path is not None:
140
142
  database_path = self.path / f"{name}.db"
141
-
143
+
142
144
  self._database = Database[DatabaseItemType](
143
145
  name=name,
144
146
  schema=schema,
145
147
  ttl=ttl,
146
148
  path=database_path,
147
- table_name=f"qdrant_{name}"
149
+ table_name=f"qdrant_{name}",
148
150
  )
149
151
 
150
152
  # Initialize Qdrant client (lazily to handle import errors gracefully)
@@ -159,17 +161,14 @@ class QdrantCollectionIndex:
159
161
  try:
160
162
  self._client = utils.create_qdrant_client(self.settings)
161
163
  self._client_wrapper = utils.QdrantClientWrapper(
162
- client=self._client,
163
- collection_name=self.name
164
+ client=self._client, collection_name=self.name
164
165
  )
165
-
166
+
166
167
  # Create collection if it doesn't exist
167
168
  utils.create_collection_if_not_exists(
168
- self._client,
169
- self.name,
170
- self.settings
169
+ self._client, self.name, self.settings
171
170
  )
172
-
171
+
173
172
  except utils.QdrantCollectionIndexError:
174
173
  # Qdrant not available - only SQL storage will work
175
174
  self._client = None
@@ -178,17 +177,17 @@ class QdrantCollectionIndex:
178
177
  def _get_embedding_function(self) -> Optional[Callable[[Any], List[float]]]:
179
178
  """Get or create embedding function from model configuration."""
180
179
  if self._embedding_function is None and self.embedding_model:
181
- from .....genai.embedding_models.embedding_model import EmbeddingModel
182
-
180
+ from .....genai.models.embeddings.model import EmbeddingModel
181
+
183
182
  model = EmbeddingModel(model=self.embedding_model)
184
-
183
+
185
184
  def embedding_function(item: Any) -> List[float]:
186
185
  response = model.run(
187
186
  input=item,
188
187
  dimensions=self.embedding_dimensions,
189
188
  api_key=self.embedding_api_key,
190
189
  api_base=self.embedding_base_url,
191
- format=True
190
+ format=True,
192
191
  )
193
192
  if response.data and len(response.data) > 0:
194
193
  return response.data[0].embedding
@@ -196,34 +195,34 @@ class QdrantCollectionIndex:
196
195
  raise utils.QdrantCollectionIndexError(
197
196
  "Failed to generate embedding: empty response"
198
197
  )
199
-
198
+
200
199
  self._embedding_function = embedding_function
201
-
200
+
202
201
  return self._embedding_function
203
-
202
+
204
203
  def _rerank_results(
205
- self,
206
- query: str,
204
+ self,
205
+ query: str,
207
206
  results: List[Tuple[DatabaseItem[DatabaseItemType], float]],
208
- top_n: Optional[int] = None
207
+ top_n: Optional[int] = None,
209
208
  ) -> List[Tuple[DatabaseItem[DatabaseItemType], float]]:
210
209
  """
211
210
  Rerank search results using the configured rerank model.
212
-
211
+
213
212
  Args:
214
213
  query: The original search query
215
214
  results: List of (DatabaseItem, similarity_score) tuples
216
215
  top_n: Number of top results to return after reranking
217
-
216
+
218
217
  Returns:
219
218
  Reranked list of (DatabaseItem, rerank_score) tuples
220
219
  """
221
220
  if not self.rerank_model or not results:
222
221
  return results
223
-
222
+
224
223
  try:
225
- from .....genai.rerank_models import run_rerank_model
226
-
224
+ from .....genai.models.reranking import run_reranking_model
225
+
227
226
  # Extract documents for reranking
228
227
  documents = []
229
228
  for db_item, _ in results:
@@ -233,17 +232,17 @@ class QdrantCollectionIndex:
233
232
  else:
234
233
  doc_text = str(db_item.item)
235
234
  documents.append(doc_text)
236
-
235
+
237
236
  # Perform reranking
238
- rerank_response = run_rerank_model(
237
+ rerank_response = run_reranking_model(
239
238
  model=self.rerank_model,
240
239
  query=query,
241
240
  documents=documents,
242
241
  top_n=top_n or len(results),
243
242
  api_key=self.rerank_api_key,
244
- api_base=self.rerank_base_url
243
+ api_base=self.rerank_base_url,
245
244
  )
246
-
245
+
247
246
  # Reorder results based on rerank scores
248
247
  reranked_results = []
249
248
  for rerank_result in rerank_response.results:
@@ -253,13 +252,13 @@ class QdrantCollectionIndex:
253
252
  # Update the score on the DatabaseItem itself
254
253
  db_item.score = rerank_score
255
254
  reranked_results.append((db_item, rerank_score))
256
-
255
+
257
256
  return reranked_results
258
-
257
+
259
258
  except Exception:
260
259
  # If reranking fails, return original results
261
260
  return results
262
-
261
+
263
262
  def _prepare_vector(self, item: Any) -> List[float]:
264
263
  """Prepare vector from item using embedding function or direct vector."""
265
264
  embedding_function = self._get_embedding_function()
@@ -291,11 +290,11 @@ class QdrantCollectionIndex:
291
290
  if not self._vector_size_determined:
292
291
  self.vector_size = size
293
292
  self._vector_size_determined = True
294
-
293
+
295
294
  # Update settings with determined vector size
296
295
  if self.settings:
297
296
  self.settings.vector_size = size
298
-
297
+
299
298
  # Initialize Qdrant client now that we have vector size
300
299
  self._init_qdrant_client()
301
300
 
@@ -310,38 +309,31 @@ class QdrantCollectionIndex:
310
309
  if not self._client:
311
310
  # Qdrant not available, skip vector indexing
312
311
  return
313
-
312
+
314
313
  try:
315
314
  try:
316
315
  from qdrant_client.models import PointStruct
317
316
  except ImportError:
318
317
  raise ImportError(
319
- "Using Qdrant requires the `qdrant-client` package. Please install with: pip install 'hammad-python[ai]'"
318
+ "Using Qdrant requires the `qdrant-client` package. Please install with: pip install 'hammad-python[genai]'"
320
319
  )
321
-
320
+
322
321
  # Prepare payload with metadata
323
322
  payload = {
324
323
  "item_data": json.dumps(utils.serialize(item)),
325
324
  "created_at": datetime.now(timezone.utc).isoformat(),
326
325
  }
327
-
326
+
328
327
  # Add filters as top-level payload fields
329
328
  if filters:
330
329
  for key, value in filters.items():
331
330
  payload[key] = value
332
331
 
333
332
  # Create point and upsert to Qdrant
334
- point = PointStruct(
335
- id=item_id,
336
- vector=vector,
337
- payload=payload
338
- )
333
+ point = PointStruct(id=item_id, vector=vector, payload=payload)
334
+
335
+ self._client.upsert(collection_name=self.name, points=[point])
339
336
 
340
- self._client.upsert(
341
- collection_name=self.name,
342
- points=[point]
343
- )
344
-
345
337
  except Exception:
346
338
  # Vector indexing failed, but data is still in SQL database
347
339
  pass
@@ -357,14 +349,14 @@ class QdrantCollectionIndex:
357
349
  ) -> str:
358
350
  """
359
351
  Add an item to the index.
360
-
352
+
361
353
  Args:
362
354
  item: The item to store.
363
355
  id: Optional ID (will generate UUID if not provided).
364
356
  filters: Optional filters/metadata.
365
357
  ttl: Optional TTL in seconds.
366
358
  vector: Optional pre-computed vector (if not provided, will use embedding_function).
367
-
359
+
368
360
  Returns:
369
361
  The ID of the stored item.
370
362
  """
@@ -375,7 +367,7 @@ class QdrantCollectionIndex:
375
367
  filters=filters,
376
368
  ttl=ttl,
377
369
  )
378
-
370
+
379
371
  # Prepare vector for Qdrant storage
380
372
  if vector is None:
381
373
  try:
@@ -385,10 +377,10 @@ class QdrantCollectionIndex:
385
377
  return item_id
386
378
  else:
387
379
  prepared_vector = utils.prepare_vector(vector, self.vector_size)
388
-
380
+
389
381
  # Add to Qdrant vector store
390
382
  self._add_to_qdrant(item_id, prepared_vector, item, filters)
391
-
383
+
392
384
  return item_id
393
385
 
394
386
  def get(
@@ -399,11 +391,11 @@ class QdrantCollectionIndex:
399
391
  ) -> Optional[DatabaseItem[DatabaseItemType]]:
400
392
  """
401
393
  Get an item by ID.
402
-
394
+
403
395
  Args:
404
396
  id: The item ID.
405
397
  filters: Optional filters to match.
406
-
398
+
407
399
  Returns:
408
400
  The database item or None if not found.
409
401
  """
@@ -422,7 +414,7 @@ class QdrantCollectionIndex:
422
414
  ) -> Union[List[DatabaseItem[DatabaseItemType]], List[VectorSearchResult]]:
423
415
  """
424
416
  Internal method to perform vector similarity search.
425
-
417
+
426
418
  Args:
427
419
  query_vector: Query vector for similarity search.
428
420
  filters: Optional filters to apply.
@@ -431,7 +423,7 @@ class QdrantCollectionIndex:
431
423
  query_text: Optional original query text for reranking.
432
424
  enable_rerank: Whether to enable reranking if rerank model is configured.
433
425
  return_scores: Whether to return scores with results.
434
-
426
+
435
427
  Returns:
436
428
  List of matching database items sorted by similarity score (and reranked if enabled),
437
429
  or list of VectorSearchResult objects if return_scores is True.
@@ -439,14 +431,14 @@ class QdrantCollectionIndex:
439
431
  if not self._client:
440
432
  # Qdrant not available, return empty results
441
433
  return []
442
-
434
+
443
435
  # Prepare query vector
444
436
  prepared_vector = utils.prepare_vector(query_vector, self.vector_size)
445
-
437
+
446
438
  try:
447
439
  # Build Qdrant filter
448
440
  qdrant_filter = utils.build_qdrant_filter(filters)
449
-
441
+
450
442
  # Perform search
451
443
  results = self._client.query_points(
452
444
  collection_name=self.name,
@@ -457,7 +449,7 @@ class QdrantCollectionIndex:
457
449
  with_payload=True,
458
450
  with_vectors=False,
459
451
  )
460
-
452
+
461
453
  # Get item IDs from results and fetch from database with scores
462
454
  db_items_with_scores = []
463
455
  for result in results.points:
@@ -467,23 +459,24 @@ class QdrantCollectionIndex:
467
459
  # Set the score on the DatabaseItem itself
468
460
  db_item.score = result.score
469
461
  db_items_with_scores.append((db_item, result.score))
470
-
462
+
471
463
  # Apply reranking if enabled and configured
472
464
  if enable_rerank and self.rerank_model and query_text:
473
465
  db_items_with_scores = self._rerank_results(
474
- query=query_text,
475
- results=db_items_with_scores,
476
- top_n=limit
466
+ query=query_text, results=db_items_with_scores, top_n=limit
477
467
  )
478
-
468
+
479
469
  # Return results with or without scores based on return_scores parameter
480
470
  if return_scores:
481
- return [VectorSearchResult(item=item, score=score) for item, score in db_items_with_scores]
471
+ return [
472
+ VectorSearchResult(item=item, score=score)
473
+ for item, score in db_items_with_scores
474
+ ]
482
475
  else:
483
476
  # Extract just the database items (without scores) for backward compatibility
484
477
  db_items = [item for item, score in db_items_with_scores]
485
478
  return db_items
486
-
479
+
487
480
  except Exception:
488
481
  # Vector search failed, return empty results
489
482
  return []
@@ -501,7 +494,7 @@ class QdrantCollectionIndex:
501
494
  ) -> Union[List[DatabaseItem[DatabaseItemType]], List[VectorSearchResult]]:
502
495
  """
503
496
  Query items from the collection.
504
-
497
+
505
498
  Args:
506
499
  query: Search query string.
507
500
  filters: Optional filters to apply.
@@ -510,12 +503,12 @@ class QdrantCollectionIndex:
510
503
  rerank: Whether to use reranking (requires rerank_model to be configured).
511
504
  query_vector: Optional pre-computed query vector for similarity search.
512
505
  return_scores: Whether to return similarity scores with results (only applies to vector search).
513
-
506
+
514
507
  Returns:
515
508
  List of matching database items, or list of VectorSearchResult objects if return_scores is True.
516
509
  """
517
510
  effective_limit = limit or self.query_settings.limit
518
-
511
+
519
512
  # If explicit vector is provided, use it directly
520
513
  if query_vector is not None:
521
514
  return self._vector_search(
@@ -527,16 +520,16 @@ class QdrantCollectionIndex:
527
520
  enable_rerank=rerank,
528
521
  return_scores=return_scores,
529
522
  )
530
-
523
+
531
524
  # If vector=True, use vector search with embedding model
532
525
  if vector:
533
526
  if not query:
534
527
  raise ValueError("Query string is required when vector=True")
535
-
528
+
536
529
  embedding_function = self._get_embedding_function()
537
530
  if not embedding_function:
538
531
  raise ValueError("Embedding model not configured for vector search")
539
-
532
+
540
533
  try:
541
534
  query_vector = embedding_function(query)
542
535
  return self._vector_search(
@@ -550,19 +543,19 @@ class QdrantCollectionIndex:
550
543
  )
551
544
  except Exception as e:
552
545
  raise ValueError(f"Failed to generate embedding for query: {e}")
553
-
546
+
554
547
  # If rerank=True but vector=False, perform both standard and vector search, then rerank
555
548
  if rerank and query:
556
549
  if not self.rerank_model:
557
550
  raise ValueError("Rerank model not configured")
558
-
551
+
559
552
  # Get results from both database and vector search (if possible)
560
553
  db_results = self._database.query(
561
554
  limit=effective_limit,
562
555
  order_by="created_at",
563
556
  ascending=False,
564
557
  )
565
-
558
+
566
559
  vector_results = []
567
560
  embedding_function = self._get_embedding_function()
568
561
  if embedding_function:
@@ -579,28 +572,26 @@ class QdrantCollectionIndex:
579
572
  )
580
573
  except Exception:
581
574
  pass
582
-
575
+
583
576
  # Combine and deduplicate results
584
577
  combined_results = []
585
578
  seen_ids = set()
586
-
579
+
587
580
  for result in db_results + vector_results:
588
581
  if result.id not in seen_ids:
589
582
  combined_results.append((result, 0.0)) # Score placeholder
590
583
  seen_ids.add(result.id)
591
-
584
+
592
585
  # Apply reranking to combined results
593
586
  if combined_results:
594
587
  reranked_results = self._rerank_results(
595
- query=query,
596
- results=combined_results,
597
- top_n=effective_limit
588
+ query=query, results=combined_results, top_n=effective_limit
598
589
  )
599
590
  # Scores are already set on the DatabaseItem objects by _rerank_results
600
591
  return [item for item, _ in reranked_results]
601
-
592
+
602
593
  return [item for item, _ in combined_results]
603
-
594
+
604
595
  # Default: fall back to database query
605
596
  return self._database.query(
606
597
  limit=effective_limit,
@@ -611,27 +602,24 @@ class QdrantCollectionIndex:
611
602
  def delete(self, id: str) -> bool:
612
603
  """
613
604
  Delete an item by ID.
614
-
605
+
615
606
  Args:
616
607
  id: The item ID.
617
-
608
+
618
609
  Returns:
619
610
  True if item was deleted, False if not found.
620
611
  """
621
612
  # Delete from database
622
613
  deleted = self._database.delete(id)
623
-
614
+
624
615
  if deleted and self._client:
625
616
  # Delete from Qdrant
626
617
  try:
627
- self._client.delete(
628
- collection_name=self.name,
629
- points_selector=[id]
630
- )
618
+ self._client.delete(collection_name=self.name, points_selector=[id])
631
619
  except Exception:
632
620
  # Vector deletion failed, but item was removed from database
633
621
  pass
634
-
622
+
635
623
  return deleted
636
624
 
637
625
  def count(
@@ -640,26 +628,28 @@ class QdrantCollectionIndex:
640
628
  ) -> int:
641
629
  """
642
630
  Count items matching the filters.
643
-
631
+
644
632
  Args:
645
633
  filters: Optional filters to apply.
646
-
634
+
647
635
  Returns:
648
636
  Number of matching items.
649
637
  """
650
638
  if not self._client:
651
639
  # Use database count
652
640
  from ....sql.types import QueryFilter, QueryCondition
653
-
641
+
654
642
  query_filter = None
655
643
  if filters:
656
644
  conditions = [
657
- QueryCondition(field="filters", operator="contains", value=json.dumps(filters))
645
+ QueryCondition(
646
+ field="filters", operator="contains", value=json.dumps(filters)
647
+ )
658
648
  ]
659
649
  query_filter = QueryFilter(conditions=conditions)
660
-
650
+
661
651
  return self._database.count(query_filter)
662
-
652
+
663
653
  try:
664
654
  # Use Qdrant count
665
655
  qdrant_filter = utils.build_qdrant_filter(filters)
@@ -676,38 +666,36 @@ class QdrantCollectionIndex:
676
666
  def clear(self) -> int:
677
667
  """
678
668
  Clear all items from the index.
679
-
669
+
680
670
  Returns:
681
671
  Number of items deleted.
682
672
  """
683
673
  count = self._database.clear()
684
-
674
+
685
675
  if self._client:
686
676
  # Clear Qdrant collection by recreating it
687
677
  try:
688
678
  utils.create_collection_if_not_exists(
689
- self._client,
690
- self.name,
691
- self.settings
679
+ self._client, self.name, self.settings
692
680
  )
693
681
  except Exception:
694
682
  pass
695
-
683
+
696
684
  return count
697
685
 
698
686
  def get_vector(self, id: str) -> Optional[List[float]]:
699
687
  """
700
688
  Get the vector for a specific item by ID.
701
-
689
+
702
690
  Args:
703
691
  id: The item ID.
704
-
692
+
705
693
  Returns:
706
694
  The vector or None if not found.
707
695
  """
708
696
  if not self._client:
709
697
  return None
710
-
698
+
711
699
  try:
712
700
  points = self._client.retrieve(
713
701
  collection_name=self.name,
@@ -715,16 +703,16 @@ class QdrantCollectionIndex:
715
703
  with_payload=False,
716
704
  with_vectors=True,
717
705
  )
718
-
706
+
719
707
  if not points:
720
708
  return None
721
-
709
+
722
710
  vector = points[0].vector
723
711
  if isinstance(vector, dict):
724
712
  # Handle named vectors if used
725
713
  return list(vector.values())[0] if vector else None
726
714
  return vector
727
-
715
+
728
716
  except Exception:
729
717
  return None
730
718
 
@@ -732,4 +720,4 @@ class QdrantCollectionIndex:
732
720
  """String representation of the index."""
733
721
  location = str(self.path) if self.path else "memory"
734
722
  vector_available = "yes" if self._client else "no"
735
- return f"<QdrantCollectionIndex name='{self.name}' location='{location}' vector_size={self.vector_size} qdrant_available={vector_available}>"
723
+ return f"<QdrantCollectionIndex name='{self.name}' location='{location}' vector_size={self.vector_size} qdrant_available={vector_available}>"