主题
Hermes Docker + NewAPI Gateway Implementation Plan
Goal: Deploy Hermes agents as Docker containers using the official nousresearch/hermes-agent image, routed through the self-hosted NewAPI LLM gateway at llm.fsagent.cc.
Status: Components 1 and 3 done. Component 2 (SearXNG) pending.
Architecture
User (WeChat Pay)
↓
provisioner / spawn-profile.sh
↓
docker run nousresearch/hermes-agent ← per-user container
↓ ↓
/opt/data hermes gateway :8642
(profile dir) ↓
.env (LLM_API_KEY) MCP + web search
config.yaml
skills/
↓
llm.fsagent.cc/v1 ← NewAPI gateway (Vultr Japan)
http://host.docker.internal:9100/mcp ← twilight-mcp-tushare
http://127.0.0.1:8088/search [TODO] ← SearXNG (not yet deployed)Component 1: LLM — NewAPI Gateway ✅ DONE
Commit: fbd83f2 feat(profile): switch LLM provider to NewAPI gateway
What changed
config.yaml.template:base_url: https://llm.fsagent.cc/v1,api_key: ${LLM_API_KEY}, model:openrouter/free- Removed
fallback_providersblock — NewAPI handles channel pooling internally spawn-profile.sh: inputLLM_API_KEYreplacesSILICONFLOW_KEY/OPENROUTER_KEYsecrets.schema.json+.env.exampleupdated to match
Available models via Hermes_Test key (sk-J6ItPNKnNSxWnvjgWxOsG5J1XK2zuOnGJpK6R4nBDe4JIhMM)
All :free tier, routed through openrouter/free by default:
openrouter/free(default — gateway picks best available free model)nvidia/nemotron-3-super-120b-a12b:freenvidia/nemotron-3-nano-30b-a3b:freenvidia/nemotron-3-nano-omni-30b-a3b-reasoning:freearcee-ai/trinity-large-thinking:freeliquid/lfm-2.5-1.2b-thinking:freenvidia/nemotron-nano-12b-v2-vl:freenvidia/nemotron-nano-9b-v2:freepoolside/laguna-m.1:freepoolside/laguna-xs.2:freeinclusionai/ring-2.6-1t:freebaidu/cobuddy:freeliquid/lfm-2.5-1.2b-instruct:free
Per-user provisioning
When a user subscribes, provisioner must:
- Call NewAPI API to create a per-user channel key (or issue from a key pool)
- Pass
LLM_API_KEY=<key>tospawn-profile.sh
NewAPI user creation API:
bash
# Create channel via NewAPI admin API (requires admin key)
POST https://llm.fsagent.cc/api/user/register # or admin/token createComponent 2: Web Search — SearXNG ⬜ TODO
Plan (implement after SearXNG keys are shared)
Add
searxngservice todeploy/compose.yml(warehouse stack)- Image:
searxng/searxng:latest - Bind:
127.0.0.1:8088:8080 - Mount: SearXNG config at
/etc/searxng/settings.yml - Configure engines: Google Custom Search (API key), Bing, DuckDuckGo
- Image:
Add
deploy/searxng/settings.yml— SearXNG config with enabled enginesUpdate
config.yaml.template:yamlweb: backend: searxng url: ${SEARXNG_URL}Update
spawn-profile.sh— writeSEARXNG_URLbased on tier:prefab(host network):http://127.0.0.1:8088/searchcontainer(isolated):http://host.docker.internal:8088/search
Add
SEARXNG_URL=to.env.example
Note on Exa/Tavily: Not standard SearXNG engines. Options:
- (A) Add as MCP tools in
mcp_serversblock ofconfig.yaml.template - (B) Skip for now — SearXNG + DuckDuckGo covers basic needs
Component 3: Hermes Docker Container ✅ DONE
Commits: b1a48f6 (config.yaml materialization), fbd83f2 (LLM key)
How it works
spawn-profile.sh already handles the full container lifecycle:
bash
# Prefab tier (host network, moderate limits)
spawn-profile.sh <name> prefab LLM_API_KEY=<key>
# Container tier (isolated network, tighter limits)
spawn-profile.sh <name> container LLM_API_KEY=<key>Container details:
- Image:
nousresearch/hermes-agent:latest - Profile dir →
/opt/data(HOME) config.yamlmaterialized at spawn time from template{{MCP_URL}}substituted: prefab=http://127.0.0.1:9100/mcp, container=http://host.docker.internal:9100/mcp- Health:
curl http://127.0.0.1:8642/healthevery 30s - Runs:
gateway run
What container tier needs from each profile
/opt/data/
├── config.yaml ← materialized from template (spawn-profile.sh handles)
├── .env ← written by spawn-profile.sh
└── skills/
└── research/
└── stock-research/ ← copied from repo at spawn timeTest a profile manually
bash
# On ECS (or locally with Docker)
cd ~/twilight/source
./scripts/admin/spawn-profile.sh test-user-1 container \
LLM_API_KEY=sk-J6ItPNKnNSxWnvjgWxOsG5J1XK2zuOnGJpK6R4nBDe4JIhMM \
DASHSCOPE_KEY=<your-key>
# Check logs
docker logs -f hermes-test-user-1
# Check health
docker inspect hermes-test-user-1 --format '{{.State.Health.Status}}'Open Questions
- NewAPI per-user key issuance: How does provisioner create a key per user? Need NewAPI admin API docs or admin key.
- SearXNG keys: User has Google Custom Search, Exa, Tavily keys — share in a file to complete component 2.
- Exa/Tavily routing: SearXNG MCP engine vs direct MCP tools — decision pending.