beast-agent 2.38.4 → 2.40.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/src/agent/bots.js +66 -0
- package/src/agent/customtools.js +52 -2
- package/src/agent/defaulttools/mt5_barlar2/run.js +188 -0
- package/src/agent/defaulttools/mt5_barlar2/tool.json +23 -0
- package/src/agent/defaulttools/mt5_bekleyen/run.js +100 -0
- package/src/agent/defaulttools/mt5_bekleyen/tool.json +17 -0
- package/src/agent/defaulttools/mt5_durum/run.js +93 -0
- package/src/agent/defaulttools/mt5_durum/tool.json +10 -0
- package/src/agent/defaulttools/mt5_emir/run.js +98 -0
- package/src/agent/defaulttools/mt5_emir/tool.json +17 -0
- package/src/agent/defaulttools/mt5_emir_iptal/run.js +90 -0
- package/src/agent/defaulttools/mt5_emir_iptal/tool.json +12 -0
- package/src/agent/defaulttools/mt5_fiyat/run.js +87 -0
- package/src/agent/defaulttools/mt5_fiyat/tool.json +16 -0
- package/src/agent/defaulttools/mt5_gecmis/run.js +87 -0
- package/src/agent/defaulttools/mt5_gecmis/tool.json +12 -0
- package/src/agent/defaulttools/mt5_kapat/run.js +92 -0
- package/src/agent/defaulttools/mt5_kapat/tool.json +13 -0
- package/src/agent/defaulttools/mt5_m15_m5/m15m5.py +60 -0
- package/src/agent/defaulttools/mt5_m15_m5/run.js +73 -0
- package/src/agent/defaulttools/mt5_m15_m5/tool.json +10 -0
- package/src/agent/defaulttools/mt5_pozisyon_gecmis/run.js +144 -0
- package/src/agent/defaulttools/mt5_pozisyon_gecmis/tool.json +12 -0
- package/src/agent/defaulttools/mt5_shot/run.js +428 -0
- package/src/agent/defaulttools/mt5_shot/tool.json +20 -0
- package/src/agent/defaulttools/mt5_sltp/run.js +92 -0
- package/src/agent/defaulttools/mt5_sltp/tool.json +14 -0
- package/src/agent/engine.js +259 -47
- package/src/agent/financetools.js +52 -0
- package/src/agent/mt5/BeastFinance.mq5 +427 -0
- package/src/agent/mt5/BeastShot.tpl +0 -0
- package/src/agent/mt5setup.js +542 -0
- package/src/agent/scripts/mt5_bridge.py +112 -0
- package/src/agent/seeds/mql5/SKILL.md +27 -2
- package/src/agent/seeds/tool-yazma/SKILL.md +6 -4
- package/src/main.js +233 -13
- package/src/preload.js +1 -0
- package/src/renderer/index.html +18 -5
- package/src/renderer/renderer.js +170 -37
- package/src/renderer/style.css +45 -17
package/src/agent/engine.js
CHANGED
|
@@ -132,15 +132,16 @@ const PERM_TOOL_SETS = {
|
|
|
132
132
|
'web_search', 'http_fetch', 'webfetch', 'deep_search',
|
|
133
133
|
'browser_open', 'browser_read', 'browser_snapshot', 'browser_screenshot',
|
|
134
134
|
'browser_click', 'browser_type', 'browser_press', 'browser_scroll', 'browser_select',
|
|
135
|
-
'ocr_read',
|
|
135
|
+
'ocr_read', 'tool_request',
|
|
136
136
|
]),
|
|
137
137
|
read: new Set([
|
|
138
138
|
'web_search', 'http_fetch', 'webfetch', 'deep_search',
|
|
139
139
|
'browser_open', 'browser_read', 'browser_snapshot',
|
|
140
140
|
'list_dir', 'read_file', 'grep', 'glob',
|
|
141
141
|
'git_diff_review', 'repo_map', 'repo_symbols', 'xlsx_read',
|
|
142
|
+
'tool_request',
|
|
142
143
|
]),
|
|
143
|
-
chat: new Set([]), //
|
|
144
|
+
chat: new Set(['tool_request']), // sohbet + tool devri
|
|
144
145
|
};
|
|
145
146
|
const PERM_LEVELS = ['all', 'web', 'read', 'chat'];
|
|
146
147
|
|
|
@@ -320,6 +321,8 @@ class Engine {
|
|
|
320
321
|
this.browser = opts.browser || null; // dahili tarayıcı kancaları
|
|
321
322
|
this.fileSend = opts.fileSend || null; // #26 dosya gönderim köprüsü (chat/WA)
|
|
322
323
|
this.notifyOwnerFail = opts.notifyOwnerFail !== false; // #25 hata mail bildirimi (runtime /notify)
|
|
324
|
+
/* ENTEGRASYON BİLDİRİMİ: tool yazım/doğrulama adımları WA/TG/Discord'a düşer */
|
|
325
|
+
this.integrationNotify = typeof opts.integrationNotify === 'function' ? opts.integrationNotify : null;
|
|
323
326
|
this.reminders = opts.reminders || null; // hatırlatıcı kancası (main enjekte eder)
|
|
324
327
|
this.watchers = opts.watchers || null; // arka plan izleyici köprüsü (main enjekte eder)
|
|
325
328
|
/* opencode permission Service (birebir port): ask/reply — once|always|reject.
|
|
@@ -399,6 +402,7 @@ class Engine {
|
|
|
399
402
|
if (nrBoot.unref) nrBoot.unref();
|
|
400
403
|
skills.seedIfEmpty();
|
|
401
404
|
agentdefs.seedIfEmpty();
|
|
405
|
+
try { customtools.seedDefaults(); } catch {} // varsayılan MT5 toolları (mt5_shot, mt5_barlar2, ...) — tüm oturumlara açılır
|
|
402
406
|
}
|
|
403
407
|
|
|
404
408
|
/* ---------- opencode agent.ts port: özel ajanlar ---------- */
|
|
@@ -1915,9 +1919,11 @@ class Engine {
|
|
|
1915
1919
|
risk:
|
|
1916
1920
|
'ROL: RİSK AJANI 🛡 — portföyün RİSK GÖZCÜSÜSÜN, İşlem AÇMAZSIN (mt5_trade/mt5_pending/mt5_close KULLANMA). Her turda: hesap + pozisyonlar + marj kullanımı → kaldıraç/exposure değerlendirmesi; SL\u2019siz pozisyon, limit aşımı, tek yönlü birikme, günlük kayıp hızı risklerini raporla; net düzeltme önerisi ver (hangi pozisyon küçültülmeli/kapatılmalı).',
|
|
1917
1921
|
technic:
|
|
1918
|
-
'ROL: TEKNİK ANALİZ AJANI 📊 — fiyat yapısı uzmanısın, İşlem AÇMAZSIN (mt5_trade/mt5_pending/mt5_close KULLANMA). Her turda odak semboller için: trend/yapı, destek-direnç bölgeleri, momentum (mt5_market + mt5_history verisiyle); sembol başına AL/SAT/BEKLE + giriş/SL/TP fikri üret — trader bu öneriyi işleme çevirir.',
|
|
1922
|
+
'ROL: TEKNİK ANALİZ AJANI 📊 — fiyat yapısı uzmanısın, İşlem AÇMAZSIN (mt5_trade/mt5_pending/mt5_close KULLANMA). Her turda odak semboller için: trend/yapı, destek-direnç bölgeleri, momentum (mt5_market + mt5_history verisiyle); sembol başına AL/SAT/BEKLE + giriş/SL/TP fikri üret — trader bu öneriyi işleme çevirir. Bulgularını mt5_ea action:"note" ile grafiğe ÇİZ (destek/direnç/SL/TP seviyeleri) ve tool__mt5_shot ile seviyelerin göründüğünü teyit et; önemli seviyeleri görselle birlikte agent_dm ile trader\'a/ekibe ilet — grafik üzerinde ortak karar alın.',
|
|
1919
1923
|
macro:
|
|
1920
1924
|
'ROL: MAKRO AJANI 🌍 — büyük resim uzmanısın, İşlem AÇMAZSIN (mt5_trade/mt5_pending/mt5_close KULLANMA). Her turda web_search ile güncel makro manşetleri + ekonomik takvim riskleri (faiz, CPI, jeopolitik); DXY/altın/petrol bağıntılarını odak sembollere çevir; sembol başına yön eğilimi + TEMKİN/BEKLE notu ver.',
|
|
1925
|
+
visual:
|
|
1926
|
+
'ROL: GÖRSEL ANALİZ AJANI 👁 — grafik/ekran görüntüsü uzmanısın, İşlem AÇMAZSIN (mt5_trade/mt5_pending/mt5_close KULLANMA). MT5 grafiği için ÖNCE tool__mt5_shot kullan (BeastFinance EA "shot": gerçek grafik PNG + görsel SONRAKİ TURDA gözüne gelir; symbol/timeframe vererek başka sembol/periyot çekebilirsin; dönen path send_file ile gönderilebilir); gerekirse EA panosuna mt5_ea action:"note" ile plan/seviye yaz. web grafiklerinde browser_open + browser_screenshot; bilgisayar ekranı için computer_look; görsel göremeyen metin-model isen ocr_read (source:"screen"/"browser") kullan. Gördüğün yapıyı yorumla: trend, formasyon, mum yapısı, destek-direnç ve SL/TP çizgileri; sembol başına GÖRSEL TEYİT + AL/SAT/BEKLE notu üret. Önemli bulguyu GÖRSELİYLE paylaş: agent_dm image:true (son ekran görüntün) ya da image:"<mt5_shot path>" ile ANA TRADER\'a/ekibe gönder — karşı ajan görüntüyü GERÇEKTEN görür, AJAN DM panelinde açılır.',
|
|
1921
1927
|
})[String((session && session.financeRole) || '')] || '';
|
|
1922
1928
|
/* ROL → SKILL eşleştirmesi (ayarlar modalı): rol başına TEK ve ZORUNLU
|
|
1923
1929
|
skill; ANA TRADER için ayrıca PLAYBOOK skill'i (roleSkills.trader).
|
|
@@ -1956,12 +1962,23 @@ class Engine {
|
|
|
1956
1962
|
modeBlock2 + '\n' +
|
|
1957
1963
|
(roleBlockFull ? roleBlockFull + '\n' : '') +
|
|
1958
1964
|
(teamLine || '') +
|
|
1959
|
-
'MT5 ARAÇLARI: mt5_status (bağlantı), mt5_account (hesap), mt5_market (canlı fiyat), mt5_positions (açık pozisyonlar), mt5_orders (bekleyen emirler), mt5_history (kapanan işlemler), mt5_trade (piyasa emri), mt5_close (kapat), mt5_modify (SL/TP), mt5_pending (bekleyen emir), mt5_cancel (emir iptal).\n' +
|
|
1965
|
+
'MT5 ARAÇLARI: mt5_status (bağlantı), mt5_account (hesap), mt5_market (canlı fiyat), mt5_positions (açık pozisyonlar), mt5_orders (bekleyen emirler), mt5_history (kapanan işlemler), mt5_ea (BeastFinance grafik panosu: status/ping/chart/note), mt5_trade (piyasa emri), mt5_close (kapat), mt5_modify (SL/TP), mt5_pending (bekleyen emir), mt5_cancel (emir iptal).\n' +
|
|
1966
|
+
'KİŞİSEL MT5 ARAÇLARI (VARSAYILAN KURULU — tool__* tüm oturumlarda çağrılabilir): tool__mt5_shot (grafikten GERÇEK PNG + görsel ajana enjekte — grafik işlerinde BİRİNCİL), tool__mt5_barlar2 (OHLC mumlar, köprüsüz), tool__mt5_m15_m5 (GOLD M15+M5 hazır paket), tool__mt5_fiyat, tool__mt5_durum (hesap+pozisyon+emir tek çağrı), tool__mt5_gecmis, tool__mt5_pozisyon_gecmis, tool__mt5_sltp, tool__mt5_kapat, tool__mt5_bekleyen, tool__mt5_emir, tool__mt5_emir_iptal.\n' +
|
|
1967
|
+
'BEASTFINANCE EA (OTOMATİK GRAFİK UZMANI — ENTEGRASYON KANALI): MT5 terminaline bağlanıldığında BeastFinance uzman danışmanı İLK GRAFİĞE OTOMATİK yüklenir, AutoTrading izni açılır (kurulum sistem tarafından yapılır; elle ekleme gerekmez). Grafik panosu + seviye çizgileri + dosya köprüsü (beast_ea.json / beast_cmd.json / beast_note.json) bu EA üzerinden yürür: entegrasyon işlerinde (status/ping/chart/note) mt5_ea kullan; ekran görüntüsü işlerinde tool__mt5_shot ("shot" komutu — gerçek PNG + ajan görseli) birincildir. Yazdığın not ve çizgiler tool__mt5_shot ve computer_look screenshot\'ında GÖRÜNÜR.\n' +
|
|
1960
1968
|
'YETKİLERİN (AÇIK — çekinmeden kullan):\n' +
|
|
1961
1969
|
'- skill: kurulu SKILL.md kataloğunu oku ve uygula — tool yazmadan ÖNCE skill("tool-yazma"), MT5 tarafı işlerden ÖNCE skill("mql5") oku ve prosedürüne birebir uy.\n' +
|
|
1962
1970
|
'- Kişisel tool yazma: %APPDATA%\\beast\\tools\\<slug>\\ içine tool.json + run.js yaz (write_file/edit_file); run_command ile çıktısını (JSON, ok alanlı) doğrula → tool__<slug> ANINDA tüm finance ajanlarında çağrılabilir olur.\n' +
|
|
1963
1971
|
'- MQL5: MT5 tarafında script/gösterge/EA yaz (write_file), metaeditor64.exe /compile ile derle, MQL5\\Files dosya köprüsüyle veriyi Beast\'e taşı; kullanıcıya çalıştırma adımını açıkça söyle.\n' +
|
|
1964
|
-
'- Yerleşik araçlar: run_command, python_run, read_file/write_file/edit_file, web_search/deep_search, browser_
|
|
1972
|
+
'- Yerleşik araçlar: run_command, python_run, read_file/write_file/edit_file, web_search/deep_search, browser_*, computer_look (ekran görüntüsü) — hepsi açık.\n' +
|
|
1973
|
+
'GRAFİK & GÖRSEL DOĞRULAMA (karar öncesi — vazgeçilmez):\n' +
|
|
1974
|
+
'- tool__mt5_shot: MT5 grafiğinin GERÇEK PNG\'si (BeastFinance EA "shot" komutu). Görsel SONRAKİ TURDA gözüne gelir; aktif grafikte Beast panosu + mt5_ea note ile çizilen seviyeler GÖRÜNÜR. symbol/timeframe ver → EA geçici grafik açıp o sembol/periyottan çeker; dönen path send_file ile kullanıcıya gönderilebilir. Grafik analizinde İLK tercih budur.\n' +
|
|
1975
|
+
'- mt5_ea action:"note": grafiğe kısa plan metni + yatay seviye çizgileri yazar (destek/direnç/SL/TP) — sonra tool__mt5_shot ile çekip seviyelerin doğru yerde olduğunu GÖRSEL doğrula.\n' +
|
|
1976
|
+
'- computer_look: tüm masaüstü ekranı (MT5 dışı pencereler dahil); browser_screenshot: web grafikleri (TradingView/Investing) — browser_open ile aç.\n' +
|
|
1977
|
+
'- Görsel göremiyorsan (metin-model) ocr_read (source:"screen"/"browser") ile grafikteki fiyat/seviyeleri metne çevir.\n' +
|
|
1978
|
+
'- Grafikte gezinme/ölçek: computer_act ile timeframe, scroll, zoom (arka planda çalışır — kullanıcının faresini çalmaz).\n' +
|
|
1979
|
+
'- EKİPLE GÖRSEL PAYLAŞIM: chart PNG\'sini agent_dm image:true (son görüntün) ya da image:"<dosya yolu>" (ör. tool__mt5_shot dönen path) ile trader/ekibe gönder — karşı ajan görüntüyü GERÇEKTEN görür, AJAN DM panelinde açılır. Ortak kararlarda grafiği paylaşmak zorunlu disiplindir.\n' +
|
|
1980
|
+
'- PARALEL EKİP AKIŞI: teknik ajan seviyeleri hesaplar → mt5_ea note ile grafiğe çizer; görsel ajan tool__mt5_shot ile çekip TEYİT eder ve agent_dm ile görseli trader\'a atar; risk ajanı aynı görsel üzerinden SL/TP yerleşimini denetler; trader kararı işleme çevirir. Aynı sembolde koşan ajanlar tek DM grubunda (agent_dm group) toplanır — çelişen hareket etme.\n' +
|
|
1981
|
+
'- EKSİK ARAÇ: özel grafik aracı gerekiyorsa (ör. çoklu timeframe tek görüntü, indikatör paneli okuma) VAR SAYMA — tool_request ile TOOL botuna yazdır (doğrulanınca tool__<ad> olarak ANINDA çağrılır); küçük aracı skill("tool-yazma") prosedürüyle kendin de yazabilirsin.\n' +
|
|
1965
1982
|
'VERİ AKIŞI (her değerlendirmede): mt5_account + mt5_positions + mt5_market çağrılarını AYNI turda PARALEL ver; gerekiyorsa mt5_history ile son işlemleri gör.\n' +
|
|
1966
1983
|
'PARALEL + KOORDİNASYON: uzun araştırma/işleri run_background ile paralel finance işçisine devret (parent finance olduğu için işçi mt5 okuma araçlarını görür); koşan ajanlarla konuşmak için agent_dm (to: ajan başlığındaki anahtar kelime, örn "GOLD"; ortak karar için group: "İSİM" ile grup sohbeti kur — mesaj tüm üyelere düşer). Görevin bitince DM/grup sohbetleri otomatik KAPANIR (geçmiş panelde kalır).\n' +
|
|
1967
1984
|
(symbols ? `İZLEME LİSTESİ: ${symbols}\n` : '') +
|
|
@@ -2031,6 +2048,14 @@ class Engine {
|
|
|
2031
2048
|
'# SKILLS\nKullanmadan önce ilgili SKILL.md dosyasını read_file ile oku.\n' + sk.join('\n')
|
|
2032
2049
|
);
|
|
2033
2050
|
}
|
|
2051
|
+
/* BOTLAR: MT5/Beast Finance entegrasyon kanalı — BeastFinance EA'sı otomatik
|
|
2052
|
+
kurulur; botlar grafik/entegrasyon işlerinde bunu bilerek hareket etsin */
|
|
2053
|
+
if (bctx) {
|
|
2054
|
+
parts.push(
|
|
2055
|
+
'# MT5 / BEAST FINANCE ENTEGRASYONU\n' +
|
|
2056
|
+
'Beast Finance açıldığında MT5 terminaline bağlanılır; BeastFinance.mq5 uzman danışmanı İLK GRAFİĞE OTOMATİK kurulur ve AutoTrading açılır. Grafik/entegrasyon işleri bu EA üzerinden yürür (heartbeat beast_ea.json, komut köprüsü beast_cmd.json, grafik panosu/seviyeler beast_note.json; finance oturumlarında mt5_ea status/ping/chart/note). Grafik görseli için varsayılan kurulu tool__mt5_shot kullan (EA "shot" komutu: gerçek PNG + görsel ajana enjekte edilir; path send_file/agent_dm ile paylaşılabilir) — pano ve çizgiler bu screenshot\'ta görünür. Elle EA ekleme varsayma; eksik araç gerekiyorsa Tool botuna tool_request at.'
|
|
2057
|
+
);
|
|
2058
|
+
}
|
|
2034
2059
|
/* opencode instruction port (ajan modu): workspace AGENTS/CLAUDE/CONTEXT
|
|
2035
2060
|
talimatları — oturum başına bir kez okunur, epoch boyunca sabit */
|
|
2036
2061
|
const projChat = this._projectInstructions(session);
|
|
@@ -2072,6 +2097,7 @@ class Engine {
|
|
|
2072
2097
|
'Kullanıcı bir tarihte/saatte hatırlatılmasını isterse set_reminder kullan; when değerini ORTAMdaki bugüne göre hesapla (yerel saat). "Her sabah/gün/hafta" gibi tekrarlı isteklerde repeat alanını da ver (daily/weekly/monthly/weekdays veya cron).',
|
|
2073
2098
|
'Kullanıcı kalıcı bir arka plan takibi isterse (fiyat eşiği, pil seviyesi, sayfa değişikliği) watcher_add ile izleyici kur; kurduktan sonra watcher_list ile doğrula ve kullanıcıya koşulu + kontrol sıklığını kısaca bildir.',
|
|
2074
2099
|
'Anlık olay takipleri için (yeni mail, fiyat eşiği, dosya değişimi, webhook) event_subscribe kullan — cron/polling gerekmez; listeyi event_list ile göster, vazgeçirirse event_unsubscribe.',
|
|
2100
|
+
'ARAÇ EKSİKSE ÇEKİNME (CEPHANE): ihtiyacın olan bir araç yoksa/bozuksa tool_request ile TOOL botuna yazdır — tool yazımı onun TEK işidir; task alanına araç adı + ne yapacağı + girdi/çıktı sözleşmesini, context alanına örnek veri/yol/endpoint yaz. Araç doğrulanınca tool__<ad> olarak ANINDA çağrılabilir. Küçük kişisel araçları skill("tool-yazma") prosedürüyle kendin de yazabilirsin — yazdığını run_command ile MUTLAKA doğrula.',
|
|
2075
2101
|
'LOG ZEKASI: "hata var mı / ne oldu / neden çalışmadı" sorularında ya da bir iş beklenmedik bittiğinde/hata verdiğini fark ettiğinde log_analyze ile logları tara — top desenleri okuyup en olası KÖK NEDENİ tek cümlede söyle, somut çözüm öner; aynı desen 3+ tekrarlıysa bunu vurgula. Sürekli log gözetimi istenirse watcher_add ile kind:"logs" kur (örn "hata artarsa bağır" → level:"error", windowMin:10, op:"gt", value:2) ve koşulu kısaca bildir.',
|
|
2076
2102
|
'Kullanıcı "artık hep böyle yap / bunu unutma" tarzı kalıcı talimat verirse kural olarak kaydet: sohbette /rule <metin> kullanmasını söyle VEYA kullanıcı isterse event_subscribe ile olaya bağlan (mail/fiyat/dosya/webhook).',
|
|
2077
2103
|
'Kullanıcının mesajında 2+ ayrı iş/hedef varsa (örn "X yap ve sonra Y\u2019i kontrol et") KODLAMAYA/İŞE BAŞLAMADAN önce todo_write ile plan çıkar ve sırayla yürüt; her adımı tamamlarken güncelle. LİSTE DİSİPLİNİ: her adım bittiği AN status:"done" yap; son cevabını vermeden önce tüm maddeler done olmalı — yapılmayacaksa listeden düş. Listeyi yarım bırakma.',
|
|
@@ -2753,14 +2779,30 @@ class Engine {
|
|
|
2753
2779
|
const jobRec = this._bgJobs && this._bgJobs.get(String(sessionId));
|
|
2754
2780
|
if (jobRec && Array.isArray(jobRec.dmInbox) && jobRec.dmInbox.length) {
|
|
2755
2781
|
const inbox = jobRec.dmInbox.splice(0);
|
|
2756
|
-
const boxText = inbox
|
|
2782
|
+
const boxText = inbox
|
|
2783
|
+
.map((x) => (typeof x === 'string' ? x : String((x && x.text) || '')))
|
|
2784
|
+
.join('\n\n')
|
|
2785
|
+
.slice(0, 6000);
|
|
2786
|
+
/* görselli DM'ler: son 2 görsel bu turun mesajına vision olarak eklenir */
|
|
2787
|
+
const inboxImgs = inbox
|
|
2788
|
+
.map((x) => (x && typeof x === 'object' && /^data:image\//i.test(String(x.image || '')) ? String(x.image) : ''))
|
|
2789
|
+
.filter(Boolean)
|
|
2790
|
+
.slice(-2);
|
|
2757
2791
|
const prefix =
|
|
2758
2792
|
`[BEKLEYEN AJAN DM'LERİ — ${inbox.length} mesaj]\n${boxText}\n` +
|
|
2759
2793
|
`(Tur aralığında biriken DM'ler. Bu turda değerlendir; yalnızca aksiyon/cevap GEREKİYORSA agent_dm ile TEK kısa cevap ver — teşekkür/onay/ack mesajı YAZMA.)\n\n`;
|
|
2760
2794
|
if (typeof msg.content === 'string') {
|
|
2761
|
-
msg.content =
|
|
2762
|
-
|
|
2763
|
-
|
|
2795
|
+
msg.content = inboxImgs.length
|
|
2796
|
+
? [
|
|
2797
|
+
{ type: 'text', text: prefix + msg.content },
|
|
2798
|
+
...inboxImgs.map((u) => ({ type: 'image_url', image_url: { url: u } })),
|
|
2799
|
+
]
|
|
2800
|
+
: prefix + msg.content;
|
|
2801
|
+
} else if (Array.isArray(msg.content)) {
|
|
2802
|
+
if (msg.content[0] && typeof msg.content[0].text === 'string') {
|
|
2803
|
+
msg.content[0] = { ...msg.content[0], text: prefix + msg.content[0].text };
|
|
2804
|
+
}
|
|
2805
|
+
for (const u of inboxImgs) msg.content.push({ type: 'image_url', image_url: { url: u } });
|
|
2764
2806
|
}
|
|
2765
2807
|
}
|
|
2766
2808
|
} catch {}
|
|
@@ -3604,13 +3646,21 @@ class Engine {
|
|
|
3604
3646
|
if (this._deletedSessions && this._deletedSessions.has(sessionId)) continue;
|
|
3605
3647
|
if (continuous) {
|
|
3606
3648
|
job.dmInbox = job.dmInbox || [];
|
|
3607
|
-
job.dmInbox.push(
|
|
3649
|
+
job.dmInbox.push({
|
|
3650
|
+
text: String(r.text || '').slice(0, 4000),
|
|
3651
|
+
...(r.image ? { image: String(r.image) } : {}),
|
|
3652
|
+
});
|
|
3608
3653
|
if (job.dmInbox.length > 20) job.dmInbox.splice(0, job.dmInbox.length - 20);
|
|
3609
3654
|
continue;
|
|
3610
3655
|
}
|
|
3611
3656
|
if (this.isBusy(sessionId)) { rest.push(r); continue; }
|
|
3612
3657
|
let sent = false;
|
|
3613
|
-
try {
|
|
3658
|
+
try {
|
|
3659
|
+
const payload = { text: r.text };
|
|
3660
|
+
/* görselli DM: hedef ajan görüntüyü gerçekten GÖRSÜN (vision mesajı) */
|
|
3661
|
+
if (r.image) payload.attachments = [{ type: 'image', name: 'ekran goruntusu', dataUrl: String(r.image) }];
|
|
3662
|
+
sent = !!this.send(sessionId, payload);
|
|
3663
|
+
} catch {}
|
|
3614
3664
|
if (!sent) rest.push(r);
|
|
3615
3665
|
}
|
|
3616
3666
|
this._pendingReports = rest;
|
|
@@ -3630,6 +3680,7 @@ class Engine {
|
|
|
3630
3680
|
`DOSYA KURALI: dosya işlemlerinde özel araçları kullan — VAR OLAN dosyayı edit_file ile düzenle, yeniyi write_file ile yaz, okuma/arama read_file/grep/glob; run_command terminal işlerindir (build, git, kurulum). Bir dosyayı BİR KEZ oku — içerik bağlamda kalır, tekrar okuma.\n` +
|
|
3631
3681
|
(proj ? `PROJE TALİMATLARI (workspace AGENTS/CLAUDE/CONTEXT — daima uy):\n${proj}\n` : '') +
|
|
3632
3682
|
`HIZ KURALLARI:\n` +
|
|
3683
|
+
`- TOOL İSTEĞİ (CEPHANE): ihtiyacın olan araç yoksa/bozuksa tool_request ile TOOL botuna yazdır (araç doğrulanınca tool__<ad> olarak anında çağrılır); küçük aracı skill("tool-yazma") ile kendin de yaz ve run_command ile doğrula.\n` +
|
|
3633
3684
|
`- Döngülü işleri (çok URL/dosya/sayfa, tekrarlı parse-hesap) TEK python_run betiğinde topluca bitir.\n` +
|
|
3634
3685
|
`- Web için web_search kullan (zincir dahili tarayıcıyla başlar — gerçek Chromium ile Google); tek aramada bulunamazsa veya çok kaynaklı derin araştırma gerekiyorsa deep_search kullan (çoklu sorgu paralel + gizli tarayıcıda tam sayfa okuma). Sayfa açma/göstermenin VARSAYILANI DAHİLİ tarayıcıdır: browser_open → browser_snapshot → browser_click/type/read. Kullanıcı açıkça dış tarayıcı (chrome/firefox/başka/normal/kendi tarayıcım) istediyse run_command ile \`start "" <url>\` çalıştır. Görseli göremiyorsan metni ocr_read ile oku (source:"browser").\n` +
|
|
3635
3686
|
`- Bağımsız araç çağrılarını aynı turda PARALEL ver.\n` +
|
|
@@ -3708,6 +3759,11 @@ class Engine {
|
|
|
3708
3759
|
) {
|
|
3709
3760
|
toolsList = [...toolsList, AGENT_DM_DEF];
|
|
3710
3761
|
}
|
|
3762
|
+
/* TOOL İSTEĞİ (cephane): tool botu hariç TÜM oturumlar — müşteri bot
|
|
3763
|
+
sohbetleri, paralel ajanlar ve finance ajanları dahil */
|
|
3764
|
+
if (session && !session.isBotDm && session.botId !== 'tool') {
|
|
3765
|
+
toolsList = [...toolsList, TOOL_REQUEST_DEF];
|
|
3766
|
+
}
|
|
3711
3767
|
/* panel_run yalnız SANDBOX oturumlarında görünsün — diğer panellerde
|
|
3712
3768
|
modelin alet çantasında olmasın (hook olmadan çalışmaz) */
|
|
3713
3769
|
if (!(session && session.sbSandbox)) {
|
|
@@ -4272,7 +4328,7 @@ class Engine {
|
|
|
4272
4328
|
const imgMsg = {
|
|
4273
4329
|
role: 'user',
|
|
4274
4330
|
content: [
|
|
4275
|
-
{ type: 'text', text: '[
|
|
4331
|
+
{ type: 'text', text: '[araç görseli — bu kareyi analiz et ve devam et]' },
|
|
4276
4332
|
{ type: 'image_url', image_url: { url: injectedImage } },
|
|
4277
4333
|
],
|
|
4278
4334
|
};
|
|
@@ -4613,33 +4669,21 @@ const skills = require('./skills');
|
|
|
4613
4669
|
Admin bot, 5 haneli kodla başka bota özel mesaj atar; hedef botun cevabı
|
|
4614
4670
|
senkron döner. İzolasyon: DM turları gizli pair oturumunda yürür, bot_dm
|
|
4615
4671
|
DM oturumlarında KAPALI (döngü koruması). Tüm trafik admin DM Log'ta. */
|
|
4616
|
-
async _botDm(args, sessionId, signal) {
|
|
4617
|
-
const bots = require('./bots');
|
|
4618
|
-
const code = String((args && args.to) || '').replace(/\D/g, '');
|
|
4619
|
-
const message = String((args && args.message) || '').slice(0, 6000);
|
|
4620
|
-
if (!/^\d{5}$/.test(code)) return { ok: false, error: 'geçersiz kod — 5 haneli bot kodu gir' };
|
|
4621
|
-
if (!message.trim()) return { ok: false, error: 'mesaj boş' };
|
|
4622
|
-
|
|
4623
|
-
const session = this.cache.get(String(sessionId)) || this._load(String(sessionId));
|
|
4624
|
-
const senderBotId = (session && session.botId) || 'beast';
|
|
4625
|
-
const senderBot = (typeof this.resolveBot === 'function' && senderBotId) ? this.resolveBot(senderBotId) : null;
|
|
4626
|
-
const senderIsAdmin = !session.botId || !!(senderBot && senderBot.admin);
|
|
4627
|
-
if (!senderIsAdmin) {
|
|
4628
|
-
return { ok: false, error: 'yetki yok — botlar arası DM yalnız yönetici (admin) bot tarafından açılabilir' };
|
|
4629
|
-
}
|
|
4630
|
-
|
|
4631
|
-
const target = bots.byCode(code);
|
|
4632
|
-
if (!target) return { ok: false, error: `bu kotta bot yok: ${code}` };
|
|
4633
|
-
if (target.id === senderBotId) return { ok: false, error: 'kendine DM atılamaz' };
|
|
4634
4672
|
|
|
4635
|
-
|
|
4636
|
-
|
|
4673
|
+
/* Deterministik pair oturumu: dm + (küçük kod + büyük kod) — aynı çift aynı oturum */
|
|
4674
|
+
_botPairId(senderBotId, target) {
|
|
4675
|
+
const sender = (typeof this.resolveBot === 'function' && senderBotId) ? this.resolveBot(senderBotId) : null;
|
|
4676
|
+
const codes = [String(sender ? sender.code || '' : ''), String(target && target.code || '')]
|
|
4637
4677
|
.map((c) => (/^\d{5}$/.test(c) ? c : '00000'))
|
|
4638
4678
|
.sort();
|
|
4639
|
-
|
|
4679
|
+
return 'dm' + codes[0] + codes[1];
|
|
4680
|
+
}
|
|
4640
4681
|
|
|
4682
|
+
/* Ortak bot sohbeti: hedef bota mesajı düşür, tur bitene kadar bekle, son
|
|
4683
|
+
asistan cevabını döndür. bot_dm (admin) + tool_request (tool botu) kullanır. */
|
|
4684
|
+
async _botConverse(senderBotId, target, message, signal, timeoutMs) {
|
|
4685
|
+
const pairId = this._botPairId(senderBotId, target);
|
|
4641
4686
|
let pair = this.cache.get(pairId) || this._load(pairId);
|
|
4642
|
-
const fresh = !pair.isBotDm && !pair.messages.length;
|
|
4643
4687
|
if (!pair.isBotDm) {
|
|
4644
4688
|
try {
|
|
4645
4689
|
fs.appendFileSync(this._file(pairId), JSON.stringify({ t: 'botdm', a: senderBotId, b: target.id, at: nowIso() }) + '\n');
|
|
@@ -4651,24 +4695,24 @@ const skills = require('./skills');
|
|
|
4651
4695
|
/* hedef botun kimliğiyle çalışsın; izolasyon _botSystemBlock'tan gelir */
|
|
4652
4696
|
this.setSessionBot(pairId, target.id);
|
|
4653
4697
|
this.setSessionPerm(pairId, target.perm || 'all');
|
|
4654
|
-
|
|
4698
|
+
const senderBot = (typeof this.resolveBot === 'function' && senderBotId) ? this.resolveBot(senderBotId) : null;
|
|
4655
4699
|
const senderName = senderBot ? senderBot.name : 'Beast';
|
|
4656
|
-
const senderCode = senderBot && /^\d{5}$/.test(String(senderBot.code || '')) ? senderBot.code :
|
|
4657
|
-
const prefix = `[BOT DM — gönderen bot: ${senderName} (kod
|
|
4700
|
+
const senderCode = senderBot && /^\d{5}$/.test(String(senderBot.code || '')) ? senderBot.code : '';
|
|
4701
|
+
const prefix = `[BOT DM — gönderen bot: ${senderName}${senderCode ? ' (kod ' + senderCode + ')' : ''} — cevabını kısa ve net ver, araç kullanman gerekmiyorsa kullanma]`;
|
|
4658
4702
|
const before = pair.messages.length;
|
|
4659
4703
|
const sent = this.send(pairId, { text: prefix + '\n' + message });
|
|
4660
4704
|
if (!sent) return { ok: false, error: 'DM oturumu başlatılamadı' };
|
|
4661
|
-
|
|
4662
|
-
|
|
4705
|
+
/* tur bitene kadar bekle (ctrl kaydı düşer) */
|
|
4706
|
+
const limit = Math.max(30000, Math.min(600000, Number(timeoutMs) || 120000));
|
|
4663
4707
|
const t0 = Date.now();
|
|
4664
|
-
while (Date.now() - t0 <
|
|
4708
|
+
while (Date.now() - t0 < limit) {
|
|
4665
4709
|
if (signal && signal.aborted) return { ok: false, error: 'iptal edildi' };
|
|
4666
4710
|
await new Promise((r) => setTimeout(r, 400));
|
|
4667
4711
|
if (!this.ctrls.has(pairId)) break;
|
|
4668
4712
|
}
|
|
4669
4713
|
if (this.ctrls.has(pairId)) {
|
|
4670
|
-
try { this.interrupt(pairId, 'bot DM zaman aşımına uğradı
|
|
4671
|
-
return { ok: false, error:
|
|
4714
|
+
try { this.interrupt(pairId, 'bot DM zaman aşımına uğradı — tur kesildi'); } catch {}
|
|
4715
|
+
return { ok: false, error: `hedef bot zaman aşımına uğradı (${Math.round(limit / 1000)} sn) — TOOLS panelinden sonucu takip et` };
|
|
4672
4716
|
}
|
|
4673
4717
|
const after = this.cache.get(pairId) || pair;
|
|
4674
4718
|
const newMsgs = after.messages.slice(before);
|
|
@@ -4678,6 +4722,74 @@ const skills = require('./skills');
|
|
|
4678
4722
|
return { ok: true, from: target.name, code: target.code, reply };
|
|
4679
4723
|
}
|
|
4680
4724
|
|
|
4725
|
+
async _botDm(args, sessionId, signal) {
|
|
4726
|
+
const bots = require('./bots');
|
|
4727
|
+
const code = String((args && args.to) || '').replace(/\D/g, '');
|
|
4728
|
+
const message = String((args && args.message) || '').slice(0, 6000);
|
|
4729
|
+
if (!/^\d{5}$/.test(code)) return { ok: false, error: 'geçersiz kod — 5 haneli bot kodu gir' };
|
|
4730
|
+
if (!message.trim()) return { ok: false, error: 'mesaj boş' };
|
|
4731
|
+
|
|
4732
|
+
const session = this.cache.get(String(sessionId)) || this._load(String(sessionId));
|
|
4733
|
+
const senderBotId = (session && session.botId) || 'beast';
|
|
4734
|
+
const senderBot = (typeof this.resolveBot === 'function' && senderBotId) ? this.resolveBot(senderBotId) : null;
|
|
4735
|
+
const senderIsAdmin = !session.botId || !!(senderBot && senderBot.admin);
|
|
4736
|
+
if (!senderIsAdmin) {
|
|
4737
|
+
return { ok: false, error: 'yetki yok — botlar arası DM yalnız yönetici (admin) bot tarafından açılabilir' };
|
|
4738
|
+
}
|
|
4739
|
+
|
|
4740
|
+
const target = bots.byCode(code);
|
|
4741
|
+
if (!target) return { ok: false, error: `bu kotta bot yok: ${code}` };
|
|
4742
|
+
if (target.id === senderBotId) return { ok: false, error: 'kendine DM atılamaz' };
|
|
4743
|
+
return this._botConverse(senderBotId, target, message, signal, 120000);
|
|
4744
|
+
}
|
|
4745
|
+
|
|
4746
|
+
/* TOOL İSTEĞİ (cephane): her oturum/bot eksik aracı TOOL botuna yazdırır.
|
|
4747
|
+
Admin şartı YOK — amaç tüm ajanların tool üretebilmesi; tool botunun
|
|
4748
|
+
kendisi ve DM oturumları hariç (döngü koruması). */
|
|
4749
|
+
async _toolRequest(args, sessionId, signal) {
|
|
4750
|
+
const bots = require('./bots');
|
|
4751
|
+
const task = String((args && args.task) || '').slice(0, 4000);
|
|
4752
|
+
const context = String((args && args.context) || '').slice(0, 4000);
|
|
4753
|
+
if (!task.trim()) return { ok: false, error: 'task gerekli — hangi araç, ne yapacak, girdi/çıktısı ne?' };
|
|
4754
|
+
const session = this.cache.get(String(sessionId)) || this._load(String(sessionId));
|
|
4755
|
+
if (session && session.isBotDm) return { ok: false, error: 'DM oturumunda tool_request kullanılamaz' };
|
|
4756
|
+
const senderBotId = (session && session.botId) || 'beast';
|
|
4757
|
+
if (senderBotId === 'tool') return { ok: false, error: 'Tool botu kendi işini kendisi yapar — doğrudan yaz' };
|
|
4758
|
+
const all = bots.list() || [];
|
|
4759
|
+
const target = all.find((b) => b && b.id === 'tool') || all.find((b) => b && /tool/i.test(String(b.name || '')));
|
|
4760
|
+
if (!target) return { ok: false, error: 'Tool botu bulunamadı — botlar sayfasından oluştur' };
|
|
4761
|
+
const who = (() => {
|
|
4762
|
+
try {
|
|
4763
|
+
const b = typeof this.resolveBot === 'function' ? this.resolveBot(senderBotId) : null;
|
|
4764
|
+
return (b && b.name) || (session && session.bgTitle) || 'Beast';
|
|
4765
|
+
} catch { return 'Beast'; }
|
|
4766
|
+
})();
|
|
4767
|
+
const message =
|
|
4768
|
+
`TOOL İSTEĞİ (gönderen: ${who}):\n` + task + '\n' +
|
|
4769
|
+
(context ? `\nBAĞLAM (kod/yol/örnek veri/endpoint):\n` + context + '\n' : '') +
|
|
4770
|
+
`\nHatırlatma: skill("tool-yazma") oku; %APPDATA%\\beast\\tools\\<slug>\\ içine tool.json + run.js yaz; run_command ile TEST DÖNGÜSÜNÜ işlet (çıktı {ok:true} olana kadar hata oku → edit_file ile düzelt → yeniden test; en fazla 5 deneme). Ancak test geçince yayınla; geçmeyen aracı yayınlama. Raporunda adımları yaz: yazıldı → test sonucu → (varsa) düzeltmeler → YAYINDA/BAŞARISIZ + tek satır çağrı örneği.`;
|
|
4771
|
+
const r = await this._botConverse(senderBotId, target, message, signal, 240000);
|
|
4772
|
+
/* RAPOR: tool yazım/doğrulama adımları bağlı entegrasyonlara (WA/TG/Discord) düşer */
|
|
4773
|
+
const notifyIntegrations = (text) => {
|
|
4774
|
+
try { if (typeof this.integrationNotify === 'function') this.integrationNotify(text); } catch {}
|
|
4775
|
+
};
|
|
4776
|
+
if (!r || !r.ok) {
|
|
4777
|
+
notifyIntegrations('🛠️ Tool botu BAŞARISIZ — isteyen: ' + who + '\nİstenen: ' + task.slice(0, 140) + '\nSebep: ' + String((r && r.error) || 'yanıt yok'));
|
|
4778
|
+
return r || { ok: false, error: 'Tool botu yanıt vermedi' };
|
|
4779
|
+
}
|
|
4780
|
+
notifyIntegrations(
|
|
4781
|
+
'🛠️ Tool botu raporu — isteyen: ' + who + '\n' +
|
|
4782
|
+
'İstenen: ' + task.slice(0, 140) + '\n' +
|
|
4783
|
+
String(r.reply || '').replace(/\s+/g, ' ').slice(0, 500)
|
|
4784
|
+
);
|
|
4785
|
+
return {
|
|
4786
|
+
ok: true,
|
|
4787
|
+
tool_bot: r.from,
|
|
4788
|
+
reply: r.reply,
|
|
4789
|
+
note: 'Araç hazır olduğunda modele tool__<slug> olarak ANINDA açılır (doğrulama testini Tool botu yaptı; adımlar entegrasyonlara bildirildi).',
|
|
4790
|
+
};
|
|
4791
|
+
}
|
|
4792
|
+
|
|
4681
4793
|
/* ADMIN İZLEME: tüm botlar arası DM oturumlarının listesi */
|
|
4682
4794
|
listBotDmSessions() {
|
|
4683
4795
|
const bots = require('./bots');
|
|
@@ -5046,7 +5158,7 @@ const skills = require('./skills');
|
|
|
5046
5158
|
}
|
|
5047
5159
|
/* AJAN DM: ajanlar arası mesaj — hedef koşan ajanın oturumuna düşer */
|
|
5048
5160
|
if (name === 'agent_dm') {
|
|
5049
|
-
return JSON.stringify(this._agentDmSend(sessionId, args));
|
|
5161
|
+
return JSON.stringify(await this._agentDmSend(sessionId, args));
|
|
5050
5162
|
}
|
|
5051
5163
|
/* KİŞİSEL TOOL: %APPDATA%\beast\tools\ — çocuk node prosesinde izole koşar */
|
|
5052
5164
|
if (String(name).startsWith('tool__')) {
|
|
@@ -5236,6 +5348,11 @@ const skills = require('./skills');
|
|
|
5236
5348
|
const r = await this._botDm(args, sessionId, signal);
|
|
5237
5349
|
return JSON.stringify(r);
|
|
5238
5350
|
}
|
|
5351
|
+
/* TOOL İSTEĞİ (cephane): eksik/bozuk aracı TOOL botuna yazdırır —
|
|
5352
|
+
tanım toolsList'e ekleniyordu ama dispatch'e bağlı değildi, burada bağlanır */
|
|
5353
|
+
if (name === 'tool_request') {
|
|
5354
|
+
return JSON.stringify(await this._toolRequest(args || {}, sessionId, signal));
|
|
5355
|
+
}
|
|
5239
5356
|
if (name === 'send_file') {
|
|
5240
5357
|
if (typeof this.fileSend !== 'function') {
|
|
5241
5358
|
return JSON.stringify({ ok: false, error: 'dosya gönderim köprüsü yok' });
|
|
@@ -5610,7 +5727,7 @@ const AGENT_DM_DEF = {
|
|
|
5610
5727
|
function: {
|
|
5611
5728
|
name: 'agent_dm',
|
|
5612
5729
|
description:
|
|
5613
|
-
'Send a short DM to another running agent (parallel agents / finance agents) to coordinate: share findings, ask status, warn about risk, hand off work, and MAKE JOINT DECISIONS. `to` = target session id OR a keyword from the agent title (e.g. "GOLD", "Trader"). `topic` = short subject label — replies to the same topic stay in the SAME conversation thread, so ALWAYS reuse the topic you were DMed with when replying. `group` = optional group-chat name (e.g. "GOLD EKIP"): creates or reuses a group conversation, adds the target agent as a member, and your message is delivered to EVERY member — use groups when a decision needs multiple agents.',
|
|
5730
|
+
'Send a short DM to another running agent (parallel agents / finance agents) to coordinate: share findings, ask status, warn about risk, hand off work, and MAKE JOINT DECISIONS. `to` = target session id OR a keyword from the agent title (e.g. "GOLD", "Trader"). `topic` = short subject label — replies to the same topic stay in the SAME conversation thread, so ALWAYS reuse the topic you were DMed with when replying. `group` = optional group-chat name (e.g. "GOLD EKIP"): creates or reuses a group conversation, adds the target agent as a member, and your message is delivered to EVERY member — use groups when a decision needs multiple agents. `image` shares a chart/screen as an attachment the receiving agent REALLY sees and the AJAN DM panel shows: true = your last screenshot (fresh capture if none); a file path (e.g. the tool__mt5_shot "path") or a data URL = that exact image.',
|
|
5614
5731
|
parameters: {
|
|
5615
5732
|
type: 'object',
|
|
5616
5733
|
properties: {
|
|
@@ -5618,12 +5735,32 @@ const AGENT_DM_DEF = {
|
|
|
5618
5735
|
topic: { type: 'string', description: 'Short subject label for the conversation thread, e.g. "GOLD pozisyon riski"' },
|
|
5619
5736
|
message: { type: 'string', description: 'Short message (1-3 sentences)' },
|
|
5620
5737
|
group: { type: 'string', description: 'Optional group-chat name — send to ALL members of that group (creates it on first use, adds the target agent)' },
|
|
5738
|
+
image: { type: ['boolean', 'string'], description: 'true = son ekran görüntün (yoksa taze yakalar); dosya yolu (ör. tool__mt5_shot dönen PNG path) ya da data:image URL = o görsel iliştirilir. Panelde ve karşı ajanda GÖRÜNÜR; grafik/ekran bulgusunu paylaşmak için kullan' },
|
|
5621
5739
|
},
|
|
5622
5740
|
required: ['message'],
|
|
5623
5741
|
},
|
|
5624
5742
|
},
|
|
5625
5743
|
};
|
|
5626
5744
|
|
|
5745
|
+
/* TOOL İSTEĞİ (cephane kuralı): eksik/bozuk araç TOOL botuna yazdırılır.
|
|
5746
|
+
Tool botunun kendisi ve bot-DM oturumları hariç TÜM oturumlara açılır. */
|
|
5747
|
+
const TOOL_REQUEST_DEF = {
|
|
5748
|
+
type: 'function',
|
|
5749
|
+
function: {
|
|
5750
|
+
name: 'tool_request',
|
|
5751
|
+
description:
|
|
5752
|
+
'İhtiyaç duyduğun bir araç eksikse ya da bozuksa TOOL botuna yazdırır ve doğrulanmış aracın raporunu döndürür. Tool yazımı Tool botunun TEK işidir — sen tool yazmaya çalışma. task: araç adı + ne yapacak + girdi/çıktı sözleşmesi; context: örnek veri, dosya yolu, endpoint veya hata çıktısı. Araç hazır olunca tool__<ad> olarak ANINDA çağrılabilir.',
|
|
5753
|
+
parameters: {
|
|
5754
|
+
type: 'object',
|
|
5755
|
+
properties: {
|
|
5756
|
+
task: { type: 'string', description: 'Araç ihtiyacı: ad, işlev, girdi/çıktı sözleşmesi' },
|
|
5757
|
+
context: { type: 'string', description: 'Örnek veri, yol, endpoint ya da hata çıktısı' },
|
|
5758
|
+
},
|
|
5759
|
+
required: ['task'],
|
|
5760
|
+
},
|
|
5761
|
+
},
|
|
5762
|
+
};
|
|
5763
|
+
|
|
5627
5764
|
const TOOLS = [
|
|
5628
5765
|
...tools.definitions,
|
|
5629
5766
|
{
|
|
@@ -6409,11 +6546,22 @@ Engine.prototype.clearTodos = function (sid) {
|
|
|
6409
6546
|
/* Ajan DM gönder: hedef koşan paralel/finance ajanı (id YA DA başlık
|
|
6410
6547
|
anahtar kelimesi). Teslim _pendingReports kuyruğuyla yapılır — hedef
|
|
6411
6548
|
meşgulse mesaj done olunca düşer, kaybolmaz. Panel agent-dms.json'dan. */
|
|
6412
|
-
Engine.prototype._agentDmSend = function (fromSid, args) {
|
|
6549
|
+
Engine.prototype._agentDmSend = async function (fromSid, args) {
|
|
6413
6550
|
try {
|
|
6414
6551
|
const to = String((args && args.to) || '').trim();
|
|
6415
6552
|
const text = String((args && args.message) || '').trim().slice(0, 1200);
|
|
6416
6553
|
if (!text) return { ok: false, error: 'mesaj boş' };
|
|
6554
|
+
/* GÖRSEL DM: image:true → son ekran görüntüsü (yoksa taze yakalama);
|
|
6555
|
+
image:"<dosya yolu>" ya da data URL → o görsel BİREBİR iliştirilir
|
|
6556
|
+
(ör. tool__mt5_shot dönen PNG path'i). Karşı ajan görüntüyü görür. */
|
|
6557
|
+
const imgArg = args && args.image;
|
|
6558
|
+
let image = '';
|
|
6559
|
+
if (typeof imgArg === 'string' && imgArg.trim()) {
|
|
6560
|
+
const s = imgArg.trim();
|
|
6561
|
+
image = /^data:image\//i.test(s) ? s : this._agentDmImageFromFile(s);
|
|
6562
|
+
} else if (imgArg === true || imgArg === 'true') {
|
|
6563
|
+
image = await this._agentDmCaptureImage(fromSid);
|
|
6564
|
+
}
|
|
6417
6565
|
const groupName = String((args && args.group) || '').replace(/\s+/g, ' ').trim().slice(0, 40);
|
|
6418
6566
|
const jobs = this._bgJobs || new Map();
|
|
6419
6567
|
const fromJob = jobs.get(String(fromSid));
|
|
@@ -6538,6 +6686,7 @@ Engine.prototype._agentDmSend = function (fromSid, args) {
|
|
|
6538
6686
|
groupTitle: g.title,
|
|
6539
6687
|
topic,
|
|
6540
6688
|
text,
|
|
6689
|
+
...(image ? { image } : {}),
|
|
6541
6690
|
};
|
|
6542
6691
|
this._pushAgentDm(dm);
|
|
6543
6692
|
/* canlı event TEK SEFER — üye başına emit edilirse panelde çoğalır */
|
|
@@ -6549,6 +6698,7 @@ Engine.prototype._agentDmSend = function (fromSid, args) {
|
|
|
6549
6698
|
text:
|
|
6550
6699
|
`[AJAN DM (grup: "${g.title}") — ${dm.fromTitle} · konu: "${topic}"]\n${text}\n` +
|
|
6551
6700
|
`(Cevap yalnızca aksiyon/karar GEREKİYORSA ver — agent_dm group: "${g.title}", to: "${dm.fromTitle}", topic: "${topic}"; teşekkür/onay yazma.)`,
|
|
6701
|
+
...(image ? { image } : {}),
|
|
6552
6702
|
});
|
|
6553
6703
|
this.flushPendingReports(m);
|
|
6554
6704
|
}
|
|
@@ -6564,7 +6714,7 @@ Engine.prototype._agentDmSend = function (fromSid, args) {
|
|
|
6564
6714
|
|
|
6565
6715
|
/* BİREYSEL DM — DÜZ CHAT OTURUMUNA (sahibin sohbet geçmişi) ENJEKTE
|
|
6566
6716
|
ETMEYİZ: DM trafik yalnız AJAN DM konsolunda görünür. */
|
|
6567
|
-
const dm = { at, from: String(fromSid), fromTitle, to: String(target), toTitle, topic, text };
|
|
6717
|
+
const dm = { at, from: String(fromSid), fromTitle, to: String(target), toTitle, topic, text, ...(image ? { image } : {}) };
|
|
6568
6718
|
this._pushAgentDm(dm);
|
|
6569
6719
|
this._persistAgentDms();
|
|
6570
6720
|
emitSafe(this, target, { type: 'agent-dm', ...dm });
|
|
@@ -6574,6 +6724,7 @@ Engine.prototype._agentDmSend = function (fromSid, args) {
|
|
|
6574
6724
|
text:
|
|
6575
6725
|
`[AJAN DM — ${dm.fromTitle} · konu: "${topic}"]\n${text}\n` +
|
|
6576
6726
|
`(Cevap yalnızca aksiyon/karar GEREKİYORSA ver — agent_dm to: "${dm.fromTitle}", topic: "${topic}"; teşekkür/onay yazma.)`,
|
|
6727
|
+
...(image ? { image } : {}),
|
|
6577
6728
|
});
|
|
6578
6729
|
this.flushPendingReports(target);
|
|
6579
6730
|
}
|
|
@@ -6583,6 +6734,58 @@ Engine.prototype._agentDmSend = function (fromSid, args) {
|
|
|
6583
6734
|
}
|
|
6584
6735
|
};
|
|
6585
6736
|
|
|
6737
|
+
/* AJAN DM görseli (dosyadan): png/jpg/webp/gif dosyasını data URL'e çevirir.
|
|
6738
|
+
Send_file kapısına takılmadan (ör. tool__mt5_shot path'i) görsel paylaşımı;
|
|
6739
|
+
2.5MB üstü DM kaydını şişirmesin diye atlanır. */
|
|
6740
|
+
Engine.prototype._agentDmImageFromFile = function (p) {
|
|
6741
|
+
try {
|
|
6742
|
+
const fp = String(p || '').trim();
|
|
6743
|
+
if (!fp) return '';
|
|
6744
|
+
const ext = path.extname(fp).toLowerCase();
|
|
6745
|
+
const mime =
|
|
6746
|
+
ext === '.png' ? 'image/png'
|
|
6747
|
+
: ext === '.jpg' || ext === '.jpeg' ? 'image/jpeg'
|
|
6748
|
+
: ext === '.webp' ? 'image/webp'
|
|
6749
|
+
: ext === '.gif' ? 'image/gif'
|
|
6750
|
+
: '';
|
|
6751
|
+
if (!mime) return '';
|
|
6752
|
+
const buf = fs.readFileSync(fp);
|
|
6753
|
+
if (!buf.length || buf.length > 2500000) return '';
|
|
6754
|
+
return 'data:' + mime + ';base64,' + buf.toString('base64');
|
|
6755
|
+
} catch {
|
|
6756
|
+
return '';
|
|
6757
|
+
}
|
|
6758
|
+
};
|
|
6759
|
+
|
|
6760
|
+
/* AJAN DM görseli: gönderenin oturumundaki EN SON ekran görüntüsünü (yoksa
|
|
6761
|
+
taze yakalama) data URL olarak döndürür. Çok büyük görseller DM kaydını
|
|
6762
|
+
şişirmesin diye 2.5MB üstü atlanır. */
|
|
6763
|
+
Engine.prototype._agentDmCaptureImage = async function (sid) {
|
|
6764
|
+
let found = '';
|
|
6765
|
+
const sess = this.cache.get(String(sid || '')) || null;
|
|
6766
|
+
const msgs = (sess && Array.isArray(sess.messages) ? sess.messages : []);
|
|
6767
|
+
for (let i = msgs.length - 1; i >= 0 && !found; i--) {
|
|
6768
|
+
const c = msgs[i] && msgs[i].content;
|
|
6769
|
+
if (!Array.isArray(c)) continue;
|
|
6770
|
+
for (let j = c.length - 1; j >= 0; j--) {
|
|
6771
|
+
const p = c[j];
|
|
6772
|
+
if (p && p.type === 'image_url' && p.image_url && /^data:image\//i.test(String(p.image_url.url || ''))) {
|
|
6773
|
+
found = String(p.image_url.url);
|
|
6774
|
+
break;
|
|
6775
|
+
}
|
|
6776
|
+
}
|
|
6777
|
+
}
|
|
6778
|
+
if (!found && this.computer && typeof this.computer.look === 'function') {
|
|
6779
|
+
try {
|
|
6780
|
+
const shot = await this.computer.look();
|
|
6781
|
+
const url = typeof shot === 'string' ? shot : (shot && (shot.image || shot.dataUrl || shot.__injectImage)) || '';
|
|
6782
|
+
if (/^data:image\//i.test(String(url || ''))) found = String(url);
|
|
6783
|
+
} catch {}
|
|
6784
|
+
}
|
|
6785
|
+
if (!found || found.length > 2500000) return '';
|
|
6786
|
+
return found;
|
|
6787
|
+
};
|
|
6788
|
+
|
|
6586
6789
|
/* İki ajanın ORTAK üyesi olduğu AÇIK grup var mı — 1:1 DM'leri grup içine
|
|
6587
6790
|
yönlendirirken kullanılır (ekip içi trafik tek thread'de toplanır). */
|
|
6588
6791
|
Engine.prototype._agentDmSharedGroup = function (a, b) {
|
|
@@ -6735,7 +6938,16 @@ Engine.prototype._persistAgentDms = function () {
|
|
|
6735
6938
|
try {
|
|
6736
6939
|
const groups = {};
|
|
6737
6940
|
for (const [, g] of this._agentGroups || new Map()) groups[g.id] = g;
|
|
6738
|
-
|
|
6941
|
+
/* görsel bütçesi: disk şişmesin — en yeni görseller tutulur (~24MB) */
|
|
6942
|
+
const dms = (this._agentDms || []).slice();
|
|
6943
|
+
let budget = 24 * 1024 * 1024;
|
|
6944
|
+
for (let i = dms.length - 1; i >= 0; i--) {
|
|
6945
|
+
const d = dms[i];
|
|
6946
|
+
if (!d || typeof d.image !== 'string' || !d.image) continue;
|
|
6947
|
+
if (d.image.length <= budget) { budget -= d.image.length; continue; }
|
|
6948
|
+
dms[i] = { ...d, image: '', imageOmitted: true };
|
|
6949
|
+
}
|
|
6950
|
+
this._atomicWrite(this._agentDmsFile, JSON.stringify({ dms, groups }, null, 2));
|
|
6739
6951
|
} catch {}
|
|
6740
6952
|
};
|
|
6741
6953
|
|
|
@@ -22,6 +22,7 @@ const NAMES = [
|
|
|
22
22
|
'mt5_history',
|
|
23
23
|
'mt5_alerts',
|
|
24
24
|
'mt5_note',
|
|
25
|
+
'mt5_ea',
|
|
25
26
|
'mt5_trade',
|
|
26
27
|
'mt5_close',
|
|
27
28
|
'mt5_modify',
|
|
@@ -226,6 +227,29 @@ const definitions = NAMES.map((name) => {
|
|
|
226
227
|
required: ['symbol', 'note'],
|
|
227
228
|
},
|
|
228
229
|
},
|
|
230
|
+
mt5_ea: {
|
|
231
|
+
description:
|
|
232
|
+
'BEASTFINANCE EA KÖPRÜSÜ (grafikte çalışan uzman danışman): action:"status" → EA heartbeat (yüklü mü, AutoTrading/EA izni, equity, pozisyon, son ack); "ping" → EA canlı yanıt; "chart" → aktif grafiğin sembol/periyot/fiyat/spread bilgisi; "note" → {symbol?, text, levels:[{price,label}]} grafik panosuna not + yatay seviye çizgileri yazar. NOT: yazdığın pano ve çizgiler görsel ajanın screenshot\'ında GÖRÜNÜR — GERÇEK grafik PNG\'si için varsayılan kurulu tool__mt5_shot kullan (EA "shot" komutu; görsel ajanın gözüne gelir), seviyeleri çizdikten sonra tool__mt5_shot ile görsel doğrula; grafiği agent_dm image ile ekibe paylaş.',
|
|
233
|
+
parameters: {
|
|
234
|
+
type: 'object',
|
|
235
|
+
properties: {
|
|
236
|
+
action: { type: 'string', enum: ['status', 'ping', 'chart', 'note'] },
|
|
237
|
+
symbol: { type: 'string', description: 'note: yalnız bu sembolün grafiğine uygulanır (boş = tüm grafikler)' },
|
|
238
|
+
text: { type: 'string', description: 'note: grafik panosuna yazılacak kısa analiz/plan metni' },
|
|
239
|
+
levels: {
|
|
240
|
+
type: 'array',
|
|
241
|
+
description: 'note: yatay seviye çizgileri (destek/direnç/SL/TP)',
|
|
242
|
+
items: {
|
|
243
|
+
type: 'object',
|
|
244
|
+
properties: { price: { type: 'number' }, label: { type: 'string' } },
|
|
245
|
+
required: ['price'],
|
|
246
|
+
},
|
|
247
|
+
},
|
|
248
|
+
timeoutSec: { type: 'number', description: 'ping/chart: EA yanıt bekleme süresi sn (varsayılan 8)' },
|
|
249
|
+
},
|
|
250
|
+
required: ['action'],
|
|
251
|
+
},
|
|
252
|
+
},
|
|
229
253
|
mt5_trade: {
|
|
230
254
|
description:
|
|
231
255
|
'PİYASA EMRİ AÇAR: mt5_trade {symbol, side:"buy"|"sell", volume, sl?, tp?, comment?, reason?}. Lot limiti ve max pozisyon sayısı sistem tarafından zorlanır. Otomatik işlem anahtarı kapalıysa reddedilir. SL/TP vermek ŞIDDETLİ önerilir. reason: kararın tek cümlelik tezi (günlüğe yazılır, performans değerlendirmesinde kullanılır).',
|
|
@@ -410,6 +434,34 @@ const handlers = {
|
|
|
410
434
|
}, ctx || {});
|
|
411
435
|
return { ok: true, saved: true };
|
|
412
436
|
},
|
|
437
|
+
async mt5_ea(args) {
|
|
438
|
+
if (!mt5.running) return notConnected();
|
|
439
|
+
const action = String(args.action || 'status').toLowerCase();
|
|
440
|
+
if (action === 'status') {
|
|
441
|
+
const data = await bcall('ea_status', {}, 10000);
|
|
442
|
+
return { ok: true, ...data };
|
|
443
|
+
}
|
|
444
|
+
if (action === 'note') {
|
|
445
|
+
const levels = Array.isArray(args.levels)
|
|
446
|
+
? args.levels
|
|
447
|
+
.slice(0, 20)
|
|
448
|
+
.map((x) => ({ price: Number(x && x.price) || 0, label: String((x && x.label) || '').slice(0, 40) }))
|
|
449
|
+
.filter((x) => x.price > 0)
|
|
450
|
+
: [];
|
|
451
|
+
const data = await bcall('ea_note', {
|
|
452
|
+
symbol: String(args.symbol || '').trim().toUpperCase(),
|
|
453
|
+
text: String(args.text || '').slice(0, 4000),
|
|
454
|
+
levels,
|
|
455
|
+
}, 10000);
|
|
456
|
+
return { ok: true, ...data, note: 'Grafik panosu güncellendi — computer_look screenshot\'ında görünür' };
|
|
457
|
+
}
|
|
458
|
+
if (action === 'ping' || action === 'chart') {
|
|
459
|
+
const timeoutSec = Math.max(2, Math.min(20, Number(args.timeoutSec) || 8));
|
|
460
|
+
const data = await bcall('ea_cmd', { cmd: action, timeoutSec }, (timeoutSec + 6) * 1000);
|
|
461
|
+
return { ok: true, ...data };
|
|
462
|
+
}
|
|
463
|
+
return { ok: false, error: 'action: status|ping|chart|note' };
|
|
464
|
+
},
|
|
413
465
|
async mt5_risksize(args) {
|
|
414
466
|
if (!mt5.running) return notConnected();
|
|
415
467
|
const cfg = getCfg();
|