Skip to content

feat: interactive provider + API-key setup in the TUI#24

Open
jaylann wants to merge 10 commits into
mainfrom
feat/interactive-api-key-setup
Open

feat: interactive provider + API-key setup in the TUI#24
jaylann wants to merge 10 commits into
mainfrom
feat/interactive-api-key-setup

Conversation

@jaylann

@jaylann jaylann commented Jun 8, 2026

Copy link
Copy Markdown
Owner

This pull request introduces an interactive, TUI-based provider selection and API key setup for the translate command. When no API key is configured for the required provider (or when no model is specified), the CLI now guides the user through a friendly terminal prompt to choose a provider and enter their API key—persisting it to a local .env file for future use.

Key changes

  • Provider selection menu
    If no model or API key is provided, a menu lists available providers (Anthropic, OpenAI, Google, OpenRouter) with their default model. The user picks one.

  • API key prompt
    For the selected provider, the user is asked to enter their key (masked input). The key is saved to .env in the current directory and exported to the environment for the current run.

  • Automatic resolution

    • When a model is specified but the corresponding provider key is missing, the user is prompted only for that provider’s key.
    • When no model is specified, the default (Anthropic/sonnet) is used if its key exists; otherwise the provider menu appears.
  • Dry‑run support
    The --dry-run flag bypasses the API key requirement entirely—no prompts appear, even in an interactive terminal.

  • .env loading
    The project now loads .env files from the working directory on startup, so keys saved during a previous interactive session are automatically picked up.

  • Model validation
    The --model option is now optional. When omitted, the CLI defaults to sonnet (Anthropic) if the key is present, or the user’s chosen provider otherwise. Explicit model validation is only performed when a model argument is supplied.

  • New test coverage
    Unit tests cover the provider resolution logic, .env saving, menu/key prompt flow, and dry‑run behavior.

This enhancement makes it easier for new users to get started without manually editing configuration files, while still being transparent and scriptable in non‑interactive environments.

Summary by CodeRabbit

  • New Features

    • Load configuration from .env files at startup.
    • Interactive provider selection and secure API-key prompt that persists keys to a local .env and exports them for the running session.
    • --model is now optional; defaults to Anthropic when credentials exist, otherwise prompts for provider.
  • Bug Fixes

    • Dry-run mode skips live pricing and key prompts.
  • Tests

    • Added tests covering provider selection, interactive menu behavior, and API-key persistence.

When no provider API key is set, the translate command now guides the user
through a clean Rich input flow instead of failing inside pydantic-ai:
- If no model is given, show a provider picker (Anthropic/OpenAI/Google/OpenRouter)
- Prompt for the matching key in a masked input box, derived from -m when given
- Save the key to .env and auto-load .env on startup (adds python-dotenv)

Non-TTY runs and --dry-run skip the prompt, preserving existing behavior.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 8, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: c5f481a1-6173-43d6-8a83-63db44b780b5

📥 Commits

Reviewing files that changed from the base of the PR and between aaed5f5 and e8c7f4b.

📒 Files selected for processing (2)
  • src/xcstrings_translator/cli.py
  • tests/test_cli.py
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/xcstrings_translator/cli.py
  • tests/test_cli.py

📝 Walkthrough

Walkthrough

Adds dotenv/readchar deps, loads .env, and implements provider metadata, an interactive TTY provider picker with non‑TTY fallback, secure API-key prompting that persists keys to ./.env and os.environ, makes --model optional and delegates provider/key assurance to a new helper, and adds tests covering these flows.

Changes

Interactive Provider Setup and API Key Management

Layer / File(s) Summary
Runtime Dependencies
pyproject.toml
Add python-dotenv>=1.0 and readchar>=4.0 to support environment file loading and interactive keyboard input.
Provider/Key Management Utilities
src/xcstrings_translator/cli.py
Define provider metadata (env var names, default models, URLs), implement interactive provider picker (TTY arrow-key menu with wrap-around and non-TTY numbered fallback), prompt for missing API keys with masking, persist keys to ./.env and export to os.environ, and add _ensure_provider_and_key to resolve provider/model and ensure credentials are available.
CLI Command Integration
src/xcstrings_translator/cli.py
Change translate command's --model parameter to optional `str
Provider/Key Setup Test Coverage
tests/test_cli.py
Add TestProviderKeySetup with tests for provider resolution (including openrouter mapping), .env key writing/updating and os.environ export, _ensure_provider_and_key behavior for TTY/non-TTY/dry-run scenarios, interactive menu navigation (arrow keys, wrapping, numeric shortcuts), and end-to-end menu+key persistence.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested labels

feature, dependencies, tests, security

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 47.83% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main feature: interactive provider and API-key setup for the TUI. It directly matches the primary changes (provider selection menu, API-key prompting, .env file management).
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@lanfermann-reviewer

This comment has been minimized.

Comment thread tests/test_cli.py Outdated
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@lanfermann-reviewer

This comment has been minimized.

jaylann and others added 2 commits June 9, 2026 01:38
Replace the numbered provider prompt with an interactive ↑/↓ menu (also j/k
and number-key shortcuts, Enter to select) rendered via Rich Live + readchar.
Falls back to the numbered prompt when stdin is not an interactive TTY.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@lanfermann-reviewer

This comment has been minimized.

Comment thread tests/test_cli.py Outdated
@jaylann

jaylann commented Jun 8, 2026

Copy link
Copy Markdown
Owner Author

@kody start-review

@jaylann

jaylann commented Jun 9, 2026

Copy link
Copy Markdown
Owner Author

@kody start-review

Annotate the new TestProviderKeySetup methods and the _feed_keys helper with
parameter and return types (pytest.MonkeyPatch, Path, list[str], -> None) to
satisfy the project's Typed classifier / py.typed marker.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@lanfermann-reviewer

lanfermann-reviewer Bot commented Jun 9, 2026

Copy link
Copy Markdown

Kody Review Complete

Great news! 🎉
No issues were found that match your current review configurations.

Keep up the excellent work! 🚀

Kody Guide: Usage and Configuration
Interacting with Kody
  • Request a Review: Ask Kody to review your PR manually by adding a comment with the @kody start-review command at the root of your PR.

  • Validate Business Logic: Ask Kody to validate your code against business rules by adding a comment with the @kody -v business-logic command.

  • Provide Feedback: Help Kody learn and improve by reacting to its comments with a 👍 for helpful suggestions or a 👎 if improvements are needed.

Current Kody Configuration
Review Options

The following review options are enabled or disabled:

Options Enabled
Bug
Performance
Security
Business Logic

Access your configuration settings here.

@coderabbitai coderabbitai Bot added dependencies Pull requests that update a dependency file feature security tests breaking labels Jun 9, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/xcstrings_translator/cli.py (1)

694-709: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Make --dry-run fully side-effect free.

Line 696 skips key prompts, but Line 708 still passes fetch_live_pricing=not no_fetch, and _translate_one_file() creates XCStringsTranslator before the dry-run return path. That means a dry run can still perform network I/O for live pricing. Gate pricing fetches behind not dry_run too.

Proposed fix
     common = {
         "languages": target_langs,
         "model": model,
         "resolved": resolved,
         "batch_size": batch_size,
         "concurrency": concurrency,
         "overwrite": overwrite,
         "dry_run": dry_run,
         "app_context": app_context,
         "fill_missing": fill_missing,
-        "fetch_live_pricing": not no_fetch,
+        "fetch_live_pricing": not dry_run and not no_fetch,
     }

As per coding guidelines, src/xcstrings_translator/cli.py: "dry-run paths that perform writes or live API calls".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/xcstrings_translator/cli.py` around lines 694 - 709, The dry-run path
still triggers live pricing and potentially constructs XCStringsTranslator;
change the common dict entry "fetch_live_pricing" to be False when dry_run is
true (i.e., "fetch_live_pricing": not no_fetch and not dry_run) and ensure
callers like _translate_one_file do not instantiate XCStringsTranslator or
otherwise perform network I/O when dry_run is true—either by early-returning
before creating XCStringsTranslator or by passing dry_run through and gating
network calls inside XCStringsTranslator. Use the existing symbols
_ensure_provider_and_key, common, _translate_one_file, XCStringsTranslator,
fetch_live_pricing, dry_run and no_fetch to locate the code to change.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/xcstrings_translator/cli.py`:
- Around line 573-580: Update the help string for the CLI option named model
(the Annotated typer.Option in cli.py) to remove the misleading "Default:
sonnet" text and instead describe the actual behavior when no model is provided
(e.g., default is None, users may be prompted to choose a provider or a
provider-specific default may apply); ensure the help mentions valid formats
(sonnet, gpt-5, gemini-2.5-flash, openrouter:vendor/model or provider:model) and
that first-time users without an Anthropic key may be prompted to select a
provider.

In `@tests/test_cli.py`:
- Around line 300-305: The test test_ensure_non_tty_no_prompt unpacks (model,
resolved) from _ensure_provider_and_key but only asserts model; add an assertion
that verifies the second return value indicates no API key was resolved (e.g.,
assert resolved is False) to fully validate the non-TTY behavior of
_ensure_provider_and_key.
- Around line 307-312: The test unpacks both model and resolved but only asserts
resolved; add an assertion that model == "gpt-5.4" to confirm
_ensure_provider_and_key returns the expected model string. Update the
test_ensure_dry_run_skips_key case to include assert model == "gpt-5.4"
immediately before or after the existing assert on resolved so both return
values are validated.

---

Outside diff comments:
In `@src/xcstrings_translator/cli.py`:
- Around line 694-709: The dry-run path still triggers live pricing and
potentially constructs XCStringsTranslator; change the common dict entry
"fetch_live_pricing" to be False when dry_run is true (i.e.,
"fetch_live_pricing": not no_fetch and not dry_run) and ensure callers like
_translate_one_file do not instantiate XCStringsTranslator or otherwise perform
network I/O when dry_run is true—either by early-returning before creating
XCStringsTranslator or by passing dry_run through and gating network calls
inside XCStringsTranslator. Use the existing symbols _ensure_provider_and_key,
common, _translate_one_file, XCStringsTranslator, fetch_live_pricing, dry_run
and no_fetch to locate the code to change.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 61746637-4b0b-4f73-84cb-85a99416666c

📥 Commits

Reviewing files that changed from the base of the PR and between bf1ab62 and aaed5f5.

⛔ Files ignored due to path filters (1)
  • uv.lock is excluded by !**/*.lock, !**/*.lock
📒 Files selected for processing (3)
  • pyproject.toml
  • src/xcstrings_translator/cli.py
  • tests/test_cli.py

Comment thread src/xcstrings_translator/cli.py
Comment thread tests/test_cli.py
Comment thread tests/test_cli.py
- Fix --model help text now that the option defaults to None instead of sonnet
- Make --dry-run side-effect free: skip live pricing fetch (no network I/O)
- Assert both return values in the non-TTY and dry-run resolution tests

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@jaylann

jaylann commented Jun 9, 2026

Copy link
Copy Markdown
Owner Author

All review findings addressed in e8c7f4b:

  • --model help text — rewritten to describe the new None default (sonnet when an Anthropic key exists, otherwise provider prompt).
  • Dry-run side effects (CodeRabbit, Major / outside-diff)fetch_live_pricing is now gated as not dry_run and not no_fetch, so --dry-run no longer makes live OpenRouter pricing network calls.
  • Incomplete test assertionstest_ensure_non_tty_no_prompt now asserts resolved == "anthropic:claude-sonnet-4-6" and test_ensure_dry_run_skips_key asserts model == "gpt-5.4".
  • Type annotations on tests (Kody) — already added in aaed5f5.

ruff check, ruff format --check, and the full pytest suite pass locally.

@jaylann

jaylann commented Jun 9, 2026

Copy link
Copy Markdown
Owner Author

@lanfermann-reviewer is this PR fine

1 similar comment
@jaylann

jaylann commented Jun 9, 2026

Copy link
Copy Markdown
Owner Author

@lanfermann-reviewer is this PR fine

@jaylann

jaylann commented Jun 9, 2026

Copy link
Copy Markdown
Owner Author

@lanfermann-reviewer is this PR fine

@lanfermann-reviewer

Copy link
Copy Markdown

The PR looks solid overall. Adding interactive TUI provider selection and API key setup greatly improves onboarding. Here are a few points to consider:

  • Positive: User-friendly guided flow, dry‑run support, and automatic .env loading reduce manual steps. The optional --model with smart defaulting is a nice touch.
  • Potential improvement: Ensure the interactive prompts degrade gracefully in non-interactive terminals (e.g., CI/CD pipelines). The description mentions non‑interactive fallback, but verify there’s no hanging prompt.
  • Security: Storing API keys in a local .env is fine for CLI tools, but a small reminder in the README to keep the file secure would help.
  • Tests: New unit tests are included, which is great. Consider adding an integration test for the full prompt flow if not already present.

Otherwise, the changes are well‑contained and follow good UX practices. I’d approve it after addressing the terminal fallback check.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

breaking dependencies Pull requests that update a dependency file feature security tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant