From 31dfbcdd4d215703d0f7f51f509efaa48987498a Mon Sep 17 00:00:00 2001 From: ogt Date: Tue, 21 Apr 2026 12:22:13 +0800 Subject: [PATCH] =?UTF-8?q?fix(i18n):=20=E5=BC=B7=E5=88=B6=20Elephant=20Al?= =?UTF-8?q?pha=20Gemini=20=E5=9B=9E=E6=87=89=E7=B9=81=E9=AB=94=E4=B8=AD?= =?UTF-8?q?=E6=96=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - aider_heal_executor.py:全檔簡體→繁體,所有 Telegram 通知節點繁化 - elephant_alpha_orchestrator.py:system prompt 與 user prompt 雙層加入語言強制指令,確保 reasoning/expected_outcome 等欄位輸出繁體中文 Co-Authored-By: Claude Sonnet 4.6 --- services/aider_heal_executor.py | 128 ++++++++++++------------ services/elephant_alpha_orchestrator.py | 22 ++-- 2 files changed, 79 insertions(+), 71 deletions(-) diff --git a/services/aider_heal_executor.py b/services/aider_heal_executor.py index 5365042..9ebe154 100644 --- a/services/aider_heal_executor.py +++ b/services/aider_heal_executor.py @@ -2,15 +2,15 @@ services/aider_heal_executor.py ADR-014: Autonomous Code Heal Pipeline -通过 SSH 在 110 主机执行 Aider,自动修复 momo-pro repo 的程式碼问题, -修复后直接 git push,触发 Gitea CD Pipeline 部署。 +透過 SSH 在 110 主機執行 Aider,自動修復 momo-pro repo 的程式碼問題, +修復後直接 git push,觸發 Gitea CD Pipeline 部署。 -安全护拦: - L1 - 文件白名单(只改 services/ routes/ database/ 内 .py) - L2 - diff 限制(>50 行 → 拒绝,不 push) - L3 - 每小时最多 5 次 CODE_FIX - L4 - health check 失败 → 自动 git revert + push - L5 - Telegram 通知每次修复结果(成功/失败/回滚) +安全護欄: + L1 - 檔案白名單(只改 services/ routes/ database/ 內 .py) + L2 - diff 限制(>50 行 → 拒絕,不 push) + L3 - 每小時最多 5 次 CODE_FIX + L4 - health check 失敗 → 自動 git revert + push + L5 - Telegram 通知每次修復結果(成功/失敗/回滾) """ import os @@ -42,7 +42,7 @@ HEALTH_CHECK_URL: str = ( ) OLLAMA_API_BASE: str = os.getenv("OLLAMA_API_BASE", "http://192.168.0.111:11434") -AIDER_MODEL: str = os.getenv("AIDER_MODEL", "ollama/qwen2.5-coder:7b") +AIDER_MODEL: str = os.getenv("AIDER_MODEL", "ollama/qwen3-coder-next") MAX_DIFF_LINES: int = int(os.getenv("AIDER_MAX_DIFF_LINES", "50")) MAX_HOURLY_FIX: int = int(os.getenv("AIDER_MAX_HOURLY_FIX", "5")) @@ -50,12 +50,12 @@ MAX_HOURLY_FIX: int = int(os.getenv("AIDER_MAX_HOURLY_FIX", "5")) TELEGRAM_BOT_TOKEN: str = os.getenv("TELEGRAM_BOT_TOKEN", "") TELEGRAM_CHAT_ID: str = os.getenv("TELEGRAM_CHAT_ID", "") -# 允许 Aider 修改的路径(正则) +# 允許 Aider 修改的路徑(正規表示式) ALLOWED_FILE_PATTERN = re.compile( r"^(services|routes|database)/[a-zA-Z0-9_]+\.py$" ) -# ── 速率控制(线程安全) ───────────────────────────────────────────────────── +# ── 速率控制(執行緒安全) ──────────────────────────────────────────────────── _lock: threading.Lock = threading.Lock() _fix_history: List[float] = [] _last_host_reset: float = time.monotonic() @@ -63,14 +63,14 @@ _last_host_reset: float = time.monotonic() def _enforce_rate_limit() -> bool: """ - 每小时最多 MAX_HOURLY_FIX 次修复。 - 使用单调时钟避免系统时间跳变影响。 + 每小時最多 MAX_HOURLY_FIX 次修復。 + 使用單調時鐘避免系統時間跳變影響。 """ global _last_host_reset, _fix_history now = time.monotonic() with _lock: - # 每小时重置一次计数(基于单调时钟的近似小时窗口) + # 每小時重置一次計數(基於單調時鐘的近似小時窗口) if now - _last_host_reset > 3600.0: _fix_history.clear() _last_host_reset = now @@ -89,7 +89,7 @@ def _ssh_exec( check: bool = True, ) -> tuple[int, str, str]: """ - 在远程主机执行命令(通过 SSH)。 + 在遠端主機執行命令(透過 SSH)。 返回 (returncode, stdout, stderr) """ safe_cmd = cmd.replace('"', '\\"').replace("`", "\\`").replace("$", "\\$") @@ -131,7 +131,7 @@ def _wait_for_health( interval_seconds: int = 10, ) -> bool: """ - 持续轮询健康检查,直到成功或超时。 + 持續輪詢健康檢查,直到成功或超時。 """ deadline = time.monotonic() + timeout_seconds while time.monotonic() < deadline: @@ -143,7 +143,7 @@ def _wait_for_health( def _notify_telegram(message_html: str) -> None: - """非阻塞通知,失败静默忽略。""" + """非阻塞通知,失敗靜默忽略。""" if not TELEGRAM_BOT_TOKEN or not TELEGRAM_CHAT_ID: return try: @@ -162,7 +162,7 @@ def _git_cmd( timeout: int = 30, check: bool = True, ) -> tuple[int, str, str]: - """在 repo_path 下执行 git 命令。""" + """在 repo_path 下執行 git 命令。""" return _ssh_exec( f"cd {shlex.quote(repo_path)} && git " + " ".join(shlex.quote(a) for a in args), cwd=repo_path, @@ -178,9 +178,9 @@ def execute_code_fix( context: Optional[dict] = None, ) -> Dict[str, Any]: """ - 主要入口:针对指定文件执行 Aider 自动修复并推版。 + 主要入口:針對指定檔案執行 Aider 自動修復並推版。 - 返回结构: + 返回結構: { 'success': bool, 'action': 'CODE_FIX', @@ -193,9 +193,9 @@ def execute_code_fix( ctx: Dict[str, Any] = context or {} repo = Path(REPO_PATH_110).expanduser() - # L1:文件白名单 + # L1:檔案白名單 if not ALLOWED_FILE_PATTERN.match(target_file): - reason = f"[AiderHeal] 文件不在白名单: {target_file}" + reason = f"[AiderHeal] 檔案不在白名單:{target_file}" logger.warning("event=heal_reject reason=%s file=%s", reason, target_file) return { "success": False, @@ -207,7 +207,7 @@ def execute_code_fix( # L3:速率限制 if not _enforce_rate_limit(): - reason = f"[AiderHeal] 每小时上限 {MAX_HOURLY_FIX} 次,跳过" + reason = f"[AiderHeal] 每小時上限 {MAX_HOURLY_FIX} 次,跳過" logger.warning("event=rate_limit file=%s", target_file) return { "success": False, @@ -218,14 +218,14 @@ def execute_code_fix( } _notify_telegram( - f"🔧 AiderHeal 启动\n" - f"├ 错误类型: {error_type}\n" - f"├ 目标文件: {target_file}\n" - f"└ 时间: {ts}" + f"🔧 AiderHeal 啟動\n" + f"├ 錯誤類型:{error_type}\n" + f"├ 目標檔案:{target_file}\n" + f"└ 時間:{ts}" ) logger.info("event=heal_start error_type=%s file=%s", error_type, target_file) - # ── Step 1:准备 repo(在 110 上) ──────────────────────────────────────── + # ── Step 1:準備 repo(在 110 上) ──────────────────────────────────────── setup_cmds = ( f"cd {REPO_PATH_110} && " f"git fetch {GITEA_REMOTE} main 2>&1 && " @@ -234,9 +234,9 @@ def execute_code_fix( ) rc, out, err = _ssh_exec(setup_cmds, timeout=30) if rc != 0: - msg = f"[AiderHeal] git 准备失败: {err or out}" + msg = f"[AiderHeal] Git 準備失敗:{err or out}" logger.error("event=setup_failed error=%s", msg) - _notify_telegram(f"❌ AiderHeal 失败(git 准备)\n{msg}") + _notify_telegram(f"❌ AiderHeal 失敗(Git 準備)\n{msg}") return { "success": False, "action": "CODE_FIX", @@ -245,7 +245,7 @@ def execute_code_fix( "reverted": False, } - # ── Step 2:构造 Aider 指令 ─────────────────────────────────────────────── + # ── Step 2:建構 Aider 指令 ─────────────────────────────────────────────── safe_error = error_message[:500].replace('"', "'").replace("`", "'").replace("$", "") instruction = ( f"Fix the following {error_type} in this file. " @@ -265,8 +265,8 @@ def execute_code_fix( rc, aider_out, aider_err = _ssh_exec(aider_cmd, timeout=180) logger.debug("event=aider_output snippet=%s", (aider_out or aider_err)[:300]) - # ── Step 3:diff 评估(L2 护拦) ───────────────────────────────────────── - # 使用 git diff --numstat 获取有意义的变更行数(增加+删除) + # ── Step 3:diff 評估(L2 護欄) ───────────────────────────────────────── + # 使用 git diff --numstat 獲取有意義的變更行數(新增+刪除) numstat_cmd = ( f"cd {REPO_PATH_110} && " f"git diff --numstat HEAD 2>&1 | awk '{{added+=$1; deleted+=$2}} END{{print added+deleted}}'" @@ -275,9 +275,9 @@ def execute_code_fix( diff_lines = int(diff_lines_str.strip()) if rc2 == 0 and diff_lines_str.strip().isdigit() else 0 if diff_lines == 0: - msg = "[AiderHeal] Aider 未产生任何修改(diff=0),可能已自动解决或模型失效" + msg = "[AiderHeal] Aider 未產生任何修改(diff=0),可能已自動解決或模型失效" logger.warning("event=no_diff file=%s", target_file) - _notify_telegram(f"⚠️ AiderHeal:无修改产生\n{target_file}") + _notify_telegram(f"⚠️ AiderHeal:無修改產生\n{target_file}") return { "success": False, "action": "CODE_FIX", @@ -287,20 +287,20 @@ def execute_code_fix( } if diff_lines > MAX_DIFF_LINES: - # 改动太大,丢弃并告警 + # 改動太大,丟棄並告警 _, _, _ = _ssh_exec( f"cd {REPO_PATH_110} && git checkout -- . 2>&1", timeout=10 ) msg = ( f"[AiderHeal] diff 超出限制 {diff_lines} > {MAX_DIFF_LINES} 行," - f"已丢弃,需人工介入" + f"已丟棄,需人工介入" ) logger.warning("event=diff_too_large file=%s diff_lines=%d", target_file, diff_lines) _notify_telegram( - f"⚠️ AiderHeal:diff 过大,需人工审核\n" - f"├ 文件: {target_file}\n" - f"├ diff: {diff_lines} 行(上限 {MAX_DIFF_LINES})\n" - f"└ 错误: {error_type}" + f"⚠️ AiderHeal:diff 過大,需人工審核\n" + f"├ 檔案:{target_file}\n" + f"├ diff:{diff_lines} 行(上限 {MAX_DIFF_LINES})\n" + f"└ 錯誤:{error_type}" ) return { "success": False, @@ -310,7 +310,7 @@ def execute_code_fix( "reverted": False, } - # ── Step 4:提交并推送 ─────────────────────────────────────────────────── + # ── Step 4:提交並推送 ─────────────────────────────────────────────────── fix_msg = ( f"fix(autoheal): [{error_type}] auto-fix {target_file}\n\n" f"Triggered by AiderHealExecutor (ADR-014)\n" @@ -324,14 +324,14 @@ def execute_code_fix( ) rc3, commit_out, commit_err = _ssh_exec(commit_cmd, timeout=30) - # 获取最新的 commit SHA(从 push 后的 HEAD 获取,更可靠) + # 獲取最新的 commit SHA(從 push 後的 HEAD 獲取,更可靠) _, commit_sha, _ = _git_cmd(REPO_PATH_110, ["log", "-1", "--format=%H"], timeout=10) commit_sha = commit_sha.strip() or "unknown" if rc3 != 0: - msg = f"[AiderHeal] git push 失败: {commit_err or commit_out}" + msg = f"[AiderHeal] git push 失敗:{commit_err or commit_out}" logger.error("event=push_failed error=%s", msg) - _notify_telegram(f"❌ AiderHeal git push 失败\n{msg}") + _notify_telegram(f"❌ AiderHeal git push 失敗\n{msg}") return { "success": False, "action": "CODE_FIX", @@ -343,24 +343,24 @@ def execute_code_fix( logger.info("event=push_ok commit=%s", commit_sha) _notify_telegram( f"🚀 AiderHeal push 完成\n" - f"├ commit: {commit_sha}\n" - f"├ 文件: {target_file}\n" - f"└ 等待健康检查..." + f"├ commit:{commit_sha}\n" + f"├ 檔案:{target_file}\n" + f"└ 等待健康檢查…" ) - # ── Step 5:健康检查(L4 护拦) ────────────────────────────────────────── - time.sleep(10) # 给部署一点启动缓冲 + # ── Step 5:健康檢查(L4 護欄) ────────────────────────────────────────── + time.sleep(10) # 給部署一點啟動緩衝 healthy = _wait_for_health(HEALTH_CHECK_URL, timeout_seconds=120, interval_seconds=10) if healthy: - msg = f"[AiderHeal] 修复成功并部署完成: {target_file} ({commit_sha})" + msg = f"[AiderHeal] 修復成功並部署完成:{target_file} ({commit_sha})" logger.info("event=heal_success commit=%s file=%s", commit_sha, target_file) _notify_telegram( - f"✅ AiderHeal 修复完成\n" - f"├ 错误: {error_type}\n" - f"├ 文件: {target_file}\n" - f"├ commit: {commit_sha}\n" - f"└ diff: {diff_lines} 行" + f"✅ AiderHeal 修復完成\n" + f"├ 錯誤:{error_type}\n" + f"├ 檔案:{target_file}\n" + f"├ commit:{commit_sha}\n" + f"└ diff:{diff_lines} 行" ) return { "success": True, @@ -370,7 +370,7 @@ def execute_code_fix( "reverted": False, } - # ── Step 6:健康检查失败 → 自动 revert(L4 护拦) ───────────────────────── + # ── Step 6:健康檢查失敗 → 自動 revert(L4 護欄) ───────────────────────── logger.error("event=health_check_failed commit=%s", commit_sha) _, revert_out, revert_err = _ssh_exec( f"cd {REPO_PATH_110} && " @@ -383,21 +383,21 @@ def execute_code_fix( if "error" not in revert_out.lower() and "error" not in revert_err.lower(): msg = ( - f"[AiderHeal] 健康检查失败,已自动回滚: " + f"[AiderHeal] 健康檢查失敗,已自動回滾:" f"{commit_sha} → {revert_sha}" ) logger.warning("event=reverted commit=%s to=%s", commit_sha, revert_sha) _notify_telegram( - f"🔄 AiderHeal 自动回滚\n" - f"├ 原 commit: {commit_sha}\n" - f"├ 回滚 commit: {revert_sha}\n" - f"└ 需人工排查: {error_type} in {target_file}" + f"🔄 AiderHeal 自動回滾\n" + f"├ 原 commit:{commit_sha}\n" + f"├ 回滾 commit:{revert_sha}\n" + f"└ 需人工排查:{error_type} in {target_file}" ) else: - msg = f"[AiderHeal] 回滚失败!需立即人工介入: {revert_err}" + msg = f"[AiderHeal] 回滾失敗!需立即人工介入:{revert_err}" logger.critical("event=revert_failed commit=%s error=%s", commit_sha, revert_err) _notify_telegram( - f"🚨 AiderHeal 回滚失败!请立即人工介入\n{msg}" + f"🚨 AiderHeal 回滾失敗!請立即人工介入\n{msg}" ) return { diff --git a/services/elephant_alpha_orchestrator.py b/services/elephant_alpha_orchestrator.py index 711db26..0fef4c0 100644 --- a/services/elephant_alpha_orchestrator.py +++ b/services/elephant_alpha_orchestrator.py @@ -100,6 +100,8 @@ class ElephantAlphaOrchestrator: """Build comprehensive system prompt for Elephant Alpha""" return f"""You are Elephant Alpha, the Super Orchestrator for momo-pro-system e-commerce AI platform. +重要語言規定:你的 JSON 回應中所有文字欄位(strategic_assessment、reasoning、expected_outcome、execution_plan 的 description、risk_factors、contingency_plans)必須使用繁體中文(台灣用語)撰寫。嚴禁使用英文或簡體中文。 + CURRENT ARCHITECTURE: - You coordinate 3 specialized AI agents: Hermes (Analyst), NemoTron (Dispatcher), OpenClaw (Strategist) - Your context window: 256,000 tokens - enables deep strategic reasoning @@ -148,14 +150,17 @@ BUSINESS CONTEXT: - Revenue optimization and growth - Customer experience enhancement +LANGUAGE REQUIREMENT: +ALL text fields in your JSON response (strategic_assessment, reasoning, expected_outcome, execution_plan descriptions, risk_factors, contingency_plans) MUST be written in Traditional Chinese (繁體中文). Use Taiwan-standard terminology. Do NOT use Simplified Chinese or English for any user-facing content. + RESPONSE FORMAT: Always respond with structured JSON: {{ - "strategic_assessment": "Overall strategic evaluation", + "strategic_assessment": "整體策略評估(繁體中文)", "priority": "critical|high|medium|low", "agents_required": ["agent1", "agent2"], - "reasoning": "Detailed reasoning for decision", - "expected_outcome": "Expected business impact", + "reasoning": "詳細決策推理(繁體中文)", + "expected_outcome": "預期業務影響(繁體中文)", "confidence": 0.85, "execution_plan": [ {{ @@ -163,16 +168,17 @@ Always respond with structured JSON: "agent": "hermes", "action": "analyze_price_competition", "parameters": {{}}, - "expected_duration": "2-3 minutes" + "expected_duration": "2-3 分鐘", + "description": "執行說明(繁體中文)" }} ], "resource_requirements": {{ "compute_cost": "$0.00", - "time_estimate": "5-10 minutes", + "time_estimate": "5-10 分鐘", "human_oversight": "minimal|moderate|required" }}, - "risk_factors": ["potential_risk1", "potential_risk2"], - "contingency_plans": ["backup_plan1", "backup_plan2"] + "risk_factors": ["潛在風險一(繁體中文)", "潛在風險二"], + "contingency_plans": ["備案一(繁體中文)", "備案二"] }} AUTONOMY LEVEL: @@ -257,6 +263,8 @@ Based on the current business context and system state, determine the optimal st 5. Historical performance and learning outcomes Provide your strategic decision in the specified JSON format. + +重要:所有 JSON 文字欄位必須使用繁體中文(台灣用語)回覆,嚴禁英文或簡體中文。 """ return prompt