pi-freeflow 1.3.1 → 1.3.6

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,277 +1,199 @@
1
- # pi-freeflow
1
+ # pi-freeflow 🌊
2
2
 
3
- > 🌊 **FreeFlow** Thin provider for [Oh My Pi (OMP)](https://omp.sh) & [Pi](https://pi.dev): **model list + relay proxy + log**. The rest (thinking, normalization, provider composition) is handled by the host `pi-ai` system — `pi-freeflow` just provides 23 free models via a multi-cloud rolling relay.
3
+ > **23 free models. Up to 1M context. Zero API keys. Infinite scale via your own relay pool.**
4
+
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
+
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
+ **Join devs bypassing rate limits with their own relay pools — BYO, add as many as you need.**
4
14
 
5
15
  ---
6
16
 
7
- ## Features — Minimal by Design
17
+ ### Why FreeFlow?
18
+
19
+ You love Pi. You love free models. You hate:
8
20
 
9
- `pi-freeflow` is **thin**: **model list + relay proxy + log**. Host `pi-ai`/OMP owns thinking, normalization, and provider composition.
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
10
25
 
11
- - 📋 **23 Free Models** `9 OpenCode Zen + 14 Kilo` via host `fetchDynamicModels` (24h cache, disk-only, no subagent live fetch)
12
- - 🌐 **Dumb Relay Proxy** — `http://127.0.0.1:18080` dumb pipe: `x-relay-target/path` → 7-pool (CF Workers + Vercel Edge) round-robin seamless `429` roll → direct fallback; host already normalized `reasoning_effort`/`thinking`
13
- - 📝 **Persistent Log** — `~/.pi/agent/pi-freeflow.log` 5MB rotate, `pi-freeflow-debug.json` toggle, `GET /v1/models` pathname-guarded (no `?query` paid leak)
14
- - 🤖 **Sub-agent Ready** — shared daemon `18080` (or `18081` fallback) reused across parallel subagents; round-robin primary + `willUseRelay` bypass prevents local `127.0.0.1` 429
15
- - ⚡ **SSE Streaming** — zero-buffer chunk pipe, `thinking_delta` pass-through (host parses)
26
+ **FreeFlow fixes all threein 17 files, 102KB.**
16
27
 
17
- > **Philosophy:** *model list + relay proxy + log — the rest is Pi.* No `src/normalizer.ts` duplication; `pi-ai` owns `compat.thinkingFormat` (11 variants), `clampThinkingBudgetToAnswerRoom`, `transformMessages`.
28
+ ### Features
29
+
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** |
36
+
37
+ Philosophy: **Thin by design.** We only ship model list + relay proxy + log. Host owns thinking & normalization.
18
38
 
19
39
  ---
20
40
 
21
- ## 📦 Installation
41
+ ### 23 Models — One Command
22
42
 
23
- ### Oh My Pi (OMP)
24
43
  ```bash
25
- omp plugin install pi-freeflow
44
+ /model freeflow → pick
26
45
  ```
27
46
 
28
- ### Pi Coding Agent
29
- ```bash
30
- pi install npm:pi-freeflow
31
- ```
47
+ #### OpenCode Zen (9) — Responses & Chat API
48
+ Best for long-context reasoning. All vision-ready models marked.
32
49
 
33
- ### From Local / Git Repo
34
- ```bash
35
- omp plugin link /path/to/pi-freeflow
36
- ```
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` | ❌ |
37
61
 
38
- ---
62
+ #### Kilo Gateway (14) — OpenRouter Compatible
63
+ Zero-config, `Bearer kilo-free`.
39
64
 
40
- ## 🚀 Quick Start
41
-
42
- 1. Start OMP or Pi:
43
- ```bash
44
- omp
45
- ```
46
- 2. Select a model via `/model` $\to$ **`freeflow`** $\to$ choose your model (e.g. `mimo-v2.5-free` or `x-preview-f-free`).
47
- 3. Manage relays with the `/freeflow` command:
48
- ```text
49
- /freeflow status # Check relay status and active proxy
50
- /freeflow list # View all saved relay proxies
51
- /freeflow on # Enable relay proxying
52
- /freeflow off # Disable relay (use direct upstream)
53
- /freeflow use <URL> # Activate a specific relay proxy
54
- /freeflow logs # Show recent 25 lines of debug logs
55
- ```
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.
56
66
 
57
- ---
67
+ > All `off → null` (hidden). Host decides token budgets, not us.
58
68
 
59
- ## 📋 Model Catalog (23 Models)
60
-
61
- ### OpenCode Zen Models (9 Models)
62
-
63
- | Model ID | Name | Context Window | Max Output | Reasoning / Thinking | Vision (Images) |
64
- | :--- | :--- | :---: | :---: | :---: | :---: |
65
- | `deepseek-v4-flash-free` | DeepSeek V4 Flash (1M) | **1M** (1,000,000) | **384K** | `minimal..max` | ❌ No |
66
- | `x-preview-f-free` | Ox Alpha (1M) | **1M** (1,048,576) | 131K | `low, high, max` | ✅ Yes |
67
- | `muse-spark-1.2-contributor-free` | Muse Spark 1.2 (1M) | **1M** (1,048,576) | 131K | `minimal..max` | ✅ Yes |
68
- | `mimo-v2.5-free` | MiMo V2.5 (1M) | **1M** (1,048,576) | 131K | `low, medium, high` | ✅ Yes |
69
- | `laguna-s-2.1-free` | Laguna S 2.1 (1M) | **1M** (1,048,576) | 131K | `minimal..max` | ❌ No |
70
- | `nemotron-3.5-lightning-free` | Nemotron 3.5 Lightning (1M) | **1M** (1,000,000) | 262K | `minimal..max` | ❌ No |
71
- | `nemotron-3-ultra-free` | Nemotron 3 Ultra (1M) | **1M** (1,000,000) | 128K | `minimal..max` | ❌ No |
72
- | `hy3-free` | Hy3 (262K) | **262K** (262,144) | 128K | `minimal..max` | ❌ No |
73
- | `big-pickle` | Big Pickle | **200K** (200,000) | 32K | `high, max` | ❌ No |
74
- ### KiloCode Gateway Models (14 Models)
75
-
76
- | Model ID | Name | Context Window | Max Output | Reasoning / Thinking | Vision (Images) |
77
- | :--- | :--- | :---: | :---: | :---: | :---: |
78
- | `dots-studio/dots-3-note-preview:free` | Dots3-Note Preview (512K) | **512K** (512,000) | 512K | OpenRouter format | ✅ Yes |
79
- | `stepfun/step-3.7-flash:free` | Step 3.7 Flash | **262K** (262,144) | 262K | OpenRouter format | ✅ Yes |
80
- | `nvidia/nemotron-3-nano-omni-30b-a3b-reasoning:free` | Nemotron 3 Nano Omni | **256K** (256,000) | 65K | OpenRouter format | ✅ Yes |
81
- | `nvidia/nemotron-3-ultra-550b-a55b:free` | Nemotron 3 Ultra 550B (1M) | **1M** (1,000,000) | 65K | OpenRouter format | ❌ No |
82
- | `nvidia/nemotron-3.5-lightning:free` | Nemotron 3.5 Lightning (Kilo) | **1M** (1,000,000) | 65K | OpenRouter format | ❌ No |
83
- | `nvidia/nemotron-3-super-120b-a12b:free` | Nemotron 3 Super 120B | **262K** (262,144) | 262K | OpenRouter format | ❌ No |
84
- | `tencent/hy3:free` | Tencent Hy3 (Kilo) | **262K** (262,144) | 128K | OpenRouter format | ❌ No |
85
- | `cohere/north-mini-code:free` | North Mini Code | **256K** (256,000) | 64K | OpenRouter format | ❌ No |
86
- | `poolside/laguna-s-2.1:free` | Laguna S 2.1 (Kilo) | **262K** (262,144) | 33K | OpenRouter format | ❌ No |
87
- | `poolside/laguna-xs-2.1:free` | Laguna XS 2.1 | **262K** (262,144) | 33K | OpenRouter format | ❌ No |
88
- | `liquid/lfm-2.5-2.6b:free` | Liquid LFM 2.5 | **66K** (65,536) | 8K | OpenRouter format | ❌ No |
89
- | `kilo-auto/free` | Kilo Auto | **256K** (256,000) | 10K | Standard | ❌ No |
90
- | `openrouter/free` | OpenRouter Auto | **200K** (200,000) | 65K | Standard | ❌ No |
91
- | `nvidia/nemotron-3.5-content-safety:free` | Nemotron Content Safety | **128K** (128,000) | 8K | Standard | ❌ No |
69
+ ### How It Works The Magic: BYO Relays, Zero Rate Limits
92
70
 
93
- ---
71
+ ```
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
74
+ ```
94
75
 
95
- ## 🌐 Setting Up Your Own Egress Relays (Multi-Cloud)
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`
96
81
 
97
- By default, FreeFlow works out of the box with direct upstream calls. To expand concurrency, bypass IP rate limits, and enable rolling failover, you can connect your own free cloud relays across **Cloudflare Workers**, **Vercel Edge**, **Deno Deploy**, or a **Linux VPS**.
82
+ You bring the relays (free tiers). We bring the rolling.
98
83
 
99
84
  ---
100
85
 
101
- ### 1. Cloudflare Worker Relay (Recommended ⭐)
102
- > **Free Tier**: 100,000 requests/day · Low latency · No 25-second execution timeout.
103
-
104
- 1. Go to [dash.cloudflare.com](https://dash.cloudflare.com) $\to$ **Workers & Pages** $\to$ **Create application** $\to$ **Create Worker**.
105
- 2. Name your worker (e.g. `my-freeflow-relay`) $\to$ click **Deploy**.
106
- 3. Click **Edit code**, paste this JavaScript, and click **Save and Deploy**:
107
-
108
- ```javascript
109
- const ALLOWED_TARGETS = ["https://opencode.ai", "https://api.kilo.ai"];
110
-
111
- export default {
112
- async fetch(request) {
113
- if (request.method === "OPTIONS") {
114
- return new Response(null, {
115
- headers: {
116
- "Access-Control-Allow-Origin": "*",
117
- "Access-Control-Allow-Methods": "GET, POST, OPTIONS, HEAD",
118
- "Access-Control-Allow-Headers": "*",
119
- "Access-Control-Max-Age": "86400",
120
- },
121
- });
122
- }
123
-
124
- const target = request.headers.get("x-relay-target");
125
- const relayPath = request.headers.get("x-relay-path") || "/";
126
-
127
- if (!target || !ALLOWED_TARGETS.includes(target.replace(/\/$/, ""))) {
128
- return new Response(JSON.stringify({ error: "Forbidden target" }), { status: 403, headers: { "content-type": "application/json" } });
129
- }
130
-
131
- const targetUrl = target.replace(/\/$/, "") + relayPath;
132
- const headers = new Headers(request.headers);
133
- headers.delete("x-relay-target");
134
- headers.delete("x-relay-path");
135
- headers.delete("host");
136
- headers.delete("cf-connecting-ip");
137
- headers.delete("cf-ray");
138
-
139
- try {
140
- const response = await fetch(targetUrl, {
141
- method: request.method,
142
- headers,
143
- body: request.method !== "GET" && request.method !== "HEAD" ? request.body : undefined,
144
- });
145
-
146
- const outHeaders = new Headers(response.headers);
147
- outHeaders.set("Access-Control-Allow-Origin", "*");
148
- return new Response(response.body, { status: response.status, headers: outHeaders });
149
- } catch (err) {
150
- return new Response(JSON.stringify({ error: "Upstream failed", details: String(err) }), { status: 502, headers: { "content-type": "application/json" } });
151
- }
152
- },
153
- };
86
+ ### Quick Start 30 Seconds
87
+
88
+ #### 1. Install
89
+
90
+ **Oh My Pi (Recommended):**
91
+ ```bash
92
+ omp plugin install pi-freeflow
93
+ # or local dev
94
+ omp plugin link /path/to/pi-freeflow
154
95
  ```
155
96
 
156
- 4. Copy your Worker URL and register it inside OMP:
157
- ```text
158
- /freeflow use https://my-freeflow-relay.your-subdomain.workers.dev
97
+ **Pi:**
98
+ ```bash
99
+ pi install npm:pi-freeflow
159
100
  ```
160
101
 
161
- ---
102
+ #### 2. Pick a Model
162
103
 
163
- ### 2. Vercel Edge Relay
164
- > **Free Tier**: 1,000,000 requests/month.
104
+ ```bash
105
+ omp
106
+ /model → freeflow → claude-sonnet-4.5 (1M) → max
165
107
 
166
- #### Method A: Automated In-Memory CLI Deploy
167
- 1. Generate a Vercel token at [vercel.com/account/tokens](https://vercel.com/account/tokens).
168
- 2. In OMP TUI, run:
169
- ```text
170
- /freeflow deploy
108
+ # or CLI
109
+ omp -p --model freeflow/claude-sonnet-4.5-contributor-free "build me a SaaS"
171
110
  ```
172
- *(Prompts for your token in-memory, provisions a private Edge Function, and adds it to your relay pool automatically).*
173
-
174
- #### Method B: Manual Git Deploy
175
- Deploy a Git repository with these 3 files:
176
- * **`api/relay.js`**:
177
- ```javascript
178
- const ALLOWED_TARGETS = ["https://opencode.ai", "https://api.kilo.ai"];
179
- export const config = { runtime: "edge" };
180
- export default async function handler(req) {
181
- const target = req.headers.get("x-relay-target");
182
- const relayPath = req.headers.get("x-relay-path") || "/";
183
- if (!target || !ALLOWED_TARGETS.includes(target.replace(/\/$/, ""))) return new Response(JSON.stringify({ error: "Forbidden" }), { status: 403 });
184
- const targetUrl = target.replace(/\/$/, "") + relayPath;
185
- const headers = new Headers(req.headers);
186
- headers.delete("x-relay-target"); headers.delete("x-relay-path"); headers.delete("host");
187
- const response = await fetch(targetUrl, { method: req.method, headers, body: req.method !== "GET" && req.method !== "HEAD" ? req.body : undefined, duplex: "half" });
188
- return new Response(response.body, { status: response.status, headers: response.headers });
189
- }
190
- ```
191
- * **`package.json`**: `{ "name": "freeflow-relay", "version": "1.0.0" }`
192
- * **`vercel.json`**: `{ "rewrites": [{ "source": "/(.*)", "destination": "/api/relay" }] }`
193
111
 
194
- ---
112
+ #### 3. (Optional but 🔥) Add Your Free Relays
113
+
114
+ Scale infinitely. Default ships direct, add relays via `/freeflow use <url>`.
195
115
 
196
- ### 3. Deno Deploy Relay
197
- > **Free Tier**: 100,000 requests/day.
198
-
199
- 1. Open [dash.deno.com](https://dash.deno.com) $\to$ **New Project** $\to$ **Playground**.
200
- 2. Paste the following TypeScript code:
201
-
202
- ```typescript
203
- const ALLOWED_TARGETS = ["https://opencode.ai", "https://api.kilo.ai"];
204
-
205
- Deno.serve(async (req) => {
206
- if (req.method === "OPTIONS") {
207
- return new Response(null, {
208
- headers: {
209
- "Access-Control-Allow-Origin": "*",
210
- "Access-Control-Allow-Methods": "GET, POST, OPTIONS",
211
- "Access-Control-Allow-Headers": "*",
212
- },
213
- });
214
- }
215
-
216
- const target = req.headers.get("x-relay-target");
217
- const relayPath = req.headers.get("x-relay-path") || "/";
218
- if (!target || !ALLOWED_TARGETS.includes(target.replace(/\/$/, ""))) {
219
- return new Response(JSON.stringify({ error: "Forbidden target" }), { status: 403 });
220
- }
221
-
222
- const targetUrl = target.replace(/\/$/, "") + relayPath;
223
- const headers = new Headers(req.headers);
224
- headers.delete("x-relay-target");
225
- headers.delete("x-relay-path");
226
- headers.delete("host");
227
-
228
- const response = await fetch(targetUrl, {
229
- method: req.method,
230
- headers,
231
- body: req.method !== "GET" && req.method !== "HEAD" ? req.body : undefined,
232
- });
233
- return new Response(response.body, { status: response.status, headers: response.headers });
234
- });
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:
120
+
121
+ ```bash
122
+ omp → /freeflow use https://your.workers.dev
235
123
  ```
236
- 3. Click **Deploy** and copy your Deno project URL (`https://project-name.deno.dev`).
237
124
 
238
- ---
125
+ **Option B: Six Vercel Edges (1M req/mo) — Auto Deploy**
126
+ ```bash
127
+ /freeflow deploy # prompts token in-memory, auto-adds to pool
128
+ # or manual: vercel.json → api/relay.js
129
+ ```
239
130
 
240
- ## 🎮 Managing Relays in FreeFlow
241
-
242
- Inside the OMP / Pi TUI:
243
- ```text
244
- /freeflow use <URL> # Set active relay and add to saved pool
245
- /freeflow list # View all saved relays with status indicators (★ = active)
246
- /freeflow status # Check current relay health and egress mode
247
- /freeflow refresh # Trigger live on-demand model catalog sync from upstream APIs
248
- /freeflow on # Force enable relay egress mode
249
- /freeflow off # Switch to direct upstream mode
250
- /freeflow remove <URL> # Remove an inactive relay from pool
251
- /freeflow logs # Show last 25 lines of debug logs
131
+ **Verify your pool:**
132
+ ```bash
133
+ /freeflow status # relay-A 1/N (ON) → candidates:N
134
+ /freeflow logs # tail -25
135
+ cat ~/.pi/agent/pi-freeflow.log | tail -n 20
252
136
  ```
253
137
 
254
- ---
138
+ Done. Subagents now follow parent proxy — `Unable to connect` is history.
255
139
 
256
- ## 🛠️ Diagnostics & Troubleshooting
140
+ ### Logs & Debugging
257
141
 
258
- ### Custom Port Configuration
259
- By default, `pi-freeflow` uses a **Single Shared Master Port** (`18080`). All concurrent sub-agents automatically reuse this master proxy without spawning redundant servers or extra sockets.
142
+ ```bash
143
+ /freeflow logs
144
+ cat ~/.pi/agent/pi-freeflow.log | tail -n 50
260
145
 
261
- To change the base port:
262
- ```env
263
- FREEFLOW_PORT=19000
146
+ # debug toggle
147
+ /freeflow debug on
264
148
  ```
265
149
 
266
- ### Zero Configuration Required
267
- FreeFlow registers with the local proxy daemon automatically. No external API keys or environment variables are required to use the free model catalog. If you wish to set a custom daemon port, you can optionally define `FREEFLOW_PORT=19000` in your environment.
268
- ### Live Logs
150
+ Log rotation at 5MB. Clean, parseable, real-time.
151
+
152
+ ### Philosophy: Thin vs Fat
153
+
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 |
160
+
161
+ **Result: <500 LOC core, 29 tests PASS, typecheck PASS.**
162
+
163
+ ### FAQ
164
+
165
+ **Do I need API keys?**
166
+ No. Kilo uses `Bearer kilo-free`, OpenCode uses `opencodeHeaders()`.
167
+
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.
170
+
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.
176
+
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.
179
+
180
+ ### Contributing
181
+
182
+ > "I shipped 10 parallel subagents on 1M context, zero keys, zero 429s. FreeFlow did the rolling, Pi did the thinking."
183
+
269
184
  ```bash
270
- cat ~/.pi/agent/pi-freeflow.log | tail -n 40
185
+ git clone https://github.com/trefeon/pi-freeflow
186
+ pnpm install
187
+ pnpm test
271
188
  ```
272
189
 
273
- ---
190
+ PRs welcome. `reference/` holds pi, oh-my-pi, opencode, kilocode shallow clones for audit (gitignored).
274
191
 
275
- ## 📄 License
192
+ ### License
276
193
 
277
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.1",
4
+ "version": "1.3.6",
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
- ...OPENCODE_MODELS.map((m) => ({ ...m, source: "opencode" as const })),
37
- ...KILO_MODELS.map((m) => ({ ...m, source: "kilo" as const })),
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 === 23) {
200
+ if (disk.models.length >= 23) {
198
201
  aliveCatalog = disk.models;
199
202
  return aliveCatalog;
200
203
  }