natureco-cli 5.4.7 → 5.4.9
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/commands/repl.js +52 -5
- package/src/tools/memory_write.js +56 -7
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "natureco-cli",
|
|
3
|
-
"version": "5.4.
|
|
3
|
+
"version": "5.4.9",
|
|
4
4
|
"description": "OpenClaw'dan daha güvenli, daha hızlı, daha ucuz AI agent CLI. Multi-agent, self-evolving skills, audit log, maliyet optimizasyonu ve NatureCo platform-native.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"natureco": "bin/natureco.js"
|
package/src/commands/repl.js
CHANGED
|
@@ -24,7 +24,7 @@ const chalk = require('chalk');
|
|
|
24
24
|
const tui = require('../utils/tui');
|
|
25
25
|
const { loadToolDefinitions, toOpenAIFormat, executeTool } = require('../utils/tools');
|
|
26
26
|
|
|
27
|
-
// v5.4.6: Model adi sizintisini engelle
|
|
27
|
+
// v5.4.6: Model adi sizintisini engelle — global'e ata, callback'lerden erisebilir olsun
|
|
28
28
|
const MODEL_NAMES_TO_HIDE = ['MiniMax-M2.5', 'MiniMaxM2.5', 'minimaxm25', 'Claude-3', 'GPT-4', 'ChatGPT'];
|
|
29
29
|
function fixModelNameLeak(text, botName) {
|
|
30
30
|
if (!text) return text;
|
|
@@ -38,6 +38,7 @@ function fixModelNameLeak(text, botName) {
|
|
|
38
38
|
fixed = fixed.replace(/I am\s+Claude[^.,!?\n]*/gi, 'I am İchigo');
|
|
39
39
|
return fixed;
|
|
40
40
|
}
|
|
41
|
+
global.fixModelNameLeak = fixModelNameLeak;
|
|
41
42
|
|
|
42
43
|
// v4.8.0: Tool definitions — başlangıçta bir kez yükle (performans)
|
|
43
44
|
let _toolDefs = null;
|
|
@@ -463,8 +464,20 @@ async function startRepl(args) {
|
|
|
463
464
|
// Memory yükle
|
|
464
465
|
let memory = loadMemory(cfg.userName);
|
|
465
466
|
|
|
466
|
-
// v5.4.
|
|
467
|
+
// v5.4.7: Memory'de botName yoksa otomatik İchigo set et VE kaydet
|
|
467
468
|
if (!memory.botName) memory.botName = 'İchigo';
|
|
469
|
+
// BotName'i memory'ye persist et (her oturumda ayni kalsin)
|
|
470
|
+
try {
|
|
471
|
+
const fs = require('fs');
|
|
472
|
+
const memFile = path.join(os.homedir(), '.natureco', 'memory', ((cfg.userName || 'default').toLowerCase()) + '.json');
|
|
473
|
+
if (fs.existsSync(memFile)) {
|
|
474
|
+
const memData = JSON.parse(fs.readFileSync(memFile, 'utf8'));
|
|
475
|
+
if (!memData.botName || memData.botName !== memory.botName) {
|
|
476
|
+
memData.botName = memory.botName;
|
|
477
|
+
fs.writeFileSync(memFile, JSON.stringify(memData, null, 2), 'utf8');
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
} catch (e) {} // Sessizce devam et, kritik degil
|
|
468
481
|
// v5.4.5: SOUL.md'yi yukle ve kisiligi system prompt'a enjekte et
|
|
469
482
|
const { loadSoul, summarizeSoul } = require("../tools/soul");
|
|
470
483
|
const soulContent = loadSoul();
|
|
@@ -552,6 +565,9 @@ async function startRepl(args) {
|
|
|
552
565
|
}
|
|
553
566
|
console.log(tui.C.muted(' Komutlar: ') + tui.C.yellow('/help') + tui.C.muted(' · ') + tui.C.yellow('/memory') + tui.C.muted(' · ') + tui.C.yellow('/sessions') + tui.C.muted(' · ') + tui.C.yellow('/exit'));
|
|
554
567
|
console.log('');
|
|
568
|
+
// v5.4.7: Hard-coded kimlik — model once bunu okusun
|
|
569
|
+
console.log(tui.C.brand(' 👋 Ben ' + (memory.botName || 'İchigo') + ', ' + (userName || 'kanka') + '. Sen nasilsin?'));
|
|
570
|
+
console.log('');
|
|
555
571
|
|
|
556
572
|
let totalInputTokens = 0;
|
|
557
573
|
let totalOutputTokens = 0;
|
|
@@ -712,6 +728,17 @@ async function startRepl(args) {
|
|
|
712
728
|
// User mesajı
|
|
713
729
|
messages.push({ role: 'user', content: line });
|
|
714
730
|
|
|
731
|
+
// v5.4.9: Hard-coded fallback — "sen kimsin?" gibi sorular icin model cevabindan once prefix
|
|
732
|
+
const trimmed = (line || '').toLowerCase();
|
|
733
|
+
const isIdentityQuestion = /(sen\s+kim|adin\s+ne|kendini\s+tan|kendin\s+tanit|kimsin|ne\s+adindasin)/.test(trimmed);
|
|
734
|
+
if (isIdentityQuestion) {
|
|
735
|
+
// Hard-coded "Ben İchigo" — model cevap verse bile onemli degil, bu gorunur
|
|
736
|
+
process.stdout.write(tui.styled('\n AI ', { color: tui.PALETTE.secondary, bold: true }));
|
|
737
|
+
process.stdout.write('Ben İchigo, NatureCo CLI\'nin Türkçe yapay zeka asistanıyım. ');
|
|
738
|
+
// Modelin devam etmesini beklemiyoruz, normal akis devam etsin
|
|
739
|
+
console.log('\n');
|
|
740
|
+
}
|
|
741
|
+
|
|
715
742
|
// AI cevabı
|
|
716
743
|
process.stdout.write(tui.styled('\n AI ', { color: tui.PALETTE.secondary, bold: true }));
|
|
717
744
|
try {
|
|
@@ -721,11 +748,31 @@ async function startRepl(args) {
|
|
|
721
748
|
providerApiKey,
|
|
722
749
|
apiMessages,
|
|
723
750
|
model,
|
|
724
|
-
// Text chunk callback — v5.4.
|
|
751
|
+
// Text chunk callback — v5.4.9: streaming buffer + fix
|
|
752
|
+
// Streaming'de cümleler chunk'lar arasinda bolunur ("Ben " + "NatureCo " + "CLI").
|
|
753
|
+
// Buffer biriktir, cumle tamamlaninca (. ! ? veya newline) fix uygula.
|
|
725
754
|
(chunk) => {
|
|
726
755
|
try {
|
|
727
|
-
|
|
728
|
-
|
|
756
|
+
let c = String(chunk || '');
|
|
757
|
+
// Eger fixBuffer global'de yoksa olustur
|
|
758
|
+
if (!global._fixBuffer) global._fixBuffer = '';
|
|
759
|
+
global._fixBuffer += c;
|
|
760
|
+
|
|
761
|
+
// Son karakterle karar ver
|
|
762
|
+
const lastChar = global._fixBuffer.slice(-1);
|
|
763
|
+
// Noktalama veya newline varsa, buffer'i isle ve temizle
|
|
764
|
+
if (/[.!?\n]/.test(lastChar)) {
|
|
765
|
+
let toProcess = global._fixBuffer;
|
|
766
|
+
global._fixBuffer = '';
|
|
767
|
+
// Tum model adlarini İchigo ile degistir
|
|
768
|
+
toProcess = toProcess.replace(/MiniMax[\s\-\w\.]*/g, 'İchigo');
|
|
769
|
+
toProcess = toProcess.replace(/Claude[\s\-\w\.]*/g, 'İchigo');
|
|
770
|
+
toProcess = toProcess.replace(/GPT[\s\-\w\.]*/g, 'İchigo');
|
|
771
|
+
toProcess = toProcess.replace(/ChatGPT/g, 'İchigo');
|
|
772
|
+
toProcess = toProcess.replace(/Ben\s+(?:MiniMax|Claude|GPT|NatureCo\s+CLI|bir\s+AI)[^\n.!?]*/gi, 'Ben İchigo');
|
|
773
|
+
process.stdout.write(toProcess);
|
|
774
|
+
}
|
|
775
|
+
// Noktalama yoksa, sadece bekle (sonraki chunk'ta tamamlanir)
|
|
729
776
|
} catch (e) {
|
|
730
777
|
process.stdout.write(chunk);
|
|
731
778
|
}
|
|
@@ -58,16 +58,54 @@ function decayFacts(memory) {
|
|
|
58
58
|
return memory;
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* v5.4.9: Memory yazma sonrasi verification — geri oku ve gercekten yazildigini dogrula
|
|
64
|
+
* Self-validation mekanizmasi: tool cagirip "success" demesine ragmen dosya bos olabilir
|
|
65
|
+
*/
|
|
66
|
+
function verifyMemoryWrite(username, expectedFact, expectedBotName) {
|
|
67
|
+
try {
|
|
68
|
+
const memFile = getMemoryFile(username);
|
|
69
|
+
if (!fs.existsSync(memFile)) {
|
|
70
|
+
return { success: false, error: "Memory dosyasi olusturulamadi: " + memFile };
|
|
71
|
+
}
|
|
72
|
+
const mem = JSON.parse(fs.readFileSync(memFile, "utf8"));
|
|
73
|
+
|
|
74
|
+
// Fact verification
|
|
75
|
+
if (expectedFact) {
|
|
76
|
+
const found = (mem.facts || []).some(f => f.value === expectedFact);
|
|
77
|
+
if (!found) {
|
|
78
|
+
return { success: false, error: "Fact memory'de bulunamadi: " + expectedFact };
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// BotName verification
|
|
83
|
+
if (expectedBotName && mem.botName !== expectedBotName) {
|
|
84
|
+
return { success: false, error: "BotName guncellenmedi: " + mem.botName };
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return { success: true, message: "Memory dogrulandi" };
|
|
88
|
+
} catch (e) {
|
|
89
|
+
return { success: false, error: e.message };
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
|
|
61
94
|
function addMemory({ username, fact, score = 5, category = "general", botName, nickname, name }) {
|
|
62
|
-
|
|
95
|
+
// Username yoksa ve 'name' parametresi varsa, onu username olarak kullan
|
|
96
|
+
// (Parton'un "patron" diye hitap etmesi durumu icin)
|
|
97
|
+
const effectiveUsername = username || (name && name.toLowerCase()) || 'default';
|
|
98
|
+
if (!effectiveUsername || effectiveUsername === 'default') {
|
|
99
|
+
// Hicbir username yok, default.json'a yaz
|
|
100
|
+
}
|
|
63
101
|
|
|
64
|
-
let memory = loadMemory(
|
|
102
|
+
let memory = loadMemory(effectiveUsername);
|
|
65
103
|
memory = decayFacts(memory);
|
|
66
104
|
|
|
67
|
-
// identity updates (botName, nickname, name)
|
|
105
|
+
// identity updates (botName, nickname, name) — name sadece memory.name, username degil
|
|
68
106
|
if (botName) memory.botName = botName;
|
|
69
107
|
if (nickname !== undefined) memory.nickname = nickname;
|
|
70
|
-
if (name) memory.name = name;
|
|
108
|
+
if (name) memory.name = name; // Bu memory.name (kullanici gercek adi), username degil
|
|
71
109
|
|
|
72
110
|
if (fact) {
|
|
73
111
|
// duplicate kontrol
|
|
@@ -87,12 +125,23 @@ function addMemory({ username, fact, score = 5, category = "general", botName, n
|
|
|
87
125
|
}
|
|
88
126
|
|
|
89
127
|
if (!memory.preferences) memory.preferences = [];
|
|
90
|
-
memory = saveMemory(
|
|
128
|
+
memory = saveMemory(effectiveUsername, memory);
|
|
129
|
+
|
|
130
|
+
// v5.4.9: Verification - geri oku ve dogrula
|
|
131
|
+
const verifyResult = verifyMemoryWrite(effectiveUsername, fact, botName);
|
|
132
|
+
if (!verifyResult.success) {
|
|
133
|
+
return {
|
|
134
|
+
success: false,
|
|
135
|
+
error: "Memory yazildi ama dogrulanamadi: " + verifyResult.error,
|
|
136
|
+
username: effectiveUsername,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
91
139
|
|
|
92
140
|
return {
|
|
93
141
|
success: true,
|
|
94
|
-
message: "Memory guncellendi",
|
|
95
|
-
username,
|
|
142
|
+
message: "Memory guncellendi ve dogrulandi",
|
|
143
|
+
username: effectiveUsername,
|
|
144
|
+
verified: true,
|
|
96
145
|
totalFacts: memory.facts.length,
|
|
97
146
|
facts: memory.facts.map(f => ({ value: f.value, score: f.score, category: f.category })),
|
|
98
147
|
botName: memory.botName,
|