Aasher commited on
Commit
2e96320
·
1 Parent(s): 4193809

feat: Refactor Chainlit UI to load and manage MCP servers dynamically with improved error handling and logging

Browse files
Files changed (1) hide show
  1. chainlit_ui.py +93 -37
chainlit_ui.py CHANGED
@@ -1,54 +1,110 @@
1
  import chainlit as cl
 
 
 
2
 
3
- from agents.mcp import MCPServerStdio
4
  from src.axiom.agent import AxiomAgent
 
 
5
 
6
- @cl.on_chat_start
 
 
 
 
 
 
 
 
 
7
  async def on_chat_start():
8
 
9
- server1 = MCPServerStdio(
10
- name="Documentation MCP",
11
- params={
12
- "command": "npx",
13
- "args": ['-y', '@upstash/context7-mcp@latest']
14
- },
15
- )
16
- server2 = MCPServerStdio(
17
- name="Sequential Thinking MCP",
18
- params={
19
- "command": "npx",
20
- "args": ['-y', '@modelcontextprotocol/server-sequential-thinking']
21
- },
22
- )
23
  try:
24
- # Manually enter the async context
25
- await server1.__aenter__()
26
- await server2.__aenter__()
27
- except Exception as e:
28
- cl.Message(content=f"Failed to start MCP Server: {e}").send()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29
  return
30
 
31
- agent = AxiomAgent(mcp_servers=[server1, server2])
32
- cl.user_session.set("axiom_agent", agent)
33
- cl.user_session.set("chat_history", [])
 
 
 
 
 
 
 
 
 
 
 
34
 
35
  @cl.on_message
36
  async def on_message(message: cl.Message):
37
- agent = cl.user_session.get("axiom_agent")
38
- chat_history = cl.user_session.get("chat_history")
 
39
  # Add user message to history
40
  chat_history.append({"role": "user", "content": message.content})
41
- cl.user_session.set("chat_history", chat_history)
42
-
43
- response_generator = agent.stream_agent(chat_history)
44
-
45
  full_response = ""
46
- msg = cl.Message(content="") # Initialize an empty message for streaming
47
 
48
- async for token in response_generator:
49
- full_response += token
50
- await msg.stream_token(token) # Stream tokens to the UI
51
- await msg.send() # Send the final message
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52
 
53
- chat_history.append({"role": "assistant", "content": full_response})
54
- cl.user_session.set("chat_history", chat_history) # Update chat history
 
1
  import chainlit as cl
2
+ import asyncio
3
+ import logging
4
+ from typing import Optional
5
 
 
6
  from src.axiom.agent import AxiomAgent
7
+ from src.axiom.config import settings, load_mcp_servers_from_config
8
+ from agents.mcp import MCPServer
9
 
10
+ # Configure logging for the UI module
11
+ logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
12
+ logger = logging.getLogger(__name__)
13
+
14
+ # --- Constants ---
15
+ SESSION_AGENT_KEY = "axiom_agent"
16
+ SESSION_HISTORY_KEY = "chat_history"
17
+ SESSION_MCP_SERVERS_KEY = "mcp_servers"
18
+
19
+ @cl.on_chat_start
20
  async def on_chat_start():
21
 
22
+ cl.user_session.set(SESSION_HISTORY_KEY, [])
23
+ cl.user_session.set(SESSION_MCP_SERVERS_KEY, [])
24
+
25
+ loaded_mcp_servers: list[MCPServer] = []
26
+ started_mcp_servers: list[MCPServer] = []
27
+
28
+ # 1. Load MCP Server configurations
 
 
 
 
 
 
 
29
  try:
30
+ loaded_mcp_servers = load_mcp_servers_from_config()
31
+
32
+ await cl.Message(content=f"Attempting to start {len(loaded_mcp_servers)} MCP server(s)...").send()
33
+
34
+ except FileNotFoundError:
35
+ await cl.ErrorMessage(content=f"Fatal Error: MCP configuration file not found at '{settings.mcp_config_path}'. Agent cannot start.").send()
36
+ return
37
+ except (ValueError, Exception) as e:
38
+ logger.exception("Failed to load MCP server configurations.")
39
+ await cl.ErrorMessage(content=f"Fatal Error: Could not load MCP configurations: {e}. Agent cannot start.").send()
40
+ return
41
+
42
+ # 2. Start the loaded MCP servers sequentially
43
+ if loaded_mcp_servers:
44
+ for server in loaded_mcp_servers:
45
+ try:
46
+ logger.info(f"Starting MCP Server: {server.name}...")
47
+ # The __aenter__ starts the server process
48
+ await server.__aenter__()
49
+ started_mcp_servers.append(server)
50
+ logger.info(f"MCP Server '{server.name}' started successfully.")
51
+ except Exception as e:
52
+ logger.error(f"Failed to start MCP Server '{server.name}': {e}")
53
+
54
+ # Store only the successfully started servers for later cleanup
55
+ cl.user_session.set(SESSION_MCP_SERVERS_KEY, started_mcp_servers)
56
+
57
+ # 3. Initialize the Axiom Agent
58
+ agent = AxiomAgent(mcp_servers=started_mcp_servers)
59
+ cl.user_session.set(SESSION_AGENT_KEY, agent)
60
+
61
+ async def cleanup_mcp_servers():
62
+ started_mcp_servers = cl.user_session.get(SESSION_MCP_SERVERS_KEY, [])
63
+ if not started_mcp_servers:
64
  return
65
 
66
+ logger.info(f"Cleaning up {len(started_mcp_servers)} MCP server(s)...")
67
+ for server in started_mcp_servers:
68
+ try:
69
+ await server.__aexit__(None, None, None)
70
+ logger.info(f"MCP Server '{server.name}' stopped.")
71
+ except Exception as e:
72
+ logger.error(f"Error stopping MCP Server '{server.name}': {e}", exc_info=True)
73
+
74
+ cl.user_session.set(SESSION_MCP_SERVERS_KEY, []) # Clear the list
75
+
76
+ @cl.on_chat_end
77
+ async def on_chat_end():
78
+ logger.info("Chat session ending.")
79
+ await cleanup_mcp_servers()
80
 
81
  @cl.on_message
82
  async def on_message(message: cl.Message):
83
+ agent = cl.user_session.get(SESSION_AGENT_KEY)
84
+ chat_history: list[dict] = cl.user_session.get(SESSION_HISTORY_KEY, [])
85
+
86
  # Add user message to history
87
  chat_history.append({"role": "user", "content": message.content})
88
+
89
+ msg = cl.Message(content="")
 
 
90
  full_response = ""
 
91
 
92
+ try:
93
+ response = agent.stream_agent(chat_history)
94
+ async for token in response:
95
+ full_response += token
96
+ await msg.stream_token(token) # Stream tokens to the UI
97
+ # Send the final message
98
+ await msg.send()
99
+ except Exception as e:
100
+ logger.exception(f"Error during agent response streaming: {e}")
101
+ # Update the message placeholder with an error
102
+ await msg.update(content=f"Sorry, an error occurred while processing your request.")
103
+ chat_history.append({"role": "assistant", "content": f"[Agent Error Occurred]"})
104
+ else:
105
+ # Only append successful response if no exception occurred
106
+ chat_history.append({"role": "assistant", "content": full_response})
107
+ finally:
108
+ # Update session history
109
+ cl.user_session.set(SESSION_HISTORY_KEY, chat_history)
110