29
29
from langgraph .graph import StateGraph
30
30
from pydantic import BaseModel , Field
31
31
32
+ from browser_use .browser .context import BrowserContextWindowSize , BrowserContextConfig
33
+
32
34
from src .agent .browser_use .browser_use_agent import BrowserUseAgent
33
35
from src .browser .custom_browser import CustomBrowser
34
- from src .browser .custom_context import CustomBrowserContextConfig
35
36
from src .controller .custom_controller import CustomController
36
37
from src .utils .mcp_client import setup_mcp_client_and_tools
37
38
47
48
48
49
49
50
async def run_single_browser_task (
50
- task_query : str ,
51
- task_id : str ,
52
- llm : Any , # Pass the main LLM
53
- browser_config : Dict [str , Any ],
54
- stop_event : threading .Event ,
55
- use_vision : bool = False ,
51
+ task_query : str ,
52
+ task_id : str ,
53
+ llm : Any , # Pass the main LLM
54
+ browser_config : Dict [str , Any ],
55
+ stop_event : threading .Event ,
56
+ use_vision : bool = False ,
56
57
) -> Dict [str , Any ]:
57
58
"""
58
59
Runs a single BrowserUseAgent task.
@@ -104,10 +105,9 @@ async def run_single_browser_task(
104
105
)
105
106
)
106
107
107
- context_config = CustomBrowserContextConfig (
108
+ context_config = BrowserContextConfig (
108
109
save_downloads_path = "./tmp/downloads" ,
109
- window_width = window_w ,
110
- window_height = window_h ,
110
+ browser_window_size = BrowserContextWindowSize (width = window_w , height = window_h ),
111
111
force_new_context = True ,
112
112
)
113
113
bu_browser_context = await bu_browser .new_context (config = context_config )
@@ -198,12 +198,12 @@ class BrowserSearchInput(BaseModel):
198
198
199
199
200
200
async def _run_browser_search_tool (
201
- queries : List [str ],
202
- task_id : str , # Injected dependency
203
- llm : Any , # Injected dependency
204
- browser_config : Dict [str , Any ],
205
- stop_event : threading .Event ,
206
- max_parallel_browsers : int = 1 ,
201
+ queries : List [str ],
202
+ task_id : str , # Injected dependency
203
+ llm : Any , # Injected dependency
204
+ browser_config : Dict [str , Any ],
205
+ stop_event : threading .Event ,
206
+ max_parallel_browsers : int = 1 ,
207
207
) -> List [Dict [str , Any ]]:
208
208
"""
209
209
Internal function to execute parallel browser searches based on LLM-provided queries.
@@ -267,11 +267,11 @@ async def task_wrapper(query):
267
267
268
268
269
269
def create_browser_search_tool (
270
- llm : Any ,
271
- browser_config : Dict [str , Any ],
272
- task_id : str ,
273
- stop_event : threading .Event ,
274
- max_parallel_browsers : int = 1 ,
270
+ llm : Any ,
271
+ browser_config : Dict [str , Any ],
272
+ task_id : str ,
273
+ stop_event : threading .Event ,
274
+ max_parallel_browsers : int = 1 ,
275
275
) -> StructuredTool :
276
276
"""Factory function to create the browser search tool with necessary dependencies."""
277
277
# Use partial to bind the dependencies that aren't part of the LLM call arguments
@@ -553,7 +553,7 @@ async def research_execution_node(state: DeepResearchState) -> Dict[str, Any]:
553
553
else :
554
554
current_task_message = [
555
555
SystemMessage (
556
- content = "You are a research assistant executing one step of a research plan. Use the available tools, especially the 'parallel_browser_search' tool, to gather information needed for the current task. Be precise with your search queries if using the browser tool."
556
+ content = "You are a research assistant executing one step of a research plan. Use the available tools, especially the 'parallel_browser_search' tool, to gather information needed for the current task. Be precise with your search queries if using the browser tool. Please output at least one tool. "
557
557
),
558
558
HumanMessage (
559
559
content = f"Research Task (Step { current_step ['step' ]} ): { current_step ['task' ]} "
@@ -582,8 +582,11 @@ async def research_execution_node(state: DeepResearchState) -> Dict[str, Any]:
582
582
_save_plan_to_md (plan , output_dir )
583
583
return {
584
584
"research_plan" : plan ,
585
- "current_step_index" : current_index + 1 ,
586
- "error_message" : f"LLM failed to call a tool for step { current_step ['step' ]} ." ,
585
+ "status" : "pending" ,
586
+ "current_step_index" : current_index ,
587
+ "messages" : [
588
+ f"LLM failed to call a tool for step { current_step ['step' ]} . Response: { ai_response .content } "
589
+ f". Please use tool to do research unless you are thinking or summary" ],
587
590
}
588
591
589
592
# Process tool calls
@@ -665,8 +668,8 @@ async def research_execution_node(state: DeepResearchState) -> Dict[str, Any]:
665
668
browser_tool_called = "parallel_browser_search" in executed_tool_names
666
669
# We might need a more nuanced status based on the *content* of tool_results
667
670
step_failed = (
668
- any ("Error:" in str (tr .content ) for tr in tool_results )
669
- or not browser_tool_called
671
+ any ("Error:" in str (tr .content ) for tr in tool_results )
672
+ or not browser_tool_called
670
673
)
671
674
672
675
if step_failed :
@@ -695,9 +698,9 @@ async def research_execution_node(state: DeepResearchState) -> Dict[str, Any]:
695
698
"search_results" : current_search_results , # Update with new results
696
699
"current_step_index" : current_index + 1 ,
697
700
"messages" : state ["messages" ]
698
- + current_task_message
699
- + [ai_response ]
700
- + tool_results ,
701
+ + current_task_message
702
+ + [ai_response ]
703
+ + tool_results ,
701
704
# Optionally return the tool_results messages if needed by downstream nodes
702
705
}
703
706
@@ -879,10 +882,10 @@ def should_continue(state: DeepResearchState) -> str:
879
882
880
883
class DeepResearchAgent :
881
884
def __init__ (
882
- self ,
883
- llm : Any ,
884
- browser_config : Dict [str , Any ],
885
- mcp_server_config : Optional [Dict [str , Any ]] = None ,
885
+ self ,
886
+ llm : Any ,
887
+ browser_config : Dict [str , Any ],
888
+ mcp_server_config : Optional [Dict [str , Any ]] = None ,
886
889
):
887
890
"""
888
891
Initializes the DeepSearchAgent.
@@ -904,7 +907,7 @@ def __init__(
904
907
self .runner : Optional [asyncio .Task ] = None # To hold the asyncio task for run
905
908
906
909
async def _setup_tools (
907
- self , task_id : str , stop_event : threading .Event , max_parallel_browsers : int = 1
910
+ self , task_id : str , stop_event : threading .Event , max_parallel_browsers : int = 1
908
911
) -> List [Tool ]:
909
912
"""Sets up the basic tools (File I/O) and optional MCP tools."""
910
913
tools = [
@@ -981,11 +984,11 @@ def _compile_graph(self) -> StateGraph:
981
984
return app
982
985
983
986
async def run (
984
- self ,
985
- topic : str ,
986
- task_id : Optional [str ] = None ,
987
- save_dir : str = "./tmp/deep_research" ,
988
- max_parallel_browsers : int = 1 ,
987
+ self ,
988
+ topic : str ,
989
+ task_id : Optional [str ] = None ,
990
+ save_dir : str = "./tmp/deep_research" ,
991
+ max_parallel_browsers : int = 1 ,
989
992
) -> Dict [str , Any ]:
990
993
"""
991
994
Starts the deep research process (Async Generator Version).
0 commit comments