#!/usr/bin/env python import datetime from random import randint from datetime import time import random from typing import Optional from crewai import Crew from crewai.flow.flow import router, or_ from pydantic import BaseModel from crewai.flow import Flow, listen, start from engineering_team_using_flow.crews.engineering_crew.engineering_crew import ( CodeReviewFeedback, EngineeringCrew, ) from .shared_queue import TaskInfo, add_to_queue class EngineeringState(BaseModel): module_name: str = "" business_requirement: str = "" technical_design: Optional[str] = "" backend_code: Optional[str] = "" frontend_code: Optional[str] = "" unit_test_code: Optional[str] = "" backend_code_review_feedbacks: list[CodeReviewFeedback] = [] frontend_code_review_feedbacks: list[CodeReviewFeedback] = [] MAX_REVIEW_ITERATIONS = 3 BUSINESS_REQUIREMENTS: list[EngineeringState] = [ EngineeringState( module_name="mod_series_eval", business_requirement="Create a web application that allows the user to evaluate the first N terms of a given series and \ multiply the total by X (default to 4). for instance, the series could be something like :\ 1 + 1/3 - 1/5 + 1/7 - 1/9 ... ", ) ] class EngineeringFlow(Flow[EngineeringState]): def __init__(self, module_name:str, business_requirement:str): super().__init__() self.module_name = module_name self.business_requirement = business_requirement @start() def generate_business_requirement(self): print("Generating business requirement") self.state.business_requirement = self.business_requirement self.state.module_name = self.module_name add_to_queue( TaskInfo( name="Gathering Business Requirements", type="markdown", output=f"Gathering Business Requirements for {self.state.module_name}...", ) ) # chosen_requirement = random.choice(BUSINESS_REQUIREMENTS) # self.state.business_requirement = chosen_requirement.business_requirement # self.state.module_name = chosen_requirement.module_name add_to_queue( TaskInfo( name="Gather Business Requirements", type="markdown", output=f"#### Business Requirements for {self.state.module_name}: \n{self.state.business_requirement}", ) ) @listen(generate_business_requirement) def design_product(self): print("Designing product for requirement: ", self.state) add_to_queue( TaskInfo( name="Generating Design", type="markdown", output=f"Designing the product ...", ) ) engineeringCrew = EngineeringCrew() mycrew = Crew( agents=[engineeringCrew.development_lead()], tasks=[engineeringCrew.design_task()], ) result = mycrew.kickoff( inputs={ "id": self.state.id, "requirement": self.state.business_requirement, "module_name": self.state.module_name, "review_comments": "", } ) print("Product Design Created", result.raw) self.state.technical_design = result.raw add_to_queue( TaskInfo( name="Generate Design", type="markdown", output=f"{self.state.technical_design}", ) ) @listen(or_("design_product", "REWRITE_BACKEND_CODE")) def develop_backend(self): print("Developing backend : ", self.state) add_to_queue( TaskInfo( name="Generating Backend Code", type="markdown", output=f"Generating Backend Code ...", ) ) engineeringCrew = EngineeringCrew() mycrew = Crew( agents=[engineeringCrew.backend_engineer()], tasks=[engineeringCrew.backend_coding_task()], ) result = mycrew.kickoff( inputs={ "id": self.state.id, "requirement": self.state.business_requirement, "module_name": self.state.module_name, "review_comments": ( self.state.backend_code_review_feedbacks[ -1 ].review_comments_markdown if self.state.backend_code_review_feedbacks else "" ), } ) print("Backend Code Created", result.raw) self.state.backend_code = result.raw add_to_queue( TaskInfo( name="Generate Backend Code", type="markdown", output=f"#### Backend Code for {self.state.module_name}: \n ```{self.state.backend_code}\n```", ) ) return "BACKEND_CODE_CREATED" @router(develop_backend) def review_backend_code(self): print("Reviewing backend code : ", self.state) if len(self.state.backend_code_review_feedbacks) >= MAX_REVIEW_ITERATIONS: add_to_queue( TaskInfo( name="Maximum Iterations Exceeded!", type="markdown", output=f"#### Maximum Iterations Exceeded!", ) ) return "MAX_REVIEW_ITERATIONS_EXCEEDED" engineeringCrew = EngineeringCrew() add_to_queue( TaskInfo( name="Reviewing Backend Code", type="markdown", output=f"Reviewing Backend Code ...", ) ) mycrew = Crew( agents=[engineeringCrew.code_reviewer()], tasks=[engineeringCrew.code_review_task()], ) if self.state.backend_code_review_feedbacks is None: self.state.backend_code_review_feedbacks = [] result = mycrew.kickoff( inputs={ "id": self.state.id, "requirement": self.state.business_requirement, "module_name": self.state.module_name, "backend_code": self.state.backend_code, "iteration": len(self.state.backend_code_review_feedbacks), } ) codeReviewFeedback: CodeReviewFeedback = result.tasks_output[0].pydantic # type: ignore[index] print(codeReviewFeedback) add_to_queue( TaskInfo( name="Generate Backend Code Review", type="markdown", output=f"#### Backend Code Review Iteration {len(self.state.backend_code_review_feedbacks)} for {self.state.module_name}: \n{codeReviewFeedback.review_comments_markdown}", ) ) self.state.backend_code_review_feedbacks.append(codeReviewFeedback) if codeReviewFeedback.passed_review: return "BACKEND_CODE_REVIEWED" else: return "REWRITE_BACKEND_CODE" @listen(or_("BACKEND_CODE_REVIEWED", "REWRITE_FRONTEND_CODE")) def develop_frontend(self): print("Developing frontend : ", self.state) add_to_queue( TaskInfo( name="Developing Frontend Code", type="markdown", output=f"Developing Frontend Code ...", ) ) engineeringCrew = EngineeringCrew() mycrew = Crew( agents=[engineeringCrew.frontend_engineer()], tasks=[engineeringCrew.frontend_coding_task()], ) result = mycrew.kickoff( inputs={ "id": self.state.id, "requirement": self.state.business_requirement, "module_name": self.state.module_name, "review_comments": ( self.state.frontend_code_review_feedbacks[ -1 ].review_comments_markdown if self.state.frontend_code_review_feedbacks else "" ), } ) print("Frontend Code Created", result.raw) self.state.frontend_code = result.raw add_to_queue( TaskInfo( name="Generate Frontend Code", type="markdown", output=f"#### Frontend Code for {self.state.module_name}:\n ```{self.state.frontend_code}```", ) ) return "FRONTEND_CODE_CREATED" @router(develop_frontend) def review_frontend_code(self): print("Reviewing frontkend code : ", self.state) if len(self.state.frontend_code_review_feedbacks) >= MAX_REVIEW_ITERATIONS: add_to_queue( TaskInfo( name="Maximum Iterations Exceeded!", type="markdown", output=f"#### Maximum Iterations Exceeded!", ) ) return "MAX_REVIEW_ITERATIONS_EXCEEDED" engineeringCrew = EngineeringCrew() add_to_queue( TaskInfo( name="Reviewing Frontend Code", type="markdown", output=f"Reviewing Frontend Code ...", ) ) mycrew = Crew( agents=[engineeringCrew.code_reviewer()], tasks=[engineeringCrew.frontend_code_review_task()], ) if self.state.frontend_code_review_feedbacks is None: self.state.frontend_code_review_feedbacks = [] result = mycrew.kickoff( inputs={ "id": self.state.id, "requirement": self.state.business_requirement, "module_name": self.state.module_name, "frontend_code": self.state.frontend_code, "iteration": len(self.state.frontend_code_review_feedbacks), } ) codeReviewFeedback: CodeReviewFeedback = result.tasks_output[0].pydantic # type: ignore[index] print(codeReviewFeedback) add_to_queue( TaskInfo( name="Generate Frontend Code Review", type="markdown", output=f"#### Frontend Code Review Iteration {len(self.state.frontend_code_review_feedbacks)} for {self.state.module_name}: \n{codeReviewFeedback.review_comments_markdown}", ) ) self.state.frontend_code_review_feedbacks.append(codeReviewFeedback) if codeReviewFeedback.passed_review: return "FRONTEND_CODE_REVIEWED" else: return "REWRITE_FRONTEND_CODE" @listen("FRONTEND_CODE_REVIEWED") def write_test_cases(self): print("Writing test cases : ", self.state) add_to_queue( TaskInfo( name="Writing Test Cases", type="markdown", output=f"Writing Test Cases ...", ) ) engineeringCrew = EngineeringCrew() mycrew = Crew( agents=[engineeringCrew.test_engineer()], tasks=[engineeringCrew.test_preparation_task()], ) result = mycrew.kickoff( inputs={ "id": self.state.id, "requirement": self.state.business_requirement, "module_name": self.state.module_name, "backend_code": self.state.backend_code, "frontend_code": self.state.frontend_code, } ) self.state.unit_test_code = result.raw add_to_queue( TaskInfo( name="Generate Test Cases", type="markdown", output=f"#### Test Cases for {self.state.module_name}: \n```{self.state.unit_test_code}```", ) ) return "TEST_CASES_PREPARED" def kickoff(): engineering_flow = EngineeringFlow() engineering_flow.kickoff() def plot(): engineering_flow = EngineeringFlow() engineering_flow.plot() if __name__ == "__main__": kickoff()