Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
116 changes: 91 additions & 25 deletions pdd/sync_orchestration.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
import subprocess
import re
import os
import sys
import io
from contextlib import contextmanager
from pathlib import Path
from typing import Dict, Any, Optional, List
from dataclasses import asdict
Expand Down Expand Up @@ -228,6 +231,43 @@ def _execute_tests_and_create_run_report(test_file: Path, basename: str, languag
save_run_report(asdict(report), basename, language)
return report

# --- Output Capture Helper ---

@contextmanager
def capture_output():
"""Context manager to capture stdout and stderr."""
old_stdout = sys.stdout
old_stderr = sys.stderr
stdout_buffer = io.StringIO()
stderr_buffer = io.StringIO()

try:
sys.stdout = stdout_buffer
sys.stderr = stderr_buffer
yield stdout_buffer, stderr_buffer
finally:
sys.stdout = old_stdout
sys.stderr = old_stderr

def call_with_capture(func, quiet=False, *args, **kwargs):
Copy link

Copilot AI Oct 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The quiet parameter should be the first positional parameter after func to follow Python conventions for boolean flags in function signatures.

Copilot uses AI. Check for mistakes.
"""Call a function and capture its output, returning (result, captured_output)."""
captured_output = []

if not quiet:
with capture_output() as (stdout_buf, stderr_buf):
result = func(*args, **kwargs)
stdout_content = stdout_buf.getvalue()
stderr_content = stderr_buf.getvalue()
if stdout_content or stderr_content:
if stdout_content:
captured_output.append(f"STDOUT:\n{stdout_content}")
if stderr_content:
captured_output.append(f"STDERR:\n{stderr_content}")
else:
result = func(*args, **kwargs)

return result, captured_output

# --- Helper for Click Context ---

def _create_mock_context(**kwargs) -> click.Context:
Expand Down Expand Up @@ -662,6 +702,7 @@ def sync_orchestration(

result = {}
success = False
captured_output = []
start_time = time.time() # Track execution time

# --- Execute Operation ---
Expand All @@ -673,14 +714,17 @@ def sync_orchestration(
# Read original prompt content to compare later
original_content = pdd_files['prompt'].read_text(encoding='utf-8')

result = auto_deps_main(
ctx,
prompt_file=str(pdd_files['prompt']),
result, operation_output = call_with_capture(
auto_deps_main,
quiet,
Copy link

Copilot AI Oct 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The quiet parameter is being passed as a positional argument but the function signature expects it as a keyword argument. This will cause quiet to be passed as the first argument to auto_deps_main instead of controlling the capture behavior.

Suggested change
quiet,
quiet=quiet,

Copilot uses AI. Check for mistakes.
ctx,
prompt_file=str(pdd_files['prompt']),
directory_path=f"{examples_dir}/*",
auto_deps_csv_path="project_dependencies.csv",
output=temp_output,
force_scan=False # Don't force scan every time
)
captured_output.extend(operation_output)

# Only move the temp file back if content actually changed
if Path(temp_output).exists():
Expand All @@ -694,22 +738,28 @@ def sync_orchestration(
# Mark as successful with no changes
result = (new_content, 0.0, 'no-changes')
elif operation == 'generate':
result = code_generator_main(
ctx,
prompt_file=str(pdd_files['prompt']),
result, operation_output = call_with_capture(
code_generator_main,
quiet,
Copy link

Copilot AI Oct 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same issue as with auto_deps_main - quiet should be passed as a keyword argument: call_with_capture(code_generator_main, quiet=quiet, ctx, ...)

Suggested change
quiet,
quiet=quiet,

Copilot uses AI. Check for mistakes.
ctx,
prompt_file=str(pdd_files['prompt']),
output=str(pdd_files['code']),
original_prompt_file_path=None,
force_incremental_flag=False
)
captured_output.extend(operation_output)
elif operation == 'example':
print(f"DEBUG SYNC: pdd_files['example'] = {pdd_files['example']}")
print(f"DEBUG SYNC: str(pdd_files['example']) = {str(pdd_files['example'])}")
result = context_generator_main(
ctx,
prompt_file=str(pdd_files['prompt']),
code_file=str(pdd_files['code']),
result, operation_output = call_with_capture(
context_generator_main,
quiet,
Copy link

Copilot AI Oct 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same issue as with previous operations - quiet should be passed as a keyword argument: call_with_capture(context_generator_main, quiet=quiet, ctx, ...)

Suggested change
quiet,
quiet=quiet,

Copilot uses AI. Check for mistakes.
ctx,
prompt_file=str(pdd_files['prompt']),
code_file=str(pdd_files['code']),
output=str(pdd_files['example'])
)
captured_output.extend(operation_output)
elif operation == 'crash':
# Validate required files exist before attempting crash operation
required_files = [pdd_files['code'], pdd_files['example']]
Expand Down Expand Up @@ -875,18 +925,21 @@ def sync_orchestration(
Path("crash.log").write_text(crash_log_content)

try:
result = crash_main(
ctx,
prompt_file=str(pdd_files['prompt']),
code_file=str(pdd_files['code']),
program_file=str(pdd_files['example']),
result, operation_output = call_with_capture(
crash_main,
quiet,
Copy link

Copilot AI Oct 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same issue as with previous operations - quiet should be passed as a keyword argument: call_with_capture(crash_main, quiet=quiet, ctx, ...)

Suggested change
quiet,
quiet=quiet,

Copilot uses AI. Check for mistakes.
ctx,
prompt_file=str(pdd_files['prompt']),
code_file=str(pdd_files['code']),
program_file=str(pdd_files['example']),
error_file="crash.log",
output=str(pdd_files['code']),
output_program=str(pdd_files['example']),
loop=True,
max_attempts=max_attempts,
budget=budget - current_cost_ref[0]
)
captured_output.extend(operation_output)
except (RuntimeError, Exception) as e:
error_str = str(e)
if ("LLM returned None" in error_str or
Expand Down Expand Up @@ -954,17 +1007,20 @@ def sync_orchestration(
print(f"Creating test directory: {test_path.parent}")
test_path.parent.mkdir(parents=True, exist_ok=True)

result = cmd_test_main(
ctx,
prompt_file=str(pdd_files['prompt']),
code_file=str(pdd_files['code']),
result, operation_output = call_with_capture(
cmd_test_main,
quiet,
Copy link

Copilot AI Oct 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same issue as with previous operations - quiet should be passed as a keyword argument: call_with_capture(cmd_test_main, quiet=quiet, ctx, ...)

Suggested change
quiet,
quiet=quiet,

Copilot uses AI. Check for mistakes.
ctx,
prompt_file=str(pdd_files['prompt']),
code_file=str(pdd_files['code']),
output=str(pdd_files['test']),
language=language,
coverage_report=None,
existing_tests=None,
target_coverage=target_coverage,
merge=False
)
captured_output.extend(operation_output)

# After test generation, check if the test file was actually created
test_file = pdd_files['test']
Expand Down Expand Up @@ -1026,11 +1082,13 @@ def sync_orchestration(

error_file_path.write_text(error_content)

result = fix_main(
ctx,
prompt_file=str(pdd_files['prompt']),
code_file=str(pdd_files['code']),
unit_test_file=str(pdd_files['test']),
result, operation_output = call_with_capture(
fix_main,
quiet,
Copy link

Copilot AI Oct 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same issue as with previous operations - quiet should be passed as a keyword argument: call_with_capture(fix_main, quiet=quiet, ctx, ...)

Suggested change
quiet,
quiet=quiet,

Copilot uses AI. Check for mistakes.
ctx,
prompt_file=str(pdd_files['prompt']),
code_file=str(pdd_files['code']),
unit_test_file=str(pdd_files['test']),
error_file=str(error_file_path),
output_test=str(pdd_files['test']),
output_code=str(pdd_files['code']),
Expand All @@ -1041,6 +1099,7 @@ def sync_orchestration(
budget=budget - current_cost_ref[0],
auto_submit=True
)
captured_output.extend(operation_output)
elif operation == 'update':
result = update_main(
ctx,
Expand All @@ -1053,7 +1112,7 @@ def sync_orchestration(
else:
errors.append(f"Unknown operation '{operation}' requested.")
result = {'success': False, 'cost': 0.0}

# Handle different return formats from command functions
if isinstance(result, dict):
# Dictionary return (e.g., from some commands)
Expand Down Expand Up @@ -1107,6 +1166,13 @@ def sync_orchestration(
}, duration)
append_sync_log(basename, language, log_entry)

# Display captured output if any
if captured_output and not quiet:
print(f"\n--- {operation.upper()} OUTPUT ---")
for output_section in captured_output:
print(output_section)
print("--- END OUTPUT ---\n")

# Track the most recent model used on a successful step
if success and isinstance(model_name, str) and model_name:
last_model_name = model_name
Expand Down