File size: 9,011 Bytes
4c95634
 
 
99dcb22
 
0b184f7
 
957adf6
0b184f7
 
 
957adf6
0b184f7
 
 
 
99dcb22
0b184f7
4c95634
99dcb22
 
 
 
 
 
 
 
 
0b184f7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4c95634
0b184f7
4c95634
a3f7cf5
99dcb22
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4c95634
b490652
4c95634
99dcb22
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b490652
4c95634
 
99dcb22
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4c95634
99dcb22
 
4c95634
0b184f7
 
 
 
 
 
 
 
 
99dcb22
 
0b184f7
 
99dcb22
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0b184f7
 
99dcb22
 
 
 
 
 
 
 
 
 
 
0b184f7
99dcb22
 
 
 
 
 
 
 
 
4c95634
 
 
 
99dcb22
 
4c95634
 
99dcb22
 
 
 
 
4c95634
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
import gradio as gr
import requests
from smolagents import CodeAgent
import json
import re
import logging
from tenacity import retry, stop_after_attempt, wait_exponential

# Configure logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

# Use lowercase and verify your exact Hugging Face Space URL
HF_SPACE_URL = "https://manavraj-troubleshoot-mcp.hf.space"  # Note: Changed underscores to hyphens

@retry(stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=4, max=10))
def call_mcp_server(message, tool_type="knowledge_base"):
    """Call your MCP server with retries and proper error handling"""
    try:
        # Determine which tool to use based on tool_type
        fn_index_map = {
            "knowledge_base": 0,
            "web_search": 1, 
            "formatter": 2
        }
        
        fn_index = fn_index_map.get(tool_type, 0)
        
        logger.info(f"Calling MCP server with message: {message[:50]}...")
        
        response = requests.post(
            f"{HF_SPACE_URL}/api/predict",
            json={"data": [message], "fn_index": fn_index},
            verify=False,  # Temporarily disable SSL verification
            timeout=30
        )
        
        if response.status_code != 200:
            raise Exception(f"MCP server returned {response.status_code}")
            
        data = response.json()
        if not isinstance(data, dict) or 'data' not in data:
            raise Exception("Invalid MCP response format")
            
        return data['data'][0]
        
    except Exception as e:
        logger.error(f"MCP server call failed: {str(e)}")
        return f"MCP server error: {str(e)}"

def extract_thought_action_observation(response):
    """Extract and format the thought-action-observation cycle from agent response"""
    sections = {
        'thought': '',
        'action': '',
        'observation': ''
    }
    
    # Try to extract sections using regex
    thought_match = re.search(r'(?:THOUGHT|Thought):\s*(.*?)(?=(?:ACTION|Action|OBSERVATION|Observation|$))', response, re.DOTALL | re.IGNORECASE)
    action_match = re.search(r'(?:ACTION|Action):\s*(.*?)(?=(?:OBSERVATION|Observation|FINAL|Final|$))', response, re.DOTALL | re.IGNORECASE)
    observation_match = re.search(r'(?:OBSERVATION|Observation):\s*(.*?)(?=(?:FINAL|Final|$))', response, re.DOTALL | re.IGNORECASE)
    
    if thought_match:
        sections['thought'] = thought_match.group(1).strip()
    if action_match:
        sections['action'] = action_match.group(1).strip()
    if observation_match:
        sections['observation'] = observation_match.group(1).strip()
    
    return sections

# Initialize CodeAgent with enhanced system prompt
agent = CodeAgent(
    tools=[],
    model="microsoft/DialoGPT-medium",
    system_prompt="""You are a Technical Support AI Agent that uses a structured Thought-Action-Observation cycle to solve user queries effectively.
WORKFLOW:
For every user query, you MUST follow this exact structure:
THOUGHT: Analyze the user's problem and decide what action to take
- Identify the type of issue (technical problem, information request, formatting need)
- Determine which MCP server tool would be most appropriate
- Consider what information you need to provide a complete answer
ACTION: Specify exactly what action you will take
- "search_knowledge_base" for known technical issues (wifi, screen, hardware problems)
- "web_search" for current information, news, or unknown topics
- "format_response" for organizing or structuring information
- "direct_response" if you can answer without tools
OBSERVATION: Analyze the results and determine next steps
- Evaluate if the action provided sufficient information
- Identify if additional actions are needed
- Note any gaps in the information
FINAL RESPONSE: Provide a clear, helpful answer to the user
EXAMPLE:
User: "My wifi keeps disconnecting"
THOUGHT: The user has a wifi connectivity issue. This is a common technical problem that likely has solutions in our knowledge base. I should search the knowledge base first for wifi-related solutions.
ACTION: search_knowledge_base with query "wifi disconnecting problem"
OBSERVATION: The knowledge base provided basic wifi troubleshooting steps. These steps are helpful but I should also check for any recent wifi issues or advanced solutions via web search to provide comprehensive help.
FINAL RESPONSE: [Provide complete solution combining knowledge base and any additional insights]
Remember:
- Always use the THOUGHT-ACTION-OBSERVATION-FINAL RESPONSE structure
- Be specific about which tool you're using and why
- Provide actionable, clear solutions
- If one action isn't sufficient, explain what additional actions you'll take
{{managed_agents_descriptions}}
{{authorized_imports}}"""
)

def determine_tool_type(message):
    """Determine which MCP tool to use based on user message"""
    message_lower = message.lower()
    
    # Technical issues - use knowledge base
    tech_keywords = ["wifi", "screen", "computer", "laptop", "error", "problem", "issue", "broken", "not working"]
    if any(keyword in message_lower for keyword in tech_keywords):
        return "knowledge_base"
    
    # Search queries - use web search
    search_keywords = ["search", "find", "news", "latest", "current", "what is", "how to", "information about"]
    if any(keyword in message_lower for keyword in search_keywords):
        return "web_search"
    
    # Formatting requests - use formatter
    format_keywords = ["format", "organize", "list", "steps", "number"]
    if any(keyword in message_lower for keyword in format_keywords):
        return "formatter"
    
    # Default to knowledge base for technical support
    return "knowledge_base"

def chat_interface(message, history):
    """Enhanced chat interface with thought-action-observation cycle"""
    
    try:
        # Step 1: Let agent think about the problem
        thinking_prompt = f"""
        User Query: "{message}"
        
        Follow the THOUGHT-ACTION-OBSERVATION cycle:
        
        THOUGHT: Analyze this query and determine the best approach.
        """
        
        # Get agent's initial thought process
        agent_response = agent.run(thinking_prompt)
        if not isinstance(agent_response, str):
            raise ValueError("Agent returned non-string response")
        
        # Extract thought and determine action
        cycle_parts = extract_thought_action_observation(agent_response)
        
        # Determine tool type based on message content and agent's thought
        tool_type = determine_tool_type(message)
        
        # Step 2: Execute the action via MCP server
        mcp_response = call_mcp_server(message, tool_type)
        
        # Step 3: Let agent observe and provide final response
        final_prompt = f"""
        User Query: "{message}"
        
        THOUGHT: {cycle_parts.get('thought', 'Analyzing user query for appropriate technical support response.')}
        
        ACTION: Used {tool_type} tool with query: "{message}"
        
        OBSERVATION: The MCP server returned: "{mcp_response}"
        
        FINAL RESPONSE: Based on the observation, provide a complete, helpful response to the user. If the MCP server response is insufficient, explain what additional steps might be needed.
        """
        
        final_response = agent.run(final_prompt)
        if not isinstance(final_response, str):
            final_response = str(final_response)
        
        # Format the response to show the thinking process
        formatted_response = f"""πŸ€” **THOUGHT:** {cycle_parts.get('thought', 'Analyzing your query...')}
⚑ **ACTION:** Used {tool_type.replace('_', ' ')} tool
πŸ‘οΈ **OBSERVATION:** {mcp_response[:200]}{'...' if len(mcp_response) > 200 else ''}
βœ… **SOLUTION:**
{final_response}"""
        
        return formatted_response
        
    except Exception as e:
        logger.error(f"Error in chat interface: {str(e)}")
        # Fallback to direct MCP response with simple structure
        tool_type = determine_tool_type(message)
        mcp_response = call_mcp_server(message, tool_type)
        
        return f"""πŸ€” **THOUGHT:** You have a {tool_type.replace('_', ' ')} related query.
⚑ **ACTION:** Consulted the MCP server using {tool_type} tool.
πŸ‘οΈ **OBSERVATION:** Found relevant information.
βœ… **SOLUTION:**
{mcp_response}"""

# Create Gradio interface
demo = gr.ChatInterface(
    fn=chat_interface,
    title="πŸ”§ MCP Technical Support Agent (TAO Cycle)", 
    description="Technical support powered by MCP server tools using Thought-Action-Observation methodology",
    examples=[
        "I have a wifi connection problem",
        "My screen keeps flickering", 
        "Search for latest cybersecurity news",
        "Format these steps: Install driver. Restart computer. Test connection"
    ],
    chatbot=gr.Chatbot(height=600)
)

if __name__ == "__main__":
    demo.launch()