44import json
55import sys
66from pathlib import Path
7- from typing import Any , Optional
87
98from langchain .agents import create_agent
10- from langchain_core .messages import HumanMessage
9+ from langchain_core .messages import HumanMessage , SystemMessage
1110from langchain_mcp_adapters .client import MultiServerMCPClient
1211from langgraph .graph import END , START , MessagesState , StateGraph
1312from pydantic import BaseModel
13+
1414from uipath_langchain .chat import UiPathChat
1515
1616model = UiPathChat (model = "gpt-4o-2024-08-06" , temperature = 0.7 )
1717
1818server_path = Path (__file__ ).parent / "server.py"
1919
20- _client = None
21- _react_agent = None
20+ manager = None
21+
22+
23+ class MCPManager :
24+ def __init__ (self ):
25+ self ._client : MultiServerMCPClient | None = None
26+ self ._react_agent = None
27+
28+ async def get_client (self ):
29+ if self ._client is None :
30+ self ._client = MultiServerMCPClient ({
31+ "code-refactoring" : {
32+ "command" : sys .executable ,
33+ "args" : [str (server_path )],
34+ "transport" : "stdio" ,
35+ },
36+ })
37+ return self ._client
2238
39+ async def get_agent (self ):
40+ if self ._react_agent is None :
41+ client = await self .get_client ()
42+ tools = await client .get_tools ()
2343
24- async def _get_client ():
25- """Get or initialize the MCP client."""
26- global _client
27- if _client is None :
28- _client = MultiServerMCPClient ({
29- "code-refactoring" : {
30- "command" : sys .executable ,
31- "args" : [str (server_path )],
32- "transport" : "stdio" ,
33- },
34- })
35- return _client
44+ model_with_tools = model .bind_tools (
45+ tools ,
46+ tool_choice = {"type" : "function" , "function" : {"name" : "get_refactoring_guide" }}
47+ )
48+ self ._react_agent = create_agent (model_with_tools , tools = tools )
49+ return self ._react_agent
3650
3751
38- async def _get_agent ():
39- """Get or initialize the ReAct agent with MCP tools."""
40- global _react_agent
41- if _react_agent is None :
42- client = await _get_client ()
43- tools = await client .get_tools ()
44- _react_agent = create_agent (model , tools = tools )
45- return _react_agent
52+ manager = MCPManager ()
4653
4754
48- def _try_parse_json (value : Any ) -> Optional [ dict ] :
55+ def _try_parse_json (value ) -> dict | None :
4956 """Robustly parse JSON from various formats (dict, str, list)."""
5057 if value is None :
5158 return None
@@ -95,27 +102,25 @@ class State(BaseModel):
95102
96103async def agent_node (state : State ) -> State :
97104 """Agent analyzes code and determines which prompt to use."""
98- react_agent = await _get_agent ()
99-
100- initial_msg = HumanMessage (
101- content = f"""You are a refactoring assistant.
102-
103- 1) Analyze this code using analyze_code_complexity
104- 2) Detect issues using detect_code_smells
105- 3) Call get_refactoring_guide with:
106- - issue_type: the main issue detected
107- - code: the code to refactor
108- - complexity_info: results from step 1
109- - smells_info: results from step 2
110-
111- The get_refactoring_guide tool will return {{\" prompt_name\" : \" ...\" , \" arguments\" : {{...}}}} ready for the next step.
112-
113- CODE:
114- { state .code }
115- """
105+ react_agent = await manager .get_agent ()
106+
107+ system_msg = SystemMessage (
108+ content = (
109+ "You are a refactoring assistant.\n \n "
110+ "1) Analyze this code using analyze_code_complexity\n "
111+ "2) Detect issues using detect_code_smells\n "
112+ "3) Call get_refactoring_guide with:\n "
113+ " - issue_type: the main issue detected\n "
114+ " - code: the code to refactor\n "
115+ " - complexity_info: results from step 1\n "
116+ " - smells_info: results from step 2\n \n "
117+ 'The get_refactoring_guide tool will return {"prompt_name": "...", "arguments": {...}} ready for the next step.'
118+ )
116119 )
117120
118- messages_state = MessagesState (messages = [initial_msg ])
121+ user_msg = HumanMessage (content = state .code )
122+
123+ messages_state = MessagesState (messages = [system_msg , user_msg ])
119124 result = await react_agent .ainvoke (messages_state )
120125
121126 prompt_name = ""
@@ -132,19 +137,11 @@ async def agent_node(state: State) -> State:
132137 break
133138
134139 if not prompt_name :
135- return State (
136- code = state .code ,
137- prompt_name = "" ,
138- prompt_arguments = {},
139- )
140+ return State (code = state .code , prompt_name = "" , prompt_arguments = {})
140141
141142 prompt_args .setdefault ('code' , state .code )
142143
143- return State (
144- code = state .code ,
145- prompt_name = prompt_name ,
146- prompt_arguments = prompt_args ,
147- )
144+ return State (code = state .code , prompt_name = prompt_name , prompt_arguments = prompt_args )
148145
149146
150147async def prompt_node (state : State ) -> Output :
@@ -155,7 +152,7 @@ async def prompt_node(state: State) -> Output:
155152 "Please ensure the agent analyzed the code and called get_refactoring_guide."
156153 )
157154
158- client = await _get_client ()
155+ client = await manager . get_client ()
159156
160157 prompt_messages = await client .get_prompt (
161158 "code-refactoring" ,
@@ -179,3 +176,4 @@ async def prompt_node(state: State) -> Output:
179176
180177graph = builder .compile ()
181178
179+
0 commit comments