netra-sdk 0.1.14__tar.gz → 0.1.16__tar.gz

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.

Potentially problematic release.


This version of netra-sdk might be problematic. Click here for more details.

Files changed (47) hide show
  1. {netra_sdk-0.1.14 → netra_sdk-0.1.16}/PKG-INFO +2 -2
  2. {netra_sdk-0.1.14 → netra_sdk-0.1.16}/netra/__init__.py +20 -5
  3. {netra_sdk-0.1.14 → netra_sdk-0.1.16}/netra/instrumentation/openai/wrappers.py +32 -21
  4. netra_sdk-0.1.16/netra/version.py +1 -0
  5. {netra_sdk-0.1.14 → netra_sdk-0.1.16}/pyproject.toml +2 -2
  6. netra_sdk-0.1.14/netra/version.py +0 -2
  7. {netra_sdk-0.1.14 → netra_sdk-0.1.16}/LICENCE +0 -0
  8. {netra_sdk-0.1.14 → netra_sdk-0.1.16}/README.md +0 -0
  9. {netra_sdk-0.1.14 → netra_sdk-0.1.16}/netra/anonymizer/__init__.py +0 -0
  10. {netra_sdk-0.1.14 → netra_sdk-0.1.16}/netra/anonymizer/anonymizer.py +0 -0
  11. {netra_sdk-0.1.14 → netra_sdk-0.1.16}/netra/anonymizer/base.py +0 -0
  12. {netra_sdk-0.1.14 → netra_sdk-0.1.16}/netra/anonymizer/fp_anonymizer.py +0 -0
  13. {netra_sdk-0.1.14 → netra_sdk-0.1.16}/netra/config.py +0 -0
  14. {netra_sdk-0.1.14 → netra_sdk-0.1.16}/netra/decorators.py +0 -0
  15. {netra_sdk-0.1.14 → netra_sdk-0.1.16}/netra/exceptions/__init__.py +0 -0
  16. {netra_sdk-0.1.14 → netra_sdk-0.1.16}/netra/exceptions/injection.py +0 -0
  17. {netra_sdk-0.1.14 → netra_sdk-0.1.16}/netra/exceptions/pii.py +0 -0
  18. {netra_sdk-0.1.14 → netra_sdk-0.1.16}/netra/input_scanner.py +0 -0
  19. {netra_sdk-0.1.14 → netra_sdk-0.1.16}/netra/instrumentation/__init__.py +0 -0
  20. {netra_sdk-0.1.14 → netra_sdk-0.1.16}/netra/instrumentation/aiohttp/__init__.py +0 -0
  21. {netra_sdk-0.1.14 → netra_sdk-0.1.16}/netra/instrumentation/aiohttp/version.py +0 -0
  22. {netra_sdk-0.1.14 → netra_sdk-0.1.16}/netra/instrumentation/cohere/__init__.py +0 -0
  23. {netra_sdk-0.1.14 → netra_sdk-0.1.16}/netra/instrumentation/cohere/version.py +0 -0
  24. {netra_sdk-0.1.14 → netra_sdk-0.1.16}/netra/instrumentation/fastapi/__init__.py +0 -0
  25. {netra_sdk-0.1.14 → netra_sdk-0.1.16}/netra/instrumentation/fastapi/version.py +0 -0
  26. {netra_sdk-0.1.14 → netra_sdk-0.1.16}/netra/instrumentation/google_genai/__init__.py +0 -0
  27. {netra_sdk-0.1.14 → netra_sdk-0.1.16}/netra/instrumentation/google_genai/config.py +0 -0
  28. {netra_sdk-0.1.14 → netra_sdk-0.1.16}/netra/instrumentation/google_genai/utils.py +0 -0
  29. {netra_sdk-0.1.14 → netra_sdk-0.1.16}/netra/instrumentation/google_genai/version.py +0 -0
  30. {netra_sdk-0.1.14 → netra_sdk-0.1.16}/netra/instrumentation/httpx/__init__.py +0 -0
  31. {netra_sdk-0.1.14 → netra_sdk-0.1.16}/netra/instrumentation/httpx/version.py +0 -0
  32. {netra_sdk-0.1.14 → netra_sdk-0.1.16}/netra/instrumentation/instruments.py +0 -0
  33. {netra_sdk-0.1.14 → netra_sdk-0.1.16}/netra/instrumentation/mistralai/__init__.py +0 -0
  34. {netra_sdk-0.1.14 → netra_sdk-0.1.16}/netra/instrumentation/mistralai/config.py +0 -0
  35. {netra_sdk-0.1.14 → netra_sdk-0.1.16}/netra/instrumentation/mistralai/utils.py +0 -0
  36. {netra_sdk-0.1.14 → netra_sdk-0.1.16}/netra/instrumentation/mistralai/version.py +0 -0
  37. {netra_sdk-0.1.14 → netra_sdk-0.1.16}/netra/instrumentation/openai/__init__.py +0 -0
  38. {netra_sdk-0.1.14 → netra_sdk-0.1.16}/netra/instrumentation/openai/version.py +0 -0
  39. {netra_sdk-0.1.14 → netra_sdk-0.1.16}/netra/instrumentation/weaviate/__init__.py +0 -0
  40. {netra_sdk-0.1.14 → netra_sdk-0.1.16}/netra/instrumentation/weaviate/version.py +0 -0
  41. {netra_sdk-0.1.14 → netra_sdk-0.1.16}/netra/pii.py +0 -0
  42. {netra_sdk-0.1.14 → netra_sdk-0.1.16}/netra/processors/__init__.py +0 -0
  43. {netra_sdk-0.1.14 → netra_sdk-0.1.16}/netra/processors/session_span_processor.py +0 -0
  44. {netra_sdk-0.1.14 → netra_sdk-0.1.16}/netra/scanner.py +0 -0
  45. {netra_sdk-0.1.14 → netra_sdk-0.1.16}/netra/session_manager.py +0 -0
  46. {netra_sdk-0.1.14 → netra_sdk-0.1.16}/netra/span_wrapper.py +0 -0
  47. {netra_sdk-0.1.14 → netra_sdk-0.1.16}/netra/tracer.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: netra-sdk
3
- Version: 0.1.14
3
+ Version: 0.1.16
4
4
  Summary: A Python SDK for AI application observability that provides OpenTelemetry-based monitoring, tracing, and PII protection for LLM and vector database applications. Enables easy instrumentation, session tracking, and privacy-focused data collection for AI systems in production environments.
5
5
  License: Apache-2.0
6
6
  Keywords: netra,tracing,observability,sdk,ai,llm,vector,database
@@ -67,7 +67,7 @@ Requires-Dist: opentelemetry-instrumentation-urllib (>=0.55b1,<1.0.0)
67
67
  Requires-Dist: opentelemetry-instrumentation-urllib3 (>=0.55b1,<1.0.0)
68
68
  Requires-Dist: opentelemetry-sdk (>=1.34.0,<2.0.0)
69
69
  Requires-Dist: presidio-analyzer (>=2.2.358,<3.0.0)
70
- Requires-Dist: traceloop-sdk (>=0.40.7,<0.41.0)
70
+ Requires-Dist: traceloop-sdk (>=0.40.7,<0.43.0)
71
71
  Project-URL: Bug Tracker, https://github.com/KeyValueSoftwareSystems/netra-sdk-py/issues
72
72
  Project-URL: Documentation, https://github.com/KeyValueSoftwareSystems/netra-sdk-py/blob/main/README.md
73
73
  Project-URL: Homepage, https://github.com/KeyValueSoftwareSystems/netra-sdk-py
@@ -88,7 +88,10 @@ class Netra:
88
88
  Args:
89
89
  session_id: Session identifier
90
90
  """
91
- SessionManager.set_session_context("session_id", session_id)
91
+ if session_id:
92
+ SessionManager.set_session_context("session_id", session_id)
93
+ else:
94
+ logger.warning("Session ID must be provided for setting session_id.")
92
95
 
93
96
  @classmethod
94
97
  def set_user_id(cls, user_id: str) -> None:
@@ -98,7 +101,10 @@ class Netra:
98
101
  Args:
99
102
  user_id: User identifier
100
103
  """
101
- SessionManager.set_session_context("user_id", user_id)
104
+ if user_id:
105
+ SessionManager.set_session_context("user_id", user_id)
106
+ else:
107
+ logger.warning("User ID must be provided for setting user_id.")
102
108
 
103
109
  @classmethod
104
110
  def set_tenant_id(cls, tenant_id: str) -> None:
@@ -108,7 +114,10 @@ class Netra:
108
114
  Args:
109
115
  user_account_id: User account identifier
110
116
  """
111
- SessionManager.set_session_context("tenant_id", tenant_id)
117
+ if tenant_id:
118
+ SessionManager.set_session_context("tenant_id", tenant_id)
119
+ else:
120
+ logger.warning("Tenant ID must be provided for setting tenant_id.")
112
121
 
113
122
  @classmethod
114
123
  def set_custom_attributes(cls, key: str, value: Any) -> None:
@@ -119,7 +128,10 @@ class Netra:
119
128
  key: Custom attribute key
120
129
  value: Custom attribute value
121
130
  """
122
- SessionManager.set_session_context("custom_attributes", {key: value})
131
+ if key and value:
132
+ SessionManager.set_session_context("custom_attributes", {key: value})
133
+ else:
134
+ logger.warning("Both key and value must be provided for custom attributes.")
123
135
 
124
136
  @classmethod
125
137
  def set_custom_event(cls, event_name: str, attributes: Any) -> None:
@@ -130,7 +142,10 @@ class Netra:
130
142
  event_name: Name of the custom event
131
143
  attributes: Attributes of the custom event
132
144
  """
133
- SessionManager.set_custom_event(event_name, attributes)
145
+ if event_name and attributes:
146
+ SessionManager.set_custom_event(event_name, attributes)
147
+ else:
148
+ logger.warning("Both event_name and attributes must be provided for custom events.")
134
149
 
135
150
  @classmethod
136
151
  def start_span(
@@ -12,6 +12,9 @@ from typing import Any, AsyncIterator, Callable, Dict, Iterator, Tuple
12
12
 
13
13
  from opentelemetry import context as context_api
14
14
  from opentelemetry.instrumentation.utils import _SUPPRESS_INSTRUMENTATION_KEY
15
+ from opentelemetry.semconv_ai import (
16
+ SpanAttributes,
17
+ )
15
18
  from opentelemetry.trace import Span, SpanKind, Tracer
16
19
  from opentelemetry.trace.status import Status, StatusCode
17
20
  from wrapt import ObjectProxy
@@ -55,34 +58,39 @@ def set_request_attributes(span: Span, kwargs: Dict[str, Any], operation_type: s
55
58
  return
56
59
 
57
60
  # Set operation type
58
- span.set_attribute("llm.request.type", operation_type)
61
+ span.set_attribute(f"{SpanAttributes.LLM_REQUEST_TYPE}", operation_type)
59
62
 
60
63
  # Common attributes
61
64
  if kwargs.get("model"):
62
- span.set_attribute("llm.request.model", kwargs["model"])
65
+ span.set_attribute(f"{SpanAttributes.LLM_REQUEST_MODEL}", kwargs["model"])
63
66
 
64
67
  if kwargs.get("temperature") is not None:
65
- span.set_attribute("llm.request.temperature", kwargs["temperature"])
68
+ span.set_attribute(f"{SpanAttributes.LLM_REQUEST_TEMPERATURE}", kwargs["temperature"])
66
69
 
67
70
  if kwargs.get("max_tokens") is not None:
68
- span.set_attribute("llm.request.max_tokens", kwargs["max_tokens"])
71
+ span.set_attribute(f"{SpanAttributes.LLM_REQUEST_MAX_TOKENS}", kwargs["max_tokens"])
69
72
 
70
73
  if kwargs.get("stream") is not None:
71
- span.set_attribute("llm.stream", kwargs["stream"])
74
+ span.set_attribute("gen_ai.stream", kwargs["stream"])
72
75
 
73
76
  # Chat-specific attributes
74
77
  if operation_type == "chat" and kwargs.get("messages"):
75
78
  messages = kwargs["messages"]
76
79
  if isinstance(messages, list) and len(messages) > 0:
77
- span.set_attribute("llm.prompts.0.role", messages[0].get("role", ""))
78
- span.set_attribute("llm.prompts.0.content", str(messages[0].get("content", "")))
80
+ for index, message in enumerate(messages):
81
+ if hasattr(message, "content"):
82
+ span.set_attribute(f"{SpanAttributes.LLM_PROMPTS}.{index}.role", "user")
83
+ span.set_attribute(f"{SpanAttributes.LLM_PROMPTS}.{index}.content", message.content)
84
+ elif isinstance(message, dict):
85
+ span.set_attribute(f"{SpanAttributes.LLM_PROMPTS}.{index}.role", message.get("role", "user"))
86
+ span.set_attribute(f"{SpanAttributes.LLM_PROMPTS}.{index}.content", str(message.get("content", "")))
79
87
 
80
88
  # Response-specific attributes
81
89
  if operation_type == "response":
82
90
  if kwargs.get("instructions"):
83
- span.set_attribute("llm.instructions", kwargs["instructions"])
91
+ span.set_attribute("gen_ai.instructions", kwargs["instructions"])
84
92
  if kwargs.get("input"):
85
- span.set_attribute("llm.input", kwargs["input"])
93
+ span.set_attribute("gen_ai.input", kwargs["input"])
86
94
 
87
95
 
88
96
  def set_response_attributes(span: Span, response_dict: Dict[str, Any]) -> None:
@@ -91,33 +99,36 @@ def set_response_attributes(span: Span, response_dict: Dict[str, Any]) -> None:
91
99
  return
92
100
 
93
101
  if response_dict.get("model"):
94
- span.set_attribute("llm.response.model", response_dict["model"])
102
+ span.set_attribute(f"{SpanAttributes.LLM_RESPONSE_MODEL}", response_dict["model"])
95
103
 
96
104
  if response_dict.get("id"):
97
- span.set_attribute("llm.response.id", response_dict["id"])
105
+ span.set_attribute("gen_ai.response.id", response_dict["id"])
98
106
 
99
107
  # Usage information
100
108
  usage = response_dict.get("usage", {})
101
109
  if usage:
102
110
  if usage.get("prompt_tokens"):
103
- span.set_attribute("llm.usage.prompt_tokens", usage["prompt_tokens"])
111
+ span.set_attribute(f"{SpanAttributes.LLM_USAGE_PROMPT_TOKENS}", usage["prompt_tokens"])
104
112
  if usage.get("completion_tokens"):
105
- span.set_attribute("llm.usage.completion_tokens", usage["completion_tokens"])
113
+ span.set_attribute(f"{SpanAttributes.LLM_USAGE_COMPLETION_TOKENS}", usage["completion_tokens"])
114
+ if usage.get("cache_read_input_token"):
115
+ span.set_attribute(f"{SpanAttributes.LLM_USAGE_CACHE_READ_INPUT_TOKENS}", usage["cache_read_input_token"])
106
116
  if usage.get("total_tokens"):
107
- span.set_attribute("llm.usage.total_tokens", usage["total_tokens"])
117
+ span.set_attribute(f"{SpanAttributes.LLM_USAGE_TOTAL_TOKENS}", usage["total_tokens"])
108
118
 
109
119
  # Response content
110
120
  choices = response_dict.get("choices", [])
111
- if choices and len(choices) > 0:
112
- first_choice = choices[0]
113
- if first_choice.get("message", {}).get("content"):
114
- span.set_attribute("llm.completions.0.content", first_choice["message"]["content"])
115
- if first_choice.get("finish_reason"):
116
- span.set_attribute("llm.completions.0.finish_reason", first_choice["finish_reason"])
121
+ for index, choice in enumerate(choices):
122
+ if choice.get("message", {}).get("role"):
123
+ span.set_attribute(f"{SpanAttributes.LLM_COMPLETIONS}.{index}.role", choice["message"]["role"])
124
+ if choice.get("message", {}).get("content"):
125
+ span.set_attribute(f"{SpanAttributes.LLM_COMPLETIONS}.{index}.content", choice["message"]["content"])
126
+ if choice.get("finish_reason"):
127
+ span.set_attribute(f"{SpanAttributes.LLM_COMPLETIONS}.{index}.finish_reason", choice["finish_reason"])
117
128
 
118
129
  # For responses.create
119
130
  if response_dict.get("output_text"):
120
- span.set_attribute("llm.response.output_text", response_dict["output_text"])
131
+ span.set_attribute("gen_ai.response.output_text", response_dict["output_text"])
121
132
 
122
133
 
123
134
  def chat_wrapper(tracer: Tracer) -> Callable[..., Any]:
@@ -0,0 +1 @@
1
+ __version__ = "0.1.16"
@@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"
4
4
 
5
5
  [project]
6
6
  name = "netra-sdk"
7
- version = "0.1.14"
7
+ version = "0.1.16"
8
8
  description = "A Python SDK for AI application observability that provides OpenTelemetry-based monitoring, tracing, and PII protection for LLM and vector database applications. Enables easy instrumentation, session tracking, and privacy-focused data collection for AI systems in production environments."
9
9
  authors = [
10
10
  {name = "Sooraj Thomas",email = "sooraj@keyvalue.systems"}
@@ -32,7 +32,7 @@ dependencies = [
32
32
  "opentelemetry-api>=1.34.0,<2.0.0",
33
33
  "opentelemetry-sdk>=1.34.0,<2.0.0",
34
34
  "opentelemetry-instrumentation-fastapi>=0.55b1,<1.0.0",
35
- "traceloop-sdk>=0.40.7,<0.41.0",
35
+ "traceloop-sdk>=0.40.7,<0.43.0",
36
36
  "presidio-analyzer>=2.2.358,<3.0.0",
37
37
  "opentelemetry-instrumentation-httpx>=0.55b1,<1.0.0",
38
38
  "opentelemetry-instrumentation-aiohttp-client>=0.55b1,<1.0.0",
@@ -1,2 +0,0 @@
1
- __version__ = "0.1.14"
2
-
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes