Skip to content

Fail TUI runs on terminal model-id rejection; ship a Bedrock Claude Code TUI provider#1278

Merged
atomantic merged 5 commits into
mainfrom
fix/tui-bedrock-reformat
Jun 15, 2026
Merged

Fail TUI runs on terminal model-id rejection; ship a Bedrock Claude Code TUI provider#1278
atomantic merged 5 commits into
mainfrom
fix/tui-bedrock-reformat

Conversation

@atomantic

Copy link
Copy Markdown
Owner

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-8 sent to a Bedrock-backed Claude Code, which answers API 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 as success, and with no tui-response.txt written 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

  1. Detect the terminal model-id rejection in-stream (errorDetection.js). A new immediate-fallback signal recognizes Claude Code's non-recoverable model rejections (Bedrock 400 model identifier is invalid, Anthropic 404 not_found_error) and fails the run as MODEL_NOT_FOUND, so runPromptThroughProvider benches the provider and retries its configured fallback (e.g. claude-code-tuiclaude-code-bedrock). Anchored on the literal API 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.

  2. Surface the failure reason inline (autoFixer.js). The 🤖 AI provider error detected pm2 log line now includes the model, error category, exit code, and the (single-line, capped) error text — so "why" is visible without opening data/runs/<id>/metadata.json.

  3. Ship a claude-code-tui-bedrock provider in the seed defaults (data.reference/providers.json, toolkit providers.sample.json). Completes the native/Bedrock × CLI/TUI matrix. Disabled with an empty AWS_BEARER_TOKEN_BEDROCK (opt-in; no secret in git), token marked in secretEnvVars; existing installs pick it up via setup-data.js's providers merge.

Test plan

  • errorDetection.test.js — terminal model-id rejection (Bedrock 400 + Anthropic 404) classifies as MODEL_NOT_FOUND; retryable 429/500 and an un-prefixed phrase do not trip the signal.
  • tuiPromptRunner.test.js — a streamed API Error … 400 … model identifier is invalid early-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.
  • Full affected suites green: errorDetection, tuiPromptRunner, providers, autoFixer, runner, manuscriptReformat.

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.
@atomantic atomantic merged commit 12036cc into main Jun 15, 2026
2 checks passed
@atomantic atomantic deleted the fix/tui-bedrock-reformat branch June 15, 2026 22:35
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.

1 participant