diff --git a/skills/archived/hermes-api-server-setup/SKILL.md b/skills/archived/hermes-api-server-setup/SKILL.md new file mode 100644 index 0000000..001fece --- /dev/null +++ b/skills/archived/hermes-api-server-setup/SKILL.md @@ -0,0 +1,139 @@ +--- +name: hermes-api-server-setup +description: "Set up Hermes Agent built-in OpenAI-compatible API server on a custom port with external access. Includes the critical extra nesting pitfall." +version: 1.0 +category: devops +--- + +# Hermes API Server Setup + +Hermes has a built-in OpenAI-compatible API server (`gateway/platforms/api_server.py`) that exposes endpoints like `/v1/chat/completions`, `/v1/responses`, `/v1/models`, `/health`, etc. Any OpenAI-compatible frontend (Open WebUI, LobeChat, LibreChat, ChatBox, etc.) can connect. + +## Critical Pitfall - extra Nesting + +**Host, port, key, cors_origins MUST be nested under `extra:` in config.yaml.** If placed directly under the platform name, `PlatformConfig.from_dict()` silently ignores them (it only reads `enabled`, `token`, `api_key`, `home_channel`, `reply_to_mode`, `extra`). + +WRONG - binds to 127.0.0.1 only (silently ignores host/port): +```yaml +platforms: + api_server: + enabled: true + host: "0.0.0.0" + port: 8642 + key: "my-secret" +``` + +CORRECT - binds to 0.0.0.0: +```yaml +platforms: + api_server: + enabled: true + extra: + host: "0.0.0.0" + port: 8642 + key: "my-secret" + cors_origins: + - "*" +``` + +## Defaults + +- `DEFAULT_HOST`: `127.0.0.1` (localhost only - NOT externally accessible) +- `DEFAULT_PORT`: `8642` + +## Setup Steps + +1. Add the `platforms:` block at the TOP LEVEL of `~/.hermes/config.yaml` (not nested under `display:` or `agent:`). + +2. Ensure host is `0.0.0.0` for external access, set a `key` for API auth, and `cors_origins: ["*"]` for browser clients. + +3. Restart the gateway: + ```bash + systemctl --user restart hermes-gateway.service + ``` + +4. Verify: + ```bash + # Check port is listening on 0.0.0.0 + ss -tlnp | grep 8642 + # Health check + curl http://localhost:8642/health + # Model list (auth required) + curl http://localhost:8642/v1/models -H "Authorization: Bearer YOUR_KEY" + ``` + +5. If `ss` shows `127.0.0.1:8642` instead of `0.0.0.0:8642`, the `extra:` nesting is wrong - recheck step 1. + +## Client Connection + +| Field | Value | +|------------|----------------------------------| +| Base URL | `http://YOUR_HOST:8642/v1` | +| API Key | Value of `extra.key` in config | +| Model ID | `hermes-agent` (or active profile name) | + +## Available Endpoints + +- `GET /health` - Health check +- `GET /v1/models` - Model list +- `POST /v1/chat/completions` - OpenAI Chat Completions (SSE streaming supported) +- `POST /v1/responses` - OpenAI Responses API (stateful) +- `GET /v1/responses/{id}` - Retrieve stored response +- `DELETE /v1/responses/{id}` - Delete stored response +- `POST /v1/runs` - Async run (returns 202 + run_id) +- `GET /v1/runs/{id}/events` - SSE stream of run lifecycle events + +### Session Management Endpoints + +- `GET /v1/sessions` - List sessions (query: `limit`, `offset`, `source`, `include_children`, `order_by_last_active`) +- `DELETE /v1/sessions/{session_id}` - Delete a session and its messages +- `POST /v1/sessions/prune` - Delete ended sessions older than N days (body: `older_than_days`, `source`) +- `GET /v1/capabilities` - Advertises all endpoints including sessions (third-party UIs use this for discovery) + +Session IDs are validated (hex + underscore/dash only) to prevent path traversal. All session endpoints require the same `Authorization: Bearer KEY` as other endpoints. + +## Troubleshooting: API Server Unresponsive + +If the API server returns connection refused or times out: + +1. **Check if gateway service is running:** + ```bash + systemctl --user status hermes-gateway.service + ``` + +2. **Check if port is listening:** + ```bash + ss -tlnp | grep 8642 + ``` + No output = gateway not running or API Server not started. + +3. **Check gateway logs for startup errors or SIGTERM:** + ```bash + cat ~/.hermes/logs/gateway.log + ``` + Look for `Received SIGTERM` (systemd or user killed it) or `api_server connected` (started OK). + +4. **Restart gateway:** + ```bash + systemctl --user restart hermes-gateway.service + # or: hermes gateway start + ``` + +5. **Verify after restart:** + ```bash + sleep 5 && curl -s http://localhost:8642/health + ``` + +Common cause: Gateway received SIGTERM (e.g. from `hermes gateway stop`, system reboot, or OOM). The API Server is NOT a separate process — it runs inside the gateway. If the gateway dies, API Server dies with it. + +## Environment Variable Alternative + +Instead of config.yaml, you can also use env vars (checked at gateway startup): +- `API_SERVER_ENABLED=true` +- `API_SERVER_HOST=0.0.0.0` +- `API_SERVER_PORT=8642` +- `API_SERVER_KEY=my-secret` +- `API_SERVER_CORS_ORIGINS=*` +- `API_SERVER_MODEL_NAME=custom-name` + +These are read in `gateway/config.py` and take effect if `API_SERVER_ENABLED=true` OR `API_SERVER_KEY` is set.