Krishp1/Autonomous-Coding-Agent
0
1# main.py — Graph builder for Autonomous Python Coding Agent2 3import os4 5try:6 from dotenv import load_dotenv7 load_dotenv() # reads .env in the current working directory8except ImportError:9 raise RuntimeError(10 "python-dotenv is not installed but a .env file is expected. "11 "Run `pip install python-dotenv` then try again."12 )13 14_groq_key = os.environ.get("GROQ_API_KEY")15if not _groq_key:16 raise RuntimeError(17 "GROQ_API_KEY is not set. Add GROQ_API_KEY=your_key to your .env file "18 "(in the same folder as main.py), or `export GROQ_API_KEY=your_key` "19 "before starting the app."20 )21os.environ["GROQ_API_KEY"] = _groq_key22 23from langgraph.graph import StateGraph, END24 25from state import State26from nodes import (27 planner, coder, ast_validator, test_generator,28 tester, hypothesis_tester, performance_benchmarker,29 debugger, security_auditor, complexity_judge,30 self_reflection, reviewer, explainer31)32from edges import (33 route_after_ast, route_after_test, route_after_hypothesis,34 route_after_benchmark, route_after_security,35 route_after_complexity, route_after_reflection36)37 38# ── BUILD GRAPH ───────────────────────────39def build_graph():40 builder = StateGraph(State)41 42 # Add all 13 nodes43 builder.add_node("planner", planner)44 builder.add_node("coder", coder)45 builder.add_node("ast_validator", ast_validator)46 builder.add_node("test_generator", test_generator)47 builder.add_node("tester", tester)48 builder.add_node("hypothesis", hypothesis_tester)49 builder.add_node("benchmark", performance_benchmarker)50 builder.add_node("debugger", debugger)51 builder.add_node("security", security_auditor)52 builder.add_node("complexity", complexity_judge)53 builder.add_node("reflection", self_reflection)54 builder.add_node("reviewer", reviewer)55 builder.add_node("explainer", explainer)56 57 # Entry point58 builder.set_entry_point("planner")59 60 # Fixed edges61 builder.add_edge("planner", "coder")62 builder.add_edge("coder", "ast_validator")63 builder.add_edge("test_generator", "tester")64 builder.add_edge("debugger", "ast_validator")65 builder.add_edge("reviewer", "explainer")66 builder.add_edge("explainer", END)67 68 # Conditional edges69 builder.add_conditional_edges("ast_validator", route_after_ast,70 {"test_generator": "test_generator", "debugger": "debugger", "__end__": END})71 builder.add_conditional_edges("tester", route_after_test,72 {"hypothesis": "hypothesis", "debugger": "debugger"})73 builder.add_conditional_edges("hypothesis", route_after_hypothesis,74 {"benchmark": "benchmark"})75 builder.add_conditional_edges("benchmark", route_after_benchmark,76 {"security": "security", "debugger": "debugger"})77 builder.add_conditional_edges("security", route_after_security,78 {"complexity": "complexity", "coder": "coder"})79 builder.add_conditional_edges("complexity", route_after_complexity,80 {"reflection": "reflection", "coder": "coder"})81 builder.add_conditional_edges("reflection", route_after_reflection,82 {"reviewer": "reviewer", "coder": "coder"})83 84 return builder.compile()85 86# ── COMPILED GRAPH ────────────────────────87graph = build_graph()88 89# ── INITIAL STATE ─────────────────────────90def get_initial_state(task: str) -> dict:91 return {92 "task": task,93 "plan": "",94 "code": "",95 "test_result": "",96 "error": "",97 "fixed_code": "",98 "explanation": "",99 "review": "",100 "final_code": "",101 "retries": 0,102 "security_retries": 0,103 "complexity_retries": 0,104 "reflection_retries": 0,105 "passed": False,106 "is_secure": False,107 "is_simple": False,108 "ast_valid": False,109 "generated_tests": "",110 "hypothesis_result": "",111 "benchmark_ms": 0.0,112 "reflection_ok": False,113 "reflection_notes": "",114 "confidence_score": 0,115 }116 117# ── RUN ───────────────────────────────────118if __name__ == "__main__":119 tasks = [120 "Write a Python function to find all prime numbers up to n",121 "Write a Python function to check if a string is a palindrome",122 ]123 124 for task in tasks:125 print(f"\n{'='*60}")126 print(f"📋 Task: {task}")127 print("="*60)128 129 result = graph.invoke(get_initial_state(task), {"recursion_limit": 50})130 131 print(f"\n{'='*60}")132 print(f"💻 Final Code:\n{result['final_code'] or result['code']}")133 print(f"\n📖 Explanation:\n{result['explanation']}")134 bms = result['benchmark_ms']135 conf = result['confidence_score']136 print(f"\n🧪 Tests: {result['test_result'][:100]}")137 print(f"🎲 Hypothesis: {result['hypothesis_result']}")138 print(f"⚡ Speed: {bms:.1f}ms" if bms > 0 else "⚡ Speed: Skipped")139 print(f"🪞 Confidence: {conf}/10" if conf > 0 else "🪞 Confidence: 7/10 (default)")140 print(f"🔒 Secure: {result['is_secure']}")141 print(f"📊 Simple: {result['is_simple']}")142 print(f"🔄 Retries: {result['retries']}")