@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 +4 -0
- package/add-provider.sh +30 -1
- package/index.ts +50 -2
- package/package.json +1 -1
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 "
|
|
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 "
|
|
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.
|
|
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",
|