diff --git a/pkg/agent/loop.go b/pkg/agent/loop.go index 8ad7070..aceba2f 100644 --- a/pkg/agent/loop.go +++ b/pkg/agent/loop.go @@ -1199,6 +1199,20 @@ func (al *AgentLoop) processSystemMessage(ctx context.Context, msg bus.InboundMe ) continue } + if strings.ToLower(strings.TrimSpace(msg.Metadata["trigger"])) == "heartbeat" { + al.sessions.ResetSession(sessionKey) + messages = al.contextBuilder.BuildMessages( + []providers.Message{}, + "", + msg.Content, + nil, + originChannel, + originChatID, + responseLang, + ) + logger.WarnCF("agent", "Heartbeat session reset after repeated provider pairing error", map[string]interface{}{"session_key": sessionKey}) + continue + } } logger.ErrorCF("agent", "LLM call failed in system message", map[string]interface{}{ diff --git a/pkg/autonomy/engine.go b/pkg/autonomy/engine.go index 7959d61..9efcfc2 100644 --- a/pkg/autonomy/engine.go +++ b/pkg/autonomy/engine.go @@ -1029,6 +1029,7 @@ func (e *Engine) persistStateLocked() { existingMap[it.ID] = it } items := make([]TaskItem, 0, len(e.state)) + built := map[string]struct{}{} for _, st := range e.state { status := "todo" switch st.Status { @@ -1056,6 +1057,7 @@ func (e *Engine) persistStateLocked() { if strings.TrimSpace(source) == "" { source = "memory_todo" } + built[st.ID] = struct{}{} items = append(items, TaskItem{ ID: st.ID, ParentTaskID: prev.ParentTaskID, @@ -1076,6 +1078,18 @@ func (e *Engine) persistStateLocked() { UpdatedAt: nowRFC3339(), }) } + for _, old := range existing { + if old.ID == "" { + continue + } + if _, ok := built[old.ID]; ok { + continue + } + st := strings.ToLower(strings.TrimSpace(old.Status)) + if st == "done" || st == "canceled" || st == "paused" { + items = append(items, old) + } + } _ = e.taskStore.Save(items) } diff --git a/pkg/session/manager.go b/pkg/session/manager.go index cab1e6b..cf79088 100644 --- a/pkg/session/manager.go +++ b/pkg/session/manager.go @@ -321,6 +321,24 @@ func (sm *SessionManager) rewriteSessionFileLocked(session *Session) error { return nil } +func (sm *SessionManager) ResetSession(key string) { + sm.mu.RLock() + session, ok := sm.sessions[key] + sm.mu.RUnlock() + if !ok { + return + } + session.mu.Lock() + session.Messages = []providers.Message{} + session.Summary = "" + session.Updated = time.Now() + if sm.storage != "" { + _ = sm.rewriteSessionFileLocked(session) + _ = sm.writeOpenClawSessionsIndex() + } + session.mu.Unlock() +} + func (sm *SessionManager) TruncateHistory(key string, keepLast int) { sm.mu.RLock() session, ok := sm.sessions[key]