beast-agent 0.30.0 → 1.0.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 (46) hide show
  1. package/package.json +6 -3
  2. package/src/agent/engine.js +463 -21
  3. package/src/agent/llm.js +52 -3
  4. package/src/agent/obscura.js +26 -10
  5. package/src/agent/skills.js +2 -2
  6. package/src/agent/tools.js +519 -7
  7. package/src/main.js +28 -13
  8. package/src/renderer/i18n.js +7 -7
  9. package/src/renderer/index.html +5 -2
  10. package/src/renderer/renderer.js +154 -5
  11. package/src/renderer/style.css +45 -4
  12. package/.env.example +0 -8
  13. package/config.example.yaml +0 -39
  14. package/eng.traineddata +0 -0
  15. package/scripts/fix-electron.js +0 -126
  16. package/scripts/release.js +0 -121
  17. package/scripts/swap-electron.js +0 -40
  18. package/store/skills.json +0 -5
  19. package/tests/approval.test.js +0 -56
  20. package/tests/bg-jobs.test.js +0 -424
  21. package/tests/bots-name.test.js +0 -42
  22. package/tests/bus.test.js +0 -46
  23. package/tests/computeruse-context.test.js +0 -69
  24. package/tests/cron.test.js +0 -95
  25. package/tests/engine.test.js +0 -203
  26. package/tests/eval.test.js +0 -91
  27. package/tests/fallout.test.js +0 -188
  28. package/tests/llm.test.js +0 -205
  29. package/tests/memory.test.js +0 -33
  30. package/tests/memoryloop.test.js +0 -26
  31. package/tests/notegen.test.js +0 -63
  32. package/tests/obscura.test.js +0 -124
  33. package/tests/owner.test.js +0 -32
  34. package/tests/python.test.js +0 -76
  35. package/tests/research.test.js +0 -116
  36. package/tests/scenarios.json +0 -81
  37. package/tests/sessioncode.test.js +0 -50
  38. package/tests/setup.js +0 -9
  39. package/tests/tokens.test.js +0 -42
  40. package/tests/tools.test.js +0 -84
  41. package/tests/usage.test.js +0 -44
  42. package/tests/v11.test.js +0 -76
  43. package/tests/watchers.test.js +0 -206
  44. package/tests/watext.test.js +0 -53
  45. package/tests/whatsapp.test.js +0 -103
  46. package/tests/wherewasi.test.js +0 -40
package/src/agent/llm.js CHANGED
@@ -70,6 +70,38 @@ function friendlyError(status, statusText, detail) {
70
70
  return msg;
71
71
  }
72
72
 
73
+ /* opencode cache disiplini (provider/transform.ts:1262-1276 port): destekleyen
74
+ sağlayıcılara oturum-sabit önbellek anahtarı gönderilir — aynı önek tekrar
75
+ kullanıldığında girdi tokenleri cache'ten okunur (~%90 ucuz + hızlı TTFT) */
76
+ const CACHE_KEY_PROVIDER_RE = /openai|azure|xai|deepseek|cerebras|deepinfra|mistral|venice/i;
77
+ const CACHE_KEY_MODEL_RE = /openai|gpt-|^o[134]|xai|grok|deepseek|cerebras|deepinfra|mistral|venice/i;
78
+ function wantsCacheKey(sel) {
79
+ if (!sel) return false;
80
+ return (
81
+ CACHE_KEY_PROVIDER_RE.test(String(sel.providerId || '')) ||
82
+ CACHE_KEY_MODEL_RE.test(String(sel.model || ''))
83
+ );
84
+ }
85
+
86
+ /* Retry-After başlığı: saniye ("2"), milisaniye ("120ms" / retry-after-ms)
87
+ ya da HTTP-tarih olabilir (opencode session/retry.ts port) */
88
+ function parseRetryAfter(v) {
89
+ if (v == null) return null;
90
+ const s = String(v).trim();
91
+ if (!s) return null;
92
+ const ms = /^(\d+)\s*ms$/i.exec(s);
93
+ if (ms) return Number(ms[1]);
94
+ if (/^\d+(\.\d+)?$/.test(s)) return Number(s) * 1000;
95
+ const d = Date.parse(s);
96
+ if (!Number.isNaN(d)) return Math.max(0, d - Date.now());
97
+ return null;
98
+ }
99
+
100
+ const RETRY_AFTER_CAP_MS = 30000; /* opencode retry.ts:39 — headersız bekleme tavanı */
101
+ function clampMs(v) {
102
+ return Math.min(RETRY_AFTER_CAP_MS, Math.max(0, Number(v) || 0));
103
+ }
104
+
73
105
  function sleep(ms, signal) {
74
106
  return new Promise((resolve, reject) => {
75
107
  const t = setTimeout(resolve, ms);
@@ -112,9 +144,14 @@ async function withRetries(fn, { signal, onRetry } = {}) {
112
144
  try {
113
145
  onRetry && onRetry(attempt, status);
114
146
  } catch {}
115
- const wait = netErr
116
- ? NET_BACKOFF[Math.min(attempt - 1, NET_BACKOFF.length - 1)]
117
- : 800 * Math.pow(2, attempt - 1);
147
+ /* sağlayıcı retry-after dediye: backoff yerine ona uy (30 sn tavan);
148
+ opencode session/retry.ts:26-31 ile aynı politika */
149
+ let wait;
150
+ if (e.retryAfterMs) wait = clampMs(e.retryAfterMs);
151
+ else
152
+ wait = netErr
153
+ ? NET_BACKOFF[Math.min(attempt - 1, NET_BACKOFF.length - 1)]
154
+ : 800 * Math.pow(2, attempt - 1);
118
155
  await sleep(wait, signal);
119
156
  }
120
157
  }
@@ -133,6 +170,10 @@ async function openChat(sel, body, { stream, signal, omitReasoning } = {}) {
133
170
  if (body.reasoningEffort && !omitReasoning) {
134
171
  payload.reasoning_effort = String(body.reasoningEffort);
135
172
  }
173
+ /* prompt cache anahtarı: oturum başına sabit → sağlayıcı önek önbelleği tutar */
174
+ if (body.cacheKey && wantsCacheKey(sel)) {
175
+ payload.prompt_cache_key = String(body.cacheKey);
176
+ }
136
177
  return fetch(sel.url, {
137
178
  method: 'POST',
138
179
  signal,
@@ -180,6 +221,9 @@ async function streamOnce(sel, body, { signal, onDelta, onRetry } = {}, omitReas
180
221
  } catch {}
181
222
  const err = new Error(friendlyError(r.status, r.statusText, detail));
182
223
  err.status = r.status;
224
+ err.retryAfterMs = parseRetryAfter(
225
+ r.headers && (r.headers.get('retry-after-ms') || r.headers.get('retry-after'))
226
+ );
183
227
  throw err;
184
228
  }
185
229
  return r;
@@ -317,6 +361,9 @@ async function chatOnce(sel, body, { signal, onRetry } = {}) {
317
361
  } catch {}
318
362
  const err = new Error(friendlyError(r.status, r.statusText, detail));
319
363
  err.status = r.status;
364
+ err.retryAfterMs = parseRetryAfter(
365
+ r.headers && (r.headers.get('retry-after-ms') || r.headers.get('retry-after'))
366
+ );
320
367
  throw err;
321
368
  }
322
369
  return r;
@@ -343,4 +390,6 @@ module.exports = {
343
390
  sumUsage,
344
391
  setNetProbe,
345
392
  isNetworkError,
393
+ wantsCacheKey,
394
+ parseRetryAfter,
346
395
  };
@@ -23,6 +23,12 @@ const FETCH_TIMEOUT_MS = 25000;
23
23
  /* content-length gelmezse yüzde tahmini için yaklaşık boyut (stealth zip ≈74 MB) */
24
24
  const EST_ZIP_BYTES = 74 * 1024 * 1024;
25
25
 
26
+ /* Beast Agent PAKETİNE gömülü zip (vendor/) — varsa HİÇ indirme yapılmaz */
27
+ function bundledZip() {
28
+ const p = path.join(__dirname, '..', '..', 'vendor', 'obscura.zip');
29
+ try { return fs.existsSync(p) ? p : null; } catch { return null; }
30
+ }
31
+
26
32
  function obscuraDir() {
27
33
  const base = process.env.APPDATA || path.join(os.homedir(), 'AppData', 'Roaming');
28
34
  return path.join(base, 'beast', 'obscura');
@@ -130,8 +136,8 @@ function psExpand(zipPath, destDir) {
130
136
  });
131
137
  }
132
138
 
133
- /* Obscura'yı kur / güncelle (yeniden indirip üzerine yazar).
134
- onProgress({pct, phase}) — 1-88 indirme, 89-96 açma, 97-99 doğrulama. */
139
+ /* Obscura'yı kur / güncelle. SIRA: pakete gömülü vendor zip'i (network YOK,
140
+ anında) → yoksa GitHub'dan indir. onProgress({pct, phase}). */
135
141
  async function installObscura(signal, onProgress) {
136
142
  const tick = (pct, phase) => {
137
143
  if (typeof onProgress === 'function') {
@@ -142,14 +148,23 @@ async function installObscura(signal, onProgress) {
142
148
  tick(0, 'hazırlanıyor');
143
149
  const dest = obscuraDir();
144
150
  fs.mkdirSync(dest, { recursive: true });
145
- const zipPath = path.join(os.tmpdir(), 'beast-obscura.zip');
146
- const buf = await httpsDownload(RELEASE_BASE + WINDOWS_ZIP, 5, signal, onProgress);
147
- tick(89, 'kuruluyor');
148
- fs.writeFileSync(zipPath, buf);
149
- tick(90, 'kuruluyor');
150
- const ok = await psExpand(zipPath, dest);
151
- try { fs.unlinkSync(zipPath); } catch {}
152
- tick(97, 'doğrulanıyor');
151
+ const bundled = bundledZip();
152
+ let ok = false;
153
+ if (bundled) {
154
+ /* PAKET İÇİ kurulum — indirme yok, saniyeler sürer */
155
+ tick(30, 'kuruluyor');
156
+ ok = await psExpand(bundled, dest);
157
+ tick(97, 'doğrulanıyor');
158
+ } else {
159
+ const zipPath = path.join(os.tmpdir(), 'beast-obscura.zip');
160
+ const buf = await httpsDownload(RELEASE_BASE + WINDOWS_ZIP, 5, signal, onProgress);
161
+ tick(89, 'kuruluyor');
162
+ fs.writeFileSync(zipPath, buf);
163
+ tick(90, 'kuruluyor');
164
+ ok = await psExpand(zipPath, dest);
165
+ try { fs.unlinkSync(zipPath); } catch {}
166
+ tick(97, 'doğrulanıyor');
167
+ }
153
168
  if (!ok || !obscuraInstalled()) {
154
169
  return { ok: false, error: 'obscura kurulumu başarısız (zip açılamadı)' };
155
170
  }
@@ -265,6 +280,7 @@ module.exports = {
265
280
  ENGINE: 'obscura',
266
281
  RELEASE_BASE,
267
282
  WINDOWS_ZIP,
283
+ bundledZip,
268
284
  obscuraDir,
269
285
  obscuraExe,
270
286
  obscuraInstalled,
@@ -1,4 +1,4 @@
1
- 'use strict';
1
+ 'use strict';
2
2
 
3
3
  /* Beast skills: %APPDATA%\beast\skills\**\SKILL.md
4
4
  Only name+description go into the system prompt (few tokens).
@@ -236,7 +236,7 @@ Gerçek Chromium olduğu için Google'a bot koruması uygulamaz. Arama aep=1 ile
236
236
 
237
237
  ## 2. Obscura (stealth headless — DuckDuckGo)
238
238
 
239
- Rust tabanlı gizli tarayıcı: anti-detect parmak izi + V8 JS. Kurulu değilse uygulama açılışında OTOMATİK indirilir (%APPDATA%\\beast\\obscura). Varsayılan AKTİF — tarayıcı engellenirse bot korumasını aşarak DuckDuckGo'dan sonuç getirir.
239
+ Rust tabanlı gizli tarayıcı: anti-detect parmak izi + V8 JS. Beast Agent PAKETİNDE hazır gelir ilk açılışta %APPDATA%\\beast\\obscura'ya açılır (indirme yok). Varsayılan AKTİF — tarayıcı engellenirse bot korumasını aşarak DuckDuckGo'dan sonuç getirir.
240
240
 
241
241
  ## 3. TinyFish API (anahtar varsa)
242
242