@jack-yang/opencode-tps-meter 1.2.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +18 -11
- package/README.zh-CN.md +18 -11
- package/package.json +4 -2
- package/tui.tsx +645 -429
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Jack Yang
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -21,7 +21,7 @@ TPS 42.5 | AVG 38.2 | TTFT 0.8s ⠒⠑⠂
|
|
|
21
21
|
- **TPS** — current tokens per second (live, color-coded)
|
|
22
22
|
- **AVG** — session-wide cumulative average from completed messages (color-coded)
|
|
23
23
|
- **TTFT** — time to first token, shown immediately on first token, persists until next generation (color-coded)
|
|
24
|
-
- **Thinking stream** — while reasoning streams, a FIFO particle stream (newest dot on the left, fading right, color shifts over time) appears to the right of TTFT. Only rendered while thinking — no space is reserved when idle.
|
|
24
|
+
- **Thinking stream** — while reasoning streams, a FIFO particle stream (newest dot on the left, fading right, color shifts over time) appears to the right of TTFT. Each cell has its own color (a gradient fading to muted). Only rendered while thinking — no space is reserved when idle.
|
|
25
25
|
|
|
26
26
|
## Color Tiers
|
|
27
27
|
|
|
@@ -159,28 +159,34 @@ All options are optional — defaults are sane.
|
|
|
159
159
|
| Option | Default | Description |
|
|
160
160
|
|---|---|---|
|
|
161
161
|
| `spinner.theme` | `"tech"` | Color preset: `"tech"` (cyan→blue→purple) or `"red"` (KITT-style red). `"none"` disables the thinking stream. |
|
|
162
|
-
| `spinner.colors` | _from theme_ | Custom gradient (hex strings); overrides `theme`. |
|
|
163
|
-
| `spinner.intervalMs` | `100` | Particle stream frame interval (ms). |
|
|
164
|
-
| `spinner.cells` | `6` | Number of cells (width) of the thinking stream. |
|
|
162
|
+
| `spinner.colors` | _from theme_ | Custom gradient (hex strings `#rgb` / `#rrggbb` / `#rrggbbaa`); overrides `theme`. Invalid entries are ignored. |
|
|
163
|
+
| `spinner.intervalMs` | `100` | Particle stream frame interval (ms), clamped to 40–1000. |
|
|
164
|
+
| `spinner.cells` | `6` | Number of cells (width) of the thinking stream, clamped to 2–16. |
|
|
165
165
|
| `tiers.tps` | `{20,50,100}` | TPS/AVG thresholds (slow/normal/fast, in TPS); above `fast` is "faster". |
|
|
166
166
|
| `tiers.ttft` | `{10000,20000}` | TTFT thresholds in ms (fast/ok); above `ok` is "slow". |
|
|
167
|
+
|
|
168
|
+
Tier values must be positive and ascending; otherwise the defaults are used.
|
|
167
169
|
| `slot` | `"prompt.footer.status"` | opencode 2.x only: which TUI slot the meter renders into. |
|
|
168
170
|
|
|
169
171
|
## How It Works
|
|
170
172
|
|
|
171
173
|
### Live TPS
|
|
172
174
|
|
|
173
|
-
Tracks text
|
|
175
|
+
Tracks text, reasoning and tool-argument delta events in a rolling 5-second window (so a model writing a large file through a tool call still shows a speed). Uses wall-clock duration (`now - oldest sample`) instead of inter-arrival time sums to avoid inflation from network buffering.
|
|
174
176
|
|
|
175
|
-
Token estimation uses `ceil(byteLength / 4)` with a **calibration factor**: when a message completes, the estimated token count is compared against actual `tokens.output + tokens.reasoning` from the message metadata, and a running median ratio corrects future estimates.
|
|
177
|
+
Token estimation uses `ceil(byteLength / 4)` with a **calibration factor**: when a message completes, the estimated token count is compared against the actual `tokens.output` (+ `tokens.reasoning` when reasoning was streamed) from the message metadata, and a running median ratio corrects future estimates.
|
|
176
178
|
|
|
177
179
|
### AVG
|
|
178
180
|
|
|
179
|
-
Session-wide cumulative average from all completed messages: `sum(actual tokens) / sum(generation durations)`. Updates when a message completes. Generation duration = `last delta - first delta` per
|
|
181
|
+
Session-wide cumulative average from all completed messages: `sum(actual tokens) / sum(generation durations)`. Updates when a message completes. Generation duration = `last delta - first delta` per step, where deltas include text, reasoning and tool-call arguments (excludes tool execution time and TTFT).
|
|
182
|
+
|
|
183
|
+
To avoid inflated numbers:
|
|
184
|
+
- reasoning tokens are only counted when the reasoning was actually streamed (some models report reasoning tokens without streaming them);
|
|
185
|
+
- a step that made tool calls but whose arguments were not streamed (older opencode versions) is excluded from AVG and calibration instead of being guessed.
|
|
180
186
|
|
|
181
187
|
### TTFT
|
|
182
188
|
|
|
183
|
-
Time from
|
|
189
|
+
Time from step start (`info.time.created`) to the first output delta (text, reasoning or tool arguments). Displayed immediately when the first token arrives, and persists until the next generation starts.
|
|
184
190
|
|
|
185
191
|
## Development
|
|
186
192
|
|
|
@@ -188,10 +194,11 @@ Time from message creation (`info.time.created`) to the first text/reasoning del
|
|
|
188
194
|
git clone https://github.com/yangwudong/opencode-tps-meter.git
|
|
189
195
|
cd opencode-tps-meter
|
|
190
196
|
npm install
|
|
191
|
-
npm test
|
|
197
|
+
npm test # unit tests
|
|
198
|
+
npm run typecheck # tsc, 0 errors expected
|
|
192
199
|
```
|
|
193
200
|
|
|
194
|
-
Pure measurement
|
|
201
|
+
Pure measurement logic lives in `measure.ts` (67 unit tests). The TUI plugin (`tui.tsx`) is a standalone single file for direct deployment; it embeds an identical copy of the pure region — edit `measure.ts`, then run `npm run sync-region` (`test/sync.test.ts` fails if they drift).
|
|
195
202
|
|
|
196
203
|
## Requirements
|
|
197
204
|
|
|
@@ -199,4 +206,4 @@ Pure measurement functions (`measure.ts`) have 29 unit tests. The TUI plugin (`t
|
|
|
199
206
|
|
|
200
207
|
## License
|
|
201
208
|
|
|
202
|
-
MIT
|
|
209
|
+
[MIT](./LICENSE)
|
package/README.zh-CN.md
CHANGED
|
@@ -21,7 +21,7 @@ TPS 42.5 | AVG 38.2 | TTFT 0.8s ⠒⠑⠂
|
|
|
21
21
|
- **TPS** — 当前每秒 token 数(实时跳动,带颜色)
|
|
22
22
|
- **AVG** — 整个会话的累计平均速度(消息完成后更新,带颜色)
|
|
23
23
|
- **TTFT** — 首个 token 的等待时间,第一个 token 到达即显示,保留到下次生成(带颜色)
|
|
24
|
-
- **思考粒子条** — 推理流式输出时,TTFT 右侧出现一个 FIFO
|
|
24
|
+
- **思考粒子条** — 推理流式输出时,TTFT 右侧出现一个 FIFO 粒子流(左侧最新、向右渐暗,颜色随时间渐变)。每一格单独着色(渐变淡出到 muted)。仅在思考时渲染,空闲时不占位。
|
|
25
25
|
|
|
26
26
|
## 颜色等级
|
|
27
27
|
|
|
@@ -159,11 +159,13 @@ curl -o ~/.config/opencode/tps-meter.tsx https://raw.githubusercontent.com/yangw
|
|
|
159
159
|
| 配置项 | 默认值 | 说明 |
|
|
160
160
|
|---|---|---|
|
|
161
161
|
| `spinner.theme` | `"tech"` | 配色预设:`"tech"`(青→蓝→紫)或 `"red"`(KITT 风格红)。`"none"` 关闭思考粒子流。 |
|
|
162
|
-
| `spinner.colors` | _随 theme_ |
|
|
163
|
-
| `spinner.intervalMs` | `100` |
|
|
164
|
-
| `spinner.cells` | `6` |
|
|
162
|
+
| `spinner.colors` | _随 theme_ | 自定义渐变(十六进制字符串 `#rgb` / `#rrggbb` / `#rrggbbaa`);覆盖 theme。无效项会被忽略。 |
|
|
163
|
+
| `spinner.intervalMs` | `100` | 粒子流帧间隔(毫秒),限制在 40–1000。 |
|
|
164
|
+
| `spinner.cells` | `6` | 粒子流格数(宽度),限制在 2–16。 |
|
|
165
165
|
| `tiers.tps` | `{20,50,100}` | TPS/AVG 阈值(慢/正常/快,单位 TPS);超过 fast 为"很快"。 |
|
|
166
166
|
| `tiers.ttft` | `{10000,20000}` | TTFT 阈值(毫秒,快/正常);超过 ok 为"慢"。 |
|
|
167
|
+
|
|
168
|
+
阈值必须为正数且递增,否则使用默认值。
|
|
167
169
|
| `slot` | `"prompt.footer.status"` | 仅 opencode 2.x:仪表渲染到的 TUI slot。 |
|
|
168
170
|
|
|
169
171
|
> 一条命令安装(`opencode plugin ...`)使用默认值;如需自定义,改用上面的元组/对象形式。
|
|
@@ -172,17 +174,21 @@ curl -o ~/.config/opencode/tps-meter.tsx https://raw.githubusercontent.com/yangw
|
|
|
172
174
|
|
|
173
175
|
### 实时 TPS
|
|
174
176
|
|
|
175
|
-
在 5
|
|
177
|
+
在 5 秒滚动窗口内追踪文本、推理和工具参数的 delta 事件(模型通过工具调用写大文件时也有速度显示)。使用壁钟时长(`当前时间 - 最早样本时间`)而非间隔时间累加,避免网络批量传输导致的 TPS 虚高。
|
|
176
178
|
|
|
177
|
-
Token 估算使用 `ceil(字节数 / 4)`,并带有**校准因子**:消息完成时,将估算的 token 数与实际的 `tokens.output
|
|
179
|
+
Token 估算使用 `ceil(字节数 / 4)`,并带有**校准因子**:消息完成时,将估算的 token 数与实际的 `tokens.output`(推理确实流式输出时再加上 `tokens.reasoning`)对比,用中位数比率自动修正后续估算。
|
|
178
180
|
|
|
179
181
|
### AVG
|
|
180
182
|
|
|
181
|
-
所有已完成消息的会话级累计平均值:`总实际 token 数 / 总生成时长`。消息完成时更新。生成时长 =
|
|
183
|
+
所有已完成消息的会话级累计平均值:`总实际 token 数 / 总生成时长`。消息完成时更新。生成时长 = 每个 step 的 `最后 delta - 首个 delta`,delta 包括文本、推理和工具调用参数(不含工具执行时间和 TTFT)。
|
|
184
|
+
|
|
185
|
+
为避免数值虚高:
|
|
186
|
+
- 只有推理内容确实流式输出时才计入 reasoning token(有些模型只上报 reasoning token 而不流式输出推理);
|
|
187
|
+
- 发起了工具调用、但工具参数没有流式输出的 step(旧版 opencode)直接不计入 AVG 和校准,而不是去猜。
|
|
182
188
|
|
|
183
189
|
### TTFT
|
|
184
190
|
|
|
185
|
-
|
|
191
|
+
从 step 开始(`info.time.created`)到第一个输出 delta(文本、推理或工具参数)的时间。第一个 token 到达时立即显示,保留到下次生成开始。
|
|
186
192
|
|
|
187
193
|
## 开发
|
|
188
194
|
|
|
@@ -190,10 +196,11 @@ Token 估算使用 `ceil(字节数 / 4)`,并带有**校准因子**:消息完
|
|
|
190
196
|
git clone https://github.com/yangwudong/opencode-tps-meter.git
|
|
191
197
|
cd opencode-tps-meter
|
|
192
198
|
npm install
|
|
193
|
-
npm test
|
|
199
|
+
npm test # 单元测试
|
|
200
|
+
npm run typecheck # tsc,应为 0 错误
|
|
194
201
|
```
|
|
195
202
|
|
|
196
|
-
|
|
203
|
+
纯计算逻辑在 `measure.ts`(67 个单元测试)。TUI 插件(`tui.tsx`)是独立的单文件,可直接部署;它内嵌了一份完全相同的纯计算区——修改 `measure.ts` 后运行 `npm run sync-region`(两份不一致时 `test/sync.test.ts` 会失败)。
|
|
197
204
|
|
|
198
205
|
## 环境要求
|
|
199
206
|
|
|
@@ -201,4 +208,4 @@ npm test
|
|
|
201
208
|
|
|
202
209
|
## 许可证
|
|
203
210
|
|
|
204
|
-
MIT
|
|
211
|
+
[MIT](./LICENSE)
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package.json",
|
|
3
3
|
"name": "@jack-yang/opencode-tps-meter",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.3.0",
|
|
5
5
|
"description": "Live TPS/AVG/TTFT meter plugin for OpenCode TUI with color-coded speed tiers",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"exports": {
|
|
@@ -27,7 +27,9 @@
|
|
|
27
27
|
},
|
|
28
28
|
"scripts": {
|
|
29
29
|
"test": "vitest run",
|
|
30
|
-
"test:watch": "vitest"
|
|
30
|
+
"test:watch": "vitest",
|
|
31
|
+
"typecheck": "tsc --noEmit --jsx react-jsx --jsxImportSource @opentui/solid --module esnext --target esnext --moduleResolution bundler --skipLibCheck tui.tsx measure.ts",
|
|
32
|
+
"sync-region": "node scripts/sync-region.mjs"
|
|
31
33
|
},
|
|
32
34
|
"files": [
|
|
33
35
|
"tui.tsx",
|