Files
OmniRoute/src/shared/utils/providerHints.ts
diegosouzapw 87dfbcca62 Merge remote-tracking branch 'origin/release/v3.8.0' into feat/zero-config-auto-routing
# Conflicts:
#	CHANGELOG.md
#	Dockerfile
#	docs/i18n/ar/CHANGELOG.md
#	docs/i18n/bg/CHANGELOG.md
#	docs/i18n/bn/CHANGELOG.md
#	docs/i18n/cs/CHANGELOG.md
#	docs/i18n/da/CHANGELOG.md
#	docs/i18n/de/CHANGELOG.md
#	docs/i18n/es/CHANGELOG.md
#	docs/i18n/fa/CHANGELOG.md
#	docs/i18n/fi/CHANGELOG.md
#	docs/i18n/fr/CHANGELOG.md
#	docs/i18n/gu/CHANGELOG.md
#	docs/i18n/he/CHANGELOG.md
#	docs/i18n/hi/CHANGELOG.md
#	docs/i18n/hu/CHANGELOG.md
#	docs/i18n/id/CHANGELOG.md
#	docs/i18n/it/CHANGELOG.md
#	docs/i18n/ja/CHANGELOG.md
#	docs/i18n/ko/CHANGELOG.md
#	docs/i18n/mr/CHANGELOG.md
#	docs/i18n/ms/CHANGELOG.md
#	docs/i18n/nl/CHANGELOG.md
#	docs/i18n/no/CHANGELOG.md
#	docs/i18n/phi/CHANGELOG.md
#	docs/i18n/pl/CHANGELOG.md
#	docs/i18n/pt-BR/CHANGELOG.md
#	docs/i18n/pt/CHANGELOG.md
#	docs/i18n/ro/CHANGELOG.md
#	docs/i18n/ru/CHANGELOG.md
#	docs/i18n/sk/CHANGELOG.md
#	docs/i18n/sv/CHANGELOG.md
#	docs/i18n/sw/CHANGELOG.md
#	docs/i18n/ta/CHANGELOG.md
#	docs/i18n/te/CHANGELOG.md
#	docs/i18n/th/CHANGELOG.md
#	docs/i18n/tr/CHANGELOG.md
#	docs/i18n/uk-UA/CHANGELOG.md
#	docs/i18n/ur/CHANGELOG.md
#	docs/i18n/vi/CHANGELOG.md
#	docs/i18n/zh-CN/CHANGELOG.md
#	open-sse/config/providerRegistry.ts
#	open-sse/handlers/chatCore.ts
#	open-sse/services/usage.ts
#	open-sse/utils/streamReadiness.ts
#	scripts/check-docs-sync.mjs
#	src/app/(dashboard)/dashboard/cache/media/MediaPageClient.tsx
#	src/app/(dashboard)/dashboard/providers/[id]/page.tsx
#	src/app/(dashboard)/dashboard/settings/components/ProxyTab.tsx
#	src/app/(dashboard)/dashboard/settings/components/RoutingTab.tsx
#	src/app/(dashboard)/dashboard/usage/components/ProviderLimits/utils.tsx
#	src/app/api/usage/analytics/route.ts
#	src/i18n/messages/zh-CN.json
#	src/lib/embeddings/service.ts
#	src/lib/usage/providerLimits.ts
#	src/mitm/cert/install.ts
#	src/shared/constants/providers.ts
#	src/sse/handlers/chat.ts
#	tests/unit/compression/rtk-code-stripper.test.ts
#	tests/unit/usage-service-hardening.test.ts
2026-05-10 18:33:20 -03:00

74 lines
2.4 KiB
TypeScript

/**
* Per-provider default policy for upstream 429 hint trust.
*
* @see Issue #2100 follow-up — surface a user-overridable per-profile toggle
* that decides whether the circuit breaker uses upstream 429 body / Retry-After
* hints (`classify429`, `cooldownByKind`) to differentiate rate-limit from
* quota-exhausted failure cooldowns.
*
* This helper returns the **default** answer for a given provider. The actual
* runtime decision is the user override (if any) OR this default. See
* `accountFallback.ts` / `chat.ts` / `chatHelpers.ts` for the resolution
* call sites:
*
* ```ts
* const userValue = providerProfile.useUpstream429BreakerHints; // boolean | undefined
* const useHints = userValue !== undefined
* ? userValue
* : defaultUseUpstream429BreakerHints(provider);
* ```
*
* Default policy: direct cloud providers default `true` because their 429
* bodies and `Retry-After` headers are authoritative. Reverse-proxy /
* self-hosted / CLI-backed providers default `false` because forwarded 429
* metadata is often unreliable or fabricated by the proxy.
*
* @module shared/utils/providerHints
*/
import {
UPSTREAM_PROXY_PROVIDERS,
SELF_HOSTED_CHAT_PROVIDER_IDS,
isLocalProvider,
isClaudeCodeCompatibleProvider,
} from "../constants/providers";
/**
* Conservative per-provider default for `useUpstream429BreakerHints`.
*
* Returns `false` for any provider whose 429 metadata may be forwarded by
* an intermediary (proxy, self-hosted runtime, CLI wrapper). Returns `true`
* for direct cloud providers where the upstream response is authoritative.
*/
export function defaultUseUpstream429BreakerHints(providerId: string): boolean {
if (Object.prototype.hasOwnProperty.call(UPSTREAM_PROXY_PROVIDERS, providerId)) {
return false;
}
if (isLocalProvider(providerId)) {
return false;
}
if (SELF_HOSTED_CHAT_PROVIDER_IDS.has(providerId)) {
return false;
}
if (isClaudeCodeCompatibleProvider(providerId)) {
return false;
}
return true;
}
/**
* Resolve the effective `useHints` decision: the user override wins if set,
* otherwise fall back to the per-provider default.
*
* `undefined` means "not user-set" and triggers the default lookup.
*/
export function resolveUseUpstream429BreakerHints(
providerId: string,
userValue: boolean | undefined
): boolean {
if (userValue !== undefined) {
return userValue;
}
return defaultUseUpstream429BreakerHints(providerId);
}