Add cache-write and tool-use prompt tokens to TokenUsageDto
## Problem/Motivation
`TokenUsageDto` (`src/Dto/TokenUsageDto.php`) only models five token counts:
```php
public ?int $input = NULL,
public ?int $output = NULL,
public ?int $total = NULL,
public ?int $reasoning = NULL,
public ?int $cached = NULL,
```
Two token-usage values reported by the major providers have nowhere to live in this DTO, so
they are silently dropped before reaching logging/observability or any cost-reporting layer:
### 1. Cache **write** / cache creation tokens
The current `cached` field maps only to **cache reads**
(`prompt_tokens_details.cached_tokens` in `OpenAiBasedProviderClientBase::setChatTokenUsage()`).
There is no field for **cache writes / cache creation**. Anthropic reports this separately as
`cache_creation_input_tokens` and bills it at a *premium* (≈1.25× input for the 5-minute TTL,
≈2× for the 1-hour TTL). A request that creates a large cache entry therefore currently looks
free, which makes accurate cost attribution impossible.
### 2. Tool-use prompt tokens
Gemini reports `toolUsePromptTokenCount` — the input tokens consumed by function calling /
code execution. There is no DTO field for these, so tool-heavy requests under-report their
real input usage.
## Current mapping
`OpenAiBasedProviderClientBase::setChatTokenUsage()` populates the DTO as:
| DTO field | Source |
|-------------|--------|
| `input` | `usage.prompt_tokens` |
| `output` | `usage.completion_tokens` |
| `total` | `usage.total_tokens` |
| `reasoning` | `usage.completion_tokens_details.reasoning_tokens` |
| `cached` | `usage.prompt_tokens_details.cached_tokens` (cache **read** only) |
## Provider references
- **Anthropic (Messages `usage`):** `cache_creation_input_tokens` (with a `cache_creation`
breakdown of `ephemeral_5m_input_tokens` / `ephemeral_1h_input_tokens`); `cache_read_input_tokens`
is what currently maps to `cached`.
- **Google Gemini (`usageMetadata`):** `toolUsePromptTokenCount`.
## Proposed solution
Add two nullable fields to `TokenUsageDto`. Because every constructor argument is optional and
nullable, this is backward-compatible — providers that don't set them keep working unchanged.
Suggested additions (names open to bikeshedding):
- `cachedWrite` — cache creation / cache write tokens (Anthropic `cache_creation_input_tokens`).
Also document that the existing `cached` is specifically cache **read**.
- `toolUse` — tool/function-call prompt tokens (Gemini `toolUsePromptTokenCount`).
Open question: should the cache-write TTL split (5m vs 1h) be modeled now, or left for a
follow-up? It is provider-specific and may be better as a nested structure.
## Remaining tasks
- [ ] Agree on the field names.
- [ ] Add `cachedWrite` and `toolUse` (nullable) to `TokenUsageDto`.
- [ ] Populate them in `OpenAiBasedProviderClientBase::setChatTokenUsage()`, the streaming
iterator, and any other provider clients that build the DTO.
- [ ] Update/extend unit tests and the `ai_observability` logging/metrics subscribers so the
new counts are recorded.
issue