Skip to content

Releases: ChiR24/opencode-tps-meter

v0.4.1 — Accurate TPS, subagent throughput, cache hit rate, theme colors

Choose a tag to compare

@ChiR24 ChiR24 released this 11 Oct 09:25

The throughput figures are now measured correctly, and three community features
land alongside. Tested on OpenCode v1 and v2. Install with
opencode-tps-meter@latest.

Accurate throughput

  • No more five-digit spikes. Hosts batch output before publishing it (v2
    flushes every ~100ms), and the first batch of a stream was divided by the few
    milliseconds before the meter's first update, so readings like 10364 appeared,
    most visibly as a subagent's frozen average. Each chunk is now rated over the
    interval it was actually generated in, and the opening chunk counts toward the
    total but never toward a rate.
  • The live rate is right from the start. It used to begin at a fixed 100 TPS
    and climb toward the real figure over several seconds on fast models. It is now
    exact from the second chunk (about 100ms in) at any speed, with no smoothing lag.
  • Settled averages describe what streamed. A step's average is its streamed
    tokens over the time they streamed, corrected by the provider's count only when
    the two agree within 2x. Provider totals that include output the host never
    streamed, such as hidden reasoning, no longer inflate the rate.
  • Tool-call arguments count as output (v2). The text a model writes for a tool
    call (a file write, an edit) is now counted, so a step that only calls a tool has
    a real reading instead of none.
  • Calibration persists and is weighted by size (v2). The live estimate's
    per-model correction is saved, so new sessions start calibrated, and small steps
    no longer swing it. Steps whose reasoning count the provider leaves ambiguous are
    left out.
  • A stalled stream shows its rate falling instead of holding its last value.
  • One clock per measurement. v1 no longer divides by server completion time
    minus a local first-token time.
  • The v1 toast keeps its main line on the primary session (a subagent's chunk
    used to relabel the subagent's rate as the main one) and no longer drops an
    update that lands inside its throttle window.
  • Dashboard. gen is replaced by tools, the time a turn spent running tools,
    since tool time is never inside a step's rate window. The per-model ledger starts
    fresh, as its old best/mean figures were recorded with the spiking formula.
  • Same-named subagents in the footer get a short id suffix, e.g. explore(9B5c),
    and a step that ends on an error now settles the reading and still counts its
    usage.

Added

  • Multi-session footer (#8, @ondrejch). While subagents run, the footer
    switches to an aggregate line, e.g. TPS Σ 318 | main 63 | explore 91 | +2.
    Σ sums every session generating right now, and each agent is labeled by name.
    Columns keep their spawn order, so they don't swap places. A subagent stays
    visible through long tool calls and drops off about 4s after it finishes.
    Works on both hosts: v1 resolves the session tree from session.created /
    session.updated and api.state.session, v2 from ctx.data.session.
  • Prompt cache hit rate (#9, @Anigx). The footer shows
    cache N% · session cache N%: the cached share of the prompt for the last
    step and for the whole session, computed as
    cache.read / (input + cache.read + cache.write). It also appears in the v2
    dashboard and the v1 final-stats toast. The figures appear once a session's
    first step has finished. Toggle with showCacheHit (default true) or
    TPS_METER_SHOW_CACHE_HIT.

Fixed

  • Theme colors on current v2 hosts (#10, @dragonish). v2 renamed its theme
    tokens to text.base / text.muted / feedback.<kind>.base. The meter now
    resolves those names, falling back to the older ones, instead of rendering in
    the host's default color. The theme is also read live, so a theme switch
    recolors the meter without restarting the TUI.
  • Cache figures after a tool-call-only step. A step that ends in a tool call
    without streaming any text now updates the footer's cache figures on both
    hosts, instead of leaving the previous step's numbers on screen.

Notes

  • New config option: showCacheHit (default true), env
    TPS_METER_SHOW_CACHE_HIT. No other config changes.
  • Thanks to @ondrejch, @Anigx and @dragonish for the contributions.

v0.4.0 - OpenCode v2 support (stable)

Choose a tag to compare

@ChiR24 ChiR24 released this 14 Sep 06:51

v0.4.0 — OpenCode v2 support (stable)

Promotes v0.4.0-beta.1 to stable with loader fixes verified end to end against
OpenCode 2.0.2: the server reports
"features":{"server":true,"tui":true},"state":{"status":"active"} for the
plugin, and the meter renders in the TUI prompt footer. Install with
opencode-tps-meter@latest. Everything in the beta.1 notes below carries over.

🐞 Fixed since beta.1

  • Removed the tui: true flag from the server plugin definition. The loader
    treats any tui key as a legacy handler and throws
    Plugin <spec> has invalid tui export on a non-function, aborting the whole
    plugin load with no meter.
  • ./server resolves to the dual-host dist/index.mjs again ({ id, server, setup }), the only shape valid on both loaders. The v2-only
    dist/v2/server.mjs ({ id, setup }) fails the v1 server() requirement.
    The /v2 exports remain for programmatic import only.
  • Local file:// installs must target <package>/dist, not the repo root.
    The 2.0.2 resolver handles local directories by file path (<dir>/server,
    <dir>/index, <dir>/tui) and ignores package.json#exports there, so the
    repo root (no root index.*) is silently skipped. dist/ contains both
    index.mjs (server) and tui.mjs (TUI).
  • A build-invariants regression test now locks both entrypoints against both
    loaders, including a direct guard on dist/v2/server.mjs.

📝 Notes

  • OpenCode 2.x ships its own per-message tok/s readout next to each assistant
    reply. To show only this plugin's meter, set "tps": false under session in
    cli.json. To keep the built-in readout instead, run /tps hidden.
  • Local installs should register file:///<path>/opencode-tps-meter/dist in
    opencode.json (plugin), cli.json (plugins), and tui.json (plugin).

v0.4.0-beta.1 — OpenCode v2 support (beta)

Choose a tag to compare

@ChiR24 ChiR24 released this 20 Aug 13:03

Prerelease. This targets opencode2, which is itself beta and whose plugin API is documented as subject to change before 2.0 is stable. Published under the beta dist-tag — latest stays on 0.3.1.

npm install opencode-tps-meter@beta

OpenCode v2 support

One package now serves both generations. v1 reads server/tui, v2 reads setup, and v1 behaviour is unchanged.

v2 deleted the entire message.* event family the meter was built on, so this is a port rather than a version bump:

v1 v2
message.part.delta (field text) session.text.delta
message.part.updated (reasoning) session.reasoning.delta
message.updated (completed) session.step.ended
message.updated (info.tokens) session.usage.updated
session.idle unchanged

New on v2

Measurements v1 could not make, because its events carried no timestamps and StepStartPart carried neither model nor agent:

  • Calibrated live rate — each step compares streamed tokens against the provider's count and learns a per-model correction
  • Generation vs end-to-end TPS — tool execution subtracted, so a turn that waited on a shell command still reports the model's real rate
  • Time to first token, measured on the host clock
  • Hidden overhead — the auto-title and compaction tokens no step reports
  • Per-subagent breakdown in the sidebar, using the real session tree
  • Durable ledger and /tps dashboard, persisted and shared across windows

Performance

Delta counting re-read the whole accumulated response on every chunk — O(n²) per response.

word heuristic before after
186k chars (v2 path) 10,223 ms 12.2 ms
62k chars (v1 path) 1,571 ms, +11.7 MB 10.4 ms

Live updates were also being dropped by a clock mismatch in the publish throttle: 8 updates at p50 184 ms over 120 deltas became 120 updates at p50 15.3 ms.

Both fixes benefit v1 as well.

Known limitations

  • Registering only in opencode.json loads the server half but not the TUI meter. Point ~/.config/opencode/cli.json at the built file for now:
    { "plugins": ["file:///abs/path/to/opencode-tps-meter/dist/tui.mjs"] }
  • The footer meter is confirmed working on opencode2 beta. The dashboard, sidebar panel and calibration are covered by tests but have not been exercised in a live TUI.

Feedback welcome — especially from anyone already running opencode2.

v0.3.1

Choose a tag to compare

@ChiR24 ChiR24 released this 02 Jun 04:59

Changes

  • Keeps the persistent TUI TPS meter visible when assistant responses transition into tool calls.
  • Keeps the latest TUI TPS status visible after idle/non-streaming phases.
  • Adds configurable initial display latency with initialDisplayDelayMs / TPS_METER_INITIAL_DISPLAY_DELAY_MS and a 10ms default.
  • Improves live stream token counting and fallback delta/full-part deduplication.

v0.3.0

Choose a tag to compare

@ChiR24 ChiR24 released this 31 May 17:49

Highlights

  • Add persistent OpenCode TUI TPS meter via the opencode-tps-meter/tui entrypoint.
  • Disable legacy toast popups by default; opt back in with toastFallback or TPS_METER_TOAST_FALLBACK=true.
  • Add per-session final TPS persistence, delta/full-part dedupe, lifecycle cleanup, package export, docs, and test coverage.

v0.2.1

Choose a tag to compare

@ChiR24 ChiR24 released this 20 Apr 11:24

What's Changed

message.part.delta event support

The event handler now processes message.part.delta events alongside message.part.updated. This new event type carries only { sessionID, messageID, partID, field, delta } without a full Part object. The handleMessagePartUpdated function was extracted from the plugin closure and updated with a two-path dispatch: if a Part object is present, it uses the existing accumulated-text-delta logic; if only delta + sessionID + messageID are present, it uses the delta string directly. The event switch now matches both "message.part.updated" and "message.part.delta".

MessageEvent type expanded

The MessageEvent.type union in types.ts now includes "message.part.delta". The MessageEvent.properties shape gained three optional fields: messageID, partID, and field — used by the delta-only event path.

Background agent detection reverted to cross-session only

getAllActiveAgentsGlobally no longer includes same-session agents with messageAgentCache entries. The isSameSessionAgent check was removed — only trackers where sessionId !== primarySessionId are identified as background agents. isPrimarySessionActive no longer skips trackers with cached agent names; any tracker with recent activity in the primary session counts as primary activity.

Primary session assignment simplified

The message.part.updated handler no longer checks messageAgentCache before setting primarySessionId. The first session to receive any assistant token chunk becomes the primary session, unconditionally.

Multi-agent tests aligned with cross-session design

Tests were using same-session agents, but the code only detects background agents across sessions. Tests 1, 2, and 4 now use separate session IDs per agent and send primary part.updated tokens first to establish primarySessionId. Test 3 (agents-only) updated: the original code always shows the primary TPS line when the primary session has tokens, so the test now verifies agent labels appear alongside the primary line rather than expecting no primary line.

Version bump

package.json version updated from 0.2.0 to 0.2.1.

Full Changelog: v0.2.0...v0.2.1

v0.2.0: Realistic TPS and Better Agent IDs

Choose a tag to compare

@ChiR24 ChiR24 released this 10 Feb 12:26

Improvements

Fixed

  • Inflated TPS values — Changed denominator from to . This prevents 300+ TPS spikes when tokens arrive in bursts by accounting for idle time that naturally lowers the rate.
  • Identical agent labels — All agents showed because OpenCode message IDs share the prefix. Now strips this prefix and shows 6 differentiating characters.

Changed

  • Faster timing constants for more responsive feel:
    • : 250ms → 150ms (40% faster initial display)
    • : 500ms → 250ms (more responsive smoothing)
    • : 150ms → 80ms (nearly 2x faster UI updates)
    • : 0.1s → 0.3s (stable baseline)
  • Reduced toast throttling — multiplier: 3x → 2x

Commits

  • fix: correct TPS calculation to use elapsed time from oldest entry
  • feat: improve TPS responsiveness with faster timing constants
  • fix: improve agent ID display and reduce UI throttling
  • docs: update README timing and bump version to 0.2.0

0.1.9

Choose a tag to compare

@ChiR24 ChiR24 released this 08 Feb 12:52

Full Changelog: v0.1.8...0.1.9

v0.1.8 - Agent Detection Improvements

Choose a tag to compare

@ChiR24 ChiR24 released this 08 Feb 09:36

Improvements

  • Improved agent name detection from multiple sources
  • Better handling of missing agent metadata
  • Added debug logging for troubleshooting

Bug Fixes

  • Fixed buildAgentLabel to handle missing type gracefully
  • Improved getAllActiveAgentsGlobally to get agent name from cache when metadata is missing

v0.1.7 - Bug Fixes

Choose a tag to compare

@ChiR24 ChiR24 released this 07 Feb 17:32

Bug Fixes

  • Agent name caching fixed - Previously the cache was never populated because info.agent is an AgentIdentity object (not a string). Now correctly extracts name from: agent.name > agent.type > agentType > agent.id
  • Color coding in agent-only mode - Previously showed "slow" (red) because TPS was 0. Now uses max agent TPS for color determination
  • formatAgentLine respects config - Now properly uses showInstant, showAverage, showTotalTokens settings instead of always showing all

Files Changed

  • src/index.ts - Fixed agent name extraction from AgentIdentity object
  • src/ui.ts - Fixed color coding logic and formatAgentLine config respect