feat(commands): add interactive buttons for lang/model/mode commands

generated by llmgit

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
chenhg5andClaude committed 2026-03-07 08:36:30 +08:00
1 parent 8f630a0538
commit 0179d098ce
2 files changed
+102 -18

No files matched your search

+66 -3
View File
@@ -1811,7 +1811,20 @@ func (e *Engine) cmdLang(p Platform, msg *Message, args []string) {
if len(args) == 0 {
cur := e.i18n.CurrentLang()
name := langDisplayName(cur)
e.reply(p, msg.ReplyCtx, e.i18n.Tf(MsgLangCurrent, name))
text := e.i18n.Tf(MsgLangCurrent, name)
buttons := [][]ButtonOption{
{
{Text: "English", Data: "cmd:/lang en"},
{Text: "中文", Data: "cmd:/lang zh"},
{Text: "繁體中文", Data: "cmd:/lang zh-TW"},
},
{
{Text: "日本語", Data: "cmd:/lang ja"},
{Text: "Español", Data: "cmd:/lang es"},
{Text: "Auto", Data: "cmd:/lang auto"},
},
}
e.replyWithButtons(p, msg.ReplyCtx, text, buttons)
return
}
@@ -1896,7 +1909,26 @@ func (e *Engine) cmdModel(p Platform, msg *Message, args []string) {
}
sb.WriteString("\n")
sb.WriteString(e.i18n.T(MsgModelUsage))
e.reply(p, msg.ReplyCtx, sb.String())
// Build button rows (max 3 per row); use numeric index to stay within
// Telegram's 64-byte callback_data limit for long model names.
var buttons [][]ButtonOption
var row []ButtonOption
for i, m := range models {
label := m.Name
if m.Name == current {
label = "▶ " + label
}
row = append(row, ButtonOption{Text: label, Data: fmt.Sprintf("cmd:/model %d", i+1)})
if len(row) >= 3 {
buttons = append(buttons, row)
row = nil
}
}
if len(row) > 0 {
buttons = append(buttons, row)
}
e.replyWithButtons(p, msg.ReplyCtx, sb.String(), buttons)
return
}
@@ -1940,7 +1972,27 @@ func (e *Engine) cmdMode(p Platform, msg *Message, args []string) {
}
}
sb.WriteString(e.i18n.T(MsgModeUsage))
e.reply(p, msg.ReplyCtx, sb.String())
var buttons [][]ButtonOption
var row []ButtonOption
for _, m := range modes {
label := m.Name
if zhLike {
label = m.NameZh
}
if m.Key == current {
label = "▶ " + label
}
row = append(row, ButtonOption{Text: label, Data: "cmd:/mode " + m.Key})
if len(row) >= 2 {
buttons = append(buttons, row)
row = nil
}
}
if len(row) > 0 {
buttons = append(buttons, row)
}
e.replyWithButtons(p, msg.ReplyCtx, sb.String(), buttons)
return
}
@@ -2384,6 +2436,17 @@ func (e *Engine) reply(p Platform, replyCtx any, content string) {
}
}
// replyWithButtons sends a reply with inline buttons if the platform supports it,
// otherwise falls back to plain text reply.
func (e *Engine) replyWithButtons(p Platform, replyCtx any, content string, buttons [][]ButtonOption) {
if bs, ok := p.(InlineButtonSender); ok {
if err := bs.SendWithButtons(e.ctx, replyCtx, content, buttons); err == nil {
return
}
}
e.reply(p, replyCtx, content)
}
// ──────────────────────────────────────────────────────────────
// /memory command
// ──────────────────────────────────────────────────────────────
+36 -15
View File
@@ -258,7 +258,39 @@ func (p *Platform) handleCallbackQuery(cb *tgbotapi.CallbackQuery) {
answer := tgbotapi.NewCallback(cb.ID, "")
p.bot.Request(answer)
// Map callback data to permission response text
userName := cb.From.UserName
if userName == "" {
userName = strings.TrimSpace(cb.From.FirstName + " " + cb.From.LastName)
}
sessionKey := fmt.Sprintf("telegram:%d:%d", chatID, cb.From.ID)
rctx := replyContext{chatID: chatID, messageID: msgID}
// Command callbacks (cmd:/lang en, cmd:/mode yolo, etc.)
if strings.HasPrefix(data, "cmd:") {
command := strings.TrimPrefix(data, "cmd:")
// Edit original message: append the chosen option and remove buttons
origText := cb.Message.Text
if origText == "" {
origText = ""
}
edit := tgbotapi.NewEditMessageText(chatID, msgID, origText+"\n\n> "+command)
emptyMarkup := tgbotapi.NewInlineKeyboardMarkup()
edit.ReplyMarkup = &emptyMarkup
p.bot.Send(edit)
p.handler(p, &core.Message{
SessionKey: sessionKey,
Platform: "telegram",
UserID: userID,
UserName: userName,
Content: command,
ReplyCtx: rctx,
})
return
}
// Permission callbacks (perm:allow, perm:deny, perm:allow_all)
var responseText string
switch data {
case "perm:allow":
@@ -272,7 +304,6 @@ func (p *Platform) handleCallbackQuery(cb *tgbotapi.CallbackQuery) {
return
}
// Edit the original message to show the choice and remove buttons
choiceLabel := responseText
switch data {
case "perm:allow":
@@ -287,29 +318,19 @@ func (p *Platform) handleCallbackQuery(cb *tgbotapi.CallbackQuery) {
if origText == "" {
origText = "(permission request)"
}
editText := origText + "\n\n" + choiceLabel
edit := tgbotapi.NewEditMessageText(chatID, msgID, editText)
edit := tgbotapi.NewEditMessageText(chatID, msgID, origText+"\n\n"+choiceLabel)
emptyMarkup := tgbotapi.NewInlineKeyboardMarkup()
edit.ReplyMarkup = &emptyMarkup
p.bot.Send(edit)
// Route as a regular message to the engine's permission handler
userName := cb.From.UserName
if userName == "" {
userName = strings.TrimSpace(cb.From.FirstName + " " + cb.From.LastName)
}
sessionKey := fmt.Sprintf("telegram:%d:%d", chatID, cb.From.ID)
rctx := replyContext{chatID: chatID, messageID: msgID}
coreMsg := &core.Message{
p.handler(p, &core.Message{
SessionKey: sessionKey,
Platform: "telegram",
UserID: userID,
UserName: userName,
Content: responseText,
ReplyCtx: rctx,
}
p.handler(p, coreMsg)
})
}
// isDirectedAtBot checks whether a group message is directed at this bot: