File size: 3,245 Bytes
3e0f245
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#!/usr/bin/env python
"""Source adapters for the Web Research Agent (#13) β€” different areas need different sources.

Every adapter is keyless and returns the same shape [{title,url,snippet,source}] so the agent can
fetch + cite uniformly. Areas map to a blend of adapters:

  web         β†’ general web            (opportunity/competitive/client baseline)
  opportunity β†’ web + fresh news
  competitive β†’ web + fresh news
  technical   β†’ web + arXiv + GitHub
  client      β†’ web
"""
import urllib.parse

import requests
import feedparser

from search import search as web_search, search_news

_UA = "Mozilla/5.0 (compatible; GritAI-Research/1.0)"


def arxiv(query: str, n: int = 4) -> list:
    """arXiv abstracts (keyless Atom API). Abstract pages are readable/fetchable."""
    url = ("http://export.arxiv.org/api/query?search_query=all:"
           f"{urllib.parse.quote(query)}&start=0&max_results={int(n)}&sortBy=relevance")
    d = feedparser.parse(url)
    out = []
    for e in d.entries[:n]:
        link = e.get("link", "")
        out.append({"title": e.get("title", "").replace("\n", " ").strip(),
                    "url": link, "snippet": (e.get("summary", "") or "")[:300], "source": "arxiv"})
    return [r for r in out if r["url"]]


def github(query: str, n: int = 4) -> list:
    """GitHub repository search (keyless public API; low-volume friendly)."""
    try:
        r = requests.get("https://api.github.com/search/repositories",
                         params={"q": query, "sort": "stars", "per_page": n},
                         headers={"User-Agent": _UA, "Accept": "application/vnd.github+json"}, timeout=15)
        items = r.json().get("items", [])
        return [{"title": f"{it['full_name']} (β˜…{it.get('stargazers_count', 0)})",
                 "url": it["html_url"], "snippet": (it.get("description") or "")[:300], "source": "github"}
                for it in items[:n]]
    except Exception:
        return []


AREAS = {
    "web":         [("web", 1.0)],
    "opportunity": [("web", 0.6), ("news", 0.4)],
    "competitive": [("web", 0.6), ("news", 0.4)],
    "technical":   [("web", 0.5), ("arxiv", 0.25), ("github", 0.25)],
    "client":      [("web", 1.0)],
}

_ADAPTERS = {"web": web_search, "news": search_news, "arxiv": arxiv, "github": github}


def search_area(query: str, area: str = "web", n: int = 6) -> list:
    """Blend results from the adapters mapped to `area`, deduped by URL."""
    plan = AREAS.get(area, AREAS["web"])
    seen, out = set(), []
    for name, weight in plan:
        want = max(1, round(n * weight))
        try:
            hits = _ADAPTERS[name](query, want + 1)
        except Exception:
            hits = []
        for h in hits[:want]:
            key = (h["url"] or "").split("#")[0].rstrip("/")
            if key and key not in seen:
                seen.add(key)
                out.append(h)
    return out[:n]


if __name__ == "__main__":
    import sys, json
    area = sys.argv[1] if len(sys.argv) > 1 else "technical"
    q = " ".join(sys.argv[2:]) or "retrieval augmented generation agents"
    print(f"area={area} query={q}")
    for r in search_area(q, area, 8):
        print(f"  [{r['source']}] {r['title'][:64]} β€” {r['url'][:70]}")