← Về thư mục
📄 / / root / GitHub / docs / research / telegram-discord-agent-bridge.md

Research: Telegram & Discord Bridges for Remote AI Agent Control & HITL

This research report outlines the architecture patterns, workflow designs, and project structures for bridging a local AI coding agent (specifically Google Antigravity SDK) to Telegram or Discord for remote execution, status updates, and interactive "Yes/No" tool approvals (Human-in-the-Loop).


1. Executive Summary


2. Methodology & Sources

This research synthesized patterns from: 1. LangGraph State Interrupts: Analyzing how LangGraph uses checkpointers and interrupts to pause agents for human approval. 2. LobeHub Telegram HITL MCP: Standardized model context protocol patterns for piping questions to messaging apps. 3. Community Discord Bridges: Analyzing how developers route tmux sessions and CLI outputs to Discord channels. 4. Google Antigravity SDK: Reviewing the native hooks and LocalAgentConfig APIs for tool interception.


3. Workflow Diagram (HITL & Session Routing)

The following diagram illustrates how a command is routed from Discord, executed by the agent, paused for approval, and completed.

sequenceDiagram
    autonumber
    actor User as User (Phone/Discord)
    participant Discord as Discord Server
    participant Bot as Python Bot (Host)
    participant Agent as Antigravity Agent
    participant System as Local OS / Filesystem

    User->>Discord: Create Thread & Send: "Refactor main.py"
    Discord->>Bot: Event: on_message (in Thread)
    Note over Bot: Identify Project from Channel Path<br/>Identify Session from Thread ID
    Bot->>Agent: Initialize/Retrieve Agent & Send Prompt
    Agent->>Agent: Process prompt & decide to use tool: "write_file"

    rect rgb(240, 240, 255)
        Note over Agent, Bot: HITL Approval Gate
        Agent->>Bot: Trigger Hook: pre_tool_call_decide(write_file)
        Note over Agent: Agent Pauses (Async Wait)
        Bot->>Discord: Send Message with Buttons: [Approve] / [Deny]
        User->>Discord: Taps [Approve]
        Discord->>Bot: Event: on_interaction (Button Click)
        Bot->>Agent: Resume Hook with HookResult(allow=True)
    end

    Agent->>System: Execute write_file tool
    System-->>Agent: Tool Result (Success)
    Agent-->>Bot: Return Final Answer
    Bot->>Discord: Send Final Response to Thread
    Discord-->>User: View complete refactoring

4. Project Design & Architecture

To implement this on your Mac, we will structure a lightweight Python project.

Directory Structure

antigravity-messenger-bridge/
├── .env                  # BOT_TOKEN, AUTHORIZED_USER_IDS, WORKSPACE_ROOT
├── requirements.txt      # discord.py, google-antigravity, python-dotenv
├── main.py               # Bot entrypoint and event loop
├── bridge/
│   ├── __init__.py
│   ├── bot.py            # Discord client & event handlers
│   ├── manager.py        # Session & Project routing manager
│   └── agent_wrapper.py  # Antigravity agent wrapper & hook definitions
└── config.json           # Maps Discord Channel IDs to local project paths

Core Components Design

A. The Session Manager (bridge/manager.py)

Responsible for routing messages. * It reads config.json to map Discord Channels to local directory paths. * Example: Channel #website-frontend $\rightarrow$ /Users/keira/Documents/GitHub/my-frontend. * It tracks active Discord Threads. Each Thread ID represents an isolated conversation context. * When a message arrives in a Thread, it retrieves the corresponding AgentWrapper or creates a new one.

B. The Agent Wrapper & Hooks (bridge/agent_wrapper.py)

Wraps the google-antigravity SDK and implements the approval gate.

import asyncio
from google.antigravity import types
from google.antigravity.connections.local import LocalAgentConfig, LocalAgent

class AgentWrapper:
    def __init__(self, project_path, thread_id, bot_client):
        self.project_path = project_path
        self.thread_id = thread_id
        self.bot = bot_client

        # Future used to block the hook until the user clicks a button
        self.approval_future = None 

        # Configure the Agent with local hooks
        self.config = LocalAgentConfig(
            workspace=self.project_path,
            hooks=[
                self.pre_tool_call_hook,
                self.post_tool_call_hook
            ]
        )
        self.agent = LocalAgent(self.config)

    async def pre_tool_call_hook(self, tool_call: types.ToolCall) -> types.HookResult:
        # 1. Create the approval future
        self.approval_future = asyncio.get_event_loop().create_future()

        # 2. Send the approval request to Discord
        await self.bot.send_approval_request(
            thread_id=self.thread_id, 
            tool_name=tool_call.name, 
            arguments=tool_call.arguments
        )

        # 3. Wait for the Discord button click event to resolve the future
        approved = await self.approval_future

        return types.HookResult(allow=approved)

    def resolve_approval(self, approved: bool):
        if self.approval_future and not self.approval_future.done():
            self.approval_future.set_result(approved)

5. Inherit vs. Takeaway Analysis

Inherit (Ground Truth) Takeaway (Actionable Insights)
Secure User Validation: Messengers are public networks; we must strictly validate the sender's ID. Implement a hard check: if message.author.id != AUTHORIZED_USER_ID: return on every event.
Stateful Asynchrony: AI agents run asynchronously and cannot be blocked using synchronous input(). Use asyncio.Future to pause the SDK's async hook execution cleanly without freezing the bot's event loop.
Workspace Isolation: Operating on multiple projects requires changing the working directory of the agent. Dynamically instantiate LocalAgent with a different workspace path depending on the Discord channel.

6. Next Steps

  1. Register a Discord Bot: Go to the Discord Developer Portal, create a bot, enable Guilds, Guild Messages, and Message Content intents, and invite it to your private server.
  2. Create Project Directories: Set up the Python project structure on your Mac.
  3. Implement main.py: Write the integration code connecting discord.py with google-antigravity.