@aliou/pi-neuralwatt 0.7.6 → 0.8.0
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 +4 -2
- package/{src/extensions → extensions}/command-quotas/command.ts +2 -2
- package/extensions/command-quotas/components/progress-bar.ts +38 -0
- package/{src/extensions → extensions}/command-quotas/components/quota-tabs.ts +4 -4
- package/{src/extensions → extensions}/command-quotas/components/quotas-display.ts +1 -1
- package/{src/extensions → extensions}/command-quotas/index.ts +3 -3
- package/extensions/provider/commands/settings/index.ts +246 -0
- package/{src/extensions → extensions}/provider/index.ts +28 -20
- package/{src/extensions → extensions}/provider/models/hidden.ts +3 -3
- package/{src/extensions → extensions}/provider/quota-store.ts +4 -4
- package/{src/extensions → extensions}/provider/sse-quotas.ts +1 -1
- package/{src/extensions → extensions}/quota-warnings/index.ts +6 -7
- package/{src/extensions → extensions}/quota-warnings/notifier.ts +2 -2
- package/{src/extensions → extensions}/sub-bar-integration/index.ts +9 -10
- package/{src/extensions → extensions}/sub-bar-integration/snapshot.ts +3 -3
- package/package.json +20 -14
- package/schema.json +50 -6
- package/src/config/defaults.ts +17 -0
- package/src/config/index.ts +9 -0
- package/src/config/loader.ts +74 -0
- package/src/config/migration/01-disable-legacy-model-ids-by-default.ts +44 -0
- package/src/config/migration/02-flat-to-nested-config.ts +149 -0
- package/src/config/migration/index.ts +16 -0
- package/src/config/types.ts +77 -0
- package/src/{types/quota-events.ts → events.ts} +25 -13
- package/src/lib/neuralwatt-api.ts +1 -1
- package/src/types/quota-result.ts +12 -0
- package/src/utils/quota-bar.ts +0 -38
- package/src/config.ts +0 -210
- /package/{src/lib/env.ts → extensions/_shared/auth.ts} +0 -0
- /package/{src/extensions → extensions}/provider/context-overflow.ts +0 -0
- /package/{src/extensions → extensions}/provider/models/cache.ts +0 -0
- /package/{src/extensions → extensions}/provider/models/index.ts +0 -0
- /package/{src/extensions → extensions}/provider/models/legacy.ts +0 -0
- /package/{src/extensions → extensions}/provider/models/public-models.ts +0 -0
- /package/{src/extensions → extensions}/provider/rate-limit-error.ts +0 -0
- /package/{src/extensions → extensions}/provider/stream-simple.ts +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aliou/pi-neuralwatt",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"private": false,
|
|
@@ -15,10 +15,10 @@
|
|
|
15
15
|
},
|
|
16
16
|
"pi": {
|
|
17
17
|
"extensions": [
|
|
18
|
-
"./
|
|
19
|
-
"./
|
|
20
|
-
"./
|
|
21
|
-
"./
|
|
18
|
+
"./extensions/provider/index.ts",
|
|
19
|
+
"./extensions/command-quotas/index.ts",
|
|
20
|
+
"./extensions/quota-warnings/index.ts",
|
|
21
|
+
"./extensions/sub-bar-integration/index.ts"
|
|
22
22
|
],
|
|
23
23
|
"video": "https://assets.aliou.me/github/aliou/pi-neuralwatt/demo.mp4"
|
|
24
24
|
},
|
|
@@ -27,25 +27,28 @@
|
|
|
27
27
|
},
|
|
28
28
|
"files": [
|
|
29
29
|
"src",
|
|
30
|
+
"extensions",
|
|
30
31
|
"schema.json",
|
|
31
32
|
"README.md",
|
|
32
|
-
"!src/**/*.test.ts"
|
|
33
|
+
"!src/**/*.test.ts",
|
|
34
|
+
"!extensions/**/*.test.ts"
|
|
33
35
|
],
|
|
34
36
|
"dependencies": {
|
|
35
|
-
"@aliou/pi-utils-settings": "^0.
|
|
36
|
-
"@aliou/pi-utils-ui": "^0.
|
|
37
|
-
"@earendil-works/pi-ai": "$@earendil-works/pi-coding-agent"
|
|
37
|
+
"@aliou/pi-utils-settings": "^0.18.0",
|
|
38
|
+
"@aliou/pi-utils-ui": "^0.5.0"
|
|
38
39
|
},
|
|
39
40
|
"peerDependencies": {
|
|
41
|
+
"@earendil-works/pi-ai": "*",
|
|
40
42
|
"@earendil-works/pi-coding-agent": "*",
|
|
41
43
|
"@earendil-works/pi-tui": "*"
|
|
42
44
|
},
|
|
43
45
|
"devDependencies": {
|
|
44
|
-
"@aliou/biome-plugins": "^0.
|
|
46
|
+
"@aliou/biome-plugins": "^0.11.0",
|
|
45
47
|
"@biomejs/biome": "^2.4.15",
|
|
46
48
|
"@changesets/cli": "^2.27.11",
|
|
47
|
-
"@earendil-works/pi-
|
|
48
|
-
"@earendil-works/pi-
|
|
49
|
+
"@earendil-works/pi-ai": "0.80.3",
|
|
50
|
+
"@earendil-works/pi-coding-agent": "0.80.3",
|
|
51
|
+
"@earendil-works/pi-tui": "0.80.3",
|
|
49
52
|
"@types/node": "^25.0.10",
|
|
50
53
|
"husky": "^9.1.7",
|
|
51
54
|
"ts-json-schema-generator": "^2.4.0",
|
|
@@ -64,8 +67,8 @@
|
|
|
64
67
|
"format": "biome check --write",
|
|
65
68
|
"test": "vitest run",
|
|
66
69
|
"test:watch": "vitest",
|
|
67
|
-
"gen:schema": "ts-json-schema-generator --path src/config.ts --type NeuralwattConfig --no-type-check -o schema.json",
|
|
68
|
-
"check:schema": "ts-json-schema-generator --path src/config.ts --type NeuralwattConfig --no-type-check -o /tmp/schema-check.json && diff -q schema.json /tmp/schema-check.json",
|
|
70
|
+
"gen:schema": "ts-json-schema-generator --path src/config/types.ts --type NeuralwattConfig --no-type-check -o schema.json",
|
|
71
|
+
"check:schema": "ts-json-schema-generator --path src/config/types.ts --type NeuralwattConfig --no-type-check -o /tmp/schema-check.json && diff -q schema.json /tmp/schema-check.json",
|
|
69
72
|
"check:lockfile": "pnpm install --frozen-lockfile --ignore-scripts",
|
|
70
73
|
"prepare": "[ -d .git ] && husky || true",
|
|
71
74
|
"changeset": "changeset",
|
|
@@ -74,6 +77,9 @@
|
|
|
74
77
|
},
|
|
75
78
|
"packageManager": "pnpm@10.26.1",
|
|
76
79
|
"peerDependenciesMeta": {
|
|
80
|
+
"@earendil-works/pi-ai": {
|
|
81
|
+
"optional": true
|
|
82
|
+
},
|
|
77
83
|
"@earendil-works/pi-coding-agent": {
|
|
78
84
|
"optional": true
|
|
79
85
|
},
|
package/schema.json
CHANGED
|
@@ -3,6 +3,32 @@
|
|
|
3
3
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
4
4
|
"definitions": {
|
|
5
5
|
"NeuralwattConfig": {
|
|
6
|
+
"additionalProperties": false,
|
|
7
|
+
"properties": {
|
|
8
|
+
"$schema": {
|
|
9
|
+
"description": "$schema URL for editor autocomplete.",
|
|
10
|
+
"type": "string"
|
|
11
|
+
},
|
|
12
|
+
"provider": {
|
|
13
|
+
"$ref": "#/definitions/NeuralwattProviderConfig",
|
|
14
|
+
"description": "Provider/model behavior."
|
|
15
|
+
},
|
|
16
|
+
"quotaCommand": {
|
|
17
|
+
"$ref": "#/definitions/NeuralwattQuotaCommandConfig",
|
|
18
|
+
"description": "Quota command feature."
|
|
19
|
+
},
|
|
20
|
+
"quotaWarnings": {
|
|
21
|
+
"$ref": "#/definitions/NeuralwattQuotaWarningsConfig",
|
|
22
|
+
"description": "Quota warning feature."
|
|
23
|
+
},
|
|
24
|
+
"subBarIntegration": {
|
|
25
|
+
"$ref": "#/definitions/NeuralwattSubBarIntegrationConfig",
|
|
26
|
+
"description": "Sub-bar/status-bar integration feature."
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"type": "object"
|
|
30
|
+
},
|
|
31
|
+
"NeuralwattProviderConfig": {
|
|
6
32
|
"additionalProperties": false,
|
|
7
33
|
"properties": {
|
|
8
34
|
"includeHiddenModels": {
|
|
@@ -12,16 +38,34 @@
|
|
|
12
38
|
"includeLegacyModelIds": {
|
|
13
39
|
"description": "Include legacy Neuralwatt model IDs in the model picker.",
|
|
14
40
|
"type": "boolean"
|
|
15
|
-
}
|
|
16
|
-
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
"type": "object"
|
|
44
|
+
},
|
|
45
|
+
"NeuralwattQuotaCommandConfig": {
|
|
46
|
+
"additionalProperties": false,
|
|
47
|
+
"properties": {
|
|
48
|
+
"enabled": {
|
|
17
49
|
"description": "Show the quota command (/neuralwatt:quota).",
|
|
18
50
|
"type": "boolean"
|
|
19
|
-
}
|
|
20
|
-
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
"type": "object"
|
|
54
|
+
},
|
|
55
|
+
"NeuralwattQuotaWarningsConfig": {
|
|
56
|
+
"additionalProperties": false,
|
|
57
|
+
"properties": {
|
|
58
|
+
"enabled": {
|
|
21
59
|
"description": "Show quota warnings when credits or energy are low.",
|
|
22
60
|
"type": "boolean"
|
|
23
|
-
}
|
|
24
|
-
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
"type": "object"
|
|
64
|
+
},
|
|
65
|
+
"NeuralwattSubBarIntegrationConfig": {
|
|
66
|
+
"additionalProperties": false,
|
|
67
|
+
"properties": {
|
|
68
|
+
"enabled": {
|
|
25
69
|
"description": "Show usage in the sub-bar / status bar.",
|
|
26
70
|
"type": "boolean"
|
|
27
71
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ResolvedNeuralwattConfig } from "./types";
|
|
2
|
+
|
|
3
|
+
export const DEFAULT_CONFIG: ResolvedNeuralwattConfig = {
|
|
4
|
+
provider: {
|
|
5
|
+
includeLegacyModelIds: false,
|
|
6
|
+
includeHiddenModels: false,
|
|
7
|
+
},
|
|
8
|
+
quotaCommand: {
|
|
9
|
+
enabled: true,
|
|
10
|
+
},
|
|
11
|
+
quotaWarnings: {
|
|
12
|
+
enabled: true,
|
|
13
|
+
},
|
|
14
|
+
subBarIntegration: {
|
|
15
|
+
enabled: true,
|
|
16
|
+
},
|
|
17
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { DEFAULT_CONFIG } from "./defaults";
|
|
2
|
+
export { configLoader } from "./loader";
|
|
3
|
+
export { migrations } from "./migration";
|
|
4
|
+
export type {
|
|
5
|
+
NeuralwattConfig,
|
|
6
|
+
NeuralwattRawConfig,
|
|
7
|
+
PreviousNeuralwattConfig,
|
|
8
|
+
ResolvedNeuralwattConfig,
|
|
9
|
+
} from "./types";
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { buildSchemaUrl, ConfigLoader } from "@aliou/pi-utils-settings";
|
|
2
|
+
import packageJson from "../../package.json";
|
|
3
|
+
import { DEFAULT_CONFIG } from "./defaults";
|
|
4
|
+
import { migrations } from "./migration";
|
|
5
|
+
import type { NeuralwattRawConfig, ResolvedNeuralwattConfig } from "./types";
|
|
6
|
+
|
|
7
|
+
type ConfigRecord = Record<string, unknown>;
|
|
8
|
+
|
|
9
|
+
type MaybeEnabled = { enabled?: boolean };
|
|
10
|
+
type MaybeProvider = {
|
|
11
|
+
includeLegacyModelIds?: boolean;
|
|
12
|
+
includeHiddenModels?: boolean;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
function featureEnabled(value: unknown, fallback: boolean): boolean {
|
|
16
|
+
if (typeof value === "boolean") return value;
|
|
17
|
+
if (value && typeof value === "object") {
|
|
18
|
+
const { enabled } = value as MaybeEnabled;
|
|
19
|
+
if (typeof enabled === "boolean") return enabled;
|
|
20
|
+
}
|
|
21
|
+
return fallback;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function normalizeResolvedConfig(
|
|
25
|
+
resolved: ResolvedNeuralwattConfig,
|
|
26
|
+
): ResolvedNeuralwattConfig {
|
|
27
|
+
const record = resolved as unknown as ConfigRecord;
|
|
28
|
+
const provider =
|
|
29
|
+
record.provider && typeof record.provider === "object"
|
|
30
|
+
? (record.provider as MaybeProvider)
|
|
31
|
+
: {};
|
|
32
|
+
|
|
33
|
+
return {
|
|
34
|
+
provider: {
|
|
35
|
+
includeLegacyModelIds:
|
|
36
|
+
provider.includeLegacyModelIds ??
|
|
37
|
+
(typeof record.includeLegacyModelIds === "boolean"
|
|
38
|
+
? record.includeLegacyModelIds
|
|
39
|
+
: DEFAULT_CONFIG.provider.includeLegacyModelIds),
|
|
40
|
+
includeHiddenModels:
|
|
41
|
+
provider.includeHiddenModels ??
|
|
42
|
+
(typeof record.includeHiddenModels === "boolean"
|
|
43
|
+
? record.includeHiddenModels
|
|
44
|
+
: DEFAULT_CONFIG.provider.includeHiddenModels),
|
|
45
|
+
},
|
|
46
|
+
quotaCommand: {
|
|
47
|
+
enabled: featureEnabled(
|
|
48
|
+
record.quotaCommand,
|
|
49
|
+
DEFAULT_CONFIG.quotaCommand.enabled,
|
|
50
|
+
),
|
|
51
|
+
},
|
|
52
|
+
quotaWarnings: {
|
|
53
|
+
enabled: featureEnabled(
|
|
54
|
+
record.quotaWarnings,
|
|
55
|
+
DEFAULT_CONFIG.quotaWarnings.enabled,
|
|
56
|
+
),
|
|
57
|
+
},
|
|
58
|
+
subBarIntegration: {
|
|
59
|
+
enabled: featureEnabled(
|
|
60
|
+
record.subBarIntegration,
|
|
61
|
+
DEFAULT_CONFIG.subBarIntegration.enabled,
|
|
62
|
+
),
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export const configLoader = new ConfigLoader<
|
|
68
|
+
NeuralwattRawConfig,
|
|
69
|
+
ResolvedNeuralwattConfig
|
|
70
|
+
>("neuralwatt", DEFAULT_CONFIG, {
|
|
71
|
+
migrations,
|
|
72
|
+
schemaUrl: buildSchemaUrl("@aliou/pi-neuralwatt", packageJson.version),
|
|
73
|
+
afterMerge: normalizeResolvedConfig,
|
|
74
|
+
});
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { Migration } from "@aliou/pi-utils-settings";
|
|
2
|
+
import type { NeuralwattConfig, PreviousNeuralwattConfig } from "../types";
|
|
3
|
+
|
|
4
|
+
type MigrationConfig = PreviousNeuralwattConfig | NeuralwattConfig;
|
|
5
|
+
|
|
6
|
+
type MutableConfigRecord = Record<string, unknown>;
|
|
7
|
+
|
|
8
|
+
function hasOwn(record: MutableConfigRecord, key: string): boolean {
|
|
9
|
+
return Object.hasOwn(record, key);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function hasNestedConfig(config: MigrationConfig): boolean {
|
|
13
|
+
return Boolean(
|
|
14
|
+
("provider" in config && config.provider) ||
|
|
15
|
+
(config.quotaCommand && typeof config.quotaCommand === "object") ||
|
|
16
|
+
(config.quotaWarnings && typeof config.quotaWarnings === "object") ||
|
|
17
|
+
(config.subBarIntegration &&
|
|
18
|
+
typeof config.subBarIntegration === "object"),
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function isPreviousConfigWithoutLegacyDefault(
|
|
23
|
+
config: MigrationConfig,
|
|
24
|
+
): config is PreviousNeuralwattConfig {
|
|
25
|
+
return (
|
|
26
|
+
!hasNestedConfig(config) &&
|
|
27
|
+
!hasOwn(config as MutableConfigRecord, "includeLegacyModelIds")
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export const disableLegacyModelIdsByDefaultMigration: Migration<MigrationConfig> =
|
|
32
|
+
{
|
|
33
|
+
name: "disable-legacy-model-ids-by-default",
|
|
34
|
+
shouldRun: isPreviousConfigWithoutLegacyDefault,
|
|
35
|
+
message:
|
|
36
|
+
"[neuralwatt] legacy model IDs (ids including the provider and the quantization) are disabled by default. You can enable them with /neuralwatt:settings.",
|
|
37
|
+
run: (config) => {
|
|
38
|
+
const previous = config as PreviousNeuralwattConfig;
|
|
39
|
+
return {
|
|
40
|
+
...previous,
|
|
41
|
+
includeLegacyModelIds: false,
|
|
42
|
+
};
|
|
43
|
+
},
|
|
44
|
+
};
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { constants } from "node:fs";
|
|
2
|
+
import { copyFile } from "node:fs/promises";
|
|
3
|
+
import { basename, dirname, join } from "node:path";
|
|
4
|
+
import type { Migration } from "@aliou/pi-utils-settings";
|
|
5
|
+
import packageJson from "../../../package.json";
|
|
6
|
+
import type { NeuralwattConfig, PreviousNeuralwattConfig } from "../types";
|
|
7
|
+
|
|
8
|
+
type MigrationConfig = PreviousNeuralwattConfig | NeuralwattConfig;
|
|
9
|
+
|
|
10
|
+
type FlatConfigKey = keyof Omit<PreviousNeuralwattConfig, "$schema">;
|
|
11
|
+
type MutableConfigRecord = Record<string, unknown>;
|
|
12
|
+
|
|
13
|
+
const FLAT_CONFIG_KEYS = [
|
|
14
|
+
"quotaCommand",
|
|
15
|
+
"quotaWarnings",
|
|
16
|
+
"subBarIntegration",
|
|
17
|
+
"includeLegacyModelIds",
|
|
18
|
+
"includeHiddenModels",
|
|
19
|
+
] as const satisfies readonly FlatConfigKey[];
|
|
20
|
+
|
|
21
|
+
const FLAT_CONFIG_MIGRATION_MESSAGE =
|
|
22
|
+
"Config migrated to the nested format. A backup was written next to the original config file.";
|
|
23
|
+
|
|
24
|
+
function booleanValue(
|
|
25
|
+
record: MutableConfigRecord,
|
|
26
|
+
key: FlatConfigKey,
|
|
27
|
+
): boolean | undefined {
|
|
28
|
+
return typeof record[key] === "boolean"
|
|
29
|
+
? (record[key] as boolean)
|
|
30
|
+
: undefined;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function isObject(value: unknown): value is Record<string, unknown> {
|
|
34
|
+
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function isPreviousConfig(
|
|
38
|
+
config: MigrationConfig,
|
|
39
|
+
): config is PreviousNeuralwattConfig {
|
|
40
|
+
const record = config as MutableConfigRecord;
|
|
41
|
+
return FLAT_CONFIG_KEYS.some((key) => typeof record[key] === "boolean");
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export async function backupConfig(filePath: string): Promise<void> {
|
|
45
|
+
const dir = dirname(filePath);
|
|
46
|
+
const base = basename(filePath, ".json");
|
|
47
|
+
const backupPath = join(
|
|
48
|
+
dir,
|
|
49
|
+
`${base}.v${packageJson.version}-flat-config.json`,
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
try {
|
|
53
|
+
await copyFile(filePath, backupPath, constants.COPYFILE_EXCL);
|
|
54
|
+
} catch (error) {
|
|
55
|
+
if (
|
|
56
|
+
error &&
|
|
57
|
+
typeof error === "object" &&
|
|
58
|
+
"code" in error &&
|
|
59
|
+
error.code === "EEXIST"
|
|
60
|
+
) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
throw error;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export const flatToNestedConfigMigration: Migration<MigrationConfig> = {
|
|
68
|
+
name: "flat-to-nested-config",
|
|
69
|
+
shouldRun: isPreviousConfig,
|
|
70
|
+
message: FLAT_CONFIG_MIGRATION_MESSAGE,
|
|
71
|
+
run: async (config, filePath) => {
|
|
72
|
+
await backupConfig(filePath);
|
|
73
|
+
|
|
74
|
+
const previous = config as PreviousNeuralwattConfig;
|
|
75
|
+
const nestedConfig = config as NeuralwattConfig;
|
|
76
|
+
const record = previous as MutableConfigRecord;
|
|
77
|
+
const nested: NeuralwattConfig = {
|
|
78
|
+
provider: {
|
|
79
|
+
...(isObject(nestedConfig.provider) ? nestedConfig.provider : {}),
|
|
80
|
+
},
|
|
81
|
+
quotaCommand: isObject(nestedConfig.quotaCommand)
|
|
82
|
+
? { ...nestedConfig.quotaCommand }
|
|
83
|
+
: {},
|
|
84
|
+
quotaWarnings: isObject(nestedConfig.quotaWarnings)
|
|
85
|
+
? { ...nestedConfig.quotaWarnings }
|
|
86
|
+
: {},
|
|
87
|
+
subBarIntegration: isObject(nestedConfig.subBarIntegration)
|
|
88
|
+
? { ...nestedConfig.subBarIntegration }
|
|
89
|
+
: {},
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
const includeLegacyModelIds = booleanValue(record, "includeLegacyModelIds");
|
|
93
|
+
if (
|
|
94
|
+
nested.provider?.includeLegacyModelIds === undefined &&
|
|
95
|
+
includeLegacyModelIds !== undefined
|
|
96
|
+
) {
|
|
97
|
+
nested.provider = {
|
|
98
|
+
...nested.provider,
|
|
99
|
+
includeLegacyModelIds,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const includeHiddenModels = booleanValue(record, "includeHiddenModels");
|
|
104
|
+
if (
|
|
105
|
+
nested.provider?.includeHiddenModels === undefined &&
|
|
106
|
+
includeHiddenModels !== undefined
|
|
107
|
+
) {
|
|
108
|
+
nested.provider = {
|
|
109
|
+
...nested.provider,
|
|
110
|
+
includeHiddenModels,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const quotaCommand = booleanValue(record, "quotaCommand");
|
|
115
|
+
if (
|
|
116
|
+
nested.quotaCommand?.enabled === undefined &&
|
|
117
|
+
quotaCommand !== undefined
|
|
118
|
+
) {
|
|
119
|
+
nested.quotaCommand = {
|
|
120
|
+
...nested.quotaCommand,
|
|
121
|
+
enabled: quotaCommand,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const quotaWarnings = booleanValue(record, "quotaWarnings");
|
|
126
|
+
if (
|
|
127
|
+
nested.quotaWarnings?.enabled === undefined &&
|
|
128
|
+
quotaWarnings !== undefined
|
|
129
|
+
) {
|
|
130
|
+
nested.quotaWarnings = {
|
|
131
|
+
...nested.quotaWarnings,
|
|
132
|
+
enabled: quotaWarnings,
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const subBarIntegration = booleanValue(record, "subBarIntegration");
|
|
137
|
+
if (
|
|
138
|
+
nested.subBarIntegration?.enabled === undefined &&
|
|
139
|
+
subBarIntegration !== undefined
|
|
140
|
+
) {
|
|
141
|
+
nested.subBarIntegration = {
|
|
142
|
+
...nested.subBarIntegration,
|
|
143
|
+
enabled: subBarIntegration,
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return nested;
|
|
148
|
+
},
|
|
149
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Migration } from "@aliou/pi-utils-settings";
|
|
2
|
+
import type { NeuralwattRawConfig } from "../types";
|
|
3
|
+
|
|
4
|
+
export { disableLegacyModelIdsByDefaultMigration } from "./01-disable-legacy-model-ids-by-default";
|
|
5
|
+
export {
|
|
6
|
+
backupConfig,
|
|
7
|
+
flatToNestedConfigMigration,
|
|
8
|
+
} from "./02-flat-to-nested-config";
|
|
9
|
+
|
|
10
|
+
import { disableLegacyModelIdsByDefaultMigration } from "./01-disable-legacy-model-ids-by-default";
|
|
11
|
+
import { flatToNestedConfigMigration } from "./02-flat-to-nested-config";
|
|
12
|
+
|
|
13
|
+
export const migrations: Migration<NeuralwattRawConfig>[] = [
|
|
14
|
+
disableLegacyModelIdsByDefaultMigration,
|
|
15
|
+
flatToNestedConfigMigration,
|
|
16
|
+
];
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
export interface PreviousNeuralwattConfig {
|
|
2
|
+
/** $schema URL for editor autocomplete. */
|
|
3
|
+
$schema?: string;
|
|
4
|
+
|
|
5
|
+
/** Show the quota command (/neuralwatt:quota). */
|
|
6
|
+
quotaCommand?: boolean;
|
|
7
|
+
|
|
8
|
+
/** Show quota warnings when credits or energy are low. */
|
|
9
|
+
quotaWarnings?: boolean;
|
|
10
|
+
|
|
11
|
+
/** Show usage in the sub-bar / status bar. */
|
|
12
|
+
subBarIntegration?: boolean;
|
|
13
|
+
|
|
14
|
+
/** Include legacy Neuralwatt model IDs in the model picker. */
|
|
15
|
+
includeLegacyModelIds?: boolean;
|
|
16
|
+
|
|
17
|
+
/** Include hidden Neuralwatt models discovered via the authenticated API. */
|
|
18
|
+
includeHiddenModels?: boolean;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface NeuralwattProviderConfig {
|
|
22
|
+
/** Include legacy Neuralwatt model IDs in the model picker. */
|
|
23
|
+
includeLegacyModelIds?: boolean;
|
|
24
|
+
|
|
25
|
+
/** Include hidden Neuralwatt models discovered via the authenticated API. */
|
|
26
|
+
includeHiddenModels?: boolean;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface NeuralwattQuotaCommandConfig {
|
|
30
|
+
/** Show the quota command (/neuralwatt:quota). */
|
|
31
|
+
enabled?: boolean;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface NeuralwattQuotaWarningsConfig {
|
|
35
|
+
/** Show quota warnings when credits or energy are low. */
|
|
36
|
+
enabled?: boolean;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface NeuralwattSubBarIntegrationConfig {
|
|
40
|
+
/** Show usage in the sub-bar / status bar. */
|
|
41
|
+
enabled?: boolean;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface NeuralwattConfig {
|
|
45
|
+
/** $schema URL for editor autocomplete. */
|
|
46
|
+
$schema?: string;
|
|
47
|
+
|
|
48
|
+
/** Provider/model behavior. */
|
|
49
|
+
provider?: NeuralwattProviderConfig;
|
|
50
|
+
|
|
51
|
+
/** Quota command feature. */
|
|
52
|
+
quotaCommand?: NeuralwattQuotaCommandConfig;
|
|
53
|
+
|
|
54
|
+
/** Quota warning feature. */
|
|
55
|
+
quotaWarnings?: NeuralwattQuotaWarningsConfig;
|
|
56
|
+
|
|
57
|
+
/** Sub-bar/status-bar integration feature. */
|
|
58
|
+
subBarIntegration?: NeuralwattSubBarIntegrationConfig;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export type NeuralwattRawConfig = PreviousNeuralwattConfig | NeuralwattConfig;
|
|
62
|
+
|
|
63
|
+
export interface ResolvedNeuralwattConfig {
|
|
64
|
+
provider: {
|
|
65
|
+
includeLegacyModelIds: boolean;
|
|
66
|
+
includeHiddenModels: boolean;
|
|
67
|
+
};
|
|
68
|
+
quotaCommand: {
|
|
69
|
+
enabled: boolean;
|
|
70
|
+
};
|
|
71
|
+
quotaWarnings: {
|
|
72
|
+
enabled: boolean;
|
|
73
|
+
};
|
|
74
|
+
subBarIntegration: {
|
|
75
|
+
enabled: boolean;
|
|
76
|
+
};
|
|
77
|
+
}
|
|
@@ -1,6 +1,19 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ResolvedNeuralwattConfig } from "./config";
|
|
2
|
+
import type { NeuralwattQuotas } from "./types/quota-api";
|
|
2
3
|
|
|
3
|
-
export type
|
|
4
|
+
export type NeuralwattFeatureId =
|
|
5
|
+
| "quotaCommand"
|
|
6
|
+
| "quotaWarnings"
|
|
7
|
+
| "subBarIntegration";
|
|
8
|
+
|
|
9
|
+
export const NEURALWATT_EXTENSIONS_REQUEST_EVENT =
|
|
10
|
+
"neuralwatt:extensions:request" as const;
|
|
11
|
+
|
|
12
|
+
export const NEURALWATT_EXTENSIONS_REGISTER_EVENT =
|
|
13
|
+
"neuralwatt:extensions:register" as const;
|
|
14
|
+
|
|
15
|
+
export const NEURALWATT_CONFIG_UPDATED_EVENT =
|
|
16
|
+
"neuralwatt:config:updated" as const;
|
|
4
17
|
|
|
5
18
|
export const NEURALWATT_QUOTAS_UPDATED_EVENT =
|
|
6
19
|
"neuralwatt:quotas:updated" as const;
|
|
@@ -8,22 +21,21 @@ export const NEURALWATT_QUOTAS_UPDATED_EVENT =
|
|
|
8
21
|
export const NEURALWATT_QUOTAS_REQUEST_EVENT =
|
|
9
22
|
"neuralwatt:quotas:request" as const;
|
|
10
23
|
|
|
24
|
+
export interface NeuralwattExtensionsRegisterPayload {
|
|
25
|
+
feature: NeuralwattFeatureId;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface NeuralwattConfigUpdatedPayload {
|
|
29
|
+
config: ResolvedNeuralwattConfig;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export type QuotaSource = "header" | "api" | "sse";
|
|
33
|
+
|
|
11
34
|
export interface NeuralwattQuotasUpdatedPayload {
|
|
12
35
|
quotas: NeuralwattQuotas;
|
|
13
36
|
source: QuotaSource;
|
|
14
37
|
}
|
|
15
38
|
|
|
16
|
-
export type QuotasErrorKind =
|
|
17
|
-
| "cancelled"
|
|
18
|
-
| "timeout"
|
|
19
|
-
| "config"
|
|
20
|
-
| "http"
|
|
21
|
-
| "network";
|
|
22
|
-
|
|
23
|
-
export type QuotasResult =
|
|
24
|
-
| { success: true; data: { quotas: NeuralwattQuotas } }
|
|
25
|
-
| { success: false; error: { message: string; kind: QuotasErrorKind } };
|
|
26
|
-
|
|
27
39
|
/** Minimal quota data parsed from response headers */
|
|
28
40
|
export interface NeuralwattHeaderQuotas {
|
|
29
41
|
allowanceRemainingUsd: number;
|
|
@@ -3,7 +3,7 @@ import type {
|
|
|
3
3
|
NeuralwattApiModelsResponse,
|
|
4
4
|
} from "../types/models-api";
|
|
5
5
|
import type { NeuralwattQuotas } from "../types/quota-api";
|
|
6
|
-
import type { QuotasResult } from "../types/quota-
|
|
6
|
+
import type { QuotasResult } from "../types/quota-result";
|
|
7
7
|
|
|
8
8
|
const BASE_URL = "https://api.neuralwatt.com/v1";
|
|
9
9
|
const FETCH_TIMEOUT_MS = 15_000;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { NeuralwattQuotas } from "./quota-api";
|
|
2
|
+
|
|
3
|
+
export type QuotasErrorKind =
|
|
4
|
+
| "cancelled"
|
|
5
|
+
| "timeout"
|
|
6
|
+
| "config"
|
|
7
|
+
| "http"
|
|
8
|
+
| "network";
|
|
9
|
+
|
|
10
|
+
export type QuotasResult =
|
|
11
|
+
| { success: true; data: { quotas: NeuralwattQuotas } }
|
|
12
|
+
| { success: false; error: { message: string; kind: QuotasErrorKind } };
|
package/src/utils/quota-bar.ts
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import type { Theme } from "@earendil-works/pi-coding-agent";
|
|
2
|
-
|
|
3
1
|
export type Severity = "success" | "warning" | "error";
|
|
4
2
|
|
|
5
3
|
export function severityFromPercent(pct: number): Severity {
|
|
@@ -8,42 +6,6 @@ export function severityFromPercent(pct: number): Severity {
|
|
|
8
6
|
return "error";
|
|
9
7
|
}
|
|
10
8
|
|
|
11
|
-
export type BarStyle = "filled-used" | "filled-remaining";
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Render a progress bar.
|
|
15
|
-
*
|
|
16
|
-
* filled-used: filled region = used portion (colored by severity of remaining%)
|
|
17
|
-
* filled-remaining: filled region = remaining portion (colored by severity of remaining%)
|
|
18
|
-
*/
|
|
19
|
-
export function renderProgressBar(
|
|
20
|
-
percent: number,
|
|
21
|
-
width: number,
|
|
22
|
-
theme: Theme,
|
|
23
|
-
severity: Severity,
|
|
24
|
-
style: BarStyle = "filled-remaining",
|
|
25
|
-
): string {
|
|
26
|
-
const clamped = Math.max(0, Math.min(100, Math.round(percent)));
|
|
27
|
-
const filledCount = Math.round((clamped / 100) * width);
|
|
28
|
-
|
|
29
|
-
const parts: string[] = [];
|
|
30
|
-
for (let idx = 0; idx < width; idx++) {
|
|
31
|
-
const isFilled = idx < filledCount;
|
|
32
|
-
if (style === "filled-used") {
|
|
33
|
-
// filled = used (severity color), empty = remaining (dim)
|
|
34
|
-
parts.push(
|
|
35
|
-
isFilled ? theme.fg(severity, "\u2593") : theme.fg("success", "\u2591"),
|
|
36
|
-
);
|
|
37
|
-
} else {
|
|
38
|
-
// filled = remaining (severity color), empty = used (dim)
|
|
39
|
-
parts.push(
|
|
40
|
-
isFilled ? theme.fg(severity, "\u2588") : theme.fg("dim", "\u2591"),
|
|
41
|
-
);
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
return parts.join("");
|
|
45
|
-
}
|
|
46
|
-
|
|
47
9
|
export function percentCreditsRemaining(quotas: {
|
|
48
10
|
balance: { credits_remaining_usd: number; total_credits_usd: number };
|
|
49
11
|
}): number {
|