Skip to content

OpenCode Vitals 0.1.5

Choose a tag to compare

@moutazideal moutazideal released this 26 Sep 15:57
· 4 commits to main since this release

Honest rates, a second reading, and a bar you can size

tok/s was sometimes wrong, and in one measured case wrong by two orders of magnitude. A step's token count includes the tokens spent writing its tool call, and those arguments stream as session.tool.input.* rather than text — they were counted in the numerator with no time in the denominator. On this machine that printed 4686 tok/s for a turn whose visible output was 80 characters. Tool-call arguments are measured as model time now, and the record carries toolArgCharacters and toolArgDeltaCount so the arithmetic can be checked. A four digit rate prints short (4.7k) so the line always fits.

Totals are merged as whole snapshots too. The plugin and the bar each took the maximum of every field separately, so a record could hold one turn's token count next to another turn's stream time — and every reader divides one by the other. Totals are ranked and replaced as a whole now, so an older snapshot can no longer walk the numbers backwards.

New in the bar

  • The average of the last ten responses, next to the session average. · N last10 is the mean of the rates of the last ten completed responses on screen. The session average is the whole session divided as one sum and barely moves once a session is long; the last-ten reading reacts to the reply you just watched. The rates live in the session totals, so they survive a plugin reload.
  • The bar is yours to size. Drag the bottom-right grip, or hold Ctrl and use the wheel; everything scales together and the size is remembered. Right-click resets it to 100%, OPENCODE_LATENCY_SCALE pins it, the range is 0.6×–2.5×, and the collapsed bar scales with the same number.
  • The bar steps aside when your attention moves. Minimized, another program focused, or another window covering OpenCode by 60% — each one fail-open, and each switchable with OPENCODE_LATENCY_HIDE_UNFOCUSED=0 or OPENCODE_LATENCY_HIDE_OCCLUDED=0.
  • New screenshots at 2× from the running program, and a real desktop capture sent in by the project's author, reading 7 turns · 66 steps · 243 tok/s · 311 last10.

Also fixed

  • Clicking the bar made it flicker. Tk's winfo_id() names the child window it draws in, while the window manager tracks the parent, and the parent is what _NET_ACTIVE_WINDOW reports the moment the bar is clicked. The manager's window is matched once by title now, and a click on the bar counts as being in the app.
  • A restart could freeze a session's totals, last-ten list included. The totals file is part of the seed now — history first, then the file, newest snapshot per session — and the merged view is published at startup instead of waiting for the next response.
  • Publishing totals erased the other projects' sessions. Several instances of this plugin share one totals file, one per project directory, and each wrote only what it knew. The on-disk sessions are merged in before writing now.
  • A reconnect inflated the denominator. A stream that stops for longer than 30 seconds and continues under the same message id restarts the span there instead of counting the silence (STREAM_GAP_LIMIT_MS).
  • A reply that arrived in one piece showed no rate at all. The rate falls back to first-to-last, then to that message's own wall time, and the record carries rateSource so the fallback is visible.
  • Two executions running at once were reported as one turn. A second session.execution.started closes the open turn first, so parallel work and subagents no longer merge into a single inflated turn.
  • Unknown event types were dropped in silence. Anything outside the known lists is counted, reported on the record as unknownEventTypes, and logged at most once every few minutes.
  • A bar that correctly stood down was counted as a crash. It exits with code 6 when another instance owns the lock, and the plugin treats that as the wanted state: no backoff, no failure line in the log.
  • The bar polled far harder than it needed to. Records are read through a stat-based cache, the poll beat went from 200ms to 500ms, the window search runs on its own slower beat with rejected window ids remembered, and the announcement write moved out of the render path.

Changed

  • log now defaults to false: one line per completed turn in somebody else's log file is noise, and the numbers are on the bar. Errors and version changes go through a new warn() path.
  • The selftest reports whether xprop and xwininfo are present, as notes.

Measured

  • 223 plugin checks and 135 bar checks, up from 166 and 66.

Upgrade

npx opencode-vitals install     # updates in place

The bar process is replaced within about five seconds of the new script landing; a restart of OpenCode is only needed for the version recorded by the plugin to read 0.1.5.