Skip to content

Commit 3a63c16

Browse files
tombeckenhamclaude
andcommitted
docs(protocol): clarify usage/UsageTotals is a TanStack extension, not AG-UI
AG-UI's RUN_FINISHED only defines threadId/runId/result; finishReason and usage are TanStack additions that ride along via AG-UI's passthrough schemas. Rename the documented type TokenUsage → UsageTotals to match the exported type, correct fields that don't exist on the breakdowns (cacheCreation/cacheRead, accepted/rejectedPredictionTokens), and document cost/costDetails plus an OpenRouter cost example. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent d41c9f7 commit 3a63c16

1 file changed

Lines changed: 57 additions & 20 deletions

File tree

docs/protocol/chunk-definitions.md

Lines changed: 57 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -81,48 +81,61 @@ interface RunStartedEvent extends BaseAGUIEvent {
8181

8282
Emitted when a run completes successfully.
8383

84+
> **AG-UI vs TanStack AI:** AG-UI's `RUN_FINISHED` event only defines
85+
> `threadId`, `runId`, and an optional `result`. The `finishReason` and `usage`
86+
> fields below are **TanStack AI extensions** — they ride along on the event
87+
> (AG-UI event schemas are `passthrough`) but are not part of the AG-UI protocol
88+
> itself. `usage` is typed as `UsageTotals`, defined and owned by `@tanstack/ai`;
89+
> `@tanstack/ai-event-client` mirrors the same shape for wire/devtools consumers.
90+
8491
```typescript
8592
interface RunFinishedEvent extends BaseAGUIEvent {
8693
type: 'RUN_FINISHED';
8794
runId: string;
88-
finishReason: 'stop' | 'length' | 'content_filter' | 'tool_calls' | null;
89-
usage?: TokenUsage;
95+
finishReason?: 'stop' | 'length' | 'content_filter' | 'tool_calls' | null; // TanStack AI addition
96+
usage?: UsageTotals; // TanStack AI addition
9097
}
9198

92-
interface TokenUsage {
99+
// TanStack AI extension — not an AG-UI primitive.
100+
interface UsageTotals {
93101
// Core token counts (always present when usage is available)
94102
promptTokens: number;
95103
completionTokens: number;
96104
totalTokens: number;
97-
98-
// Detailed prompt token breakdown
105+
106+
// Detailed prompt token breakdown (provider-dependent)
99107
promptTokensDetails?: {
100-
cachedTokens?: number; // Tokens from prompt cache hits
101-
cacheWriteTokens?: number; // Tokens written to cache
102-
cacheCreationTokens?: number; // Anthropic cache creation tokens
103-
cacheReadTokens?: number; // Anthropic cache read tokens
108+
cachedTokens?: number; // Tokens read from cache (prompt cache hits)
109+
cacheWriteTokens?: number; // Tokens written to cache (Anthropic cache creation)
104110
audioTokens?: number; // Audio input tokens
105111
videoTokens?: number; // Video input tokens
106112
imageTokens?: number; // Image input tokens
107113
textTokens?: number; // Text input tokens
108114
};
109-
110-
// Detailed completion token breakdown
115+
116+
// Detailed completion token breakdown (provider-dependent)
111117
completionTokensDetails?: {
112-
reasoningTokens?: number; // Reasoning/thinking tokens (o1, Claude)
118+
reasoningTokens?: number; // Reasoning/thinking tokens (o1, Claude thinking)
113119
audioTokens?: number; // Audio output tokens
114120
videoTokens?: number; // Video output tokens
115121
imageTokens?: number; // Image output tokens
116122
textTokens?: number; // Text output tokens
117-
acceptedPredictionTokens?: number; // Accepted prediction tokens
118-
rejectedPredictionTokens?: number; // Rejected prediction tokens
119123
};
120-
121-
// Provider-specific details
122-
providerUsageDetails?: Record<string, unknown>;
123-
124-
// Duration (for some billing models)
124+
125+
// Duration in seconds for duration-billed models (e.g. Whisper transcription)
125126
durationSeconds?: number;
127+
128+
// Provider-specific fields not covered by the standard schema (e.g. OpenRouter
129+
// accepted/rejectedPredictionTokens, Anthropic serverToolUse)
130+
providerUsageDetails?: Record<string, unknown>;
131+
132+
// Provider-reported cost, when available (e.g. OpenRouter)
133+
cost?: number;
134+
costDetails?: {
135+
upstreamCost?: number; // Total cost the gateway paid upstream
136+
upstreamInputCost?: number; // Upstream cost for input (prompt) tokens
137+
upstreamOutputCost?: number; // Upstream cost for output (completion) tokens
138+
};
126139
}
127140
```
128141

@@ -200,11 +213,35 @@ interface TokenUsage {
200213
}
201214
```
202215

216+
**Example (OpenRouter with cost):**
217+
```json
218+
{
219+
"type": "RUN_FINISHED",
220+
"runId": "run_abc123",
221+
"model": "openai/gpt-4o",
222+
"timestamp": 1701234567892,
223+
"finishReason": "stop",
224+
"usage": {
225+
"promptTokens": 150,
226+
"completionTokens": 75,
227+
"totalTokens": 225,
228+
"cost": 0.0012,
229+
"costDetails": {
230+
"upstreamInputCost": 0.0008,
231+
"upstreamOutputCost": 0.0004
232+
}
233+
}
234+
}
235+
```
236+
203237
**Token Usage Notes:**
238+
- `usage` is a TanStack AI extension to the AG-UI `RUN_FINISHED` event; all fields beyond the three core counts are optional and provider-dependent.
204239
- `promptTokensDetails.cachedTokens` - Tokens read from cache (OpenAI/Anthropic prompt caching)
205240
- `promptTokensDetails.cacheWriteTokens` - Tokens written to cache (Anthropic prompt caching)
206241
- `completionTokensDetails.reasoningTokens` - Internal reasoning tokens (o1, Claude thinking)
207-
- `providerUsageDetails` - Provider-specific fields not in the standard schema
242+
- `durationSeconds` - Set by duration-billed models (e.g. Whisper transcription) instead of token counts
243+
- `providerUsageDetails` - Provider-specific fields not in the standard schema (e.g. OpenRouter's accepted/rejected prediction tokens, Anthropic's server tool use)
244+
- `cost` / `costDetails` - Provider-reported per-request cost, populated only by gateways that return it (e.g. OpenRouter)
208245
- For Gemini, modality-specific token counts (audio, video, image, text) are extracted from the response
209246

210247

0 commit comments

Comments
 (0)