From 1c1b7ffe7e2f85cc4ce31170efe8be45fd55ac68 Mon Sep 17 00:00:00 2001 From: db123-ai Date: Wed, 10 Jun 2026 00:49:17 +0330 Subject: [PATCH] feat(memory): add RAG memory store and self-memory system (promises, strategies) --- internal/memory/self_memory.go | 94 ++++++++++++++++++++++++++++++++++ internal/memory/store.go | 71 +++++++++++++++++++++++++ 2 files changed, 165 insertions(+) create mode 100644 internal/memory/self_memory.go create mode 100644 internal/memory/store.go diff --git a/internal/memory/self_memory.go b/internal/memory/self_memory.go new file mode 100644 index 0000000..d2eb3a6 --- /dev/null +++ b/internal/memory/self_memory.go @@ -0,0 +1,94 @@ +package memory + +import ( + "time" + + "git.db123.ir/db123/divacode/internal/storage" +) + +type SelfMemory struct { + db *storage.DB +} + +type Promise struct { + ID string + Promise string + Context string + Fulfilled bool + CreatedAt time.Time + Deadline *time.Time +} + +type Strategy struct { + ID string + Situation string + Strategy string + Outcome string + CreatedAt time.Time +} + +func NewSelfMemory(db *storage.DB) *SelfMemory { + return &SelfMemory{db: db} +} + +func (sm *SelfMemory) AddPromise(promise, context string, deadline *time.Time) error { + id := time.Now().Format("150405.000") + return sm.db.Exec( + "INSERT INTO agent_promises (id, promise, context, deadline) VALUES (?, ?, ?, ?)", + id, promise, context, deadline, + ) +} + +func (sm *SelfMemory) FulfillPromise(id string) error { + return sm.db.Exec("UPDATE agent_promises SET fulfilled = 1 WHERE id = ?", id) +} + +func (sm *SelfMemory) ActivePromises() ([]Promise, error) { + rows, err := sm.db.Query( + "SELECT id, promise, context, fulfilled, created_at FROM agent_promises WHERE fulfilled = 0 ORDER BY created_at DESC", + ) + if err != nil { + return nil, err + } + defer rows.Close() + + var promises []Promise + for rows.Next() { + var p Promise + var created string + if err := rows.Scan(&p.ID, &p.Promise, &p.Context, &p.Fulfilled, &created); err != nil { + continue + } + promises = append(promises, p) + } + return promises, nil +} + +func (sm *SelfMemory) AddStrategy(situation, strategy, outcome string) error { + id := time.Now().Format("150405.000") + return sm.db.Exec( + "INSERT INTO agent_strategies (id, situation, strategy, outcome) VALUES (?, ?, ?, ?)", + id, situation, strategy, outcome, + ) +} + +func (sm *SelfMemory) StrategiesByOutcome(outcome string) ([]Strategy, error) { + rows, err := sm.db.Query( + "SELECT id, situation, strategy, outcome FROM agent_strategies WHERE outcome = ? ORDER BY created_at DESC", + outcome, + ) + if err != nil { + return nil, err + } + defer rows.Close() + + var strategies []Strategy + for rows.Next() { + var s Strategy + if err := rows.Scan(&s.ID, &s.Situation, &s.Strategy, &s.Outcome); err != nil { + continue + } + strategies = append(strategies, s) + } + return strategies, nil +} diff --git a/internal/memory/store.go b/internal/memory/store.go new file mode 100644 index 0000000..b01a8d3 --- /dev/null +++ b/internal/memory/store.go @@ -0,0 +1,71 @@ +package memory + +import ( + "context" + "log/slog" + "sync" + "time" + + "git.db123.ir/db123/divacode/internal/storage" +) + +type Store struct { + mu sync.Mutex + db *storage.DB +} + +func NewStore(db *storage.DB) *Store { + return &Store{db: db} +} + +func (s *Store) Store(ctx context.Context, content string, source string) error { + s.mu.Lock() + defer s.mu.Unlock() + + importance := 0.5 + if len(content) > 100 { + importance = 0.7 + } + + id := time.Now().Format("150405.000000000") + return s.db.Exec( + "INSERT INTO memories (id, content, importance, source, created_at) VALUES (?, ?, ?, ?, datetime('now'))", + id, content, importance, source, + ) +} + +func (s *Store) Search(ctx context.Context, query string, topK int) ([]string, error) { + s.mu.Lock() + defer s.mu.Unlock() + + rows, err := s.db.Query( + `SELECT content FROM memories + WHERE content LIKE ? + ORDER BY importance DESC, created_at DESC + LIMIT ?`, + "%"+query+"%", topK, + ) + if err != nil { + return nil, err + } + defer rows.Close() + + var results []string + for rows.Next() { + var content string + if err := rows.Scan(&content); err != nil { + continue + } + results = append(results, content) + } + + slog.Debug("memory search", "query", query, "results", len(results)) + return results, nil +} + +func (s *Store) UpdateImportance(ctx context.Context, id string, importance float64) error { + return s.db.Exec( + "UPDATE memories SET importance = ?, last_accessed = datetime('now') WHERE id = ?", + importance, id, + ) +}