pdd-cli 0.0.45__py3-none-any.whl → 0.0.118__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.
- pdd/__init__.py +40 -8
- pdd/agentic_bug.py +323 -0
- pdd/agentic_bug_orchestrator.py +497 -0
- pdd/agentic_change.py +231 -0
- pdd/agentic_change_orchestrator.py +526 -0
- pdd/agentic_common.py +598 -0
- pdd/agentic_crash.py +534 -0
- pdd/agentic_e2e_fix.py +319 -0
- pdd/agentic_e2e_fix_orchestrator.py +426 -0
- pdd/agentic_fix.py +1294 -0
- pdd/agentic_langtest.py +162 -0
- pdd/agentic_update.py +387 -0
- pdd/agentic_verify.py +183 -0
- pdd/architecture_sync.py +565 -0
- pdd/auth_service.py +210 -0
- pdd/auto_deps_main.py +71 -51
- pdd/auto_include.py +245 -5
- pdd/auto_update.py +125 -47
- pdd/bug_main.py +196 -23
- pdd/bug_to_unit_test.py +2 -0
- pdd/change_main.py +11 -4
- pdd/cli.py +22 -1181
- pdd/cmd_test_main.py +350 -150
- pdd/code_generator.py +60 -18
- pdd/code_generator_main.py +790 -57
- pdd/commands/__init__.py +48 -0
- pdd/commands/analysis.py +306 -0
- pdd/commands/auth.py +309 -0
- pdd/commands/connect.py +290 -0
- pdd/commands/fix.py +163 -0
- pdd/commands/generate.py +257 -0
- pdd/commands/maintenance.py +175 -0
- pdd/commands/misc.py +87 -0
- pdd/commands/modify.py +256 -0
- pdd/commands/report.py +144 -0
- pdd/commands/sessions.py +284 -0
- pdd/commands/templates.py +215 -0
- pdd/commands/utility.py +110 -0
- pdd/config_resolution.py +58 -0
- pdd/conflicts_main.py +8 -3
- pdd/construct_paths.py +589 -111
- pdd/context_generator.py +10 -2
- pdd/context_generator_main.py +175 -76
- pdd/continue_generation.py +53 -10
- pdd/core/__init__.py +33 -0
- pdd/core/cli.py +527 -0
- pdd/core/cloud.py +237 -0
- pdd/core/dump.py +554 -0
- pdd/core/errors.py +67 -0
- pdd/core/remote_session.py +61 -0
- pdd/core/utils.py +90 -0
- pdd/crash_main.py +262 -33
- pdd/data/language_format.csv +71 -63
- pdd/data/llm_model.csv +20 -18
- pdd/detect_change_main.py +5 -4
- pdd/docs/prompting_guide.md +864 -0
- pdd/docs/whitepaper_with_benchmarks/data_and_functions/benchmark_analysis.py +495 -0
- pdd/docs/whitepaper_with_benchmarks/data_and_functions/creation_compare.py +528 -0
- pdd/fix_code_loop.py +523 -95
- pdd/fix_code_module_errors.py +6 -2
- pdd/fix_error_loop.py +491 -92
- pdd/fix_errors_from_unit_tests.py +4 -3
- pdd/fix_main.py +278 -21
- pdd/fix_verification_errors.py +12 -100
- pdd/fix_verification_errors_loop.py +529 -286
- pdd/fix_verification_main.py +294 -89
- pdd/frontend/dist/assets/index-B5DZHykP.css +1 -0
- pdd/frontend/dist/assets/index-DQ3wkeQ2.js +449 -0
- pdd/frontend/dist/index.html +376 -0
- pdd/frontend/dist/logo.svg +33 -0
- pdd/generate_output_paths.py +139 -15
- pdd/generate_test.py +218 -146
- pdd/get_comment.py +19 -44
- pdd/get_extension.py +8 -9
- pdd/get_jwt_token.py +318 -22
- pdd/get_language.py +8 -7
- pdd/get_run_command.py +75 -0
- pdd/get_test_command.py +68 -0
- pdd/git_update.py +70 -19
- pdd/incremental_code_generator.py +2 -2
- pdd/insert_includes.py +13 -4
- pdd/llm_invoke.py +1711 -181
- pdd/load_prompt_template.py +19 -12
- pdd/path_resolution.py +140 -0
- pdd/pdd_completion.fish +25 -2
- pdd/pdd_completion.sh +30 -4
- pdd/pdd_completion.zsh +79 -4
- pdd/postprocess.py +14 -4
- pdd/preprocess.py +293 -24
- pdd/preprocess_main.py +41 -6
- pdd/prompts/agentic_bug_step10_pr_LLM.prompt +182 -0
- pdd/prompts/agentic_bug_step1_duplicate_LLM.prompt +73 -0
- pdd/prompts/agentic_bug_step2_docs_LLM.prompt +129 -0
- pdd/prompts/agentic_bug_step3_triage_LLM.prompt +95 -0
- pdd/prompts/agentic_bug_step4_reproduce_LLM.prompt +97 -0
- pdd/prompts/agentic_bug_step5_root_cause_LLM.prompt +123 -0
- pdd/prompts/agentic_bug_step6_test_plan_LLM.prompt +107 -0
- pdd/prompts/agentic_bug_step7_generate_LLM.prompt +172 -0
- pdd/prompts/agentic_bug_step8_verify_LLM.prompt +119 -0
- pdd/prompts/agentic_bug_step9_e2e_test_LLM.prompt +289 -0
- pdd/prompts/agentic_change_step10_identify_issues_LLM.prompt +1006 -0
- pdd/prompts/agentic_change_step11_fix_issues_LLM.prompt +984 -0
- pdd/prompts/agentic_change_step12_create_pr_LLM.prompt +131 -0
- pdd/prompts/agentic_change_step1_duplicate_LLM.prompt +73 -0
- pdd/prompts/agentic_change_step2_docs_LLM.prompt +101 -0
- pdd/prompts/agentic_change_step3_research_LLM.prompt +126 -0
- pdd/prompts/agentic_change_step4_clarify_LLM.prompt +164 -0
- pdd/prompts/agentic_change_step5_docs_change_LLM.prompt +981 -0
- pdd/prompts/agentic_change_step6_devunits_LLM.prompt +1005 -0
- pdd/prompts/agentic_change_step7_architecture_LLM.prompt +1044 -0
- pdd/prompts/agentic_change_step8_analyze_LLM.prompt +1027 -0
- pdd/prompts/agentic_change_step9_implement_LLM.prompt +1077 -0
- pdd/prompts/agentic_crash_explore_LLM.prompt +49 -0
- pdd/prompts/agentic_e2e_fix_step1_unit_tests_LLM.prompt +90 -0
- pdd/prompts/agentic_e2e_fix_step2_e2e_tests_LLM.prompt +91 -0
- pdd/prompts/agentic_e2e_fix_step3_root_cause_LLM.prompt +89 -0
- pdd/prompts/agentic_e2e_fix_step4_fix_e2e_tests_LLM.prompt +96 -0
- pdd/prompts/agentic_e2e_fix_step5_identify_devunits_LLM.prompt +91 -0
- pdd/prompts/agentic_e2e_fix_step6_create_unit_tests_LLM.prompt +106 -0
- pdd/prompts/agentic_e2e_fix_step7_verify_tests_LLM.prompt +116 -0
- pdd/prompts/agentic_e2e_fix_step8_run_pdd_fix_LLM.prompt +120 -0
- pdd/prompts/agentic_e2e_fix_step9_verify_all_LLM.prompt +146 -0
- pdd/prompts/agentic_fix_explore_LLM.prompt +45 -0
- pdd/prompts/agentic_fix_harvest_only_LLM.prompt +48 -0
- pdd/prompts/agentic_fix_primary_LLM.prompt +85 -0
- pdd/prompts/agentic_update_LLM.prompt +925 -0
- pdd/prompts/agentic_verify_explore_LLM.prompt +45 -0
- pdd/prompts/auto_include_LLM.prompt +122 -905
- pdd/prompts/change_LLM.prompt +3093 -1
- pdd/prompts/detect_change_LLM.prompt +686 -27
- pdd/prompts/example_generator_LLM.prompt +22 -1
- pdd/prompts/extract_code_LLM.prompt +5 -1
- pdd/prompts/extract_program_code_fix_LLM.prompt +7 -1
- pdd/prompts/extract_prompt_update_LLM.prompt +7 -8
- pdd/prompts/extract_promptline_LLM.prompt +17 -11
- pdd/prompts/find_verification_errors_LLM.prompt +6 -0
- pdd/prompts/fix_code_module_errors_LLM.prompt +12 -2
- pdd/prompts/fix_errors_from_unit_tests_LLM.prompt +9 -0
- pdd/prompts/fix_verification_errors_LLM.prompt +22 -0
- pdd/prompts/generate_test_LLM.prompt +41 -7
- pdd/prompts/generate_test_from_example_LLM.prompt +115 -0
- pdd/prompts/increase_tests_LLM.prompt +1 -5
- pdd/prompts/insert_includes_LLM.prompt +316 -186
- pdd/prompts/prompt_code_diff_LLM.prompt +119 -0
- pdd/prompts/prompt_diff_LLM.prompt +82 -0
- pdd/prompts/trace_LLM.prompt +25 -22
- pdd/prompts/unfinished_prompt_LLM.prompt +85 -1
- pdd/prompts/update_prompt_LLM.prompt +22 -1
- pdd/pytest_output.py +127 -12
- pdd/remote_session.py +876 -0
- pdd/render_mermaid.py +236 -0
- pdd/server/__init__.py +52 -0
- pdd/server/app.py +335 -0
- pdd/server/click_executor.py +587 -0
- pdd/server/executor.py +338 -0
- pdd/server/jobs.py +661 -0
- pdd/server/models.py +241 -0
- pdd/server/routes/__init__.py +31 -0
- pdd/server/routes/architecture.py +451 -0
- pdd/server/routes/auth.py +364 -0
- pdd/server/routes/commands.py +929 -0
- pdd/server/routes/config.py +42 -0
- pdd/server/routes/files.py +603 -0
- pdd/server/routes/prompts.py +1322 -0
- pdd/server/routes/websocket.py +473 -0
- pdd/server/security.py +243 -0
- pdd/server/terminal_spawner.py +209 -0
- pdd/server/token_counter.py +222 -0
- pdd/setup_tool.py +648 -0
- pdd/simple_math.py +2 -0
- pdd/split_main.py +3 -2
- pdd/summarize_directory.py +237 -195
- pdd/sync_animation.py +8 -4
- pdd/sync_determine_operation.py +839 -112
- pdd/sync_main.py +351 -57
- pdd/sync_orchestration.py +1400 -756
- pdd/sync_tui.py +848 -0
- pdd/template_expander.py +161 -0
- pdd/template_registry.py +264 -0
- pdd/templates/architecture/architecture_json.prompt +237 -0
- pdd/templates/generic/generate_prompt.prompt +174 -0
- pdd/trace.py +168 -12
- pdd/trace_main.py +4 -3
- pdd/track_cost.py +140 -63
- pdd/unfinished_prompt.py +51 -4
- pdd/update_main.py +567 -67
- pdd/update_model_costs.py +2 -2
- pdd/update_prompt.py +19 -4
- {pdd_cli-0.0.45.dist-info → pdd_cli-0.0.118.dist-info}/METADATA +29 -11
- pdd_cli-0.0.118.dist-info/RECORD +227 -0
- {pdd_cli-0.0.45.dist-info → pdd_cli-0.0.118.dist-info}/licenses/LICENSE +1 -1
- pdd_cli-0.0.45.dist-info/RECORD +0 -116
- {pdd_cli-0.0.45.dist-info → pdd_cli-0.0.118.dist-info}/WHEEL +0 -0
- {pdd_cli-0.0.45.dist-info → pdd_cli-0.0.118.dist-info}/entry_points.txt +0 -0
- {pdd_cli-0.0.45.dist-info → pdd_cli-0.0.118.dist-info}/top_level.txt +0 -0
pdd/fix_verification_main.py
CHANGED
|
@@ -3,13 +3,18 @@ import os
|
|
|
3
3
|
import subprocess
|
|
4
4
|
import click
|
|
5
5
|
import logging
|
|
6
|
+
import json
|
|
7
|
+
from pathlib import Path
|
|
6
8
|
from typing import Optional, Tuple, List, Dict, Any
|
|
7
9
|
|
|
10
|
+
import requests
|
|
11
|
+
|
|
8
12
|
# Use Rich for pretty printing to the console
|
|
9
13
|
from rich import print as rich_print
|
|
10
14
|
from rich.panel import Panel
|
|
11
15
|
from rich.syntax import Syntax
|
|
12
16
|
from rich.text import Text
|
|
17
|
+
from rich.console import Console
|
|
13
18
|
|
|
14
19
|
# Internal imports using relative paths
|
|
15
20
|
from .construct_paths import construct_paths
|
|
@@ -18,14 +23,27 @@ from .fix_verification_errors_loop import fix_verification_errors_loop
|
|
|
18
23
|
# Import DEFAULT_STRENGTH from the main package
|
|
19
24
|
from . import DEFAULT_STRENGTH, DEFAULT_TIME
|
|
20
25
|
from .python_env_detector import detect_host_python_executable
|
|
26
|
+
from .core.cloud import CloudConfig
|
|
21
27
|
|
|
22
28
|
# Default values from the README
|
|
23
29
|
DEFAULT_TEMPERATURE = 0.0
|
|
24
30
|
DEFAULT_MAX_ATTEMPTS = 3
|
|
25
31
|
DEFAULT_BUDGET = 5.0
|
|
26
32
|
|
|
33
|
+
# Cloud request timeout
|
|
34
|
+
CLOUD_REQUEST_TIMEOUT = 400 # seconds
|
|
35
|
+
|
|
27
36
|
# Configure logging
|
|
28
37
|
logger = logging.getLogger(__name__)
|
|
38
|
+
console = Console()
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _env_flag_enabled(name: str) -> bool:
|
|
42
|
+
"""Return True when an env var is set to a truthy value."""
|
|
43
|
+
value = os.environ.get(name)
|
|
44
|
+
if value is None:
|
|
45
|
+
return False
|
|
46
|
+
return str(value).strip().lower() in {"1", "true", "yes", "on"}
|
|
29
47
|
|
|
30
48
|
# Define a constant for the verification program name
|
|
31
49
|
VERIFICATION_PROGRAM_NAME = "verification_program.py" # Example, adjust if needed
|
|
@@ -116,6 +134,9 @@ def fix_verification_main(
|
|
|
116
134
|
verification_program: Optional[str], # Only used if loop=True
|
|
117
135
|
max_attempts: int = DEFAULT_MAX_ATTEMPTS,
|
|
118
136
|
budget: float = DEFAULT_BUDGET,
|
|
137
|
+
agentic_fallback: bool = True,
|
|
138
|
+
strength: Optional[float] = None,
|
|
139
|
+
temperature: Optional[float] = None,
|
|
119
140
|
) -> Tuple[bool, str, str, int, float, str]:
|
|
120
141
|
"""
|
|
121
142
|
CLI wrapper for the 'verify' command. Verifies code correctness by running
|
|
@@ -144,9 +165,9 @@ def fix_verification_main(
|
|
|
144
165
|
- total_cost (float): Total cost incurred.
|
|
145
166
|
- model_name (str): Name of the LLM used.
|
|
146
167
|
"""
|
|
147
|
-
# Extract global options from context
|
|
148
|
-
strength: float = ctx.obj.get('strength', DEFAULT_STRENGTH)
|
|
149
|
-
temperature: float = ctx.obj.get('temperature', DEFAULT_TEMPERATURE)
|
|
168
|
+
# Extract global options from context (prefer passed parameters over ctx.obj)
|
|
169
|
+
strength: float = strength if strength is not None else ctx.obj.get('strength', DEFAULT_STRENGTH)
|
|
170
|
+
temperature: float = temperature if temperature is not None else ctx.obj.get('temperature', DEFAULT_TEMPERATURE)
|
|
150
171
|
force: bool = ctx.obj.get('force', False)
|
|
151
172
|
quiet: bool = ctx.obj.get('quiet', False)
|
|
152
173
|
verbose: bool = ctx.obj.get('verbose', False)
|
|
@@ -204,6 +225,8 @@ def fix_verification_main(
|
|
|
204
225
|
quiet=quiet,
|
|
205
226
|
command="verify",
|
|
206
227
|
command_options=command_options,
|
|
228
|
+
context_override=ctx.obj.get('context'),
|
|
229
|
+
confirm_callback=ctx.obj.get('confirm_callback')
|
|
207
230
|
)
|
|
208
231
|
output_code_path = output_file_paths.get("output_code")
|
|
209
232
|
output_results_path = output_file_paths.get("output_results")
|
|
@@ -212,6 +235,9 @@ def fix_verification_main(
|
|
|
212
235
|
if verbose:
|
|
213
236
|
rich_print("[dim]Resolved output paths via construct_paths.[/dim]")
|
|
214
237
|
|
|
238
|
+
except click.Abort:
|
|
239
|
+
# User cancelled - re-raise to stop the sync loop
|
|
240
|
+
raise
|
|
215
241
|
except Exception as e:
|
|
216
242
|
# If the helper does not understand the "verify" command fall back.
|
|
217
243
|
if "invalid command" in str(e).lower():
|
|
@@ -230,7 +256,8 @@ def fix_verification_main(
|
|
|
230
256
|
input_strings["program_file"] = f.read()
|
|
231
257
|
except FileNotFoundError as fe:
|
|
232
258
|
rich_print(f"[bold red]Error:[/bold red] {fe}")
|
|
233
|
-
sys.exit(1)
|
|
259
|
+
# Return error result instead of sys.exit(1) to allow orchestrator to handle gracefully
|
|
260
|
+
return False, "", "", 0, 0.0, f"FileNotFoundError: {fe}"
|
|
234
261
|
|
|
235
262
|
# Pick or build output paths
|
|
236
263
|
if output_code_path is None:
|
|
@@ -252,7 +279,8 @@ def fix_verification_main(
|
|
|
252
279
|
if verbose:
|
|
253
280
|
import traceback
|
|
254
281
|
rich_print(Panel(traceback.format_exc(), title="Traceback", border_style="red"))
|
|
255
|
-
sys.exit(1)
|
|
282
|
+
# Return error result instead of sys.exit(1) to allow orchestrator to handle gracefully
|
|
283
|
+
return False, "", "", 0, 0.0, f"Error: {e}"
|
|
256
284
|
|
|
257
285
|
# --- Core Logic ---
|
|
258
286
|
success: bool = False
|
|
@@ -263,28 +291,55 @@ def fix_verification_main(
|
|
|
263
291
|
model_name: str = "N/A"
|
|
264
292
|
results_log_content: str = ""
|
|
265
293
|
|
|
294
|
+
# Determine cloud vs local execution preference
|
|
295
|
+
is_local_execution_preferred = ctx.obj.get('local', False)
|
|
296
|
+
cloud_only = _env_flag_enabled("PDD_CLOUD_ONLY") or _env_flag_enabled("PDD_NO_LOCAL_FALLBACK")
|
|
297
|
+
current_execution_is_local = is_local_execution_preferred and not cloud_only
|
|
298
|
+
|
|
299
|
+
# Cloud execution tracking
|
|
300
|
+
cloud_execution_attempted = False
|
|
301
|
+
cloud_execution_succeeded = False
|
|
302
|
+
|
|
266
303
|
try:
|
|
267
304
|
if loop:
|
|
305
|
+
# Determine if loop should use cloud for LLM calls (hybrid mode)
|
|
306
|
+
# Local verification execution stays local, but LLM fix calls can go to cloud
|
|
307
|
+
use_cloud_for_loop = not is_local_execution_preferred and not cloud_only
|
|
308
|
+
|
|
309
|
+
# If cloud_only is set but we're in loop mode, we still use hybrid approach
|
|
310
|
+
if cloud_only and not is_local_execution_preferred:
|
|
311
|
+
use_cloud_for_loop = True
|
|
312
|
+
|
|
313
|
+
if verbose:
|
|
314
|
+
mode_desc = "hybrid (local execution + cloud LLM)" if use_cloud_for_loop else "local"
|
|
315
|
+
console.print(Panel(f"Performing {mode_desc} verification loop...", title="[blue]Mode[/blue]", expand=False))
|
|
316
|
+
|
|
268
317
|
if not quiet:
|
|
269
318
|
rich_print("[dim]Running Iterative Verification (fix_verification_errors_loop)...[/dim]")
|
|
270
319
|
try:
|
|
320
|
+
# Build kwargs for fix_verification_errors_loop
|
|
321
|
+
loop_kwargs = {
|
|
322
|
+
"program_file": program_file,
|
|
323
|
+
"code_file": code_file,
|
|
324
|
+
"prompt": input_strings["prompt_file"],
|
|
325
|
+
"prompt_file": prompt_file,
|
|
326
|
+
"verification_program": verification_program,
|
|
327
|
+
"strength": strength,
|
|
328
|
+
"temperature": temperature,
|
|
329
|
+
"llm_time": time,
|
|
330
|
+
"max_attempts": max_attempts,
|
|
331
|
+
"budget": budget,
|
|
332
|
+
"verification_log_file": output_results_path,
|
|
333
|
+
"verbose": verbose,
|
|
334
|
+
"program_args": [],
|
|
335
|
+
"agentic_fallback": agentic_fallback,
|
|
336
|
+
}
|
|
337
|
+
# Only pass use_cloud when explicitly True (cloud not ready for prod yet)
|
|
338
|
+
if use_cloud_for_loop:
|
|
339
|
+
loop_kwargs["use_cloud"] = True
|
|
340
|
+
|
|
271
341
|
# Call fix_verification_errors_loop for iterative fixing
|
|
272
|
-
loop_results = fix_verification_errors_loop(
|
|
273
|
-
program_file=program_file, # Changed to pass the program_file path
|
|
274
|
-
code_file=code_file, # Changed to pass the code_file path
|
|
275
|
-
prompt=input_strings["prompt_file"], # Correctly passing prompt content
|
|
276
|
-
verification_program=verification_program, # Path to the verifier program
|
|
277
|
-
strength=strength,
|
|
278
|
-
temperature=temperature,
|
|
279
|
-
llm_time=time, # Changed 'time' to 'llm_time'
|
|
280
|
-
max_attempts=max_attempts,
|
|
281
|
-
budget=budget,
|
|
282
|
-
verification_log_file=output_results_path, # Use resolved output_results_path
|
|
283
|
-
# output_code_path should not be passed here
|
|
284
|
-
# output_program_path should not be passed here
|
|
285
|
-
verbose=verbose,
|
|
286
|
-
program_args=[] # Pass an empty list for program_args
|
|
287
|
-
)
|
|
342
|
+
loop_results = fix_verification_errors_loop(**loop_kwargs)
|
|
288
343
|
success = loop_results.get('success', False)
|
|
289
344
|
final_program = loop_results.get('final_program', "") # Use .get for safety
|
|
290
345
|
final_code = loop_results.get('final_code', "") # Use .get for safety
|
|
@@ -304,7 +359,7 @@ def fix_verification_main(
|
|
|
304
359
|
rich_print("\n[bold blue]Running Single Pass Verification (fix_verification_errors)...[/bold blue]")
|
|
305
360
|
attempts = 1 # Single pass is one attempt
|
|
306
361
|
|
|
307
|
-
# 1. Run the program file to get its output
|
|
362
|
+
# 1. Run the program file to get its output (always local)
|
|
308
363
|
if not quiet:
|
|
309
364
|
rich_print(f"Executing program: [cyan]{program_file}[/cyan]")
|
|
310
365
|
run_success, program_stdout, program_stderr = run_program(program_file)
|
|
@@ -315,71 +370,215 @@ def fix_verification_main(
|
|
|
315
370
|
rich_print(Panel(program_output if program_output else "[No Output]", border_style="dim"))
|
|
316
371
|
rich_print("[dim]--- End Program Output ---[/dim]")
|
|
317
372
|
|
|
318
|
-
#
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
373
|
+
# 2. Attempt cloud verification first if not local preferred
|
|
374
|
+
if not current_execution_is_local:
|
|
375
|
+
if verbose:
|
|
376
|
+
console.print(Panel("Attempting cloud verification execution...", title="[blue]Mode[/blue]", expand=False))
|
|
377
|
+
|
|
378
|
+
jwt_token = CloudConfig.get_jwt_token(verbose=verbose)
|
|
379
|
+
|
|
380
|
+
if not jwt_token:
|
|
381
|
+
if cloud_only:
|
|
382
|
+
console.print("[red]Cloud authentication failed.[/red]")
|
|
383
|
+
raise click.UsageError("Cloud authentication failed")
|
|
384
|
+
console.print("[yellow]Cloud authentication failed. Falling back to local execution.[/yellow]")
|
|
385
|
+
current_execution_is_local = True
|
|
386
|
+
|
|
387
|
+
if jwt_token and not current_execution_is_local:
|
|
388
|
+
cloud_execution_attempted = True
|
|
389
|
+
# Build cloud payload
|
|
390
|
+
payload = {
|
|
391
|
+
"programContent": input_strings["program_file"],
|
|
392
|
+
"promptContent": input_strings["prompt_file"],
|
|
393
|
+
"codeContent": input_strings["code_file"],
|
|
394
|
+
"outputContent": program_output,
|
|
395
|
+
"language": language,
|
|
396
|
+
"strength": strength,
|
|
397
|
+
"temperature": temperature,
|
|
398
|
+
"time": time if time is not None else 0.25,
|
|
399
|
+
"verbose": verbose,
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
headers = {
|
|
403
|
+
"Authorization": f"Bearer {jwt_token}",
|
|
404
|
+
"Content-Type": "application/json"
|
|
405
|
+
}
|
|
406
|
+
cloud_url = CloudConfig.get_endpoint_url("verifyCode")
|
|
407
|
+
|
|
408
|
+
try:
|
|
409
|
+
response = requests.post(
|
|
410
|
+
cloud_url,
|
|
411
|
+
json=payload,
|
|
412
|
+
headers=headers,
|
|
413
|
+
timeout=CLOUD_REQUEST_TIMEOUT
|
|
414
|
+
)
|
|
415
|
+
response.raise_for_status()
|
|
416
|
+
|
|
417
|
+
response_data = response.json()
|
|
418
|
+
fixed_code = response_data.get("fixedCode", "")
|
|
419
|
+
fixed_program = response_data.get("fixedProgram", "")
|
|
420
|
+
explanation = response_data.get("explanation", "")
|
|
421
|
+
issues_count = response_data.get("issuesCount", 0)
|
|
422
|
+
total_cost = float(response_data.get("totalCost", 0.0))
|
|
423
|
+
model_name = response_data.get("modelName", "cloud_model")
|
|
424
|
+
|
|
425
|
+
cloud_execution_succeeded = True
|
|
426
|
+
|
|
427
|
+
# Determine success based on issues count
|
|
428
|
+
code_updated = fixed_code != input_strings["code_file"]
|
|
429
|
+
program_updated = fixed_program != input_strings["program_file"]
|
|
430
|
+
|
|
431
|
+
if issues_count == 0:
|
|
432
|
+
success = True
|
|
433
|
+
if not quiet: rich_print("[green]Verification Passed:[/green] Cloud found no discrepancies.")
|
|
434
|
+
elif code_updated or program_updated:
|
|
435
|
+
success = True
|
|
436
|
+
if not quiet: rich_print("[yellow]Verification Issues Found:[/yellow] Cloud proposed fixes.")
|
|
437
|
+
else:
|
|
438
|
+
success = False
|
|
439
|
+
if not quiet: rich_print("[red]Verification Failed:[/red] Cloud found discrepancies but proposed no fixes.")
|
|
440
|
+
|
|
441
|
+
final_program = fixed_program
|
|
442
|
+
final_code = fixed_code
|
|
443
|
+
|
|
444
|
+
# Build results log content for cloud execution
|
|
445
|
+
results_log_content = "PDD Verify Results (Cloud Single Pass)\n"
|
|
446
|
+
results_log_content += f"Prompt File: {prompt_file}\n"
|
|
447
|
+
results_log_content += f"Code File: {code_file}\n"
|
|
448
|
+
results_log_content += f"Program File: {program_file}\n"
|
|
449
|
+
results_log_content += f"Success: {success}\n"
|
|
450
|
+
results_log_content += f"Issues Found Count: {issues_count}\n"
|
|
451
|
+
results_log_content += f"Code Updated: {code_updated}\n"
|
|
452
|
+
results_log_content += f"Program Updated: {program_updated}\n"
|
|
453
|
+
results_log_content += f"Model Used: {model_name}\n"
|
|
454
|
+
results_log_content += f"Total Cost: ${total_cost:.6f}\n"
|
|
455
|
+
results_log_content += "\n--- LLM Explanation ---\n"
|
|
456
|
+
results_log_content += explanation or 'N/A'
|
|
457
|
+
results_log_content += "\n\n--- Program Output Used for Verification ---\n"
|
|
458
|
+
results_log_content += program_output
|
|
459
|
+
|
|
460
|
+
if verbose:
|
|
461
|
+
console.print(Panel(
|
|
462
|
+
f"Cloud verification completed. Model: {model_name}, Cost: ${total_cost:.6f}",
|
|
463
|
+
title="[green]Cloud Success[/green]",
|
|
464
|
+
expand=False
|
|
465
|
+
))
|
|
466
|
+
|
|
467
|
+
except requests.exceptions.Timeout:
|
|
468
|
+
if cloud_only:
|
|
469
|
+
console.print(f"[red]Cloud execution timed out ({CLOUD_REQUEST_TIMEOUT}s).[/red]")
|
|
470
|
+
raise click.UsageError("Cloud execution timed out")
|
|
471
|
+
console.print(f"[yellow]Cloud execution timed out ({CLOUD_REQUEST_TIMEOUT}s). Falling back to local.[/yellow]")
|
|
472
|
+
current_execution_is_local = True
|
|
473
|
+
|
|
474
|
+
except requests.exceptions.HTTPError as e:
|
|
475
|
+
status_code = e.response.status_code if e.response else 0
|
|
476
|
+
err_content = e.response.text[:200] if e.response else "No response content"
|
|
477
|
+
|
|
478
|
+
# Non-recoverable errors: do NOT fall back to local
|
|
479
|
+
if status_code == 402: # Insufficient credits
|
|
480
|
+
try:
|
|
481
|
+
error_data = e.response.json()
|
|
482
|
+
current_balance = error_data.get("currentBalance", "unknown")
|
|
483
|
+
estimated_cost = error_data.get("estimatedCost", "unknown")
|
|
484
|
+
console.print(f"[red]Insufficient credits. Current balance: {current_balance}, estimated cost: {estimated_cost}[/red]")
|
|
485
|
+
except Exception:
|
|
486
|
+
console.print(f"[red]Insufficient credits: {err_content}[/red]")
|
|
487
|
+
raise click.UsageError("Insufficient credits for cloud verification")
|
|
488
|
+
elif status_code == 401: # Authentication error
|
|
489
|
+
console.print(f"[red]Authentication failed: {err_content}[/red]")
|
|
490
|
+
raise click.UsageError("Cloud authentication failed")
|
|
491
|
+
elif status_code == 403: # Authorization error (not approved)
|
|
492
|
+
console.print(f"[red]Access denied: {err_content}[/red]")
|
|
493
|
+
raise click.UsageError("Access denied - user not approved")
|
|
494
|
+
elif status_code == 400: # Validation error
|
|
495
|
+
console.print(f"[red]Invalid request: {err_content}[/red]")
|
|
496
|
+
raise click.UsageError(f"Invalid request: {err_content}")
|
|
497
|
+
else:
|
|
498
|
+
# Recoverable errors (5xx, unexpected errors): fall back to local
|
|
499
|
+
if cloud_only:
|
|
500
|
+
console.print(f"[red]Cloud HTTP error ({status_code}): {err_content}[/red]")
|
|
501
|
+
raise click.UsageError(f"Cloud HTTP error ({status_code}): {err_content}")
|
|
502
|
+
console.print(f"[yellow]Cloud HTTP error ({status_code}): {err_content}. Falling back to local.[/yellow]")
|
|
503
|
+
current_execution_is_local = True
|
|
504
|
+
|
|
505
|
+
except requests.exceptions.RequestException as e:
|
|
506
|
+
if cloud_only:
|
|
507
|
+
console.print(f"[red]Cloud network error: {e}[/red]")
|
|
508
|
+
raise click.UsageError(f"Cloud network error: {e}")
|
|
509
|
+
console.print(f"[yellow]Cloud network error: {e}. Falling back to local.[/yellow]")
|
|
510
|
+
current_execution_is_local = True
|
|
511
|
+
|
|
512
|
+
except json.JSONDecodeError:
|
|
513
|
+
if cloud_only:
|
|
514
|
+
console.print("[red]Cloud returned invalid JSON.[/red]")
|
|
515
|
+
raise click.UsageError("Cloud returned invalid JSON")
|
|
516
|
+
console.print("[yellow]Cloud returned invalid JSON. Falling back to local.[/yellow]")
|
|
517
|
+
current_execution_is_local = True
|
|
518
|
+
|
|
519
|
+
# Local execution path (when cloud failed/skipped or local preferred)
|
|
520
|
+
if not cloud_execution_succeeded:
|
|
521
|
+
if verbose:
|
|
522
|
+
console.print(Panel("Performing local verification...", title="[blue]Mode[/blue]", expand=False))
|
|
523
|
+
|
|
524
|
+
# Call fix_verification_errors with content and program output
|
|
525
|
+
if not quiet:
|
|
526
|
+
rich_print("Calling LLM to verify program output against prompt...")
|
|
527
|
+
fix_results = fix_verification_errors(
|
|
528
|
+
program=input_strings["program_file"],
|
|
529
|
+
prompt=input_strings["prompt_file"],
|
|
530
|
+
code=input_strings["code_file"],
|
|
531
|
+
output=program_output,
|
|
532
|
+
strength=strength,
|
|
533
|
+
temperature=temperature,
|
|
534
|
+
verbose=verbose,
|
|
535
|
+
time=time # Pass time to single pass function
|
|
536
|
+
)
|
|
382
537
|
|
|
538
|
+
# Determine success: If no issues were found OR if fixes were applied
|
|
539
|
+
# The definition of 'success' here means the *final* state is verified.
|
|
540
|
+
issues_found = fix_results['verification_issues_count'] > 0
|
|
541
|
+
code_updated = fix_results['fixed_code'] != input_strings["code_file"]
|
|
542
|
+
program_updated = fix_results['fixed_program'] != input_strings["program_file"]
|
|
543
|
+
|
|
544
|
+
if not issues_found:
|
|
545
|
+
success = True
|
|
546
|
+
if not quiet: rich_print("[green]Verification Passed:[/green] LLM found no discrepancies.")
|
|
547
|
+
elif code_updated or program_updated:
|
|
548
|
+
# If issues were found AND fixes were made, assume success for this single pass.
|
|
549
|
+
# A more robust check might re-run the program with fixed code, but that's the loop's job.
|
|
550
|
+
success = True
|
|
551
|
+
if not quiet: rich_print("[yellow]Verification Issues Found:[/yellow] LLM proposed fixes.")
|
|
552
|
+
else:
|
|
553
|
+
success = False
|
|
554
|
+
if not quiet: rich_print("[red]Verification Failed:[/red] LLM found discrepancies but proposed no fixes.")
|
|
555
|
+
|
|
556
|
+
final_program = fix_results['fixed_program']
|
|
557
|
+
final_code = fix_results['fixed_code']
|
|
558
|
+
total_cost = fix_results['total_cost']
|
|
559
|
+
model_name = fix_results['model_name']
|
|
560
|
+
|
|
561
|
+
# Build results log content for single pass
|
|
562
|
+
results_log_content = "PDD Verify Results (Single Pass)\n"
|
|
563
|
+
results_log_content += f"Timestamp: {os.path.getmtime(prompt_file)}\n"
|
|
564
|
+
results_log_content += f"Prompt File: {prompt_file}\n"
|
|
565
|
+
results_log_content += f"Code File: {code_file}\n"
|
|
566
|
+
results_log_content += f"Program File: {program_file}\n"
|
|
567
|
+
results_log_content += f"Success: {success}\n"
|
|
568
|
+
results_log_content += f"Issues Found Count: {fix_results['verification_issues_count']}\n"
|
|
569
|
+
results_log_content += f"Code Updated: {code_updated}\n"
|
|
570
|
+
results_log_content += f"Program Updated: {program_updated}\n"
|
|
571
|
+
results_log_content += f"Model Used: {model_name}\n"
|
|
572
|
+
results_log_content += f"Total Cost: ${total_cost:.6f}\n"
|
|
573
|
+
results_log_content += "\n--- LLM Explanation ---\n"
|
|
574
|
+
results_log_content += fix_results.get('explanation') or 'N/A'
|
|
575
|
+
results_log_content += "\n\n--- Program Output Used for Verification ---\n"
|
|
576
|
+
results_log_content += program_output
|
|
577
|
+
|
|
578
|
+
|
|
579
|
+
except click.UsageError:
|
|
580
|
+
# Re-raise UsageError for proper CLI handling (e.g., cloud auth failures, insufficient credits)
|
|
581
|
+
raise
|
|
383
582
|
except Exception as e:
|
|
384
583
|
success = False
|
|
385
584
|
rich_print(f"[bold red]Error during verification process:[/bold red] {e}")
|
|
@@ -407,7 +606,9 @@ def fix_verification_main(
|
|
|
407
606
|
try:
|
|
408
607
|
if verbose:
|
|
409
608
|
rich_print(f"[cyan bold DEBUG] In fix_verification_main, ATTEMPTING to write code to: {output_code_path!r}")
|
|
410
|
-
|
|
609
|
+
output_code_path_obj = Path(output_code_path)
|
|
610
|
+
output_code_path_obj.parent.mkdir(parents=True, exist_ok=True)
|
|
611
|
+
with open(output_code_path_obj, "w") as f:
|
|
411
612
|
f.write(final_code)
|
|
412
613
|
saved_code_path = output_code_path
|
|
413
614
|
if not quiet:
|
|
@@ -427,7 +628,9 @@ def fix_verification_main(
|
|
|
427
628
|
try:
|
|
428
629
|
if verbose:
|
|
429
630
|
rich_print(f"[cyan bold DEBUG] In fix_verification_main, ATTEMPTING to write program to: {output_program_path!r}")
|
|
430
|
-
|
|
631
|
+
output_program_path_obj = Path(output_program_path)
|
|
632
|
+
output_program_path_obj.parent.mkdir(parents=True, exist_ok=True)
|
|
633
|
+
with open(output_program_path_obj, "w") as f:
|
|
431
634
|
f.write(final_program)
|
|
432
635
|
saved_program_path = output_program_path
|
|
433
636
|
if not quiet:
|
|
@@ -437,7 +640,9 @@ def fix_verification_main(
|
|
|
437
640
|
|
|
438
641
|
if not loop and output_results_path:
|
|
439
642
|
try:
|
|
440
|
-
|
|
643
|
+
output_results_path_obj = Path(output_results_path)
|
|
644
|
+
output_results_path_obj.parent.mkdir(parents=True, exist_ok=True)
|
|
645
|
+
with open(output_results_path_obj, "w") as f:
|
|
441
646
|
f.write(results_log_content)
|
|
442
647
|
saved_results_path = output_results_path
|
|
443
648
|
if not quiet:
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.react-flow{direction:ltr}.react-flow__container{position:absolute;width:100%;height:100%;top:0;left:0}.react-flow__pane{z-index:1;cursor:-webkit-grab;cursor:grab}.react-flow__pane.selection{cursor:pointer}.react-flow__pane.dragging{cursor:-webkit-grabbing;cursor:grabbing}.react-flow__viewport{transform-origin:0 0;z-index:2;pointer-events:none}.react-flow__renderer{z-index:4}.react-flow__selection{z-index:6}.react-flow__nodesselection-rect:focus,.react-flow__nodesselection-rect:focus-visible{outline:none}.react-flow .react-flow__edges{pointer-events:none;overflow:visible}.react-flow__edge-path,.react-flow__connection-path{stroke:#b1b1b7;stroke-width:1;fill:none}.react-flow__edge{pointer-events:visibleStroke;cursor:pointer}.react-flow__edge.animated path{stroke-dasharray:5;-webkit-animation:dashdraw .5s linear infinite;animation:dashdraw .5s linear infinite}.react-flow__edge.animated path.react-flow__edge-interaction{stroke-dasharray:none;-webkit-animation:none;animation:none}.react-flow__edge.inactive{pointer-events:none}.react-flow__edge.selected,.react-flow__edge:focus,.react-flow__edge:focus-visible{outline:none}.react-flow__edge.selected .react-flow__edge-path,.react-flow__edge:focus .react-flow__edge-path,.react-flow__edge:focus-visible .react-flow__edge-path{stroke:#555}.react-flow__edge-textwrapper{pointer-events:all}.react-flow__edge-textbg{fill:#fff}.react-flow__edge .react-flow__edge-text{pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.react-flow__connection{pointer-events:none}.react-flow__connection .animated{stroke-dasharray:5;-webkit-animation:dashdraw .5s linear infinite;animation:dashdraw .5s linear infinite}.react-flow__connectionline{z-index:1001}.react-flow__nodes{pointer-events:none;transform-origin:0 0}.react-flow__node{position:absolute;-webkit-user-select:none;-moz-user-select:none;user-select:none;pointer-events:all;transform-origin:0 0;box-sizing:border-box;cursor:-webkit-grab;cursor:grab}.react-flow__node.dragging{cursor:-webkit-grabbing;cursor:grabbing}.react-flow__nodesselection{z-index:3;transform-origin:left top;pointer-events:none}.react-flow__nodesselection-rect{position:absolute;pointer-events:all;cursor:-webkit-grab;cursor:grab}.react-flow__handle{position:absolute;pointer-events:none;min-width:5px;min-height:5px;width:6px;height:6px;background:#1a192b;border:1px solid white;border-radius:100%}.react-flow__handle.connectionindicator{pointer-events:all;cursor:crosshair}.react-flow__handle-bottom{top:auto;left:50%;bottom:-4px;transform:translate(-50%)}.react-flow__handle-top{left:50%;top:-4px;transform:translate(-50%)}.react-flow__handle-left{top:50%;left:-4px;transform:translateY(-50%)}.react-flow__handle-right{right:-4px;top:50%;transform:translateY(-50%)}.react-flow__edgeupdater{cursor:move;pointer-events:all}.react-flow__panel{position:absolute;z-index:5;margin:15px}.react-flow__panel.top{top:0}.react-flow__panel.bottom{bottom:0}.react-flow__panel.left{left:0}.react-flow__panel.right{right:0}.react-flow__panel.center{left:50%;transform:translate(-50%)}.react-flow__attribution{font-size:10px;background:#ffffff80;padding:2px 3px;margin:0}.react-flow__attribution a{text-decoration:none;color:#999}@-webkit-keyframes dashdraw{0%{stroke-dashoffset:10}}@keyframes dashdraw{0%{stroke-dashoffset:10}}.react-flow__edgelabel-renderer{position:absolute;width:100%;height:100%;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.react-flow__edge.updating .react-flow__edge-path{stroke:#777}.react-flow__edge-text{font-size:10px}.react-flow__node.selectable:focus,.react-flow__node.selectable:focus-visible{outline:none}.react-flow__node-default,.react-flow__node-input,.react-flow__node-output,.react-flow__node-group{padding:10px;border-radius:3px;width:150px;font-size:12px;color:#222;text-align:center;border-width:1px;border-style:solid;border-color:#1a192b;background-color:#fff}.react-flow__node-default.selectable:hover,.react-flow__node-input.selectable:hover,.react-flow__node-output.selectable:hover,.react-flow__node-group.selectable:hover{box-shadow:0 1px 4px 1px #00000014}.react-flow__node-default.selectable.selected,.react-flow__node-default.selectable:focus,.react-flow__node-default.selectable:focus-visible,.react-flow__node-input.selectable.selected,.react-flow__node-input.selectable:focus,.react-flow__node-input.selectable:focus-visible,.react-flow__node-output.selectable.selected,.react-flow__node-output.selectable:focus,.react-flow__node-output.selectable:focus-visible,.react-flow__node-group.selectable.selected,.react-flow__node-group.selectable:focus,.react-flow__node-group.selectable:focus-visible{box-shadow:0 0 0 .5px #1a192b}.react-flow__node-group{background-color:#f0f0f040}.react-flow__nodesselection-rect,.react-flow__selection{background:#0059dc14;border:1px dotted rgba(0,89,220,.8)}.react-flow__nodesselection-rect:focus,.react-flow__nodesselection-rect:focus-visible,.react-flow__selection:focus,.react-flow__selection:focus-visible{outline:none}.react-flow__controls{box-shadow:0 0 2px 1px #00000014}.react-flow__controls-button{border:none;background:#fefefe;border-bottom:1px solid #eee;box-sizing:content-box;display:flex;justify-content:center;align-items:center;width:16px;height:16px;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;user-select:none;padding:5px}.react-flow__controls-button:hover{background:#f4f4f4}.react-flow__controls-button svg{width:100%;max-width:12px;max-height:12px}.react-flow__controls-button:disabled{pointer-events:none}.react-flow__controls-button:disabled svg{fill-opacity:.4}.react-flow__minimap{background-color:#fff}.react-flow__minimap svg{display:block}.react-flow__resize-control{position:absolute}.react-flow__resize-control.left,.react-flow__resize-control.right{cursor:ew-resize}.react-flow__resize-control.top,.react-flow__resize-control.bottom{cursor:ns-resize}.react-flow__resize-control.top.left,.react-flow__resize-control.bottom.right{cursor:nwse-resize}.react-flow__resize-control.bottom.left,.react-flow__resize-control.top.right{cursor:nesw-resize}.react-flow__resize-control.handle{width:4px;height:4px;border:1px solid #fff;border-radius:1px;background-color:#3367d9;transform:translate(-50%,-50%)}.react-flow__resize-control.handle.left{left:0;top:50%}.react-flow__resize-control.handle.right{left:100%;top:50%}.react-flow__resize-control.handle.top{left:50%;top:0}.react-flow__resize-control.handle.bottom{left:50%;top:100%}.react-flow__resize-control.handle.top.left,.react-flow__resize-control.handle.bottom.left{left:0}.react-flow__resize-control.handle.top.right,.react-flow__resize-control.handle.bottom.right{left:100%}.react-flow__resize-control.line{border-color:#3367d9;border-width:0;border-style:solid}.react-flow__resize-control.line.left,.react-flow__resize-control.line.right{width:1px;transform:translate(-50%);top:0;height:100%}.react-flow__resize-control.line.left{left:0;border-left-width:1px}.react-flow__resize-control.line.right{left:100%;border-right-width:1px}.react-flow__resize-control.line.top,.react-flow__resize-control.line.bottom{height:1px;transform:translateY(-50%);left:0;width:100%}.react-flow__resize-control.line.top{top:0;border-top-width:1px}.react-flow__resize-control.line.bottom{border-bottom-width:1px;top:100%}
|