Skip to content
Merged
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
4 changes: 2 additions & 2 deletions backend/app/agents/devrel/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from langchain_google_genai import ChatGoogleGenerativeAI
from langgraph.checkpoint.memory import InMemorySaver
from ..base_agent import BaseAgent, AgentState
from .tools.search_tool import TavilySearchTool
from .tools.search_tool.ddg import DuckDuckGoSearchTool
from .tools.faq_tool import FAQTool
from .github.github_toolkit import GitHubToolkit
from app.core.config import settings
Expand All @@ -27,7 +27,7 @@ def __init__(self, config: Dict[str, Any] = None):
temperature=0.3,
google_api_key=settings.gemini_api_key
)
self.search_tool = TavilySearchTool()
self.search_tool = DuckDuckGoSearchTool()
self.faq_tool = FAQTool()
self.github_toolkit = GitHubToolkit()
self.checkpointer = InMemorySaver()
Expand Down
6 changes: 3 additions & 3 deletions backend/app/agents/devrel/github/tools/search.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import logging
from typing import Dict, Any
from app.agents.devrel.tools.search_tool import TavilySearchTool
from app.agents.devrel.tools.search_tool.ddg import DuckDuckGoSearchTool
logger = logging.getLogger(__name__)


async def handle_web_search(query: str) -> Dict[str, Any]:
"""Handle web search using Tavily search tool"""
"""Handle web search using DuckDuckGo search tool"""
logger.info("Handling web search request")

try:
search_tool = TavilySearchTool()
search_tool = DuckDuckGoSearchTool()
search_results = await search_tool.search(query, max_results=5)

if not search_results:
Expand Down
11 changes: 5 additions & 6 deletions backend/app/agents/devrel/nodes/handlers/web_search.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
from langchain_core.messages import HumanMessage
from app.agents.devrel.prompts.search_prompt import EXTRACT_SEARCH_QUERY_PROMPT


logger = logging.getLogger(__name__)

async def _extract_search_query(message: str, llm) -> str:
Expand Down Expand Up @@ -42,16 +41,17 @@ async def handle_web_search_node(state: AgentState, search_tool, llm) -> dict:
"type": "web_search",
"query": search_query,
"results": search_results,
"source": "tavily_search"
"source": "duckduckgo_search"
},
"tools_used": ["tavily_search"],
"tools_used": ["duckduckgo_search"],
"current_task": "web_search_handled"
}

def create_search_response(task_result: Dict[str, Any]) -> str:
"""
Create a user-friendly response string from search results.
"""

query = task_result.get("query")
results = task_result.get("results", [])

Expand All @@ -61,10 +61,9 @@ def create_search_response(task_result: Dict[str, Any]) -> str:
response_parts = [f"Here's what I found for '{query}':"]
for i, result in enumerate(results[:5]):
title = result.get('title', 'N/A')
snippet = result.get('snippet', 'N/A')
snippet = result.get('content', 'N/A')
url = result.get('url', '#')
result_line = f"{i+1}. {title}: {snippet}"
response_parts.append(result_line)
response_parts.append(f"{i+1}. {title}: {snippet}")
response_parts.append(f" (Source: {url})")

response_parts.append("You can ask me to search again with a different query if these aren't helpful.")
Expand Down
43 changes: 43 additions & 0 deletions backend/app/agents/devrel/tools/search_tool/ddg.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import asyncio
import logging
from typing import List, Dict, Any
from ddgs import DDGS
from langsmith import traceable

logger = logging.getLogger(__name__)

class DuckDuckGoSearchTool:
"""DDGS-based DuckDuckGo search integration"""

def __init__(self):
pass

def _perform_search(self, query: str, max_results: int):
with DDGS() as ddg:
return ddg.text(query, max_results=max_results)

@traceable(name="duckduckgo_search_tool", run_type="tool")
async def search(self, query: str, max_results: int = 5) -> List[Dict[str, Any]]:
try:
response = await asyncio.to_thread(
self._perform_search,
query=query,
max_results=max_results
)

results = []
for result in response or []:
results.append({
"title": result.get("title", ""),
"content": result.get("body", ""),
"url": result.get("href", ""),
"score": 0
})
return results

except (ConnectionError, TimeoutError) as e:
logger.warning("Network issue during DDG search: %s", e)
return []
except Exception as e:
logger.error("DuckDuckGo search failed: %s", str(e))
return []
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,4 @@ async def search(self, query: str, max_results: int = 5) -> List[Dict[str, Any]]
return []
except (ConnectionError, TimeoutError) as e:
logger.error("Network error during search: %s", str(e))
return []
return []
135 changes: 134 additions & 1 deletion poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading