@lokeraar/pi-enclave-bridge 0.1.0 → 0.1.2
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 +98 -0
- package/enclave-live.ts +7 -1
- package/package.json +1 -1
- package/scripts/test-sync.mjs +3 -2
package/README.md
CHANGED
|
@@ -1,10 +1,70 @@
|
|
|
1
1
|
# @lokeraar/pi-enclave-bridge
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/@lokeraar/pi-enclave-bridge)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
|
|
3
6
|
EnClave provider for [Pi](https://pi.dev). The live router catalog shows up in
|
|
4
7
|
`/model` with **real context windows, real per-token prices, live membership and
|
|
5
8
|
the router's task aliases** — resolved from the model catalog Pi already ships,
|
|
6
9
|
with no extra account required.
|
|
7
10
|
|
|
11
|
+
<a href="https://github.com/Gentleman-Programming/gentle-ai">
|
|
12
|
+
<img width="220" src="https://raw.githubusercontent.com/Gentleman-Programming/gentle-ai/main/docs/assets/brand/built-with-gentle-ai.png" alt="Built with Gentle-AI" />
|
|
13
|
+
</a>
|
|
14
|
+
|
|
15
|
+
## 🔗 Where to find me
|
|
16
|
+
|
|
17
|
+
| | |
|
|
18
|
+
|---|---|
|
|
19
|
+
| 📦 **npm** | [`@lokeraar/pi-enclave-bridge`](https://www.npmjs.com/package/@lokeraar/pi-enclave-bridge) |
|
|
20
|
+
| 🌐 **Pi catalog** | [pi.dev/packages/@lokeraar/pi-enclave-bridge](https://pi.dev/packages/@lokeraar/pi-enclave-bridge) |
|
|
21
|
+
| ⭐ **Source** | [github.com/Lokeraar/pi-EnClave-bridge](https://github.com/Lokeraar/pi-EnClave-bridge) |
|
|
22
|
+
|
|
23
|
+
Install it in Pi:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
pi install npm:@lokeraar/pi-enclave-bridge
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
> 💛 If this bridge ever saved you from guessing a model's limits, a ⭐ on the
|
|
30
|
+
> repo goes a long way — it is the only thing that helps somebody else find it.
|
|
31
|
+
> Every star is read by a human, and so is every bug report.
|
|
32
|
+
|
|
33
|
+
## 📋 Releases
|
|
34
|
+
|
|
35
|
+
### 0.1.2 — documentation
|
|
36
|
+
|
|
37
|
+
Links in both directions, so the npm page and the source repo point at each
|
|
38
|
+
other, and a note asking for a star. No behaviour change.
|
|
39
|
+
|
|
40
|
+
### 0.1.1 — a clamp that left room for an actual prompt
|
|
41
|
+
|
|
42
|
+
The ceiling clamp kept back 2,048 tokens for the prompt. That router counts
|
|
43
|
+
`messages + tools + max_tokens` against the window, not the output alone, and a
|
|
44
|
+
real Pi call carries the system prompt plus every tool schema — order 20k
|
|
45
|
+
tokens. The reserve only covered a toy request.
|
|
46
|
+
|
|
47
|
+
`gpt-oss-120b` exposed it: a 131,072 window with a 117,964 ceiling left 13,108
|
|
48
|
+
tokens for input, below what Pi sends, so **every** call failed with `400` as
|
|
49
|
+
soon as the conversation carried anything. Measured with the same prompt:
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
input ~16k ceiling 117964 HTTP 400 "needs about 133,972 tokens"
|
|
53
|
+
input ~16k ceiling 98304 HTTP 200
|
|
54
|
+
input ~28k ceiling 98304 HTTP 200
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
The published value is a ceiling, not a fixed request: Pi reduces it per turn to
|
|
58
|
+
`min(published, contextWindow − prompt − reserve)`. The reserve just had to be
|
|
59
|
+
realistic.
|
|
60
|
+
|
|
61
|
+
### 0.1.0 — first release
|
|
62
|
+
|
|
63
|
+
Values resolved from the model catalog Pi ships, with the vendor's model card
|
|
64
|
+
outranking every catalog. `/login` once and the live router catalog appears in
|
|
65
|
+
`/model` with real context windows, real per-token prices, live membership and
|
|
66
|
+
the router's task aliases.
|
|
67
|
+
|
|
8
68
|
## ⚡ Quick Start
|
|
9
69
|
|
|
10
70
|
```bash
|
|
@@ -116,6 +176,44 @@ They are deliberately **never** resolved from a catalog. OpenRouter has a model
|
|
|
116
176
|
called `auto` too, advertising a 2,000,000 window — a different thing that shares
|
|
117
177
|
the name, and a lie here.
|
|
118
178
|
|
|
179
|
+
## 🐞 Fixes
|
|
180
|
+
|
|
181
|
+
**A ceiling that the window cannot hold is impossible, not large.** OpenRouter
|
|
182
|
+
listed `inkling` at 471,859 against a 262,144 window here, and the endpoint
|
|
183
|
+
refused it with *"This request needs about N tokens (messages + tools +
|
|
184
|
+
max_tokens)"*. Clamped to the window minus a prompt reserve.
|
|
185
|
+
|
|
186
|
+
**The reserve has to survive a real conversation.** 2,048 tokens covered a toy
|
|
187
|
+
request. This router counts `messages + tools + max_tokens` against the window,
|
|
188
|
+
not the output alone, and a real Pi call carries the system prompt plus every
|
|
189
|
+
tool schema — order 20k tokens. `gpt-oss-120b` had 13,108 tokens of input room
|
|
190
|
+
and **every** call returned `400` as soon as the conversation carried anything.
|
|
191
|
+
|
|
192
|
+
**`maxTokens` must never be `null`.** Pi's model list calls `.toString()` on it
|
|
193
|
+
and crashes with *"Cannot read properties of undefined"*, taking the whole list
|
|
194
|
+
with it.
|
|
195
|
+
|
|
196
|
+
**`compat` is never inherited from a catalog.** OpenRouter ships
|
|
197
|
+
`thinkingFormat: "openrouter"` plus seven other flags describing how *it* wants
|
|
198
|
+
reasoning framed. This endpoint speaks the OpenAI shape — verified by sending
|
|
199
|
+
`reasoning_effort` and watching what came back. Copying those flags would change
|
|
200
|
+
the request format on an endpoint they were never tested against.
|
|
201
|
+
|
|
202
|
+
**An accepted value is not an implemented one.** The endpoint accepts all six
|
|
203
|
+
effort levels for `glm-5.3`; the vendor card says the model only implements
|
|
204
|
+
low, high and max. The extras are accepted and then ignored, which is worse than
|
|
205
|
+
not offering them: Pi would show a thinking level that silently does nothing.
|
|
206
|
+
|
|
207
|
+
**A catalog that omits a key has not claimed anything.** An explicit `null` is a
|
|
208
|
+
claim and is applied; an absent key is silence and does not erase a known value.
|
|
209
|
+
Thinking maps are merged key by key, so a one-key catalog entry cannot delete a
|
|
210
|
+
seven-key one.
|
|
211
|
+
|
|
212
|
+
**A scoped package publishes private by default.** `npm publish` failed with
|
|
213
|
+
`E402 "You must sign up for private packages"`, which reads like a billing
|
|
214
|
+
problem and is not one: restricted packages need a paid plan. Declared in the
|
|
215
|
+
manifest as `"publishConfig": { "access": "public" }`.
|
|
216
|
+
|
|
119
217
|
## 🔑 Authentication
|
|
120
218
|
|
|
121
219
|
```
|
package/enclave-live.ts
CHANGED
|
@@ -181,8 +181,14 @@ const num = (v: unknown, fallback: number) => (typeof v === "number" && v > 0 ?
|
|
|
181
181
|
/**
|
|
182
182
|
* Tokens held back from an output ceiling so the prompt has room. See the clamp
|
|
183
183
|
* in buildBlock.
|
|
184
|
+
*
|
|
185
|
+
* This must cover a real Pi request, not a toy one. The router counts
|
|
186
|
+
* `messages + tools + max_tokens` against the window, so a reserve smaller than
|
|
187
|
+
* the system prompt plus every tool schema makes the model unusable in practice:
|
|
188
|
+
* gpt-oss-120b (131,072 window) shipped a 117,964 ceiling that left ~13k for
|
|
189
|
+
* input, below what Pi sends, and every call 400'd once the conversation grew.
|
|
184
190
|
*/
|
|
185
|
-
const PROMPT_RESERVE_TOKENS =
|
|
191
|
+
export const PROMPT_RESERVE_TOKENS = 32_768;
|
|
186
192
|
|
|
187
193
|
/** Aliases the router exposes: never resolved from a donor. See donors.ts. */
|
|
188
194
|
function isAliasId(id: string, aliases: readonly CatalogAlias[]): boolean {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lokeraar/pi-enclave-bridge",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "EnClave provider bridge for Pi: /login once and the live router catalog appears in /model with real context windows, real per-token prices, live membership and the router's task aliases \u2014 resolved from the model catalog Pi already ships.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./index.ts",
|
package/scripts/test-sync.mjs
CHANGED
|
@@ -20,7 +20,7 @@ import { join } from "node:path";
|
|
|
20
20
|
const ROOT = join(new URL(".", import.meta.url).pathname, "..");
|
|
21
21
|
const { bareName, resolveModel, readBundledCatalog, readPiCatalogs, findBundledCatalogDir, findBundledCatalogs, ROUNDING_TOLERANCE } =
|
|
22
22
|
await import(join(ROOT, "donors.ts"));
|
|
23
|
-
const { buildBlock } = await import(join(ROOT, "enclave-live.ts"));
|
|
23
|
+
const { buildBlock, PROMPT_RESERVE_TOKENS } = await import(join(ROOT, "enclave-live.ts"));
|
|
24
24
|
|
|
25
25
|
let passed = 0;
|
|
26
26
|
const failed = [];
|
|
@@ -214,7 +214,8 @@ console.log("\nthe block: matching, near misses, endpoint-owned fields");
|
|
|
214
214
|
check("alias price is the catalog ceiling", by["cyberouter/auto"].cost.input === 1.4, String(by["cyberouter/auto"].cost.input));
|
|
215
215
|
check("aliases carry no donor record", by["cyberouter/auto"].donor === undefined);
|
|
216
216
|
|
|
217
|
-
check("an impossible ceiling is clamped below the window", by["cyberouter/inkling"].maxTokens === 262144 -
|
|
217
|
+
check("an impossible ceiling is clamped below the window", by["cyberouter/inkling"].maxTokens === 262144 - PROMPT_RESERVE_TOKENS, String(by["cyberouter/inkling"].maxTokens));
|
|
218
|
+
check("the clamp leaves room for a real prompt", PROMPT_RESERVE_TOKENS >= 32_768, String(PROMPT_RESERVE_TOKENS));
|
|
218
219
|
check("maxTokens is never null (Pi crashes formatting it)", out.models.every((m) => typeof m.maxTokens === "number"), "hay un null");
|
|
219
220
|
}
|
|
220
221
|
|