beast-agent 2.16.0 → 2.17.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 +88 -2
- package/src/agent/supermemory.js +132 -0
- package/src/main.js +42 -0
- package/src/preload.js +3 -0
package/package.json
CHANGED
package/src/agent/engine.js
CHANGED
|
@@ -17,6 +17,7 @@ const research = require('./research');
|
|
|
17
17
|
const agentdefs = require('./agentdefs');
|
|
18
18
|
const memory = require('./memory');
|
|
19
19
|
const mem0 = require('./mem0');
|
|
20
|
+
const supermemory = require('./supermemory');
|
|
20
21
|
const nightref = require('./nightref');
|
|
21
22
|
const skills = require('./skills');
|
|
22
23
|
const mcp = require('./mcp');
|
|
@@ -275,6 +276,14 @@ class Engine {
|
|
|
275
276
|
/* mem0-native hafıza katmanı: semantik arama + LLM konsolidasyonu (bot başına izole store).
|
|
276
277
|
Ayarlardan kapatılabilir (mem0:false) — kapalıysa klasik keyword hafızası çalışır. */
|
|
277
278
|
this.mem0Enabled = opts.mem0 !== false;
|
|
279
|
+
/* Supermemory (lokal) bellek katmanı — DEFAULT AÇIK: sunucu ayaktaysa
|
|
280
|
+
(npx supermemory local → localhost:6767) hibrit arama + kullanıcı profili
|
|
281
|
+
öncelikli gelir; ayakta değilse klasik hafıza sorunsuz devralır.
|
|
282
|
+
Sağlık önbelleği: probe 60 sn'de bir tazelenir (spam probe yok). */
|
|
283
|
+
this.supermemory = opts.supermemory || null; // { enabled, baseUrl, apiKey, containerTag }
|
|
284
|
+
this._smUp = null; // null = henüz bilinmiyor
|
|
285
|
+
this._smCheckedAt = 0;
|
|
286
|
+
this._smWarned = false; // erişilemez iletisi bir kez basılır
|
|
278
287
|
/* ANA KOD KİLİDİ: agent kendi kaynak koduna dokunamaz (yazma/silme yok, okuma serbest) */
|
|
279
288
|
this.protectedDirs = (opts.protectedDirs || [])
|
|
280
289
|
.map((d) => String(d).replace(/[\\/]+$/, '').toLowerCase().replace(/\//g, '\\'))
|
|
@@ -1588,6 +1597,74 @@ class Engine {
|
|
|
1588
1597
|
}
|
|
1589
1598
|
}
|
|
1590
1599
|
|
|
1600
|
+
/* ---------- Supermemory (lokal) bellek köprüsü ---------- */
|
|
1601
|
+
|
|
1602
|
+
_smConfig() {
|
|
1603
|
+
const sm = this.supermemory;
|
|
1604
|
+
if (!sm || sm.enabled === false || !sm.baseUrl) return null;
|
|
1605
|
+
return sm;
|
|
1606
|
+
}
|
|
1607
|
+
|
|
1608
|
+
/* Ayaktayken true — 60 sn cooldown'lu probe (aynı tura 10 kez probe vurmaz) */
|
|
1609
|
+
async _smReady() {
|
|
1610
|
+
const sm = this._smConfig();
|
|
1611
|
+
if (!sm) return false;
|
|
1612
|
+
const now = Date.now();
|
|
1613
|
+
if (this._smUp === true && now - this._smCheckedAt < supermemory.HEALTH_COOLDOWN_MS) return true;
|
|
1614
|
+
if (this._smUp === false && now - this._smCheckedAt < supermemory.HEALTH_COOLDOWN_MS) return false;
|
|
1615
|
+
this._smUp = await supermemory.probe(sm.baseUrl, sm.apiKey);
|
|
1616
|
+
this._smCheckedAt = now;
|
|
1617
|
+
if (!this._smUp && !this._smWarned) {
|
|
1618
|
+
this._smWarned = true;
|
|
1619
|
+
emitSafe(this, null, {
|
|
1620
|
+
type: 'status',
|
|
1621
|
+
status: '🧠 supermemory erişilemedi — klasik hafıza kullanılıyor (açmak için: npx supermemory local)',
|
|
1622
|
+
});
|
|
1623
|
+
}
|
|
1624
|
+
return this._smUp;
|
|
1625
|
+
}
|
|
1626
|
+
|
|
1627
|
+
/* Container tag: bot oturumları kendi izole havuzuna yazar (mem0 deseni) */
|
|
1628
|
+
_smContainer(sessionId) {
|
|
1629
|
+
const sm = this._smConfig();
|
|
1630
|
+
const bctx = this._sessionBotCtx(sessionId ? this.cache.get(String(sessionId)) : null);
|
|
1631
|
+
return (bctx && bctx.id ? 'bot:' + bctx.id : '') || (sm && sm.containerTag) || 'beast';
|
|
1632
|
+
}
|
|
1633
|
+
|
|
1634
|
+
/* YAZ: yerel hafıza HER ZAMEN yazılır (risksiz yedek); supermemory ASENKRON
|
|
1635
|
+
push edilir — turu bloklamaz, hata yutulur (mem0 deseninin aynısı) */
|
|
1636
|
+
_smPush(sessionId, text) {
|
|
1637
|
+
const sm = this._smConfig();
|
|
1638
|
+
if (!sm) return;
|
|
1639
|
+
supermemory
|
|
1640
|
+
.add(sm.baseUrl, sm.apiKey, { content: text, containerTag: this._smContainer(sessionId), metadata: { type: 'conversation' } })
|
|
1641
|
+
.catch(() => {});
|
|
1642
|
+
}
|
|
1643
|
+
|
|
1644
|
+
/* ARA: supermemory hibrit arama + profil → yerel sonuçlarla BİRLEŞTİR.
|
|
1645
|
+
Sunucu yoksa/hata yerse eski akış aynen çalışır (fallback). */
|
|
1646
|
+
async _smSearch(sessionId, q, limit) {
|
|
1647
|
+
const sm = this._smConfig();
|
|
1648
|
+
if (!sm || !(await this._smReady())) return null;
|
|
1649
|
+
const container = this._smContainer(sessionId);
|
|
1650
|
+
try {
|
|
1651
|
+
const [hits, prof] = await Promise.all([
|
|
1652
|
+
supermemory.search(sm.baseUrl, sm.apiKey, { q, containerTag: container, limit, mode: 'hybrid' }),
|
|
1653
|
+
supermemory.profile(sm.baseUrl, sm.apiKey, { containerTag: container }).catch(() => null),
|
|
1654
|
+
]);
|
|
1655
|
+
const out = {
|
|
1656
|
+
engine: 'supermemory',
|
|
1657
|
+
results: hits.map((h) => ({ text: h.text, score: h.similarity, source: 'supermemory' })),
|
|
1658
|
+
};
|
|
1659
|
+
if (prof && (prof.static.length || prof.dynamic.length)) out.profile = prof;
|
|
1660
|
+
return out;
|
|
1661
|
+
} catch {
|
|
1662
|
+
this._smUp = false;
|
|
1663
|
+
this._smCheckedAt = Date.now();
|
|
1664
|
+
return null;
|
|
1665
|
+
}
|
|
1666
|
+
}
|
|
1667
|
+
|
|
1591
1668
|
/* opencode request.ts prepare — system birleşimi (birebir sıra) */
|
|
1592
1669
|
buildOcSystem(session, agentInfo) {
|
|
1593
1670
|
const sid = String(session && session.id);
|
|
@@ -4682,6 +4759,9 @@ const skills = require('./skills');
|
|
|
4682
4759
|
return JSON.stringify(await mcp.call(name, args, signal));
|
|
4683
4760
|
}
|
|
4684
4761
|
if (name === 'memory_write') {
|
|
4762
|
+
/* Supermemory (lokal) DEFAULT: her yazım asenkron push edilir —
|
|
4763
|
+
sunucu ayaktaysa graf motoru özet/çelişki/unutma işlerini yürütür */
|
|
4764
|
+
this._smPush(sessionId, args.text);
|
|
4685
4765
|
/* bot oturumu → botun KENDİ hafıza store'una yaz (global Beast hafızasına değil).
|
|
4686
4766
|
mem0 açıkken: hash+semantic dedup'lı store'a gider, MEMORY.md aynası güncellenir. */
|
|
4687
4767
|
const bctx = this._sessionBotCtx(sessionId ? this.cache.get(String(sessionId)) : null);
|
|
@@ -4690,7 +4770,7 @@ const skills = require('./skills');
|
|
|
4690
4770
|
const r = await mem0.add('bot:' + bctx.id, [args.text]).catch(() => null);
|
|
4691
4771
|
if (r && r.ok) {
|
|
4692
4772
|
mem0.syncMirror('bot:' + bctx.id);
|
|
4693
|
-
return JSON.stringify({ ok: true, duplicate: r.skipped > 0, event: r.events[0] && r.events[0].event });
|
|
4773
|
+
return JSON.stringify({ ok: true, duplicate: r.skipped > 0, event: r.events[0] && r.events[0].event, supermemory: !!this._smConfig() });
|
|
4694
4774
|
}
|
|
4695
4775
|
}
|
|
4696
4776
|
return JSON.stringify(this.botMemory.append(bctx.id, args.text));
|
|
@@ -4699,7 +4779,7 @@ const skills = require('./skills');
|
|
|
4699
4779
|
const r = await mem0.add('main', [args.text]).catch(() => null);
|
|
4700
4780
|
if (r && r.ok) {
|
|
4701
4781
|
mem0.syncMirror('main');
|
|
4702
|
-
return JSON.stringify({ ok: true, duplicate: r.skipped > 0, event: r.events[0] && r.events[0].event });
|
|
4782
|
+
return JSON.stringify({ ok: true, duplicate: r.skipped > 0, event: r.events[0] && r.events[0].event, supermemory: !!this._smConfig() });
|
|
4703
4783
|
}
|
|
4704
4784
|
}
|
|
4705
4785
|
return JSON.stringify(memory.append(args.text));
|
|
@@ -4717,6 +4797,12 @@ const skills = require('./skills');
|
|
|
4717
4797
|
const bctx = this._sessionBotCtx(sessionId ? this.cache.get(String(sessionId)) : null);
|
|
4718
4798
|
const q = String(args.query || '');
|
|
4719
4799
|
const limit = clamp(Number(args.limit) || 5, 1, 15);
|
|
4800
|
+
/* Supermemory DEFAULT öncelik: hibrit arama + kullanıcı profili.
|
|
4801
|
+
Erişilemediyse/hata yerse yerel yollar aynen çalışır (fallback). */
|
|
4802
|
+
const smRes = await this._smSearch(sessionId, q, limit);
|
|
4803
|
+
if (smRes && smRes.results.length) {
|
|
4804
|
+
return JSON.stringify({ ok: true, query: q, ...smRes });
|
|
4805
|
+
}
|
|
4720
4806
|
if (bctx && this.botMemory) {
|
|
4721
4807
|
const rows = this.mem0Enabled
|
|
4722
4808
|
? await mem0.search('bot:' + bctx.id, q, { limit }).catch(() => [])
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/* ---------- Supermemory (lokal) adaptörü ----------
|
|
4
|
+
Beast'in bellek katmanına supermemory (git.new/memory) köprüsü — mem0.js
|
|
5
|
+
deseniyle TAKILABİLİR katman: sunucu (npx supermemory local → localhost:6767)
|
|
6
|
+
ayaktayken daha akıllı bellek (graf motoru, otomatik unutma, çelişki
|
|
7
|
+
çözümü, kullanıcı profili); ayakta değilken engine mevcut hafızaya sorunsuz
|
|
8
|
+
düşer. Zero npm bağımlılık — Node 18+ global fetch.
|
|
9
|
+
|
|
10
|
+
Uçlar (supermemory docs birebir):
|
|
11
|
+
POST /v3/documents { content, containerTag, customId?, metadata? }
|
|
12
|
+
POST /v4/search { q, containerTag, searchMode, limit, include? }
|
|
13
|
+
POST /v4/profile { containerTag, q? }
|
|
14
|
+
Auth: Authorization: Bearer <apiKey> (local key ilk boot'ta basılır) */
|
|
15
|
+
|
|
16
|
+
const BASE_TIMEOUT_MS = 8000;
|
|
17
|
+
const PROBE_TIMEOUT_MS = 2500;
|
|
18
|
+
const HEALTH_COOLDOWN_MS = 60000; // kapalıya aynı dakikada 200 kez vurma
|
|
19
|
+
|
|
20
|
+
function normalizeBase(url) {
|
|
21
|
+
return String(url || '').trim().replace(/\/+$/, '');
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async function call(baseUrl, apiKey, path, body, timeoutMs) {
|
|
25
|
+
const base = normalizeBase(baseUrl);
|
|
26
|
+
if (!base) throw new Error('supermemory baseUrl boş');
|
|
27
|
+
const ctrl = new AbortController();
|
|
28
|
+
const timer = setTimeout(() => ctrl.abort(), timeoutMs || BASE_TIMEOUT_MS);
|
|
29
|
+
try {
|
|
30
|
+
const res = await fetch(base + path, {
|
|
31
|
+
method: 'POST',
|
|
32
|
+
headers: {
|
|
33
|
+
'content-type': 'application/json',
|
|
34
|
+
...(apiKey ? { authorization: 'Bearer ' + apiKey } : {}),
|
|
35
|
+
},
|
|
36
|
+
body: JSON.stringify(body || {}),
|
|
37
|
+
signal: ctrl.signal,
|
|
38
|
+
});
|
|
39
|
+
if (!res.ok) {
|
|
40
|
+
const txt = await res.text().catch(() => '');
|
|
41
|
+
throw new Error('HTTP ' + res.status + (txt ? ': ' + txt.slice(0, 180) : ''));
|
|
42
|
+
}
|
|
43
|
+
return await res.json();
|
|
44
|
+
} finally {
|
|
45
|
+
clearTimeout(timer);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/* Sunucu ayakta mı? GET / ile ucuz sağlık kontrolü */
|
|
50
|
+
async function probe(baseUrl, apiKey) {
|
|
51
|
+
const base = normalizeBase(baseUrl);
|
|
52
|
+
if (!base) return false;
|
|
53
|
+
const ctrl = new AbortController();
|
|
54
|
+
const timer = setTimeout(() => ctrl.abort(), PROBE_TIMEOUT_MS);
|
|
55
|
+
try {
|
|
56
|
+
const res = await fetch(base, {
|
|
57
|
+
method: 'GET',
|
|
58
|
+
headers: apiKey ? { authorization: 'Bearer ' + apiKey } : {},
|
|
59
|
+
signal: ctrl.signal,
|
|
60
|
+
});
|
|
61
|
+
return res.status < 500;
|
|
62
|
+
} catch {
|
|
63
|
+
return false;
|
|
64
|
+
} finally {
|
|
65
|
+
clearTimeout(timer);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/* Konuşma/belgi yut — arka planda çağrılır (fire-and-forget desenine uygun) */
|
|
70
|
+
async function add(baseUrl, apiKey, { content, containerTag, customId, metadata }) {
|
|
71
|
+
return call(baseUrl, apiKey, '/v3/documents', {
|
|
72
|
+
content: String(content || ''),
|
|
73
|
+
containerTag: String(containerTag || 'beast'),
|
|
74
|
+
...(customId ? { customId: String(customId) } : {}),
|
|
75
|
+
...(metadata && typeof metadata === 'object' ? { metadata } : {}),
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/* Hibrit arama → normalize: [{text, similarity}] — memories varsayılan;
|
|
80
|
+
'hybrid' RAG + bellek tek sorguda */
|
|
81
|
+
async function search(baseUrl, apiKey, { q, containerTag, limit, mode }) {
|
|
82
|
+
const r = await call(
|
|
83
|
+
baseUrl,
|
|
84
|
+
apiKey,
|
|
85
|
+
'/v4/search',
|
|
86
|
+
{
|
|
87
|
+
q: String(q || ''),
|
|
88
|
+
containerTag: String(containerTag || 'beast'),
|
|
89
|
+
searchMode: mode === 'documents' || mode === 'hybrid' ? mode : 'memories',
|
|
90
|
+
limit: Math.min(20, Math.max(1, Number(limit) || 5)),
|
|
91
|
+
},
|
|
92
|
+
12000
|
|
93
|
+
);
|
|
94
|
+
const out = [];
|
|
95
|
+
for (const hit of (r && Array.isArray(r.results) ? r.results : []).slice(0, 10)) {
|
|
96
|
+
if (hit && typeof hit.memory === 'string' && hit.memory.trim()) {
|
|
97
|
+
out.push({ text: hit.memory.trim().slice(0, 600), similarity: Number(hit.similarity) || 0 });
|
|
98
|
+
}
|
|
99
|
+
/* hybrid mod: chunk'lar da gelir */
|
|
100
|
+
for (const c of (hit && Array.isArray(hit.chunks) ? hit.chunks : []).slice(0, 3)) {
|
|
101
|
+
const t = c && (c.content || c.text);
|
|
102
|
+
if (typeof t === 'string' && t.trim()) {
|
|
103
|
+
out.push({ text: t.trim().slice(0, 600), similarity: Number(c && c.similarity) || 0 });
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return out.slice(0, Math.max(1, Number(limit) || 5));
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/* Kullanıcı profili: { static: [], dynamic: [] } — her turda ucuz bağlam */
|
|
111
|
+
async function profile(baseUrl, apiKey, { containerTag, q }) {
|
|
112
|
+
const r = await call(
|
|
113
|
+
baseUrl,
|
|
114
|
+
apiKey,
|
|
115
|
+
'/v4/profile',
|
|
116
|
+
{
|
|
117
|
+
containerTag: String(containerTag || 'beast'),
|
|
118
|
+
...(q ? { q: String(q) } : {}),
|
|
119
|
+
},
|
|
120
|
+
12000
|
|
121
|
+
);
|
|
122
|
+
const p = (r && r.profile) || {};
|
|
123
|
+
const arr = (x) =>
|
|
124
|
+
Array.isArray(x)
|
|
125
|
+
? x.map((s) => String(s || '').trim()).filter(Boolean).slice(0, 12)
|
|
126
|
+
: typeof x === 'string' && x.trim()
|
|
127
|
+
? [x.trim().slice(0, 300)]
|
|
128
|
+
: [];
|
|
129
|
+
return { static: arr(p.static), dynamic: arr(p.dynamic) };
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
module.exports = { probe, add, search, profile, HEALTH_COOLDOWN_MS };
|
package/src/main.js
CHANGED
|
@@ -426,6 +426,11 @@ function parseSettingsText(text) {
|
|
|
426
426
|
const parsed = JSON.parse(text);
|
|
427
427
|
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) throw new Error('bozuk yapı');
|
|
428
428
|
if (!parsed.roleModels) parsed.roleModels = {};
|
|
429
|
+
/* Supermemory (lokal) DEFAULT AÇIK — sunucu ayaktayken daha akıllı bellek;
|
|
430
|
+
ayakta değilken klasik hafıza sorunsuz çalışır (engine fallback) */
|
|
431
|
+
if (!parsed.supermemory || typeof parsed.supermemory !== 'object') {
|
|
432
|
+
parsed.supermemory = { enabled: true, baseUrl: 'http://localhost:6767', apiKey: '', containerTag: 'beast' };
|
|
433
|
+
}
|
|
429
434
|
return parsed;
|
|
430
435
|
}
|
|
431
436
|
|
|
@@ -3075,6 +3080,10 @@ function reloadBackend() {
|
|
|
3075
3080
|
nightReflectAt: settings.nightReflectAt || null,
|
|
3076
3081
|
approvals: settings.security && settings.security.approvals ? approvalsBridge : null,
|
|
3077
3082
|
alwaysAllowTools: (settings.security && settings.security.alwaysAllow) || [],
|
|
3083
|
+
/* Supermemory (lokal) bellek katmanı — default açıktır (parseSettingsText);
|
|
3084
|
+
sunucu ayakta değilse engine klasik hafızaya düşer. Kapamak:
|
|
3085
|
+
settings.json → supermemory.enabled = false */
|
|
3086
|
+
supermemory: settings.supermemory || { enabled: true, baseUrl: 'http://localhost:6767', apiKey: '', containerTag: 'beast' },
|
|
3078
3087
|
crashFile: FALLOUT_CRASH_FILE,
|
|
3079
3088
|
notifyOwnerFail: settings.notifyOwnerFail !== false,
|
|
3080
3089
|
fileSend: deliverFile,
|
|
@@ -6030,6 +6039,39 @@ ipcMain.handle('sec:set', (_e, cfg) => {
|
|
|
6030
6039
|
log.info('sec', `güvenlik: onay kapısı ${settings.security.approvals ? 'AÇIK' : 'KAPALI (her şey serbest)'}`);
|
|
6031
6040
|
return { approvals: settings.security.approvals, alwaysAllow: settings.security.alwaysAllow };
|
|
6032
6041
|
});
|
|
6042
|
+
|
|
6043
|
+
/* Supermemory (lokal) ayarları: engine'e canlı yansıt + sağlık önbelleğini tazele */
|
|
6044
|
+
ipcMain.handle('supermemory:set', (_e, cfg) => {
|
|
6045
|
+
try {
|
|
6046
|
+
const base = String((cfg && cfg.baseUrl) || '').trim() || 'http://localhost:6767';
|
|
6047
|
+
settings.supermemory = {
|
|
6048
|
+
enabled: !!(cfg && cfg.enabled),
|
|
6049
|
+
baseUrl: base.replace(/\/+$/, ''),
|
|
6050
|
+
apiKey: String((cfg && cfg.apiKey) || '').trim(),
|
|
6051
|
+
containerTag: String((cfg && cfg.containerTag) || 'beast').trim() || 'beast',
|
|
6052
|
+
};
|
|
6053
|
+
saveSettings();
|
|
6054
|
+
if (engine) {
|
|
6055
|
+
engine.supermemory = settings.supermemory;
|
|
6056
|
+
engine._smUp = null;
|
|
6057
|
+
engine._smCheckedAt = 0;
|
|
6058
|
+
engine._smWarned = false;
|
|
6059
|
+
}
|
|
6060
|
+
return { ok: true, supermemory: settings.supermemory };
|
|
6061
|
+
} catch (e) {
|
|
6062
|
+
return { ok: false, error: String((e && e.message) || e) };
|
|
6063
|
+
}
|
|
6064
|
+
});
|
|
6065
|
+
ipcMain.handle('supermemory:get', () => {
|
|
6066
|
+
const sm = settings.supermemory || {};
|
|
6067
|
+
return {
|
|
6068
|
+
enabled: sm.enabled !== false,
|
|
6069
|
+
baseUrl: sm.baseUrl || 'http://localhost:6767',
|
|
6070
|
+
apiKey: sm.apiKey || '',
|
|
6071
|
+
containerTag: sm.containerTag || 'beast',
|
|
6072
|
+
up: engine ? !!engine._smUp : null,
|
|
6073
|
+
};
|
|
6074
|
+
});
|
|
6033
6075
|
ipcMain.handle('approval:respond', (_e, { id, ok, always }) => resolveApproval(id, ok, always));
|
|
6034
6076
|
/* opencode permission reply (BC): UI kartı üçlü cevap verir —
|
|
6035
6077
|
'once' | 'always' | 'reject' (+ opsiyonel geri bildirim) */
|
package/src/preload.js
CHANGED
|
@@ -89,6 +89,9 @@ contextBridge.exposeInMainWorld('beast', {
|
|
|
89
89
|
bcDeleteAll: () => ipcRenderer.invoke('bc:deleteAll'),
|
|
90
90
|
/* opencode permission (BC): UI kartı cevabı — 'once' | 'always' | 'reject' */
|
|
91
91
|
permissionReply: (requestId, action, message) => ipcRenderer.invoke('permission:reply', { requestId, action, message }),
|
|
92
|
+
/* Supermemory (lokal) bellek katmanı ayarları */
|
|
93
|
+
supermemoryGet: () => ipcRenderer.invoke('supermemory:get'),
|
|
94
|
+
supermemorySet: (cfg) => ipcRenderer.invoke('supermemory:set', cfg),
|
|
92
95
|
studioSend: (msg, attachments) => ipcRenderer.invoke('studio:send', { msg, attachments }),
|
|
93
96
|
studioStop: () => ipcRenderer.invoke('studio:stop'),
|
|
94
97
|
studioNew: () => ipcRenderer.invoke('studio:new'),
|