felix-framework / examples /code_reviewer.py
jkbennitt
Clean hf-space branch and prepare for HuggingFace Spaces deployment
fb867c3
#!/usr/bin/env python3
"""
Code Reviewer Demo using Felix Framework Geometric Orchestration.
This demo showcases how the Felix Framework can be used for collaborative
code review, with multiple specialized agents examining code from different
perspectives and converging naturally toward a comprehensive review.
The demo demonstrates the geometric attention focusing mechanism - early
agents perform broad analysis while later agents focus on specific issues
and provide final synthesis.
Usage:
python examples/code_reviewer.py path/to/code.py
python examples/code_reviewer.py --code-string "def hello(): print('hello')"
Requirements:
- LM Studio running with a model loaded (http://localhost:1234)
- openai Python package installed
"""
import sys
import time
import argparse
from typing import List, Dict, Any, Optional
from pathlib import Path
# Add src to path for imports
sys.path.insert(0, str(Path(__file__).parent.parent / "src"))
from core.helix_geometry import HelixGeometry
from llm.lm_studio_client import LMStudioClient, LMStudioConnectionError
from agents.llm_agent import LLMTask
from agents.specialized_agents import (
ResearchAgent, AnalysisAgent, SynthesisAgent, CriticAgent
)
from communication.central_post import CentralPost
from communication.spoke import SpokeManager
class FelixCodeReviewer:
"""
Code review system using Felix geometric orchestration.
Demonstrates how helix-based agent coordination can provide
comprehensive code review through natural convergence of
different analytical perspectives.
"""
def __init__(self, lm_studio_url: str = "http://localhost:1234/v1"):
"""Initialize the Felix code review system."""
# Create helix geometry
self.helix = HelixGeometry(
top_radius=33.0,
bottom_radius=0.001,
height=33.0,
turns=33
)
# Initialize LLM client
self.llm_client = LMStudioClient(base_url=lm_studio_url)
# Initialize communication system
self.central_post = CentralPost(max_agents=15, enable_metrics=True)
self.spoke_manager = SpokeManager(self.central_post)
# Review agents
self.agents = []
print(f"Felix Code Reviewer initialized")
def test_connection(self) -> bool:
"""Test connection to LM Studio."""
try:
if self.llm_client.test_connection():
print("✓ LM Studio connection successful")
return True
else:
print("✗ LM Studio connection failed")
return False
except LMStudioConnectionError as e:
print(f"✗ LM Studio connection error: {e}")
return False
def create_code_review_team(self) -> None:
"""Create specialized team for code review."""
print(f"\nCreating code review team with geometric specialization...")
# Research agents - broad analysis (spawn early, top of helix)
self.agents.extend([
ResearchAgent("code_analysis_001", 0.05, self.helix, self.llm_client, "code_structure"),
ResearchAgent("code_analysis_002", 0.10, self.helix, self.llm_client, "functionality"),
ResearchAgent("code_analysis_003", 0.15, self.helix, self.llm_client, "style"),
])
# Analysis agents - focused evaluation (spawn mid, middle of helix)
self.agents.extend([
AnalysisAgent("detailed_review_001", 0.35, self.helix, self.llm_client, "performance"),
AnalysisAgent("detailed_review_002", 0.45, self.helix, self.llm_client, "security"),
AnalysisAgent("detailed_review_003", 0.55, self.helix, self.llm_client, "maintainability"),
])
# Critic agents - quality assurance (spawn late-mid, narrowing helix)
self.agents.extend([
CriticAgent("quality_check_001", 0.65, self.helix, self.llm_client, "bug_detection"),
CriticAgent("quality_check_002", 0.75, self.helix, self.llm_client, "best_practices"),
])
# Synthesis agent - final review (spawn latest, bottom of helix)
self.agents.append(
SynthesisAgent("final_review_001", 0.85, self.helix, self.llm_client, "code_review_report")
)
# Register all agents
for agent in self.agents:
self.spoke_manager.register_agent(agent)
print(f"Created review team of {len(self.agents)} specialized agents:")
for agent in self.agents:
depth_at_spawn = agent.spawn_time # Approximation
print(f" - {agent.agent_id}: {agent.agent_type} @ t={agent.spawn_time:.2f} "
f"(depth ≈ {depth_at_spawn:.2f})")
def load_code_to_review(self, code_path: Optional[str] = None,
code_string: Optional[str] = None) -> str:
"""Load code for review from file or string."""
if code_string:
return code_string
elif code_path:
try:
with open(code_path, 'r') as f:
return f.read()
except Exception as e:
raise ValueError(f"Could not read code file {code_path}: {e}")
else:
raise ValueError("Must provide either code_path or code_string")
def run_code_review_session(self, code: str, filename: str = "code.py") -> Dict[str, Any]:
"""
Run collaborative code review session.
Args:
code: Code to review
filename: Filename for context
Returns:
Comprehensive review results
"""
print(f"\n{'='*60}")
print(f"FELIX CODE REVIEW SESSION")
print(f"File: {filename} ({len(code)} characters)")
print(f"{'='*60}")
# Preview code
lines = code.split('\n')
print(f"\nCode Preview (first 10 lines):")
for i, line in enumerate(lines[:10], 1):
print(f"{i:2d}: {line}")
if len(lines) > 10:
print(f" ... and {len(lines) - 10} more lines")
# Create review task
review_task = LLMTask(
task_id="code_review_001",
description=f"Perform a thorough code review of the following code:\n\n```python\n{code}\n```",
context=f"This is a collaborative code review. Multiple agents will examine "
f"different aspects (structure, functionality, style, performance, security, etc.) "
f"and converge toward a comprehensive review. File: {filename}",
metadata={"filename": filename, "code_length": len(code), "line_count": len(lines)}
)
# Track review results
results = {
"filename": filename,
"code": code,
"review_participants": [],
"review_timeline": [],
"convergence_pattern": [],
"final_review": None,
"session_stats": {}
}
# Run review simulation
current_time = 0.0
time_step = 0.05
simulation_time = 1.0
session_start = time.perf_counter()
print(f"\nStarting geometric code review orchestration...")
print(f"Agents will spawn and converge from broad analysis → focused critique → final synthesis")
while current_time <= simulation_time:
# Check for agents ready to spawn
for agent in self.agents:
if (agent.can_spawn(current_time) and
agent.state.value == "waiting"):
# Calculate position info for visual feedback
pos_info = agent.get_position_info(current_time + 0.01) # Slight offset for spawning
depth = pos_info.get("depth_ratio", 0.0)
radius = pos_info.get("radius", 0.0)
print(f"\n[t={current_time:.2f}] 🔍 {agent.agent_id} ({agent.agent_type}) spawning")
print(f" Helix position: depth={depth:.2f}, radius={radius:.1f}")
print(f" Focus level: {'Broad exploration' if depth < 0.3 else 'Focused analysis' if depth < 0.7 else 'Precise critique'}")
# Spawn and process
try:
agent.spawn(current_time, review_task)
result = agent.process_task_with_llm(review_task, current_time)
# Share result with central post via spoke communication
message = agent.share_result_to_central(result)
self.spoke_manager.send_message(agent.agent_id, message)
# Central post will handle distribution through spoke system
# Track participation
participant_info = {
"agent_id": agent.agent_id,
"agent_type": agent.agent_type,
"spawn_time": current_time,
"position_info": result.position_info,
"review_focus": getattr(agent, 'research_domain', None) or
getattr(agent, 'analysis_type', None) or
getattr(agent, 'review_focus', None) or
getattr(agent, 'output_format', None),
"content_length": len(result.content),
"tokens_used": result.llm_response.tokens_used,
"processing_time": result.processing_time,
"review_preview": result.content[:150] + "..."
}
results["review_participants"].append(participant_info)
# Track convergence pattern
results["convergence_pattern"].append({
"timestamp": current_time,
"agent_id": agent.agent_id,
"depth_ratio": result.position_info.get("depth_ratio", 0.0),
"radius": result.position_info.get("radius", 0.0),
"content_focus": self._analyze_content_focus(result.content)
})
print(f" ✓ Review completed ({result.llm_response.tokens_used} tokens, "
f"{result.processing_time:.2f}s)")
print(f" Preview: {result.content[:100]}...")
# Check for final synthesis
if agent.agent_type == "synthesis":
if hasattr(agent, 'finalize_output'):
final_review = agent.finalize_output(result)
results["final_review"] = final_review
print(f" 🎯 Final review synthesis completed!")
except Exception as e:
print(f" ✗ Error during review: {e}")
# Update positions and process communication
for agent in self.agents:
if agent.state.value == "active":
agent.update_position(current_time)
self.spoke_manager.process_all_messages()
current_time += time_step
session_end = time.perf_counter()
# Collect session statistics
results["session_stats"] = {
"total_duration": session_end - session_start,
"agents_participated": len(results["review_participants"]),
"total_tokens_used": sum(p["tokens_used"] for p in results["review_participants"]),
"total_messages": self.central_post.total_messages_processed,
"llm_client_stats": self.llm_client.get_usage_stats(),
"convergence_stages": len(set(p["agent_type"] for p in results["review_participants"]))
}
return results
def _analyze_content_focus(self, content: str) -> str:
"""Analyze what aspect of code the review content focuses on."""
content_lower = content.lower()
focus_keywords = {
"structure": ["class", "function", "method", "organization", "architecture"],
"style": ["naming", "format", "convention", "readability", "style"],
"performance": ["efficiency", "performance", "optimization", "speed", "memory"],
"security": ["security", "vulnerability", "injection", "validation", "sanitize"],
"bugs": ["bug", "error", "exception", "issue", "problem", "fix"],
"maintainability": ["maintainability", "documentation", "testing", "modularity"]
}
focus_scores = {}
for focus, keywords in focus_keywords.items():
score = sum(1 for keyword in keywords if keyword in content_lower)
if score > 0:
focus_scores[focus] = score
if focus_scores:
return max(focus_scores, key=focus_scores.get)
else:
return "general"
def display_review_results(self, results: Dict[str, Any]) -> None:
"""Display code review results."""
print(f"\n{'='*60}")
print(f"CODE REVIEW RESULTS")
print(f"{'='*60}")
stats = results["session_stats"]
print(f"File: {results['filename']}")
print(f"Review Duration: {stats['total_duration']:.2f} seconds")
print(f"Participants: {stats['agents_participated']} agents")
print(f"Total Tokens: {stats['total_tokens_used']}")
print(f"Convergence Stages: {stats['convergence_stages']}")
print(f"\nReview Progression (Geometric Convergence):")
for participant in results["review_participants"]:
depth = participant["position_info"].get("depth_ratio", 0.0)
focus = participant["review_focus"] or "general"
print(f" {participant['spawn_time']:.2f}s: {participant['agent_id']} "
f"(depth={depth:.2f}, focus={focus})")
print(f" {participant['review_preview']}")
if results["final_review"]:
print(f"\n{'='*60}")
print(f"FINAL COMPREHENSIVE REVIEW")
print(f"{'='*60}")
print(results["final_review"]["content"])
metadata = results["final_review"]["metadata"]
print(f"\n[Review completed by {metadata['agent_id']} "
f"using {metadata['tokens_used']} tokens at "
f"helix depth {metadata['position_info'].get('depth_ratio', 0):.2f}]")
else:
print(f"\n⚠️ No final synthesis was generated")
# Show convergence pattern
print(f"\nGeometric Convergence Pattern:")
focus_by_depth = {}
for entry in results["convergence_pattern"]:
depth_bucket = round(entry["depth_ratio"], 1)
if depth_bucket not in focus_by_depth:
focus_by_depth[depth_bucket] = []
focus_by_depth[depth_bucket].append(entry["content_focus"])
for depth in sorted(focus_by_depth.keys()):
focuses = focus_by_depth[depth]
print(f" Depth {depth:.1f}: {', '.join(set(focuses))}")
def main():
"""Main function for code reviewer demo."""
parser = argparse.ArgumentParser(description="Felix Framework Code Reviewer Demo")
parser.add_argument("code_file", nargs="?", help="Python file to review")
parser.add_argument("--code-string", help="Code string to review")
parser.add_argument("--lm-studio-url", default="http://localhost:1234/v1",
help="LM Studio API URL")
args = parser.parse_args()
if not args.code_file and not args.code_string:
parser.error("Must provide either a code file or --code-string")
# Create code reviewer
reviewer = FelixCodeReviewer(lm_studio_url=args.lm_studio_url)
# Test connection
if not reviewer.test_connection():
print("\nPlease ensure LM Studio is running with a model loaded.")
sys.exit(1)
# Load code
try:
code = reviewer.load_code_to_review(
code_path=args.code_file,
code_string=args.code_string
)
filename = args.code_file or "provided_code.py"
except ValueError as e:
print(f"Error loading code: {e}")
sys.exit(1)
# Create review team and run session
reviewer.create_code_review_team()
results = reviewer.run_code_review_session(code, filename)
# Display results
reviewer.display_review_results(results)
if __name__ == "__main__":
main()