beast-agent 0.20.0 → 0.21.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/package.json +1 -1
- package/scripts/release.js +21 -34
- package/src/agent/engine.js +223 -40
- package/src/main.js +232 -3
- package/src/preload.js +10 -0
- package/src/renderer/i18n.js +20 -0
- package/src/renderer/index.html +45 -1
- package/src/renderer/renderer.js +796 -2
- package/src/renderer/style.css +524 -2
package/package.json
CHANGED
package/scripts/release.js
CHANGED
|
@@ -1,18 +1,17 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
/* Beast Agent — Dağıtım / Senkron Sistemi
|
|
4
|
-
Tek komutla tam sürüm
|
|
5
|
-
npm run release → otomatik patch bump (0.
|
|
6
|
-
npm run release -- minor → 0.
|
|
7
|
-
npm release -- 0.
|
|
4
|
+
Tek komutla tam sürüm akışı (EXE/INSTALLER YOK — npm + kaynak dağıtımı):
|
|
5
|
+
npm run release → otomatik patch bump (0.20.0 → 0.20.1)
|
|
6
|
+
npm run release -- minor → 0.21.0
|
|
7
|
+
npm run release -- 0.22.0 → belirli sürüm
|
|
8
8
|
|
|
9
9
|
Adımlar:
|
|
10
10
|
1) package.json sürümü yükselt
|
|
11
11
|
2) commit + tag + push (main + tag)
|
|
12
|
-
3)
|
|
13
|
-
4)
|
|
14
|
-
5)
|
|
15
|
-
6) OneDrive yedek klasörüne kaynak kopyası (beast-v< sürüm >)
|
|
12
|
+
3) GitHub Release (yalnız kaynak — exe/asset yüklenmez)
|
|
13
|
+
4) npm publish (NPM_TOKEN env var ise; yoksa atlar ve uyarır)
|
|
14
|
+
5) OneDrive yedek klasörüne kaynak kopyası (beast-v< sürüm >)
|
|
16
15
|
*/
|
|
17
16
|
|
|
18
17
|
const fs = require('fs');
|
|
@@ -29,7 +28,8 @@ const warn = (msg) => console.log(' \x1b[33m!\x1b[0m ' + msg);
|
|
|
29
28
|
const fail = (msg) => { console.error(' \x1b[31m✗ ' + msg + '\x1b[0m'); process.exit(1); };
|
|
30
29
|
|
|
31
30
|
function run(cmd, opts = {}) {
|
|
32
|
-
|
|
31
|
+
/* stdio:'inherit' iken execSync null döner — trim patlamasın */
|
|
32
|
+
return String(execSync(cmd, { cwd: ROOT, stdio: opts.inherit ? 'inherit' : 'pipe', encoding: 'utf8', ...opts }) ?? '').trim();
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
function bump(version, kind) {
|
|
@@ -51,13 +51,13 @@ const tag = 'v' + next;
|
|
|
51
51
|
console.log(`\x1b[1mBeast Agent release: ${current} → ${next}\x1b[0m`);
|
|
52
52
|
|
|
53
53
|
/* ---------- 1) sürüm bump ---------- */
|
|
54
|
-
step('1/
|
|
54
|
+
step('1/5 sürüm yükselt: ' + current + ' → ' + next);
|
|
55
55
|
pkg.version = next;
|
|
56
56
|
fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 4) + '\n');
|
|
57
57
|
ok('package.json → ' + next);
|
|
58
58
|
|
|
59
59
|
/* ---------- 2) commit + push ---------- */
|
|
60
|
-
step('2/
|
|
60
|
+
step('2/5 git: commit + tag + push');
|
|
61
61
|
try {
|
|
62
62
|
run('git add -A');
|
|
63
63
|
run(`git commit -m "v${next}"`);
|
|
@@ -67,43 +67,30 @@ run('git push origin main');
|
|
|
67
67
|
run(`git push origin ${tag}`);
|
|
68
68
|
ok('pushed: main + ' + tag);
|
|
69
69
|
|
|
70
|
-
/* ---------- 3)
|
|
71
|
-
step('3/
|
|
72
|
-
run('npm run dist', { inherit: true });
|
|
73
|
-
const setupExe = path.join(ROOT, 'dist', `BeastAgent-Setup-${next}.exe`);
|
|
74
|
-
const portableExe = path.join(ROOT, 'dist', 'BeastAgent.exe');
|
|
75
|
-
if (!fs.existsSync(setupExe)) fail('setup exe bulunamadı: ' + setupExe);
|
|
76
|
-
if (!fs.existsSync(portableExe)) fail('portable exe bulunamadı: ' + portableExe);
|
|
77
|
-
ok('dist hazır: Setup + Portable');
|
|
78
|
-
|
|
79
|
-
/* ---------- 4) GitHub release ---------- */
|
|
80
|
-
step('4/6 GitHub Release ' + tag);
|
|
70
|
+
/* ---------- 3) GitHub Release (kaynak — exe yok) ---------- */
|
|
71
|
+
step('3/5 GitHub Release ' + tag);
|
|
81
72
|
const gh = process.env.GH || 'gh';
|
|
82
73
|
try {
|
|
83
74
|
const notes = [
|
|
84
75
|
`## Beast Agent ${tag}`,
|
|
85
76
|
'',
|
|
86
|
-
'-
|
|
87
|
-
'- \`BeastAgent.exe\` — portable',
|
|
88
|
-
'- \`npm i -g beast-agent\` — npm üzerinden',
|
|
77
|
+
'- \`npm i -g beast-agent@\`' + next,
|
|
89
78
|
'',
|
|
79
|
+
'Dağıtım npm üzerinden yapılır — exe/installer sürümü kaldırıldı.',
|
|
90
80
|
'Tam değişiklik listesi: commit geçmişi.',
|
|
91
81
|
].join('\n');
|
|
92
82
|
const notesFile = path.join(ROOT, 'dist', 'release-notes.md');
|
|
83
|
+
fs.mkdirSync(path.dirname(notesFile), { recursive: true });
|
|
93
84
|
fs.writeFileSync(notesFile, notes);
|
|
94
|
-
const assets = [setupExe, setupExe + '.blockmap', portableExe, path.join(ROOT, 'dist', 'latest.yml')]
|
|
95
|
-
.filter((f) => fs.existsSync(f))
|
|
96
|
-
.map((f) => `"${f}"`)
|
|
97
|
-
.join(' ');
|
|
98
85
|
try { run(`${gh} release delete ${tag} --yes --cleanup-tag`); } catch {}
|
|
99
|
-
run(`${gh} release create ${tag}
|
|
86
|
+
run(`${gh} release create ${tag} --title "Beast Agent ${tag}" --notes-file "${notesFile}"`, { inherit: true });
|
|
100
87
|
ok('release yayında: https://github.com/algokodcom/beast-agent/releases/tag/' + tag);
|
|
101
88
|
} catch (e) {
|
|
102
89
|
fail('GitHub release: ' + String(e));
|
|
103
90
|
}
|
|
104
91
|
|
|
105
|
-
/* ----------
|
|
106
|
-
step('5
|
|
92
|
+
/* ---------- 4) npm publish ---------- */
|
|
93
|
+
step('4/5 npm publish');
|
|
107
94
|
if (process.env.NPM_TOKEN) {
|
|
108
95
|
try {
|
|
109
96
|
run(`npm publish --//registry.npmjs.org/:_authToken=${process.env.NPM_TOKEN}`, { inherit: true });
|
|
@@ -116,8 +103,8 @@ if (process.env.NPM_TOKEN) {
|
|
|
116
103
|
warn('Elle: set NPM_TOKEN=<token> && npm publish');
|
|
117
104
|
}
|
|
118
105
|
|
|
119
|
-
/* ----------
|
|
120
|
-
step('
|
|
106
|
+
/* ---------- 5) OneDrive kaynak yedeği ---------- */
|
|
107
|
+
step('5/5 OneDrive yedek (beast-v' + next + ')');
|
|
121
108
|
try {
|
|
122
109
|
const dest = path.join(ONE_DRIVE_DIR, 'beast-v' + next);
|
|
123
110
|
fs.mkdirSync(dest, { recursive: true });
|
package/src/agent/engine.js
CHANGED
|
@@ -413,32 +413,66 @@ class Engine {
|
|
|
413
413
|
return per || this.limits.default || 0;
|
|
414
414
|
}
|
|
415
415
|
|
|
416
|
-
/*
|
|
417
|
-
|
|
418
|
-
|
|
416
|
+
/* Tek mesajı token bütçesine göre kes: string/array içerik kırpılır,
|
|
417
|
+
tool_calls korunur (araç zinciri bozulmasın) */
|
|
418
|
+
_truncateMsgTokens(m, tokenBudget) {
|
|
419
|
+
if (!m) return m;
|
|
420
|
+
const cap = (txt) =>
|
|
421
|
+
String(txt).slice(0, Math.max(200, tokenBudget * 4)) + '\n…[girdi limiti için kırpıldı]';
|
|
422
|
+
if (typeof m.content === 'string') return { ...m, content: cap(m.content) };
|
|
423
|
+
if (Array.isArray(m.content)) {
|
|
424
|
+
return {
|
|
425
|
+
...m,
|
|
426
|
+
content: m.content.map((p) =>
|
|
427
|
+
p && p.type === 'text' ? { ...p, text: cap(p.text) } : p
|
|
428
|
+
),
|
|
429
|
+
};
|
|
430
|
+
}
|
|
431
|
+
return m;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
/* Payload limiti aşıyorsa SERT şekilde sıkıştır: system korunur, sondan
|
|
435
|
+
bağlantı pencere alınır, en yeni mesaj tek başına bile taşarsa İÇERİĞİ
|
|
436
|
+
kırpılarak tutulur, hâlâ taşarsa en eskiler atılır. Kullanıcının son
|
|
437
|
+
mesajı asla sessizce düşürülmez. */
|
|
419
438
|
_compressPayload(payload, maxTokens, withNote) {
|
|
420
439
|
if (!Array.isArray(payload) || payload.length < 2) return payload;
|
|
421
440
|
const sys = payload[0];
|
|
422
441
|
const rest = payload.slice(1);
|
|
423
|
-
const
|
|
424
|
-
const
|
|
425
|
-
|
|
442
|
+
const cost = (m) => Math.ceil(estMsgTokens(m) * this.tokRatio);
|
|
443
|
+
const sysCost = cost(sys);
|
|
444
|
+
const over = (arr) => arr.reduce((a, m) => a + cost(m), 0) + sysCost > maxTokens;
|
|
445
|
+
if (!over(rest)) return payload;
|
|
446
|
+
|
|
447
|
+
const budget = Math.max(0, maxTokens - sysCost - 48);
|
|
448
|
+
|
|
449
|
+
/* 1) sondan geriye bağlantı pencere (kesintisiz — kronoloji korunur) */
|
|
426
450
|
const picked = [];
|
|
427
451
|
let used = 0;
|
|
428
452
|
for (let i = rest.length - 1; i >= 0; i--) {
|
|
429
|
-
const
|
|
430
|
-
if (used +
|
|
431
|
-
if (picked.length) break; // sığmayan eski mesajlar atılır
|
|
432
|
-
continue; // en yeni mesaj bile sığmıyorsa onu da at (aşağıda min. 1 tutulur)
|
|
433
|
-
}
|
|
453
|
+
const c = cost(rest[i]);
|
|
454
|
+
if (used + c > budget) break;
|
|
434
455
|
picked.unshift(rest[i]);
|
|
435
|
-
used +=
|
|
456
|
+
used += c;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
/* 2) hiçbir mesaj sığmadıysa: EN YENİ mesajı keserek tut */
|
|
460
|
+
if (!picked.length && rest.length) {
|
|
461
|
+
picked.push(this._truncateMsgTokens(rest[rest.length - 1], budget));
|
|
436
462
|
}
|
|
437
|
-
|
|
438
|
-
/* kopuk tool yanıtıyla başlama — assistant/tool_calls grubu bozulmasın */
|
|
463
|
+
|
|
464
|
+
/* 3) kopuk tool yanıtıyla başlama — assistant/tool_calls grubu bozulmasın */
|
|
439
465
|
while (picked.length && picked[0].role === 'tool') picked.shift();
|
|
440
|
-
if (!picked.length) picked.push(rest[rest.length - 1]);
|
|
441
|
-
|
|
466
|
+
if (!picked.length) picked.push(this._truncateMsgTokens(rest[rest.length - 1], budget));
|
|
467
|
+
|
|
468
|
+
/* 4) hâlâ limite taşıyorsa en eskilerini at */
|
|
469
|
+
while (picked.length > 1) {
|
|
470
|
+
const t = picked.reduce((a, m) => a + cost(m), 0) + sysCost + 48;
|
|
471
|
+
if (t <= maxTokens) break;
|
|
472
|
+
picked.shift();
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
if (picked.length >= rest.length && !over(rest)) return payload; // zaten sığıyordu
|
|
442
476
|
if (withNote) {
|
|
443
477
|
const dropped = rest.length - picked.length;
|
|
444
478
|
picked.unshift({
|
|
@@ -516,32 +550,53 @@ class Engine {
|
|
|
516
550
|
return list;
|
|
517
551
|
}
|
|
518
552
|
|
|
519
|
-
/* Adayları sırayla dene. Hata olursa durumu kaydet, zincirdeki sonrakine geç.
|
|
553
|
+
/* Adayları sırayla dene. Hata olursa durumu kaydet, zincirdeki sonrakine geç.
|
|
554
|
+
413/TPM "Requested N" hatası → gerçek token sayısı öğrenilir, tahmin
|
|
555
|
+
kalibre edilir ve aynı model BİR KEZ daha sıkı sıkıştırmayla denenir. */
|
|
520
556
|
async _streamWithFallbacks(session, payload, activeTools, signal, onDelta, sel, wasVision) {
|
|
521
557
|
const cands = this._chatCandidates(sel, wasVision);
|
|
522
558
|
let lastErr = null;
|
|
523
559
|
for (let i = 0; i < cands.length; i++) {
|
|
524
560
|
const c = cands[i];
|
|
561
|
+
let retried413 = false;
|
|
525
562
|
try {
|
|
526
|
-
/* provider bazlı girdi limiti: payload aşıyorsa sıkıştırılıp öyle gönderilir
|
|
563
|
+
/* provider bazlı girdi limiti: payload aşıyorsa sıkıştırılıp öyle gönderilir.
|
|
564
|
+
Tahmin: mesajlar + TOOLS şemaları (sağlayıcı onları da sayar) + %30 pay.
|
|
565
|
+
Hedef %15 tamponlu — katı sağlayıcılar (TPM/413) için limit aşılmasın */
|
|
527
566
|
let msgs = payload;
|
|
528
567
|
const lim = this._inputLimitFor(c);
|
|
568
|
+
const toolsCost =
|
|
569
|
+
activeTools && activeTools.length
|
|
570
|
+
? Math.ceil(estTokens(JSON.stringify(activeTools)) * 1.1)
|
|
571
|
+
: 0;
|
|
572
|
+
const rawNow = payload.reduce((a, m) => a + estMsgTokens(m), 0) + toolsCost;
|
|
529
573
|
if (lim > 0) {
|
|
530
|
-
const est = Math.ceil(
|
|
574
|
+
const est = Math.ceil(rawNow * this.tokRatio * 1.3);
|
|
531
575
|
if (est > lim) {
|
|
532
576
|
const before = msgs.length;
|
|
533
|
-
|
|
577
|
+
const target = Math.max(600, Math.round(lim * 0.85) - toolsCost);
|
|
578
|
+
msgs = this._compressPayload(payload, target, this.limits.compress);
|
|
534
579
|
if (i === 0) {
|
|
535
580
|
emitSafe(this, session.id, {
|
|
536
581
|
type: 'status',
|
|
537
582
|
status: `bağlam sıkıştırıldı: ~${est} token → limit ${lim} (${c.providerName}, ${before}→${msgs.length} mesaj)`,
|
|
538
583
|
});
|
|
539
584
|
}
|
|
585
|
+
/* system + araçlar tek başına limiti aşıyorsa kullanıcıya net söyle */
|
|
586
|
+
const floor = Math.ceil(
|
|
587
|
+
(estMsgTokens(msgs[0]) + toolsCost) * this.tokRatio
|
|
588
|
+
);
|
|
589
|
+
if (floor > lim) {
|
|
590
|
+
emitSafe(this, session.id, {
|
|
591
|
+
type: 'status',
|
|
592
|
+
status: `⚠ girdi limiti (${lim}) çok düşük: system + araç tanımları tek başına ~${floor} token — limiti en az ${Math.ceil(floor * 1.15)} yap`,
|
|
593
|
+
});
|
|
594
|
+
}
|
|
540
595
|
}
|
|
541
596
|
}
|
|
542
597
|
const res = await chatStream(
|
|
543
598
|
c,
|
|
544
|
-
{ messages: msgs, tools: activeTools, reasoningEffort: this.
|
|
599
|
+
{ messages: msgs, tools: activeTools, reasoningEffort: this._thinkEffortFor(session) },
|
|
545
600
|
{
|
|
546
601
|
signal,
|
|
547
602
|
onDelta,
|
|
@@ -571,6 +626,23 @@ class Engine {
|
|
|
571
626
|
if (e && (e.name === 'AbortError' || (signal && signal.aborted))) throw e;
|
|
572
627
|
lastErr = e;
|
|
573
628
|
const msgStr = String((e && e.message) || '');
|
|
629
|
+
/* 413 TPM: sağlayıcı gerçek istek boyutunu söylüyor → kalibre et,
|
|
630
|
+
aynı modeli yeniden sıkıştırıp BİR KEZ daha dene */
|
|
631
|
+
const m413 = /Requested\s+([\d,]+)/i.exec(msgStr) || (e && e.status === 413 ? [, 0] : null);
|
|
632
|
+
if (m413 && !retried413) {
|
|
633
|
+
retried413 = true;
|
|
634
|
+
const real = Number(String(m413[1] || '0').replace(/,/g, ''));
|
|
635
|
+
if (real > 0) {
|
|
636
|
+
const r = clamp(real / Math.max(1, rawNow), 0.75, 3);
|
|
637
|
+
if (r > this.tokRatio) this.tokRatio = r; /* tahmin yukarı kilitlenir */
|
|
638
|
+
emitSafe(this, session.id, {
|
|
639
|
+
type: 'status',
|
|
640
|
+
status: `⇩ 413 kalibrasyonu: gerçek ${real} token — daha sıkı sıkıştırıp yeniden deneniyor`,
|
|
641
|
+
});
|
|
642
|
+
}
|
|
643
|
+
i--; /* aynı adayı tekrar dene */
|
|
644
|
+
continue;
|
|
645
|
+
}
|
|
574
646
|
const imgIssue =
|
|
575
647
|
wasVision &&
|
|
576
648
|
([400, 404, 422].includes(e.status) ||
|
|
@@ -658,6 +730,13 @@ class Engine {
|
|
|
658
730
|
this.workspace = dir;
|
|
659
731
|
}
|
|
660
732
|
|
|
733
|
+
/* Oturum bazlı çalışma klasörü — Beast Code gibi özel oturumlar sol paneldeki
|
|
734
|
+
klasörde çalışabilsin diye (sess.workspace yoksa global workspace) */
|
|
735
|
+
_sessionWorkspace(sessionId) {
|
|
736
|
+
const s = sessionId ? this.cache.get(String(sessionId)) : null;
|
|
737
|
+
return (s && s.workspace) || this.workspace;
|
|
738
|
+
}
|
|
739
|
+
|
|
661
740
|
setThinkLevel(v) {
|
|
662
741
|
this.thinkLevel = Math.min(5, Math.max(0, Math.round(Number(v) || 0)));
|
|
663
742
|
return this.thinkLevel;
|
|
@@ -668,6 +747,13 @@ class Engine {
|
|
|
668
747
|
return lv.effort || null;
|
|
669
748
|
}
|
|
670
749
|
|
|
750
|
+
/* Oturum bazlı düşünme çabası: Beast Code hız modunda en fazla 'low' */
|
|
751
|
+
_thinkEffortFor(session) {
|
|
752
|
+
const e = this._thinkEffort();
|
|
753
|
+
if (!session || !session.bcCode) return e;
|
|
754
|
+
return e ? 'low' : null;
|
|
755
|
+
}
|
|
756
|
+
|
|
671
757
|
_thinkLabel() {
|
|
672
758
|
const lv = THINK_LEVELS[this.thinkLevel] || THINK_LEVELS[0];
|
|
673
759
|
return lv.label;
|
|
@@ -716,6 +802,27 @@ class Engine {
|
|
|
716
802
|
if (session.code) this._codeIndex.set(session.code, session.id);
|
|
717
803
|
}
|
|
718
804
|
|
|
805
|
+
/* Oturum dosyasındaki son 'msg' satırını (user) güncel içerikle değiştir —
|
|
806
|
+
yanıtsız kalmış user mesajıyla yeni mesaj birleştirildiğinde kullanılır */
|
|
807
|
+
_rewriteLastMsg(id, content) {
|
|
808
|
+
try {
|
|
809
|
+
const file = this._file(String(id));
|
|
810
|
+
const lines = fs.readFileSync(file, 'utf8').split('\n');
|
|
811
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
812
|
+
if (!lines[i].trim()) continue;
|
|
813
|
+
let r;
|
|
814
|
+
try { r = JSON.parse(lines[i]); } catch { continue; }
|
|
815
|
+
if (r.t === 'msg' && r.role === 'user') {
|
|
816
|
+
lines[i] = JSON.stringify({ t: 'msg', role: 'user', content: String(content || '') });
|
|
817
|
+
break;
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
const tmp = file + '.tmp';
|
|
821
|
+
fs.writeFileSync(tmp, lines.join('\n'));
|
|
822
|
+
fs.renameSync(tmp, file);
|
|
823
|
+
} catch {}
|
|
824
|
+
}
|
|
825
|
+
|
|
719
826
|
_load(id) {
|
|
720
827
|
if (this.cache.has(id)) return this.cache.get(id);
|
|
721
828
|
const file = this._file(id);
|
|
@@ -1001,6 +1108,28 @@ class Engine {
|
|
|
1001
1108
|
|
|
1002
1109
|
/* ---------- prompt assembly (the frugal part) ---------- */
|
|
1003
1110
|
|
|
1111
|
+
/* Beast Code (IDE paneli): VS Code hızında çalışsın diye SECMET prompt.
|
|
1112
|
+
Hafıza embedding araması, skills taraması, kişilik/kural blokları YOK —
|
|
1113
|
+
prompt kısa kalır → ilk token hızlı, tur maliyeti düşük. */
|
|
1114
|
+
buildBcSystem(session) {
|
|
1115
|
+
const nowD = new Date();
|
|
1116
|
+
const localDate = nowD.toLocaleDateString('tr-TR');
|
|
1117
|
+
const localTime = nowD.toLocaleTimeString('tr-TR', { hour: '2-digit', minute: '2-digit' });
|
|
1118
|
+
return (
|
|
1119
|
+
'Sen BEAST CODE\u2019sun — IDE panelinde çalışan hızlı bir kodlama ajanı. VS Code gibi çevik ol.\n' +
|
|
1120
|
+
`Çalışma klasörü: ${(session && session.workspace) || this.workspace}\n` +
|
|
1121
|
+
`Yerel zaman: ${localDate} ${localTime}\n` +
|
|
1122
|
+
'HIZ KURALLARI:\n' +
|
|
1123
|
+
'- İLK EYLEMİN daima todo_write olsun: işi 2-6 maddelik plana böl; her adım bitince status:"done" ile güncelle.\n' +
|
|
1124
|
+
'- Kodu ve dosyaları DOĞRUDAN write_file ile yaz/güncelle. Basit dosya oluşturma/düzenleme için asla Python scripti yazma; python_run yalnız gerçek hesap/veri işleme gerekiyorsa.\n' +
|
|
1125
|
+
'- Kurulum, test, build, git gibi işler için run_command kullan (Windows PowerShell ortamı).\n' +
|
|
1126
|
+
'- Bağımsız araç çağrılarını AYNI TURDA paralel ver.\n' +
|
|
1127
|
+
'- Dosyayı kullanıcı söylememişse list_dir ile yapıyı görüp kendin karar ver.\n' +
|
|
1128
|
+
'- Uzun açıklama yok: doğrudan çalış, bitince 1-3 satırlık kısa özet ver. Soru sorma, sohbet etme.\n' +
|
|
1129
|
+
FORMAT_RULES
|
|
1130
|
+
);
|
|
1131
|
+
}
|
|
1132
|
+
|
|
1004
1133
|
buildSystem(queryText, session) {
|
|
1005
1134
|
/* BOT OTURUMU: non-admin bota bağlıysa global Beast hafızası HIÇ girmez —
|
|
1006
1135
|
o botun kendi SOUL/USER/MEMORY dosyaları kullanılır (tam izolasyon) */
|
|
@@ -1041,6 +1170,7 @@ class Engine {
|
|
|
1041
1170
|
'# SKILLS\nKullanmadan önce ilgili SKILL.md dosyasını read_file ile oku.\n' + sk.join('\n')
|
|
1042
1171
|
);
|
|
1043
1172
|
}
|
|
1173
|
+
/* Beast Code (bcCode) oturumları buildBcSystem kullanır — buraya düşmez */
|
|
1044
1174
|
const nowD = new Date();
|
|
1045
1175
|
const localDate = nowD.toLocaleDateString('tr-TR');
|
|
1046
1176
|
const localTime = nowD.toLocaleTimeString('tr-TR', { hour: '2-digit', minute: '2-digit' });
|
|
@@ -1049,7 +1179,7 @@ class Engine {
|
|
|
1049
1179
|
tz = Intl.DateTimeFormat().resolvedOptions().timeZone || '';
|
|
1050
1180
|
} catch {}
|
|
1051
1181
|
parts.push(
|
|
1052
|
-
`# ORTAM\nWindows + PowerShell. Çalışma klasörü: ${this.workspace}\n` +
|
|
1182
|
+
`# ORTAM\nWindows + PowerShell. Çalışma klasörü: ${(session && session.workspace) || this.workspace}\n` +
|
|
1053
1183
|
`Yerel tarih: ${localDate} (${['Pazar','Pazartesi','Salı','Çarşamba','Perşembe','Cuma','Cumartesi'][nowD.getDay()]})\n` +
|
|
1054
1184
|
`Yerel saat: ${localTime}${tz ? ` (saat dilimi: ${tz})` : ''}\n` +
|
|
1055
1185
|
'Tarih/saat gerektiren her işte bu YEREL zamanı esas al; UTC varsayma, kendin dönüşüm yapma. Bu satırlar her mesajda güncellenir.\n' +
|
|
@@ -1327,12 +1457,29 @@ class Engine {
|
|
|
1327
1457
|
}
|
|
1328
1458
|
|
|
1329
1459
|
if (!String(typeof msg.content === 'string' ? msg.content : msg.content[0].text || '').trim()) return false;
|
|
1330
|
-
/* #12 kişilik kalibrasyonu: kullanıcı cümlelerini örnek havuzuna düşür */
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1460
|
+
/* #12 kişilik kalibrasyonu: kullanıcı cümlelerini örnek havuzuna düşür (Beast Code hariç — hız) */
|
|
1461
|
+
if (!s.bcCode) {
|
|
1462
|
+
try { memory.addStyleSample(this._plainText(msg)); } catch {}
|
|
1463
|
+
}
|
|
1464
|
+
|
|
1465
|
+
/* Önceki tur yanıtlanmadan kaldıysa (hata/durdurma sonrası artık user mesajı)
|
|
1466
|
+
katı sağlayıcılar art arda user mesajını reddeder: "messages illegal" (400).
|
|
1467
|
+
Yeni metni o mesajla BİRLEŞTİR — dosyadaki son satır da güncellenir. */
|
|
1468
|
+
const lastMsg = s.messages[s.messages.length - 1];
|
|
1469
|
+
if (
|
|
1470
|
+
lastMsg && lastMsg.role === 'user' &&
|
|
1471
|
+
typeof lastMsg.content === 'string' &&
|
|
1472
|
+
typeof msg.content === 'string'
|
|
1473
|
+
) {
|
|
1474
|
+
lastMsg.content = lastMsg.content + '\n' + msg.content;
|
|
1475
|
+
msg = lastMsg;
|
|
1476
|
+
this._rewriteLastMsg(s.id, lastMsg.content);
|
|
1477
|
+
} else {
|
|
1478
|
+
s.messages.push(msg);
|
|
1479
|
+
try {
|
|
1480
|
+
this._append(s, msg);
|
|
1481
|
+
} catch {}
|
|
1482
|
+
}
|
|
1336
1483
|
this.emit({ type: 'message', sessionId: s.id, message: msg });
|
|
1337
1484
|
this.emit({ type: 'sessions' });
|
|
1338
1485
|
this._run(s).catch(() => {});
|
|
@@ -1871,17 +2018,51 @@ class Engine {
|
|
|
1871
2018
|
_bgTrim(session) {
|
|
1872
2019
|
const max = Engine.BG_KEEP_MSGS;
|
|
1873
2020
|
const msgs = session.messages;
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
2021
|
+
/* bg işleri + Beast Code: uzun geçmiş payload'ı şişirip yavaşlatır */
|
|
2022
|
+
if ((!session.bgJob && !session.bcCode) || msgs.length <= max) return;
|
|
2023
|
+
let keep = msgs.slice(-max);
|
|
2024
|
+
/* GÜVENLİ SINIR: kesim bir assistant(tool_calls) + tool sonuç çiftini BÖLMESİN.
|
|
2025
|
+
Yetim 'tool' mesajı ya da sonuçları pencere dışında kalan tool_calls'lı
|
|
2026
|
+
asistan mesajı sağlayıcıda "messages parameter is illegal" (HTTP 400) verir. */
|
|
2027
|
+
while (keep.length) {
|
|
2028
|
+
const f = keep[0];
|
|
2029
|
+
if (f.role === 'tool') { keep.shift(); continue; }
|
|
2030
|
+
if (f.role === 'assistant' && Array.isArray(f.tool_calls) && f.tool_calls.length) {
|
|
2031
|
+
const need = f.tool_calls.length;
|
|
2032
|
+
let got = 0;
|
|
2033
|
+
for (let i = 1; i < keep.length && keep[i].role === 'tool' && got < need; i++) got++;
|
|
2034
|
+
if (got < need) { keep.shift(); continue; }
|
|
2035
|
+
}
|
|
2036
|
+
break;
|
|
2037
|
+
}
|
|
1877
2038
|
const firstUser = msgs.find((m) => m.role === 'user');
|
|
1878
2039
|
if (firstUser && !keep.includes(firstUser)) keep.unshift(firstUser);
|
|
1879
2040
|
session.messages = keep;
|
|
1880
2041
|
}
|
|
1881
2042
|
|
|
1882
2043
|
async _chatTurn(session, signal, onDelta, toolsList = TOOLS) {
|
|
2044
|
+
/* Beast Code: todo_write açıklaması "3+ adım" kısıtı içerir ve model küçük
|
|
2045
|
+
işlerde atlar — bcCode oturumunda HER işte İLK araç olacak şekilde değiştir */
|
|
2046
|
+
if (session && session.bcCode) {
|
|
2047
|
+
toolsList = toolsList.map((t) =>
|
|
2048
|
+
t && t.function && t.function.name === 'todo_write'
|
|
2049
|
+
? {
|
|
2050
|
+
...t,
|
|
2051
|
+
function: {
|
|
2052
|
+
...t.function,
|
|
2053
|
+
description:
|
|
2054
|
+
'Replace the visible task checklist for this chat. Beast Code session: ALWAYS call this tool as your VERY FIRST action for EVERY job (even tiny 1-step jobs) BEFORE any text or other tool, then update statuses (status:"done") as you complete each step. Keep titles short, verb-first.',
|
|
2055
|
+
},
|
|
2056
|
+
}
|
|
2057
|
+
: t
|
|
2058
|
+
);
|
|
2059
|
+
}
|
|
1883
2060
|
const promptText = this._lastUserText(session);
|
|
1884
|
-
let system = session.bgJob
|
|
2061
|
+
let system = session.bgJob
|
|
2062
|
+
? this.buildBgSystem(session)
|
|
2063
|
+
: session.bcCode
|
|
2064
|
+
? this.buildBcSystem(session)
|
|
2065
|
+
: this.buildSystem(promptText, session);
|
|
1885
2066
|
// Granül izin: oturumun yetki seviyesine göre araç seti daraltılır
|
|
1886
2067
|
const perm = this.sessionPermFor(session.id);
|
|
1887
2068
|
const allowedSet = PERM_TOOL_SETS[perm] || null;
|
|
@@ -1943,8 +2124,8 @@ class Engine {
|
|
|
1943
2124
|
if (actual > 0) {
|
|
1944
2125
|
const predicted = this._payloadTokens(payload);
|
|
1945
2126
|
if (predicted > 50) {
|
|
1946
|
-
const r = clamp(actual / predicted, 0.
|
|
1947
|
-
this.tokRatio = clamp(this.tokRatio * 0.7 + r * 0.3, 0.
|
|
2127
|
+
const r = clamp(actual / predicted, 0.75, 3);
|
|
2128
|
+
this.tokRatio = clamp(this.tokRatio * 0.7 + r * 0.3, 0.75, 3);
|
|
1948
2129
|
}
|
|
1949
2130
|
}
|
|
1950
2131
|
return res;
|
|
@@ -1975,8 +2156,10 @@ class Engine {
|
|
|
1975
2156
|
|
|
1976
2157
|
if (!res.toolCalls || !res.toolCalls.length) {
|
|
1977
2158
|
// cevap tamam — pencereden düşecek kısmın oturum notlarını güncelle
|
|
1978
|
-
/* #21 bg ajanı: görev sonu ekstra LLM çağrıları YOK — hızlı kapansın
|
|
1979
|
-
|
|
2159
|
+
/* #21 bg ajanı: görev sonu ekstra LLM çağrıları YOK — hızlı kapansın.
|
|
2160
|
+
Beast Code (bcCode) oturumları da aynı şekilde ANINDA kapansın:
|
|
2161
|
+
not/hafıza/skill yansıtma çağrıları yapılmaz → done hemen gelir */
|
|
2162
|
+
if (!session.bgJob && !session.bcCode) {
|
|
1980
2163
|
const r = await this._updateSessionNotes(session, ctrl.signal);
|
|
1981
2164
|
if (r && r.ok) {
|
|
1982
2165
|
emitSafe(this, sid, { type: 'status', status: `oturum notları güncellendi (${session.code || ''})` });
|
|
@@ -1985,13 +2168,13 @@ class Engine {
|
|
|
1985
2168
|
}
|
|
1986
2169
|
}
|
|
1987
2170
|
/* otomatik memory döngüsü: kalıcı değerli bilgiyi MEMORY.md'ye düşür */
|
|
1988
|
-
if (!ctrl.signal.aborted && !session.bgJob) {
|
|
2171
|
+
if (!ctrl.signal.aborted && !session.bgJob && !session.bcCode) {
|
|
1989
2172
|
try {
|
|
1990
2173
|
await this._autoMemory(session, ctrl.signal);
|
|
1991
2174
|
} catch {}
|
|
1992
2175
|
}
|
|
1993
2176
|
/* deneyimden skill doğurma (#2): 5+ yeni araç çağrısı biriktiyse yansıt */
|
|
1994
|
-
if (this.reflection.enabled && !ctrl.signal.aborted && !session.bgJob) {
|
|
2177
|
+
if (this.reflection.enabled && !ctrl.signal.aborted && !session.bgJob && !session.bcCode) {
|
|
1995
2178
|
try {
|
|
1996
2179
|
const made = await this._maybeReflectSkill(session);
|
|
1997
2180
|
if (made) emitSafe(this, sid, { type: 'status', status: `skill taslağı doğdu: ${made}` });
|
|
@@ -2625,7 +2808,7 @@ class Engine {
|
|
|
2625
2808
|
}
|
|
2626
2809
|
if (!r || !r.ok || !(r.results || []).length) {
|
|
2627
2810
|
try {
|
|
2628
|
-
r = JSON.parse(await tools.exec('web_search', args, { cwd: this.
|
|
2811
|
+
r = JSON.parse(await tools.exec('web_search', args, { cwd: this._sessionWorkspace(sessionId), signal }));
|
|
2629
2812
|
} catch {}
|
|
2630
2813
|
}
|
|
2631
2814
|
return JSON.stringify(r || { ok: false, error: 'web arama başarısız — tüm motorlar boş döndü' });
|
|
@@ -2672,7 +2855,7 @@ class Engine {
|
|
|
2672
2855
|
name === 'web_search' || name === 'http_fetch' || name === 'python_run')) {
|
|
2673
2856
|
return JSON.stringify({ ok: false, error: `unknown tool ${name}` });
|
|
2674
2857
|
}
|
|
2675
|
-
return await tools.exec(name, args, { cwd: this.
|
|
2858
|
+
return await tools.exec(name, args, { cwd: this._sessionWorkspace(sessionId), signal });
|
|
2676
2859
|
} catch (e) {
|
|
2677
2860
|
return JSON.stringify({ ok: false, error: String((e && e.message) || e) });
|
|
2678
2861
|
}
|