Commands with descriptions and argumentsΒΆ

A bot is mostly commands. Raito adds three small decorators from the rt namespace that make commands self-describing and type-safe.

DescriptionsΒΆ

rt.description attaches a human description to a command. Raito collects these and registers them with Telegram, so they show up in the client’s slash menu automatically.

from aiogram import Router, filters, types
from raito import rt

router = Router(name="ping")


@router.message(filters.Command("ping"))
@rt.description("Check that the bot is alive")
async def ping(message: types.Message) -> None:
    await message.answer("pong πŸ“")

To publish the menu, call raito.Raito.register_commands() once at startup (usually from a lifespan handler):

await raito.register_commands(bot)

Hiding a commandΒΆ

Some commands are internal. Decorate them with rt.hidden (note: no parentheses) and they are registered as handlers but kept out of the slash command menu:

@router.message(filters.Command("debug"))
@rt.hidden
async def debug(message: types.Message) -> None:
    ...

Typed argumentsΒΆ

For a command like /add 2 3, rt.params extracts positional arguments, converts them to the declared types and injects them into your handler by name:

@router.message(filters.Command("add"))
@rt.description("Add two numbers")
@rt.params(a=int, b=int)
async def add(message: types.Message, a: int, b: int) -> None:
    await message.answer(f"{a} + {b} = {a + b}")

Supported types are int, float, str and bool (bool accepts true/yes/on/1/ok/+). If an argument is missing or fails to convert, Raito replies with an auto-generated usage message instead of calling your handler β€” so /add two 3 shows help, not a traceback.

Tip

Arguments are positional and split on whitespace, in declaration order. @rt.params(name=str) with /hello John Doe gives name="John", so use a single trailing argument for multi-word input, or parse message.text yourself.

Important

Positional command arguments fit developer and testing tools, not user-facing flows. /add 2 3 is fine for you; asking ordinary users to pass arguments in the right order is not friendly. To collect input from real users, ask one thing at a time with a scene (backed by FSM) or a conversation (wait_for).

You now have described, typed commands. Next, restrict who can call them in Access control with roles.