@fyeeme/pi-statusline 1.0.2 → 1.1.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/CHANGELOG.md +13 -0
- package/README.md +77 -18
- package/cost.ts +135 -0
- package/index.ts +17 -6
- package/package.json +1 -1
- package/providers/deepseek.ts +8 -0
- package/token-usage.ts +7 -2
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [1.1.0] - 2026-08-07
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- DeepSeek 结算币种感知定价(新模块 `cost.ts`):CNY 计费账户按官方 ¥ 单价重算(flash ¥1/¥2/¥0.02、pro ¥3/¥6/¥0.025 每百万 tokens),修正 pi 内置 USD 价低估约 7 倍;USD 计费账户保持 pi 内置价。
|
|
15
|
+
- balance API 自动探测账户结算币种;`/currency` 手动覆盖(auto/¥/$),切换后即时刷新注册表定价。
|
|
16
|
+
- 币种判定后即时对齐运行时注册表定价(覆盖与还原均可逆、跟随结算币种)。
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
|
|
20
|
+
- USD 计费账户启动后不再整场会话停在 CNY 价:balance 探测到币种后立即重新应用定价补丁。
|
|
21
|
+
- 会话内新增 deepseek 模型(编辑 `models.json` + reload)后再次应用定价补丁时,不再因陈旧快照 + `registerProvider` 整表替换丢弃新增模型。
|
|
22
|
+
|
|
10
23
|
## [1.0.2] - 2025-07-15
|
|
11
24
|
|
|
12
25
|
### Fixed
|
package/README.md
CHANGED
|
@@ -1,17 +1,55 @@
|
|
|
1
1
|
# pi-statusline
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/@fyeeme/pi-statusline)
|
|
4
|
+
[](LICENSE)
|
|
5
|
+
|
|
6
|
+
A rich custom status bar for [pi](https://pi.dev) that replaces the default footer. Provider-aware: shows live account balance for **DeepSeek** and rolling quota for **GLM/ZAI**, plus session tokens, cost, context window, and timing.
|
|
4
7
|
|
|
5
8
|
## Features
|
|
6
9
|
|
|
7
|
-
- **
|
|
8
|
-
- **
|
|
9
|
-
- **
|
|
10
|
+
- **Provider-aware usage** — special support for DeepSeek and GLM/ZAI (see [Provider Support](#provider-support))
|
|
11
|
+
- **Token usage**: input, output, cache read/write, total per session, with cache hit rate
|
|
12
|
+
- **Cost**: cumulative session cost with currency auto-detection (¥ for DeepSeek/CNY, $ otherwise)
|
|
10
13
|
- **Context window**: usage percentage and size
|
|
11
14
|
- **Timing**: elapsed time + tokens/sec for last response
|
|
12
|
-
- **MCP status**: connected server count and total tool count
|
|
13
15
|
- **Git branch**: current branch shown in cwd display
|
|
14
16
|
|
|
17
|
+
## Provider Support
|
|
18
|
+
|
|
19
|
+
This extension uses a provider-aware strategy: when the active model belongs to a supported provider, the status bar shows live account-level usage data fetched directly from that provider's API. Other providers fall back to session-scoped cost only.
|
|
20
|
+
|
|
21
|
+
### DeepSeek
|
|
22
|
+
|
|
23
|
+
Shows live **account balance** and **weekly token usage**.
|
|
24
|
+
|
|
25
|
+
| Segment | Example | Source |
|
|
26
|
+
|---------|---------|--------|
|
|
27
|
+
| Balance | `¥0.12/50.00` | `GET /user/balance` (cached 5 min) |
|
|
28
|
+
| Weekly tokens | `7d:1.2M` | Local session file scan (rolling 7 days) |
|
|
29
|
+
|
|
30
|
+
- Currency auto-detected as `¥` (CNY) from the balance API response
|
|
31
|
+
- Balance is fetched on startup and refreshed in the background; cached for 5 minutes
|
|
32
|
+
- Triggered when `model.provider === "deepseek"`
|
|
33
|
+
|
|
34
|
+
### GLM / ZAI
|
|
35
|
+
|
|
36
|
+
Shows **5-hour rolling quota** and **weekly quota** (or natural-week usage as fallback).
|
|
37
|
+
|
|
38
|
+
| Segment | Example | Source |
|
|
39
|
+
|---------|---------|--------|
|
|
40
|
+
| 5h quota | `Usage 42%(1h23m)` | `GET /api/monitor/usage/quota/limit` (`unit:3`) |
|
|
41
|
+
| Weekly quota | `W:35%(1.2M,3d4h)` | `quota/limit` (`unit:6`) + `model-usage` API |
|
|
42
|
+
| Natural week | `W:1.2M` | `model-usage` API (Mon 00:00 local → now) |
|
|
43
|
+
|
|
44
|
+
- **5-hour rolling window**: percentage used + countdown to reset
|
|
45
|
+
- **Weekly quota**: if the plan exposes a `unit:6` weekly limit, shows percentage, tokens, and reset countdown; otherwise falls back to real usage for the current natural week (host local timezone)
|
|
46
|
+
- **Account level**: also fetched (visible in `/status-debug`)
|
|
47
|
+
- Supports both `zai` (`api.z.ai`) and `zai-coding-cn` (`open.bigmodel.cn`) endpoints
|
|
48
|
+
|
|
49
|
+
### Other providers
|
|
50
|
+
|
|
51
|
+
Session-scoped cost only (`$0.12` or `¥0.12`), with no live account data.
|
|
52
|
+
|
|
15
53
|
## Install
|
|
16
54
|
|
|
17
55
|
Requires the [pi](https://pi.dev) CLI.
|
|
@@ -20,16 +58,16 @@ Requires the [pi](https://pi.dev) CLI.
|
|
|
20
58
|
|
|
21
59
|
```bash
|
|
22
60
|
# Global (user) install — available in every project
|
|
23
|
-
pi install
|
|
61
|
+
pi install @fyeeme/pi-statusline
|
|
24
62
|
|
|
25
63
|
# Project-local — written to .pi/settings.json, shareable with your team
|
|
26
|
-
pi install -l
|
|
64
|
+
pi install -l @fyeeme/pi-statusline
|
|
27
65
|
|
|
28
66
|
# Pinned version — skipped by `pi update`
|
|
29
|
-
pi install
|
|
67
|
+
pi install @fyeeme/pi-statusline@1.0.2
|
|
30
68
|
|
|
31
69
|
# Try it once without saving (current run only)
|
|
32
|
-
pi -e
|
|
70
|
+
pi -e @fyeeme/pi-statusline
|
|
33
71
|
```
|
|
34
72
|
|
|
35
73
|
### From GitHub
|
|
@@ -40,7 +78,7 @@ Source: [`fyeeme/pi-packages`](https://github.com/fyeeme/pi-packages).
|
|
|
40
78
|
# HTTPS shorthand
|
|
41
79
|
pi install git:github.com/fyeeme/pi-packages
|
|
42
80
|
# Pin to a tag or commit (skipped by `pi update`)
|
|
43
|
-
pi install git:github.com/fyeeme/pi-packages@v1.0.
|
|
81
|
+
pi install git:github.com/fyeeme/pi-packages@v1.0.2
|
|
44
82
|
# Raw URL form
|
|
45
83
|
pi install https://github.com/fyeeme/pi-packages
|
|
46
84
|
```
|
|
@@ -51,20 +89,41 @@ See the Pi Packages guide on [pi.dev](https://pi.dev) for the full list of sourc
|
|
|
51
89
|
|
|
52
90
|
| Command | Description |
|
|
53
91
|
|---|---|
|
|
54
|
-
| `/
|
|
55
|
-
| `/
|
|
56
|
-
| `/status-debug` | Dump session stats to `/tmp/pi-status-debug.log` |
|
|
92
|
+
| `/currency [auto\|¥\|$]` | Toggle cost currency display (`auto` follows DeepSeek → ¥) |
|
|
93
|
+
| `/status-debug` | Dump session stats + provider usage to `/tmp/pi-status-debug.log` |
|
|
57
94
|
|
|
58
95
|
## Status Bar Layout
|
|
59
96
|
|
|
60
97
|
```
|
|
61
98
|
~/projects/my-repo (main) deepseek-v3 · xhigh
|
|
62
|
-
in 12k, out 8k, cache 45k
|
|
99
|
+
tokens 65k(in 12k, out 8k, cache 45k) · ¥0.12/50.00 · 7d:1.2M · 45.2%/64k · 2m30s 38.2tok/s
|
|
63
100
|
```
|
|
64
101
|
|
|
65
|
-
Line 1
|
|
66
|
-
|
|
102
|
+
**Line 1**: cwd + git branch (left) | model + thinking level (right)
|
|
103
|
+
|
|
104
|
+
**Line 2**: token stats · provider usage · context window · timing
|
|
105
|
+
|
|
106
|
+
### GLM/ZAI example
|
|
107
|
+
|
|
108
|
+
```
|
|
109
|
+
~/projects/my-repo (main) glm-4.6 · high
|
|
110
|
+
tokens 65k(in 12k, out 8k, cache 45k) · Usage 42%(1h23m) · W:35%(1.2M,3d4h) · 45.2%/64k · 2m30s 38.2tok/s
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Environment Variables
|
|
114
|
+
|
|
115
|
+
None required. API keys are resolved automatically by pi's model registry for the active provider.
|
|
116
|
+
|
|
117
|
+
## How It Works
|
|
118
|
+
|
|
119
|
+
The extension registers a `UsageProvider` per supported provider and refreshes usage data in the background (on startup, on model switch, and after each agent run). Results are cached with a 5-minute TTL (DeepSeek) or per-refresh (ZAI) to avoid hammering the provider APIs.
|
|
120
|
+
|
|
121
|
+
All network calls are best-effort with a 5-second timeout — failures stay silent and never block the status bar.
|
|
122
|
+
|
|
123
|
+
## Changelog
|
|
124
|
+
|
|
125
|
+
See [CHANGELOG.md](CHANGELOG.md).
|
|
67
126
|
|
|
68
|
-
##
|
|
127
|
+
## License
|
|
69
128
|
|
|
70
|
-
|
|
129
|
+
MIT
|
package/cost.ts
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DeepSeek 定价修正(跟随结算币种)。
|
|
3
|
+
*
|
|
4
|
+
* 背景:pi 内置的 deepseek 定价数据(pi-ai 的 providers/data/deepseek.json)用的是官方 USD 价
|
|
5
|
+
* (flash $0.14/0.28/0.0028、pro $0.435/0.87/0.003625 每百万 tokens)。DeepSeek 账户分 CNY 与 USD
|
|
6
|
+
* 两种结算:CNY 账户按 ¥1/¥2/¥0.02、¥3/¥6/¥0.025 计费,此时 pi 记录的成本低估约 7 倍;USD 账户
|
|
7
|
+
* 按 USD 计费,pi 内置价本来就是对的。
|
|
8
|
+
*
|
|
9
|
+
* 因此所有"修正"都必须跟随结算币种:
|
|
10
|
+
* 1. `deepSeekBilledInCny()`:判定 DeepSeek 是否按 CNY 计价 —— 用户显式 `/currency` 优先;
|
|
11
|
+
* 否则按 balance API 探测到的账户币种(探测失败/未知时按 CNY,保持原行为)。
|
|
12
|
+
* 2. `deepseekMessageCostCny`:按官方 CNY 单价重算单条消息成本(仅 CNY 计价时用于兜底存量消息,
|
|
13
|
+
* 会话文件里已记录的 cost 无法追溯修正)。
|
|
14
|
+
* 3. `applyDeepSeekPricingPatch`:运行时把注册表中 deepseek 模型定价覆盖为官方 CNY 价(仅 CNY
|
|
15
|
+
* 计价时;USD 计价时还原为 pi 内置 USD 价)。内存补丁,不修改数据文件、pi 升级不丢。
|
|
16
|
+
*/
|
|
17
|
+
import type { Model, Api } from "@earendil-works/pi-ai";
|
|
18
|
+
import type { ModelRegistry } from "@earendil-works/pi-coding-agent";
|
|
19
|
+
|
|
20
|
+
export interface DeepSeekPricedUsage {
|
|
21
|
+
input: number;
|
|
22
|
+
output: number;
|
|
23
|
+
cacheRead: number;
|
|
24
|
+
cacheWrite: number;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** DeepSeek 官方 CNY 单价(元 / 百万 tokens):缓存命中输入 / 未命中输入 / 输出(见官方定价页)。 */
|
|
28
|
+
export const DEEPSEEK_CNY_PRICES: Record<string, DeepSeekPricedUsage> = {
|
|
29
|
+
"deepseek-v4-flash": { input: 1, output: 2, cacheRead: 0.02, cacheWrite: 0 },
|
|
30
|
+
"deepseek-v4-pro": { input: 3, output: 6, cacheRead: 0.025, cacheWrite: 0 },
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const PER_MILLION = 1_000_000;
|
|
34
|
+
|
|
35
|
+
// ---------------------------------------------------------------------------
|
|
36
|
+
// 结算币种状态(DeepSeek)
|
|
37
|
+
// ---------------------------------------------------------------------------
|
|
38
|
+
|
|
39
|
+
/** balance API 探测到的账户结算币种(CNY / USD / 其他)。 */
|
|
40
|
+
let detectedDeepSeekCurrency: string | null = null;
|
|
41
|
+
/** 用户显式 `/currency` 设置,覆盖自动判定。 */
|
|
42
|
+
let costCurrencyOverride: "¥" | "$" | undefined = undefined;
|
|
43
|
+
/** 首次 applyDeepSeekPricingPatch 时缓存的原始模型定义(用于 USD 计价时还原)。 */
|
|
44
|
+
let originalDeepSeekModels: Model<Api>[] | null = null;
|
|
45
|
+
|
|
46
|
+
/** 记录 balance API 探测到的 DeepSeek 账户结算币种(fetchUsage 成功后写入;null 表示未知)。 */
|
|
47
|
+
export function setDetectedDeepSeekCurrency(currency: string | null): void {
|
|
48
|
+
detectedDeepSeekCurrency = currency;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** 设置用户显式币种偏好(`/currency` 命令);undefined 恢复自动判定。 */
|
|
52
|
+
export function setCostCurrencyOverride(override: "¥" | "$" | undefined): void {
|
|
53
|
+
costCurrencyOverride = override;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** 当前用户显式币种偏好(undefined = 自动)。 */
|
|
57
|
+
export function getCostCurrencyOverride(): "¥" | "$" | undefined {
|
|
58
|
+
return costCurrencyOverride;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* DeepSeek 是否按 CNY 计价:用户显式偏好优先;否则仅当探测明确为 USD 时按 USD 计价,
|
|
63
|
+
* 其余情况(CNY 或未知)按 CNY —— 保持原有"deepseek → ¥"的默认行为。
|
|
64
|
+
*/
|
|
65
|
+
export function deepSeekBilledInCny(): boolean {
|
|
66
|
+
if (costCurrencyOverride === "$") return false;
|
|
67
|
+
if (costCurrencyOverride === "¥") return true;
|
|
68
|
+
return detectedDeepSeekCurrency !== "USD";
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** 重置币种状态与补丁缓存(测试用)。 */
|
|
72
|
+
export function resetDeepSeekPricingState(): void {
|
|
73
|
+
detectedDeepSeekCurrency = null;
|
|
74
|
+
costCurrencyOverride = undefined;
|
|
75
|
+
originalDeepSeekModels = null;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// ---------------------------------------------------------------------------
|
|
79
|
+
// 单条消息成本重算
|
|
80
|
+
// ---------------------------------------------------------------------------
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* 按官方 CNY 单价重算单条消息成本;模型不在定价表内返回 null(调用方回退 `m.usage.cost`)。
|
|
84
|
+
*
|
|
85
|
+
* @param model 消息模型 id(如 `deepseek-v4-flash`)
|
|
86
|
+
* @param usage 消息的 token 用量分解
|
|
87
|
+
*/
|
|
88
|
+
export function deepseekMessageCostCny(
|
|
89
|
+
model: string | undefined,
|
|
90
|
+
usage: DeepSeekPricedUsage,
|
|
91
|
+
): number | null {
|
|
92
|
+
if (!model) return null;
|
|
93
|
+
const p = DEEPSEEK_CNY_PRICES[model];
|
|
94
|
+
if (!p) return null;
|
|
95
|
+
return (
|
|
96
|
+
(p.input * usage.input +
|
|
97
|
+
p.output * usage.output +
|
|
98
|
+
p.cacheRead * usage.cacheRead +
|
|
99
|
+
p.cacheWrite * usage.cacheWrite) /
|
|
100
|
+
PER_MILLION
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// ---------------------------------------------------------------------------
|
|
105
|
+
// 运行时注册表补丁(根治 pi 内置定价,可逆、跟随结算币种)
|
|
106
|
+
// ---------------------------------------------------------------------------
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* 把注册表中 deepseek 模型的定价与结算币种对齐:
|
|
110
|
+
* - CNY 计价:cost 覆盖为官方 CNY 价;
|
|
111
|
+
* - USD 计价:还原为 pi 内置 USD 价(首次调用时缓存原始定义,之后不再被 CNY 覆盖)。
|
|
112
|
+
* 未知/未来新增模型原样保留;重复调用幂等;注册表未加载模型时静默跳过(由调用方后续重试)。
|
|
113
|
+
*/
|
|
114
|
+
export function applyDeepSeekPricingPatch(registry: ModelRegistry): void {
|
|
115
|
+
const dsModels = registry.getAll().filter((m) => m.provider === "deepseek");
|
|
116
|
+
if (dsModels.length === 0) return;
|
|
117
|
+
if (!originalDeepSeekModels) {
|
|
118
|
+
originalDeepSeekModels = dsModels;
|
|
119
|
+
} else {
|
|
120
|
+
// Merge in deepseek models added after the first snapshot, so a later
|
|
121
|
+
// re-patch(币种切换 / model_select / 探测后纠正)不会丢掉它们:registerProvider
|
|
122
|
+
// 是整表替换,用陈旧快照 map 会把新增模型从 registry 里静默删掉。
|
|
123
|
+
const known = new Set(originalDeepSeekModels.map((m) => m.id));
|
|
124
|
+
for (const m of dsModels) if (!known.has(m.id)) originalDeepSeekModels.push(m);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const billedInCny = deepSeekBilledInCny();
|
|
128
|
+
const models = originalDeepSeekModels.map((m) => {
|
|
129
|
+
if (!billedInCny) return m;
|
|
130
|
+
const cny = DEEPSEEK_CNY_PRICES[m.id];
|
|
131
|
+
if (!cny) return m;
|
|
132
|
+
return { ...m, cost: { ...m.cost, ...cny } };
|
|
133
|
+
});
|
|
134
|
+
registry.registerProvider("deepseek", { models });
|
|
135
|
+
}
|
package/index.ts
CHANGED
|
@@ -22,6 +22,11 @@ import { DeepSeekUsageProvider } from "./providers/deepseek.ts";
|
|
|
22
22
|
import { ZaiUsageProvider } from "./providers/zai.ts";
|
|
23
23
|
import type { UsageProvider } from "./providers/types.ts";
|
|
24
24
|
import { SessionTokenUsageCalculator } from "./token-usage.ts";
|
|
25
|
+
import {
|
|
26
|
+
applyDeepSeekPricingPatch,
|
|
27
|
+
setCostCurrencyOverride,
|
|
28
|
+
getCostCurrencyOverride,
|
|
29
|
+
} from "./cost.ts";
|
|
25
30
|
import { refreshUsage, getCachedUsage, getUsageCacheAge } from "./cache.ts";
|
|
26
31
|
import { formatCwd, buildStatLine, buildInfoLine } from "./footer.ts";
|
|
27
32
|
|
|
@@ -45,9 +50,8 @@ let lastModel: ExtensionContext["model"] = undefined;
|
|
|
45
50
|
let agentRunning = false;
|
|
46
51
|
let lastElapsedSec = 0;
|
|
47
52
|
let lastTps = 0;
|
|
48
|
-
let currencyOverride: "¥" | "$" | undefined = undefined;
|
|
49
53
|
|
|
50
|
-
const tokenCalculator = new SessionTokenUsageCalculator(() =>
|
|
54
|
+
const tokenCalculator = new SessionTokenUsageCalculator(() => getCostCurrencyOverride());
|
|
51
55
|
|
|
52
56
|
// ---------------------------------------------------------------------------
|
|
53
57
|
// Helpers
|
|
@@ -158,17 +162,20 @@ export default function (pi: ExtensionAPI) {
|
|
|
158
162
|
handler: async (args, ctx) => {
|
|
159
163
|
const a = args.trim().toLowerCase();
|
|
160
164
|
if (a === "auto" || a === "") {
|
|
161
|
-
|
|
162
|
-
ctx.ui.notify("Currency: auto (deepseek→¥)", "info");
|
|
165
|
+
setCostCurrencyOverride(undefined);
|
|
166
|
+
ctx.ui.notify("Currency: auto (deepseek→¥ or balance currency)", "info");
|
|
163
167
|
} else if (a === "¥" || a === "rmb" || a === "cny") {
|
|
164
|
-
|
|
168
|
+
setCostCurrencyOverride("¥");
|
|
165
169
|
ctx.ui.notify("Currency: ¥", "info");
|
|
166
170
|
} else if (a === "$" || a === "usd") {
|
|
167
|
-
|
|
171
|
+
setCostCurrencyOverride("$");
|
|
168
172
|
ctx.ui.notify("Currency: $", "info");
|
|
169
173
|
} else {
|
|
170
174
|
ctx.ui.notify("Usage: /currency [auto|¥|$]", "warning");
|
|
175
|
+
return;
|
|
171
176
|
}
|
|
177
|
+
// 币种变更后立即对齐注册表定价(CNY→覆盖为官方价;USD→还原 pi 内置价)
|
|
178
|
+
applyDeepSeekPricingPatch(ctx.modelRegistry);
|
|
172
179
|
},
|
|
173
180
|
});
|
|
174
181
|
|
|
@@ -176,6 +183,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
176
183
|
pi.on("model_select", (event) => {
|
|
177
184
|
if (lastCtx) {
|
|
178
185
|
lastModel = event.model;
|
|
186
|
+
applyDeepSeekPricingPatch(lastCtx.modelRegistry);
|
|
179
187
|
void refreshUsage(providers, lastCtx.modelRegistry, event.model);
|
|
180
188
|
}
|
|
181
189
|
});
|
|
@@ -188,6 +196,9 @@ export default function (pi: ExtensionAPI) {
|
|
|
188
196
|
lastElapsedSec = 0;
|
|
189
197
|
lastTps = 0;
|
|
190
198
|
|
|
199
|
+
// 根治:运行时修正 deepseek 定价(pi 内置定价低估约 7 倍),使后续 usage.cost 记录全局正确
|
|
200
|
+
applyDeepSeekPricingPatch(ctx.modelRegistry);
|
|
201
|
+
|
|
191
202
|
// Prime usage cache on startup (non-blocking)
|
|
192
203
|
lastCtx = ctx;
|
|
193
204
|
lastModel = ctx.model;
|
package/package.json
CHANGED
package/providers/deepseek.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
2
2
|
import type { DeepSeekResult, ProviderUsageResult } from "../types.ts";
|
|
3
3
|
import type { UsageProvider } from "./types.ts";
|
|
4
|
+
import { applyDeepSeekPricingPatch, setDetectedDeepSeekCurrency } from "../cost.ts";
|
|
4
5
|
import { scanWeeklyTokens } from "../session-scanner.ts";
|
|
5
6
|
import { fmt } from "../footer.ts";
|
|
6
7
|
|
|
@@ -39,6 +40,13 @@ export class DeepSeekUsageProvider implements UsageProvider {
|
|
|
39
40
|
const info = data.balance_infos?.[0];
|
|
40
41
|
if (!info) return null;
|
|
41
42
|
|
|
43
|
+
// 记录账户结算币种:CNY 账户按官方 ¥ 价计费;USD 账户保持 pi 内置 USD 价(不覆盖)
|
|
44
|
+
setDetectedDeepSeekCurrency(info.currency ?? null);
|
|
45
|
+
// 探测到币种后立即重新对齐注册表定价:session_start 时(detectedDeepSeekCurrency 尚为
|
|
46
|
+
// null)已按默认 CNY 覆盖过一次;此处按真实币种纠正,避免 USD 账户停在被高估约 7 倍的
|
|
47
|
+
// CNY 价上,直到下一次 model_select//currency 才修正。
|
|
48
|
+
applyDeepSeekPricingPatch(modelRegistry);
|
|
49
|
+
|
|
42
50
|
const weeklyTokens = scanWeeklyTokens("deepseek");
|
|
43
51
|
|
|
44
52
|
return {
|
package/token-usage.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { AssistantMessage } from "@earendil-works/pi-ai";
|
|
2
2
|
import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
3
3
|
import type { TokenUsage, TokenUsageCalculator } from "./types.ts";
|
|
4
|
+
import { deepSeekBilledInCny, deepseekMessageCostCny } from "./cost.ts";
|
|
4
5
|
|
|
5
6
|
export class SessionTokenUsageCalculator implements TokenUsageCalculator {
|
|
6
7
|
private getCurrencyOverride: () => "\u00a5" | "$" | undefined;
|
|
@@ -17,6 +18,8 @@ export class SessionTokenUsageCalculator implements TokenUsageCalculator {
|
|
|
17
18
|
let total = 0;
|
|
18
19
|
let cost = 0;
|
|
19
20
|
|
|
21
|
+
const billedInCny = deepSeekBilledInCny();
|
|
22
|
+
|
|
20
23
|
for (const entry of ctx.sessionManager.getEntries()) {
|
|
21
24
|
if (entry.type === "message" && entry.message.role === "assistant") {
|
|
22
25
|
const m = entry.message as AssistantMessage;
|
|
@@ -25,7 +28,9 @@ export class SessionTokenUsageCalculator implements TokenUsageCalculator {
|
|
|
25
28
|
cacheRead += m.usage.cacheRead;
|
|
26
29
|
cacheWrite += m.usage.cacheWrite;
|
|
27
30
|
total += m.usage.totalTokens;
|
|
28
|
-
|
|
31
|
+
// DeepSeek 仅按 CNY 计价时重算(pi 内置 USD 价低估约 7 倍);USD 结算用户沿用 pi 记录的 cost
|
|
32
|
+
const dsCost = billedInCny ? deepseekMessageCostCny(m.model, m.usage) : null;
|
|
33
|
+
cost += dsCost !== null ? dsCost : (m.usage.cost?.total ?? 0);
|
|
29
34
|
}
|
|
30
35
|
}
|
|
31
36
|
|
|
@@ -37,7 +42,7 @@ export class SessionTokenUsageCalculator implements TokenUsageCalculator {
|
|
|
37
42
|
currency = override;
|
|
38
43
|
} else {
|
|
39
44
|
const p = ctx.model?.provider ?? "";
|
|
40
|
-
if (p.toLowerCase().includes("deepseek")) currency = "\u00a5";
|
|
45
|
+
if (p.toLowerCase().includes("deepseek")) currency = deepSeekBilledInCny() ? "\u00a5" : "$";
|
|
41
46
|
}
|
|
42
47
|
|
|
43
48
|
return { input, output, cacheRead, cacheWrite, total, hitRate, cost, currency };
|