# `CMDC.TokenUsage`
[🔗](https://github.com/tuplehq/cmdc/blob/v0.4.0/lib/cmdc/token_usage.ex#L1)

公开的 token 用量 struct（v0.2 RFC B5 引入）。

CMDC 在 Provider 层把不同 LLM 厂商的 raw usage（OpenAI 风格 `prompt_tokens` /
`completion_tokens`，Anthropic 风格 `input_tokens` / `output_tokens`，
Google 风格 `prompt_token_count` / `candidates_token_count`）统一归一化为本 struct。

事件协议（v0.2 起）：

- `{:agent_end, messages, %CMDC.TokenUsage{}}` — 第三参数是 struct
- `CMDC.status/1` 返回 `:token_usage` 字段为 struct，原 `:total_tokens` Int 字段保留

## 字段约定（OpenAI 行业事实标准）

- `:prompt_tokens` — 输入 token 总数（Anthropic 的 input_tokens 也归到这里）
- `:completion_tokens` — 输出 token 总数（Anthropic 的 output_tokens 也归到这里）
- `:total_tokens` — 累计 token 总数（多数 Provider 自带；缺失时由 prompt + completion 补齐）
- `:cost_usd` — 累计美元成本（基于 token 用量与模型定价计算；Provider 未配置定价时为 `nil`）
- `:cached_tokens` — Anthropic prompt cache 命中的 token 数（Provider 不支持时为 `nil`）

## 使用

    iex> CMDC.TokenUsage.new(prompt_tokens: 100, completion_tokens: 50)
    %CMDC.TokenUsage{
      prompt_tokens: 100,
      completion_tokens: 50,
      total_tokens: 150,
      cost_usd: nil,
      cached_tokens: nil
    }

    # 从 Anthropic raw usage 归一化（total_tokens 缺失自动补齐）
    iex> u = CMDC.TokenUsage.from_raw(%{input_tokens: 80, output_tokens: 40})
    iex> {u.prompt_tokens, u.completion_tokens, u.total_tokens}
    {80, 40, 120}

# `t`

```elixir
@type t() :: %CMDC.TokenUsage{
  cached_tokens: non_neg_integer() | nil,
  completion_tokens: non_neg_integer(),
  cost_usd: float() | nil,
  prompt_tokens: non_neg_integer(),
  total_tokens: non_neg_integer()
}
```

# `add`

```elixir
@spec add(t(), t()) :: t()
```

累加另一份 token usage（用于多轮 / 多 Provider 调用聚合）。

- `prompt_tokens` / `completion_tokens` / `total_tokens` / `cached_tokens` 取加和
  （nil 视为 0）
- `cost_usd` 也取加和（双方都是数字时累加；任意一方为 nil 时取另一方的值）

## 示例

    iex> a = CMDC.TokenUsage.new(prompt_tokens: 10, completion_tokens: 5)
    iex> b = CMDC.TokenUsage.new(prompt_tokens: 20, completion_tokens: 10)
    iex> CMDC.TokenUsage.add(a, b)
    %CMDC.TokenUsage{prompt_tokens: 30, completion_tokens: 15, total_tokens: 45,
                     cost_usd: nil, cached_tokens: nil}

# `from_raw`

```elixir
@spec from_raw(map() | t()) :: t()
```

从任意 Provider raw usage map 构造（Anthropic / OpenAI / Google 兼容）。

字段映射：

- `prompt_tokens` ← `:prompt_tokens` / `:input_tokens` / `:prompt_token_count`
- `completion_tokens` ← `:completion_tokens` / `:output_tokens` / `:candidates_token_count`
- `total_tokens` ← `:total_tokens`（缺失时由 prompt + completion 补齐）
- `cached_tokens` ← `:cache_read_input_tokens` / `:cached_tokens`

支持 atom 或 string key 的混合输入。

# `from_state_token_map`

```elixir
@spec from_state_token_map(map(), float() | nil, non_neg_integer() | nil) :: t()
```

把 Agent State 内部 token map + cost_usd 转换为公开 struct。

Agent 内部为兼容性保留扩展 map（含 `:context_window` / `:current_context_tokens`,
这两个字段是上下文窗口元数据，不属于"用量"，不进入公开 struct）。

# `new`

```elixir
@spec new(map() | keyword()) :: t()
```

从 keyword / map 构造 TokenUsage struct。

缺省字段：`prompt_tokens` / `completion_tokens` / `total_tokens` 默认 0,
`cost_usd` / `cached_tokens` 默认 `nil`。

## 示例

    iex> CMDC.TokenUsage.new()
    %CMDC.TokenUsage{prompt_tokens: 0, completion_tokens: 0, total_tokens: 0,
                     cost_usd: nil, cached_tokens: nil}

    iex> CMDC.TokenUsage.new(prompt_tokens: 10, completion_tokens: 5, cost_usd: 0.0001)
    %CMDC.TokenUsage{prompt_tokens: 10, completion_tokens: 5, total_tokens: 15,
                     cost_usd: 0.0001, cached_tokens: nil}

---

*Consult [api-reference.md](api-reference.md) for complete listing*
