99from agentops .semconv .agent import AgentAttributes
1010from agentops .semconv .tool import ToolAttributes
1111from agentops .semconv .message import MessageAttributes
12- from agentops .instrumentation .common .attributes import AttributeMap
1312
1413# Initialize logger for logging potential issues and operations
1514logger = logging .getLogger (__name__ )
@@ -200,106 +199,132 @@ def _process_task(self):
200199 for i , tool in enumerate (tools ):
201200 self ._set_attribute (MessageAttributes .TOOL_CALL_NAME .format (i = i ), tool .get ("name" , "" ))
202201 self ._set_attribute (MessageAttributes .TOOL_CALL_DESCRIPTION .format (i = i ), tool .get ("description" , "" ))
203- except :
204- logger .warning (f"Failed to parse tools json : { task [ 'tools' ] } " )
202+ except ( json . JSONDecodeError , TypeError ) :
203+ logger .warning (f"Failed to parse tools for task : { task . get ( 'id' , 'unknown' ) } " )
205204
206205 def _process_llm (self ):
207206 """Process an LLM instance."""
207+ llm = {}
208208 self ._set_attribute (SpanAttributes .AGENTOPS_SPAN_KIND , "llm" )
209209
210- # Parse model parameters
211- model_name = getattr (self .instance , "model" , None ) or getattr (self .instance , "model_name" , None ) or ""
212- temp = getattr (self .instance , "temperature" , None )
213- max_tokens = getattr (self .instance , "max_tokens" , None )
214-
215- self ._set_attribute (SpanAttributes .LLM_REQUEST_MODEL , model_name )
216- if temp is not None :
217- self ._set_attribute (SpanAttributes .LLM_REQUEST_TEMPERATURE , str (temp ))
218- if max_tokens is not None :
219- self ._set_attribute (SpanAttributes .LLM_REQUEST_MAX_TOKENS , str (max_tokens ))
220-
221- # Add provider info based on class attributes or parent class
222- if hasattr (self .instance , 'provider' ):
223- provider = self .instance .provider
224- self ._set_attribute (SpanAttributes .LLM_PROVIDER , provider )
225-
226- # Set additional LLM attributes
227210 for key , value in self .instance .__dict__ .items ():
228211 if value is None :
229212 continue
230- self . _set_attribute ( f"crewai. llm. { key } " , str (value ) )
213+ llm [ key ] = str (value )
231214
232- def _parse_agents (self , agents ):
233- """Process a list of agents for a crew instance."""
234- # Track agents in an array
235- for i , agent in enumerate (agents ):
236- if not agent :
237- continue
238-
239- agent_data = self ._extract_agent_data (agent )
240-
241- # Set span attributes for each agent
242- agent_prefix = f"crewai.crew.agent.{ i } ."
243- for key , value in agent_data .items ():
244- self ._set_attribute (f"{ agent_prefix } { key } " , value )
245-
246- # Process tools if available
247- if hasattr (agent , "tools" ) and agent .tools :
248- parsed_tools = _parse_tools (agent .tools )
249- for j , tool in enumerate (parsed_tools ):
250- tool_prefix = f"{ agent_prefix } tool.{ j } ."
251- for tool_key , tool_value in tool .items ():
252- self ._set_attribute (f"{ tool_prefix } { tool_key } " , str (tool_value ))
215+ model_name = llm .get ('model_name' , '' ) or llm .get ('model' , '' )
216+ self ._set_attribute (SpanAttributes .LLM_REQUEST_MODEL , model_name )
217+ self ._set_attribute (SpanAttributes .LLM_REQUEST_TEMPERATURE , llm .get ('temperature' , '' ))
218+ self ._set_attribute (SpanAttributes .LLM_REQUEST_MAX_TOKENS , llm .get ('max_tokens' , '' ))
219+ self ._set_attribute (SpanAttributes .LLM_REQUEST_TOP_P , llm .get ('top_p' , '' ))
220+
221+ if 'frequency_penalty' in llm :
222+ self ._set_attribute (SpanAttributes .LLM_REQUEST_FREQUENCY_PENALTY , llm .get ('frequency_penalty' , '' ))
223+ if 'presence_penalty' in llm :
224+ self ._set_attribute (SpanAttributes .LLM_REQUEST_PRESENCE_PENALTY , llm .get ('presence_penalty' , '' ))
225+ if 'streaming' in llm :
226+ self ._set_attribute (SpanAttributes .LLM_REQUEST_STREAMING , llm .get ('streaming' , '' ))
227+
228+ if 'api_key' in llm :
229+ self ._set_attribute ("gen_ai.request.api_key_present" , "true" )
253230
254- # Process LLM if available
255- if hasattr (agent , "llm" ) and agent .llm :
256- llm = agent .llm
257- if hasattr (llm , "model" ) and llm .model :
258- self ._set_attribute (f"{ agent_prefix } llm.model" , str (llm .model ))
259- elif hasattr (llm , "model_name" ) and llm .model_name :
260- self ._set_attribute (f"{ agent_prefix } llm.model" , str (llm .model_name ))
231+ if 'base_url' in llm :
232+ self ._set_attribute (SpanAttributes .LLM_OPENAI_API_BASE , llm .get ('base_url' , '' ))
233+
234+ if 'api_version' in llm :
235+ self ._set_attribute (SpanAttributes .LLM_OPENAI_API_VERSION , llm .get ('api_version' , '' ))
261236
262- def _parse_llms (self , llms ):
263- """Process a dictionary of LLMs for a crew instance."""
264- if not llms or not isinstance (llms , dict ):
237+ def _parse_agents (self , agents ):
238+ """Parse agents into a list of dictionaries."""
239+ if not agents :
240+ logger .debug ("CrewAI: No agents to parse" )
265241 return
242+
243+ agent_count = len (agents )
244+ logger .debug (f"CrewAI: Parsing { agent_count } agents" )
245+
246+ # Pre-process all agents to collect their data first
247+ agent_data_list = []
266248
267- # Track LLMs in an array
268- for i , (role , llm ) in enumerate (llms .items ()):
269- if not llm :
249+ for idx , agent in enumerate (agents ):
250+ if agent is None :
251+ logger .debug (f"CrewAI: Agent at index { idx } is None, skipping" )
252+ agent_data_list .append (None )
270253 continue
271254
272- # Set basic LLM information
273- llm_prefix = f"crewai.crew.llm.{ i } ."
274- self ._set_attribute (f"{ llm_prefix } role" , str (role ))
275-
276- # Extract model information
277- if hasattr (llm , "model" ) and llm .model :
278- self ._set_attribute (f"{ llm_prefix } model" , str (llm .model ))
279- elif hasattr (llm , "model_name" ) and llm .model_name :
280- self ._set_attribute (f"{ llm_prefix } model" , str (llm .model_name ))
255+ logger .debug (f"CrewAI: Processing agent at index { idx } " )
256+ try :
257+ agent_data = self ._extract_agent_data (agent )
258+ agent_data_list .append (agent_data )
259+ except Exception as e :
260+ logger .error (f"CrewAI: Error extracting data for agent at index { idx } : { str (e )} " )
261+ agent_data_list .append (None )
262+
263+ # Now set all attributes at once for each agent
264+ for idx , agent_data in enumerate (agent_data_list ):
265+ if agent_data is None :
266+ continue
281267
282- # Extract other important LLM parameters
283- for key in ["temperature" , "max_tokens" , "top_p" ]:
284- if hasattr (llm , key ) and getattr (llm , key ) is not None :
285- self ._set_attribute (f"{ llm_prefix } { key } " , str (getattr (llm , key )))
268+ for key , value in agent_data .items ():
269+ if key == "tools" and isinstance (value , list ):
270+ for tool_idx , tool in enumerate (value ):
271+ for tool_key , tool_value in tool .items ():
272+ self ._set_attribute (f"crewai.agents.{ idx } .tools.{ tool_idx } .{ tool_key } " , str (tool_value ))
273+ else :
274+ self ._set_attribute (f"crewai.agents.{ idx } .{ key } " , value )
275+
276+ def _parse_llms (self , llms ):
277+ """Parse LLMs into a list of dictionaries."""
278+ for idx , llm in enumerate (llms ):
279+ if llm is not None :
280+ model_name = getattr (llm , "model" , None ) or getattr (llm , "model_name" , None ) or ""
281+ llm_data = {
282+ "model" : model_name ,
283+ "temperature" : llm .temperature ,
284+ "max_tokens" : llm .max_tokens ,
285+ "max_completion_tokens" : llm .max_completion_tokens ,
286+ "top_p" : llm .top_p ,
287+ "n" : llm .n ,
288+ "seed" : llm .seed ,
289+ "base_url" : llm .base_url ,
290+ "api_version" : llm .api_version ,
291+ }
292+
293+ self ._set_attribute (f"{ SpanAttributes .LLM_REQUEST_MODEL } .{ idx } " , model_name )
294+ if hasattr (llm , "temperature" ):
295+ self ._set_attribute (f"{ SpanAttributes .LLM_REQUEST_TEMPERATURE } .{ idx } " , str (llm .temperature ))
296+ if hasattr (llm , "max_tokens" ):
297+ self ._set_attribute (f"{ SpanAttributes .LLM_REQUEST_MAX_TOKENS } .{ idx } " , str (llm .max_tokens ))
298+ if hasattr (llm , "top_p" ):
299+ self ._set_attribute (f"{ SpanAttributes .LLM_REQUEST_TOP_P } .{ idx } " , str (llm .top_p ))
300+
301+ for key , value in llm_data .items ():
302+ if value is not None :
303+ self ._set_attribute (f"crewai.llms.{ idx } .{ key } " , str (value ))
286304
287305 def _extract_agent_data (self , agent ):
288- """Extract relevant data from an agent instance."""
289- agent_data = {}
290-
291- # Extract basic agent information
292- for key in ["id" , "role" , "name" , "goal" , "backstory" ]:
293- if hasattr (agent , key ) and getattr (agent , key ):
294- agent_data [key ] = str (getattr (agent , key ))
295-
296- # Extract configuration settings
297- for key in ["allow_delegation" , "allow_code_execution" , "max_iter" , "max_rpm" , "verbose" ]:
298- if hasattr (agent , key ) and getattr (agent , key ) is not None :
299- agent_data [key ] = str (getattr (agent , key ))
300-
301- return agent_data
306+ """Extract data from an agent."""
307+ model = getattr (agent .llm , "model" , None ) or getattr (agent .llm , "model_name" , None ) or ""
308+
309+ tools_list = []
310+ if hasattr (agent , "tools" ) and agent .tools :
311+ tools_list = _parse_tools (agent .tools )
312+
313+ return {
314+ "id" : str (agent .id ),
315+ "role" : agent .role ,
316+ "goal" : agent .goal ,
317+ "backstory" : agent .backstory ,
318+ "cache" : agent .cache ,
319+ "config" : agent .config ,
320+ "verbose" : agent .verbose ,
321+ "allow_delegation" : agent .allow_delegation ,
322+ "tools" : tools_list ,
323+ "max_iter" : agent .max_iter ,
324+ "llm" : str (model ),
325+ }
302326
303327 def _set_attribute (self , key , value ):
304- """Set an attribute on the span with validation."""
305- set_span_attribute (self .span , key , value )
328+ """Set an attribute on the span."""
329+ if value is not None and value != "" :
330+ set_span_attribute (self .span , key , value )
0 commit comments