feat: add /clear command to clear chat history (#1266)

* * add clear command to clear chat history

* check nil

* * update comment
This commit is contained in:
lxowalle 2026-03-09 16:39:33 +08:00 committed by GitHub
parent 82773fcd42
commit aaf99d7a30
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 49 additions and 13 deletions

View file

@ -581,15 +581,6 @@ func (al *AgentLoop) processMessage(ctx context.Context, msg bus.InboundMessage)
} }
route, agent, routeErr := al.resolveMessageRoute(msg) route, agent, routeErr := al.resolveMessageRoute(msg)
// Commands are checked before requiring a successful route.
// Global commands (/help, /show, /switch) work even when routing fails;
// context-dependent commands check their own Runtime fields and report
// "unavailable" when the required capability is nil.
if response, handled := al.handleCommand(ctx, msg, agent); handled {
return response, nil
}
if routeErr != nil { if routeErr != nil {
return "", routeErr return "", routeErr
} }
@ -615,7 +606,7 @@ func (al *AgentLoop) processMessage(ctx context.Context, msg bus.InboundMessage)
"route_channel": route.Channel, "route_channel": route.Channel,
}) })
return al.runAgentLoop(ctx, agent, processOptions{ opts := processOptions{
SessionKey: sessionKey, SessionKey: sessionKey,
Channel: msg.Channel, Channel: msg.Channel,
ChatID: msg.ChatID, ChatID: msg.ChatID,
@ -624,7 +615,15 @@ func (al *AgentLoop) processMessage(ctx context.Context, msg bus.InboundMessage)
DefaultResponse: defaultResponse, DefaultResponse: defaultResponse,
EnableSummary: true, EnableSummary: true,
SendResponse: false, SendResponse: false,
}) }
// context-dependent commands check their own Runtime fields and report
// "unavailable" when the required capability is nil.
if response, handled := al.handleCommand(ctx, msg, agent, &opts); handled {
return response, nil
}
return al.runAgentLoop(ctx, agent, opts)
} }
func (al *AgentLoop) resolveMessageRoute(msg bus.InboundMessage) (routing.ResolvedRoute, *AgentInstance, error) { func (al *AgentLoop) resolveMessageRoute(msg bus.InboundMessage) (routing.ResolvedRoute, *AgentInstance, error) {
@ -1682,6 +1681,7 @@ func (al *AgentLoop) handleCommand(
ctx context.Context, ctx context.Context,
msg bus.InboundMessage, msg bus.InboundMessage,
agent *AgentInstance, agent *AgentInstance,
opts *processOptions,
) (string, bool) { ) (string, bool) {
if !commands.HasCommandPrefix(msg.Content) { if !commands.HasCommandPrefix(msg.Content) {
return "", false return "", false
@ -1691,7 +1691,7 @@ func (al *AgentLoop) handleCommand(
return "", false return "", false
} }
rt := al.buildCommandsRuntime(agent) rt := al.buildCommandsRuntime(agent, opts)
executor := commands.NewExecutor(al.cmdRegistry, rt) executor := commands.NewExecutor(al.cmdRegistry, rt)
var commandReply string var commandReply string
@ -1720,7 +1720,7 @@ func (al *AgentLoop) handleCommand(
} }
} }
func (al *AgentLoop) buildCommandsRuntime(agent *AgentInstance) *commands.Runtime { func (al *AgentLoop) buildCommandsRuntime(agent *AgentInstance, opts *processOptions) *commands.Runtime {
rt := &commands.Runtime{ rt := &commands.Runtime{
Config: al.cfg, Config: al.cfg,
ListAgentIDs: al.registry.ListAgentIDs, ListAgentIDs: al.registry.ListAgentIDs,
@ -1750,6 +1750,20 @@ func (al *AgentLoop) buildCommandsRuntime(agent *AgentInstance) *commands.Runtim
agent.Model = value agent.Model = value
return oldModel, nil return oldModel, nil
} }
rt.ClearHistory = func() error {
if opts == nil {
return fmt.Errorf("process options not available")
}
if agent.Sessions == nil {
return fmt.Errorf("sessions not initialized for agent")
}
agent.Sessions.SetHistory(opts.SessionKey, make([]providers.Message, 0))
agent.Sessions.SetSummary(opts.SessionKey, "")
agent.Sessions.Save(opts.SessionKey)
return nil
}
} }
return rt return rt
} }

View file

@ -12,5 +12,6 @@ func BuiltinDefinitions() []Definition {
listCommand(), listCommand(),
switchCommand(), switchCommand(),
checkCommand(), checkCommand(),
clearCommand(),
} }
} }

20
pkg/commands/cmd_clear.go Normal file
View file

@ -0,0 +1,20 @@
package commands
import "context"
func clearCommand() Definition {
return Definition{
Name: "clear",
Description: "Clear the chat history",
Usage: "/clear",
Handler: func(_ context.Context, req Request, rt *Runtime) error {
if rt == nil || rt.ClearHistory == nil {
return req.Reply(unavailableMsg)
}
if err := rt.ClearHistory(); err != nil {
return req.Reply("Failed to clear chat history: " + err.Error())
}
return req.Reply("Chat history cleared!")
},
}
}

View file

@ -13,4 +13,5 @@ type Runtime struct {
GetEnabledChannels func() []string GetEnabledChannels func() []string
SwitchModel func(value string) (oldModel string, err error) SwitchModel func(value string) (oldModel string, err error)
SwitchChannel func(value string) error SwitchChannel func(value string) error
ClearHistory func() error
} }