Skip to content

Commit ed85a5e

Browse files
Merge pull request #106 from Rudra775/ddg-rewrite
feat: integrated DDGS search tool and refactored handlers
2 parents 6c7dc98 + 6724f33 commit ed85a5e

File tree

7 files changed

+189
-13
lines changed

7 files changed

+189
-13
lines changed

backend/app/agents/devrel/agent.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from langchain_google_genai import ChatGoogleGenerativeAI
66
from langgraph.checkpoint.memory import InMemorySaver
77
from ..base_agent import BaseAgent, AgentState
8-
from .tools.search_tool import TavilySearchTool
8+
from .tools.search_tool.ddg import DuckDuckGoSearchTool
99
from .tools.faq_tool import FAQTool
1010
from .github.github_toolkit import GitHubToolkit
1111
from app.core.config import settings
@@ -27,7 +27,7 @@ def __init__(self, config: Dict[str, Any] = None):
2727
temperature=0.3,
2828
google_api_key=settings.gemini_api_key
2929
)
30-
self.search_tool = TavilySearchTool()
30+
self.search_tool = DuckDuckGoSearchTool()
3131
self.faq_tool = FAQTool()
3232
self.github_toolkit = GitHubToolkit()
3333
self.checkpointer = InMemorySaver()

backend/app/agents/devrel/github/tools/search.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
import logging
22
from typing import Dict, Any
3-
from app.agents.devrel.tools.search_tool import TavilySearchTool
3+
from app.agents.devrel.tools.search_tool.ddg import DuckDuckGoSearchTool
44
logger = logging.getLogger(__name__)
55

66

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

1111
try:
12-
search_tool = TavilySearchTool()
12+
search_tool = DuckDuckGoSearchTool()
1313
search_results = await search_tool.search(query, max_results=5)
1414

1515
if not search_results:

backend/app/agents/devrel/nodes/handlers/web_search.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
from langchain_core.messages import HumanMessage
55
from app.agents.devrel.prompts.search_prompt import EXTRACT_SEARCH_QUERY_PROMPT
66

7-
87
logger = logging.getLogger(__name__)
98

109
async def _extract_search_query(message: str, llm) -> str:
@@ -42,16 +41,17 @@ async def handle_web_search_node(state: AgentState, search_tool, llm) -> dict:
4241
"type": "web_search",
4342
"query": search_query,
4443
"results": search_results,
45-
"source": "tavily_search"
44+
"source": "duckduckgo_search"
4645
},
47-
"tools_used": ["tavily_search"],
46+
"tools_used": ["duckduckgo_search"],
4847
"current_task": "web_search_handled"
4948
}
5049

5150
def create_search_response(task_result: Dict[str, Any]) -> str:
5251
"""
5352
Create a user-friendly response string from search results.
5453
"""
54+
5555
query = task_result.get("query")
5656
results = task_result.get("results", [])
5757

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

7069
response_parts.append("You can ask me to search again with a different query if these aren't helpful.")
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import asyncio
2+
import logging
3+
from typing import List, Dict, Any
4+
from ddgs import DDGS
5+
from langsmith import traceable
6+
7+
logger = logging.getLogger(__name__)
8+
9+
class DuckDuckGoSearchTool:
10+
"""DDGS-based DuckDuckGo search integration"""
11+
12+
def __init__(self):
13+
pass
14+
15+
def _perform_search(self, query: str, max_results: int):
16+
with DDGS() as ddg:
17+
return ddg.text(query, max_results=max_results)
18+
19+
@traceable(name="duckduckgo_search_tool", run_type="tool")
20+
async def search(self, query: str, max_results: int = 5) -> List[Dict[str, Any]]:
21+
try:
22+
response = await asyncio.to_thread(
23+
self._perform_search,
24+
query=query,
25+
max_results=max_results
26+
)
27+
28+
results = []
29+
for result in response or []:
30+
results.append({
31+
"title": result.get("title", ""),
32+
"content": result.get("body", ""),
33+
"url": result.get("href", ""),
34+
"score": 0
35+
})
36+
return results
37+
38+
except (ConnectionError, TimeoutError) as e:
39+
logger.warning("Network issue during DDG search: %s", e)
40+
return []
41+
except Exception as e:
42+
logger.error("DuckDuckGo search failed: %s", str(e))
43+
return []

backend/app/agents/devrel/tools/search_tool.py renamed to backend/app/agents/devrel/tools/search_tool/tavilly.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,4 +49,4 @@ async def search(self, query: str, max_results: int = 5) -> List[Dict[str, Any]]
4949
return []
5050
except (ConnectionError, TimeoutError) as e:
5151
logger.error("Network error during search: %s", str(e))
52-
return []
52+
return []

poetry.lock

Lines changed: 134 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)