El diseño de retry backoff de Codex es ridículo: tras un 403, cuanto más reintentas más pareces un bot

Hace poco, al usar Codex CLI con un upstream no muy estable, me topé con un problema bastante gracioso, pero muy real.

Ahora Codex ha hecho que la reconexión en streaming sea un backoff exponencial hardcodeado. Las primeras veces parece normal, pero luego se dispara de forma muy exagerada:

  • La 1.ª vez, unos 0,2 segundos
  • La 5.ª vez, unos 3,2 segundos
  • La 10.ª vez ya pasa de 1 minuto
  • Más adelante incluso puede subir a una vez cada diez y tantos minutos, o incluso cada varias decenas de minutos

El problema es que este diseño asume por defecto que «cuanto más tiempo se falla, más lento debería ser el reintento». Pero en la práctica, muchos upstream no funcionan así:

  • El gateway falla de forma esporádica
  • El enrutamiento del backend es inestable
  • Algunos proxies compatibles con OpenAI devuelven temporalmente 403 / el estado de la cuota aún no se ha actualizado
  • En realidad, con intentarlo unas cuantas veces más, se recupera enseguida

Es decir, lo que realmente se necesita es:

  • Que el usuario decida por sí mismo la frecuencia de reintento
  • Al menos permitir reintentos con intervalo fijo, por ejemplo, una vez cada 500 ms
  • En lugar de quedar secuestrado por un backoff exponencial hardcodeado

Y aún más absurdo: Codex ahora le da al usuario stream_max_retries, pero no le da la posibilidad de configurar el intervalo de reintento ni la estrategia de backoff. Esto hace que:
puedes subir el número a 100, pero después del 10.º intento, cada espera empieza a volverse irrazonablemente larga, alejándose por completo del escenario de «con intentarlo unas cuantas veces más basta para que funcione».

Ya he llevado este problema al upstream:

Tengo la sensación de que este problema, en el fondo, no es solo que los parámetros estén mal elegidos, sino que el diseño se toma demasiadas atribuciones y no le deja al usuario libertad de elección.

Si en TOML se pudiera soportar explícitamente una configuración como la siguiente, al menos sería devolverle al usuario el poder de decisión:

[model_providers.custom]
stream_max_retries = 100
stream_retry_delay_ms = 500
stream_retry_backoff = "fixed"

Este tipo de necesidad es en realidad muy común:
«Este upstream suele fallar, pero si lo intentas rápido unas cuantas veces seguidas normalmente se recupera; por favor, no me lo alargues automáticamente a una vez cada varias decenas de minutos.»