fix(agent): restore generic command parity across channels

This commit is contained in:
mingmxren 2026-03-01 15:57:24 +08:00
parent 32638082cf
commit 72bf2e0901
4 changed files with 128 additions and 2 deletions

View file

@ -1329,6 +1329,10 @@ func (al *AgentLoop) handleCommand(
} }
oldModel := defaultAgent.Model oldModel := defaultAgent.Model
defaultAgent.Model = value defaultAgent.Model = value
if al.cfg != nil {
al.cfg.Agents.Defaults.ModelName = value
al.cfg.Agents.Defaults.Model = value
}
return fmt.Sprintf("Switched model from %s to %s", oldModel, value), true return fmt.Sprintf("Switched model from %s to %s", oldModel, value), true
case "channel": case "channel":
if al.channelManager == nil { if al.channelManager == nil {

View file

@ -715,6 +715,114 @@ func TestProcessMessage_CommandOutcomes(t *testing.T) {
} }
} }
func TestProcessMessage_CLI_SessionCommandsStillWork(t *testing.T) {
tmpDir, err := os.MkdirTemp("", "agent-test-*")
if err != nil {
t.Fatalf("Failed to create temp dir: %v", err)
}
defer os.RemoveAll(tmpDir)
cfg := &config.Config{
Agents: config.AgentsConfig{
Defaults: config.AgentDefaults{
Workspace: tmpDir,
Model: "test-model",
MaxTokens: 4096,
MaxToolIterations: 10,
},
},
Session: config.SessionConfig{
BacklogLimit: 20,
},
}
msgBus := bus.NewMessageBus()
provider := &countingMockProvider{response: "LLM reply"}
al := NewAgentLoop(cfg, msgBus, provider)
helper := testHelper{al: al}
newResp := helper.executeAndGetResponse(t, context.Background(), bus.InboundMessage{
Channel: "cli",
SenderID: "user1",
ChatID: "cli",
Content: "/new",
})
if !strings.Contains(newResp, "Started new session:") {
t.Fatalf("unexpected /new reply on cli: %q", newResp)
}
listResp := helper.executeAndGetResponse(t, context.Background(), bus.InboundMessage{
Channel: "cli",
SenderID: "user1",
ChatID: "cli",
Content: "/session list",
})
if !strings.Contains(listResp, "Sessions for current chat:") {
t.Fatalf("unexpected /session list reply on cli: %q", listResp)
}
if provider.calls != 0 {
t.Fatalf("LLM should not be called for handled cli session commands, calls=%d", provider.calls)
}
}
func TestProcessMessage_SwitchModelShowModelConsistency(t *testing.T) {
tmpDir, err := os.MkdirTemp("", "agent-test-*")
if err != nil {
t.Fatalf("Failed to create temp dir: %v", err)
}
defer os.RemoveAll(tmpDir)
cfg := &config.Config{
Agents: config.AgentsConfig{
Defaults: config.AgentDefaults{
Workspace: tmpDir,
Provider: "openai",
Model: "before-switch",
MaxTokens: 4096,
MaxToolIterations: 10,
},
},
}
msgBus := bus.NewMessageBus()
provider := &countingMockProvider{response: "LLM reply"}
al := NewAgentLoop(cfg, msgBus, provider)
helper := testHelper{al: al}
switchResp := helper.executeAndGetResponse(t, context.Background(), bus.InboundMessage{
Channel: "telegram",
SenderID: "user1",
ChatID: "chat1",
Content: "/switch model to after-switch",
Peer: bus.Peer{
Kind: "direct",
ID: "user1",
},
})
if !strings.Contains(switchResp, "Switched model from before-switch to after-switch") {
t.Fatalf("unexpected /switch reply: %q", switchResp)
}
showResp := helper.executeAndGetResponse(t, context.Background(), bus.InboundMessage{
Channel: "telegram",
SenderID: "user1",
ChatID: "chat1",
Content: "/show model",
Peer: bus.Peer{
Kind: "direct",
ID: "user1",
},
})
if !strings.Contains(showResp, "Current Model: after-switch (Provider: openai)") {
t.Fatalf("unexpected /show model reply after switch: %q", showResp)
}
if provider.calls != 0 {
t.Fatalf("LLM should not be called for /switch and /show, calls=%d", provider.calls)
}
}
// TestToolResult_SilentToolDoesNotSendUserMessage verifies silent tools don't trigger outbound // TestToolResult_SilentToolDoesNotSendUserMessage verifies silent tools don't trigger outbound
func TestToolResult_SilentToolDoesNotSendUserMessage(t *testing.T) { func TestToolResult_SilentToolDoesNotSendUserMessage(t *testing.T) {
tmpDir, err := os.MkdirTemp("", "agent-test-*") tmpDir, err := os.MkdirTemp("", "agent-test-*")

View file

@ -59,14 +59,14 @@ func builtinDefinitions(cfg *config.Config, runtime Runtime) []Definition {
Aliases: []string{"reset"}, Aliases: []string{"reset"},
Description: "Start a new chat session", Description: "Start a new chat session",
Usage: "/new", Usage: "/new",
Channels: []string{"telegram", "whatsapp", "whatsapp_native"}, Channels: nil,
Handler: newHandler, Handler: newHandler,
}, },
{ {
Name: "session", Name: "session",
Description: "Manage chat sessions", Description: "Manage chat sessions",
Usage: "/session [list|resume <index>]", Usage: "/session [list|resume <index>]",
Channels: []string{"telegram", "whatsapp", "whatsapp_native"}, Channels: nil,
Handler: sessionHandler, Handler: sessionHandler,
}, },
{ {

View file

@ -37,6 +37,20 @@ func TestBuiltinDefinitions_WhatsAppOnlyHasBasicCommands(t *testing.T) {
} }
} }
func TestBuiltinDefinitions_CLIHasSessionCommands(t *testing.T) {
defs := NewRegistry(BuiltinDefinitions(nil)).ForChannel("cli")
names := map[string]bool{}
for _, d := range defs {
names[d.Name] = true
}
if !names["new"] || !names["session"] {
t.Fatalf("cli should include new/session, got %+v", names)
}
if names["show"] || names["list"] {
t.Fatalf("cli should not include show/list, got %+v", names)
}
}
func TestBuiltinDefinitions_DefaultSessionCommandsArePassthrough(t *testing.T) { func TestBuiltinDefinitions_DefaultSessionCommandsArePassthrough(t *testing.T) {
defs := BuiltinDefinitions(nil) defs := BuiltinDefinitions(nil)