fix(commands): guard nil Reply and update tests for unknown command behavior
- Add nil guard for req.Reply in Executor.Execute before calling it - Update TestShowListHandlers_ChannelPolicy to expect OutcomeHandled for unknown commands - Update TestProcessMessage_CommandOutcomes to verify unknown /foo and /new return error messages without LLM calls - Fix leftover double blank lines in whatsapp_native.go (fmt) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
f092429d15
commit
73df8f0848
5 changed files with 30 additions and 17 deletions
|
|
@ -1513,11 +1513,11 @@ func TestProcessMessage_CommandOutcomes(t *testing.T) {
|
||||||
Content: "/foo",
|
Content: "/foo",
|
||||||
Peer: baseMsg.Peer,
|
Peer: baseMsg.Peer,
|
||||||
})
|
})
|
||||||
if fooResp != "LLM reply" {
|
if fooResp != "Unknown command: foo" {
|
||||||
t.Fatalf("unexpected /foo reply: %q", fooResp)
|
t.Fatalf("unexpected /foo reply: %q", fooResp)
|
||||||
}
|
}
|
||||||
if provider.calls != 1 {
|
if provider.calls != 0 {
|
||||||
t.Fatalf("LLM should be called exactly once after /foo passthrough, calls=%d", provider.calls)
|
t.Fatalf("LLM should not be called for unknown command /foo, calls=%d", provider.calls)
|
||||||
}
|
}
|
||||||
|
|
||||||
newResp := helper.executeAndGetResponse(t, context.Background(), bus.InboundMessage{
|
newResp := helper.executeAndGetResponse(t, context.Background(), bus.InboundMessage{
|
||||||
|
|
@ -1527,11 +1527,11 @@ func TestProcessMessage_CommandOutcomes(t *testing.T) {
|
||||||
Content: "/new",
|
Content: "/new",
|
||||||
Peer: baseMsg.Peer,
|
Peer: baseMsg.Peer,
|
||||||
})
|
})
|
||||||
if newResp != "LLM reply" {
|
if newResp != "Unknown command: new" {
|
||||||
t.Fatalf("unexpected /new reply: %q", newResp)
|
t.Fatalf("unexpected /new reply: %q", newResp)
|
||||||
}
|
}
|
||||||
if provider.calls != 2 {
|
if provider.calls != 0 {
|
||||||
t.Fatalf("LLM should be called for passthrough /new command, calls=%d", provider.calls)
|
t.Fatalf("LLM should not be called for unknown command /new, calls=%d", provider.calls)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -454,7 +454,10 @@ func (c *WhatsAppNativeChannel) handleIncoming(evt *events.Message) {
|
||||||
"WhatsApp message blocked (not in allow_from)",
|
"WhatsApp message blocked (not in allow_from)",
|
||||||
map[string]any{"sender_id": senderID},
|
map[string]any{"sender_id": senderID},
|
||||||
)
|
)
|
||||||
_, _ = c.Send(c.runCtx, bus.OutboundMessage{Channel: "whatsapp", ChatID: chatID, Content: channels.ForbiddenReplyText})
|
_, _ = c.Send(
|
||||||
|
c.runCtx,
|
||||||
|
bus.OutboundMessage{Channel: "whatsapp", ChatID: chatID, Content: channels.ForbiddenReplyText},
|
||||||
|
)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -527,7 +530,6 @@ func isMentionedInGroup(msg *waE2E.Message, content string, botUsers []string) b
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// VoiceCapabilities reports that this channel supports ASR (speech-to-text).
|
// VoiceCapabilities reports that this channel supports ASR (speech-to-text).
|
||||||
func (c *WhatsAppNativeChannel) VoiceCapabilities() channels.VoiceCapabilities {
|
func (c *WhatsAppNativeChannel) VoiceCapabilities() channels.VoiceCapabilities {
|
||||||
return channels.VoiceCapabilities{ASR: true, TTS: false}
|
return channels.VoiceCapabilities{ASR: true, TTS: false}
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,10 @@ func (e *Executor) Execute(ctx context.Context, req Request) ExecuteResult {
|
||||||
def, found := e.reg.Lookup(cmdName)
|
def, found := e.reg.Lookup(cmdName)
|
||||||
if !found {
|
if !found {
|
||||||
// Return an error for unrecognized commands instead of forwarding to LLM
|
// Return an error for unrecognized commands instead of forwarding to LLM
|
||||||
err := req.Reply(fmt.Sprintf("Unknown command: %s", cmdName))
|
var err error
|
||||||
|
if req.Reply != nil {
|
||||||
|
err = req.Reply(fmt.Sprintf("Unknown command: %s", cmdName))
|
||||||
|
}
|
||||||
return ExecuteResult{Outcome: OutcomeHandled, Command: cmdName, Err: err}
|
return ExecuteResult{Outcome: OutcomeHandled, Command: cmdName, Err: err}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -88,4 +91,4 @@ func (e *Executor) executeDefinition(ctx context.Context, req Request, def Defin
|
||||||
// Unknown sub-command
|
// Unknown sub-command
|
||||||
err := req.Reply(fmt.Sprintf("Unknown option: %s. Usage: %s", subName, def.EffectiveUsage()))
|
err := req.Reply(fmt.Sprintf("Unknown option: %s. Usage: %s", subName, def.EffectiveUsage()))
|
||||||
return ExecuteResult{Outcome: OutcomeHandled, Command: def.Name, Err: err}
|
return ExecuteResult{Outcome: OutcomeHandled, Command: def.Name, Err: err}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,10 @@ func TestExecutor_UnknownSlashCommand_ReturnsError(t *testing.T) {
|
||||||
ex := NewExecutor(NewRegistry(defs), nil)
|
ex := NewExecutor(NewRegistry(defs), nil)
|
||||||
|
|
||||||
var reply string
|
var reply string
|
||||||
res := ex.Execute(context.Background(), Request{Channel: "telegram", Text: "/unknown", Reply: func(text string) error { reply = text; return nil }})
|
res := ex.Execute(
|
||||||
|
context.Background(),
|
||||||
|
Request{Channel: "telegram", Text: "/unknown", Reply: func(text string) error { reply = text; return nil }},
|
||||||
|
)
|
||||||
if res.Outcome != OutcomeHandled {
|
if res.Outcome != OutcomeHandled {
|
||||||
t.Fatalf("outcome=%v, want=%v", res.Outcome, OutcomeHandled)
|
t.Fatalf("outcome=%v, want=%v", res.Outcome, OutcomeHandled)
|
||||||
}
|
}
|
||||||
|
|
@ -267,4 +270,4 @@ func TestExecutor_SubCommand_NilHandler_ReturnsPassthrough(t *testing.T) {
|
||||||
if res.Outcome != OutcomePassthrough {
|
if res.Outcome != OutcomePassthrough {
|
||||||
t.Fatalf("outcome=%v, want=%v", res.Outcome, OutcomePassthrough)
|
t.Fatalf("outcome=%v, want=%v", res.Outcome, OutcomePassthrough)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -44,15 +44,20 @@ func TestShowListHandlers_ChannelPolicy(t *testing.T) {
|
||||||
t.Fatalf("whatsapp /show reply=%q, want=%q", whatsappReply, "Current Channel: whatsapp")
|
t.Fatalf("whatsapp /show reply=%q, want=%q", whatsappReply, "Current Channel: whatsapp")
|
||||||
}
|
}
|
||||||
|
|
||||||
passthrough := ex.Execute(context.Background(), Request{
|
var fooReply string
|
||||||
|
unknown := ex.Execute(context.Background(), Request{
|
||||||
Channel: "whatsapp",
|
Channel: "whatsapp",
|
||||||
Text: "/foo",
|
Text: "/foo",
|
||||||
|
Reply: func(text string) error { fooReply = text; return nil },
|
||||||
})
|
})
|
||||||
if passthrough.Outcome != OutcomePassthrough {
|
if unknown.Outcome != OutcomeHandled {
|
||||||
t.Fatalf("whatsapp /foo outcome=%v, want=%v", passthrough.Outcome, OutcomePassthrough)
|
t.Fatalf("whatsapp /foo outcome=%v, want=%v", unknown.Outcome, OutcomeHandled)
|
||||||
}
|
}
|
||||||
if passthrough.Command != "foo" {
|
if unknown.Command != "foo" {
|
||||||
t.Fatalf("whatsapp /foo command=%q, want=%q", passthrough.Command, "foo")
|
t.Fatalf("whatsapp /foo command=%q, want=%q", unknown.Command, "foo")
|
||||||
|
}
|
||||||
|
if fooReply != "Unknown command: foo" {
|
||||||
|
t.Fatalf("whatsapp /foo reply=%q, want=%q", fooReply, "Unknown command: foo")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue