ara-cli 0.1.10.5__py3-none-any.whl → 0.1.14.0__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.
- ara_cli/__init__.py +51 -6
- ara_cli/__main__.py +87 -75
- ara_cli/ara_command_action.py +189 -101
- ara_cli/ara_config.py +187 -128
- ara_cli/ara_subcommands/common.py +2 -2
- ara_cli/ara_subcommands/config.py +221 -0
- ara_cli/ara_subcommands/convert.py +107 -0
- ara_cli/ara_subcommands/fetch.py +41 -0
- ara_cli/ara_subcommands/fetch_agents.py +22 -0
- ara_cli/ara_subcommands/fetch_scripts.py +19 -0
- ara_cli/ara_subcommands/fetch_templates.py +15 -10
- ara_cli/ara_subcommands/list.py +97 -23
- ara_cli/ara_subcommands/prompt.py +266 -106
- ara_cli/artefact_autofix.py +117 -64
- ara_cli/artefact_converter.py +355 -0
- ara_cli/artefact_creator.py +41 -17
- ara_cli/artefact_lister.py +3 -3
- ara_cli/artefact_models/artefact_model.py +1 -1
- ara_cli/artefact_models/artefact_templates.py +0 -9
- ara_cli/artefact_models/feature_artefact_model.py +8 -8
- ara_cli/artefact_reader.py +62 -43
- ara_cli/artefact_scan.py +39 -17
- ara_cli/chat.py +300 -71
- ara_cli/chat_agent/__init__.py +0 -0
- ara_cli/chat_agent/agent_process_manager.py +155 -0
- ara_cli/chat_script_runner/__init__.py +0 -0
- ara_cli/chat_script_runner/script_completer.py +23 -0
- ara_cli/chat_script_runner/script_finder.py +41 -0
- ara_cli/chat_script_runner/script_lister.py +36 -0
- ara_cli/chat_script_runner/script_runner.py +36 -0
- ara_cli/chat_web_search/__init__.py +0 -0
- ara_cli/chat_web_search/web_search.py +263 -0
- ara_cli/children_contribution_updater.py +737 -0
- ara_cli/classifier.py +34 -0
- ara_cli/commands/agent_run_command.py +98 -0
- ara_cli/commands/fetch_agents_command.py +106 -0
- ara_cli/commands/fetch_scripts_command.py +43 -0
- ara_cli/commands/fetch_templates_command.py +39 -0
- ara_cli/commands/fetch_templates_commands.py +39 -0
- ara_cli/commands/list_agents_command.py +39 -0
- ara_cli/commands/load_command.py +4 -3
- ara_cli/commands/load_image_command.py +1 -1
- ara_cli/commands/read_command.py +23 -27
- ara_cli/completers.py +95 -35
- ara_cli/constants.py +2 -0
- ara_cli/directory_navigator.py +37 -4
- ara_cli/error_handler.py +26 -11
- ara_cli/file_loaders/document_reader.py +0 -178
- ara_cli/file_loaders/factories/__init__.py +0 -0
- ara_cli/file_loaders/factories/document_reader_factory.py +32 -0
- ara_cli/file_loaders/factories/file_loader_factory.py +27 -0
- ara_cli/file_loaders/file_loader.py +1 -30
- ara_cli/file_loaders/loaders/__init__.py +0 -0
- ara_cli/file_loaders/{document_file_loader.py → loaders/document_file_loader.py} +1 -1
- ara_cli/file_loaders/loaders/text_file_loader.py +47 -0
- ara_cli/file_loaders/readers/__init__.py +0 -0
- ara_cli/file_loaders/readers/docx_reader.py +49 -0
- ara_cli/file_loaders/readers/excel_reader.py +27 -0
- ara_cli/file_loaders/{markdown_reader.py → readers/markdown_reader.py} +1 -1
- ara_cli/file_loaders/readers/odt_reader.py +59 -0
- ara_cli/file_loaders/readers/pdf_reader.py +54 -0
- ara_cli/file_loaders/readers/pptx_reader.py +104 -0
- ara_cli/file_loaders/tools/__init__.py +0 -0
- ara_cli/llm_utils.py +58 -0
- ara_cli/output_suppressor.py +53 -0
- ara_cli/prompt_chat.py +20 -4
- ara_cli/prompt_extractor.py +47 -32
- ara_cli/prompt_handler.py +123 -17
- ara_cli/tag_extractor.py +8 -7
- ara_cli/template_loader.py +2 -1
- ara_cli/template_manager.py +52 -21
- ara_cli/templates/global-scripts/hello_global.py +1 -0
- ara_cli/templates/prompt-modules/commands/add_scenarios_for_new_behaviour.feature_creation_agent.commands.md +1 -0
- ara_cli/templates/prompt-modules/commands/align_feature_with_implementation_changes.interview_agent.commands.md +1 -0
- ara_cli/templates/prompt-modules/commands/analyze_codebase_and_plan_tasks.interview_agent.commands.md +1 -0
- ara_cli/templates/prompt-modules/commands/choose_best_parent_artefact.interview_agent.commands.md +1 -0
- ara_cli/templates/prompt-modules/commands/create_tasks_from_artefact_content.interview_agent.commands.md +1 -0
- ara_cli/templates/prompt-modules/commands/create_tests_for_uncovered_modules.test_generation_agent.commands.md +1 -0
- ara_cli/templates/prompt-modules/commands/derive_features_from_video_description.feature_creation_agent.commands.md +1 -0
- ara_cli/templates/prompt-modules/commands/describe_agent_capabilities.agent.commands.md +1 -0
- ara_cli/templates/prompt-modules/commands/empty.commands.md +2 -12
- ara_cli/templates/prompt-modules/commands/execute_scoped_todos_in_task.interview_agent.commands.md +1 -0
- ara_cli/templates/prompt-modules/commands/explain_single_file_purpose.interview_agent.commands.md +1 -0
- ara_cli/templates/prompt-modules/commands/extract_file_information_bullets.interview_agent.commands.md +1 -0
- ara_cli/templates/prompt-modules/commands/extract_general.commands.md +12 -0
- ara_cli/templates/prompt-modules/commands/extract_markdown.commands.md +11 -0
- ara_cli/templates/prompt-modules/commands/extract_python.commands.md +13 -0
- ara_cli/templates/prompt-modules/commands/feature_add_or_modifiy_specified_behavior.commands.md +36 -0
- ara_cli/templates/prompt-modules/commands/feature_generate_initial_specified_bevahior.commands.md +53 -0
- ara_cli/templates/prompt-modules/commands/fix_failing_behave_step_definitions.interview_agent.commands.md +1 -0
- ara_cli/templates/prompt-modules/commands/fix_failing_pytest_tests.interview_agent.commands.md +1 -0
- ara_cli/templates/prompt-modules/commands/general_instruction_policy.commands.md +47 -0
- ara_cli/templates/prompt-modules/commands/generate_and_fix_pytest_tests.test_generation_agent.commands.md +1 -0
- ara_cli/templates/prompt-modules/commands/prompt_template_tech_stack_transformer.commands.md +95 -0
- ara_cli/templates/prompt-modules/commands/python_bug_fixing_code.commands.md +34 -0
- ara_cli/templates/prompt-modules/commands/python_generate_code.commands.md +27 -0
- ara_cli/templates/prompt-modules/commands/python_refactoring_code.commands.md +39 -0
- ara_cli/templates/prompt-modules/commands/python_step_definitions_generation_and_fixing.commands.md +40 -0
- ara_cli/templates/prompt-modules/commands/python_unittest_generation_and_fixing.commands.md +48 -0
- ara_cli/templates/prompt-modules/commands/suggest_next_story_child_tasks.interview_agent.commands.md +1 -0
- ara_cli/templates/prompt-modules/commands/summarize_or_transcribe_media.interview_agent.commands.md +1 -0
- ara_cli/templates/prompt-modules/commands/update_feature_to_match_implementation.feature_creation_agent.commands.md +1 -0
- ara_cli/templates/prompt-modules/commands/update_user_story_with_requirements.interview_agent.commands.md +1 -0
- ara_cli/version.py +1 -1
- {ara_cli-0.1.10.5.dist-info → ara_cli-0.1.14.0.dist-info}/METADATA +49 -11
- ara_cli-0.1.14.0.dist-info/RECORD +253 -0
- {ara_cli-0.1.10.5.dist-info → ara_cli-0.1.14.0.dist-info}/WHEEL +1 -1
- tests/test_ara_command_action.py +31 -19
- tests/test_ara_config.py +177 -90
- tests/test_artefact_autofix.py +170 -97
- tests/test_artefact_autofix_integration.py +495 -0
- tests/test_artefact_converter.py +312 -0
- tests/test_artefact_extraction.py +564 -0
- tests/test_artefact_lister.py +11 -8
- tests/test_chat.py +166 -130
- tests/test_chat_givens_images.py +603 -0
- tests/test_chat_script_runner.py +454 -0
- tests/test_children_contribution_updater.py +98 -0
- tests/test_document_loader_office.py +267 -0
- tests/test_llm_utils.py +164 -0
- tests/test_prompt_chat.py +343 -0
- tests/test_prompt_extractor.py +683 -0
- tests/test_prompt_handler.py +416 -214
- tests/test_setup_default_chat_prompt_mode.py +198 -0
- tests/test_tag_extractor.py +95 -49
- tests/test_web_search.py +467 -0
- ara_cli/file_loaders/document_readers.py +0 -233
- ara_cli/file_loaders/file_loaders.py +0 -123
- ara_cli/file_loaders/text_file_loader.py +0 -187
- ara_cli/templates/prompt-modules/blueprints/complete_pytest_unittest.blueprint.md +0 -27
- ara_cli/templates/prompt-modules/blueprints/pytest_unittest_prompt.blueprint.md +0 -32
- ara_cli/templates/prompt-modules/blueprints/task_todo_list_implement_feature_BDD_way.blueprint.md +0 -30
- ara_cli/templates/prompt-modules/commands/artefact_classification.commands.md +0 -9
- ara_cli/templates/prompt-modules/commands/artefact_extension.commands.md +0 -17
- ara_cli/templates/prompt-modules/commands/artefact_formulation.commands.md +0 -14
- ara_cli/templates/prompt-modules/commands/behave_step_generation.commands.md +0 -102
- ara_cli/templates/prompt-modules/commands/code_generation_complex.commands.md +0 -20
- ara_cli/templates/prompt-modules/commands/code_generation_simple.commands.md +0 -13
- ara_cli/templates/prompt-modules/commands/error_fixing.commands.md +0 -20
- ara_cli/templates/prompt-modules/commands/feature_file_update.commands.md +0 -18
- ara_cli/templates/prompt-modules/commands/feature_formulation.commands.md +0 -43
- ara_cli/templates/prompt-modules/commands/js_code_generation_simple.commands.md +0 -13
- ara_cli/templates/prompt-modules/commands/refactoring.commands.md +0 -15
- ara_cli/templates/prompt-modules/commands/refactoring_analysis.commands.md +0 -9
- ara_cli/templates/prompt-modules/commands/reverse_engineer_feature_file.commands.md +0 -15
- ara_cli/templates/prompt-modules/commands/reverse_engineer_program_flow.commands.md +0 -19
- ara_cli-0.1.10.5.dist-info/RECORD +0 -194
- /ara_cli/file_loaders/{binary_file_loader.py → loaders/binary_file_loader.py} +0 -0
- /ara_cli/file_loaders/{image_processor.py → tools/image_processor.py} +0 -0
- {ara_cli-0.1.10.5.dist-info → ara_cli-0.1.14.0.dist-info}/entry_points.txt +0 -0
- {ara_cli-0.1.10.5.dist-info → ara_cli-0.1.14.0.dist-info}/top_level.txt +0 -0
ara_cli/artefact_autofix.py
CHANGED
|
@@ -140,16 +140,11 @@ def construct_prompt(artefact_type, reason, file_path, artefact_text):
|
|
|
140
140
|
|
|
141
141
|
|
|
142
142
|
def run_agent(prompt, artefact_class):
|
|
143
|
-
from
|
|
144
|
-
|
|
145
|
-
#
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
agent = Agent(
|
|
149
|
-
model="anthropic:claude-4-sonnet-20250514",
|
|
150
|
-
output_type=artefact_class,
|
|
151
|
-
instrument=True,
|
|
152
|
-
)
|
|
143
|
+
from ara_cli.llm_utils import create_pydantic_ai_agent
|
|
144
|
+
|
|
145
|
+
# Use the shared agent creation logic which respects configuration and validation
|
|
146
|
+
agent = create_pydantic_ai_agent(output_type=artefact_class, instrument=True)
|
|
147
|
+
|
|
153
148
|
result = agent.run_sync(prompt)
|
|
154
149
|
return result.output
|
|
155
150
|
|
|
@@ -161,7 +156,7 @@ def write_corrected_artefact(file_path, corrected_text):
|
|
|
161
156
|
|
|
162
157
|
|
|
163
158
|
def ask_for_correct_contribution(
|
|
164
|
-
artefact_info: Optional[tuple[str, str]] = None
|
|
159
|
+
artefact_info: Optional[tuple[str, str]] = None,
|
|
165
160
|
) -> tuple[str, str]:
|
|
166
161
|
"""
|
|
167
162
|
Ask the user to provide a valid contribution when no match can be found.
|
|
@@ -199,8 +194,12 @@ def ask_for_correct_contribution(
|
|
|
199
194
|
return name, classifier
|
|
200
195
|
|
|
201
196
|
|
|
202
|
-
def ask_for_contribution_choice(
|
|
203
|
-
|
|
197
|
+
def ask_for_contribution_choice(
|
|
198
|
+
choices: List[str], artefact_info: Optional[tuple[str, str]] = None
|
|
199
|
+
) -> Optional[str]:
|
|
200
|
+
artefact_name, artefact_classifier = (
|
|
201
|
+
artefact_info if artefact_info else (None, None)
|
|
202
|
+
)
|
|
204
203
|
message = "Found multiple close matches for the contribution"
|
|
205
204
|
if artefact_name and artefact_classifier:
|
|
206
205
|
message += f" of the {artefact_classifier} '{artefact_name}'"
|
|
@@ -248,12 +247,16 @@ def ask_for_rule_choice(matches: List[str]) -> Optional[str]:
|
|
|
248
247
|
|
|
249
248
|
|
|
250
249
|
def _update_rule(
|
|
251
|
-
artefact: Artefact,
|
|
250
|
+
artefact: Artefact,
|
|
251
|
+
name: str,
|
|
252
|
+
classifier: str,
|
|
253
|
+
classified_file_info: dict,
|
|
254
|
+
delete_if_not_found: bool = False,
|
|
252
255
|
) -> None:
|
|
253
256
|
"""Updates the rule in the contribution if a close match is found."""
|
|
254
257
|
rule = artefact.contribution.rule
|
|
255
258
|
|
|
256
|
-
content, artefact_data = ArtefactReader.read_artefact_data(
|
|
259
|
+
content, artefact_data = ArtefactReader().read_artefact_data(
|
|
257
260
|
artefact_name=name,
|
|
258
261
|
classifier=classifier,
|
|
259
262
|
classified_file_info=classified_file_info,
|
|
@@ -317,7 +320,9 @@ def set_closest_contribution(
|
|
|
317
320
|
classifier = contribution.classifier
|
|
318
321
|
rule = contribution.rule
|
|
319
322
|
|
|
320
|
-
classified_file_info = populate_classified_artefact_info(
|
|
323
|
+
classified_file_info = populate_classified_artefact_info(
|
|
324
|
+
classified_artefact_info=classified_file_info
|
|
325
|
+
)
|
|
321
326
|
|
|
322
327
|
all_artefact_names = extract_artefact_names_of_classifier(
|
|
323
328
|
classified_files=classified_file_info, classifier=classifier
|
|
@@ -360,7 +365,7 @@ def set_closest_contribution(
|
|
|
360
365
|
if not rule:
|
|
361
366
|
return artefact, True
|
|
362
367
|
|
|
363
|
-
content, artefact = ArtefactReader.read_artefact_data(
|
|
368
|
+
content, artefact = ArtefactReader().read_artefact_data(
|
|
364
369
|
artefact_name=name,
|
|
365
370
|
classifier=classifier,
|
|
366
371
|
classified_file_info=classified_file_info,
|
|
@@ -385,12 +390,12 @@ def fix_scenario_placeholder_mismatch(
|
|
|
385
390
|
lines = artefact_text.splitlines()
|
|
386
391
|
new_lines = []
|
|
387
392
|
i = 0
|
|
388
|
-
|
|
393
|
+
|
|
389
394
|
while i < len(lines):
|
|
390
395
|
line = lines[i]
|
|
391
396
|
stripped_line = line.strip()
|
|
392
|
-
|
|
393
|
-
if stripped_line.startswith(
|
|
397
|
+
|
|
398
|
+
if stripped_line.startswith("Scenario:"):
|
|
394
399
|
scenario_lines, next_index = _extract_scenario_block(lines, i)
|
|
395
400
|
processed_lines = _process_scenario_block(scenario_lines)
|
|
396
401
|
new_lines.extend(processed_lines)
|
|
@@ -398,7 +403,7 @@ def fix_scenario_placeholder_mismatch(
|
|
|
398
403
|
else:
|
|
399
404
|
new_lines.append(line)
|
|
400
405
|
i += 1
|
|
401
|
-
|
|
406
|
+
|
|
402
407
|
return "\n".join(new_lines)
|
|
403
408
|
|
|
404
409
|
|
|
@@ -406,20 +411,20 @@ def _extract_scenario_block(lines: list, start_index: int) -> tuple[list, int]:
|
|
|
406
411
|
"""Extract all lines belonging to a scenario block."""
|
|
407
412
|
scenario_lines = [lines[start_index]]
|
|
408
413
|
j = start_index + 1
|
|
409
|
-
|
|
414
|
+
|
|
410
415
|
while j < len(lines):
|
|
411
416
|
next_line = lines[j].strip()
|
|
412
417
|
if _is_scenario_boundary(next_line):
|
|
413
418
|
break
|
|
414
419
|
scenario_lines.append(lines[j])
|
|
415
420
|
j += 1
|
|
416
|
-
|
|
421
|
+
|
|
417
422
|
return scenario_lines, j
|
|
418
423
|
|
|
419
424
|
|
|
420
425
|
def _is_scenario_boundary(line: str) -> bool:
|
|
421
426
|
"""Check if a line marks the boundary of a scenario block."""
|
|
422
|
-
boundaries = [
|
|
427
|
+
boundaries = ["Scenario:", "Scenario Outline:", "Background:", "Feature:"]
|
|
423
428
|
return any(line.startswith(boundary) for boundary in boundaries)
|
|
424
429
|
|
|
425
430
|
|
|
@@ -427,38 +432,38 @@ def _process_scenario_block(scenario_lines: list) -> list:
|
|
|
427
432
|
"""Process a scenario block and convert to outline if placeholders are found."""
|
|
428
433
|
if not scenario_lines:
|
|
429
434
|
return scenario_lines
|
|
430
|
-
|
|
435
|
+
|
|
431
436
|
first_line = scenario_lines[0]
|
|
432
437
|
indentation = _get_line_indentation(first_line)
|
|
433
438
|
placeholders = _extract_placeholders_from_scenario(scenario_lines[1:])
|
|
434
|
-
|
|
439
|
+
|
|
435
440
|
if not placeholders:
|
|
436
441
|
return scenario_lines
|
|
437
|
-
|
|
442
|
+
|
|
438
443
|
return _convert_to_scenario_outline(scenario_lines, placeholders, indentation)
|
|
439
444
|
|
|
440
445
|
|
|
441
446
|
def _get_line_indentation(line: str) -> str:
|
|
442
447
|
"""Get the indentation of a line."""
|
|
443
|
-
return line[:len(line) - len(line.lstrip())]
|
|
448
|
+
return line[: len(line) - len(line.lstrip())]
|
|
444
449
|
|
|
445
450
|
|
|
446
451
|
def _extract_placeholders_from_scenario(step_lines: list) -> set:
|
|
447
452
|
"""Extract placeholders from scenario step lines, ignoring docstrings."""
|
|
448
453
|
placeholders = set()
|
|
449
454
|
in_docstring = False
|
|
450
|
-
|
|
455
|
+
|
|
451
456
|
for line in step_lines:
|
|
452
457
|
step_line = line.strip()
|
|
453
458
|
if not step_line:
|
|
454
459
|
continue
|
|
455
|
-
|
|
460
|
+
|
|
456
461
|
in_docstring = _update_docstring_state(step_line, in_docstring)
|
|
457
|
-
|
|
462
|
+
|
|
458
463
|
if not in_docstring and '"""' not in step_line:
|
|
459
|
-
found = re.findall(r
|
|
464
|
+
found = re.findall(r"<([^>]+)>", step_line)
|
|
460
465
|
placeholders.update(found)
|
|
461
|
-
|
|
466
|
+
|
|
462
467
|
return placeholders
|
|
463
468
|
|
|
464
469
|
|
|
@@ -469,18 +474,20 @@ def _update_docstring_state(line: str, current_state: bool) -> bool:
|
|
|
469
474
|
return current_state
|
|
470
475
|
|
|
471
476
|
|
|
472
|
-
def _convert_to_scenario_outline(
|
|
477
|
+
def _convert_to_scenario_outline(
|
|
478
|
+
scenario_lines: list, placeholders: set, indentation: str
|
|
479
|
+
) -> list:
|
|
473
480
|
"""Convert scenario lines to scenario outline format with examples table."""
|
|
474
481
|
first_line = scenario_lines[0]
|
|
475
|
-
title = first_line.strip()[len(
|
|
476
|
-
|
|
482
|
+
title = first_line.strip()[len("Scenario:") :].strip()
|
|
483
|
+
|
|
477
484
|
new_lines = [f"{indentation}Scenario Outline: {title}"]
|
|
478
485
|
new_lines.extend(scenario_lines[1:])
|
|
479
486
|
new_lines.append("")
|
|
480
|
-
|
|
487
|
+
|
|
481
488
|
examples_lines = _create_examples_table(placeholders, indentation)
|
|
482
489
|
new_lines.extend(examples_lines)
|
|
483
|
-
|
|
490
|
+
|
|
484
491
|
return new_lines
|
|
485
492
|
|
|
486
493
|
|
|
@@ -488,15 +495,15 @@ def _create_examples_table(placeholders: set, base_indentation: str) -> list:
|
|
|
488
495
|
"""Create the Examples table for the scenario outline."""
|
|
489
496
|
examples_indentation = base_indentation + " "
|
|
490
497
|
table_indentation = examples_indentation + " "
|
|
491
|
-
|
|
498
|
+
|
|
492
499
|
sorted_placeholders = sorted(placeholders)
|
|
493
500
|
header = "| " + " | ".join(sorted_placeholders) + " |"
|
|
494
501
|
sample_row = "| " + " | ".join(f"<{p}_value>" for p in sorted_placeholders) + " |"
|
|
495
|
-
|
|
502
|
+
|
|
496
503
|
return [
|
|
497
504
|
f"{examples_indentation}Examples:",
|
|
498
505
|
f"{table_indentation}{header}",
|
|
499
|
-
f"{table_indentation}{sample_row}"
|
|
506
|
+
f"{table_indentation}{sample_row}",
|
|
500
507
|
]
|
|
501
508
|
|
|
502
509
|
|
|
@@ -539,7 +546,9 @@ def fix_contribution(
|
|
|
539
546
|
classified_artefact_info: dict,
|
|
540
547
|
**kwargs,
|
|
541
548
|
):
|
|
542
|
-
classified_artefact_info = populate_classified_artefact_info(
|
|
549
|
+
classified_artefact_info = populate_classified_artefact_info(
|
|
550
|
+
classified_artefact_info=classified_artefact_info
|
|
551
|
+
)
|
|
543
552
|
artefact = artefact_class.deserialize(artefact_text)
|
|
544
553
|
artefact, _ = set_closest_contribution(artefact)
|
|
545
554
|
artefact_text = artefact.serialize()
|
|
@@ -553,7 +562,9 @@ def fix_rule(
|
|
|
553
562
|
classified_artefact_info: dict,
|
|
554
563
|
**kwargs,
|
|
555
564
|
):
|
|
556
|
-
classified_artefact_info = populate_classified_artefact_info(
|
|
565
|
+
classified_artefact_info = populate_classified_artefact_info(
|
|
566
|
+
classified_artefact_info=classified_artefact_info
|
|
567
|
+
)
|
|
557
568
|
artefact = artefact_class.deserialize(artefact_text)
|
|
558
569
|
contribution = artefact.contribution
|
|
559
570
|
assert contribution is not None
|
|
@@ -562,11 +573,13 @@ def fix_rule(
|
|
|
562
573
|
name=contribution.artefact_name,
|
|
563
574
|
classifier=contribution.classifier,
|
|
564
575
|
classified_file_info=classified_artefact_info,
|
|
565
|
-
delete_if_not_found=True
|
|
576
|
+
delete_if_not_found=True,
|
|
577
|
+
)
|
|
578
|
+
feedback_message = (
|
|
579
|
+
f"Updating contribution of {artefact._artefact_type().value} "
|
|
580
|
+
f"'{artefact.title}' to {contribution.classifier} "
|
|
581
|
+
f"'{contribution.artefact_name}' "
|
|
566
582
|
)
|
|
567
|
-
feedback_message = (f"Updating contribution of {artefact._artefact_type().value} "
|
|
568
|
-
f"'{artefact.title}' to {contribution.classifier} "
|
|
569
|
-
f"'{contribution.artefact_name}' ")
|
|
570
583
|
rule = contribution.rule
|
|
571
584
|
if rule:
|
|
572
585
|
feedback_message += f"with rule '{rule}'"
|
|
@@ -593,7 +606,7 @@ def fix_misplaced_content(file_path: str, artefact_text: str, **kwargs) -> str:
|
|
|
593
606
|
|
|
594
607
|
pre_desc_lines = lines[:desc_start_idx]
|
|
595
608
|
desc_line = lines[desc_start_idx]
|
|
596
|
-
post_desc_lines = lines[desc_start_idx+1:]
|
|
609
|
+
post_desc_lines = lines[desc_start_idx + 1 :]
|
|
597
610
|
|
|
598
611
|
misplaced_content = []
|
|
599
612
|
new_post_desc_lines = []
|
|
@@ -608,11 +621,15 @@ def fix_misplaced_content(file_path: str, artefact_text: str, **kwargs) -> str:
|
|
|
608
621
|
return artefact_text
|
|
609
622
|
|
|
610
623
|
# Rebuild the file content
|
|
611
|
-
final_lines =
|
|
624
|
+
final_lines = (
|
|
625
|
+
pre_desc_lines + misplaced_content + [""] + [desc_line] + new_post_desc_lines
|
|
626
|
+
)
|
|
612
627
|
return "\n".join(final_lines)
|
|
613
628
|
|
|
614
629
|
|
|
615
|
-
def should_skip_issue(
|
|
630
|
+
def should_skip_issue(
|
|
631
|
+
deterministic_issue, deterministic, non_deterministic, file_path
|
|
632
|
+
) -> bool:
|
|
616
633
|
if not non_deterministic and not deterministic_issue:
|
|
617
634
|
print(f"Skipping non-deterministic fix for {file_path} as per request.")
|
|
618
635
|
return True
|
|
@@ -621,15 +638,23 @@ def should_skip_issue(deterministic_issue, deterministic, non_deterministic, fil
|
|
|
621
638
|
return True
|
|
622
639
|
return False
|
|
623
640
|
|
|
641
|
+
|
|
624
642
|
def determine_attempt_count(single_pass, file_path) -> int:
|
|
625
643
|
if single_pass:
|
|
626
644
|
print(f"Single-pass mode enabled for {file_path}. Running for 1 attempt.")
|
|
627
645
|
return 1
|
|
628
646
|
return 3
|
|
629
647
|
|
|
648
|
+
|
|
630
649
|
def apply_deterministic_fix(
|
|
631
|
-
deterministic,
|
|
632
|
-
|
|
650
|
+
deterministic,
|
|
651
|
+
deterministic_issue,
|
|
652
|
+
file_path,
|
|
653
|
+
artefact_text,
|
|
654
|
+
artefact_class,
|
|
655
|
+
classified_artefact_info,
|
|
656
|
+
deterministic_markers_to_functions,
|
|
657
|
+
corrected_text,
|
|
633
658
|
) -> str:
|
|
634
659
|
if deterministic and deterministic_issue:
|
|
635
660
|
print(f"Applying deterministic fix for '{deterministic_issue}'...")
|
|
@@ -642,9 +667,16 @@ def apply_deterministic_fix(
|
|
|
642
667
|
)
|
|
643
668
|
return corrected_text
|
|
644
669
|
|
|
670
|
+
|
|
645
671
|
def apply_non_deterministic_fix(
|
|
646
|
-
non_deterministic,
|
|
647
|
-
|
|
672
|
+
non_deterministic,
|
|
673
|
+
deterministic_issue,
|
|
674
|
+
corrected_text,
|
|
675
|
+
artefact_type,
|
|
676
|
+
current_reason,
|
|
677
|
+
file_path,
|
|
678
|
+
artefact_text,
|
|
679
|
+
artefact_class,
|
|
648
680
|
) -> Optional[str]:
|
|
649
681
|
"""
|
|
650
682
|
Applies LLM fix. Return None in case of an exception
|
|
@@ -662,6 +694,7 @@ def apply_non_deterministic_fix(
|
|
|
662
694
|
return None
|
|
663
695
|
return corrected_text
|
|
664
696
|
|
|
697
|
+
|
|
665
698
|
def attempt_autofix_loop(
|
|
666
699
|
file_path: str,
|
|
667
700
|
artefact_type,
|
|
@@ -702,19 +735,32 @@ def attempt_autofix_loop(
|
|
|
702
735
|
None,
|
|
703
736
|
)
|
|
704
737
|
|
|
705
|
-
if should_skip_issue(
|
|
738
|
+
if should_skip_issue(
|
|
739
|
+
deterministic_issue, deterministic, non_deterministic, file_path
|
|
740
|
+
):
|
|
706
741
|
return False
|
|
707
742
|
|
|
708
743
|
corrected_text = None
|
|
709
744
|
|
|
710
745
|
corrected_text = apply_deterministic_fix(
|
|
711
|
-
deterministic,
|
|
712
|
-
|
|
713
|
-
|
|
746
|
+
deterministic,
|
|
747
|
+
deterministic_issue,
|
|
748
|
+
file_path,
|
|
749
|
+
artefact_text,
|
|
750
|
+
artefact_class,
|
|
751
|
+
classified_artefact_info,
|
|
752
|
+
deterministic_markers_to_functions,
|
|
753
|
+
corrected_text,
|
|
714
754
|
)
|
|
715
755
|
corrected_text = apply_non_deterministic_fix(
|
|
716
|
-
non_deterministic,
|
|
717
|
-
|
|
756
|
+
non_deterministic,
|
|
757
|
+
deterministic_issue,
|
|
758
|
+
corrected_text,
|
|
759
|
+
artefact_type,
|
|
760
|
+
current_reason,
|
|
761
|
+
file_path,
|
|
762
|
+
artefact_text,
|
|
763
|
+
artefact_class,
|
|
718
764
|
)
|
|
719
765
|
|
|
720
766
|
if corrected_text is None or corrected_text.strip() == artefact_text.strip():
|
|
@@ -725,12 +771,17 @@ def attempt_autofix_loop(
|
|
|
725
771
|
|
|
726
772
|
write_corrected_artefact(file_path, corrected_text)
|
|
727
773
|
|
|
728
|
-
print(
|
|
729
|
-
|
|
774
|
+
print(
|
|
775
|
+
" File modified. Re-classifying artefact information for next check..."
|
|
776
|
+
)
|
|
777
|
+
classified_artefact_info = populate_classified_artefact_info(
|
|
778
|
+
classified_artefact_info, force=True
|
|
779
|
+
)
|
|
730
780
|
|
|
731
781
|
print(f"❌ Failed to fix {file_path} after {max_attempts} attempts.")
|
|
732
782
|
return False
|
|
733
783
|
|
|
784
|
+
|
|
734
785
|
def apply_autofix(
|
|
735
786
|
file_path: str,
|
|
736
787
|
classifier: str,
|
|
@@ -757,7 +808,9 @@ def apply_autofix(
|
|
|
757
808
|
if artefact_type is None or artefact_class is None:
|
|
758
809
|
return False
|
|
759
810
|
|
|
760
|
-
classified_artefact_info = populate_classified_artefact_info(
|
|
811
|
+
classified_artefact_info = populate_classified_artefact_info(
|
|
812
|
+
classified_artefact_info
|
|
813
|
+
)
|
|
761
814
|
max_attempts = determine_attempt_count(single_pass, file_path)
|
|
762
815
|
|
|
763
816
|
return attempt_autofix_loop(
|
|
@@ -769,4 +822,4 @@ def apply_autofix(
|
|
|
769
822
|
deterministic=deterministic,
|
|
770
823
|
non_deterministic=non_deterministic,
|
|
771
824
|
classified_artefact_info=classified_artefact_info,
|
|
772
|
-
)
|
|
825
|
+
)
|