Usage metrics — cost and live token speed in the chat

Overview

Every chat turn reports a usage block ({ promptTokens, completionTokens }) when the upstream finishes streaming. The chat UI turns that block into a per-message cost (in USD) and a live tokens/s counter that ticks under each user turn as the assistant's tokens stream in. Pricing comes from a per-model pricing map so the user can override defaults for any model they configure; sensible defaults are bundled for the providers the AI client ships with.

Usage

What the user sees

For every assistant message in the chat, the UI renders a small status line directly below the reply:

gpt-4o-mini  •  context 243  •  output 118  •  cost $0.00012  •  37 tok/s

Per-model pricing

Pricing is an opt-in addition to the existing model record, so existing projects keep working without any change:

// <projectDir>/.mouaif.json
{
  "models": [
    {
      "id": "gpt-4o-mini",
      "provider": "openai-compatible",
      "label": "GPT-4o mini",
      "contextWindow": 128000,
      "pricing": {               // NEW (all fields optional)
        "inputPer1K":  0.00015,   // USD per 1 000 prompt tokens
        "outputPer1K": 0.00060,   // USD per 1 000 completion tokens
        "cacheReadFactor": 0.10,  // optional: prompt-cache read multiplier (default 0.10)
        "cacheWriteFactor": 1.25  // optional: prompt-cache write multiplier (default 1.25)
      }
    }
  ]
}

A chat with no pricing block falls back to the app-level default (settings.app.modelPricing[<modelId>]), which in turn falls back to a small built-in table for well-known model ids. The built-in table is best-effort and intentionally not exhaustive — the moment a model id is unknown, the cost line renders -- and the token/s line keeps working.

The app-level table is editable through the existing Settings UI so a user can lock in a price without editing JSON:

// ~/.mouaif/store.sqlite  (settings.app.modelPricing)
{
  "gpt-4o-mini":        { "inputPer1K": 0.00015, "outputPer1K": 0.00060 },
  "claude-3-5-sonnet":  { "inputPer1K": 0.00300, "outputPer1K": 0.01500 }
}

Behavior