diff --git a/apps/desktop/src/components/desktop-onboarding-overlay.test.tsx b/apps/desktop/src/components/desktop-onboarding-overlay.test.tsx index 379642c9973..1e31fbd3d95 100644 --- a/apps/desktop/src/components/desktop-onboarding-overlay.test.tsx +++ b/apps/desktop/src/components/desktop-onboarding-overlay.test.tsx @@ -52,11 +52,11 @@ describe('onboarding Picker', () => { expect(screen.getByText('Nous Portal')).toBeTruthy() expect(screen.getByText('Recommended')).toBeTruthy() - expect(screen.queryByText('Anthropic Claude')).toBeNull() + expect(screen.queryByText('Anthropic API Key')).toBeNull() fireEvent.click(screen.getByRole('button', { name: 'Other providers' })) - expect(screen.getByText('Anthropic Claude')).toBeTruthy() + expect(screen.getByText('Anthropic API Key')).toBeTruthy() expect(screen.getByRole('button', { name: 'Collapse' })).toBeTruthy() }) @@ -64,8 +64,8 @@ describe('onboarding Picker', () => { setProviders([provider('anthropic', 'Anthropic Claude'), provider('openai-codex', 'OpenAI Codex / ChatGPT')]) render() - expect(screen.getByText('Anthropic Claude')).toBeTruthy() - expect(screen.getByText('OpenAI Codex / ChatGPT')).toBeTruthy() + expect(screen.getByText('Anthropic API Key')).toBeTruthy() + expect(screen.getByText('OpenAI OAuth (ChatGPT)')).toBeTruthy() expect(screen.queryByText('Other sign-in options')).toBeNull() expect(screen.queryByText('Recommended')).toBeNull() }) diff --git a/apps/desktop/src/components/desktop-onboarding-overlay.tsx b/apps/desktop/src/components/desktop-onboarding-overlay.tsx index 2763b93b635..75366731549 100644 --- a/apps/desktop/src/components/desktop-onboarding-overlay.tsx +++ b/apps/desktop/src/components/desktop-onboarding-overlay.tsx @@ -102,12 +102,14 @@ const API_KEY_OPTIONS: ApiKeyOption[] = [ const PROVIDER_DISPLAY: Record = { nous: { order: 0, title: 'Nous Portal' }, - anthropic: { order: 1, title: 'Anthropic Claude' }, - 'openai-codex': { order: 2, title: 'OpenAI Codex / ChatGPT' }, - 'minimax-oauth': { order: 3, title: 'MiniMax' }, + 'openai-codex': { order: 1, title: 'OpenAI OAuth (ChatGPT)' }, + 'minimax-oauth': { order: 2, title: 'MiniMax' }, + 'qwen-oauth': { order: 3, title: 'Qwen Code' }, 'xai-oauth': { order: 4, title: 'xAI Grok' }, - 'claude-code': { order: 5, title: 'Claude Code' }, - 'qwen-oauth': { order: 6, title: 'Qwen Code' } + // Both Anthropic entries sit at the bottom: the API-key path first, then + // the subscription OAuth path (only works with extra usage credits). + anthropic: { order: 5, title: 'Anthropic API Key' }, + 'claude-code': { order: 6, title: 'Anthropic OAuth: Required Extra Usage Credits to Use Subscription' } } const assetPath = (path: string) => `${import.meta.env.BASE_URL}${path.replace(/^\/+/, '')}` diff --git a/hermes_cli/web_server.py b/hermes_cli/web_server.py index 01eab91965f..2b1835483bc 100644 --- a/hermes_cli/web_server.py +++ b/hermes_cli/web_server.py @@ -3099,22 +3099,6 @@ def _claude_code_only_status() -> Dict[str, Any]: # show code + verification URL + poll, ``external`` = read-only (delegated # to a third-party CLI like Claude Code or Qwen). _OAUTH_PROVIDER_CATALOG: tuple[Dict[str, Any], ...] = ( - { - "id": "anthropic", - "name": "Anthropic (Claude API)", - "flow": "pkce", - "cli_command": "hermes auth add anthropic", - "docs_url": "https://docs.claude.com/en/api/getting-started", - "status_fn": _anthropic_oauth_status, - }, - { - "id": "claude-code", - "name": "Claude Code (subscription)", - "flow": "external", - "cli_command": "claude setup-token", - "docs_url": "https://docs.claude.com/en/docs/claude-code", - "status_fn": _claude_code_only_status, - }, { "id": "nous", "name": "Nous Portal", @@ -3125,7 +3109,7 @@ _OAUTH_PROVIDER_CATALOG: tuple[Dict[str, Any], ...] = ( }, { "id": "openai-codex", - "name": "OpenAI Codex (ChatGPT)", + "name": "OpenAI OAuth (ChatGPT)", "flow": "device_code", "cli_command": "hermes auth add openai-codex", "docs_url": "https://platform.openai.com/docs", @@ -3163,6 +3147,25 @@ _OAUTH_PROVIDER_CATALOG: tuple[Dict[str, Any], ...] = ( "docs_url": "https://hermes-agent.nousresearch.com/docs/guides/xai-grok-oauth", "status_fn": None, # dispatched via auth.get_xai_oauth_auth_status }, + # ── Anthropic / Claude entries sit at the bottom: the API-key path + # first, then the subscription OAuth path (which only works with extra + # usage credits on top of a Claude Max plan — see disclaimer in name). + { + "id": "anthropic", + "name": "Anthropic API Key", + "flow": "pkce", + "cli_command": "hermes auth add anthropic", + "docs_url": "https://docs.claude.com/en/api/getting-started", + "status_fn": _anthropic_oauth_status, + }, + { + "id": "claude-code", + "name": "Anthropic OAuth: Required Extra Usage Credits to Use Subscription", + "flow": "external", + "cli_command": "claude setup-token", + "docs_url": "https://docs.claude.com/en/docs/claude-code", + "status_fn": _claude_code_only_status, + }, )