Workflow Operator on Telegram
Workflow Operator on Telegram uses a Telegram bot to map each Telegram chat to a persistent Dagu AI agent session. Messages sent in Telegram are forwarded to the built-in AI agent, and agent responses are sent back to Telegram. When a DAG run completes, Workflow Operator can also send AI-generated notifications so follow-up stays in the same conversation.
Prerequisites
Before setting up Workflow Operator on Telegram, configure the AI agent in the Web UI. Go to Agent Settings (/agent-settings) and set your LLM provider and API key. The Telegram bot forwards messages to the built-in agent, so it must be configured first. See Agent Overview for details.
Creating a Telegram Bot
Before configuring Dagu, you need to create a bot on Telegram and get its token.
Open Telegram and search for
@BotFather, or go to https://t.me/BotFather.Send
/newbot.BotFather will ask for a display name (e.g.,
My Dagu Bot). Send it.BotFather will ask for a username. This must end in
bot(e.g.,my_dagu_bot). Send it.BotFather replies with a message containing your bot token. It looks like this:
Done! Congratulations on your new bot. You will find it at t.me/my_dagu_bot. You can now add a description, about section and profile picture for your bot, see /help for a list of commands. Use this token to access the HTTP API: 123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11Copy the token (
123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11in this example). This is the value forbots.telegram.tokenin Dagu config or theDAGU_BOTS_TELEGRAM_TOKENenvironment variable.Open a chat with your new bot in Telegram (search for
@my_dagu_bot) and send any message. This is needed so the bot has a chat to respond to, and so you can retrieve your chat ID (see Finding your chat ID below).
Running
The Telegram connector for Workflow Operator starts automatically when bots.provider is set to telegram and you run either:
dagu serveror
dagu start-allIn both modes, the connector shares the server's agent API instance.
Configuration
Set provider: telegram under bots and configure the Telegram-specific fields. Only one connector can be active at a time. Set these in the Dagu config file (~/.config/dagu/config.yaml or the path set by DAGU_HOME):
bots:
provider: telegram
safe_mode: true
telegram:
token: "123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11"
allowed_chat_ids:
- 123456789
- 987654321bots fields
| Field | Type | Default | Description |
|---|---|---|---|
provider | string | "" (disabled) | Which connector to run. Set to "telegram" or "slack". If empty, no bot starts. Only one provider can be active at a time. |
safe_mode | bool | true | Passed to the agent's ChatRequest.SafeMode field. Applies to all bot connectors. |
bots.telegram fields
| Field | Type | Default | Description |
|---|---|---|---|
token | string | (required) | Bot token from Telegram's @BotFather |
allowed_chat_ids | []int64 | (required) | Telegram chat IDs authorized to use the bot. Messages from other chats are rejected. |
Environment variables
| Variable | Config equivalent |
|---|---|
DAGU_BOTS_PROVIDER | bots.provider |
DAGU_BOTS_SAFE_MODE | bots.safe_mode |
DAGU_BOTS_TELEGRAM_TOKEN | bots.telegram.token |
DAGU_BOTS_TELEGRAM_ALLOWED_CHAT_IDS | bots.telegram.allowed_chat_ids |
The environment variable takes precedence over the config file value for the token.
Finding your chat ID
Send a message to your bot, then call the Telegram API to see the chat.id:
curl -s "https://api.telegram.org/bot<YOUR_TOKEN>/getUpdates" | jq '.result[0].message.chat.id'Telegram Commands
| Command | Behavior |
|---|---|
/start | Prints a welcome message listing available commands |
/new | Resets the chat state and clears the current agent session |
/cancel | Cancels the currently active agent session |
Any non-command text message is forwarded to the agent. If no session exists, one is created. If a session already exists, the message is sent to it.
Agent Prompts
When the agent asks the user a question (a UserPrompt), the bot renders it in Telegram:
- If the prompt has predefined options, they appear as inline keyboard buttons. Tapping a button submits that option.
- If the prompt allows free text (
AllowFreeText: true), the user can also reply with a regular text message. - If the prompt includes a
Commandfield, it is shown in the message as`command text`.
Only prompts that are currently pending in the session are shown. Prompts that were already answered are not re-displayed.
Session Rotation
The bot tracks token usage across all messages in a session. When total tokens exceed 50% of the assumed context limit (200,000 tokens), the bot automatically:
- Collects the last 3 user/assistant exchanges from the old session (each truncated to 200/300 characters respectively)
- Resets the chat state
- Creates a new session with the summary prepended to the user's message
- Sends a notice:
(Session context limit reached — continuing with recent context carried forward)
DAG Run Notifications
When a DAGRunStore is available (it is in both server and start-all modes), the bot starts a DAG run monitor that polls for completed runs and sends notifications.
Monitored statuses
Notifications are sent for these DAG run statuses:
succeededfailedabortedpartially_succeededrejectedwaiting(for human approval requests)
How notifications work
- The monitor polls every 10 seconds for runs with the above statuses from the last hour.
- On startup, it seeds its "seen" set with all completed runs from the last 24 hours to avoid notifying about old runs.
- For each new completion, it creates a dedicated agent session per allowed chat, sends a structured prompt with the run details (DAG name, status, error, start/finish times, step results), and waits for the agent to generate a notification message (up to 10 minutes).
- The notification session is adopted as the chat's active session, so the user can send follow-up messages like "show me the logs" or "retry it".
- Seen entries are evicted after 2 hours.
Fallback
If the agent API is unavailable or times out, the bot sends a plain text fallback:
<emoji> DAG '<name>' <status>
Error: <error message if any>Where the emoji is: ✅ succeeded/partial, ❌ failed/rejected, ⚠️ aborted, ⏳ waiting.
Polling Behavior
The bot subscribes to agent session updates by polling GetSessionDetail. Polling starts at 1 second intervals. When there are no new messages and the agent is not working, the interval doubles up to 5 seconds. When new messages arrive, it resets to 1 second. Polling stops when the agent is not working and no new messages have appeared for 3+ consecutive polls.
