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.
- openlit/__helpers.py +235 -86
- openlit/__init__.py +16 -13
- openlit/_instrumentors.py +2 -1
- openlit/evals/all.py +50 -21
- openlit/evals/bias_detection.py +47 -20
- openlit/evals/hallucination.py +53 -22
- openlit/evals/toxicity.py +50 -21
- openlit/evals/utils.py +54 -30
- openlit/guard/all.py +61 -19
- openlit/guard/prompt_injection.py +34 -14
- openlit/guard/restrict_topic.py +46 -15
- openlit/guard/sensitive_topic.py +34 -14
- openlit/guard/utils.py +58 -22
- openlit/instrumentation/ag2/__init__.py +24 -8
- openlit/instrumentation/ag2/ag2.py +34 -13
- openlit/instrumentation/ag2/async_ag2.py +34 -13
- openlit/instrumentation/ag2/utils.py +133 -30
- openlit/instrumentation/ai21/__init__.py +43 -14
- openlit/instrumentation/ai21/ai21.py +47 -21
- openlit/instrumentation/ai21/async_ai21.py +47 -21
- openlit/instrumentation/ai21/utils.py +299 -78
- openlit/instrumentation/anthropic/__init__.py +21 -4
- openlit/instrumentation/anthropic/anthropic.py +28 -17
- openlit/instrumentation/anthropic/async_anthropic.py +28 -17
- openlit/instrumentation/anthropic/utils.py +145 -35
- openlit/instrumentation/assemblyai/__init__.py +11 -2
- openlit/instrumentation/assemblyai/assemblyai.py +15 -4
- openlit/instrumentation/assemblyai/utils.py +120 -25
- openlit/instrumentation/astra/__init__.py +43 -10
- openlit/instrumentation/astra/astra.py +28 -5
- openlit/instrumentation/astra/async_astra.py +28 -5
- openlit/instrumentation/astra/utils.py +151 -55
- openlit/instrumentation/azure_ai_inference/__init__.py +43 -10
- openlit/instrumentation/azure_ai_inference/async_azure_ai_inference.py +53 -21
- openlit/instrumentation/azure_ai_inference/azure_ai_inference.py +53 -21
- openlit/instrumentation/azure_ai_inference/utils.py +307 -83
- openlit/instrumentation/bedrock/__init__.py +21 -4
- openlit/instrumentation/bedrock/bedrock.py +63 -25
- openlit/instrumentation/bedrock/utils.py +139 -30
- openlit/instrumentation/chroma/__init__.py +89 -16
- openlit/instrumentation/chroma/chroma.py +28 -6
- openlit/instrumentation/chroma/utils.py +167 -51
- openlit/instrumentation/cohere/__init__.py +63 -18
- openlit/instrumentation/cohere/async_cohere.py +63 -24
- openlit/instrumentation/cohere/cohere.py +63 -24
- openlit/instrumentation/cohere/utils.py +286 -73
- openlit/instrumentation/controlflow/__init__.py +35 -9
- openlit/instrumentation/controlflow/controlflow.py +66 -33
- openlit/instrumentation/crawl4ai/__init__.py +25 -10
- openlit/instrumentation/crawl4ai/async_crawl4ai.py +78 -31
- openlit/instrumentation/crawl4ai/crawl4ai.py +78 -31
- openlit/instrumentation/crewai/__init__.py +40 -15
- openlit/instrumentation/crewai/async_crewai.py +32 -7
- openlit/instrumentation/crewai/crewai.py +32 -7
- openlit/instrumentation/crewai/utils.py +159 -56
- openlit/instrumentation/dynamiq/__init__.py +46 -12
- openlit/instrumentation/dynamiq/dynamiq.py +74 -33
- openlit/instrumentation/elevenlabs/__init__.py +23 -4
- openlit/instrumentation/elevenlabs/async_elevenlabs.py +16 -4
- openlit/instrumentation/elevenlabs/elevenlabs.py +16 -4
- openlit/instrumentation/elevenlabs/utils.py +128 -25
- openlit/instrumentation/embedchain/__init__.py +11 -2
- openlit/instrumentation/embedchain/embedchain.py +68 -35
- openlit/instrumentation/firecrawl/__init__.py +24 -7
- openlit/instrumentation/firecrawl/firecrawl.py +46 -20
- openlit/instrumentation/google_ai_studio/__init__.py +45 -10
- openlit/instrumentation/google_ai_studio/async_google_ai_studio.py +67 -44
- openlit/instrumentation/google_ai_studio/google_ai_studio.py +67 -44
- openlit/instrumentation/google_ai_studio/utils.py +180 -67
- openlit/instrumentation/gpt4all/__init__.py +22 -7
- openlit/instrumentation/gpt4all/gpt4all.py +67 -29
- openlit/instrumentation/gpt4all/utils.py +285 -61
- openlit/instrumentation/gpu/__init__.py +128 -47
- openlit/instrumentation/groq/__init__.py +21 -4
- openlit/instrumentation/groq/async_groq.py +33 -21
- openlit/instrumentation/groq/groq.py +33 -21
- openlit/instrumentation/groq/utils.py +192 -55
- openlit/instrumentation/haystack/__init__.py +70 -24
- openlit/instrumentation/haystack/async_haystack.py +28 -6
- openlit/instrumentation/haystack/haystack.py +28 -6
- openlit/instrumentation/haystack/utils.py +196 -74
- openlit/instrumentation/julep/__init__.py +69 -19
- openlit/instrumentation/julep/async_julep.py +53 -27
- openlit/instrumentation/julep/julep.py +53 -28
- openlit/instrumentation/langchain/__init__.py +74 -63
- openlit/instrumentation/langchain/callback_handler.py +1100 -0
- openlit/instrumentation/langchain_community/__init__.py +13 -2
- openlit/instrumentation/langchain_community/async_langchain_community.py +23 -5
- openlit/instrumentation/langchain_community/langchain_community.py +23 -5
- openlit/instrumentation/langchain_community/utils.py +35 -9
- openlit/instrumentation/letta/__init__.py +68 -15
- openlit/instrumentation/letta/letta.py +99 -54
- openlit/instrumentation/litellm/__init__.py +43 -14
- openlit/instrumentation/litellm/async_litellm.py +51 -26
- openlit/instrumentation/litellm/litellm.py +51 -26
- openlit/instrumentation/litellm/utils.py +304 -102
- openlit/instrumentation/llamaindex/__init__.py +267 -90
- openlit/instrumentation/llamaindex/async_llamaindex.py +28 -6
- openlit/instrumentation/llamaindex/llamaindex.py +28 -6
- openlit/instrumentation/llamaindex/utils.py +204 -91
- openlit/instrumentation/mem0/__init__.py +11 -2
- openlit/instrumentation/mem0/mem0.py +50 -29
- openlit/instrumentation/milvus/__init__.py +10 -2
- openlit/instrumentation/milvus/milvus.py +31 -6
- openlit/instrumentation/milvus/utils.py +166 -67
- openlit/instrumentation/mistral/__init__.py +63 -18
- openlit/instrumentation/mistral/async_mistral.py +63 -24
- openlit/instrumentation/mistral/mistral.py +63 -24
- openlit/instrumentation/mistral/utils.py +277 -69
- openlit/instrumentation/multion/__init__.py +69 -19
- openlit/instrumentation/multion/async_multion.py +57 -26
- openlit/instrumentation/multion/multion.py +57 -26
- openlit/instrumentation/ollama/__init__.py +39 -18
- openlit/instrumentation/ollama/async_ollama.py +57 -26
- openlit/instrumentation/ollama/ollama.py +57 -26
- openlit/instrumentation/ollama/utils.py +226 -50
- openlit/instrumentation/openai/__init__.py +156 -32
- openlit/instrumentation/openai/async_openai.py +147 -67
- openlit/instrumentation/openai/openai.py +150 -67
- openlit/instrumentation/openai/utils.py +657 -185
- openlit/instrumentation/openai_agents/__init__.py +5 -1
- openlit/instrumentation/openai_agents/processor.py +110 -90
- openlit/instrumentation/phidata/__init__.py +13 -5
- openlit/instrumentation/phidata/phidata.py +67 -32
- openlit/instrumentation/pinecone/__init__.py +48 -9
- openlit/instrumentation/pinecone/async_pinecone.py +27 -5
- openlit/instrumentation/pinecone/pinecone.py +27 -5
- openlit/instrumentation/pinecone/utils.py +153 -47
- openlit/instrumentation/premai/__init__.py +22 -7
- openlit/instrumentation/premai/premai.py +51 -26
- openlit/instrumentation/premai/utils.py +246 -59
- openlit/instrumentation/pydantic_ai/__init__.py +49 -22
- openlit/instrumentation/pydantic_ai/pydantic_ai.py +69 -16
- openlit/instrumentation/pydantic_ai/utils.py +89 -24
- openlit/instrumentation/qdrant/__init__.py +19 -4
- openlit/instrumentation/qdrant/async_qdrant.py +33 -7
- openlit/instrumentation/qdrant/qdrant.py +33 -7
- openlit/instrumentation/qdrant/utils.py +228 -93
- openlit/instrumentation/reka/__init__.py +23 -10
- openlit/instrumentation/reka/async_reka.py +17 -11
- openlit/instrumentation/reka/reka.py +17 -11
- openlit/instrumentation/reka/utils.py +138 -36
- openlit/instrumentation/together/__init__.py +44 -12
- openlit/instrumentation/together/async_together.py +50 -27
- openlit/instrumentation/together/together.py +50 -27
- openlit/instrumentation/together/utils.py +301 -71
- openlit/instrumentation/transformers/__init__.py +2 -1
- openlit/instrumentation/transformers/transformers.py +13 -3
- openlit/instrumentation/transformers/utils.py +139 -36
- openlit/instrumentation/vertexai/__init__.py +81 -16
- openlit/instrumentation/vertexai/async_vertexai.py +33 -15
- openlit/instrumentation/vertexai/utils.py +123 -27
- openlit/instrumentation/vertexai/vertexai.py +33 -15
- openlit/instrumentation/vllm/__init__.py +12 -5
- openlit/instrumentation/vllm/utils.py +121 -31
- openlit/instrumentation/vllm/vllm.py +16 -10
- openlit/otel/events.py +35 -10
- openlit/otel/metrics.py +32 -24
- openlit/otel/tracing.py +24 -9
- openlit/semcov/__init__.py +72 -6
- {openlit-1.34.30.dist-info → openlit-1.34.31.dist-info}/METADATA +2 -1
- openlit-1.34.31.dist-info/RECORD +166 -0
- openlit/instrumentation/langchain/async_langchain.py +0 -102
- openlit/instrumentation/langchain/langchain.py +0 -102
- openlit/instrumentation/langchain/utils.py +0 -252
- openlit-1.34.30.dist-info/RECORD +0 -168
- {openlit-1.34.30.dist-info → openlit-1.34.31.dist-info}/LICENSE +0 -0
- {openlit-1.34.30.dist-info → openlit-1.34.31.dist-info}/WHEEL +0 -0
@@ -1,4 +1,5 @@
|
|
1
1
|
"""Initializer of Auto Instrumentation of LangChain Community Functions"""
|
2
|
+
|
2
3
|
from typing import Collection
|
3
4
|
import importlib.metadata
|
4
5
|
from opentelemetry.instrumentation.instrumentor import BaseInstrumentor
|
@@ -40,6 +41,7 @@ WRAPPED_METHODS = [
|
|
40
41
|
},
|
41
42
|
]
|
42
43
|
|
44
|
+
|
43
45
|
class LangChainCommunityInstrumentor(BaseInstrumentor):
|
44
46
|
"""
|
45
47
|
An instrumentor for LangChain Community client library.
|
@@ -66,8 +68,17 @@ class LangChainCommunityInstrumentor(BaseInstrumentor):
|
|
66
68
|
wrap_function_wrapper(
|
67
69
|
wrap_package,
|
68
70
|
wrap_object,
|
69
|
-
wrapper(
|
70
|
-
|
71
|
+
wrapper(
|
72
|
+
gen_ai_endpoint,
|
73
|
+
version,
|
74
|
+
environment,
|
75
|
+
application_name,
|
76
|
+
tracer,
|
77
|
+
pricing_info,
|
78
|
+
capture_message_content,
|
79
|
+
metrics,
|
80
|
+
disable_metrics,
|
81
|
+
),
|
71
82
|
)
|
72
83
|
|
73
84
|
def _uninstrument(self, **kwargs):
|
@@ -12,8 +12,18 @@ from openlit.instrumentation.langchain_community.utils import process_general_re
|
|
12
12
|
# Initialize logger for LangChain Community instrumentation
|
13
13
|
logger = logging.getLogger(__name__)
|
14
14
|
|
15
|
-
|
16
|
-
|
15
|
+
|
16
|
+
def async_general_wrap(
|
17
|
+
gen_ai_endpoint,
|
18
|
+
version,
|
19
|
+
environment,
|
20
|
+
application_name,
|
21
|
+
tracer,
|
22
|
+
pricing_info,
|
23
|
+
capture_message_content,
|
24
|
+
metrics,
|
25
|
+
disable_metrics,
|
26
|
+
):
|
17
27
|
"""
|
18
28
|
Generates a telemetry wrapper for GenAI operations.
|
19
29
|
"""
|
@@ -28,15 +38,23 @@ def async_general_wrap(gen_ai_endpoint, version, environment, application_name,
|
|
28
38
|
server_port = "80"
|
29
39
|
|
30
40
|
# Get the parent span from the tracer
|
31
|
-
with tracer.start_as_current_span(
|
41
|
+
with tracer.start_as_current_span(
|
42
|
+
gen_ai_endpoint, kind=trace.SpanKind.CLIENT
|
43
|
+
) as span:
|
32
44
|
try:
|
33
45
|
# Call the original async function
|
34
46
|
response = await wrapped(*args, **kwargs)
|
35
47
|
|
36
48
|
# Process the response using the utility function
|
37
49
|
response = process_general_response(
|
38
|
-
response,
|
39
|
-
|
50
|
+
response,
|
51
|
+
gen_ai_endpoint,
|
52
|
+
server_port,
|
53
|
+
server_address,
|
54
|
+
environment,
|
55
|
+
application_name,
|
56
|
+
span,
|
57
|
+
version,
|
40
58
|
)
|
41
59
|
|
42
60
|
span.set_status(Status(StatusCode.OK))
|
@@ -12,8 +12,18 @@ from openlit.instrumentation.langchain_community.utils import process_general_re
|
|
12
12
|
# Initialize logger for LangChain Community instrumentation
|
13
13
|
logger = logging.getLogger(__name__)
|
14
14
|
|
15
|
-
|
16
|
-
|
15
|
+
|
16
|
+
def general_wrap(
|
17
|
+
gen_ai_endpoint,
|
18
|
+
version,
|
19
|
+
environment,
|
20
|
+
application_name,
|
21
|
+
tracer,
|
22
|
+
pricing_info,
|
23
|
+
capture_message_content,
|
24
|
+
metrics,
|
25
|
+
disable_metrics,
|
26
|
+
):
|
17
27
|
"""
|
18
28
|
Generates a telemetry wrapper for GenAI operations.
|
19
29
|
"""
|
@@ -28,15 +38,23 @@ def general_wrap(gen_ai_endpoint, version, environment, application_name, tracer
|
|
28
38
|
server_port = "80"
|
29
39
|
|
30
40
|
# Get the parent span from the tracer
|
31
|
-
with tracer.start_as_current_span(
|
41
|
+
with tracer.start_as_current_span(
|
42
|
+
gen_ai_endpoint, kind=trace.SpanKind.CLIENT
|
43
|
+
) as span:
|
32
44
|
try:
|
33
45
|
# Call the original function
|
34
46
|
response = wrapped(*args, **kwargs)
|
35
47
|
|
36
48
|
# Process the response using the utility function
|
37
49
|
response = process_general_response(
|
38
|
-
response,
|
39
|
-
|
50
|
+
response,
|
51
|
+
gen_ai_endpoint,
|
52
|
+
server_port,
|
53
|
+
server_address,
|
54
|
+
environment,
|
55
|
+
application_name,
|
56
|
+
span,
|
57
|
+
version,
|
40
58
|
)
|
41
59
|
|
42
60
|
span.set_status(Status(StatusCode.OK))
|
@@ -5,8 +5,17 @@ Utility functions for LangChain Community instrumentation.
|
|
5
5
|
from opentelemetry.trace import Status, StatusCode
|
6
6
|
from openlit.semcov import SemanticConvention
|
7
7
|
|
8
|
-
|
9
|
-
|
8
|
+
|
9
|
+
def process_general_response(
|
10
|
+
response,
|
11
|
+
gen_ai_endpoint,
|
12
|
+
server_port,
|
13
|
+
server_address,
|
14
|
+
environment,
|
15
|
+
application_name,
|
16
|
+
span,
|
17
|
+
version="1.0.0",
|
18
|
+
):
|
10
19
|
"""
|
11
20
|
Process general LangChain Community operations (document loading, text splitting) and generate telemetry.
|
12
21
|
|
@@ -25,9 +34,14 @@ def process_general_response(response, gen_ai_endpoint, server_port, server_addr
|
|
25
34
|
"""
|
26
35
|
|
27
36
|
# Set span attributes for general operations
|
28
|
-
span.set_attribute(
|
37
|
+
span.set_attribute(
|
38
|
+
SemanticConvention.GEN_AI_SYSTEM, SemanticConvention.GEN_AI_SYSTEM_LANGCHAIN
|
39
|
+
)
|
29
40
|
span.set_attribute(SemanticConvention.GEN_AI_ENDPOINT, gen_ai_endpoint)
|
30
|
-
span.set_attribute(
|
41
|
+
span.set_attribute(
|
42
|
+
SemanticConvention.GEN_AI_OPERATION,
|
43
|
+
SemanticConvention.GEN_AI_OPERATION_TYPE_FRAMEWORK,
|
44
|
+
)
|
31
45
|
span.set_attribute(SemanticConvention.GEN_AI_SDK_VERSION, version)
|
32
46
|
span.set_attribute(SemanticConvention.GEN_AI_ENVIRONMENT, environment)
|
33
47
|
span.set_attribute(SemanticConvention.GEN_AI_APPLICATION_NAME, application_name)
|
@@ -38,9 +52,13 @@ def process_general_response(response, gen_ai_endpoint, server_port, server_addr
|
|
38
52
|
if hasattr(response, "__iter__") and len(response) > 0:
|
39
53
|
# For document loaders, try to get source from first document
|
40
54
|
first_doc = response[0]
|
41
|
-
if hasattr(first_doc, "metadata") and isinstance(
|
55
|
+
if hasattr(first_doc, "metadata") and isinstance(
|
56
|
+
first_doc.metadata, dict
|
57
|
+
):
|
42
58
|
source = first_doc.metadata.get("source", "unknown")
|
43
|
-
span.set_attribute(
|
59
|
+
span.set_attribute(
|
60
|
+
SemanticConvention.GEN_AI_RETRIEVAL_SOURCE, source
|
61
|
+
)
|
44
62
|
|
45
63
|
# Count number of documents loaded
|
46
64
|
span.set_attribute("gen_ai.retrieval.documents.count", len(response))
|
@@ -49,17 +67,25 @@ def process_general_response(response, gen_ai_endpoint, server_port, server_addr
|
|
49
67
|
pass
|
50
68
|
|
51
69
|
# For text splitting operations
|
52
|
-
elif gen_ai_endpoint and (
|
70
|
+
elif gen_ai_endpoint and (
|
71
|
+
"split_documents" in gen_ai_endpoint or "create_documents" in gen_ai_endpoint
|
72
|
+
):
|
53
73
|
try:
|
54
74
|
if hasattr(response, "__iter__") and len(response) > 0:
|
55
75
|
# Count number of text chunks created
|
56
76
|
span.set_attribute("gen_ai.text_splitter.chunks.count", len(response))
|
57
77
|
|
58
78
|
# Try to get average chunk size
|
59
|
-
total_chars = sum(
|
79
|
+
total_chars = sum(
|
80
|
+
len(doc.page_content)
|
81
|
+
for doc in response
|
82
|
+
if hasattr(doc, "page_content")
|
83
|
+
)
|
60
84
|
if total_chars > 0:
|
61
85
|
avg_chunk_size = total_chars // len(response)
|
62
|
-
span.set_attribute(
|
86
|
+
span.set_attribute(
|
87
|
+
"gen_ai.text_splitter.avg_chunk_size", avg_chunk_size
|
88
|
+
)
|
63
89
|
except (AttributeError, TypeError):
|
64
90
|
# If we cant extract chunk information, just continue without it
|
65
91
|
pass
|
@@ -6,12 +6,11 @@ import importlib.metadata
|
|
6
6
|
from opentelemetry.instrumentation.instrumentor import BaseInstrumentor
|
7
7
|
from wrapt import wrap_function_wrapper
|
8
8
|
|
9
|
-
from openlit.instrumentation.letta.letta import
|
10
|
-
create_agent, send_message
|
11
|
-
)
|
9
|
+
from openlit.instrumentation.letta.letta import create_agent, send_message
|
12
10
|
|
13
11
|
_instruments = ("letta >= 0.6.2",)
|
14
12
|
|
13
|
+
|
15
14
|
class LettaInstrumentor(BaseInstrumentor):
|
16
15
|
"""
|
17
16
|
An instrumentor for Letta's client library.
|
@@ -33,43 +32,97 @@ class LettaInstrumentor(BaseInstrumentor):
|
|
33
32
|
wrap_function_wrapper(
|
34
33
|
"letta.client.client",
|
35
34
|
"LocalClient.create_agent",
|
36
|
-
create_agent(
|
37
|
-
|
35
|
+
create_agent(
|
36
|
+
"letta.create_agent",
|
37
|
+
version,
|
38
|
+
environment,
|
39
|
+
application_name,
|
40
|
+
tracer,
|
41
|
+
pricing_info,
|
42
|
+
capture_message_content,
|
43
|
+
metrics,
|
44
|
+
disable_metrics,
|
45
|
+
),
|
38
46
|
)
|
39
47
|
|
40
48
|
wrap_function_wrapper(
|
41
49
|
"letta.client.client",
|
42
50
|
"LocalClient.get_agent",
|
43
|
-
create_agent(
|
44
|
-
|
51
|
+
create_agent(
|
52
|
+
"letta.get_agent",
|
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
|
wrap_function_wrapper(
|
48
65
|
"letta.client.client",
|
49
66
|
"LocalClient.send_message",
|
50
|
-
send_message(
|
51
|
-
|
67
|
+
send_message(
|
68
|
+
"letta.send_message",
|
69
|
+
version,
|
70
|
+
environment,
|
71
|
+
application_name,
|
72
|
+
tracer,
|
73
|
+
pricing_info,
|
74
|
+
capture_message_content,
|
75
|
+
metrics,
|
76
|
+
disable_metrics,
|
77
|
+
),
|
52
78
|
)
|
53
79
|
|
54
80
|
wrap_function_wrapper(
|
55
81
|
"letta.client.client",
|
56
82
|
"RESTClient.create_agent",
|
57
|
-
create_agent(
|
58
|
-
|
83
|
+
create_agent(
|
84
|
+
"letta.create_agent",
|
85
|
+
version,
|
86
|
+
environment,
|
87
|
+
application_name,
|
88
|
+
tracer,
|
89
|
+
pricing_info,
|
90
|
+
capture_message_content,
|
91
|
+
metrics,
|
92
|
+
disable_metrics,
|
93
|
+
),
|
59
94
|
)
|
60
95
|
|
61
96
|
wrap_function_wrapper(
|
62
97
|
"letta.client.client",
|
63
98
|
"RESTClient.get_agent",
|
64
|
-
create_agent(
|
65
|
-
|
99
|
+
create_agent(
|
100
|
+
"letta.get_agent",
|
101
|
+
version,
|
102
|
+
environment,
|
103
|
+
application_name,
|
104
|
+
tracer,
|
105
|
+
pricing_info,
|
106
|
+
capture_message_content,
|
107
|
+
metrics,
|
108
|
+
disable_metrics,
|
109
|
+
),
|
66
110
|
)
|
67
111
|
|
68
112
|
wrap_function_wrapper(
|
69
113
|
"letta.client.client",
|
70
114
|
"RESTClient.send_message",
|
71
|
-
send_message(
|
72
|
-
|
115
|
+
send_message(
|
116
|
+
"letta.send_message",
|
117
|
+
version,
|
118
|
+
environment,
|
119
|
+
application_name,
|
120
|
+
tracer,
|
121
|
+
pricing_info,
|
122
|
+
capture_message_content,
|
123
|
+
metrics,
|
124
|
+
disable_metrics,
|
125
|
+
),
|
73
126
|
)
|
74
127
|
|
75
128
|
def _uninstrument(self, **kwargs):
|
@@ -5,17 +5,29 @@ Module for monitoring Letta calls.
|
|
5
5
|
|
6
6
|
import logging
|
7
7
|
from opentelemetry.trace import SpanKind, Status, StatusCode
|
8
|
-
from opentelemetry.sdk.resources import
|
9
|
-
|
10
|
-
|
8
|
+
from opentelemetry.sdk.resources import (
|
9
|
+
SERVICE_NAME,
|
10
|
+
TELEMETRY_SDK_NAME,
|
11
|
+
DEPLOYMENT_ENVIRONMENT,
|
11
12
|
)
|
13
|
+
from openlit.__helpers import handle_exception, get_chat_model_cost
|
12
14
|
from openlit.semcov import SemanticConvention
|
13
15
|
|
14
16
|
# Initialize logger for logging potential issues and operations
|
15
17
|
logger = logging.getLogger(__name__)
|
16
18
|
|
17
|
-
|
18
|
-
|
19
|
+
|
20
|
+
def create_agent(
|
21
|
+
gen_ai_endpoint,
|
22
|
+
version,
|
23
|
+
environment,
|
24
|
+
application_name,
|
25
|
+
tracer,
|
26
|
+
pricing_info,
|
27
|
+
capture_message_content,
|
28
|
+
metrics,
|
29
|
+
disable_metrics,
|
30
|
+
):
|
19
31
|
"""
|
20
32
|
Generates a telemetry wrapper for chat completions to collect metrics.
|
21
33
|
|
@@ -50,34 +62,39 @@ def create_agent(gen_ai_endpoint, version, environment, application_name,
|
|
50
62
|
"""
|
51
63
|
|
52
64
|
# pylint: disable=line-too-long
|
53
|
-
with tracer.start_as_current_span(
|
65
|
+
with tracer.start_as_current_span(
|
66
|
+
gen_ai_endpoint, kind=SpanKind.CLIENT
|
67
|
+
) as span:
|
54
68
|
response = wrapped(*args, **kwargs)
|
55
69
|
|
56
70
|
try:
|
57
71
|
# Set base span attribues
|
58
72
|
span.set_attribute(TELEMETRY_SDK_NAME, "openlit")
|
59
|
-
span.set_attribute(
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
span.set_attribute(
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
span.set_attribute(
|
68
|
-
|
69
|
-
span.set_attribute(
|
70
|
-
|
71
|
-
span.set_attribute(SemanticConvention.GEN_AI_AGENT_ROLE,
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
span.set_attribute(
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
73
|
+
span.set_attribute(
|
74
|
+
SemanticConvention.GEN_AI_SYSTEM,
|
75
|
+
SemanticConvention.GEN_AI_SYSTEM_LETTA,
|
76
|
+
)
|
77
|
+
span.set_attribute(
|
78
|
+
SemanticConvention.GEN_AI_OPERATION,
|
79
|
+
SemanticConvention.GEN_AI_OPERATION_TYPE_AGENT,
|
80
|
+
)
|
81
|
+
span.set_attribute(SemanticConvention.GEN_AI_ENDPOINT, gen_ai_endpoint)
|
82
|
+
span.set_attribute(SERVICE_NAME, application_name)
|
83
|
+
span.set_attribute(DEPLOYMENT_ENVIRONMENT, environment)
|
84
|
+
span.set_attribute(SemanticConvention.GEN_AI_AGENT_ID, response.id)
|
85
|
+
span.set_attribute(SemanticConvention.GEN_AI_AGENT_ROLE, response.name)
|
86
|
+
span.set_attribute(
|
87
|
+
SemanticConvention.GEN_AI_AGENT_INSTRUCTIONS, response.system
|
88
|
+
)
|
89
|
+
span.set_attribute(
|
90
|
+
SemanticConvention.GEN_AI_REQUEST_MODEL, response.llm_config.model
|
91
|
+
)
|
92
|
+
span.set_attribute(
|
93
|
+
SemanticConvention.GEN_AI_AGENT_TYPE, response.agent_type
|
94
|
+
)
|
95
|
+
span.set_attribute(
|
96
|
+
SemanticConvention.GEN_AI_AGENT_TOOLS, response.tool_names
|
97
|
+
)
|
81
98
|
|
82
99
|
span.set_status(Status(StatusCode.OK))
|
83
100
|
|
@@ -93,8 +110,18 @@ def create_agent(gen_ai_endpoint, version, environment, application_name,
|
|
93
110
|
|
94
111
|
return wrapper
|
95
112
|
|
96
|
-
|
97
|
-
|
113
|
+
|
114
|
+
def send_message(
|
115
|
+
gen_ai_endpoint,
|
116
|
+
version,
|
117
|
+
environment,
|
118
|
+
application_name,
|
119
|
+
tracer,
|
120
|
+
pricing_info,
|
121
|
+
capture_message_content,
|
122
|
+
metrics,
|
123
|
+
disable_metrics,
|
124
|
+
):
|
98
125
|
"""
|
99
126
|
Generates a telemetry wrapper for chat completions to collect metrics.
|
100
127
|
|
@@ -129,47 +156,65 @@ def send_message(gen_ai_endpoint, version, environment, application_name,
|
|
129
156
|
"""
|
130
157
|
|
131
158
|
# pylint: disable=line-too-long
|
132
|
-
with tracer.start_as_current_span(
|
159
|
+
with tracer.start_as_current_span(
|
160
|
+
gen_ai_endpoint, kind=SpanKind.CLIENT
|
161
|
+
) as span:
|
133
162
|
response = wrapped(*args, **kwargs)
|
134
163
|
|
135
164
|
try:
|
136
165
|
# Calculate cost of the operation
|
137
|
-
cost = get_chat_model_cost(
|
138
|
-
|
139
|
-
|
166
|
+
cost = get_chat_model_cost(
|
167
|
+
kwargs.get("model", "gpt-4o"),
|
168
|
+
pricing_info,
|
169
|
+
response.usage.prompt_tokens,
|
170
|
+
response.usage.completion_tokens,
|
171
|
+
)
|
140
172
|
# Set base span attribues
|
141
173
|
span.set_attribute(TELEMETRY_SDK_NAME, "openlit")
|
142
|
-
span.set_attribute(
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
span.set_attribute(
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
span.set_attribute(SemanticConvention.
|
151
|
-
|
152
|
-
span.set_attribute(
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
span.set_attribute(
|
157
|
-
|
158
|
-
|
159
|
-
|
174
|
+
span.set_attribute(
|
175
|
+
SemanticConvention.GEN_AI_SYSTEM,
|
176
|
+
SemanticConvention.GEN_AI_SYSTEM_LETTA,
|
177
|
+
)
|
178
|
+
span.set_attribute(
|
179
|
+
SemanticConvention.GEN_AI_OPERATION,
|
180
|
+
SemanticConvention.GEN_AI_OPERATION_TYPE_AGENT,
|
181
|
+
)
|
182
|
+
span.set_attribute(SemanticConvention.GEN_AI_ENDPOINT, gen_ai_endpoint)
|
183
|
+
span.set_attribute(SERVICE_NAME, application_name)
|
184
|
+
span.set_attribute(
|
185
|
+
SemanticConvention.GEN_AI_AGENT_STEP_COUNT,
|
186
|
+
response.usage.step_count,
|
187
|
+
)
|
188
|
+
span.set_attribute(
|
189
|
+
SemanticConvention.GEN_AI_USAGE_INPUT_TOKENS,
|
190
|
+
response.usage.prompt_tokens,
|
191
|
+
)
|
192
|
+
span.set_attribute(
|
193
|
+
SemanticConvention.GEN_AI_USAGE_OUTPUT_TOKENS,
|
194
|
+
response.usage.completion_tokens,
|
195
|
+
)
|
196
|
+
span.set_attribute(
|
197
|
+
SemanticConvention.GEN_AI_USAGE_TOTAL_TOKENS,
|
198
|
+
response.usage.total_tokens,
|
199
|
+
)
|
200
|
+
span.set_attribute(SemanticConvention.GEN_AI_USAGE_COST, cost)
|
160
201
|
|
161
202
|
if capture_message_content:
|
162
203
|
span.add_event(
|
163
204
|
name=SemanticConvention.GEN_AI_CONTENT_PROMPT_EVENT,
|
164
205
|
attributes={
|
165
|
-
SemanticConvention.GEN_AI_CONTENT_PROMPT: kwargs.get(
|
206
|
+
SemanticConvention.GEN_AI_CONTENT_PROMPT: kwargs.get(
|
207
|
+
"message", ""
|
208
|
+
),
|
166
209
|
},
|
167
210
|
)
|
168
211
|
span.add_event(
|
169
212
|
name=SemanticConvention.GEN_AI_CONTENT_COMPLETION_EVENT,
|
170
213
|
# pylint: disable=line-too-long
|
171
214
|
attributes={
|
172
|
-
SemanticConvention.GEN_AI_CONTENT_COMPLETION: str(
|
215
|
+
SemanticConvention.GEN_AI_CONTENT_COMPLETION: str(
|
216
|
+
response.messages
|
217
|
+
),
|
173
218
|
},
|
174
219
|
)
|
175
220
|
|
@@ -5,15 +5,12 @@ import importlib.metadata
|
|
5
5
|
from opentelemetry.instrumentation.instrumentor import BaseInstrumentor
|
6
6
|
from wrapt import wrap_function_wrapper
|
7
7
|
|
8
|
-
from openlit.instrumentation.litellm.litellm import
|
9
|
-
|
10
|
-
)
|
11
|
-
from openlit.instrumentation.litellm.async_litellm import (
|
12
|
-
acompletion, aembedding
|
13
|
-
)
|
8
|
+
from openlit.instrumentation.litellm.litellm import completion, embedding
|
9
|
+
from openlit.instrumentation.litellm.async_litellm import acompletion, aembedding
|
14
10
|
|
15
11
|
_instruments = ("litellm >= 1.52.6",)
|
16
12
|
|
13
|
+
|
17
14
|
class LiteLLMInstrumentor(BaseInstrumentor):
|
18
15
|
"""
|
19
16
|
An instrumentor for LiteLLM client library.
|
@@ -36,32 +33,64 @@ class LiteLLMInstrumentor(BaseInstrumentor):
|
|
36
33
|
wrap_function_wrapper(
|
37
34
|
"litellm",
|
38
35
|
"completion",
|
39
|
-
completion(
|
40
|
-
|
36
|
+
completion(
|
37
|
+
version,
|
38
|
+
environment,
|
39
|
+
application_name,
|
40
|
+
tracer,
|
41
|
+
pricing_info,
|
42
|
+
capture_message_content,
|
43
|
+
metrics,
|
44
|
+
disable_metrics,
|
45
|
+
),
|
41
46
|
)
|
42
47
|
|
43
48
|
# Async chat completions
|
44
49
|
wrap_function_wrapper(
|
45
50
|
"litellm",
|
46
51
|
"acompletion",
|
47
|
-
acompletion(
|
48
|
-
|
52
|
+
acompletion(
|
53
|
+
version,
|
54
|
+
environment,
|
55
|
+
application_name,
|
56
|
+
tracer,
|
57
|
+
pricing_info,
|
58
|
+
capture_message_content,
|
59
|
+
metrics,
|
60
|
+
disable_metrics,
|
61
|
+
),
|
49
62
|
)
|
50
63
|
|
51
64
|
# Embeddings
|
52
65
|
wrap_function_wrapper(
|
53
66
|
"litellm",
|
54
67
|
"embedding",
|
55
|
-
embedding(
|
56
|
-
|
68
|
+
embedding(
|
69
|
+
version,
|
70
|
+
environment,
|
71
|
+
application_name,
|
72
|
+
tracer,
|
73
|
+
pricing_info,
|
74
|
+
capture_message_content,
|
75
|
+
metrics,
|
76
|
+
disable_metrics,
|
77
|
+
),
|
57
78
|
)
|
58
79
|
|
59
80
|
# Async embeddings
|
60
81
|
wrap_function_wrapper(
|
61
82
|
"litellm",
|
62
83
|
"aembedding",
|
63
|
-
aembedding(
|
64
|
-
|
84
|
+
aembedding(
|
85
|
+
version,
|
86
|
+
environment,
|
87
|
+
application_name,
|
88
|
+
tracer,
|
89
|
+
pricing_info,
|
90
|
+
capture_message_content,
|
91
|
+
metrics,
|
92
|
+
disable_metrics,
|
93
|
+
),
|
65
94
|
)
|
66
95
|
|
67
96
|
def _uninstrument(self, **kwargs):
|