feat!: breaking change - OpenRouter models are now read from conf/openrouter_models.json while Custom / Self-hosted models are read from conf/custom_models.json
feat: Azure OpenAI / Azure AI Foundry support. Models should be defined in conf/azure_models.json (or a custom path). See .env.example for environment variables or see readme. https://github.com/BeehiveInnovations/zen-mcp-server/issues/265 feat: OpenRouter / Custom Models / Azure can separately also use custom config paths now (see .env.example ) refactor: Model registry class made abstract, OpenRouter / Custom Provider / Azure OpenAI now subclass these refactor: breaking change: `is_custom` property has been removed from model_capabilities.py (and thus custom_models.json) given each models are now read from separate configuration files
This commit is contained in:
@@ -8,7 +8,7 @@ from urllib.parse import urlparse
|
||||
|
||||
from openai import OpenAI
|
||||
|
||||
from utils.env import get_env
|
||||
from utils.env import get_env, suppress_env_vars
|
||||
from utils.image_utils import validate_image
|
||||
|
||||
from .base import ModelProvider
|
||||
@@ -257,80 +257,74 @@ class OpenAICompatibleProvider(ModelProvider):
|
||||
def client(self):
|
||||
"""Lazy initialization of OpenAI client with security checks and timeout configuration."""
|
||||
if self._client is None:
|
||||
import os
|
||||
|
||||
import httpx
|
||||
|
||||
# Temporarily disable proxy environment variables to prevent httpx from detecting them
|
||||
original_env = {}
|
||||
proxy_env_vars = ["HTTP_PROXY", "HTTPS_PROXY", "ALL_PROXY", "http_proxy", "https_proxy", "all_proxy"]
|
||||
|
||||
for var in proxy_env_vars:
|
||||
if var in os.environ:
|
||||
original_env[var] = os.environ[var]
|
||||
del os.environ[var]
|
||||
|
||||
try:
|
||||
# Create a custom httpx client that explicitly avoids proxy parameters
|
||||
timeout_config = (
|
||||
self.timeout_config
|
||||
if hasattr(self, "timeout_config") and self.timeout_config
|
||||
else httpx.Timeout(30.0)
|
||||
)
|
||||
|
||||
# Create httpx client with minimal config to avoid proxy conflicts
|
||||
# Note: proxies parameter was removed in httpx 0.28.0
|
||||
# Check for test transport injection
|
||||
if hasattr(self, "_test_transport"):
|
||||
# Use custom transport for testing (HTTP recording/replay)
|
||||
http_client = httpx.Client(
|
||||
transport=self._test_transport,
|
||||
timeout=timeout_config,
|
||||
follow_redirects=True,
|
||||
)
|
||||
else:
|
||||
# Normal production client
|
||||
http_client = httpx.Client(
|
||||
timeout=timeout_config,
|
||||
follow_redirects=True,
|
||||
)
|
||||
|
||||
# Keep client initialization minimal to avoid proxy parameter conflicts
|
||||
client_kwargs = {
|
||||
"api_key": self.api_key,
|
||||
"http_client": http_client,
|
||||
}
|
||||
|
||||
if self.base_url:
|
||||
client_kwargs["base_url"] = self.base_url
|
||||
|
||||
if self.organization:
|
||||
client_kwargs["organization"] = self.organization
|
||||
|
||||
# Add default headers if any
|
||||
if self.DEFAULT_HEADERS:
|
||||
client_kwargs["default_headers"] = self.DEFAULT_HEADERS.copy()
|
||||
|
||||
logging.debug(f"OpenAI client initialized with custom httpx client and timeout: {timeout_config}")
|
||||
|
||||
# Create OpenAI client with custom httpx client
|
||||
self._client = OpenAI(**client_kwargs)
|
||||
|
||||
except Exception as e:
|
||||
# If all else fails, try absolute minimal client without custom httpx
|
||||
logging.warning(f"Failed to create client with custom httpx, falling back to minimal config: {e}")
|
||||
with suppress_env_vars(*proxy_env_vars):
|
||||
try:
|
||||
minimal_kwargs = {"api_key": self.api_key}
|
||||
# Create a custom httpx client that explicitly avoids proxy parameters
|
||||
timeout_config = (
|
||||
self.timeout_config
|
||||
if hasattr(self, "timeout_config") and self.timeout_config
|
||||
else httpx.Timeout(30.0)
|
||||
)
|
||||
|
||||
# Create httpx client with minimal config to avoid proxy conflicts
|
||||
# Note: proxies parameter was removed in httpx 0.28.0
|
||||
# Check for test transport injection
|
||||
if hasattr(self, "_test_transport"):
|
||||
# Use custom transport for testing (HTTP recording/replay)
|
||||
http_client = httpx.Client(
|
||||
transport=self._test_transport,
|
||||
timeout=timeout_config,
|
||||
follow_redirects=True,
|
||||
)
|
||||
else:
|
||||
# Normal production client
|
||||
http_client = httpx.Client(
|
||||
timeout=timeout_config,
|
||||
follow_redirects=True,
|
||||
)
|
||||
|
||||
# Keep client initialization minimal to avoid proxy parameter conflicts
|
||||
client_kwargs = {
|
||||
"api_key": self.api_key,
|
||||
"http_client": http_client,
|
||||
}
|
||||
|
||||
if self.base_url:
|
||||
minimal_kwargs["base_url"] = self.base_url
|
||||
self._client = OpenAI(**minimal_kwargs)
|
||||
except Exception as fallback_error:
|
||||
logging.error(f"Even minimal OpenAI client creation failed: {fallback_error}")
|
||||
raise
|
||||
finally:
|
||||
# Restore original proxy environment variables
|
||||
for var, value in original_env.items():
|
||||
os.environ[var] = value
|
||||
client_kwargs["base_url"] = self.base_url
|
||||
|
||||
if self.organization:
|
||||
client_kwargs["organization"] = self.organization
|
||||
|
||||
# Add default headers if any
|
||||
if self.DEFAULT_HEADERS:
|
||||
client_kwargs["default_headers"] = self.DEFAULT_HEADERS.copy()
|
||||
|
||||
logging.debug(
|
||||
"OpenAI client initialized with custom httpx client and timeout: %s",
|
||||
timeout_config,
|
||||
)
|
||||
|
||||
# Create OpenAI client with custom httpx client
|
||||
self._client = OpenAI(**client_kwargs)
|
||||
|
||||
except Exception as e:
|
||||
# If all else fails, try absolute minimal client without custom httpx
|
||||
logging.warning(
|
||||
"Failed to create client with custom httpx, falling back to minimal config: %s",
|
||||
e,
|
||||
)
|
||||
try:
|
||||
minimal_kwargs = {"api_key": self.api_key}
|
||||
if self.base_url:
|
||||
minimal_kwargs["base_url"] = self.base_url
|
||||
self._client = OpenAI(**minimal_kwargs)
|
||||
except Exception as fallback_error:
|
||||
logging.error("Even minimal OpenAI client creation failed: %s", fallback_error)
|
||||
raise
|
||||
|
||||
return self._client
|
||||
|
||||
|
||||
Reference in New Issue
Block a user