Skip to content

Commit 360e1a5

Browse files
Fix
1 parent 83d6f6a commit 360e1a5

2 files changed

Lines changed: 39 additions & 3 deletions

File tree

code_puppy/model_factory.py

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
from pydantic_ai.providers.openai import OpenAIProvider
1515
from pydantic_ai.providers.openrouter import OpenRouterProvider
1616

17+
from code_puppy.tools.common import console
18+
1719
# Environment variables used in this module:
1820
# - GEMINI_API_KEY: API key for Google's Gemini models. Required when using Gemini models.
1921
# - OPENAI_API_KEY: API key for OpenAI models. Required when using OpenAI models or custom_openai endpoints.
@@ -46,6 +48,9 @@ def build_httpx_proxy(proxy):
4648
proxy_url = f"http://{ip}:{port}"
4749
proxy_auth = (username, password)
4850

51+
# Log the proxy being used
52+
console.log(f"Using proxy: {proxy_url} with username: {username}")
53+
4954
return httpx.Proxy(url=proxy_url, auth=proxy_auth)
5055

5156

@@ -61,7 +66,11 @@ def get_random_proxy_from_file(file_path):
6166
raise ValueError(f"Proxy file '{file_path}' is empty or contains only whitespace.")
6267

6368
selected_proxy = random.choice(proxies)
64-
return build_httpx_proxy(selected_proxy)
69+
try:
70+
return build_httpx_proxy(selected_proxy)
71+
except ValueError as e:
72+
console.log(f"Warning: Malformed proxy '{selected_proxy}' found in file '{file_path}', ignoring and continuing without proxy.")
73+
return None
6574

6675

6776
def get_custom_config(model_config):
@@ -145,7 +154,11 @@ def get_model(model_name: str, config: Dict[str, Any]) -> Any:
145154
if proxy_file_path:
146155
proxy = get_random_proxy_from_file(proxy_file_path)
147156

148-
client = httpx.AsyncClient(headers=headers, verify=ca_certs_path, proxy=proxy)
157+
# Only pass proxy to client if it's valid
158+
client_args = {"headers": headers, "verify": ca_certs_path}
159+
if proxy is not None:
160+
client_args["proxy"] = proxy
161+
client = httpx.AsyncClient(**client_args)
149162
anthropic_client = AsyncAnthropic(
150163
base_url=url,
151164
http_client=client,
@@ -217,7 +230,11 @@ def get_model(model_name: str, config: Dict[str, Any]) -> Any:
217230
if proxy_file_path:
218231
proxy = get_random_proxy_from_file(proxy_file_path)
219232

220-
client = httpx.AsyncClient(headers=headers, verify=ca_certs_path, proxy=proxy)
233+
# Only pass proxy to client if it's valid
234+
client_args = {"headers": headers, "verify": ca_certs_path}
235+
if proxy is not None:
236+
client_args["proxy"] = proxy
237+
client = httpx.AsyncClient(**client_args)
221238
provider_args = dict(
222239
base_url=url,
223240
http_client=client,

tests/test_model_factory.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,3 +182,22 @@ def test_custom_anthropic_missing_url():
182182
}
183183
with pytest.raises(ValueError):
184184
ModelFactory.get_model("x", config)
185+
186+
187+
def test_get_random_proxy_from_file_with_malformed_proxy(monkeypatch, tmp_path):
188+
from code_puppy.model_factory import get_random_proxy_from_file
189+
190+
# Create a proxy file with both valid and malformed proxies
191+
proxy_file = tmp_path / "proxies.txt"
192+
proxy_file.write_text("192.168.1.1:8080:user:pass\nmalformed_proxy_without_correct_format\n10.0.0.1:3128:admin:secret")
193+
194+
# Mock console.log to avoid printing warnings during test
195+
monkeypatch.setattr("code_puppy.model_factory.console.log", lambda x: None)
196+
197+
# Should return None for malformed proxy instead of raising ValueError
198+
proxy = get_random_proxy_from_file(str(proxy_file))
199+
# Either a valid proxy object or None (if the malformed one was selected)
200+
# We're fine with either outcome as long as no ValueError is raised
201+
202+
# If we get here without exception, the test passes
203+
assert proxy is None or hasattr(proxy, 'url')

0 commit comments

Comments
 (0)