natureco-cli 2.3.2 → 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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "natureco-cli",
3
- "version": "2.3.2",
3
+ "version": "2.4.1",
4
4
  "description": "NatureCo AI Bot Terminal Interface",
5
5
  "main": "bin/natureco.js",
6
6
  "bin": {
@@ -211,7 +211,7 @@ body::before{
211
211
  <div class="header-bot-name" id="header-bot-name">Nature Bot</div>
212
212
  <div class="header-bot-model" id="header-bot-model">NatureCo</div>
213
213
  </div>
214
- <div class="version-badge" id="version-badge">v2.3.2</div>
214
+ <div class="version-badge" id="version-badge">v2.4.1</div>
215
215
  </div>
216
216
  <div class="messages" id="messages"></div>
217
217
  <div class="input-area">
@@ -341,7 +341,7 @@ function dashboard(action) {
341
341
  apiKey: cfg.apiKey,
342
342
  defaultBot: cfg.defaultBot,
343
343
  defaultBotId: cfg.defaultBotId,
344
- version: 'v2.3.2',
344
+ version: 'v2.4.1',
345
345
  bots: cfg.bots || [],
346
346
  telegramToken: cfg.telegramToken || null,
347
347
  whatsappConnected: cfg.whatsappConnected || false,
package/src/utils/api.js CHANGED
@@ -1,13 +1,65 @@
1
- // NatureCo CLI v2.2.2 - Universal LLM Provider Support
1
+ // NatureCo CLI v2.4.1 - Universal LLM Provider Support
2
2
  // Supports: OpenAI, Groq, Together, Fireworks, Perplexity, Mistral, DeepSeek, OpenRouter, Ollama, LM Studio, Anthropic
3
3
 
4
+ const fs = require('fs');
4
5
  const os = require('os');
6
+ const path = require('path');
5
7
  const { getConfig } = require('./config');
6
8
  const { getToolDefinitions, executeToolCalls } = require('./tool-runner');
7
9
 
8
- // Conversation history for multi-turn chat
10
+ // Persistent conversation directory
11
+ const CONV_DIR = path.join(os.homedir(), '.natureco', 'conversations');
12
+
13
+ // Conversation history for multi-turn chat (deprecated - now using disk storage)
9
14
  const conversationHistory = new Map();
10
15
 
16
+ /**
17
+ * Generate default conversation ID based on provider config
18
+ */
19
+ function generateDefaultConvId() {
20
+ const config = getConfig();
21
+
22
+ // Use provider URL + model as base for consistent ID
23
+ const providerUrl = config.providerUrl || 'default';
24
+ const model = config.providerModel || 'default';
25
+
26
+ // Create simple hash-like ID from provider + model
27
+ const base = `${providerUrl}_${model}`.replace(/[^a-z0-9]/gi, '_').toLowerCase();
28
+
29
+ // Return consistent ID (e.g., "groq_llama_3_1_8b_instant")
30
+ return base.slice(0, 50); // Limit length
31
+ }
32
+
33
+ /**
34
+ * Load conversation from disk
35
+ */
36
+ function loadConversation(convId) {
37
+ const file = path.join(CONV_DIR, `${convId.replace(/[^a-z0-9]/gi, '_')}.json`);
38
+ try {
39
+ fs.mkdirSync(CONV_DIR, { recursive: true });
40
+ if (fs.existsSync(file)) {
41
+ return JSON.parse(fs.readFileSync(file, 'utf8'));
42
+ }
43
+ } catch (e) {
44
+ // Silently fail
45
+ }
46
+ return [];
47
+ }
48
+
49
+ /**
50
+ * Save conversation to disk
51
+ */
52
+ function saveConversation(convId, messages) {
53
+ const file = path.join(CONV_DIR, `${convId.replace(/[^a-z0-9]/gi, '_')}.json`);
54
+ try {
55
+ fs.mkdirSync(CONV_DIR, { recursive: true });
56
+ // Keep only last 20 messages
57
+ fs.writeFileSync(file, JSON.stringify(messages.slice(-20), null, 2));
58
+ } catch (e) {
59
+ // Silently fail
60
+ }
61
+ }
62
+
11
63
  /**
12
64
  * Check if debug mode is enabled
13
65
  */
@@ -182,12 +234,10 @@ async function sendMessageToProvider(apiKey, message, conversationId = null, sys
182
234
  );
183
235
  }
184
236
 
185
- // Get or create conversation history
186
- const convId = conversationId || `conv_${Date.now()}`;
187
- if (!conversationHistory.has(convId)) {
188
- conversationHistory.set(convId, []);
189
- }
190
- const history = conversationHistory.get(convId);
237
+ // Get or create conversation history (load from disk)
238
+ // Use consistent ID based on provider config instead of timestamp
239
+ const convId = conversationId || generateDefaultConvId();
240
+ const history = loadConversation(convId);
191
241
 
192
242
  // Build messages
193
243
  const messages = [];
@@ -276,10 +326,8 @@ async function sendMessageToProvider(apiKey, message, conversationId = null, sys
276
326
  history.push({ role: 'user', content: message });
277
327
  history.push({ role: 'assistant', content: finalResponse });
278
328
 
279
- // Keep history limited to last 20 messages
280
- if (history.length > 20) {
281
- conversationHistory.set(convId, history.slice(-20));
282
- }
329
+ // Save to disk (automatically keeps last 20 messages)
330
+ saveConversation(convId, history);
283
331
 
284
332
  return {
285
333
  reply: finalResponse,
@@ -294,8 +342,30 @@ async function sendMessageToProvider(apiKey, message, conversationId = null, sys
294
342
  */
295
343
  function clearConversation(conversationId) {
296
344
  if (conversationId) {
345
+ // Delete from disk
346
+ const file = path.join(CONV_DIR, `${conversationId.replace(/[^a-z0-9]/gi, '_')}.json`);
347
+ try {
348
+ if (fs.existsSync(file)) {
349
+ fs.unlinkSync(file);
350
+ }
351
+ } catch (e) {
352
+ // Silently fail
353
+ }
354
+ // Also clear from memory (legacy)
297
355
  conversationHistory.delete(conversationId);
298
356
  } else {
357
+ // Clear all conversations from disk
358
+ try {
359
+ if (fs.existsSync(CONV_DIR)) {
360
+ const files = fs.readdirSync(CONV_DIR);
361
+ files.forEach(file => {
362
+ fs.unlinkSync(path.join(CONV_DIR, file));
363
+ });
364
+ }
365
+ } catch (e) {
366
+ // Silently fail
367
+ }
368
+ // Also clear from memory (legacy)
299
369
  conversationHistory.clear();
300
370
  }
301
371
  }