free-coding-models 0.5.88 โ†’ 0.5.89

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
@@ -151,6 +151,12 @@ free-coding-models --daemon-stop # stop
151
151
 
152
152
  > ๐Ÿ“– **Full guide (probes, circuit breaker, failover, Playground, `--sync-set`, REST API):** [`docs/router.md`](./docs/router.md)
153
153
 
154
+ ### ๐Ÿงช Router v2 engine (built in)
155
+
156
+ The router daemon now runs the hardened v2 engine internally: content-validated failover (a 200 with empty or garbage output is a failure and fails over), quota-aware routing with `Retry-After` pauses, persisted circuit breakers with a DEGRADED warning state, per-request decision traces, an Anthropic `/v1/messages` endpoint, and "test via router" actions that exercise the real routing chain. Same command, same port, same endpoints - existing setups upgrade by updating the package.
157
+
158
+ Open the TUI with `Shift+V` (or the "Router v2" entry in the Web Dashboard) to see the live fallback chain, per-request attempt chains and run pinned-model tests (`Ctrl+T`). Docs: [`docs/router-v2.md`](./docs/router-v2.md).
159
+
154
160
  ---
155
161
 
156
162
  ## ๐Ÿ“– CLI Flags
@@ -118,7 +118,7 @@ async function main() {
118
118
  ensureFavoritesConfig(config);
119
119
 
120
120
  const isDevMode = isPackageDevMode();
121
- const shouldEnforceUpdate = !cliArgs.daemonStopMode && !cliArgs.daemonStatusMode;
121
+ const shouldEnforceUpdate = !cliArgs.daemonStopMode && !cliArgs.daemonStatusMode && !cliArgs.routerV2StopMode && !cliArgs.routerV2StatusMode;
122
122
  const startupUpdate = shouldEnforceUpdate
123
123
  ? await enforceMandatoryStartupUpdate(config, {
124
124
  saveConfig,
@@ -168,7 +168,11 @@ async function main() {
168
168
  && !cliArgs.daemonMode
169
169
  && !cliArgs.daemonBackgroundMode
170
170
  && !cliArgs.daemonStopMode
171
- && !cliArgs.daemonStatusMode;
171
+ && !cliArgs.daemonStatusMode
172
+ && !cliArgs.routerV2Mode
173
+ && !cliArgs.routerV2BackgroundMode
174
+ && !cliArgs.routerV2StopMode
175
+ && !cliArgs.routerV2StatusMode;
172
176
  try {
173
177
  await checkConfigSecurity({ autoFix: cliArgs.fixPermissionsMode, promptAllowed });
174
178
  } catch {
@@ -210,6 +214,33 @@ async function main() {
210
214
  process.exit(result.ok ? 0 : 1);
211
215
  }
212
216
 
217
+ // ๐Ÿ“– Router v2 lifecycle flags are now ALIASES of the main daemon: the v2
218
+ // engine (content-validated failover, persisted breakers, decision traces,
219
+ // Anthropic /v1/messages) is merged into the regular router daemon on the
220
+ // historical port. The flags keep working for existing scripts.
221
+ if (cliArgs.routerV2Mode || cliArgs.routerV2BackgroundMode || cliArgs.routerV2StopMode || cliArgs.routerV2StatusMode) {
222
+ const {
223
+ getRouterDaemonStatus,
224
+ runRouterDaemon,
225
+ startRouterDaemonBackground,
226
+ stopRouterDaemon,
227
+ } = await import('../src/core/router-daemon.js');
228
+
229
+ if (cliArgs.routerV2Mode) {
230
+ await runRouterDaemon();
231
+ return;
232
+ }
233
+
234
+ const result = cliArgs.routerV2BackgroundMode
235
+ ? await startRouterDaemonBackground()
236
+ : cliArgs.routerV2StopMode
237
+ ? await stopRouterDaemon()
238
+ : await getRouterDaemonStatus();
239
+
240
+ console.log(JSON.stringify(result, null, 2));
241
+ process.exit(result.ok ? 0 : 1);
242
+ }
243
+
213
244
  // ๐Ÿ“– --sync-set [name] โ€” auto-discover, probe, and populate a router set
214
245
  if (cliArgs.syncSetMode) {
215
246
  const { syncSet } = await import('../src/core/sync-set.js');
@@ -0,0 +1,20 @@
1
+ # Changelog v0.5.89 - 2026-09-06
2
+
3
+ ### Added
4
+ - ๐Ÿงช **Smart Model Router v2 engine (built in)**: the regular router daemon (`--daemon-bg`, historical port) now runs the hardened v2 engine - same command, same port, same endpoints, existing setups upgrade transparently. A hardened parallel beta ran on port 19380 during development; it is retired by this release. Open the TUI overlay with `Shift+V`, or use the "Router v2" page in the Web Dashboard (BETA badge on both surfaces).
5
+ - ๐Ÿ›ก๏ธ **Content-validated failover**: a 200 only counts as a success when the answer holds real content. Empty `choices`, embedded `error` objects or content-less replies now fail over to the next model, in both streaming and non-streaming. This closes the biggest v1 blind spot where free providers serving empty 200s were reported as successes.
6
+ - โฑ๏ธ **Body-read timeout**: a provider that sends headers but trickles (or never sends) the body can no longer hang your coding tool; the read is raced against `router.failover.bodyReadTimeoutMs` (default 30s) and fails over.
7
+ - ๐Ÿ”ฅ **Quota-aware routing**: models answering 429 are paused for their `Retry-After` window and skipped; when every model is paused the client gets a proper `429` + `Retry-After` instead of a generic 503.
8
+ - โš–๏ธ **Blame attribution**: client-caused 4xx (bad payload, unsupported fields) fail over but never damage healthy models' circuit breakers, and client disconnects never mark failures.
9
+ - ๐Ÿ’พ **Persisted circuit breakers**: breaker state survives daemon restarts, with a new amber `DEGRADED` warning state (60% of the failure threshold) and escalating cooldowns for repeatedly-tripping models.
10
+ - ๐Ÿ” **Decision traces**: every response carries `x-fcm-v2-model`, `x-fcm-v2-attempts` and `x-fcm-v2-decision` headers, and every request chain (attempts, statuses, skip reasons) is persisted locally and rendered in the TUI overlay and the web page. Routing metadata only: no prompts, no keys.
11
+ - ๐Ÿค– **Anthropic `/v1/messages` support** on the v2 port: request, response and SSE stream translation (including `tool_use` / `input_json_delta`), so Anthropic-protocol agents can use the router directly.
12
+ - ๐Ÿ“Œ **Pinned-model requests**: `model: "fcm:@provider/modelId"` routes to one exact model through the full chain with failover disabled. New `Ctrl+T` (test selected model) and `Ctrl+Shift+T` (test all visible models) TUI hotkeys use it to test the real routing path, unlike the direct-to-provider `Ctrl+A` / `Ctrl+U` benchmarks.
13
+ - ๐Ÿš‘ **Last-resort model**: optional `router.failover.lastResortModel` config gives a designated model one final shot when the whole set fails.
14
+ - โšก **Fast first boot**: v2 listens before its first probe pass, removing the old first-boot stall where the router port stayed dark for up to ~36 seconds.
15
+
16
+ ### Security
17
+ - ๐Ÿ”’ Client `x-api-key` headers are now stripped before proxying to upstream providers on v2, so the local router token can never leak to a provider.
18
+
19
+ ### Fixed
20
+ - ๐Ÿ› Ghost "active requests" no longer accumulate in v2 stats when a request is rejected before routing (v1 leaks one entry per rejected request until restart).
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "free-coding-models",
3
- "version": "0.5.88",
4
- "description": "Find the fastest coding LLM models in seconds โ€” ping free models from multiple providers, pick the best one for OpenCode, Cursor, or any AI coding assistant.",
3
+ "version": "0.5.89",
4
+ "description": "Find the fastest coding LLM models in seconds \u2014 ping free models from multiple providers, pick the best one for OpenCode, Cursor, or any AI coding assistant.",
5
5
  "keywords": [
6
6
  "nvidia",
7
7
  "nim",