package companion import ( "context" "sync" "time" "git.db123.ir/db123/divacode/internal/config" "git.db123.ir/db123/divacode/internal/storage" "git.db123.ir/db123/divacode/pkg/personality" "git.db123.ir/db123/divacode/pkg/types" ) type PromptInput struct { UserMessage string RecentMessages []types.Message Memories []string } type Engine struct { mu sync.Mutex cfg *config.Config db *storage.DB personality *PersonalityEngine relationship *RelationshipEngine reflection *ReflectionEngine promptBuilder *PromptBuilder mood *MoodEngine lastContact time.Time pendingAutoMsg string } func NewEngine(cfg *config.Config, db *storage.DB) *Engine { return &Engine{ cfg: cfg, db: db, personality: NewPersonalityEngine(db), relationship: NewRelationshipEngine(db), reflection: NewReflectionEngine(db), promptBuilder: NewPromptBuilder(cfg), mood: NewMoodEngine(), lastContact: time.Now(), } } func (e *Engine) BuildPrompt(ctx context.Context, input *PromptInput) (string, error) { e.mu.Lock() defer e.mu.Unlock() traits := e.personality.Current() rel := e.relationship.Current() mood := e.mood.Current() observations := e.reflection.RecentObservations(5) prompt := e.promptBuilder.Build(&BuildInput{ SystemPrompt: e.cfg.SystemPrompt, Traits: traits, Relationship: rel, Mood: mood, Observations: observations, UserMessage: input.UserMessage, Memories: input.Memories, Messages: input.RecentMessages, }) e.lastContact = time.Now() return prompt, nil } func (e *Engine) WriteDiary(ctx context.Context) error { e.mu.Lock() defer e.mu.Unlock() return e.reflection.GenerateDiary(ctx, e.lastContact) } func (e *Engine) Mood() types.Mood { e.mu.Lock() defer e.mu.Unlock() return e.mood.Current() } func (e *Engine) Trust() float64 { e.mu.Lock() defer e.mu.Unlock() return e.relationship.Trust() } func (e *Engine) LastContactDuration() time.Duration { e.mu.Lock() defer e.mu.Unlock() return time.Since(e.lastContact) } func (e *Engine) QueueAutonomousMessage(msg string) { e.mu.Lock() defer e.mu.Unlock() e.pendingAutoMsg = msg } func (e *Engine) PopAutonomousMessage() string { e.mu.Lock() defer e.mu.Unlock() msg := e.pendingAutoMsg e.pendingAutoMsg = "" return msg } func (e *Engine) Personality() *PersonalityEngine { return e.personality } func (e *Engine) Relationship() *RelationshipEngine { return e.relationship } func (e *Engine) Reflection() *ReflectionEngine { return e.reflection } type BuildInput struct { SystemPrompt string Traits []personality.TraitValue Relationship *personality.RelationshipMetrics Mood types.Mood Observations []personality.Observation UserMessage string Memories []string Messages []types.Message }