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:
|
def _build_api_kwargs(self, api_messages: list) -> dict:
|
||||||
"""Build the keyword arguments dict for the active API mode."""
|
"""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":
|
if self.api_mode == "anthropic_messages":
|
||||||
from agent.anthropic_adapter import build_anthropic_kwargs
|
from agent.anthropic_adapter import build_anthropic_kwargs
|
||||||
anthropic_messages = self._prepare_anthropic_messages_for_api(api_messages)
|
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