simplex-chat-python: add BotCommand.params field (#7034)

This commit is contained in:
sh
2026-06-01 12:20:29 +00:00
committed by GitHub
parent 60e75aa398
commit e4ef8ef101
3 changed files with 126 additions and 5 deletions
@@ -33,8 +33,38 @@ from .types import T
@dataclass(slots=True)
class BotCommand:
"""One entry in the bot's advertised slash-command list (wire-side
`groupPreferences.commands` or profile `preferences.commands`).
`keyword` and `label` are required: `keyword` is what the user
types after `/`; `label` is the human-readable description shown
next to the keyword in the SimpleX client's commands menu.
`params` is an optional placeholder string that controls how the
client behaves when the user taps the command in the menu:
* `params=None` (default) — the client SENDS `/<keyword>`
immediately on tap; no input-box detour. Use this for
zero-argument commands (`/help`, `/ping`) where the action is
unambiguous.
* `params="<value>"` — the client PASTES `/<keyword> <params>`
into the input box and positions the cursor at the end. The
user edits the placeholder and sends. Use this for commands
that take a required argument (`/review <pr-url>`,
`/order <number>`) so the user sees the expected shape
without having to remember it.
Mirrors `CBCCommand` in the Haskell core
(`Simplex.Chat.Types.Preferences`) and the wire TypedDict
`ChatBotCommand_command`. Both SimpleX clients (Android/Kotlin
and iOS/Swift) implement the paste-vs-send branch on the
`params` field; see `CommandsMenuView.{kt,swift}` for the
reference UI behaviour.
"""
keyword: str
label: str
params: str | None = None
class Bot(Client):
@@ -145,10 +175,24 @@ class Bot(Client):
"files": {"allow": "yes" if self._allow_files else "no"},
}
if self._commands:
prefs["commands"] = [
{"type": "command", "keyword": c.keyword, "label": c.label}
for c in self._commands
]
cmds: list[T.ChatBotCommand] = []
for c in self._commands:
entry: T.ChatBotCommand_command = {
"type": "command",
"keyword": c.keyword,
"label": c.label,
}
# `params` is `NotRequired[str]` on the wire; omit the
# key entirely when None so the Haskell parser sees
# `Nothing` rather than `Just ""`. The two have
# different client semantics: `Nothing` (`params=None`)
# triggers an immediate send on tap; `Just ""` would
# paste `/<keyword> ` (with a trailing space) into the
# input box, which is rarely what the operator wants.
if c.params is not None:
entry["params"] = c.params
cmds.append(entry)
prefs["commands"] = cmds
p["preferences"] = prefs
p["peerType"] = "bot"
return p