Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion env.example
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
TELEGRAM_BOT_TOKEN=
TELEGRAM_CHAT_ID=
GBYTE_ERP_URL=""
API_KEY=secret-agent-key
API_KEY=secret-agent-key
TAVILY_API_KEY=
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ pyyaml
dateparser
pytz
ddgs
tavily-python
youtube-transcript-api
python-dateutil
playwright
Expand Down
41 changes: 31 additions & 10 deletions tools/web_search.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,44 @@
Web Search Tool — Search the web and summarize content.
"""
import logging
import os
import re
from langchain_core.tools import tool
import config as app_config


def perform_web_search(query):
"""Performs a DuckDuckGo search."""
def _tavily_search(query):
"""Performs a web search using Tavily."""
from tavily import TavilyClient
client = TavilyClient()
response = client.search(query=query, max_results=5, search_depth="basic")
results = response.get("results", [])
if not results:
return "No results found."
summary = ""
for r in results:
summary += f"- [{r['title']}]({r['url']}): {r['content']}\n"
return summary


def _ddgs_search(query):
"""Performs a web search using DuckDuckGo."""
from ddgs import DDGS
results = DDGS().text(query, max_results=5)
if not results:
return "No results found."
Comment on lines +28 to +30
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The DDGS().text() method in the duckduckgo_search library (and similar wrappers) often returns a generator. In Python, a generator object is always truthy, so the if not results check will fail to detect empty results. Converting the results to a list ensures the check works correctly and allows for safe iteration.

Suggested change
results = DDGS().text(query, max_results=5)
if not results:
return "No results found."
results = list(DDGS().text(query, max_results=5))
if not results:
return "No results found."

summary = ""
for r in results:
summary += f"- [{r['title']}]({r['href']}): {r['body']}\n"
return summary


def perform_web_search(query):
"""Performs a web search using Tavily (if TAVILY_API_KEY is set) or DuckDuckGo."""
try:
results = DDGS().text(query, max_results=5)
if not results:
return "No results found."

summary = ""
for r in results:
summary += f"- [{r['title']}]({r['href']}): {r['body']}\n"
return summary
if os.environ.get("TAVILY_API_KEY"):
return _tavily_search(query)
return _ddgs_search(query)
except Exception as e:
return f"Error performing search: {e}"
Comment on lines 43 to 44
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This try...except block catches all exceptions and returns them as a string, which is then passed to the LLM. However, it doesn't log the error, making it difficult to debug issues (like API failures or network errors) from the server logs. Since the caller web_search also has a try...except block with logging, it would be better to either log the error here or let the exception bubble up.

Suggested change
except Exception as e:
return f"Error performing search: {e}"
except Exception as e:
logging.error(f"Web search error: {e}", exc_info=True)
return f"Error performing search: {e}"


Expand Down