@chenlongapps/opencode-token-usage 0.2.4 → 0.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/README.md CHANGED
@@ -49,7 +49,8 @@ For remote sessions, add the package name to `plugins` in your local `~/.config/
49
49
  | `Cache Rate` | `Cache Read ÷ (Input + Cache Read + Cache Write)` |
50
50
  | `Total` | Sum of all five token categories |
51
51
  | `Context` | Latest context usage after the most recent completed compaction in the viewed session; not aggregated across the subtree |
52
- | `Cost` | Estimated cost for the entire tree, recalculated using the viewed session's active model; not a provider bill |
52
+ | `Steps` | Assistant message count across the session tree, including subagents; follows OpenCode's own stats definition, so compaction and user messages are not steps |
53
+ | `Cost` | Estimated cost across the tree, pricing each assistant and compaction call with its actual model |
53
54
  | `TPS` | Generation throughput for `Output + Reasoning` across the tree; live estimates are marked with `~` |
54
55
  | `TTFT` | Average time to first token across measurable assistant steps in the tree |
55
56
 
@@ -58,7 +59,10 @@ For remote sessions, add the package name to `plugins` in your local `~/.config/
58
59
  - Usage includes server-reported assistant and compaction messages throughout the session tree, including unopened subagents. Token counts are never inferred from text length.
59
60
  - A fork is a separate session tree. Inherited message copies are attributed only to their original source to prevent double counting.
60
61
  - `Context` only searches messages after the most recent compaction with `status === "completed"` and is hidden when reliable usage or a model context limit is unavailable.
61
- - `Cost` applies the viewed session's active model to the whole tree. Missing applicable prices fall back to 0, matching OpenCode's behavior.
62
+ - `Steps` counts every assistant message in the tree, whether or not it reported usage, and reuses the fork-copy de-duplication so inherited history is never counted twice.
63
+ - `Cost` prices every message with its recorded model. A complete applicable price resolved by OpenCode takes precedence; when OpenCode has no usable price, the plugin falls back to a packaged snapshot of manufacturer prices.
64
+ - Gateway models can use manufacturer fallback prices through exact model IDs and documented aliases. The fallback does not include gateway markups, regional premiums, discounts, tool fees, or taxes, so Cost is an estimate rather than a provider bill.
65
+ - Confirmed free usage displays `$0.00`; unavailable prices display `—`; known subtotals with unpriced messages are marked `partial`. See the [built-in price snapshot](docs/pricing.md) for coverage, sources, and limitations.
62
66
  - Initial read failures display `Unavailable`. Later failures retain the last complete snapshot, display `Not updated`, and retry automatically.
63
67
 
64
68
  ### Development
@@ -71,7 +75,7 @@ npm run build
71
75
  npm run test:smoke
72
76
  ```
73
77
 
74
- `test:smoke` packages the real artifact and validates loading, refreshes, subagent aggregation, model switching, TPS, and TTFT against an isolated OpenCode instance and a local mock provider. It requires Python 3, an available local port, and npm network access. It never modifies your existing OpenCode configuration or calls paid models.
78
+ `test:smoke` packages the real artifact and validates loading, refreshes, subagent aggregation, per-message pricing, official-price fallback, model switching, TPS, and TTFT against an isolated OpenCode instance and a local mock provider. It requires Python 3, an available local port, and npm network access. It never modifies your existing OpenCode configuration or calls paid models.
75
79
 
76
80
  To load the plugin from source, build the project and add the repository's absolute path to `plugins` in the target project.
77
81
 
package/README.zh-CN.md CHANGED
@@ -49,7 +49,8 @@ opencode plugin add @chenlongapps/opencode-token-usage
49
49
  | `Cache Rate` | `Cache Read ÷ (Input + Cache Read + Cache Write)` |
50
50
  | `Total` | 五类 token 之和 |
51
51
  | `Context` | 当前会话最后一次已完成压缩后的最新上下文用量,不随子树累计 |
52
- | `Cost` | 按当前会话活动模型重新估算的全树费用,不代表提供商账单 |
52
+ | `Steps` | 全树(含子代理)的 assistant 消息数,口径与 OpenCode 自带统计一致,compaction 与用户消息不计为 step |
53
+ | `Cost` | 按每条 assistant 与 compaction 消息实际模型估算的全树费用 |
53
54
  | `TPS` | 全树 `Output + Reasoning` 的生成速度;生成中的估算值带 `~` 标记 |
54
55
  | `TTFT` | 全树中可测 assistant step 的平均首 token 时间 |
55
56
 
@@ -58,7 +59,10 @@ opencode plugin add @chenlongapps/opencode-token-usage
58
59
  - 用量覆盖会话树中服务端上报的 assistant 与 compaction 消息,包括未打开的子代理;不按文本长度估算 token。
59
60
  - 分叉会话是独立会话树。继承消息副本只归原始来源,避免重复计费。
60
61
  - `Context` 仅搜索最后一次 `status === "completed"` 的 compaction 之后;没有可靠用量或模型上限时隐藏。
61
- - `Cost` 使用当前查看会话的活动模型重算整棵树;缺失适用价格时按 OpenCode 行为回退为 0。
62
+ - `Steps` 统计树中全部 assistant 消息,无论是否已上报用量;复用分叉副本去重,继承历史不会重复计数。
63
+ - `Cost` 按每条消息记录的实际模型分别计算。OpenCode 当前解析出的完整适用价格优先;OpenCode 没有可用价格时,回退到插件内置的厂商官方价格快照。
64
+ - 网关模型可通过精确模型 ID 和已记录别名使用厂商价格,但不包含网关加价、区域溢价、折扣、工具费和税费,因此 Cost 是估算而非提供商账单。
65
+ - 确认免费时显示 `$0.00`;价格不可用时显示 `—`;只有部分消息可计算时在已知小计后标注 `partial`。覆盖范围、来源和限制见[内置官方价格快照](docs/pricing.md)。
62
66
  - 首次读取失败显示 `Unavailable`;后续失败保留上次完整快照、标注 `Not updated` 并自动重试。
63
67
 
64
68
  ### 开发
@@ -71,7 +75,7 @@ npm run build
71
75
  npm run test:smoke
72
76
  ```
73
77
 
74
- `test:smoke` 会打包真实产物,并在隔离的 OpenCode 与本地模拟提供商中验证加载、刷新、子代理累计、模型切换、TPS 和 TTFT。它需要 Python 3、可用的本地端口和 npm 网络访问,不会修改现有 OpenCode 配置或调用付费模型。
78
+ `test:smoke` 会打包真实产物,并在隔离的 OpenCode 与本地模拟提供商中验证加载、刷新、子代理累计、逐消息计价、官方价格补全、模型切换、TPS 和 TTFT。它需要 Python 3、可用的本地端口和 npm 网络访问,不会修改现有 OpenCode 配置或调用付费模型。
75
79
 
76
80
  从源码加载时,先构建项目,再将仓库绝对路径加入目标项目的 `plugins`。
77
81
 
package/ROADMAP.md CHANGED
@@ -54,13 +54,33 @@ TPS 48.7 tok/s
54
54
  TTFT 2.7s
55
55
  ```
56
56
 
57
- ## v0.3.0 — 公开价格目录
57
+ ## v0.2.5 — Steps 计数
58
58
 
59
- 目标:提供可查询的价格目录,便于用户了解不同模型的计费档位。
59
+ 目标:让整棵树的模型调用次数可见。
60
60
 
61
- * [ ] 构建公开价格目录,包含模型、价格档位及阈值
62
- * [ ] 只收录半年内发布的模型
63
- <!-- TODO -->
61
+ * [x] 显示全树(含子代理)的 `Steps` 计数
62
+ * [x] 口径与 OpenCode 官方统计一致:每条 assistant 消息为一个 step,compaction 与用户消息不计
63
+ * [x] 分叉继承副本不重复计数
64
+ * [x] 行位置为 Context 之后、Input 之前;无 Context 时位于面板第一行
65
+ * [x] 实际打包产物在 OpenCode 2.0.11 中验证显示与刷新
66
+
67
+ ```text
68
+ Steps 1,234
69
+ ```
70
+
71
+ ## v0.3.0 — 官方价格补全
72
+
73
+ 目标:按每条消息实际使用的模型统计费用,并在 OpenCode 缺少价格时使用厂商官方价格补全。
74
+
75
+ * [x] 内置可追溯的厂商官方价格快照
76
+ * [x] 首版收录最近半年发布且具有明确标准 token 定价的模型
77
+ * [x] OpenCode 完整适用价格优先,缺失时整条消息回退到官方价格
78
+ * [x] 按 assistant 与 compaction 消息实际模型分别计算
79
+ * [x] 支持价格阶梯、缓存读写和 Reasoning 费用
80
+ * [x] 支持网关模型到厂商模型的精确 ID 与明确别名映射
81
+ * [x] 区分免费、部分可计算和价格不可用
82
+ * [x] 已收录模型永久保留,后续持续核验价格和来源
83
+ * [x] 通过单元测试与 OpenCode 2.0.11 打包集成验证
64
84
 
65
85
  ## v0.4.0 — 用量命令
66
86
 
@@ -74,5 +94,4 @@ TTFT 2.7s
74
94
 
75
95
  ## 后续评估
76
96
 
77
- * [ ] 公开价格目录与更新策略
78
97
  * [x] 首次 npm 发布:`@chenlongapps/opencode-token-usage@0.2.1`
@@ -137,7 +137,7 @@ export class UsageController {
137
137
  this.performanceTimer = undefined;
138
138
  this.update({
139
139
  status: "ready",
140
- summary: summarize(messages, snapshot.model.prices),
140
+ summary: summarize(messages, snapshot.model.catalog),
141
141
  context: contextUsage(viewedMessages(snapshot), snapshot.model.context),
142
142
  performance: this.performance.summary(messages, this.sessions),
143
143
  model: snapshot.model.label,
@@ -0,0 +1,142 @@
1
+ import type { ModelRef, Price } from "./usage.js";
2
+ export interface OfficialPriceEntry {
3
+ /** Canonical model ID used by the model manufacturer. */
4
+ id: string;
5
+ /** First public release date, used to enforce the snapshot's inclusion window. */
6
+ released: string;
7
+ /** Exact alternate IDs used by supported gateways or manufacturer aliases. */
8
+ aliases?: readonly string[];
9
+ /** Standard, synchronous API token rates in USD per million tokens. */
10
+ prices: readonly Price[];
11
+ /** Manufacturer pricing page used to verify the rates. */
12
+ source: string;
13
+ }
14
+ export declare const OFFICIAL_PRICE_SNAPSHOT: {
15
+ readonly verified: "2026-09-23";
16
+ readonly newModelCutoff: "2026-03-22";
17
+ readonly entries: ({
18
+ id: string;
19
+ released: string;
20
+ source: string;
21
+ prices: ({
22
+ input: number;
23
+ output: number;
24
+ cache: {
25
+ read: number;
26
+ };
27
+ tier?: never;
28
+ } | {
29
+ tier: {
30
+ type: "context";
31
+ size: number;
32
+ };
33
+ input: number;
34
+ output: number;
35
+ cache: {
36
+ read: number;
37
+ };
38
+ })[];
39
+ aliases?: never;
40
+ } | {
41
+ id: string;
42
+ released: string;
43
+ source: string;
44
+ prices: ({
45
+ input: number;
46
+ output: number;
47
+ tier?: never;
48
+ } | {
49
+ tier: {
50
+ type: "context";
51
+ size: number;
52
+ };
53
+ input: number;
54
+ output: number;
55
+ })[];
56
+ aliases?: never;
57
+ } | {
58
+ id: string;
59
+ released: string;
60
+ source: string;
61
+ prices: ({
62
+ input: number;
63
+ output: number;
64
+ cache: {
65
+ read: number;
66
+ write: number;
67
+ };
68
+ tier?: never;
69
+ } | {
70
+ tier: {
71
+ type: "context";
72
+ size: number;
73
+ };
74
+ input: number;
75
+ output: number;
76
+ cache: {
77
+ read: number;
78
+ write: number;
79
+ };
80
+ })[];
81
+ aliases?: never;
82
+ } | {
83
+ id: string;
84
+ aliases: string[];
85
+ released: string;
86
+ source: string;
87
+ prices: {
88
+ input: number;
89
+ output: number;
90
+ cache: {
91
+ read: number;
92
+ write: number;
93
+ };
94
+ }[];
95
+ } | {
96
+ id: string;
97
+ aliases: string[];
98
+ released: string;
99
+ source: string;
100
+ prices: ({
101
+ input: number;
102
+ output: number;
103
+ tier?: never;
104
+ } | {
105
+ tier: {
106
+ type: "context";
107
+ size: number;
108
+ };
109
+ input: number;
110
+ output: number;
111
+ })[];
112
+ } | {
113
+ id: string;
114
+ aliases: string[];
115
+ released: string;
116
+ source: string;
117
+ prices: ({
118
+ input: number;
119
+ output: number;
120
+ cache: {
121
+ read: number;
122
+ };
123
+ tier?: never;
124
+ } | {
125
+ tier: {
126
+ type: "context";
127
+ size: number;
128
+ };
129
+ input: number;
130
+ output: number;
131
+ cache: {
132
+ read: number;
133
+ };
134
+ })[];
135
+ })[];
136
+ };
137
+ /**
138
+ * Resolves exact manufacturer IDs through common gateway wrappers. It never
139
+ * performs substring or model-name matching, so similarly named variants do
140
+ * not silently inherit a different model's price.
141
+ */
142
+ export declare function officialPrice(model: ModelRef): OfficialPriceEntry | undefined;
@@ -0,0 +1,484 @@
1
+ export const OFFICIAL_PRICE_SNAPSHOT = {
2
+ verified: "2026-09-23",
3
+ newModelCutoff: "2026-03-22",
4
+ entries: [
5
+ // OpenAI standard processing. The tier sizes are exclusive thresholds, so
6
+ // 271,999 implements the official "long context at 272K" boundary.
7
+ {
8
+ id: "gpt-5.5", released: "2026-04-23", source: "https://developers.openai.com/api/docs/pricing",
9
+ prices: [
10
+ { input: 5, output: 30, cache: { read: 0.5 } },
11
+ { tier: { type: "context", size: 271_999 }, input: 10, output: 45, cache: { read: 1 } },
12
+ ],
13
+ },
14
+ {
15
+ id: "gpt-5.5-pro", released: "2026-04-23", source: "https://developers.openai.com/api/docs/pricing",
16
+ prices: [
17
+ { input: 30, output: 180 },
18
+ { tier: { type: "context", size: 271_999 }, input: 60, output: 270 },
19
+ ],
20
+ },
21
+ {
22
+ id: "gpt-5.6-sol", released: "2026-07-09", source: "https://developers.openai.com/api/docs/pricing",
23
+ prices: [
24
+ { input: 4, output: 20, cache: { read: 0.4, write: 5 } },
25
+ { tier: { type: "context", size: 271_999 }, input: 8, output: 30, cache: { read: 0.8, write: 10 } },
26
+ ],
27
+ },
28
+ {
29
+ id: "gpt-5.6-terra", released: "2026-07-09", source: "https://developers.openai.com/api/docs/pricing",
30
+ prices: [
31
+ { input: 2, output: 12, cache: { read: 0.2, write: 2.5 } },
32
+ { tier: { type: "context", size: 271_999 }, input: 4, output: 18, cache: { read: 0.4, write: 5 } },
33
+ ],
34
+ },
35
+ {
36
+ id: "gpt-5.6-luna", released: "2026-07-09", source: "https://developers.openai.com/api/docs/pricing",
37
+ prices: [
38
+ { input: 0.2, output: 1.2, cache: { read: 0.02, write: 0.25 } },
39
+ { tier: { type: "context", size: 271_999 }, input: 0.4, output: 1.8, cache: { read: 0.04, write: 0.5 } },
40
+ ],
41
+ },
42
+ {
43
+ id: "gpt-6-astra", released: "2026-09-04", source: "https://developers.openai.com/api/docs/pricing",
44
+ prices: [
45
+ { input: 10, output: 50, cache: { read: 1, write: 12.5 } },
46
+ { tier: { type: "context", size: 271_999 }, input: 20, output: 75, cache: { read: 2, write: 25 } },
47
+ ],
48
+ },
49
+ // The official ChatGPT SKU `chat-latest`. OpenRouter serves it under the
50
+ // slug `openai/gpt-chat-latest`, which is registered as an exact alias.
51
+ {
52
+ id: "chat-latest", aliases: ["gpt-chat-latest"], released: "2026-05-05",
53
+ source: "https://developers.openai.com/api/docs/pricing",
54
+ prices: [{ input: 5, output: 30, cache: { read: 0.5 } }],
55
+ },
56
+ // Anthropic standard processing and 5-minute cache writes. OpenCode's
57
+ // aggregate cache-write counter cannot distinguish 5-minute from 1-hour TTL.
58
+ {
59
+ id: "claude-opus-4-7", aliases: ["claude-opus-4.7"], released: "2026-04-14", source: "https://platform.claude.com/docs/en/about-claude/pricing",
60
+ prices: [{ input: 5, output: 25, cache: { read: 0.5, write: 6.25 } }],
61
+ },
62
+ {
63
+ id: "claude-opus-4-8", aliases: ["claude-opus-4.8"], released: "2026-05-28", source: "https://platform.claude.com/docs/en/about-claude/pricing",
64
+ prices: [{ input: 5, output: 25, cache: { read: 0.5, write: 6.25 } }],
65
+ },
66
+ {
67
+ id: "claude-fable-5", released: "2026-06-07", source: "https://platform.claude.com/docs/en/about-claude/pricing",
68
+ prices: [{ input: 10, output: 50, cache: { read: 1, write: 12.5 } }],
69
+ },
70
+ {
71
+ id: "claude-sonnet-5", released: "2026-06-29", source: "https://platform.claude.com/docs/en/about-claude/pricing",
72
+ prices: [{ input: 2, output: 10, cache: { read: 0.2, write: 2.5 } }],
73
+ },
74
+ {
75
+ id: "claude-opus-5", released: "2026-07-24", source: "https://platform.claude.com/docs/en/about-claude/pricing",
76
+ prices: [{ input: 5, output: 25, cache: { read: 0.5, write: 6.25 } }],
77
+ },
78
+ {
79
+ id: "claude-fable-5-1", aliases: ["claude-fable-5.1"], released: "2026-09-01",
80
+ source: "https://platform.claude.com/docs/en/about-claude/pricing",
81
+ prices: [{ input: 10, output: 50, cache: { read: 0.25, write: 12.5 } }],
82
+ },
83
+ // Google paid Standard API rates. Cache storage is billed separately by
84
+ // time and is intentionally not represented as a cache-write token rate.
85
+ {
86
+ id: "gemini-3.1-flash-lite", released: "2026-05-07", source: "https://ai.google.dev/gemini-api/docs/pricing",
87
+ prices: [{ input: 0.25, output: 1.5, cache: { read: 0.025 } }],
88
+ },
89
+ {
90
+ id: "gemini-3.5-flash", released: "2026-05-19", source: "https://ai.google.dev/gemini-api/docs/pricing",
91
+ prices: [{ input: 1.5, output: 9, cache: { read: 0.15 } }],
92
+ },
93
+ {
94
+ id: "gemini-3.5-flash-lite", released: "2026-07-21", source: "https://ai.google.dev/gemini-api/docs/pricing",
95
+ prices: [{ input: 0.3, output: 2.5, cache: { read: 0.03 } }],
96
+ },
97
+ {
98
+ id: "gemini-3.6-flash", released: "2026-07-21", source: "https://ai.google.dev/gemini-api/docs/pricing",
99
+ prices: [{ input: 0.75, output: 3.75, cache: { read: 0.075 } }],
100
+ },
101
+ {
102
+ id: "gemini-3.7-flash", released: "2026-08-13", source: "https://ai.google.dev/gemini-api/docs/pricing",
103
+ prices: [{ input: 0.75, output: 3.75, cache: { read: 0.075 } }],
104
+ },
105
+ {
106
+ id: "gemini-3.8-flash", released: "2026-09-02", source: "https://ai.google.dev/gemini-api/docs/pricing",
107
+ prices: [{ input: 0.75, output: 3.75, cache: { read: 0.075 } }],
108
+ },
109
+ // xAI standard text API rates. 199,999 implements the official higher
110
+ // price at 200K prompt tokens with OpenCode's exclusive-tier formula.
111
+ {
112
+ id: "grok-build-0.1", released: "2026-04-16", source: "https://docs.x.ai/developers/models",
113
+ prices: [
114
+ { input: 1, output: 2, cache: { read: 0.2 } },
115
+ { tier: { type: "context", size: 199_999 }, input: 2, output: 4, cache: { read: 0.4 } },
116
+ ],
117
+ },
118
+ {
119
+ id: "grok-4.3", released: "2026-04-17", source: "https://docs.x.ai/developers/models",
120
+ prices: [
121
+ { input: 1.25, output: 2.5, cache: { read: 0.2 } },
122
+ { tier: { type: "context", size: 199_999 }, input: 2.5, output: 5, cache: { read: 0.4 } },
123
+ ],
124
+ },
125
+ {
126
+ id: "grok-4.5", released: "2026-07-08", source: "https://docs.x.ai/developers/models",
127
+ prices: [
128
+ { input: 2, output: 6, cache: { read: 0.3 } },
129
+ { tier: { type: "context", size: 199_999 }, input: 4, output: 12, cache: { read: 0.6 } },
130
+ ],
131
+ },
132
+ {
133
+ id: "grok-4.6", released: "2026-08-12", source: "https://docs.x.ai/developers/models",
134
+ prices: [
135
+ { input: 2, output: 6, cache: { read: 0.5 } },
136
+ { tier: { type: "context", size: 199_999 }, input: 4, output: 12, cache: { read: 1 } },
137
+ ],
138
+ },
139
+ {
140
+ id: "grok-4.7", released: "2026-09-21",
141
+ source: "https://docs.x.ai/developers/models",
142
+ prices: [
143
+ { input: 2, output: 6, cache: { read: 0.5 } },
144
+ { tier: { type: "context", size: 199_999 }, input: 4, output: 12, cache: { read: 1 } },
145
+ ],
146
+ },
147
+ {
148
+ id: "mistral-medium-3-5-26-04",
149
+ aliases: ["mistral-medium-2604", "mistral-medium-3-5"],
150
+ released: "2026-04-29",
151
+ source: "https://docs.mistral.ai/inference/pricing",
152
+ prices: [{ input: 1.5, output: 7.5, cache: { read: 0.15 } }],
153
+ },
154
+ {
155
+ id: "command-a-plus-05-2026",
156
+ released: "2026-05-20",
157
+ source: "https://cohere.com/pricing",
158
+ prices: [{ input: 2.5, output: 10 }],
159
+ },
160
+ // Meta Model API standard-tier rates. The contributor tier is a separate
161
+ // discounted program that permits training on prompts and completions, so
162
+ // it is intentionally not part of the standard snapshot.
163
+ {
164
+ id: "muse-spark-1.1", released: "2026-07-09", source: "https://ai.developer.meta.com/docs/pricing-rate-limits",
165
+ prices: [{ input: 1.25, output: 4.25, cache: { read: 0.15 } }],
166
+ },
167
+ {
168
+ id: "muse-spark-1.2", released: "2026-08-05", source: "https://ai.developer.meta.com/docs/pricing-rate-limits",
169
+ prices: [{ input: 1.25, output: 4.25, cache: { read: 0.15 } }],
170
+ },
171
+ {
172
+ id: "muse-spark-1.3", released: "2026-09-02", source: "https://ai.developer.meta.com/docs/pricing-rate-limits",
173
+ prices: [{ input: 1.25, output: 4.25, cache: { read: 0.15 } }],
174
+ },
175
+ // Inception's current Mercury 2.5 API page shows an 80% launch discount;
176
+ // the snapshot records the billed standard-platform rates on verification
177
+ // day rather than the crossed-out list prices. No cache-write token rate is
178
+ // published.
179
+ {
180
+ id: "mercury-2.5", aliases: ["mercury-2.5-preview"], released: "2026-09-08",
181
+ source: "https://www.inceptionlabs.ai/models",
182
+ prices: [{ input: 0.04, output: 0.15, cache: { read: 0.004 } }],
183
+ },
184
+ // Upstage Solar Pro 4 standard Console API rates. The dated version ID is
185
+ // an exact manufacturer alias; no cache-write token rate is published.
186
+ {
187
+ id: "solar-pro4", aliases: ["solar-pro4-260806"], released: "2026-08-06",
188
+ source: "https://console.upstage.ai/docs/models/solar-pro-4",
189
+ prices: [{ input: 0.3, output: 1.2, cache: { read: 0.06 } }],
190
+ },
191
+ // Arcee AI's hosted API rates for the official Trinity reasoning release.
192
+ // The model is also available as open weights, but only the hosted API
193
+ // price is relevant to this token-cost snapshot.
194
+ {
195
+ id: "trinity-large-thinking", released: "2026-04-01", source: "https://docs.arcee.ai/get-started/pricing",
196
+ prices: [{ input: 0.25, output: 0.8, cache: { read: 0.06 } }],
197
+ },
198
+ // Aion Labs' own model catalog publishes these per-token API rates. The
199
+ // OpenRouter slugs retain the manufacturer's `aion-labs/` prefix, so it is
200
+ // registered as an exact alias rather than inferred from the name.
201
+ {
202
+ id: "aion-3.0", aliases: ["aion-labs/aion-3.0"], released: "2026-05-05",
203
+ source: "https://www.aionlabs.ai/docs/models",
204
+ prices: [{ input: 3, output: 6, cache: { read: 0.75 } }],
205
+ },
206
+ {
207
+ id: "aion-3.0-mini", aliases: ["aion-labs/aion-3.0-mini"], released: "2026-05-14",
208
+ source: "https://www.aionlabs.ai/docs/models",
209
+ prices: [{ input: 0.7, output: 1.4, cache: { read: 0.18 } }],
210
+ },
211
+ // Z.ai (Zhipu GLM) standard API rates. The page publishes a cache-hit input
212
+ // rate and prices cache storage by time instead of a cache-write token rate,
213
+ // so no cache-write rate is stored for these models.
214
+ {
215
+ id: "glm-5.1", released: "2026-04-06", source: "https://docs.z.ai/guides/overview/pricing",
216
+ prices: [{ input: 1.4, output: 4.4, cache: { read: 0.26 } }],
217
+ },
218
+ {
219
+ id: "glm-5.2", released: "2026-06-16", source: "https://docs.z.ai/guides/overview/pricing",
220
+ prices: [{ input: 1.4, output: 4.4, cache: { read: 0.26 } }],
221
+ },
222
+ {
223
+ id: "glm-5.3", released: "2026-08-16", source: "https://docs.z.ai/guides/overview/pricing",
224
+ prices: [{ input: 1.4, output: 4.4, cache: { read: 0.26 } }],
225
+ },
226
+ {
227
+ id: "glm-5.3-flash", released: "2026-08-26", source: "https://docs.z.ai/guides/overview/pricing",
228
+ prices: [{ input: 0.15, output: 0.5, cache: { read: 0.03 } }],
229
+ },
230
+ {
231
+ id: "glm-5.3-flashx", released: "2026-09-18", source: "https://docs.z.ai/guides/overview/pricing",
232
+ prices: [{ input: 0.37, output: 1.25, cache: { read: 0.075 } }],
233
+ },
234
+ // DeepSeek standard API peak rates. The vendor charges half these rates
235
+ // off-peak; using the peak tier provides a conservative upper-bound
236
+ // estimate because historical messages do not retain the billing hour.
237
+ // Retired V4 Flash and Vision Exp names currently route to V4.1 Flash at
238
+ // the Flash price. The dated 0731 and 0813 IDs are exact gateway aliases.
239
+ {
240
+ id: "deepseek-v4.1-flash",
241
+ aliases: ["deepseek-flash", "deepseek-v4-flash", "deepseek-v4-flash-0731", "deepseek-v4-flash-vision-exp"],
242
+ released: "2026-09-10",
243
+ source: "https://api-docs.deepseek.com/quick_start/pricing",
244
+ prices: [{ input: 0.3, output: 1.2, cache: { read: 0.006 } }],
245
+ },
246
+ {
247
+ id: "deepseek-v4-pro-0813", aliases: ["deepseek-v4-pro"], released: "2026-08-13",
248
+ source: "https://api-docs.deepseek.com/quick_start/pricing",
249
+ prices: [{ input: 1.32, output: 3.96, cache: { read: 0.044 } }],
250
+ },
251
+ // Moonshot Kimi standard API rates. K3 publishes 5-minute and 1-hour cache
252
+ // writes; following the Anthropic convention, the aggregate counter cannot
253
+ // tell them apart, so the snapshot stores the 5-minute write. The K2 table
254
+ // publishes only a cache-hit input rate and no cache-write price.
255
+ {
256
+ id: "kimi-k3", released: "2026-07-15", source: "https://platform.moonshot.ai/docs/pricing",
257
+ prices: [{ input: 3, output: 15, cache: { read: 0.3, write: 3 } }],
258
+ },
259
+ {
260
+ id: "kimi-k2.7-code", released: "2026-06-12", source: "https://platform.moonshot.ai/docs/pricing",
261
+ prices: [{ input: 0.95, output: 4, cache: { read: 0.19 } }],
262
+ },
263
+ {
264
+ id: "kimi-k2.6", released: "2026-04-20", source: "https://platform.moonshot.ai/docs/pricing",
265
+ prices: [{ input: 0.95, output: 4, cache: { read: 0.16 } }],
266
+ },
267
+ // Alibaba Cloud Model Studio standard (Singapore "International") list
268
+ // prices. Tier sizes implement the official inclusive boundaries
269
+ // ("0<Token≤256K" then "256K<Token≤1M") with the exclusive-threshold formula.
270
+ // Cache Read stores the official implicit-cache hit rate, 20% of the tier
271
+ // input, where the page publishes it. The qwen3.8 max/flash family reports
272
+ // cache rates only in the console, so no cache rate is stored for them, and
273
+ // no cache-write rate is stored anywhere because implicit cache writes bill
274
+ // at 100% of the input price while explicit cache writes bill at 125% and
275
+ // the aggregate counter cannot distinguish the two.
276
+ {
277
+ id: "qwen3.8-max", aliases: ["qwen3.8-max-0902"], released: "2026-08-03",
278
+ source: "https://www.alibabacloud.com/help/en/model-studio/model-pricing",
279
+ prices: [{ input: 2, output: 6 }],
280
+ },
281
+ {
282
+ id: "qwen3.8-2.4t-a95b", released: "2026-08-12",
283
+ source: "https://www.alibabacloud.com/help/en/model-studio/model-pricing",
284
+ prices: [{ input: 2, output: 6 }],
285
+ },
286
+ {
287
+ id: "qwen3.8-27b", released: "2026-08-14",
288
+ source: "https://www.alibabacloud.com/help/en/model-studio/model-pricing",
289
+ prices: [{ input: 0.5, output: 3, cache: { read: 0.1 } }],
290
+ },
291
+ {
292
+ id: "qwen3.8-flash", released: "2026-08-26",
293
+ source: "https://www.alibabacloud.com/help/en/model-studio/model-pricing",
294
+ prices: [{ input: 0.15, output: 0.47 }],
295
+ },
296
+ {
297
+ id: "qwen3.7-max", released: "2026-05-20",
298
+ source: "https://www.alibabacloud.com/help/en/model-studio/model-pricing",
299
+ prices: [{ input: 2.5, output: 7.5, cache: { read: 0.5 } }],
300
+ },
301
+ {
302
+ id: "qwen3.7-plus", released: "2026-05-26",
303
+ source: "https://www.alibabacloud.com/help/en/model-studio/model-pricing",
304
+ prices: [
305
+ { input: 0.4, output: 1.6, cache: { read: 0.08 } },
306
+ { tier: { type: "context", size: 256_000 }, input: 1.2, output: 4.8, cache: { read: 0.24 } },
307
+ ],
308
+ },
309
+ {
310
+ id: "qwen3.7-flash", released: "2026-07-15",
311
+ source: "https://www.alibabacloud.com/help/en/model-studio/model-pricing",
312
+ prices: [
313
+ { input: 0.03, output: 0.13, cache: { read: 0.006 } },
314
+ { tier: { type: "context", size: 32_000 }, input: 0.1, output: 0.4, cache: { read: 0.02 } },
315
+ { tier: { type: "context", size: 256_000 }, input: 0.2, output: 0.8, cache: { read: 0.04 } },
316
+ ],
317
+ },
318
+ {
319
+ id: "qwen3.6-max-preview", released: "2026-04-20",
320
+ source: "https://www.alibabacloud.com/help/en/model-studio/model-pricing",
321
+ prices: [
322
+ { input: 1.3, output: 7.8 },
323
+ { tier: { type: "context", size: 128_000 }, input: 2, output: 12 },
324
+ ],
325
+ },
326
+ {
327
+ id: "qwen3.6-plus", released: "2026-04-02",
328
+ source: "https://www.alibabacloud.com/help/en/model-studio/model-pricing",
329
+ prices: [
330
+ { input: 0.5, output: 3 },
331
+ { tier: { type: "context", size: 256_000 }, input: 2, output: 6 },
332
+ ],
333
+ },
334
+ {
335
+ id: "qwen3.6-flash", released: "2026-04-16",
336
+ source: "https://www.alibabacloud.com/help/en/model-studio/model-pricing",
337
+ prices: [
338
+ { input: 0.25, output: 1.5 },
339
+ { tier: { type: "context", size: 256_000 }, input: 1, output: 4 },
340
+ ],
341
+ },
342
+ {
343
+ id: "qwen3.6-27b", released: "2026-04-22",
344
+ source: "https://www.alibabacloud.com/help/en/model-studio/model-pricing",
345
+ prices: [{ input: 0.6, output: 3.6 }],
346
+ },
347
+ {
348
+ id: "qwen3.6-35b-a3b", released: "2026-04-15",
349
+ source: "https://www.alibabacloud.com/help/en/model-studio/model-pricing",
350
+ prices: [{ input: 0.375, output: 2.25 }],
351
+ },
352
+ {
353
+ id: "qwen3.5-plus-2026-04-20", aliases: ["qwen3.5-plus-20260420"], released: "2026-04-20",
354
+ source: "https://www.alibabacloud.com/help/en/model-studio/model-pricing",
355
+ prices: [
356
+ { input: 0.4, output: 2.4 },
357
+ { tier: { type: "context", size: 256_000 }, input: 0.5, output: 3 },
358
+ ],
359
+ },
360
+ // Xiaomi MiMo overseas USD rates. The MiMo-V2.6 series keeps the V2.5 API
361
+ // pricing. Cache writes are free for a limited time, so no cache-write rate
362
+ // is stored.
363
+ {
364
+ id: "mimo-v2.5", released: "2026-04-22", source: "https://mimo.mi.com/docs/price/pay-as-you-go",
365
+ prices: [{ input: 0.14, output: 0.28, cache: { read: 0.0028 } }],
366
+ },
367
+ {
368
+ id: "mimo-v2.5-pro", released: "2026-04-22", source: "https://mimo.mi.com/docs/price/pay-as-you-go",
369
+ prices: [{ input: 0.435, output: 0.87, cache: { read: 0.0036 } }],
370
+ },
371
+ {
372
+ id: "mimo-v2.6-flash", released: "2026-09-21", source: "https://mimo.mi.com/docs/price/pay-as-you-go",
373
+ prices: [{ input: 0.14, output: 0.28, cache: { read: 0.0028 } }],
374
+ },
375
+ {
376
+ id: "mimo-v2.6-pro", released: "2026-09-21", source: "https://mimo.mi.com/docs/price/pay-as-you-go",
377
+ prices: [{ input: 0.435, output: 0.87, cache: { read: 0.0036 } }],
378
+ },
379
+ {
380
+ id: "mimo-v2.6-pro-ultraspeed", released: "2026-09-21", source: "https://mimo.mi.com/docs/price/pay-as-you-go",
381
+ prices: [{ input: 4.35, output: 8.7, cache: { read: 0.036 } }],
382
+ },
383
+ // MiniMax pay-as-you-go billed rates. The page labels the M3 rates as a
384
+ // permanent 50% off and shows the struck-through list price beside them;
385
+ // like the GPT-5.6 Sol promotion, the snapshot stores the billed rates shown
386
+ // on the verification date. Only a prompt-caching read rate is published.
387
+ {
388
+ id: "minimax-m3", released: "2026-05-31", source: "https://platform.minimax.io/docs/guides/pricing-paygo",
389
+ prices: [
390
+ { input: 0.3, output: 1.2, cache: { read: 0.06 } },
391
+ { tier: { type: "context", size: 512_000 }, input: 0.6, output: 2.4, cache: { read: 0.12 } },
392
+ ],
393
+ },
394
+ // Tencent Cloud TokenHub international (Singapore) USD list prices for the
395
+ // vendor's own Hunyuan models. Cache is the published cache-hit rate; the
396
+ // page publishes no cache-write rate.
397
+ {
398
+ id: "hy3", released: "2026-07-06", source: "https://intl.cloud.tencent.com/document/product/1300/78937",
399
+ prices: [{ input: 0.132, output: 0.528, cache: { read: 0.033 } }],
400
+ },
401
+ {
402
+ id: "hy4-preview", released: "2026-08-27", source: "https://intl.cloud.tencent.com/document/product/1300/78937",
403
+ prices: [{ input: 0.834, output: 2.501, cache: { read: 0.042 } }],
404
+ },
405
+ // StepFun overseas platform rates. The page publishes a cache-hit input
406
+ // rate. For Step 5 Preview it explicitly states that cache-miss input
407
+ // includes writing new content to the cache, so split cache-write tokens
408
+ // retain the same rate as ordinary cache-miss input.
409
+ {
410
+ id: "step-5-preview", released: "2026-09-21", source: "https://platform.stepfun.ai/docs/en/guides/pricing/details",
411
+ prices: [{ input: 1, output: 2.7, cache: { read: 0.05, write: 1 } }],
412
+ },
413
+ {
414
+ id: "step-3.7-flash", released: "2026-05-28", source: "https://platform.stepfun.ai/docs/en/guides/pricing/details",
415
+ prices: [{ input: 0.2, output: 1.15, cache: { read: 0.04 } }],
416
+ },
417
+ // ByteDance Seed 2.1 Turbo standard online inference rates on BytePlus
418
+ // ModelArk. The cache-storage fee is time-based rather than a token write
419
+ // rate, so only the published cache-hit input price is represented.
420
+ {
421
+ id: "dola-seed-2-1-turbo",
422
+ aliases: ["seed-2-1-turbo", "dola-seed-2-1-turbo-260628"],
423
+ released: "2026-06-23",
424
+ source: "https://docs.byteplus.com/en/docs/ModelArk/1099320",
425
+ prices: [{ input: 0.5, output: 2.5, cache: { read: 0.1 } }],
426
+ },
427
+ // Sakana Fugu's fixed standard API rates. Fugu Ultra's orchestration
428
+ // tokens are included in the API's input/output usage fields and therefore
429
+ // use the same token rates. Web search/fetch tool fees are not token fees
430
+ // and cannot be represented by the plugin's five usage counters.
431
+ {
432
+ id: "fugu-ultra-v2.0", aliases: ["fugu-ultra-v2"], released: "2026-09-11",
433
+ source: "https://console.sakana.ai/pricing",
434
+ prices: [
435
+ { input: 5, output: 30, cache: { read: 0.5 } },
436
+ { tier: { type: "context", size: 271_999 }, input: 10, output: 45, cache: { read: 1 } },
437
+ ],
438
+ },
439
+ {
440
+ id: "fugu-max-v1.0", aliases: ["fugu-max"], released: "2026-09-11",
441
+ source: "https://console.sakana.ai/pricing",
442
+ prices: [{ input: 2, output: 6, cache: { read: 0.25 } }],
443
+ },
444
+ // LongCat's official API page shows both list and limited-time discounted
445
+ // rates. As with the other documented promotions in this snapshot, record
446
+ // the billed discounted rate visible on verification day. Cache storage or
447
+ // cache writes have no separate token rate on the page.
448
+ {
449
+ id: "longcat-2.0", released: "2026-06-30",
450
+ source: "https://longcat.chat/platform/docs/Pricing/LongCat-2.0.html",
451
+ prices: [{ input: 0.3, output: 1.2, cache: { read: 0.006 } }],
452
+ },
453
+ ],
454
+ };
455
+ const index = new Map();
456
+ for (const entry of OFFICIAL_PRICE_SNAPSHOT.entries) {
457
+ for (const id of [entry.id, ...(entry.aliases ?? [])]) {
458
+ const key = id.toLowerCase();
459
+ if (index.has(key))
460
+ throw new Error(`Duplicate official price ID: ${id}`);
461
+ index.set(key, entry);
462
+ }
463
+ }
464
+ /**
465
+ * Resolves exact manufacturer IDs through common gateway wrappers. It never
466
+ * performs substring or model-name matching, so similarly named variants do
467
+ * not silently inherit a different model's price.
468
+ */
469
+ export function officialPrice(model) {
470
+ const id = model.id.toLowerCase().replace(/@default$/, "");
471
+ const candidates = [id];
472
+ const slash = id.lastIndexOf("/");
473
+ if (slash >= 0)
474
+ candidates.push(id.slice(slash + 1));
475
+ const dot = id.lastIndexOf(".");
476
+ if (dot >= 0)
477
+ candidates.push(id.slice(dot + 1));
478
+ for (const candidate of candidates) {
479
+ const entry = index.get(candidate);
480
+ if (entry)
481
+ return entry;
482
+ }
483
+ return undefined;
484
+ }
package/dist/source.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { OpenCodeClient, SessionInfo } from "@opencode/client";
2
- import type { Price, UsageMessage } from "./usage.js";
2
+ import type { PriceCatalog, UsageMessage } from "./usage.js";
3
3
  export type Session = Pick<SessionInfo, "id" | "parentID" | "fork" | "model" | "location">;
4
4
  export interface Page<T> {
5
5
  data: T[];
@@ -8,10 +8,10 @@ export interface Page<T> {
8
8
  previous?: string | null;
9
9
  };
10
10
  }
11
- /** Active model of the viewed session: price tiers, display label and context window. */
11
+ /** Active model of the viewed session plus the location's current resolved price catalog. */
12
12
  export interface ActiveModel {
13
13
  label: string;
14
- prices: readonly Price[];
14
+ catalog: PriceCatalog;
15
15
  context?: number | undefined;
16
16
  }
17
17
  export interface UsageSource {
package/dist/source.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { modelKey } from "./usage.js";
1
2
  export function createSource(client) {
2
3
  return {
3
4
  session: (sessionID, signal) => client.session.get({ sessionID }, { signal }),
@@ -7,12 +8,16 @@ export function createSource(client) {
7
8
  async model(session, signal) {
8
9
  const input = { location: session.location };
9
10
  const selected = session.model;
11
+ const models = (await client.model.list(input, { signal })).data;
10
12
  const model = selected
11
- ? (await client.model.list(input, { signal })).data.find(m => m.providerID === selected.providerID && m.id === selected.id)
12
- : (await client.model.default(input, { signal })).data;
13
+ ? models.find(m => m.providerID === selected.providerID && m.id === selected.id)
14
+ : (await client.model.default(input, { signal })).data ?? undefined;
15
+ const catalog = new Map(models.map(value => [modelKey(value), value.cost]));
16
+ if (model && !catalog.has(modelKey(model)))
17
+ catalog.set(modelKey(model), model.cost);
13
18
  return {
14
19
  label: model ? `${model.providerID}/${model.id}` : selected ? `${selected.providerID}/${selected.id}` : "Default model",
15
- prices: model?.cost ?? [],
20
+ catalog,
16
21
  context: model?.limit?.context,
17
22
  };
18
23
  },
package/dist/usage.d.ts CHANGED
@@ -29,10 +29,19 @@ export interface Price {
29
29
  write?: number;
30
30
  };
31
31
  }
32
+ export interface ModelRef {
33
+ providerID: string;
34
+ id: string;
35
+ variant?: string;
36
+ }
37
+ export type PriceCatalog = ReadonlyMap<string, readonly Price[]>;
38
+ export declare const modelKey: (model: Pick<ModelRef, "providerID" | "id">) => string;
32
39
  export interface UsageMessage {
33
40
  id: string;
34
41
  type: string;
35
42
  status?: string;
43
+ model?: ModelRef;
44
+ cost?: number;
36
45
  tokens?: TokenInput;
37
46
  time?: {
38
47
  created: number;
@@ -73,12 +82,16 @@ export declare function estimate(tokens: Tokens, prices?: readonly Price[]): {
73
82
  cost: number;
74
83
  defaultPrice: boolean;
75
84
  };
76
- export declare function summarize(messages: Iterable<UsageMessage>, prices?: readonly Price[]): {
85
+ export type CostStatus = "empty" | "complete" | "partial" | "unavailable";
86
+ /** Prices every call with its recorded model. OpenCode's resolved price wins;
87
+ * the built-in manufacturer snapshot is used only when that price is incomplete. */
88
+ export declare function summarize(messages: Iterable<UsageMessage>, catalog?: PriceCatalog): {
77
89
  tokens: Tokens;
78
90
  total: number;
79
91
  cacheRate: number;
92
+ steps: number;
80
93
  cost: number;
81
- defaultPrice: boolean;
94
+ costStatus: CostStatus;
82
95
  };
83
96
  export type Summary = ReturnType<typeof summarize>;
84
97
  export interface ContextUsage {
package/dist/usage.js CHANGED
@@ -1,3 +1,5 @@
1
+ import { officialPrice } from "./pricing.js";
2
+ export const modelKey = (model) => `${model.providerID}/${model.id}`;
1
3
  const safe = (n) => n !== undefined && Number.isFinite(n) ? Math.max(0, n) : 0;
2
4
  export function normalize(tokens) {
3
5
  return {
@@ -7,24 +9,33 @@ export function normalize(tokens) {
7
9
  }
8
10
  export const incoming = (t) => t.input + t.cache.read + t.cache.write;
9
11
  export const total = (t) => incoming(t) + t.output + t.reasoning;
10
- // Matches OpenCode 2.0.9 SessionUsage.calculateCost: thresholds are exclusive.
12
+ // Matches OpenCode 2.0.11 SessionUsage.calculateCost: thresholds are exclusive.
11
13
  export function estimate(tokens, prices = []) {
12
14
  const tier = prices.filter(p => p.tier && incoming(tokens) > p.tier.size)
13
15
  .sort((a, b) => b.tier.size - a.tier.size)[0];
14
16
  const price = tier ?? prices.find(p => !p.tier);
15
17
  const rates = [price?.input, price?.output, price?.cache?.read, price?.cache?.write];
18
+ const quantities = [tokens.input, tokens.output + tokens.reasoning, tokens.cache.read, tokens.cache.write];
16
19
  return {
17
- cost: (tokens.input * safe(rates[0]) + (tokens.output + tokens.reasoning) * safe(rates[1])
18
- + tokens.cache.read * safe(rates[2]) + tokens.cache.write * safe(rates[3])) / 1_000_000,
19
- defaultPrice: rates.some(rate => rate === undefined || !Number.isFinite(rate) || rate < 0),
20
+ cost: quantities.reduce((sum, quantity, index) => sum + quantity * safe(rates[index]), 0) / 1_000_000,
21
+ defaultPrice: total(tokens) > 0 && (!price || rates.some((rate, index) => quantities[index] > 0
22
+ && (rate === undefined || !Number.isFinite(rate) || rate < 0))),
20
23
  };
21
24
  }
22
- export function summarize(messages, prices = []) {
25
+ /** Prices every call with its recorded model. OpenCode's resolved price wins;
26
+ * the built-in manufacturer snapshot is used only when that price is incomplete. */
27
+ export function summarize(messages, catalog = new Map()) {
23
28
  const tokens = normalize();
24
29
  let cost = 0;
25
- let defaultPrice = prices.length === 0;
30
+ let steps = 0;
31
+ let knownCosts = 0;
32
+ let missingCosts = 0;
26
33
  for (const message of messages) {
27
- if ((message.type !== "assistant" && message.type !== "compaction") || !message.tokens)
34
+ // Matches OpenCode SessionStats: every assistant message is one step,
35
+ // with or without reported usage; compaction and user messages are not.
36
+ if (message.type === "assistant")
37
+ steps++;
38
+ if (message.type !== "assistant" && message.type !== "compaction")
28
39
  continue;
29
40
  const t = normalize(message.tokens);
30
41
  tokens.input += t.input;
@@ -32,11 +43,29 @@ export function summarize(messages, prices = []) {
32
43
  tokens.reasoning += t.reasoning;
33
44
  tokens.cache.read += t.cache.read;
34
45
  tokens.cache.write += t.cache.write;
35
- const value = estimate(t, prices);
36
- cost += value.cost;
37
- defaultPrice ||= value.defaultPrice;
46
+ if (total(t) === 0)
47
+ continue;
48
+ if (!message.model) {
49
+ missingCosts++;
50
+ continue;
51
+ }
52
+ let value = estimate(t, catalog.get(modelKey(message.model)));
53
+ if (value.defaultPrice)
54
+ value = estimate(t, officialPrice(message.model)?.prices);
55
+ if (value.defaultPrice)
56
+ missingCosts++;
57
+ else {
58
+ cost += value.cost;
59
+ knownCosts++;
60
+ }
38
61
  }
39
- return { tokens, total: total(tokens), cacheRate: incoming(tokens) ? tokens.cache.read / incoming(tokens) : 0, cost, defaultPrice };
62
+ const costStatus = missingCosts > 0
63
+ ? knownCosts > 0 ? "partial" : "unavailable"
64
+ : knownCosts > 0 ? "complete" : "empty";
65
+ return {
66
+ tokens, total: total(tokens), cacheRate: incoming(tokens) ? tokens.cache.read / incoming(tokens) : 0,
67
+ steps, cost, costStatus,
68
+ };
40
69
  }
41
70
  const usableLimit = (value) => value !== undefined && Number.isFinite(value) && value > 0;
42
71
  // Matches the OpenCode 2.0.10 sidebar: the last assistant message with tokens that follows
@@ -73,12 +102,16 @@ export function usageRows(summary, context, performance) {
73
102
  const rows = [];
74
103
  if (context)
75
104
  rows.push(["Context", `${formatTokens(context.used)} / ${formatTokens(context.limit)} (${context.percent.toFixed(1)}%)`]);
76
- rows.push(["Input", number(t?.input)], ["Output", number(t?.output)], ["Reasoning", number(t?.reasoning)], ["Cache Read", number(t?.cache.read)]);
105
+ rows.push(["Steps", number(summary?.steps)], ["Input", number(t?.input)], ["Output", number(t?.output)], ["Reasoning", number(t?.reasoning)], ["Cache Read", number(t?.cache.read)]);
77
106
  if (t && t.cache.write > 0)
78
107
  rows.push(["Cache Write", number(t.cache.write)]);
79
108
  rows.push(["Cache Rate", summary ? `${(summary.cacheRate * 100).toFixed(1)}%` : "—"], ["Total", number(summary?.total)]);
80
- if (summary && summary.cost > 0)
109
+ if (summary?.costStatus === "complete")
81
110
  rows.push(["Cost", formatCost(summary.cost)]);
111
+ if (summary?.costStatus === "partial")
112
+ rows.push(["Cost", `${formatCost(summary.cost)} · partial`]);
113
+ if (summary?.costStatus === "unavailable")
114
+ rows.push(["Cost", "—"]);
82
115
  if (performance?.tps !== undefined && Number.isFinite(performance.tps)) {
83
116
  rows.push(["TPS", `${performance.tpsEstimated ? "~" : ""}${Math.max(0, performance.tps).toFixed(1)} tok/s`]);
84
117
  }
@@ -0,0 +1,279 @@
1
+ # 内置官方价格快照
2
+
3
+ v0.3.0 在 OpenCode 当前模型目录没有可用于某条消息的完整价格时,使用本页所列的厂商官方标准价补全。快照核验于 **2026-09-23**,共收录 71 个模型,金额均为美元 / 100 万 token。
4
+
5
+ ## 规则
6
+
7
+ - 每条 assistant 与 compaction 消息按自身记录的 `providerID`、模型 ID 和 token 用量分别计算。
8
+ - OpenCode 当前解析出的完整适用价格优先;仅当适用档位或本次实际使用的 token 类别缺价时,整条消息回退到内置价格,不混用两套费率。
9
+ - 网关模型只通过精确厂商 ID、精确别名及已知包装格式匹配,例如 `openai/gpt-5.6-luna`、`us.anthropic.claude-opus-5` 和 `claude-opus-5@default`。不按相似名称猜测。
10
+ - 目录首版只新增 2026-03-22 至 2026-09-22 发布、具有明确标准 token 价格的模型。后续版本只限制新增窗口,已经收录的模型不会因超过半年而自动删除。
11
+ - 采用标准同步 API 的公开价,不含 Batch、Flex、Fast/Priority、区域溢价、网关加价、免费额度、企业折扣、工具费和税费,因此 Cost 仍是估算,不代表账单。
12
+ - 任一有用量消息仍无法定价时,已知小计标记 `partial`;全部无法定价时显示 `—`。明确零价才显示 `$0.00`。
13
+ - 促销价按核验日官网显示的费率收录(如 `gpt-5.6-sol`、MiniMax-M3 的"长期 5 折"标价),不用划线原价。
14
+
15
+ ## OpenAI
16
+
17
+ 来源:[OpenAI API Pricing](https://developers.openai.com/api/docs/pricing)
18
+
19
+ | 模型 | 发布日期 | Input | Output | Cache Read | Cache Write | 长上下文档位 |
20
+ | --- | --- | ---: | ---: | ---: | ---: | --- |
21
+ | `gpt-5.5` | 2026-04-23 | 5 | 30 | 0.5 | — | ≥272K:10 / 45 / 1 / — |
22
+ | `gpt-5.5-pro` | 2026-04-23 | 30 | 180 | — | — | ≥272K:60 / 270 / — / — |
23
+ | `gpt-5.6-sol` | 2026-07-09 | 4 | 20 | 0.4 | 5 | ≥272K:8 / 30 / 0.8 / 10 |
24
+ | `gpt-5.6-terra` | 2026-07-09 | 2 | 12 | 0.2 | 2.5 | ≥272K:4 / 18 / 0.4 / 5 |
25
+ | `gpt-5.6-luna` | 2026-07-09 | 0.2 | 1.2 | 0.02 | 0.25 | ≥272K:0.4 / 1.8 / 0.04 / 0.5 |
26
+ | `gpt-6-astra` | 2026-09-04 | 10 | 50 | 1 | 12.5 | ≥272K:20 / 75 / 2 / 25 |
27
+ | `chat-latest`(别名 `gpt-chat-latest`) | 2026-05-05 | 5 | 30 | 0.5 | — | — |
28
+
29
+ `gpt-5.6-sol` 的当前标准价是限期促销价;快照采用核验日官网显示的费率。`chat-latest` 是官方 ChatGPT SKU,OpenRouter 上的 `gpt-chat-latest` 作为精确别名指向同一条目。
30
+
31
+ ## Anthropic
32
+
33
+ 来源:[Claude Platform Pricing](https://platform.claude.com/docs/en/about-claude/pricing)
34
+
35
+ | 模型 | 发布日期 | Input | Output | Cache Read | Cache Write |
36
+ | --- | --- | ---: | ---: | ---: | ---: |
37
+ | `claude-opus-4-7` | 2026-04-14 | 5 | 25 | 0.5 | 6.25 |
38
+ | `claude-opus-4-8` | 2026-05-28 | 5 | 25 | 0.5 | 6.25 |
39
+ | `claude-fable-5` | 2026-06-07 | 10 | 50 | 1 | 12.5 |
40
+ | `claude-sonnet-5` | 2026-06-29 | 2 | 10 | 0.2 | 2.5 |
41
+ | `claude-opus-5` | 2026-07-24 | 5 | 25 | 0.5 | 6.25 |
42
+ | `claude-fable-5-1` | 2026-09-01 | 10 | 50 | 0.25 | 12.5 |
43
+
44
+ Cache Write 采用官方 5 分钟写入价。OpenCode 的聚合字段不区分 5 分钟与 1 小时 TTL,无法从历史消息可靠应用 1 小时写入价。OpenRouter 的 `claude-opus-4.7`、`claude-opus-4.8` 圆点写法注册为对应条目的精确别名。
45
+
46
+ ## Google
47
+
48
+ 来源:[Gemini Developer API Pricing](https://ai.google.dev/gemini-api/docs/pricing)
49
+
50
+ | 模型 | 发布日期 | Input | Output(含 thinking) | Cache Read |
51
+ | --- | --- | ---: | ---: | ---: |
52
+ | `gemini-3.1-flash-lite` | 2026-05-07 | 0.25 | 1.5 | 0.025 |
53
+ | `gemini-3.5-flash` | 2026-05-19 | 1.5 | 9 | 0.15 |
54
+ | `gemini-3.5-flash-lite` | 2026-07-21 | 0.3 | 2.5 | 0.03 |
55
+ | `gemini-3.6-flash` | 2026-07-21 | 0.75 | 3.75 | 0.075 |
56
+ | `gemini-3.7-flash` | 2026-08-13 | 0.75 | 3.75 | 0.075 |
57
+ | `gemini-3.8-flash` | 2026-09-02 | 0.75 | 3.75 | 0.075 |
58
+
59
+ Gemini 3.6–3.8 Flash 的表中价格有效至 2026-12-31。上下文缓存还按存储时间收费;消息 token 统计无法表示该费用,因此目录不伪造 Cache Write 费率,遇到实际 cache write 且 OpenCode 也缺价时会标为不可用。
60
+
61
+ ## xAI
62
+
63
+ 来源:[Grok Models & Pricing](https://docs.x.ai/developers/models)
64
+
65
+ | 模型 | 发布日期 | Input | Output | Cache Read | ≥200K Input / Output / Cache Read |
66
+ | --- | --- | ---: | ---: | ---: | --- |
67
+ | `grok-build-0.1` | 2026-04-16 | 1 | 2 | 0.2 | 2 / 4 / 0.4 |
68
+ | `grok-4.3` | 2026-04-17 | 1.25 | 2.5 | 0.2 | 2.5 / 5 / 0.4 |
69
+ | `grok-4.5` | 2026-07-08 | 2 | 6 | 0.3 | 4 / 12 / 0.6 |
70
+ | `grok-4.6` | 2026-08-12 | 2 | 6 | 0.5 | 4 / 12 / 1 |
71
+ | `grok-4.7` | 2026-09-21 | 2 | 6 | 0.5 | 4 / 12 / 1 |
72
+
73
+ ## Mistral 与 Cohere
74
+
75
+ 来源:[Mistral Pricing](https://docs.mistral.ai/inference/pricing)、[Cohere Pricing](https://cohere.com/pricing)
76
+
77
+ | 模型 | 发布日期 | Input | Output | Cache Read |
78
+ | --- | --- | ---: | ---: | ---: |
79
+ | `mistral-medium-3-5-26-04` | 2026-04-29 | 1.5 | 7.5 | 0.15 |
80
+ | `command-a-plus-05-2026` | 2026-05-20 | 2.5 | 10 | — |
81
+
82
+ ## Z.ai(GLM)
83
+
84
+ 来源:[Z.AI Pricing](https://docs.z.ai/guides/overview/pricing)
85
+
86
+ | 模型 | 发布日期 | Input | Output | Cache Read |
87
+ | --- | --- | ---: | ---: | ---: |
88
+ | `glm-5.1` | 2026-04-06 | 1.4 | 4.4 | 0.26 |
89
+ | `glm-5.2` | 2026-06-16 | 1.4 | 4.4 | 0.26 |
90
+ | `glm-5.3` | 2026-08-16 | 1.4 | 4.4 | 0.26 |
91
+ | `glm-5.3-flash` | 2026-08-26 | 0.15 | 0.5 | 0.03 |
92
+ | `glm-5.3-flashx` | 2026-09-18 | 0.37 | 1.25 | 0.075 |
93
+
94
+ 官方按时间收取缓存存储费(限期免费),没有 cache write token 价,因此这些模型遇到实际 cache write 用量且 OpenCode 也缺价时标记为不可用。
95
+
96
+ ## DeepSeek
97
+
98
+ 来源:[DeepSeek Models & Pricing](https://api-docs.deepseek.com/quick_start/pricing)
99
+
100
+ | 模型 | 发布日期 | Input | Output | Cache Read |
101
+ | --- | --- | ---: | ---: | ---: |
102
+ | `deepseek-v4.1-flash` | 2026-09-10 | 0.30 | 1.20 | 0.006 |
103
+ | `deepseek-v4-pro-0813` | 2026-08-13 | 1.32 | 3.96 | 0.044 |
104
+
105
+ 表中采用官方**峰值时段最高价**作为保守估算上界;非峰值时段实际费率为表中一半。历史消息没有保留请求发生时对应的计费时段,无法准确选择峰谷档。已退役的 `deepseek-v4-flash` 与 `deepseek-v4-flash-vision-exp` 当前由官方路由到 V4.1 Flash 并按 Flash 价格计费;`deepseek-v4-flash-0731` 作为明确版本别名映射到同一条目。`deepseek-v4-pro` 当前对应 V4-Pro-0813。
106
+
107
+ ## Moonshot(Kimi)
108
+
109
+ 来源:[Kimi Model Inference Pricing](https://platform.moonshot.ai/docs/pricing)
110
+
111
+ | 模型 | 发布日期 | Input | Output | Cache Read | Cache Write |
112
+ | --- | --- | ---: | ---: | ---: | ---: |
113
+ | `kimi-k3` | 2026-07-15 | 3 | 15 | 0.30 | 3(5 分钟 TTL) |
114
+ | `kimi-k2.7-code` | 2026-06-12 | 0.95 | 4.00 | 0.19 | — |
115
+ | `kimi-k2.6` | 2026-04-20 | 0.95 | 4.00 | 0.16 | — |
116
+
117
+ K3 同时公布 5 分钟与 1 小时 cache write,快照沿用 Anthropic 约定取 5 分钟档;K2 系列只公布 cache 命中输入价,没有 cache write 价。
118
+
119
+ ## 阿里云百炼(Qwen)
120
+
121
+ 来源:[Model Studio Model inference pricing](https://www.alibabacloud.com/help/en/model-studio/model-pricing)(新加坡 International 站点标准价)
122
+
123
+ | 模型 | 发布日期 | Input | Output | Cache Read |
124
+ | --- | --- | ---: | ---: | ---: |
125
+ | `qwen3.8-max`(含别名 `qwen3.8-max-0902`) | 2026-08-03 | 2 | 6 | — |
126
+ | `qwen3.8-2.4t-a95b` | 2026-08-12 | 2 | 6 | — |
127
+ | `qwen3.8-27b` | 2026-08-14 | 0.5 | 3 | 0.1 |
128
+ | `qwen3.8-flash` | 2026-08-26 | 0.15 | 0.47 | — |
129
+ | `qwen3.7-max` | 2026-05-20 | 2.5 | 7.5 | 0.5 |
130
+ | `qwen3.7-plus` | 2026-05-26 | 0.4 / 1.2(>256K) | 1.6 / 4.8(>256K) | 0.08 / 0.24(>256K) |
131
+ | `qwen3.7-flash` | 2026-07-15 | 0.03 / 0.10 / 0.20(>32K、>256K) | 0.13 / 0.40 / 0.80(>32K、>256K) | 0.006 / 0.02 / 0.04(>32K、>256K) |
132
+ | `qwen3.6-max-preview` | 2026-04-20 | 1.3 / 2(>128K) | 7.8 / 12(>128K) | — |
133
+ | `qwen3.6-plus` | 2026-04-02 | 0.5 / 2(>256K) | 3 / 6(>256K) | — |
134
+ | `qwen3.6-flash` | 2026-04-16 | 0.25 / 1(>256K) | 1.5 / 4(>256K) | — |
135
+ | `qwen3.6-27b` | 2026-04-22 | 0.6 | 3.6 | — |
136
+ | `qwen3.6-35b-a3b` | 2026-04-15 | 0.375 | 2.25 | — |
137
+ | `qwen3.5-plus-2026-04-20`(别名 `qwen3.5-plus-20260420`) | 2026-04-20 | 0.4 / 0.5(>256K) | 2.4 / 3(>256K) | — |
138
+
139
+ 档位边界按官方措辞换算:`256K<Token≤1M` 即传入超过 256,000 token 启用高价档。Cache Read 收录官方隐式缓存命中价(所在档 Input 的 20%),仅限官方公布该费率的模型;`qwen3.8-max`、`qwen3.8-max-0902`、`qwen3.8-flash`、`qwen3.8-2.4t-a95b` 的缓存价只在控制台公布,不收录。隐式缓存创建按 Input 100% 计费、显式缓存创建按 125% 计费,聚合字段无法区分,因此一律不收 Cache Write。`qwen3.7-plus` 页面当前标注限期 8 折,快照采用未打折的刊例价。
140
+
141
+ ## 小米(MiMo)
142
+
143
+ 来源:[Xiaomi MiMo API Pricing](https://mimo.mi.com/docs/price/pay-as-you-go)(海外美元价)
144
+
145
+ | 模型 | 发布日期 | Input | Output | Cache Read |
146
+ | --- | --- | ---: | ---: | ---: |
147
+ | `mimo-v2.5` | 2026-04-22 | 0.14 | 0.28 | 0.0028 |
148
+ | `mimo-v2.5-pro` | 2026-04-22 | 0.435 | 0.87 | 0.0036 |
149
+ | `mimo-v2.6-flash` | 2026-09-21 | 0.14 | 0.28 | 0.0028 |
150
+ | `mimo-v2.6-pro` | 2026-09-21 | 0.435 | 0.87 | 0.0036 |
151
+ | `mimo-v2.6-pro-ultraspeed` | 2026-09-21 | 4.35 | 8.7 | 0.036 |
152
+
153
+ V2.6 系列官方宣布沿用 V2.5 系列 API 定价。Cache Write 官方限期免费,不设 token 价。
154
+
155
+ ## MiniMax
156
+
157
+ 来源:[MiniMax Pay as You Go](https://platform.minimax.io/docs/guides/pricing-paygo)
158
+
159
+ | 模型 | 发布日期 | Input | Output | Cache Read |
160
+ | --- | --- | ---: | ---: | ---: |
161
+ | `minimax-m3` | 2026-05-31 | 0.30 / 0.60(>512K) | 1.20 / 2.40(>512K) | 0.06 / 0.12(>512K) |
162
+
163
+ M3 页面标注"长期 5 折",快照按核验日的实收价收录;官方只公布 cache 读取价,没有 cache write 价。
164
+
165
+ ## 腾讯(混元)
166
+
167
+ 来源:[Tencent Cloud TokenHub Model pricing](https://intl.cloud.tencent.com/document/product/1300/78937)(新加坡国际站美元价)
168
+
169
+ | 模型 | 发布日期 | Input | Output | Cache Read |
170
+ | --- | --- | ---: | ---: | ---: |
171
+ | `hy3` | 2026-07-06 | 0.132 | 0.528 | 0.033 |
172
+ | `hy4-preview` | 2026-08-27 | 0.834 | 2.501 | 0.042 |
173
+
174
+ 官方页面只公布 cache 命中价,没有 cache write 价。
175
+
176
+ ## StepFun
177
+
178
+ 来源:[StepFun Pricing Details](https://platform.stepfun.ai/docs/en/guides/pricing/details)(海外站)
179
+
180
+ | 模型 | 发布日期 | Input | Output | Cache Read | Cache Write |
181
+ | --- | --- | ---: | ---: | ---: | ---: |
182
+ | `step-5-preview` | 2026-09-21 | 1 | 2.7 | 0.05 | 1 |
183
+ | `step-3.7-flash` | 2026-05-28 | 0.20 | 1.15 | 0.04 | — |
184
+
185
+ Step 5 Preview 官方明确说明 cache-miss Input 包含首次缓存写入,因此 OpenCode 单独上报的 Cache Write 按同一 `$1 / M` 费率计算。按 7:2:1 的 Cache Read / Input / Output token 比例,综合价为 `(7 × 0.05 + 2 × 1 + 1 × 2.7) / 10 = $0.505 / M`,约 `$0.51 / M`;该数值仅用于场景比较,插件仍按每条消息的实际五类 token 计算。Step 3.7 Flash 没有公布独立 cache write 价。
186
+
187
+ ## Meta(Muse Spark)
188
+
189
+ 来源:[Meta Model API Pricing and rate limits](https://ai.developer.meta.com/docs/pricing-rate-limits)
190
+
191
+ | 模型 | 发布日期 | Input | Output | Cache Read |
192
+ | --- | --- | ---: | ---: | ---: |
193
+ | `muse-spark-1.1` | 2026-07-09 | 1.25 | 4.25 | 0.15 |
194
+ | `muse-spark-1.2` | 2026-08-05 | 1.25 | 4.25 | 0.15 |
195
+ | `muse-spark-1.3` | 2026-09-02 | 1.25 | 4.25 | 0.15 |
196
+
197
+ 这里只收录 Standard tier。Contributor tier 虽然也是官方 API,但以允许 Meta 使用提示词和回答训练为条件的折扣方案,不属于标准价;官方没有 cache write token 价。
198
+
199
+ ## Inception
200
+
201
+ 来源:[Inception Models](https://www.inceptionlabs.ai/models)
202
+
203
+ | 模型 | 发布日期 | Input | Output | Cache Read |
204
+ | --- | --- | ---: | ---: | ---: |
205
+ | `mercury-2.5`(别名 `mercury-2.5-preview`) | 2026-09-08 | 0.04 | 0.15 | 0.004 |
206
+
207
+ 官网在核验日同时显示 `$0.20 / $0.75 / $0.02` 的刊例价和 80% off 的当前 API 价;快照采用当前实收的促销价,未使用 OpenRouter 自行报价。官方没有公布 cache write token 价。
208
+
209
+ ## Upstage
210
+
211
+ 来源:[Solar Pro 4 model page](https://console.upstage.ai/docs/models/solar-pro-4)
212
+
213
+ | 模型 | 发布日期 | Input | Output | Cache Read |
214
+ | --- | --- | ---: | ---: | ---: |
215
+ | `solar-pro4`(别名 `solar-pro4-260806`) | 2026-08-06 | 0.30 | 1.20 | 0.06 |
216
+
217
+ Solar Pro 4 的 90% off 活动已于 2026-09-10 结束,快照采用模型页当前标准 Console API 价;官方没有公布 cache write token 价。
218
+
219
+ ## Arcee AI
220
+
221
+ 来源:[Arcee Platform Pricing](https://docs.arcee.ai/get-started/pricing)
222
+
223
+ | 模型 | 发布日期 | Input | Output | Cache Read |
224
+ | --- | --- | ---: | ---: | ---: |
225
+ | `trinity-large-thinking` | 2026-04-01 | 0.25 | 0.80 | 0.06 |
226
+
227
+ 该条目是 Arcee 托管 API 的标准推理价;模型同时提供开源权重,但本目录只记录 API 费用。官方没有公布 cache write token 价。
228
+
229
+ ## ByteDance Seed
230
+
231
+ 来源:[BytePlus ModelArk Pricing](https://docs.byteplus.com/en/docs/ModelArk/1099320)、[Seed2.1 release](https://seed.bytedance.com/en/blog/seed2-1-officially-released-advancing-ai-productivity)
232
+
233
+ | 模型 | 发布日期 | Input | Output | Cache Read |
234
+ | --- | --- | ---: | ---: | ---: |
235
+ | `dola-seed-2-1-turbo`(别名 `seed-2-1-turbo`、`dola-seed-2-1-turbo-260628`) | 2026-06-23 | 0.50 | 2.50 | 0.10 |
236
+
237
+ 表中采用 BytePlus ModelArk 在线标准推理价。缓存存储按 token·小时另行收费,不是可由当前五类 token 统计表示的 Cache Write 单价,因此不收录。
238
+
239
+ ## Sakana Fugu
240
+
241
+ 来源:[Sakana Fugu Pricing](https://console.sakana.ai/pricing)、[Fugu Max and Fugu Ultra v2 release](https://sakana.ai/fugu-max-release)
242
+
243
+ | 模型 | 发布日期 | Input | Output | Cache Read | 长上下文档位 |
244
+ | --- | --- | ---: | ---: | ---: | --- |
245
+ | `fugu-ultra-v2.0`(别名 `fugu-ultra-v2`) | 2026-09-11 | 5 | 30 | 0.50 | >272K:10 / 45 / 1 |
246
+ | `fugu-max-v1.0`(别名 `fugu-max`) | 2026-09-11 | 2 | 6 | 0.25 | — |
247
+
248
+ Fugu Ultra 的编排 token 已包含在 API 返回的 input/output 用量中,按同一 token 价估算;web search/web fetch 等工具调用费不是五类 token,故不计入 Cost。官方没有公布 cache write token 价。
249
+
250
+ ## Aion Labs
251
+
252
+ 来源:[Aion Labs Models](https://www.aionlabs.ai/docs/models)
253
+
254
+ | 模型 | 发布日期 | Input | Output | Cache Read |
255
+ | --- | --- | ---: | ---: | ---: |
256
+ | `aion-3.0`(别名 `aion-labs/aion-3.0`) | 2026-05-05 | 3.00 | 6.00 | 0.75 |
257
+ | `aion-3.0-mini`(别名 `aion-labs/aion-3.0-mini`) | 2026-05-14 | 0.70 | 1.40 | 0.18 |
258
+
259
+ 表中是 Aion Labs 自家 API 目录公布的 per-token 价,不是 OpenRouter 网关价;官方没有公布 cache write token 价。Aion 3.0 与 3.0 Mini 是基于 GLM / DeepSeek 家族的多模型协作系统,按一次请求的输入输出 token 计费。
260
+
261
+ ## 美团(LongCat)
262
+
263
+ 来源:[LongCat API Docs — LongCat-2.0 Pricing](https://longcat.chat/platform/docs/Pricing/LongCat-2.0.html)、[LongCat-2.0 发布](https://www.meituan.com/news/NN260630164005904)
264
+
265
+ | 模型 | 发布日期 | Input | Output | Cache Read |
266
+ | --- | --- | ---: | ---: | ---: |
267
+ | `longcat-2.0` | 2026-06-30 | 0.30 | 1.20 | 0.006 |
268
+
269
+ 官方页面同时列出刊例价($0.75 / $2.95 / $0.015)与限时活动价;与 MiniMax-M3、Mercury 2.5 相同,快照按核验日实际计收的限时价收录。官方没有公布 cache write token 价,缓存存储也不同 token 计费。
270
+
271
+ ## 暂不收录
272
+
273
+ - Realtime、音频、图片、视频、embedding、按页、按分钟和按工具调用收费的模型无法仅由当前五类 token 用量准确计算。
274
+ - `grok-4.20`、`grok-4.20-multi-agent` 发布于 2026-03-09,早于目录收录窗口起点 2026-03-22。
275
+ - Fast/Priority 等加速档(`claude-opus-*-fast`、`gpt-5.6-*-pro`、`gpt-6-astra-pro`、MiniMax priority 档)不是标准同步价。
276
+ - 免费模型(Gemma 系列、`cohere/north-mini-code` 等开源或网关零价款)不设价格条目。
277
+ - 无法从厂商官方页面确认标准 token 价格的模型不猜价,包括 OpenRouter stealth/alpha 匿名模型、`z-ai/glm-5v-turbo`、`qwen3.6-plus-preview`、腾讯 `hy3-preview` 与 `hy-mt2-*`、`kwaipilot/kat-coder-pro-v2.5` 及其 Air 版本、`inclusionai/ling-3.0-*`、`bytedance-seed/seed-2.0-code` 等。这些模型目前只能查到 OpenRouter、AtlasCloud、DeepInfra 等网关或第三方报价,不能据此推断厂商标准价。
278
+ - 浮动别名(`-latest` 指针与 OpenRouter `~` 前缀条目)随底层模型漂移,不收录固定价。
279
+ - 只有询价、托管部署价或无法从厂商官方页面确认标准 token 价格的模型不猜价。
@@ -2,14 +2,14 @@
2
2
 
3
3
  ## 未发布(SDK 2.0.11)
4
4
 
5
- 验证日期:2026-09-22。环境:macOS、Node.js v22.23.2、npm 10.9.8、OpenCode v2.0.11;`@opencode/plugin`、`@opencode/client`、`@opencode/schema` 和 `@opencode/theme` 均精确锁定为 2.0.11。
5
+ 验证日期:2026-09-23。环境:macOS、Node.js v22.23.2、npm 10.9.8、OpenCode v2.0.11;`@opencode/plugin`、`@opencode/client`、`@opencode/schema` 和 `@opencode/theme` 均精确锁定为 2.0.11。
6
6
 
7
7
  ### 自动化检查
8
8
 
9
9
  | 检查 | 结果 |
10
10
  | --- | --- |
11
11
  | `npm run typecheck` | 通过 |
12
- | `npm test` | 31 项通过 |
12
+ | `npm test` | 43 项通过 |
13
13
  | `npm run build` | 通过,输出 ESM 与类型声明 |
14
14
  | `npm run test:smoke` | 通过,使用实际 `.tgz` 安装产物和真实 OpenCode 2.0.11 |
15
15
 
@@ -17,13 +17,17 @@ SDK 从 2.0.9 升级到 2.0.11 后,四个顶层 OpenCode 包及锁文件中的
17
17
 
18
18
  新增共享性能监视器测试覆盖:查看会话 A 时捕获独立会话 B 的流,切换到 B 后立即恢复实时 TPS/TTFT;生成中切走、继续接收 delta 再切回;控制器销毁重建后恢复共享流;不同会话树隔离、新子代理即时纳入,以及删除会话清理运行期状态。既有重复事件去重与完成后收敛为精确 TPS 的断言继续通过。
19
19
 
20
+ 新增 Steps 计数覆盖:`summarize` 对带与不带 `tokens` 的 assistant 消息各计一个 step、compaction 与 user 消息不计、无 summary 时显示 `—`;`uniqueMessages` 链路上分叉继承副本不重复计数(快照 2 个 step、独立分叉树 1 个 step)、compaction 不产生 step、孙会话视图与根视图同为 6 个 step;行序断言锁定 Context → Steps → Input,无 Context 时 Steps 位于面板第一行。基准行数由 6 行调整为 7 行。
21
+
22
+ v0.3.0 成本测试覆盖:assistant 与 compaction 按消息实际 `model` 和五类 token 分别计算,混合模型树各自采用对应价格,消息自带 `cost` 不参与主 Cost。当前 OpenCode 模型目录中的完整适用价格优先;适用档位或实际使用类别缺价时,整条消息回退到内置官方快照,不拼接两套费率。官方目录测试锁定 71 个 2026-03-22 至 2026-09-22 发布的模型、来源 URL、唯一 ID、OpenAI/xAI/通义千问/MiniMax/Sakana 长上下文与上下文档位边界,以及 OpenRouter、Bedrock、Vertex 等包装格式和明确别名;相似名称不得猜价。目录按 OpenCode 当前模型目录(`temp/models.json`,210 个模型)补齐主流厂商:OpenAI、Anthropic、Google、xAI、Mistral、Cohere 之外新增 Z.ai(GLM)、DeepSeek、Moonshot(Kimi)、阿里云百炼(Qwen)、小米(MiMo)、MiniMax、腾讯(混元)、StepFun、Meta、Inception、Upstage、Arcee AI、ByteDance Seed、Sakana、Aion Labs、美团(LongCat);DeepSeek V4.1 Flash 与 V4 Pro 按厂商官方峰值最高价估算,旧 Flash、Vision Exp 和日期版本通过精确别名匹配。Step 5 Preview 的缓存写入按官方“cache-miss Input 包含首次缓存写入”规则使用 `$1 / M`。OpenRouter 圆点写法 `claude-opus-4.7`/`4.8`、官方 ChatGPT SKU `chat-latest`(别名 `gpt-chat-latest`)、Mercury 2.5、Solar Pro 4、Seed 2.1 Turbo、Fugu 版本、Aion 的 `aion-labs/` 前缀与 LongCat 网关链路同样通过精确别名匹配。窗口外的 `grok-4.20`、Fast/Priority 档、图片/音频/视频、免费与无官方标准价的模型均不收录;`kwaipilot/kat-coder-pro-v2.5`、`inclusionai/ling-3.0-*` 和 `bytedance-seed/seed-2.0-code` 只有网关或第三方报价,未据此猜价。缺价显示 `Cost —`,已知小计与缺价消息并存时显示 `· partial`,明确零价显示 `$0.00`。
23
+
20
24
  ### 真实 OpenCode 集成
21
25
 
22
- 隔离 smoke 测试确认打包插件可加载;空会话隐藏无数据行;在独立会话已经开始慢速流后,同一 TUI 切换过去会立即显示 `TPS ~…` 与 TTFT,完成后变为无 `~` 的精确 TPS;既有 token、上下文与费用刷新、真实子代理全树累计、会话局部上下文及模型切换验证均继续通过。测试产物保存在 `/var/folders/rw/bmx6c8hd737brl55m0_ff_b80000gn/T/token-usage-smoke-cgsCK2`。
26
+ 隔离 smoke 测试确认打包插件可加载;空会话隐藏无数据行并显示 `Steps 0`;在独立会话已经开始慢速流后,同一 TUI 切换过去会立即显示 `TPS ~…` 与 TTFT,完成后变为无 `~` 的精确 TPS;既有 token、上下文刷新、真实子代理全树累计、会话局部上下文及模型切换验证均继续通过。Steps 在真实集成中断言为:首条 assistant 完成后 `Steps 1` 且行序位于 Context 与 Input 之间;真实子代理场景下根视图与子代理视图均为 `Steps 4`(父 3 条 + 子 1 条),而被查看会话自身仍为 1。按 OpenCode 夹具价格计算,首条调用为 `$0.00126`,四条父/子代理调用累计 `$0.00504`;根会话切换到另一价格模型后,历史消息仍按自身模型保持 `$0.00504`,Context 则从 128,000 上限同步切换到 32,000。另一个模型在 OpenCode 目录中明确为 `cost: []`,其 `gpt-5.6-luna` 调用由打包产物内置官方价格计算为 `$0.000149`,TUI 显示 `Cost <$0.01`;安装包同时断言包含 `dist/pricing.js`、类型声明与 `docs/pricing.md`。本次 smoke 使用官方 `@opencode/cli-darwin-arm64@2.0.11` 的隔离二进制(安装于 `/private/var/folders/rw/bmx6c8hd737brl55m0_ff_b80000gn/T/opencode/isolated-cli-2011`,机器默认宿主仍为 2.0.14,未放宽版本断言),测试产物保存在 `/var/folders/rw/bmx6c8hd737brl55m0_ff_b80000gn/T/token-usage-smoke-Zq62zn`。
23
27
 
24
28
  ### 验证边界
25
29
 
26
- 当前 SDK 2.0.11 与宿主 2.0.11 的组合已完整验证。验证时机器默认宿主已是 2.0.12,因此 smoke 使用校验完整性的官方 `@opencode/cli-darwin-arm64@2.0.11` 隔离二进制,没有放宽宿主版本断言。2.0.9 和 2.0.10 宿主的历史验证记录保留在下方,但升级 SDK 后未重新执行这两个旧宿主的打包矩阵。后续升级 SDK 或宿主时,仍需重新核对分叉副本、compaction 排序及 step/delta 事件语义。
30
+ 当前 SDK 2.0.11 与宿主 2.0.11 的组合已完整验证。验证时机器默认宿主已是 2.0.14,因此 smoke 使用校验完整性的官方 `@opencode/cli-darwin-arm64@2.0.11` 隔离二进制,没有放宽宿主版本断言。2.0.9 和 2.0.10 宿主的历史验证记录保留在下方,但升级 SDK 后未重新执行这两个旧宿主的打包矩阵。后续升级 SDK 或宿主时,仍需重新核对消息模型字段、模型价格结构、分叉副本、compaction 排序及 step/delta 事件语义。官方价格是 2026-09-23 的版本内快照,采用标准同步 API 公开价;DeepSeek 峰谷计费采用峰值最高价作为保守上界。网关溢价、区域价、免费额度、折扣、工具费及无法由五类 token 表示的计费不在估算内,详细范围见 `docs/pricing.md`。
27
31
 
28
32
  ## v0.2.1(TPS 与 TTFT)
29
33
 
@@ -93,7 +97,7 @@ npm 发布前检查确认无作用域名称 `opencode-token-usage` 已由其他
93
97
  - 宿主 `Ws` 还使用 `session.revert` 作为搜索上界;本版本不读取 revert 状态,回退会话的取值可能与宿主不同。
94
98
  - 分母使用被查看会话的**活动模型**,而不是产生该用量的消息自身记录的模型;会话中途切换模型后两者可能不同。
95
99
  - Cost 与上下文上限使用同一活动模型解析规则,同样不使用消息自身记录的 `model` 字段:混合模型会话的 Cost 按查看时活动模型统一重算,不等于各模型实际账单之和。真实集成只验证了单夹具模型下的价格重算,混合模型的失真未单独断言。
96
- - 不显示进度条,上下文百分比与用量同行;行值加标签约 31 字符,窄侧边栏可能换行,响应式布局留待 v0.3.0。
100
+ - 不显示进度条,上下文百分比与用量同行;行值加标签约 31 字符,窄侧边栏可能换行,响应式布局与进度条留待后续版本。
97
101
  - 夹具 `usage-test/large` 的上下文上限改为 32,000 以便观测模型切换,`usage-test/small` 保持 128,000。
98
102
 
99
103
  ## v0.1.0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chenlongapps/opencode-token-usage",
3
- "version": "0.2.4",
3
+ "version": "0.3.0",
4
4
  "description": "Session-tree token usage, live performance, context window and estimated cost for OpenCode 2",
5
5
  "keywords": [
6
6
  "opencode",
@@ -30,6 +30,7 @@
30
30
  "dist",
31
31
  "README.md",
32
32
  "ROADMAP.md",
33
+ "docs/pricing.md",
33
34
  "docs/verification.md",
34
35
  "LICENSE"
35
36
  ],