mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-20 15:33:54 +00:00
refactor(agent): treat unknown Solar models as reasoning-capable
Invert the reasoning-support check from an allow-list (solar-pro, solar-open) to a deny-list of the known non-reasoning families (solar-mini, syn-pro). Newly released Solar models now get reasoning_effort by default instead of having it silently dropped. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
20502b407c
commit
0031c5c371
2 changed files with 44 additions and 15 deletions
|
|
@ -6,10 +6,12 @@ from providers import register_provider
|
|||
from providers.base import ProviderProfile
|
||||
|
||||
|
||||
# Model-name markers for Solar families that accept ``reasoning_effort``.
|
||||
# Substring match (not startswith) so dated variants like
|
||||
# ``solar-pro3-250127`` and ``solar-open-...`` are covered too.
|
||||
_REASONING_MODEL_MARKERS = ("solar-pro", "solar-open")
|
||||
# Model-name markers for Solar families that do NOT accept ``reasoning_effort``.
|
||||
# Deny-list on purpose: newly released Solar models are assumed
|
||||
# reasoning-capable by default, so only the known non-reasoning families are
|
||||
# listed here. Substring match (not startswith) so dated variants like
|
||||
# ``solar-mini-250127`` are covered too.
|
||||
_NON_REASONING_MODEL_MARKERS = ("solar-mini", "syn-pro")
|
||||
|
||||
# When the user hasn't picked a reasoning effort, Hermes passes
|
||||
# reasoning_config=None. Solar's own server default is "minimal" (reasoning
|
||||
|
|
@ -22,15 +24,20 @@ _DEFAULT_REASONING_EFFORT = "medium"
|
|||
|
||||
|
||||
def _model_supports_reasoning(model: str | None) -> bool:
|
||||
"""Solar reasoning-capable models.
|
||||
"""Solar reasoning-capable models — True unless the model is deny-listed.
|
||||
|
||||
The Solar Pro family (``solar-pro``, ``solar-pro2``, ``solar-pro3`` and
|
||||
dated variants like ``solar-pro3-250127``) and the Solar Open family
|
||||
(``solar-open*``) accept ``reasoning_effort``. ``solar-mini`` / ``syn-pro``
|
||||
ignore the parameter, so we don't send it.
|
||||
(``solar-open*``) accept ``reasoning_effort``; only ``solar-mini`` /
|
||||
``syn-pro`` ignore the parameter, so we deny-list those and treat every
|
||||
other (incl. future) Solar model as reasoning-capable.
|
||||
|
||||
``None``/empty model → True: the provider default (``fallback_models[0]``,
|
||||
the ``solar-pro`` rolling alias) is reasoning-capable, so an unset model
|
||||
gets the same default-on behaviour.
|
||||
"""
|
||||
m = (model or "").strip().lower()
|
||||
return any(marker in m for marker in _REASONING_MODEL_MARKERS)
|
||||
return not any(marker in m for marker in _NON_REASONING_MODEL_MARKERS)
|
||||
|
||||
|
||||
class UpstageProfile(ProviderProfile):
|
||||
|
|
@ -54,7 +61,8 @@ class UpstageProfile(ProviderProfile):
|
|||
) -> tuple[dict[str, Any], dict[str, Any]]:
|
||||
top_level: dict[str, Any] = {}
|
||||
|
||||
# solar-mini / syn-pro ignore reasoning_effort — send nothing.
|
||||
# solar-mini / syn-pro (the deny-list) ignore reasoning_effort — send
|
||||
# nothing. Everything else, including future Solar models, gets it.
|
||||
if not _model_supports_reasoning(model):
|
||||
return {}, top_level
|
||||
|
||||
|
|
|
|||
|
|
@ -113,9 +113,9 @@ class TestUpstageReasoning:
|
|||
_, top_level = upstage_profile.build_api_kwargs_extras(model=model)
|
||||
assert top_level == {"reasoning_effort": "medium"}
|
||||
|
||||
@pytest.mark.parametrize("model", ["solar-mini", "syn-pro"])
|
||||
def test_no_config_non_pro_still_omits(self, upstage_profile, model):
|
||||
# Default-on must not leak to non-reasoning models.
|
||||
@pytest.mark.parametrize("model", ["solar-mini", "solar-mini-202610", "syn-pro"])
|
||||
def test_no_config_deny_listed_still_omits(self, upstage_profile, model):
|
||||
# Default-on must not leak to the deny-listed non-reasoning models.
|
||||
_, top_level = upstage_profile.build_api_kwargs_extras(model=model)
|
||||
assert top_level == {}
|
||||
|
||||
|
|
@ -137,15 +137,36 @@ class TestUpstageReasoning:
|
|||
)
|
||||
assert top_level == {"reasoning_effort": "high"}
|
||||
|
||||
@pytest.mark.parametrize("model", ["solar-mini", "syn-pro"])
|
||||
def test_non_pro_models_never_send_reasoning(self, upstage_profile, model):
|
||||
# solar-mini / syn-pro ignore reasoning_effort, so never send it.
|
||||
@pytest.mark.parametrize("model", ["solar-mini", "solar-mini-202610", "syn-pro"])
|
||||
def test_deny_listed_models_never_send_reasoning(self, upstage_profile, model):
|
||||
# solar-mini / syn-pro ignore reasoning_effort, so never send it —
|
||||
# even when the user explicitly enables reasoning.
|
||||
extra_body, top_level = upstage_profile.build_api_kwargs_extras(
|
||||
reasoning_config={"enabled": True, "effort": "high"}, model=model
|
||||
)
|
||||
assert extra_body == {}
|
||||
assert top_level == {}
|
||||
|
||||
@pytest.mark.parametrize("model", ["solar-future", "solar-future-260601"])
|
||||
def test_unknown_future_models_default_to_reasoning(self, upstage_profile, model):
|
||||
# Deny-list semantics: a future Solar model we've never heard of is
|
||||
# assumed reasoning-capable, so reasoning_effort is sent instead of
|
||||
# being silently dropped (the old allow-list failure mode).
|
||||
_, top_level = upstage_profile.build_api_kwargs_extras(
|
||||
reasoning_config={"enabled": True, "effort": "high"}, model=model
|
||||
)
|
||||
assert top_level == {"reasoning_effort": "high"}
|
||||
|
||||
# And the unset-config default-on path applies to it too.
|
||||
_, top_level = upstage_profile.build_api_kwargs_extras(model=model)
|
||||
assert top_level == {"reasoning_effort": "medium"}
|
||||
|
||||
def test_none_model_defaults_to_reasoning(self, upstage_profile):
|
||||
# No model in context → treated as reasoning-capable, consistent with
|
||||
# the provider default (fallback_models[0] == "solar-pro").
|
||||
_, top_level = upstage_profile.build_api_kwargs_extras(model=None)
|
||||
assert top_level == {"reasoning_effort": "medium"}
|
||||
|
||||
|
||||
def upstage_profile_singleton():
|
||||
import providers
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue