pi-freeflow 1.38.2 → 1.38.3
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 +6 -0
- package/README.md +6 -7
- package/package.json +1 -1
- package/src/catalog.ts +7 -1
- package/src/models.ts +17 -38
- package/src/stream-pipe.ts +49 -14
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.38.3
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Absorb tool-call argument fragments arriving on terminal finish_reason chunks into buffered prefixes to prevent argument rotation and corrupted JSON loops. Add Reflection AI's Beam Free (1M context) to the OpenCode Zen lineup, and retire deprecated LL Alpha and Muse Spark 1.3 contributor free models.
|
|
8
|
+
|
|
3
9
|
## 1.38.2
|
|
4
10
|
|
|
5
11
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# pi-freeflow
|
|
2
2
|
|
|
3
|
-
>
|
|
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,7 +16,7 @@ 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
|
-
| **
|
|
19
|
+
| **36 free models** | 13 from OpenCode Zen, 13 from KiloCode Gateway, 2 from Cline, 8 from OVHcloud AI Endpoints, context windows up to 1M. Full list below. | **$0** |
|
|
20
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
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** |
|
|
@@ -197,14 +197,14 @@ The same command set works identically in OMP and Pi:
|
|
|
197
197
|
|
|
198
198
|
---
|
|
199
199
|
|
|
200
|
-
###
|
|
200
|
+
### 36 models, one command
|
|
201
201
|
|
|
202
202
|
```bash
|
|
203
203
|
/model → freeflow → pick
|
|
204
204
|
```
|
|
205
205
|
|
|
206
206
|
Every model specification is reconciled against [models.dev](https://models.dev/), [OpenRouter](https://openrouter.ai/), and OMP's built-in catalog, configured with the highest verified context, output ceiling, and reasoning capabilities across twin models.
|
|
207
|
-
#### OpenCode Zen (
|
|
207
|
+
#### OpenCode Zen (13 models), Responses and Chat API
|
|
208
208
|
|
|
209
209
|
Good defaults for long coding sessions and agentic work.
|
|
210
210
|
|
|
@@ -212,7 +212,6 @@ Good defaults for long coding sessions and agentic work.
|
|
|
212
212
|
| :--- | :--- | :--- | :--- | :--- | :--- |
|
|
213
213
|
| `cat-jam-free` | Cat Jam | **256K** (262.144) | **131K** (131.072) | `low … max` | ❌ |
|
|
214
214
|
| `muse-spark-1.2-contributor-free` | Meta Superintelligence Labs | **1M** (1.048.576) | **131K** (131.072) | `minimal … xhigh` | ✅ |
|
|
215
|
-
| `muse-spark-1.3-contributor-free` | Meta Superintelligence Labs | **1M** (1.048.576) | **131K** (131.072) | `minimal … xhigh` | ✅ |
|
|
216
215
|
| `mimo-v2.6-flash-free` | Xiaomi MiMo | **1M** (1.048.576) | **131K** (131.072) | `minimal … xhigh`\* | ✅ |
|
|
217
216
|
| `nemotron-3.5-lightning-free` | NVIDIA | **1M** (1.000.000) | **262K** (262.144) | `minimal … xhigh` | ❌ |
|
|
218
217
|
| `nemotron-3.5-super-vl-free` | NVIDIA | **1M** (1.000.000) | **131K** (131.072) | `minimal … xhigh` | ✅ |
|
|
@@ -221,7 +220,7 @@ Good defaults for long coding sessions and agentic work.
|
|
|
221
220
|
| `space-bunny-free` | Stealth preview (lab undisclosed) | **1M** (1.048.576) | **512K** (524.288) | `low … max` | ✅ |
|
|
222
221
|
| `longcat-2.5-preview-free` | Meituan LongCat | **1M** (1.000.000) | **131K** (131.072) | `minimal … max` | ✅ |
|
|
223
222
|
| `glm-5.3-flash-free` | Zhipu AI | **1M** (1.000.000) | **32K** (32.000) | `minimal … max` | ✅ |
|
|
224
|
-
| `
|
|
223
|
+
| `beam-free` | Reflection AI | **1M** (1.048.576) | **131K** (131.072) | `low … max` | ❌ |
|
|
225
224
|
| `exo-free` | Undisclosed | **1M** (1.048.576) | **131K** (131.072) | `high` | ✅ |
|
|
226
225
|
| `deepseek-v4.1-flash-free` | DeepSeek | **1M** (1.000.000) | **384K** (384.000) | `minimal … max` | ✅ |
|
|
227
226
|
|
|
@@ -368,7 +367,7 @@ pnpm smoke # verifies extensions/index.ts loads without crashing
|
|
|
368
367
|
#### Project structure
|
|
369
368
|
|
|
370
369
|
```
|
|
371
|
-
├── models.ts #
|
|
370
|
+
├── models.ts # 36-model catalog definitions
|
|
372
371
|
├── index.ts # extension entry, lifecycle hooks
|
|
373
372
|
├── catalog.ts # model catalog cache (24h disk)
|
|
374
373
|
├── proxy.ts # local proxy server (127.0.0.1:28180)
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-freeflow",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.38.
|
|
4
|
+
"version": "1.38.3",
|
|
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
|
@@ -124,6 +124,12 @@ export const DEAD_MODEL_IDS = new Set<string>([
|
|
|
124
124
|
// answers 401 PAID_MODEL_AUTH_REQUIRED while the sibling z-ai/glm-5.3-flash
|
|
125
125
|
// answers 200 keyless with the same request shape.
|
|
126
126
|
"stepfun/step-5-preview-free",
|
|
127
|
+
// ll-alpha-free: decommissioned upstream (2026-10-17) — gone from live
|
|
128
|
+
// Zen /v1/models list, answers HTTP 410 "Model ll-alpha-free has been deprecated".
|
|
129
|
+
"ll-alpha-free",
|
|
130
|
+
// muse-spark-1.3-contributor-free: decommissioned upstream (2026-10-17) — gone from
|
|
131
|
+
// live Zen /v1/models list, answers HTTP 410 "Model muse-spark-1.3-contributor-free has been deprecated".
|
|
132
|
+
"muse-spark-1.3-contributor-free",
|
|
127
133
|
]);
|
|
128
134
|
/**
|
|
129
135
|
* Free-tier allowlist for anything entering the picker via network or stale disk.
|
|
@@ -163,7 +169,7 @@ export function sanitizeCatalogModels(models: RegisteredModel[]): RegisteredMode
|
|
|
163
169
|
}
|
|
164
170
|
/**
|
|
165
171
|
* In-memory cache of currently active/available free models.
|
|
166
|
-
* Initialized with all
|
|
172
|
+
* Initialized with all 36 verified models for 0ms instant availability.
|
|
167
173
|
*/
|
|
168
174
|
let aliveCatalog: RegisteredModel[] = ALL_MODELS.map((m) => ({
|
|
169
175
|
...m,
|
package/src/models.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Static model definitions and upstream routing catalogs for pi-freeflow
|
|
3
3
|
*
|
|
4
|
-
* Defines the
|
|
5
|
-
* -
|
|
4
|
+
* Defines the 36 verified free models (live-verified 2026-10-17):
|
|
5
|
+
* - 13 OpenCode Zen models (1 Responses API + 12 Chat Completions)
|
|
6
6
|
* - 13 KiloCode Keyless Gateway models (OpenRouter format)
|
|
7
7
|
* - 2 Cline direct-only models (per-user pool)
|
|
8
8
|
* - 8 OVHcloud AI Endpoints models (keyless, direct-only)
|
|
@@ -59,24 +59,6 @@ export const OPENCODE_MODELS: ModelDef[] = [
|
|
|
59
59
|
max: null,
|
|
60
60
|
},
|
|
61
61
|
},
|
|
62
|
-
{
|
|
63
|
-
id: "muse-spark-1.3-contributor-free",
|
|
64
|
-
name: "Muse Spark 1.3 [OpenCode]",
|
|
65
|
-
reasoning: true,
|
|
66
|
-
contextWindow: 1_048_576,
|
|
67
|
-
maxTokens: 131_072,
|
|
68
|
-
api: "openai-responses",
|
|
69
|
-
input: ["text", "image", "video"],
|
|
70
|
-
thinkingLevelMap: {
|
|
71
|
-
off: null,
|
|
72
|
-
minimal: "minimal",
|
|
73
|
-
low: "low",
|
|
74
|
-
medium: "medium",
|
|
75
|
-
high: "high",
|
|
76
|
-
xhigh: "xhigh",
|
|
77
|
-
max: null,
|
|
78
|
-
},
|
|
79
|
-
},
|
|
80
62
|
{
|
|
81
63
|
id: "mimo-v2.6-flash-free",
|
|
82
64
|
name: "MiMo V2.6 Flash [OpenCode]",
|
|
@@ -251,23 +233,20 @@ export const OPENCODE_MODELS: ModelDef[] = [
|
|
|
251
233
|
},
|
|
252
234
|
},
|
|
253
235
|
{
|
|
254
|
-
// Added 2026-10-
|
|
255
|
-
//
|
|
256
|
-
//
|
|
257
|
-
//
|
|
258
|
-
//
|
|
259
|
-
//
|
|
260
|
-
//
|
|
261
|
-
//
|
|
262
|
-
//
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
// produced no answer.
|
|
266
|
-
id: "ll-alpha-free",
|
|
267
|
-
name: "LL Alpha [OpenCode]",
|
|
236
|
+
// Added 2026-10-17: Reflection AI's Beam 501B open-weight MoE model (23B active),
|
|
237
|
+
// added as a limited-time free model on OpenCode Zen (/zen/v1/models: beam-free).
|
|
238
|
+
// Live-probed 2026-10-17: 200 with stream:true and tool sextet.
|
|
239
|
+
// Context window: 1_048_576 tokens (1M), maxTokens: 131_072.
|
|
240
|
+
// Probed boundary: filler up to 900,000 words (~1.1M tokens) answers 200.
|
|
241
|
+
// Input: text-only (image probe answers 400 "Beam supports text input only").
|
|
242
|
+
// Wire format: Chat Completions (/v1/responses answers 400 ModelProtocolUnsupported).
|
|
243
|
+
// Reasoning effort ladder: minimal is rejected with 400 (unsupported_value),
|
|
244
|
+
// low/medium/high/xhigh/max all answer 200 with reasoning.
|
|
245
|
+
id: "beam-free",
|
|
246
|
+
name: "Beam Free [OpenCode]",
|
|
268
247
|
reasoning: true,
|
|
269
|
-
contextWindow:
|
|
270
|
-
maxTokens:
|
|
248
|
+
contextWindow: 1_048_576,
|
|
249
|
+
maxTokens: 131_072,
|
|
271
250
|
input: ["text"],
|
|
272
251
|
thinkingLevelMap: {
|
|
273
252
|
off: null,
|
|
@@ -722,7 +701,7 @@ export const MODEL_ALIASES: Record<string, string> = {
|
|
|
722
701
|
"space-bunny": "space-bunny-free",
|
|
723
702
|
"longcat-2.5-preview": "longcat-2.5-preview-free",
|
|
724
703
|
"longcat": "longcat-2.5-preview-free",
|
|
725
|
-
"
|
|
704
|
+
"beam": "beam-free",
|
|
726
705
|
"deepseek-v4.1-flash": "deepseek-v4.1-flash-free",
|
|
727
706
|
// provider-prefixed short aliases (slash-normalized)
|
|
728
707
|
"laguna-s-2.1:free": "poolside/laguna-s-2.1:free",
|
|
@@ -777,7 +756,7 @@ export const OVH_MODEL_IDS = new Set<string>([
|
|
|
777
756
|
.map(([alias]) => alias),
|
|
778
757
|
]);
|
|
779
758
|
/**
|
|
780
|
-
* Combined list of all
|
|
759
|
+
* Combined list of all 36 static free models (canonical)
|
|
781
760
|
*/
|
|
782
761
|
export const ALL_MODELS: ModelDef[] = [...OPENCODE_MODELS, ...KILO_MODELS, ...CLINE_MODELS, ...OVH_MODELS];
|
|
783
762
|
|
package/src/stream-pipe.ts
CHANGED
|
@@ -442,6 +442,53 @@ function cloakStreamResponsesObject(resp: unknown, cloak: StreamCloakOptions): v
|
|
|
442
442
|
(resp as Record<string, unknown>).output = kept;
|
|
443
443
|
}
|
|
444
444
|
|
|
445
|
+
/**
|
|
446
|
+
* Terminal chunk for chat choice: absorb any tool-call argument fragment
|
|
447
|
+
* riding the finish_reason chunk into the buffered prefix, then re-emit every
|
|
448
|
+
* buffered tool call's whole argument packet, repaired.
|
|
449
|
+
* Returns true if delta was mutated.
|
|
450
|
+
*/
|
|
451
|
+
function flushChatTerminalToolCalls(
|
|
452
|
+
d: Record<string, unknown>,
|
|
453
|
+
state: SseStreamCloakState,
|
|
454
|
+
cloak: StreamCloakOptions,
|
|
455
|
+
flushedIndices: Set<number>,
|
|
456
|
+
): boolean {
|
|
457
|
+
if (state.chatArgsByIndex.size === 0) return false;
|
|
458
|
+
|
|
459
|
+
for (const tc of Array.isArray(d.tool_calls) ? d.tool_calls : []) {
|
|
460
|
+
if (!tc || typeof tc !== "object" || Array.isArray(tc)) continue;
|
|
461
|
+
const rec = tc as Record<string, unknown>;
|
|
462
|
+
const idx = typeof rec.index === "number" ? rec.index : 0;
|
|
463
|
+
const fn = rec.function;
|
|
464
|
+
const fnRec = fn && typeof fn === "object" && !Array.isArray(fn) ? (fn as Record<string, unknown>) : null;
|
|
465
|
+
if (fnRec && state.chatArgsByIndex.has(idx) && typeof fnRec.arguments === "string") {
|
|
466
|
+
state.chatArgsByIndex.set(idx, (state.chatArgsByIndex.get(idx) ?? "") + fnRec.arguments);
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
const flushed: unknown[] = [];
|
|
471
|
+
for (const [idx, args] of state.chatArgsByIndex) {
|
|
472
|
+
const name = state.chatNameByIndex.get(idx);
|
|
473
|
+
if (name === undefined) continue;
|
|
474
|
+
flushedIndices.add(idx);
|
|
475
|
+
flushed.push({ index: idx, type: "function", function: { name, arguments: repairToolArguments(name, args, cloak.argSchemas) } });
|
|
476
|
+
}
|
|
477
|
+
state.chatArgsByIndex.clear();
|
|
478
|
+
state.chatNameByIndex.clear();
|
|
479
|
+
|
|
480
|
+
if (flushed.length === 0) return false;
|
|
481
|
+
|
|
482
|
+
const remaining = (Array.isArray(d.tool_calls) ? d.tool_calls : []).filter((tc) => {
|
|
483
|
+
if (!tc || typeof tc !== "object" || Array.isArray(tc)) return true;
|
|
484
|
+
const rec = tc as Record<string, unknown>;
|
|
485
|
+
const idx = typeof rec.index === "number" ? rec.index : 0;
|
|
486
|
+
return !flushedIndices.has(idx);
|
|
487
|
+
});
|
|
488
|
+
d.tool_calls = [...remaining, ...flushed];
|
|
489
|
+
return true;
|
|
490
|
+
}
|
|
491
|
+
|
|
445
492
|
/**
|
|
446
493
|
* Rewrite one Chat Completions SSE block: drop injected delta.tool_calls
|
|
447
494
|
* (including nameless argument continuations via per-index tracking), restore
|
|
@@ -489,20 +536,8 @@ function rewriteChatBlock(
|
|
|
489
536
|
// Indices flushed on this block: their arguments are final, so the
|
|
490
537
|
// per-delta loop below must not buffer them a second time.
|
|
491
538
|
const flushedIndices = new Set<number>();
|
|
492
|
-
if (c.finish_reason && state
|
|
493
|
-
|
|
494
|
-
for (const [idx, args] of state.chatArgsByIndex) {
|
|
495
|
-
const name = state.chatNameByIndex.get(idx);
|
|
496
|
-
if (name === undefined) continue;
|
|
497
|
-
flushedIndices.add(idx);
|
|
498
|
-
flushed.push({ index: idx, type: "function", function: { name, arguments: repairToolArguments(name, args, cloak.argSchemas) } });
|
|
499
|
-
}
|
|
500
|
-
state.chatArgsByIndex.clear();
|
|
501
|
-
state.chatNameByIndex.clear();
|
|
502
|
-
if (flushed.length > 0) {
|
|
503
|
-
d.tool_calls = [...(Array.isArray(d.tool_calls) ? d.tool_calls : []), ...flushed];
|
|
504
|
-
changed = true;
|
|
505
|
-
}
|
|
539
|
+
if (c.finish_reason && flushChatTerminalToolCalls(d, state, cloak, flushedIndices)) {
|
|
540
|
+
changed = true;
|
|
506
541
|
}
|
|
507
542
|
if (!Array.isArray(d.tool_calls)) {
|
|
508
543
|
if (Object.keys(d).length > 0) allDeltasEmpty = false;
|