mirror of
https://github.com/TencentCloud/TencentDB-Agent-Memory
synced 2026-07-10 12:34:27 +00:00
211 lines
6.9 KiB
Bash
Executable File
211 lines
6.9 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
# ============================================================
|
||
# seed-v2.sh — 起 standalone gateway → 跑 seed-v2 → 验落盘 → 停
|
||
#
|
||
# 这是给"想完整自动化跑一次"的用户准备的便利 wrapper。
|
||
# 不想自动起停 gateway 的话,直接 `npm run seed-v2 -- --input <file>` 即可。
|
||
#
|
||
# 用法:
|
||
# ./seed-v2.sh # 默认用 fixtures/minimal.json
|
||
# ./seed-v2.sh path/to/fixture.json # 用指定 fixture
|
||
# ./seed-v2.sh --keep # 跑完不停 gateway(调试)
|
||
# ./seed-v2.sh --no-start # 假设 gateway 已在跑(不 reset、不 start、不 stop)
|
||
# ./seed-v2.sh --no-reset # 不清空数据目录(增量灌)
|
||
#
|
||
# 透传给 seed-v2.ts 的环境变量:
|
||
# SEED_ENDPOINT / SEED_API_KEY / SEED_SERVICE_ID
|
||
# SEED_EVERY_N / SEED_POLL_MS / SEED_STABLE_ROUNDS / SEED_MAX_WAIT_MS
|
||
# SEED_VERBOSE 1=详细 / 0=安静
|
||
#
|
||
# 退出码:
|
||
# 0 成功 + 落盘断言全部通过
|
||
# 1 seed 或断言失败
|
||
# 2 前置条件不满足
|
||
# ============================================================
|
||
set -euo pipefail
|
||
|
||
# Compute our own dir BEFORE sourcing env.sh (which overwrites SCRIPT_DIR).
|
||
SEED_V2_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||
PLUGIN_ROOT="$(cd "$SEED_V2_DIR/../.." && pwd)"
|
||
STANDALONE_HELPERS="$PLUGIN_ROOT/__tests__/standalone"
|
||
|
||
# 复用 standalone 测试套件里的 env / start / stop 工具(保持一份真理之源,
|
||
# 不在这里重复实现 gateway 起停)
|
||
if [ ! -f "$STANDALONE_HELPERS/env.sh" ]; then
|
||
echo "✗ standalone helpers not found at: $STANDALONE_HELPERS" >&2
|
||
echo " this wrapper depends on env.sh / start.sh / stop.sh from there." >&2
|
||
exit 2
|
||
fi
|
||
# shellcheck disable=SC1091
|
||
source "$STANDALONE_HELPERS/env.sh"
|
||
|
||
# ============================================================
|
||
# 参数
|
||
# ============================================================
|
||
KEEP_RUNNING=0
|
||
NO_START=0
|
||
DO_RESET=1
|
||
FIXTURE="$SEED_V2_DIR/fixtures/minimal.json"
|
||
|
||
while [ $# -gt 0 ]; do
|
||
case "$1" in
|
||
--keep) KEEP_RUNNING=1 ;;
|
||
--no-start) NO_START=1; KEEP_RUNNING=1; DO_RESET=0 ;;
|
||
--no-reset) DO_RESET=0 ;;
|
||
-h|--help)
|
||
sed -n '2,25p' "$0" | sed 's/^# \?//'
|
||
exit 0
|
||
;;
|
||
-*)
|
||
log_err "unknown flag: $1"
|
||
exit 2
|
||
;;
|
||
*)
|
||
FIXTURE="$1"
|
||
;;
|
||
esac
|
||
shift
|
||
done
|
||
|
||
[ -f "$FIXTURE" ] || { log_err "fixture not found: $FIXTURE"; exit 2; }
|
||
|
||
# ============================================================
|
||
# Reset 数据目录(必须在 start.sh 之前)
|
||
# ============================================================
|
||
if [ "$DO_RESET" -eq 1 ]; then
|
||
if echo "$STANDALONE_DATA_DIR" | grep -q "/\.codebuddy/"; then
|
||
log_info "resetting data dir: $STANDALONE_DATA_DIR"
|
||
rm -rf "$STANDALONE_DATA_DIR"
|
||
else
|
||
log_err "refuse to reset $STANDALONE_DATA_DIR (must be under .codebuddy/)"
|
||
exit 2
|
||
fi
|
||
fi
|
||
|
||
# ============================================================
|
||
# 起 gateway
|
||
# ============================================================
|
||
if [ "$NO_START" -eq 0 ]; then
|
||
log_info "starting gateway..."
|
||
if ! "$STANDALONE_HELPERS/start.sh"; then
|
||
log_err "start.sh failed"
|
||
exit 2
|
||
fi
|
||
fi
|
||
|
||
if ! gateway_alive; then
|
||
log_err "gateway not reachable at $STANDALONE_BASE"
|
||
exit 2
|
||
fi
|
||
|
||
# ============================================================
|
||
# trap:保证不论结果如何,都按 KEEP_RUNNING 决定要不要停
|
||
# ============================================================
|
||
cleanup() {
|
||
local rc=$?
|
||
if [ "$KEEP_RUNNING" -eq 0 ]; then
|
||
log_info "stopping gateway"
|
||
"$STANDALONE_HELPERS/stop.sh" >/dev/null 2>&1 || true
|
||
else
|
||
log_info "gateway kept at $STANDALONE_BASE (use $STANDALONE_HELPERS/stop.sh to stop)"
|
||
fi
|
||
exit $rc
|
||
}
|
||
trap cleanup EXIT INT TERM
|
||
|
||
# ============================================================
|
||
# 跑 seed-v2(通过 npm bin)
|
||
# ============================================================
|
||
log_info "running seed-v2 with fixture: $FIXTURE"
|
||
echo
|
||
|
||
cd "$PLUGIN_ROOT"
|
||
SEED_ENDPOINT="${SEED_ENDPOINT:-$STANDALONE_BASE}" \
|
||
SEED_API_KEY="${SEED_API_KEY:-standalone-e2e}" \
|
||
SEED_SERVICE_ID="${SEED_SERVICE_ID:-default}" \
|
||
SEED_EVERY_N="${SEED_EVERY_N:-5}" \
|
||
SEED_POLL_MS="${SEED_POLL_MS:-500}" \
|
||
SEED_STABLE_ROUNDS="${SEED_STABLE_ROUNDS:-2}" \
|
||
SEED_MAX_WAIT_MS="${SEED_MAX_WAIT_MS:-600000}" \
|
||
SEED_VERBOSE="${SEED_VERBOSE:-1}" \
|
||
node "$PLUGIN_ROOT/bin/seed-v2.mjs" --input "$FIXTURE"
|
||
|
||
SEED_RC=$?
|
||
|
||
# ============================================================
|
||
# 落盘断言
|
||
# ============================================================
|
||
echo
|
||
log_info "=== Post-seed assertions ==="
|
||
|
||
ASSERT_PASS=0
|
||
ASSERT_FAIL=0
|
||
assert() {
|
||
local name="$1"
|
||
local cond="$2"
|
||
if eval "$cond" >/dev/null 2>&1; then
|
||
log_ok "$name"
|
||
ASSERT_PASS=$((ASSERT_PASS+1))
|
||
else
|
||
log_err "$name"
|
||
ASSERT_FAIL=$((ASSERT_FAIL+1))
|
||
fi
|
||
}
|
||
|
||
# 1. L0: JSONL 镜像(standalone 特有)
|
||
TODAY="$(date +%Y-%m-%d)"
|
||
JSONL_PATH="$STANDALONE_DATA_DIR/conversations/$TODAY.jsonl"
|
||
assert "L0: JSONL mirror exists" "[ -f \"$JSONL_PATH\" ]"
|
||
if [ -f "$JSONL_PATH" ]; then
|
||
JSONL_LINES=$(wc -l < "$JSONL_PATH")
|
||
log_info " JSONL line count: $JSONL_LINES"
|
||
fi
|
||
|
||
# 2. L0: SQLite (vectors.db)
|
||
DB_PATH="$STANDALONE_DATA_DIR/vectors.db"
|
||
assert "L0: SQLite vectors.db exists" "[ -f \"$DB_PATH\" ]"
|
||
SQLITE_BIN="$(command -v sqlite3 || true)"
|
||
if [ -z "$SQLITE_BIN" ] && [ -x "$HOME/miniconda3/bin/sqlite3" ]; then
|
||
SQLITE_BIN="$HOME/miniconda3/bin/sqlite3"
|
||
fi
|
||
if [ -f "$DB_PATH" ] && [ -n "$SQLITE_BIN" ]; then
|
||
L0_COUNT="$("$SQLITE_BIN" "$DB_PATH" "SELECT COUNT(*) FROM l0_conversations" 2>/dev/null || echo 0)"
|
||
log_info " SQLite l0_conversations count: $L0_COUNT"
|
||
assert "L0: SQLite has records" "[ \"$L0_COUNT\" -gt 0 ]"
|
||
else
|
||
log_info "L0: sqlite3 binary not found, skipping SQLite assertion"
|
||
fi
|
||
|
||
# 3. L1: records JSONL — 仅当 LLM key 配置时会有产出
|
||
RECORDS_DIR="$STANDALONE_DATA_DIR/records"
|
||
if [ -d "$RECORDS_DIR" ]; then
|
||
RECORD_FILES="$(find "$RECORDS_DIR" -name "*.jsonl" -size +0 2>/dev/null | wc -l)"
|
||
if [ "$RECORD_FILES" -gt 0 ]; then
|
||
log_ok "L1: records/ has $RECORD_FILES non-empty jsonl file(s) [LLM key configured]"
|
||
ASSERT_PASS=$((ASSERT_PASS+1))
|
||
else
|
||
log_info "L1: records/ exists but empty (LLM key likely not configured — skipped, not a failure)"
|
||
fi
|
||
else
|
||
log_info "L1: records/ not created (LLM key likely not configured — skipped, not a failure)"
|
||
fi
|
||
|
||
# 4. Pipeline status: busy=false at the end
|
||
STATUS_RESP="$(curl -sS -X POST "$STANDALONE_BASE/v2/pipeline/status" \
|
||
-H 'Content-Type: application/json' \
|
||
-H 'Authorization: Bearer standalone-e2e' \
|
||
-H 'x-tdai-service-id: default' \
|
||
-d '{}')"
|
||
assert "Pipeline status: busy=false at completion" \
|
||
"echo '$STATUS_RESP' | python3 -c 'import sys,json; assert json.loads(sys.stdin.read())[\"data\"][\"busy\"] is False'"
|
||
|
||
# 汇总
|
||
echo
|
||
if [ "$ASSERT_FAIL" -gt 0 ]; then
|
||
log_err "Post-seed assertions: $ASSERT_PASS passed, $ASSERT_FAIL failed"
|
||
exit 1
|
||
fi
|
||
log_ok "Post-seed assertions: $ASSERT_PASS/$ASSERT_PASS passed"
|
||
|
||
exit $SEED_RC
|