beast-agent 2.3.4 → 2.4.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/src/main.js CHANGED
@@ -2937,6 +2937,7 @@ function reloadBackend() {
2937
2937
  },
2938
2938
  emit: (ev) => {
2939
2939
  if (win && !win.isDestroyed()) win.webContents.send('agent:event', ev);
2940
+ try { empatiRememberFromEvent(ev); } catch {} /* empati hafızası: sohbet → kayıt + ilgi öğrenme */
2940
2941
  flushDesktopOnDone(ev); /* biriken desktop mesajlarını sıraya bas */
2941
2942
  bcFlushOnDone(ev); /* Beast Code kuyruğunu iş bitiminde boşalt */
2942
2943
  stFlushOnDone(ev); /* Beast Studio kuyruğunu iş bitiminde boşalt */
@@ -3256,6 +3257,7 @@ app.whenReady().then(() => {
3256
3257
  createTray();
3257
3258
  cron.init({ onFire: cronFire });
3258
3259
  watchers.start({ onTrigger: watcherFire });
3260
+ empatiKickoff(); // empati loop: açılış + 90 sn sonra ilk tarama, sonra cfg aralığı
3259
3261
  startEventBus();
3260
3262
  ideWatchStart(); // soldaki dosya ağacı canlı izlemede
3261
3263
  studioWatchStart(); // Beast Studio klasörü canlı izlemede
@@ -6187,6 +6189,227 @@ function watcherFire(w, value) {
6187
6189
  } catch {}
6188
6190
  }
6189
6191
 
6192
+ /* ---------- EMPATİ LOOP: proaktif algı/event alt sistemi ----------
6193
+ Ana sohbet motorundan bağımsız: sinyal topla → ucuz filtre modeliyle puanla →
6194
+ kompozit öncelik → değerliyse ANA modelle kısa proaktif mesaj üret →
6195
+ masaüstü + WA'ya bildir. Önemsiz olaylar yalnız depoya yazılır, rahatsız etmez. */
6196
+
6197
+ const empati = require('./agent/perception');
6198
+ const empatiRuntime = { running: false, timer: null };
6199
+
6200
+ function empatiCfg() {
6201
+ return empati.mergeCfg(settings.empati || {});
6202
+ }
6203
+
6204
+ /* EMPATİ HAFIZASI: sohbet akışını kaydet + kullanıcı ilgi alanlarını öğren.
6205
+ - user mesajı → hafızaya yaz + sık kelimelerden ilgi etiketi öğren
6206
+ - assistant cevabı → hafızaya yaz (konuşmanın iki yanı da kalsın)
6207
+ Beast Code/Studio iş mesajları, /komutlar ve bağlam enjeksiyonları kayda girmez. */
6208
+ function empatiRememberFromEvent(ev) {
6209
+ if (!ev || ev.type !== 'message' || !ev.message || !ev.message.role) return;
6210
+ const m = ev.message;
6211
+ if (m.role !== 'user' && m.role !== 'assistant') return;
6212
+ const txt = typeof m.content === 'string' ? m.content : '';
6213
+ if (!txt.trim()) return;
6214
+ if (txt.startsWith((engine && engine.OBSERVE_MARK) || '[BAĞLAM')) return; /* sessiz bağlam — sohbet değil */
6215
+ if (m.role === 'user' && txt.startsWith('/')) return; /* slash komut gürültüsü */
6216
+ let bc = false;
6217
+ try {
6218
+ const s = engine && engine.cache && engine.cache.get(String(ev.sessionId || ''));
6219
+ bc = !!(s && (s.bcCode || s.bcMode));
6220
+ } catch {}
6221
+ if (bc) return; /* kod işi — ilgi alanını bulanıklaştırır */
6222
+ if (m.role === 'user') {
6223
+ empati.rememberConversation(txt, 'sohbet');
6224
+ empati.learnInterests(txt);
6225
+ } else {
6226
+ empati.rememberConversation(txt, 'beast');
6227
+ }
6228
+ }
6229
+
6230
+ function empatiLog(line) {
6231
+ try { waLog('[EMPATİ] ' + line); } catch {}
6232
+ }
6233
+
6234
+ /* tarama (filtre) modeli: sekmeden seçilmişse onu çöz; seçilmemişse ANA model */
6235
+ function empatiFilterSel() {
6236
+ const fm = empatiCfg().filterModel;
6237
+ if (fm) {
6238
+ try {
6239
+ const r = engine._resolve(fm);
6240
+ if (r) return r;
6241
+ } catch {}
6242
+ }
6243
+ return engine.sel;
6244
+ }
6245
+
6246
+ /* sinyal toplayıcılar — perception modülü saf kalır, engine/köprülerle burada konuşur */
6247
+ async function empatiSignalSelf() {
6248
+ const out = [];
6249
+ try {
6250
+ const w = engine.lastWhereWasI();
6251
+ if (w && w.pendingTodos && w.pendingTodos.length) {
6252
+ out.push({
6253
+ type: 'todo',
6254
+ title: 'Yarım kalan görevler: ' + w.pendingTodos.map((t) => t.title).join(' · ').slice(0, 200),
6255
+ detail: 'oturum ' + (w.code || '') + ' · ' + w.pendingTodos.length + ' görev bekliyor',
6256
+ });
6257
+ }
6258
+ } catch {}
6259
+ return out;
6260
+ }
6261
+
6262
+ async function empatiSignalNews() {
6263
+ const topics = String(empatiCfg().newsTopics || '').split(',').map((s) => s.trim()).filter(Boolean);
6264
+ if (!topics.length) return [];
6265
+ return empati.fetchNews(topics);
6266
+ }
6267
+
6268
+ /* tek toplu filtre çağrısı (maliyet freni); model yok/çökerse boş → deterministik puan */
6269
+ function empatiLlmFilter(prompt) {
6270
+ const sel = empatiFilterSel();
6271
+ if (!sel) return Promise.resolve('');
6272
+ const ctrl = new AbortController();
6273
+ const kill = setTimeout(() => ctrl.abort(), 45000);
6274
+ return require('./agent/llm')
6275
+ .chatOnce(sel, {
6276
+ messages: [
6277
+ { role: 'system', content: empati.FILTER_SYSTEM },
6278
+ { role: 'user', content: prompt },
6279
+ ],
6280
+ temperature: 0.1,
6281
+ }, { signal: ctrl.signal })
6282
+ .then((r) => String(r.content || ''))
6283
+ .catch(() => '')
6284
+ .finally(() => clearTimeout(kill));
6285
+ }
6286
+
6287
+ /* compose her zaman ANA model kullanır — filtre ucuz, anlamlandırma güçlü */
6288
+ function empatiLlmCompose(prompt) {
6289
+ if (!engine.sel) return Promise.resolve('');
6290
+ const ctrl = new AbortController();
6291
+ const kill = setTimeout(() => ctrl.abort(), 60000);
6292
+ return require('./agent/llm')
6293
+ .chatOnce(engine.sel, {
6294
+ messages: [
6295
+ { role: 'system', content: empati.COMPOSE_SYSTEM },
6296
+ { role: 'user', content: prompt },
6297
+ ],
6298
+ temperature: 0.6,
6299
+ }, { signal: ctrl.signal })
6300
+ .then((r) => String(r.content || '').trim().slice(0, 600))
6301
+ .catch(() => '')
6302
+ .finally(() => clearTimeout(kill));
6303
+ }
6304
+
6305
+ /* bildirim hedefi: sekmeden seçilen entegrasyon; seçilmemişse bağlı olanlar.
6306
+ Hiçbir entegrasyon yazılamazsa masaüstü chat UI (toast) kalır. */
6307
+ function empatiNotify(text, ev) {
6308
+ const cfg = empatiCfg();
6309
+ const senders = [];
6310
+ const tryWa = () => {
6311
+ try {
6312
+ const own = waOwnerNum();
6313
+ if (own && wa && wa.connected) senders.push(() => sendWaSafe(own + '@s.whatsapp.net', '🫡 *Beast proaktif:*\n' + text));
6314
+ } catch {}
6315
+ };
6316
+ const tryTg = () => {
6317
+ try {
6318
+ if (tg && tg.connected) for (const id of tgOwnerIds()) senders.push(() => sendTgSafe(id, '🫡 *Beast proaktif:*\n' + text));
6319
+ } catch {}
6320
+ };
6321
+ const tryDc = () => {
6322
+ try {
6323
+ if (dc && dc.connected) for (const id of dcOwnerIds()) senders.push(() => sendDcSafe(id, '🫡 **Beast proaktif:**\n' + text));
6324
+ } catch {}
6325
+ };
6326
+ if (cfg.notifyTarget === 'whatsapp') tryWa();
6327
+ else if (cfg.notifyTarget === 'telegram') tryTg();
6328
+ else if (cfg.notifyTarget === 'discord') tryDc();
6329
+ else { tryWa(); tryTg(); tryDc(); } // auto: ekli/bağlı entegrasyonlar
6330
+ let sent = 0;
6331
+ for (const fn of senders) {
6332
+ try { fn(); sent++; } catch {}
6333
+ }
6334
+ /* hiçbir entegrasyona yazılamadıysa yalnız masaüstü chat UI'a düş */
6335
+ try {
6336
+ if (!sent && win && !win.isDestroyed()) {
6337
+ win.webContents.send('agent:event', { type: 'proactive', id: ev.id, level: ev.level, title: ev.title, text });
6338
+ }
6339
+ } catch {}
6340
+ }
6341
+
6342
+ async function empatiCycle(manual) {
6343
+ if (empatiRuntime.running) return { ok: false, error: 'döngü zaten çalışıyor' };
6344
+ const cfg = empatiCfg();
6345
+ if (!cfg.enabled && !manual) return { ok: false, error: 'kapalı' };
6346
+ empatiRuntime.running = true;
6347
+ try {
6348
+ /* zaman aşımı emniyeti: sinyal/LLM takılırsa `running` bayrağı sonsuz kilitlenmesin
6349
+ (yoksa "Şimdi Tara" sürekli 'döngü zaten çalışıyor' der) */
6350
+ const r = await Promise.race([
6351
+ empati.runCycle({
6352
+ cfg,
6353
+ signals: { self: empatiSignalSelf, news: empatiSignalNews },
6354
+ llmFilter: empatiLlmFilter,
6355
+ now: new Date(),
6356
+ log: empatiLog,
6357
+ }),
6358
+ new Promise((_, rej) => setTimeout(() => rej(new Error('döngü zaman aşımı (2 dk)')), 120000).unref()),
6359
+ ]);
6360
+ let notified = 0;
6361
+ for (const a of r.actions) {
6362
+ let text = '';
6363
+ try { text = await empatiLlmCompose(empati.composePrompt(a.event, cfg)); } catch {}
6364
+ if (!text) text = empati.composeFallback(a.event);
6365
+ empatiNotify(text, a.event);
6366
+ empati.markNotified(a.event.id, a.level, text, cfg.cooldownMin);
6367
+ try { empati.rememberConversation('[proaktif] ' + text, 'empati'); } catch {}
6368
+ notified++;
6369
+ }
6370
+ if (notified && win && !win.isDestroyed()) {
6371
+ win.webContents.send('agent:event', { type: 'empati', notified });
6372
+ }
6373
+ return { ok: true, ...r.summary, notified };
6374
+ } finally {
6375
+ empatiRuntime.running = false;
6376
+ }
6377
+ }
6378
+
6379
+ function empatiSchedule() {
6380
+ if (empatiRuntime.timer) clearTimeout(empatiRuntime.timer);
6381
+ empatiRuntime.timer = null;
6382
+ const cfg = empatiCfg();
6383
+ if (!cfg.enabled) return;
6384
+ empatiRuntime.timer = setTimeout(async () => {
6385
+ try { await empatiCycle(false); } catch {}
6386
+ empatiSchedule();
6387
+ }, cfg.intervalMin * 60000);
6388
+ }
6389
+
6390
+ /* açılış + 90 sn: ilk tarama (başlangıç fırtınasını önle), sonra cfg aralığı */
6391
+ function empatiKickoff() {
6392
+ setTimeout(() => {
6393
+ empatiCycle(false).catch(() => {});
6394
+ empatiSchedule();
6395
+ }, 90 * 1000);
6396
+ }
6397
+
6398
+ ipcMain.handle('empati:get', () => ({ ...empatiCfg(), running: empatiRuntime.running, lastRunAt: empati.lastRunAt() }));
6399
+ ipcMain.handle('empati:set', (_e, patch) => {
6400
+ const cfg = empati.mergeCfg({ ...empatiCfg(), ...(patch || {}) });
6401
+ settings.empati = cfg;
6402
+ saveSettings();
6403
+ empatiSchedule(); // aralık/model değişmiş olabilir
6404
+ return { ...cfg };
6405
+ });
6406
+ ipcMain.handle('empati:scan', async () => {
6407
+ try { return await empatiCycle(true); } catch (e) { return { ok: false, error: String((e && e.message) || e).slice(0, 200) }; }
6408
+ });
6409
+ ipcMain.handle('empati:events', () => empati.listEvents(80));
6410
+ ipcMain.handle('empati:memory', () => empati.memSnapshot(40));
6411
+ ipcMain.handle('empati:memclear', () => empati.memClear());
6412
+
6190
6413
  ipcMain.handle('cron:list', () => cron.list());
6191
6414
  /* #23 Fallout: provider → kayıtlı API key haritası.
6192
6415
  Birincil kaynak: engine chain (config+custom+env çözülmüş).
package/src/preload.js CHANGED
@@ -207,4 +207,10 @@ contextBridge.exposeInMainWorld('beast', {
207
207
  ideDelete: (rel) => ipcRenderer.invoke('ide:delete', rel),
208
208
  onWaEvent: (cb) => ipcRenderer.on('wa:event', (_e, ev) => cb(ev)),
209
209
  onEvent: (cb) => ipcRenderer.on('agent:event', (_e, ev) => cb(ev)),
210
+ empatiGet: () => ipcRenderer.invoke('empati:get'),
211
+ empatiSet: (patch) => ipcRenderer.invoke('empati:set', patch),
212
+ empatiScan: () => ipcRenderer.invoke('empati:scan'),
213
+ empatiEvents: () => ipcRenderer.invoke('empati:events'),
214
+ empatiMemory: () => ipcRenderer.invoke('empati:memory'),
215
+ empatiMemClear: () => ipcRenderer.invoke('empati:memclear'),
210
216
  });
@@ -114,6 +114,50 @@
114
114
  up_install_now: 'Yeniden Başlat & Kur',
115
115
  up_note: 'Kurulumdan sonra uygulama otomatik yeniden başlar. İstersen WhatsApp\u2019tan /update komutunu da kullanabilirsin.',
116
116
  tab_events: 'Olay Merkezi',
117
+ tab_empati: 'Empati Loop',
118
+ em_h2: 'Empati Loop — Proaktif Algı',
119
+ em_sub: 'Beast arka planda periyodik tarar: yarım kalan işler, haber akışı. Boru hattı: sinyal → ucuz filtre modeli → öncelik puanı → bildirim. Önemsiz olaylar yalnız depoya yazılır, seni rahatsız etmez.',
120
+ em_ipc_err: 'Empati servisine ulaşılamadı.',
121
+ em_on: 'Empati Loop açık',
122
+ em_interval: 'Tarama aralığı (dk)',
123
+ em_min_notify: 'Bildirim eşiği (puan)',
124
+ em_cooldown: 'Konu sessizliği (dk)',
125
+ em_model: 'Tarama (filtre) modeli',
126
+ em_model_main: 'Ana model (seçili)',
127
+ em_model_sub: 'Seçmezsen tarama ana modelle yapılır. Anlamlandırma (mesaj yazımı) her zaman ana modelle.',
128
+ em_notify: 'Bildirim hedefi',
129
+ em_notify_auto: 'Otomatik — bağlı entegrasyonlar',
130
+ em_notify_wa: 'WhatsApp',
131
+ em_notify_tg: 'Telegram',
132
+ em_notify_dc: 'Discord',
133
+ em_notify_sub: 'Seçmezsen ekli ve bağlı entegrasyonların hepsine yazar; hiçbiri bağlı değilse masaüstü sohbete düşer.',
134
+ em_interests: 'İlgi alanların — haber filtresi buna göre ağırlıklandırılır',
135
+ em_interests_ph: 'örn: yapay zeka, yazılım, trading, open source',
136
+ em_news: 'Haber kaynağı (Google News)',
137
+ em_news_topics_ph: 'haber konuları, virgülle: yapay zeka, ekonomi…',
138
+ em_scan: 'Şimdi Tara',
139
+ em_scan_ok: 'Tarama: {raw} sinyal · {queued} bildirim · {stored} depo',
140
+ em_events: 'Son olaylar',
141
+ em_no_events: 'Henüz olay yok — Şimdi Tara ile deneyebilirsin.',
142
+ em_saved: 'Empati ayarları kaydedildi',
143
+ em_lastrun: 'Son tarama',
144
+ em_note: 'İzleyiciler (watchers) kendi bildirimlerini zaten yapıyor; Empati Loop onları tekrar bildirmez. Filtre modeli tek toplu çağrıyla çalışır; model yoksa puanlama deterministik yapılır.',
145
+ em_st_notified: 'bildirildi',
146
+ em_st_queued: 'kuyrukta',
147
+ em_st_stored: 'depo',
148
+ em_st_ignored: 'yok sayıldı',
149
+ em_lv_high: 'YÜKSEK',
150
+ em_lv_medium: 'ORTA',
151
+ em_interests_auto: 'Bunlara ek olarak sohbetlerinden öğrenilen ilgi alanları da otomatik devreye girer.',
152
+ em_scan_busy: 'Tarama hâlâ çalışıyor — birkaç saniye sonra tekrar dene.',
153
+ em_mem_h2: 'Empati Hafızası',
154
+ em_mem_sub: 'Konuşmalarınız burada birikir; sohbetlerinden ilgi alanların öğrenilir. Tarama ve bildirim mesajları bu hafızayla sana göre kişiselleşir.',
155
+ em_mem_learned: 'Sohbetlerden öğrenilen ilgi alanları',
156
+ em_mem_no_learned: 'Henüz öğrenilen ilgi yok — sohbet ettikçe burada birikir.',
157
+ em_mem_recent: 'Son konuşma kayıtları',
158
+ em_mem_no_recent: 'Henüz kayıt yok.',
159
+ em_mem_clear: 'Hafızayı Temizle',
160
+ em_mem_cleared: 'Empati hafızası temizlendi',
117
161
  tab_cron: 'Cron',
118
162
  tab_usage: 'Maliyet · Limit',
119
163
  tab_logs: 'Log',
@@ -153,7 +197,6 @@
153
197
  btn_close: 'Kapat',
154
198
  tip_win_min: 'Simge durumunda küçült',
155
199
  tip_win_max: 'Pencereyi büyüt/küçült',
156
- em_pass_masked: 'Mevcut şifre korunuyor — değiştirmek için yeniden gir',
157
200
  p_h2: 'Provider',
158
201
  p_sub: 'Beast config.yaml\u2019dan gelen modeller — aktif olanı seç',
159
202
  p_del_title: 'Modeli listeden sil',
@@ -223,11 +266,12 @@
223
266
  tts_chat_auto: 'Chat\'te ajanın yazdıklarını otomatik seslendir',
224
267
  tts_on: 'TTS açık — cevaplar sesli de gider',
225
268
  tts_off: 'TTS kapalı',
226
- em_h2: 'E-posta (Gmail)',
227
- em_sub: 'IMAP/SMTP — Gmail hesabında "Uygulama Şifresi" oluşturup buraya gir. Agent mailleri okur, özetler ve senin adına gönderir.',
228
- em_save: 'E-posta Kaydet',
229
- em_note: 'Kaydettikten sonra agent\u2019a "gelen mailleri özetle", "X\u2019e mail at" gibi komutlar verebilirsin.',
230
- em_saved: 'E-posta kaydedildi — agent artık maillere erişebilir',
269
+ mail_h2: 'E-posta (Gmail)',
270
+ mail_sub: 'IMAP/SMTP — Gmail hesabında "Uygulama Şifresi" oluşturup buraya gir. Agent mailleri okur, özetler ve senin adına gönderir.',
271
+ mail_save: 'E-posta Kaydet',
272
+ mail_note: 'Kaydettikten sonra agent\u2019a "gelen mailleri özetle", "X\u2019e mail at" gibi komutlar verebilirsin.',
273
+ mail_saved: 'E-posta kaydedildi — agent artık maillere erişebilir',
274
+ mail_pass_masked: 'Mevcut şifre korunuyor — değiştirmek için yeniden gir',
231
275
  it_h2: 'Entegrasyonlar',
232
276
  it_sub: 'Mesajlaşma köprüleri — gelen mesajlar Beast\u2019e gider, cevap geri döner',
233
277
  it_wa_sub: 'Özel mesajlar · gruplar (@mention ile) · slash komutları (/help)',
@@ -691,6 +735,50 @@
691
735
  up_install_now: 'Restart & Install',
692
736
  up_note: 'The app restarts itself after installing. You can also use the /update command from WhatsApp.',
693
737
  tab_events: 'Event Center',
738
+ tab_empati: 'Empathy Loop',
739
+ em_h2: 'Empathy Loop — Proactive Perception',
740
+ em_sub: 'Beast scans periodically in the background: half-done work, news flow. Pipeline: signal → cheap filter model → priority score → notification. Unimportant events are only stored, they never bother you.',
741
+ em_ipc_err: 'Could not reach the empathy service.',
742
+ em_on: 'Empathy Loop enabled',
743
+ em_interval: 'Scan interval (min)',
744
+ em_min_notify: 'Notify threshold (score)',
745
+ em_cooldown: 'Topic silence (min)',
746
+ em_model: 'Scan (filter) model',
747
+ em_model_main: 'Main model (selected)',
748
+ em_model_sub: 'If left empty, scanning uses the main model. Composing the message always uses the main model.',
749
+ em_notify: 'Notification target',
750
+ em_notify_auto: 'Auto — connected integrations',
751
+ em_notify_wa: 'WhatsApp',
752
+ em_notify_tg: 'Telegram',
753
+ em_notify_dc: 'Discord',
754
+ em_notify_sub: 'If left empty, it writes to all connected integrations; with none connected it lands in the desktop chat.',
755
+ em_interests: 'Your interests — news filtering is weighted by these',
756
+ em_interests_ph: 'e.g. AI, software, trading, open source',
757
+ em_news: 'News source (Google News)',
758
+ em_news_topics_ph: 'news topics, comma separated: AI, economy…',
759
+ em_scan: 'Scan Now',
760
+ em_scan_ok: 'Scan: {raw} signals · {queued} notify · {stored} stored',
761
+ em_events: 'Recent events',
762
+ em_no_events: 'No events yet — try Scan Now.',
763
+ em_saved: 'Empathy settings saved',
764
+ em_lastrun: 'Last scan',
765
+ em_note: 'Watchers already notify on their own; the Empathy Loop does not repeat them. The filter model runs in a single batched call; without a model, scoring is deterministic.',
766
+ em_st_notified: 'notified',
767
+ em_st_queued: 'queued',
768
+ em_st_stored: 'stored',
769
+ em_st_ignored: 'ignored',
770
+ em_lv_high: 'HIGH',
771
+ em_lv_medium: 'MEDIUM',
772
+ em_interests_auto: 'On top of these, interest areas learned from your chats kick in automatically.',
773
+ em_scan_busy: 'A scan is still running — try again in a few seconds.',
774
+ em_mem_h2: 'Empathy Memory',
775
+ em_mem_sub: 'Your conversations accumulate here; interest areas are learned from your chats. Scans and notification texts are personalized with this memory.',
776
+ em_mem_learned: 'Interest areas learned from chats',
777
+ em_mem_no_learned: 'No learned interests yet — they accumulate as you chat.',
778
+ em_mem_recent: 'Recent conversation records',
779
+ em_mem_no_recent: 'No records yet.',
780
+ em_mem_clear: 'Clear Memory',
781
+ em_mem_cleared: 'Empathy memory cleared',
694
782
  tab_cron: 'Cron',
695
783
  tab_usage: 'Cost · Limit',
696
784
  tab_logs: 'Logs',
@@ -730,7 +818,6 @@
730
818
  btn_close: 'Close',
731
819
  tip_win_min: 'Minimize',
732
820
  tip_win_max: 'Maximize/Restore',
733
- em_pass_masked: 'Current password kept — type a new one to change it',
734
821
  p_h2: 'Provider',
735
822
  p_sub: 'Models from Beast config.yaml — pick the active one',
736
823
  p_del_title: 'Remove model from list',
@@ -800,11 +887,12 @@
800
887
  tts_chat_auto: 'Auto-speak agent replies in chat',
801
888
  tts_on: 'TTS on — replies also go as voice',
802
889
  tts_off: 'TTS off',
803
- em_h2: 'E-mail (Gmail)',
804
- em_sub: 'IMAP/SMTP — create an "App Password" in your Gmail account and enter it here. The agent reads, summarizes and sends mail on your behalf.',
805
- em_save: 'Save E-mail',
806
- em_note: 'After saving you can give the agent commands like "summarize incoming mail", "send mail to X".',
807
- em_saved: 'E-mail saved — the agent can now access mail',
890
+ mail_h2: 'E-mail (Gmail)',
891
+ mail_sub: 'IMAP/SMTP — create an "App Password" in your Gmail account and enter it here. The agent reads, summarizes and sends mail on your behalf.',
892
+ mail_save: 'Save E-mail',
893
+ mail_note: 'After saving you can give the agent commands like "summarize incoming mail", "send mail to X".',
894
+ mail_saved: 'E-mail saved — the agent can now access mail',
895
+ mail_pass_masked: 'Current password kept — type a new one to change it',
808
896
  it_h2: 'Integrations',
809
897
  it_sub: 'Messaging bridges — incoming messages go to Beast, replies come back',
810
898
  it_wa_sub: 'Private messages · groups (@mention) · slash commands (/help)',
@@ -239,6 +239,7 @@
239
239
  <button class="tab" data-tab="websearch" data-i18n="tab_websearch">Web Arama</button>
240
240
  <button class="tab" data-tab="mcp" data-i18n="tab_mcp">MCP</button>
241
241
  <button class="tab" data-tab="events" data-i18n="tab_events">Olay Merkezi</button>
242
+ <button class="tab" data-tab="empati" data-i18n="tab_empati">Empati Loop</button>
242
243
  <button class="tab" data-tab="cron" data-i18n="tab_cron">Cron</button>
243
244
  <button class="tab" data-tab="usage" data-i18n="tab_usage">Maliyet · Limit</button>
244
245
  <button class="tab" data-tab="logs" data-i18n="tab_logs">Log</button>
@@ -264,6 +265,7 @@
264
265
  <div id="tab-websearch" class="pane" hidden></div>
265
266
  <div id="tab-mcp" class="pane" hidden></div>
266
267
  <div id="tab-events" class="pane" hidden></div>
268
+ <div id="tab-empati" class="pane" hidden></div>
267
269
  <div id="tab-usage" class="pane" hidden></div>
268
270
  <div id="tab-logs" class="pane" hidden></div>
269
271
  <div id="tab-dash" class="pane" hidden></div>