diff --git a/agent/account_usage.py b/agent/account_usage.py index b6de6e65bb..564b74572c 100644 --- a/agent/account_usage.py +++ b/agent/account_usage.py @@ -8,7 +8,7 @@ from typing import TYPE_CHECKING, Any, Callable, Optional import httpx -from agent.anthropic_adapter import _is_oauth_token, resolve_anthropic_token +from agent.anthropic_credentials import _is_oauth_token, resolve_anthropic_token from hermes_cli.auth import AuthError, _read_codex_tokens, resolve_codex_runtime_credentials from hermes_cli.runtime_provider import resolve_runtime_provider diff --git a/agent/agent_init.py b/agent/agent_init.py index a0158d4305..a12099a431 100644 --- a/agent/agent_init.py +++ b/agent/agent_init.py @@ -723,7 +723,8 @@ def _print_key_banner(key, label: str, warn_missing: bool = False) -> None: def _init_anthropic_client(agent, api_key, base_url, _provider_timeout): """anthropic_messages: native Anthropic SDK (or AnthropicBedrock for Bedrock+Claude).""" - from agent.anthropic_adapter import build_anthropic_client, resolve_anthropic_token + from agent.anthropic_adapter import build_anthropic_client + from agent.anthropic_credentials import resolve_anthropic_token agent.client = None agent._client_kwargs = {} agent._anthropic_base_url = base_url @@ -766,7 +767,7 @@ def _init_anthropic_client(agent, api_key, base_url, _provider_timeout): # Third-party providers (MiniMax, Kimi, GLM, LiteLLM proxies) that accept the Anthropic protocol must # never trip OAuth code paths — doing so injects Claude-Code identity headers and system prompts that # cause 401/403 on their endpoints. See #1739. - from agent.anthropic_adapter import _is_oauth_token as _is_oat + from agent.anthropic_credentials import _is_oauth_token as _is_oat agent._is_anthropic_oauth = _is_oat(effective_key) if (_is_native_anthropic and isinstance(effective_key, str)) else False agent._anthropic_client = build_anthropic_client(effective_key, base_url, timeout=_provider_timeout) if not agent.quiet_mode: diff --git a/agent/agent_runtime_helpers.py b/agent/agent_runtime_helpers.py index e5d6e9c52a..8df9c243f4 100644 --- a/agent/agent_runtime_helpers.py +++ b/agent/agent_runtime_helpers.py @@ -1499,7 +1499,7 @@ def anthropic_prompt_cache_policy( # 64K-token prompts and re-billing the full prompt on every turn. Observed within-turn progression with # cache enabled: 1% → 67% → 84% → 97% (#25970). Reuses the canonical family matcher (covers bare # k1./k2./k25 release slugs the substring check missed). - from agent.anthropic_adapter import _model_name_is_kimi_family + from agent.anthropic_endpoints import _model_name_is_kimi_family is_kimi = _model_name_is_kimi_family(eff_model) or "moonshot" in model_lower is_openrouter = base_url_host_matches(eff_base_url, "openrouter.ai") # Nous Portal proxies to OpenRouter; treat as OpenRouter-equivalent for cache layout. @@ -1859,7 +1859,8 @@ def _build_switched_client(agent, new_provider, api_key, base_url, api_mode, new agent.client = build_moa_facade(agent, agent.model) return if api_mode == "anthropic_messages": - from agent.anthropic_adapter import build_anthropic_client, resolve_anthropic_token, _is_oauth_token + from agent.anthropic_adapter import build_anthropic_client + from agent.anthropic_credentials import resolve_anthropic_token, _is_oauth_token # Only fall back to ANTHROPIC_TOKEN for native Anthropic; other anthropic_messages providers # must never receive Anthropic credentials. is_native_anthropic = new_provider == "anthropic" diff --git a/agent/anthropic_adapter.py b/agent/anthropic_adapter.py index cd21338fa5..4db2e2ea9b 100644 --- a/agent/anthropic_adapter.py +++ b/agent/anthropic_adapter.py @@ -2,38 +2,26 @@ OpenAI-style internals. Auth: API keys (``sk-ant-api*``) -> x-api-key; OAuth setup-tokens (``sk-ant-oat*``) and Claude Code credentials -> Bearer + beta header. Endpoint predicates, payload conversion and credentials live in ``agent/anthropic_{endpoints,message_convert, -credentials}.py`` and are re-exported here for long-standing imports.""" +credentials}.py``; import them from there.""" import logging import math import re import subprocess from contextlib import suppress -from pathlib import Path # noqa: F401 (tests patch ``anthropic_adapter.Path.home``) from typing import Any, Dict, List, Optional from utils import normalize_proxy_env_vars -from agent.anthropic_endpoints import ( # noqa: F401 +from agent.anthropic_credentials import _is_oauth_token +from agent.anthropic_endpoints import ( _base_url_needs_context_1m_beta, _is_azure_anthropic_endpoint, _is_kimi_coding_endpoint, _is_minimax_anthropic_endpoint, _is_nous_portal_endpoint, _is_opencode_endpoint, _is_third_party_anthropic_endpoint, _model_name_is_kimi_family, _normalize_base_url_text, _requires_bearer_auth, ) -from agent.anthropic_message_convert import ( # noqa: F401 - _EMPTY_TEXT_PLACEHOLDER, _convert_assistant_message, _convert_content_part_to_anthropic, - _convert_user_message, _ensure_leading_user_turn, _is_bedrock_model_id, _safe_text, - _sanitize_replay_block, _scrub_blank_text_blocks, _to_plain_data, convert_messages_to_anthropic, - convert_tools_to_anthropic, normalize_model_name, -) -from agent.anthropic_credentials import ( # noqa: F401 - _OAUTH_TOKEN_USER_AGENT, CredentialPersistError, _get_hermes_oauth_file, _getenv, _is_oauth_token, - _read_claude_code_credentials_from_keychain, _refresh_oauth_token, _resolve_anthropic_pool_token, - _resolve_claude_code_token_from_credentials, _write_claude_code_credentials, - _write_hermes_oauth_credentials, claude_code_credentials_path, is_claude_code_token_valid, - is_rotation_consumed_uncommitted, mark_rotation_consumed_uncommitted, read_claude_code_credentials, - read_hermes_oauth_credentials, refresh_anthropic_oauth_pure, resolve_anthropic_token, - run_hermes_oauth_login_pure, run_oauth_setup_token, +from agent.anthropic_message_convert import ( + convert_messages_to_anthropic, convert_tools_to_anthropic, normalize_model_name, ) from hermes_cli import __version__ as _HERMES_VERSION diff --git a/agent/anthropic_credentials.py b/agent/anthropic_credentials.py index 5dcf3eab38..ed3f57f0ac 100644 --- a/agent/anthropic_credentials.py +++ b/agent/anthropic_credentials.py @@ -5,8 +5,7 @@ ``auth.json`` credential pool. ``~/.hermes/.anthropic_oauth.json`` (Hermes PKCE) and the Claude Code file are *singletons*: ``credential_pool._seed_from_singletons()`` re-reads them on every ``load_pool()``, so a failed write here is a failed refresh -(``CredentialPersistError``), not a cache miss. ``agent.anthropic_adapter`` re-exports -every public name below. +(``CredentialPersistError``), not a cache miss. """ import base64 @@ -33,11 +32,9 @@ logger = logging.getLogger(__name__) _OAUTH_CLIENT_ID = "9d1c250a-e61b-44d9-88ed-5944d1962f5e" # platform.claude.com is the live token host; console.anthropic.com 404s but is kept as a fallback. -# _OAUTH_TOKEN_URL stays for backward-compatible imports. _OAUTH_TOKEN_URLS = [ "https://platform.claude.com/v1/oauth/token", "https://console.anthropic.com/v1/oauth/token" ] -_OAUTH_TOKEN_URL = _OAUTH_TOKEN_URLS[0] # Anthropic 429s token-endpoint requests whose UA starts with ``claude-code/`` (or Mozilla); the real CLI uses # bare axios there. Inference (build_anthropic_kwargs) still needs claude-code/. _OAUTH_TOKEN_USER_AGENT = "axios/1.7.9" diff --git a/agent/anthropic_endpoints.py b/agent/anthropic_endpoints.py index e261c1d34d..82b96c5af1 100644 --- a/agent/anthropic_endpoints.py +++ b/agent/anthropic_endpoints.py @@ -5,7 +5,7 @@ headers, and request quirks (MiniMax, Kimi/Moonshot, DeepSeek, OpenCode, Azure A Portal, Bedrock). Every such difference is decided from the configured base URL, so the predicates live together here as pure functions (no I/O, SDK or credentials) that both ``agent/anthropic_adapter.py`` and ``agent/anthropic_message_convert.py`` can import without a -cycle. ``agent.anthropic_adapter`` re-exports every name below. +cycle. """ from urllib.parse import urlparse diff --git a/agent/anthropic_message_convert.py b/agent/anthropic_message_convert.py index cbfeb5c7cb..2335345ea7 100644 --- a/agent/anthropic_message_convert.py +++ b/agent/anthropic_message_convert.py @@ -2,7 +2,7 @@ schemas, and the message list (content blocks, thinking blocks and their signatures, tool_use/tool_result pairing, cache_control placement, screenshot eviction, blank-block scrubbing). Endpoint predicates come from ``agent/anthropic_endpoints.py`` so this module never -imports the adapter (no cycle); ``agent.anthropic_adapter`` re-exports the public names.""" +imports the adapter (no cycle).""" import copy import json diff --git a/agent/auxiliary_client.py b/agent/auxiliary_client.py index 9796ac8d8c..92e12a18e0 100644 --- a/agent/auxiliary_client.py +++ b/agent/auxiliary_client.py @@ -1600,7 +1600,7 @@ class _AnthropicCompletionsAdapter: candidate = str(getattr(real_client, "base_url", "") or "") or None if candidate: with contextlib.suppress(Exception): - from agent.anthropic_adapter import _is_nous_portal_endpoint + from agent.anthropic_endpoints import _is_nous_portal_endpoint if _is_nous_portal_endpoint(candidate): self._base_url = candidate @@ -2810,7 +2810,8 @@ def _try_azure_foundry( def _try_anthropic(explicit_api_key: str = None) -> Tuple[Optional[Any], Optional[str]]: try: - from agent.anthropic_adapter import build_anthropic_client, resolve_anthropic_token + from agent.anthropic_adapter import build_anthropic_client + from agent.anthropic_credentials import resolve_anthropic_token except ImportError: return None, None pool_present, entry = _select_pool_entry("anthropic") @@ -2835,7 +2836,7 @@ def _try_anthropic(explicit_api_key: str = None) -> Tuple[Optional[Any], Optiona cfg_base_url = (model_cfg.get("base_url") or "").strip().rstrip("/") if cfg_base_url and _is_anthropic_compatible_host(cfg_base_url): base_url = cfg_base_url - from agent.anthropic_adapter import _is_oauth_token + from agent.anthropic_credentials import _is_oauth_token is_oauth = _is_oauth_token(token) model = _get_aux_model_for_provider("anthropic") or "claude-haiku-4-5-20251001" if _aux_probe_active(): diff --git a/agent/chat_completion_helpers.py b/agent/chat_completion_helpers.py index 6a1350082c..4fa0d7b545 100644 --- a/agent/chat_completion_helpers.py +++ b/agent/chat_completion_helpers.py @@ -1922,7 +1922,8 @@ def _swap_fallback_clients(agent, fb_client, fb_provider: str, fb_model: str, fb """Install the fallback client(s) in place, honoring request_timeout_seconds (None = SDK default).""" timeout = get_provider_request_timeout(fb_provider, fb_model) if fb_api_mode == "anthropic_messages": - from agent.anthropic_adapter import build_anthropic_client, resolve_anthropic_token, _is_oauth_token + from agent.anthropic_adapter import build_anthropic_client + from agent.anthropic_credentials import resolve_anthropic_token, _is_oauth_token is_anthropic = fb_provider == "anthropic" effective_key = fb_client.api_key or (resolve_anthropic_token() if is_anthropic else None) or "" agent.api_key = agent._anthropic_api_key = effective_key diff --git a/agent/client_lifecycle.py b/agent/client_lifecycle.py index 46b0d26448..a782654afe 100644 --- a/agent/client_lifecycle.py +++ b/agent/client_lifecycle.py @@ -420,7 +420,7 @@ class ClientLifecycleMixin: def _anthropic_oauth_flag(self, token: str) -> bool: """OAuth flag only on native Anthropic; third-party Anthropic-protocol endpoints must not trip OAuth paths.""" - from agent.anthropic_adapter import _is_oauth_token + from agent.anthropic_credentials import _is_oauth_token return _is_oauth_token(token) if self.provider == "anthropic" else False def _build_anthropic_client_for_key(self, key: tuple) -> Any: @@ -752,7 +752,7 @@ class ClientLifecycleMixin: ): return False try: - from agent.anthropic_adapter import resolve_anthropic_token + from agent.anthropic_credentials import resolve_anthropic_token new_token = resolve_anthropic_token() except Exception as exc: logger.debug("Anthropic credential refresh failed: %s", exc) diff --git a/agent/transports/anthropic.py b/agent/transports/anthropic.py index c80ad07099..978a0d4af2 100644 --- a/agent/transports/anthropic.py +++ b/agent/transports/anthropic.py @@ -44,12 +44,12 @@ class AnthropicTransport(ProviderTransport): def convert_messages(self, messages: List[Dict[str, Any]], **kwargs) -> Any: """Convert OpenAI messages to an Anthropic (system, messages) tuple; ``base_url`` affects thinking-signature handling.""" - from agent.anthropic_adapter import convert_messages_to_anthropic + from agent.anthropic_message_convert import convert_messages_to_anthropic return convert_messages_to_anthropic(messages, base_url=kwargs.get("base_url")) def convert_tools(self, tools: List[Dict[str, Any]]) -> Any: """Convert OpenAI tool schemas to Anthropic input_schema format.""" - from agent.anthropic_adapter import convert_tools_to_anthropic + from agent.anthropic_message_convert import convert_tools_to_anthropic return convert_tools_to_anthropic(tools) def build_kwargs( @@ -65,7 +65,7 @@ class AnthropicTransport(ProviderTransport): def normalize_response(self, response: Any, **kwargs) -> NormalizedResponse: """Parse content blocks (text/thinking/tool_use), map stop_reason, collect reasoning_details.""" import json - from agent.anthropic_adapter import _sanitize_replay_block, _to_plain_data + from agent.anthropic_message_convert import _sanitize_replay_block, _to_plain_data strip_tool_prefix = kwargs.get("strip_tool_prefix", False) text_parts, reasoning_parts, reasoning_details, tool_calls = [], [], [], [] # Anthropic signs each thinking block against the blocks PRECEDING it; when thinking diff --git a/hermes_cli/auth_commands.py b/hermes_cli/auth_commands.py index 7b6b7f0cd1..a3c76ad564 100644 --- a/hermes_cli/auth_commands.py +++ b/hermes_cli/auth_commands.py @@ -179,7 +179,7 @@ def _format_exhausted_status(entry) -> str: def _anthropic_oauth_login(args) -> dict: - from agent import anthropic_adapter as anthropic_mod + from agent import anthropic_credentials as anthropic_mod creds = anthropic_mod.run_hermes_oauth_login_pure() if not creds: raise SystemExit("Anthropic OAuth login did not return credentials.") diff --git a/hermes_cli/doctor_connectivity.py b/hermes_cli/doctor_connectivity.py index 27ad855a0e..f5628c6b5c 100644 --- a/hermes_cli/doctor_connectivity.py +++ b/hermes_cli/doctor_connectivity.py @@ -154,7 +154,8 @@ def _probe_anthropic() -> ProbeResult: return _skip(name) try: import httpx - from agent.anthropic_adapter import _is_oauth_token, _COMMON_BETAS, _OAUTH_ONLY_BETAS, _CONTEXT_1M_BETA + from agent.anthropic_adapter import _COMMON_BETAS, _OAUTH_ONLY_BETAS, _CONTEXT_1M_BETA + from agent.anthropic_credentials import _is_oauth_token is_oauth = _is_oauth_token(key) headers = {"anthropic-version": "2023-06-01", **({"Authorization": f"Bearer {key}", "anthropic-beta": ",".join(_COMMON_BETAS + _OAUTH_ONLY_BETAS)} if is_oauth else {"x-api-key": key})} diff --git a/hermes_cli/inventory.py b/hermes_cli/inventory.py index 9f910f8162..4102115891 100644 --- a/hermes_cli/inventory.py +++ b/hermes_cli/inventory.py @@ -439,7 +439,7 @@ def _anthropic_oauth_credentials_present() -> bool: """True when the user explicitly authenticated Anthropic via OAuth (Hermes device flow or Claude Code login) — those leave no trace in active_provider / model.provider / API-key env vars.""" try: - from agent.anthropic_adapter import read_claude_code_credentials, read_hermes_oauth_credentials + from agent.anthropic_credentials import read_claude_code_credentials, read_hermes_oauth_credentials readers = (read_hermes_oauth_credentials, read_claude_code_credentials) if any((read() or {}).get("accessToken") for read in readers): diff --git a/hermes_cli/main.py b/hermes_cli/main.py index d113bc9143..918a3e0e6c 100644 --- a/hermes_cli/main.py +++ b/hermes_cli/main.py @@ -1164,10 +1164,7 @@ def _has_any_provider_configured(*, strict_profile_scope: bool = False) -> bool: # configured — having Claude Code installed isn't consent to use its tokens. if _has_hermes_config and not strict_profile_scope: try: - from agent.anthropic_adapter import ( - read_claude_code_credentials, - is_claude_code_token_valid, - ) + from agent.anthropic_credentials import read_claude_code_credentials, is_claude_code_token_valid creds = read_claude_code_credentials() if creds and ( diff --git a/hermes_cli/main_provider_setup.py b/hermes_cli/main_provider_setup.py index 06ad533e51..c35bcb2f51 100644 --- a/hermes_cli/main_provider_setup.py +++ b/hermes_cli/main_provider_setup.py @@ -644,7 +644,7 @@ def _stepfun_base_url_for_region(region: str) -> str: def _run_anthropic_oauth_flow(save_env_value): """Run the Claude OAuth setup-token flow. Returns True if credentials were saved.""" - from agent.anthropic_adapter import run_oauth_setup_token, read_claude_code_credentials, is_claude_code_token_valid + from agent.anthropic_credentials import run_oauth_setup_token, read_claude_code_credentials, is_claude_code_token_valid from hermes_cli.config import save_anthropic_oauth_token, use_anthropic_claude_code_credentials def _activate_claude_code_credentials_if_available() -> bool: diff --git a/hermes_cli/model_setup_flows.py b/hermes_cli/model_setup_flows.py index b065a652d1..c227aa7c12 100644 --- a/hermes_cli/model_setup_flows.py +++ b/hermes_cli/model_setup_flows.py @@ -999,7 +999,7 @@ def _model_flow_anthropic(config, current_model=""): existing_key = get_anthropic_key() cc_available = False with contextlib.suppress(Exception): - from agent.anthropic_adapter import read_claude_code_credentials, is_claude_code_token_valid, _is_oauth_token + from agent.anthropic_credentials import read_claude_code_credentials, is_claude_code_token_valid, _is_oauth_token cc_creds = read_claude_code_credentials() if cc_creds and is_claude_code_token_valid(cc_creds): cc_available = True diff --git a/hermes_cli/model_switch_providers.py b/hermes_cli/model_switch_providers.py index d673407546..72e3f3e036 100644 --- a/hermes_cli/model_switch_providers.py +++ b/hermes_cli/model_switch_providers.py @@ -747,7 +747,7 @@ def _overlay_has_creds(b: _PickerBuild, pid: str, hermes_slug: str, overlay) -> # The pool gates anthropic behind is_provider_explicitly_configured() (aux tasks must not # consume Claude Code tokens); the picker is discovery-oriented, so read the files directly. try: - from agent.anthropic_adapter import read_claude_code_credentials, read_hermes_oauth_credentials + from agent.anthropic_credentials import read_claude_code_credentials, read_hermes_oauth_credentials hermes_creds = read_hermes_oauth_credentials() cc_creds = read_claude_code_credentials() if (hermes_creds and hermes_creds.get("accessToken")) or (cc_creds and cc_creds.get("accessToken")): diff --git a/hermes_cli/models.py b/hermes_cli/models.py index 57a709eadf..dac18836e3 100644 --- a/hermes_cli/models.py +++ b/hermes_cli/models.py @@ -1668,7 +1668,7 @@ def _fetch_anthropic_models( ``api_key``, else ``resolve_anthropic_token()`` (env / OAuth / Claude Code), else a read-only API-key credential_pool entry.""" try: - from agent.anthropic_adapter import resolve_anthropic_token, _is_oauth_token + from agent.anthropic_credentials import resolve_anthropic_token, _is_oauth_token except ImportError: return None diff --git a/hermes_cli/runtime_provider.py b/hermes_cli/runtime_provider.py index cc8c6e2ff7..d1807bdc2c 100644 --- a/hermes_cli/runtime_provider.py +++ b/hermes_cli/runtime_provider.py @@ -273,7 +273,7 @@ def _anthropic_cfg_base_url(model_cfg: Dict[str, Any]) -> str: def _anthropic_token_or_raise() -> str: - from agent.anthropic_adapter import resolve_anthropic_token + from agent.anthropic_credentials import resolve_anthropic_token token = resolve_anthropic_token() if not token: raise AuthError(_NO_ANTHROPIC_CREDENTIALS_MSG) diff --git a/hermes_cli/web_routers/oauth.py b/hermes_cli/web_routers/oauth.py index 3157b8f2b9..fb37c12fbf 100644 --- a/hermes_cli/web_routers/oauth.py +++ b/hermes_cli/web_routers/oauth.py @@ -528,7 +528,7 @@ def _clear_anthropic_auth() -> bool: """Clear only the Hermes-managed PKCE file and auth-store entry (never ~/.claude/*).""" cleared = False try: - from agent.anthropic_adapter import _get_hermes_oauth_file + from agent.anthropic_credentials import _get_hermes_oauth_file oauth_file = _get_hermes_oauth_file() if oauth_file.exists(): oauth_file.unlink() diff --git a/hermes_cli/web_server_oauth.py b/hermes_cli/web_server_oauth.py index b4b83bb653..ceac055848 100644 --- a/hermes_cli/web_server_oauth.py +++ b/hermes_cli/web_server_oauth.py @@ -51,7 +51,7 @@ def _anthropic_oauth_status() -> Dict[str, Any]: ``claude-code`` entry, and counting it here would shadow a real ANTHROPIC_API_KEY. """ try: - from agent.anthropic_adapter import read_hermes_oauth_credentials, _get_hermes_oauth_file + from agent.anthropic_credentials import read_hermes_oauth_credentials, _get_hermes_oauth_file hermes_creds = read_hermes_oauth_credentials() except Exception: hermes_creds = None @@ -79,7 +79,7 @@ def _anthropic_oauth_status() -> Dict[str, Any]: def _claude_code_only_status() -> Dict[str, Any]: """Claude Code CLI credentials as their own entry, independent of the Anthropic card.""" try: - from agent.anthropic_adapter import read_claude_code_credentials + from agent.anthropic_credentials import read_claude_code_credentials creds = read_claude_code_credentials() except Exception: creds = None diff --git a/tests/agent/test_anthropic_adapter.py b/tests/agent/test_anthropic_adapter.py index 61754a4307..3ded294a6c 100644 --- a/tests/agent/test_anthropic_adapter.py +++ b/tests/agent/test_anthropic_adapter.py @@ -9,23 +9,10 @@ from unittest.mock import patch, MagicMock import pytest from agent.prompt_caching import apply_anthropic_cache_control -from agent.anthropic_adapter import ( - _is_azure_anthropic_endpoint, - _is_oauth_token, - _refresh_oauth_token, - _to_plain_data, - _write_claude_code_credentials, - build_anthropic_client, - build_anthropic_bedrock_client, - build_anthropic_kwargs, - convert_messages_to_anthropic, - convert_tools_to_anthropic, - is_claude_code_token_valid, - normalize_model_name, - read_claude_code_credentials, - resolve_anthropic_token, - run_oauth_setup_token, -) +from agent.anthropic_adapter import build_anthropic_client, build_anthropic_bedrock_client, build_anthropic_kwargs +from agent.anthropic_credentials import _is_oauth_token, _refresh_oauth_token, _write_claude_code_credentials, is_claude_code_token_valid, read_claude_code_credentials, resolve_anthropic_token, run_oauth_setup_token +from agent.anthropic_endpoints import _is_azure_anthropic_endpoint +from agent.anthropic_message_convert import _to_plain_data, convert_messages_to_anthropic, convert_tools_to_anthropic, normalize_model_name from agent.transports import get_transport @@ -169,7 +156,7 @@ class TestReadClaudeCodeCredentials: "expiresAt": int(time.time() * 1000) + 3600_000, } })) - monkeypatch.setattr("agent.anthropic_adapter.Path.home", lambda: tmp_path) + monkeypatch.setattr("agent.anthropic_credentials.Path.home", lambda: tmp_path) creds = read_claude_code_credentials() assert creds is not None assert creds["accessToken"] == "sk-ant-oat01-token" @@ -179,7 +166,7 @@ class TestReadClaudeCodeCredentials: def test_ignores_primary_api_key_for_native_anthropic_resolution(self, tmp_path, monkeypatch): claude_json = tmp_path / ".claude.json" claude_json.write_text(json.dumps({"primaryApiKey": "sk-ant-api03-primary"})) - monkeypatch.setattr("agent.anthropic_adapter.Path.home", lambda: tmp_path) + monkeypatch.setattr("agent.anthropic_credentials.Path.home", lambda: tmp_path) creds = read_claude_code_credentials() assert creds is None @@ -210,7 +197,7 @@ class TestResolveAnthropicToken: monkeypatch.setenv("ANTHROPIC_API_KEY", "sk-ant-api03-mykey") monkeypatch.setenv("ANTHROPIC_TOKEN", "sk-ant-oat01-mytoken") monkeypatch.delenv("CLAUDE_CODE_OAUTH_TOKEN", raising=False) - monkeypatch.setattr("agent.anthropic_adapter.Path.home", lambda: tmp_path) + monkeypatch.setattr("agent.anthropic_credentials.Path.home", lambda: tmp_path) assert resolve_anthropic_token() == "sk-ant-oat01-mytoken" def test_does_not_resolve_primary_api_key_as_native_anthropic_token(self, monkeypatch, tmp_path): @@ -218,7 +205,7 @@ class TestResolveAnthropicToken: monkeypatch.delenv("ANTHROPIC_TOKEN", raising=False) monkeypatch.delenv("CLAUDE_CODE_OAUTH_TOKEN", raising=False) (tmp_path / ".claude.json").write_text(json.dumps({"primaryApiKey": "sk-ant-api03-primary"})) - monkeypatch.setattr("agent.anthropic_adapter.Path.home", lambda: tmp_path) + monkeypatch.setattr("agent.anthropic_credentials.Path.home", lambda: tmp_path) assert resolve_anthropic_token() is None @@ -226,7 +213,7 @@ class TestResolveAnthropicToken: monkeypatch.setenv("ANTHROPIC_API_KEY", "sk-ant...ykey") monkeypatch.delenv("ANTHROPIC_TOKEN", raising=False) monkeypatch.delenv("CLAUDE_CODE_OAUTH_TOKEN", raising=False) - monkeypatch.setattr("agent.anthropic_adapter.Path.home", lambda: tmp_path) + monkeypatch.setattr("agent.anthropic_credentials.Path.home", lambda: tmp_path) assert resolve_anthropic_token() == "sk-ant...ykey" def test_api_key_wins_over_auto_discovered_claude_code_credentials( @@ -244,7 +231,7 @@ class TestResolveAnthropicToken: "expiresAt": int(time.time() * 1000) + 3600_000, } })) - monkeypatch.setattr("agent.anthropic_adapter.Path.home", lambda: tmp_path) + monkeypatch.setattr("agent.anthropic_credentials.Path.home", lambda: tmp_path) assert resolve_anthropic_token() == "sk-ant...ykey" @@ -272,14 +259,14 @@ class TestResolveAnthropicToken: "expiresAt": int(time.time() * 1000) + 3600_000, } })) - monkeypatch.setattr("agent.anthropic_adapter.Path.home", lambda: tmp_path) + monkeypatch.setattr("agent.anthropic_credentials.Path.home", lambda: tmp_path) assert resolve_anthropic_token() == "cc-auto-token" def test_falls_back_to_anthropic_credential_pool_oauth(self, monkeypatch, tmp_path): monkeypatch.delenv("ANTHROPIC_API_KEY", raising=False) monkeypatch.delenv("ANTHROPIC_TOKEN", raising=False) monkeypatch.delenv("CLAUDE_CODE_OAUTH_TOKEN", raising=False) - monkeypatch.setattr("agent.anthropic_adapter.Path.home", lambda: tmp_path) + monkeypatch.setattr("agent.anthropic_credentials.Path.home", lambda: tmp_path) # Isolate source #5 (credential_pool): ensure source #4 (Claude Code # creds, incl. the macOS keychain read which Path.home does not cover) # returns nothing, mirroring a Hermes-PKCE-only setup. @@ -300,7 +287,7 @@ class TestResolveAnthropicToken: monkeypatch.setenv("ANTHROPIC_API_KEY", "sk-ant...ykey") monkeypatch.delenv("ANTHROPIC_TOKEN", raising=False) monkeypatch.delenv("CLAUDE_CODE_OAUTH_TOKEN", raising=False) - monkeypatch.setattr("agent.anthropic_adapter.Path.home", lambda: tmp_path) + monkeypatch.setattr("agent.anthropic_credentials.Path.home", lambda: tmp_path) monkeypatch.setattr( "agent.anthropic_credentials.read_claude_code_credentials", self._assert_not_called, @@ -320,7 +307,7 @@ class TestResolveAnthropicToken: monkeypatch.setenv("ANTHROPIC_API_KEY", "sk-ant...ykey") monkeypatch.delenv("ANTHROPIC_TOKEN", raising=False) monkeypatch.delenv("CLAUDE_CODE_OAUTH_TOKEN", raising=False) - monkeypatch.setattr("agent.anthropic_adapter.Path.home", lambda: tmp_path) + monkeypatch.setattr("agent.anthropic_credentials.Path.home", lambda: tmp_path) monkeypatch.setattr("agent.anthropic_credentials.read_claude_code_credentials", lambda: None) broken_entry = SimpleNamespace(auth_type="oauth", access_token=None) @@ -340,7 +327,7 @@ class TestResolveAnthropicToken: monkeypatch.delenv("ANTHROPIC_API_KEY", raising=False) monkeypatch.delenv("ANTHROPIC_TOKEN", raising=False) monkeypatch.delenv("CLAUDE_CODE_OAUTH_TOKEN", raising=False) - monkeypatch.setattr("agent.anthropic_adapter.Path.home", lambda: tmp_path) + monkeypatch.setattr("agent.anthropic_credentials.Path.home", lambda: tmp_path) monkeypatch.setattr("agent.anthropic_credentials.read_claude_code_credentials", lambda: None) api_key_entry = SimpleNamespace(auth_type="api_key", access_token="sk-pool-apikey") @@ -360,7 +347,7 @@ class TestResolveAnthropicToken: monkeypatch.delenv("ANTHROPIC_API_KEY", raising=False) monkeypatch.delenv("ANTHROPIC_TOKEN", raising=False) monkeypatch.delenv("CLAUDE_CODE_OAUTH_TOKEN", raising=False) - monkeypatch.setattr("agent.anthropic_adapter.Path.home", lambda: tmp_path) + monkeypatch.setattr("agent.anthropic_credentials.Path.home", lambda: tmp_path) monkeypatch.setattr("agent.anthropic_credentials.read_claude_code_credentials", lambda: None) captured = {} @@ -389,7 +376,7 @@ class TestResolveAnthropicToken: "expiresAt": int(time.time() * 1000) + 3600_000, } })) - monkeypatch.setattr("agent.anthropic_adapter.Path.home", lambda: tmp_path) + monkeypatch.setattr("agent.anthropic_credentials.Path.home", lambda: tmp_path) assert resolve_anthropic_token() == "cc-auto-token" @@ -397,7 +384,7 @@ class TestResolveAnthropicToken: class TestRefreshOauthToken: def test_returns_none_without_refresh_token(self, tmp_path, monkeypatch): - monkeypatch.setattr("agent.anthropic_adapter.Path.home", lambda: tmp_path) + monkeypatch.setattr("agent.anthropic_credentials.Path.home", lambda: tmp_path) # Neutralize live Claude Code sources (macOS Keychain + ~/.claude file) # so the adopt-already-refreshed branch can't short-circuit with a real # credential on a dev/CI machine that happens to have Claude Code creds. @@ -408,7 +395,7 @@ class TestRefreshOauthToken: assert _refresh_oauth_token(creds) is None def test_successful_refresh(self, tmp_path, monkeypatch): - monkeypatch.setattr("agent.anthropic_adapter.Path.home", lambda: tmp_path) + monkeypatch.setattr("agent.anthropic_credentials.Path.home", lambda: tmp_path) monkeypatch.setattr( "agent.anthropic_credentials.read_claude_code_credentials", lambda: None ) @@ -444,7 +431,7 @@ class TestRefreshOauthToken: assert written["claudeAiOauth"]["refreshToken"] == "new-refresh-456" def test_failed_refresh_returns_none(self, tmp_path, monkeypatch): - monkeypatch.setattr("agent.anthropic_adapter.Path.home", lambda: tmp_path) + monkeypatch.setattr("agent.anthropic_credentials.Path.home", lambda: tmp_path) monkeypatch.setattr( "agent.anthropic_credentials.read_claude_code_credentials", lambda: None ) @@ -460,7 +447,7 @@ class TestRefreshOauthToken: class TestWriteClaudeCodeCredentials: def test_writes_new_file(self, tmp_path, monkeypatch): - monkeypatch.setattr("agent.anthropic_adapter.Path.home", lambda: tmp_path) + monkeypatch.setattr("agent.anthropic_credentials.Path.home", lambda: tmp_path) _write_claude_code_credentials("tok", "ref", 12345) cred_file = tmp_path / ".claude" / ".credentials.json" assert cred_file.exists() @@ -470,7 +457,7 @@ class TestWriteClaudeCodeCredentials: assert data["claudeAiOauth"]["expiresAt"] == 12345 def test_preserves_existing_fields(self, tmp_path, monkeypatch): - monkeypatch.setattr("agent.anthropic_adapter.Path.home", lambda: tmp_path) + monkeypatch.setattr("agent.anthropic_credentials.Path.home", lambda: tmp_path) cred_dir = tmp_path / ".claude" cred_dir.mkdir() cred_file = cred_dir / ".credentials.json" @@ -490,7 +477,7 @@ class TestWriteClaudeCodeCredentials: the fix shipped in #19673 (google_oauth) and #21148 (mcp_oauth). """ import stat as _stat - monkeypatch.setattr("agent.anthropic_adapter.Path.home", lambda: tmp_path) + monkeypatch.setattr("agent.anthropic_credentials.Path.home", lambda: tmp_path) _write_claude_code_credentials("tok", "ref", 12345) cred_file = tmp_path / ".claude" / ".credentials.json" @@ -516,7 +503,7 @@ class TestResolveWithRefresh: "expiresAt": int(time.time() * 1000) - 3600_000, } })) - monkeypatch.setattr("agent.anthropic_adapter.Path.home", lambda: tmp_path) + monkeypatch.setattr("agent.anthropic_credentials.Path.home", lambda: tmp_path) # Mock refresh to succeed with patch("agent.anthropic_credentials._refresh_oauth_token", return_value="refreshed-token"): @@ -538,7 +525,7 @@ class TestResolveWithRefresh: "expiresAt": int(time.time() * 1000) - 3600_000, } })) - monkeypatch.setattr("agent.anthropic_adapter.Path.home", lambda: tmp_path) + monkeypatch.setattr("agent.anthropic_credentials.Path.home", lambda: tmp_path) with patch("agent.anthropic_credentials._refresh_oauth_token", return_value="refreshed-token"): result = resolve_anthropic_token() @@ -564,7 +551,7 @@ class TestRunOauthSetupToken: "expiresAt": int(time.time() * 1000) + 3600_000, } })) - monkeypatch.setattr("agent.anthropic_adapter.Path.home", lambda: tmp_path) + monkeypatch.setattr("agent.anthropic_credentials.Path.home", lambda: tmp_path) with patch("subprocess.run") as mock_run: mock_run.return_value = MagicMock(returncode=0) @@ -583,7 +570,7 @@ class TestRunOauthSetupToken: monkeypatch.setattr("shutil.which", lambda _: "/usr/bin/claude") monkeypatch.delenv("CLAUDE_CODE_OAUTH_TOKEN", raising=False) monkeypatch.delenv("ANTHROPIC_TOKEN", raising=False) - monkeypatch.setattr("agent.anthropic_adapter.Path.home", lambda: tmp_path) + monkeypatch.setattr("agent.anthropic_credentials.Path.home", lambda: tmp_path) with patch("subprocess.run") as mock_run: mock_run.return_value = MagicMock(returncode=0) @@ -1053,10 +1040,8 @@ class TestBuildAnthropicKwargs: classified as Kimi family (adaptive thinking) even on proxied endpoints where only the model name is available. Lookalike non-Kimi names must NOT match the exact-slug rule.""" - from agent.anthropic_adapter import ( - _model_name_is_kimi_family, - _supports_adaptive_thinking, - ) + from agent.anthropic_adapter import _supports_adaptive_thinking + from agent.anthropic_endpoints import _model_name_is_kimi_family for m in ("k3", "K3", "moonshotai/k3", "k3.1-preview", "k3-turbo"): assert _model_name_is_kimi_family(m) is True, m assert _supports_adaptive_thinking("k3") is True @@ -1502,7 +1487,7 @@ class TestBlankTextBlockFiltering: """ def _convert(self, message): - from agent.anthropic_adapter import _convert_assistant_message + from agent.anthropic_message_convert import _convert_assistant_message return _convert_assistant_message(message) @@ -1563,7 +1548,7 @@ class TestBlankTextBlockFiltering: a blank text block carrying cache_control (e.g. a stored, previously cache-marked turn where prompt_caching later becomes blank on replay) must not silently lose the breakpoint when dropped.""" - from agent.anthropic_adapter import _convert_assistant_message + from agent.anthropic_message_convert import _convert_assistant_message msg = { "role": "assistant", "content": "", @@ -1604,7 +1589,7 @@ class TestAllBlankFallbackAndNonStringText: """ def _convert(self, message): - from agent.anthropic_adapter import _convert_assistant_message + from agent.anthropic_message_convert import _convert_assistant_message return _convert_assistant_message(message) @@ -1674,7 +1659,7 @@ class TestReplayAllBlankFallback: """ def _convert(self, message): - from agent.anthropic_adapter import _convert_assistant_message + from agent.anthropic_message_convert import _convert_assistant_message return _convert_assistant_message(message) def test_sole_blank_marked_replay_block_keeps_marker_on_placeholder(self): diff --git a/tests/agent/test_anthropic_keychain.py b/tests/agent/test_anthropic_keychain.py index 7f1174967c..3b7cfffeca 100644 --- a/tests/agent/test_anthropic_keychain.py +++ b/tests/agent/test_anthropic_keychain.py @@ -7,11 +7,7 @@ from unittest.mock import patch, MagicMock import pytest -from agent.anthropic_adapter import ( - _read_claude_code_credentials_from_keychain, - read_claude_code_credentials, - _refresh_oauth_token, -) +from agent.anthropic_credentials import _read_claude_code_credentials_from_keychain, read_claude_code_credentials, _refresh_oauth_token # This module exercises the reader itself with explicit platform and subprocess @@ -67,7 +63,7 @@ class TestReadClaudeCodeCredentialsPriority: "expiresAt": 9999999999999, } })) - monkeypatch.setattr("agent.anthropic_adapter.Path.home", lambda: tmp_path) + monkeypatch.setattr("agent.anthropic_credentials.Path.home", lambda: tmp_path) # Mock Keychain to return a "newer" token with patch("agent.anthropic_adapter.subprocess.run") as mock_run: @@ -100,7 +96,7 @@ class TestReadClaudeCodeCredentialsPriority: "expiresAt": 9999999999999, } })) - monkeypatch.setattr("agent.anthropic_adapter.Path.home", lambda: tmp_path) + monkeypatch.setattr("agent.anthropic_credentials.Path.home", lambda: tmp_path) with patch("agent.anthropic_adapter.subprocess.run") as mock_run: # Simulate Keychain entry not found @@ -113,7 +109,7 @@ class TestReadClaudeCodeCredentialsPriority: def test_returns_none_when_neither_keychain_nor_json_has_creds(self, tmp_path, monkeypatch): """No credentials anywhere — must return None cleanly.""" - monkeypatch.setattr("agent.anthropic_adapter.Path.home", lambda: tmp_path) + monkeypatch.setattr("agent.anthropic_credentials.Path.home", lambda: tmp_path) with patch("agent.anthropic_adapter.subprocess.run") as mock_run: mock_run.return_value = MagicMock(returncode=1, stdout="", stderr="") @@ -147,7 +143,7 @@ class TestReadClaudeCodeCredentialsDesync: "expiresAt": file_expires_at, } })) - monkeypatch.setattr("agent.anthropic_adapter.Path.home", lambda: tmp_path) + monkeypatch.setattr("agent.anthropic_credentials.Path.home", lambda: tmp_path) def _keychain_payload(self, *, access_token, expires_at, refresh_token="kc-refresh"): return MagicMock( diff --git a/tests/agent/test_anthropic_kimi_signed_thinking_replay.py b/tests/agent/test_anthropic_kimi_signed_thinking_replay.py index efb3edabca..bd3058c409 100644 --- a/tests/agent/test_anthropic_kimi_signed_thinking_replay.py +++ b/tests/agent/test_anthropic_kimi_signed_thinking_replay.py @@ -3,7 +3,7 @@ from types import SimpleNamespace from agent.transports import get_transport -from agent.anthropic_adapter import convert_messages_to_anthropic +from agent.anthropic_message_convert import convert_messages_to_anthropic SIG = "sig-k3" diff --git a/tests/agent/test_anthropic_oauth_pkce.py b/tests/agent/test_anthropic_oauth_pkce.py index 764623232c..3336317643 100644 --- a/tests/agent/test_anthropic_oauth_pkce.py +++ b/tests/agent/test_anthropic_oauth_pkce.py @@ -120,7 +120,7 @@ def test_authorization_url_state_is_not_pkce_verifier(monkeypatch, tmp_path): monkeypatch.setattr(builtins, "input", fake_input) - from agent.anthropic_adapter import run_hermes_oauth_login_pure + from agent.anthropic_credentials import run_hermes_oauth_login_pure result = run_hermes_oauth_login_pure() assert result is not None, "OAuth flow should succeed with matching state" @@ -176,7 +176,7 @@ def test_login_token_exchange_uses_platform_claude_host(monkeypatch, tmp_path): monkeypatch.setattr(builtins, "input", fake_input) - from agent.anthropic_adapter import run_hermes_oauth_login_pure + from agent.anthropic_credentials import run_hermes_oauth_login_pure result = run_hermes_oauth_login_pure() @@ -207,7 +207,7 @@ def test_callback_state_mismatch_aborts(monkeypatch, tmp_path, caplog): capture_token_request=captured_token, ) - from agent.anthropic_adapter import run_hermes_oauth_login_pure + from agent.anthropic_credentials import run_hermes_oauth_login_pure result = run_hermes_oauth_login_pure() diff --git a/tests/agent/test_anthropic_oauth_ua_prefix.py b/tests/agent/test_anthropic_oauth_ua_prefix.py index 8f0ae90fa7..e5161afa2d 100644 --- a/tests/agent/test_anthropic_oauth_ua_prefix.py +++ b/tests/agent/test_anthropic_oauth_ua_prefix.py @@ -45,7 +45,7 @@ class TestOAuthUserAgentPrefix: def test_token_refresh_ua_not_throttled(self): """refresh_anthropic_oauth_pure must NOT send a throttled token-endpoint UA.""" import inspect - import agent.anthropic_adapter as mod + import agent.anthropic_credentials as mod func = getattr(mod, "refresh_anthropic_oauth_pure", None) if func is None or not callable(func): diff --git a/tests/agent/test_anthropic_output_field_leak.py b/tests/agent/test_anthropic_output_field_leak.py index 138aba2c0e..d2b883c317 100644 --- a/tests/agent/test_anthropic_output_field_leak.py +++ b/tests/agent/test_anthropic_output_field_leak.py @@ -11,11 +11,7 @@ normalize_response capture, _sanitize_replay_block (ordered-blocks replay), and _convert_content_part_to_anthropic (content-list replay). """ import pytest -from agent.anthropic_adapter import ( - _sanitize_replay_block, - _convert_content_part_to_anthropic, - _convert_assistant_message, -) +from agent.anthropic_message_convert import _sanitize_replay_block, _convert_content_part_to_anthropic, _convert_assistant_message FORBIDDEN = {"parsed_output", "caller"} diff --git a/tests/agent/test_anthropic_request_blank_block_guard.py b/tests/agent/test_anthropic_request_blank_block_guard.py index e253436911..cc8095a306 100644 --- a/tests/agent/test_anthropic_request_blank_block_guard.py +++ b/tests/agent/test_anthropic_request_blank_block_guard.py @@ -13,10 +13,7 @@ list, and the system-block path coerces blanks at extraction time (a blank block carrying a cache_control breakpoint cannot be dropped). Ref #69512 / #70909 (follow-up: request-level guard, not just per-message). """ -from agent.anthropic_adapter import ( - _EMPTY_TEXT_PLACEHOLDER, - convert_messages_to_anthropic, -) +from agent.anthropic_message_convert import _EMPTY_TEXT_PLACEHOLDER, convert_messages_to_anthropic def _all_text_blocks(messages): diff --git a/tests/agent/test_anthropic_thinking_block_order.py b/tests/agent/test_anthropic_thinking_block_order.py index 5455b3339a..db73d46b80 100644 --- a/tests/agent/test_anthropic_thinking_block_order.py +++ b/tests/agent/test_anthropic_thinking_block_order.py @@ -36,7 +36,7 @@ from types import SimpleNamespace import pytest from agent.transports import get_transport -from agent.anthropic_adapter import convert_messages_to_anthropic +from agent.anthropic_message_convert import convert_messages_to_anthropic def _thinking_block(text: str, signature: str) -> SimpleNamespace: diff --git a/tests/agent/test_anthropic_token_scope_isolation.py b/tests/agent/test_anthropic_token_scope_isolation.py index 6f3a48c1ab..a435e3d74b 100644 --- a/tests/agent/test_anthropic_token_scope_isolation.py +++ b/tests/agent/test_anthropic_token_scope_isolation.py @@ -32,7 +32,7 @@ import pytest from unittest.mock import patch from agent import secret_scope as ss -from agent.anthropic_adapter import resolve_anthropic_token +from agent.anthropic_credentials import resolve_anthropic_token @pytest.fixture(autouse=True) diff --git a/tests/agent/test_anthropic_whitespace_text_blocks.py b/tests/agent/test_anthropic_whitespace_text_blocks.py index 4232240f05..9aac5aa111 100644 --- a/tests/agent/test_anthropic_whitespace_text_blocks.py +++ b/tests/agent/test_anthropic_whitespace_text_blocks.py @@ -12,12 +12,7 @@ text to a non-whitespace placeholder at two points on the Anthropic request path in ``_convert_assistant_message`` (main path). Ref #69512. """ import pytest -from agent.anthropic_adapter import ( - _EMPTY_TEXT_PLACEHOLDER, - _safe_text, - _sanitize_replay_block, - _convert_assistant_message, -) +from agent.anthropic_message_convert import _EMPTY_TEXT_PLACEHOLDER, _safe_text, _sanitize_replay_block, _convert_assistant_message def _text_blocks(msg): diff --git a/tests/agent/test_auxiliary_anthropic_pool_fallback_regression.py b/tests/agent/test_auxiliary_anthropic_pool_fallback_regression.py index 6277bac5f1..e797765ef0 100644 --- a/tests/agent/test_auxiliary_anthropic_pool_fallback_regression.py +++ b/tests/agent/test_auxiliary_anthropic_pool_fallback_regression.py @@ -53,7 +53,7 @@ class TestAnthropicPoolExhaustedFallsBackToEnv: with patch( "agent.auxiliary_client._select_pool_entry", return_value=(True, None) ), patch( - "agent.anthropic_adapter.resolve_anthropic_token", return_value=None + "agent.anthropic_credentials.resolve_anthropic_token", return_value=None ): from agent.auxiliary_client import _try_anthropic diff --git a/tests/agent/test_auxiliary_client.py b/tests/agent/test_auxiliary_client.py index c0c485ea72..f2930a0604 100644 --- a/tests/agent/test_auxiliary_client.py +++ b/tests/agent/test_auxiliary_client.py @@ -670,7 +670,7 @@ class TestAnthropicOAuthFlag: def test_api_key_no_oauth_flag(self, monkeypatch): """Regular API keys (sk-ant-api-*) should create client with is_oauth=False.""" - with patch("agent.anthropic_adapter.resolve_anthropic_token", return_value="sk-ant-api03-testkey1234"), \ + with patch("agent.anthropic_credentials.resolve_anthropic_token", return_value="sk-ant-api03-testkey1234"), \ patch("agent.anthropic_adapter.build_anthropic_client") as mock_build, \ patch("agent.auxiliary_client._select_pool_entry", return_value=(False, None)): mock_build.return_value = MagicMock() @@ -695,7 +695,7 @@ class TestAnthropicOAuthFlag: with ( patch("agent.auxiliary_client.load_pool", return_value=_Pool()), - patch("agent.anthropic_adapter.resolve_anthropic_token", side_effect=AssertionError("legacy path should not run")), + patch("agent.anthropic_credentials.resolve_anthropic_token", side_effect=AssertionError("legacy path should not run")), patch("agent.anthropic_adapter.build_anthropic_client", return_value=MagicMock()) as mock_build, ): from agent.auxiliary_client import _try_anthropic @@ -961,7 +961,7 @@ class TestExplicitProviderRouting: def test_explicit_anthropic_api_key(self, monkeypatch): """provider='anthropic' + regular API key should work with is_oauth=False.""" - with patch("agent.anthropic_adapter.resolve_anthropic_token", return_value="sk-ant-api-regular-key"), \ + with patch("agent.anthropic_credentials.resolve_anthropic_token", return_value="sk-ant-api-regular-key"), \ patch("agent.anthropic_adapter.build_anthropic_client") as mock_build, \ patch("agent.auxiliary_client._select_pool_entry", return_value=(False, None)): mock_build.return_value = MagicMock() @@ -1217,7 +1217,7 @@ class TestVisionClientFallback: patch("agent.auxiliary_client._read_main_provider", return_value="anthropic"), patch("agent.auxiliary_client._read_main_model", return_value="claude-sonnet-4"), patch("agent.anthropic_adapter.build_anthropic_client", return_value=MagicMock()), - patch("agent.anthropic_adapter.resolve_anthropic_token", return_value="***"), + patch("agent.anthropic_credentials.resolve_anthropic_token", return_value="***"), ): backends = get_available_vision_backends() @@ -4027,7 +4027,7 @@ class TestAnthropicExplicitApiKey: def test_try_anthropic_uses_explicit_api_key_over_env(self): """_try_anthropic(explicit_api_key) must use the supplied key, not the env fallback.""" - with patch("agent.anthropic_adapter.resolve_anthropic_token", return_value="env-fallback-key"), \ + with patch("agent.anthropic_credentials.resolve_anthropic_token", return_value="env-fallback-key"), \ patch("agent.anthropic_adapter.build_anthropic_client") as mock_build, \ patch("agent.auxiliary_client._select_pool_entry", return_value=(False, None)): mock_build.return_value = MagicMock() @@ -4041,7 +4041,7 @@ class TestAnthropicExplicitApiKey: def test_try_anthropic_without_explicit_key_falls_back_to_resolve(self): """Without explicit_api_key, _try_anthropic falls back to resolve_anthropic_token.""" - with patch("agent.anthropic_adapter.resolve_anthropic_token", return_value="env-fallback-key"), \ + with patch("agent.anthropic_credentials.resolve_anthropic_token", return_value="env-fallback-key"), \ patch("agent.anthropic_adapter.build_anthropic_client") as mock_build, \ patch("agent.auxiliary_client._select_pool_entry", return_value=(False, None)): mock_build.return_value = MagicMock() @@ -4052,7 +4052,7 @@ class TestAnthropicExplicitApiKey: def test_resolve_provider_client_passes_explicit_api_key_to_anthropic(self): """resolve_provider_client(provider='anthropic', explicit_api_key=...) must propagate the key.""" - with patch("agent.anthropic_adapter.resolve_anthropic_token", return_value="env-key"), \ + with patch("agent.anthropic_credentials.resolve_anthropic_token", return_value="env-key"), \ patch("agent.anthropic_adapter.build_anthropic_client") as mock_build, \ patch("agent.auxiliary_client._select_pool_entry", return_value=(False, None)): mock_build.return_value = MagicMock() diff --git a/tests/agent/test_auxiliary_client_base_url_host_validation_52608.py b/tests/agent/test_auxiliary_client_base_url_host_validation_52608.py index 478a366078..a55d01a07d 100644 --- a/tests/agent/test_auxiliary_client_base_url_host_validation_52608.py +++ b/tests/agent/test_auxiliary_client_base_url_host_validation_52608.py @@ -39,7 +39,7 @@ class TestTryAnthropicBaseUrlHostValidation: "agent.auxiliary_client._select_pool_entry", return_value=(False, None) ), patch( - "agent.anthropic_adapter.resolve_anthropic_token", + "agent.anthropic_credentials.resolve_anthropic_token", return_value="***", ), patch( @@ -74,7 +74,7 @@ class TestTryAnthropicBaseUrlHostValidation: "agent.auxiliary_client._select_pool_entry", return_value=(False, None) ), patch( - "agent.anthropic_adapter.resolve_anthropic_token", + "agent.anthropic_credentials.resolve_anthropic_token", return_value="***", ), patch( @@ -106,7 +106,7 @@ class TestTryAnthropicBaseUrlHostValidation: "agent.auxiliary_client._select_pool_entry", return_value=(False, None) ), patch( - "agent.anthropic_adapter.resolve_anthropic_token", + "agent.anthropic_credentials.resolve_anthropic_token", return_value="***", ), patch( @@ -141,7 +141,7 @@ class TestTryAnthropicBaseUrlHostValidation: "agent.auxiliary_client._select_pool_entry", return_value=(False, None) ), patch( - "agent.anthropic_adapter.resolve_anthropic_token", + "agent.anthropic_credentials.resolve_anthropic_token", return_value="***", ), patch( @@ -175,7 +175,7 @@ class TestTryAnthropicBaseUrlHostValidation: "agent.auxiliary_client._select_pool_entry", return_value=(False, None) ), patch( - "agent.anthropic_adapter.resolve_anthropic_token", + "agent.anthropic_credentials.resolve_anthropic_token", return_value="***", ), patch( @@ -220,7 +220,7 @@ class TestTryAnthropicBaseUrlHostValidation: "agent.auxiliary_client._select_pool_entry", return_value=(False, None) ), patch( - "agent.anthropic_adapter.resolve_anthropic_token", + "agent.anthropic_credentials.resolve_anthropic_token", return_value="***", ), patch( diff --git a/tests/agent/test_bedrock_integration.py b/tests/agent/test_bedrock_integration.py index bd9da1cfe0..fb4476447b 100644 --- a/tests/agent/test_bedrock_integration.py +++ b/tests/agent/test_bedrock_integration.py @@ -290,7 +290,7 @@ class TestPackaging: # us.anthropic.claude-sonnet-4-5-20250929-v1:0 # apac.anthropic.claude-haiku-4-5 # -# ``agent.anthropic_adapter.normalize_model_name`` converts dots to hyphens +# ``agent.anthropic_message_convert.normalize_model_name`` converts dots to hyphens # unless the caller opts in via ``preserve_dots=True``. Before this fix, # ``AIAgent._anthropic_preserve_dots`` returned False for the ``bedrock`` # provider, so Claude-on-Bedrock requests went out with @@ -339,7 +339,7 @@ class TestBedrockModelNameNormalization: def test_global_anthropic_inference_profile_preserved(self): """The reporter's exact model ID.""" - from agent.anthropic_adapter import normalize_model_name + from agent.anthropic_message_convert import normalize_model_name assert normalize_model_name( "global.anthropic.claude-opus-4-7", preserve_dots=True ) == "global.anthropic.claude-opus-4-7" @@ -351,7 +351,7 @@ class TestBedrockModelNameNormalization: always returned unmangled -- ``preserve_dots`` is irrelevant for these IDs because the dots are namespace separators, not version separators. Regression for #12295.""" - from agent.anthropic_adapter import normalize_model_name + from agent.anthropic_message_convert import normalize_model_name assert normalize_model_name( "global.anthropic.claude-opus-4-7", preserve_dots=False ) == "global.anthropic.claude-opus-4-7" @@ -403,7 +403,7 @@ class TestBedrockModelIdDetection: regardless of ``preserve_dots``. Regression for #12295.""" def test_bare_bedrock_id_detected(self): - from agent.anthropic_adapter import _is_bedrock_model_id + from agent.anthropic_message_convert import _is_bedrock_model_id assert _is_bedrock_model_id("anthropic.claude-opus-4-7") is True @@ -415,7 +415,7 @@ class TestBedrockModelIdDetection: """The primary bug from #12295: ``anthropic.claude-opus-4-7`` sent to bedrock-mantle via auxiliary clients that don't pass ``preserve_dots=True``.""" - from agent.anthropic_adapter import normalize_model_name + from agent.anthropic_message_convert import normalize_model_name assert normalize_model_name( "anthropic.claude-opus-4-7", preserve_dots=False ) == "anthropic.claude-opus-4-7" diff --git a/tests/agent/test_credential_pool_oat_authtype.py b/tests/agent/test_credential_pool_oat_authtype.py index 468e2b1e96..409d2c5397 100644 --- a/tests/agent/test_credential_pool_oat_authtype.py +++ b/tests/agent/test_credential_pool_oat_authtype.py @@ -53,7 +53,7 @@ def test_load_heals_legacy_row_and_exposes_it_to_resolver(tmp_path, monkeypatch) }, })) - from agent.anthropic_adapter import resolve_anthropic_token + from agent.anthropic_credentials import resolve_anthropic_token from agent.credential_pool import load_pool entry = load_pool("anthropic").entries()[0] diff --git a/tests/agent/test_deepseek_anthropic_thinking.py b/tests/agent/test_deepseek_anthropic_thinking.py index 845f230de8..9f0dd66f00 100644 --- a/tests/agent/test_deepseek_anthropic_thinking.py +++ b/tests/agent/test_deepseek_anthropic_thinking.py @@ -35,7 +35,7 @@ class TestDeepSeekAnthropicPreservesThinking: DeepSeek issues its own signatures and cannot validate Anthropic's — the strip-signed / keep-unsigned split matches the Kimi policy. """ - from agent.anthropic_adapter import convert_messages_to_anthropic + from agent.anthropic_message_convert import convert_messages_to_anthropic messages = [ {"role": "user", "content": "hi"}, @@ -73,7 +73,7 @@ class TestDeepSeekAnthropicPreservesThinking: as ignored — cache markers interfere with signature validation on upstreams that do check them, so Hermes strips them everywhere. """ - from agent.anthropic_adapter import convert_messages_to_anthropic + from agent.anthropic_message_convert import convert_messages_to_anthropic messages = [ {"role": "user", "content": "hi"}, diff --git a/tests/agent/test_kimi_coding_anthropic_thinking.py b/tests/agent/test_kimi_coding_anthropic_thinking.py index 309fa8a400..24a1180f9c 100644 --- a/tests/agent/test_kimi_coding_anthropic_thinking.py +++ b/tests/agent/test_kimi_coding_anthropic_thinking.py @@ -118,7 +118,7 @@ class TestKimiFamilyGetsAdaptiveThinking: blocks must survive the third-party signature-stripping pass so the upstream's message-history validation passes. """ - from agent.anthropic_adapter import convert_messages_to_anthropic + from agent.anthropic_message_convert import convert_messages_to_anthropic messages = [ {"role": "user", "content": "hi"}, diff --git a/tests/agent/test_meta_agent_init.py b/tests/agent/test_meta_agent_init.py index 60be0da0bf..2d56453d10 100644 --- a/tests/agent/test_meta_agent_init.py +++ b/tests/agent/test_meta_agent_init.py @@ -97,7 +97,7 @@ def test_agent_init_anthropic_url_implies_provider_and_api_mode(): from run_agent import AIAgent with patch("agent.anthropic_adapter.build_anthropic_client", return_value=MagicMock()), patch( - "agent.anthropic_adapter._is_oauth_token", return_value=False + "agent.anthropic_credentials._is_oauth_token", return_value=False ): agent = AIAgent( provider=None, @@ -127,7 +127,7 @@ def test_agent_init_anthropic_url_preserves_credential_pool(): pool = SimpleNamespace(provider="anthropic") with patch("agent.anthropic_adapter.build_anthropic_client", return_value=MagicMock()), patch( - "agent.anthropic_adapter._is_oauth_token", return_value=False + "agent.anthropic_credentials._is_oauth_token", return_value=False ): agent = AIAgent( provider=None, diff --git a/tests/agent/test_minimax_provider.py b/tests/agent/test_minimax_provider.py index bd50838337..a6996e8179 100644 --- a/tests/agent/test_minimax_provider.py +++ b/tests/agent/test_minimax_provider.py @@ -275,7 +275,7 @@ class TestMinimaxPreserveDots: def test_normalize_preserves_m25_free_dot(self): - from agent.anthropic_adapter import normalize_model_name + from agent.anthropic_message_convert import normalize_model_name assert normalize_model_name("minimax-m2.5-free", preserve_dots=True) == "minimax-m2.5-free" @@ -312,8 +312,8 @@ class TestMinimaxSwitchModelCredentialGuard: agent._fallback_chain = [] with patch("agent.anthropic_adapter.build_anthropic_client") as mock_build, \ - patch("agent.anthropic_adapter.resolve_anthropic_token", return_value="sk-ant-leaked") as mock_resolve, \ - patch("agent.anthropic_adapter._is_oauth_token", return_value=False): + patch("agent.anthropic_credentials.resolve_anthropic_token", return_value="sk-ant-leaked") as mock_resolve, \ + patch("agent.anthropic_credentials._is_oauth_token", return_value=False): agent.switch_model( new_model="MiniMax-M2.7", diff --git a/tests/agent/test_none_deref_guards.py b/tests/agent/test_none_deref_guards.py index 58ff72c456..7834ced543 100644 --- a/tests/agent/test_none_deref_guards.py +++ b/tests/agent/test_none_deref_guards.py @@ -6,7 +6,7 @@ a present-but-null value sails through as None and crashes any chained method call. """ -from agent.anthropic_adapter import _convert_user_message +from agent.anthropic_message_convert import _convert_user_message from agent.moa_loop import _slot_label diff --git a/tests/agent/test_nous_portal_anthropic_wire.py b/tests/agent/test_nous_portal_anthropic_wire.py index 2b4521c87e..af85a6003e 100644 --- a/tests/agent/test_nous_portal_anthropic_wire.py +++ b/tests/agent/test_nous_portal_anthropic_wire.py @@ -172,10 +172,7 @@ class TestClientShape: def test_lookalike_host_does_not_get_portal_treatment(self): """Substring matching would hand a spoofed host the Portal JWT as a Bearer token. Hostname matching must reject it.""" - from agent.anthropic_adapter import ( - _is_nous_portal_endpoint, - _requires_bearer_auth, - ) + from agent.anthropic_endpoints import _is_nous_portal_endpoint, _requires_bearer_auth spoofed = "https://inference-api.nousresearch.com.attacker.test/v1" assert not _is_nous_portal_endpoint(spoofed) @@ -369,7 +366,7 @@ class TestPortalThinkingReplay: ] def _assert_thinking_kept(self, base_url): - from agent.anthropic_adapter import convert_messages_to_anthropic + from agent.anthropic_message_convert import convert_messages_to_anthropic _system, converted = convert_messages_to_anthropic( self._messages(), @@ -402,7 +399,7 @@ class TestPortalThinkingReplay: def test_other_third_party_gateways_still_strip_thinking(self): """The Portal carve-out must not leak into MiniMax-style proxies.""" - from agent.anthropic_adapter import convert_messages_to_anthropic + from agent.anthropic_message_convert import convert_messages_to_anthropic _system, converted = convert_messages_to_anthropic( self._messages(), diff --git a/tests/agent/test_pydantic_dump_warning_leak.py b/tests/agent/test_pydantic_dump_warning_leak.py index 48f18de71c..d17794bedc 100644 --- a/tests/agent/test_pydantic_dump_warning_leak.py +++ b/tests/agent/test_pydantic_dump_warning_leak.py @@ -101,7 +101,7 @@ def test_relay_tools_jsonable_no_warning_leak(): def test_anthropic_to_plain_data_no_warning_leak(): - from agent.anthropic_adapter import _to_plain_data + from agent.anthropic_message_convert import _to_plain_data _, snapshot = _accumulated_stop_event() with warnings.catch_warnings(record=True) as recorded: @@ -126,7 +126,7 @@ def test_duck_typed_model_dump_fallback(): """Non-pydantic objects with a bare model_dump() must still serialize.""" from agent.relay_llm import _jsonable as rl_jsonable from agent.relay_tools import _jsonable as rt_jsonable - from agent.anthropic_adapter import _to_plain_data + from agent.anthropic_message_convert import _to_plain_data class Duck: def model_dump(self): # no mode/warnings kwargs diff --git a/tests/conftest.py b/tests/conftest.py index e4dfb0ed06..fb62a748c2 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -631,21 +631,16 @@ def _neutralize_macos_keychain_creds(request, monkeypatch): if request.node.get_closest_marker(_ALLOW_MACOS_KEYCHAIN_MARK): return None - # Patch the implementation owner (agent.anthropic_credentials) AND the - # adapter re-export: after the adapter godfile split, the real call - # executes inside agent.anthropic_credentials, so patching only the - # adapter alias silently stopped intercepting Keychain reads. - for _module_name in ("agent.anthropic_credentials", "agent.anthropic_adapter"): - try: - _mod = importlib.import_module(_module_name) - except Exception: - continue - monkeypatch.setattr( - _mod, - "_read_claude_code_credentials_from_keychain", - lambda *_args, **_kwargs: None, - raising=False, - ) + try: + _mod = importlib.import_module("agent.anthropic_credentials") + except Exception: + return None + monkeypatch.setattr( + _mod, + "_read_claude_code_credentials_from_keychain", + lambda *_args, **_kwargs: None, + raising=False, + ) return None diff --git a/tests/hermes_cli/test_anthropic_model_flow_stale_oauth.py b/tests/hermes_cli/test_anthropic_model_flow_stale_oauth.py index 7691724459..40526514cd 100644 --- a/tests/hermes_cli/test_anthropic_model_flow_stale_oauth.py +++ b/tests/hermes_cli/test_anthropic_model_flow_stale_oauth.py @@ -27,7 +27,7 @@ class TestStaleOAuthTokenDetection: # No valid Claude Code credentials available (expired, no refresh token) monkeypatch.setattr( - "agent.anthropic_adapter.read_claude_code_credentials", + "agent.anthropic_credentials.read_claude_code_credentials", lambda: { "accessToken": "expired-cc-token", "refreshToken": "", # No refresh — can't recover @@ -36,16 +36,16 @@ class TestStaleOAuthTokenDetection: }, ) monkeypatch.setattr( - "agent.anthropic_adapter.is_claude_code_token_valid", + "agent.anthropic_credentials.is_claude_code_token_valid", lambda creds: False, # Explicitly expired ) monkeypatch.setattr( - "agent.anthropic_adapter._is_oauth_token", + "agent.anthropic_credentials._is_oauth_token", lambda key: key.startswith("sk-ant-"), ) # _resolve_claude_code_token_from_credentials has no valid path monkeypatch.setattr( - "agent.anthropic_adapter._resolve_claude_code_token_from_credentials", + "agent.anthropic_credentials._resolve_claude_code_token_from_credentials", lambda creds=None: None, ) @@ -77,15 +77,15 @@ class TestStaleOAuthTokenDetection: save_env_value("ANTHROPIC_TOKEN", "") monkeypatch.setattr( - "agent.anthropic_adapter.read_claude_code_credentials", + "agent.anthropic_credentials.read_claude_code_credentials", lambda: None, # No CC creds ) monkeypatch.setattr( - "agent.anthropic_adapter.is_claude_code_token_valid", + "agent.anthropic_credentials.is_claude_code_token_valid", lambda creds: False, ) monkeypatch.setattr( - "agent.anthropic_adapter._is_oauth_token", + "agent.anthropic_credentials._is_oauth_token", lambda key: key.startswith("sk-ant-") and "oat" in key, ) diff --git a/tests/hermes_cli/test_anthropic_oauth_flow.py b/tests/hermes_cli/test_anthropic_oauth_flow.py index d9c06d2513..0213b05e95 100644 --- a/tests/hermes_cli/test_anthropic_oauth_flow.py +++ b/tests/hermes_cli/test_anthropic_oauth_flow.py @@ -6,11 +6,11 @@ from hermes_cli.config import load_env, save_env_value def test_run_anthropic_oauth_flow_prefers_claude_code_credentials(tmp_path, monkeypatch, capsys): monkeypatch.setenv("HERMES_HOME", str(tmp_path)) monkeypatch.setattr( - "agent.anthropic_adapter.run_oauth_setup_token", + "agent.anthropic_credentials.run_oauth_setup_token", lambda: "sk-ant-oat01-from-claude-setup", ) monkeypatch.setattr( - "agent.anthropic_adapter.read_claude_code_credentials", + "agent.anthropic_credentials.read_claude_code_credentials", lambda: { "accessToken": "cc-access-token", "refreshToken": "cc-refresh-token", @@ -18,7 +18,7 @@ def test_run_anthropic_oauth_flow_prefers_claude_code_credentials(tmp_path, monk }, ) monkeypatch.setattr( - "agent.anthropic_adapter.is_claude_code_token_valid", + "agent.anthropic_credentials.is_claude_code_token_valid", lambda creds: True, ) @@ -36,9 +36,9 @@ def test_run_anthropic_oauth_flow_prefers_claude_code_credentials(tmp_path, monk def test_run_anthropic_oauth_flow_manual_token_still_persists(tmp_path, monkeypatch, capsys): monkeypatch.setenv("HERMES_HOME", str(tmp_path)) - monkeypatch.setattr("agent.anthropic_adapter.run_oauth_setup_token", lambda: None) - monkeypatch.setattr("agent.anthropic_adapter.read_claude_code_credentials", lambda: None) - monkeypatch.setattr("agent.anthropic_adapter.is_claude_code_token_valid", lambda creds: False) + monkeypatch.setattr("agent.anthropic_credentials.run_oauth_setup_token", lambda: None) + monkeypatch.setattr("agent.anthropic_credentials.read_claude_code_credentials", lambda: None) + monkeypatch.setattr("agent.anthropic_credentials.is_claude_code_token_valid", lambda creds: False) monkeypatch.setattr("builtins.input", lambda _prompt="": "sk-ant-oat01-manual-token") monkeypatch.setattr( "hermes_cli.secret_prompt.masked_secret_prompt", diff --git a/tests/hermes_cli/test_anthropic_pool_model_discovery.py b/tests/hermes_cli/test_anthropic_pool_model_discovery.py index 74689a93fa..edeaa0fcdf 100644 --- a/tests/hermes_cli/test_anthropic_pool_model_discovery.py +++ b/tests/hermes_cli/test_anthropic_pool_model_discovery.py @@ -23,7 +23,7 @@ def test_anthropic_picker_discovers_models_with_pool_api_key(monkeypatch): """A direct API key stored only in auth.json must reach /v1/models.""" monkeypatch.setattr(models, "_get_model_config_dict", lambda: {"provider": "nous"}) monkeypatch.setattr( - "agent.anthropic_adapter.resolve_anthropic_token", + "agent.anthropic_credentials.resolve_anthropic_token", lambda: None, ) monkeypatch.setattr( @@ -71,7 +71,7 @@ def test_anthropic_pool_api_key_overrides_conflicting_active_endpoint(monkeypatc lambda: {"provider": "anthropic", "base_url": active_endpoint}, ) monkeypatch.setattr( - "agent.anthropic_adapter.resolve_anthropic_token", + "agent.anthropic_credentials.resolve_anthropic_token", lambda: None, ) monkeypatch.setattr( diff --git a/tests/hermes_cli/test_api_key_providers.py b/tests/hermes_cli/test_api_key_providers.py index 16aee6c957..18fd8dd1fb 100644 --- a/tests/hermes_cli/test_api_key_providers.py +++ b/tests/hermes_cli/test_api_key_providers.py @@ -535,11 +535,11 @@ class TestHasAnyProviderConfigured: monkeypatch.setattr("hermes_cli.auth.get_auth_status", lambda _pid: {}) # Simulate valid Claude Code credentials monkeypatch.setattr( - "agent.anthropic_adapter.read_claude_code_credentials", + "agent.anthropic_credentials.read_claude_code_credentials", lambda: {"accessToken": "sk-ant-test", "refreshToken": "ref-tok"}, ) monkeypatch.setattr( - "agent.anthropic_adapter.is_claude_code_token_valid", + "agent.anthropic_credentials.is_claude_code_token_valid", lambda creds: True, ) from hermes_cli.main import _has_any_provider_configured diff --git a/tests/hermes_cli/test_auth_commands.py b/tests/hermes_cli/test_auth_commands.py index 29e992d2bd..682807add3 100644 --- a/tests/hermes_cli/test_auth_commands.py +++ b/tests/hermes_cli/test_auth_commands.py @@ -960,7 +960,7 @@ def test_seed_from_singletons_respects_hermes_pkce_suppression(tmp_path, monkeyp })) # Stub the readers so only hermes_pkce is "available"; claude_code returns None - import agent.anthropic_adapter as aa + import agent.anthropic_credentials as aa monkeypatch.setattr(aa, "read_hermes_oauth_credentials", lambda: { "accessToken": "tok", "refreshToken": "r", "expiresAt": 9999999999000, }) diff --git a/tests/hermes_cli/test_inventory.py b/tests/hermes_cli/test_inventory.py index b4bf1fb92a..6726c55b3a 100644 --- a/tests/hermes_cli/test_inventory.py +++ b/tests/hermes_cli/test_inventory.py @@ -311,11 +311,11 @@ def test_anthropic_oauth_presence_accepts_pool_only_oauth_entry(): with ( patch( - "agent.anthropic_adapter.read_hermes_oauth_credentials", + "agent.anthropic_credentials.read_hermes_oauth_credentials", return_value=None, ), patch( - "agent.anthropic_adapter.read_claude_code_credentials", + "agent.anthropic_credentials.read_claude_code_credentials", return_value=None, ), patch( @@ -331,11 +331,11 @@ def test_anthropic_oauth_presence_accepts_pool_only_oauth_entry(): # (they are handled by the explicit-config gate / env var paths). with ( patch( - "agent.anthropic_adapter.read_hermes_oauth_credentials", + "agent.anthropic_credentials.read_hermes_oauth_credentials", return_value=None, ), patch( - "agent.anthropic_adapter.read_claude_code_credentials", + "agent.anthropic_credentials.read_claude_code_credentials", return_value=None, ), patch( diff --git a/tests/hermes_cli/test_model_switch_opencode_anthropic.py b/tests/hermes_cli/test_model_switch_opencode_anthropic.py index c863356fef..faad9c4b30 100644 --- a/tests/hermes_cli/test_model_switch_opencode_anthropic.py +++ b/tests/hermes_cli/test_model_switch_opencode_anthropic.py @@ -154,8 +154,8 @@ class TestAgentSwitchModelDefenseInDepth: with patch( "agent.anthropic_adapter.build_anthropic_client", side_effect=_raise_after_capture, - ), patch("agent.anthropic_adapter.resolve_anthropic_token", return_value=""), patch( - "agent.anthropic_adapter._is_oauth_token", return_value=False + ), patch("agent.anthropic_credentials.resolve_anthropic_token", return_value=""), patch( + "agent.anthropic_credentials._is_oauth_token", return_value=False ): with pytest.raises(_Sentinel): agent.switch_model( diff --git a/tests/hermes_cli/test_runtime_provider_resolution.py b/tests/hermes_cli/test_runtime_provider_resolution.py index 71614d0d27..35865157c6 100644 --- a/tests/hermes_cli/test_runtime_provider_resolution.py +++ b/tests/hermes_cli/test_runtime_provider_resolution.py @@ -1192,7 +1192,7 @@ class TestAzureAnthropicEnvVarHint: called["resolve_anthropic_token"] = True return "token-from-resolver" monkeypatch.setattr( - "agent.anthropic_adapter.resolve_anthropic_token", + "agent.anthropic_credentials.resolve_anthropic_token", _fake_resolve, ) diff --git a/tests/plugins/model_providers/test_commandcode_profile.py b/tests/plugins/model_providers/test_commandcode_profile.py index e41a2bdc30..f7ce6b0244 100644 --- a/tests/plugins/model_providers/test_commandcode_profile.py +++ b/tests/plugins/model_providers/test_commandcode_profile.py @@ -156,14 +156,14 @@ class TestCommandCodeAnthropicBearerAuth: """ def test_requires_bearer_auth_recognizes_commandcode(self): - from agent.anthropic_adapter import _requires_bearer_auth + from agent.anthropic_endpoints import _requires_bearer_auth assert _requires_bearer_auth("https://api.commandcode.ai/provider/v1") is True assert _requires_bearer_auth("https://api.commandcode.ai/provider/v1/models") is True assert _requires_bearer_auth("https://api.commandcode.ai/anthropic") is True def test_bearer_auth_does_not_affect_unrelated(self): - from agent.anthropic_adapter import _requires_bearer_auth + from agent.anthropic_endpoints import _requires_bearer_auth # Native Anthropic still uses x-api-key assert _requires_bearer_auth("https://api.anthropic.com") is False @@ -171,7 +171,7 @@ class TestCommandCodeAnthropicBearerAuth: assert _requires_bearer_auth("https://openrouter.ai/api/v1") is False def test_bearer_auth_case_insensitive(self): - from agent.anthropic_adapter import _requires_bearer_auth + from agent.anthropic_endpoints import _requires_bearer_auth assert _requires_bearer_auth("https://API.COMMANDCODE.AI/provider/v1") is True diff --git a/tests/run_agent/test_63425_credential_pool_auto_detect.py b/tests/run_agent/test_63425_credential_pool_auto_detect.py index 5ac6dbcd9a..b89edf76cd 100644 --- a/tests/run_agent/test_63425_credential_pool_auto_detect.py +++ b/tests/run_agent/test_63425_credential_pool_auto_detect.py @@ -38,8 +38,8 @@ class TestCredentialPoolPreservedOnAutoDetect: with patch("agent.auxiliary_client.resolve_provider_client", return_value=(None, None)), \ patch("run_agent.get_tool_definitions", return_value=[]), \ patch('agent.anthropic_adapter.build_anthropic_client', return_value=MagicMock()), \ - patch('agent.anthropic_adapter.resolve_anthropic_token', return_value=''), \ - patch('agent.anthropic_adapter._is_oauth_token', return_value=False), \ + patch('agent.anthropic_credentials.resolve_anthropic_token', return_value=''), \ + patch('agent.anthropic_credentials._is_oauth_token', return_value=False), \ patch('agent.azure_identity_adapter.is_token_provider', return_value=False), \ patch('hermes_cli.model_normalize.normalize_model_for_provider', return_value='test-model'), \ patch('agent.credential_pool.load_pool', return_value=MagicMock()), \ diff --git a/tests/run_agent/test_anthropic_third_party_oauth_guard.py b/tests/run_agent/test_anthropic_third_party_oauth_guard.py index ea6dae0733..031ee0ca71 100644 --- a/tests/run_agent/test_anthropic_third_party_oauth_guard.py +++ b/tests/run_agent/test_anthropic_third_party_oauth_guard.py @@ -64,7 +64,7 @@ class TestOAuthFlagOnRefresh: agent._is_anthropic_oauth = False with ( - patch("agent.anthropic_adapter.resolve_anthropic_token", + patch("agent.anthropic_credentials.resolve_anthropic_token", return_value=_OAUTH_LIKE_TOKEN), patch("agent.anthropic_adapter.build_anthropic_client", return_value=MagicMock()), @@ -111,7 +111,7 @@ class TestOAuthFlagOnConstruction: return_value=MagicMock()), # Simulate a stale ANTHROPIC_TOKEN in the env — the init code # MUST NOT fall back to it when provider != anthropic. - patch("agent.anthropic_adapter.resolve_anthropic_token", + patch("agent.anthropic_credentials.resolve_anthropic_token", return_value=_OAUTH_LIKE_TOKEN), ): agent = AIAgent( @@ -136,7 +136,7 @@ class TestOAuthFlagOnFallbackActivation: def test_fallback_to_third_party_does_not_flip_oauth(self, agent): """Directly mimic the post-fallback assignment at line ~6537.""" - from agent.anthropic_adapter import _is_oauth_token + from agent.anthropic_credentials import _is_oauth_token # Emulate the relevant lines of _try_activate_fallback without # running the entire recovery stack (which pulls in streaming, @@ -153,6 +153,6 @@ class TestApiKeyTokensAlwaysSafe: """Regression: plain API-key shapes must always resolve to non-OAuth, any provider.""" def test_native_anthropic_with_api_key_token(self): - from agent.anthropic_adapter import _is_oauth_token + from agent.anthropic_credentials import _is_oauth_token assert _is_oauth_token(_API_KEY_TOKEN) is False diff --git a/tests/run_agent/test_switch_model_fallback_prune.py b/tests/run_agent/test_switch_model_fallback_prune.py index a01a60348c..3aee34183d 100644 --- a/tests/run_agent/test_switch_model_fallback_prune.py +++ b/tests/run_agent/test_switch_model_fallback_prune.py @@ -40,8 +40,8 @@ def _make_agent(chain): def _switch_to_anthropic(agent): with ( patch("agent.anthropic_adapter.build_anthropic_client", return_value=MagicMock()), - patch("agent.anthropic_adapter.resolve_anthropic_token", return_value="sk-ant-xyz"), - patch("agent.anthropic_adapter._is_oauth_token", return_value=False), + patch("agent.anthropic_credentials.resolve_anthropic_token", return_value="sk-ant-xyz"), + patch("agent.anthropic_credentials._is_oauth_token", return_value=False), patch("hermes_cli.timeouts.get_provider_request_timeout", return_value=None), ): agent.switch_model( diff --git a/tests/run_agent/test_switch_model_rollback.py b/tests/run_agent/test_switch_model_rollback.py index d5a1abf2c0..6009a6ce10 100644 --- a/tests/run_agent/test_switch_model_rollback.py +++ b/tests/run_agent/test_switch_model_rollback.py @@ -127,10 +127,10 @@ def test_anthropic_client_rebuild_failure_rolls_back_to_original_state(): side_effect=RuntimeError("simulated anthropic build failure"), ), patch( - "agent.anthropic_adapter.resolve_anthropic_token", + "agent.anthropic_credentials.resolve_anthropic_token", return_value="sk-ant-resolved", ), - patch("agent.anthropic_adapter._is_oauth_token", return_value=False), + patch("agent.anthropic_credentials._is_oauth_token", return_value=False), patch("hermes_cli.timeouts.get_provider_request_timeout", return_value=None), ): with pytest.raises(RuntimeError, match="simulated anthropic build failure"): diff --git a/tests/test_hermetic_side_effect_guards.py b/tests/test_hermetic_side_effect_guards.py index 983e6c44ad..d9df5ca01d 100644 --- a/tests/test_hermetic_side_effect_guards.py +++ b/tests/test_hermetic_side_effect_guards.py @@ -33,14 +33,11 @@ def test_webbrowser_get_controller_is_neutralized(_neutralize_webbrowser): def _isolate_anthropic_credentials(monkeypatch, tmp_path): - from agent import anthropic_adapter as aa from agent import anthropic_credentials as ac monkeypatch.delenv("ANTHROPIC_API_KEY", raising=False) monkeypatch.delenv("ANTHROPIC_TOKEN", raising=False) monkeypatch.delenv("CLAUDE_CODE_OAUTH_TOKEN", raising=False) - # Patch the implementation owner (anthropic_credentials); the adapter - # merely re-exports these functions after the godfile split. monkeypatch.setattr(ac.Path, "home", lambda: tmp_path) monkeypatch.setattr(ac.platform, "system", lambda: "Darwin") @@ -48,22 +45,22 @@ def _isolate_anthropic_credentials(monkeypatch, tmp_path): raise AssertionError("test reached the real macOS Keychain command") monkeypatch.setattr(ac.subprocess, "run", _real_keychain_reached) - return aa + return ac def test_claude_code_credential_read_does_not_touch_macos_keychain( monkeypatch, tmp_path ): """The real credential reader should be safe under the suite guard.""" - aa = _isolate_anthropic_credentials(monkeypatch, tmp_path) + ac = _isolate_anthropic_credentials(monkeypatch, tmp_path) - assert aa.read_claude_code_credentials() is None + assert ac.read_claude_code_credentials() is None def test_anthropic_token_resolution_does_not_touch_macos_keychain( monkeypatch, tmp_path ): """Token resolution should be safe under the same suite guard.""" - aa = _isolate_anthropic_credentials(monkeypatch, tmp_path) + ac = _isolate_anthropic_credentials(monkeypatch, tmp_path) - assert aa.resolve_anthropic_token() is None + assert ac.resolve_anthropic_token() is None diff --git a/tests/tools/test_computer_use.py b/tests/tools/test_computer_use.py index b5a0cfd1b4..eb4df4175c 100644 --- a/tests/tools/test_computer_use.py +++ b/tests/tools/test_computer_use.py @@ -406,7 +406,7 @@ class TestCuaCaptureImageDimensions: class TestAnthropicAdapterMultimodal: def test_multimodal_envelope_becomes_tool_result_with_image_block(self): - from agent.anthropic_adapter import convert_messages_to_anthropic + from agent.anthropic_message_convert import convert_messages_to_anthropic fake_png = "iVBORw0KGgo=" messages = [ @@ -446,7 +446,7 @@ class TestAnthropicAdapterMultimodal: def test_old_screenshots_are_evicted_beyond_max_keep(self): """Image blocks in old tool_results get replaced with placeholders.""" - from agent.anthropic_adapter import convert_messages_to_anthropic + from agent.anthropic_message_convert import convert_messages_to_anthropic fake_png = "iVBORw0KGgo="