Documentação oficial desta página · v0.20.6
Pools de Credenciais
Pools de credenciais deixam você registrar várias chaves de API ou tokens OAuth do mesmo provedor. Quando uma chave bate num limite de taxa ou numa cota de cobrança, o Hermes gira automaticamente para a próxima chave saudável — mantendo a sua sessão viva sem trocar de provedor.
Isso é diferente dos provedores de reserva, que trocam por um provedor totalmente diferente. Pools de credenciais são rotação dentro do mesmo provedor; provedores de reserva são failover entre provedores. Os pools são tentados primeiro — se todas as chaves do pool se esgotarem, aí sim o provedor de reserva entra em ação.
Os caches de prompt do lado do provedor (Anthropic, OpenAI, OpenRouter) valem por conta/chave de API que fez a requisição. Quando o pool gira para outra chave no meio da sessão, a chave nova não tem prefixo em cache da sua conversa — a requisição seguinte relê o histórico inteiro pelo preço cheio de entrada, e voltar para a chave anterior mais tarde é outra releitura completa, a menos que o TTL do cache da chave antiga ainda esteja válido. A rotação mantém a sua sessão de pé, que é o objetivo, mas em conversas longas cada rotação custa uma passagem de preço cheio sobre o contexto.
Pools de credenciais servem principalmente para provedores com chave de API (OpenRouter, Anthropic). Um único OAuth do Nous Portal cobre mais de 300 modelos, então a maioria dos usuários não precisa de pool quando está no Portal.
Como funciona
Sua requisição
→ Escolhe uma chave do pool (round_robin / least_used / fill_first / random)
→ Envia ao provedor
→ 429 de limite de taxa?
→ Limite do plano/uso atingido (ex.: "usage limit reached" do ChatGPT/Codex)?
→ Gira já para a próxima chave do pool (sem retentativa — o teto não some ao repetir)
→ 429 genérico / transitório?
→ Repete uma vez com a mesma chave (falha passageira)
→ Segundo 429 → gira para a próxima chave do pool
→ Todas as chaves esgotadas → fallback_model (outro provedor)
→ 402 de erro de cobrança?
→ Gira imediatamente para a próxima chave do pool (1h de espera)
→ 401 de autenticação expirada?
→ Tenta renovar o token (OAuth)
→ Renovação falhou → gira para a próxima chave do pool
→ Sucesso → segue normalmente
Início rápido
Se você já tem uma chave de API definida no .env, o Hermes a descobre sozinho como um pool de 1 chave. Para tirar proveito do pool, acrescente mais chaves:
# Acrescenta uma segunda chave do OpenRouter
hermes auth add openrouter --api-key sk-or-v1-sua-segunda-chave
# Acrescenta uma segunda chave da Anthropic
hermes auth add anthropic --type api-key --api-key sk-ant-api03-sua-segunda-chave
# Acrescenta uma credencial OAuth da Anthropic (exige plano Claude Max + créditos extras de uso)
hermes auth add anthropic --type oauth
# Abre o navegador para o login OAuth
Confira os seus pools:
hermes auth list
Saída:
openrouter (2 credentials):
#1 OPENROUTER_API_KEY api_key env:OPENROUTER_API_KEY ←
#2 backup-key api_key manual
anthropic (3 credentials):
#1 hermes_pkce oauth hermes_pkce ←
#2 claude_code oauth claude_code
#3 ANTHROPIC_API_KEY api_key env:ANTHROPIC_API_KEY
O ← marca a credencial selecionada no momento.
Gerenciamento interativo
Rode hermes auth sem subcomando para abrir um assistente interativo:
hermes auth
Ele mostra o estado completo dos seus pools e oferece um menu:
What would you like to do?
1. Add a credential
2. Remove a credential
3. Reset cooldowns for a provider
4. Set rotation strategy for a provider
5. Exit
Para provedores que aceitam tanto chave de API quanto OAuth (Anthropic, Nous, Codex), o fluxo de adição pergunta qual dos dois:
anthropic supports both API keys and OAuth login.
1. API key (paste a key from the provider dashboard)
2. OAuth login (authenticate via browser)
Type [1/2]:
Comandos da CLI
| Comando | Descrição |
|---|---|
hermes auth | Assistente interativo de gerenciamento de pools |
hermes auth list | Mostra todos os pools e credenciais |
hermes auth list <provider> | Mostra o pool de um provedor específico |
hermes auth add <provider> | Acrescenta uma credencial (pergunta o tipo e a chave) |
hermes auth add <provider> --type api-key --api-key <key> | Acrescenta uma chave de API sem interação |
hermes auth add <provider> --type oauth | Acrescenta uma credencial OAuth pelo login no navegador |
hermes auth remove <provider> <index> | Remove a credencial pelo índice (começa em 1) |
hermes auth reset <provider> | Limpa todos os tempos de espera e o estado de esgotamento |
Estratégias de rotação
Configure em hermes auth → "Set rotation strategy", ou no config.yaml:
credential_pool_strategies:
openrouter: round_robin
anthropic: least_used
| Estratégia | Comportamento |
|---|---|
fill_first (padrão) | Usa a primeira chave saudável até esgotá-la, depois passa para a próxima |
round_robin | Percorre as chaves de forma equilibrada, girando a cada seleção |
least_used | Escolhe sempre a chave com a menor contagem de requisições |
random | Seleção aleatória entre as chaves saudáveis |
Recuperação de erros
O pool trata cada erro de um jeito:
| Erro | Comportamento | Tempo de espera |
|---|---|---|
| 429 limite de taxa | Repete uma vez com a mesma chave (transitório). O segundo 429 seguido gira para a próxima chave | 1 hora |
| 402 cobrança/cota | Gira imediatamente para a próxima chave | 1 hora |
| 401 autenticação expirada | Tenta primeiro renovar o token OAuth. Só gira se a renovação falhar | 5 minutos |
| Todas as chaves esgotadas | Cai para o fallback_model, se estiver configurado | — |
Carimbos de reset_at fornecidos pelo provedor sobrescrevem esses tempos de espera padrão.
A flag has_retried_429 é zerada a cada chamada de API bem-sucedida, então um 429 transitório isolado não dispara rotação.
Pools de endpoints personalizados
Endpoints personalizados compatíveis com a OpenAI (Together.ai, RunPod, servidores locais) ganham pools próprios, indexados pelo nome do endpoint no dicionário providers: do config.yaml (ou pela lista legada custom_providers, que é migrada automaticamente).
Quando você configura um endpoint personalizado com hermes model, ele gera sozinho um nome como "Together.ai" ou "Local (localhost:8080)". Esse nome vira a chave do pool.
# Depois de configurar um endpoint personalizado com hermes model:
hermes auth list
# Mostra:
# Together.ai (1 credential):
# #1 config key api_key config:Together.ai ←
# Acrescente uma segunda chave para o mesmo endpoint:
hermes auth add Together.ai --api-key sk-together-segunda-chave
Os pools de endpoints personalizados ficam no auth.json, dentro de credential_pool, com o prefixo custom::
{
"credential_pool": {
"openrouter": [...],
"custom:together.ai": [...]
}
}
Descoberta automática
O Hermes descobre credenciais sozinho, em várias fontes, e semeia o pool na inicialização:
| Fonte | Exemplo | Semeada automaticamente? |
|---|---|---|
| Variáveis de ambiente | OPENROUTER_API_KEY, ANTHROPIC_API_KEY | Sim |
| Tokens OAuth (auth.json) | Device code do Codex, device code da Nous | Sim |
| Credenciais do Claude Code | ~/.claude/.credentials.json | Sim (Anthropic) |
| OAuth PKCE do Hermes | ~/.hermes/auth.json | Sim (Anthropic) |
| Configuração de endpoint personalizado | model.api_key no config.yaml | Sim (endpoints personalizados) |
| Entradas manuais | Acrescentadas com hermes auth add | Persistidas no auth.json |
As entradas semeadas automaticamente são atualizadas a cada carga do pool — se você remover uma variável de ambiente, a entrada correspondente é podada sozinha. Entradas manuais (acrescentadas com hermes auth add) nunca são podadas automaticamente.
Segredos de runtime emprestados (por exemplo, variáveis de ambiente, referências a Bitwarden/Vault/keyring/systemd e valores de configuração personalizados) são apenas referências na fronteira do auth.json. O Hermes pode usar o valor resolvido em memória durante a execução atual, mas só persiste metadados: a referência de origem, o rótulo, o status, os contadores de requisição e uma impressão digital não reversível. Entradas manuais e o estado de OAuth/device code que pertence ao Hermes guardam os tokens duráveis de que precisam para renovar.
Delegação e compartilhamento com subagentes
Quando o agente cria subagentes com delegate_task, o pool de credenciais do pai é compartilhado automaticamente com os filhos:
- Mesmo provedor — o filho recebe o pool completo do pai, o que permite rotação de chave em limites de taxa
- Provedor diferente — o filho carrega o pool próprio daquele provedor (se houver)
- Nenhum pool configurado — o filho recorre à chave de API única herdada
Ou seja, os subagentes ganham a mesma resiliência a limite de taxa que o pai, sem configuração extra. O empréstimo de credencial por tarefa garante que os filhos não conflitem entre si ao girar chaves em paralelo.
Segurança entre threads
O pool de credenciais usa um lock de threading para toda mutação de estado (select(), mark_exhausted_and_rotate(), try_refresh_current(), mark_used()). Isso garante acesso concorrente seguro quando o gateway atende várias sessões de chat ao mesmo tempo.
Arquitetura
Para o diagrama completo do fluxo de dados, veja docs/credential-pool-flow.excalidraw no repositório.
O pool de credenciais se integra na camada de resolução de provedor:
agent/credential_pool.py— gerenciador do pool: armazenamento, seleção, rotação, tempos de esperahermes_cli/auth_commands.py— comandos da CLI e assistente interativohermes_cli/runtime_provider.py— resolução de credencial ciente do poolrun_agent.py— recuperação de erros: 429/402/401 → rotação do pool → reserva
Armazenamento
O estado do pool fica em ~/.hermes/auth.json, sob a chave credential_pool:
{
"version": 1,
"credential_pool": {
"openrouter": [
{
"id": "abc123",
"label": "OPENROUTER_API_KEY",
"auth_type": "api_key",
"priority": 0,
"source": "env:OPENROUTER_API_KEY",
"secret_source": "bitwarden",
"secret_fingerprint": "sha256:12ab34cd56ef7890",
"last_status": "ok",
"request_count": 142
}
],
"anthropic": [
{
"id": "manual1",
"label": "personal-api-key",
"auth_type": "api_key",
"priority": 0,
"source": "manual",
"access_token": "sk-ant-api03-..."
}
]
}
}
A entrada do OpenRouter acima foi emprestada de uma fonte externa, então a chave crua não fica guardada no auth.json. A entrada manual da Anthropic foi acrescentada de propósito ao armazenamento de credenciais do Hermes, então o token dela continua persistível.
As estratégias ficam no config.yaml (não no auth.json):
credential_pool_strategies:
openrouter: round_robin
anthropic: least_used