yao/agent/memory/memory.go
Max 632c0f5674 Refactor Context Management to Use Memory Instead of Space
- Replaced all instances of `ctx.Space` with `ctx.Memory.Context` in the context management code, ensuring a more structured approach to handling temporary request-scoped data.
- Updated related test cases to reflect the changes in context memory usage, enhancing the reliability and clarity of tests.
- Removed the deprecated `Space` references and adjusted comments and documentation to align with the new memory management strategy.
2025-12-22 11:19:00 +08:00

185 lines
4 KiB
Go

package memory
import (
"fmt"
"time"
"github.com/yaoapp/gou/store"
)
// Default TTL values for each memory space
const (
DefaultUserTTL = 0 // No expiration for user-level memory
DefaultTeamTTL = 0 // No expiration for team-level memory
DefaultChatTTL = 24 * time.Hour // 24 hours for chat-level memory
DefaultContextTTL = 30 * time.Minute // 30 minutes for context-level memory
)
// New creates a new Memory instance with the given configuration and identifiers
func New(cfg *Config, userID, teamID, chatID, contextID string) (*Memory, error) {
if cfg == nil {
cfg = &Config{}
}
m := &Memory{
UserID: userID,
TeamID: teamID,
ChatID: chatID,
ContextID: contextID,
Config: cfg,
}
// Initialize user namespace
if userID != "" {
ns, err := newNamespace(SpaceUser, userID, cfg.User, DefaultUserTTL)
if err != nil {
return nil, fmt.Errorf("failed to create user namespace: %w", err)
}
m.User = ns
}
// Initialize team namespace
if teamID != "" {
ns, err := newNamespace(SpaceTeam, teamID, cfg.Team, DefaultTeamTTL)
if err != nil {
return nil, fmt.Errorf("failed to create team namespace: %w", err)
}
m.Team = ns
}
// Initialize chat namespace
if chatID != "" {
ns, err := newNamespace(SpaceChat, chatID, cfg.Chat, DefaultChatTTL)
if err != nil {
return nil, fmt.Errorf("failed to create chat namespace: %w", err)
}
m.Chat = ns
}
// Initialize context namespace
if contextID != "" {
ns, err := newNamespace(SpaceContext, contextID, cfg.Context, DefaultContextTTL)
if err != nil {
return nil, fmt.Errorf("failed to create context namespace: %w", err)
}
m.Context = ns
}
return m, nil
}
// newNamespace creates a new Namespace with the given parameters
func newNamespace(space Space, id, storeID string, defaultTTL time.Duration) (*Namespace, error) {
// Use default store ID if not specified
if storeID == "" {
switch space {
case SpaceUser:
storeID = DefaultUserStore
case SpaceTeam:
storeID = DefaultTeamStore
case SpaceChat:
storeID = DefaultChatStore
case SpaceContext:
storeID = DefaultContextStore
}
}
// Get store instance
s, err := store.Get(storeID)
if err != nil {
return nil, fmt.Errorf("failed to get store %s: %w", storeID, err)
}
return &Namespace{
Space: space,
ID: id,
Store: s,
StoreID: storeID,
Prefix: fmt.Sprintf("%s:%s:", space, id),
Default: defaultTTL,
}, nil
}
// GetUser returns the user-level memory namespace accessor
func (m *Memory) GetUser() NamespaceAccessor {
if m.User == nil {
return nil
}
return m.User
}
// GetTeam returns the team-level memory namespace accessor
func (m *Memory) GetTeam() NamespaceAccessor {
if m.Team == nil {
return nil
}
return m.Team
}
// GetChat returns the chat-level memory namespace accessor
func (m *Memory) GetChat() NamespaceAccessor {
if m.Chat == nil {
return nil
}
return m.Chat
}
// GetContext returns the context-level memory namespace accessor
func (m *Memory) GetContext() NamespaceAccessor {
if m.Context == nil {
return nil
}
return m.Context
}
// GetSpace returns a memory namespace by space type
func (m *Memory) GetSpace(space Space) NamespaceAccessor {
switch space {
case SpaceUser:
return m.GetUser()
case SpaceTeam:
return m.GetTeam()
case SpaceChat:
return m.GetChat()
case SpaceContext:
return m.GetContext()
default:
return nil
}
}
// GetStats returns memory statistics for all namespaces
func (m *Memory) GetStats() *Stats {
stats := &Stats{}
if m.User != nil {
stats.User = m.User.Stats()
}
if m.Team != nil {
stats.Team = m.Team.Stats()
}
if m.Chat != nil {
stats.Chat = m.Chat.Stats()
}
if m.Context != nil {
stats.Context = m.Context.Stats()
}
return stats
}
// Clear clears all memory in all namespaces for this memory instance
func (m *Memory) Clear() {
if m.User != nil {
m.User.Clear()
}
if m.Team != nil {
m.Team.Clear()
}
if m.Chat != nil {
m.Chat.Clear()
}
if m.Context != nil {
m.Context.Clear()
}
}