From 4cd9757abc9b682d11d0bda3536e707adcadb7b9 Mon Sep 17 00:00:00 2001 From: Paul O'Reilly Date: Thu, 23 Apr 2026 18:33:39 +1200 Subject: [PATCH] feat(claude-profile): warn when non-Anthropic provider used with OAuth profile Add a warning when ANTHROPIC_BASE_URL would be set but the active profile's .credentials.json would override ANTHROPIC_API_KEY with subscription OAuth, routing requests to Anthropic instead of the intended provider. Fixes the MiniMax routing issue: use --profile minimax (~/.claude-minimax/, no stored credentials) for non-Anthropic providers. Update presets example to use profile: minimax for quick-minimax preset. 63 tests passing. Co-Authored-By: Claude Sonnet 4.6 --- data/claude-profile/presets.yaml.example | 4 ++-- scripts/claude-profile | 10 ++++++++++ tests/test-claude-profile.sh | 18 ++++++++++++++++++ 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/data/claude-profile/presets.yaml.example b/data/claude-profile/presets.yaml.example index 74d415a..aefe88f 100644 --- a/data/claude-profile/presets.yaml.example +++ b/data/claude-profile/presets.yaml.example @@ -40,9 +40,9 @@ hybrid-day: time_horizon: hours async: yes -# Quick session via MiniMax (Sonnet-class, pay-per-token, no subscription) +# Quick session via MiniMax — uses the minimax profile (no OAuth credentials) quick-minimax: - profile: oreillyit + profile: minimax mode: quick provider: minimax-sonnet project: small-scripts diff --git a/scripts/claude-profile b/scripts/claude-profile index 23bf61c..117d9b2 100755 --- a/scripts/claude-profile +++ b/scripts/claude-profile @@ -425,6 +425,16 @@ PROVIDER_API_KEY_FILE=$(parse_provider_field "$provider_file" api_key_file) [[ -n "$MODEL_ID" ]] || err "Provider file $provider_file is missing required field: model_id" +# Warn when a non-Anthropic provider is selected but the profile has stored OAuth credentials. +# Claude Code uses .credentials.json for auth before checking ANTHROPIC_API_KEY, which +# routes requests to Anthropic regardless of ANTHROPIC_BASE_URL. +if [[ -n "$PROVIDER_BASE_URL" && -f "$target/.credentials.json" ]]; then + echo "Warning: profile '$PROFILE' has stored OAuth credentials ($target/.credentials.json)." >&2 + echo " These take precedence over ANTHROPIC_API_KEY and will route requests to Anthropic," >&2 + echo " not $PROVIDER. Use a profile without .credentials.json for non-Anthropic providers." >&2 + echo " See: claude-profile --help" >&2 +fi + # === Phase 3: Launch === # Validate context-load exists diff --git a/tests/test-claude-profile.sh b/tests/test-claude-profile.sh index e31c3da..6dc99d2 100755 --- a/tests/test-claude-profile.sh +++ b/tests/test-claude-profile.sh @@ -199,6 +199,7 @@ assert_contains "chat default provider is anthropic-haiku" "Provider: ant assert_contains "chat default model ID is haiku" "Model ID: claude-haiku-4-5-20251001" "$out" # === Test 14: --preset + --provider mutual exclusion === + echo echo "Test 14: error path — --preset + --provider mutual exclusion" out=$(run --dryrun --preset whatever --provider minimax-sonnet) @@ -206,6 +207,23 @@ rc=$? assert_exit_code "preset+provider exits 1" 1 "$rc" assert_contains "preset+provider error message" "mutually exclusive" "$out" +# === Test 15: OAuth credentials warning fires for non-Anthropic provider === +echo +echo "Test 15: OAuth credentials warning" +out=$(run --dryrun oreillyit --mode quick --provider minimax-sonnet) +rc=$? +assert_exit_code "credentials warning dryrun exits 0" 0 "$rc" +assert_contains "warning mentions stored credentials" ".credentials.json" "$out" +assert_contains "warning names the provider" "minimax-sonnet" "$out" + +# === Test 16: No warning when profile has no OAuth credentials === +echo +echo "Test 16: no warning for credentials-free profile" +out=$(run --dryrun minimax --mode quick --provider minimax-sonnet) +rc=$? +assert_exit_code "no-credentials dryrun exits 0" 0 "$rc" +assert_not_contains "no credentials warning" ".credentials.json" "$out" + # === Summary === echo echo "================================"