Repository navigation
fix(providers): per-provider opt-out for anonymous no-auth fallback (opencode-go/zen 401s) - #9675
Conversation
d2b3031 to
6a1dda6
Compare
|
Coverage gate run on this exact branch ( The 60% coverage minimums are met on all four metrics. The run's non-zero exit comes from 3938 test failures that are ALL the pre-existing base breakage on |
6a1dda6 to
0838bee
Compare
|
Thanks for the PR. Please address the mandatory items (tests and/or merge blockers) in this branch, then rerun checks before /merge-prs. |
3 similar comments
|
Thanks for the PR. Please address the mandatory items (tests and/or merge blockers) in this branch, then rerun checks before /merge-prs. |
|
Thanks for the PR. Please address the mandatory items (tests and/or merge blockers) in this branch, then rerun checks before /merge-prs. |
|
Thanks for the PR. Please address the mandatory items (tests and/or merge blockers) in this branch, then rerun checks before /merge-prs. |
|
Obrigado pelo PR. Mantive a revisão de
|
Rebase of PR cheaper-inference#9675 onto origin/release/v3.8.50. This feature was already cherry-picked into the release branch (commit 58f0ff1, PR cheaper-inference#9873), so the branch is reconciled to the release tip, resolving the merge conflict without reintroducing duplicate i18n keys or stray content. Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
0838bee to
f3bee90
Compare
ff3e3b5
into
cheaper-inference:release/v3.8.50
…heaper-inference#9675) Rebase of PR cheaper-inference#9675 onto origin/release/v3.8.50. This feature was already cherry-picked into the release branch (commit 574bea5, PR cheaper-inference#9873), so the branch is reconciled to the release tip, resolving the merge conflict without reintroducing duplicate i18n keys or stray content. Co-authored-by: Hermes Agent <hermes@hermes-chloe.hyades.io> Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
Summary
API-key providers whose static definition declares
anonymousFallback: true(opencode-go,opencode-zen,pollinations,kilocode) receive a syntheticnoauthconnection frommaybeSyntheticNoAuthFallback()whenever every real configured connection is terminal (credits_exhausted/banned/expired) or all connections are unavailable. The opencode upstream now rejects anonymous requests with401 Missing API key, so an exhausted opencode-go account makes every request attempt a guaranteed-failing anonymous round trip first — added latency plus health/reconnect noise — before the combo falls through to the next provider.This PR adds a per-provider, UI-toggleable opt-out: a new top-level
noAuthFallbackDisabledProviderssettings array (zod-validated inupdateSettingsSchema, persisted viaPATCH /api/settings, following the existingblockedProviderspattern). When a provider is listed,maybeSyntheticNoAuthFallback()returnsnullfor anonymousFallback-only providers, so an exhausted provider is skipped immediately with its normalallExpired/allRateLimitedresult while the combo moves on. Real keyed connections are unaffected and become eligible again automatically once quota state clears — no manual re-enable needed.Deliberately NOT conflated with
blockedProviders: the provider stays enabled, its models stay in combos and/v1/models, and only the synthetic anonymous fallback is suppressed. True no-auth providers (opencode,mimocode, web-cookie providers) are never matched by the new setting — for them the synthetic credential is the only credential path, andblockedProvidersremains their disable mechanism.Default behavior is unchanged: an absent/empty list preserves today's fallback behavior for every provider (backward compatible).
Changes
src/shared/validation/settingsSchemas.ts— addnoAuthFallbackDisabledProviders: z.array(z.string().max(100)).optional()next toblockedProviders.src/sse/services/noAuthProviderSettings.ts— newisAnonymousFallbackDisabledBySettings(providerId)helper (id-or-alias match via the existingisProviderBlockedByIdOrAlias; fail-open on settings-read errors).src/sse/services/auth.ts— newisAnonymousFallbackOnlyProvider()predicate (staticanonymousFallback: trueAND not a true no-auth provider) and a single gate insidemaybeSyntheticNoAuthFallback(), which covers all four call sites (terminal-connections, no-connections, all-unavailable, no-auth early path). No call-site changes.src/app/(dashboard)/dashboard/providers/[id]/components/AnonymousFallbackToggle.tsx(new) — "Anonymous fallback" toggle rendered on the provider detail page, self-hiding unless the static provider definition declaresanonymousFallback: true; optimistic PATCH with rollback + toast, default ON.ProviderDetailPageClient.tsx— render the toggle in the API-key provider branch.src/i18n/messages/en.json— 5 newproviders.*strings (other locales fall back to English via the existingproviderTextfallback convention).CHANGELOG.md[Unreleased]entry +changelog.d/fixes/fragment.Related Issues
Validation
npm run lint(changed files, with repo suppressions — clean)Focused runs (all green):
tests/unit/auth-anonymous-fallback-toggle.test.ts(new, 7 tests): default backward-compat fallback, disabled+all-terminal →allExpired(nevernoauth), disabled+zero-connections →null, disabled+healthy-connection → real keyed credentials selected, recovery semantics (rate-limited →allRateLimited, quota cleared → real connection again, no toggle change needed), true no-auth provider (opencode) unaffected even when listed, re-enable restores the fallback.auth-opencode-zen-noauth-fallback,auth-noauth-fallback-loop-3061,7993-noauth-proxy-routing,kilocode-anonymous-fallback-4019— 16/16 pass.anonymousFallbackToggle.test.tsx(vitest) — 7/7 pass.npm run check:dashboard-typecheck— clean.npm run typecheck:coreoutput is byte-identical to the pristine base (pre-existing combo-module breakage tracked by fix(test): reconcile base-drifted test expectations on release/v3.8.50 #9634; zero errors in touched files).Coverage gate:
npm run test:coverageon this exact branch currently fails because the baserelease/v3.8.50HEAD is broken for every DB-touching test — migration version collision134_ccr_blocks.sqlvs134_proxy_logs_egress_ip.sql(fixed by the pending #9634, unrelated to this PR). Raw output preserved; with the collision rename applied locally in scratch space, all 23 focused tests above pass. Full-suite coverage numbers will be added as a comment once the base is green.Tests Added Or Updated
tests/unit/auth-anonymous-fallback-toggle.test.ts(new)src/app/(dashboard)/dashboard/providers/[id]/__tests__/anonymousFallbackToggle.test.tsx(new)Coverage Notes
src/changed: the gate path inauth.ts+ helper innoAuthProviderSettings.tsare exercised by the 7 new unit tests across default/disabled/recovery/re-enable matrices; UI list-update helpers are exercised by the new vitest file. No touched file's coverage decreases (pure additions plus one new conditional branch, covered both ways).Reviewer Notes
maybeSyntheticNoAuthFallback(); the four call sites are untouched, so all existing fallback flows (terminal, no-connections, all-unavailable, true-no-auth early path) behave exactly as before unless the provider is explicitly listed in the new setting.anonymousFallback: true; there is nothing to configure for other providers.blockedProviders.