Discourse AI: la richiesta Gemini bloccata tramite promptFeedback.blockReason viene trattata come risposta vuota e non viene mai tradotta

Descrizione

Quando l’API Gemini di Google rifiuta una richiesta con promptFeedback.blockReason, Discourse AI gestisce la risposta come una replica di successo ma vuota. Nella traduzione AI, questo ha due effetti: l’argomento o il post non riceve mai una lingua rilevata, quindi non viene mai tradotto, e il backfill invia nuovamente la stessa richiesta bloccata nelle esecuzioni successive. Nessun elemento indica a un amministratore che si è verificato un blocco.

Osservato su un sito self-hosted in esecuzione con release/2026.7 (2026.7.3, commit f1caa6321287f918644fba9ff8943579fdcf027a) con il plugin discourse-ai incluso. La richiesta era il rilevamento della lingua di un titolo di argomento, utilizzando l’agente rilevatore di lingua locale integrato su gemini-3.5-flash-lite. Il titolo era una frase breve e innocua in svedese. Lo stesso titolo è stato tradotto da gemini-3.8-flash senza blocchi.

Google ha risposto con HTTP 200 e un singolo evento di stream senza candidati:

data: {"promptFeedback": {"blockReason": "PROHIBITED_CONTENT"},"usageMetadata": {"promptTokenCount": 417,"totalTokenCount": 417,"promptTokensDetails": [{"modality": "TEXT","tokenCount": 417}],"serviceTier": "standard"},"modelVersion": "gemini-3.5-flash-lite","responseId": "..."}

La richiesta include già BLOCK_NONE per le quattro categorie di sicurezza impostate da Discourse AI, quindi questo blocco non è influenzato da quelle impostazioni. Il registro di audit registra response_status 200.

Causa principale

  1. DiscourseAi::Completions::Endpoints::Gemini#decode_chunk legge solo candidates da ciascun evento di stream. promptFeedback non viene mai ispezionato, quindi una richiesta bloccata produce un risultato vuoto senza errori.
  2. DiscourseAi::Translation::LanguageDetector#detect restituisce nil quando la risposta non corrisponde al suo modello di tag linguistico, il che è il caso di una risposta vuota. L’argomento o il post mantiene locale NULL.
  3. Jobs::TopicsLocaleDetectionBackfill seleziona argomenti con locale NULL in ogni esecuzione e non ha un limite di tentativi, quindi leggendo il codice, la richiesta bloccata viene ripetuta ogni cinque minuti per tutta la durata in cui l’argomento è nella finestra di backfill. I post sono limitati a due tentativi di rilevamento al giorno dalla quota di rilocazione e vengono ritentati ogni giorno.
  4. I candidati per la traduzione richiedono un locale rilevato, quindi l’elemento non viene mai tradotto.

Lo stesso codice è presente su main al 2026-10-03.

Correzione suggerita

  1. Rilevare promptFeedback.blockReason nell’endpoint Gemini e sollevare o registrare un errore distinto e visibile che specifichi la ragione.
  2. Registrare il fallimento sull’argomento o sul post in modo che il backfill smetta di ripetere una richiesta che verrà nuovamente bloccata, oppure applicare un limite di tentativi al rilevamento degli argomenti come già esiste per i post.
  3. Mostrare gli elementi bloccati nella pagina di amministrazione della traduzione, in modo che un amministratore possa impostare la lingua manualmente.

Riproduzione

Il blocco dipende dal filtro di Google e non può essere forzato con un input noto. Le chiamate interessate possono essere trovate nel registro di audit:

SELECT id, created_at, language_model, post_id, topic_id, response_status
FROM ai_api_audit_logs
WHERE feature_name = 'translation'
  AND raw_response_payload LIKE '%blockReason%'
ORDER BY created_at

Soluzione temporanea

Impostare manualmente la lingua dell’argomento consente di procedere con la traduzione. Su questo sito, il modello di traduzione non ha bloccato lo stesso testo.