feat(session): add configurable memory summarization thresholds

This commit is contained in:
easyzoom 2026-02-19 01:00:37 +08:00
parent 80c8b57533
commit 96fda2e090
3 changed files with 33 additions and 3 deletions

View file

@ -9,6 +9,11 @@
"max_tool_iterations": 20 "max_tool_iterations": 20
} }
}, },
"session": {
"memory_message_limit": 20,
"memory_token_percent": 75,
"memory_notify_user": false
},
"model_list": [ "model_list": [
{ {
"model_name": "gpt4", "model_name": "gpt4",

View file

@ -29,6 +29,11 @@ import (
"github.com/sipeed/picoclaw/pkg/utils" "github.com/sipeed/picoclaw/pkg/utils"
) )
const (
defaultMemoryMessageLimit = 20
defaultMemoryTokenPercent = 75
)
type AgentLoop struct { type AgentLoop struct {
bus *bus.MessageBus bus *bus.MessageBus
cfg *config.Config cfg *config.Config
@ -747,19 +752,35 @@ func (al *AgentLoop) updateToolContexts(agent *AgentInstance, channel, chatID st
func (al *AgentLoop) maybeSummarize(agent *AgentInstance, sessionKey, channel, chatID string) { func (al *AgentLoop) maybeSummarize(agent *AgentInstance, sessionKey, channel, chatID string) {
newHistory := agent.Sessions.GetHistory(sessionKey) newHistory := agent.Sessions.GetHistory(sessionKey)
tokenEstimate := al.estimateTokens(newHistory) tokenEstimate := al.estimateTokens(newHistory)
threshold := agent.ContextWindow * 75 / 100
if len(newHistory) > 20 || tokenEstimate > threshold { msgLimit := defaultMemoryMessageLimit
tokenPercent := defaultMemoryTokenPercent
notifyUser := false
if al.cfg != nil {
if al.cfg.Session.MemoryMessageLimit > 0 {
msgLimit = al.cfg.Session.MemoryMessageLimit
}
if al.cfg.Session.MemoryTokenPercent > 0 {
tokenPercent = al.cfg.Session.MemoryTokenPercent
}
notifyUser = al.cfg.Session.MemoryNotifyUser
}
threshold := agent.ContextWindow * tokenPercent / 100
if len(newHistory) > msgLimit || tokenEstimate > threshold {
summarizeKey := agent.ID + ":" + sessionKey summarizeKey := agent.ID + ":" + sessionKey
if _, loading := al.summarizing.LoadOrStore(summarizeKey, true); !loading { if _, loading := al.summarizing.LoadOrStore(summarizeKey, true); !loading {
go func() { go func() {
defer al.summarizing.Delete(summarizeKey) defer al.summarizing.Delete(summarizeKey)
if !constants.IsInternalChannel(channel) { if notifyUser && !constants.IsInternalChannel(channel) {
al.bus.PublishOutbound(bus.OutboundMessage{ al.bus.PublishOutbound(bus.OutboundMessage{
Channel: channel, Channel: channel,
ChatID: chatID, ChatID: chatID,
Content: "Memory threshold reached. Optimizing conversation history...", Content: "Memory threshold reached. Optimizing conversation history...",
}) })
} else if !constants.IsInternalChannel(channel) {
logger.InfoCF("agent", "Memory threshold reached, optimizing conversation history",
map[string]interface{}{"session_key": sessionKey})
} }
al.summarizeSession(agent, sessionKey) al.summarizeSession(agent, sessionKey)
}() }()

View file

@ -164,6 +164,10 @@ type AgentBinding struct {
type SessionConfig struct { type SessionConfig struct {
DMScope string `json:"dm_scope,omitempty"` DMScope string `json:"dm_scope,omitempty"`
IdentityLinks map[string][]string `json:"identity_links,omitempty"` IdentityLinks map[string][]string `json:"identity_links,omitempty"`
// Memory summarization: trigger when history exceeds message count or token percent of context window
MemoryMessageLimit int `json:"memory_message_limit,omitempty"` // default 20
MemoryTokenPercent int `json:"memory_token_percent,omitempty"` // default 75
MemoryNotifyUser bool `json:"memory_notify_user,omitempty"` // if true, send "Memory threshold reached..." to user; default false
} }
type AgentDefaults struct { type AgentDefaults struct {