Repository navigation
fix(python-llamaindex-agent): disable streaming so LLM retries work - #1098
Merged
Merged
Conversation
ReActAgent.streaming defaults to True, which routes every LLM call through OpenAI._astream_chat. The network call lives in an inner generator that the caller iterates after the @llm_retry_decorator function has already returned, so tenacity wraps a function that performs no I/O. The openai SDK's own max_retries is out of reach too: with stream=True its retry-guarded _send_request returns once headers arrive, and the body is consumed later in AsyncStream.__stream__, which has no transport-error handling. Result: a mid-stream connection drop surfaces as a raw httpx.ReadError and fails the whole Actor run. With streaming=False the call goes through _achat, where the request sits directly in the decorated body and the response body is read inside the SDK's retry-guarded _send_request, so both retry layers engage. The template does not consume AgentStream events, only ToolCall and ToolCallResult, which the call_tool step emits regardless of this setting, so verbose logging is unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
apify-factory
approved these changes
Oct 22, 2026
apify-factory
left a comment
Contributor
There was a problem hiding this comment.
Looks good, nothing blocking.
🏭 Apify Factory auto approved ✅ — we looked twice, just to be sure
Every gate passed, and neither the reviewer nor a juror found anything a human needs to look at.
Approval locked to 4671eb454 · workflow run
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.
Note
TL;DR
autofix tests
Mechanism
ReActAgent(tools=..., llm=llm)leavesstreamingat its default ofTrue, so every LLM call goes throughllama_index.llms.openai.base.OpenAI._astream_chat. That method carries@llm_retry_decorator, but the network call lives inside an innerasync def gen()that the caller iterates after the decorated function has returned. Tenacity therefore wraps a function that performs no I/O and can never fire.The openai SDK's own
max_retries=3is out of reach for the same shape of reason: withstream=Truethe retry-guarded_send_requestreturns as soon as headers arrive, and the body is consumed later inAsyncStream.__stream__, which has no transport-error handling.So a mid-stream connection drop propagates as a raw
httpx.ReadErrorout ofawait handlerinagent.py, intorun_query'sexceptinmy_actor/main.py, which callsActor.fail()and exits 1.With
streaming=Falsethe call routes to_achat, where the request sits directly in the decorated function body and astream=Falseresponse has its body read inside the SDK's retry-guarded_send_request. Both retry layers engage.Verified against the installed library
ReActAgent(tools=[], llm=llm).streamingisTrue; passingstreaming=Falsesets it toFalse.AgentStreamevents — itsstream_events()loop handles onlyToolCallandToolCallResult, whichMultiAgentWorkflow.call_toolemits independently ofself.streaming. Verbose logging is unchanged.ReActAgent.take_stepdiffer only in whetherAgentStreamdeltas are written; both return the sameAgentOutputwith the sametool_calls.Evidence
Run 38986102096, job 117257819030 (2026-10-17,
windows-latest/ Python 3.12). The traceback runsreact_agent.py:158→_get_streaming_response→llama_index/llms/openai/base.py:831ingen→openai/_streaming.py→httpx.ReadError, with no tenacity frame in it.Honesty about confidence
This is n=1: one failure in 30 days, and the same SHA passed on the nightly schedule on 10-16, 10-18 and 10-19. The fix is unproven against a live failure — nobody can reproduce a dropped connection on demand, and I did not run the template against the OpenAI API. What is proven is the code path: the retry decorator demonstrably wraps no I/O on the streaming path, and does wrap it on the non-streaming path. The change removes a retry layer that was silently doing nothing; whether that particular
ReadErrorwould have been retried away is an inference, not a measurement.Archives
dist/templates/python-llamaindex-agent.zipis rebuilt automatically — the "Build template archives" workflow runs on every push tomasterand commitschore: Update template archives [skip ci]. Not hand-edited here, matching #1073.Checks run locally
ruff check,ruff format --check,ty checkon the template;pnpm run lint,pnpm run build,pnpm run test-without-templatesat the repo root. All pass. (pnpm run format:checkflags an untracked local.claude/settings.local.json, unrelated to this change.)🤖 Generated with Claude Code