Metadata-Version: 2.4
Name: cloptima-llm-observability
Version: 0.1.2
Summary: LLM usage telemetry SDK for Cloptima reporting, attribution, and analytics
Author-email: Cloptima <support@cloptima.ai>
License: Copyright (c) Cloptima.
        All rights reserved.
        
        No part of this repository or package may be copied, modified, distributed,
        published, sublicensed, or sold except as explicitly authorized by Cloptima.
        
        This software may be made available publicly for source inspection and package
        consumption, but no open source license is granted by default.
        
        For commercial licensing or redistribution permissions, contact:
        support@cloptima.ai
        
Project-URL: Homepage, https://github.com/cloptima/cloptima-llm-observability-python#readme
Project-URL: Repository, https://github.com/cloptima/cloptima-llm-observability-python
Project-URL: Issues, https://github.com/cloptima/cloptima-llm-observability-python/issues
Project-URL: Documentation, https://github.com/cloptima/cloptima-llm-observability-python/tree/main/examples
Project-URL: Changelog, https://github.com/cloptima/cloptima-llm-observability-python/blob/main/CHANGELOG.md
Keywords: cloptima,llm,observability,telemetry,finops,otlp
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: System :: Monitoring
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: httpx
Requires-Dist: httpx>=0.27; extra == "httpx"
Dynamic: license-file

# Cloptima LLM Observability Python SDK

Capture LLM usage telemetry from your application and send it to Cloptima for cost reporting, attribution, and analytics.

This SDK is designed for teams that want observability without replacing their existing provider clients, wrappers, retries, auth, or application security controls.

## Install

```bash
pip install cloptima-llm-observability
```

If you want the `httpx` transport helpers:

```bash
pip install "cloptima-llm-observability[httpx]"
```

## Quick start

Required configuration:

- `CLOPTIMA_LLM_OBSERVABILITY_API_KEY`
- `CLOPTIMA_LLM_OBSERVABILITY_APP_ID`

Recommended while testing:

- `CLOPTIMA_LLM_OBSERVABILITY_ENVIRONMENT=dev`

```python
from cloptima_llm_observability import extract_openai_usage, init_from_env

cloptima = init_from_env()

result = cloptima.observe_call(
    provider="openai",
    model="gpt-4.1-mini",
    call=lambda: summary_service.generate(prompt),
    extract_usage=extract_openai_usage,
    feature_id="summary_generation",
    workflow_id="support_agent",
    fire_and_forget=False,
)
```

By default, the SDK sends bearer-authenticated HTTPS requests to Cloptima at `https://api.cloptima.ai/v1/ai/integrations/sdk/events`.

If the required configuration is missing, `init_from_env()` returns a disabled pass-through client so local development and tests do not break.

## Choose your integration path

### Call-site or wrapper boundary

This is the default path for most teams.

Use it when you already know the provider, model, and business context at the point where your code calls an LLM or an existing AI wrapper.

- `observe_call(...)` for direct integration
- `create_observed_call(...)` for reusable wrappers
- `wrap_observed_service(...)` to instrument customer-owned service classes

```python
from cloptima_llm_observability import (
    extract_openai_usage,
    init_from_env,
    wrap_observed_service,
)


class SummaryService:
    def generate_summary(self, prompt: str):
        return openai.responses.create(model="gpt-4.1-mini", input=prompt)


cloptima = init_from_env()
summary_service = wrap_observed_service(
    cloptima,
    SummaryService(),
    {
        "generate_summary": {
            "kind": "call",
            "options": {
                "provider": "openai",
                "model": "gpt-4.1-mini",
                "extract_usage": extract_openai_usage,
                "fire_and_forget": False,
            },
            "resolve_overrides": lambda prompt: {
                "attribution": {
                    "feature_id": "summary_generation",
                },
            },
        }
    },
)
```

### Context-first attribution

Use context helpers when you want workflow or feature attribution to apply across nested calls without threading more parameters through your own service signatures.

- `with_attribution(...)`
- `run_with_attribution(...)`
- `with_workflow(...)`
- `with_task(...)`
- `@workflow(...)`
- `@task(...)`

```python
from cloptima_llm_observability import with_task, with_workflow

with with_workflow("support_agent", tenant_id="acme-prod"):
    with with_task("draft_reply", team_id="customer-support"):
        summary_service.generate_summary(prompt)
```

Per-call attribution still works and overrides context when needed.

### Shared transport integration

If your application centralizes outbound LLM calls behind `httpx`, instrument that shared boundary:

```python
import httpx

from cloptima_llm_observability import init_from_env, instrument_httpx_transport

cloptima = init_from_env()
transport = instrument_httpx_transport(
    httpx.HTTPTransport(),
    cloptima=cloptima,
    provider="openai",
    model="gpt-4o-mini",
    fire_and_forget=False,
)
client = httpx.Client(transport=transport)
```

This gives broad coverage, but it has less business context than call-site or wrapper-boundary integration.

### OTLP delivery to Cloptima

Use `otlp_http` when your enterprise prefers OpenTelemetry-compatible payloads but still wants to send that telemetry to Cloptima.

- `cloptima_http` is the default delivery mode
- `otlp_http` sends OpenTelemetry-compatible payloads to Cloptima's OTLP receiver

```bash
CLOPTIMA_LLM_OBSERVABILITY_DELIVERY_MODE=otlp_http
CLOPTIMA_LLM_OBSERVABILITY_OTLP_SERVICE_NAME=agent-api
CLOPTIMA_LLM_OBSERVABILITY_OTLP_SERVICE_VERSION=2026.06.14
```

If you already operate an OTEL collector and emit GenAI spans, you can also send OTLP data to Cloptima without using this SDK. Use the SDK OTLP mode when you want application-managed instrumentation that still fits an OTLP-shaped delivery contract.

## Built-in extractors and compatibility

Built-in usage extractors cover:

- OpenAI
- Azure OpenAI
- Anthropic
- Gemini
- Vertex AI
- Bedrock

If a provider response shape drifts, you do not need to replace the whole extractor path. Compose or patch it instead:

- `try_extract_usage(...)`
- `compose_usage_extractors(...)`
- `with_usage_overrides(...)`
- `create_mapped_usage_extractor(...)`
- `list_supported_providers()`

## Attribution fields

Common ownership and reporting fields:

- `app_id`
- `environment`
- `team_id`
- `feature_id`
- `workflow_id`
- `cost_center`
- `business_unit`
- `product`
- `tenant_id`
- `end_customer_id`
- `customer_segment`
- `release`

Set defaults once in `default_attribution`, set them in context, or override them per call.

## Metadata and privacy

Use `metadata_policy` to control how custom metadata is retained:

- `metadata_only`
- `allowlisted_metadata`
- `strict_finops`
- `debug_observability`

Sensitive-looking keys such as prompts, messages, credentials, and secrets are treated conservatively by default.

## Validation and local previews

Use these helpers in local tests, CI, or rollout checks:

- `preview_event_payload(...)`
- `preview_batch_payload(...)`
- `preview_otlp_request(...)`
- `validate_payload(...)`

They build or validate payloads in memory and do not send network traffic.

## Examples

Public examples live in `examples/`:

- `basic.py`: direct call-site integration
- `custom_wrapper.py`: existing service wrapper integration
- `workflow_context.py`: context-first attribution without signature bloat
- `httpx_transport.py`: shared `httpx` integration
- `otlp_basic.py`: OTLP-compatible delivery to Cloptima
- `openai_basic.py`, `anthropic_basic.py`, `gemini_basic.py`: provider-specific extractor examples

## Troubleshooting

No telemetry arrives:

- verify the API key is valid for Cloptima telemetry ingestion
- check `client.is_enabled()`
- inspect a sample event with `validate_payload(preview_event_payload(...))`

Unexpected provider response shape:

- start with the closest built-in extractor
- patch field differences with `with_usage_overrides(...)` or `create_mapped_usage_extractor(...)`
- compare against `list_supported_providers()` if you need a supported-provider snapshot

## Support

- Issues: `https://github.com/cloptima/cloptima-llm-observability-python/issues`
- Security: see `SECURITY.md`
- Product support: `hello@cloptima.ai`
