Commit graph

10 commits

Author SHA1 Message Date
Simbiot Harness
06be288657 feat(inbox): батч-триаж входящих TG — сводный ответ закрывает все сообщения за один тик (t-260930064924)
Минутный тик отвечал по одному сообщению за тик (m-516173222..228 —
7 тиков подряд на один разговор): контекст показывал все, но мандат
говорил «ответь на него», и главное — нечем было закрыть несколько
входящих одним ответом (tg-reply закрывает одно, «хвосты» снова будили
гейт важности).

- tg_inbox.send_batch_reply: одна TG-отправка → ReplySent на КАЖДОЕ
  входящее батча (полный текст у головного, у хвостовых — ссылка);
  гонки (replied/ignored выпадают, пустой батч → ValueError), разные
  чаты делят батч — каждому своя отправка
- cli tg-reply <id1>,<id2>,… -c: батч-режим; несколько id без -c — отказ
  (защита от случайного закрытия); одиночный режим обратно совместим
- build_context: секция инбокса = «БАТЧ из N» с готовой командой
  (все id через запятую) и инструкцией закрыть ВСЁ за этот тик; кап
  10 → 50 (показываем весь батч, а не хвост)
- мандат min: батч-семантика (сводный ответ по смыслу разговора)
- тесты tests/test_inbox_batch.py: 32 проверки (hermetic), все зелёные
2026-09-30 10:12:47 +00:00
Simbiot Harness
ec7fe76734 fix(tg): send_reply грузит .env до sendChatAction (свежий процесс терял индикатор); safe-restart: пост-рестарт верификация сек-тика на команде; tests/test_tg_commands.py (41 проверка) 2026-09-30 02:42:09 +00:00
Simbiot Harness
76aa204f2b feat(tg-cmd): без-LLM команды бота /лестница /статус /задачи /помощь — мгновенные ответы сек-рефлексом + setMyCommands (t-260929210755-9bf6a6)
- harness/tg_commands.py: реестр команд, парсер (кириллица/транслит/@бот/без слэша),
  хендлеры из read model, answer_pending (идемпотентно, cooldown 60с при лежащем TG),
  setMyCommands с фолбэком кириллица→транслит (Bot API латиницу только)
- scheduler.py: сек-тик отвечает на команды без LLM (payload.commands),
  build_context НЕ показывает команды мин-уровню (гонки/лежащий TG не тратят LLM)
- tg_inbox.py: send_message/send_reply принимают короткий timeout для рефлекса;
  поллер при старте авторегистрирует команды бота
- cli.py: tg-commands --register/--list
2026-09-30 02:30:27 +00:00
Simbiot Harness
e580b15653 feat(voice): транскрипция голосовых TG в рантайме — полный путь file_id→download→ASR→MessageTranscribed (t-260929171234-cad7af)
- voice.py: download по file_id (getFile→file, кэш ogg по file_unique_id),
  два ASR-яруса: whisper-asr-webservice base (быстро ~1с) → fallback
  faster-whisper large-v3-turbo (CPU int8, ~11с, точный на русском;
  короткие voice ≤30с идут сразу в точный ярус — base коверкает фразы)
- _fw_asr_worker.py: faster-whisper в системном python3 (в venv нет),
  subprocess JSON-обёртка (stdin JSON → stdout JSON)
- tg_inbox.py: file_unique_id в MessageReceived + расшифровка сразу
  при приёме (поллер пишет MessageTranscribed до первого мин-тика;
  сбой транскрипции не валит поллер) + video_note как транскрибируемый kind
- es.py: проекция MessageTranscribed (transcript→text, original_text,
  reset для --force), cli tg-transcribe <id> [--force] — ручная расшифровка
- scheduler.py: голосовые в контексте мин-уровня даже с пустым текстом
  (неотвеченное не исчезает): пометки «расшифровано/не расшифровано/
  расшифровка не удалась», сортировка по ts, срез 10

Е2Е проверено: m-516173163 — кэш-хит → turbo → «Ты теперь слышишь мои
голосовые, да?» в стор; base на том же файле давал «Туше, что ты тебя
слышишь» — выбор ярусов подтверждён фактом. Воркер past-hour умер по
2880с-таймауту до коммита; WIP доведён, протестирован, закоммичен.
2026-09-30 00:02:30 +00:00
simbiot-harness
9cd10256c4 fix(ladder): занятость уровня в срезе из running-задач, а не cycle_state.busy (t-260929170039-aad557)
busy в read model всегда False — истинная занятость живёт в памяти
планировщика, событий для неё нет. Срез показывал «ожидает», пока
часовой уровень держал running-задачу. TaskClaimed закрепляет уровень
за задачей в проекции — теперь срез показывает «занят (running-задача)».
2026-09-29 21:07:12 +00:00
simbiot-harness
78ba888bb9 feat(tg): TG-visibility — уведомления о занятости уровней + срез лестницы по запросу (t-260929170039-aad557)
- tg_inbox.notify_chat(): отправка в чат харнеса без входящего-родителя
  (чат = последний MessageReceived от Alex)
- tg_inbox.ladder_snapshot(): срез лестницы — занятость/тики/ошибки уровней,
  готово/в работе, открытые эскалации; read-only через run_projections()
- scheduler._notify_busy(): уровень сообщает в TG о взятии задачи
  (анти-спам 15м на уровень) — TaskClaimed в scheduler.run_level_tick
- cli.py: команда ladder + tg-notify; /лестница|/ladder|/статус|/status
  в tg-reply заменяется на срез лестницы — запрос из TG самодостаточен
- guard в __main__ tg_inbox: единственный легитимный поллер — systemd-сервис
  (раньше python -m harness.tg_inbox с любыми аргументами поднимал
  конкурирующего поллера → 409 Conflict в легитимном)
2026-09-29 21:04:31 +00:00
Simbiot Harness
43e3c3b63b tg_inbox: сохранять file_id/длительность голосовых и фото (нужно для транскрипции) 2026-09-29 17:12:47 +00:00
Simbiot Harness
728ebb86c0 fix(tg): kind нетекстовых сообщений в MessageReceived (стикер/фото/голос) + caption как text — пустые text больше не выглядят загадкой 2026-09-29 17:08:12 +00:00
simbiot-harness
47f9139948 feat(tg): typing-индикатор (sendChatAction) перед ответом мин-уровня — в TG видно «печатает…» 2026-09-29 16:47:58 +00:00
Simbiot Harness
94cc921ccd feat: Telegram-инбокс — сообщения Алекса как события
- harness/tg_inbox.py: long-polling поллер (@juno42bot) + send_reply
- события MessageReceived/ReplySent/MessageIgnored (агрегат inbox)
- проекция inbox в read model (кап 100)
- контекст минутного тика: входящие ждущие ответа + мандат триажа
- cli.py tg-reply: Telegram-отправка + ReplySent закрывает входящее
- systemd simbiot-harness-tg.service
- E2E: «йоу» от Алекса → минутный тик ответил в TG + дайджест в сторе
2026-09-29 15:52:46 +00:00