@@ -40,6 +40,31 @@ def _build_hybrid_diff_section(pr_diff: str, max_lines: int) -> str:
4040 "Use this as a starting point only. You MUST validate findings with repository tool reads.\n "
4141 )
4242
43+ def _build_diff_section (pr_diff : Optional [str ], include_diff : bool ) -> str :
44+ """Build unified-prompt diff section for backward compatibility."""
45+ if pr_diff and include_diff :
46+ return f"""
47+
48+ PR DIFF CONTENT:
49+ ```
50+ { pr_diff }
51+ ```
52+
53+ Review the complete diff above. This contains all code changes in the PR.
54+ """
55+
56+ return """
57+
58+ IMPORTANT - FILE READING INSTRUCTIONS:
59+ You have access to the repository files. For each file listed above, use the Read tool to examine the changes.
60+ Focus on the files that are most likely to contain issues based on the PR context.
61+
62+ To review effectively:
63+ 1. Read each modified file to understand the current code
64+ 2. Look at surrounding code context when needed to understand the changes
65+ 3. Check related files if you need to understand dependencies or usage patterns
66+ """
67+
4368
4469def _base_context_block (pr_data : Dict [str , Any ], pr_diff : str , max_diff_lines : int ) -> str :
4570 """Shared context block used across prompts."""
@@ -281,48 +306,76 @@ def get_unified_review_prompt(
281306 include_diff : bool = True ,
282307 custom_review_instructions : Optional [str ] = None ,
283308 custom_security_instructions : Optional [str ] = None ,
309+ review_context : Optional [str ] = None ,
284310) -> str :
285- """Backward-compatible unified prompt used by tests and direct calls.
286-
287- The unified prompt now enforces hybrid behavior: even when diff is included,
288- repository context reads are still mandatory.
289- """
290- diff_text = pr_diff if include_diff else ""
291- max_lines = len (diff_text .splitlines ()) if diff_text else 0
292- combined = build_quality_prompt (
293- pr_data ,
294- diff_text ,
295- max_lines ,
296- discovered_context = {},
297- custom_review_instructions = custom_review_instructions ,
298- )
299- security = build_security_prompt (
300- pr_data ,
301- diff_text ,
302- max_lines ,
303- discovered_context = {},
304- custom_security_instructions = custom_security_instructions ,
305- )
311+ """Backward-compatible unified prompt used by tests and direct calls."""
312+ files_changed = _format_files_changed (pr_data )
313+ diff_section = _build_diff_section (pr_diff , include_diff )
314+ custom_review_section = f"\n { custom_review_instructions } \n " if custom_review_instructions else ""
315+ custom_security_section = f"\n { custom_security_instructions } \n " if custom_security_instructions else ""
306316
307- file_reading_block = (
308- "\n IMPORTANT - FILE READING INSTRUCTIONS:\n "
309- "You MUST read changed files and nearby context with repository tools before final findings.\n "
310- )
311- if include_diff and diff_text :
312- diff_anchor = f"\n PR DIFF CONTENT:\n ```diff\n { diff_text } \n ```\n "
313- else :
314- diff_anchor = "\n "
317+ pr_description = (pr_data .get ('body' , '' ) or '' ).strip ()
318+ pr_description_section = ""
319+ if pr_description :
320+ if len (pr_description ) > 2000 :
321+ pr_description = pr_description [:2000 ] + "... (truncated)"
322+ pr_description_section = f"\n PR Description:\n { pr_description } \n "
315323
316- return (
317- f"You are a senior engineer conducting a comprehensive code review of GitHub PR #{ pr_data .get ('number' , 'unknown' )} .\n "
318- "CONTEXT:\n "
319- f"- Title: { pr_data .get ('title' , 'unknown' )} \n "
320- "OBJECTIVE:\n "
321- "Perform a high-signal code quality and security review with mandatory repository context validation.\n "
322- + diff_anchor
323- + file_reading_block
324- + "\n REQUIRED OUTPUT FORMAT:\n JSON only.\n \n "
325- + combined
326- + "\n \n "
327- + security
328- )
324+ review_context_section = review_context or ""
325+
326+ return f"""
327+ You are a senior engineer conducting a comprehensive code review of GitHub PR #{ pr_data .get ('number' , 'unknown' )} : "{ pr_data .get ('title' , 'unknown' )} "
328+
329+ CONTEXT:
330+ - Repository: { pr_data .get ('head' , {}).get ('repo' , {}).get ('full_name' , 'unknown' )}
331+ - Author: { pr_data .get ('user' , 'unknown' )}
332+ - Files changed: { pr_data .get ('changed_files' , 0 )}
333+ - Lines added: { pr_data .get ('additions' , 0 )}
334+ - Lines deleted: { pr_data .get ('deletions' , 0 )}
335+ { pr_description_section }
336+ Files modified:
337+ { files_changed } { diff_section } { review_context_section }
338+
339+ OBJECTIVE:
340+ Perform a focused, high-signal code review to identify HIGH-CONFIDENCE issues introduced by this PR.
341+
342+ CODE QUALITY CATEGORIES:
343+ - correctness, reliability, performance, maintainability, testing
344+ { custom_review_section }
345+ SECURITY CATEGORIES:
346+ - input validation, authn/authz, crypto/secrets, code execution, data exposure
347+ { custom_security_section }
348+
349+ REQUIRED OUTPUT FORMAT:
350+
351+ {{
352+ "pr_summary": {{
353+ "overview": "2-4 sentence summary of what this PR changes and why it matters",
354+ "file_changes": [
355+ {{
356+ "label": "src/auth.py",
357+ "files": ["src/auth.py"],
358+ "changes": "Brief description of changes (~10 words)"
359+ }}
360+ ]
361+ }},
362+ "findings": [
363+ {{
364+ "file": "path/to/file.py",
365+ "line": 42,
366+ "severity": "HIGH|MEDIUM|LOW",
367+ "category": "correctness|reliability|performance|maintainability|testing|security",
368+ "title": "Short summary of the issue",
369+ "description": "What is wrong and where it happens",
370+ "impact": "Concrete impact or failure mode",
371+ "recommendation": "Actionable fix or mitigation",
372+ "confidence": 0.95
373+ }}
374+ ]
375+ }}
376+
377+ PR SUMMARY GUIDELINES:
378+ - overview: 2-4 sentences describing WHAT changed and WHY (purpose/goal)
379+ - file_changes: One entry per file or group of related files
380+ - changes: Brief description (~10 words), focus on purpose not implementation
381+ """
0 commit comments