feat(telegram): add welcome message for new group members
- handler.py: Added handle_new_members() to send customized greetings (supports {name} placeholder, skips bots). - bot_manager.py: Registered new handler using NEW_CHAT_MEMBERS filter. - _10_telegram_bot.py: Integrated _wrap_new_members to ensure the bot uses the latest configuration. - config.html: Added Welcome New Members toggle and Welcome Message input (conditional visibility based on Group Mode). - telegram-config-store.js & default_config.yaml: Added default state (false) and documentation.
keyboardstaff committed
Mar 22, 2026 at 10:09 UTC
4a06e0c05ea79b68da7f5984fdbea90de1652e2a
6 files changed
+65
-1
plugins/_telegram_integration/default_config.yaml
+2
@@ -9,6 +9,8 @@ bots: []
9
# webhook_secret: "" # optional shared secret for webhook verification
10
# allowed_users: [] # Telegram user IDs or @usernames. Empty = allow all.
11
# group_mode: mention # mention (respond when @mentioned or replied to) | all (respond to every message) | off (ignore groups)
12
+# welcome_enabled: false # Send a greeting when someone joins the group
13
+# welcome_message: "" # Welcome template. Use {name} for the new member's name. Default: "Welcome, {name}!"
14
# user_projects: {} # Map Telegram user_id to project name, e.g. { "123456": "my_project" }
15
# default_project: "" # Fallback project if user not in user_projects
16
# attachment_max_age_hours: 0 # Hours to keep downloaded attachments. 0 = keep forever.
plugins/_telegram_integration/extensions/python/job_loop/_10_telegram_bot.py
+8
@@ -26,6 +26,7 @@ class TelegramBotManager(Extension):
26
handle_clear,
27
handle_message,
28
handle_callback_query,
29
+ handle_new_members,
30
cleanup_old_attachments,
31
)
32
@@ -67,6 +68,7 @@ class TelegramBotManager(Extension):
68
_on_clear = partial(_wrap_clear, bot_name=name, bot_cfg=bot_cfg)
69
_on_message = partial(_wrap_message, bot_name=name, bot_cfg=bot_cfg)
70
_on_callback = partial(_wrap_callback, bot_name=name, bot_cfg=bot_cfg)
71
+ _on_new_members = partial(_wrap_new_members, bot_name=name, bot_cfg=bot_cfg)
72
73
instance = create_bot(
74
name=name,
@@ -75,6 +77,7 @@ class TelegramBotManager(Extension):
77
on_command_start=_on_start,
78
on_command_clear=_on_clear,
79
on_callback_query=_on_callback,
80
+ on_new_members=_on_new_members,
81
group_mode=bot_cfg.get("group_mode", "mention"),
82
)
83
@@ -130,3 +133,8 @@ async def _wrap_message(message, bot_name: str, bot_cfg: dict):
133
async def _wrap_callback(query, bot_name: str, bot_cfg: dict):
134
from plugins._telegram_integration.helpers.handler import handle_callback_query
135
await handle_callback_query(query, bot_name, _get_current_bot_cfg(bot_name) or bot_cfg)
136
+
137
+
138
+async def _wrap_new_members(message, bot_name: str, bot_cfg: dict):
139
+ from plugins._telegram_integration.helpers.handler import handle_new_members
140
+ await handle_new_members(message, bot_name, _get_current_bot_cfg(bot_name) or bot_cfg)
plugins/_telegram_integration/helpers/bot_manager.py
+5
-1
@@ -4,7 +4,7 @@ from typing import Callable, Awaitable
4
5
from aiogram import Bot, Dispatcher, Router, F
6
from aiogram.client.default import DefaultBotProperties
7
-from aiogram.enums import ParseMode, ChatType
7
+from aiogram.enums import ParseMode, ChatType, ContentType
8
from aiogram.filters import Command, CommandStart
9
from aiogram.types import Message
10
@@ -46,6 +46,7 @@ def create_bot(
46
on_command_start: Callable[..., Awaitable],
47
on_command_clear: Callable[..., Awaitable],
48
on_callback_query: Callable[..., Awaitable] | None = None,
49
+ on_new_members: Callable[..., Awaitable] | None = None,
50
group_mode: str = "mention",
51
) -> BotInstance:
52
bot = Bot(token=token, default=DefaultBotProperties(parse_mode=ParseMode.HTML))
@@ -59,6 +60,9 @@ def create_bot(
60
if on_callback_query:
61
router.callback_query.register(on_callback_query)
62
63
+ if on_new_members:
64
+ router.message.register(on_new_members, F.content_type == ContentType.NEW_CHAT_MEMBERS)
65
+
66
# Register message handler with group filtering
67
if group_mode == "off":
68
# Private chats only
plugins/_telegram_integration/helpers/handler.py
+25
@@ -289,6 +289,31 @@ async def handle_callback_query(query: CallbackQuery, bot_name: str, bot_cfg: di
289
context.communicate(UserMessage(message=user_msg))
290
save_tmp_chat(context)
291
292
+
293
+async def handle_new_members(message: TgMessage, bot_name: str, bot_cfg: dict):
294
+ """Send welcome message when new members join a group."""
295
+ if not bot_cfg.get("welcome_enabled", False):
296
+ return
297
+
298
+ new_members = message.new_chat_members or []
299
+ if not new_members:
300
+ return
301
+
302
+ instance = get_bot(bot_name)
303
+ if not instance:
304
+ return
305
+
306
+ template = bot_cfg.get("welcome_message", "").strip()
307
+ if not template:
308
+ template = "Welcome, {name}!"
309
+
310
+ for member in new_members:
311
+ if member.is_bot:
312
+ continue
313
+ name = member.full_name or member.first_name or str(member.id)
314
+ text = template.replace("{name}", name)
315
+ await _send_with_temp_bot(instance.bot.token, message.chat.id, text, parse_mode=None)
316
+
317
# Context management
318
319
async def _get_or_create_context(
plugins/_telegram_integration/webui/config.html
+23
@@ -179,6 +179,29 @@
179
</div>
180
</div>
181
182
+ <div class="field" x-show="bot.group_mode !== 'off'">
183
+ <div class="field-label">
184
+ <div class="field-title">Welcome New Members</div>
185
+ <div class="field-description">Send a greeting when someone joins the group</div>
186
+ </div>
187
+ <div class="field-control">
188
+ <label class="toggle">
189
+ <input type="checkbox" x-model="bot.welcome_enabled" />
190
+ <span class="toggler"></span>
191
+ </label>
192
+ </div>
193
+ </div>
194
+
195
+ <div class="field" x-show="bot.group_mode !== 'off' && bot.welcome_enabled">
196
+ <div class="field-label">
197
+ <div class="field-title">Welcome Message</div>
198
+ <div class="field-description">Use {name} for the new member's name</div>
199
+ </div>
200
+ <div class="field-control">
201
+ <input type="text" x-model="bot.welcome_message" placeholder="Welcome, {name}!" />
202
+ </div>
203
+ </div>
204
+
205
<div class="field">
206
<div class="field-label">
207
<div class="field-title">User Project Mapping</div>
plugins/_telegram_integration/webui/telegram-config-store.js
+2
@@ -32,6 +32,8 @@ export const store = createStore("telegramConfig", {
32
webhook_secret: "",
33
allowed_users: [],
34
group_mode: "mention",
35
+ welcome_enabled: false,
36
+ welcome_message: "",
37
user_projects: {},
38
default_project: "",
39
agent_instructions: "",