@aliou/pi-neuralwatt 0.10.2 → 0.10.4

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.
@@ -6,7 +6,40 @@ import { NEURALWATT_MODELS } from "./public-models";
6
6
  // Hidden aliases that work for authorized accounts but are omitted from the
7
7
  // authenticated /v1/models response. Keep these gated by includeHiddenModels.
8
8
  // Move an entry to public-models.ts once Neuralwatt advertises it publicly.
9
- export const HIDDEN_NEURALWATT_MODELS: ProviderModelConfig[] = [];
9
+ export const HIDDEN_NEURALWATT_MODELS: ProviderModelConfig[] = [
10
+ // DeepSeek V4 Flash Canary - early-access 284B/13B-active MoE served on B200s.
11
+ // Neuralwatt omits it from the authenticated catalog. Context and runtime
12
+ // capabilities were verified directly; pricing follows DeepSeek's upstream
13
+ // rates until Neuralwatt publishes model metadata.
14
+ {
15
+ id: "deepseek-v4-flash",
16
+ name: "DeepSeek V4 Flash (Canary)",
17
+ reasoning: true,
18
+ input: ["text", "image"],
19
+ cost: {
20
+ input: 0.14,
21
+ output: 0.28,
22
+ cacheRead: 0.0028,
23
+ cacheWrite: 0,
24
+ },
25
+ contextWindow: 1_000_000,
26
+ maxTokens: 384_000,
27
+ thinkingLevelMap: {
28
+ off: "none",
29
+ minimal: "low",
30
+ low: "low",
31
+ medium: "medium",
32
+ high: "high",
33
+ xhigh: null,
34
+ max: "max",
35
+ },
36
+ compat: {
37
+ supportsDeveloperRole: false,
38
+ maxTokensField: "max_tokens",
39
+ requiresReasoningContentOnAssistantMessages: true,
40
+ },
41
+ },
42
+ ];
10
43
 
11
44
  // Per-ID overrides for known hidden models. The authenticated /v1/models endpoint
12
45
  // exposes pricing and capabilities, but some Pi-specific behavior (thinking levels,
@@ -3,6 +3,25 @@ import type { ProviderModelConfig } from "@earendil-works/pi-coding-agent";
3
3
  // Public models returned by https://api.neuralwatt.com/v1/models (unauthenticated view).
4
4
  // Pricing, capabilities, and limits are sourced from the API metadata fields.
5
5
  export const NEURALWATT_MODELS: ProviderModelConfig[] = [
6
+ // Gemma 4 31B - NVIDIA NVFP4 checkpoint
7
+ {
8
+ id: "nvidia/Gemma-4-31B-IT-NVFP4",
9
+ name: "Gemma 4 31B (NVFP4)",
10
+ reasoning: false,
11
+ input: ["text", "image"],
12
+ cost: {
13
+ input: 0.144,
14
+ output: 0.42,
15
+ cacheRead: 0.036,
16
+ cacheWrite: 0,
17
+ },
18
+ contextWindow: 262128,
19
+ maxTokens: 16384,
20
+ compat: {
21
+ supportsDeveloperRole: false,
22
+ maxTokensField: "max_tokens",
23
+ },
24
+ },
6
25
  // Gemma 4 31B - Google, served from NVIDIA's NVFP4 checkpoint
7
26
  {
8
27
  id: "gemma-4-31b",
@@ -86,7 +105,7 @@ export const NEURALWATT_MODELS: ProviderModelConfig[] = [
86
105
  cacheWrite: 0,
87
106
  },
88
107
  contextWindow: 199984,
89
- maxTokens: 65536,
108
+ maxTokens: 32000,
90
109
  thinkingLevelMap: {
91
110
  off: "none",
92
111
  minimal: null,
@@ -115,7 +134,7 @@ export const NEURALWATT_MODELS: ProviderModelConfig[] = [
115
134
  cacheWrite: 0,
116
135
  },
117
136
  contextWindow: 199984,
118
- maxTokens: 65536,
137
+ maxTokens: 32000,
119
138
  compat: {
120
139
  supportsDeveloperRole: false,
121
140
  maxTokensField: "max_tokens",
@@ -5,6 +5,13 @@ import { formatKwh, formatUsd } from "../../src/utils/quota-format";
5
5
  export type WarningSeverity = "warning" | "critical";
6
6
 
7
7
  const COOLDOWN_MS = 60 * 60 * 1000; // 60 minutes
8
+ const LOW_PCT = 25;
9
+ const CRITICAL_PCT = 10;
10
+
11
+ /** Per-kWh price once a subscription's included kWh are exhausted. */
12
+ const OVERAGE_RATE_PER_KWH_SUBSCRIBED = 5;
13
+ /** Per-kWh price when there is no active subscription (no included kWh). */
14
+ const OVERAGE_RATE_PER_KWH_UNSUBSCRIBED = 10;
8
15
 
9
16
  interface AlertState {
10
17
  lastSeverity: WarningSeverity;
@@ -19,14 +26,16 @@ export function clearAlertState(): void {
19
26
  alerts.clear();
20
27
  }
21
28
 
29
+ function severityForPct(pct: number): WarningSeverity {
30
+ return pct <= CRITICAL_PCT ? "critical" : "warning";
31
+ }
32
+
22
33
  function shouldNotify(key: string, severity: WarningSeverity): boolean {
23
34
  const state = alerts.get(key);
24
35
  if (!state) return true;
25
36
 
26
37
  const order: WarningSeverity[] = ["warning", "critical"];
27
- const currentIndex = order.indexOf(severity);
28
- const lastIndex = order.indexOf(state.lastSeverity);
29
- if (currentIndex > lastIndex) return true;
38
+ if (order.indexOf(severity) > order.indexOf(state.lastSeverity)) return true;
30
39
 
31
40
  return Date.now() - state.lastNotifiedAt >= COOLDOWN_MS;
32
41
  }
@@ -35,9 +44,121 @@ function markNotified(key: string, severity: WarningSeverity): void {
35
44
  alerts.set(key, { lastSeverity: severity, lastNotifiedAt: Date.now() });
36
45
  }
37
46
 
47
+ interface PendingWarning {
48
+ key: string;
49
+ severity: WarningSeverity;
50
+ message: string;
51
+ }
52
+
53
+ /** Subscription energy (kWh) — the primary billing pool while subscribed. */
54
+ function energyWarning(
55
+ sub: NonNullable<NeuralwattQuotas["subscription"]>,
56
+ ): PendingWarning | undefined {
57
+ if (sub.kwh_included <= 0) return;
58
+ const pct = (sub.kwh_remaining / sub.kwh_included) * 100;
59
+ if (pct > LOW_PCT) return;
60
+ return {
61
+ key: "energy",
62
+ severity: severityForPct(pct),
63
+ message: `Energy: ${pct.toFixed(0)}% remaining (${formatKwh(sub.kwh_remaining)} of ${formatKwh(sub.kwh_included)})`,
64
+ };
65
+ }
66
+
67
+ /** Balance credits (USD) — on-demand top-up pool. */
68
+ function creditsWarning(quotas: NeuralwattQuotas): PendingWarning | undefined {
69
+ const { credits_remaining_usd, total_credits_usd } = quotas.balance;
70
+ if (total_credits_usd <= 0) return;
71
+ const pct = (credits_remaining_usd / total_credits_usd) * 100;
72
+ if (pct > LOW_PCT) return;
73
+ return {
74
+ key: "credits",
75
+ severity: severityForPct(pct),
76
+ message: `Credits: ${pct.toFixed(0)}% remaining (${formatUsd(credits_remaining_usd)} of ${formatUsd(total_credits_usd)})`,
77
+ };
78
+ }
79
+
80
+ /** Overage usage billed against the overage cap, derived from kWh usage. */
81
+ interface OverageProgress {
82
+ /** kWh billed at the overage rate. */
83
+ overageKwh: number;
84
+ /** Per-kWh rate applied (USD). */
85
+ rate: number;
86
+ /** Cost of the overage kWh so far (USD). */
87
+ costUsd: number;
88
+ /** Configured overage cap (USD), or 0 when none. */
89
+ capUsd: number;
90
+ /** Remaining cap headroom (USD), clamped at 0. */
91
+ remainingUsd: number;
92
+ /** Remaining cap as a percentage of the cap (0-100). 0 when no cap. */
93
+ pctRemaining: number;
94
+ /** Cap exhausted (overage cost has reached or passed the cap). */
95
+ exhausted: boolean;
96
+ }
97
+
98
+ export function computeOverageProgress(
99
+ quotas: NeuralwattQuotas,
100
+ ): OverageProgress {
101
+ const capUsd = quotas.limits.overage_limit_usd ?? 0;
102
+ const hasSub = quotas.subscription !== null;
103
+
104
+ // Subscribed: only kWh beyond the included quota are billed at the overage
105
+ // rate. Unsubscribed: every kWh is billable — the monthly usage total is the
106
+ // overage pool (there is no included quota to subtract from).
107
+ const overageKwh = hasSub
108
+ ? Math.max(
109
+ 0,
110
+ (quotas.subscription?.kwh_used ?? 0) -
111
+ (quotas.subscription?.kwh_included ?? 0),
112
+ )
113
+ : quotas.usage.current_month.energy_kwh;
114
+
115
+ const rate = hasSub
116
+ ? OVERAGE_RATE_PER_KWH_SUBSCRIBED
117
+ : OVERAGE_RATE_PER_KWH_UNSUBSCRIBED;
118
+ const costUsd = overageKwh * rate;
119
+ const remainingUsd = Math.max(0, capUsd - costUsd);
120
+ const pctRemaining = capUsd > 0 ? (remainingUsd / capUsd) * 100 : 0;
121
+
122
+ return {
123
+ overageKwh,
124
+ rate,
125
+ costUsd,
126
+ capUsd,
127
+ remainingUsd,
128
+ pctRemaining,
129
+ exhausted: capUsd > 0 && remainingUsd <= 0,
130
+ };
131
+ }
132
+
133
+ function overageWarning(progress: OverageProgress): PendingWarning {
134
+ const pct = Math.max(0, Math.min(100, progress.pctRemaining));
135
+ return {
136
+ key: "overage",
137
+ // Entering overage is itself worth a critical alert; the % controls the
138
+ // message, not whether we notify.
139
+ severity: "critical",
140
+ message: `Overage cap: ${pct.toFixed(0)}% remaining (${formatUsd(progress.remainingUsd)} of ${formatUsd(progress.capUsd)}, ${formatKwh(progress.overageKwh)} over @ ${formatUsd(progress.rate)}/kWh)`,
141
+ };
142
+ }
143
+
38
144
  /**
39
- * When a subscription is active, energy is the primary billing method.
40
- * Credits are on-demand/top-up only don't warn for credits when subscribed.
145
+ * Warning progression mirrors Neuralwatt's billing order. Each stage uses its
146
+ * own alert key, so once a later stage starts the earlier one stops — the
147
+ * warning "moves on" instead of re-reporting a depleted pool forever.
148
+ *
149
+ * subscribed, not in overage → energy (kWh remaining of quota)
150
+ * subscribed, in overage, cap set → overage cap progress (credits unreachable)
151
+ * subscribed, in overage, cap exhausted→ balance credits
152
+ * subscribed, in overage, no cap → balance credits (overage draws them down)
153
+ * no subscription, cap set → overage cap progress (all kWh billable)
154
+ * no subscription, no cap → balance credits
155
+ *
156
+ * Overage cost is derived from kWh usage: subscribed pays $5/kWh for kWh
157
+ * beyond the included quota; unsubscribed pays $10/kWh for all usage. There is
158
+ * no overage-spent counter in the API, so progress is computed.
159
+ *
160
+ * Usage totals (monthly/lifetime cost in USD) are deliberately not used as a
161
+ * threshold basis — they are not directly tied to the subscription's kWh quota.
41
162
  */
42
163
  export function checkQuotas(
43
164
  ctx: ExtensionContext,
@@ -45,55 +166,59 @@ export function checkQuotas(
45
166
  ): void {
46
167
  if (!ctx.hasUI) return;
47
168
 
48
- const warnings: string[] = [];
49
- const hasSub = quotas.subscription !== null;
169
+ const pending: PendingWarning[] = [];
170
+ const sub = quotas.subscription;
50
171
 
51
- // Credits warning — only when no active subscription
52
- if (!hasSub) {
53
- const { credits_remaining_usd, total_credits_usd } = quotas.balance;
54
- if (total_credits_usd > 0) {
55
- const pct = (credits_remaining_usd / total_credits_usd) * 100;
56
- if (pct <= 25) {
57
- const severity: WarningSeverity = pct <= 10 ? "critical" : "warning";
58
- const key = "credits";
59
- if (shouldNotify(key, severity)) {
60
- markNotified(key, severity);
61
- warnings.push(
62
- `Credits: ${pct.toFixed(0)}% remaining (${formatUsd(credits_remaining_usd)} of ${formatUsd(total_credits_usd)})`,
63
- );
64
- }
172
+ if (sub?.in_overage) {
173
+ const cap = quotas.limits.overage_limit_usd;
174
+ if (cap !== null && cap > 0) {
175
+ const progress = computeOverageProgress(quotas);
176
+ if (progress.exhausted) {
177
+ // Cap spent fall through to the balance credits.
178
+ const cw = creditsWarning(quotas);
179
+ if (cw) pending.push(cw);
180
+ } else {
181
+ pending.push(overageWarning(progress));
65
182
  }
183
+ } else {
184
+ // No cap: overage spends down the balance credits directly.
185
+ const cw = creditsWarning(quotas);
186
+ if (cw) pending.push(cw);
66
187
  }
67
- }
68
-
69
- // Subscription energy check
70
- if (quotas.subscription) {
71
- const { kwh_included, kwh_remaining, in_overage } = quotas.subscription;
72
- if (kwh_included > 0) {
73
- const pct = (kwh_remaining / kwh_included) * 100;
74
- if (in_overage || pct <= 25) {
75
- const severity: WarningSeverity = in_overage
76
- ? "critical"
77
- : pct <= 10
78
- ? "critical"
79
- : "warning";
80
- const key = "energy";
81
- if (shouldNotify(key, severity)) {
82
- markNotified(key, severity);
83
- const tag = in_overage ? " [OVERAGE]" : "";
84
- warnings.push(
85
- `Energy${tag}: ${pct.toFixed(0)}% remaining (${formatKwh(kwh_remaining)} of ${formatKwh(kwh_included)})`,
86
- );
87
- }
188
+ } else if (sub) {
189
+ const ew = energyWarning(sub);
190
+ if (ew) pending.push(ew);
191
+ } else {
192
+ // No subscription. All kWh bill at the unsubscribed rate; warn on the
193
+ // overage cap when one is set, otherwise on the balance credits.
194
+ const cap = quotas.limits.overage_limit_usd;
195
+ if (cap !== null && cap > 0) {
196
+ const progress = computeOverageProgress(quotas);
197
+ if (progress.exhausted) {
198
+ const cw = creditsWarning(quotas);
199
+ if (cw) pending.push(cw);
200
+ } else if (progress.pctRemaining <= LOW_PCT) {
201
+ pending.push(overageWarning(progress));
88
202
  }
203
+ } else {
204
+ const cw = creditsWarning(quotas);
205
+ if (cw) pending.push(cw);
89
206
  }
90
207
  }
91
208
 
92
- if (warnings.length === 0) return;
209
+ const fired = pending.filter((w) => {
210
+ if (shouldNotify(w.key, w.severity)) {
211
+ markNotified(w.key, w.severity);
212
+ return true;
213
+ }
214
+ return false;
215
+ });
216
+
217
+ if (fired.length === 0) return;
93
218
 
94
- const hasCritical = warnings.some((w) => w.includes("[OVERAGE]"));
219
+ const hasCritical = fired.some((w) => w.severity === "critical");
95
220
  ctx.ui.notify(
96
- `Neuralwatt quota warning:\n${warnings.map((w) => ` - ${w}`).join("\n")}`,
221
+ `Neuralwatt quota warning:\n${fired.map((w) => ` - ${w.message}`).join("\n")}`,
97
222
  hasCritical ? "error" : "warning",
98
223
  );
99
224
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aliou/pi-neuralwatt",
3
- "version": "0.10.2",
3
+ "version": "0.10.4",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "private": false,