refactor(channels): remove dead command parser remnants
This commit is contained in:
parent
15a1e7afdf
commit
9c610bc037
11 changed files with 17 additions and 340 deletions
|
|
@ -5,6 +5,8 @@ import (
|
|||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
|
|
|
|||
|
|
@ -48,10 +48,3 @@ type PlaceholderRecorder interface {
|
|||
type CommandRegistrarCapable interface {
|
||||
RegisterCommands(ctx context.Context, defs []commands.Definition) error
|
||||
}
|
||||
|
||||
// CommandParserCapable is implemented by channels that expose a command
|
||||
// dispatch entrypoint backed by shared command definitions/dispatcher.
|
||||
// It is optional and intended for cross-channel command handling features.
|
||||
type CommandParserCapable interface {
|
||||
DispatchCommand(ctx context.Context, req commands.Request) commands.Result
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,16 +11,6 @@ type mockRegistrar struct{}
|
|||
|
||||
func (mockRegistrar) RegisterCommands(context.Context, []commands.Definition) error { return nil }
|
||||
|
||||
type mockParser struct{}
|
||||
|
||||
func (mockParser) DispatchCommand(context.Context, commands.Request) commands.Result {
|
||||
return commands.Result{Matched: false}
|
||||
}
|
||||
|
||||
func TestCommandRegistrarCapable_Compiles(t *testing.T) {
|
||||
var _ CommandRegistrarCapable = mockRegistrar{}
|
||||
}
|
||||
|
||||
func TestCommandParserCapable_Compiles(t *testing.T) {
|
||||
var _ CommandParserCapable = mockParser{}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,8 +43,6 @@ type TelegramChannel struct {
|
|||
*channels.BaseChannel
|
||||
bot *telego.Bot
|
||||
bh *telegohandler.BotHandler
|
||||
commands TelegramCommander
|
||||
dispatcher commands.Dispatching
|
||||
config *config.Config
|
||||
chatIDs map[string]int64
|
||||
ctx context.Context
|
||||
|
|
@ -94,8 +92,6 @@ func NewTelegramChannel(cfg *config.Config, bus *bus.MessageBus) (*TelegramChann
|
|||
|
||||
return &TelegramChannel{
|
||||
BaseChannel: base,
|
||||
commands: NewTelegramCommands(bot, cfg),
|
||||
dispatcher: commands.NewDispatcher(commands.NewRegistry(commands.BuiltinDefinitions(cfg))),
|
||||
bot: bot,
|
||||
config: cfg,
|
||||
chatIDs: make(map[string]int64),
|
||||
|
|
@ -123,9 +119,6 @@ func (c *TelegramChannel) Start(ctx context.Context) error {
|
|||
c.bh = bh
|
||||
|
||||
bh.HandleMessage(func(ctx *th.Context, message telego.Message) error {
|
||||
if c.dispatchCommand(ctx, message) {
|
||||
return nil
|
||||
}
|
||||
return c.handleMessage(ctx, &message)
|
||||
}, th.AnyMessage())
|
||||
|
||||
|
|
|
|||
|
|
@ -1,154 +0,0 @@
|
|||
package telegram
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/mymmrac/telego"
|
||||
|
||||
"github.com/sipeed/picoclaw/pkg/commands"
|
||||
"github.com/sipeed/picoclaw/pkg/config"
|
||||
)
|
||||
|
||||
type TelegramCommander interface {
|
||||
Help(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 {
|
||||
bot *telego.Bot
|
||||
config *config.Config
|
||||
}
|
||||
|
||||
func NewTelegramCommands(bot *telego.Bot, cfg *config.Config) TelegramCommander {
|
||||
return &cmd{
|
||||
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 {
|
||||
defs := commands.NewRegistry(commands.BuiltinDefinitions(c.config)).ForChannel("telegram")
|
||||
msg := commands.FormatHelpMessage(defs)
|
||||
_, err := c.bot.SendMessage(ctx, &telego.SendMessageParams{
|
||||
ChatID: telego.ChatID{ID: message.Chat.ID},
|
||||
Text: msg,
|
||||
ReplyParameters: &telego.ReplyParameters{
|
||||
MessageID: message.MessageID,
|
||||
},
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *cmd) Start(ctx context.Context, message telego.Message) error {
|
||||
_, err := c.bot.SendMessage(ctx, &telego.SendMessageParams{
|
||||
ChatID: telego.ChatID{ID: message.Chat.ID},
|
||||
Text: "Hello! I am PicoClaw 🦞",
|
||||
ReplyParameters: &telego.ReplyParameters{
|
||||
MessageID: message.MessageID,
|
||||
},
|
||||
})
|
||||
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.json",
|
||||
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
|
||||
}
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
package telegram
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/mymmrac/telego"
|
||||
|
||||
"github.com/sipeed/picoclaw/pkg/commands"
|
||||
)
|
||||
|
||||
func (c *TelegramChannel) DispatchCommand(ctx context.Context, req commands.Request) commands.Result {
|
||||
if c.dispatcher == nil {
|
||||
return commands.Result{Matched: false}
|
||||
}
|
||||
return c.dispatcher.Dispatch(ctx, req)
|
||||
}
|
||||
|
||||
func (c *TelegramChannel) dispatchCommand(ctx context.Context, message telego.Message) bool {
|
||||
// Generic slash commands are now executed in the agent-centric command path.
|
||||
// Channel adapters must not consume them locally.
|
||||
return false
|
||||
}
|
||||
|
|
@ -9,34 +9,8 @@ import (
|
|||
|
||||
"github.com/sipeed/picoclaw/pkg/bus"
|
||||
"github.com/sipeed/picoclaw/pkg/channels"
|
||||
"github.com/sipeed/picoclaw/pkg/commands"
|
||||
)
|
||||
|
||||
func TestDispatchCommand_DoesNotConsumeGenericCommandsLocally(t *testing.T) {
|
||||
ch := &TelegramChannel{}
|
||||
called := false
|
||||
ch.dispatcher = commands.DispatchFunc(func(context.Context, commands.Request) commands.Result {
|
||||
called = true
|
||||
return commands.Result{Matched: true, Command: "noop"}
|
||||
})
|
||||
|
||||
msg := telego.Message{
|
||||
Text: "/help",
|
||||
MessageID: 7,
|
||||
Chat: telego.Chat{
|
||||
ID: 123,
|
||||
},
|
||||
}
|
||||
|
||||
handled := ch.dispatchCommand(context.Background(), msg)
|
||||
if handled {
|
||||
t.Fatalf("handled=%v", handled)
|
||||
}
|
||||
if called {
|
||||
t.Fatalf("handled=%v called=%v", handled, called)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleMessage_DoesNotConsumeGenericCommandsLocally(t *testing.T) {
|
||||
messageBus := bus.NewMessageBus()
|
||||
ch := &TelegramChannel{
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ import (
|
|||
|
||||
"github.com/sipeed/picoclaw/pkg/bus"
|
||||
"github.com/sipeed/picoclaw/pkg/channels"
|
||||
"github.com/sipeed/picoclaw/pkg/commands"
|
||||
"github.com/sipeed/picoclaw/pkg/config"
|
||||
"github.com/sipeed/picoclaw/pkg/identity"
|
||||
"github.com/sipeed/picoclaw/pkg/logger"
|
||||
|
|
@ -23,7 +22,6 @@ type WhatsAppChannel struct {
|
|||
conn *websocket.Conn
|
||||
config config.WhatsAppConfig
|
||||
url string
|
||||
dispatcher commands.Dispatching
|
||||
ctx context.Context
|
||||
cancel context.CancelFunc
|
||||
mu sync.Mutex
|
||||
|
|
@ -44,7 +42,6 @@ func NewWhatsAppChannel(cfg config.WhatsAppConfig, bus *bus.MessageBus) (*WhatsA
|
|||
BaseChannel: base,
|
||||
config: cfg,
|
||||
url: cfg.BridgeURL,
|
||||
dispatcher: commands.NewDispatcher(commands.NewRegistry(commands.BuiltinDefinitions(nil))),
|
||||
connected: false,
|
||||
}, nil
|
||||
}
|
||||
|
|
@ -251,25 +248,5 @@ func (c *WhatsAppChannel) handleIncomingMessage(msg map[string]any) {
|
|||
return
|
||||
}
|
||||
|
||||
if c.tryHandleCommand(c.ctx, content, chatID, senderID, messageID) {
|
||||
return
|
||||
}
|
||||
|
||||
c.HandleMessage(c.ctx, peer, messageID, senderID, chatID, content, mediaPaths, metadata, sender)
|
||||
}
|
||||
|
||||
func (c *WhatsAppChannel) tryHandleCommand(
|
||||
ctx context.Context,
|
||||
text, chatID, senderID, messageID string,
|
||||
) bool {
|
||||
// Generic slash commands are now executed in the agent-centric command path.
|
||||
// Channel adapters must not consume them locally.
|
||||
return false
|
||||
}
|
||||
|
||||
func (c *WhatsAppChannel) DispatchCommand(ctx context.Context, req commands.Request) commands.Result {
|
||||
if c.dispatcher == nil {
|
||||
return commands.Result{Matched: false}
|
||||
}
|
||||
return c.dispatcher.Dispatch(ctx, req)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,36 +7,13 @@ import (
|
|||
|
||||
"github.com/sipeed/picoclaw/pkg/bus"
|
||||
"github.com/sipeed/picoclaw/pkg/channels"
|
||||
"github.com/sipeed/picoclaw/pkg/commands"
|
||||
"github.com/sipeed/picoclaw/pkg/config"
|
||||
)
|
||||
|
||||
func TestTryHandleCommand_DoesNotConsumeGenericCommandsLocally(t *testing.T) {
|
||||
ch := &WhatsAppChannel{}
|
||||
called := false
|
||||
ch.dispatcher = commands.DispatchFunc(func(context.Context, commands.Request) commands.Result {
|
||||
called = true
|
||||
return commands.Result{Matched: true, Handled: true}
|
||||
})
|
||||
|
||||
handled := ch.tryHandleCommand(context.Background(), "/help", "chat1", "user1", "mid1")
|
||||
if handled {
|
||||
t.Fatalf("handled=%v", handled)
|
||||
}
|
||||
if called {
|
||||
t.Fatalf("handled=%v called=%v", handled, called)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleIncomingMessage_DoesNotConsumeGenericCommandsLocally(t *testing.T) {
|
||||
messageBus := bus.NewMessageBus()
|
||||
called := false
|
||||
ch := &WhatsAppChannel{
|
||||
BaseChannel: channels.NewBaseChannel("whatsapp", config.WhatsAppConfig{}, messageBus, nil),
|
||||
dispatcher: commands.DispatchFunc(func(context.Context, commands.Request) commands.Result {
|
||||
called = true
|
||||
return commands.Result{Matched: true, Handled: true}
|
||||
}),
|
||||
ctx: context.Background(),
|
||||
}
|
||||
|
||||
|
|
@ -48,10 +25,6 @@ func TestHandleIncomingMessage_DoesNotConsumeGenericCommandsLocally(t *testing.T
|
|||
"content": "/help",
|
||||
})
|
||||
|
||||
if called {
|
||||
t.Fatal("expected generic command dispatch to be bypassed")
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
|
||||
defer cancel()
|
||||
|
||||
|
|
|
|||
|
|
@ -14,36 +14,13 @@ import (
|
|||
|
||||
"github.com/sipeed/picoclaw/pkg/bus"
|
||||
"github.com/sipeed/picoclaw/pkg/channels"
|
||||
"github.com/sipeed/picoclaw/pkg/commands"
|
||||
"github.com/sipeed/picoclaw/pkg/config"
|
||||
)
|
||||
|
||||
func TestTryHandleCommand_DoesNotConsumeGenericCommandsLocally(t *testing.T) {
|
||||
ch := &WhatsAppNativeChannel{}
|
||||
called := false
|
||||
ch.dispatcher = commands.DispatchFunc(func(context.Context, commands.Request) commands.Result {
|
||||
called = true
|
||||
return commands.Result{Matched: true, Handled: true}
|
||||
})
|
||||
|
||||
handled := ch.tryHandleCommand(context.Background(), "/help", "chat1", "user1", "mid1")
|
||||
if handled {
|
||||
t.Fatalf("handled=%v", handled)
|
||||
}
|
||||
if called {
|
||||
t.Fatalf("handled=%v called=%v", handled, called)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleIncoming_DoesNotConsumeGenericCommandsLocally(t *testing.T) {
|
||||
messageBus := bus.NewMessageBus()
|
||||
called := false
|
||||
ch := &WhatsAppNativeChannel{
|
||||
BaseChannel: channels.NewBaseChannel("whatsapp_native", config.WhatsAppConfig{}, messageBus, nil),
|
||||
dispatcher: commands.DispatchFunc(func(context.Context, commands.Request) commands.Result {
|
||||
called = true
|
||||
return commands.Result{Matched: true, Handled: true}
|
||||
}),
|
||||
runCtx: context.Background(),
|
||||
}
|
||||
|
||||
|
|
@ -63,10 +40,6 @@ func TestHandleIncoming_DoesNotConsumeGenericCommandsLocally(t *testing.T) {
|
|||
|
||||
ch.handleIncoming(evt)
|
||||
|
||||
if called {
|
||||
t.Fatal("expected generic command dispatch to be bypassed")
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
|
||||
defer cancel()
|
||||
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@ import (
|
|||
|
||||
"github.com/sipeed/picoclaw/pkg/bus"
|
||||
"github.com/sipeed/picoclaw/pkg/channels"
|
||||
"github.com/sipeed/picoclaw/pkg/commands"
|
||||
"github.com/sipeed/picoclaw/pkg/config"
|
||||
"github.com/sipeed/picoclaw/pkg/identity"
|
||||
"github.com/sipeed/picoclaw/pkg/logger"
|
||||
|
|
@ -56,7 +55,6 @@ type WhatsAppNativeChannel struct {
|
|||
mu sync.Mutex
|
||||
runCtx context.Context
|
||||
runCancel context.CancelFunc
|
||||
dispatcher commands.Dispatching
|
||||
reconnectMu sync.Mutex
|
||||
reconnecting bool
|
||||
stopping atomic.Bool // set once Stop begins; prevents new wg.Add calls
|
||||
|
|
@ -78,7 +76,6 @@ func NewWhatsAppNativeChannel(
|
|||
BaseChannel: base,
|
||||
config: cfg,
|
||||
storePath: storePath,
|
||||
dispatcher: commands.NewDispatcher(commands.NewRegistry(commands.BuiltinDefinitions(nil))),
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
|
@ -390,9 +387,6 @@ func (c *WhatsAppNativeChannel) handleIncoming(evt *events.Message) {
|
|||
if !c.IsAllowedSender(sender) {
|
||||
return
|
||||
}
|
||||
if c.tryHandleCommand(c.runCtx, content, chatID, senderID, messageID) {
|
||||
return
|
||||
}
|
||||
|
||||
logger.DebugCF(
|
||||
"whatsapp",
|
||||
|
|
@ -402,22 +396,6 @@ func (c *WhatsAppNativeChannel) handleIncoming(evt *events.Message) {
|
|||
c.HandleMessage(c.runCtx, peer, messageID, senderID, chatID, content, mediaPaths, metadata, sender)
|
||||
}
|
||||
|
||||
func (c *WhatsAppNativeChannel) tryHandleCommand(
|
||||
ctx context.Context,
|
||||
text, chatID, senderID, messageID string,
|
||||
) bool {
|
||||
// Generic slash commands are now executed in the agent-centric command path.
|
||||
// Channel adapters must not consume them locally.
|
||||
return false
|
||||
}
|
||||
|
||||
func (c *WhatsAppNativeChannel) DispatchCommand(ctx context.Context, req commands.Request) commands.Result {
|
||||
if c.dispatcher == nil {
|
||||
return commands.Result{Matched: false}
|
||||
}
|
||||
return c.dispatcher.Dispatch(ctx, req)
|
||||
}
|
||||
|
||||
func (c *WhatsAppNativeChannel) Send(ctx context.Context, msg bus.OutboundMessage) error {
|
||||
if !c.IsRunning() {
|
||||
return channels.ErrNotRunning
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue