@bacnh85/pi-sub 0.1.18 → 0.1.21
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 +8 -0
- package/extensions/index.ts +48 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -61,6 +61,14 @@ The built-in `zai-coding-cn` provider targets the domestic BigModel endpoint (`o
|
|
|
61
61
|
(Z.ai (CN) key#1a2b3c4d) R:55%/2H W:80%/3D 42 tok/s
|
|
62
62
|
```
|
|
63
63
|
|
|
64
|
+
### 9router
|
|
65
|
+
|
|
66
|
+
9router is a proxy/router with no upstream usage API, so the footer shows the configured endpoint and last response speed:
|
|
67
|
+
|
|
68
|
+
```text
|
|
69
|
+
9router (172.30.55.22:20128) 145 tok/s
|
|
70
|
+
```
|
|
71
|
+
|
|
64
72
|
### Tokens per second
|
|
65
73
|
|
|
66
74
|
`pi-sub` tracks each response's tokens-per-second (tok/s) speed by measuring the time from provider request to message completion against the response's output token count. The last response's speed is shown in the footer next to usage data. The `/sub` detail view shows both the last response speed and the session-wide average.
|
package/extensions/index.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { readStoredCredential, type ExtensionAPI, type ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
2
2
|
import { createHash } from "node:crypto";
|
|
3
|
+
import fs from "node:fs";
|
|
3
4
|
import os from "node:os";
|
|
4
5
|
import path from "node:path";
|
|
5
6
|
|
|
@@ -15,6 +16,8 @@ const ZAI_PROVIDER = "zai";
|
|
|
15
16
|
const ZAI_USAGE_URL = "https://api.z.ai/api/monitor/usage/quota/limit";
|
|
16
17
|
const ZAI_CODING_CN_PROVIDER = "zai-coding-cn";
|
|
17
18
|
const ZAI_CODING_CN_USAGE_URL = "https://open.bigmodel.cn/api/monitor/usage/quota/limit";
|
|
19
|
+
const NINE_ROUTER_PROVIDER = "9router";
|
|
20
|
+
const NINE_ROUTER_CONFIG_PATH = path.join(os.homedir(), ".pi", "agent", "9router-config.json");
|
|
18
21
|
|
|
19
22
|
type ModelLike = { provider?: string; id?: string } | undefined;
|
|
20
23
|
|
|
@@ -110,6 +113,10 @@ function isZaiCodingCnModel(model: ModelLike): boolean {
|
|
|
110
113
|
return (model?.provider?.toLowerCase() ?? "") === ZAI_CODING_CN_PROVIDER;
|
|
111
114
|
}
|
|
112
115
|
|
|
116
|
+
function isNineRouterModel(model: ModelLike): boolean {
|
|
117
|
+
return (model?.provider?.toLowerCase() ?? "") === NINE_ROUTER_PROVIDER;
|
|
118
|
+
}
|
|
119
|
+
|
|
113
120
|
function piAuthPath(): string {
|
|
114
121
|
const configDir = process.env.PI_CODING_AGENT_DIR?.trim() || path.join(os.homedir(), ".pi", "agent");
|
|
115
122
|
return path.join(configDir, "auth.json");
|
|
@@ -294,6 +301,21 @@ async function readZaiAuth(providerId: string, label: string): Promise<{ key: st
|
|
|
294
301
|
return { key: entry.key, account: authAccountSnapshot(label, entry) };
|
|
295
302
|
}
|
|
296
303
|
|
|
304
|
+
// ponytail: duplicated from pi-9router — no shared config lib, 8 lines, acceptable
|
|
305
|
+
function readNineRouterConfig(): { baseUrl: string; apiKey?: string } | null {
|
|
306
|
+
try {
|
|
307
|
+
const exists = (p: string) => { try { return fs.statSync(p).isFile(); } catch { return false; } };
|
|
308
|
+
if (!exists(NINE_ROUTER_CONFIG_PATH)) return null;
|
|
309
|
+
const data = JSON.parse(fs.readFileSync(NINE_ROUTER_CONFIG_PATH, "utf8")) as Record<string, unknown>;
|
|
310
|
+
const baseUrl = process.env.NINE_ROUTER_BASE_URL || (typeof data.baseUrl === "string" ? data.baseUrl : undefined);
|
|
311
|
+
const apiKey = process.env.NINE_ROUTER_API_KEY || (typeof data.apiKey === "string" ? data.apiKey : undefined);
|
|
312
|
+
if (!baseUrl || typeof baseUrl !== "string") return null;
|
|
313
|
+
return { baseUrl, apiKey };
|
|
314
|
+
} catch {
|
|
315
|
+
return null;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
297
319
|
async function fetchUsageFromPiAuth(entry: PiAuthEntry, signal?: AbortSignal): Promise<UsageApiSnapshot | undefined> {
|
|
298
320
|
const accountId = getCodexAccountId(entry) ?? entry.accountId;
|
|
299
321
|
if (!accountId) throw new Error("Missing openai-codex OAuth entry in Pi auth");
|
|
@@ -364,6 +386,31 @@ async function fetchOpenCodeGoUsage(_signal?: AbortSignal): Promise<Subscription
|
|
|
364
386
|
}
|
|
365
387
|
}
|
|
366
388
|
|
|
389
|
+
async function fetchNineRouterUsage(_signal?: AbortSignal): Promise<SubscriptionUsageSnapshot> {
|
|
390
|
+
const cfg = readNineRouterConfig();
|
|
391
|
+
const now = Date.now();
|
|
392
|
+
if (!cfg) {
|
|
393
|
+
return {
|
|
394
|
+
providerDisplayName: "9router",
|
|
395
|
+
accounts: [],
|
|
396
|
+
fetchedAt: now,
|
|
397
|
+
error: "9router not configured — run /login-9router",
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
const account: SubscriptionAccountSnapshot = {
|
|
401
|
+
id: cfg.baseUrl,
|
|
402
|
+
isActive: true,
|
|
403
|
+
accountLabel: cfg.baseUrl.replace(/^https?:\/\//, ""),
|
|
404
|
+
lastActivity: "Now",
|
|
405
|
+
};
|
|
406
|
+
return {
|
|
407
|
+
providerDisplayName: "9router",
|
|
408
|
+
accounts: [account],
|
|
409
|
+
activeAccount: account,
|
|
410
|
+
fetchedAt: now,
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
|
|
367
414
|
// ---------------------------------------------------------------------------
|
|
368
415
|
// Z.ai adapter
|
|
369
416
|
// ---------------------------------------------------------------------------
|
|
@@ -552,6 +599,7 @@ function supportedAdapter(model: ModelLike): SubscriptionProviderAdapter | undef
|
|
|
552
599
|
if (isOpenCodeGoModel(model)) return { id: OPC_PROVIDER, displayName: "OpenCode Go", fetchUsage: fetchOpenCodeGoUsage };
|
|
553
600
|
if (isZaiModel(model)) return { id: ZAI_PROVIDER, displayName: "Z.ai", ...zaiUsageAdapter(ZAI_PROVIDER, ZAI_USAGE_URL, "Z.ai") };
|
|
554
601
|
if (isZaiCodingCnModel(model)) return { id: ZAI_CODING_CN_PROVIDER, displayName: "Z.ai (CN)", ...zaiUsageAdapter(ZAI_CODING_CN_PROVIDER, ZAI_CODING_CN_USAGE_URL, "Z.ai (CN)") };
|
|
602
|
+
if (isNineRouterModel(model)) return { id: NINE_ROUTER_PROVIDER, displayName: "9router", fetchUsage: fetchNineRouterUsage };
|
|
555
603
|
return undefined;
|
|
556
604
|
}
|
|
557
605
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bacnh85/pi-sub",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.21",
|
|
4
4
|
"description": "Pi extension showing subscription usage for supported model providers.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -38,6 +38,6 @@
|
|
|
38
38
|
"node": ">=20.3.0"
|
|
39
39
|
},
|
|
40
40
|
"peerDependencies": {
|
|
41
|
-
"@earendil-works/pi-coding-agent": ">=0.80.8 <0.
|
|
41
|
+
"@earendil-works/pi-coding-agent": ">=0.80.8 <0.83.0"
|
|
42
42
|
}
|
|
43
43
|
}
|