openlit 1.33.19__py3-none-any.whl → 1.33.21__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.
- openlit/__helpers.py +64 -7
- openlit/__init__.py +3 -3
- openlit/evals/utils.py +7 -7
- openlit/guard/utils.py +7 -7
- openlit/instrumentation/ag2/ag2.py +24 -24
- openlit/instrumentation/ai21/ai21.py +3 -3
- openlit/instrumentation/ai21/async_ai21.py +3 -3
- openlit/instrumentation/ai21/utils.py +59 -59
- openlit/instrumentation/anthropic/anthropic.py +2 -2
- openlit/instrumentation/anthropic/async_anthropic.py +2 -2
- openlit/instrumentation/anthropic/utils.py +34 -34
- openlit/instrumentation/assemblyai/assemblyai.py +24 -24
- openlit/instrumentation/astra/astra.py +3 -3
- openlit/instrumentation/astra/async_astra.py +3 -3
- openlit/instrumentation/astra/utils.py +39 -39
- openlit/instrumentation/azure_ai_inference/async_azure_ai_inference.py +2 -2
- openlit/instrumentation/azure_ai_inference/azure_ai_inference.py +2 -2
- openlit/instrumentation/azure_ai_inference/utils.py +36 -36
- openlit/instrumentation/bedrock/bedrock.py +2 -2
- openlit/instrumentation/bedrock/utils.py +35 -35
- openlit/instrumentation/chroma/chroma.py +57 -57
- openlit/instrumentation/cohere/async_cohere.py +88 -88
- openlit/instrumentation/cohere/cohere.py +88 -88
- openlit/instrumentation/controlflow/controlflow.py +15 -15
- openlit/instrumentation/crawl4ai/async_crawl4ai.py +14 -14
- openlit/instrumentation/crawl4ai/crawl4ai.py +14 -14
- openlit/instrumentation/crewai/crewai.py +22 -22
- openlit/instrumentation/dynamiq/dynamiq.py +19 -19
- openlit/instrumentation/elevenlabs/async_elevenlabs.py +24 -25
- openlit/instrumentation/elevenlabs/elevenlabs.py +23 -25
- openlit/instrumentation/embedchain/embedchain.py +15 -15
- openlit/instrumentation/firecrawl/firecrawl.py +10 -10
- openlit/instrumentation/google_ai_studio/async_google_ai_studio.py +33 -33
- openlit/instrumentation/google_ai_studio/google_ai_studio.py +33 -33
- openlit/instrumentation/gpt4all/gpt4all.py +78 -78
- openlit/instrumentation/gpu/__init__.py +8 -8
- openlit/instrumentation/groq/async_groq.py +74 -74
- openlit/instrumentation/groq/groq.py +74 -74
- openlit/instrumentation/haystack/haystack.py +6 -6
- openlit/instrumentation/julep/async_julep.py +14 -14
- openlit/instrumentation/julep/julep.py +14 -14
- openlit/instrumentation/langchain/async_langchain.py +39 -39
- openlit/instrumentation/langchain/langchain.py +39 -39
- openlit/instrumentation/letta/letta.py +26 -26
- openlit/instrumentation/litellm/async_litellm.py +94 -94
- openlit/instrumentation/litellm/litellm.py +94 -94
- openlit/instrumentation/llamaindex/llamaindex.py +7 -7
- openlit/instrumentation/mem0/mem0.py +13 -13
- openlit/instrumentation/milvus/milvus.py +47 -47
- openlit/instrumentation/mistral/async_mistral.py +88 -88
- openlit/instrumentation/mistral/mistral.py +88 -88
- openlit/instrumentation/multion/async_multion.py +21 -21
- openlit/instrumentation/multion/multion.py +21 -21
- openlit/instrumentation/ollama/__init__.py +47 -34
- openlit/instrumentation/ollama/async_ollama.py +7 -5
- openlit/instrumentation/ollama/ollama.py +7 -5
- openlit/instrumentation/ollama/utils.py +58 -54
- openlit/instrumentation/openai/async_openai.py +225 -225
- openlit/instrumentation/openai/openai.py +225 -225
- openlit/instrumentation/openai_agents/openai_agents.py +11 -11
- openlit/instrumentation/phidata/phidata.py +15 -15
- openlit/instrumentation/pinecone/pinecone.py +43 -43
- openlit/instrumentation/premai/premai.py +86 -86
- openlit/instrumentation/qdrant/async_qdrant.py +95 -95
- openlit/instrumentation/qdrant/qdrant.py +99 -99
- openlit/instrumentation/reka/async_reka.py +33 -33
- openlit/instrumentation/reka/reka.py +33 -33
- openlit/instrumentation/together/async_together.py +90 -90
- openlit/instrumentation/together/together.py +90 -90
- openlit/instrumentation/transformers/__init__.py +11 -7
- openlit/instrumentation/transformers/transformers.py +32 -168
- openlit/instrumentation/transformers/utils.py +183 -0
- openlit/instrumentation/vertexai/async_vertexai.py +64 -64
- openlit/instrumentation/vertexai/vertexai.py +64 -64
- openlit/instrumentation/vllm/vllm.py +24 -24
- openlit/otel/metrics.py +11 -11
- openlit/semcov/__init__.py +3 -3
- {openlit-1.33.19.dist-info → openlit-1.33.21.dist-info}/METADATA +8 -8
- openlit-1.33.21.dist-info/RECORD +132 -0
- {openlit-1.33.19.dist-info → openlit-1.33.21.dist-info}/WHEEL +1 -1
- openlit-1.33.19.dist-info/RECORD +0 -131
- {openlit-1.33.19.dist-info → openlit-1.33.21.dist-info}/LICENSE +0 -0
openlit/__helpers.py
CHANGED
@@ -12,7 +12,7 @@ import requests
|
|
12
12
|
from opentelemetry.sdk.resources import SERVICE_NAME, TELEMETRY_SDK_NAME, DEPLOYMENT_ENVIRONMENT
|
13
13
|
from opentelemetry.trace import Status, StatusCode
|
14
14
|
from opentelemetry._events import Event
|
15
|
-
from openlit.semcov import
|
15
|
+
from openlit.semcov import SemanticConvention
|
16
16
|
|
17
17
|
# Set up logging
|
18
18
|
logger = logging.getLogger(__name__)
|
@@ -176,12 +176,12 @@ def create_metrics_attributes(
|
|
176
176
|
TELEMETRY_SDK_NAME: 'openlit',
|
177
177
|
SERVICE_NAME: service_name,
|
178
178
|
DEPLOYMENT_ENVIRONMENT: deployment_environment,
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
179
|
+
SemanticConvention.GEN_AI_OPERATION: operation,
|
180
|
+
SemanticConvention.GEN_AI_SYSTEM: system,
|
181
|
+
SemanticConvention.GEN_AI_REQUEST_MODEL: request_model,
|
182
|
+
SemanticConvention.SERVER_ADDRESS: server_address,
|
183
|
+
SemanticConvention.SERVER_PORT: server_port,
|
184
|
+
SemanticConvention.GEN_AI_RESPONSE_MODEL: response_model
|
185
185
|
}
|
186
186
|
|
187
187
|
def set_server_address_and_port(client_instance: Any,
|
@@ -240,6 +240,11 @@ def extract_and_format_input(messages):
|
|
240
240
|
fixed_roles = ['user', 'assistant', 'system', 'tool', 'developer']
|
241
241
|
formatted_messages = {role_key: {'role': '', 'content': ''} for role_key in fixed_roles}
|
242
242
|
|
243
|
+
# Check if input is a simple string
|
244
|
+
if isinstance(messages, str):
|
245
|
+
formatted_messages['user'] = {'role': 'user', 'content': messages}
|
246
|
+
return formatted_messages
|
247
|
+
|
243
248
|
for message in messages:
|
244
249
|
message = response_as_dict(message)
|
245
250
|
|
@@ -276,3 +281,55 @@ def concatenate_all_contents(formatted_messages):
|
|
276
281
|
for message_data in formatted_messages.values()
|
277
282
|
if message_data['content']
|
278
283
|
)
|
284
|
+
|
285
|
+
def format_and_concatenate(messages):
|
286
|
+
"""
|
287
|
+
Process a list of messages to extract content, categorize them by role,
|
288
|
+
and concatenate all 'content' fields into a single string with role: content format.
|
289
|
+
"""
|
290
|
+
|
291
|
+
formatted_messages = {}
|
292
|
+
|
293
|
+
# Check if input is a simple string
|
294
|
+
if isinstance(messages, str):
|
295
|
+
formatted_messages['user'] = {'role': 'user', 'content': messages}
|
296
|
+
elif isinstance(messages, list) and all(isinstance(m, str) for m in messages):
|
297
|
+
# If it's a list of strings, each string is 'user' input
|
298
|
+
user_content = ' '.join(messages)
|
299
|
+
formatted_messages['user'] = {'role': 'user', 'content': user_content}
|
300
|
+
else:
|
301
|
+
for message in messages:
|
302
|
+
message = response_as_dict(message)
|
303
|
+
role = message.get('role', 'unknown') # Default to 'unknown' if no role is specified
|
304
|
+
content = message.get('content', '')
|
305
|
+
|
306
|
+
# Initialize role in formatted messages if not present
|
307
|
+
if role not in formatted_messages:
|
308
|
+
formatted_messages[role] = {'role': role, 'content': ''}
|
309
|
+
|
310
|
+
# Handle list of dictionaries in content
|
311
|
+
if isinstance(content, list):
|
312
|
+
content_str = []
|
313
|
+
for item in content:
|
314
|
+
if isinstance(item, dict):
|
315
|
+
# Collect text or other attributes as needed
|
316
|
+
text = item.get('text', '')
|
317
|
+
image_url = item.get('image_url', '')
|
318
|
+
content_str.append(text)
|
319
|
+
content_str.append(image_url)
|
320
|
+
content_str = ", ".join(filter(None, content_str))
|
321
|
+
else:
|
322
|
+
content_str = content
|
323
|
+
|
324
|
+
# Concatenate content
|
325
|
+
if formatted_messages[role]['content']:
|
326
|
+
formatted_messages[role]['content'] += ' ' + content_str
|
327
|
+
else:
|
328
|
+
formatted_messages[role]['content'] = content_str
|
329
|
+
|
330
|
+
# Concatenate role and content for all messages
|
331
|
+
return ' '.join(
|
332
|
+
f"{message_data['role']}: {message_data['content']}"
|
333
|
+
for message_data in formatted_messages.values()
|
334
|
+
if message_data['content']
|
335
|
+
)
|
openlit/__init__.py
CHANGED
@@ -18,7 +18,7 @@ import requests
|
|
18
18
|
from opentelemetry import trace as t
|
19
19
|
from opentelemetry.trace import SpanKind, Status, StatusCode, Span
|
20
20
|
from opentelemetry.sdk.resources import SERVICE_NAME, DEPLOYMENT_ENVIRONMENT
|
21
|
-
from openlit.semcov import
|
21
|
+
from openlit.semcov import SemanticConvention
|
22
22
|
from openlit.otel.tracing import setup_tracing
|
23
23
|
from openlit.otel.metrics import setup_meter
|
24
24
|
from openlit.otel.events import setup_events
|
@@ -573,7 +573,7 @@ def trace(wrapped):
|
|
573
573
|
try:
|
574
574
|
response = wrapped(*args, **kwargs)
|
575
575
|
span.set_attribute(
|
576
|
-
|
576
|
+
SemanticConvention.GEN_AI_CONTENT_COMPLETION, response or ""
|
577
577
|
)
|
578
578
|
span.set_status(Status(StatusCode.OK))
|
579
579
|
except Exception as e:
|
@@ -632,7 +632,7 @@ class TracedSpan:
|
|
632
632
|
result: The result to be set as an attribute on the span.
|
633
633
|
"""
|
634
634
|
|
635
|
-
self._span.set_attribute(
|
635
|
+
self._span.set_attribute(SemanticConvention.GEN_AI_CONTENT_COMPLETION, result)
|
636
636
|
|
637
637
|
def set_metadata(self, metadata: Dict):
|
638
638
|
"""
|
openlit/evals/utils.py
CHANGED
@@ -10,7 +10,7 @@ from opentelemetry.metrics import get_meter
|
|
10
10
|
from opentelemetry.sdk.resources import TELEMETRY_SDK_NAME
|
11
11
|
from anthropic import Anthropic
|
12
12
|
from openai import OpenAI
|
13
|
-
from openlit.semcov import
|
13
|
+
from openlit.semcov import SemanticConvention
|
14
14
|
|
15
15
|
# Initialize logger for logging potential issues and operations
|
16
16
|
logger = logging.getLogger(__name__)
|
@@ -238,7 +238,7 @@ def eval_metrics():
|
|
238
238
|
)
|
239
239
|
|
240
240
|
guard_requests = meter.create_counter(
|
241
|
-
name=
|
241
|
+
name=SemanticConvention.EVAL_REQUESTS,
|
242
242
|
description="Counter for evaluation requests",
|
243
243
|
unit="1"
|
244
244
|
)
|
@@ -262,14 +262,14 @@ def eval_metric_attributes(verdict, score, validator, classification, explanatio
|
|
262
262
|
return {
|
263
263
|
TELEMETRY_SDK_NAME:
|
264
264
|
"openlit",
|
265
|
-
|
265
|
+
SemanticConvention.EVAL_VERDICT:
|
266
266
|
verdict,
|
267
|
-
|
267
|
+
SemanticConvention.EVAL_SCORE:
|
268
268
|
score,
|
269
|
-
|
269
|
+
SemanticConvention.EVAL_VALIDATOR:
|
270
270
|
validator,
|
271
|
-
|
271
|
+
SemanticConvention.EVAL_CLASSIFICATION:
|
272
272
|
classification,
|
273
|
-
|
273
|
+
SemanticConvention.EVAL_EXPLANATION:
|
274
274
|
explanation,
|
275
275
|
}
|
openlit/guard/utils.py
CHANGED
@@ -11,7 +11,7 @@ from opentelemetry.metrics import get_meter
|
|
11
11
|
from opentelemetry.sdk.resources import TELEMETRY_SDK_NAME
|
12
12
|
from anthropic import Anthropic
|
13
13
|
from openai import OpenAI
|
14
|
-
from openlit.semcov import
|
14
|
+
from openlit.semcov import SemanticConvention
|
15
15
|
|
16
16
|
# Initialize logger for logging potential issues and operations
|
17
17
|
logger = logging.getLogger(__name__)
|
@@ -202,7 +202,7 @@ def guard_metrics():
|
|
202
202
|
)
|
203
203
|
|
204
204
|
guard_requests = meter.create_counter(
|
205
|
-
name=
|
205
|
+
name=SemanticConvention.GUARD_REQUESTS,
|
206
206
|
description="Counter for Guard requests",
|
207
207
|
unit="1"
|
208
208
|
)
|
@@ -224,9 +224,9 @@ def guard_metric_attributes(verdict, score, validator, classification, explanati
|
|
224
224
|
"""
|
225
225
|
return {
|
226
226
|
TELEMETRY_SDK_NAME: "openlit",
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
227
|
+
SemanticConvention.GUARD_VERDICT: verdict,
|
228
|
+
SemanticConvention.GUARD_SCORE: score,
|
229
|
+
SemanticConvention.GUARD_VALIDATOR: validator,
|
230
|
+
SemanticConvention.GUARD_CLASSIFICATION: classification,
|
231
|
+
SemanticConvention.GUARD_EXPLANATION: explanation,
|
232
232
|
}
|
@@ -11,7 +11,7 @@ from openlit.__helpers import (
|
|
11
11
|
get_chat_model_cost,
|
12
12
|
otel_event,
|
13
13
|
)
|
14
|
-
from openlit.semcov import
|
14
|
+
from openlit.semcov import SemanticConvention
|
15
15
|
|
16
16
|
# Initialize logger for logging potential issues and operations
|
17
17
|
logger = logging.getLogger(__name__)
|
@@ -29,17 +29,17 @@ def set_span_attributes(span, version, operation_name, environment,
|
|
29
29
|
|
30
30
|
# Set Span attributes (OTel Semconv)
|
31
31
|
span.set_attribute(TELEMETRY_SDK_NAME, 'openlit')
|
32
|
-
span.set_attribute(
|
33
|
-
span.set_attribute(
|
34
|
-
span.set_attribute(
|
35
|
-
span.set_attribute(
|
36
|
-
span.set_attribute(
|
37
|
-
span.set_attribute(
|
32
|
+
span.set_attribute(SemanticConvention.GEN_AI_OPERATION, operation_name)
|
33
|
+
span.set_attribute(SemanticConvention.GEN_AI_SYSTEM, SemanticConvention.GEN_AI_SYSTEM_AG2)
|
34
|
+
span.set_attribute(SemanticConvention.GEN_AI_AGENT_NAME, AGENT_NAME)
|
35
|
+
span.set_attribute(SemanticConvention.SERVER_ADDRESS, server_address)
|
36
|
+
span.set_attribute(SemanticConvention.SERVER_PORT, server_port)
|
37
|
+
span.set_attribute(SemanticConvention.GEN_AI_REQUEST_MODEL, request_model)
|
38
38
|
|
39
39
|
# Set Span attributes (Extras)
|
40
40
|
span.set_attribute(DEPLOYMENT_ENVIRONMENT, environment)
|
41
41
|
span.set_attribute(SERVICE_NAME, application_name)
|
42
|
-
span.set_attribute(
|
42
|
+
span.set_attribute(SemanticConvention.GEN_AI_SDK_VERSION, version)
|
43
43
|
|
44
44
|
def calculate_tokens_and_cost(response, request_model, pricing_info):
|
45
45
|
"""
|
@@ -64,13 +64,13 @@ def emit_events(response, event_provider, capture_message_content):
|
|
64
64
|
"""
|
65
65
|
for chat in response.chat_history:
|
66
66
|
event_type = (
|
67
|
-
|
68
|
-
else
|
67
|
+
SemanticConvention.GEN_AI_CHOICE if chat['role'] == 'user'
|
68
|
+
else SemanticConvention.GEN_AI_USER_MESSAGE
|
69
69
|
)
|
70
70
|
choice_event = otel_event(
|
71
71
|
name=event_type,
|
72
72
|
attributes={
|
73
|
-
|
73
|
+
SemanticConvention.GEN_AI_SYSTEM: SemanticConvention.GEN_AI_SYSTEM_AG2
|
74
74
|
},
|
75
75
|
body={
|
76
76
|
'index': response.chat_history.index(chat),
|
@@ -97,7 +97,7 @@ def conversable_agent(version, environment, application_name,
|
|
97
97
|
SYSTEM_MESSAGE = kwargs.get('system_message', '')
|
98
98
|
MODEL_AND_NAME_SET = True
|
99
99
|
|
100
|
-
span_name = f'{
|
100
|
+
span_name = f'{SemanticConvention.GEN_AI_OPERATION_TYPE_CREATE_AGENT} {AGENT_NAME}'
|
101
101
|
|
102
102
|
with tracer.start_as_current_span(span_name, kind=SpanKind.CLIENT) as span:
|
103
103
|
try:
|
@@ -105,11 +105,11 @@ def conversable_agent(version, environment, application_name,
|
|
105
105
|
response = wrapped(*args, **kwargs)
|
106
106
|
end_time = time.time()
|
107
107
|
|
108
|
-
set_span_attributes(span, version,
|
108
|
+
set_span_attributes(span, version, SemanticConvention.GEN_AI_OPERATION_TYPE_CREATE_AGENT,
|
109
109
|
environment, application_name, server_address, server_port, REQUEST_MODEL)
|
110
|
-
span.set_attribute(
|
111
|
-
span.set_attribute(
|
112
|
-
span.set_attribute(
|
110
|
+
span.set_attribute(SemanticConvention.GEN_AI_AGENT_DESCRIPTION, SYSTEM_MESSAGE)
|
111
|
+
span.set_attribute(SemanticConvention.GEN_AI_RESPONSE_MODEL, REQUEST_MODEL)
|
112
|
+
span.set_attribute(SemanticConvention.GEN_AI_SERVER_TTFT, end_time - start_time)
|
113
113
|
|
114
114
|
span.set_status(Status(StatusCode.OK))
|
115
115
|
|
@@ -130,7 +130,7 @@ def agent_run(version, environment, application_name,
|
|
130
130
|
def wrapper(wrapped, instance, args, kwargs):
|
131
131
|
server_address, server_port = '127.0.0.1', 80
|
132
132
|
|
133
|
-
span_name = f'{
|
133
|
+
span_name = f'{SemanticConvention.GEN_AI_OPERATION_TYPE_EXECUTE_AGENT_TASK} {AGENT_NAME}'
|
134
134
|
|
135
135
|
with tracer.start_as_current_span(span_name, kind=SpanKind.CLIENT) as span:
|
136
136
|
try:
|
@@ -141,14 +141,14 @@ def agent_run(version, environment, application_name,
|
|
141
141
|
input_tokens, output_tokens, cost = calculate_tokens_and_cost(response, REQUEST_MODEL, pricing_info)
|
142
142
|
response_model = list(response.cost.get('usage_including_cached_inference', {}).keys())[1]
|
143
143
|
|
144
|
-
set_span_attributes(span, version,
|
144
|
+
set_span_attributes(span, version, SemanticConvention.GEN_AI_OPERATION_TYPE_EXECUTE_AGENT_TASK,
|
145
145
|
environment, application_name, server_address, server_port, REQUEST_MODEL)
|
146
|
-
span.set_attribute(
|
147
|
-
span.set_attribute(
|
148
|
-
span.set_attribute(
|
149
|
-
span.set_attribute(
|
150
|
-
span.set_attribute(
|
151
|
-
span.set_attribute(
|
146
|
+
span.set_attribute(SemanticConvention.GEN_AI_RESPONSE_MODEL, response_model)
|
147
|
+
span.set_attribute(SemanticConvention.GEN_AI_USAGE_INPUT_TOKENS, input_tokens)
|
148
|
+
span.set_attribute(SemanticConvention.GEN_AI_USAGE_OUTPUT_TOKENS, output_tokens)
|
149
|
+
span.set_attribute(SemanticConvention.GEN_AI_CLIENT_TOKEN_USAGE, input_tokens + output_tokens)
|
150
|
+
span.set_attribute(SemanticConvention.GEN_AI_USAGE_COST, cost)
|
151
|
+
span.set_attribute(SemanticConvention.GEN_AI_SERVER_TTFT, end_time - start_time)
|
152
152
|
|
153
153
|
emit_events(response, event_provider, capture_message_content)
|
154
154
|
span.set_status(Status(StatusCode.OK))
|
@@ -16,7 +16,7 @@ from openlit.instrumentation.ai21.utils import (
|
|
16
16
|
process_chat_rag_response
|
17
17
|
)
|
18
18
|
|
19
|
-
from openlit.semcov import
|
19
|
+
from openlit.semcov import SemanticConvention
|
20
20
|
|
21
21
|
# Initialize logger for logging potential issues and operations
|
22
22
|
logger = logging.getLogger(__name__)
|
@@ -113,7 +113,7 @@ def chat(version, environment, application_name,
|
|
113
113
|
server_address, server_port = set_server_address_and_port(instance, 'api.ai21.com', 443)
|
114
114
|
request_model = kwargs.get('model', 'jamba-1.5-mini')
|
115
115
|
|
116
|
-
span_name = f'{
|
116
|
+
span_name = f'{SemanticConvention.GEN_AI_OPERATION_TYPE_CHAT} {request_model}'
|
117
117
|
|
118
118
|
# pylint: disable=no-else-return
|
119
119
|
if streaming:
|
@@ -163,7 +163,7 @@ def chat_rag(version, environment, application_name,
|
|
163
163
|
server_address, server_port = set_server_address_and_port(instance, 'api.ai21.com', 443)
|
164
164
|
request_model = kwargs.get('model', 'jamba-1.5-mini')
|
165
165
|
|
166
|
-
span_name = f'{
|
166
|
+
span_name = f'{SemanticConvention.GEN_AI_OPERATION_TYPE_CHAT} {request_model}'
|
167
167
|
|
168
168
|
with tracer.start_as_current_span(span_name, kind= SpanKind.CLIENT) as span:
|
169
169
|
start_time = time.time()
|
@@ -16,7 +16,7 @@ from openlit.instrumentation.ai21.utils import (
|
|
16
16
|
process_chat_rag_response
|
17
17
|
)
|
18
18
|
|
19
|
-
from openlit.semcov import
|
19
|
+
from openlit.semcov import SemanticConvention
|
20
20
|
|
21
21
|
# Initialize logger for logging potential issues and operations
|
22
22
|
logger = logging.getLogger(__name__)
|
@@ -113,7 +113,7 @@ def async_chat(version, environment, application_name,
|
|
113
113
|
server_address, server_port = set_server_address_and_port(instance, 'api.ai21.com', 443)
|
114
114
|
request_model = kwargs.get('model', 'jamba-1.5-mini')
|
115
115
|
|
116
|
-
span_name = f'{
|
116
|
+
span_name = f'{SemanticConvention.GEN_AI_OPERATION_TYPE_CHAT} {request_model}'
|
117
117
|
|
118
118
|
# pylint: disable=no-else-return
|
119
119
|
if streaming:
|
@@ -163,7 +163,7 @@ def async_chat_rag(version, environment, application_name,
|
|
163
163
|
server_address, server_port = set_server_address_and_port(instance, 'api.ai21.com', 443)
|
164
164
|
request_model = kwargs.get('model', 'jamba-1.5-mini')
|
165
165
|
|
166
|
-
span_name = f'{
|
166
|
+
span_name = f'{SemanticConvention.GEN_AI_OPERATION_TYPE_CHAT} {request_model}'
|
167
167
|
|
168
168
|
with tracer.start_as_current_span(span_name, kind= SpanKind.CLIENT) as span:
|
169
169
|
start_time = time.time()
|
@@ -19,7 +19,7 @@ from openlit.__helpers import (
|
|
19
19
|
otel_event,
|
20
20
|
concatenate_all_contents
|
21
21
|
)
|
22
|
-
from openlit.semcov import
|
22
|
+
from openlit.semcov import SemanticConvention
|
23
23
|
|
24
24
|
def setup_common_span_attributes(span, request_model, kwargs, tokens,
|
25
25
|
server_port, server_address, environment,
|
@@ -30,32 +30,32 @@ def setup_common_span_attributes(span, request_model, kwargs, tokens,
|
|
30
30
|
|
31
31
|
# Base attributes from SDK and operation settings.
|
32
32
|
span.set_attribute(TELEMETRY_SDK_NAME, 'openlit')
|
33
|
-
span.set_attribute(
|
34
|
-
span.set_attribute(
|
35
|
-
span.set_attribute(
|
36
|
-
span.set_attribute(
|
37
|
-
span.set_attribute(
|
38
|
-
span.set_attribute(
|
39
|
-
span.set_attribute(
|
40
|
-
span.set_attribute(
|
41
|
-
span.set_attribute(
|
42
|
-
span.set_attribute(
|
43
|
-
span.set_attribute(
|
33
|
+
span.set_attribute(SemanticConvention.GEN_AI_OPERATION, SemanticConvention.GEN_AI_OPERATION_TYPE_CHAT)
|
34
|
+
span.set_attribute(SemanticConvention.GEN_AI_SYSTEM, SemanticConvention.GEN_AI_SYSTEM_AI21)
|
35
|
+
span.set_attribute(SemanticConvention.GEN_AI_REQUEST_MODEL, request_model)
|
36
|
+
span.set_attribute(SemanticConvention.SERVER_PORT, server_port)
|
37
|
+
span.set_attribute(SemanticConvention.GEN_AI_REQUEST_SEED, kwargs.get('seed', ''))
|
38
|
+
span.set_attribute(SemanticConvention.GEN_AI_REQUEST_FREQUENCY_PENALTY, kwargs.get('frequency_penalty', 0.0))
|
39
|
+
span.set_attribute(SemanticConvention.GEN_AI_REQUEST_MAX_TOKENS, kwargs.get('max_tokens', -1))
|
40
|
+
span.set_attribute(SemanticConvention.GEN_AI_REQUEST_PRESENCE_PENALTY, kwargs.get('presence_penalty', 0.0))
|
41
|
+
span.set_attribute(SemanticConvention.GEN_AI_REQUEST_STOP_SEQUENCES, kwargs.get('stop', []))
|
42
|
+
span.set_attribute(SemanticConvention.GEN_AI_REQUEST_TEMPERATURE, kwargs.get('temperature', 0.4))
|
43
|
+
span.set_attribute(SemanticConvention.GEN_AI_REQUEST_TOP_P, kwargs.get('top_p', 1.0))
|
44
44
|
|
45
45
|
# Add token-related attributes if available.
|
46
46
|
if 'finish_reason' in tokens:
|
47
|
-
span.set_attribute(
|
47
|
+
span.set_attribute(SemanticConvention.GEN_AI_RESPONSE_FINISH_REASON, [tokens['finish_reason']])
|
48
48
|
if 'response_id' in tokens:
|
49
|
-
span.set_attribute(
|
49
|
+
span.set_attribute(SemanticConvention.GEN_AI_RESPONSE_ID, tokens['response_id'])
|
50
50
|
if 'input_tokens' in tokens:
|
51
|
-
span.set_attribute(
|
51
|
+
span.set_attribute(SemanticConvention.GEN_AI_USAGE_INPUT_TOKENS, tokens['input_tokens'])
|
52
52
|
if 'output_tokens' in tokens:
|
53
|
-
span.set_attribute(
|
53
|
+
span.set_attribute(SemanticConvention.GEN_AI_USAGE_OUTPUT_TOKENS, tokens['output_tokens'])
|
54
54
|
if 'total_tokens' in tokens:
|
55
|
-
span.set_attribute(
|
55
|
+
span.set_attribute(SemanticConvention.GEN_AI_USAGE_TOTAL_TOKENS, tokens['total_tokens'])
|
56
56
|
|
57
|
-
span.set_attribute(
|
58
|
-
span.set_attribute(
|
57
|
+
span.set_attribute(SemanticConvention.GEN_AI_RESPONSE_MODEL, request_model)
|
58
|
+
span.set_attribute(SemanticConvention.SERVER_ADDRESS, server_address)
|
59
59
|
# Environment and service identifiers.
|
60
60
|
span.set_attribute(DEPLOYMENT_ENVIRONMENT, environment)
|
61
61
|
span.set_attribute(SERVICE_NAME, application_name)
|
@@ -73,8 +73,8 @@ def record_common_metrics(metrics, application_name, environment, request_model,
|
|
73
73
|
attributes = create_metrics_attributes(
|
74
74
|
service_name=application_name,
|
75
75
|
deployment_environment=environment,
|
76
|
-
operation=
|
77
|
-
system=
|
76
|
+
operation=SemanticConvention.GEN_AI_OPERATION_TYPE_CHAT,
|
77
|
+
system=SemanticConvention.GEN_AI_SYSTEM_AI21,
|
78
78
|
request_model=request_model,
|
79
79
|
server_address=server_address,
|
80
80
|
server_port=server_port,
|
@@ -121,15 +121,15 @@ def emit_common_events(event_provider, choices, finish_reason, llmresponse, form
|
|
121
121
|
}
|
122
122
|
})
|
123
123
|
event = otel_event(
|
124
|
-
name=
|
125
|
-
attributes={
|
124
|
+
name=SemanticConvention.GEN_AI_CHOICE,
|
125
|
+
attributes={SemanticConvention.GEN_AI_SYSTEM: SemanticConvention.GEN_AI_SYSTEM_AI21},
|
126
126
|
body=choice_event_body
|
127
127
|
)
|
128
128
|
event_provider.emit(event)
|
129
129
|
else:
|
130
130
|
event = otel_event(
|
131
|
-
name=
|
132
|
-
attributes={
|
131
|
+
name=SemanticConvention.GEN_AI_CHOICE,
|
132
|
+
attributes={SemanticConvention.GEN_AI_SYSTEM: SemanticConvention.GEN_AI_SYSTEM_AI21},
|
133
133
|
body=choice_event_body
|
134
134
|
)
|
135
135
|
event_provider.emit(event)
|
@@ -144,8 +144,8 @@ def emit_common_events(event_provider, choices, finish_reason, llmresponse, form
|
|
144
144
|
}
|
145
145
|
}
|
146
146
|
event = otel_event(
|
147
|
-
name=
|
148
|
-
attributes={
|
147
|
+
name=SemanticConvention.GEN_AI_CHOICE,
|
148
|
+
attributes={SemanticConvention.GEN_AI_SYSTEM: SemanticConvention.GEN_AI_SYSTEM_AI21},
|
149
149
|
body=choice_event_body
|
150
150
|
)
|
151
151
|
event_provider.emit(event)
|
@@ -175,8 +175,8 @@ def emit_common_events(event_provider, choices, finish_reason, llmresponse, form
|
|
175
175
|
if tool_calls:
|
176
176
|
event_body['id'] = tool_calls[0].get('id', '')
|
177
177
|
event = otel_event(
|
178
|
-
name=getattr(
|
179
|
-
attributes={
|
178
|
+
name=getattr(SemanticConvention, f'GEN_AI_{role.upper()}_MESSAGE'),
|
179
|
+
attributes={SemanticConvention.GEN_AI_SYSTEM: SemanticConvention.GEN_AI_SYSTEM_AI21},
|
180
180
|
body=event_body
|
181
181
|
)
|
182
182
|
event_provider.emit(event)
|
@@ -233,13 +233,13 @@ def common_chat_logic(scope, pricing_info, environment, application_name, metric
|
|
233
233
|
'total_tokens': scope._input_tokens + scope._output_tokens,
|
234
234
|
}
|
235
235
|
extra_attrs = {
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
236
|
+
SemanticConvention.GEN_AI_REQUEST_IS_STREAM: is_stream,
|
237
|
+
SemanticConvention.GEN_AI_CLIENT_TOKEN_USAGE: scope._input_tokens + scope._output_tokens,
|
238
|
+
SemanticConvention.GEN_AI_USAGE_COST: cost,
|
239
|
+
SemanticConvention.GEN_AI_SERVER_TBT: scope._tbt,
|
240
|
+
SemanticConvention.GEN_AI_SERVER_TTFT: scope._ttft,
|
241
|
+
SemanticConvention.GEN_AI_SDK_VERSION: version,
|
242
|
+
SemanticConvention.GEN_AI_OUTPUT_TYPE: 'text' if isinstance(scope._llmresponse, str) else 'json'
|
243
243
|
}
|
244
244
|
# Set span attributes.
|
245
245
|
setup_common_span_attributes(scope._span, request_model, scope._kwargs, tokens,
|
@@ -249,12 +249,12 @@ def common_chat_logic(scope, pricing_info, environment, application_name, metric
|
|
249
249
|
# Optionally add events capturing the prompt and completion.
|
250
250
|
if capture_message_content:
|
251
251
|
scope._span.add_event(
|
252
|
-
name=
|
253
|
-
attributes={
|
252
|
+
name=SemanticConvention.GEN_AI_CONTENT_PROMPT_EVENT,
|
253
|
+
attributes={SemanticConvention.GEN_AI_CONTENT_PROMPT: prompt},
|
254
254
|
)
|
255
255
|
scope._span.add_event(
|
256
|
-
name=
|
257
|
-
attributes={
|
256
|
+
name=SemanticConvention.GEN_AI_CONTENT_COMPLETION_EVENT,
|
257
|
+
attributes={SemanticConvention.GEN_AI_CONTENT_COMPLETION: scope._llmresponse},
|
258
258
|
)
|
259
259
|
|
260
260
|
# Emit events for each choice and message role.
|
@@ -336,15 +336,15 @@ def process_chat_rag_response(response, request_model, pricing_info, server_port
|
|
336
336
|
# Create tokens dict and RAG-specific extra attributes.
|
337
337
|
tokens = {'response_id': response_dict.get('id'), 'input_tokens': input_tokens}
|
338
338
|
extra_attrs = {
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
339
|
+
SemanticConvention.GEN_AI_REQUEST_IS_STREAM: False,
|
340
|
+
SemanticConvention.GEN_AI_SERVER_TTFT: end_time - start_time,
|
341
|
+
SemanticConvention.GEN_AI_SDK_VERSION: version,
|
342
|
+
SemanticConvention.GEN_AI_RAG_MAX_SEGMENTS: kwargs.get('max_segments', -1),
|
343
|
+
SemanticConvention.GEN_AI_RAG_STRATEGY: kwargs.get('retrieval_strategy', 'segments'),
|
344
|
+
SemanticConvention.GEN_AI_RAG_SIMILARITY_THRESHOLD: kwargs.get('retrieval_similarity_threshold', -1),
|
345
|
+
SemanticConvention.GEN_AI_RAG_MAX_NEIGHBORS: kwargs.get('max_neighbors', -1),
|
346
|
+
SemanticConvention.GEN_AI_RAG_FILE_IDS: str(kwargs.get('file_ids', '')),
|
347
|
+
SemanticConvention.GEN_AI_RAG_DOCUMENTS_PATH: kwargs.get('path', '')
|
348
348
|
}
|
349
349
|
# Set common span attributes.
|
350
350
|
setup_common_span_attributes(span, request_model, kwargs, tokens,
|
@@ -354,8 +354,8 @@ def process_chat_rag_response(response, request_model, pricing_info, server_port
|
|
354
354
|
# Record the prompt event if requested.
|
355
355
|
if capture_message_content:
|
356
356
|
span.add_event(
|
357
|
-
name=
|
358
|
-
attributes={
|
357
|
+
name=SemanticConvention.GEN_AI_CONTENT_PROMPT_EVENT,
|
358
|
+
attributes={SemanticConvention.GEN_AI_CONTENT_PROMPT: prompt},
|
359
359
|
)
|
360
360
|
|
361
361
|
output_tokens = 0
|
@@ -368,13 +368,13 @@ def process_chat_rag_response(response, request_model, pricing_info, server_port
|
|
368
368
|
aggregated_completion.append(content)
|
369
369
|
output_tokens += general_tokens(content)
|
370
370
|
if kwargs.get('tools'):
|
371
|
-
span.set_attribute(
|
371
|
+
span.set_attribute(SemanticConvention.GEN_AI_TOOL_CALLS,
|
372
372
|
str(choices[i].get('message', {}).get('tool_calls')))
|
373
373
|
# Set output type based on actual content type.
|
374
374
|
if isinstance(content, str):
|
375
|
-
span.set_attribute(
|
375
|
+
span.set_attribute(SemanticConvention.GEN_AI_OUTPUT_TYPE, 'text')
|
376
376
|
elif content is not None:
|
377
|
-
span.set_attribute(
|
377
|
+
span.set_attribute(SemanticConvention.GEN_AI_OUTPUT_TYPE, 'json')
|
378
378
|
|
379
379
|
# Concatenate completion responses.
|
380
380
|
llmresponse = ''.join(aggregated_completion)
|
@@ -382,16 +382,16 @@ def process_chat_rag_response(response, request_model, pricing_info, server_port
|
|
382
382
|
tokens['total_tokens'] = input_tokens + output_tokens
|
383
383
|
|
384
384
|
cost = get_chat_model_cost(request_model, pricing_info, input_tokens, output_tokens)
|
385
|
-
span.set_attribute(
|
386
|
-
span.set_attribute(
|
387
|
-
span.set_attribute(
|
385
|
+
span.set_attribute(SemanticConvention.GEN_AI_USAGE_COST, cost)
|
386
|
+
span.set_attribute(SemanticConvention.GEN_AI_USAGE_OUTPUT_TOKENS, output_tokens)
|
387
|
+
span.set_attribute(SemanticConvention.GEN_AI_USAGE_TOTAL_TOKENS, input_tokens + output_tokens)
|
388
388
|
|
389
389
|
span.set_status(Status(StatusCode.OK))
|
390
390
|
# Emit a single aggregated completion event.
|
391
391
|
if capture_message_content:
|
392
392
|
span.add_event(
|
393
|
-
name=
|
394
|
-
attributes={
|
393
|
+
name=SemanticConvention.GEN_AI_CONTENT_COMPLETION_EVENT,
|
394
|
+
attributes={SemanticConvention.GEN_AI_CONTENT_COMPLETION: llmresponse},
|
395
395
|
)
|
396
396
|
# Emit the rest of the events (choice and role-based events) as before.
|
397
397
|
n = kwargs.get('n', 1)
|
@@ -14,7 +14,7 @@ from openlit.instrumentation.anthropic.utils import (
|
|
14
14
|
process_chat_response,
|
15
15
|
process_streaming_chat_response,
|
16
16
|
)
|
17
|
-
from openlit.semcov import
|
17
|
+
from openlit.semcov import SemanticConvention
|
18
18
|
|
19
19
|
# Initialize logger for logging potential issues and operations
|
20
20
|
logger = logging.getLogger(__name__)
|
@@ -113,7 +113,7 @@ def messages(version, environment, application_name, tracer, event_provider,
|
|
113
113
|
server_address, server_port = set_server_address_and_port(instance, 'api.anthropic.com', 443)
|
114
114
|
request_model = kwargs.get('model', 'claude-3-5-sonnet-latest')
|
115
115
|
|
116
|
-
span_name = f'{
|
116
|
+
span_name = f'{SemanticConvention.GEN_AI_OPERATION_TYPE_CHAT} {request_model}'
|
117
117
|
|
118
118
|
# pylint: disable=no-else-return
|
119
119
|
if streaming:
|
@@ -14,7 +14,7 @@ from openlit.instrumentation.anthropic.utils import (
|
|
14
14
|
process_chat_response,
|
15
15
|
process_streaming_chat_response,
|
16
16
|
)
|
17
|
-
from openlit.semcov import
|
17
|
+
from openlit.semcov import SemanticConvention
|
18
18
|
|
19
19
|
# Initialize logger for logging potential issues and operations
|
20
20
|
logger = logging.getLogger(__name__)
|
@@ -113,7 +113,7 @@ def async_messages(version, environment, application_name, tracer, event_provide
|
|
113
113
|
server_address, server_port = set_server_address_and_port(instance, 'api.anthropic.com', 443)
|
114
114
|
request_model = kwargs.get('model', 'claude-3-5-sonnet-latest')
|
115
115
|
|
116
|
-
span_name = f'{
|
116
|
+
span_name = f'{SemanticConvention.GEN_AI_OPERATION_TYPE_CHAT} {request_model}'
|
117
117
|
|
118
118
|
# pylint: disable=no-else-return
|
119
119
|
if streaming:
|