From e2d2e9fe2b450a7084cc7a54f265bdc44c12ba42 Mon Sep 17 00:00:00 2001 From: Dev User Date: Wed, 11 Mar 2026 00:09:37 +0100 Subject: [PATCH] fix(gateway): pass model to temporary AIAgent instances Memory flush, /compress, and session hygiene create AIAgent without model=, falling back to the hardcoded default "anthropic/claude-opus-4.6". This fails with a 400 error when the active provider is openai-codex (Codex only accepts its own model names like gpt-5.1-codex-mini). Add _resolve_gateway_model() that mirrors the env/config resolution already used by _run_agent_sync, and wire it into all three temporary agent creation sites. Co-Authored-By: Claude Opus 4.6 --- gateway/run.py | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/gateway/run.py b/gateway/run.py index d1a639b8c..f9f75f517 100644 --- a/gateway/run.py +++ b/gateway/run.py @@ -187,6 +187,30 @@ def _resolve_runtime_agent_kwargs() -> dict: } +def _resolve_gateway_model() -> str: + """Read model from env/config — mirrors the resolution in _run_agent_sync. + + Without this, temporary AIAgent instances (memory flush, /compress) fall + back to the hardcoded default ("anthropic/claude-opus-4.6") which fails + when the active provider is openai-codex. + """ + model = os.getenv("HERMES_MODEL") or os.getenv("LLM_MODEL") or "anthropic/claude-opus-4.6" + try: + import yaml as _y + _cfg_path = _hermes_home / "config.yaml" + if _cfg_path.exists(): + with open(_cfg_path, encoding="utf-8") as _f: + _cfg = _y.safe_load(_f) or {} + _model_cfg = _cfg.get("model", {}) + if isinstance(_model_cfg, str): + model = _model_cfg + elif isinstance(_model_cfg, dict): + model = _model_cfg.get("default", model) + except Exception: + pass + return model + + class GatewayRunner: """ Main gateway controller. @@ -258,8 +282,14 @@ def _flush_memories_for_session(self, old_session_id: str): if not runtime_kwargs.get("api_key"): return + # Resolve model from config — AIAgent's default is OpenRouter- + # formatted ("anthropic/claude-opus-4.6") which fails when the + # active provider is openai-codex. + model = _resolve_gateway_model() + tmp_agent = AIAgent( **runtime_kwargs, + model=model, max_iterations=8, quiet_mode=True, enabled_toolsets=["memory", "skills"], @@ -1047,6 +1077,7 @@ async def _handle_message(self, event: MessageEvent) -> Optional[str]: if len(_hyg_msgs) >= 4: _hyg_agent = AIAgent( **_hyg_runtime, + model=_hyg_model, max_iterations=4, quiet_mode=True, enabled_toolsets=["memory"], @@ -1867,6 +1898,9 @@ async def _handle_compress_command(self, event: MessageEvent) -> str: if not runtime_kwargs.get("api_key"): return "No provider configured -- cannot compress." + # Resolve model from config (same reason as memory flush above). + model = _resolve_gateway_model() + msgs = [ {"role": m.get("role"), "content": m.get("content")} for m in history @@ -1877,6 +1911,7 @@ async def _handle_compress_command(self, event: MessageEvent) -> str: tmp_agent = AIAgent( **runtime_kwargs, + model=model, max_iterations=4, quiet_mode=True, enabled_toolsets=["memory"],