LiamKhoaLe commited on
Commit
8bafa0f
Β·
1 Parent(s): 0e45c9f

Upd agent mcp fallback

Browse files
Files changed (1) hide show
  1. app.py +70 -27
app.py CHANGED
@@ -277,25 +277,36 @@ async def get_mcp_session():
277
  session = ClientSession(read, write)
278
  await session.__aenter__()
279
 
280
- # Wait longer for the server to fully initialize
281
  # The server needs time to start up and be ready
282
- await asyncio.sleep(1.0)
 
283
 
284
  # Verify the session works by listing tools with retries
285
- max_init_retries = 5
 
286
  for init_attempt in range(max_init_retries):
287
  try:
288
  tools = await session.list_tools()
289
- if tools and hasattr(tools, 'tools'):
290
- logger.info(f"MCP server initialized with {len(tools.tools)} tools: {[t.name for t in tools.tools]}")
 
291
  break
292
  except Exception as e:
293
  if init_attempt < max_init_retries - 1:
294
- logger.debug(f"Initialization attempt {init_attempt + 1}/{max_init_retries} failed, retrying...")
295
- await asyncio.sleep(0.5 * (init_attempt + 1))
 
296
  else:
297
- logger.warning(f"Could not list tools after {max_init_retries} attempts: {e}")
298
- # Continue anyway, might work on first actual call
 
 
 
 
 
 
 
299
 
300
  # Store both the session and stdio context to keep them alive
301
  global_mcp_session = session
@@ -323,18 +334,23 @@ async def call_agent(user_prompt: str, system_prompt: str = None, files: list =
323
  return ""
324
 
325
  # Retry listing tools if it fails the first time
326
- max_retries = 3
 
327
  tools = None
328
  for attempt in range(max_retries):
329
  try:
330
  tools = await session.list_tools()
331
- break
 
 
 
332
  except Exception as e:
333
  if attempt < max_retries - 1:
334
- logger.debug(f"Failed to list tools (attempt {attempt + 1}/{max_retries}), retrying...")
335
- await asyncio.sleep(0.5 * (attempt + 1)) # Exponential backoff
 
336
  else:
337
- logger.error(f"Failed to list MCP tools after {max_retries} attempts: {e}")
338
  return ""
339
 
340
  if not tools or not hasattr(tools, 'tools'):
@@ -366,7 +382,7 @@ async def call_agent(user_prompt: str, system_prompt: str = None, files: list =
366
  if temperature is not None:
367
  arguments["temperature"] = temperature
368
 
369
- logger.debug(f"Calling Gemini MCP tool '{generate_tool.name}' with arguments: {list(arguments.keys())}")
370
  result = await session.call_tool(generate_tool.name, arguments=arguments)
371
 
372
  # Parse result
@@ -793,11 +809,13 @@ async def search_web_mcp(query: str, max_results: int = 5) -> list:
793
  # First try to use a dedicated web search MCP tool (like DuckDuckGo MCP server)
794
  results = await search_web_mcp_tool(query, max_results)
795
  if results:
 
796
  return results
797
 
798
  # If no web search MCP tool available, use direct search (ddgs)
799
- # This is the correct approach - Gemini MCP cannot search the web
800
- logger.info("No web search MCP tool found, using direct DuckDuckGo search")
 
801
  return search_web_fallback(query, max_results)
802
 
803
  def search_web_fallback(query: str, max_results: int = 5) -> list:
@@ -1034,9 +1052,10 @@ def autonomous_reasoning(query: str, history: list) -> dict:
1034
  """
1035
  Autonomous reasoning: Analyze query complexity, intent, and information needs.
1036
  Returns reasoning analysis with query type, complexity, and required information sources.
 
1037
  """
1038
  if not MCP_AVAILABLE:
1039
- logger.warning("Gemini MCP not available for reasoning, using fallback")
1040
  # Fallback reasoning
1041
  return {
1042
  "query_type": "general_info",
@@ -1048,19 +1067,35 @@ def autonomous_reasoning(query: str, history: list) -> dict:
1048
  }
1049
 
1050
  try:
 
1051
  loop = asyncio.get_event_loop()
1052
  if loop.is_running():
1053
  try:
1054
  import nest_asyncio
1055
- return nest_asyncio.run(autonomous_reasoning_gemini(query))
 
 
 
 
 
 
1056
  except Exception as e:
1057
- logger.error(f"Error in nested async reasoning: {e}")
1058
  else:
1059
- return loop.run_until_complete(autonomous_reasoning_gemini(query))
 
 
 
 
 
 
1060
  except Exception as e:
1061
- logger.error(f"Gemini MCP reasoning error: {e}")
 
 
1062
 
1063
- # Fallback reasoning
 
1064
  return {
1065
  "query_type": "general_info",
1066
  "complexity": "moderate",
@@ -1559,16 +1594,24 @@ def stream_chat(
1559
  web_sources = []
1560
  web_urls = [] # Store URLs for citations
1561
  if final_use_web_search:
1562
- logger.info("🌐 Performing web search (MCP or direct ddgs)...")
1563
  web_results = search_web(message, max_results=5)
1564
  if web_results:
1565
- logger.info(f"πŸ“Š Summarizing {len(web_results)} web search results using Gemini MCP...")
1566
  web_summary = summarize_web_content(web_results, message)
1567
- web_context = f"\n\nAdditional Web Sources:\n{web_summary}"
 
 
 
 
 
 
1568
  web_sources = [r['title'] for r in web_results[:3]]
1569
  # Extract unique URLs for citations
1570
  web_urls = [r.get('url', '') for r in web_results if r.get('url')]
1571
- logger.info(f"Web search completed, found {len(web_results)} results, summarized with Gemini MCP")
 
 
1572
 
1573
  # Build final context
1574
  context_parts = []
 
277
  session = ClientSession(read, write)
278
  await session.__aenter__()
279
 
280
+ # Wait for the server to fully initialize
281
  # The server needs time to start up and be ready
282
+ # Increased wait time and retries for better reliability
283
+ await asyncio.sleep(5.0)
284
 
285
  # Verify the session works by listing tools with retries
286
+ max_init_retries = 10
287
+ tools_listed = False
288
  for init_attempt in range(max_init_retries):
289
  try:
290
  tools = await session.list_tools()
291
+ if tools and hasattr(tools, 'tools') and len(tools.tools) > 0:
292
+ logger.info(f"βœ… MCP server initialized with {len(tools.tools)} tools: {[t.name for t in tools.tools]}")
293
+ tools_listed = True
294
  break
295
  except Exception as e:
296
  if init_attempt < max_init_retries - 1:
297
+ wait_time = 1.0 * (init_attempt + 1) # Progressive wait: 1s, 2s, 3s...
298
+ logger.debug(f"Initialization attempt {init_attempt + 1}/{max_init_retries} failed, waiting {wait_time}s before retry...")
299
+ await asyncio.sleep(wait_time)
300
  else:
301
+ logger.error(f"❌ Could not list tools after {max_init_retries} attempts: {e}")
302
+ # Don't continue - if we can't list tools, the session is not usable
303
+ await session.__aexit__(None, None, None)
304
+ await stdio_ctx.__aexit__(None, None, None)
305
+ return None
306
+
307
+ if not tools_listed:
308
+ logger.error("MCP server failed to initialize - tools could not be listed")
309
+ return None
310
 
311
  # Store both the session and stdio context to keep them alive
312
  global_mcp_session = session
 
334
  return ""
335
 
336
  # Retry listing tools if it fails the first time
337
+ # Use more retries and longer waits since MCP server might need time
338
+ max_retries = 5
339
  tools = None
340
  for attempt in range(max_retries):
341
  try:
342
  tools = await session.list_tools()
343
+ if tools and hasattr(tools, 'tools') and len(tools.tools) > 0:
344
+ break
345
+ else:
346
+ raise ValueError("Empty tools list")
347
  except Exception as e:
348
  if attempt < max_retries - 1:
349
+ wait_time = 1.0 * (attempt + 1) # Progressive wait
350
+ logger.debug(f"Failed to list tools (attempt {attempt + 1}/{max_retries}), waiting {wait_time}s...")
351
+ await asyncio.sleep(wait_time)
352
  else:
353
+ logger.error(f"❌ Failed to list MCP tools after {max_retries} attempts: {e}")
354
  return ""
355
 
356
  if not tools or not hasattr(tools, 'tools'):
 
382
  if temperature is not None:
383
  arguments["temperature"] = temperature
384
 
385
+ logger.info(f"πŸ”§ Calling Gemini MCP tool '{generate_tool.name}' for: {user_prompt[:100]}...")
386
  result = await session.call_tool(generate_tool.name, arguments=arguments)
387
 
388
  # Parse result
 
809
  # First try to use a dedicated web search MCP tool (like DuckDuckGo MCP server)
810
  results = await search_web_mcp_tool(query, max_results)
811
  if results:
812
+ logger.info(f"βœ… Web search via MCP tool: found {len(results)} results")
813
  return results
814
 
815
  # If no web search MCP tool available, use direct search (ddgs)
816
+ # Note: Gemini MCP doesn't have web search capability, so we use direct API
817
+ # The results will then be summarized using Gemini MCP
818
+ logger.info("ℹ️ No web search MCP tool found, using direct DuckDuckGo search (results will be summarized with Gemini MCP)")
819
  return search_web_fallback(query, max_results)
820
 
821
  def search_web_fallback(query: str, max_results: int = 5) -> list:
 
1052
  """
1053
  Autonomous reasoning: Analyze query complexity, intent, and information needs.
1054
  Returns reasoning analysis with query type, complexity, and required information sources.
1055
+ Uses Gemini MCP for reasoning.
1056
  """
1057
  if not MCP_AVAILABLE:
1058
+ logger.warning("⚠️ Gemini MCP not available for reasoning, using fallback")
1059
  # Fallback reasoning
1060
  return {
1061
  "query_type": "general_info",
 
1067
  }
1068
 
1069
  try:
1070
+ logger.info("πŸ€” Using Gemini MCP for autonomous reasoning...")
1071
  loop = asyncio.get_event_loop()
1072
  if loop.is_running():
1073
  try:
1074
  import nest_asyncio
1075
+ reasoning = nest_asyncio.run(autonomous_reasoning_gemini(query))
1076
+ if reasoning and reasoning.get("query_type") != "general_info": # Check if we got real reasoning
1077
+ logger.info(f"βœ… Gemini MCP reasoning successful: {reasoning.get('query_type')}, complexity: {reasoning.get('complexity')}")
1078
+ return reasoning
1079
+ else:
1080
+ logger.warning("⚠️ Gemini MCP returned fallback reasoning, using it anyway")
1081
+ return reasoning
1082
  except Exception as e:
1083
+ logger.error(f"❌ Error in nested async reasoning: {e}")
1084
  else:
1085
+ reasoning = loop.run_until_complete(autonomous_reasoning_gemini(query))
1086
+ if reasoning and reasoning.get("query_type") != "general_info":
1087
+ logger.info(f"βœ… Gemini MCP reasoning successful: {reasoning.get('query_type')}, complexity: {reasoning.get('complexity')}")
1088
+ return reasoning
1089
+ else:
1090
+ logger.warning("⚠️ Gemini MCP returned fallback reasoning, using it anyway")
1091
+ return reasoning
1092
  except Exception as e:
1093
+ logger.error(f"❌ Gemini MCP reasoning error: {e}")
1094
+ import traceback
1095
+ logger.debug(traceback.format_exc())
1096
 
1097
+ # Fallback reasoning only if all attempts failed
1098
+ logger.warning("⚠️ Falling back to default reasoning")
1099
  return {
1100
  "query_type": "general_info",
1101
  "complexity": "moderate",
 
1594
  web_sources = []
1595
  web_urls = [] # Store URLs for citations
1596
  if final_use_web_search:
1597
+ logger.info("🌐 Performing web search...")
1598
  web_results = search_web(message, max_results=5)
1599
  if web_results:
1600
+ logger.info(f"πŸ“Š Found {len(web_results)} web search results, now summarizing with Gemini MCP...")
1601
  web_summary = summarize_web_content(web_results, message)
1602
+ if web_summary and len(web_summary) > 50: # Check if we got a real summary
1603
+ logger.info(f"βœ… Gemini MCP summarization successful ({len(web_summary)} chars)")
1604
+ web_context = f"\n\nAdditional Web Sources:\n{web_summary}"
1605
+ else:
1606
+ logger.warning("⚠️ Gemini MCP summarization failed or returned empty, using raw results")
1607
+ # Fallback: use first result's content
1608
+ web_context = f"\n\nAdditional Web Sources:\n{web_results[0].get('content', '')[:500]}"
1609
  web_sources = [r['title'] for r in web_results[:3]]
1610
  # Extract unique URLs for citations
1611
  web_urls = [r.get('url', '') for r in web_results if r.get('url')]
1612
+ logger.info(f"βœ… Web search completed: {len(web_results)} results, summarized with Gemini MCP")
1613
+ else:
1614
+ logger.warning("⚠️ Web search returned no results")
1615
 
1616
  # Build final context
1617
  context_parts = []