beast-agent 2.21.0 → 2.22.1
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/customtools.js +18 -8
- package/src/agent/engine.js +75 -7
- package/src/main.js +26 -14
- package/src/renderer/index.html +1 -0
- package/src/renderer/renderer.js +57 -33
- package/src/renderer/style.css +8 -0
package/package.json
CHANGED
package/src/agent/customtools.js
CHANGED
|
@@ -40,6 +40,22 @@ function invalidate() {
|
|
|
40
40
|
cache = null;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
+
/* klasör damgası: ajan/kullanıcı klasöre elle müdahale edince (write_file
|
|
44
|
+
vb.) cache BAYATLAR — damga değişince otomatik yeniden taranır */
|
|
45
|
+
let lastStamp = 0;
|
|
46
|
+
function folderStamp() {
|
|
47
|
+
try { return fs.statSync(dir()).mtimeMs; } catch { return 0; }
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function ensureFresh() {
|
|
51
|
+
const s = folderStamp();
|
|
52
|
+
if (dirty || !cache || s !== lastStamp) {
|
|
53
|
+
cache = scan();
|
|
54
|
+
dirty = false;
|
|
55
|
+
lastStamp = s;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
43
59
|
function readTool(d) {
|
|
44
60
|
try {
|
|
45
61
|
const json = JSON.parse(fs.readFileSync(path.join(d, 'tool.json'), 'utf8'));
|
|
@@ -81,10 +97,7 @@ function list() {
|
|
|
81
97
|
|
|
82
98
|
/* engine _chatTurn'e OpenAI function formatında şemalar */
|
|
83
99
|
function definitions() {
|
|
84
|
-
|
|
85
|
-
cache = scan();
|
|
86
|
-
dirty = false;
|
|
87
|
-
}
|
|
100
|
+
ensureFresh();
|
|
88
101
|
return cache.map((t) => ({
|
|
89
102
|
type: 'function',
|
|
90
103
|
function: {
|
|
@@ -97,10 +110,7 @@ function definitions() {
|
|
|
97
110
|
}
|
|
98
111
|
|
|
99
112
|
function names() {
|
|
100
|
-
|
|
101
|
-
cache = scan();
|
|
102
|
-
dirty = false;
|
|
103
|
-
}
|
|
113
|
+
ensureFresh();
|
|
104
114
|
return cache.map((t) => 'tool__' + t.id);
|
|
105
115
|
}
|
|
106
116
|
|
package/src/agent/engine.js
CHANGED
|
@@ -2190,7 +2190,52 @@ class Engine {
|
|
|
2190
2190
|
flat[k] = rest;
|
|
2191
2191
|
}
|
|
2192
2192
|
}
|
|
2193
|
-
|
|
2193
|
+
/* emniyet: assistant(tool_calls) ↔ tool sonucu ÇİFTLERİ hizala —
|
|
2194
|
+
yetim tool mesajı / cevapsız tool_call sağlayıcıda
|
|
2195
|
+
"Messages with role 'tool' must be a response to a preceding message
|
|
2196
|
+
with 'tool_calls'" (HTTP 400) verir (tur ortası enjeksiyon/kırpma
|
|
2197
|
+
çifti böldüğünde). */
|
|
2198
|
+
return Engine._alignToolPairs([{ role: 'system', content: system }, ...head, ...flat]);
|
|
2199
|
+
}
|
|
2200
|
+
|
|
2201
|
+
/* assistant(tool_calls) + hemen ardından gelen tool sonuçlarını hizalar:
|
|
2202
|
+
- cevabı GELMEYEN tool_call, assistant'tan DÜŞER (sonuç yok)
|
|
2203
|
+
- karşılıksız tool sonucu (yetim) DÜŞER
|
|
2204
|
+
- hiç sonucu olmayan assistant, düz metin asistana döner
|
|
2205
|
+
- tool_calls'sız mesajların ardından gelen tool'lar da yetimdir → düşer */
|
|
2206
|
+
static _alignToolPairs(msgs) {
|
|
2207
|
+
const out = [];
|
|
2208
|
+
for (let i = 0; i < msgs.length; i++) {
|
|
2209
|
+
const m = msgs[i];
|
|
2210
|
+
if (m && m.role === 'assistant' && Array.isArray(m.tool_calls) && m.tool_calls.length) {
|
|
2211
|
+
const results = [];
|
|
2212
|
+
let j = i + 1;
|
|
2213
|
+
while (j < msgs.length && msgs[j] && msgs[j].role === 'tool') {
|
|
2214
|
+
results.push(msgs[j]);
|
|
2215
|
+
j++;
|
|
2216
|
+
}
|
|
2217
|
+
const answered = new Set(results.map((r) => String(r.tool_call_id || '')));
|
|
2218
|
+
const kept = m.tool_calls.filter((tc) => answered.has(String(tc.id || '')));
|
|
2219
|
+
if (kept.length === m.tool_calls.length) {
|
|
2220
|
+
out.push(m);
|
|
2221
|
+
} else if (kept.length) {
|
|
2222
|
+
out.push({ ...m, tool_calls: kept });
|
|
2223
|
+
} else {
|
|
2224
|
+
const plain = { ...m };
|
|
2225
|
+
delete plain.tool_calls;
|
|
2226
|
+
out.push(plain);
|
|
2227
|
+
}
|
|
2228
|
+
const keepIds = new Set(kept.map((tc) => String(tc.id || '')));
|
|
2229
|
+
for (const r of results) {
|
|
2230
|
+
if (keepIds.has(String(r.tool_call_id || ''))) out.push(r);
|
|
2231
|
+
}
|
|
2232
|
+
i = j - 1;
|
|
2233
|
+
continue;
|
|
2234
|
+
}
|
|
2235
|
+
if (m && m.role === 'tool') continue; // yetim araç sonucu
|
|
2236
|
+
out.push(m);
|
|
2237
|
+
}
|
|
2238
|
+
return out;
|
|
2194
2239
|
}
|
|
2195
2240
|
|
|
2196
2241
|
_lastUserText(session) {
|
|
@@ -4681,13 +4726,15 @@ const skills = require('./skills');
|
|
|
4681
4726
|
});
|
|
4682
4727
|
}
|
|
4683
4728
|
if (name === 'ocr_read') return JSON.stringify(await this._ocrRead(args || {}, signal));
|
|
4684
|
-
/* opencode general-agent portu: alt-ajan da edit/grep/glob kullanır
|
|
4729
|
+
/* opencode general-agent portu: alt-ajan da edit/grep/glob kullanır.
|
|
4730
|
+
MT5 (mt5_*) araçları da tools.exec'e geçer (finance işçileri/danışma). */
|
|
4685
4731
|
if (!(name === 'run_command' || name === 'read_file' || name === 'write_file' || name === 'edit_file' ||
|
|
4686
4732
|
name === 'list_dir' || name === 'grep' || name === 'glob' ||
|
|
4687
4733
|
name === 'git_commit' || name === 'git_diff_review' || name === 'git_pr_create' ||
|
|
4688
4734
|
name === 'repo_map' || name === 'repo_symbols' ||
|
|
4689
4735
|
name === 'xlsx_read' || name === 'xlsx_write' || name === 'xlsx_edit' ||
|
|
4690
|
-
name === 'web_search' || name === 'http_fetch' || name === 'webfetch' || name === 'python_run')
|
|
4736
|
+
name === 'web_search' || name === 'http_fetch' || name === 'webfetch' || name === 'python_run') &&
|
|
4737
|
+
!FINANCE_TOOL_SET.has(name)) {
|
|
4691
4738
|
return JSON.stringify({ ok: false, error: `unknown tool ${name}` });
|
|
4692
4739
|
}
|
|
4693
4740
|
return await tools.exec(name, args, { cwd: this.workspace, signal });
|
|
@@ -5211,10 +5258,16 @@ const skills = require('./skills');
|
|
|
5211
5258
|
return JSON.stringify(await apps.call(name, args || {}, signal));
|
|
5212
5259
|
}
|
|
5213
5260
|
/* opencode tool registry portu: edit_file/grep/glob ana ajanın da araçları —
|
|
5214
|
-
bunlar olmadan model write_file + tam dosya okuma döngüsüne düşer
|
|
5215
|
-
|
|
5216
|
-
|
|
5217
|
-
|
|
5261
|
+
bunlar olmadan model write_file + tam dosya okuma döngüsüne düşer.
|
|
5262
|
+
MT5 (mt5_*) araçları tools.exec → financetools.handlers'a yönlendirilir —
|
|
5263
|
+
whitelist'te yoklarsa finance ajanı "unknown tool" yiyordu (işlem açamama
|
|
5264
|
+
hatasının kök nedeni). */
|
|
5265
|
+
if (
|
|
5266
|
+
!(name === 'run_command' || name === 'read_file' || name === 'write_file' || name === 'edit_file' ||
|
|
5267
|
+
name === 'list_dir' || name === 'grep' || name === 'glob' ||
|
|
5268
|
+
name === 'web_search' || name === 'http_fetch' || name === 'webfetch' || name === 'python_run') &&
|
|
5269
|
+
!FINANCE_TOOL_SET.has(name)
|
|
5270
|
+
) {
|
|
5218
5271
|
return JSON.stringify({ ok: false, error: `unknown tool ${name}` });
|
|
5219
5272
|
}
|
|
5220
5273
|
return await tools.exec(name, args, { cwd: this._sessionWorkspace(sessionId), signal, wantDiff: true });
|
|
@@ -6152,6 +6205,21 @@ Engine.prototype._agentDmSend = function (fromSid, args) {
|
|
|
6152
6205
|
if (String(target) === String(fromSid)) return { ok: false, error: 'kendine DM atılamaz' };
|
|
6153
6206
|
const fromJob = jobs.get(String(fromSid));
|
|
6154
6207
|
const toJob = jobs.get(target);
|
|
6208
|
+
/* FİNANS SINIRI: Beast Finance oturumu agent_dm kullansa bile finance
|
|
6209
|
+
dünyasının DIŞINA ÇIKMAZ — yalnız finance ajanlarına DM atabilir
|
|
6210
|
+
(trader ↔ GOLD işçisi ↔ finance işçileri). Finance dışı hedef reddedilir. */
|
|
6211
|
+
const fromSess = this.cache.get(String(fromSid)) || null;
|
|
6212
|
+
if (fromSess && fromSess.finance) {
|
|
6213
|
+
const targetSess = this.cache.get(String(target)) || null;
|
|
6214
|
+
if (!targetSess || !targetSess.finance) {
|
|
6215
|
+
return {
|
|
6216
|
+
ok: false,
|
|
6217
|
+
error:
|
|
6218
|
+
'Beast Finance ajanı yalnız finance dünyasındaki ajanlara DM atabilir — hedef finance dışı: ' +
|
|
6219
|
+
String((toJob && toJob.title) || to),
|
|
6220
|
+
};
|
|
6221
|
+
}
|
|
6222
|
+
}
|
|
6155
6223
|
/* konu etiketi: aynı konudaki DM'ler panelde AYNI oturumda toplanır */
|
|
6156
6224
|
const topic = String((args && args.topic) || '').replace(/\s+/g, ' ').trim().slice(0, 60) || '(genel)';
|
|
6157
6225
|
const dm = {
|
package/src/main.js
CHANGED
|
@@ -5063,22 +5063,19 @@ ipcMain.handle('agent:send', (_e, { sessionId, text }) => {
|
|
|
5063
5063
|
}
|
|
5064
5064
|
}
|
|
5065
5065
|
} catch {}
|
|
5066
|
-
/* BEAST FINANCE: finance
|
|
5067
|
-
|
|
5066
|
+
/* BEAST FINANCE: finance modunda yazılan sohbetler KALICI finance etiketi
|
|
5067
|
+
taşır — beast finance'ta kayıtlı kalır; normal modda yazmak etiketi
|
|
5068
|
+
KALDIRMAZ (oturum finance dışına çıkamaz) */
|
|
5068
5069
|
try {
|
|
5069
5070
|
if (sessionId) {
|
|
5070
5071
|
const fsid = String(sessionId);
|
|
5071
5072
|
let fsess = engine.cache.get(fsid);
|
|
5072
5073
|
if (!fsess) { try { fsess = engine._load(fsid); } catch {} }
|
|
5073
|
-
if (fsess && !fsess.botId && !fsess.bgJob) {
|
|
5074
|
-
|
|
5075
|
-
|
|
5076
|
-
|
|
5077
|
-
|
|
5078
|
-
engine.cache.set(fsid, fsess);
|
|
5079
|
-
} else if (fsess.finance) {
|
|
5080
|
-
engine.unmarkFinance(fsid); /* normal modda yazınca normal sohbete döner */
|
|
5081
|
-
}
|
|
5074
|
+
if (fsess && !fsess.botId && !fsess.bgJob && financeState.mode && !fsess.finance) {
|
|
5075
|
+
engine.markFinance(fsid, false);
|
|
5076
|
+
finApplyTraderFields(fsess);
|
|
5077
|
+
fsess.financeTrader = false; /* chat copilot'ı — trader değil */
|
|
5078
|
+
engine.cache.set(fsid, fsess);
|
|
5082
5079
|
}
|
|
5083
5080
|
}
|
|
5084
5081
|
} catch {}
|
|
@@ -8369,6 +8366,22 @@ try {
|
|
|
8369
8366
|
});
|
|
8370
8367
|
} catch {}
|
|
8371
8368
|
|
|
8369
|
+
/* TOOLS klasörü izleyici: ajan write_file ile tool yazdığında (ya da elle)
|
|
8370
|
+
konsol OTOMATİK güncellenir — restart gerekmez */
|
|
8371
|
+
try {
|
|
8372
|
+
fs.mkdirSync(customtools.dir(), { recursive: true });
|
|
8373
|
+
let toolWatchTimer = null;
|
|
8374
|
+
fs.watch(customtools.dir(), { recursive: true }, () => {
|
|
8375
|
+
clearTimeout(toolWatchTimer);
|
|
8376
|
+
toolWatchTimer = setTimeout(() => {
|
|
8377
|
+
customtools.invalidate();
|
|
8378
|
+
try {
|
|
8379
|
+
if (win && !win.isDestroyed()) win.webContents.send('agent:event', { type: 'tools-changed' });
|
|
8380
|
+
} catch {}
|
|
8381
|
+
}, 400);
|
|
8382
|
+
});
|
|
8383
|
+
} catch {}
|
|
8384
|
+
|
|
8372
8385
|
function financeEnsureBridge() {
|
|
8373
8386
|
const f = finCfg();
|
|
8374
8387
|
const candidates = [String(f.pythonPath || '').trim(), 'python', 'py -3'].filter(Boolean);
|
|
@@ -8744,10 +8757,9 @@ ipcMain.handle('finance:mode', async (_e, payload) => {
|
|
|
8744
8757
|
(eski davranış WhatsApp oturumunu da finance listesine karıştırıyordu) */
|
|
8745
8758
|
needNew = true;
|
|
8746
8759
|
}
|
|
8747
|
-
} else {
|
|
8748
|
-
/* mod kapandı: aktif finance oturumu normal sohbete döner */
|
|
8749
|
-
if (s.finance) engine.unmarkFinance(sid);
|
|
8750
8760
|
}
|
|
8761
|
+
/* mod kapandığında finance oturumları etiketlerini KORUR —
|
|
8762
|
+
beast finance'ta kayıtlı kalırlar (kaybolmazlar) */
|
|
8751
8763
|
engine.cache.set(sid, s);
|
|
8752
8764
|
}
|
|
8753
8765
|
} catch {}
|
package/src/renderer/index.html
CHANGED
|
@@ -378,6 +378,7 @@
|
|
|
378
378
|
<div id="dmDialogHead">
|
|
379
379
|
<span id="dmDialogTitle">AJAN DM — OTURUMLAR</span>
|
|
380
380
|
<span class="bot-bar-btns">
|
|
381
|
+
<button id="dmBackBtn" title="Oturum listesine dön" hidden>◀︎ Oturumlar</button>
|
|
381
382
|
<button id="dmColumnBtn" title="Yan sütunda canlı akış olarak da göster">▤︎</button>
|
|
382
383
|
<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
384
|
<button id="dmModalClose" title="Kapat">✕︎</button>
|
package/src/renderer/renderer.js
CHANGED
|
@@ -50,6 +50,7 @@ const els = {
|
|
|
50
50
|
dmModalClose: $('#dmModalClose'),
|
|
51
51
|
dmModalClear: $('#dmModalClear'),
|
|
52
52
|
dmColumnBtn: $('#dmColumnBtn'),
|
|
53
|
+
dmBackBtn: $('#dmBackBtn'),
|
|
53
54
|
watchBtn: $('#watchBtn'),
|
|
54
55
|
watchPaneList: $('#watchPaneList'),
|
|
55
56
|
watchPaneOpen: $('#watchPaneOpen'),
|
|
@@ -5025,13 +5026,13 @@ async function loadRailChat(id) {
|
|
|
5025
5026
|
}
|
|
5026
5027
|
|
|
5027
5028
|
/* ---------------- AJAN DM (ajanlar arası konuşma) ----------------
|
|
5028
|
-
|
|
5029
|
-
|
|
5030
|
-
|
|
5029
|
+
Paralel Ajanlar gibi: ✉ sağdaki SÜTUNU açar/kapatır (oturum listesi,
|
|
5030
|
+
canlı akış). Sütunda bir oturuma tıklayınca SOHBET yalnızca MODAL'da
|
|
5031
|
+
açılır — gelen/giden hepsi kronolojik. Thread = ajan çifti + KONU. */
|
|
5031
5032
|
|
|
5032
5033
|
const dmState = {
|
|
5033
5034
|
dms: [], // { at, from, fromTitle, to, toTitle, topic, text }
|
|
5034
|
-
|
|
5035
|
+
modalThread: null, // modalde açık oturum key'i (null = oturum listesi)
|
|
5035
5036
|
};
|
|
5036
5037
|
|
|
5037
5038
|
function dmThreadOf(dm) {
|
|
@@ -5074,35 +5075,27 @@ function dmMsgHtml(m) {
|
|
|
5074
5075
|
);
|
|
5075
5076
|
}
|
|
5076
5077
|
|
|
5077
|
-
/* ---
|
|
5078
|
+
/* --- sağ sütun: OTURUM LİSTESİ (rail gibi) --- */
|
|
5078
5079
|
|
|
5079
5080
|
function renderDmRail() {
|
|
5080
5081
|
const list = els.dmRailList;
|
|
5081
5082
|
if (!list) return;
|
|
5082
5083
|
if (!dmState.dms.length) {
|
|
5083
|
-
list.innerHTML = '<div class="dm-empty">Ajanlar arasında DM yok.<br>Ajanlar agent_dm aracıyla birbirine mesaj attıkça burada
|
|
5084
|
+
list.innerHTML = '<div class="dm-empty">Ajanlar arasında DM yok.<br>Ajanlar agent_dm aracıyla birbirine mesaj attıkça oturumlar burada birikir.</div>';
|
|
5084
5085
|
return;
|
|
5085
5086
|
}
|
|
5086
5087
|
list.innerHTML = '';
|
|
5087
5088
|
for (const [key, msgs] of dmThreads()) {
|
|
5088
|
-
const open = dmState.open.has(key);
|
|
5089
5089
|
const last = msgs[msgs.length - 1];
|
|
5090
5090
|
const el = document.createElement('div');
|
|
5091
|
-
el.className = 'dmt'
|
|
5091
|
+
el.className = 'dmt';
|
|
5092
5092
|
el.innerHTML =
|
|
5093
5093
|
'<div class="dmt-head">' +
|
|
5094
5094
|
`<span class="dmt-title">${escapeHtml(dmThreadTitle(last))}</span>` +
|
|
5095
5095
|
`<span class="dmt-count">${msgs.length}</span>` +
|
|
5096
5096
|
'</div>' +
|
|
5097
|
-
`<div class="dmt-last">${escapeHtml(String(last.text || '').replace(/\s+/g, ' ').slice(0, 90))} · ${dmTime(last.at)}</div
|
|
5098
|
-
|
|
5099
|
-
el.addEventListener('click', () => {
|
|
5100
|
-
if (dmState.open.has(key)) dmState.open.delete(key);
|
|
5101
|
-
else dmState.open.add(key);
|
|
5102
|
-
renderDmRail();
|
|
5103
|
-
const again = els.dmRailList.querySelector('.dmt.open .dmt-msgs');
|
|
5104
|
-
if (again) again.scrollTop = again.scrollHeight;
|
|
5105
|
-
});
|
|
5097
|
+
`<div class="dmt-last">${escapeHtml(String(last.text || '').replace(/\s+/g, ' ').slice(0, 90))} · ${dmTime(last.at)}</div>`;
|
|
5098
|
+
el.addEventListener('click', () => openDmModal(key)); // sohbet yalnız modalde
|
|
5106
5099
|
list.appendChild(el);
|
|
5107
5100
|
}
|
|
5108
5101
|
}
|
|
@@ -5113,6 +5106,7 @@ async function refreshDmRail() {
|
|
|
5113
5106
|
if (Array.isArray(dms)) dmState.dms = dms;
|
|
5114
5107
|
} catch {}
|
|
5115
5108
|
renderDmRail();
|
|
5109
|
+
if (els.dmOverlay && !els.dmOverlay.hidden) renderDmModal();
|
|
5116
5110
|
}
|
|
5117
5111
|
|
|
5118
5112
|
function toggleDmRail(hide) {
|
|
@@ -5123,45 +5117,58 @@ function toggleDmRail(hide) {
|
|
|
5123
5117
|
if (!hide) refreshDmRail();
|
|
5124
5118
|
}
|
|
5125
5119
|
|
|
5126
|
-
/* --- modal (
|
|
5120
|
+
/* --- modal: SOHBET (yalnız burada tam döküm) --- */
|
|
5127
5121
|
|
|
5128
5122
|
function renderDmModal() {
|
|
5129
5123
|
const list = els.dmDialogList;
|
|
5130
5124
|
if (!list) return;
|
|
5131
5125
|
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
|
|
5126
|
+
list.innerHTML = '<div class="dm-empty">Henüz ajan DM\u2019i yok.<br>Ajanlar agent_dm aracıyla birbirine mesaj attıkça oturumlar birikir.</div>';
|
|
5127
|
+
if (els.dmDialogTitle) els.dmDialogTitle.textContent = 'AJAN DM — OTURUMLAR';
|
|
5128
|
+
if (els.dmBackBtn) els.dmBackBtn.hidden = true;
|
|
5133
5129
|
return;
|
|
5134
5130
|
}
|
|
5131
|
+
if (dmState.modalThread) {
|
|
5132
|
+
/* TEK OTURUM: tam sohbet dökümü */
|
|
5133
|
+
const msgs = (dmThreads().find(([k]) => k === dmState.modalThread) || [null, []])[1];
|
|
5134
|
+
if (!msgs.length) {
|
|
5135
|
+
dmState.modalThread = null;
|
|
5136
|
+
return renderDmModal();
|
|
5137
|
+
}
|
|
5138
|
+
if (els.dmDialogTitle) els.dmDialogTitle.textContent = dmThreadTitle(msgs[msgs.length - 1]);
|
|
5139
|
+
if (els.dmBackBtn) els.dmBackBtn.hidden = false;
|
|
5140
|
+
list.innerHTML = '<div class="dm-thread-msgs">' + msgs.map(dmMsgHtml).join('') + '</div>';
|
|
5141
|
+
const box = list.querySelector('.dm-thread-msgs');
|
|
5142
|
+
if (box) box.scrollTop = box.scrollHeight;
|
|
5143
|
+
return;
|
|
5144
|
+
}
|
|
5145
|
+
/* OTURUM LİSTESİ */
|
|
5146
|
+
if (els.dmDialogTitle) els.dmDialogTitle.textContent = 'AJAN DM — OTURUMLAR';
|
|
5147
|
+
if (els.dmBackBtn) els.dmBackBtn.hidden = true;
|
|
5135
5148
|
list.innerHTML = '';
|
|
5136
5149
|
for (const [key, msgs] of dmThreads()) {
|
|
5137
|
-
const open = dmState.open.has(key);
|
|
5138
5150
|
const last = msgs[msgs.length - 1];
|
|
5139
5151
|
const el = document.createElement('div');
|
|
5140
|
-
el.className = 'dmt'
|
|
5152
|
+
el.className = 'dmt';
|
|
5141
5153
|
el.innerHTML =
|
|
5142
5154
|
'<div class="dmt-head">' +
|
|
5143
5155
|
`<span class="dmt-title">${escapeHtml(dmThreadTitle(last))}</span>` +
|
|
5144
5156
|
`<span class="dmt-count">${msgs.length}</span>` +
|
|
5145
5157
|
'</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>';
|
|
5158
|
+
`<div class="dmt-last">${escapeHtml(String(last.text || '').replace(/\s+/g, ' ').slice(0, 120))} · ${dmTime(last.at)}</div>`;
|
|
5148
5159
|
el.addEventListener('click', () => {
|
|
5149
|
-
|
|
5150
|
-
else dmState.open.add(key);
|
|
5160
|
+
dmState.modalThread = key;
|
|
5151
5161
|
renderDmModal();
|
|
5152
|
-
const again = els.dmDialogList.querySelector('.dmt.open .dmt-msgs');
|
|
5153
|
-
if (again) again.scrollTop = again.scrollHeight;
|
|
5154
5162
|
});
|
|
5155
5163
|
list.appendChild(el);
|
|
5156
5164
|
}
|
|
5157
5165
|
}
|
|
5158
5166
|
|
|
5159
|
-
|
|
5167
|
+
function openDmModal(threadKey) {
|
|
5160
5168
|
if (!els.dmOverlay) return;
|
|
5169
|
+
dmState.modalThread = threadKey || null;
|
|
5161
5170
|
els.dmOverlay.hidden = false;
|
|
5162
|
-
|
|
5163
|
-
renderDmModal();
|
|
5164
|
-
if (els.dmBtn) els.dmBtn.classList.add('on');
|
|
5171
|
+
refreshDmRail().then(() => renderDmModal());
|
|
5165
5172
|
}
|
|
5166
5173
|
|
|
5167
5174
|
function closeDmModal() {
|
|
@@ -5173,14 +5180,26 @@ async function dmClearAll() {
|
|
|
5173
5180
|
if (!(await uiConfirm('TÜM ajan DM geçmişi silinsin mi?', 'Sil'))) return;
|
|
5174
5181
|
try { await beast.agentDmsClear(); } catch {}
|
|
5175
5182
|
dmState.dms = [];
|
|
5183
|
+
dmState.modalThread = null;
|
|
5176
5184
|
renderDmRail();
|
|
5177
5185
|
renderDmModal();
|
|
5178
5186
|
toast('Ajan DM geçmişi silindi');
|
|
5179
5187
|
}
|
|
5180
5188
|
|
|
5181
|
-
if (els.dmBtn)
|
|
5189
|
+
if (els.dmBtn) {
|
|
5190
|
+
els.dmBtn.addEventListener('click', () => {
|
|
5191
|
+
/* kapalıyken (dm-hidden VAR) aç: toggle 'hide' SEMANTIĞI tersine çevrilir */
|
|
5192
|
+
toggleDmRail(!$('#dmRail').classList.contains('dm-hidden'));
|
|
5193
|
+
});
|
|
5194
|
+
}
|
|
5182
5195
|
if (els.dmModalClose) els.dmModalClose.addEventListener('click', closeDmModal);
|
|
5183
5196
|
if (els.dmModalClear) els.dmModalClear.addEventListener('click', dmClearAll);
|
|
5197
|
+
if (els.dmBackBtn) {
|
|
5198
|
+
els.dmBackBtn.addEventListener('click', () => {
|
|
5199
|
+
dmState.modalThread = null; // oturum listesine dön
|
|
5200
|
+
renderDmModal();
|
|
5201
|
+
});
|
|
5202
|
+
}
|
|
5184
5203
|
if (els.dmOverlay) {
|
|
5185
5204
|
els.dmOverlay.addEventListener('click', (e) => {
|
|
5186
5205
|
if (e.target === els.dmOverlay) closeDmModal();
|
|
@@ -5193,7 +5212,7 @@ if (els.dmClear) els.dmClear.addEventListener('click', dmClearAll);
|
|
|
5193
5212
|
if (els.dmColumnBtn) {
|
|
5194
5213
|
els.dmColumnBtn.addEventListener('click', () => {
|
|
5195
5214
|
closeDmModal();
|
|
5196
|
-
toggleDmRail(false); //
|
|
5215
|
+
toggleDmRail(false); // sütunda canlı akış
|
|
5197
5216
|
});
|
|
5198
5217
|
}
|
|
5199
5218
|
|
|
@@ -5557,6 +5576,11 @@ function onEvent(ev) {
|
|
|
5557
5576
|
scheduleToolRender();
|
|
5558
5577
|
return;
|
|
5559
5578
|
}
|
|
5579
|
+
/* TOOLS klasörü değişti (ajan yeni tool yazdı / elle edit) — konsolu tazele */
|
|
5580
|
+
if (ev.type === 'tools-changed') {
|
|
5581
|
+
scheduleToolRender();
|
|
5582
|
+
return;
|
|
5583
|
+
}
|
|
5560
5584
|
/* OFFLINE MESAJ KUYRUĞU: bağlantı + kuyruk olayları (sessionId filtresinden önce) */
|
|
5561
5585
|
if (ev.type === 'net' || ev.type === 'netQueue') { onNetEvent(ev); return; }
|
|
5562
5586
|
/* Sandbox klonlama progress'i (sessionId'siz global olay) */
|
package/src/renderer/style.css
CHANGED
|
@@ -2240,6 +2240,14 @@ body.rail-hidden #dmRailHead { padding-right: 148px; }
|
|
|
2240
2240
|
flex-direction: column;
|
|
2241
2241
|
align-items: stretch;
|
|
2242
2242
|
}
|
|
2243
|
+
/* tek oturum sohbeti: kaydırılabilir blok */
|
|
2244
|
+
.dm-thread-msgs {
|
|
2245
|
+
display: flex;
|
|
2246
|
+
flex-direction: column;
|
|
2247
|
+
gap: 5px;
|
|
2248
|
+
max-height: 56vh;
|
|
2249
|
+
overflow-y: auto;
|
|
2250
|
+
}
|
|
2243
2251
|
.dm-hint {
|
|
2244
2252
|
flex: none;
|
|
2245
2253
|
font-size: 10px;
|