Token Costs
Rhesis prices a trace by multiplying the tokens each LLM call reported by the published per-token rate for that model, in USD.
Pricing runs as part of enrichment, which is dispatched asynchronously after a trace is ingested. Tokens therefore appear on a trace immediately while cost appears a moment later, and a trace opened the instant it arrives shows tokens with no cost yet.
Where the rates come from
Rhesis does not keep its own price list. Rates come from LiteLLM’s model database , which ships with the backend and covers the commercial providers and their published per-token prices for input and output separately.
A model that database does not know gets no cost recorded at all. Its tokens are still counted, and the trace reads as having no cost data rather than as a free run. That happens for a self-hosted or private deployment, and for a model newer than the LiteLLM version the backend was built against.
What gets priced
Only spans whose ai.operation.type attribute is llm.invoke are priced. Two kinds of span
carry token counts but are deliberately left out:
- Agent-run spans. Frameworks such as Pydantic AI report aggregated usage on the agent-run span and per-call usage on each child model call. Counting both would roughly double the trace.
- Embedding spans. They carry
ai.llm.tokens.*attributes but their operation type isembedding.create. Pricing them would put the token total and the cost total on different footings.
A trace with no llm.invoke spans has no cost at all, not a cost of zero. Neither has a span that
reported no tokens: there is nothing to multiply the rate by, and a call that used nothing is
almost always one whose reply Rhesis could not read rather than one that was free.
When a figure is missing
Rhesis distinguishes “not known” from “nothing spent”. A number it does not have is left blank rather than shown as zero, so an empty cost never reads as a free run. The cost card says No cost data for that case, and a trace with no cost shows a dash in the list rather than a figure.
| What you see | What it means |
|---|---|
| No cost data, tokens present | No model in the run could be priced |
| No cost data, no tokens either | The calls reported no tokens, so there was nothing to price |
| Working out what this cost, tokens present | Enrichment has traces of this run left to price |
| A cost of zero | The run was priced and came to nothing, for example on a free tier |
| Cost present, no input/output split | The trace was priced before Rhesis recorded the two halves separately |
Provider shown as unknown | The span reported no provider and its model name could not be placed |
A span that cannot be priced still contributes its tokens. Dropping it would make a trace that mixes priced and unpriced models undercount what it actually used.
Cached prompts
Providers that cache prompts bill those tokens at their own rates: writing a cache costs more than
an ordinary input token, reading one costs far less. Rhesis records the two counts separately, as
ai.llm.tokens.cache_write and ai.llm.tokens.cache_read, and prices each at its own rate.
ai.llm.tokens.input is the uncached part alone, which is why a trace’s total is the input plus the
output plus the cached tokens. A call that read 4,000 tokens from cache beside 50 fresh ones
therefore reports 4,070 tokens and a cost covering all of them.
Traces recorded before Rhesis kept these counts report no cached tokens and price exactly as they did before, since there is nothing to charge them for.
Providers
The provider is read from the ai.model.provider span attribute where the span carries one. An
integration sets it when it can place the call: from the framework’s own report, from the module
or class that made it, or from the model name. Where it cannot, it sets nothing rather than
guessing, and Rhesis derives the provider from the model name instead. That fallback is also what
covers raw OTLP and any framework Rhesis does not translate. Where neither works, the provider is
recorded as unknown.
Provider names are normalised so one provider appears once. LiteLLM names providers by how it routes
to them, which splits some into two: a bare gemini-2.0-flash is vertex_ai to LiteLLM while the
Google ADK integration reports gemini for the same call. Rhesis folds those onto a single name.
Currencies
USD is the stored figure. Costs can be shown in USD, EUR, GBP or CHF, converted from the stored figure at the current rate rather than read from a second stored one, so every figure on a screen is on the same basis.
Rates come from Frankfurter , which republishes European Central Bank reference rates. The ECB sets those once per working day, so the rates are daily rather than real-time, and Rhesis caches them for a day. Hovering a cost shows the same figure in the other currencies and the day the rates are from.
Pick the currency in two places. An organization sets the default under Settings → Preferences, which everyone sees unless they choose otherwise. An individual overrides it under their own Settings → Preferences, or chooses to follow the organization.
Set USD_TO_EUR_RATE to pin a fallback rate for an instance with no outbound network access. It
covers EUR only, which is all it has ever covered — with no rates available, the other currencies
are not offered and costs show as stored rather than being converted at a guess.
Accuracy
Two things to know when reconciling a Rhesis figure against a provider invoice.
Per-span costs are rounded to six decimal places before being summed, so input cost plus output cost can differ from the total by a fraction of a cent on a trace with many spans.
Rhesis prices what the instrumented call reported. Discounts, committed-use pricing and batch rates are not applied, so a figure here is list price for the tokens observed.