Tokens is the default and is carried by the token fields on ModelUsage. The other
kinds are continuous measures — what a model bills for when tokens are not the unit of work —
and are carried by ModelUsage.inputUnits / ModelUsage.outputUnits.
Always the BASE measure, never the billing measure: audio billed per hour is still counted in
Seconds, and the price unit type driver does the conversion. That keeps one recorded quantity
valid across vendors who bill the same model per minute and per hour.
This union must stay a SUPERSET of the AIUsageType catalog. Those rows are the source:
MJAIPromptRunEntityServer resolves a run's UsageTypeID to its Name and hands the string
straight to this type. Adding a usage-type row whose name is absent here means every run
recorded in it becomes unpriceable at runtime — a data change breaking a type, with no compile
error to warn you. MODEL_USAGE_UNIT_KINDS below exists so a test can assert the two agree;
Characters is present for exactly that reason, ahead of any driver for it.
A kind being listed here does NOT mean runs recorded in it can be priced. Pricing is driven by
MJ: AI Model Price Unit Types drivers, and both AIEngineBase.CalculateModelCost and
MJAIPromptRunEntityServer deliberately REFUSE to price a run whose kind no driver claims,
rather than produce a plausible wrong number. Characters has no driver yet — per-character TTS
billing is real and will arrive — so such a run is left uncosted with a logged reason, which is
the intended safe behaviour rather than an oversight.
The base measure a model's usage is counted in.
Tokensis the default and is carried by the token fields on ModelUsage. The other kinds are continuous measures — what a model bills for when tokens are not the unit of work — and are carried by ModelUsage.inputUnits / ModelUsage.outputUnits.Always the BASE measure, never the billing measure: audio billed per hour is still counted in
Seconds, and the price unit type driver does the conversion. That keeps one recorded quantity valid across vendors who bill the same model per minute and per hour.This union must stay a SUPERSET of the
AIUsageTypecatalog. Those rows are the source:MJAIPromptRunEntityServerresolves a run'sUsageTypeIDto itsNameand hands the string straight to this type. Adding a usage-type row whose name is absent here means every run recorded in it becomes unpriceable at runtime — a data change breaking a type, with no compile error to warn you.MODEL_USAGE_UNIT_KINDSbelow exists so a test can assert the two agree;Charactersis present for exactly that reason, ahead of any driver for it.A kind being listed here does NOT mean runs recorded in it can be priced. Pricing is driven by
MJ: AI Model Price Unit Typesdrivers, and bothAIEngineBase.CalculateModelCostandMJAIPromptRunEntityServerdeliberately REFUSE to price a run whose kind no driver claims, rather than produce a plausible wrong number.Charactershas no driver yet — per-character TTS billing is real and will arrive — so such a run is left uncosted with a logged reason, which is the intended safe behaviour rather than an oversight.