beast-agent 2.20.0 → 2.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/src/agent/engine.js +13 -7
- package/src/agent/skills.js +83 -1
- package/src/renderer/index.html +15 -0
- package/src/renderer/renderer.js +114 -41
- package/src/renderer/style.css +70 -8
package/package.json
CHANGED
package/src/agent/engine.js
CHANGED
|
@@ -5317,23 +5317,25 @@ function emitSafe(engine, sessionId, ev) {
|
|
|
5317
5317
|
|
|
5318
5318
|
/* AJAN DM aracı: paralel/finance ajanlarının birbirine kısa mesaj atması.
|
|
5319
5319
|
Salt metin — hedef ajanın oturumuna [AJAN DM] bloğu olarak düşer; AJAN DM
|
|
5320
|
-
panelinde iki yönlü görünür.
|
|
5320
|
+
panelinde iki yönlü görünür. topic verirsen aynı konudaki mesajlar aynı
|
|
5321
|
+
oturumda toplanır (cevap zinciri tek thread'de devam eder). */
|
|
5321
5322
|
const AGENT_DM_DEF = {
|
|
5322
5323
|
type: 'function',
|
|
5323
5324
|
function: {
|
|
5324
5325
|
name: 'agent_dm',
|
|
5325
5326
|
description:
|
|
5326
|
-
'Send a short DM to another
|
|
5327
|
+
'Send a short DM to another running agent (parallel agents / finance agents) to coordinate: share findings, ask status, warn about risk, hand off work. `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.',
|
|
5327
5328
|
parameters: {
|
|
5328
5329
|
type: 'object',
|
|
5329
5330
|
properties: {
|
|
5330
5331
|
to: { type: 'string', description: 'Target agent session id or a title keyword' },
|
|
5332
|
+
topic: { type: 'string', description: 'Short subject label for the conversation thread, e.g. "GOLD pozisyon riski"' },
|
|
5331
5333
|
message: { type: 'string', description: 'Short message (1-3 sentences)' },
|
|
5332
5334
|
},
|
|
5333
5335
|
required: ['to', 'message'],
|
|
5334
5336
|
},
|
|
5335
5337
|
},
|
|
5336
|
-
};
|
|
5338
|
+
};
|
|
5337
5339
|
|
|
5338
5340
|
const TOOLS = [
|
|
5339
5341
|
...tools.definitions,
|
|
@@ -6150,12 +6152,15 @@ Engine.prototype._agentDmSend = function (fromSid, args) {
|
|
|
6150
6152
|
if (String(target) === String(fromSid)) return { ok: false, error: 'kendine DM atılamaz' };
|
|
6151
6153
|
const fromJob = jobs.get(String(fromSid));
|
|
6152
6154
|
const toJob = jobs.get(target);
|
|
6155
|
+
/* konu etiketi: aynı konudaki DM'ler panelde AYNI oturumda toplanır */
|
|
6156
|
+
const topic = String((args && args.topic) || '').replace(/\s+/g, ' ').trim().slice(0, 60) || '(genel)';
|
|
6153
6157
|
const dm = {
|
|
6154
6158
|
at: new Date().toISOString(),
|
|
6155
6159
|
from: String(fromSid),
|
|
6156
6160
|
fromTitle: (fromJob && fromJob.title) || 'Ajan',
|
|
6157
6161
|
to: String(target),
|
|
6158
6162
|
toTitle: (toJob && toJob.title) || 'Ajan',
|
|
6163
|
+
topic,
|
|
6159
6164
|
text,
|
|
6160
6165
|
};
|
|
6161
6166
|
this._agentDms = this._agentDms || [];
|
|
@@ -6165,15 +6170,16 @@ Engine.prototype._agentDmSend = function (fromSid, args) {
|
|
|
6165
6170
|
fs.writeFileSync(this._agentDmsFile, JSON.stringify({ dms: this._agentDms }, null, 2));
|
|
6166
6171
|
} catch {}
|
|
6167
6172
|
emitSafe(this, target, { type: 'agent-dm', ...dm });
|
|
6168
|
-
/* teslim: hedef meşgulse pending kuyruğunda bekler, done olunca düşer
|
|
6173
|
+
/* teslim: hedef meşgulse pending kuyruğunda bekler, done olunca düşer.
|
|
6174
|
+
Cevap zinciri AYNI thread'den sürsün diye topic geri bildirilir. */
|
|
6169
6175
|
(this._pendingReports = this._pendingReports || []).push({
|
|
6170
6176
|
parentId: target,
|
|
6171
6177
|
text:
|
|
6172
|
-
`[AJAN DM — ${dm.fromTitle}]\n${text}\n` +
|
|
6173
|
-
`(Cevabını agent_dm aracıyla ver — to: "${dm.fromTitle}")`,
|
|
6178
|
+
`[AJAN DM — ${dm.fromTitle} · konu: "${topic}"]\n${text}\n` +
|
|
6179
|
+
`(Cevabını agent_dm aracıyla ver — to: "${dm.fromTitle}", topic: "${topic}")`,
|
|
6174
6180
|
});
|
|
6175
6181
|
this.flushPendingReports(target);
|
|
6176
|
-
return { ok: true, to: target, toTitle: dm.toTitle };
|
|
6182
|
+
return { ok: true, to: target, toTitle: dm.toTitle, topic };
|
|
6177
6183
|
} catch (e) {
|
|
6178
6184
|
return { ok: false, error: String((e && e.message) || e) };
|
|
6179
6185
|
}
|
package/src/agent/skills.js
CHANGED
|
@@ -129,7 +129,8 @@ Get-Content "$env:APPDATA\\beast\\sessions\\bg-jobs.json" | ConvertFrom-Json | %
|
|
|
129
129
|
| \`agent/agentdefs.js\` | Özel ajan tanımları: %APPDATA%\beast\agents\\*.md (frontmatter: model/tools/steps/mode + prompt gövdesi); /agent ile bağlanır, run_background(agent:) ile paralel ajana verilir |
|
|
130
130
|
| \`agent/searxng.js\` | SearXNG entegrasyonu: gömülü Python'a kurulum + 127.0.0.1:8888 başlatıcı + JSON arama motoru |
|
|
131
131
|
| \`agent/bots.js\` | Bot CRUD, 5 haneli bot kodu, izolasyon; ad-ilk-harf doğrulaması |
|
|
132
|
-
| \`agent/skills.js\` | Builtin tohumlar (help, email, python-web-search, pdf, gold-trading + superpowers metodoloji paketi: brainstorming/writing-plans/executing-plans/TDD/paralel-ajan/alt-ajan-geliştirme/sistematik-debugging/doğrulama/skill-yazma) + SKILL.md taraması + taslaklar |
|
|
132
|
+
| \`agent/skills.js\` | Builtin tohumlar (help, email, python-web-search, pdf, gold-trading, tool-yazma + superpowers metodoloji paketi: brainstorming/writing-plans/executing-plans/TDD/paralel-ajan/alt-ajan-geliştirme/sistematik-debugging/doğrulama/skill-yazma) + SKILL.md taraması + taslaklar |
|
|
133
|
+
| \`agent/customtools.js\` | Kişisel toollar: %APPDATA%\\beast\\tools\\<ad>\\tool.json + run.js (stdin JSON → stdout JSON) — tool__<ad> olarak TÜM oturumlara açılır; sol panel TOOLLAR kutusunda yazılır/test edilir. Yeni tool yazarken \`tool-yazma\` skill'ini oku. |
|
|
133
134
|
| \`agent/memory.js\`, \`agent/kb.js\` | Kalıcı hafıza + bilgi bankası |
|
|
134
135
|
| \`cron.js\` (src kökü), \`agent/watchers.js\`, \`agent/bus.js\` | Cron, izleyici, olay merkezi — /stop bunlara DOKUNMAZ |
|
|
135
136
|
| \`agent/usage.js\` | Token/maliyet sayaçları |
|
|
@@ -456,6 +457,87 @@ const { createWorker } = require('tesseract.js');
|
|
|
456
457
|
| read_file boş metin döndü | taranmış PDF → 4. adım (görselleştir) + 5. adım (OCR) |
|
|
457
458
|
| tesseract dil verisi hatası | ilk indirme internet ister; tekrar dene |`,
|
|
458
459
|
},
|
|
460
|
+
{
|
|
461
|
+
folder: 'tool-yazma',
|
|
462
|
+
force: true,
|
|
463
|
+
body: `---
|
|
464
|
+
name: tool-yazma
|
|
465
|
+
description: Kişisel TOOL yazma/düzenleme rehberi — %APPDATA%\\beast\\tools\\<ad>\\ altına tool.json + run.js yazılacak veya mevcut bir tool editlenecekse ÖNCE bu skill'i oku. Tool'un sözleşmesi: stdin JSON argüman → stdout JSON sonuç; ajan tool__<ad> olarak çağırır (Beast Finance dahil tüm oturumlarda çalışır).
|
|
466
|
+
version: 1.0.0
|
|
467
|
+
---
|
|
468
|
+
|
|
469
|
+
# Kişisel TOOL Yazma
|
|
470
|
+
|
|
471
|
+
## TOOL NEDİR / NE ZAMAN YAZILIR
|
|
472
|
+
|
|
473
|
+
Kişisel tool = modelin alet çantasına GİREN gerçek bir araçtır: %APPDATA%\\beast\\tools\\<slug>\\ klasöründe **tool.json** (tanım) + **run.js** (kod) bulunur. Tüm oturumlarda — Beast Finance chat/trader/işçiler dahil — \`tool__<slug>\` adıyla çağrılır.
|
|
474
|
+
|
|
475
|
+
Yaz ZAMAN: mevcut araçlar işi görmüyorsa (örn. broker sembol adlandırması mt5_trade'i düşürüyorsa), özel bir API'ye bağlanman, tekrarlı bir hesap/işlem rutini gerekiyorsa. Basit işler için YAZMA — önce yerleşik araçları (mt5_*, web_search, python_run, run_command) dene.
|
|
476
|
+
|
|
477
|
+
## SÖZLEŞME (birebir uygula)
|
|
478
|
+
|
|
479
|
+
- **stdin**: JSON argümanlar (tek satırda, güvenli parse)
|
|
480
|
+
- **stdout**: SADECE JSON sonuç — son satır JSON'a çevrilmeye çalışılır; günlük/metin yazarsan JSON bozulur, \`console.error\` kullan
|
|
481
|
+
- **çalışma klasörü**: tool'un kendi klasörü (yanına dosya yazabilirsin)
|
|
482
|
+
- **zaman aşımı**: 90 sn — uzun işleri kendin parçalama, \`run_background\`'a devret
|
|
483
|
+
- **sonuç biçimi**: \`{ "ok": true, ... }\` ya da \`{ "ok": false, "error": "sebep" }\` — ok alanı ZORUNLU
|
|
484
|
+
|
|
485
|
+
## YENİ TOOL OLUŞTURMA (2 dosya, write_file ile)
|
|
486
|
+
|
|
487
|
+
\`%APPDATA%\\beast\\tools\\<slug>\\tool.json\`:
|
|
488
|
+
\`\`\`json
|
|
489
|
+
{
|
|
490
|
+
"name": "gold_emir",
|
|
491
|
+
"description": "GOLD için özel emir açar — side (buy/sell), lot, sl, tp alır; sonucu ticket ile döndürür.",
|
|
492
|
+
"parameters": {
|
|
493
|
+
"type": "object",
|
|
494
|
+
"properties": {
|
|
495
|
+
"side": { "type": "string", "description": "buy | sell" },
|
|
496
|
+
"lot": { "type": "number", "description": "0.01-1.0" },
|
|
497
|
+
"sl": { "type": "number" },
|
|
498
|
+
"tp": { "type": "number" }
|
|
499
|
+
},
|
|
500
|
+
"required": ["side", "lot"]
|
|
501
|
+
},
|
|
502
|
+
"updatedAt": "2026-09-09T00:00:00.000Z"
|
|
503
|
+
}
|
|
504
|
+
\`\`\`
|
|
505
|
+
|
|
506
|
+
\`%APPDATA%\\beast\\tools\\<slug>\\run.js\`:
|
|
507
|
+
\`\`\`javascript
|
|
508
|
+
'use strict';
|
|
509
|
+
// stdin: JSON args · stdout: JSON sonuç (SADECE JSON yaz!)
|
|
510
|
+
const fs = require('fs');
|
|
511
|
+
let args = {};
|
|
512
|
+
try { args = JSON.parse(fs.readFileSync(0, 'utf8') || '{}'); } catch {}
|
|
513
|
+
(function main() {
|
|
514
|
+
const { side, lot, sl, tp } = args;
|
|
515
|
+
if (!side || !lot) {
|
|
516
|
+
console.log(JSON.stringify({ ok: false, error: 'side ve lot zorunlu' }));
|
|
517
|
+
return;
|
|
518
|
+
}
|
|
519
|
+
// --- kendi işin burada: HTTP çağrısı, MT5 köprüsü, dosya, hesap... ---
|
|
520
|
+
// Örn: https modülüyle özel endpoint'e istek at, sonucu ok alanıyla sar.
|
|
521
|
+
console.log(JSON.stringify({ ok: true, side, lot, sl: sl || 0, tp: tp || 0, ticket: 0 }));
|
|
522
|
+
})();
|
|
523
|
+
\`\`\`
|
|
524
|
+
|
|
525
|
+
Slug kuralları: a-z, 0-9, alt çizgi, tire — 2-24 karakter (örn: gold_emir, haber_ozet). Hazır taslak: %APPDATA%\\beast\\tools\\ornek_echo klasörünü referans al; yeni tool'u o biçimle yaz.
|
|
526
|
+
|
|
527
|
+
## DÜZENLEME / DOĞRULAMA
|
|
528
|
+
|
|
529
|
+
1. Mevcut toolu değiştirme: \`edit_file\` ile tool.json / run.js düzenle — ASLA tüm klasörü silip baştan yazma.
|
|
530
|
+
2. Kayıttan sonra tool ANINDA aktifleşir (yeniden başlatma gerekmez) — bir sonraki turda \`tool__<slug>\` çağrılabilir.
|
|
531
|
+
3. Doğrula: \`run_command\` ile \`echo \\"{\\\\\\"mesaj\\\\\\":\\\\\\"test\\\\\\"}\\" | node \\"%APPDATA%\\\\beast\\\\tools\\\\<slug>\\\\run.js\\"\` — çıktı JSON olmalı ve \`ok\` alanı içermeli.
|
|
532
|
+
4. Hata çıktısı \`ok:false + error\` olsun — model hatayı okuyup düzeltir; çıplak stack yasak.
|
|
533
|
+
|
|
534
|
+
## GÜVENLİK + STİL
|
|
535
|
+
|
|
536
|
+
- Şifre/API anahtarını ASLA stdout'a, log'a, skill'e yazma.
|
|
537
|
+
- Ağ çağrılarında timeout kullan (\`https\` modülü + \`req.setTimeout\` veya fetch); sonsuz bekleyen script yazma.
|
|
538
|
+
- Tek sorumluluk: bir tool = bir iş. Çok işli dev tool yazma — parçala.
|
|
539
|
+
- Kullanıcıya tool'u nasıl yöneteceğini söyle: sol panelde TOOLLAR kutusunda test/düzenle/sil + 📂 klasör.`,
|
|
540
|
+
},
|
|
459
541
|
];
|
|
460
542
|
|
|
461
543
|
function writeSeed(seed) {
|
package/src/renderer/index.html
CHANGED
|
@@ -373,6 +373,21 @@
|
|
|
373
373
|
</aside>
|
|
374
374
|
</div>
|
|
375
375
|
|
|
376
|
+
<div id="dmOverlay" hidden>
|
|
377
|
+
<div id="dmDialog">
|
|
378
|
+
<div id="dmDialogHead">
|
|
379
|
+
<span id="dmDialogTitle">AJAN DM — OTURUMLAR</span>
|
|
380
|
+
<span class="bot-bar-btns">
|
|
381
|
+
<button id="dmColumnBtn" title="Yan sütunda canlı akış olarak da göster">▤︎</button>
|
|
382
|
+
<button id="dmModalClear" title="Tüm DM geçmişini sil"><svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a1 1 0 0 1 1-1h6a1 1 0 0 1 1 1v2"/><path d="M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6"/><path d="M10 11v6"/><path d="M14 11v6"/></svg></button>
|
|
383
|
+
<button id="dmModalClose" title="Kapat">✕︎</button>
|
|
384
|
+
</span>
|
|
385
|
+
</div>
|
|
386
|
+
<div id="dmDialogList"></div>
|
|
387
|
+
<div class="dm-hint">Thread = ajan çifti + konu · gelen/giden hepsi kronolojik</div>
|
|
388
|
+
</div>
|
|
389
|
+
</div>
|
|
390
|
+
|
|
376
391
|
<div id="toolOverlay" hidden>
|
|
377
392
|
<div id="toolDialog">
|
|
378
393
|
<div id="toolDialogHead">
|
package/src/renderer/renderer.js
CHANGED
|
@@ -45,6 +45,11 @@ const els = {
|
|
|
45
45
|
dmBtn: $('#dmBtn'),
|
|
46
46
|
dmRailList: $('#dmRailList'),
|
|
47
47
|
dmClear: $('#dmClear'),
|
|
48
|
+
dmOverlay: $('#dmOverlay'),
|
|
49
|
+
dmDialogList: $('#dmDialogList'),
|
|
50
|
+
dmModalClose: $('#dmModalClose'),
|
|
51
|
+
dmModalClear: $('#dmModalClear'),
|
|
52
|
+
dmColumnBtn: $('#dmColumnBtn'),
|
|
48
53
|
watchBtn: $('#watchBtn'),
|
|
49
54
|
watchPaneList: $('#watchPaneList'),
|
|
50
55
|
watchPaneOpen: $('#watchPaneOpen'),
|
|
@@ -5019,25 +5024,41 @@ async function loadRailChat(id) {
|
|
|
5019
5024
|
}
|
|
5020
5025
|
}
|
|
5021
5026
|
|
|
5022
|
-
/* ---------------- AJAN DM
|
|
5023
|
-
|
|
5024
|
-
|
|
5027
|
+
/* ---------------- AJAN DM (ajanlar arası konuşma) ----------------
|
|
5028
|
+
İki görünüm: ✉ modal (oturum listesi) + yan sütun (canlı akış).
|
|
5029
|
+
Thread anahtarı = ajan çifti + KONU — aynı konudaki mesajlar tek
|
|
5030
|
+
oturumda toplanır, gelen/giden hepsi kronolojik görünür. */
|
|
5025
5031
|
|
|
5026
5032
|
const dmState = {
|
|
5027
|
-
dms: [], // { at, from, fromTitle, to, toTitle, text }
|
|
5028
|
-
open: new Set(), // açık thread key'leri
|
|
5033
|
+
dms: [], // { at, from, fromTitle, to, toTitle, topic, text }
|
|
5034
|
+
open: new Set(), // açık thread key'leri (modal + sütun ortak)
|
|
5029
5035
|
};
|
|
5030
5036
|
|
|
5031
|
-
function
|
|
5037
|
+
function dmThreadOf(dm) {
|
|
5032
5038
|
const a = String(dm.from || '');
|
|
5033
5039
|
const b = String(dm.to || '');
|
|
5034
|
-
|
|
5040
|
+
const pair = a < b ? a + '|' + b : b + '|' + a;
|
|
5041
|
+
return pair + '|' + String(dm.topic || '(genel)').toLowerCase();
|
|
5035
5042
|
}
|
|
5036
5043
|
|
|
5037
|
-
function
|
|
5044
|
+
function dmThreadTitle(dm) {
|
|
5038
5045
|
const a = String(dm.fromTitle || 'Ajan');
|
|
5039
5046
|
const b = String(dm.toTitle || 'Ajan');
|
|
5040
|
-
|
|
5047
|
+
const pair = a < b ? a + ' ↔ ' + b : b + ' ↔ ' + a;
|
|
5048
|
+
const topic = String(dm.topic || '(genel)');
|
|
5049
|
+
return topic === '(genel)' ? pair : pair + ' · ' + topic;
|
|
5050
|
+
}
|
|
5051
|
+
|
|
5052
|
+
function dmThreads() {
|
|
5053
|
+
const threads = new Map();
|
|
5054
|
+
for (const dm of dmState.dms) {
|
|
5055
|
+
const key = dmThreadOf(dm);
|
|
5056
|
+
if (!threads.has(key)) threads.set(key, []);
|
|
5057
|
+
threads.get(key).push(dm);
|
|
5058
|
+
}
|
|
5059
|
+
return [...threads.entries()].sort(
|
|
5060
|
+
(x, y) => new Date(y[1][y[1].length - 1].at) - new Date(x[1][x[1].length - 1].at)
|
|
5061
|
+
);
|
|
5041
5062
|
}
|
|
5042
5063
|
|
|
5043
5064
|
function dmTime(iso) {
|
|
@@ -5046,6 +5067,15 @@ function dmTime(iso) {
|
|
|
5046
5067
|
return d.toLocaleTimeString('tr-TR', { hour: '2-digit', minute: '2-digit' });
|
|
5047
5068
|
}
|
|
5048
5069
|
|
|
5070
|
+
function dmMsgHtml(m) {
|
|
5071
|
+
return (
|
|
5072
|
+
`<div class="dmt-msg"><span class="dm-who">${escapeHtml(String(m.fromTitle || 'Ajan'))} → ${escapeHtml(String(m.toTitle || 'Ajan'))}</span>` +
|
|
5073
|
+
`${escapeHtml(String(m.text || ''))}<span class="dm-at">${dmTime(m.at)}</span></div>`
|
|
5074
|
+
);
|
|
5075
|
+
}
|
|
5076
|
+
|
|
5077
|
+
/* --- yan sütun --- */
|
|
5078
|
+
|
|
5049
5079
|
function renderDmRail() {
|
|
5050
5080
|
const list = els.dmRailList;
|
|
5051
5081
|
if (!list) return;
|
|
@@ -5053,37 +5083,19 @@ function renderDmRail() {
|
|
|
5053
5083
|
list.innerHTML = '<div class="dm-empty">Ajanlar arasında DM yok.<br>Ajanlar agent_dm aracıyla birbirine mesaj attıkça burada görünür.</div>';
|
|
5054
5084
|
return;
|
|
5055
5085
|
}
|
|
5056
|
-
/* çiftlere grupla (kronolojik) — en yeni thread üstte */
|
|
5057
|
-
const threads = new Map();
|
|
5058
|
-
for (const dm of dmState.dms) {
|
|
5059
|
-
const key = dmPairOf(dm);
|
|
5060
|
-
if (!threads.has(key)) threads.set(key, []);
|
|
5061
|
-
threads.get(key).push(dm);
|
|
5062
|
-
}
|
|
5063
|
-
const rows = [...threads.entries()].sort(
|
|
5064
|
-
(x, y) => new Date(y[1][y[1].length - 1].at) - new Date(x[1][x[1].length - 1].at)
|
|
5065
|
-
);
|
|
5066
5086
|
list.innerHTML = '';
|
|
5067
|
-
for (const [key, msgs] of
|
|
5087
|
+
for (const [key, msgs] of dmThreads()) {
|
|
5068
5088
|
const open = dmState.open.has(key);
|
|
5069
5089
|
const last = msgs[msgs.length - 1];
|
|
5070
5090
|
const el = document.createElement('div');
|
|
5071
5091
|
el.className = 'dmt' + (open ? ' open' : '');
|
|
5072
5092
|
el.innerHTML =
|
|
5073
5093
|
'<div class="dmt-head">' +
|
|
5074
|
-
`<span class="dmt-title">${escapeHtml(
|
|
5094
|
+
`<span class="dmt-title">${escapeHtml(dmThreadTitle(last))}</span>` +
|
|
5075
5095
|
`<span class="dmt-count">${msgs.length}</span>` +
|
|
5076
5096
|
'</div>' +
|
|
5077
5097
|
`<div class="dmt-last">${escapeHtml(String(last.text || '').replace(/\s+/g, ' ').slice(0, 90))} · ${dmTime(last.at)}</div>` +
|
|
5078
|
-
'<div class="dmt-msgs">' +
|
|
5079
|
-
msgs
|
|
5080
|
-
.map(
|
|
5081
|
-
(m) =>
|
|
5082
|
-
`<div class="dmt-msg"><span class="dm-who">${escapeHtml(String(m.fromTitle || 'Ajan'))} → ${escapeHtml(String(m.toTitle || 'Ajan'))}</span>` +
|
|
5083
|
-
`${escapeHtml(String(m.text || ''))}<span class="dm-at">${dmTime(m.at)}</span></div>`
|
|
5084
|
-
)
|
|
5085
|
-
.join('') +
|
|
5086
|
-
'</div>';
|
|
5098
|
+
'<div class="dmt-msgs">' + msgs.map(dmMsgHtml).join('') + '</div>';
|
|
5087
5099
|
el.addEventListener('click', () => {
|
|
5088
5100
|
if (dmState.open.has(key)) dmState.open.delete(key);
|
|
5089
5101
|
else dmState.open.add(key);
|
|
@@ -5111,18 +5123,77 @@ function toggleDmRail(hide) {
|
|
|
5111
5123
|
if (!hide) refreshDmRail();
|
|
5112
5124
|
}
|
|
5113
5125
|
|
|
5114
|
-
|
|
5115
|
-
|
|
5116
|
-
|
|
5126
|
+
/* --- modal (✉ butonu) --- */
|
|
5127
|
+
|
|
5128
|
+
function renderDmModal() {
|
|
5129
|
+
const list = els.dmDialogList;
|
|
5130
|
+
if (!list) return;
|
|
5131
|
+
if (!dmState.dms.length) {
|
|
5132
|
+
list.innerHTML = '<div class="dm-empty">Henüz ajan DM\u2019i yok.<br>Ajanlar agent_dm aracıyla birbirine mesaj attıkça oturumlar burada birikir.</div>';
|
|
5133
|
+
return;
|
|
5134
|
+
}
|
|
5135
|
+
list.innerHTML = '';
|
|
5136
|
+
for (const [key, msgs] of dmThreads()) {
|
|
5137
|
+
const open = dmState.open.has(key);
|
|
5138
|
+
const last = msgs[msgs.length - 1];
|
|
5139
|
+
const el = document.createElement('div');
|
|
5140
|
+
el.className = 'dmt' + (open ? ' open' : '');
|
|
5141
|
+
el.innerHTML =
|
|
5142
|
+
'<div class="dmt-head">' +
|
|
5143
|
+
`<span class="dmt-title">${escapeHtml(dmThreadTitle(last))}</span>` +
|
|
5144
|
+
`<span class="dmt-count">${msgs.length}</span>` +
|
|
5145
|
+
'</div>' +
|
|
5146
|
+
`<div class="dmt-last">${escapeHtml(String(last.text || '').replace(/\s+/g, ' ').slice(0, 120))} · ${dmTime(last.at)}</div>` +
|
|
5147
|
+
'<div class="dmt-msgs">' + msgs.map(dmMsgHtml).join('') + '</div>';
|
|
5148
|
+
el.addEventListener('click', () => {
|
|
5149
|
+
if (dmState.open.has(key)) dmState.open.delete(key);
|
|
5150
|
+
else dmState.open.add(key);
|
|
5151
|
+
renderDmModal();
|
|
5152
|
+
const again = els.dmDialogList.querySelector('.dmt.open .dmt-msgs');
|
|
5153
|
+
if (again) again.scrollTop = again.scrollHeight;
|
|
5154
|
+
});
|
|
5155
|
+
list.appendChild(el);
|
|
5156
|
+
}
|
|
5157
|
+
}
|
|
5158
|
+
|
|
5159
|
+
async function openDmModal() {
|
|
5160
|
+
if (!els.dmOverlay) return;
|
|
5161
|
+
els.dmOverlay.hidden = false;
|
|
5162
|
+
await refreshDmRail(); // kayıtları tazele
|
|
5163
|
+
renderDmModal();
|
|
5164
|
+
if (els.dmBtn) els.dmBtn.classList.add('on');
|
|
5165
|
+
}
|
|
5166
|
+
|
|
5167
|
+
function closeDmModal() {
|
|
5168
|
+
if (els.dmOverlay) els.dmOverlay.hidden = true;
|
|
5169
|
+
if (els.dmBtn) els.dmBtn.classList.remove('on');
|
|
5170
|
+
}
|
|
5171
|
+
|
|
5172
|
+
async function dmClearAll() {
|
|
5173
|
+
if (!(await uiConfirm('TÜM ajan DM geçmişi silinsin mi?', 'Sil'))) return;
|
|
5174
|
+
try { await beast.agentDmsClear(); } catch {}
|
|
5175
|
+
dmState.dms = [];
|
|
5176
|
+
renderDmRail();
|
|
5177
|
+
renderDmModal();
|
|
5178
|
+
toast('Ajan DM geçmişi silindi');
|
|
5179
|
+
}
|
|
5180
|
+
|
|
5181
|
+
if (els.dmBtn) els.dmBtn.addEventListener('click', openDmModal);
|
|
5182
|
+
if (els.dmModalClose) els.dmModalClose.addEventListener('click', closeDmModal);
|
|
5183
|
+
if (els.dmModalClear) els.dmModalClear.addEventListener('click', dmClearAll);
|
|
5184
|
+
if (els.dmOverlay) {
|
|
5185
|
+
els.dmOverlay.addEventListener('click', (e) => {
|
|
5186
|
+
if (e.target === els.dmOverlay) closeDmModal();
|
|
5187
|
+
});
|
|
5188
|
+
els.dmOverlay.addEventListener('keydown', (e) => {
|
|
5189
|
+
if (e.key === 'Escape') { e.stopPropagation(); closeDmModal(); }
|
|
5117
5190
|
});
|
|
5118
5191
|
}
|
|
5119
|
-
if (els.dmClear)
|
|
5120
|
-
|
|
5121
|
-
|
|
5122
|
-
|
|
5123
|
-
|
|
5124
|
-
renderDmRail();
|
|
5125
|
-
toast('Ajan DM geçmişi silindi');
|
|
5192
|
+
if (els.dmClear) els.dmClear.addEventListener('click', dmClearAll);
|
|
5193
|
+
if (els.dmColumnBtn) {
|
|
5194
|
+
els.dmColumnBtn.addEventListener('click', () => {
|
|
5195
|
+
closeDmModal();
|
|
5196
|
+
toggleDmRail(false); // yan sütunda canlı akış
|
|
5126
5197
|
});
|
|
5127
5198
|
}
|
|
5128
5199
|
|
|
@@ -5456,7 +5527,7 @@ function onEvent(ev) {
|
|
|
5456
5527
|
scheduleAgentsRender();
|
|
5457
5528
|
return;
|
|
5458
5529
|
}
|
|
5459
|
-
/* AJAN DM: ajanlar arası mesaj —
|
|
5530
|
+
/* AJAN DM: ajanlar arası mesaj — açık görünümde canlı düşer (modal/sütun) */
|
|
5460
5531
|
if (ev.type === 'agent-dm') {
|
|
5461
5532
|
dmState.dms.push({
|
|
5462
5533
|
at: ev.at,
|
|
@@ -5464,9 +5535,11 @@ function onEvent(ev) {
|
|
|
5464
5535
|
fromTitle: ev.fromTitle,
|
|
5465
5536
|
to: ev.to,
|
|
5466
5537
|
toTitle: ev.toTitle,
|
|
5538
|
+
topic: ev.topic,
|
|
5467
5539
|
text: ev.text,
|
|
5468
5540
|
});
|
|
5469
5541
|
if (dmState.dms.length > 400) dmState.dms.splice(0, dmState.dms.length - 400);
|
|
5542
|
+
if (els.dmOverlay && !els.dmOverlay.hidden) renderDmModal();
|
|
5470
5543
|
if ($('#dmRail') && !$('#dmRail').classList.contains('dm-hidden')) renderDmRail();
|
|
5471
5544
|
return;
|
|
5472
5545
|
}
|
package/src/renderer/style.css
CHANGED
|
@@ -110,15 +110,16 @@ body {
|
|
|
110
110
|
}
|
|
111
111
|
#newChat:hover { background: rgba(19, 19, 21, 0.14); }
|
|
112
112
|
|
|
113
|
-
#sessList { flex: 1; overflow-y: auto; padding: 4px 8px; }
|
|
113
|
+
#sessList { flex: 1 1 0; min-height: 0; overflow-y: auto; padding: 4px 8px; }
|
|
114
114
|
|
|
115
115
|
/* ---------- İZLEYİCİLER paneli (sol kenar çubuğu — sohbet geçmişinin alt yarısı) ----------
|
|
116
|
-
Yalnız agent (chat) modunda görünür; IDE/Studio/Sandbox'ta sessList ile birlikte gizli.
|
|
116
|
+
Yalnız agent (chat) modunda görünür; IDE/Studio/Sandbox'ta sessList ile birlikte gizli.
|
|
117
|
+
Sohbet geçmişi + izleyiciler + toollar EŞİT yer paylaşır (flex 1 1 0). */
|
|
117
118
|
#watchPane {
|
|
118
119
|
display: none;
|
|
119
120
|
flex-direction: column;
|
|
120
|
-
|
|
121
|
-
min-height:
|
|
121
|
+
flex: 1 1 0;
|
|
122
|
+
min-height: 110px;
|
|
122
123
|
border-top: 1px solid var(--border);
|
|
123
124
|
background: var(--panel);
|
|
124
125
|
}
|
|
@@ -2187,6 +2188,66 @@ body.rail-hidden #dmRailHead { padding-right: 148px; }
|
|
|
2187
2188
|
margin-top: 2px;
|
|
2188
2189
|
}
|
|
2189
2190
|
|
|
2191
|
+
/* ---------- AJAN DM modalı (✉) ---------- */
|
|
2192
|
+
#dmOverlay {
|
|
2193
|
+
position: fixed;
|
|
2194
|
+
inset: 0;
|
|
2195
|
+
background: rgba(0, 0, 0, 0.45);
|
|
2196
|
+
z-index: 300;
|
|
2197
|
+
display: flex;
|
|
2198
|
+
align-items: center;
|
|
2199
|
+
justify-content: center;
|
|
2200
|
+
}
|
|
2201
|
+
#dmOverlay[hidden] { display: none; }
|
|
2202
|
+
#dmDialog {
|
|
2203
|
+
width: min(680px, 92vw);
|
|
2204
|
+
max-height: 86vh;
|
|
2205
|
+
display: flex;
|
|
2206
|
+
flex-direction: column;
|
|
2207
|
+
background: var(--panel);
|
|
2208
|
+
border: 1px solid var(--border);
|
|
2209
|
+
border-radius: 12px;
|
|
2210
|
+
padding: 14px 16px;
|
|
2211
|
+
gap: 10px;
|
|
2212
|
+
}
|
|
2213
|
+
#dmDialogHead {
|
|
2214
|
+
display: flex;
|
|
2215
|
+
align-items: center;
|
|
2216
|
+
justify-content: space-between;
|
|
2217
|
+
font-size: 13px;
|
|
2218
|
+
font-weight: 800;
|
|
2219
|
+
letter-spacing: 1px;
|
|
2220
|
+
color: var(--text);
|
|
2221
|
+
}
|
|
2222
|
+
#dmDialogHead button {
|
|
2223
|
+
border: none;
|
|
2224
|
+
background: none;
|
|
2225
|
+
color: var(--muted);
|
|
2226
|
+
cursor: pointer;
|
|
2227
|
+
font-size: 13px;
|
|
2228
|
+
padding: 2px 6px;
|
|
2229
|
+
border-radius: 6px;
|
|
2230
|
+
display: inline-flex;
|
|
2231
|
+
align-items: center;
|
|
2232
|
+
}
|
|
2233
|
+
#dmDialogHead button:hover { color: var(--accent); background: var(--panel2); }
|
|
2234
|
+
#dmDialogHead .bot-bar-btns { display: flex; gap: 4px; }
|
|
2235
|
+
#dmDialogList {
|
|
2236
|
+
flex: 1 1 auto;
|
|
2237
|
+
min-height: 200px;
|
|
2238
|
+
overflow-y: auto;
|
|
2239
|
+
display: flex;
|
|
2240
|
+
flex-direction: column;
|
|
2241
|
+
align-items: stretch;
|
|
2242
|
+
}
|
|
2243
|
+
.dm-hint {
|
|
2244
|
+
flex: none;
|
|
2245
|
+
font-size: 10px;
|
|
2246
|
+
color: var(--muted);
|
|
2247
|
+
text-align: center;
|
|
2248
|
+
letter-spacing: 0.4px;
|
|
2249
|
+
}
|
|
2250
|
+
|
|
2190
2251
|
/* PİYASA satırındaki ▶ ajan butonu */
|
|
2191
2252
|
.fin-sym { position: relative; }
|
|
2192
2253
|
.fin-sym .fs-agent {
|
|
@@ -2275,10 +2336,11 @@ body.rail-hidden #dmRailHead { padding-right: 148px; }
|
|
|
2275
2336
|
color: var(--muted);
|
|
2276
2337
|
}
|
|
2277
2338
|
|
|
2278
|
-
/* ---------- sol panel: TOOLS konsolu (kişisel araçlar) ----------
|
|
2339
|
+
/* ---------- sol panel: TOOLS konsolu (kişisel araçlar) ----------
|
|
2340
|
+
Sohbet geçmişi + izleyiciler + toollar EŞİT yer paylaşır (flex 1 1 0). */
|
|
2279
2341
|
#toolBox {
|
|
2280
|
-
flex:
|
|
2281
|
-
|
|
2342
|
+
flex: 1 1 0;
|
|
2343
|
+
min-height: 90px;
|
|
2282
2344
|
display: none;
|
|
2283
2345
|
flex-direction: column;
|
|
2284
2346
|
border-top: 1px solid var(--border);
|
|
@@ -2296,8 +2358,8 @@ body:not(.ide-mode):not(.studio-mode):not(.sandbox-mode) #toolBox { display: fle
|
|
|
2296
2358
|
color: var(--muted);
|
|
2297
2359
|
}
|
|
2298
2360
|
#toolList {
|
|
2361
|
+
flex: 1 1 auto;
|
|
2299
2362
|
min-height: 40px;
|
|
2300
|
-
max-height: 200px;
|
|
2301
2363
|
overflow-y: auto;
|
|
2302
2364
|
display: flex;
|
|
2303
2365
|
flex-direction: column;
|