# Fix for Hermes API Server: Model Override Not Respected

## Problem

The Hermes API server's POST /v1/runs endpoint accepts a `model` parameter in the request body,
but this parameter is only stored in run status for reporting. The agent created for the run
always uses the model from `config.yaml` (resolved by `_resolve_gateway_model()`), ignoring
the override.

## Root Cause

In `gateway/platforms/api_server.py`:

1. `_handle_runs()` extracts `model=body.get("model", self._model_name)` and stores it in run status (line 2862-2866)
2. `_create_agent()` is called WITHOUT passing the model from the request (line 2873-2878)
3. Inside `_create_agent()`, the model is set via `model = _resolve_gateway_model()` which always reads from config.yaml

## Solution

Modify `_create_agent()` to accept an optional `model_override` parameter and use it instead of
`_resolve_gateway_model()` when provided.

## Patch

Apply this patch to `~/.hermes/hermes-agent/gateway/platforms/api_server.py`:

```python
# Line 798 - Modify _create_agent signature to accept model_override
def _create_agent(
        self,
        ephemeral_system_prompt: Optional[str] = None,
        session_id: Optional[str] = None,
        stream_delta_callback=None,
        tool_progress_callback=None,
        tool_start_callback=None,
        tool_complete_callback=None,
        gateway_session_key: Optional[str] = None,
        model_override: Optional[str] = None,  # NEW PARAMETER
    ) -> Any:
        """
        Create an AIAgent instance using the gateway's runtime config.

        Uses _resolve_runtime_agent_kwargs() to pick up model, api_key,
        base_url, etc. from config.yaml / env vars.  Toolsets are resolved
        from config.yaml platform_toolsets.api_server (same as all other
        gateway platforms), falling back to the hermes-api-server default.

        ``gateway_session_key`` is a stable per-channel identifier supplied
        by the client (via ``X-Hermes-Session-Key``).  Unlike ``session_id``
        which scopes the short-term transcript and rotates on /new, this
        key is meant to persist across transcripts so long-term memory
        providers (e.g. Honcho) can scope their per-chat state correctly
        — matching the semantics of the native gateway's ``session_key``.

        ``model_override`` is an optional model identifier from the POST
        /v1/runs request body that takes precedence over config.yaml.
        """
        from run_agent import AIAgent
        from gateway.run import _resolve_runtime_agent_kwargs, _resolve_gateway_model, _load_gateway_config, GatewayRunner
        from hermes_cli.tools_config import _get_platform_tools

        runtime_kwargs = _resolve_runtime_agent_kwargs()
        reasoning_config = GatewayRunner._load_reasoning_config()
        
        # MODIFIED: Use model_override if provided, otherwise resolve from config
        model = model_override if model_override else _resolve_gateway_model()

        user_config = _load_gateway_config()
        enabled_toolsets = sorted(_get_platform_tools(user_config, "api_server"))

        max_iterations = int(os.getenv("HERMES_MAX_ITERATIONS", "90"))

        # Load fallback provider chain so the API server platform has the
        # same fallback behaviour as Telegram/Discord/Slack (fixes #4954).
        fallback_model = GatewayRunner._load_fallback_model()

        agent = AIAgent(
            model=model,
            **runtime_kwargs,
            max_iterations=max_iterations,
            quiet_mode=True,
            verbose_logging=False,
            ephemeral_system_prompt=ephemeral_system_prompt or None,
            enabled_toolsets=enabled_toolsets,
            session_id=session_id,
            platform="api_server",
            stream_delta_callback=stream_delta_callback,
            tool_progress_callback=tool_progress_callback,
            tool_start_callback=tool_start_callback,
            tool_complete_callback=tool_complete_callback,
            session_db=self._ensure_session_db(),
            fallback_model=fallback_model,
            reasoning_config=reasoning_config,
            gateway_session_key=gateway_session_key,
        )
        return agent
```

Then modify the call site in `_handle_runs()` (around line 2873) to pass the model override:

```python
# Line 2873 - Add model_override parameter
agent = self._create_agent(
    ephemeral_system_prompt=ephemeral_system_prompt,
    session_id=session_id,
    stream_delta_callback=_text_cb,
    tool_progress_callback=event_cb,
    gateway_session_key=gateway_session_key,
    model_override=body.get("model"),  # PASS MODEL FROM REQUEST BODY
)
```

## Verification

After applying the patch, restart the Hermes gateway and test:

1. Start a session with model override:
   ```bash
   curl -X POST http://localhost:8643/v1/runs \
     -H "Content-Type: application/json" \
     -d '{"input": "What is 2+2?", "model": "openrouter/z-ai/glm-4.7"}'
   ```

2. Check `~/.hermes/logs/agent.log` for the model actually used:
   ```bash
   tail -f ~/.hermes/logs/agent.log | grep -i model
   ```

You should see the requested model being used instead of the default from config.yaml.

## Alternative: Workaround in Bridge Adapter

If you can't patch the Hermes API server, you can work around this issue by
setting the model in `~/.hermes/config.yaml`:

```yaml
model:
  default: "openrouter/z-ai/glm-4.7"
```

However, this affects all API server runs, not just the Beacon bridge.