@billjr99/pi-openai-compat 1.1.31 → 1.1.32

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 CHANGED
@@ -68,6 +68,10 @@ If pi is already running when you install, type `/reload` first.
68
68
  | **Token Harbor** | `https://tokenharbor.ai/v1` | `thk_live_...` Universal Key from tokenharbor.ai/dashboard/api-keys |
69
69
  | **Atria ASI** | `https://api.atria-asi.ai/v1` | `atr_...` key from api.atria-asi.ai/console/keys (Google sign-in) |
70
70
  | **Unbiased AI** | `https://api.unbiased.ai/v1` | `sk_...` key from platform.unbiased.ai (signup reviewed by hand) |
71
+ | **Kilo AI** | `https://api.kilo.ai/api/gateway` | API key from app.kilo.ai → Your Profile (personal account), at the bottom of the page; needs account credits |
72
+ | **ModelScope** | `https://api-inference.modelscope.cn/v1` | `ms-...` SDK token from modelscope.cn/my/myaccesstoken |
73
+ | **Aion Labs** | `https://api.aionlabs.ai/v1` | API key from aionlabs.ai/app/api-keys (aionlabs.ai/docs) |
74
+ | **Agnes AI** | `https://apihub.agnes-ai.com/v1` | `sk-...` key from the Agnes console at platform.agnes-ai.com (wiki.agnes-ai.com) |
71
75
  | **Ollama (local)** | `http://localhost:11434/v1` (editable) | Optional bearer token; leave blank for a default local install |
72
76
  | **Ollama Cloud** | `https://ollama.com/v1` | Ollama Cloud API key from ollama.com |
73
77
  | **llmproxy** | `http://localhost:8080/v1` (editable) | Keyless by default; bearer token if your instance requires one |
package/add-provider.sh CHANGED
@@ -72,6 +72,30 @@ const BUILTIN = {
72
72
  keyless: false,
73
73
  keyHint: "platform.unbiased.ai (signup is reviewed by hand; keys look like sk_...)",
74
74
  },
75
+ kilo: {
76
+ displayName: "Kilo AI",
77
+ baseUrl: "https://api.kilo.ai/api/gateway",
78
+ keyless: false,
79
+ keyHint: "app.kilo.ai → Your Profile on your personal account (not an organization), at the bottom of the page; needs account credits (docs at kilo.ai/docs/gateway)",
80
+ },
81
+ modelscope: {
82
+ displayName: "ModelScope",
83
+ baseUrl: "https://api-inference.modelscope.cn/v1",
84
+ keyless: false,
85
+ keyHint: "modelscope.cn/my/myaccesstoken (SDK token, format ms-...; docs at modelscope.cn/docs/model-service/API-Inference/intro)",
86
+ },
87
+ aion_labs: {
88
+ displayName: "Aion Labs",
89
+ baseUrl: "https://api.aionlabs.ai/v1",
90
+ keyless: false,
91
+ keyHint: "aionlabs.ai/app/api-keys (docs at aionlabs.ai/docs/api-reference)",
92
+ },
93
+ agnes_ai: {
94
+ displayName: "Agnes AI",
95
+ baseUrl: "https://apihub.agnes-ai.com/v1",
96
+ keyless: false,
97
+ keyHint: "platform.agnes-ai.com → API Key management (keys look like sk-...; docs at wiki.agnes-ai.com)",
98
+ },
75
99
  };
76
100
 
77
101
  // README "Auth" column text for the built-in providers, used only by patchreadme.
@@ -82,6 +106,10 @@ const BUILTIN_AUTH = {
82
106
  tokenharbor: "`thk_live_...` Universal Key from tokenharbor.ai/dashboard/api-keys",
83
107
  atria_asi: "`atr_...` key from api.atria-asi.ai/console/keys (Google sign-in)",
84
108
  unbiased_ai: "`sk_...` key from platform.unbiased.ai (signup reviewed by hand)",
109
+ kilo: "API key from app.kilo.ai → Your Profile (personal account), at the bottom of the page; needs account credits",
110
+ modelscope: "`ms-...` SDK token from modelscope.cn/my/myaccesstoken",
111
+ aion_labs: "API key from aionlabs.ai/app/api-keys (aionlabs.ai/docs)",
112
+ agnes_ai: "`sk-...` key from the Agnes console at platform.agnes-ai.com (wiki.agnes-ai.com)",
85
113
  };
86
114
 
87
115
  /**
@@ -158,8 +186,9 @@ function normalizeModels(body, idField, keepTask) {
158
186
  else if (json && typeof json === "object") {
159
187
  if (Array.isArray(json.data)) raw = json.data;
160
188
  else if (Array.isArray(json.result)) raw = json.result;
189
+ else if (Array.isArray(json.models)) raw = json.models;
161
190
  }
162
- if (!raw) throw new Error('expected an array or an object with a "data" or "result" array');
191
+ if (!raw) throw new Error('expected an array or an object with a "data", "result" or "models" array');
163
192
  const field = idField || "id";
164
193
  return raw
165
194
  .filter((m) => {
package/index.ts CHANGED
@@ -418,6 +418,52 @@ export const TEMPLATES: Record<string, {
418
418
  // fallbackModels override is needed.
419
419
  keyHint: "platform.unbiased.ai (signup is reviewed by hand; keys look like sk_...)",
420
420
  },
421
+ kilo: {
422
+ displayName: "Kilo AI",
423
+ baseUrl: "https://api.kilo.ai/api/gateway",
424
+ keyless: false,
425
+ // Multi-vendor gateway; the base path is /api/gateway, not /v1. GET
426
+ // /api/gateway/models answers 200 without a key and returns an
427
+ // OpenRouter-shaped {"data": [...]} catalog (~380 models, ids like
428
+ // anthropic/claude-sonnet-5), so no modelsUrl or fallbackModels override
429
+ // is needed. Inference itself needs a key and account credits.
430
+ keyHint: "app.kilo.ai → Your Profile on your personal account (not an organization), at the bottom of the page; needs account credits (docs at kilo.ai/docs/gateway)",
431
+ },
432
+ modelscope: {
433
+ displayName: "ModelScope",
434
+ baseUrl: "https://api-inference.modelscope.cn/v1",
435
+ keyless: false,
436
+ // Alibaba's API-Inference service. GET /v1/models answers 200 without a
437
+ // key in the plain OpenAI {"data": [...]} shape, so the default discovery
438
+ // path works as is. Free tier is an account-wide 2,000 requests/day.
439
+ keyHint: "modelscope.cn/my/myaccesstoken (SDK token, format ms-...; docs at modelscope.cn/docs/model-service/API-Inference/intro)",
440
+ },
441
+ aion_labs: {
442
+ displayName: "Aion Labs",
443
+ baseUrl: "https://api.aionlabs.ai/v1",
444
+ keyless: false,
445
+ // Aion's own API reference documents GET /v1/models as needing no
446
+ // authentication and returning its array under a top-level "models" key
447
+ // rather than "data". fetchModels normalizes that shape, so no modelsUrl
448
+ // or fallbackModels override is needed. Four models as of
449
+ // September 2026 (aion-2.0, aion-3.0, aion-3.0-mini, aion-rp-llama-3.1-8b).
450
+ keyHint: "aionlabs.ai/app/api-keys (docs at aionlabs.ai/docs/api-reference)",
451
+ },
452
+ agnes_ai: {
453
+ displayName: "Agnes AI",
454
+ baseUrl: "https://apihub.agnes-ai.com/v1",
455
+ keyless: false,
456
+ // Multimodal gateway. GET /v1/models is key-gated (it answers 401 "Token
457
+ // not provided", where an unknown /v1 path answers 404), which is exactly
458
+ // what fetchModels already sends, so no override is needed. The catalog
459
+ // also carries image and video model ids (agnes-image-*, agnes-video-*);
460
+ // they are registered too and will show up in /model, but only the text
461
+ // models serve chat/completions: the free flash tier (agnes-3.0-flash,
462
+ // agnes-2.5-flash, agnes-2.0-flash) and the paid agnes-2.5-pro pair. No
463
+ // modelFilter is set because the live id list could not be confirmed
464
+ // without a key, and a filter that misses would register nothing.
465
+ keyHint: "platform.agnes-ai.com → API Key management (keys look like sk-...; docs at wiki.agnes-ai.com)",
466
+ },
421
467
  custom: {
422
468
  displayName: "Custom Endpoint",
423
469
  baseUrl: "",
@@ -652,22 +698,24 @@ export async function fetchModels(
652
698
  // Normalize the various shapes /models can return:
653
699
  // - OpenAI style: {"data": [...]}
654
700
  // - Cloudflare / some gateways: {"result": [...]}
701
+ // - Aion Labs: {"models": [...]}
655
702
  // - Together (and a few others): [...] (bare JSON array)
656
703
  const json = (await resp.json()) as unknown;
657
704
  let raw: RawModel[] | undefined;
658
705
  if (Array.isArray(json)) {
659
706
  raw = json as RawModel[];
660
707
  } else if (json && typeof json === "object") {
661
- const obj = json as { data?: unknown; result?: unknown };
708
+ const obj = json as { data?: unknown; result?: unknown; models?: unknown };
662
709
  if (Array.isArray(obj.data)) raw = obj.data as RawModel[];
663
710
  else if (Array.isArray(obj.result)) raw = obj.result as RawModel[];
711
+ else if (Array.isArray(obj.models)) raw = obj.models as RawModel[];
664
712
  }
665
713
  if (!raw) {
666
714
  // `url` may be an override (e.g. /catalog/models, /ai/models/search), so
667
715
  // keep the wording generic rather than referring specifically to /models.
668
716
  throw new Error(
669
717
  `Unexpected model catalog payload shape from ${url} ` +
670
- `(expected an array or an object with a "data" or "result" array).`
718
+ `(expected an array or an object with a "data", "result" or "models" array).`
671
719
  );
672
720
  }
673
721
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@billjr99/pi-openai-compat",
3
- "version": "1.1.31",
3
+ "version": "1.1.32",
4
4
  "description": "pi-coding-agent extension: OpenAI-compatible endpoint support (OpenRouter, NVIDIA NIM, Nous Portal, Ollama, custom)",
5
5
  "author": "Bill Mongan <https://github.com/BillJr99>",
6
6
  "license": "MIT",