langtrace-python-sdk 3.8.0__py3-none-any.whl → 3.8.2__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.
- examples/cleanlab_example/simple.py +18 -0
- langtrace_python_sdk/constants/instrumentation/common.py +2 -1
- langtrace_python_sdk/instrumentation/__init__.py +5 -6
- langtrace_python_sdk/instrumentation/agno/patch.py +142 -88
- langtrace_python_sdk/instrumentation/cleanlab/__init__.py +5 -0
- langtrace_python_sdk/instrumentation/cleanlab/instrumentation.py +62 -0
- langtrace_python_sdk/instrumentation/cleanlab/patch.py +75 -0
- langtrace_python_sdk/instrumentation/graphlit/patch.py +4 -5
- langtrace_python_sdk/langtrace.py +14 -57
- langtrace_python_sdk/version.py +1 -1
- {langtrace_python_sdk-3.8.0.dist-info → langtrace_python_sdk-3.8.2.dist-info}/METADATA +1 -1
- {langtrace_python_sdk-3.8.0.dist-info → langtrace_python_sdk-3.8.2.dist-info}/RECORD +15 -11
- {langtrace_python_sdk-3.8.0.dist-info → langtrace_python_sdk-3.8.2.dist-info}/WHEEL +0 -0
- {langtrace_python_sdk-3.8.0.dist-info → langtrace_python_sdk-3.8.2.dist-info}/entry_points.txt +0 -0
- {langtrace_python_sdk-3.8.0.dist-info → langtrace_python_sdk-3.8.2.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,18 @@
|
|
1
|
+
import os
|
2
|
+
|
3
|
+
from cleanlab_tlm import TLM
|
4
|
+
from dotenv import find_dotenv, load_dotenv
|
5
|
+
|
6
|
+
from langtrace_python_sdk import langtrace
|
7
|
+
|
8
|
+
_ = load_dotenv(find_dotenv())
|
9
|
+
|
10
|
+
langtrace.init()
|
11
|
+
|
12
|
+
api_key = os.getenv("CLEANLAB_API_KEY")
|
13
|
+
tlm = TLM(api_key=api_key, options={"log": ["explanation"], "model": "gpt-4o-mini"}) # GPT, Claude, etc
|
14
|
+
out = tlm.prompt("What's the third month of the year alphabetically?")
|
15
|
+
trustworthiness_score = tlm.get_trustworthiness_score("What's the first month of the year?", response="January")
|
16
|
+
|
17
|
+
print(out)
|
18
|
+
print(trustworthiness_score)
|
@@ -13,6 +13,8 @@ SERVICE_PROVIDERS = {
|
|
13
13
|
"ARCH": "Arch",
|
14
14
|
"AZURE": "Azure",
|
15
15
|
"CHROMA": "Chroma",
|
16
|
+
"CLEANLAB": "CleanLab",
|
17
|
+
"COHERE": "Cohere",
|
16
18
|
"CREWAI": "CrewAI",
|
17
19
|
"DEEPSEEK": "DeepSeek",
|
18
20
|
"DSPY": "DSPy",
|
@@ -25,7 +27,6 @@ SERVICE_PROVIDERS = {
|
|
25
27
|
"LLAMAINDEX": "LlamaIndex",
|
26
28
|
"OPENAI": "OpenAI",
|
27
29
|
"PINECONE": "Pinecone",
|
28
|
-
"COHERE": "Cohere",
|
29
30
|
"PPLX": "Perplexity",
|
30
31
|
"QDRANT": "Qdrant",
|
31
32
|
"WEAVIATE": "Weaviate",
|
@@ -1,8 +1,10 @@
|
|
1
|
+
from .agno import AgnoInstrumentation
|
1
2
|
from .anthropic import AnthropicInstrumentation
|
2
3
|
from .autogen import AutogenInstrumentation
|
3
4
|
from .aws_bedrock import AWSBedrockInstrumentation
|
4
5
|
from .cerebras import CerebrasInstrumentation
|
5
6
|
from .chroma import ChromaInstrumentation
|
7
|
+
from .cleanlab import CleanLabInstrumentation
|
6
8
|
from .cohere import CohereInstrumentation
|
7
9
|
from .crewai import CrewAIInstrumentation
|
8
10
|
from .crewai_tools import CrewaiToolsInstrumentation
|
@@ -10,6 +12,7 @@ from .dspy import DspyInstrumentation
|
|
10
12
|
from .embedchain import EmbedchainInstrumentation
|
11
13
|
from .gemini import GeminiInstrumentation
|
12
14
|
from .google_genai import GoogleGenaiInstrumentation
|
15
|
+
from .graphlit import GraphlitInstrumentation
|
13
16
|
from .groq import GroqInstrumentation
|
14
17
|
from .langchain import LangchainInstrumentation
|
15
18
|
from .langchain_community import LangchainCommunityInstrumentation
|
@@ -21,17 +24,12 @@ from .milvus import MilvusInstrumentation
|
|
21
24
|
from .mistral import MistralInstrumentation
|
22
25
|
from .ollama import OllamaInstrumentor
|
23
26
|
from .openai import OpenAIInstrumentation
|
27
|
+
from .phidata import PhiDataInstrumentation
|
24
28
|
from .pinecone import PineconeInstrumentation
|
25
29
|
from .pymongo import PyMongoInstrumentation
|
26
30
|
from .qdrant import QdrantInstrumentation
|
27
31
|
from .vertexai import VertexAIInstrumentation
|
28
32
|
from .weaviate import WeaviateInstrumentation
|
29
|
-
from .cerebras import CerebrasInstrumentation
|
30
|
-
from .milvus import MilvusInstrumentation
|
31
|
-
from .google_genai import GoogleGenaiInstrumentation
|
32
|
-
from .graphlit import GraphlitInstrumentation
|
33
|
-
from .phidata import PhiDataInstrumentation
|
34
|
-
from .agno import AgnoInstrumentation
|
35
33
|
|
36
34
|
__all__ = [
|
37
35
|
"AnthropicInstrumentation",
|
@@ -65,4 +63,5 @@ __all__ = [
|
|
65
63
|
"GraphlitInstrumentation",
|
66
64
|
"PhiDataInstrumentation",
|
67
65
|
"AgnoInstrumentation",
|
66
|
+
"CleanLabInstrumentation",
|
68
67
|
]
|
@@ -15,26 +15,46 @@ from langtrace_python_sdk.utils import set_span_attribute
|
|
15
15
|
from langtrace_python_sdk.utils.llm import get_span_name, set_span_attributes
|
16
16
|
from langtrace_python_sdk.utils.misc import serialize_args, serialize_kwargs
|
17
17
|
|
18
|
+
def _safe_serialize(obj):
|
19
|
+
"""Safely serialize objects that might not be JSON serializable"""
|
20
|
+
if hasattr(obj, 'to_dict'):
|
21
|
+
return obj.to_dict()
|
22
|
+
elif hasattr(obj, '__dict__'):
|
23
|
+
return {k: _safe_serialize(v) for k, v in obj.__dict__.items() if not k.startswith('_')}
|
24
|
+
elif isinstance(obj, dict):
|
25
|
+
return {k: _safe_serialize(v) for k, v in obj.items()}
|
26
|
+
elif isinstance(obj, (list, tuple)):
|
27
|
+
return [_safe_serialize(i) for i in obj]
|
28
|
+
return str(obj)
|
29
|
+
|
30
|
+
def _safe_json_dumps(obj):
|
31
|
+
"""Safely dump an object to JSON, handling non-serializable types"""
|
32
|
+
try:
|
33
|
+
return json.dumps(obj)
|
34
|
+
except (TypeError, ValueError):
|
35
|
+
return json.dumps(_safe_serialize(obj))
|
36
|
+
|
18
37
|
def _extract_metrics(metrics: Dict[str, Any]) -> Dict[str, Any]:
|
19
38
|
"""Helper function to extract and format metrics"""
|
20
|
-
|
39
|
+
if not metrics:
|
40
|
+
return {}
|
41
|
+
|
42
|
+
if hasattr(metrics, 'to_dict'):
|
43
|
+
metrics = metrics.to_dict()
|
44
|
+
elif hasattr(metrics, '__dict__'):
|
45
|
+
metrics = {k: v for k, v in metrics.__dict__.items() if not k.startswith('_')}
|
21
46
|
|
22
|
-
|
47
|
+
formatted_metrics = {}
|
48
|
+
|
23
49
|
for key in ['time', 'time_to_first_token', 'input_tokens', 'output_tokens',
|
24
|
-
'prompt_tokens', 'completion_tokens', 'total_tokens'
|
50
|
+
'prompt_tokens', 'completion_tokens', 'total_tokens',
|
51
|
+
'prompt_tokens_details', 'completion_tokens_details', 'tool_call_times']:
|
25
52
|
if key in metrics:
|
26
53
|
formatted_metrics[key] = metrics[key]
|
27
|
-
|
28
|
-
# Extract nested metric details if present
|
29
|
-
if 'prompt_tokens_details' in metrics:
|
30
|
-
formatted_metrics['prompt_tokens_details'] = metrics['prompt_tokens_details']
|
31
|
-
if 'completion_tokens_details' in metrics:
|
32
|
-
formatted_metrics['completion_tokens_details'] = metrics['completion_tokens_details']
|
33
|
-
if 'tool_call_times' in metrics:
|
34
|
-
formatted_metrics['tool_call_times'] = metrics['tool_call_times']
|
35
|
-
|
54
|
+
|
36
55
|
return formatted_metrics
|
37
56
|
|
57
|
+
|
38
58
|
def patch_memory(operation_name, version, tracer: Tracer):
|
39
59
|
def traced_method(wrapped, instance, args, kwargs):
|
40
60
|
service_provider = SERVICE_PROVIDERS["AGNO"]
|
@@ -110,86 +130,120 @@ def patch_agent(operation_name, version, tracer: Tracer):
|
|
110
130
|
try:
|
111
131
|
set_span_attributes(span, attributes)
|
112
132
|
AgnoSpanAttributes(span=span, instance=instance)
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
continue
|
125
|
-
|
126
|
-
if not response_metadata:
|
127
|
-
response_metadata = {
|
128
|
-
"run_id": response.run_id,
|
129
|
-
"agent_id": response.agent_id,
|
130
|
-
"session_id": response.session_id,
|
131
|
-
"model": response.model,
|
132
|
-
"content_type": response.content_type,
|
133
|
-
}
|
134
|
-
for key, value in response_metadata.items():
|
135
|
-
if value is not None:
|
136
|
-
set_span_attribute(span, f"agno.agent.{key}", str(value))
|
137
|
-
|
138
|
-
if response.content:
|
139
|
-
accumulated_content += response.content
|
140
|
-
set_span_attribute(span, "agno.agent.response", accumulated_content)
|
141
|
-
|
142
|
-
if response.messages:
|
143
|
-
for msg in response.messages:
|
144
|
-
if msg.tool_calls:
|
145
|
-
for tool_call in msg.tool_calls:
|
146
|
-
tool_id = tool_call.get('id')
|
147
|
-
if tool_id and tool_id not in seen_tool_calls:
|
148
|
-
seen_tool_calls.add(tool_id)
|
149
|
-
tool_info = {
|
150
|
-
'id': tool_id,
|
151
|
-
'name': tool_call.get('function', {}).get('name'),
|
152
|
-
'arguments': tool_call.get('function', {}).get('arguments'),
|
153
|
-
'start_time': msg.created_at,
|
154
|
-
}
|
155
|
-
current_tool_call = tool_info
|
156
|
-
set_span_attribute(span, f"agno.agent.tool_call.{tool_id}", json.dumps(tool_info))
|
157
|
-
|
158
|
-
if msg.metrics:
|
159
|
-
metrics = _extract_metrics(msg.metrics)
|
160
|
-
role_prefix = f"agno.agent.metrics.{msg.role}"
|
161
|
-
for key, value in metrics.items():
|
162
|
-
set_span_attribute(span, f"{role_prefix}.{key}", str(value))
|
163
|
-
|
164
|
-
if response.tools:
|
165
|
-
for tool in response.tools:
|
166
|
-
tool_id = tool.get('tool_call_id')
|
167
|
-
if tool_id and current_tool_call and current_tool_call['id'] == tool_id:
|
168
|
-
tool_result = {
|
169
|
-
**current_tool_call,
|
170
|
-
'result': tool.get('content'),
|
171
|
-
'error': tool.get('tool_call_error'),
|
172
|
-
'end_time': tool.get('created_at'),
|
173
|
-
'metrics': tool.get('metrics'),
|
174
|
-
}
|
175
|
-
set_span_attribute(span, f"agno.agent.tool_call.{tool_id}", json.dumps(tool_result))
|
176
|
-
current_tool_call = None
|
177
|
-
|
178
|
-
yield response
|
179
|
-
|
180
|
-
except Exception as err:
|
181
|
-
span.record_exception(err)
|
182
|
-
span.set_status(Status(StatusCode.ERROR, str(err)))
|
183
|
-
raise
|
184
|
-
finally:
|
185
|
-
span.set_status(Status(StatusCode.OK))
|
186
|
-
if len(seen_tool_calls) > 0:
|
187
|
-
span.set_attribute("agno.agent.total_tool_calls", len(seen_tool_calls))
|
133
|
+
is_streaming = kwargs.get('stream', False)
|
134
|
+
result = wrapped(*args, **kwargs)
|
135
|
+
|
136
|
+
if not is_streaming and not operation_name.startswith('Agent._'):
|
137
|
+
if hasattr(result, 'to_dict'):
|
138
|
+
_process_response(span, result)
|
139
|
+
return result
|
140
|
+
|
141
|
+
# Handle streaming (generator) case
|
142
|
+
return _process_generator(span, result)
|
143
|
+
|
188
144
|
except Exception as err:
|
189
145
|
span.record_exception(err)
|
190
146
|
span.set_status(Status(StatusCode.ERROR, str(err)))
|
191
147
|
raise
|
192
148
|
|
149
|
+
# Helper function to process a generator
|
150
|
+
def _process_generator(span, result_generator):
|
151
|
+
accumulated_content = ""
|
152
|
+
current_tool_call = None
|
153
|
+
response_metadata = None
|
154
|
+
seen_tool_calls = set()
|
155
|
+
|
156
|
+
try:
|
157
|
+
for response in result_generator:
|
158
|
+
if not hasattr(response, 'to_dict'):
|
159
|
+
yield response
|
160
|
+
continue
|
161
|
+
|
162
|
+
_process_response(span, response,
|
163
|
+
accumulated_content=accumulated_content,
|
164
|
+
current_tool_call=current_tool_call,
|
165
|
+
response_metadata=response_metadata,
|
166
|
+
seen_tool_calls=seen_tool_calls)
|
167
|
+
|
168
|
+
if response.content:
|
169
|
+
accumulated_content += response.content
|
170
|
+
|
171
|
+
yield response
|
172
|
+
|
173
|
+
except Exception as err:
|
174
|
+
span.record_exception(err)
|
175
|
+
span.set_status(Status(StatusCode.ERROR, str(err)))
|
176
|
+
raise
|
177
|
+
finally:
|
178
|
+
span.set_status(Status(StatusCode.OK))
|
179
|
+
if len(seen_tool_calls) > 0:
|
180
|
+
span.set_attribute("agno.agent.total_tool_calls", len(seen_tool_calls))
|
181
|
+
|
182
|
+
def _process_response(span, response, accumulated_content="", current_tool_call=None,
|
183
|
+
response_metadata=None, seen_tool_calls=set()):
|
184
|
+
if not response_metadata:
|
185
|
+
response_metadata = {
|
186
|
+
"run_id": response.run_id,
|
187
|
+
"agent_id": response.agent_id,
|
188
|
+
"session_id": response.session_id,
|
189
|
+
"model": response.model,
|
190
|
+
"content_type": response.content_type,
|
191
|
+
}
|
192
|
+
for key, value in response_metadata.items():
|
193
|
+
if value is not None:
|
194
|
+
set_span_attribute(span, f"agno.agent.{key}", str(value))
|
195
|
+
|
196
|
+
if response.content:
|
197
|
+
if accumulated_content:
|
198
|
+
accumulated_content += response.content
|
199
|
+
else:
|
200
|
+
accumulated_content = response.content
|
201
|
+
set_span_attribute(span, "agno.agent.response", accumulated_content)
|
202
|
+
|
203
|
+
if response.messages:
|
204
|
+
for msg in response.messages:
|
205
|
+
if msg.tool_calls:
|
206
|
+
for tool_call in msg.tool_calls:
|
207
|
+
tool_id = tool_call.get('id')
|
208
|
+
if tool_id and tool_id not in seen_tool_calls:
|
209
|
+
seen_tool_calls.add(tool_id)
|
210
|
+
tool_info = {
|
211
|
+
'id': tool_id,
|
212
|
+
'name': tool_call.get('function', {}).get('name'),
|
213
|
+
'arguments': tool_call.get('function', {}).get('arguments'),
|
214
|
+
'start_time': msg.created_at,
|
215
|
+
}
|
216
|
+
current_tool_call = tool_info
|
217
|
+
set_span_attribute(span, f"agno.agent.tool_call.{tool_id}", _safe_json_dumps(tool_info))
|
218
|
+
|
219
|
+
if msg.metrics:
|
220
|
+
metrics = _extract_metrics(msg.metrics)
|
221
|
+
role_prefix = f"agno.agent.metrics.{msg.role}"
|
222
|
+
for key, value in metrics.items():
|
223
|
+
set_span_attribute(span, f"{role_prefix}.{key}", str(value))
|
224
|
+
|
225
|
+
if response.tools:
|
226
|
+
for tool in response.tools:
|
227
|
+
tool_id = tool.get('tool_call_id')
|
228
|
+
if tool_id and current_tool_call and current_tool_call['id'] == tool_id:
|
229
|
+
tool_result = {
|
230
|
+
**current_tool_call,
|
231
|
+
'result': tool.get('content'),
|
232
|
+
'error': tool.get('tool_call_error'),
|
233
|
+
'end_time': tool.get('created_at'),
|
234
|
+
'metrics': tool.get('metrics'),
|
235
|
+
}
|
236
|
+
set_span_attribute(span, f"agno.agent.tool_call.{tool_id}", _safe_json_dumps(tool_result))
|
237
|
+
current_tool_call = None
|
238
|
+
|
239
|
+
if response.metrics:
|
240
|
+
metrics = _extract_metrics(response.metrics)
|
241
|
+
for key, value in metrics.items():
|
242
|
+
set_span_attribute(span, f"agno.agent.metrics.{key}", str(value))
|
243
|
+
|
244
|
+
if len(seen_tool_calls) > 0:
|
245
|
+
span.set_attribute("agno.agent.total_tool_calls", len(seen_tool_calls))
|
246
|
+
|
193
247
|
return traced_method
|
194
248
|
|
195
249
|
class AgnoSpanAttributes:
|
@@ -238,7 +292,7 @@ class AgnoSpanAttributes:
|
|
238
292
|
|
239
293
|
if hasattr(self.instance.model, 'metrics') and self.instance.model.metrics:
|
240
294
|
metrics = _extract_metrics(self.instance.model.metrics)
|
241
|
-
set_span_attribute(self.span, "agno.agent.model.metrics",
|
295
|
+
set_span_attribute(self.span, "agno.agent.model.metrics", _safe_json_dumps(metrics))
|
242
296
|
|
243
297
|
if self.instance.tools:
|
244
298
|
tool_list = []
|
@@ -0,0 +1,62 @@
|
|
1
|
+
"""
|
2
|
+
Copyright (c) 2025 Scale3 Labs
|
3
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
you may not use this file except in compliance with the License.
|
5
|
+
You may obtain a copy of the License at
|
6
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
7
|
+
Unless required by applicable law or agreed to in writing, software
|
8
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
9
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
10
|
+
See the License for the specific language governing permissions and
|
11
|
+
limitations under the License.
|
12
|
+
"""
|
13
|
+
|
14
|
+
import importlib.metadata
|
15
|
+
import logging
|
16
|
+
from typing import Any, Collection, Optional
|
17
|
+
|
18
|
+
from opentelemetry.instrumentation.instrumentor import BaseInstrumentor
|
19
|
+
from opentelemetry.trace import TracerProvider, get_tracer
|
20
|
+
from wrapt import wrap_function_wrapper
|
21
|
+
|
22
|
+
from langtrace_python_sdk.instrumentation.cleanlab.patch import generic_patch
|
23
|
+
|
24
|
+
logging.basicConfig(level=logging.FATAL)
|
25
|
+
|
26
|
+
|
27
|
+
class CleanLabInstrumentation(BaseInstrumentor): # type: ignore
|
28
|
+
|
29
|
+
def instrumentation_dependencies(self) -> Collection[str]:
|
30
|
+
return ["cleanlab-tlm >= 1.0.7", "trace-attributes >= 4.0.5"]
|
31
|
+
|
32
|
+
def _instrument(self, **kwargs: Any) -> None:
|
33
|
+
tracer_provider: Optional[TracerProvider] = kwargs.get("tracer_provider")
|
34
|
+
tracer = get_tracer(__name__, "", tracer_provider)
|
35
|
+
version: str = importlib.metadata.version("cleanlab_tlm")
|
36
|
+
|
37
|
+
wrap_function_wrapper(
|
38
|
+
"cleanlab_tlm.tlm",
|
39
|
+
"TLM.prompt",
|
40
|
+
generic_patch(version, tracer),
|
41
|
+
)
|
42
|
+
|
43
|
+
wrap_function_wrapper(
|
44
|
+
"cleanlab_tlm.tlm",
|
45
|
+
"TLM.get_trustworthiness_score",
|
46
|
+
generic_patch(version, tracer),
|
47
|
+
)
|
48
|
+
|
49
|
+
wrap_function_wrapper(
|
50
|
+
"cleanlab_tlm.tlm",
|
51
|
+
"TLM.try_prompt",
|
52
|
+
generic_patch(version, tracer),
|
53
|
+
)
|
54
|
+
|
55
|
+
wrap_function_wrapper(
|
56
|
+
"cleanlab_tlm.tlm",
|
57
|
+
"TLM.try_get_trustworthiness_score",
|
58
|
+
generic_patch(version, tracer),
|
59
|
+
)
|
60
|
+
|
61
|
+
def _uninstrument(self, **kwargs: Any) -> None:
|
62
|
+
pass
|
@@ -0,0 +1,75 @@
|
|
1
|
+
import json
|
2
|
+
from typing import Any, Callable, List
|
3
|
+
|
4
|
+
from importlib_metadata import version as v
|
5
|
+
from langtrace.trace_attributes import FrameworkSpanAttributes
|
6
|
+
from opentelemetry import baggage
|
7
|
+
from opentelemetry.trace import SpanKind, Tracer
|
8
|
+
from opentelemetry.trace.status import Status, StatusCode
|
9
|
+
|
10
|
+
from langtrace_python_sdk.constants import LANGTRACE_SDK_NAME
|
11
|
+
from langtrace_python_sdk.constants.instrumentation.common import (
|
12
|
+
LANGTRACE_ADDITIONAL_SPAN_ATTRIBUTES_KEY, SERVICE_PROVIDERS)
|
13
|
+
from langtrace_python_sdk.instrumentation.openai.types import \
|
14
|
+
ChatCompletionsCreateKwargs
|
15
|
+
from langtrace_python_sdk.utils.llm import set_span_attributes
|
16
|
+
from langtrace_python_sdk.utils.misc import serialize_args, serialize_kwargs
|
17
|
+
|
18
|
+
|
19
|
+
def generic_patch(version: str, tracer: Tracer) -> Callable:
|
20
|
+
"""Wrap the `prompt` method of the `TLM` class to trace it."""
|
21
|
+
|
22
|
+
def traced_method(
|
23
|
+
wrapped: Callable,
|
24
|
+
instance: Any,
|
25
|
+
args: List[Any],
|
26
|
+
kwargs: ChatCompletionsCreateKwargs,
|
27
|
+
) -> Any:
|
28
|
+
service_provider = SERVICE_PROVIDERS["CLEANLAB"]
|
29
|
+
extra_attributes = baggage.get_baggage(LANGTRACE_ADDITIONAL_SPAN_ATTRIBUTES_KEY)
|
30
|
+
span_attributes = {
|
31
|
+
"langtrace.sdk.name": "langtrace-python-sdk",
|
32
|
+
"langtrace.service.name": service_provider,
|
33
|
+
"langtrace.service.type": "framework",
|
34
|
+
"langtrace.service.version": version,
|
35
|
+
"langtrace.version": v(LANGTRACE_SDK_NAME),
|
36
|
+
**(extra_attributes if extra_attributes is not None else {}),
|
37
|
+
}
|
38
|
+
|
39
|
+
span_attributes["tlm.metadata"] = serialize_kwargs(**kwargs)
|
40
|
+
span_attributes["tlm.inputs"] = serialize_args(*args)
|
41
|
+
|
42
|
+
attributes = FrameworkSpanAttributes(**span_attributes)
|
43
|
+
|
44
|
+
with tracer.start_as_current_span(
|
45
|
+
name=f"tlm.{wrapped.__name__}", kind=SpanKind.CLIENT
|
46
|
+
) as span:
|
47
|
+
try:
|
48
|
+
set_span_attributes(span, attributes)
|
49
|
+
result = wrapped(*args, **kwargs)
|
50
|
+
if result:
|
51
|
+
# Handle result serialization based on its type
|
52
|
+
if hasattr(result, 'model_dump_json'):
|
53
|
+
# For Pydantic models
|
54
|
+
result_json = json.loads(result.model_dump_json())
|
55
|
+
elif isinstance(result, dict):
|
56
|
+
# For dictionary results
|
57
|
+
result_json = result
|
58
|
+
else:
|
59
|
+
# For other types, try to convert to dict or use string representation
|
60
|
+
try:
|
61
|
+
result_json = json.loads(json.dumps(result, default=str))
|
62
|
+
except Exception: # pylint: disable=W0702, W0718
|
63
|
+
result_json = str(result)
|
64
|
+
|
65
|
+
span.set_attribute("tlm.result", str(result_json))
|
66
|
+
span.set_status(Status(StatusCode.OK))
|
67
|
+
|
68
|
+
return result
|
69
|
+
|
70
|
+
except Exception as err:
|
71
|
+
span.record_exception(err)
|
72
|
+
span.set_status(Status(StatusCode.ERROR, str(err)))
|
73
|
+
raise
|
74
|
+
|
75
|
+
return traced_method
|
@@ -1,4 +1,5 @@
|
|
1
1
|
import json
|
2
|
+
|
2
3
|
from importlib_metadata import version as v
|
3
4
|
from langtrace.trace_attributes import FrameworkSpanAttributes
|
4
5
|
from opentelemetry import baggage
|
@@ -7,9 +8,7 @@ from opentelemetry.trace.status import Status, StatusCode
|
|
7
8
|
|
8
9
|
from langtrace_python_sdk.constants import LANGTRACE_SDK_NAME
|
9
10
|
from langtrace_python_sdk.constants.instrumentation.common import (
|
10
|
-
LANGTRACE_ADDITIONAL_SPAN_ATTRIBUTES_KEY,
|
11
|
-
SERVICE_PROVIDERS,
|
12
|
-
)
|
11
|
+
LANGTRACE_ADDITIONAL_SPAN_ATTRIBUTES_KEY, SERVICE_PROVIDERS)
|
13
12
|
from langtrace_python_sdk.utils.llm import set_span_attributes
|
14
13
|
from langtrace_python_sdk.utils.misc import serialize_args, serialize_kwargs
|
15
14
|
|
@@ -27,8 +26,8 @@ def patch_graphlit_operation(operation_name, version, tracer: Tracer):
|
|
27
26
|
**(extra_attributes if extra_attributes is not None else {}),
|
28
27
|
}
|
29
28
|
|
30
|
-
span_attributes["
|
31
|
-
span_attributes["
|
29
|
+
span_attributes["graphlit.metadata"] = serialize_kwargs(**kwargs)
|
30
|
+
span_attributes["graphlit.inputs"] = serialize_args(*args)
|
32
31
|
|
33
32
|
attributes = FrameworkSpanAttributes(**span_attributes)
|
34
33
|
|
@@ -29,54 +29,9 @@ from opentelemetry.exporter.otlp.proto.http.trace_exporter import \
|
|
29
29
|
from opentelemetry.instrumentation.sqlalchemy import SQLAlchemyInstrumentor
|
30
30
|
from opentelemetry.sdk.resources import SERVICE_NAME, Resource
|
31
31
|
from opentelemetry.sdk.trace import TracerProvider
|
32
|
-
from opentelemetry.sdk.trace.export import (
|
33
|
-
|
34
|
-
|
35
|
-
SimpleSpanProcessor,
|
36
|
-
)
|
37
|
-
|
38
|
-
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import (
|
39
|
-
OTLPSpanExporter as GRPCExporter,
|
40
|
-
)
|
41
|
-
from opentelemetry.exporter.otlp.proto.http.trace_exporter import (
|
42
|
-
OTLPSpanExporter as HTTPExporter,
|
43
|
-
)
|
44
|
-
from langtrace_python_sdk.constants.exporter.langtrace_exporter import (
|
45
|
-
LANGTRACE_REMOTE_URL,
|
46
|
-
LANGTRACE_SESSION_ID_HEADER,
|
47
|
-
)
|
48
|
-
from langtrace_python_sdk.instrumentation import (
|
49
|
-
AnthropicInstrumentation,
|
50
|
-
ChromaInstrumentation,
|
51
|
-
CohereInstrumentation,
|
52
|
-
CrewAIInstrumentation,
|
53
|
-
DspyInstrumentation,
|
54
|
-
EmbedchainInstrumentation,
|
55
|
-
GeminiInstrumentation,
|
56
|
-
GroqInstrumentation,
|
57
|
-
LangchainCommunityInstrumentation,
|
58
|
-
LangchainCoreInstrumentation,
|
59
|
-
LangchainInstrumentation,
|
60
|
-
LanggraphInstrumentation,
|
61
|
-
LiteLLMInstrumentation,
|
62
|
-
LlamaindexInstrumentation,
|
63
|
-
MistralInstrumentation,
|
64
|
-
AWSBedrockInstrumentation,
|
65
|
-
OllamaInstrumentor,
|
66
|
-
OpenAIInstrumentation,
|
67
|
-
PineconeInstrumentation,
|
68
|
-
QdrantInstrumentation,
|
69
|
-
AutogenInstrumentation,
|
70
|
-
VertexAIInstrumentation,
|
71
|
-
WeaviateInstrumentation,
|
72
|
-
PyMongoInstrumentation,
|
73
|
-
CerebrasInstrumentation,
|
74
|
-
MilvusInstrumentation,
|
75
|
-
GoogleGenaiInstrumentation,
|
76
|
-
GraphlitInstrumentation,
|
77
|
-
PhiDataInstrumentation,
|
78
|
-
AgnoInstrumentation,
|
79
|
-
)
|
32
|
+
from opentelemetry.sdk.trace.export import (BatchSpanProcessor,
|
33
|
+
ConsoleSpanExporter,
|
34
|
+
SimpleSpanProcessor)
|
80
35
|
from opentelemetry.util.re import parse_env_headers
|
81
36
|
from sentry_sdk.types import Event, Hint
|
82
37
|
|
@@ -86,17 +41,18 @@ from langtrace_python_sdk.constants.exporter.langtrace_exporter import (
|
|
86
41
|
from langtrace_python_sdk.extensions.langtrace_exporter import \
|
87
42
|
LangTraceExporter
|
88
43
|
from langtrace_python_sdk.instrumentation import (
|
89
|
-
AnthropicInstrumentation, AutogenInstrumentation,
|
44
|
+
AgnoInstrumentation, AnthropicInstrumentation, AutogenInstrumentation,
|
90
45
|
AWSBedrockInstrumentation, CerebrasInstrumentation, ChromaInstrumentation,
|
91
|
-
CohereInstrumentation, CrewAIInstrumentation,
|
92
|
-
DspyInstrumentation, EmbedchainInstrumentation,
|
93
|
-
GoogleGenaiInstrumentation,
|
94
|
-
|
95
|
-
|
46
|
+
CleanLabInstrumentation, CohereInstrumentation, CrewAIInstrumentation,
|
47
|
+
CrewaiToolsInstrumentation, DspyInstrumentation, EmbedchainInstrumentation,
|
48
|
+
GeminiInstrumentation, GoogleGenaiInstrumentation, GraphlitInstrumentation,
|
49
|
+
GroqInstrumentation, LangchainCommunityInstrumentation,
|
50
|
+
LangchainCoreInstrumentation, LangchainInstrumentation,
|
51
|
+
LanggraphInstrumentation, LiteLLMInstrumentation,
|
96
52
|
LlamaindexInstrumentation, MilvusInstrumentation, MistralInstrumentation,
|
97
|
-
OllamaInstrumentor, OpenAIInstrumentation,
|
98
|
-
PyMongoInstrumentation, QdrantInstrumentation,
|
99
|
-
WeaviateInstrumentation)
|
53
|
+
OllamaInstrumentor, OpenAIInstrumentation, PhiDataInstrumentation,
|
54
|
+
PineconeInstrumentation, PyMongoInstrumentation, QdrantInstrumentation,
|
55
|
+
VertexAIInstrumentation, WeaviateInstrumentation)
|
100
56
|
from langtrace_python_sdk.types import (DisableInstrumentations,
|
101
57
|
InstrumentationMethods)
|
102
58
|
from langtrace_python_sdk.utils import (check_if_sdk_is_outdated,
|
@@ -334,6 +290,7 @@ def init(
|
|
334
290
|
"cerebras-cloud-sdk": CerebrasInstrumentation(),
|
335
291
|
"pymilvus": MilvusInstrumentation(),
|
336
292
|
"crewai-tools": CrewaiToolsInstrumentation(),
|
293
|
+
"cleanlab-tlm": CleanLabInstrumentation(),
|
337
294
|
}
|
338
295
|
|
339
296
|
init_instrumentations(config.disable_instrumentations, all_instrumentations)
|
langtrace_python_sdk/version.py
CHANGED
@@ -1 +1 @@
|
|
1
|
-
__version__ = "3.8.
|
1
|
+
__version__ = "3.8.2"
|
@@ -11,6 +11,7 @@ examples/cerebras_example/__init__.py,sha256=ydfNi0DjFMGVcfo79XVG3VEbzIrHo5wYBgS
|
|
11
11
|
examples/cerebras_example/main.py,sha256=QrzQLTEr0dkrrPrlOPqwXkeeGU4dwc8tPR4LhHPOQ3k,6573
|
12
12
|
examples/chroma_example/__init__.py,sha256=Mrf8KptW1hhzu6WDdRRTxbaB-0kM7x5u-Goc_zR7G5c,203
|
13
13
|
examples/chroma_example/basic.py,sha256=oO7-__8HptnFXLVKbnPgoz02yM-CAPi721xsbUb_gYg,868
|
14
|
+
examples/cleanlab_example/simple.py,sha256=YxKzHikcsTlwWVBtRzhgC35j_XsCGDPgTjzMQQ3PMjQ,548
|
14
15
|
examples/cohere_example/__init__.py,sha256=7Sa0MEQrRU5gBZg31Ao6kXGDC9raHoLU0BxqVWAX8b8,736
|
15
16
|
examples/cohere_example/chat.py,sha256=A1ZSkkPPOj3h27VSSa_o_Thabz08ZUzUgTVgAG0pgcA,901
|
16
17
|
examples/cohere_example/chat_stream.py,sha256=BvhUgBEuyMhyzRZ_2i_SBvO9Ndf0b7-aRDyO399RyFE,664
|
@@ -114,8 +115,8 @@ examples/vertexai_example/main.py,sha256=gndId5X5ksD-ycxnAWMdEqIDbLc3kz5Vt8vm4YP
|
|
114
115
|
examples/weaviate_example/__init__.py,sha256=8JMDBsRSEV10HfTd-YC7xb4txBjD3la56snk-Bbg2Kw,618
|
115
116
|
examples/weaviate_example/query_text.py,sha256=wPHQTc_58kPoKTZMygVjTj-2ZcdrIuaausJfMxNQnQc,127162
|
116
117
|
langtrace_python_sdk/__init__.py,sha256=VZM6i71NR7pBQK6XvJWRelknuTYUhqwqE7PlicKa5Wg,1166
|
117
|
-
langtrace_python_sdk/langtrace.py,sha256=
|
118
|
-
langtrace_python_sdk/version.py,sha256=
|
118
|
+
langtrace_python_sdk/langtrace.py,sha256=L0ktJXsGjvKS0dc6kWGCOUoNsGTERLEmd-1QfzDppq8,13706
|
119
|
+
langtrace_python_sdk/version.py,sha256=RbOxThvu1HcxD17bsEp4gU_z66QQb8i2Fh75JKkh0is,22
|
119
120
|
langtrace_python_sdk/constants/__init__.py,sha256=3CNYkWMdd1DrkGqzLUgNZXjdAlM6UFMlf_F-odAToyc,146
|
120
121
|
langtrace_python_sdk/constants/exporter/langtrace_exporter.py,sha256=EVCrouYCpY98f0KSaKr4PzNxPULTZZO6dSA_crEOyJU,106
|
121
122
|
langtrace_python_sdk/constants/instrumentation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -123,7 +124,7 @@ langtrace_python_sdk/constants/instrumentation/anthropic.py,sha256=YX3llt3zwDY6X
|
|
123
124
|
langtrace_python_sdk/constants/instrumentation/aws_bedrock.py,sha256=QwKtO4NBarOZoGkt5cFCcpxAw3zvZxcMMWBbzPPGv-g,422
|
124
125
|
langtrace_python_sdk/constants/instrumentation/chroma.py,sha256=hiPGYdHS0Yj4Kh3eaYBbuCAl_swqIygu80yFqkOgdak,955
|
125
126
|
langtrace_python_sdk/constants/instrumentation/cohere.py,sha256=9yD133VdrYZ5BoJR4nJHlj67gHEImB9-KsD-NkzHW1I,1159
|
126
|
-
langtrace_python_sdk/constants/instrumentation/common.py,sha256=
|
127
|
+
langtrace_python_sdk/constants/instrumentation/common.py,sha256=DxcrwO9iI4Q1-ECTAbfFzY6vjU3K9kyoU54W-I2Ebs0,1326
|
127
128
|
langtrace_python_sdk/constants/instrumentation/embedchain.py,sha256=HodCJvaFjILoOG50OwFObxfVxt_8VUaIAIqvgoN3tzo,278
|
128
129
|
langtrace_python_sdk/constants/instrumentation/gemini.py,sha256=UAmfgg9FM7uNeOCdPfWlir6OIH-8BoxFGPRpdBd9ZZs,358
|
129
130
|
langtrace_python_sdk/constants/instrumentation/groq.py,sha256=VFXmIl4aqGY_fS0PAmjPj_Qm7Tibxbx7Ur_e7rQpqXc,134
|
@@ -140,10 +141,10 @@ langtrace_python_sdk/constants/instrumentation/weaviate.py,sha256=gtv-JBxvNGClEM
|
|
140
141
|
langtrace_python_sdk/extensions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
141
142
|
langtrace_python_sdk/extensions/langtrace_exporter.py,sha256=ckd8dMmY6h2oxE04p1JFLwUB5PSJX_Cy4eDFEM6aj4Y,6605
|
142
143
|
langtrace_python_sdk/extensions/langtrace_filesystem.py,sha256=34fZutG28EJ66l67OvTGsydAH3ZpXgikdE7hVLqBpG4,7863
|
143
|
-
langtrace_python_sdk/instrumentation/__init__.py,sha256=
|
144
|
+
langtrace_python_sdk/instrumentation/__init__.py,sha256=UOtU6nT-ZT-ZvHzOgPNhG_IooMe5jU8lzgdoDCHpeBc,2469
|
144
145
|
langtrace_python_sdk/instrumentation/agno/__init__.py,sha256=95fn4oA-CHB0mxc6KnVB20KSbXGl_ZZr9n99EEaXzrY,91
|
145
146
|
langtrace_python_sdk/instrumentation/agno/instrumentation.py,sha256=CrwHzkzLpdo2m2nBHE69d8MIFMxZuvTsT1LTxqlTWV0,2664
|
146
|
-
langtrace_python_sdk/instrumentation/agno/patch.py,sha256=
|
147
|
+
langtrace_python_sdk/instrumentation/agno/patch.py,sha256=tbMscAxsZuo4MAEUQ9tUPiluyj8RRcksF7sYU-v2knM,13399
|
147
148
|
langtrace_python_sdk/instrumentation/anthropic/__init__.py,sha256=donrurJAGYlxrSRA3BIf76jGeUcAx9Tq8CVpah68S0Y,101
|
148
149
|
langtrace_python_sdk/instrumentation/anthropic/instrumentation.py,sha256=ndXdruI0BG7n75rsuEpKjfzePxrZxg40gZ39ONmD_v4,1845
|
149
150
|
langtrace_python_sdk/instrumentation/anthropic/patch.py,sha256=ztPN4VZujoxYOKhTbFnup7Ibms9NAzYCPAJY43NUgKw,4935
|
@@ -162,6 +163,9 @@ langtrace_python_sdk/instrumentation/cerebras/patch.py,sha256=HR4slOrE3pMp0ABafn
|
|
162
163
|
langtrace_python_sdk/instrumentation/chroma/__init__.py,sha256=pNZ5UO8Q-d5VkXSobBf79reB6AmEl_usnnTp5Itv818,95
|
163
164
|
langtrace_python_sdk/instrumentation/chroma/instrumentation.py,sha256=nT6PS6bsrIOO9kLV5GuUeRjMe6THHHAZGvqWBP1dYog,1807
|
164
165
|
langtrace_python_sdk/instrumentation/chroma/patch.py,sha256=jYcqBeu-0cYA29PO880oXYRwYh-R1oseXmzfK6UDBps,9074
|
166
|
+
langtrace_python_sdk/instrumentation/cleanlab/__init__.py,sha256=UuwRiRAPH2i6cucqK8CgNYOGrsG4t_SGAQJSExRuZ1U,99
|
167
|
+
langtrace_python_sdk/instrumentation/cleanlab/instrumentation.py,sha256=CtWdtDUCqh60HU2Vs38O9Y32rlB4jzHIEbVRbwIf_Wg,2088
|
168
|
+
langtrace_python_sdk/instrumentation/cleanlab/patch.py,sha256=aI0QfG9UH5P7OvmzeIdeMhRd28oV4JMuXIkPv8s869s,3138
|
165
169
|
langtrace_python_sdk/instrumentation/cohere/__init__.py,sha256=sGUSLdTUyYf36Tm6L5jQflhzCqvmWrhnBOMYHjvp6Hs,95
|
166
170
|
langtrace_python_sdk/instrumentation/cohere/instrumentation.py,sha256=1wxMhWMfsvKprdV52BIfCZhZS1beRYBW9rUzUDDkyCk,2854
|
167
171
|
langtrace_python_sdk/instrumentation/cohere/patch.py,sha256=q29gJnik8bnJ7fnwaJ8PArHTQbJkWhhwBfDdQOTRBng,25422
|
@@ -185,7 +189,7 @@ langtrace_python_sdk/instrumentation/google_genai/instrumentation.py,sha256=oqKD
|
|
185
189
|
langtrace_python_sdk/instrumentation/google_genai/patch.py,sha256=X0TWY1D4XHweaNu70PlXBDzKEaHIibLpkJiIsp4jF6A,4115
|
186
190
|
langtrace_python_sdk/instrumentation/graphlit/__init__.py,sha256=mkUPwozR-I-D5ZrumJs1gS7sSouY0UN68Ne9LiNEBTs,92
|
187
191
|
langtrace_python_sdk/instrumentation/graphlit/instrumentation.py,sha256=V9GRZ6cj2lt20xCVfL55lGU4p0HlZxAYUqwpWogXDtY,2074
|
188
|
-
langtrace_python_sdk/instrumentation/graphlit/patch.py,sha256=
|
192
|
+
langtrace_python_sdk/instrumentation/graphlit/patch.py,sha256=jVME4xlFTwJRPWOBGUtQiZrGkr1ScR2DSYwcWPd5smk,2921
|
189
193
|
langtrace_python_sdk/instrumentation/groq/__init__.py,sha256=ZXeq_nrej6Lm_uoMFEg8wbSejhjB2UJ5IoHQBPc2-C0,91
|
190
194
|
langtrace_python_sdk/instrumentation/groq/instrumentation.py,sha256=Ttf07XVKhdYY1_fqJc7QWiSdmgEhEVyQB_3Az2_wqYo,1832
|
191
195
|
langtrace_python_sdk/instrumentation/groq/patch.py,sha256=J0h8SXEw2LyMIJhKZTVydEysyKfSLWkCuhEharzDS4w,23161
|
@@ -293,8 +297,8 @@ tests/pinecone/cassettes/test_query.yaml,sha256=b5v9G3ssUy00oG63PlFUR3JErF2Js-5A
|
|
293
297
|
tests/pinecone/cassettes/test_upsert.yaml,sha256=neWmQ1v3d03V8WoLl8FoFeeCYImb8pxlJBWnFd_lITU,38607
|
294
298
|
tests/qdrant/conftest.py,sha256=9n0uHxxIjWk9fbYc4bx-uP8lSAgLBVx-cV9UjnsyCHM,381
|
295
299
|
tests/qdrant/test_qdrant.py,sha256=pzjAjVY2kmsmGfrI2Gs2xrolfuaNHz7l1fqGQCjp5_o,3353
|
296
|
-
langtrace_python_sdk-3.8.
|
297
|
-
langtrace_python_sdk-3.8.
|
298
|
-
langtrace_python_sdk-3.8.
|
299
|
-
langtrace_python_sdk-3.8.
|
300
|
-
langtrace_python_sdk-3.8.
|
300
|
+
langtrace_python_sdk-3.8.2.dist-info/METADATA,sha256=HCBbeEC66vg50PnJIkzbCXkSf_J3LyB0AjxP3nydWH4,15792
|
301
|
+
langtrace_python_sdk-3.8.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
302
|
+
langtrace_python_sdk-3.8.2.dist-info/entry_points.txt,sha256=1_b9-qvf2fE7uQNZcbUei9vLpFZBbbh9LrtGw95ssAo,70
|
303
|
+
langtrace_python_sdk-3.8.2.dist-info/licenses/LICENSE,sha256=QwcOLU5TJoTeUhuIXzhdCEEDDvorGiC6-3YTOl4TecE,11356
|
304
|
+
langtrace_python_sdk-3.8.2.dist-info/RECORD,,
|
File without changes
|
{langtrace_python_sdk-3.8.0.dist-info → langtrace_python_sdk-3.8.2.dist-info}/entry_points.txt
RENAMED
File without changes
|
{langtrace_python_sdk-3.8.0.dist-info → langtrace_python_sdk-3.8.2.dist-info}/licenses/LICENSE
RENAMED
File without changes
|