beast-agent 2.3.3 → 2.4.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/mem0.js +6 -1
- package/src/agent/perception.js +447 -0
- package/src/agent/progressbus.js +41 -0
- package/src/agent/tools.js +10 -3
- package/src/agent/whatsapp.js +97 -2
- package/src/main.js +287 -6
- package/src/preload.js +4 -0
- package/src/renderer/i18n.js +68 -0
- package/src/renderer/index.html +2 -0
- package/src/renderer/renderer.js +176 -1
package/src/renderer/renderer.js
CHANGED
|
@@ -1066,6 +1066,7 @@ async function renderActiveSettingsTab() {
|
|
|
1066
1066
|
case 'websearch': await renderWebSearchPane(); break;
|
|
1067
1067
|
case 'mcp': await renderMcpPane(); break;
|
|
1068
1068
|
case 'events': await renderEventsPane(); break;
|
|
1069
|
+
case 'empati': await renderEmpatiPane(); break;
|
|
1069
1070
|
case 'cron': await openCron(); break;
|
|
1070
1071
|
case 'usage': await renderUsagePane(); break;
|
|
1071
1072
|
case 'agents': await refreshAgentsPane(); break;
|
|
@@ -1151,7 +1152,7 @@ function switchTab(name) {
|
|
|
1151
1152
|
document.querySelectorAll('#setTabs .tab').forEach((b) =>
|
|
1152
1153
|
b.classList.toggle('active', b.dataset.tab === name)
|
|
1153
1154
|
);
|
|
1154
|
-
|
|
1155
|
+
for (const p of ['lang', 'provider', 'fallout', 'skills', 'agents', 'tts', 'install', 'email', 'integrations', 'websearch', 'mcp', 'events', 'empati', 'cron', 'usage', 'logs', 'dash', 'sec', 'update']) {
|
|
1155
1156
|
const el = $('#tab-' + p);
|
|
1156
1157
|
if (el) el.hidden = p !== name; // guard: eksik pane tüm sekmeleri kilitlemesin
|
|
1157
1158
|
}
|
|
@@ -1160,6 +1161,7 @@ function switchTab(name) {
|
|
|
1160
1161
|
if (name === 'usage') renderUsagePane();
|
|
1161
1162
|
if (name === 'install') renderInstallPane();
|
|
1162
1163
|
if (name === 'events') renderEventsPane();
|
|
1164
|
+
if (name === 'empati') renderEmpatiPane();
|
|
1163
1165
|
if (name === 'logs') renderLogPane();
|
|
1164
1166
|
if (name === 'dash') renderDashboardPane();
|
|
1165
1167
|
if (name === 'sec') renderSecurityPane();
|
|
@@ -2146,13 +2148,26 @@ async function renderInstallPane() {
|
|
|
2146
2148
|
if (!el) return;
|
|
2147
2149
|
if (!rows || !rows.length) { el.innerHTML = '<div class="sub">Durum alınamadı</div>'; return; }
|
|
2148
2150
|
autoStart(rows);
|
|
2151
|
+
const hasPct = (r) => typeof r.pct === 'number' && ['missing', 'partial', 'loading'].includes(r.state);
|
|
2152
|
+
const pctLabel = (r) => {
|
|
2153
|
+
if (!hasPct(r)) return '<span id="inst-pct-' + r.id + '" style="display:none"></span>';
|
|
2154
|
+
const mb = (r.loadedMb && r.totalMb) ? ' · ' + r.loadedMb + '/' + r.totalMb + ' MB' : '';
|
|
2155
|
+
return '<span id="inst-pct-' + r.id + '" style="color:#d9a441;font-weight:700;font-size:11px;flex:none">%' + Math.round(r.pct) + mb + '</span>';
|
|
2156
|
+
};
|
|
2157
|
+
const bar = (r) => {
|
|
2158
|
+
if (!hasPct(r)) return '<div id="inst-bar-' + r.id + '" style="display:none"></div>';
|
|
2159
|
+
return '<div id="inst-bar-' + r.id + '" style="margin-top:7px;height:6px;border-radius:3px;background:var(--border);overflow:hidden">' +
|
|
2160
|
+
'<div id="inst-fill-' + r.id + '" style="height:100%;width:' + Math.max(2, Math.round(r.pct)) + '%;background:#d9a441;border-radius:3px;transition:width .4s ease"></div></div>';
|
|
2161
|
+
};
|
|
2149
2162
|
el.innerHTML = rows.map((r) => (
|
|
2150
2163
|
'<div style="display:flex;align-items:center;gap:10px;padding:9px 0;border-bottom:1px solid var(--border)">' +
|
|
2151
2164
|
'<div style="flex:1;min-width:0">' +
|
|
2152
2165
|
'<div style="font-size:13px">' + escapeHtml(r.name) + '</div>' +
|
|
2153
2166
|
'<div class="sub" style="font-size:11px">' + escapeHtml(r.detail || '') + (r.mb ? ' · ' + r.mb + ' MB' : '') + '</div>' +
|
|
2167
|
+
bar(r) +
|
|
2154
2168
|
'</div>' +
|
|
2155
2169
|
badge(r.state) +
|
|
2170
|
+
pctLabel(r) +
|
|
2156
2171
|
'</div>'
|
|
2157
2172
|
)).join('');
|
|
2158
2173
|
};
|
|
@@ -2168,6 +2183,26 @@ async function renderInstallPane() {
|
|
|
2168
2183
|
refreshTimer = setInterval(refresh, 4000);
|
|
2169
2184
|
}
|
|
2170
2185
|
|
|
2186
|
+
/* Kurulum progress event'i: sekme açıksa bar'ı anında güncelle (4 sn polling beklemeden).
|
|
2187
|
+
Sekme kapalıysa yok say — açılınca install:status zaten kayıtlı yüzeyi getirir. */
|
|
2188
|
+
function updateInstallPct(ev) {
|
|
2189
|
+
try {
|
|
2190
|
+
if (!ev || !ev.id) return;
|
|
2191
|
+
const pane = document.getElementById('tab-install');
|
|
2192
|
+
if (!pane || pane.hidden) return;
|
|
2193
|
+
const bar = document.getElementById('inst-bar-' + ev.id);
|
|
2194
|
+
const fill = document.getElementById('inst-fill-' + ev.id);
|
|
2195
|
+
const label = document.getElementById('inst-pct-' + ev.id);
|
|
2196
|
+
if (!bar || !fill || !label) return;
|
|
2197
|
+
const pct = Math.max(0, Math.min(100, Math.round(ev.pct || 0)));
|
|
2198
|
+
const mb = (ev.loaded && ev.total) ? ' · ' + Math.round(ev.loaded / 1048576) + '/' + Math.round(ev.total / 1048576) + ' MB' : '';
|
|
2199
|
+
bar.style.display = '';
|
|
2200
|
+
fill.style.width = Math.max(2, pct) + '%';
|
|
2201
|
+
label.style.display = '';
|
|
2202
|
+
label.textContent = '%' + pct + mb;
|
|
2203
|
+
} catch {}
|
|
2204
|
+
}
|
|
2205
|
+
|
|
2171
2206
|
async function renderTtsPane() { const pane = $('#tab-tts');
|
|
2172
2207
|
if (!pane) return;
|
|
2173
2208
|
/* STT DURUMU: model indirildi mi / iniyor mu / hangi motor */
|
|
@@ -2989,6 +3024,136 @@ async function renderEventsPane() {
|
|
|
2989
3024
|
});
|
|
2990
3025
|
}
|
|
2991
3026
|
|
|
3027
|
+
/* ---------------- EMPATİ LOOP (proaktif algı sekmesi) ---------------- */
|
|
3028
|
+
async function renderEmpatiPane() {
|
|
3029
|
+
const pane = $('#tab-empati');
|
|
3030
|
+
if (!pane) return;
|
|
3031
|
+
const cfg = await beast.empatiGet().catch(() => null);
|
|
3032
|
+
let events = [];
|
|
3033
|
+
try { events = await beast.empatiEvents(); } catch {}
|
|
3034
|
+
let models = [];
|
|
3035
|
+
try { models = (await beast.getState()).models || []; } catch {}
|
|
3036
|
+
if (!cfg) {
|
|
3037
|
+
pane.innerHTML = '<h2>' + _t('em_h2') + '</h2><div class="sub">' + _t('em_ipc_err') + '</div>';
|
|
3038
|
+
return;
|
|
3039
|
+
}
|
|
3040
|
+
const modelOpts =
|
|
3041
|
+
'<option value="">' + _t('em_model_main') + '</option>' +
|
|
3042
|
+
models.map((m) =>
|
|
3043
|
+
'<option value="' + escapeHtml(m.sel || '') + '"' + (cfg.filterModel === m.sel ? ' selected' : '') + '>' +
|
|
3044
|
+
escapeHtml((m.providerName || '') + ' · ' + (m.model || '')) + '</option>'
|
|
3045
|
+
).join('');
|
|
3046
|
+
const targetOpts = [
|
|
3047
|
+
['whatsapp', _t('em_notify_wa')],
|
|
3048
|
+
['telegram', _t('em_notify_tg')],
|
|
3049
|
+
['discord', _t('em_notify_dc')],
|
|
3050
|
+
].map(([v, lbl]) =>
|
|
3051
|
+
'<option value="' + v + '"' + (cfg.notifyTarget === v ? ' selected' : '') + '>' + escapeHtml(lbl) + '</option>'
|
|
3052
|
+
).join('');
|
|
3053
|
+
const when = (iso) => {
|
|
3054
|
+
try {
|
|
3055
|
+
return new Date(iso).toLocaleString('tr-TR', { day: '2-digit', month: '2-digit', hour: '2-digit', minute: '2-digit' });
|
|
3056
|
+
} catch { return String(iso || ''); }
|
|
3057
|
+
};
|
|
3058
|
+
const statusT = { notified: _t('em_st_notified'), queued: _t('em_st_queued'), stored: _t('em_st_stored'), ignored: _t('em_st_ignored') };
|
|
3059
|
+
const lvBadge = (e) => {
|
|
3060
|
+
if (!e.level) return '';
|
|
3061
|
+
const color = e.level === 'high' ? '#e06c75' : '#d9a441';
|
|
3062
|
+
return ' · <b style="color:' + color + '">' + (e.level === 'high' ? _t('em_lv_high') : _t('em_lv_medium')) + '</b>';
|
|
3063
|
+
};
|
|
3064
|
+
let rows = '';
|
|
3065
|
+
for (const e of events) {
|
|
3066
|
+
rows +=
|
|
3067
|
+
'<div class="usage-row" style="align-items:flex-start">' +
|
|
3068
|
+
'<div style="min-width:0;flex:1">' +
|
|
3069
|
+
'<div style="font-size:12px">' + escapeHtml(e.title || '') + '</div>' +
|
|
3070
|
+
'<div class="ur-meta">' + escapeHtml(e.source || '') + ' · ' + when(e.ts) + ' · %' + (e.priority || 0) +
|
|
3071
|
+
(e.reason ? ' · ' + escapeHtml(e.reason) : '') + '</div>' +
|
|
3072
|
+
(e.text ? '<div class="sub" style="font-size:11px">' + escapeHtml(e.text) + '</div>' : '') +
|
|
3073
|
+
'</div>' +
|
|
3074
|
+
'<span style="flex:none;font-size:11px;color:var(--muted)">' + (statusT[e.status] || e.status) + lvBadge(e) + '</span>' +
|
|
3075
|
+
'</div>';
|
|
3076
|
+
}
|
|
3077
|
+
|
|
3078
|
+
pane.innerHTML =
|
|
3079
|
+
'<h2>' + _t('em_h2') + '</h2>' +
|
|
3080
|
+
'<div class="sub">' + _t('em_sub') + '</div>' +
|
|
3081
|
+
(cfg.lastRunAt ? '<div class="sub">' + _t('em_lastrun') + ': ' + when(cfg.lastRunAt) + (cfg.running ? ' · ⏳' : '') + '</div>' : '') +
|
|
3082
|
+
`<div class="fo-toggles" style="margin-top:10px">
|
|
3083
|
+
<label class="lock-row"><input type="checkbox" id="emOn" ${cfg.enabled ? 'checked' : ''}/><span>${_t('em_on')}</span></label>
|
|
3084
|
+
</div>
|
|
3085
|
+
<div id="emDetail" style="${cfg.enabled ? '' : 'opacity:.5'}">
|
|
3086
|
+
<div class="form-grid" style="grid-template-columns:1fr 1fr 1fr;margin-top:8px">
|
|
3087
|
+
<div><label class="sub">${_t('em_interval')}</label><input id="emInterval" class="inp" type="number" min="3" max="1440" value="${cfg.intervalMin}"/></div>
|
|
3088
|
+
<div><label class="sub">${_t('em_min_notify')}</label><input id="emMin" class="inp" type="number" min="0" max="100" value="${cfg.minNotifyPriority}"/></div>
|
|
3089
|
+
<div><label class="sub">${_t('em_cooldown')}</label><input id="emCd" class="inp" type="number" min="0" max="10080" value="${cfg.cooldownMin}"/></div>
|
|
3090
|
+
</div>
|
|
3091
|
+
<div style="margin-top:8px">
|
|
3092
|
+
<label class="sub">${_t('em_model')}</label>
|
|
3093
|
+
<select id="emModel" class="inp">${modelOpts}</select>
|
|
3094
|
+
<div class="sub">${_t('em_model_sub')}</div>
|
|
3095
|
+
</div>
|
|
3096
|
+
<div style="margin-top:8px">
|
|
3097
|
+
<label class="sub">${_t('em_notify')}</label>
|
|
3098
|
+
<select id="emTarget" class="inp"><option value="">${_t('em_notify_auto')}</option>${targetOpts}</select>
|
|
3099
|
+
<div class="sub">${_t('em_notify_sub')}</div>
|
|
3100
|
+
</div>
|
|
3101
|
+
<div style="margin-top:8px">
|
|
3102
|
+
<label class="sub">${_t('em_interests')}</label>
|
|
3103
|
+
<textarea id="emInterests" class="inp" rows="2" placeholder="${_t('em_interests_ph')}">${escapeHtml(cfg.interests || '')}</textarea>
|
|
3104
|
+
</div>
|
|
3105
|
+
<label class="lock-row" style="margin-top:8px"><input type="checkbox" id="emNews" ${cfg.newsTopics ? 'checked' : ''}/><span>${_t('em_news')}</span></label>
|
|
3106
|
+
<input id="emTopics" class="inp" style="${cfg.newsTopics ? '' : 'opacity:.5'}" placeholder="${_t('em_news_topics_ph')}" value="${escapeHtml(cfg.newsTopics || '')}" spellcheck="false"/>
|
|
3107
|
+
<div style="display:flex;gap:8px;margin-top:10px;align-items:center">
|
|
3108
|
+
<button id="emSave" class="btn">${_t('mcp_save')}</button>
|
|
3109
|
+
<button id="emScan" class="btn ghost">${_t('em_scan')}</button>
|
|
3110
|
+
<span id="emMsg" class="sub" style="margin:0"></span>
|
|
3111
|
+
</div>
|
|
3112
|
+
<div class="sub" style="margin-top:6px">${_t('em_note')}</div>
|
|
3113
|
+
</div>
|
|
3114
|
+
<h3 style="margin-top:16px;color:var(--muted)">${_t('em_events')}</h3>`;
|
|
3115
|
+
const wrap = document.createElement('div');
|
|
3116
|
+
if (!rows) wrap.innerHTML = '<p class="sub">' + _t('em_no_events') + '</p>';
|
|
3117
|
+
else wrap.innerHTML = rows;
|
|
3118
|
+
pane.appendChild(wrap);
|
|
3119
|
+
|
|
3120
|
+
const emOn = $('#emOn');
|
|
3121
|
+
const emDetail = $('#emDetail');
|
|
3122
|
+
const emNews = $('#emNews');
|
|
3123
|
+
const emTopics = $('#emTopics');
|
|
3124
|
+
emOn.addEventListener('change', () => { emDetail.style.opacity = emOn.checked ? '' : '.5'; });
|
|
3125
|
+
emNews.addEventListener('change', () => { emTopics.style.opacity = emNews.checked ? '' : '.5'; });
|
|
3126
|
+
$('#emSave').addEventListener('click', async () => {
|
|
3127
|
+
const patch = {
|
|
3128
|
+
enabled: emOn.checked,
|
|
3129
|
+
intervalMin: Number($('#emInterval').value) || cfg.intervalMin,
|
|
3130
|
+
minNotifyPriority: Number($('#emMin').value),
|
|
3131
|
+
cooldownMin: Number($('#emCd').value),
|
|
3132
|
+
notifyTarget: $('#emTarget') ? $('#emTarget').value : '',
|
|
3133
|
+
filterModel: $('#emModel') ? $('#emModel').value : '',
|
|
3134
|
+
interests: $('#emInterests').value.trim(),
|
|
3135
|
+
newsTopics: emNews.checked ? emTopics.value.trim() : '',
|
|
3136
|
+
};
|
|
3137
|
+
const r = await beast.empatiSet(patch).catch(() => null);
|
|
3138
|
+
toast(r ? _t('em_saved') : 'Hata');
|
|
3139
|
+
if (r) renderEmpatiPane();
|
|
3140
|
+
});
|
|
3141
|
+
$('#emScan').addEventListener('click', async () => {
|
|
3142
|
+
const msg = $('#emMsg');
|
|
3143
|
+
msg.textContent = '⏳';
|
|
3144
|
+
const r = await beast.empatiScan().catch(() => null);
|
|
3145
|
+
if (r && r.ok) {
|
|
3146
|
+
msg.textContent = _t('em_scan_ok')
|
|
3147
|
+
.replace('{raw}', String(r.raw || 0))
|
|
3148
|
+
.replace('{queued}', String(r.queued || 0))
|
|
3149
|
+
.replace('{stored}', String(r.stored || 0));
|
|
3150
|
+
renderEmpatiPane();
|
|
3151
|
+
} else {
|
|
3152
|
+
msg.textContent = (r && r.error) || 'hata';
|
|
3153
|
+
}
|
|
3154
|
+
});
|
|
3155
|
+
}
|
|
3156
|
+
|
|
2992
3157
|
async function renderWaAllow() {
|
|
2993
3158
|
const wrap = $('#waAllowChips');
|
|
2994
3159
|
if (!wrap) return;
|
|
@@ -4672,6 +4837,16 @@ function onEvent(ev) {
|
|
|
4672
4837
|
showApprovalCard(ev);
|
|
4673
4838
|
return;
|
|
4674
4839
|
}
|
|
4840
|
+
if (ev.type === 'install-progress') { updateInstallPct(ev); return; }
|
|
4841
|
+
/* EMPATİ LOOP: proaktif bildirim (masaüstü) + sekme canlı yenileme */
|
|
4842
|
+
if (ev.type === 'proactive') {
|
|
4843
|
+
toast('🫡 ' + (ev.text || ev.title || ''));
|
|
4844
|
+
return;
|
|
4845
|
+
}
|
|
4846
|
+
if (ev.type === 'empati') {
|
|
4847
|
+
if (!els.settingsOverlay.hidden && setTab === 'empati') renderEmpatiPane();
|
|
4848
|
+
return;
|
|
4849
|
+
}
|
|
4675
4850
|
if (ev.type === 'update') {
|
|
4676
4851
|
if (ev.downloaded) toast(_t('up_downloaded') + ' (v' + (ev.version || '?') + ') — /update now');
|
|
4677
4852
|
else if (ev.available && ev.version && ev.version !== ev.current) toast(_t('up_available') + ' (v' + ev.version + ')');
|