Skip to content

Commit a0c8bdd

Browse files
committed
feat(prompts_sample): fixed minor issues from reviews
1 parent cea65fc commit a0c8bdd

File tree

6 files changed

+112
-98
lines changed

6 files changed

+112
-98
lines changed

samples/mcp-refactoring-assistant/.agent/SDK_REFERENCE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -398,7 +398,7 @@ Guardrails service
398398

399399
```python
400400
# Validate input text using the provided guardrail.
401-
sdk.guardrails.evaluate_guardrail(input_data: str | dict[str, Any], guardrail: uipath.platform.guardrails.guardrails.BuiltInValidatorGuardrail) -> uipath.core.guardrails.guardrails.GuardrailValidationResult
401+
sdk.guardrails.evaluate_guardrail(input_data: str | dict[str, Any], guardrail: Annotated[Union[uipath.platform.guardrails.guardrails.CustomGuardrail, uipath.platform.guardrails.guardrails.BuiltInValidatorGuardrail], FieldInfo(annotation=NoneType, required=True, discriminator='guardrail_type')]) -> uipath.platform.guardrails.guardrails.GuardrailValidationResult
402402

403403
```
404404

samples/mcp-refactoring-assistant/entry-points.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"entryPoints": [
55
{
66
"filePath": "agent",
7-
"uniqueId": "426f3cb2-ac10-4969-840e-399932250e3a",
7+
"uniqueId": "d016126e-57b7-4493-93de-d834c86b9b70",
88
"type": "agent",
99
"input": {
1010
"type": "object",

samples/mcp-refactoring-assistant/graph.py

Lines changed: 53 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -4,48 +4,55 @@
44
import json
55
import sys
66
from pathlib import Path
7-
from typing import Any, Optional
87

98
from langchain.agents import create_agent
10-
from langchain_core.messages import HumanMessage
9+
from langchain_core.messages import HumanMessage, SystemMessage
1110
from langchain_mcp_adapters.client import MultiServerMCPClient
1211
from langgraph.graph import END, START, MessagesState, StateGraph
1312
from pydantic import BaseModel
13+
1414
from uipath_langchain.chat import UiPathChat
1515

1616
model = UiPathChat(model="gpt-4o-2024-08-06", temperature=0.7)
1717

1818
server_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

96103
async 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

150147
async 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

180177
graph = builder.compile()
181178

179+

samples/mcp-refactoring-assistant/server.py

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
from typing import Any, Dict, List
2-
31
from mcp.server.fastmcp import FastMCP
42
from mcp.server.fastmcp.prompts.base import Message
53
from prompts import (extract_method, improve_naming, remove_duplication,
@@ -11,7 +9,7 @@
119

1210
# Register Code Analysis Tools
1311
@mcp.tool()
14-
def analyze_code_complexity(code: str) -> Dict[str, Any]:
12+
def analyze_code_complexity(code: str) -> dict:
1513
"""Analyze Python code complexity using heuristics.
1614
1715
Args:
@@ -24,7 +22,7 @@ def analyze_code_complexity(code: str) -> Dict[str, Any]:
2422

2523

2624
@mcp.tool()
27-
def detect_code_smells(code: str) -> Dict[str, Any]:
25+
def detect_code_smells(code: str) -> dict:
2826
"""Detect common code smells in Python code.
2927
3028
Args:
@@ -40,9 +38,9 @@ def detect_code_smells(code: str) -> Dict[str, Any]:
4038
def get_refactoring_guide(
4139
issue_type: str,
4240
code: str = "",
43-
complexity_info: Dict[str, Any] = None,
44-
smells_info: Dict[str, Any] = None
45-
) -> Dict[str, Any]:
41+
complexity_info: dict | None = None,
42+
smells_info: dict | None = None
43+
) -> dict:
4644
"""Get guidance on which refactoring prompt to use for a specific issue.
4745
4846
Args:
@@ -65,7 +63,7 @@ def get_refactoring_guide(
6563

6664
# Register Refactoring Prompts
6765
@mcp.prompt()
68-
def extract_method_prompt(code: str, target_lines: str = "auto") -> List[Message]:
66+
def extract_method_prompt(code: str, target_lines: str = "auto") -> list[Message]:
6967
"""Guide for extracting a method from complex code.
7068
7169
Args:
@@ -79,7 +77,7 @@ def extract_method_prompt(code: str, target_lines: str = "auto") -> List[Message
7977

8078

8179
@mcp.prompt()
82-
def simplify_conditional_prompt(code: str, pattern: str = "guard_clause") -> List[Message]:
80+
def simplify_conditional_prompt(code: str, pattern: str = "guard_clause") -> list[Message]:
8381
"""Guide for simplifying complex conditional logic.
8482
8583
Args:
@@ -93,7 +91,7 @@ def simplify_conditional_prompt(code: str, pattern: str = "guard_clause") -> Lis
9391

9492

9593
@mcp.prompt()
96-
def remove_duplication_prompt(code: str, duplicate_blocks: str) -> List[Message]:
94+
def remove_duplication_prompt(code: str, duplicate_blocks: str) -> list[Message]:
9795
"""Guide for removing code duplication.
9896
9997
Args:
@@ -107,7 +105,7 @@ def remove_duplication_prompt(code: str, duplicate_blocks: str) -> List[Message]
107105

108106

109107
@mcp.prompt()
110-
def improve_naming_prompt(code: str, symbols: str, context: str = "") -> List[Message]:
108+
def improve_naming_prompt(code: str, symbols: str, context: str = "") -> list[Message]:
111109
"""Guide for improving variable and function names.
112110
113111
Args:

samples/mcp-refactoring-assistant/tools/code_analysis.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
"""Code analysis tools for detecting complexity and code smells."""
22

33
import re
4-
from typing import Any, Dict
54

65

7-
def analyze_code_complexity(code: str) -> Dict[str, Any]:
6+
def analyze_code_complexity(code: str) -> dict:
87
"""Analyze Python code complexity using heuristics.
98
109
Args:
@@ -64,7 +63,7 @@ def analyze_code_complexity(code: str) -> Dict[str, Any]:
6463
}
6564

6665

67-
def detect_code_smells(code: str) -> Dict[str, Any]:
66+
def detect_code_smells(code: str) -> dict:
6867
"""Detect common code smells in Python code.
6968
7069
Args:

samples/mcp-refactoring-assistant/tools/refactoring_guide.py

Lines changed: 46 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
1-
"""Refactoring guide tool that maps code issues to refactoring prompts."""
2-
3-
from typing import Any, Dict, Optional
1+
"""Refactoring guide tool that maps code issues to refactoring prompts."""
42

53

64
def get_refactoring_guide(
75
issue_type: str,
86
code: str = "",
9-
complexity_info: Optional[Dict[str, Any]] = None,
10-
smells_info: Optional[Dict[str, Any]] = None
11-
) -> Dict[str, Any]:
7+
complexity_info: dict | None = None,
8+
smells_info: dict | None = None
9+
) -> dict:
1210
"""Get guidance on which refactoring prompt to use for a specific issue.
1311
1412
@@ -101,47 +99,68 @@ def get_refactoring_guide(
10199

102100
# Construct arguments dict based on prompt requirements
103101
if prompt_name == "extract_method_prompt":
104-
arguments = {
105-
"code": code,
106-
"target_lines": "auto" # Agent can override if needed
102+
return {
103+
"prompt_name": prompt_name,
104+
"arguments": {
105+
"code": code,
106+
"target_lines": "auto"
107+
},
108+
"description": guide["description"],
109+
"priority": guide["priority"]
107110
}
108-
elif prompt_name == "simplify_conditional_prompt":
111+
112+
if prompt_name == "simplify_conditional_prompt":
109113
# Determine pattern based on issue type
110114
pattern = "guard_clause" if issue_type == "deep_nesting" else "early_return"
111-
arguments = {
112-
"code": code,
113-
"pattern": pattern
115+
return {
116+
"prompt_name": prompt_name,
117+
"arguments": {
118+
"code": code,
119+
"pattern": pattern
120+
},
121+
"description": guide["description"],
122+
"priority": guide["priority"]
114123
}
115-
elif prompt_name == "remove_duplication_prompt":
124+
125+
if prompt_name == "remove_duplication_prompt":
116126
# Extract duplicate info from smells_info if available
117127
duplicate_blocks = "auto-detected duplicates"
118128
if smells_info and "duplicate_code" in smells_info.get("smells", []):
119129
duplicate_blocks = "See code analysis for duplicate blocks"
120-
arguments = {
121-
"code": code,
122-
"duplicate_blocks": duplicate_blocks
130+
return {
131+
"prompt_name": prompt_name,
132+
"arguments": {
133+
"code": code,
134+
"duplicate_blocks": duplicate_blocks
135+
},
136+
"description": guide["description"],
137+
"priority": guide["priority"]
123138
}
124-
elif prompt_name == "improve_naming_prompt":
139+
140+
if prompt_name == "improve_naming_prompt":
125141
# Extract poor naming symbols from smells_info
126142
symbols = "x,y,z" # Default, agent can override
127143
if smells_info:
128144
poor_names = [s.get("symbol", "") for s in smells_info.get("smells", [])
129145
if s.get("type") == "poor_naming"]
130146
if poor_names:
131147
symbols = ",".join(poor_names)
132-
arguments = {
133-
"code": code,
134-
"symbols": symbols,
135-
"context": "" # Optional, agent can provide
148+
return {
149+
"prompt_name": prompt_name,
150+
"arguments": {
151+
"code": code,
152+
"symbols": symbols,
153+
"context": "" # Optional, agent can provide
154+
},
155+
"description": guide["description"],
156+
"priority": guide["priority"]
136157
}
137-
else:
138-
# Fallback: just provide code
139-
arguments = {"code": code}
140158

141-
# Return structured response ready for client.get_prompt()
159+
# Fallback: just provide code
142160
return {
143161
"prompt_name": prompt_name,
144-
"arguments": arguments,
162+
"arguments": {"code": code},
145163
"description": guide["description"],
146164
"priority": guide["priority"]
147165
}
166+

0 commit comments

Comments
 (0)