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.

@@ -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
- try:
9
- from langfuse.langchain import CallbackHandler as LangfuseCallbackHandler
10
- from .async_langfuse_handler import AsyncLangfuseCallbackHandler
11
- from langfuse import get_client
12
- LANGFUSE_AVAILABLE = True
13
- except ImportError:
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
- def on_chain_start(
36
- self,
37
- serialized: Dict[str, Any],
38
- inputs: Dict[str, Any],
39
- run_id: UUID,
40
- **kwargs: Any,
41
- ) -> Any:
42
- self.logger.debug(f"on_chain_start triggered for run_id: {run_id}")
43
- # First, let the base handler do its work, which includes creating the trace
44
- run = super().on_chain_start(serialized, inputs, run_id, **kwargs)
45
- self.logger.debug(f"Base handler's on_chain_start completed. Current trace_id: {self.last_trace_id}")
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
- try:
48
- # The base handler sets `self.last_trace_id` when a trace is created
49
- if self.last_trace_id:
50
- self.run_trace_map[str(run_id)] = self.last_trace_id
51
- self.logger.info(f"Mapping run_id '{run_id}' to trace_id '{self.last_trace_id}'.")
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
- # Then, update the created trace with the run_id as metadata
54
- langfuse_client = get_client()
55
- langfuse_client.update_current_trace(
56
- metadata={"langchain_run_id": str(run_id)}
57
- )
58
- self.logger.info(f"Successfully updated trace '{self.last_trace_id}' with metadata for run_id '{run_id}'.")
59
- else:
60
- self.logger.warning(f"Could not find 'last_trace_id' for run_id '{run_id}'. Metadata will not be updated.")
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
- except Exception as e:
63
- self.logger.error(f"Failed to process run_id '{run_id}' in RunIdCallbackHandler: {e}", exc_info=True)
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
- return run
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
- class AsyncRunIdCallbackHandler(AsyncLangfuseCallbackHandler):
68
- """
69
- A custom asynchronous callback handler that captures the Langchain run_id
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
- async def on_chain_start(
79
- self,
80
- serialized: Dict[str, Any],
81
- inputs: Dict[str, Any],
82
- run_id: UUID,
83
- **kwargs: Any,
84
- ) -> Any:
85
- self.logger.debug(f"Async on_chain_start triggered for run_id: {run_id}")
86
- # First, let the base handler do its work
87
- run = await super().on_chain_start(serialized, inputs, run_id, **kwargs)
88
- self.logger.debug(f"Async base handler's on_chain_start completed. Current trace_id: {self.last_trace_id}")
89
-
90
- try:
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
- langfuse_client = get_client()
96
- langfuse_client.update_current_trace(
97
- metadata={"langchain_run_id": str(run_id)}
98
- )
99
- self.logger.info(f"Async: Successfully updated trace '{self.last_trace_id}' with metadata for run_id '{run_id}'.")
100
- else:
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
- except Exception as e:
104
- self.logger.error(f"Async: Failed to process run_id '{run_id}' in AsyncRunIdCallbackHandler: {e}", exc_info=True)
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
- return run
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,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: crewplus
3
- Version: 0.2.66
3
+ Version: 0.2.68
4
4
  Summary: Base services for CrewPlus AI applications
5
5
  Author-Email: Tim Liu <tim@opsmateai.com>
6
6
  License: MIT
@@ -1,17 +1,17 @@
1
- crewplus-0.2.66.dist-info/METADATA,sha256=nfG_3A6490ii2Hmp9cfDZgWd_aIOebzVa7cyhAsCDao,5424
2
- crewplus-0.2.66.dist-info/WHEEL,sha256=9P2ygRxDrTJz3gsagc0Z96ukrxjr-LFBGOgv3AuKlCA,90
3
- crewplus-0.2.66.dist-info/entry_points.txt,sha256=6OYgBcLyFCUgeqLgnvMyOJxPCWzgy7se4rLPKtNonMs,34
4
- crewplus-0.2.66.dist-info/licenses/LICENSE,sha256=2_NHSHRTKB_cTcT_GXgcenOCtIZku8j343mOgAguTfc,1087
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=UurImqJYJg_EnOKB8nzBmG377KL4wI7fl8lz-98_VXY,4964
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=tTha3NGoQUvO0gwBrx_pJzQ3-2eEz2ZsJtICtI6OeiA,7033
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.66.dist-info/RECORD,,
26
+ crewplus-0.2.68.dist-info/RECORD,,