merge: integrate 246-side commits (bot reconnect fix + docs) with session work

This commit is contained in:
hmo
2026-07-20 08:28:16 +08:00
21 changed files with 3143 additions and 291 deletions
+9 -1
View File
@@ -1,4 +1,12 @@
# MoFin 架构改革 — 变更日志
## 2026-07-19 — XMPP bot 递归重连修复
### 根因
XMPP bot 断线后 `on_disconnect` 调用 `self.reconnect()`,但 slixmpp 在重连失败时再次触发 disconnect 事件,导致 `on_disconnect → reconnect → disconnect` 无限递归,最终 `maximum recursion depth exceeded`
### 修改
- **文件:** `MoFin/deploy/bot/xmpp_agent_core.py`
- **变更:** 在 `XmppAgent.__init__` 中增加 `_reconnecting` 标志位,重连开始前设为 True、结束后(finally)恢复 False。重入时直接 return。
- **效果预期:** 断线重连失败后最多尝试一次,不会爆栈;bot 保持在 service 管理下等待 systemd 自动重启。
> 日期:2026-06-29 ~ 2026-07-03
> 执行:Sisyphus (小小莫) + Zhiwei (知微)
+11 -1
View File
@@ -1,4 +1,14 @@
记录知微对MoFin系统的缺陷修复和知识萃取项。
## 2026-07-19 20:58 XMPP bot on_disconnect 递归重连修复
**发现了什么:** zhiwei XMPP bot 从 20:53:57 开始反复输出 "XMPP 断开" × 27次,最后 "重连失败: maximum recursion depth exceeded"。slixmpp 的 `reconnect()` 在连接失败时会再次触发 disconnect 事件,而 `on_disconnect` 无条件调用 `reconnect()`,形成无限递归。
**修改了什么:**
- 文件: `MoFin/deploy/bot/xmpp_agent_core.py`
-`XmppAgent.__init__` 添加 `self._reconnecting = False`
- `on_disconnect` 判断 `_reconnecting` 为 True 时直接 return
- 重连前后用 try/finally 管理标志位
**效果预期:** 断线后最多一次 reconnect 尝试,不会爆栈。重连失败后保持静默,靠 systemd 的 Restart=always 自动恢复。
## 2026-07-02 11:30 macro_context_collector.py Pattern 9 百分比阈值修复 + 跨句涨幅匹配修复
+304
View File
@@ -0,0 +1,304 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
dashboard.py - MoFin management dashboard backend
==================================================
Minimal Flask app on :5804. Monitors MoFin services and serves
module specs (human_help + ai_spec) via ?§ button system.
Adapted from AgentsMeeting dashboard.py. Does NOT modify server.py.
"""
import os, sys, json, socket, logging, time
from pathlib import Path
from datetime import datetime
from flask import Flask, jsonify, request, send_from_directory
# ---- Paths (auto-detect from script location) ----
_SCRIPT_DIR = Path(__file__).resolve().parent # MoFin/
_TEMPLATES_DIR = _SCRIPT_DIR / "templates"
_SPECS_DIR = _SCRIPT_DIR / "specs"
_GATEWAY_DIR = _SCRIPT_DIR / "gateway"
_LOGS_DIR = _GATEWAY_DIR / "logs"
_TEMP_DIR = _GATEWAY_DIR / "temp"
# Allow override via env
_PROJECT_ROOT = os.environ.get("MOFIN_ROOT")
if _PROJECT_ROOT:
_SCRIPT_DIR = Path(_PROJECT_ROOT)
_TEMPLATES_DIR = _SCRIPT_DIR / "templates"
_SPECS_DIR = _SCRIPT_DIR / "specs"
_GATEWAY_DIR = _SCRIPT_DIR / "gateway"
_LOGS_DIR = _GATEWAY_DIR / "logs"
_TEMP_DIR = _GATEWAY_DIR / "temp"
app = Flask(__name__, template_folder=str(_TEMPLATES_DIR))
# ---- Logging ----
_LOG_FILE = _LOGS_DIR / "dashboard.log"
_LOG_FILE.parent.mkdir(parents=True, exist_ok=True)
logging.basicConfig(
filename=str(_LOG_FILE),
level=logging.INFO,
format="%(asctime)s [dashboard] %(message)s",
)
log = logging.getLogger("dashboard")
# ---- Constants ----
PORT = int(os.environ.get("MOFIN_DASHBOARD_PORT", 5807))
START_TIME = time.time()
# ---- Monitored Services ----
SERVICES = [
{
"name": "mofin_api",
"label": "MoFin API",
"port": 8899,
"host": "127.0.0.1",
"type": "http",
"check": "/api/portfolio",
"layer": "核心服务",
"critical": True,
},
{
"name": "mofin_dashboard",
"label": "Dashboard",
"port": 5807,
"host": "127.0.0.1",
"type": "http",
"check": "/api/health",
"layer": "核心服务",
"critical": True,
},
{
"name": "zhiwei_gateway",
"label": "知微 Gateway",
"port": 8643,
"host": "127.0.0.1",
"type": "http",
"check": "/v1/health",
"layer": "AI 网关",
"critical": True,
},
{
"name": "ejabberd",
"label": "ejabberd XMPP",
"port": 5222,
"host": "127.0.0.1",
"type": "tcp",
"check": None,
"layer": "通信层",
"critical": True,
},
{
"name": "mofin_db",
"label": "MoFin 数据库",
"port": 0,
"host": "127.0.0.1",
"type": "db",
"check": "/home/hmo/web-dashboard/data/mofin.db",
"layer": "数据层",
"critical": True,
},
]
# ---- Service Check Helpers ----
def _check_tcp(host, port, timeout=3):
"""Check if TCP port is open."""
try:
sock = socket.create_connection((host, port), timeout=timeout)
sock.close()
return True
except Exception:
return False
def _check_http(host, port, path, timeout=3):
"""Check HTTP endpoint returns 2xx."""
import urllib.request
try:
url = f"http://{host}:{port}{path}" if host else f"http://127.0.0.1:{port}{path}"
req = urllib.request.Request(url)
resp = urllib.request.urlopen(req, timeout=timeout)
return 200 <= resp.status < 300
except Exception:
return False
def _check_db(db_path):
"""Check SQLite database is accessible."""
import sqlite3
try:
conn = sqlite3.connect(db_path)
conn.execute("SELECT 1")
conn.close()
return True
except Exception:
return False
def _check_service(svc):
"""Check a single service, return (ok, detail)."""
if svc["type"] == "tcp":
ok = _check_tcp(svc["host"], svc["port"])
return ok, "port open" if ok else "port closed"
elif svc["type"] == "http":
ok = _check_http(svc["host"], svc["port"], svc["check"])
return ok, "HTTP 2xx" if ok else "HTTP fail"
elif svc["type"] == "db":
ok = _check_db(svc["check"])
return ok, "DB accessible" if ok else "DB fail"
return False, "unknown type"
# ---- API Endpoints ----
@app.route("/")
def index():
return send_from_directory(str(_TEMPLATES_DIR), "dashboard.html")
@app.route("/api/health")
def api_health():
return jsonify({
"status": "ok",
"uptime": int(time.time() - START_TIME),
"version": "1.0",
})
@app.route("/api/services")
def api_services():
"""Return status of all monitored services."""
result = []
for svc in SERVICES:
ok, detail = _check_service(svc)
result.append({
"name": svc["name"],
"label": svc["label"],
"port": svc["port"],
"type": svc["type"],
"layer": svc["layer"],
"critical": svc["critical"],
"health": {"ok": ok},
"detail": detail,
})
ok_count = sum(1 for s in result if s["health"]["ok"])
return jsonify({
"services": result,
"summary": {"ok": ok_count, "total": len(result)},
})
@app.route("/api/expected")
def api_expected():
"""Return expectation matrix."""
expected = []
for svc in SERVICES:
expected.append({
"name": svc["name"],
"label": svc["label"],
"port": svc["port"],
"expected": "running",
"critical": svc["critical"],
"layer": svc["layer"],
"check": f"{svc['type']}:{svc['port']}" if svc["port"] else svc["type"],
})
# Actual status
actual = {}
for svc in SERVICES:
ok, _ = _check_service(svc)
actual[svc["name"]] = "running" if ok else "stopped"
return jsonify({
"expected": expected,
"actual": actual,
})
@app.route("/api/monitor")
def api_monitor():
"""Aggregate health check data from Tier1/Tier2 reports."""
tasks = []
tier1 = {"summary": {"ok": 0, "total": 0}, "services": []}
tier2 = {"summary": {"ok": 0, "total": 0}, "services": []}
# Try to read Tier1 report
t1_path = _TEMP_DIR / "last_health_check.json"
if t1_path.exists():
try:
with open(t1_path, encoding="utf-8") as f:
tier1 = json.load(f)
tasks.append({"name": "agents-health-check", "status": "cron_ok"})
except Exception:
tasks.append({"name": "agents-health-check", "status": "error"})
else:
tasks.append({"name": "agents-health-check", "status": "not_deployed"})
# Try to read Tier2 report
t2_path = _TEMP_DIR / "last_daily_health.json"
if t2_path.exists():
try:
with open(t2_path, encoding="utf-8") as f:
tier2 = json.load(f)
tasks.append({"name": "agents-daily-health", "status": "cron_ok"})
except Exception:
tasks.append({"name": "agents-daily-health", "status": "error"})
else:
tasks.append({"name": "agents-daily-health", "status": "not_deployed"})
# Self-check: are we running?
svc_result = api_services().get_json()
tasks.append({
"name": "dashboard",
"status": "running",
"detail": f"services: {svc_result.get('summary', {}).get('ok', 0)}/{svc_result.get('summary', {}).get('total', 0)}",
})
return jsonify({
"tasks": tasks,
"tier1": tier1,
"tier2": tier2,
"generated_at": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
})
@app.route("/api/module-spec/<module>")
def api_module_spec(module):
"""Serve spec JSON for a module."""
# Safety: prevent path traversal
module = module.replace("..", "").replace("/", "").replace("\\", "")
spec_path = _SPECS_DIR / f"{module}.json"
if spec_path.exists():
try:
with open(spec_path, encoding="utf-8") as f:
return jsonify(json.load(f))
except Exception as e:
return jsonify({"error": f"Failed to read spec: {e}"}), 500
return jsonify({"error": f"Module '{module}' not found"}), 404
# ---- Main ----
if __name__ == "__main__":
# Ensure directories exist
_LOGS_DIR.mkdir(parents=True, exist_ok=True)
_TEMP_DIR.mkdir(parents=True, exist_ok=True)
log.info(f"MoFin Dashboard starting on port {PORT}")
log.info(f"Specs dir: {_SPECS_DIR}")
log.info(f"Templates dir: {_TEMPLATES_DIR}")
# Optional: PID guard
try:
sys.path.insert(0, str(_SCRIPT_DIR))
from proc_guard import guard
if not guard("mofin_dashboard"):
log.error("Another dashboard instance is already running")
sys.exit(1)
except ImportError:
log.warning("proc_guard not available, skipping PID lock")
app.run(host="0.0.0.0", port=PORT, debug=False)
+190
View File
@@ -0,0 +1,190 @@
{
"holdings": [
{
"code": "518880",
"name": "黄金ETF华安",
"shares": 2400,
"cost": 12.1915,
"position_pct": null,
"added_at": "2026-07-17",
"is_active": 1,
"closed_at": null,
"close_pnl": null,
"price": 8.29,
"market_value": 19862.4,
"change_pct": -0.85,
"currency": "CNY"
},
{
"code": "601899",
"name": "紫金矿业",
"shares": 2400,
"cost": 39.8885,
"position_pct": null,
"added_at": "2026-07-17",
"is_active": 1,
"closed_at": null,
"close_pnl": null,
"price": 28.38,
"market_value": 68184.0,
"change_pct": -2.97,
"currency": "CNY"
},
{
"code": "688411",
"name": "海博思创",
"shares": 200,
"cost": 266.9461,
"position_pct": null,
"added_at": "2026-07-17",
"is_active": 1,
"closed_at": null,
"close_pnl": null,
"price": 184.26,
"market_value": 37048.0,
"change_pct": -4.97,
"currency": "CNY"
},
{
"code": "688639",
"name": "华恒生物",
"shares": 2800,
"cost": 21.5085,
"position_pct": null,
"added_at": "2026-07-17",
"is_active": 1,
"closed_at": null,
"close_pnl": null,
"price": 16.47,
"market_value": 46480.0,
"change_pct": -4.19,
"currency": "CNY"
},
{
"code": "688981",
"name": "中芯国际",
"shares": 300,
"cost": 126.0681,
"position_pct": null,
"added_at": "2026-07-17",
"is_active": 1,
"closed_at": null,
"close_pnl": null,
"price": 144.84,
"market_value": 44436.0,
"change_pct": -4.58,
"currency": "CNY"
},
{
"code": "000850",
"name": "华茂股份",
"shares": 20400,
"cost": 3.9408,
"position_pct": null,
"added_at": "2026-07-17",
"is_active": 1,
"closed_at": null,
"close_pnl": null,
"price": 4.09,
"market_value": 83232.0,
"change_pct": 0.25,
"currency": "CNY"
},
{
"code": "300035",
"name": "中科电气",
"shares": 1400,
"cost": 22.2914,
"position_pct": null,
"added_at": "2026-07-17",
"is_active": 1,
"closed_at": null,
"close_pnl": null,
"price": 12.31,
"market_value": 18116.0,
"change_pct": -1.44,
"currency": "CNY"
},
{
"code": "00700",
"name": "腾讯控股",
"shares": 100,
"cost": 445.2906,
"position_pct": null,
"added_at": "2026-07-17",
"is_active": 1,
"closed_at": null,
"close_pnl": null,
"price": 461.0,
"market_value": 39837.28,
"change_pct": -4.75,
"currency": "CNY"
},
{
"code": "01088",
"name": "中国神华",
"shares": 500,
"cost": 46.1178,
"position_pct": null,
"added_at": "2026-07-17",
"is_active": 1,
"closed_at": null,
"close_pnl": null,
"price": 41.62,
"market_value": 18114.13,
"change_pct": -0.62,
"currency": "CNY"
},
{
"code": "01211",
"name": "比亚迪股份",
"shares": 600,
"cost": 105.3827,
"position_pct": null,
"added_at": "2026-07-17",
"is_active": 1,
"closed_at": null,
"close_pnl": null,
"price": 87.6,
"market_value": 45328.5,
"change_pct": -3.68,
"currency": "CNY"
},
{
"code": "01478",
"name": "丘钛科技",
"shares": 11000,
"cost": 13.531,
"position_pct": null,
"added_at": "2026-07-17",
"is_active": 1,
"closed_at": null,
"close_pnl": null,
"price": 6.56,
"market_value": 62967.76,
"change_pct": -6.42,
"currency": "CNY"
},
{
"code": "02202",
"name": "万科企业",
"shares": 19700,
"cost": 4.6906,
"position_pct": null,
"added_at": "2026-07-17",
"is_active": 1,
"closed_at": null,
"close_pnl": null,
"price": 2.36,
"market_value": 40141.19,
"change_pct": -5.98,
"currency": "CNY"
}
],
"cash": 321271.0,
"frozen_cash": 0.0,
"total_market_value": 521073.53,
"total_assets": 842344.53,
"position_pct": 61.86,
"updated_at": "2026-07-17 14:08:07"
}
+7 -1
View File
@@ -245,6 +245,7 @@ class XmppAgent(slixmpp.ClientXMPP):
self._nick = nick
self._muc_joined = False
self._recent_sent = []
self._reconnecting = False # 防递归重连
self.add_event_handler('session_start', self.on_start)
self.add_event_handler('message', self.on_msg)
self.add_event_handler('disconnected', self.on_disconnect)
@@ -266,11 +267,16 @@ class XmppAgent(slixmpp.ClientXMPP):
def on_disconnect(self, event):
self._muc_joined = False
log.info(f"{AGENT_NAME} XMPP 断开")
# 自动重连:slixmpp 1.15.0 没有 auto_reconnect 属性,需手动
if self._reconnecting:
log.warning(f"{AGENT_NAME} 已在重连中,跳过递归重连")
return
self._reconnecting = True
try:
self.reconnect(wait=5.0, reason="断线自动重连")
except Exception as e:
log.warning(f"{AGENT_NAME} 重连失败: {e}")
finally:
self._reconnecting = False
def on_msg(self, msg):
if msg['type'] in ('chat', 'groupchat'):
+205 -194
View File
@@ -1,194 +1,205 @@
#!/usr/bin/env python3
"""market_scanner.py — 全市场异动扫描(替代小果扫描线)
每15分钟扫描:
1. 板块轮动检测(从已采集的 sector_snapshots 读)
2. 热门板块领涨股扫描(从腾讯API批量拉)
3. 资金流向异常检测(从已有 capital_flow_cache 读)
4. 输出候选股到 candidates 表
不依赖小果LLM,纯数据驱动。
"""
import sys, json, sqlite3, urllib.request, re, time
from pathlib import Path
from datetime import datetime
DB_PATH = Path("/home/hmo/MoFin/data/mofin.db")
CANDIDATES_FILE = Path("/home/hmo/web-dashboard/data/candidate_pool.json")
UA = "Mozilla/5.0"
def get_conn():
return sqlite3.connect(str(DB_PATH))
def fetch_qq_batch(symbols):
"""腾讯批量行情"""
if not symbols:
return {}
url = f"http://qt.gtimg.cn/q={','.join(symbols)}"
try:
req = urllib.request.Request(url, headers={"User-Agent": UA})
proxy = urllib.request.ProxyHandler({})
opener = urllib.request.build_opener(proxy)
with opener.open(req, timeout=15) as r:
text = r.read().decode("gbk")
results = {}
for line in text.strip().split("\n"):
if "~" not in line:
continue
parts = line.split("~")
if len(parts) < 40:
continue
m = re.search(r'_(\w+)=', parts[0])
market = m.group(1) if m else ""
code = parts[2]
name = parts[1]
price = float(parts[3]) if parts[3] else 0
chg_pct = float(parts[32]) if parts[32] else 0
high = float(parts[33]) if parts[33] else 0
low = float(parts[34]) if parts[34] else 0
volume = int(parts[6]) if parts[6] else 0
amount = float(parts[37]) if len(parts) > 37 and parts[37] else 0
if price > 0:
results[code] = {"code": code, "name": name, "price": price,
"change_pct": chg_pct, "high": high, "low": low,
"volume": volume, "amount": amount,
"market": "SH" if market == "sh" else "SZ" if market == "sz" else "HK"}
return results
except Exception as e:
print(f"[SCANNER] 腾讯API错误: {e}", file=sys.stderr)
return {}
def scan_hot_sectors():
"""从DB读热门板块,返回板块名+领涨股"""
conn = get_conn()
latest = conn.execute("SELECT MAX(id) FROM market_snapshots").fetchone()[0]
if not latest:
conn.close()
return []
sectors = conn.execute("""
SELECT name, change_pct, lead_stock, lead_stock_code, up_count, down_count
FROM sector_snapshots WHERE snapshot_id=?
ORDER BY change_pct DESC LIMIT 15
""", (latest,)).fetchall()
conn.close()
return [{"name": s[0], "change": s[1], "lead_stock": s[2],
"lead_code": s[3], "up": s[4], "down": s[5]} for s in sectors if s[1] > 2.0]
def scan_candidates():
"""主扫描流程"""
print(f"[SCANNER] {datetime.now().strftime('%H:%M')} 开始扫描", flush=True)
# 1. 热门板块领涨股
hot = scan_hot_sectors()
print(f" 热门板块(涨幅>2%): {len(hot)}", flush=True)
candidates = {}
# 从热门板块拉领涨股
lead_codes = []
for s in hot:
if s.get("lead_code"):
lc = str(s["lead_code"]).strip()
if lc and lc not in candidates:
lead_codes.append(lc)
candidates[lc] = {"source": f"板块:{s['name']}(+{s['change']:.1f}%)", "sector": s["name"]}
print(f" 领涨股待查: {len(lead_codes)}", flush=True)
# 2. 腾讯API批量查行情
symbols = []
for c in lead_codes:
if len(c) == 6:
if c.startswith(("5", "6", "9")):
symbols.append(f"sh{c}")
else:
symbols.append(f"sz{c}")
else:
symbols.append(f"hk{c}")
prices = fetch_qq_batch(symbols)
print(f" 行情返回: {len(prices)}", flush=True)
# 3. 评估候选
new_candidates = []
for code, info in prices.items():
if code not in candidates:
continue
src = candidates[code]
price = info["price"]
chg = info["change_pct"]
name = info["name"]
vol = info["volume"]
amt = info["amount"]
# 条件:涨幅>3%,有量
if chg < 3.0:
continue
if vol <= 0:
continue
score = min(10, round(3 + chg * 0.5 + (amt / 1e8 if amt > 0 else 0) * 0.1, 1))
entry_low = round(price * 0.95, 2)
entry_high = round(price, 2)
stop_loss = round(price * 0.92, 2)
take_profit = round(price * 1.15, 2)
candidate = {
"code": code,
"name": name,
"price": price,
"change_pct": chg,
"score": score,
"entry_low": entry_low,
"entry_high": entry_high,
"stop_loss": stop_loss,
"take_profit": take_profit,
"source": src["source"],
"sector": src.get("sector", ""),
"reason": f"热门板块{src['sector']}领涨+{chg:.1f}%"
}
new_candidates.append(candidate)
print(f"{code} {name}{price} (+{chg:.1f}%) 评分{score}", flush=True)
# 4. 写入candidates表
if new_candidates:
conn = get_conn()
for c in new_candidates:
conn.execute(
"INSERT OR REPLACE INTO candidates (code, name, price, change_pct, score, "
"entry_low, entry_high, stop_loss, take_profit, source, sector, reason, created_at) "
"VALUES (?,?,?,?,?,?,?,?,?,?,?,?,datetime('now','localtime'))",
(c["code"], c["name"], c["price"], c["change_pct"], c["score"],
c["entry_low"], c["entry_high"], c["stop_loss"], c["take_profit"],
c["source"], c["sector"], c["reason"])
)
conn.commit()
conn.close()
print(f" ✅ 写入{len(new_candidates)}只候选", flush=True)
else:
print(f" ⚪ 无新候选", flush=True)
# 5. 推送到Dad(只推高分)
high_score = [c for c in new_candidates if c["score"] >= 6]
if high_score:
lines = ["🔍 市场扫描发现潜在机会:"]
for c in high_score[:3]:
lines.append(
f" {c['name']}({c['code']}) 价{c['price']:.2f}(+{c['change_pct']:.1f}%) "
f"评分{c['score']}/10 | {c['reason']}"
)
msg = "\n".join(lines)
# 推XMPP
try:
payload = json.dumps({"to": "hmo@yoin.fun", "body": msg, "type": "chat"}).encode()
req = urllib.request.Request("http://127.0.0.1:5805/", data=payload,
headers={"Content-Type": "application/json"})
urllib.request.urlopen(req, timeout=5)
print(f" 📨 已推送{len(high_score)}只高评分候选", flush=True)
except Exception as e:
print(f" ⚠️ 推送失败: {e}", file=sys.stderr)
if __name__ == "__main__":
scan_candidates()
#!/usr/bin/env python3
"""market_scanner.py — 全市场异动扫描(替代小果扫描线)
每15分钟扫描:
1. 板块轮动检测(从已采集的 sector_snapshots 读)
2. 热门板块领涨股扫描(从腾讯API批量拉)
3. 资金流向异常检测(从已有 capital_flow_cache 读)
4. 输出候选股到 candidates 表
不依赖小果LLM,纯数据驱动。
"""
import sys, json, sqlite3, urllib.request, re, time
from pathlib import Path
from datetime import datetime
# XMPP 日志 hook
try:
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
from xmpp_logger import log_xmpp
except ImportError:
def log_xmpp(*a, **kw): pass
DB_PATH = Path("/home/hmo/MoFin/data/mofin.db")
CANDIDATES_FILE = Path("/home/hmo/web-dashboard/data/candidate_pool.json")
UA = "Mozilla/5.0"
def get_conn():
return sqlite3.connect(str(DB_PATH))
def fetch_qq_batch(symbols):
"""腾讯批量行情"""
if not symbols:
return {}
url = f"http://qt.gtimg.cn/q={','.join(symbols)}"
try:
req = urllib.request.Request(url, headers={"User-Agent": UA})
proxy = urllib.request.ProxyHandler({})
opener = urllib.request.build_opener(proxy)
with opener.open(req, timeout=15) as r:
text = r.read().decode("gbk")
results = {}
for line in text.strip().split("\n"):
if "~" not in line:
continue
parts = line.split("~")
if len(parts) < 40:
continue
m = re.search(r'_(\w+)=', parts[0])
market = m.group(1) if m else ""
code = parts[2]
name = parts[1]
price = float(parts[3]) if parts[3] else 0
chg_pct = float(parts[32]) if parts[32] else 0
high = float(parts[33]) if parts[33] else 0
low = float(parts[34]) if parts[34] else 0
volume = int(parts[6]) if parts[6] else 0
amount = float(parts[37]) if len(parts) > 37 and parts[37] else 0
if price > 0:
results[code] = {"code": code, "name": name, "price": price,
"change_pct": chg_pct, "high": high, "low": low,
"volume": volume, "amount": amount,
"market": "SH" if market == "sh" else "SZ" if market == "sz" else "HK"}
return results
except Exception as e:
print(f"[SCANNER] 腾讯API错误: {e}", file=sys.stderr)
return {}
def scan_hot_sectors():
"""从DB读热门板块,返回板块名+领涨股"""
conn = get_conn()
latest = conn.execute("SELECT MAX(id) FROM market_snapshots").fetchone()[0]
if not latest:
conn.close()
return []
sectors = conn.execute("""
SELECT name, change_pct, lead_stock, lead_stock_code, up_count, down_count
FROM sector_snapshots WHERE snapshot_id=?
ORDER BY change_pct DESC LIMIT 15
""", (latest,)).fetchall()
conn.close()
return [{"name": s[0], "change": s[1], "lead_stock": s[2],
"lead_code": s[3], "up": s[4], "down": s[5]} for s in sectors if s[1] > 2.0]
def scan_candidates():
"""主扫描流程"""
print(f"[SCANNER] {datetime.now().strftime('%H:%M')} 开始扫描", flush=True)
# 1. 热门板块领涨股
hot = scan_hot_sectors()
print(f" 热门板块(涨幅>2%): {len(hot)}", flush=True)
candidates = {}
# 从热门板块拉领涨股
lead_codes = []
for s in hot:
if s.get("lead_code"):
lc = str(s["lead_code"]).strip()
if lc and lc not in candidates:
lead_codes.append(lc)
candidates[lc] = {"source": f"板块:{s['name']}(+{s['change']:.1f}%)", "sector": s["name"]}
print(f" 领涨股待查: {len(lead_codes)}", flush=True)
# 2. 腾讯API批量查行情
symbols = []
for c in lead_codes:
if len(c) == 6:
if c.startswith(("5", "6", "9")):
symbols.append(f"sh{c}")
else:
symbols.append(f"sz{c}")
else:
symbols.append(f"hk{c}")
prices = fetch_qq_batch(symbols)
print(f" 行情返回: {len(prices)}", flush=True)
# 3. 评估候选
new_candidates = []
for code, info in prices.items():
if code not in candidates:
continue
src = candidates[code]
price = info["price"]
chg = info["change_pct"]
name = info["name"]
vol = info["volume"]
amt = info["amount"]
# 条件:涨幅>3%,有量
if chg < 3.0:
continue
if vol <= 0:
continue
score = min(10, round(3 + chg * 0.5 + (amt / 1e8 if amt > 0 else 0) * 0.1, 1))
entry_low = round(price * 0.95, 2)
entry_high = round(price, 2)
stop_loss = round(price * 0.92, 2)
take_profit = round(price * 1.15, 2)
candidate = {
"code": code,
"name": name,
"price": price,
"change_pct": chg,
"score": score,
"entry_low": entry_low,
"entry_high": entry_high,
"stop_loss": stop_loss,
"take_profit": take_profit,
"source": src["source"],
"sector": src.get("sector", ""),
"reason": f"热门板块{src['sector']}领涨+{chg:.1f}%"
}
new_candidates.append(candidate)
print(f"{code} {name}{price} (+{chg:.1f}%) 评分{score}", flush=True)
# 4. 写入candidates表
if new_candidates:
conn = get_conn()
for c in new_candidates:
conn.execute(
"INSERT OR REPLACE INTO candidates (code, name, price, change_pct, score, "
"entry_low, entry_high, stop_loss, take_profit, source, sector, reason, created_at) "
"VALUES (?,?,?,?,?,?,?,?,?,?,?,?,datetime('now','localtime'))",
(c["code"], c["name"], c["price"], c["change_pct"], c["score"],
c["entry_low"], c["entry_high"], c["stop_loss"], c["take_profit"],
c["source"], c["sector"], c["reason"])
)
conn.commit()
conn.close()
print(f" ✅ 写入{len(new_candidates)}只候选", flush=True)
else:
print(f" ⚪ 无新候选", flush=True)
# 5. 推送到Dad(只推高分)
high_score = [c for c in new_candidates if c["score"] >= 6]
if high_score:
lines = ["🔍 市场扫描发现潜在机会:"]
for c in high_score[:3]:
lines.append(
f" {c['name']}({c['code']}) 价{c['price']:.2f}(+{c['change_pct']:.1f}%) "
f"评分{c['score']}/10 | {c['reason']}"
)
msg = "\n".join(lines)
# 推XMPP(通过知微 Bot HTTP 桥 :5805
import time as _time
t0 = _time.time()
try:
payload = json.dumps({"to": "hmo@yoin.fun", "body": msg, "type": "chat"}).encode()
req = urllib.request.Request("http://127.0.0.1:5805/", data=payload,
headers={"Content-Type": "application/json"})
urllib.request.urlopen(req, timeout=5)
print(f" 📨 已推送{len(high_score)}只高评分候选", flush=True)
log_xmpp("out", "zhiwei@yoin.fun", "hmo@yoin.fun", msg, "ok", None, int((_time.time()-t0)*1000))
except Exception as e:
print(f" ⚠️ 推送失败: {e}", file=sys.stderr)
log_xmpp("out", "zhiwei@yoin.fun", "hmo@yoin.fun", msg, "error", str(e)[:200], int((_time.time()-t0)*1000))
if __name__ == "__main__":
scan_candidates()
+217
View File
@@ -0,0 +1,217 @@
# MoFin 开发规范
> 版本: v1.0 | 更新: 2026-07-19 | 基于 AgentsMeeting 样板重构
>
> 📋 样板参考: [AgentsMeeting TEMPLATE-GUIDE.md](../AgentsMeeting/docs/TEMPLATE-GUIDE.md)
---
## 五条红线
1. **先读/写 Spec,再写代码** — 新增功能先写 spec 再实现;修改已有功能先读对应 spec 了解架构和约束再动手。没有 spec 的模块在 Dashboard 不可见,视为未完成
2. **部署必验** — 部署后不打开 Dashboard F Tab 验证 = 部署未完成
3. **不可见即不存在** — 组件不在 Dashboard 中显示 = 等于没部署。离线不告警 = 监控缺陷
4. **实现后同步 Spec** — 每轮开发完毕后,必须将 `specs/{module}.json` 更新为与实际实现一致的状态。文档过期 = 等于没写
5. **部署目标即验收标准** — 所有代码必须以部署目标环境(Linux 246)为基准编写和测试。禁止使用 Windows 专属 API`tasklist``netstat``schtasks``wmic`)在 246 部署的代码中
---
## 一、双轨同源规范体系
每新增/修改一个独立功能模块,必须先写 `specs/{module}.json`
一个来源同时产出两套文档:
```
specs/{module}.json
├── human_help → ? 按钮(人类看说明/排错)
└── ai_spec → § 按钮(AI 看接口/约束/依赖)
```
### 什么算一个模块
满足以下任一条件即视为独立模块,必须写 spec:
- 暴露独立的 HTTP API 端点
- 在 Dashboard 上有独立 UI 面板(`?` + `§` 按钮)
- 有独立的配置文件 / 数据文件
- 可独立部署(如定时任务、数据采集脚本)
### Spec 字段标准
```json
{
"module": "模块名(与 Dashboard 引用名一致)",
"version": "1.0",
"purpose": "一句话说明这个模块干什么",
"human_help": {
"title": "面向人类的标题",
"description": ["说明段落数组"],
"usage": ["使用步骤数组"],
"troubleshooting": ["常见问题数组"]
},
"ai_spec": {
"apis": [
{"method": "GET", "path": "/api/xxx", "returns": "返回值说明"}
],
"dependencies": ["依赖的服务或文件"],
"constraints": ["AI 必须遵守的约束"],
"must_not": ["AI 绝对不能做的事"],
"tests": [{"id": "T1", "name": "测试用例名"}],
"related_files": ["实现文件路径"]
}
}
```
### 当前模块清单
| 模块 | spec 路径 | 说明 | 状态 |
|------|----------|------|------|
| portfolio | `specs/portfolio.json` | 持仓数据 + 总览 | ✅ |
| watchlist | `specs/watchlist.json` | 自选股管理 | ✅ |
| decisions | `specs/decisions.json` | 策略决策库 | ✅ |
| market | `specs/market.json` | 市场观察数据 | ✅ |
| signals | `specs/signals.json` | 信号 + 全市场扫描 | ✅ |
| scanner | `specs/scanner.json` | 全市场选股机制 | ✅ |
| evaluation | `specs/evaluation.json` | 策略评估 | ✅ |
| prompts | `specs/prompts.json` | 提示词版本管理 | ✅ |
| reports | `specs/reports.json` | 分析报告管理 | ✅ |
| dashboard | `specs/dashboard.json` | Dashboard 自身 | ✅ |
| health | `specs/health.json` | 健康监控管线 | ✅ |
| xmpp_monitor | `specs/xmpp_monitor.json` | XMPP 通信可观测性 | ✅ |
| price_monitor | `specs/price_monitor.json` | 价格监控 cron | 📋 |
| strategy_lifecycle | `specs/strategy_lifecycle.json` | 策略生命周期 | 📋 |
> 状态: ✅ = spec 已完成 | 📋 = 待编写
---
## 二、验证闭环
```
┌────────────┐ ┌──────────┐ ┌──────────┐
│ G: 规范体系 │────→│ K: 测试 │────→│ F: 健康 │
│ 定义期望 │ │ 验证实现 │ │ 持续监控 │
└────────────┘ └──────────┘ └──────────┘
↑ ↑ │
└────────────────┼────────────────┘
┌────────┴────────┐
│ F 异常 → 触发 K │
│ K 失败 → 更新 G │
└─────────────────┘
```
### 核心反馈链路
| 方向 | 触发条件 | 动作 |
|------|---------|------|
| G → K | 新增/修改 spec | 对应测试 ID 必须新增/更新 |
| K → F | 测试全部通过 | F Tab 组件标记为已验证 |
| **F → K** | **F Tab 发现异常** | 触发对应测试重跑,确认是服务故障还是测试过期 |
| **F → G** | **F Tab 持续异常但测试通过** | 期望矩阵或 spec 过时,应更新 G 和对应 spec |
### F — 系统健康度(Dashboard F Tab
- **期望矩阵**:应该运行的服务 vs 实际状态
- **监控数据**Tier15min)/ Tier2(日报)作为实时状态输入
- **服务拓扑**:所有服务的健康、端口状态
- **?§ 覆盖**:F Tab 中的每条服务必须有对应的 ?human_help)和 §(ai_spec)按钮
---
## 三、开发流程
### 新增功能流程
```
确定模块边界
├─ 1. 创建 specs/{module}.json
│ human_help + ai_spec
├─ 2. 实现功能代码
│ 包含 /health 端点 + PID 锁(proc_guard
├─ 3. 注册到系统
│ - 端口注册
│ - 添加到期望矩阵(F Tab 自动检测)
├─ 4. 编写测试
│ - ai_spec.tests 添加对应测试标识
├─ 5. 同步更新 Spec
│ - 将 specs/{module}.json 更新为与实际实现一致
└─ 6. 提交 → 部署 → 验证
```
### 修改已有功能流程
```
识别要修改的模块(查看模块清单确定 module 名)
├─ 1. 读 specs/{module}.json
│ 重点读 ai_specapis / constraints / dependencies / must_not
├─ 2. 确认理解
│ - 如果 spec 描述与代码实际行为不一致,优先怀疑 spec 过期
├─ 3. 修改功能代码
│ 只改动需求直接涉及的部分,不顺手优化无关代码
├─ 4. 同步更新 Spec
└─ 5. 提交 → 部署 → 验证
```
### Git 操作规范
| # | 规则 | 说明 |
|---|------|------|
| 1 | 开工前必 pull | `git pull --rebase` |
| 2 | 改完即 commit | 一个逻辑单元一次提交。禁止含密钥 |
| 3 | 推前必拉 + 配代理 | push 前 `git pull --rebase`。远程操作前配 `:15000` 代理 |
| 4 | trunk-based | 日常在 main。仅长周期大改开分支 |
### 已有编码规范
MoFin 已有的编码规范见 `docs/DEVELOPMENT_STANDARDS.md`,包含:
- 代码结构(mo_models → mo_data → mofin_db 三层)
- 数据规范(币种、汇率、数据源)
- DB 规范(表设计、迁移)
- LLM Prompt 规范
- Cron 规范(独立运行、幂等性)
- 测试要求(`run_all_tests.py`
以上规范与本文件互补,不冲突。本文件侧重"先 spec 后代码"和"通过 Dashboard 保证可见性"。
---
## 四、部署环境
| 项目 | 值 |
|------|-----|
| **生产环境** | Linux 192.168.1.246 |
| **代码目录** | `/home/hmo/MoFin/` |
| **数据库** | `/home/hmo/web-dashboard/data/mofin.db`SQLite |
| **Flask API** | `server.py``:8899`(含 Dashboard |
| **Python** | 系统 Python 3 |
---
## 五、文档索引
| 文档 | 用途 |
|------|------|
| `docs/dev-spec.md` | 本文件 — 开发规范(含五条红线) |
| `docs/DEVELOPMENT_STANDARDS.md` | 编码规范(已有) |
| `SYSTEM_ARCHITECTURE.md` | 系统架构(已有) |
| `docs/cron-catalog.md` | Cron 任务清单(已有) |
| `docs/DEPLOY.md` | 部署指南 |
| `docs/QUICKSTART.md` | 快速操作 |
| `docs/DASHBOARD.md` | Dashboard API 参考 |
| `docs/HEALTH-PIPELINE.md` | 健康管线文档 |
| `docs/learned.md` | 经验教训记录 |
| `docs/decisions/` | 架构决策日志 |
+52
View File
@@ -0,0 +1,52 @@
2026-07-19 10:53:45,896 [dashboard] MoFin Dashboard starting on port 5805
2026-07-19 10:53:45,896 [dashboard] Specs dir: /home/hmo/MoFin/specs
2026-07-19 10:53:45,896 [dashboard] Templates dir: /home/hmo/MoFin/templates
2026-07-19 10:53:45,896 [dashboard] proc_guard not available, skipping PID lock
2026-07-19 10:53:56,269 [dashboard] MoFin Dashboard starting on port 5805
2026-07-19 10:53:56,269 [dashboard] Specs dir: /home/hmo/MoFin/specs
2026-07-19 10:53:56,269 [dashboard] Templates dir: /home/hmo/MoFin/templates
2026-07-19 10:53:56,269 [dashboard] proc_guard not available, skipping PID lock
2026-07-19 10:54:06,498 [dashboard] MoFin Dashboard starting on port 5805
2026-07-19 10:54:06,498 [dashboard] Specs dir: /home/hmo/MoFin/specs
2026-07-19 10:54:06,498 [dashboard] Templates dir: /home/hmo/MoFin/templates
2026-07-19 10:54:06,498 [dashboard] proc_guard not available, skipping PID lock
2026-07-19 10:54:16,745 [dashboard] MoFin Dashboard starting on port 5805
2026-07-19 10:54:16,745 [dashboard] Specs dir: /home/hmo/MoFin/specs
2026-07-19 10:54:16,745 [dashboard] Templates dir: /home/hmo/MoFin/templates
2026-07-19 10:54:16,745 [dashboard] proc_guard not available, skipping PID lock
2026-07-19 10:54:26,989 [dashboard] MoFin Dashboard starting on port 5805
2026-07-19 10:54:26,989 [dashboard] Specs dir: /home/hmo/MoFin/specs
2026-07-19 10:54:26,989 [dashboard] Templates dir: /home/hmo/MoFin/templates
2026-07-19 10:54:26,989 [dashboard] proc_guard not available, skipping PID lock
2026-07-19 10:54:37,246 [dashboard] MoFin Dashboard starting on port 5805
2026-07-19 10:54:37,246 [dashboard] Specs dir: /home/hmo/MoFin/specs
2026-07-19 10:54:37,246 [dashboard] Templates dir: /home/hmo/MoFin/templates
2026-07-19 10:54:37,246 [dashboard] proc_guard not available, skipping PID lock
2026-07-19 10:54:47,458 [dashboard] MoFin Dashboard starting on port 5807
2026-07-19 10:54:47,458 [dashboard] Specs dir: /home/hmo/MoFin/specs
2026-07-19 10:54:47,458 [dashboard] Templates dir: /home/hmo/MoFin/templates
2026-07-19 10:54:47,459 [dashboard] proc_guard not available, skipping PID lock
2026-07-19 10:54:47,464 [dashboard] WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
* Running on all addresses (0.0.0.0)
* Running on http://127.0.0.1:5807
* Running on http://192.168.1.246:5807
2026-07-19 10:54:47,464 [dashboard] Press CTRL+C to quit
2026-07-19 10:54:55,309 [dashboard] MoFin Dashboard starting on port 5807
2026-07-19 10:54:55,309 [dashboard] Specs dir: /home/hmo/MoFin/specs
2026-07-19 10:54:55,309 [dashboard] Templates dir: /home/hmo/MoFin/templates
2026-07-19 10:54:55,309 [dashboard] proc_guard not available, skipping PID lock
2026-07-19 10:54:55,314 [dashboard] WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
* Running on all addresses (0.0.0.0)
* Running on http://127.0.0.1:5807
* Running on http://192.168.1.246:5807
2026-07-19 10:54:55,314 [dashboard] Press CTRL+C to quit
2026-07-19 10:55:13,917 [dashboard] 127.0.0.1 - - [19/Jul/2026 10:55:13] "GET /api/health HTTP/1.1" 200 -
2026-07-19 10:55:13,981 [dashboard] 127.0.0.1 - - [19/Jul/2026 10:55:13] "GET /api/health HTTP/1.1" 200 -
2026-07-19 10:55:13,987 [dashboard] 127.0.0.1 - - [19/Jul/2026 10:55:13] "GET /api/services HTTP/1.1" 200 -
2026-07-19 10:55:31,857 [dashboard] 127.0.0.1 - - [19/Jul/2026 10:55:31] "GET /api/health HTTP/1.1" 200 -
2026-07-19 10:55:40,596 [dashboard] 127.0.0.1 - - [19/Jul/2026 10:55:40] "GET /api/health HTTP/1.1" 200 -
2026-07-19 10:55:40,602 [dashboard] 127.0.0.1 - - [19/Jul/2026 10:55:40] "GET /api/monitor HTTP/1.1" 200 -
2026-07-19 10:55:40,639 [dashboard] 127.0.0.1 - - [19/Jul/2026 10:55:40] "GET /api/module-spec/health HTTP/1.1" 200 -
2026-07-19 10:56:17,871 [dashboard] 127.0.0.1 - - [19/Jul/2026 10:56:17] "GET / HTTP/1.1" 200 -
2026-07-19 10:56:17,898 [dashboard] 127.0.0.1 - - [19/Jul/2026 10:56:17] "GET / HTTP/1.1" 200 -
2026-07-19 11:00:01,611 [dashboard] 127.0.0.1 - - [19/Jul/2026 11:00:01] "GET /api/health HTTP/1.1" 200 -
+90
View File
@@ -0,0 +1,90 @@
[2026-07-19 14:30:01] ISSUES: 1 failed
- 知微 Gateway: <urlopen error [Errno 111] Connection refused>
[2026-07-19 14:45:01] ISSUES: 1 failed
- 知微 Gateway: <urlopen error [Errno 111] Connection refused>
[2026-07-19 14:50:01] ISSUES: 1 failed
- 知微 Gateway: <urlopen error [Errno 111] Connection refused>
[2026-07-19 15:10:01] ISSUES: 1 failed
- 知微 Gateway: <urlopen error [Errno 111] Connection refused>
[2026-07-19 15:16:56] ISSUES: 1 failed
- 知微 Gateway: <urlopen error [Errno 111] Connection refused>
[2026-07-19 15:20:01] ISSUES: 1 failed
- 知微 Gateway: <urlopen error [Errno 111] Connection refused>
[2026-07-19 15:35:01] ISSUES: 1 failed
- 知微 Gateway: timed out
[2026-07-19 15:40:01] ISSUES: 1 failed
- 知微 Gateway: <urlopen error [Errno 111] Connection refused>
[2026-07-19 15:45:01] ISSUES: 1 failed
- 知微 Gateway: <urlopen error [Errno 111] Connection refused>
[2026-07-19 15:50:01] ISSUES: 1 failed
- 知微 Gateway: <urlopen error [Errno 111] Connection refused>
[2026-07-19 16:00:01] ISSUES: 1 failed
- 知微 Gateway: <urlopen error [Errno 111] Connection refused>
[2026-07-19 16:05:01] ISSUES: 1 failed
- 知微 Gateway: <urlopen error [Errno 111] Connection refused>
[2026-07-19 16:20:01] ISSUES: 1 failed
- 知微 Gateway: <urlopen error [Errno 111] Connection refused>
[2026-07-19 16:30:01] ISSUES: 1 failed
- 知微 Gateway: <urlopen error [Errno 111] Connection refused>
[2026-07-19 16:35:01] ISSUES: 1 failed
- 知微 Gateway: <urlopen error [Errno 111] Connection refused>
[2026-07-19 16:40:02] ISSUES: 1 failed
- 知微 Gateway: <urlopen error [Errno 111] Connection refused>
[2026-07-19 16:55:01] ISSUES: 1 failed
- 知微 Gateway: <urlopen error [Errno 111] Connection refused>
[2026-07-19 17:00:01] ISSUES: 1 failed
- 知微 Gateway: <urlopen error [Errno 111] Connection refused>
[2026-07-19 17:05:01] ISSUES: 1 failed
- 知微 Gateway: <urlopen error [Errno 111] Connection refused>
[2026-07-19 17:10:02] ISSUES: 1 failed
- 知微 Gateway: <urlopen error [Errno 111] Connection refused>
[2026-07-19 17:15:01] ISSUES: 1 failed
- 知微 Gateway: <urlopen error [Errno 111] Connection refused>
[2026-07-19 17:20:01] ISSUES: 1 failed
- 知微 Gateway: <urlopen error [Errno 111] Connection refused>
[2026-07-19 17:25:01] ISSUES: 1 failed
- 知微 Gateway: <urlopen error [Errno 111] Connection refused>
[2026-07-19 17:45:01] ISSUES: 1 failed
- 知微 Gateway: <urlopen error [Errno 111] Connection refused>
[2026-07-19 17:55:02] ISSUES: 1 failed
- 知微 Gateway: <urlopen error [Errno 111] Connection refused>
[2026-07-19 18:00:01] ISSUES: 1 failed
- 知微 Gateway: <urlopen error [Errno 111] Connection refused>
[2026-07-19 18:05:01] ISSUES: 1 failed
- 知微 Gateway: <urlopen error [Errno 111] Connection refused>
[2026-07-19 18:15:01] ISSUES: 1 failed
- 知微 Gateway: <urlopen error [Errno 111] Connection refused>
[2026-07-19 18:15:32] ISSUES: 1 failed
- 知微 Gateway: <urlopen error [Errno 111] Connection refused>
[2026-07-19 18:20:01] ISSUES: 1 failed
- 知微 Gateway: <urlopen error [Errno 111] Connection refused>
[2026-07-19 18:22:09] ISSUES: 1 failed
- 知微 Gateway: <urlopen error [Errno 111] Connection refused>
[2026-07-19 18:25:01] ISSUES: 1 failed
- 知微 Gateway: <urlopen error [Errno 111] Connection refused>
[2026-07-19 18:30:02] ISSUES: 1 failed
- 知微 Gateway: <urlopen error [Errno 111] Connection refused>
[2026-07-19 18:35:02] ISSUES: 1 failed
- 知微 Gateway: timed out
[2026-07-19 18:40:01] ISSUES: 1 failed
- 知微 Gateway: timed out
[2026-07-19 18:45:01] ISSUES: 1 failed
- 知微 Gateway: <urlopen error [Errno 111] Connection refused>
[2026-07-19 18:50:01] ISSUES: 1 failed
- 知微 Gateway: <urlopen error [Errno 111] Connection refused>
[2026-07-19 18:55:02] ISSUES: 1 failed
- 知微 Gateway: <urlopen error [Errno 111] Connection refused>
[2026-07-19 19:00:01] ISSUES: 1 failed
- 知微 Gateway: timed out
[2026-07-19 19:05:02] ISSUES: 1 failed
- 知微 Gateway: timed out
[2026-07-19 19:10:01] ISSUES: 1 failed
- 知微 Gateway: <urlopen error [Errno 111] Connection refused>
[2026-07-19 19:30:01] ISSUES: 1 failed
- 知微 Gateway: <urlopen error [Errno 111] Connection refused>
[2026-07-19 19:50:01] AUTO-HEAL actions:
{"action": "check_keys", "best_key": "key6", "current_provider": "ocg-key6", "best_provider": "ocg-key6", "rolling_pct": 38, "weekly_pct": 28, "issues": []}
{"action": "restart_hermes_gateway", "target": "position-analyst", "success": true, "detail": "restart triggered (async)"}
[2026-07-19 20:40:01] Gateway DOWN → systemctl restart triggered (async, cooldown set)
[2026-07-19 20:40:01] ISSUES: 1 failed
- 知微 Gateway: timed out
+102
View File
@@ -0,0 +1,102 @@
[14:30] Health check: 1/4 services failed
FAIL: 知微 Gateway (zhiwei_gateway) — <urlopen error [Errno 111] Connection refused>
[14:45] Health check: 1/4 services failed
FAIL: 知微 Gateway (zhiwei_gateway) — <urlopen error [Errno 111] Connection refused>
[14:50] Health check: 1/4 services failed
FAIL: 知微 Gateway (zhiwei_gateway) — <urlopen error [Errno 111] Connection refused>
[15:10] Health check: 1/4 services failed
FAIL: 知微 Gateway (zhiwei_gateway) — <urlopen error [Errno 111] Connection refused>
Traceback (most recent call last):
File "/home/hmo/MoFin/agents_health_check.py", line 143, in <module>
run()
File "/home/hmo/MoFin/agents_health_check.py", line 110, in run
_collect_xmpp_health(now)
^^^^^^^^^^^^^^^^^^^^
NameError: name '_collect_xmpp_health' is not defined
[15:20] Health check: 1/4 services failed
FAIL: 知微 Gateway (zhiwei_gateway) — <urlopen error [Errno 111] Connection refused>
[15:35] Health check: 1/4 services failed
FAIL: 知微 Gateway (zhiwei_gateway) — timed out
[15:40] Health check: 1/4 services failed
FAIL: 知微 Gateway (zhiwei_gateway) — <urlopen error [Errno 111] Connection refused>
[15:45] Health check: 1/4 services failed
FAIL: 知微 Gateway (zhiwei_gateway) — <urlopen error [Errno 111] Connection refused>
[15:50] Health check: 1/4 services failed
FAIL: 知微 Gateway (zhiwei_gateway) — <urlopen error [Errno 111] Connection refused>
[16:00] Health check: 1/4 services failed
FAIL: 知微 Gateway (zhiwei_gateway) — <urlopen error [Errno 111] Connection refused>
[16:05] Health check: 1/4 services failed
FAIL: 知微 Gateway (zhiwei_gateway) — <urlopen error [Errno 111] Connection refused>
[16:20] Health check: 1/4 services failed
FAIL: 知微 Gateway (zhiwei_gateway) — <urlopen error [Errno 111] Connection refused>
[16:30] Health check: 1/4 services failed
FAIL: 知微 Gateway (zhiwei_gateway) — <urlopen error [Errno 111] Connection refused>
[16:35] Health check: 1/4 services failed
FAIL: 知微 Gateway (zhiwei_gateway) — <urlopen error [Errno 111] Connection refused>
[16:40] Health check: 1/4 services failed
FAIL: 知微 Gateway (zhiwei_gateway) — <urlopen error [Errno 111] Connection refused>
[16:55] Health check: 1/4 services failed
FAIL: 知微 Gateway (zhiwei_gateway) — <urlopen error [Errno 111] Connection refused>
[17:00] Health check: 1/4 services failed
FAIL: 知微 Gateway (zhiwei_gateway) — <urlopen error [Errno 111] Connection refused>
[17:05] Health check: 1/4 services failed
FAIL: 知微 Gateway (zhiwei_gateway) — <urlopen error [Errno 111] Connection refused>
[17:10] Health check: 1/4 services failed
FAIL: 知微 Gateway (zhiwei_gateway) — <urlopen error [Errno 111] Connection refused>
[17:15] Health check: 1/4 services failed
FAIL: 知微 Gateway (zhiwei_gateway) — <urlopen error [Errno 111] Connection refused>
[17:20] Health check: 1/4 services failed
FAIL: 知微 Gateway (zhiwei_gateway) — <urlopen error [Errno 111] Connection refused>
[17:25] Health check: 1/4 services failed
FAIL: 知微 Gateway (zhiwei_gateway) — <urlopen error [Errno 111] Connection refused>
[17:45] Health check: 1/4 services failed
FAIL: 知微 Gateway (zhiwei_gateway) — <urlopen error [Errno 111] Connection refused>
[17:55] Health check: 1/4 services failed
FAIL: 知微 Gateway (zhiwei_gateway) — <urlopen error [Errno 111] Connection refused>
[18:00] Health check: 1/4 services failed
FAIL: 知微 Gateway (zhiwei_gateway) — <urlopen error [Errno 111] Connection refused>
[18:05] Health check: 1/4 services failed
FAIL: 知微 Gateway (zhiwei_gateway) — <urlopen error [Errno 111] Connection refused>
[18:15] Health check: 1/4 services failed
FAIL: 知微 Gateway (zhiwei_gateway) — <urlopen error [Errno 111] Connection refused>
[18:20] Health check: 1/4 services failed
FAIL: 知微 Gateway (zhiwei_gateway) — <urlopen error [Errno 111] Connection refused>
[18:25] Auto-heal: Gateway DOWN → restarted
[18:25] Health check: 1/4 services failed
FAIL: 知微 Gateway (zhiwei_gateway) — <urlopen error [Errno 111] Connection refused>
[18:30] Auto-heal: Gateway DOWN → restarted
[18:30] Health check: 1/4 services failed
FAIL: 知微 Gateway (zhiwei_gateway) — <urlopen error [Errno 111] Connection refused>
[18:35] Auto-heal: Gateway DOWN → restarted
[18:35] Health check: 1/4 services failed
FAIL: 知微 Gateway (zhiwei_gateway) — timed out
[18:40] Auto-heal: Gateway DOWN → restarted
[18:40] Health check: 1/4 services failed
FAIL: 知微 Gateway (zhiwei_gateway) — timed out
[18:45] Auto-heal: Gateway DOWN → restarted
[18:45] Health check: 1/4 services failed
FAIL: 知微 Gateway (zhiwei_gateway) — <urlopen error [Errno 111] Connection refused>
[18:50] Auto-heal: Gateway DOWN → restarted
[18:50] Health check: 1/4 services failed
FAIL: 知微 Gateway (zhiwei_gateway) — <urlopen error [Errno 111] Connection refused>
[18:55] Auto-heal: Gateway DOWN → restarted
[18:55] Health check: 1/4 services failed
FAIL: 知微 Gateway (zhiwei_gateway) — <urlopen error [Errno 111] Connection refused>
[19:00] Auto-heal: Gateway DOWN → restarted
[19:00] Health check: 1/4 services failed
FAIL: 知微 Gateway (zhiwei_gateway) — timed out
[19:05] Auto-heal: Gateway DOWN → restarted
[19:05] Health check: 1/4 services failed
FAIL: 知微 Gateway (zhiwei_gateway) — timed out
[19:10] Auto-heal: Gateway DOWN → restarted
[19:10] Health check: 1/4 services failed
FAIL: 知微 Gateway (zhiwei_gateway) — <urlopen error [Errno 111] Connection refused>
[19:30] Auto-heal: Gateway DOWN → restarted
[19:30] Health check: 1/4 services failed
FAIL: 知微 Gateway (zhiwei_gateway) — <urlopen error [Errno 111] Connection refused>
[19:50] Auto-heal: 2 action(s) — degraded
→ check_keys: success=?
→ restart_hermes_gateway: success=True
[20:40] Gateway DOWN → systemctl restart triggered
[20:40] Health check: 1/4 services failed
FAIL: 知微 Gateway (zhiwei_gateway) — timed out
+1
View File
@@ -0,0 +1 @@
1784464840.6959908
+71
View File
@@ -0,0 +1,71 @@
{"timestamp": "2026-07-19 15:16:56", "status": "no_data", "last_message_age_sec": -1, "error_rate_1h": 0, "bot_activity": {"inbound": 0, "outbound": 0, "errors": 0, "last_error": null, "last_inbound": null, "last_outbound": null}, "gateways": {"zhiwei": {"port": 8643, "alive": false}, "mohe": {"port": 8642, "alive": true}, "xiaoguo": {"port": 8645, "alive": true}}, "llm_provider": {}, "best_key": {"key_id": "key6", "label": "key6 (ycdennismo@163.com)", "masked": "sk-oF1WG...hCS3", "rolling": {"reset_in_sec": 10509, "status": "ok", "usage_percent": 7}, "weekly": {"reset_in_sec": 60188, "status": "ok", "usage_percent": 13}, "monthly": {"reset_in_sec": 2489884, "status": "ok", "usage_percent": 6}, "session_expired": false, "issues": [], "total_keys": 6}}
{"timestamp": "2026-07-19 15:20:01", "status": "no_data", "last_message_age_sec": -1, "error_rate_1h": 0, "bot_activity": {"inbound": 0, "outbound": 0, "errors": 0, "last_error": null, "last_inbound": null, "last_outbound": null}, "gateways": {"zhiwei": {"port": 8643, "alive": false}, "mohe": {"port": 8642, "alive": true}, "xiaoguo": {"port": 8645, "alive": true}}, "llm_provider": {}, "best_key": {"key_id": "key6", "label": "key6 (ycdennismo@163.com)", "masked": "sk-oF1WG...hCS3", "rolling": {"reset_in_sec": 10509, "status": "ok", "usage_percent": 7}, "weekly": {"reset_in_sec": 60188, "status": "ok", "usage_percent": 13}, "monthly": {"reset_in_sec": 2489884, "status": "ok", "usage_percent": 6}, "session_expired": false, "issues": [], "total_keys": 6}}
{"timestamp": "2026-07-19 15:25:01", "status": "degraded", "last_message_age_sec": -1, "error_rate_1h": 0, "bot_activity": {"inbound": 0, "outbound": 0, "errors": 0, "last_error": null, "last_inbound": null, "last_outbound": null}, "gateways": {"zhiwei": {"port": 8643, "alive": true}, "mohe": {"port": 8642, "alive": true}, "xiaoguo": {"port": 8645, "alive": true}}, "llm_provider": {"status": "error", "error": "timed out"}, "best_key": {"key_id": "key6", "label": "key6 (ycdennismo@163.com)", "masked": "sk-oF1WG...hCS3", "rolling": {"reset_in_sec": 10200, "status": "ok", "usage_percent": 7}, "weekly": {"reset_in_sec": 59879, "status": "ok", "usage_percent": 13}, "monthly": {"reset_in_sec": 2489575, "status": "ok", "usage_percent": 6}, "session_expired": false, "issues": [], "total_keys": 6}}
{"timestamp": "2026-07-19 15:30:02", "status": "degraded", "last_message_age_sec": -1, "error_rate_1h": 0, "bot_activity": {"inbound": 0, "outbound": 0, "errors": 0, "last_error": null, "last_inbound": null, "last_outbound": null}, "gateways": {"zhiwei": {"port": 8643, "alive": true}, "mohe": {"port": 8642, "alive": true}, "xiaoguo": {"port": 8645, "alive": true}}, "llm_provider": {"status": "error", "error": "timed out"}, "best_key": {"key_id": "key6", "label": "key6 (ycdennismo@163.com)", "masked": "sk-oF1WG...hCS3", "rolling": {"reset_in_sec": 9887, "status": "ok", "usage_percent": 7}, "weekly": {"reset_in_sec": 59566, "status": "ok", "usage_percent": 13}, "monthly": {"reset_in_sec": 2489262, "status": "ok", "usage_percent": 6}, "session_expired": false, "issues": [], "total_keys": 6}}
{"timestamp": "2026-07-19 15:35:01", "status": "degraded", "last_message_age_sec": -1, "error_rate_1h": 0, "bot_activity": {"inbound": 0, "outbound": 0, "errors": 0, "last_error": null, "last_inbound": null, "last_outbound": null}, "gateways": {"zhiwei": {"port": 8643, "alive": true}, "mohe": {"port": 8642, "alive": true}, "xiaoguo": {"port": 8645, "alive": true}}, "llm_provider": {"status": "error", "error": "timed out"}, "best_key": {"key_id": "key6", "label": "key6 (ycdennismo@163.com)", "masked": "sk-oF1WG...hCS3", "rolling": {"reset_in_sec": 9576, "status": "ok", "usage_percent": 7}, "weekly": {"reset_in_sec": 59255, "status": "ok", "usage_percent": 13}, "monthly": {"reset_in_sec": 2488951, "status": "ok", "usage_percent": 6}, "session_expired": false, "issues": [], "total_keys": 6}}
{"timestamp": "2026-07-19 15:40:01", "status": "no_data", "last_message_age_sec": -1, "error_rate_1h": 0, "bot_activity": {"inbound": 0, "outbound": 0, "errors": 0, "last_error": null, "last_inbound": null, "last_outbound": null}, "gateways": {"zhiwei": {"port": 8643, "alive": false}, "mohe": {"port": 8642, "alive": true}, "xiaoguo": {"port": 8645, "alive": true}}, "llm_provider": {}, "best_key": {"key_id": "key6", "label": "key6 (ycdennismo@163.com)", "masked": "sk-oF1WG...hCS3", "rolling": {"reset_in_sec": 9262, "status": "ok", "usage_percent": 7}, "weekly": {"reset_in_sec": 58941, "status": "ok", "usage_percent": 13}, "monthly": {"reset_in_sec": 2488637, "status": "ok", "usage_percent": 6}, "session_expired": false, "issues": [], "total_keys": 6}}
{"timestamp": "2026-07-19 15:45:01", "status": "no_data", "last_message_age_sec": -1, "error_rate_1h": 0, "bot_activity": {"inbound": 0, "outbound": 0, "errors": 0, "last_error": null, "last_inbound": null, "last_outbound": null}, "gateways": {"zhiwei": {"port": 8643, "alive": false}, "mohe": {"port": 8642, "alive": true}, "xiaoguo": {"port": 8645, "alive": true}}, "llm_provider": {}, "best_key": {"key_id": "key6", "label": "key6 (ycdennismo@163.com)", "masked": "sk-oF1WG...hCS3", "rolling": {"reset_in_sec": 8952, "status": "ok", "usage_percent": 7}, "weekly": {"reset_in_sec": 58631, "status": "ok", "usage_percent": 13}, "monthly": {"reset_in_sec": 2488327, "status": "ok", "usage_percent": 6}, "session_expired": false, "issues": [], "total_keys": 6}}
{"timestamp": "2026-07-19 15:50:01", "status": "no_data", "last_message_age_sec": -1, "error_rate_1h": 0, "bot_activity": {"inbound": 0, "outbound": 0, "errors": 0, "last_error": null, "last_inbound": null, "last_outbound": null}, "gateways": {"zhiwei": {"port": 8643, "alive": false}, "mohe": {"port": 8642, "alive": true}, "xiaoguo": {"port": 8645, "alive": true}}, "llm_provider": {}, "best_key": {"key_id": "key6", "label": "key6 (ycdennismo@163.com)", "masked": "sk-oF1WG...hCS3", "rolling": {"reset_in_sec": 8643, "status": "ok", "usage_percent": 7}, "weekly": {"reset_in_sec": 58322, "status": "ok", "usage_percent": 13}, "monthly": {"reset_in_sec": 2488018, "status": "ok", "usage_percent": 6}, "session_expired": false, "issues": [], "total_keys": 6}}
{"timestamp": "2026-07-19 15:55:01", "status": "degraded", "last_message_age_sec": -1, "error_rate_1h": 0, "bot_activity": {"inbound": 0, "outbound": 0, "errors": 0, "last_error": null, "last_inbound": null, "last_outbound": null}, "gateways": {"zhiwei": {"port": 8643, "alive": true}, "mohe": {"port": 8642, "alive": true}, "xiaoguo": {"port": 8645, "alive": true}}, "llm_provider": {"status": "error", "error": "timed out"}, "best_key": {"key_id": "key6", "label": "key6 (ycdennismo@163.com)", "masked": "sk-oF1WG...hCS3", "rolling": {"reset_in_sec": 8333, "status": "ok", "usage_percent": 7}, "weekly": {"reset_in_sec": 58012, "status": "ok", "usage_percent": 13}, "monthly": {"reset_in_sec": 2487708, "status": "ok", "usage_percent": 6}, "session_expired": false, "issues": [], "total_keys": 6}}
{"timestamp": "2026-07-19 16:00:01", "status": "no_data", "last_message_age_sec": -1, "error_rate_1h": 0, "bot_activity": {"inbound": 0, "outbound": 0, "errors": 0, "last_error": null, "last_inbound": null, "last_outbound": null}, "gateways": {"zhiwei": {"port": 8643, "alive": false}, "mohe": {"port": 8642, "alive": true}, "xiaoguo": {"port": 8645, "alive": true}}, "llm_provider": {}, "best_key": {"key_id": "key6", "label": "key6 (ycdennismo@163.com)", "masked": "sk-oF1WG...hCS3", "rolling": {"reset_in_sec": 8022, "status": "ok", "usage_percent": 7}, "weekly": {"reset_in_sec": 57701, "status": "ok", "usage_percent": 13}, "monthly": {"reset_in_sec": 2487397, "status": "ok", "usage_percent": 6}, "session_expired": false, "issues": [], "total_keys": 6}}
{"timestamp": "2026-07-19 16:05:01", "status": "no_data", "last_message_age_sec": -1, "error_rate_1h": 0, "bot_activity": {"inbound": 0, "outbound": 0, "errors": 0, "last_error": null, "last_inbound": null, "last_outbound": null}, "gateways": {"zhiwei": {"port": 8643, "alive": false}, "mohe": {"port": 8642, "alive": true}, "xiaoguo": {"port": 8645, "alive": true}}, "llm_provider": {}, "best_key": {"key_id": "key6", "label": "key6 (ycdennismo@163.com)", "masked": "sk-oF1WG...hCS3", "rolling": {"reset_in_sec": 7710, "status": "ok", "usage_percent": 7}, "weekly": {"reset_in_sec": 57389, "status": "ok", "usage_percent": 13}, "monthly": {"reset_in_sec": 2487085, "status": "ok", "usage_percent": 6}, "session_expired": false, "issues": [], "total_keys": 6}}
{"timestamp": "2026-07-19 16:10:01", "status": "degraded", "last_message_age_sec": -1, "error_rate_1h": 0, "bot_activity": {"inbound": 0, "outbound": 0, "errors": 0, "last_error": null, "last_inbound": null, "last_outbound": null}, "gateways": {"zhiwei": {"port": 8643, "alive": true}, "mohe": {"port": 8642, "alive": true}, "xiaoguo": {"port": 8645, "alive": true}}, "llm_provider": {"status": "error", "error": "timed out"}, "best_key": {"key_id": "key6", "label": "key6 (ycdennismo@163.com)", "masked": "sk-oF1WG...hCS3", "rolling": {"reset_in_sec": 7397, "status": "ok", "usage_percent": 7}, "weekly": {"reset_in_sec": 57076, "status": "ok", "usage_percent": 13}, "monthly": {"reset_in_sec": 2486772, "status": "ok", "usage_percent": 6}, "session_expired": false, "issues": [], "total_keys": 6}}
{"timestamp": "2026-07-19 16:15:01", "status": "degraded", "last_message_age_sec": -1, "error_rate_1h": 0, "bot_activity": {"inbound": 0, "outbound": 0, "errors": 0, "last_error": null, "last_inbound": null, "last_outbound": null}, "gateways": {"zhiwei": {"port": 8643, "alive": true}, "mohe": {"port": 8642, "alive": true}, "xiaoguo": {"port": 8645, "alive": true}}, "llm_provider": {"status": "error", "error": "timed out"}, "best_key": {"key_id": "key6", "label": "key6 (ycdennismo@163.com)", "masked": "sk-oF1WG...hCS3", "rolling": {"reset_in_sec": 7085, "status": "ok", "usage_percent": 7}, "weekly": {"reset_in_sec": 56764, "status": "ok", "usage_percent": 13}, "monthly": {"reset_in_sec": 2486460, "status": "ok", "usage_percent": 6}, "session_expired": false, "issues": [], "total_keys": 6}}
{"timestamp": "2026-07-19 16:20:01", "status": "no_data", "last_message_age_sec": -1, "error_rate_1h": 0, "bot_activity": {"inbound": 0, "outbound": 0, "errors": 0, "last_error": null, "last_inbound": null, "last_outbound": null}, "gateways": {"zhiwei": {"port": 8643, "alive": false}, "mohe": {"port": 8642, "alive": true}, "xiaoguo": {"port": 8645, "alive": true}}, "llm_provider": {}, "best_key": {"key_id": "key6", "label": "key6 (ycdennismo@163.com)", "masked": "sk-oF1WG...hCS3", "rolling": {"reset_in_sec": 6768, "status": "ok", "usage_percent": 7}, "weekly": {"reset_in_sec": 56447, "status": "ok", "usage_percent": 13}, "monthly": {"reset_in_sec": 2486143, "status": "ok", "usage_percent": 6}, "session_expired": false, "issues": [], "total_keys": 6}}
{"timestamp": "2026-07-19 16:25:01", "status": "degraded", "last_message_age_sec": -1, "error_rate_1h": 0, "bot_activity": {"inbound": 0, "outbound": 0, "errors": 0, "last_error": null, "last_inbound": null, "last_outbound": null}, "gateways": {"zhiwei": {"port": 8643, "alive": true}, "mohe": {"port": 8642, "alive": true}, "xiaoguo": {"port": 8645, "alive": true}}, "llm_provider": {"status": "error", "error": "timed out"}, "best_key": {"key_id": "key6", "label": "key6 (ycdennismo@163.com)", "masked": "sk-oF1WG...hCS3", "rolling": {"reset_in_sec": 6452, "status": "ok", "usage_percent": 7}, "weekly": {"reset_in_sec": 56131, "status": "ok", "usage_percent": 13}, "monthly": {"reset_in_sec": 2485827, "status": "ok", "usage_percent": 6}, "session_expired": false, "issues": [], "total_keys": 6}}
{"timestamp": "2026-07-19 16:30:01", "status": "no_data", "last_message_age_sec": -1, "error_rate_1h": 0, "bot_activity": {"inbound": 0, "outbound": 0, "errors": 0, "last_error": null, "last_inbound": null, "last_outbound": null}, "gateways": {"zhiwei": {"port": 8643, "alive": false}, "mohe": {"port": 8642, "alive": true}, "xiaoguo": {"port": 8645, "alive": true}}, "llm_provider": {}, "best_key": {"key_id": "key6", "label": "key6 (ycdennismo@163.com)", "masked": "sk-oF1WG...hCS3", "rolling": {"reset_in_sec": 6142, "status": "ok", "usage_percent": 7}, "weekly": {"reset_in_sec": 55821, "status": "ok", "usage_percent": 13}, "monthly": {"reset_in_sec": 2485517, "status": "ok", "usage_percent": 6}, "session_expired": false, "issues": [], "total_keys": 6}}
{"timestamp": "2026-07-19 16:35:01", "status": "ok", "last_message_age_sec": 59, "error_rate_1h": 0.0, "bot_activity": {"inbound": 0, "outbound": 0, "errors": 0, "last_error": null, "last_inbound": null, "last_outbound": null}, "gateways": {"zhiwei": {"port": 8643, "alive": false}, "mohe": {"port": 8642, "alive": true}, "xiaoguo": {"port": 8645, "alive": true}}, "llm_provider": {}, "best_key": {"key_id": "key6", "label": "key6 (ycdennismo@163.com)", "masked": "sk-oF1WG...hCS3", "rolling": {"reset_in_sec": 5832, "status": "ok", "usage_percent": 7}, "weekly": {"reset_in_sec": 55511, "status": "ok", "usage_percent": 13}, "monthly": {"reset_in_sec": 2485207, "status": "ok", "usage_percent": 6}, "session_expired": false, "issues": [], "total_keys": 6}}
{"timestamp": "2026-07-19 16:40:02", "status": "ok", "last_message_age_sec": 360, "error_rate_1h": 0.0, "bot_activity": {"inbound": 0, "outbound": 0, "errors": 0, "last_error": null, "last_inbound": null, "last_outbound": null}, "gateways": {"zhiwei": {"port": 8643, "alive": false}, "mohe": {"port": 8642, "alive": true}, "xiaoguo": {"port": 8645, "alive": true}}, "llm_provider": {}, "best_key": {"key_id": "key6", "label": "key6 (ycdennismo@163.com)", "masked": "sk-oF1WG...hCS3", "rolling": {"reset_in_sec": 5832, "status": "ok", "usage_percent": 7}, "weekly": {"reset_in_sec": 55511, "status": "ok", "usage_percent": 13}, "monthly": {"reset_in_sec": 2485207, "status": "ok", "usage_percent": 6}, "session_expired": false, "issues": [], "total_keys": 6}}
{"timestamp": "2026-07-19 16:45:01", "status": "degraded", "last_message_age_sec": 658, "error_rate_1h": 0.0, "bot_activity": {"inbound": 0, "outbound": 0, "errors": 0, "last_error": null, "last_inbound": null, "last_outbound": null}, "gateways": {"zhiwei": {"port": 8643, "alive": true}, "mohe": {"port": 8642, "alive": true}, "xiaoguo": {"port": 8645, "alive": true}}, "llm_provider": {"status": "error", "error": "timed out"}, "best_key": {"key_id": "key6", "label": "key6 (ycdennismo@163.com)", "masked": "sk-oF1WG...hCS3", "rolling": {"reset_in_sec": 5516, "status": "ok", "usage_percent": 7}, "weekly": {"reset_in_sec": 55195, "status": "ok", "usage_percent": 13}, "monthly": {"reset_in_sec": 2484891, "status": "ok", "usage_percent": 6}, "session_expired": false, "issues": [], "total_keys": 6}}
{"timestamp": "2026-07-19 16:50:01", "status": "degraded", "last_message_age_sec": 959, "error_rate_1h": 0.0, "bot_activity": {"inbound": 0, "outbound": 0, "errors": 0, "last_error": null, "last_inbound": null, "last_outbound": null}, "gateways": {"zhiwei": {"port": 8643, "alive": true}, "mohe": {"port": 8642, "alive": true}, "xiaoguo": {"port": 8645, "alive": true}}, "llm_provider": {"status": "error", "error": "timed out"}, "best_key": {"key_id": "key6", "label": "key6 (ycdennismo@163.com)", "masked": "sk-oF1WG...hCS3", "rolling": {"reset_in_sec": 5206, "status": "ok", "usage_percent": 7}, "weekly": {"reset_in_sec": 54885, "status": "ok", "usage_percent": 13}, "monthly": {"reset_in_sec": 2484581, "status": "ok", "usage_percent": 6}, "session_expired": false, "issues": [], "total_keys": 6}}
{"timestamp": "2026-07-19 16:55:01", "status": "critical", "last_message_age_sec": 1259, "error_rate_1h": 0.0, "bot_activity": {"inbound": 0, "outbound": 0, "errors": 0, "last_error": null, "last_inbound": null, "last_outbound": null}, "gateways": {"zhiwei": {"port": 8643, "alive": false}, "mohe": {"port": 8642, "alive": true}, "xiaoguo": {"port": 8645, "alive": true}}, "llm_provider": {}, "best_key": {"key_id": "key6", "label": "key6 (ycdennismo@163.com)", "masked": "sk-oF1WG...hCS3", "rolling": {"reset_in_sec": 4897, "status": "ok", "usage_percent": 7}, "weekly": {"reset_in_sec": 54576, "status": "ok", "usage_percent": 13}, "monthly": {"reset_in_sec": 2484272, "status": "ok", "usage_percent": 6}, "session_expired": false, "issues": [], "total_keys": 6}}
{"timestamp": "2026-07-19 17:00:01", "status": "critical", "last_message_age_sec": 1559, "error_rate_1h": 0.0, "bot_activity": {"inbound": 0, "outbound": 0, "errors": 0, "last_error": null, "last_inbound": null, "last_outbound": null}, "gateways": {"zhiwei": {"port": 8643, "alive": false}, "mohe": {"port": 8642, "alive": true}, "xiaoguo": {"port": 8645, "alive": true}}, "llm_provider": {}, "best_key": {"key_id": "key6", "label": "key6 (ycdennismo@163.com)", "masked": "sk-oF1WG...hCS3", "rolling": {"reset_in_sec": 4589, "status": "ok", "usage_percent": 7}, "weekly": {"reset_in_sec": 54268, "status": "ok", "usage_percent": 13}, "monthly": {"reset_in_sec": 2483964, "status": "ok", "usage_percent": 6}, "session_expired": false, "issues": [], "total_keys": 6}}
{"timestamp": "2026-07-19 17:05:01", "status": "critical", "last_message_age_sec": 1859, "error_rate_1h": 0.0, "bot_activity": {"inbound": 0, "outbound": 0, "errors": 0, "last_error": null, "last_inbound": null, "last_outbound": null}, "gateways": {"zhiwei": {"port": 8643, "alive": false}, "mohe": {"port": 8642, "alive": true}, "xiaoguo": {"port": 8645, "alive": true}}, "llm_provider": {}, "best_key": {"key_id": "key6", "label": "key6 (ycdennismo@163.com)", "masked": "sk-oF1WG...hCS3", "rolling": {"reset_in_sec": 4280, "status": "ok", "usage_percent": 7}, "weekly": {"reset_in_sec": 53959, "status": "ok", "usage_percent": 13}, "monthly": {"reset_in_sec": 2483655, "status": "ok", "usage_percent": 6}, "session_expired": false, "issues": [], "total_keys": 6}}
{"timestamp": "2026-07-19 17:10:02", "status": "critical", "last_message_age_sec": 2159, "error_rate_1h": 0.0, "bot_activity": {"inbound": 0, "outbound": 0, "errors": 0, "last_error": null, "last_inbound": null, "last_outbound": null}, "gateways": {"zhiwei": {"port": 8643, "alive": false}, "mohe": {"port": 8642, "alive": true}, "xiaoguo": {"port": 8645, "alive": true}}, "llm_provider": {}, "best_key": {"key_id": "key6", "label": "key6 (ycdennismo@163.com)", "masked": "sk-oF1WG...hCS3", "rolling": {"reset_in_sec": 3970, "status": "ok", "usage_percent": 7}, "weekly": {"reset_in_sec": 53649, "status": "ok", "usage_percent": 13}, "monthly": {"reset_in_sec": 2483345, "status": "ok", "usage_percent": 6}, "session_expired": false, "issues": [], "total_keys": 6}}
{"timestamp": "2026-07-19 17:15:01", "status": "critical", "last_message_age_sec": 2459, "error_rate_1h": 0.0, "bot_activity": {"inbound": 0, "outbound": 0, "errors": 0, "last_error": null, "last_inbound": null, "last_outbound": null}, "gateways": {"zhiwei": {"port": 8643, "alive": false}, "mohe": {"port": 8642, "alive": true}, "xiaoguo": {"port": 8645, "alive": true}}, "llm_provider": {}, "best_key": {"key_id": "key6", "label": "key6 (ycdennismo@163.com)", "masked": "sk-oF1WG...hCS3", "rolling": {"reset_in_sec": 3659, "status": "ok", "usage_percent": 7}, "weekly": {"reset_in_sec": 53338, "status": "ok", "usage_percent": 13}, "monthly": {"reset_in_sec": 2483034, "status": "ok", "usage_percent": 6}, "session_expired": false, "issues": [], "total_keys": 6}}
{"timestamp": "2026-07-19 17:20:01", "status": "critical", "last_message_age_sec": 2760, "error_rate_1h": 0.0, "bot_activity": {"inbound": 0, "outbound": 0, "errors": 0, "last_error": null, "last_inbound": null, "last_outbound": null}, "gateways": {"zhiwei": {"port": 8643, "alive": false}, "mohe": {"port": 8642, "alive": true}, "xiaoguo": {"port": 8645, "alive": true}}, "llm_provider": {}, "best_key": {"key_id": "key6", "label": "key6 (ycdennismo@163.com)", "masked": "sk-oF1WG...hCS3", "rolling": {"reset_in_sec": 3350, "status": "ok", "usage_percent": 7}, "weekly": {"reset_in_sec": 53029, "status": "ok", "usage_percent": 13}, "monthly": {"reset_in_sec": 2482725, "status": "ok", "usage_percent": 6}, "session_expired": false, "issues": [], "total_keys": 6}}
{"timestamp": "2026-07-19 17:25:01", "status": "degraded", "last_message_age_sec": 3059, "error_rate_1h": 0.0, "bot_activity": {"inbound": 0, "outbound": 0, "errors": 0, "last_error": null, "last_inbound": null, "last_outbound": null}, "gateways": {"zhiwei": {"port": 8643, "alive": true}, "mohe": {"port": 8642, "alive": true}, "xiaoguo": {"port": 8645, "alive": true}}, "llm_provider": {"status": "error", "error": "timed out"}, "best_key": {"key_id": "key6", "label": "key6 (ycdennismo@163.com)", "masked": "sk-oF1WG...hCS3", "rolling": {"reset_in_sec": 3040, "status": "ok", "usage_percent": 7}, "weekly": {"reset_in_sec": 52719, "status": "ok", "usage_percent": 13}, "monthly": {"reset_in_sec": 2482415, "status": "ok", "usage_percent": 6}, "session_expired": false, "issues": [], "total_keys": 6}}
{"timestamp": "2026-07-19 17:30:01", "status": "critical", "last_message_age_sec": 3360, "error_rate_1h": 0.0, "bot_activity": {"inbound": 0, "outbound": 0, "errors": 0, "last_error": null, "last_inbound": null, "last_outbound": null}, "gateways": {"zhiwei": {"port": 8643, "alive": false}, "mohe": {"port": 8642, "alive": true}, "xiaoguo": {"port": 8645, "alive": true}}, "llm_provider": {}, "best_key": {"key_id": "key6", "label": "key6 (ycdennismo@163.com)", "masked": "sk-oF1WG...hCS3", "rolling": {"reset_in_sec": 2731, "status": "ok", "usage_percent": 7}, "weekly": {"reset_in_sec": 52410, "status": "ok", "usage_percent": 13}, "monthly": {"reset_in_sec": 2482106, "status": "ok", "usage_percent": 6}, "session_expired": false, "issues": [], "total_keys": 6}}
{"timestamp": "2026-07-19 17:35:01", "status": "degraded", "last_message_age_sec": 3659, "error_rate_1h": 0, "bot_activity": {"inbound": 0, "outbound": 0, "errors": 0, "last_error": null, "last_inbound": null, "last_outbound": null}, "gateways": {"zhiwei": {"port": 8643, "alive": true}, "mohe": {"port": 8642, "alive": true}, "xiaoguo": {"port": 8645, "alive": true}}, "llm_provider": {"status": "error", "error": "timed out"}, "best_key": {"key_id": "key6", "label": "key6 (ycdennismo@163.com)", "masked": "sk-oF1WG...hCS3", "rolling": {"reset_in_sec": 2422, "status": "ok", "usage_percent": 7}, "weekly": {"reset_in_sec": 52101, "status": "ok", "usage_percent": 13}, "monthly": {"reset_in_sec": 2481797, "status": "ok", "usage_percent": 6}, "session_expired": false, "issues": [], "total_keys": 6}}
{"timestamp": "2026-07-19 17:40:01", "status": "degraded", "last_message_age_sec": 3959, "error_rate_1h": 0, "bot_activity": {"inbound": 0, "outbound": 0, "errors": 0, "last_error": null, "last_inbound": null, "last_outbound": null}, "gateways": {"zhiwei": {"port": 8643, "alive": true}, "mohe": {"port": 8642, "alive": true}, "xiaoguo": {"port": 8645, "alive": true}}, "llm_provider": {"status": "error", "error": "timed out"}, "best_key": {"key_id": "key6", "label": "key6 (ycdennismo@163.com)", "masked": "sk-oF1WG...hCS3", "rolling": {"reset_in_sec": 2104, "status": "ok", "usage_percent": 7}, "weekly": {"reset_in_sec": 51783, "status": "ok", "usage_percent": 13}, "monthly": {"reset_in_sec": 2481479, "status": "ok", "usage_percent": 6}, "session_expired": false, "issues": [], "total_keys": 6}}
{"timestamp": "2026-07-19 17:45:01", "status": "critical", "last_message_age_sec": 4259, "error_rate_1h": 0, "bot_activity": {"inbound": 0, "outbound": 0, "errors": 0, "last_error": null, "last_inbound": null, "last_outbound": null}, "gateways": {"zhiwei": {"port": 8643, "alive": false}, "mohe": {"port": 8642, "alive": true}, "xiaoguo": {"port": 8645, "alive": true}}, "llm_provider": {}, "best_key": {"key_id": "key6", "label": "key6 (ycdennismo@163.com)", "masked": "sk-oF1WG...hCS3", "rolling": {"reset_in_sec": 1795, "status": "ok", "usage_percent": 7}, "weekly": {"reset_in_sec": 51474, "status": "ok", "usage_percent": 13}, "monthly": {"reset_in_sec": 2481170, "status": "ok", "usage_percent": 6}, "session_expired": false, "issues": [], "total_keys": 6}}
{"timestamp": "2026-07-19 17:50:01", "status": "degraded", "last_message_age_sec": 4561, "error_rate_1h": 0, "bot_activity": {"inbound": 0, "outbound": 0, "errors": 0, "last_error": null, "last_inbound": null, "last_outbound": null}, "gateways": {"zhiwei": {"port": 8643, "alive": true}, "mohe": {"port": 8642, "alive": true}, "xiaoguo": {"port": 8645, "alive": true}}, "llm_provider": {"status": "error", "error": "timed out"}, "best_key": {"key_id": "key6", "label": "key6 (ycdennismo@163.com)", "masked": "sk-oF1WG...hCS3", "rolling": {"reset_in_sec": 1484, "status": "ok", "usage_percent": 7}, "weekly": {"reset_in_sec": 51163, "status": "ok", "usage_percent": 13}, "monthly": {"reset_in_sec": 2480859, "status": "ok", "usage_percent": 6}, "session_expired": false, "issues": [], "total_keys": 6}}
{"timestamp": "2026-07-19 17:55:02", "status": "critical", "last_message_age_sec": 4860, "error_rate_1h": 0, "bot_activity": {"inbound": 0, "outbound": 0, "errors": 0, "last_error": null, "last_inbound": null, "last_outbound": null}, "gateways": {"zhiwei": {"port": 8643, "alive": false}, "mohe": {"port": 8642, "alive": true}, "xiaoguo": {"port": 8645, "alive": true}}, "llm_provider": {}, "best_key": {"key_id": "key6", "label": "key6 (ycdennismo@163.com)", "masked": "sk-oF1WG...hCS3", "rolling": {"reset_in_sec": 1175, "status": "ok", "usage_percent": 7}, "weekly": {"reset_in_sec": 50854, "status": "ok", "usage_percent": 13}, "monthly": {"reset_in_sec": 2480550, "status": "ok", "usage_percent": 6}, "session_expired": false, "issues": [], "total_keys": 6}}
{"timestamp": "2026-07-19 18:00:01", "status": "critical", "last_message_age_sec": 5159, "error_rate_1h": 0, "bot_activity": {"inbound": 0, "outbound": 0, "errors": 0, "last_error": null, "last_inbound": null, "last_outbound": null}, "gateways": {"zhiwei": {"port": 8643, "alive": false}, "mohe": {"port": 8642, "alive": true}, "xiaoguo": {"port": 8645, "alive": true}}, "llm_provider": {}, "best_key": {"key_id": "key6", "label": "key6 (ycdennismo@163.com)", "masked": "sk-oF1WG...hCS3", "rolling": {"reset_in_sec": 866, "status": "ok", "usage_percent": 7}, "weekly": {"reset_in_sec": 50545, "status": "ok", "usage_percent": 13}, "monthly": {"reset_in_sec": 2480241, "status": "ok", "usage_percent": 6}, "session_expired": false, "issues": [], "total_keys": 6}}
{"timestamp": "2026-07-19 18:05:01", "status": "critical", "last_message_age_sec": 5460, "error_rate_1h": 0, "bot_activity": {"inbound": 0, "outbound": 0, "errors": 0, "last_error": null, "last_inbound": null, "last_outbound": null}, "gateways": {"zhiwei": {"port": 8643, "alive": false}, "mohe": {"port": 8642, "alive": true}, "xiaoguo": {"port": 8645, "alive": true}}, "llm_provider": {}, "best_key": {"key_id": "key6", "label": "key6 (ycdennismo@163.com)", "masked": "sk-oF1WG...hCS3", "rolling": {"reset_in_sec": 558, "status": "ok", "usage_percent": 7}, "weekly": {"reset_in_sec": 50237, "status": "ok", "usage_percent": 13}, "monthly": {"reset_in_sec": 2479933, "status": "ok", "usage_percent": 6}, "session_expired": false, "issues": [], "total_keys": 6}}
{"timestamp": "2026-07-19 18:10:01", "status": "degraded", "last_message_age_sec": 5759, "error_rate_1h": 0, "bot_activity": {"inbound": 0, "outbound": 0, "errors": 0, "last_error": null, "last_inbound": null, "last_outbound": null}, "gateways": {"zhiwei": {"port": 8643, "alive": true}, "mohe": {"port": 8642, "alive": true}, "xiaoguo": {"port": 8645, "alive": true}}, "llm_provider": {"status": "error", "error": "timed out"}, "best_key": {"key_id": "key6", "label": "key6 (ycdennismo@163.com)", "masked": "sk-oF1WG...hCS3", "rolling": {"reset_in_sec": 251, "status": "ok", "usage_percent": 7}, "weekly": {"reset_in_sec": 49930, "status": "ok", "usage_percent": 13}, "monthly": {"reset_in_sec": 2479626, "status": "ok", "usage_percent": 6}, "session_expired": false, "issues": [], "total_keys": 6}}
{"timestamp": "2026-07-19 18:15:01", "status": "degraded", "last_message_age_sec": 6058, "error_rate_1h": 0, "bot_activity": {"inbound": 1, "outbound": 0, "errors": 1, "last_error": "2026-07-19 18:12:21,700 ERROR call_hermes error: RemoteDisconnected: Remote end closed connection without response", "last_inbound": "2026-07-19 18:12:03,842 INFO 📩 收到: from=hmo@yoin.fun/gajim.02ZMOMIM type=chat body=> 其实我的现金和持仓都发生了变化。但是之前给你发截图,你好像并没有回应", "last_outbound": null}, "gateways": {"zhiwei": {"port": 8643, "alive": false}, "mohe": {"port": 8642, "alive": true}, "xiaoguo": {"port": 8645, "alive": true}}, "llm_provider": {}, "best_key": {"key_id": "key6", "label": "key6 (ycdennismo@163.com)", "masked": "sk-oF1WG...hCS3", "rolling": {"reset_in_sec": 18000, "status": "ok", "usage_percent": 0}, "weekly": {"reset_in_sec": 49621, "status": "ok", "usage_percent": 13}, "monthly": {"reset_in_sec": 2479317, "status": "ok", "usage_percent": 6}, "session_expired": false, "issues": [], "total_keys": 6}}
{"timestamp": "2026-07-19 18:15:32", "status": "degraded", "last_message_age_sec": 6089, "error_rate_1h": 0, "bot_activity": {"inbound": 1, "outbound": 0, "errors": 1, "last_error": "2026-07-19 18:12:21,700 ERROR call_hermes error: RemoteDisconnected: Remote end closed connection without response", "last_inbound": "2026-07-19 18:12:03,842 INFO 📩 收到: from=hmo@yoin.fun/gajim.02ZMOMIM type=chat body=> 其实我的现金和持仓都发生了变化。但是之前给你发截图,你好像并没有回应", "last_outbound": null}, "gateways": {"zhiwei": {"port": 8643, "alive": false}, "mohe": {"port": 8642, "alive": true}, "xiaoguo": {"port": 8645, "alive": true}}, "llm_provider": {}, "best_key": {"key_id": "key6", "label": "key6 (ycdennismo@163.com)", "masked": "sk-oF1WG...hCS3", "rolling": {"reset_in_sec": 18000, "status": "ok", "usage_percent": 0}, "weekly": {"reset_in_sec": 49621, "status": "ok", "usage_percent": 13}, "monthly": {"reset_in_sec": 2479317, "status": "ok", "usage_percent": 6}, "session_expired": false, "issues": [], "total_keys": 6}}
{"timestamp": "2026-07-19 18:20:01", "status": "degraded", "last_message_age_sec": 6359, "error_rate_1h": 0, "bot_activity": {"inbound": 1, "outbound": 0, "errors": 1, "last_error": "2026-07-19 18:12:21,700 ERROR call_hermes error: RemoteDisconnected: Remote end closed connection without response", "last_inbound": "2026-07-19 18:12:03,842 INFO 📩 收到: from=hmo@yoin.fun/gajim.02ZMOMIM type=chat body=> 其实我的现金和持仓都发生了变化。但是之前给你发截图,你好像并没有回应", "last_outbound": null}, "gateways": {"zhiwei": {"port": 8643, "alive": false}, "mohe": {"port": 8642, "alive": true}, "xiaoguo": {"port": 8645, "alive": true}}, "llm_provider": {}, "best_key": {"key_id": "key6", "label": "key6 (ycdennismo@163.com)", "masked": "sk-oF1WG...hCS3", "rolling": {"reset_in_sec": 17827, "status": "ok", "usage_percent": 0}, "weekly": {"reset_in_sec": 49312, "status": "ok", "usage_percent": 13}, "monthly": {"reset_in_sec": 2479008, "status": "ok", "usage_percent": 6}, "session_expired": false, "issues": [], "total_keys": 6}}
{"timestamp": "2026-07-19 18:22:09", "status": "degraded", "last_message_age_sec": 6487, "error_rate_1h": 0, "bot_activity": {"inbound": 1, "outbound": 0, "errors": 1, "last_error": "2026-07-19 18:12:21,700 ERROR call_hermes error: RemoteDisconnected: Remote end closed connection without response", "last_inbound": "2026-07-19 18:12:03,842 INFO 📩 收到: from=hmo@yoin.fun/gajim.02ZMOMIM type=chat body=> 其实我的现金和持仓都发生了变化。但是之前给你发截图,你好像并没有回应", "last_outbound": null}, "gateways": {"zhiwei": {"port": 8643, "alive": false}, "mohe": {"port": 8642, "alive": true}, "xiaoguo": {"port": 8645, "alive": true}}, "llm_provider": {}, "best_key": {"key_id": "key6", "label": "key6 (ycdennismo@163.com)", "masked": "sk-oF1WG...hCS3", "rolling": {"reset_in_sec": 17827, "status": "ok", "usage_percent": 0}, "weekly": {"reset_in_sec": 49312, "status": "ok", "usage_percent": 13}, "monthly": {"reset_in_sec": 2479008, "status": "ok", "usage_percent": 6}, "session_expired": false, "issues": [], "total_keys": 6}}
{"timestamp": "2026-07-19 18:25:01", "status": "degraded", "last_message_age_sec": 6659, "error_rate_1h": 0, "bot_activity": {"inbound": 1, "outbound": 0, "errors": 1, "last_error": "2026-07-19 18:12:21,700 ERROR call_hermes error: RemoteDisconnected: Remote end closed connection without response", "last_inbound": "2026-07-19 18:12:03,842 INFO 📩 收到: from=hmo@yoin.fun/gajim.02ZMOMIM type=chat body=> 其实我的现金和持仓都发生了变化。但是之前给你发截图,你好像并没有回应", "last_outbound": null}, "gateways": {"zhiwei": {"port": 8643, "alive": false}, "mohe": {"port": 8642, "alive": true}, "xiaoguo": {"port": 8645, "alive": true}}, "llm_provider": {}, "best_key": {"key_id": "key6", "label": "key6 (ycdennismo@163.com)", "masked": "sk-oF1WG...hCS3", "rolling": {"reset_in_sec": 17520, "status": "ok", "usage_percent": 1}, "weekly": {"reset_in_sec": 49005, "status": "ok", "usage_percent": 14}, "monthly": {"reset_in_sec": 2478701, "status": "ok", "usage_percent": 7}, "session_expired": false, "issues": [], "total_keys": 6}}
{"timestamp": "2026-07-19 18:30:02", "status": "degraded", "last_message_age_sec": 6959, "error_rate_1h": 0, "bot_activity": {"inbound": 1, "outbound": 0, "errors": 1, "last_error": "2026-07-19 18:12:21,700 ERROR call_hermes error: RemoteDisconnected: Remote end closed connection without response", "last_inbound": "2026-07-19 18:12:03,842 INFO 📩 收到: from=hmo@yoin.fun/gajim.02ZMOMIM type=chat body=> 其实我的现金和持仓都发生了变化。但是之前给你发截图,你好像并没有回应", "last_outbound": null}, "gateways": {"zhiwei": {"port": 8643, "alive": false}, "mohe": {"port": 8642, "alive": true}, "xiaoguo": {"port": 8645, "alive": true}}, "llm_provider": {}, "best_key": {"key_id": "key6", "label": "key6 (ycdennismo@163.com)", "masked": "sk-oF1WG...hCS3", "rolling": {"reset_in_sec": 17212, "status": "ok", "usage_percent": 1}, "weekly": {"reset_in_sec": 48697, "status": "ok", "usage_percent": 14}, "monthly": {"reset_in_sec": 2478393, "status": "ok", "usage_percent": 7}, "session_expired": false, "issues": [], "total_keys": 6}}
{"timestamp": "2026-07-19 18:35:02", "status": "degraded", "last_message_age_sec": 7263, "error_rate_1h": 0, "bot_activity": {"inbound": 1, "outbound": 0, "errors": 1, "last_error": "2026-07-19 18:12:21,700 ERROR call_hermes error: RemoteDisconnected: Remote end closed connection without response", "last_inbound": "2026-07-19 18:12:03,842 INFO 📩 收到: from=hmo@yoin.fun/gajim.02ZMOMIM type=chat body=> 其实我的现金和持仓都发生了变化。但是之前给你发截图,你好像并没有回应", "last_outbound": null}, "gateways": {"zhiwei": {"port": 8643, "alive": true}, "mohe": {"port": 8642, "alive": true}, "xiaoguo": {"port": 8645, "alive": true}}, "llm_provider": {"status": "error", "error": "timed out"}, "best_key": {"key_id": "key6", "label": "key6 (ycdennismo@163.com)", "masked": "sk-oF1WG...hCS3", "rolling": {"reset_in_sec": 16902, "status": "ok", "usage_percent": 3}, "weekly": {"reset_in_sec": 48387, "status": "ok", "usage_percent": 14}, "monthly": {"reset_in_sec": 2478083, "status": "ok", "usage_percent": 7}, "session_expired": false, "issues": [], "total_keys": 6}}
{"timestamp": "2026-07-19 18:40:01", "status": "degraded", "last_message_age_sec": 7562, "error_rate_1h": 0, "bot_activity": {"inbound": 1, "outbound": 0, "errors": 1, "last_error": "2026-07-19 18:12:21,700 ERROR call_hermes error: RemoteDisconnected: Remote end closed connection without response", "last_inbound": "2026-07-19 18:12:03,842 INFO 📩 收到: from=hmo@yoin.fun/gajim.02ZMOMIM type=chat body=> 其实我的现金和持仓都发生了变化。但是之前给你发截图,你好像并没有回应", "last_outbound": null}, "gateways": {"zhiwei": {"port": 8643, "alive": false}, "mohe": {"port": 8642, "alive": true}, "xiaoguo": {"port": 8645, "alive": true}}, "llm_provider": {}, "best_key": {"key_id": "key6", "label": "key6 (ycdennismo@163.com)", "masked": "sk-oF1WG...hCS3", "rolling": {"reset_in_sec": 16594, "status": "ok", "usage_percent": 3}, "weekly": {"reset_in_sec": 48079, "status": "ok", "usage_percent": 14}, "monthly": {"reset_in_sec": 2477775, "status": "ok", "usage_percent": 7}, "session_expired": false, "issues": [], "total_keys": 6}}
{"timestamp": "2026-07-19 18:45:01", "status": "critical", "last_message_age_sec": 7859, "error_rate_1h": 0, "bot_activity": {"inbound": 0, "outbound": 0, "errors": 0, "last_error": null, "last_inbound": null, "last_outbound": null}, "gateways": {"zhiwei": {"port": 8643, "alive": false}, "mohe": {"port": 8642, "alive": true}, "xiaoguo": {"port": 8645, "alive": true}}, "llm_provider": {}, "best_key": {"key_id": "key6", "label": "key6 (ycdennismo@163.com)", "masked": "sk-oF1WG...hCS3", "rolling": {"reset_in_sec": 16286, "status": "ok", "usage_percent": 3}, "weekly": {"reset_in_sec": 47771, "status": "ok", "usage_percent": 14}, "monthly": {"reset_in_sec": 2477467, "status": "ok", "usage_percent": 7}, "session_expired": false, "issues": [], "total_keys": 6}}
{"timestamp": "2026-07-19 18:50:01", "status": "degraded", "last_message_age_sec": 8159, "error_rate_1h": 0, "bot_activity": {"inbound": 0, "outbound": 0, "errors": 0, "last_error": null, "last_inbound": null, "last_outbound": null}, "gateways": {"zhiwei": {"port": 8643, "alive": true}, "mohe": {"port": 8642, "alive": true}, "xiaoguo": {"port": 8645, "alive": true}}, "llm_provider": {"status": "error", "error": "timed out"}, "best_key": {"key_id": "key6", "label": "key6 (ycdennismo@163.com)", "masked": "sk-oF1WG...hCS3", "rolling": {"reset_in_sec": 15977, "status": "ok", "usage_percent": 4}, "weekly": {"reset_in_sec": 47462, "status": "ok", "usage_percent": 15}, "monthly": {"reset_in_sec": 2477158, "status": "ok", "usage_percent": 7}, "session_expired": false, "issues": [], "total_keys": 6}}
{"timestamp": "2026-07-19 18:55:02", "status": "critical", "last_message_age_sec": 8460, "error_rate_1h": 0, "bot_activity": {"inbound": 0, "outbound": 0, "errors": 0, "last_error": null, "last_inbound": null, "last_outbound": null}, "gateways": {"zhiwei": {"port": 8643, "alive": false}, "mohe": {"port": 8642, "alive": true}, "xiaoguo": {"port": 8645, "alive": true}}, "llm_provider": {}, "best_key": {"key_id": "key6", "label": "key6 (ycdennismo@163.com)", "masked": "sk-oF1WG...hCS3", "rolling": {"reset_in_sec": 15665, "status": "ok", "usage_percent": 5}, "weekly": {"reset_in_sec": 47150, "status": "ok", "usage_percent": 15}, "monthly": {"reset_in_sec": 2476846, "status": "ok", "usage_percent": 7}, "session_expired": false, "issues": [], "total_keys": 6}}
{"timestamp": "2026-07-19 19:00:01", "status": "degraded", "last_message_age_sec": 8762, "error_rate_1h": 0, "bot_activity": {"inbound": 0, "outbound": 0, "errors": 0, "last_error": null, "last_inbound": null, "last_outbound": null}, "gateways": {"zhiwei": {"port": 8643, "alive": true}, "mohe": {"port": 8642, "alive": false}, "xiaoguo": {"port": 8645, "alive": true}}, "llm_provider": {"status": "error", "error": "[Errno 104] Connection reset by peer"}, "best_key": {"key_id": "key6", "label": "key6 (ycdennismo@163.com)", "masked": "sk-oF1WG...hCS3", "rolling": {"reset_in_sec": 15357, "status": "ok", "usage_percent": 6}, "weekly": {"reset_in_sec": 46842, "status": "ok", "usage_percent": 16}, "monthly": {"reset_in_sec": 2476538, "status": "ok", "usage_percent": 8}, "session_expired": false, "issues": [], "total_keys": 6}}
{"timestamp": "2026-07-19 19:05:02", "status": "degraded", "last_message_age_sec": 9062, "error_rate_1h": 0, "bot_activity": {"inbound": 0, "outbound": 0, "errors": 0, "last_error": null, "last_inbound": null, "last_outbound": null}, "gateways": {"zhiwei": {"port": 8643, "alive": true}, "mohe": {"port": 8642, "alive": true}, "xiaoguo": {"port": 8645, "alive": true}}, "llm_provider": {"status": "error", "error": "Remote end closed connection without response"}, "best_key": {"key_id": "key6", "label": "key6 (ycdennismo@163.com)", "masked": "sk-oF1WG...hCS3", "rolling": {"reset_in_sec": 15040, "status": "ok", "usage_percent": 7}, "weekly": {"reset_in_sec": 46525, "status": "ok", "usage_percent": 16}, "monthly": {"reset_in_sec": 2476221, "status": "ok", "usage_percent": 8}, "session_expired": false, "issues": [], "total_keys": 6}}
{"timestamp": "2026-07-19 19:10:01", "status": "critical", "last_message_age_sec": 9359, "error_rate_1h": 0, "bot_activity": {"inbound": 0, "outbound": 0, "errors": 0, "last_error": null, "last_inbound": null, "last_outbound": null}, "gateways": {"zhiwei": {"port": 8643, "alive": false}, "mohe": {"port": 8642, "alive": true}, "xiaoguo": {"port": 8645, "alive": true}}, "llm_provider": {}, "best_key": {"key_id": "key6", "label": "key6 (ycdennismo@163.com)", "masked": "sk-oF1WG...hCS3", "rolling": {"reset_in_sec": 14730, "status": "ok", "usage_percent": 8}, "weekly": {"reset_in_sec": 46215, "status": "ok", "usage_percent": 17}, "monthly": {"reset_in_sec": 2475911, "status": "ok", "usage_percent": 8}, "session_expired": false, "issues": [], "total_keys": 6}}
{"timestamp": "2026-07-19 19:15:01", "status": "degraded", "last_message_age_sec": 9659, "error_rate_1h": 0, "bot_activity": {"inbound": 0, "outbound": 0, "errors": 0, "last_error": null, "last_inbound": null, "last_outbound": null}, "gateways": {"zhiwei": {"port": 8643, "alive": true}, "mohe": {"port": 8642, "alive": true}, "xiaoguo": {"port": 8645, "alive": true}}, "llm_provider": {"status": "error", "error": "timed out"}, "best_key": {"key_id": "key6", "label": "key6 (ycdennismo@163.com)", "masked": "sk-oF1WG...hCS3", "rolling": {"reset_in_sec": 14419, "status": "ok", "usage_percent": 10}, "weekly": {"reset_in_sec": 45904, "status": "ok", "usage_percent": 17}, "monthly": {"reset_in_sec": 2475600, "status": "ok", "usage_percent": 8}, "session_expired": false, "issues": [], "total_keys": 6}}
{"timestamp": "2026-07-19 19:20:02", "status": "degraded", "last_message_age_sec": 9960, "error_rate_1h": 0, "bot_activity": {"inbound": 0, "outbound": 0, "errors": 0, "last_error": null, "last_inbound": null, "last_outbound": null}, "gateways": {"zhiwei": {"port": 8643, "alive": true}, "mohe": {"port": 8642, "alive": true}, "xiaoguo": {"port": 8645, "alive": true}}, "llm_provider": {"status": "error", "error": "timed out"}, "best_key": {"key_id": "key6", "label": "key6 (ycdennismo@163.com)", "masked": "sk-oF1WG...hCS3", "rolling": {"reset_in_sec": 14103, "status": "ok", "usage_percent": 10}, "weekly": {"reset_in_sec": 45588, "status": "ok", "usage_percent": 17}, "monthly": {"reset_in_sec": 2475284, "status": "ok", "usage_percent": 8}, "session_expired": false, "issues": [], "total_keys": 6}}
{"timestamp": "2026-07-19 19:25:01", "status": "degraded", "last_message_age_sec": 10259, "error_rate_1h": 0, "bot_activity": {"inbound": 0, "outbound": 0, "errors": 0, "last_error": null, "last_inbound": null, "last_outbound": null}, "gateways": {"zhiwei": {"port": 8643, "alive": true}, "mohe": {"port": 8642, "alive": true}, "xiaoguo": {"port": 8645, "alive": true}}, "llm_provider": {"status": "error", "error": "timed out"}, "best_key": {"key_id": "key6", "label": "key6 (ycdennismo@163.com)", "masked": "sk-oF1WG...hCS3", "rolling": {"reset_in_sec": 14103, "status": "ok", "usage_percent": 10}, "weekly": {"reset_in_sec": 45588, "status": "ok", "usage_percent": 17}, "monthly": {"reset_in_sec": 2475284, "status": "ok", "usage_percent": 8}, "session_expired": false, "issues": [], "total_keys": 6}}
{"timestamp": "2026-07-19 19:30:01", "status": "critical", "last_message_age_sec": 10560, "error_rate_1h": 0, "bot_activity": {"inbound": 0, "outbound": 0, "errors": 0, "last_error": null, "last_inbound": null, "last_outbound": null}, "gateways": {"zhiwei": {"port": 8643, "alive": false}, "mohe": {"port": 8642, "alive": true}, "xiaoguo": {"port": 8645, "alive": true}}, "llm_provider": {}, "best_key": {"key_id": "key6", "label": "key6 (ycdennismo@163.com)", "masked": "sk-oF1WG...hCS3", "rolling": {"reset_in_sec": 13794, "status": "ok", "usage_percent": 18}, "weekly": {"reset_in_sec": 45279, "status": "ok", "usage_percent": 20}, "monthly": {"reset_in_sec": 2474975, "status": "ok", "usage_percent": 10}, "session_expired": false, "issues": [], "total_keys": 6}}
{"timestamp": "2026-07-19 19:35:01", "status": "degraded", "last_message_age_sec": 10859, "error_rate_1h": 0, "bot_activity": {"inbound": 0, "outbound": 0, "errors": 0, "last_error": null, "last_inbound": null, "last_outbound": null}, "gateways": {"zhiwei": {"port": 8643, "alive": true}, "mohe": {"port": 8642, "alive": true}, "xiaoguo": {"port": 8645, "alive": true}}, "llm_provider": {"status": "error", "error": "timed out"}, "best_key": {"key_id": "key6", "label": "key6 (ycdennismo@163.com)", "masked": "sk-oF1WG...hCS3", "rolling": {"reset_in_sec": 13487, "status": "ok", "usage_percent": 22}, "weekly": {"reset_in_sec": 44972, "status": "ok", "usage_percent": 22}, "monthly": {"reset_in_sec": 2474668, "status": "ok", "usage_percent": 11}, "session_expired": false, "issues": [], "total_keys": 7}}
{"timestamp": "2026-07-19 19:40:01", "status": "degraded", "last_message_age_sec": 11159, "error_rate_1h": 0, "bot_activity": {"inbound": 0, "outbound": 0, "errors": 0, "last_error": null, "last_inbound": null, "last_outbound": null}, "gateways": {"zhiwei": {"port": 8643, "alive": true}, "mohe": {"port": 8642, "alive": true}, "xiaoguo": {"port": 8645, "alive": true}}, "llm_provider": {"status": "error", "error": "timed out"}, "best_key": {"key_id": "key6", "label": "key6 (ycdennismo@163.com)", "masked": "sk-oF1WG...hCS3", "rolling": {"reset_in_sec": 13178, "status": "ok", "usage_percent": 26}, "weekly": {"reset_in_sec": 44663, "status": "ok", "usage_percent": 24}, "monthly": {"reset_in_sec": 2474359, "status": "ok", "usage_percent": 12}, "session_expired": false, "issues": [], "total_keys": 7}}
{"timestamp": "2026-07-19 19:45:02", "status": "degraded", "last_message_age_sec": 11459, "error_rate_1h": 0, "bot_activity": {"inbound": 0, "outbound": 0, "errors": 0, "last_error": null, "last_inbound": null, "last_outbound": null}, "gateways": {"zhiwei": {"port": 8643, "alive": true}, "mohe": {"port": 8642, "alive": true}, "xiaoguo": {"port": 8645, "alive": true}}, "llm_provider": {"status": "error", "error": "timed out"}, "best_key": {"key_id": "key6", "label": "key6 (ycdennismo@163.com)", "masked": "sk-oF1WG...hCS3", "rolling": {"reset_in_sec": 12872, "status": "ok", "usage_percent": 32}, "weekly": {"reset_in_sec": 44357, "status": "ok", "usage_percent": 26}, "monthly": {"reset_in_sec": 2474053, "status": "ok", "usage_percent": 13}, "session_expired": false, "issues": [], "total_keys": 7}}
{"timestamp": "2026-07-19 19:50:01", "status": "critical", "last_message_age_sec": 11759, "error_rate_1h": 0, "bot_activity": {"inbound": 0, "outbound": 0, "errors": 0, "last_error": null, "last_inbound": null, "last_outbound": null}, "gateways": {"zhiwei": {"port": 8643, "alive": true}, "mohe": {"port": 8642, "alive": true}, "xiaoguo": {"port": 8645, "alive": true}}, "llm_provider": {"status": "ok", "latency": "fast"}, "best_key": {"key_id": "key6", "label": "key6 (ycdennismo@163.com)", "masked": "sk-oF1WG...hCS3", "rolling": {"reset_in_sec": 12401, "status": "ok", "usage_percent": 38}, "weekly": {"reset_in_sec": 43886, "status": "ok", "usage_percent": 28}, "monthly": {"reset_in_sec": 2473582, "status": "ok", "usage_percent": 14}, "session_expired": false, "issues": [], "total_keys": 7}}
{"timestamp": "2026-07-19 20:00:01", "status": "critical", "last_message_age_sec": 12359, "error_rate_1h": 0, "bot_activity": {"inbound": 0, "outbound": 0, "errors": 0, "last_error": null, "last_inbound": null, "last_outbound": null}, "gateways": {"zhiwei": {"port": 8643, "alive": true}, "mohe": {"port": 8642, "alive": true}, "xiaoguo": {"port": 8645, "alive": true}}, "llm_provider": {"status": "ok", "latency": "fast"}, "best_key": {"key_id": "key6", "label": "key6 (ycdennismo@163.com)", "masked": "sk-oF1WG...hCS3", "rolling": {"reset_in_sec": 11775, "status": "ok", "usage_percent": 49}, "weekly": {"reset_in_sec": 43260, "status": "ok", "usage_percent": 33}, "monthly": {"reset_in_sec": 2472956, "status": "ok", "usage_percent": 16}, "session_expired": false, "issues": [], "total_keys": 7}}
{"timestamp": "2026-07-19 20:05:01", "status": "critical", "last_message_age_sec": 12659, "error_rate_1h": 0, "bot_activity": {"inbound": 0, "outbound": 0, "errors": 0, "last_error": null, "last_inbound": null, "last_outbound": null}, "gateways": {"zhiwei": {"port": 8643, "alive": true}, "mohe": {"port": 8642, "alive": true}, "xiaoguo": {"port": 8645, "alive": true}}, "llm_provider": {"status": "ok", "latency": "fast"}, "best_key": {"key_id": "key6", "label": "key6 (ycdennismo@163.com)", "masked": "sk-oF1WG...hCS3", "rolling": {"reset_in_sec": 11464, "status": "ok", "usage_percent": 60}, "weekly": {"reset_in_sec": 42949, "status": "ok", "usage_percent": 37}, "monthly": {"reset_in_sec": 2472645, "status": "ok", "usage_percent": 18}, "session_expired": false, "issues": [], "total_keys": 7}}
{"timestamp": "2026-07-19 20:10:02", "status": "critical", "last_message_age_sec": 12960, "error_rate_1h": 0, "bot_activity": {"inbound": 0, "outbound": 0, "errors": 0, "last_error": null, "last_inbound": null, "last_outbound": null}, "gateways": {"zhiwei": {"port": 8643, "alive": true}, "mohe": {"port": 8642, "alive": true}, "xiaoguo": {"port": 8645, "alive": true}}, "llm_provider": {"status": "ok", "latency": "fast"}, "best_key": {"key_id": "key6", "label": "key6 (ycdennismo@163.com)", "masked": "sk-oF1WG...hCS3", "rolling": {"reset_in_sec": 11153, "status": "ok", "usage_percent": 70}, "weekly": {"reset_in_sec": 42638, "status": "ok", "usage_percent": 41}, "monthly": {"reset_in_sec": 2472334, "status": "ok", "usage_percent": 20}, "session_expired": false, "issues": [], "total_keys": 7}}
{"timestamp": "2026-07-19 20:15:01", "status": "critical", "last_message_age_sec": 13259, "error_rate_1h": 0, "bot_activity": {"inbound": 0, "outbound": 0, "errors": 0, "last_error": null, "last_inbound": null, "last_outbound": null}, "gateways": {"zhiwei": {"port": 8643, "alive": true}, "mohe": {"port": 8642, "alive": true}, "xiaoguo": {"port": 8645, "alive": true}}, "llm_provider": {"status": "ok", "latency": "fast"}, "best_key": {"key_id": "key6", "label": "key6 (ycdennismo@163.com)", "masked": "sk-oF1WG...hCS3", "rolling": {"reset_in_sec": 10842, "status": "ok", "usage_percent": 77}, "weekly": {"reset_in_sec": 42327, "status": "ok", "usage_percent": 44}, "monthly": {"reset_in_sec": 2472023, "status": "ok", "usage_percent": 22}, "session_expired": false, "issues": [], "total_keys": 7}}
{"timestamp": "2026-07-19 20:20:02", "status": "critical", "last_message_age_sec": 13559, "error_rate_1h": 0, "bot_activity": {"inbound": 0, "outbound": 0, "errors": 0, "last_error": null, "last_inbound": null, "last_outbound": null}, "gateways": {"zhiwei": {"port": 8643, "alive": true}, "mohe": {"port": 8642, "alive": true}, "xiaoguo": {"port": 8645, "alive": true}}, "llm_provider": {"status": "ok", "latency": "fast"}, "best_key": {"key_id": "key6", "label": "key6 (ycdennismo@163.com)", "masked": "sk-oF1WG...hCS3", "rolling": {"reset_in_sec": 10532, "status": "ok", "usage_percent": 77}, "weekly": {"reset_in_sec": 42017, "status": "ok", "usage_percent": 44}, "monthly": {"reset_in_sec": 2471713, "status": "ok", "usage_percent": 22}, "session_expired": false, "issues": [], "total_keys": 7}}
{"timestamp": "2026-07-19 20:25:01", "status": "critical", "last_message_age_sec": 13859, "error_rate_1h": 0, "bot_activity": {"inbound": 0, "outbound": 0, "errors": 0, "last_error": null, "last_inbound": null, "last_outbound": null}, "gateways": {"zhiwei": {"port": 8643, "alive": true}, "mohe": {"port": 8642, "alive": true}, "xiaoguo": {"port": 8645, "alive": true}}, "llm_provider": {"status": "ok", "latency": "fast"}, "best_key": {"key_id": "key6", "label": "key6 (ycdennismo@163.com)", "masked": "sk-oF1WG...hCS3", "rolling": {"reset_in_sec": 10301, "status": "ok", "usage_percent": 78}, "weekly": {"reset_in_sec": 41786, "status": "ok", "usage_percent": 44}, "monthly": {"reset_in_sec": 2471482, "status": "ok", "usage_percent": 22}, "session_expired": false, "issues": [], "total_keys": 7}}
{"timestamp": "2026-07-19 20:30:01", "status": "critical", "last_message_age_sec": 14159, "error_rate_1h": 0, "bot_activity": {"inbound": 0, "outbound": 0, "errors": 0, "last_error": null, "last_inbound": null, "last_outbound": null}, "gateways": {"zhiwei": {"port": 8643, "alive": true}, "mohe": {"port": 8642, "alive": true}, "xiaoguo": {"port": 8645, "alive": true}}, "llm_provider": {"status": "ok", "latency": "fast"}, "best_key": {"key_id": "key6", "label": "key6 (ycdennismo@163.com)", "masked": "sk-oF1WG...hCS3", "rolling": {"reset_in_sec": 9991, "status": "ok", "usage_percent": 78}, "weekly": {"reset_in_sec": 41476, "status": "ok", "usage_percent": 44}, "monthly": {"reset_in_sec": 2471172, "status": "ok", "usage_percent": 22}, "session_expired": false, "issues": [], "total_keys": 7}}
{"timestamp": "2026-07-19 20:35:01", "status": "critical", "last_message_age_sec": 14459, "error_rate_1h": 0, "bot_activity": {"inbound": 0, "outbound": 0, "errors": 0, "last_error": null, "last_inbound": null, "last_outbound": null}, "gateways": {"zhiwei": {"port": 8643, "alive": true}, "mohe": {"port": 8642, "alive": true}, "xiaoguo": {"port": 8645, "alive": true}}, "llm_provider": {"status": "ok", "latency": "fast"}, "best_key": {"key_id": "key6", "label": "key6 (ycdennismo@163.com)", "masked": "sk-oF1WG...hCS3", "rolling": {"reset_in_sec": 9681, "status": "ok", "usage_percent": 78}, "weekly": {"reset_in_sec": 41166, "status": "ok", "usage_percent": 45}, "monthly": {"reset_in_sec": 2470862, "status": "ok", "usage_percent": 22}, "session_expired": false, "issues": [], "total_keys": 7}}
{"timestamp": "2026-07-19 20:40:01", "status": "critical", "last_message_age_sec": 14762, "error_rate_1h": 0, "bot_activity": {"inbound": 0, "outbound": 0, "errors": 0, "last_error": null, "last_inbound": null, "last_outbound": null}, "gateways": {"zhiwei": {"port": 8643, "alive": true}, "mohe": {"port": 8642, "alive": true}, "xiaoguo": {"port": 8645, "alive": true}}, "llm_provider": {"status": "ok", "latency": "fast"}, "best_key": {"key_id": "key6", "label": "key6 (ycdennismo@163.com)", "masked": "sk-oF1WG...hCS3", "rolling": {"reset_in_sec": 9362, "status": "ok", "usage_percent": 79}, "weekly": {"reset_in_sec": 40847, "status": "ok", "usage_percent": 45}, "monthly": {"reset_in_sec": 2470543, "status": "ok", "usage_percent": 22}, "session_expired": false, "issues": [], "total_keys": 7}}
{"timestamp": "2026-07-19 20:45:02", "status": "critical", "last_message_age_sec": 15059, "error_rate_1h": 0, "bot_activity": {"inbound": 0, "outbound": 0, "errors": 0, "last_error": null, "last_inbound": null, "last_outbound": null}, "gateways": {"zhiwei": {"port": 8643, "alive": true}, "mohe": {"port": 8642, "alive": true}, "xiaoguo": {"port": 8645, "alive": true}}, "llm_provider": {"status": "ok", "latency": "fast"}, "best_key": {"key_id": "key6", "label": "key6 (ycdennismo@163.com)", "masked": "sk-oF1WG...hCS3", "rolling": {"reset_in_sec": 9047, "status": "ok", "usage_percent": 79}, "weekly": {"reset_in_sec": 40532, "status": "ok", "usage_percent": 45}, "monthly": {"reset_in_sec": 2470228, "status": "ok", "usage_percent": 22}, "session_expired": false, "issues": [], "total_keys": 7}}
{"timestamp": "2026-07-19 20:50:01", "status": "critical", "last_message_age_sec": 15363, "error_rate_1h": 0, "bot_activity": {"error": "journalctl failed"}, "gateways": {"zhiwei": {"port": 8643, "alive": true}, "mohe": {"port": 8642, "alive": true}, "xiaoguo": {"port": 8645, "alive": true}}, "llm_provider": {"status": "ok", "latency": "fast"}, "best_key": {"key_id": "key6", "label": "key6 (ycdennismo@163.com)", "masked": "sk-oF1WG...hCS3", "rolling": {"reset_in_sec": 8732, "status": "ok", "usage_percent": 79}, "weekly": {"reset_in_sec": 40217, "status": "ok", "usage_percent": 45}, "monthly": {"reset_in_sec": 2469913, "status": "ok", "usage_percent": 22}, "session_expired": false, "issues": [], "total_keys": 7}}
{"timestamp": "2026-07-19 20:55:01", "status": "critical", "last_message_age_sec": 15661, "error_rate_1h": 0, "bot_activity": {"inbound": 0, "outbound": 0, "errors": 0, "last_error": null, "last_inbound": null, "last_outbound": null}, "gateways": {"zhiwei": {"port": 8643, "alive": true}, "mohe": {"port": 8642, "alive": true}, "xiaoguo": {"port": 8645, "alive": true}}, "llm_provider": {"status": "ok", "latency": "fast"}, "best_key": {"key_id": "key6", "label": "key6 (ycdennismo@163.com)", "masked": "sk-oF1WG...hCS3", "rolling": {"reset_in_sec": 8423, "status": "ok", "usage_percent": 79}, "weekly": {"reset_in_sec": 39908, "status": "ok", "usage_percent": 45}, "monthly": {"reset_in_sec": 2469604, "status": "ok", "usage_percent": 22}, "session_expired": false, "issues": [], "total_keys": 7}}
{"timestamp": "2026-07-19 21:00:01", "status": "critical", "last_message_age_sec": 15958, "error_rate_1h": 0, "bot_activity": {"inbound": 0, "outbound": 0, "errors": 0, "last_error": null, "last_inbound": null, "last_outbound": null}, "gateways": {"zhiwei": {"port": 8643, "alive": true}, "mohe": {"port": 8642, "alive": true}, "xiaoguo": {"port": 8645, "alive": true}}, "llm_provider": {"status": "ok", "latency": "fast"}, "best_key": {"key_id": "key6", "label": "key6 (ycdennismo@163.com)", "masked": "sk-oF1WG...hCS3", "rolling": {"reset_in_sec": 8114, "status": "ok", "usage_percent": 79}, "weekly": {"reset_in_sec": 39599, "status": "ok", "usage_percent": 45}, "monthly": {"reset_in_sec": 2469295, "status": "ok", "usage_percent": 22}, "session_expired": false, "issues": [], "total_keys": 7}}
+3
View File
@@ -0,0 +1,3 @@
{"timestamp": "2026-07-19 16:30:03", "direction": "out", "from": "zhiwei@yoin.fun", "to": "hmo@yoin.fun", "body_preview": "【每日汇总】今日以下cron报告未送达(已拦截): • 脚本输出 99次 无操作信号的报告正常静默,有操作信号的都已送达。", "status": "ok", "error": null, "latency_ms": 1436, "epoch": 1784449803.6249352}
{"timestamp": "2026-07-19 16:32:02", "direction": "out", "from": "zhiwei@yoin.fun", "to": "hmo@yoin.fun", "body_preview": "【每日汇总】今日以下cron报告未送达(已拦截): • 脚本输出 99次 无操作信号的报告正常静默,有操作信号的都已送达。", "status": "ok", "error": null, "latency_ms": 401, "epoch": 1784449922.3636103}
{"timestamp": "2026-07-19 16:34:02", "direction": "out", "from": "zhiwei@yoin.fun", "to": "hmo@yoin.fun", "body_preview": "【每日汇总】今日以下cron报告未送达(已拦截): • 脚本输出 99次 无操作信号的报告正常静默,有操作信号的都已送达。", "status": "ok", "error": null, "latency_ms": 430, "epoch": 1784450042.5418942}
+43
View File
@@ -0,0 +1,43 @@
{"service": "zhiwei_gateway", "label": "知微 Gateway", "reason": "<urlopen error [Errno 111] Connection refused>", "timestamp": "2026-07-19T14:30:01.660636"}
{"service": "zhiwei_gateway", "label": "知微 Gateway", "reason": "<urlopen error [Errno 111] Connection refused>", "timestamp": "2026-07-19T14:45:01.509824"}
{"service": "zhiwei_gateway", "label": "知微 Gateway", "reason": "<urlopen error [Errno 111] Connection refused>", "timestamp": "2026-07-19T14:50:01.299686"}
{"service": "zhiwei_gateway", "label": "知微 Gateway", "reason": "<urlopen error [Errno 111] Connection refused>", "timestamp": "2026-07-19T15:10:01.664172"}
{"service": "zhiwei_gateway", "label": "知微 Gateway", "reason": "<urlopen error [Errno 111] Connection refused>", "timestamp": "2026-07-19T15:16:56.095701"}
{"service": "zhiwei_gateway", "label": "知微 Gateway", "reason": "<urlopen error [Errno 111] Connection refused>", "timestamp": "2026-07-19T15:20:01.499188"}
{"service": "zhiwei_gateway", "label": "知微 Gateway", "reason": "timed out", "timestamp": "2026-07-19T15:35:01.728475"}
{"service": "zhiwei_gateway", "label": "知微 Gateway", "reason": "<urlopen error [Errno 111] Connection refused>", "timestamp": "2026-07-19T15:40:01.641145"}
{"service": "zhiwei_gateway", "label": "知微 Gateway", "reason": "<urlopen error [Errno 111] Connection refused>", "timestamp": "2026-07-19T15:45:01.566000"}
{"service": "zhiwei_gateway", "label": "知微 Gateway", "reason": "<urlopen error [Errno 111] Connection refused>", "timestamp": "2026-07-19T15:50:01.481496"}
{"service": "zhiwei_gateway", "label": "知微 Gateway", "reason": "<urlopen error [Errno 111] Connection refused>", "timestamp": "2026-07-19T16:00:01.977074"}
{"service": "zhiwei_gateway", "label": "知微 Gateway", "reason": "<urlopen error [Errno 111] Connection refused>", "timestamp": "2026-07-19T16:05:01.820740"}
{"service": "zhiwei_gateway", "label": "知微 Gateway", "reason": "<urlopen error [Errno 111] Connection refused>", "timestamp": "2026-07-19T16:20:01.556094"}
{"service": "zhiwei_gateway", "label": "知微 Gateway", "reason": "<urlopen error [Errno 111] Connection refused>", "timestamp": "2026-07-19T16:30:01.714587"}
{"service": "zhiwei_gateway", "label": "知微 Gateway", "reason": "<urlopen error [Errno 111] Connection refused>", "timestamp": "2026-07-19T16:35:01.890435"}
{"service": "zhiwei_gateway", "label": "知微 Gateway", "reason": "<urlopen error [Errno 111] Connection refused>", "timestamp": "2026-07-19T16:40:02.012734"}
{"service": "zhiwei_gateway", "label": "知微 Gateway", "reason": "<urlopen error [Errno 111] Connection refused>", "timestamp": "2026-07-19T16:55:01.801842"}
{"service": "zhiwei_gateway", "label": "知微 Gateway", "reason": "<urlopen error [Errno 111] Connection refused>", "timestamp": "2026-07-19T17:00:01.449735"}
{"service": "zhiwei_gateway", "label": "知微 Gateway", "reason": "<urlopen error [Errno 111] Connection refused>", "timestamp": "2026-07-19T17:05:01.397273"}
{"service": "zhiwei_gateway", "label": "知微 Gateway", "reason": "<urlopen error [Errno 111] Connection refused>", "timestamp": "2026-07-19T17:10:02.184096"}
{"service": "zhiwei_gateway", "label": "知微 Gateway", "reason": "<urlopen error [Errno 111] Connection refused>", "timestamp": "2026-07-19T17:15:01.441236"}
{"service": "zhiwei_gateway", "label": "知微 Gateway", "reason": "<urlopen error [Errno 111] Connection refused>", "timestamp": "2026-07-19T17:20:01.917698"}
{"service": "zhiwei_gateway", "label": "知微 Gateway", "reason": "<urlopen error [Errno 111] Connection refused>", "timestamp": "2026-07-19T17:25:01.507624"}
{"service": "zhiwei_gateway", "label": "知微 Gateway", "reason": "<urlopen error [Errno 111] Connection refused>", "timestamp": "2026-07-19T17:45:01.480343"}
{"service": "zhiwei_gateway", "label": "知微 Gateway", "reason": "<urlopen error [Errno 111] Connection refused>", "timestamp": "2026-07-19T17:55:02.087320"}
{"service": "zhiwei_gateway", "label": "知微 Gateway", "reason": "<urlopen error [Errno 111] Connection refused>", "timestamp": "2026-07-19T18:00:01.432964"}
{"service": "zhiwei_gateway", "label": "知微 Gateway", "reason": "<urlopen error [Errno 111] Connection refused>", "timestamp": "2026-07-19T18:05:01.877289"}
{"service": "zhiwei_gateway", "label": "知微 Gateway", "reason": "<urlopen error [Errno 111] Connection refused>", "timestamp": "2026-07-19T18:15:01.180290"}
{"service": "zhiwei_gateway", "label": "知微 Gateway", "reason": "<urlopen error [Errno 111] Connection refused>", "timestamp": "2026-07-19T18:15:32.047339"}
{"service": "zhiwei_gateway", "label": "知微 Gateway", "reason": "<urlopen error [Errno 111] Connection refused>", "timestamp": "2026-07-19T18:20:01.729488"}
{"service": "zhiwei_gateway", "label": "知微 Gateway", "reason": "<urlopen error [Errno 111] Connection refused>", "timestamp": "2026-07-19T18:22:09.444652"}
{"service": "zhiwei_gateway", "label": "知微 Gateway", "reason": "<urlopen error [Errno 111] Connection refused>", "timestamp": "2026-07-19T18:25:01.641678"}
{"service": "zhiwei_gateway", "label": "知微 Gateway", "reason": "<urlopen error [Errno 111] Connection refused>", "timestamp": "2026-07-19T18:30:02.180070"}
{"service": "zhiwei_gateway", "label": "知微 Gateway", "reason": "timed out", "timestamp": "2026-07-19T18:35:02.017521"}
{"service": "zhiwei_gateway", "label": "知微 Gateway", "reason": "timed out", "timestamp": "2026-07-19T18:40:01.770567"}
{"service": "zhiwei_gateway", "label": "知微 Gateway", "reason": "<urlopen error [Errno 111] Connection refused>", "timestamp": "2026-07-19T18:45:01.936046"}
{"service": "zhiwei_gateway", "label": "知微 Gateway", "reason": "<urlopen error [Errno 111] Connection refused>", "timestamp": "2026-07-19T18:50:01.336498"}
{"service": "zhiwei_gateway", "label": "知微 Gateway", "reason": "<urlopen error [Errno 111] Connection refused>", "timestamp": "2026-07-19T18:55:02.111939"}
{"service": "zhiwei_gateway", "label": "知微 Gateway", "reason": "timed out", "timestamp": "2026-07-19T19:00:01.584617"}
{"service": "zhiwei_gateway", "label": "知微 Gateway", "reason": "timed out", "timestamp": "2026-07-19T19:05:02.034721"}
{"service": "zhiwei_gateway", "label": "知微 Gateway", "reason": "<urlopen error [Errno 111] Connection refused>", "timestamp": "2026-07-19T19:10:01.565114"}
{"service": "zhiwei_gateway", "label": "知微 Gateway", "reason": "<urlopen error [Errno 111] Connection refused>", "timestamp": "2026-07-19T19:30:01.210250"}
{"service": "zhiwei_gateway", "label": "知微 Gateway", "reason": "timed out", "timestamp": "2026-07-19T20:40:01.598513"}
+49
View File
@@ -0,0 +1,49 @@
{
"services": [
{
"name": "mofin_api",
"label": "MoFin API",
"type": "http",
"port": 8899,
"health": {
"ok": true
},
"detail": "HTTP 200"
},
{
"name": "zhiwei_gateway",
"label": "知微 Gateway",
"type": "http",
"port": 8643,
"health": {
"ok": true
},
"detail": "HTTP 200"
},
{
"name": "ejabberd",
"label": "ejabberd XMPP",
"type": "tcp",
"port": 5222,
"health": {
"ok": true
},
"detail": "ok"
},
{
"name": "mofin_db",
"label": "MoFin 数据库",
"type": "db",
"port": 0,
"health": {
"ok": true
},
"detail": "ok"
}
],
"summary": {
"ok": 4,
"total": 4
},
"generated_at": "2026-07-19 21:00:01"
}
+1695
View File
File diff suppressed because it is too large Load Diff
+19 -19
View File
@@ -1,19 +1,19 @@
═══════════════════════════════════════
知微 收盘简报 | {GENERATED_AT}
═══════════════════════════════════════
【数据面板 — 代码采集,LLM不得修改】
现金 {CASH_AMOUNT} CNY | 冻结 {portfolio.frozen_cash} CNY
持仓市值 {STOCK_VALUE} CNY | 总资产 {TOTAL_ASSETS} CNY
仓位 {POSITION_PCT}% | 持仓 {HOLDINGS_COUNT} 只
现金来源: {CASH_SOURCE}
持仓明细:
{HOLDINGS_TABLE}
⚠️ 浮亏>20%:
{HOLDINGS_RISK}
═══════════════════════════════════════
═══════════════════════════════════════
知微 收盘简报 | {GENERATED_AT}
═══════════════════════════════════════
【数据面板 — 代码采集,LLM不得修改】
现金 {CASH_AMOUNT} CNY | 冻结 {portfolio.frozen_cash} CNY
持仓市值 {STOCK_VALUE} CNY | 总资产 {TOTAL_ASSETS} CNY
仓位 {POSITION_PCT}% | 持仓 {HOLDINGS_COUNT} 只
现金来源: {CASH_SOURCE}
持仓明细:
{HOLDINGS_TABLE}
⚠️ 浮亏>20%:
{HOLDINGS_RISK}
═══════════════════════════════════════
+22 -22
View File
@@ -1,22 +1,22 @@
═══════════════════════════════════════
MoFin 盘中监控 | {GENERATED_AT}
═══════════════════════════════════════
【数据面板 — 代码采集,LLM不得修改】
大盘: 上证 {market.sh_index} ({market.sh_change:+.2f}%) | 深证 {market.sz_index} ({market.sz_change:+.2f}%)
涨跌比 {market.advance_decline_ratio} | 情绪 {market.mood}
现金 {CASH_AMOUNT} CNY | 冻结 {portfolio.frozen_cash} CNY
持仓市值 {STOCK_VALUE} CNY | 总资产 {TOTAL_ASSETS} CNY
仓位 {POSITION_PCT}% | 持仓 {HOLDINGS_COUNT} 只 | 港币汇率 {HK_RATE}
现金来源: {CASH_SOURCE}
持仓明细:
{HOLDINGS_TABLE}
⚠️ 浮亏>20%:
{HOLDINGS_RISK}
═══════════════════════════════════════
═══════════════════════════════════════
MoFin 盘中监控 | {GENERATED_AT}
═══════════════════════════════════════
【数据面板 — 代码采集,LLM不得修改】
大盘: 上证 {market.sh_index} ({market.sh_change:+.2f}%) | 深证 {market.sz_index} ({market.sz_change:+.2f}%)
涨跌比 {market.advance_decline_ratio} | 情绪 {market.mood}
现金 {CASH_AMOUNT} CNY | 冻结 {portfolio.frozen_cash} CNY
持仓市值 {STOCK_VALUE} CNY | 总资产 {TOTAL_ASSETS} CNY
仓位 {POSITION_PCT}% | 持仓 {HOLDINGS_COUNT} 只 | 港币汇率 {HK_RATE}
现金来源: {CASH_SOURCE}
持仓明细:
{HOLDINGS_TABLE}
⚠️ 浮亏>20%:
{HOLDINGS_RISK}
═══════════════════════════════════════
+19 -19
View File
@@ -1,19 +1,19 @@
═══════════════════════════════════════
知微 开盘简报 | {GENERATED_AT}
═══════════════════════════════════════
【数据面板 — 代码采集,LLM不得修改】
现金 {CASH_AMOUNT} CNY | 冻结 {portfolio.frozen_cash} CNY
持仓市值 {STOCK_VALUE} CNY | 总资产 {TOTAL_ASSETS} CNY
仓位 {POSITION_PCT}% | 持仓 {HOLDINGS_COUNT} 只
现金来源: {CASH_SOURCE}
持仓明细:
{HOLDINGS_TABLE}
⚠️ 浮亏>20%:
{HOLDINGS_RISK}
═══════════════════════════════════════
═══════════════════════════════════════
知微 开盘简报 | {GENERATED_AT}
═══════════════════════════════════════
【数据面板 — 代码采集,LLM不得修改】
现金 {CASH_AMOUNT} CNY | 冻结 {portfolio.frozen_cash} CNY
持仓市值 {STOCK_VALUE} CNY | 总资产 {TOTAL_ASSETS} CNY
仓位 {POSITION_PCT}% | 持仓 {HOLDINGS_COUNT} 只
现金来源: {CASH_SOURCE}
持仓明细:
{HOLDINGS_TABLE}
⚠️ 浮亏>20%:
{HOLDINGS_RISK}
═══════════════════════════════════════
+15 -15
View File
@@ -1,15 +1,15 @@
═══════════════════════════════════════
自选买入提醒 | {GENERATED_AT}
═══════════════════════════════════════
【数据面板 — 代码采集,LLM不得修改】
总资产 {TOTAL_ASSETS} CNY | 现金 {CASH_AMOUNT} CNY | 冻结 {portfolio.frozen_cash} CNY
仓位 {POSITION_PCT}% | 港币汇率 {HK_RATE}
现金来源: {CASH_SOURCE}
持仓明细(已有持仓,不计入现金占用):
{HOLDINGS_TABLE}
═══════════════════════════════════════
═══════════════════════════════════════
自选买入提醒 | {GENERATED_AT}
═══════════════════════════════════════
【数据面板 — 代码采集,LLM不得修改】
总资产 {TOTAL_ASSETS} CNY | 现金 {CASH_AMOUNT} CNY | 冻结 {portfolio.frozen_cash} CNY
仓位 {POSITION_PCT}% | 港币汇率 {HK_RATE}
现金来源: {CASH_SOURCE}
持仓明细(已有持仓,不计入现金占用):
{HOLDINGS_TABLE}
═══════════════════════════════════════
+19 -19
View File
@@ -1,19 +1,19 @@
═══════════════════════════════════════
MoFin 策略评估 | {GENERATED_AT}
═══════════════════════════════════════
【数据面板 — 代码采集,LLM不得修改】
组合概况:
总资产 {TOTAL_ASSETS} CNY | 现金 {CASH_AMOUNT} CNY | 仓位 {POSITION_PCT}%
持仓 {HOLDINGS_COUNT} 只 | 港币汇率 {HK_RATE}
持仓明细:
{HOLDINGS_TABLE}
⚠️ 浮亏>20%:
{HOLDINGS_RISK}
现金来源: {CASH_SOURCE}
═══════════════════════════════════════
═══════════════════════════════════════
MoFin 策略评估 | {GENERATED_AT}
═══════════════════════════════════════
【数据面板 — 代码采集,LLM不得修改】
组合概况:
总资产 {TOTAL_ASSETS} CNY | 现金 {CASH_AMOUNT} CNY | 仓位 {POSITION_PCT}%
持仓 {HOLDINGS_COUNT} 只 | 港币汇率 {HK_RATE}
持仓明细:
{HOLDINGS_TABLE}
⚠️ 浮亏>20%:
{HOLDINGS_RISK}
现金来源: {CASH_SOURCE}
═══════════════════════════════════════