Lists the panel account's client commands as Telegram slash commands (hourly refresh, cached on the device), shows their parameters while typing, runs complete commands on the panel instead of sending them and shows the answer as an "Only visible to you" message (latest 20 kept in memory). Holding send offers Run / Send as message / Send response in chat (red ! badge); an answer's menu starts with Send in chat. Other plugins register their own commands through the client_commands library module. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
3.4 KiB
The library: commands from other plugins
Client Commands publishes the module client_commands. Another plugin registers commands
with it. Those commands show in the / list with their parameters and run on the device, and
their answers show like the panel's: only to you, or in the chat when Send response in chat
is on.
Registering
import random
import sys
import types
from base_plugin import BasePlugin
__id__ = "dice"
__name__ = "Dice"
def setup(api):
api.register(
"roll",
roll,
summary="Rolls a die",
params=[
api.Param("sides", "integer", required=False, default=6, description="How many sides"),
api.Param("style", "choice", required=False, default="plain", choices=("plain", "big")),
],
owner=__id__,
)
def roll(ctx, sides=6, style="plain"):
api = sys.modules["client_commands"]
if sides < 2:
raise api.CommandError("A die needs at least 2 sides")
result = random.randint(1, sides)
return f"🎲 <b>{result}</b>" if style == "big" else f"🎲 {result}"
class DicePlugin(BasePlugin):
def on_plugin_load(self):
# Works whichever plugin loads first.
api = sys.modules.setdefault("client_commands", types.ModuleType("client_commands"))
if hasattr(api, "register"):
setup(api)
else:
api.__dict__.setdefault("pending", []).append(setup)
def on_plugin_unload(self):
api = sys.modules.get("client_commands")
if api is not None and hasattr(api, "unregister_owner"):
api.unregister_owner(__id__)
API
| Name | What it does |
|---|---|
register(name, handler, *, params=(), summary="", description="", aliases=(), reply="none", owner=None) |
Adds or replaces a command. reply is none, optional or required. params are Params, or dicts shaped like the panel's. |
unregister(name) |
Removes one command. |
unregister_owner(owner) |
Removes every command owner registered. Call it from on_plugin_unload. |
commands() |
The registered commands, as dicts. |
Param(name, type="string", required=True, description="", default=None, choices=()) |
type is string, integer, number, boolean or choice. |
CommandError |
Raise it for a user-facing error. The message is shown as the answer. |
escape(text) |
Makes text safe to put into an HTML answer. |
VERSION, available |
The API version, and whether Client Commands is loaded right now. |
handler(ctx, **values) runs off the UI thread. Its arguments are the parsed parameter
values, with defaults for those not given. It returns the answer as Telegram HTML, or None
(the answer is then "✓ Done"). These tags work: b, i, u, s, code, pre, a href,
blockquote, tg-spoiler, tg-emoji and br.
ctx has:
account,dialog_idandtopic_id;reply_to, the repliedMessageObjector None;text, the command as typed, andcommand, its name;values, the parsed parameters;send_to_chat, whether the answer goes into the chat as the account;client, the SDK'sAccountClientof the account.
Parsing follows the same rules as the panel's commands (see how-it-works.md). A panel command with the same name shadows yours.
Registrations survive Client Commands being updated or turned off and on. A client_commands
module kept from before still works.