feat(MAT-64): Add web search tool to text bot

The text bot had no websearch capability while the voice agent did.
Added Brave Search integration as a web_search tool so the bot can
answer questions about current events and look up information.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Christian Gick
2026-02-28 13:30:36 +02:00
parent e880376fdb
commit 2826455036

48
bot.py
View File

@@ -76,6 +76,7 @@ CONFLUENCE_USER = os.environ.get("CONFLUENCE_USER", "")
CONFLUENCE_TOKEN = os.environ.get("CONFLUENCE_TOKEN", "")
PORTAL_URL = os.environ.get("PORTAL_URL", "")
BOT_API_KEY = os.environ.get("BOT_API_KEY", "")
BRAVE_API_KEY = os.environ.get("BRAVE_API_KEY", "")
MAX_TOOL_ITERATIONS = 5
SYSTEM_PROMPT = """You are a helpful AI assistant in a Matrix chat room.
@@ -94,6 +95,7 @@ IMPORTANT RULES — FOLLOW THESE STRICTLY:
- You can see and analyze images that users send. Describe what you see when asked about an image.
- You can read and analyze PDF documents that users send. Summarize content and answer questions about them.
- You can generate images when asked — use the generate_image tool for any image creation, drawing, or illustration requests.
- You can search the web using the web_search tool. Use it when users ask about current events, facts, or anything that needs up-to-date information.
- You can search Confluence and Jira using tools. When users ask about documentation, wiki pages, tickets, or tasks, use the appropriate tool. Use confluence_recent_pages FIRST to show recently edited pages before searching.
- When creating Jira issues, always confirm the project key and summary with the user before creating.
- If a user's Atlassian account is not connected, tell them to connect it at matrixhost.eu/settings and provide the link.
@@ -268,7 +270,23 @@ ATLASSIAN_TOOLS = [
},
]
ALL_TOOLS = IMAGE_GEN_TOOLS + ATLASSIAN_TOOLS
WEB_SEARCH_TOOLS = [{
"type": "function",
"function": {
"name": "web_search",
"description": "Search the web for current information. Use when the user asks about recent events, facts, or anything that needs up-to-date information from the internet.",
"parameters": {
"type": "object",
"properties": {
"query": {"type": "string", "description": "Search query"},
"count": {"type": "integer", "description": "Number of results (default 5)", "default": 5},
},
"required": ["query"],
},
},
}]
ALL_TOOLS = IMAGE_GEN_TOOLS + WEB_SEARCH_TOOLS + ATLASSIAN_TOOLS
ATLASSIAN_NOT_CONNECTED_MSG = (
"Your Atlassian account is not connected. "
@@ -1923,6 +1941,30 @@ class Bot:
finally:
self._pending_connects.pop(sender, None)
async def _brave_search(self, query: str, count: int = 5) -> str:
"""Call Brave Search API and return formatted results."""
if not BRAVE_API_KEY:
return "Web search unavailable (no API key configured)."
try:
async with httpx.AsyncClient(timeout=10.0) as client:
resp = await client.get(
"https://api.search.brave.com/res/v1/web/search",
headers={"Accept": "application/json", "X-Subscription-Token": BRAVE_API_KEY},
params={"q": query, "count": count, "text_decorations": False},
)
resp.raise_for_status()
data = resp.json()
results = data.get("web", {}).get("results", [])
if not results:
return "No results found."
lines = []
for r in results[:count]:
lines.append(f"- {r.get('title', '')}: {r.get('description', '')} ({r.get('url', '')})")
return "\n".join(lines)
except Exception as exc:
logger.warning("Brave search error: %s", exc)
return f"Search failed: {exc}"
async def _execute_tool(self, tool_name: str, args: dict, sender: str, room_id: str) -> str:
"""Execute a tool call and return the result as a string."""
# Image generation — no Atlassian token needed
@@ -1930,6 +1972,10 @@ class Bot:
await self._generate_and_send_image(room_id, args.get("prompt", ""))
return "Image generated and sent to the room."
# Web search — no auth needed
if tool_name == "web_search":
return await self._brave_search(args.get("query", ""), args.get("count", 5))
# Atlassian tools — need per-user token
token = await self.atlassian.get_token(sender) if sender else None
if not token: