pi-freeflow 1.33.3 → 1.35.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,71 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.35.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 9085408: Nine more free models, from OVHcloud's AI Endpoints — and no account needed
8
+
9
+ 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.
10
+
11
+ 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.
12
+
13
+ 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.
14
+
15
+ 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.
16
+
17
+ ### Patch Changes
18
+
19
+ - 3408dad: Stop conversations from dying on request shapes the provider rejects
20
+
21
+ Three shapes that the provider answers with `400 invalid parameters` are now reshaped on the way out instead of failing the whole turn.
22
+
23
+ - **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.
24
+ - **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.
25
+ - **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.
26
+
27
+ 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.
28
+
29
+ - 9085408: Three free models that no longer answer are gone from the picker
30
+
31
+ `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).
32
+
33
+ ## 1.34.0
34
+
35
+ ### Minor Changes
36
+
37
+ - aa6f259: Three new free models, picked the same way as the rest (`/model` → `freeflow` → pick):
38
+
39
+ - **Step 5 Preview** on OpenCode Zen (`step-5-preview-free`, short name `step-5-preview`) — 1M context, answers with vision.
40
+ - **Step 5 Preview** on KiloCode (`stepfun/step-5-preview-free`, short name `step-5-preview:kilo`) — 1M context, answers with vision.
41
+ - **Glyph Cluster** on KiloCode (`stealth/glyph-cluster`, short name `glyph-cluster`) — 256K context, text answers.
42
+
43
+ ### Patch Changes
44
+
45
+ - 50981fb: Align nine model entries with the specs their upstream catalogs publish. Models now advertise video input where the vendor lists it, two entries pick up a larger context window, and Step 5 Preview on KiloCode reports the full 64K output allowance.
46
+ - f637c58: Recover tool calls that arrive with the tail of the previous call stuck to the
47
+ front. Some models open a new call by echoing the end of the one they have just
48
+ seen, so a single call is delivered as `<tail of previous>{"…this call…"}` and
49
+ the host refuses it as invalid JSON. When such a payload does not parse, the
50
+ proxy now locates the complete call behind the stray text and hands that back.
51
+
52
+ Only payloads that already fail to parse are rescanned, and only a position that
53
+ yields a complete object is accepted — a well-formed call is never rewritten,
54
+ and a truncated one is still refused rather than completed.
55
+
56
+ Also adds a whole-inventory fidelity test covering every tool either host can
57
+ declare, across all three API shapes.
58
+
59
+ - aa6f259: Remove three free models that stopped serving upstream, so they no longer appear in the model list:
60
+
61
+ - **Fledge Alpha** on OpenCode (`fledge-alpha-free`) — withdrawn upstream and no longer listed.
62
+ - **Ling 3.0 Flash Sante** on KiloCode (`inclusionai/ling-3.0-flash-sante:free`) — the free variant is gone; only the paid one remains.
63
+ - **Step 3.7 Flash** on KiloCode (`stepfun/step-3.7-flash:free`) — the free variant is gone; only the paid one remains.
64
+
65
+ All three are excluded permanently, so a stale on-disk catalog or a later catalog refresh cannot bring them back.
66
+
67
+ - 50981fb: Correct the OpenCode Zen Step 5 Preview entry: it is a reasoning model with 1M context, 64K max output, text/image/video input, and only `low`/`medium`/`high` thinking levels (`minimal` is explicitly disabled). Previously the entry mirrored the Kilo sibling and the fallback heuristic, so the picker showed no thinking support.
68
+
3
69
  ## 1.33.3
4
70
 
5
71
  ### Patch 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
+ > 36 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
+ | **36 free models** | 10 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,7 +185,7 @@ The same command set works identically in OMP and Pi:
185
185
 
186
186
  ---
187
187
 
188
- ### 30 models, one command
188
+ ### 36 models, one command
189
189
 
190
190
  ```bash
191
191
  /model → freeflow → pick
@@ -205,10 +205,10 @@ Good defaults for long coding sessions and agentic work.
205
205
  | `big-pickle` | Big Pickle | **200K** (200.000) | **32K** (32.000) | `high / max` | ❌ |
206
206
  | `space-bunny-free` | Stealth preview (lab undisclosed) | **1M** (1.048.576) | **512K** (524.288) | `low … max` | ✅ |
207
207
  | `longcat-2.5-preview-free` | Meituan LongCat | **1M** (1.000.000) | **131K** (131.072) | `minimal … max` | ✅ |
208
- | `fledge-alpha-free` | Stealth preview (lab undisclosed) | **1M** (1.048.576) | **131K** (131.072) | `low / high / max` | ✅ |
208
+ | `step-5-preview-free` | StepFun | **1M** (1.000.000) | **64K** (65.536) | `low … high` | ✅ |
209
209
  | `ling-3.1-flash-free` | Inclusion AI | **262K** (262.144) | **32K** (32.768) | `minimal … max` | ❌ |
210
210
 
211
- #### KiloCode Gateway (16 models), OpenRouter compatible
211
+ #### KiloCode Gateway (15 models), OpenRouter compatible
212
212
 
213
213
  Keyless access. Short aliases work for every row (the full ID is in parentheses).
214
214
 
@@ -225,14 +225,14 @@ Keyless access. Short aliases work for every row (the full ID is in parentheses)
225
225
  | `lfm-2.5` (`liquid/lfm-2.5-2.6b:free`) | Liquid AI | **65K** (65.536) | **32K** (32.768) | `minimal…xhigh`\* | ❌ |
226
226
  | `kilo-auto` (`kilo-auto/free`) | Kilo Gateway Auto | **256K** (256.000) | **10K** (10.000) | `minimal…xhigh`\* | ❌ |
227
227
  | `openrouter` (`openrouter/free`) | OpenRouter Free | **200K** (200.000) | **65K** (65.536) | `minimal…xhigh`\* | ✅ |
228
- | `ling-3.0-flash-sante` (`inclusionai/ling-3.0-flash-sante:free`) | Inclusion AI | **262K** (262.144) | **32K** (32.768) | `minimal…xhigh`\* | ❌ |
229
- | `step-3.7-flash` (`stepfun/...:free`) | StepFun | **262K** (262.144) | **262K** (262.144) | `minimal…xhigh`\* | ✅ |
228
+ | `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** (65.536) | `minimal…xhigh`\* | ✅ |
230
230
  | `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`\* | ❌ |
231
+ | `ling-3.1-flash:kilo` (`inclusionai/ling-3.1-flash`) | Inclusion AI | **262K** (262.144) | **32K** (32.768) | `minimal…xhigh`\* | ❌ |
232
232
 
233
233
  \* 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
234
 
235
- #### Cline (5 models), OpenAI compatible
235
+ #### Cline (2 models), OpenAI compatible
236
236
 
237
237
  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
238
 
@@ -242,11 +242,28 @@ Each account can only be saved once: an extra login for an account you already h
242
242
 
243
243
  | Model ID | Creator / Lab | Context | Max Output | Thinking | Vision |
244
244
  | :--- | :--- | :--- | :--- | :--- | :--- |
245
- | `cline-free/deepseek-v4.1-flash` | DeepSeek | **1M** (1.000.000) | **384K** (384.000) | `low/high/max` | ✅ |
246
245
  | `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`\* | ❌ |
246
+ | `z-ai/glm-5.3-flash` | Zhipu AI | **1M** (1.048.576) | **131K** (131.072) | `low/high/max` | ✅ |
247
+
248
+ #### OVHcloud AI Endpoints (9 models), OpenAI compatible
249
+
250
+ 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.
251
+
252
+ 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.
253
+
254
+ 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.
255
+
256
+ | Model ID | Creator / Lab | Context | Max Output | Thinking | Vision |
257
+ | :--- | :--- | :--- | :--- | :--- | :--- |
258
+ | `gpt-oss-120b` (`ovh-free/gpt-oss-120b`) | OpenAI | **128K** (131.072) | **32K** (32.768) | `low/high` | ❌ |
259
+ | `gpt-oss-20b` (`ovh-free/gpt-oss-20b`) | OpenAI | **128K** (131.072) | **32K** (32.768) | `low/high` | ❌ |
260
+ | `qwen3.5-397b` (`ovh-free/Qwen3.5-397B-A17B`) | Alibaba Qwen | **256K** (262.144) | **64K** (65.536) | `low/high` | ✅ |
261
+ | `qwen3.5-9b` (`ovh-free/Qwen3.5-9B`) | Alibaba Qwen | **256K** (262.144) | **64K** (65.536) | `low/high` | ✅ |
262
+ | `qwen3.6-27b` (`ovh-free/Qwen3.6-27B`) | Alibaba Qwen | **256K** (262.144) | **64K** (65.536) | `low/high` | ✅ |
263
+ | `qwen3.8-27b` (`ovh-free/Qwen3.8-27B`) | Alibaba Qwen | **256K** (262.144) | **32K** (32.768) | `low/high` | ✅ |
264
+ | `mistral-small-3.2` (`ovh-free/Mistral-Small-3.2-24B-Instruct-2506`) | Mistral AI | **128K** (131.072) | **16K** (16.384) | ❌ | ✅ |
265
+ | `mistral-7b-v0.3` (`ovh-free/Mistral-7B-Instruct-v0.3`) | Mistral AI | **64K** (65.536) | **64K** (65.536) | ❌ | ❌ |
266
+ | `llama-3.3-70b` (`ovh-free/Meta-Llama-3_3-70B-Instruct`) | Meta | **128K** (131.072) | **16K** (16.384) | ❌ | ❌ |
250
267
 
251
268
  ---
252
269
 
@@ -264,16 +281,16 @@ cat ~/.pi/agent/pi-freeflow.log | tail -n 50
264
281
 
265
282
  ### Design
266
283
 
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`).
284
+ 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
285
 
269
- About 19k lines including tests. The full suite (sandboxed, network-mocked) and typecheck pass before every release. See CHANGELOG.md.
286
+ 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
287
 
271
288
  ---
272
289
 
273
290
  ### FAQ
274
291
 
275
292
  **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.
293
+ 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
294
 
278
295
  **What if all relays hit rate limits?**
279
296
  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 +357,42 @@ pnpm smoke # verifies extensions/index.ts loads without crashing
340
357
 
341
358
  ```
342
359
  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
360
+ ├── index.ts # extension entry, lifecycle hooks
361
+ ├── models.ts # 36-model catalog definitions
362
+ ├── catalog.ts # model catalog cache (24h disk)
363
+ ├── proxy.ts # local proxy server (127.0.0.1:28180)
364
+ ├── client.ts # session-side daemon attach/spawn and heartbeat
365
+ ├── daemon.ts # detached proxy daemon process (owns the port)
366
+ ├── lease.ts # client lease registry and TTL retirement
367
+ ├── health.ts # loopback /_health relay snapshot
368
+ ├── responses.ts # Responses-API reasoning portability
369
+ ├── tool-translation.ts # tool reshape across chat/responses/messages
370
+ ├── tool-args.ts # schema-driven repair of model tool-call arguments
371
+ ├── relay.ts # relay fetch, rolling on retryable failures
372
+ ├── relay-state.ts # relay pool state, health tracking
373
+ ├── probe.ts # relay reachability and latency probe
374
+ ├── upstream-health.ts # Zen free-tier gating watch and Kilo failover
375
+ ├── stream-pipe.ts # SSE stream piping and truncation resilience
376
+ ├── opencode-fingerprint.ts # Zen free-tier client fingerprint enforcement
377
+ ├── system-ca-fetch.ts # OS-trust-store retry for intercepted TLS
378
+ ├── commands.ts # /freeflow CLI subcommands
379
+ ├── deploy.ts # guided relay deploy (vercel/cloudflare/deno)
380
+ ├── cline-accounts.ts # per-slot Cline key pool with failover
381
+ ├── cline-device-auth.ts # Cline WorkOS device-flow login
382
+ ├── update-checker.ts # npm registry version check, cached
383
+ ├── updater.ts # package-manager choice for /freeflow update
384
+ ├── config.ts # constants, whitelists, paths, and runtime settings
385
+ ├── logger.ts # file logger with 10MB rotation
386
+ └── types.ts # shared type definitions
355
387
  extensions/
356
- └── index.ts # OMP/Pi extension manifest
388
+ └── index.ts # OMP/Pi extension manifest
357
389
  test/
358
- └── *.test.ts # mirrors src/, node:test runner
390
+ └── *.test.ts # mirrors src/, node:test runner
359
391
  ```
360
392
 
361
393
  #### Guidelines
362
394
 
363
- - **Stay thin.** Zero runtime dependencies, no build step. If it belongs in the host (`pi-ai`), don't add it here.
395
+ - **Stay thin.** One runtime dependency (`undici`), no build step. If it belongs in the host (`pi-ai`), don't add it here.
364
396
  - **Test what you touch.** Every `src/*.ts` has a matching `test/*.test.ts`. Add or update tests for your change.
365
397
  - **Keep model IDs clean.** Slash-free, colon-free aliases for CLI compatibility. See existing patterns in `models.ts`.
366
398
  - **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.33.3",
4
+ "version": "1.35.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
@@ -30,7 +30,8 @@ import type {
30
30
 
31
31
  /**
32
32
  * Pruned model IDs that must never re-enter the catalog via disk cache or upstream merge.
33
- * - jev-1.13-free: non-chat decision model, chat-incompatible (live chat 500) — never registered.
33
+ * - jev-1.13-free: non-chat decision model, chat-incompatible — never registered.
34
+ * Re-confirmed 2026-10-09: 400 through the plugin while every catalog model 200s.
34
35
  * - deepseek-v4-flash-free: listed but unserved upstream (live chat 400 "Model is unavailable").
35
36
  * - nex-agi/nex-n2.5-pro:free + nex-agi/nex-n2.5-mini:free: gone 2026-09-28 — zero nex-agi
36
37
  * IDs on the live Kilo list, keyless chat 404 "does not exist".
@@ -43,7 +44,18 @@ import type {
43
44
  * - inclusionai/ling-3.0-flash-fin:free: gone from Kilo (2026-10-01) — keyless chat 404
44
45
  * "The requested model ... does not exist".
45
46
  * - mimo-v2.5-free: decommissioned upstream (2026-10-07) — HTTP 401 "Model mimo-v2.5-free is not supported".
46
- * - exo-free: unserved upstream (2026-10-07) — HTTP 503 "Error from provider (Console): Upstream request failed: Endpoint is unavailable.".
47
+ * - exo-free: deprecated upstream (2026-10-09) — HTTP 410 "Model exo-free has
48
+ * been deprecated." (was 503 "Endpoint is unavailable" on 2026-10-07).
49
+ * - fledge-alpha-free: withdrawn upstream (2026-10-09) — absent from the live
50
+ * Zen list, chat 401 "Model fledge-alpha-free is not supported".
51
+ * - inclusionai/ling-3.0-flash-sante:free: demoted to paid on Kilo (2026-10-09) —
52
+ * :free ID gone from the live list, keyless chat 404 "does not exist";
53
+ * only the paid counterpart remains.
54
+ * - stepfun/step-3.7-flash:free: demoted to paid on Kilo (2026-10-09) — same
55
+ * shape: :free ID gone, keyless 404; paid ID remains.
56
+ * - meituan/longcat-2.0-free: demoted to paid on Kilo (2026-10-09) —
57
+ * `meituan/longcat-2.0` remains live with isFree:false; keyless chat
58
+ * answers 401 PAID_MODEL_AUTH_REQUIRED.
47
59
  * - stealth/space-bunny-alpha: gone from Kilo (2026-10-07) — keyless chat 404 "The requested model ... does not exist".
48
60
  * - qwen/qwen3.8-27b:free: gone from Kilo (2026-10-07) — keyless chat 404 "The requested model is currently unavailable.".
49
61
  * - nvidia/nemotron-3.5-content-safety:free: tool-less guardrail model (2026-10-08),
@@ -54,6 +66,15 @@ import type {
54
66
  * and responses from LLMs", not a chat model. Same exclusion class as
55
67
  * jev-1.13-free: live, wrong shape for an agentic harness, so it must never
56
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.
57
78
  */
58
79
  export const DEAD_MODEL_IDS = new Set<string>([
59
80
  "jev-1.13-free",
@@ -78,6 +99,12 @@ export const DEAD_MODEL_IDS = new Set<string>([
78
99
  "stealth/space-bunny-alpha",
79
100
  "qwen/qwen3.8-27b:free",
80
101
  "nvidia/nemotron-3.5-content-safety:free",
102
+ "fledge-alpha-free",
103
+ "inclusionai/ling-3.0-flash-sante:free",
104
+ "stepfun/step-3.7-flash:free",
105
+ "cline-free/deepseek-v4.1-flash",
106
+ "cline-free/kimi-k3",
107
+ "cline-free/solar-pro4",
81
108
  ]);
82
109
  /**
83
110
  * Free-tier allowlist for anything entering the picker via network or stale disk.
@@ -117,7 +144,7 @@ export function sanitizeCatalogModels(models: RegisteredModel[]): RegisteredMode
117
144
  }
118
145
  /**
119
146
  * In-memory cache of currently active/available free models.
120
- * Initialized with all 30 verified models for 0ms instant availability.
147
+ * Initialized with all 36 verified models for 0ms instant availability.
121
148
  */
122
149
  let aliveCatalog: RegisteredModel[] = ALL_MODELS.map((m) => ({
123
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 36 free models (10 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,