You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Expose time-to-first-token in AgentUsage so plugins can compute a real generation speed
#6850
Plugins that report a token generation speed cannot compute one correctly, because AgentUsage has no time-to-first-token. Without TTFT the only denominator available is the turn's whole elapsed span, which includes the prefill over the prompt, the model's thinking, and provider latency. Dividing output tokens by that span produces a figure that is not a speed at all: in a real Codex session on this machine a turn was reported as 43 tok/s, while the gateway serving that same model reports roughly 200 tok/s for the same work. The figure is off by ~4-5x, and it gets worse the longer the context and the harder the model thinks — i.e. exactly where a user would most want to see it.
This is not a request to build a speed UI in Paseo. It is a request for the one field that makes a correct speed computable by a plugin, in the same spirit as the existing contextWindowUsedTokens.
What the data would be
Add an optional time-to-first-token to the usage contract, per model call (or per turn, for providers that report a turn aggregate):
exportinterfaceAgentUsage{inputTokens?: number;cachedInputTokens?: number;outputTokens?: number;totalCostUsd?: number;contextWindowMaxTokens?: number;contextWindowUsedTokens?: number;// proposed/** Milliseconds from the request being sent to the first content token. */timeToFirstTokenMs?: number;/** Milliseconds from request sent to the last content token. */durationMs?: number;}
A speed then follows from outputTokens / (durationMs - timeToFirstTokenMs), which is what a gateway computes. Both fields are cheap for Paseo to produce: they are wall-clock timings around a stream the daemon is already reading.
Evidence that the source data exists
Codex already records both numbers in its own session file.~/.codex/sessions/**/rollout-*.jsonl carries time_to_first_token_ms and duration_ms per turn. Sampled from this machine:
The Codex app-server therefore emits this, and Paseo's Codex adapter is in the position to read it (and may already read the session file for other purposes — if it does not, timing the stream it consumes gives the same numbers).
A gateway doing this today:magpie sits in the HTTP stream and computes decode speed as Millis - TTFT (internal/usage/usage.go), with sanity gates on the window. It is a good reference for the arithmetic and for how brittle the naive version is.
Current workaround and why it is not enough
The community plugin TokenLedger now subtracts tool-call wait from the denominator, pairing each tool call's running and terminal events and taking the union of the intervals. That is correct but tiny: on a captured long turn, tool time was 6.8% of wall clock (31.2s of 455.6s). The other 93% is prefill, thinking and provider wait, none of which a plugin can separate.
Thinking time specifically cannot be recovered from the event stream: reasoning items arrive as a burst at the end of a thought — one capture showed 24 of them over 1.6s at 60-70ms intervals after several seconds of silence — so their timestamps mark when thinking stopped, not how long it ran.
Scope note
For providers that report a whole-turn aggregate rather than per-request usage (Claude), a turn-level TTFT is enough for a usable figure; for providers reporting per-request usage (Codex), per-request timings are better because a long turn may contain many calls. Either shape — or both, as optional fields — unblocks correct speed reporting for every usage-oriented plugin, not only TokenLedger.
Happy to test against Codex and Claude sessions on 0.11.2 if a branch appears.
plugin-apiPaseo plugin API capabilities for plugin authors
1 participant
Heading
Bold
Italic
Quote
Code
Link
Numbered list
Unordered list
Task list
Attach files
Mention
Reference
Menu
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
What problem does this solve?
Plugins that report a token generation speed cannot compute one correctly, because
AgentUsagehas no time-to-first-token. Without TTFT the only denominator available is the turn's whole elapsed span, which includes the prefill over the prompt, the model's thinking, and provider latency. Dividing output tokens by that span produces a figure that is not a speed at all: in a real Codex session on this machine a turn was reported as 43 tok/s, while the gateway serving that same model reports roughly 200 tok/s for the same work. The figure is off by ~4-5x, and it gets worse the longer the context and the harder the model thinks — i.e. exactly where a user would most want to see it.This is not a request to build a speed UI in Paseo. It is a request for the one field that makes a correct speed computable by a plugin, in the same spirit as the existing
contextWindowUsedTokens.What the data would be
Add an optional time-to-first-token to the usage contract, per model call (or per turn, for providers that report a turn aggregate):
A speed then follows from
outputTokens / (durationMs - timeToFirstTokenMs), which is what a gateway computes. Both fields are cheap for Paseo to produce: they are wall-clock timings around a stream the daemon is already reading.Evidence that the source data exists
Codex already records both numbers in its own session file.
~/.codex/sessions/**/rollout-*.jsonlcarriestime_to_first_token_msandduration_msper turn. Sampled from this machine:The Codex app-server therefore emits this, and Paseo's Codex adapter is in the position to read it (and may already read the session file for other purposes — if it does not, timing the stream it consumes gives the same numbers).
A gateway doing this today: magpie sits in the HTTP stream and computes decode speed as
Millis - TTFT(internal/usage/usage.go), with sanity gates on the window. It is a good reference for the arithmetic and for how brittle the naive version is.Current workaround and why it is not enough
The community plugin TokenLedger now subtracts tool-call wait from the denominator, pairing each tool call's
runningand terminal events and taking the union of the intervals. That is correct but tiny: on a captured long turn, tool time was 6.8% of wall clock (31.2s of 455.6s). The other 93% is prefill, thinking and provider wait, none of which a plugin can separate.Thinking time specifically cannot be recovered from the event stream:
reasoningitems arrive as a burst at the end of a thought — one capture showed 24 of them over 1.6s at 60-70ms intervals after several seconds of silence — so their timestamps mark when thinking stopped, not how long it ran.Scope note
For providers that report a whole-turn aggregate rather than per-request usage (Claude), a turn-level TTFT is enough for a usable figure; for providers reporting per-request usage (Codex), per-request timings are better because a long turn may contain many calls. Either shape — or both, as optional fields — unblocks correct speed reporting for every usage-oriented plugin, not only TokenLedger.
Happy to test against Codex and Claude sessions on 0.11.2 if a branch appears.
All reactions