| |
| """ |
| Stack 2.9 CLI - Terminal User Interface |
| Main entry point for interacting with Stack 2.9 |
| """ |
|
|
| import os |
| import sys |
| import argparse |
| from pathlib import Path |
| from typing import Optional |
|
|
| |
| sys.path.insert(0, str(Path(__file__).parent)) |
| sys.path.insert(0, str(Path(__file__).parent.parent / "stack" / "eval")) |
| sys.path.insert(0, str(Path(__file__).parent.parent / "stack" / "training")) |
|
|
| from model_client import create_model_client, ChatMessage |
| from pattern_miner import PatternMiner |
| from data_quality import DataQualityAnalyzer |
|
|
|
|
| class Stack29CLI: |
| """Stack 2.9 Terminal User Interface""" |
|
|
| def __init__(self, provider: str = None, model: str = None): |
| self.provider = provider or os.environ.get("MODEL_PROVIDER", "ollama") |
| self.model = model or os.environ.get("MODEL_NAME", "") |
| self.client = None |
| self.agent = None |
| self.miner = PatternMiner() |
| self.chat_history = [] |
|
|
| |
| self.BLUE = '\033[94m' |
| self.GREEN = '\033[92m' |
| self.YELLOW = '\033[93m' |
| self.RED = '\033[91m' |
| self.END = '\033[0m' |
| self.BOLD = '\033[1m' |
|
|
| def print_header(self): |
| """Print CLI header""" |
| print(f""" |
| {self.BLUE}╔═══════════════════════════════════════════════════════╗ |
| ║ {self.BOLD}Stack 2.9 - Self-Evolving AI{self.END}{self.BLUE} ║ |
| ║ {self.YELLOW}Your AI coding companion{self.END}{self.BLUE} ║ |
| ╚═══════════════════════════════════════════════════════╝{self.END} |
| """) |
|
|
| def print_menu(self): |
| """Print main menu""" |
| print(f""" |
| {self.BOLD}Main Menu:{self.END} |
| {self.GREEN}[1]{self.END} Chat with Stack 2.9 |
| {self.GREEN}[2]{self.END} Run Evaluation (Benchmarks) |
| {self.GREEN}[3]{self.END} Manage Patterns (Self-Evolution) |
| {self.GREEN}[4]{self.END} Train Model (LoRA Fine-tuning) |
| {self.GREEN}[5]{self.END} Settings |
| {self.GREEN}[0]{self.END} Exit |
| |
| """) |
|
|
| def init_client(self): |
| """Initialize model client""" |
| try: |
| self.client = create_model_client(self.provider, self.model) |
| print(f"{self.GREEN}✓{self.END} Connected to {self.provider}: {self.client.get_model_name()}") |
| except Exception as e: |
| print(f"{self.RED}✗{self.END} Failed to connect: {e}") |
| print(f"{self.YELLOW}!{self.END} Make sure {self.provider} is running") |
| self.client = None |
|
|
| def chat_mode(self): |
| """Interactive chat mode using agent with tool calling""" |
| if not self.client: |
| print(f"{self.RED}No model connected!{self.END}") |
| return |
|
|
| print(f"\n{self.BLUE}=== Chat Mode ==={self.END}") |
| print("Type 'exit' to return to menu, 'clear' to clear history\n") |
|
|
| |
| if not hasattr(self, 'agent') or self.agent is None: |
| from cli.agent import StackAgent |
| self.agent = StackAgent(workspace='/Users/walidsobhi/stack-2.9') |
| print(f"{self.GREEN}✓{self.END} Agent initialized") |
|
|
| while True: |
| try: |
| user_input = input(f"{self.GREEN}You:{self.END} ").strip() |
|
|
| if not user_input: |
| continue |
|
|
| if user_input.lower() in ['exit', 'quit', 'q']: |
| break |
|
|
| if user_input.lower() == 'clear': |
| print("Chat cleared.\n") |
| continue |
|
|
| |
| print(f"{self.BLUE}Stack 2.9:{self.END} ", end="", flush=True) |
|
|
| try: |
| response = self.agent.process(user_input) |
| print(response.content) |
|
|
| except Exception as e: |
| print(f"{self.RED}Error: {e}{self.END}") |
|
|
| except Exception as e: |
| print(f"{self.RED}Error: {e}{self.END}") |
|
|
| print() |
|
|
| except KeyboardInterrupt: |
| print("\n") |
| break |
|
|
| def eval_mode(self): |
| """Run evaluation benchmarks""" |
| print(f"\n{self.BLUE}=== Evaluation ==={self.END}") |
| print(f"{self.GREEN}[1]{self.END} MBPP (Code Generation)") |
| print(f"{self.GREEN}[2]{self.END} HumanEval (Python)") |
| print(f"{self.GREEN}[3]{self.END} GSM8K (Math)") |
| print(f"{self.GREEN}[4]{self.END} Run All") |
| print(f"{self.GREEN}[0]{self.END} Back") |
|
|
| choice = input("\nSelect: ").strip() |
|
|
| if choice == '0': |
| return |
|
|
| benchmarks = { |
| '1': ('mbpp', 'MBPP'), |
| '2': ('human_eval', 'HumanEval'), |
| '3': ('gsm8k', 'GSM8K'), |
| '4': ('all', 'All') |
| } |
|
|
| if choice not in benchmarks: |
| print(f"{self.RED}Invalid choice{self.END}") |
| return |
|
|
| bench_name, bench_label = benchmarks[choice] |
|
|
| print(f"\n{self.YELLOW}Running {bench_label} benchmark...{self.END}") |
|
|
| try: |
| if bench_name == 'all': |
| from benchmarks.mbpp import MBPP |
| from benchmarks.human_eval import HumanEval |
| from benchmarks.gsm8k import GSM8K |
|
|
| for name, Benchmark in [('MBPP', MBPP), ('HumanEval', HumanEval), ('GSM8K', GSM8K)]: |
| print(f"\n--- {name} ---") |
| b = Benchmark(model_provider=self.provider, model_name=self.model) |
| results = b.evaluate() |
| print(f" Accuracy: {results['accuracy']*100:.1f}%") |
| else: |
| module = __import__(f'benchmarks.{bench_name}', fromlist=['MBPP', 'HumanEval', 'GSM8K']) |
| Benchmark = getattr(module, bench_name.upper() if bench_name != 'mbpp' else 'MBPP') |
| b = Benchmark(model_provider=self.provider, model_name=self.model) |
| results = b.evaluate() |
| print(f"\n{self.GREEN}Results:{self.END}") |
| print(f" Accuracy: {results['accuracy']*100:.1f}%") |
| print(f" Passed: {results['pass_at_1']}/{results['total_cases']}") |
|
|
| except Exception as e: |
| print(f"{self.RED}Error: {e}{self.END}") |
|
|
| input("\nPress Enter to continue...") |
|
|
| def pattern_mode(self): |
| """Manage patterns for self-evolution""" |
| print(f"\n{self.BLUE}=== Pattern Manager ==={self.END}") |
| print(f"{self.GREEN}[1]{self.END} View Patterns") |
| print(f"{self.GREEN}[2]{self.END} View Statistics") |
| print(f"{self.GREEN}[3]{self.END} Generate Synthetic Data") |
| print(f"{self.GREEN}[4]{self.END} Clear Patterns") |
| print(f"{self.GREEN}[0]{self.END} Back") |
|
|
| choice = input("\nSelect: ").strip() |
|
|
| if choice == '0': |
| return |
|
|
| if choice == '1': |
| patterns = self.miner.get_relevant_patterns(limit=20) |
| print(f"\n{self.YELLOW}Stored Patterns ({len(patterns)}):{self.END}") |
| for p in patterns: |
| print(f" [{p.pattern_type}] {p.code_snippet[:50]}... (rate: {p.success_rate:.0%})") |
|
|
| elif choice == '2': |
| stats = self.miner.get_statistics() |
| print(f"\n{self.YELLOW}Statistics:{self.END}") |
| print(f" Total Feedback: {stats['total_feedback']}") |
| print(f" Success Rate: {stats['success_rate']:.1%}") |
| print(f" Total Patterns: {stats['total_patterns']}") |
| print(f" By Type: {stats['patterns_by_type']}") |
|
|
| elif choice == '3': |
| try: |
| count = int(input("Number of examples: ").strip()) |
| self.miner.store_feedback( |
| problem_type="synthetic", |
| solution="# Synthetic pattern", |
| success=True |
| ) |
| print(f"{self.GREEN}✓{self.END} Generated {count} synthetic patterns") |
| except ValueError: |
| print(f"{self.RED}Invalid number{self.END}") |
|
|
| elif choice == '4': |
| confirm = input("Clear all patterns? (y/n): ").strip().lower() |
| if confirm == 'y': |
| |
| print(f"{self.YELLOW}Feature not implemented{self.END}") |
|
|
| input("\nPress Enter to continue...") |
|
|
| def train_mode(self): |
| """Train model with LoRA""" |
| print(f"\n{self.BLUE}=== Training ==={self.END}") |
| print(f"{self.YELLOW}Note: Requires GPU and training data{self.END}") |
| print(f"\n{self.GREEN}[1]{self.END} Prepare Data") |
| print(f"{self.GREEN}[2]{self.END} Train LoRA") |
| print(f"{self.GREEN}[3]{self.END} Merge Adapter") |
| print(f"{self.GREEN}[0]{self.END} Back") |
|
|
| choice = input("\nSelect: ").strip() |
|
|
| if choice == '0': |
| return |
|
|
| if choice == '1': |
| print(f"\n{self.YELLOW}Preparing training data...{self.END}") |
| try: |
| from prepare_data import prepare_data |
| result = prepare_data() |
| print(f"{self.GREEN}✓{self.END} Prepared {result['train_samples']} training samples") |
| except Exception as e: |
| print(f"{self.RED}Error: {e}{self.END}") |
|
|
| elif choice == '2': |
| print(f"\n{YELLOW}Training LoRA...{self.END}") |
| print(f"{self.YELLOW}Note: This requires significant GPU resources{self.END}") |
| confirm = input("Continue? (y/n): ").strip().lower() |
| if confirm == 'y': |
| try: |
| from train_lora import train_lora |
| trainer = train_lora() |
| print(f"{self.GREEN}✓{self.END} Training complete") |
| except Exception as e: |
| print(f"{self.RED}Error: {e}{self.END}") |
|
|
| input("\nPress Enter to continue...") |
|
|
| def settings_mode(self): |
| """Configure settings""" |
| print(f"\n{self.BLUE}=== Settings ==={self.END}") |
| print(f"Provider: {self.provider}") |
| print(f"Model: {self.model}") |
| print(f"\n{self.GREEN}[1]{self.END} Change Provider") |
| print(f"{self.GREEN}[2]{self.END} Change Model") |
| print(f"{self.GREEN}[0]{self.END} Back") |
|
|
| choice = input("\nSelect: ").strip() |
|
|
| if choice == '1': |
| print("Providers: ollama, openai, anthropic") |
| new_provider = input("Provider: ").strip() |
| if new_provider in ['ollama', 'openai', 'anthropic']: |
| self.provider = new_provider |
| self.init_client() |
|
|
| elif choice == '2': |
| new_model = input("Model name: ").strip() |
| if new_model: |
| self.model = new_model |
| self.init_client() |
|
|
| def run(self): |
| """Run the CLI""" |
| self.print_header() |
| self.init_client() |
|
|
| while True: |
| self.print_menu() |
| choice = input(f"{self.GREEN}Select>{self.END} ").strip() |
|
|
| if choice == '0': |
| print(f"\n{self.BLUE}Thanks for using Stack 2.9!{self.END}\n") |
| break |
|
|
| if choice == '1': |
| self.chat_mode() |
| elif choice == '2': |
| self.eval_mode() |
| elif choice == '3': |
| self.pattern_mode() |
| elif choice == '4': |
| self.train_mode() |
| elif choice == '5': |
| self.settings_mode() |
| else: |
| print(f"{self.RED}Invalid option{self.END}") |
|
|
|
|
| def main(): |
| parser = argparse.ArgumentParser(description="Stack 2.9 CLI") |
| parser.add_argument("--provider", "-p", choices=["ollama", "openai", "anthropic"], |
| help="Model provider") |
| parser.add_argument("--model", "-m", type=str, help="Model name") |
| parser.add_argument("--chat", "-c", action="store_true", help="Start in chat mode") |
| parser.add_argument("--eval", "-e", choices=["mbpp", "human_eval", "gsm8k", "all"], |
| help="Run evaluation") |
|
|
| args = parser.parse_args() |
|
|
| cli = Stack29CLI(provider=args.provider, model=args.model) |
|
|
| if args.chat: |
| cli.init_client() |
| cli.chat_mode() |
| elif args.eval: |
| cli.init_client() |
| cli.eval_mode() |
| else: |
| cli.run() |
|
|
|
|
| if __name__ == "__main__": |
| main() |