@bacnh85/pi-sub 0.1.35 → 0.1.36

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 CHANGED
@@ -1,5 +1,23 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.36 (2026-09-07)
4
+
5
+ ### Fixed
6
+
7
+ - **Removed the incorrect dead `tok-per-sec` module** (added in 0.1.35, never
8
+ wired in): its `withThinking` formula summed `reasoning` on top of `output`,
9
+ but Pi's `usage.output` already includes reasoning tokens (`reasoning` is a
10
+ subset), which would have inflated thinking-mode tok/s up to ~2×. The live
11
+ footer/footer tok/s math (`output / elapsed`) was and remains correct in both
12
+ thinking and normal mode.
13
+
14
+ ### Added
15
+
16
+ - **`/sub` thinking/answer split** — when the model reasoned, the details line
17
+ now reads e.g. `Last response: 46 tok/s (36 think + 10 answer)` instead of a
18
+ bare total, using the correct subset math (`answer = output − reasoning`).
19
+ Footer keeps the single total number.
20
+
3
21
  ## 0.1.35 (2026-09-05)
4
22
 
5
23
  ### Added
@@ -127,6 +127,7 @@ interface State {
127
127
  debounceTimer?: NodeJS.Timeout;
128
128
  responseStartTime?: number;
129
129
  lastTokPerSec?: number;
130
+ lastTokPerSecLabel?: string;
130
131
  cumulativeOutput: number;
131
132
  cumulativeDurationMs: number;
132
133
  cumulativeCost: number;
@@ -462,6 +463,9 @@ if (process.env.PI_SUB_SELF_CHECK === "1") {
462
463
  assert(p.personalWeekly?.remaining === 90, "personal weekly 90");
463
464
  assert(p.session?.remaining === 47, "session 47");
464
465
  assert(p.providerWeekly?.remaining === 28, "provider weekly 28");
466
+ // tok/s split label: usage.reasoning ⊂ usage.output, never summed.
467
+ assert(tokPerSecLabel(3200, 2500, 70_000) === "46 tok/s (36 think + 10 answer)", "tok/s split label");
468
+ assert(tokPerSecLabel(200, 0, 10_000) === "20 tok/s", "tok/s plain label");
465
469
  assert(p.personalDaily?.resetLabel?.includes("15h") === true, "daily reset label");
466
470
  const disabled = parseOmniUsageText("Usage command is disabled for this API key.");
467
471
  assert(Object.keys(disabled).length === 0, "disabled text parses empty");
@@ -1193,11 +1197,21 @@ function pad(value: string, width: number): string {
1193
1197
  return value.length >= width ? value : value + " ".repeat(width - value.length);
1194
1198
  }
1195
1199
 
1200
+ /** "46 tok/s (36 think + 10 answer)" — split shown only when the model
1201
+ * reasoned. usage.reasoning is a subset of usage.output (Pi SDK contract),
1202
+ * so answer speed = (output − reasoning)/s, never output + reasoning. */
1203
+ function tokPerSecLabel(output: number, thinking: number, elapsedMs: number): string {
1204
+ const total = Math.round(output / (elapsedMs / 1000));
1205
+ if (thinking <= 0) return `${total} tok/s`;
1206
+ const secs = elapsedMs / 1000;
1207
+ return `${total} tok/s (${Math.round(thinking / secs)} think + ${Math.round((output - thinking) / secs)} answer)`;
1208
+ }
1209
+
1196
1210
  function buildDetails(snapshot: SubscriptionUsageSnapshot | undefined, state: State): string {
1197
1211
  if (!state.adapter) {
1198
1212
  const header = `Provider: ${state.model?.provider ?? "unknown"}${state.model?.id ? ` · Model: ${state.model.id}` : ""}`;
1199
1213
  if (state.lastTokPerSec === undefined) return `${header}\nSubscription tracking inactive for this provider.`;
1200
- const tokPerSecLine = `Last response: ${state.lastTokPerSec} tok/s` +
1214
+ const tokPerSecLine = `Last response: ${state.lastTokPerSecLabel}` +
1201
1215
  (state.cumulativeDurationMs > 0
1202
1216
  ? ` · Session avg: ${Math.round(state.cumulativeOutput / (state.cumulativeDurationMs / 1000))} tok/s`
1203
1217
  : "");
@@ -1240,7 +1254,7 @@ function buildDetails(snapshot: SubscriptionUsageSnapshot | undefined, state: St
1240
1254
 
1241
1255
  const costLine = state.cumulativeCost > 0 ? `\nSession cost: $${state.cumulativeCost.toFixed(2)}` : "";
1242
1256
  const tokPerSecLine = state.lastTokPerSec !== undefined
1243
- ? `\nLast response: ${state.lastTokPerSec} tok/s` +
1257
+ ? `\nLast response: ${state.lastTokPerSecLabel}` +
1244
1258
  (state.cumulativeDurationMs > 0
1245
1259
  ? ` · Session avg: ${Math.round(state.cumulativeOutput / (state.cumulativeDurationMs / 1000))} tok/s`
1246
1260
  : "")
@@ -1277,11 +1291,15 @@ export default function (pi: ExtensionAPI) {
1277
1291
  if (event.message.role === "assistant") {
1278
1292
  state.cumulativeCost += (event.message.usage as any)?.cost?.total ?? 0;
1279
1293
  if (state.responseStartTime) {
1294
+ // usage.output already includes reasoning tokens (Pi SDK contract) —
1295
+ // this is total tok/s in both thinking and normal mode.
1280
1296
  const output = (event.message.usage as any)?.output ?? 0;
1297
+ const reasoning = (event.message.usage as any)?.reasoning ?? 0;
1281
1298
  const elapsed = Date.now() - state.responseStartTime;
1282
1299
  state.responseStartTime = undefined;
1283
1300
  if (elapsed > 0 && output > 0) {
1284
1301
  state.lastTokPerSec = Math.round(output / (elapsed / 1000));
1302
+ state.lastTokPerSecLabel = tokPerSecLabel(output, reasoning, elapsed);
1285
1303
  state.cumulativeOutput += output;
1286
1304
  state.cumulativeDurationMs += elapsed;
1287
1305
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bacnh85/pi-sub",
3
- "version": "0.1.35",
3
+ "version": "0.1.36",
4
4
  "description": "Pi extension showing subscription usage for supported model providers.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -42,6 +42,5 @@
42
42
  "@earendil-works/pi-coding-agent": ">=0.80.8 <0.86.0"
43
43
  },
44
44
  "devDependencies": {
45
- "@earendil-works/pi-server": "^0.85.1"
46
45
  }
47
46
  }