Ctrl K
ComunidadGuías…

scripts/butler-wechat-attach-probe.sh

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

Archivo original ↗Preguntar a KiBot
#!/usr/bin/env bash
# Handler-level WeChat md/txt attach probe — no gateway process, no LLM.
# Verifies /详细、/诊断 详细、委派完成推送 在 wechat 平台生成 exports/ 路径行。
#
# Usage: bash scripts/butler-wechat-attach-probe.sh
set -euo pipefail

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

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

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

import os
import re
import time
from unittest.mock import patch

from butler.gateway.message_handler import ButlerMessageHandler
from butler.gateway.outbound_files import is_deliverable_export_file
from butler.gateway.wechat_text_export import build_delegate_completion_message, wechat_attach_brief_chars
from butler.report import AgentReport, cache_report, clear_report_cache

os.environ.setdefault("BUTLER_EXPORT_SEND_WECHAT_FILE", "1")
os.environ.setdefault("BUTLER_WECHAT_ATTACH_DETAIL", "1")
os.environ.setdefault("BUTLER_WECHAT_ATTACH_DIAGNOSTIC", "1")
os.environ.setdefault("BUTLER_WECHAT_ATTACH_DELEGATE", "1")

ns = time.time_ns()
owner = f"attach-probe-{ns}"
sk = f"wechat:{owner}:attach-probe"
handler = ButlerMessageHandler(channel="gateway")
errors: list[str] = []


def has_export_path(text: str) -> bool:
    for line in (text or "").splitlines():
        candidate = line.strip()
        if candidate.startswith("/") and is_deliverable_export_file(candidate):
            return True
    return False


def chat_body_before_path(text: str) -> str:
    lines: list[str] = []
    for line in (text or "").splitlines():
        candidate = line.strip()
        if candidate.startswith("/") and is_deliverable_export_file(candidate):
            break
        lines.append(line)
    return "\n".join(lines).strip()


def ends_with_brief_truncation(text: str) -> bool:
    return bool(re.search(r"\n…\s*$", (text or "").rstrip()))


def check(name: str, text: str, *, need_attach: bool, need_hint: bool = True) -> None:
    if not text or not str(text).strip():
        errors.append(f"{name}: empty reply")
        return
    if need_attach and not has_export_path(text):
        errors.append(f"{name}: missing deliverable exports/ path line")
    if need_hint and "附件" not in text:
        errors.append(f"{name}: missing 附件 hint")
    if need_attach:
        body = chat_body_before_path(text)
        cap = wechat_attach_brief_chars()
        main = body.split("(完整")[0].strip() if "(完整" in body else body
        if len(main) > cap + 5 and "…" not in body:
            errors.append(f"{name}: expected brief truncation (…)")
        if len(body) > cap + 100:
            errors.append(f"{name}: chat brief too long ({len(body)} chars)")


print("=== WeChat attach probe (handler + Owner session) ===")
print(f"session: {sk}")

with patch("butler.gateway.owner_gate.is_gateway_owner", return_value=True):
    clear_report_cache()
    cache_report(
        AgentReport(
            headline="开发代理已完成任务",
            summary="验收摘要\n" + ("详细行 " * 120),
            success=True,
            task_id="task_attach_probe",
            changes=[],
        ),
        session_key=sk,
    )

    detail = handler._handle_command(
        "/详细",
        session_key=sk,
        platform="wechat",
        external_id=owner,
    )
    print("\n--- /详细 ---")
    print((detail or "")[:280])
    check("/详细", detail or "", need_attach=True)
    if "task_attach_probe" not in (detail or ""):
        errors.append("/详细: expected cached task_attach_probe in reply")

    diag_full = handler._handle_command(
        "/诊断 详细",
        session_key=sk,
        platform="wechat",
        external_id=owner,
    )
    print("\n--- /诊断 详细 ---")
    print((diag_full or "")[:280])
    check("/诊断 详细", diag_full or "", need_attach=True)

    report = AgentReport(
        headline="开发代理已完成任务",
        summary="done " * 200,
        success=True,
        task_id="task_delegate_probe",
        changes=[],
    )
    delegate_msg = build_delegate_completion_message(report, platform="wechat")
    print("\n--- delegate completion ---")
    print(delegate_msg[:280])
    check("delegate completion", delegate_msg, need_attach=True)

    cli_diag = handler._handle_command(
        "/诊断 详细",
        session_key=sk,
        platform="cli",
        external_id=owner,
    )
    if has_export_path(cli_diag or ""):
        errors.append("cli /诊断 详细: should not embed export path")
    if ends_with_brief_truncation(cli_diag or ""):
        errors.append("cli /诊断 详细: should not truncate with …")

if errors:
    print("\nFAIL:")
    for err in errors:
        print(f"  - {err}")
    raise SystemExit(1)

print("\nOK: WeChat attach probe passed")
PY