mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-20 15:33:54 +00:00
refactor(reasoning): unify per-model reasoning resolution behind a single chokepoint
Collapse the six per-surface copies of override-then-global resolution (CLI startup, gateway, TUI, cron, /model switch, fallback activation) onto one shared resolve_reasoning_config() in hermes_constants. Also fixes the gateway resolving reasoning against config model.default instead of the session's effective model: after a session-only /model switch, the switched model's override now applies (gateway message paths pass the resolved session model through _resolve_session_reasoning_config; /reasoning status reads the session model override). Cleanup: drop docs/PER_MODEL_REASONING.md (duplicates the website docs page), drop the change-detector _config_version test (no bump needed — deep-merge handles new keys), remove a stale plan-reference comment. Adds chokepoint contract tests (13) and gateway session-effective-model regression tests (2).
This commit is contained in:
parent
d9cdb81923
commit
e81d18dfb4
11 changed files with 302 additions and 253 deletions
|
|
@ -2074,40 +2074,19 @@ def switch_model(agent, new_model, new_provider, api_key='', base_url='', api_mo
|
|||
|
||||
# ── Re-resolve reasoning_config from per-model override ──
|
||||
# The new model may have a different reasoning_effort override. Re-read
|
||||
# config so the override takes effect immediately on /model switch.
|
||||
# Try both agent.model (normalized, e.g. "claude-opus-4-5") AND the raw
|
||||
# config default (user's original spelling, e.g. "claude-opus-4.5") so
|
||||
# override keys match regardless of how downstream consumers normalized
|
||||
# the input. See plan FINDING #7 + session follow-up.
|
||||
# config so the override takes effect immediately on /model switch —
|
||||
# resolved through the shared chokepoint (per-model > global; YAML
|
||||
# boolean False = disabled).
|
||||
try:
|
||||
from hermes_constants import (
|
||||
parse_reasoning_effort,
|
||||
resolve_per_model_reasoning_effort,
|
||||
)
|
||||
from hermes_constants import resolve_reasoning_config
|
||||
from hermes_cli.config import load_config as _sm_load_config
|
||||
|
||||
_reasoning_cfg = _sm_load_config() or {}
|
||||
_sm_overrides = (_reasoning_cfg.get("agent") or {}).get("reasoning_overrides", {}) or {}
|
||||
# Try the normalized agent.model first, then the raw config default
|
||||
_sm_raw_model_default = str((_reasoning_cfg.get("model") or {}).get("default", "") or "").strip()
|
||||
_sm_per_model = None
|
||||
for _candidate in (agent.model, _sm_raw_model_default):
|
||||
if _candidate:
|
||||
_sm_per_model = resolve_per_model_reasoning_effort(_candidate, _sm_overrides)
|
||||
if _sm_per_model is not None:
|
||||
break
|
||||
if _sm_per_model is not None:
|
||||
agent.reasoning_config = _sm_per_model
|
||||
logger.info(
|
||||
"switch_model: reasoning_config resolved to per-model override for %s: %s",
|
||||
agent.model, _sm_per_model,
|
||||
)
|
||||
else:
|
||||
# Raw value — a YAML boolean False means thinking disabled,
|
||||
# see parse_reasoning_effort. Do NOT str()/strip() coerce.
|
||||
_sm_global = (_reasoning_cfg.get("agent") or {}).get("reasoning_effort", "")
|
||||
agent.reasoning_config = parse_reasoning_effort(_sm_global)
|
||||
logger.info("switch_model: reasoning_config resolved to global effort: %s", _sm_global or "(none)")
|
||||
agent.reasoning_config = resolve_reasoning_config(_reasoning_cfg, agent.model)
|
||||
logger.info(
|
||||
"switch_model: reasoning_config resolved for %s: %s",
|
||||
agent.model, agent.reasoning_config,
|
||||
)
|
||||
except Exception as _reasoning_err:
|
||||
logger.debug("switch_model: could not re-resolve reasoning_config: %s", _reasoning_err)
|
||||
|
||||
|
|
|
|||
|
|
@ -1636,37 +1636,20 @@ def try_activate_fallback(agent, reason: "FailoverReason | None" = None) -> bool
|
|||
)
|
||||
|
||||
# Re-resolve reasoning_config for the new fallback model (Closes #21256).
|
||||
# Per-model override (if any) takes precedence, else global reasoning_effort.
|
||||
# Wrapped in try/except because config load failure must not kill the swap.
|
||||
# Shared chokepoint: per-model override > global reasoning_effort
|
||||
# (YAML boolean False = disabled). Wrapped in try/except because a
|
||||
# config load failure must not kill the swap.
|
||||
try:
|
||||
from hermes_cli.config import load_config
|
||||
from hermes_constants import parse_reasoning_effort, resolve_per_model_reasoning_effort
|
||||
from hermes_constants import resolve_reasoning_config
|
||||
|
||||
_fb_cfg = load_config() or {}
|
||||
_fb_agent_cfg = _fb_cfg.get("agent", {}) or {}
|
||||
_fb_overrides = _fb_agent_cfg.get("reasoning_overrides", {}) or {}
|
||||
_fb_per_model = resolve_per_model_reasoning_effort(agent.model, _fb_overrides)
|
||||
if _fb_per_model is not None:
|
||||
agent.reasoning_config = _fb_per_model
|
||||
logger.info(
|
||||
"Fallback %s: reasoning_config resolved to per-model override: %s",
|
||||
agent.model, _fb_per_model,
|
||||
)
|
||||
else:
|
||||
# Raw value — a YAML boolean False means thinking disabled,
|
||||
# see parse_reasoning_effort. Do NOT coerce with ``or ""``.
|
||||
_fb_global_effort = _fb_agent_cfg.get("reasoning_effort", "")
|
||||
agent.reasoning_config = parse_reasoning_effort(_fb_global_effort)
|
||||
if agent.reasoning_config:
|
||||
logger.info(
|
||||
"Fallback %s: reasoning_config resolved to global effort: %s",
|
||||
agent.model, _fb_global_effort,
|
||||
)
|
||||
else:
|
||||
logger.info(
|
||||
"Fallback %s: reasoning_config resolved to None (disabled or default)",
|
||||
agent.model,
|
||||
)
|
||||
agent.reasoning_config = resolve_reasoning_config(
|
||||
load_config() or {}, agent.model
|
||||
)
|
||||
logger.info(
|
||||
"Fallback %s: reasoning_config resolved: %s",
|
||||
agent.model, agent.reasoning_config,
|
||||
)
|
||||
except Exception as _reasoning_err:
|
||||
logger.debug(
|
||||
"Failed to resolve reasoning_config for fallback %s; keeping current: %s",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue