@aliou/pi-neuralwatt 0.10.6 → 0.11.2
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 +1 -0
- package/extensions/provider/commands/settings/index.ts +22 -0
- package/extensions/provider/index.ts +5 -0
- package/extensions/provider/models/aliases.ts +35 -0
- package/extensions/provider/models/early-access.ts +2 -25
- package/extensions/provider/models/index.ts +12 -0
- package/extensions/provider/models/legacy.ts +13 -6
- package/extensions/provider/models/public-models.ts +43 -57
- package/extensions/provider/models/refresh.ts +40 -11
- package/extensions/quota-warnings/index.ts +24 -11
- package/extensions/sub-bar-integration/index.ts +16 -12
- package/package.json +1 -1
- package/schema.json +4 -0
- package/src/config/defaults.ts +1 -0
- package/src/config/loader.ts +3 -0
- package/src/config/migration/04-enable-aliases-for-legacy-users.ts +49 -0
- package/src/config/migration/index.ts +3 -0
- package/src/config/types.ts +4 -0
package/README.md
CHANGED
|
@@ -78,6 +78,7 @@ Configure features with `/neuralwatt:settings`:
|
|
|
78
78
|
- **Quota warnings** — Enable/disable low quota notifications
|
|
79
79
|
- **Sub-bar integration** — Show/hide usage in status bar
|
|
80
80
|
- **Legacy model IDs** — Include deprecated model aliases
|
|
81
|
+
- **Alias model IDs** — Include active creator-scoped model aliases
|
|
81
82
|
- **Early access models** — Include pre-release models available only to the configured API key
|
|
82
83
|
|
|
83
84
|
The provider itself cannot be disabled — it is always loaded.
|
|
@@ -119,6 +119,18 @@ export function registerNeuralwattSettings(
|
|
|
119
119
|
: "ignore",
|
|
120
120
|
values: ["include", "ignore"],
|
|
121
121
|
},
|
|
122
|
+
{
|
|
123
|
+
id: "includeAliasedModelIds",
|
|
124
|
+
label: "Alias model IDs",
|
|
125
|
+
description:
|
|
126
|
+
"Include active creator-scoped model IDs as aliases in the model picker",
|
|
127
|
+
currentValue:
|
|
128
|
+
(tabConfig?.provider?.includeAliasedModelIds ??
|
|
129
|
+
resolved.provider.includeAliasedModelIds)
|
|
130
|
+
? "include"
|
|
131
|
+
: "ignore",
|
|
132
|
+
values: ["include", "ignore"],
|
|
133
|
+
},
|
|
122
134
|
{
|
|
123
135
|
id: "includeEarlyAccessModels",
|
|
124
136
|
label: "Early access models",
|
|
@@ -148,6 +160,16 @@ export function registerNeuralwattSettings(
|
|
|
148
160
|
};
|
|
149
161
|
}
|
|
150
162
|
|
|
163
|
+
if (id === "includeAliasedModelIds") {
|
|
164
|
+
return {
|
|
165
|
+
...config,
|
|
166
|
+
provider: {
|
|
167
|
+
...config.provider,
|
|
168
|
+
includeAliasedModelIds: newValue === "include",
|
|
169
|
+
},
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
|
|
151
173
|
if (id === "includeEarlyAccessModels") {
|
|
152
174
|
return {
|
|
153
175
|
...config,
|
|
@@ -44,6 +44,7 @@ function registerNeuralwattProvider(
|
|
|
44
44
|
|
|
45
45
|
const models = getNeuralwattModels({
|
|
46
46
|
includeLegacyModelIds: providerConfig.includeLegacyModelIds,
|
|
47
|
+
includeAliasedModelIds: providerConfig.includeAliasedModelIds,
|
|
47
48
|
});
|
|
48
49
|
|
|
49
50
|
const config: Parameters<ExtensionAPI["registerProvider"]>[1] = {
|
|
@@ -61,6 +62,8 @@ function registerNeuralwattProvider(
|
|
|
61
62
|
refreshNeuralwattModels(context, {
|
|
62
63
|
includeLegacyModelIds:
|
|
63
64
|
configLoader.getConfig().provider.includeLegacyModelIds,
|
|
65
|
+
includeAliasedModelIds:
|
|
66
|
+
configLoader.getConfig().provider.includeAliasedModelIds,
|
|
64
67
|
includeEarlyAccessModels:
|
|
65
68
|
configLoader.getConfig().provider.includeEarlyAccessModels,
|
|
66
69
|
}),
|
|
@@ -113,6 +116,8 @@ export default async function (pi: ExtensionAPI) {
|
|
|
113
116
|
if (
|
|
114
117
|
next.includeLegacyModelIds ===
|
|
115
118
|
registeredProviderSettings.includeLegacyModelIds &&
|
|
119
|
+
next.includeAliasedModelIds ===
|
|
120
|
+
registeredProviderSettings.includeAliasedModelIds &&
|
|
116
121
|
next.includeEarlyAccessModels ===
|
|
117
122
|
registeredProviderSettings.includeEarlyAccessModels
|
|
118
123
|
) {
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { ProviderModelConfig } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
import { NEURALWATT_MODELS } from "./public-models";
|
|
3
|
+
|
|
4
|
+
// Alternate creator-scoped model IDs that Neuralwatt accepts for active models.
|
|
5
|
+
// These are only included when `includeAliasedModelIds` is enabled.
|
|
6
|
+
export const ALIAS_MODEL_MAP = {
|
|
7
|
+
"deepseek-ai/DeepSeek-V4-Flash": "deepseek-v4-flash",
|
|
8
|
+
"zai-org/GLM-5.2-FP8": "glm-5.2",
|
|
9
|
+
"moonshotai/Kimi-K2.7-Code": "kimi-k2.7-code",
|
|
10
|
+
"moonshotai/Kimi-K3": "kimi-k3",
|
|
11
|
+
"Qwen/Qwen3.6-35B-A3B": "qwen3.6-35b",
|
|
12
|
+
"nvidia/Gemma-4-31B-IT-NVFP4": "gemma-4-31b",
|
|
13
|
+
} as const;
|
|
14
|
+
|
|
15
|
+
export const ALIAS_NEURALWATT_MODEL_IDS = new Set<string>(
|
|
16
|
+
Object.keys(ALIAS_MODEL_MAP),
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
export function buildAliasNeuralwattModels(
|
|
20
|
+
canonicalModels: ProviderModelConfig[] = NEURALWATT_MODELS,
|
|
21
|
+
): ProviderModelConfig[] {
|
|
22
|
+
return Object.entries(ALIAS_MODEL_MAP).flatMap(([aliasId, canonicalId]) => {
|
|
23
|
+
const canonical = canonicalModels.find((model) => model.id === canonicalId);
|
|
24
|
+
|
|
25
|
+
if (!canonical) return [];
|
|
26
|
+
|
|
27
|
+
return [
|
|
28
|
+
{
|
|
29
|
+
...canonical,
|
|
30
|
+
id: aliasId,
|
|
31
|
+
name: `${canonical.name} (alias ID)`,
|
|
32
|
+
},
|
|
33
|
+
];
|
|
34
|
+
});
|
|
35
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { ProviderModelConfig } from "@earendil-works/pi-coding-agent";
|
|
2
2
|
import { fetchNeuralwattModels } from "../../../src/lib/neuralwatt-api";
|
|
3
3
|
import type { NeuralwattApiModel } from "../../../src/types/models-api";
|
|
4
|
-
import {
|
|
4
|
+
import { resolveMaxTokens } from "./build";
|
|
5
5
|
import { NEURALWATT_MODELS } from "./public-models";
|
|
6
6
|
|
|
7
7
|
// Pre-release models. Neuralwatt ships these to authorized accounts before they
|
|
@@ -9,30 +9,7 @@ import { NEURALWATT_MODELS } from "./public-models";
|
|
|
9
9
|
// gated by includeEarlyAccessModels and hardcode entries so they remain
|
|
10
10
|
// available from the offline catalog.
|
|
11
11
|
// Move an entry to public-models.ts once Neuralwatt advertises it publicly.
|
|
12
|
-
export const EARLY_ACCESS_NEURALWATT_MODELS: ProviderModelConfig[] = [
|
|
13
|
-
// Kimi K3 - early-access MoonshotAI multimodal MoE.
|
|
14
|
-
// Metadata is sourced from Neuralwatt's authenticated model catalog.
|
|
15
|
-
buildNeuralwattModel(
|
|
16
|
-
{
|
|
17
|
-
cost: { input: 3, output: 15, cacheRead: 0.3 },
|
|
18
|
-
vision: true,
|
|
19
|
-
thinkingLevelMap: {
|
|
20
|
-
minimal: null,
|
|
21
|
-
low: null,
|
|
22
|
-
medium: "medium",
|
|
23
|
-
high: null,
|
|
24
|
-
xhigh: null,
|
|
25
|
-
},
|
|
26
|
-
},
|
|
27
|
-
{
|
|
28
|
-
id: "kimi-k3",
|
|
29
|
-
name: "Kimi K3",
|
|
30
|
-
contextWindow: 1048560,
|
|
31
|
-
maxOutputTokens: null,
|
|
32
|
-
reasoning: true,
|
|
33
|
-
},
|
|
34
|
-
),
|
|
35
|
-
];
|
|
12
|
+
export const EARLY_ACCESS_NEURALWATT_MODELS: ProviderModelConfig[] = [];
|
|
36
13
|
|
|
37
14
|
// Per-ID overrides for known early-access models. The authenticated /v1/models
|
|
38
15
|
// endpoint exposes pricing and capabilities, but some Pi-specific behavior
|
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
import type { ProviderModelConfig } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
import { buildAliasNeuralwattModels } from "./aliases";
|
|
2
3
|
import { buildLegacyNeuralwattModels } from "./legacy";
|
|
3
4
|
import { NEURALWATT_MODELS } from "./public-models";
|
|
4
5
|
|
|
6
|
+
export {
|
|
7
|
+
ALIAS_MODEL_MAP,
|
|
8
|
+
ALIAS_NEURALWATT_MODEL_IDS,
|
|
9
|
+
buildAliasNeuralwattModels,
|
|
10
|
+
} from "./aliases";
|
|
11
|
+
|
|
5
12
|
export {
|
|
6
13
|
EARLY_ACCESS_NEURALWATT_MODELS,
|
|
7
14
|
loadEarlyAccessModels,
|
|
@@ -16,6 +23,7 @@ export { refreshNeuralwattModels } from "./refresh";
|
|
|
16
23
|
|
|
17
24
|
export function getNeuralwattModels(options?: {
|
|
18
25
|
includeLegacyModelIds?: boolean;
|
|
26
|
+
includeAliasedModelIds?: boolean;
|
|
19
27
|
}): ProviderModelConfig[] {
|
|
20
28
|
const models: ProviderModelConfig[] = [...NEURALWATT_MODELS];
|
|
21
29
|
|
|
@@ -23,5 +31,9 @@ export function getNeuralwattModels(options?: {
|
|
|
23
31
|
models.push(...buildLegacyNeuralwattModels());
|
|
24
32
|
}
|
|
25
33
|
|
|
34
|
+
if (options?.includeAliasedModelIds) {
|
|
35
|
+
models.push(...buildAliasNeuralwattModels());
|
|
36
|
+
}
|
|
37
|
+
|
|
26
38
|
return models;
|
|
27
39
|
}
|
|
@@ -4,15 +4,22 @@ import { NEURALWATT_MODELS } from "./public-models";
|
|
|
4
4
|
// Legacy model IDs that should resolve to a canonical public model.
|
|
5
5
|
// These are phased out over time and are only included when `includeLegacyModelIds` is enabled.
|
|
6
6
|
export const LEGACY_MODEL_ALIAS_MAP = {
|
|
7
|
+
// GLM 5.1 → GLM 5.2
|
|
7
8
|
"glm-5.1": "glm-5.2",
|
|
8
9
|
"glm-5.1-fast": "glm-5.2-fast",
|
|
9
10
|
"zai-org/GLM-5.1-FP8": "glm-5.2",
|
|
10
|
-
|
|
11
|
-
"
|
|
12
|
-
"
|
|
13
|
-
|
|
14
|
-
"
|
|
15
|
-
"
|
|
11
|
+
// Kimi K2.5 → Kimi K2.7 Code (K2.6 was retired 8/3, redirected to K2.7)
|
|
12
|
+
"moonshotai/Kimi-K2.5": "kimi-k2.7-code",
|
|
13
|
+
"kimi-k2.5-fast": "kimi-k2.7-code-fast",
|
|
14
|
+
// Kimi K2.6 retired 8/3, redirected to Kimi K2.7 Code
|
|
15
|
+
"kimi-k2.6": "kimi-k2.7-code",
|
|
16
|
+
"kimi-k2.6-fast": "kimi-k2.7-code-fast",
|
|
17
|
+
"kimi-k2.6-flex": "kimi-k2.7-code-flex",
|
|
18
|
+
"moonshotai/Kimi-K2.6": "kimi-k2.7-code",
|
|
19
|
+
// Qwen 3.5 retired 8/3, redirected to Qwen 3.6
|
|
20
|
+
"qwen3.5-397b": "qwen3.6-35b",
|
|
21
|
+
"qwen3.5-397b-fast": "qwen3.6-35b-fast",
|
|
22
|
+
"Qwen/Qwen3.5-397B-A17B-FP8": "qwen3.6-35b",
|
|
16
23
|
} as const;
|
|
17
24
|
|
|
18
25
|
export const LEGACY_NEURALWATT_MODEL_IDS = new Set<string>(
|
|
@@ -27,23 +27,29 @@ const GLM_THINKING: ThinkingLevelMap = {
|
|
|
27
27
|
max: "max",
|
|
28
28
|
};
|
|
29
29
|
|
|
30
|
-
// Binary thinking control
|
|
30
|
+
// Binary thinking control (Kimi K2.x, Qwen3.x): no graded `reasoning_effort`
|
|
31
|
+
// upstream, only a thinking on/off toggle. Expose a single known-good Pi
|
|
32
|
+
// level; "high" stands in for standard full thinking.
|
|
31
33
|
const BINARY_THINKING: ThinkingLevelMap = {
|
|
32
34
|
minimal: null,
|
|
33
35
|
low: null,
|
|
34
|
-
medium:
|
|
35
|
-
high:
|
|
36
|
+
medium: null,
|
|
37
|
+
high: "high",
|
|
36
38
|
xhigh: null,
|
|
37
39
|
};
|
|
38
40
|
|
|
39
41
|
const DEEPSEEK_V4_FLASH: NeuralwattModelFamily = {
|
|
40
|
-
cost: { input: 0.
|
|
42
|
+
cost: { input: 0.14, output: 0.28, cacheRead: 0.028 },
|
|
41
43
|
vision: false,
|
|
44
|
+
// DeepSeek V4 Flash accepts reasoning_effort low/high/max (default high);
|
|
45
|
+
// there is no "medium" tier, so Pi's low/high/max map directly and
|
|
46
|
+
// minimal/medium/xhigh are unsupported holes.
|
|
47
|
+
// https://api-docs.deepseek.com/guides/thinking_mode/
|
|
42
48
|
thinkingLevelMap: {
|
|
43
49
|
off: "none",
|
|
44
|
-
minimal:
|
|
50
|
+
minimal: null,
|
|
45
51
|
low: "low",
|
|
46
|
-
medium:
|
|
52
|
+
medium: null,
|
|
47
53
|
high: "high",
|
|
48
54
|
xhigh: null,
|
|
49
55
|
max: "max",
|
|
@@ -52,41 +58,47 @@ const DEEPSEEK_V4_FLASH: NeuralwattModelFamily = {
|
|
|
52
58
|
|
|
53
59
|
// Google, served from NVIDIA's NVFP4 checkpoint.
|
|
54
60
|
const GEMMA_4: NeuralwattModelFamily = {
|
|
55
|
-
cost: { input: 0.144, output: 0.42, cacheRead: 0.
|
|
61
|
+
cost: { input: 0.144, output: 0.42, cacheRead: 0.0144 },
|
|
56
62
|
vision: true,
|
|
57
63
|
};
|
|
58
64
|
|
|
59
65
|
// ZhipuAI.
|
|
60
66
|
const GLM_5_2: NeuralwattModelFamily = {
|
|
61
|
-
cost: { input: 1.45, output: 4.5, cacheRead: 0.
|
|
67
|
+
cost: { input: 1.45, output: 4.5, cacheRead: 0.145 },
|
|
62
68
|
vision: false,
|
|
63
69
|
thinkingLevelMap: GLM_THINKING,
|
|
64
70
|
};
|
|
65
71
|
|
|
66
|
-
// MoonshotAI.
|
|
67
|
-
|
|
68
|
-
|
|
72
|
+
// MoonshotAI. K3 is the largest open-weight model ever released, served in
|
|
73
|
+
// preview with limited concurrency. K3 always reasons (thinking cannot be
|
|
74
|
+
// disabled) and supports `reasoning_effort` values "low", "high", and "max"
|
|
75
|
+
// (default "max"). There is no "medium" tier upstream, so Pi's low/high/max
|
|
76
|
+
// map directly and `off`, `minimal`, `medium`, and `xhigh` are unsupported
|
|
77
|
+
// holes. The `-fast` endpoint is a shorthand to set thinking to off.
|
|
78
|
+
const KIMI_K3: NeuralwattModelFamily = {
|
|
79
|
+
cost: { input: 3, output: 15, cacheRead: 0.3 },
|
|
69
80
|
vision: true,
|
|
70
|
-
thinkingLevelMap:
|
|
81
|
+
thinkingLevelMap: {
|
|
82
|
+
off: null,
|
|
83
|
+
minimal: null,
|
|
84
|
+
low: "low",
|
|
85
|
+
medium: null,
|
|
86
|
+
high: "high",
|
|
87
|
+
xhigh: null,
|
|
88
|
+
max: "max",
|
|
89
|
+
},
|
|
71
90
|
};
|
|
72
91
|
|
|
73
92
|
// MoonshotAI.
|
|
74
93
|
const KIMI_K2_7_CODE: NeuralwattModelFamily = {
|
|
75
|
-
cost: { input: 0.95, output: 4.0, cacheRead: 0.
|
|
94
|
+
cost: { input: 0.95, output: 4.0, cacheRead: 0.095 },
|
|
76
95
|
vision: true,
|
|
77
96
|
thinkingLevelMap: { off: null, ...BINARY_THINKING },
|
|
78
97
|
};
|
|
79
98
|
|
|
80
|
-
// Qwen.
|
|
81
|
-
const QWEN_3_5_397B: NeuralwattModelFamily = {
|
|
82
|
-
cost: { input: 0.69, output: 4.14, cacheRead: 0.1725 },
|
|
83
|
-
vision: false,
|
|
84
|
-
thinkingLevelMap: BINARY_THINKING,
|
|
85
|
-
};
|
|
86
|
-
|
|
87
99
|
// Qwen.
|
|
88
100
|
const QWEN_3_6_35B: NeuralwattModelFamily = {
|
|
89
|
-
cost: { input: 0.29, output: 1.15, cacheRead: 0.
|
|
101
|
+
cost: { input: 0.29, output: 1.15, cacheRead: 0.029 },
|
|
90
102
|
vision: true,
|
|
91
103
|
thinkingLevelMap: BINARY_THINKING,
|
|
92
104
|
};
|
|
@@ -174,30 +186,22 @@ const FAMILIES: [NeuralwattModelFamily, NeuralwattVariantSpec[]][] = [
|
|
|
174
186
|
],
|
|
175
187
|
],
|
|
176
188
|
[
|
|
177
|
-
|
|
189
|
+
KIMI_K3,
|
|
178
190
|
[
|
|
179
191
|
{
|
|
180
|
-
id: "kimi-
|
|
181
|
-
name: "Kimi
|
|
182
|
-
contextWindow:
|
|
192
|
+
id: "kimi-k3",
|
|
193
|
+
name: "Kimi K3",
|
|
194
|
+
contextWindow: 1048560,
|
|
183
195
|
maxOutputTokens: null,
|
|
184
196
|
reasoning: true,
|
|
185
197
|
},
|
|
186
198
|
{
|
|
187
|
-
id: "kimi-
|
|
188
|
-
name: "Kimi
|
|
189
|
-
contextWindow:
|
|
199
|
+
id: "kimi-k3-fast",
|
|
200
|
+
name: "Kimi K3 Fast",
|
|
201
|
+
contextWindow: 1048560,
|
|
190
202
|
maxOutputTokens: null,
|
|
191
203
|
reasoning: false,
|
|
192
204
|
},
|
|
193
|
-
{
|
|
194
|
-
id: "kimi-k2.6-flex",
|
|
195
|
-
name: "Kimi K2.6 (flex)",
|
|
196
|
-
contextWindow: 262128,
|
|
197
|
-
maxOutputTokens: null,
|
|
198
|
-
reasoning: true,
|
|
199
|
-
costMultiplier: FLEX_COST_MULTIPLIER,
|
|
200
|
-
},
|
|
201
205
|
],
|
|
202
206
|
],
|
|
203
207
|
[
|
|
@@ -227,25 +231,6 @@ const FAMILIES: [NeuralwattModelFamily, NeuralwattVariantSpec[]][] = [
|
|
|
227
231
|
},
|
|
228
232
|
],
|
|
229
233
|
],
|
|
230
|
-
[
|
|
231
|
-
QWEN_3_5_397B,
|
|
232
|
-
[
|
|
233
|
-
{
|
|
234
|
-
id: "qwen3.5-397b",
|
|
235
|
-
name: "Qwen3.5 397B",
|
|
236
|
-
contextWindow: 262128,
|
|
237
|
-
maxOutputTokens: null,
|
|
238
|
-
reasoning: true,
|
|
239
|
-
},
|
|
240
|
-
{
|
|
241
|
-
id: "qwen3.5-397b-fast",
|
|
242
|
-
name: "Qwen3.5 397B Fast",
|
|
243
|
-
contextWindow: 262128,
|
|
244
|
-
maxOutputTokens: null,
|
|
245
|
-
reasoning: false,
|
|
246
|
-
},
|
|
247
|
-
],
|
|
248
|
-
],
|
|
249
234
|
[
|
|
250
235
|
QWEN_3_6_35B,
|
|
251
236
|
[
|
|
@@ -269,8 +254,9 @@ const FAMILIES: [NeuralwattModelFamily, NeuralwattVariantSpec[]][] = [
|
|
|
269
254
|
|
|
270
255
|
// `-flex` variants are the Flex tier: same model, context window, output cap,
|
|
271
256
|
// and prompt cache as the standard variant, admitted on spare capacity.
|
|
272
|
-
//
|
|
273
|
-
//
|
|
257
|
+
// The API now advertises flex variants but lists them at standard pricing;
|
|
258
|
+
// the 35% Flex discount is a billing-time concept applied here via
|
|
259
|
+
// `costMultiplier` rather than reflected in the catalog metadata.
|
|
274
260
|
// https://portal.neuralwatt.com/docs/guides/flex-tier
|
|
275
261
|
|
|
276
262
|
export const NEURALWATT_MODELS: ProviderModelConfig[] = FAMILIES.flatMap(
|
|
@@ -5,6 +5,10 @@ import type {
|
|
|
5
5
|
RefreshModelsContext,
|
|
6
6
|
} from "@earendil-works/pi-ai";
|
|
7
7
|
import type { ProviderModelConfig } from "@earendil-works/pi-coding-agent";
|
|
8
|
+
import {
|
|
9
|
+
ALIAS_NEURALWATT_MODEL_IDS,
|
|
10
|
+
buildAliasNeuralwattModels,
|
|
11
|
+
} from "./aliases";
|
|
8
12
|
import {
|
|
9
13
|
EARLY_ACCESS_NEURALWATT_MODELS,
|
|
10
14
|
loadEarlyAccessModels,
|
|
@@ -18,16 +22,28 @@ const API = "openai-completions" as const;
|
|
|
18
22
|
|
|
19
23
|
export interface RefreshNeuralwattModelsOptions {
|
|
20
24
|
includeLegacyModelIds: boolean;
|
|
25
|
+
includeAliasedModelIds: boolean;
|
|
21
26
|
includeEarlyAccessModels: boolean;
|
|
22
27
|
loadEarlyAccess?: typeof loadEarlyAccessModels;
|
|
23
28
|
}
|
|
24
29
|
|
|
25
30
|
function configuredModels(
|
|
26
31
|
includeLegacyModelIds: boolean,
|
|
32
|
+
includeAliasedModelIds: boolean,
|
|
33
|
+
extraCanonicalModels: ProviderModelConfig[] = [],
|
|
27
34
|
): ProviderModelConfig[] {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
35
|
+
const canonicalModels = [...NEURALWATT_MODELS, ...extraCanonicalModels];
|
|
36
|
+
const models: ProviderModelConfig[] = [...canonicalModels];
|
|
37
|
+
|
|
38
|
+
if (includeLegacyModelIds) {
|
|
39
|
+
models.push(...buildLegacyNeuralwattModels());
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (includeAliasedModelIds) {
|
|
43
|
+
models.push(...buildAliasNeuralwattModels(canonicalModels));
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return models;
|
|
31
47
|
}
|
|
32
48
|
|
|
33
49
|
function toStoredModel(model: ProviderModelConfig): Model<Api> {
|
|
@@ -91,11 +107,16 @@ function cachedEarlyAccessModels(
|
|
|
91
107
|
): ProviderModelConfig[] {
|
|
92
108
|
if (!stored) return [];
|
|
93
109
|
|
|
94
|
-
const allStaticIds = new Set(
|
|
110
|
+
const allStaticIds = new Set(
|
|
111
|
+
configuredModels(true, true).map((model) => model.id),
|
|
112
|
+
);
|
|
95
113
|
|
|
96
114
|
return stored.models
|
|
97
115
|
.filter(
|
|
98
|
-
(model) =>
|
|
116
|
+
(model) =>
|
|
117
|
+
model.provider === PROVIDER_ID &&
|
|
118
|
+
!allStaticIds.has(model.id) &&
|
|
119
|
+
!ALIAS_NEURALWATT_MODEL_IDS.has(model.id),
|
|
99
120
|
)
|
|
100
121
|
.map(toProviderModel);
|
|
101
122
|
}
|
|
@@ -115,7 +136,10 @@ export async function refreshNeuralwattModels(
|
|
|
115
136
|
context: RefreshModelsContext,
|
|
116
137
|
options: RefreshNeuralwattModelsOptions,
|
|
117
138
|
): Promise<ProviderModelConfig[]> {
|
|
118
|
-
const baseline = configuredModels(
|
|
139
|
+
const baseline = configuredModels(
|
|
140
|
+
options.includeLegacyModelIds,
|
|
141
|
+
options.includeAliasedModelIds,
|
|
142
|
+
);
|
|
119
143
|
const stored = await context.store.read();
|
|
120
144
|
|
|
121
145
|
if (!options.includeEarlyAccessModels) {
|
|
@@ -127,7 +151,11 @@ export async function refreshNeuralwattModels(
|
|
|
127
151
|
cachedEarlyAccessModels(stored),
|
|
128
152
|
baseline,
|
|
129
153
|
);
|
|
130
|
-
const cachedCatalog =
|
|
154
|
+
const cachedCatalog = configuredModels(
|
|
155
|
+
options.includeLegacyModelIds,
|
|
156
|
+
options.includeAliasedModelIds,
|
|
157
|
+
cachedEarlyAccess,
|
|
158
|
+
);
|
|
131
159
|
|
|
132
160
|
if (!context.allowNetwork || context.signal?.aborted) {
|
|
133
161
|
return cachedCatalog;
|
|
@@ -146,10 +174,11 @@ export async function refreshNeuralwattModels(
|
|
|
146
174
|
throw new Error("Neuralwatt model catalog refresh failed");
|
|
147
175
|
}
|
|
148
176
|
|
|
149
|
-
const catalog =
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
177
|
+
const catalog = configuredModels(
|
|
178
|
+
options.includeLegacyModelIds,
|
|
179
|
+
options.includeAliasedModelIds,
|
|
180
|
+
configuredEarlyAccessModels(earlyAccess, baseline),
|
|
181
|
+
);
|
|
153
182
|
await persistModels(context, catalog);
|
|
154
183
|
return catalog;
|
|
155
184
|
}
|
|
@@ -17,7 +17,8 @@ export default async function (pi: ExtensionAPI) {
|
|
|
17
17
|
await configLoader.load();
|
|
18
18
|
|
|
19
19
|
let enabled = configLoader.getConfig().quotaWarnings.enabled;
|
|
20
|
-
let
|
|
20
|
+
let currentProvider: string | undefined;
|
|
21
|
+
let unsubscribeQuotas: (() => void) | undefined;
|
|
21
22
|
|
|
22
23
|
// Listen for config changes at runtime
|
|
23
24
|
pi.events.on(NEURALWATT_CONFIG_UPDATED_EVENT, (data: unknown) => {
|
|
@@ -29,32 +30,44 @@ export default async function (pi: ExtensionAPI) {
|
|
|
29
30
|
}
|
|
30
31
|
});
|
|
31
32
|
|
|
32
|
-
|
|
33
|
+
// The quota handler runs on the shared event bus, so it must only touch a
|
|
34
|
+
// session ctx captured by a live session-scoped subscription: pi
|
|
35
|
+
// invalidates session-bound ctx after session replacement (newSession/
|
|
36
|
+
// fork/switchSession/reload), and dereferencing a stale ctx throws. We
|
|
37
|
+
// subscribe in session_start (capturing the fresh ctx in the closure) and
|
|
38
|
+
// unsubscribe in session_shutdown, before the ctx can go stale.
|
|
39
|
+
function handleQuotas(ctx: ExtensionContext, data: unknown): void {
|
|
33
40
|
if (!enabled) return;
|
|
34
41
|
if (!data || typeof data !== "object") return;
|
|
35
|
-
if (
|
|
36
|
-
if (currentContext.model?.provider !== "neuralwatt") return;
|
|
42
|
+
if (currentProvider !== "neuralwatt") return;
|
|
37
43
|
|
|
38
44
|
const { quotas } = data as NeuralwattQuotasUpdatedPayload;
|
|
39
|
-
checkQuotas(
|
|
40
|
-
}
|
|
45
|
+
checkQuotas(ctx, quotas);
|
|
46
|
+
}
|
|
41
47
|
|
|
42
48
|
pi.on("session_start", async (_event, ctx) => {
|
|
43
|
-
|
|
44
|
-
|
|
49
|
+
unsubscribeQuotas?.();
|
|
50
|
+
currentProvider = ctx.model?.provider;
|
|
51
|
+
unsubscribeQuotas = pi.events.on(NEURALWATT_QUOTAS_UPDATED_EVENT, (data) =>
|
|
52
|
+
handleQuotas(ctx, data),
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
if (currentProvider !== "neuralwatt") return;
|
|
45
56
|
clearAlertState();
|
|
46
57
|
});
|
|
47
58
|
|
|
48
59
|
pi.on("model_select", (_event, ctx) => {
|
|
49
|
-
|
|
60
|
+
currentProvider = ctx.model?.provider;
|
|
50
61
|
});
|
|
51
62
|
|
|
52
63
|
pi.on("session_before_switch", (_event, ctx) => {
|
|
53
|
-
|
|
64
|
+
currentProvider = ctx.model?.provider;
|
|
54
65
|
});
|
|
55
66
|
|
|
56
67
|
pi.on("session_shutdown", () => {
|
|
57
|
-
|
|
68
|
+
unsubscribeQuotas?.();
|
|
69
|
+
unsubscribeQuotas = undefined;
|
|
70
|
+
currentProvider = undefined;
|
|
58
71
|
clearAlertState();
|
|
59
72
|
});
|
|
60
73
|
|
|
@@ -57,7 +57,7 @@ export default async function (pi: ExtensionAPI) {
|
|
|
57
57
|
let enabled = configLoader.getConfig().subBarIntegration.enabled;
|
|
58
58
|
let subCoreReady = false;
|
|
59
59
|
let currentProvider: string | undefined;
|
|
60
|
-
let
|
|
60
|
+
let unsubscribeQuotas: (() => void) | undefined;
|
|
61
61
|
|
|
62
62
|
// Listen for config changes at runtime
|
|
63
63
|
pi.events.on(NEURALWATT_CONFIG_UPDATED_EVENT, (data: unknown) => {
|
|
@@ -82,32 +82,35 @@ export default async function (pi: ExtensionAPI) {
|
|
|
82
82
|
pi.events.emit(NEURALWATT_QUOTAS_REQUEST_EVENT, undefined);
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
-
|
|
85
|
+
// The quota handler runs on the shared event bus, so it must only touch a
|
|
86
|
+
// session ctx captured by a live session-scoped subscription: pi
|
|
87
|
+
// invalidates session-bound ctx after session replacement (newSession/
|
|
88
|
+
// fork/switchSession/reload), and dereferencing a stale ctx throws. We
|
|
89
|
+
// subscribe in session_start (capturing the fresh ctx in the closure) and
|
|
90
|
+
// unsubscribe in session_shutdown, before the ctx can go stale.
|
|
91
|
+
function handleQuotas(ctx: ExtensionContext, data: unknown): void {
|
|
86
92
|
if (!isActive() || !subCoreReady || !enabled) return;
|
|
87
93
|
if (!data || typeof data !== "object") return;
|
|
88
94
|
const { quotas } = data as NeuralwattQuotasUpdatedPayload;
|
|
89
95
|
emitUsage(quotas);
|
|
90
96
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
"neuralwatt-usage",
|
|
94
|
-
formatStatus(quotas, currentContext.ui.theme),
|
|
95
|
-
);
|
|
96
|
-
}
|
|
97
|
-
});
|
|
97
|
+
ctx.ui.setStatus("neuralwatt-usage", formatStatus(quotas, ctx.ui.theme));
|
|
98
|
+
}
|
|
98
99
|
|
|
99
100
|
pi.events.on("sub-core:ready", () => {
|
|
100
101
|
subCoreReady = true;
|
|
101
102
|
});
|
|
102
103
|
|
|
103
104
|
pi.on("session_start", async (_event, ctx) => {
|
|
105
|
+
unsubscribeQuotas?.();
|
|
104
106
|
currentProvider = ctx.model?.provider;
|
|
105
|
-
|
|
107
|
+
unsubscribeQuotas = pi.events.on(NEURALWATT_QUOTAS_UPDATED_EVENT, (data) =>
|
|
108
|
+
handleQuotas(ctx, data),
|
|
109
|
+
);
|
|
106
110
|
});
|
|
107
111
|
|
|
108
112
|
pi.on("model_select", async (_event, ctx) => {
|
|
109
113
|
currentProvider = ctx.model?.provider;
|
|
110
|
-
currentContext = ctx;
|
|
111
114
|
|
|
112
115
|
if (subCoreReady && isActive() && enabled) {
|
|
113
116
|
requestQuotas();
|
|
@@ -115,8 +118,9 @@ export default async function (pi: ExtensionAPI) {
|
|
|
115
118
|
});
|
|
116
119
|
|
|
117
120
|
pi.on("session_shutdown", () => {
|
|
121
|
+
unsubscribeQuotas?.();
|
|
122
|
+
unsubscribeQuotas = undefined;
|
|
118
123
|
currentProvider = undefined;
|
|
119
|
-
currentContext = undefined;
|
|
120
124
|
});
|
|
121
125
|
|
|
122
126
|
pi.events.on(NEURALWATT_EXTENSIONS_REQUEST_EVENT, () => {
|
package/package.json
CHANGED
package/schema.json
CHANGED
|
@@ -31,6 +31,10 @@
|
|
|
31
31
|
"NeuralwattProviderConfig": {
|
|
32
32
|
"additionalProperties": false,
|
|
33
33
|
"properties": {
|
|
34
|
+
"includeAliasedModelIds": {
|
|
35
|
+
"description": "Include alternate creator-scoped Neuralwatt model IDs in the model picker.",
|
|
36
|
+
"type": "boolean"
|
|
37
|
+
},
|
|
34
38
|
"includeEarlyAccessModels": {
|
|
35
39
|
"description": "Include early-access Neuralwatt models discovered via the authenticated API.",
|
|
36
40
|
"type": "boolean"
|
package/src/config/defaults.ts
CHANGED
package/src/config/loader.ts
CHANGED
|
@@ -18,6 +18,9 @@ function normalizeResolvedConfig(
|
|
|
18
18
|
includeLegacyModelIds:
|
|
19
19
|
config.provider?.includeLegacyModelIds ??
|
|
20
20
|
DEFAULT_CONFIG.provider.includeLegacyModelIds,
|
|
21
|
+
includeAliasedModelIds:
|
|
22
|
+
config.provider?.includeAliasedModelIds ??
|
|
23
|
+
DEFAULT_CONFIG.provider.includeAliasedModelIds,
|
|
21
24
|
includeEarlyAccessModels:
|
|
22
25
|
config.provider?.includeEarlyAccessModels ??
|
|
23
26
|
DEFAULT_CONFIG.provider.includeEarlyAccessModels,
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { Migration } from "@aliou/pi-utils-settings";
|
|
2
|
+
import type { NeuralwattConfig } from "../types";
|
|
3
|
+
|
|
4
|
+
/** The provider section before alias IDs got a separate setting. */
|
|
5
|
+
interface PreviousProviderConfig {
|
|
6
|
+
includeLegacyModelIds?: boolean;
|
|
7
|
+
includeAliasedModelIds?: boolean;
|
|
8
|
+
includeEarlyAccessModels?: boolean;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function previousProvider(
|
|
12
|
+
config: NeuralwattConfig,
|
|
13
|
+
): PreviousProviderConfig | undefined {
|
|
14
|
+
if (!("provider" in config)) return undefined;
|
|
15
|
+
const { provider } = config;
|
|
16
|
+
return provider && typeof provider === "object"
|
|
17
|
+
? (provider as PreviousProviderConfig)
|
|
18
|
+
: undefined;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Creator-scoped active model IDs were split out of the legacy model ID setting.
|
|
23
|
+
* Preserve behavior for users who had explicitly enabled legacy model IDs.
|
|
24
|
+
*/
|
|
25
|
+
export const enableAliasesForLegacyUsersMigration: Migration<NeuralwattConfig> =
|
|
26
|
+
{
|
|
27
|
+
name: "enable-alias-model-ids-for-legacy-users",
|
|
28
|
+
shouldRun: (config) => {
|
|
29
|
+
const provider = previousProvider(config);
|
|
30
|
+
return (
|
|
31
|
+
provider?.includeLegacyModelIds === true &&
|
|
32
|
+
provider.includeAliasedModelIds === undefined
|
|
33
|
+
);
|
|
34
|
+
},
|
|
35
|
+
message:
|
|
36
|
+
"[neuralwatt] active model aliases now use `provider.includeAliasedModelIds`; it was enabled because legacy model IDs were enabled.",
|
|
37
|
+
run: (config) => {
|
|
38
|
+
const provider = previousProvider(config);
|
|
39
|
+
if (!provider) return config;
|
|
40
|
+
|
|
41
|
+
return {
|
|
42
|
+
...config,
|
|
43
|
+
provider: {
|
|
44
|
+
...provider,
|
|
45
|
+
includeAliasedModelIds: true,
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
},
|
|
49
|
+
};
|
|
@@ -7,13 +7,16 @@ export {
|
|
|
7
7
|
flatToNestedConfigMigration,
|
|
8
8
|
} from "./02-flat-to-nested-config";
|
|
9
9
|
export { renameHiddenToEarlyAccessMigration } from "./03-rename-hidden-to-early-access";
|
|
10
|
+
export { enableAliasesForLegacyUsersMigration } from "./04-enable-aliases-for-legacy-users";
|
|
10
11
|
|
|
11
12
|
import { disableLegacyModelIdsByDefaultMigration } from "./01-disable-legacy-model-ids-by-default";
|
|
12
13
|
import { flatToNestedConfigMigration } from "./02-flat-to-nested-config";
|
|
13
14
|
import { renameHiddenToEarlyAccessMigration } from "./03-rename-hidden-to-early-access";
|
|
15
|
+
import { enableAliasesForLegacyUsersMigration } from "./04-enable-aliases-for-legacy-users";
|
|
14
16
|
|
|
15
17
|
export const migrations: Migration<NeuralwattConfig>[] = [
|
|
16
18
|
disableLegacyModelIdsByDefaultMigration,
|
|
17
19
|
flatToNestedConfigMigration,
|
|
18
20
|
renameHiddenToEarlyAccessMigration,
|
|
21
|
+
enableAliasesForLegacyUsersMigration,
|
|
19
22
|
];
|
package/src/config/types.ts
CHANGED
|
@@ -2,6 +2,9 @@ export interface NeuralwattProviderConfig {
|
|
|
2
2
|
/** Include legacy Neuralwatt model IDs in the model picker. */
|
|
3
3
|
includeLegacyModelIds?: boolean;
|
|
4
4
|
|
|
5
|
+
/** Include alternate creator-scoped Neuralwatt model IDs in the model picker. */
|
|
6
|
+
includeAliasedModelIds?: boolean;
|
|
7
|
+
|
|
5
8
|
/** Include early-access Neuralwatt models discovered via the authenticated API. */
|
|
6
9
|
includeEarlyAccessModels?: boolean;
|
|
7
10
|
}
|
|
@@ -41,6 +44,7 @@ export interface NeuralwattConfig {
|
|
|
41
44
|
export interface ResolvedNeuralwattConfig {
|
|
42
45
|
provider: {
|
|
43
46
|
includeLegacyModelIds: boolean;
|
|
47
|
+
includeAliasedModelIds: boolean;
|
|
44
48
|
includeEarlyAccessModels: boolean;
|
|
45
49
|
};
|
|
46
50
|
quotaCommand: {
|