feat: extract and use retry delay from Gemini 429 error payloads - #662
Conversation
When using Gemini models a 429 response often includes a retryDelay in the JSON. This is typically o(10) seconds, sometimes more. cecli uses a blind backoff computation. This can result in denial of service when using Gemini models. To correct this, respect the retryDelay delivered in Gemini model responses. - Add `_extract_gemini_retry_delay` helper to `Model` class in `cecli/models.py` to extract suggested `retryDelay` (in seconds) from 429 error response payloads. - Update `send_completion()` and `simple_send_with_retries()` to prioritize Gemini's suggested retry delay over blind unilateral backoff multipliers when available. - Add unit tests in `tests/unit/test_gemini_retry_backoff.py` covering valid retryDelay extraction, JSON string payloads, non-429 responses, and missing details fields. Co-authored-by: cecli (gemini/gemini-3.6-flash)
Co-authored-by: cecli (gemini/gemini-3.6-flash)
Co-authored-by: cecli (gemini/gemini-3.6-flash)
|
For an example, the actual Gemini payload with a 429 looks like this: And that |
|
I think this whole thing can be simplified with the dot separated path accessor I use quite a bit with nested.getter(). It's built for pretty much exactly this type of thing and we can make the delay extraction provider agnostic by just adding path strings. The syntax would be something like: nested.getter(err, ["..that long api path"], None) Edit: I guess there's a bit of looping involved, but most of the deeply nested object logic and intermediate json checking and parsing can be done with the above and utils.split_concatenated_json() to keep the code base consistent-ish |
- extract retry delay via Gemini payload and HTTP headers - add tests for same Co-authored-by: cecli (gemini/gemini-3.7-flash)
|
OK see what you think about this. I've generalized it beyond Gemini. The other providers use headers; Gemini uses a value in the payload. Unfortunately the black formatter (via pre-commit) seems to be changing lots of minor formatting things that are irrelevant. |
|
Yep, this is exactly what I meant. I want to keep most of the model specific logic inside of the llms module because it's really easy for agents to start adding model/provider specific shims in essentially random places around the code base if we let them and it makes the core agent loop more brittle as a result. Thanks! |
When using Gemini models a 429 response often includes a retryDelay in the JSON. This is typically o(10) seconds, sometimes more. cecli uses a blind backoff computation. This can result in denial of service when using Gemini models. To correct this, respect the retryDelay delivered in Gemini model responses.
Add
_extract_gemini_retry_delayhelper toModelclass incecli/models.pyto extract suggestedretryDelay(in seconds) from 429 error response payloads.Update
send_completion()andsimple_send_with_retries()to prioritize Gemini's suggested retry delay over blind unilateral backoff multipliers when available.Add unit tests in
tests/unit/test_gemini_retry_backoff.pycovering valid retryDelay extraction, JSON string payloads, non-429 responses, and missing details fields.Co-authored-by: cecli (gemini/gemini-3.6-flash)