feat(ws4): Hermes NL 自然語言介面 — 12-Agent Claude SDK 接入(ADR-094/095)

## hermes/ 套件(5 個新模組)

### display_names.py
- 12 agent 視覺識別表(emoji + hashtag + handle + short_name)
- format_response_header() 產生 Telegram 前綴

### agent_loader.py
- 解析 .claude/agents/*.md frontmatter → system prompt
- lru_cache 避免重複讀檔

### safety_hooks.py
- 移植 awoooi-guard.js 20 條 HARD BLOCK 規則(DENY_PATTERNS)
- 5 條 MUTATE_PATTERNS → 須走審批流

### nl_gateway.py
- Layer 1: 關鍵字正則路由(12 條規則,<10ms)
- Layer 3: DEFAULT_AGENT = "debugger"
- Claude Agent SDK query() 非同步串流,取 ResultMessage.result
- 安全降級:SDK error → 友好錯誤訊息

### telegram_webhook.py
- WS4 Hermes NL 接入(@tsenyangbot mention 或私訊觸發)
- HERMES_NL_ENABLED=False(feature flag 保護,預設關閉)

## telegram_gateway.py
- send_hermes_reply(text, chat_id, reply_to_message_id)
  無 500 字截斷,支援 Agent 長回覆

## config.py
- HERMES_NL_ENABLED: bool = False
- TELEGRAM_BOT_USERNAME: str = "tsenyangbot"

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Your Name
2026-04-25 02:05:18 +08:00
parent 5675e7c3b0
commit 2572ec46d2
8 changed files with 361 additions and 5 deletions

View File

@@ -0,0 +1,37 @@
"""載入 .claude/agents/*.md 並解析 system promptADR-095
2026-04-24 Claude Sonnet 4.6 (WS4 Hermes NL)
"""
from __future__ import annotations
import pathlib
from functools import lru_cache
_AGENTS_DIR = pathlib.Path("/Users/ogt/awoooi/.claude/agents")
def _parse_agent_md(path: pathlib.Path) -> str:
"""去除 YAML frontmatter回傳 body 作為 system prompt"""
text = path.read_text(encoding="utf-8")
# --- frontmatter ---
if text.startswith("---"):
end = text.find("---", 3)
if end != -1:
return text[end + 3:].strip()
return text.strip()
@lru_cache(maxsize=None)
def get_agent_system_prompt(agent_name: str) -> str | None:
"""
回傳指定 agent 的 system prompt。
若 .md 不存在回傳 Nonecaller 決定是否 fallback
"""
path = _AGENTS_DIR / f"{agent_name}.md"
if not path.exists():
return None
return _parse_agent_md(path)
def list_available_agents() -> list[str]:
"""回傳目前存在的 agent 名稱列表(無副檔名)"""
return [p.stem for p in sorted(_AGENTS_DIR.glob("*.md"))]