natureco-cli 5.20.4 → 5.22.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/CHANGELOG.md +779 -750
- package/README.md +608 -610
- package/bin/natureco.js +1099 -1095
- package/package.json +95 -94
- package/scripts/generate-qr.js +21 -0
- package/scripts/import-curated-skills-log.json +5 -0
- package/scripts/import-curated-skills.js +262 -0
- package/scripts/import-skills-log.json +167 -0
- package/scripts/import-skills.js +261 -0
- package/scripts/postinstall.js +125 -0
- package/src/commands/agent.js +280 -280
- package/src/commands/ask.js +4 -2
- package/src/commands/chat.js +0 -1
- package/src/commands/help.js +0 -2
- package/src/commands/naturehub.js +206 -373
- package/src/commands/repl.js +56 -63
- package/src/providers/mem0-memory.js +121 -121
- package/src/providers/supermemory-memory.js +117 -117
- package/src/tools/llm_task.js +150 -163
- package/src/tools/mac_alarm.js +199 -199
- package/src/tools/workflow.js +438 -439
- package/src/utils/api.js +1211 -1188
- package/src/utils/cost-tracker.js +361 -360
- package/src/utils/inquirer-wrapper.js +43 -31
- package/src/utils/paste-safe-input.js +346 -334
- package/src/utils/process-errors.js +129 -115
- package/src/utils/provider-detect.js +76 -72
- package/src/utils/skills.js +1 -1
- package/src/utils/system-prompt.js +141 -136
- package/src/utils/tools.js +324 -324
- package/README.md.bak +0 -565
- package/src/tools/http.js.bak +0 -78
package/src/commands/repl.js
CHANGED
|
@@ -101,7 +101,6 @@ function rebuildSystemPrompt(opts) {
|
|
|
101
101
|
|
|
102
102
|
// ── Tool Guardrails instance (Hermes-style) ─────────────────────────────
|
|
103
103
|
const guardrails = new ToolGuardrails();
|
|
104
|
-
const noopCallback = () => {};
|
|
105
104
|
|
|
106
105
|
// CLI komutları (REPL içinden çalıştırılabilir)
|
|
107
106
|
const CLI_COMMANDS = {
|
|
@@ -119,31 +118,31 @@ const CLI_COMMANDS = {
|
|
|
119
118
|
'/models': { desc: 'Modeller', run: ['models', 'list'] },
|
|
120
119
|
'/memory-ls': { desc: 'Memory dosyaları', run: ['memory', 'list'] },
|
|
121
120
|
'/seo': { desc: 'SEO denetimi (URL gerek)', needsArg: true, run: ['seo', 'audit'] },
|
|
122
|
-
'/naturehub': { desc: '
|
|
121
|
+
'/naturehub': { desc: 'Bota mesaj gönder (text gerek)', needsArg: true, run: ['naturehub', 'post'] },
|
|
123
122
|
'/dashboard': { desc: 'Web dashboard başlat (port 7421)', run: ['dashboard', 'start'] },
|
|
124
123
|
};
|
|
125
124
|
|
|
126
|
-
|
|
127
|
-
const
|
|
128
|
-
const
|
|
129
|
-
const
|
|
125
|
+
// Profil desteği: --profile <ad> ile ~/.natureco-<ad> kullanılır (config ile tutarlı)
|
|
126
|
+
const { CONFIG_DIR: PROFILE_DIR } = require('../utils/config');
|
|
127
|
+
const MEMORY_DIR = path.join(PROFILE_DIR, 'memory');
|
|
128
|
+
const SESSION_DIR = path.join(PROFILE_DIR, 'sessions');
|
|
129
|
+
const SESSIONS_INDEX = path.join(PROFILE_DIR, 'sessions.json');
|
|
130
|
+
const REPL_STATE = path.join(PROFILE_DIR, 'repl-state.json');
|
|
130
131
|
|
|
131
132
|
function ensureDir(dir) {
|
|
132
133
|
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
133
134
|
}
|
|
134
135
|
|
|
135
136
|
function getConfig() {
|
|
137
|
+
// Merkezi config'e delege — --profile desteği, backup ve validation
|
|
138
|
+
// yerel kopyada yoktu; REPL kullanıcının gerçek config'ini okuyordu
|
|
136
139
|
try {
|
|
137
|
-
return
|
|
140
|
+
return require('../utils/config').getConfig() || {};
|
|
138
141
|
} catch { return {}; }
|
|
139
142
|
}
|
|
140
143
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
}
|
|
144
|
-
function isGemini(url) {
|
|
145
|
-
return url && (url.includes('generativelanguage.googleapis.com') || url.includes('gemini'));
|
|
146
|
-
}
|
|
144
|
+
// Tek doğruluk kaynağı: provider-detect (MiniMax /v1 toleransı dahil)
|
|
145
|
+
const { isMiniMax, isGemini, buildChatEndpoint } = require('../utils/provider-detect');
|
|
147
146
|
|
|
148
147
|
function loadMemory(username) {
|
|
149
148
|
const file = path.join(MEMORY_DIR, `${(username || 'default').toLowerCase()}.json`);
|
|
@@ -197,8 +196,6 @@ function saveSession(messages, meta) {
|
|
|
197
196
|
return id;
|
|
198
197
|
}
|
|
199
198
|
|
|
200
|
-
|
|
201
|
-
|
|
202
199
|
function loadSession(id) {
|
|
203
200
|
// ID veya index
|
|
204
201
|
const idx = loadSessionsIndex();
|
|
@@ -227,12 +224,10 @@ function extractFacts(messages, currentFacts) {
|
|
|
227
224
|
|
|
228
225
|
// İsim/tercih pattern'leri
|
|
229
226
|
const patterns = [
|
|
230
|
-
{ re: /(?:benim
|
|
231
|
-
{ re: /(?:yaşıyorum|yaşadığım|
|
|
232
|
-
{ re: /(
|
|
233
|
-
{ re: /(
|
|
234
|
-
{ re: /(?:çalışıyorum|işim|mesleğim|çalışırım|I work as)\s+([A-ZÇĞİÖŞÜa-zçğıöşü\s]+)/i, val: m => `Meslek: ${m[1].trim()}` },
|
|
235
|
-
{ re: /(\d{1,3})\s*(?:yaş[ıi]nday[ıi]m|yaş[ıi]nda)/i, val: m => `Yaş: ${m[1]}` },
|
|
227
|
+
{ re: /(?:benim adım|adım|I'm called|my name is)\s+([A-ZÇĞİÖŞÜa-zçğıöşü]+)/i, val: m => `Adı: ${m[1]}` },
|
|
228
|
+
{ re: /(?:yaşıyorum|yaşadığım|I live in)\s+([A-ZÇĞİÖŞÜa-zçğıöşü\s]+)/i, val: m => `Yaşadığı yer: ${m[1].trim()}` },
|
|
229
|
+
{ re: /(?:seviyorum|severim|sevdiğim|like|love)\s+(?:şu|bu)?\s*([a-zA-ZçğıöşüÇĞİÖŞÜ\s]{2,30})/i, val: m => `Sevdiği şey: ${m[1].trim()}` },
|
|
230
|
+
{ re: /(?:çalışıyorum|işim|mesleğim|I work as)\s+([A-ZÇĞİÖŞÜa-zçğıöşü\s]+)/i, val: m => `Meslek: ${m[1].trim()}` },
|
|
236
231
|
];
|
|
237
232
|
|
|
238
233
|
for (const p of patterns) {
|
|
@@ -251,12 +246,7 @@ function extractFacts(messages, currentFacts) {
|
|
|
251
246
|
|
|
252
247
|
function apiRequest(providerUrl, providerApiKey, body, stream = false, retries = 3) {
|
|
253
248
|
return new Promise((resolve, reject) => {
|
|
254
|
-
const
|
|
255
|
-
const endpoint = isMM
|
|
256
|
-
? `${providerUrl.replace(/\/+$/, '')}/v1/text/chatcompletion_v2`
|
|
257
|
-
: isGemini(providerUrl)
|
|
258
|
-
? `${providerUrl.replace(/\/+$/, '')}/openai/chat/completions`
|
|
259
|
-
: `${providerUrl.replace(/\/+$/, '')}/chat/completions`;
|
|
249
|
+
const endpoint = buildChatEndpoint(providerUrl);
|
|
260
250
|
const doRequest = (attempt) => {
|
|
261
251
|
const req = https.request(endpoint, {
|
|
262
252
|
method: 'POST',
|
|
@@ -612,11 +602,9 @@ async function sendStreaming(providerUrl, providerApiKey, messages, model, onChu
|
|
|
612
602
|
const res = await apiRequest(providerUrl, providerApiKey, body, false);
|
|
613
603
|
const msg = res.choices?.[0]?.message || {};
|
|
614
604
|
const content = msg.content || '';
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
await new Promise(r => setTimeout(r, 8));
|
|
619
|
-
}
|
|
605
|
+
for (const char of content) {
|
|
606
|
+
onChunk(char);
|
|
607
|
+
await new Promise(r => setTimeout(r, 8));
|
|
620
608
|
}
|
|
621
609
|
fullText = content;
|
|
622
610
|
// Non-stream tool call desteği
|
|
@@ -629,13 +617,8 @@ async function sendStreaming(providerUrl, providerApiKey, messages, model, onChu
|
|
|
629
617
|
break;
|
|
630
618
|
}
|
|
631
619
|
|
|
632
|
-
// OpenAI uyumlu streaming
|
|
633
|
-
|
|
634
|
-
const endpoint = isMM
|
|
635
|
-
? `${providerUrl.replace(/\/+$/, '')}/v1/text/chatcompletion_v2`
|
|
636
|
-
: isGemini(providerUrl)
|
|
637
|
-
? `${providerUrl.replace(/\/+$/, '')}/openai/chat/completions`
|
|
638
|
-
: `${providerUrl.replace(/\/+$/, '')}/chat/completions`;
|
|
620
|
+
// OpenAI uyumlu streaming — tek doğruluk kaynağı buildChatEndpoint
|
|
621
|
+
const endpoint = buildChatEndpoint(providerUrl);
|
|
639
622
|
let result;
|
|
640
623
|
try {
|
|
641
624
|
result = await new Promise((resolve, reject) => {
|
|
@@ -803,7 +786,7 @@ async function processToolCalls(toolCalls, onToolCall, onAsk) {
|
|
|
803
786
|
const name = tc.function?.name || tc.name;
|
|
804
787
|
const argsStr = tc.function?.arguments || tc.args || '{}';
|
|
805
788
|
const id = tc.id || `call_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`;
|
|
806
|
-
let args
|
|
789
|
+
let args;
|
|
807
790
|
try {
|
|
808
791
|
args = typeof argsStr === 'string' ? JSON.parse(argsStr) : argsStr;
|
|
809
792
|
} catch (e) {
|
|
@@ -1107,6 +1090,8 @@ async function startRepl(args) {
|
|
|
1107
1090
|
memorySnapshotBlock, skillsIndexBlock, projectRules,
|
|
1108
1091
|
crossSessionContext: crossSessionContext || '',
|
|
1109
1092
|
userHome: cfg.userHome || '',
|
|
1093
|
+
platform: process.platform,
|
|
1094
|
+
desktopPath: cfg.userHome ? path.join(cfg.userHome, 'Desktop') : '',
|
|
1110
1095
|
hasHistory: messages.length > 0,
|
|
1111
1096
|
memoryFacts: memory.facts || [],
|
|
1112
1097
|
};
|
|
@@ -1127,7 +1112,8 @@ async function startRepl(args) {
|
|
|
1127
1112
|
console.log(tui.styled(' ' + '─'.repeat(56), { color: tui.PALETTE.border }));
|
|
1128
1113
|
console.log(tui.C.muted(' Provider: ') + tui.C.brand(providerUrl.replace(/https?:\/\//, '')));
|
|
1129
1114
|
console.log(tui.C.muted(' Model: ') + tui.C.brand(model));
|
|
1130
|
-
|
|
1115
|
+
const displayUser = memory.nickname || cfg.userName || require('os').userInfo().username || 'Kullanıcı';
|
|
1116
|
+
console.log(tui.C.muted(' Kullanıcı: ') + tui.C.brand(displayUser + (memory.nickname && cfg.userName ? ` (${cfg.userName})` : '')));
|
|
1131
1117
|
console.log(tui.C.muted(' Bot: ') + tui.C.brand(memory.botName || 'Asistan'));
|
|
1132
1118
|
if (messages.length > 1) {
|
|
1133
1119
|
console.log(tui.C.muted(' Oturum: ') + tui.C.amber(`${messages.filter(m => m.role === 'user' || m.role === 'assistant').length} mesaj (resume)`));
|
|
@@ -1162,9 +1148,6 @@ async function startRepl(args) {
|
|
|
1162
1148
|
let totalInputTokens = 0;
|
|
1163
1149
|
let totalOutputTokens = 0;
|
|
1164
1150
|
|
|
1165
|
-
let _pendingCount = 0;
|
|
1166
|
-
let _closeRequested = false;
|
|
1167
|
-
|
|
1168
1151
|
enableBracketedPaste(process.stdout);
|
|
1169
1152
|
|
|
1170
1153
|
const rl = readline.createInterface({
|
|
@@ -1173,7 +1156,12 @@ async function startRepl(args) {
|
|
|
1173
1156
|
prompt: tui.styled('\n You ', { color: tui.PALETTE.primary, bold: true }),
|
|
1174
1157
|
terminal: true,
|
|
1175
1158
|
});
|
|
1176
|
-
|
|
1159
|
+
// Pipe/script kullanımında EOF, yanıt hâlâ üretilirken gelir —
|
|
1160
|
+
// aktif işlem varken kapanışı bekletmek için sayaç + kapalı-rl koruması
|
|
1161
|
+
let _busy = 0;
|
|
1162
|
+
let _rlClosed = false;
|
|
1163
|
+
const safePrompt = () => { if (!_rlClosed) rl.prompt(); };
|
|
1164
|
+
safePrompt();
|
|
1177
1165
|
|
|
1178
1166
|
const cleanup = async (exitCode = 0) => {
|
|
1179
1167
|
if (messages.length > 1) {
|
|
@@ -1273,10 +1261,18 @@ async function startRepl(args) {
|
|
|
1273
1261
|
process.on('SIGTERM', () => cleanup(0));
|
|
1274
1262
|
|
|
1275
1263
|
rl.on('line', async (input) => {
|
|
1276
|
-
|
|
1264
|
+
// BOM ve benzeri görünmez karakterleri temizle (PowerShell echo BOM'lu gönderir)
|
|
1265
|
+
const line = restoreNewlines(input).replace(/[\u200B\u200C\u200D\uFEFF]/g, '').trim();
|
|
1266
|
+
if (!line) { safePrompt(); return; }
|
|
1267
|
+
_busy++;
|
|
1277
1268
|
try {
|
|
1278
|
-
|
|
1279
|
-
|
|
1269
|
+
await handleLine(line);
|
|
1270
|
+
} finally {
|
|
1271
|
+
_busy--;
|
|
1272
|
+
}
|
|
1273
|
+
});
|
|
1274
|
+
|
|
1275
|
+
async function handleLine(line) {
|
|
1280
1276
|
|
|
1281
1277
|
// Çok satırlı paste: output filter'a echo'yu durdurma sinyalini ver
|
|
1282
1278
|
clearPasteContext();
|
|
@@ -1435,7 +1431,7 @@ async function startRepl(args) {
|
|
|
1435
1431
|
console.log(chalk.yellow(` Bilinmeyen komut: /${cmd}. /help yazın.`));
|
|
1436
1432
|
}
|
|
1437
1433
|
}
|
|
1438
|
-
|
|
1434
|
+
safePrompt();
|
|
1439
1435
|
return;
|
|
1440
1436
|
}
|
|
1441
1437
|
|
|
@@ -1474,7 +1470,8 @@ async function startRepl(args) {
|
|
|
1474
1470
|
// v5.13.0: Run workflow FIRST for every request
|
|
1475
1471
|
process.stdout.write(tui.styled('\r 🔧 workflow... ', { color: tui.PALETTE.muted }));
|
|
1476
1472
|
const wfToolDefs = getToolDefs();
|
|
1477
|
-
const
|
|
1473
|
+
const recentHistory = messages.length > 1 ? messages.slice(-10) : [];
|
|
1474
|
+
const wfResult = await executeTool('workflow', { action: 'run', task: line, conversationHistory: recentHistory }, wfToolDefs);
|
|
1478
1475
|
const wf = wfResult?.result || {};
|
|
1479
1476
|
if (wf.success !== false) {
|
|
1480
1477
|
const loaded = wf.skillsLoaded && wf.skillsLoaded.length > 0 ? ` [skill: ${wf.skillsLoaded.join(', ')}]` : '';
|
|
@@ -1530,7 +1527,7 @@ async function startRepl(args) {
|
|
|
1530
1527
|
messages,
|
|
1531
1528
|
model,
|
|
1532
1529
|
// v5.6.12: Callback bos - tam metin 'reply' olarak gelecek (non-stream mode)
|
|
1533
|
-
|
|
1530
|
+
() => {},
|
|
1534
1531
|
// Tool call callback — Hermes-style per-tool status line
|
|
1535
1532
|
((toolEvent) => {
|
|
1536
1533
|
const name = toolEvent.name;
|
|
@@ -1583,21 +1580,17 @@ async function startRepl(args) {
|
|
|
1583
1580
|
process.stdout.write('\n');
|
|
1584
1581
|
console.log(chalk.red(' ❌ ' + err.message));
|
|
1585
1582
|
}
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
_pendingCount--;
|
|
1589
|
-
if (_closeRequested && _pendingCount === 0) {
|
|
1590
|
-
await cleanup(0);
|
|
1591
|
-
}
|
|
1592
|
-
}
|
|
1593
|
-
});
|
|
1583
|
+
safePrompt();
|
|
1584
|
+
}
|
|
1594
1585
|
|
|
1595
1586
|
rl.on('close', () => {
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1587
|
+
_rlClosed = true;
|
|
1588
|
+
// EOF (pipe/script): süren yanıt varsa bitmesini bekle, sonra kapan
|
|
1589
|
+
const wait = () => {
|
|
1590
|
+
if (_busy > 0) { setTimeout(wait, 200); return; }
|
|
1599
1591
|
cleanup(0);
|
|
1600
|
-
}
|
|
1592
|
+
};
|
|
1593
|
+
wait();
|
|
1601
1594
|
});
|
|
1602
1595
|
}
|
|
1603
1596
|
|
|
@@ -1,121 +1,121 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* mem0-memory.js — Mem0 memory provider
|
|
3
|
-
*
|
|
4
|
-
* Uses the mem0ai npm package (platform API) or local OSS Memory class.
|
|
5
|
-
* Requires MEM0_API_KEY env var or config.mem0.apiKey.
|
|
6
|
-
* npm install mem0ai
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
const { MemoryProvider, registerProvider } = require('../utils/memory-provider');
|
|
10
|
-
|
|
11
|
-
class Mem0MemoryProvider extends MemoryProvider {
|
|
12
|
-
constructor(config = {}) {
|
|
13
|
-
super(config);
|
|
14
|
-
this.name = 'mem0';
|
|
15
|
-
this._client = null;
|
|
16
|
-
this._mode = 'platform'; // or 'oss'
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
_getConfig() {
|
|
20
|
-
return this.config.mem0 || this.config.Mem0 || {};
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
_apiKey() {
|
|
24
|
-
return process.env.MEM0_API_KEY || this._getConfig().apiKey || '';
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
async _ensureClient() {
|
|
28
|
-
if (this._client) return;
|
|
29
|
-
try {
|
|
30
|
-
const apiKey = this._apiKey();
|
|
31
|
-
if (apiKey) {
|
|
32
|
-
const { MemoryClient } = await import('mem0ai');
|
|
33
|
-
this._client = new MemoryClient({ apiKey });
|
|
34
|
-
this._mode = 'platform';
|
|
35
|
-
} else {
|
|
36
|
-
const { Memory } = await import('mem0ai/oss');
|
|
37
|
-
this._client = new Memory(this._getConfig().oss || {});
|
|
38
|
-
this._mode = 'oss';
|
|
39
|
-
}
|
|
40
|
-
} catch (e) {
|
|
41
|
-
throw new Error('mem0ai paketi yuklu degil. npm install mem0ai');
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
async add(userId, content, metadata = {}) {
|
|
46
|
-
await this._ensureClient();
|
|
47
|
-
const uid = userId || 'default';
|
|
48
|
-
if (this._mode === 'platform') {
|
|
49
|
-
const messages = [{ role: 'user', content }];
|
|
50
|
-
await this._client.add(messages, { userId: uid, metadata });
|
|
51
|
-
} else {
|
|
52
|
-
const messages = [
|
|
53
|
-
{ role: 'user', content },
|
|
54
|
-
{ role: 'assistant', content: 'Bilgi kaydedildi.' },
|
|
55
|
-
];
|
|
56
|
-
await this._client.add(messages, { userId: uid, metadata });
|
|
57
|
-
}
|
|
58
|
-
return { success: true, id: content, message: 'Mem0 memory added', provider: 'mem0' };
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
async search(query, options = {}) {
|
|
62
|
-
await this._ensureClient();
|
|
63
|
-
const uid = options.userId;
|
|
64
|
-
const filters = uid ? { userId: uid } : {};
|
|
65
|
-
if (options.limit) filters.limit = options.limit;
|
|
66
|
-
try {
|
|
67
|
-
const results = await this._client.search(query, { filters });
|
|
68
|
-
return { success: true, results: (results.results || results || []).map(r => ({
|
|
69
|
-
id: r.id || r.memory,
|
|
70
|
-
content: r.memory || r.content || '',
|
|
71
|
-
score: r.score || 0,
|
|
72
|
-
metadata: r.metadata || {},
|
|
73
|
-
})) };
|
|
74
|
-
} catch (e) {
|
|
75
|
-
return { success: false, error: e.message, results: [] };
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
async list(userId) {
|
|
80
|
-
await this._ensureClient();
|
|
81
|
-
const uid = userId || 'default';
|
|
82
|
-
try {
|
|
83
|
-
const memories = await this._client.getAll({ userId: uid });
|
|
84
|
-
return {
|
|
85
|
-
success: true,
|
|
86
|
-
memories: (memories || []).map(r => ({
|
|
87
|
-
id: r.id || r.memory,
|
|
88
|
-
content: r.memory || r.content || '',
|
|
89
|
-
score: r.score || 0,
|
|
90
|
-
metadata: r.metadata || {},
|
|
91
|
-
})),
|
|
92
|
-
};
|
|
93
|
-
} catch (e) {
|
|
94
|
-
return { success: false, error: e.message, memories: [] };
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
async remove(id) {
|
|
99
|
-
await this._ensureClient();
|
|
100
|
-
try {
|
|
101
|
-
await this._client.delete(id);
|
|
102
|
-
return { success: true, message: 'Mem0 memory removed' };
|
|
103
|
-
} catch (e) {
|
|
104
|
-
return { success: false, error: e.message };
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
async clear(userId) {
|
|
109
|
-
await this._ensureClient();
|
|
110
|
-
const uid = userId || 'default';
|
|
111
|
-
try {
|
|
112
|
-
await this._client.deleteAll({ userId: uid });
|
|
113
|
-
return { success: true, message: `Mem0 memory cleared for ${uid}` };
|
|
114
|
-
} catch (e) {
|
|
115
|
-
return { success: false, error: e.message };
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
registerProvider('mem0', Mem0MemoryProvider);
|
|
121
|
-
module.exports = Mem0MemoryProvider;
|
|
1
|
+
/**
|
|
2
|
+
* mem0-memory.js — Mem0 memory provider
|
|
3
|
+
*
|
|
4
|
+
* Uses the mem0ai npm package (platform API) or local OSS Memory class.
|
|
5
|
+
* Requires MEM0_API_KEY env var or config.mem0.apiKey.
|
|
6
|
+
* npm install mem0ai
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const { MemoryProvider, registerProvider } = require('../utils/memory-provider');
|
|
10
|
+
|
|
11
|
+
class Mem0MemoryProvider extends MemoryProvider {
|
|
12
|
+
constructor(config = {}) {
|
|
13
|
+
super(config);
|
|
14
|
+
this.name = 'mem0';
|
|
15
|
+
this._client = null;
|
|
16
|
+
this._mode = 'platform'; // or 'oss'
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
_getConfig() {
|
|
20
|
+
return this.config.mem0 || this.config.Mem0 || {};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
_apiKey() {
|
|
24
|
+
return process.env.MEM0_API_KEY || this._getConfig().apiKey || '';
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async _ensureClient() {
|
|
28
|
+
if (this._client) return;
|
|
29
|
+
try {
|
|
30
|
+
const apiKey = this._apiKey();
|
|
31
|
+
if (apiKey) {
|
|
32
|
+
const { MemoryClient } = await import('mem0ai');
|
|
33
|
+
this._client = new MemoryClient({ apiKey });
|
|
34
|
+
this._mode = 'platform';
|
|
35
|
+
} else {
|
|
36
|
+
const { Memory } = await import('mem0ai/oss');
|
|
37
|
+
this._client = new Memory(this._getConfig().oss || {});
|
|
38
|
+
this._mode = 'oss';
|
|
39
|
+
}
|
|
40
|
+
} catch (e) {
|
|
41
|
+
throw new Error('mem0ai paketi yuklu degil. npm install mem0ai', { cause: e });
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async add(userId, content, metadata = {}) {
|
|
46
|
+
await this._ensureClient();
|
|
47
|
+
const uid = userId || 'default';
|
|
48
|
+
if (this._mode === 'platform') {
|
|
49
|
+
const messages = [{ role: 'user', content }];
|
|
50
|
+
await this._client.add(messages, { userId: uid, metadata });
|
|
51
|
+
} else {
|
|
52
|
+
const messages = [
|
|
53
|
+
{ role: 'user', content },
|
|
54
|
+
{ role: 'assistant', content: 'Bilgi kaydedildi.' },
|
|
55
|
+
];
|
|
56
|
+
await this._client.add(messages, { userId: uid, metadata });
|
|
57
|
+
}
|
|
58
|
+
return { success: true, id: content, message: 'Mem0 memory added', provider: 'mem0' };
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
async search(query, options = {}) {
|
|
62
|
+
await this._ensureClient();
|
|
63
|
+
const uid = options.userId;
|
|
64
|
+
const filters = uid ? { userId: uid } : {};
|
|
65
|
+
if (options.limit) filters.limit = options.limit;
|
|
66
|
+
try {
|
|
67
|
+
const results = await this._client.search(query, { filters });
|
|
68
|
+
return { success: true, results: (results.results || results || []).map(r => ({
|
|
69
|
+
id: r.id || r.memory,
|
|
70
|
+
content: r.memory || r.content || '',
|
|
71
|
+
score: r.score || 0,
|
|
72
|
+
metadata: r.metadata || {},
|
|
73
|
+
})) };
|
|
74
|
+
} catch (e) {
|
|
75
|
+
return { success: false, error: e.message, results: [] };
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
async list(userId) {
|
|
80
|
+
await this._ensureClient();
|
|
81
|
+
const uid = userId || 'default';
|
|
82
|
+
try {
|
|
83
|
+
const memories = await this._client.getAll({ userId: uid });
|
|
84
|
+
return {
|
|
85
|
+
success: true,
|
|
86
|
+
memories: (memories || []).map(r => ({
|
|
87
|
+
id: r.id || r.memory,
|
|
88
|
+
content: r.memory || r.content || '',
|
|
89
|
+
score: r.score || 0,
|
|
90
|
+
metadata: r.metadata || {},
|
|
91
|
+
})),
|
|
92
|
+
};
|
|
93
|
+
} catch (e) {
|
|
94
|
+
return { success: false, error: e.message, memories: [] };
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
async remove(id) {
|
|
99
|
+
await this._ensureClient();
|
|
100
|
+
try {
|
|
101
|
+
await this._client.delete(id);
|
|
102
|
+
return { success: true, message: 'Mem0 memory removed' };
|
|
103
|
+
} catch (e) {
|
|
104
|
+
return { success: false, error: e.message };
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
async clear(userId) {
|
|
109
|
+
await this._ensureClient();
|
|
110
|
+
const uid = userId || 'default';
|
|
111
|
+
try {
|
|
112
|
+
await this._client.deleteAll({ userId: uid });
|
|
113
|
+
return { success: true, message: `Mem0 memory cleared for ${uid}` };
|
|
114
|
+
} catch (e) {
|
|
115
|
+
return { success: false, error: e.message };
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
registerProvider('mem0', Mem0MemoryProvider);
|
|
121
|
+
module.exports = Mem0MemoryProvider;
|