From 9717bdf431855d738cdaff750e6bcf6be6841466 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 24 Feb 2026 05:20:30 +0000 Subject: [PATCH 1/3] Initial plan From 43f448ff012f64f4a1983dd47d5c13fc463af046 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 24 Feb 2026 05:22:28 +0000 Subject: [PATCH 2/3] fix: use self.model instead of hardcoded deprecated model in validate_api_access Co-authored-by: edhedges <825537+edhedges@users.noreply.github.com> --- claudecode/claude_api_client.py | 2 +- claudecode/test_claude_api_client.py | 43 ++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 claudecode/test_claude_api_client.py diff --git a/claudecode/claude_api_client.py b/claudecode/claude_api_client.py index 19a6d40..c5dab80 100644 --- a/claudecode/claude_api_client.py +++ b/claudecode/claude_api_client.py @@ -59,7 +59,7 @@ def validate_api_access(self) -> Tuple[bool, str]: try: # Simple test call to verify API access self.client.messages.create( - model="claude-3-5-haiku-20241022", + model=self.model, max_tokens=10, messages=[{"role": "user", "content": "Hello"}], timeout=10 diff --git a/claudecode/test_claude_api_client.py b/claudecode/test_claude_api_client.py new file mode 100644 index 0000000..dba748f --- /dev/null +++ b/claudecode/test_claude_api_client.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python3 +""" +Pytest tests for Claude API client. +""" + +from unittest.mock import patch, MagicMock + +from claudecode.claude_api_client import ClaudeAPIClient + + +class TestValidateApiAccess: + """Test validate_api_access uses self.model instead of a hardcoded value.""" + + def test_validate_api_access_uses_instance_model(self): + """Ensure validate_api_access passes self.model to the API call.""" + custom_model = "claude-sonnet-4-20250514" + client = ClaudeAPIClient(model=custom_model, api_key="fake-key") + + mock_response = MagicMock() + with patch.object(client.client.messages, "create", return_value=mock_response) as mock_create: + success, error = client.validate_api_access() + + mock_create.assert_called_once() + call_kwargs = mock_create.call_args[1] + assert call_kwargs["model"] == custom_model, ( + f"Expected model '{custom_model}', got '{call_kwargs['model']}'" + ) + assert success is True + assert error == "" + + def test_validate_api_access_uses_default_model(self): + """Ensure validate_api_access uses DEFAULT_CLAUDE_MODEL when no model is specified.""" + from claudecode.constants import DEFAULT_CLAUDE_MODEL + + client = ClaudeAPIClient(api_key="fake-key") + + mock_response = MagicMock() + with patch.object(client.client.messages, "create", return_value=mock_response) as mock_create: + success, _ = client.validate_api_access() + + call_kwargs = mock_create.call_args[1] + assert call_kwargs["model"] == DEFAULT_CLAUDE_MODEL + assert success is True From d0f6ae415ed9e72141ef4a3d3fe0128a2019b7dc Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 24 Feb 2026 05:26:06 +0000 Subject: [PATCH 3/3] fix: use VALIDATION_MODEL constant (claude-haiku-4-5) for cheap validation pings Co-authored-by: edhedges <825537+edhedges@users.noreply.github.com> --- claudecode/claude_api_client.py | 4 ++-- claudecode/constants.py | 1 + claudecode/test_claude_api_client.py | 23 ++++++++++++----------- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/claudecode/claude_api_client.py b/claudecode/claude_api_client.py index c5dab80..2c6ecfa 100644 --- a/claudecode/claude_api_client.py +++ b/claudecode/claude_api_client.py @@ -10,7 +10,7 @@ from claudecode.constants import ( DEFAULT_CLAUDE_MODEL, DEFAULT_TIMEOUT_SECONDS, DEFAULT_MAX_RETRIES, - RATE_LIMIT_BACKOFF_MAX, PROMPT_TOKEN_LIMIT, + RATE_LIMIT_BACKOFF_MAX, PROMPT_TOKEN_LIMIT, VALIDATION_MODEL, ) from claudecode.json_parser import parse_json_with_fallbacks from claudecode.logger import get_logger @@ -59,7 +59,7 @@ def validate_api_access(self) -> Tuple[bool, str]: try: # Simple test call to verify API access self.client.messages.create( - model=self.model, + model=VALIDATION_MODEL, max_tokens=10, messages=[{"role": "user", "content": "Hello"}], timeout=10 diff --git a/claudecode/constants.py b/claudecode/constants.py index 3a563ed..ca557d7 100644 --- a/claudecode/constants.py +++ b/claudecode/constants.py @@ -6,6 +6,7 @@ # API Configuration DEFAULT_CLAUDE_MODEL = os.environ.get('CLAUDE_MODEL') or 'claude-opus-4-1-20250805' +VALIDATION_MODEL = 'claude-haiku-4-5' DEFAULT_TIMEOUT_SECONDS = 180 # 3 minutes DEFAULT_MAX_RETRIES = 3 RATE_LIMIT_BACKOFF_MAX = 30 # Maximum backoff time for rate limits diff --git a/claudecode/test_claude_api_client.py b/claudecode/test_claude_api_client.py index dba748f..b4d5b75 100644 --- a/claudecode/test_claude_api_client.py +++ b/claudecode/test_claude_api_client.py @@ -6,13 +6,14 @@ from unittest.mock import patch, MagicMock from claudecode.claude_api_client import ClaudeAPIClient +from claudecode.constants import VALIDATION_MODEL class TestValidateApiAccess: - """Test validate_api_access uses self.model instead of a hardcoded value.""" + """Test validate_api_access uses VALIDATION_MODEL for cheap validation pings.""" - def test_validate_api_access_uses_instance_model(self): - """Ensure validate_api_access passes self.model to the API call.""" + def test_validate_api_access_uses_validation_model(self): + """Ensure validate_api_access uses VALIDATION_MODEL, not self.model.""" custom_model = "claude-sonnet-4-20250514" client = ClaudeAPIClient(model=custom_model, api_key="fake-key") @@ -22,22 +23,22 @@ def test_validate_api_access_uses_instance_model(self): mock_create.assert_called_once() call_kwargs = mock_create.call_args[1] - assert call_kwargs["model"] == custom_model, ( - f"Expected model '{custom_model}', got '{call_kwargs['model']}'" + assert call_kwargs["model"] == VALIDATION_MODEL, ( + f"Expected VALIDATION_MODEL '{VALIDATION_MODEL}', got '{call_kwargs['model']}'" ) assert success is True assert error == "" - def test_validate_api_access_uses_default_model(self): - """Ensure validate_api_access uses DEFAULT_CLAUDE_MODEL when no model is specified.""" - from claudecode.constants import DEFAULT_CLAUDE_MODEL - - client = ClaudeAPIClient(api_key="fake-key") + def test_validate_api_access_does_not_use_instance_model(self): + """Ensure validate_api_access does not pass self.model (expensive) to the validation call.""" + expensive_model = "claude-opus-4-1-20250805" + client = ClaudeAPIClient(model=expensive_model, api_key="fake-key") mock_response = MagicMock() with patch.object(client.client.messages, "create", return_value=mock_response) as mock_create: success, _ = client.validate_api_access() call_kwargs = mock_create.call_args[1] - assert call_kwargs["model"] == DEFAULT_CLAUDE_MODEL + assert call_kwargs["model"] == VALIDATION_MODEL + assert call_kwargs["model"] != expensive_model assert success is True