pi-freeflow 1.15.2 → 1.17.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 CHANGED
@@ -1,359 +1,360 @@
1
- # pi-freeflow
2
-
3
- > 26 free models with up to 1M context. No API keys to manage. Add your own relays to spread requests across more IPs.
4
-
5
- Thin by design: a model list, a relay proxy, and a log. The host (`pi-ai`) handles thinking, normalization, and provider behavior.
6
-
7
- [![npm version](https://img.shields.io/npm/v/pi-freeflow?style=flat-square&color=00E5FF)](https://www.npmjs.com/package/pi-freeflow)
8
- [![npm downloads](https://img.shields.io/npm/dm/pi-freeflow?style=flat-square)](https://www.npmjs.com/package/pi-freeflow)
9
- [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg?style=flat-square)](https://opensource.org/licenses/MIT)
10
- [![Pi](https://img.shields.io/badge/Powered%20by-Pi-7c3aed?style=flat-square)](https://github.com/badlogic/pi-ai)
11
- [![Oh My Pi](https://img.shields.io/badge/Compatible-OMP-black?style=flat-square)](https://github.com/coder/oh-my-pi)
12
-
13
- ---
14
-
15
- ### What you get
16
-
17
- | Feature | What it does | Cost |
18
- | :--- | :--- | :--- |
19
- | **26 free models** | 7 from OpenCode Zen, 19 from KiloCode Gateway, context windows up to 1M. Full list below. | **$0** |
20
- | **Relay pool** | Route requests through your own Cloudflare Workers and Vercel Edge relays. Requests rotate across the pool. A relay that rate-limits, times out, or drops the connection cools down while healthy ones take its traffic. | **$0** beyond your platforms' free tiers |
21
- | **Automatic fallback** | When every relay is cooling down, requests go direct to upstream instead of failing. | **$0** |
22
- | **Short model names** | Every model has a slash-free, colon-free alias, plus an optional `:effort` suffix for thinking depth. You type `freeflow/<name>`. | **$0** |
23
- | **Shared local proxy** | One daemon on `127.0.0.1:28180` serves every session on the machine, so parallel subagents reuse it instead of opening their own connections. | **$0** |
24
- | **Logs you can read** | `~/.pi/agent/pi-freeflow.log`, rotated at 10MB. Tail it with `/freeflow logs`. | **$0** |
25
-
26
- ---
27
-
28
- ### Install
29
-
30
- **On Oh My Pi (OMP):**
31
- ```bash
32
- omp plugin install pi-freeflow
33
- # or local dev (repo checkout)
34
- omp plugin link /path/to/pi-freeflow
35
- ```
36
-
37
- **On Pi:**
38
- ```bash
39
- pi install npm:pi-freeflow
40
- ```
41
-
42
- > Both commands fetch the same npm package from the registry. pi-freeflow
43
- > is an extension loaded by the host, not a standalone CLI. It works on OMP
44
- > and Pi only (they share the extension API).
45
-
46
- ### Pick a model
47
-
48
- **OMP, interactive:**
49
- ```bash
50
- omp
51
- /model → freeflow → muse-spark-1.2-contributor-free (1M) → max
52
- ```
53
-
54
- **OMP, one shot:**
55
- ```bash
56
- omp -p --model freeflow/muse-spark-1.2-contributor-free "build me a SaaS"
57
- omp -p --model freeflow/step-3.7-flash:high "solve this bug" # alias + thinking level
58
- ```
59
-
60
- **Pi, interactive:**
61
- ```bash
62
- pi
63
- /model → freeflow → pick
64
- ```
65
-
66
- **Pi, one shot:**
67
- ```bash
68
- pi -p --model freeflow/step-3.7-flash:high "solve this bug"
69
- ```
70
-
71
- Model IDs accept a full canonical ID, a short alias (see the tables below),
72
- and an optional `:effort` suffix (`:minimal` through `:xhigh`, `:max` where
73
- supported). The host resolves the rest.
74
-
75
- ### Add relays
76
-
77
- The default setup talks to upstream directly. Add relays when shared IPs start
78
- hitting rate limits. The fastest path is guided deploy: run
79
- `/freeflow deploy cloudflare` (or `deno`, `vercel`), paste your platform token
80
- once when asked, and the relay is created and added to your pool. The token
81
- stays in memory and is never written to disk.
82
-
83
- Manual fallback per platform:
84
-
85
- **Option A: Cloudflare Workers, auto deploy**
86
- ```bash
87
- /freeflow deploy cloudflare # prompts token in-memory, auto-adds to pool
88
- ```
89
- Manual fallback: `dash.cloudflare.com` → Workers → Create → Deploy → Edit code → paste the canonical worker source (see below) → Deploy → `/freeflow add https://your.workers.dev cf-worker-1`
90
-
91
- **Option B: Vercel Edge Relay, auto deploy**
92
- ```bash
93
- /freeflow deploy vercel # prompts token in-memory, auto-adds to pool
94
- # or shorthand: /freeflow deploy
95
- ```
96
- Manual fallback: push 2 files (`api/relay.js` + `vercel.json`) to GitHub, then Import on `vercel.com`, then `/freeflow add https://your.vercel.app vercel-relay-1`
97
-
98
- For `api/relay.js`, use the canonical worker source (see below); `vercel.json` stays:
99
-
100
- ```json
101
- { "rewrites": [{ "source": "/(.*)", "destination": "/api/relay" }] }
102
- ```
103
-
104
- **Option C: Deno Deploy, auto deploy**
105
- ```bash
106
- /freeflow deploy deno # prompts token in-memory, auto-adds to pool
107
- ```
108
- Manual fallback: `dash.deno.com` → New Project → Playground → paste the canonical worker source (see below) → Deploy → `/freeflow add https://your-project.deno.dev deno-relay-1`
109
-
110
- **Canonical worker source (all platforms)**
111
-
112
- The relay worker template is generated per deployment by `/freeflow deploy`, with one shared core adapted for Vercel, Cloudflare, and Deno. Deployed relays accept requests from any pi-freeflow user by default, while only forwarding to an allowlist (`https://opencode.ai`, `https://api.kilo.ai`) with private-host and path checks.
113
-
114
- ```js
115
- // Minimal Cloudflare illustration. Prefer /freeflow deploy: the generated
116
- // worker is the hardened source for all three platforms.
117
- // This example omits the private-host guard, path validation, and auth.
118
- const ALLOWED_TARGETS = ["https://opencode.ai", "https://api.kilo.ai"];
119
- export default {
120
- async fetch(req) {
121
- const target = req.headers.get("x-relay-target");
122
- const relayPath = req.headers.get("x-relay-path") || "/";
123
- if (!target || !ALLOWED_TARGETS.includes(target.replace(/\/$/, ""))) {
124
- return new Response(JSON.stringify({ error: "Forbidden target" }), { status: 403 });
125
- }
126
- const headers = new Headers(req.headers);
127
- headers.delete("x-relay-target"); headers.delete("x-relay-path"); headers.delete("host");
128
- return fetch(target.replace(/\/$/, "") + relayPath, { method: req.method, headers, body: req.method !== "GET" && req.method !== "HEAD" ? req.body : undefined });
129
- },
130
- };
131
- ```
132
-
133
- **Verify your pool:**
134
- ```bash
135
- /freeflow status # active relay, pool status, candidates
136
- /freeflow list # every relay with health status
137
- /freeflow logs # tail -25
138
- ```
139
-
140
- ### Carry your pool to another machine
141
-
142
- ```bash
143
- /freeflow export # save pool to ./freeflow-relays.json
144
- /freeflow export backup/team.json # save to a path you choose
145
- /freeflow import backup/team.json # add its relays to this machine (merge)
146
- /freeflow import backup/team.json --replace --dry-run # preview a full swap first
147
- ```
148
-
149
- Merge is the default and never deletes anything. Replace swaps the whole pool
150
- and always asks first. Passwords stay out of the file unless you pass
151
- `--include-secrets`; a file without passwords still imports, and you re-enter
152
- each password once afterwards.
153
-
154
- ---
155
-
156
- ### Commands reference (`/freeflow`)
157
-
158
- The same command set works identically in OMP and Pi:
159
-
160
- ```bash
161
- /freeflow status # View active relay, pool status, and candidates
162
- /freeflow list # List all relays with real-time health badges
163
- /freeflow use <url|index|label> # Switch active relay
164
- /freeflow url <url> # Set the active relay URL directly
165
- /freeflow add <url> [label] # Add new relay to the pool
166
- /freeflow label <index|url> <name># Assign a friendly label to a relay
167
- /freeflow remove <index|url|label># Remove a relay from the pool
168
- /freeflow test <index|url|label> # Probe a relay for reachability and latency
169
- /freeflow on | off | auto # Toggle relay mode (auto = enabled for freeflow)
170
- /freeflow deploy <platform> # Guided relay deploy: vercel|cloudflare|deno, token in-memory, auto-adds
171
- /freeflow logs [lines] # Inspect recent proxy logs
172
- /freeflow trace [req-id] # Tail logs filtered by request correlation ID
173
- /freeflow refresh # Reload the model catalog from live upstreams
174
- /freeflow update # Check for and install a package update
175
- /freeflow debug on | off # Toggle full HTTP lifecycle debug logging
176
- /freeflow kill # Stop the shared proxy daemon now (restarts on next use)
177
- /freeflow export [path] [--include-secrets] # Save the relay pool to a file (default freeflow-relays.json; passwords left out unless asked)
178
- /freeflow import <path> [--merge|--replace] [--dry-run] # Load a relay pool from a file (merge is default; replace asks first; dry-run previews only)
179
- ```
180
-
181
- ---
182
-
183
- ### 26 models, one command
184
-
185
- ```bash
186
- /model → freeflow → pick
187
- ```
188
-
189
- #### OpenCode Zen (7 models), Responses and Chat API
190
-
191
- Good defaults for long coding sessions and agentic work.
192
-
193
- | Model ID | Creator / Lab | Context | Max Output | Thinking | Vision |
194
- | :--- | :--- | :--- | :--- | :--- | :--- |
195
- | `muse-spark-1.2-contributor-free` | Meta Superintelligence Labs | **1M** (1.048.576) | **131K** (131.072) | `minimal … xhigh` | ✅ |
196
- | `muse-spark-1.3-contributor-free` | Meta Superintelligence Labs | **1M** (1.048.576) | **131K** (131.072) | `minimal … xhigh` | ✅ |
197
- | `mimo-v2.5-free` | Xiaomi MiMo | **1M** (1.048.576) | **131K** (131.072) | `minimal … xhigh`\* | ✅ |
198
- | `nemotron-3.5-lightning-free` | NVIDIA | **1M** (1.000.000) | **262K** (262.144) | `minimal … xhigh` | ❌ |
199
- | `nemotron-3-ultra-free` | NVIDIA | **1M** (1.000.000) | **128K** (128.000) | `minimal … xhigh` | ❌ |
200
- | `big-pickle` | Big Pickle | **200K** (200.000) | **32K** (32.000) | `high / max` | ❌ |
201
- | `ling-3.0-flash-fin-free` | Inclusion AI | **262K** (262.144) | **131K** (131.072) | `minimal … xhigh` | ❌ |
202
-
203
- #### KiloCode Gateway (19 models), OpenRouter compatible
204
-
205
- Keyless access. Short aliases work for every row (the full ID is in parentheses).
206
-
207
- | Model ID | Creator / Lab | Context | Max Output | Thinking | Vision |
208
- | :--- | :--- | :--- | :--- | :--- | :--- |
209
- | `dots-3-note-preview` (`dots-studio/...:free`) | Dots Studio | **512K** (512.000) | **512K** (512.000) | `minimal…xhigh`\* | ✅ |
210
- | `step-3.7-flash` (`stepfun/...:free`) | StepFun | **262K** (262.144) | **262K** (262.144) | `minimal…xhigh`\* | ✅ |
211
- | `nemotron-3-nano-omni` (`nvidia/...:free`) | NVIDIA | **256K** (256.000) | **131K** (131.072) | `minimal…xhigh`\* | ✅ |
212
- | `nemotron-3-ultra-550b` (`nvidia/...:free`) | NVIDIA | **1M** (1.000.000) | **128K** (128.000) | `minimal…xhigh`\* | ❌ |
213
- | `nvidia/nemotron-3.5-lightning:free` | NVIDIA | **1M** (1.000.000) | **262K** (262.144) | `minimal…xhigh`\* | ❌ |
214
- | `nemotron-3-super` (`nvidia/...:free`) | NVIDIA | **262K** (262.144) | **262K** (262.144) | `minimal…xhigh`\* | ❌ |
215
- | `north-mini-code` (`cohere/...:free`) | Cohere | **256K** (256.000) | **64K** (64.000) | `minimal…xhigh`\* | ❌ |
216
- | `laguna-s-2.1:free` (`poolside/...:free`) | Poolside | **262K** (262.144) | **32K** (32.768) | `minimal…xhigh`\* | ❌ |
217
- | `laguna-xs-2.1:free` (`poolside/...:free`) | Poolside | **262K** (262.144) | **32K** (32.768) | `minimal…xhigh`\* | ❌ |
218
- | `lfm-2.5` (`liquid/lfm-2.5-2.6b:free`) | Liquid AI | **65K** (65.536) | **32K** (32.768) | `minimal…xhigh`\* | ❌ |
219
- | `kilo-auto` (`kilo-auto/free`) | Kilo Gateway Auto | **256K** (256.000) | **10K** (10.000) | `minimal…xhigh`\* | ❌ |
220
- | `openrouter` (`openrouter/free`) | OpenRouter Free | **200K** (200.000) | **65K** (65.536) | `minimal…xhigh`\* | ✅ |
221
- | `content-safety` (`nvidia/...:free`) | NVIDIA | **128K** (128.000) | **8K** (8.192) | ❌ *(non-thinking)* | ✅ |
222
- | `ling-3.0-flash-fin` (`inclusionai/ling-3.0-flash-fin:free`) | Inclusion AI | **262K** (262.144) | **32K** (32.768) | `minimal…xhigh`\* | ❌ |
223
- | `ling-3.0-flash-sante` (`inclusionai/ling-3.0-flash-sante:free`) | Inclusion AI | **262K** (262.144) | **32K** (32.768) | `minimal…xhigh`\* | ❌ |
224
- | `nex-n2.5-pro` (`nex-agi/nex-n2.5-pro:free`) | Nex AGI | **262K** (262.144) | **235K** (235.929) | `minimal…xhigh`\* | ✅ |
225
- | `nex-n2.5-mini` (`nex-agi/nex-n2.5-mini:free`) | Nex AGI | **262K** (262.144) | **235K** (235.929) | `minimal…xhigh`\* | ✅ |
226
- | `ling-3.0-flash-vl` (`inclusionai/ling-3.0-flash-vl:free`) | Inclusion AI | **262K** (262.144) | **32K** (32.768) | `minimal…xhigh`\* | ✅ |
227
- | `inkling-small` (`thinkingmachines/inkling-small:free`) | Thinking Machines | **1M** (1.048.576) | **262K** (262.144) | `minimal…xhigh`\* | ✅ |
228
-
229
- \* Levels are forwarded as-is through the OpenRouter-style nested `reasoning` parameter; effort mapping is decided by each model. MiMo collapses `minimal→low` and `xhigh→high` upstream, so its selector shows 5 labels but only 3 distinct effort values.
230
-
231
- ---
232
-
233
- ### Logs and debugging
234
-
235
- ```bash
236
- /freeflow logs
237
- cat ~/.pi/agent/pi-freeflow.log | tail -n 50
238
-
239
- # full debug logging is on by default; `off` restores info level
240
- /freeflow debug on
241
- ```
242
-
243
- ---
244
-
245
- ### Design
246
-
247
- This package stays thin. It ships three things: a model catalog, a relay proxy, and a log. There is no build step and zero runtime dependencies. Thinking and prompt normalization stay with the host (`pi-ai`).
248
-
249
- About 19k lines including tests. The full suite (sandboxed, network-mocked) and typecheck pass before every release. See CHANGELOG.md.
250
-
251
- ---
252
-
253
- ### FAQ
254
-
255
- **Do I need API keys?**
256
- No. Kilo uses a shared free credential and OpenCode free models need no header. You never paste a key.
257
-
258
- **What if all relays hit rate limits?**
259
- The proxy tries direct upstream. If that is also rate-limited, the host shows the limit. That number is the shared upstream cap; without relays you would hit the same wall sooner.
260
-
261
- **Can I use it without relays?**
262
- Yes. `/freeflow off` talks direct. Add relays later when you need them.
263
-
264
- **What happens when I update to a new version?**
265
- The local proxy daemon is shared across sessions on port 28180. On upgrade, the new extension
266
- detects a stale daemon (an older version still running) and replaces it automatically, with no manual
267
- kill and no restart of other sessions. Replacement only happens when the running daemon is
268
- idle: sessions with in-flight requests are never interrupted (busy or newer daemons are reused
269
- with a log note instead). If a daemon cannot be replaced (for example the port is held by an unrelated process),
270
- it falls back to reusing it with a warning. To disable replacement entirely, set the no-kill env
271
- to `1` before starting a session.
272
-
273
- **What happens when I close a session?**
274
- Nothing visible to your other sessions. The proxy daemon is a separate background
275
- process shared by every OMP/Pi session on the machine. Closing one session just
276
- unregisters it; the daemon keeps serving the rest and retires itself automatically
277
- once the last client disconnects and no client re-attaches within a short grace window.
278
- To stop it manually, run `/freeflow kill`. The next freeflow use starts it again.
279
-
280
- **Why did my long session stop with a "reasoning was not issued to this caller" error?**
281
- The upstream backend signs each thinking block so only the backend that produced it can read it back. When a later turn reaches a different backend, the old blocks get rejected and the session stalls. pi-freeflow keeps each conversation on the relay that produced its thinking while that relay is healthy. When the relay has to change anyway (rate limit, relay removed, direct-mode switch), that turn is sent without the old thinking blocks so the new backend accepts it, and only the rejected blocks are dropped afterwards. Messages, tool calls, and tool results are always kept.
282
-
283
- **Why is it installed via npm?**
284
- The npm package is the distribution channel only. Both hosts resolve it internally:
285
- `omp plugin install pi-freeflow` and `pi install npm:pi-freeflow` install the same
286
- package from the npm registry. pi-freeflow is an extension, not a standalone CLI.
287
- The host (OMP or Pi) loads and runs it. A plain `npm install` just downloads the
288
- files; it is not a supported way to run the extension.
289
-
290
- **Which hosts can use it?**
291
- Oh My Pi (OMP) and Pi only. They share the same extension API, so one
292
- package serves both. Other AI agents (OpenCode, KiloCode, Cursor, and similar) have their
293
- own plugin systems and do not load this extension.
294
-
295
- ---
296
-
297
- ### Contributing
298
-
299
- Contributions welcome: bug fixes, new relay platforms, model additions, docs improvements.
300
-
301
- #### Prerequisites
302
-
303
- - **Node.js ≥ 22.19.0** (uses `--experimental-strip-types`, no build step)
304
- - **pnpm** (package manager)
305
-
306
- #### Setup and verify
307
-
308
- ```bash
309
- git clone https://github.com/trefeon/pi-freeflow
310
- cd pi-freeflow
311
- pnpm install
312
-
313
- # run all three before opening a PR
314
- pnpm test # full suite; sandboxed and network-mocked
315
- pnpm typecheck # tsc --noEmit, must pass clean
316
- pnpm smoke # verifies extensions/index.ts loads without crashing
317
- ```
318
-
319
- #### Project structure
320
-
321
- ```
322
- src/
323
- ├── index.ts # extension entry, lifecycle hooks
324
- ├── models.ts # 26-model catalog definitions
325
- ├── catalog.ts # model catalog cache (24h disk)
326
- ├── proxy.ts # local proxy server (127.0.0.1:28180)
327
- ├── relay.ts # relay selection and round-robin
328
- ├── relay-state.ts # relay pool state, health tracking
329
- ├── stream-pipe.ts # SSE stream piping and truncation resilience
330
- ├── commands.ts # /freeflow CLI subcommands
331
- ├── deploy.ts # guided relay deploy (vercel/cloudflare/deno)
332
- ├── config.ts # constants, whitelists, paths, and runtime settings
333
- ├── logger.ts # file logger with 10MB rotation
334
- └── types.ts # shared type definitions
335
- extensions/
336
- └── index.ts # OMP/Pi extension manifest
337
- test/
338
- └── *.test.ts # mirrors src/, node:test runner
339
- ```
340
-
341
- #### Guidelines
342
-
343
- - **Stay thin.** Zero runtime dependencies, no build step. If it belongs in the host (`pi-ai`), don't add it here.
344
- - **Test what you touch.** Every `src/*.ts` has a matching `test/*.test.ts`. Add or update tests for your change.
345
- - **Keep model IDs clean.** Slash-free, colon-free aliases for CLI compatibility. See existing patterns in `models.ts`.
346
- - **One concern per PR.** Bug fix? One PR. New relay platform? Separate PR. Easier to review, faster to merge.
347
-
348
- #### Reporting issues
349
-
350
- Found a bug or want a feature? [Open an issue](https://github.com/trefeon/pi-freeflow/issues) with:
351
- - What happened vs what you expected
352
- - Your relay setup (`/freeflow status` output helps)
353
- - Relevant logs (`/freeflow logs` or `~/.pi/agent/pi-freeflow.log`)
354
-
355
- ---
356
-
357
- ### License
358
-
359
- MIT © trefeon
1
+ # pi-freeflow
2
+
3
+ > 27 free models with up to 1M context. No API keys to manage. Add your own relays to spread requests across more IPs.
4
+
5
+ Thin by design: a model list, a relay proxy, and a log. The host (`pi-ai`) handles thinking, normalization, and provider behavior.
6
+
7
+ [![npm version](https://img.shields.io/npm/v/pi-freeflow?style=flat-square&color=00E5FF)](https://www.npmjs.com/package/pi-freeflow)
8
+ [![npm downloads](https://img.shields.io/npm/dm/pi-freeflow?style=flat-square)](https://www.npmjs.com/package/pi-freeflow)
9
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg?style=flat-square)](https://opensource.org/licenses/MIT)
10
+ [![Pi](https://img.shields.io/badge/Powered%20by-Pi-7c3aed?style=flat-square)](https://github.com/badlogic/pi-ai)
11
+ [![Oh My Pi](https://img.shields.io/badge/Compatible-OMP-black?style=flat-square)](https://github.com/coder/oh-my-pi)
12
+
13
+ ---
14
+
15
+ ### What you get
16
+
17
+ | Feature | What it does | Cost |
18
+ | :--- | :--- | :--- |
19
+ | **27 free models** | 8 from OpenCode Zen, 19 from KiloCode Gateway, context windows up to 1M. Full list below. | **$0** |
20
+ | **Relay pool** | Route requests through your own Cloudflare Workers and Vercel Edge relays. Requests rotate across the pool. A relay that rate-limits, times out, or drops the connection cools down while healthy ones take its traffic. | **$0** beyond your platforms' free tiers |
21
+ | **Automatic fallback** | When every relay is cooling down, requests go direct to upstream instead of failing. | **$0** |
22
+ | **Short model names** | Every model has a slash-free, colon-free alias, plus an optional `:effort` suffix for thinking depth. You type `freeflow/<name>`. | **$0** |
23
+ | **Shared local proxy** | One daemon on `127.0.0.1:28180` serves every session on the machine, so parallel subagents reuse it instead of opening their own connections. | **$0** |
24
+ | **Logs you can read** | `~/.pi/agent/pi-freeflow.log`, rotated at 10MB. Tail it with `/freeflow logs`. | **$0** |
25
+
26
+ ---
27
+
28
+ ### Install
29
+
30
+ **On Oh My Pi (OMP):**
31
+ ```bash
32
+ omp plugin install pi-freeflow
33
+ # or local dev (repo checkout)
34
+ omp plugin link /path/to/pi-freeflow
35
+ ```
36
+
37
+ **On Pi:**
38
+ ```bash
39
+ pi install npm:pi-freeflow
40
+ ```
41
+
42
+ > Both commands fetch the same npm package from the registry. pi-freeflow
43
+ > is an extension loaded by the host, not a standalone CLI. It works on OMP
44
+ > and Pi only (they share the extension API).
45
+
46
+ ### Pick a model
47
+
48
+ **OMP, interactive:**
49
+ ```bash
50
+ omp
51
+ /model → freeflow → muse-spark-1.2-contributor-free (1M) → max
52
+ ```
53
+
54
+ **OMP, one shot:**
55
+ ```bash
56
+ omp -p --model freeflow/muse-spark-1.2-contributor-free "build me a SaaS"
57
+ omp -p --model freeflow/step-3.7-flash:high "solve this bug" # alias + thinking level
58
+ ```
59
+
60
+ **Pi, interactive:**
61
+ ```bash
62
+ pi
63
+ /model → freeflow → pick
64
+ ```
65
+
66
+ **Pi, one shot:**
67
+ ```bash
68
+ pi -p --model freeflow/step-3.7-flash:high "solve this bug"
69
+ ```
70
+
71
+ Model IDs accept a full canonical ID, a short alias (see the tables below),
72
+ and an optional `:effort` suffix (`:minimal` through `:xhigh`, `:max` where
73
+ supported). The host resolves the rest.
74
+
75
+ ### Add relays
76
+
77
+ The default setup talks to upstream directly. Add relays when shared IPs start
78
+ hitting rate limits. The fastest path is guided deploy: run
79
+ `/freeflow deploy cloudflare` (or `deno`, `vercel`), paste your platform token
80
+ once when asked, and the relay is created and added to your pool. The token
81
+ stays in memory and is never written to disk.
82
+
83
+ Manual fallback per platform:
84
+
85
+ **Option A: Cloudflare Workers, auto deploy**
86
+ ```bash
87
+ /freeflow deploy cloudflare # prompts token in-memory, auto-adds to pool
88
+ ```
89
+ Manual fallback: `dash.cloudflare.com` → Workers → Create → Deploy → Edit code → paste the canonical worker source (see below) → Deploy → `/freeflow add https://your.workers.dev cf-worker-1`
90
+
91
+ **Option B: Vercel Edge Relay, auto deploy**
92
+ ```bash
93
+ /freeflow deploy vercel # prompts token in-memory, auto-adds to pool
94
+ # or shorthand: /freeflow deploy
95
+ ```
96
+ Manual fallback: push 2 files (`api/relay.js` + `vercel.json`) to GitHub, then Import on `vercel.com`, then `/freeflow add https://your.vercel.app vercel-relay-1`
97
+
98
+ For `api/relay.js`, use the canonical worker source (see below); `vercel.json` stays:
99
+
100
+ ```json
101
+ { "rewrites": [{ "source": "/(.*)", "destination": "/api/relay" }] }
102
+ ```
103
+
104
+ **Option C: Deno Deploy, auto deploy**
105
+ ```bash
106
+ /freeflow deploy deno # prompts token in-memory, auto-adds to pool
107
+ ```
108
+ Manual fallback: `dash.deno.com` → New Project → Playground → paste the canonical worker source (see below) → Deploy → `/freeflow add https://your-project.deno.dev deno-relay-1`
109
+
110
+ **Canonical worker source (all platforms)**
111
+
112
+ The relay worker template is generated per deployment by `/freeflow deploy`, with one shared core adapted for Vercel, Cloudflare, and Deno. Deployed relays accept requests from any pi-freeflow user by default, while only forwarding to an allowlist (`https://opencode.ai`, `https://api.kilo.ai`) with private-host and path checks.
113
+
114
+ ```js
115
+ // Minimal Cloudflare illustration. Prefer /freeflow deploy: the generated
116
+ // worker is the hardened source for all three platforms.
117
+ // This example omits the private-host guard, path validation, and auth.
118
+ const ALLOWED_TARGETS = ["https://opencode.ai", "https://api.kilo.ai"];
119
+ export default {
120
+ async fetch(req) {
121
+ const target = req.headers.get("x-relay-target");
122
+ const relayPath = req.headers.get("x-relay-path") || "/";
123
+ if (!target || !ALLOWED_TARGETS.includes(target.replace(/\/$/, ""))) {
124
+ return new Response(JSON.stringify({ error: "Forbidden target" }), { status: 403 });
125
+ }
126
+ const headers = new Headers(req.headers);
127
+ headers.delete("x-relay-target"); headers.delete("x-relay-path"); headers.delete("host");
128
+ return fetch(target.replace(/\/$/, "") + relayPath, { method: req.method, headers, body: req.method !== "GET" && req.method !== "HEAD" ? req.body : undefined });
129
+ },
130
+ };
131
+ ```
132
+
133
+ **Verify your pool:**
134
+ ```bash
135
+ /freeflow status # active relay, pool status, candidates
136
+ /freeflow list # every relay with health status
137
+ /freeflow logs # tail -25
138
+ ```
139
+
140
+ ### Carry your pool to another machine
141
+
142
+ ```bash
143
+ /freeflow export # save pool to ./freeflow-relays.json
144
+ /freeflow export backup/team.json # save to a path you choose
145
+ /freeflow import backup/team.json # add its relays to this machine (merge)
146
+ /freeflow import backup/team.json --replace --dry-run # preview a full swap first
147
+ ```
148
+
149
+ Merge is the default and never deletes anything. Replace swaps the whole pool
150
+ and always asks first. Passwords stay out of the file unless you pass
151
+ `--include-secrets`; a file without passwords still imports, and you re-enter
152
+ each password once afterwards.
153
+
154
+ ---
155
+
156
+ ### Commands reference (`/freeflow`)
157
+
158
+ The same command set works identically in OMP and Pi:
159
+
160
+ ```bash
161
+ /freeflow status # View active relay, pool status, and candidates
162
+ /freeflow list # List all relays with real-time health badges
163
+ /freeflow use <url|index|label> # Switch active relay
164
+ /freeflow url <url> # Set the active relay URL directly
165
+ /freeflow add <url> [label] # Add new relay to the pool
166
+ /freeflow label <index|url> <name># Assign a friendly label to a relay
167
+ /freeflow remove <index|url|label># Remove a relay from the pool
168
+ /freeflow test <index|url|label> # Probe a relay for reachability and latency
169
+ /freeflow on | off | auto # Toggle relay mode (auto = enabled for freeflow)
170
+ /freeflow deploy <platform> # Guided relay deploy: vercel|cloudflare|deno, token in-memory, auto-adds
171
+ /freeflow logs [lines] # Inspect recent proxy logs
172
+ /freeflow trace [req-id] # Tail logs filtered by request correlation ID
173
+ /freeflow refresh # Reload the model catalog from live upstreams
174
+ /freeflow update # Check for and install a package update
175
+ /freeflow debug on | off # Toggle full HTTP lifecycle debug logging
176
+ /freeflow kill # Stop the shared proxy daemon now (restarts on next use)
177
+ /freeflow export [path] [--include-secrets] # Save the relay pool to a file (default freeflow-relays.json; passwords left out unless asked)
178
+ /freeflow import <path> [--merge|--replace] [--dry-run] # Load a relay pool from a file (merge is default; replace asks first; dry-run previews only)
179
+ ```
180
+
181
+ ---
182
+
183
+ ### 27 models, one command
184
+
185
+ ```bash
186
+ /model → freeflow → pick
187
+ ```
188
+
189
+ #### OpenCode Zen (8 models), Responses, Chat, and Messages API
190
+
191
+ Good defaults for long coding sessions and agentic work.
192
+
193
+ | Model ID | Creator / Lab | Context | Max Output | Thinking | Vision |
194
+ | :--- | :--- | :--- | :--- | :--- | :--- |
195
+ | `muse-spark-1.2-contributor-free` | Meta Superintelligence Labs | **1M** (1.048.576) | **131K** (131.072) | `minimal … xhigh` | ✅ |
196
+ | `muse-spark-1.3-contributor-free` | Meta Superintelligence Labs | **1M** (1.048.576) | **131K** (131.072) | `minimal … xhigh` | ✅ |
197
+ | `mimo-v2.5-free` | Xiaomi MiMo | **1M** (1.048.576) | **131K** (131.072) | `minimal … xhigh`\* | ✅ |
198
+ | `nemotron-3.5-lightning-free` | NVIDIA | **1M** (1.000.000) | **262K** (262.144) | `minimal … xhigh` | ❌ |
199
+ | `nemotron-3-ultra-free` | NVIDIA | **1M** (1.000.000) | **128K** (128.000) | `minimal … xhigh` | ❌ |
200
+ | `big-pickle` | Big Pickle | **200K** (200.000) | **32K** (32.000) | `high / max` | ❌ |
201
+ | `ling-3.0-flash-fin-free` | Inclusion AI | **262K** (262.144) | **131K** (131.072) | `minimal … xhigh` | ❌ |
202
+ | `union-alpha` | Union | **262K** (262.144) | **131K** (131.072) | — *(no effort levels)* | ✅ |
203
+
204
+ #### KiloCode Gateway (19 models), OpenRouter compatible
205
+
206
+ Keyless access. Short aliases work for every row (the full ID is in parentheses).
207
+
208
+ | Model ID | Creator / Lab | Context | Max Output | Thinking | Vision |
209
+ | :--- | :--- | :--- | :--- | :--- | :--- |
210
+ | `dots-3-note-preview` (`dots-studio/...:free`) | Dots Studio | **512K** (512.000) | **512K** (512.000) | `minimal…xhigh`\* | ✅ |
211
+ | `step-3.7-flash` (`stepfun/...:free`) | StepFun | **262K** (262.144) | **262K** (262.144) | `minimal…xhigh`\* | ✅ |
212
+ | `nemotron-3-nano-omni` (`nvidia/...:free`) | NVIDIA | **256K** (256.000) | **131K** (131.072) | `minimal…xhigh`\* | ✅ |
213
+ | `nemotron-3-ultra-550b` (`nvidia/...:free`) | NVIDIA | **1M** (1.000.000) | **128K** (128.000) | `minimal…xhigh`\* | ❌ |
214
+ | `nvidia/nemotron-3.5-lightning:free` | NVIDIA | **1M** (1.000.000) | **262K** (262.144) | `minimal…xhigh`\* | ❌ |
215
+ | `nemotron-3-super` (`nvidia/...:free`) | NVIDIA | **262K** (262.144) | **262K** (262.144) | `minimal…xhigh`\* | ❌ |
216
+ | `north-mini-code` (`cohere/...:free`) | Cohere | **256K** (256.000) | **64K** (64.000) | `minimal…xhigh`\* | ❌ |
217
+ | `laguna-s-2.1:free` (`poolside/...:free`) | Poolside | **262K** (262.144) | **32K** (32.768) | `minimal…xhigh`\* | ❌ |
218
+ | `laguna-xs-2.1:free` (`poolside/...:free`) | Poolside | **262K** (262.144) | **32K** (32.768) | `minimal…xhigh`\* | ❌ |
219
+ | `lfm-2.5` (`liquid/lfm-2.5-2.6b:free`) | Liquid AI | **65K** (65.536) | **32K** (32.768) | `minimal…xhigh`\* | ❌ |
220
+ | `kilo-auto` (`kilo-auto/free`) | Kilo Gateway Auto | **256K** (256.000) | **10K** (10.000) | `minimal…xhigh`\* | ❌ |
221
+ | `openrouter` (`openrouter/free`) | OpenRouter Free | **200K** (200.000) | **65K** (65.536) | `minimal…xhigh`\* | ✅ |
222
+ | `content-safety` (`nvidia/...:free`) | NVIDIA | **128K** (128.000) | **8K** (8.192) | ❌ *(non-thinking)* | ✅ |
223
+ | `ling-3.0-flash-fin` (`inclusionai/ling-3.0-flash-fin:free`) | Inclusion AI | **262K** (262.144) | **32K** (32.768) | `minimal…xhigh`\* | ❌ |
224
+ | `ling-3.0-flash-sante` (`inclusionai/ling-3.0-flash-sante:free`) | Inclusion AI | **262K** (262.144) | **32K** (32.768) | `minimal…xhigh`\* | ❌ |
225
+ | `nex-n2.5-pro` (`nex-agi/nex-n2.5-pro:free`) | Nex AGI | **262K** (262.144) | **235K** (235.929) | `minimal…xhigh`\* | ✅ |
226
+ | `nex-n2.5-mini` (`nex-agi/nex-n2.5-mini:free`) | Nex AGI | **262K** (262.144) | **235K** (235.929) | `minimal…xhigh`\* | ✅ |
227
+ | `ling-3.0-flash-vl` (`inclusionai/ling-3.0-flash-vl:free`) | Inclusion AI | **262K** (262.144) | **32K** (32.768) | `minimal…xhigh`\* | ✅ |
228
+ | `inkling-small` (`thinkingmachines/inkling-small:free`) | Thinking Machines | **1M** (1.048.576) | **262K** (262.144) | `minimal…xhigh`\* | ✅ |
229
+
230
+ \* Levels are forwarded as-is through the OpenRouter-style nested `reasoning` parameter; effort mapping is decided by each model. MiMo collapses `minimal→low` and `xhigh→high` upstream, so its selector shows 5 labels but only 3 distinct effort values.
231
+
232
+ ---
233
+
234
+ ### Logs and debugging
235
+
236
+ ```bash
237
+ /freeflow logs
238
+ cat ~/.pi/agent/pi-freeflow.log | tail -n 50
239
+
240
+ # full debug logging is on by default; `off` restores info level
241
+ /freeflow debug on
242
+ ```
243
+
244
+ ---
245
+
246
+ ### Design
247
+
248
+ This package stays thin. It ships three things: a model catalog, a relay proxy, and a log. There is no build step and zero runtime dependencies. Thinking and prompt normalization stay with the host (`pi-ai`).
249
+
250
+ About 19k lines including tests. The full suite (sandboxed, network-mocked) and typecheck pass before every release. See CHANGELOG.md.
251
+
252
+ ---
253
+
254
+ ### FAQ
255
+
256
+ **Do I need API keys?**
257
+ No. Kilo uses a shared free credential and OpenCode free models need no header. You never paste a key.
258
+
259
+ **What if all relays hit rate limits?**
260
+ The proxy tries direct upstream. If that is also rate-limited, the host shows the limit. That number is the shared upstream cap; without relays you would hit the same wall sooner.
261
+
262
+ **Can I use it without relays?**
263
+ Yes. `/freeflow off` talks direct. Add relays later when you need them.
264
+
265
+ **What happens when I update to a new version?**
266
+ The local proxy daemon is shared across sessions on port 28180. On upgrade, the new extension
267
+ detects a stale daemon (an older version still running) and replaces it automatically, with no manual
268
+ kill and no restart of other sessions. Replacement only happens when the running daemon is
269
+ idle: sessions with in-flight requests are never interrupted (busy or newer daemons are reused
270
+ with a log note instead). If a daemon cannot be replaced (for example the port is held by an unrelated process),
271
+ it falls back to reusing it with a warning. To disable replacement entirely, set the no-kill env
272
+ to `1` before starting a session.
273
+
274
+ **What happens when I close a session?**
275
+ Nothing visible to your other sessions. The proxy daemon is a separate background
276
+ process shared by every OMP/Pi session on the machine. Closing one session just
277
+ unregisters it; the daemon keeps serving the rest and retires itself automatically
278
+ once the last client disconnects and no client re-attaches within a short grace window.
279
+ To stop it manually, run `/freeflow kill`. The next freeflow use starts it again.
280
+
281
+ **Why did my long session stop with a "reasoning was not issued to this caller" error?**
282
+ The upstream backend signs each thinking block so only the backend that produced it can read it back. When a later turn reaches a different backend, the old blocks get rejected and the session stalls. pi-freeflow keeps each conversation on the relay that produced its thinking while that relay is healthy. When the relay has to change anyway (rate limit, relay removed, direct-mode switch), that turn is sent without the old thinking blocks so the new backend accepts it, and only the rejected blocks are dropped afterwards. Messages, tool calls, and tool results are always kept.
283
+
284
+ **Why is it installed via npm?**
285
+ The npm package is the distribution channel only. Both hosts resolve it internally:
286
+ `omp plugin install pi-freeflow` and `pi install npm:pi-freeflow` install the same
287
+ package from the npm registry. pi-freeflow is an extension, not a standalone CLI.
288
+ The host (OMP or Pi) loads and runs it. A plain `npm install` just downloads the
289
+ files; it is not a supported way to run the extension.
290
+
291
+ **Which hosts can use it?**
292
+ Oh My Pi (OMP) and Pi only. They share the same extension API, so one
293
+ package serves both. Other AI agents (OpenCode, KiloCode, Cursor, and similar) have their
294
+ own plugin systems and do not load this extension.
295
+
296
+ ---
297
+
298
+ ### Contributing
299
+
300
+ Contributions welcome: bug fixes, new relay platforms, model additions, docs improvements.
301
+
302
+ #### Prerequisites
303
+
304
+ - **Node.js ≥ 22.19.0** (uses `--experimental-strip-types`, no build step)
305
+ - **pnpm** (package manager)
306
+
307
+ #### Setup and verify
308
+
309
+ ```bash
310
+ git clone https://github.com/trefeon/pi-freeflow
311
+ cd pi-freeflow
312
+ pnpm install
313
+
314
+ # run all three before opening a PR
315
+ pnpm test # full suite; sandboxed and network-mocked
316
+ pnpm typecheck # tsc --noEmit, must pass clean
317
+ pnpm smoke # verifies extensions/index.ts loads without crashing
318
+ ```
319
+
320
+ #### Project structure
321
+
322
+ ```
323
+ src/
324
+ ├── index.ts # extension entry, lifecycle hooks
325
+ ├── models.ts # 27-model catalog definitions
326
+ ├── catalog.ts # model catalog cache (24h disk)
327
+ ├── proxy.ts # local proxy server (127.0.0.1:28180)
328
+ ├── relay.ts # relay selection and round-robin
329
+ ├── relay-state.ts # relay pool state, health tracking
330
+ ├── stream-pipe.ts # SSE stream piping and truncation resilience
331
+ ├── commands.ts # /freeflow CLI subcommands
332
+ ├── deploy.ts # guided relay deploy (vercel/cloudflare/deno)
333
+ ├── config.ts # constants, whitelists, paths, and runtime settings
334
+ ├── logger.ts # file logger with 10MB rotation
335
+ └── types.ts # shared type definitions
336
+ extensions/
337
+ └── index.ts # OMP/Pi extension manifest
338
+ test/
339
+ └── *.test.ts # mirrors src/, node:test runner
340
+ ```
341
+
342
+ #### Guidelines
343
+
344
+ - **Stay thin.** Zero runtime dependencies, no build step. If it belongs in the host (`pi-ai`), don't add it here.
345
+ - **Test what you touch.** Every `src/*.ts` has a matching `test/*.test.ts`. Add or update tests for your change.
346
+ - **Keep model IDs clean.** Slash-free, colon-free aliases for CLI compatibility. See existing patterns in `models.ts`.
347
+ - **One concern per PR.** Bug fix? One PR. New relay platform? Separate PR. Easier to review, faster to merge.
348
+
349
+ #### Reporting issues
350
+
351
+ Found a bug or want a feature? [Open an issue](https://github.com/trefeon/pi-freeflow/issues) with:
352
+ - What happened vs what you expected
353
+ - Your relay setup (`/freeflow status` output helps)
354
+ - Relevant logs (`/freeflow logs` or `~/.pi/agent/pi-freeflow.log`)
355
+
356
+ ---
357
+
358
+ ### License
359
+
360
+ MIT © trefeon