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:
1 parent
8f630a0538
commit
0179d098ce
2 files changed
+102
-18
No files matched your search
+66
-3
@@ -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
|
||||
// ──────────────────────────────────────────────────────────────
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in new issue
Block a user