cloptima-llm-observability 0.1.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.
@@ -0,0 +1,11 @@
1
+ Copyright (c) Cloptima.
2
+ All rights reserved.
3
+
4
+ No part of this repository or package may be copied, modified, distributed,
5
+ published, sublicensed, or sold except as explicitly authorized by Cloptima.
6
+
7
+ This software may be made available publicly for source inspection and package
8
+ consumption, but no open source license is granted by default.
9
+
10
+ For commercial licensing or redistribution permissions, contact:
11
+ support@cloptima.ai
@@ -0,0 +1,267 @@
1
+ Metadata-Version: 2.4
2
+ Name: cloptima-llm-observability
3
+ Version: 0.1.0
4
+ Summary: LLM usage telemetry SDK for Cloptima reporting, attribution, and analytics
5
+ Author-email: Cloptima <support@cloptima.ai>
6
+ License: Copyright (c) Cloptima.
7
+ All rights reserved.
8
+
9
+ No part of this repository or package may be copied, modified, distributed,
10
+ published, sublicensed, or sold except as explicitly authorized by Cloptima.
11
+
12
+ This software may be made available publicly for source inspection and package
13
+ consumption, but no open source license is granted by default.
14
+
15
+ For commercial licensing or redistribution permissions, contact:
16
+ support@cloptima.ai
17
+
18
+ Project-URL: Homepage, https://github.com/cloptima/cloptima-llm-observability-python#readme
19
+ Project-URL: Repository, https://github.com/cloptima/cloptima-llm-observability-python
20
+ Project-URL: Issues, https://github.com/cloptima/cloptima-llm-observability-python/issues
21
+ Project-URL: Documentation, https://github.com/cloptima/cloptima-llm-observability-python/tree/main/examples
22
+ Project-URL: Changelog, https://github.com/cloptima/cloptima-llm-observability-python/blob/main/CHANGELOG.md
23
+ Keywords: cloptima,llm,observability,telemetry,finops,otlp
24
+ Classifier: Development Status :: 4 - Beta
25
+ Classifier: Intended Audience :: Developers
26
+ Classifier: License :: OSI Approved :: MIT License
27
+ Classifier: Programming Language :: Python :: 3
28
+ Classifier: Programming Language :: Python :: 3.9
29
+ Classifier: Programming Language :: Python :: 3.10
30
+ Classifier: Programming Language :: Python :: 3.11
31
+ Classifier: Programming Language :: Python :: 3.12
32
+ Classifier: Programming Language :: Python :: 3.13
33
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
34
+ Classifier: Topic :: System :: Monitoring
35
+ Requires-Python: >=3.9
36
+ Description-Content-Type: text/markdown
37
+ License-File: LICENSE
38
+ Provides-Extra: httpx
39
+ Requires-Dist: httpx>=0.27; extra == "httpx"
40
+ Dynamic: license-file
41
+
42
+ # Cloptima LLM Observability Python SDK
43
+
44
+ Capture LLM usage telemetry from your application and send it to Cloptima for cost reporting, attribution, and analytics.
45
+
46
+ Use this SDK when you want visibility into LLM usage without replacing your existing provider clients, retry policies, authentication, or application-level security controls.
47
+
48
+ ## Install
49
+
50
+ ```bash
51
+ pip install cloptima-llm-observability
52
+ ```
53
+
54
+ If you want to use the `httpx` transport helpers, install the optional extra:
55
+
56
+ ```bash
57
+ pip install "cloptima-llm-observability[httpx]"
58
+ ```
59
+
60
+ ## Configuration
61
+
62
+ Required environment variables:
63
+
64
+ | Variable | Required | Purpose |
65
+ | --- | --- | --- |
66
+ | `CLOPTIMA_LLM_OBSERVABILITY_INGEST_URL` | Yes | HTTPS endpoint for SDK event ingestion |
67
+ | `CLOPTIMA_LLM_OBSERVABILITY_API_KEY` | Yes | Cloptima API key for telemetry writes |
68
+ | `CLOPTIMA_LLM_OBSERVABILITY_APP_ID` | Yes | Application or service identifier |
69
+ | `CLOPTIMA_LLM_OBSERVABILITY_ENVIRONMENT` | Yes | Deployment environment such as `dev`, `staging`, or `prod` |
70
+ | `CLOPTIMA_LLM_OBSERVABILITY_TEAM_ID` | No | Team or ownership group |
71
+ | `CLOPTIMA_LLM_OBSERVABILITY_ENABLED` | No | Explicitly enable or disable the SDK |
72
+ | `CLOPTIMA_LLM_OBSERVABILITY_DELIVERY_MODE` | No | `cloptima_http`, `otlp_http`, or `dual` |
73
+ | `CLOPTIMA_LLM_OBSERVABILITY_OTLP_URL` | No | Custom OTLP endpoint |
74
+ | `CLOPTIMA_LLM_OBSERVABILITY_OTLP_SERVICE_NAME` | No | OTLP service name |
75
+ | `CLOPTIMA_LLM_OBSERVABILITY_OTLP_SERVICE_VERSION` | No | OTLP service version |
76
+
77
+ The SDK sends bearer-authenticated HTTPS requests to the configured Cloptima ingest endpoint.
78
+
79
+ ## Quick start
80
+
81
+ Use `observe_call(...)` at the point where your application already invokes an LLM provider or an internal AI helper.
82
+
83
+ ```python
84
+ from cloptima_llm_observability import (
85
+ extract_openai_usage,
86
+ init_from_env,
87
+ )
88
+
89
+ cloptima = init_from_env()
90
+
91
+ result = cloptima.observe_call(
92
+ provider="openai",
93
+ model="gpt-4.1-mini",
94
+ call=lambda: summary_service.generate(prompt),
95
+ extract_usage=extract_openai_usage,
96
+ feature_id="summaries",
97
+ workflow_id="support-agent",
98
+ team_id="customer-support",
99
+ fire_and_forget=False,
100
+ )
101
+ ```
102
+
103
+ This integration style works well because it:
104
+
105
+ - keeps your existing provider integration intact
106
+ - captures the most accurate model and feature context
107
+ - avoids SDK-specific coupling throughout your codebase
108
+ - works well with existing wrappers and shared AI services
109
+
110
+ ## Async and streaming calls
111
+
112
+ If your application already uses async calls or streaming responses, use the matching helpers:
113
+
114
+ ```python
115
+ result = await cloptima.observe_async_call(
116
+ provider="anthropic",
117
+ model="claude-3-5-sonnet",
118
+ call=lambda: assistant_client.reply(messages),
119
+ feature_id="chat_reply",
120
+ )
121
+
122
+ async for chunk in cloptima.observe_async_stream_call(
123
+ provider="openai",
124
+ model="gpt-4.1-mini",
125
+ call=lambda: stream_client.stream(prompt),
126
+ feature_id="live_answer",
127
+ ):
128
+ print(chunk)
129
+ ```
130
+
131
+ ## Shared transport integration
132
+
133
+ If your application centralizes outbound LLM calls behind a shared `httpx` transport, instrument that boundary instead:
134
+
135
+ ```python
136
+ import httpx
137
+
138
+ from cloptima_llm_observability import init_from_env, instrument_httpx_transport
139
+
140
+ cloptima = init_from_env()
141
+ transport = instrument_httpx_transport(
142
+ httpx.HTTPTransport(),
143
+ cloptima=cloptima,
144
+ provider="openai",
145
+ model="gpt-4o-mini",
146
+ fire_and_forget=False,
147
+ )
148
+ client = httpx.Client(transport=transport)
149
+ ```
150
+
151
+ This is useful for broad coverage, but it has less application context than `observe_call(...)`. Prefer the boundary helper when you already know the provider, model, and feature at the call site.
152
+
153
+ ## OTLP mode
154
+
155
+ The SDK supports three delivery modes:
156
+
157
+ - `cloptima_http`
158
+ - `otlp_http`
159
+ - `dual`
160
+
161
+ Use `otlp_http` or `dual` when you want OpenTelemetry-compatible output in addition to, or instead of, direct Cloptima delivery.
162
+
163
+ ## Attribution fields
164
+
165
+ The most useful fields for reporting and ownership are:
166
+
167
+ - `app_id`
168
+ - `environment`
169
+ - `team_id`
170
+ - `feature_id`
171
+ - `workflow_id`
172
+ - `cost_center`
173
+ - `business_unit`
174
+ - `tenant_id`
175
+ - `customer_segment`
176
+ - `cloud_account_id`
177
+ - `cluster_id`
178
+ - `repository_id`
179
+
180
+ You can pass them through `default_attribution`, or directly on `observe_call(...)` / `observe_stream_call(...)`.
181
+
182
+ ## Metadata controls
183
+
184
+ Use `metadata_policy` to control what custom metadata is retained:
185
+
186
+ - `metadata_only`
187
+ - `allowlisted_metadata`
188
+ - `strict_finops`
189
+ - `debug_observability`
190
+
191
+ Sensitive-looking keys such as prompts, messages, credentials, and secrets are treated conservatively by default.
192
+
193
+ ## Validation helpers
194
+
195
+ These helpers are useful when you want to inspect payloads locally before sending traffic to Cloptima:
196
+
197
+ - `preview_event_payload(...)`
198
+ - `preview_batch_payload(...)`
199
+ - `preview_otlp_request(...)`
200
+ - `validate_payload(...)`
201
+
202
+ They return payload previews in memory and do not send network traffic.
203
+
204
+ ## Examples
205
+
206
+ See the `examples/` directory for:
207
+
208
+ - OpenAI boundary instrumentation
209
+ - Anthropic boundary instrumentation
210
+ - Gemini boundary instrumentation
211
+ - custom wrapper instrumentation
212
+ - httpx transport instrumentation
213
+
214
+ ## Public API
215
+
216
+ Stable core surface:
217
+
218
+ - `CloptimaLLMObservability`
219
+ - `init_from_env`
220
+ - `disabled_client`
221
+ - `observe`
222
+ - `observe_call`
223
+ - `observe_async_call`
224
+ - `observe_stream`
225
+ - `observe_stream_call`
226
+ - `record`
227
+ - `record_batch`
228
+ - `record_async`
229
+ - provider usage extractors
230
+
231
+ Additional helper surface:
232
+
233
+ - `instrument_httpx_client`
234
+ - `instrument_httpx_transport`
235
+ - `instrument_openai_compatible_response`
236
+ - `instrument_openai_compatible_stream`
237
+ - `ainstrument_openai_compatible_response`
238
+ - `ainstrument_openai_compatible_stream`
239
+ - `instrument_fastapi_request_context`
240
+ - `instrument_flask_request_context`
241
+
242
+ ## Troubleshooting
243
+
244
+ No telemetry arrives:
245
+
246
+ - verify `CLOPTIMA_LLM_OBSERVABILITY_INGEST_URL`
247
+ - verify the API key is valid for SDK event ingestion
248
+ - check `client.is_enabled()`
249
+ - inspect a sample event with `validate_payload(preview_event_payload(...))`
250
+
251
+ Configuration behavior:
252
+
253
+ - `init_from_env()` returns a disabled pass-through client when configuration is absent
254
+ - if you explicitly enable the SDK with incomplete config, initialization stays non-blocking by default unless `strict=True`
255
+
256
+ ## Payload contracts
257
+
258
+ - single event schema: `cloptima.llm.event.v1`
259
+ - batch schema: `cloptima.llm.batch.v1`
260
+
261
+ SDK envelopes also include `sdk_delivery_stats` for delivery monitoring.
262
+
263
+ ## Support
264
+
265
+ - Issues: `https://github.com/cloptima/cloptima-llm-observability-python/issues`
266
+ - Security: see `SECURITY.md`
267
+ - Product support: `hello@cloptima.ai`
@@ -0,0 +1,226 @@
1
+ # Cloptima LLM Observability Python SDK
2
+
3
+ Capture LLM usage telemetry from your application and send it to Cloptima for cost reporting, attribution, and analytics.
4
+
5
+ Use this SDK when you want visibility into LLM usage without replacing your existing provider clients, retry policies, authentication, or application-level security controls.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ pip install cloptima-llm-observability
11
+ ```
12
+
13
+ If you want to use the `httpx` transport helpers, install the optional extra:
14
+
15
+ ```bash
16
+ pip install "cloptima-llm-observability[httpx]"
17
+ ```
18
+
19
+ ## Configuration
20
+
21
+ Required environment variables:
22
+
23
+ | Variable | Required | Purpose |
24
+ | --- | --- | --- |
25
+ | `CLOPTIMA_LLM_OBSERVABILITY_INGEST_URL` | Yes | HTTPS endpoint for SDK event ingestion |
26
+ | `CLOPTIMA_LLM_OBSERVABILITY_API_KEY` | Yes | Cloptima API key for telemetry writes |
27
+ | `CLOPTIMA_LLM_OBSERVABILITY_APP_ID` | Yes | Application or service identifier |
28
+ | `CLOPTIMA_LLM_OBSERVABILITY_ENVIRONMENT` | Yes | Deployment environment such as `dev`, `staging`, or `prod` |
29
+ | `CLOPTIMA_LLM_OBSERVABILITY_TEAM_ID` | No | Team or ownership group |
30
+ | `CLOPTIMA_LLM_OBSERVABILITY_ENABLED` | No | Explicitly enable or disable the SDK |
31
+ | `CLOPTIMA_LLM_OBSERVABILITY_DELIVERY_MODE` | No | `cloptima_http`, `otlp_http`, or `dual` |
32
+ | `CLOPTIMA_LLM_OBSERVABILITY_OTLP_URL` | No | Custom OTLP endpoint |
33
+ | `CLOPTIMA_LLM_OBSERVABILITY_OTLP_SERVICE_NAME` | No | OTLP service name |
34
+ | `CLOPTIMA_LLM_OBSERVABILITY_OTLP_SERVICE_VERSION` | No | OTLP service version |
35
+
36
+ The SDK sends bearer-authenticated HTTPS requests to the configured Cloptima ingest endpoint.
37
+
38
+ ## Quick start
39
+
40
+ Use `observe_call(...)` at the point where your application already invokes an LLM provider or an internal AI helper.
41
+
42
+ ```python
43
+ from cloptima_llm_observability import (
44
+ extract_openai_usage,
45
+ init_from_env,
46
+ )
47
+
48
+ cloptima = init_from_env()
49
+
50
+ result = cloptima.observe_call(
51
+ provider="openai",
52
+ model="gpt-4.1-mini",
53
+ call=lambda: summary_service.generate(prompt),
54
+ extract_usage=extract_openai_usage,
55
+ feature_id="summaries",
56
+ workflow_id="support-agent",
57
+ team_id="customer-support",
58
+ fire_and_forget=False,
59
+ )
60
+ ```
61
+
62
+ This integration style works well because it:
63
+
64
+ - keeps your existing provider integration intact
65
+ - captures the most accurate model and feature context
66
+ - avoids SDK-specific coupling throughout your codebase
67
+ - works well with existing wrappers and shared AI services
68
+
69
+ ## Async and streaming calls
70
+
71
+ If your application already uses async calls or streaming responses, use the matching helpers:
72
+
73
+ ```python
74
+ result = await cloptima.observe_async_call(
75
+ provider="anthropic",
76
+ model="claude-3-5-sonnet",
77
+ call=lambda: assistant_client.reply(messages),
78
+ feature_id="chat_reply",
79
+ )
80
+
81
+ async for chunk in cloptima.observe_async_stream_call(
82
+ provider="openai",
83
+ model="gpt-4.1-mini",
84
+ call=lambda: stream_client.stream(prompt),
85
+ feature_id="live_answer",
86
+ ):
87
+ print(chunk)
88
+ ```
89
+
90
+ ## Shared transport integration
91
+
92
+ If your application centralizes outbound LLM calls behind a shared `httpx` transport, instrument that boundary instead:
93
+
94
+ ```python
95
+ import httpx
96
+
97
+ from cloptima_llm_observability import init_from_env, instrument_httpx_transport
98
+
99
+ cloptima = init_from_env()
100
+ transport = instrument_httpx_transport(
101
+ httpx.HTTPTransport(),
102
+ cloptima=cloptima,
103
+ provider="openai",
104
+ model="gpt-4o-mini",
105
+ fire_and_forget=False,
106
+ )
107
+ client = httpx.Client(transport=transport)
108
+ ```
109
+
110
+ This is useful for broad coverage, but it has less application context than `observe_call(...)`. Prefer the boundary helper when you already know the provider, model, and feature at the call site.
111
+
112
+ ## OTLP mode
113
+
114
+ The SDK supports three delivery modes:
115
+
116
+ - `cloptima_http`
117
+ - `otlp_http`
118
+ - `dual`
119
+
120
+ Use `otlp_http` or `dual` when you want OpenTelemetry-compatible output in addition to, or instead of, direct Cloptima delivery.
121
+
122
+ ## Attribution fields
123
+
124
+ The most useful fields for reporting and ownership are:
125
+
126
+ - `app_id`
127
+ - `environment`
128
+ - `team_id`
129
+ - `feature_id`
130
+ - `workflow_id`
131
+ - `cost_center`
132
+ - `business_unit`
133
+ - `tenant_id`
134
+ - `customer_segment`
135
+ - `cloud_account_id`
136
+ - `cluster_id`
137
+ - `repository_id`
138
+
139
+ You can pass them through `default_attribution`, or directly on `observe_call(...)` / `observe_stream_call(...)`.
140
+
141
+ ## Metadata controls
142
+
143
+ Use `metadata_policy` to control what custom metadata is retained:
144
+
145
+ - `metadata_only`
146
+ - `allowlisted_metadata`
147
+ - `strict_finops`
148
+ - `debug_observability`
149
+
150
+ Sensitive-looking keys such as prompts, messages, credentials, and secrets are treated conservatively by default.
151
+
152
+ ## Validation helpers
153
+
154
+ These helpers are useful when you want to inspect payloads locally before sending traffic to Cloptima:
155
+
156
+ - `preview_event_payload(...)`
157
+ - `preview_batch_payload(...)`
158
+ - `preview_otlp_request(...)`
159
+ - `validate_payload(...)`
160
+
161
+ They return payload previews in memory and do not send network traffic.
162
+
163
+ ## Examples
164
+
165
+ See the `examples/` directory for:
166
+
167
+ - OpenAI boundary instrumentation
168
+ - Anthropic boundary instrumentation
169
+ - Gemini boundary instrumentation
170
+ - custom wrapper instrumentation
171
+ - httpx transport instrumentation
172
+
173
+ ## Public API
174
+
175
+ Stable core surface:
176
+
177
+ - `CloptimaLLMObservability`
178
+ - `init_from_env`
179
+ - `disabled_client`
180
+ - `observe`
181
+ - `observe_call`
182
+ - `observe_async_call`
183
+ - `observe_stream`
184
+ - `observe_stream_call`
185
+ - `record`
186
+ - `record_batch`
187
+ - `record_async`
188
+ - provider usage extractors
189
+
190
+ Additional helper surface:
191
+
192
+ - `instrument_httpx_client`
193
+ - `instrument_httpx_transport`
194
+ - `instrument_openai_compatible_response`
195
+ - `instrument_openai_compatible_stream`
196
+ - `ainstrument_openai_compatible_response`
197
+ - `ainstrument_openai_compatible_stream`
198
+ - `instrument_fastapi_request_context`
199
+ - `instrument_flask_request_context`
200
+
201
+ ## Troubleshooting
202
+
203
+ No telemetry arrives:
204
+
205
+ - verify `CLOPTIMA_LLM_OBSERVABILITY_INGEST_URL`
206
+ - verify the API key is valid for SDK event ingestion
207
+ - check `client.is_enabled()`
208
+ - inspect a sample event with `validate_payload(preview_event_payload(...))`
209
+
210
+ Configuration behavior:
211
+
212
+ - `init_from_env()` returns a disabled pass-through client when configuration is absent
213
+ - if you explicitly enable the SDK with incomplete config, initialization stays non-blocking by default unless `strict=True`
214
+
215
+ ## Payload contracts
216
+
217
+ - single event schema: `cloptima.llm.event.v1`
218
+ - batch schema: `cloptima.llm.batch.v1`
219
+
220
+ SDK envelopes also include `sdk_delivery_stats` for delivery monitoring.
221
+
222
+ ## Support
223
+
224
+ - Issues: `https://github.com/cloptima/cloptima-llm-observability-python/issues`
225
+ - Security: see `SECURITY.md`
226
+ - Product support: `hello@cloptima.ai`
@@ -0,0 +1,71 @@
1
+ from .client import (
2
+ ainstrument_openai_compatible_response,
3
+ ainstrument_openai_compatible_stream,
4
+ CloptimaLLMObservability,
5
+ CloptimaLLMClientStats,
6
+ DisabledCloptimaLLMObservability,
7
+ LLMAttribution,
8
+ LLMUsageEvent,
9
+ MetadataPrivacyPolicy,
10
+ disabled_client,
11
+ extract_anthropic_usage,
12
+ extract_anthropic_stream_usage,
13
+ extract_azure_openai_usage,
14
+ extract_bedrock_stream_usage,
15
+ extract_bedrock_usage,
16
+ extract_gemini_stream_usage,
17
+ extract_gemini_usage,
18
+ init_from_env,
19
+ instrument_fastapi_request_context,
20
+ instrument_flask_request_context,
21
+ instrument_httpx_client,
22
+ instrument_httpx_transport,
23
+ instrument_httpx_transport_metadata,
24
+ instrument_openai_compatible_response,
25
+ instrument_openai_compatible_stream,
26
+ is_enabled,
27
+ preview_batch_payload,
28
+ preview_event_payload,
29
+ preview_otlp_request,
30
+ extract_openai_usage,
31
+ extract_openai_stream_usage,
32
+ extract_vertex_stream_usage,
33
+ extract_vertex_usage,
34
+ validate_payload,
35
+ )
36
+
37
+ __all__ = [
38
+ "CloptimaLLMObservability",
39
+ "CloptimaLLMClientStats",
40
+ "LLMAttribution",
41
+ "LLMUsageEvent",
42
+ "MetadataPrivacyPolicy",
43
+ "ainstrument_openai_compatible_response",
44
+ "ainstrument_openai_compatible_stream",
45
+ "DisabledCloptimaLLMObservability",
46
+ "disabled_client",
47
+ "extract_anthropic_usage",
48
+ "extract_anthropic_stream_usage",
49
+ "extract_azure_openai_usage",
50
+ "extract_bedrock_stream_usage",
51
+ "extract_bedrock_usage",
52
+ "extract_gemini_stream_usage",
53
+ "extract_gemini_usage",
54
+ "init_from_env",
55
+ "instrument_fastapi_request_context",
56
+ "instrument_flask_request_context",
57
+ "instrument_httpx_client",
58
+ "instrument_httpx_transport",
59
+ "instrument_httpx_transport_metadata",
60
+ "instrument_openai_compatible_response",
61
+ "instrument_openai_compatible_stream",
62
+ "is_enabled",
63
+ "preview_batch_payload",
64
+ "preview_event_payload",
65
+ "preview_otlp_request",
66
+ "extract_openai_usage",
67
+ "extract_openai_stream_usage",
68
+ "extract_vertex_stream_usage",
69
+ "extract_vertex_usage",
70
+ "validate_payload",
71
+ ]