crewplus 0.2.70__py3-none-any.whl → 0.2.72__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.

Potentially problematic release.


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

@@ -1,6 +1,6 @@
1
1
  # File: crewplus/services/tracing_manager.py
2
2
 
3
- from typing import Any, Optional, List, Protocol
3
+ from typing import Any, Optional, List, Protocol, Dict
4
4
  import os
5
5
  import logging
6
6
 
@@ -9,11 +9,14 @@ import logging
9
9
  try:
10
10
  from langfuse.langchain import CallbackHandler as LangfuseCallbackHandler
11
11
  from ..callbacks.async_langfuse_handler import AsyncLangfuseCallbackHandler
12
+ from ..utils.tracing_util import get_langfuse_handler, get_async_langfuse_handler
12
13
  LANGFUSE_AVAILABLE = True
13
14
  except ImportError:
14
15
  LANGFUSE_AVAILABLE = False
15
16
  LangfuseCallbackHandler = None
16
17
  AsyncLangfuseCallbackHandler = None
18
+ get_langfuse_handler = None
19
+ get_async_langfuse_handler = None
17
20
 
18
21
  class TracingContext(Protocol):
19
22
  """
@@ -102,11 +105,11 @@ class TracingManager:
102
105
  if enable_langfuse:
103
106
  try:
104
107
  # Create both sync and async handlers. We'll pick one at runtime.
105
- sync_handler = LangfuseCallbackHandler()
108
+ sync_handler = get_langfuse_handler()
106
109
  self._sync_handlers.append(sync_handler)
107
110
 
108
111
  if AsyncLangfuseCallbackHandler:
109
- async_handler = AsyncLangfuseCallbackHandler()
112
+ async_handler = get_async_langfuse_handler()
110
113
  self._async_handlers.append(async_handler)
111
114
 
112
115
  self.context.logger.info(f"Langfuse tracing enabled for {self.context.get_model_identifier()}")
@@ -115,7 +118,7 @@ class TracingManager:
115
118
  else:
116
119
  self.context.logger.info("Langfuse is not enabled, skipping handler initialization.")
117
120
 
118
- def _add_callbacks_to_config(self, config: Optional[dict], handlers: List[Any]) -> dict:
121
+ def add_callbacks_to_config(self, config: Optional[dict], handlers: List[Any]) -> dict:
119
122
  """A generic helper to add a list of handlers to a config object."""
120
123
  if config is None:
121
124
  config = {}
@@ -154,10 +157,26 @@ class TracingManager:
154
157
 
155
158
  return config
156
159
 
157
- def add_sync_callbacks_to_config(self, config: Optional[dict]) -> dict:
158
- """Adds synchronous tracing handlers to the request configuration."""
159
- return self._add_callbacks_to_config(config, self._sync_handlers)
160
+ def add_sync_callbacks_to_config(self, config: Optional[dict], handlers: Optional[List[Any]] = None) -> dict:
161
+ """
162
+ Adds synchronous tracing handlers to the request configuration.
163
+
164
+ Args:
165
+ config: The configuration dictionary to which callbacks will be added.
166
+ handlers: An optional list of handlers to add. If not provided,
167
+ the manager's default synchronous handlers are used.
168
+ """
169
+ handlers_to_add = self._sync_handlers if handlers is None else handlers
170
+ return self.add_callbacks_to_config(config, handlers_to_add)
160
171
 
161
- def add_async_callbacks_to_config(self, config: Optional[dict]) -> dict:
162
- """Adds asynchronous tracing handlers to the request configuration."""
163
- return self._add_callbacks_to_config(config, self._async_handlers)
172
+ def add_async_callbacks_to_config(self, config: Optional[dict], handlers: Optional[List[Any]] = None) -> dict:
173
+ """
174
+ Adds asynchronous tracing handlers to the request configuration.
175
+
176
+ Args:
177
+ config: The configuration dictionary to which callbacks will be added.
178
+ handlers: An optional list of handlers to add. If not provided,
179
+ the manager's default asynchronous handlers are used.
180
+ """
181
+ handlers_to_add = self._async_handlers if handlers is None else handlers
182
+ return self.add_callbacks_to_config(config, handlers_to_add)
@@ -0,0 +1,51 @@
1
+ from typing import Dict, Any, Optional
2
+ from langchain_core.runnables import RunnableConfig
3
+ from langfuse.langchain import CallbackHandler as LangfuseCallbackHandler
4
+ from ..callbacks.async_langfuse_handler import AsyncLangfuseCallbackHandler
5
+
6
+ # Singleton holder for the Langfuse handler to avoid multiple instances per run
7
+ _LANGFUSE_HANDLER: Optional[LangfuseCallbackHandler] = None
8
+ _ASYNC_LANGFUSE_HANDLER: Optional[AsyncLangfuseCallbackHandler] = None
9
+
10
+ def _get_langfuse_handler() -> LangfuseCallbackHandler:
11
+ global _LANGFUSE_HANDLER
12
+ if _LANGFUSE_HANDLER is None:
13
+ _LANGFUSE_HANDLER = LangfuseCallbackHandler()
14
+ return _LANGFUSE_HANDLER
15
+
16
+ def get_langfuse_handler() -> LangfuseCallbackHandler:
17
+ return _get_langfuse_handler()
18
+
19
+ def get_async_langfuse_handler() -> "AsyncLangfuseCallbackHandler":
20
+ """Returns a singleton instance of the async Langfuse handler."""
21
+ global _ASYNC_LANGFUSE_HANDLER
22
+ if _ASYNC_LANGFUSE_HANDLER is None:
23
+ _ASYNC_LANGFUSE_HANDLER = AsyncLangfuseCallbackHandler()
24
+ return _ASYNC_LANGFUSE_HANDLER
25
+
26
+ def prepare_trace_config(context: Dict[str, Any]) -> RunnableConfig:
27
+ """
28
+ Prepares a minimal RunnableConfig for tracing, primarily for Langfuse.
29
+
30
+ - Creates a new config containing only tracing-related information.
31
+ - Extracts 'trace_metadata' from the context's 'configurable' dict
32
+ and uses it as the 'metadata' for the new trace config.
33
+ - Adds a singleton Langfuse callback handler.
34
+ """
35
+ # The full config is passed in the 'config' key of the context
36
+ # Start with a copy of the existing config from the graph to preserve its state
37
+ run_config = context.get("config", {}).copy()
38
+
39
+ # Extract trace_metadata from the 'configurable' part of the full config
40
+ trace_metadata = run_config.get("trace_metadata", {})
41
+ if not trace_metadata:
42
+ trace_metadata = run_config.get("configurable", {}).get("trace_metadata", {})
43
+
44
+ # If trace_metadata exists, merge all its fields into the main metadata key
45
+ if trace_metadata and isinstance(trace_metadata, dict):
46
+ if "metadata" not in run_config:
47
+ run_config["metadata"] = {}
48
+ run_config["metadata"].update(trace_metadata)
49
+
50
+ return run_config
51
+
@@ -5,14 +5,15 @@
5
5
  # @Last Modified time: 2025-10-09
6
6
 
7
7
  import logging
8
- from typing import List, Dict, Union, Optional
8
+ from typing import List, Dict, Union, Optional, Any
9
9
  from langchain_milvus import Milvus
10
10
  from langchain_core.embeddings import Embeddings
11
11
  from langchain_openai import AzureOpenAIEmbeddings
12
- from pymilvus import MilvusClient, AsyncMilvusClient
12
+ from pymilvus import MilvusClient, AsyncMilvusClient, connections
13
13
  import time
14
14
  import asyncio
15
15
  import uuid
16
+ from collections import defaultdict
16
17
 
17
18
  from ...services.init_services import get_model_balancer
18
19
  from .schema_milvus import SchemaMilvus, DEFAULT_SCHEMA
@@ -96,6 +97,7 @@ class VDBService(object):
96
97
  _async_client: Optional[AsyncMilvusClient] = None
97
98
  _instances: Dict[str, Milvus] = {}
98
99
  _async_instances: Dict[str, Milvus] = {}
100
+ _async_instance_locks: Dict[str, asyncio.Lock] = defaultdict(asyncio.Lock)
99
101
 
100
102
  schema: str
101
103
  embedding_function: Embeddings
@@ -168,6 +170,10 @@ class VDBService(object):
168
170
  # lazy-initialize async milvus
169
171
  # self._async_client = self._initialize_async_milvus_client(provider)
170
172
 
173
+ # Do not initialize the async client here.
174
+ # It must be lazily initialized within an async context.
175
+ self._async_client: Optional[AsyncMilvusClient] = None
176
+
171
177
  self.schema = schema
172
178
  self.index_params = self.settings.get("index_params")
173
179
 
@@ -256,12 +262,16 @@ class VDBService(object):
256
262
 
257
263
  async def aget_async_vector_client(self) -> AsyncMilvusClient:
258
264
  """
259
- Asynchronously returns the active AsyncMilvusClient instance, initializing it if necessary.
260
-
261
- Returns:
262
- AsyncMilvusClient: The initialized async client for interacting with the vector database.
265
+ Lazily initializes and returns the AsyncMilvusClient.
266
+ This ensures the client is created within the running event loop.
263
267
  """
264
- return await self._get_or_create_async_client()
268
+ if self._async_client is None:
269
+ self.logger.info("Lazily initializing AsyncMilvusClient...")
270
+ client_args = self._get_milvus_client_args(self._provider)
271
+ # Use the dedicated async alias
272
+ client_args['alias'] = self.async_alias
273
+ self._async_client = AsyncMilvusClient(**client_args)
274
+ return self._async_client
265
275
 
266
276
  def get_vector_field(self, collection_name: str) -> str:
267
277
  """
@@ -370,6 +380,7 @@ class VDBService(object):
370
380
  Asynchronously checks if a collection exists and creates it if it doesn't.
371
381
  """
372
382
  try:
383
+ # Call the new lazy initializer for the async client
373
384
  client = await self.aget_async_vector_client()
374
385
  if check_existence and not await client.has_collection(collection_name):
375
386
  self.logger.info(f"Collection '{collection_name}' does not exist. Creating it.")
@@ -498,130 +509,117 @@ class VDBService(object):
498
509
 
499
510
  async def _get_or_create_async_client(self) -> AsyncMilvusClient:
500
511
  """
501
- Lazily initializes and returns the AsyncMilvusClient.
502
- This runs the blocking constructor in a separate thread, but also creates
503
- a temporary event loop inside that thread to satisfy the client's
504
- initialization requirements.
512
+ Lazily initializes the AsyncMilvusClient.
513
+ Based on grpcio source, the client MUST be initialized in a thread
514
+ with a running event loop. Therefore, we initialize it directly in the
515
+ main async context. The synchronous __init__ is fast enough not to
516
+ block the event loop meaningfully.
505
517
  """
506
518
  if self._async_client is None:
507
- self.logger.info("Lazily initializing AsyncMilvusClient...")
508
-
509
- def _create_with_loop():
510
- # This function runs in a separate thread via asyncio.to_thread
511
- try:
512
- # Check if an event loop exists in this new thread
513
- asyncio.get_running_loop()
514
- except RuntimeError: # 'RuntimeError: There is no current event loop...'
515
- # If not, create and set a new one
516
- loop = asyncio.new_event_loop()
517
- asyncio.set_event_loop(loop)
518
-
519
- # Now, with an event loop present in this thread, initialize the client.
520
- # This is still a blocking call, but it's contained in the thread.
521
- provider = self.settings.get("vector_store", {}).get("provider")
522
- return self._initialize_async_milvus_client(provider)
523
-
524
- self._async_client = await asyncio.to_thread(_create_with_loop)
519
+ self.logger.info("Lazily initializing AsyncMilvusClient directly in the main event loop...")
520
+ provider = self.settings.get("vector_store", {}).get("provider")
521
+ # This is a synchronous call, but it's lightweight and must run here.
522
+ self._async_client = self._initialize_async_milvus_client(provider)
525
523
 
526
524
  return self._async_client
527
525
 
528
526
  async def aget_vector_store(self, collection_name: str, embeddings: Embeddings = None, metric_type: str = "IP") -> Milvus:
529
527
  """
530
528
  Asynchronously gets a vector store instance, creating it if it doesn't exist.
529
+ This version is optimized to handle high concurrency using a lock.
531
530
  """
532
531
  if not collection_name:
533
532
  self.logger.error("aget_vector_store called with no collection_name.")
534
533
  raise ValueError("collection_name must be provided.")
535
534
 
536
- # Check for a cached instance. If found, return it immediately.
537
- if collection_name in self._async_instances:
538
- self.logger.info(f"Returning existing async vector store instance for collection: {collection_name}")
539
- return self._async_instances[collection_name]
540
-
541
- self.logger.info(f"Creating new async vector store instance for collection: {collection_name}")
542
- if embeddings is None:
543
- embeddings = self.get_embeddings()
535
+ lock = self._async_instance_locks[collection_name]
536
+ async with lock:
537
+ if collection_name in self._async_instances:
538
+ self.logger.info(f"Returning existing async vector store instance for collection: {collection_name} (post-lock)")
539
+ return self._async_instances[collection_name]
544
540
 
545
- await self._aensure_collection_exists(collection_name, embeddings, check_existence=True)
541
+ self.logger.info(f"Creating new async vector store instance for collection: {collection_name}")
542
+ if embeddings is None:
543
+ embeddings = self.get_embeddings()
546
544
 
547
- # try:
548
- # self.logger.info(f"Testing embedding function for collection '{collection_name}'...")
549
- # await embeddings.aembed_query("validation_test_string")
550
- # self.logger.info("Embedding function is valid.")
551
- # except Exception as e:
552
- # self.logger.error(
553
- # f"The provided embedding function is invalid and failed with error: {e}. "
554
- # f"Cannot create a vector store for collection '{collection_name}'."
555
- # )
556
- # raise RuntimeError(f"Invalid embedding function provided.") from e
545
+ # CRITICAL: Ensure the shared async client is initialized *under the lock*
546
+ # before any operation that might use it.
547
+ await self._get_or_create_async_client()
557
548
 
558
- index_params = self.index_params or {
559
- "metric_type": metric_type,
560
- "index_type": "AUTOINDEX",
561
- "params": {}
562
- }
563
-
564
- # Create a dedicated connection_args for the async path with the correct alias
565
- async_conn_args = self.connection_args.copy()
566
- async_conn_args['alias'] = self.async_alias
567
-
568
- # For async operations, we MUST instantiate the Milvus object using the SYNCHRONOUS alias
569
- # because its __init__ method is synchronous. This is now done in a separate thread.
570
- vdb = await self._acreate_milvus_instance_with_retry(
571
- collection_name=collection_name,
572
- embeddings=embeddings,
573
- index_params=index_params,
574
- connection_args=async_conn_args # Pass the async-specific connection args
575
- )
549
+ await self._aensure_collection_exists(collection_name, embeddings, check_existence=True)
576
550
 
577
- # After successful synchronous initialization, we hot-swap the alias on the
578
- # ASYNCHRONOUS client to ensure future async operations use the correct connection.
579
- self.logger.info(f"Swapping to async alias for instance of collection {collection_name}")
580
- # DO NOT get the async client here, get it outside this function
581
- #await self._get_or_create_async_client()
582
- vdb.aclient._using = self.async_alias
551
+ vdb = await self._acreate_milvus_instance_with_retry(
552
+ collection_name=collection_name,
553
+ embeddings=embeddings,
554
+ metric_type=metric_type
555
+ )
583
556
 
584
- self._async_instances[collection_name] = vdb
557
+ self.logger.info(f"Swapping to async alias for instance of collection {collection_name}")
558
+ vdb.aclient._using = self.async_alias
585
559
 
586
- return vdb
560
+ self._async_instances[collection_name] = vdb
561
+ return vdb
587
562
 
588
- async def _acreate_milvus_instance_with_retry(self, collection_name: str, embeddings: Embeddings, index_params: dict, connection_args: Optional[dict] = None) -> Milvus:
563
+ async def _acreate_milvus_instance_with_retry(
564
+ self,
565
+ embeddings: Embeddings,
566
+ collection_name: str,
567
+ metric_type: str = "IP",
568
+ ) -> Milvus:
589
569
  """
590
- Asynchronously creates a Milvus instance with a retry mechanism, running the synchronous
591
- constructor in a separate thread to avoid blocking the event loop.
570
+ Asynchronously creates a Milvus instance with retry logic, ensuring the connection
571
+ is established in the target thread.
592
572
  """
593
- retries = 2
594
- conn_args = connection_args if connection_args is not None else self.connection_args
595
-
596
- def _create_instance():
597
- # This synchronous function will be run in a thread
598
- return Milvus(
599
- embedding_function=embeddings,
600
- collection_name=collection_name,
601
- connection_args=conn_args,
602
- index_params=index_params
603
- )
604
-
605
- self.logger.info(f"Creating Milvus instance for collection '{collection_name}' in a separate thread...")
606
- self.logger.info(f"Connection args: {conn_args}")
573
+ retries = 3
574
+ last_exception = None
607
575
 
608
- for attempt in range(retries + 1):
576
+ for attempt in range(retries):
609
577
  try:
610
- # Run the blocking constructor in a separate thread
611
- vdb = await asyncio.to_thread(_create_instance)
612
-
613
- self.logger.info(f"Successfully connected to Milvus for collection '{collection_name}' on attempt {attempt + 1}.")
614
- return vdb # Return on success
578
+ conn_args = self.connection_args.copy()
579
+ # Langchain's Milvus class will use the alias to find the connection.
580
+ conn_args["alias"] = self.sync_alias
581
+
582
+ def _create_instance_in_thread():
583
+ # --- START: CRITICAL FIX ---
584
+ # Manually connect within the thread before creating the Milvus instance.
585
+ # This ensures pymilvus registers the connection details for the current thread.
586
+ try:
587
+ connections.connect(**conn_args)
588
+ self.logger.info(f"Successfully connected to Milvus with alias '{self.sync_alias}' in thread.")
589
+ except Exception as e:
590
+ self.logger.error(f"Failed to manually connect in thread: {e}")
591
+ raise
592
+
593
+ # Now, creating the Milvus instance will find the existing connection via the alias.
594
+ instance = Milvus(
595
+ embedding_function=embeddings,
596
+ collection_name=collection_name,
597
+ connection_args=conn_args, # Pass args for completeness
598
+ # metric_type=metric_type, # <-- CRITICAL FIX: REMOVE THIS LINE
599
+ consistency_level="Strong",
600
+ # --- START: CRITICAL FIX ---
601
+ # Pass self.index_params to the Milvus constructor here
602
+ index_params=self.index_params,
603
+ # --- END: CRITICAL FIX ---
604
+ )
605
+ return instance
606
+ # --- END: CRITICAL FIX ---
607
+
608
+ self.logger.info(f"Attempt {attempt + 1}/{retries}: Creating Milvus instance for collection '{collection_name}' in a separate thread...")
609
+ vdb = await asyncio.to_thread(_create_instance_in_thread)
610
+ self.logger.info("Successfully created Milvus instance.")
611
+ return vdb
612
+
615
613
  except Exception as e:
614
+ last_exception = e
616
615
  self.logger.warning(
617
- f"Attempt {attempt + 1}/{retries + 1} to connect to Milvus for collection '{collection_name}' failed: {e}"
616
+ f"Attempt {attempt + 1}/{retries} failed to create Milvus instance: {e}. Retrying in {2 ** attempt}s..."
618
617
  )
619
- if attempt < retries:
620
- self.logger.info("Retrying in 3 seconds...")
621
- await asyncio.sleep(3) # Use async sleep
622
- else:
623
- self.logger.error(f"Failed to connect to Milvus for collection '{collection_name}' after {retries + 1} attempts.")
624
- raise RuntimeError(f"Could not connect to Milvus after {retries + 1} attempts.") from e
618
+ await asyncio.sleep(2 ** attempt)
619
+
620
+ raise RuntimeError(
621
+ f"Failed to create Milvus instance after {retries} retries."
622
+ ) from last_exception
625
623
 
626
624
  def _create_milvus_instance_with_retry(self, collection_name: str, embeddings: Embeddings, index_params: dict, connection_args: Optional[dict] = None) -> Milvus:
627
625
  """
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: crewplus
3
- Version: 0.2.70
3
+ Version: 0.2.72
4
4
  Summary: Base services for CrewPlus AI applications
5
5
  Author-Email: Tim Liu <tim@opsmateai.com>
6
6
  License: MIT
@@ -1,7 +1,7 @@
1
- crewplus-0.2.70.dist-info/METADATA,sha256=M2xMdWJbR5BsBLfIGxner83D2vLfE5ui-hmEmhcVMUQ,5424
2
- crewplus-0.2.70.dist-info/WHEEL,sha256=9P2ygRxDrTJz3gsagc0Z96ukrxjr-LFBGOgv3AuKlCA,90
3
- crewplus-0.2.70.dist-info/entry_points.txt,sha256=6OYgBcLyFCUgeqLgnvMyOJxPCWzgy7se4rLPKtNonMs,34
4
- crewplus-0.2.70.dist-info/licenses/LICENSE,sha256=2_NHSHRTKB_cTcT_GXgcenOCtIZku8j343mOgAguTfc,1087
1
+ crewplus-0.2.72.dist-info/METADATA,sha256=RYFh6zu4R5RZg4Ojlp2jIKOV61A7DNvwu_4s1SDu1X0,5424
2
+ crewplus-0.2.72.dist-info/WHEEL,sha256=9P2ygRxDrTJz3gsagc0Z96ukrxjr-LFBGOgv3AuKlCA,90
3
+ crewplus-0.2.72.dist-info/entry_points.txt,sha256=6OYgBcLyFCUgeqLgnvMyOJxPCWzgy7se4rLPKtNonMs,34
4
+ crewplus-0.2.72.dist-info/licenses/LICENSE,sha256=2_NHSHRTKB_cTcT_GXgcenOCtIZku8j343mOgAguTfc,1087
5
5
  crewplus/__init__.py,sha256=m46HkZL1Y4toD619NL47Sn2Qe084WFFSFD7e6VoYKZc,284
6
6
  crewplus/callbacks/__init__.py,sha256=YG7ieeb91qEjp1zF0-inEN7mjZ7yT_D2yzdWFT8Z1Ws,63
7
7
  crewplus/callbacks/async_langfuse_handler.py,sha256=A4uFeLpvOUdc58M7sZoE65_C1V98u0QCvx5jUquM0pM,7006
@@ -10,16 +10,17 @@ crewplus/services/azure_chat_model.py,sha256=iWzJ2GQFSNmwJx-2O5_xKPSB6VVc-7T6bcf
10
10
  crewplus/services/gemini_chat_model.py,sha256=DYqz01H2TIHiCDQesSozVfOsMigno6QGwOtIweg7UHk,40103
11
11
  crewplus/services/init_services.py,sha256=tc1ti8Yufo2ixlJpwg8uH0KmoyQ4EqxCOe4uTEWnlRM,2413
12
12
  crewplus/services/model_load_balancer.py,sha256=Q9Gx3GrbKworU-Ytxeqp0ggHSgZ1Q6brtTk-nCl4sak,12095
13
- crewplus/services/tracing_manager.py,sha256=_C4zYj6o_k5mDWY7vM8UeaVaXp8SqrkvYOb0Jj-y3sY,7566
13
+ crewplus/services/tracing_manager.py,sha256=pwNFeA77vnoZMh_AUOnK5TvAaPOOLg5oDnVOe1yUa9A,8502
14
14
  crewplus/utils/__init__.py,sha256=2Gk1n5srFJQnFfBuYTxktdtKOVZyNrFcNaZKhXk35Pw,142
15
15
  crewplus/utils/schema_action.py,sha256=GDaBoVFQD1rXqrLVSMTfXYW1xcUu7eDcHsn57XBSnIg,422
16
16
  crewplus/utils/schema_document_updater.py,sha256=frvffxn2vbi71fHFPoGb9hq7gH2azmmdq17p-Fumnvg,7322
17
+ crewplus/utils/tracing_util.py,sha256=39F9ydMjXSy5UbQIjYDKc1yiBVnibuWt0cGpYM55k7Q,2281
17
18
  crewplus/vectorstores/milvus/__init__.py,sha256=OeYv2rdyG7tcREIjBJPyt2TbE54NvyeRoWMe7LwopRE,245
18
19
  crewplus/vectorstores/milvus/milvus_schema_manager.py,sha256=-QRav-hzu-XWeJ_yKUMolal_EyMUspSg-nvh5sqlrlQ,11442
19
20
  crewplus/vectorstores/milvus/schema_milvus.py,sha256=wwNpfqsKS0xeozZES40IvB0iNwUtpCall_7Hkg0dL1g,27223
20
- crewplus/vectorstores/milvus/vdb_service.py,sha256=Jo2GWzdEuDSPlADCWA7wTgDbYQ65QiYWgFGbtkG9vG8,37789
21
+ crewplus/vectorstores/milvus/vdb_service.py,sha256=U8I6IUYZK0gCe1R9rTnVezvZfEcUS9UEbKEoeJPX8kY,37528
21
22
  docs/GeminiChatModel.md,sha256=zZYyl6RmjZTUsKxxMiC9O4yV70MC4TD-IGUmWhIDBKA,8677
22
23
  docs/ModelLoadBalancer.md,sha256=aGHES1dcXPz4c7Y8kB5-vsCNJjriH2SWmjBkSGoYKiI,4398
23
24
  docs/VDBService.md,sha256=Dw286Rrf_fsi13jyD3Bo4Sy7nZ_G7tYm7d8MZ2j9hxk,9375
24
25
  docs/index.md,sha256=3tlc15uR8lzFNM5WjdoZLw0Y9o1P1gwgbEnOdIBspqc,1643
25
- crewplus-0.2.70.dist-info/RECORD,,
26
+ crewplus-0.2.72.dist-info/RECORD,,