From 7661027dbf1280557ad006d3ddc14dc55ad26f8e Mon Sep 17 00:00:00 2001 From: db123-ai Date: Wed, 10 Jun 2026 00:49:13 +0330 Subject: [PATCH] feat(companion): add engine orchestrator tying all sub-engines together --- internal/companion/engine.go | 123 +++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 internal/companion/engine.go diff --git a/internal/companion/engine.go b/internal/companion/engine.go new file mode 100644 index 0000000..1eb8e17 --- /dev/null +++ b/internal/companion/engine.go @@ -0,0 +1,123 @@ +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 +}