revert: restore /show /list /switch as slash commands, hide from :help
The colon-prefix unification was not practical for these commands. Restore original /show, /list, /switch behavior and Telegram handlers. Remove them from :help output to keep the help text focused on colon commands. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
cd0ecff2e2
commit
cc3b58d9da
4 changed files with 217 additions and 116 deletions
|
|
@ -1151,7 +1151,12 @@ func (al *AgentLoop) estimateTokens(messages []providers.Message) int {
|
||||||
func (al *AgentLoop) handleCommand(ctx context.Context, msg bus.InboundMessage) (string, bool) {
|
func (al *AgentLoop) handleCommand(ctx context.Context, msg bus.InboundMessage) (string, bool) {
|
||||||
content := strings.TrimSpace(msg.Content)
|
content := strings.TrimSpace(msg.Content)
|
||||||
|
|
||||||
if !strings.HasPrefix(content, ":") {
|
// Handle : prefixed extension commands (work across all channels)
|
||||||
|
if strings.HasPrefix(content, ":") {
|
||||||
|
return al.handleExtensionCommand(content)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !strings.HasPrefix(content, "/") {
|
||||||
return "", false
|
return "", false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1163,6 +1168,91 @@ func (al *AgentLoop) handleCommand(ctx context.Context, msg bus.InboundMessage)
|
||||||
cmd := parts[0]
|
cmd := parts[0]
|
||||||
args := parts[1:]
|
args := parts[1:]
|
||||||
|
|
||||||
|
switch cmd {
|
||||||
|
case "/show":
|
||||||
|
if len(args) < 1 {
|
||||||
|
return "Usage: /show [model|channel|agents]", true
|
||||||
|
}
|
||||||
|
switch args[0] {
|
||||||
|
case "model":
|
||||||
|
defaultAgent := al.registry.GetDefaultAgent()
|
||||||
|
if defaultAgent == nil {
|
||||||
|
return "No default agent configured", true
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("Current model: %s", defaultAgent.Model), true
|
||||||
|
case "channel":
|
||||||
|
return fmt.Sprintf("Current channel: %s", msg.Channel), true
|
||||||
|
case "agents":
|
||||||
|
agentIDs := al.registry.ListAgentIDs()
|
||||||
|
return fmt.Sprintf("Registered agents: %s", strings.Join(agentIDs, ", ")), true
|
||||||
|
default:
|
||||||
|
return fmt.Sprintf("Unknown show target: %s", args[0]), true
|
||||||
|
}
|
||||||
|
|
||||||
|
case "/list":
|
||||||
|
if len(args) < 1 {
|
||||||
|
return "Usage: /list [models|channels|agents]", true
|
||||||
|
}
|
||||||
|
switch args[0] {
|
||||||
|
case "models":
|
||||||
|
return "Available models: configured in config.json per agent", true
|
||||||
|
case "channels":
|
||||||
|
if al.channelManager == nil {
|
||||||
|
return "Channel manager not initialized", true
|
||||||
|
}
|
||||||
|
channels := al.channelManager.GetEnabledChannels()
|
||||||
|
if len(channels) == 0 {
|
||||||
|
return "No channels enabled", true
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("Enabled channels: %s", strings.Join(channels, ", ")), true
|
||||||
|
case "agents":
|
||||||
|
agentIDs := al.registry.ListAgentIDs()
|
||||||
|
return fmt.Sprintf("Registered agents: %s", strings.Join(agentIDs, ", ")), true
|
||||||
|
default:
|
||||||
|
return fmt.Sprintf("Unknown list target: %s", args[0]), true
|
||||||
|
}
|
||||||
|
|
||||||
|
case "/switch":
|
||||||
|
if len(args) < 3 || args[1] != "to" {
|
||||||
|
return "Usage: /switch [model|channel] to <name>", true
|
||||||
|
}
|
||||||
|
target := args[0]
|
||||||
|
value := args[2]
|
||||||
|
|
||||||
|
switch target {
|
||||||
|
case "model":
|
||||||
|
defaultAgent := al.registry.GetDefaultAgent()
|
||||||
|
if defaultAgent == nil {
|
||||||
|
return "No default agent configured", true
|
||||||
|
}
|
||||||
|
oldModel := defaultAgent.Model
|
||||||
|
defaultAgent.Model = value
|
||||||
|
return fmt.Sprintf("Switched model from %s to %s", oldModel, value), true
|
||||||
|
case "channel":
|
||||||
|
if al.channelManager == nil {
|
||||||
|
return "Channel manager not initialized", true
|
||||||
|
}
|
||||||
|
if _, exists := al.channelManager.GetChannel(value); !exists && value != "cli" {
|
||||||
|
return fmt.Sprintf("Channel '%s' not found or not enabled", value), true
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("Switched target channel to %s", value), true
|
||||||
|
default:
|
||||||
|
return fmt.Sprintf("Unknown switch target: %s", target), true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
|
||||||
|
// handleExtensionCommand handles : prefixed commands that work across all channels.
|
||||||
|
func (al *AgentLoop) handleExtensionCommand(content string) (string, bool) {
|
||||||
|
parts := strings.Fields(content)
|
||||||
|
if len(parts) == 0 {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd := parts[0]
|
||||||
|
|
||||||
switch cmd {
|
switch cmd {
|
||||||
case ":cmd", ":pico", ":hipico", ":edit":
|
case ":cmd", ":pico", ":hipico", ":edit":
|
||||||
// Pass through to processMessage for mode handling (needs sessionKey from routing)
|
// Pass through to processMessage for mode handling (needs sessionKey from routing)
|
||||||
|
|
@ -1174,10 +1264,7 @@ func (al *AgentLoop) handleCommand(ctx context.Context, msg bus.InboundMessage)
|
||||||
:cmd - Switch to command mode (execute shell commands)
|
:cmd - Switch to command mode (execute shell commands)
|
||||||
:pico - Switch to chat mode (default, AI conversation)
|
:pico - Switch to chat mode (default, AI conversation)
|
||||||
:hipico <msg> - Ask AI for help (from command mode, one-shot)
|
:hipico <msg> - Ask AI for help (from command mode, one-shot)
|
||||||
:edit <file> - View/edit files (cmd mode)
|
:edit <file> - View/edit files (cmd mode)`, true
|
||||||
:show [model|channel|agents] - Show current configuration
|
|
||||||
:list [models|channels|agents] - List available options
|
|
||||||
:switch [model|channel] to <name> - Switch model or channel`, true
|
|
||||||
|
|
||||||
case ":usage":
|
case ":usage":
|
||||||
agent := al.registry.GetDefaultAgent()
|
agent := al.registry.GetDefaultAgent()
|
||||||
|
|
@ -1204,77 +1291,6 @@ Token usage (this session):
|
||||||
agent.TotalRequests.Load(),
|
agent.TotalRequests.Load(),
|
||||||
), true
|
), true
|
||||||
|
|
||||||
case ":show":
|
|
||||||
if len(args) < 1 {
|
|
||||||
return "Usage: :show [model|channel|agents]", true
|
|
||||||
}
|
|
||||||
switch args[0] {
|
|
||||||
case "model":
|
|
||||||
defaultAgent := al.registry.GetDefaultAgent()
|
|
||||||
if defaultAgent == nil {
|
|
||||||
return "No default agent configured", true
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("Current model: %s", defaultAgent.Model), true
|
|
||||||
case "channel":
|
|
||||||
return fmt.Sprintf("Current channel: %s", msg.Channel), true
|
|
||||||
case "agents":
|
|
||||||
agentIDs := al.registry.ListAgentIDs()
|
|
||||||
return fmt.Sprintf("Registered agents: %s", strings.Join(agentIDs, ", ")), true
|
|
||||||
default:
|
|
||||||
return fmt.Sprintf("Unknown show target: %s", args[0]), true
|
|
||||||
}
|
|
||||||
|
|
||||||
case ":list":
|
|
||||||
if len(args) < 1 {
|
|
||||||
return "Usage: :list [models|channels|agents]", true
|
|
||||||
}
|
|
||||||
switch args[0] {
|
|
||||||
case "models":
|
|
||||||
return "Available models: configured in config.json per agent", true
|
|
||||||
case "channels":
|
|
||||||
if al.channelManager == nil {
|
|
||||||
return "Channel manager not initialized", true
|
|
||||||
}
|
|
||||||
channels := al.channelManager.GetEnabledChannels()
|
|
||||||
if len(channels) == 0 {
|
|
||||||
return "No channels enabled", true
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("Enabled channels: %s", strings.Join(channels, ", ")), true
|
|
||||||
case "agents":
|
|
||||||
agentIDs := al.registry.ListAgentIDs()
|
|
||||||
return fmt.Sprintf("Registered agents: %s", strings.Join(agentIDs, ", ")), true
|
|
||||||
default:
|
|
||||||
return fmt.Sprintf("Unknown list target: %s", args[0]), true
|
|
||||||
}
|
|
||||||
|
|
||||||
case ":switch":
|
|
||||||
if len(args) < 3 || args[1] != "to" {
|
|
||||||
return "Usage: :switch [model|channel] to <name>", true
|
|
||||||
}
|
|
||||||
target := args[0]
|
|
||||||
value := args[2]
|
|
||||||
|
|
||||||
switch target {
|
|
||||||
case "model":
|
|
||||||
defaultAgent := al.registry.GetDefaultAgent()
|
|
||||||
if defaultAgent == nil {
|
|
||||||
return "No default agent configured", true
|
|
||||||
}
|
|
||||||
oldModel := defaultAgent.Model
|
|
||||||
defaultAgent.Model = value
|
|
||||||
return fmt.Sprintf("Switched model from %s to %s", oldModel, value), true
|
|
||||||
case "channel":
|
|
||||||
if al.channelManager == nil {
|
|
||||||
return "Channel manager not initialized", true
|
|
||||||
}
|
|
||||||
if _, exists := al.channelManager.GetChannel(value); !exists && value != "cli" {
|
|
||||||
return fmt.Sprintf("Channel '%s' not found or not enabled", value), true
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("Switched target channel to %s", value), true
|
|
||||||
default:
|
|
||||||
return fmt.Sprintf("Unknown switch target: %s", target), true
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// Don't intercept unrecognized : prefixed messages (e.g. :) :D :thinking:)
|
// Don't intercept unrecognized : prefixed messages (e.g. :) :D :thinking:)
|
||||||
// Let them pass through as normal chat messages
|
// Let them pass through as normal chat messages
|
||||||
|
|
|
||||||
|
|
@ -632,9 +632,9 @@ func TestAgentLoop_ContextExhaustionRetry(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestHandleCommand_EmojiPassthrough verifies that emoji-like
|
// TestHandleExtensionCommand_EmojiPassthrough verifies that emoji-like
|
||||||
// messages starting with : are not intercepted as commands.
|
// messages starting with : are not intercepted as commands.
|
||||||
func TestHandleCommand_EmojiPassthrough(t *testing.T) {
|
func TestHandleExtensionCommand_EmojiPassthrough(t *testing.T) {
|
||||||
cfg := &config.Config{
|
cfg := &config.Config{
|
||||||
Agents: config.AgentsConfig{
|
Agents: config.AgentsConfig{
|
||||||
Defaults: config.AgentDefaults{
|
Defaults: config.AgentDefaults{
|
||||||
|
|
@ -647,12 +647,10 @@ func TestHandleCommand_EmojiPassthrough(t *testing.T) {
|
||||||
msgBus := bus.NewMessageBus()
|
msgBus := bus.NewMessageBus()
|
||||||
provider := &mockProvider{}
|
provider := &mockProvider{}
|
||||||
al := NewAgentLoop(cfg, msgBus, provider)
|
al := NewAgentLoop(cfg, msgBus, provider)
|
||||||
ctx := context.Background()
|
|
||||||
|
|
||||||
emojiInputs := []string{":)", ":D", ":heart:", ":thinking:", ":-)", ":100:"}
|
emojiInputs := []string{":)", ":D", ":heart:", ":thinking:", ":-)", ":100:"}
|
||||||
for _, input := range emojiInputs {
|
for _, input := range emojiInputs {
|
||||||
msg := bus.InboundMessage{Content: input}
|
_, handled := al.handleExtensionCommand(input)
|
||||||
_, handled := al.handleCommand(ctx, msg)
|
|
||||||
if handled {
|
if handled {
|
||||||
t.Errorf("Expected %q to pass through (not handled), but it was handled", input)
|
t.Errorf("Expected %q to pass through (not handled), but it was handled", input)
|
||||||
}
|
}
|
||||||
|
|
@ -661,36 +659,9 @@ func TestHandleCommand_EmojiPassthrough(t *testing.T) {
|
||||||
// Known commands should still be handled
|
// Known commands should still be handled
|
||||||
knownCommands := []string{":help", ":usage"}
|
knownCommands := []string{":help", ":usage"}
|
||||||
for _, cmd := range knownCommands {
|
for _, cmd := range knownCommands {
|
||||||
msg := bus.InboundMessage{Content: cmd}
|
_, handled := al.handleExtensionCommand(cmd)
|
||||||
_, handled := al.handleCommand(ctx, msg)
|
|
||||||
if !handled {
|
if !handled {
|
||||||
t.Errorf("Expected %q to be handled, but it was not", cmd)
|
t.Errorf("Expected %q to be handled, but it was not", cmd)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// :show, :list, :switch should be handled
|
|
||||||
showMsg := bus.InboundMessage{Content: ":show model", Channel: "cli"}
|
|
||||||
resp, handled := al.handleCommand(ctx, showMsg)
|
|
||||||
if !handled {
|
|
||||||
t.Error("Expected :show model to be handled")
|
|
||||||
}
|
|
||||||
if resp != "Current model: test-model" {
|
|
||||||
t.Errorf("Unexpected :show model response: %s", resp)
|
|
||||||
}
|
|
||||||
|
|
||||||
listMsg := bus.InboundMessage{Content: ":list agents"}
|
|
||||||
_, handled = al.handleCommand(ctx, listMsg)
|
|
||||||
if !handled {
|
|
||||||
t.Error("Expected :list agents to be handled")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Non-: messages should not be handled
|
|
||||||
plainInputs := []string{"hello", "/show model", "ls -la"}
|
|
||||||
for _, input := range plainInputs {
|
|
||||||
msg := bus.InboundMessage{Content: input}
|
|
||||||
_, handled := al.handleCommand(ctx, msg)
|
|
||||||
if handled {
|
|
||||||
t.Errorf("Expected %q to not be handled, but it was", input)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -76,7 +76,7 @@ func NewTelegramChannel(cfg *config.Config, bus *bus.MessageBus) (*TelegramChann
|
||||||
|
|
||||||
return &TelegramChannel{
|
return &TelegramChannel{
|
||||||
BaseChannel: base,
|
BaseChannel: base,
|
||||||
commands: NewTelegramCommands(bot),
|
commands: NewTelegramCommands(bot, cfg),
|
||||||
bot: bot,
|
bot: bot,
|
||||||
config: cfg,
|
config: cfg,
|
||||||
chatIDs: make(map[string]int64),
|
chatIDs: make(map[string]int64),
|
||||||
|
|
@ -113,6 +113,14 @@ func (c *TelegramChannel) Start(ctx context.Context) error {
|
||||||
return c.commands.Start(ctx, message)
|
return c.commands.Start(ctx, message)
|
||||||
}, th.CommandEqual("start"))
|
}, th.CommandEqual("start"))
|
||||||
|
|
||||||
|
bh.HandleMessage(func(ctx *th.Context, message telego.Message) error {
|
||||||
|
return c.commands.Show(ctx, message)
|
||||||
|
}, th.CommandEqual("show"))
|
||||||
|
|
||||||
|
bh.HandleMessage(func(ctx *th.Context, message telego.Message) error {
|
||||||
|
return c.commands.List(ctx, message)
|
||||||
|
}, th.CommandEqual("list"))
|
||||||
|
|
||||||
bh.HandleMessage(func(ctx *th.Context, message telego.Message) error {
|
bh.HandleMessage(func(ctx *th.Context, message telego.Message) error {
|
||||||
return c.handleMessage(ctx, &message)
|
return c.handleMessage(ctx, &message)
|
||||||
}, th.AnyMessage())
|
}, th.AnyMessage())
|
||||||
|
|
|
||||||
|
|
@ -2,31 +2,46 @@ package channels
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/mymmrac/telego"
|
"github.com/mymmrac/telego"
|
||||||
|
|
||||||
|
"github.com/sipeed/picoclaw/pkg/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
type TelegramCommander interface {
|
type TelegramCommander interface {
|
||||||
Help(ctx context.Context, message telego.Message) error
|
Help(ctx context.Context, message telego.Message) error
|
||||||
Start(ctx context.Context, message telego.Message) error
|
Start(ctx context.Context, message telego.Message) error
|
||||||
|
Show(ctx context.Context, message telego.Message) error
|
||||||
|
List(ctx context.Context, message telego.Message) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type cmd struct {
|
type cmd struct {
|
||||||
bot *telego.Bot
|
bot *telego.Bot
|
||||||
|
config *config.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTelegramCommands(bot *telego.Bot) TelegramCommander {
|
func NewTelegramCommands(bot *telego.Bot, cfg *config.Config) TelegramCommander {
|
||||||
return &cmd{
|
return &cmd{
|
||||||
bot: bot,
|
bot: bot,
|
||||||
|
config: cfg,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func commandArgs(text string) string {
|
||||||
|
parts := strings.SplitN(text, " ", 2)
|
||||||
|
if len(parts) < 2 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return strings.TrimSpace(parts[1])
|
||||||
|
}
|
||||||
|
|
||||||
func (c *cmd) Help(ctx context.Context, message telego.Message) error {
|
func (c *cmd) Help(ctx context.Context, message telego.Message) error {
|
||||||
msg := `/start - Start the bot
|
msg := `/start - Start the bot
|
||||||
/help - Show this help message
|
/help - Show this help message
|
||||||
:show [model|channel|agents] - Show current configuration
|
/show [model|channel] - Show current configuration
|
||||||
:list [models|channels|agents] - List available options
|
/list [models|channels] - List available options
|
||||||
:switch [model|channel] to <name> - Switch model or channel
|
|
||||||
`
|
`
|
||||||
_, err := c.bot.SendMessage(ctx, &telego.SendMessageParams{
|
_, err := c.bot.SendMessage(ctx, &telego.SendMessageParams{
|
||||||
ChatID: telego.ChatID{ID: message.Chat.ID},
|
ChatID: telego.ChatID{ID: message.Chat.ID},
|
||||||
|
|
@ -48,3 +63,94 @@ func (c *cmd) Start(ctx context.Context, message telego.Message) error {
|
||||||
})
|
})
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *cmd) Show(ctx context.Context, message telego.Message) error {
|
||||||
|
args := commandArgs(message.Text)
|
||||||
|
if args == "" {
|
||||||
|
_, err := c.bot.SendMessage(ctx, &telego.SendMessageParams{
|
||||||
|
ChatID: telego.ChatID{ID: message.Chat.ID},
|
||||||
|
Text: "Usage: /show [model|channel]",
|
||||||
|
ReplyParameters: &telego.ReplyParameters{
|
||||||
|
MessageID: message.MessageID,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var response string
|
||||||
|
switch args {
|
||||||
|
case "model":
|
||||||
|
response = fmt.Sprintf("Current Model: %s (Provider: %s)",
|
||||||
|
c.config.Agents.Defaults.GetModelName(),
|
||||||
|
c.config.Agents.Defaults.Provider)
|
||||||
|
case "channel":
|
||||||
|
response = "Current Channel: telegram"
|
||||||
|
default:
|
||||||
|
response = fmt.Sprintf("Unknown parameter: %s. Try 'model' or 'channel'.", args)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := c.bot.SendMessage(ctx, &telego.SendMessageParams{
|
||||||
|
ChatID: telego.ChatID{ID: message.Chat.ID},
|
||||||
|
Text: response,
|
||||||
|
ReplyParameters: &telego.ReplyParameters{
|
||||||
|
MessageID: message.MessageID,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cmd) List(ctx context.Context, message telego.Message) error {
|
||||||
|
args := commandArgs(message.Text)
|
||||||
|
if args == "" {
|
||||||
|
_, err := c.bot.SendMessage(ctx, &telego.SendMessageParams{
|
||||||
|
ChatID: telego.ChatID{ID: message.Chat.ID},
|
||||||
|
Text: "Usage: /list [models|channels]",
|
||||||
|
ReplyParameters: &telego.ReplyParameters{
|
||||||
|
MessageID: message.MessageID,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var response string
|
||||||
|
switch args {
|
||||||
|
case "models":
|
||||||
|
provider := c.config.Agents.Defaults.Provider
|
||||||
|
if provider == "" {
|
||||||
|
provider = "configured default"
|
||||||
|
}
|
||||||
|
response = fmt.Sprintf("Configured Model: %s\nProvider: %s\n\nTo change models, update config.yaml",
|
||||||
|
c.config.Agents.Defaults.GetModelName(), provider)
|
||||||
|
|
||||||
|
case "channels":
|
||||||
|
var enabled []string
|
||||||
|
if c.config.Channels.Telegram.Enabled {
|
||||||
|
enabled = append(enabled, "telegram")
|
||||||
|
}
|
||||||
|
if c.config.Channels.WhatsApp.Enabled {
|
||||||
|
enabled = append(enabled, "whatsapp")
|
||||||
|
}
|
||||||
|
if c.config.Channels.Feishu.Enabled {
|
||||||
|
enabled = append(enabled, "feishu")
|
||||||
|
}
|
||||||
|
if c.config.Channels.Discord.Enabled {
|
||||||
|
enabled = append(enabled, "discord")
|
||||||
|
}
|
||||||
|
if c.config.Channels.Slack.Enabled {
|
||||||
|
enabled = append(enabled, "slack")
|
||||||
|
}
|
||||||
|
response = fmt.Sprintf("Enabled Channels:\n- %s", strings.Join(enabled, "\n- "))
|
||||||
|
|
||||||
|
default:
|
||||||
|
response = fmt.Sprintf("Unknown parameter: %s. Try 'models' or 'channels'.", args)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := c.bot.SendMessage(ctx, &telego.SendMessageParams{
|
||||||
|
ChatID: telego.ChatID{ID: message.Chat.ID},
|
||||||
|
Text: response,
|
||||||
|
ReplyParameters: &telego.ReplyParameters{
|
||||||
|
MessageID: message.MessageID,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue