This commit is contained in:
Fahad
2025-06-13 16:05:21 +04:00
parent 6739182c20
commit 048ebf90bf
13 changed files with 46 additions and 26 deletions

View File

@@ -103,9 +103,27 @@
"supports_function_calling": false, "supports_function_calling": false,
"description": "Meta's Llama 3 70B model" "description": "Meta's Llama 3 70B model"
}, },
{
"model_name": "openai/gpt-4o",
"aliases": ["gpt4o", "4o", "gpt-4o"],
"context_window": 128000,
"supports_extended_thinking": false,
"supports_json_mode": true,
"supports_function_calling": true,
"description": "OpenAI's GPT-4o model"
},
{
"model_name": "deepseek/deepseek-coder",
"aliases": ["deepseek-coder", "deepseek", "coder"],
"context_window": 65536,
"supports_extended_thinking": false,
"supports_json_mode": true,
"supports_function_calling": true,
"description": "DeepSeek Coder model for programming tasks"
},
{ {
"model_name": "deepseek/deepseek-r1-0528", "model_name": "deepseek/deepseek-r1-0528",
"aliases": ["deepseek-r1", "deepseek", "r1", "deepseek-thinking"], "aliases": ["deepseek-r1", "r1", "deepseek-thinking"],
"context_window": 65536, "context_window": 65536,
"supports_extended_thinking": true, "supports_extended_thinking": true,
"supports_json_mode": true, "supports_json_mode": true,

View File

@@ -212,9 +212,7 @@ class ModelProvider(ABC):
# Validate temperature # Validate temperature
min_temp, max_temp = capabilities.temperature_range min_temp, max_temp = capabilities.temperature_range
if not min_temp <= temperature <= max_temp: if not min_temp <= temperature <= max_temp:
raise ValueError( raise ValueError(f"Temperature {temperature} out of range [{min_temp}, {max_temp}] for model {model_name}")
f"Temperature {temperature} out of range [{min_temp}, {max_temp}] " f"for model {model_name}"
)
@abstractmethod @abstractmethod
def supports_thinking_mode(self, model_name: str) -> bool: def supports_thinking_mode(self, model_name: str) -> bool:

View File

@@ -246,9 +246,7 @@ class OpenAICompatibleProvider(ModelProvider):
""" """
# Validate model name against allow-list # Validate model name against allow-list
if not self.validate_model_name(model_name): if not self.validate_model_name(model_name):
raise ValueError( raise ValueError(f"Model '{model_name}' not in allowed models list. Allowed models: {self.allowed_models}")
f"Model '{model_name}' not in allowed models list. " f"Allowed models: {self.allowed_models}"
)
# Validate parameters # Validate parameters
self.validate_parameters(model_name, temperature) self.validate_parameters(model_name, temperature)
@@ -367,7 +365,7 @@ class OpenAICompatibleProvider(ModelProvider):
# Check if we're using generic capabilities # Check if we're using generic capabilities
if hasattr(capabilities, "_is_generic"): if hasattr(capabilities, "_is_generic"):
logging.debug( logging.debug(
f"Using generic parameter validation for {model_name}. " "Actual model constraints may differ." f"Using generic parameter validation for {model_name}. Actual model constraints may differ."
) )
# Validate temperature using parent class method # Validate temperature using parent class method

View File

@@ -154,7 +154,7 @@ class OpenRouterModelRegistry:
if alias_lower in alias_map: if alias_lower in alias_map:
existing_model = alias_map[alias_lower] existing_model = alias_map[alias_lower]
raise ValueError( raise ValueError(
f"Duplicate alias '{alias}' found for models " f"'{existing_model}' and '{config.model_name}'" f"Duplicate alias '{alias}' found for models '{existing_model}' and '{config.model_name}'"
) )
alias_map[alias_lower] = config.model_name alias_map[alias_lower] = config.model_name

View File

@@ -138,7 +138,11 @@ class Calculator:
# Execute the command # Execute the command
result = subprocess.run( result = subprocess.run(
docker_cmd, input=input_data, text=True, capture_output=True, timeout=3600 # 1 hour timeout docker_cmd,
input=input_data,
text=True,
capture_output=True,
timeout=3600, # 1 hour timeout
) )
if result.returncode != 0: if result.returncode != 0:

View File

@@ -284,7 +284,7 @@ I'd be happy to examine the error handling patterns in more detail if that would
turns = [ turns = [
ConversationTurn( ConversationTurn(
role="assistant" if i % 2 else "user", role="assistant" if i % 2 else "user",
content=f"Turn {i+1}", content=f"Turn {i + 1}",
timestamp="2023-01-01T00:00:00Z", timestamp="2023-01-01T00:00:00Z",
tool_name="test_continuation", tool_name="test_continuation",
) )

View File

@@ -246,9 +246,9 @@ class TestCollaborationWorkflow:
) )
response = json.loads(result[0].text) response = json.loads(result[0].text)
assert ( assert response["status"] == "requires_clarification", (
response["status"] == "requires_clarification" "Should request clarification when asked about dependencies without package files"
), "Should request clarification when asked about dependencies without package files" )
clarification = json.loads(response["content"]) clarification = json.loads(response["content"])
assert "package.json" in str(clarification["files_needed"]), "Should specifically request package.json" assert "package.json" in str(clarification["files_needed"]), "Should specifically request package.json"

View File

@@ -95,7 +95,9 @@ class TestCustomProvider:
# Call with an alias # Call with an alias
result = provider.generate_content( result = provider.generate_content(
prompt="test prompt", model_name="llama", temperature=0.7 # This is an alias prompt="test prompt",
model_name="llama",
temperature=0.7, # This is an alias
) )
# Verify parent method was called with resolved model name # Verify parent method was called with resolved model name

View File

@@ -76,7 +76,6 @@ class TestIntelligentFallback:
patch("config.DEFAULT_MODEL", "auto"), patch("config.DEFAULT_MODEL", "auto"),
patch.dict(os.environ, {"OPENAI_API_KEY": "sk-test-key", "GEMINI_API_KEY": ""}, clear=False), patch.dict(os.environ, {"OPENAI_API_KEY": "sk-test-key", "GEMINI_API_KEY": ""}, clear=False),
): ):
ModelProviderRegistry.clear_cache() ModelProviderRegistry.clear_cache()
# Create a context with at least one turn so it doesn't exit early # Create a context with at least one turn so it doesn't exit early
@@ -115,7 +114,6 @@ class TestIntelligentFallback:
patch("config.DEFAULT_MODEL", "auto"), patch("config.DEFAULT_MODEL", "auto"),
patch.dict(os.environ, {"OPENAI_API_KEY": "", "GEMINI_API_KEY": "test-key"}, clear=False), patch.dict(os.environ, {"OPENAI_API_KEY": "", "GEMINI_API_KEY": "test-key"}, clear=False),
): ):
ModelProviderRegistry.clear_cache() ModelProviderRegistry.clear_cache()
from utils.conversation_memory import ConversationTurn from utils.conversation_memory import ConversationTurn
@@ -148,7 +146,6 @@ class TestIntelligentFallback:
from utils.conversation_memory import ThreadContext, build_conversation_history from utils.conversation_memory import ThreadContext, build_conversation_history
with patch("config.IS_AUTO_MODE", False), patch("config.DEFAULT_MODEL", "gemini-2.5-pro-preview-06-05"): with patch("config.IS_AUTO_MODE", False), patch("config.DEFAULT_MODEL", "gemini-2.5-pro-preview-06-05"):
from utils.conversation_memory import ConversationTurn from utils.conversation_memory import ConversationTurn
context = ThreadContext( context = ThreadContext(

View File

@@ -233,7 +233,11 @@ TEMPERATURE_ANALYTICAL = 0.2 # For code review, debugging
# Test the centralized file preparation method directly # Test the centralized file preparation method directly
file_content = tool._prepare_file_content_for_prompt( file_content = tool._prepare_file_content_for_prompt(
[config_path], None, "Test files", max_tokens=100000, reserve_tokens=1000 # No continuation [config_path],
None,
"Test files",
max_tokens=100000,
reserve_tokens=1000, # No continuation
) )
# Should contain file markers # Should contain file markers

View File

@@ -34,9 +34,9 @@ class TestThinkingModes:
] ]
for tool, expected_default in tools: for tool, expected_default in tools:
assert ( assert tool.get_default_thinking_mode() == expected_default, (
tool.get_default_thinking_mode() == expected_default f"{tool.__class__.__name__} should default to {expected_default}"
), f"{tool.__class__.__name__} should default to {expected_default}" )
@pytest.mark.asyncio @pytest.mark.asyncio
@patch("tools.base.BaseTool.get_model_provider") @patch("tools.base.BaseTool.get_model_provider")

View File

@@ -58,8 +58,7 @@ class ToolRequest(BaseModel):
thinking_mode: Optional[Literal["minimal", "low", "medium", "high", "max"]] = Field( thinking_mode: Optional[Literal["minimal", "low", "medium", "high", "max"]] = Field(
None, None,
description=( description=(
"Thinking depth: minimal (0.5% of model max), low (8%), medium (33%), high (67%), " "Thinking depth: minimal (0.5% of model max), low (8%), medium (33%), high (67%), max (100% of model max)"
"max (100% of model max)"
), ),
) )
use_websearch: Optional[bool] = Field( use_websearch: Optional[bool] = Field(

View File

@@ -372,7 +372,7 @@ def get_conversation_file_list(context: ThreadContext) -> list[str]:
for i, turn in enumerate(context.turns): for i, turn in enumerate(context.turns):
if turn.files: if turn.files:
logger.debug(f"[FILES] Turn {i+1} has {len(turn.files)} files: {turn.files}") logger.debug(f"[FILES] Turn {i + 1} has {len(turn.files)} files: {turn.files}")
for file_path in turn.files: for file_path in turn.files:
if file_path not in seen_files: if file_path not in seen_files:
seen_files.add(file_path) seen_files.add(file_path)
@@ -381,7 +381,7 @@ def get_conversation_file_list(context: ThreadContext) -> list[str]:
else: else:
logger.debug(f"[FILES] Duplicate file skipped: {file_path}") logger.debug(f"[FILES] Duplicate file skipped: {file_path}")
else: else:
logger.debug(f"[FILES] Turn {i+1} has no files") logger.debug(f"[FILES] Turn {i + 1} has no files")
logger.debug(f"[FILES] Final unique file list ({len(unique_files)}): {unique_files}") logger.debug(f"[FILES] Final unique file list ({len(unique_files)}): {unique_files}")
return unique_files return unique_files