diff --git a/pkg/agent/loop.go b/pkg/agent/loop.go index 406ba35..1544fe4 100644 --- a/pkg/agent/loop.go +++ b/pkg/agent/loop.go @@ -475,6 +475,7 @@ func (al *AgentLoop) processMessage(ctx context.Context, msg bus.InboundMessage) Content: userContent, }) al.sessions.SetLastLanguage(msg.SessionKey, responseLang) + al.compactSessionIfNeeded(msg.SessionKey) al.sessions.Save(al.sessions.GetOrCreate(msg.SessionKey)) @@ -653,6 +654,7 @@ func (al *AgentLoop) processSystemMessage(ctx context.Context, msg bus.InboundMe Content: finalContent, }) al.sessions.SetLastLanguage(sessionKey, responseLang) + al.compactSessionIfNeeded(sessionKey) al.sessions.Save(al.sessions.GetOrCreate(sessionKey)) @@ -680,6 +682,32 @@ func truncate(s string, maxLen int) string { } // GetStartupInfo returns information about loaded tools and skills for logging. +func (al *AgentLoop) compactSessionIfNeeded(sessionKey string) { + if !al.compactionEnabled { + return + } + trigger := al.compactionTrigger + if trigger <= 0 { + trigger = 60 + } + keepRecent := al.compactionKeepRecent + if keepRecent <= 0 || keepRecent >= trigger { + keepRecent = trigger / 2 + if keepRecent < 10 { + keepRecent = 10 + } + } + h := al.sessions.GetHistory(sessionKey) + if len(h) <= trigger { + return + } + removed := len(h) - keepRecent + note := fmt.Sprintf("[runtime-compaction] removed %d old messages, kept %d recent messages", removed, keepRecent) + if al.sessions.CompactSession(sessionKey, keepRecent, note) { + al.sessions.Save(al.sessions.GetOrCreate(sessionKey)) + } +} + // RunStartupSelfCheckAllSessions runs startup compaction checks across loaded sessions. func (al *AgentLoop) RunStartupSelfCheckAllSessions(ctx context.Context) StartupCompactionReport { report := StartupCompactionReport{TotalSessions: al.sessions.Count()} @@ -712,17 +740,11 @@ func (al *AgentLoop) RunStartupSelfCheckAllSessions(ctx context.Context) Startup } removed := len(history) - keepRecent - summary := al.sessions.GetSummary(key) note := fmt.Sprintf("[startup-compaction] removed %d old messages, kept %d recent messages", removed, keepRecent) - if strings.TrimSpace(summary) == "" { - al.sessions.SetSummary(key, note) - } else { - al.sessions.SetSummary(key, summary+"\n"+note) + if al.sessions.CompactSession(key, keepRecent, note) { + al.sessions.Save(al.sessions.GetOrCreate(key)) + report.CompactedSessions++ } - - al.sessions.TruncateHistory(key, keepRecent) - al.sessions.Save(al.sessions.GetOrCreate(key)) - report.CompactedSessions++ } return report diff --git a/pkg/session/manager.go b/pkg/session/manager.go index 671264e..eeb8606 100644 --- a/pkg/session/manager.go +++ b/pkg/session/manager.go @@ -20,6 +20,7 @@ type Session struct { Kind string `json:"kind,omitempty"` Messages []providers.Message `json:"messages"` Summary string `json:"summary,omitempty"` + CompactionCount int `json:"compaction_count,omitempty"` LastLanguage string `json:"last_language,omitempty"` PreferredLanguage string `json:"preferred_language,omitempty"` Created time.Time `json:"created"` @@ -180,6 +181,32 @@ func (sm *SessionManager) SetSummary(key string, summary string) { } } +func (sm *SessionManager) CompactSession(key string, keepLast int, note string) bool { + sm.mu.RLock() + session, ok := sm.sessions[key] + sm.mu.RUnlock() + if !ok { + return false + } + + session.mu.Lock() + defer session.mu.Unlock() + if keepLast <= 0 || len(session.Messages) <= keepLast { + return false + } + session.Messages = session.Messages[len(session.Messages)-keepLast:] + session.CompactionCount++ + if strings.TrimSpace(note) != "" { + if strings.TrimSpace(session.Summary) == "" { + session.Summary = note + } else { + session.Summary += "\n" + note + } + } + session.Updated = time.Now() + return true +} + func (sm *SessionManager) GetLanguagePreferences(key string) (preferred string, last string) { sm.mu.RLock() session, ok := sm.sessions[key] @@ -271,6 +298,7 @@ func (sm *SessionManager) List(limit int) []Session { SessionID: s.SessionID, Kind: s.Kind, Summary: s.Summary, + CompactionCount: s.CompactionCount, LastLanguage: s.LastLanguage, PreferredLanguage: s.PreferredLanguage, Created: s.Created, @@ -388,7 +416,7 @@ func (sm *SessionManager) writeOpenClawSessionsIndex() error { "updatedAt": s.Updated.UnixMilli(), "systemSent": true, "abortedLastRun": false, - "compactionCount": 0, + "compactionCount": s.CompactionCount, "chatType": mapKindToChatType(s.Kind), "sessionFile": sessionFile, "kind": s.Kind, @@ -430,11 +458,12 @@ func (sm *SessionManager) loadSessions() error { indexPath := filepath.Join(sm.storage, "sessions.json") if data, err := os.ReadFile(indexPath); err == nil { var index map[string]struct { - SessionID string `json:"sessionId"` - SessionKey string `json:"sessionKey"` - UpdatedAt int64 `json:"updatedAt"` - Kind string `json:"kind"` - ChatType string `json:"chatType"` + SessionID string `json:"sessionId"` + SessionKey string `json:"sessionKey"` + UpdatedAt int64 `json:"updatedAt"` + Kind string `json:"kind"` + ChatType string `json:"chatType"` + CompactionCount int `json:"compactionCount"` } if err := json.Unmarshal(data, &index); err == nil { for key, row := range index { @@ -451,6 +480,7 @@ func (sm *SessionManager) loadSessions() error { if row.UpdatedAt > 0 { session.Updated = time.UnixMilli(row.UpdatedAt) } + session.CompactionCount = row.CompactionCount session.mu.Unlock() } }