pdd-cli 0.0.42__py3-none-any.whl → 0.0.90__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.
Files changed (119) hide show
  1. pdd/__init__.py +4 -4
  2. pdd/agentic_common.py +863 -0
  3. pdd/agentic_crash.py +534 -0
  4. pdd/agentic_fix.py +1179 -0
  5. pdd/agentic_langtest.py +162 -0
  6. pdd/agentic_update.py +370 -0
  7. pdd/agentic_verify.py +183 -0
  8. pdd/auto_deps_main.py +15 -5
  9. pdd/auto_include.py +63 -5
  10. pdd/bug_main.py +3 -2
  11. pdd/bug_to_unit_test.py +2 -0
  12. pdd/change_main.py +11 -4
  13. pdd/cli.py +22 -1181
  14. pdd/cmd_test_main.py +80 -19
  15. pdd/code_generator.py +58 -18
  16. pdd/code_generator_main.py +672 -25
  17. pdd/commands/__init__.py +42 -0
  18. pdd/commands/analysis.py +248 -0
  19. pdd/commands/fix.py +140 -0
  20. pdd/commands/generate.py +257 -0
  21. pdd/commands/maintenance.py +174 -0
  22. pdd/commands/misc.py +79 -0
  23. pdd/commands/modify.py +230 -0
  24. pdd/commands/report.py +144 -0
  25. pdd/commands/templates.py +215 -0
  26. pdd/commands/utility.py +110 -0
  27. pdd/config_resolution.py +58 -0
  28. pdd/conflicts_main.py +8 -3
  29. pdd/construct_paths.py +281 -81
  30. pdd/context_generator.py +10 -2
  31. pdd/context_generator_main.py +113 -11
  32. pdd/continue_generation.py +47 -7
  33. pdd/core/__init__.py +0 -0
  34. pdd/core/cli.py +503 -0
  35. pdd/core/dump.py +554 -0
  36. pdd/core/errors.py +63 -0
  37. pdd/core/utils.py +90 -0
  38. pdd/crash_main.py +44 -11
  39. pdd/data/language_format.csv +71 -62
  40. pdd/data/llm_model.csv +20 -18
  41. pdd/detect_change_main.py +5 -4
  42. pdd/fix_code_loop.py +331 -77
  43. pdd/fix_error_loop.py +209 -60
  44. pdd/fix_errors_from_unit_tests.py +4 -3
  45. pdd/fix_main.py +75 -18
  46. pdd/fix_verification_errors.py +12 -100
  47. pdd/fix_verification_errors_loop.py +319 -272
  48. pdd/fix_verification_main.py +57 -17
  49. pdd/generate_output_paths.py +93 -10
  50. pdd/generate_test.py +16 -5
  51. pdd/get_jwt_token.py +48 -9
  52. pdd/get_run_command.py +73 -0
  53. pdd/get_test_command.py +68 -0
  54. pdd/git_update.py +70 -19
  55. pdd/increase_tests.py +7 -0
  56. pdd/incremental_code_generator.py +2 -2
  57. pdd/insert_includes.py +11 -3
  58. pdd/llm_invoke.py +1278 -110
  59. pdd/load_prompt_template.py +36 -10
  60. pdd/pdd_completion.fish +25 -2
  61. pdd/pdd_completion.sh +30 -4
  62. pdd/pdd_completion.zsh +79 -4
  63. pdd/postprocess.py +10 -3
  64. pdd/preprocess.py +228 -15
  65. pdd/preprocess_main.py +8 -5
  66. pdd/prompts/agentic_crash_explore_LLM.prompt +49 -0
  67. pdd/prompts/agentic_fix_explore_LLM.prompt +45 -0
  68. pdd/prompts/agentic_fix_harvest_only_LLM.prompt +48 -0
  69. pdd/prompts/agentic_fix_primary_LLM.prompt +85 -0
  70. pdd/prompts/agentic_update_LLM.prompt +1071 -0
  71. pdd/prompts/agentic_verify_explore_LLM.prompt +45 -0
  72. pdd/prompts/auto_include_LLM.prompt +98 -101
  73. pdd/prompts/change_LLM.prompt +1 -3
  74. pdd/prompts/detect_change_LLM.prompt +562 -3
  75. pdd/prompts/example_generator_LLM.prompt +22 -1
  76. pdd/prompts/extract_code_LLM.prompt +5 -1
  77. pdd/prompts/extract_program_code_fix_LLM.prompt +14 -2
  78. pdd/prompts/extract_prompt_update_LLM.prompt +7 -8
  79. pdd/prompts/extract_promptline_LLM.prompt +17 -11
  80. pdd/prompts/find_verification_errors_LLM.prompt +6 -0
  81. pdd/prompts/fix_code_module_errors_LLM.prompt +16 -4
  82. pdd/prompts/fix_errors_from_unit_tests_LLM.prompt +6 -41
  83. pdd/prompts/fix_verification_errors_LLM.prompt +22 -0
  84. pdd/prompts/generate_test_LLM.prompt +21 -6
  85. pdd/prompts/increase_tests_LLM.prompt +1 -2
  86. pdd/prompts/insert_includes_LLM.prompt +1181 -6
  87. pdd/prompts/split_LLM.prompt +1 -62
  88. pdd/prompts/trace_LLM.prompt +25 -22
  89. pdd/prompts/unfinished_prompt_LLM.prompt +85 -1
  90. pdd/prompts/update_prompt_LLM.prompt +22 -1
  91. pdd/prompts/xml_convertor_LLM.prompt +3246 -7
  92. pdd/pytest_output.py +188 -21
  93. pdd/python_env_detector.py +151 -0
  94. pdd/render_mermaid.py +236 -0
  95. pdd/setup_tool.py +648 -0
  96. pdd/simple_math.py +2 -0
  97. pdd/split_main.py +3 -2
  98. pdd/summarize_directory.py +56 -7
  99. pdd/sync_determine_operation.py +918 -186
  100. pdd/sync_main.py +82 -32
  101. pdd/sync_orchestration.py +1456 -453
  102. pdd/sync_tui.py +848 -0
  103. pdd/template_registry.py +264 -0
  104. pdd/templates/architecture/architecture_json.prompt +242 -0
  105. pdd/templates/generic/generate_prompt.prompt +174 -0
  106. pdd/trace.py +168 -12
  107. pdd/trace_main.py +4 -3
  108. pdd/track_cost.py +151 -61
  109. pdd/unfinished_prompt.py +49 -3
  110. pdd/update_main.py +549 -67
  111. pdd/update_model_costs.py +2 -2
  112. pdd/update_prompt.py +19 -4
  113. {pdd_cli-0.0.42.dist-info → pdd_cli-0.0.90.dist-info}/METADATA +20 -7
  114. pdd_cli-0.0.90.dist-info/RECORD +153 -0
  115. {pdd_cli-0.0.42.dist-info → pdd_cli-0.0.90.dist-info}/licenses/LICENSE +1 -1
  116. pdd_cli-0.0.42.dist-info/RECORD +0 -115
  117. {pdd_cli-0.0.42.dist-info → pdd_cli-0.0.90.dist-info}/WHEEL +0 -0
  118. {pdd_cli-0.0.42.dist-info → pdd_cli-0.0.90.dist-info}/entry_points.txt +0 -0
  119. {pdd_cli-0.0.42.dist-info → pdd_cli-0.0.90.dist-info}/top_level.txt +0 -0
pdd/git_update.py CHANGED
@@ -4,6 +4,8 @@ from rich import print
4
4
  from rich.console import Console
5
5
  from rich.panel import Panel
6
6
  from .update_prompt import update_prompt
7
+ from .agentic_common import get_available_agents
8
+ from .agentic_update import run_agentic_update
7
9
  import git
8
10
  from . import DEFAULT_TIME
9
11
  console = Console()
@@ -14,21 +16,33 @@ def git_update(
14
16
  strength: float,
15
17
  temperature: float,
16
18
  verbose: bool = False,
17
- time: float = DEFAULT_TIME
19
+ time: float = DEFAULT_TIME,
20
+ simple: bool = False,
21
+ quiet: bool = False,
22
+ prompt_file: Optional[str] = None
18
23
  ) -> Tuple[Optional[str], float, str]:
19
24
  """
20
- Read in modified code, restore the prior checked-in version from GitHub,
21
- update the prompt, write back the modified code, and return outputs.
25
+ Read in modified code, restore the prior checked-in version from Git,
26
+ update the prompt (via agentic or legacy path), write back the modified code,
27
+ and return outputs.
22
28
 
23
29
  Args:
24
- input_prompt (str): The prompt that generated the original code.
30
+ input_prompt (str): The prompt TEXT content (not a file path).
25
31
  modified_code_file (str): Filepath of the modified code.
26
32
  strength (float): Strength parameter for the LLM model.
27
33
  temperature (float): Temperature parameter for the LLM model.
34
+ verbose (bool): Enable verbose logging.
35
+ time (float): Time parameter for the LLM model.
36
+ simple (bool): If True, skip agentic and use legacy update_prompt().
37
+ quiet (bool): Suppress non-error logging.
38
+ prompt_file (Optional[str]): Path to prompt file (required for agentic path).
28
39
 
29
40
  Returns:
30
- Tuple[Optional[str], float, str]: Modified prompt, total cost, and model name.
41
+ Tuple[Optional[str], float, str]: Updated prompt content, total cost, and model name.
31
42
  """
43
+ modified_code: Optional[str] = None
44
+ agentic_cost = 0.0
45
+
32
46
  try:
33
47
  # Check if inputs are valid
34
48
  if not input_prompt or not modified_code_file:
@@ -37,26 +51,57 @@ def git_update(
37
51
  if not os.path.exists(modified_code_file):
38
52
  raise FileNotFoundError(f"Modified code file not found: {modified_code_file}")
39
53
 
40
- # Initialize git repository
41
- repo = git.Repo(search_parent_directories=True)
54
+ # Initialize git repository object once
55
+ repo = git.Repo(modified_code_file, search_parent_directories=True)
56
+ repo_root = repo.working_tree_dir
42
57
 
43
58
  # Get the file's relative path to the repo root
44
- repo_root = repo.git.rev_parse("--show-toplevel")
45
59
  relative_path = os.path.relpath(modified_code_file, repo_root)
46
60
 
47
- # Read the modified code
61
+ # Read the modified code FIRST (before any git operations)
48
62
  with open(modified_code_file, 'r') as file:
49
63
  modified_code = file.read()
50
64
 
51
- # Restore the prior checked-in version
65
+ # Restore the prior checked-in version using the relative path
52
66
  repo.git.checkout('HEAD', '--', relative_path)
53
67
 
54
68
  # Read the original input code
55
69
  with open(modified_code_file, 'r') as file:
56
70
  original_input_code = file.read()
57
71
 
58
- # Call update_prompt function
59
- modified_prompt, total_cost, model_name = update_prompt(
72
+ # Routing decision: agentic vs legacy
73
+ use_agentic = (
74
+ not simple
75
+ and prompt_file is not None
76
+ and get_available_agents()
77
+ )
78
+
79
+ if use_agentic:
80
+ # Agentic path
81
+ success, message, agentic_cost, provider, changed_files = run_agentic_update(
82
+ prompt_file=prompt_file,
83
+ code_file=modified_code_file,
84
+ verbose=verbose,
85
+ quiet=quiet
86
+ )
87
+ if success:
88
+ # Read updated prompt content from file
89
+ with open(prompt_file, 'r') as file:
90
+ updated_prompt = file.read()
91
+
92
+ # Pretty print the results
93
+ console.print(Panel.fit(
94
+ f"[bold green]Success (agentic):[/bold green]\n"
95
+ f"Provider: {provider}\n"
96
+ f"Total cost: ${agentic_cost:.6f}\n"
97
+ f"Changed files: {', '.join(changed_files)}"
98
+ ))
99
+
100
+ return updated_prompt, agentic_cost, provider
101
+ # Fall through to legacy on agentic failure
102
+
103
+ # Legacy path
104
+ result_prompt, legacy_cost, model_name = update_prompt(
60
105
  input_prompt=input_prompt,
61
106
  input_code=original_input_code,
62
107
  modified_code=modified_code,
@@ -66,21 +111,27 @@ def git_update(
66
111
  time=time
67
112
  )
68
113
 
69
- # Write back the modified code
70
- with open(modified_code_file, 'w') as file:
71
- file.write(modified_code)
72
-
114
+ total_cost = agentic_cost + legacy_cost
73
115
 
74
116
  # Pretty print the results
75
117
  console.print(Panel.fit(
76
118
  f"[bold green]Success:[/bold green]\n"
77
- f"Modified prompt: {modified_prompt}\n"
119
+ f"Modified prompt: {result_prompt}\n"
78
120
  f"Total cost: ${total_cost:.6f}\n"
79
121
  f"Model name: {model_name}"
80
122
  ))
81
123
 
82
- return modified_prompt, total_cost, model_name
124
+ return result_prompt, total_cost, model_name
83
125
 
84
126
  except Exception as e:
85
127
  console.print(Panel(f"[bold red]Error:[/bold red] {str(e)}", title="Error", expand=False))
86
- return None, 0.0, ""
128
+ return None, agentic_cost, ""
129
+
130
+ finally:
131
+ # Always restore user's modified code to disk before returning
132
+ if modified_code is not None and modified_code_file:
133
+ try:
134
+ with open(modified_code_file, 'w') as file:
135
+ file.write(modified_code)
136
+ except Exception:
137
+ pass # Best effort restoration
pdd/increase_tests.py CHANGED
@@ -78,6 +78,13 @@ def increase_tests(
78
78
  time=time,
79
79
  verbose=verbose
80
80
  )
81
+
82
+ # Debug: Check LLM response
83
+ console.print(f"[blue]DEBUG increase_tests: LLM response type: {type(llm_response)}[/blue]")
84
+ console.print(f"[blue]DEBUG increase_tests: LLM response keys: {llm_response.keys() if isinstance(llm_response, dict) else 'Not a dict'}[/blue]")
85
+ console.print(f"[blue]DEBUG increase_tests: LLM result type: {type(llm_response.get('result', 'No result key'))}[/blue]")
86
+ console.print(f"[blue]DEBUG increase_tests: LLM result length: {len(llm_response['result']) if 'result' in llm_response and llm_response['result'] else 0}[/blue]")
87
+ console.print(f"[blue]DEBUG increase_tests: LLM result preview: {repr(llm_response['result'][:300]) if 'result' in llm_response and llm_response['result'] else 'Empty or no result'}[/blue]")
81
88
 
82
89
  increase_test_function, total_cost, model_name = postprocess(
83
90
  llm_response['result'],
@@ -59,8 +59,8 @@ def incremental_code_generator(
59
59
  if not original_prompt or not new_prompt or not existing_code or not language:
60
60
  raise ValueError("All required inputs (original_prompt, new_prompt, existing_code, language) must be provided.")
61
61
 
62
- if not 0 <= strength <= 1 or not 0 <= temperature <= 1 or not 0 <= time <= 1:
63
- raise ValueError("Strength, temperature, and time must be between 0 and 1.")
62
+ if not 0 <= strength <= 1 or not 0 <= temperature <= 2 or not 0 <= time <= 1:
63
+ raise ValueError("Strength and time must be between 0 and 1. Temperature must be between 0 and 2.")
64
64
 
65
65
  try:
66
66
  total_cost = 0.0
pdd/insert_includes.py CHANGED
@@ -1,4 +1,4 @@
1
- from typing import Tuple
1
+ from typing import Callable, Optional, Tuple
2
2
  from pathlib import Path
3
3
  from rich import print
4
4
  from pydantic import BaseModel, Field
@@ -16,10 +16,12 @@ def insert_includes(
16
16
  input_prompt: str,
17
17
  directory_path: str,
18
18
  csv_filename: str,
19
+ prompt_filename: Optional[str] = None,
19
20
  strength: float = DEFAULT_STRENGTH,
20
21
  temperature: float = 0.0,
21
22
  time: float = DEFAULT_TIME,
22
- verbose: bool = False
23
+ verbose: bool = False,
24
+ progress_callback: Optional[Callable[[int, int], None]] = None
23
25
  ) -> Tuple[str, str, float, str]:
24
26
  """
25
27
  Determine needed dependencies and insert them into a prompt.
@@ -28,10 +30,14 @@ def insert_includes(
28
30
  input_prompt (str): The prompt to process
29
31
  directory_path (str): Directory path where the prompt file is located
30
32
  csv_filename (str): Name of the CSV file containing dependencies
33
+ prompt_filename (Optional[str]): The prompt filename being processed,
34
+ used to filter out self-referential example files
31
35
  strength (float): Strength parameter for the LLM model
32
36
  temperature (float): Temperature parameter for the LLM model
33
37
  time (float): Time budget for the LLM model
34
38
  verbose (bool, optional): Whether to print detailed information. Defaults to False.
39
+ progress_callback (Optional[Callable[[int, int], None]]): Callback for progress updates.
40
+ Called with (current, total) for each file processed.
35
41
 
36
42
  Returns:
37
43
  Tuple[str, str, float, str]: Tuple containing:
@@ -75,10 +81,12 @@ def insert_includes(
75
81
  input_prompt=input_prompt,
76
82
  directory_path=directory_path,
77
83
  csv_file=csv_content,
84
+ prompt_filename=prompt_filename,
78
85
  strength=strength,
79
86
  temperature=temperature,
80
87
  time=time,
81
- verbose=verbose
88
+ verbose=verbose,
89
+ progress_callback=progress_callback
82
90
  )
83
91
 
84
92
  if verbose: