diff --git a/hermes_cli/main.py b/hermes_cli/main.py index f817d6ea2..9c0368aa8 100644 --- a/hermes_cli/main.py +++ b/hermes_cli/main.py @@ -1560,7 +1560,7 @@ def _model_flow_api_key_provider(config, provider_id, current_model=""): def _model_flow_anthropic(config, current_model=""): - """Flow for Anthropic provider — API key, setup-token, or Claude Code creds.""" + """Flow for Anthropic provider — setup-token, API key, or Claude Code creds.""" import os from hermes_cli.auth import ( PROVIDER_REGISTRY, _prompt_model_selection, _save_model_choice, @@ -1571,15 +1571,13 @@ def _model_flow_anthropic(config, current_model=""): pconfig = PROVIDER_REGISTRY["anthropic"] - # Check for existing credentials (env vars or Claude Code) + # Check for existing credentials existing_key = ( get_env_value("ANTHROPIC_API_KEY") or os.getenv("ANTHROPIC_API_KEY", "") or get_env_value("ANTHROPIC_TOKEN") or os.getenv("ANTHROPIC_TOKEN", "") ) - - # Check for Claude Code auto-discovery cc_available = False try: from agent.anthropic_adapter import read_claude_code_credentials, is_claude_code_token_valid @@ -1590,21 +1588,75 @@ def _model_flow_anthropic(config, current_model=""): pass if existing_key: - print(f" Anthropic key: {existing_key[:12]}... ✓") - elif cc_available: - print(" Claude Code credentials: ✓ (auto-detected from ~/.claude/.credentials.json)") - else: - print("No Anthropic credentials found.") + print(f" Anthropic credentials: {existing_key[:12]}... ✓") + print() try: - new_key = input("ANTHROPIC_API_KEY (or Enter to cancel): ").strip() + update = input("Update credentials? [y/N]: ").strip().lower() + except (KeyboardInterrupt, EOFError): + update = "" + if update != "y": + pass # skip to model selection + else: + existing_key = "" # fall through to auth choice below + elif cc_available: + print(" Claude Code credentials: ✓ (auto-detected)") + print() + + if not existing_key and not cc_available: + # No credentials — show auth method choice + print() + print(" Choose authentication method:") + print() + print(" 1. Claude Pro/Max subscription (setup-token)") + print(" 2. Anthropic API key (pay-per-token)") + print(" 3. Cancel") + print() + try: + choice = input(" Choice [1/2/3]: ").strip() except (KeyboardInterrupt, EOFError): print() return - if not new_key: - print("Cancelled.") + + if choice == "1": + print() + print(" To get a setup-token from your Claude subscription:") + print() + print(" 1. Install Claude Code: npm install -g @anthropic-ai/claude-code") + print(" 2. Run: claude setup-token") + print(" 3. Open the URL it prints in your browser") + print(" 4. Log in and click \"Authorize\"") + print(" 5. Paste the auth code back into Claude Code") + print(" 6. Copy the resulting sk-ant-oat01-... token") + print() + try: + token = input(" Paste setup-token here: ").strip() + except (KeyboardInterrupt, EOFError): + print() + return + if not token: + print(" Cancelled.") + return + save_env_value("ANTHROPIC_API_KEY", token) + print(" ✓ Setup-token saved.") + + elif choice == "2": + print() + print(" Get an API key at: https://console.anthropic.com/settings/keys") + print() + try: + api_key = input(" API key (sk-ant-api03-...): ").strip() + except (KeyboardInterrupt, EOFError): + print() + return + if not api_key: + print(" Cancelled.") + return + save_env_value("ANTHROPIC_API_KEY", api_key) + print(" ✓ API key saved.") + + else: + print(" No change.") return - save_env_value("ANTHROPIC_API_KEY", new_key) - print("API key saved.") print() # Model selection diff --git a/hermes_cli/setup.py b/hermes_cli/setup.py index 5b29b9d24..1ea4ae0ca 100644 --- a/hermes_cli/setup.py +++ b/hermes_cli/setup.py @@ -1008,41 +1008,61 @@ def setup_model_provider(config: dict): elif provider_idx == 8: # Anthropic selected_provider = "anthropic" print() - print_header("Anthropic API Key or Claude Code Credentials") + print_header("Anthropic Authentication") from hermes_cli.auth import PROVIDER_REGISTRY pconfig = PROVIDER_REGISTRY["anthropic"] - print_info(f"Provider: {pconfig.name}") - print_info("Accepts API keys (sk-ant-api-*) or setup-tokens (sk-ant-oat-*)") - print_info("Get an API key at: https://console.anthropic.com/") - print_info("Or run 'claude setup-token' to get a setup-token from Claude Code") - print() # Check for Claude Code credential auto-discovery from agent.anthropic_adapter import read_claude_code_credentials, is_claude_code_token_valid cc_creds = read_claude_code_credentials() if cc_creds and is_claude_code_token_valid(cc_creds): print_success("Found valid Claude Code credentials (~/.claude/.credentials.json)") - if not prompt_yes_no("Use Claude Code credentials? (You can also enter an API key)", True): + if prompt_yes_no("Use these credentials?", True): + print_success("Using Claude Code subscription credentials") + else: cc_creds = None existing_key = get_env_value("ANTHROPIC_API_KEY") or get_env_value("ANTHROPIC_TOKEN") - if cc_creds and is_claude_code_token_valid(cc_creds): - # Use Claude Code creds — no need to prompt for a key - print_success("Using Claude Code subscription credentials") - elif existing_key: - print_info(f"Current: {existing_key[:12]}... (configured)") - if prompt_yes_no("Update key?", False): - api_key = prompt("Enter Anthropic API key or setup-token", password=True) - if api_key: - save_env_value("ANTHROPIC_API_KEY", api_key) - print_success("Anthropic key saved") - else: - api_key = prompt("Enter Anthropic API key or setup-token", password=True) - if api_key: - save_env_value("ANTHROPIC_API_KEY", api_key) - print_success("Anthropic key saved") - else: - print_warning("Skipped - agent won't work without an API key") + + if not (cc_creds and is_claude_code_token_valid(cc_creds)): + if existing_key: + print_info(f"Current credentials: {existing_key[:12]}...") + if not prompt_yes_no("Update credentials?", False): + existing_key = None # skip — keep existing + + if not existing_key and not (cc_creds and is_claude_code_token_valid(cc_creds)): + auth_choices = [ + "Claude Pro/Max subscription (setup-token)", + "Anthropic API key (pay-per-token)", + ] + auth_idx = prompt_choice("Choose authentication method:", auth_choices, 0) + + if auth_idx == 0: + print() + print_info("To get a setup-token from your Claude subscription:") + print_info(" 1. Install Claude Code: npm install -g @anthropic-ai/claude-code") + print_info(" 2. Run: claude setup-token") + print_info(" 3. Open the URL it prints in your browser") + print_info(" 4. Log in and click \"Authorize\"") + print_info(" 5. Paste the auth code back into Claude Code") + print_info(" 6. Copy the resulting sk-ant-oat01-... token") + print() + token = prompt("Paste setup-token here", password=True) + if token: + save_env_value("ANTHROPIC_API_KEY", token) + print_success("Setup-token saved") + else: + print_warning("Skipped — agent won't work without credentials") + else: + print() + print_info("Get an API key at: https://console.anthropic.com/settings/keys") + print() + api_key = prompt("API key (sk-ant-api03-...)", password=True) + if api_key: + save_env_value("ANTHROPIC_API_KEY", api_key) + print_success("API key saved") + else: + print_warning("Skipped — agent won't work without credentials") # Clear custom endpoint vars if switching if existing_custom: