pi-freeflow 1.34.0 → 1.36.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/CHANGELOG.md CHANGED
@@ -1,5 +1,64 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.36.0
4
+
5
+ ### Minor Changes
6
+
7
+ - bf358da: A new free model on the OpenCode Zen lane: Cat Jam
8
+
9
+ `cat-jam-free` joins the picker, bringing the catalog to 37 models (11 OpenCode, 15 Kilo, 2 Cline, 9 OVHcloud). No account, no key, no setup — it is keyless like every other Zen free model.
10
+
11
+ It thinks, and it has a 262,144-token window. That number was measured the hard way: the gateway happily accepts prompts four times that size and answers normally, but the model can no longer read them. A marker planted at the end of a 248,232-token prompt comes back; at 250,272 tokens it does not. So the advertised window is what the model can actually use, not merely what the service tolerates.
12
+
13
+ Two honest limits worth knowing before you pick it:
14
+
15
+ - **It is not available on the Responses API.** Requests sent that way are refused with a protocol error. It works on chat completions, which is what hosts use by default, but a host pinned specifically to Responses will not see it.
16
+ - **Thinking depth starts at "low".** The lowest setting is refused, so "minimal" is not offered; low, medium, high and extra-high all work.
17
+
18
+ The output budget is 131,072, the published figure for this model.
19
+
20
+ ### Patch Changes
21
+
22
+ - bf358da: Long sessions no longer stall on a tool call whose arguments arrived spliced
23
+
24
+ Some models open their next tool call by echoing the tail of the one they had just seen, and occasionally stop before the closing brace. The result is a single argument string carrying both faults at once: the previous call's leftover text in front, and the last brace missing. The whole call was then rejected, the turn failed, and the host retried — which resent the same broken payload, so a long session could get stuck repeating it.
25
+
26
+ Both faults are now repaired together, so the caller's own arguments arrive intact.
27
+
28
+ The repair stays deliberately narrow. It only fires when a leftover fragment is actually present in front of the object, which is the evidence that the model was mid-call rather than that the request itself was malformed, and only when what follows is a complete object merely missing its closing brace. Arguments cut off part-way through a value are still refused untouched, because completing those would silently shorten them — and these arguments carry shell commands.
29
+
30
+ Tool calls that were already well-formed are unaffected and pass through byte-identically.
31
+
32
+ ## 1.35.0
33
+
34
+ ### Minor Changes
35
+
36
+ - 9085408: Nine more free models, from OVHcloud's AI Endpoints — and no account needed
37
+
38
+ The picker now offers nine open-weight models served by OVHcloud AI Endpoints, bringing the catalog to 36: GPT-OSS 120B and 20B, four Qwen models (3.5 397B, 3.5 9B, 3.6 27B, 3.8 27B), Mistral Small 3.2 and Mistral 7B, and Meta Llama 3.3 70B. The four Qwens and Mistral Small 3.2 also read images.
39
+
40
+ Access is anonymous and keyless. There is nothing to sign up for and no key to paste — no login step, no saved credential, no setup of any kind. Pick a model and it works.
41
+
42
+ The honest caveat: OVH rate-limits anonymous callers per IP address. A burst of parallel subagents can run into `API rate limit exceeded`, the same way a shared OpenCode or Kilo quota does. Wait it out or spread the work across models. Requests to these models always go straight to OVH from your machine, never through your relay pool — there is no per-IP gate for a relay to route around.
43
+
44
+ Thinking depth is limited to the two levels OVH confirms, `low` and `high`, on the six models that reason. The output budgets are deliberately conservative: they are the smallest cap any provider offers for the same underlying model, so a turn never asks for more than OVH will give.
45
+
46
+ ### Patch Changes
47
+
48
+ - 3408dad: Stop conversations from dying on request shapes the provider rejects
49
+
50
+ Three shapes that the provider answers with `400 invalid parameters` are now reshaped on the way out instead of failing the whole turn.
51
+
52
+ - **A model narrates a tool call instead of making one.** The reply is recorded as pre-tool commentary, and every later message replayed that turn back to the provider was rejected — the session could not continue or be resumed, because each retry sent the same history again.
53
+ - **A host asks for a specific tool or forces a tool call.** The free provider accepts only automatic tool selection, so an unsupported choice is dropped rather than sent. Nothing is imposed on a host that did not ask.
54
+ - **A tool name carries a character the provider rejects.** Spaces, colons and slashes are folded for the trip out and the caller's own name is restored on the way back, so the tool still runs under the name it was registered with. Names that are already accepted are sent exactly as they always were.
55
+
56
+ Measured on Muse Spark 1.3: the same three requests that each failed with an error now answer normally, and a well-formed tool set reaches the model byte-identical to before.
57
+
58
+ - 9085408: Three free models that no longer answer are gone from the picker
59
+
60
+ `cline-free/deepseek-v4.1-flash`, `cline-free/kimi-k3` and `cline-free/solar-pro4` were retired upstream, so every turn on them failed. All three were probed twice against the live service on 2026-10-13 and each time answered `404 model not found` ("Cline has no such model. Refresh the model list and retry."), while the two Cline models that survive — `cline-free/muse-spark-1.3-contributor` and `z-ai/glm-5.3-flash` — answered 200 with the same login and request shape. The login, the quota rollover and every other model are unchanged; the picker is now 36 models (10 OpenCode, 15 Kilo, 2 Cline, 9 OVH).
61
+
3
62
  ## 1.34.0
4
63
 
5
64
  ### Minor Changes
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # pi-freeflow
2
2
 
3
- > 30 free models with up to 1M context. No API keys to manage. Add your own relays to spread requests across more IPs.
3
+ > 37 free models with up to 1M context. No API keys to manage. Add your own relays to spread requests across more IPs.
4
4
 
5
5
  Thin by design: a model list, a relay proxy, and a log. The host (`pi-ai`) handles thinking, normalization, and provider behavior.
6
6
 
@@ -16,10 +16,10 @@ Thin by design: a model list, a relay proxy, and a log. The host (`pi-ai`) handl
16
16
 
17
17
  | Feature | What it does | Cost |
18
18
  | :--- | :--- | :--- |
19
- | **30 free models** | 10 from OpenCode Zen, 15 from KiloCode Gateway, 5 from Cline, context windows up to 1M. Full list below. | **$0** |
20
- | **Relay pool** | Route requests through your own Cloudflare Workers and Vercel Edge relays. Traffic spreads across the pool, or stays on one sticky relay. 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 |
19
+ | **37 free models** | 11 from OpenCode Zen, 15 from KiloCode Gateway, 2 from Cline, 9 from OVHcloud AI Endpoints, context windows up to 1M. Full list below. | **$0** |
20
+ | **Relay pool** | Route requests through your own Cloudflare Workers, Deno Deploy, and Vercel Edge relays. Traffic spreads across the pool, or stays on one sticky relay. 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
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** |
22
+ | **Short model names** | Most models have a slash-free, colon-free alias, plus an optional `:effort` suffix for thinking depth. You type `freeflow/<name>`; the two Cline models have no alias and must be typed in full. | **$0** |
23
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
24
  | **Logs you can read** | `~/.pi/agent/pi-freeflow.log`, rotated at 10MB. Tail it with `/freeflow logs`. | **$0** |
25
25
 
@@ -85,7 +85,7 @@ Manual fallback per platform:
85
85
  **Option A: Cloudflare Workers, auto deploy (recommended)**
86
86
  ```bash
87
87
  /freeflow deploy cloudflare # prompts token in-memory, auto-adds to pool
88
- # or shorthand: /freeflow deploy (defaults to Cloudflare)
88
+ # or /freeflow deploy with no argument to pick the platform interactively
89
89
  ```
90
90
  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`
91
91
 
@@ -110,7 +110,7 @@ For `api/relay.js`, use the canonical worker source (see below); `vercel.json` s
110
110
 
111
111
  **Canonical worker source (all platforms)**
112
112
 
113
- 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
+ The relay worker template is generated per deployment by `/freeflow deploy`, with one shared core adapted for Vercel, Cloudflare, and Deno. Every deploy embeds a random 32-byte secret, and the generated worker answers `401` to any request without a matching `x-relay-auth` header; the client sends that secret to each relay in the pool. Only a hand-pasted legacy worker built without a secret is open to anyone. Either way, a relay forwards only to an allowlist (`https://opencode.ai`, `https://api.kilo.ai`) with private-host and path checks.
114
114
 
115
115
  ```js
116
116
  // Minimal Cloudflare illustration. Prefer /freeflow deploy: the generated
@@ -185,18 +185,19 @@ The same command set works identically in OMP and Pi:
185
185
 
186
186
  ---
187
187
 
188
- ### 30 models, one command
188
+ ### 37 models, one command
189
189
 
190
190
  ```bash
191
191
  /model → freeflow → pick
192
192
  ```
193
193
 
194
- #### OpenCode Zen (10 models), Responses and Chat API
194
+ #### OpenCode Zen (11 models), Responses and Chat API
195
195
 
196
196
  Good defaults for long coding sessions and agentic work.
197
197
 
198
198
  | Model ID | Creator / Lab | Context | Max Output | Thinking | Vision |
199
199
  | :--- | :--- | :--- | :--- | :--- | :--- |
200
+ | `cat-jam-free` | Cat Jam | **256K** (262.144) | **131K** (131.072) | `low … xhigh` | ❌ |
200
201
  | `muse-spark-1.2-contributor-free` | Meta Superintelligence Labs | **1M** (1.048.576) | **131K** (131.072) | `minimal … xhigh` | ✅ |
201
202
  | `muse-spark-1.3-contributor-free` | Meta Superintelligence Labs | **1M** (1.048.576) | **131K** (131.072) | `minimal … xhigh` | ✅ |
202
203
  | `mimo-v2.6-flash-free` | Xiaomi MiMo | **1M** (1.048.576) | **131K** (131.072) | `minimal … xhigh`\* | ✅ |
@@ -208,7 +209,7 @@ Good defaults for long coding sessions and agentic work.
208
209
  | `step-5-preview-free` | StepFun | **1M** (1.000.000) | **64K** (65.536) | `low … high` | ✅ |
209
210
  | `ling-3.1-flash-free` | Inclusion AI | **262K** (262.144) | **32K** (32.768) | `minimal … max` | ❌ |
210
211
 
211
- #### KiloCode Gateway (16 models), OpenRouter compatible
212
+ #### KiloCode Gateway (15 models), OpenRouter compatible
212
213
 
213
214
  Keyless access. Short aliases work for every row (the full ID is in parentheses).
214
215
 
@@ -226,13 +227,13 @@ Keyless access. Short aliases work for every row (the full ID is in parentheses)
226
227
  | `kilo-auto` (`kilo-auto/free`) | Kilo Gateway Auto | **256K** (256.000) | **10K** (10.000) | `minimal…xhigh`\* | ❌ |
227
228
  | `openrouter` (`openrouter/free`) | OpenRouter Free | **200K** (200.000) | **65K** (65.536) | `minimal…xhigh`\* | ✅ |
228
229
  | `glyph-cluster` (`stealth/glyph-cluster`) | Stealth preview (lab undisclosed) | **256K** (256.000) | **256K** (256.000) | `minimal…xhigh`\* | ❌ |
229
- | `step-5-preview:kilo` (`stepfun/...:free`) | StepFun | **1M** (1.000.000) | **64K** (64.000) | `minimal…xhigh`\* | ✅ |
230
+ | `step-5-preview:kilo` (`stepfun/...:free`) | StepFun | **1M** (1.000.000) | **64K** (65.536) | `minimal…xhigh`\* | ✅ |
230
231
  | `inkling-small` (`thinkingmachines/inkling-small:free`) | Thinking Machines | **1M** (1.048.576) | **262K** (262.144) | `minimal…xhigh`\* | ✅ |
231
- | `ling-3.1-flash-kilo` (`inclusionai/ling-3.1-flash`) | Inclusion AI | **262K** (262.144) | **32K** (32.768) | `minimal…xhigh`\* | ❌ |
232
+ | `ling-3.1-flash:kilo` (`inclusionai/ling-3.1-flash`) | Inclusion AI | **262K** (262.144) | **32K** (32.768) | `minimal…xhigh`\* | ❌ |
232
233
 
233
234
  \* 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.
234
235
 
235
- #### Cline (5 models), OpenAI compatible
236
+ #### Cline (2 models), OpenAI compatible
236
237
 
237
238
  Rotating per-account promo, direct only (never through the relay pool). Sign in through your browser with `/freeflow cline login`, manage with `/freeflow cline accounts` and `/freeflow cline logout`. Requests roll across saved logins when one hits its daily free limit.
238
239
 
@@ -242,11 +243,28 @@ Each account can only be saved once: an extra login for an account you already h
242
243
 
243
244
  | Model ID | Creator / Lab | Context | Max Output | Thinking | Vision |
244
245
  | :--- | :--- | :--- | :--- | :--- | :--- |
245
- | `cline-free/deepseek-v4.1-flash` | DeepSeek | **1M** (1.000.000) | **384K** (384.000) | `low/high/max` | ✅ |
246
246
  | `cline-free/muse-spark-1.3-contributor` | Meta Superintelligence Labs | **1M** (1.048.576) | **131K** (131.072) | `minimal…xhigh`\* | ✅ |
247
- | `z-ai/glm-5.3-flash` | Zhipu AI | **1M** (1.000.000) | **131K** (131.072) | `low/high/max` | ✅ |
248
- | `cline-free/kimi-k3` | Moonshot AI | **1M** (1.048.576) | **131K** (131.072) | `low/high/max` | ✅ |
249
- | `cline-free/solar-pro4` | Upstage | **512K** (524.288) | **131K** (131.072) | `minimal…max`\* | ❌ |
247
+ | `z-ai/glm-5.3-flash` | Zhipu AI | **1M** (1.048.576) | **131K** (131.072) | `low/high/max` | ✅ |
248
+
249
+ #### OVHcloud AI Endpoints (9 models), OpenAI compatible
250
+
251
+ Anonymous access — no account, no key, nothing to sign in to. Direct only (never through the relay pool), because OVH has no per-IP gate for relays to route around. OVH rate-limits anonymous callers per IP, so a burst of parallel subagents can hit `429 API rate limit exceeded`; the model list itself never costs anything.
252
+
253
+ Pick them with the slash-free short name (the full ID is in parentheses). Only `low` and `high` thinking levels are offered, because those are the two OVH confirmed.
254
+
255
+ All nine talk the normal chat API. Hosts that prefer the responses API work too — the proxy maps that shape to chat and maps the answer back, so tool calls and streamed output behave exactly as they do on the other providers.
256
+
257
+ | Model ID | Creator / Lab | Context | Max Output | Thinking | Vision |
258
+ | :--- | :--- | :--- | :--- | :--- | :--- |
259
+ | `gpt-oss-120b` (`ovh-free/gpt-oss-120b`) | OpenAI | **128K** (131.072) | **32K** (32.768) | `low/high` | ❌ |
260
+ | `gpt-oss-20b` (`ovh-free/gpt-oss-20b`) | OpenAI | **128K** (131.072) | **32K** (32.768) | `low/high` | ❌ |
261
+ | `qwen3.5-397b` (`ovh-free/Qwen3.5-397B-A17B`) | Alibaba Qwen | **256K** (262.144) | **64K** (65.536) | `low/high` | ✅ |
262
+ | `qwen3.5-9b` (`ovh-free/Qwen3.5-9B`) | Alibaba Qwen | **256K** (262.144) | **64K** (65.536) | `low/high` | ✅ |
263
+ | `qwen3.6-27b` (`ovh-free/Qwen3.6-27B`) | Alibaba Qwen | **256K** (262.144) | **64K** (65.536) | `low/high` | ✅ |
264
+ | `qwen3.8-27b` (`ovh-free/Qwen3.8-27B`) | Alibaba Qwen | **256K** (262.144) | **32K** (32.768) | `low/high` | ✅ |
265
+ | `mistral-small-3.2` (`ovh-free/Mistral-Small-3.2-24B-Instruct-2506`) | Mistral AI | **128K** (131.072) | **16K** (16.384) | ❌ | ✅ |
266
+ | `mistral-7b-v0.3` (`ovh-free/Mistral-7B-Instruct-v0.3`) | Mistral AI | **64K** (65.536) | **64K** (65.536) | ❌ | ❌ |
267
+ | `llama-3.3-70b` (`ovh-free/Meta-Llama-3_3-70B-Instruct`) | Meta | **128K** (131.072) | **16K** (16.384) | ❌ | ❌ |
250
268
 
251
269
  ---
252
270
 
@@ -264,16 +282,16 @@ cat ~/.pi/agent/pi-freeflow.log | tail -n 50
264
282
 
265
283
  ### Design
266
284
 
267
- 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`).
285
+ This package stays thin. It ships three things: a model catalog, a relay proxy, and a log. There is no build step and one runtime dependency (`undici`). Thinking and prompt normalization stay with the host (`pi-ai`).
268
286
 
269
- About 19k lines including tests. The full suite (sandboxed, network-mocked) and typecheck pass before every release. See CHANGELOG.md.
287
+ About 43k lines including tests: `src/` is roughly 17k across 27 files, and the 78 test files add roughly 26k more. The full suite (sandboxed, network-mocked) and typecheck pass before every release. See CHANGELOG.md.
270
288
 
271
289
  ---
272
290
 
273
291
  ### FAQ
274
292
 
275
293
  **Do I need API keys?**
276
- No. Kilo uses a shared free credential and OpenCode free models need no header. You never paste a key. Cline free models need a browser login instead: `/freeflow cline login` saves it to a per-user pool on your machine.
294
+ No. OpenCode and Kilo free models are both keyless: the proxy sends no `Authorization` header at all, and a placeholder credential is rejected rather than merely unused — `Bearer kilo-free` answers `401 INVALID_TOKEN`, while sending nothing answers 200 for every free catalog model. You never paste a key. Cline free models need a browser login instead: `/freeflow cline login` saves it to a per-user pool on your machine. OVHcloud AI Endpoints models need no account and no key at all.
277
295
 
278
296
  **What if all relays hit rate limits?**
279
297
  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.
@@ -340,27 +358,42 @@ pnpm smoke # verifies extensions/index.ts loads without crashing
340
358
 
341
359
  ```
342
360
  src/
343
- ├── index.ts # extension entry, lifecycle hooks
344
- ├── models.ts # 30-model catalog definitions
345
- ├── catalog.ts # model catalog cache (24h disk)
346
- ├── proxy.ts # local proxy server (127.0.0.1:28180)
347
- ├── relay.ts # relay fetch, rolling on retryable failures
348
- ├── relay-state.ts # relay pool state, health tracking
349
- ├── stream-pipe.ts # SSE stream piping and truncation resilience
350
- ├── commands.ts # /freeflow CLI subcommands
351
- ├── deploy.ts # guided relay deploy (vercel/cloudflare/deno)
352
- ├── config.ts # constants, whitelists, paths, and runtime settings
353
- ├── logger.ts # file logger with 10MB rotation
354
- └── types.ts # shared type definitions
361
+ ├── index.ts # extension entry, lifecycle hooks
362
+ ├── models.ts # 37-model catalog definitions
363
+ ├── catalog.ts # model catalog cache (24h disk)
364
+ ├── proxy.ts # local proxy server (127.0.0.1:28180)
365
+ ├── client.ts # session-side daemon attach/spawn and heartbeat
366
+ ├── daemon.ts # detached proxy daemon process (owns the port)
367
+ ├── lease.ts # client lease registry and TTL retirement
368
+ ├── health.ts # loopback /_health relay snapshot
369
+ ├── responses.ts # Responses-API reasoning portability
370
+ ├── tool-translation.ts # tool reshape across chat/responses/messages
371
+ ├── tool-args.ts # schema-driven repair of model tool-call arguments
372
+ ├── relay.ts # relay fetch, rolling on retryable failures
373
+ ├── relay-state.ts # relay pool state, health tracking
374
+ ├── probe.ts # relay reachability and latency probe
375
+ ├── upstream-health.ts # Zen free-tier gating watch and Kilo failover
376
+ ├── stream-pipe.ts # SSE stream piping and truncation resilience
377
+ ├── opencode-fingerprint.ts # Zen free-tier client fingerprint enforcement
378
+ ├── system-ca-fetch.ts # OS-trust-store retry for intercepted TLS
379
+ ├── commands.ts # /freeflow CLI subcommands
380
+ ├── deploy.ts # guided relay deploy (vercel/cloudflare/deno)
381
+ ├── cline-accounts.ts # per-slot Cline key pool with failover
382
+ ├── cline-device-auth.ts # Cline WorkOS device-flow login
383
+ ├── update-checker.ts # npm registry version check, cached
384
+ ├── updater.ts # package-manager choice for /freeflow update
385
+ ├── config.ts # constants, whitelists, paths, and runtime settings
386
+ ├── logger.ts # file logger with 10MB rotation
387
+ └── types.ts # shared type definitions
355
388
  extensions/
356
- └── index.ts # OMP/Pi extension manifest
389
+ └── index.ts # OMP/Pi extension manifest
357
390
  test/
358
- └── *.test.ts # mirrors src/, node:test runner
391
+ └── *.test.ts # mirrors src/, node:test runner
359
392
  ```
360
393
 
361
394
  #### Guidelines
362
395
 
363
- - **Stay thin.** Zero runtime dependencies, no build step. If it belongs in the host (`pi-ai`), don't add it here.
396
+ - **Stay thin.** One runtime dependency (`undici`), no build step. If it belongs in the host (`pi-ai`), don't add it here.
364
397
  - **Test what you touch.** Every `src/*.ts` has a matching `test/*.test.ts`. Add or update tests for your change.
365
398
  - **Keep model IDs clean.** Slash-free, colon-free aliases for CLI compatibility. See existing patterns in `models.ts`.
366
399
  - **One concern per PR.** Bug fix? One PR. New relay platform? Separate PR. Easier to review, faster to merge.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pi-freeflow",
3
3
  "type": "module",
4
- "version": "1.34.0",
4
+ "version": "1.36.0",
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",
package/src/catalog.ts CHANGED
@@ -66,6 +66,15 @@ import type {
66
66
  * and responses from LLMs", not a chat model. Same exclusion class as
67
67
  * jev-1.13-free: live, wrong shape for an agentic harness, so it must never
68
68
  * re-enter the picker via disk cache or upstream merge.
69
+ * - cline-free/deepseek-v4.1-flash, cline-free/kimi-k3, cline-free/solar-pro4:
70
+ * retired upstream (2026-10-13) — probed live twice each against the real
71
+ * Cline pool, every attempt answered HTTP 404 `{"error":"model not found",
72
+ * "success":false,"hint":"Cline has no such model. Refresh the model list and
73
+ * retry."}`, while the two Cline models that survive (cline-free/
74
+ * muse-spark-1.3-contributor and z-ai/glm-5.3-flash) answered 200 with the
75
+ * same account and request shape. The lane is healthy; these three ids are
76
+ * gone, so they must never re-enter the picker from disk cache or an
77
+ * upstream merge.
69
78
  */
70
79
  export const DEAD_MODEL_IDS = new Set<string>([
71
80
  "jev-1.13-free",
@@ -93,6 +102,9 @@ export const DEAD_MODEL_IDS = new Set<string>([
93
102
  "fledge-alpha-free",
94
103
  "inclusionai/ling-3.0-flash-sante:free",
95
104
  "stepfun/step-3.7-flash:free",
105
+ "cline-free/deepseek-v4.1-flash",
106
+ "cline-free/kimi-k3",
107
+ "cline-free/solar-pro4",
96
108
  ]);
97
109
  /**
98
110
  * Free-tier allowlist for anything entering the picker via network or stale disk.
@@ -132,7 +144,7 @@ export function sanitizeCatalogModels(models: RegisteredModel[]): RegisteredMode
132
144
  }
133
145
  /**
134
146
  * In-memory cache of currently active/available free models.
135
- * Initialized with all 30 verified models for 0ms instant availability.
147
+ * Initialized with all 36 verified models for 0ms instant availability.
136
148
  */
137
149
  let aliveCatalog: RegisteredModel[] = ALL_MODELS.map((m) => ({
138
150
  ...m,
@@ -116,15 +116,17 @@ export const CLINE_CLIENT_VERSION = "3.5.54";
116
116
  * mirror reference/cline providers/request-headers.ts
117
117
  * (DEFAULT_CLINE_REQUEST_HEADERS) — no credential is derived from them.
118
118
  *
119
- * `X-CLIENT-TYPE` is the Cline desktop app's identity, and it is what the
120
- * free-model feed keys on (measured live 2026-09-22). The recommended-models
121
- * endpoint returns five free entries for `cline-sdk` / `cline-cli` / the
122
- * `VSCode Extension` label, but six for `cline-desktop` — the extra one being
123
- * `cline-free/kimi-k3`. The identity header alone flips that list
124
- * (`X-PLATFORM: Cline Desktop` does not; `X-CLIENT-TYPE` decides), and the
125
- * sixth model serves live chat completions (HTTP 200 + SSE) for the saved
126
- * per-user login under either identity. Version and User-Agent stay as-is:
127
- * the feed serves the six-model list with them unchanged.
119
+ * `X-CLIENT-TYPE` is the Cline desktop app's identity, and it gates the
120
+ * `cline-free/*` id space (measured live 2026-09-22: that prefix answers 403
121
+ * "only available via Cline product surfaces" with a bare bearer, and 200 with
122
+ * this set; every non-prefixed id answers 200 either way). The header is kept
123
+ * because one catalog id still depends on it — after the 2026-10-13 prune,
124
+ * `cline-free/muse-spark-1.3-contributor` is the last prefixed model in the
125
+ * catalog. It also decided the free-model feed at the time: five entries for
126
+ * `cline-sdk` / `cline-cli` / the `VSCode Extension` label against six for
127
+ * `cline-desktop`, the extra one being `cline-free/kimi-k3`. That sixth model
128
+ * is retired upstream and no longer requested. Version and User-Agent stay
129
+ * as-is: the feed served the desktop list with them unchanged.
128
130
  */
129
131
  export const CLINE_CLIENT_HEADERS: Record<string, string> = {
130
132
  "HTTP-Referer": "https://cline.bot",
@@ -138,12 +140,12 @@ export const CLINE_CLIENT_HEADERS: Record<string, string> = {
138
140
  /**
139
141
  * Free-limit report carried by a Cline 429 body, e.g.
140
142
  * {"error":{"code":"INFERENCE_CAP_ERROR","message":"Error 429: Daily free limit
141
- * reached on model deepseek/deepseek-v4.1-flash. Try again in 20h 4m"}}.
143
+ * reached on model meta/muse-spark-1.3-contributor. Try again in 20h 4m"}}.
142
144
  *
143
145
  * `modelId` is the name Cline spells in its own body, which is a different
144
- * namespace from the id this proxy requests (measured live 2026-09-22: we ask
145
- * for `cline-free/deepseek-v4.1-flash`, Cline answers about
146
- * `deepseek/deepseek-v4.1-flash`). The limit cache is therefore keyed by the
146
+ * namespace from the id this proxy requests (measured live 2026-10-13: we ask
147
+ * for `cline-free/muse-spark-1.3-contributor`, Cline answers about
148
+ * `meta/muse-spark-1.3-contributor`). The limit cache is therefore keyed by the
147
149
  * requested id; `modelId` is diagnostics only.
148
150
  */
149
151
  export interface ClineFreeLimit {
package/src/config.ts CHANGED
@@ -31,6 +31,17 @@ export const OPENCODE_API_URL = `${UPSTREAM_OPENCODE}/v1`;
31
31
  // supplied at call time (never stored here).
32
32
  export const CLINE_API_BASE = "https://api.cline.bot/api/v1";
33
33
  export const CLINE_CHAT_URL = `${CLINE_API_BASE}/chat/completions`;
34
+ // OVHcloud AI Endpoints serves OpenAI-compatible chat completions with no
35
+ // credential at all (probed keyless 2026-10-13: no Authorization header,
36
+ // 200). Direct-only: OVH has no Zen-style per-IP gate to route around, so
37
+ // it never rides the relay pool and is deliberately absent from the deployed
38
+ // relay allowlist (src/deploy.ts), which keeps the relay surface at exactly
39
+ // two upstreams. Chat-only: OVH's responses endpoint rejects every array
40
+ // input shape with 422 "input: data did not match any variant of untagged
41
+ // enum ResponseInput" and accepts only a bare string (probed 2026-10-13), so
42
+ // a responses-path caller is translated to chat upstream and back.
43
+ export const OVH_API_BASE = "https://oai.endpoints.kepler.ai.cloud.ovh.net/v1";
44
+ export const OVH_CHAT_URL = `${OVH_API_BASE}/chat/completions`;
34
45
 
35
46
  // ── Network & Server defaults ───────────────────────────────────────
36
47
  export const DEFAULT_PORT = 28180;
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 30 free models (10 OpenCode Zen + 15 KiloCode Gateway + 5 Cline) with:
4
+ * Provides access to 37 free models (11 OpenCode Zen + 15 KiloCode Gateway + 2 Cline + 9 OVH) 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
@@ -126,7 +126,7 @@ export function buildProviderConfig(
126
126
  id: m.id,
127
127
  name: m.name,
128
128
  api: m.api,
129
- owned_by: m.source === "kilo" ? "kilocode" : m.source === "cline" ? "clinecode" : "opencode",
129
+ owned_by: m.source === "kilo" ? "kilocode" : m.source === "cline" ? "clinecode" : m.source === "ovh" ? "ovhcloud" : "opencode",
130
130
  reasoning: m.reasoning,
131
131
  thinking: m.reasoning
132
132
  ? {
@@ -146,7 +146,7 @@ export function buildProviderConfig(
146
146
  }
147
147
  : m.api === "openai-responses"
148
148
  ? { sessionAffinityFormat: "openai-nosession" }
149
- : m.source === "kilo" || m.source === "cline"
149
+ : m.source === "kilo" || m.source === "cline" || m.source === "ovh"
150
150
  ? {
151
151
  supportsDeveloperRole: false,
152
152
  supportsReasoningEffort: !!m.thinkingLevelMap,