99 lines
5.2 KiB
Bash
Executable File
99 lines
5.2 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -Eeuo pipefail
|
|
|
|
HERMES_CONTAINER=${HERMES_CONTAINER:-mike-ai-hermes}
|
|
SECRETS_DIR=${SECRETS_DIR:-/etc/mike-ai}
|
|
HERMES_DATA_DIR=${HERMES_DATA_DIR:-/data/hermes}
|
|
|
|
die() { printf 'FEHLER: %s\n' "$*" >&2; exit 1; }
|
|
docker inspect "$HERMES_CONTAINER" >/dev/null 2>&1 || \
|
|
die "Hermes-Container fehlt: $HERMES_CONTAINER"
|
|
|
|
deadline=$((SECONDS + 180))
|
|
until [[ $(docker inspect --format '{{if .State.Health}}{{.State.Health.Status}}{{else}}{{.State.Status}}{{end}}' \
|
|
"$HERMES_CONTAINER" 2>/dev/null || true) == healthy ]]; do
|
|
(( SECONDS < deadline )) || die "Hermes wurde nicht rechtzeitig gesund."
|
|
sleep 2
|
|
done
|
|
|
|
create_profile() {
|
|
local name=$1 model=$2 context=$3 description=$4
|
|
if ! docker exec "$HERMES_CONTAINER" hermes profile show "$name" >/dev/null 2>&1; then
|
|
docker exec "$HERMES_CONTAINER" hermes profile create "$name" \
|
|
--clone-from default --description "$description"
|
|
fi
|
|
docker exec "$HERMES_CONTAINER" hermes -p "$name" config set model.default "$model"
|
|
docker exec "$HERMES_CONTAINER" hermes -p "$name" config set model.context_length "$context"
|
|
# These are platform-wide latency and loop safeguards, not model-specific
|
|
# tuning. Enforce them on old profiles as well as newly cloned profiles.
|
|
docker exec "$HERMES_CONTAINER" hermes -p "$name" config set model.max_tokens 8192
|
|
docker exec "$HERMES_CONTAINER" hermes -p "$name" config set agent.max_turns 64
|
|
docker exec "$HERMES_CONTAINER" hermes -p "$name" config set agent.reasoning_effort minimal
|
|
docker exec "$HERMES_CONTAINER" hermes -p "$name" config set auxiliary.title_generation.enabled false
|
|
docker exec "$HERMES_CONTAINER" hermes -p "$name" config unset compression.threshold_tokens || true
|
|
docker exec "$HERMES_CONTAINER" hermes -p "$name" config set compression.threshold 0.82
|
|
docker exec "$HERMES_CONTAINER" hermes -p "$name" config set compression.target_ratio 0.35
|
|
docker exec "$HERMES_CONTAINER" hermes -p "$name" config set compression.protect_last_n 20
|
|
docker exec "$HERMES_CONTAINER" hermes -p "$name" config set compression.protect_first_n 0
|
|
# The small compressor remains an opt-in benchmark endpoint. It is not safe
|
|
# as a global technical-session compressor: end-to-end tests showed that it
|
|
# can omit older exact KEY=value state. Remove stale opt-in settings so the
|
|
# selected 27B profile performs production compaction.
|
|
docker exec "$HERMES_CONTAINER" hermes -p "$name" config unset auxiliary.compression || true
|
|
docker exec "$HERMES_CONTAINER" hermes -p "$name" config set platform_toolsets.cli \
|
|
'["web","terminal","file","skills","todo","memory","vision","tts"]'
|
|
[[ $(docker exec "$HERMES_CONTAINER" hermes -p "$name" config get model.default) == "$model" ]] || \
|
|
die "Modellalias von Profil $name konnte nicht verifiziert werden."
|
|
[[ $(docker exec "$HERMES_CONTAINER" hermes -p "$name" config get model.context_length) == "$context" ]] || \
|
|
die "Kontext von Profil $name konnte nicht verifiziert werden."
|
|
}
|
|
|
|
create_profile fast qwen-fast 76800 \
|
|
"Schnelles Qwen3.8-27B-Profil mit 76,8K Kontext fuer kurze Chats und schnelle Aufgaben."
|
|
create_profile medium qwen-medium 160000 \
|
|
"Ausgewogenes Qwen3.8-27B-Standardprofil mit 160K Kontext fuer Alltag und agentische Aufgaben."
|
|
create_profile large qwen-large 192000 \
|
|
"Grosses Qwen3.8-27B-Profil mit 192K Kontext fuer umfangreiche Dokumente und lange Aufgaben."
|
|
create_profile ultra qwen-ultra 262144 \
|
|
"Maximales Qwen3.8-27B-Profil mit 262K Kontext fuer sehr grosse Kontexte; langsamer als die Standardprofile."
|
|
create_profile uncensored qwen-uncensored 80000 \
|
|
"Unzensiertes Qwen3.8-27B-Profil mit 80K Kontext fuer spezielle Anfragen."
|
|
|
|
# Existing profiles may predate managed secret rendering and therefore contain
|
|
# the literal ${ROUTER_API_KEY}. Repair only that exact placeholder; never log
|
|
# or commit the secret itself.
|
|
[[ -s $SECRETS_DIR/router-api-key ]] || die "Router-API-Key fehlt."
|
|
router_key=$(<"$SECRETS_DIR/router-api-key")
|
|
ROUTER_API_KEY="$router_key" HERMES_DATA_DIR="$HERMES_DATA_DIR" python3 <<'PY'
|
|
import os
|
|
import pathlib
|
|
|
|
root = pathlib.Path(os.environ["HERMES_DATA_DIR"]) / "profiles"
|
|
placeholder = "${ROUTER_API_KEY}"
|
|
paths = [pathlib.Path(os.environ["HERMES_DATA_DIR"]) / "config.yaml"]
|
|
paths.extend(sorted(root.glob("*/config.yaml")))
|
|
for path in paths:
|
|
if not path.exists():
|
|
continue
|
|
text = path.read_text()
|
|
if placeholder in text:
|
|
text = text.replace(placeholder, os.environ["ROUTER_API_KEY"], 1)
|
|
# Avoid collision with Hermes' disabled built-in `homeassistant` toolset.
|
|
# The collision filters the healthy external MCP out of agent snapshots.
|
|
text = text.replace(
|
|
"\n homeassistant:\n url: http://mcp-homeassistant:8000/mcp\n",
|
|
"\n homeassistant-admin:\n url: http://mcp-homeassistant:8000/mcp\n",
|
|
)
|
|
path.write_text(text)
|
|
PY
|
|
|
|
sync_args=(--registry "${STACK_DIR:-/opt/mike-ai/stack}/config/mcp-registry.json")
|
|
while IFS= read -r config; do
|
|
sync_args+=(--hermes "$config")
|
|
done < <(find "$HERMES_DATA_DIR" -name config.yaml -type f -print)
|
|
python3 "${STACK_DIR:-/opt/mike-ai/stack}/platform/mcp/sync-clients.py" "${sync_args[@]}"
|
|
|
|
"${STACK_DIR:-/opt/mike-ai/stack}/platform/hermes/install-skills.sh"
|
|
docker exec "$HERMES_CONTAINER" hermes profile list
|
|
printf 'HERMES_PROFILES_OK\n'
|