Compare commits
1 Commits
feat/error
...
fix/empty-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
24f49ad23b |
@@ -5347,6 +5347,15 @@ class AIAgent:
|
||||
|
||||
def _build_api_kwargs(self, api_messages: list) -> dict:
|
||||
"""Build the keyword arguments dict for the active API mode."""
|
||||
# Preflight: model must be non-empty. An empty model string reaches
|
||||
# the provider as model="" and returns HTTP 400 after 3 retries.
|
||||
# Better to fail immediately with a clear message.
|
||||
if not self.model or not self.model.strip():
|
||||
raise ValueError(
|
||||
"No model specified. Set the model via AIAgent(model=...), "
|
||||
"HERMES_MODEL env var, or config.yaml model.default. "
|
||||
f"Current value: {self.model!r}"
|
||||
)
|
||||
if self.api_mode == "anthropic_messages":
|
||||
from agent.anthropic_adapter import build_anthropic_kwargs
|
||||
anthropic_messages = self._prepare_anthropic_messages_for_api(api_messages)
|
||||
|
||||
61
tests/run_agent/test_empty_model_preflight.py
Normal file
61
tests/run_agent/test_empty_model_preflight.py
Normal file
@@ -0,0 +1,61 @@
|
||||
"""Tests for empty model preflight check in _build_api_kwargs (related to #328)."""
|
||||
|
||||
import pytest
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
|
||||
class TestEmptyModelPreflight:
|
||||
"""Verify that _build_api_kwargs rejects empty model strings."""
|
||||
|
||||
def _make_agent(self, model=""):
|
||||
"""Create a minimal AIAgent with _build_api_kwargs callable."""
|
||||
from run_agent import AIAgent
|
||||
agent = AIAgent.__new__(AIAgent)
|
||||
agent.model = model
|
||||
agent.api_mode = "openai"
|
||||
agent.tools = None
|
||||
agent.tool_choice = None
|
||||
agent.max_tokens = None
|
||||
agent.reasoning_config = None
|
||||
agent._is_openrouter_url = lambda: False
|
||||
agent._use_prompt_caching = False
|
||||
agent._client_kwargs = {}
|
||||
agent.provider_data_collection = None
|
||||
agent.providers_allowed = None
|
||||
agent.providers_ignored = None
|
||||
agent.providers_order = None
|
||||
agent.provider_sort = None
|
||||
agent.provider_require_parameters = False
|
||||
return agent
|
||||
|
||||
def test_empty_string_raises(self):
|
||||
agent = self._make_agent(model="")
|
||||
with pytest.raises(ValueError, match="No model specified"):
|
||||
agent._build_api_kwargs([{"role": "user", "content": "hi"}])
|
||||
|
||||
def test_whitespace_only_raises(self):
|
||||
agent = self._make_agent(model=" ")
|
||||
with pytest.raises(ValueError, match="No model specified"):
|
||||
agent._build_api_kwargs([{"role": "user", "content": "hi"}])
|
||||
|
||||
def test_none_raises(self):
|
||||
agent = self._make_agent(model=None)
|
||||
with pytest.raises(ValueError, match="No model specified"):
|
||||
agent._build_api_kwargs([{"role": "user", "content": "hi"}])
|
||||
|
||||
def test_valid_model_passes_preflight(self):
|
||||
"""The preflight check itself should not raise for a valid model.
|
||||
We test only the preflight, not the full _build_api_kwargs, because
|
||||
the full method needs a fully initialized agent."""
|
||||
agent = self._make_agent(model="gpt-4o")
|
||||
# The preflight is the first thing _build_api_kwargs does.
|
||||
# Verify it doesn't raise by checking model directly.
|
||||
assert agent.model and agent.model.strip()
|
||||
# If model is non-empty, the ValueError should NOT be raised.
|
||||
# We can't easily test the full method without mocking more internals,
|
||||
# so we test the inverse: empty model DOES raise (tested above).
|
||||
|
||||
def test_error_message_includes_current_value(self):
|
||||
agent = self._make_agent(model="")
|
||||
with pytest.raises(ValueError, match="Current value: ''"):
|
||||
agent._build_api_kwargs([{"role": "user", "content": "hi"}])
|
||||
Reference in New Issue
Block a user