Update app.py
Browse files
app.py
CHANGED
|
@@ -95,32 +95,12 @@ append_answer_lock = threading.Lock()
|
|
| 95 |
# Initialize browser
|
| 96 |
browser = SimpleTextBrowser(request_kwargs={})
|
| 97 |
|
| 98 |
-
# Initialize tools
|
| 99 |
-
ti_tool = TextInspectorTool(None, 20000) # Will be updated with session-specific model
|
| 100 |
-
|
| 101 |
# Initialize vulnerability tools
|
| 102 |
cvedb_tool = CVEDBTool()
|
| 103 |
epss_tool = EpsTool()
|
| 104 |
nvd_tool = NvdTool()
|
| 105 |
kevin_tool = KevinTool()
|
| 106 |
|
| 107 |
-
# Default tools (will be updated with session-specific models)
|
| 108 |
-
WEB_TOOLS = [
|
| 109 |
-
web_search, # duckduckgo
|
| 110 |
-
VisitTool(browser),
|
| 111 |
-
PageUpTool(browser),
|
| 112 |
-
PageDownTool(browser),
|
| 113 |
-
FinderTool(browser),
|
| 114 |
-
FindNextTool(browser),
|
| 115 |
-
ArchiveSearchTool(browser),
|
| 116 |
-
] + ([ti_tool] if ti_tool else []) + [
|
| 117 |
-
cvedb_tool, # CVEDB Tool
|
| 118 |
-
# report_generator, # Report generation tool - COMMENTED: Only works locally
|
| 119 |
-
epss_tool, # EPSS Tool
|
| 120 |
-
nvd_tool, # NVD Tool
|
| 121 |
-
kevin_tool, # KEVin Tool
|
| 122 |
-
]
|
| 123 |
-
|
| 124 |
def validate_hf_api_key(api_key: str) -> tuple[bool, str]:
|
| 125 |
"""Validate Hugging Face API key by making a test request."""
|
| 126 |
if not api_key or not api_key.strip():
|
|
@@ -168,10 +148,19 @@ def create_model_with_api_key(hf_token: str, model_id: str = None) -> InferenceC
|
|
| 168 |
|
| 169 |
def create_tools_with_model(model: InferenceClientModel):
|
| 170 |
"""Create tools with the provided model."""
|
|
|
|
|
|
|
|
|
|
|
|
|
| 171 |
# Update text inspector tool with the model
|
|
|
|
| 172 |
ti_tool = TextInspectorTool(model, 20000)
|
| 173 |
|
| 174 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 175 |
web_search, # duckduckgo
|
| 176 |
VisitTool(browser),
|
| 177 |
PageUpTool(browser),
|
|
@@ -179,13 +168,15 @@ def create_tools_with_model(model: InferenceClientModel):
|
|
| 179 |
FinderTool(browser),
|
| 180 |
FindNextTool(browser),
|
| 181 |
ArchiveSearchTool(browser),
|
| 182 |
-
|
| 183 |
cvedb_tool, # CVEDB Tool
|
| 184 |
# report_generator, # Report generation tool - COMMENTED: Only works locally
|
| 185 |
epss_tool, # EPSS Tool
|
| 186 |
nvd_tool, # NVD Tool
|
| 187 |
kevin_tool, # KEVin Tool
|
| 188 |
]
|
|
|
|
|
|
|
| 189 |
|
| 190 |
# Agent creation in a factory function
|
| 191 |
def create_agent(hf_token: str = None, model_id: str = None, max_steps: int = 10):
|
|
@@ -199,6 +190,11 @@ def create_agent(hf_token: str = None, model_id: str = None, max_steps: int = 10
|
|
| 199 |
model = create_model_with_api_key(hf_token, model_id)
|
| 200 |
tools = create_tools_with_model(model)
|
| 201 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 202 |
agent = CodeAgent(
|
| 203 |
model=model,
|
| 204 |
tools=[visualizer] + tools,
|
|
@@ -211,9 +207,6 @@ def create_agent(hf_token: str = None, model_id: str = None, max_steps: int = 10
|
|
| 211 |
logger.info("Agent created successfully")
|
| 212 |
return agent
|
| 213 |
|
| 214 |
-
# Document inspection tool will be created per session
|
| 215 |
-
document_inspection_tool = None
|
| 216 |
-
|
| 217 |
def get_user_session(request: gr.Request) -> str:
|
| 218 |
"""Get or create a unique session ID for the user."""
|
| 219 |
if not request:
|
|
@@ -486,7 +479,12 @@ User Query: """
|
|
| 486 |
# Combine system prompt with user message
|
| 487 |
full_prompt = system_prompt + prompt
|
| 488 |
|
| 489 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 490 |
yield messages
|
| 491 |
|
| 492 |
logger.info(f"Starting agent interaction for session {session_id[:8]}...")
|
|
@@ -614,13 +612,18 @@ User Query: """
|
|
| 614 |
), file_uploads_log + [file_path]
|
| 615 |
|
| 616 |
def log_user_message(self, text_input, file_uploads_log):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 617 |
return (
|
| 618 |
-
|
| 619 |
-
+ (
|
| 620 |
-
f"\nYou have been provided with these files, which might be helpful or not: {file_uploads_log}"
|
| 621 |
-
if len(file_uploads_log) > 0
|
| 622 |
-
else ""
|
| 623 |
-
),
|
| 624 |
gr.Textbox(
|
| 625 |
value="",
|
| 626 |
interactive=False,
|
|
@@ -821,18 +824,20 @@ This AI agent specializes in automated vulnerability research and analysis, buil
|
|
| 821 |
setup_api_btn = gr.Button("Setup API Key", variant="secondary")
|
| 822 |
|
| 823 |
# If an upload folder is provided, enable the upload feature
|
| 824 |
-
|
| 825 |
-
|
| 826 |
-
|
| 827 |
-
|
| 828 |
-
|
| 829 |
-
|
| 830 |
-
|
| 831 |
-
|
| 832 |
-
|
| 833 |
-
|
| 834 |
-
|
| 835 |
-
|
|
|
|
|
|
|
| 836 |
|
| 837 |
# Powered by smolagents
|
| 838 |
with gr.Row():
|
|
@@ -1000,6 +1005,22 @@ This AI agent specializes in automated vulnerability research and analysis, buil
|
|
| 1000 |
variant="primary",
|
| 1001 |
)
|
| 1002 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1003 |
# Examples Section for Mobile
|
| 1004 |
with gr.Accordion("💡 Example Prompts", open=False):
|
| 1005 |
gr.Markdown("**Click any example below to populate your request field:**")
|
|
@@ -1129,7 +1150,7 @@ This AI agent specializes in automated vulnerability research and analysis, buil
|
|
| 1129 |
|
| 1130 |
demo.launch(
|
| 1131 |
debug=True,
|
| 1132 |
-
server_name="
|
| 1133 |
server_port=7860,
|
| 1134 |
share=False,
|
| 1135 |
**kwargs
|
|
@@ -1137,6 +1158,6 @@ This AI agent specializes in automated vulnerability research and analysis, buil
|
|
| 1137 |
|
| 1138 |
# can this fix ctrl-c no response? no
|
| 1139 |
try:
|
| 1140 |
-
GradioUI().launch(
|
| 1141 |
except KeyboardInterrupt:
|
| 1142 |
...
|
|
|
|
| 95 |
# Initialize browser
|
| 96 |
browser = SimpleTextBrowser(request_kwargs={})
|
| 97 |
|
|
|
|
|
|
|
|
|
|
| 98 |
# Initialize vulnerability tools
|
| 99 |
cvedb_tool = CVEDBTool()
|
| 100 |
epss_tool = EpsTool()
|
| 101 |
nvd_tool = NvdTool()
|
| 102 |
kevin_tool = KevinTool()
|
| 103 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 104 |
def validate_hf_api_key(api_key: str) -> tuple[bool, str]:
|
| 105 |
"""Validate Hugging Face API key by making a test request."""
|
| 106 |
if not api_key or not api_key.strip():
|
|
|
|
| 148 |
|
| 149 |
def create_tools_with_model(model: InferenceClientModel):
|
| 150 |
"""Create tools with the provided model."""
|
| 151 |
+
# Verify the model was created correctly
|
| 152 |
+
if model is None:
|
| 153 |
+
raise ValueError("Model is None, cannot create TextInspectorTool")
|
| 154 |
+
|
| 155 |
# Update text inspector tool with the model
|
| 156 |
+
# 20000 = maximum characters to read from files (text_limit)
|
| 157 |
ti_tool = TextInspectorTool(model, 20000)
|
| 158 |
|
| 159 |
+
# Verify the tool was created correctly
|
| 160 |
+
if ti_tool is None:
|
| 161 |
+
raise ValueError("Failed to create TextInspectorTool")
|
| 162 |
+
|
| 163 |
+
tools = [
|
| 164 |
web_search, # duckduckgo
|
| 165 |
VisitTool(browser),
|
| 166 |
PageUpTool(browser),
|
|
|
|
| 168 |
FinderTool(browser),
|
| 169 |
FindNextTool(browser),
|
| 170 |
ArchiveSearchTool(browser),
|
| 171 |
+
ti_tool, # TextInspectorTool - always available
|
| 172 |
cvedb_tool, # CVEDB Tool
|
| 173 |
# report_generator, # Report generation tool - COMMENTED: Only works locally
|
| 174 |
epss_tool, # EPSS Tool
|
| 175 |
nvd_tool, # NVD Tool
|
| 176 |
kevin_tool, # KEVin Tool
|
| 177 |
]
|
| 178 |
+
|
| 179 |
+
return tools
|
| 180 |
|
| 181 |
# Agent creation in a factory function
|
| 182 |
def create_agent(hf_token: str = None, model_id: str = None, max_steps: int = 10):
|
|
|
|
| 190 |
model = create_model_with_api_key(hf_token, model_id)
|
| 191 |
tools = create_tools_with_model(model)
|
| 192 |
|
| 193 |
+
# Verify that TextInspectorTool is in the tools list
|
| 194 |
+
has_text_inspector = any(hasattr(tool, 'name') and tool.name == 'inspect_file_as_text' for tool in tools)
|
| 195 |
+
if not has_text_inspector:
|
| 196 |
+
raise ValueError("TextInspectorTool not found in tools list")
|
| 197 |
+
|
| 198 |
agent = CodeAgent(
|
| 199 |
model=model,
|
| 200 |
tools=[visualizer] + tools,
|
|
|
|
| 207 |
logger.info("Agent created successfully")
|
| 208 |
return agent
|
| 209 |
|
|
|
|
|
|
|
|
|
|
| 210 |
def get_user_session(request: gr.Request) -> str:
|
| 211 |
"""Get or create a unique session ID for the user."""
|
| 212 |
if not request:
|
|
|
|
| 479 |
# Combine system prompt with user message
|
| 480 |
full_prompt = system_prompt + prompt
|
| 481 |
|
| 482 |
+
# Extract clean message for display (remove internal context)
|
| 483 |
+
display_message = prompt
|
| 484 |
+
if "[INTERNAL CONTEXT:" in prompt:
|
| 485 |
+
display_message = prompt.split("[INTERNAL CONTEXT:")[0].strip()
|
| 486 |
+
|
| 487 |
+
messages.append(gr.ChatMessage(role="user", content=display_message))
|
| 488 |
yield messages
|
| 489 |
|
| 490 |
logger.info(f"Starting agent interaction for session {session_id[:8]}...")
|
|
|
|
| 612 |
), file_uploads_log + [file_path]
|
| 613 |
|
| 614 |
def log_user_message(self, text_input, file_uploads_log):
|
| 615 |
+
# Create the user message for display (clean, without file info)
|
| 616 |
+
display_message = text_input
|
| 617 |
+
|
| 618 |
+
# Create the internal message for the agent (with file context)
|
| 619 |
+
internal_message = text_input
|
| 620 |
+
if len(file_uploads_log) > 0:
|
| 621 |
+
file_names = [os.path.basename(f) for f in file_uploads_log]
|
| 622 |
+
file_paths = [f for f in file_uploads_log] # Full paths
|
| 623 |
+
internal_message += f"\n\n[Uploaded files available: {', '.join(file_names)}. Use inspect_file_as_text(file_path='uploads/filename') to analyze them. Use the content as plain text context if readable, no need to parse or create complex functions.]"
|
| 624 |
+
|
| 625 |
return (
|
| 626 |
+
internal_message, # This goes to the agent (with file context)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 627 |
gr.Textbox(
|
| 628 |
value="",
|
| 629 |
interactive=False,
|
|
|
|
| 824 |
setup_api_btn = gr.Button("Setup API Key", variant="secondary")
|
| 825 |
|
| 826 |
# If an upload folder is provided, enable the upload feature
|
| 827 |
+
# COMMENTED: File upload feature temporarily disabled - works but consumes too many steps for parsing
|
| 828 |
+
# TODO: Re-enable after optimizing TextInspectorTool to use fewer steps
|
| 829 |
+
# if self.file_upload_folder is not None:
|
| 830 |
+
# upload_file = gr.File(label="Upload a file")
|
| 831 |
+
# upload_status = gr.Textbox(
|
| 832 |
+
# label="Upload Status",
|
| 833 |
+
# interactive=False,
|
| 834 |
+
# visible=False,
|
| 835 |
+
# )
|
| 836 |
+
# upload_file.change(
|
| 837 |
+
# self.upload_file,
|
| 838 |
+
# [upload_file, file_uploads_log],
|
| 839 |
+
# [upload_status, file_uploads_log],
|
| 840 |
+
# )
|
| 841 |
|
| 842 |
# Powered by smolagents
|
| 843 |
with gr.Row():
|
|
|
|
| 1005 |
variant="primary",
|
| 1006 |
)
|
| 1007 |
|
| 1008 |
+
# File upload section for mobile (simple)
|
| 1009 |
+
# COMMENTED: File upload feature temporarily disabled - works but consumes too many steps for parsing
|
| 1010 |
+
# TODO: Re-enable after optimizing
|
| 1011 |
+
# if self.file_upload_folder is not None:
|
| 1012 |
+
# mobile_upload_file = gr.File(label="📎 Upload PDF/TXT file (optional)")
|
| 1013 |
+
# mobile_upload_status = gr.Textbox(
|
| 1014 |
+
# label="Upload Status",
|
| 1015 |
+
# interactive=False,
|
| 1016 |
+
# visible=False,
|
| 1017 |
+
# )
|
| 1018 |
+
# mobile_upload_file.change(
|
| 1019 |
+
# self.upload_file,
|
| 1020 |
+
# [mobile_upload_file, file_uploads_log],
|
| 1021 |
+
# [mobile_upload_status, file_uploads_log],
|
| 1022 |
+
# )
|
| 1023 |
+
|
| 1024 |
# Examples Section for Mobile
|
| 1025 |
with gr.Accordion("💡 Example Prompts", open=False):
|
| 1026 |
gr.Markdown("**Click any example below to populate your request field:**")
|
|
|
|
| 1150 |
|
| 1151 |
demo.launch(
|
| 1152 |
debug=True,
|
| 1153 |
+
server_name="localhost",
|
| 1154 |
server_port=7860,
|
| 1155 |
share=False,
|
| 1156 |
**kwargs
|
|
|
|
| 1158 |
|
| 1159 |
# can this fix ctrl-c no response? no
|
| 1160 |
try:
|
| 1161 |
+
GradioUI(file_upload_folder="uploads").launch()
|
| 1162 |
except KeyboardInterrupt:
|
| 1163 |
...
|