Skip to content

feat(cli): numbered menu for require_one_of provider selection#734

Merged
AbirAbbas merged 1 commit into
mainfrom
feat/env-group-prompt-menu
Jul 7, 2026
Merged

feat(cli): numbered menu for require_one_of provider selection#734
AbirAbbas merged 1 commit into
mainfrom
feat/env-group-prompt-menu

Conversation

@AbirAbbas

Copy link
Copy Markdown
Contributor

Summary

Fixes the require_one_of provider prompt in af run / af install. When a
node needed one of several keys (e.g. SWE-AF's ANTHROPIC_API_KEY or
OPENROUTER_API_KEY), the old flow prompted for each option in sequence and
told the user to "fill in one, leave the rest blank" — so to pick OpenRouter you
had to know to press Enter past the Anthropic prompt. There was no visible way
to select. It also rendered the options as ANTHROPIC_API_KEY | OPENROUTER_API_KEY,
which reads poorly.

Before

  This node needs an LLM provider key — fill in one, leave the rest blank:
    ANTHROPIC_API_KEY  |  OPENROUTER_API_KEY
  Enter ANTHROPIC_API_KEY (Anthropic API key (Claude)) [hidden]:

After

  This node needs an LLM provider key — choose one:
    [1]  ANTHROPIC_API_KEY   Anthropic API key (Claude)
    [2]  OPENROUTER_API_KEY  OpenRouter API key (DeepSeek/Qwen/Llama/… — 200+ models)
  Enter 1 or 2 (or press Enter to skip): 2
  Enter OPENROUTER_API_KEY (…) [hidden]:

Typing 2 prompts only OpenRouter — no more guessing which blank does what.

Changes

  • Numbered menu for groups with 2+ options: each option on its own line with
    its description; a single line of input selects one, and only the chosen
    provider is then prompted for and persisted. A single-option group still
    prompts directly (no menu).
  • "or" instead of "|" everywhere options are enumerated — the menu prompt
    ("Enter 1 or 2 …") and the missing-env error ("at least one of A or B is
    required"), via a small orJoin helper.
  • Adds PromptLine to the Prompter interface (an echoed, trimmed line read for
    the selection — never used for secret values); TTYPrompter implements it.

Validation contract / tests

  • Menu prompts only the picked option; resolves & persists just that one.
  • Selecting the 2nd entry resolves that alternative.
  • Invalid / out-of-range selection re-prompts (bounded); exhausting attempts
    leaves the group unsatisfied without prompting for a secret.
  • Empty line skips the whole group (→ missing-env error), nothing prompted.
  • Selecting an option but leaving its value blank leaves the group unsatisfied.
  • Single-option group prompts directly, never consulting the menu.
  • orJoin / missing-env wording joins with "or", never "|".
  • PromptLine reads a trimmed line from stdin.

Verified end-to-end by driving a real af run swe-planner through a PTY (menu
rendered, selection routed to the right key). internal/packages + internal/ui
suites green; changed files are lint-clean. New functions: promptGroup 90%,
storeGroupOption 89%, orJoin 100%, PromptLine 83% (only error-return
branches uncovered).

🤖 Generated with Claude Code

When an interactive `af run`/`af install` hits an unsatisfied
require_one_of group, the old flow prompted for each option in sequence
and told the user to "fill in one, leave the rest blank" — so to use
OpenRouter you had to know to press Enter past the Anthropic prompt.
Nobody could tell how to select. It also listed options as
`ANTHROPIC_API_KEY  |  OPENROUTER_API_KEY`, which reads poorly.

Now a group with two or more options renders a numbered menu (each
option on its own line with its description), reads a single selection,
and prompts only for the chosen provider. A single-option group still
prompts directly. All user-facing option enumerations join with "or"
instead of "|" (menu prompt "Enter 1 or 2 …", and the missing-env
error).

Adds a PromptLine method to the Prompter interface (echoed line read for
the selection) with a stdin-swap test, and menu contract tests covering
select/retry/skip/exhaust/blank/single-option paths.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@AbirAbbas AbirAbbas requested a review from a team as a code owner July 7, 2026 21:53
@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

📊 Coverage gate

Thresholds from .coverage-gate.toml: per-surface ≥ 84%, aggregate ≥ 85%, max per-surface regression ≤ 1.0 pp, max aggregate regression ≤ 0.50 pp.

Surface Current Baseline Δ
control-plane 86.90% 87.40% ↓ -0.50 pp 🟡
sdk-go 91.90% 92.00% ↓ -0.10 pp 🟢
sdk-python 93.76% 93.73% ↑ +0.03 pp 🟢
sdk-typescript 90.42% 90.42% → +0.00 pp 🟢
web-ui 84.75% 84.79% ↓ -0.04 pp 🟡
aggregate 85.54% 85.75% ↓ -0.21 pp 🟡

✅ Gate passed

No surface regressed past the allowed threshold and the aggregate stayed above the floor.

@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

📐 Patch coverage gate

Threshold: 80% on lines this PR touches vs origin/main (from .coverage-gate.toml:thresholds.min_patch).

Surface Touched lines Patch coverage Status
control-plane 58 89.00%
sdk-go 0 ➖ no changes
sdk-python 0 ➖ no changes
sdk-typescript 0 ➖ no changes
web-ui 0 ➖ no changes

✅ Patch gate passed

Every surface whose lines were touched by this PR has patch coverage at or above the threshold.

@AbirAbbas AbirAbbas merged commit c07b197 into main Jul 7, 2026
27 checks passed
@AbirAbbas AbirAbbas deleted the feat/env-group-prompt-menu branch July 7, 2026 21:58
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