revenium-python-sdk 0.1.0__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 (73) hide show
  1. revenium_middleware/__init__.py +184 -0
  2. revenium_middleware/_core/__init__.py +65 -0
  3. revenium_middleware/_core/config.py +165 -0
  4. revenium_middleware/_core/context.py +109 -0
  5. revenium_middleware/_core/decorators.py +202 -0
  6. revenium_middleware/_core/metering.py +207 -0
  7. revenium_middleware/_core/prompt_extraction.py +55 -0
  8. revenium_middleware/_core/subscriber.py +51 -0
  9. revenium_middleware/_core/trace_fields.py +265 -0
  10. revenium_middleware/anthropic/__init__.py +108 -0
  11. revenium_middleware/anthropic/bedrock_adapter.py +753 -0
  12. revenium_middleware/anthropic/config.py +29 -0
  13. revenium_middleware/anthropic/middleware.py +1070 -0
  14. revenium_middleware/anthropic/prompt_extractor.py +178 -0
  15. revenium_middleware/anthropic/provider.py +141 -0
  16. revenium_middleware/anthropic/summary_printer.py +286 -0
  17. revenium_middleware/anthropic/trace_fields.py +158 -0
  18. revenium_middleware/google/__init__.py +114 -0
  19. revenium_middleware/google/common/__init__.py +127 -0
  20. revenium_middleware/google/common/exceptions.py +137 -0
  21. revenium_middleware/google/common/protocols.py +192 -0
  22. revenium_middleware/google/common/summary_printer.py +271 -0
  23. revenium_middleware/google/common/trace_fields.py +205 -0
  24. revenium_middleware/google/common/types.py +208 -0
  25. revenium_middleware/google/common/utils.py +1111 -0
  26. revenium_middleware/google/config.py +64 -0
  27. revenium_middleware/google/google_ai/__init__.py +53 -0
  28. revenium_middleware/google/google_ai/middleware.py +667 -0
  29. revenium_middleware/google/google_ai/provider.py +135 -0
  30. revenium_middleware/google/prompt_extractor.py +396 -0
  31. revenium_middleware/google/vertex_ai/__init__.py +56 -0
  32. revenium_middleware/google/vertex_ai/middleware.py +1162 -0
  33. revenium_middleware/google/vertex_ai/provider.py +99 -0
  34. revenium_middleware/litellm/__init__.py +25 -0
  35. revenium_middleware/litellm/client/__init__.py +81 -0
  36. revenium_middleware/litellm/client/config.py +53 -0
  37. revenium_middleware/litellm/client/context.py +198 -0
  38. revenium_middleware/litellm/client/decorators.py +912 -0
  39. revenium_middleware/litellm/client/hooks.py +192 -0
  40. revenium_middleware/litellm/client/integrations/__init__.py +26 -0
  41. revenium_middleware/litellm/client/integrations/crewai.py +446 -0
  42. revenium_middleware/litellm/client/middleware.py +321 -0
  43. revenium_middleware/litellm/client/summary_printer.py +314 -0
  44. revenium_middleware/litellm/client/trace_fields.py +51 -0
  45. revenium_middleware/litellm/client/validation.py +207 -0
  46. revenium_middleware/litellm/proxy/__init__.py +25 -0
  47. revenium_middleware/litellm/proxy/middleware.py +217 -0
  48. revenium_middleware/ollama/__init__.py +28 -0
  49. revenium_middleware/ollama/middleware.py +569 -0
  50. revenium_middleware/ollama/trace_fields.py +63 -0
  51. revenium_middleware/openai/__init__.py +23 -0
  52. revenium_middleware/openai/azure_config.py +169 -0
  53. revenium_middleware/openai/azure_model_resolver.py +219 -0
  54. revenium_middleware/openai/config.py +45 -0
  55. revenium_middleware/openai/exceptions.py +115 -0
  56. revenium_middleware/openai/langchain/__init__.py +114 -0
  57. revenium_middleware/openai/langchain/_utils.py +129 -0
  58. revenium_middleware/openai/langchain/unified_handler.py +526 -0
  59. revenium_middleware/openai/middleware.py +1451 -0
  60. revenium_middleware/openai/prompt_extractor.py +173 -0
  61. revenium_middleware/openai/provider.py +170 -0
  62. revenium_middleware/openai/summary_printer.py +292 -0
  63. revenium_middleware/openai/trace_fields.py +98 -0
  64. revenium_middleware/perplexity/__init__.py +97 -0
  65. revenium_middleware/perplexity/middleware.py +379 -0
  66. revenium_middleware/perplexity/perplexity_sdk.py +256 -0
  67. revenium_middleware/perplexity/provider.py +84 -0
  68. revenium_middleware/perplexity/trace_fields.py +25 -0
  69. revenium_python_sdk-0.1.0.dist-info/METADATA +252 -0
  70. revenium_python_sdk-0.1.0.dist-info/RECORD +73 -0
  71. revenium_python_sdk-0.1.0.dist-info/WHEEL +5 -0
  72. revenium_python_sdk-0.1.0.dist-info/licenses/LICENSE +21 -0
  73. revenium_python_sdk-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,265 @@
1
+ """
2
+ Shared trace visualization field capture and validation.
3
+
4
+ This module provides the canonical implementations of trace field functions
5
+ shared across all provider middlewares. Provider-specific trace_fields modules
6
+ import from here and re-export, keeping only provider-specific functions.
7
+ """
8
+
9
+ import os
10
+ import re
11
+ import logging
12
+ from typing import Optional, Dict, Any
13
+
14
+ from .config import Config
15
+
16
+ logger = logging.getLogger(__name__)
17
+
18
+ # Re-export environment variable names from core config
19
+ ENV_REVENIUM_ENVIRONMENT = Config.ENV_REVENIUM_ENVIRONMENT
20
+ ENV_ENVIRONMENT = Config.ENV_ENVIRONMENT
21
+ ENV_DEPLOYMENT_ENV = Config.ENV_DEPLOYMENT_ENV
22
+
23
+ ENV_REVENIUM_REGION = Config.ENV_REVENIUM_REGION
24
+ ENV_AWS_REGION = "AWS_REGION"
25
+ ENV_AWS_DEFAULT_REGION = "AWS_DEFAULT_REGION"
26
+ ENV_AZURE_REGION = "AZURE_REGION"
27
+ ENV_GCP_REGION = "GCP_REGION"
28
+ ENV_GOOGLE_CLOUD_REGION = "GOOGLE_CLOUD_REGION"
29
+
30
+ ENV_REVENIUM_CREDENTIAL_ALIAS = Config.ENV_REVENIUM_CREDENTIAL_ALIAS
31
+ ENV_REVENIUM_TRACE_TYPE = Config.ENV_REVENIUM_TRACE_TYPE
32
+ ENV_REVENIUM_TRACE_NAME = Config.ENV_REVENIUM_TRACE_NAME
33
+ ENV_REVENIUM_PARENT_TRANSACTION_ID = Config.ENV_REVENIUM_PARENT_TRANSACTION_ID
34
+ ENV_REVENIUM_TRANSACTION_NAME = Config.ENV_REVENIUM_TRANSACTION_NAME
35
+ ENV_REVENIUM_RETRY_NUMBER = Config.ENV_REVENIUM_RETRY_NUMBER
36
+
37
+ # Validation constants
38
+ TRACE_TYPE_MAX_LENGTH = 128
39
+ TRACE_NAME_MAX_LENGTH = 256
40
+ TRACE_TYPE_PATTERN = re.compile(r'^[a-zA-Z0-9_-]+$')
41
+
42
+
43
+ def get_environment() -> Optional[str]:
44
+ """
45
+ Get deployment environment from environment variables.
46
+
47
+ Checks in order:
48
+ 1. REVENIUM_ENVIRONMENT
49
+ 2. ENVIRONMENT
50
+ 3. DEPLOYMENT_ENV
51
+
52
+ Returns:
53
+ Environment name (e.g., 'production', 'staging') or None
54
+ """
55
+ return (
56
+ os.getenv(ENV_REVENIUM_ENVIRONMENT) or
57
+ os.getenv(ENV_ENVIRONMENT) or
58
+ os.getenv(ENV_DEPLOYMENT_ENV)
59
+ )
60
+
61
+
62
+ def get_region() -> Optional[str]:
63
+ """
64
+ Get cloud region from environment variables.
65
+
66
+ Checks in order:
67
+ 1. REVENIUM_REGION
68
+ 2. AWS_REGION or AWS_DEFAULT_REGION
69
+ 3. AZURE_REGION
70
+ 4. GCP_REGION or GOOGLE_CLOUD_REGION
71
+
72
+ Returns:
73
+ Region name (e.g., 'us-east-1', 'eastus') or None
74
+ """
75
+ # Try Revenium-specific env var first
76
+ region = os.getenv(ENV_REVENIUM_REGION)
77
+ if region:
78
+ return region
79
+
80
+ # Try AWS region
81
+ region = os.getenv(ENV_AWS_REGION) or os.getenv(ENV_AWS_DEFAULT_REGION)
82
+ if region:
83
+ return region
84
+
85
+ # Try Azure region
86
+ region = os.getenv(ENV_AZURE_REGION)
87
+ if region:
88
+ return region
89
+
90
+ # Try GCP region
91
+ region = os.getenv(ENV_GCP_REGION) or os.getenv(ENV_GOOGLE_CLOUD_REGION)
92
+ if region:
93
+ return region
94
+
95
+ return None
96
+
97
+
98
+ def get_credential_alias() -> Optional[str]:
99
+ """
100
+ Get credential alias from environment variables.
101
+
102
+ Returns:
103
+ Credential alias (e.g., 'prod-api-key', 'staging-key') or None
104
+ """
105
+ return os.getenv(ENV_REVENIUM_CREDENTIAL_ALIAS)
106
+
107
+
108
+ def get_trace_type() -> Optional[str]:
109
+ """
110
+ Get and validate trace type from environment variables.
111
+
112
+ Returns:
113
+ Validated trace type or None if invalid/not set
114
+ """
115
+ trace_type = os.getenv(ENV_REVENIUM_TRACE_TYPE)
116
+ if trace_type:
117
+ return validate_trace_type(trace_type)
118
+ return None
119
+
120
+
121
+ def get_trace_name() -> Optional[str]:
122
+ """
123
+ Get and validate trace name from environment variables.
124
+
125
+ Returns:
126
+ Validated trace name (truncated if needed) or None if not set
127
+ """
128
+ trace_name = os.getenv(ENV_REVENIUM_TRACE_NAME)
129
+ if trace_name:
130
+ return validate_trace_name(trace_name)
131
+ return None
132
+
133
+
134
+ def get_parent_transaction_id() -> Optional[str]:
135
+ """
136
+ Get parent transaction ID from environment variables.
137
+
138
+ Returns:
139
+ Parent transaction ID or None
140
+ """
141
+ return os.getenv(ENV_REVENIUM_PARENT_TRANSACTION_ID)
142
+
143
+
144
+ def get_transaction_name(usage_metadata: Optional[Dict[str, Any]] = None) -> Optional[str]:
145
+ """
146
+ Get transaction name with fallback to task_type.
147
+
148
+ Checks in order:
149
+ 1. REVENIUM_TRANSACTION_NAME env var
150
+ 2. transactionName from usage_metadata
151
+ 3. task_type from usage_metadata (fallback)
152
+
153
+ Args:
154
+ usage_metadata: Optional metadata dictionary
155
+
156
+ Returns:
157
+ Transaction name or None
158
+ """
159
+ # First priority: env var
160
+ transaction_name = os.getenv(ENV_REVENIUM_TRANSACTION_NAME)
161
+ if transaction_name:
162
+ return transaction_name
163
+
164
+ # Second priority: usage_metadata
165
+ if usage_metadata:
166
+ transaction_name = (
167
+ usage_metadata.get('transactionName') or
168
+ usage_metadata.get('transaction_name')
169
+ )
170
+ if transaction_name:
171
+ return transaction_name
172
+
173
+ # Third priority: fallback to task_type
174
+ task_type = (
175
+ usage_metadata.get('task_type') or
176
+ usage_metadata.get('taskType')
177
+ )
178
+ if task_type:
179
+ return task_type
180
+
181
+ return None
182
+
183
+
184
+ def get_retry_number() -> int:
185
+ """
186
+ Get retry number from environment variables.
187
+
188
+ Returns:
189
+ Retry number (0 for first attempt, 1+ for retries)
190
+ """
191
+ try:
192
+ return int(os.getenv(ENV_REVENIUM_RETRY_NUMBER, '0'))
193
+ except ValueError:
194
+ logger.warning(
195
+ "Invalid REVENIUM_RETRY_NUMBER value, defaulting to 0"
196
+ )
197
+ return 0
198
+
199
+
200
+ def validate_trace_type(trace_type: str) -> Optional[str]:
201
+ """
202
+ Validate trace type format and length.
203
+
204
+ Rules:
205
+ - Only alphanumeric characters, hyphens, and underscores
206
+ - Maximum 128 characters
207
+
208
+ Args:
209
+ trace_type: Trace type to validate
210
+
211
+ Returns:
212
+ Valid trace type or None if invalid
213
+ """
214
+ if not trace_type:
215
+ return None
216
+
217
+ # Check length
218
+ if len(trace_type) > TRACE_TYPE_MAX_LENGTH:
219
+ logger.warning(
220
+ f"traceType exceeds maximum length of "
221
+ f"{TRACE_TYPE_MAX_LENGTH} characters: '{trace_type}'. "
222
+ f"Field will be omitted."
223
+ )
224
+ return None
225
+
226
+ # Check format
227
+ if not TRACE_TYPE_PATTERN.match(trace_type):
228
+ logger.warning(
229
+ f"traceType contains invalid characters "
230
+ f"(only alphanumeric, hyphens, and underscores allowed): "
231
+ f"'{trace_type}'. Field will be omitted."
232
+ )
233
+ return None
234
+
235
+ return trace_type
236
+
237
+
238
+ def validate_trace_name(trace_name: str) -> Optional[str]:
239
+ """
240
+ Validate trace name length and truncate if needed.
241
+
242
+ Rules:
243
+ - Maximum 256 characters
244
+ - Truncates with warning if too long
245
+
246
+ Args:
247
+ trace_name: Trace name to validate
248
+
249
+ Returns:
250
+ Valid trace name (truncated if needed) or None if empty
251
+ """
252
+ if not trace_name:
253
+ return None
254
+
255
+ # Check length and truncate if needed
256
+ if len(trace_name) > TRACE_NAME_MAX_LENGTH:
257
+ logger.warning(
258
+ f"traceName exceeds maximum length of "
259
+ f"{TRACE_NAME_MAX_LENGTH} characters. "
260
+ f"Truncating from {len(trace_name)} to "
261
+ f"{TRACE_NAME_MAX_LENGTH} characters."
262
+ )
263
+ return trace_name[:TRACE_NAME_MAX_LENGTH]
264
+
265
+ return trace_name
@@ -0,0 +1,108 @@
1
+ """
2
+ Revenium Middleware for Anthropic Python SDK
3
+
4
+ This library automatically hooks anthropic.resources.messages.create using wrapt,
5
+ and logs token usage after each request. You can customize or extend this logging
6
+ logic later to add user or organization metadata for metering purposes.
7
+
8
+ Now supports AWS Bedrock integration for routing Anthropic Claude models
9
+ through Amazon Bedrock while maintaining the same metering functionality.
10
+
11
+ Auto-initialization: The middleware is automatically initialized on import for
12
+ a simple "just works" experience. For explicit control, use the exported
13
+ initialize() function.
14
+ """
15
+
16
+ import logging
17
+ import os
18
+
19
+ logger = logging.getLogger("revenium_middleware.anthropic.init")
20
+
21
+ # Import provider detection (no SDK dependency)
22
+ from .provider import Provider, detect_provider, get_provider_metadata, is_bedrock_provider
23
+
24
+ # Conditionally import middleware (requires anthropic SDK)
25
+ try:
26
+ import anthropic # noqa: F401
27
+ from . import middleware
28
+ from .middleware import create_wrapper, usage_context
29
+ except ImportError:
30
+ logger.debug("Anthropic SDK (anthropic) not available, middleware not loaded")
31
+ middleware = None # type: ignore
32
+ create_wrapper = None # type: ignore
33
+ usage_context = None # type: ignore
34
+
35
+
36
+ def initialize():
37
+ """
38
+ Explicitly initialize the Revenium middleware.
39
+
40
+ This function can be called manually for explicit control over initialization,
41
+ or it's called automatically on import with graceful fallback.
42
+
43
+ Returns:
44
+ bool: True if initialization succeeded, False otherwise
45
+ """
46
+ try:
47
+ # Check if required environment variables are set
48
+ api_key = os.getenv("REVENIUM_METERING_API_KEY")
49
+ if not api_key:
50
+ logger.debug("REVENIUM_METERING_API_KEY not set - middleware will not meter requests")
51
+ return False
52
+
53
+ # The middleware is automatically activated by importing create_wrapper
54
+ # which uses @wrapt.patch_function_wrapper decorator
55
+ logger.debug("Revenium middleware initialized successfully")
56
+ return True
57
+
58
+ except Exception as e:
59
+ logger.debug(f"Failed to initialize Revenium middleware: {e}")
60
+ return False
61
+
62
+
63
+ def is_initialized():
64
+ """
65
+ Check if the middleware has been initialized.
66
+
67
+ Returns:
68
+ bool: True if middleware is active and ready to meter requests
69
+ """
70
+ try:
71
+ # Check if environment is properly configured
72
+ api_key = os.getenv("REVENIUM_METERING_API_KEY")
73
+ base_url = os.getenv("REVENIUM_METERING_BASE_URL")
74
+
75
+ return bool(api_key and base_url)
76
+ except Exception:
77
+ return False
78
+
79
+
80
+ # Auto-initialize with graceful fallback
81
+ try:
82
+ _auto_init_success = initialize()
83
+ if _auto_init_success:
84
+ logger.debug("Auto-initialization successful")
85
+ else:
86
+ logger.debug("Auto-initialization skipped - manual configuration may be needed")
87
+ except Exception as e:
88
+ # Log debug message but don't throw
89
+ # Allow manual configuration later
90
+ logger.debug(f"Auto-initialization failed: {e}")
91
+ _auto_init_success = False
92
+
93
+ # Export functions for explicit control
94
+ __all__ = [
95
+ # Core middleware components
96
+ "create_wrapper",
97
+ "usage_context",
98
+
99
+ # Provider detection
100
+ "Provider",
101
+ "detect_provider",
102
+ "get_provider_metadata",
103
+ "is_bedrock_provider",
104
+
105
+ # Initialization control
106
+ "initialize",
107
+ "is_initialized",
108
+ ]