From ab1159358194dd326a091a3a295617db39fba83d Mon Sep 17 00:00:00 2001 From: SwiftyOS Date: Mon, 26 Feb 2024 16:57:34 +0100 Subject: [PATCH 1/8] Add Pydantic class tracking in FunctionVisitor --- codex/develop/develop.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/codex/develop/develop.py b/codex/develop/develop.py index d243128..f835a53 100644 --- a/codex/develop/develop.py +++ b/codex/develop/develop.py @@ -67,6 +67,7 @@ class FunctionVisitor(ast.NodeVisitor): def __init__(self): self.functions = {} self.imports = [] + self.pydantic_classes = [] def visit_Import(self, node): for alias in node.names: @@ -117,6 +118,19 @@ class FunctionVisitor(ast.NodeVisitor): ) self.generic_visit(node) + def visit_ClassDef(self, node: ast.ClassDef) -> None: + """ + Visits a ClassDef node in the AST and checks if it is a Pydantic class. + If it is a Pydantic class, adds its name to the list of Pydantic classes. + """ + for base in node.bases: + base_id = getattr(base, "id", None) + # This will only work for direct children of BaseModel + if base_id == "BaseModel" or "pydantic.BaseModel" in ast.unparse(base): + self.pydantic_classes.append(node.name) + + self.generic_visit(node) + class DevelopAIBlock(AIBlock): developement_phase: DevelopmentPhase = DevelopmentPhase.DEVELOPMENT From 2237c53d5eae9ad49dd7c5904c3cbfd2462c681f Mon Sep 17 00:00:00 2001 From: SwiftyOS Date: Mon, 26 Feb 2024 16:57:48 +0100 Subject: [PATCH 2/8] fix formatting --- codex/requirements/database.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/codex/requirements/database.py b/codex/requirements/database.py index 54ce004..93f1b7e 100644 --- a/codex/requirements/database.py +++ b/codex/requirements/database.py @@ -71,7 +71,6 @@ async def create_spec(ids: Identifiers, spec: ApplicationRequirements) -> Specif create_route["DatabaseSchema"] = {"create": create_db} routes.append(create_route) - create_spec = SpecificationCreateInput( name=spec.name, context=spec.context, @@ -79,7 +78,7 @@ async def create_spec(ids: Identifiers, spec: ApplicationRequirements) -> Specif Application={"connect": {"id": ids.app_id}}, ApiRouteSpecs={"create": routes}, ) - + new_spec = await Specification.prisma().create( data=create_spec, include={ From 11da0b66f034a1ea5db1dd8c8216d8e2b2a4f03c Mon Sep 17 00:00:00 2001 From: SwiftyOS Date: Mon, 26 Feb 2024 16:57:58 +0100 Subject: [PATCH 3/8] Add ast_test.py with test_function_visitor() --- codex/tests/ast_test.py | 139 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 139 insertions(+) create mode 100644 codex/tests/ast_test.py diff --git a/codex/tests/ast_test.py b/codex/tests/ast_test.py new file mode 100644 index 0000000..4a5978e --- /dev/null +++ b/codex/tests/ast_test.py @@ -0,0 +1,139 @@ +import ast + +import pytest + +from codex.develop.develop import FunctionVisitor + +SAMPLE_CODE = """ +from pydantic import BaseModel +from datetime import datetime, timedelta +from typing import Dict, List, Tuple + +class Location(BaseModel): + name: str # For named locations or coordinates as a string + +class ProfessionalWorkingHours(BaseModel): + professional_id: str + start: datetime + end: datetime + +class Appointment(BaseModel): + start_time: datetime + end_time: datetime + professional_id: str + location: str + +class TravelTime(BaseModel): + start_location: str + end_location: str + time: timedelta + +class SomeClass: + start_location: str + end_location: str + time: timedelta + + +def calculate_travel_time(start_location: Location, end_location: Location) -> timedelta: + \"\"\" + Stub function to calculate the travel time between two locations. + + This function is intended to compute the estimated time it takes to travel from a start location to an end location. + It can accept either named locations (e.g., "Office", "Home") or geographical coordinates in string format (e.g., "40.7128,-74.0060"). + The actual implementation of this function would involve complex logic possibly including API calls to mapping services, + but in this stub, the specifics of how travel time is calculated are abstract. + + Args: + start_location (str): The starting location's name or coordinates. + end_location (str): The ending location's name or coordinates. + + Returns: + timedelta: The estimated travel time between the two locations. For the purposes of this stub, a fixed + travel time is returned to simulate functionality. + + Example: + calculate_travel_time("Office", "Client Site") + > timedelta(minutes=30) + \"\"\" + pass + +def is_within_working_hours( + professional_id: str, + proposed_time: datetime, + working_hours: Dict[str, ProfessionalWorkingHours] +) -> bool: + \"\"\" + Determination whether a proposed appointment time falls within a professional's predefined working hours. + + This function assesses the suitability of a proposed appointment time by comparing it with the professional's working + hours. It is particularly useful in scheduling systems where appointments need to be set during specific hours. + + Args: + professional_id (str): Unique identifier of the professional. + proposed_time (datetime): The datetime object representing the proposed appointment time. + working_hours (Dict[str, Tuple[datetime, datetime]]): A dictionary with professional_id as keys and tuples + representing the start and end of working hours as values. + + Returns: + bool: A boolean value indicating if the proposed_time falls within the working hours of the specified professional. + + Example: + is_within_working_hours( + "prof123", + datetime(2023, 4, 15, 10, 0), + {"prof123": (datetime(2023, 4, 15, 9, 0), datetime(2023, 4, 15, 17, 0))} + ) + > True + \"\"\" + pass + +def create_schedule( + appointments: List[Appointment], + working_hours: Dict[str, ProfessionalWorkingHours], + travel_times: Dict[Tuple[str, str], TravelTime] +) -> List[Appointment]: + suggested_appointments = [] + + for prof_id, working_hour in working_hours.items(): + available_start = working_hour.start + while available_start < working_hour.end: + # Find end time by adding minimum appointment duration to start + available_end = available_start + timedelta(hours=1) # Assuming 1-hour appointments + + # Check if this slot is within working hours and not overlapping with existing appointments + if is_within_working_hours(prof_id, available_start, working_hours) and all( + not (appointment.start_time <= available_start < appointment.end_time or + appointment.start_time < available_end <= appointment.end_time) + for appointment in appointments if appointment.professional_id == prof_id + ): + # Assuming all appointments are at the same location for simplification + # In a real scenario, you would check travel times between locations here + suggested_appointments.append(Appointment( + start_time=available_start, + end_time=available_end, + professional_id=prof_id, + location="Assumed Single Location" # Placeholder + )) + # Adjust start time for next potential slot by considering travel time + available_start = available_end + timedelta(minutes=30) # Assuming fixed travel time for simplification + else: + # Move to the next slot if this one is not suitable + available_start += timedelta(minutes=15) # Check every 15 minutes for availability + + return suggested_appointments +""" + + +def test_function_visitor(): + tree = ast.parse(SAMPLE_CODE) + + visitor = FunctionVisitor() + visitor.visit(tree) + + # Check that all Pydantic classes are identified + assert "SomeClass" not in visitor.pydantic_classes + assert "ProfessionalWorkingHours" in visitor.pydantic_classes + + # Check that all functions are identified + assert len(visitor.pydantic_classes) == 4 + assert len(visitor.functions) == 3 From 133088203ce5c15f03d06b6dc38acf5abbd0b834 Mon Sep 17 00:00:00 2001 From: Swiftyos Date: Mon, 26 Feb 2024 15:58:39 +0000 Subject: [PATCH 4/8] style fixes by ruff --- codex/requirements/database.py | 1 + 1 file changed, 1 insertion(+) diff --git a/codex/requirements/database.py b/codex/requirements/database.py index 93f1b7e..e91ca05 100644 --- a/codex/requirements/database.py +++ b/codex/requirements/database.py @@ -1,5 +1,6 @@ from prisma.models import Specification from prisma.types import SpecificationCreateInput + from codex.api_model import ( Identifiers, Pagination, From ed5149bdfe046b30f690e6d82e41937d717e72df Mon Sep 17 00:00:00 2001 From: SwiftyOS Date: Mon, 26 Feb 2024 17:14:24 +0100 Subject: [PATCH 5/8] added more tests --- codex/tests/ast_test.py | 233 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 231 insertions(+), 2 deletions(-) diff --git a/codex/tests/ast_test.py b/codex/tests/ast_test.py index 4a5978e..805d945 100644 --- a/codex/tests/ast_test.py +++ b/codex/tests/ast_test.py @@ -86,14 +86,14 @@ def is_within_working_hours( > True \"\"\" pass - + def create_schedule( appointments: List[Appointment], working_hours: Dict[str, ProfessionalWorkingHours], travel_times: Dict[Tuple[str, str], TravelTime] ) -> List[Appointment]: suggested_appointments = [] - + for prof_id, working_hour in working_hours.items(): available_start = working_hour.start while available_start < working_hour.end: @@ -137,3 +137,232 @@ def test_function_visitor(): # Check that all functions are identified assert len(visitor.pydantic_classes) == 4 assert len(visitor.functions) == 3 + + +# Visiting a simple function definition with no arguments or return type +def test_simple_function_definition(): + # Initialize FunctionVisitor + visitor = FunctionVisitor() + + # Create AST for a simple function definition + code = ast.parse("def my_function():\n pass") + + # Visit the AST + visitor.visit(code) + + # Assert that the function was added to the functions dictionary + assert "my_function" in visitor.functions + + # Assert the properties of the FunctionDef object + function_def = visitor.functions["my_function"] + assert function_def.name == "my_function" + assert function_def.args == "" + assert function_def.return_type == "Unknown" + assert function_def.function_template == "def my_function():\n pass" + assert function_def.function_code == "def my_function():\n pass" + + +# Visiting a function definition with default arguments +def test_function_with_default_arguments(): + # Initialize FunctionVisitor + visitor = FunctionVisitor() + + # Create AST for a function definition with default arguments + code = ast.parse("def my_function(arg1, arg2='default', arg3=123):\n pass") + + # Visit the AST + visitor.visit(code) + + # Assert that the function was added to the functions dictionary + assert "my_function" in visitor.functions + + # Assert the properties of the FunctionDef object + function_def = visitor.functions["my_function"] + assert function_def.name == "my_function" + assert function_def.args == "Unknown, Unknown, Unknown" + assert function_def.return_type == "Unknown" + assert ( + function_def.function_template + == "def my_function(arg1, arg2='default', arg3=123):\n pass" + ) + assert ( + function_def.function_code + == "def my_function(arg1, arg2='default', arg3=123):\n pass" + ) + + +# Visiting a function definition with a decorator +def test_visiting_function_with_decorator(): + # Initialize FunctionVisitor + visitor = FunctionVisitor() + + # Create AST for a function definition with a decorator + code = ast.parse("@decorator\ndef my_function():\n pass") + + # Visit the AST + visitor.visit(code) + + # Assert that the function was added to the functions dictionary + assert "my_function" in visitor.functions + + # Assert the properties of the FunctionDef object + function_def = visitor.functions["my_function"] + assert function_def.name == "my_function" + assert function_def.args == "" + assert function_def.return_type == "Unknown" + assert function_def.function_template == "@decorator\ndef my_function():\n pass" + assert function_def.function_code == "@decorator\ndef my_function():\n pass" + + +# Visiting a class definition with no Pydantic inheritance +def test_visiting_class_definition_no_pydantic_inheritance(): + # Initialize FunctionVisitor + visitor = FunctionVisitor() + + # Create AST for a class definition with no Pydantic inheritance + code = ast.parse("class MyClass:\n pass") + + # Visit the AST + visitor.visit(code) + + # Assert that the pydantic_classes list is empty + assert len(visitor.pydantic_classes) == 0 + + +# Visiting a class definition with Pydantic inheritance +def test_visiting_class_with_pydantic_inheritance(): + # Initialize FunctionVisitor + visitor = FunctionVisitor() + + # Create AST for a class definition with Pydantic inheritance + code = ast.parse("class MyClass(pydantic.BaseModel):\n pass") + + # Visit the AST + visitor.visit(code) + + # Assert that the class name was added to the list of Pydantic classes + assert "MyClass" in visitor.pydantic_classes + + +# Visiting an import statement with an alias +def test_visiting_import_statement_with_alias(): + # Initialize FunctionVisitor + visitor = FunctionVisitor() + + # Create AST for an import statement with an alias + code = ast.parse("import module as m") + + # Visit the AST + visitor.visit(code) + + # Assert that the import statement was added to the imports list + assert "import module as m" in visitor.imports + + +# Visiting an import statement with no alias +def test_visiting_import_statement_with_no_alias(): + # Initialize FunctionVisitor + visitor = FunctionVisitor() + + # Create AST for an import statement with no alias + code = ast.parse("import module") + + # Visit the AST + visitor.visit_Import(code.body[0]) + + # Assert that the import line was added to the imports list + assert visitor.imports == ["import module"] + + +# Visiting a function definition with annotations that are not strings or constants +def test_visiting_function_with_non_string_annotations(): + # Initialize FunctionVisitor + visitor = FunctionVisitor() + + # Create AST for a function definition with non-string annotations + code = ast.parse( + "def my_function(arg1: int, arg2: List[str]) -> Dict[str, int]:\n pass" + ) + + # Visit the AST + visitor.visit(code) + + # Assert that the function was added to the functions dictionary + assert "my_function" in visitor.functions + + # Assert the properties of the FunctionDef object + function_def = visitor.functions["my_function"] + assert function_def.name == "my_function" + assert function_def.args == "int, List[str]" + assert function_def.return_type == "Dict[str, int]" + assert ( + function_def.function_template + == "def my_function(arg1: int, arg2: List[str]) -> Dict[str, int]:\n pass" + ) + assert ( + function_def.function_code + == "def my_function(arg1: int, arg2: List[str]) -> Dict[str, int]:\n pass" + ) + + +# Visiting a function definition with a return annotation that is not a string or constant +def test_visiting_function_with_non_string_return_annotation(): + # Initialize FunctionVisitor + visitor = FunctionVisitor() + + # Create AST for a function definition with a non-string return annotation + code = ast.parse("def my_function() -> int:\n pass") + + # Visit the AST + visitor.visit(code) + + # Assert that the function was added to the functions dictionary + assert "my_function" in visitor.functions + + # Assert the properties of the FunctionDef object + function_def = visitor.functions["my_function"] + assert function_def.name == "my_function" + assert function_def.args == "" + assert function_def.return_type == "int" + assert function_def.function_template == "def my_function() -> int:\n pass" + assert function_def.function_code == "def my_function() -> int:\n pass" + + +# Visiting a class definition with a body that is not a list of statements +def test_visiting_class_definition_with_non_list_body(): + # Initialize FunctionVisitor + visitor = FunctionVisitor() + + # Create AST for a class definition with a non-list body + code = ast.parse("class MyClass:\n x = 1") + + # Visit the AST + visitor.visit(code) + + # Assert that the class was not added to the pydantic_classes list + assert "MyClass" not in visitor.pydantic_classes + + +# Visiting a function definition with a body that is not a list of statements +def test_visiting_function_with_non_list_body(): + # Initialize FunctionVisitor + visitor = FunctionVisitor() + + # Create AST for a function definition with a non-list body + code = ast.parse("def my_function():\n print('Hello, World!')") + + # Visit the AST + visitor.visit(code) + + # Assert that the function was added to the functions dictionary + assert "my_function" in visitor.functions + + # Assert the properties of the FunctionDef object + function_def = visitor.functions["my_function"] + assert function_def.name == "my_function" + assert function_def.args == "" + assert function_def.return_type == "Unknown" + assert function_def.function_template == "def my_function():\n pass" + assert ( + function_def.function_code == "def my_function():\n print('Hello, World!')" + ) From 55bc04114ba291eebc5feb3822c0160bd487745d Mon Sep 17 00:00:00 2001 From: SwiftyOS Date: Tue, 27 Feb 2024 09:18:49 +0100 Subject: [PATCH 6/8] Refactor pydantic class identification in FunctionVisitor --- codex/develop/develop.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/codex/develop/develop.py b/codex/develop/develop.py index f835a53..a90c51a 100644 --- a/codex/develop/develop.py +++ b/codex/develop/develop.py @@ -126,7 +126,11 @@ class FunctionVisitor(ast.NodeVisitor): for base in node.bases: base_id = getattr(base, "id", None) # This will only work for direct children of BaseModel - if base_id == "BaseModel" or "pydantic.BaseModel" in ast.unparse(base): + is_pydantic = ( + (isinstance(base, ast.Name) and base.id == "BaseModel") or + (isinstance(base, ast.Attribute) and base.attr == "BaseModel") + ) + if is_pydantic: self.pydantic_classes.append(node.name) self.generic_visit(node) From 9b8dc28c2f06e0f5490f25d034cfbf3bf2702a7b Mon Sep 17 00:00:00 2001 From: Swiftyos Date: Tue, 27 Feb 2024 08:19:08 +0000 Subject: [PATCH 7/8] style fixes by ruff --- codex/develop/develop.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/codex/develop/develop.py b/codex/develop/develop.py index a90c51a..faca692 100644 --- a/codex/develop/develop.py +++ b/codex/develop/develop.py @@ -126,9 +126,8 @@ class FunctionVisitor(ast.NodeVisitor): for base in node.bases: base_id = getattr(base, "id", None) # This will only work for direct children of BaseModel - is_pydantic = ( - (isinstance(base, ast.Name) and base.id == "BaseModel") or - (isinstance(base, ast.Attribute) and base.attr == "BaseModel") + is_pydantic = (isinstance(base, ast.Name) and base.id == "BaseModel") or ( + isinstance(base, ast.Attribute) and base.attr == "BaseModel" ) if is_pydantic: self.pydantic_classes.append(node.name) From 0ca37c25d6fcb9fb6fb302c35e4353e9a665abeb Mon Sep 17 00:00:00 2001 From: Zamil Majdy Date: Tue, 27 Feb 2024 15:00:34 +0400 Subject: [PATCH 8/8] Fix unimplemented function semantic (#58) * Fix unimplemented function semantic --------- Co-authored-by: majdyz Co-authored-by: majdyz Co-authored-by: Swifty --- codex/develop/agent.py | 4 ++- codex/develop/develop.py | 35 ++++++++++++++----- codex/develop/model.py | 1 + .../develop/python.system.j2 | 28 +++++++++------ .../gpt-4-0125-preview/develop/python.user.j2 | 24 +++++++------ codex/tests/api_tests.py | 4 +-- 6 files changed, 63 insertions(+), 33 deletions(-) diff --git a/codex/develop/agent.py b/codex/develop/agent.py index d58150b..3504366 100644 --- a/codex/develop/agent.py +++ b/codex/develop/agent.py @@ -2,6 +2,7 @@ import asyncio import logging import os +from prisma.enums import FunctionState from prisma.models import APIRouteSpec, CompletedApp, Function, Specification from codex.api_model import Identifiers @@ -78,7 +79,7 @@ async def develop_route( invoke_params={ "function_name": function_name, "goal": goal_description, - "description": function_template or "", + "function_signature": function_template, "provided_functions": [ f.template for f in generated_functions @@ -107,6 +108,7 @@ async def develop_route( generated_functions=generated_functions, ) for child in route_function.ChildFunction + if child.state == FunctionState.DEFINITION ] await asyncio.gather(*tasks) else: diff --git a/codex/develop/develop.py b/codex/develop/develop.py index faca692..c049f70 100644 --- a/codex/develop/develop.py +++ b/codex/develop/develop.py @@ -85,6 +85,10 @@ class FunctionVisitor(ast.NodeVisitor): self.imports.append(import_line) self.generic_visit(node) + # TODO(AGPT-425): + # - Add visit_ClassDef and parse input output complex types + # - Exclude function inside the class and 'unexpected' nested functions. + def visit_FunctionDef(self, node: ast.FunctionDef) -> None: args = [] for arg in node.args.args: @@ -93,27 +97,36 @@ class FunctionVisitor(ast.NodeVisitor): args_str = ", ".join(args) return_type = ast.unparse(node.returns) if node.returns else "Unknown" - # Extracting the function_template with doc_string if it exists - original_body = node.body.copy() + # Extract doc_string & function body + pass_block = ast.parse("pass").body[0] if ( node.body and isinstance(node.body[0], ast.Expr) and isinstance(node.body[0].value, (ast.Str, ast.Constant)) ): - node.body = node.body[:1] + doc_string_body = [node.body[0], pass_block] + code_body = node.body[1:] else: - node.body = [] + doc_string_body = [pass_block] + code_body = node.body - # add "pass" statement to the node.body - node.body.append(ast.parse("pass").body[0]) + # Construct function template + original_body = node.body.copy() + node.body = doc_string_body function_template = ast.unparse(node) node.body = original_body + # Function is not implemented if it has pass_block as its body + is_implemented = len(code_body) > 1 or ast.unparse(code_body[0]) != ast.unparse( + pass_block + ) + self.functions[node.name] = FunctionDef( name=node.name, - function_template=function_template, args=args_str, return_type=return_type, + is_implemented=is_implemented, + function_template=function_template, function_code=ast.unparse(node), ) self.generic_visit(node) @@ -182,7 +195,7 @@ class DevelopAIBlock(AIBlock): invoke_params["function_name"] ] - if "pass" in requested_func.function_code: + if not requested_func.is_implemented: # Important: ValidationErrors are used in the retry prompt raise ValidationError( "Main Function body is empty, it should contain" @@ -228,7 +241,11 @@ class DevelopAIBlock(AIBlock): functionName=value.name, template=value.function_template, apiRouteSpecId=generated_response.api_route_spec.id, - state=FunctionState.DEFINITION, + state=FunctionState.WRITTEN + if value.is_implemented + else FunctionState.DEFINITION, + rawCode=value.function_code, + functionCode=value.function_code, ) function_defs.append(model) diff --git a/codex/develop/model.py b/codex/develop/model.py index 0933409..4b7c553 100644 --- a/codex/develop/model.py +++ b/codex/develop/model.py @@ -15,6 +15,7 @@ class FunctionDef(BaseModel): name: str args: str return_type: str + is_implemented: bool function_template: str function_code: str diff --git a/codex/prompts/gpt-4-0125-preview/develop/python.system.j2 b/codex/prompts/gpt-4-0125-preview/develop/python.system.j2 index 0e73690..0546466 100644 --- a/codex/prompts/gpt-4-0125-preview/develop/python.system.j2 +++ b/codex/prompts/gpt-4-0125-preview/develop/python.system.j2 @@ -82,6 +82,8 @@ def convert_to_markdown(html: str) -> str: def convert_webpages(urls: List[str], format: str) -> List[str]: """ + ~ THIS IS THE REQUESTED FUNCTION, SO YOU HAVE TO FULLY IMPLEMENT THIS FUNCTION ~ + Converts a list of webpages to a specified format. This function takes a list of URLs and downloads the HTML content of each webpage. @@ -117,13 +119,19 @@ def convert_webpages(urls: List[str], format: str) -> List[str]: Thinking carefully step by step. Always start your answer with your analysis of the problem and possible problems. Then discuss the types of objects that maybe useful ## IMPORTANT -1. USE A SINGLE CODE BLOCK ("```python") FOR ALL PYTHON CODE (THIS IS MANDATORY) -2. THE GENERATED CODE HAS TO BE A WORKING CODE, NO SIMPLIFICATIONS OR INCOMPLETE CODE, UNIMPLEMENTED FUNCTIONS MUST BE STUBS. -3. CREATE STUB ONLY IF IT'S REALLY NECESSARY! TRY TO KEEP ONLY A SINGLE FUNCTION. KEEP THE CODE AS SIMPLE AS POSSIBLE WITH LESS STUBS AND ABSTRACTIONS. -4. ONLY PROVIDE THE STUB FUNCTIONS USED IN THE IMPLEMENTED FUNCTION, NO NEED TO PROVIDE THE OTHER STUB FUNCTIONS, JUST THE REQUESTED FUNCTION AND THE STUB FUNCTIONS. -5. USE A SINGLE REQUIREMENTS BLOCK ("```requirements") FOR ALL REQUIREMENTS CODE (THIS IS MANDATORY EVEN IF THERE ARE NO REQUIREMENTS) -6. IF THE FUNCTION USE NON-CORE PYTHON LIBS, ADD THE IMPORTS STATEMENTS, AND ADD THE LIBS TO THE REQUIREMENTS BLOCK. -7. YOU ARE CONTINUING AN ONGOING WORK, SO YOU ONLY NEED TO IMPLEMENT THE FUNCTIONALITY THAT IS REQUESTED, DON'T IMPLEMENT UNREQUESTED FUNCTIONALITY. -8. DOC STRING ON EACH FUNCTION AND STUB IS MANDATORY AND AS DETAILED AS POSSIBLE! ALWAYS DEFINE: Function description, `Args`, `Returns`, and `Example`, EVEN THE STUBS. FOR STUBS, THE LONGER THE DOC STRING, THE BETTER. -9. DO NOT CHANGE THE SIGNATURE OF THE FUNCTION, THE FUNCTION NAME, OR THE PARAMETER NAMES. THE FUNCTIONALITY MUST BE THE SAME AS THE ORIGINAL FUNCTION. -10. AVOID NESTED FUNCTIONS, THE STUBS AND FUNCTIONS MUST BE IN THE GLOBAL SCOPE. +* USE A SINGLE CODE BLOCK ("```python") FOR ALL PYTHON CODE, USE A SINGLE REQUIREMENTS BLOCK ("```requirements") FOR ALL REQUIREMENTS CODE (THIS IS MANDATORY) +{% if allow_stub %} +* THE GENERATED CODE HAS TO BE A WORKING CODE, NO SIMPLIFICATIONS OR INCOMPLETE CODE, UNIMPLEMENTED FUNCTIONS MUST BE STUBS. +* CREATE STUB ONLY IF IT'S REALLY NECESSARY! TRY TO KEEP ONLY A SINGLE FUNCTION. KEEP THE CODE AS SIMPLE AS POSSIBLE WITH LESS STUBS AND ABSTRACTIONS. +* ONLY PROVIDE THE STUB FUNCTIONS USED IN THE IMPLEMENTED FUNCTION, NO NEED TO PROVIDE THE OTHER STUB FUNCTIONS, JUST THE REQUESTED FUNCTION AND THE STUB FUNCTIONS. +* IMPORTANT: ALWAYS USE `pass` KEYWORD IN THE STUBS, DO NOT RETURN DUMMY VALUES, OR USE `...` OR `None` OR RAISE EXCEPTIONS. THE STUBS MUST BE EMPTY FUNCTIONS WITH DOC STRINGS and `pass` KEYWORD. +{% else %} +* IMPORTANT: FOR THIS GENERATION, CREATE ONLY ONE FUNCTION WITHOUT ANY STUBS. THE GENERATED FUNCTION HAS TO BE A WORKING CODE, NO SIMPLIFICATIONS OR INCOMPLETE CODE. +{% endif %} +* IF THE FUNCTION USE NON-CORE PYTHON LIBS, ADD THE IMPORTS STATEMENTS, AND ADD THE LIBS TO THE REQUIREMENTS BLOCK. +* YOU ARE CONTINUING AN ONGOING WORK, SO YOU ONLY NEED TO IMPLEMENT THE FUNCTIONALITY THAT IS REQUESTED, DON'T IMPLEMENT UNREQUESTED FUNCTIONALITY. +* DOC STRING ON EACH FUNCTION AND STUB IS MANDATORY AND AS DETAILED AS POSSIBLE! ALWAYS DEFINE: Function description, `Args`, `Returns`, and `Example`, EVEN THE STUBS. FOR STUBS, THE LONGER THE DOC STRING, THE BETTER. +* DO NOT CHANGE THE SIGNATURE OF THE FUNCTION, THE FUNCTION NAME, OR THE PARAMETER NAMES. THE FUNCTIONALITY MUST BE THE SAME AS THE ORIGINAL FUNCTION. IF THE REQUESTED FUNCTION IS ALREADY IMPLEMENTED, CHANGE IT ONLY IF IT'S REALLY NECESSARY. +* AVOID NESTED FUNCTIONS, THE STUBS AND FUNCTIONS MUST BE IN THE GLOBAL SCOPE. +* ONLY WRITE FUNCTIONS NOT CLASS, UNLESS IT'S DATA CLASS OR NAMEDTUPLE. +* NEVER USE DUMMY DATA OR GLOBAL VARIABLES! ALWAYS PASS WHAT'S NEEDED AS ARGUMENTS! NO HARDCODED VALUES! diff --git a/codex/prompts/gpt-4-0125-preview/develop/python.user.j2 b/codex/prompts/gpt-4-0125-preview/develop/python.user.j2 index 91e53be..1546bcc 100644 --- a/codex/prompts/gpt-4-0125-preview/develop/python.user.j2 +++ b/codex/prompts/gpt-4-0125-preview/develop/python.user.j2 @@ -1,12 +1,17 @@ -Main function name: {{ function_name }} -Main function detail: -{{ description }} +Create the working code implementation of function called: {{ function_name }} +{% if function_signature %} +With this function signature: +```python +{{ function_signature }} +``` +The created function has to match exactly as this signature! +{% endif %} +For additional context, this function that you need to implement will be used as part of a larger program for this goal: +"{{ goal }}". -The signature has to match exactly as the one in the description. -For additional context, this function that you need to implement will be used as part of a larger program for {{ goal }}. - ----- +NOTE: IMPLEMENT THE REQUIRED FUNCTION WITH A REAL CODE IMPLEMENTATION, NOT JUST A STUB, PLACEHOLDER, OR PSEUDOCODE! {% if provided_functions %} +---- You can re-use these functions without introducing a new stub: ```python {% for function in provided_functions %} @@ -17,8 +22,5 @@ You can re-use these functions without introducing a new stub: NOTE: DO NOT RE-WRITE THESE FUNCTIONS. JUST CALL IT IN THE FUNCTION THAT YOU WRITE (IF NEEDED). YOU SHOULD ONLY PRODUCE THE REQUIRED FUNCTION AND THE NEW STUBS (IF THERE IS ANY). -{% endif %} - -{% if not allow_stub %} -IMPORTANT: FOR THIS GENERATION, CREATE ONLY ONE FUNCTION WITHOUT ANY STUBS. +---- {% endif %} diff --git a/codex/tests/api_tests.py b/codex/tests/api_tests.py index 253a9e3..6e8d65b 100644 --- a/codex/tests/api_tests.py +++ b/codex/tests/api_tests.py @@ -119,8 +119,8 @@ async def test_recursive_create_code_graphs(): setup_logging(local=True) ids = Identifiers( - user_id="123e4567-e89b-12d3-a456-426614174000", - app_id="d3954dee-6b41-47f5-be2f-a253f7544a59", + user_id=user_id_1, + app_id=app_id_1, ) spec = await get_latest_specification(ids.user_id, ids.app_id) ans = await agent.develop_application(ids=ids, spec=spec)