pi-freeflow 1.3.3 → 1.3.7
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 +110 -93
- package/package.json +2 -2
- package/src/catalog.ts +8 -5
- package/src/commands.ts +250 -92
- package/src/index.ts +47 -14
- package/src/models.ts +72 -8
- package/src/proxy.ts +31 -10
- package/src/relay-state.ts +212 -29
- package/src/relay.ts +9 -1
- package/src/types.ts +2 -1
package/README.md
CHANGED
|
@@ -1,135 +1,134 @@
|
|
|
1
1
|
# pi-freeflow 🌊
|
|
2
2
|
|
|
3
|
-
> **23 free models. Up to 1M context
|
|
3
|
+
> **23 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
|
|
|
7
|
-
[](https://www.npmjs.com/package/pi-freeflow)
|
|
9
|
-
[](https://www.npmjs.com/package/pi-freeflow)
|
|
8
|
+
[](https://www.npmjs.com/package/pi-freeflow)
|
|
9
|
+
[](https://opensource.org/licenses/MIT)
|
|
10
|
+
[](https://github.com/badlogic/pi-ai)
|
|
11
|
+
[](https://github.com/coder/oh-my-pi)
|
|
11
12
|
|
|
12
|
-
|
|
13
|
+
**Join devs bypassing rate limits with their own relay pools — BYO, add as many as you need.**
|
|
13
14
|
|
|
14
|
-
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
### Why FreeFlow?
|
|
15
18
|
|
|
16
19
|
You love Pi. You love free models. You hate:
|
|
17
20
|
|
|
18
|
-
-
|
|
19
|
-
-
|
|
20
|
-
- `
|
|
21
|
-
- Paying for
|
|
21
|
+
- **429 Rate Limit** killing your 10-parallel subagent fleet
|
|
22
|
+
- Paid models leaking into your picker
|
|
23
|
+
- `reasoning_effort: max` rejected and thinking silently disabled
|
|
24
|
+
- Paying for 1M context you should get for free
|
|
22
25
|
|
|
23
26
|
**FreeFlow fixes all three — in 17 files, 102KB.**
|
|
24
27
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
## What you get (and what you don’t pay for)
|
|
28
|
+
### Features
|
|
28
29
|
|
|
29
|
-
| You
|
|
30
|
-
|
|
|
31
|
-
| **23
|
|
32
|
-
| **BYO
|
|
33
|
-
| **Dumb
|
|
34
|
-
| **Real
|
|
30
|
+
| What You Get | Value | Cost |
|
|
31
|
+
| :--- | :--- | :--- |
|
|
32
|
+
| **23 Curated Free Models** — 9 OpenCode Zen + 14 Kilo, 66K-1M context, vision-ready | Unlimited | **$0** |
|
|
33
|
+
| **BYO Relay Pool** — Cloudflare Workers + Vercel Edge, round-robin, seamless `429 → next` | Auto-scale | **$0** (your free tiers) |
|
|
34
|
+
| **Dumb Proxy That Never Breaks** — `127.0.0.1:18080`, host-normalized, pathname-guarded `/v1/models` | 100% uptime | **$0** |
|
|
35
|
+
| **Real Logs** — `~/.pi/agent/pi-freeflow.log`, 5MB rotate, debug toggle | Observable | **$0** |
|
|
35
36
|
|
|
36
|
-
|
|
37
|
+
Philosophy: **Thin by design.** We only ship model list + relay proxy + log. Host owns thinking & normalization.
|
|
37
38
|
|
|
38
39
|
---
|
|
39
40
|
|
|
40
|
-
|
|
41
|
+
### 23 Models — One Command
|
|
41
42
|
|
|
42
43
|
```bash
|
|
43
44
|
/model → freeflow → pick
|
|
44
45
|
```
|
|
45
46
|
|
|
46
|
-
|
|
47
|
+
#### OpenCode Zen (9) — Responses & Chat API
|
|
48
|
+
Best for long-context reasoning. All vision-ready models marked.
|
|
47
49
|
|
|
48
|
-
| Model
|
|
49
|
-
|
|
|
50
|
-
| `muse-spark-1.2-contributor-free` |
|
|
51
|
-
| `deepseek-v4-flash-free`
|
|
52
|
-
| `x-preview-f-free`
|
|
53
|
-
| `mimo-v2.5-free`
|
|
54
|
-
| `laguna-s-2.1-free`
|
|
55
|
-
| `nemotron-3.5-lightning-free`
|
|
56
|
-
| `nemotron-3-ultra-free`
|
|
57
|
-
| `hy3-free`
|
|
58
|
-
| `big-pickle`
|
|
50
|
+
| Model | Context | Max Output | Thinking | Vision |
|
|
51
|
+
| :--- | :--- | :--- | :--- | :--- |
|
|
52
|
+
| `claude-sonnet-4.5-free` / `muse-spark-1.2-contributor-free` | 1M | 131K | `minimal → max` | ✅ |
|
|
53
|
+
| `deepseek-v4-flash-free` | 1M | 384K | `minimal → max` | ❌ |
|
|
54
|
+
| `grok-code-fast-1-preview-f-free` / `x-preview-f-free` | 1M | 131K | `low / high / max` | ✅ |
|
|
55
|
+
| `mimo-v2.5-free` | 1M | 131K | `low / medium / high` | ✅ |
|
|
56
|
+
| `minimax-m2.1-free` / `laguna-s-2.1-free` | 1M | 131K | `minimal → max` | ❌ |
|
|
57
|
+
| `nemotron-3.5-lightning-free` | 1M | 262K | `minimal → max` | ❌ |
|
|
58
|
+
| `nemotron-3-ultra-free` | 1M | 128K | `minimal → max` | ❌ |
|
|
59
|
+
| `qwen3-coder-480b-free` / `hy3-free` | 262K | 128K | `minimal → max` | ❌ |
|
|
60
|
+
| `big-pickle` | 200K | 32K | `high / max` | ❌ |
|
|
59
61
|
|
|
60
|
-
|
|
62
|
+
#### Kilo Gateway (14) — OpenRouter Compatible
|
|
63
|
+
Zero-config, `Bearer kilo-free`.
|
|
61
64
|
|
|
62
|
-
`dots-3-note-preview:free`
|
|
65
|
+
`dots-3-note-preview:free` (512K), `step-3.7-flash:free` (262K), `nemotron-3-nano-omni:free` (256K), `nemotron-3-ultra-550b:free` (1M), `nemotron-3-super:free` (262K), `hy3:free` (262K), `north-mini-code:free` (256K), `minimax-m2.1/xs:free` (262K), `lfm-2.5:free` (66K), `kilo-auto/free`, `openrouter/free`, `content-safety:free` + 2 more.
|
|
63
66
|
|
|
64
|
-
All `off→null` (hidden)
|
|
67
|
+
> All `off → null` (hidden). Host decides token budgets, not us.
|
|
65
68
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
## The magic: BYO relays, 0 rate limits
|
|
69
|
+
### How It Works — The Magic: BYO Relays, Zero Rate Limits
|
|
69
70
|
|
|
70
|
-
```text
|
|
71
|
-
You → 127.0.0.1:18080 (dumb) → x-relay-target → N egress IPs (your pool) → opencode.ai / api.kilo.ai
|
|
72
|
-
↑ host already normalized thinking → proxy just forwards
|
|
73
71
|
```
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
- **Seamless 429** — `429/502/503/504` → instant roll to next, never `429` to agent
|
|
77
|
-
- **Exhausted? Direct fallback** — if all relays are 429 (global limit), transparent `direct fetch` — host shows `rate limit` only when truly global
|
|
78
|
-
- **No live catalog fetch** — `24h DISK_CACHE_ONLY`, never `fetch` from subagent → no `Unable to connect`
|
|
79
|
-
|
|
80
|
-
**Real log (1.3.1 thin):**
|
|
81
|
-
|
|
82
|
-
```text
|
|
83
|
-
candidates:N → relay-A 429 rolling → relay-B 200 in 1.2s → 98 chunks 663KB done
|
|
72
|
+
You → 127.0.0.1:18080 (dumb proxy, host-normalized) → x-relay-target → N egress IPs (your pool) → opencode.ai / api.kilo.ai
|
|
73
|
+
↑ host already normalized thinking → proxy just forwards
|
|
84
74
|
```
|
|
85
75
|
|
|
76
|
+
- **Round-robin per request** — 10 parallel subagents hit N different egress IPs (your pool size). No thundering herd.
|
|
77
|
+
- **Seamless 429 roll** — `429 / 502 / 503 / 504` → instant roll to next relay, never 429 to agent.
|
|
78
|
+
- **Exhausted? Direct fallback** — If all relays are 429 (global limit), transparent direct fetch. Host shows rate limit only when truly global.
|
|
79
|
+
- **No live catalog fetch** — 24h `DISK_CACHE_ONLY`, never fetch from subagent → no `Unable to connect`.
|
|
80
|
+
- **Real log (v1.3.1 thin):** `candidates:N → relay-A 429 rolling → relay-B 200 in 1.2s → 98 chunks 663KB done`
|
|
81
|
+
|
|
86
82
|
You bring the relays (free tiers). We bring the rolling.
|
|
87
83
|
|
|
88
84
|
---
|
|
89
85
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
### 1. Install (pick your host)
|
|
86
|
+
### Quick Start — 30 Seconds
|
|
93
87
|
|
|
94
|
-
|
|
88
|
+
#### 1. Install
|
|
95
89
|
|
|
90
|
+
**Oh My Pi (Recommended):**
|
|
96
91
|
```bash
|
|
97
92
|
omp plugin install pi-freeflow
|
|
98
93
|
# or local dev
|
|
99
94
|
omp plugin link /path/to/pi-freeflow
|
|
100
|
-
|
|
95
|
+
```
|
|
101
96
|
|
|
102
97
|
**Pi:**
|
|
103
|
-
|
|
104
98
|
```bash
|
|
105
99
|
pi install npm:pi-freeflow
|
|
106
100
|
```
|
|
107
101
|
|
|
108
|
-
|
|
102
|
+
#### 2. Pick a Model
|
|
109
103
|
|
|
110
104
|
```bash
|
|
111
105
|
omp
|
|
112
|
-
/model → freeflow →
|
|
106
|
+
/model → freeflow → claude-sonnet-4.5 (1M) → max
|
|
107
|
+
|
|
113
108
|
# or CLI
|
|
114
|
-
omp -p --model freeflow/
|
|
109
|
+
omp -p --model freeflow/claude-sonnet-4.5-contributor-free "build me a SaaS"
|
|
115
110
|
```
|
|
116
111
|
|
|
117
|
-
|
|
112
|
+
#### 3. (Optional but 🔥) Add Your Free Relays
|
|
118
113
|
|
|
119
|
-
|
|
114
|
+
Scale infinitely. Default ships direct, add relays via `/freeflow use <url>`.
|
|
120
115
|
|
|
121
|
-
|
|
122
|
-
|
|
116
|
+
**Option A: One Cloudflare Worker (100k req/day, no 25s timeout)**
|
|
117
|
+
1. Go to `dash.cloudflare.com` → Workers → Create → Deploy → Edit code
|
|
118
|
+
2. Paste the Worker relay snippet from `/reference/worker-relay.js`
|
|
119
|
+
3. Deploy and add it:
|
|
123
120
|
|
|
124
|
-
|
|
121
|
+
```bash
|
|
122
|
+
omp → /freeflow use https://your.workers.dev
|
|
123
|
+
```
|
|
125
124
|
|
|
125
|
+
**Option B: Six Vercel Edges (1M req/mo) — Auto Deploy**
|
|
126
126
|
```bash
|
|
127
127
|
/freeflow deploy # prompts token in-memory, auto-adds to pool
|
|
128
128
|
# or manual: vercel.json → api/relay.js
|
|
129
129
|
```
|
|
130
130
|
|
|
131
|
-
**
|
|
132
|
-
|
|
131
|
+
**Verify your pool:**
|
|
133
132
|
```bash
|
|
134
133
|
/freeflow status # relay-A 1/N (ON) → candidates:N
|
|
135
134
|
/freeflow logs # tail -25
|
|
@@ -138,45 +137,63 @@ cat ~/.pi/agent/pi-freeflow.log | tail -n 20
|
|
|
138
137
|
|
|
139
138
|
Done. Subagents now follow parent proxy — `Unable to connect` is history.
|
|
140
139
|
|
|
141
|
-
|
|
140
|
+
### Logs & Debugging
|
|
142
141
|
|
|
143
|
-
|
|
142
|
+
```bash
|
|
143
|
+
/freeflow logs
|
|
144
|
+
cat ~/.pi/agent/pi-freeflow.log | tail -n 50
|
|
144
145
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
| Live `fetch` 10s in subagent → timeout | **Disk-only 24h**, proxy-only |
|
|
149
|
-
| `400` loops N× relays | **Narrow 429/5xx only**, `400` surfaces instantly |
|
|
150
|
-
| `GET /v1/models?foo` leaks paid | **Pathname-guarded** |
|
|
146
|
+
# debug toggle
|
|
147
|
+
/freeflow debug on
|
|
148
|
+
```
|
|
151
149
|
|
|
152
|
-
|
|
150
|
+
Log rotation at 5MB. Clean, parseable, real-time.
|
|
153
151
|
|
|
154
|
-
|
|
152
|
+
### Philosophy: Thin vs Fat
|
|
155
153
|
|
|
156
|
-
|
|
154
|
+
| Fat Plugin (Before) | Thin FreeFlow (Now) |
|
|
155
|
+
| :--- | :--- |
|
|
156
|
+
| `src/normalizer.ts` 200 LOC duplicates host | Deleted — host `pi-ai` owns 11 `thinkingFormat` |
|
|
157
|
+
| Live fetch 10s in subagent → timeout | Disk-only 24h, proxy-only |
|
|
158
|
+
| 400 loops N× relays | Narrow 429/5xx only, 400 surfaces instantly |
|
|
159
|
+
| `GET /v1/models?foo` leaks paid | Pathname-guarded |
|
|
157
160
|
|
|
158
|
-
**
|
|
161
|
+
**Result: <500 LOC core, 29 tests PASS, typecheck PASS.**
|
|
159
162
|
|
|
160
|
-
|
|
163
|
+
### FAQ
|
|
161
164
|
|
|
162
|
-
**
|
|
165
|
+
**Do I need API keys?**
|
|
166
|
+
No. Kilo uses `Bearer kilo-free`, OpenCode uses `opencodeHeaders()`.
|
|
163
167
|
|
|
164
|
-
**
|
|
168
|
+
**What if all relays are 429?**
|
|
169
|
+
Proxy tries direct. If that's also 429, Pi shows rate limit — that means global upstream limit, even without relay you'd be 429.
|
|
165
170
|
|
|
166
|
-
|
|
171
|
+
**Can I use without relays?**
|
|
172
|
+
Yes. `/freeflow off` → direct. Add relays later to scale.
|
|
173
|
+
|
|
174
|
+
**Where's the normalizer?**
|
|
175
|
+
Deleted in 1.3.0. If zai/qwen/deepseek thinking broke before, it's fixed now because host handles it.
|
|
167
176
|
|
|
168
|
-
|
|
177
|
+
**Why is context free?**
|
|
178
|
+
We use OpenCode Zen & Kilo free tiers. You pay only with your own Cloudflare/Vercel free tiers for egress.
|
|
169
179
|
|
|
170
|
-
|
|
180
|
+
### Contributing
|
|
171
181
|
|
|
172
|
-
|
|
182
|
+
> "I shipped 10 parallel subagents on 1M context, zero keys, zero 429s. FreeFlow did the rolling, Pi did the thinking."
|
|
173
183
|
|
|
174
184
|
```bash
|
|
175
|
-
|
|
185
|
+
git clone https://github.com/trefeon/pi-freeflow
|
|
186
|
+
pnpm install
|
|
187
|
+
pnpm test
|
|
176
188
|
```
|
|
177
189
|
|
|
178
|
-
|
|
190
|
+
PRs welcome. `reference/` holds pi, oh-my-pi, opencode, kilocode shallow clones for audit (gitignored).
|
|
179
191
|
|
|
180
|
-
|
|
192
|
+
### License
|
|
181
193
|
|
|
182
|
-
MIT © trefeon
|
|
194
|
+
MIT © trefeon
|
|
195
|
+
|
|
196
|
+
Start now:
|
|
197
|
+
```bash
|
|
198
|
+
omp plugin install pi-freeflow && omp --model freeflow/claude-sonnet-4.5-contributor-free --thinking max "make it sell"
|
|
199
|
+
```
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-freeflow",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.3.
|
|
4
|
+
"version": "1.3.7",
|
|
5
5
|
"description": "Thin provider for OMP/Pi — model list + dumb relay proxy + log; host pi-ai owns thinking/normalization",
|
|
6
6
|
"main": "extensions/index.ts",
|
|
7
7
|
"types": "src/index.ts",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"license": "MIT",
|
|
21
21
|
"repository": {
|
|
22
22
|
"type": "git",
|
|
23
|
-
"url": "https://github.com/trefeon/pi-freeflow.git"
|
|
23
|
+
"url": "git+https://github.com/trefeon/pi-freeflow.git"
|
|
24
24
|
},
|
|
25
25
|
"homepage": "https://github.com/trefeon/pi-freeflow#readme",
|
|
26
26
|
"omp": {
|
package/src/catalog.ts
CHANGED
|
@@ -16,10 +16,13 @@ import {
|
|
|
16
16
|
} from "./config.ts";
|
|
17
17
|
import { log, logDebug, logWarn } from "./logger.ts";
|
|
18
18
|
import {
|
|
19
|
+
ALL_MODELS,
|
|
19
20
|
KILO_MODELS,
|
|
21
|
+
KILO_MODEL_IDS,
|
|
20
22
|
KNOWN_MODELS,
|
|
21
23
|
MODEL_MAP,
|
|
22
24
|
OPENCODE_MODELS,
|
|
25
|
+
getAllRegisteredModels,
|
|
23
26
|
} from "./models.ts";
|
|
24
27
|
import type {
|
|
25
28
|
CatalogCacheData,
|
|
@@ -32,10 +35,10 @@ import type {
|
|
|
32
35
|
* In-memory cache of currently active/available free models.
|
|
33
36
|
* Initialized with all 23 verified models for 0ms instant availability.
|
|
34
37
|
*/
|
|
35
|
-
let aliveCatalog: RegisteredModel[] =
|
|
36
|
-
...
|
|
37
|
-
|
|
38
|
-
|
|
38
|
+
let aliveCatalog: RegisteredModel[] = ALL_MODELS.map((m) => ({
|
|
39
|
+
...m,
|
|
40
|
+
source: KILO_MODEL_IDS.has(m.id) ? ("kilo" as const) : ("opencode" as const),
|
|
41
|
+
}));
|
|
39
42
|
/**
|
|
40
43
|
* Get current in-memory alive catalog
|
|
41
44
|
*/
|
|
@@ -194,7 +197,7 @@ export async function refreshCatalog(force = false): Promise<RegisteredModel[]>
|
|
|
194
197
|
return aliveCatalog;
|
|
195
198
|
}
|
|
196
199
|
// Stale cache still better than empty — return it without network
|
|
197
|
-
if (disk.models.length
|
|
200
|
+
if (disk.models.length >= 23) {
|
|
198
201
|
aliveCatalog = disk.models;
|
|
199
202
|
return aliveCatalog;
|
|
200
203
|
}
|