omp packages

@jack-yang/pi-tps-meter1.0.0

Live TPS / AVG / TTFT meter for the pi coding agent, calibrated against authoritative token counts (port of opencode-tps-meter)

GitHub Actions Published 9 days ago MIT ~1.1K downloads/mo

Untested on omp

This is a pi package. No one has reported whether it works on omp yet. If you try it, add your result below.

Did it work for you?

Result

One report per person. A new report replaces your old one.

Reports 0

No reports yet.

Readme

pi-tps-meter

npm version license CI pi

为 pi coding agent 实时显示 token 生成速度的扩展:TPS(当前速度)、AVG(会话均值)、TTFT(首 token 延迟),并用模型返回的权威 token 数自动校准,中文内容下读数也可信。

移植自 opencode-tps-meter:测量核心(5 秒滑动窗口、权威 token 校准、AVG 口径)与分档配色和原版一致,只替换了宿主事件层和渲染层。

显示效果

⠔⠀⠈⠀⠤⠔ TPS 42.5 | AVG 38.2 | TTFT 0.8s

默认显示在 footer 的目录那一行右端(/tps footer),和下一行的模型名右对齐,不额外占行;其他扩展的 footer 状态(比如 pi-lens 的 LSP Inactive)也挤不动它。下图是模型思考时的样子,读数左边是思考粒子流:

footer 目录行右端:思考中,粒子流 + TPS 38.2 / AVG 62.2 / TTFT 1.9s

  • TPS:流式输出时的实时速度,基于 5 秒滑动窗口,约 10Hz 刷新;超过 1.5 秒没有新 token 时显示 --。
  • AVG:会话级累计平均。所有已完成消息的权威 token 数之和,除以各消息生成时长之和。
  • TTFT:从本轮请求开始到第一个文本或思考 token 的时间。首个 token 到达立即显示,一直保留到下一次生成开始。
  • 思考粒子流:模型流式输出思考内容时,一串盲文点从读数旁流出:最新的一格最亮,越旧越淡,亮色随时间沿渐变色漂移;开始输出正文就消失。只在思考时出现,平时不占位。

流结束后 AVG / TTFT 摘要不会清空:工具执行期间、等待下一轮响应期间都保持可见,下一条助手消息开始时才更新。

颜色

TPS / AVG(越高越好)

档位 范围(tok/s) 颜色
slow < 20 红
normal 20–50 黄
fast 50–100 绿
faster ≥ 100 青

TTFT(越低越好)

档位 范围 颜色
fast < 10s 绿
ok 10–20s 黄
slow ≥ 20s 红

档位下界包含在内:恰好 20 TPS 算 normal,恰好 10s 算 ok。阈值可以在配置文件里改。标签和 -- 用暗色显示。

安装

pi install npm:@jack-yang/pi-tps-meter     # 从 npm 安装(推荐)
pi install /path/to/pi-tps-meter           # 本地目录:不复制,直接从该路径加载
pi -e npm:@jack-yang/pi-tps-meter          # 只在本次启动试用,不写入 settings

安装后重启 pi,或在已打开的会话里执行 /reload。以后升级用 pi update --extensions。npm 版和本地目录版只装一个,两个都装会出现两条读数,命令也会变成 /tps:1 和 /tps:2。

本地目录请用不带 npm: 前缀的路径形式。pi install npm:./pi-tps-meter 在 pi 1.5.0 下能装上,但加载不了:pi 按 npm: 后面的字符串推算安装目录,路径形式的 spec 永远对不上 node_modules/@jack-yang/pi-tps-meter;而且这个相对路径会原样写进 settings,下次启动时 pi 会在新的工作目录下重装并失败。

环境要求:pi ≥ 1.5.0(已在 1.5.0 实测)。没有运行时依赖,也不发起任何网络请求。

命令

命令 作用
/tps 循环切换 footer → right → status → widget → off
/tps footer footer 的目录那一行右端(默认),不额外占行
/tps right 编辑器下方单独一行,右对齐,紧贴 footer
/tps status footer 的扩展状态行,和其他扩展共用一行,按扩展名排序
/tps widget 编辑器上方的单行组件
/tps off 完全隐藏。计量仍在后台进行,切回来立即显示当前读数

模式写入配置文件,下次启动沿用。

footer 模式是怎么做的:pi 的 footer 没有给扩展留定位的口子(扩展状态只能左对齐拼在最后一行),所以这里用 setFooter 挂了一个包装层:里面跑的就是 pi 自己导出的 FooterComponent,统计行、状态行都由 pi 自己渲染,实测和原装 footer 逐字符、连颜色都一致;只是在目录那一行右端补上读数。终端变窄时先截短目录(和 pi 一样用 ...),读数保持完整;中文目录名按双宽字符计算。如果将来某个 pi 版本改了 footer 内部导致包装失败,会自动恢复 pi 原装 footer、退回 right 模式并提示一次,不会把 footer 弄坏。

如果也嫌 pi-lens 的 LSP Inactive 占地方,pi-lens 自己有开关:在 ~/.pi-lens/config.json 里设 ui.compactLspStatus: true(压成一个图标)或 ui.hideLspStatus: true(不显示)。

配置

配置文件位于 ~/.pi/agent/pi-tps-meter/config.json;设置了 PI_CODING_AGENT_DIR 时,位于该目录下的 pi-tps-meter/config.json。

{
  "mode": "footer",
  "tiers": {
    "tps":  { "slow": 20, "normal": 50, "fast": 100 },
    "ttft": { "fast": 10000, "ok": 20000 }
  },
  "spinner": { "theme": "tech", "intervalMs": 100, "cells": 6 }
}
键 默认值 说明
mode "footer" footer / right / status / widget / off。/tps 只改写这个键,其他内容原样保留
tiers.tps { slow: 20, normal: 50, fast: 100 } TPS 与 AVG 的分档阈值(tok/s)
tiers.ttft { fast: 10000, ok: 20000 } TTFT 分档阈值(毫秒)
spinner.theme "tech" 粒子流配色:"tech"(青 → 蓝 → 紫)、"red"(KITT 风格红);"none" 关闭粒子流
spinner.colors 随 theme 自定义渐变色,"#rrggbb" / "#rgb" 数组,优先于 theme
spinner.intervalMs 100 粒子前进一格的间隔(毫秒)
spinner.cells 6 粒子流格数(宽度),至少 2
spinner.enabled true false 关闭粒子流
  • 所有键都可省略,按字段覆盖默认值,例如只写 { "tiers": { "tps": { "fast": 80 } } }。不是数字的值会被忽略。
  • 文件在会话启动时读取,手动修改后执行 /reload 生效。
  • 文件无法解析时,使用默认值并给出提示;这种情况下 /tps 也不会覆盖它。

工作原理

TPS

每个流式 delta(text、thinking、toolcall 三种都算)按 UTF-8 字节数 ÷ 4 估算 token 数,记入 5 秒滑动窗口:

TPS = 窗口内估算 token 之和 × 校准因子 ÷ (当前时间 − 窗口内最早样本)

时长下限是 1 秒,避免刚开始的一两个 chunk 显示成尖峰;最后一个样本已经超过 1.5 秒时不显示。跨度用墙钟时间计算,不累加 delta 之间的间隔,因为网络会把多个 token 打包到达,间隔之和会让速率虚高。

校准

字节 ÷ 4 对中文偏差很大(一个汉字占 3 字节)。每条消息结束时,用 pi 给出的权威输出 token 数(usage.output)除以这条消息的累计估算值,得到一个比率(限制在 0.3–3.0 之间)。扩展保留最近 10 个比率,取中位数作为校准因子,用于之后消息的实时速率;第一条消息结束之前,因子是 1.0。

实测(GLM-5.3-Flash,400–500 字中文短文):未校准时实时 TPS 偏高 17%–30%;校准一轮之后,按校准因子换算的整条消息 token 数与权威值相差 +1%~+12%。

AVG

AVG = Σ 权威 token 数 ÷ Σ (最后一个 delta − 第一个 delta)

只统计已完成的消息,单条消息的时长下限为 1 秒,所以 TTFT 等待和工具执行时间都不计入。出错或被中断的消息(usage 不完整)不计入 AVG,也不参与校准。

TTFT

TTFT 从 turn_start 开始计时(在 pi 里,一个 turn 就是一次模型请求),到这条消息的第一个 text 或 thinking delta 为止。toolcall delta 不会结束 TTFT 等待,但会计入 TPS。只调用工具、没有任何文本或思考输出的消息,TTFT 显示 --。

为什么不从 message_start 开始算:pi 收到 HTTP 响应头之后才发出 message_start,而多数服务端要排完队、做完 prefill 才返回响应头。实测中,响应头在请求发出约 2 秒后才到,message_start 和第一个 delta 落在同一毫秒;从 message_start 算,TTFT 几乎永远是 0。

工具调用

工具在两条助手消息之间执行。每条消息结束时清空滑动窗口,所以工具耗时不会摊进下一条消息的速率。

与 opencode-tps-meter 的差异

  • TTFT 起点用 turn_start,对应原版的 session.step.started(模型调用开始)。
  • 下一条助手消息开始时清空 TTFT,原版要等到下一个首 token 才覆盖。
  • toolcall delta 计入 TPS 和校准,因为 pi 的 usage.output 包含工具调用参数的 token;原版只统计文本和推理。TTFT 仍然只认文本和思考。
  • 权威 token 数直接用 usage.output:pi 的 output 已经包含推理 token,原版需要把 output 和 reasoning 相加。
  • 思考粒子流已移植(配色预设、渐变、FIFO 流动、配置项都和原版一致),并做了原版想做但受限于 opencode 做不到的一点:每个粒子单独着色,真正从亮到暗渐隐(原版受 opentui 限制,整串只能用一种颜色)。右对齐时粒子流放在读数左边、方向镜像,读数本身不会移动。
  • 显示位置:原版在 opencode 输入框右侧的 slot 里;pi 没有对应的位置,默认放在 footer 目录行右端(包装 pi 自己的 footer,不替换),另有 right / status / widget 可选。
  • 颜色用 ANSI 基本色:红 31、黄 33、绿 32、青 36,标签用暗色;原版用的是 opencode 主题槽位。

已知限制

  • 不流式输出的推理:有些模型按推理 token 计费,但不把推理内容流式发出来。这时校准比率会顶到 3.0 上限,AVG 也会偏高(原版同样如此)。
  • 一次性返回工具参数的 provider(如 Gemini):消息末尾会出现一个短暂的 TPS 尖峰,消息结束后立即清除。
  • footer 和其他替换 footer 的扩展互斥:pi 同一时间只有一个 footer,后设置的生效。如果还开着 awesome-pi-themes 的 look-pack 这类扩展,改用 /tps right。status 模式也依赖 pi 的默认 footer(look-pack 不渲染扩展状态)。
  • AVG 和校准只在当前会话内累计:/new、/resume、/fork、/reload 会重新开始;不会从历史记录里重建。
  • TTFT 包含客户端准备时间:包括请求前的上下文处理(实测约 7ms)和 provider 层的自动重试等待,也就是用户实际等待的时间。
  • 时间戳取自 pi 把事件派发给扩展的时刻:其他扩展的慢 handler 会推迟派发,从而影响读数。

开发

npm test                            # node --test,不需要安装依赖(Node ≥ 22.19)
npm install && npm run typecheck    # 可选:tsc 严格检查,会装上 pi 作为 peer 依赖以获得类型
pi -e .                             # 在真实会话中试用

许可证

MIT