mirror of
https://github.com/YspCoder/clawgo.git
synced 2026-05-07 18:07:39 +08:00
make sessions.json authoritative and remove legacy .meta files
This commit is contained in:
@@ -236,26 +236,11 @@ func (sm *SessionManager) TruncateHistory(key string, keepLast int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (sm *SessionManager) Save(session *Session) error {
|
func (sm *SessionManager) Save(session *Session) error {
|
||||||
// 现已通过 AddMessageFull 实时增量持久化
|
// Messages are persisted incrementally via AddMessageFull.
|
||||||
// 这里保留 Save 方法用于更新 Summary 等元数据
|
// Metadata is now centralized in sessions.json (OpenClaw-style index).
|
||||||
if sm.storage == "" {
|
if sm.storage == "" {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
metaPath := filepath.Join(sm.storage, session.Key+".meta")
|
|
||||||
meta := map[string]interface{}{
|
|
||||||
"session_id": session.SessionID,
|
|
||||||
"kind": session.Kind,
|
|
||||||
"summary": session.Summary,
|
|
||||||
"last_language": session.LastLanguage,
|
|
||||||
"preferred_language": session.PreferredLanguage,
|
|
||||||
"updated": session.Updated,
|
|
||||||
"created": session.Created,
|
|
||||||
}
|
|
||||||
data, _ := json.MarshalIndent(meta, "", " ")
|
|
||||||
if err := os.WriteFile(metaPath, data, 0644); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return sm.writeOpenClawSessionsIndex()
|
return sm.writeOpenClawSessionsIndex()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -412,7 +397,18 @@ func (sm *SessionManager) writeOpenClawSessionsIndex() error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return os.WriteFile(filepath.Join(sm.storage, "sessions.json"), data, 0644)
|
if err := os.WriteFile(filepath.Join(sm.storage, "sessions.json"), data, 0644); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// Cleanup legacy .meta files: sessions.json is source of truth now.
|
||||||
|
entries, _ := os.ReadDir(sm.storage)
|
||||||
|
for _, e := range entries {
|
||||||
|
if e.IsDir() || filepath.Ext(e.Name()) != ".meta" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
_ = os.Remove(filepath.Join(sm.storage, e.Name()))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func mapKindToChatType(kind string) string {
|
func mapKindToChatType(kind string) string {
|
||||||
@@ -427,71 +423,59 @@ func mapKindToChatType(kind string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (sm *SessionManager) loadSessions() error {
|
func (sm *SessionManager) loadSessions() error {
|
||||||
|
// 1) Load sessions index first (sessions.json as source of truth)
|
||||||
|
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"`
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal(data, &index); err == nil {
|
||||||
|
for key, row := range index {
|
||||||
|
session := sm.GetOrCreate(key)
|
||||||
|
session.mu.Lock()
|
||||||
|
if strings.TrimSpace(row.SessionID) != "" {
|
||||||
|
session.SessionID = row.SessionID
|
||||||
|
}
|
||||||
|
if strings.TrimSpace(row.Kind) != "" {
|
||||||
|
session.Kind = row.Kind
|
||||||
|
}
|
||||||
|
if row.UpdatedAt > 0 {
|
||||||
|
session.Updated = time.UnixMilli(row.UpdatedAt)
|
||||||
|
}
|
||||||
|
session.mu.Unlock()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2) Load JSONL histories
|
||||||
files, err := os.ReadDir(sm.storage)
|
files, err := os.ReadDir(sm.storage)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, file := range files {
|
for _, file := range files {
|
||||||
if file.IsDir() {
|
if file.IsDir() || filepath.Ext(file.Name()) != ".jsonl" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
sessionKey := strings.TrimSuffix(file.Name(), ".jsonl")
|
||||||
|
session := sm.GetOrCreate(sessionKey)
|
||||||
|
|
||||||
// 处理 JSONL 历史消息
|
f, err := os.Open(filepath.Join(sm.storage, file.Name()))
|
||||||
if filepath.Ext(file.Name()) == ".jsonl" {
|
if err != nil {
|
||||||
sessionKey := strings.TrimSuffix(file.Name(), ".jsonl")
|
continue
|
||||||
session := sm.GetOrCreate(sessionKey)
|
|
||||||
|
|
||||||
f, err := os.Open(filepath.Join(sm.storage, file.Name()))
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
scanner := bufio.NewScanner(f)
|
|
||||||
session.mu.Lock()
|
|
||||||
for scanner.Scan() {
|
|
||||||
if msg, ok := fromJSONLLine(scanner.Bytes()); ok {
|
|
||||||
session.Messages = append(session.Messages, msg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
session.mu.Unlock()
|
|
||||||
f.Close()
|
|
||||||
}
|
}
|
||||||
|
scanner := bufio.NewScanner(f)
|
||||||
// 处理元数据
|
session.mu.Lock()
|
||||||
if filepath.Ext(file.Name()) == ".meta" {
|
for scanner.Scan() {
|
||||||
sessionKey := strings.TrimSuffix(file.Name(), ".meta")
|
if msg, ok := fromJSONLLine(scanner.Bytes()); ok {
|
||||||
session := sm.GetOrCreate(sessionKey)
|
session.Messages = append(session.Messages, msg)
|
||||||
|
|
||||||
data, err := os.ReadFile(filepath.Join(sm.storage, file.Name()))
|
|
||||||
if err == nil {
|
|
||||||
var meta struct {
|
|
||||||
SessionID string `json:"session_id"`
|
|
||||||
Kind string `json:"kind"`
|
|
||||||
Summary string `json:"summary"`
|
|
||||||
LastLanguage string `json:"last_language"`
|
|
||||||
PreferredLanguage string `json:"preferred_language"`
|
|
||||||
Updated time.Time `json:"updated"`
|
|
||||||
Created time.Time `json:"created"`
|
|
||||||
}
|
|
||||||
if err := json.Unmarshal(data, &meta); err == nil {
|
|
||||||
session.SessionID = strings.TrimSpace(meta.SessionID)
|
|
||||||
if session.SessionID == "" {
|
|
||||||
session.SessionID = deriveSessionID(session.Key)
|
|
||||||
}
|
|
||||||
session.Kind = meta.Kind
|
|
||||||
if strings.TrimSpace(session.Kind) == "" {
|
|
||||||
session.Kind = detectSessionKind(session.Key)
|
|
||||||
}
|
|
||||||
session.Summary = meta.Summary
|
|
||||||
session.LastLanguage = meta.LastLanguage
|
|
||||||
session.PreferredLanguage = meta.PreferredLanguage
|
|
||||||
session.Updated = meta.Updated
|
|
||||||
session.Created = meta.Created
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
session.mu.Unlock()
|
||||||
|
f.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return sm.writeOpenClawSessionsIndex()
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user