Files
hermes-agent/tests/test_nexus_architect.py

667 lines
21 KiB
Python
Raw Normal View History

feat: Issue #42 - Nexus Architect for autonomous Three.js world building Implement Phase 31: Autonomous 'Nexus' Expansion & Architecture DELIVERABLES: - agent/nexus_architect.py: AI agent for natural language to Three.js conversion * Prompt engineering for LLM-driven immersive environment generation * Mental state integration for dynamic aesthetic tuning * Mood preset system (contemplative, energetic, mysterious, etc.) * Room and portal design generation - tools/nexus_build_tool.py: Build tool interface with functions: * create_room(name, description, style) - Generate room modules * create_portal(from_room, to_room, style) - Generate portal connections * add_lighting(room, type, color, intensity) - Add Three.js lighting * add_geometry(room, shape, position, material) - Add 3D objects * generate_scene_from_mood(mood_description) - Mood-based generation * deploy_nexus_module(module_code, test=True) - Deploy and test - agent/nexus_deployment.py: Real-time deployment system * Hot-reload Three.js modules without page refresh * Validation (syntax check, Three.js API compliance) * Rollback on error with version history * Module versioning and status tracking - config/nexus-templates/: Template library * base_room.js - Base room template (Three.js r128+) * portal_template.js - Portal template (circular, rectangular, stargate) * lighting_presets.json - Warm, cool, dramatic, serene, crystalline presets * material_presets.json - 15 material presets including Timmy's gold, Allegro blue - tests/test_nexus_architect.py: Comprehensive test coverage * Unit tests for all components * Integration tests for full workflow * Template file validation DESIGN PRINCIPLES: - Modular architecture (each room = separate JS module) - Valid Three.js code (r128+ compatible) - Hot-reloadable (no page refresh needed) - Mental state integration (SOUL.md values influence aesthetic) NEXUS AESTHETIC GUIDELINES: - Timmy's color: warm gold (#D4AF37) - Allegro's color: motion blue (#4A90E2) - Sovereignty theme: crystalline structures, clean lines - Service theme: open spaces, welcoming lighting - Default mood: contemplative, expansive, hopeful
2026-04-01 02:45:36 +00:00
#!/usr/bin/env python3
"""
Tests for Nexus Architect System
Test coverage for:
- agent/nexus_architect.py (AI design generation)
- tools/nexus_build_tool.py (Build tool integration)
- agent/nexus_deployment.py (Deployment system)
- config/nexus-templates/ (Template library)
"""
import sys
import os
import json
import unittest
from unittest.mock import patch, MagicMock
# Add parent directory to path
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from agent.nexus_architect import (
NexusArchitectAI,
PromptEngineer,
MentalState,
RoomDesign,
MoodPresets,
NexusColors,
create_room,
create_portal,
generate_scene_from_mood,
set_mental_state,
get_nexus_summary,
)
from tools.nexus_build_tool import (
create_room as build_create_room,
create_portal as build_create_portal,
add_lighting,
add_geometry,
deploy_nexus_module,
_generate_room_template,
_generate_lighting_code,
)
from agent.nexus_deployment import (
NexusDeployer,
DeploymentStatus,
deploy_nexus_module as deploy_module,
validate_nexus_code,
)
# =============================================================================
# Test Cases
# =============================================================================
class TestMentalState(unittest.TestCase):
"""Test mental state handling."""
def test_default_mental_state(self):
"""Test default mental state creation."""
state = MentalState()
self.assertEqual(state.mood, "contemplative")
self.assertEqual(state.energy_level, 0.5)
self.assertEqual(state.clarity, 0.7)
def test_mental_state_to_dict(self):
"""Test mental state serialization."""
state = MentalState(mood="energetic", energy_level=0.8, clarity=0.9)
d = state.to_dict()
self.assertEqual(d["mood"], "energetic")
self.assertEqual(d["energy_level"], 0.8)
self.assertEqual(d["clarity"], 0.9)
class TestPromptEngineer(unittest.TestCase):
"""Test prompt engineering functionality."""
def test_infer_mood_from_description(self):
"""Test mood inference from description."""
engineer = PromptEngineer()
# Test contemplative
mood = engineer._infer_mood("serene and peaceful space for meditation")
self.assertEqual(mood, "contemplative")
# Test energetic
mood = engineer._infer_mood("dynamic and vibrant full of motion")
self.assertEqual(mood, "energetic")
# Test mysterious
mood = engineer._infer_mood("dark mysterious shadow realm")
self.assertEqual(mood, "mysterious")
def test_infer_mood_with_mental_state(self):
"""Test mood inference with mental state override."""
engineer = PromptEngineer()
state = MentalState(mood="welcoming")
mood = engineer._infer_mood("any description", state)
self.assertEqual(mood, "welcoming")
def test_room_prompt_contains_required_elements(self):
"""Test that room prompts contain required elements."""
engineer = PromptEngineer()
prompt = engineer.engineer_room_prompt(
name="test_room",
description="A test room",
style="minimalist"
)
# Check for required elements
self.assertIn("test_room", prompt)
self.assertIn("Three.js", prompt)
self.assertIn("createTestRoom", prompt)
self.assertIn("SAFETY", prompt)
self.assertIn("NO eval", prompt)
class TestNexusArchitectAI(unittest.TestCase):
"""Test Nexus Architect AI functionality."""
def setUp(self):
"""Create fresh architect instance for each test."""
self.architect = NexusArchitectAI()
def test_design_room_success(self):
"""Test successful room design."""
result = self.architect.design_room(
name="zen_garden",
description="Peaceful garden with floating stones",
style="minimalist_ethereal"
)
self.assertTrue(result["success"])
self.assertEqual(result["room_name"], "zen_garden")
self.assertIn("design", result)
self.assertIn("llm_prompt", result)
self.assertIn("zen_garden", self.architect.room_designs)
def test_design_room_stores_design(self):
"""Test that room design is stored."""
self.architect.design_room(
name="crystal_cave",
description="Cave with glowing crystals",
style="crystalline"
)
design = self.architect.room_designs["crystal_cave"]
self.assertEqual(design.name, "crystal_cave")
self.assertEqual(design.style, "crystalline")
def test_create_portal_without_rooms_fails(self):
"""Test that portal creation fails without existing rooms."""
result = self.architect.create_portal(
name="test_portal",
from_room="room_a",
to_room="room_b"
)
self.assertFalse(result["success"])
self.assertIn("error", result)
def test_create_portal_with_rooms_succeeds(self):
"""Test successful portal creation."""
# Create rooms first
self.architect.design_room("room_a", "Room A", "style_a")
self.architect.design_room("room_b", "Room B", "style_b")
# Create portal
result = self.architect.create_portal(
name="portal_ab",
from_room="room_a",
to_room="room_b",
style="energy_vortex"
)
self.assertTrue(result["success"])
self.assertEqual(result["portal_name"], "portal_ab")
self.assertIn("portal_ab", self.architect.portal_designs)
def test_generate_scene_from_mood(self):
"""Test mood-based scene generation."""
result = self.architect.generate_scene_from_mood(
"Timmy is feeling introspective and seeking clarity"
)
self.assertTrue(result["success"])
self.assertIn("inferred_mood", result)
self.assertIn("llm_prompt", result)
def test_mental_state_influences_colors(self):
"""Test that mental state influences color palette."""
# Set high clarity mental state
self.architect.set_mental_state(
MentalState(mood="contemplative", clarity=0.9, focus_area="creative")
)
# Design room
result = self.architect.design_room(
name="test_room",
description="A test space",
style="minimalist"
)
design = result["design"]
colors = design["color_palette"]
# Should have Timmy's gold (high clarity) and Allegro blue (creative focus)
self.assertIn(NexusColors.TIMMY_GOLD, colors)
self.assertIn(NexusColors.ALLEGRO_BLUE, colors)
def test_get_design_summary(self):
"""Test design summary generation."""
# Create some designs
self.architect.design_room("room1", "Room 1", "style1")
self.architect.design_room("room2", "Room 2", "style2")
summary = self.architect.get_design_summary()
self.assertEqual(summary["total_rooms"], 2)
self.assertEqual(len(summary["rooms"]), 2)
class TestNexusColors(unittest.TestCase):
"""Test Nexus color constants."""
def test_timmy_gold(self):
"""Test Timmy's gold color."""
self.assertEqual(NexusColors.TIMMY_GOLD, "#D4AF37")
def test_allegro_blue(self):
"""Test Allegro blue color."""
self.assertEqual(NexusColors.ALLEGRO_BLUE, "#4A90E2")
class TestMoodPresets(unittest.TestCase):
"""Test mood preset definitions."""
def test_contemplative_preset(self):
"""Test contemplative mood preset."""
preset = MoodPresets.CONTEMPLATIVE
self.assertIn("lighting", preset)
self.assertIn("colors", preset)
self.assertEqual(preset["atmosphere"], "calm")
def test_all_presets_have_required_keys(self):
"""Test that all presets have required keys."""
presets = [
MoodPresets.CONTEMPLATIVE,
MoodPresets.ENERGETIC,
MoodPresets.MYSTERIOUS,
MoodPresets.WELCOMING,
MoodPresets.SOVEREIGN,
]
required_keys = ["lighting", "colors", "geometry", "atmosphere", "description"]
for preset in presets:
for key in required_keys:
self.assertIn(key, preset)
class TestBuildTool(unittest.TestCase):
"""Test Nexus Build Tool functionality."""
def test_create_room_returns_expected_structure(self):
"""Test that create_room returns expected structure."""
result = build_create_room(
name="test_room",
description="A test room",
style="minimalist"
)
self.assertTrue(result["success"])
self.assertIn("room_name", result)
self.assertIn("design", result)
self.assertIn("prompt", result)
self.assertIn("template_code", result)
self.assertIn("build_metadata", result)
def test_create_portal_returns_expected_structure(self):
"""Test that create_portal returns expected structure."""
# First create rooms
build_create_room("room_a", "Room A", "style_a")
build_create_room("room_b", "Room B", "style_b")
result = build_create_portal(
from_room="room_a",
to_room="room_b"
)
self.assertTrue(result["success"])
self.assertIn("portal_name", result)
self.assertIn("design", result)
self.assertIn("template_code", result)
def test_add_lighting_valid_type(self):
"""Test adding valid lighting type."""
result = add_lighting(
room="test_room",
light_type="point",
color="#ffffff",
intensity=1.0
)
self.assertTrue(result["success"])
self.assertIn("code", result)
self.assertIn("THREE.PointLight", result["code"])
def test_add_lighting_invalid_type(self):
"""Test adding invalid lighting type."""
result = add_lighting(
room="test_room",
light_type="invalid_type"
)
self.assertFalse(result["success"])
self.assertIn("error", result)
def test_add_geometry_valid_shape(self):
"""Test adding valid geometry shape."""
result = add_geometry(
room="test_room",
shape="sphere",
position={"x": 0, "y": 1, "z": 0}
)
self.assertTrue(result["success"])
self.assertIn("code", result)
self.assertIn("SphereGeometry", result["code"])
def test_add_geometry_invalid_shape(self):
"""Test adding invalid geometry shape."""
result = add_geometry(
room="test_room",
shape="invalid_shape",
position={"x": 0, "y": 0, "z": 0}
)
self.assertFalse(result["success"])
self.assertIn("error", result)
def test_generate_scene_from_mood(self):
"""Test mood-based scene generation."""
result = build_create_room(
name="mood_room",
description="A room based on mood",
style="ethereal"
)
self.assertTrue(result["success"])
self.assertIn("design", result)
class TestTemplateGenerators(unittest.TestCase):
"""Test template code generators."""
def test_room_template_generation(self):
"""Test room template generation."""
design = {
"name": "test_room",
"style": "minimalist",
"mood_preset": "contemplative",
"dimensions": {"width": 10, "height": 5, "depth": 10},
"color_palette": ["#1A1A2E", "#16213E"],
"features": ["ambient"]
}
code = _generate_room_template(design)
self.assertIn("THREE.Group", code)
self.assertIn("test_room", code)
self.assertIn("createTestRoom", code)
self.assertIn("floor", code)
def test_lighting_code_generation(self):
"""Test lighting code generation."""
config = {
"room": "test_room",
"type": "point",
"color": "#ffffff",
"intensity": 1.0,
"position": {"x": 0, "y": 5, "z": 0},
"cast_shadow": True
}
code = _generate_lighting_code(config)
self.assertIn("THREE.PointLight", code)
self.assertIn("0, 5, 0", code)
def test_ambient_lighting_code(self):
"""Test ambient lighting code generation."""
config = {
"room": "test_room",
"type": "ambient",
"color": "#404040",
"intensity": 0.5,
"position": {"x": 0, "y": 0, "z": 0},
"cast_shadow": False
}
code = _generate_lighting_code(config)
self.assertIn("THREE.AmbientLight", code)
class TestNexusDeployment(unittest.TestCase):
"""Test Nexus Deployment system."""
def setUp(self):
"""Create fresh deployer for each test."""
self.deployer = NexusDeployer(modules_dir="/tmp/test_nexus_modules")
def tearDown(self):
"""Clean up test modules."""
import shutil
if os.path.exists("/tmp/test_nexus_modules"):
shutil.rmtree("/tmp/test_nexus_modules", ignore_errors=True)
def test_deploy_valid_module(self):
"""Test deploying a valid module."""
code = """
(function() {
function createTestRoom() {
const room = new THREE.Group();
const light = new THREE.AmbientLight(0x404040, 0.5);
room.add(light);
return room;
}
return { createTestRoom };
})();
"""
result = self.deployer.deploy_module(code, "test_module")
self.assertTrue(result["success"])
self.assertEqual(result["module_name"], "test_module")
self.assertIn("test_module", self.deployer.modules)
def test_deploy_with_validation_errors(self):
"""Test deployment with validation errors."""
code = """
(function() {
eval("bad code"); // Security violation
return {};
})();
"""
result = self.deployer.deploy_module(code, "bad_module")
self.assertFalse(result["success"])
self.assertIn("validation", result)
self.assertFalse(result["validation"]["is_valid"])
def test_hot_reload_module(self):
"""Test hot-reloading a module."""
# Deploy initial version
code1 = "(function() { return { version: 1 }; })();"
self.deployer.deploy_module(code1, "reloadable_module")
# Hot-reload with new code
code2 = "(function() { return { version: 2 }; })();"
result = self.deployer.hot_reload_module("reloadable_module", code2)
self.assertTrue(result["success"])
def test_get_module_status(self):
"""Test getting module status."""
code = "(function() { return {}; })();"
self.deployer.deploy_module(code, "status_module")
status = self.deployer.get_module_status("status_module")
self.assertIsNotNone(status)
self.assertEqual(status["name"], "status_module")
self.assertEqual(status["status"], "active")
def test_validate_module(self):
"""Test module validation."""
code = """
(function() {
const scene = new THREE.Scene();
const light = new THREE.AmbientLight(0xffffff, 0.5);
scene.add(light);
return scene;
})();
"""
result = self.deployer.validate_module(code)
self.assertIn("is_valid", result)
self.assertIn("syntax_valid", result)
self.assertIn("safety_score", result)
class TestTemplateFiles(unittest.TestCase):
"""Test that template files are valid."""
def test_lighting_presets_json(self):
"""Test lighting presets JSON is valid."""
presets_path = os.path.join(
os.path.dirname(__file__),
"..",
"config",
"nexus-templates",
"lighting_presets.json"
)
if os.path.exists(presets_path):
with open(presets_path) as f:
presets = json.load(f)
self.assertIn("presets", presets)
self.assertIn("warm", presets["presets"])
self.assertIn("cool", presets["presets"])
self.assertIn("dramatic", presets["presets"])
def test_material_presets_json(self):
"""Test material presets JSON is valid."""
presets_path = os.path.join(
os.path.dirname(__file__),
"..",
"config",
"nexus-templates",
"material_presets.json"
)
if os.path.exists(presets_path):
with open(presets_path) as f:
presets = json.load(f)
self.assertIn("presets", presets)
self.assertIn("timmy_gold", presets["presets"])
self.assertIn("allegro_blue", presets["presets"])
self.assertIn("sovereignty_crystal", presets["presets"])
def test_base_room_template(self):
"""Test base room template exists and is valid JS."""
template_path = os.path.join(
os.path.dirname(__file__),
"..",
"config",
"nexus-templates",
"base_room.js"
)
if os.path.exists(template_path):
with open(template_path) as f:
content = f.read()
self.assertIn("THREE.Group", content)
self.assertIn("createBaseRoom", content)
self.assertIn("CONFIG", content)
def test_portal_template(self):
"""Test portal template exists and is valid JS."""
template_path = os.path.join(
os.path.dirname(__file__),
"..",
"config",
"nexus-templates",
"portal_template.js"
)
if os.path.exists(template_path):
with open(template_path) as f:
content = f.read()
self.assertIn("createPortal", content)
self.assertIn("PORTAL_CONFIG", content)
self.assertIn("circular", content)
class TestIntegration(unittest.TestCase):
"""Integration tests for the full Nexus system."""
def test_full_room_creation_workflow(self):
"""Test complete room creation workflow."""
# Step 1: Design room with AI architect
result = create_room(
name="integration_test_room",
description="A serene space with floating crystals",
style="crystalline_ethereal"
)
self.assertTrue(result["success"])
# Step 2: Use build tool to add lighting
lighting_result = add_lighting(
room="integration_test_room",
light_type="point",
color=NexusColors.TIMMY_GOLD,
intensity=0.8
)
self.assertTrue(lighting_result["success"])
# Step 3: Add geometry
geometry_result = add_geometry(
room="integration_test_room",
shape="sphere",
position={"x": 0, "y": 3, "z": 0},
material={"color": NexusColors.ALLEGRO_BLUE}
)
self.assertTrue(geometry_result["success"])
# Step 4: Generate template code
template = _generate_room_template(result["design"])
self.assertIn("THREE.Group", template)
# Step 5: Validate code
validation = validate_nexus_code(template)
self.assertIn("is_valid", validation)
def test_mood_based_generation(self):
"""Test mood-based scene generation."""
# Set mental state
set_mental_state(
mood="contemplative",
energy_level=0.3,
clarity=0.8
)
# Generate from mood
result = generate_scene_from_mood(
"Timmy is feeling introspective and seeking clarity"
)
self.assertTrue(result["success"])
self.assertEqual(result["inferred_mood"], "contemplative")
def test_portal_creation_between_rooms(self):
"""Test portal creation between two rooms."""
# Create two rooms
create_room("room_alpha", "First room", "modern")
create_room("room_beta", "Second room", "organic")
# Create portal
result = create_portal(
name="portal_alpha_beta",
from_room="room_alpha",
to_room="room_beta",
style="energy_vortex"
)
self.assertTrue(result["success"])
self.assertEqual(result["design"]["from_room"], "room_alpha")
self.assertEqual(result["design"]["to_room"], "room_beta")
# =============================================================================
# Main Entry Point
# =============================================================================
def run_tests():
"""Run all tests and return results."""
loader = unittest.TestLoader()
suite = loader.loadTestsFromModule(sys.modules[__name__])
runner = unittest.TextTestRunner(verbosity=2)
result = runner.run(suite)
return result.wasSuccessful()
if __name__ == "__main__":
success = run_tests()
sys.exit(0 if success else 1)