Added proper temperature constraints to the model, fixes: https://github.com/BeehiveInnovations/zen-mcp-server/issues/78
Prompt tweaks
This commit is contained in:
@@ -100,6 +100,26 @@ class DiscreteTemperatureConstraint(TemperatureConstraint):
|
||||
return self.default_temp
|
||||
|
||||
|
||||
def create_temperature_constraint(constraint_type: str) -> TemperatureConstraint:
|
||||
"""Create temperature constraint object from configuration string.
|
||||
|
||||
Args:
|
||||
constraint_type: Type of constraint ("fixed", "range", "discrete")
|
||||
|
||||
Returns:
|
||||
TemperatureConstraint object based on configuration
|
||||
"""
|
||||
if constraint_type == "fixed":
|
||||
# Fixed temperature models (O3/O4) only support temperature=1.0
|
||||
return FixedTemperatureConstraint(1.0)
|
||||
elif constraint_type == "discrete":
|
||||
# For models with specific allowed values - using common OpenAI values as default
|
||||
return DiscreteTemperatureConstraint([0.0, 0.3, 0.7, 1.0, 1.5, 2.0], 0.7)
|
||||
else:
|
||||
# Default range constraint (for "range" or None)
|
||||
return RangeTemperatureConstraint(0.0, 2.0, 0.7)
|
||||
|
||||
|
||||
@dataclass
|
||||
class ModelCapabilities:
|
||||
"""Capabilities and constraints for a specific model."""
|
||||
@@ -114,6 +134,7 @@ class ModelCapabilities:
|
||||
supports_function_calling: bool = False
|
||||
supports_images: bool = False # Whether model can process images
|
||||
max_image_size_mb: float = 0.0 # Maximum total size for all images in MB
|
||||
supports_temperature: bool = True # Whether model accepts temperature parameter in API calls
|
||||
|
||||
# Temperature constraint object - preferred way to define temperature limits
|
||||
temperature_constraint: TemperatureConstraint = field(
|
||||
@@ -245,3 +266,17 @@ class ModelProvider(ABC):
|
||||
List of all model names and alias targets known by this provider
|
||||
"""
|
||||
pass
|
||||
|
||||
def _resolve_model_name(self, model_name: str) -> str:
|
||||
"""Resolve model shorthand to full name.
|
||||
|
||||
Base implementation returns the model name unchanged.
|
||||
Subclasses should override to provide alias resolution.
|
||||
|
||||
Args:
|
||||
model_name: Model name that may be an alias
|
||||
|
||||
Returns:
|
||||
Resolved model name
|
||||
"""
|
||||
return model_name
|
||||
|
||||
@@ -162,6 +162,7 @@ class CustomProvider(OpenAICompatibleProvider):
|
||||
supports_system_prompts=True,
|
||||
supports_streaming=True,
|
||||
supports_function_calling=False, # Conservative default
|
||||
supports_temperature=True, # Most custom models accept temperature parameter
|
||||
temperature_constraint=RangeTemperatureConstraint(0.0, 2.0, 0.7),
|
||||
)
|
||||
|
||||
|
||||
@@ -94,6 +94,7 @@ class GeminiModelProvider(ModelProvider):
|
||||
supports_function_calling=True,
|
||||
supports_images=config.get("supports_images", False),
|
||||
max_image_size_mb=config.get("max_image_size_mb", 0.0),
|
||||
supports_temperature=True, # Gemini models accept temperature parameter
|
||||
temperature_constraint=temp_constraint,
|
||||
)
|
||||
|
||||
|
||||
@@ -448,23 +448,41 @@ class OpenAICompatibleProvider(ModelProvider):
|
||||
completion_params = {
|
||||
"model": model_name,
|
||||
"messages": messages,
|
||||
"temperature": temperature,
|
||||
}
|
||||
|
||||
# Add max tokens if specified
|
||||
if max_output_tokens:
|
||||
# Check model capabilities once to determine parameter support
|
||||
resolved_model = self._resolve_model_name(model_name)
|
||||
|
||||
# Get model capabilities once to avoid duplicate calls
|
||||
try:
|
||||
capabilities = self.get_capabilities(model_name)
|
||||
# Defensive check for supports_temperature field (backward compatibility)
|
||||
supports_temperature = getattr(capabilities, "supports_temperature", True)
|
||||
except Exception as e:
|
||||
# If capability check fails, fall back to conservative behavior
|
||||
# Default to including temperature for most models (backward compatibility)
|
||||
logging.debug(f"Failed to check temperature support for {model_name}: {e}")
|
||||
supports_temperature = True
|
||||
|
||||
# Add temperature parameter if supported
|
||||
if supports_temperature:
|
||||
completion_params["temperature"] = temperature
|
||||
|
||||
# Add max tokens if specified and model supports it
|
||||
# O3/O4 models that don't support temperature also don't support max_tokens
|
||||
if max_output_tokens and supports_temperature:
|
||||
completion_params["max_tokens"] = max_output_tokens
|
||||
|
||||
# Add any additional OpenAI-specific parameters
|
||||
# Use capabilities to filter parameters for reasoning models
|
||||
for key, value in kwargs.items():
|
||||
if key in ["top_p", "frequency_penalty", "presence_penalty", "seed", "stop", "stream"]:
|
||||
# Reasoning models (those that don't support temperature) also don't support these parameters
|
||||
if not supports_temperature and key in ["top_p", "frequency_penalty", "presence_penalty"]:
|
||||
continue # Skip unsupported parameters for reasoning models
|
||||
completion_params[key] = value
|
||||
|
||||
# Check if this is o3-pro and needs the responses endpoint
|
||||
resolved_model = model_name
|
||||
if hasattr(self, "_resolve_model_name"):
|
||||
resolved_model = self._resolve_model_name(model_name)
|
||||
|
||||
if resolved_model == "o3-pro-2025-06-10":
|
||||
# This model requires the /v1/responses endpoint
|
||||
# If it fails, we should not fall back to chat/completions
|
||||
|
||||
@@ -4,11 +4,10 @@ import logging
|
||||
from typing import Optional
|
||||
|
||||
from .base import (
|
||||
FixedTemperatureConstraint,
|
||||
ModelCapabilities,
|
||||
ModelResponse,
|
||||
ProviderType,
|
||||
RangeTemperatureConstraint,
|
||||
create_temperature_constraint,
|
||||
)
|
||||
from .openai_compatible import OpenAICompatibleProvider
|
||||
|
||||
@@ -25,18 +24,24 @@ class OpenAIModelProvider(OpenAICompatibleProvider):
|
||||
"supports_extended_thinking": False,
|
||||
"supports_images": True, # O3 models support vision
|
||||
"max_image_size_mb": 20.0, # 20MB per OpenAI docs
|
||||
"supports_temperature": False, # O3 models don't accept temperature parameter
|
||||
"temperature_constraint": "fixed", # Fixed at 1.0
|
||||
},
|
||||
"o3-mini": {
|
||||
"context_window": 200_000, # 200K tokens
|
||||
"supports_extended_thinking": False,
|
||||
"supports_images": True, # O3 models support vision
|
||||
"max_image_size_mb": 20.0, # 20MB per OpenAI docs
|
||||
"supports_temperature": False, # O3 models don't accept temperature parameter
|
||||
"temperature_constraint": "fixed", # Fixed at 1.0
|
||||
},
|
||||
"o3-pro-2025-06-10": {
|
||||
"context_window": 200_000, # 200K tokens
|
||||
"supports_extended_thinking": False,
|
||||
"supports_images": True, # O3 models support vision
|
||||
"max_image_size_mb": 20.0, # 20MB per OpenAI docs
|
||||
"supports_temperature": False, # O3 models don't accept temperature parameter
|
||||
"temperature_constraint": "fixed", # Fixed at 1.0
|
||||
},
|
||||
# Aliases
|
||||
"o3-pro": "o3-pro-2025-06-10",
|
||||
@@ -45,18 +50,24 @@ class OpenAIModelProvider(OpenAICompatibleProvider):
|
||||
"supports_extended_thinking": False,
|
||||
"supports_images": True, # O4 models support vision
|
||||
"max_image_size_mb": 20.0, # 20MB per OpenAI docs
|
||||
"supports_temperature": False, # O4 models don't accept temperature parameter
|
||||
"temperature_constraint": "fixed", # Fixed at 1.0
|
||||
},
|
||||
"o4-mini-high": {
|
||||
"context_window": 200_000, # 200K tokens
|
||||
"supports_extended_thinking": False,
|
||||
"supports_images": True, # O4 models support vision
|
||||
"max_image_size_mb": 20.0, # 20MB per OpenAI docs
|
||||
"supports_temperature": False, # O4 models don't accept temperature parameter
|
||||
"temperature_constraint": "fixed", # Fixed at 1.0
|
||||
},
|
||||
"gpt-4.1-2025-04-14": {
|
||||
"context_window": 1_000_000, # 1M tokens
|
||||
"supports_extended_thinking": False,
|
||||
"supports_images": True, # GPT-4.1 supports vision
|
||||
"max_image_size_mb": 20.0, # 20MB per OpenAI docs
|
||||
"supports_temperature": True, # Regular models accept temperature parameter
|
||||
"temperature_constraint": "range", # 0.0-2.0 range
|
||||
},
|
||||
# Shorthands
|
||||
"mini": "o4-mini", # Default 'mini' to latest mini model
|
||||
@@ -90,13 +101,10 @@ class OpenAIModelProvider(OpenAICompatibleProvider):
|
||||
|
||||
config = self.SUPPORTED_MODELS[resolved_name]
|
||||
|
||||
# Define temperature constraints per model
|
||||
if resolved_name in ["o3", "o3-mini", "o3-pro", "o3-pro-2025-06-10", "o4-mini", "o4-mini-high"]:
|
||||
# O3 and O4 reasoning models only support temperature=1.0
|
||||
temp_constraint = FixedTemperatureConstraint(1.0)
|
||||
else:
|
||||
# Other OpenAI models (including GPT-4.1) support 0.0-2.0 range
|
||||
temp_constraint = RangeTemperatureConstraint(0.0, 2.0, 0.7)
|
||||
# Get temperature constraints and support from configuration
|
||||
supports_temperature = config.get("supports_temperature", True) # Default to True for backward compatibility
|
||||
temp_constraint_type = config.get("temperature_constraint", "range") # Default to range
|
||||
temp_constraint = create_temperature_constraint(temp_constraint_type)
|
||||
|
||||
return ModelCapabilities(
|
||||
provider=ProviderType.OPENAI,
|
||||
@@ -109,6 +117,7 @@ class OpenAIModelProvider(OpenAICompatibleProvider):
|
||||
supports_function_calling=True,
|
||||
supports_images=config.get("supports_images", False),
|
||||
max_image_size_mb=config.get("max_image_size_mb", 0.0),
|
||||
supports_temperature=supports_temperature,
|
||||
temperature_constraint=temp_constraint,
|
||||
)
|
||||
|
||||
|
||||
@@ -8,7 +8,12 @@ from typing import Optional
|
||||
|
||||
from utils.file_utils import read_json_file
|
||||
|
||||
from .base import ModelCapabilities, ProviderType, RangeTemperatureConstraint
|
||||
from .base import (
|
||||
ModelCapabilities,
|
||||
ProviderType,
|
||||
TemperatureConstraint,
|
||||
create_temperature_constraint,
|
||||
)
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -25,9 +30,21 @@ class OpenRouterModelConfig:
|
||||
supports_json_mode: bool = False
|
||||
supports_images: bool = False # Whether model can process images
|
||||
max_image_size_mb: float = 0.0 # Maximum total size for all images in MB
|
||||
supports_temperature: bool = True # Whether model accepts temperature parameter in API calls
|
||||
temperature_constraint: Optional[str] = (
|
||||
None # Type of temperature constraint: "fixed", "range", "discrete", or None for default range
|
||||
)
|
||||
is_custom: bool = False # True for models that should only be used with custom endpoints
|
||||
description: str = ""
|
||||
|
||||
def _create_temperature_constraint(self) -> TemperatureConstraint:
|
||||
"""Create temperature constraint object from configuration.
|
||||
|
||||
Returns:
|
||||
TemperatureConstraint object based on configuration
|
||||
"""
|
||||
return create_temperature_constraint(self.temperature_constraint or "range")
|
||||
|
||||
def to_capabilities(self) -> ModelCapabilities:
|
||||
"""Convert to ModelCapabilities object."""
|
||||
return ModelCapabilities(
|
||||
@@ -41,7 +58,8 @@ class OpenRouterModelConfig:
|
||||
supports_function_calling=self.supports_function_calling,
|
||||
supports_images=self.supports_images,
|
||||
max_image_size_mb=self.max_image_size_mb,
|
||||
temperature_constraint=RangeTemperatureConstraint(0.0, 2.0, 1.0),
|
||||
supports_temperature=self.supports_temperature,
|
||||
temperature_constraint=self._create_temperature_constraint(),
|
||||
)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user