From b2391c2b5b6cf33711088b79eaa6bb4f7de66901 Mon Sep 17 00:00:00 2001 From: Simbiot Harness Date: Fri, 16 Oct 2026 14:19:22 +0000 Subject: [PATCH] =?UTF-8?q?set-tg-bot:=203=20=D0=BF=D0=BE=D0=BF=D1=8B?= =?UTF-8?q?=D1=82=D0=BA=D0=B8=20getMe=20timeout=3D15=20+=20backoff=203/6?= =?UTF-8?q?=D1=81=20(t-261016141220)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cli.py | 35 +++++++++++++++++++++++++++++++++++ harness/portal_channel.py | 30 ++++++++++++++++++++---------- 2 files changed, 55 insertions(+), 10 deletions(-) diff --git a/cli.py b/cli.py index fb28def..f7a2ecc 100644 --- a/cli.py +++ b/cli.py @@ -187,6 +187,9 @@ def main(): p_mcp.add_argument("--list", action="store_true", help="показать тулы шлюза и выйти") p_mcp.add_argument("--timeout", type=int, default=None, help="таймаут запроса, сек") + p_mcs = sub.add_parser("mcp-stats", help="статистика MCP-вызовов по журналу mcp_calls.log (t-261015091108)") + p_mcs.add_argument("--tail", type=int, default=10, help="последние N вызовов (0 — только сводка)") + args = ap.parse_args() if args.cmd == "init": @@ -447,6 +450,38 @@ def main(): ap.error("mcp-call: укажи tool (или --list)") kw = {"timeout": args.timeout} if args.timeout else {} print(portal_mcp.call_tool(args.tool, args.arguments, **kw)) + elif args.cmd == "mcp-stats": + # t-261015091108: статистика MCP-вызовов из журнала mcp_calls.log + import collections + log_path = os.path.join(_paths.home(), "mcp_calls.log") + if not os.path.exists(log_path): + print("(журнала ещё нет — mcp_calls.log пуст, вызовов не было)") + return + rows = [] + with open(log_path, encoding="utf-8") as f: + for line in f: + line = line.strip() + if not line: + continue + try: + rows.append(json.loads(line)) + except ValueError: + pass + by_tool = collections.Counter(r.get("tool", "?") for r in rows) + by_level = collections.Counter(r.get("level", "?") for r in rows) + fails = sum(1 for r in rows if not r.get("ok")) + ms = [r.get("ms", 0) for r in rows if isinstance(r.get("ms"), int)] + print(f"всего вызовов: {len(rows)} (ошибок: {fails})") + if ms: + print(f"время ответа: медиана {sorted(ms)[len(ms)//2]}мс, макс {max(ms)}мс") + print("по тулам: " + ", ".join(f"{k}×{v}" for k, v in by_tool.most_common())) + print("по уровням: " + ", ".join(f"{k}×{v}" for k, v in by_level.most_common())) + if args.tail: + print(f"\nпоследние {min(args.tail, len(rows))}:") + for r in rows[-args.tail:]: + args_s = json.dumps(r.get("arguments", {}), ensure_ascii=False)[:120] + print(f"{r.get('ts','?')} [{r.get('level','?')}] {r.get('tool','?')} " + f"{'ok' if r.get('ok') else 'FAIL'} {r.get('ms','?')}мс {args_s}") elif args.cmd == "escalate": es.init_db() eid, to_level = commands.raise_escalation( diff --git a/harness/portal_channel.py b/harness/portal_channel.py index dd46c7d..6309062 100644 --- a/harness/portal_channel.py +++ b/harness/portal_channel.py @@ -298,17 +298,27 @@ def _apply_tg_command(text: str) -> None: except OSError: pass # 1) самотест токена ДО записи: getMe от Telegram - try: - req = urllib.request.Request(f"https://api.telegram.org/bot{token}/getMe") - with urllib.request.urlopen(req, timeout=10) as r: - me = json.loads(r.read().decode()) - if not (me.get("ok") and (me.get("result") or {}).get("username")): - raise RuntimeError(str(me)[:150]) - uname = me["result"].get("username") or "bot" - except Exception as e: - _report(f"❌ TG-токен не принят Telegram (getMe): {e}") - print(f"[set-tg] токен не валиден: {e}", flush=True) + # (t-261016141XXX: 3 попытки с паузой — таймаут сети не должен ронять привязку) + me = None + _last_err = None + for _attempt in range(3): + try: + req = urllib.request.Request(f"https://api.telegram.org/bot{token}/getMe") + with urllib.request.urlopen(req, timeout=15) as r: + me = json.loads(r.read().decode()) + if not (me.get("ok") and (me.get("result") or {}).get("username")): + raise RuntimeError(str(me)[:150]) + break + except Exception as e: + _last_err = e + me = None + if _attempt < 2: + time.sleep(3 * (_attempt + 1)) + if me is None: + _report(f"❌ TG-токен не принят Telegram (getMe, 3 попытки): {_last_err}") + print(f"[set-tg] токен не валиден: {_last_err}", flush=True) return + uname = me["result"].get("username") or "bot" # 2) аллоулист: из команды (allowed=…), иначе сохранённый в .env allowed = payload.get("allowed") or payload.get("owner_tg") or "" if not allowed: