pi-free 2.0.14 → 2.1.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.
Files changed (45) hide show
  1. package/CHANGELOG.md +90 -0
  2. package/README.md +64 -78
  3. package/banner.svg +21 -36
  4. package/config.ts +123 -9
  5. package/constants.ts +3 -9
  6. package/index.ts +14 -15
  7. package/lib/built-in-toggle.ts +29 -16
  8. package/lib/json-persistence.ts +90 -22
  9. package/lib/logger.ts +21 -12
  10. package/lib/model-detection.ts +2 -12
  11. package/lib/model-enhancer.ts +11 -2
  12. package/lib/model-metadata.ts +387 -0
  13. package/lib/open-browser.ts +74 -24
  14. package/lib/paths.ts +90 -0
  15. package/lib/probe-cache.ts +19 -19
  16. package/lib/provider-cache.ts +74 -28
  17. package/lib/provider-compat.ts +58 -9
  18. package/lib/provider-probe.ts +188 -0
  19. package/lib/registry.ts +1 -5
  20. package/lib/session-start-metrics.ts +46 -0
  21. package/lib/telemetry.ts +115 -86
  22. package/lib/types.ts +22 -2
  23. package/lib/util.ts +80 -21
  24. package/package.json +7 -2
  25. package/provider-failover/benchmark-lookup.ts +17 -5
  26. package/provider-helper.ts +11 -2
  27. package/providers/cline/cline-models.ts +12 -2
  28. package/providers/cline/cline-xml-bridge.ts +974 -0
  29. package/providers/cline/cline.ts +67 -176
  30. package/providers/crofai/crofai.ts +6 -1
  31. package/providers/deepinfra/deepinfra.ts +69 -2
  32. package/providers/dynamic-built-in/index.ts +237 -2
  33. package/providers/kilo/kilo-models.ts +3 -1
  34. package/providers/kilo/kilo.ts +268 -41
  35. package/providers/model-fetcher.ts +18 -55
  36. package/providers/novita/novita.ts +69 -2
  37. package/providers/ollama/ollama.ts +48 -24
  38. package/providers/opencode-session.ts +67 -2
  39. package/providers/routeway/routeway.ts +188 -2
  40. package/providers/sambanova/sambanova.ts +67 -1
  41. package/providers/together/together.ts +69 -2
  42. package/providers/tokenrouter/tokenrouter.ts +378 -0
  43. package/providers/zenmux/zenmux.ts +6 -1
  44. package/scripts/check-extensions.mjs +32 -16
  45. package/providers/nvidia/nvidia.ts +0 -504
package/CHANGELOG.md CHANGED
@@ -7,6 +7,94 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [2.1.0] - 2026-06-15
11
+
12
+ ### Added
13
+
14
+ - **Cline XML tool bridge** — Replaced Cline's native OpenAI tool-message path with a custom `streamSimple` XML bridge. Cline-trained models now receive Cline-style XML tool instructions and emit XML tool calls that pi-free converts back to Pi `toolCall` blocks. This fixes strict upstream errors such as `Tool message must have tool_call_id` and `missing field "tool_call_id"` on models like `xiaomi/mimo-v2.5` and `nex-agi/nex-n2-pro:free` ([#232](https://github.com/apmantza/pi-free/pull/232)).
15
+
16
+ - **Cline-native tool name mapping** — The XML bridge maps Cline-native tool names to Pi runtime tools:
17
+ - `read_file` → `read`
18
+ - `write_to_file` → `write`
19
+ - `replace_in_file` → `edit` (supports multi-block SEARCH/REPLACE diffs as one Pi `edit` call with multiple edits)
20
+ - `execute_command` → `bash`
21
+ - `list_files`, `search_files`, `list_code_definition_names` → `bash` (safe command generation)
22
+ - Unknown Pi tools pass through by their original names ([#235](https://github.com/apmantza/pi-free/pull/235), [#237](https://github.com/apmantza/pi-free/pull/237)).
23
+
24
+ - **Cline XML thinking-tag hardening** — Strips `<thinking>...</thinking>` blocks, orphan `</thinking>` close tags, and dangling planning text before tool parsing, so Cline models don't emit visible plan text instead of tool calls ([#239](https://github.com/apmantza/pi-free/pull/239), [#240](https://github.com/apmantza/pi-free/pull/240)).
25
+
26
+ - **Live Cline smoke test** — Added `npm run smoke:cline` gated test that hits the real Cline API and verifies Cline `read_file` XML is converted into a Pi `read` tool call ([#232](https://github.com/apmantza/pi-free/pull/232)).
27
+
28
+ ### Fixed
29
+
30
+ - **TokenRouter MiniMax-M3 `<think>` leak** — The model sometimes emits DeepSeek-style `<think>` reasoning tags inline in assistant text. Added a `message_end` handler scoped to TokenRouter that extracts these blocks (including unclosed dangling tags) and promotes them to proper `ThinkingContent`, so Pi renders them as reasoning instead of visible text ([#243](https://github.com/apmantza/pi-free/pull/243)).
31
+
32
+ - **TokenRouter provider** — OpenAI-compatible API gateway at `api.tokenrouter.com/v1` with 88 text chat models. 1 free via hardcoded `KNOWN_FREE_MODELS` + 1 `nvidia/nemotron-3-nano-omni-30b-a3b-reasoning:free` model. Set `TOKENROUTER_API_KEY` or add `tokenrouter_api_key` to `~/.pi/free.json` ([#222](https://github.com/apmantza/pi-free/pull/222)).
33
+
34
+ - **Generic probe system** — New `lib/provider-probe.ts` factory `createProviderProbe()` handles batching, probe-cache integration, auto-hiding, and re-registration. Enables consistent probe commands across providers ([#218](https://github.com/apmantza/pi-free/pull/218)).
35
+
36
+ - **Probe commands** — New `/probe-deepinfra`, `/probe-sambanova`, `/probe-together`, `/probe-novita` commands test model availability and auto-hide broken models ([#218](https://github.com/apmantza/pi-free/pull/218)).
37
+
38
+ - **OpenCode probe commands** — `/probe-opencode` and `/probe-opencode-go` detect expired free promotions (reports only, no auto-hide) ([#218](https://github.com/apmantza/pi-free/pull/218)).
39
+
40
+ - **Session timing metrics** — `wrapSessionStartHandler()` logs wall-clock time per handler in `lib/session-start-metrics.ts`. Wrapped: cline, kilo, routeway, built-in-toggle, dynamic-built-in auto-probe ([#218](https://github.com/apmantza/pi-free/pull/218)).
41
+
42
+ ### Changed
43
+
44
+ - **Refactored `recordModelCall` signature** — Replaced 5 positional args with an options object (`RecordModelCallOptions`) for `success`, `stopReason`, and `errorMessage` ([#221](https://github.com/apmantza/pi-free/pull/221)).
45
+
46
+ - **Extracted `sleep` helper and simplified `cleanModelName`** — Shared utilities in `lib/util.ts` ([#221](https://github.com/apmantza/pi-free/pull/221)).
47
+
48
+ - **Cleanup pass on `lib/` utilities (Sprint B)** — 8 categories of code-quality refactors in [#224](https://github.com/apmantza/pi-free/pull/224):
49
+ - `open-browser.ts`: `rundll32 url.dll,FileProtocolHandler` replaces `cmd /c start` (CodeQL fix) + strict URL validation (`isSafeUrl`)
50
+ - `logger.ts`: `parseLogLevel()` validates `LOG_LEVEL` / `PI_FREE_LOG_LEVEL` env vars
51
+ - `telemetry.ts`: 1h TTL cleanup for `_inFlight` map; migrated to `createJSONStore` (drops ~80 LOC of `load`/`save`/`Lock` boilerplate)
52
+ - `util.ts`: `OpenAIModelCallbacks` parameter decouples `fetchOpenAICompatibleModels` from `lib/provider-compat.ts` (DIP fix)
53
+ - `provider-compat.ts`: extracted `isDeepSeekStyleModel()` and `isKimiModel()` predicates + new `KIMI_PROXY_COMPAT` constant
54
+ - `model-detection.ts`: removed duplicate `isModelFree` (canonical `isFreeModel` in `registry.ts` already exists)
55
+ - `registry.ts`: removed dead `_pi` parameter from `applyGlobalFilter`
56
+ - `built-in-toggle.ts`: lazy `_opencodeSession` initialisation (only created when an OpenCode provider is actually captured)
57
+
58
+ ### Removed
59
+
60
+ - **NVIDIA NIM provider** — Now a built-in Pi provider. Set `NVIDIA_API_KEY` to use directly. Removed `providers/nvidia/`, constants, config re-exports, and tests ([#218](https://github.com/apmantza/pi-free/pull/218)).
61
+
62
+ ### Security
63
+
64
+ - **CI/release hardening** — Added production dependency audit, lockfile drift check, tarball content/artifact verification, installed entry smoke-load, and pinned-action workflows. Added Dependabot config for npm and GitHub Actions. Hardened helper scripts against PATH-lookup Sonar hotspots by resolving `npm` and `tar` to fixed locations (#236).
65
+
66
+ - **open-browser: `rundll32` + strict URL validation** — Replaced `cmd /c start "" <url>` with `rundll32 url.dll,FileProtocolHandler <url>` to fix GitHub Advanced Security CodeQL `js/uncontrolled-command-line` (Critical). rundll32 does NOT parse the command line, so the URL is handed to ShellExecute as a literal. Defense-in-depth: `isSafeUrl()` allows only `http`/`https`, rejects control characters, malformed URLs, and overlong URLs (>2048 chars) ([#223](https://github.com/apmantza/pi-free/pull/223), [#224](https://github.com/apmantza/pi-free/pull/224)).
67
+
68
+ - **Path-validate env-var file overrides** — New `lib/paths.ts` centralises `PI_DATA_DIR`, `ensureDir()`, and `resolveSafeDataFile()` (rejects path separators, null bytes, dot-only, >128-char). Applied to `PI_FREE_LOG_PATH`, `PI_FREE_PROVIDER_CACHE`, `PI_FREE_TELEMETRY_FILE` ([#223](https://github.com/apmantza/pi-free/pull/223)).
69
+
70
+ - **json-persistence: lock `save`/`load` + atomic `update()`** — `Lock` mutex serialises RMW operations. `clearProviderCache` / `clearAllProviderCaches` now async, use `_cache.update()` ([#218](https://github.com/apmantza/pi-free/pull/218), [#223](https://github.com/apmantza/pi-free/pull/223)).
71
+
72
+ - **JSONL `append`/`clear` lock** — `createJSONLStore` operations are now async and lock-serialised, preventing `clear` from truncating mid-`append` ([#223](https://github.com/apmantza/pi-free/pull/223)).
73
+
74
+ - **telemetry: concurrent-write safety** — `Lock` mutex around telemetry writes; `recordModelCall` and `clearTelemetry` are now async and serialized. File path overridable via `PI_FREE_TELEMETRY_FILE` ([#218](https://github.com/apmantza/pi-free/pull/218)).
75
+
76
+ - **provider-cache: isolated copies** — `loadProviderCache` returns `structuredClone(cached.models)`; `saveProviderCache` uses `update()` for atomic RMW ([#218](https://github.com/apmantza/pi-free/pull/218)).
77
+
78
+ - **provider-probe: config RMW lock** — `config.ts` `updateConfig()` uses internal `ConfigLock` (promise-chained mutex); provider-probe auto-hide now uses it ([#223](https://github.com/apmantza/pi-free/pull/223)).
79
+
80
+ - **Prototype pollution reviver** — `safeJsonReviver()` strips `__proto__` / `constructor` keys at every `JSON.parse` level. Applied in `lib/json-persistence.ts`, `config.ts`, `lib/telemetry.ts` ([#223](https://github.com/apmantza/pi-free/pull/223)).
81
+
82
+ - **Log sanitization** — `scripts/update-benchmarks.ts` now sanitizes external API data before passing to `console.log`/error, preventing log injection (SonarCloud S5693) ([#219](https://github.com/apmantza/pi-free/pull/219)).
83
+
84
+ ## [2.0.15] - 2026-06-02
85
+
86
+ ### Fixed
87
+
88
+ - **Qwen 3.7 reasoning compat** — `qwen/qwen3.7-max` on Cline/OpenRouter uses DeepSeek-style `reasoning_content` format. Added `DEEPSEEK_PROXY_COMPAT` so Pi preserves and replays reasoning tokens correctly, preventing plan-mode hangs ([#213](https://github.com/apmantza/pi-free/pull/213)).
89
+
90
+ - **Kimi K2.6 reasoning compat** — Kimi models on NVIDIA/OpenRouter need `requiresReasoningContentOnAssistantMessages: true` to correctly replay reasoning tokens in assistant messages. Without it, the model gets stuck when trying to call tools or produce output after thinking. Refs [earendil-works/pi#5309](https://github.com/earendil-works/pi/issues/5309) ([#213](https://github.com/apmantza/pi-free/pull/213)).
91
+
92
+ - **MiniMax reasoning compat** — MiniMax M3 and other MiniMax models now have full DeepSeek-style compat (`thinkingFormat: "deepseek"`, `requiresReasoningContentOnAssistantMessages: true`). Previously, models marked `reasoning: true` without `thinkingFormat` caused Pi to enter plan mode but couldn't parse the reasoning tokens, resulting in hangs ([#212](https://github.com/apmantza/pi-free/pull/212), [#213](https://github.com/apmantza/pi-free/pull/213)).
93
+
94
+ ### Added
95
+
96
+ - **`/probe-routeway` command** — Tests each Routeway model with a minimal chat request and auto-hides models that return 5xx or 404 errors. Runs lazily on first `session_start` with 24h probe cache TTL. Follows the same pattern as `/probe-nvidia` ([#213](https://github.com/apmantza/pi-free/pull/213)).
97
+
10
98
  ## [2.0.14] - 2026-06-02
11
99
 
12
100
  ### Added
@@ -19,6 +107,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
19
107
 
20
108
  - **`_pricingKnown` / `_freeKnown` authoritatve flag** — Providers can now signal whether pricing data is authoritative via `_pricingKnown`. When `false`, `isFreeModel` falls back to name-based detection. Kilo's `isFree` API flag now flows through as `_freeKnown` ([#209](https://github.com/apmantza/pi-free/pull/209)).
21
109
 
110
+ - **MiniMax reasoning compat** — MiniMax M3 and other MiniMax models now have `supportsReasoningEffort: true` compat settings. Previously, models marked `reasoning: true` without compat caused Pi to enter plan mode without knowing the thinking format, resulting in hangs.
111
+
22
112
  ## [2.0.13] - 2026-05-21
23
113
 
24
114
  ### Added
package/README.md CHANGED
@@ -14,19 +14,21 @@ Free and paid AI model providers for [Pi](https://pi.dev). Access **free and pai
14
14
 
15
15
  When you install pi-free, it:
16
16
 
17
- 1. **Registers free-tier providers** with Pi's model picker — Kilo (free), Cline (free), NVIDIA (freemium), ZenMux (paid), CrofAI (paid), Ollama Cloud (freemium), and more
17
+ 1. **Registers free-tier providers** with Pi's model picker — Kilo (free), Cline (free), LLM7 (free), TokenRouter (1 free model), ZenMux (paid), CrofAI (paid), Ollama Cloud (freemium), SambaNova (freemium), Codestral (freemium), DeepInfra (trial credit), Together AI (trial credit), Novita (paid), Routeway (paid), and more
18
18
 
19
- 2. **Fetches models dynamically** from provider APIsNVIDIA NIM, ZenMux, CrofAI, and Pi's built-in providers (Mistral, Groq, Cerebras, xAI, Hugging Face, OpenRouter) when API keys are configured
19
+ 2. **Captures Pi's built-in OpenCode and OpenRouter providers** with a free/paid toggle OpenCode and OpenRouter are now built into Pi; pi-free adds `/toggle-opencode` and `/toggle-openrouter` so you can switch between free-only and all models without restart
20
20
 
21
- 3. **Filters to show only free models by default** for providers that expose pricing You see only the models that cost $0 to use. Paid models are hidden until you explicitly toggle them on.
21
+ 3. **Fetches models dynamically** from provider APIsZenMux, CrofAI, and Pi's built-in providers (Mistral, Groq, Cerebras, xAI, Hugging Face, OpenRouter) when API keys are configured
22
22
 
23
- 4. **Provides per-provider toggle commands** Run `/toggle-{provider}` (e.g., `/toggle-kilo`) to switch between free-only mode and showing all models including paid ones. Changes apply immediately and your preference is saved for the next Pi restart.
23
+ 4. **Filters to show only free models by default** for providers that expose pricing You see only the models that cost $0 to use. Paid models are hidden until you explicitly toggle them on.
24
24
 
25
- 5. **Handles authentication for you** — OAuth flows (Kilo, Cline) open your browser automatically; API keys are read from `~/.pi/free.json` or environment variables
25
+ 5. **Provides per-provider toggle commands** — Run `/toggle-{provider}` (e.g., `/toggle-kilo`) to switch between free-only mode and showing all models including paid ones. Changes apply immediately and your preference is saved for the next Pi restart.
26
26
 
27
- 6. **Adds Coding Index scores** — Model names include a coding benchmark score (CI: 45.2) to help you pick capable coding models at a glance
27
+ 6. **Handles authentication for you** — OAuth flows (Kilo, Cline) open your browser automatically; API keys are read from `~/.pi/free.json` or environment variables
28
28
 
29
- 7. **Persists your preferences** — Your toggle choices (free vs all models) are saved to `~/.pi/free.json` and remembered across Pi restarts
29
+ 7. **Adds Coding Index scores** — Model names include a coding benchmark score (CI: 45.2) to help you pick capable coding models at a glance
30
+
31
+ 8. **Persists your preferences** — Your toggle choices (free vs all models) are saved to `~/.pi/free.json` and remembered across Pi restarts
30
32
 
31
33
  ---
32
34
 
@@ -50,21 +52,22 @@ Free models are shown by default — look for the provider prefixes:
50
52
  - `openrouter/` — OpenRouter models (free account required)
51
53
  - `cline/` — Cline models (run `/login cline` to use)
52
54
  - `llm7/` — LLM7 gateway models (free tier: default/fast selectors, 100 req/hr)
55
+ - `tokenrouter/` — TokenRouter gateway (1 free model: `MiniMax-M3`; requires API key with credits for the rest)
53
56
 
54
57
  **🔄 Freemium (free tier with limits, then paid):**
55
58
 
56
- - `nvidia/` — NVIDIA NIM models (1,000 free requests/month, then credits)
57
59
  - `ollama-cloud/` — Ollama Cloud models (usage-based free tier, resets every 5 hours + 7 days)
58
60
  - `sambanova/` — SambaNova Cloud models (20-480 RPM free, no credit card required)
61
+ - `codestral/` — Codestral via Mistral (free Experiment plan: 2 req/min, 1B tokens/month)
59
62
 
60
63
  **💳 Paid Providers (API key with credits required):**
61
64
 
62
65
  - `zenmux/` — ZenMux AI gateway (200+ models from OpenAI, Anthropic, Google, etc.)
63
66
  - `crofai/` — CrofAI OpenAI-compatible API (streaming, reasoning models)
64
- - `codestral/` — Codestral via Mistral (free Experiment plan: 2 req/min, 1B tokens/month)
65
67
  - `deepinfra/` — DeepInfra inference cloud ($5 one-time trial credit, no credit card)
66
68
  - `novita/` — Novita AI (100+ open-source models, OpenAI-compatible, 3 free models)
67
69
  - `routeway/` — Routeway AI gateway (OpenAI-compatible, `:free` models)
70
+ - `together/` — Together AI ($1 one-time trial credit, 200+ open-source models)
68
71
 
69
72
  > **Note:** Paid providers may occasionally offer free models or promotional credits. The `isFreeModel` helper automatically detects free models based on provider pricing data or model names containing "free". For providers that don't expose pricing (like CrofAI), only models with "free" in their names are marked as free.
70
73
 
@@ -78,7 +81,7 @@ Free models are shown by default — look for the provider prefixes:
78
81
  - `openrouter/` — OpenRouter models (fetched from openrouter.ai, when `OPENROUTER_API_KEY` set)
79
82
  - `fastrouter/` — FastRouter models (always discovered, 170+ models, no auth for listing)
80
83
 
81
- **Note:** Fireworks is now a [built-in Pi provider](https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/CHANGELOG.md#0681---2026-04-22) — no extension needed. Set `FIREWORKS_API_KEY` to use it directly.
84
+ **Note:** Fireworks and NVIDIA NIM are now [built-in Pi providers](https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/CHANGELOG.md#0681---2026-04-22) — no extension needed. Set `FIREWORKS_API_KEY` or `NVIDIA_API_KEY` to use them directly.
82
85
 
83
86
  ### 3. Toggle between free and paid models
84
87
 
@@ -87,8 +90,8 @@ Want to see paid models too? Run the toggle command for your provider:
87
90
  ```
88
91
  /toggle-kilo # Toggle Kilo (✅ offers free models)
89
92
  /toggle-openrouter # Toggle OpenRouter (✅ offers free models)
93
+ /toggle-opencode # Toggle OpenCode (✅ offers free models)
90
94
  /toggle-cline # Toggle Cline (✅ offers free models)
91
- /toggle-nvidia # Toggle NVIDIA (🔄 freemium)
92
95
  /toggle-ollama # Toggle Ollama Cloud (🔄 freemium)
93
96
  /toggle-mistral # Toggle Mistral (🔧 dynamic - needs API key)
94
97
  /toggle-groq # Toggle Groq (🔧 dynamic - needs API key)
@@ -97,7 +100,7 @@ Want to see paid models too? Run the toggle command for your provider:
97
100
  /toggle-huggingface # Toggle Hugging Face (🔧 dynamic - needs HF_TOKEN)
98
101
  /toggle-zenmux # Toggle ZenMux (💳 paid - needs API key with credits)
99
102
  /toggle-crofai # Toggle CrofAI (💳 paid - needs API key with credits)
100
- /toggle-codestral # Toggle Codestral (💳 paid - free Experiment plan)
103
+ /toggle-codestral # Toggle Codestral (🔄 free Experiment plan)
101
104
  /toggle-deepinfra # Toggle DeepInfra (💳 trial credit provider)
102
105
  /toggle-together # Toggle Together AI (💳 trial credit provider)
103
106
  /toggle-sambanova # Toggle SambaNova (🔄 freemium)
@@ -105,6 +108,7 @@ Want to see paid models too? Run the toggle command for your provider:
105
108
  /toggle-novita # Toggle Novita AI (💳 paid — 3 free models)
106
109
  /toggle-routeway # Toggle Routeway AI (💳 paid — has :free models)
107
110
  /toggle-fastrouter # Toggle FastRouter (🔧 dynamic — always discovered)
111
+ /toggle-tokenrouter # Toggle TokenRouter (💳 paid — 1 free model)
108
112
  ```
109
113
 
110
114
  **Notes:**
@@ -126,7 +130,6 @@ Add your API keys to this file:
126
130
 
127
131
  ```json
128
132
  {
129
- "nvidia_api_key": "nvapi-...",
130
133
  "ollama_api_key": "...",
131
134
  "mistral_api_key": "...",
132
135
  "codestral_api_key": "...",
@@ -139,7 +142,7 @@ Add your API keys to this file:
139
142
  }
140
143
  ```
141
144
 
142
- Or set environment variables instead (same names, uppercase: `OPENROUTER_API_KEY`, `NVIDIA_API_KEY`, etc.)
145
+ Or set environment variables instead (same names, uppercase: `OPENROUTER_API_KEY`, `OLLAMA_API_KEY`, etc.)
143
146
 
144
147
  If `~/.pi/free.json` contains invalid JSON, pi-free now logs the parse error to `~/.pi/free.log` so you can fix the file quickly.
145
148
 
@@ -147,27 +150,35 @@ See the [Providers That Need Authentication](#providers-that-need-authentication
147
150
 
148
151
  ### 5. Quick commands reference
149
152
 
150
- | Command | What it does |
151
- | -------------------- | --------------------------------------------------------- |
152
- | `/toggle-{provider}` | Switch between free-only and all models for that provider |
153
- | `/toggle-free` | Toggle global free-only mode for ALL providers |
154
- | `/free-providers` | Show free/paid model counts for all providers |
155
- | `/login kilo` | Start OAuth flow for Kilo |
156
- | `/login cline` | Start OAuth flow for Cline |
157
- | `/logout kilo` | Clear Kilo OAuth credentials |
158
- | `/logout cline` | Clear Cline OAuth credentials |
153
+ | Command | What it does |
154
+ | -------------------------- | --------------------------------------------------------- |
155
+ | `/toggle-{provider}` | Switch between free-only and all models for that provider |
156
+ | `/toggle-free` | Toggle global free-only mode for ALL providers |
157
+ | `/free-providers` | Show free/paid model counts for all providers |
158
+ | `/free-telemetry` | Show real-world performance data (tokens/s, latency, success rate) for free models |
159
+ | `/clear-free-telemetry` | Clear all stored telemetry data |
160
+ | `/login kilo` | Start OAuth flow for Kilo |
161
+ | `/login cline` | Start OAuth flow for Cline |
162
+ | `/logout kilo` | Clear Kilo OAuth credentials |
163
+ | `/logout cline` | Clear Cline OAuth credentials |
159
164
 
160
165
  ---
161
166
 
162
167
  ## Features
163
168
 
164
- ### 🔍 NVIDIA: Pre-Filtering + 404 Detection
169
+ ### 🔍 Model Availability Probing
170
+
171
+ Some provider APIs list models that return errors when you try to use them (expired free promotions, decommissioned models, server spin-down). pi-free automatically detects and hides broken models:
165
172
 
166
- NVIDIA's API lists 130+ models, but 57+ return 404 "Function not found" when you try to use them. pi-free solves this:
173
+ - **Ollama Cloud**: `/probe-ollama` probes for 403 errors, auto-hides inaccessible models
174
+ - **Routeway**: `/probe-routeway` — probes for 5xx/404 errors, auto-hides broken models
175
+ - **OpenCode**: `/probe-opencode`, `/probe-opencode-go` — probes for expired free promotions (reports only, no auto-hide)
176
+ - **DeepInfra**: `/probe-deepinfra` — probes for 404/5xx errors, auto-hides broken models
177
+ - **SambaNova**: `/probe-sambanova` — probes for 404/5xx errors, auto-hides broken models
178
+ - **Together AI**: `/probe-together` — probes for 404/5xx errors, auto-hides broken models
179
+ - **Novita AI**: `/probe-novita` — probes for 404/5xx errors, auto-hides broken models
167
180
 
168
- - **57 known 404s hard-filtered** Discontinued models (`dbrx-instruct`, `codellama-70b`), embedding models mislabeled as chat-capable (`nv-embed-*`), and stale catalog entries are silently excluded
169
- - **Auto-discovery from NVIDIA's API** — Queries `integrate.api.nvidia.com/v1/models` directly for the ground-truth list
170
- - **`/probe-nvidia` command** — On-demand health check: tests every model with a minimal request, auto-hides new 404s, and re-registers immediately
181
+ All probes use a **24-hour probe cache** to avoid re-checking recently-verified models. Run any probe command manually to force a full re-check, or let the lazy auto-probe on first `session_start` handle it.
171
182
 
172
183
  ### 🎯 Coding Index (CI) Scores
173
184
 
@@ -175,13 +186,13 @@ Every model shows a **Coding Index score** (e.g., `CI: 52.3`) in the model picke
175
186
 
176
187
  - **Benchmark-based** — Scores derived from Artificial Analysis coding benchmarks (HumanEval, MBPP, etc.)
177
188
  - **Quality indicator** — Higher scores = better coding performance
178
- - **All providers** — Applied to every model from every provider (NVIDIA, Mistral, Groq, etc.)
189
+ - **All providers** — Applied to every model from every provider (Mistral, Groq, Cerebras, etc.)
179
190
 
180
191
  **Missing CI scores?** Provider model IDs often don't match benchmark database keys exactly. pi-free applies provider-specific normalization to improve matching:
181
192
 
182
193
  | Provider | Normalization Applied |
183
194
  | ------------ | ------------------------------------------------------------------ |
184
- | **NVIDIA** | Strips vendor prefixes (`meta/`, `mistralai/`, `microsoft/`, etc.) |
195
+ | **Fireworks** | Strips vendor prefixes (`meta/`, `mistralai/`, `microsoft/`, etc.) |
185
196
  | **Groq** | Removes `-versatile` and numeric suffixes (`-32768`) |
186
197
  | **Cerebras** | Normalizes `llama3.1` → `llama-3.1`, adds `instruct` suffix |
187
198
  | **Mistral** | Strips `-latest` suffix |
@@ -194,6 +205,7 @@ Every model shows a **Coding Index score** (e.g., `CI: 52.3`) in the model picke
194
205
  Providers have different pricing models. pi-free handles them all:
195
206
 
196
207
  - **Free-only by default** — Shows only zero-cost models initially
208
+ - **Auto-probe on session_start** — Lazy background probes detect broken models automatically on your first session; no manual command needed
197
209
  - **Per-provider toggles** — Run `/toggle-{provider}` to switch between "free only" vs "all models"
198
210
  - **Persists across sessions** — Your preference is saved to `~/.pi/free.json`
199
211
  - **Instant updates** — Changes apply immediately; no Pi restart needed
@@ -201,7 +213,7 @@ Providers have different pricing models. pi-free handles them all:
201
213
  **Provider types:**
202
214
 
203
215
  - ✅ **Free providers** (Kilo, Cline) — Toggle between free-only vs paid models
204
- - 🔄 **Freemium** (NVIDIA, Ollama) — Free tier with limits, toggle shows all
216
+ - 🔄 **Freemium** (Ollama, SambaNova) — Free tier with limits, toggle shows all
205
217
  - 🔧 **Dynamic API** (Mistral, Groq, Cerebras, xAI) — Fetched when API key configured, toggle filters the list
206
218
 
207
219
  ### 🔐 OAuth + API Key Handling
@@ -283,44 +295,9 @@ Then use `/toggle-openrouter` to switch between free-only and all models.
283
295
 
284
296
  **Note:** `openrouter_api_key` in `~/.pi/free.json` is ignored. OpenRouter always reads from Pi's auth system to avoid stale keys.
285
297
 
286
- ### NVIDIA NIM (Free Credits System)
287
-
288
- NVIDIA provides **free monthly credits** (1000 requests/month) at [build.nvidia.com](https://build.nvidia.com).
289
-
290
- **Important:** Models have different "costs" per token:
291
-
292
- - **Zero-cost models**: Don't consume your credit balance (shown by default)
293
- - **Credit-costing models**: Consume credits faster (hidden by default)
294
-
295
- Get your API key and optionally enable all models:
296
-
297
- **Option A: Show only free models (default)**
298
-
299
- ```bash
300
- export NVIDIA_API_KEY="nvapi-..."
301
- ```
302
-
303
- Uses only zero-cost models → your 1000 credits last the full month
298
+ ### NVIDIA NIM (now built-in)
304
299
 
305
- **Option B: Show all models (uses credits faster)**
306
-
307
- ```bash
308
- export NVIDIA_API_KEY="nvapi-..."
309
- export NVIDIA_SHOW_PAID=true
310
- ```
311
-
312
- Or in `~/.pi/free.json`:
313
-
314
- ```json
315
- {
316
- "nvidia_api_key": "nvapi-...",
317
- "nvidia_show_paid": true
318
- }
319
- ```
320
-
321
- Toggle anytime with `/toggle-nvidia`
322
-
323
- **Models available:** Llama 4/3.x, Mistral Small 3.1, DeepSeek R1, Gemma 4, Kimi K2.5/2.6, Qwen 3/2.5, OpenAI GPT-OSS, and more.
300
+ NVIDIA NIM is now a **built-in Pi provider** no extension needed. Set `NVIDIA_API_KEY` to use it directly with Pi's built-in model picker.
324
301
 
325
302
  ### Ollama Cloud
326
303
 
@@ -437,21 +414,25 @@ Each provider has toggle commands to switch between free and all models:
437
414
  | ----------------------- | -------------------------------------------------------- |
438
415
  | `/toggle-kilo` | Toggle between free/all Kilo models |
439
416
  | `/toggle-openrouter` | Toggle between free/all OpenRouter models |
417
+ | `/toggle-opencode` | Toggle between free/all OpenCode models |
440
418
  | `/toggle-cline` | Toggle between free/all Cline models |
441
- | `/toggle-nvidia` | Toggle between free/all NVIDIA models |
442
419
  | `/toggle-ollama` | Toggle between free/all Ollama Cloud models |
443
420
  | `/toggle-mistral` | Toggle between free/all Mistral models (🔧 dynamic) |
444
421
  | `/toggle-groq` | Toggle between free/all Groq models (🔧 dynamic) |
445
422
  | `/toggle-cerebras` | Toggle between free/all Cerebras models (🔧 dynamic) |
446
423
  | `/toggle-xai` | Toggle between free/all xAI models (🔧 dynamic) |
447
- | `/toggle-huggingface` | Toggle between free/all Hugging Face models (🔧 dynamic) |
448
- | `/toggle-codestral` | Toggle Codestral (💳 paid) |
424
+ | `/toggle-huggingface` | Toggle between free/all Hugging Face models (🔧 dynamic) |
425
+ | `/toggle-codestral` | Toggle Codestral (🔄 freemium) |
449
426
  | `/toggle-deepinfra` | Toggle DeepInfra (💳 trial credit) |
450
427
  | `/toggle-together` | Toggle Together AI (💳 trial credit) |
451
428
  | `/toggle-sambanova` | Toggle SambaNova (🔄 freemium) |
452
429
  | `/toggle-llm7` | Toggle LLM7 (✅ free gateway) |
453
430
  | `/toggle-zenmux` | Toggle ZenMux (💳 paid) |
454
431
  | `/toggle-crofai` | Toggle CrofAI (💳 paid) |
432
+ | `/toggle-novita` | Toggle Novita AI (💳 paid) |
433
+ | `/toggle-routeway` | Toggle Routeway AI (💳 paid) |
434
+ | `/toggle-fastrouter` | Toggle FastRouter (🔧 dynamic) |
435
+ | `/toggle-tokenrouter` | Toggle TokenRouter (💳 paid — 1 free model) |
455
436
  | `/ollama-cloud-refresh` | Re-fetch Ollama Cloud models live (no restart needed) |
456
437
  | `/probe-ollama` | Test Ollama Cloud models for 403 errors (auto-hide) |
457
438
 
@@ -465,12 +446,18 @@ Each provider has toggle commands to switch between free and all models:
465
446
 
466
447
  ### Probe Commands (Health Check)
467
448
 
468
- Test models for 404/403 errors and auto-hide broken ones:
449
+ Test models for errors and auto-hide broken ones:
469
450
 
470
- | Command | What it does |
471
- | --------------- | ----------------------------------------------------------- |
472
- | `/probe-nvidia` | Test all NVIDIA models, auto-hide 404s in `~/.pi/free.json` |
473
- | `/probe-ollama` | Test all Ollama models, auto-hide 403s in `~/.pi/free.json` |
451
+ | Command | What it does |
452
+ | ---------------------- | ----------------------------------------------------------- |
453
+ | `/probe-ollama` | Test all Ollama Cloud models, auto-hide 403s |
454
+ | `/probe-routeway` | Test all Routeway models, auto-hide 5xx/404s |
455
+ | `/probe-opencode` | Test all OpenCode free models for expired promotions |
456
+ | `/probe-opencode-go` | Test all OpenCode Go free models for expired promotions |
457
+ | `/probe-deepinfra` | Test all DeepInfra models for availability, auto-hide broken|
458
+ | `/probe-sambanova` | Test all SambaNova models for availability, auto-hide broken|
459
+ | `/probe-together` | Test all Together AI models for availability, auto-hide broken|
460
+ | `/probe-novita` | Test all Novita AI models for availability, auto-hide broken|
474
461
 
475
462
  **How it works:**
476
463
 
@@ -490,7 +477,6 @@ Create `~/.pi/free.json` in your home directory:
490
477
 
491
478
  ```json
492
479
  {
493
- "nvidia_api_key": "YOUR_NVIDIA_KEY",
494
480
  "mistral_api_key": "YOUR_MISTRAL_KEY",
495
481
  "ollama_api_key": "YOUR_OLLAMA_KEY",
496
482
  "ollama_show_paid": true,
@@ -501,8 +487,8 @@ Create `~/.pi/free.json` in your home directory:
501
487
  Or use environment variables (same names, uppercase):
502
488
 
503
489
  ```bash
504
- export NVIDIA_API_KEY="..."
505
490
  export MISTRAL_API_KEY="..."
491
+ export OLLAMA_API_KEY="..."
506
492
  ```
507
493
 
508
494
  ---
package/banner.svg CHANGED
@@ -23,14 +23,6 @@
23
23
  <stop offset="0%" stop-color="#06b6d4" stop-opacity="0.15"/>
24
24
  <stop offset="100%" stop-color="#06b6d4" stop-opacity="0.05"/>
25
25
  </linearGradient>
26
- <linearGradient id="card3" x1="0" y1="0" x2="0" y2="1">
27
- <stop offset="0%" stop-color="#10b981" stop-opacity="0.15"/>
28
- <stop offset="100%" stop-color="#10b981" stop-opacity="0.05"/>
29
- </linearGradient>
30
- <linearGradient id="card4" x1="0" y1="0" x2="0" y2="1">
31
- <stop offset="0%" stop-color="#f59e0b" stop-opacity="0.15"/>
32
- <stop offset="100%" stop-color="#f59e0b" stop-opacity="0.05"/>
33
- </linearGradient>
34
26
  <filter id="glow">
35
27
  <feGaussianBlur stdDeviation="3" result="blur"/>
36
28
  <feMerge>
@@ -74,61 +66,54 @@
74
66
  Free &amp; Paid AI Model Providers for Pi
75
67
  </text>
76
68
 
77
- <!-- Subtitle -->
78
- <text x="160" y="178" font-family="system-ui, -apple-system, sans-serif" font-size="13" fill="#7c8a9a" letter-spacing="0.02em">
79
- </text>
80
-
81
- <!-- Provider badges -->
69
+ <!-- Provider category badges -->
82
70
  <g transform="translate(160, 200)">
83
- <!-- Free -->
84
71
  <rect x="0" y="0" width="90" height="28" rx="6" fill="#10b981" opacity="0.15" stroke="#10b981" stroke-width="0.5" stroke-opacity="0.3"/>
85
- <text x="45" y="18" font-family="system-ui, sans-serif" font-size="11" fill="#6ee7b7" text-anchor="middle" font-weight="600">✅ Free</text>
72
+ <text x="45" y="18" font-family="system-ui, sans-serif" font-size="11" fill="#6ee7b7" text-anchor="middle" font-weight="600">Free</text>
86
73
  </g>
87
74
 
88
75
  <g transform="translate(260, 200)">
89
76
  <rect x="0" y="0" width="100" height="28" rx="6" fill="#f59e0b" opacity="0.15" stroke="#f59e0b" stroke-width="0.5" stroke-opacity="0.3"/>
90
- <text x="50" y="18" font-family="system-ui, sans-serif" font-size="11" fill="#fcd34d" text-anchor="middle" font-weight="600">🔄 Freemium</text>
77
+ <text x="50" y="18" font-family="system-ui, sans-serif" font-size="11" fill="#fcd34d" text-anchor="middle" font-weight="600">Freemium</text>
91
78
  </g>
92
79
 
93
80
  <g transform="translate(370, 200)">
94
- <rect x="0" y="0" width="90" height="28" rx="6" fill="#7c3aed" opacity="0.15" stroke="#7c3aed" stroke-width="0.5" stroke-opacity="0.3"/>
95
- <text x="45" y="18" font-family="system-ui, sans-serif" font-size="11" fill="#a78bfa" text-anchor="middle" font-weight="600">🔧 Dynamic</text>
81
+ <rect x="0" y="0" width="100" height="28" rx="6" fill="#7c3aed" opacity="0.15" stroke="#7c3aed" stroke-width="0.5" stroke-opacity="0.3"/>
82
+ <text x="50" y="18" font-family="system-ui, sans-serif" font-size="11" fill="#a78bfa" text-anchor="middle" font-weight="600">Dynamic</text>
96
83
  </g>
97
84
 
98
- <g transform="translate(470, 200)">
85
+ <g transform="translate(480, 200)">
99
86
  <rect x="0" y="0" width="90" height="28" rx="6" fill="#ef4444" opacity="0.15" stroke="#ef4444" stroke-width="0.5" stroke-opacity="0.3"/>
100
- <text x="45" y="18" font-family="system-ui, sans-serif" font-size="11" fill="#fca5a5" text-anchor="middle" font-weight="600">💳 Paid</text>
87
+ <text x="45" y="18" font-family="system-ui, sans-serif" font-size="11" fill="#fca5a5" text-anchor="middle" font-weight="600">Paid</text>
101
88
  </g>
102
89
 
103
90
  <!-- Provider cards (right side) -->
104
91
  <g transform="translate(700, 55)">
105
- <!-- Card 1: Custom Providers -->
106
92
  <rect x="0" y="0" width="250" height="170" rx="12" fill="url(#card1)" stroke="#7c3aed" stroke-width="0.5" stroke-opacity="0.2" filter="url(#shadow)"/>
107
93
  <rect x="0" y="0" width="250" height="170" rx="12" fill="none" stroke="url(#accent)" stroke-width="0.5" opacity="0.1"/>
108
- <text x="20" y="28" font-family="system-ui, sans-serif" font-size="13" font-weight="700" fill="#c4b5fd">Custom Providers</text>
109
- <text x="20" y="50" font-family="system-ui, sans-serif" font-size="11" fill="#8b9aaa">Kilo · Cline · NVIDIA</text>
110
- <text x="20" y="70" font-family="system-ui, sans-serif" font-size="11" fill="#8b9aaa">Ollama Cloud · ZenMux</text>
111
- <text x="20" y="90" font-family="system-ui, sans-serif" font-size="11" fill="#8b9aaa">CrofAI · Codestral · LLM7</text>
112
- <text x="20" y="110" font-family="system-ui, sans-serif" font-size="11" fill="#8b9aaa">DeepInfra · SambaNova</text>
113
- <text x="20" y="130" font-family="system-ui, sans-serif" font-size="11" fill="#8b9aaa">Together · Novita · FastRouter</text>
94
+ <text x="20" y="28" font-family="system-ui, sans-serif" font-size="13" font-weight="700" fill="#c4b5fd">Providers</text>
95
+ <text x="20" y="50" font-family="system-ui, sans-serif" font-size="11" fill="#8b9aaa">Kilo · Cline · OpenCode</text>
96
+ <text x="20" y="70" font-family="system-ui, sans-serif" font-size="11" fill="#8b9aaa">Ollama Cloud · SambaNova</text>
97
+ <text x="20" y="90" font-family="system-ui, sans-serif" font-size="11" fill="#8b9aaa">Codestral · LLM7 · Novita</text>
98
+ <text x="20" y="110" font-family="system-ui, sans-serif" font-size="11" fill="#8b9aaa">ZenMux · CrofAI · DeepInfra</text>
99
+ <text x="20" y="130" font-family="system-ui, sans-serif" font-size="11" fill="#8b9aaa">Together · TokenRouter · FastRouter</text>
114
100
  </g>
115
101
 
116
102
  <g transform="translate(970, 55)">
117
- <!-- Card 2: Features -->
118
103
  <rect x="0" y="0" width="250" height="170" rx="12" fill="url(#card2)" stroke="#06b6d4" stroke-width="0.5" stroke-opacity="0.2" filter="url(#shadow)"/>
119
104
  <rect x="0" y="0" width="250" height="170" rx="12" fill="none" stroke="url(#accent2)" stroke-width="0.5" opacity="0.1"/>
120
105
  <text x="20" y="28" font-family="system-ui, sans-serif" font-size="13" font-weight="700" fill="#67e8f9">Features</text>
121
- <text x="20" y="50" font-family="system-ui, sans-serif" font-size="11" fill="#8b9aaa">✦ Free model auto-detection</text>
122
- <text x="20" y="68" font-family="system-ui, sans-serif" font-size="11" fill="#8b9aaa">✦ Per-provider toggles</text>
123
- <text x="20" y="86" font-family="system-ui, sans-serif" font-size="11" fill="#8b9aaa">✦ OAuth flows (Kilo, Cline)</text>
124
- <text x="20" y="104" font-family="system-ui, sans-serif" font-size="11" fill="#8b9aaa">✦ Coding Index (CI) scores</text>
125
- <text x="20" y="122" font-family="system-ui, sans-serif" font-size="11" fill="#8b9aaa">✦ Model health probes</text>
126
- <text x="20" y="140" font-family="system-ui, sans-serif" font-size="11" fill="#8b9aaa">✦ Thinking level maps</text>
127
- <text x="20" y="158" font-family="system-ui, sans-serif" font-size="11" fill="#8b9aaa">✦ 404/403 auto-hide on probe</text>
106
+ <text x="20" y="50" font-family="system-ui, sans-serif" font-size="11" fill="#8b9aaa">Free model auto-detection</text>
107
+ <text x="20" y="68" font-family="system-ui, sans-serif" font-size="11" fill="#8b9aaa">Per-provider toggles</text>
108
+ <text x="20" y="86" font-family="system-ui, sans-serif" font-size="11" fill="#8b9aaa">OAuth flows (Kilo, Cline)</text>
109
+ <text x="20" y="104" font-family="system-ui, sans-serif" font-size="11" fill="#8b9aaa">Coding Index (CI) scores</text>
110
+ <text x="20" y="122" font-family="system-ui, sans-serif" font-size="11" fill="#8b9aaa">Model health probes</text>
111
+ <text x="20" y="140" font-family="system-ui, sans-serif" font-size="11" fill="#8b9aaa">Thinking level maps</text>
112
+ <text x="20" y="158" font-family="system-ui, sans-serif" font-size="11" fill="#8b9aaa">404/403 auto-hide on probe</text>
128
113
  </g>
129
114
 
130
115
  <!-- Bottom tagline -->
131
116
  <text x="640" y="305" font-family="system-ui, -apple-system, sans-serif" font-size="12" fill="#5a6a7a" text-anchor="middle" letter-spacing="0.04em">
132
- npx pi install git:github.com/apmantza/pi-free
117
+ pi install git:github.com/apmantza/pi-free
133
118
  </text>
134
119
  </svg>