@billjr99/pi-openai-compat 1.1.15 → 1.1.17
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 +30 -0
- package/index.ts +49 -11
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -56,8 +56,29 @@ If pi is already running when you install, type `/reload` first.
|
|
|
56
56
|
| **OpenCode Zen** | `https://opencode.ai/zen/v1` | API key from opencode.ai |
|
|
57
57
|
| **Ollama (local)** | `http://localhost:11434/v1` | Keyless |
|
|
58
58
|
| **Ollama Cloud** | `https://ollama.com/v1` | Ollama Cloud API key from ollama.com |
|
|
59
|
+
| **llmproxy** | `http://localhost:8080/v1` (editable) | Keyless by default; bearer token if your instance requires one |
|
|
59
60
|
| **Custom** | Any URL you supply | Optional bearer token |
|
|
60
61
|
|
|
62
|
+
> **The `__` → `/` model-id rewrite (display compatibility).**
|
|
63
|
+
> Some providers advertise model ids in a `provider__model` form. For example,
|
|
64
|
+
> [llmproxy](https://github.com/BillJr99/llmproxy) exposes ids like
|
|
65
|
+
> `openrouter__gpt-4` and virtual models such as `llmproxy__free` and
|
|
66
|
+
> `llmproxy__loadbalanced`. The extension can optionally rewrite the first `__`
|
|
67
|
+
> of each id to `/` (e.g. `openrouter__gpt-4` → `openrouter/gpt-4`,
|
|
68
|
+
> `llmproxy__free` → `llmproxy/free`) before registering with pi, so the ids
|
|
69
|
+
> display in the more familiar `provider/model` slash form. Upstreams that use
|
|
70
|
+
> the `__` convention canonicalize the slash form back to `__` on each request,
|
|
71
|
+
> so routing still works.
|
|
72
|
+
>
|
|
73
|
+
> This is a presentation-only convenience controlled by a per-provider config
|
|
74
|
+
> field (`rewriteDoubleUnderscore`, default **false**). It is enabled
|
|
75
|
+
> automatically for the llmproxy template purely for display consistency — other
|
|
76
|
+
> providers are unaffected, and you can turn it on or off freely. If you added a
|
|
77
|
+
> provider as a **Custom** endpoint and want the slash-form display, set
|
|
78
|
+
> `"rewriteDoubleUnderscore": true` on that provider in
|
|
79
|
+
> `~/.config/pi-openai-compat/config.json` (or re-run `/compat-login` and pick a
|
|
80
|
+
> template that enables it). Leaving it off keeps the original `__` ids.
|
|
81
|
+
|
|
61
82
|
> **Providers whose model catalog lives at a non-standard `/models` path (as of June 2026)**
|
|
62
83
|
> Some providers don't return models at `<base_url>/models`. The extension
|
|
63
84
|
> handles them in one of two ways:
|
|
@@ -327,6 +348,15 @@ For Ollama: pull at least one model first (`ollama pull llama3`).
|
|
|
327
348
|
For OpenRouter: some keys are restricted to free-tier models only.
|
|
328
349
|
For NIM: confirm your account has inference access enabled.
|
|
329
350
|
|
|
351
|
+
**`/compat-login` reports N models but far fewer appear in `/model`**
|
|
352
|
+
The usual cause is a **scoped or restricted API key/account** — the catalog
|
|
353
|
+
endpoint advertises the full model list, but your credentials are only entitled
|
|
354
|
+
to a subset, so pi only surfaces the ones you can actually use. Check whether your
|
|
355
|
+
key is limited to specific models or a free tier on the provider's dashboard.
|
|
356
|
+
(This is unrelated to the `__` → `/` rewrite, which is a display-only convenience —
|
|
357
|
+
see the note in **Supported providers** above. Toggling `rewriteDoubleUnderscore`
|
|
358
|
+
only changes how ids are displayed, not how many appear.)
|
|
359
|
+
|
|
330
360
|
**Models appear in `/model` but requests fail**
|
|
331
361
|
Check `/compat-login` ran successfully (no error message).
|
|
332
362
|
Verify Ollama is still running if using a local endpoint.
|
package/index.ts
CHANGED
|
@@ -48,6 +48,13 @@ interface ProviderConfig {
|
|
|
48
48
|
// matches its template and can't be auto-migrated, so the notice is shown
|
|
49
49
|
// only once rather than on every session_start while the config stays stale.
|
|
50
50
|
staleNotified?: boolean;
|
|
51
|
+
// When true, rewrite the FIRST "__" of every model id to "/" before
|
|
52
|
+
// registering with pi, so ids from providers that use a "provider__model"
|
|
53
|
+
// convention (e.g. llmproxy) display in the more familiar "provider/model"
|
|
54
|
+
// slash form. This is a display-only convenience: such upstreams canonicalize
|
|
55
|
+
// the slash form back to "__" on each request, so requests still round-trip.
|
|
56
|
+
// Defaults false; the wizard turns it on only for the llmproxy template.
|
|
57
|
+
rewriteDoubleUnderscore?: boolean;
|
|
51
58
|
}
|
|
52
59
|
|
|
53
60
|
interface ExtensionConfig {
|
|
@@ -97,6 +104,13 @@ const TEMPLATES: Record<string, {
|
|
|
97
104
|
modelsIdField?: string;
|
|
98
105
|
/** Keep only models whose task.name matches this string (case-insensitive). */
|
|
99
106
|
modelsKeepTask?: string;
|
|
107
|
+
/**
|
|
108
|
+
* Rewrite the first "__" of each model id to "/" before registering with pi,
|
|
109
|
+
* for display compatibility — ids from "provider__model" upstreams (e.g.
|
|
110
|
+
* llmproxy) then show in the familiar "provider/model" slash form. Display-only;
|
|
111
|
+
* default false; set true where you want the slash-form presentation.
|
|
112
|
+
*/
|
|
113
|
+
rewriteDoubleUnderscore?: boolean;
|
|
100
114
|
}> = {
|
|
101
115
|
openrouter: {
|
|
102
116
|
displayName: "OpenRouter",
|
|
@@ -288,6 +302,10 @@ const TEMPLATES: Record<string, {
|
|
|
288
302
|
baseUrl: "http://localhost:8080/v1",
|
|
289
303
|
keyless: true,
|
|
290
304
|
promptUrl: true,
|
|
305
|
+
// llmproxy advertises "provider__model" ids (and virtuals like
|
|
306
|
+
// "llmproxy__free"). Rewrite the first "__" to "/" here so they display in
|
|
307
|
+
// the familiar slash form; llmproxy canonicalizes it back on requests.
|
|
308
|
+
rewriteDoubleUnderscore: true,
|
|
291
309
|
},
|
|
292
310
|
vercel: {
|
|
293
311
|
displayName: "Vercel AI Gateway",
|
|
@@ -535,16 +553,31 @@ async function fetchModels(
|
|
|
535
553
|
// Provider registration helpers
|
|
536
554
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
537
555
|
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
})
|
|
556
|
+
/**
|
|
557
|
+
* Rewrite the FIRST "__" of a model id to "/". Only the first occurrence is
|
|
558
|
+
* touched: the provider/virtual segment that precedes it never contains "__" or
|
|
559
|
+
* "/", so this is the exact inverse of the slash→"__" canonicalization llmproxy
|
|
560
|
+
* applies on the request side, keeping ids round-trippable. Ids without "__" are
|
|
561
|
+
* returned unchanged.
|
|
562
|
+
*/
|
|
563
|
+
function rewriteFirstDoubleUnderscore(id: string): string {
|
|
564
|
+
const i = id.indexOf("__");
|
|
565
|
+
return i === -1 ? id : `${id.slice(0, i)}/${id.slice(i + 2)}`;
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
function buildProviderModels(models: CachedModel[], rewriteDoubleUnderscore = false) {
|
|
569
|
+
return models.map((m) => {
|
|
570
|
+
const id = rewriteDoubleUnderscore ? rewriteFirstDoubleUnderscore(m.id) : m.id;
|
|
571
|
+
return {
|
|
572
|
+
id,
|
|
573
|
+
name: id,
|
|
574
|
+
reasoning: false,
|
|
575
|
+
input: ["text"] as string[],
|
|
576
|
+
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
577
|
+
contextWindow: m.contextWindow ?? 128_000,
|
|
578
|
+
maxTokens: m.maxTokens ?? 4_096,
|
|
579
|
+
};
|
|
580
|
+
});
|
|
548
581
|
}
|
|
549
582
|
|
|
550
583
|
function compatKey(key: string): string {
|
|
@@ -552,12 +585,16 @@ function compatKey(key: string): string {
|
|
|
552
585
|
}
|
|
553
586
|
|
|
554
587
|
function registerProvider(pi: ExtensionAPI, key: string, p: ProviderConfig): void {
|
|
588
|
+
// Honor the persisted per-provider flag; fall back to the template default for
|
|
589
|
+
// this key so providers logged in before the flag existed (e.g. an existing
|
|
590
|
+
// llmproxy provider) still get the rewrite without a re-login.
|
|
591
|
+
const rewrite = p.rewriteDoubleUnderscore ?? TEMPLATES[key]?.rewriteDoubleUnderscore ?? false;
|
|
555
592
|
pi.registerProvider(compatKey(key), {
|
|
556
593
|
name: `compat/${key.replace(/_/g, "-")}`,
|
|
557
594
|
baseUrl: p.baseUrl,
|
|
558
595
|
apiKey: p.apiKey ?? (isLocalUrl(p.baseUrl) ? "local" : ""),
|
|
559
596
|
api: "openai-completions" as const,
|
|
560
|
-
models: buildProviderModels(p.cachedModels),
|
|
597
|
+
models: buildProviderModels(p.cachedModels, rewrite),
|
|
561
598
|
});
|
|
562
599
|
}
|
|
563
600
|
|
|
@@ -800,6 +837,7 @@ export default async function (pi: ExtensionAPI) {
|
|
|
800
837
|
modelsUrl,
|
|
801
838
|
modelsIdField: tpl.modelsIdField,
|
|
802
839
|
modelsKeepTask: tpl.modelsKeepTask,
|
|
840
|
+
rewriteDoubleUnderscore: tpl.rewriteDoubleUnderscore,
|
|
803
841
|
};
|
|
804
842
|
saveConfig(config);
|
|
805
843
|
registerProvider(pi, key, config.providers[key]);
|
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.17",
|
|
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",
|