crewplus 0.2.66__py3-none-any.whl → 0.2.68__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/callbacks/run_id_handler.py +113 -88
- crewplus/services/tracing_manager.py +18 -2
- {crewplus-0.2.66.dist-info → crewplus-0.2.68.dist-info}/METADATA +1 -1
- {crewplus-0.2.66.dist-info → crewplus-0.2.68.dist-info}/RECORD +7 -7
- {crewplus-0.2.66.dist-info → crewplus-0.2.68.dist-info}/WHEEL +0 -0
- {crewplus-0.2.66.dist-info → crewplus-0.2.68.dist-info}/entry_points.txt +0 -0
- {crewplus-0.2.66.dist-info → crewplus-0.2.68.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,106 +1,131 @@
|
|
|
1
1
|
# File: crewplus/callbacks/run_id_handler.py
|
|
2
2
|
|
|
3
|
-
from typing import Any, Dict
|
|
3
|
+
from typing import Any, Dict, List
|
|
4
4
|
from uuid import UUID
|
|
5
5
|
import logging
|
|
6
6
|
|
|
7
7
|
# Langfuse imports with graceful fallback
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
LANGFUSE_AVAILABLE = False
|
|
15
|
-
# Define dummy base classes if langfuse is not available to avoid runtime errors
|
|
16
|
-
class LangfuseCallbackHandler: pass
|
|
17
|
-
class AsyncLangfuseCallbackHandler: pass
|
|
18
|
-
get_client = None
|
|
8
|
+
from langfuse.langchain import CallbackHandler as LangfuseCallbackHandler
|
|
9
|
+
from .async_langfuse_handler import AsyncLangfuseCallbackHandler
|
|
10
|
+
from langfuse import get_client
|
|
11
|
+
from langchain_core.messages import BaseMessage
|
|
12
|
+
#from langchain_core.outputs import LLMResult
|
|
13
|
+
LANGFUSE_AVAILABLE = True
|
|
19
14
|
|
|
20
15
|
# --- Custom Callback Handlers to capture the run_id ---
|
|
21
|
-
if LANGFUSE_AVAILABLE:
|
|
22
|
-
class RunIdCallbackHandler(LangfuseCallbackHandler):
|
|
23
|
-
"""
|
|
24
|
-
A custom synchronous callback handler that captures the Langchain run_id
|
|
25
|
-
and adds it to the Langfuse trace metadata. It also stores the mapping
|
|
26
|
-
between the run_id and the generated trace_id.
|
|
27
|
-
"""
|
|
28
|
-
def __init__(self, *args, **kwargs):
|
|
29
|
-
super().__init__(*args, **kwargs)
|
|
30
|
-
self.run_trace_map = {}
|
|
31
|
-
# Use a named logger for better context
|
|
32
|
-
self.logger = logging.getLogger(__name__)
|
|
33
|
-
self.logger.info("RunIdCallbackHandler initialized.")
|
|
34
16
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
)
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
17
|
+
class RunIdCallbackHandler(LangfuseCallbackHandler):
|
|
18
|
+
"""
|
|
19
|
+
A custom handler that injects the LangChain run_id into the metadata
|
|
20
|
+
before the Langfuse observation is created.
|
|
21
|
+
"""
|
|
22
|
+
def __init__(self, *args, **kwargs):
|
|
23
|
+
super().__init__(*args, **kwargs)
|
|
24
|
+
self.run_trace_map = {}
|
|
25
|
+
# Use a named logger for better context
|
|
26
|
+
self.logger = logging.getLogger(__name__)
|
|
27
|
+
self.logger.info("RunIdCallbackHandler initialized.")
|
|
46
28
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
29
|
+
def _inject_run_id_to_metadata(self, run_id: UUID, kwargs: Dict[str, Any]) -> Dict[str, Any]:
|
|
30
|
+
"""Helper to safely add the run_id to the metadata in kwargs."""
|
|
31
|
+
metadata = kwargs.get("metadata") or {}
|
|
32
|
+
metadata["langchain_run_id"] = str(run_id)
|
|
33
|
+
kwargs["metadata"] = metadata
|
|
34
|
+
return kwargs
|
|
52
35
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
36
|
+
def on_chain_start(
|
|
37
|
+
self,
|
|
38
|
+
serialized: Dict[str, Any],
|
|
39
|
+
inputs: Dict[str, Any],
|
|
40
|
+
*,
|
|
41
|
+
run_id: UUID,
|
|
42
|
+
**kwargs: Any,
|
|
43
|
+
) -> Any:
|
|
44
|
+
self.logger.debug(f"[on_chain_start] Intercepted run_id: {run_id}")
|
|
45
|
+
kwargs = self._inject_run_id_to_metadata(run_id, kwargs)
|
|
46
|
+
|
|
47
|
+
# Call the base handler with the modified kwargs
|
|
48
|
+
result = super().on_chain_start(serialized, inputs, run_id=run_id, **kwargs)
|
|
49
|
+
|
|
50
|
+
# We still map the trace_id for easy retrieval in tests
|
|
51
|
+
if self.last_trace_id:
|
|
52
|
+
self.run_trace_map[str(run_id)] = self.last_trace_id
|
|
53
|
+
self.logger.info(f"[on_chain_start] Mapped run_id '{run_id}' to trace_id '{self.last_trace_id}'.")
|
|
54
|
+
|
|
55
|
+
return result
|
|
61
56
|
|
|
62
|
-
|
|
63
|
-
|
|
57
|
+
def on_chat_model_start(
|
|
58
|
+
self,
|
|
59
|
+
serialized: Dict[str, Any],
|
|
60
|
+
messages: List[List[BaseMessage]],
|
|
61
|
+
*,
|
|
62
|
+
run_id: UUID,
|
|
63
|
+
parent_run_id: UUID | None = None,
|
|
64
|
+
**kwargs: Any,
|
|
65
|
+
) -> Any:
|
|
66
|
+
self.logger.debug(f"[on_chat_model_start] Intercepted run_id: {run_id}")
|
|
67
|
+
|
|
68
|
+
# Only inject the run_id if this is the root of the trace
|
|
69
|
+
if parent_run_id is None:
|
|
70
|
+
kwargs = self._inject_run_id_to_metadata(run_id, kwargs)
|
|
64
71
|
|
|
65
|
-
|
|
72
|
+
# Call the base handler with potentially modified kwargs
|
|
73
|
+
result = super().on_chat_model_start(serialized, messages, run_id=run_id, parent_run_id=parent_run_id, **kwargs)
|
|
66
74
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
and adds it to the Langfuse trace metadata.
|
|
71
|
-
"""
|
|
72
|
-
def __init__(self, *args, **kwargs):
|
|
73
|
-
super().__init__(*args, **kwargs)
|
|
74
|
-
self.run_trace_map = {}
|
|
75
|
-
self.logger = logging.getLogger(__name__)
|
|
76
|
-
self.logger.info("AsyncRunIdCallbackHandler initialized.")
|
|
75
|
+
if parent_run_id is None and self.last_trace_id:
|
|
76
|
+
self.run_trace_map[str(run_id)] = self.last_trace_id
|
|
77
|
+
self.logger.info(f"[on_chat_model_start] Mapped root run_id '{run_id}' to trace_id '{self.last_trace_id}'.")
|
|
77
78
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
if self.last_trace_id:
|
|
92
|
-
self.run_trace_map[str(run_id)] = self.last_trace_id
|
|
93
|
-
self.logger.info(f"Async: Mapping run_id '{run_id}' to trace_id '{self.last_trace_id}'.")
|
|
79
|
+
return result
|
|
80
|
+
|
|
81
|
+
# You would similarly update the AsyncRunIdCallbackHandler if you use it
|
|
82
|
+
class AsyncRunIdCallbackHandler(AsyncLangfuseCallbackHandler):
|
|
83
|
+
"""
|
|
84
|
+
An async custom handler that injects the LangChain run_id into the metadata
|
|
85
|
+
before the Langfuse observation is created.
|
|
86
|
+
"""
|
|
87
|
+
def __init__(self, *args, **kwargs):
|
|
88
|
+
super().__init__(*args, **kwargs)
|
|
89
|
+
self.run_trace_map = {}
|
|
90
|
+
self.logger = logging.getLogger(__name__)
|
|
91
|
+
self.logger.info("AsyncRunIdCallbackHandler initialized.")
|
|
94
92
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
self.logger.warning(f"Async: Could not find 'last_trace_id' for run_id '{run_id}'. Metadata will not be updated.")
|
|
93
|
+
def _inject_run_id_to_metadata(self, run_id: UUID, kwargs: Dict[str, Any]) -> Dict[str, Any]:
|
|
94
|
+
"""Helper to safely add the run_id to the metadata in kwargs."""
|
|
95
|
+
metadata = kwargs.get("metadata") or {}
|
|
96
|
+
metadata["langchain_run_id"] = str(run_id)
|
|
97
|
+
kwargs["metadata"] = metadata
|
|
98
|
+
return kwargs
|
|
102
99
|
|
|
103
|
-
|
|
104
|
-
|
|
100
|
+
async def on_chain_start(
|
|
101
|
+
self,
|
|
102
|
+
serialized: Dict[str, Any],
|
|
103
|
+
inputs: Dict[str, Any],
|
|
104
|
+
*,
|
|
105
|
+
run_id: UUID,
|
|
106
|
+
**kwargs: Any,
|
|
107
|
+
) -> Any:
|
|
108
|
+
self.logger.debug(f"Async [on_chain_start] Intercepted run_id: {run_id}")
|
|
109
|
+
kwargs = self._inject_run_id_to_metadata(run_id, kwargs)
|
|
110
|
+
result = await super().on_chain_start(serialized, inputs, run_id=run_id, **kwargs)
|
|
111
|
+
if self.last_trace_id:
|
|
112
|
+
self.run_trace_map[str(run_id)] = self.last_trace_id
|
|
113
|
+
return result
|
|
105
114
|
|
|
106
|
-
|
|
115
|
+
async def on_chat_model_start(
|
|
116
|
+
self,
|
|
117
|
+
serialized: Dict[str, Any],
|
|
118
|
+
messages: List[List[BaseMessage]],
|
|
119
|
+
*,
|
|
120
|
+
run_id: UUID,
|
|
121
|
+
parent_run_id: UUID | None = None,
|
|
122
|
+
**kwargs: Any,
|
|
123
|
+
) -> Any:
|
|
124
|
+
self.logger.debug(f"Async [on_chat_model_start] Intercepted run_id: {run_id}")
|
|
125
|
+
if parent_run_id is None:
|
|
126
|
+
kwargs = self._inject_run_id_to_metadata(run_id, kwargs)
|
|
127
|
+
result = await super().on_chat_model_start(serialized, messages, run_id=run_id, parent_run_id=parent_run_id, **kwargs)
|
|
128
|
+
|
|
129
|
+
if parent_run_id is None and self.last_trace_id:
|
|
130
|
+
self.run_trace_map[str(run_id)] = self.last_trace_id
|
|
131
|
+
return result
|
|
@@ -89,20 +89,26 @@ class TracingManager:
|
|
|
89
89
|
|
|
90
90
|
def _initialize_langfuse(self):
|
|
91
91
|
"""Initializes the Langfuse handler if it's available and enabled."""
|
|
92
|
+
self.context.logger.debug("Attempting to initialize Langfuse handlers.")
|
|
92
93
|
if not LANGFUSE_AVAILABLE:
|
|
93
94
|
if self.context.enable_tracing is True:
|
|
94
95
|
self.context.logger.warning("Langfuse is not installed; tracing will be disabled. Install with: pip install langfuse")
|
|
96
|
+
else:
|
|
97
|
+
self.context.logger.debug("Langfuse is not installed, skipping handler initialization.")
|
|
95
98
|
return
|
|
96
99
|
|
|
97
100
|
# Determine if Langfuse should be enabled via an explicit flag or
|
|
98
101
|
# by detecting its environment variables.
|
|
99
102
|
enable_langfuse = self.context.enable_tracing
|
|
100
103
|
if enable_langfuse is None: # Auto-detect if not explicitly set
|
|
104
|
+
self.context.logger.debug("enable_tracing is None, auto-detecting via environment variables.")
|
|
101
105
|
langfuse_env_vars = ["LANGFUSE_PUBLIC_KEY", "LANGFUSE_SECRET_KEY"]
|
|
102
106
|
enable_langfuse = any(os.getenv(var) for var in langfuse_env_vars)
|
|
107
|
+
self.context.logger.debug(f"Auto-detection result for enable_langfuse: {enable_langfuse}")
|
|
103
108
|
|
|
104
109
|
if enable_langfuse:
|
|
105
110
|
try:
|
|
111
|
+
self.context.logger.debug("Langfuse is enabled, creating handlers.")
|
|
106
112
|
# Create and add both the standard and the run_id-capturing handlers.
|
|
107
113
|
# The standard handler creates the trace, and the custom one updates it.
|
|
108
114
|
self._sync_handlers.append(LangfuseCallbackHandler())
|
|
@@ -112,27 +118,37 @@ class TracingManager:
|
|
|
112
118
|
self._async_handlers.append(AsyncLangfuseCallbackHandler())
|
|
113
119
|
self._async_handlers.append(AsyncRunIdCallbackHandler())
|
|
114
120
|
|
|
115
|
-
self.context.logger.info(f"Langfuse tracing enabled for {self.context.get_model_identifier()}")
|
|
121
|
+
self.context.logger.info(f"Langfuse tracing enabled for {self.context.get_model_identifier()}. Sync handlers loaded: {len(self._sync_handlers)}")
|
|
116
122
|
except Exception as e:
|
|
117
|
-
self.context.logger.warning(f"Failed to initialize Langfuse: {e}")
|
|
123
|
+
self.context.logger.warning(f"Failed to initialize Langfuse: {e}", exc_info=True)
|
|
124
|
+
else:
|
|
125
|
+
self.context.logger.info("Langfuse is not enabled, skipping handler initialization.")
|
|
118
126
|
|
|
119
127
|
def _add_callbacks_to_config(self, config: Optional[dict], handlers: List[Any]) -> dict:
|
|
120
128
|
"""A generic helper to add a list of handlers to a config object."""
|
|
121
129
|
if config is None:
|
|
122
130
|
config = {}
|
|
123
131
|
|
|
132
|
+
self.context.logger.debug(f"Adding callbacks to config. Have {len(handlers)} handlers to add.")
|
|
133
|
+
|
|
124
134
|
if not handlers or config.get("metadata", {}).get("tracing_disabled"):
|
|
135
|
+
self.context.logger.debug("No handlers to add or tracing is disabled for this run.")
|
|
125
136
|
return config
|
|
126
137
|
|
|
127
138
|
callbacks = config.get("callbacks")
|
|
128
139
|
|
|
129
140
|
if hasattr(callbacks, 'add_handler') and hasattr(callbacks, 'handlers'):
|
|
141
|
+
# This block is for CallbackManager instances
|
|
142
|
+
self.context.logger.debug(f"Config has a CallbackManager with {len(callbacks.handlers)} existing handlers.")
|
|
130
143
|
for handler in handlers:
|
|
131
144
|
if not any(isinstance(cb, type(handler)) for cb in callbacks.handlers):
|
|
132
145
|
callbacks.add_handler(handler, inherit=True)
|
|
146
|
+
self.context.logger.debug(f"CallbackManager now has {len(callbacks.handlers)} handlers.")
|
|
133
147
|
return config
|
|
134
148
|
|
|
149
|
+
# This block is for simple lists of callbacks
|
|
135
150
|
current_callbacks = callbacks or []
|
|
151
|
+
self.context.logger.debug(f"Config has a list with {len(current_callbacks)} existing callbacks.")
|
|
136
152
|
new_callbacks = list(current_callbacks)
|
|
137
153
|
|
|
138
154
|
for handler in handlers:
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
crewplus-0.2.
|
|
2
|
-
crewplus-0.2.
|
|
3
|
-
crewplus-0.2.
|
|
4
|
-
crewplus-0.2.
|
|
1
|
+
crewplus-0.2.68.dist-info/METADATA,sha256=sqbjQMZRzh7U0AajzZZ1lvgXuZzRsYDI3_pC9AKYLYg,5424
|
|
2
|
+
crewplus-0.2.68.dist-info/WHEEL,sha256=9P2ygRxDrTJz3gsagc0Z96ukrxjr-LFBGOgv3AuKlCA,90
|
|
3
|
+
crewplus-0.2.68.dist-info/entry_points.txt,sha256=6OYgBcLyFCUgeqLgnvMyOJxPCWzgy7se4rLPKtNonMs,34
|
|
4
|
+
crewplus-0.2.68.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
|
-
crewplus/callbacks/run_id_handler.py,sha256=
|
|
8
|
+
crewplus/callbacks/run_id_handler.py,sha256=T_YqmGmUp2_DIc01dlVY-aC43NKcevfRejAWN-lft6M,5266
|
|
9
9
|
crewplus/services/__init__.py,sha256=V1CG8b2NOmRzNgQH7BPl4KVxWSYJH5vfEsW1wVErKNE,375
|
|
10
10
|
crewplus/services/azure_chat_model.py,sha256=iWzJ2GQFSNmwJx-2O5_xKPSB6VVc-7T6bcfFI8_WezA,5521
|
|
11
11
|
crewplus/services/gemini_chat_model.py,sha256=DYqz01H2TIHiCDQesSozVfOsMigno6QGwOtIweg7UHk,40103
|
|
12
12
|
crewplus/services/init_services.py,sha256=tc1ti8Yufo2ixlJpwg8uH0KmoyQ4EqxCOe4uTEWnlRM,2413
|
|
13
13
|
crewplus/services/model_load_balancer.py,sha256=Q9Gx3GrbKworU-Ytxeqp0ggHSgZ1Q6brtTk-nCl4sak,12095
|
|
14
|
-
crewplus/services/tracing_manager.py,sha256=
|
|
14
|
+
crewplus/services/tracing_manager.py,sha256=oyKoPAfirAvb9M6Kca6HMNQYo3mBtXCLM3jFkPYU55s,8368
|
|
15
15
|
crewplus/utils/__init__.py,sha256=2Gk1n5srFJQnFfBuYTxktdtKOVZyNrFcNaZKhXk35Pw,142
|
|
16
16
|
crewplus/utils/schema_action.py,sha256=GDaBoVFQD1rXqrLVSMTfXYW1xcUu7eDcHsn57XBSnIg,422
|
|
17
17
|
crewplus/utils/schema_document_updater.py,sha256=frvffxn2vbi71fHFPoGb9hq7gH2azmmdq17p-Fumnvg,7322
|
|
@@ -23,4 +23,4 @@ docs/GeminiChatModel.md,sha256=zZYyl6RmjZTUsKxxMiC9O4yV70MC4TD-IGUmWhIDBKA,8677
|
|
|
23
23
|
docs/ModelLoadBalancer.md,sha256=aGHES1dcXPz4c7Y8kB5-vsCNJjriH2SWmjBkSGoYKiI,4398
|
|
24
24
|
docs/VDBService.md,sha256=Dw286Rrf_fsi13jyD3Bo4Sy7nZ_G7tYm7d8MZ2j9hxk,9375
|
|
25
25
|
docs/index.md,sha256=3tlc15uR8lzFNM5WjdoZLw0Y9o1P1gwgbEnOdIBspqc,1643
|
|
26
|
-
crewplus-0.2.
|
|
26
|
+
crewplus-0.2.68.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|