@victor-software-house/pi-openai-proxy 4.0.5 → 4.1.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/dist/index.mjs CHANGED
@@ -1283,31 +1283,25 @@ async function piStream(model, context, request, options) {
1283
1283
  }
1284
1284
  //#endregion
1285
1285
  //#region src/server/routes.ts
1286
- /**
1287
- * Build a ModelExposureConfig from the server config.
1288
- */
1289
- function buildExposureConfig(config) {
1286
+ function fileConfigReader() {
1287
+ const file = loadConfigFromFile();
1290
1288
  return {
1291
- publicModelIdMode: config.publicModelIdMode,
1292
- modelExposureMode: config.modelExposureMode,
1293
- scopedProviders: config.scopedProviders,
1294
- customModels: config.customModels,
1295
- providerPrefixes: config.providerPrefixes
1289
+ publicModelIdMode: file.publicModelIdMode,
1290
+ modelExposureMode: file.modelExposureMode,
1291
+ scopedProviders: file.scopedProviders,
1292
+ customModels: file.customModels,
1293
+ providerPrefixes: file.providerPrefixes
1296
1294
  };
1297
1295
  }
1298
- /**
1299
- * Compute or refresh the model exposure from the current registry and config.
1300
- * Returns the exposure result or throws on config errors.
1301
- */
1302
- function getExposure(config) {
1303
- const outcome = computeModelExposure(getAvailableModels(), getAllModels(), buildExposureConfig(config));
1304
- if (!outcome.ok) throw new Error(`Model exposure configuration error: ${outcome.message}`);
1305
- return outcome;
1306
- }
1307
- function createRoutes(config) {
1296
+ function createRoutes(config, configReader = fileConfigReader) {
1297
+ function getExposure() {
1298
+ const outcome = computeModelExposure(getAvailableModels(), getAllModels(), configReader());
1299
+ if (!outcome.ok) throw new Error(`Model exposure configuration error: ${outcome.message}`);
1300
+ return outcome;
1301
+ }
1308
1302
  const routes = new Hono();
1309
1303
  routes.get("/v1/models", (c) => {
1310
- const exposure = getExposure(config);
1304
+ const exposure = getExposure();
1311
1305
  return c.json(buildModelList(exposure.models));
1312
1306
  });
1313
1307
  routes.get("/v1/models/*", (c) => {
@@ -1316,7 +1310,7 @@ function createRoutes(config) {
1316
1310
  const modelIdEncoded = rawPath.slice(11);
1317
1311
  if (modelIdEncoded.length === 0) return c.json(modelNotFound(""), 404);
1318
1312
  const modelId = decodeURIComponent(modelIdEncoded);
1319
- const resolved = resolveExposedModel(getExposure(config), modelId);
1313
+ const resolved = resolveExposedModel(getExposure(), modelId);
1320
1314
  if (resolved === void 0) return c.json(modelNotFound(modelId), 404);
1321
1315
  return c.json(toOpenAIModel(resolved));
1322
1316
  });
@@ -1336,7 +1330,7 @@ function createRoutes(config) {
1336
1330
  return c.json(invalidRequest(validation.message, validation.param ?? void 0), 400);
1337
1331
  }
1338
1332
  const request = validation.data;
1339
- const resolved = resolveExposedModel(getExposure(config), request.model);
1333
+ const resolved = resolveExposedModel(getExposure(), request.model);
1340
1334
  if (resolved === void 0) return c.json(modelNotFound(request.model), 404);
1341
1335
  const model = resolved.model;
1342
1336
  const canonicalModelId = resolved.canonicalId;
@@ -1422,13 +1416,13 @@ function createRoutes(config) {
1422
1416
  }
1423
1417
  //#endregion
1424
1418
  //#region src/server/app.ts
1425
- function createApp(config) {
1419
+ function createApp(config, configReader) {
1426
1420
  const app = new Hono();
1427
1421
  app.use("*", requestIdMiddleware());
1428
1422
  app.use("*", disconnectMiddleware());
1429
1423
  app.use("*", bodySizeLimitMiddleware(config));
1430
1424
  app.use("/v1/*", proxyAuthMiddleware(config));
1431
- app.route("/", createRoutes(config));
1425
+ app.route("/", createRoutes(config, configReader));
1432
1426
  return app;
1433
1427
  }
1434
1428
  //#endregion
@@ -614,6 +614,40 @@ export default function proxyExtension(pi: ExtensionAPI): void {
614
614
  };
615
615
  }
616
616
 
617
+ // --- Dynamic descriptions ---
618
+
619
+ const ID_MODE_DESCRIPTIONS: Record<string, string> = {
620
+ "collision-prefixed": "Short names; adds provider/ prefix only when models collide",
621
+ universal: "Short names only; fails if any model name is shared by two providers",
622
+ "always-prefixed": "Always provider/model-id for every model",
623
+ };
624
+
625
+ const EXPOSURE_MODE_DESCRIPTIONS: Record<string, string> = {
626
+ scoped: "Expose models from pi's configured auth (default)",
627
+ all: "Expose all registered models, including those without auth",
628
+ custom: "Expose only manually selected models",
629
+ };
630
+
631
+ function idModeDescription(): string {
632
+ return ID_MODE_DESCRIPTIONS[config.publicModelIdMode] ?? "";
633
+ }
634
+
635
+ function exposureModeDescription(): string {
636
+ return EXPOSURE_MODE_DESCRIPTIONS[config.modelExposureMode] ?? "";
637
+ }
638
+
639
+ function customModelsDescription(): string {
640
+ if (config.modelExposureMode === "custom") return "Press Enter to open model selector";
641
+ return "Switch exposure mode to 'custom' to select models";
642
+ }
643
+
644
+ function authDescription(): string {
645
+ if (config.authToken.length > 0) {
646
+ return `Token: ${config.authToken.slice(0, 8)}... (use /proxy show to copy)`;
647
+ }
648
+ return "Require bearer token for all requests";
649
+ }
650
+
617
651
  function buildSettingItems(): SettingItem[] {
618
652
  return [
619
653
  // --- Server ---
@@ -641,10 +675,7 @@ export default function proxyExtension(pi: ExtensionAPI): void {
641
675
  {
642
676
  id: "authToken",
643
677
  label: "Proxy auth",
644
- description:
645
- config.authToken.length > 0
646
- ? `Token: ${config.authToken.slice(0, 8)}... (use /proxy show to copy)`
647
- : "Require bearer token for all requests",
678
+ description: authDescription(),
648
679
  currentValue: config.authToken.length > 0 ? "enabled" : "disabled",
649
680
  values: ["disabled", "enabled"],
650
681
  },
@@ -672,32 +703,50 @@ export default function proxyExtension(pi: ExtensionAPI): void {
672
703
  // --- Model exposure ---
673
704
  {
674
705
  id: "publicModelIdMode",
675
- label: "Public ID mode",
676
- description: "How public model IDs are generated from canonical provider/model-id",
706
+ label: "Model ID format",
707
+ description: idModeDescription(),
677
708
  currentValue: config.publicModelIdMode,
678
709
  values: ["collision-prefixed", "universal", "always-prefixed"],
679
710
  },
680
711
  {
681
712
  id: "modelExposureMode",
682
713
  label: "Exposure mode",
683
- description:
684
- "scoped = pi's available models, all = all registered, custom = manual selection",
714
+ description: exposureModeDescription(),
685
715
  currentValue: config.modelExposureMode,
686
716
  values: ["scoped", "all", "custom"],
687
717
  },
688
718
  {
689
719
  id: "customModels",
690
720
  label: "Select models",
691
- description:
692
- config.modelExposureMode === "custom"
693
- ? "Press Enter to open model selector"
694
- : "Switch exposure mode to 'custom' to select models",
721
+ description: customModelsDescription(),
695
722
  currentValue: customModelsDisplay(),
696
723
  submenu: config.modelExposureMode === "custom" ? buildModelSelectorSubmenu : undefined,
697
724
  },
698
725
  ];
699
726
  }
700
727
 
728
+ /**
729
+ * Update descriptions on items that change dynamically based on the current value.
730
+ */
731
+ function refreshDescriptions(items: SettingItem[]): void {
732
+ for (const item of items) {
733
+ switch (item.id) {
734
+ case "publicModelIdMode":
735
+ item.description = idModeDescription();
736
+ break;
737
+ case "modelExposureMode":
738
+ item.description = exposureModeDescription();
739
+ break;
740
+ case "customModels":
741
+ item.description = customModelsDescription();
742
+ break;
743
+ case "authToken":
744
+ item.description = authDescription();
745
+ break;
746
+ }
747
+ }
748
+ }
749
+
701
750
  const VALID_ID_MODES = new Set<string>(["collision-prefixed", "universal", "always-prefixed"]);
702
751
 
703
752
  function isPublicModelIdMode(v: string): v is PublicModelIdMode {
@@ -821,8 +870,9 @@ export default function proxyExtension(pi: ExtensionAPI): void {
821
870
  ctx.ui.notify(`Auth token: ${lastGeneratedToken}`, "info");
822
871
  }
823
872
 
824
- // Update display value in-place (no rebuild, preserves selection)
873
+ // Update display value and descriptions in-place (preserves selection)
825
874
  settingsList.updateValue(id, getDisplayValue(id));
875
+ refreshDescriptions(items);
826
876
 
827
877
  // When exposure mode changes, update the "Select models" item
828
878
  if (id === "modelExposureMode") {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@victor-software-house/pi-openai-proxy",
3
- "version": "4.0.5",
3
+ "version": "4.1.0",
4
4
  "description": "OpenAI-compatible HTTP proxy for pi's multi-provider model registry",
5
5
  "license": "MIT",
6
6
  "author": "Victor Software House",