@snailuu/pi-token-use
Pi extension: interactive multi-dimensional drill-down of local token usage (time / project / model)
Package details
Install @snailuu/pi-token-use from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:@snailuu/pi-token-use- Package
@snailuu/pi-token-use- Version
0.2.1- Published
- Jul 25, 2026
- Downloads
- 442/mo · 442/wk
- Author
- snailuu
- License
- MIT
- Types
- extension
- Size
- 69.3 KB
- Dependencies
- 0 dependencies · 2 peers
Pi manifest JSON
{
"extensions": [
"./src/index.ts"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
@snailuu/pi-token-use
pi 扩展:交互式浏览本机 token 用量与花费,按时间 / 项目 / 模型多维钻取。
pi 自带的 /session 只能看当前会话。本扩展扫描本机全部历史会话,用一个可导航的浮层面板回答「哪个项目最花钱」「某段时间内各模型分别用了多少」「这次暴增是哪次对话干的」。
金额默认自动算出:单价优先取 pi 自己维护的模型目录,你也可以在配置文件里为自建中转等渠道指定实际单价。
安装
pi install npm:@snailuu/pi-token-use
本地开发:
pi install /path/to/pi-token-use-npm
使用
/token-use 打开面板(默认全部时间)
/token-use today 只看今天
/token-use 7d | 30d | all 预设时间窗
/token-use 2026-07-01..2026-07-24 自定义日期区间(闭区间,本地时区)
面板占满整个终端。顶部三行(时间 / 分组 / 排序)和下方表格都是可聚焦区域:
| 键 | 作用 |
|---|---|
↑ ↓ |
在表格内移动行;到达表格顶端后继续 ↑ 依次进入 排序 → 分组 → 时间 |
← → |
在筛选行上:切换该行的选项,立即生效在表格上:展开 / 收起当前行 |
Enter |
在筛选行上:回到表格在表格上:展开 / 收起 |
Tab |
快捷切换分组(不必先把焦点移上去) |
t |
快捷切换时间窗 |
s |
快捷切换排序列 |
p |
在用量视图和定价视图之间切换 |
e |
(定价页)就地编辑当前渠道的单价 |
d |
(定价页)清除手工价,回退自动匹配 |
r |
(定价页)重读配置文件,同步外部改动 |
Esc |
关闭 |
面板长这样(▸ 标记当前聚焦的筛选行,▶ 标记表格光标):
╭────────────────────────────────────────────────────────────────────────────╮
│ pi token 用量 [用量] 定价 (p 切换) │
│ 时间: 今天 7天 30天 [全部] │
│ 分组: [项目] 模型 │
│ 排序: [金额] input output cacheRead 命中率 │
├────────────────────────────────────────────────────────────────────────────┤
│ 项目 input output cacheRead 命中率 金额│
│ 合计 8.67M 356K 123.3M 93.4% $7.11│
│ ▾ team/web-app ● 8.16M 310K 112.4M 93.2% $6.86│
│▶ ▾ provider-a/model-pro 7.90M 301K 110.1M 93.3% $4.18│
│ 03-14 14:07 · 补结... 4.80M 213K 65.9M 93.2% $2.56│
│ 03-14 14:07 · 重构... 3.10M 88K 44.2M 93.4% $1.62│
│ ▸ my-relay/model-mini 264K 9.1K 2.30M 89.7% $2.67│
│ ▸ team/api-server 415K 38K 9.80M 95.9% $0.26│
├────────────────────────────────────────────────────────────────────────────┤
│ 1 个渠道借用了同名模型的官方价,金额仅供参考:my-relay/model-mini │
│ 1 个渠道无单价,其 token 未计入金额:provider-x/model-unknown │
│ ↑↓ 移动 · ←→ 切换/展开 · Tab 分组 · t 时间 · s 排序 · p 定价 · Esc 关闭 │
╰────────────────────────────────────────────────────────────────────────────╯
● 标记当前所在项目。合计行固定在表头下方,不参与排序也不随滚动。价格来源可疑的渠道不在行内打标记,只在底部集中说明。
按 p 进入定价页,看每个渠道实际生效的单价及其出处,并直接改价:
╭────────────────────────────────────────────────────────────────────────────╮
│ pi token 用量 用量 [定价] (p 切换) │
├────────────────────────────────────────────────────────────────────────────┤
│ 渠道 input output cacheR 来源│
│▶provider-a/model-pro $0.44 $0.88 $0.004 目录│
│ my-relay/model-mini $2.5 $15 $0.25 借用│
│ provider-x/model-unknown — — — 无单价│
├────────────────────────────────────────────────────────────────────────────┤
│ 单价单位 $/百万 token · 配置文件 ~/.pi/agent/extensions/pi-token-use/con...│
│ ↑↓ 移动 · e 编辑 · d 清除手工价 · r 重读配置 · p 返回用量 · Esc 关闭 │
╰────────────────────────────────────────────────────────────────────────────╯
定价页列出的是全部历史用到过的渠道,与时间窗无关——定价是渠道的固有属性。
按 e 就地改价,四个字段预填当前生效值,把中转站的数字覆盖上去即可:
│ 渠道 input output cacheR 来源│
│▶provider-a/model-pro [0.44█] 0.88 0.004 编辑中│
│ my-relay/model-mini $2.5 $15 $0.25 借用│
├────────────────────────────────────────────────────────────────────────────┤
│ 输入数字 · Tab/←→ 切字段 · Enter 保存 · Esc 取消编辑 │
╰────────────────────────────────────────────────────────────────────────────╯
- 只接受数字和小数点,其他按键忽略
Enter写进配置文件的pricing段并立即重算金额,切回用量页就是新数字Esc只取消编辑,不关闭面板d清除该渠道的手工价,回退到自动匹配- 编辑本身带阶梯定价的渠道时,底部会提示保存后阶梯定价将失效(手工价是整条替换的)
为什么四类 token 要分开看
因为它们的单价差着两个数量级。cacheRead(复用的 prompt 前缀)在某些模型上只有 input 的 1/120。一台机器上 90%+ 的 token 是 cacheRead 很常见——此时「总 token」这个数字几乎不携带信息,排行榜会完全被缓存复读主导。
所以本扩展不提供「总计」列,默认按 input 排序,并单独给出命中率。
定价配置
金额默认全自动,多数情况下不用配。只有当某个渠道的实际价格和官方价不同(自建中转常有折扣或加价),才需要改。
改单个渠道直接在定价页按 e;要批量导入整份价格表,就直接写配置文件——两者改的是同一份数据。
配置文件:~/.pi/agent/extensions/pi-token-use/config.json,第一次打开面板时自动生成,分两段:
{
"_note": "catalog 段由插件自动同步为 pi 的官方定价,直接修改它不会生效;要覆盖某个渠道的价格,请写到 pricing 段。",
"catalog": {
"provider-a/model-pro": { "input": 0.44, "output": 0.88, "cacheRead": 0.004, "cacheWrite": 0 },
"my-relay/model-mini": { "input": 2.5, "output": 15, "cacheRead": 0.25, "cacheWrite": 0 }
},
"pricing": {
"my-relay/model-mini": { "input": 3.5, "output": 21, "cacheRead": 0.35, "cacheWrite": 0 },
"my-relay/*": { "input": 2, "output": 10, "cacheRead": 0.2, "cacheWrite": 0 }
}
}
| 段 | 谁写 | 作用 |
|---|---|---|
catalog |
插件自动写,每次打开面板同步为 pi 最新官方价 | 只供查阅和复制,改它无效;官方降价会自动反映在这里 |
pricing |
你或 AI 写,插件除了 e 保存外绝不碰 |
实际生效的覆盖价,优先级最高 |
要改价,就把 catalog 里那一条复制到 pricing 再改数字。
catalog 段只列四个基础单价,不写阶梯规则(避免文件太长)。但计价时仍会用官方阶梯——某些模型单次请求 prompt 超过阈值后单价会翻倍,这个规则直接来自 pi 的模型目录。一旦你在 pricing 里覆盖了某渠道,它就按你给的单一价计算,不再有阶梯。
- key 是
provider/model;provider/*作为该渠道的兜底默认值 - 单价单位是 每百万 token 美元,与 pi 自带定价表一致
- 省略的字段按
0计 - 解析不出官方价的渠道不会写进
catalog——写成 0 等于把「未知」伪装成「免费」 - 阶梯定价写
"tiers": [{ "inputTokensAbove": 272000, "input": 10, "output": 45, "cacheRead": 1 }]
改完文件重新打开面板即生效,不需要重启 pi;面板正开着的话,在定价页按 r 就能重读。文件是纯 JSON,方便让 AI 读了中转站价格表后批量写入 pricing 段,不必一条条手填。
在定价页按 e 保存时,只会改动那一条,文件里其他内容(AI 批量写入的整份价格表、其他配置段)原样保留。如果文件当前是坏 JSON,保存会被拒绝并提示——宁可不写,也不能把你原有的内容冲掉。
配置写错不会被静默忽略——用量页底部会提示有几处问题,按 p 看具体是哪一条哪个字段。
单价从哪来
按优先级取第一个命中的:
| 优先级 | 来源 | 面板显示 |
|---|---|---|
| 1 | 配置文件里 provider/model 精确匹配 |
手工配置 |
| 2 | 配置文件里 provider/* 通配 |
手工通配 |
| 3 | pi 模型目录中同 provider 同 model | pi 定价表 |
| 4 | pi 模型目录中其他 provider 下的同名 model | 借用同名模型 |
第 4 种是推测——它假定你的中转按被借用方的官方价计费。这个假设未必成立,所以面板底部会明确列出哪些渠道用的是借来的价。想让数字变准,就在配置里给这些渠道填上真实单价。
四种都不命中时该渠道没有金额,显示 — 而不是 $0:0 表示免费,— 表示不知道,两者不能混。
关于金额的算法
金额是逐条记录算完再相加的,不是把 token 汇总后乘单价。
因为阶梯定价按单次请求的 prompt 量判定档位(且 cacheRead 计入该判定)。若先汇总,总量必然落进最高档,金额会被系统性抬高——在实测数据上这个差距达到 71%。
工作方式
数据源是 ~/.pi/agent/sessions/ 下的会话 JSONL,扩展只读不写,不 hook 模型调用,也不建任何缓存或数据库——每次打开面板全量重扫(数十个会话、数千条记录的规模下约 100ms),所以看到的永远是最新数据,包括你刚刚这轮对话产生的用量。
所有数据都留在本地,不发往任何外部服务。
术语定义见 CONTEXT.md。
开发
pnpm install
pnpm test # vitest,覆盖解析与聚合纯函数
pnpm typecheck
License
MIT