-
Notifications
You must be signed in to change notification settings - Fork 7
Catch silent Claude-coder failures: per-model preflight + bundled-CLI doctor check (0.1.2)#17
Merged
ofer-mendelevitch-thenvoi merged 2 commits intoJun 17, 2026
Merged
Conversation
A Claude coder could connect to its room, receive its dispatch, and then silently do nothing — no crash, no chat, nothing the watchdog could catch — so a subtask sat "pending" forever. Root cause: the coder ran an opus model through the stale Claude Code CLI bundled inside an old claude-agent-sdk. That CLI emits the legacy `thinking.type.enabled` request shape, which current models reject with a 400; band's adapter swallows the error (logs at DEBUG, marks the message processed) and emits nothing. The failure was invisible because preflight only probed a default Sonnet model, never the coder's opus. Changes: - preflight: probe each *distinct* configured Claude model (not a hardcoded default), and classify the `invalid_request_error` / "is not supported for this model" 400 with a remediation pointing at `pip install -U claude-agent-sdk`. A model that rejects the request shape now fails `cb run` fast instead of producing a silent do-nothing agent. - doctor: new "Bundled Claude CLI" check warns when the CLI bundled in claude_agent_sdk is older than the system `claude` (the SDK uses the bundled one). - bump version to 0.1.2. Per-turn "zombie" detection at runtime is intentionally not included: the error is swallowed inside band's adapter, which codeband can't intercept without band SDK hooks. The per-model preflight prevents this specific failure before agents spawn. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Ofer Mendelevitch <ofermend@gmail.com>
_claude_models hand-listed conductor/mergemaster + the 4 pools and duplicated the spawner's per-role default-model logic, so a newly added role would be silently skipped by the preflight probe. Discover models by introspecting the AgentsConfig fields (duck-typing the singleton vs pool shapes the rest of the code already uses); only the one non-Sonnet default (coders -> Opus) stays in _POOL_MODEL_DEFAULT. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Ofer Mendelevitch <ofermend@gmail.com>
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.
Problem
A Claude coder could connect to its Band room, receive its dispatch, and then silently do nothing — no crash, no chat message, nothing the Watchdog could catch — so an assigned subtask sat
pendingforever.Root cause (confirmed by live repro)
Reproduced with
cb run --agent coder-claude_sdk-0 --debug+ a human @mention; the debug log showed:claude-agent-sdk(bundled2.1.81vs system2.1.179).thinking.type.enabledrequest shape, which current models reject with a 400 (thinking.type.enabled is not supported for this model. Use thinking.type.adaptive).claude_sdkadapter swallows the error (logs at DEBUG,0ドル.0000, marks the message processed) and emits nothing → a healthy-looking zombie.Changes
preflight.py): probe each distinct configured Claude model (not a hardcoded default), threadingmodelthroughcheck_claude_auth. New classified patterns for theinvalid_request_error/is not supported for this model400 with remediation pointing atpip install -U claude-agent-sdk. A model that rejects the request shape now failscb runfast instead of spawning a silent do-nothing agent.doctor.py): new "Bundled Claude CLI" check — warns when the CLI bundled inclaude_agent_sdkis older than the systemclaude(agents use the bundled one), with the same remediation.Deliberately out of scope
Per-turn "zombie" detection at runtime is not included: the 400 is swallowed inside band's adapter, which codeband can't intercept without band SDK hooks (
player_claude.pyonly exposes.adaptertoAgent.create()). The per-model preflight prevents this specific failure before agents spawn, which is the higher-leverage fix.Tests
thinking/invalid_request400; verifies the probe uses the configured model; verifiesrun_preflightprobes each distinct model (Opus and Sonnet).ruffclean.🤖 Generated with Claude Code