fix(agent): escalate stream retry delays and honor Retry-After - #1247
Conversation
The single stream retry slept a fixed constant at both call sites, so a sustained provider overload burned the retry budget at a flat 1s per iteration. Each site now doubles the delay across consecutive retryable failures (capped, exponent clamped like the worker-level backoff) and honors a provider-suggested Retry-After on 429/529, bounded by the new SWARM_STREAM_RETRY_MAX_DELAY_S / VT_STREAM_RETRY_MAX_DELAY_S knobs. Retry-After is extracted once on ProviderStreamError so every retry site benefits. Retry counts and first-failure timing are unchanged. Closes HKUDS#1208 Signed-off-by: lorenzozanee <wyz0707@proton.me>
#1247 turns the stream-retry delay from a flat 1.0s constant into a capped exponential that reaches 30s by default, and a provider Retry-After can ask for the cap on the very first failure. Both retry sites served that with a blocking sleep, so pressing Stop mid-backoff was not observed until the whole delay elapsed — and the doomed retry stream was issued anyway. Both sites now wait on the cancellation event instead, which returns the moment it is set, and skip the retry stream when it is. The swarm worker keeps time.sleep when no cancel_event was injected. Regression test asserts the 30s delay is requested but the run returns in under 5s with the retry stream never issued; it fails (37s) against a sleep.
|
Merged. Putting One follow-up pushed on top ( Both sites now wait on the cancellation event, which returns the moment it is set, and skip the retry when it is. The swarm worker keeps |
Summary
ProviderStreamError, so every current and future retry site can use it.Why
Closes #1208 — the two layers left open after #1210. During a sustained provider overload each site still burned its single retry after a flat 1s, and nothing in this repo's own LLM retry layers reads Retry-After. The OpenAI SDK honors it for pre-stream errors, but mid-stream failures (connection reset, no headers) and the swarm/agent-loop layers compose to exhaust the retry budget in seconds. Retry-After extraction lives on
ProviderStreamErrorat the provider layer, per the discussion on #1208, so every retry site benefits.Changes
ProviderStreamErrorcarriesretry_after_s, parsed defensively from the original exception's response headers (absent/garbage → None, no behavior change for callers that ignore it).SWARM_STREAM_RETRY_DELAY_S/VT_STREAM_RETRY_DELAY_Sexactly as before, each consecutive failure doubles the delay (capped, exponent clamped at 62 like the worker-level backoff), and only a clean iteration resets the streak — a successful retry does not.SWARM_STREAM_RETRY_MAX_DELAY_S/VT_STREAM_RETRY_MAX_DELAY_Sknobs (default 30s) so a broken header cannot freeze a run.ge=0, cap >= base validation;SWARM_STREAM_RETRY_MAX_DELAY_Sdocumented inagent/.env.example(VT_* stream tuning has never been listed there, so the VT knob follows existing precedent).Test Plan
pytest agent/tests/test_swarm_worker_stream_retry.py agent/tests/test_agent_loop_stream_retry.py agent/tests/test_swarm_worker_retry_backoff.py agent/tests/test_swarm_worker_content_filter.py agent/tests/test_chat_llm_streaming.py agent/tests/test_env_schema.py -q→ 137 passed)agent/tests/test_stream_retry_escalation.py, 23 tests; 160 passed for the seven suites together): escalation across consecutive iterations with successful retries, streak reset on a clean iteration, first-failure backward compatibility, Retry-After honored/clamped/garbage-fallback, extraction unit tests, config validation. All provider behavior mocked; no live provider calls.py_compile/compileallpassed on all changed filesChecklist
src/agent/,src/session/,src/providers/) without prior discussion — the changes tosrc/agent/loop.pyandsrc/providers/chat.pyimplement exactly the layers flagged as open and accepted on Retry delays don't escalate across the three retry layers — a sustained provider overload burns every retry budget in seconds #1208, with provider-layer placement per the maintainer comment thereagent/.env.example)Risk and boundary
No broker, live-trading, MCP, network, secret, or deployment behavior is changed. Retry counts are unchanged (one stream retry per site). With the new cap knobs at their defaults the worst added wait per attempt is 30s; setting the existing
SWARM_STREAM_RETRY_DELAY_S=0restores immediate stream retry timing. Rollback: revert the commit.