from app.agents.pm_agent import run_pm_agent from app.agents.dev_agent import run_dev_agent from app.agents.qa_agent import run_qa_agent from app.services.retrieval_service import find_existing_project from app.graph.state import WorkflowState from langchain_core.runnables import RunnableConfig async def pm_node(state: WorkflowState): history = state.get("chat_history", []) or [] if state.get("status") == "spec_incomplete" and state.get("user_feedback"): current_input = state["user_feedback"] full_user_input = f"{state['user_input']}\n{current_input}" else: current_input = state["user_input"] full_user_input = current_input spec = await run_pm_agent(user_input=current_input, history=history) updated_history = list(history) updated_history.append({"role": "user", "content": current_input}) if not spec.is_complete and spec.clarifying_question: updated_history.append({"role": "assistant", "content": spec.clarifying_question}) return { "spec": spec.model_dump(), "status": "spec_ready" if spec.is_complete else "spec_incomplete", "chat_history": updated_history, "user_input": full_user_input, "user_feedback": None, "loop_count": 0, } async def retrieval_node(state: WorkflowState, config: RunnableConfig): qdrant_repo = config.get("configurable", {}).get("qdrant_repo") if not qdrant_repo: raise ValueError("❌ Erreur : Le repository Qdrant n'a pas été transmis au graphe.") existing_project = await find_existing_project(qdrant_repo, state["user_input"]) return { "existing_project": existing_project, "status": "existing_found" if existing_project else "no_existing_project", } async def dev_node(state: WorkflowState): qa_logs = [] qa_result = state.get("qa_result") if qa_result: global_summary = qa_result.get("global_summary") technical_feedback = qa_result.get("technical_feedback", []) if global_summary: qa_logs.append(f"Résumé Global : {global_summary}") if isinstance(technical_feedback, list): qa_logs.extend(technical_feedback) elif technical_feedback: qa_logs.append(technical_feedback) generated_code_state = state.get("generated_code") or {} existing_repo_url = generated_code_state.get("repo_url") existing_files = generated_code_state.get("files") generated_code = await run_dev_agent( spec=state["spec"], qa_feedback=qa_logs if qa_logs else None, repo_url=existing_repo_url, files=existing_files ) return { "generated_code": generated_code, "status": "code_generated", } async def qa_node(state: WorkflowState): dev_data = state.get("generated_code", {}) project_title = dev_data.get("spec_title", "default_project") current_loops = state.get("loop_count", 0) qa_eval = await run_qa_agent( project_title=project_title, dev_output=dev_data ) if hasattr(qa_eval, "model_dump"): clean_qa_result = qa_eval.model_dump() elif isinstance(qa_eval, dict): clean_qa_result = qa_eval else: clean_qa_result = { "is_complete_and_safe": getattr(qa_eval, "is_complete_and_safe", False), "global_summary": getattr(qa_eval, "global_summary", "Erreur d'analyse"), "technical_feedback": getattr(qa_eval, "technical_feedback", []) } is_success = clean_qa_result.get("is_complete_and_safe", False) return { "qa_result": clean_qa_result, "loop_count": current_loops if is_success else current_loops + 1, "status": "qa_done", } async def human_review_node(state: WorkflowState): print("[Human Review] Passage en mode automatique (Mock)...") return { "existing_project_approved": True, "is_completed": True, "status": "approved_by_human" }