pdd-cli 0.0.90__py3-none-any.whl → 0.0.121__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 +38 -6
- pdd/agentic_bug.py +323 -0
- pdd/agentic_bug_orchestrator.py +506 -0
- pdd/agentic_change.py +231 -0
- pdd/agentic_change_orchestrator.py +537 -0
- pdd/agentic_common.py +533 -770
- pdd/agentic_crash.py +2 -1
- pdd/agentic_e2e_fix.py +319 -0
- pdd/agentic_e2e_fix_orchestrator.py +582 -0
- pdd/agentic_fix.py +118 -3
- pdd/agentic_update.py +27 -9
- pdd/agentic_verify.py +3 -2
- pdd/architecture_sync.py +565 -0
- pdd/auth_service.py +210 -0
- pdd/auto_deps_main.py +63 -53
- pdd/auto_include.py +236 -3
- pdd/auto_update.py +125 -47
- pdd/bug_main.py +195 -23
- pdd/cmd_test_main.py +345 -197
- pdd/code_generator.py +4 -2
- pdd/code_generator_main.py +118 -32
- pdd/commands/__init__.py +6 -0
- pdd/commands/analysis.py +113 -48
- pdd/commands/auth.py +309 -0
- pdd/commands/connect.py +358 -0
- pdd/commands/fix.py +155 -114
- pdd/commands/generate.py +5 -0
- pdd/commands/maintenance.py +3 -2
- pdd/commands/misc.py +8 -0
- pdd/commands/modify.py +225 -163
- pdd/commands/sessions.py +284 -0
- pdd/commands/utility.py +12 -7
- pdd/construct_paths.py +334 -32
- pdd/context_generator_main.py +167 -170
- pdd/continue_generation.py +6 -3
- pdd/core/__init__.py +33 -0
- pdd/core/cli.py +44 -7
- pdd/core/cloud.py +237 -0
- pdd/core/dump.py +68 -20
- pdd/core/errors.py +4 -0
- pdd/core/remote_session.py +61 -0
- pdd/crash_main.py +219 -23
- pdd/data/llm_model.csv +4 -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 +208 -34
- pdd/fix_code_module_errors.py +6 -2
- pdd/fix_error_loop.py +291 -38
- pdd/fix_main.py +208 -6
- pdd/fix_verification_errors_loop.py +235 -26
- pdd/fix_verification_main.py +269 -83
- pdd/frontend/dist/assets/index-B5DZHykP.css +1 -0
- pdd/frontend/dist/assets/index-CUWd8al1.js +450 -0
- pdd/frontend/dist/index.html +376 -0
- pdd/frontend/dist/logo.svg +33 -0
- pdd/generate_output_paths.py +46 -5
- pdd/generate_test.py +212 -151
- pdd/get_comment.py +19 -44
- pdd/get_extension.py +8 -9
- pdd/get_jwt_token.py +309 -20
- pdd/get_language.py +8 -7
- pdd/get_run_command.py +7 -5
- pdd/insert_includes.py +2 -1
- pdd/llm_invoke.py +531 -97
- pdd/load_prompt_template.py +15 -34
- pdd/operation_log.py +342 -0
- pdd/path_resolution.py +140 -0
- pdd/postprocess.py +122 -97
- pdd/preprocess.py +68 -12
- pdd/preprocess_main.py +33 -1
- 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 +140 -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_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_primary_LLM.prompt +2 -2
- pdd/prompts/agentic_update_LLM.prompt +192 -338
- pdd/prompts/auto_include_LLM.prompt +22 -0
- pdd/prompts/change_LLM.prompt +3093 -1
- pdd/prompts/detect_change_LLM.prompt +571 -14
- pdd/prompts/fix_code_module_errors_LLM.prompt +8 -0
- pdd/prompts/fix_errors_from_unit_tests_LLM.prompt +1 -0
- pdd/prompts/generate_test_LLM.prompt +19 -1
- pdd/prompts/generate_test_from_example_LLM.prompt +366 -0
- pdd/prompts/insert_includes_LLM.prompt +262 -252
- pdd/prompts/prompt_code_diff_LLM.prompt +123 -0
- pdd/prompts/prompt_diff_LLM.prompt +82 -0
- pdd/remote_session.py +876 -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 +1347 -0
- pdd/server/routes/websocket.py +473 -0
- pdd/server/security.py +243 -0
- pdd/server/terminal_spawner.py +217 -0
- pdd/server/token_counter.py +222 -0
- pdd/summarize_directory.py +236 -237
- pdd/sync_animation.py +8 -4
- pdd/sync_determine_operation.py +329 -47
- pdd/sync_main.py +272 -28
- pdd/sync_orchestration.py +289 -211
- pdd/sync_order.py +304 -0
- pdd/template_expander.py +161 -0
- pdd/templates/architecture/architecture_json.prompt +41 -46
- pdd/trace.py +1 -1
- pdd/track_cost.py +0 -13
- pdd/unfinished_prompt.py +2 -1
- pdd/update_main.py +68 -26
- {pdd_cli-0.0.90.dist-info → pdd_cli-0.0.121.dist-info}/METADATA +15 -10
- pdd_cli-0.0.121.dist-info/RECORD +229 -0
- pdd_cli-0.0.90.dist-info/RECORD +0 -153
- {pdd_cli-0.0.90.dist-info → pdd_cli-0.0.121.dist-info}/WHEEL +0 -0
- {pdd_cli-0.0.90.dist-info → pdd_cli-0.0.121.dist-info}/entry_points.txt +0 -0
- {pdd_cli-0.0.90.dist-info → pdd_cli-0.0.121.dist-info}/licenses/LICENSE +0 -0
- {pdd_cli-0.0.90.dist-info → pdd_cli-0.0.121.dist-info}/top_level.txt +0 -0
pdd/agentic_fix.py
CHANGED
|
@@ -4,6 +4,7 @@ import os
|
|
|
4
4
|
import re
|
|
5
5
|
import shutil
|
|
6
6
|
import subprocess
|
|
7
|
+
import sys
|
|
7
8
|
import difflib
|
|
8
9
|
import tempfile
|
|
9
10
|
from pathlib import Path
|
|
@@ -56,6 +57,68 @@ def _verbose(msg: str) -> None:
|
|
|
56
57
|
if _IS_VERBOSE:
|
|
57
58
|
console.print(msg)
|
|
58
59
|
|
|
60
|
+
|
|
61
|
+
def _detect_suspicious_files(cwd: Path, context: str = "") -> List[Path]:
|
|
62
|
+
"""
|
|
63
|
+
Detect suspicious single-character files (like C, E, T) in a directory.
|
|
64
|
+
|
|
65
|
+
This is a diagnostic function to help identify when/where these files are created.
|
|
66
|
+
Issue #186: Empty files named C, E, T (first letters of Code, Example, Test)
|
|
67
|
+
have been appearing during agentic operations.
|
|
68
|
+
|
|
69
|
+
Args:
|
|
70
|
+
cwd: Directory to scan
|
|
71
|
+
context: Description of what operation just ran (for logging)
|
|
72
|
+
|
|
73
|
+
Returns:
|
|
74
|
+
List of suspicious file paths found
|
|
75
|
+
"""
|
|
76
|
+
suspicious: List[Path] = []
|
|
77
|
+
try:
|
|
78
|
+
for f in cwd.iterdir():
|
|
79
|
+
if f.is_file() and len(f.name) <= 2 and not f.name.startswith('.'):
|
|
80
|
+
suspicious.append(f)
|
|
81
|
+
|
|
82
|
+
if suspicious:
|
|
83
|
+
import datetime
|
|
84
|
+
timestamp = datetime.datetime.now().isoformat()
|
|
85
|
+
_always(f"[bold red]⚠️ SUSPICIOUS FILES DETECTED (Issue #186)[/bold red]")
|
|
86
|
+
_always(f"[red]Timestamp: {timestamp}[/red]")
|
|
87
|
+
_always(f"[red]Context: {context}[/red]")
|
|
88
|
+
_always(f"[red]Directory: {cwd}[/red]")
|
|
89
|
+
for sf in suspicious:
|
|
90
|
+
try:
|
|
91
|
+
size = sf.stat().st_size
|
|
92
|
+
_always(f"[red] - {sf.name} (size: {size} bytes)[/red]")
|
|
93
|
+
except Exception:
|
|
94
|
+
_always(f"[red] - {sf.name} (could not stat)[/red]")
|
|
95
|
+
|
|
96
|
+
# Also log to a file for persistence
|
|
97
|
+
log_file = Path.home() / ".pdd" / "suspicious_files.log"
|
|
98
|
+
log_file.parent.mkdir(parents=True, exist_ok=True)
|
|
99
|
+
with open(log_file, "a") as lf:
|
|
100
|
+
lf.write(f"\n{'='*60}\n")
|
|
101
|
+
lf.write(f"Timestamp: {timestamp}\n")
|
|
102
|
+
lf.write(f"Context: {context}\n")
|
|
103
|
+
lf.write(f"Directory: {cwd}\n")
|
|
104
|
+
lf.write(f"CWD at detection: {Path.cwd()}\n")
|
|
105
|
+
for sf in suspicious:
|
|
106
|
+
try:
|
|
107
|
+
size = sf.stat().st_size
|
|
108
|
+
lf.write(f" - {sf.name} (size: {size} bytes)\n")
|
|
109
|
+
except Exception as e:
|
|
110
|
+
lf.write(f" - {sf.name} (error: {e})\n")
|
|
111
|
+
# Log stack trace to help identify caller
|
|
112
|
+
import traceback
|
|
113
|
+
lf.write("Stack trace:\n")
|
|
114
|
+
lf.write(traceback.format_stack()[-10:][0] if traceback.format_stack() else "N/A")
|
|
115
|
+
lf.write("\n")
|
|
116
|
+
except Exception as e:
|
|
117
|
+
_verbose(f"[yellow]Could not scan for suspicious files: {e}[/yellow]")
|
|
118
|
+
|
|
119
|
+
return suspicious
|
|
120
|
+
|
|
121
|
+
|
|
59
122
|
def _begin_marker(path: Path) -> str:
|
|
60
123
|
"""Marker that must wrap the BEGIN of a corrected file block emitted by the agent."""
|
|
61
124
|
return f"<<<BEGIN_FILE:{path}>>>"
|
|
@@ -130,10 +193,41 @@ _MULTI_FILE_BLOCK_RE = re.compile(
|
|
|
130
193
|
re.DOTALL,
|
|
131
194
|
)
|
|
132
195
|
|
|
196
|
+
|
|
197
|
+
def _is_suspicious_path(path: str) -> bool:
|
|
198
|
+
"""
|
|
199
|
+
Reject paths that look like LLM artifacts or template variables.
|
|
200
|
+
|
|
201
|
+
This defends against:
|
|
202
|
+
- Single/double character filenames (e.g., 'C', 'E', 'T' from agent misbehavior)
|
|
203
|
+
- Template variables like {path}, {code_abs} captured by regex
|
|
204
|
+
- Other LLM-generated garbage patterns
|
|
205
|
+
|
|
206
|
+
Returns True if the path should be rejected.
|
|
207
|
+
"""
|
|
208
|
+
if not path:
|
|
209
|
+
return True
|
|
210
|
+
# Get the basename for validation
|
|
211
|
+
base_name = Path(path).name
|
|
212
|
+
# Reject single or double character filenames (too short to be legitimate)
|
|
213
|
+
if len(base_name) <= 2:
|
|
214
|
+
return True
|
|
215
|
+
# Reject template variable patterns like {path}, {code_abs}
|
|
216
|
+
if '{' in base_name or '}' in base_name:
|
|
217
|
+
return True
|
|
218
|
+
# Reject paths that are just dots like "..", "..."
|
|
219
|
+
if base_name.strip('.') == '':
|
|
220
|
+
return True
|
|
221
|
+
return False
|
|
222
|
+
|
|
223
|
+
|
|
133
224
|
def _extract_files_from_output(*blobs: str) -> Dict[str, str]:
|
|
134
225
|
"""
|
|
135
226
|
Parse stdout/stderr blobs and collect all emitted file blocks into {path: content}.
|
|
136
227
|
Returns an empty dict if none found.
|
|
228
|
+
|
|
229
|
+
Note: Suspicious paths (single-char, template variables) are rejected to prevent
|
|
230
|
+
LLM artifacts from being written to disk.
|
|
137
231
|
"""
|
|
138
232
|
out: Dict[str, str] = {}
|
|
139
233
|
for blob in blobs:
|
|
@@ -143,6 +237,9 @@ def _extract_files_from_output(*blobs: str) -> Dict[str, str]:
|
|
|
143
237
|
path = (m.group(1) or "").strip()
|
|
144
238
|
body = m.group(2) or ""
|
|
145
239
|
if path and body != "":
|
|
240
|
+
if _is_suspicious_path(path):
|
|
241
|
+
_info(f"[yellow]Skipping suspicious path from LLM output: {path!r}[/yellow]")
|
|
242
|
+
continue
|
|
146
243
|
out[path] = body
|
|
147
244
|
return out
|
|
148
245
|
|
|
@@ -401,6 +498,12 @@ def _run_anthropic_variants(prompt_text: str, cwd: Path, total_timeout: int, lab
|
|
|
401
498
|
return last
|
|
402
499
|
finally:
|
|
403
500
|
prompt_file.unlink(missing_ok=True)
|
|
501
|
+
# Issue #186: Scan for suspicious files after Anthropic agent runs
|
|
502
|
+
_detect_suspicious_files(cwd, f"After _run_anthropic_variants ({label})")
|
|
503
|
+
# Also scan project root in case agent created files there
|
|
504
|
+
project_root = Path.cwd()
|
|
505
|
+
if project_root != cwd:
|
|
506
|
+
_detect_suspicious_files(project_root, f"After _run_anthropic_variants ({label}) - project root")
|
|
404
507
|
|
|
405
508
|
def _run_cli_args_google(args: List[str], cwd: Path, timeout: int) -> subprocess.CompletedProcess:
|
|
406
509
|
"""Subprocess runner for Google commands with common sanitized env."""
|
|
@@ -460,6 +563,12 @@ def _run_google_variants(prompt_text: str, cwd: Path, total_timeout: int, label:
|
|
|
460
563
|
return last
|
|
461
564
|
finally:
|
|
462
565
|
prompt_file.unlink(missing_ok=True)
|
|
566
|
+
# Issue #186: Scan for suspicious files after Google agent runs
|
|
567
|
+
_detect_suspicious_files(cwd, f"After _run_google_variants ({label})")
|
|
568
|
+
# Also scan project root in case agent created files there
|
|
569
|
+
project_root = Path.cwd()
|
|
570
|
+
if project_root != cwd:
|
|
571
|
+
_detect_suspicious_files(project_root, f"After _run_google_variants ({label}) - project root")
|
|
463
572
|
|
|
464
573
|
def _run_testcmd(cmd: str, cwd: Path) -> bool:
|
|
465
574
|
"""
|
|
@@ -498,7 +607,7 @@ def _verify_and_log(unit_test_file: str, cwd: Path, *, verify_cmd: Optional[str]
|
|
|
498
607
|
return _run_testcmd(run_cmd, cwd)
|
|
499
608
|
# Fallback: try running with Python if no run command found
|
|
500
609
|
verify = subprocess.run(
|
|
501
|
-
[
|
|
610
|
+
[sys.executable, str(Path(unit_test_file).resolve())],
|
|
502
611
|
capture_output=True,
|
|
503
612
|
text=True,
|
|
504
613
|
check=False,
|
|
@@ -549,10 +658,16 @@ def _normalize_target_path(
|
|
|
549
658
|
) -> Optional[Path]:
|
|
550
659
|
"""
|
|
551
660
|
Resolve an emitted path to a safe file path we should write:
|
|
661
|
+
- reject suspicious paths (single-char, template variables)
|
|
552
662
|
- make path absolute under project root
|
|
553
663
|
- allow direct match, primary-file match (with/without _fixed), or basename search
|
|
554
664
|
- create new files only if allow_new is True
|
|
555
665
|
"""
|
|
666
|
+
# Early rejection of suspicious paths (defense against LLM artifacts)
|
|
667
|
+
if _is_suspicious_path(emitted_path):
|
|
668
|
+
_info(f"[yellow]Skipping suspicious path: {emitted_path!r}[/yellow]")
|
|
669
|
+
return None
|
|
670
|
+
|
|
556
671
|
p = Path(emitted_path)
|
|
557
672
|
if not p.is_absolute():
|
|
558
673
|
p = (project_root / emitted_path).resolve()
|
|
@@ -760,7 +875,7 @@ def _try_harvest_then_verify(
|
|
|
760
875
|
newest = code_path.read_text(encoding="utf-8")
|
|
761
876
|
_print_diff(code_snapshot, newest, code_path)
|
|
762
877
|
ok = _post_apply_verify_or_testcmd(
|
|
763
|
-
provider, unit_test_file,
|
|
878
|
+
provider, unit_test_file, cwd,
|
|
764
879
|
verify_cmd=verify_cmd, verify_enabled=verify_enabled,
|
|
765
880
|
stdout=res.stdout or "", stderr=res.stderr or ""
|
|
766
881
|
)
|
|
@@ -952,7 +1067,7 @@ def run_agentic_fix(
|
|
|
952
1067
|
else:
|
|
953
1068
|
# Fallback: run directly with Python interpreter
|
|
954
1069
|
pre = subprocess.run(
|
|
955
|
-
[
|
|
1070
|
+
[sys.executable, str(Path(unit_test_file).resolve())],
|
|
956
1071
|
capture_output=True,
|
|
957
1072
|
text=True,
|
|
958
1073
|
check=False,
|
pdd/agentic_update.py
CHANGED
|
@@ -16,8 +16,9 @@ import os
|
|
|
16
16
|
import traceback
|
|
17
17
|
|
|
18
18
|
from rich.console import Console
|
|
19
|
+
from rich.markdown import Markdown
|
|
19
20
|
|
|
20
|
-
from .agentic_common import get_available_agents, run_agentic_task
|
|
21
|
+
from .agentic_common import get_available_agents, run_agentic_task, DEFAULT_MAX_RETRIES
|
|
21
22
|
from .load_prompt_template import load_prompt_template
|
|
22
23
|
|
|
23
24
|
# Optional globals from package root; ignore if not present.
|
|
@@ -107,17 +108,23 @@ def _detect_changed_files(
|
|
|
107
108
|
return sorted({p.resolve() for p in changed})
|
|
108
109
|
|
|
109
110
|
|
|
110
|
-
def _discover_test_files(
|
|
111
|
+
def _discover_test_files(
|
|
112
|
+
code_path: Path,
|
|
113
|
+
tests_dir: Optional[Path] = None,
|
|
114
|
+
) -> List[Path]:
|
|
111
115
|
"""
|
|
112
116
|
Discover test files associated with a given code file.
|
|
113
117
|
|
|
114
118
|
Uses pattern: ``test_{code_stem}*{code_suffix}`` and searches in:
|
|
115
|
-
1.
|
|
116
|
-
2.
|
|
117
|
-
3.
|
|
119
|
+
1. Configured tests_dir from .pddrc (if provided)
|
|
120
|
+
2. ``tests/`` relative to the code file directory
|
|
121
|
+
3. The same directory as the code file
|
|
122
|
+
4. Sibling ``tests/`` directory (../tests/)
|
|
123
|
+
5. Project root ``tests/``
|
|
118
124
|
|
|
119
125
|
Args:
|
|
120
126
|
code_path: Path to the main code file.
|
|
127
|
+
tests_dir: Optional path to tests directory from .pddrc config.
|
|
121
128
|
|
|
122
129
|
Returns:
|
|
123
130
|
Ordered list of discovered test file paths (deduplicated).
|
|
@@ -127,11 +134,15 @@ def _discover_test_files(code_path: Path) -> List[Path]:
|
|
|
127
134
|
suffix = code_path.suffix
|
|
128
135
|
pattern = f"test_{stem}*{suffix}"
|
|
129
136
|
|
|
130
|
-
search_dirs: List[Path] = [
|
|
137
|
+
search_dirs: List[Path] = []
|
|
138
|
+
if tests_dir is not None:
|
|
139
|
+
search_dirs.append(Path(tests_dir).resolve())
|
|
140
|
+
search_dirs.extend([
|
|
131
141
|
code_path.parent / "tests",
|
|
132
142
|
code_path.parent,
|
|
143
|
+
code_path.parent.parent / "tests", # Sibling tests dir (../tests/)
|
|
133
144
|
PROJECT_ROOT / "tests",
|
|
134
|
-
]
|
|
145
|
+
])
|
|
135
146
|
|
|
136
147
|
seen: set[Path] = set()
|
|
137
148
|
discovered: List[Path] = []
|
|
@@ -183,6 +194,7 @@ def run_agentic_update(
|
|
|
183
194
|
code_file: str,
|
|
184
195
|
test_files: Optional[List[Path]] = None,
|
|
185
196
|
*,
|
|
197
|
+
tests_dir: Optional[Path] = None,
|
|
186
198
|
verbose: bool = False,
|
|
187
199
|
quiet: bool = False,
|
|
188
200
|
) -> Tuple[bool, str, float, str, List[str]]:
|
|
@@ -205,6 +217,8 @@ def run_agentic_update(
|
|
|
205
217
|
test files are auto-discovered using the pattern
|
|
206
218
|
``test_{code_stem}*{code_suffix}`` in the configured search
|
|
207
219
|
locations.
|
|
220
|
+
tests_dir: Optional path to tests directory from .pddrc config.
|
|
221
|
+
Used for auto-discovery when test_files is None.
|
|
208
222
|
verbose: If True, enable verbose logging for the underlying agent task.
|
|
209
223
|
quiet: If True, suppress informational logging from this function.
|
|
210
224
|
(Passed through to the agent as well; ``quiet`` takes precedence
|
|
@@ -268,7 +282,7 @@ def run_agentic_update(
|
|
|
268
282
|
return False, error, 0.0, "", []
|
|
269
283
|
selected_tests = normalized_tests or []
|
|
270
284
|
else:
|
|
271
|
-
selected_tests = _discover_test_files(code_path)
|
|
285
|
+
selected_tests = _discover_test_files(code_path, tests_dir=tests_dir)
|
|
272
286
|
|
|
273
287
|
# Paths to track *before* running the agent (for mtime comparison)
|
|
274
288
|
before_paths: set[Path] = {prompt_path.resolve(), code_path.resolve()}
|
|
@@ -323,6 +337,7 @@ def run_agentic_update(
|
|
|
323
337
|
verbose=bool(verbose and not quiet),
|
|
324
338
|
quiet=quiet,
|
|
325
339
|
label=f"agentic_update:{code_path.stem}",
|
|
340
|
+
max_retries=DEFAULT_MAX_RETRIES,
|
|
326
341
|
)
|
|
327
342
|
except Exception as exc:
|
|
328
343
|
message = f"Agentic task failed with an exception: {exc}"
|
|
@@ -361,7 +376,10 @@ def run_agentic_update(
|
|
|
361
376
|
|
|
362
377
|
if not quiet:
|
|
363
378
|
if success:
|
|
364
|
-
console.print(
|
|
379
|
+
console.print("[green]Prompt file updated successfully.[/green]")
|
|
380
|
+
if output_message:
|
|
381
|
+
console.print("\n[bold]Agent output:[/bold]")
|
|
382
|
+
console.print(Markdown(output_message))
|
|
365
383
|
else:
|
|
366
384
|
console.print(f"[yellow]{base_msg}[/yellow]")
|
|
367
385
|
|
pdd/agentic_verify.py
CHANGED
|
@@ -8,7 +8,7 @@ from typing import Any
|
|
|
8
8
|
|
|
9
9
|
from rich.console import Console
|
|
10
10
|
|
|
11
|
-
from .agentic_common import run_agentic_task
|
|
11
|
+
from .agentic_common import run_agentic_task, DEFAULT_MAX_RETRIES
|
|
12
12
|
from .load_prompt_template import load_prompt_template
|
|
13
13
|
|
|
14
14
|
console = Console()
|
|
@@ -133,7 +133,8 @@ def run_agentic_verify(
|
|
|
133
133
|
cwd=project_root,
|
|
134
134
|
verbose=verbose,
|
|
135
135
|
quiet=quiet,
|
|
136
|
-
label="verify-explore"
|
|
136
|
+
label="verify-explore",
|
|
137
|
+
max_retries=DEFAULT_MAX_RETRIES,
|
|
137
138
|
)
|
|
138
139
|
|
|
139
140
|
# 6. Record State After Execution & Detect Changes
|