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 # некому: чат ещё не известен