netra-sdk 0.1.14__tar.gz → 0.1.15__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.
- {netra_sdk-0.1.14 → netra_sdk-0.1.15}/PKG-INFO +2 -2
- {netra_sdk-0.1.14 → netra_sdk-0.1.15}/netra/instrumentation/openai/wrappers.py +32 -21
- netra_sdk-0.1.15/netra/version.py +2 -0
- {netra_sdk-0.1.14 → netra_sdk-0.1.15}/pyproject.toml +2 -2
- netra_sdk-0.1.14/netra/version.py +0 -2
- {netra_sdk-0.1.14 → netra_sdk-0.1.15}/LICENCE +0 -0
- {netra_sdk-0.1.14 → netra_sdk-0.1.15}/README.md +0 -0
- {netra_sdk-0.1.14 → netra_sdk-0.1.15}/netra/__init__.py +0 -0
- {netra_sdk-0.1.14 → netra_sdk-0.1.15}/netra/anonymizer/__init__.py +0 -0
- {netra_sdk-0.1.14 → netra_sdk-0.1.15}/netra/anonymizer/anonymizer.py +0 -0
- {netra_sdk-0.1.14 → netra_sdk-0.1.15}/netra/anonymizer/base.py +0 -0
- {netra_sdk-0.1.14 → netra_sdk-0.1.15}/netra/anonymizer/fp_anonymizer.py +0 -0
- {netra_sdk-0.1.14 → netra_sdk-0.1.15}/netra/config.py +0 -0
- {netra_sdk-0.1.14 → netra_sdk-0.1.15}/netra/decorators.py +0 -0
- {netra_sdk-0.1.14 → netra_sdk-0.1.15}/netra/exceptions/__init__.py +0 -0
- {netra_sdk-0.1.14 → netra_sdk-0.1.15}/netra/exceptions/injection.py +0 -0
- {netra_sdk-0.1.14 → netra_sdk-0.1.15}/netra/exceptions/pii.py +0 -0
- {netra_sdk-0.1.14 → netra_sdk-0.1.15}/netra/input_scanner.py +0 -0
- {netra_sdk-0.1.14 → netra_sdk-0.1.15}/netra/instrumentation/__init__.py +0 -0
- {netra_sdk-0.1.14 → netra_sdk-0.1.15}/netra/instrumentation/aiohttp/__init__.py +0 -0
- {netra_sdk-0.1.14 → netra_sdk-0.1.15}/netra/instrumentation/aiohttp/version.py +0 -0
- {netra_sdk-0.1.14 → netra_sdk-0.1.15}/netra/instrumentation/cohere/__init__.py +0 -0
- {netra_sdk-0.1.14 → netra_sdk-0.1.15}/netra/instrumentation/cohere/version.py +0 -0
- {netra_sdk-0.1.14 → netra_sdk-0.1.15}/netra/instrumentation/fastapi/__init__.py +0 -0
- {netra_sdk-0.1.14 → netra_sdk-0.1.15}/netra/instrumentation/fastapi/version.py +0 -0
- {netra_sdk-0.1.14 → netra_sdk-0.1.15}/netra/instrumentation/google_genai/__init__.py +0 -0
- {netra_sdk-0.1.14 → netra_sdk-0.1.15}/netra/instrumentation/google_genai/config.py +0 -0
- {netra_sdk-0.1.14 → netra_sdk-0.1.15}/netra/instrumentation/google_genai/utils.py +0 -0
- {netra_sdk-0.1.14 → netra_sdk-0.1.15}/netra/instrumentation/google_genai/version.py +0 -0
- {netra_sdk-0.1.14 → netra_sdk-0.1.15}/netra/instrumentation/httpx/__init__.py +0 -0
- {netra_sdk-0.1.14 → netra_sdk-0.1.15}/netra/instrumentation/httpx/version.py +0 -0
- {netra_sdk-0.1.14 → netra_sdk-0.1.15}/netra/instrumentation/instruments.py +0 -0
- {netra_sdk-0.1.14 → netra_sdk-0.1.15}/netra/instrumentation/mistralai/__init__.py +0 -0
- {netra_sdk-0.1.14 → netra_sdk-0.1.15}/netra/instrumentation/mistralai/config.py +0 -0
- {netra_sdk-0.1.14 → netra_sdk-0.1.15}/netra/instrumentation/mistralai/utils.py +0 -0
- {netra_sdk-0.1.14 → netra_sdk-0.1.15}/netra/instrumentation/mistralai/version.py +0 -0
- {netra_sdk-0.1.14 → netra_sdk-0.1.15}/netra/instrumentation/openai/__init__.py +0 -0
- {netra_sdk-0.1.14 → netra_sdk-0.1.15}/netra/instrumentation/openai/version.py +0 -0
- {netra_sdk-0.1.14 → netra_sdk-0.1.15}/netra/instrumentation/weaviate/__init__.py +0 -0
- {netra_sdk-0.1.14 → netra_sdk-0.1.15}/netra/instrumentation/weaviate/version.py +0 -0
- {netra_sdk-0.1.14 → netra_sdk-0.1.15}/netra/pii.py +0 -0
- {netra_sdk-0.1.14 → netra_sdk-0.1.15}/netra/processors/__init__.py +0 -0
- {netra_sdk-0.1.14 → netra_sdk-0.1.15}/netra/processors/session_span_processor.py +0 -0
- {netra_sdk-0.1.14 → netra_sdk-0.1.15}/netra/scanner.py +0 -0
- {netra_sdk-0.1.14 → netra_sdk-0.1.15}/netra/session_manager.py +0 -0
- {netra_sdk-0.1.14 → netra_sdk-0.1.15}/netra/span_wrapper.py +0 -0
- {netra_sdk-0.1.14 → netra_sdk-0.1.15}/netra/tracer.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: netra-sdk
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.15
|
|
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.
|
|
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
|
|
@@ -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("
|
|
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("
|
|
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("
|
|
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("
|
|
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("
|
|
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
|
-
|
|
78
|
-
|
|
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("
|
|
91
|
+
span.set_attribute("gen_ai.instructions", kwargs["instructions"])
|
|
84
92
|
if kwargs.get("input"):
|
|
85
|
-
span.set_attribute("
|
|
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("
|
|
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("
|
|
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("
|
|
111
|
+
span.set_attribute(f"{SpanAttributes.LLM_USAGE_PROMPT_TOKENS}", usage["prompt_tokens"])
|
|
104
112
|
if usage.get("completion_tokens"):
|
|
105
|
-
span.set_attribute("
|
|
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("
|
|
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
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
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("
|
|
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]:
|
|
@@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "netra-sdk"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.15"
|
|
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.
|
|
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",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|