codeplain 0.1.5__py3-none-any.whl → 0.1.7__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: codeplain
3
- Version: 0.1.5
3
+ Version: 0.1.7
4
4
  Summary: Transform plain language specifications into working code
5
5
  Classifier: Environment :: Console
6
6
  Classifier: Intended Audience :: Developers
@@ -12,7 +12,6 @@ License-File: LICENSE
12
12
  Requires-Dist: python-liquid2==0.3.0
13
13
  Requires-Dist: mistletoe==1.3.0
14
14
  Requires-Dist: requests==2.32.3
15
- Requires-Dist: rich==13.9.4
16
15
  Requires-Dist: tiktoken==0.12.0
17
16
  Requires-Dist: PyYAML==6.0.2
18
17
  Requires-Dist: gitpython==3.1.42
@@ -26,10 +25,6 @@ Requires-Dist: pytest==8.3.5; extra == "dev"
26
25
  Requires-Dist: flake8==7.0.0; extra == "dev"
27
26
  Requires-Dist: black==24.2.0; extra == "dev"
28
27
  Requires-Dist: isort==5.13.2; extra == "dev"
29
- Requires-Dist: flake8-bugbear==24.12.12; extra == "dev"
30
- Requires-Dist: flake8-unused-arguments==0.0.13; extra == "dev"
31
- Requires-Dist: flake8-eradicate==1.5.0; extra == "dev"
32
- Requires-Dist: pep8-naming==0.15.1; extra == "dev"
33
28
  Requires-Dist: mypy==1.11.2; extra == "dev"
34
29
  Dynamic: license-file
35
30
 
@@ -1,11 +1,11 @@
1
- codeplain_REST_api.py,sha256=VlL0I2-6u8DpMV9DJFQVlnzX2Vko8a4o6iARXG_SN6M,16237
1
+ codeplain_REST_api.py,sha256=qfzUw9v0-NKII4ibw3vqSBrCeU2WP4RcrrEti43F3zs,18400
2
2
  concept_utils.py,sha256=vwSY4-FmxyqaDBxhntYzqG8t9pXvAWwiULP0DYQI32o,7905
3
3
  event_bus.py,sha256=sduIR3bgIbxAbLhwKd8Gx9YN9gzaeqy9-mNupS04aKw,1759
4
- file_utils.py,sha256=9kUbndoxfOABmxvciPtqkseCB_cwCy4X4_L9ahY8paE,11335
4
+ file_utils.py,sha256=4BIxzsteZQOaK-efkvQcoaIfYydsQNFR6elpsxJgXLQ,11591
5
5
  git_utils.py,sha256=gTRps6RIzJJkyy9amaDxP38FPoxYulZViBWr9V0IPQg,12414
6
6
  hash_key.py,sha256=lMKgKpOhPeC4UpFf9e7eCNK20FEaDsXTCJ8j3eCWidE,837
7
- module_renderer.py,sha256=U3lQbLtTBkb5mJ_2YnL9SIQ6eJbv6XuiP0_fwOliWOs,6024
8
- plain2code.py,sha256=lYiF5R4h2HGEfZrKT6Wyidl2Omo-cCf5HhpHsUEiWDM,9492
7
+ module_renderer.py,sha256=LLjLb34phSJlF2YblwGDy5HKWVdi9mo57rr7s-Hj3RA,6261
8
+ plain2code.py,sha256=b0VJBnYVtpVZPx1TQZHNsnXREbhdW8V_S8TC-wWQqWw,8970
9
9
  plain2code_arguments.py,sha256=DHbkWyB33zifROt2SQMlGUC1AZIDJXoJQHlK7Za9b7U,12024
10
10
  plain2code_console.py,sha256=-QorOFimS1AWYK7dmFqI3uhjc51cPtEWsaK4DhFibIw,4139
11
11
  plain2code_events.py,sha256=5fPhpRzgJ02xWh0MXqrMv9A4curr2UOE68Y1uKlAcqQ,1347
@@ -16,19 +16,20 @@ plain2code_read_config.py,sha256=QnpbW_Bi9LzDIOubM5x7fVXH1HgiFL3-5Oa_O1EUoE4,244
16
16
  plain2code_state.py,sha256=InLXdytMXnm9YC4o8MSTbtB1TmqYYUs6rASGBlyA_YY,1274
17
17
  plain2code_utils.py,sha256=3xPXWci5yVdpdK_WrNcbinSV94XSeMQDW5UzDuBMaUM,1767
18
18
  plain_file.py,sha256=OXbWvErVTVhaeRFUu9f0bzi16P01DShW_jLhNI-tmeA,28931
19
- plain_modules.py,sha256=9UC1kC0dObeNpg3gVmX9Uqc6kJEHclOrtOL3l5to0T0,4837
19
+ plain_modules.py,sha256=iDqqamtix5KahMC_v-vfQ7yndugmqtBW1z6XxTB4x6w,4876
20
20
  plain_spec.py,sha256=zC-VOb_UJOs8OxtEiwQJuonw7Lkmbi7YHyFvvCvUZNo,13529
21
21
  spinner.py,sha256=Ro6Gd9Przf-whuHqPRY6HwI0T57yJjyNPbhDbigZKZE,2471
22
22
  system_config.py,sha256=mgHLn-CRHLO9Y9vKyI_eFBreY_YhFad-ctZgBYp-rIg,1777
23
- codeplain-0.1.5.dist-info/licenses/LICENSE,sha256=wsFi5dpbJurnRNfBj8q2RCcF3ryrmdRIfxc3lPcmc4c,1069
24
- config/__init__.py,sha256=iHrUksORYKKYsPhE2D_zvZ5tV7mfFAp16c_Cp38hT7A,38
23
+ codeplain-0.1.7.dist-info/licenses/LICENSE,sha256=wsFi5dpbJurnRNfBj8q2RCcF3ryrmdRIfxc3lPcmc4c,1069
24
+ config/__init__.py,sha256=beYSsJWmBNHDP5rYmVDouqgEeP3t1lkkepbXJ-oq0F8,37
25
25
  config/system_config.yaml,sha256=bB5Th5jxgXFyaIvceUPID1ReebMMXsyMibV4gtu9sWQ,1148
26
+ render_machine/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
26
27
  render_machine/code_renderer.py,sha256=jOoYivkZzCuGG947YlNPlvD1Dpd2xTWVK8pwfF_OqDU,2957
27
28
  render_machine/conformance_test_helpers.py,sha256=6Ru7Dh24SLNIKWfz_sP5hE_EmWpvk6nfgN1T1yaCZus,2887
28
- render_machine/conformance_tests.py,sha256=XRZ4RRz7mrSTdVF8xbDPckB_5ZuwH3shz-8MbeVTdws,6883
29
+ render_machine/conformance_tests.py,sha256=M0dMCawkUljMLwnf-9BLzjyKKJjfxmxJ4wUFyJX0hHU,7155
29
30
  render_machine/implementation_code_helpers.py,sha256=KctilT0x07niph0IWgKwP7ACXw8KJyErhJsl1iC3LQg,960
30
- render_machine/render_context.py,sha256=2DVUZ-xv2ntRN1cs52ubOVTwpJqGaCOO-ozi_o3PxhA,21033
31
- render_machine/render_types.py,sha256=yDOazYNiOoln4cZHQhMFHnRJtO2BbN2b8hWoBfP6Odk,6782
31
+ render_machine/render_context.py,sha256=9rvjpp_sm7D5CWvSInWVNJ44k4GDZLegfWFI55vNMcg,21519
32
+ render_machine/render_types.py,sha256=Y0MTzlEEPyqEF3NH-SGe5tL5TeCjYOCWhQ1aqBZdy-Q,7187
32
33
  render_machine/render_utils.py,sha256=nUO6mT2dqMmP4t7vefvZRAvxrRJPyrtQBA5qDd_rVI8,4485
33
34
  render_machine/state_machine_config.py,sha256=sd-P9kdvBYlj0R6aT1RZLFquIwAcbEBNL3aZG-Wo4hw,27988
34
35
  render_machine/states.py,sha256=niFXqayyA_rezCrlzo0hYeHAruErcPzQVF-BeIBGnL8,1968
@@ -40,14 +41,14 @@ render_machine/actions/commit_implementation_code_changes.py,sha256=yi51oAArLCgW
40
41
  render_machine/actions/create_dist.py,sha256=ZyhCgl_UHEPjGLLEdqV_2geG7yh_y6G7pYBrlpH99_Q,1046
41
42
  render_machine/actions/exit_with_error.py,sha256=IgTQQbhpluKzTcc1SHYMq8XjNgkx3sEF8Rf8877uK8Q,1044
42
43
  render_machine/actions/finish_functional_requirement.py,sha256=g279oDxfz7BoRxoJT6Gsv5reawed1lfLZw_7fn0mZ0g,687
43
- render_machine/actions/fix_conformance_test.py,sha256=H_k2CzeFCTaOwygJj1a3smtDJMk7QcLnIx_FelBg8lg,6294
44
+ render_machine/actions/fix_conformance_test.py,sha256=YsKPDlheGtBmzh0ac9ugsI8JZQYAZW5CHevZSsatlKI,7326
44
45
  render_machine/actions/fix_unit_tests.py,sha256=wrj5c8flhln9wAZUQ-hELI3dRbLNl1HZqImNDcLE-OE,2558
45
- render_machine/actions/prepare_repositories.py,sha256=ZfQJ1SIvtpgNCBnxNhvCI7RG6KrHGCvFlHPlm1iC_RM,3159
46
+ render_machine/actions/prepare_repositories.py,sha256=1jLGwbJS7jJkhjm-1p2oNv_9n1pD105S1gCCnMNCyrg,3160
46
47
  render_machine/actions/prepare_testing_environment.py,sha256=u5Qdk8EOMewtVNQ4WbscrrnEBDGpDdEK3WG_TlpfI8s,1851
47
48
  render_machine/actions/refactor_code.py,sha256=2cZViWb4Dj6t7dCN2fo9qniIIrn_VE22dsSORjmr_oA,2112
48
- render_machine/actions/render_conformance_tests.py,sha256=Iq0053R2FT0-XeCX3W_gcN9PGYdS5pwBj13PZd91Bms,8529
49
- render_machine/actions/render_functional_requirement.py,sha256=m0LFm3FXaXFF0XLAslWPt9TxoT1VDfurkYPGu1eOs3s,3928
50
- render_machine/actions/run_conformance_tests.py,sha256=fz3ABLXBXq_M0xM5erUdfjaxco0-chWgM-CdRaWgt5I,3157
49
+ render_machine/actions/render_conformance_tests.py,sha256=UwxFJHGjv_xnM97n2haiqXz2h7EEcNqZ71ZLr_0j4v4,8873
50
+ render_machine/actions/render_functional_requirement.py,sha256=O3FOYwK6LUbV2HAzgy3xSh9wkTVurdBVxcfpIIBFT1w,4153
51
+ render_machine/actions/run_conformance_tests.py,sha256=ICOzo2lgJm57cnT8AWGMCuay2s5d7O4Olex0OciX--E,3414
51
52
  render_machine/actions/run_unit_tests.py,sha256=kJOmKhNCLY1latm60DBHvxCKl5-GXdlYUmloZcB1pRY,2031
52
53
  render_machine/actions/summarize_conformance_tests.py,sha256=BbBMJX3HkrZF_BlyNFw6prPgF9NLySapoLeGQ6_e3xU,1867
53
54
  standard_template_library/__init__.py,sha256=LtsHl0c3VV46DUInIqyOw4KKVoxKEMOx8dAZpMXtAXc,43
@@ -62,8 +63,8 @@ tui/plain2code_tui.py,sha256=7agVU0NnaCuF1LuOSEmjx-XfEOQ6HHr1HlWe_b1Tses,11695
62
63
  tui/state_handlers.py,sha256=HbjgaV-9xGhp3E-3X114zOqPkeNcCjT-R1PbVRxVdso,12674
63
64
  tui/styles.css,sha256=Umm2TLePmywizZGV4Nd8UezZRiK5pFyibYRbpRvGqbs,3056
64
65
  tui/widget_helpers.py,sha256=VJorEM2PjRBzN-jIDmKJPolFgo2d8-2NmTumgC5xeNo,5229
65
- codeplain-0.1.5.dist-info/METADATA,sha256=rqos94OuBdYUh2tTXzYa1aw7wO2hlnycEUJ3zfXXz1w,4553
66
- codeplain-0.1.5.dist-info/WHEEL,sha256=qELbo2s1Yzl39ZmrAibXA2jjPLUYfnVhUNTlyF1rq0Y,92
67
- codeplain-0.1.5.dist-info/entry_points.txt,sha256=oDZkBqu9WhtZApb_K6ia8-fn9aojwmAsgnKELceX5T4,46
68
- codeplain-0.1.5.dist-info/top_level.txt,sha256=mj1YZAk6MowQ7wZZkVOAcdUJrJKeWQ7IRZnUHHjaFTM,602
69
- codeplain-0.1.5.dist-info/RECORD,,
66
+ codeplain-0.1.7.dist-info/METADATA,sha256=er9997odKgrndshtXlsIMcpQfvRh4A9eFRSdLgHemNk,4300
67
+ codeplain-0.1.7.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
68
+ codeplain-0.1.7.dist-info/entry_points.txt,sha256=oDZkBqu9WhtZApb_K6ia8-fn9aojwmAsgnKELceX5T4,46
69
+ codeplain-0.1.7.dist-info/top_level.txt,sha256=mj1YZAk6MowQ7wZZkVOAcdUJrJKeWQ7IRZnUHHjaFTM,602
70
+ codeplain-0.1.7.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.10.1)
2
+ Generator: setuptools (80.10.2)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
codeplain_REST_api.py CHANGED
@@ -99,6 +99,7 @@ class CodeplainAPI:
99
99
  plain_source_tree: dict,
100
100
  linked_resources: dict,
101
101
  existing_files_content: dict,
102
+ memory_files_content: dict,
102
103
  module_name: str,
103
104
  required_modules: dict,
104
105
  run_state: RunState,
@@ -116,6 +117,8 @@ class CodeplainAPI:
116
117
  they are linked to.
117
118
  existing_files_content (dict): A dictionary where the keys represent filenames
118
119
  and the values are the content of those files.
120
+ memory_files_content (dict): A dictionary where the keys represent memory filenames
121
+ and the values are the content of those files.
119
122
  module_name (str): The name of the module to render the functional requirement for.
120
123
  required_modules (dict): A dictionary where the keys represent module names
121
124
  and the values are lists of functionalities implemented in those modules.
@@ -135,6 +138,7 @@ class CodeplainAPI:
135
138
  "plain_source_tree": plain_source_tree,
136
139
  "linked_resources": linked_resources,
137
140
  "existing_files_content": existing_files_content,
141
+ "memory_files_content": memory_files_content,
138
142
  "module_name": module_name,
139
143
  "required_modules": required_modules,
140
144
  }
@@ -168,6 +172,44 @@ class CodeplainAPI:
168
172
 
169
173
  return self.post_request(endpoint_url, headers, payload, run_state)
170
174
 
175
+ def create_conformance_test_memory(
176
+ self,
177
+ frid,
178
+ plain_source_tree,
179
+ linked_resources,
180
+ existing_files_content,
181
+ memory_files_content,
182
+ module_name,
183
+ required_modules,
184
+ code_diff,
185
+ conformance_tests_files,
186
+ acceptance_tests,
187
+ conformance_tests_issue,
188
+ conformance_tests_folder_name,
189
+ previous_conformance_tests_issue_old,
190
+ run_state: RunState,
191
+ ):
192
+ endpoint_url = f"{self.api_url}/create_conformance_test_memory"
193
+ headers = {"X-API-Key": self.api_key, "Content-Type": "application/json"}
194
+
195
+ payload = {
196
+ "frid": frid,
197
+ "plain_source_tree": plain_source_tree,
198
+ "linked_resources": linked_resources,
199
+ "existing_files_content": existing_files_content,
200
+ "memory_files_content": memory_files_content,
201
+ "module_name": module_name,
202
+ "required_modules": required_modules,
203
+ "code_diff": code_diff,
204
+ "conformance_tests_files": conformance_tests_files,
205
+ "acceptance_tests": acceptance_tests,
206
+ "conformance_tests_issue": conformance_tests_issue,
207
+ "conformance_tests_folder_name": conformance_tests_folder_name,
208
+ "previous_conformance_tests_issue": previous_conformance_tests_issue_old,
209
+ }
210
+
211
+ return self.post_request(endpoint_url, headers, payload, run_state)
212
+
171
213
  def refactor_source_files_if_needed(self, frid, files_to_check, existing_files_content, run_state: RunState):
172
214
  endpoint_url = f"{self.api_url}/refactor_source_files_if_needed"
173
215
  headers = {"X-API-Key": self.api_key, "Content-Type": "application/json"}
@@ -187,6 +229,7 @@ class CodeplainAPI:
187
229
  plain_source_tree,
188
230
  linked_resources,
189
231
  existing_files_content,
232
+ memory_files_content,
190
233
  module_name: str,
191
234
  required_modules,
192
235
  conformance_tests_folder_name,
@@ -203,6 +246,7 @@ class CodeplainAPI:
203
246
  "plain_source_tree": plain_source_tree,
204
247
  "linked_resources": linked_resources,
205
248
  "existing_files_content": existing_files_content,
249
+ "memory_files_content": memory_files_content,
206
250
  "module_name": module_name,
207
251
  "required_modules": required_modules,
208
252
  "conformance_tests_folder_name": conformance_tests_folder_name,
@@ -238,6 +282,7 @@ class CodeplainAPI:
238
282
  plain_source_tree,
239
283
  linked_resources,
240
284
  existing_files_content,
285
+ memory_files_content,
241
286
  module_name: str,
242
287
  conformance_tests_module_name: str,
243
288
  required_modules,
@@ -259,6 +304,7 @@ class CodeplainAPI:
259
304
  "plain_source_tree": plain_source_tree,
260
305
  "linked_resources": linked_resources,
261
306
  "existing_files_content": existing_files_content,
307
+ "memory_files_content": memory_files_content,
262
308
  "module_name": module_name,
263
309
  "conformance_tests_module_name": conformance_tests_module_name,
264
310
  "required_modules": required_modules,
@@ -281,6 +327,7 @@ class CodeplainAPI:
281
327
  plain_source_tree,
282
328
  linked_resources,
283
329
  existing_files_content,
330
+ memory_files_content,
284
331
  conformance_tests_files,
285
332
  module_name: str,
286
333
  required_modules,
@@ -297,6 +344,8 @@ class CodeplainAPI:
297
344
  and the values are the content of those resources.
298
345
  existing_files_content (dict): A dictionary where the keys represent code base
299
346
  filenames and the values are the content of those files.
347
+ memory_files_content (dict): A dictionary where the keys represent memory filenames
348
+ and the values are the content of those files.
300
349
  conformance_tests_files (dict): A dictionary containing conformance test files.
301
350
  required_modules (dict): A dictionary where the keys represent module names
302
351
  and the values are lists of functionalities implemented in those modules.
@@ -316,6 +365,7 @@ class CodeplainAPI:
316
365
  "plain_source_tree": plain_source_tree,
317
366
  "linked_resources": linked_resources,
318
367
  "existing_files_content": existing_files_content,
368
+ "memory_files_content": memory_files_content,
319
369
  "conformance_tests_files": conformance_tests_files,
320
370
  "module_name": module_name,
321
371
  "required_modules": required_modules,
config/__init__.py CHANGED
@@ -1,2 +1 @@
1
1
  # Configuration files for plain2code
2
-
file_utils.py CHANGED
@@ -7,6 +7,7 @@ from liquid2.exceptions import UndefinedError
7
7
 
8
8
  import plain_spec
9
9
  from plain2code_nodes import Plain2CodeIncludeTag, Plain2CodeLoaderMixin
10
+ from plain_modules import CODEPLAIN_MEMORY_SUBFOLDER, CODEPLAIN_METADATA_FOLDER
10
11
 
11
12
  BINARY_FILE_EXTENSIONS = [".pyc"]
12
13
 
@@ -34,6 +35,7 @@ FILE_EXTENSION_MAPPING = {
34
35
  ".kt": "Kotlin",
35
36
  ".sql": "SQL",
36
37
  ".json": "JSON",
38
+ ".jsonl": "JSONL",
37
39
  ".xml": "XML",
38
40
  ".yaml": "YAML",
39
41
  ".yml": "YAML", # YAML has two common extensions
@@ -53,10 +55,12 @@ def get_file_type(file_name):
53
55
 
54
56
  def list_all_text_files(directory):
55
57
  all_files = []
58
+ skip_dirs = [".git", CODEPLAIN_METADATA_FOLDER, CODEPLAIN_MEMORY_SUBFOLDER]
56
59
  for root, dirs, files in os.walk(directory, topdown=True):
57
- # Skip .git directory
58
- if ".git" in dirs:
59
- dirs.remove(".git")
60
+ # Skip directories that should not be traversed
61
+ for skip_dir in skip_dirs:
62
+ if skip_dir in dirs:
63
+ dirs.remove(skip_dir)
60
64
 
61
65
  modified_root = os.path.relpath(root, directory)
62
66
  if modified_root == ".":
module_renderer.py CHANGED
@@ -5,6 +5,7 @@ import plain_file
5
5
  import plain_modules
6
6
  import plain_spec
7
7
  from event_bus import EventBus
8
+ from memory_management import MemoryManager
8
9
  from plain2code_console import console
9
10
  from plain2code_events import RenderCompleted, RenderFailed
10
11
  from plain2code_state import RunState
@@ -37,6 +38,7 @@ class ModuleRenderer:
37
38
  def _build_render_context_for_module(
38
39
  self,
39
40
  module_name: str,
41
+ memory_manager: MemoryManager,
40
42
  plain_source: dict,
41
43
  required_modules: list[PlainModule],
42
44
  template_dirs: list[str],
@@ -44,6 +46,7 @@ class ModuleRenderer:
44
46
  ) -> RenderContext:
45
47
  return RenderContext(
46
48
  self.codeplainAPI,
49
+ memory_manager,
47
50
  module_name,
48
51
  plain_source,
49
52
  required_modules,
@@ -114,9 +117,11 @@ class ModuleRenderer:
114
117
  ):
115
118
  return False, required_modules, False
116
119
 
120
+ memory_manager = MemoryManager(self.codeplainAPI, os.path.join(self.args.build_folder, module_name))
117
121
  render_context = self._build_render_context_for_module(
118
- module_name, plain_source, required_modules, self.template_dirs, render_range
122
+ module_name, memory_manager, plain_source, required_modules, self.template_dirs, render_range
119
123
  )
124
+
120
125
  code_renderer = CodeRenderer(render_context)
121
126
  if self.args.render_machine_graph:
122
127
  code_renderer.generate_render_machine_graph()
plain2code.py CHANGED
@@ -27,7 +27,6 @@ from plain2code_logger import (
27
27
  get_log_file_path,
28
28
  )
29
29
  from plain2code_state import RunState
30
- from plain2code_utils import print_dry_run_output
31
30
  from system_config import system_config
32
31
  from tui.plain2code_tui import Plain2CodeTUI
33
32
 
@@ -105,8 +104,9 @@ def setup_logging(
105
104
  logging.getLogger("git").setLevel(logging.WARNING)
106
105
  logging.getLogger("anthropic._base_client").setLevel(logging.WARNING)
107
106
  logging.getLogger("services.langsmith.langsmith_service").setLevel(logging.WARNING)
108
- logging.getLogger("transitions").setLevel(logging.WARNING)
109
107
  logging.getLogger("repositories").setLevel(logging.WARNING)
108
+ logging.getLogger("transitions").setLevel(logging.ERROR)
109
+ logging.getLogger("transitions.extensions.diagrams").setLevel(logging.ERROR)
110
110
 
111
111
  log_file_path = get_log_file_path(plain_file_path, log_file_name)
112
112
 
@@ -120,17 +120,6 @@ def setup_logging(
120
120
  except Exception as e:
121
121
  console.warning(f"Failed to load logging configuration from {args.logging_config_path}: {str(e)}")
122
122
 
123
- # Silence noisy third-party libraries
124
- logging.getLogger("urllib3").setLevel(logging.WARNING)
125
- logging.getLogger("httpx").setLevel(logging.WARNING)
126
- logging.getLogger("httpcore").setLevel(logging.WARNING)
127
- logging.getLogger("anthropic").setLevel(logging.WARNING)
128
- logging.getLogger("langsmith").setLevel(logging.WARNING)
129
- logging.getLogger("git").setLevel(logging.WARNING)
130
- logging.getLogger("openai").setLevel(logging.WARNING)
131
- logging.getLogger("transitions").setLevel(logging.WARNING)
132
- logging.getLogger("google_genai").setLevel(logging.WARNING)
133
-
134
123
  # Allow detailed retry logs for anthropic if needed
135
124
  logging.getLogger("anthropic._base_client").setLevel(logging.DEBUG)
136
125
  if logging.getLogger("anthropic._base_client").level == logging.DEBUG:
@@ -252,6 +241,7 @@ def main():
252
241
  console.error(f"Error rendering plain code: {str(e)}\n")
253
242
  console.debug(f"Render ID: {run_state.render_id}")
254
243
  traceback.print_exc()
244
+ dump_crash_logs(args)
255
245
 
256
246
 
257
247
  if __name__ == "__main__": # noqa: C901
plain_modules.py CHANGED
@@ -9,6 +9,7 @@ import git_utils
9
9
  import plain_spec
10
10
  from render_machine.implementation_code_helpers import ImplementationCodeHelpers
11
11
 
12
+ CODEPLAIN_MEMORY_SUBFOLDER = ".memory"
12
13
  CODEPLAIN_METADATA_FOLDER = ".codeplain"
13
14
  MODULE_METADATA_FILENAME = "module_metadata.json"
14
15
  MODULE_FUNCTIONALITIES = "functionalities"
File without changes
@@ -1,7 +1,9 @@
1
1
  from typing import Any
2
2
 
3
+ import diff_utils
3
4
  import file_utils
4
5
  import plain_spec
6
+ from memory_management import MemoryManager
5
7
  from plain2code_console import console
6
8
  from plain2code_exceptions import UnexpectedState
7
9
  from render_machine.actions.base_action import BaseAction
@@ -22,6 +24,13 @@ class FixConformanceTest(BaseAction):
22
24
  raise UnexpectedState("Previous action payload does not contain previous conformance tests issue.")
23
25
  previous_conformance_tests_issue = previous_action_payload["previous_conformance_tests_issue"]
24
26
 
27
+ render_context.conformance_tests_running_context.previous_conformance_tests_issue_old = (
28
+ previous_conformance_tests_issue
29
+ )
30
+ render_context.conformance_tests_running_context.previous_conformance_tests_issue_frid = (
31
+ render_context.conformance_tests_running_context.current_testing_frid
32
+ )
33
+
25
34
  if render_context.conformance_tests_running_context.current_testing_frid == render_context.frid_context.frid:
26
35
  console_message = f"Fixing conformance test for functional requirement {render_context.conformance_tests_running_context.current_testing_frid} in module {render_context.conformance_tests_running_context.current_testing_module_name}."
27
36
  else:
@@ -30,6 +39,7 @@ class FixConformanceTest(BaseAction):
30
39
  existing_files, existing_files_content = ImplementationCodeHelpers.fetch_existing_files(
31
40
  render_context.build_folder
32
41
  )
42
+ _, memory_files_content = MemoryManager.fetch_memory_files(render_context.memory_manager.memory_folder)
33
43
  (
34
44
  existing_conformance_test_files,
35
45
  existing_conformance_test_files_content,
@@ -75,6 +85,7 @@ class FixConformanceTest(BaseAction):
75
85
  render_context.plain_source_tree,
76
86
  render_context.frid_context.linked_resources,
77
87
  existing_files_content,
88
+ memory_files_content,
78
89
  render_context.module_name,
79
90
  render_context.conformance_tests_running_context.current_testing_module_name,
80
91
  render_context.get_required_modules_functionalities(),
@@ -87,6 +98,7 @@ class FixConformanceTest(BaseAction):
87
98
  render_context.conformance_tests_running_context.current_testing_frid_high_level_implementation_plan,
88
99
  run_state=render_context.run_state,
89
100
  )
101
+ code_diff_files_content = {}
90
102
 
91
103
  if conformance_tests_fixed:
92
104
  render_context.conformance_tests.store_conformance_tests_files(
@@ -97,10 +109,15 @@ class FixConformanceTest(BaseAction):
97
109
  response_files,
98
110
  existing_conformance_test_files,
99
111
  )
112
+ code_diff_files_content = diff_utils.get_code_diff(response_files, existing_conformance_test_files_content)
113
+ render_context.conformance_tests_running_context.code_diff_files = code_diff_files_content
114
+
100
115
  return self.IMPLEMENTATION_CODE_NOT_UPDATED, None
101
116
  else:
102
117
  if len(response_files) > 0:
103
118
  file_utils.store_response_files(render_context.build_folder, response_files, existing_files)
119
+ code_diff_files_content = diff_utils.get_code_diff(response_files, existing_files_content)
120
+ render_context.conformance_tests_running_context.code_diff_files = code_diff_files_content
104
121
  if render_context.verbose:
105
122
  console.print_files(
106
123
  "Files fixed:",
@@ -31,6 +31,7 @@ class PrepareRepositories(BaseAction):
31
31
  render_context.conformance_tests.get_module_conformance_tests_folder(render_context.module_name),
32
32
  previous_frid,
33
33
  )
34
+
34
35
  else:
35
36
  if render_context.required_modules:
36
37
  previous_module = render_context.required_modules[-1]
@@ -3,6 +3,7 @@ from typing import Any
3
3
 
4
4
  import file_utils
5
5
  import plain_spec
6
+ from memory_management import MemoryManager
6
7
  from plain2code_console import console
7
8
  from render_machine.actions.base_action import BaseAction
8
9
  from render_machine.implementation_code_helpers import ImplementationCodeHelpers
@@ -70,6 +71,7 @@ class RenderConformanceTests(BaseAction):
70
71
  )
71
72
 
72
73
  _, existing_files_content = ImplementationCodeHelpers.fetch_existing_files(render_context.build_folder)
74
+ _, memory_files_content = MemoryManager.fetch_memory_files(render_context.memory_manager.memory_folder)
73
75
  if render_context.verbose:
74
76
  tmp_resources_list = []
75
77
  plain_spec.collect_linked_resources(
@@ -102,6 +104,7 @@ class RenderConformanceTests(BaseAction):
102
104
  render_context.plain_source_tree,
103
105
  render_context.frid_context.linked_resources,
104
106
  existing_files_content,
107
+ memory_files_content,
105
108
  render_context.module_name,
106
109
  render_context.get_required_modules_functionalities(),
107
110
  conformance_tests_folder_name,
@@ -130,6 +133,7 @@ class RenderConformanceTests(BaseAction):
130
133
 
131
134
  def _render_acceptance_test(self, render_context: RenderContext):
132
135
  _, existing_files_content = ImplementationCodeHelpers.fetch_existing_files(render_context.build_folder)
136
+ _, memory_files_content = MemoryManager.fetch_memory_files(render_context.memory_manager.memory_folder)
133
137
  (
134
138
  conformance_tests_files,
135
139
  conformance_tests_files_content,
@@ -157,6 +161,7 @@ class RenderConformanceTests(BaseAction):
157
161
  render_context.plain_source_tree,
158
162
  render_context.frid_context.linked_resources,
159
163
  existing_files_content,
164
+ memory_files_content,
160
165
  conformance_tests_files_content,
161
166
  render_context.module_name,
162
167
  render_context.get_required_modules_functionalities(),
@@ -2,6 +2,7 @@ from typing import Any
2
2
 
3
3
  import file_utils
4
4
  import render_machine.render_utils as render_utils
5
+ from memory_management import MemoryManager
5
6
  from plain2code_console import console
6
7
  from plain2code_exceptions import FunctionalRequirementTooComplex
7
8
  from render_machine.actions.base_action import BaseAction
@@ -21,6 +22,7 @@ class RenderFunctionalRequirement(BaseAction):
21
22
  existing_files, existing_files_content = ImplementationCodeHelpers.fetch_existing_files(
22
23
  render_context.build_folder
23
24
  )
25
+ _, memory_files_content = MemoryManager.fetch_memory_files(render_context.memory_manager.memory_folder)
24
26
 
25
27
  if render_context.verbose:
26
28
  msg = f"Module: {render_context.module_name}\n"
@@ -46,6 +48,7 @@ class RenderFunctionalRequirement(BaseAction):
46
48
  render_context.plain_source_tree,
47
49
  render_context.frid_context.linked_resources,
48
50
  existing_files_content,
51
+ memory_files_content,
49
52
  render_context.module_name,
50
53
  render_context.get_required_modules_functionalities(),
51
54
  render_context.run_state,
@@ -54,7 +57,7 @@ class RenderFunctionalRequirement(BaseAction):
54
57
  error_message = f"The functional requirement:\n[b]{render_context.frid_context.functional_requirement_text}[/b]\n is too complex to be implemented. Please break down the functional requirement into smaller parts ({str(e)})."
55
58
  if e.proposed_breakdown:
56
59
  error_message += "\nProposed breakdown:"
57
- for _, part in e.proposed_breakdown.items():
60
+ for _, part in e.proposed_breakdown["functional_requirements"].items():
58
61
  error_message += f"\n - {part}"
59
62
 
60
63
  return (
@@ -46,6 +46,14 @@ class RunConformanceTests(BaseAction):
46
46
  )
47
47
  render_context.script_execution_history.latest_conformance_test_output_path = conformance_tests_temp_file_path
48
48
  render_context.script_execution_history.should_update_script_outputs = True
49
+
50
+ render_context.memory_manager.create_conformance_tests_memory(
51
+ render_context, exit_code, conformance_tests_issue
52
+ )
53
+
54
+ if exit_code == 0:
55
+ conformance_tests_issue = "All conformance tests passed successfully!"
56
+
49
57
  if exit_code == 0:
50
58
  return self.SUCCESSFUL_OUTCOME, None
51
59
 
@@ -26,7 +26,8 @@ class ConformanceTests:
26
26
 
27
27
  def _get_full_conformance_tests_definition_file_name(self, module_name: str) -> str:
28
28
  return os.path.join(
29
- self.get_module_conformance_tests_folder(module_name), self.conformance_tests_definition_file_name
29
+ self.get_module_conformance_tests_folder(module_name),
30
+ self.conformance_tests_definition_file_name,
30
31
  )
31
32
 
32
33
  def get_conformance_tests_json(self, module_name: str) -> dict:
@@ -112,7 +113,10 @@ class ConformanceTests:
112
113
 
113
114
  [source_conformance_test_folder_name, new_conformance_test_folder_name] = (
114
115
  self.get_source_conformance_test_folder_name(
115
- module_name, required_modules, current_testing_module_name, current_conformance_test_folder_name
116
+ module_name,
117
+ required_modules,
118
+ current_testing_module_name,
119
+ current_conformance_test_folder_name,
116
120
  )
117
121
  )
118
122
 
@@ -120,7 +124,12 @@ class ConformanceTests:
120
124
  console.info(
121
125
  f"Creating folder {new_conformance_test_folder_name} for a copy of conformance tests {source_conformance_test_folder_name}"
122
126
  )
123
- file_utils.copy_folder_content(source_conformance_test_folder_name, new_conformance_test_folder_name)
127
+
128
+ if not os.path.exists(new_conformance_test_folder_name):
129
+ file_utils.copy_folder_content(
130
+ source_conformance_test_folder_name,
131
+ new_conformance_test_folder_name,
132
+ )
124
133
 
125
134
  current_conformance_test_folder_name = new_conformance_test_folder_name
126
135
 
@@ -147,7 +156,10 @@ class ConformanceTests:
147
156
  ) -> tuple[list[str], dict[str, str]]:
148
157
  if module_name != current_testing_module_name:
149
158
  [current_conformance_test_folder_name, _] = self.get_source_conformance_test_folder_name(
150
- module_name, required_modules, current_testing_module_name, current_conformance_test_folder_name
159
+ module_name,
160
+ required_modules,
161
+ current_testing_module_name,
162
+ current_conformance_test_folder_name,
151
163
  )
152
164
 
153
165
  existing_conformance_test_files = file_utils.list_all_text_files(current_conformance_test_folder_name)
@@ -31,6 +31,7 @@ class RenderContext:
31
31
  def __init__(
32
32
  self,
33
33
  codeplain_api,
34
+ memory_manager,
34
35
  module_name: str,
35
36
  plain_source_tree: dict,
36
37
  required_modules: list[PlainModule],
@@ -52,6 +53,7 @@ class RenderContext:
52
53
  event_bus: EventBus,
53
54
  ):
54
55
  self.codeplain_api: CodeplainAPI = codeplain_api
56
+ self.memory_manager = memory_manager
55
57
  self.plain_source_tree = plain_source_tree
56
58
  self.module_name = module_name
57
59
  self.template_dirs = template_dirs
@@ -207,15 +209,21 @@ class RenderContext:
207
209
 
208
210
  if module is None:
209
211
  conformance_tests_running_context.current_testing_module_name = self.module_name
212
+ if not conformance_tests_running_context.conformance_tests_json_has_module_populated(
213
+ conformance_tests_running_context.current_testing_module_name
214
+ ):
215
+ conformance_tests_running_context.set_conformance_tests_json(
216
+ conformance_tests_running_context.current_testing_module_name,
217
+ {},
218
+ )
210
219
  else:
211
220
  conformance_tests_running_context.current_testing_module_name = module.name
212
-
213
- conformance_tests_running_context.set_conformance_tests_json(
214
- conformance_tests_running_context.current_testing_module_name,
215
- self.conformance_tests.get_conformance_tests_json(
216
- conformance_tests_running_context.current_testing_module_name
217
- ),
218
- )
221
+ conformance_tests_running_context.set_conformance_tests_json(
222
+ conformance_tests_running_context.current_testing_module_name,
223
+ self.conformance_tests.get_conformance_tests_json(
224
+ conformance_tests_running_context.current_testing_module_name
225
+ ),
226
+ )
219
227
 
220
228
  if module is None:
221
229
  conformance_tests_running_context.current_testing_frid = plain_spec.get_first_frid(self.plain_source_tree)
@@ -47,10 +47,16 @@ class ConformanceTestsRunningContext:
47
47
  # - conformance_test_phase_index == 0 (conformance tests phase)
48
48
  self.regenerating_conformance_tests: bool = False
49
49
  self.current_testing_frid_high_level_implementation_plan: Optional[str] = None
50
+ self.previous_conformance_tests_issue_old: Optional[str] = None
51
+ self.previous_conformance_tests_issue_frid: Optional[str] = None
52
+ self.code_diff_files: Optional[dict[str, str]] = None
50
53
 
51
54
  def get_conformance_tests_json(self, module_name: str) -> dict:
52
55
  return self._conformance_tests_json[module_name]
53
56
 
57
+ def conformance_tests_json_has_module_populated(self, module_name: str) -> bool:
58
+ return module_name in self._conformance_tests_json and len(self._conformance_tests_json[module_name]) > 0
59
+
54
60
  def set_conformance_tests_json(self, module_name: str, conformance_tests_json: dict):
55
61
  self._conformance_tests_json[module_name] = conformance_tests_json
56
62
 
@@ -73,7 +79,7 @@ class ConformanceTestsRunningContext:
73
79
  plain_spec.ACCEPTANCE_TESTS
74
80
  ]
75
81
 
76
- return None
82
+ return []
77
83
 
78
84
  def get_current_acceptance_test(self) -> Optional[str]:
79
85
  """Get the current acceptance test text (raw, unformatted)."""