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
@@ -1,4 +1,3 @@
1
- import re
2
1
  from typing import Dict, Any, Optional
3
2
  from rich import print as rprint
4
3
  from rich.markdown import Markdown
@@ -145,6 +144,7 @@ def fix_verification_errors(
145
144
  verification_result_obj = verification_response.get('result')
146
145
 
147
146
  if isinstance(verification_result_obj, VerificationOutput):
147
+ # llm_invoke handles all parsing when output_pydantic is specified
148
148
  verification_issues_count = verification_result_obj.issues_count
149
149
  verification_details = verification_result_obj.details
150
150
  if verbose:
@@ -162,66 +162,18 @@ def fix_verification_errors(
162
162
  if verbose:
163
163
  rprint(f"\n[yellow]Found {verification_issues_count} potential issues. Proceeding to fix step.[/yellow]")
164
164
  else:
165
- rprint(f"[yellow]Warning:[/yellow] <issues_count> is {verification_issues_count}, but <details> field is empty or missing. Treating as no actionable issues found.")
165
+ rprint(f"[yellow]Warning:[/yellow] issues_count is {verification_issues_count}, but details field is empty or missing. Treating as no actionable issues found.")
166
166
  verification_issues_count = 0
167
167
  else:
168
168
  if verbose:
169
169
  rprint("\n[green]No issues found during verification based on structured output.[/green]")
170
- elif isinstance(verification_result_obj, str):
171
- try:
172
- issues_match = re.search(r'<issues_count>(\d+)</issues_count>', verification_result_obj)
173
- if issues_match:
174
- parsed_issues_count = int(issues_match.group(1))
175
- details_match = re.search(r'<details>(.*?)</details>', verification_result_obj, re.DOTALL)
176
- parsed_verification_details = details_match.group(1).strip() if (details_match and details_match.group(1)) else None
177
-
178
-
179
- if parsed_issues_count > 0:
180
- if parsed_verification_details: # Check if details exist and are not empty
181
- issues_found = True
182
- verification_issues_count = parsed_issues_count
183
- verification_details = parsed_verification_details
184
- if verbose:
185
- rprint(f"\n[yellow]Found {verification_issues_count} potential issues in string response. Proceeding to fix step.[/yellow]")
186
- else:
187
- rprint(f"[yellow]Warning:[/yellow] <issues_count> is {parsed_issues_count} in string response, but <details> field is empty or missing. Treating as no actionable issues found.")
188
- verification_issues_count = 0
189
- issues_found = False
190
- else: # parsed_issues_count == 0
191
- verification_issues_count = 0
192
- issues_found = False
193
- if verbose:
194
- rprint("\n[green]No issues found in string verification based on <issues_count> being 0.[/green]")
195
- else: # issues_match is None (tag not found or content not digits)
196
- rprint("[bold red]Error:[/bold red] Could not find or parse integer value from <issues_count> tag in string response.")
197
- return {
198
- "explanation": None,
199
- "fixed_program": program,
200
- "fixed_code": code,
201
- "total_cost": total_cost,
202
- "model_name": model_name,
203
- "verification_issues_count": 0,
204
- }
205
- except ValueError: # Should not be hit if regex is \d+, but as a safeguard
206
- rprint("[bold red]Error:[/bold red] Invalid non-integer value in <issues_count> tag in string response.")
207
- return {
208
- "explanation": None,
209
- "fixed_program": program,
210
- "fixed_code": code,
211
- "total_cost": total_cost,
212
- "model_name": model_name,
213
- "verification_issues_count": 0,
214
- }
215
- else: # Not VerificationOutput and not a successfully parsed string
216
- rprint("[bold red]Error:[/bold red] Verification LLM call did not return the expected structured output (e.g., parsing failed).")
217
- rprint(f" [dim]Expected type:[/dim] {VerificationOutput} or str")
170
+ else:
171
+ # llm_invoke should always return VerificationOutput when output_pydantic is specified
172
+ rprint("[bold red]Error:[/bold red] Verification LLM call did not return the expected structured output.")
173
+ rprint(f" [dim]Expected type:[/dim] {VerificationOutput}")
218
174
  rprint(f" [dim]Received type:[/dim] {type(verification_result_obj)}")
219
175
  content_str = str(verification_result_obj)
220
176
  rprint(f" [dim]Received content:[/dim] {content_str[:500]}{'...' if len(content_str) > 500 else ''}")
221
- raw_text = verification_response.get('result_text')
222
- if raw_text:
223
- raw_text_str = str(raw_text)
224
- rprint(f" [dim]Raw LLM text (if available from llm_invoke):[/dim] {raw_text_str[:500]}{'...' if len(raw_text_str) > 500 else ''}")
225
177
  return {
226
178
  "explanation": None,
227
179
  "fixed_program": program,
@@ -262,63 +214,23 @@ def fix_verification_errors(
262
214
  rprint(f" [dim]Cost:[/dim] ${fix_response.get('cost', 0.0):.6f}")
263
215
 
264
216
  fix_result_obj = fix_response.get('result')
265
- parsed_fix_successfully = False
266
217
 
267
218
  if isinstance(fix_result_obj, FixerOutput):
219
+ # llm_invoke handles all parsing and unescaping via _unescape_code_newlines
268
220
  fixed_program = fix_result_obj.fixed_program
269
221
  fixed_code = fix_result_obj.fixed_code
270
222
  fix_explanation = fix_result_obj.explanation
271
-
272
- # Unescape literal \n strings to actual newlines
273
- if fixed_program:
274
- fixed_program = fixed_program.replace('\\n', '\n')
275
- if fixed_code:
276
- fixed_code = fixed_code.replace('\\n', '\n')
277
-
278
- parsed_fix_successfully = True
223
+
279
224
  if verbose:
280
225
  rprint("[green]Successfully parsed structured output for fix.[/green]")
281
226
  rprint(Markdown(f"**Explanation from LLM:**\n{fix_explanation}"))
282
- elif isinstance(fix_result_obj, str):
283
- program_match = re.search(r'<fixed_program>(.*?)</fixed_program>', fix_result_obj, re.DOTALL)
284
- code_match = re.search(r'<fixed_code>(.*?)</fixed_code>', fix_result_obj, re.DOTALL)
285
- explanation_match = re.search(r'<explanation>(.*?)</explanation>', fix_result_obj, re.DOTALL)
286
-
287
- if program_match or code_match or explanation_match: # If any tag is found, attempt to parse
288
- fixed_program_candidate = program_match.group(1).strip() if (program_match and program_match.group(1)) else None
289
- fixed_code_candidate = code_match.group(1).strip() if (code_match and code_match.group(1)) else None
290
- fix_explanation_candidate = explanation_match.group(1).strip() if (explanation_match and explanation_match.group(1)) else None
291
-
292
- # Unescape literal \n strings to actual newlines
293
- if fixed_program_candidate:
294
- fixed_program_candidate = fixed_program_candidate.replace('\\n', '\n')
295
- if fixed_code_candidate:
296
- fixed_code_candidate = fixed_code_candidate.replace('\\n', '\n')
297
-
298
- fixed_program = fixed_program_candidate if fixed_program_candidate else program
299
- fixed_code = fixed_code_candidate if fixed_code_candidate else code
300
- fix_explanation = fix_explanation_candidate if fix_explanation_candidate else "[Fix explanation not provided by LLM]"
301
- parsed_fix_successfully = True
302
-
303
- if verbose:
304
- if not program_match or not fixed_program_candidate:
305
- rprint("[yellow]Warning:[/yellow] Could not find or parse <fixed_program> tag in fix result string. Using original program.")
306
- if not code_match or not fixed_code_candidate:
307
- rprint("[yellow]Warning:[/yellow] Could not find or parse <fixed_code> tag in fix result string. Using original code module.")
308
- if not explanation_match or not fix_explanation_candidate:
309
- rprint("[yellow]Warning:[/yellow] Could not find or parse <explanation> tag in fix result string. Using default explanation.")
310
- # else: string, but no relevant tags. Will fall to parsed_fix_successfully = False below
311
-
312
- if not parsed_fix_successfully:
313
- rprint(f"[bold red]Error:[/bold red] Fix generation LLM call did not return the expected structured output (e.g., parsing failed).")
314
- rprint(f" [dim]Expected type:[/dim] {FixerOutput} or str (with XML tags)")
227
+ else:
228
+ # llm_invoke should always return FixerOutput when output_pydantic is specified
229
+ rprint(f"[bold red]Error:[/bold red] Fix generation LLM call did not return the expected structured output.")
230
+ rprint(f" [dim]Expected type:[/dim] {FixerOutput}")
315
231
  rprint(f" [dim]Received type:[/dim] {type(fix_result_obj)}")
316
232
  content_str = str(fix_result_obj)
317
233
  rprint(f" [dim]Received content:[/dim] {content_str[:500]}{'...' if len(content_str) > 500 else ''}")
318
- raw_text = fix_response.get('result_text')
319
- if raw_text:
320
- raw_text_str = str(raw_text)
321
- rprint(f" [dim]Raw LLM text (if available from llm_invoke):[/dim] {raw_text_str[:500]}{'...' if len(raw_text_str) > 500 else ''}")
322
234
  fix_explanation = "[Error: Failed to parse structured output from LLM for fix explanation]"
323
235
  # fixed_program and fixed_code remain original (already initialized)
324
236