Skip to content

fix(llm): reject failed Claude CLI responses before returning stdout - #576

Merged
codelion merged 1 commit into
algorithmicsuperintelligence:mainfrom
Elon-Jiang:fix/claude-cli-exit-status
Nov 2, 2026
Merged

codelion merged 1 commit into
algorithmicsuperintelligence:mainfrom
Elon-Jiang:fix/claude-cli-exit-status

Conversation

@Elon-Jiang

Copy link
Copy Markdown
Contributor

Problem

ClaudeCodeLLM treats a non-zero Claude CLI exit as a warning when stdout is non-empty, returns that text as a successful generation and skips its retry loop. A failed process that writes a partial response or error text can consequently be passed to evolution as a valid model response. The sibling Copilot CLI backend already raises on non-zero exit.

Change

Raise RuntimeError on a non-zero exit before accepting stdout. Include the exit code and the existing 500-character stderr limit. The existing retry loop now retries this failure and raises after its configured attempt budget. Successful stdout, stdin prompt delivery, empty-response validation and subprocess timeout handling remain unchanged.

Add regressions for a real local Python process emitting stdout/stderr and exiting 7, a failed response followed by a successful retry through generate(), and retry exhaustion when every failed attempt emits stdout.

This is separate from #515, which changes the default budget in __init__; its production diff does not touch exit-status handling.

Validation

Python 3.12.13, macOS arm64, main cb49662150aa794149d477379c605a3bff0c08a2:

  • Provider tests before: 3 failed, 15 passed. After: 18 passed.
  • Separate public-path generate() check with a real offline CLI stub: before, returns the first failed process's partial stdout after one attempt; after, retries and returns only the successful response after two attempts.
  • OPENAI_API_KEY=test-key-for-unit-tests python -m unittest discover tests: 1,006 tests run, 2 skipped; all remaining tests pass.
  • Black, isort and git diff --check: pass.

The process regression executes only the running Python interpreter, and the offline public-path check replaces claude with a temporary script. No actual Claude CLI, authentication flow, or live model/provider was invoked. Public retry regressions mock the subprocess transport while exercising the production retry logic.

Prepared with AI assistance from an independent source review; subprocess status, returned output and attempt counts were verified directly.

@codelion
codelion merged commit 7e29fff into algorithmicsuperintelligence:main Nov 2, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants