Skip to content

Commit 5591619

Browse files
committed
Cleanlab integration
1 parent b6e9387 commit 5591619

File tree

9 files changed

+186
-70
lines changed

9 files changed

+186
-70
lines changed
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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)

src/langtrace_python_sdk/constants/instrumentation/common.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
"ARCH": "Arch",
1414
"AZURE": "Azure",
1515
"CHROMA": "Chroma",
16+
"CLEANLAB": "CleanLab",
17+
"COHERE": "Cohere",
1618
"CREWAI": "CrewAI",
1719
"DEEPSEEK": "DeepSeek",
1820
"DSPY": "DSPy",
@@ -25,7 +27,6 @@
2527
"LLAMAINDEX": "LlamaIndex",
2628
"OPENAI": "OpenAI",
2729
"PINECONE": "Pinecone",
28-
"COHERE": "Cohere",
2930
"PPLX": "Perplexity",
3031
"QDRANT": "Qdrant",
3132
"WEAVIATE": "Weaviate",

src/langtrace_python_sdk/instrumentation/__init__.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
1+
from .agno import AgnoInstrumentation
12
from .anthropic import AnthropicInstrumentation
23
from .autogen import AutogenInstrumentation
34
from .aws_bedrock import AWSBedrockInstrumentation
45
from .cerebras import CerebrasInstrumentation
56
from .chroma import ChromaInstrumentation
7+
from .cleanlab import CleanLabInstrumentation
68
from .cohere import CohereInstrumentation
79
from .crewai import CrewAIInstrumentation
810
from .crewai_tools import CrewaiToolsInstrumentation
911
from .dspy import DspyInstrumentation
1012
from .embedchain import EmbedchainInstrumentation
1113
from .gemini import GeminiInstrumentation
1214
from .google_genai import GoogleGenaiInstrumentation
15+
from .graphlit import GraphlitInstrumentation
1316
from .groq import GroqInstrumentation
1417
from .langchain import LangchainInstrumentation
1518
from .langchain_community import LangchainCommunityInstrumentation
@@ -21,17 +24,12 @@
2124
from .mistral import MistralInstrumentation
2225
from .ollama import OllamaInstrumentor
2326
from .openai import OpenAIInstrumentation
27+
from .phidata import PhiDataInstrumentation
2428
from .pinecone import PineconeInstrumentation
2529
from .pymongo import PyMongoInstrumentation
2630
from .qdrant import QdrantInstrumentation
2731
from .vertexai import VertexAIInstrumentation
2832
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
3533

3634
__all__ = [
3735
"AnthropicInstrumentation",
@@ -65,4 +63,5 @@
6563
"GraphlitInstrumentation",
6664
"PhiDataInstrumentation",
6765
"AgnoInstrumentation",
66+
"CleanLabInstrumentation",
6867
]
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
from .instrumentation import CleanLabInstrumentation
2+
3+
__all__ = [
4+
"CleanLabInstrumentation",
5+
]
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

src/langtrace_python_sdk/instrumentation/graphlit/patch.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import json
2+
23
from importlib_metadata import version as v
34
from langtrace.trace_attributes import FrameworkSpanAttributes
45
from opentelemetry import baggage
@@ -7,9 +8,7 @@
78

89
from langtrace_python_sdk.constants import LANGTRACE_SDK_NAME
910
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)
1312
from langtrace_python_sdk.utils.llm import set_span_attributes
1413
from langtrace_python_sdk.utils.misc import serialize_args, serialize_kwargs
1514

@@ -27,8 +26,8 @@ async def traced_method(wrapped, instance, args, kwargs):
2726
**(extra_attributes if extra_attributes is not None else {}),
2827
}
2928

30-
span_attributes["langchain.metadata"] = serialize_kwargs(**kwargs)
31-
span_attributes["langchain.inputs"] = serialize_args(*args)
29+
span_attributes["graphlit.metadata"] = serialize_kwargs(**kwargs)
30+
span_attributes["graphlit.inputs"] = serialize_args(*args)
3231

3332
attributes = FrameworkSpanAttributes(**span_attributes)
3433

src/langtrace_python_sdk/langtrace.py

Lines changed: 14 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -29,54 +29,9 @@
2929
from opentelemetry.instrumentation.sqlalchemy import SQLAlchemyInstrumentor
3030
from opentelemetry.sdk.resources import SERVICE_NAME, Resource
3131
from opentelemetry.sdk.trace import TracerProvider
32-
from opentelemetry.sdk.trace.export import (
33-
BatchSpanProcessor,
34-
ConsoleSpanExporter,
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)
8035
from opentelemetry.util.re import parse_env_headers
8136
from sentry_sdk.types import Event, Hint
8237

@@ -86,17 +41,18 @@
8641
from langtrace_python_sdk.extensions.langtrace_exporter import \
8742
LangTraceExporter
8843
from langtrace_python_sdk.instrumentation import (
89-
AnthropicInstrumentation, AutogenInstrumentation,
44+
AgnoInstrumentation, AnthropicInstrumentation, AutogenInstrumentation,
9045
AWSBedrockInstrumentation, CerebrasInstrumentation, ChromaInstrumentation,
91-
CohereInstrumentation, CrewAIInstrumentation, CrewaiToolsInstrumentation,
92-
DspyInstrumentation, EmbedchainInstrumentation, GeminiInstrumentation,
93-
GoogleGenaiInstrumentation, GroqInstrumentation,
94-
LangchainCommunityInstrumentation, LangchainCoreInstrumentation,
95-
LangchainInstrumentation, LanggraphInstrumentation, LiteLLMInstrumentation,
46+
CleanLabInstrumentation, CohereInstrumentation, CrewAIInstrumentation,
47+
CrewaiToolsInstrumentation, DspyInstrumentation, EmbedchainInstrumentation,
48+
GeminiInstrumentation, GoogleGenaiInstrumentation, GraphlitInstrumentation,
49+
GroqInstrumentation, LangchainCommunityInstrumentation,
50+
LangchainCoreInstrumentation, LangchainInstrumentation,
51+
LanggraphInstrumentation, LiteLLMInstrumentation,
9652
LlamaindexInstrumentation, MilvusInstrumentation, MistralInstrumentation,
97-
OllamaInstrumentor, OpenAIInstrumentation, PineconeInstrumentation,
98-
PyMongoInstrumentation, QdrantInstrumentation, VertexAIInstrumentation,
99-
WeaviateInstrumentation)
53+
OllamaInstrumentor, OpenAIInstrumentation, PhiDataInstrumentation,
54+
PineconeInstrumentation, PyMongoInstrumentation, QdrantInstrumentation,
55+
VertexAIInstrumentation, WeaviateInstrumentation)
10056
from langtrace_python_sdk.types import (DisableInstrumentations,
10157
InstrumentationMethods)
10258
from langtrace_python_sdk.utils import (check_if_sdk_is_outdated,
@@ -334,6 +290,7 @@ def init(
334290
"cerebras-cloud-sdk": CerebrasInstrumentation(),
335291
"pymilvus": MilvusInstrumentation(),
336292
"crewai-tools": CrewaiToolsInstrumentation(),
293+
"cleanlab-tlm": CleanLabInstrumentation(),
337294
}
338295

339296
init_instrumentations(config.disable_instrumentations, all_instrumentations)
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = "3.8.0"
1+
__version__ = "3.8.1"

0 commit comments

Comments
 (0)