@billjr99/pi-openai-compat 1.0.0 → 1.0.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/index.ts +137 -10
- package/package.json +1 -1
package/index.ts
CHANGED
|
@@ -57,6 +57,10 @@ const TEMPLATES: Record<string, {
|
|
|
57
57
|
baseUrl: string;
|
|
58
58
|
keyless: boolean;
|
|
59
59
|
keyHint?: string;
|
|
60
|
+
/** If set, only models whose id appears in this list are kept after fetching. */
|
|
61
|
+
modelFilter?: string[];
|
|
62
|
+
/** If true, prompt the user to confirm/edit the base URL (like ollama/custom). */
|
|
63
|
+
promptUrl?: boolean;
|
|
60
64
|
}> = {
|
|
61
65
|
openrouter: {
|
|
62
66
|
displayName: "OpenRouter",
|
|
@@ -76,15 +80,116 @@ const TEMPLATES: Record<string, {
|
|
|
76
80
|
keyless: false,
|
|
77
81
|
keyHint: "Your Nous Portal API key",
|
|
78
82
|
},
|
|
83
|
+
google: {
|
|
84
|
+
displayName: "Google Gemini",
|
|
85
|
+
baseUrl: "https://generativelanguage.googleapis.com/v1beta/openai",
|
|
86
|
+
keyless: false,
|
|
87
|
+
keyHint: "Free key from aistudio.google.com (free Google account, no credit card)",
|
|
88
|
+
modelFilter: [
|
|
89
|
+
"gemini-2.5-flash",
|
|
90
|
+
"gemini-2.5-flash-lite",
|
|
91
|
+
"gemini-3-flash-preview",
|
|
92
|
+
"gemini-3.1-flash-lite-preview",
|
|
93
|
+
"gemini-3.1-pro-preview",
|
|
94
|
+
],
|
|
95
|
+
},
|
|
96
|
+
cerebras: {
|
|
97
|
+
displayName: "Cerebras",
|
|
98
|
+
baseUrl: "https://api.cerebras.ai/v1",
|
|
99
|
+
keyless: false,
|
|
100
|
+
keyHint: "Free account at cerebras.ai (no credit card)",
|
|
101
|
+
modelFilter: ["qwen3-235b"],
|
|
102
|
+
},
|
|
103
|
+
github_models: {
|
|
104
|
+
displayName: "GitHub Models",
|
|
105
|
+
baseUrl: "https://models.inference.ai.azure.com",
|
|
106
|
+
keyless: false,
|
|
107
|
+
keyHint: "GitHub Personal Access Token (any free GitHub account, no special scopes needed)",
|
|
108
|
+
modelFilter: ["gpt-4o", "openai/gpt-4.1"],
|
|
109
|
+
},
|
|
110
|
+
sambanova: {
|
|
111
|
+
displayName: "SambaNova",
|
|
112
|
+
baseUrl: "https://api.sambanova.ai/v1",
|
|
113
|
+
keyless: false,
|
|
114
|
+
keyHint: "Free account at cloud.sambanova.ai (no credit card)",
|
|
115
|
+
modelFilter: [
|
|
116
|
+
"Meta-Llama-3.3-70B-Instruct",
|
|
117
|
+
"DeepSeek-V3.1",
|
|
118
|
+
"DeepSeek-V3.2",
|
|
119
|
+
"gpt-oss-120b",
|
|
120
|
+
"Llama-4-Maverick-17B-128E-Instruct",
|
|
121
|
+
"gemma-3-12b-it",
|
|
122
|
+
],
|
|
123
|
+
},
|
|
124
|
+
mistral: {
|
|
125
|
+
displayName: "Mistral",
|
|
126
|
+
baseUrl: "https://api.mistral.ai/v1",
|
|
127
|
+
keyless: false,
|
|
128
|
+
keyHint: 'Free "Experiment" tier at console.mistral.ai (no credit card)',
|
|
129
|
+
modelFilter: [
|
|
130
|
+
"mistral-large-latest",
|
|
131
|
+
"mistral-medium-latest",
|
|
132
|
+
"magistral-medium-latest",
|
|
133
|
+
"codestral-latest",
|
|
134
|
+
"devstral-latest",
|
|
135
|
+
],
|
|
136
|
+
},
|
|
137
|
+
groq: {
|
|
138
|
+
displayName: "Groq",
|
|
139
|
+
baseUrl: "https://api.groq.com/openai/v1",
|
|
140
|
+
keyless: false,
|
|
141
|
+
keyHint: "Free account at console.groq.com (no credit card)",
|
|
142
|
+
modelFilter: [
|
|
143
|
+
"llama-3.3-70b-versatile",
|
|
144
|
+
"meta-llama/llama-4-scout-17b-16e-instruct",
|
|
145
|
+
"openai/gpt-oss-120b",
|
|
146
|
+
"openai/gpt-oss-20b",
|
|
147
|
+
"qwen/qwen3-32b",
|
|
148
|
+
"llama-3.1-8b-instant",
|
|
149
|
+
],
|
|
150
|
+
},
|
|
151
|
+
cloudflare: {
|
|
152
|
+
displayName: "Cloudflare Workers AI",
|
|
153
|
+
baseUrl: "https://api.cloudflare.com/client/v4/accounts/YOUR_ACCOUNT_ID/ai/v1",
|
|
154
|
+
keyless: false,
|
|
155
|
+
promptUrl: true,
|
|
156
|
+
keyHint: 'Cloudflare API Token with "Workers AI Read" permission (free account at cloudflare.com)',
|
|
157
|
+
modelFilter: [
|
|
158
|
+
"@cf/meta/llama-3.3-70b-instruct-fp8-fast",
|
|
159
|
+
"@cf/meta/llama-4-scout-17b-16e-instruct",
|
|
160
|
+
"@cf/openai/gpt-oss-120b",
|
|
161
|
+
"@cf/zai-org/glm-4.7-flash",
|
|
162
|
+
"@cf/moonshotai/kimi-k2.5",
|
|
163
|
+
"@cf/moonshotai/kimi-k2.6",
|
|
164
|
+
"@cf/qwen/qwen3-30b-a3b-fp8",
|
|
165
|
+
"@cf/deepseek-ai/deepseek-r1-distill-qwen-32b",
|
|
166
|
+
"@cf/ibm-granite/granite-4.0-h-micro",
|
|
167
|
+
],
|
|
168
|
+
},
|
|
169
|
+
zhipu: {
|
|
170
|
+
displayName: "Zhipu (Z.ai / BigModel)",
|
|
171
|
+
baseUrl: "https://open.bigmodel.cn/api/paas/v4",
|
|
172
|
+
keyless: false,
|
|
173
|
+
keyHint: "Free account at open.bigmodel.cn (no credit card)",
|
|
174
|
+
modelFilter: ["glm-4.5-flash", "glm-4.7-flash"],
|
|
175
|
+
},
|
|
176
|
+
cohere: {
|
|
177
|
+
displayName: "Cohere",
|
|
178
|
+
baseUrl: "https://api.cohere.com/compatibility/v1",
|
|
179
|
+
keyless: false,
|
|
180
|
+
keyHint: "Your Cohere API key",
|
|
181
|
+
},
|
|
79
182
|
ollama: {
|
|
80
183
|
displayName: "Ollama (local, keyless)",
|
|
81
184
|
baseUrl: "http://localhost:11434/v1",
|
|
82
185
|
keyless: true,
|
|
186
|
+
promptUrl: true,
|
|
83
187
|
},
|
|
84
188
|
custom: {
|
|
85
189
|
displayName: "Custom Endpoint",
|
|
86
190
|
baseUrl: "",
|
|
87
191
|
keyless: false,
|
|
192
|
+
promptUrl: true,
|
|
88
193
|
keyHint: "Bearer token or API key (leave blank if keyless)",
|
|
89
194
|
},
|
|
90
195
|
};
|
|
@@ -266,18 +371,26 @@ export default async function (pi: ExtensionAPI) {
|
|
|
266
371
|
const key = keys[labels.indexOf(selectedLabel)];
|
|
267
372
|
const tpl = TEMPLATES[key];
|
|
268
373
|
|
|
269
|
-
// Step 2 — base URL
|
|
374
|
+
// Step 2 — base URL
|
|
270
375
|
let baseUrl = tpl.baseUrl;
|
|
271
|
-
if (key === "
|
|
272
|
-
|
|
376
|
+
if (key === "cloudflare") {
|
|
377
|
+
// Ask for just the account ID and splice it into the template URL.
|
|
273
378
|
const entered = await ctx.ui.input(
|
|
274
|
-
"
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
: "Base URL of your endpoint (e.g. https://api.example.com/v1):",
|
|
278
|
-
defaultUrl
|
|
379
|
+
"Account ID",
|
|
380
|
+
"Your Cloudflare Account ID (find it on the Cloudflare dashboard overview page):",
|
|
381
|
+
""
|
|
279
382
|
);
|
|
280
|
-
if (entered
|
|
383
|
+
if (entered == null) { ctx.ui.notify("Login cancelled.", "info"); return; }
|
|
384
|
+
const accountId = entered.trim();
|
|
385
|
+
if (!accountId) { ctx.ui.notify("Account ID cannot be empty.", "error"); return; }
|
|
386
|
+
baseUrl = tpl.baseUrl.replace("YOUR_ACCOUNT_ID", accountId);
|
|
387
|
+
} else if (tpl.promptUrl) {
|
|
388
|
+
const defaultUrl = tpl.baseUrl;
|
|
389
|
+
const prompt = key === "ollama"
|
|
390
|
+
? `Ollama base URL — press Enter for default (${defaultUrl}):`
|
|
391
|
+
: "Base URL of your endpoint (e.g. https://api.example.com/v1):";
|
|
392
|
+
const entered = await ctx.ui.input("Base URL", prompt, defaultUrl);
|
|
393
|
+
if (entered == null) { ctx.ui.notify("Login cancelled.", "info"); return; }
|
|
281
394
|
baseUrl = (entered.trim() || defaultUrl).replace(/\/+$/, "");
|
|
282
395
|
if (!baseUrl) { ctx.ui.notify("Base URL cannot be empty.", "error"); return; }
|
|
283
396
|
}
|
|
@@ -290,7 +403,7 @@ export default async function (pi: ExtensionAPI) {
|
|
|
290
403
|
`${tpl.keyHint ?? "Your API key"} — leave blank if keyless:`,
|
|
291
404
|
""
|
|
292
405
|
);
|
|
293
|
-
if (entered
|
|
406
|
+
if (entered == null) { ctx.ui.notify("Login cancelled.", "info"); return; }
|
|
294
407
|
apiKey = entered.trim() || null;
|
|
295
408
|
}
|
|
296
409
|
|
|
@@ -308,6 +421,20 @@ export default async function (pi: ExtensionAPI) {
|
|
|
308
421
|
return;
|
|
309
422
|
}
|
|
310
423
|
|
|
424
|
+
// Apply model filter if the template defines one (keeps only free/known models).
|
|
425
|
+
if (tpl.modelFilter && tpl.modelFilter.length > 0) {
|
|
426
|
+
const filterSet = new Set(tpl.modelFilter);
|
|
427
|
+
const filtered = models.filter((m) => filterSet.has(m.id));
|
|
428
|
+
if (filtered.length > 0) {
|
|
429
|
+
models = filtered;
|
|
430
|
+
} else {
|
|
431
|
+
ctx.ui.notify(
|
|
432
|
+
`None of the expected free models were found — registering all ${models.length} model(s) returned by the provider. The provider may have renamed their models.`,
|
|
433
|
+
"warning"
|
|
434
|
+
);
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
|
|
311
438
|
// Step 5 — save to config and register with pi
|
|
312
439
|
config.providers[key] = {
|
|
313
440
|
displayName: tpl.displayName,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@billjr99/pi-openai-compat",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
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",
|