crewplus 0.2.43__tar.gz → 0.2.46__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 (25) hide show
  1. {crewplus-0.2.43 → crewplus-0.2.46}/PKG-INFO +1 -1
  2. crewplus-0.2.46/crewplus/callbacks/async_langfuse_handler.py +162 -0
  3. {crewplus-0.2.43 → crewplus-0.2.46}/pyproject.toml +1 -1
  4. crewplus-0.2.43/crewplus/callbacks/async_langfuse_handler.py +0 -107
  5. {crewplus-0.2.43 → crewplus-0.2.46}/LICENSE +0 -0
  6. {crewplus-0.2.43 → crewplus-0.2.46}/README.md +0 -0
  7. {crewplus-0.2.43 → crewplus-0.2.46}/crewplus/__init__.py +0 -0
  8. {crewplus-0.2.43 → crewplus-0.2.46}/crewplus/callbacks/__init__.py +0 -0
  9. {crewplus-0.2.43 → crewplus-0.2.46}/crewplus/services/__init__.py +0 -0
  10. {crewplus-0.2.43 → crewplus-0.2.46}/crewplus/services/azure_chat_model.py +0 -0
  11. {crewplus-0.2.43 → crewplus-0.2.46}/crewplus/services/gemini_chat_model.py +0 -0
  12. {crewplus-0.2.43 → crewplus-0.2.46}/crewplus/services/init_services.py +0 -0
  13. {crewplus-0.2.43 → crewplus-0.2.46}/crewplus/services/model_load_balancer.py +0 -0
  14. {crewplus-0.2.43 → crewplus-0.2.46}/crewplus/services/tracing_manager.py +0 -0
  15. {crewplus-0.2.43 → crewplus-0.2.46}/crewplus/utils/__init__.py +0 -0
  16. {crewplus-0.2.43 → crewplus-0.2.46}/crewplus/utils/schema_action.py +0 -0
  17. {crewplus-0.2.43 → crewplus-0.2.46}/crewplus/utils/schema_document_updater.py +0 -0
  18. {crewplus-0.2.43 → crewplus-0.2.46}/crewplus/vectorstores/milvus/__init__.py +0 -0
  19. {crewplus-0.2.43 → crewplus-0.2.46}/crewplus/vectorstores/milvus/milvus_schema_manager.py +0 -0
  20. {crewplus-0.2.43 → crewplus-0.2.46}/crewplus/vectorstores/milvus/schema_milvus.py +0 -0
  21. {crewplus-0.2.43 → crewplus-0.2.46}/crewplus/vectorstores/milvus/vdb_service.py +0 -0
  22. {crewplus-0.2.43 → crewplus-0.2.46}/docs/GeminiChatModel.md +0 -0
  23. {crewplus-0.2.43 → crewplus-0.2.46}/docs/ModelLoadBalancer.md +0 -0
  24. {crewplus-0.2.43 → crewplus-0.2.46}/docs/VDBService.md +0 -0
  25. {crewplus-0.2.43 → crewplus-0.2.46}/docs/index.md +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: crewplus
3
- Version: 0.2.43
3
+ Version: 0.2.46
4
4
  Summary: Base services for CrewPlus AI applications
5
5
  Author-Email: Tim Liu <tim@opsmateai.com>
6
6
  License: MIT
@@ -0,0 +1,162 @@
1
+ # File: crewplus/callbacks/async_langfuse_handler.py
2
+ import asyncio
3
+ import contextvars
4
+ from contextlib import contextmanager
5
+ from typing import Any, Dict, List, Union, Optional, Sequence
6
+ from uuid import UUID
7
+
8
+ try:
9
+ from langfuse.langchain import CallbackHandler as LangfuseCallbackHandler
10
+ from langchain_core.callbacks import AsyncCallbackHandler
11
+ from langchain_core.outputs import LLMResult, ChatGeneration
12
+ from langchain_core.messages import BaseMessage
13
+ from langchain.schema.agent import AgentAction, AgentFinish
14
+ from langchain.schema.document import Document
15
+ LANGFUSE_AVAILABLE = True
16
+ except ImportError:
17
+ LANGFUSE_AVAILABLE = False
18
+ LangfuseCallbackHandler = None
19
+ AsyncCallbackHandler = object
20
+ # Define dummy types if langchain is not available
21
+ LLMResult = object
22
+ BaseMessage = object
23
+ AgentAction = object
24
+ AgentFinish = object
25
+ Document = object
26
+
27
+
28
+ _ASYNC_CONTEXT_TOKEN = "in_async_context"
29
+ in_async_context = contextvars.ContextVar(_ASYNC_CONTEXT_TOKEN, default=False)
30
+
31
+ @contextmanager
32
+ def async_context():
33
+ """A context manager to signal that we are in an async execution context."""
34
+ token = in_async_context.set(True)
35
+ try:
36
+ yield
37
+ finally:
38
+ in_async_context.reset(token)
39
+
40
+ class AsyncLangfuseCallbackHandler(AsyncCallbackHandler):
41
+ """
42
+ Wraps the synchronous LangfuseCallbackHandler to make it fully compatible with
43
+ LangChain's async methods by handling all relevant events.
44
+ """
45
+ def __init__(self, *args: Any, **kwargs: Any):
46
+ if not LANGFUSE_AVAILABLE:
47
+ raise ImportError("Langfuse is not available. Please install it with 'pip install langfuse'")
48
+ self.sync_handler = LangfuseCallbackHandler(*args, **kwargs)
49
+
50
+ def __getattr__(self, name: str) -> Any:
51
+ return getattr(self.sync_handler, name)
52
+
53
+ # LLM Events
54
+ async def on_llm_start(
55
+ self, serialized: Dict[str, Any], prompts: List[str], *, run_id: UUID, parent_run_id: Optional[UUID] = None, **kwargs: Any
56
+ ) -> None:
57
+ corrected_prompts = prompts if isinstance(prompts, list) else [prompts]
58
+ await asyncio.to_thread(
59
+ self.sync_handler.on_llm_start, serialized, corrected_prompts, run_id=run_id, parent_run_id=parent_run_id, **kwargs
60
+ )
61
+
62
+ async def on_chat_model_start(
63
+ self, serialized: Dict[str, Any], messages: List[List[BaseMessage]], *, run_id: UUID, parent_run_id: Optional[UUID] = None, **kwargs: Any
64
+ ) -> Any:
65
+ await asyncio.to_thread(
66
+ self.sync_handler.on_chat_model_start, serialized, messages, run_id=run_id, parent_run_id=parent_run_id, **kwargs
67
+ )
68
+
69
+ async def on_llm_end(
70
+ self, response: LLMResult, *, run_id: UUID, parent_run_id: Optional[UUID] = None, **kwargs: Any
71
+ ) -> None:
72
+ await asyncio.to_thread(
73
+ self.sync_handler.on_llm_end, response, run_id=run_id, parent_run_id=parent_run_id, **kwargs
74
+ )
75
+
76
+ async def on_llm_error(
77
+ self, error: Union[Exception, KeyboardInterrupt], *, run_id: UUID, parent_run_id: Optional[UUID] = None, **kwargs: Any
78
+ ) -> None:
79
+ await asyncio.to_thread(
80
+ self.sync_handler.on_llm_error, error, run_id=run_id, parent_run_id=parent_run_id, **kwargs
81
+ )
82
+
83
+ # Chain Events
84
+ async def on_chain_start(
85
+ self, serialized: Dict[str, Any], inputs: Dict[str, Any], *, run_id: UUID, parent_run_id: Optional[UUID] = None, **kwargs: Any
86
+ ) -> Any:
87
+ await asyncio.to_thread(
88
+ self.sync_handler.on_chain_start, serialized, inputs, run_id=run_id, parent_run_id=parent_run_id, **kwargs
89
+ )
90
+
91
+ async def on_chain_end(
92
+ self, outputs: Dict[str, Any], *, run_id: UUID, parent_run_id: Optional[UUID] = None, **kwargs: Any
93
+ ) -> Any:
94
+ await asyncio.to_thread(
95
+ self.sync_handler.on_chain_end, outputs, run_id=run_id, parent_run_id=parent_run_id, **kwargs
96
+ )
97
+
98
+ async def on_chain_error(
99
+ self, error: Union[Exception, KeyboardInterrupt], *, run_id: UUID, parent_run_id: Optional[UUID] = None, **kwargs: Any
100
+ ) -> Any:
101
+ await asyncio.to_thread(
102
+ self.sync_handler.on_chain_error, error, run_id=run_id, parent_run_id=parent_run_id, **kwargs
103
+ )
104
+
105
+ # Tool Events
106
+ async def on_tool_start(
107
+ self, serialized: Dict[str, Any], input_str: str, *, run_id: UUID, parent_run_id: Optional[UUID] = None, **kwargs: Any
108
+ ) -> Any:
109
+ await asyncio.to_thread(
110
+ self.sync_handler.on_tool_start, serialized, input_str, run_id=run_id, parent_run_id=parent_run_id, **kwargs
111
+ )
112
+
113
+ async def on_tool_end(
114
+ self, output: str, *, run_id: UUID, parent_run_id: Optional[UUID] = None, **kwargs: Any
115
+ ) -> Any:
116
+ await asyncio.to_thread(
117
+ self.sync_handler.on_tool_end, output, run_id=run_id, parent_run_id=parent_run_id, **kwargs
118
+ )
119
+
120
+ async def on_tool_error(
121
+ self, error: Union[Exception, KeyboardInterrupt], *, run_id: UUID, parent_run_id: Optional[UUID] = None, **kwargs: Any
122
+ ) -> Any:
123
+ await asyncio.to_thread(
124
+ self.sync_handler.on_tool_error, error, run_id=run_id, parent_run_id=parent_run_id, **kwargs
125
+ )
126
+
127
+ # Retriever Events
128
+ async def on_retriever_start(
129
+ self, serialized: Dict[str, Any], query: str, *, run_id: UUID, parent_run_id: Optional[UUID] = None, **kwargs: Any
130
+ ) -> Any:
131
+ await asyncio.to_thread(
132
+ self.sync_handler.on_retriever_start, serialized, query, run_id=run_id, parent_run_id=parent_run_id, **kwargs
133
+ )
134
+
135
+ async def on_retriever_end(
136
+ self, documents: Sequence[Document], *, run_id: UUID, parent_run_id: Optional[UUID] = None, **kwargs: Any
137
+ ) -> Any:
138
+ await asyncio.to_thread(
139
+ self.sync_handler.on_retriever_end, documents, run_id=run_id, parent_run_id=parent_run_id, **kwargs
140
+ )
141
+
142
+ async def on_retriever_error(
143
+ self, error: Union[Exception, KeyboardInterrupt], *, run_id: UUID, parent_run_id: Optional[UUID] = None, **kwargs: Any
144
+ ) -> Any:
145
+ await asyncio.to_thread(
146
+ self.sync_handler.on_retriever_error, error, run_id=run_id, parent_run_id=parent_run_id, **kwargs
147
+ )
148
+
149
+ # Agent Events
150
+ async def on_agent_action(
151
+ self, action: AgentAction, *, run_id: UUID, parent_run_id: Optional[UUID] = None, **kwargs: Any
152
+ ) -> Any:
153
+ await asyncio.to_thread(
154
+ self.sync_handler.on_agent_action, action, run_id=run_id, parent_run_id=parent_run_id, **kwargs
155
+ )
156
+
157
+ async def on_agent_finish(
158
+ self, finish: AgentFinish, *, run_id: UUID, parent_run_id: Optional[UUID] = None, **kwargs: Any
159
+ ) -> Any:
160
+ await asyncio.to_thread(
161
+ self.sync_handler.on_agent_finish, finish, run_id=run_id, parent_run_id=parent_run_id, **kwargs
162
+ )
@@ -6,7 +6,7 @@ build-backend = "pdm.backend"
6
6
 
7
7
  [project]
8
8
  name = "crewplus"
9
- version = "0.2.43"
9
+ version = "0.2.46"
10
10
  description = "Base services for CrewPlus AI applications"
11
11
  authors = [
12
12
  { name = "Tim Liu", email = "tim@opsmateai.com" },
@@ -1,107 +0,0 @@
1
- # File: crewplus/callbacks/async_langfuse_handler.py
2
- import asyncio
3
- import contextvars
4
- from contextlib import contextmanager
5
- from typing import Any, Dict, List, Union
6
-
7
- try:
8
- from langfuse.langchain import CallbackHandler as LangfuseCallbackHandler
9
- from langchain_core.callbacks import AsyncCallbackHandler
10
- from langchain_core.outputs import LLMResult
11
- LANGFUSE_AVAILABLE = True
12
- except ImportError:
13
- LANGFUSE_AVAILABLE = False
14
- LangfuseCallbackHandler = None
15
- AsyncCallbackHandler = object
16
-
17
- # This token is a simple flag to indicate that we are in an async context.
18
- # We use a context variable to make it available only within the async task.
19
- _ASYNC_CONTEXT_TOKEN = "in_async_context"
20
- in_async_context = contextvars.ContextVar(_ASYNC_CONTEXT_TOKEN, default=False)
21
-
22
- @contextmanager
23
- def async_context():
24
- """A context manager to signal that we are in an async execution context."""
25
- token = in_async_context.set(True)
26
- try:
27
- yield
28
- finally:
29
- in_async_context.reset(token)
30
-
31
- class AsyncLangfuseCallbackHandler(AsyncCallbackHandler):
32
- """
33
- Wraps the synchronous LangfuseCallbackHandler to make it compatible with
34
- LangChain's async methods.
35
-
36
- This works by running the synchronous handler's methods in a separate thread
37
- using `asyncio.to_thread`. This is crucial because `asyncio`'s default
38
- executor can correctly propagate `contextvars`, which solves the
39
- `ValueError: <Token ...> was created in a different Context` from OpenTelemetry.
40
- """
41
- def __init__(self, *args: Any, **kwargs: Any):
42
- if not LANGFUSE_AVAILABLE:
43
- raise ImportError("Langfuse is not available. Please install it with 'pip install langfuse'")
44
- self.sync_handler = LangfuseCallbackHandler(*args, **kwargs)
45
-
46
- def __getattr__(self, name: str) -> Any:
47
- # Delegate any other attribute access to the sync handler
48
- return getattr(self.sync_handler, name)
49
-
50
- async def on_llm_start(
51
- self, serialized: Dict[str, Any], prompts: List[str], **kwargs: Any
52
- ) -> None:
53
- # --- DEBUGGING: Inspect the arguments from LangChain ---
54
- print("--- [DEBUG] AsyncLangfuseCallbackHandler.on_llm_start ---")
55
- print(f"Received prompts type: {type(prompts)}")
56
- print(f"Received prompts value: {prompts!r}") # Using !r to see quotes if it's a string
57
- print("----------------------------------------------------------")
58
- # --- END DEBUGGING ---
59
-
60
- # WORKAROUND: LangChain's async implementation can sometimes pass a raw
61
- # string for prompts instead of a list. We wrap it in a list to ensure
62
- # compatibility with the synchronous handler.
63
- corrected_prompts = prompts if isinstance(prompts, list) else [prompts]
64
-
65
- await asyncio.to_thread(
66
- self.sync_handler.on_llm_start, serialized, corrected_prompts, **kwargs
67
- )
68
-
69
- async def on_llm_end(self, response: LLMResult, **kwargs: Any) -> None:
70
- await asyncio.to_thread(
71
- self.sync_handler.on_llm_end, response, **kwargs
72
- )
73
-
74
- async def on_llm_error(self, error: Union[Exception, KeyboardInterrupt], **kwargs: Any) -> None:
75
- await asyncio.to_thread(
76
- self.sync_handler.on_llm_error, error, **kwargs
77
- )
78
-
79
- async def on_tool_start(self, serialized: Dict[str, Any], input_str: str, **kwargs: Any) -> Any:
80
- await asyncio.to_thread(
81
- self.sync_handler.on_tool_start, serialized, input_str, **kwargs
82
- )
83
-
84
- async def on_tool_end(self, output: str, **kwargs: Any) -> Any:
85
- await asyncio.to_thread(
86
- self.sync_handler.on_tool_end, output, **kwargs
87
- )
88
-
89
- async def on_tool_error(self, error: Union[Exception, KeyboardInterrupt], **kwargs: Any) -> Any:
90
- await asyncio.to_thread(
91
- self.sync_handler.on_tool_error, error, **kwargs
92
- )
93
-
94
- async def on_chain_start(self, serialized: Dict[str, Any], inputs: Dict[str, Any], **kwargs: Any) -> Any:
95
- await asyncio.to_thread(
96
- self.sync_handler.on_chain_start, serialized, inputs, **kwargs
97
- )
98
-
99
- async def on_chain_end(self, outputs: Dict[str, Any], **kwargs: Any) -> Any:
100
- await asyncio.to_thread(
101
- self.sync_handler.on_chain_end, outputs, **kwargs
102
- )
103
-
104
- async def on_chain_error(self, error: Union[Exception, KeyboardInterrupt], **kwargs: Any) -> Any:
105
- await asyncio.to_thread(
106
- self.sync_handler.on_chain_error, error, **kwargs
107
- )
File without changes
File without changes
File without changes
File without changes