OpenClaw-Setup/openclaw-setup-max/scripts/model_hygiene_workflow.sh

190 lines
5.9 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
PROFILES_CONFIG="${MODEL_PROFILES_CONFIG:-$ROOT_DIR/config/model-profiles.config.json}"
BUDGET_CONFIG="${MODEL_GUARD_CONFIG:-$ROOT_DIR/config/model-budget-guard.config.json}"
AUTH_STORE="${OPENCLAW_AUTH_STORE:-$HOME/.openclaw/agents/main/agent/auth-profiles.json}"
if ! command -v jq >/dev/null 2>&1; then
echo "[model-hygiene] jq is required" >&2
exit 1
fi
if ! command -v openclaw >/dev/null 2>&1; then
echo "[model-hygiene] openclaw CLI is required" >&2
exit 1
fi
usage() {
cat <<'USAGE'
Usage:
bash ./scripts/model_hygiene_workflow.sh <profile> [--no-live] [--no-guards]
Behavior:
1) Applies profile via model_profile_switch.sh
2) Reinstalls guard LaunchAgents (unless --no-guards)
3) Prunes legacy models/providers/auth not referenced by config
4) Prints models status
Examples:
bash ./scripts/model_hygiene_workflow.sh paid
bash ./scripts/model_hygiene_workflow.sh free --no-live
USAGE
}
in_array() {
local needle="$1"
shift
local item
for item in "$@"; do
if [[ "$item" == "$needle" ]]; then
return 0
fi
done
return 1
}
profile="${1:-}"
if [[ -z "$profile" ]]; then
usage
exit 1
fi
if [[ "$profile" == "-h" || "$profile" == "--help" ]]; then
usage
exit 0
fi
shift || true
apply_live="true"
install_guards="true"
while (( "$#" )); do
case "$1" in
--no-live) apply_live="false" ;;
--no-guards) install_guards="false" ;;
-h|--help)
usage
exit 0
;;
*)
echo "[model-hygiene] unknown argument: $1" >&2
usage
exit 1
;;
esac
shift
done
if [[ ! -f "$PROFILES_CONFIG" ]]; then
echo "[model-hygiene] missing config: $PROFILES_CONFIG" >&2
exit 1
fi
profile_exists="$(jq -r --arg p "$profile" '.profiles[$p] != null' "$PROFILES_CONFIG")"
if [[ "$profile_exists" != "true" ]]; then
echo "[model-hygiene] unknown profile '$profile'" >&2
jq -r '.profiles | keys[]' "$PROFILES_CONFIG" | sed 's/^/ - /'
exit 1
fi
echo "[model-hygiene] collecting managed models/providers from config"
keep_models=()
while IFS= read -r model; do
[[ -z "$model" ]] && continue
if ! in_array "$model" "${keep_models[@]-}"; then
keep_models+=("$model")
fi
done < <(jq -r '.profiles | to_entries[] | .value.primary, (.value.fallbacks[]? // empty)' "$PROFILES_CONFIG")
if [[ -f "$BUDGET_CONFIG" ]]; then
while IFS= read -r model; do
[[ -z "$model" ]] && continue
if ! in_array "$model" "${keep_models[@]-}"; then
keep_models+=("$model")
fi
done < <(jq -r '.lowModel // empty, (.highModels[]? // empty)' "$BUDGET_CONFIG")
fi
if [[ ${#keep_models[@]} -eq 0 ]]; then
echo "[model-hygiene] no models discovered in config; aborting" >&2
exit 1
fi
keep_providers=()
for model in "${keep_models[@]}"; do
provider="${model%%/*}"
[[ -z "$provider" || "$provider" == "$model" ]] && continue
if ! in_array "$provider" "${keep_providers[@]-}"; then
keep_providers+=("$provider")
fi
done
echo "[model-hygiene] applying profile '$profile'"
switch_args=("$profile" "--no-status")
if [[ "$apply_live" != "true" ]]; then
switch_args+=("--no-live")
fi
bash "$SCRIPT_DIR/model_profile_switch.sh" "${switch_args[@]}"
if [[ "$install_guards" == "true" ]]; then
echo "[model-hygiene] reinstalling guard LaunchAgents"
bash "$SCRIPT_DIR/install_local_model_guardrails.sh" >/dev/null
fi
echo "[model-hygiene] pruning legacy configured models"
current_models_json="$(openclaw config get agents.defaults.models 2>/dev/null || echo '{}')"
while IFS= read -r model; do
[[ -z "$model" ]] && continue
if ! in_array "$model" "${keep_models[@]-}"; then
openclaw config unset "agents.defaults.models[$model]" >/dev/null || true
fi
done < <(jq -r 'keys[]? // empty' <<<"$current_models_json")
for model in "${keep_models[@]}"; do
openclaw config set --json "agents.defaults.models[$model]" '{}' >/dev/null || true
done
echo "[model-hygiene] pruning legacy aliases"
while IFS=$'\t' read -r alias target; do
[[ -z "$alias" || -z "$target" ]] && continue
if ! in_array "$target" "${keep_models[@]-}"; then
openclaw models aliases remove "$alias" >/dev/null || true
fi
done < <(openclaw models status --json 2>/dev/null | jq -r '.aliases // {} | to_entries[] | "\(.key)\t\(.value)"')
echo "[model-hygiene] pruning legacy provider blocks"
providers_json="$(openclaw config get models.providers 2>/dev/null || echo '{}')"
while IFS= read -r provider; do
[[ -z "$provider" ]] && continue
if ! in_array "$provider" "${keep_providers[@]-}"; then
openclaw config unset "models.providers.$provider" >/dev/null || true
fi
done < <(jq -r 'keys[]? // empty' <<<"$providers_json")
echo "[model-hygiene] pruning legacy auth profiles in openclaw config"
auth_profiles_json="$(openclaw config get auth.profiles 2>/dev/null || echo '{}')"
while IFS=$'\t' read -r profile_id provider; do
[[ -z "$profile_id" || -z "$provider" ]] && continue
if ! in_array "$provider" "${keep_providers[@]-}"; then
openclaw config unset "auth.profiles[$profile_id]" >/dev/null || true
fi
done < <(jq -r 'to_entries[]? | "\(.key)\t\(.value.provider // empty)"' <<<"$auth_profiles_json")
if [[ -f "$AUTH_STORE" ]]; then
echo "[model-hygiene] pruning legacy auth profiles in auth store"
keep_providers_json="$(printf '%s\n' "${keep_providers[@]-}" | jq -R . | jq -s .)"
tmp_auth="$(mktemp)"
jq --argjson keep "$keep_providers_json" '
.profiles |= with_entries(select((.value.provider // "") as $p | ($keep | index($p)) != null))
| .lastGood |= with_entries(select(.key as $p | ($keep | index($p)) != null))
| .usageStats |= with_entries(select((.key | split(":")[0]) as $p | ($keep | index($p)) != null))
' "$AUTH_STORE" > "$tmp_auth"
mv "$tmp_auth" "$AUTH_STORE"
fi
echo "[model-hygiene] complete"
echo "[model-hygiene] providers kept: ${keep_providers[*]}"
echo "[model-hygiene] models kept: ${keep_models[*]}"
echo ""
openclaw models status