-
Notifications
You must be signed in to change notification settings - Fork 11
feat: integrate LangChain agent into prejudge pipeline #13
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| """ | ||
| Prejudge Module | ||
|
|
||
| Provides various analyses for kernel patches to determine if they should be backported. | ||
| """ | ||
|
|
||
| from prejudge.judge_agent import JudgeAgent | ||
| from prejudge.prejudge import PrejudgeController | ||
|
|
||
| __all__ = ["JudgeAgent", "PrejudgeController"] | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,323 @@ | ||||||||||||||||||||||||||||
| #!/usr/bin/env python3 | ||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||
| Judge Agent for Patch Backport Necessity | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| This module uses an LLM-based agent to analyze kernel patches and determine | ||||||||||||||||||||||||||||
| whether they need to be backported to downstream kernels based on whether | ||||||||||||||||||||||||||||
| the vulnerable code exists in the target. | ||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| import os | ||||||||||||||||||||||||||||
| import subprocess | ||||||||||||||||||||||||||||
| from functools import partial | ||||||||||||||||||||||||||||
| from pathlib import Path | ||||||||||||||||||||||||||||
| from typing import Literal | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| from langchain.agents import AgentExecutor, create_tool_calling_agent | ||||||||||||||||||||||||||||
| from langchain.prompts import ChatPromptTemplate, MessagesPlaceholder | ||||||||||||||||||||||||||||
| from langchain_openai import ChatOpenAI | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| # Handle imports for both direct execution and module import | ||||||||||||||||||||||||||||
| import sys | ||||||||||||||||||||||||||||
| from pathlib import Path | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| # Add src directory to path for imports | ||||||||||||||||||||||||||||
| _src_path = Path(__file__).parent.parent | ||||||||||||||||||||||||||||
| if str(_src_path) not in sys.path: | ||||||||||||||||||||||||||||
| sys.path.insert(0, str(_src_path)) | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| from prejudge.judge_tools import create_locate_symbol_tool, create_view_code_tool | ||||||||||||||||||||||||||||
| from prejudge.judge_prompt import JUDGE_SYSTEM_PROMPT, JUDGE_USER_PROMPT | ||||||||||||||||||||||||||||
|
Comment on lines
+20
to
+30
|
||||||||||||||||||||||||||||
| # Handle imports for both direct execution and module import | |
| import sys | |
| from pathlib import Path | |
| # Add src directory to path for imports | |
| _src_path = Path(__file__).parent.parent | |
| if str(_src_path) not in sys.path: | |
| sys.path.insert(0, str(_src_path)) | |
| from prejudge.judge_tools import create_locate_symbol_tool, create_view_code_tool | |
| from prejudge.judge_prompt import JUDGE_SYSTEM_PROMPT, JUDGE_USER_PROMPT | |
| from .judge_tools import create_locate_symbol_tool, create_view_code_tool | |
| from .judge_prompt import JUDGE_SYSTEM_PROMPT, JUDGE_USER_PROMPT |
Copilot
AI
Apr 13, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The LLM client is configured with verbose=True and a hard-coded base_url at import time. This can unintentionally log prompt/patch contents and forces all runs to send code to a specific external endpoint. Please make verbosity default to False (or tie it to debug_mode) and make the endpoint configurable (e.g., via an env var) with a safe default.
Copilot
AI
Apr 13, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
_parse_decision will return True for responses containing phrases like "not found in …" because the fallback tone check looks for the substring "found in" (and there is no corresponding negative indicator for "not found"). This mis-parses explicit negative answers and can inflate backport decisions. Add negative patterns like "not found"/"no occurrences" (or use a regex that excludes not found) and/or remove the ambiguous fallback substring check.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -88,6 +88,21 @@ def judge_arch(self, commit_id: str) -> bool: | |
| except Exception: | ||
| # If check fails, allow proceeding | ||
| return True | ||
|
|
||
| def judge_agent_llm(self, commit_id: str) -> bool: | ||
| """ | ||
| Judge if the patch needs to be backported using LLM agent | ||
| Returns True if the vulnerable code exists in target kernel, False otherwise | ||
| """ | ||
| from judge_llm import judge_with_llm | ||
|
|
||
| try: | ||
| result = judge_with_llm(commit_id, str(self.kernel_dir), str(self.target_project_dir)) | ||
| return result | ||
|
Comment on lines
+97
to
+101
|
||
| except Exception as e: | ||
| # If agent fails, log error but be conservative and return True | ||
| print(f"Warning: LLM agent check failed: {e}", file=sys.stderr) | ||
| return True | ||
|
|
||
| def judge_config(self, patch_content: str) -> Set[str]: | ||
| """ | ||
|
|
@@ -201,7 +216,7 @@ def analyze_and_report(self, commit_id: str) -> None: | |
| # Step 1: Check if fix commits exist in target project (before config checking) | ||
| fix_exists = self.judge_fix(commit_id) | ||
| if not fix_exists: | ||
| # Fix commits don't exist in target project, no need to check config | ||
| # Fix commits don't exist in target project, no need to check further | ||
| print("false") | ||
| return | ||
|
|
||
|
|
@@ -233,8 +248,11 @@ def analyze_and_report(self, commit_id: str) -> None: | |
| print("false") | ||
| return | ||
|
|
||
| # All checks passed | ||
| print("true") | ||
| # Step 5: Use LLM agent to check if vulnerable code exists in target kernel | ||
| agent_result = self.judge_agent_llm(commit_id) | ||
|
|
||
| # Output final result based on agent's decision | ||
| print("true" if agent_result else "false") | ||
|
|
||
|
|
||
| def main(): | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Importing
JudgeAgentandPrejudgeControllerat package import time makesimport prejudgeeagerly pull in LangChain/OpenAI dependencies and also triggers side effects fromjudge_agent.py(e.g.,sys.pathmutation). Consider avoiding eager imports here (e.g., expose names via lazy__getattr__, or only set__all__and let callers import submodules explicitly) to keep package import lightweight and predictable.