langtrace-python-sdk 3.3.14__py3-none-any.whl → 3.3.16__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,8 +1,11 @@
1
1
  from examples.cohere_example.chat import chat_comp
2
+ from examples.cohere_example.chatv2 import chat_v2
3
+ from examples.cohere_example.chat_streamv2 import chat_stream_v2
2
4
  from examples.cohere_example.chat_stream import chat_stream
3
5
  from examples.cohere_example.tools import tool_calling
4
6
  from examples.cohere_example.embed import embed
5
7
  from examples.cohere_example.rerank import rerank
8
+ from examples.cohere_example.rerankv2 import rerank_v2
6
9
  from langtrace_python_sdk import with_langtrace_root_span
7
10
 
8
11
 
@@ -10,8 +13,11 @@ class CohereRunner:
10
13
 
11
14
  @with_langtrace_root_span("Cohere")
12
15
  def run(self):
16
+ chat_v2()
17
+ chat_stream_v2()
13
18
  chat_comp()
14
19
  chat_stream()
15
20
  tool_calling()
16
21
  embed()
17
22
  rerank()
23
+ rerank_v2()
@@ -0,0 +1,17 @@
1
+ import os
2
+ from langtrace_python_sdk import langtrace
3
+ import cohere
4
+
5
+ langtrace.init(api_key=os.getenv("LANGTRACE_API_KEY"))
6
+ co = cohere.ClientV2(api_key=os.getenv("COHERE_API_KEY"))
7
+
8
+ def chat_stream_v2():
9
+ res = co.chat_stream(
10
+ model="command-r-plus-08-2024",
11
+ messages=[{"role": "user", "content": "Write a title for a blog post about API design. Only output the title text"}],
12
+ )
13
+
14
+ for event in res:
15
+ if event:
16
+ if event.type == "content-delta":
17
+ print(event.delta.message.content.text)
@@ -0,0 +1,21 @@
1
+ import os
2
+ from langtrace_python_sdk import langtrace
3
+ import cohere
4
+
5
+ langtrace.init(api_key=os.getenv("LANGTRACE_API_KEY"))
6
+
7
+
8
+ def chat_v2():
9
+ co = cohere.ClientV2(api_key=os.getenv("COHERE_API_KEY"))
10
+
11
+ res = co.chat(
12
+ model="command-r-plus-08-2024",
13
+ messages=[
14
+ {
15
+ "role": "user",
16
+ "content": "Write a title for a blog post about API design. Only output the title text.",
17
+ }
18
+ ],
19
+ )
20
+
21
+ print(res.message.content[0].text)
@@ -0,0 +1,23 @@
1
+ import os
2
+ from langtrace_python_sdk import langtrace
3
+ import cohere
4
+
5
+ langtrace.init(api_key=os.getenv("LANGTRACE_API_KEY"))
6
+ co = cohere.ClientV2(api_key=os.getenv("COHERE_API_KEY"))
7
+
8
+ docs = [
9
+ "Carson City is the capital city of the American state of Nevada.",
10
+ "The Commonwealth of the Northern Mariana Islands is a group of islands in the Pacific Ocean. Its capital is Saipan.",
11
+ "Capitalization or capitalisation in English grammar is the use of a capital letter at the start of a word. English usage varies from capitalization in other languages.",
12
+ "Washington, D.C. (also known as simply Washington or D.C., and officially as the District of Columbia) is the capital of the United States. It is a federal district.",
13
+ "Capital punishment has existed in the United States since beforethe United States was a country. As of 2017, capital punishment is legal in 30 of the 50 states.",
14
+ ]
15
+
16
+ def rerank_v2():
17
+ response = co.rerank(
18
+ model="rerank-v3.5",
19
+ query="What is the capital of the United States?",
20
+ documents=docs,
21
+ top_n=3,
22
+ )
23
+ print(response)
@@ -1 +1,2 @@
1
- LANGTRACE_REMOTE_URL = "https://app.langtrace.ai"
1
+ LANGTRACE_REMOTE_URL = "https://app.langtrace.ai"
2
+ LANGTRACE_SESSION_ID_HEADER = "x-langtrace-session-id"
@@ -4,19 +4,39 @@ APIS = {
4
4
  "METHOD": "cohere.client.chat",
5
5
  "ENDPOINT": "/v1/chat",
6
6
  },
7
+ "CHAT_CREATE_V2": {
8
+ "URL": "https://api.cohere.ai",
9
+ "METHOD": "cohere.client_v2.chat",
10
+ "ENDPOINT": "/v2/chat",
11
+ },
7
12
  "EMBED": {
8
13
  "URL": "https://api.cohere.ai",
9
14
  "METHOD": "cohere.client.embed",
10
15
  "ENDPOINT": "/v1/embed",
11
16
  },
17
+ "EMBED_V2": {
18
+ "URL": "https://api.cohere.ai",
19
+ "METHOD": "cohere.client_v2.embed",
20
+ "ENDPOINT": "/v2/embed",
21
+ },
12
22
  "CHAT_STREAM": {
13
23
  "URL": "https://api.cohere.ai",
14
24
  "METHOD": "cohere.client.chat_stream",
15
- "ENDPOINT": "/v1/messages",
25
+ "ENDPOINT": "/v1/chat",
26
+ },
27
+ "CHAT_STREAM_V2": {
28
+ "URL": "https://api.cohere.ai",
29
+ "METHOD": "cohere.client_v2.chat_stream",
30
+ "ENDPOINT": "/v2/chat",
16
31
  },
17
32
  "RERANK": {
18
33
  "URL": "https://api.cohere.ai",
19
34
  "METHOD": "cohere.client.rerank",
20
35
  "ENDPOINT": "/v1/rerank",
21
36
  },
37
+ "RERANK_V2": {
38
+ "URL": "https://api.cohere.ai",
39
+ "METHOD": "cohere.client_v2.rerank",
40
+ "ENDPOINT": "/v2/rerank",
41
+ },
22
42
  }
@@ -9,6 +9,7 @@ from opentelemetry.trace.span import format_trace_id
9
9
 
10
10
  from langtrace_python_sdk.constants.exporter.langtrace_exporter import (
11
11
  LANGTRACE_REMOTE_URL,
12
+ LANGTRACE_SESSION_ID_HEADER,
12
13
  )
13
14
  from colorama import Fore
14
15
  from requests.exceptions import RequestException
@@ -51,12 +52,14 @@ class LangTraceExporter(SpanExporter):
51
52
  api_key: str
52
53
  api_host: str
53
54
  disable_logging: bool
55
+ session_id: str
54
56
 
55
57
  def __init__(
56
58
  self,
57
59
  api_host,
58
60
  api_key: str = None,
59
61
  disable_logging: bool = False,
62
+ session_id: str = None,
60
63
  ) -> None:
61
64
  self.api_key = api_key or os.environ.get("LANGTRACE_API_KEY")
62
65
  self.api_host = (
@@ -65,6 +68,7 @@ class LangTraceExporter(SpanExporter):
65
68
  else api_host
66
69
  )
67
70
  self.disable_logging = disable_logging
71
+ self.session_id = session_id or os.environ.get("LANGTRACE_SESSION_ID")
68
72
 
69
73
  def export(self, spans: typing.Sequence[ReadableSpan]) -> SpanExportResult:
70
74
  """
@@ -82,6 +86,10 @@ class LangTraceExporter(SpanExporter):
82
86
  "User-Agent": "LangtraceExporter",
83
87
  }
84
88
 
89
+ # Add session ID if available
90
+ if self.session_id:
91
+ headers[LANGTRACE_SESSION_ID_HEADER] = self.session_id
92
+
85
93
  # Check if the OTEL_EXPORTER_OTLP_HEADERS environment variable is set
86
94
  otel_headers = os.getenv("OTEL_EXPORTER_OTLP_HEADERS", None)
87
95
  if otel_headers:
@@ -23,6 +23,7 @@ from wrapt import wrap_function_wrapper
23
23
 
24
24
  from langtrace_python_sdk.instrumentation.cohere.patch import (
25
25
  chat_create,
26
+ chat_create_v2,
26
27
  chat_stream,
27
28
  embed,
28
29
  rerank,
@@ -48,6 +49,18 @@ class CohereInstrumentation(BaseInstrumentor):
48
49
  chat_create("cohere.client.chat", version, tracer),
49
50
  )
50
51
 
52
+ wrap_function_wrapper(
53
+ "cohere.client_v2",
54
+ "ClientV2.chat",
55
+ chat_create_v2("cohere.client_v2.chat", version, tracer),
56
+ )
57
+
58
+ wrap_function_wrapper(
59
+ "cohere.client_v2",
60
+ "ClientV2.chat_stream",
61
+ chat_create_v2("cohere.client_v2.chat", version, tracer, stream=True),
62
+ )
63
+
51
64
  wrap_function_wrapper(
52
65
  "cohere.client",
53
66
  "Client.chat_stream",
@@ -60,12 +73,24 @@ class CohereInstrumentation(BaseInstrumentor):
60
73
  embed("cohere.client.embed", version, tracer),
61
74
  )
62
75
 
76
+ wrap_function_wrapper(
77
+ "cohere.client_v2",
78
+ "ClientV2.embed",
79
+ embed("cohere.client.embed", version, tracer, v2=True),
80
+ )
81
+
63
82
  wrap_function_wrapper(
64
83
  "cohere.client",
65
84
  "Client.rerank",
66
85
  rerank("cohere.client.rerank", version, tracer),
67
86
  )
68
87
 
88
+ wrap_function_wrapper(
89
+ "cohere.client_v2",
90
+ "ClientV2.rerank",
91
+ rerank("cohere.client.rerank", version, tracer, v2=True),
92
+ )
93
+
69
94
  def _instrument_module(self, module_name):
70
95
  pass
71
96
 
@@ -24,6 +24,7 @@ from langtrace_python_sdk.utils.llm import (
24
24
  get_span_name,
25
25
  set_event_completion,
26
26
  set_usage_attributes,
27
+ StreamWrapper
27
28
  )
28
29
  from langtrace.trace_attributes import Event, LLMSpanAttributes
29
30
  from langtrace_python_sdk.utils import set_span_attribute
@@ -38,7 +39,7 @@ from langtrace_python_sdk.constants.instrumentation.common import (
38
39
  from langtrace.trace_attributes import SpanAttributes
39
40
 
40
41
 
41
- def rerank(original_method, version, tracer):
42
+ def rerank(original_method, version, tracer, v2=False):
42
43
  """Wrap the `rerank` method."""
43
44
 
44
45
  def traced_method(wrapped, instance, args, kwargs):
@@ -49,8 +50,8 @@ def rerank(original_method, version, tracer):
49
50
  **get_llm_request_attributes(kwargs, operation_name="rerank"),
50
51
  **get_llm_url(instance),
51
52
  SpanAttributes.LLM_REQUEST_MODEL: kwargs.get("model") or "command-r-plus",
52
- SpanAttributes.LLM_URL: APIS["RERANK"]["URL"],
53
- SpanAttributes.LLM_PATH: APIS["RERANK"]["ENDPOINT"],
53
+ SpanAttributes.LLM_URL: APIS["RERANK" if not v2 else "RERANK_V2"]["URL"],
54
+ SpanAttributes.LLM_PATH: APIS["RERANK" if not v2 else "RERANK_V2"]["ENDPOINT"],
54
55
  SpanAttributes.LLM_REQUEST_DOCUMENTS: json.dumps(
55
56
  kwargs.get("documents"), cls=datetime_encoder
56
57
  ),
@@ -61,7 +62,7 @@ def rerank(original_method, version, tracer):
61
62
  attributes = LLMSpanAttributes(**span_attributes)
62
63
 
63
64
  span = tracer.start_span(
64
- name=get_span_name(APIS["RERANK"]["METHOD"]), kind=SpanKind.CLIENT
65
+ name=get_span_name(APIS["RERANK" if not v2 else "RERANK_V2"]["METHOD"]), kind=SpanKind.CLIENT
65
66
  )
66
67
  for field, value in attributes.model_dump(by_alias=True).items():
67
68
  set_span_attribute(span, field, value)
@@ -119,7 +120,7 @@ def rerank(original_method, version, tracer):
119
120
  return traced_method
120
121
 
121
122
 
122
- def embed(original_method, version, tracer):
123
+ def embed(original_method, version, tracer, v2=False):
123
124
  """Wrap the `embed` method."""
124
125
 
125
126
  def traced_method(wrapped, instance, args, kwargs):
@@ -129,8 +130,8 @@ def embed(original_method, version, tracer):
129
130
  **get_langtrace_attributes(version, service_provider),
130
131
  **get_llm_request_attributes(kwargs, operation_name="embed"),
131
132
  **get_llm_url(instance),
132
- SpanAttributes.LLM_URL: APIS["EMBED"]["URL"],
133
- SpanAttributes.LLM_PATH: APIS["EMBED"]["ENDPOINT"],
133
+ SpanAttributes.LLM_URL: APIS["EMBED" if not v2 else "EMBED_V2"]["URL"],
134
+ SpanAttributes.LLM_PATH: APIS["EMBED" if not v2 else "EMBED_V2"]["ENDPOINT"],
134
135
  SpanAttributes.LLM_REQUEST_EMBEDDING_INPUTS: json.dumps(
135
136
  kwargs.get("texts")
136
137
  ),
@@ -143,7 +144,7 @@ def embed(original_method, version, tracer):
143
144
  attributes = LLMSpanAttributes(**span_attributes)
144
145
 
145
146
  span = tracer.start_span(
146
- name=get_span_name(APIS["EMBED"]["METHOD"]),
147
+ name=get_span_name(APIS["EMBED" if not v2 else "EMBED_V2"]["METHOD"]),
147
148
  kind=SpanKind.CLIENT,
148
149
  )
149
150
  for field, value in attributes.model_dump(by_alias=True).items():
@@ -343,6 +344,103 @@ def chat_create(original_method, version, tracer):
343
344
  return traced_method
344
345
 
345
346
 
347
+ def chat_create_v2(original_method, version, tracer, stream=False):
348
+ """Wrap the `chat_create` method for Cohere API v2."""
349
+
350
+ def traced_method(wrapped, instance, args, kwargs):
351
+ service_provider = SERVICE_PROVIDERS["COHERE"]
352
+
353
+ messages = kwargs.get("messages", [])
354
+ if kwargs.get("preamble"):
355
+ messages = [{"role": "system", "content": kwargs["preamble"]}] + messages
356
+
357
+ span_attributes = {
358
+ **get_langtrace_attributes(version, service_provider),
359
+ **get_llm_request_attributes(kwargs, prompts=messages),
360
+ **get_llm_url(instance),
361
+ SpanAttributes.LLM_REQUEST_MODEL: kwargs.get("model") or "command-r-plus",
362
+ SpanAttributes.LLM_URL: APIS["CHAT_CREATE_V2"]["URL"],
363
+ SpanAttributes.LLM_PATH: APIS["CHAT_CREATE_V2"]["ENDPOINT"],
364
+ **get_extra_attributes(),
365
+ }
366
+
367
+ attributes = LLMSpanAttributes(**span_attributes)
368
+
369
+ for attr_name in ["max_input_tokens", "conversation_id", "connectors", "tools", "tool_results"]:
370
+ value = kwargs.get(attr_name)
371
+ if value is not None:
372
+ if attr_name == "max_input_tokens":
373
+ attributes.llm_max_input_tokens = str(value)
374
+ elif attr_name == "conversation_id":
375
+ attributes.conversation_id = value
376
+ else:
377
+ setattr(attributes, f"llm_{attr_name}", json.dumps(value))
378
+
379
+ span = tracer.start_span(
380
+ name=get_span_name(APIS["CHAT_CREATE_V2"]["METHOD"]),
381
+ kind=SpanKind.CLIENT
382
+ )
383
+
384
+ for field, value in attributes.model_dump(by_alias=True).items():
385
+ set_span_attribute(span, field, value)
386
+
387
+ try:
388
+ result = wrapped(*args, **kwargs)
389
+
390
+ if stream:
391
+ return StreamWrapper(
392
+ result,
393
+ span,
394
+ tool_calls=kwargs.get("tools") is not None,
395
+ )
396
+ else:
397
+ if hasattr(result, "id") and result.id is not None:
398
+ span.set_attribute(SpanAttributes.LLM_GENERATION_ID, result.id)
399
+ span.set_attribute(SpanAttributes.LLM_RESPONSE_ID, result.id)
400
+
401
+ if (hasattr(result, "message") and
402
+ hasattr(result.message, "content") and
403
+ len(result.message.content) > 0 and
404
+ hasattr(result.message.content[0], "text") and
405
+ result.message.content[0].text is not None and
406
+ result.message.content[0].text != ""):
407
+ responses = [{
408
+ "role": result.message.role,
409
+ "content": result.message.content[0].text
410
+ }]
411
+ set_event_completion(span, responses)
412
+ if hasattr(result, "tool_calls") and result.tool_calls is not None:
413
+ tool_calls = [tool_call.json() for tool_call in result.tool_calls]
414
+ span.set_attribute(
415
+ SpanAttributes.LLM_TOOL_RESULTS,
416
+ json.dumps(tool_calls)
417
+ )
418
+ if hasattr(result, "usage") and result.usage is not None:
419
+ if (hasattr(result.usage, "billed_units") and
420
+ result.usage.billed_units is not None):
421
+ usage = result.usage.billed_units
422
+ for metric, value in {
423
+ "input": usage.input_tokens or 0,
424
+ "output": usage.output_tokens or 0,
425
+ "total": (usage.input_tokens or 0) + (usage.output_tokens or 0),
426
+ }.items():
427
+ span.set_attribute(
428
+ f"gen_ai.usage.{metric}_tokens",
429
+ int(value)
430
+ )
431
+ span.set_status(StatusCode.OK)
432
+ span.end()
433
+ return result
434
+
435
+ except Exception as error:
436
+ span.record_exception(error)
437
+ span.set_status(Status(StatusCode.ERROR, str(error)))
438
+ span.end()
439
+ raise
440
+
441
+ return traced_method
442
+
443
+
346
444
  def chat_stream(original_method, version, tracer):
347
445
  """Wrap the `messages_stream` method."""
348
446
 
@@ -50,7 +50,7 @@ def patch_bootstrapfewshot_optimizer(operation_name, version, tracer):
50
50
  ),
51
51
  }
52
52
  span_attributes["dspy.optimizer.module.prog"] = json.dumps(prog)
53
- if hasattr(instance, "metric"):
53
+ if hasattr(instance, "metric") and getattr(instance, "metric") is not None:
54
54
  span_attributes["dspy.optimizer.metric"] = getattr(
55
55
  instance, "metric"
56
56
  ).__name__
@@ -120,8 +120,6 @@ def patch_signature(operation_name, version, tracer):
120
120
  **get_extra_attributes(),
121
121
  }
122
122
 
123
- trace_checkpoint = os.environ.get("TRACE_DSPY_CHECKPOINT", "true").lower()
124
-
125
123
  if instance.__class__.__name__:
126
124
  span_attributes["dspy.signature.name"] = instance.__class__.__name__
127
125
  span_attributes["dspy.signature"] = str(instance.signature)
@@ -143,9 +141,6 @@ def patch_signature(operation_name, version, tracer):
143
141
  "dspy.signature.result",
144
142
  json.dumps(result.toDict()),
145
143
  )
146
- if trace_checkpoint == "true":
147
- print(Fore.RED + "Note: DSPy checkpoint tracing is enabled in Langtrace. To disable it, set the env var, TRACE_DSPY_CHECKPOINT to false" + Fore.RESET)
148
- set_span_attribute(span, "dspy.checkpoint", ujson.dumps(instance.dump_state(False), indent=2))
149
144
  span.set_status(Status(StatusCode.OK))
150
145
 
151
146
  span.end()
@@ -342,8 +342,12 @@ def async_chat_completions_create(version: str, tracer: Tracer) -> Callable:
342
342
  service_provider = SERVICE_PROVIDERS["PPLX"]
343
343
  elif "azure" in get_base_url(instance):
344
344
  service_provider = SERVICE_PROVIDERS["AZURE"]
345
+ elif "groq" in get_base_url(instance):
346
+ service_provider = SERVICE_PROVIDERS["GROQ"]
345
347
  elif "x.ai" in get_base_url(instance):
346
348
  service_provider = SERVICE_PROVIDERS["XAI"]
349
+ elif "deepseek" in get_base_url(instance):
350
+ service_provider = SERVICE_PROVIDERS["DEEPSEEK"]
347
351
  llm_prompts = []
348
352
  for item in kwargs.get("messages", []):
349
353
  tools = get_tool_calls(item)
@@ -431,6 +435,18 @@ def embeddings_create(version: str, tracer: Tracer) -> Callable:
431
435
  kwargs: EmbeddingsCreateKwargs,
432
436
  ) -> Any:
433
437
  service_provider = SERVICE_PROVIDERS["OPENAI"]
438
+ base_url = get_base_url(instance)
439
+
440
+ if "perplexity" in base_url:
441
+ service_provider = SERVICE_PROVIDERS["PPLX"]
442
+ elif "azure" in base_url:
443
+ service_provider = SERVICE_PROVIDERS["AZURE"]
444
+ elif "groq" in base_url:
445
+ service_provider = SERVICE_PROVIDERS["GROQ"]
446
+ elif "x.ai" in base_url:
447
+ service_provider = SERVICE_PROVIDERS["XAI"]
448
+ elif "deepseek" in base_url:
449
+ service_provider = SERVICE_PROVIDERS["DEEPSEEK"]
434
450
 
435
451
  span_attributes = {
436
452
  **get_langtrace_attributes(version, service_provider, vendor_type="llm"),
@@ -469,7 +485,6 @@ def embeddings_create(version: str, tracer: Tracer) -> Callable:
469
485
  kind=SpanKind.CLIENT,
470
486
  context=set_span_in_context(trace.get_current_span()),
471
487
  ) as span:
472
-
473
488
  set_span_attributes(span, attributes)
474
489
  try:
475
490
  # Attempt to call the original method
@@ -507,17 +522,27 @@ def async_embeddings_create(version: str, tracer: Tracer) -> Callable:
507
522
  ) -> Awaitable[Any]:
508
523
 
509
524
  service_provider = SERVICE_PROVIDERS["OPENAI"]
525
+ base_url = get_base_url(instance)
526
+ if "perplexity" in base_url:
527
+ service_provider = SERVICE_PROVIDERS["PPLX"]
528
+ elif "azure" in base_url:
529
+ service_provider = SERVICE_PROVIDERS["AZURE"]
530
+ elif "groq" in base_url:
531
+ service_provider = SERVICE_PROVIDERS["GROQ"]
532
+ elif "x.ai" in base_url:
533
+ service_provider = SERVICE_PROVIDERS["XAI"]
534
+ elif "deepseek" in base_url:
535
+ service_provider = SERVICE_PROVIDERS["DEEPSEEK"]
510
536
 
511
537
  span_attributes = {
512
538
  **get_langtrace_attributes(version, service_provider, vendor_type="llm"),
513
539
  **get_llm_request_attributes(kwargs, operation_name="embed"),
540
+ **get_llm_url(instance),
514
541
  SpanAttributes.LLM_PATH: APIS["EMBEDDINGS_CREATE"]["ENDPOINT"],
515
542
  SpanAttributes.LLM_REQUEST_DIMENSIONS: kwargs.get("dimensions"),
516
543
  **get_extra_attributes(), # type: ignore
517
544
  }
518
545
 
519
- attributes = LLMSpanAttributes(**filter_valid_attributes(span_attributes))
520
-
521
546
  encoding_format = kwargs.get("encoding_format")
522
547
  if encoding_format is not None:
523
548
  if not isinstance(encoding_format, list):
@@ -530,17 +555,31 @@ def async_embeddings_create(version: str, tracer: Tracer) -> Callable:
530
555
  span_attributes[SpanAttributes.LLM_REQUEST_EMBEDDING_INPUTS] = json.dumps(
531
556
  [kwargs.get("input", "")]
532
557
  )
558
+ span_attributes[SpanAttributes.LLM_PROMPTS] = json.dumps(
559
+ [
560
+ {
561
+ "role": "user",
562
+ "content": kwargs.get("input"),
563
+ }
564
+ ]
565
+ )
566
+
567
+ attributes = LLMSpanAttributes(**filter_valid_attributes(span_attributes))
533
568
 
534
569
  with tracer.start_as_current_span(
535
570
  name=get_span_name(APIS["EMBEDDINGS_CREATE"]["METHOD"]),
536
571
  kind=SpanKind.CLIENT,
537
572
  context=set_span_in_context(trace.get_current_span()),
538
573
  ) as span:
539
-
540
574
  set_span_attributes(span, attributes)
541
575
  try:
542
576
  # Attempt to call the original method
543
577
  result = await wrapped(*args, **kwargs)
578
+ usage = getattr(result, "usage", None)
579
+ if usage:
580
+ set_usage_attributes(
581
+ span, {"prompt_tokens": getattr(usage, "prompt_tokens", 0)}
582
+ )
544
583
  span.set_status(StatusCode.OK)
545
584
  return result
546
585
  except Exception as err:
@@ -39,6 +39,7 @@ from opentelemetry.exporter.otlp.proto.http.trace_exporter import (
39
39
  )
40
40
  from langtrace_python_sdk.constants.exporter.langtrace_exporter import (
41
41
  LANGTRACE_REMOTE_URL,
42
+ LANGTRACE_SESSION_ID_HEADER,
42
43
  )
43
44
  from langtrace_python_sdk.instrumentation import (
44
45
  AnthropicInstrumentation,
@@ -98,6 +99,9 @@ class LangtraceConfig:
98
99
  or os.environ.get("LANGTRACE_HEADERS")
99
100
  or os.environ.get("OTEL_EXPORTER_OTLP_HEADERS")
100
101
  )
102
+ self.session_id = kwargs.get("session_id") or os.environ.get(
103
+ "LANGTRACE_SESSION_ID"
104
+ )
101
105
 
102
106
 
103
107
  def get_host(config: LangtraceConfig) -> str:
@@ -134,15 +138,19 @@ def setup_tracer_provider(config: LangtraceConfig, host: str) -> TracerProvider:
134
138
 
135
139
 
136
140
  def get_headers(config: LangtraceConfig):
137
- if not config.headers:
138
- return {
139
- "x-api-key": config.api_key,
140
- }
141
+ headers = {
142
+ "x-api-key": config.api_key,
143
+ }
144
+
145
+ if config.session_id:
146
+ headers[LANGTRACE_SESSION_ID_HEADER] = config.session_id
141
147
 
142
148
  if isinstance(config.headers, str):
143
- return parse_env_headers(config.headers, liberal=True)
149
+ headers.update(parse_env_headers(config.headers, liberal=True))
150
+ elif config.headers:
151
+ headers.update(config.headers)
144
152
 
145
- return config.headers
153
+ return headers
146
154
 
147
155
 
148
156
  def get_exporter(config: LangtraceConfig, host: str):
@@ -150,9 +158,16 @@ def get_exporter(config: LangtraceConfig, host: str):
150
158
  return config.custom_remote_exporter
151
159
 
152
160
  headers = get_headers(config)
153
- host = f"{host}/api/trace" if host == LANGTRACE_REMOTE_URL else host
154
- if "http" in host.lower() or "https" in host.lower():
155
- return HTTPExporter(endpoint=host, headers=headers)
161
+ exporter_protocol = os.environ.get("OTEL_EXPORTER_OTLP_PROTOCOL", "http")
162
+ if "http" in exporter_protocol.lower():
163
+ return HTTPExporter(
164
+ endpoint=(
165
+ f"{host}/api/trace"
166
+ if host == LANGTRACE_REMOTE_URL
167
+ else f"{host}/v1/traces"
168
+ ),
169
+ headers=headers,
170
+ )
156
171
  else:
157
172
  return GRPCExporter(endpoint=host, headers=headers)
158
173
 
@@ -215,6 +230,7 @@ def init(
215
230
  service_name: Optional[str] = None,
216
231
  disable_logging: bool = False,
217
232
  headers: Dict[str, str] = {},
233
+ session_id: Optional[str] = None,
218
234
  ):
219
235
 
220
236
  check_if_sdk_is_outdated()
@@ -229,6 +245,7 @@ def init(
229
245
  service_name=service_name,
230
246
  disable_logging=disable_logging,
231
247
  headers=headers,
248
+ session_id=session_id,
232
249
  )
233
250
 
234
251
  if config.disable_logging:
@@ -162,11 +162,12 @@ def get_llm_url(instance):
162
162
 
163
163
 
164
164
  def get_base_url(instance):
165
- return (
165
+ base_url = (
166
166
  str(instance._client._base_url)
167
167
  if hasattr(instance, "_client") and hasattr(instance._client, "_base_url")
168
168
  else ""
169
169
  )
170
+ return base_url
170
171
 
171
172
 
172
173
  def is_streaming(kwargs):
@@ -393,8 +394,19 @@ class StreamWrapper:
393
394
  if hasattr(chunk, "text") and chunk.text is not None:
394
395
  content = [chunk.text]
395
396
 
397
+ # CohereV2
398
+ if (hasattr(chunk, "delta") and
399
+ chunk.delta is not None and
400
+ hasattr(chunk.delta, "message") and
401
+ chunk.delta.message is not None and
402
+ hasattr(chunk.delta.message, "content") and
403
+ chunk.delta.message.content is not None and
404
+ hasattr(chunk.delta.message.content, "text") and
405
+ chunk.delta.message.content.text is not None):
406
+ content = [chunk.delta.message.content.text]
407
+
396
408
  # Anthropic
397
- if hasattr(chunk, "delta") and chunk.delta is not None:
409
+ if hasattr(chunk, "delta") and chunk.delta is not None and not hasattr(chunk.delta, "message"):
398
410
  content = [chunk.delta.text] if hasattr(chunk.delta, "text") else []
399
411
 
400
412
  if isinstance(chunk, dict):
@@ -408,7 +420,17 @@ class StreamWrapper:
408
420
 
409
421
  # Anthropic & OpenAI
410
422
  if hasattr(chunk, "type") and chunk.type == "message_start":
411
- self.prompt_tokens = chunk.message.usage.input_tokens
423
+ if hasattr(chunk.message, "usage") and chunk.message.usage is not None:
424
+ self.prompt_tokens = chunk.message.usage.input_tokens
425
+
426
+ # CohereV2
427
+ if hasattr(chunk, "type") and chunk.type == "message-end":
428
+ if (hasattr(chunk, "delta") and chunk.delta is not None and
429
+ hasattr(chunk.delta, "usage") and chunk.delta.usage is not None and
430
+ hasattr(chunk.delta.usage, "billed_units") and chunk.delta.usage.billed_units is not None):
431
+ usage = chunk.delta.usage.billed_units
432
+ self.completion_tokens = int(usage.output_tokens)
433
+ self.prompt_tokens = int(usage.input_tokens)
412
434
 
413
435
  if hasattr(chunk, "usage") and chunk.usage is not None:
414
436
  if hasattr(chunk.usage, "output_tokens"):
@@ -61,6 +61,11 @@ def with_langtrace_root_span(
61
61
  span_id = str(span.get_span_context().span_id)
62
62
  trace_id = str(span.get_span_context().trace_id)
63
63
 
64
+ # Attach session ID if available
65
+ session_id = os.environ.get("LANGTRACE_SESSION_ID")
66
+ if session_id:
67
+ span.set_attribute("session.id", session_id)
68
+
64
69
  if (
65
70
  "span_id" in func.__code__.co_varnames
66
71
  and "trace_id" in func.__code__.co_varnames
@@ -82,6 +87,12 @@ def with_langtrace_root_span(
82
87
  ) as span:
83
88
  span_id = span.get_span_context().span_id
84
89
  trace_id = span.get_span_context().trace_id
90
+
91
+ # Attach session ID if available
92
+ session_id = os.environ.get("LANGTRACE_SESSION_ID")
93
+ if session_id:
94
+ span.set_attribute("session.id", session_id)
95
+
85
96
  if (
86
97
  "span_id" in func.__code__.co_varnames
87
98
  and "trace_id" in func.__code__.co_varnames
@@ -1 +1 @@
1
- __version__ = "3.3.14"
1
+ __version__ = "3.3.16"
@@ -1,10 +1,11 @@
1
- Metadata-Version: 2.3
1
+ Metadata-Version: 2.4
2
2
  Name: langtrace-python-sdk
3
- Version: 3.3.14
3
+ Version: 3.3.16
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>
7
- License: Apache-2.0
7
+ License-Expression: Apache-2.0
8
+ License-File: LICENSE
8
9
  Classifier: License :: OSI Approved :: Apache Software License
9
10
  Classifier: Operating System :: OS Independent
10
11
  Classifier: Programming Language :: Python :: 3
@@ -11,11 +11,14 @@ 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/cohere_example/__init__.py,sha256=oYpsnS-dKOlWLkPEUWhXxi1vfxa77bt_DOdkJHg__7g,502
14
+ examples/cohere_example/__init__.py,sha256=7Sa0MEQrRU5gBZg31Ao6kXGDC9raHoLU0BxqVWAX8b8,736
15
15
  examples/cohere_example/chat.py,sha256=A1ZSkkPPOj3h27VSSa_o_Thabz08ZUzUgTVgAG0pgcA,901
16
16
  examples/cohere_example/chat_stream.py,sha256=BvhUgBEuyMhyzRZ_2i_SBvO9Ndf0b7-aRDyO399RyFE,664
17
+ examples/cohere_example/chat_streamv2.py,sha256=mOzTmBoCm3e8aKzNWDaTxfeSwl_dG-aCExEMA67oTb4,544
18
+ examples/cohere_example/chatv2.py,sha256=dEiCxdMLHKe6hjAZW_h3cmDgxHcIn31gMhs0B-3q8_k,504
17
19
  examples/cohere_example/embed.py,sha256=p9BJvOg09JVb8BfTCb63v3uh_wOsi_OyrCAJdXXrE6E,496
18
20
  examples/cohere_example/rerank.py,sha256=9XEG90sTa6djcHqikSqZDnffLhxEZub76e7-l2LPYdI,1445
21
+ examples/cohere_example/rerankv2.py,sha256=ihWpv_eez6U9cjv0MwfFVBbCJ7DZLIGegZV6kNrJ1hs,1103
19
22
  examples/cohere_example/tools.py,sha256=a5uvS058tcwU6PJbF9EDO6LPVmPj2LoW4Vn8Web3Iq8,1656
20
23
  examples/crewai_example/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
21
24
  examples/crewai_example/basic.py,sha256=PBu4f8yQfZO1L_22UDm_ReU9lnEcycjZcGuy5UpgDJM,1948
@@ -105,15 +108,15 @@ examples/vertexai_example/main.py,sha256=gndId5X5ksD-ycxnAWMdEqIDbLc3kz5Vt8vm4YP
105
108
  examples/weaviate_example/__init__.py,sha256=8JMDBsRSEV10HfTd-YC7xb4txBjD3la56snk-Bbg2Kw,618
106
109
  examples/weaviate_example/query_text.py,sha256=wPHQTc_58kPoKTZMygVjTj-2ZcdrIuaausJfMxNQnQc,127162
107
110
  langtrace_python_sdk/__init__.py,sha256=VZM6i71NR7pBQK6XvJWRelknuTYUhqwqE7PlicKa5Wg,1166
108
- langtrace_python_sdk/langtrace.py,sha256=AN6ecuL47c5eIkgYLW-0nDyEZPaqKfOYRbw7ceZzJss,12598
109
- langtrace_python_sdk/version.py,sha256=CqO2fihQQDwHrmeVCLh8taqNG1MqN22CIlPvPJZ-nVc,23
111
+ langtrace_python_sdk/langtrace.py,sha256=BxuXc2nFp_P0UYyuTV5DLNPWGsuaSMjZ8mqcqCWpxI4,13099
112
+ langtrace_python_sdk/version.py,sha256=2by_AinXADvzUFKp--fRsB9P_I_LD3NXs1PvFwaL31c,23
110
113
  langtrace_python_sdk/constants/__init__.py,sha256=3CNYkWMdd1DrkGqzLUgNZXjdAlM6UFMlf_F-odAToyc,146
111
- langtrace_python_sdk/constants/exporter/langtrace_exporter.py,sha256=d-3Qn5C_NTy1NkmdavZvy-6vePwTC5curN6QMy2haHc,50
114
+ langtrace_python_sdk/constants/exporter/langtrace_exporter.py,sha256=EVCrouYCpY98f0KSaKr4PzNxPULTZZO6dSA_crEOyJU,106
112
115
  langtrace_python_sdk/constants/instrumentation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
113
116
  langtrace_python_sdk/constants/instrumentation/anthropic.py,sha256=YX3llt3zwDY6XrYk3CB8WEVqgrzRXEw_ffyk56JoF3k,126
114
117
  langtrace_python_sdk/constants/instrumentation/aws_bedrock.py,sha256=f9eukqoxrPgPeaBJX2gpBUz1uu0dZIPahOpvoudfbH8,310
115
118
  langtrace_python_sdk/constants/instrumentation/chroma.py,sha256=hiPGYdHS0Yj4Kh3eaYBbuCAl_swqIygu80yFqkOgdak,955
116
- langtrace_python_sdk/constants/instrumentation/cohere.py,sha256=tf9sDfb5K3qOAHChEE5o8eYWPZ1io58VsOjZDCZPxfw,577
119
+ langtrace_python_sdk/constants/instrumentation/cohere.py,sha256=9yD133VdrYZ5BoJR4nJHlj67gHEImB9-KsD-NkzHW1I,1159
117
120
  langtrace_python_sdk/constants/instrumentation/common.py,sha256=DPDX8icb0Tj3OrgpbL9WeiIaMG7Si2IKiSL8YRwwor4,1203
118
121
  langtrace_python_sdk/constants/instrumentation/embedchain.py,sha256=HodCJvaFjILoOG50OwFObxfVxt_8VUaIAIqvgoN3tzo,278
119
122
  langtrace_python_sdk/constants/instrumentation/gemini.py,sha256=UAmfgg9FM7uNeOCdPfWlir6OIH-8BoxFGPRpdBd9ZZs,358
@@ -129,7 +132,7 @@ langtrace_python_sdk/constants/instrumentation/qdrant.py,sha256=yL7BopNQTXW7L7Z-
129
132
  langtrace_python_sdk/constants/instrumentation/vertexai.py,sha256=0s2vX3Y0iwjOPkUg5lAKi-7o3LaNivDSBBbF-o695Ok,1266
130
133
  langtrace_python_sdk/constants/instrumentation/weaviate.py,sha256=gtv-JBxvNGClEMxClmRKzjJ1khgOonsli4D_k9IagSE,2601
131
134
  langtrace_python_sdk/extensions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
132
- langtrace_python_sdk/extensions/langtrace_exporter.py,sha256=UFupNL03zklVd5penpsfXjbWSb5qB39mEv2BY2wczSs,6307
135
+ langtrace_python_sdk/extensions/langtrace_exporter.py,sha256=ckd8dMmY6h2oxE04p1JFLwUB5PSJX_Cy4eDFEM6aj4Y,6605
133
136
  langtrace_python_sdk/extensions/langtrace_filesystem.py,sha256=34fZutG28EJ66l67OvTGsydAH3ZpXgikdE7hVLqBpG4,7863
134
137
  langtrace_python_sdk/instrumentation/__init__.py,sha256=ftQa0rnss2V-HLZC2KDkhTEsLHhvRzdzabQTVV0omZQ,2002
135
138
  langtrace_python_sdk/instrumentation/anthropic/__init__.py,sha256=donrurJAGYlxrSRA3BIf76jGeUcAx9Tq8CVpah68S0Y,101
@@ -149,14 +152,14 @@ langtrace_python_sdk/instrumentation/chroma/__init__.py,sha256=pNZ5UO8Q-d5VkXSob
149
152
  langtrace_python_sdk/instrumentation/chroma/instrumentation.py,sha256=nT6PS6bsrIOO9kLV5GuUeRjMe6THHHAZGvqWBP1dYog,1807
150
153
  langtrace_python_sdk/instrumentation/chroma/patch.py,sha256=jYcqBeu-0cYA29PO880oXYRwYh-R1oseXmzfK6UDBps,9074
151
154
  langtrace_python_sdk/instrumentation/cohere/__init__.py,sha256=sGUSLdTUyYf36Tm6L5jQflhzCqvmWrhnBOMYHjvp6Hs,95
152
- langtrace_python_sdk/instrumentation/cohere/instrumentation.py,sha256=YQFHZIBd7SSPD4b6Va-ZR0thf_AuBCqj5yzHLHJVWnM,2121
153
- langtrace_python_sdk/instrumentation/cohere/patch.py,sha256=AnRWIy00XaLdQg670s8FDXoVWai3sF1JKeR70pDuZ7I,20986
155
+ langtrace_python_sdk/instrumentation/cohere/instrumentation.py,sha256=1wxMhWMfsvKprdV52BIfCZhZS1beRYBW9rUzUDDkyCk,2854
156
+ langtrace_python_sdk/instrumentation/cohere/patch.py,sha256=q29gJnik8bnJ7fnwaJ8PArHTQbJkWhhwBfDdQOTRBng,25422
154
157
  langtrace_python_sdk/instrumentation/crewai/__init__.py,sha256=_UBKfvQv7l0g2_wnmA5F6CdSAFH0atNOVPd49zsN3aM,88
155
158
  langtrace_python_sdk/instrumentation/crewai/instrumentation.py,sha256=5Umzq8zjEnMEtjZZiMB4DQOPkxZ-1vts7RKC6JWpn24,2969
156
159
  langtrace_python_sdk/instrumentation/crewai/patch.py,sha256=VoyOtGKYzaOIu7UnVNTemZeB3LrCIodrrYwmXLdxRw8,9133
157
160
  langtrace_python_sdk/instrumentation/dspy/__init__.py,sha256=tM1srfi_QgyCzrde4izojMrRq2Wm7Dj5QUvVQXIJzkk,84
158
161
  langtrace_python_sdk/instrumentation/dspy/instrumentation.py,sha256=qx2vBeuODI7rubf-0bkuNzDWu4bLI-E5uabrWTEuH6k,2923
159
- langtrace_python_sdk/instrumentation/dspy/patch.py,sha256=H7zF4PVdtepOSpzJuEcckKUjnZQYKlY7yhn3dk6xbpY,10458
162
+ langtrace_python_sdk/instrumentation/dspy/patch.py,sha256=BpesWxlNJAibzu06xNU9mSH82Ufw5h3p5jxM5d3QXqE,10073
160
163
  langtrace_python_sdk/instrumentation/embedchain/__init__.py,sha256=5L6n8-brMnRWZ0CMmHEuN1mrhIxrYLNtxRy0Ujc-hOY,103
161
164
  langtrace_python_sdk/instrumentation/embedchain/instrumentation.py,sha256=dShwm0duy25IvL7g9I_v-2oYuyh2fadeiJqXtXBay-8,1987
162
165
  langtrace_python_sdk/instrumentation/embedchain/patch.py,sha256=ovvBrtqUDwGSmSgK_S3pOOrDa4gkPSFG-HvmsxqmJE8,3627
@@ -196,7 +199,7 @@ langtrace_python_sdk/instrumentation/ollama/instrumentation.py,sha256=jdsvkqUJAA
196
199
  langtrace_python_sdk/instrumentation/ollama/patch.py,sha256=w99r9wCCVDdJnZQEezYE2lW_iNFEtrldt9vq3ISAsag,5375
197
200
  langtrace_python_sdk/instrumentation/openai/__init__.py,sha256=VPHRNCQEdkizIVP2d0Uw_a7t8XOTSTprEIB8oboJFbs,95
198
201
  langtrace_python_sdk/instrumentation/openai/instrumentation.py,sha256=PZxI0qfoud1VsKGmJu49YDp0Z9z9TzCR8qxR3uznOMA,2810
199
- langtrace_python_sdk/instrumentation/openai/patch.py,sha256=V--KWPZ_tQAfSAMOVaHxeDt0ZBK7YTMjcWlfiUwrsF8,25058
202
+ langtrace_python_sdk/instrumentation/openai/patch.py,sha256=u8qlCooN-JmGVWLe7jwAeBMHTIi35ktVvL9gWVBfDko,26809
200
203
  langtrace_python_sdk/instrumentation/openai/types.py,sha256=aVkoa7tmAbYfyOhnyMrDaVjQuwhmRNLMthlNtKMtWX8,4311
201
204
  langtrace_python_sdk/instrumentation/pinecone/__init__.py,sha256=DzXyGh9_MGWveJvXULkFwdkf7PbG2s3bAWtT1Dmz7Ok,99
202
205
  langtrace_python_sdk/instrumentation/pinecone/instrumentation.py,sha256=HDXkRITrVPwdQEoOYJOfMzZE_2-vDDvuqHTlD8W1lQw,1845
@@ -216,15 +219,16 @@ langtrace_python_sdk/instrumentation/weaviate/patch.py,sha256=aWLDbNGz35V6XQUv4l
216
219
  langtrace_python_sdk/types/__init__.py,sha256=2VykM6fNHRlkOaIEUCdK3VyaaVgk2rTIr9jMmCVj2Ag,4676
217
220
  langtrace_python_sdk/utils/__init__.py,sha256=VVDOG-QLd59ZvSHp0avjof0sbxlZ1QQOf0KoOF7ofhQ,3310
218
221
  langtrace_python_sdk/utils/langtrace_sampler.py,sha256=BupNndHbU9IL_wGleKetz8FdcveqHMBVz1bfKTTW80w,1753
219
- langtrace_python_sdk/utils/llm.py,sha256=jFOypinssPg14KtiDUnut545DO_nqccOAPgeskFiJR4,14990
222
+ langtrace_python_sdk/utils/llm.py,sha256=qX-4aMCq_7wetlPqhsd4aqr8e76ePdTNBJM_PwvPcAg,16160
220
223
  langtrace_python_sdk/utils/misc.py,sha256=LaQr5LOmZMiuwVdjYh7aIu6o2C_Xb1wgpQGNOVmRzfE,1918
221
224
  langtrace_python_sdk/utils/prompt_registry.py,sha256=n5dQMVLBw8aJZY8Utvf67bncc25ELf6AH9BYw8_hSzo,2619
222
225
  langtrace_python_sdk/utils/sdk_version_checker.py,sha256=F-VVVH7Fmhr5LcY0IIe-34zIi5RQcx26uuxFpPzZesM,1782
223
226
  langtrace_python_sdk/utils/silently_fail.py,sha256=wzmvRDZppaRZgVP8C1xpq2GlWXYCwubhaeWvEbQP1SI,1196
224
227
  langtrace_python_sdk/utils/types.py,sha256=l-N6o7cnWUyrD6dBvW7W3Pf5CkPo5QaoT__k1XLbrQg,383
225
- langtrace_python_sdk/utils/with_root_span.py,sha256=EW0WQfxESntf23dJt0E0rFdHV-7BRniW1Ce6nrCoEPY,8291
228
+ langtrace_python_sdk/utils/with_root_span.py,sha256=9WtZP6kbixKxdwyWLKERShxyrHk6NEyCDAc_BF4CEL4,8720
226
229
  tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
227
230
  tests/conftest.py,sha256=0Jo6iCZTXbdvyJVhG9UpYGkLabL75378oauCzmt-Sa8,603
231
+ tests/test_session_id.py,sha256=ncdkzsDdUVolAq8W6WOq8mlBoAGatDfmwaB9prZxPIY,1862
228
232
  tests/utils.py,sha256=8ZBYvxBH6PynipT1sqenfyjTGLhEV7SORQH1NJjnpsM,2500
229
233
  tests/anthropic/conftest.py,sha256=ht1zF3q4Xb1UiZ3BL_L-CQ3YWrd52Dqb4WTZ3f-GdG4,739
230
234
  tests/anthropic/test_anthropic.py,sha256=ODeGDGSZCopR7QVA8Y-Vvv3wBLs-LOlQ58LneU-aTng,2864
@@ -252,12 +256,13 @@ tests/langchain/test_langchain.py,sha256=BYAQY3ShJIVnLS1b-TkJ4wMKhbiPV-E4-ISTjGy
252
256
  tests/langchain/cassettes/test_langchain.yaml,sha256=KPBTVIYMUPFaSNpwrTDgWzsu4p3hHj_yNDoudDa-Jis,3755
253
257
  tests/openai/conftest.py,sha256=BkehS6heg-O91Nzoc4546OSiAzy8KgSgk7VCO3A11zM,700
254
258
  tests/openai/test_chat_completion.py,sha256=vkUtyF01U41J2TR8O8ygvoRXPniXI734QuQ79DgImOg,4863
255
- tests/openai/test_embeddings.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
259
+ tests/openai/test_embeddings.py,sha256=CGBDPH6cF7a83dhcNrKdVoWZSVViJ7rmC4FH3vuTR1k,3200
256
260
  tests/openai/test_image_generation.py,sha256=u6lJCDPs2kZ_MfoaEXEszU_VTOQr7xGK7ki93E2e-wY,4902
257
261
  tests/openai/cassettes/test_async_chat_completion_streaming.yaml,sha256=bna_jKychb6v7gwAd8IrVjzIluUw7NoI27nvlKVYXkI,6847
258
262
  tests/openai/cassettes/test_async_image_generation.yaml,sha256=OwWDdzameaStU4jScuDK7SvpN8Ziuu4tkbKTaBMlXas,3701
259
263
  tests/openai/cassettes/test_chat_completion.yaml,sha256=BoI0Wn4_jNQ8fesIiTQkmn92y0p_1JczGMS4fCmXnzQ,2930
260
264
  tests/openai/cassettes/test_chat_completion_streaming.yaml,sha256=urfMUkDkUveT3t18k9KuiEE3SMZSwu7EFYTWbTPRIbA,2592397
265
+ tests/openai/cassettes/test_embeddings_base_url.yaml,sha256=K039Y6iP_xkifySWBR4JTaXoXnLaeJEtHFxLG-xeRZ4,11779
261
266
  tests/openai/cassettes/test_image_generation.yaml,sha256=GL-AqzMOjL_t3m7WbgXlK06piXiUEH--4c-p8D4vabU,3629
262
267
  tests/pinecone/conftest.py,sha256=EY1m5M6MKSOktbVEe__wYNjCW9A7H0xdC-aXhU8JEOg,916
263
268
  tests/pinecone/test_pinecone.py,sha256=o1NnY4QirQU4JgMAi21kl9ejuXsGhF9EjyS9C2HuWtU,3599
@@ -265,8 +270,8 @@ tests/pinecone/cassettes/test_query.yaml,sha256=b5v9G3ssUy00oG63PlFUR3JErF2Js-5A
265
270
  tests/pinecone/cassettes/test_upsert.yaml,sha256=neWmQ1v3d03V8WoLl8FoFeeCYImb8pxlJBWnFd_lITU,38607
266
271
  tests/qdrant/conftest.py,sha256=9n0uHxxIjWk9fbYc4bx-uP8lSAgLBVx-cV9UjnsyCHM,381
267
272
  tests/qdrant/test_qdrant.py,sha256=pzjAjVY2kmsmGfrI2Gs2xrolfuaNHz7l1fqGQCjp5_o,3353
268
- langtrace_python_sdk-3.3.14.dist-info/METADATA,sha256=keb-ijUSoM7Pcas5rJH4UMhaw4pwWTP8dW3ujw6G8GE,15643
269
- langtrace_python_sdk-3.3.14.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87
270
- langtrace_python_sdk-3.3.14.dist-info/entry_points.txt,sha256=1_b9-qvf2fE7uQNZcbUei9vLpFZBbbh9LrtGw95ssAo,70
271
- langtrace_python_sdk-3.3.14.dist-info/licenses/LICENSE,sha256=QwcOLU5TJoTeUhuIXzhdCEEDDvorGiC6-3YTOl4TecE,11356
272
- langtrace_python_sdk-3.3.14.dist-info/RECORD,,
273
+ langtrace_python_sdk-3.3.16.dist-info/METADATA,sha256=J5e-JB6fDqEMbeXWLm6CjtbUEU322tgGic0XYoKo2XM,15676
274
+ langtrace_python_sdk-3.3.16.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
275
+ langtrace_python_sdk-3.3.16.dist-info/entry_points.txt,sha256=1_b9-qvf2fE7uQNZcbUei9vLpFZBbbh9LrtGw95ssAo,70
276
+ langtrace_python_sdk-3.3.16.dist-info/licenses/LICENSE,sha256=QwcOLU5TJoTeUhuIXzhdCEEDDvorGiC6-3YTOl4TecE,11356
277
+ langtrace_python_sdk-3.3.16.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.26.3
2
+ Generator: hatchling 1.27.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -0,0 +1,208 @@
1
+ interactions:
2
+ - request:
3
+ body: '{"input": "Test input", "model": "text-embedding-ada-002", "encoding_format":
4
+ "base64"}'
5
+ headers:
6
+ accept:
7
+ - application/json
8
+ accept-encoding:
9
+ - gzip, deflate
10
+ connection:
11
+ - keep-alive
12
+ content-length:
13
+ - '87'
14
+ content-type:
15
+ - application/json
16
+ host:
17
+ - api.openai.com
18
+ user-agent:
19
+ - OpenAI/Python 1.54.4
20
+ x-stainless-arch:
21
+ - x64
22
+ x-stainless-async:
23
+ - 'false'
24
+ x-stainless-lang:
25
+ - python
26
+ x-stainless-os:
27
+ - Linux
28
+ x-stainless-package-version:
29
+ - 1.54.4
30
+ x-stainless-retry-count:
31
+ - '0'
32
+ x-stainless-runtime:
33
+ - CPython
34
+ x-stainless-runtime-version:
35
+ - 3.12.5
36
+ method: POST
37
+ uri: https://api.openai.com/v1/embeddings
38
+ response:
39
+ body:
40
+ string: !!binary |
41
+ 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
149
+ 8r+2G/3nv/4PAAAA//8DAEF/1EXeIAAA
150
+ headers:
151
+ CF-Cache-Status:
152
+ - DYNAMIC
153
+ CF-RAY:
154
+ - 8ef92722e9cb8389-SEA
155
+ Connection:
156
+ - keep-alive
157
+ Content-Encoding:
158
+ - gzip
159
+ Content-Type:
160
+ - application/json
161
+ Date:
162
+ - Tue, 10 Dec 2024 00:35:05 GMT
163
+ Server:
164
+ - cloudflare
165
+ Set-Cookie:
166
+ - __cf_bm=Bc46FmH66u.HvNfo3T4q3vwT9_TGhtm3wFFMbxQcZ0U-1733790905-1.0.1.1-mXshj7zBxHMWpnIh3c8EmaqnQsDr8FCF6kOqoQvhFoytI6b7MXLbqkZNRfXRP0pd_OraJnyZhUzOl8KaZdq9qg;
167
+ path=/; expires=Tue, 10-Dec-24 01:05:05 GMT; domain=.api.openai.com; HttpOnly;
168
+ Secure; SameSite=None
169
+ - _cfuvid=pdqpFgJ05BGtT4Cs8llmvgLkp1kOJXZNJgkv3mk5xnA-1733790905081-0.0.1.1-604800000;
170
+ path=/; domain=.api.openai.com; HttpOnly; Secure; SameSite=None
171
+ Transfer-Encoding:
172
+ - chunked
173
+ X-Content-Type-Options:
174
+ - nosniff
175
+ access-control-allow-origin:
176
+ - '*'
177
+ access-control-expose-headers:
178
+ - X-Request-ID
179
+ alt-svc:
180
+ - h3=":443"; ma=86400
181
+ openai-model:
182
+ - text-embedding-ada-002
183
+ openai-organization:
184
+ - scale3-1
185
+ openai-processing-ms:
186
+ - '49'
187
+ openai-version:
188
+ - '2020-10-01'
189
+ strict-transport-security:
190
+ - max-age=31536000; includeSubDomains; preload
191
+ x-ratelimit-limit-requests:
192
+ - '10000'
193
+ x-ratelimit-limit-tokens:
194
+ - '10000000'
195
+ x-ratelimit-remaining-requests:
196
+ - '9999'
197
+ x-ratelimit-remaining-tokens:
198
+ - '9999998'
199
+ x-ratelimit-reset-requests:
200
+ - 6ms
201
+ x-ratelimit-reset-tokens:
202
+ - 0s
203
+ x-request-id:
204
+ - req_0ce98b0d1723b6734062d2cd711aa85e
205
+ status:
206
+ code: 200
207
+ message: OK
208
+ version: 1
@@ -0,0 +1,88 @@
1
+ import pytest
2
+ import httpx
3
+ from openai import OpenAI
4
+ from opentelemetry.trace import SpanKind, StatusCode
5
+ from langtrace.trace_attributes import SpanAttributes
6
+ from langtrace_python_sdk.constants.instrumentation.openai import APIS
7
+ from langtrace_python_sdk.instrumentation.openai import OpenAIInstrumentation
8
+ from tests.utils import assert_token_count
9
+ from importlib_metadata import version as v
10
+
11
+ # Initialize OpenAI instrumentation
12
+ instrumentor = OpenAIInstrumentation()
13
+ instrumentor.instrument()
14
+
15
+ @pytest.mark.vcr()
16
+ def test_embeddings_base_url(exporter, openai_client):
17
+ input_value = "Test input"
18
+ kwargs = {
19
+ "input": input_value,
20
+ "model": "text-embedding-ada-002",
21
+ }
22
+
23
+ openai_client.embeddings.create(**kwargs)
24
+ spans = exporter.get_finished_spans()
25
+ embedding_span = spans[-1]
26
+
27
+ attributes = embedding_span.attributes
28
+ assert attributes.get(SpanAttributes.LLM_URL) == "https://api.openai.com/v1/"
29
+ assert attributes.get(SpanAttributes.LANGTRACE_SERVICE_NAME) == "OpenAI"
30
+
31
+
32
+ def test_embeddings_azure_provider(exporter, monkeypatch):
33
+ # Mock response data
34
+ mock_response = {
35
+ "data": [{"embedding": [0.1] * 1536, "index": 0, "object": "embedding"}],
36
+ "model": "text-embedding-ada-002",
37
+ "object": "list",
38
+ "usage": {"prompt_tokens": 5, "total_tokens": 5}
39
+ }
40
+
41
+ # Create a mock send method for the HTTP client
42
+ def mock_send(self, request, **kwargs):
43
+ # Create a proper request with headers
44
+ headers = {
45
+ "authorization": "Bearer test_api_key",
46
+ "content-type": "application/json",
47
+ }
48
+ request = httpx.Request(
49
+ method="POST",
50
+ url="https://your-resource.azure.openai.com/v1/embeddings",
51
+ headers=headers,
52
+ )
53
+
54
+ # Create response with proper context
55
+ return httpx.Response(
56
+ status_code=200,
57
+ content=b'{"data": [{"embedding": [0.1, 0.1], "index": 0, "object": "embedding"}], "model": "text-embedding-ada-002", "object": "list", "usage": {"prompt_tokens": 5, "total_tokens": 5}}',
58
+ request=request,
59
+ headers={"content-type": "application/json"}
60
+ )
61
+
62
+ # Create Azure client
63
+ azure_client = OpenAI(
64
+ api_key="test_api_key",
65
+ base_url="https://your-resource.azure.openai.com/v1",
66
+ )
67
+
68
+ # Debug prints
69
+ print(f"Debug - Azure client type: {type(azure_client)}")
70
+ print(f"Debug - Azure client base_url: {azure_client.base_url}")
71
+ print(f"Debug - Azure client _client._base_url: {azure_client._client._base_url if hasattr(azure_client, '_client') else 'No _client'}")
72
+
73
+ # Patch the HTTP client's send method
74
+ monkeypatch.setattr(httpx.Client, "send", mock_send)
75
+
76
+ input_value = "Test input"
77
+ kwargs = {
78
+ "input": input_value,
79
+ "model": "text-embedding-ada-002",
80
+ }
81
+
82
+ azure_client.embeddings.create(**kwargs)
83
+ spans = exporter.get_finished_spans()
84
+ embedding_span = spans[-1]
85
+
86
+ attributes = embedding_span.attributes
87
+ assert attributes.get(SpanAttributes.LLM_URL) == "https://your-resource.azure.openai.com/v1/"
88
+ assert attributes.get(SpanAttributes.LANGTRACE_SERVICE_NAME) == "Azure"
@@ -0,0 +1,59 @@
1
+ import os
2
+ import pytest
3
+ from opentelemetry.trace import SpanKind
4
+ from langtrace_python_sdk.langtrace import LangtraceConfig
5
+ from langtrace_python_sdk.extensions.langtrace_exporter import LangTraceExporter
6
+ from langtrace_python_sdk.utils.with_root_span import with_langtrace_root_span
7
+ from langtrace_python_sdk.constants.exporter.langtrace_exporter import LANGTRACE_SESSION_ID_HEADER
8
+
9
+ def test_session_id_from_env(exporter):
10
+ # Test session ID from environment variable
11
+ test_session_id = "test-session-123"
12
+ os.environ["LANGTRACE_SESSION_ID"] = test_session_id
13
+
14
+ @with_langtrace_root_span()
15
+ def test_function():
16
+ pass
17
+
18
+ test_function()
19
+
20
+ spans = exporter.get_finished_spans()
21
+ assert len(spans) == 1
22
+ span = spans[0]
23
+ assert span.attributes.get("session.id") == test_session_id
24
+
25
+ # Cleanup
26
+ del os.environ["LANGTRACE_SESSION_ID"]
27
+
28
+ def test_session_id_in_config():
29
+ # Test session ID through LangtraceConfig
30
+ test_session_id = "config-session-456"
31
+ config = LangtraceConfig(session_id=test_session_id)
32
+ exporter = LangTraceExporter(
33
+ api_host="http://test",
34
+ api_key="test-key",
35
+ session_id=config.session_id
36
+ )
37
+
38
+ assert exporter.session_id == test_session_id
39
+
40
+ def test_session_id_in_headers():
41
+ # Test session ID in HTTP headers
42
+ test_session_id = "header-session-789"
43
+ exporter = LangTraceExporter(
44
+ api_host="http://test",
45
+ api_key="test-key",
46
+ session_id=test_session_id
47
+ )
48
+
49
+ # Export method adds headers, so we'll check the headers directly
50
+ headers = {
51
+ "Content-Type": "application/json",
52
+ "x-api-key": "test-key",
53
+ "User-Agent": "LangtraceExporter",
54
+ }
55
+
56
+ if test_session_id:
57
+ headers[LANGTRACE_SESSION_ID_HEADER] = test_session_id
58
+
59
+ assert headers[LANGTRACE_SESSION_ID_HEADER] == test_session_id