fix(ia): o resguardo de provider agora existe de verdade - #38
Merged
Conversation
"Gerar nova versão" do Plano de Voo falhou com "IA retornou narrativas inválidas: resposta vazia da IA [modelo=gpt-5-nano]". A IA não devolveu vazio — a OpenAI recusou por cobrança. A telemetria da casa (`ai_calls`) tinha o erro cru guardado o tempo todo: openai_http_429: "You exceeded your current quota, please check your plan and billing" Padrão nos últimos 30 dias: TODA chamada que foi pro gpt-5-nano falhou assim (15/07, 21/07 ×2, 23/07, 27/07); TODA que foi pro gemini-2.5-flash-lite passou com valid=true e zero retry — inclusive as 5 gerações de Plano de Voo que estão no ar. E `fallback_used` NULL em todas as falhas: o resguardo nunca entrou. ## Por que o resguardo não entrou — e não entraria Três defeitos empilhados, cada um suficiente pra derrubar a geração: 1. FALLBACK DESLIGADO POR PADRÃO. `getFallbackProvider` devolvia null a menos que `AI_FALLBACK_PROVIDER` estivesse setada à mão. Ninguém setou. Com o Gemini ao lado, funcionando e de graça, um 429 de cobrança derrubava tudo. Agora o padrão é LIGADO: o outro provider assume, desde que tenha chave. `AI_FALLBACK_PROVIDER=off` desliga de propósito. 2. O OVERRIDE DE MODELO VAZAVA ENTRE PROVIDERS — e este é o que tornava o resguardo decorativo. O caller passa `model: "gpt-5-nano"`; a OpenAI estoura a quota; o cliente cai no Gemini... e chama o Gemini pedindo "gpt-5-nano", que não existe. Mesmo com a env setada, o fallback morria na porta. `resolveModel` agora ignora override que pertence claramente ao OUTRO provider (nome desconhecido — fine-tune, alias — segue respeitado). 3. DOIS DEFAULTS CONTRADITÓRIOS. `getProvider()` resolve gemini quando `AI_PROVIDER` está ausente; os callers do Plano de Voo e do Retrato faziam `(process.env.AI_PROVIDER ?? "openai")` por conta própria só pra decidir o override. Efeito: sem a env, o caller mandava nome de modelo da OpenAI e o cliente chamava o Gemini com ele. Ou seja, "só remover a variável" teria trocado um erro por outro. Os callers agora sempre passam o override da família OpenAI e deixam o cliente decidir — com (2) no lugar, é seguro. ## A mensagem também mentia `meta.error` carregava o 429 e a mensagem montada só mostrava modelo/latência/ retries. Quem depurava ia atrás do prompt em vez da conta. Agora provider, fallback e a causa crua entram no texto. Mesma correção no `retrato/narrativa`, que respondia só "IA indisponível". Nada aqui muda qual provider é o primário: isso segue em `AI_PROVIDER` (e o default do cliente, gemini, é o plano grátis). O que muda é que a queda de um lado deixa de ser queda do sistema. Validação: 151 arquivos, 1403/1403 (13 novos cobrindo default, fallback com/sem chave, desligamento explícito, o não-vazamento de modelo nos dois sentidos e o caminho exato do bug) · tsc limpo · eslint 0 · zero migration. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
This pull request has been ignored for the connected project Preview Branches by Supabase. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
O erro real
"Gerar nova versão" falhou com "IA retornou narrativas inválidas: resposta vazia da IA [modelo=gpt-5-nano]". A IA não devolveu vazio — a OpenAI recusou por cobrança. A telemetria (
ai_calls) tinha o erro guardado:Padrão dos últimos 30 dias — toda chamada ao gpt-5-nano falhou; toda ao gemini-2.5-flash-lite passou:
E
fallback_usedNULL em todas as falhas: o resguardo nunca entrou.Três defeitos empilhados
1. Fallback desligado por padrão.
getFallbackProviderdevolvianulla menos queAI_FALLBACK_PROVIDERestivesse setada à mão. Ninguém setou. Agora o padrão é ligado — o outro provider assume, desde que tenha chave.AI_FALLBACK_PROVIDER=offdesliga.2. O override de modelo vazava entre providers — este é o que tornava o resguardo decorativo. O caller passa
model: "gpt-5-nano", a OpenAI estoura a quota, o cliente cai no Gemini… e chama o Gemini pedindo"gpt-5-nano". Mesmo com a env setada, o fallback morria na porta.resolveModelagora ignora override que pertence claramente ao outro provider.3. Dois defaults contraditórios.
getProvider()resolve gemini semAI_PROVIDER; os callers faziam(process.env.AI_PROVIDER ?? "openai")por conta própria. Sem a env, o caller mandava modelo da OpenAI e o cliente chamava o Gemini com ele — ou seja, "só remover a variável" teria trocado um erro por outro.A mensagem também mentia
meta.errorcarregava o 429; a mensagem só mostrava modelo/latência/retries. Agora provider, fallback e causa crua entram no texto. Mesma correção noretrato/narrativa, que respondia só "IA indisponível".Validação
151 arquivos, 1403/1403 (13 novos) · tsc limpo · eslint 0 · zero migration.
Nada aqui muda qual provider é o primário — isso segue em
AI_PROVIDER. O que muda é que a queda de um lado deixa de ser queda do sistema.🤖 Generated with Claude Code