Skip to content

Commit 2a5fddc

Browse files
committed
Added prepare_implementation_information and prepare_conformance_test_fix actions.
1 parent af8ad9a commit 2a5fddc

12 files changed

Lines changed: 159 additions & 41 deletions

codeplain_REST_api.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,54 @@ def generate_folder_name_from_functional_requirement(
384384

385385
return self.post_request(endpoint_url, headers, payload, run_state)
386386

387+
def prepare_conformance_test_fix(
388+
self,
389+
frid,
390+
functional_requirement_id,
391+
plain_source_tree,
392+
linked_resources,
393+
existing_files_content,
394+
memory_files_content,
395+
module_name: str,
396+
conformance_tests_module_name: str,
397+
required_modules,
398+
code_diff,
399+
conformance_tests_files,
400+
acceptance_tests,
401+
conformance_tests_issue,
402+
implementation_fix_count,
403+
conformance_tests_folder_name,
404+
current_testing_frid_high_level_implementation_plan: Optional[str],
405+
run_state: RunState,
406+
prepare_conformance_test_fix_script: str,
407+
) -> dict:
408+
endpoint_url = f"{self.api_url}/prepare_conformance_test_fix"
409+
headers = {"X-API-Key": self.api_key, "Content-Type": "application/json"}
410+
411+
payload = {
412+
"frid": frid,
413+
"functional_requirement_id": functional_requirement_id,
414+
"plain_source_tree": plain_source_tree,
415+
"linked_resources": linked_resources,
416+
"existing_files_content": existing_files_content,
417+
"memory_files_content": memory_files_content,
418+
"module_name": module_name,
419+
"conformance_tests_module_name": conformance_tests_module_name,
420+
"required_modules": required_modules,
421+
"code_diff": code_diff,
422+
"conformance_tests_files": conformance_tests_files,
423+
"conformance_tests_issue": conformance_tests_issue,
424+
"implementation_fix_count": implementation_fix_count,
425+
"conformance_tests_folder_name": conformance_tests_folder_name,
426+
"current_testing_frid_high_level_implementation_plan": current_testing_frid_high_level_implementation_plan,
427+
"prepare_conformance_test_fix_script": prepare_conformance_test_fix_script,
428+
}
429+
430+
if acceptance_tests is not None:
431+
payload["acceptance_tests"] = acceptance_tests
432+
433+
return self.post_request(endpoint_url, headers, payload, run_state)
434+
387435
def fix_conformance_tests_issue(
388436
self,
389437
frid,
@@ -404,6 +452,7 @@ def fix_conformance_tests_issue(
404452
current_testing_frid_high_level_implementation_plan: Optional[str],
405453
conflicting_requirements_count: int,
406454
run_state: RunState,
455+
conformance_test_fix_information: Optional[str] = None,
407456
):
408457
endpoint_url = f"{self.api_url}/fix_conformance_tests_issue"
409458
headers = {"X-API-Key": self.api_key, "Content-Type": "application/json"}
@@ -430,6 +479,9 @@ def fix_conformance_tests_issue(
430479
if acceptance_tests is not None:
431480
payload["acceptance_tests"] = acceptance_tests
432481

482+
if conformance_test_fix_information is not None:
483+
payload["conformance_test_fix_information"] = conformance_test_fix_information
484+
433485
return self.post_request(endpoint_url, headers, payload, run_state)
434486

435487
def render_acceptance_tests(

module_renderer.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,7 @@ def _build_render_context_for_module(
179179
prepare_environment_script=self.args.prepare_environment_script,
180180
prepare_implementation_script=self.args.prepare_implementation_script,
181181
copy_build=self.args.copy_build,
182+
prepare_conformance_test_fix_script=self.args.prepare_conformance_test_fix_script,
182183
copy_conformance_tests=self.args.copy_conformance_tests,
183184
render_range=render_range,
184185
render_conformance_tests=self.args.render_conformance_tests,

plain2code_arguments.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
DEFAULT_LOG_FILE_NAME = "codeplain.log"
2020
PREPARE_ENVIRONMENT_SCRIPT_NAME = "prepare_environment_script"
2121
PREPARE_IMPLEMENTATION_SCRIPT_NAME = "prepare_implementation_script"
22+
PREPARE_CONFORMANCE_TEST_FIX_SCRIPT_NAME = "prepare_conformance_test_fix_script"
2223

2324

2425
def process_test_script_path(script_arg_name, config):
@@ -261,6 +262,14 @@ def create_parser():
261262
"and should print the LLM response to stdout.",
262263
)
263264

265+
parser.add_argument(
266+
"--prepare-conformance-test-fix-script",
267+
type=str,
268+
help="Path to a shell script that queries an LLM to produce additional information before fixing a conformance test. "
269+
"The script receives a path to a file containing LLM query instructions as its first argument "
270+
"and should print the LLM response to stdout.",
271+
)
272+
264273
parser.add_argument(
265274
"--test-script-timeout",
266275
type=int,
@@ -380,7 +389,13 @@ def parse_arguments():
380389
if args.full_plain and args.dry_run:
381390
parser.error("--full-plain and --dry-run are mutually exclusive")
382391

383-
script_arg_names = [UNIT_TESTS_SCRIPT_NAME, CONFORMANCE_TESTS_SCRIPT_NAME, PREPARE_ENVIRONMENT_SCRIPT_NAME, PREPARE_IMPLEMENTATION_SCRIPT_NAME]
392+
script_arg_names = [
393+
UNIT_TESTS_SCRIPT_NAME,
394+
CONFORMANCE_TESTS_SCRIPT_NAME,
395+
PREPARE_ENVIRONMENT_SCRIPT_NAME,
396+
PREPARE_IMPLEMENTATION_SCRIPT_NAME,
397+
PREPARE_CONFORMANCE_TEST_FIX_SCRIPT_NAME,
398+
]
384399
for script_name in script_arg_names:
385400
args = process_test_script_path(script_name, args)
386401

render_machine/actions/fix_conformance_test.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ def execute(self, render_context: RenderContext, previous_action_payload: Any |
112112
render_context.conformance_tests_running_context.current_testing_frid_high_level_implementation_plan,
113113
render_context.conformance_tests_running_context.conflicting_requirement_count,
114114
run_state=render_context.run_state,
115+
conformance_test_fix_information=render_context.conformance_tests_running_context.conformance_test_fix_information,
115116
)
116117
code_diff_files_content = {}
117118

Lines changed: 19 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
1-
import os
2-
import tempfile
31
from typing import Any
42

53
import render_machine.render_utils as render_utils
64
from memory_management import MemoryManager
7-
from plain2code_console import console
85
from render_machine.actions.base_action import BaseAction
96
from render_machine.implementation_code_helpers import ImplementationCodeHelpers
107
from render_machine.render_context import RenderContext
@@ -16,12 +13,6 @@ class PrepareImplementationInformation(BaseAction):
1613
FAILED_OUTCOME = "implementation_information_preparation_failed"
1714

1815
def execute(self, render_context: RenderContext, _previous_action_payload: Any | None):
19-
if render_context.verbose:
20-
console.info(
21-
f"Running prepare_implementation_script {render_context.prepare_implementation_script} "
22-
f"for FRID {render_context.frid_context.frid}."
23-
)
24-
2516
_, existing_files_content = ImplementationCodeHelpers.fetch_existing_files(render_context.build_folder)
2617
_, memory_files_content = MemoryManager.fetch_memory_files(render_context.memory_manager.memory_folder)
2718

@@ -42,36 +33,27 @@ def execute(self, render_context: RenderContext, _previous_action_payload: Any |
4233
)
4334
instructions = api_response.get("instructions", "")
4435

45-
tmp_path = None
46-
try:
47-
with tempfile.NamedTemporaryFile(mode="w", suffix=".txt", delete=False, encoding="utf-8") as tmp:
48-
tmp.write(instructions)
49-
tmp_path = tmp.name
50-
51-
exit_code, implementation_information, script_output_path = render_utils.execute_script(
52-
render_context.prepare_implementation_script,
53-
[tmp_path],
54-
render_context.verbose,
55-
"Prepare Implementation Information",
56-
timeout=render_context.test_script_timeout,
57-
stop_event=render_context.stop_event,
58-
)
59-
finally:
60-
if tmp_path and os.path.exists(tmp_path):
61-
os.unlink(tmp_path)
36+
exit_code, implementation_information, script_output_path = render_utils.execute_script(
37+
render_context.prepare_implementation_script,
38+
[instructions],
39+
render_context.verbose,
40+
"Prepare Implementation Information",
41+
timeout=render_context.test_script_timeout,
42+
stop_event=render_context.stop_event,
43+
)
6244

63-
if exit_code == 0:
45+
if exit_code == 0 or exit_code == render_utils.TIMEOUT_ERROR_EXIT_CODE:
6446
render_context.frid_context.implementation_information = implementation_information
6547
render_context.script_execution_history.latest_prepare_implementation_output_path = script_output_path
6648
render_context.script_execution_history.should_update_script_outputs = True
6749
return self.SUCCESSFUL_OUTCOME, None
68-
else:
69-
return (
70-
self.FAILED_OUTCOME,
71-
RenderError.encode(
72-
message="Prepare implementation information failed. Please check the prepare_implementation_script.",
73-
error_type="PREPARE_IMPLEMENTATION_ERROR",
74-
exit_code=exit_code,
75-
script=render_context.prepare_implementation_script,
76-
).to_payload(),
77-
)
50+
51+
return (
52+
self.FAILED_OUTCOME,
53+
RenderError.encode(
54+
message="Prepare implementation information failed. Please check the prepare_implementation_script.",
55+
error_type="PREPARE_IMPLEMENTATION_ERROR",
56+
exit_code=exit_code,
57+
script=render_context.prepare_implementation_script,
58+
).to_payload(),
59+
)

render_machine/render_context.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ def __init__(
5858
test_script_timeout: Optional[int] = None,
5959
stop_event: Optional[threading.Event] = None,
6060
enter_pause_event: Optional[threading.Event] = None,
61+
prepare_conformance_test_fix_script: Optional[str] = None,
6162
):
6263
self.codeplain_api: CodeplainAPI = codeplain_api
6364
self.memory_manager = memory_manager
@@ -73,6 +74,7 @@ def __init__(
7374
self.conformance_tests_script = conformance_tests_script
7475
self.prepare_environment_script = prepare_environment_script
7576
self.prepare_implementation_script = prepare_implementation_script
77+
self.prepare_conformance_test_fix_script = prepare_conformance_test_fix_script
7678
self.copy_build = copy_build
7779
self.copy_conformance_tests = copy_conformance_tests
7880
self.render_range = render_range
@@ -349,6 +351,10 @@ def start_prepare_implementation_information(self):
349351
if self.prepare_implementation_script is None:
350352
self.machine.dispatch(triggers.MARK_IMPLEMENTATION_INFORMATION_PREPARED)
351353

354+
def start_prepare_conformance_test_fix(self):
355+
if self.prepare_conformance_test_fix_script is None:
356+
self.machine.dispatch(triggers.MARK_CONFORMANCE_TEST_FIX_PREPARED)
357+
352358
def start_testing_environment_preparation(self):
353359
if (
354360
self.prepare_environment_script is None

render_machine/render_types.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ def __init__(
9595
self.previous_conformance_tests_issue_frid: Optional[str] = None
9696
self.previous_conformance_tests_issue_module: Optional[str] = None
9797
self.code_diff_files: Optional[dict[str, str]] = None
98+
self.conformance_test_fix_information: Optional[str] = None
9899

99100
def get_conformance_tests_json(self, module_name: str) -> dict:
100101
return self._conformance_tests_json[module_name]
@@ -157,6 +158,7 @@ class ScriptExecutionHistory:
157158
latest_conformance_test_output_path: Optional[str] = None
158159
latest_testing_environment_output_path: Optional[str] = None
159160
latest_prepare_implementation_output_path: Optional[str] = None
161+
latest_prepare_conformance_test_fix_output_path: Optional[str] = None
160162
should_update_script_outputs: bool = False
161163

162164

render_machine/state_machine_config.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,9 @@
1818
from render_machine.actions.finish_functional_requirement import FinishFunctionalRequirement
1919
from render_machine.actions.fix_conformance_test import FixConformanceTest
2020
from render_machine.actions.fix_unit_tests import FixUnitTests
21-
from render_machine.actions.prepare_repositories import PrepareRepositories
21+
from render_machine.actions.prepare_conformance_test_fix import PrepareConformanceTestFix
2222
from render_machine.actions.prepare_implementation_information import PrepareImplementationInformation
23+
from render_machine.actions.prepare_repositories import PrepareRepositories
2324
from render_machine.actions.prepare_testing_environment import PrepareTestingEnvironment
2425
from render_machine.actions.refactor_code import RefactorCode
2526
from render_machine.actions.render_conformance_tests import RenderConformanceTests
@@ -94,6 +95,7 @@ def get_action_map(self) -> Dict[str, Any]:
9495
f"{States.IMPLEMENTING_FRID.value}_{States.PROCESSING_CONFORMANCE_TESTS.value}_{States.CONFORMANCE_TESTING_INITIALISED.value}": RenderConformanceTests(),
9596
f"{States.IMPLEMENTING_FRID.value}_{States.PROCESSING_CONFORMANCE_TESTS.value}_{States.CONFORMANCE_TEST_GENERATED.value}": PrepareTestingEnvironment(),
9697
f"{States.IMPLEMENTING_FRID.value}_{States.PROCESSING_CONFORMANCE_TESTS.value}_{States.CONFORMANCE_TEST_ENV_PREPARED.value}": RunConformanceTests(),
98+
f"{States.IMPLEMENTING_FRID.value}_{States.PROCESSING_CONFORMANCE_TESTS.value}_{States.PREPARE_CONFORMANCE_TEST_FIX.value}": PrepareConformanceTestFix(),
9799
f"{States.IMPLEMENTING_FRID.value}_{States.PROCESSING_CONFORMANCE_TESTS.value}_{States.CONFORMANCE_TEST_FAILED.value}": FixConformanceTest(),
98100
f"{States.IMPLEMENTING_FRID.value}_{States.PROCESSING_CONFORMANCE_TESTS.value}_{States.POSTPROCESSING_CONFORMANCE_TESTS.value}_{States.CONFORMANCE_TESTS_READY_FOR_SUMMARY.value}": SummarizeConformanceTests(),
99101
f"{States.IMPLEMENTING_FRID.value}_{States.PROCESSING_CONFORMANCE_TESTS.value}_{States.POSTPROCESSING_CONFORMANCE_TESTS.value}_{States.CONFORMANCE_TESTS_READY_FOR_COMMIT.value}": CommitConformanceTestsChanges(
@@ -133,6 +135,8 @@ def get_action_result_triggers_map(self) -> Dict[str, str]:
133135
RunConformanceTests.SUCCESSFUL_OUTCOME: triggers.MOVE_TO_NEXT_CONFORMANCE_TEST,
134136
RunConformanceTests.FAILED_OUTCOME: triggers.MARK_CONFORMANCE_TESTS_FAILED,
135137
RunConformanceTests.UNRECOVERABLE_ERROR_OUTCOME: triggers.HANDLE_ERROR,
138+
PrepareConformanceTestFix.SUCCESSFUL_OUTCOME: triggers.MARK_CONFORMANCE_TEST_FIX_PREPARED,
139+
PrepareConformanceTestFix.FAILED_OUTCOME: triggers.HANDLE_ERROR,
136140
FixConformanceTest.IMPLEMENTATION_CODE_NOT_UPDATED: triggers.MARK_CONFORMANCE_TESTS_READY,
137141
FixConformanceTest.IMPLEMENTATION_CODE_UPDATED: triggers.MARK_UNIT_TESTS_READY,
138142
CommitConformanceTestsChanges.SUCCESSFUL_OUTCOME_IMPLEMENTATION_UPDATED: triggers.MARK_NEXT_CONFORMANCE_TESTS_POSTPROCESSING_STEP,
@@ -190,6 +194,10 @@ def get_processing_conformance_tests_states(self, render_context: RenderContext)
190194
"on_enter": "start_testing_environment_preparation",
191195
},
192196
States.CONFORMANCE_TEST_ENV_PREPARED.value,
197+
{
198+
"name": States.PREPARE_CONFORMANCE_TEST_FIX.value,
199+
"on_enter": "start_prepare_conformance_test_fix",
200+
},
193201
{
194202
"name": States.CONFORMANCE_TEST_FAILED.value,
195203
"on_enter": "start_fixing_conformance_tests",
@@ -403,6 +411,11 @@ def get_transitions(self) -> List[Dict[str, Any]]:
403411
{
404412
"source": f"{States.IMPLEMENTING_FRID.value}_{States.PROCESSING_CONFORMANCE_TESTS.value}_{States.CONFORMANCE_TEST_ENV_PREPARED.value}",
405413
"trigger": triggers.MARK_CONFORMANCE_TESTS_FAILED,
414+
"dest": f"{States.IMPLEMENTING_FRID.value}_{States.PROCESSING_CONFORMANCE_TESTS.value}_{States.PREPARE_CONFORMANCE_TEST_FIX.value}",
415+
},
416+
{
417+
"source": f"{States.IMPLEMENTING_FRID.value}_{States.PROCESSING_CONFORMANCE_TESTS.value}_{States.PREPARE_CONFORMANCE_TEST_FIX.value}",
418+
"trigger": triggers.MARK_CONFORMANCE_TEST_FIX_PREPARED,
406419
"dest": f"{States.IMPLEMENTING_FRID.value}_{States.PROCESSING_CONFORMANCE_TESTS.value}_{States.CONFORMANCE_TEST_FAILED.value}",
407420
},
408421
{

render_machine/states.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ class States(Enum):
4141
CONFORMANCE_TESTING_INITIALISED = "conformanceTestingInitialised"
4242
CONFORMANCE_TEST_GENERATED = "conformanceTestGenerated"
4343
CONFORMANCE_TEST_ENV_PREPARED = "conformanceTestEnvironmentPrepared"
44+
PREPARE_CONFORMANCE_TEST_FIX = "prepareConformanceTestFix"
4445
CONFORMANCE_TEST_FAILED = "conformanceTestFailed"
4546

4647
# Postprocessing conformance tests states

render_machine/triggers.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,4 @@
2525
MARK_ALL_CONFORMANCE_TESTS_PASSED = "mark_all_conformance_tests_passed"
2626
MARK_REGENERATION_OF_CONFORMANCE_TESTS = "mark_regeneration_of_conformance_tests"
2727
MARK_NEXT_CONFORMANCE_TESTS_POSTPROCESSING_STEP = "mark_next_conformance_tests_postprocessing_step"
28+
MARK_CONFORMANCE_TEST_FIX_PREPARED = "mark_conformance_test_fix_prepared"

0 commit comments

Comments
 (0)