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 }