mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-09-17 20:32:25 +03:00
Validado numa worktree combinada com as 16 PRs desta leva sobre `release/v3.8.51`: typecheck:core limpo, check-file-size e check-changelog-integrity OK, complexity 2788/3218 e cognitive 1261/1437, ESLint 0 erros nos 152 arquivos alterados, 771 testes unitários focados, 49 de integração e a suíte vitest:ui completa (2149) verdes. O ponto que sustenta a PR é o `models.dev` virar overlay de preço em vez de fonte de catálogo. Um catálogo estático que sobrevive à conta já ter listado ids mais novos é o tipo de defeito que só aparece quando o modelo novo é justamente o que se quer usar. Nota de integração: `activeSyncedCatalog.ts` colidiu com o #12934 (união dos `customModels` do picker no catálogo de despacho). Como você extraiu o bloco original para `loadConnectionCatalog`, os dois se compõem: a união dos irmãos agy/antigravity primeiro, o `unionCustomModels` por cima. Revalidei com `custom-models-live-catalog-12597`, `live-model-catalog-reconciliation-8926`, `sync-models-degraded-cached-catalog-9683`, `models-dev-catalog-read-gate`, `discovery-class`, `reactive-model-sync` e `l1-oauth-autosync-default` juntos — 48/48 — mais typecheck:core limpo. Sobre o `autoSync` padrão em Claude/Codex/Copilot com scheduler de 6h: passei isso pelo dono antes de mergear e a decisão foi manter como está.
73 lines
2.6 KiB
TypeScript
73 lines
2.6 KiB
TypeScript
import {
|
|
isUserCallableAntigravityModelId,
|
|
toClientAntigravityModelId,
|
|
} from "@omniroute/open-sse/config/antigravityModelAliases.ts";
|
|
import { isDiscoverableAgyModelId } from "@omniroute/open-sse/config/agyModels.ts";
|
|
|
|
type JsonRecord = Record<string, unknown>;
|
|
|
|
export function isRecord(value: unknown): value is JsonRecord {
|
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
}
|
|
|
|
export function isUsageQuotaKeyAllowed(provider: string, quotaKey: string): boolean {
|
|
if (quotaKey === "credits" || quotaKey === "models") return true;
|
|
if (provider === "antigravity") return isUserCallableAntigravityModelId(quotaKey);
|
|
if (provider === "agy") return isDiscoverableAgyModelId(quotaKey);
|
|
return true;
|
|
}
|
|
|
|
export function normalizeUsageQuotaKey(provider: string, quotaKey: string): string | null {
|
|
if (quotaKey === "credits" || quotaKey === "models") return quotaKey;
|
|
if (provider === "antigravity" || provider === "agy") {
|
|
const clientKey = toClientAntigravityModelId(quotaKey);
|
|
return isUsageQuotaKeyAllowed(provider, clientKey) ? clientKey : null;
|
|
}
|
|
return isUsageQuotaKeyAllowed(provider, quotaKey) ? quotaKey : null;
|
|
}
|
|
|
|
export function normalizeUsageQuotasForProvider(
|
|
provider: string,
|
|
quotas: JsonRecord | null | undefined
|
|
): JsonRecord | null {
|
|
if (!isRecord(quotas)) return quotas ?? null;
|
|
|
|
const normalized: JsonRecord = {};
|
|
let changed = false;
|
|
|
|
for (const [quotaKey, quota] of Object.entries(quotas)) {
|
|
const normalizedKey = normalizeUsageQuotaKey(provider, quotaKey);
|
|
if (!normalizedKey) {
|
|
changed = true;
|
|
continue;
|
|
}
|
|
|
|
const existing = normalized[normalizedKey];
|
|
if (existing && isRecord(existing) && isRecord(quota)) {
|
|
const existingSource = String(existing.quotaSource ?? "");
|
|
const nextSource = String(quota.quotaSource ?? "");
|
|
const sourceRank: Record<string, number> = {
|
|
fetchAvailableModels: 0,
|
|
localUsageHistory: 1,
|
|
retrieveUserQuota: 2,
|
|
};
|
|
if ((sourceRank[existingSource] ?? 0) > (sourceRank[nextSource] ?? 0)) {
|
|
continue;
|
|
}
|
|
}
|
|
|
|
normalized[normalizedKey] = quota as JsonRecord;
|
|
if (normalizedKey !== quotaKey) changed = true;
|
|
}
|
|
|
|
return changed ? normalized : quotas;
|
|
}
|
|
|
|
export function sanitizeUsageQuotasForProvider(provider: string, usage: JsonRecord): JsonRecord {
|
|
if (provider !== "antigravity" && provider !== "agy") return usage;
|
|
if (!isRecord(usage.quotas)) return usage;
|
|
|
|
const sanitizedQuotas = normalizeUsageQuotasForProvider(provider, usage.quotas);
|
|
return sanitizedQuotas === usage.quotas ? usage : { ...usage, quotas: sanitizedQuotas };
|
|
}
|