import warnings from langchain_core._api.deprecation import LangChainPendingDeprecationWarning warnings.filterwarnings("ignore", category=LangChainPendingDeprecationWarning) from langgraph.graph import StateGraph, END from app.graph.state import WorkflowState from app.graph.nodes import ( pm_node, retrieval_node, dev_node, qa_node, human_review_node, ) def route_entry_point(state: WorkflowState): if state.get("status") == "spec_approved": return "retrieval" return "pm" # --- Fonctions de Routage (Conditional Edges) --- def route_after_pm(state: WorkflowState): current_status = state.get("status") if current_status in ["spec_incomplete", "spec_ready"]: return END return "retrieval" def route_after_retrieval(state: WorkflowState): # Si un projet existe, on demande d'abord à l'humain (via le nœud de review) if state.get("existing_project"): return "human_review" return "dev" def route_after_qa(state: WorkflowState): qa_res = state.get("qa_result", {}) # Loop 1 : Si échec des tests ET qu'on a pas dépassé 3 essais -> On renvoie chez le Dev if not qa_res.get("success") and state.get("loop_count", 0) < 3: return "dev" # Si c'est vert (ou trop d'échecs), on présente le résultat à l'utilisateur # EXTENSION FUTURE : si trop d'échecs, on pourrait envoyer à une IA plus puissante return "human_review" def route_after_human(state: WorkflowState): # Cas d'un projet existant proposé if state.get("existing_project") and not state.get("generated_code"): if state.get("existing_project_approved") == True: return END # L'utilisateur est satisfait du projet existant return "dev" # L'utilisateur refuse l'existant, on génère du neuf # Cas du code généré if state.get("is_completed") == True: return END # Si l'utilisateur a refusé le code -> Retour à la case PM avec ses commentaires return "pm" # --- Assemblage du Graphe --- graph = StateGraph(WorkflowState) graph.add_node("pm", pm_node) graph.add_node("retrieval", retrieval_node) graph.add_node("dev", dev_node) graph.add_node("qa", qa_node) graph.add_node("human_review", human_review_node) graph.set_conditional_entry_point( route_entry_point, { "pm": "pm", "retrieval": "retrieval", }, ) graph.add_conditional_edges( "pm", route_after_pm, { END: END, "retrieval": "retrieval", }, ) # Étape 1 : Choix après recherche vectorielle graph.add_conditional_edges( "retrieval", route_after_retrieval, { "dev": "dev", "human_review": "human_review", }, ) # Étape 2 & 3 : Boucle Dev <-> QA (Loop 1) graph.add_edge("dev", "qa") graph.add_conditional_edges( "qa", route_after_qa, { "dev": "dev", "human_review": "human_review", }, ) # Étape 4 : Boucle de Feedback Humain (Loop 2) ou Clôture graph.add_conditional_edges( "human_review", route_after_human, { "pm": "pm", "dev": "dev", END: END, }, ) compiled_graph = graph.compile()