beast-agent 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +7 -0
- package/LICENSE +21 -0
- package/README.md +94 -0
- package/assets/app.ico +0 -0
- package/assets/tray.png +0 -0
- package/bin/beast-agent.js +23 -0
- package/config.example.yaml +26 -0
- package/eng.traineddata +0 -0
- package/package.json +101 -0
- package/scripts/swap-electron.js +40 -0
- package/src/agent/bus.js +384 -0
- package/src/agent/computeruse.js +200 -0
- package/src/agent/config.js +284 -0
- package/src/agent/engine.js +3118 -0
- package/src/agent/kb.js +123 -0
- package/src/agent/llm.js +219 -0
- package/src/agent/logger.js +90 -0
- package/src/agent/memory.js +383 -0
- package/src/agent/pdf.js +20 -0
- package/src/agent/scripts/__pycache__/websearch.cpython-312.pyc +0 -0
- package/src/agent/scripts/news.py +113 -0
- package/src/agent/scripts/websearch.py +225 -0
- package/src/agent/skills.js +522 -0
- package/src/agent/tokens.js +39 -0
- package/src/agent/tools.js +911 -0
- package/src/agent/usage.js +125 -0
- package/src/agent/watchers.js +312 -0
- package/src/agent/watext.js +75 -0
- package/src/agent/whatsapp.js +494 -0
- package/src/cron.js +245 -0
- package/src/main.js +3622 -0
- package/src/preload.js +122 -0
- package/src/renderer/browserPreload.js +73 -0
- package/src/renderer/i18n.js +757 -0
- package/src/renderer/index.html +227 -0
- package/src/renderer/renderer.js +3250 -0
- package/src/renderer/style.css +1559 -0
- package/tests/approval.test.js +56 -0
- package/tests/bg-jobs.test.js +315 -0
- package/tests/bus.test.js +46 -0
- package/tests/computeruse-context.test.js +69 -0
- package/tests/cron.test.js +95 -0
- package/tests/engine.test.js +140 -0
- package/tests/eval.test.js +91 -0
- package/tests/fallout.test.js +188 -0
- package/tests/llm.test.js +56 -0
- package/tests/memory.test.js +33 -0
- package/tests/memoryloop.test.js +26 -0
- package/tests/notegen.test.js +63 -0
- package/tests/owner.test.js +32 -0
- package/tests/python.test.js +75 -0
- package/tests/scenarios.json +81 -0
- package/tests/sessioncode.test.js +50 -0
- package/tests/setup.js +9 -0
- package/tests/tokens.test.js +42 -0
- package/tests/tools.test.js +84 -0
- package/tests/usage.test.js +44 -0
- package/tests/v11.test.js +76 -0
- package/tests/watchers.test.js +206 -0
- package/tests/watext.test.js +53 -0
- package/tests/whatsapp.test.js +103 -0
- package/tests/wherewasi.test.js +40 -0
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""Beast hızlı web arama — önce ddgs kütüphanesi (kuruluysa), sonra çoklu motor PARALEL (thread).
|
|
4
|
+
|
|
5
|
+
ddgs (github.com/deedy5/ddgs) kuruluysa onu kullanır: anti-bot/CAPTCHA korumalı,
|
|
6
|
+
çok backend'li metasearch. Kurulu değilse DuckDuckGo HTML, Bing, Mojeek motorları
|
|
7
|
+
aynı anda sorgulanır (stdlib-only), sonuçlar harmanlanır + URL bazlı tekilleştirilir.
|
|
8
|
+
|
|
9
|
+
Kullanım:
|
|
10
|
+
python websearch.py "sorgu" # 8 sonuç
|
|
11
|
+
python websearch.py "sorgu" --limit 5 --json
|
|
12
|
+
Çıktı (--json): satır başına {"engine","title","url","snippet"}
|
|
13
|
+
"""
|
|
14
|
+
import argparse
|
|
15
|
+
import base64
|
|
16
|
+
import concurrent.futures as cf
|
|
17
|
+
import html as H
|
|
18
|
+
import json
|
|
19
|
+
import re
|
|
20
|
+
import sys
|
|
21
|
+
import urllib.parse
|
|
22
|
+
import urllib.request
|
|
23
|
+
|
|
24
|
+
try:
|
|
25
|
+
sys.stdout.reconfigure(encoding="utf-8", errors="replace")
|
|
26
|
+
sys.stderr.reconfigure(encoding="utf-8", errors="replace")
|
|
27
|
+
except Exception:
|
|
28
|
+
pass
|
|
29
|
+
|
|
30
|
+
UA = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126 Safari/537.36"}
|
|
31
|
+
TAG_RE = re.compile(r"<[^>]+>")
|
|
32
|
+
WS_RE = re.compile(r"\s+")
|
|
33
|
+
JUNK_TITLES = {"301 moved permanently", "302 moved temporarily", "just a moment...", "attention required!"}
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def clean(s):
|
|
37
|
+
return WS_RE.sub(" ", TAG_RE.sub("", H.unescape(s or ""))).strip()
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def realurl(u):
|
|
41
|
+
"""Bing /ck/a redirect linklerini çözer; DDG uddg'yi çözer."""
|
|
42
|
+
if "bing.com/ck/" in u:
|
|
43
|
+
m = re.search(r"[?&]u=a1([^&]+)", u)
|
|
44
|
+
if m:
|
|
45
|
+
s = m.group(1)
|
|
46
|
+
s += "=" * (-len(s) % 4)
|
|
47
|
+
try:
|
|
48
|
+
dec = base64.urlsafe_b64decode(s).decode("utf-8", "replace")
|
|
49
|
+
if dec.startswith("http"):
|
|
50
|
+
return dec
|
|
51
|
+
except Exception:
|
|
52
|
+
pass
|
|
53
|
+
if "uddg=" in u:
|
|
54
|
+
m = re.search(r"[?&]uddg=([^&]+)", u)
|
|
55
|
+
if m:
|
|
56
|
+
return urllib.parse.unquote(m.group(1))
|
|
57
|
+
if u.startswith("//"):
|
|
58
|
+
u = "https:" + u
|
|
59
|
+
return u
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def good(row):
|
|
63
|
+
return (
|
|
64
|
+
row["title"]
|
|
65
|
+
and row["url"].startswith("http")
|
|
66
|
+
and "bing.com/ck/" not in row["url"]
|
|
67
|
+
and row["title"].strip().lower() not in JUNK_TITLES
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def get(url, timeout=7):
|
|
72
|
+
req = urllib.request.Request(url, headers=UA)
|
|
73
|
+
with urllib.request.urlopen(req, timeout=timeout) as r:
|
|
74
|
+
return r.read().decode("utf-8", "replace")
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def is_ddg_bot_page(raw):
|
|
78
|
+
"""DDG kapalı DEĞİL: bot koruması (CAPTCHA/anomaly) sayfası mı?"""
|
|
79
|
+
low = (raw or "").lower()
|
|
80
|
+
return "bots use duckduckgo" in low or "anomaly-modal" in low or "anomaly" in low and "duckduckgo" in low
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def ddg(q):
|
|
84
|
+
out = []
|
|
85
|
+
try:
|
|
86
|
+
raw = get("https://html.duckduckgo.com/html/?q=" + urllib.parse.quote(q))
|
|
87
|
+
except Exception:
|
|
88
|
+
raw = ""
|
|
89
|
+
if is_ddg_bot_page(raw):
|
|
90
|
+
print("[websearch] ddg: bot koruması (CAPTCHA) — kapalı DEĞİL, Bing/Mojeek devrede", file=sys.stderr)
|
|
91
|
+
return out
|
|
92
|
+
for m in re.finditer(
|
|
93
|
+
r'<a[^>]+class="[^"]*result__a[^"]*"[^>]+href="([^"]+)"[^>]*>(.*?)</a>',
|
|
94
|
+
raw,
|
|
95
|
+
re.S,
|
|
96
|
+
):
|
|
97
|
+
title = clean(m.group(2))
|
|
98
|
+
row = {"engine": "ddg", "title": title, "url": realurl(m.group(1)), "snippet": ""}
|
|
99
|
+
if good(row):
|
|
100
|
+
out.append(row)
|
|
101
|
+
for i, s in enumerate(re.findall(r'class="[^"]*result__snippet[^"]*"[^>]*>(.*?)</a>', raw, re.S)):
|
|
102
|
+
if i < len(out):
|
|
103
|
+
out[i]["snippet"] = clean(s)[:300]
|
|
104
|
+
if out:
|
|
105
|
+
return out
|
|
106
|
+
# yedek: lite arayüz
|
|
107
|
+
try:
|
|
108
|
+
raw = get("https://lite.duckduckgo.com/lite/?q=" + urllib.parse.quote(q))
|
|
109
|
+
except Exception:
|
|
110
|
+
return out
|
|
111
|
+
for m in re.finditer(r"<a[^>]+href=\"([^\"]+)\"[^>]*class=['\"]result-link['\"][^>]*>(.*?)</a>", raw, re.S):
|
|
112
|
+
row = {"engine": "ddg", "title": clean(m.group(2)), "url": realurl(m.group(1)), "snippet": ""}
|
|
113
|
+
if good(row):
|
|
114
|
+
out.append(row)
|
|
115
|
+
snips = [clean(x) for x in re.findall(r"class=['\"]result-snippet['\"][^>]*>(.*?)</td>", raw, re.S)]
|
|
116
|
+
for i, s in enumerate(snips):
|
|
117
|
+
if i < len(out):
|
|
118
|
+
out[i]["snippet"] = s[:300]
|
|
119
|
+
return out
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def bing(q):
|
|
123
|
+
out = []
|
|
124
|
+
raw = get("https://www.bing.com/search?q=" + urllib.parse.quote(q) + "&setlang=tr")
|
|
125
|
+
for m in re.finditer(
|
|
126
|
+
r'<li class="b_algo".*?<h2[^>]*><a[^>]+href="(http[^"]+)"[^>]*>(.*?)</a></h2>(.*?)(?=<li class="b_algo"|</ol>)',
|
|
127
|
+
raw,
|
|
128
|
+
re.S,
|
|
129
|
+
):
|
|
130
|
+
row = {"engine": "bing", "title": clean(m.group(2)), "url": realurl(m.group(1)), "snippet": clean(m.group(3))[:300]}
|
|
131
|
+
if good(row):
|
|
132
|
+
out.append(row)
|
|
133
|
+
return out
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def mojeek(q):
|
|
137
|
+
out = []
|
|
138
|
+
raw = get("https://www.mojeek.com/search?q=" + urllib.parse.quote(q))
|
|
139
|
+
for m in re.finditer(
|
|
140
|
+
r'<h2[^>]*>\s*<a[^>]+href="(http[^"]+)"[^>]*>(.*?)</a></h2>(.*?)(?=<h2|$)',
|
|
141
|
+
raw,
|
|
142
|
+
re.S,
|
|
143
|
+
):
|
|
144
|
+
row = {"engine": "mojeek", "title": clean(m.group(2)), "url": realurl(m.group(1)), "snippet": clean(m.group(3))[:300]}
|
|
145
|
+
if good(row):
|
|
146
|
+
out.append(row)
|
|
147
|
+
return out
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
ENGINES = {"ddg": ddg, "bing": bing, "mojeek": mojeek}
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def ddg_api(q):
|
|
154
|
+
"""ddgs kütüphanesi kuruluysa onu kullan: anti-bot korumalı, çok backend'li.
|
|
155
|
+
Kurulu değilse None döner (stdlib motorlara düşülür)."""
|
|
156
|
+
try:
|
|
157
|
+
from ddgs import DDGS
|
|
158
|
+
except Exception:
|
|
159
|
+
return None
|
|
160
|
+
rows = []
|
|
161
|
+
try:
|
|
162
|
+
with DDGS() as d:
|
|
163
|
+
for r in d.text(q, max_results=15):
|
|
164
|
+
url = str(r.get("href") or r.get("url") or "")
|
|
165
|
+
title = clean(str(r.get("title") or ""))
|
|
166
|
+
if not title or not url.startswith("http"):
|
|
167
|
+
continue
|
|
168
|
+
rows.append({
|
|
169
|
+
"engine": "ddgs",
|
|
170
|
+
"title": title,
|
|
171
|
+
"url": url,
|
|
172
|
+
"snippet": clean(str(r.get("body") or ""))[:300],
|
|
173
|
+
})
|
|
174
|
+
except Exception as e:
|
|
175
|
+
print(f"[websearch] ddgs: {e}", file=sys.stderr)
|
|
176
|
+
return rows
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def main():
|
|
180
|
+
ap = argparse.ArgumentParser()
|
|
181
|
+
ap.add_argument("query")
|
|
182
|
+
ap.add_argument("--limit", type=int, default=8)
|
|
183
|
+
ap.add_argument("--json", action="store_true")
|
|
184
|
+
a = ap.parse_args()
|
|
185
|
+
|
|
186
|
+
merged, seen = [], set()
|
|
187
|
+
|
|
188
|
+
def add_rows(rows):
|
|
189
|
+
for row in rows:
|
|
190
|
+
key = row["url"].split("#")[0].rstrip("/")
|
|
191
|
+
if not key or key in seen:
|
|
192
|
+
continue
|
|
193
|
+
seen.add(key)
|
|
194
|
+
merged.append(row)
|
|
195
|
+
|
|
196
|
+
api_rows = ddg_api(a.query)
|
|
197
|
+
add_rows(api_rows or [])
|
|
198
|
+
|
|
199
|
+
# ddgs yetersiz kaldıysa / kurulu değilse stdlib motorları paralele sok
|
|
200
|
+
if len(merged) < a.limit:
|
|
201
|
+
with cf.ThreadPoolExecutor(max_workers=len(ENGINES)) as ex:
|
|
202
|
+
futs = {ex.submit(fn, a.query): name for name, fn in ENGINES.items()}
|
|
203
|
+
try:
|
|
204
|
+
for fut in cf.as_completed(futs, timeout=10):
|
|
205
|
+
name = futs[fut]
|
|
206
|
+
try:
|
|
207
|
+
add_rows(fut.result())
|
|
208
|
+
except Exception as e:
|
|
209
|
+
print(f"[websearch] {name}: {e}", file=sys.stderr)
|
|
210
|
+
except cf.TimeoutError:
|
|
211
|
+
print("[websearch] bazı motorlar zaman aşımına uğradı", file=sys.stderr)
|
|
212
|
+
|
|
213
|
+
merged = merged[: max(1, a.limit)]
|
|
214
|
+
if a.json:
|
|
215
|
+
for r in merged:
|
|
216
|
+
print(json.dumps(r, ensure_ascii=False))
|
|
217
|
+
else:
|
|
218
|
+
for i, r in enumerate(merged, 1):
|
|
219
|
+
print(f"{i}. {r['title']}\n {r['url']}\n {r['snippet']}\n")
|
|
220
|
+
src = "ddgs" if api_rows else "stdlib"
|
|
221
|
+
print(f"[websearch] {len(merged)} sonuç ({src})", file=sys.stderr)
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
if __name__ == "__main__":
|
|
225
|
+
main()
|