Ctrl K
ComunidadGuías…

scripts/butler-p3h-rollout-verify.sh

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
#!/usr/bin/env bash
# P3-H unified recall rollout verify — handler sim + health report + CLI (no iLink).
#
# Usage:
#   bash scripts/butler-p3h-rollout-verify.sh
#   bash scripts/butler-p3h-rollout-verify.sh --with-hermes   # also run hermes-rollout sim
set -euo pipefail

ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$ROOT"
export PYTHONPATH="$ROOT"

WITH_HERMES=0
for arg in "$@"; do
  case "$arg" in
    --with-hermes) WITH_HERMES=1 ;;
  esac
done

if [[ -f "$ROOT/.env" ]]; then
  # shellcheck source=scripts/lib/butler-source-env.sh
  source "$ROOT/scripts/lib/butler-source-env.sh"
  butler_source_env "$ROOT/.env" 2>/dev/null || true
fi

if [[ "$WITH_HERMES" == "1" ]]; then
  bash "$ROOT/scripts/butler-hermes-rollout-wechat-sim.sh"
fi

exec python3 - <<'PY'
from __future__ import annotations

import json
import os
import subprocess
import sys
import time

from butler.config import get_butler_home, reload_butler_settings

reload_butler_settings()
owner = (os.getenv("BUTLER_OWNER_WECHAT_ID") or "").strip()
if not owner:
    print("FAIL: BUTLER_OWNER_WECHAT_ID not set")
    raise SystemExit(1)

failures: list[str] = []
sk = f"wechat:{owner}:p3h-verify-{time.time_ns()}"


def ok(name: str, cond: bool, detail: str = "") -> None:
    if cond:
        print(f"  [ok] {name}" + (f" — {detail}" if detail else ""))
    else:
        failures.append(name)
        print(f"  [FAIL] {name}" + (f" — {detail}" if detail else ""))


print("=== P3-H rollout verification ===")
for key in (
    "BUTLER_MEMORY_OBSERVER_QUEUE",
    "BUTLER_MEMORY_OBSERVATION_RECALL",
    "BUTLER_MEMORY_UNIFIED_RECALL",
    "BUTLER_SEMANTIC_MEMORY",
):
    print(f"  {key}={os.getenv(key, '')!r}")

from butler.gateway.message_handler import ButlerMessageHandler
from butler.memory.butler_memory import ButlerMemory
from butler.memory.owner_write_pending import (
    approve_owner_pending,
    queue_owner_write,
    reject_all_owner_pending,
)
from butler.memory.vector_sync_telemetry import get_vector_sync_times
from butler.ops.health_report import (
    HealthReportInput,
    build_health_report,
    collect_mem_stats_for_health,
)
from butler.orchestrator import ButlerOrchestrator

reject_all_owner_pending()
bm = ButlerMemory(get_butler_home())
queue_owner_write(scope="owner_profile", content="p3h-rollout-verify: vector sync")
approve_owner_pending(0, bm)
ok("vector sync telemetry", "owner_profile" in get_vector_sync_times())

orch = ButlerOrchestrator()
health: dict = {}
full = build_health_report(
    HealthReportInput(
        session_key=sk,
        health=health,
        tool_summary={"total": 0, "failed": 0, "codes": []},
        mem_stats=collect_mem_stats_for_health(orch, sk, health),
        orchestrator=orch,
    )
)
ok("统一 hybrid 召回: 开", "统一 hybrid 召回: 开" in full)
ok("observation 辅助召回: 开", "observation 辅助召回: 开" in full)
ok("最近向量写入", "最近向量写入" in full and "owner_profile" in full)

handler = ButlerMessageHandler(channel="gateway")
detail = handler.handle_message(
    "/诊断 详细", session_key=sk, platform="wechat", external_id=owner
) or ""
ok("wechat /诊断 详细", "诊断" in detail and ("附件" in detail or "…" in detail))

root = os.getcwd()
env = {**os.environ, "PYTHONPATH": root}
py = sys.executable


def run_cli(args: list[str]) -> subprocess.CompletedProcess[str]:
    return subprocess.run(
        [py, "butler/main.py", *args],
        cwd=root,
        env=env,
        capture_output=True,
        text=True,
    )


for label, cli_args in (
    ("hybrid CLI", ["memory", "search", "pytest", "--scope", "hybrid", "--project", "普通试点项目", "--limit", "3", "--json"]),
    ("observation CLI", ["memory", "search", "read_file", "--scope", "observation", "--project", "灵文1号", "--limit", "3", "--json"]),
):
    proc = run_cli(cli_args)
    try:
        data = json.loads(proc.stdout)
        ok(label, data.get("ok") is True)
    except json.JSONDecodeError:
        ok(label, False, (proc.stderr or proc.stdout)[:160])

ok("butler doctor", run_cli(["doctor"]).returncode == 0)

print(f"\np3h-rollout-verify: {'ALL PASS' if not failures else failures}")
raise SystemExit(1 if failures else 0)
PY