- internal/llama/template.go: ChatML/Llama3 template engine with stop tokens - internal/agent/reasoning.go: parse <think>/<reasoning> tags from LLM output - companion/promptbuilder.go: output structured BuildResult, add date/time context - agent/agent.go: wire templates + reasoning split into message loop - storage: add reasoning TEXT column to messages table + migration - channel/tui.go: collapsible reasoning (tab toggle), mouse scroll, polished dimmed style - config: CHAT_TEMPLATE env var (chatml|llama3|none) - plan.md: mark Phase 2 complete, add themes TODO
124 lines
2.8 KiB
Go
124 lines
2.8 KiB
Go
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) (*BuildResult, 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)
|
|
|
|
result := 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 result, 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
|
|
}
|