crewplus 0.2.58__py3-none-any.whl → 0.2.60__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.
- crewplus/services/init_services.py +8 -3
- crewplus/vectorstores/milvus/vdb_service.py +86 -18
- {crewplus-0.2.58.dist-info → crewplus-0.2.60.dist-info}/METADATA +1 -2
- {crewplus-0.2.58.dist-info → crewplus-0.2.60.dist-info}/RECORD +7 -7
- {crewplus-0.2.58.dist-info → crewplus-0.2.60.dist-info}/WHEEL +0 -0
- {crewplus-0.2.58.dist-info → crewplus-0.2.60.dist-info}/entry_points.txt +0 -0
- {crewplus-0.2.58.dist-info → crewplus-0.2.60.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import os
|
|
2
1
|
import logging
|
|
2
|
+
import os
|
|
3
3
|
from typing import Optional
|
|
4
|
+
|
|
4
5
|
from .model_load_balancer import ModelLoadBalancer
|
|
5
6
|
|
|
6
7
|
model_balancer = None
|
|
@@ -26,9 +27,13 @@ def init_load_balancer(
|
|
|
26
27
|
global model_balancer
|
|
27
28
|
if model_balancer is None:
|
|
28
29
|
# Use parameter if provided, otherwise check env var, then default
|
|
30
|
+
current_dir = os.path.dirname(os.path.abspath(__file__))
|
|
31
|
+
base_package_dir = os.path.dirname(os.path.dirname(current_dir))
|
|
32
|
+
default_config_path = os.path.join(base_package_dir, "_config", "models_config.json")
|
|
33
|
+
|
|
29
34
|
final_config_path = config_path or os.getenv(
|
|
30
|
-
"MODEL_CONFIG_PATH",
|
|
31
|
-
|
|
35
|
+
"MODEL_CONFIG_PATH",
|
|
36
|
+
default_config_path
|
|
32
37
|
)
|
|
33
38
|
try:
|
|
34
39
|
# 1. Create a local instance first.
|
|
@@ -234,7 +234,7 @@ class VDBService(object):
|
|
|
234
234
|
return AsyncMilvusClient(**client_args)
|
|
235
235
|
except Exception as e:
|
|
236
236
|
self.logger.error(f"Failed to initialize AsyncMilvusClient, trying again. Error: {e}")
|
|
237
|
-
#
|
|
237
|
+
time.sleep(1) # sync sleep is fine, we are in a thread
|
|
238
238
|
try:
|
|
239
239
|
return AsyncMilvusClient(**client_args)
|
|
240
240
|
except Exception as e_retry:
|
|
@@ -254,18 +254,14 @@ class VDBService(object):
|
|
|
254
254
|
|
|
255
255
|
return self._client
|
|
256
256
|
|
|
257
|
-
def
|
|
257
|
+
async def aget_async_vector_client(self) -> AsyncMilvusClient:
|
|
258
258
|
"""
|
|
259
|
-
|
|
259
|
+
Asynchronously returns the active AsyncMilvusClient instance, initializing it if necessary.
|
|
260
260
|
|
|
261
261
|
Returns:
|
|
262
262
|
AsyncMilvusClient: The initialized async client for interacting with the vector database.
|
|
263
263
|
"""
|
|
264
|
-
|
|
265
|
-
self.logger.debug("Initializing asynchronous AsyncMilvusClient...")
|
|
266
|
-
self._async_client = self._initialize_async_milvus_client(self._provider)
|
|
267
|
-
|
|
268
|
-
return self._async_client
|
|
264
|
+
return await self._get_or_create_async_client()
|
|
269
265
|
|
|
270
266
|
def get_vector_field(self, collection_name: str) -> str:
|
|
271
267
|
"""
|
|
@@ -374,7 +370,7 @@ class VDBService(object):
|
|
|
374
370
|
Asynchronously checks if a collection exists and creates it if it doesn't.
|
|
375
371
|
"""
|
|
376
372
|
try:
|
|
377
|
-
client = self.
|
|
373
|
+
client = await self.aget_async_vector_client()
|
|
378
374
|
if check_existence and not await client.has_collection(collection_name):
|
|
379
375
|
self.logger.info(f"Collection '{collection_name}' does not exist. Creating it.")
|
|
380
376
|
|
|
@@ -512,6 +508,35 @@ class VDBService(object):
|
|
|
512
508
|
|
|
513
509
|
return vdb
|
|
514
510
|
|
|
511
|
+
async def _get_or_create_async_client(self) -> AsyncMilvusClient:
|
|
512
|
+
"""
|
|
513
|
+
Lazily initializes and returns the AsyncMilvusClient.
|
|
514
|
+
This runs the blocking constructor in a separate thread, but also creates
|
|
515
|
+
a temporary event loop inside that thread to satisfy the client's
|
|
516
|
+
initialization requirements.
|
|
517
|
+
"""
|
|
518
|
+
if self._async_client is None:
|
|
519
|
+
self.logger.info("Lazily initializing AsyncMilvusClient...")
|
|
520
|
+
|
|
521
|
+
def _create_with_loop():
|
|
522
|
+
# This function runs in a separate thread via asyncio.to_thread
|
|
523
|
+
try:
|
|
524
|
+
# Check if an event loop exists in this new thread
|
|
525
|
+
asyncio.get_running_loop()
|
|
526
|
+
except RuntimeError: # 'RuntimeError: There is no current event loop...'
|
|
527
|
+
# If not, create and set a new one
|
|
528
|
+
loop = asyncio.new_event_loop()
|
|
529
|
+
asyncio.set_event_loop(loop)
|
|
530
|
+
|
|
531
|
+
# Now, with an event loop present in this thread, initialize the client.
|
|
532
|
+
# This is still a blocking call, but it's contained in the thread.
|
|
533
|
+
provider = self.settings.get("vector_store", {}).get("provider")
|
|
534
|
+
return self._initialize_async_milvus_client(provider)
|
|
535
|
+
|
|
536
|
+
self._async_client = await asyncio.to_thread(_create_with_loop)
|
|
537
|
+
|
|
538
|
+
return self._async_client
|
|
539
|
+
|
|
515
540
|
async def aget_vector_store(self, collection_name: str, embeddings: Embeddings = None, metric_type: str = "IP") -> Milvus:
|
|
516
541
|
"""
|
|
517
542
|
Asynchronously gets a vector store instance, creating it if it doesn't exist.
|
|
@@ -539,12 +564,12 @@ class VDBService(object):
|
|
|
539
564
|
if embeddings is None:
|
|
540
565
|
embeddings = self.get_embeddings()
|
|
541
566
|
|
|
542
|
-
await self._aensure_collection_exists(collection_name, embeddings, check_existence=check_existence)
|
|
567
|
+
# await self._aensure_collection_exists(collection_name, embeddings, check_existence=check_existence)
|
|
543
568
|
|
|
544
569
|
try:
|
|
545
|
-
self.logger.
|
|
570
|
+
self.logger.info(f"Testing embedding function for collection '{collection_name}'...")
|
|
546
571
|
await embeddings.aembed_query("validation_test_string")
|
|
547
|
-
self.logger.
|
|
572
|
+
self.logger.info("Embedding function is valid.")
|
|
548
573
|
except Exception as e:
|
|
549
574
|
self.logger.error(
|
|
550
575
|
f"The provided embedding function is invalid and failed with error: {e}. "
|
|
@@ -558,24 +583,67 @@ class VDBService(object):
|
|
|
558
583
|
"params": {}
|
|
559
584
|
}
|
|
560
585
|
|
|
586
|
+
# Create a dedicated connection_args for the async path with the correct alias
|
|
587
|
+
async_conn_args = self.connection_args.copy()
|
|
588
|
+
async_conn_args['alias'] = self.async_alias
|
|
589
|
+
|
|
561
590
|
# For async operations, we MUST instantiate the Milvus object using the SYNCHRONOUS alias
|
|
562
|
-
# because its __init__ method is synchronous.
|
|
563
|
-
vdb = self.
|
|
591
|
+
# because its __init__ method is synchronous. This is now done in a separate thread.
|
|
592
|
+
vdb = await self._acreate_milvus_instance_with_retry(
|
|
564
593
|
collection_name=collection_name,
|
|
565
594
|
embeddings=embeddings,
|
|
566
595
|
index_params=index_params,
|
|
567
|
-
connection_args=
|
|
596
|
+
connection_args=async_conn_args # Pass the async-specific connection args
|
|
568
597
|
)
|
|
569
598
|
|
|
570
599
|
# After successful synchronous initialization, we hot-swap the alias on the
|
|
571
600
|
# ASYNCHRONOUS client to ensure future async operations use the correct connection.
|
|
572
|
-
self.logger.
|
|
601
|
+
self.logger.info(f"Swapping to async alias for instance of collection {collection_name}")
|
|
602
|
+
await self._get_or_create_async_client()
|
|
573
603
|
vdb.aclient._using = self.async_alias
|
|
574
604
|
|
|
575
605
|
self._async_instances[collection_name] = vdb
|
|
576
606
|
|
|
577
607
|
return vdb
|
|
578
608
|
|
|
609
|
+
async def _acreate_milvus_instance_with_retry(self, collection_name: str, embeddings: Embeddings, index_params: dict, connection_args: Optional[dict] = None) -> Milvus:
|
|
610
|
+
"""
|
|
611
|
+
Asynchronously creates a Milvus instance with a retry mechanism, running the synchronous
|
|
612
|
+
constructor in a separate thread to avoid blocking the event loop.
|
|
613
|
+
"""
|
|
614
|
+
retries = 2
|
|
615
|
+
conn_args = connection_args if connection_args is not None else self.connection_args
|
|
616
|
+
|
|
617
|
+
def _create_instance():
|
|
618
|
+
# This synchronous function will be run in a thread
|
|
619
|
+
return Milvus(
|
|
620
|
+
embedding_function=embeddings,
|
|
621
|
+
collection_name=collection_name,
|
|
622
|
+
connection_args=conn_args,
|
|
623
|
+
index_params=index_params
|
|
624
|
+
)
|
|
625
|
+
|
|
626
|
+
self.logger.info(f"Creating Milvus instance for collection '{collection_name}' in a separate thread...")
|
|
627
|
+
self.logger.info(f"Connection args: {conn_args}")
|
|
628
|
+
|
|
629
|
+
for attempt in range(retries + 1):
|
|
630
|
+
try:
|
|
631
|
+
# Run the blocking constructor in a separate thread
|
|
632
|
+
vdb = await asyncio.to_thread(_create_instance)
|
|
633
|
+
|
|
634
|
+
self.logger.info(f"Successfully connected to Milvus for collection '{collection_name}' on attempt {attempt + 1}.")
|
|
635
|
+
return vdb # Return on success
|
|
636
|
+
except Exception as e:
|
|
637
|
+
self.logger.warning(
|
|
638
|
+
f"Attempt {attempt + 1}/{retries + 1} to connect to Milvus for collection '{collection_name}' failed: {e}"
|
|
639
|
+
)
|
|
640
|
+
if attempt < retries:
|
|
641
|
+
self.logger.info("Retrying in 3 seconds...")
|
|
642
|
+
await asyncio.sleep(3) # Use async sleep
|
|
643
|
+
else:
|
|
644
|
+
self.logger.error(f"Failed to connect to Milvus for collection '{collection_name}' after {retries + 1} attempts.")
|
|
645
|
+
raise RuntimeError(f"Could not connect to Milvus after {retries + 1} attempts.") from e
|
|
646
|
+
|
|
579
647
|
def _create_milvus_instance_with_retry(self, collection_name: str, embeddings: Embeddings, index_params: dict, connection_args: Optional[dict] = None) -> Milvus:
|
|
580
648
|
"""
|
|
581
649
|
Creates a Milvus instance with a retry mechanism for connection failures.
|
|
@@ -651,7 +719,7 @@ class VDBService(object):
|
|
|
651
719
|
self.logger.info(f"Attempting to drop collection asynchronously: {collection_name}")
|
|
652
720
|
|
|
653
721
|
try:
|
|
654
|
-
client = self.
|
|
722
|
+
client = await self.aget_async_vector_client()
|
|
655
723
|
await client.drop_collection(collection_name=collection_name)
|
|
656
724
|
self.logger.info(f"Successfully dropped collection asynchronously: {collection_name}")
|
|
657
725
|
except Exception as e:
|
|
@@ -690,7 +758,7 @@ class VDBService(object):
|
|
|
690
758
|
self.logger.info(f"Delete data by filter asynchronously:{filter}")
|
|
691
759
|
|
|
692
760
|
try:
|
|
693
|
-
client=self.
|
|
761
|
+
client= await self.aget_async_vector_client()
|
|
694
762
|
if collection_name is None or client is None or filter is None:
|
|
695
763
|
return RuntimeError(f"collection_name must be not null or check out your client to link milvus")
|
|
696
764
|
await client.delete(collection_name=collection_name, filter=filter)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: crewplus
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.60
|
|
4
4
|
Summary: Base services for CrewPlus AI applications
|
|
5
5
|
Author-Email: Tim Liu <tim@opsmateai.com>
|
|
6
6
|
License: MIT
|
|
@@ -15,7 +15,6 @@ Requires-Dist: google-genai>=1.21.1
|
|
|
15
15
|
Requires-Dist: langchain-milvus<0.3.0,>=0.2.1
|
|
16
16
|
Requires-Dist: langfuse<4.0.0,>=3.1.3
|
|
17
17
|
Requires-Dist: langchain-mcp-adapters>=0.1.4
|
|
18
|
-
Requires-Dist: protobuf<6.0,>=5.27
|
|
19
18
|
Description-Content-Type: text/markdown
|
|
20
19
|
|
|
21
20
|
# CrewPlus
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
crewplus-0.2.
|
|
2
|
-
crewplus-0.2.
|
|
3
|
-
crewplus-0.2.
|
|
4
|
-
crewplus-0.2.
|
|
1
|
+
crewplus-0.2.60.dist-info/METADATA,sha256=PBmO4kKCatXJ6RnPqFdLqyHtncR3HfDzCgnyly9kcsc,5424
|
|
2
|
+
crewplus-0.2.60.dist-info/WHEEL,sha256=9P2ygRxDrTJz3gsagc0Z96ukrxjr-LFBGOgv3AuKlCA,90
|
|
3
|
+
crewplus-0.2.60.dist-info/entry_points.txt,sha256=6OYgBcLyFCUgeqLgnvMyOJxPCWzgy7se4rLPKtNonMs,34
|
|
4
|
+
crewplus-0.2.60.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
|
|
8
8
|
crewplus/services/__init__.py,sha256=V1CG8b2NOmRzNgQH7BPl4KVxWSYJH5vfEsW1wVErKNE,375
|
|
9
9
|
crewplus/services/azure_chat_model.py,sha256=iWzJ2GQFSNmwJx-2O5_xKPSB6VVc-7T6bcfFI8_WezA,5521
|
|
10
10
|
crewplus/services/gemini_chat_model.py,sha256=DYqz01H2TIHiCDQesSozVfOsMigno6QGwOtIweg7UHk,40103
|
|
11
|
-
crewplus/services/init_services.py,sha256=
|
|
11
|
+
crewplus/services/init_services.py,sha256=tc1ti8Yufo2ixlJpwg8uH0KmoyQ4EqxCOe4uTEWnlRM,2413
|
|
12
12
|
crewplus/services/model_load_balancer.py,sha256=Q9Gx3GrbKworU-Ytxeqp0ggHSgZ1Q6brtTk-nCl4sak,12095
|
|
13
13
|
crewplus/services/tracing_manager.py,sha256=0KR-F0BKYEMdADANWofFZH9D9jcWDHzDICUE7nDhzJc,6579
|
|
14
14
|
crewplus/utils/__init__.py,sha256=2Gk1n5srFJQnFfBuYTxktdtKOVZyNrFcNaZKhXk35Pw,142
|
|
@@ -17,9 +17,9 @@ crewplus/utils/schema_document_updater.py,sha256=frvffxn2vbi71fHFPoGb9hq7gH2azmm
|
|
|
17
17
|
crewplus/vectorstores/milvus/__init__.py,sha256=OeYv2rdyG7tcREIjBJPyt2TbE54NvyeRoWMe7LwopRE,245
|
|
18
18
|
crewplus/vectorstores/milvus/milvus_schema_manager.py,sha256=-QRav-hzu-XWeJ_yKUMolal_EyMUspSg-nvh5sqlrlQ,11442
|
|
19
19
|
crewplus/vectorstores/milvus/schema_milvus.py,sha256=wwNpfqsKS0xeozZES40IvB0iNwUtpCall_7Hkg0dL1g,27223
|
|
20
|
-
crewplus/vectorstores/milvus/vdb_service.py,sha256=
|
|
20
|
+
crewplus/vectorstores/milvus/vdb_service.py,sha256=qlmFWO_ZRXIeCGZGSEAlS2ciHhTPTH1Dg2ovovA1ZEY,38792
|
|
21
21
|
docs/GeminiChatModel.md,sha256=zZYyl6RmjZTUsKxxMiC9O4yV70MC4TD-IGUmWhIDBKA,8677
|
|
22
22
|
docs/ModelLoadBalancer.md,sha256=aGHES1dcXPz4c7Y8kB5-vsCNJjriH2SWmjBkSGoYKiI,4398
|
|
23
23
|
docs/VDBService.md,sha256=Dw286Rrf_fsi13jyD3Bo4Sy7nZ_G7tYm7d8MZ2j9hxk,9375
|
|
24
24
|
docs/index.md,sha256=3tlc15uR8lzFNM5WjdoZLw0Y9o1P1gwgbEnOdIBspqc,1643
|
|
25
|
-
crewplus-0.2.
|
|
25
|
+
crewplus-0.2.60.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|