SuperPenguin Python SDK — AI cost management, attribution, and spend tracking
Project description
SuperPenguin Python SDK
Track AI costs automatically. Wrap your OpenAI or Anthropic client — or patch litellm — and every LLM call is captured with token counts, estimated cost, latency, and attribution metadata. No proxy required.
Installation
pip install superpenguin
Or install from source (in the sdk/python/ directory):
pip install -e .
Quick Start
1. Wrap your client (one line)
import superpenguin as sp
from openai import OpenAI
sp.init(api_key="sp_...") # your SuperPenguin API key
client = sp.wrap(OpenAI())
# Use the client exactly as normal — cost events are captured automatically
response = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": "Hello!"}],
)
print(response.choices[0].message.content)
That's it. Every create() call through the wrapped client is captured with provider, model, token counts, estimated cost (USD), and latency.
2. Works with Anthropic too
import superpenguin as sp
from anthropic import Anthropic
sp.init(api_key="sp_...")
client = sp.wrap(Anthropic())
response = client.messages.create(
model="claude-sonnet-4-20250514",
max_tokens=1024,
messages=[{"role": "user", "content": "Hello!"}],
)
3. Streaming works transparently
client = sp.wrap(OpenAI())
stream = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": "Tell me a story"}],
stream=True,
)
for chunk in stream:
if chunk.choices and chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="", flush=True)
# Cost event is submitted automatically when the stream finishes
4. LiteLLM support
If you use litellm to call 100+ LLM providers through a single interface, one call patches everything:
import superpenguin as sp
import litellm
sp.init(api_key="sp_...")
sp.patch_litellm()
# Every litellm.completion() / litellm.acompletion() is now tracked
response = litellm.completion(
model="openai/gpt-4o",
messages=[{"role": "user", "content": "Hello!"}],
)
5. Add attribution metadata
Attach metadata to attribute costs to customers, features, teams, or environments:
# Set defaults for all calls from this client
client = sp.wrap(OpenAI(), metadata={
"customer_id": "cust_acme_123",
"feature": "doc_summary",
"team": "product",
"environment": "production",
})
# Or override per-call via extra_body
response = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": "Summarize this document"}],
extra_body={
"sp_metadata": {
"customer_id": "cust_other_456",
"prompt_key": "summarize_v2",
"prompt_version": "3",
}
},
)
@sp.trace Decorator
For multi-step pipelines (RAG, agents, chains), use the @sp.trace decorator. Any wrapped LLM calls inside the function are automatically linked as children.
import superpenguin as sp
from openai import OpenAI
sp.init(api_key="sp_...")
client = sp.wrap(OpenAI())
@sp.trace
def answer_question(question: str) -> str:
docs = search_knowledge_base(question)
response = client.chat.completions.create(
model="gpt-4o",
messages=[
{"role": "system", "content": f"Context:\n{docs}"},
{"role": "user", "content": question},
],
)
return response.choices[0].message.content
result = answer_question("How do I reset my password?")
Decorator variants
@sp.trace
def my_function(): ...
@sp.trace("my-pipeline")
def my_function(): ...
@sp.trace(name="my-pipeline", tags=["production"], metadata={"customer_id": "acme"})
def my_function(): ...
Async support
Both wrap() and @sp.trace work with async clients and functions:
from openai import AsyncOpenAI
client = sp.wrap(AsyncOpenAI())
@sp.trace
async def answer_question(question: str) -> str:
response = await client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": question}],
)
return response.choices[0].message.content
Configuration
sp.init()
| Parameter | Type | Default | Description |
|---|---|---|---|
api_key |
str |
SP_API_KEY env var |
Your SuperPenguin API key |
base_url |
str |
https://api.carrotlabs.ai |
API endpoint |
flush_interval |
float |
5.0 |
Seconds between background batch flushes |
batch_size |
int |
50 |
Max events per batch POST |
Environment variables
| Variable | Description |
|---|---|
SP_API_KEY |
API key (used if not passed to init()) |
SP_BASE_URL |
API base URL override |
If SP_API_KEY is set, init() is called automatically on first use.
sp.wrap()
| Parameter | Type | Default | Description |
|---|---|---|---|
client |
OpenAI | Anthropic |
required | The LLM client to wrap |
name |
str |
None |
Override the default event name |
metadata |
dict |
None |
Default metadata for every call (customer_id, feature, team, etc.) |
tags |
list[str] |
None |
Tags added to every event |
sp.patch_litellm()
| Parameter | Type | Default | Description |
|---|---|---|---|
name |
str |
None |
Override the default event name |
metadata |
dict |
None |
Default metadata for every litellm call |
tags |
list[str] |
None |
Tags added to every event |
sp.flush()
Force-flush any pending events. Useful before process exit in short-lived scripts:
sp.flush()
An atexit handler also flushes automatically on normal interpreter shutdown.
Metadata Fields
| Field | Type | Purpose |
|---|---|---|
customer_id |
string | End-customer or account consuming the AI call |
feature |
string | Product feature name (e.g., search, support_agent) |
team |
string | Internal team owning the feature |
environment |
string | production, staging, dev, etc. |
prompt_key |
string | Identifier for the prompt template |
prompt_version |
string | Version of the prompt template |
| Any other key | string | Stored as custom tags, queryable in the dashboard |
What Gets Tracked
Each event includes:
| Field | Description |
|---|---|
provider |
"openai", "anthropic", or "litellm" |
model |
Model name used |
input_tokens |
Prompt token count |
output_tokens |
Completion token count |
cached_tokens |
Cached prompt tokens (if applicable) |
cost_usd_micros |
Estimated cost in USD micros (1 USD = 1,000,000 micros) |
latency_ms |
End-to-end call duration |
streaming |
Whether the call was streamed |
has_tools |
Whether tool calls were used |
has_vision |
Whether image inputs were included |
Never captured: Prompt content, response content, images, audio, tool arguments, or function results. The SDK only captures cost-relevant metadata.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file superpenguin-0.1.0.tar.gz.
File metadata
- Download URL: superpenguin-0.1.0.tar.gz
- Upload date:
- Size: 13.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2cda7c16e0bc1f9c3887cacfecdb411646c5c9e01c4c662b4f17be0f4822e640
|
|
| MD5 |
915ae04469a9db8b16934499bf829be1
|
|
| BLAKE2b-256 |
f6d7386b81f3043a53f87ff2a939825bb2fecc7e7d477603cd2f7a651fa867dc
|
File details
Details for the file superpenguin-0.1.0-py3-none-any.whl.
File metadata
- Download URL: superpenguin-0.1.0-py3-none-any.whl
- Upload date:
- Size: 16.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5c58ac2a95f67c30cd8e16b45406465d8e3b4e48b1e9eb7a9a05fe123a1bd39c
|
|
| MD5 |
319f75cc074afb2dfc6de164e7944db0
|
|
| BLAKE2b-256 |
0c18a6674198f2492b5700cb3bacf3d20abf2e28f16c6a8d9ee62349b4d8c812
|