task lifecycle + heartbeat resilience: preserve archived done tasks and reset heartbeat session on pairing-loop errors

This commit is contained in:
DBT
2026-03-02 10:31:31 +00:00
parent eb4f1dc82a
commit d2f680debb
3 changed files with 46 additions and 0 deletions

View File

@@ -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{}{

View File

@@ -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)
}

View File

@@ -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]