@aliou/pi-neuralwatt 0.7.2 → 0.7.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aliou/pi-neuralwatt",
3
- "version": "0.7.2",
3
+ "version": "0.7.4",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "private": false,
@@ -46,6 +46,11 @@ function registerNeuralwattProvider(
46
46
  const { includeLegacyModelIds, includeHiddenModels } =
47
47
  configLoader.getConfig();
48
48
 
49
+ const publicModels = getNeuralwattModels({ includeLegacyModelIds });
50
+ const resolvedHiddenModels = includeHiddenModels
51
+ ? dedupeHiddenModels(hiddenModels, publicModels)
52
+ : [];
53
+
49
54
  const config: Parameters<ExtensionAPI["registerProvider"]>[1] = {
50
55
  baseUrl: "https://api.neuralwatt.com/v1",
51
56
  apiKey: "$NEURALWATT_API_KEY",
@@ -55,10 +60,7 @@ function registerNeuralwattProvider(
55
60
  Referer: "https://pi.dev",
56
61
  "X-Title": "npm:@aliou/pi-neuralwatt",
57
62
  },
58
- models: [
59
- ...getNeuralwattModels({ includeLegacyModelIds }),
60
- ...(includeHiddenModels ? hiddenModels : []),
61
- ],
63
+ models: [...publicModels, ...resolvedHiddenModels],
62
64
  };
63
65
 
64
66
  const provider = getApiProvider("openai-completions");
@@ -73,6 +75,23 @@ function registerNeuralwattProvider(
73
75
  pi.registerProvider("neuralwatt", config);
74
76
  }
75
77
 
78
+ /**
79
+ * Drop any hidden model whose ID collides with a public or legacy model.
80
+ *
81
+ * Models can graduate from hidden (authenticated /v1/models only) to public
82
+ * (unauthenticated list). When that happens, a stale on-disk cache may still
83
+ * list the now-public ID, which would register it twice and make Pi treat the
84
+ * scoped model as ambiguous ("No models match pattern"). Dedupe against the
85
+ * public list so a stale cache can never shadow a public model.
86
+ */
87
+ function dedupeHiddenModels(
88
+ hiddenModels: ProviderModelConfig[],
89
+ publicModels: ProviderModelConfig[],
90
+ ): ProviderModelConfig[] {
91
+ const publicIds = new Set(publicModels.map((m) => m.id));
92
+ return hiddenModels.filter((m) => !publicIds.has(m.id));
93
+ }
94
+
76
95
  export default async function (pi: ExtensionAPI) {
77
96
  await configLoader.load();
78
97
 
@@ -171,12 +190,21 @@ export default async function (pi: ExtensionAPI) {
171
190
  return { message };
172
191
  }
173
192
 
193
+ // Fallback for 429s where no layer-specific headers were captured. The
194
+ // streamSimple wrap (wrapNeuralwattStreamSimple) already formats a
195
+ // detailed message via formatRateLimitError when it captures headers;
196
+ // detect that case by the `"429 rate limit:"` prefix it emits and leave
197
+ // it untouched. This branch only fires for genuinely headerless 429s
198
+ // (e.g. anonymous playground limits, or a 429 from infra in front of
199
+ // Neuralwatt), since after_provider_response cannot observe 429s — the
200
+ // OpenAI SDK throws before Pi's onResponse hook runs.
174
201
  if (
175
202
  event.message.role === "assistant" &&
176
203
  event.message.stopReason === "error" &&
177
204
  (event.message.provider === "neuralwatt" ||
178
205
  ctx.model?.provider === "neuralwatt") &&
179
- event.message.errorMessage?.includes("429")
206
+ event.message.errorMessage?.includes("429") &&
207
+ !event.message.errorMessage.startsWith("429 rate limit:")
180
208
  ) {
181
209
  return {
182
210
  message: normalizeNeuralwattRateLimitError(event.message, {
@@ -245,14 +273,14 @@ export default async function (pi: ExtensionAPI) {
245
273
  ctx.modelRegistry.authStorage,
246
274
  hiddenModelsAbort.signal,
247
275
  );
248
- // Persist for the next startup so scoped models resolve without warnings
249
- // on Pi's subsequent launches.
250
- if (fetched.length > 0) {
251
- hiddenModels = fetched;
252
- await writeHiddenModelsCache(hiddenModels);
253
- if (!hiddenModelsAbort.signal.aborted) {
254
- registerNeuralwattProvider(pi, handleSseQuota, hiddenModels);
255
- }
276
+ // Persist for the next startup so scoped models resolve without
277
+ // warnings on Pi's subsequent launches. Always write the cache (even
278
+ // when empty) and re-register, so graduated or removed hidden models
279
+ // are purged from both the cache and the provider's model list.
280
+ hiddenModels = fetched;
281
+ await writeHiddenModelsCache(hiddenModels);
282
+ if (!hiddenModelsAbort.signal.aborted) {
283
+ registerNeuralwattProvider(pi, handleSseQuota, hiddenModels);
256
284
  }
257
285
  }
258
286
 
@@ -10,19 +10,10 @@ import { NEURALWATT_MODELS } from "./public-models";
10
10
  // Per-ID overrides for known hidden models. The authenticated /v1/models endpoint
11
11
  // exposes pricing and capabilities, but some Pi-specific behavior (thinking levels,
12
12
  // compat flags) has to be supplied by hand.
13
+ // Previously hidden models that have since gone public now live in public-models.ts.
13
14
  const HIDDEN_MODEL_OVERRIDES: Partial<
14
15
  Record<string, Partial<ProviderModelConfig>>
15
- > = {
16
- "glm-5.2-short": {
17
- thinkingLevelMap: {
18
- minimal: null,
19
- low: null,
20
- medium: null,
21
- high: "high",
22
- xhigh: "max",
23
- },
24
- },
25
- };
16
+ > = {};
26
17
 
27
18
  function buildHiddenModel(apiModel: NeuralwattApiModel): ProviderModelConfig {
28
19
  const meta = apiModel.metadata;
@@ -49,6 +49,52 @@ export const NEURALWATT_MODELS: ProviderModelConfig[] = [
49
49
  maxTokensField: "max_tokens",
50
50
  },
51
51
  },
52
+ // GLM-5.2 Short - ZhipuAI (200K context, bounded reasoning budget)
53
+ {
54
+ id: "glm-5.2-short",
55
+ name: "GLM-5.2 Short",
56
+ reasoning: true,
57
+ input: ["text"],
58
+ cost: {
59
+ input: 1.45,
60
+ output: 4.5,
61
+ cacheRead: 0.3625,
62
+ cacheWrite: 0,
63
+ },
64
+ contextWindow: 199984,
65
+ maxTokens: 65536,
66
+ thinkingLevelMap: {
67
+ minimal: null,
68
+ low: null,
69
+ medium: null,
70
+ high: "high",
71
+ xhigh: "max",
72
+ },
73
+ compat: {
74
+ supportsDeveloperRole: false,
75
+ maxTokensField: "max_tokens",
76
+ requiresReasoningContentOnAssistantMessages: true,
77
+ },
78
+ },
79
+ // GLM-5.2 Short Fast - ZhipuAI (200K context, reasoning disabled)
80
+ {
81
+ id: "glm-5.2-short-fast",
82
+ name: "GLM-5.2 Short Fast",
83
+ reasoning: false,
84
+ input: ["text"],
85
+ cost: {
86
+ input: 1.45,
87
+ output: 4.5,
88
+ cacheRead: 0.3625,
89
+ cacheWrite: 0,
90
+ },
91
+ contextWindow: 199984,
92
+ maxTokens: 65536,
93
+ compat: {
94
+ supportsDeveloperRole: false,
95
+ maxTokensField: "max_tokens",
96
+ },
97
+ },
52
98
  // Kimi K2.5 - MoonshotAI
53
99
  {
54
100
  id: "moonshotai/Kimi-K2.5",