Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions backend/app/services/claude_code.py
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,21 @@ def setup_claude_code_bash_timeouts() -> Dict[str, str]:
}


def setup_claude_code_resilience_env() -> Dict[str, str]:
"""Forward Claude Code CLI's own HTTP client retry/timeout tuning to the agent subprocess.

Without these, a transient network blip (DNS hiccup, provider connection drop) either
times out too slowly or gives up before Claude Code's own retry logic gets a chance to
recover — forcing the caller's phase-level resume loop (agent_query_with_resume) to
burn a resume attempt, or the whole phase, on something the CLI itself could retry past.
"""

return {
"API_TIMEOUT_MS": "120000", # 120 seconds per attempt before the CLI times out
"CLAUDE_CODE_MAX_RETRIES": "3", # retry a failed/timed-out request up to 3 times before giving up
"CLAUDE_ASYNC_AGENT_STALL_TIMEOUT_MS": "120000", # 120 seconds of no progress before an async subagent is considered stalled
}


async def simple_query():
options = ClaudeAgentOptions(
Expand Down Expand Up @@ -760,6 +775,7 @@ async def agent_query(
env_config.update(setup_claude_code_tmpdir())
env_config.update(setup_claude_code_max_output_tokens())
env_config.update(setup_claude_code_bash_timeouts())
env_config.update(setup_claude_code_resilience_env())
if extra_env:
env_config.update(extra_env)

Expand Down Expand Up @@ -1574,3 +1590,5 @@ async def planning_agent_fn(
# Planning agent writes markdown only; conversion agent (REPARSE_PLAN step) produces JSON.
logger.info("Planning agent complete — conversion agent will produce JSON from markdown")
return None