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 +14 -9
- package/changelog/v0.5.27.md +15 -0
- package/package.json +1 -1
- package/sources.js +98 -1
- package/src/core/config.js +5 -0
- package/src/core/provider-metadata.js +72 -1
- package/src/core/quota-capabilities.js +5 -0
- package/src/core/setup.js +5 -4
- package/src/tui/app.js +5 -4
- package/src/tui/key-handler.js +5 -0
- package/src/tui/overlays.js +12 -5
- package/src/tui/theme.js +10 -0
- package/src/tui/tui-filters.js +1 -1
- package/web/dist/assets/{index-BDV-Qeuc.js → index-JUPDB-J-.js} +2 -2
- package/web/dist/index.html +1 -1
- package/web/server.js +4 -0
- package/web/src/components/settings/SettingsView.jsx +4 -4
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 ~
|
|
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-
|
|
20
|
-
<img src="https://img.shields.io/badge/providers-
|
|
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 **~
|
|
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
|
-
**~
|
|
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) |
|
|
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) |
|
|
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 ~
|
|
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.
|
|
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
|
package/src/core/config.js
CHANGED
|
@@ -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:
|
|
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(`
|
|
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
|
-
|
|
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 (!
|
|
212
|
+
if (!hasAnyUsableProvider) {
|
|
212
213
|
const result = await promptApiKey(config)
|
|
213
214
|
if (!result) {
|
|
214
215
|
console.log()
|
package/src/tui/key-handler.js
CHANGED
|
@@ -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
|
package/src/tui/overlays.js
CHANGED
|
@@ -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
|
-
|
|
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
|
|
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
|
|
209
|
-
|
|
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
|
|
package/src/tui/tui-filters.js
CHANGED
|
@@ -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'
|