okovia — OkOvia Python SDK
Measure the cost and margin of every AI operation from your backends, workers, queues, and AI-infrastructure code. OkOvia prices each model call and GPU-second and attributes it to a product operation.
Server-side only — use a secret (vik_sec_…) or ingest-only
(vik_ing_…) key. Never ship this in a browser or mobile app (use the
web tag or the Swift SDK there).
Install
pip install okovia
Usage
from okovia import OkoviaClient
client = OkoviaClient(
secret_key="vik_sec_xxx",
project_id="project_123",
endpoint="https://api.okovia.com",
)
client.record_usage(
operation_id="op_checkout_7K9x",
provider="openai",
model_name="gpt-4o",
input_tokens=1200,
output_tokens=300,
cache_write_tokens=2048, # cost-category fields the pricing engine uses
reasoning_tokens=128,
stream_status="complete",
)
Time a step automatically
with client.step(operation_id="op_1", step_name="rag", provider="openai") as step:
result = call_your_llm()
step.add_metric("input_tokens", result.usage.input_tokens)
step.add_metric("output_tokens", result.usage.output_tokens)
# an unhandled exception inside the block marks the event status="error"
Correlate browser context with backend usage (FastAPI/Starlette)
from okovia import OkoviaCorrelationMiddleware, current_operation_id
app.add_middleware(OkoviaCorrelationMiddleware)
# ... then in a request handler:
client.record_usage(operation_id=current_operation_id() or "op_fallback", ...)
On-device hashing for recommendations (privacy-safe)
from okovia import hash_prompt_prefix
# Salted digest of the repeated prompt prefix — content never leaves the
# process; only the hash is sent. Feeds the "prompt caching off" rule.
client.record_usage(
operation_id="op_1",
prompt_prefix_hash=hash_prompt_prefix(prompt, salt="your-project-salt"),
...
)
Evaluate quality — only the score travels (0.4.0)
Quality evaluation runs inside your process; the model output never
leaves your app. Only the resulting score joins the pipeline, on the same
operation_id as the cost:
import okovia
from okovia.evaluators import json_valid, refusal_detected, truncated
okovia.configure(secret_key="vik_sec_...", project_id="...",
endpoint="https://api.okovia.com")
okovia.evaluate("op_1", model_output,
evaluators=[json_valid(), refusal_detected(), truncated()])
Built-in heuristic evaluators (stdlib, zero cost): json_valid,
schema_match(schema), refusal_detected, language_match(lang),
pii_leak_in_output, truncated. All score in [0, 1], higher is
better.
LLM-as-judge with your own provider key — the judge call is reported as a regular usage event, so the cost of measuring quality is measured:
from okovia.evaluators import LLMJudge, JudgeVerdict
def my_judge(output: str) -> JudgeVerdict:
response = my_provider_call(output) # your key, your process
return JudgeVerdict(score=parse_score(response),
provider="openai", model="gpt-5-mini",
input_tokens=response.usage.input_tokens,
output_tokens=response.usage.output_tokens)
okovia.evaluate("op_1", model_output,
evaluators=[LLMJudge("helpfulness_judge", my_judge)])
client.evaluate(...) works the same on an existing OkoviaClient.
Inside a request handled by OkoviaCorrelationMiddleware, pass
operation_id=None and the current operation is used.
Run under the remote policy — control plane (0.5.0)
Publish a policy in the console (fallback chains, budget caps, quality floors, routing) and let the SDK enforce it inside your process — OkOvia never proxies your calls:
import okovia
okovia.configure(secret_key="vik_sec_...", project_id="...",
endpoint="https://api.okovia.com")
result = okovia.run_with_policy(
"chat",
models={
"gpt-4o": lambda: call_openai("gpt-4o", prompt),
"gpt-4o-mini": lambda: call_openai("gpt-4o-mini", prompt),
},
)
result.value # your callable's return
result.model_used # after routing / downgrade / fallback
# Attach the decisions to your usage event:
with client.step(operation_id=op, step_name="answer") as step:
result = client.run_with_policy("chat", models={...})
step.apply_policy(result) # model_used + policy_version/fallback_from/...
Semantics: exceeded budget caps alert (proceed, marked), downgrade
(start from the cheapest chain model) or block
(OkoviaPolicyBlockedError before any call); fallback chains retry the
next model on error/timeout. Fail-open: no config, no policy, or an
unreachable endpoint mean plain execution — OkOvia being down never
blocks you. Caps are soft ceilings with bounded staleness (~5 min server
state + 300s SDK TTL).
Quality floors (0.6.0). When the console declares
policy.quality_floor.<feature>.min_score and the measured eval average
falls below it, run_with_policy can escalate: list "quality_floor" in
the feature's fallback triggers and the call starts from the chain's
first (preferred) model instead of the routed/cheaper one —
result.quality_action == "escalate". Without the trigger it only marks
the result ("alert"). Budget actions always win over quality.
Command line (okovia)
Installing the package also installs the okovia CLI — for the places
SDKs don't reach naturally: shell scripts, cron jobs, CI pipelines, GPU
batch workers.
export OKOVIA_INGEST_KEY="vik_ing_..."
export OKOVIA_PROJECT_ID="..."
export OKOVIA_ENDPOINT="https://api.okovia.com"
okovia doctor --send-test # validate credentials + connectivity end to end
okovia track --provider openai --model gpt-4o \
--input-tokens 1200 --output-tokens 340 --feature nightly_batch
okovia track --gpu-seconds 142.5 --provider runpod --model a100 \
--feature training_job # unit type is inferred
okovia costs # cost by feature, straight from the API
track infers the unit type from the flags you pass (tokens → tokens,
--gpu-seconds → GPU, --images → image generation, none → api_call)
and prints the ingestion result as JSON, so it composes with jq.
Privacy
Prompts and completions are never collected. Only usage metadata and salted hashes leave your process; sensitive fields are rejected client-side before sending.
Your own redaction list (0.6.0): fields listed under SDK → Privacy →
redact_fields in the console are stripped from raw_usage_json and eval
metadata before anything is sent — case-insensitive, at any depth, no
release needed. The SDK reads them from the same cached /v1/config the
control plane uses (one request per 5 minutes, fail-open: no published
config means no extra redaction).
Compatibility
The historical viking_metering package and VikingMeteringClient name
remain importable for existing code:
from viking_metering import VikingMeteringClient # still works
License
MIT — free while OkOvia is in beta.
Metadata
Release files for okovia 0.6.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| okovia-0.6.0.tar.gz | 44.0 kB | Without provenance | Details for okovia-0.6.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| okovia-0.6.0-py3-none-any.whl | Python 3 | none | any | Details for okovia-0.6.0-py3-none-any.whl |
Total release size: 77.8 kB
Release files / okovia-0.6.0.tar.gz
| Download URL | okovia-0.6.0.tar.gz |
|---|---|
| Size | 44.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
e3e85b7a2c3fe8094103bf2ac3efa1bf4c9d5b784c97cd4b4e5dd04882ecad77
|
|
BLAKE2b-256 checksum How to use checksums |
e6f1a4b280cd5cad0fcd873fa454c9177a26a2dd5d806fa7930175130c33b0bd
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.15
|
Release files / okovia-0.6.0-py3-none-any.whl
| Download URL | okovia-0.6.0-py3-none-any.whl |
|---|---|
| Size | 33.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
6634ff9de7d25da308251734a3f2a9bfa0fe5a9e998314dcc1fb27c795fd6a49
|
|
BLAKE2b-256 checksum How to use checksums |
1716b80a8d47d7ed497aa748d0a2de86ed7937acd4892e19514b4e24d7bc9274
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.15
|
Security for okovia 0.6.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.