Files
matrix-ai-agent/cron/brave_search.py
Christian Gick 4d8ea44b3d feat(MAT-174): Add cron job scheduler and executors
Cron package that syncs jobs from matrixhost portal API, schedules execution
with timezone-aware timing, and posts results to Matrix rooms. Includes
Brave Search, reminder, and browser scrape (placeholder) executors with
formatter. 31 pytest tests.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 09:31:19 +02:00

64 lines
2.0 KiB
Python

"""Brave Search executor for cron jobs."""
import logging
import os
import httpx
from .formatter import format_search_results
logger = logging.getLogger(__name__)
BRAVE_API_KEY = os.environ.get("BRAVE_API_KEY", "")
async def execute_brave_search(job: dict, send_text, **_kwargs) -> dict:
"""Run a Brave Search query, dedup against known keys, post new results to Matrix."""
if not BRAVE_API_KEY:
return {"status": "error", "error": "BRAVE_API_KEY not configured"}
config = job.get("config", {})
query = config.get("query", "")
max_results = config.get("maxResults", 10)
target_room = job["targetRoom"]
dedup_keys = set(job.get("dedupKeys", []))
if not query:
return {"status": "error", "error": "No search query configured"}
try:
async with httpx.AsyncClient(timeout=15.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": max_results, "text_decorations": False},
)
resp.raise_for_status()
data = resp.json()
results = data.get("web", {}).get("results", [])
if not results:
return {"status": "no_results"}
# Dedup by URL
new_results = [r for r in results if r.get("url") not in dedup_keys]
if not new_results:
return {"status": "no_results"}
msg = format_search_results(job["name"], new_results)
await send_text(target_room, msg)
new_keys = [r["url"] for r in new_results if r.get("url")]
return {
"status": "success",
"newDedupKeys": new_keys,
}
except Exception as exc:
logger.error("Brave search cron failed: %s", exc, exc_info=True)
return {"status": "error", "error": str(exc)}