diff --git a/nanobot/channels/telegram.py b/nanobot/channels/telegram.py index e3fd11485..9a9ec9bbd 100644 --- a/nanobot/channels/telegram.py +++ b/nanobot/channels/telegram.py @@ -311,6 +311,7 @@ class TelegramChannel(BaseChannel): BotCommand("goal", "Start a sustained objective (long-running task)"), BotCommand("pairing", "Manage DM pairing (approve/deny/list)"), BotCommand("model", "Switch runtime model preset"), + BotCommand("skill", "List enabled skills"), BotCommand("dream", "Run Dream memory consolidation now"), BotCommand("dream_log", "Show the latest Dream memory change"), BotCommand("dream_restore", "Restore Dream memory to an earlier version"), @@ -320,7 +321,7 @@ class TelegramChannel(BaseChannel): # Regex for slash commands routed to AgentLoop via ``_forward_command``. # Hyphenated ``dream-*`` commands stay on a separate handler (below). TELEGRAM_BUS_SLASH_COMMAND_RE = re.compile( - r"^/(?:new|stop|restart|status|dream|history|goal|pairing|model)(?:@\w+)?(?:\s+.*)?$" + r"^/(?:new|stop|restart|status|dream|history|goal|pairing|model|skill)(?:@\w+)?(?:\s+.*)?$" ) @classmethod diff --git a/tests/channels/test_telegram_channel.py b/tests/channels/test_telegram_channel.py index f53d8d8a1..9b66d58be 100644 --- a/tests/channels/test_telegram_channel.py +++ b/tests/channels/test_telegram_channel.py @@ -212,6 +212,7 @@ async def test_start_creates_separate_pools_with_proxy(monkeypatch) -> None: assert callable(app.updater.start_polling_kwargs["error_callback"]) assert any(cmd.command == "status" for cmd in app.bot.commands) assert any(cmd.command == "history" for cmd in app.bot.commands) + assert any(cmd.command == "skill" for cmd in app.bot.commands) assert any(cmd.command == "dream" for cmd in app.bot.commands) assert any(cmd.command == "dream_log" for cmd in app.bot.commands) assert any(cmd.command == "dream_restore" for cmd in app.bot.commands) @@ -1426,6 +1427,8 @@ def test_telegram_bus_slash_command_regex_matches_agent_loop_commands() -> None: assert pat.fullmatch("/goal ship the feature") assert pat.fullmatch("/pairing list") assert pat.fullmatch("/model fast") + assert pat.fullmatch("/skill") + assert pat.fullmatch("/skill@nanobot_bot") assert pat.fullmatch("/new@nanobot_bot") assert pat.fullmatch("/goal@nanobot_bot refine objective") assert pat.fullmatch("/dream-log deadbeef") is None @@ -1447,6 +1450,7 @@ async def test_on_help_includes_restart_command() -> None: help_text = update.message.reply_text.await_args.args[0] assert "/restart" in help_text assert "/status" in help_text + assert "/skill" in help_text assert "/dream" in help_text assert "/dream-log" in help_text assert "/goal" in help_text