55from langchain_google_genai import ChatGoogleGenerativeAI
66from langgraph .checkpoint .memory import InMemorySaver
77from ..base_agent import BaseAgent , AgentState
8- from ..classification_router import MessageCategory
98from .tools .search_tool import TavilySearchTool
109from .tools .faq_tool import FAQTool
10+ from .github .github_toolkit import GitHubToolkit
1111from app .core .config import settings
1212from .nodes .gather_context import gather_context_node
13- from .nodes .handlers .faq import handle_faq_node
14- from .nodes .handlers .web_search import handle_web_search_node
15- from .nodes .handlers .technical_support import handle_technical_support_node
16- from .nodes .handlers .onboarding import handle_onboarding_node
17- from .generate_response_node import generate_response_node
1813from .nodes .summarization import check_summarization_needed , summarize_conversation_node , store_summary_to_database
14+ from .nodes .react_supervisor import react_supervisor_node , supervisor_decision_router
15+ from .tool_wrappers import web_search_tool_node , faq_handler_tool_node , onboarding_tool_node , github_toolkit_tool_node
16+ from .nodes .generate_response import generate_response_node
1917
2018logger = logging .getLogger (__name__ )
2119
@@ -31,48 +29,55 @@ def __init__(self, config: Dict[str, Any] = None):
3129 )
3230 self .search_tool = TavilySearchTool ()
3331 self .faq_tool = FAQTool ()
32+ self .github_toolkit = GitHubToolkit ()
3433 self .checkpointer = InMemorySaver ()
3534 super ().__init__ ("DevRelAgent" , self .config )
3635
3736 def _build_graph (self ):
3837 """Build the DevRel agent workflow graph"""
3938 workflow = StateGraph (AgentState )
4039
41- # Add nodes
40+ # Phase 1: Gather Context
4241 workflow .add_node ("gather_context" , gather_context_node )
43- workflow .add_node ("handle_faq" , partial (handle_faq_node , faq_tool = self .faq_tool ))
44- workflow .add_node ("handle_web_search" , partial (
45- handle_web_search_node , search_tool = self .search_tool , llm = self .llm ))
46- workflow .add_node ("handle_technical_support" , handle_technical_support_node )
47- workflow .add_node ("handle_onboarding" , handle_onboarding_node )
42+
43+ # Phase 2: ReAct Supervisor - Decide what to do next
44+ workflow .add_node ("react_supervisor" , partial (react_supervisor_node , llm = self .llm ))
45+ workflow .add_node ("web_search_tool" , partial (web_search_tool_node , search_tool = self .search_tool , llm = self .llm ))
46+ workflow .add_node ("faq_handler_tool" , partial (faq_handler_tool_node , faq_tool = self .faq_tool ))
47+ workflow .add_node ("onboarding_tool" , onboarding_tool_node )
48+ workflow .add_node ("github_toolkit_tool" , partial (github_toolkit_tool_node , github_toolkit = self .github_toolkit ))
49+
50+ # Phase 3: Generate Response
4851 workflow .add_node ("generate_response" , partial (generate_response_node , llm = self .llm ))
52+
53+ # Phase 4: Summarization
4954 workflow .add_node ("check_summarization" , check_summarization_needed )
5055 workflow .add_node ("summarize_conversation" , partial (summarize_conversation_node , llm = self .llm ))
5156
52- # Add edges
57+ # Entry point
58+ workflow .set_entry_point ("gather_context" )
59+ workflow .add_edge ("gather_context" , "react_supervisor" )
60+
61+ # ReAct supervisor routing
5362 workflow .add_conditional_edges (
54- "gather_context " ,
55- self . _route_to_handler ,
63+ "react_supervisor " ,
64+ supervisor_decision_router ,
5665 {
57- MessageCategory .FAQ : "handle_faq" ,
58- MessageCategory .WEB_SEARCH : "handle_web_search" ,
59- MessageCategory .ONBOARDING : "handle_onboarding" ,
60- MessageCategory .TECHNICAL_SUPPORT : "handle_technical_support" ,
61- MessageCategory .COMMUNITY_ENGAGEMENT : "handle_technical_support" ,
62- MessageCategory .DOCUMENTATION : "handle_technical_support" ,
63- MessageCategory .BUG_REPORT : "handle_technical_support" ,
64- MessageCategory .FEATURE_REQUEST : "handle_technical_support" ,
65- MessageCategory .NOT_DEVREL : "handle_technical_support"
66+ "web_search" : "web_search_tool" ,
67+ "faq_handler" : "faq_handler_tool" ,
68+ "onboarding" : "onboarding_tool" ,
69+ "github_toolkit" : "github_toolkit_tool" ,
70+ "complete" : "generate_response"
6671 }
6772 )
6873
69- # All handlers lead to response generation
70- for node in ["handle_faq " , "handle_web_search " , "handle_technical_support " , "handle_onboarding " ]:
71- workflow .add_edge (node , "generate_response " )
74+ # All tools return to supervisor
75+ for tool in ["web_search_tool " , "faq_handler_tool " , "onboarding_tool " , "github_toolkit_tool " ]:
76+ workflow .add_edge (tool , "react_supervisor " )
7277
7378 workflow .add_edge ("generate_response" , "check_summarization" )
7479
75- # Conditional edge for summarization
80+ # Summarization routing
7681 workflow .add_conditional_edges (
7782 "check_summarization" ,
7883 self ._should_summarize ,
@@ -82,42 +87,11 @@ def _build_graph(self):
8287 }
8388 )
8489
85- # End after summarization
8690 workflow .add_edge ("summarize_conversation" , END )
8791
88- # Set entry point
89- workflow .set_entry_point ("gather_context" )
90-
91- # Compile with InMemorySaver checkpointer
92+ # Compile with checkpointer
9293 self .graph = workflow .compile (checkpointer = self .checkpointer )
9394
94- def _route_to_handler (self , state : AgentState ) -> str :
95- """Route to the appropriate handler based on intent"""
96- classification = state .context .get ("classification" , {})
97- intent = classification .get ("category" )
98-
99- if isinstance (intent , str ):
100- try :
101- intent = MessageCategory (intent .lower ())
102- except ValueError :
103- logger .warning (f"Unknown intent string '{ intent } ', defaulting to TECHNICAL_SUPPORT" )
104- intent = MessageCategory .TECHNICAL_SUPPORT
105-
106- logger .info (f"Routing based on intent: { intent } for session { state .session_id } " )
107-
108- # Mapping from MessageCategory enum to string keys used in add_conditional_edges
109- if intent in [MessageCategory .FAQ , MessageCategory .WEB_SEARCH ,
110- MessageCategory .ONBOARDING , MessageCategory .TECHNICAL_SUPPORT ,
111- MessageCategory .COMMUNITY_ENGAGEMENT , MessageCategory .DOCUMENTATION ,
112- MessageCategory .BUG_REPORT , MessageCategory .FEATURE_REQUEST ,
113- MessageCategory .NOT_DEVREL ]:
114- logger .info (f"Routing to handler for: { intent } " )
115- return intent
116-
117- # Later to be changed to handle anomalies
118- logger .info (f"Unknown intent '{ intent } ', routing to technical support" )
119- return MessageCategory .TECHNICAL_SUPPORT
120-
12195 def _should_summarize (self , state : AgentState ) -> str :
12296 """Determine if conversation should be summarized"""
12397 if state .summarization_needed :
0 commit comments