langtrace-python-sdk 2.1.28__py3-none-any.whl → 2.2.1__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 (55) hide show
  1. examples/cohere_example/chat.py +1 -0
  2. examples/cohere_example/chat_stream.py +3 -0
  3. examples/gemini_example/__init__.py +6 -0
  4. examples/gemini_example/function_tools.py +62 -0
  5. examples/gemini_example/main.py +91 -0
  6. examples/langchain_example/__init__.py +8 -0
  7. examples/langchain_example/groq_example.py +28 -15
  8. examples/ollama_example/basic.py +1 -0
  9. examples/openai_example/__init__.py +1 -0
  10. examples/openai_example/async_tool_calling_nonstreaming.py +1 -1
  11. examples/openai_example/chat_completion.py +1 -1
  12. examples/openai_example/embeddings_create.py +1 -0
  13. examples/openai_example/images_edit.py +2 -2
  14. examples/vertexai_example/__init__.py +6 -0
  15. examples/vertexai_example/main.py +214 -0
  16. langtrace_python_sdk/constants/instrumentation/common.py +2 -0
  17. langtrace_python_sdk/constants/instrumentation/gemini.py +12 -0
  18. langtrace_python_sdk/constants/instrumentation/vertexai.py +42 -0
  19. langtrace_python_sdk/instrumentation/__init__.py +4 -0
  20. langtrace_python_sdk/instrumentation/anthropic/patch.py +68 -96
  21. langtrace_python_sdk/instrumentation/chroma/patch.py +29 -29
  22. langtrace_python_sdk/instrumentation/cohere/patch.py +143 -242
  23. langtrace_python_sdk/instrumentation/gemini/__init__.py +3 -0
  24. langtrace_python_sdk/instrumentation/gemini/instrumentation.py +36 -0
  25. langtrace_python_sdk/instrumentation/gemini/patch.py +186 -0
  26. langtrace_python_sdk/instrumentation/groq/patch.py +82 -125
  27. langtrace_python_sdk/instrumentation/ollama/patch.py +62 -65
  28. langtrace_python_sdk/instrumentation/openai/patch.py +190 -494
  29. langtrace_python_sdk/instrumentation/qdrant/patch.py +6 -6
  30. langtrace_python_sdk/instrumentation/vertexai/__init__.py +3 -0
  31. langtrace_python_sdk/instrumentation/vertexai/instrumentation.py +33 -0
  32. langtrace_python_sdk/instrumentation/vertexai/patch.py +131 -0
  33. langtrace_python_sdk/langtrace.py +7 -1
  34. langtrace_python_sdk/utils/__init__.py +14 -3
  35. langtrace_python_sdk/utils/llm.py +311 -6
  36. langtrace_python_sdk/version.py +1 -1
  37. {langtrace_python_sdk-2.1.28.dist-info → langtrace_python_sdk-2.2.1.dist-info}/METADATA +26 -19
  38. {langtrace_python_sdk-2.1.28.dist-info → langtrace_python_sdk-2.2.1.dist-info}/RECORD +55 -36
  39. tests/anthropic/test_anthropic.py +28 -27
  40. tests/cohere/test_cohere_chat.py +36 -36
  41. tests/cohere/test_cohere_embed.py +12 -9
  42. tests/cohere/test_cohere_rerank.py +18 -11
  43. tests/groq/cassettes/test_async_chat_completion.yaml +113 -0
  44. tests/groq/cassettes/test_async_chat_completion_streaming.yaml +2232 -0
  45. tests/groq/cassettes/test_chat_completion.yaml +114 -0
  46. tests/groq/cassettes/test_chat_completion_streaming.yaml +2512 -0
  47. tests/groq/conftest.py +33 -0
  48. tests/groq/test_groq.py +142 -0
  49. tests/openai/cassettes/test_async_chat_completion_streaming.yaml +28 -28
  50. tests/openai/test_chat_completion.py +53 -67
  51. tests/openai/test_image_generation.py +47 -24
  52. tests/utils.py +40 -5
  53. {langtrace_python_sdk-2.1.28.dist-info → langtrace_python_sdk-2.2.1.dist-info}/WHEEL +0 -0
  54. {langtrace_python_sdk-2.1.28.dist-info → langtrace_python_sdk-2.2.1.dist-info}/entry_points.txt +0 -0
  55. {langtrace_python_sdk-2.1.28.dist-info → langtrace_python_sdk-2.2.1.dist-info}/licenses/LICENSE +0 -0
@@ -1,41 +1,35 @@
1
1
  from langtrace_python_sdk.constants.instrumentation.ollama import APIS
2
- from importlib_metadata import version as v
3
- from langtrace_python_sdk.constants import LANGTRACE_SDK_NAME
4
2
  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,
3
+ from langtrace_python_sdk.utils.llm import (
4
+ get_extra_attributes,
5
+ get_langtrace_attributes,
6
+ get_llm_request_attributes,
7
+ get_llm_url,
8
+ set_event_completion,
9
9
  )
10
- from opentelemetry import baggage
10
+ from langtrace_python_sdk.utils.silently_fail import silently_fail
11
+ from langtrace_python_sdk.constants.instrumentation.common import SERVICE_PROVIDERS
11
12
  from langtrace.trace_attributes import LLMSpanAttributes, Event
12
13
  from opentelemetry.trace import SpanKind
13
14
  import json
14
15
  from opentelemetry.trace.status import Status, StatusCode
16
+ from langtrace.trace_attributes import SpanAttributes
15
17
 
16
18
 
17
19
  def generic_patch(operation_name, version, tracer):
18
20
  def traced_method(wrapped, instance, args, kwargs):
19
- base_url = (
20
- str(instance._client._base_url)
21
- if hasattr(instance, "_client") and hasattr(instance._client, "_base_url")
22
- else ""
23
- )
24
21
  api = APIS[operation_name]
25
22
  service_provider = SERVICE_PROVIDERS["OLLAMA"]
26
- extra_attributes = baggage.get_baggage(LANGTRACE_ADDITIONAL_SPAN_ATTRIBUTES_KEY)
27
23
  span_attributes = {
28
- "langtrace.sdk.name": "langtrace-python-sdk",
29
- "langtrace.service.name": service_provider,
30
- "langtrace.service.type": "llm",
31
- "langtrace.service.version": version,
32
- "langtrace.version": v(LANGTRACE_SDK_NAME),
33
- "llm.model": kwargs.get("model"),
34
- "llm.stream": kwargs.get("stream"),
35
- "url.full": base_url,
36
- "llm.api": api["ENDPOINT"],
37
- "llm.response_format": kwargs.get("format"),
38
- **(extra_attributes if extra_attributes is not None else {}),
24
+ **get_langtrace_attributes(version, service_provider),
25
+ **get_llm_request_attributes(
26
+ kwargs,
27
+ prompts=kwargs.get("messages", None),
28
+ ),
29
+ **get_llm_url(instance),
30
+ SpanAttributes.LLM_PATH: api["ENDPOINT"],
31
+ SpanAttributes.LLM_RESPONSE_FORMAT: kwargs.get("format"),
32
+ **get_extra_attributes(),
39
33
  }
40
34
 
41
35
  attributes = LLMSpanAttributes(**span_attributes)
@@ -77,24 +71,14 @@ def ageneric_patch(operation_name, version, tracer):
77
71
  async def traced_method(wrapped, instance, args, kwargs):
78
72
  api = APIS[operation_name]
79
73
  service_provider = SERVICE_PROVIDERS["OLLAMA"]
80
- extra_attributes = baggage.get_baggage(LANGTRACE_ADDITIONAL_SPAN_ATTRIBUTES_KEY)
81
74
  span_attributes = {
82
- "langtrace.sdk.name": "langtrace-python-sdk",
83
- "langtrace.service.name": service_provider,
84
- "url.full": "",
85
- "llm.api": "",
86
- "langtrace.service.type": "llm",
87
- "langtrace.service.version": version,
88
- "langtrace.version": v(LANGTRACE_SDK_NAME),
89
- "llm.model": kwargs.get("model"),
90
- "llm.stream": kwargs.get("stream"),
91
- "llm.response_format": kwargs.get("format"),
92
- "http.timeout": (
93
- kwargs.get("keep_alive") if "keep_alive" in kwargs else None
94
- ),
95
- **(extra_attributes if extra_attributes is not None else {}),
75
+ **get_langtrace_attributes(version, service_provider),
76
+ **get_llm_request_attributes(kwargs),
77
+ **get_llm_url(instance),
78
+ SpanAttributes.LLM_PATH: api["ENDPOINT"],
79
+ SpanAttributes.LLM_RESPONSE_FORMAT: kwargs.get("format"),
80
+ **get_extra_attributes(),
96
81
  }
97
-
98
82
  attributes = LLMSpanAttributes(**span_attributes)
99
83
  with tracer.start_as_current_span(api["METHOD"], kind=SpanKind.CLIENT) as span:
100
84
  _set_input_attributes(span, kwargs, attributes)
@@ -130,23 +114,25 @@ def _set_response_attributes(span, response):
130
114
  input_tokens = response.get("prompt_eval_count") or 0
131
115
  output_tokens = response.get("eval_count") or 0
132
116
  total_tokens = input_tokens + output_tokens
133
- usage_dict = {
134
- "input_tokens": input_tokens,
135
- "output_tokens": output_tokens,
136
- "total_tokens": total_tokens,
137
- }
138
117
 
139
118
  if total_tokens > 0:
140
- set_span_attribute(span, "llm.token.counts", json.dumps(usage_dict))
141
- set_span_attribute(span, "llm.finish_reason", response.get("done_reason"))
119
+ set_span_attribute(span, SpanAttributes.LLM_USAGE_PROMPT_TOKENS, input_tokens)
120
+ set_span_attribute(
121
+ span, SpanAttributes.LLM_USAGE_COMPLETION_TOKENS, output_tokens
122
+ )
123
+ set_span_attribute(span, SpanAttributes.LLM_USAGE_TOTAL_TOKENS, total_tokens)
124
+
125
+ set_span_attribute(
126
+ span,
127
+ SpanAttributes.LLM_RESPONSE_FINISH_REASON,
128
+ response.get("done_reason"),
129
+ )
142
130
  if "message" in response:
143
- set_span_attribute(span, "llm.responses", json.dumps([response.get("message")]))
131
+ set_event_completion(span, [response.get("message")])
144
132
 
145
133
  if "response" in response:
146
- set_span_attribute(
147
- span,
148
- "llm.responses",
149
- json.dumps([{"role": "assistant", "content": response.get("response")}]),
134
+ set_event_completion(
135
+ span, [{"role": "assistant", "content": response.get("response")}]
150
136
  )
151
137
 
152
138
 
@@ -156,26 +142,23 @@ def _set_input_attributes(span, kwargs, attributes):
156
142
 
157
143
  for field, value in attributes.model_dump(by_alias=True).items():
158
144
  set_span_attribute(span, field, value)
159
- if "messages" in kwargs:
145
+
146
+ if "options" in kwargs:
160
147
  set_span_attribute(
161
148
  span,
162
- "llm.prompts",
163
- json.dumps(kwargs.get("messages", [])),
149
+ SpanAttributes.LLM_REQUEST_TEMPERATURE,
150
+ options.get("temperature"),
164
151
  )
165
- if "prompt" in kwargs:
152
+ set_span_attribute(span, SpanAttributes.LLM_REQUEST_TOP_P, options.get("top_p"))
166
153
  set_span_attribute(
167
154
  span,
168
- "llm.prompts",
169
- json.dumps([{"role": "user", "content": kwargs.get("prompt", "")}]),
155
+ SpanAttributes.LLM_FREQUENCY_PENALTY,
156
+ options.get("frequency_penalty"),
170
157
  )
171
- if "options" in kwargs:
172
- set_span_attribute(span, "llm.temperature", options.get("temperature"))
173
- set_span_attribute(span, "llm.top_p", options.get("top_p"))
174
158
  set_span_attribute(
175
- span, "llm.frequency_penalty", options.get("frequency_penalty")
176
- )
177
- set_span_attribute(
178
- span, "llm.presence_penalty", options.get("presence_penalty")
159
+ span,
160
+ SpanAttributes.LLM_PRESENCE_PENALTY,
161
+ options.get("presence_penalty"),
179
162
  )
180
163
 
181
164
 
@@ -194,6 +177,14 @@ def _handle_streaming_response(span, response, api):
194
177
  if api == "generate":
195
178
  accumulated_tokens["response"] += chunk["response"]
196
179
 
180
+ span.add_event(
181
+ Event.STREAM_OUTPUT.value,
182
+ {
183
+ SpanAttributes.LLM_CONTENT_COMPLETION_CHUNK: chunk.get("response")
184
+ or chunk.get("message").get("content"),
185
+ },
186
+ )
187
+
197
188
  _set_response_attributes(span, chunk | accumulated_tokens)
198
189
  finally:
199
190
  # Finalize span after processing all chunks
@@ -220,6 +211,12 @@ async def _ahandle_streaming_response(span, response, api):
220
211
  if api == "generate":
221
212
  accumulated_tokens["response"] += chunk["response"]
222
213
 
214
+ span.add_event(
215
+ Event.STREAM_OUTPUT.value,
216
+ {
217
+ SpanAttributes.LLM_CONTENT_COMPLETION_CHUNK: json.dumps(chunk),
218
+ },
219
+ )
223
220
  _set_response_attributes(span, chunk | accumulated_tokens)
224
221
  finally:
225
222
  # Finalize span after processing all chunks