fix(auth): show subscription setup errors
Preserve subscription-auth failures instead of rewriting them as missing API keys, and point Claude/Codex subscription users at the correct login and provider commands. Fixes #254
This commit is contained in:
@@ -198,13 +198,8 @@ def _resolve_api_client_from_settings(settings) -> SupportsStreamingMessages:
|
||||
def _safe_resolve_auth():
|
||||
try:
|
||||
return settings.resolve_auth()
|
||||
except (ValueError, Exception):
|
||||
print(
|
||||
"Error: No API key configured.\n"
|
||||
" Run `oh auth login` to set up authentication, or set the\n"
|
||||
" ANTHROPIC_API_KEY (or OPENAI_API_KEY) environment variable.",
|
||||
file=sys.stderr,
|
||||
)
|
||||
except Exception as exc:
|
||||
_print_auth_resolution_error(settings, exc)
|
||||
raise SystemExit(1)
|
||||
|
||||
if settings.api_format == "copilot":
|
||||
@@ -243,6 +238,39 @@ def _resolve_api_client_from_settings(settings) -> SupportsStreamingMessages:
|
||||
)
|
||||
|
||||
|
||||
def _print_auth_resolution_error(settings, exc: Exception) -> None:
|
||||
"""Render auth failures without collapsing subscription errors into API-key advice."""
|
||||
try:
|
||||
profile_name, profile = settings.resolve_profile()
|
||||
auth_source = (getattr(profile, "auth_source", "") or "").strip()
|
||||
except Exception:
|
||||
profile_name = ""
|
||||
auth_source = ""
|
||||
|
||||
message = str(exc).strip() or exc.__class__.__name__
|
||||
if auth_source in {"claude_subscription", "codex_subscription"}:
|
||||
login_command = "claude-login" if auth_source == "claude_subscription" else "codex-login"
|
||||
provider_name = profile_name or (
|
||||
"claude-subscription" if auth_source == "claude_subscription" else "codex"
|
||||
)
|
||||
print(
|
||||
f"Error: {message}\n"
|
||||
f" This profile uses subscription auth, not an API key.\n"
|
||||
f" Run `oh auth {login_command}` to bind the local CLI session, then\n"
|
||||
f" run `oh provider use {provider_name}` to activate it.",
|
||||
file=sys.stderr,
|
||||
)
|
||||
return
|
||||
|
||||
print(
|
||||
"Error: No API key configured.\n"
|
||||
f" {message}\n"
|
||||
" Run `oh auth login` to set up authentication, or set the\n"
|
||||
" ANTHROPIC_API_KEY (or OPENAI_API_KEY) environment variable.",
|
||||
file=sys.stderr,
|
||||
)
|
||||
|
||||
|
||||
async def build_runtime(
|
||||
*,
|
||||
prompt: str | None = None,
|
||||
|
||||
@@ -31,3 +31,19 @@ async def test_build_runtime_exits_cleanly_for_openai_format(monkeypatch):
|
||||
|
||||
with pytest.raises(SystemExit, match="1"):
|
||||
await build_runtime(active_profile="openai-compatible", api_format="openai")
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_build_runtime_reports_subscription_auth_setup(monkeypatch, tmp_path, capsys):
|
||||
"""Subscription profiles should not be reported as missing API keys."""
|
||||
monkeypatch.setenv("OPENHARNESS_CONFIG_DIR", str(tmp_path / "config"))
|
||||
monkeypatch.delenv("ANTHROPIC_AUTH_TOKEN", raising=False)
|
||||
|
||||
with pytest.raises(SystemExit, match="1"):
|
||||
await build_runtime(active_profile="claude-subscription")
|
||||
|
||||
captured = capsys.readouterr()
|
||||
assert "subscription auth, not an API key" in captured.err
|
||||
assert "oh auth claude-login" in captured.err
|
||||
assert "oh provider use claude-subscription" in captured.err
|
||||
assert "No API key configured" not in captured.err
|
||||
|
||||
Reference in New Issue
Block a user