mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-06-09 08:21:50 +00:00
fix(tui): preserve fallback provider chain
This commit is contained in:
parent
dbf2470d46
commit
4b073d0906
2 changed files with 132 additions and 1 deletions
|
|
@ -902,6 +902,108 @@ def test_startup_runtime_detects_provider_for_model_env(monkeypatch):
|
|||
)
|
||||
|
||||
|
||||
def test_load_fallback_model_prefers_fallback_providers(monkeypatch):
|
||||
fallback_chain = [
|
||||
{"provider": "openrouter", "model": "openai/gpt-5.5"},
|
||||
{"provider": "anthropic", "model": "claude-sonnet-4-6"},
|
||||
]
|
||||
monkeypatch.setattr(
|
||||
server,
|
||||
"_load_cfg",
|
||||
lambda: {
|
||||
"fallback_model": {"provider": "legacy", "model": "legacy-model"},
|
||||
"fallback_providers": fallback_chain,
|
||||
},
|
||||
)
|
||||
|
||||
assert server._load_fallback_model() == fallback_chain
|
||||
|
||||
|
||||
def test_make_agent_passes_configured_fallback_chain(monkeypatch):
|
||||
captured = {}
|
||||
fallback_chain = [
|
||||
{"provider": "openrouter", "model": "openai/gpt-5.5"},
|
||||
]
|
||||
|
||||
def fake_agent(**kwargs):
|
||||
captured.update(kwargs)
|
||||
return types.SimpleNamespace(model=kwargs.get("model"))
|
||||
|
||||
monkeypatch.delenv("HERMES_MODEL", raising=False)
|
||||
monkeypatch.delenv("HERMES_INFERENCE_MODEL", raising=False)
|
||||
monkeypatch.delenv("HERMES_TUI_PROVIDER", raising=False)
|
||||
monkeypatch.setattr(
|
||||
server,
|
||||
"_load_cfg",
|
||||
lambda: {
|
||||
"model": {"default": "gpt-5.5", "provider": "openai-codex"},
|
||||
"fallback_providers": fallback_chain,
|
||||
},
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
"hermes_cli.runtime_provider.resolve_runtime_provider",
|
||||
lambda requested=None, target_model=None: {
|
||||
"provider": "openai-codex",
|
||||
"base_url": "https://chatgpt.com/backend-api/codex",
|
||||
"api_key": "token",
|
||||
"api_mode": "codex_responses",
|
||||
"credential_pool": None,
|
||||
},
|
||||
)
|
||||
monkeypatch.setattr("run_agent.AIAgent", fake_agent)
|
||||
monkeypatch.setattr(server, "_load_enabled_toolsets", lambda: ["file"])
|
||||
monkeypatch.setattr(server, "_get_db", lambda: None)
|
||||
|
||||
agent = server._make_agent("sid", "session-key")
|
||||
|
||||
assert agent.model == "gpt-5.5"
|
||||
assert captured["fallback_model"] == fallback_chain
|
||||
assert captured["platform"] == "tui"
|
||||
|
||||
|
||||
def test_background_agent_kwargs_preserves_full_fallback_chain(monkeypatch):
|
||||
chain = [
|
||||
{"provider": "openrouter", "model": "openai/gpt-5.5"},
|
||||
{"provider": "anthropic", "model": "claude-sonnet-4-6"},
|
||||
]
|
||||
agent = types.SimpleNamespace(
|
||||
model="gpt-5.5",
|
||||
provider="openai-codex",
|
||||
_fallback_chain=chain,
|
||||
)
|
||||
monkeypatch.setattr(server, "_load_cfg", lambda: {"max_turns": 25})
|
||||
monkeypatch.setattr(server, "_load_enabled_toolsets", lambda: ["file"])
|
||||
monkeypatch.setattr(server, "_get_db", lambda: None)
|
||||
|
||||
kwargs = server._background_agent_kwargs(agent, "task-id")
|
||||
|
||||
assert kwargs["fallback_model"] == chain
|
||||
|
||||
|
||||
def test_background_agent_kwargs_preserves_empty_fallback_chain(monkeypatch):
|
||||
agent = types.SimpleNamespace(
|
||||
model="gpt-5.5",
|
||||
provider="anthropic",
|
||||
_fallback_chain=[],
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
server,
|
||||
"_load_cfg",
|
||||
lambda: {
|
||||
"max_turns": 25,
|
||||
"fallback_providers": [
|
||||
{"provider": "openrouter", "model": "openai/gpt-5.5"},
|
||||
],
|
||||
},
|
||||
)
|
||||
monkeypatch.setattr(server, "_load_enabled_toolsets", lambda: ["file"])
|
||||
monkeypatch.setattr(server, "_get_db", lambda: None)
|
||||
|
||||
kwargs = server._background_agent_kwargs(agent, "task-id")
|
||||
|
||||
assert kwargs["fallback_model"] == []
|
||||
|
||||
|
||||
def test_startup_runtime_resolves_short_alias_without_network(monkeypatch):
|
||||
monkeypatch.setenv("HERMES_MODEL", "sonnet")
|
||||
monkeypatch.delenv("HERMES_TUI_PROVIDER", raising=False)
|
||||
|
|
|
|||
|
|
@ -2587,6 +2587,34 @@ def _parse_tui_skills_env() -> list[str]:
|
|||
return skills
|
||||
|
||||
|
||||
def _load_fallback_model():
|
||||
"""Return the configured fallback chain for TUI-created agents.
|
||||
|
||||
Keep this in parity with ``HermesCLI.__init__``: prefer the new
|
||||
``fallback_providers`` list and accept the legacy single-dict
|
||||
``fallback_model`` shape.
|
||||
"""
|
||||
cfg = _load_cfg()
|
||||
fb = cfg.get("fallback_providers") or cfg.get("fallback_model") or []
|
||||
if isinstance(fb, dict):
|
||||
fb = [fb] if fb.get("provider") and fb.get("model") else []
|
||||
if isinstance(fb, list):
|
||||
return [
|
||||
f for f in fb
|
||||
if isinstance(f, dict) and f.get("provider") and f.get("model")
|
||||
]
|
||||
return []
|
||||
|
||||
|
||||
def _agent_fallback_model(agent):
|
||||
"""Return an agent's fallback chain without rehydrating deliberately empty chains."""
|
||||
if hasattr(agent, "_fallback_chain"):
|
||||
return getattr(agent, "_fallback_chain") or []
|
||||
if hasattr(agent, "_fallback_model"):
|
||||
return getattr(agent, "_fallback_model", None)
|
||||
return _load_fallback_model()
|
||||
|
||||
|
||||
def _background_agent_kwargs(agent, task_id: str) -> dict:
|
||||
cfg = _load_cfg()
|
||||
|
||||
|
|
@ -2621,7 +2649,7 @@ def _background_agent_kwargs(agent, task_id: str) -> dict:
|
|||
"request_overrides": dict(getattr(agent, "request_overrides", {}) or {}),
|
||||
"platform": "tui",
|
||||
"session_db": _get_db(),
|
||||
"fallback_model": getattr(agent, "_fallback_model", None),
|
||||
"fallback_model": _agent_fallback_model(agent),
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -2880,6 +2908,7 @@ def _make_agent(
|
|||
pass_session_id=is_truthy_value(os.environ.get("HERMES_TUI_PASS_SESSION_ID")),
|
||||
skip_context_files=is_truthy_value(os.environ.get("HERMES_IGNORE_RULES")),
|
||||
skip_memory=is_truthy_value(os.environ.get("HERMES_IGNORE_RULES")),
|
||||
fallback_model=_load_fallback_model(),
|
||||
**_agent_cbs(sid),
|
||||
)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue