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.
Files changed (62) hide show
  1. package/.env.example +7 -0
  2. package/LICENSE +21 -0
  3. package/README.md +94 -0
  4. package/assets/app.ico +0 -0
  5. package/assets/tray.png +0 -0
  6. package/bin/beast-agent.js +23 -0
  7. package/config.example.yaml +26 -0
  8. package/eng.traineddata +0 -0
  9. package/package.json +101 -0
  10. package/scripts/swap-electron.js +40 -0
  11. package/src/agent/bus.js +384 -0
  12. package/src/agent/computeruse.js +200 -0
  13. package/src/agent/config.js +284 -0
  14. package/src/agent/engine.js +3118 -0
  15. package/src/agent/kb.js +123 -0
  16. package/src/agent/llm.js +219 -0
  17. package/src/agent/logger.js +90 -0
  18. package/src/agent/memory.js +383 -0
  19. package/src/agent/pdf.js +20 -0
  20. package/src/agent/scripts/__pycache__/websearch.cpython-312.pyc +0 -0
  21. package/src/agent/scripts/news.py +113 -0
  22. package/src/agent/scripts/websearch.py +225 -0
  23. package/src/agent/skills.js +522 -0
  24. package/src/agent/tokens.js +39 -0
  25. package/src/agent/tools.js +911 -0
  26. package/src/agent/usage.js +125 -0
  27. package/src/agent/watchers.js +312 -0
  28. package/src/agent/watext.js +75 -0
  29. package/src/agent/whatsapp.js +494 -0
  30. package/src/cron.js +245 -0
  31. package/src/main.js +3622 -0
  32. package/src/preload.js +122 -0
  33. package/src/renderer/browserPreload.js +73 -0
  34. package/src/renderer/i18n.js +757 -0
  35. package/src/renderer/index.html +227 -0
  36. package/src/renderer/renderer.js +3250 -0
  37. package/src/renderer/style.css +1559 -0
  38. package/tests/approval.test.js +56 -0
  39. package/tests/bg-jobs.test.js +315 -0
  40. package/tests/bus.test.js +46 -0
  41. package/tests/computeruse-context.test.js +69 -0
  42. package/tests/cron.test.js +95 -0
  43. package/tests/engine.test.js +140 -0
  44. package/tests/eval.test.js +91 -0
  45. package/tests/fallout.test.js +188 -0
  46. package/tests/llm.test.js +56 -0
  47. package/tests/memory.test.js +33 -0
  48. package/tests/memoryloop.test.js +26 -0
  49. package/tests/notegen.test.js +63 -0
  50. package/tests/owner.test.js +32 -0
  51. package/tests/python.test.js +75 -0
  52. package/tests/scenarios.json +81 -0
  53. package/tests/sessioncode.test.js +50 -0
  54. package/tests/setup.js +9 -0
  55. package/tests/tokens.test.js +42 -0
  56. package/tests/tools.test.js +84 -0
  57. package/tests/usage.test.js +44 -0
  58. package/tests/v11.test.js +76 -0
  59. package/tests/watchers.test.js +206 -0
  60. package/tests/watext.test.js +53 -0
  61. package/tests/whatsapp.test.js +103 -0
  62. 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()