Skip to content

Connect Hermes Agent to Router One as a custom endpoint

Hermes Agent is Nous Research's open-source (MIT) agent: an interactive terminal session with tools, plus a messaging gateway that answers from Telegram, Discord, Slack and other apps. It accepts any OpenAI-compatible endpoint, so one Router One key gives it the Claude, GPT, Gemini, Grok and DeepSeek chat models in the catalog, and every request it sends that the gateway forwards to a model, its side tasks included, appears in Dashboard → Logs with its tokens and the wallet charge or plan quota it used (a streamed request that failed before any output may have no record). You can add Router One through the Custom endpoint entry of the hermes model wizard, or as a named provider in config.yaml, which also lets a model run on the Anthropic Messages or Responses transport. Checked on 2026-11-10 against Hermes Agent v0.23.1 (the latest release, published 2026-11-10), the release its official installer installs and hermes update follows, and against its docs and source at that release.

Install Hermes Agent and create a dedicated key

Install with the official one-line installer rather than pip: as of 2026-11-10 the hermes-agent package on PyPI is still at 0.19.0 (2026-07-20), while the latest GitHub release is v0.23.1. Per Hermes' installation and Updating docs (checked 2026-11-10), the installer puts a new install on the latest stable release, and hermes update then moves it from one release to the next; hermes update --set-channel main makes it follow every commit on main instead. On macOS, Linux and WSL2 the installer checks for git and curl, and it sets up Python, Node.js and Hermes' other dependencies itself. Windows is supported natively: run the PowerShell command below in PowerShell, and Hermes installs under %LOCALAPPDATA%\hermes (inside WSL2 it installs under ~/.hermes, as on Linux). When it runs in a terminal, the installer starts hermes setup, whose Model & Provider section is the same flow as hermes model, so you can enter the Router One values from the next section there or later. Then create a key for Hermes alone in Dashboard → API Keys with Create Key and give it a maxSpend cap: every model turn of an agent task is a billed request and Hermes' side tasks add more, so the cap is the hard stop on wallet charges, and a dedicated key keeps Hermes' requests together in Logs.

terminal
# macOS, Linux, WSL2 (needs git and curl)
curl -fsSL https://hermes-agent.nousresearch.com/install.sh | bash
source ~/.bashrc     # or source ~/.zshrc, or open a new terminal

# Windows (native PowerShell)
iex (irm https://hermes-agent.nousresearch.com/install.ps1)

hermes --version

Configure Hermes Agent to use the Router One base URL

Run hermes model in a terminal, outside any chat session, and choose Custom endpoint. At API base URL enter https://api.router.one/v1, and at API key paste the dedicated key. Hermes then checks the endpoint with GET /v1/models; Router One answers that call only when a key is present, and the reply lists every catalog ID, image-generation models included, so type the exact chat ID rather than picking a number from the list. At Select API compatibility mode choose 2, Chat Completions: api.router.one is not on Hermes' auto-detect list, and Chat Completions serves every chat model. Enter a model ID from /models such as anthropic/claude-sonnet-5, leave Context length in tokens blank for now (see the context section below) and set Display name to Router One. Hermes saves the key in its .env file as HERMES_CUSTOM_API_ROUTER_ONE_API_KEY and writes provider: custom, the base URL, the API mode and the model to config.yaml, which only references the key. To keep Router One next to other providers, or to add another transport later, define it as a named provider in config.yaml instead:

API base URL (hermes model → Custom endpoint)
https://api.router.one/v1
config.yaml
# ~/.hermes/config.yaml — native Windows / 原生 Windows: %LOCALAPPDATA%\hermes\config.yaml
providers:
  router-one:
    api: https://api.router.one/v1
    key_env: ROUTER_ONE_API_KEY      # set in Hermes' .env / 写在 Hermes 的 .env 中
    transport: chat_completions

model:
  provider: custom:router-one
  default: anthropic/claude-sonnet-5

compression:
  threshold_tokens: 240000         # set it yourself: no default on main since 2026-09-28; below 200000 for Grok IDs / 需自行设置:main 分支 2026-09-28 起不再有默认值;用 Grok ID 时设到 200000 以下

# ~/.hermes/.env
# ROUTER_ONE_API_KEY=sk-your-router-one-key

Pick a transport for each Router One model ID

A named provider speaks one transport: chat_completions, which Hermes also uses when the field is empty, anthropic_messages or codex_responses. Router One serves every chat model on Chat Completions, Claude-family and DeepSeek V4 IDs on Anthropic Messages, and GPT-family, DeepSeek V4 and Grok chat IDs natively on Responses, so one chat_completions entry reaches every chat model, and a second entry changes the wire format for one family. GPT-6 IDs need that second entry for tool calls: per OpenAI's GPT-6 guide (checked 2026-11-10), GPT-6 Astra, GPT-6.1 Sol and GPT-6.1 Terra support Chat Completions but take tool calls only on the Responses API, and GPT-6 Sol and GPT-6 Luna support function calling on Chat Completions only with reasoning_effort set to none. Hermes sends its tool definitions on every agent turn, so if you use openai/gpt-6-astra, openai/gpt-6.1-sol, openai/gpt-6.1-terra, openai/gpt-6-sol or openai/gpt-6-luna, run it on a codex_responses entry. On a chat_completions entry, Router One sends an openai/gpt-6-luna request that carries tools with reasoning_effort none, replacing the level Hermes sends without telling Hermes (since 2026-11-03, observed 2026-11-05), so Luna's tool turns there run without reasoning; on a codex_responses entry, which uses the Responses API, Router One keeps the level you set. The api value follows the transport: Hermes' Anthropic client removes a trailing /v1 because its SDK appends /v1/messages itself, so either form works there, while the two OpenAI transports append /chat/completions or /responses to /v1. Sent over codex_responses, a Claude ID is rejected with HTTP 400 before any model runs (model '<id>' must be called via /v1/messages or /v1/chat/completions); sent over anthropic_messages, a chat ID outside the Claude and DeepSeek families gets 400 with must be called via /v1/chat/completions. Hermes sends the key as Authorization: Bearer on the OpenAI transports and as x-api-key to a third-party Anthropic host; Router One accepts both, so every entry can share one key.

config.yaml
providers:
  router-one:
    api: https://api.router.one/v1
    key_env: ROUTER_ONE_API_KEY
  router-one-claude:
    api: https://api.router.one
    key_env: ROUTER_ONE_API_KEY
    transport: anthropic_messages

# switch inside a Hermes session:
#   /model custom:router-one:openai/gpt-5.6-sol
#   /model custom:router-one-claude:anthropic/claude-sonnet-5
Pick a transport for each Router One model ID
transportapiRouter One model IDs
chat_completions (default)https://api.router.one/v1Every chat model in the catalog: Claude, GPT, Gemini, Grok and DeepSeek IDs
anthropic_messageshttps://api.router.oneClaude-family IDs, channel IDs such as aws/claude-… included, plus deepseek-v4.1-flash and deepseek-v4-flash
codex_responseshttps://api.router.one/v1GPT-family IDs, azure/gpt-… channel IDs included, plus deepseek-v4.1-flash, deepseek-v4-flash and Grok chat IDs

Set the context length and the compression point yourself

Hermes plans compression around the model's context window. A context_length you set, in the model section or per model under providers.<name>.models, always wins; left empty, Hermes tries its cache and the endpoint's /models reply before it falls back to built-in defaults. Router One's GET /v1/models reply has no field Hermes reads as the window, so the detected value may not match the Router One model page. At startup Hermes prints the window it uses as Context limit and marks a configured value as pinned. The model page on /models shows each model's full window, which is the value to enter if you set context_length. Per Hermes' configuration docs and its source at v0.23.1 (checked 2026-11-10), compression fires at compression.threshold, 0.50 of the window (raised to 0.75 for windows under 512K), or at compression.threshold_tokens if you set it, whichever comes first. The threshold_tokens cap is off by default: Hermes' main branch dropped the 256000 default on 2026-09-28, and v0.23.1, the release the installer installs, ships without it too. Left unset, a session with a 1M window compresses only at about half the window, around 500,000 input tokens, and until then every turn resends, and bills, the whole history as input. Some model pages also list a long-context price line that covers the whole request once its input is above a threshold: 272,000 tokens on openai/gpt-5.6-sol and 200,000 on grok-4.7. So set compression.threshold_tokens yourself, as in the config below: 240000 compresses sessions before they reach the 256,000-token plan quota band of anthropic/claude-sonnet-5 and anthropic/claude-opus-5 (on a plan, a request whose input is above 256,000 tokens counts as 2 plan requests) or the 272,000 line of openai/gpt-5.6-sol, and for Grok IDs use a value below 200000, for example 190000; per Hermes' docs the value stays in force when you switch models. On the codex_responses transport, per Hermes' docs, GPT slugs such as gpt-5.6-sol take their window from Hermes' Codex table (272K for most) unless you set context_length; per its source, the openai/ prefix of a Router One ID does not change that, but to pick that window Hermes uses the first transport declared among the entries with the same api URL, not the one on the entry in use. So if more than one entry uses https://api.router.one/v1 (the Custom endpoint wizard saves one too), set context_length per model under providers.<name>.models.

Reasoning effort, side tasks and embeddings

Per Hermes' docs, chat_completions requests carry reasoning_effort: medium when you have not set an effort, and a level you set with /reasoning or agent.reasoning_effort reaches the endpoint unchanged, up to max. Router One maps the value to output_config.effort on Claude Opus 5.5 (since 2026-09-24) and Claude Sonnet 5.5 (observed 2026-10-31), both in no plan tier as of the 2026-11-10 plan response; whether another model honors it, ignores it or rejects the request with 400 depends on the model, so check the status of your first requests in Dashboard → Logs, and again after changing the level. On /v1/chat/completions, Router One sends a reasoning_effort of none or minimal as low for google/gemini-3.8-flash, vertex/gemini-3.8-flash and openai/gpt-6.1-sol (since 2026-10-30, observed 2026-11-05), without telling Hermes. Hermes also runs side tasks, among them session titles, context compression and image description, on your main model unless you route them elsewhere, and each one is another request on the same key. To send a task to a cheaper Router One model, set auxiliary.<task>.provider to your named provider and auxiliary.<task>.model to an exact ID, as below, or use Configure auxiliary models in hermes model. Router One serves no embeddings endpoint, so if you turn on a Hermes feature that needs an embedding model, give it another provider.

config.yaml
auxiliary:
  compression:
    provider: router-one
    model: google/gemini-3.8-flash
  vision:
    provider: router-one
    model: google/gemini-3.8-flash

What Hermes sends, and how to read its 4xx errors

Each model turn is one request: a task that reads files, runs commands and edits code sends one per tool round, and the side tasks above add their own, so filter Dashboard → Logs by the Hermes key. Each record shows the model, tokens, the wallet charge or plan quota used, status, total time and, for streamed requests that produced output, time to first token (TTFT). Read errors by status: 401 means the key is missing or wrong (with key_env, check that the variable is really in Hermes' .env); 402 means the wallet balance or the key's maxSpend is used up, and once the cap is reached the key's wallet-billed requests return 402 while your other keys keep working; 404 usually means a wrong path or an ID outside the catalog, so copy the ID again from /models; 400 with must be called via means the transport does not serve that ID. The gateway returns these four errors before it calls a model, so they leave no record in Dashboard → Logs; read them from the status and message Hermes shows. A turn that never reached Router One leaves no record either, which points back at the local configuration.

Which model ID should Hermes Agent send?

Copy the exact model ID from /models, preserving case, hyphens, and version suffixes; do not substitute a display name. Open its detail page and match the supported API endpoints, context window, and capabilities such as tool calling to the provider and features selected in Hermes Agent. A catalog listing does not mean the client can use every feature of that model. Give each client or application a dedicated API key with a maxSpend cap. A key's spend cap (maxSpend) limits what that key can charge to your wallet: once its cumulative wallet charges reach the cap, its wallet-billed requests return HTTP 402. Requests covered by your plan's quota draw from the account's shared plan quota and do not count toward any key's cap.

Which API protocol is Hermes Agent using?

OpenAI-compatible describes an interface format; it does not make Chat Completions (/v1/chat/completions), Responses (/v1/responses), and Anthropic Messages (/v1/messages) interchangeable. Check the installed client version, provider configuration, and actual request path against the model detail page and API compatibility fact sheet. A successful plain-text chat does not establish support for hosted tools, conversation state, or file-editing features.

Verify the Hermes Agent call in your request trace

Send a simple text request from Hermes Agent, then match its trace in Dashboard → Logs by time, model, and request_id: tokens, the wallet charge or plan quota it used, latency, and status. Next, test streaming, tool calls, and multi-turn history separately. For failures, retain the actual request path, full error message, and request_id. If there is no matching log, either the request never reached the gateway (client configuration or connectivity) or the gateway refused it before calling a model — a 401 for the key, a 402 for funds, a 429 from your key's or account's limits, or a 400 or 404 for the model ID or endpoint; a streamed request that failed before any output may have no log either. The status and error message the client received tell which, so check them before attributing the error to the gateway or upstream.

FAQ

Where does Hermes keep the Router One settings?

In config.yaml in the Hermes home directory: ~/.hermes on macOS, Linux and WSL2, and %LOCALAPPDATA%\hermes on native Windows, unless HERMES_HOME points elsewhere. The key goes in the .env file next to it. hermes config path and hermes config env-path print the two locations, and hermes config edit opens the config in your editor. The Custom endpoint wizard saves the key as HERMES_CUSTOM_API_ROUTER_ONE_API_KEY and config.yaml only references it; with a named provider, key_env names the variable. Keep both files out of dotfile repositories and shared backups.

I set OPENAI_BASE_URL, but Hermes still does not call Router One. Why?

Per Hermes' provider docs, OPENAI_BASE_URL is honored only for its openai-api provider; a custom endpoint or a named provider reads its URL from config.yaml. Run hermes model and choose Custom endpoint, or set model.provider to custom:router-one as in the example above, then start a new session. The /model command inside a chat only switches between providers you have already configured; it cannot add one.

Can I switch between Claude and GPT in one Hermes session?

Yes, among configured providers. /model custom:router-one:openai/gpt-5.6-sol switches to a GPT ID on the router-one entry, and /model custom:router-one-claude:anthropic/claude-sonnet-5 switches to a Claude ID on an anthropic_messages entry, if you defined one. A context_length set in the model section is dropped when you switch, so give each model you use its own context_length under providers.<name>.models.

The model list shows image models and IDs without capability labels. Which should I pick?

GET /v1/models returns the whole catalog, including image-generation models and IDs whose model page lists no capabilities. Hermes works through tool calls, so pick a chat model whose page on /models lists tool calling; for other IDs, test one tool call first. Image-generation IDs cannot serve Hermes' chat turns.

Can I install Hermes with pip install hermes-agent?

You would get an older release. As of 2026-11-10 the hermes-agent package on PyPI is at 0.19.0 (released 2026-07-20), while the latest GitHub release is v0.23.1 (2026-11-10), which the official installer installs. The installer also sets up Hermes' own Python environment and dependencies, and hermes update keeps it current afterwards: per Hermes' Updating docs (checked 2026-11-10), a source installation moves from one published release to the next.

Does Hermes Agent set compression.threshold_tokens by default?

No. v0.23.1, the release the official installer installs, sets no threshold_tokens default (per its source, checked 2026-11-10), and the main branch dropped the 256000 default on 2026-09-28. Left unset, a session with a 1M window compresses only at about half the window. Set compression.threshold_tokens yourself: 240000 keeps anthropic/claude-sonnet-5 and anthropic/claude-opus-5 requests under the 256,000-token plan quota band, and Grok IDs need a value below 200000. If you set it to 256000 from an earlier version of this guide, change it to 240000; per the same source, config migration v47 also removes a value of exactly 256000 when hermes update migrates a config.yaml stamped by an older Hermes.

Which models can Hermes Agent use through the gateway?

Choose a current catalog model that supports both the endpoint and the features Hermes Agent uses. Check /models and the model detail page for the exact ID, current rates, and capabilities; a family name such as GPT or Claude is not a compatibility guarantee. A client that lists a model has only read the ID, from its own configuration or from GET /v1/models; verify an actual request too.

Models are listed, but requests fail with 400 or 404. What should I check?

Record the actual request path and error message, then check the exact model ID. A 400 can indicate invalid parameters, unsupported tools, or a model/endpoint mismatch; a 404 can indicate an incorrect path or missing resource, so it does not by itself establish that a model was retired. If the error says must be called via, use the named endpoint or select a model supported on the current endpoint. Do not add or remove /v1 or /chat/completions across all clients indiscriminately.

Does this work from Mainland China?

Hermes' model requests to Router One work from Mainland China without a VPN, with the same configuration as elsewhere. Installing and updating Hermes is a separate matter: the installer clones the Hermes repository from GitHub and downloads its Python tooling, so it depends on your network's access to those hosts.

How do I debug a 401/402/403/429?

Start from what your client received: the status, the error body and the X-Request-ID header. A 401 (missing, unknown, revoked or expired key), a 402 (wallet balance, or the key's maxSpend cap) and a 429 from your key's or account's rate limits are refused before any model is called, so they never appear in Dashboard → Logs — nor does a 400 or 404 for a wrong model ID or endpoint. For 401, check that the full key is sent and still active in Dashboard → API Keys; for 402, top up or raise the key's maxSpend; for a 403, keep the full error body. For 429, back off and retry later; a 429 that does show up in Logs came back from upstream after the gateway's retries. Keep the request_id and follow the error-codes reference.