Skip to content

Commit 0c2fc69

Browse files
committed
Added prepare_implementation_information and prepare_conformance_test_fix actions.
1 parent 9ab2a69 commit 0c2fc69

13 files changed

Lines changed: 170 additions & 47 deletions

codeplain_REST_api.py

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

367367
return self.post_request(endpoint_url, headers, payload, run_state)
368368

369+
def prepare_conformance_test_fix(
370+
self,
371+
frid,
372+
functional_requirement_id,
373+
plain_source_tree,
374+
linked_resources,
375+
existing_files_content,
376+
memory_files_content,
377+
module_name: str,
378+
conformance_tests_module_name: str,
379+
required_modules,
380+
code_diff,
381+
conformance_tests_files,
382+
acceptance_tests,
383+
conformance_tests_issue,
384+
implementation_fix_count,
385+
conformance_tests_folder_name,
386+
current_testing_frid_high_level_implementation_plan: Optional[str],
387+
run_state: RunState,
388+
prepare_conformance_test_fix_script: str,
389+
) -> dict:
390+
endpoint_url = f"{self.api_url}/prepare_conformance_test_fix"
391+
headers = {"X-API-Key": self.api_key, "Content-Type": "application/json"}
392+
393+
payload = {
394+
"frid": frid,
395+
"functional_requirement_id": functional_requirement_id,
396+
"plain_source_tree": plain_source_tree,
397+
"linked_resources": linked_resources,
398+
"existing_files_content": existing_files_content,
399+
"memory_files_content": memory_files_content,
400+
"module_name": module_name,
401+
"conformance_tests_module_name": conformance_tests_module_name,
402+
"required_modules": required_modules,
403+
"code_diff": code_diff,
404+
"conformance_tests_files": conformance_tests_files,
405+
"conformance_tests_issue": conformance_tests_issue,
406+
"implementation_fix_count": implementation_fix_count,
407+
"conformance_tests_folder_name": conformance_tests_folder_name,
408+
"current_testing_frid_high_level_implementation_plan": current_testing_frid_high_level_implementation_plan,
409+
"prepare_conformance_test_fix_script": prepare_conformance_test_fix_script,
410+
}
411+
412+
if acceptance_tests is not None:
413+
payload["acceptance_tests"] = acceptance_tests
414+
415+
return self.post_request(endpoint_url, headers, payload, run_state)
416+
369417
def fix_conformance_tests_issue(
370418
self,
371419
frid,
@@ -385,6 +433,7 @@ def fix_conformance_tests_issue(
385433
conformance_tests_folder_name,
386434
current_testing_frid_high_level_implementation_plan: Optional[str],
387435
run_state: RunState,
436+
conformance_test_fix_information: Optional[str] = None,
388437
):
389438
endpoint_url = f"{self.api_url}/fix_conformance_tests_issue"
390439
headers = {"X-API-Key": self.api_key, "Content-Type": "application/json"}
@@ -410,6 +459,9 @@ def fix_conformance_tests_issue(
410459
if acceptance_tests is not None:
411460
payload["acceptance_tests"] = acceptance_tests
412461

462+
if conformance_test_fix_information is not None:
463+
payload["conformance_test_fix_information"] = conformance_test_fix_information
464+
413465
return self.post_request(endpoint_url, headers, payload, run_state)
414466

415467
def render_acceptance_tests(

module_renderer.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ def _build_render_context_for_module(
175175
prepare_environment_script=self.args.prepare_environment_script,
176176
prepare_implementation_script=self.args.prepare_implementation_script,
177177
copy_build=self.args.copy_build,
178+
prepare_conformance_test_fix_script=self.args.prepare_conformance_test_fix_script,
178179
copy_conformance_tests=self.args.copy_conformance_tests,
179180
render_range=render_range,
180181
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
@@ -100,6 +100,7 @@ def execute(self, render_context: RenderContext, previous_action_payload: Any |
100100
render_context.conformance_tests_running_context.get_current_conformance_test_folder_name(),
101101
render_context.conformance_tests_running_context.current_testing_frid_high_level_implementation_plan,
102102
run_state=render_context.run_state,
103+
conformance_test_fix_information=render_context.conformance_tests_running_context.conformance_test_fix_information,
103104
)
104105
code_diff_files_content = {}
105106

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/actions/render_conformance_tests.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ def _render_conformance_tests(self, render_context: RenderContext):
3737
f"[{console.INFO_STYLE}]Generating folder name for conformance tests for functionality {render_context.conformance_tests_running_context.current_testing_frid}...\n"
3838
):
3939
fr_subfolder_name = render_context.codeplain_api.generate_folder_name_from_functional_requirement(
40-
frid=render_context.conformance_tests_running_context.current_testing_frid,
41-
module_name=render_context.conformance_tests_running_context.current_testing_module_name,
40+
frid=render_context.frid_context.frid,
41+
module_name=render_context.module_name,
4242
functional_requirement=render_context.conformance_tests_running_context.current_testing_frid_specifications[
4343
plain_spec.FUNCTIONAL_REQUIREMENTS
4444
][

render_machine/render_context.py

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ def __init__(
5656
test_script_timeout: Optional[int] = None,
5757
stop_event: Optional[threading.Event] = None,
5858
enter_pause_event: Optional[threading.Event] = None,
59+
prepare_conformance_test_fix_script: Optional[str] = None,
5960
):
6061
self.codeplain_api: CodeplainAPI = codeplain_api
6162
self.memory_manager = memory_manager
@@ -71,6 +72,7 @@ def __init__(
7172
self.conformance_tests_script = conformance_tests_script
7273
self.prepare_environment_script = prepare_environment_script
7374
self.prepare_implementation_script = prepare_implementation_script
75+
self.prepare_conformance_test_fix_script = prepare_conformance_test_fix_script
7476
self.copy_build = copy_build
7577
self.copy_conformance_tests = copy_conformance_tests
7678
self.render_range = render_range
@@ -348,6 +350,10 @@ def start_prepare_implementation_information(self):
348350
if self.prepare_implementation_script is None:
349351
self.machine.dispatch(triggers.MARK_IMPLEMENTATION_INFORMATION_PREPARED)
350352

353+
def start_prepare_conformance_test_fix(self):
354+
if self.prepare_conformance_test_fix_script is None:
355+
self.machine.dispatch(triggers.MARK_CONFORMANCE_TEST_FIX_PREPARED)
356+
351357
def start_testing_environment_preparation(self):
352358
if (
353359
self.prepare_environment_script is None
@@ -399,10 +405,15 @@ def start_conformance_tests_for_frid(self):
399405
) or self.conformance_tests_running_context.conformance_test_phase_index == len(
400406
self.frid_context.specifications[plain_spec.ACCEPTANCE_TESTS]
401407
):
402-
self.machine.dispatch(triggers.MARK_ALL_CONFORMANCE_TESTS_PASSED)
403-
return
404-
if self.conformance_tests_running_context.conformance_test_phase_index == 0:
405-
self.conformance_tests_running_context.current_testing_frid_high_level_implementation_plan = None
408+
# All phases done — start regression run over earlier FRIDs
409+
self.conformance_tests_running_context.regression_run_started = True
410+
self.conformance_tests_running_context.current_testing_frid = None
411+
# fall through to get_first below
412+
else:
413+
if self.conformance_tests_running_context.conformance_test_phase_index == 0:
414+
self.conformance_tests_running_context.current_testing_frid_high_level_implementation_plan = (
415+
None
416+
)
406417

407418
self.conformance_tests_running_context.conformance_test_phase_index += 1
408419
current_acceptance_tests = self.frid_context.specifications[plain_spec.ACCEPTANCE_TESTS][

render_machine/render_types.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ def __init__(
5252
self.previous_conformance_tests_issue_frid: Optional[str] = None
5353
self.previous_conformance_tests_issue_module: Optional[str] = None
5454
self.code_diff_files: Optional[dict[str, str]] = None
55+
self.conformance_test_fix_information: Optional[str] = None
5556

5657
def get_conformance_tests_json(self, module_name: str) -> dict:
5758
return self._conformance_tests_json[module_name]
@@ -109,6 +110,7 @@ class ScriptExecutionHistory:
109110
latest_conformance_test_output_path: Optional[str] = None
110111
latest_testing_environment_output_path: Optional[str] = None
111112
latest_prepare_implementation_output_path: Optional[str] = None
113+
latest_prepare_conformance_test_fix_output_path: Optional[str] = None
112114
should_update_script_outputs: bool = False
113115

114116

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

0 commit comments

Comments
 (0)