← Back to DevBytes

Building a Code Review Agent with LangGraph: Step-by-Step Tutorial

Building a Code Review Agent with LangGraph: Step-by-Step Tutorial

What Is a Code Review Agent?

A code review agent is an automated system that analyzes source code submissions and provides structured feedback — much like a human reviewer would. Powered by large language models (LLMs), such agents can examine code for style violations, potential bugs, security vulnerabilities, performance issues, and logical errors. When built with LangGraph, these agents gain the ability to orchestrate complex, multi-step review workflows where different specialized "reviewers" collaborate, results are aggregated, and the process can branch or loop based on findings.

LangGraph is a framework from the LangChain ecosystem designed for building stateful, multi-actor applications with LLMs. It lets you define workflows as directed graphs — nodes represent discrete steps (like running a security scan or checking style), and edges represent transitions between steps. State flows through the graph, accumulating results as the agent progresses. This graph-based approach is ideal for code review because real code review is inherently multi-dimensional: you need to check multiple concern areas, sometimes revisit files based on earlier findings, and produce a consolidated report.

Why It Matters

Manual code review is time-consuming and inconsistent. Senior developers spend hours reviewing pull requests, and fatigue leads to missed issues. An LLM-powered code review agent offers several compelling benefits:

With LangGraph specifically, you gain the ability to model complex review policies. For example, you might route code through different reviewers based on language or file type, escalate high-severity findings to a second-pass analysis, or loop back for re-review after automated fixes are applied. This flexibility goes far beyond a simple "ask the LLM for feedback" script.

Prerequisites

Before building the agent, ensure you have the following installed and configured:

pip install langgraph langchain langchain-openai

For this tutorial, we'll use OpenAI's GPT-4o, but you can substitute any LangChain-compatible model. Make sure your API key is set as an environment variable:

export OPENAI_API_KEY="your-api-key-here"

Core Concepts of LangGraph

Before diving into code, let's quickly review the three building blocks of LangGraph:

The graph compiles into a runnable object. You invoke it with an initial state, and it executes nodes in the defined order until it reaches the exit point, returning the final state.

Step 1: Define the State Schema

The state is the backbone of our agent. It must carry the input code, accumulate findings from each reviewer, and store the final aggregated report. We'll use a Python TypedDict for simplicity:

from typing import TypedDict, List, Optional, Annotated
from langgraph.graph.message import add_messages
import operator

class CodeReviewState(TypedDict):
    # The source code to review (as a string)
    source_code: str
    # Optional: programming language for context-aware review
    language: str
    # Findings from individual reviewers, accumulated as a list
    findings: Annotated[List[str], operator.add]
    # Structured review report (final output)
    final_report: Optional[str]
    # Flag to track if critical issues were found
    has_critical_issues: bool
    # Number of review iterations (for loop control)
    iteration_count: int

Note the Annotated type for findings. By using operator.add, we tell LangGraph that when multiple nodes return updates to findings, the lists should be concatenated rather than overwritten. This is crucial for accumulating results from parallel or sequential reviewers.

Step 2: Create the Reviewer Nodes

Each node is a function that receives the current state, performs an LLM-based analysis of a specific concern area, and returns a partial state update. We'll build four specialized reviewers: Style & Convention, Security, Logic & Bugs, and Performance.

We'll use LangChain's chat model interface for consistency. Each reviewer function constructs a system prompt tailored to its domain, sends the code to the LLM, and parses the response into a structured finding.

2a. Style & Convention Reviewer

from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage, SystemMessage

llm = ChatOpenAI(model="gpt-4o", temperature=0.2)

def style_reviewer(state: CodeReviewState) -> dict:
    """Review code for style issues: naming, formatting, conventions."""
    system_prompt = SystemMessage(content="""You are an expert code style reviewer. 
    Analyze the provided code for:
    - Naming conventions (camelCase, snake_case, PascalCase as appropriate)
    - Indentation and formatting consistency
    - Line length and readability
    - Comment quality and placement
    - Adherence to language-specific style guides (PEP 8 for Python, etc.)
    
    For each issue found, provide:
    - File/line reference (if detectable from context)
    - Severity: LOW, MEDIUM, or HIGH
    - A clear description of the issue
    - A suggested fix
    
    Format each finding as a single structured line:
    [STYLE] {severity}: {description} | Suggestion: {fix}
    
    If no issues are found, respond with exactly: NO_STYLE_ISSUES_FOUND""")
    
    user_message = HumanMessage(content=f"""Review the following {state.get('language', 'code')} code for style issues:
    
    {state.get('language', '')}
    {state['source_code']}
    """)
    
    response = llm.invoke([system_prompt, user_message])
    result = response.content.strip()
    
    if result == "NO_STYLE_ISSUES_FOUND":
        return {"findings": []}
    
    findings = [line.strip() for line in result.split("\n") if line.strip() and "[STYLE]" in line]
    return {"findings": findings}

2b. Security Reviewer

def security_reviewer(state: CodeReviewState) -> dict:
    """Review code for security vulnerabilities."""
    system_prompt = SystemMessage(content="""You are an expert application security reviewer.
    Analyze the provided code for:
    - Injection vulnerabilities (SQL, command, code injection)
    - Hardcoded secrets, API keys, or credentials
    - Insecure cryptographic practices
    - Missing input validation or sanitization
    - Authentication and authorization flaws
    - Path traversal risks
    - Unsafe deserialization
    
    For each vulnerability found, provide:
    - Severity: LOW, MEDIUM, HIGH, CRITICAL
    - A clear description with the vulnerable code pattern
    - A concrete fix recommendation
    
    Format each finding as:
    [SECURITY] {severity}: {description} | Fix: {recommendation}
    
    If no vulnerabilities are found, respond with exactly: NO_SECURITY_ISSUES_FOUND""")
    
    user_message = HumanMessage(content=f"""Review this code for security vulnerabilities:
    
    {state.get('language', '')}
    {state['source_code']}
    """)
    
    response = llm.invoke([system_prompt, user_message])
    result = response.content.strip()
    
    if result == "NO_SECURITY_ISSUES_FOUND":
        return {"findings": [], "has_critical_issues": False}
    
    findings = [line.strip() for line in result.split("\n") if line.strip() and "[SECURITY]" in line]
    has_critical = any("CRITICAL" in f for f in findings)
    return {"findings": findings, "has_critical_issues": has_critical}

2c. Logic & Bug Reviewer

def logic_reviewer(state: CodeReviewState) -> dict:
    """Review code for logical errors and potential bugs."""
    system_prompt = SystemMessage(content="""You are an expert code logic reviewer.
    Analyze the provided code for:
    - Off-by-one errors and boundary condition bugs
    - Incorrect boolean logic or conditionals
    - Null/None reference risks
    - Type mismatches or unsafe type coercion
    - Resource leaks (unclosed files, connections, etc.)
    - Race conditions in concurrent code
    - Incorrect error handling or swallowed exceptions
    
    Format each finding as:
    [LOGIC] {severity}: {description} | Fix: {recommendation}
    
    Severity levels: LOW, MEDIUM, HIGH, CRITICAL
    If no issues found, respond with: NO_LOGIC_ISSUES_FOUND""")
    
    user_message = HumanMessage(content=f"""Review this code for logical errors and bugs:
    
    {state.get('language', '')}
    {state['source_code']}
    """)
    
    response = llm.invoke([system_prompt, user_message])
    result = response.content.strip()
    
    if result == "NO_LOGIC_ISSUES_FOUND":
        return {"findings": [], "has_critical_issues": False}
    
    findings = [line.strip() for line in result.split("\n") if line.strip() and "[LOGIC]" in line]
    has_critical = any("CRITICAL" in f for f in findings)
    return {"findings": findings, "has_critical_issues": has_critical}

2d. Performance Reviewer

def performance_reviewer(state: CodeReviewState) -> dict:
    """Review code for performance issues."""
    system_prompt = SystemMessage(content="""You are an expert performance engineer.
    Analyze the provided code for:
    - Inefficient algorithms or data structures
    - Unnecessary loops or redundant computations
    - Memory allocation inefficiencies
    - Missing caching opportunities
    - N+1 query patterns (if database code)
    - Blocking operations that could be async
    - Excessive object creation
    
    Format each finding as:
    [PERFORMANCE] {severity}: {description} | Improvement: {suggestion}
    
    Severity: LOW, MEDIUM, HIGH
    If no issues found, respond with: NO_PERFORMANCE_ISSUES_FOUND""")
    
    user_message = HumanMessage(content=f"""Review this code for performance issues:
    
    {state.get('language', '')}
    {state['source_code']}
    """)
    
    response = llm.invoke([system_prompt, user_message])
    result = response.content.strip()
    
    if result == "NO_PERFORMANCE_ISSUES_FOUND":
        return {"findings": []}
    
    findings = [line.strip() for line in result.split("\n") if line.strip() and "[PERFORMANCE]" in line]
    return {"findings": findings}

Step 3: Build the Report Aggregator Node

After all reviewers have contributed their findings, we need a node that synthesizes everything into a polished, actionable report. This node also handles cases where no issues were found anywhere:

def report_aggregator(state: CodeReviewState) -> dict:
    """Aggregate all findings into a structured final report."""
    findings = state.get("findings", [])
    
    if not findings:
        return {
            "final_report": "✅ **Code Review Complete** — No issues were found across all review dimensions (Style, Security, Logic, Performance). The code looks clean!",
            "iteration_count": state.get("iteration_count", 0) + 1
        }
    
    # Sort findings by severity priority
    severity_order = {"CRITICAL": 0, "HIGH": 1, "MEDIUM": 2, "LOW": 3}
    
    def severity_key(finding: str) -> int:
        for sev in ["CRITICAL", "HIGH", "MEDIUM", "LOW"]:
            if sev in finding:
                return severity_order[sev]
        return 99
    
    sorted_findings = sorted(findings, key=severity_key)
    
    # Build the report
    report_lines = ["# 📋 Automated Code Review Report", ""]
    report_lines.append(f"**Language:** {state.get('language', 'Unknown')}")
    report_lines.append(f"**Total Issues Found:** {len(sorted_findings)}")
    report_lines.append("")
    
    # Group by category
    categories = {}
    for finding in sorted_findings:
        for cat in ["STYLE", "SECURITY", "LOGIC", "PERFORMANCE"]:
            if f"[{cat}]" in finding:
                categories.setdefault(cat, []).append(finding)
                break
    
    category_labels = {
        "STYLE": "🎨 Style & Convention",
        "SECURITY": "🔒 Security",
        "LOGIC": "🐛 Logic & Potential Bugs",
        "PERFORMANCE": "⚡ Performance"
    }
    
    for cat_key in ["SECURITY", "LOGIC", "STYLE", "PERFORMANCE"]:
        if cat_key in categories:
            report_lines.append(f"## {category_labels[cat_key]}")
            report_lines.append("")
            for i, finding in enumerate(categories[cat_key], 1):
                # Extract just the description part after the tag
                clean = finding.replace(f"[{cat_key}] ", f"{i}. ")
                report_lines.append(clean)
            report_lines.append("")
    
    # Add summary
    critical_count = sum(1 for f in findings if "CRITICAL" in f)
    high_count = sum(1 for f in findings if "HIGH" in f)
    
    if critical_count > 0:
        report_lines.append(f"## ⚠️ Action Required")
        report_lines.append(f"**{critical_count} CRITICAL** issues need immediate attention before deployment.")
    
    report_lines.append("")
    report_lines.append("---")
    report_lines.append("*Report generated by LangGraph Code Review Agent*")
    
    final_report = "\n".join(report_lines)
    
    return {
        "final_report": final_report,
        "iteration_count": state.get("iteration_count", 0) + 1,
        "has_critical_issues": state.get("has_critical_issues", False) or critical_count > 0
    }

Step 4: Define the Graph Structure

Now we assemble the nodes and edges into a StateGraph. The key architectural decision is: should reviewers run in parallel or sequentially? For code review, parallel execution is ideal — each reviewer operates independently on the same source code, and their findings are merged automatically via the Annotated list. LangGraph handles this elegantly by fanning out from a single node to multiple nodes, then converging back.

Here's how to build the graph:

from langgraph.graph import StateGraph, START, END

# Initialize the graph with our state type
builder = StateGraph(CodeReviewState)

# Add all nodes
builder.add_node("style_reviewer", style_reviewer)
builder.add_node("security_reviewer", security_reviewer)
builder.add_node("logic_reviewer", logic_reviewer)
builder.add_node("performance_reviewer", performance_reviewer)
builder.add_node("report_aggregator", report_aggregator)

# Define the flow:
# START -> all four reviewers (parallel fan-out)
# Each reviewer -> report_aggregator (fan-in convergence)
# report_aggregator -> END

# Entry point: from START, go to all reviewers
builder.add_edge(START, "style_reviewer")
builder.add_edge(START, "security_reviewer")
builder.add_edge(START, "logic_reviewer")
builder.add_edge(START, "performance_reviewer")

# All reviewers converge to the aggregator
builder.add_edge("style_reviewer", "report_aggregator")
builder.add_edge("security_reviewer", "report_aggregator")
builder.add_edge("logic_reviewer", "report_aggregator")
builder.add_edge("performance_reviewer", "report_aggregator")

# Aggregator completes the workflow
builder.add_edge("report_aggregator", END)

# Compile the graph
graph = builder.compile()

This creates a simple but powerful fan-out/fan-in pattern. When invoked, LangGraph sends the initial state to all four reviewers simultaneously. Each returns its findings independently. LangGraph waits for all four to complete, merges the findings lists (thanks to the operator.add annotation), and then invokes the aggregator with the combined findings.

Step 5: Add Conditional Routing for Critical Issues

The basic graph works well, but real code review often requires escalation. Let's add a conditional edge: if critical security or logic issues are found, route to a deeper "second-pass" analysis node before finalizing the report. This demonstrates LangGraph's powerful conditional routing:

def deep_security_analysis(state: CodeReviewState) -> dict:
    """Perform a deeper security analysis when critical issues are flagged."""
    system_prompt = SystemMessage(content="""You are a senior application security specialist.
    A previous review flagged CRITICAL security issues. Perform a deeper analysis:
    - Trace the vulnerable code path end-to-end
    - Assess exploitability and potential impact
    - Provide a detailed remediation plan with code examples
    - Check if the vulnerability pattern appears elsewhere in the codebase
    
    Format findings as:
    [DEEP-SECURITY] {severity}: {detailed_analysis} | Remediation: {steps}""")
    
    user_message = HumanMessage(content=f"""Deep security analysis requested. Original findings:
    {chr(10).join(state.get('findings', []))}
    
    Source code:
    {state.get('language', '')}
    {state['source_code']}
    """)
    
    response = llm.invoke([system_prompt, user_message])
    result = response.content.strip()
    
    deep_findings = [line.strip() for line in result.split("\n") if line.strip() and "[DEEP-SECURITY]" in line]
    return {"findings": deep_findings}

def should_escalate(state: CodeReviewState) -> str:
    """Conditional routing: escalate if critical issues exist and we haven't already."""
    if state.get("has_critical_issues", False) and state.get("iteration_count", 0) < 1:
        return "deep_security_analysis"
    return "report_aggregator"

# Build the enhanced graph
builder_v2 = StateGraph(CodeReviewState)

# Add all nodes (including the new deep analysis node)
builder_v2.add_node("style_reviewer", style_reviewer)
builder_v2.add_node("security_reviewer", security_reviewer)
builder_v2.add_node("logic_reviewer", logic_reviewer)
builder_v2.add_node("performance_reviewer", performance_reviewer)
builder_v2.add_node("deep_security_analysis", deep_security_analysis)
builder_v2.add_node("report_aggregator", report_aggregator)

# Fan-out from START to reviewers
builder_v2.add_edge(START, "style_reviewer")
builder_v2.add_edge(START, "security_reviewer")
builder_v2.add_edge(START, "logic_reviewer")
builder_v2.add_edge(START, "performance_reviewer")

# Instead of all going directly to aggregator, we route through a conditional
# after security and logic reviewers complete (they set has_critical_issues)
builder_v2.add_edge("style_reviewer", "report_aggregator")
builder_v2.add_edge("performance_reviewer", "report_aggregator")

# Security and logic reviewers go to a conditional check
builder_v2.add_conditional_edges(
    "security_reviewer",
    should_escalate,
    {
        "deep_security_analysis": "deep_security_analysis",
        "report_aggregator": "report_aggregator"
    }
)
builder_v2.add_conditional_edges(
    "logic_reviewer",
    should_escalate,
    {
        "deep_security_analysis": "deep_security_analysis",
        "report_aggregator": "report_aggregator"
    }
)

# Deep analysis always goes to aggregator afterward
builder_v2.add_edge("deep_security_analysis", "report_aggregator")
builder_v2.add_edge("report_aggregator", END)

graph_v2 = builder_v2.compile()

The conditional function should_escalate checks the state for critical issues and whether we've already performed a deep analysis (tracked via iteration_count). If conditions are met, the graph routes to deep_security_analysis; otherwise, it proceeds directly to the aggregator. This prevents infinite loops while enabling intelligent escalation.

Step 6: Run the Agent

With the graph compiled, running the agent is straightforward. Here's a complete example with sample code to review:

# Sample code with intentional issues to test the agent
sample_code = """
import os
import requests

def get_user_data(user_id):
    query = f"SELECT * FROM users WHERE id = {user_id}"
    db_password = "super_secret_123"
    conn = psycopg2.connect(
        host="localhost",
        password=db_password
    )
    cursor = conn.cursor()
    cursor.execute(query)
    result = cursor.fetchone()
    return result

def process_items(items):
    result = []
    for i in range(len(items)):
        item = items[i]
        if item != None:
            processed = heavy_computation(item)
            result.append(processed)
    return result

def heavy_computation(x):
    # Expensive operation without caching
    import time
    time.sleep(1)
    return x * x
"""

# Initialize state
initial_state: CodeReviewState = {
    "source_code": sample_code,
    "language": "python",
    "findings": [],
    "final_report": None,
    "has_critical_issues": False,
    "iteration_count": 0
}

# Run the enhanced graph
print("🔍 Running LangGraph Code Review Agent...")
print("=" * 60)

final_state = graph_v2.invoke(initial_state)

# Display the final report
print(final_state["final_report"])
print("\n" + "=" * 60)
print(f"Total findings: {len(final_state.get('findings', []))}")
print(f"Iterations: {final_state.get('iteration_count', 0)}")
print(f"Critical issues: {final_state.get('has_critical_issues', False)}")

Expected Output Structure

When you run this, the agent will produce a structured Markdown report similar to:

# 📋 Automated Code Review Report

**Language:** python
**Total Issues Found:** 7

## 🔒 Security
1. CRITICAL: SQL injection vulnerability in get_user_data() - query constructed with string formatting | Fix: Use parameterized queries
2. CRITICAL: Hardcoded database password 'super_secret_123' in source code | Fix: Use environment variables or secrets manager
3. ...

## 🐛 Logic & Potential Bugs
4. HIGH: item != None should use 'is not None' for proper None checking | Fix: Replace with 'if item is not None'
...

## 🎨 Style & Convention
...

## ⚡ Performance
...

## ⚠️ Action Required
**2 CRITICAL** issues need immediate attention before deployment.
---
*Report generated by LangGraph Code Review Agent*

Step 7: Visualizing the Graph (Optional)

LangGraph includes utilities to visualize your graph structure, which is invaluable for debugging complex workflows:

from langgraph.graph import Graph

# For the simple graph
graph_image = graph.get_graph().draw_png()
with open("code_review_graph.png", "wb") as f:
    f.write(graph_image)

# For the enhanced graph with conditional routing
graph_v2_image = graph_v2.get_graph().draw_png()
with open("code_review_graph_v2.png", "wb") as f:
    f.write(graph_v2_image)

print("Graph visualizations saved as PNG files.")

Complete Agent Code

Below is the full, self-contained code for the enhanced code review agent. Save it as code_review_agent.py:

"""
LangGraph Code Review Agent
A multi-specialist automated code reviewer with conditional escalation.
"""

import operator
import os
from typing import TypedDict, List, Optional, Annotated

from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage, SystemMessage
from langgraph.graph import StateGraph, START, END


# ─── State Definition ───────────────────────────────────────────

class CodeReviewState(TypedDict):
    source_code: str
    language: str
    findings: Annotated[List[str], operator.add]
    final_report: Optional[str]
    has_critical_issues: bool
    iteration_count: int


# ─── LLM Configuration ──────────────────────────────────────────

llm = ChatOpenAI(model="gpt-4o", temperature=0.2)


# ─── Reviewer Nodes ─────────────────────────────────────────────

def style_reviewer(state: CodeReviewState) -> dict:
    system_prompt = SystemMessage(content="""You are an expert code style reviewer.
    Analyze the provided code for naming conventions, formatting, readability,
    comment quality, and language-specific style guide adherence.
    
    Format each finding as: [STYLE] {severity}: {description} | Suggestion: {fix}
    Severity: LOW, MEDIUM, HIGH
    If no issues found, respond with exactly: NO_STYLE_ISSUES_FOUND""")
    
    user_message = HumanMessage(content=f"""Review this {state.get('language', 'code')} code:
    {state.get('language', '')}
    {state['source_code']}
    """)
    
    response = llm.invoke([system_prompt, user_message])
    result = response.content.strip()
    
    if result == "NO_STYLE_ISSUES_FOUND":
        return {"findings": []}
    findings = [line.strip() for line in result.split("\n") if line.strip() and "[STYLE]" in line]
    return {"findings": findings}


def security_reviewer(state: CodeReviewState) -> dict:
    system_prompt = SystemMessage(content="""You are an expert application security reviewer.
    Analyze for injection vulnerabilities, hardcoded secrets, insecure crypto,
    missing validation, auth flaws, path traversal, unsafe deserialization.
    
    Format: [SECURITY] {severity}: {description} | Fix: {recommendation}
    Severity: LOW, MEDIUM, HIGH, CRITICAL
    If no issues: NO_SECURITY_ISSUES_FOUND""")
    
    user_message = HumanMessage(content=f"""Security review:
    {state.get('language', '')}
    {state['source_code']}
    """)
    
    response = llm.invoke([system_prompt, user_message])
    result = response.content.strip()
    
    if result == "NO_SECURITY_ISSUES_FOUND":
        return {"findings": [], "has_critical_issues": False}
    findings = [line.strip() for line in result.split("\n") if line.strip() and "[SECURITY]" in line]
    has_critical = any("CRITICAL" in f for f in findings)
    return {"findings": findings, "has_critical_issues": has_critical}


def logic_reviewer(state: CodeReviewState) -> dict:
    system_prompt = SystemMessage(content="""You are an expert logic reviewer.
    Analyze for off-by-one errors, boundary bugs, incorrect conditionals,
    null reference risks, type mismatches, resource leaks, race conditions,
    and error handling flaws.
    
    Format: [LOGIC] {severity}: {description} | Fix: {recommendation}
    Severity: LOW, MEDIUM, HIGH, CRITICAL
    If no issues: NO_LOGIC_ISSUES_FOUND""")
    
    user_message = HumanMessage(content=f"""Logic review:
    {state.get('language', '')}
    {state['source_code']}
    """)
    
    response = llm.invoke([system_prompt, user_message])
    result = response.content.strip()
    
    if result == "NO_LOGIC_ISSUES_FOUND":
        return {"findings": [], "has_critical_issues": False}
    findings = [line.strip() for line in result.split("\n") if line.strip() and "[LOGIC]" in line]
    has_critical = any("CRITICAL" in f for f in findings)
    return {"findings": findings, "has_critical_issues": has_critical}


def performance_reviewer(state: CodeReviewState) -> dict:
    system_prompt = SystemMessage(content="""You are an expert performance engineer.
    Analyze for inefficient algorithms, redundant computations, memory waste,
    missing caching, N+1 patterns, blocking operations, excessive allocations.
    
    Format: [PERFORMANCE] {severity}: {description} | Improvement: {suggestion}
    Severity: LOW, MEDIUM, HIGH
    If no issues: NO_PERFORMANCE_ISSUES_FOUND""")
    
    user_message = HumanMessage(content=f"""Performance review:
    {state.get('language', '')}
    {state['source_code']}
    """)
    
    response = llm.invoke([system_prompt, user_message])
    result = response.content.strip()
    
    if result == "NO_PERFORMANCE_ISSUES_FOUND":
        return {"findings": []}
    findings = [line.strip() for line in result.split("\n") if line.strip() and "[PERFORMANCE]" in line]
    return {"findings": findings}


def deep_security_analysis(state: CodeReviewState) -> dict:
    system_prompt = SystemMessage(content="""You are a senior application security specialist.
    Perform a deeper analysis of previously flagged CRITICAL issues:
    - Trace vulnerable code paths end-to-end
    - Assess exploitability and impact
    - Provide detailed remediation with code examples
    - Check for pattern repetition
    
    Format: [DEEP-SECURITY] {severity}: {detailed_analysis} | Remediation: {steps}""")
    
    user_message = HumanMessage(content=f"""Deep security analysis. Original findings:
    {chr(10).join(state.get('findings', []))}
    
    Source code:
    {state.get('language', '')}
    {state['source_code']}
    """)
    
    response = llm.invoke([system_prompt, user_message])
    result = response.content.strip()
    
    deep_findings = [line.strip() for line in result.split("\n") if line.strip() and "[DEEP-SECURITY]" in line]
    return {"findings": deep_findings}


# ─── Report Aggregator ──────────────────────────────────────────

def report_aggregator(state: CodeReviewState) -> dict:
    findings = state.get("findings", [])
    
    if not findings:
        return {
            "final_report": "✅ **Code Review Complete** — No issues found across all dimensions.",
            "iteration_count": state.get("iteration_count", 0) + 1
        }
    
    severity_order = {"CRITICAL": 0, "HIGH": 1, "MEDIUM": 2, "LOW": 3}
    sorted_findings = sorted(findings, key=lambda f: next(
        (severity_order[s] for s in ["CRITICAL", "HIGH", "MEDIUM", "LOW"] if s in f), 99))
    
    categories = {}
    for finding in sorted_findings:
        for cat in ["STYLE", "SECURITY", "LOGIC", "PERFORMANCE", "DEEP-SECURITY"]:
            if f"[{cat}]" in finding:
                categories.setdefault(cat, []).append(finding)
                break
    
    report_lines = ["# 📋 Automated Code Review Report", ""]
    report_lines.append(f"**Language:** {state.get('language', 'Unknown')}")
    report_lines.append(f"**Total Issues Found:** {len(sorted_findings)}")
    report_lines.append("")
    
    category_labels = {
        "DEEP-SECURITY": "🔴 Deep Security Analysis (Escalated)",
        "SECURITY": "🔒 Security",
        "LOGIC": "🐛 Logic & Potential Bugs",
        "STYLE": "🎨 Style & Convention",
        "PERFORMANCE": "⚡ Performance"
    }
    
    priority_order = ["DEEP-SECURITY", "SECURITY", "LOGIC", "STYLE", "PERFORMANCE"]
    for cat_key in priority_order:
        if cat_key in categories:
            report_lines.append(f"## {category_labels[cat_key]}")
            report_lines.append("")
            for i, finding in enumerate(categories[cat_key], 1):
                clean = finding.replace

— Ad —

Google AdSense will appear here after approval

← Back to all articles