Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ RUN pip install --no-cache-dir -r requirements.txt && \
COPY adapter.py .
COPY __init__.py .
COPY executor.py .
COPY scripts/ /app/scripts/
COPY start.sh /usr/local/bin/start.sh
RUN chmod +x /usr/local/bin/start.sh

Expand Down
10 changes: 9 additions & 1 deletion install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,16 @@ chmod 600 "$HERMES_HOME/.env"
# cli-config.yaml.example here as config.yaml which defaults to
# anthropic/claude-opus-4.6 + provider:auto. Our bridge needs
# deterministic routing.
PROVIDER="${HERMES_INFERENCE_PROVIDER:-auto}"
#
# Provider derivation: scripts/derive-provider.sh looks at the model
# slug prefix and sets $PROVIDER accordingly (minimax/* → minimax,
# anthropic/* → anthropic, openai/* → openrouter (hermes has no
# direct openai provider), nousresearch/* → nous-or-openrouter based
# on keys present, etc.). Explicit HERMES_INFERENCE_PROVIDER in the
# env always wins.
DEFAULT_MODEL="${HERMES_DEFAULT_MODEL:-nousresearch/hermes-4-70b}"
HERMES_DEFAULT_MODEL="${DEFAULT_MODEL}" \
. "$(dirname "$0")/scripts/derive-provider.sh"
{
echo "# Seeded by template-hermes install.sh on $(date -u -Iseconds)"
echo "# Rewritten each boot from HERMES_DEFAULT_MODEL + HERMES_INFERENCE_PROVIDER env."
Expand Down
79 changes: 79 additions & 0 deletions scripts/derive-provider.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
#!/usr/bin/env bash
# derive-provider.sh — map a hermes-agent model slug to its provider
# name. Sourced by both install.sh (SaaS bare-host path) and start.sh
# (Docker path) so the two entry-points stay consistent.
#
# Contract:
# Reads: $HERMES_INFERENCE_PROVIDER (if already set, we respect it)
# $HERMES_DEFAULT_MODEL (slug, e.g. "minimax/MiniMax-M2.7-highspeed")
# $HERMES_API_KEY / $NOUS_API_KEY (affect the nousresearch/* branch)
# Writes: $PROVIDER — the derived provider name, or "auto" if unknown.
#
# Why the per-template sub-script (vs doing this in CP): every runtime
# has its own provider taxonomy. Keeping the logic inside the template
# repo means CP stays runtime-agnostic and adding a new runtime with
# different provider semantics doesn't require a CP edit.
#
# Hermes-specific quirks encoded here:
# - `openai/...` routes through `openrouter` (hermes has no direct
# openai provider; openai-codex is OAuth-only for Codex models)
# - `nousresearch/...` prefers direct `nous` if HERMES_API_KEY is
# set, else falls back to `openrouter` (which also serves Hermes 3)
# - chinese-region variants (minimax-cn, kimi-coding-cn) keep their
# full prefix as the provider name
#
# See molecule-controlplane/docs/canary-tenants.md and the hermes-agent
# providers.md docs for the full taxonomy.

# Honour an explicit override.
if [ -n "${HERMES_INFERENCE_PROVIDER:-}" ]; then
PROVIDER="${HERMES_INFERENCE_PROVIDER}"
return 0 2>/dev/null || exit 0
fi

if [ -z "${HERMES_DEFAULT_MODEL:-}" ]; then
PROVIDER="auto"
return 0 2>/dev/null || exit 0
fi

case "${HERMES_DEFAULT_MODEL}" in
# Keep full CN-suffix as provider so chinese-region keys route right
minimax-cn/*) PROVIDER="minimax-cn" ;;
kimi-coding-cn/*) PROVIDER="kimi-coding-cn" ;;

# Direct-SDK providers (clean 1:1 prefix→provider mapping)
minimax/*) PROVIDER="minimax" ;;
anthropic/*) PROVIDER="anthropic" ;;
gemini/*) PROVIDER="gemini" ;;
deepseek/*) PROVIDER="deepseek" ;;
zai/*) PROVIDER="zai" ;;
kimi-coding/*) PROVIDER="kimi-coding" ;;
alibaba/*|dashscope/*|qwen/*) PROVIDER="alibaba" ;;
xiaomi/*|mimo/*) PROVIDER="xiaomi" ;;
arcee/*|arcee-ai/*) PROVIDER="arcee" ;;
nvidia/*|nim/*) PROVIDER="nvidia" ;;
ollama-cloud/*) PROVIDER="ollama-cloud" ;;
huggingface/*|hf/*) PROVIDER="huggingface" ;;
ai-gateway/*|aigateway/*) PROVIDER="ai-gateway" ;;
kilocode/*) PROVIDER="kilocode" ;;
opencode-zen/*) PROVIDER="opencode-zen" ;;
opencode-go/*) PROVIDER="opencode-go" ;;

# Hermes-specific routing quirks
openai/*) PROVIDER="openrouter" ;; # no direct openai provider; openrouter covers it
nousresearch/*)
# Prefer direct Nous Portal if Nous credentials present, else OR.
if [ -n "${HERMES_API_KEY:-}" ] || [ -n "${NOUS_API_KEY:-}" ]; then
PROVIDER="nous"
else
PROVIDER="openrouter"
fi
;;

# Explicit catch-alls
openrouter/*) PROVIDER="openrouter" ;;
custom/*) PROVIDER="custom" ;;

# Unknown prefix → let hermes auto-detect
*) PROVIDER="auto" ;;
esac
8 changes: 7 additions & 1 deletion start.sh
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,14 @@ chmod 600 "$ENV_FILE"
# the selection; operators override via HERMES_INFERENCE_PROVIDER
# + HERMES_DEFAULT_MODEL env, or by editing config.yaml at runtime
# inside the container.
PROVIDER="${HERMES_INFERENCE_PROVIDER:-auto}"
DEFAULT_MODEL="${HERMES_DEFAULT_MODEL:-nousresearch/hermes-4-70b}"
# Derive provider from model slug prefix — shared with install.sh via
# scripts/derive-provider.sh so Docker + bare-host paths match.
# Dockerfile COPYs scripts/ to /app/scripts; fall back to /scripts
# for dev environments that run start.sh with a different WORKDIR.
DERIVE_SCRIPT="/app/scripts/derive-provider.sh"
[ -f "$DERIVE_SCRIPT" ] || DERIVE_SCRIPT="/scripts/derive-provider.sh"
HERMES_DEFAULT_MODEL="${DEFAULT_MODEL}" . "$DERIVE_SCRIPT"
{
echo "# Seeded by molecule template-hermes start.sh. Customize via"
echo "# \`hermes config edit\` or by editing this file directly."
Expand Down
Loading