Bug
React/Ink TUI sessions do not receive the configured fallback_model / fallback_providers chain when tui_gateway.server._create_agent() constructs the foreground AIAgent. As a result, when the primary model fails (timeouts, connection errors, rate limits, etc.), the agent exhausts retries on the primary and returns API call failed after 3 retries instead of activating the configured fallback.
This is inconsistent with gateway/API sessions, which pass fallback_model=self._fallback_model into AIAgent and do activate the fallback chain.
Reproduction
-
Configure a primary model plus fallback in ~/.hermes/config.yaml, for example:
model:
provider: openai-codex
default: gpt-5.5
fallback_model:
provider: zenmux-anthropic
model: anthropic/claude-sonnet-4.6
(fallback_providers: list format should be affected the same way.)
-
Start Hermes via the React/Ink TUI path (hermes --tui) so the session is served by tui_gateway.
-
Make the primary provider fail repeatedly (observed with openai-codex/gpt-5.5 timeouts / connection errors).
-
Observe that the turn fails after primary retries, with logs like:
API call failed (attempt 3/3) ... provider=openai-codex ... model=gpt-5.5 summary=Request timed out.
API call failed after 3 retries. Request timed out. | provider=openai-codex model=gpt-5.5
-
No Fallback activated: gpt-5.5 → ... log appears for the TUI session.
Expected behavior
TUI sessions should respect the same global fallback configuration as CLI/gateway/API sessions. After retries are exhausted (or on eager-fallback errors), _try_activate_fallback() should see a non-empty _fallback_chain and switch to the configured fallback provider/model.
Actual behavior
The TUI-created agent has an empty fallback chain, so _try_activate_fallback() returns False immediately and the turn fails.
Root cause
tui_gateway/server.py::_create_agent() constructs AIAgent(...) without passing fallback_model:
return AIAgent(
model=model,
max_iterations=_cfg_max_turns(cfg, 90),
provider=runtime.get("provider"),
base_url=runtime.get("base_url"),
api_key=runtime.get("api_key"),
api_mode=runtime.get("api_mode"),
...
session_db=_get_db(),
...
)
Because agent/agent_init.py only initializes _fallback_chain from the fallback_model constructor parameter, this path ends up with:
agent._fallback_chain = []
For comparison, gateway/run.py loads and passes the chain:
self._fallback_model = self._load_fallback_model()
...
AIAgent(..., fallback_model=self._fallback_model)
Suggested fix
Add a TUI equivalent of the gateway fallback loader and pass it into all relevant TUI-created AIAgent instances.
Minimal foreground-session fix:
def _load_fallback_model() -> list | dict | None:
cfg = _load_config()
return cfg.get("fallback_providers") or cfg.get("fallback_model") or None
# in _create_agent()
return AIAgent(
...
fallback_model=_load_fallback_model(),
...
)
Also check _background_agent_kwargs() / background TUI runs: it currently forwards getattr(agent, "_fallback_model", None), which is legacy single-entry state. It may need to preserve the full fallback chain, e.g. getattr(agent, "_fallback_chain", None) or getattr(agent, "_fallback_model", None).
Related issues
This is the same class of bug as other entrypoints not propagating fallback config, but I could not find an existing TUI-specific issue:
Environment
- Hermes Agent: current main/local install as of 2026-05-19
- UI path: React/Ink TUI (
tui_gateway.entry / tui_gateway.server)
- Primary observed:
openai-codex / gpt-5.5
- Fallback observed/configured: custom Anthropic-compatible provider (
zenmux-anthropic / anthropic/claude-sonnet-4.6)
Bug
React/Ink TUI sessions do not receive the configured
fallback_model/fallback_providerschain whentui_gateway.server._create_agent()constructs the foregroundAIAgent. As a result, when the primary model fails (timeouts, connection errors, rate limits, etc.), the agent exhausts retries on the primary and returnsAPI call failed after 3 retriesinstead of activating the configured fallback.This is inconsistent with gateway/API sessions, which pass
fallback_model=self._fallback_modelintoAIAgentand do activate the fallback chain.Reproduction
Configure a primary model plus fallback in
~/.hermes/config.yaml, for example:(
fallback_providers:list format should be affected the same way.)Start Hermes via the React/Ink TUI path (
hermes --tui) so the session is served bytui_gateway.Make the primary provider fail repeatedly (observed with
openai-codex/gpt-5.5timeouts / connection errors).Observe that the turn fails after primary retries, with logs like:
No
Fallback activated: gpt-5.5 → ...log appears for the TUI session.Expected behavior
TUI sessions should respect the same global fallback configuration as CLI/gateway/API sessions. After retries are exhausted (or on eager-fallback errors),
_try_activate_fallback()should see a non-empty_fallback_chainand switch to the configured fallback provider/model.Actual behavior
The TUI-created agent has an empty fallback chain, so
_try_activate_fallback()returnsFalseimmediately and the turn fails.Root cause
tui_gateway/server.py::_create_agent()constructsAIAgent(...)without passingfallback_model:Because
agent/agent_init.pyonly initializes_fallback_chainfrom thefallback_modelconstructor parameter, this path ends up with:For comparison,
gateway/run.pyloads and passes the chain:Suggested fix
Add a TUI equivalent of the gateway fallback loader and pass it into all relevant TUI-created
AIAgentinstances.Minimal foreground-session fix:
Also check
_background_agent_kwargs()/ background TUI runs: it currently forwardsgetattr(agent, "_fallback_model", None), which is legacy single-entry state. It may need to preserve the full fallback chain, e.g.getattr(agent, "_fallback_chain", None) or getattr(agent, "_fallback_model", None).Related issues
This is the same class of bug as other entrypoints not propagating fallback config, but I could not find an existing TUI-specific issue:
fallback_modeltoAIAgent--oneshotCLI mode did not propagatefallback_providerstoAIAgentfallback_providerstoAIAgentEnvironment
tui_gateway.entry/tui_gateway.server)openai-codex / gpt-5.5zenmux-anthropic / anthropic/claude-sonnet-4.6)