Files
TencentDB-Agent-Memory/scripts/sync-hermes-llm-to-tdai.sh
T
2026-05-29 17:51:28 +08:00

234 lines
7.8 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
#
# sync-hermes-llm-to-tdai.sh — 读取系统 Hermes 模型配置,同步到 TDAI Gateway
#
# 前置条件:
# 1. memory-tencentdb-ctl.sh 存在
# 2. ~/.hermes/config.yaml 存在且包含模型配置
#
# 用法:
# bash sync-hermes-llm-to-tdai.sh [--restart] [--dry-run] [--hermes]
#
# 参数语义:
# --restart 仅当 CTL 脚本的 `status` 显示 Gateway 当前为 RUNNING 时,
# 才透传给 `memory-tencentdb-ctl.sh config llm` 执行重启;
# 若当前未运行,则本脚本只同步配置,不拉起新进程。
# --hermes 以 hermes 集成模式调用 CTL(影响 status 判定与配置落点)
# --standalone 以 standalone 模式调用 CTL
# --dry-run 透传给 CTL,预演写配置但不真正落盘
#
# 可选环境变量:
# HERMES_HOME hermes 主目录(默认 ~/.hermes
# MEMORY_TENCENTDB_ROOT TDAI 统一根目录(默认 ~/.memory-tencentdb
#
set -euo pipefail
SCRIPT_NAME="sync-hermes-llm-to-tdai"
USER_HOME="${HOME:-$(eval echo "~$(whoami)")}"
# ============================================================
# 路径
# ============================================================
HERMES_HOME="${HERMES_HOME:-$USER_HOME/.hermes}"
HERMES_CONFIG="$HERMES_HOME/config.yaml"
MEMORY_TENCENTDB_ROOT="${MEMORY_TENCENTDB_ROOT:-$USER_HOME/.memory-tencentdb}"
TDAI_INSTALL_DIR="${TDAI_INSTALL_DIR:-$MEMORY_TENCENTDB_ROOT/tdai-memory-openclaw-plugin}"
CTL_SCRIPT="$TDAI_INSTALL_DIR/scripts/memory-tencentdb-ctl.sh"
# ============================================================
# 通用 helpers
# ============================================================
log() { printf '[%s] %s\n' "$SCRIPT_NAME" "$*"; }
warn() { printf '[%s:warn] %s\n' "$SCRIPT_NAME" "$*" >&2; }
die() { printf '[%s:error] %s\n' "$SCRIPT_NAME" "$*" >&2; exit "${2:-1}"; }
should_restart_gateway() {
local ctl_mode_args=()
case "${SYNC_MODE:-standalone}" in
hermes) ctl_mode_args+=("--hermes") ;;
*) ctl_mode_args+=("--standalone") ;;
esac
local status_out
status_out="$(bash "$CTL_SCRIPT" "${ctl_mode_args[@]}" status 2>&1 || true)"
if printf '%s\n' "$status_out" | grep -Eq 'state[[:space:]]*:[[:space:]]*RUNNING'; then
log "通过 ctl status 检测到 Gateway 正在运行,允许执行 --restart"
return 0
fi
warn "ctl status 未显示 Gateway 处于 RUNNING;本次仅同步配置,不执行 --restart,也不会拉起新进程。"
return 1
}
# ============================================================
# Step 1: 检查 memory-tencentdb-ctl.sh 是否存在
# ============================================================
if [[ ! -f "$CTL_SCRIPT" ]]; then
# 也尝试旧路径
_LEGACY_CTL="$USER_HOME/tdai-memory-openclaw-plugin/scripts/memory-tencentdb-ctl.sh"
if [[ -f "$_LEGACY_CTL" ]]; then
CTL_SCRIPT="$_LEGACY_CTL"
warn "使用旧路径: $CTL_SCRIPT"
else
die "memory-tencentdb-ctl.sh 不存在,TDAI 未安装。退出。" 1
fi
fi
log "找到 ctl 脚本: $CTL_SCRIPT"
# ============================================================
# Step 2: 检查 hermes config.yaml
# ============================================================
if [[ ! -f "$HERMES_CONFIG" ]]; then
die "Hermes 配置文件不存在: $HERMES_CONFIG" 1
fi
log "读取 Hermes 配置: $HERMES_CONFIG"
# ============================================================
# Step 3: 从 hermes config.yaml 提取模型配置
# ============================================================
need_cmd() {
command -v "$1" >/dev/null 2>&1 || die "必需命令未找到: $1" 127
}
need_cmd python3
# 使用 python3 安全解析 YAML,提取 model 段的 default / base_url / api_key
read_hermes_model_config() {
python3 - "$HERMES_CONFIG" <<'PYEOF'
import sys, json
config_path = sys.argv[1]
# 尝试使用 PyYAML;如果不存在则手动逐行解析
try:
import yaml
with open(config_path, "r", encoding="utf-8") as f:
cfg = yaml.safe_load(f) or {}
model_section = cfg.get("model", {})
result = {
"model": model_section.get("default", ""),
"base_url": model_section.get("base_url", ""),
"api_key": model_section.get("api_key", ""),
}
print(json.dumps(result))
except ImportError:
# PyYAML 不可用,用简单逐行解析提取 model 段
import re
with open(config_path, "r", encoding="utf-8") as f:
lines = f.readlines()
in_model = False
result = {"model": "", "base_url": "", "api_key": ""}
for line in lines:
stripped = line.rstrip("\n")
# 检测 model: 顶层段
if re.match(r"^model:\s*$", stripped) or re.match(r"^model:\s*#", stripped):
in_model = True
continue
# 进入新的顶层段则退出
if in_model and re.match(r"^[A-Za-z_]", stripped):
break
if in_model:
m = re.match(r"^\s+default:\s*(.+)", stripped)
if m:
result["model"] = m.group(1).strip().strip("'\"")
m = re.match(r"^\s+base_url:\s*(.+)", stripped)
if m:
result["base_url"] = m.group(1).strip().strip("'\"")
m = re.match(r"^\s+api_key:\s*(.+)", stripped)
if m:
result["api_key"] = m.group(1).strip().strip("'\"")
print(json.dumps(result))
PYEOF
}
MODEL_JSON="$(read_hermes_model_config)"
HERMES_MODEL="$(printf '%s' "$MODEL_JSON" | python3 -c 'import json,sys; print(json.load(sys.stdin)["model"])')"
HERMES_BASE_URL="$(printf '%s' "$MODEL_JSON" | python3 -c 'import json,sys; print(json.load(sys.stdin)["base_url"])')"
HERMES_API_KEY="$(printf '%s' "$MODEL_JSON" | python3 -c 'import json,sys; print(json.load(sys.stdin)["api_key"])')"
# 校验必需字段
if [[ -z "$HERMES_MODEL" ]]; then
die "Hermes 配置中 model.default 为空" 1
fi
if [[ -z "$HERMES_BASE_URL" ]]; then
die "Hermes 配置中 model.base_url 为空" 1
fi
if [[ -z "$HERMES_API_KEY" ]]; then
die "Hermes 配置中 model.api_key 为空" 1
fi
log "Hermes 模型配置:"
log " model = $HERMES_MODEL"
log " base_url = $HERMES_BASE_URL"
log " api_key = <${#HERMES_API_KEY} chars>"
# ============================================================
# Step 4: 透传参数(--restart / --dry-run / --hermes
# ============================================================
CTL_EXTRA_ARGS=()
SYNC_MODE="standalone"
REQUEST_RESTART=0
for arg in "$@"; do
case "$arg" in
--restart)
REQUEST_RESTART=1
;;
--hermes)
SYNC_MODE="hermes"
CTL_EXTRA_ARGS+=("$arg")
;;
--standalone)
SYNC_MODE="standalone"
CTL_EXTRA_ARGS+=("$arg")
;;
--dry-run)
CTL_EXTRA_ARGS+=("$arg")
;;
*)
warn "忽略未知参数: $arg"
;;
esac
done
if [[ $REQUEST_RESTART -eq 1 ]]; then
# 新语义:--restart 只在 Gateway 当前已运行时才生效。
# 这里复用 CTL 的 status 输出作为唯一事实来源,避免本脚本
# 自己维护另一套“端口监听/健康检查”判定逻辑。
if should_restart_gateway; then
CTL_EXTRA_ARGS+=("--restart")
else
log "已按新逻辑跳过 --restart。"
fi
fi
# ============================================================
# Step 5: 调用 memory-tencentdb-ctl.sh config llm 同步配置
# ============================================================
log "调用 memory-tencentdb-ctl.sh config llm 同步配置到 TDAI ..."
bash "$CTL_SCRIPT" "${CTL_EXTRA_ARGS[@]+"${CTL_EXTRA_ARGS[@]}"}" \
config llm \
--api-key "$HERMES_API_KEY" \
--base-url "$HERMES_BASE_URL" \
--model "$HERMES_MODEL"
log "同步完成。"
log ""
log "如需立即重启 Gateway 使配置生效,请重新运行并追加 --restart"
log " bash $0 --restart"