Repository navigation
fix(catalog): reclassify PublicAI from keyless to one-time-initial (requires API key) (#3558) - #3568
Conversation
…equires API key) (#3558)
There was a problem hiding this comment.
Code Review
This pull request corrects the classification of PublicAI models, which were previously miscatalogued as keyless/free, by updating their freeType to one-time-initial and setting hasFree to false in the provider registry. A new unit test was also added to prevent regressions. Feedback on these changes suggests removing the PublicAI entries from the free model catalog entirely to avoid dead entries, and refactoring the new unit test to use Vitest instead of Node's built-in test runner to maintain consistency with the repository's testing framework.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| { provider: "publicai", modelId: "swiss-ai/apertus-70b-instruct", displayName: "swiss-ai/apertus-70b-instruct", monthlyTokens: 0, creditTokens: 0, freeType: "one-time-initial", poolKey: "publicai", tos: "caution" }, | ||
| { provider: "publicai", modelId: "aisingapore/Qwen-SEA-LION-v4-32B-IT", displayName: "aisingapore/Qwen-SEA-LION-v4-32B-IT", monthlyTokens: 0, creditTokens: 0, freeType: "one-time-initial", poolKey: "publicai", tos: "caution" }, | ||
| { provider: "publicai", modelId: "allenai/Olmo-3-32B-Think", displayName: "allenai/Olmo-3-32B-Think", monthlyTokens: 0, creditTokens: 0, freeType: "one-time-initial", poolKey: "publicai", tos: "caution" }, |
There was a problem hiding this comment.
Since publicai is now marked as hasFree: false in providers.ts and has both monthlyTokens: 0 and creditTokens: 0, these models are no longer part of any active free tier or budget. Keeping them in FREE_MODEL_BUDGETS (which is specifically for free model budgets) is inconsistent and could lead to dead entries or unexpected behavior in the UI/routing logic.
Consider removing these three publicai entries from FREE_MODEL_BUDGETS entirely instead of reclassifying them to one-time-initial with zero tokens.
| import test from "node:test"; | ||
| import assert from "node:assert/strict"; | ||
| import { FREE_MODEL_BUDGETS } from "../../open-sse/config/freeModelCatalog.data.ts"; | ||
|
|
||
| // Regression for #3558: PublicAI was catalogued with freeType:"keyless" (in the RECURRING set, | ||
| // so it surfaced as keyless-free and could be picked into the no-auth pool with no Authorization | ||
| // header). But the provider registry requires a key (authType:"apikey"), and freeTierCatalog.ts | ||
| // already excludes publicai from recurring free budgets — an internal inconsistency. PublicAI | ||
| // grants a one-time signup credit then bills, so it must NOT be "keyless". | ||
|
|
||
| test("#3558 PublicAI has no freeType:keyless catalog entries", () => { | ||
| const keyless = FREE_MODEL_BUDGETS.filter( | ||
| (b) => b.provider === "publicai" && b.freeType === "keyless" | ||
| ); | ||
| assert.equal(keyless.length, 0, `publicai must not be keyless; found ${keyless.length}`); | ||
| }); | ||
|
|
||
| test("#3558 PublicAI catalog entries are classified one-time-initial", () => { | ||
| const entries = FREE_MODEL_BUDGETS.filter((b) => b.provider === "publicai"); | ||
| assert.ok(entries.length > 0, "publicai still has catalog entries"); | ||
| for (const e of entries) { | ||
| assert.equal(e.freeType, "one-time-initial", `${e.modelId} should be one-time-initial`); | ||
| } | ||
| }); |
There was a problem hiding this comment.
Since the project uses Vitest (as indicated by vitest.config.ts in the root), it is highly recommended to use vitest for writing unit tests instead of Node's built-in node:test and node:assert. This ensures consistent test execution, reporting, and coverage analysis across the codebase.
If you decide to remove the publicai entries from FREE_MODEL_BUDGETS entirely (as suggested in the other comment), this test can be simplified to assert that FREE_MODEL_BUDGETS contains zero entries for publicai. Below is the suggested implementation using Vitest.
| import test from "node:test"; | |
| import assert from "node:assert/strict"; | |
| import { FREE_MODEL_BUDGETS } from "../../open-sse/config/freeModelCatalog.data.ts"; | |
| // Regression for #3558: PublicAI was catalogued with freeType:"keyless" (in the RECURRING set, | |
| // so it surfaced as keyless-free and could be picked into the no-auth pool with no Authorization | |
| // header). But the provider registry requires a key (authType:"apikey"), and freeTierCatalog.ts | |
| // already excludes publicai from recurring free budgets — an internal inconsistency. PublicAI | |
| // grants a one-time signup credit then bills, so it must NOT be "keyless". | |
| test("#3558 PublicAI has no freeType:keyless catalog entries", () => { | |
| const keyless = FREE_MODEL_BUDGETS.filter( | |
| (b) => b.provider === "publicai" && b.freeType === "keyless" | |
| ); | |
| assert.equal(keyless.length, 0, `publicai must not be keyless; found ${keyless.length}`); | |
| }); | |
| test("#3558 PublicAI catalog entries are classified one-time-initial", () => { | |
| const entries = FREE_MODEL_BUDGETS.filter((b) => b.provider === "publicai"); | |
| assert.ok(entries.length > 0, "publicai still has catalog entries"); | |
| for (const e of entries) { | |
| assert.equal(e.freeType, "one-time-initial", `${e.modelId} should be one-time-initial`); | |
| } | |
| }); | |
| import { test, expect } from "vitest"; | |
| import { FREE_MODEL_BUDGETS } from "../../open-sse/config/freeModelCatalog.data.ts"; | |
| // Regression for #3558: PublicAI requires an API key and is not part of the free model catalog. | |
| test("#3558 PublicAI has no entries in the free model catalog", () => { | |
| const entries = FREE_MODEL_BUDGETS.filter((b) => b.provider === "publicai"); | |
| expect(entries.length).toBe(0); | |
| }); |
References
- The repository uses Vitest as its official testing framework (as indicated by vitest.config.ts and Vitest files references in the style guide). Unit tests should use Vitest APIs rather than node:test. (link)
Code Review SummaryStatus: No Issues Found | Recommendation: Merge This PR correctly addresses #3558 by fixing an internal inconsistency where PublicAI was miscatalogued as keyless/free when it actually requires an API key. The changes are:
All changes are consistent with the provider registry which already specifies Files Reviewed (4 files)
Reviewed by laguna-m.1-20260312:free · 1,082,400 tokens |
* chore(release): open v3.8.20 development cycle * fix(images): prefer bare combos over image aliases (#3527) Integrated into release/v3.8.20 * fix(translator): map Codex local_shell tool (#3534) Integrated into release/v3.8.20 * fix(usage): make opencode-go quota fetcher fail-open instead of throwing 500 (#3522) Integrated into release/v3.8.20 * Fix Runtime page breaker state rendering (#3533) Integrated into release/v3.8.20 * Expose provider breaker degradation threshold setting (#3535) Integrated into release/v3.8.20 * fix(executor): strip provider prefix from versioned built-in tool model field (#3532) Integrated into release/v3.8.20 * feat(providers): add Claude Fable 5 support (#3524) Integrated into release/v3.8.20 * feat(resilience): add global provider cooldown tracking to prevent combo re-walking (#3556) Integrated into release/v3.8.20 (default OFF, opt-in) * fix(translator): scope thoughtSignature bypass to Antigravity/CLI only (#3560) Integrated into release/v3.8.20. Co-authored-by: Six7Day <six7day@gmail.com> * fix(routing): normalize thinking:disabled for combo-substituted models that reject it (#3554) (#3563) Integrated into release/v3.8.20 * fix(usage): accept 0/empty budget limits so the dashboard can save and clear (#3537) (#3564) Integrated into release/v3.8.20 * docs(changelog): credit @Six7Day for #3560 thoughtSignature fix (#3414) The #3560 squash co-author trailer landed inline (unparsed by GitHub), so add an explicit CHANGELOG credit ensuring @Six7Day (original #3414) and @oyi77 are on the public record for the Gemini thoughtSignature fix. * fix(gamification): dedup badge unlock via user_badges so events don't re-fire every request (#3472) (#3565) Integrated into release/v3.8.20 * fix(routing): pass through 'auto' keyword on codex /v1/responses instead of rewriting to codex/auto (#3509) (#3566) Integrated into release/v3.8.20 * fix(cli-tools): normalize apiKey null in guide-settings schema so cloud-mode config saves (#3552) (#3567) Integrated into release/v3.8.20 * fix(catalog): reclassify PublicAI from keyless to one-time-initial (requires API key) (#3558) (#3568) Integrated into release/v3.8.20 * fix(gemini-web): surface missing Playwright browser as actionable 503 + cooldown hint, not a retryable 500 loop (#3516) (#3570) Integrated into release/v3.8.20 * fix(security): sanitize raw err.message in web executors + embeddings/search response bodies (Rule #12) (#3494, #3495) (#3573) Integrated into release/v3.8.20 * fix(dashboard): point CustomHostsManager + FeatureFlagsGrid at real routes (#3486, #3487) (#3574) Integrated into release/v3.8.20 * chore(providers): remove dead krutrim entry (#3483) + docs(api): fix agent-bridge per-agent state route (#3489) (#3575) Integrated into release/v3.8.20 * docs(api): correct API_REFERENCE.md paths for skills/plugins/admin/cache/acp/system-info (#3497) (#3577) Integrated into release/v3.8.20 * fix(proxy): drive SOCKS5 UI option from runtime ENABLE_SOCKS5_PROXY, not build-time NEXT_PUBLIC (#3508) (#3579) Integrated into release/v3.8.20 * fix(playground): filter playground models by node prefix so custom-endpoint models appear (#3505) (#3581) Integrated into release/v3.8.20 * fix(usage): show an informative message instead of a blank Kiro quota card when no usage breakdown (#3506) (#3582) Integrated into release/v3.8.20 * docs(changelog): add the #3506 Kiro quota entry (missed in #3582 due to a stale-base CHANGELOG anchor) (#3583) Integrated into release/v3.8.20 * fix(auto-update): use stable PROJECT_ROOT walker, not frozen process.cwd() (#3561) Integrated into release/v3.8.20. Auto-update PROJECT_ROOT now uses a stable __dirname-anchored upward walker instead of the no-op process.cwd() resolver. * fix: address PR #3518 review comments (lifecycle hooks, regex, indentation, route params) (#3562) Integrated into release/v3.8.20. Addresses #3518 review: regex literals, logs/[id] route params (Next 16), indentation, and wires plugin lifecycle hooks (onInstall/onActivate/onDeactivate/onUninstall) in the loader so manager.ts can register them. Adds Rule #18 regression test. * docs(changelog): credit @ViFigueiredo (#3423) for PROJECT_ROOT + log #3561/#3562 (v3.8.20) * fix: openai to gemini incorrectly translates historical tool calls into text (#3569) Integrated into release/v3.8.20. Standard Gemini direct path now maps historical tool calls to native functionCall/functionResponse parts (signaturelessToolCallMode: native) instead of inert text — validated against the real Gemini API (gemini-2.5-flash returns 200 for signatureless native functionCall, even with tools+thinking; Hard Rule #18). Eliminates the text-serialization leak. Antigravity/CLI sentinel path (#3560) untouched. * docs(changelog)+test: reconcile standard-Gemini native mode (#3569) — update round-2 rationale comment + log VPS validation * docs(changelog): reconcile v3.8.20 — add 9 missing bullets + move [Unreleased] to versioned section * docs(changelog): complete v3.8.20 reconciliation — 27 bullets, 11 contributors --------- Co-authored-by: Alexander Averyanov <alex@averyan.ru> Co-authored-by: Hakan Kurşun <bykamaka@gmail.com> Co-authored-by: Wilson <pedbookmed@gmail.com> Co-authored-by: Randi <55005611+rdself@users.noreply.github.com> Co-authored-by: Giorgos Giakoumettis <giorgos@yiakoumettis.gr> Co-authored-by: PizzaV <103120356+pizzav-xyz@users.noreply.github.com> Co-authored-by: Paijo <14921983+oyi77@users.noreply.github.com> Co-authored-by: Markus Hartung <mail@hartmark.se>
* chore(release): open v3.8.20 development cycle * fix(images): prefer bare combos over image aliases (cheaper-inference#3527) Integrated into release/v3.8.20 * fix(translator): map Codex local_shell tool (cheaper-inference#3534) Integrated into release/v3.8.20 * fix(usage): make opencode-go quota fetcher fail-open instead of throwing 500 (cheaper-inference#3522) Integrated into release/v3.8.20 * Fix Runtime page breaker state rendering (cheaper-inference#3533) Integrated into release/v3.8.20 * Expose provider breaker degradation threshold setting (cheaper-inference#3535) Integrated into release/v3.8.20 * fix(executor): strip provider prefix from versioned built-in tool model field (cheaper-inference#3532) Integrated into release/v3.8.20 * feat(providers): add Claude Fable 5 support (cheaper-inference#3524) Integrated into release/v3.8.20 * feat(resilience): add global provider cooldown tracking to prevent combo re-walking (cheaper-inference#3556) Integrated into release/v3.8.20 (default OFF, opt-in) * fix(translator): scope thoughtSignature bypass to Antigravity/CLI only (cheaper-inference#3560) Integrated into release/v3.8.20. Co-authored-by: Six7Day <six7day@gmail.com> * fix(routing): normalize thinking:disabled for combo-substituted models that reject it (cheaper-inference#3554) (cheaper-inference#3563) Integrated into release/v3.8.20 * fix(usage): accept 0/empty budget limits so the dashboard can save and clear (cheaper-inference#3537) (cheaper-inference#3564) Integrated into release/v3.8.20 * docs(changelog): credit @Six7Day for cheaper-inference#3560 thoughtSignature fix (cheaper-inference#3414) The cheaper-inference#3560 squash co-author trailer landed inline (unparsed by GitHub), so add an explicit CHANGELOG credit ensuring @Six7Day (original cheaper-inference#3414) and @oyi77 are on the public record for the Gemini thoughtSignature fix. * fix(gamification): dedup badge unlock via user_badges so events don't re-fire every request (cheaper-inference#3472) (cheaper-inference#3565) Integrated into release/v3.8.20 * fix(routing): pass through 'auto' keyword on codex /v1/responses instead of rewriting to codex/auto (cheaper-inference#3509) (cheaper-inference#3566) Integrated into release/v3.8.20 * fix(cli-tools): normalize apiKey null in guide-settings schema so cloud-mode config saves (cheaper-inference#3552) (cheaper-inference#3567) Integrated into release/v3.8.20 * fix(catalog): reclassify PublicAI from keyless to one-time-initial (requires API key) (cheaper-inference#3558) (cheaper-inference#3568) Integrated into release/v3.8.20 * fix(gemini-web): surface missing Playwright browser as actionable 503 + cooldown hint, not a retryable 500 loop (cheaper-inference#3516) (cheaper-inference#3570) Integrated into release/v3.8.20 * fix(security): sanitize raw err.message in web executors + embeddings/search response bodies (Rule cheaper-inference#12) (cheaper-inference#3494, cheaper-inference#3495) (cheaper-inference#3573) Integrated into release/v3.8.20 * fix(dashboard): point CustomHostsManager + FeatureFlagsGrid at real routes (cheaper-inference#3486, cheaper-inference#3487) (cheaper-inference#3574) Integrated into release/v3.8.20 * chore(providers): remove dead krutrim entry (cheaper-inference#3483) + docs(api): fix agent-bridge per-agent state route (cheaper-inference#3489) (cheaper-inference#3575) Integrated into release/v3.8.20 * docs(api): correct API_REFERENCE.md paths for skills/plugins/admin/cache/acp/system-info (cheaper-inference#3497) (cheaper-inference#3577) Integrated into release/v3.8.20 * fix(proxy): drive SOCKS5 UI option from runtime ENABLE_SOCKS5_PROXY, not build-time NEXT_PUBLIC (cheaper-inference#3508) (cheaper-inference#3579) Integrated into release/v3.8.20 * fix(playground): filter playground models by node prefix so custom-endpoint models appear (cheaper-inference#3505) (cheaper-inference#3581) Integrated into release/v3.8.20 * fix(usage): show an informative message instead of a blank Kiro quota card when no usage breakdown (cheaper-inference#3506) (cheaper-inference#3582) Integrated into release/v3.8.20 * docs(changelog): add the cheaper-inference#3506 Kiro quota entry (missed in cheaper-inference#3582 due to a stale-base CHANGELOG anchor) (cheaper-inference#3583) Integrated into release/v3.8.20 * fix(auto-update): use stable PROJECT_ROOT walker, not frozen process.cwd() (cheaper-inference#3561) Integrated into release/v3.8.20. Auto-update PROJECT_ROOT now uses a stable __dirname-anchored upward walker instead of the no-op process.cwd() resolver. * fix: address PR cheaper-inference#3518 review comments (lifecycle hooks, regex, indentation, route params) (cheaper-inference#3562) Integrated into release/v3.8.20. Addresses cheaper-inference#3518 review: regex literals, logs/[id] route params (Next 16), indentation, and wires plugin lifecycle hooks (onInstall/onActivate/onDeactivate/onUninstall) in the loader so manager.ts can register them. Adds Rule cheaper-inference#18 regression test. * docs(changelog): credit @ViFigueiredo (cheaper-inference#3423) for PROJECT_ROOT + log cheaper-inference#3561/cheaper-inference#3562 (v3.8.20) * fix: openai to gemini incorrectly translates historical tool calls into text (cheaper-inference#3569) Integrated into release/v3.8.20. Standard Gemini direct path now maps historical tool calls to native functionCall/functionResponse parts (signaturelessToolCallMode: native) instead of inert text — validated against the real Gemini API (gemini-2.5-flash returns 200 for signatureless native functionCall, even with tools+thinking; Hard Rule cheaper-inference#18). Eliminates the text-serialization leak. Antigravity/CLI sentinel path (cheaper-inference#3560) untouched. * docs(changelog)+test: reconcile standard-Gemini native mode (cheaper-inference#3569) — update round-2 rationale comment + log VPS validation * docs(changelog): reconcile v3.8.20 — add 9 missing bullets + move [Unreleased] to versioned section * docs(changelog): complete v3.8.20 reconciliation — 27 bullets, 11 contributors --------- Co-authored-by: Alexander Averyanov <alex@averyan.ru> Co-authored-by: Hakan Kurşun <bykamaka@gmail.com> Co-authored-by: Wilson <pedbookmed@gmail.com> Co-authored-by: Randi <55005611+rdself@users.noreply.github.com> Co-authored-by: Giorgos Giakoumettis <giorgos@yiakoumettis.gr> Co-authored-by: PizzaV <103120356+pizzav-xyz@users.noreply.github.com> Co-authored-by: Paijo <14921983+oyi77@users.noreply.github.com> Co-authored-by: Markus Hartung <mail@hartmark.se>
* chore(release): open v3.8.20 development cycle * fix(images): prefer bare combos over image aliases (cheaper-inference#3527) Integrated into release/v3.8.20 * fix(translator): map Codex local_shell tool (cheaper-inference#3534) Integrated into release/v3.8.20 * fix(usage): make opencode-go quota fetcher fail-open instead of throwing 500 (cheaper-inference#3522) Integrated into release/v3.8.20 * Fix Runtime page breaker state rendering (cheaper-inference#3533) Integrated into release/v3.8.20 * Expose provider breaker degradation threshold setting (cheaper-inference#3535) Integrated into release/v3.8.20 * fix(executor): strip provider prefix from versioned built-in tool model field (cheaper-inference#3532) Integrated into release/v3.8.20 * feat(providers): add Claude Fable 5 support (cheaper-inference#3524) Integrated into release/v3.8.20 * feat(resilience): add global provider cooldown tracking to prevent combo re-walking (cheaper-inference#3556) Integrated into release/v3.8.20 (default OFF, opt-in) * fix(translator): scope thoughtSignature bypass to Antigravity/CLI only (cheaper-inference#3560) Integrated into release/v3.8.20. Co-authored-by: Six7Day <six7day@gmail.com> * fix(routing): normalize thinking:disabled for combo-substituted models that reject it (cheaper-inference#3554) (cheaper-inference#3563) Integrated into release/v3.8.20 * fix(usage): accept 0/empty budget limits so the dashboard can save and clear (cheaper-inference#3537) (cheaper-inference#3564) Integrated into release/v3.8.20 * docs(changelog): credit @Six7Day for cheaper-inference#3560 thoughtSignature fix (cheaper-inference#3414) The cheaper-inference#3560 squash co-author trailer landed inline (unparsed by GitHub), so add an explicit CHANGELOG credit ensuring @Six7Day (original cheaper-inference#3414) and @oyi77 are on the public record for the Gemini thoughtSignature fix. * fix(gamification): dedup badge unlock via user_badges so events don't re-fire every request (cheaper-inference#3472) (cheaper-inference#3565) Integrated into release/v3.8.20 * fix(routing): pass through 'auto' keyword on codex /v1/responses instead of rewriting to codex/auto (cheaper-inference#3509) (cheaper-inference#3566) Integrated into release/v3.8.20 * fix(cli-tools): normalize apiKey null in guide-settings schema so cloud-mode config saves (cheaper-inference#3552) (cheaper-inference#3567) Integrated into release/v3.8.20 * fix(catalog): reclassify PublicAI from keyless to one-time-initial (requires API key) (cheaper-inference#3558) (cheaper-inference#3568) Integrated into release/v3.8.20 * fix(gemini-web): surface missing Playwright browser as actionable 503 + cooldown hint, not a retryable 500 loop (cheaper-inference#3516) (cheaper-inference#3570) Integrated into release/v3.8.20 * fix(security): sanitize raw err.message in web executors + embeddings/search response bodies (Rule cheaper-inference#12) (cheaper-inference#3494, cheaper-inference#3495) (cheaper-inference#3573) Integrated into release/v3.8.20 * fix(dashboard): point CustomHostsManager + FeatureFlagsGrid at real routes (cheaper-inference#3486, cheaper-inference#3487) (cheaper-inference#3574) Integrated into release/v3.8.20 * chore(providers): remove dead krutrim entry (cheaper-inference#3483) + docs(api): fix agent-bridge per-agent state route (cheaper-inference#3489) (cheaper-inference#3575) Integrated into release/v3.8.20 * docs(api): correct API_REFERENCE.md paths for skills/plugins/admin/cache/acp/system-info (cheaper-inference#3497) (cheaper-inference#3577) Integrated into release/v3.8.20 * fix(proxy): drive SOCKS5 UI option from runtime ENABLE_SOCKS5_PROXY, not build-time NEXT_PUBLIC (cheaper-inference#3508) (cheaper-inference#3579) Integrated into release/v3.8.20 * fix(playground): filter playground models by node prefix so custom-endpoint models appear (cheaper-inference#3505) (cheaper-inference#3581) Integrated into release/v3.8.20 * fix(usage): show an informative message instead of a blank Kiro quota card when no usage breakdown (cheaper-inference#3506) (cheaper-inference#3582) Integrated into release/v3.8.20 * docs(changelog): add the cheaper-inference#3506 Kiro quota entry (missed in cheaper-inference#3582 due to a stale-base CHANGELOG anchor) (cheaper-inference#3583) Integrated into release/v3.8.20 * fix(auto-update): use stable PROJECT_ROOT walker, not frozen process.cwd() (cheaper-inference#3561) Integrated into release/v3.8.20. Auto-update PROJECT_ROOT now uses a stable __dirname-anchored upward walker instead of the no-op process.cwd() resolver. * fix: address PR cheaper-inference#3518 review comments (lifecycle hooks, regex, indentation, route params) (cheaper-inference#3562) Integrated into release/v3.8.20. Addresses cheaper-inference#3518 review: regex literals, logs/[id] route params (Next 16), indentation, and wires plugin lifecycle hooks (onInstall/onActivate/onDeactivate/onUninstall) in the loader so manager.ts can register them. Adds Rule cheaper-inference#18 regression test. * docs(changelog): credit @ViFigueiredo (cheaper-inference#3423) for PROJECT_ROOT + log cheaper-inference#3561/cheaper-inference#3562 (v3.8.20) * fix: openai to gemini incorrectly translates historical tool calls into text (cheaper-inference#3569) Integrated into release/v3.8.20. Standard Gemini direct path now maps historical tool calls to native functionCall/functionResponse parts (signaturelessToolCallMode: native) instead of inert text — validated against the real Gemini API (gemini-2.5-flash returns 200 for signatureless native functionCall, even with tools+thinking; Hard Rule cheaper-inference#18). Eliminates the text-serialization leak. Antigravity/CLI sentinel path (cheaper-inference#3560) untouched. * docs(changelog)+test: reconcile standard-Gemini native mode (cheaper-inference#3569) — update round-2 rationale comment + log VPS validation * docs(changelog): reconcile v3.8.20 — add 9 missing bullets + move [Unreleased] to versioned section * docs(changelog): complete v3.8.20 reconciliation — 27 bullets, 11 contributors --------- Co-authored-by: Alexander Averyanov <alex@averyan.ru> Co-authored-by: Hakan Kurşun <bykamaka@gmail.com> Co-authored-by: Wilson <pedbookmed@gmail.com> Co-authored-by: Randi <55005611+rdself@users.noreply.github.com> Co-authored-by: Giorgos Giakoumettis <giorgos@yiakoumettis.gr> Co-authored-by: PizzaV <103120356+pizzav-xyz@users.noreply.github.com> Co-authored-by: Paijo <14921983+oyi77@users.noreply.github.com> Co-authored-by: Markus Hartung <mail@hartmark.se>
* chore(release): open v3.8.20 development cycle * fix(images): prefer bare combos over image aliases (cheaper-inference#3527) Integrated into release/v3.8.20 * fix(translator): map Codex local_shell tool (cheaper-inference#3534) Integrated into release/v3.8.20 * fix(usage): make opencode-go quota fetcher fail-open instead of throwing 500 (cheaper-inference#3522) Integrated into release/v3.8.20 * Fix Runtime page breaker state rendering (cheaper-inference#3533) Integrated into release/v3.8.20 * Expose provider breaker degradation threshold setting (cheaper-inference#3535) Integrated into release/v3.8.20 * fix(executor): strip provider prefix from versioned built-in tool model field (cheaper-inference#3532) Integrated into release/v3.8.20 * feat(providers): add Claude Fable 5 support (cheaper-inference#3524) Integrated into release/v3.8.20 * feat(resilience): add global provider cooldown tracking to prevent combo re-walking (cheaper-inference#3556) Integrated into release/v3.8.20 (default OFF, opt-in) * fix(translator): scope thoughtSignature bypass to Antigravity/CLI only (cheaper-inference#3560) Integrated into release/v3.8.20. Co-authored-by: Six7Day <six7day@gmail.com> * fix(routing): normalize thinking:disabled for combo-substituted models that reject it (cheaper-inference#3554) (cheaper-inference#3563) Integrated into release/v3.8.20 * fix(usage): accept 0/empty budget limits so the dashboard can save and clear (cheaper-inference#3537) (cheaper-inference#3564) Integrated into release/v3.8.20 * docs(changelog): credit @Six7Day for cheaper-inference#3560 thoughtSignature fix (cheaper-inference#3414) The cheaper-inference#3560 squash co-author trailer landed inline (unparsed by GitHub), so add an explicit CHANGELOG credit ensuring @Six7Day (original cheaper-inference#3414) and @oyi77 are on the public record for the Gemini thoughtSignature fix. * fix(gamification): dedup badge unlock via user_badges so events don't re-fire every request (cheaper-inference#3472) (cheaper-inference#3565) Integrated into release/v3.8.20 * fix(routing): pass through 'auto' keyword on codex /v1/responses instead of rewriting to codex/auto (cheaper-inference#3509) (cheaper-inference#3566) Integrated into release/v3.8.20 * fix(cli-tools): normalize apiKey null in guide-settings schema so cloud-mode config saves (cheaper-inference#3552) (cheaper-inference#3567) Integrated into release/v3.8.20 * fix(catalog): reclassify PublicAI from keyless to one-time-initial (requires API key) (cheaper-inference#3558) (cheaper-inference#3568) Integrated into release/v3.8.20 * fix(gemini-web): surface missing Playwright browser as actionable 503 + cooldown hint, not a retryable 500 loop (cheaper-inference#3516) (cheaper-inference#3570) Integrated into release/v3.8.20 * fix(security): sanitize raw err.message in web executors + embeddings/search response bodies (Rule cheaper-inference#12) (cheaper-inference#3494, cheaper-inference#3495) (cheaper-inference#3573) Integrated into release/v3.8.20 * fix(dashboard): point CustomHostsManager + FeatureFlagsGrid at real routes (cheaper-inference#3486, cheaper-inference#3487) (cheaper-inference#3574) Integrated into release/v3.8.20 * chore(providers): remove dead krutrim entry (cheaper-inference#3483) + docs(api): fix agent-bridge per-agent state route (cheaper-inference#3489) (cheaper-inference#3575) Integrated into release/v3.8.20 * docs(api): correct API_REFERENCE.md paths for skills/plugins/admin/cache/acp/system-info (cheaper-inference#3497) (cheaper-inference#3577) Integrated into release/v3.8.20 * fix(proxy): drive SOCKS5 UI option from runtime ENABLE_SOCKS5_PROXY, not build-time NEXT_PUBLIC (cheaper-inference#3508) (cheaper-inference#3579) Integrated into release/v3.8.20 * fix(playground): filter playground models by node prefix so custom-endpoint models appear (cheaper-inference#3505) (cheaper-inference#3581) Integrated into release/v3.8.20 * fix(usage): show an informative message instead of a blank Kiro quota card when no usage breakdown (cheaper-inference#3506) (cheaper-inference#3582) Integrated into release/v3.8.20 * docs(changelog): add the cheaper-inference#3506 Kiro quota entry (missed in cheaper-inference#3582 due to a stale-base CHANGELOG anchor) (cheaper-inference#3583) Integrated into release/v3.8.20 * fix(auto-update): use stable PROJECT_ROOT walker, not frozen process.cwd() (cheaper-inference#3561) Integrated into release/v3.8.20. Auto-update PROJECT_ROOT now uses a stable __dirname-anchored upward walker instead of the no-op process.cwd() resolver. * fix: address PR cheaper-inference#3518 review comments (lifecycle hooks, regex, indentation, route params) (cheaper-inference#3562) Integrated into release/v3.8.20. Addresses cheaper-inference#3518 review: regex literals, logs/[id] route params (Next 16), indentation, and wires plugin lifecycle hooks (onInstall/onActivate/onDeactivate/onUninstall) in the loader so manager.ts can register them. Adds Rule cheaper-inference#18 regression test. * docs(changelog): credit @ViFigueiredo (cheaper-inference#3423) for PROJECT_ROOT + log cheaper-inference#3561/cheaper-inference#3562 (v3.8.20) * fix: openai to gemini incorrectly translates historical tool calls into text (cheaper-inference#3569) Integrated into release/v3.8.20. Standard Gemini direct path now maps historical tool calls to native functionCall/functionResponse parts (signaturelessToolCallMode: native) instead of inert text — validated against the real Gemini API (gemini-2.5-flash returns 200 for signatureless native functionCall, even with tools+thinking; Hard Rule cheaper-inference#18). Eliminates the text-serialization leak. Antigravity/CLI sentinel path (cheaper-inference#3560) untouched. * docs(changelog)+test: reconcile standard-Gemini native mode (cheaper-inference#3569) — update round-2 rationale comment + log VPS validation * docs(changelog): reconcile v3.8.20 — add 9 missing bullets + move [Unreleased] to versioned section * docs(changelog): complete v3.8.20 reconciliation — 27 bullets, 11 contributors --------- Co-authored-by: Alexander Averyanov <alex@averyan.ru> Co-authored-by: Hakan Kurşun <bykamaka@gmail.com> Co-authored-by: Wilson <pedbookmed@gmail.com> Co-authored-by: Randi <55005611+rdself@users.noreply.github.com> Co-authored-by: Giorgos Giakoumettis <giorgos@yiakoumettis.gr> Co-authored-by: PizzaV <103120356+pizzav-xyz@users.noreply.github.com> Co-authored-by: Paijo <14921983+oyi77@users.noreply.github.com> Co-authored-by: Markus Hartung <mail@hartmark.se>
…equires API key) (cheaper-inference#3558) (cheaper-inference#3568) Integrated into release/v3.8.20
* chore(release): open v3.8.20 development cycle * fix(images): prefer bare combos over image aliases (cheaper-inference#3527) Integrated into release/v3.8.20 * fix(translator): map Codex local_shell tool (cheaper-inference#3534) Integrated into release/v3.8.20 * fix(usage): make opencode-go quota fetcher fail-open instead of throwing 500 (cheaper-inference#3522) Integrated into release/v3.8.20 * Fix Runtime page breaker state rendering (cheaper-inference#3533) Integrated into release/v3.8.20 * Expose provider breaker degradation threshold setting (cheaper-inference#3535) Integrated into release/v3.8.20 * fix(executor): strip provider prefix from versioned built-in tool model field (cheaper-inference#3532) Integrated into release/v3.8.20 * feat(providers): add Claude Fable 5 support (cheaper-inference#3524) Integrated into release/v3.8.20 * feat(resilience): add global provider cooldown tracking to prevent combo re-walking (cheaper-inference#3556) Integrated into release/v3.8.20 (default OFF, opt-in) * fix(translator): scope thoughtSignature bypass to Antigravity/CLI only (cheaper-inference#3560) Integrated into release/v3.8.20. Co-authored-by: Six7Day <six7day@gmail.com> * fix(routing): normalize thinking:disabled for combo-substituted models that reject it (cheaper-inference#3554) (cheaper-inference#3563) Integrated into release/v3.8.20 * fix(usage): accept 0/empty budget limits so the dashboard can save and clear (cheaper-inference#3537) (cheaper-inference#3564) Integrated into release/v3.8.20 * docs(changelog): credit @Six7Day for cheaper-inference#3560 thoughtSignature fix (cheaper-inference#3414) The cheaper-inference#3560 squash co-author trailer landed inline (unparsed by GitHub), so add an explicit CHANGELOG credit ensuring @Six7Day (original cheaper-inference#3414) and @oyi77 are on the public record for the Gemini thoughtSignature fix. * fix(gamification): dedup badge unlock via user_badges so events don't re-fire every request (cheaper-inference#3472) (cheaper-inference#3565) Integrated into release/v3.8.20 * fix(routing): pass through 'auto' keyword on codex /v1/responses instead of rewriting to codex/auto (cheaper-inference#3509) (cheaper-inference#3566) Integrated into release/v3.8.20 * fix(cli-tools): normalize apiKey null in guide-settings schema so cloud-mode config saves (cheaper-inference#3552) (cheaper-inference#3567) Integrated into release/v3.8.20 * fix(catalog): reclassify PublicAI from keyless to one-time-initial (requires API key) (cheaper-inference#3558) (cheaper-inference#3568) Integrated into release/v3.8.20 * fix(gemini-web): surface missing Playwright browser as actionable 503 + cooldown hint, not a retryable 500 loop (cheaper-inference#3516) (cheaper-inference#3570) Integrated into release/v3.8.20 * fix(security): sanitize raw err.message in web executors + embeddings/search response bodies (Rule cheaper-inference#12) (cheaper-inference#3494, cheaper-inference#3495) (cheaper-inference#3573) Integrated into release/v3.8.20 * fix(dashboard): point CustomHostsManager + FeatureFlagsGrid at real routes (cheaper-inference#3486, cheaper-inference#3487) (cheaper-inference#3574) Integrated into release/v3.8.20 * chore(providers): remove dead krutrim entry (cheaper-inference#3483) + docs(api): fix agent-bridge per-agent state route (cheaper-inference#3489) (cheaper-inference#3575) Integrated into release/v3.8.20 * docs(api): correct API_REFERENCE.md paths for skills/plugins/admin/cache/acp/system-info (cheaper-inference#3497) (cheaper-inference#3577) Integrated into release/v3.8.20 * fix(proxy): drive SOCKS5 UI option from runtime ENABLE_SOCKS5_PROXY, not build-time NEXT_PUBLIC (cheaper-inference#3508) (cheaper-inference#3579) Integrated into release/v3.8.20 * fix(playground): filter playground models by node prefix so custom-endpoint models appear (cheaper-inference#3505) (cheaper-inference#3581) Integrated into release/v3.8.20 * fix(usage): show an informative message instead of a blank Kiro quota card when no usage breakdown (cheaper-inference#3506) (cheaper-inference#3582) Integrated into release/v3.8.20 * docs(changelog): add the cheaper-inference#3506 Kiro quota entry (missed in cheaper-inference#3582 due to a stale-base CHANGELOG anchor) (cheaper-inference#3583) Integrated into release/v3.8.20 * fix(auto-update): use stable PROJECT_ROOT walker, not frozen process.cwd() (cheaper-inference#3561) Integrated into release/v3.8.20. Auto-update PROJECT_ROOT now uses a stable __dirname-anchored upward walker instead of the no-op process.cwd() resolver. * fix: address PR cheaper-inference#3518 review comments (lifecycle hooks, regex, indentation, route params) (cheaper-inference#3562) Integrated into release/v3.8.20. Addresses cheaper-inference#3518 review: regex literals, logs/[id] route params (Next 16), indentation, and wires plugin lifecycle hooks (onInstall/onActivate/onDeactivate/onUninstall) in the loader so manager.ts can register them. Adds Rule cheaper-inference#18 regression test. * docs(changelog): credit @ViFigueiredo (cheaper-inference#3423) for PROJECT_ROOT + log cheaper-inference#3561/cheaper-inference#3562 (v3.8.20) * fix: openai to gemini incorrectly translates historical tool calls into text (cheaper-inference#3569) Integrated into release/v3.8.20. Standard Gemini direct path now maps historical tool calls to native functionCall/functionResponse parts (signaturelessToolCallMode: native) instead of inert text — validated against the real Gemini API (gemini-2.5-flash returns 200 for signatureless native functionCall, even with tools+thinking; Hard Rule cheaper-inference#18). Eliminates the text-serialization leak. Antigravity/CLI sentinel path (cheaper-inference#3560) untouched. * docs(changelog)+test: reconcile standard-Gemini native mode (cheaper-inference#3569) — update round-2 rationale comment + log VPS validation * docs(changelog): reconcile v3.8.20 — add 9 missing bullets + move [Unreleased] to versioned section * docs(changelog): complete v3.8.20 reconciliation — 27 bullets, 11 contributors --------- Co-authored-by: Alexander Averyanov <alex@averyan.ru> Co-authored-by: Hakan Kurşun <bykamaka@gmail.com> Co-authored-by: Wilson <pedbookmed@gmail.com> Co-authored-by: Randi <55005611+rdself@users.noreply.github.com> Co-authored-by: Giorgos Giakoumettis <giorgos@yiakoumettis.gr> Co-authored-by: PizzaV <103120356+pizzav-xyz@users.noreply.github.com> Co-authored-by: Paijo <14921983+oyi77@users.noreply.github.com> Co-authored-by: Markus Hartung <mail@hartmark.se>
Closes #3558
Problem: PublicAI's 3 models were tagged
freeType:"keyless"(in the RECURRING set), so they surfaced as keyless-free and could be picked into the no-auth pool and dispatched with no Authorization header. But the registry requires a key (authType:"apikey") andfreeTierCatalog.tsalready excluded publicai — an internal inconsistency that both misled users ("free") and produced upstream rejections.Fix: the 3 PublicAI entries move to
freeType:"one-time-initial"(signup credit then paid, like nscale/qoder), andproviders.tspublicai.hasFree→falsewith an accurate note.Validation: this is an internal catalog/registry consistency correction (the registry authType + the freeTierCatalog exclusion already establish publicai is key-required). Test (Rule #18):
tests/unit/publicai-not-keyless-3558.test.ts— RED before the fix; asserts no publicai keyless entry remains and all are one-time-initial. free-model-catalog + free-budget-card suites still green.Source: discussion #3548 (reporter @ColaIan).