crewplus 0.2.52__tar.gz → 0.2.54__tar.gz

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.

Potentially problematic release.


This version of crewplus might be problematic. Click here for more details.

Files changed (24) hide show
  1. {crewplus-0.2.52 → crewplus-0.2.54}/PKG-INFO +1 -1
  2. {crewplus-0.2.52 → crewplus-0.2.54}/crewplus/vectorstores/milvus/vdb_service.py +57 -16
  3. {crewplus-0.2.52 → crewplus-0.2.54}/pyproject.toml +1 -1
  4. {crewplus-0.2.52 → crewplus-0.2.54}/LICENSE +0 -0
  5. {crewplus-0.2.52 → crewplus-0.2.54}/README.md +0 -0
  6. {crewplus-0.2.52 → crewplus-0.2.54}/crewplus/__init__.py +0 -0
  7. {crewplus-0.2.52 → crewplus-0.2.54}/crewplus/callbacks/__init__.py +0 -0
  8. {crewplus-0.2.52 → crewplus-0.2.54}/crewplus/callbacks/async_langfuse_handler.py +0 -0
  9. {crewplus-0.2.52 → crewplus-0.2.54}/crewplus/services/__init__.py +0 -0
  10. {crewplus-0.2.52 → crewplus-0.2.54}/crewplus/services/azure_chat_model.py +0 -0
  11. {crewplus-0.2.52 → crewplus-0.2.54}/crewplus/services/gemini_chat_model.py +0 -0
  12. {crewplus-0.2.52 → crewplus-0.2.54}/crewplus/services/init_services.py +0 -0
  13. {crewplus-0.2.52 → crewplus-0.2.54}/crewplus/services/model_load_balancer.py +0 -0
  14. {crewplus-0.2.52 → crewplus-0.2.54}/crewplus/services/tracing_manager.py +0 -0
  15. {crewplus-0.2.52 → crewplus-0.2.54}/crewplus/utils/__init__.py +0 -0
  16. {crewplus-0.2.52 → crewplus-0.2.54}/crewplus/utils/schema_action.py +0 -0
  17. {crewplus-0.2.52 → crewplus-0.2.54}/crewplus/utils/schema_document_updater.py +0 -0
  18. {crewplus-0.2.52 → crewplus-0.2.54}/crewplus/vectorstores/milvus/__init__.py +0 -0
  19. {crewplus-0.2.52 → crewplus-0.2.54}/crewplus/vectorstores/milvus/milvus_schema_manager.py +0 -0
  20. {crewplus-0.2.52 → crewplus-0.2.54}/crewplus/vectorstores/milvus/schema_milvus.py +0 -0
  21. {crewplus-0.2.52 → crewplus-0.2.54}/docs/GeminiChatModel.md +0 -0
  22. {crewplus-0.2.52 → crewplus-0.2.54}/docs/ModelLoadBalancer.md +0 -0
  23. {crewplus-0.2.52 → crewplus-0.2.54}/docs/VDBService.md +0 -0
  24. {crewplus-0.2.52 → crewplus-0.2.54}/docs/index.md +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: crewplus
3
- Version: 0.2.52
3
+ Version: 0.2.54
4
4
  Summary: Base services for CrewPlus AI applications
5
5
  Author-Email: Tim Liu <tim@opsmateai.com>
6
6
  License: MIT
@@ -95,6 +95,7 @@ class VDBService(object):
95
95
  _client: MilvusClient
96
96
  _async_client: AsyncMilvusClient
97
97
  _instances: Dict[str, Milvus] = {}
98
+ _async_instances: Dict[str, Milvus] = {}
98
99
 
99
100
  schema: str
100
101
  embedding_function: Embeddings
@@ -153,8 +154,13 @@ class VDBService(object):
153
154
  self.logger.error(msg)
154
155
  raise ValueError(msg)
155
156
 
156
- self.alias = f"crewplus-vdb-{uuid.uuid4()}"
157
- self.connection_args['alias'] = self.alias
157
+ # Create separate aliases for sync and async clients to avoid connection handler race conditions.
158
+ self.sync_alias = f"crewplus-vdb-sync-{uuid.uuid4()}"
159
+ self.async_alias = f"crewplus-vdb-async-{uuid.uuid4()}"
160
+
161
+ # The default alias in connection_args should be the sync one, as langchain_milvus
162
+ # primarily uses a synchronous client and will pick up this alias.
163
+ self.connection_args['alias'] = self.sync_alias
158
164
 
159
165
  self._client = self._initialize_milvus_client(provider)
160
166
  self._async_client = self._initialize_async_milvus_client(provider)
@@ -183,12 +189,14 @@ class VDBService(object):
183
189
  "user": self.connection_args.get("user"),
184
190
  "password": self.connection_args.get("password"),
185
191
  "db_name": self.connection_args.get("db_name"),
186
- "alias": self.connection_args.get("alias")
187
192
  }
188
193
  return {k: v for k, v in client_args.items() if v is not None}
189
194
 
190
195
  elif provider == "zilliz":
191
- return self.connection_args
196
+ # Return a copy without the default alias, as it will be added specifically for sync/async clients.
197
+ zilliz_args = self.connection_args.copy()
198
+ zilliz_args.pop('alias', None)
199
+ return zilliz_args
192
200
  else:
193
201
  self.logger.error(f"Unsupported vector store provider: {provider}")
194
202
  raise NotImplementedError(f"Vector store provider '{provider}' is not supported.")
@@ -198,6 +206,7 @@ class VDBService(object):
198
206
  Initializes and returns a MilvusClient with a retry mechanism.
199
207
  """
200
208
  client_args = self._get_milvus_client_args(provider)
209
+ client_args["alias"] = self.sync_alias
201
210
 
202
211
  try:
203
212
  # First attempt to connect
@@ -216,6 +225,8 @@ class VDBService(object):
216
225
  Initializes and returns an AsyncMilvusClient with a retry mechanism.
217
226
  """
218
227
  client_args = self._get_milvus_client_args(provider)
228
+ client_args["alias"] = self.async_alias
229
+
219
230
  try:
220
231
  return AsyncMilvusClient(**client_args)
221
232
  except Exception as e:
@@ -245,6 +256,30 @@ class VDBService(object):
245
256
  """
246
257
  return self._async_client
247
258
 
259
+ def get_vector_field(self, collection_name: str) -> str:
260
+ """
261
+ Retrieves the vector field name for a given collection from a cached instance.
262
+
263
+ Args:
264
+ collection_name (str): The name of the collection.
265
+
266
+ Returns:
267
+ str: The name of the vector field.
268
+
269
+ Raises:
270
+ ValueError: If no cached instance is found for the collection.
271
+ """
272
+ if collection_name in self._instances:
273
+ return self._instances[collection_name]._vector_field
274
+ if collection_name in self._async_instances:
275
+ return self._async_instances[collection_name]._vector_field
276
+
277
+ self.logger.warning(f"No cached instance found for collection '{collection_name}' to get vector field. Creating a temporary sync instance.")
278
+ # As a fallback, create a temporary sync instance to fetch the schema info.
279
+ # This is less efficient but ensures the method is robust.
280
+ temp_instance = self.get_vector_store(collection_name)
281
+ return temp_instance._vector_field
282
+
248
283
  def get_embeddings(self, from_model_balancer: bool = False, provider: Optional[str] = "azure-openai", model_type: Optional[str] = "embedding-large") -> Embeddings:
249
284
  """
250
285
  Gets an embedding function, either from the model balancer or directly from settings.
@@ -472,21 +507,21 @@ class VDBService(object):
472
507
  raise ValueError("collection_name must be provided.")
473
508
 
474
509
  check_existence = True
475
- if collection_name in self._instances:
476
- instance = self._instances[collection_name]
510
+ if collection_name in self._async_instances:
511
+ instance = self._async_instances[collection_name]
477
512
  is_connected, collection_exists = await self._ais_good_connection(instance, collection_name)
478
513
 
479
514
  if is_connected and collection_exists:
480
- self.logger.info(f"Returning existing vector store instance for collection: {collection_name}")
515
+ self.logger.info(f"Returning existing async vector store instance for collection: {collection_name}")
481
516
  return instance
482
517
 
483
- self.logger.warning(f"Cached instance for '{collection_name}' is invalid. Removing it from cache.")
484
- del self._instances[collection_name]
518
+ self.logger.warning(f"Cached async instance for '{collection_name}' is invalid. Removing it from cache.")
519
+ del self._async_instances[collection_name]
485
520
 
486
521
  if is_connected and not collection_exists:
487
522
  check_existence = False
488
523
 
489
- self.logger.info(f"Creating new vector store instance for collection: {collection_name}")
524
+ self.logger.info(f"Creating new async vector store instance for collection: {collection_name}")
490
525
  if embeddings is None:
491
526
  embeddings = self.get_embeddings()
492
527
 
@@ -509,28 +544,34 @@ class VDBService(object):
509
544
  "params": {}
510
545
  }
511
546
 
547
+ # Prepare connection args with the specific async alias
548
+ async_connection_args = self.connection_args.copy()
549
+ async_connection_args["alias"] = self.async_alias
550
+
512
551
  vdb = await asyncio.to_thread(
513
552
  self._create_milvus_instance_with_retry,
514
553
  collection_name=collection_name,
515
554
  embeddings=embeddings,
516
- index_params=index_params
555
+ index_params=index_params,
556
+ connection_args=async_connection_args
517
557
  )
518
558
 
519
- self._instances[collection_name] = vdb
559
+ self._async_instances[collection_name] = vdb
520
560
 
521
561
  return vdb
522
562
 
523
- def _create_milvus_instance_with_retry(self, collection_name: str, embeddings: Embeddings, index_params: dict) -> Milvus:
563
+ def _create_milvus_instance_with_retry(self, collection_name: str, embeddings: Embeddings, index_params: dict, connection_args: Optional[dict] = None) -> Milvus:
524
564
  """
525
565
  Creates a Milvus instance with a retry mechanism for connection failures.
526
566
  """
527
567
  retries = 2
568
+ conn_args = connection_args if connection_args is not None else self.connection_args
528
569
  for attempt in range(retries + 1):
529
570
  try:
530
571
  vdb = Milvus(
531
572
  embedding_function=embeddings,
532
573
  collection_name=collection_name,
533
- connection_args=self.connection_args,
574
+ connection_args=conn_args,
534
575
  index_params=index_params
535
576
  )
536
577
  self.logger.info(f"Successfully connected to Milvus for collection '{collection_name}' on attempt {attempt + 1}.")
@@ -602,8 +643,8 @@ class VDBService(object):
602
643
  raise RuntimeError(f"An error occurred while dropping collection '{collection_name}' asynchronously.") from e
603
644
  finally:
604
645
  # Whether successful or not, remove the stale instance from the cache.
605
- if collection_name in self._instances:
606
- del self._instances[collection_name]
646
+ if collection_name in self._async_instances:
647
+ del self._async_instances[collection_name]
607
648
  self.logger.info(f"Removed '{collection_name}' from instance cache.")
608
649
 
609
650
  def delete_data_by_filter(self, collection_name: str = None, filter: str = None) -> None:
@@ -6,7 +6,7 @@ build-backend = "pdm.backend"
6
6
 
7
7
  [project]
8
8
  name = "crewplus"
9
- version = "0.2.52"
9
+ version = "0.2.54"
10
10
  description = "Base services for CrewPlus AI applications"
11
11
  authors = [
12
12
  { name = "Tim Liu", email = "tim@opsmateai.com" },
File without changes
File without changes
File without changes
File without changes