langtrace-python-sdk 2.1.20__py3-none-any.whl → 2.1.22__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.
@@ -0,0 +1,70 @@
1
+ import os
2
+
3
+ os.environ["OPENAI_MODEL_NAME"] = "gpt-3.5-turbo"
4
+ os.environ["SERPER_API_KEY"] = "" # serper.dev API key
5
+ from langtrace_python_sdk import langtrace
6
+ from langtrace_python_sdk.utils.with_root_span import with_langtrace_root_span
7
+ from crewai import Crew, Process
8
+ from crewai import Task
9
+ from crewai import Agent
10
+ from crewai_tools import SerperDevTool
11
+ from crewai_tools import YoutubeVideoSearchTool
12
+
13
+ langtrace.init()
14
+
15
+ search_tool = SerperDevTool()
16
+
17
+ # Targeted search within a specific Youtube video's content
18
+ youtube_tool = YoutubeVideoSearchTool(
19
+ youtube_video_url="https://www.youtube.com/watch?v=blqIZGXWUpU"
20
+ )
21
+
22
+ # Creating a senior researcher agent with memory and verbose mode
23
+ researcher = Agent(
24
+ role="Senior Researcher",
25
+ goal="Uncover groundbreaking technologies in {topic}",
26
+ verbose=True,
27
+ memory=True,
28
+ backstory=(
29
+ "Driven by curiosity, you're at the forefront of"
30
+ "innovation, eager to explore and share knowledge that could change"
31
+ "the world."
32
+ ),
33
+ tools=[youtube_tool],
34
+ )
35
+
36
+ # Research task
37
+ research_task = Task(
38
+ description=(
39
+ "Do a {topic} of the given youtube video."
40
+ "Focus on identifying the overall narrative."
41
+ "Your final report should clearly articulate the key points."
42
+ ),
43
+ expected_output="10 key points from the shared video.",
44
+ tools=[youtube_tool],
45
+ agent=researcher,
46
+ callback="research_callback", # Example of task callback
47
+ human_input=True,
48
+ )
49
+
50
+
51
+ # Forming the tech-focused crew with some enhanced configurations
52
+ crew = Crew(
53
+ agents=[researcher],
54
+ tasks=[research_task],
55
+ process=Process.sequential, # Optional: Sequential task execution is default
56
+ memory=False,
57
+ cache=False,
58
+ max_rpm=20,
59
+ )
60
+
61
+ # Starting the task execution process with enhanced feedback
62
+
63
+
64
+ @with_langtrace_root_span("Crew")
65
+ def test_crew():
66
+ result = crew.kickoff(inputs={"topic": "summary"})
67
+ return result
68
+
69
+
70
+ test_crew()
@@ -0,0 +1,42 @@
1
+ import dspy
2
+ from dspy.datasets.gsm8k import GSM8K, gsm8k_metric
3
+ from dspy.teleprompt import BootstrapFewShot
4
+
5
+ # flake8: noqa
6
+ from langtrace_python_sdk import langtrace, with_langtrace_root_span
7
+
8
+ langtrace.init()
9
+
10
+ turbo = dspy.OpenAI(model="gpt-3.5-turbo", max_tokens=250)
11
+ dspy.settings.configure(lm=turbo)
12
+
13
+ # Load math questions from the GSM8K dataset
14
+ gsm8k = GSM8K()
15
+ gsm8k_trainset, gsm8k_devset = gsm8k.train[:10], gsm8k.dev[:10]
16
+
17
+
18
+ class CoT(dspy.Module):
19
+ def __init__(self):
20
+ super().__init__()
21
+ self.prog = dspy.ChainOfThought("question -> answer")
22
+
23
+ def forward(self, question):
24
+ return self.prog(question=question)
25
+
26
+
27
+ @with_langtrace_root_span(name="math_problems_cot_example")
28
+ def example():
29
+
30
+ # Set up the optimizer: we want to "bootstrap" (i.e., self-generate) 4-shot examples of our CoT program.
31
+ config = dict(max_bootstrapped_demos=4, max_labeled_demos=4)
32
+
33
+ # Optimize! Use the `gsm8k_metric` here. In general, the metric is going to tell the optimizer how well it's doing.
34
+ teleprompter = BootstrapFewShot(metric=gsm8k_metric, **config)
35
+ optimized_cot = teleprompter.compile(CoT(), trainset=gsm8k_trainset)
36
+
37
+ ans = optimized_cot(question="What is the sqrt of 345?")
38
+ print(ans)
39
+
40
+
41
+ if __name__ == "__main__":
42
+ example()
@@ -0,0 +1,35 @@
1
+ import dspy
2
+
3
+ # flake8: noqa
4
+ from langtrace_python_sdk import langtrace, with_langtrace_root_span
5
+
6
+ langtrace.init()
7
+
8
+ turbo = dspy.OpenAI(model="gpt-3.5-turbo", max_tokens=250)
9
+ dspy.settings.configure(lm=turbo)
10
+
11
+
12
+ # Define a simple signature for basic question answering
13
+ class BasicQA(dspy.Signature):
14
+ """Answer questions with short factoid answers."""
15
+
16
+ question = dspy.InputField()
17
+ answer = dspy.OutputField(desc="often between 1 and 5 words")
18
+
19
+
20
+ @with_langtrace_root_span(name="pot_example")
21
+ def example():
22
+
23
+ # Pass signature to ProgramOfThought Module
24
+ pot = dspy.ProgramOfThought(BasicQA)
25
+
26
+ # Call the ProgramOfThought module on a particular input
27
+ question = "Sarah has 5 apples. She buys 7 more apples from the store. How many apples does Sarah have now?"
28
+ result = pot(question=question)
29
+
30
+ print(f"Question: {question}")
31
+ print(f"Final Predicted Answer (after ProgramOfThought process): {result.answer}")
32
+
33
+
34
+ if __name__ == "__main__":
35
+ example()
@@ -0,0 +1,113 @@
1
+ import dspy
2
+ import json
3
+ from dspy.datasets import HotPotQA
4
+ from dspy.teleprompt import BootstrapFewShot
5
+ from dspy.evaluate.evaluate import Evaluate
6
+
7
+ # flake8: noqa
8
+ from langtrace_python_sdk import langtrace, with_langtrace_root_span
9
+
10
+ langtrace.init()
11
+
12
+
13
+ colbertv2_wiki17_abstracts = dspy.ColBERTv2(
14
+ url="http://20.102.90.50:2017/wiki17_abstracts"
15
+ )
16
+ dspy.settings.configure(rm=colbertv2_wiki17_abstracts)
17
+ turbo = dspy.OpenAI(model="gpt-3.5-turbo-0613", max_tokens=500)
18
+ dspy.settings.configure(lm=turbo, trace=[], temperature=0.7)
19
+
20
+ dataset = HotPotQA(
21
+ train_seed=1,
22
+ train_size=300,
23
+ eval_seed=2023,
24
+ dev_size=300,
25
+ test_size=0,
26
+ keep_details=True,
27
+ )
28
+ trainset = [x.with_inputs("question", "answer") for x in dataset.train]
29
+ devset = [x.with_inputs("question", "answer") for x in dataset.dev]
30
+
31
+
32
+ class GenerateAnswerChoices(dspy.Signature):
33
+ """Generate answer choices in JSON format that include the correct answer and plausible distractors for the specified question."""
34
+
35
+ question = dspy.InputField()
36
+ correct_answer = dspy.InputField()
37
+ number_of_choices = dspy.InputField()
38
+ answer_choices = dspy.OutputField(desc="JSON key-value pairs")
39
+
40
+
41
+ class QuizAnswerGenerator(dspy.Module):
42
+ def __init__(self):
43
+ super().__init__()
44
+ self.prog = dspy.ChainOfThought(GenerateAnswerChoices)
45
+
46
+ def forward(self, question, answer):
47
+ choices = self.prog(
48
+ question=question, correct_answer=answer, number_of_choices="4"
49
+ ).answer_choices
50
+ # dspy.Suggest(
51
+ # format_checker(choices),
52
+ # "The format of the answer choices should be in JSON format. Please revise accordingly.",
53
+ # target_module=GenerateAnswerChoices,
54
+ # )
55
+ return dspy.Prediction(choices=choices)
56
+
57
+
58
+ def format_checker(choice_string):
59
+ try:
60
+ choices = json.loads(choice_string)
61
+ if isinstance(choices, dict) and all(
62
+ isinstance(key, str) and isinstance(value, str)
63
+ for key, value in choices.items()
64
+ ):
65
+ return True
66
+ except json.JSONDecodeError:
67
+ return False
68
+
69
+ return False
70
+
71
+
72
+ def format_valid_metric(gold, pred, trace=None):
73
+ generated_choices = pred.choices
74
+ format_valid = format_checker(generated_choices)
75
+ score = format_valid
76
+ return score
77
+
78
+
79
+ @with_langtrace_root_span(name="quiz_generator_1")
80
+ def quiz_generator_1():
81
+ quiz_generator = QuizAnswerGenerator()
82
+
83
+ example = devset[67]
84
+ print("Example Question: ", example.question)
85
+ print("Example Answer: ", example.answer)
86
+ # quiz_choices = quiz_generator(question=example.question, answer=example.answer)
87
+ # print("Generated Quiz Choices: ", quiz_choices.choices)
88
+
89
+ optimizer = BootstrapFewShot(
90
+ metric=format_valid_metric, max_bootstrapped_demos=4, max_labeled_demos=4
91
+ )
92
+ compiled_quiz_generator = optimizer.compile(
93
+ quiz_generator,
94
+ trainset=trainset,
95
+ )
96
+ quiz_choices = compiled_quiz_generator(
97
+ question=example.question, answer=example.answer
98
+ )
99
+ print("Generated Quiz Choices: ", quiz_choices.choices)
100
+
101
+ # Evaluate
102
+ evaluate = Evaluate(
103
+ metric=format_valid_metric,
104
+ devset=devset[67:70],
105
+ num_threads=1,
106
+ display_progress=True,
107
+ display_table=5,
108
+ )
109
+ evaluate(quiz_generator)
110
+
111
+
112
+ if __name__ == "__main__":
113
+ quiz_generator_1()
@@ -0,0 +1,39 @@
1
+ import sys
2
+ import os
3
+ import dspy
4
+
5
+ # Add the local src folder to the Python path
6
+ sys.path.insert(0, os.path.abspath('/Users/karthikkalyanaraman/work/langtrace/langtrace-python-sdk/src'))
7
+
8
+ # flake8: noqa
9
+ from langtrace_python_sdk import langtrace, with_langtrace_root_span
10
+ langtrace.init()
11
+
12
+ turbo = dspy.OpenAI(model='gpt-3.5-turbo', max_tokens=250)
13
+ dspy.settings.configure(lm=turbo)
14
+
15
+ colbertv2_wiki17_abstracts = dspy.ColBERTv2(url='http://20.102.90.50:2017/wiki17_abstracts')
16
+ dspy.settings.configure(rm=colbertv2_wiki17_abstracts)
17
+ retriever = dspy.Retrieve(k=3)
18
+
19
+ # Define a simple signature for basic question answering
20
+ class BasicQA(dspy.Signature):
21
+ """Answer questions with short factoid answers."""
22
+ question = dspy.InputField()
23
+ answer = dspy.OutputField(desc="often between 1 and 5 words")
24
+
25
+ @with_langtrace_root_span(name="react_example")
26
+ def example():
27
+
28
+ # Pass signature to ReAct module
29
+ react_module = dspy.ReAct(BasicQA)
30
+
31
+ # Call the ReAct module on a particular input
32
+ question = 'Aside from the Apple Remote, what other devices can control the program Apple Remote was originally designed to interact with?'
33
+ result = react_module(question=question)
34
+
35
+ print(f"Question: {question}")
36
+ print(f"Final Predicted Answer (after ReAct process): {result.answer}")
37
+
38
+ if __name__ == '__main__':
39
+ example()
@@ -11,6 +11,8 @@ SERVICE_PROVIDERS = {
11
11
  "ANTHROPIC": "Anthropic",
12
12
  "AZURE": "Azure",
13
13
  "CHROMA": "Chroma",
14
+ "CREWAI": "CrewAI",
15
+ "DSPY": "DSPy",
14
16
  "GROQ": "Groq",
15
17
  "LANGCHAIN": "Langchain",
16
18
  "LANGCHAIN_COMMUNITY": "Langchain Community",
@@ -1,6 +1,7 @@
1
1
  from .anthropic import AnthropicInstrumentation
2
2
  from .chroma import ChromaInstrumentation
3
3
  from .cohere import CohereInstrumentation
4
+ from .crewai import CrewAIInstrumentation
4
5
  from .groq import GroqInstrumentation
5
6
  from .langchain import LangchainInstrumentation
6
7
  from .langchain_community import LangchainCommunityInstrumentation
@@ -12,11 +13,13 @@ from .pinecone import PineconeInstrumentation
12
13
  from .qdrant import QdrantInstrumentation
13
14
  from .weaviate import WeaviateInstrumentation
14
15
  from .ollama import OllamaInstrumentor
16
+ from .dspy import DspyInstrumentation
15
17
 
16
18
  __all__ = [
17
19
  "AnthropicInstrumentation",
18
20
  "ChromaInstrumentation",
19
21
  "CohereInstrumentation",
22
+ "CrewAIInstrumentation",
20
23
  "GroqInstrumentation",
21
24
  "LangchainInstrumentation",
22
25
  "LangchainCommunityInstrumentation",
@@ -28,4 +31,5 @@ __all__ = [
28
31
  "QdrantInstrumentation",
29
32
  "WeaviateInstrumentation",
30
33
  "OllamaInstrumentor",
34
+ "DspyInstrumentation",
31
35
  ]
@@ -0,0 +1,3 @@
1
+ from .instrumentation import CrewAIInstrumentation
2
+
3
+ __all__ = ["CrewAIInstrumentation"]
@@ -0,0 +1,53 @@
1
+ """
2
+ Copyright (c) 2024 Scale3 Labs
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ """
16
+
17
+ from opentelemetry.instrumentation.instrumentor import BaseInstrumentor
18
+ from opentelemetry.trace import get_tracer
19
+ from wrapt import wrap_function_wrapper as _W
20
+ from typing import Collection
21
+ from importlib_metadata import version as v
22
+ from .patch import patch_crew
23
+
24
+
25
+ class CrewAIInstrumentation(BaseInstrumentor):
26
+ """
27
+ The CrewAIInstrumentation class represents the CrewAI instrumentation"""
28
+
29
+ def instrumentation_dependencies(self) -> Collection[str]:
30
+ return ["crewai >= 0.32.0"]
31
+
32
+ def _instrument(self, **kwargs):
33
+ tracer_provider = kwargs.get("tracer_provider")
34
+ tracer = get_tracer(__name__, "", tracer_provider)
35
+ version = v("crewai")
36
+ _W(
37
+ "crewai.crew",
38
+ "Crew.kickoff",
39
+ patch_crew("Crew.kickoff", version, tracer),
40
+ )
41
+ _W(
42
+ "crewai.agent",
43
+ "Agent.execute_task",
44
+ patch_crew("Agent.execute_task", version, tracer),
45
+ )
46
+ _W(
47
+ "crewai.task",
48
+ "Task.execute",
49
+ patch_crew("Task.execute", version, tracer),
50
+ )
51
+
52
+ def _uninstrument(self, **kwargs):
53
+ pass
@@ -0,0 +1,173 @@
1
+ import json
2
+ from importlib_metadata import version as v
3
+ from langtrace_python_sdk.constants import LANGTRACE_SDK_NAME
4
+ from langtrace_python_sdk.utils import set_span_attribute
5
+ from langtrace_python_sdk.utils.silently_fail import silently_fail
6
+ from langtrace_python_sdk.constants.instrumentation.common import (
7
+ LANGTRACE_ADDITIONAL_SPAN_ATTRIBUTES_KEY,
8
+ SERVICE_PROVIDERS,
9
+ )
10
+ from opentelemetry import baggage
11
+ from langtrace.trace_attributes import FrameworkSpanAttributes
12
+ from opentelemetry.trace import SpanKind
13
+ from opentelemetry.trace.status import Status, StatusCode
14
+
15
+
16
+ crew_properties = {
17
+ "tasks": "object",
18
+ "agents": "object",
19
+ "cache": "bool",
20
+ "process": "object",
21
+ "verbose": "bool",
22
+ "memory": "bool",
23
+ "embedder": "json",
24
+ "full_output": "bool",
25
+ "manager_llm": "object",
26
+ "manager_agent": "object",
27
+ "manager_callbacks": "object",
28
+ "function_calling_llm": "object",
29
+ "config": "json",
30
+ "id": "object",
31
+ "max_rpm": "int",
32
+ "share_crew": "bool",
33
+ "step_callback": "object",
34
+ "task_callback": "object",
35
+ "prompt_file": "object",
36
+ "output_log_file": "object",
37
+ }
38
+
39
+ task_properties = {
40
+ "id": "object",
41
+ "used_tools": "int",
42
+ "tools_errors": "int",
43
+ "delegations": "int",
44
+ "i18n": "object",
45
+ "thread": "object",
46
+ "prompt_context": "object",
47
+ "description": "str",
48
+ "expected_output": "str",
49
+ "config": "object",
50
+ "callback": "str",
51
+ "agent": "object",
52
+ "context": "object",
53
+ "async_execution": "bool",
54
+ "output_json": "object",
55
+ "output_pydantic": "object",
56
+ "output_file": "object",
57
+ "output": "object",
58
+ "tools": "object",
59
+ "human_input": "bool",
60
+ }
61
+
62
+ agent_properties = {
63
+ "formatting_errors": "int",
64
+ "id": "object",
65
+ "role": "str",
66
+ "goal": "str",
67
+ "backstory": "str",
68
+ "cache": "bool",
69
+ "config": "object",
70
+ "max_rpm": "int",
71
+ "verbose": "bool",
72
+ "allow_delegation": "bool",
73
+ "tools": "object",
74
+ "max_iter": "int",
75
+ "max_execution_time": "object",
76
+ "agent_executor": "object",
77
+ "tools_handler": "object",
78
+ "force_answer_max_iterations": "int",
79
+ "crew": "object",
80
+ "cache_handler": "object",
81
+ "step_callback": "object",
82
+ "i18n": "object",
83
+ "llm": "object",
84
+ "function_calling_llm": "object",
85
+ "callbacks": "object",
86
+ "system_template": "object",
87
+ "prompt_template": "object",
88
+ "response_template": "object",
89
+ }
90
+
91
+
92
+ def patch_crew(operation_name, version, tracer):
93
+ def traced_method(wrapped, instance, args, kwargs):
94
+
95
+ service_provider = SERVICE_PROVIDERS["CREWAI"]
96
+ extra_attributes = baggage.get_baggage(LANGTRACE_ADDITIONAL_SPAN_ATTRIBUTES_KEY)
97
+ span_attributes = {
98
+ "langtrace.sdk.name": "langtrace-python-sdk",
99
+ "langtrace.service.name": service_provider,
100
+ "langtrace.service.type": "framework",
101
+ "langtrace.service.version": version,
102
+ "langtrace.version": v(LANGTRACE_SDK_NAME),
103
+ **(extra_attributes if extra_attributes is not None else {}),
104
+ }
105
+
106
+ crew_config = {}
107
+ for key, value in instance.__dict__.items():
108
+ if instance.__class__.__name__ == "Crew":
109
+ if key in crew_properties and value is not None:
110
+ if crew_properties[key] == "json":
111
+ crew_config[key] = json.dumps(value)
112
+ elif crew_properties[key] == "object":
113
+ crew_config[key] = str(value)
114
+ else:
115
+ crew_config[key] = value
116
+ elif instance.__class__.__name__ == "Agent":
117
+ if key in agent_properties and value is not None:
118
+ if agent_properties[key] == "json":
119
+ crew_config[key] = json.dumps(value)
120
+ elif agent_properties[key] == "object":
121
+ crew_config[key] = str(value)
122
+ else:
123
+ crew_config[key] = value
124
+ elif instance.__class__.__name__ == "Task":
125
+ if key in task_properties and value is not None:
126
+ if task_properties[key] == "json":
127
+ crew_config[key] = json.dumps(value)
128
+ elif task_properties[key] == "object":
129
+ crew_config[key] = str(value)
130
+ else:
131
+ crew_config[key] = value
132
+ if crew_config:
133
+ if instance.__class__.__name__ == "Crew":
134
+ if "inputs" in kwargs and kwargs["inputs"]:
135
+ crew_config["inputs"] = json.dumps(kwargs["inputs"])
136
+ span_attributes["crewai.crew.config"] = json.dumps(crew_config)
137
+ elif instance.__class__.__name__ == "Agent":
138
+ if "context" in kwargs and kwargs["context"]:
139
+ crew_config["context"] = json.dumps(kwargs["context"])
140
+ span_attributes["crewai.agent.config"] = json.dumps(crew_config)
141
+ elif instance.__class__.__name__ == "Task":
142
+ span_attributes["crewai.task.config"] = json.dumps(crew_config)
143
+
144
+ attributes = FrameworkSpanAttributes(**span_attributes)
145
+
146
+ with tracer.start_as_current_span(operation_name, kind=SpanKind.CLIENT) as span:
147
+ _set_input_attributes(span, kwargs, attributes)
148
+
149
+ try:
150
+ result = wrapped(*args, **kwargs)
151
+ if result:
152
+ span.set_status(Status(StatusCode.OK))
153
+
154
+ span.end()
155
+ return result
156
+
157
+ except Exception as err:
158
+ # Record the exception in the span
159
+ span.record_exception(err)
160
+
161
+ # Set the span status to indicate an error
162
+ span.set_status(Status(StatusCode.ERROR, str(err)))
163
+
164
+ # Reraise the exception to ensure it's not swallowed
165
+ raise
166
+
167
+ return traced_method
168
+
169
+
170
+ @silently_fail
171
+ def _set_input_attributes(span, kwargs, attributes):
172
+ for field, value in attributes.model_dump(by_alias=True).items():
173
+ set_span_attribute(span, field, value)
@@ -0,0 +1,3 @@
1
+ from .instrumentation import DspyInstrumentation
2
+
3
+ __all__ = ["DspyInstrumentation"]
@@ -0,0 +1,85 @@
1
+ """
2
+ Copyright (c) 2024 Scale3 Labs
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ """
16
+
17
+ from opentelemetry.instrumentation.instrumentor import BaseInstrumentor
18
+ from opentelemetry.trace import get_tracer
19
+ from wrapt import wrap_function_wrapper as _W
20
+ from typing import Collection
21
+ from importlib_metadata import version as v
22
+ from .patch import patch_bootstrapfewshot_optimizer, patch_signature, patch_evaluate
23
+
24
+
25
+ class DspyInstrumentation(BaseInstrumentor):
26
+ """
27
+ The DspyInstrumentor class represents the DSPy instrumentation"""
28
+
29
+ def instrumentation_dependencies(self) -> Collection[str]:
30
+ return ["dspy >= 0.1.5"]
31
+
32
+ def _instrument(self, **kwargs):
33
+ tracer_provider = kwargs.get("tracer_provider")
34
+ tracer = get_tracer(__name__, "", tracer_provider)
35
+ version = v("dspy")
36
+ _W(
37
+ "dspy.teleprompt.bootstrap",
38
+ "BootstrapFewShot.compile",
39
+ patch_bootstrapfewshot_optimizer(
40
+ "BootstrapFewShot.compile", version, tracer
41
+ ),
42
+ )
43
+ _W(
44
+ "dspy.predict.predict",
45
+ "Predict.forward",
46
+ patch_signature("Predict.forward", version, tracer),
47
+ )
48
+ _W(
49
+ "dspy.predict.chain_of_thought",
50
+ "ChainOfThought.forward",
51
+ patch_signature("ChainOfThought.forward", version, tracer),
52
+ )
53
+ _W(
54
+ "dspy.predict.chain_of_thought_with_hint",
55
+ "ChainOfThoughtWithHint.forward",
56
+ patch_signature("ChainOfThoughtWithHint.forward", version, tracer),
57
+ )
58
+ _W(
59
+ "dspy.predict.react",
60
+ "ReAct.forward",
61
+ patch_signature("ReAct.forward", version, tracer),
62
+ )
63
+ _W(
64
+ "dspy.predict.program_of_thought",
65
+ "ProgramOfThought.forward",
66
+ patch_signature("ProgramOfThought.forward", version, tracer),
67
+ )
68
+ _W(
69
+ "dspy.predict.multi_chain_comparison",
70
+ "MultiChainComparison.forward",
71
+ patch_signature("MultiChainComparison.forward", version, tracer),
72
+ )
73
+ _W(
74
+ "dspy.predict.retry",
75
+ "Retry.forward",
76
+ patch_signature("Retry.forward", version, tracer),
77
+ )
78
+ _W(
79
+ "dspy.evaluate.evaluate",
80
+ "Evaluate.__call__",
81
+ patch_evaluate("Evaluate", version, tracer),
82
+ )
83
+
84
+ def _uninstrument(self, **kwargs):
85
+ pass
@@ -0,0 +1,206 @@
1
+ import json
2
+ from importlib_metadata import version as v
3
+ from langtrace_python_sdk.constants import LANGTRACE_SDK_NAME
4
+ from langtrace_python_sdk.utils import set_span_attribute
5
+ from langtrace_python_sdk.utils.silently_fail import silently_fail
6
+ from langtrace_python_sdk.constants.instrumentation.common import (
7
+ LANGTRACE_ADDITIONAL_SPAN_ATTRIBUTES_KEY,
8
+ SERVICE_PROVIDERS,
9
+ )
10
+ from opentelemetry import baggage
11
+ from langtrace.trace_attributes import FrameworkSpanAttributes
12
+ from opentelemetry.trace import SpanKind
13
+ from opentelemetry.trace.status import Status, StatusCode
14
+
15
+
16
+ def patch_bootstrapfewshot_optimizer(operation_name, version, tracer):
17
+ def traced_method(wrapped, instance, args, kwargs):
18
+
19
+ service_provider = SERVICE_PROVIDERS["DSPY"]
20
+ extra_attributes = baggage.get_baggage(LANGTRACE_ADDITIONAL_SPAN_ATTRIBUTES_KEY)
21
+ span_attributes = {
22
+ "langtrace.sdk.name": "langtrace-python-sdk",
23
+ "langtrace.service.name": service_provider,
24
+ "langtrace.service.type": "framework",
25
+ "langtrace.service.version": version,
26
+ "langtrace.version": v(LANGTRACE_SDK_NAME),
27
+ **(extra_attributes if extra_attributes is not None else {}),
28
+ }
29
+
30
+ if instance.__class__.__name__:
31
+ span_attributes["dspy.optimizer"] = instance.__class__.__name__
32
+ if len(args) > 0:
33
+ span_attributes["dspy.optimizer.module"] = args[0].__class__.__name__
34
+ if args[0].prog:
35
+ prog = {
36
+ "name": args[0].prog.__class__.__name__,
37
+ "signature": str(args[0].prog.signature) if args[0].prog.signature else None,
38
+ }
39
+ span_attributes["dspy.optimizer.module.prog"] = json.dumps(prog)
40
+ if "metric" in instance and instance.metric:
41
+ span_attributes["dspy.optimizer.metric"] = instance.metric.__name__
42
+ if kwargs.get("trainset") and len(kwargs.get("trainset")) > 0:
43
+ span_attributes["dspy.optimizer.trainset"] = str(kwargs.get("trainset"))
44
+ config = {}
45
+ if "metric_threshold" in instance and instance.metric_threshold:
46
+ config["metric_threshold"] = instance.metric_threshold
47
+ if "teacher_settings" in instance and instance.teacher_settings:
48
+ config["teacher_settings"] = instance.teacher_settings
49
+ if "max_bootstrapped_demos" in instance and instance.max_bootstrapped_demos:
50
+ config["max_bootstrapped_demos"] = instance.max_bootstrapped_demos
51
+ if "max_labeled_demos" in instance and instance.max_labeled_demos:
52
+ config["max_labeled_demos"] = instance.max_labeled_demos
53
+ if "max_rounds" in instance and instance.max_rounds:
54
+ config["max_rounds"] = instance.max_rounds
55
+ if "max_errors" in instance and instance.max_errors:
56
+ config["max_errors"] = instance.max_errors
57
+ if "error_count" in instance and instance.error_count:
58
+ config["error_count"] = instance.error_count
59
+ if config and len(config) > 0:
60
+ span_attributes["dspy.optimizer.config"] = json.dumps(config)
61
+
62
+ attributes = FrameworkSpanAttributes(**span_attributes)
63
+ with tracer.start_as_current_span(
64
+ operation_name, kind=SpanKind.CLIENT
65
+ ) as span:
66
+ _set_input_attributes(span, kwargs, attributes)
67
+
68
+ try:
69
+ result = wrapped(*args, **kwargs)
70
+ if result:
71
+ span.set_status(Status(StatusCode.OK))
72
+
73
+ span.end()
74
+ return result
75
+
76
+ except Exception as err:
77
+ # Record the exception in the span
78
+ span.record_exception(err)
79
+
80
+ # Set the span status to indicate an error
81
+ span.set_status(Status(StatusCode.ERROR, str(err)))
82
+
83
+ # Reraise the exception to ensure it's not swallowed
84
+ raise
85
+
86
+ return traced_method
87
+
88
+
89
+ def patch_signature(operation_name, version, tracer):
90
+ def traced_method(wrapped, instance, args, kwargs):
91
+
92
+ service_provider = SERVICE_PROVIDERS["DSPY"]
93
+ extra_attributes = baggage.get_baggage(LANGTRACE_ADDITIONAL_SPAN_ATTRIBUTES_KEY)
94
+ span_attributes = {
95
+ "langtrace.sdk.name": "langtrace-python-sdk",
96
+ "langtrace.service.name": service_provider,
97
+ "langtrace.service.type": "framework",
98
+ "langtrace.service.version": version,
99
+ "langtrace.version": v(LANGTRACE_SDK_NAME),
100
+ **(extra_attributes if extra_attributes is not None else {}),
101
+ }
102
+
103
+ if instance.__class__.__name__:
104
+ span_attributes["dspy.signature.name"] = instance.__class__.__name__
105
+ span_attributes["dspy.signature"] = str(instance)
106
+
107
+ if kwargs and len(kwargs) > 0:
108
+ span_attributes["dspy.signature.args"] = str(kwargs)
109
+
110
+ attributes = FrameworkSpanAttributes(**span_attributes)
111
+ with tracer.start_as_current_span(
112
+ operation_name, kind=SpanKind.CLIENT
113
+ ) as span:
114
+ _set_input_attributes(span, kwargs, attributes)
115
+
116
+ try:
117
+ result = wrapped(*args, **kwargs)
118
+ if result:
119
+ set_span_attribute(span, "dspy.signature.result", str(result))
120
+ span.set_status(Status(StatusCode.OK))
121
+
122
+ span.end()
123
+ return result
124
+
125
+ except Exception as err:
126
+ # Record the exception in the span
127
+ span.record_exception(err)
128
+
129
+ # Set the span status to indicate an error
130
+ span.set_status(Status(StatusCode.ERROR, str(err)))
131
+
132
+ # Reraise the exception to ensure it's not swallowed
133
+ raise
134
+
135
+ return traced_method
136
+
137
+
138
+ def patch_evaluate(operation_name, version, tracer):
139
+ def traced_method(wrapped, instance, args, kwargs):
140
+
141
+ service_provider = SERVICE_PROVIDERS["DSPY"]
142
+ extra_attributes = baggage.get_baggage(LANGTRACE_ADDITIONAL_SPAN_ATTRIBUTES_KEY)
143
+ span_attributes = {
144
+ "langtrace.sdk.name": "langtrace-python-sdk",
145
+ "langtrace.service.name": service_provider,
146
+ "langtrace.service.type": "framework",
147
+ "langtrace.service.version": version,
148
+ "langtrace.version": v(LANGTRACE_SDK_NAME),
149
+ **(extra_attributes if extra_attributes is not None else {}),
150
+ }
151
+
152
+ if "devset" in instance and instance.devset is not None:
153
+ span_attributes["dspy.evaluate.devset"] = str(instance.devset)
154
+ if "display" in instance and instance.display is not None:
155
+ span_attributes["dspy.evaluate.display"] = str(instance.display)
156
+ if "num_threads" in instance and instance.num_threads is not None:
157
+ span_attributes["dspy.evaluate.num_threads"] = str(instance.num_threads)
158
+ if "return_outputs" in instance and instance.return_outputs is not None:
159
+ span_attributes["dspy.evaluate.return_outputs"] = str(instance.return_outputs)
160
+ if "display_table" in instance and instance.display_table is not None:
161
+ span_attributes["dspy.evaluate.display_table"] = str(instance.display_table)
162
+ if "display_progress" in instance and instance.display_progress is not None:
163
+ span_attributes["dspy.evaluate.display_progress"] = str(instance.display_progress)
164
+ if "metric" in instance and instance.metric is not None:
165
+ span_attributes["dspy.evaluate.metric"] = instance.metric.__name__
166
+ if "error_count" in instance and instance.error_count is not None:
167
+ span_attributes["dspy.evaluate.error_count"] = str(instance.error_count)
168
+ if "error_lock" in instance and instance.error_lock is not None:
169
+ span_attributes["dspy.evaluate.error_lock"] = str(instance.error_lock)
170
+ if "max_errors" in instance and instance.max_errors is not None:
171
+ span_attributes["dspy.evaluate.max_errors"] = str(instance.max_errors)
172
+ if args and len(args) > 0:
173
+ span_attributes["dspy.evaluate.args"] = str(args)
174
+
175
+ attributes = FrameworkSpanAttributes(**span_attributes)
176
+ with tracer.start_as_current_span(
177
+ operation_name, kind=SpanKind.CLIENT
178
+ ) as span:
179
+ _set_input_attributes(span, kwargs, attributes)
180
+
181
+ try:
182
+ result = wrapped(*args, **kwargs)
183
+ if result is not None:
184
+ set_span_attribute(span, "dspy.evaluate.result", str(result))
185
+ span.set_status(Status(StatusCode.OK))
186
+
187
+ span.end()
188
+ return result
189
+
190
+ except Exception as err:
191
+ # Record the exception in the span
192
+ span.record_exception(err)
193
+
194
+ # Set the span status to indicate an error
195
+ span.set_status(Status(StatusCode.ERROR, str(err)))
196
+
197
+ # Reraise the exception to ensure it's not swallowed
198
+ raise
199
+
200
+ return traced_method
201
+
202
+
203
+ @silently_fail
204
+ def _set_input_attributes(span, kwargs, attributes):
205
+ for field, value in attributes.model_dump(by_alias=True).items():
206
+ set_span_attribute(span, field, value)
@@ -275,6 +275,110 @@ def images_edit(original_method, version, tracer):
275
275
  return traced_method
276
276
 
277
277
 
278
+ class StreamWrapper:
279
+ def __init__(self, stream, span, prompt_tokens, function_call=False, tool_calls=False):
280
+ self.stream = stream
281
+ self.span = span
282
+ self.prompt_tokens = prompt_tokens
283
+ self.function_call = function_call
284
+ self.tool_calls = tool_calls
285
+ self.result_content = []
286
+ self.completion_tokens = 0
287
+
288
+ def __enter__(self):
289
+ self.span.add_event(Event.STREAM_START.value)
290
+ return self
291
+
292
+ def __exit__(self, exc_type, exc_val, exc_tb):
293
+ self.span.add_event(Event.STREAM_END.value)
294
+ self.span.set_attribute(
295
+ "llm.token.counts",
296
+ json.dumps(
297
+ {
298
+ "input_tokens": self.prompt_tokens,
299
+ "output_tokens": self.completion_tokens,
300
+ "total_tokens": self.prompt_tokens + self.completion_tokens,
301
+ }
302
+ ),
303
+ )
304
+ self.span.set_attribute(
305
+ "llm.responses",
306
+ json.dumps(
307
+ [
308
+ {
309
+ "role": "assistant",
310
+ "content": "".join(self.result_content),
311
+ }
312
+ ]
313
+ ),
314
+ )
315
+ self.span.set_status(StatusCode.OK)
316
+ self.span.end()
317
+
318
+ def __iter__(self):
319
+ return self
320
+
321
+ def __next__(self):
322
+ try:
323
+ chunk = next(self.stream)
324
+ self.process_chunk(chunk)
325
+ return chunk
326
+ except StopIteration:
327
+ raise
328
+
329
+ def process_chunk(self, chunk):
330
+ if hasattr(chunk, "model") and chunk.model is not None:
331
+ self.span.set_attribute("llm.model", chunk.model)
332
+ if hasattr(chunk, "choices") and chunk.choices is not None:
333
+ content = []
334
+ if not self.function_call and not self.tool_calls:
335
+ for choice in chunk.choices:
336
+ if choice.delta and choice.delta.content is not None:
337
+ token_counts = estimate_tokens(choice.delta.content)
338
+ self.completion_tokens += token_counts
339
+ content = [choice.delta.content]
340
+ elif self.function_call:
341
+ for choice in chunk.choices:
342
+ if (
343
+ choice.delta
344
+ and choice.delta.function_call is not None
345
+ and choice.delta.function_call.arguments is not None
346
+ ):
347
+ token_counts = estimate_tokens(
348
+ choice.delta.function_call.arguments
349
+ )
350
+ self.completion_tokens += token_counts
351
+ content = [choice.delta.function_call.arguments]
352
+ elif self.tool_calls:
353
+ for choice in chunk.choices:
354
+ if choice.delta and choice.delta.tool_calls is not None:
355
+ toolcalls = choice.delta.tool_calls
356
+ content = []
357
+ for tool_call in toolcalls:
358
+ if (
359
+ tool_call
360
+ and tool_call.function is not None
361
+ and tool_call.function.arguments is not None
362
+ ):
363
+ token_counts = estimate_tokens(
364
+ tool_call.function.arguments
365
+ )
366
+ self.completion_tokens += token_counts
367
+ content.append(tool_call.function.arguments)
368
+ self.span.add_event(
369
+ Event.STREAM_OUTPUT.value,
370
+ {
371
+ "response": (
372
+ "".join(content)
373
+ if len(content) > 0 and content[0] is not None
374
+ else ""
375
+ )
376
+ },
377
+ )
378
+ if content:
379
+ self.result_content.append(content[0])
380
+
381
+
278
382
  def chat_completions_create(original_method, version, tracer):
279
383
  """Wrap the `create` method of the `ChatCompletion` class to trace it."""
280
384
 
@@ -427,7 +531,7 @@ def chat_completions_create(original_method, version, tracer):
427
531
  json.dumps(function), kwargs.get("model")
428
532
  )
429
533
 
430
- return handle_streaming_response(
534
+ return StreamWrapper(
431
535
  result,
432
536
  span,
433
537
  prompt_tokens,
@@ -441,98 +545,6 @@ def chat_completions_create(original_method, version, tracer):
441
545
  span.end()
442
546
  raise
443
547
 
444
- def handle_streaming_response(
445
- result, span, prompt_tokens, function_call=False, tool_calls=False
446
- ):
447
- """Process and yield streaming response chunks."""
448
- result_content = []
449
- span.add_event(Event.STREAM_START.value)
450
- completion_tokens = 0
451
- try:
452
- for chunk in result:
453
- if hasattr(chunk, "model") and chunk.model is not None:
454
- span.set_attribute("llm.model", chunk.model)
455
- if hasattr(chunk, "choices") and chunk.choices is not None:
456
- if not function_call and not tool_calls:
457
- for choice in chunk.choices:
458
- if choice.delta and choice.delta.content is not None:
459
- token_counts = estimate_tokens(choice.delta.content)
460
- completion_tokens += token_counts
461
- content = [choice.delta.content]
462
- elif function_call:
463
- for choice in chunk.choices:
464
- if (
465
- choice.delta
466
- and choice.delta.function_call is not None
467
- and choice.delta.function_call.arguments is not None
468
- ):
469
- token_counts = estimate_tokens(
470
- choice.delta.function_call.arguments
471
- )
472
- completion_tokens += token_counts
473
- content = [choice.delta.function_call.arguments]
474
- elif tool_calls:
475
- for choice in chunk.choices:
476
- tool_call = ""
477
- if choice.delta and choice.delta.tool_calls is not None:
478
- toolcalls = choice.delta.tool_calls
479
- content = []
480
- for tool_call in toolcalls:
481
- if (
482
- tool_call
483
- and tool_call.function is not None
484
- and tool_call.function.arguments is not None
485
- ):
486
- token_counts = estimate_tokens(
487
- tool_call.function.arguments
488
- )
489
- completion_tokens += token_counts
490
- content = content + [
491
- tool_call.function.arguments
492
- ]
493
- else:
494
- content = content + []
495
- else:
496
- content = []
497
- span.add_event(
498
- Event.STREAM_OUTPUT.value,
499
- {
500
- "response": (
501
- "".join(content)
502
- if len(content) > 0 and content[0] is not None
503
- else ""
504
- )
505
- },
506
- )
507
- result_content.append(content[0] if len(content) > 0 else "")
508
- yield chunk
509
- finally:
510
- # Finalize span after processing all chunks
511
- span.add_event(Event.STREAM_END.value)
512
- span.set_attribute(
513
- "llm.token.counts",
514
- json.dumps(
515
- {
516
- "input_tokens": prompt_tokens,
517
- "output_tokens": completion_tokens,
518
- "total_tokens": prompt_tokens + completion_tokens,
519
- }
520
- ),
521
- )
522
- span.set_attribute(
523
- "llm.responses",
524
- json.dumps(
525
- [
526
- {
527
- "role": "assistant",
528
- "content": "".join(result_content),
529
- }
530
- ]
531
- ),
532
- )
533
- span.set_status(StatusCode.OK)
534
- span.end()
535
-
536
548
  # return the wrapped method
537
549
  return traced_method
538
550
 
@@ -687,7 +699,7 @@ def async_chat_completions_create(original_method, version, tracer):
687
699
  json.dumps(function), kwargs.get("model")
688
700
  )
689
701
 
690
- return ahandle_streaming_response(
702
+ return StreamWrapper(
691
703
  result,
692
704
  span,
693
705
  prompt_tokens,
@@ -701,99 +713,6 @@ def async_chat_completions_create(original_method, version, tracer):
701
713
  span.end()
702
714
  raise
703
715
 
704
- async def ahandle_streaming_response(
705
- result, span, prompt_tokens, function_call=False, tool_calls=False
706
- ):
707
- """Process and yield streaming response chunks."""
708
- result_content = []
709
- span.add_event(Event.STREAM_START.value)
710
- completion_tokens = 0
711
- try:
712
- content = []
713
- async for chunk in result:
714
- if hasattr(chunk, "model") and chunk.model is not None:
715
- span.set_attribute("llm.model", chunk.model)
716
- if hasattr(chunk, "choices") and chunk.choices is not None:
717
- if not function_call and not tool_calls:
718
- for choice in chunk.choices:
719
- if choice.delta and choice.delta.content is not None:
720
- token_counts = estimate_tokens(choice.delta.content)
721
- completion_tokens += token_counts
722
- content = [choice.delta.content]
723
- elif function_call:
724
- for choice in chunk.choices:
725
- if (
726
- choice.delta
727
- and choice.delta.function_call
728
- and choice.delta.function_call.arguments is not None
729
- ):
730
- token_counts = estimate_tokens(
731
- choice.delta.function_call.arguments
732
- )
733
- completion_tokens += token_counts
734
- content = [choice.delta.function_call.arguments]
735
- elif tool_calls:
736
- for choice in chunk.choices:
737
- tool_call = ""
738
- if choice.delta and choice.delta.tool_calls is not None:
739
- toolcalls = choice.delta.tool_calls
740
- content = []
741
- for tool_call in toolcalls:
742
- if (
743
- tool_call
744
- and tool_call.function is not None
745
- and tool_call.function.arguments is not None
746
- ):
747
- token_counts = estimate_tokens(
748
- tool_call.function.arguments
749
- )
750
- completion_tokens += token_counts
751
- content = content + [
752
- tool_call.function.arguments
753
- ]
754
- else:
755
- content = content + []
756
- else:
757
- content = []
758
- span.add_event(
759
- Event.STREAM_OUTPUT.value,
760
- {
761
- "response": (
762
- "".join(content)
763
- if len(content) > 0 and content[0] is not None
764
- else ""
765
- )
766
- },
767
- )
768
- result_content.append(content[0] if len(content) > 0 else "")
769
- yield chunk
770
- finally:
771
- # Finalize span after processing all chunks
772
- span.add_event(Event.STREAM_END.value)
773
- span.set_attribute(
774
- "llm.token.counts",
775
- json.dumps(
776
- {
777
- "input_tokens": prompt_tokens,
778
- "output_tokens": completion_tokens,
779
- "total_tokens": prompt_tokens + completion_tokens,
780
- }
781
- ),
782
- )
783
- span.set_attribute(
784
- "llm.responses",
785
- json.dumps(
786
- [
787
- {
788
- "role": "assistant",
789
- "content": "".join(result_content),
790
- }
791
- ]
792
- ),
793
- )
794
- span.set_status(StatusCode.OK)
795
- span.end()
796
-
797
716
  # return the wrapped method
798
717
  return traced_method
799
718
 
@@ -40,6 +40,7 @@ from langtrace_python_sdk.instrumentation import (
40
40
  AnthropicInstrumentation,
41
41
  ChromaInstrumentation,
42
42
  CohereInstrumentation,
43
+ CrewAIInstrumentation,
43
44
  GroqInstrumentation,
44
45
  LangchainInstrumentation,
45
46
  LangchainCommunityInstrumentation,
@@ -51,6 +52,7 @@ from langtrace_python_sdk.instrumentation import (
51
52
  QdrantInstrumentation,
52
53
  WeaviateInstrumentation,
53
54
  OllamaInstrumentor,
55
+ DspyInstrumentation,
54
56
  )
55
57
  from opentelemetry.instrumentation.sqlalchemy import SQLAlchemyInstrumentor
56
58
  from colorama import Fore
@@ -108,6 +110,8 @@ def init(
108
110
  "weaviate": WeaviateInstrumentation(),
109
111
  "sqlalchemy": SQLAlchemyInstrumentor(),
110
112
  "ollama": OllamaInstrumentor(),
113
+ "dspy": DspyInstrumentation(),
114
+ "crewai": CrewAIInstrumentation(),
111
115
  }
112
116
 
113
117
  init_instrumentations(disable_instrumentations, all_instrumentations)
@@ -1 +1 @@
1
- __version__ = "2.1.20"
1
+ __version__ = "2.1.22"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: langtrace-python-sdk
3
- Version: 2.1.20
3
+ Version: 2.1.22
4
4
  Summary: Python SDK for LangTrace
5
5
  Project-URL: Homepage, https://github.com/Scale3-Labs/langtrace-python-sdk
6
6
  Author-email: Scale3 Labs <engineering@scale3labs.com>
@@ -9,6 +9,11 @@ examples/cohere_example/chat_stream.py,sha256=daWGrj2yucN9sWKGiPzTw18clh23Grv-MI
9
9
  examples/cohere_example/embed.py,sha256=p9BJvOg09JVb8BfTCb63v3uh_wOsi_OyrCAJdXXrE6E,496
10
10
  examples/cohere_example/rerank.py,sha256=e7OU0A2FzfiQDuOmCy3Kg5LLNYGRmRIK5LqeLnTWlP4,1118
11
11
  examples/cohere_example/tools.py,sha256=a5uvS058tcwU6PJbF9EDO6LPVmPj2LoW4Vn8Web3Iq8,1656
12
+ examples/crewai_example/basic.py,sha256=PBu4f8yQfZO1L_22UDm_ReU9lnEcycjZcGuy5UpgDJM,1948
13
+ examples/dspy_example/math_problems_cot.py,sha256=Z98nB6myt8WJse2dWS6Ap7CFUhC27lBNb37R1Gg80VQ,1282
14
+ examples/dspy_example/program_of_thought_basic.py,sha256=oEbtJdeKENMUbex25-zyStWwurRWW6OdP0KDs-jUkko,984
15
+ examples/dspy_example/quiz_gen.py,sha256=OyGhepeX8meKOtLdmlYUjMD2ECk-ZQuQXUZif1hFQY4,3371
16
+ examples/dspy_example/react.py,sha256=dmhO6AyO5K3w0WNkwe-Usd2cIgVmEPoWzusrLxXIfPo,1340
12
17
  examples/fastapi_example/__init__.py,sha256=INIfvJP7zC_KkJCtulS1qbh61-MJTPAHnzAgzeKi0yU,87
13
18
  examples/fastapi_example/basic_route.py,sha256=_IRXjkOtJQ-bTIGa1WbvUF_2LF4bjghjyXt4YrHaRvw,1170
14
19
  examples/hiveagent_example/basic.py,sha256=Sd7I5w8w5Xx7ODaydTY30yiq9HwJDMKHQywrZjgehP0,441
@@ -45,15 +50,15 @@ examples/qdrant_example/basic.py,sha256=DCMjHSuBZKkhEjCkwy5d5La9WMyW0lCWqtcZWiFC
45
50
  examples/weaviate_example/__init__.py,sha256=8JMDBsRSEV10HfTd-YC7xb4txBjD3la56snk-Bbg2Kw,618
46
51
  examples/weaviate_example/query_text.py,sha256=qz9o-fTDzX5AW5m8BJF-TfmBdokxh492NfnmnPUMU3s,64814
47
52
  langtrace_python_sdk/__init__.py,sha256=VZM6i71NR7pBQK6XvJWRelknuTYUhqwqE7PlicKa5Wg,1166
48
- langtrace_python_sdk/langtrace.py,sha256=WRgbBS7T1q3ZELvVZLVCKdqa00m64lozgeiCp6MOQn8,7352
49
- langtrace_python_sdk/version.py,sha256=1o03qONF3c4_EpFCJ6aUvh-e6t48L0nm4t4sDu21mEA,23
53
+ langtrace_python_sdk/langtrace.py,sha256=pG_dWzzQxUP8r5SAMUwRScb6IopINcda1CZvJERjXBo,7486
54
+ langtrace_python_sdk/version.py,sha256=8X_w-VRCyU1lQMWejIqkf5tmhnrgO7csLi27xV88LJs,23
50
55
  langtrace_python_sdk/constants/__init__.py,sha256=P8QvYwt5czUNDZsKS64vxm9Dc41ptGbuF1TFtAF6nv4,44
51
56
  langtrace_python_sdk/constants/exporter/langtrace_exporter.py,sha256=5MNjnAOg-4am78J3gVMH6FSwq5N8TOj72ugkhsw4vi0,46
52
57
  langtrace_python_sdk/constants/instrumentation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
53
58
  langtrace_python_sdk/constants/instrumentation/anthropic.py,sha256=YX3llt3zwDY6XrYk3CB8WEVqgrzRXEw_ffyk56JoF3k,126
54
59
  langtrace_python_sdk/constants/instrumentation/chroma.py,sha256=hiPGYdHS0Yj4Kh3eaYBbuCAl_swqIygu80yFqkOgdak,955
55
60
  langtrace_python_sdk/constants/instrumentation/cohere.py,sha256=tf9sDfb5K3qOAHChEE5o8eYWPZ1io58VsOjZDCZPxfw,577
56
- langtrace_python_sdk/constants/instrumentation/common.py,sha256=UyYObokJpNPOPft_TPmhP00WONV0KqKOkX6mvN3AH5w,806
61
+ langtrace_python_sdk/constants/instrumentation/common.py,sha256=KodH_uGGjWGGP8rqTi7Ua-osjUwtPKslx69DJRbDiT4,850
57
62
  langtrace_python_sdk/constants/instrumentation/groq.py,sha256=VFXmIl4aqGY_fS0PAmjPj_Qm7Tibxbx7Ur_e7rQpqXc,134
58
63
  langtrace_python_sdk/constants/instrumentation/ollama.py,sha256=zFfSUKX5v1c612doKSxsmIwQeeQxSPkFp_ZzjWQSPNE,142
59
64
  langtrace_python_sdk/constants/instrumentation/openai.py,sha256=uEOH5UXapU2DSf2AdgXTRhhJEHGWXUNFkUGD5QafflM,1164
@@ -63,7 +68,7 @@ langtrace_python_sdk/constants/instrumentation/weaviate.py,sha256=Iytf2OpB_irZYE
63
68
  langtrace_python_sdk/extensions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
64
69
  langtrace_python_sdk/extensions/langtrace_exporter.py,sha256=gWVRU2DlB4xjZ4ww7M63DaLiAN5zQ2k1HPrythmjEdo,4202
65
70
  langtrace_python_sdk/extensions/langtrace_filesystem.py,sha256=qpnkpkuTZ2yhGgpBK64QJLt0T1iL-1zpEMPz4quJ_ng,6925
66
- langtrace_python_sdk/instrumentation/__init__.py,sha256=18E7qZOIKmSm59ij7n-ytCv3qenjkDlNz9xPjapOLtY,1107
71
+ langtrace_python_sdk/instrumentation/__init__.py,sha256=BYTzQSmHDbKAbtV98UDjxzV1UoNq_wtsWV7V4PZPzbc,1243
67
72
  langtrace_python_sdk/instrumentation/anthropic/__init__.py,sha256=donrurJAGYlxrSRA3BIf76jGeUcAx9Tq8CVpah68S0Y,101
68
73
  langtrace_python_sdk/instrumentation/anthropic/instrumentation.py,sha256=-srgE8qumAn0ulQYZxMa8ch-9IBH0XgBW_rfEnGk6LI,1684
69
74
  langtrace_python_sdk/instrumentation/anthropic/patch.py,sha256=52GRkW7fhF2VB9JvYGMaPwOvWH3Q5rsIEaVlnFm_Zz0,8548
@@ -73,6 +78,12 @@ langtrace_python_sdk/instrumentation/chroma/patch.py,sha256=HhIkXGbVfzpEB4edxzlG
73
78
  langtrace_python_sdk/instrumentation/cohere/__init__.py,sha256=sGUSLdTUyYf36Tm6L5jQflhzCqvmWrhnBOMYHjvp6Hs,95
74
79
  langtrace_python_sdk/instrumentation/cohere/instrumentation.py,sha256=YQFHZIBd7SSPD4b6Va-ZR0thf_AuBCqj5yzHLHJVWnM,2121
75
80
  langtrace_python_sdk/instrumentation/cohere/patch.py,sha256=uGjZm_c1-xpZilHD8ljGr4AqQB3UNU04SKl9s2alGzs,26726
81
+ langtrace_python_sdk/instrumentation/crewai/__init__.py,sha256=_UBKfvQv7l0g2_wnmA5F6CdSAFH0atNOVPd49zsN3aM,88
82
+ langtrace_python_sdk/instrumentation/crewai/instrumentation.py,sha256=W8PLTLzgEdrEx1DCo79wNs9xcuWK0YuxEICLavOESDw,1715
83
+ langtrace_python_sdk/instrumentation/crewai/patch.py,sha256=Vnpip9Pbk4UFbTFHoUrHtAnDgsaihwSvZBgtUeOtLr8,6109
84
+ langtrace_python_sdk/instrumentation/dspy/__init__.py,sha256=tM1srfi_QgyCzrde4izojMrRq2Wm7Dj5QUvVQXIJzkk,84
85
+ langtrace_python_sdk/instrumentation/dspy/instrumentation.py,sha256=Y-_qcH5jCT4TbGvci6Iw0_OWUUlCmovMxnysj6NCnXI,2923
86
+ langtrace_python_sdk/instrumentation/dspy/patch.py,sha256=0zBlrzvGmQEhJpb44L8fkTIhMH5i5pWOkYoSH9e8D6U,9216
76
87
  langtrace_python_sdk/instrumentation/groq/__init__.py,sha256=ZXeq_nrej6Lm_uoMFEg8wbSejhjB2UJ5IoHQBPc2-C0,91
77
88
  langtrace_python_sdk/instrumentation/groq/instrumentation.py,sha256=Ttf07XVKhdYY1_fqJc7QWiSdmgEhEVyQB_3Az2_wqYo,1832
78
89
  langtrace_python_sdk/instrumentation/groq/patch.py,sha256=EKH9tjoDbwWavIAwUadaR5tFiy-S69h1IxxzH_1SSRg,26354
@@ -96,7 +107,7 @@ langtrace_python_sdk/instrumentation/ollama/instrumentation.py,sha256=jdsvkqUJAA
96
107
  langtrace_python_sdk/instrumentation/ollama/patch.py,sha256=CGLgt0qZg3WDr6XLn32qqs4D9USdMmeTmJxctbAsDeM,7908
97
108
  langtrace_python_sdk/instrumentation/openai/__init__.py,sha256=VPHRNCQEdkizIVP2d0Uw_a7t8XOTSTprEIB8oboJFbs,95
98
109
  langtrace_python_sdk/instrumentation/openai/instrumentation.py,sha256=A0BJHRLcZ74TNVg6I0I9M5YWvSpAtXwMmME6N5CEQ_M,2945
99
- langtrace_python_sdk/instrumentation/openai/patch.py,sha256=uUoeeZMAlH8PTZyIObjAI8kU2H5iHuZbPF09Gk70IKo,41103
110
+ langtrace_python_sdk/instrumentation/openai/patch.py,sha256=-eKopJp6m56mg4553wrDr0ibGoCPpYH2iyNMh1lX9yc,36526
100
111
  langtrace_python_sdk/instrumentation/pinecone/__init__.py,sha256=DzXyGh9_MGWveJvXULkFwdkf7PbG2s3bAWtT1Dmz7Ok,99
101
112
  langtrace_python_sdk/instrumentation/pinecone/instrumentation.py,sha256=HDXkRITrVPwdQEoOYJOfMzZE_2-vDDvuqHTlD8W1lQw,1845
102
113
  langtrace_python_sdk/instrumentation/pinecone/patch.py,sha256=KiIRRz8kk47FllFT746Cb_w6F6M60AN_pcsguD979E4,5172
@@ -152,8 +163,8 @@ tests/pinecone/cassettes/test_query.yaml,sha256=b5v9G3ssUy00oG63PlFUR3JErF2Js-5A
152
163
  tests/pinecone/cassettes/test_upsert.yaml,sha256=neWmQ1v3d03V8WoLl8FoFeeCYImb8pxlJBWnFd_lITU,38607
153
164
  tests/qdrant/conftest.py,sha256=9n0uHxxIjWk9fbYc4bx-uP8lSAgLBVx-cV9UjnsyCHM,381
154
165
  tests/qdrant/test_qdrant.py,sha256=pzjAjVY2kmsmGfrI2Gs2xrolfuaNHz7l1fqGQCjp5_o,3353
155
- langtrace_python_sdk-2.1.20.dist-info/METADATA,sha256=0cem4DCsGpcKB8mDxKYrizbmBXNfjyD8tB6ZL3xg2Sk,13161
156
- langtrace_python_sdk-2.1.20.dist-info/WHEEL,sha256=zEMcRr9Kr03x1ozGwg5v9NQBKn3kndp6LSoSlVg-jhU,87
157
- langtrace_python_sdk-2.1.20.dist-info/entry_points.txt,sha256=1_b9-qvf2fE7uQNZcbUei9vLpFZBbbh9LrtGw95ssAo,70
158
- langtrace_python_sdk-2.1.20.dist-info/licenses/LICENSE,sha256=QwcOLU5TJoTeUhuIXzhdCEEDDvorGiC6-3YTOl4TecE,11356
159
- langtrace_python_sdk-2.1.20.dist-info/RECORD,,
166
+ langtrace_python_sdk-2.1.22.dist-info/METADATA,sha256=OBp1W_aK6Om6TkkaFfhhyo-7tSDZ3TC49Hdbs6KdFR0,13161
167
+ langtrace_python_sdk-2.1.22.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
168
+ langtrace_python_sdk-2.1.22.dist-info/entry_points.txt,sha256=1_b9-qvf2fE7uQNZcbUei9vLpFZBbbh9LrtGw95ssAo,70
169
+ langtrace_python_sdk-2.1.22.dist-info/licenses/LICENSE,sha256=QwcOLU5TJoTeUhuIXzhdCEEDDvorGiC6-3YTOl4TecE,11356
170
+ langtrace_python_sdk-2.1.22.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.24.2
2
+ Generator: hatchling 1.25.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any