refactor: enforce tool usage in API calls and enhance Discord message displays for search and scraping activities

This commit is contained in:
2025-08-25 23:16:08 +07:00
parent 8277e06a13
commit b51bcdc3a9
2 changed files with 159 additions and 3 deletions

View File

@@ -1146,6 +1146,7 @@ class MessageHandler:
# Add tools if using a supported model
if use_tools:
api_params["tools"] = get_tools_for_model()
api_params["tool_choice"] = "required" # Force the model to use tools when available
# Initialize variables to track tool responses
image_generation_used = False
@@ -1346,20 +1347,175 @@ class MessageHandler:
# Tool implementation methods
async def _google_search(self, args: Dict[str, Any]):
"""Perform a Google search"""
"""Perform a Google search with Discord display"""
try:
# Get the Discord message to display search activity
discord_message = self._get_discord_message_from_current_task()
# Extract search parameters
query = args.get('query', '')
num_results = args.get('num_results', 3)
# Import and call Google search
from src.utils.web_utils import google_search
result = await google_search(args)
# Display the search activity in Discord
if discord_message and query:
try:
# Parse the result to get structured data
import json
search_data = json.loads(result) if isinstance(result, str) else result
# Get the combined content
combined_content = search_data.get('combined_content', '')
# Check if content is too long for Discord message (3000 chars limit)
if len(combined_content) > 3000:
# Send content as file attachment
content_file = discord.File(
io.StringIO(combined_content),
filename="search_results.txt"
)
# Create display text without full content
search_display = "**🔍 Google Search**\n\n"
search_display += f"**📝 Query:** `{query}`\n"
search_display += f"**📊 Results:** {num_results} requested\n\n"
# Show search results with links
if 'results' in search_data and search_data['results']:
search_display += "**🔗 Found Links:**\n"
for i, item in enumerate(search_data['results'][:5], 1):
title = item.get('title', 'No title')[:80]
link = item.get('link', '')
used_mark = "" if item.get('used_for_content', False) else "📄"
search_display += f"{i}. {used_mark} [{title}]({link})\n"
search_display += "\n"
search_display += "**📄 Content:** *Attached as file (too long to display)*"
if 'error' in search_data:
search_display += f"\n**❌ Error:** {search_data['error'][:300]}"
# Send with file attachment
await discord_message.channel.send(search_display, file=content_file)
else:
# Use normal display for shorter content
search_display = "**🔍 Google Search**\n\n"
search_display += f"**📝 Query:** `{query}`\n"
search_display += f"**📊 Results:** {num_results} requested\n\n"
# Show search results with links
if 'results' in search_data and search_data['results']:
search_display += "**🔗 Found Links:**\n"
for i, item in enumerate(search_data['results'][:5], 1):
title = item.get('title', 'No title')[:80]
link = item.get('link', '')
used_mark = "" if item.get('used_for_content', False) else "📄"
search_display += f"{i}. {used_mark} [{title}]({link})\n"
search_display += "\n"
# Show content preview
if combined_content.strip():
search_display += "**📄 Content:**\n```\n"
search_display += combined_content
search_display += "\n```"
else:
search_display += "**📄 Content:** *(No content retrieved)*"
if 'error' in search_data:
search_display += f"\n**❌ Error:** {search_data['error']}"
# Send the search display to Discord
await discord_message.channel.send(search_display)
except Exception as e:
logging.error(f"Error displaying Google search: {str(e)}")
# Fallback: just send a simple message to prevent bot from getting stuck
try:
await discord_message.channel.send(f"🔍 Google search completed for: `{query}`")
except:
pass
return result
except Exception as e:
logging.error(f"Error in Google search: {str(e)}")
return json.dumps({"error": f"Google search failed: {str(e)}"})
async def _scrape_webpage(self, args: Dict[str, Any]):
"""Scrape a webpage"""
"""Scrape a webpage with Discord display"""
try:
# Get the Discord message to display scraping activity
discord_message = self._get_discord_message_from_current_task()
# Extract scraping parameters
url = args.get('url', '')
max_tokens = args.get('max_tokens', 4000)
# Import and call webpage scraper
from src.utils.web_utils import scrape_webpage
result = await scrape_webpage(args)
# Display the scraping activity in Discord
if discord_message and url:
try:
# Parse the result to get structured data
import json
scrape_data = json.loads(result) if isinstance(result, str) else result
# Get the scraped content
content = scrape_data.get('content', '') if scrape_data.get('success') else ''
# Check if content is too long for Discord message (3000 chars limit)
if len(content) > 3000:
# Send content as file attachment
content_file = discord.File(
io.StringIO(content),
filename="scraped_content.txt"
)
# Create display text without full content
scrape_display = "**🌐 Webpage Scraping**\n\n"
scrape_display += f"**🔗 URL:** {url}\n"
scrape_display += f"**⚙️ Max Tokens:** {max_tokens}\n\n"
scrape_display += "**📄 Content:** *Attached as file (too long to display)*"
if 'error' in scrape_data:
scrape_display += f"\n**❌ Error:** {scrape_data['error'][:300]}"
elif content:
scrape_display += f"\n**✅ Success:** Scraped {len(content)} characters"
# Send with file attachment
await discord_message.channel.send(scrape_display, file=content_file)
else:
# Use normal display for shorter content
scrape_display = "**🌐 Webpage Scraping**\n\n"
scrape_display += f"**🔗 URL:** {url}\n"
scrape_display += f"**⚙️ Max Tokens:** {max_tokens}\n\n"
# Show content
if content.strip():
scrape_display += "**📄 Content:**\n```\n"
scrape_display += content
scrape_display += "\n```"
else:
scrape_display += "**📄 Content:** *(No content retrieved)*"
if 'error' in scrape_data:
scrape_display += f"\n**❌ Error:** {scrape_data['error']}"
# Send the scraping display to Discord
await discord_message.channel.send(scrape_display)
except Exception as e:
logging.error(f"Error displaying webpage scraping: {str(e)}")
# Fallback: just send a simple message to prevent bot from getting stuck
try:
await discord_message.channel.send(f"🌐 Webpage scraping completed for: {url}")
except:
pass
return result
except Exception as e:
logging.error(f"Error in webpage scraping: {str(e)}")

View File

@@ -439,7 +439,7 @@ async def call_openai_api(client, messages, model, temperature=0.7, max_tokens=N
"messages": messages,
"max_tokens": max_tokens,
"tools": tools,
"tool_choice": "auto" if tools else None
"tool_choice": "required" if tools else None # Force tool usage when available
}
# Add temperature only for models that support it (exclude GPT-5 family)