free-coding-models 0.5.26 → 0.5.27

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
@@ -6,7 +6,7 @@
6
6
 
7
7
  <p align="center">
8
8
  <strong>Find the fastest free coding model in seconds</strong><br>
9
- Track ~146 models across 15 trusted free or free-limited AI providers in real time<br><br>
9
+ Track ~191 models across 20 trusted free or free-limited AI providers in real time<br><br>
10
10
  <strong>Install Free API endpoints to your favorite AI coding tools:</strong><br>
11
11
  OpenCode CLI / Desktop / WebUI, OpenClaw, Crush, Goose, Aider, Kilo CLI, Qwen Code, OpenHands, Amp, Hermes, Continue, Cline, Xcode, Pi and more...<br><br>
12
12
  <strong>Use Kimi K2, DeepSeek V3, GPT-OSS, Qwen3, MiniMax M3, GLM, Llama 4, Gemma 4, Devstral and more — for free</strong>
@@ -16,8 +16,8 @@
16
16
  <img src="https://img.shields.io/npm/v/free-coding-models?color=3d6b00&label=npm&logo=npm" alt="npm version" width="200"><br>
17
17
  <img src="https://img.shields.io/node/v/free-coding-models?color=3d6b00&logo=node.js" alt="node version" width="200"><br>
18
18
  <img src="https://img.shields.io/npm/l/free-coding-models?color=3d6b00" alt="license" width="200"><br>
19
- <img src="https://img.shields.io/badge/models-146-3d6b00?logo=nvidia" alt="models count" width="200"><br>
20
- <img src="https://img.shields.io/badge/providers-15-1a56db" alt="providers count" width="200">
19
+ <img src="https://img.shields.io/badge/models-191-3d6b00?logo=nvidia" alt="models count" width="200"><br>
20
+ <img src="https://img.shields.io/badge/providers-20-1a56db" alt="providers count" width="200">
21
21
  </p>
22
22
 
23
23
  ```bash
@@ -59,7 +59,7 @@ free-coding-models
59
59
 
60
60
  ## 💡 Why this tool?
61
61
 
62
- There are **~153 cataloged free or free-limited coding models** across 16 vetted providers. Which one is fastest right now? Which one is actually stable versus just lucky on the last ping?
62
+ There are **~191 cataloged free or free-limited coding models** across 20 vetted providers. Which one is fastest right now? Which one is actually stable versus just lucky on the last ping?
63
63
 
64
64
  This CLI pings them all in parallel, shows live latency, and calculates a **live Stability Score (0-100)**. Average latency alone is misleading if a model randomly spikes to 6 seconds; the stability score measures true reliability by combining **p95 latency** (30%), **jitter/variance** (30%), **spike rate** (20%), and **uptime** (20%).
65
65
 
@@ -71,9 +71,9 @@ It then writes the model you pick directly into your coding tool's config — so
71
71
 
72
72
  ### 🟢 List of Free AI Providers
73
73
 
74
- Create a free account on one provider below to get started:
74
+ Create a free account on one provider below to get started. A few providers (`Kilo`, `LLM7`, OVHcloud sandbox) can also answer without a key, with tighter shared limits.
75
75
 
76
- **~153 coding models** across 16 active providers, ranked by practical free-tier usefulness.
76
+ **~191 coding models** across 20 active providers, ranked by practical free-tier usefulness.
77
77
 
78
78
  | # | Provider | Models | Tier range | Free tier | Env var |
79
79
  |---|----------|--------|-----------|-----------|--------|
@@ -83,7 +83,7 @@ Create a free account on one provider below to get started:
83
83
  | 4 | [Google AI Studio](https://aistudio.google.com/apikey) | 7 | S+ → A | Gemini free quotas vary by model/region | `GOOGLE_API_KEY` |
84
84
  | 5 | [GitHub Models](https://models.github.ai) | 15 | S+ → C | Quota depends on GitHub/Copilot tier | `GITHUB_TOKEN` |
85
85
  | 6 | [Mistral La Plateforme](https://console.mistral.ai/api-keys) | 5 | S+ → A | Experiment plan, free evaluation tier | `MISTRAL_API_KEY` |
86
- | 7 | [Cloudflare Workers AI](https://dash.cloudflare.com) | 13 | S+ → B | 10K neurons/day, 300 RPM (no credit card) | `CLOUDFLARE_API_TOKEN` + `CLOUDFLARE_ACCOUNT_ID` |
86
+ | 7 | [Cloudflare Workers AI](https://dash.cloudflare.com) | 16 | S+ → B | 10K neurons/day, 300 RPM (no credit card) | `CLOUDFLARE_API_TOKEN` + `CLOUDFLARE_ACCOUNT_ID` |
87
87
  | 8 | [OpenRouter](https://openrouter.ai/keys) | 24 | S+ → C | 50 req/day free, 1K/day with $10 spend | `OPENROUTER_API_KEY` |
88
88
  | 9 | [SambaNova](https://cloud.sambanova.ai/apis) | 7 | S+ → B+ | Small developer quota, useful for light usage | `SAMBANOVA_API_KEY` |
89
89
  | 10 | [OVHcloud AI Endpoints](https://endpoints.ai.cloud.ovh.net) | 10 | S → B | 2 req/min/IP free, 400 RPM with key | `OVH_AI_ENDPOINTS_ACCESS_TOKEN` |
@@ -91,7 +91,12 @@ Create a free account on one provider below to get started:
91
91
  | 12 | [ZAI](https://z.ai) | 2 | S | Free Flash models only | `ZAI_API_KEY` |
92
92
  | 13 | [Scaleway](https://console.scaleway.com/iam/api-keys) | 10 | S+ → B | 1M free tokens | `SCALEWAY_API_KEY` |
93
93
  | 14 | [Alibaba DashScope](https://modelstudio.console.alibabacloud.com) | 11 | S+ → A+ | 1M free tokens/model, Singapore, 90 days | `DASHSCOPE_API_KEY` |
94
- | 15 | [OpenCode Zen](https://opencode.ai/zen) | 6 | S+ → A | Free with OpenCode account | Zen models ✨ |
94
+ | 15 | [OpenCode Zen](https://opencode.ai/zen) | 5 | S+ → A | Free with OpenCode account | Zen models ✨ |
95
+ | 16 | [Kilo](https://kilo.ai) | 1 | A+ | Free auto-router works without a key | optional `KILO_API_KEY` |
96
+ | 17 | [LLM7](https://llm7.io) | 4 | S+ → B+ | Shared free tier, optional free token | optional `LLM7_API_KEY` |
97
+ | 18 | [Routeway](https://routeway.ai) | 15 | S+ → C | Explicit `:free` zero-price models | `ROUTEWAY_API_KEY` |
98
+ | 19 | [Novita AI](https://novita.ai) | 4 | S+ → S | Only zero-price live chat models included | `NOVITA_API_KEY` |
99
+ | 20 | [Ollama Cloud](https://ollama.com/pricing) | 17 | S+ → A | Free cloud usage with session/weekly limits | `OLLAMA_API_KEY` |
95
100
 
96
101
  > 💡 One key is enough. Add more at any time with **`P`** inside the TUI.
97
102
 
@@ -513,7 +518,7 @@ When a tool mode is active (via `Z`), models incompatible with that tool are hig
513
518
 
514
519
  ## ✨ Features
515
520
 
516
- - **Parallel pings** — all ~150 API/Zen-callable models tested simultaneously via native `fetch` (~152 total cataloged models)
521
+ - **Parallel pings** — all ~191 API/Zen-callable models tested simultaneously via native `fetch`
517
522
  - **AI benchmark columns** — `Ctrl+A` benchmarks the selected model, `Ctrl+U` benchmarks visible models, and results split cleanly into **AI Latency** plus **TPS**. Settings includes an opt-in **Startup AI Speed Scan** toggle to run the global benchmark automatically after launch.
518
523
  - **Tiny verdict indicator** — the first `❔` column mirrors the full Verdict as a compact emoji (`🟩`, `🟢`, `🟡`, `🟠`, etc.) and sorts by the same verdict order.
519
524
  - **Adaptive monitoring** — 2s burst for 60s → 10s normal → 30s idle
@@ -0,0 +1,15 @@
1
+ # Changelog v0.5.27 - 2026-06-11
2
+
3
+ ### Added
4
+ - Added five newly audited free/free-limited providers discovered from `apmantza/pi-free`: Kilo, LLM7, Routeway, Novita AI, and Ollama Cloud.
5
+ - Added 41 coding-capable API models from those providers, keeping only no-key/free-router models, explicit `:free` zero-price Routeway models, zero-price Novita chat models, and coding-relevant Ollama Cloud models.
6
+ - Added provider metadata, environment-variable support, quota behavior, Settings key-test endpoints, no-key provider handling, and TUI colors for the new providers.
7
+ - Added 💰 billing/credits warnings in TUI Settings, first-run setup, and Web Settings for providers that require paid credits or trial-credit-style accounts despite exposing free/free-tagged models.
8
+
9
+ ### Changed
10
+ - Updated README model/provider counts to 191 models across 20 providers and documented the new providers in the main provider table.
11
+ - Improved first-run setup wording from “Free key” to “Signup/key page” so paid/trial-credit providers are not misleading.
12
+ - Exposed provider billing metadata through the Web Dashboard config API so the desktop/web surface can render the same paid-provider warnings as the TUI.
13
+
14
+ ### Fixed
15
+ - Fixed first-run usability for keyless providers by allowing Kilo and LLM7 to count as usable providers without forcing the API key wizard.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "free-coding-models",
3
- "version": "0.5.26",
3
+ "version": "0.5.27",
4
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.",
5
5
  "keywords": [
6
6
  "nvidia",
package/sources.js CHANGED
@@ -29,7 +29,7 @@
29
29
  * 📖 Secondary: https://swe-rebench.com (independent evals, scores are lower)
30
30
  * 📖 Leaderboard tracker: https://www.marc0.dev/en/leaderboard
31
31
  *
32
- * @exports nvidiaNim, groq, cerebras, sambanova, openrouter, githubModels, mistral, codestral, scaleway, googleai, zai, qwen, cloudflare, ovhcloud, opencodeZen — model arrays per active provider
32
+ * @exports nvidiaNim, groq, cerebras, sambanova, openrouter, githubModels, mistral, codestral, scaleway, googleai, zai, qwen, cloudflare, ovhcloud, opencodeZen, kilo, llm7, routeway, novita, ollamaCloud — model arrays per active provider
33
33
  * @exports sources — map of active free/free-limited providers, each with { name, url, models }
34
34
 
35
35
  * @exports MODELS — flat array of [modelId, label, tier, sweScore, ctx, providerKey]
@@ -363,6 +363,76 @@ export const opencodeZen = [
363
363
  // Added (2026-06-01): minimax-m3-free — MiniMax M3, 1M context, MSA attention (SWE-Bench Pro 59.0%)
364
364
  ]
365
365
 
366
+ // 📖 Kilo source - https://api.kilo.ai/api/gateway
367
+ // 📖 OpenAI-compatible gateway. `kilo-auto/free` works without a key and routes to Kilo's current free model pool.
368
+ // 📖 Keep only the stable router model here; individual promo `:free` models churn too quickly.
369
+ export const kilo = [
370
+ ['kilo-auto/free', 'Kilo Auto Free', 'A+', '-', '256k'],
371
+ ]
372
+
373
+ // 📖 LLM7 source - https://api.llm7.io/v1
374
+ // 📖 Free unauthenticated tier works with tight shared limits; optional free token at https://token.llm7.io
375
+ // 📖 Pro-tagged models from /v1/models are intentionally excluded.
376
+ export const llm7 = [
377
+ ['qwen3-235b', 'Qwen3 235B', 'S+', '70.0%', '240k'],
378
+ ['mistral-small-3.2', 'Mistral Small 3.2', 'B+', '34.0%', '128k'],
379
+ ['codestral-latest', 'Codestral Latest', 'B+', '34.0%', '32k'],
380
+ ['devstral-small-2:24b', 'Devstral Small 2', 'A', '-', '128k'],
381
+ ]
382
+
383
+ // 📖 Routeway source - https://api.routeway.ai/v1/models
384
+ // 📖 OpenAI-compatible gateway with explicit zero-price `:free` chat models.
385
+ // 📖 Live catalog checked 2026-06-11; only chat-completions models with free pricing are listed.
386
+ export const routeway = [
387
+ ['deepseek-v4-flash:free', 'DeepSeek V4 Flash', 'S+', '72.0%', '1M'],
388
+ ['step-3.5-flash:free', 'Step 3.5 Flash', 'S+', '74.4%', '256k'],
389
+ ['ling-2.6-flash:free', 'Ling 2.6 Flash', 'S', '-', '262k'],
390
+ ['gpt-oss-120b:free', 'GPT OSS 120B', 'S', '60.0%', '131k'],
391
+ ['minimax-m2:free', 'MiniMax M2', 'S', '-', '197k'],
392
+ ['laguna-m.1:free', 'Poolside Laguna M.1', 'S+', '-', '131k'],
393
+ ['laguna-xs.2:free', 'Poolside Laguna XS.2','S+', '-', '131k'],
394
+ ['gemma-4-31b-it:free', 'Gemma 4 31B', 'A', '45.0%', '262k'],
395
+ ['nemotron-3-nano-30b-a3b:free', 'Nemotron Nano 30B', 'A', '43.0%', '256k'],
396
+ ['llama-3.3-70b-instruct:free', 'Llama 3.3 70B', 'A-', '39.5%', '131k'],
397
+ ['mistral-nemo-instruct:free', 'Mistral Nemo', 'B+', '30.0%', '16k'],
398
+ ['nemotron-nano-9b-v2:free', 'Nemotron Nano 9B', 'B+', '18.0%', '128k'],
399
+ ['llama-3.1-8b-instruct:free', 'Llama 3.1 8B', 'B', '28.8%', '16k'],
400
+ ['llama-3.2-3b-instruct:free', 'Llama 3.2 3B', 'B', '20.0%', '16k'],
401
+ ['llama-3.2-1b-instruct:free', 'Llama 3.2 1B', 'C', '-', '16k'],
402
+ ]
403
+
404
+ // 📖 Novita AI source - https://api.novita.ai/openai/v1/models
405
+ // 📖 Novita is mostly paid/trial-credit, so this catalog only includes live chat models reporting 0 input/output price.
406
+ // 📖 Test/dev/placeholder zero-price IDs were intentionally excluded.
407
+ export const novita = [
408
+ ['qwen/qwen3.6-plus', 'Qwen3.6 Plus', 'S+', '72.0%', '1M'],
409
+ ['qwen/qwen3.5-plus', 'Qwen3.5 Plus', 'S', '68.0%', '1M'],
410
+ ['nex-agi/nex-n2-pro', 'Nex N2 Pro', 'S', '-', '262k'],
411
+ ['minimax/m2-her', 'MiniMax M2 HER', 'S', '-', '32k'],
412
+ ]
413
+
414
+ // 📖 Ollama Cloud source - https://ollama.com/pricing and https://ollama.com/v1/models
415
+ // 📖 Free plan includes cloud model access with session/weekly limits. This list keeps coding-relevant cloud models only.
416
+ export const ollamaCloud = [
417
+ ['minimax-m2.7', 'MiniMax M2.7', 'S+', '80.2%', '200k'],
418
+ ['glm-5.1', 'GLM 5.1', 'S+', '77.8%', '203k'],
419
+ ['kimi-k2.6', 'Kimi K2.6', 'S+', '76.8%', '131k'],
420
+ ['deepseek-v4-pro', 'DeepSeek V4 Pro', 'S+', '73.1%', '1M'],
421
+ ['deepseek-v4-flash', 'DeepSeek V4 Flash', 'S+', '72.0%', '1M'],
422
+ ['devstral-2:123b', 'Devstral 2 123B', 'S+', '72.2%', '200k'],
423
+ ['qwen3-coder:480b', 'Qwen3 Coder 480B', 'S+', '70.6%', '256k'],
424
+ ['nemotron-3-ultra', 'Nemotron 3 Ultra', 'S+', '-', '1M'],
425
+ ['glm-4.7', 'GLM 4.7', 'S+', '73.8%', '128k'],
426
+ ['qwen3.5:397b', 'Qwen3.5 397B', 'S', '68.0%', '128k'],
427
+ ['qwen3-coder-next', 'Qwen3 Coder Next', 'S', '65.0%', '256k'],
428
+ ['gpt-oss:120b', 'GPT OSS 120B', 'S', '60.0%', '128k'],
429
+ ['minimax-m3', 'MiniMax M3', 'S', '59.0%', '1M'],
430
+ ['mistral-large-3:675b', 'Mistral Large 3', 'A+', '58.0%', '256k'],
431
+ ['nemotron-3-super', 'Nemotron 3 Super', 'A+', '56.0%', '128k'],
432
+ ['gemma4:31b', 'Gemma 4 31B', 'A', '45.0%', '256k'],
433
+ ['gpt-oss:20b', 'GPT OSS 20B', 'A', '42.0%', '128k'],
434
+ ]
435
+
366
436
  // 📖 All sources combined - used by the main script
367
437
  // 📖 Each source has: name (display), url (API endpoint), models (array of model tuples)
368
438
  // 📖 Providers ordered by generosity of free tier (most generous first)
@@ -445,6 +515,33 @@ export const sources = {
445
515
  models: opencodeZen,
446
516
  zenOnly: true,
447
517
  },
518
+ kilo: {
519
+ name: 'Kilo',
520
+ url: 'https://api.kilo.ai/api/gateway/chat/completions',
521
+ models: kilo,
522
+ noKeyNeeded: true,
523
+ },
524
+ llm7: {
525
+ name: 'LLM7',
526
+ url: 'https://api.llm7.io/v1/chat/completions',
527
+ models: llm7,
528
+ noKeyNeeded: true,
529
+ },
530
+ routeway: {
531
+ name: 'Routeway',
532
+ url: 'https://api.routeway.ai/v1/chat/completions',
533
+ models: routeway,
534
+ },
535
+ novita: {
536
+ name: 'Novita AI',
537
+ url: 'https://api.novita.ai/openai/v1/chat/completions',
538
+ models: novita,
539
+ },
540
+ 'ollama-cloud': {
541
+ name: 'Ollama Cloud',
542
+ url: 'https://ollama.com/v1/chat/completions',
543
+ models: ollamaCloud,
544
+ },
448
545
  }
449
546
 
450
547
  // 📖 Flatten all models from all sources — each entry includes providerKey as 6th element
@@ -134,6 +134,11 @@ const ENV_VARS = {
134
134
  zai: 'ZAI_API_KEY',
135
135
  ovhcloud: 'OVH_AI_ENDPOINTS_ACCESS_TOKEN',
136
136
  'opencode-zen': 'OPENCODE_ZEN_API_KEY',
137
+ kilo: ['KILO_API_KEY', 'KILO_TOKEN'],
138
+ llm7: 'LLM7_API_KEY',
139
+ routeway: 'ROUTEWAY_API_KEY',
140
+ novita: 'NOVITA_API_KEY',
141
+ 'ollama-cloud': 'OLLAMA_API_KEY',
137
142
  }
138
143
 
139
144
  // 📖 Smart Router defaults are intentionally conservative: balanced probing,
@@ -8,7 +8,8 @@
8
8
  * This module owns three separate concerns that all relate to "knowing about providers":
9
9
  *
10
10
  * 1. `PROVIDER_METADATA` — human-readable display info (label, colour, signup URL, rate limits)
11
- * used in the setup wizard (`promptApiKey`) and the Settings overlay.
11
+ * used in the setup wizard (`promptApiKey`) and the Settings overlay. Providers that need
12
+ * credits/billing can expose `paidProviderNote`, which Settings renders as a 💰 warning.
12
13
  *
13
14
  * 2. `ENV_VAR_NAMES` — maps providerKey → the environment variable name that carries the API key.
14
15
  * Used when spawning OpenCode child processes so that keys stored only in
@@ -23,6 +24,7 @@
23
24
  *
24
25
  * @exports
25
26
  * PROVIDER_METADATA, ENV_VAR_NAMES, OPENCODE_MODEL_MAP,
27
+ * getProviderBillingNote, getProviderLabelWithBilling,
26
28
  * isWindows, isMac, isLinux
27
29
  *
28
30
  * @see bin/free-coding-models.js — consumes all exports from this module
@@ -55,6 +57,11 @@ export const ENV_VAR_NAMES = {
55
57
  ovhcloud: 'OVH_AI_ENDPOINTS_ACCESS_TOKEN',
56
58
  qwen: 'DASHSCOPE_API_KEY',
57
59
  'opencode-zen': 'OPENCODE_ZEN_API_KEY',
60
+ kilo: 'KILO_API_KEY',
61
+ llm7: 'LLM7_API_KEY',
62
+ routeway: 'ROUTEWAY_API_KEY',
63
+ novita: 'NOVITA_API_KEY',
64
+ 'ollama-cloud': 'OLLAMA_API_KEY',
58
65
  }
59
66
 
60
67
  // 📖 OPENCODE_MODEL_MAP: sparse table of model IDs that differ between sources.js and OpenCode's
@@ -70,6 +77,7 @@ export const OPENCODE_MODEL_MAP = {
70
77
  // 📖 `color` is a chalk function for visual distinction in the TUI.
71
78
  // 📖 `signupUrl` / `signupHint` guide users through first-time key generation.
72
79
  // 📖 `rateLimits` gives a quick reminder of the free-tier quota without opening a browser.
80
+ // 📖 `paidProviderNote` marks providers that require credits/billing despite exposing free/trial/free-tagged models.
73
81
  export const PROVIDER_METADATA = {
74
82
  nvidia: {
75
83
  label: 'NVIDIA NIM',
@@ -143,6 +151,7 @@ export const PROVIDER_METADATA = {
143
151
  signupUrl: 'https://deepinfra.com/login',
144
152
  signupHint: 'Login → API keys',
145
153
  rateLimits: 'Free tier: 200 concurrent requests (default)',
154
+ paidProviderNote: 'trial credit provider',
146
155
  },
147
156
  fireworks: {
148
157
  label: 'Fireworks AI',
@@ -157,6 +166,7 @@ export const PROVIDER_METADATA = {
157
166
  signupUrl: 'https://console.mistral.ai/api-keys',
158
167
  signupHint: 'La Plateforme → API keys (MISTRAL_API_KEY; CODESTRAL_API_KEY also works)',
159
168
  rateLimits: 'Codestral free access: 30 req/min, 2000/day',
169
+ paidProviderNote: 'paid - free Experiment plan',
160
170
  },
161
171
  hyperbolic: {
162
172
  label: 'Hyperbolic',
@@ -192,6 +202,7 @@ export const PROVIDER_METADATA = {
192
202
  signupUrl: 'https://api.together.ai/settings/api-keys',
193
203
  signupHint: 'Settings → API keys',
194
204
  rateLimits: 'Credits/promos vary by account (check console)',
205
+ paidProviderNote: 'trial credit provider',
195
206
  },
196
207
  cloudflare: {
197
208
  label: 'Cloudflare Workers AI',
@@ -257,4 +268,64 @@ export const PROVIDER_METADATA = {
257
268
  signupHint: 'Manager → Public Cloud → AI Endpoints → API keys (optional: sandbox works without key)',
258
269
  rateLimits: 'Free sandbox: 2 req/min per IP per model (no key). With API key: 400 RPM',
259
270
  },
271
+ kilo: {
272
+ label: 'Kilo',
273
+ color: chalk.rgb(120, 255, 190),
274
+ signupUrl: 'https://kilo.ai',
275
+ signupHint: 'No key needed for kilo-auto/free; optional OAuth/API token unlocks more models',
276
+ rateLimits: 'Free router model works without a key; limits are managed by Kilo',
277
+ noKeyNeeded: true,
278
+ },
279
+ llm7: {
280
+ label: 'LLM7',
281
+ color: chalk.rgb(180, 255, 140),
282
+ signupUrl: 'https://token.llm7.io',
283
+ signupHint: 'Optional: sign in at token.llm7.io for a free token',
284
+ rateLimits: 'Free shared tier without key; optional free token improves quota',
285
+ noKeyNeeded: true,
286
+ },
287
+ routeway: {
288
+ label: 'Routeway',
289
+ color: chalk.rgb(130, 210, 255),
290
+ signupUrl: 'https://routeway.ai',
291
+ signupHint: 'Create account → API key',
292
+ rateLimits: 'Free :free models with an API key; paid models excluded here',
293
+ paidProviderNote: 'paid — has :free models',
294
+ },
295
+ novita: {
296
+ label: 'Novita AI',
297
+ color: chalk.rgb(255, 185, 120),
298
+ signupUrl: 'https://novita.ai/settings/key-management',
299
+ signupHint: 'Settings → Key Management → Create API key',
300
+ rateLimits: 'Only zero-price live chat models are listed; other Novita models are paid/trial-credit',
301
+ paidProviderNote: 'paid — 3 free models',
302
+ },
303
+ 'ollama-cloud': {
304
+ label: 'Ollama Cloud',
305
+ color: chalk.rgb(230, 230, 230),
306
+ signupUrl: 'https://ollama.com/settings/keys',
307
+ signupHint: 'Settings → Keys → Create API key',
308
+ rateLimits: 'Free plan includes cloud access with session + weekly limits',
309
+ },
310
+ }
311
+
312
+ /**
313
+ * 📖 Return the short paid/billing warning note for a provider, formatted for UI display.
314
+ * @param {string} providerKey
315
+ * @returns {string}
316
+ */
317
+ export function getProviderBillingNote(providerKey) {
318
+ const note = PROVIDER_METADATA[providerKey]?.paidProviderNote
319
+ return typeof note === 'string' && note.trim() ? `(${note.trim()})` : ''
320
+ }
321
+
322
+ /**
323
+ * 📖 Return a provider label with a small money marker when credits/billing are required.
324
+ * @param {string} providerKey
325
+ * @param {string} fallbackLabel
326
+ * @returns {string}
327
+ */
328
+ export function getProviderLabelWithBilling(providerKey, fallbackLabel) {
329
+ const label = PROVIDER_METADATA[providerKey]?.label || fallbackLabel || providerKey
330
+ return getProviderBillingNote(providerKey) ? `${label} 💰` : label
260
331
  }
@@ -54,6 +54,11 @@ export const PROVIDER_CAPABILITIES = {
54
54
  cloudflare: { telemetryType: 'unknown', supportsEndpoint: false, usageDisplay: 'ok', resetCadence: 'daily' },
55
55
  zai: { telemetryType: 'unknown', supportsEndpoint: false, usageDisplay: 'ok', resetCadence: 'none' },
56
56
  'opencode-zen': { telemetryType: 'unknown', supportsEndpoint: false, usageDisplay: 'ok', resetCadence: 'unknown' },
57
+ kilo: { telemetryType: 'unknown', supportsEndpoint: false, usageDisplay: 'ok', resetCadence: 'unknown' },
58
+ llm7: { telemetryType: 'unknown', supportsEndpoint: false, usageDisplay: 'ok', resetCadence: 'rolling' },
59
+ routeway: { telemetryType: 'header', supportsEndpoint: false, usageDisplay: 'percent', resetCadence: 'unknown' },
60
+ novita: { telemetryType: 'unknown', supportsEndpoint: false, usageDisplay: 'ok', resetCadence: 'unknown' },
61
+ 'ollama-cloud': { telemetryType: 'unknown', supportsEndpoint: false, usageDisplay: 'ok', resetCadence: 'rolling' },
57
62
  }
58
63
 
59
64
  /** Fallback for unrecognized providers */
package/src/core/setup.js CHANGED
@@ -36,7 +36,7 @@
36
36
  import chalk from 'chalk'
37
37
  import { createRequire } from 'module'
38
38
  import { sources } from '../../sources.js'
39
- import { PROVIDER_METADATA } from './provider-metadata.js'
39
+ import { PROVIDER_METADATA, getProviderBillingNote, getProviderLabelWithBilling } from './provider-metadata.js'
40
40
  import { saveConfig } from './config.js'
41
41
 
42
42
  const require = createRequire(import.meta.url)
@@ -62,7 +62,8 @@ export async function promptApiKey(config) {
62
62
  const meta = PROVIDER_METADATA[key] || {}
63
63
  return {
64
64
  key,
65
- label: meta.label || sources[key]?.name || key,
65
+ label: getProviderLabelWithBilling(key, sources[key]?.name || key),
66
+ billingNote: getProviderBillingNote(key),
66
67
  color: meta.color || chalk.white,
67
68
  url: meta.signupUrl || 'https://example.com',
68
69
  hint: meta.signupHint || 'Create API key',
@@ -77,8 +78,8 @@ export async function promptApiKey(config) {
77
78
  })
78
79
 
79
80
  for (const p of providers) {
80
- console.log(` ${p.color('●')} ${chalk.bold(p.label)}`)
81
- console.log(chalk.dim(` Free key at: `) + chalk.cyanBright(p.url))
81
+ console.log(` ${p.color('●')} ${chalk.bold(p.label)}${p.billingNote ? ' ' + chalk.yellow(p.billingNote) : ''}`)
82
+ console.log(chalk.dim(` Signup/key page: `) + chalk.cyanBright(p.url))
82
83
  console.log(chalk.dim(` ${p.hint}`))
83
84
  const answer = await ask(chalk.dim(` Enter key (or Enter to skip): `))
84
85
  console.log()
package/src/tui/app.js CHANGED
@@ -59,7 +59,7 @@
59
59
  * ⚙️ Configuration:
60
60
  * - API keys stored per-provider in ~/.free-coding-models.json (0600 perms)
61
61
  * - Old ~/.free-coding-models plain-text auto-migrated as nvidia key on first run
62
- * - Env vars override config: NVIDIA_API_KEY, GROQ_API_KEY, CEREBRAS_API_KEY, OPENROUTER_API_KEY, GITHUB_TOKEN, MISTRAL_API_KEY, SCALEWAY_API_KEY, GOOGLE_API_KEY, CLOUDFLARE_API_TOKEN, DASHSCOPE_API_KEY, ZAI_API_KEY, etc.
62
+ * - Env vars override config: NVIDIA_API_KEY, GROQ_API_KEY, CEREBRAS_API_KEY, OPENROUTER_API_KEY, GITHUB_TOKEN, MISTRAL_API_KEY, SCALEWAY_API_KEY, GOOGLE_API_KEY, CLOUDFLARE_API_TOKEN, DASHSCOPE_API_KEY, ZAI_API_KEY, LLM7_API_KEY, ROUTEWAY_API_KEY, NOVITA_API_KEY, OLLAMA_API_KEY, etc.
63
63
  * - ZAI (z.ai) uses a non-standard base path; cloudflare needs CLOUDFLARE_ACCOUNT_ID in env.
64
64
  * - Cloudflare Workers AI requires both CLOUDFLARE_API_TOKEN (or CLOUDFLARE_API_KEY) and CLOUDFLARE_ACCOUNT_ID
65
65
  * - Models loaded from sources.js — all provider/model definitions are centralized there
@@ -205,10 +205,11 @@ export async function runApp(cliArgs, config, startupOptions = {}) {
205
205
 
206
206
  // 📖 Profile system removed - API keys now persist permanently across all sessions
207
207
 
208
- // 📖 Check if any provider has a key — if not, run the first-time setup wizard
209
- const hasAnyKey = Object.keys(sources).some(pk => !!getApiKey(config, pk))
208
+ // 📖 Check if any provider has a key — if not, run the first-time setup wizard.
209
+ // 📖 Keyless providers (Kilo/LLM7) can still run immediately, so they also count as usable.
210
+ const hasAnyUsableProvider = Object.keys(sources).some(pk => !!getApiKey(config, pk) || PROVIDER_METADATA[pk]?.noKeyNeeded)
210
211
 
211
- if (!hasAnyKey) {
212
+ if (!hasAnyUsableProvider) {
212
213
  const result = await promptApiKey(config)
213
214
  if (!result) {
214
215
  console.log()
@@ -107,6 +107,11 @@ const PROVIDER_AUTH_ENDPOINTS = {
107
107
  zai: null, // 📖 ZAI undocumented; use ping only
108
108
  googleai: null, // 📖 Google AI Studio has no OpenAI-compatible /models; use ping
109
109
  'opencode-zen': null, // 📖 OpenCode Zen uses OpenCode auth only; use ping
110
+ kilo: { url: 'https://api.kilo.ai/api/gateway/models', method: 'GET' },
111
+ llm7: { url: 'https://api.llm7.io/v1/models', method: 'GET' },
112
+ routeway: { url: 'https://api.routeway.ai/v1/models', method: 'GET' },
113
+ novita: { url: 'https://api.novita.ai/openai/v1/models', method: 'GET' },
114
+ 'ollama-cloud': { url: 'https://ollama.com/v1/models', method: 'GET' },
110
115
  }
111
116
 
112
117
  // 📖 Sleep helper kept local to this module so the Settings key test flow can
@@ -24,6 +24,7 @@ import { buildCliHelpLines } from './cli-help.js'
24
24
  import { renderRouterDashboard as renderRouterDashboardOverlay } from '../core/router-dashboard.js'
25
25
  import { renderPlayground as renderPlaygroundOverlay } from '../core/playground.js'
26
26
  import { themeColors, getThemeStatusLabel, getProviderRgb } from './theme.js'
27
+ import { getProviderBillingNote, getProviderLabelWithBilling } from '../core/provider-metadata.js'
27
28
 
28
29
  export function createOverlayRenderers(state, deps) {
29
30
  const {
@@ -183,13 +184,16 @@ export function createOverlayRenderers(state, deps) {
183
184
  else if (testResult === 'rate_limited') testBadge = themeColors.warning('[Rate limit ⏳]')
184
185
  else if (testResult === 'no_callable_model') testBadge = chalk.rgb(...getProviderRgb('openrouter'))('[No model ⚠]')
185
186
  else if (testResult === 'fail') testBadge = themeColors.error('[Test ❌]')
186
- // 📖 No truncation of rate limits - overlay now uses 100% terminal width
187
- const rateSummary = themeColors.dim(meta.rateLimits || 'No limit info')
187
+ // 📖 No truncation of rate limits - overlay now uses 100% terminal width.
188
+ // 📖 Paid/credits-required providers get an explicit money marker + parenthesized detail.
189
+ const billingNote = getProviderBillingNote(pk)
190
+ const rateSummary = themeColors.dim(`${meta.rateLimits || 'No limit info'}${billingNote ? ` ${billingNote}` : ''}`)
188
191
 
189
192
  const enabledBadge = enabled ? themeColors.successBold('✅') : themeColors.errorBold('❌')
190
193
  // 📖 Color provider names the same way as in the main table
191
194
  const providerRgb = PROVIDER_COLOR[pk] ?? [105, 190, 245]
192
- const providerName = chalk.bold.rgb(...providerRgb)((meta.label || src.name || pk).slice(0, 22).padEnd(22))
195
+ const providerLabel = getProviderLabelWithBilling(pk, src.name || pk)
196
+ const providerName = chalk.bold.rgb(...providerRgb)(providerLabel.slice(0, 24).padEnd(24))
193
197
 
194
198
  const row = `${bullet(isCursor)}[ ${enabledBadge} ] ${providerName} ${padEndDisplay(keyDisplay, 30)} ${testBadge} ${rateSummary}`
195
199
  cursorLineByRow[i] = lines.length
@@ -205,9 +209,12 @@ export function createOverlayRenderers(state, deps) {
205
209
  const setupStatus = selectedKey ? themeColors.success('API key detected ✅') : themeColors.warning('API key missing ⚠')
206
210
  // 📖 Color the provider name in the setup instructions header
207
211
  const selectedProviderRgb = PROVIDER_COLOR[selectedProviderKey] ?? [105, 190, 245]
208
- const coloredProviderName = chalk.bold.rgb(...selectedProviderRgb)(selectedMeta.label || selectedSource.name || selectedProviderKey)
209
- lines.push(` ${themeColors.textBold('Setup Instructions')} ${coloredProviderName}`)
212
+ const selectedProviderLabel = getProviderLabelWithBilling(selectedProviderKey, selectedSource.name || selectedProviderKey)
213
+ const selectedBillingNote = getProviderBillingNote(selectedProviderKey)
214
+ const coloredProviderName = chalk.bold.rgb(...selectedProviderRgb)(selectedProviderLabel)
215
+ lines.push(` ${themeColors.textBold('Setup Instructions')} — ${coloredProviderName}${selectedBillingNote ? ' ' + themeColors.warning(selectedBillingNote) : ''}`)
210
216
  lines.push(themeColors.dim(` 1) Create a ${selectedMeta.label || selectedSource.name} account: ${selectedMeta.signupUrl || 'signup link missing'}`))
217
+ if (selectedBillingNote) lines.push(themeColors.warning(` 💰 Paid provider note: ${selectedBillingNote}`))
211
218
  lines.push(themeColors.dim(` 2) ${selectedMeta.signupHint || 'Generate an API key and paste it with Enter on this row'}`))
212
219
  lines.push(themeColors.dim(` 3) Press ${themeColors.hotkey('T')} to test your key. Status: ${setupStatus}`))
213
220
  if (selectedProviderKey === 'cloudflare') {
package/src/tui/theme.js CHANGED
@@ -188,6 +188,11 @@ const PROVIDER_PALETTES = {
188
188
  zai: [150, 208, 255],
189
189
  iflow: [211, 229, 101],
190
190
  'opencode-zen': [185, 146, 255],
191
+ kilo: [120, 255, 190],
192
+ llm7: [180, 255, 140],
193
+ routeway: [130, 210, 255],
194
+ novita: [255, 185, 120],
195
+ 'ollama-cloud': [230, 230, 230],
191
196
  },
192
197
  light: {
193
198
  nvidia: [0, 126, 73],
@@ -213,6 +218,11 @@ const PROVIDER_PALETTES = {
213
218
  zai: [0, 104, 171],
214
219
  iflow: [107, 130, 0],
215
220
  'opencode-zen': [108, 58, 183],
221
+ kilo: [0, 130, 82],
222
+ llm7: [73, 130, 0],
223
+ routeway: [0, 105, 180],
224
+ novita: [173, 84, 0],
225
+ 'ollama-cloud': [88, 88, 88],
216
226
  },
217
227
  }
218
228
 
@@ -58,7 +58,7 @@ export function createTuiFilters(state, { sources, getApiKey, PROVIDER_METADATA
58
58
  // 📖 CLI-only tools and Zen models don't need traditional API keys —
59
59
  // 📖 they authenticate via their own CLI login flow, so "configured only" should never hide them.
60
60
  const providerMeta = PROVIDER_METADATA[r.providerKey]
61
- const noKeyNeeded = providerMeta?.cliOnly || providerMeta?.zenOnly
61
+ const noKeyNeeded = providerMeta?.cliOnly || providerMeta?.zenOnly || providerMeta?.noKeyNeeded
62
62
  // 📖 E toggles "Show only configured & working models":
63
63
  // 📖 hide models where provider has no key, or where the health status is noauth/auth_error (but keep timeout and 429)
64
64
  const badHealth = r.status === 'noauth' || r.status === 'auth_error'