langtrace-python-sdk 2.3.2__py3-none-any.whl → 2.3.4__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.
Files changed (30) hide show
  1. examples/anthropic_example/completion.py +1 -1
  2. examples/crewai_example/instagram_post/__init__.py +0 -0
  3. examples/crewai_example/instagram_post/agents.py +96 -0
  4. examples/crewai_example/instagram_post/main.py +80 -0
  5. examples/crewai_example/instagram_post/tasks.py +146 -0
  6. examples/crewai_example/instagram_post/tools/__init__.py +0 -0
  7. examples/crewai_example/instagram_post/tools/browser_tools.py +40 -0
  8. examples/openai_example/__init__.py +1 -0
  9. langtrace_python_sdk/instrumentation/anthropic/instrumentation.py +10 -9
  10. langtrace_python_sdk/instrumentation/anthropic/patch.py +33 -29
  11. langtrace_python_sdk/instrumentation/anthropic/types.py +105 -0
  12. langtrace_python_sdk/instrumentation/cohere/patch.py +1 -4
  13. langtrace_python_sdk/instrumentation/crewai/instrumentation.py +15 -0
  14. langtrace_python_sdk/instrumentation/crewai/patch.py +47 -25
  15. langtrace_python_sdk/instrumentation/gemini/patch.py +2 -5
  16. langtrace_python_sdk/instrumentation/groq/patch.py +7 -19
  17. langtrace_python_sdk/instrumentation/openai/instrumentation.py +14 -19
  18. langtrace_python_sdk/instrumentation/openai/patch.py +93 -101
  19. langtrace_python_sdk/instrumentation/openai/types.py +170 -0
  20. langtrace_python_sdk/instrumentation/vertexai/patch.py +2 -5
  21. langtrace_python_sdk/instrumentation/weaviate/patch.py +3 -13
  22. langtrace_python_sdk/langtrace.py +20 -21
  23. langtrace_python_sdk/utils/llm.py +12 -7
  24. langtrace_python_sdk/utils/silently_fail.py +19 -3
  25. langtrace_python_sdk/version.py +1 -1
  26. {langtrace_python_sdk-2.3.2.dist-info → langtrace_python_sdk-2.3.4.dist-info}/METADATA +1 -1
  27. {langtrace_python_sdk-2.3.2.dist-info → langtrace_python_sdk-2.3.4.dist-info}/RECORD +30 -22
  28. {langtrace_python_sdk-2.3.2.dist-info → langtrace_python_sdk-2.3.4.dist-info}/WHEEL +0 -0
  29. {langtrace_python_sdk-2.3.2.dist-info → langtrace_python_sdk-2.3.4.dist-info}/entry_points.txt +0 -0
  30. {langtrace_python_sdk-2.3.2.dist-info → langtrace_python_sdk-2.3.4.dist-info}/licenses/LICENSE +0 -0
@@ -39,6 +39,21 @@ class CrewAIInstrumentation(BaseInstrumentor):
39
39
  "Crew.kickoff",
40
40
  patch_crew("Crew.kickoff", version, tracer),
41
41
  )
42
+ _W(
43
+ "crewai.crew",
44
+ "Crew.kickoff_for_each",
45
+ patch_crew("Crew.kickoff_for_each", version, tracer),
46
+ )
47
+ _W(
48
+ "crewai.crew",
49
+ "Crew.kickoff_async",
50
+ patch_crew("Crew.kickoff_async", version, tracer),
51
+ )
52
+ _W(
53
+ "crewai.crew",
54
+ "Crew.kickoff_for_each_async",
55
+ patch_crew("Crew.kickoff_for_each_async", version, tracer),
56
+ )
42
57
  _W(
43
58
  "crewai.agent",
44
59
  "Agent.execute_task",
@@ -1,16 +1,18 @@
1
1
  import json
2
+
2
3
  from importlib_metadata import version as v
4
+ from langtrace.trace_attributes import FrameworkSpanAttributes
5
+ from opentelemetry import baggage
6
+ from opentelemetry.trace import Span, SpanKind, Tracer
7
+ from opentelemetry.trace.status import Status, StatusCode
8
+
3
9
  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.llm import get_span_name, set_span_attributes
6
10
  from langtrace_python_sdk.constants.instrumentation.common import (
7
11
  LANGTRACE_ADDITIONAL_SPAN_ATTRIBUTES_KEY,
8
12
  SERVICE_PROVIDERS,
9
13
  )
10
- from opentelemetry import baggage
11
- from langtrace.trace_attributes import FrameworkSpanAttributes
12
- from opentelemetry.trace import SpanKind, Span, Tracer
13
- from opentelemetry.trace.status import Status, StatusCode
14
+ from langtrace_python_sdk.utils import set_span_attribute
15
+ from langtrace_python_sdk.utils.llm import get_span_name, set_span_attributes
14
16
  from langtrace_python_sdk.utils.misc import serialize_args, serialize_kwargs
15
17
 
16
18
 
@@ -44,7 +46,9 @@ def patch_memory(operation_name, version, tracer: Tracer):
44
46
  set_span_attributes(span, attributes)
45
47
  result = wrapped(*args, **kwargs)
46
48
  if result is not None and len(result) > 0:
47
- set_span_attribute(span, "crewai.memory.storage.rag_storage.outputs", str(result))
49
+ set_span_attribute(
50
+ span, "crewai.memory.storage.rag_storage.outputs", str(result)
51
+ )
48
52
  if result:
49
53
  span.set_status(Status(StatusCode.OK))
50
54
  span.end()
@@ -87,20 +91,17 @@ def patch_crew(operation_name, version, tracer: Tracer):
87
91
  CrewAISpanAttributes(span=span, instance=instance)
88
92
  result = wrapped(*args, **kwargs)
89
93
  if result:
94
+ class_name = instance.__class__.__name__
95
+ span.set_attribute(
96
+ f"crewai.{class_name.lower()}.result", str(result)
97
+ )
90
98
  span.set_status(Status(StatusCode.OK))
91
- if instance.__class__.__name__ == "Crew":
92
- span.set_attribute("crewai.crew.result", str(result))
93
- if hasattr(result, "tasks_output"):
94
- span.set_attribute("crewai.crew.tasks_output", str((result.tasks_output)))
95
- if hasattr(result, "token_usage"):
96
- span.set_attribute("crewai.crew.token_usage", str((result.token_usage)))
97
- if hasattr(result, "usage_metrics"):
98
- span.set_attribute("crewai.crew.usage_metrics", str((result.usage_metrics)))
99
- elif instance.__class__.__name__ == "Agent":
100
- span.set_attribute("crewai.agent.result", str(result))
101
- elif instance.__class__.__name__ == "Task":
102
- span.set_attribute("crewai.task.result", str(result))
103
-
99
+ if class_name == "Crew":
100
+ for attr in ["tasks_output", "token_usage", "usage_metrics"]:
101
+ if hasattr(result, attr):
102
+ span.set_attribute(
103
+ f"crewai.crew.{attr}", str(getattr(result, attr))
104
+ )
104
105
  span.end()
105
106
  return result
106
107
 
@@ -137,22 +138,27 @@ class CrewAISpanAttributes:
137
138
  self.set_crew_attributes()
138
139
  for key, value in self.crew.items():
139
140
  key = f"crewai.crew.{key}"
140
- set_span_attribute(self.span, key, value)
141
+ if value is not None:
142
+ set_span_attribute(self.span, key, value)
141
143
 
142
144
  elif instance_name == "Agent":
143
145
  agent = self.set_agent_attributes()
144
146
  for key, value in agent.items():
145
147
  key = f"crewai.agent.{key}"
146
- set_span_attribute(self.span, key, value)
148
+ if value is not None:
149
+ set_span_attribute(self.span, key, value)
147
150
 
148
151
  elif instance_name == "Task":
149
152
  task = self.set_task_attributes()
150
153
  for key, value in task.items():
151
154
  key = f"crewai.task.{key}"
152
- set_span_attribute(self.span, key, value)
155
+ if value is not None:
156
+ set_span_attribute(self.span, key, value)
153
157
 
154
158
  def set_crew_attributes(self):
155
159
  for key, value in self.instance.__dict__.items():
160
+ if value is None:
161
+ continue
156
162
  if key == "tasks":
157
163
  self._parse_tasks(value)
158
164
  elif key == "agents":
@@ -163,6 +169,8 @@ class CrewAISpanAttributes:
163
169
  def set_agent_attributes(self):
164
170
  agent = {}
165
171
  for key, value in self.instance.__dict__.items():
172
+ if key == "tools":
173
+ value = self._parse_tools(value)
166
174
  if value is None:
167
175
  continue
168
176
  agent[key] = str(value)
@@ -174,8 +182,10 @@ class CrewAISpanAttributes:
174
182
  for key, value in self.instance.__dict__.items():
175
183
  if value is None:
176
184
  continue
177
-
178
- if key == "agent":
185
+ if key == "tools":
186
+ value = self._parse_tools(value)
187
+ task[key] = value
188
+ elif key == "agent":
179
189
  task[key] = value.role
180
190
  else:
181
191
  task[key] = str(value)
@@ -218,3 +228,15 @@ class CrewAISpanAttributes:
218
228
  "output_file": task.output_file,
219
229
  }
220
230
  )
231
+
232
+ def _parse_tools(self, tools):
233
+ result = []
234
+ for tool in tools:
235
+ res = {}
236
+ if hasattr(tool, "name") and tool.name is not None:
237
+ res["name"] = tool.name
238
+ if hasattr(tool, "description") and tool.description is not None:
239
+ res["description"] = tool.description
240
+ if res:
241
+ result.append(res)
242
+ return json.dumps(result)
@@ -100,12 +100,9 @@ def apatch_gemini(name, version, tracer: Tracer):
100
100
 
101
101
 
102
102
  def get_llm_model(instance):
103
- llm_model = "unknown"
104
- if hasattr(instance, "_model_id"):
105
- llm_model = instance._model_id
106
103
  if hasattr(instance, "_model_name"):
107
- llm_model = instance._model_name.replace("models/", "")
108
- return llm_model
104
+ return instance._model_name.replace("models/", "")
105
+ return getattr(instance, "_model_id", "unknown")
109
106
 
110
107
 
111
108
  def serialize_prompts(args, kwargs, instance):
@@ -158,7 +158,7 @@ def chat_completions_create(original_method, version, tracer):
158
158
  usage = result.usage
159
159
  set_usage_attributes(span, dict(usage))
160
160
 
161
- span.set_status(StatusCode.OK)
161
+ span.set_status(Status(StatusCode.OK))
162
162
  span.end()
163
163
  return result
164
164
  else:
@@ -257,7 +257,7 @@ def chat_completions_create(original_method, version, tracer):
257
257
  span, [{"role": "assistant", "content": "".join(result_content)}]
258
258
  )
259
259
 
260
- span.set_status(StatusCode.OK)
260
+ span.set_status(Status(StatusCode.OK))
261
261
  span.end()
262
262
 
263
263
  # return the wrapped method
@@ -282,21 +282,13 @@ def async_chat_completions_create(original_method, version, tracer):
282
282
  tool_calls = []
283
283
  for tool_call in item.tool_calls:
284
284
  tool_call_dict = {
285
- "id": tool_call.id if hasattr(tool_call, "id") else "",
286
- "type": tool_call.type if hasattr(tool_call, "type") else "",
285
+ "id": getattr(tool_call, "id", ""),
286
+ "type": getattr(tool_call, "type", ""),
287
287
  }
288
288
  if hasattr(tool_call, "function"):
289
289
  tool_call_dict["function"] = {
290
- "name": (
291
- tool_call.function.name
292
- if hasattr(tool_call.function, "name")
293
- else ""
294
- ),
295
- "arguments": (
296
- tool_call.function.arguments
297
- if hasattr(tool_call.function, "arguments")
298
- else ""
299
- ),
290
+ "name": getattr(tool_call.function, "name", ""),
291
+ "arguments": getattr(tool_call.function, "arguments", ""),
300
292
  }
301
293
  tool_calls.append(tool_call_dict)
302
294
  llm_prompts.append(tool_calls)
@@ -459,11 +451,7 @@ def async_chat_completions_create(original_method, version, tracer):
459
451
  tool_call.function.arguments
460
452
  )
461
453
  completion_tokens += token_counts
462
- content = content + [
463
- tool_call.function.arguments
464
- ]
465
- else:
466
- content = content + []
454
+ content += [tool_call.function.arguments]
467
455
  else:
468
456
  content = []
469
457
  span.add_event(
@@ -1,12 +1,9 @@
1
1
  """
2
2
  Copyright (c) 2024 Scale3 Labs
3
-
4
3
  Licensed under the Apache License, Version 2.0 (the "License");
5
4
  you may not use this file except in compliance with the License.
6
5
  You may obtain a copy of the License at
7
-
8
6
  http://www.apache.org/licenses/LICENSE-2.0
9
-
10
7
  Unless required by applicable law or agreed to in writing, software
11
8
  distributed under the License is distributed on an "AS IS" BASIS,
12
9
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -14,12 +11,12 @@ See the License for the specific language governing permissions and
14
11
  limitations under the License.
15
12
  """
16
13
 
14
+ from typing import Collection, Optional, Any
17
15
  import importlib.metadata
18
16
  import logging
19
- from typing import Collection
20
17
 
21
18
  from opentelemetry.instrumentation.instrumentor import BaseInstrumentor
22
- from opentelemetry.trace import get_tracer
19
+ from opentelemetry.trace import get_tracer, TracerProvider
23
20
  from wrapt import wrap_function_wrapper
24
21
 
25
22
  from langtrace_python_sdk.instrumentation.openai.patch import (
@@ -35,59 +32,57 @@ from langtrace_python_sdk.instrumentation.openai.patch import (
35
32
  logging.basicConfig(level=logging.FATAL)
36
33
 
37
34
 
38
- class OpenAIInstrumentation(BaseInstrumentor):
35
+ class OpenAIInstrumentation(BaseInstrumentor): # type: ignore
39
36
 
40
37
  def instrumentation_dependencies(self) -> Collection[str]:
41
38
  return ["openai >= 0.27.0", "trace-attributes >= 4.0.5"]
42
39
 
43
- def _instrument(self, **kwargs):
44
- tracer_provider = kwargs.get("tracer_provider")
40
+ def _instrument(self, **kwargs: Any) -> None:
41
+ tracer_provider: Optional[TracerProvider] = kwargs.get("tracer_provider")
45
42
  tracer = get_tracer(__name__, "", tracer_provider)
46
- version = importlib.metadata.version("openai")
43
+ version: str = importlib.metadata.version("openai")
47
44
 
48
45
  wrap_function_wrapper(
49
46
  "openai.resources.chat.completions",
50
47
  "Completions.create",
51
- chat_completions_create("openai.chat.completions.create", version, tracer),
48
+ chat_completions_create(version, tracer),
52
49
  )
53
50
 
54
51
  wrap_function_wrapper(
55
52
  "openai.resources.chat.completions",
56
53
  "AsyncCompletions.create",
57
- async_chat_completions_create(
58
- "openai.chat.completions.create_stream", version, tracer
59
- ),
54
+ async_chat_completions_create(version, tracer),
60
55
  )
61
56
 
62
57
  wrap_function_wrapper(
63
58
  "openai.resources.images",
64
59
  "Images.generate",
65
- images_generate("openai.images.generate", version, tracer),
60
+ images_generate(version, tracer),
66
61
  )
67
62
 
68
63
  wrap_function_wrapper(
69
64
  "openai.resources.images",
70
65
  "AsyncImages.generate",
71
- async_images_generate("openai.images.generate", version, tracer),
66
+ async_images_generate(version, tracer),
72
67
  )
73
68
 
74
69
  wrap_function_wrapper(
75
70
  "openai.resources.images",
76
71
  "Images.edit",
77
- images_edit("openai.images.edit", version, tracer),
72
+ images_edit(version, tracer),
78
73
  )
79
74
 
80
75
  wrap_function_wrapper(
81
76
  "openai.resources.embeddings",
82
77
  "Embeddings.create",
83
- embeddings_create("openai.embeddings.create", version, tracer),
78
+ embeddings_create(version, tracer),
84
79
  )
85
80
 
86
81
  wrap_function_wrapper(
87
82
  "openai.resources.embeddings",
88
83
  "AsyncEmbeddings.create",
89
- async_embeddings_create("openai.embeddings.create", version, tracer),
84
+ async_embeddings_create(version, tracer),
90
85
  )
91
86
 
92
- def _uninstrument(self, **kwargs):
87
+ def _uninstrument(self, **kwargs: Any) -> None:
93
88
  pass