Spaces:
Running
Running
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() |