Metadata-Version: 2.5
Name: spendlensai
Version: 0.1.7
Summary: Python SDK for SpendLens AI.
Author: SpendLens AI
License-Expression: MIT
Requires-Python: >=3.9
Description-Content-Type: text/markdown

# SpendLens AI Python SDK

Track supported OpenAI and Anthropic calls without proxying model traffic. SpendLens records operational metadata, token usage, latency, cache counters, workload context, and privacy-safe prompt-template context.

## Install

```bash
pip install spendlensai
```

Configure the SDK through environment variables:

```text
SPENDLENS_API_KEY=sli_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
SPENDLENS_PROJECT=shopping-assistant
SPENDLENS_API_BASE_URL=https://spendlensai.dev/backend
SPENDLENS_PROMPT_SAMPLING=template_only
SPENDLENS_DISABLE=0
```

The SDK reads process environment variables. A local `.env` file must be loaded by your application or runtime; production secrets should be injected by your deployment platform.

`SPENDLENS_PROJECT` must match an existing SpendLens project name or slug. Unknown projects are not created automatically; provider calls continue, while telemetry is dropped with a warning.

## Choose your integration

### Existing application: add one decorator

Keep your standard provider client and mark the business workflow:

```python
import spendlensai
from openai import OpenAI

client = OpenAI()

@spendlensai.observe(workload="customer-support-reply")
def generate_customer_reply(message: str):
    return client.chat.completions.create(
        model="gpt-4o",
        messages=[
            {
                "role": "system",
                "content": "You are a customer-support assistant. Give concise, accurate billing help.",
            },
            {"role": "user", "content": message},
        ],
    )
```

The bare form derives a stable endpoint from the module and qualified function name:

```python
@spendlensai.observe
async def generate_customer_reply(message: str):
    return await client.chat.completions.create(...)
```

Decorator mode currently instruments supported official Python SDK operations:

- OpenAI `chat.completions.create`
- OpenAI `responses.create`
- Anthropic `messages.create`
- Supported sync and async variants

Direct REST calls and arbitrary HTTP traffic are not automatically captured.

### Compare the dashboard's top three models in staging

Create a campaign in **Model Savings**, add local provider keys for its candidates, then turn on Compare Mode for that workload:

```python
@spendlensai.observe(workload="customer-support-reply", compare_mode=True)
def generate_customer_reply(message: str):
    return client.chat.completions.create(...)
```

Set only the provider keys required by the candidates in that campaign:

```dotenv
OPENAI_API_KEY=sk-...
ANTHROPIC_API_KEY=sk-ant-...
DEEPSEEK_API_KEY=sk-...
MISTRAL_API_KEY=...
GOOGLE_API_KEY=...       # Gemini; GEMINI_API_KEY is also accepted
DASHSCOPE_API_KEY=...    # Qwen
```

The provider keys remain in the staging process and are separate from `SPENDLENS_API_KEY`.

The SDK runs candidate model calls inside your staging application using provider keys you control and sends only aggregate cost, token, latency, reliability and error results to SpendLens. It never runs the quality judge. Optional quality evaluation is controlled from the dashboard and runs on SpendLens infrastructure using SpendLens provider credentials, the redacted template and safe generated data. Dynamic prompt values and production responses are never used for hosted quality evaluation.

### Precision tracking for new or complex applications

Use the existing tracked client when one function makes several unrelated calls or you need exact task and metadata attribution:

```python
from openai import OpenAI
from spendlensai import track

client = track(OpenAI())

with client.tag(
    endpoint="customer-support-reply",
    task="generation",
    metadata={"feature": "support"},
):
    response = client.chat.completions.create(...)
```

When both integrations are used, attribution precedence is:

```text
client.tag() → @spendlensai.observe → inferred callsite
```

The SDK prevents the same tracked call from being recorded twice.

## Environment variables

| Variable | Required? | Description |
| --- | --- | --- |
| `SPENDLENS_API_KEY` | Yes | SpendLens test or live ingestion key. |
| `SPENDLENS_PROJECT` | Yes for decorator mode | Existing dashboard project name or slug. |
| `SPENDLENS_API_BASE_URL` | No | Defaults to `https://spendlensai.dev/backend`. Do not append `/v1`. |
| `SPENDLENS_PROMPT_SAMPLING` | No | `template_only` by default; may be `off` or `redacted_sample`. |
| `SPENDLENS_DISABLE` | No | Set to `1` to disable tracking without changing application code. |

Existing explicit `track(...)` options remain supported for backwards compatibility.

## Tags and metadata

Use short, stable endpoint names such as `recommend-products`, `classify-review`, `summarize-ticket`, or `support-rag-answer`.

```python
with client.tag(
    endpoint="recommend-products",
    task="generation",
    metadata={"customer_tier": "enterprise", "region": "us"},
):
    response = client.chat.completions.create(...)
```

Do not put prompts, API keys, emails, or personal information in metadata. Nested tags are supported; inner values take precedence.

## Prompt privacy

`SPENDLENS_PROMPT_SAMPLING=template_only` is the recommended default. It sends reusable OpenAI system/developer instructions or Anthropic `system` content to improve workload classification. It does not send user messages, full message arrays, or model responses.

Set this for metadata-only tracking:

```text
SPENDLENS_PROMPT_SAMPLING=off
```

Prompt templates are truncated conservatively. API keys and prompt content are never written to SDK logs.

## Cache efficiency

When providers return cache usage, SpendLens records it automatically:

- OpenAI: `usage.prompt_tokens_details.cached_tokens`
- Anthropic: `usage.cache_read_input_tokens` and `usage.cache_creation_input_tokens`

SpendLens reports cache metrics as unavailable when the provider does not return them rather than inventing zero values.

## Short processes

Tracked clients expose `flush()` for scripts, jobs, tests, and notebooks:

```python
client.flush()
```

Long-running applications normally flush queued events automatically.

## Failure behavior

Telemetry delivery is asynchronous and fail-open. SpendLens failures do not replace provider responses. Invalid or missing decorator configuration raises a clear configuration error on the first observed provider call. Set `SPENDLENS_DISABLE=1` to disable all SpendLens activity.

SpendLens is an observability and cost-insight layer. It does not proxy model traffic, rewrite prompts, route requests, or automatically change production models.
