feat: Telegram V2 — inbound commands + actionable approve/reject from chat (#551)

* feat(telegram): V2 inbound — command router, actionable approve/reject keyboards, chat-gated poll loop

* fix(release,x,video,telegram): terminal-state guards on approve/reject; sender-identity check

* docs(map,rag): Telegram V2 inbound surfaces and terminal-state approve/reject guards

---------

Co-authored-by: Renn F <rennf93@users.noreply.github.com>
This commit is contained in:
Renzo F
2026-07-18 00:47:09 +02:00
committed by GitHub
co-authored by Renn F
parent c9c1f62981
commit 9fbec78126
30 changed files with 2732 additions and 68 deletions
@@ -0,0 +1,51 @@
"""The Telegram inbound orchestrator loop is fully dormant when disabled
(default) — mirrors ``test_x_engine_loop_dormant.py``.
With either ``telegram_enabled`` or ``telegram_inbound_enabled`` off,
``_telegram_poll_loop`` must return immediately — no sleep, no HTTP, no DB —
so a standard deployment (and even a V1-only deployment with just
``telegram_enabled`` on) behaves exactly as today.
"""
from __future__ import annotations
import asyncio
import types
from typing import cast
import pytest
from roboco.config import settings as cfg
from roboco.runtime.orchestrator import AgentOrchestrator
@pytest.mark.asyncio
async def test_telegram_poll_loop_returns_immediately_when_both_off(
monkeypatch: pytest.MonkeyPatch,
) -> None:
monkeypatch.setattr(cfg, "telegram_enabled", False)
monkeypatch.setattr(cfg, "telegram_inbound_enabled", False)
stub = cast("AgentOrchestrator", types.SimpleNamespace(_running=True))
await asyncio.wait_for(AgentOrchestrator._telegram_poll_loop(stub), timeout=1.0)
@pytest.mark.asyncio
async def test_telegram_poll_loop_dormant_when_only_v1_flag_on(
monkeypatch: pytest.MonkeyPatch,
) -> None:
"""V1-only deployment (notifications, no inbound): the poll loop still
never runs."""
monkeypatch.setattr(cfg, "telegram_enabled", True)
monkeypatch.setattr(cfg, "telegram_inbound_enabled", False)
stub = cast("AgentOrchestrator", types.SimpleNamespace(_running=True))
await asyncio.wait_for(AgentOrchestrator._telegram_poll_loop(stub), timeout=1.0)
@pytest.mark.asyncio
async def test_telegram_poll_loop_dormant_when_only_inbound_flag_on(
monkeypatch: pytest.MonkeyPatch,
) -> None:
"""The sub-switch alone (V1 master switch off) is still fully inert."""
monkeypatch.setattr(cfg, "telegram_enabled", False)
monkeypatch.setattr(cfg, "telegram_inbound_enabled", True)
stub = cast("AgentOrchestrator", types.SimpleNamespace(_running=True))
await asyncio.wait_for(AgentOrchestrator._telegram_poll_loop(stub), timeout=1.0)