From 7e19e1b3f6de8a6edf49a121278f6451fd66b0b9 Mon Sep 17 00:00:00 2001 From: Simbiot Harness Date: Sun, 4 Oct 2026 15:28:00 +0000 Subject: [PATCH] =?UTF-8?q?fix:=20=5Fdefault=5Fchat=5Fid=20=D0=BD=D0=B5=20?= =?UTF-8?q?=D0=B2=D1=8B=D0=B1=D0=B8=D1=80=D0=B0=D0=B5=D1=82=20tui:*-=D1=87?= =?UTF-8?q?=D0=B0=D1=82=20=D0=BB=D0=B8=D1=87=D0=BA=D0=BE=D0=B9=20Alex?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Тестовое TUI-сообщение (t-261004132716, chat_id=tui:local) стало последним в inbox → notify_chat/send_document целились в несуществующий Telegram-чат → уведомления тихо SKIP'ались при живом чате. Фильтр локальных каналов расширен: portal:* И tui:*. --- harness/tg_inbox.py | 33 ++++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/harness/tg_inbox.py b/harness/tg_inbox.py index 82d79b2..b3b52e5 100644 --- a/harness/tg_inbox.py +++ b/harness/tg_inbox.py @@ -228,6 +228,15 @@ def send_reply(msg_id: str, text: str, timeout: int = 35): "to_chat": m["chat_id"], "text": text[:2000], "channel": "portal", }) return msg_id + # ── TUI-канал (t-261004132716): чат 'tui:*' — локальный терминал агента. + # Доставка = запись в этот же стор: TUI-процесс (tools/tui_chat.py) читает + # reply_text проекции и печатает. Внешнего транспорта нет — ReplySent + # пишем сразу, ответ не может «потеряться в сети». + if str(m.get("chat_id") or "").startswith("tui:"): + es.append_event("inbox", msg_id, "ReplySent", { + "to_chat": m["chat_id"], "text": text[:2000], "channel": "tui", + }) + return msg_id _load_env() # sendChatAction идёт до send_message: в свежем процессе # (демон/сек-рефлекс) токен ещё не загружен — иначе «печатает…» молча теряется try: # индикатор — best effort: недоступность TG-метода не мешает ответу @@ -303,6 +312,18 @@ def send_batch_reply(msg_ids: list, text: str, timeout: int = 35): }) return head_mid for chat_id, items in by_chat.items(): + if str(chat_id).startswith("tui:"): + # TUI-канал (t-261004132716): локальная доставка событием в стор, + # без Telegram — TUI-процесс читает reply_text проекции. + for mid, m in items: + es.append_event("inbox", mid, "ReplySent", { + "to_chat": chat_id, + "text": (text if mid == head_mid + else f"(сводный ответ батча {batch_id} — см. {head_mid})")[:2000], + "channel": "tui", + "batch": {"id": batch_id, "size": len(pending), "head": head_mid}, + }) + continue try: # индикатор — best effort, как в send_reply _api("sendChatAction", {"chat_id": chat_id, "action": "typing"}, timeout=10) except Exception: @@ -413,12 +434,14 @@ def _default_chat_id(): if not TG_TOKEN: return None model = es.run_projections() - # portal:* — это портал-канал (t-261001123121), не Telegram: файлы/тексты - # туда идут через push portal_channel, а не через API Telegram. - # Без фильтра E2E/чат портала «перебивает» личку Alex дефолтным чатом - # → send_message/send_document падают 'chat not found' (найдено 02.10). + # portal:* — портал-канал (t-261001123121), tui:* — терминал-чат + # (t-261004132716): оба НЕ Telegram, уходят своими транспортами. + # Без фильтра E2E/чат портала или TUI «перебивает» личку Alex + # дефолтным чатом → send_message/send_document падают 'chat not found' + # (портал — найдено 02.10; tui — 04.10, SKIP уведомлений при живом чате). inbox = [m for m in (model.get("inbox") or {}).values() - if m.get("chat_id") and not str(m.get("chat_id")).startswith("portal") + if m.get("chat_id") + and not str(m.get("chat_id")).startswith(("portal", "tui")) and not m.get("ignored")] if not inbox: return None # некому: чат ещё не известен