115 lines
4.0 KiB
Python
115 lines
4.0 KiB
Python
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"
|
|
} |