fix(tui): keys flow — typing can no longer be saved as an API key; explain unavailable-model redirect; fit keys rows; picker legend and order (#1403) - #1404
Merged
Conversation
… key accepted, unexplained redirect, wrapped key rows, picker legend/order Red output: TestOverlay_TypedRunesDoNotReachInput leaked "hello there"; TestAPIKeys_RejectsImplausibleKey accepted "/model"; TestAPIKeys_RowsFitBoxAndLabels: status wrapped onto its own line, kimi labelled ChatGPT; TestModelSwitcher_FooterLegend/ProviderOrderCaseInsensitive fail. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WJGxhoFhA8JjkwZFcLGdS5
…en, reject implausible API keys, explain the unavailable-model redirect, fit keys rows, correct subscription labels, picker legend and case-insensitive provider order Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WJGxhoFhA8JjkwZFcLGdS5
…g-log entry Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WJGxhoFhA8JjkwZFcLGdS5
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
…vider under the direct gateway; config panel explains routing Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WJGxhoFhA8JjkwZFcLGdS5
…ed under the direct gateway; config panel says so instead of offering Direct Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WJGxhoFhA8JjkwZFcLGdS5
…e panel; footer drops the gateway arrows for such models Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WJGxhoFhA8JjkwZFcLGdS5
This was referenced Sep 8, 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.
Closes #1403
Summary
A first-time user could corrupt their provider setup just by typing: selecting a model whose provider had no key silently opened the API Keys panel, letters typed while it was open leaked into the chat input, and the next Enter plus text was stored as an API key (reproduced:
{"api_keys": {"deepseek": "/model"}}). This PR makes the panel explain why it opened, swallows typing while any panel is open (with a hint), rejects values that cannot be keys, fits the keys rows inside their box, names subscriptions correctly, adds a legend to the model picker, and sorts providers case-insensitively.Scope and issue reconciliation
All five items in #1403 plus a sixth found while verifying (recorded on the issue): an OpenRouter-only model selected under the default Direct gateway was sent to OpenRouter with a rewritten id (
deepseek-v4) and failed with 400.effectiveModelAndProvidernow leaves OpenRouter-provider models untouched; the config panel shows "served only by OpenRouter" instead of a Direct choice. Nothing else. Out of scope as stated: per-provider key formats, keys panel redesign.Impact analysis reconciliation
cmd/harnesscli/tui/model.go: overlay typing guard before the input fallthrough; key validation on confirm;apiKeyReasonset on redirect and cleared on close/open; keys list view sizes its box and truncates rows;subscriptionLabel,truncateVisible,wrapPlainhelpers.components/modelswitcher:legendSuffixappended to the three footers when availability is known; provider order case-insensitive.Architecture and duplication check
Searched
rg 'Route to input area|activeOverlay = "apikeys"|ChatGPT subscription|sort.Strings(order)' cmd/harnesscli/tui. Changes sit in the existing handlers; no new component.Test-first evidence
Red command:
go test ./cmd/harnesscli/tui/... -run 'Overlay_Typed|APIKeys_|UnavailableSelection|FooterLegend|ReadyFirst|CaseInsensitive'(commit 35c5672)Observed failure:
typed text leaked into the chat input while the keys overlay was open: "hello there";value "/model" must be rejected;status wrapped onto its own line: "│ not connected";kimi-subscription must be labelled as a Kimi subscription; legend and order tests failing.Green command:
go test ./cmd/harnesscli/tui/... -race→ 28 packages ok.Verification evidence
Live tmux 120x40, real daemon with OpenRouter configured, built binary:
Picker with legend and case-insensitive order:
Enter on an unavailable model now explains itself; rows fit; Kimi label:
Typing while the panel is open:
Confirming
/modelas a key:Routing fix, live: selecting
deepseek/deepseek-v4-proand sending a message now completes (captures in the PR comments).Rollout and rollback
TUI-only; rebuild with
scripts/install.sh, restart the TUI. Rollback: revert. Users who already stored a bogus key can overwrite it in/keys.Documentation
website/docs/cli/tui.mdnote on the picker and keys panel; engineering-log entry.Contract checklist
🤖 Generated with Claude Code
https://claude.ai/code/session_01WJGxhoFhA8JjkwZFcLGdS5