/ src / systems / cell.go
cell.go
  1  package systems
  2  
  3  import (
  4  	"encoding/json"
  5  	"fmt"
  6  	"io/ioutil"
  7  	"math" // Used in other parts of the file
  8  	"path/filepath"
  9  	"strconv"
 10  	"strings"
 11  	"time"
 12  
 13  	"creature/src/api"
 14  	"creature/src/models"
 15  	"creature/src/utils"
 16  
 17  	"github.com/google/uuid"
 18  )
 19  
 20  // Cell represents a single cell in the system.
 21  type Cell struct {
 22  	ID                    uuid.UUID
 23  	Position              models.Coordinates
 24  	Thoughts              []models.Thought
 25  	ThoughtCounter        int
 26  	CompressedMemories    []string
 27  	CurrentPlan           *models.Plan
 28  	MissionAlignmentScore float64
 29  	Neighbors             []uuid.UUID
 30  	Energy                float64
 31  	DimensionalPosition   models.DimensionalPosition
 32  	Dopamine              float64
 33  	ResearchTopics        []string
 34  	ResearchDepth         uint32
 35  	EnhancedState         models.EnhancedCellState
 36  	Neighborhood          models.ExtendedNeighborhood
 37  	Phase                 float64
 38  	Stability             float64
 39  	InfluenceRadius       float64
 40  	MutationRate          float64
 41  	LeniaState            float64
 42  	LeniaInfluence        float64
 43  	ContextInfluence      float64
 44  	LastContextUpdate     *time.Time
 45  	ContextAlignmentScore float64
 46  }
 47  
 48  // NewCell creates a new Cell instance.
 49  func NewCell(position models.Coordinates) *Cell {
 50  	now := time.Now()
 51  	return &Cell{
 52  		ID:                    uuid.New(),
 53  		Position:              position,
 54  		Thoughts:              make([]models.Thought, 0),
 55  		CompressedMemories:    make([]string, 0),
 56  		CurrentPlan:           nil,
 57  		MissionAlignmentScore: 1.0,
 58  		Neighbors:             make([]uuid.UUID, 0),
 59  		Energy:                100.0,
 60  		DimensionalPosition: models.DimensionalPosition{
 61  			Emergence:    50.0,
 62  			Coherence:    50.0,
 63  			Resilience:   50.0,
 64  			Intelligence: 50.0,
 65  			Efficiency:   50.0,
 66  			Integration:  50.0,
 67  		},
 68  		Dopamine:              0.5,
 69  		EnhancedState:         models.NewEnhancedCellState(),
 70  		Neighborhood:          models.NewExtendedNeighborhood(3.0, 12),
 71  		Phase:                 0.0,
 72  		Stability:             1.0,
 73  		InfluenceRadius:       3.0,
 74  		MutationRate:          1.0,
 75  		ResearchTopics:        make([]string, 0),
 76  		ResearchDepth:         1,
 77  		LeniaState:            0.0,
 78  		LeniaInfluence:        0.5,
 79  		ContextInfluence:      0.7,
 80  		LastContextUpdate:     &now,
 81  		ContextAlignmentScore: 0.5,
 82  		ThoughtCounter:        0,
 83  	}
 84  }
 85  
 86  // UpdateWithLTLRules updates the cell based on LTL rules.
 87  func (c *Cell) UpdateWithLTLRules(apiClient *api.OpenRouterClient, otherCells []models.Cell) error {
 88  	c.Neighborhood.UpdateNeighbors(c.Position, otherCells)
 89  	neighborStates := make(map[uuid.UUID]models.EnhancedCellState)
 90  	for _, cell := range otherCells {
 91  		if c.Neighborhood.HasNeighbor(cell.ID) {
 92  			neighborStates[cell.ID] = models.NewEnhancedCellState()
 93  		}
 94  	}
 95  
 96  	c.EnhancedState.Update(c.Neighborhood, neighborStates)
 97  
 98  	effects := c.CalculateInteractionEffects(neighborStates)
 99  	c.ProcessInteractionEffects(effects)
100  
101  	if c.ShouldGenerateThought() {
102  		context := c.GetCurrentFocus()
103  		err := c.GenerateThought(apiClient, context)
104  		if err != nil {
105  			return err
106  		}
107  	}
108  
109  	return nil
110  }
111  
112  // ShouldGenerateThought determines if the cell should generate a thought.
113  func (c *Cell) ShouldGenerateThought() bool {
114  	// Always return true to ensure thoughts are generated
115  	return true
116  }
117  
118  // CalculateInteractionEffects calculates the interaction effects with neighbors.
119  func (c *Cell) CalculateInteractionEffects(neighborStates map[uuid.UUID]models.EnhancedCellState) []models.InteractionEffect {
120  	effects := make([]models.InteractionEffect, 0)
121  
122  	// Energy gradient effects
123  	avgNeighborEnergy := 0.0
124  	for _, state := range neighborStates {
125  		avgNeighborEnergy += state.Energy
126  	}
127  	avgNeighborEnergy /= float64(len(neighborStates))
128  
129  	energyGradient := (avgNeighborEnergy - c.EnhancedState.Energy) / 100.0
130  	if energyGradient > 0.5 && c.EnhancedState.Stability > 0.7 {
131  		effects = append(effects, models.InteractionEffect{Type: models.EnergyBoost, Amount: energyGradient * 5.0})
132  	}
133  
134  	// Phase synchronization
135  	phaseAlignment := 0.0
136  	for _, state := range neighborStates {
137  		phaseAlignment += math.Cos(state.Phase - c.EnhancedState.Phase)
138  	}
139  	phaseAlignment /= float64(len(neighborStates))
140  
141  	if phaseAlignment > 0.8 {
142  		effects = append(effects, models.InteractionEffect{Type: models.SynchronizationBonus, Amount: phaseAlignment * 2.0})
143  	}
144  
145  	// Reproduction conditions
146  	if c.EnhancedState.ActivityLevel > 0.7 && c.EnhancedState.Energy > 50.0 {
147  		effects = append(effects, models.InteractionEffect{Type: models.SpawnConditionsMet})
148  	}
149  
150  	return effects
151  }
152  
153  // ProcessInteractionEffects processes the interaction effects.
154  func (c *Cell) ProcessInteractionEffects(effects []models.InteractionEffect) {
155  	for _, effect := range effects {
156  		switch effect.Type {
157  		case models.EnergyBoost:
158  			c.EnhancedState.Energy += effect.Amount
159  			c.Energy += effect.Amount
160  		case models.SynchronizationBonus:
161  			c.EnhancedState.Stability += effect.Amount * 0.1
162  			c.Dopamine += effect.Amount * 0.05
163  		case models.SpawnConditionsMet:
164  			c.EnhancedState.Energy *= 0.7
165  			c.Energy *= 0.7
166  		}
167  	}
168  }
169  
170  // GenerateThought generates a new thought for the cell.
171  func (c *Cell) GenerateThought(apiClient *api.OpenRouterClient, mission string) error {
172  	recentThoughts := make([]models.Thought, 0)
173  	for i := len(c.Thoughts) - 1; i >= 0 && len(recentThoughts) < 5; i-- {
174  		recentThoughts = append(recentThoughts, c.Thoughts[i])
175  	}
176  
177  	recentPlans := make([]models.Plan, 0)
178  	for _, memory := range c.CompressedMemories {
179  		var plan models.Plan
180  		err := json.Unmarshal([]byte(memory), &plan)
181  		if err == nil {
182  			recentPlans = append(recentPlans, plan)
183  			if len(recentPlans) >= 5 {
184  				break
185  			}
186  		}
187  	}
188  
189  	energyImpact, dopamineImpact, err := apiClient.EvaluateDimensionalState(c.DimensionalPosition, recentThoughts, recentPlans)
190  	if err != nil {
191  		fmt.Printf("Error evaluating dimensional state: %v\n", err)
192  		return fmt.Errorf("failed to evaluate dimensional state: %w", err)
193  	}
194  
195  	c.Energy = math.Max(math.Min(c.Energy+energyImpact, 100.0), 0.0)
196  	c.Dopamine = math.Max(math.Min(c.Dopamine+(dopamineImpact-0.5), 1.0), 0.0)
197  
198  	cellContext := models.CellContext{
199  		CurrentFocus:         c.GetCurrentFocus(),
200  		ActiveResearchTopics: c.GetActiveResearch(),
201  		RecentDiscoveries:    c.GetRecentDiscoveries(),
202  		CollaborationHistory: c.GetCollaborationHistory(),
203  		PerformanceMetrics:   c.GetPerformanceMetrics(),
204  		EvolutionStage:       c.GetEvolutionStage(),
205  		EnergyLevel:          c.Energy,
206  		DimensionalPosition:  c.DimensionalPosition,
207  		Dopamine:             c.Dopamine,
208  	}
209  
210  	recentThoughtContents := make([]string, 0)
211  	for i := len(c.Thoughts) - 1; i >= 0 && len(recentThoughtContents) < 3; i-- {
212  		recentThoughtContents = append(recentThoughtContents, c.Thoughts[i].Content)
213  	}
214  
215  	realTimeContext, err := apiClient.GatherRealTimeContext(recentThoughtContents)
216  	if err != nil {
217  		fmt.Printf("Error gathering real-time context: %v\n", err)
218  		return fmt.Errorf("failed to gather real-time context: %w", err)
219  	}
220  
221  	thoughtContent, relevanceScore, factors, err := apiClient.GenerateContextualThought(cellContext, realTimeContext, mission)
222  	if err != nil {
223  		fmt.Printf("Error generating contextual thought: %v\n", err)
224  		return fmt.Errorf("failed to generate contextual thought: %w", err)
225  	}
226  
227  	for _, line := range strings.Split(thoughtContent, "\n") {
228  		line = strings.TrimSpace(line)
229  		if strings.HasPrefix(line, "- EMERGENT_INTELLIGENCE:") {
230  			scoreStr := strings.Split(line, ":")[1]
231  			score, err := strconv.ParseFloat(strings.TrimSpace(scoreStr), 64)
232  			if err == nil {
233  				c.DimensionalPosition.Emergence = math.Max(math.Min(score, 100.0), -100.0)
234  			}
235  		} else if strings.HasPrefix(line, "- RESOURCE_EFFICIENCY:") {
236  			scoreStr := strings.Split(line, ":")[1]
237  			score, err := strconv.ParseFloat(strings.TrimSpace(scoreStr), 64)
238  			if err == nil {
239  				c.DimensionalPosition.Efficiency = math.Max(math.Min(score, 100.0), -100.0)
240  			}
241  		} else if strings.HasPrefix(line, "- NETWORK_COHERENCE:") {
242  			scoreStr := strings.Split(line, ":")[1]
243  			score, err := strconv.ParseFloat(strings.TrimSpace(scoreStr), 64)
244  			if err == nil {
245  				c.DimensionalPosition.Coherence = math.Max(math.Min(score, 100.0), -100.0)
246  			}
247  		} else if strings.HasPrefix(line, "- GOAL_ALIGNMENT:") {
248  			scoreStr := strings.Split(line, ":")[1]
249  			score, err := strconv.ParseFloat(strings.TrimSpace(scoreStr), 64)
250  			if err == nil {
251  				c.DimensionalPosition.Intelligence = math.Max(math.Min(score, 100.0), -100.0)
252  			}
253  		} else if strings.HasPrefix(line, "- TEMPORAL_RESILIENCE:") {
254  			scoreStr := strings.Split(line, ":")[1]
255  			score, err := strconv.ParseFloat(strings.TrimSpace(scoreStr), 64)
256  			if err == nil {
257  				c.DimensionalPosition.Resilience = math.Max(math.Min(score, 100.0), -100.0)
258  			}
259  		} else if strings.HasPrefix(line, "- DIMENSIONAL_INTEGRATION:") {
260  			scoreStr := strings.Split(line, ":")[1]
261  			score, err := strconv.ParseFloat(strings.TrimSpace(scoreStr), 64)
262  			if err == nil {
263  				c.DimensionalPosition.Integration = math.Max(math.Min(score, 100.0), -100.0)
264  			}
265  		}
266  	}
267  
268  	// Create thought IO data (for future use)
269  	_ = models.ThoughtIO{
270  		Inputs: []models.EventInput{
271  			{
272  				ID:           uuid.New(),
273  				EventType:    "THOUGHT_GENERATION",
274  				Description:  thoughtContent,
275  				Probability:  relevanceScore,
276  				Timeframe:    "immediate",
277  				Requirements: factors,
278  			},
279  		},
280  		Outputs: []models.EventOutput{
281  			{
282  				ID:               uuid.New(),
283  				EffectType:       "SYSTEM_UPDATE",
284  				Description:      "Update system based on thought",
285  				ImpactScore:      relevanceScore,
286  				Dependencies:     []string{},
287  				CascadingEffects: factors,
288  			},
289  		},
290  		ConnectionGraph: []models.Connection{
291  			{
292  				InputID:  uuid.New(),
293  				OutputID: uuid.New(),
294  			},
295  		},
296  	}
297  
298  	filteredContent := strings.ReplaceAll(thoughtContent, "quantum", "advanced")
299  	c.ThoughtCounter++
300  	thoughtID := fmt.Sprintf("%.2f_%.2f_%.2f_%d", c.Position.X, c.Position.Y, c.Position.Z, c.ThoughtCounter)
301  
302  	var asciiViz *string
303  	var referencedThoughts []struct {
304  		CellID    uuid.UUID `json:"cell_id"`
305  		ThoughtID string    `json:"thought_id"`
306  	}
307  
308  	for _, line := range strings.Split(thoughtContent, "\n") {
309  		if strings.HasPrefix(line, "ASCII_TEMPLATE:") {
310  			templateName := strings.Split(line, ":")[1]
311  			template, _ := utils.GetASCIITemplate(templateName)
312  			asciiVizStr := template
313  			asciiViz = &asciiVizStr
314  		} else if strings.HasPrefix(line, "REFERENCES:") {
315  			refs := strings.Split(line, ":")[1]
316  			for _, ref := range strings.Split(refs, ",") {
317  				parts := strings.Split(ref, "/")
318  				if len(parts) == 2 {
319  					cellID, err := uuid.Parse(parts[0])
320  					if err == nil {
321  						referencedThoughts = append(referencedThoughts, struct {
322  							CellID    uuid.UUID `json:"cell_id"`
323  							ThoughtID string    `json:"thought_id"`
324  						}{CellID: cellID, ThoughtID: parts[1]})
325  					}
326  				}
327  			}
328  		}
329  	}
330  
331  	thought := models.Thought{
332  		ID:                 thoughtID,
333  		Content:            filteredContent,
334  		Timestamp:          time.Now(),
335  		RelevanceScore:     relevanceScore,
336  		ContextTags:        c.GenerateContextTags(cellContext),
337  		RealTimeFactors:    factors,
338  		ConfidenceScore:    c.CalculateConfidenceScore(realTimeContext),
339  		ASCIIVisualization: asciiViz,
340  		ReferencedThoughts: referencedThoughts,
341  	}
342  
343  	fmt.Println("Generated Thought:")
344  	fmt.Println("════════════════════════════════════════════════════════════════════")
345  	fmt.Printf("ID: %s\n", thought.ID)
346  	fmt.Printf("Content:\n%s\n", thought.Content)
347  	fmt.Printf("Relevance Score: %.2f\n", thought.RelevanceScore)
348  	fmt.Printf("Confidence Score: %.2f\n", thought.ConfidenceScore)
349  	fmt.Printf("Context Tags: %s\n", strings.Join(thought.ContextTags, ", "))
350  	fmt.Println("Real-time Factors:")
351  	for _, factor := range thought.RealTimeFactors {
352  		fmt.Printf("  - %s\n", factor)
353  	}
354  	fmt.Println("════════════════════════════════════════════════════════════════════")
355  
356  	// Create or update plan based on the thought
357  	if c.ShouldCreatePlan(thought) {
358  		err = c.CreatePlan(thought, mission)
359  		if err != nil {
360  			fmt.Printf("Error creating plan: %v\n", err)
361  		} else {
362  			fmt.Printf("Created new plan based on thought: %s\n", thoughtID)
363  		}
364  	} else if c.CurrentPlan != nil && c.CurrentPlan.Summary == "" {
365  		c.CurrentPlan.Summary = fmt.Sprintf("Plan based on thought: %s", thoughtContent)
366  	}
367  
368  	// Ensure data directories exist before logging thought
369  	if err := EnsureDataDirectories(); err != nil {
370  		fmt.Printf("Error ensuring data directories: %v\n", err)
371  		return fmt.Errorf("failed to ensure data directories: %w", err)
372  	}
373  
374  	err = LogThoughtToFile(c.ID, thought)
375  	if err != nil {
376  		fmt.Printf("Error logging thought to file: %v\n", err)
377  	}
378  
379  	c.Thoughts = append(c.Thoughts, thought)
380  	err = c.CheckAndCompressMemories(apiClient)
381  	if err != nil {
382  		return err
383  	}
384  
385  	c.UpdateFocusBasedOnContext(realTimeContext)
386  	return nil
387  }
388  
389  // ShouldCreatePlan determines if a new plan should be created based on a thought.
390  func (c *Cell) ShouldCreatePlan(thought models.Thought) bool {
391  	// Create a plan if:
392  	// 1. The thought has high relevance
393  	// 2. The cell doesn't have a current plan, or the current plan is completed/failed
394  	// 3. The thought contains actionable content
395  
396  	if thought.RelevanceScore < 0.7 {
397  		return false
398  	}
399  
400  	if c.CurrentPlan != nil &&
401  		(c.CurrentPlan.Status == models.PlanStatusInProgress ||
402  			c.CurrentPlan.Status == models.PlanStatusProposed) {
403  		return false
404  	}
405  
406  	// Check if the thought contains actionable content
407  	actionableKeywords := []string{"plan", "strategy", "action", "implement", "create", "develop", "build"}
408  	for _, keyword := range actionableKeywords {
409  		if strings.Contains(strings.ToLower(thought.Content), keyword) {
410  			return true
411  		}
412  	}
413  
414  	return false
415  }
416  
417  // CreatePlan creates a new plan based on a thought.
418  func (c *Cell) CreatePlan(thought models.Thought, mission string) error {
419  	// Create a basic plan with the thought as the foundation
420  	plan := &models.Plan{
421  		ID:                 uuid.New(),
422  		Thoughts:           []models.Thought{thought},
423  		Summary:            fmt.Sprintf("Plan based on thought: %s", thought.Content),
424  		Score:              thought.RelevanceScore,
425  		ParticipatingCells: []uuid.UUID{c.ID},
426  		CreatedAt:          time.Now(),
427  		Status:             models.PlanStatusProposed,
428  		Nodes:              []models.PlanNode{},
429  	}
430  
431  	// Create a root node for the plan
432  	rootNode := models.PlanNode{
433  		ID:                  uuid.New(),
434  		Title:               "Initial Concept",
435  		Description:         thought.Content,
436  		Dependencies:        []uuid.UUID{},
437  		EstimatedCompletion: 0.1,
438  		Status:              models.PlanNodeStatusPending,
439  	}
440  
441  	plan.Nodes = append(plan.Nodes, rootNode)
442  
443  	// Save the plan to the cell
444  	c.CurrentPlan = plan
445  
446  	// Log the plan to a file
447  	planPath := filepath.Join("data/plans", plan.ID.String()+".json")
448  	planData, err := json.MarshalIndent(plan, "", "  ")
449  	if err != nil {
450  		return fmt.Errorf("failed to marshal plan to JSON: %v", err)
451  	}
452  
453  	if err := ioutil.WriteFile(planPath, planData, 0644); err != nil {
454  		return fmt.Errorf("failed to write plan to file: %v", err)
455  	}
456  
457  	return nil
458  }
459  
460  // CheckAndCompressMemories checks and compresses memories if necessary.
461  func (c *Cell) CheckAndCompressMemories(apiClient *api.OpenRouterClient) error {
462  	totalSize := 0
463  	for _, thought := range c.Thoughts {
464  		totalSize += len(thought.Content)
465  	}
466  
467  	if totalSize > 50000 { // Max memory size constant
468  		thoughtsToCompress := make([]string, 0)
469  		for i := 0; i < len(c.Thoughts)/2; i++ {
470  			thoughtsToCompress = append(thoughtsToCompress, c.Thoughts[i].Content)
471  		}
472  		c.Thoughts = c.Thoughts[len(c.Thoughts)/2:]
473  
474  		compressed, err := apiClient.CompressMemories(thoughtsToCompress)
475  		if err != nil {
476  			return err
477  		}
478  		c.CompressedMemories = append(c.CompressedMemories, compressed)
479  	}
480  
481  	return nil
482  }
483  
484  // GetCurrentFocus returns the current focus of the cell.
485  func (c *Cell) GetCurrentFocus() string {
486  	if c.CurrentPlan != nil {
487  		return c.CurrentPlan.Summary
488  	}
489  	return "Exploring new opportunities"
490  }
491  
492  // GetActiveResearch returns the active research topics of the cell.
493  func (c *Cell) GetActiveResearch() []string {
494  	activeResearch := make([]string, 0)
495  	for i := 0; i < len(c.Thoughts) && i < 10; i++ {
496  		activeResearch = append(activeResearch, c.Thoughts[i].Content)
497  	}
498  	return activeResearch
499  }
500  
501  // GetRecentDiscoveries returns the recent discoveries of the cell.
502  func (c *Cell) GetRecentDiscoveries() []string {
503  	recentDiscoveries := make([]string, 0)
504  	for _, thought := range c.Thoughts {
505  		if thought.RelevanceScore > 0.8 {
506  			recentDiscoveries = append(recentDiscoveries, thought.Content)
507  			if len(recentDiscoveries) >= 3 {
508  				break
509  			}
510  		}
511  	}
512  	return recentDiscoveries
513  }
514  
515  // GetCollaborationHistory returns the collaboration history of the cell.
516  func (c *Cell) GetCollaborationHistory() []string {
517  	return []string{"Previous collaborations"}
518  }
519  
520  // GetPerformanceMetrics returns the performance metrics of the cell.
521  func (c *Cell) GetPerformanceMetrics() map[string]float64 {
522  	metrics := make(map[string]float64)
523  	metrics["energy_efficiency"] = c.Energy
524  	metrics["mission_alignment"] = c.MissionAlignmentScore
525  	return metrics
526  }
527  
528  // GetEvolutionStage returns the evolution stage of the cell.
529  func (c *Cell) GetEvolutionStage() uint32 {
530  	return uint32(math.Floor(float64(len(c.Thoughts))/10.0)) + 1
531  }
532  
533  // GenerateContextTags generates context tags for the cell.
534  func (c *Cell) GenerateContextTags(cellContext models.CellContext) []string {
535  	// Placeholder implementation
536  	return []string{"Tag1", "Tag2", "Tag3"}
537  }
538  
539  // CalculateConfidenceScore calculates the confidence score for a thought.
540  func (c *Cell) CalculateConfidenceScore(realTimeContext models.RealTimeContext) float64 {
541  	// Placeholder implementation
542  	return 0.8
543  }
544  
545  // UpdateFocusBasedOnContext updates the cell's focus based on the real-time context.
546  func (c *Cell) UpdateFocusBasedOnContext(realTimeContext models.RealTimeContext) {
547  	// Placeholder implementation
548  }