pi-freeflow 1.7.0 → 1.8.0
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 +57 -14
- package/package.json +62 -62
- package/src/catalog.ts +2 -2
- package/src/index.ts +3 -3
- package/src/models.ts +42 -4
- package/src/proxy.ts +3 -4
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# pi-freeflow 🌊
|
|
2
2
|
|
|
3
|
-
> **
|
|
3
|
+
> **28 free models. Up to 1M context. Zero API keys. Infinite scale via your own relay pool.**
|
|
4
4
|
|
|
5
5
|
Thin by design: model list + dumb relay + log. Host `pi-ai` owns thinking, normalization & provider magic. We just make it free, fast, and unbreakable.
|
|
6
6
|
|
|
@@ -18,7 +18,7 @@ Join devs bypassing rate limits with their own relay pools. BYO, add as many as
|
|
|
18
18
|
|
|
19
19
|
| Feature | Description | Value | Cost |
|
|
20
20
|
| :--- | :--- | :--- | :--- |
|
|
21
|
-
| **
|
|
21
|
+
| **28 Curated Free Models** | 8 OpenCode Zen + 20 KiloCode Gateway models, up to 1M context & 512K output | Ceiling Unlocked | **$0** |
|
|
22
22
|
| **BYO Relay Pool** | Round-robin load balancing across your Cloudflare Workers & Vercel Edges | Zero Rate Limits | **$0** (your free tiers) |
|
|
23
23
|
| **Adaptive Health & Error Detection** | Auto-cooldown on 429 rate limits, 504 timeouts, and socket drops | 0ms Wasted Latency | **$0** |
|
|
24
24
|
| **Stream Truncation Resilience** | Stateful SSE terminal tracking (`response.failed` / `response.incomplete` injection) | Zero Host Crashes | **$0** |
|
|
@@ -32,7 +32,7 @@ Philosophy: **Thin by design.** We only ship model list + relay proxy + log. Hos
|
|
|
32
32
|
|
|
33
33
|
---
|
|
34
34
|
|
|
35
|
-
###
|
|
35
|
+
### 28 Curated Models, One Command
|
|
36
36
|
|
|
37
37
|
```bash
|
|
38
38
|
/model → freeflow → pick
|
|
@@ -123,33 +123,64 @@ Manage your relay pool directly from the OMP / Pi terminal:
|
|
|
123
123
|
|
|
124
124
|
### Quick Start in 30 Seconds
|
|
125
125
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
**Oh My Pi (Recommended):**
|
|
126
|
+
**On Oh My Pi (OMP):**
|
|
129
127
|
```bash
|
|
130
128
|
omp plugin install pi-freeflow
|
|
131
|
-
# or local dev
|
|
129
|
+
# or local dev (repo checkout)
|
|
132
130
|
omp plugin link /path/to/pi-freeflow
|
|
133
131
|
```
|
|
134
132
|
|
|
135
|
-
**Pi:**
|
|
133
|
+
**On Pi:**
|
|
136
134
|
```bash
|
|
137
135
|
pi install npm:pi-freeflow
|
|
138
136
|
```
|
|
139
137
|
|
|
138
|
+
> Both commands fetch the **same npm package** from the registry — pi-freeflow
|
|
139
|
+
> is an extension loaded by the host, not a standalone CLI. It works on **OMP
|
|
140
|
+
> and Pi only** (they share the extension API).
|
|
141
|
+
|
|
140
142
|
#### 2. Pick a Model
|
|
141
143
|
|
|
144
|
+
**OMP — interactive:**
|
|
142
145
|
```bash
|
|
143
146
|
omp
|
|
144
147
|
/model → freeflow → muse-spark-1.2-contributor-free (1M) → max
|
|
148
|
+
```
|
|
145
149
|
|
|
146
|
-
|
|
150
|
+
**OMP — one-shot CLI:**
|
|
151
|
+
```bash
|
|
147
152
|
omp -p --model freeflow/muse-spark-1.2-contributor-free "build me a SaaS"
|
|
148
|
-
|
|
149
|
-
|
|
153
|
+
omp -p --model freeflow/step-3.7-flash:high "solve this bug" # alias + thinking level
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
**Pi — interactive:**
|
|
157
|
+
```bash
|
|
158
|
+
pi
|
|
159
|
+
/model → freeflow → pick
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
**Pi — one-shot CLI:**
|
|
163
|
+
```bash
|
|
164
|
+
pi -p --model freeflow/step-3.7-flash:high "solve this bug"
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
> Model IDs accept a full canonical ID, a short alias (see the tables above),
|
|
168
|
+
> and an optional `:effort` suffix (`:minimal` … `:xhigh`, `:max` where
|
|
169
|
+
> supported). The host resolves the rest — you only type `freeflow/<name>`.
|
|
170
|
+
|
|
171
|
+
#### 3. Manage Your Relay Pool (OMP & Pi both)
|
|
172
|
+
|
|
173
|
+
```bash
|
|
174
|
+
/freeflow status # active relay, pool status, candidates
|
|
175
|
+
/freeflow list # relays with health badges
|
|
176
|
+
/freeflow add <url> [label]
|
|
177
|
+
/freeflow deploy # guided deploy: vercel|cloudflare|deno
|
|
178
|
+
/freeflow logs [n] # tail proxy logs
|
|
150
179
|
```
|
|
151
180
|
|
|
152
|
-
|
|
181
|
+
These slash commands work **identically in OMP and Pi** — the extension
|
|
182
|
+
registers the same `/freeflow` command set in both hosts.
|
|
183
|
+
#### 4. Add Your Free Relays (Scale Infinitely)
|
|
153
184
|
|
|
154
185
|
Default ships direct. Add relays via `/freeflow add <url> [label]`.
|
|
155
186
|
|
|
@@ -231,7 +262,7 @@ Log rotation at 10MB. Clean, parseable, real-time HTTP lifecycle tracking.
|
|
|
231
262
|
|
|
232
263
|
This package stays thin. It ships three things: a model catalog, a relay proxy, and a log. There is no build step. The only runtime dependency is `undici`, which powers the upstream fetch agent. Thinking and prompt normalization stay with the host (`pi-ai`).
|
|
233
264
|
|
|
234
|
-
Current size: about 11.3k lines including tests.
|
|
265
|
+
Current size: about 11.3k lines including tests. 230 tests pass, typecheck clean.
|
|
235
266
|
|
|
236
267
|
---
|
|
237
268
|
|
|
@@ -251,6 +282,18 @@ Deleted in 1.3.0. If zai/qwen/deepseek thinking broke before, it's fixed now bec
|
|
|
251
282
|
|
|
252
283
|
**Why is context free?**
|
|
253
284
|
We use OpenCode Zen & Kilo free tiers. You pay only with your own Cloudflare/Vercel free tiers for egress.
|
|
285
|
+
**Why is it installed via npm?**
|
|
286
|
+
The npm package is the **distribution channel** only — both hosts resolve it internally:
|
|
287
|
+
`omp plugin install pi-freeflow` and `pi install npm:pi-freeflow` install the same
|
|
288
|
+
package from the npm registry. pi-freeflow is an **extension, not a standalone CLI** —
|
|
289
|
+
the host (OMP or Pi) loads and runs it. A plain `npm install` just downloads the
|
|
290
|
+
files; it is not a supported way to run the extension.
|
|
291
|
+
|
|
292
|
+
**Which hosts can use it?**
|
|
293
|
+
Oh My Pi (OMP) and Pi only. They share the same extension API
|
|
294
|
+
(`extensions/index.ts` declares both `omp` and `pi` extension entries), so one
|
|
295
|
+
package serves both. Other AI agents (OpenCode, KiloCode, Cursor, ...) have their
|
|
296
|
+
own plugin systems and do not load this extension.
|
|
254
297
|
|
|
255
298
|
---
|
|
256
299
|
|
|
@@ -281,7 +324,7 @@ pnpm smoke # verifies extensions/index.ts loads without crashing
|
|
|
281
324
|
```
|
|
282
325
|
src/
|
|
283
326
|
├── index.ts # extension entry, lifecycle hooks
|
|
284
|
-
├── models.ts #
|
|
327
|
+
├── models.ts # 28-model catalog definitions
|
|
285
328
|
├── catalog.ts # model catalog cache (24h disk)
|
|
286
329
|
├── proxy.ts # local proxy server (127.0.0.1:28180)
|
|
287
330
|
├── relay.ts # relay selection & round-robin
|
package/package.json
CHANGED
|
@@ -1,62 +1,62 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "pi-freeflow",
|
|
3
|
-
"type": "module",
|
|
4
|
-
"version": "1.
|
|
5
|
-
"description": "Thin provider for OMP/Pi — model list + dumb relay proxy + log; host pi-ai owns thinking/normalization",
|
|
6
|
-
"main": "extensions/index.ts",
|
|
7
|
-
"types": "src/index.ts",
|
|
8
|
-
"keywords": [
|
|
9
|
-
"pi-package",
|
|
10
|
-
"pi-extension",
|
|
11
|
-
"oh-my-pi",
|
|
12
|
-
"omp",
|
|
13
|
-
"free-models",
|
|
14
|
-
"opencode",
|
|
15
|
-
"kilocode",
|
|
16
|
-
"ai-models",
|
|
17
|
-
"relay"
|
|
18
|
-
],
|
|
19
|
-
"author": "trefeon",
|
|
20
|
-
"license": "MIT",
|
|
21
|
-
"repository": {
|
|
22
|
-
"type": "git",
|
|
23
|
-
"url": "git+https://github.com/trefeon/pi-freeflow.git"
|
|
24
|
-
},
|
|
25
|
-
"homepage": "https://github.com/trefeon/pi-freeflow#readme",
|
|
26
|
-
"engines": {
|
|
27
|
-
"node": ">=22.19.0"
|
|
28
|
-
},
|
|
29
|
-
"omp": {
|
|
30
|
-
"extensions": [
|
|
31
|
-
"./extensions"
|
|
32
|
-
]
|
|
33
|
-
},
|
|
34
|
-
"pi": {
|
|
35
|
-
"extensions": [
|
|
36
|
-
"./extensions"
|
|
37
|
-
]
|
|
38
|
-
},
|
|
39
|
-
"files": [
|
|
40
|
-
"extensions",
|
|
41
|
-
"src",
|
|
42
|
-
"README.md",
|
|
43
|
-
"LICENSE"
|
|
44
|
-
],
|
|
45
|
-
"scripts": {
|
|
46
|
-
"test": "node --experimental-strip-types --test --test-concurrency=1 test/**/*.test.ts",
|
|
47
|
-
"typecheck": "tsc --noEmit",
|
|
48
|
-
"smoke": "node --experimental-strip-types -e \"import('./extensions/index.ts').then(() => console.log('✓ Smoke test passed: extensions/index.ts loaded successfully')).catch(err => { console.error(err); process.exit(1); })\"",
|
|
49
|
-
"changeset": "changeset",
|
|
50
|
-
"docs:dev": "vitepress dev docs",
|
|
51
|
-
"docs:build": "vitepress build docs"
|
|
52
|
-
},
|
|
53
|
-
"devDependencies": {
|
|
54
|
-
"@changesets/cli": "^2.27.0",
|
|
55
|
-
"@types/node": "^22.13.9",
|
|
56
|
-
"typescript": "^5.8.2",
|
|
57
|
-
"vitepress": "^1.6.4"
|
|
58
|
-
},
|
|
59
|
-
"dependencies": {
|
|
60
|
-
"undici": "^8.10.0"
|
|
61
|
-
}
|
|
62
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "pi-freeflow",
|
|
3
|
+
"type": "module",
|
|
4
|
+
"version": "1.8.0",
|
|
5
|
+
"description": "Thin provider for OMP/Pi — model list + dumb relay proxy + log; host pi-ai owns thinking/normalization",
|
|
6
|
+
"main": "extensions/index.ts",
|
|
7
|
+
"types": "src/index.ts",
|
|
8
|
+
"keywords": [
|
|
9
|
+
"pi-package",
|
|
10
|
+
"pi-extension",
|
|
11
|
+
"oh-my-pi",
|
|
12
|
+
"omp",
|
|
13
|
+
"free-models",
|
|
14
|
+
"opencode",
|
|
15
|
+
"kilocode",
|
|
16
|
+
"ai-models",
|
|
17
|
+
"relay"
|
|
18
|
+
],
|
|
19
|
+
"author": "trefeon",
|
|
20
|
+
"license": "MIT",
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "git+https://github.com/trefeon/pi-freeflow.git"
|
|
24
|
+
},
|
|
25
|
+
"homepage": "https://github.com/trefeon/pi-freeflow#readme",
|
|
26
|
+
"engines": {
|
|
27
|
+
"node": ">=22.19.0"
|
|
28
|
+
},
|
|
29
|
+
"omp": {
|
|
30
|
+
"extensions": [
|
|
31
|
+
"./extensions"
|
|
32
|
+
]
|
|
33
|
+
},
|
|
34
|
+
"pi": {
|
|
35
|
+
"extensions": [
|
|
36
|
+
"./extensions"
|
|
37
|
+
]
|
|
38
|
+
},
|
|
39
|
+
"files": [
|
|
40
|
+
"extensions",
|
|
41
|
+
"src",
|
|
42
|
+
"README.md",
|
|
43
|
+
"LICENSE"
|
|
44
|
+
],
|
|
45
|
+
"scripts": {
|
|
46
|
+
"test": "node --experimental-strip-types --test --test-concurrency=1 test/**/*.test.ts",
|
|
47
|
+
"typecheck": "tsc --noEmit",
|
|
48
|
+
"smoke": "node --experimental-strip-types -e \"import('./extensions/index.ts').then(() => console.log('✓ Smoke test passed: extensions/index.ts loaded successfully')).catch(err => { console.error(err); process.exit(1); })\"",
|
|
49
|
+
"changeset": "changeset",
|
|
50
|
+
"docs:dev": "vitepress dev docs",
|
|
51
|
+
"docs:build": "vitepress build docs"
|
|
52
|
+
},
|
|
53
|
+
"devDependencies": {
|
|
54
|
+
"@changesets/cli": "^2.27.0",
|
|
55
|
+
"@types/node": "^22.13.9",
|
|
56
|
+
"typescript": "^5.8.2",
|
|
57
|
+
"vitepress": "^1.6.4"
|
|
58
|
+
},
|
|
59
|
+
"dependencies": {
|
|
60
|
+
"undici": "^8.10.0"
|
|
61
|
+
}
|
|
62
|
+
}
|
package/src/catalog.ts
CHANGED
|
@@ -34,7 +34,7 @@ import type {
|
|
|
34
34
|
export const DEAD_MODEL_IDS = new Set<string>(["deepseek-v4-flash-free", "x-preview-f-free"]);
|
|
35
35
|
/**
|
|
36
36
|
* In-memory cache of currently active/available free models.
|
|
37
|
-
* Initialized with all
|
|
37
|
+
* Initialized with all 28 verified models for 0ms instant availability.
|
|
38
38
|
*/
|
|
39
39
|
let aliveCatalog: RegisteredModel[] = ALL_MODELS.map((m) => ({
|
|
40
40
|
...m,
|
|
@@ -328,6 +328,6 @@ export async function refreshCatalog(force = false): Promise<RegisteredModel[]>
|
|
|
328
328
|
} catch (err) {
|
|
329
329
|
logDebug("Failed reading stale catalog cache", { error: String(err) });
|
|
330
330
|
}
|
|
331
|
-
// No valid cache — return in-memory static
|
|
331
|
+
// No valid cache — return in-memory static 28 (host will refresh if needed)
|
|
332
332
|
return aliveCatalog;
|
|
333
333
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* pi-freeflow — Modular, high-resiliency LLM extension for Pi & Oh My Pi (OMP)
|
|
3
3
|
*
|
|
4
|
-
* Provides access to
|
|
4
|
+
* Provides access to 28 free models (8 OpenCode Zen + 20 KiloCode Gateway) with:
|
|
5
5
|
* - Single-port daemon reuse on 28180 across concurrent subagents
|
|
6
6
|
* - Multi-cloud rolling egress relays (Vercel Edge, Cloudflare, Deno)
|
|
7
7
|
* - 0ms instant startup with verified static catalog and background live health checks
|
|
@@ -114,7 +114,7 @@ export function buildProviderConfig(
|
|
|
114
114
|
): ProviderConfig {
|
|
115
115
|
return {
|
|
116
116
|
baseUrl: `http://${HOST}:${port}/v1`,
|
|
117
|
-
apiKey: "
|
|
117
|
+
apiKey: "public",
|
|
118
118
|
api: "openai-completions",
|
|
119
119
|
compat: { supportsDeveloperRole: false },
|
|
120
120
|
models: models.map((m) => {
|
|
@@ -310,7 +310,7 @@ export default async function (pi: ExtensionAPI): Promise<void> {
|
|
|
310
310
|
? `Relay pool ready: ${freshRelayState.relays.length} relay(s). Run /freeflow for pool management.`
|
|
311
311
|
: "Relay pool empty — direct mode. Run /freeflow deploy to add your own egress.";
|
|
312
312
|
ctx.ui?.notify?.(
|
|
313
|
-
`freeflow ready:
|
|
313
|
+
`freeflow ready: 28 free models via local proxy 127.0.0.1:28180. ${hint}`,
|
|
314
314
|
"info",
|
|
315
315
|
);
|
|
316
316
|
}
|
package/src/models.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Static model definitions and upstream routing catalogs for pi-freeflow
|
|
3
3
|
*
|
|
4
|
-
* Defines the
|
|
5
|
-
* -
|
|
6
|
-
* -
|
|
4
|
+
* Defines the 28 verified free models:
|
|
5
|
+
* - 8 OpenCode Zen models (1 Responses API + 7 Chat Completions)
|
|
6
|
+
* - 20 KiloCode Keyless Gateway models (19 OpenRouter format + 1 Standard format)
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import type { ModelDef, ThinkingLevelMap, Upstream } from "./types.ts";
|
|
@@ -126,6 +126,22 @@ export const OPENCODE_MODELS: ModelDef[] = [
|
|
|
126
126
|
xhigh: "xhigh",
|
|
127
127
|
max: null,},
|
|
128
128
|
},
|
|
129
|
+
{
|
|
130
|
+
id: "ling-3.0-flash-fin-free",
|
|
131
|
+
name: "Ling 3.0 Flash Fin (256K)",
|
|
132
|
+
reasoning: true,
|
|
133
|
+
contextWindow: 262_144,
|
|
134
|
+
maxTokens: 131_072,
|
|
135
|
+
input: ["text"],
|
|
136
|
+
thinkingLevelMap: {
|
|
137
|
+
off: null,
|
|
138
|
+
minimal: "minimal",
|
|
139
|
+
low: "low",
|
|
140
|
+
medium: "medium",
|
|
141
|
+
high: "high",
|
|
142
|
+
xhigh: "xhigh",
|
|
143
|
+
max: null,},
|
|
144
|
+
},
|
|
129
145
|
];
|
|
130
146
|
|
|
131
147
|
/**
|
|
@@ -328,6 +344,26 @@ export const KILO_MODELS: ModelDef[] = [
|
|
|
328
344
|
thinkingFormat: "openrouter",
|
|
329
345
|
thinkingLevelMap: KILO_REASONING_MAP,
|
|
330
346
|
},
|
|
347
|
+
{
|
|
348
|
+
id: "thinkingmachines/inkling:free",
|
|
349
|
+
name: "Inkling (1M)",
|
|
350
|
+
reasoning: true,
|
|
351
|
+
contextWindow: 1_048_576,
|
|
352
|
+
maxTokens: 262_144,
|
|
353
|
+
input: ["text", "image"],
|
|
354
|
+
thinkingFormat: "openrouter",
|
|
355
|
+
thinkingLevelMap: KILO_REASONING_MAP,
|
|
356
|
+
},
|
|
357
|
+
{
|
|
358
|
+
id: "thinkingmachines/inkling-small:free",
|
|
359
|
+
name: "Inkling Small (1M)",
|
|
360
|
+
reasoning: true,
|
|
361
|
+
contextWindow: 1_048_576,
|
|
362
|
+
maxTokens: 262_144,
|
|
363
|
+
input: ["text", "image"],
|
|
364
|
+
thinkingFormat: "openrouter",
|
|
365
|
+
thinkingLevelMap: KILO_REASONING_MAP,
|
|
366
|
+
},
|
|
331
367
|
];
|
|
332
368
|
|
|
333
369
|
/**
|
|
@@ -352,6 +388,8 @@ export const MODEL_ALIASES: Record<string, string> = {
|
|
|
352
388
|
"minimax-m2.7": "minimax/minimax-m2.7:free",
|
|
353
389
|
"minimax-m3": "minimax/minimax-m3:free",
|
|
354
390
|
"ling-3.0-flash-fin": "inclusionai/ling-3.0-flash-fin:free",
|
|
391
|
+
"inkling": "thinkingmachines/inkling:free",
|
|
392
|
+
"inkling-small": "thinkingmachines/inkling-small:free",
|
|
355
393
|
// provider-prefixed short aliases (slash-normalized)
|
|
356
394
|
"hy3:free": "tencent/hy3:free",
|
|
357
395
|
"laguna-s-2.1:free": "poolside/laguna-s-2.1:free",
|
|
@@ -379,7 +417,7 @@ export const KILO_MODEL_IDS = new Set<string>([
|
|
|
379
417
|
]);
|
|
380
418
|
|
|
381
419
|
/**
|
|
382
|
-
* Combined list of all
|
|
420
|
+
* Combined list of all 28 static free models (canonical)
|
|
383
421
|
*/
|
|
384
422
|
export const ALL_MODELS: ModelDef[] = [...OPENCODE_MODELS, ...KILO_MODELS];
|
|
385
423
|
|
package/src/proxy.ts
CHANGED
|
@@ -85,13 +85,12 @@ export function sanitizeHeaders(
|
|
|
85
85
|
incoming: http.IncomingHttpHeaders,
|
|
86
86
|
targetHost: string,
|
|
87
87
|
): Record<string, string> {
|
|
88
|
-
//
|
|
89
|
-
//
|
|
90
|
-
//
|
|
88
|
+
// authorization is deliberately NOT forwarded: the host provider registers
|
|
89
|
+
// with a dummy key (placeholder), and zen free models are keyless — sending
|
|
90
|
+
// that fake key upstream gets 401 Invalid API key. Kilo injects its own key.
|
|
91
91
|
const allowed: Record<string, true> = {
|
|
92
92
|
"content-type": true,
|
|
93
93
|
accept: true,
|
|
94
|
-
authorization: true,
|
|
95
94
|
"x-request-id": true,
|
|
96
95
|
};
|
|
97
96
|
const sanitized: Record<string, string> = {};
|