diff --git a/scripts/test_noping.py b/scripts/test_noping.py new file mode 100644 index 00000000..6a232329 --- /dev/null +++ b/scripts/test_noping.py @@ -0,0 +1,20 @@ +import ast, sys +for p in ['/home/hmo/MoFin/xmpp_logger.py']: + try: + ast.parse(open(p).read()) + print('SYNTAX OK:', p) + except SyntaxError as e: + print('SYNTAX ERROR:', p, e) + sys.exit(1) +sys.path.insert(0, '/home/hmo/MoFin') +import xmpp_logger as x +import time, json +print('== _scan_agent_log ==') +print(json.dumps(x._scan_agent_log(time.time()), ensure_ascii=False)) +print('== health (no LLM ping) ==') +import time as t +t0 = t.time() +h = x.health() +print(f'took {t.time()-t0:.1f}s') +print('llm_provider:', h.get('llm_provider')) +print('status:', h.get('status')) \ No newline at end of file diff --git a/xmpp_logger.py b/xmpp_logger.py index 2175d21c..f316385e 100644 --- a/xmpp_logger.py +++ b/xmpp_logger.py @@ -338,20 +338,9 @@ def health(): except Exception: pass result["gateways"][name] = {"port": port, "alive": ok} - # 测试知微的 LLM 调用是否可达 - if result["gateways"].get("zhiwei", {}).get("alive"): - try: - import urllib.request - payload = json.dumps({"model": "deepseek-v4-flash", "messages": [{"role": "user", "content": "ping"}], - "max_tokens": 5, "stream": False}).encode() - req = urllib.request.Request("http://127.0.0.1:8643/v1/chat/completions", - data=payload, headers={"Content-Type": "application/json", - "Authorization": "Bearer hermes123"}) - urllib.request.urlopen(req, timeout=90) - result["llm_provider"] = {"status": "ok", "latency": "fast"} - except Exception as e: - result["llm_provider"] = {"status": "timeout" if "timeout" in str(e).lower() else "error", - "error": str(e)[:150]} + # LLM 健康:扫 gateway agent.log 最近一次真实调用结果(零成本,不发 LLM 请求) + # agent.log 里每次真实调用都有记录:成功 "API call #N: ... latency=Xs" / 失败 "HTTP 429..." + result["llm_provider"] = _scan_agent_log(now_epoch) except Exception as e: result["gateways"] = {"error": str(e)[:100]} @@ -376,6 +365,61 @@ def health(): return result +AGENT_LOG = Path("/home/hmo/.hermes/profiles/position-analyst/logs/agent.log") + + +def _scan_agent_log(now_epoch, tail_lines=300): + """扫 gateway agent.log 尾部,取最近一次真实 LLM 调用的结果。 + + 成功行: "2026-07-19 20:04:42,880 INFO ... API call #4: ... latency=16.0s ..." + 失败行: "2026-07-19 19:35:59 WARNING ... API call failed ... HTTP 429: Weekly usage limit reached ..." + 返回 {"status": "ok"|"error"|"unknown", "latency"/"error", "age_sec"} + """ + if not AGENT_LOG.exists(): + return {"status": "unknown", "error": "agent.log not found"} + try: + # 只读尾部(大文件不全读) + size = AGENT_LOG.stat().st_size + with open(AGENT_LOG, "rb") as f: + f.seek(max(0, size - 64 * 1024)) + chunk = f.read().decode("utf-8", errors="replace") + lines = [l for l in chunk.splitlines() if l.strip()][-tail_lines:] + except Exception as e: + return {"status": "unknown", "error": str(e)[:80]} + + last_ok = None # (epoch, latency_str) + last_fail = None # (epoch, summary) + for line in lines: + m_ts = _re.search(r"(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})", line) + if not m_ts: + continue + try: + ts = datetime.strptime(m_ts.group(1), "%Y-%m-%d %H:%M:%S").timestamp() + except Exception: + continue + m_ok = _re.search(r"API call #\d+.*latency=([\d.]+)s", line) + if m_ok: + last_ok = (ts, m_ok.group(1)) + continue + if "API call failed" in line and ("summary=" in line or "after" in line): + m_err = _re.search(r"summary=(.+?)$", line) + summary = (m_err.group(1) if m_err else line)[:150] + last_fail = (ts, summary) + + if not last_ok and not last_fail: + return {"status": "unknown", "error": "no LLM calls in log"} + + if last_fail and (not last_ok or last_fail[0] > last_ok[0]): + return {"status": "error", + "error": last_fail[1], + "age_sec": int(now_epoch - last_fail[0]), + "source": "agent.log"} + return {"status": "ok", + "latency": f"{last_ok[1]}s", + "age_sec": int(now_epoch - last_ok[0]), + "source": "agent.log"} + + def _fetch_keys(): """从 AgentsMeeting Dashboard 获取可用 API Key 列表""" try: