package companion import ( "log/slog" "sync" "git.db123.ir/db123/divacode/internal/storage" "git.db123.ir/db123/divacode/pkg/personality" ) type RelationshipEngine struct { mu sync.Mutex db *storage.DB } func NewRelationshipEngine(db *storage.DB) *RelationshipEngine { e := &RelationshipEngine{db: db} e.seed() return e } func (e *RelationshipEngine) seed() { defaults := map[string]float64{ "familiarity": 0.0, "trust": 0.3, } for metric, val := range defaults { err := e.db.Exec( "INSERT OR IGNORE INTO relationship_metrics (id, metric, value) VALUES (?, ?, ?)", "rel_"+metric, metric, val, ) if err != nil { slog.Warn("seed metric failed", "metric", metric, "error", err) } } } func (e *RelationshipEngine) Current() *personality.RelationshipMetrics { e.mu.Lock() defer e.mu.Unlock() rm := &personality.RelationshipMetrics{} row := e.db.QueryRow("SELECT value FROM relationship_metrics WHERE metric = 'familiarity'") row.Scan(&rm.Familiarity) row = e.db.QueryRow("SELECT value FROM relationship_metrics WHERE metric = 'trust'") row.Scan(&rm.Trust) topics, _ := e.db.Query("SELECT topic FROM shared_topics ORDER BY count DESC LIMIT 20") if topics != nil { defer topics.Close() for topics.Next() { var t string topics.Scan(&t) rm.SharedTopics = append(rm.SharedTopics, t) } } jokes, _ := e.db.Query("SELECT joke FROM inside_jokes LIMIT 20") if jokes != nil { defer jokes.Close() for jokes.Next() { var j string jokes.Scan(&j) rm.InsideJokes = append(rm.InsideJokes, j) } } return rm } func (e *RelationshipEngine) Trust() float64 { var v float64 err := e.db.QueryRow("SELECT value FROM relationship_metrics WHERE metric = 'trust'").Scan(&v) if err != nil { return 0.3 } return v } func (e *RelationshipEngine) UpdateFamiliarity(delta float64) error { return e.adjust("familiarity", delta) } func (e *RelationshipEngine) UpdateTrust(delta float64) error { return e.adjust("trust", delta) } func (e *RelationshipEngine) AddSharedTopic(topic string) error { return e.db.Exec( `INSERT INTO shared_topics (id, topic, count, last_discussed) VALUES (?, ?, 1, datetime('now')) ON CONFLICT(topic) DO UPDATE SET count = count + 1, last_discussed = datetime('now')`, "topic_"+topic, topic, ) } func (e *RelationshipEngine) adjust(metric string, delta float64) error { e.mu.Lock() defer e.mu.Unlock() var current float64 row := e.db.QueryRow("SELECT value FROM relationship_metrics WHERE metric = ?", metric) if err := row.Scan(¤t); err != nil { current = 0 } newVal := current + delta if newVal < 0 { newVal = 0 } if newVal > 1 { newVal = 1 } return e.db.Exec( "UPDATE relationship_metrics SET value = ?, updated_at = datetime('now') WHERE metric = ?", newVal, metric, ) }