@victor-software-house/pi-openai-proxy 4.5.0 → 4.5.1
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/dist/config.d.mts +1 -1
- package/dist/config.mjs +1 -1
- package/dist/exposure.d.mts +9 -4
- package/dist/exposure.mjs +9 -8
- package/dist/index.mjs +20 -9
- package/dist/{schema-B2x0rLJN.d.mts → schema-CrOJW-mE.d.mts} +6 -6
- package/dist/{schema-IE4WK0Dj.mjs → schema-quaXHZsz.mjs} +0 -2
- package/extensions/proxy.ts +67 -24
- package/package.json +2 -2
package/dist/config.d.mts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
|
|
2
|
-
import { a as ZedSyncConfig, c as isModelExposureMode, d as normalizeConfig, f as saveConfigToFile, i as PublicModelIdMode, l as isPublicModelIdMode, n as ModelExposureMode, o as configToEnv, r as ProxyConfig, s as getConfigPath, t as DEFAULT_CONFIG, u as loadConfigFromFile } from "./schema-
|
|
2
|
+
import { a as ZedSyncConfig, c as isModelExposureMode, d as normalizeConfig, f as saveConfigToFile, i as PublicModelIdMode, l as isPublicModelIdMode, n as ModelExposureMode, o as configToEnv, r as ProxyConfig, s as getConfigPath, t as DEFAULT_CONFIG, u as loadConfigFromFile } from "./schema-CrOJW-mE.mjs";
|
|
3
3
|
export { DEFAULT_CONFIG, ModelExposureMode, ProxyConfig, PublicModelIdMode, ZedSyncConfig, configToEnv, getConfigPath, isModelExposureMode, isPublicModelIdMode, loadConfigFromFile, normalizeConfig, saveConfigToFile };
|
package/dist/config.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
|
-
import { a as isPublicModelIdMode, c as saveConfigToFile, i as isModelExposureMode, n as configToEnv, o as loadConfigFromFile, r as getConfigPath, s as normalizeConfig, t as DEFAULT_CONFIG } from "./schema-
|
|
2
|
+
import { a as isPublicModelIdMode, c as saveConfigToFile, i as isModelExposureMode, n as configToEnv, o as loadConfigFromFile, r as getConfigPath, s as normalizeConfig, t as DEFAULT_CONFIG } from "./schema-quaXHZsz.mjs";
|
|
3
3
|
export { DEFAULT_CONFIG, configToEnv, getConfigPath, isModelExposureMode, isPublicModelIdMode, loadConfigFromFile, normalizeConfig, saveConfigToFile };
|
package/dist/exposure.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
import { i as PublicModelIdMode, n as ModelExposureMode } from "./schema-
|
|
2
|
+
import { i as PublicModelIdMode, n as ModelExposureMode } from "./schema-CrOJW-mE.mjs";
|
|
3
3
|
import { Api, Model } from "@mariozechner/pi-ai";
|
|
4
4
|
|
|
5
5
|
//#region src/openai/model-exposure.d.ts
|
|
@@ -16,7 +16,13 @@ interface ExposedModel {
|
|
|
16
16
|
interface ModelExposureConfig {
|
|
17
17
|
readonly publicModelIdMode: PublicModelIdMode;
|
|
18
18
|
readonly modelExposureMode: ModelExposureMode;
|
|
19
|
-
|
|
19
|
+
/**
|
|
20
|
+
* Canonical model IDs from pi's global `enabledModels` setting.
|
|
21
|
+
* Read from `SettingsManager.getEnabledModels()` at request time.
|
|
22
|
+
* Undefined or empty means no filter (all available models exposed).
|
|
23
|
+
* Used only when modelExposureMode is "scoped".
|
|
24
|
+
*/
|
|
25
|
+
readonly enabledModels: readonly string[] | undefined;
|
|
20
26
|
readonly customModels: readonly string[];
|
|
21
27
|
readonly providerPrefixes: Readonly<Record<string, string>>;
|
|
22
28
|
}
|
|
@@ -38,12 +44,11 @@ type ModelExposureOutcome = ModelExposureResult | ModelExposureError;
|
|
|
38
44
|
* Compute the full model-exposure result from config and available models.
|
|
39
45
|
*
|
|
40
46
|
* @param available - Models with auth configured (pi's getAvailable())
|
|
41
|
-
* @param allRegistered - All registered models regardless of auth (pi's getAll())
|
|
42
47
|
* @param config - Model exposure configuration
|
|
43
48
|
*
|
|
44
49
|
* Call this at startup and whenever config or the model registry changes.
|
|
45
50
|
*/
|
|
46
|
-
declare function computeModelExposure(available: readonly Model<Api>[],
|
|
51
|
+
declare function computeModelExposure(available: readonly Model<Api>[], config: ModelExposureConfig): ModelExposureOutcome;
|
|
47
52
|
/**
|
|
48
53
|
* Resolve a model ID from an incoming request against the exposure result.
|
|
49
54
|
*
|
package/dist/exposure.mjs
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
//#region src/openai/model-exposure.ts
|
|
3
|
-
function filterExposedModels(available,
|
|
3
|
+
function filterExposedModels(available, config) {
|
|
4
4
|
switch (config.modelExposureMode) {
|
|
5
|
+
case "all": return [...available];
|
|
5
6
|
case "scoped": {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
const enabled = config.enabledModels;
|
|
8
|
+
if (enabled === void 0 || enabled.length === 0) return [...available];
|
|
9
|
+
const allowed = new Set(enabled);
|
|
10
|
+
return available.filter((m) => allowed.has(`${m.provider}/${m.id}`));
|
|
9
11
|
}
|
|
10
|
-
case "all": return [...allRegistered];
|
|
11
12
|
case "custom": {
|
|
13
|
+
if (config.customModels.length === 0) return [...available];
|
|
12
14
|
const allowed = new Set(config.customModels);
|
|
13
15
|
return available.filter((m) => allowed.has(`${m.provider}/${m.id}`));
|
|
14
16
|
}
|
|
@@ -127,13 +129,12 @@ function validatePrefixUniqueness(models, prefixes, mode) {
|
|
|
127
129
|
* Compute the full model-exposure result from config and available models.
|
|
128
130
|
*
|
|
129
131
|
* @param available - Models with auth configured (pi's getAvailable())
|
|
130
|
-
* @param allRegistered - All registered models regardless of auth (pi's getAll())
|
|
131
132
|
* @param config - Model exposure configuration
|
|
132
133
|
*
|
|
133
134
|
* Call this at startup and whenever config or the model registry changes.
|
|
134
135
|
*/
|
|
135
|
-
function computeModelExposure(available,
|
|
136
|
-
const exposed = filterExposedModels(available,
|
|
136
|
+
function computeModelExposure(available, config) {
|
|
137
|
+
const exposed = filterExposedModels(available, config);
|
|
137
138
|
const prefixError = validatePrefixUniqueness(exposed, config.providerPrefixes, config.publicModelIdMode);
|
|
138
139
|
if (prefixError !== void 0) return {
|
|
139
140
|
ok: false,
|
package/dist/index.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
|
-
import { l as isRecord, o as loadConfigFromFile, r as getConfigPath } from "./schema-
|
|
2
|
+
import { l as isRecord, o as loadConfigFromFile, r as getConfigPath } from "./schema-quaXHZsz.mjs";
|
|
3
3
|
import { computeModelExposure, resolveExposedModel } from "./exposure.mjs";
|
|
4
4
|
import * as z from "zod";
|
|
5
|
-
import { AuthStorage, ModelRegistry } from "@mariozechner/pi-coding-agent";
|
|
5
|
+
import { AuthStorage, ModelRegistry, SettingsManager } from "@mariozechner/pi-coding-agent";
|
|
6
6
|
import { randomBytes } from "node:crypto";
|
|
7
7
|
import { Type } from "@sinclair/typebox";
|
|
8
8
|
import { completeSimple, streamSimple } from "@mariozechner/pi-ai";
|
|
@@ -38,7 +38,6 @@ function loadConfig(cli = {}) {
|
|
|
38
38
|
upstreamTimeoutMs,
|
|
39
39
|
publicModelIdMode: file.publicModelIdMode,
|
|
40
40
|
modelExposureMode: file.modelExposureMode,
|
|
41
|
-
scopedProviders: file.scopedProviders,
|
|
42
41
|
customModels: file.customModels,
|
|
43
42
|
providerPrefixes: file.providerPrefixes
|
|
44
43
|
};
|
|
@@ -47,19 +46,25 @@ function loadConfig(cli = {}) {
|
|
|
47
46
|
//#region src/pi/registry.ts
|
|
48
47
|
let registry;
|
|
49
48
|
let authStorage;
|
|
49
|
+
let settingsManager;
|
|
50
50
|
/**
|
|
51
|
-
* Initialize the registry. Call once at startup.
|
|
51
|
+
* Initialize the registry and settings. Call once at startup.
|
|
52
52
|
* Returns the load error if models.json failed to parse, or undefined on success.
|
|
53
53
|
*/
|
|
54
54
|
function initRegistry() {
|
|
55
55
|
authStorage = AuthStorage.create();
|
|
56
56
|
registry = new ModelRegistry(authStorage);
|
|
57
|
+
settingsManager = SettingsManager.create();
|
|
57
58
|
return registry.getError();
|
|
58
59
|
}
|
|
59
60
|
function getRegistry() {
|
|
60
61
|
if (registry === void 0) throw new Error("ModelRegistry not initialized. Call initRegistry() first.");
|
|
61
62
|
return registry;
|
|
62
63
|
}
|
|
64
|
+
function getSettingsManager() {
|
|
65
|
+
if (settingsManager === void 0) throw new Error("SettingsManager not initialized. Call initRegistry() first.");
|
|
66
|
+
return settingsManager;
|
|
67
|
+
}
|
|
63
68
|
/**
|
|
64
69
|
* Get all models available (have auth configured).
|
|
65
70
|
*/
|
|
@@ -67,10 +72,16 @@ function getAvailableModels() {
|
|
|
67
72
|
return getRegistry().getAvailable();
|
|
68
73
|
}
|
|
69
74
|
/**
|
|
70
|
-
* Get
|
|
75
|
+
* Get the `enabledModels` patterns from pi's global settings.
|
|
76
|
+
*
|
|
77
|
+
* These are the canonical model IDs (e.g. "anthropic/claude-sonnet-4-6")
|
|
78
|
+
* persisted by the `/scoped-models` TUI when the user presses Ctrl+S.
|
|
79
|
+
*
|
|
80
|
+
* Returns undefined when no filter is configured (all models enabled).
|
|
71
81
|
*/
|
|
72
|
-
function
|
|
73
|
-
|
|
82
|
+
function getEnabledModels() {
|
|
83
|
+
getSettingsManager().reload();
|
|
84
|
+
return getSettingsManager().getEnabledModels();
|
|
74
85
|
}
|
|
75
86
|
//#endregion
|
|
76
87
|
//#region src/server/errors.ts
|
|
@@ -1307,14 +1318,14 @@ function fileConfigReader() {
|
|
|
1307
1318
|
return {
|
|
1308
1319
|
publicModelIdMode: file.publicModelIdMode,
|
|
1309
1320
|
modelExposureMode: file.modelExposureMode,
|
|
1310
|
-
|
|
1321
|
+
enabledModels: getEnabledModels(),
|
|
1311
1322
|
customModels: file.customModels,
|
|
1312
1323
|
providerPrefixes: file.providerPrefixes
|
|
1313
1324
|
};
|
|
1314
1325
|
}
|
|
1315
1326
|
function createRoutes(config, configReader = fileConfigReader) {
|
|
1316
1327
|
function getExposure() {
|
|
1317
|
-
const outcome = computeModelExposure(getAvailableModels(),
|
|
1328
|
+
const outcome = computeModelExposure(getAvailableModels(), configReader());
|
|
1318
1329
|
if (!outcome.ok) throw new Error(`Model exposure configuration error: ${outcome.message}`);
|
|
1319
1330
|
return outcome;
|
|
1320
1331
|
}
|
|
@@ -12,10 +12,12 @@ import * as z from "zod";
|
|
|
12
12
|
type PublicModelIdMode = "collision-prefixed" | "universal" | "always-prefixed";
|
|
13
13
|
/**
|
|
14
14
|
* Which models are exposed on the public HTTP API.
|
|
15
|
+
* All modes only expose auth-configured models (pi's getAvailable()).
|
|
15
16
|
*
|
|
16
|
-
* - "all": every available model
|
|
17
|
-
* - "scoped":
|
|
18
|
-
* - "custom":
|
|
17
|
+
* - "all": every available model, no filter
|
|
18
|
+
* - "scoped": delegates to pi's global `enabledModels` setting (from `/scoped-models` Ctrl+S)
|
|
19
|
+
* - "custom": same per-model filtering as "scoped" but independently managed
|
|
20
|
+
* via the proxy's own `customModels` config
|
|
19
21
|
*/
|
|
20
22
|
type ModelExposureMode = "all" | "scoped" | "custom";
|
|
21
23
|
interface ProxyConfig {
|
|
@@ -35,10 +37,8 @@ interface ProxyConfig {
|
|
|
35
37
|
readonly lifetime: "detached" | "session";
|
|
36
38
|
/** How public model IDs are generated. Default: "collision-prefixed" */
|
|
37
39
|
readonly publicModelIdMode: PublicModelIdMode;
|
|
38
|
-
/** Which models are exposed. Default: "
|
|
40
|
+
/** Which models are exposed. Default: "scoped" */
|
|
39
41
|
readonly modelExposureMode: ModelExposureMode;
|
|
40
|
-
/** Provider keys to expose when modelExposureMode is "scoped". */
|
|
41
|
-
readonly scopedProviders: readonly string[];
|
|
42
42
|
/** Canonical model IDs to expose when modelExposureMode is "custom". */
|
|
43
43
|
readonly customModels: readonly string[];
|
|
44
44
|
/** Provider key -> custom public prefix label. Default prefix = provider key. */
|
|
@@ -36,7 +36,6 @@ const DEFAULT_CONFIG = {
|
|
|
36
36
|
lifetime: "detached",
|
|
37
37
|
publicModelIdMode: "collision-prefixed",
|
|
38
38
|
modelExposureMode: "scoped",
|
|
39
|
-
scopedProviders: [],
|
|
40
39
|
customModels: [],
|
|
41
40
|
providerPrefixes: {},
|
|
42
41
|
zed: {
|
|
@@ -93,7 +92,6 @@ function normalizeConfig(raw) {
|
|
|
93
92
|
lifetime: v["lifetime"] === "session" ? "session" : "detached",
|
|
94
93
|
publicModelIdMode: typeof rawPublicIdMode === "string" && isPublicModelIdMode(rawPublicIdMode) ? rawPublicIdMode : DEFAULT_CONFIG.publicModelIdMode,
|
|
95
94
|
modelExposureMode: typeof rawExposureMode === "string" && isModelExposureMode(rawExposureMode) ? rawExposureMode : DEFAULT_CONFIG.modelExposureMode,
|
|
96
|
-
scopedProviders: normalizeStringArray(v["scopedProviders"]),
|
|
97
95
|
customModels: normalizeStringArray(v["customModels"]),
|
|
98
96
|
providerPrefixes: normalizeStringRecord(v["providerPrefixes"]),
|
|
99
97
|
zed: parseZedSyncConfig(v["zed"])
|
package/extensions/proxy.ts
CHANGED
|
@@ -31,6 +31,7 @@ import {
|
|
|
31
31
|
type ExtensionContext,
|
|
32
32
|
getSettingsListTheme,
|
|
33
33
|
ModelRegistry,
|
|
34
|
+
SettingsManager,
|
|
34
35
|
} from "@mariozechner/pi-coding-agent";
|
|
35
36
|
import {
|
|
36
37
|
type Component,
|
|
@@ -68,6 +69,17 @@ interface RuntimeStatus {
|
|
|
68
69
|
models: number;
|
|
69
70
|
}
|
|
70
71
|
|
|
72
|
+
interface ProbeBody {
|
|
73
|
+
data: unknown[];
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function isProbeBody(value: unknown): value is ProbeBody {
|
|
77
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
|
|
78
|
+
if (!("data" in value)) return false;
|
|
79
|
+
const v: { data: unknown } = value;
|
|
80
|
+
return Array.isArray(v.data);
|
|
81
|
+
}
|
|
82
|
+
|
|
71
83
|
// ---------------------------------------------------------------------------
|
|
72
84
|
// Extension
|
|
73
85
|
// ---------------------------------------------------------------------------
|
|
@@ -83,22 +95,23 @@ export default function proxyExtension(pi: ExtensionAPI): void {
|
|
|
83
95
|
|
|
84
96
|
const cachedAuth = AuthStorage.create();
|
|
85
97
|
const cachedRegistry = new ModelRegistry(cachedAuth);
|
|
98
|
+
const settingsManager = SettingsManager.create();
|
|
86
99
|
|
|
87
100
|
function getAvailableModels(): Model<Api>[] {
|
|
88
101
|
cachedRegistry.refresh();
|
|
89
102
|
return cachedRegistry.getAvailable();
|
|
90
103
|
}
|
|
91
104
|
|
|
92
|
-
function
|
|
93
|
-
|
|
94
|
-
return
|
|
105
|
+
function getEnabledModels(): readonly string[] | undefined {
|
|
106
|
+
settingsManager.reload();
|
|
107
|
+
return settingsManager.getEnabledModels();
|
|
95
108
|
}
|
|
96
109
|
|
|
97
110
|
function buildExposureConfig(): ModelExposureConfig {
|
|
98
111
|
return {
|
|
99
112
|
publicModelIdMode: config.publicModelIdMode,
|
|
100
113
|
modelExposureMode: config.modelExposureMode,
|
|
101
|
-
|
|
114
|
+
enabledModels: getEnabledModels(),
|
|
102
115
|
customModels: config.customModels,
|
|
103
116
|
providerPrefixes: config.providerPrefixes,
|
|
104
117
|
};
|
|
@@ -274,8 +287,12 @@ export default function proxyExtension(pi: ExtensionAPI): void {
|
|
|
274
287
|
headers,
|
|
275
288
|
});
|
|
276
289
|
if (res.ok) {
|
|
277
|
-
const body =
|
|
278
|
-
|
|
290
|
+
const body: unknown = await res.json();
|
|
291
|
+
let modelCount = 0;
|
|
292
|
+
if (isProbeBody(body)) {
|
|
293
|
+
modelCount = body.data.length;
|
|
294
|
+
}
|
|
295
|
+
return { reachable: true, models: modelCount };
|
|
279
296
|
}
|
|
280
297
|
} catch {
|
|
281
298
|
// not reachable
|
|
@@ -464,8 +481,11 @@ export default function proxyExtension(pi: ExtensionAPI): void {
|
|
|
464
481
|
`exposure: ${config.modelExposureMode}`,
|
|
465
482
|
];
|
|
466
483
|
|
|
467
|
-
if (config.modelExposureMode === "scoped"
|
|
468
|
-
|
|
484
|
+
if (config.modelExposureMode === "scoped") {
|
|
485
|
+
const enabledModels = getEnabledModels();
|
|
486
|
+
if (enabledModels !== undefined && enabledModels.length > 0) {
|
|
487
|
+
exposureLines.push(`enabled: ${String(enabledModels.length)} pi model(s)`);
|
|
488
|
+
}
|
|
469
489
|
}
|
|
470
490
|
if (config.modelExposureMode === "custom" && config.customModels.length > 0) {
|
|
471
491
|
exposureLines.push(`models: ${String(config.customModels.length)} custom`);
|
|
@@ -479,8 +499,7 @@ export default function proxyExtension(pi: ExtensionAPI): void {
|
|
|
479
499
|
|
|
480
500
|
// Public ID preview (first 5 exposed models)
|
|
481
501
|
const models = getAvailableModels();
|
|
482
|
-
const
|
|
483
|
-
const outcome = computeModelExposure(models, allModels, buildExposureConfig());
|
|
502
|
+
const outcome = computeModelExposure(models, buildExposureConfig());
|
|
484
503
|
if (outcome.ok && outcome.models.length > 0) {
|
|
485
504
|
const preview = outcome.models.slice(0, 5).map((m) => m.publicId);
|
|
486
505
|
const suffix =
|
|
@@ -500,8 +519,7 @@ export default function proxyExtension(pi: ExtensionAPI): void {
|
|
|
500
519
|
function showModels(ctx: ExtensionContext): void {
|
|
501
520
|
config = loadConfigFromFile();
|
|
502
521
|
const models = getAvailableModels();
|
|
503
|
-
const
|
|
504
|
-
const outcome = computeModelExposure(models, allModels, buildExposureConfig());
|
|
522
|
+
const outcome = computeModelExposure(models, buildExposureConfig());
|
|
505
523
|
|
|
506
524
|
if (!outcome.ok) {
|
|
507
525
|
ctx.ui.notify(`Model exposure error: ${outcome.message}`, "warning");
|
|
@@ -548,8 +566,6 @@ export default function proxyExtension(pi: ExtensionAPI): void {
|
|
|
548
566
|
const models = getAvailableModels();
|
|
549
567
|
const issues: string[] = [];
|
|
550
568
|
|
|
551
|
-
const allModels = getAllRegisteredModels();
|
|
552
|
-
|
|
553
569
|
// Check available models
|
|
554
570
|
if (models.length === 0) {
|
|
555
571
|
issues.push("No models have auth configured. The proxy will expose 0 models.");
|
|
@@ -569,7 +585,7 @@ export default function proxyExtension(pi: ExtensionAPI): void {
|
|
|
569
585
|
}
|
|
570
586
|
|
|
571
587
|
// Run the full exposure computation to catch ID/prefix errors
|
|
572
|
-
const outcome = computeModelExposure(models,
|
|
588
|
+
const outcome = computeModelExposure(models, buildExposureConfig());
|
|
573
589
|
if (!outcome.ok) {
|
|
574
590
|
issues.push(outcome.message);
|
|
575
591
|
}
|
|
@@ -592,8 +608,7 @@ export default function proxyExtension(pi: ExtensionAPI): void {
|
|
|
592
608
|
*/
|
|
593
609
|
function runZedSync(dryRun: boolean): { ok: boolean; message: string } {
|
|
594
610
|
const available = getAvailableModels();
|
|
595
|
-
const
|
|
596
|
-
const outcome = computeModelExposure(available, allModels, buildExposureConfig());
|
|
611
|
+
const outcome = computeModelExposure(available, buildExposureConfig());
|
|
597
612
|
if (!outcome.ok) {
|
|
598
613
|
return { ok: false, message: `Model exposure error: ${outcome.message}` };
|
|
599
614
|
}
|
|
@@ -709,12 +724,40 @@ export default function proxyExtension(pi: ExtensionAPI): void {
|
|
|
709
724
|
// Accesses private fields via bracket notation for provider jumping.
|
|
710
725
|
// Pinned to pi-tui behavior as of @mariozechner/pi-coding-agent ^0.62.0.
|
|
711
726
|
// Remove when SettingsList exposes a jumpTo/setSelectedIndex method.
|
|
727
|
+
|
|
728
|
+
// Isolated unsafe accessor for SettingsList private fields.
|
|
729
|
+
// Consolidated here so jumpProvider itself is fully type-safe.
|
|
730
|
+
function listGet(key: string): unknown {
|
|
731
|
+
return Reflect.get(list, key);
|
|
732
|
+
}
|
|
733
|
+
function listSet(key: string, value: unknown): void {
|
|
734
|
+
Reflect.set(list, key, value);
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
function getSettingsListItems(): SettingItem[] {
|
|
738
|
+
const rawSearch = listGet("searchEnabled");
|
|
739
|
+
const raw =
|
|
740
|
+
typeof rawSearch === "boolean" && rawSearch ? listGet("filteredItems") : listGet("items");
|
|
741
|
+
if (!Array.isArray(raw)) return [];
|
|
742
|
+
const result: SettingItem[] = [];
|
|
743
|
+
for (const item of raw) {
|
|
744
|
+
if (isSettingItem(item)) result.push(item);
|
|
745
|
+
}
|
|
746
|
+
return result;
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
function isSettingItem(value: unknown): value is SettingItem {
|
|
750
|
+
if (value === null || typeof value !== "object") return false;
|
|
751
|
+
if (!("id" in value)) return false;
|
|
752
|
+
const v: { id: unknown } = value;
|
|
753
|
+
return typeof v.id === "string";
|
|
754
|
+
}
|
|
755
|
+
|
|
712
756
|
function jumpProvider(direction: "prev" | "next"): void {
|
|
713
|
-
const
|
|
714
|
-
|
|
715
|
-
const
|
|
716
|
-
|
|
717
|
-
) as SettingItem[];
|
|
757
|
+
const rawIdx = listGet("selectedIndex");
|
|
758
|
+
if (typeof rawIdx !== "number") return;
|
|
759
|
+
const idx = rawIdx;
|
|
760
|
+
const display = getSettingsListItems();
|
|
718
761
|
if (display.length === 0) return;
|
|
719
762
|
|
|
720
763
|
const current = display[idx];
|
|
@@ -750,7 +793,7 @@ export default function proxyExtension(pi: ExtensionAPI): void {
|
|
|
750
793
|
}
|
|
751
794
|
}
|
|
752
795
|
}
|
|
753
|
-
|
|
796
|
+
listSet("selectedIndex", target);
|
|
754
797
|
}
|
|
755
798
|
|
|
756
799
|
return {
|
|
@@ -878,7 +921,7 @@ export default function proxyExtension(pi: ExtensionAPI): void {
|
|
|
878
921
|
label: "Select models",
|
|
879
922
|
description: customModelsDescription(),
|
|
880
923
|
currentValue: customModelsDisplay(),
|
|
881
|
-
|
|
924
|
+
...(config.modelExposureMode === "custom" ? { submenu: buildModelSelectorSubmenu } : {}),
|
|
882
925
|
},
|
|
883
926
|
// --- Zed sync ---
|
|
884
927
|
{
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@victor-software-house/pi-openai-proxy",
|
|
3
|
-
"version": "4.5.
|
|
3
|
+
"version": "4.5.1",
|
|
4
4
|
"description": "OpenAI-compatible HTTP proxy for pi's multi-provider model registry",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Victor Software House",
|
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
"typecheck": "tsc --noEmit",
|
|
63
63
|
"lint": "bun run lint:biome && bun run lint:oxlint",
|
|
64
64
|
"lint:biome": "biome check .",
|
|
65
|
-
"lint:oxlint": "oxlint --import-plugin --type-aware --tsconfig=./tsconfig.json
|
|
65
|
+
"lint:oxlint": "oxlint --import-plugin --type-aware --tsconfig=./tsconfig.json .",
|
|
66
66
|
"lint:fix": "biome check --write .",
|
|
67
67
|
"format": "biome format --write .",
|
|
68
68
|
"test": "bun test",
|