openlit 1.34.30__py3-none-any.whl → 1.34.31__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 +16 -13
  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 +24 -8
  15. openlit/instrumentation/ag2/ag2.py +34 -13
  16. openlit/instrumentation/ag2/async_ag2.py +34 -13
  17. openlit/instrumentation/ag2/utils.py +133 -30
  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 +72 -6
  161. {openlit-1.34.30.dist-info → openlit-1.34.31.dist-info}/METADATA +2 -1
  162. openlit-1.34.31.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.31.dist-info}/LICENSE +0 -0
  168. {openlit-1.34.30.dist-info → openlit-1.34.31.dist-info}/WHEEL +0 -0
@@ -17,6 +17,7 @@ from openlit.__helpers import (
17
17
  )
18
18
  from openlit.semcov import SemanticConvention
19
19
 
20
+
20
21
  def format_content(messages):
21
22
  """
22
23
  Process a list of messages to extract content.
@@ -25,9 +26,15 @@ def format_content(messages):
25
26
  formatted_messages = []
26
27
  for message in messages:
27
28
  # Handle different message formats
28
- if hasattr(message, "role") and (hasattr(message, "content") or hasattr(message, "text")):
29
+ if hasattr(message, "role") and (
30
+ hasattr(message, "content") or hasattr(message, "text")
31
+ ):
29
32
  # ChatMessage object (AI21 format)
30
- role = str(message.role) if hasattr(message.role, 'value') else str(message.role)
33
+ role = (
34
+ str(message.role)
35
+ if hasattr(message.role, "value")
36
+ else str(message.role)
37
+ )
31
38
  content = getattr(message, "content", None) or getattr(message, "text", "")
32
39
  elif isinstance(message, dict):
33
40
  # Dictionary format
@@ -36,12 +43,15 @@ def format_content(messages):
36
43
  else:
37
44
  # Fallback - try to extract as string
38
45
  role = str(getattr(message, "role", "unknown"))
39
- content = str(getattr(message, "content", "") or getattr(message, "text", ""))
46
+ content = str(
47
+ getattr(message, "content", "") or getattr(message, "text", "")
48
+ )
40
49
 
41
50
  if isinstance(content, list):
42
51
  content_str = ", ".join(
43
- f'{item["type"]}: {item["text"] if "text" in item else item["image_url"]}'
44
- if "type" in item else f'text: {item["text"]}'
52
+ f"{item['type']}: {item['text'] if 'text' in item else item['image_url']}"
53
+ if "type" in item
54
+ else f"text: {item['text']}"
45
55
  for item in content
46
56
  )
47
57
  formatted_messages.append(f"{role}: {content_str}")
@@ -50,6 +60,7 @@ def format_content(messages):
50
60
 
51
61
  return "\n".join(formatted_messages)
52
62
 
63
+
53
64
  def process_chunk(scope, chunk):
54
65
  """
55
66
  Process a chunk of response data and update state.
@@ -66,10 +77,11 @@ def process_chunk(scope, chunk):
66
77
  chunked = response_as_dict(chunk)
67
78
 
68
79
  # Collect message IDs and aggregated response from events
69
- if (len(chunked.get("choices", [])) > 0 and
70
- "delta" in chunked.get("choices")[0] and
71
- "content" in chunked.get("choices")[0].get("delta", {})):
72
-
80
+ if (
81
+ len(chunked.get("choices", [])) > 0
82
+ and "delta" in chunked.get("choices")[0]
83
+ and "content" in chunked.get("choices")[0].get("delta", {})
84
+ ):
73
85
  content = chunked.get("choices")[0].get("delta").get("content")
74
86
  if content:
75
87
  scope._llmresponse += content
@@ -81,8 +93,18 @@ def process_chunk(scope, chunk):
81
93
  scope._finish_reason = chunked.get("choices", [{}])[0].get("finish_reason")
82
94
  scope._end_time = time.time()
83
95
 
84
- def common_chat_logic(scope, pricing_info, environment, application_name, metrics,
85
- capture_message_content, disable_metrics, version, is_stream):
96
+
97
+ def common_chat_logic(
98
+ scope,
99
+ pricing_info,
100
+ environment,
101
+ application_name,
102
+ metrics,
103
+ capture_message_content,
104
+ disable_metrics,
105
+ version,
106
+ is_stream,
107
+ ):
86
108
  """
87
109
  Process chat request and generate Telemetry
88
110
  """
@@ -93,44 +115,97 @@ def common_chat_logic(scope, pricing_info, environment, application_name, metric
93
115
  prompt = format_content(scope._kwargs.get("messages", []))
94
116
  request_model = scope._kwargs.get("model", "jamba-1.5-mini")
95
117
 
96
- cost = get_chat_model_cost(request_model, pricing_info, scope._input_tokens, scope._output_tokens)
118
+ cost = get_chat_model_cost(
119
+ request_model, pricing_info, scope._input_tokens, scope._output_tokens
120
+ )
97
121
 
98
122
  # Common Span Attributes
99
- common_span_attributes(scope,
100
- SemanticConvention.GEN_AI_OPERATION_TYPE_CHAT, SemanticConvention.GEN_AI_SYSTEM_AI21,
101
- scope._server_address, scope._server_port, request_model, request_model,
102
- environment, application_name, is_stream, scope._tbt, scope._ttft, version)
123
+ common_span_attributes(
124
+ scope,
125
+ SemanticConvention.GEN_AI_OPERATION_TYPE_CHAT,
126
+ SemanticConvention.GEN_AI_SYSTEM_AI21,
127
+ scope._server_address,
128
+ scope._server_port,
129
+ request_model,
130
+ request_model,
131
+ environment,
132
+ application_name,
133
+ is_stream,
134
+ scope._tbt,
135
+ scope._ttft,
136
+ version,
137
+ )
103
138
 
104
139
  # Span Attributes for Request parameters
105
- scope._span.set_attribute(SemanticConvention.GEN_AI_REQUEST_SEED, scope._kwargs.get("seed", ""))
106
- scope._span.set_attribute(SemanticConvention.GEN_AI_REQUEST_FREQUENCY_PENALTY, scope._kwargs.get("frequency_penalty", 0.0))
107
- scope._span.set_attribute(SemanticConvention.GEN_AI_REQUEST_MAX_TOKENS, scope._kwargs.get("max_tokens", -1))
108
- scope._span.set_attribute(SemanticConvention.GEN_AI_REQUEST_PRESENCE_PENALTY, scope._kwargs.get("presence_penalty", 0.0))
109
- scope._span.set_attribute(SemanticConvention.GEN_AI_REQUEST_STOP_SEQUENCES, scope._kwargs.get("stop", []))
110
- scope._span.set_attribute(SemanticConvention.GEN_AI_REQUEST_TEMPERATURE, scope._kwargs.get("temperature", 0.4))
111
- scope._span.set_attribute(SemanticConvention.GEN_AI_REQUEST_TOP_P, scope._kwargs.get("top_p", 1.0))
140
+ scope._span.set_attribute(
141
+ SemanticConvention.GEN_AI_REQUEST_SEED, scope._kwargs.get("seed", "")
142
+ )
143
+ scope._span.set_attribute(
144
+ SemanticConvention.GEN_AI_REQUEST_FREQUENCY_PENALTY,
145
+ scope._kwargs.get("frequency_penalty", 0.0),
146
+ )
147
+ scope._span.set_attribute(
148
+ SemanticConvention.GEN_AI_REQUEST_MAX_TOKENS,
149
+ scope._kwargs.get("max_tokens", -1),
150
+ )
151
+ scope._span.set_attribute(
152
+ SemanticConvention.GEN_AI_REQUEST_PRESENCE_PENALTY,
153
+ scope._kwargs.get("presence_penalty", 0.0),
154
+ )
155
+ scope._span.set_attribute(
156
+ SemanticConvention.GEN_AI_REQUEST_STOP_SEQUENCES, scope._kwargs.get("stop", [])
157
+ )
158
+ scope._span.set_attribute(
159
+ SemanticConvention.GEN_AI_REQUEST_TEMPERATURE,
160
+ scope._kwargs.get("temperature", 0.4),
161
+ )
162
+ scope._span.set_attribute(
163
+ SemanticConvention.GEN_AI_REQUEST_TOP_P, scope._kwargs.get("top_p", 1.0)
164
+ )
112
165
 
113
166
  # Span Attributes for Response parameters
114
167
  scope._span.set_attribute(SemanticConvention.GEN_AI_RESPONSE_ID, scope._response_id)
115
- scope._span.set_attribute(SemanticConvention.GEN_AI_RESPONSE_FINISH_REASON, [scope._finish_reason])
116
- scope._span.set_attribute(SemanticConvention.GEN_AI_OUTPUT_TYPE, "text" if isinstance(scope._llmresponse, str) else "json")
168
+ scope._span.set_attribute(
169
+ SemanticConvention.GEN_AI_RESPONSE_FINISH_REASON, [scope._finish_reason]
170
+ )
171
+ scope._span.set_attribute(
172
+ SemanticConvention.GEN_AI_OUTPUT_TYPE,
173
+ "text" if isinstance(scope._llmresponse, str) else "json",
174
+ )
117
175
 
118
176
  # Span Attributes for Cost and Tokens
119
- scope._span.set_attribute(SemanticConvention.GEN_AI_USAGE_INPUT_TOKENS, scope._input_tokens)
120
- scope._span.set_attribute(SemanticConvention.GEN_AI_USAGE_OUTPUT_TOKENS, scope._output_tokens)
121
- scope._span.set_attribute(SemanticConvention.GEN_AI_CLIENT_TOKEN_USAGE, scope._input_tokens + scope._output_tokens)
177
+ scope._span.set_attribute(
178
+ SemanticConvention.GEN_AI_USAGE_INPUT_TOKENS, scope._input_tokens
179
+ )
180
+ scope._span.set_attribute(
181
+ SemanticConvention.GEN_AI_USAGE_OUTPUT_TOKENS, scope._output_tokens
182
+ )
183
+ scope._span.set_attribute(
184
+ SemanticConvention.GEN_AI_CLIENT_TOKEN_USAGE,
185
+ scope._input_tokens + scope._output_tokens,
186
+ )
122
187
  scope._span.set_attribute(SemanticConvention.GEN_AI_USAGE_COST, cost)
123
188
 
124
189
  # Span Attributes for Tools
125
190
  if scope._tools:
126
- scope._span.set_attribute(SemanticConvention.GEN_AI_TOOL_NAME, scope._tools.get("function", {}).get("name", ""))
127
- scope._span.set_attribute(SemanticConvention.GEN_AI_TOOL_CALL_ID, str(scope._tools.get("id", "")))
128
- scope._span.set_attribute(SemanticConvention.GEN_AI_TOOL_ARGS, str(scope._tools.get("function", {}).get("arguments", "")))
191
+ scope._span.set_attribute(
192
+ SemanticConvention.GEN_AI_TOOL_NAME,
193
+ scope._tools.get("function", {}).get("name", ""),
194
+ )
195
+ scope._span.set_attribute(
196
+ SemanticConvention.GEN_AI_TOOL_CALL_ID, str(scope._tools.get("id", ""))
197
+ )
198
+ scope._span.set_attribute(
199
+ SemanticConvention.GEN_AI_TOOL_ARGS,
200
+ str(scope._tools.get("function", {}).get("arguments", "")),
201
+ )
129
202
 
130
203
  # Span Attributes for Content
131
204
  if capture_message_content:
132
205
  scope._span.set_attribute(SemanticConvention.GEN_AI_CONTENT_PROMPT, prompt)
133
- scope._span.set_attribute(SemanticConvention.GEN_AI_CONTENT_COMPLETION, scope._llmresponse)
206
+ scope._span.set_attribute(
207
+ SemanticConvention.GEN_AI_CONTENT_COMPLETION, scope._llmresponse
208
+ )
134
209
 
135
210
  # To be removed once the change to span_attributes (from span events) is complete
136
211
  scope._span.add_event(
@@ -150,23 +225,69 @@ def common_chat_logic(scope, pricing_info, environment, application_name, metric
150
225
 
151
226
  # Metrics
152
227
  if not disable_metrics:
153
- record_completion_metrics(metrics, SemanticConvention.GEN_AI_OPERATION_TYPE_CHAT, SemanticConvention.GEN_AI_SYSTEM_AI21,
154
- scope._server_address, scope._server_port, request_model, request_model, environment,
155
- application_name, scope._start_time, scope._end_time, scope._input_tokens, scope._output_tokens,
156
- cost, scope._tbt, scope._ttft)
228
+ record_completion_metrics(
229
+ metrics,
230
+ SemanticConvention.GEN_AI_OPERATION_TYPE_CHAT,
231
+ SemanticConvention.GEN_AI_SYSTEM_AI21,
232
+ scope._server_address,
233
+ scope._server_port,
234
+ request_model,
235
+ request_model,
236
+ environment,
237
+ application_name,
238
+ scope._start_time,
239
+ scope._end_time,
240
+ scope._input_tokens,
241
+ scope._output_tokens,
242
+ cost,
243
+ scope._tbt,
244
+ scope._ttft,
245
+ )
157
246
 
158
- def process_streaming_chat_response(scope, pricing_info, environment, application_name, metrics,
159
- capture_message_content=False, disable_metrics=False, version=""):
247
+
248
+ def process_streaming_chat_response(
249
+ scope,
250
+ pricing_info,
251
+ environment,
252
+ application_name,
253
+ metrics,
254
+ capture_message_content=False,
255
+ disable_metrics=False,
256
+ version="",
257
+ ):
160
258
  """
161
259
  Process streaming chat request and generate Telemetry
162
260
  """
163
261
 
164
- common_chat_logic(scope, pricing_info, environment, application_name, metrics,
165
- capture_message_content, disable_metrics, version, is_stream=True)
262
+ common_chat_logic(
263
+ scope,
264
+ pricing_info,
265
+ environment,
266
+ application_name,
267
+ metrics,
268
+ capture_message_content,
269
+ disable_metrics,
270
+ version,
271
+ is_stream=True,
272
+ )
273
+
166
274
 
167
- def process_chat_response(response, request_model, pricing_info, server_port, server_address,
168
- environment, application_name, metrics, start_time, span, capture_message_content=False,
169
- disable_metrics=False, version="1.0.0", **kwargs):
275
+ def process_chat_response(
276
+ response,
277
+ request_model,
278
+ pricing_info,
279
+ server_port,
280
+ server_address,
281
+ environment,
282
+ application_name,
283
+ metrics,
284
+ start_time,
285
+ span,
286
+ capture_message_content=False,
287
+ disable_metrics=False,
288
+ version="1.0.0",
289
+ **kwargs,
290
+ ):
170
291
  """
171
292
  Process chat request and generate Telemetry
172
293
  """
@@ -189,21 +310,43 @@ def process_chat_response(response, request_model, pricing_info, server_port, se
189
310
  scope._ttft, scope._tbt = scope._end_time - scope._start_time, 0
190
311
  scope._server_address, scope._server_port = server_address, server_port
191
312
  scope._kwargs = kwargs
192
- scope._finish_reason = str(response_dict.get("choices", [])[0].get("finish_reason", ""))
313
+ scope._finish_reason = str(
314
+ response_dict.get("choices", [])[0].get("finish_reason", "")
315
+ )
193
316
 
194
317
  # Handle tool calls
195
318
  if scope._kwargs.get("tools"):
196
- scope._tools = response_dict.get("choices", [{}])[0].get("message", {}).get("tool_calls")
319
+ scope._tools = (
320
+ response_dict.get("choices", [{}])[0].get("message", {}).get("tool_calls")
321
+ )
197
322
  else:
198
323
  scope._tools = None
199
324
 
200
- common_chat_logic(scope, pricing_info, environment, application_name, metrics,
201
- capture_message_content, disable_metrics, version, is_stream=False)
325
+ common_chat_logic(
326
+ scope,
327
+ pricing_info,
328
+ environment,
329
+ application_name,
330
+ metrics,
331
+ capture_message_content,
332
+ disable_metrics,
333
+ version,
334
+ is_stream=False,
335
+ )
202
336
 
203
337
  return response
204
338
 
205
- def common_chat_rag_logic(scope, pricing_info, environment, application_name, metrics,
206
- capture_message_content, disable_metrics, version):
339
+
340
+ def common_chat_rag_logic(
341
+ scope,
342
+ pricing_info,
343
+ environment,
344
+ application_name,
345
+ metrics,
346
+ capture_message_content,
347
+ disable_metrics,
348
+ version,
349
+ ):
207
350
  """
208
351
  Process RAG chat request and generate Telemetry
209
352
  """
@@ -211,40 +354,82 @@ def common_chat_rag_logic(scope, pricing_info, environment, application_name, me
211
354
  prompt = format_content(scope._kwargs.get("messages", []))
212
355
  request_model = scope._kwargs.get("model", "jamba-1.5-mini")
213
356
 
214
- cost = get_chat_model_cost(request_model, pricing_info, scope._input_tokens, scope._output_tokens)
357
+ cost = get_chat_model_cost(
358
+ request_model, pricing_info, scope._input_tokens, scope._output_tokens
359
+ )
215
360
 
216
361
  # Common Span Attributes
217
- common_span_attributes(scope,
218
- SemanticConvention.GEN_AI_OPERATION_TYPE_CHAT, SemanticConvention.GEN_AI_SYSTEM_AI21,
219
- scope._server_address, scope._server_port, request_model, scope._response_model,
220
- environment, application_name, False, scope._tbt, scope._ttft, version)
362
+ common_span_attributes(
363
+ scope,
364
+ SemanticConvention.GEN_AI_OPERATION_TYPE_CHAT,
365
+ SemanticConvention.GEN_AI_SYSTEM_AI21,
366
+ scope._server_address,
367
+ scope._server_port,
368
+ request_model,
369
+ scope._response_model,
370
+ environment,
371
+ application_name,
372
+ False,
373
+ scope._tbt,
374
+ scope._ttft,
375
+ version,
376
+ )
221
377
 
222
378
  # RAG-specific span attributes
223
- scope._span.set_attribute(SemanticConvention.GEN_AI_RAG_MAX_SEGMENTS, scope._kwargs.get("max_segments", -1))
224
- scope._span.set_attribute(SemanticConvention.GEN_AI_RAG_STRATEGY, scope._kwargs.get("retrieval_strategy", "segments"))
225
- scope._span.set_attribute(SemanticConvention.GEN_AI_RAG_MAX_NEIGHBORS, scope._kwargs.get("max_neighbors", -1))
226
- scope._span.set_attribute(SemanticConvention.GEN_AI_RAG_FILE_IDS, str(scope._kwargs.get("file_ids", "")))
227
- scope._span.set_attribute(SemanticConvention.GEN_AI_RAG_DOCUMENTS_PATH, scope._kwargs.get("path", ""))
228
- scope._span.set_attribute(SemanticConvention.GEN_AI_RAG_SIMILARITY_THRESHOLD,
229
- scope._kwargs.get("retrieval_similarity_threshold", -1))
379
+ scope._span.set_attribute(
380
+ SemanticConvention.GEN_AI_RAG_MAX_SEGMENTS,
381
+ scope._kwargs.get("max_segments", -1),
382
+ )
383
+ scope._span.set_attribute(
384
+ SemanticConvention.GEN_AI_RAG_STRATEGY,
385
+ scope._kwargs.get("retrieval_strategy", "segments"),
386
+ )
387
+ scope._span.set_attribute(
388
+ SemanticConvention.GEN_AI_RAG_MAX_NEIGHBORS,
389
+ scope._kwargs.get("max_neighbors", -1),
390
+ )
391
+ scope._span.set_attribute(
392
+ SemanticConvention.GEN_AI_RAG_FILE_IDS, str(scope._kwargs.get("file_ids", ""))
393
+ )
394
+ scope._span.set_attribute(
395
+ SemanticConvention.GEN_AI_RAG_DOCUMENTS_PATH, scope._kwargs.get("path", "")
396
+ )
397
+ scope._span.set_attribute(
398
+ SemanticConvention.GEN_AI_RAG_SIMILARITY_THRESHOLD,
399
+ scope._kwargs.get("retrieval_similarity_threshold", -1),
400
+ )
230
401
 
231
402
  # Standard span attributes
232
403
  scope._span.set_attribute(SemanticConvention.GEN_AI_RESPONSE_ID, scope._response_id)
233
- scope._span.set_attribute(SemanticConvention.GEN_AI_OUTPUT_TYPE, "text" if isinstance(scope._llmresponse, str) else "json")
234
- scope._span.set_attribute(SemanticConvention.GEN_AI_USAGE_INPUT_TOKENS, scope._input_tokens)
235
- scope._span.set_attribute(SemanticConvention.GEN_AI_USAGE_OUTPUT_TOKENS, scope._output_tokens)
236
- scope._span.set_attribute(SemanticConvention.GEN_AI_CLIENT_TOKEN_USAGE, scope._input_tokens + scope._output_tokens)
404
+ scope._span.set_attribute(
405
+ SemanticConvention.GEN_AI_OUTPUT_TYPE,
406
+ "text" if isinstance(scope._llmresponse, str) else "json",
407
+ )
408
+ scope._span.set_attribute(
409
+ SemanticConvention.GEN_AI_USAGE_INPUT_TOKENS, scope._input_tokens
410
+ )
411
+ scope._span.set_attribute(
412
+ SemanticConvention.GEN_AI_USAGE_OUTPUT_TOKENS, scope._output_tokens
413
+ )
414
+ scope._span.set_attribute(
415
+ SemanticConvention.GEN_AI_CLIENT_TOKEN_USAGE,
416
+ scope._input_tokens + scope._output_tokens,
417
+ )
237
418
  scope._span.set_attribute(SemanticConvention.GEN_AI_USAGE_COST, cost)
238
419
 
239
420
  # Handle tool calls
240
421
  if scope._kwargs.get("tools"):
241
- scope._span.set_attribute(SemanticConvention.GEN_AI_TOOL_CALLS,
242
- str(scope._choices[0].get("message", {}).get("tool_calls", "")))
422
+ scope._span.set_attribute(
423
+ SemanticConvention.GEN_AI_TOOL_CALLS,
424
+ str(scope._choices[0].get("message", {}).get("tool_calls", "")),
425
+ )
243
426
 
244
427
  # Content attributes
245
428
  if capture_message_content:
246
429
  scope._span.set_attribute(SemanticConvention.GEN_AI_CONTENT_PROMPT, prompt)
247
- scope._span.set_attribute(SemanticConvention.GEN_AI_CONTENT_COMPLETION, scope._llmresponse)
430
+ scope._span.set_attribute(
431
+ SemanticConvention.GEN_AI_CONTENT_COMPLETION, scope._llmresponse
432
+ )
248
433
 
249
434
  # To be removed once the change to span_attributes (from span events) is complete
250
435
  scope._span.add_event(
@@ -264,14 +449,42 @@ def common_chat_rag_logic(scope, pricing_info, environment, application_name, me
264
449
 
265
450
  # Metrics
266
451
  if not disable_metrics:
267
- record_completion_metrics(metrics, SemanticConvention.GEN_AI_OPERATION_TYPE_CHAT, SemanticConvention.GEN_AI_SYSTEM_AI21,
268
- scope._server_address, scope._server_port, request_model, scope._response_model, environment,
269
- application_name, scope._start_time, scope._end_time, scope._input_tokens, scope._output_tokens,
270
- cost, scope._tbt, scope._ttft)
271
-
272
- def process_chat_rag_response(response, request_model, pricing_info, server_port, server_address,
273
- environment, application_name, metrics, start_time, span, capture_message_content=False,
274
- disable_metrics=False, version="1.0.0", **kwargs):
452
+ record_completion_metrics(
453
+ metrics,
454
+ SemanticConvention.GEN_AI_OPERATION_TYPE_CHAT,
455
+ SemanticConvention.GEN_AI_SYSTEM_AI21,
456
+ scope._server_address,
457
+ scope._server_port,
458
+ request_model,
459
+ scope._response_model,
460
+ environment,
461
+ application_name,
462
+ scope._start_time,
463
+ scope._end_time,
464
+ scope._input_tokens,
465
+ scope._output_tokens,
466
+ cost,
467
+ scope._tbt,
468
+ scope._ttft,
469
+ )
470
+
471
+
472
+ def process_chat_rag_response(
473
+ response,
474
+ request_model,
475
+ pricing_info,
476
+ server_port,
477
+ server_address,
478
+ environment,
479
+ application_name,
480
+ metrics,
481
+ start_time,
482
+ span,
483
+ capture_message_content=False,
484
+ disable_metrics=False,
485
+ version="1.0.0",
486
+ **kwargs,
487
+ ):
275
488
  """
276
489
  Process RAG chat request and generate Telemetry
277
490
  """
@@ -311,7 +524,15 @@ def process_chat_rag_response(response, request_model, pricing_info, server_port
311
524
  scope._tools = None
312
525
  scope._choices = choices
313
526
 
314
- common_chat_rag_logic(scope, pricing_info, environment, application_name, metrics,
315
- capture_message_content, disable_metrics, version)
527
+ common_chat_rag_logic(
528
+ scope,
529
+ pricing_info,
530
+ environment,
531
+ application_name,
532
+ metrics,
533
+ capture_message_content,
534
+ disable_metrics,
535
+ version,
536
+ )
316
537
 
317
538
  return response
@@ -10,6 +10,7 @@ from openlit.instrumentation.anthropic.async_anthropic import async_messages
10
10
 
11
11
  _instruments = ("anthropic >= 0.21.0",)
12
12
 
13
+
13
14
  class AnthropicInstrumentor(BaseInstrumentor):
14
15
  """
15
16
  An instrumentor for Anthropic's client library.
@@ -32,16 +33,32 @@ class AnthropicInstrumentor(BaseInstrumentor):
32
33
  wrap_function_wrapper(
33
34
  "anthropic.resources.messages",
34
35
  "Messages.create",
35
- messages(version, environment, application_name, tracer, pricing_info,
36
- capture_message_content, metrics, disable_metrics),
36
+ messages(
37
+ version,
38
+ environment,
39
+ application_name,
40
+ tracer,
41
+ pricing_info,
42
+ capture_message_content,
43
+ metrics,
44
+ disable_metrics,
45
+ ),
37
46
  )
38
47
 
39
48
  # async
40
49
  wrap_function_wrapper(
41
50
  "anthropic.resources.messages",
42
51
  "AsyncMessages.create",
43
- async_messages(version, environment, application_name, tracer, pricing_info,
44
- capture_message_content, metrics, disable_metrics),
52
+ async_messages(
53
+ version,
54
+ environment,
55
+ application_name,
56
+ tracer,
57
+ pricing_info,
58
+ capture_message_content,
59
+ metrics,
60
+ disable_metrics,
61
+ ),
45
62
  )
46
63
 
47
64
  def _uninstrument(self, **kwargs):
@@ -4,10 +4,7 @@ Module for monitoring Anthropic API calls.
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.anthropic.utils import (
12
9
  process_chunk,
13
10
  process_chat_response,
@@ -15,7 +12,17 @@ from openlit.instrumentation.anthropic.utils import (
15
12
  )
16
13
  from openlit.semcov import SemanticConvention
17
14
 
18
- def messages(version, environment, application_name, tracer, pricing_info, capture_message_content, metrics, disable_metrics):
15
+
16
+ def messages(
17
+ version,
18
+ environment,
19
+ application_name,
20
+ tracer,
21
+ pricing_info,
22
+ capture_message_content,
23
+ metrics,
24
+ disable_metrics,
25
+ ):
19
26
  """
20
27
  Generates a telemetry wrapper for Anthropic Messages.create calls.
21
28
  """
@@ -26,14 +33,14 @@ def messages(version, environment, application_name, tracer, pricing_info, captu
26
33
  """
27
34
 
28
35
  def __init__(
29
- self,
30
- wrapped,
31
- span,
32
- span_name,
33
- kwargs,
34
- server_address,
35
- server_port,
36
- ):
36
+ self,
37
+ wrapped,
38
+ span,
39
+ span_name,
40
+ kwargs,
41
+ server_address,
42
+ server_port,
43
+ ):
37
44
  self.__wrapped__ = wrapped
38
45
  self._span = span
39
46
  self._span_name = span_name
@@ -87,7 +94,7 @@ def messages(version, environment, application_name, tracer, pricing_info, captu
87
94
  metrics=metrics,
88
95
  capture_message_content=capture_message_content,
89
96
  disable_metrics=disable_metrics,
90
- version=version
97
+ version=version,
91
98
  )
92
99
  except Exception as e:
93
100
  handle_exception(self._span, e)
@@ -99,7 +106,9 @@ def messages(version, environment, application_name, tracer, pricing_info, captu
99
106
  """
100
107
 
101
108
  streaming = kwargs.get("stream", False)
102
- server_address, server_port = set_server_address_and_port(instance, "api.anthropic.com", 443)
109
+ server_address, server_port = set_server_address_and_port(
110
+ instance, "api.anthropic.com", 443
111
+ )
103
112
  request_model = kwargs.get("model", "claude-3-5-sonnet-latest")
104
113
 
105
114
  span_name = f"{SemanticConvention.GEN_AI_OPERATION_TYPE_CHAT} {request_model}"
@@ -109,7 +118,9 @@ def messages(version, environment, application_name, tracer, pricing_info, captu
109
118
  awaited_wrapped = wrapped(*args, **kwargs)
110
119
  span = tracer.start_span(span_name, kind=SpanKind.CLIENT)
111
120
 
112
- return TracedSyncStream(awaited_wrapped, span, span_name, kwargs, server_address, server_port)
121
+ return TracedSyncStream(
122
+ awaited_wrapped, span, span_name, kwargs, server_address, server_port
123
+ )
113
124
 
114
125
  else:
115
126
  with tracer.start_as_current_span(span_name, kind=SpanKind.CLIENT) as span:
@@ -131,7 +142,7 @@ def messages(version, environment, application_name, tracer, pricing_info, captu
131
142
  capture_message_content=capture_message_content,
132
143
  disable_metrics=disable_metrics,
133
144
  version=version,
134
- **kwargs
145
+ **kwargs,
135
146
  )
136
147
 
137
148
  except Exception as e: