openlit 1.34.30__py3-none-any.whl → 1.34.32__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.
Files changed (168) hide show
  1. openlit/__helpers.py +235 -86
  2. openlit/__init__.py +19 -14
  3. openlit/_instrumentors.py +2 -1
  4. openlit/evals/all.py +50 -21
  5. openlit/evals/bias_detection.py +47 -20
  6. openlit/evals/hallucination.py +53 -22
  7. openlit/evals/toxicity.py +50 -21
  8. openlit/evals/utils.py +54 -30
  9. openlit/guard/all.py +61 -19
  10. openlit/guard/prompt_injection.py +34 -14
  11. openlit/guard/restrict_topic.py +46 -15
  12. openlit/guard/sensitive_topic.py +34 -14
  13. openlit/guard/utils.py +58 -22
  14. openlit/instrumentation/ag2/__init__.py +113 -6
  15. openlit/instrumentation/ag2/ag2.py +459 -17
  16. openlit/instrumentation/ag2/async_ag2.py +459 -17
  17. openlit/instrumentation/ag2/utils.py +475 -31
  18. openlit/instrumentation/ai21/__init__.py +43 -14
  19. openlit/instrumentation/ai21/ai21.py +47 -21
  20. openlit/instrumentation/ai21/async_ai21.py +47 -21
  21. openlit/instrumentation/ai21/utils.py +299 -78
  22. openlit/instrumentation/anthropic/__init__.py +21 -4
  23. openlit/instrumentation/anthropic/anthropic.py +28 -17
  24. openlit/instrumentation/anthropic/async_anthropic.py +28 -17
  25. openlit/instrumentation/anthropic/utils.py +145 -35
  26. openlit/instrumentation/assemblyai/__init__.py +11 -2
  27. openlit/instrumentation/assemblyai/assemblyai.py +15 -4
  28. openlit/instrumentation/assemblyai/utils.py +120 -25
  29. openlit/instrumentation/astra/__init__.py +43 -10
  30. openlit/instrumentation/astra/astra.py +28 -5
  31. openlit/instrumentation/astra/async_astra.py +28 -5
  32. openlit/instrumentation/astra/utils.py +151 -55
  33. openlit/instrumentation/azure_ai_inference/__init__.py +43 -10
  34. openlit/instrumentation/azure_ai_inference/async_azure_ai_inference.py +53 -21
  35. openlit/instrumentation/azure_ai_inference/azure_ai_inference.py +53 -21
  36. openlit/instrumentation/azure_ai_inference/utils.py +307 -83
  37. openlit/instrumentation/bedrock/__init__.py +21 -4
  38. openlit/instrumentation/bedrock/bedrock.py +63 -25
  39. openlit/instrumentation/bedrock/utils.py +139 -30
  40. openlit/instrumentation/chroma/__init__.py +89 -16
  41. openlit/instrumentation/chroma/chroma.py +28 -6
  42. openlit/instrumentation/chroma/utils.py +167 -51
  43. openlit/instrumentation/cohere/__init__.py +63 -18
  44. openlit/instrumentation/cohere/async_cohere.py +63 -24
  45. openlit/instrumentation/cohere/cohere.py +63 -24
  46. openlit/instrumentation/cohere/utils.py +286 -73
  47. openlit/instrumentation/controlflow/__init__.py +35 -9
  48. openlit/instrumentation/controlflow/controlflow.py +66 -33
  49. openlit/instrumentation/crawl4ai/__init__.py +25 -10
  50. openlit/instrumentation/crawl4ai/async_crawl4ai.py +78 -31
  51. openlit/instrumentation/crawl4ai/crawl4ai.py +78 -31
  52. openlit/instrumentation/crewai/__init__.py +40 -15
  53. openlit/instrumentation/crewai/async_crewai.py +32 -7
  54. openlit/instrumentation/crewai/crewai.py +32 -7
  55. openlit/instrumentation/crewai/utils.py +159 -56
  56. openlit/instrumentation/dynamiq/__init__.py +46 -12
  57. openlit/instrumentation/dynamiq/dynamiq.py +74 -33
  58. openlit/instrumentation/elevenlabs/__init__.py +23 -4
  59. openlit/instrumentation/elevenlabs/async_elevenlabs.py +16 -4
  60. openlit/instrumentation/elevenlabs/elevenlabs.py +16 -4
  61. openlit/instrumentation/elevenlabs/utils.py +128 -25
  62. openlit/instrumentation/embedchain/__init__.py +11 -2
  63. openlit/instrumentation/embedchain/embedchain.py +68 -35
  64. openlit/instrumentation/firecrawl/__init__.py +24 -7
  65. openlit/instrumentation/firecrawl/firecrawl.py +46 -20
  66. openlit/instrumentation/google_ai_studio/__init__.py +45 -10
  67. openlit/instrumentation/google_ai_studio/async_google_ai_studio.py +67 -44
  68. openlit/instrumentation/google_ai_studio/google_ai_studio.py +67 -44
  69. openlit/instrumentation/google_ai_studio/utils.py +180 -67
  70. openlit/instrumentation/gpt4all/__init__.py +22 -7
  71. openlit/instrumentation/gpt4all/gpt4all.py +67 -29
  72. openlit/instrumentation/gpt4all/utils.py +285 -61
  73. openlit/instrumentation/gpu/__init__.py +128 -47
  74. openlit/instrumentation/groq/__init__.py +21 -4
  75. openlit/instrumentation/groq/async_groq.py +33 -21
  76. openlit/instrumentation/groq/groq.py +33 -21
  77. openlit/instrumentation/groq/utils.py +192 -55
  78. openlit/instrumentation/haystack/__init__.py +70 -24
  79. openlit/instrumentation/haystack/async_haystack.py +28 -6
  80. openlit/instrumentation/haystack/haystack.py +28 -6
  81. openlit/instrumentation/haystack/utils.py +196 -74
  82. openlit/instrumentation/julep/__init__.py +69 -19
  83. openlit/instrumentation/julep/async_julep.py +53 -27
  84. openlit/instrumentation/julep/julep.py +53 -28
  85. openlit/instrumentation/langchain/__init__.py +74 -63
  86. openlit/instrumentation/langchain/callback_handler.py +1100 -0
  87. openlit/instrumentation/langchain_community/__init__.py +13 -2
  88. openlit/instrumentation/langchain_community/async_langchain_community.py +23 -5
  89. openlit/instrumentation/langchain_community/langchain_community.py +23 -5
  90. openlit/instrumentation/langchain_community/utils.py +35 -9
  91. openlit/instrumentation/letta/__init__.py +68 -15
  92. openlit/instrumentation/letta/letta.py +99 -54
  93. openlit/instrumentation/litellm/__init__.py +43 -14
  94. openlit/instrumentation/litellm/async_litellm.py +51 -26
  95. openlit/instrumentation/litellm/litellm.py +51 -26
  96. openlit/instrumentation/litellm/utils.py +304 -102
  97. openlit/instrumentation/llamaindex/__init__.py +267 -90
  98. openlit/instrumentation/llamaindex/async_llamaindex.py +28 -6
  99. openlit/instrumentation/llamaindex/llamaindex.py +28 -6
  100. openlit/instrumentation/llamaindex/utils.py +204 -91
  101. openlit/instrumentation/mem0/__init__.py +11 -2
  102. openlit/instrumentation/mem0/mem0.py +50 -29
  103. openlit/instrumentation/milvus/__init__.py +10 -2
  104. openlit/instrumentation/milvus/milvus.py +31 -6
  105. openlit/instrumentation/milvus/utils.py +166 -67
  106. openlit/instrumentation/mistral/__init__.py +63 -18
  107. openlit/instrumentation/mistral/async_mistral.py +63 -24
  108. openlit/instrumentation/mistral/mistral.py +63 -24
  109. openlit/instrumentation/mistral/utils.py +277 -69
  110. openlit/instrumentation/multion/__init__.py +69 -19
  111. openlit/instrumentation/multion/async_multion.py +57 -26
  112. openlit/instrumentation/multion/multion.py +57 -26
  113. openlit/instrumentation/ollama/__init__.py +39 -18
  114. openlit/instrumentation/ollama/async_ollama.py +57 -26
  115. openlit/instrumentation/ollama/ollama.py +57 -26
  116. openlit/instrumentation/ollama/utils.py +226 -50
  117. openlit/instrumentation/openai/__init__.py +156 -32
  118. openlit/instrumentation/openai/async_openai.py +147 -67
  119. openlit/instrumentation/openai/openai.py +150 -67
  120. openlit/instrumentation/openai/utils.py +657 -185
  121. openlit/instrumentation/openai_agents/__init__.py +5 -1
  122. openlit/instrumentation/openai_agents/processor.py +110 -90
  123. openlit/instrumentation/phidata/__init__.py +13 -5
  124. openlit/instrumentation/phidata/phidata.py +67 -32
  125. openlit/instrumentation/pinecone/__init__.py +48 -9
  126. openlit/instrumentation/pinecone/async_pinecone.py +27 -5
  127. openlit/instrumentation/pinecone/pinecone.py +27 -5
  128. openlit/instrumentation/pinecone/utils.py +153 -47
  129. openlit/instrumentation/premai/__init__.py +22 -7
  130. openlit/instrumentation/premai/premai.py +51 -26
  131. openlit/instrumentation/premai/utils.py +246 -59
  132. openlit/instrumentation/pydantic_ai/__init__.py +49 -22
  133. openlit/instrumentation/pydantic_ai/pydantic_ai.py +69 -16
  134. openlit/instrumentation/pydantic_ai/utils.py +89 -24
  135. openlit/instrumentation/qdrant/__init__.py +19 -4
  136. openlit/instrumentation/qdrant/async_qdrant.py +33 -7
  137. openlit/instrumentation/qdrant/qdrant.py +33 -7
  138. openlit/instrumentation/qdrant/utils.py +228 -93
  139. openlit/instrumentation/reka/__init__.py +23 -10
  140. openlit/instrumentation/reka/async_reka.py +17 -11
  141. openlit/instrumentation/reka/reka.py +17 -11
  142. openlit/instrumentation/reka/utils.py +138 -36
  143. openlit/instrumentation/together/__init__.py +44 -12
  144. openlit/instrumentation/together/async_together.py +50 -27
  145. openlit/instrumentation/together/together.py +50 -27
  146. openlit/instrumentation/together/utils.py +301 -71
  147. openlit/instrumentation/transformers/__init__.py +2 -1
  148. openlit/instrumentation/transformers/transformers.py +13 -3
  149. openlit/instrumentation/transformers/utils.py +139 -36
  150. openlit/instrumentation/vertexai/__init__.py +81 -16
  151. openlit/instrumentation/vertexai/async_vertexai.py +33 -15
  152. openlit/instrumentation/vertexai/utils.py +123 -27
  153. openlit/instrumentation/vertexai/vertexai.py +33 -15
  154. openlit/instrumentation/vllm/__init__.py +12 -5
  155. openlit/instrumentation/vllm/utils.py +121 -31
  156. openlit/instrumentation/vllm/vllm.py +16 -10
  157. openlit/otel/events.py +35 -10
  158. openlit/otel/metrics.py +32 -24
  159. openlit/otel/tracing.py +24 -9
  160. openlit/semcov/__init__.py +82 -6
  161. {openlit-1.34.30.dist-info → openlit-1.34.32.dist-info}/METADATA +2 -1
  162. openlit-1.34.32.dist-info/RECORD +166 -0
  163. openlit/instrumentation/langchain/async_langchain.py +0 -102
  164. openlit/instrumentation/langchain/langchain.py +0 -102
  165. openlit/instrumentation/langchain/utils.py +0 -252
  166. openlit-1.34.30.dist-info/RECORD +0 -168
  167. {openlit-1.34.30.dist-info → openlit-1.34.32.dist-info}/LICENSE +0 -0
  168. {openlit-1.34.30.dist-info → openlit-1.34.32.dist-info}/WHEEL +0 -0
@@ -4,18 +4,59 @@ Module for monitoring AG2 API calls (async version).
4
4
 
5
5
  import time
6
6
  from opentelemetry.trace import SpanKind
7
- from openlit.__helpers import (
8
- handle_exception,
9
- set_server_address_and_port
10
- )
7
+ from openlit.__helpers import handle_exception, set_server_address_and_port
11
8
  from openlit.instrumentation.ag2.utils import (
12
9
  process_agent_creation,
13
10
  process_agent_run,
11
+ process_agent_generate_reply,
12
+ process_agent_receive,
13
+ process_agent_send,
14
+ process_groupchat_operation,
15
+ process_speaker_selection,
14
16
  )
15
17
  from openlit.semcov import SemanticConvention
16
18
 
17
- def async_conversable_agent(version, environment, application_name, tracer, pricing_info,
18
- capture_message_content, metrics, disable_metrics):
19
+
20
+ def extract_agent_name(instance, fallback="unknown_agent"):
21
+ """
22
+ Extract agent name from AG2 instance with intelligent fallbacks.
23
+
24
+ Args:
25
+ instance: AG2 instance (Agent, GroupChat, etc.)
26
+ fallback: Default name if no name can be extracted
27
+
28
+ Returns:
29
+ str: Agent name or meaningful fallback
30
+ """
31
+ # Try to get the name attribute first
32
+ agent_name = getattr(instance, "name", None)
33
+ if agent_name:
34
+ return agent_name
35
+
36
+ # Try to get from class name and make it meaningful
37
+ class_name = getattr(instance, "__class__", type(instance)).__name__.lower()
38
+
39
+ # Map common AG2 class names to meaningful names
40
+ class_name_map = {
41
+ "conversableagent": "conversable_agent",
42
+ "groupchat": "group_chat",
43
+ "groupchatmanager": "group_chat_manager",
44
+ "agent": "agent",
45
+ }
46
+
47
+ return class_name_map.get(class_name, fallback)
48
+
49
+
50
+ def async_conversable_agent(
51
+ version,
52
+ environment,
53
+ application_name,
54
+ tracer,
55
+ pricing_info,
56
+ capture_message_content,
57
+ metrics,
58
+ disable_metrics,
59
+ ):
19
60
  """
20
61
  Generates a telemetry wrapper for AG2 async conversable agent creation.
21
62
  """
@@ -25,12 +66,16 @@ def async_conversable_agent(version, environment, application_name, tracer, pric
25
66
  Wraps the AG2 async conversable agent creation call.
26
67
  """
27
68
 
28
- server_address, server_port = set_server_address_and_port(instance, "127.0.0.1", 80)
29
- agent_name = kwargs.get("name", "NOT_FOUND")
69
+ server_address, server_port = set_server_address_and_port(
70
+ instance, "127.0.0.1", 80
71
+ )
72
+ agent_name = kwargs.get("name", "unknown_agent")
30
73
  llm_config = kwargs.get("llm_config", {})
31
74
  system_message = kwargs.get("system_message", "")
32
75
 
33
- span_name = f"{SemanticConvention.GEN_AI_OPERATION_TYPE_CREATE_AGENT} {agent_name}"
76
+ span_name = (
77
+ f"{SemanticConvention.GEN_AI_OPERATION_TYPE_CREATE_AGENT} {agent_name}"
78
+ )
34
79
 
35
80
  with tracer.start_as_current_span(span_name, kind=SpanKind.CLIENT) as span:
36
81
  start_time = time.time()
@@ -51,7 +96,7 @@ def async_conversable_agent(version, environment, application_name, tracer, pric
51
96
  span=span,
52
97
  capture_message_content=capture_message_content,
53
98
  disable_metrics=disable_metrics,
54
- version=version
99
+ version=version,
55
100
  )
56
101
 
57
102
  except Exception as e:
@@ -61,8 +106,17 @@ def async_conversable_agent(version, environment, application_name, tracer, pric
61
106
 
62
107
  return wrapper
63
108
 
64
- def async_agent_run(version, environment, application_name, tracer, pricing_info,
65
- capture_message_content, metrics, disable_metrics):
109
+
110
+ def async_agent_run(
111
+ version,
112
+ environment,
113
+ application_name,
114
+ tracer,
115
+ pricing_info,
116
+ capture_message_content,
117
+ metrics,
118
+ disable_metrics,
119
+ ):
66
120
  """
67
121
  Generates a telemetry wrapper for AG2 async agent run execution.
68
122
  """
@@ -72,15 +126,17 @@ def async_agent_run(version, environment, application_name, tracer, pricing_info
72
126
  Wraps the AG2 async agent run execution call.
73
127
  """
74
128
 
75
- server_address, server_port = set_server_address_and_port(instance, "127.0.0.1", 80)
129
+ server_address, server_port = set_server_address_and_port(
130
+ instance, "127.0.0.1", 80
131
+ )
76
132
 
77
133
  # Extract agent name from instance
78
- agent_name = getattr(instance, "name", "NOT_FOUND")
134
+ agent_name = extract_agent_name(instance)
79
135
 
80
136
  # Extract model from instance llm_config
81
- request_model = "gpt-4o"
137
+ request_model = "unknown"
82
138
  if hasattr(instance, "llm_config") and isinstance(instance.llm_config, dict):
83
- request_model = instance.llm_config.get("model", "gpt-4o")
139
+ request_model = instance.llm_config.get("model", "unknown")
84
140
 
85
141
  span_name = f"{SemanticConvention.GEN_AI_OPERATION_TYPE_EXECUTE_AGENT_TASK} {agent_name}"
86
142
 
@@ -103,7 +159,393 @@ def async_agent_run(version, environment, application_name, tracer, pricing_info
103
159
  span=span,
104
160
  capture_message_content=capture_message_content,
105
161
  disable_metrics=disable_metrics,
106
- version=version
162
+ version=version,
163
+ )
164
+
165
+ except Exception as e:
166
+ handle_exception(span, e)
167
+
168
+ return response
169
+
170
+ return wrapper
171
+
172
+
173
+ def async_agent_generate_reply(
174
+ version,
175
+ environment,
176
+ application_name,
177
+ tracer,
178
+ pricing_info,
179
+ capture_message_content,
180
+ metrics,
181
+ disable_metrics,
182
+ ):
183
+ """
184
+ Generates a telemetry wrapper for AG2 ConversableAgent.generate_reply (async version).
185
+ """
186
+
187
+ def wrapper(wrapped, instance, args, kwargs):
188
+ """
189
+ Wraps the AG2 ConversableAgent.generate_reply call (async version).
190
+ """
191
+
192
+ server_address, server_port = set_server_address_and_port(
193
+ instance, "127.0.0.1", 80
194
+ )
195
+
196
+ # Extract agent name from instance
197
+ agent_name = extract_agent_name(instance)
198
+
199
+ # Extract model from instance llm_config
200
+ request_model = "unknown"
201
+ if hasattr(instance, "llm_config") and isinstance(instance.llm_config, dict):
202
+ request_model = instance.llm_config.get("model", "unknown")
203
+
204
+ span_name = f"{SemanticConvention.GEN_AI_OPERATION_TYPE_CHAT} {agent_name}"
205
+
206
+ with tracer.start_as_current_span(span_name, kind=SpanKind.CLIENT) as span:
207
+ start_time = time.time()
208
+ response = wrapped(*args, **kwargs)
209
+
210
+ try:
211
+ response = process_agent_generate_reply(
212
+ response=response,
213
+ agent_name=agent_name,
214
+ request_model=request_model,
215
+ messages=args[0] if args else kwargs.get("messages", []),
216
+ sender=args[1] if len(args) > 1 else kwargs.get("sender", None),
217
+ pricing_info=pricing_info,
218
+ server_port=server_port,
219
+ server_address=server_address,
220
+ environment=environment,
221
+ application_name=application_name,
222
+ metrics=metrics,
223
+ start_time=start_time,
224
+ span=span,
225
+ capture_message_content=capture_message_content,
226
+ disable_metrics=disable_metrics,
227
+ version=version,
228
+ )
229
+
230
+ except Exception as e:
231
+ handle_exception(span, e)
232
+
233
+ return response
234
+
235
+ return wrapper
236
+
237
+
238
+ def async_agent_receive(
239
+ version,
240
+ environment,
241
+ application_name,
242
+ tracer,
243
+ pricing_info,
244
+ capture_message_content,
245
+ metrics,
246
+ disable_metrics,
247
+ ):
248
+ """
249
+ Generates a telemetry wrapper for AG2 ConversableAgent.receive (async version).
250
+ """
251
+
252
+ def wrapper(wrapped, instance, args, kwargs):
253
+ """
254
+ Wraps the AG2 ConversableAgent.receive call (async version).
255
+ """
256
+
257
+ server_address, server_port = set_server_address_and_port(
258
+ instance, "127.0.0.1", 80
259
+ )
260
+
261
+ # Extract agent name from instance
262
+ agent_name = extract_agent_name(instance)
263
+
264
+ # Extract sender information
265
+ sender = args[0] if args else kwargs.get("sender", None)
266
+ sender_name = getattr(sender, "name", "Unknown") if sender else "Unknown"
267
+
268
+ # Extract message
269
+ message = args[1] if len(args) > 1 else kwargs.get("message", "")
270
+
271
+ span_name = f"{SemanticConvention.GEN_AI_OPERATION_TYPE_CHAT} {agent_name}"
272
+
273
+ with tracer.start_as_current_span(span_name, kind=SpanKind.CLIENT) as span:
274
+ start_time = time.time()
275
+ response = wrapped(*args, **kwargs)
276
+
277
+ try:
278
+ process_agent_receive(
279
+ message=message,
280
+ agent_name=agent_name,
281
+ sender_name=sender_name,
282
+ agent_instance=instance,
283
+ pricing_info=pricing_info,
284
+ server_port=server_port,
285
+ server_address=server_address,
286
+ environment=environment,
287
+ application_name=application_name,
288
+ metrics=metrics,
289
+ start_time=start_time,
290
+ span=span,
291
+ capture_message_content=capture_message_content,
292
+ disable_metrics=disable_metrics,
293
+ version=version,
294
+ )
295
+
296
+ except Exception as e:
297
+ handle_exception(span, e)
298
+
299
+ return response
300
+
301
+ return wrapper
302
+
303
+
304
+ def async_agent_send(
305
+ version,
306
+ environment,
307
+ application_name,
308
+ tracer,
309
+ pricing_info,
310
+ capture_message_content,
311
+ metrics,
312
+ disable_metrics,
313
+ ):
314
+ """
315
+ Generates a telemetry wrapper for AG2 ConversableAgent.send (async version).
316
+ """
317
+
318
+ def wrapper(wrapped, instance, args, kwargs):
319
+ """
320
+ Wraps the AG2 ConversableAgent.send call (async version).
321
+ """
322
+
323
+ server_address, server_port = set_server_address_and_port(
324
+ instance, "127.0.0.1", 80
325
+ )
326
+
327
+ # Extract agent name from instance
328
+ agent_name = extract_agent_name(instance)
329
+
330
+ # Extract recipient information
331
+ recipient = args[0] if args else kwargs.get("recipient", None)
332
+ recipient_name = (
333
+ getattr(recipient, "name", "Unknown") if recipient else "Unknown"
334
+ )
335
+
336
+ # Extract message
337
+ message = args[1] if len(args) > 1 else kwargs.get("message", "")
338
+
339
+ span_name = f"{SemanticConvention.GEN_AI_OPERATION_TYPE_CHAT} {agent_name}"
340
+
341
+ with tracer.start_as_current_span(span_name, kind=SpanKind.CLIENT) as span:
342
+ start_time = time.time()
343
+ response = wrapped(*args, **kwargs)
344
+
345
+ try:
346
+ process_agent_send(
347
+ message=message,
348
+ agent_name=agent_name,
349
+ recipient_name=recipient_name,
350
+ agent_instance=instance,
351
+ pricing_info=pricing_info,
352
+ server_port=server_port,
353
+ server_address=server_address,
354
+ environment=environment,
355
+ application_name=application_name,
356
+ metrics=metrics,
357
+ start_time=start_time,
358
+ span=span,
359
+ capture_message_content=capture_message_content,
360
+ disable_metrics=disable_metrics,
361
+ version=version,
362
+ )
363
+
364
+ except Exception as e:
365
+ handle_exception(span, e)
366
+
367
+ return response
368
+
369
+ return wrapper
370
+
371
+
372
+ def async_groupchat_manager_run_chat(
373
+ version,
374
+ environment,
375
+ application_name,
376
+ tracer,
377
+ pricing_info,
378
+ capture_message_content,
379
+ metrics,
380
+ disable_metrics,
381
+ ):
382
+ """
383
+ Generates a telemetry wrapper for AG2 GroupChatManager.run_chat (async version).
384
+ """
385
+
386
+ async def wrapper(wrapped, instance, args, kwargs):
387
+ """
388
+ Wraps the AG2 GroupChatManager.run_chat call (async version).
389
+ """
390
+
391
+ server_address, server_port = set_server_address_and_port(
392
+ instance, "127.0.0.1", 80
393
+ )
394
+
395
+ # Extract groupchat information
396
+ groupchat = getattr(instance, "groupchat", None)
397
+ if groupchat:
398
+ participants = [agent.name for agent in groupchat.agents]
399
+ group_name = f"GroupChat_{len(participants)}_agents"
400
+ else:
401
+ participants = []
402
+ group_name = "UnknownGroupChat"
403
+
404
+ # Extract model information from GroupChatManager
405
+ request_model = "unknown" # Default fallback
406
+ if hasattr(instance, "llm_config") and isinstance(instance.llm_config, dict):
407
+ request_model = instance.llm_config.get("model", "unknown")
408
+
409
+ # Try to get more specific model from groupchat
410
+ if groupchat and hasattr(groupchat, "select_speaker_auto_llm_config"):
411
+ llm_config = groupchat.select_speaker_auto_llm_config
412
+ if isinstance(llm_config, dict):
413
+ request_model = llm_config.get("model", request_model)
414
+ elif hasattr(llm_config, "model"):
415
+ request_model = llm_config.model
416
+
417
+ # Extract sender information
418
+ sender = kwargs.get("sender", None)
419
+
420
+ # Extract messages
421
+ messages = args[0] if args else kwargs.get("messages", [])
422
+
423
+ span_name = f"{SemanticConvention.GEN_AI_OPERATION_TYPE_FRAMEWORK} {group_name}"
424
+
425
+ with tracer.start_as_current_span(span_name, kind=SpanKind.CLIENT) as span:
426
+ start_time = time.time()
427
+ response = await wrapped(*args, **kwargs)
428
+
429
+ try:
430
+ process_groupchat_operation(
431
+ group_name=group_name,
432
+ participants=participants,
433
+ messages=messages,
434
+ sender=sender,
435
+ max_turns=None, # Not available in new API
436
+ request_model=request_model,
437
+ pricing_info=pricing_info,
438
+ server_port=server_port,
439
+ server_address=server_address,
440
+ environment=environment,
441
+ application_name=application_name,
442
+ metrics=metrics,
443
+ start_time=start_time,
444
+ span=span,
445
+ capture_message_content=capture_message_content,
446
+ disable_metrics=disable_metrics,
447
+ version=version,
448
+ )
449
+
450
+ except Exception as e:
451
+ handle_exception(span, e)
452
+
453
+ return response
454
+
455
+ return wrapper
456
+
457
+
458
+ def async_groupchat_select_speaker(
459
+ version,
460
+ environment,
461
+ application_name,
462
+ tracer,
463
+ pricing_info,
464
+ capture_message_content,
465
+ metrics,
466
+ disable_metrics,
467
+ ):
468
+ """
469
+ Generates a telemetry wrapper for AG2 GroupChat.select_speaker (async version).
470
+ """
471
+
472
+ async def wrapper(wrapped, instance, args, kwargs):
473
+ """
474
+ Wraps the AG2 GroupChat.select_speaker call (async version).
475
+ """
476
+
477
+ server_address, server_port = set_server_address_and_port(
478
+ instance, "127.0.0.1", 80
479
+ )
480
+
481
+ # Extract speaker information
482
+ last_speaker = args[0] if args else kwargs.get("last_speaker", None)
483
+ selector = args[1] if len(args) > 1 else kwargs.get("selector", None)
484
+
485
+ last_speaker_name = (
486
+ getattr(last_speaker, "name", "Unknown") if last_speaker else "Unknown"
487
+ )
488
+
489
+ # Extract agents list
490
+ agents = getattr(instance, "agents", [])
491
+
492
+ # Extract model information from GroupChat instance
493
+ request_model = "unknown" # Default fallback
494
+ # Check for speaker selection specific config
495
+ if hasattr(instance, "select_speaker_auto_llm_config"):
496
+ llm_config = instance.select_speaker_auto_llm_config
497
+ if isinstance(llm_config, dict):
498
+ request_model = llm_config.get("model", "unknown")
499
+ elif hasattr(llm_config, "model"):
500
+ request_model = llm_config.model
501
+
502
+ # Try to get model from selector if available
503
+ if (
504
+ selector
505
+ and hasattr(selector, "llm_config")
506
+ and isinstance(selector.llm_config, dict)
507
+ ):
508
+ request_model = selector.llm_config.get("model", request_model)
509
+
510
+ # Try to get model from agents if still unknown
511
+ if request_model == "unknown" and agents:
512
+ for agent in agents:
513
+ if hasattr(agent, "llm_config") and isinstance(agent.llm_config, dict):
514
+ model = agent.llm_config.get("model")
515
+ if model:
516
+ request_model = model
517
+ break
518
+
519
+ span_name = (
520
+ f"{SemanticConvention.GEN_AI_OPERATION_TYPE_AGENT} speaker_selection"
521
+ )
522
+
523
+ with tracer.start_as_current_span(span_name, kind=SpanKind.CLIENT) as span:
524
+ start_time = time.time()
525
+ response = await wrapped(*args, **kwargs)
526
+
527
+ try:
528
+ selected_speaker_name = (
529
+ getattr(response, "name", "Unknown") if response else "Unknown"
530
+ )
531
+
532
+ process_speaker_selection(
533
+ last_speaker=last_speaker_name,
534
+ selected_speaker=selected_speaker_name,
535
+ selector=selector,
536
+ agents=agents,
537
+ request_model=request_model,
538
+ pricing_info=pricing_info,
539
+ server_port=server_port,
540
+ server_address=server_address,
541
+ environment=environment,
542
+ application_name=application_name,
543
+ metrics=metrics,
544
+ start_time=start_time,
545
+ span=span,
546
+ capture_message_content=capture_message_content,
547
+ disable_metrics=disable_metrics,
548
+ version=version,
107
549
  )
108
550
 
109
551
  except Exception as e: