Fail TUI runs on terminal model-id rejection; ship a Bedrock Claude Code TUI provider#1278
Merged
Conversation
Installs running Claude Code against Amazon Bedrock can now drive the interactive TUI on Bedrock without hand-editing providers.json. Mirrors the existing native/Bedrock x CLI/TUI matrix; ships disabled with an empty AWS_BEARER_TOKEN_BEDROCK (opt-in, no secret in git) and marks the token in secretEnvVars. Existing installs pick it up via setup-data.js's providers merge.
…e error screen A Claude Code TUI run whose model id is rejected by the backend (e.g. a bare 'claude-opus-4-8' sent to a Bedrock-backed Claude Code, which answers '400 The provided model identifier is invalid') left the TUI idle at an unanswered prompt. The one-shot runner read that as success, and with no tui-response.txt written it scraped the error screen as the model's response -- surfacing downstream as the baffling 'AI reformat changed the wording' (the integrity guard correctly rejecting the screen garbage). Detect the terminal model-id rejection (Bedrock 400 'model identifier is invalid', Anthropic 404 not_found_error) as an immediate fallback signal so the run fails as MODEL_NOT_FOUND and the configured fallback fires. The signal is anchored on the literal 'API Error' + a 400/404 status so a retryable 429/500 (which Claude Code auto-retries) is left alone. Also surface the actual failure reason + category + exit code in the 'AI provider error detected' log line so pm2 logs explain why a run failed without opening data/runs/<id>/metadata.json.
A thrown assertion would otherwise leave console.log mocked for the rest of the file's tests.
…el-id signal Line-anchor the immediate-fallback pattern (like the sibling extra-usage signal) and require the 400/404 status to immediately follow the 'API Error[(model)]:' prefix, so (1) a CoS agent echoing a full error line mid-prose in its own output isn't killed (the agent spawn paths stop on this signal) and (2) a retryable 429 line that incidentally contains '404 not found' isn't treated as terminal. Adds guard tests for both; fixes a truncated run-id in the changelog example.
…-shot TUI runner Codex flagged that even line-anchored, putting the model-id rejection in the SHARED immediate-fallback detector lets a long-running agent that echoes the error at a line start (cat-ing a log, running these tests, investigating this failure) get killed and misclassified MODEL_NOT_FOUND. Move the detection out of IMMEDIATE_FALLBACK_SIGNALS into a dedicated detectTerminalModelError / createTerminalModelErrorDetector consulted only by tuiPromptRunner (the one-shot path where the idle->false-success->scrape bug lives). The agent spawn paths and CLI runner no longer see it; CLI runs still catch the same failure via the non-zero exit code. Adds a test pinning that the shared detector returns null for the model error.
This was referenced Jun 15, 2026
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.
Summary
Fixes the AI manuscript Reformat failure (
AI reformat changed the wording, so it was discarded) and the broader silent-corruption class behind it, plus ships a Bedrock-backed Claude Code TUI provider option.Root cause. A Claude Code TUI run whose model id is rejected by the backend — e.g. a bare Anthropic id
claude-opus-4-8sent to a Bedrock-backed Claude Code, which answersAPI Error (claude-opus-4-8): 400 The provided model identifier is invalid— left the TUI idle at an unanswered prompt. The one-shot runner read the idle assuccess, and with notui-response.txtwritten it scraped the error screen and returned that garbage as the model's response. For Reformat the integrity guard correctly rejected the garbage (hence the misleading message); other TUI-backed stages silently consumed it.Changes
Detect the terminal model-id rejection in-stream (
errorDetection.js). A new immediate-fallback signal recognizes Claude Code's non-recoverable model rejections (Bedrock400 model identifier is invalid, Anthropic404 not_found_error) and fails the run asMODEL_NOT_FOUND, sorunPromptThroughProviderbenches the provider and retries its configured fallback (e.g.claude-code-tui→claude-code-bedrock). Anchored on the literalAPI Error+ a 400/404 status so an agent merely printing the phrase can't trip it, and retryable 429/500 (which Claude Code auto-retries) is deliberately left alone. The post-hoc categorizer is broadened to match the same wording.Surface the failure reason inline (
autoFixer.js). The🤖 AI provider error detectedpm2 log line now includes the model, error category, exit code, and the (single-line, capped) error text — so "why" is visible without openingdata/runs/<id>/metadata.json.Ship a
claude-code-tui-bedrockprovider in the seed defaults (data.reference/providers.json, toolkitproviders.sample.json). Completes the native/Bedrock × CLI/TUI matrix. Disabled with an emptyAWS_BEARER_TOKEN_BEDROCK(opt-in; no secret in git), token marked insecretEnvVars; existing installs pick it up viasetup-data.js's providers merge.Test plan
errorDetection.test.js— terminal model-id rejection (Bedrock 400 + Anthropic 404) classifies asMODEL_NOT_FOUND; retryable 429/500 and an un-prefixed phrase do not trip the signal.tuiPromptRunner.test.js— a streamedAPI Error … 400 … model identifier is invalidearly-fails the run (success: false,fallback-signal) instead of idling to a bogus-scrape success.autoFixer.test.js— the failure log line contains the reason, category, exit code, and model.errorDetection,tuiPromptRunner,providers,autoFixer,runner,manuscriptReformat.