-
Notifications
You must be signed in to change notification settings - Fork 72
feat: add thinking_node to rephrase user queries before routing #111
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
PrithvijitBose
wants to merge
13
commits into
AOSSIE-Org:main
from
PrithvijitBose:feat/thinking-node
Closed
Changes from all commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
2215f72
feat: add thinking_node to agent and tool_wrappers
PrithvijitBose e3169ff
chore: moved HumanMessage import to module level for better performance
PrithvijitBose ad9f63a
[feat]: implement custom hybrid search
smokeyScraper 57e321a
Fix: Discord bot now creates thread only for meaningful messages
PrithvijitBose 8c65d35
Added Discord bot integration for message triage and DevRel support; β¦
PrithvijitBose b94a1f5
Merge branch 'main' into feat/thinking-node
PrithvijitBose 14f8a62
Added Discord bot integration for message triage and DevRel support; β¦
PrithvijitBose f7a46b4
Resolve merge conflict in DevRelCommands cog and cleanup token task lβ¦
PrithvijitBose 9390341
Refactor Discord bot to use slash commands and added ephemeral messages
DhruvK278 5ea7d46
Added Discord bot integration for message triage and DevRel support; β¦
PrithvijitBose f5f3db0
Resolve merge conflict in DevRelCommands cog and cleanup token task lβ¦
PrithvijitBose 8e4b3f3
Fixed Bugs
PrithvijitBose 34a7193
Resolved all Code Rabbit issues
PrithvijitBose File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,26 +1,83 @@ | ||
| import logging | ||
| from typing import List | ||
|
|
||
| from app.agents.state import AgentState | ||
| from app.agents.devrel.tools.search_tool.duckduckgo_tool import DuckDuckGoSearchTool | ||
| from langchain_core.messages import HumanMessage | ||
| from langchain_core.language_models.chat_models import BaseChatModel | ||
|
|
||
| logger = logging.getLogger(__name__) | ||
|
|
||
| async def handle_faq_node(state: AgentState, faq_tool) -> dict: | ||
| """Handle FAQ requests""" | ||
| logger.info(f"Handling FAQ for session {state.session_id}") | ||
|
|
||
| async def _generate_queries_with_llm(llm: BaseChatModel, question: str) -> List[str]: | ||
| """Use LLM to generate 2β3 refined search queries for a FAQ question.""" | ||
| try: | ||
| prompt = ( | ||
| "You are an AI assistant. Given the following user question, " | ||
| "generate 2β3 specific search queries that can help answer it accurately from the web. " | ||
| "Only return the queries, one per line, no bullet points.\n\n" | ||
| f"User question: {question}" | ||
| ) | ||
|
|
||
| response = await llm.ainvoke([HumanMessage(content=prompt)]) | ||
| raw_queries = response.content.strip().split("\n") | ||
| queries = [q.strip() for q in raw_queries if q.strip()] | ||
| return queries or [question] | ||
| except Exception as e: | ||
| logger.warning( | ||
| f"[FAQ Handler] Query generation failed, using fallback. Error: {e}" | ||
| ) | ||
| return [question] | ||
|
|
||
|
|
||
| async def handle_faq_node_with_llm(state: AgentState, llm: BaseChatModel) -> dict: | ||
| """Handles general FAQ by searching the web with LLM-generated queries.""" | ||
| logger.info(f"[FAQ Handler] Handling FAQ for session {state.session_id}") | ||
|
|
||
| # Extract latest user message | ||
| latest_message = "" | ||
| if state.messages: | ||
| latest_message = state.messages[-1].get("content", "") | ||
| elif state.context.get("original_message"): | ||
| latest_message = state.context["original_message"] | ||
|
|
||
| # faq_tool will be passed from the agent, similar to llm for classify_intent | ||
| faq_response = await faq_tool.get_response(latest_message) | ||
| if not latest_message: | ||
| logger.warning("[FAQ Handler] No user question found.") | ||
| return { | ||
| "task_result": { | ||
| "type": "faq", | ||
| "response": "Sorry, I couldn't find the question to answer.", | ||
| "source": "web_faq_llm" | ||
| }, | ||
| "current_task": "faq_handled" | ||
| } | ||
|
|
||
| # Generate refined queries | ||
| queries = await _generate_queries_with_llm(llm, latest_message) | ||
|
|
||
| # Run web search | ||
| search_tool = DuckDuckGoSearchTool() | ||
| results = [] | ||
|
|
||
| for query in queries: | ||
| try: | ||
| result = await search_tool.search(query) | ||
| results.append(f"Query: {query}\n{result}") | ||
| except Exception as e: | ||
| logger.warning( | ||
| f"[FAQ Handler] Search failed for query: {query} β {e}" | ||
| ) | ||
|
|
||
| # Combine and return results | ||
| combined_result = ( | ||
| "\n\n".join(results) if results else "Sorry, no results found from the web." | ||
| ) | ||
|
|
||
| return { | ||
| "task_result": { | ||
| "type": "faq", | ||
| "response": faq_response, | ||
| "source": "faq_database" | ||
| "response": combined_result, | ||
| "source": "web_faq_llm" | ||
| }, | ||
| "current_task": "faq_handled" | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,43 +1,21 @@ | ||
| import asyncio | ||
| import logging | ||
| from typing import List, Dict, Any | ||
| from ddgs import DDGS | ||
| from langsmith import traceable | ||
| from langchain.tools import BaseTool | ||
| from typing import Type | ||
| from pydantic import BaseModel, Field | ||
| from app.agents.devrel.tools.search_tool.duckduckgo_tool import DuckDuckGoSearchTool | ||
|
|
||
| logger = logging.getLogger(__name__) | ||
| class DuckDuckGoSearchInput(BaseModel): | ||
| query: str = Field(..., description="Search query") | ||
|
|
||
| class DuckDuckGoSearchTool: | ||
| """DDGS-based DuckDuckGo search integration""" | ||
| class DuckDuckGoSearchLangTool(BaseTool): | ||
| name: str = "duckduckgo_search" | ||
| description: str = "Search the web using DuckDuckGo" | ||
| args_schema: Type[BaseModel] = DuckDuckGoSearchInput | ||
|
|
||
| def __init__(self): | ||
| pass | ||
| def _run(self, query: str) -> str: | ||
| tool = DuckDuckGoSearchTool() | ||
| return tool.search(query) | ||
|
|
||
| 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 [] | ||
| async def _arun(self, query: str) -> str: | ||
| tool = DuckDuckGoSearchTool() | ||
| return await tool.search(query) | ||
| # Use .search here, NOT .run or ._run |
33 changes: 33 additions & 0 deletions
33
backend/app/agents/devrel/tools/search_tool/duckduckgo_tool.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| import logging | ||
| from ddgs import DDGS | ||
|
|
||
| logger = logging.getLogger(__name__) | ||
|
|
||
| class DuckDuckGoSearchTool: | ||
| async def search(self, query: str) -> str: | ||
| logger.info(f"Performing DuckDuckGo search for: {query}") | ||
| try: | ||
| with DDGS() as ddgs: | ||
| results = list(ddgs.text(query, max_results=5)) | ||
|
|
||
| if not results: | ||
| logger.info("No search results found") | ||
| return "No search results found." | ||
|
|
||
| # Format results for the agent | ||
| formatted_results = [] | ||
| for result in results: | ||
| formatted_results.append({ | ||
| 'title': result.get('title', ''), | ||
| 'content': result.get('body', ''), | ||
| 'url': result.get('href', '') | ||
| }) | ||
|
|
||
| return str(formatted_results) | ||
|
|
||
| except ConnectionError as e: | ||
| logger.error(f"Network error during search: {e}") | ||
| return f"Network error: {str(e)}" | ||
| except Exception as e: | ||
| logger.error(f"Unexpected error during search: {e}") | ||
| return f"Search failed: {str(e)}" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the
ReAct supervisor nodeis the router right? won't aligning the query this way make it more aligned for FAQ or web search? as this thinking node is present prior to the routerhave you tried any interactions, if yes please do share.