revenium-python-sdk 0.2.0__tar.gz → 0.4.0__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.
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/PKG-INFO +152 -48
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/README.md +151 -47
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/pyproject.toml +1 -1
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/__init__.py +19 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/_core/config.py +9 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/_core/context.py +44 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/_core/exceptions.py +42 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/_core/fields.py +24 -1
- revenium_python_sdk-0.4.0/revenium_middleware/_core/outcomes.py +424 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/_core/trace_fields.py +58 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/_metering/resources/ai.py +8 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/_metering/types/ai_create_completion_params.py +3 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/agentic_outcomes.py +58 -104
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/anthropic/__init__.py +11 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/anthropic/bedrock_adapter.py +36 -14
- revenium_python_sdk-0.4.0/revenium_middleware/anthropic/bedrock_transport.py +483 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/anthropic/middleware.py +23 -4
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/anthropic/trace_fields.py +3 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/fal/_metering.py +2 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/fal/trace_fields.py +6 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/google/common/trace_fields.py +4 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/google/common/utils.py +12 -5
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/google/google_ai/middleware.py +1 -1
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/google/vertex_ai/middleware.py +1 -1
- revenium_python_sdk-0.4.0/revenium_middleware/job_context.py +508 -0
- revenium_python_sdk-0.4.0/revenium_middleware/job_history.py +127 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/litellm/client/__init__.py +2 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/litellm/client/decorators.py +110 -1
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/litellm/client/integrations/crewai.py +151 -24
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/litellm/client/middleware.py +19 -5
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/litellm/client/trace_fields.py +3 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/ollama/middleware.py +5 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/ollama/trace_fields.py +3 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/openai/middleware.py +14 -3
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/openai/trace_fields.py +3 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/perplexity/middleware.py +4 -1
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/perplexity/perplexity_sdk.py +4 -1
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/perplexity/trace_fields.py +3 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_python_sdk.egg-info/PKG-INFO +152 -48
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_python_sdk.egg-info/SOURCES.txt +4 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/tests/test_metering.py +30 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/LICENSE +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/_core/__init__.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/_core/decorators.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/_core/enforcement.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/_core/log_sanitize.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/_core/metering.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/_core/metering_buffer.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/_core/metering_submission.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/_core/patch_registry.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/_core/prompt_extraction.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/_core/subscriber.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/_metering/LICENSE +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/_metering/__init__.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/_metering/_base_client.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/_metering/_client.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/_metering/_compat.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/_metering/_constants.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/_metering/_exceptions.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/_metering/_files.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/_metering/_models.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/_metering/_qs.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/_metering/_resource.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/_metering/_response.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/_metering/_streaming.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/_metering/_types.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/_metering/_utils/__init__.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/_metering/_utils/_logs.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/_metering/_utils/_proxy.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/_metering/_utils/_reflection.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/_metering/_utils/_resources_proxy.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/_metering/_utils/_streams.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/_metering/_utils/_sync.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/_metering/_utils/_transform.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/_metering/_utils/_typing.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/_metering/_utils/_utils.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/_metering/_version.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/_metering/context.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/_metering/decorator.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/_metering/py.typed +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/_metering/resources/__init__.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/_metering/resources/apis.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/_metering/resources/events.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/_metering/types/__init__.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/_metering/types/ai_create_audio_params.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/_metering/types/ai_create_image_params.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/_metering/types/ai_create_video_params.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/_metering/types/api_meter_request_params.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/_metering/types/api_meter_response_params.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/_metering/types/event_create_params.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/_metering/types/metering_response_resource.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/anthropic/config.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/anthropic/prompt_extractor.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/anthropic/provider.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/anthropic/stream_create.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/fal/__init__.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/fal/config.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/fal/middleware.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/google/__init__.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/google/common/__init__.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/google/common/exceptions.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/google/common/protocols.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/google/common/types.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/google/config.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/google/google_ai/__init__.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/google/google_ai/provider.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/google/prompt_extractor.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/google/vertex_ai/__init__.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/google/vertex_ai/provider.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/litellm/__init__.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/litellm/client/config.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/litellm/client/context.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/litellm/client/hooks.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/litellm/client/integrations/__init__.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/litellm/client/validation.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/litellm/proxy/__init__.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/litellm/proxy/middleware.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/ollama/__init__.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/openai/__init__.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/openai/azure_config.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/openai/azure_model_resolver.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/openai/config.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/openai/exceptions.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/openai/langchain/__init__.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/openai/langchain/_utils.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/openai/langchain/unified_handler.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/openai/prompt_extractor.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/openai/provider.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/perplexity/__init__.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/perplexity/provider.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/webhooks/__init__.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_middleware/webhooks/_verify.py +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_python_sdk.egg-info/dependency_links.txt +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_python_sdk.egg-info/requires.txt +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/revenium_python_sdk.egg-info/top_level.txt +0 -0
- {revenium_python_sdk-0.2.0 → revenium_python_sdk-0.4.0}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: revenium-python-sdk
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: The official Revenium Python SDK — unified AI metering middleware for OpenAI, Anthropic, Google, Ollama, LiteLLM, Perplexity, and fal.ai.
|
|
5
5
|
Author-email: Revenium <support@revenium.io>
|
|
6
6
|
License: MIT
|
|
@@ -195,7 +195,7 @@ from dotenv import load_dotenv
|
|
|
195
195
|
load_dotenv()
|
|
196
196
|
|
|
197
197
|
import openai
|
|
198
|
-
import
|
|
198
|
+
import revenium_middleware.openai # Auto-initializes on import
|
|
199
199
|
|
|
200
200
|
client = openai.OpenAI()
|
|
201
201
|
response = client.chat.completions.create(
|
|
@@ -212,6 +212,70 @@ print(response.choices[0].message.content)
|
|
|
212
212
|
|
|
213
213
|
Emit per-agent terminal outcomes (`CONVERTED`, `DEFLECTED`, `ESCALATED`) alongside completion and tool-event records, so dashboards show business value next to AI cost.
|
|
214
214
|
|
|
215
|
+
> **You need a write-scope key (`rev_sk_`) to use the agentic outcomes API.** Metering keys (`rev_mk_`) can only meter completions and tool events — they cannot report, amend, or read job outcomes, and the SDK rejects them client-side before any HTTP request is made. Key resolution: explicit `api_key=` > `REVENIUM_OUTCOME_API_KEY` > `REVENIUM_METERING_API_KEY`.
|
|
216
|
+
|
|
217
|
+
### JobContext
|
|
218
|
+
|
|
219
|
+
`JobContext` is the recommended high-level API: every AI call made inside the block is automatically metered against the job (all provider middlewares pick the job fields up from context), and the job's business outcome is reported when the work is done.
|
|
220
|
+
|
|
221
|
+
```python
|
|
222
|
+
from revenium_middleware import JobContext
|
|
223
|
+
|
|
224
|
+
with JobContext("loan-app-12345", type="loan_processing", version="2.1") as job:
|
|
225
|
+
response = client.chat.completions.create(...) # metered against the job automatically
|
|
226
|
+
job.report_outcome(
|
|
227
|
+
execution_status="SUCCESS", # SUCCESS | FAILED | CANCELLED
|
|
228
|
+
outcome_type="CONVERTED",
|
|
229
|
+
outcome_value=500.0,
|
|
230
|
+
outcome_currency="USD",
|
|
231
|
+
)
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
- **Async:** `async with JobContext(...) as job:` works identically.
|
|
235
|
+
- **Auto-FAILED:** if an unhandled exception escapes the block before an outcome was reported, the context automatically reports `execution_status="FAILED"` (error message and class in metadata) and always re-raises the original exception.
|
|
236
|
+
- **Blocking:** outcome calls are synchronous HTTP requests with retries; tune how long they may block with the `retry_attempts`, `retry_initial_seconds`, and `retry_max_seconds` arguments, accepted by the `JobContext` constructor, `JobContext.attach()`, `get_outcome_history()`, and the CrewAI wrapper's `report_job_outcome`/`amend_job_outcome`.
|
|
237
|
+
- **Team resolution:** explicit `team_id=` > `REVENIUM_TEAM_ID` > automatic resolution from the API key; `OutcomeReportingError` is raised if none of these yields a team.
|
|
238
|
+
- **Nesting:** a nested `JobContext` is a different job (replace, not merge); exiting the inner context restores the outer job's fields.
|
|
239
|
+
|
|
240
|
+
To tag AI calls with job fields without a context manager, use per-call `usage_metadata={"agentic_job_id": ...}`, the `@track_job` decorator (LiteLLM), or the process-wide `REVENIUM_AGENTIC_JOB_*` environment variables — see [Optional Environment Variables](#optional-environment-variables).
|
|
241
|
+
|
|
242
|
+
### Amending an Outcome
|
|
243
|
+
|
|
244
|
+
Outcomes are amendable: when the business result changes after the fact, amend the recorded outcome instead of re-reporting it. `JobContext.attach()` returns a lightweight handle to an existing job — it is not entered as a context manager and does not touch AI-call scoping — so amendments work from a different process than the one that ran the job.
|
|
245
|
+
|
|
246
|
+
```python
|
|
247
|
+
from revenium_middleware import JobContext, get_outcome_history
|
|
248
|
+
|
|
249
|
+
# Two weeks after the agent converted the lead at $500,
|
|
250
|
+
# the customer expands to the annual plan.
|
|
251
|
+
job = JobContext.attach("sales-lead-8842")
|
|
252
|
+
job.amend_outcome(
|
|
253
|
+
reason="Customer expanded to the annual plan after the initial conversion",
|
|
254
|
+
outcome_value=750.0,
|
|
255
|
+
)
|
|
256
|
+
job.close()
|
|
257
|
+
|
|
258
|
+
history = get_outcome_history("sales-lead-8842")
|
|
259
|
+
# List[JobOutcomeAmendment], ordered by amendment_sequence (1 = the initial report)
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
`amend_outcome()` takes a mandatory non-blank `reason` plus the same optional fields as `report_outcome()` (`execution_status`, `outcome_type`, `outcome_value`, `outcome_currency`, `metadata`, `reported_by`), and returns the updated job as a dict.
|
|
263
|
+
|
|
264
|
+
### Outcome Exceptions
|
|
265
|
+
|
|
266
|
+
All outcome exceptions are importable from `revenium_middleware` and share the `OutcomeReportingError` base, so `except OutcomeReportingError:` catches the whole family:
|
|
267
|
+
|
|
268
|
+
| Exception | Raised when | What to do |
|
|
269
|
+
|-----------|-------------|------------|
|
|
270
|
+
| `OutcomeReportingError` | Base class — configuration failures (no API key available, unresolvable `team_id`) | Fix the key / team configuration |
|
|
271
|
+
| `OutcomeAlreadyReportedError` | Re-reporting a job that already has an outcome (backend 409) | Amend with `amend_outcome()` instead; the exception carries `reported_at` and `amendment_count` |
|
|
272
|
+
| `OutcomeNotReportedError` | Amending a job that has no outcome yet (backend 422) | Call `report_outcome()` first |
|
|
273
|
+
| `OutcomeAmendConflictError` | A concurrent amendment changed the outcome (backend 409, optimistic lock) | Refetch with `get_outcome_history()` and retry — the SDK does not auto-retry |
|
|
274
|
+
|
|
275
|
+
### Low-Level Client
|
|
276
|
+
|
|
277
|
+
For manual control over every metric (one `emit_completion` per LLM call, one `emit_tool_event` per tool/step), use `AgenticOutcomeClient` directly:
|
|
278
|
+
|
|
215
279
|
```python
|
|
216
280
|
from revenium_middleware.agentic_outcomes import AgenticOutcomeClient, AgenticOutcomeSettings
|
|
217
281
|
|
|
@@ -335,7 +399,7 @@ from dotenv import load_dotenv
|
|
|
335
399
|
load_dotenv()
|
|
336
400
|
|
|
337
401
|
import openai
|
|
338
|
-
import
|
|
402
|
+
import revenium_middleware.openai # Auto-initializes
|
|
339
403
|
|
|
340
404
|
client = openai.OpenAI()
|
|
341
405
|
|
|
@@ -374,7 +438,7 @@ The middleware automatically detects Azure OpenAI when using `AzureOpenAI()` and
|
|
|
374
438
|
|
|
375
439
|
```python
|
|
376
440
|
from openai import AzureOpenAI
|
|
377
|
-
import
|
|
441
|
+
import revenium_middleware.openai
|
|
378
442
|
|
|
379
443
|
client = AzureOpenAI(
|
|
380
444
|
azure_endpoint=os.getenv("AZURE_OPENAI_ENDPOINT"),
|
|
@@ -407,7 +471,7 @@ from dotenv import load_dotenv
|
|
|
407
471
|
load_dotenv()
|
|
408
472
|
|
|
409
473
|
import anthropic
|
|
410
|
-
import
|
|
474
|
+
import revenium_middleware.anthropic # Auto-initializes
|
|
411
475
|
|
|
412
476
|
client = anthropic.Anthropic()
|
|
413
477
|
|
|
@@ -442,7 +506,7 @@ The middleware provides complete AWS Bedrock integration with automatic detectio
|
|
|
442
506
|
|
|
443
507
|
```python
|
|
444
508
|
import anthropic
|
|
445
|
-
import
|
|
509
|
+
import revenium_middleware.anthropic
|
|
446
510
|
|
|
447
511
|
# Bedrock is automatically detected when AWS credentials are available
|
|
448
512
|
# and base_url contains 'amazonaws.com'
|
|
@@ -511,7 +575,7 @@ pip install "revenium-python-sdk[google-vertex]"
|
|
|
511
575
|
from dotenv import load_dotenv
|
|
512
576
|
load_dotenv()
|
|
513
577
|
|
|
514
|
-
import
|
|
578
|
+
import revenium_middleware.google
|
|
515
579
|
from google import genai
|
|
516
580
|
|
|
517
581
|
client = genai.Client()
|
|
@@ -532,7 +596,7 @@ print(response.text)
|
|
|
532
596
|
from dotenv import load_dotenv
|
|
533
597
|
load_dotenv()
|
|
534
598
|
|
|
535
|
-
import
|
|
599
|
+
import revenium_middleware.google
|
|
536
600
|
import vertexai
|
|
537
601
|
from vertexai.generative_models import GenerativeModel
|
|
538
602
|
|
|
@@ -573,7 +637,7 @@ from dotenv import load_dotenv
|
|
|
573
637
|
load_dotenv()
|
|
574
638
|
|
|
575
639
|
import ollama
|
|
576
|
-
import
|
|
640
|
+
import revenium_middleware.ollama # Auto-initializes
|
|
577
641
|
|
|
578
642
|
# Chat completion
|
|
579
643
|
response = ollama.chat(
|
|
@@ -608,7 +672,7 @@ response = ollama.embed(model='nomic-embed-text', input=['Text 1', 'Text 2', 'Te
|
|
|
608
672
|
|
|
609
673
|
```python
|
|
610
674
|
import openai
|
|
611
|
-
import
|
|
675
|
+
import revenium_middleware.openai
|
|
612
676
|
|
|
613
677
|
openai.api_key = 'ollama'
|
|
614
678
|
openai.base_url = 'http://localhost:11434/v1/'
|
|
@@ -636,7 +700,7 @@ Supports all LLM providers available through LiteLLM with two integration patter
|
|
|
636
700
|
from dotenv import load_dotenv
|
|
637
701
|
load_dotenv()
|
|
638
702
|
|
|
639
|
-
import
|
|
703
|
+
import revenium_middleware.litellm.client.middleware # Auto-initializes
|
|
640
704
|
import litellm
|
|
641
705
|
import os
|
|
642
706
|
|
|
@@ -659,7 +723,7 @@ Add the callback to your LiteLLM `config.yaml` for server-side integration:
|
|
|
659
723
|
|
|
660
724
|
```yaml
|
|
661
725
|
litellm_settings:
|
|
662
|
-
callbacks: ["
|
|
726
|
+
callbacks: ["revenium_middleware.litellm.proxy.middleware.proxy_handler_instance"]
|
|
663
727
|
```
|
|
664
728
|
|
|
665
729
|
When using the LiteLLM proxy, pass metadata via HTTP headers (`x-revenium-*`).
|
|
@@ -678,17 +742,47 @@ LiteLLM provides additional tracking decorators beyond the standard `@revenium_m
|
|
|
678
742
|
| `@track_product()` | Track product-specific usage |
|
|
679
743
|
| `@track_subscriber()` | Identify end users |
|
|
680
744
|
| `@track_quality()` | Track response quality scores |
|
|
745
|
+
| `@track_job()` | Inject agentic job fields for cost/ROI correlation, e.g. `@track_job(job_id="loan-app-12345", type="loan_processing")` |
|
|
681
746
|
|
|
682
|
-
|
|
747
|
+
The tracking decorators above support static values, extraction from function arguments (`name_from_arg`), or extraction from object attributes (`name_from_attr`); `@track_job` supports static values and argument extraction (`job_id_from_arg`, `type_from_arg`) but has no attribute variant.
|
|
683
748
|
|
|
684
749
|
#### CrewAI Integration
|
|
685
750
|
|
|
686
751
|
```bash
|
|
687
|
-
pip install "revenium-
|
|
752
|
+
pip install "revenium-python-sdk[litellm]" crewai
|
|
688
753
|
```
|
|
689
754
|
|
|
690
755
|
Pre-built wrapper for tracking CrewAI agent executions. **Note:** CrewAI requires Python 3.12 or earlier.
|
|
691
756
|
|
|
757
|
+
**Job outcome tracking:** pass the `agentic_job_*` kwargs to tie every LLM call in the crew to one agentic job, then report (or later amend) the job's business outcome. Requires a write-scope key (`rev_sk_`) — see [Agentic Outcomes](#agentic-outcomes-outcome-based-metering).
|
|
758
|
+
|
|
759
|
+
```python
|
|
760
|
+
from revenium_middleware.litellm.client.integrations.crewai import ReveniumCrewWrapper
|
|
761
|
+
|
|
762
|
+
crew = ReveniumCrewWrapper(
|
|
763
|
+
agents=[support_agent],
|
|
764
|
+
tasks=[triage_task],
|
|
765
|
+
organization_id="AcmeCorp",
|
|
766
|
+
subscription_id="82764738",
|
|
767
|
+
product_id="Platinum",
|
|
768
|
+
agentic_job_id="support-ticket-456",
|
|
769
|
+
agentic_job_name="Support Ticket Triage",
|
|
770
|
+
agentic_job_type="customer_support",
|
|
771
|
+
agentic_job_version="2.0",
|
|
772
|
+
)
|
|
773
|
+
result = crew.kickoff()
|
|
774
|
+
|
|
775
|
+
crew.report_job_outcome(
|
|
776
|
+
execution_status="SUCCESS",
|
|
777
|
+
outcome_type="DEFLECTED",
|
|
778
|
+
outcome_value=25.0,
|
|
779
|
+
)
|
|
780
|
+
|
|
781
|
+
# Later, if the business result changes:
|
|
782
|
+
# crew.amend_job_outcome(reason="Ticket reopened and escalated to a human agent",
|
|
783
|
+
# outcome_type="ESCALATED", outcome_value=0.0)
|
|
784
|
+
```
|
|
785
|
+
|
|
692
786
|
**LiteLLM environment variables:**
|
|
693
787
|
- `LITELLM_PROXY_URL` - Your LiteLLM proxy URL
|
|
694
788
|
- `LITELLM_API_KEY` - Your LiteLLM proxy API key
|
|
@@ -708,7 +802,7 @@ from dotenv import load_dotenv
|
|
|
708
802
|
load_dotenv()
|
|
709
803
|
|
|
710
804
|
from openai import OpenAI
|
|
711
|
-
import
|
|
805
|
+
import revenium_middleware.perplexity # Auto-patches OpenAI
|
|
712
806
|
|
|
713
807
|
client = OpenAI(
|
|
714
808
|
api_key=os.getenv("PERPLEXITY_API_KEY"),
|
|
@@ -726,7 +820,7 @@ response = client.chat.completions.create(
|
|
|
726
820
|
|
|
727
821
|
```python
|
|
728
822
|
from perplexity import Perplexity
|
|
729
|
-
import
|
|
823
|
+
import revenium_middleware.perplexity # Auto-patches Perplexity
|
|
730
824
|
|
|
731
825
|
client = Perplexity(api_key=os.getenv("PERPLEXITY_API_KEY"))
|
|
732
826
|
|
|
@@ -761,7 +855,7 @@ for chunk in stream:
|
|
|
761
855
|
Supports image, video, and audio generation through fal.ai with automatic media type detection.
|
|
762
856
|
|
|
763
857
|
```python
|
|
764
|
-
import
|
|
858
|
+
import revenium_middleware.fal # Auto-activates
|
|
765
859
|
import fal_client
|
|
766
860
|
|
|
767
861
|
result = fal_client.subscribe(
|
|
@@ -793,16 +887,23 @@ for image in result.get("images", []):
|
|
|
793
887
|
|
|
794
888
|
Callback handler that automatically tracks LLM calls, chains, tools, and agent actions.
|
|
795
889
|
|
|
890
|
+
```bash
|
|
891
|
+
pip install "revenium-python-sdk[langchain]"
|
|
892
|
+
```
|
|
893
|
+
|
|
894
|
+
Wrap any LangChain LLM (or embeddings model) with `wrap()` — the Revenium callback handler is attached for you:
|
|
895
|
+
|
|
796
896
|
```python
|
|
797
897
|
from langchain_openai import ChatOpenAI
|
|
798
|
-
from
|
|
898
|
+
from revenium_middleware.openai.langchain import wrap
|
|
799
899
|
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
900
|
+
llm = wrap(
|
|
901
|
+
ChatOpenAI(model="gpt-4o-mini"),
|
|
902
|
+
usage_metadata={
|
|
903
|
+
"trace_id": "session-123",
|
|
904
|
+
"agent": "support_agent",
|
|
905
|
+
},
|
|
803
906
|
)
|
|
804
|
-
|
|
805
|
-
llm = ChatOpenAI(model="gpt-4o-mini", callbacks=[handler])
|
|
806
907
|
response = llm.invoke("Hello!")
|
|
807
908
|
```
|
|
808
909
|
|
|
@@ -813,13 +914,14 @@ from langchain_core.prompts import ChatPromptTemplate
|
|
|
813
914
|
from langchain_core.output_parsers import StrOutputParser
|
|
814
915
|
|
|
815
916
|
prompt = ChatPromptTemplate.from_template("Tell me a joke about {topic}")
|
|
816
|
-
chain = prompt | llm |
|
|
917
|
+
chain = prompt | llm | StrOutputParser()
|
|
817
918
|
result = chain.invoke({"topic": "programming"})
|
|
818
919
|
```
|
|
819
920
|
|
|
820
921
|
**With agents:**
|
|
821
922
|
|
|
822
923
|
```python
|
|
924
|
+
from langchain_core.messages import HumanMessage
|
|
823
925
|
from langchain_core.tools import tool
|
|
824
926
|
from langgraph.prebuilt import create_react_agent
|
|
825
927
|
|
|
@@ -829,40 +931,32 @@ def get_weather(city: str) -> str:
|
|
|
829
931
|
return f"Sunny, 72F in {city}"
|
|
830
932
|
|
|
831
933
|
agent = create_react_agent(llm, [get_weather])
|
|
832
|
-
result = agent.invoke(
|
|
833
|
-
{"messages": [HumanMessage(content="Weather in NYC?")]},
|
|
834
|
-
config={"callbacks": [handler]}
|
|
835
|
-
)
|
|
934
|
+
result = agent.invoke({"messages": [HumanMessage(content="Weather in NYC?")]})
|
|
836
935
|
```
|
|
837
936
|
|
|
838
|
-
**Async support:**
|
|
937
|
+
**Async support:** the handler is async-native — wrap once and use `ainvoke`/`astream` directly:
|
|
839
938
|
|
|
840
939
|
```python
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
handler = AsyncReveniumCallbackHandler(trace_id="async-session")
|
|
844
|
-
llm = ChatOpenAI(model="gpt-4o-mini", callbacks=[handler])
|
|
940
|
+
llm = wrap(ChatOpenAI(model="gpt-4o-mini"))
|
|
845
941
|
response = await llm.ainvoke("Hello!")
|
|
846
942
|
```
|
|
847
943
|
|
|
848
944
|
**Supported providers:** OpenAI, Anthropic, Google, AWS Bedrock, Azure OpenAI, Cohere, HuggingFace, Ollama. Provider is auto-detected from LangChain class name or model name prefix.
|
|
849
945
|
|
|
850
|
-
**
|
|
946
|
+
**Attaching to an existing LLM:** use `attach_to()` to add tracking in-place, with any of the standard metadata fields (see [Metadata Fields](#metadata-fields)):
|
|
851
947
|
|
|
852
948
|
```python
|
|
853
|
-
from
|
|
854
|
-
|
|
855
|
-
config = ReveniumConfig(
|
|
856
|
-
api_key="hak_your_api_key",
|
|
857
|
-
environment="production",
|
|
858
|
-
organization_name="my_org",
|
|
859
|
-
product_name="my_product",
|
|
860
|
-
subscriber=SubscriberConfig(id="user_123", email="user@example.com"),
|
|
861
|
-
)
|
|
949
|
+
from revenium_middleware.openai.langchain import attach_to
|
|
862
950
|
|
|
863
|
-
|
|
951
|
+
attach_to(llm, usage_metadata={
|
|
952
|
+
"organizationName": "my_org",
|
|
953
|
+
"productName": "my_product",
|
|
954
|
+
"subscriber": {"id": "user_123", "email": "user@example.com"},
|
|
955
|
+
})
|
|
864
956
|
```
|
|
865
957
|
|
|
958
|
+
Credentials come from the standard environment variables (`REVENIUM_METERING_API_KEY`, `REVENIUM_METERING_BASE_URL`) or `revenium_middleware.configure()`.
|
|
959
|
+
|
|
866
960
|
---
|
|
867
961
|
|
|
868
962
|
## Metadata Fields
|
|
@@ -931,6 +1025,7 @@ Enhanced observability fields for tracking AI operations across environments, re
|
|
|
931
1025
|
| `parent_transaction_id` | `REVENIUM_PARENT_TRANSACTION_ID` | Parent transaction ID | Link child operations to parents across microservices |
|
|
932
1026
|
| `transaction_name` | `REVENIUM_TRANSACTION_NAME` | Human-friendly operation name | Label operations (e.g., `"Generate Response"`, `"Analyze Sentiment"`) |
|
|
933
1027
|
| `retry_number` | `REVENIUM_RETRY_NUMBER` | Retry attempt number (0 = first attempt) | Track retry attempts for failed operations |
|
|
1028
|
+
| `ticket_id` | `REVENIUM_TICKET_ID` | External ticket or issue ID (e.g., Jira, Linear) (max 256 chars) | Attribute AI costs to individual tickets or issues |
|
|
934
1029
|
|
|
935
1030
|
**Note:** `operation_type` (e.g., `CHAT`, `EMBED`, `TOOL_CALL`) and `operation_subtype` (e.g., `function_call`, `streaming`) are automatically detected by the middleware and cannot be overridden.
|
|
936
1031
|
|
|
@@ -958,7 +1053,8 @@ response = client.chat.completions.create(
|
|
|
958
1053
|
"trace_type": "customer-support",
|
|
959
1054
|
"trace_name": "Support Chat Session",
|
|
960
1055
|
"transaction_name": "Generate Response",
|
|
961
|
-
"parent_transaction_id": "parent-txn-123"
|
|
1056
|
+
"parent_transaction_id": "parent-txn-123",
|
|
1057
|
+
"ticket_id": "JIRA-123"
|
|
962
1058
|
}
|
|
963
1059
|
)
|
|
964
1060
|
```
|
|
@@ -1179,7 +1275,7 @@ Each field has a maximum length of **50,000 characters**. If exceeded, it's trun
|
|
|
1179
1275
|
import os
|
|
1180
1276
|
os.environ["REVENIUM_CAPTURE_PROMPTS"] = "true"
|
|
1181
1277
|
|
|
1182
|
-
import
|
|
1278
|
+
import revenium_middleware.openai
|
|
1183
1279
|
from openai import OpenAI
|
|
1184
1280
|
|
|
1185
1281
|
client = OpenAI()
|
|
@@ -1362,7 +1458,7 @@ print(get_buffer_stats())
|
|
|
1362
1458
|
| `REVENIUM_LOG_LEVEL` | `INFO` | Log level: `DEBUG`, `INFO`, `WARNING`, `ERROR`, `CRITICAL` |
|
|
1363
1459
|
| `REVENIUM_CAPTURE_PROMPTS` | `false` | Enable prompt capture |
|
|
1364
1460
|
| `REVENIUM_SELECTIVE_METERING` | `false` | Only meter `@revenium_meter` decorated functions |
|
|
1365
|
-
| `REVENIUM_TEAM_ID` | - | Team ID for cost lookups |
|
|
1461
|
+
| `REVENIUM_TEAM_ID` | - | Team ID for cost lookups and outcome reporting (JobContext team resolution) |
|
|
1366
1462
|
| `REVENIUM_ENVIRONMENT` | - | Deployment environment (auto-detects from `ENVIRONMENT`, `DEPLOYMENT_ENV`) |
|
|
1367
1463
|
| `REVENIUM_REGION` | - | Cloud region (auto-detects from `AWS_REGION`, `AZURE_REGION`, `GCP_REGION`) |
|
|
1368
1464
|
| `REVENIUM_CREDENTIAL_ALIAS` | - | Human-readable API key name |
|
|
@@ -1371,10 +1467,18 @@ print(get_buffer_stats())
|
|
|
1371
1467
|
| `REVENIUM_PARENT_TRANSACTION_ID` | - | Parent transaction ID for distributed tracing |
|
|
1372
1468
|
| `REVENIUM_TRANSACTION_NAME` | - | Human-friendly operation name |
|
|
1373
1469
|
| `REVENIUM_RETRY_NUMBER` | - | Retry attempt number |
|
|
1470
|
+
| `REVENIUM_AGENTIC_JOB_ID` | - | Agentic job instance ID attached to all completions in the process (triggers backend job auto-creation) |
|
|
1471
|
+
| `REVENIUM_AGENTIC_JOB_NAME` | - | Human-readable agentic job name |
|
|
1472
|
+
| `REVENIUM_AGENTIC_JOB_TYPE` | - | Agentic job type category |
|
|
1473
|
+
| `REVENIUM_AGENTIC_JOB_VERSION` | - | Agentic job version |
|
|
1474
|
+
| `REVENIUM_OUTCOME_API_KEY` | - | Write-scope key (`rev_sk_`) for the agentic outcomes API (report/amend/history); falls back to `REVENIUM_METERING_API_KEY` |
|
|
1475
|
+
| `REVENIUM_PROFITSTREAM_BASE_URL` | `https://api.revenium.io` | Agentic outcomes API base URL |
|
|
1374
1476
|
| `REVENIUM_BEDROCK_DISABLE` | - | Set to `1` to disable Bedrock auto-detection |
|
|
1375
1477
|
| `REVENIUM_BUFFER_MAX_SIZE` | `1000` | Store-and-forward buffer capacity (oldest events evicted when full) |
|
|
1376
1478
|
| `REVENIUM_BUFFER_FLUSH_INTERVAL` | `30` | Seconds between automatic replay attempts for buffered events |
|
|
1377
1479
|
|
|
1480
|
+
Per-call `usage_metadata` values take precedence over the `REVENIUM_AGENTIC_JOB_*` environment variables, and the LiteLLM proxy path sources job fields from `x-revenium-*` headers only — these process-level env fallbacks do not apply to proxied traffic.
|
|
1481
|
+
|
|
1378
1482
|
### Provider-Specific Environment Variables
|
|
1379
1483
|
|
|
1380
1484
|
| Variable | Provider | Description |
|
|
@@ -1416,7 +1520,7 @@ print(get_buffer_stats())
|
|
|
1416
1520
|
|
|
1417
1521
|
**Force direct Anthropic API:** Set `REVENIUM_BEDROCK_DISABLE=1` to disable Bedrock auto-detection.
|
|
1418
1522
|
|
|
1419
|
-
**Check initialization status:** Use `
|
|
1523
|
+
**Check initialization status (Anthropic):** Use `revenium_middleware.anthropic.is_initialized()` to verify setup.
|
|
1420
1524
|
|
|
1421
1525
|
---
|
|
1422
1526
|
|