#!/usr/bin/env bash set -Eeuo pipefail HERMES_CONTAINER=${HERMES_CONTAINER:-Hermes-Agent} SECRETS_DIR=${SECRETS_DIR:-/etc/mike-ai} HERMES_DATA_DIR=${HERMES_DATA_DIR:-/mnt/nvme-storage/appdata/Hermes-Agent} STACK_DIR=${STACK_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)} PROFILE_MATRIX=${PROFILE_MATRIX:-$STACK_DIR/config/profile-matrix.json} die() { printf 'FEHLER: %s\n' "$*" >&2; exit 1; } docker inspect "$HERMES_CONTAINER" >/dev/null 2>&1 || \ die "Hermes-Container fehlt: $HERMES_CONTAINER" [[ -s $PROFILE_MATRIX ]] || die "Profilmatrix fehlt: $PROFILE_MATRIX" deadline=$((SECONDS + 180)) until [[ $(docker inspect --format '{{if .State.Health}}{{.State.Health.Status}}{{else}}{{.State.Status}}{{end}}' \ "$HERMES_CONTAINER" 2>/dev/null || true) =~ ^(healthy|running)$ ]]; do (( SECONDS < deadline )) || die "Hermes wurde nicht rechtzeitig gesund." sleep 2 done create_profile() { local name=$1 model=$2 context=$3 description=$4 max_tokens=$5 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 "$max_tokens" docker exec "$HERMES_CONTAINER" hermes -p "$name" config set agent.max_turns 64 # Current Hermes CLI parses the bare word `none` as YAML null. Boolean false # is the supported, unambiguous representation for disabled reasoning. docker exec "$HERMES_CONTAINER" hermes -p "$name" config set --force agent.reasoning_effort false docker exec "$HERMES_CONTAINER" hermes -p "$name" config set display.show_reasoning false docker exec "$HERMES_CONTAINER" hermes -p "$name" config set auxiliary.title_generation.enabled false docker exec "$HERMES_CONTAINER" hermes -p "$name" config set web.search_backend keenable docker exec "$HERMES_CONTAINER" hermes -p "$name" config set web.extract_backend keenable docker exec "$HERMES_CONTAINER" hermes -p "$name" config set web.keyless_fallback true docker exec "$HERMES_CONTAINER" hermes -p "$name" config set web.keyless_rescue true docker exec "$HERMES_CONTAINER" hermes -p "$name" config set plugins.enabled \ '["browser-browser-use","web-keenable"]' 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.95 docker exec "$HERMES_CONTAINER" hermes -p "$name" config set compression.target_ratio 0.15 docker exec "$HERMES_CONTAINER" hermes -p "$name" config set compression.max_attempts 1 docker exec "$HERMES_CONTAINER" hermes -p "$name" config set compression.context_timeout_seconds 45 docker exec "$HERMES_CONTAINER" hermes -p "$name" config set compression.context_total_ceiling_seconds 120 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 docker exec "$HERMES_CONTAINER" hermes -p "$name" config set compression.micro_compact true docker exec "$HERMES_CONTAINER" hermes -p "$name" config set compression.micro_compact_every_n_turns 5 docker exec "$HERMES_CONTAINER" hermes -p "$name" config set compression.micro_compact_defrag_threshold_tokens 2000 docker exec "$HERMES_CONTAINER" hermes -p "$name" config set compression.proactive_prune_tokens 32000 docker exec "$HERMES_CONTAINER" hermes -p "$name" config set compression.proactive_prune_min_result_chars 2000 docker exec "$HERMES_CONTAINER" hermes -p "$name" config set compression.proactive_prune_min_reclaim_tokens 2048 # The selected 27B profile performs production compaction. A separate small # compressor was removed after it lost exact technical state in benchmarks. docker exec "$HERMES_CONTAINER" hermes -p "$name" config unset auxiliary.compression || true docker exec "$HERMES_CONTAINER" hermes -p "$name" config set auxiliary.compression.provider main docker exec "$HERMES_CONTAINER" hermes -p "$name" config set --force auxiliary.compression.reasoning_effort false docker exec "$HERMES_CONTAINER" hermes -p "$name" config set auxiliary.compression.timeout 120 docker exec "$HERMES_CONTAINER" hermes -p "$name" config set auxiliary.compression.max_concurrency 1 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." } while IFS=$'\t' read -r name model context description max_tokens; do create_profile "$name" "$model" "$context" "$description" "$max_tokens" done < <(jq -r --argjson max "$(jq '.max_output_tokens' "$PROFILE_MATRIX")" \ '.profiles[] | [.id,.alias,(.context|tostring),(.description|gsub("[\\t\\n]";" ")),($max|tostring)] | @tsv' \ "$PROFILE_MATRIX") # The Unraid host deliberately has no system Python. Run the small declarative # client renderer in the already version-pinned MCPHub image instead of adding # host dependencies. mcphub_registry=${MCPHUB_REGISTRY:-/mnt/nvme-storage/appdata/MCPHub/config/mcp-registry.json} [[ -s $mcphub_registry ]] || die "MCPHub-Registry fehlt: $mcphub_registry" sync_args=(--registry /run/input/mcp-registry.json) mcphub_token=${MCPHUB_TOKEN_FILE:-/mnt/nvme-storage/appdata/MCPHub/client-token} token_mount=() if [[ -s $mcphub_token ]]; then token_mount=(-v "$mcphub_token:/run/input/mcphub-token:ro") sync_args+=(--mcphub-token-file /run/input/mcphub-token) fi while IFS= read -r config; do sync_args+=(--hermes "/hermes/${config#"$HERMES_DATA_DIR"/}") done < <(find "$HERMES_DATA_DIR" -name config.yaml -type f -print) docker run --rm --entrypoint python \ -v "$STACK_DIR:/stack:ro" \ -v "$HERMES_DATA_DIR:/hermes:rw" \ -v "$mcphub_registry:/run/input/mcp-registry.json:ro" \ "${token_mount[@]}" \ casaderoll/mcphub:1.2.5 \ /stack/platform/mcp/sync-clients.py "${sync_args[@]}" "$STACK_DIR/platform/hermes/install-skills.sh" docker exec "$HERMES_CONTAINER" hermes profile list printf 'HERMES_PROFILES_OK\n'