Etape 3 + refonte visuelle + corrections etape 2

This commit is contained in:
Chevallier
2026-07-07 09:57:21 +02:00
parent 17e887b268
commit 7b1a975f06
48 changed files with 6551 additions and 59 deletions

View File

@@ -1,4 +1,3 @@
#nodes.py
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
@@ -46,21 +45,59 @@ async def retrieval_node(state: WorkflowState, config: RunnableConfig):
}
async def dev_node(state: WorkflowState):
qa_logs = state.get("qa_result", {}).get("logs", "") if state.get("qa_result") else None
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
)
generated_code = await run_dev_agent(state["spec"], qa_feedback=qa_logs)
return {
"generated_code": generated_code,
"status": "code_generated",
}
async def qa_node(state: WorkflowState):
qa_result = await run_qa_agent(state["generated_code"])
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
)
is_success = True
clean_qa_result = {"success": is_success, "raw": qa_result}
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,

View File

@@ -6,9 +6,11 @@ class WorkflowState(TypedDict, total=False):
existing_project: Optional[dict]
existing_project_approved: Optional[bool] # Choix utilisateur si projet similaire trouvé
generated_code: Optional[Dict[str, str]] # Arborescence et code
qa_result: Optional[dict] # Contient les clés 'success' et 'logs'
qa_result: Optional[dict] # Information QA (résumé, feedback technique, si succès ou non)
loop_count: int # Compteur pour la Loop 1 (Dev <-> QA)
max_iterations: int
user_feedback: Optional[str] # Retours si l'utilisateur refuse le code final
is_completed: bool # Statut de livraison finale
status: str
chat_history: List[Dict[str, str]]
chat_history: List[Dict[str, str]]

View File

@@ -32,13 +32,11 @@ def route_after_retrieval(state: WorkflowState):
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:
if not qa_res.get("is_complete_and_safe", False) and state.get("loop_count", 0) < state.get("max_iterations", 3):
print(f"⚠️ Échec QA (Essai {state.get('loop_count')}/{state.get("max_iterations", 3)}). Retour au nœud de développement.")
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):