chore: tdai-gateway 看门狗 + skill-curator/learner/daemon 修复
- 新增 tdai-gateway-watchdog.sh(每30min检查 systemd active + 8420 端口,异常飞书报警) - skill-curator: PROTECTED_SKILLS + stopwords + .archive 扫描修复 - learner: pattern 支持度≥2 门禁 + episode_id 返回值修复 - daemon: L1→L2 蒸馏 procedural 分类
This commit is contained in:
parent
73029308da
commit
af0ebff46b
|
|
@ -1297,6 +1297,9 @@ def _cleanup_expired_cares():
|
|||
follow_up = c.get("follow_up_date", "2099-12-31")
|
||||
if follow_up < (today - timedelta(days=7)).isoformat():
|
||||
continue
|
||||
# stale 状态 → 物理删除(stale 不再需要保留记录)
|
||||
if c.get("status") == "stale":
|
||||
continue
|
||||
created = c.get("created_at", "")
|
||||
status = c.get("status", "pending")
|
||||
if status == "pending" and created:
|
||||
|
|
|
|||
|
|
@ -26,17 +26,45 @@ from collections import defaultdict
|
|||
from datetime import datetime
|
||||
|
||||
SKILLS_DIR = os.path.expanduser("~/.hermes/skills")
|
||||
ARCHIVE_DIR = os.path.join(SKILLS_DIR, "_archive")
|
||||
QUARANTINE_DIR = os.path.join(SKILLS_DIR, "_quarantine")
|
||||
ARCHIVE_DIR = os.path.join(SKILLS_DIR, ".archive")
|
||||
QUARANTINE_DIR = os.path.join(SKILLS_DIR, ".quarantine")
|
||||
REPORT_PATH = os.path.expanduser("~/.hermes/skill-curator-report.json")
|
||||
|
||||
# ── 保护名单 ──────────────────────────────────────
|
||||
# 这些技能被 cron jobs / SOUL.md / 系统组件直接引用,低频使用≠可删除。
|
||||
# 任何情况下不进入归档/删除建议(保护=不归档、不删除、不在报告中列为 candidate)。
|
||||
PROTECTED_SKILLS = {
|
||||
# 系统核心(cron / SOUL 引用)
|
||||
"zhiyi", "hermes-agent", "hermes-self-improvement", "self-healing-infrastructure",
|
||||
"accounting-voucher-ocr", "ao-orchestrator", "team-composer", "daily-recap",
|
||||
"soulful-framework", "openclaw", "openclaw-mcp", "stock-research",
|
||||
# 应急/铁律技能(低频=正常)
|
||||
"hermes-venv-dependency-safety", "bge-embed-crash-loop-fix",
|
||||
"cbm-code-analysis", "code-intelligence", "hermes-debug",
|
||||
"hermes-profile-gateway-troubleshooting", "llm-gateway-ops",
|
||||
"provider-tiering", "self-hosted-tunneling", "systematic-debugging",
|
||||
"web-content-extraction", "ocr-and-documents", "feishu", "feishu-bot",
|
||||
"zhiyi",
|
||||
}
|
||||
|
||||
# 通用/运维词 — 重叠检测时过滤(避免 himalaya 式 100% 幻觉)
|
||||
OVERLAP_STOPWORDS = {
|
||||
"use", "when", "for", "the", "and", "with", "that", "this", "from", "via",
|
||||
"to", "in", "of", "a", "an", "is", "are", "on", "at", "by", "or", "as",
|
||||
"be", "it", "its", "available", "readiness", "status", "tool", "skill",
|
||||
"cli", "api", "install", "config", "how", "what", "using", "used",
|
||||
"building", "setup", "set", "up", "down", "run", "running", "work",
|
||||
"works", "working", "can", "will", "would", "should", "need", "needs",
|
||||
"check", "checks", "support", "supports", "help", "helps", "manage",
|
||||
}
|
||||
|
||||
# ── 读取所有技能 ──────────────────────────────────
|
||||
|
||||
def load_all_skills():
|
||||
"""遍历 skills/ 下所有子目录,读取 SKILL.md frontmatter"""
|
||||
skills = []
|
||||
for root, dirs, files in os.walk(SKILLS_DIR):
|
||||
if "_archive" in root or "_quarantine" in root:
|
||||
if ".archive" in root or ".quarantine" in root or "_archive" in root or "_quarantine" in root:
|
||||
continue
|
||||
if "SKILL.md" in files:
|
||||
path = os.path.join(root, "SKILL.md")
|
||||
|
|
@ -144,7 +172,9 @@ def score_skill(s):
|
|||
|
||||
return min(100, max(0, score))
|
||||
|
||||
def tier_from_score(score, has_version):
|
||||
def tier_from_score(score, has_version, name=""):
|
||||
if name in PROTECTED_SKILLS:
|
||||
return 0, "core"
|
||||
if has_version and score >= 60:
|
||||
return 0, "core"
|
||||
if score >= 40:
|
||||
|
|
@ -168,7 +198,7 @@ def detect_overlaps(skills):
|
|||
tj = set(re.findall(r'[a-z0-9\-]+', descs[j]))
|
||||
|
||||
# Filter common words
|
||||
stopwords = {"use", "when", "for", "the", "and", "with", "that", "this", "from", "via", "to", "in", "of", "a", "an", "is", "are", "on", "at", "by", "or", "as", "be", "it", "its"}
|
||||
stopwords = OVERLAP_STOPWORDS
|
||||
ti = ti - stopwords
|
||||
tj = tj - stopwords
|
||||
|
||||
|
|
@ -201,7 +231,7 @@ def generate_report(skills):
|
|||
scored = []
|
||||
for s in skills:
|
||||
s["score"] = score_skill(s)
|
||||
s["tier"], s["tier_name"] = tier_from_score(s["score"], s.get("has_version", False))
|
||||
s["tier"], s["tier_name"] = tier_from_score(s["score"], s.get("has_version", False), s.get("name", ""))
|
||||
scored.append(s)
|
||||
|
||||
tiers = defaultdict(list)
|
||||
|
|
@ -230,12 +260,12 @@ def generate_report(skills):
|
|||
][:20],
|
||||
"stale_no_version": [
|
||||
{"name": s["name"], "category": s.get("category",""), "score": s["score"]}
|
||||
for s in scored if not s.get("has_version") and s["tier"] < 3
|
||||
for s in scored if not s.get("has_version") and s["tier"] < 3 and s["name"] not in PROTECTED_SKILLS
|
||||
],
|
||||
"tier0_core": [s["name"] for s in scored if s["tier"] == 0],
|
||||
"tier1_active": [s["name"] for s in scored if s["tier"] == 1],
|
||||
"tier2_legacy": [s["name"] for s in scored if s["tier"] == 2],
|
||||
"tier3_archive_candidate": [s["name"] for s in scored if s["tier"] == 3 and s["score"] < 20],
|
||||
"tier3_archive_candidate": [s["name"] for s in scored if s["tier"] == 3 and s["score"] < 20 and s["name"] not in PROTECTED_SKILLS],
|
||||
"all_skills": sorted([{
|
||||
"name": s["name"],
|
||||
"version": s.get("version", "N/A"),
|
||||
|
|
@ -279,6 +309,8 @@ def execute_cleanup(skills, dry_run=True):
|
|||
|
||||
# Archive Tier 3 skills (no version, score < 20, small size)
|
||||
for s in skills:
|
||||
if s.get("name") in PROTECTED_SKILLS:
|
||||
continue
|
||||
if not s.get("has_version") and s["score"] < 20 and s.get("size_kb", 999) < 100:
|
||||
if s["tier"] >= 2:
|
||||
action = f"ARCHIVE {s['rel_dir']}: stale (no version, score={s['score']})"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,25 @@
|
|||
#!/bin/bash
|
||||
# tdai-gateway 看门狗:检查 systemd 服务 active + 8420 端口监听
|
||||
# 正常 → 静默(空输出);异常 → 输出报警(no-agent cron 会发送)
|
||||
# 创建:2026-08-02,修复 systemd 崩溃循环 2534 次后补的监控
|
||||
|
||||
ALERT=""
|
||||
|
||||
if ! systemctl --user is-active tdai-gateway >/dev/null 2>&1; then
|
||||
STATE=$(systemctl --user is-active tdai-gateway 2>/dev/null || echo unknown)
|
||||
ALERT="tdai-gateway systemd 服务状态异常: ${STATE}"
|
||||
fi
|
||||
|
||||
if ! ss -tln 2>/dev/null | grep -q ':8420 '; then
|
||||
ALERT="${ALERT}${ALERT:+ | }tdai-gateway 端口 8420 未监听"
|
||||
fi
|
||||
|
||||
if [ -n "$ALERT" ]; then
|
||||
echo "🔴 tdai-gateway 异常 $(date '+%F %T')"
|
||||
echo "$ALERT"
|
||||
systemctl --user status tdai-gateway --no-pager 2>&1 | head -12
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# 正常:空输出 = 静默
|
||||
exit 0
|
||||
Loading…
Reference in New Issue