Python async wrapper — live attribution without a proxy
A drop-in wrapper around the OpenAI and Anthropic Python SDKs that reports usage to Cognocient asynchronously. Zero added latency, but no pre-call enforcement — the honest tradeoff explained.
A drop-in wrapper import for the OpenAI and Anthropic Python SDKs. Swap
one import, add a key, and get live cost attribution — without changing
your base_url or routing traffic through a proxy.
Source is open — cognocient-python-wrapper on GitHub, published as cognocient on PyPI.
Supported providers: OpenAI and Anthropic only
This wrapper covers two of the seven providers Cognocient supports. If your API key is for Google Gemini, Mistral, Groq, Together AI, or Azure OpenAI, this package has no wrapper class for you — see below for what to do instead.
Every method the real SDK exposes still works unchanged. This wrapper
only intercepts chat.completions.create() (messages.create() for
Anthropic) to report usage after the fact.
Which providers does this wrapper support?
Only two: OpenAI (CognocientOpenAI) and Anthropic
(CognocientAnthropic). That's it — there is no CognocientGemini,
CognocientMistral, CognocientGroq, CognocientTogether, or
CognocientAzureOpenAI class in this package today.
This matters because the proxy supports seven
providers — OpenAI, Anthropic, Google Gemini, Mistral, Groq, Together
AI, and Azure OpenAI — through one base_url. The wrapper's coverage is
narrower because it works by wrapping each provider's Python SDK object
directly, and that has to be built one SDK at a time.
I have a Gemini, Mistral, Groq, Together AI, or Azure OpenAI key — what do I do?
Two real options, no third option that "sort of" works:
- Use the proxy instead. It's provider-agnostic — it works at the HTTP layer, not the SDK layer — so all seven providers get live attribution and pre-call budget enforcement, which this wrapper never provides for any provider anyway. This is the only path that covers your provider today.
- Use the CSV/OTel importer if you don't want any live network call to Cognocient from your runtime at all — works for any provider, since it reads logs you already have, but is historical-only (no live dashboard, no budgets).
Don't try to force it through CognocientOpenAI
Groq and Together AI expose OpenAI-compatible endpoints, so passing their
base_url into CognocientOpenAI will technically run without an error.
Don't do this: the wrapper hardcodes the reported provider field to
"openai", so your dashboard would mislabel every one of those calls as
OpenAI spend. This isn't a supported path — it just fails silently
instead of loudly, which is worse.
What does cognocient_key actually do?
This is a fair question, especially if you picked the wrapper because you don't want to connect to the proxy — doesn't passing a Cognocient key mean you're connecting to Cognocient after all?
In plain terms: no. cognocient_key is only a credential for
reporting, not a connection for your traffic. Here's the full path a
call takes:
- You call
client.chat.completions.create(...). - The wrapper forwards that call straight to OpenAI or Anthropic, using
your own real
api_key— same URL, same request, as if Cognocient didn't exist. - Once the real response comes back, the wrapper starts a separate
background task: it packages up metadata (model, tokens, cost,
latency, your attribution tags) and sends it to Cognocient's
ingestion endpoint, authenticated with
cognocient_key. - That reporting call is fire-and-forget. If it's slow, fails, or never happens, your real API call already completed and returned — nothing about step 1 or 2 depends on it.
So cognocient_key never touches your prompts, your responses, or your
request path. It only tells Cognocient's ingestion API "this usage
report belongs to this account." It's the same kind of key you'd use
with the proxy, reused here for a completely different job — proving
whose report this is, not routing anything.
If you want zero dependency on Cognocient at all
Even the reporting call is optional in the sense that it never blocks or affects your app — but if you'd rather not have your process talk to Cognocient's servers under any circumstances, the CSV/OTel importer is a fully offline alternative: no live network call to Cognocient from your runtime, ever — you export logs and upload them on your own schedule.
Security — read this before you decide
This is not more secure than the proxy
It's a different tradeoff, not a strictly better one — we're not going to tell you otherwise.
With the proxy, your real provider API key lives server-side, under Cognocient's control, in one place. With this wrapper, your key stays in your own application process and calls the provider directly — exactly as it does today without Cognocient at all. Some security teams prefer that (no third-party network hop in the request path); others are less comfortable with third-party code executing inside their process with key access. Both are reasonable positions.
What this wrapper honestly gives you over the proxy:
- Zero added request latency, in the practical sense — see the measured benchmark below. Reporting happens after your real call already returned, on a background thread, off the critical path.
- Zero risk of a Cognocient outage affecting your production call. If Cognocient's ingestion API is down, your call to OpenAI or Anthropic still completes normally.
What you give up versus the proxy: pre-call enforcement. Because Cognocient only hears about a call after it already happened, budgets configured in Cognocient cannot block or degrade a call made through this wrapper before it fires. Your dashboard will say so explicitly for any account using this path — see Budget Enforcement.
Measured latency overhead
200 warm-up calls excluded, 2,000 timed iterations per leg, both legs hitting the same in-process mock transport (no real network call to OpenAI or to Cognocient — see methodology below).
| p50 | p95 | p99 | mean | |
|---|---|---|---|---|
| Raw SDK call | 0.7675ms | 0.8537ms | 1.1672ms | 0.7807ms |
| Wrapped call | 0.7827ms | 0.8701ms | 1.1897ms | 0.7961ms |
| Added overhead | +0.0152ms | — | — | +0.0153ms |
What this number does and doesn't include
This measures only the wrapper's own interception code on your request path — timing the call, stripping cognocient_* kwargs, and queuing a report. It does not include real network latency to OpenAI/Anthropic or to Cognocient's ingestion API, because reporting runs on a background thread your request never waits on — that's the architectural claim this benchmark exists to check, not assume. Reproduce it yourself: cognocient-python-wrapper/benchmark/benchmark_wrapper_overhead.py, no real API keys required.
Reliability
Reporting is fire-and-forget on a background thread with a bounded local queue, flushed every few seconds or every 50 calls, whichever comes first. If the ingestion API is slow, down, or unreachable:
- Your real provider call is completely unaffected — it already happened before reporting was attempted.
- No exception is ever raised into your code from a reporting failure.
- No retry loop that could pile up work in your process — a failed batch is dropped and logged locally, not retried.
This is verified by an actual test that simulates an unreachable
ingestion endpoint and asserts the real call still completes normally —
cognocient-python-wrapper/tests/test_reporter_failure_isolation.py,
not just claimed in this paragraph.
Known limitation: streaming isn't reported yet
stream=True calls are passed through to the real SDK completely
unmodified — your application behaves identically — but are not
currently reported to Cognocient. Usage totals aren't available until a
stream completes, and reliably capturing them requires wrapping the
stream iterator itself, which this version doesn't do. If most of your
traffic streams, use the proxy or the
CSV/OTel importer instead for now.
Attribution fields
Same field names the proxy accepts as X-Cost-* headers, passed as
keyword arguments instead — see Attribution Headers.
| Wrapper kwarg | Proxy header |
|---|---|
cognocient_feature | X-Cost-Feature |
cognocient_department | X-Cost-Department |
cognocient_user | X-Cost-User |
cognocient_session | X-Cost-Session |
cognocient_tier | X-Cost-Tier |
cognocient_project | X-Cost-Project |
cognocient_gl_account | X-Cost-GL-Account |
cognocient_workload | X-Cost-Workload |
cognocient_outcome | X-Cost-Outcome |
cognocient_run_id | X-Cost-Run-ID |
Frequently asked questions
Related articles