natureco-cli 2.23.19 → 2.23.21

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.23.19",
3
+ "version": "2.23.21",
4
4
  "description": "NatureCo AI Bot Terminal Interface",
5
5
  "bin": {
6
6
  "natureco": "bin/natureco.js"
@@ -6,7 +6,7 @@ const { execSync } = require('child_process');
6
6
  const inquirer = require('../utils/inquirer-wrapper');
7
7
  const chalk = require('chalk');
8
8
  const { getApiKey, getConfig } = require('../utils/config');
9
- const { getBots, getProviderConfig, startMcpServers } = require('../utils/api');
9
+ const { getBots, getProviderConfig, startMcpServers, sendMessageOpenAICompatible, streamProviderCompletion } = require('../utils/api');
10
10
  const { getMemoryPrompt, loadMemory } = require('../utils/memory');
11
11
  const { getAgentsPrompt } = require('../utils/agents');
12
12
  const { createSession, addMessageToSession } = require('../utils/sessions');
@@ -159,13 +159,8 @@ async function generateSummary(messages, providerConfig) {
159
159
  if (!recent.length) return 'Bu session boş geçti.';
160
160
  const prompt = `Bu kod session'ını 3-5 madde halinde Türkçe özetle. Ne yapıldı, hangi dosyalar değiştirildi, hangi sorunlar çözüldü:\n${JSON.stringify(recent).slice(0, 3000)}`;
161
161
  try {
162
- const res = await fetch(`${providerConfig.url}/chat/completions`, {
163
- method: 'POST',
164
- headers: { 'Authorization': `Bearer ${providerConfig.apiKey}`, 'Content-Type': 'application/json' },
165
- body: JSON.stringify({ model: providerConfig.model, messages: [{ role: 'user', content: prompt }], max_tokens: 400, stream: false }),
166
- });
167
- const data = await res.json();
168
- return data.choices?.[0]?.message?.content || 'Özet oluşturulamadı.';
162
+ const result = await sendMessageOpenAICompatible(providerConfig, [{ role: 'user', content: prompt }], []);
163
+ return result.content || 'Özet oluşturulamadı.';
169
164
  } catch {
170
165
  return 'Özet oluşturulamadı.';
171
166
  }
@@ -185,106 +180,29 @@ async function saveProjectMemory(messages, providerConfig, workDir) {
185
180
 
186
181
  // ── Git helpers ───────────────────────────────────────────────────────────────
187
182
  async function generateCommitMessage(diff, providerConfig) {
188
- const body = {
189
- model: providerConfig.model,
190
- messages: [
183
+ try {
184
+ const result = await sendMessageOpenAICompatible(providerConfig, [
191
185
  { role: 'system', content: 'Sen bir git commit mesajı üreticisin. Conventional Commits formatında (feat/fix/refactor/chore vb.) kısa ve açıklayıcı bir commit mesajı yaz. Sadece mesajı yaz, başka hiçbir şey yazma.' },
192
186
  { role: 'user', content: `Bu diff için commit mesajı üret:\n\n${diff}` },
193
- ],
194
- temperature: 0.3,
195
- max_tokens: 100,
196
- stream: false,
197
- };
198
- const res = await fetch(`${providerConfig.url}/chat/completions`, {
199
- method: 'POST',
200
- headers: { 'Authorization': `Bearer ${providerConfig.apiKey}`, 'Content-Type': 'application/json' },
201
- body: JSON.stringify(body),
202
- });
203
- const data = await res.json();
204
- return (data.choices?.[0]?.message?.content || 'chore: update files').trim().replace(/^["']|["']$/g, '');
187
+ ], []);
188
+ return (result.content || 'chore: update files').trim().replace(/^["']|["']$/g, '');
189
+ } catch {
190
+ return 'chore: update files';
191
+ }
205
192
  }
206
193
 
207
194
 
208
195
  async function streamMessage(providerConfig, messages, tools) {
209
- const endpoint = `${providerConfig.url}/chat/completions`;
210
- const body = {
211
- model: providerConfig.model,
212
- messages,
213
- tools,
214
- tool_choice: 'auto',
215
- temperature: 0.7,
216
- max_tokens: 4000,
217
- stream: true,
218
- };
219
-
220
- const response = await fetch(endpoint, {
221
- method: 'POST',
222
- headers: {
223
- 'Authorization': `Bearer ${providerConfig.apiKey}`,
224
- 'Content-Type': 'application/json',
225
- },
226
- body: JSON.stringify(body),
227
- });
228
-
229
- if (!response.ok) {
230
- const err = await response.text();
231
- throw new Error(`API error: ${response.status} — ${err}`);
232
- }
233
-
234
- const reader = response.body.getReader();
235
- const decoder = new TextDecoder();
236
- let fullText = '';
237
- let toolCallsBuffer = {};
238
-
239
- process.stdout.write('\n');
240
-
241
- while (true) {
242
- const { done, value } = await reader.read();
243
- if (done) break;
244
- const chunk = decoder.decode(value);
245
- const lines = chunk.split('\n').filter(l => l.startsWith('data: '));
246
- for (const line of lines) {
247
- const data = line.slice(6).trim();
248
- if (data === '[DONE]') continue;
249
- try {
250
- const json = JSON.parse(data);
251
- const delta = json.choices?.[0]?.delta;
252
- if (!delta) continue;
253
- if (delta.content) { process.stdout.write(delta.content); fullText += delta.content; }
254
- if (delta.tool_calls) {
255
- for (const tc of delta.tool_calls) {
256
- const idx = tc.index ?? 0;
257
- if (!toolCallsBuffer[idx]) {
258
- toolCallsBuffer[idx] = { id: '', name: '', arguments: '' };
259
- }
260
- if (tc.id != null) {
261
- toolCallsBuffer[idx].id = tc.id;
262
- }
263
- // OpenAI format: tc.function.name / tc.function.arguments
264
- if (tc.function) {
265
- if (tc.function.name != null) toolCallsBuffer[idx].name += tc.function.name;
266
- if (tc.function.arguments != null) toolCallsBuffer[idx].arguments += tc.function.arguments;
267
- }
268
- // Alternate format (llama-4-scout etc.): tc.name / tc.arguments directly
269
- if (tc.name != null) toolCallsBuffer[idx].name += tc.name;
270
- if (tc.arguments != null) toolCallsBuffer[idx].arguments += tc.arguments;
271
- }
272
- }
273
- } catch {}
274
- }
196
+ const result = await streamProviderCompletion(providerConfig, messages, tools);
197
+ if (result.type === 'text') {
198
+ return { text: result.content, toolCalls: [] };
275
199
  }
276
-
277
- process.stdout.write('\n');
278
-
279
- const toolCalls = Object.values(toolCallsBuffer)
280
- .filter(tc => tc.name)
281
- .map(tc => ({
282
- id: tc.id,
283
- name: tc.name,
284
- input: (() => { try { return JSON.parse(tc.arguments); } catch { return {}; } })(),
285
- }));
286
-
287
- return { text: fullText, toolCalls };
200
+ const toolCalls = result.message.tool_calls.map(tc => ({
201
+ id: tc.id,
202
+ name: tc.function.name,
203
+ input: (() => { try { return JSON.parse(tc.function.arguments); } catch { return {}; } })(),
204
+ }));
205
+ return { text: result.message.content || '', toolCalls };
288
206
  }
289
207
 
290
208
  // ── Tool execution ────────────────────────────────────────────────────────────
package/src/utils/api.js CHANGED
@@ -599,13 +599,23 @@ async function sendMessageToProvider(apiKey, message, conversationId = null, sys
599
599
  : await sendMessageOpenAICompatible(providerConfig, messages, tools);
600
600
  }
601
601
 
602
- debugLog('[Provider] Response type:', assistantMessage.tool_calls ? 'tool_calls' : 'text');
602
+ if (!assistantMessage) {
603
+ return {
604
+ reply: 'No response from provider',
605
+ conversation_id: convId,
606
+ message_id: `msg_${Date.now()}`,
607
+ success: false
608
+ };
609
+ }
610
+
611
+ debugLog('[Provider] Response type:', assistantMessage?.tool_calls ? 'tool_calls' : 'text');
603
612
 
604
613
  // Add assistant message to history
605
614
  messages.push(assistantMessage);
606
615
 
607
616
  // Check for tool calls
608
- if (assistantMessage.tool_calls && assistantMessage.tool_calls.length > 0) {
617
+ const hasToolCalls = assistantMessage?.tool_calls?.length > 0;
618
+ if (hasToolCalls) {
609
619
  debugLog(`[Provider] Tool calls: ${assistantMessage.tool_calls.length}`);
610
620
 
611
621
  // Separate local and MCP tool calls
@@ -666,7 +676,7 @@ async function sendMessageToProvider(apiKey, message, conversationId = null, sys
666
676
  }
667
677
 
668
678
  // No tool calls, we have final response
669
- finalResponse = assistantMessage.content;
679
+ finalResponse = assistantMessage?.content;
670
680
  break;
671
681
  }
672
682