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.
@@ -1,117 +1,117 @@
1
- /**
2
- * supermemory-memory.js — Supermemory memory provider
3
- *
4
- * Uses the supermemory npm package.
5
- * Requires SUPERMEMORY_API_KEY env var or config.supermemory.apiKey.
6
- * npm install supermemory
7
- */
8
-
9
- const { MemoryProvider, registerProvider } = require('../utils/memory-provider');
10
-
11
- class SupermemoryMemoryProvider extends MemoryProvider {
12
- constructor(config = {}) {
13
- super(config);
14
- this.name = 'supermemory';
15
- this._client = null;
16
- }
17
-
18
- _getConfig() {
19
- return this.config.supermemory || this.config.Supermemory || {};
20
- }
21
-
22
- _apiKey() {
23
- return process.env.SUPERMEMORY_API_KEY || this._getConfig().apiKey || '';
24
- }
25
-
26
- async _ensureClient() {
27
- if (this._client) return;
28
- try {
29
- const Supermemory = (await import('supermemory')).default;
30
- this._client = new Supermemory({
31
- apiKey: this._apiKey() || undefined,
32
- ...this._getConfig().options,
33
- });
34
- } catch (e) {
35
- throw new Error('supermemory paketi yuklu degil. npm install supermemory');
36
- }
37
- }
38
-
39
- async add(userId, content, metadata = {}) {
40
- await this._ensureClient();
41
- const tag = `user_${(userId || 'default').toLowerCase()}`;
42
- await this._client.add({
43
- content,
44
- containerTags: [tag],
45
- ...metadata,
46
- });
47
- return { success: true, id: content, message: 'Supermemory added', provider: 'supermemory' };
48
- }
49
-
50
- async search(query, options = {}) {
51
- await this._ensureClient();
52
- const tag = options.userId ? `user_${options.userId.toLowerCase()}` : undefined;
53
- try {
54
- const response = await this._client.search.documents({
55
- q: query,
56
- ...(tag ? { containerTags: [tag] } : {}),
57
- limit: options.limit || 10,
58
- });
59
- return {
60
- success: true,
61
- results: (response.results || []).map(r => ({
62
- id: r.id,
63
- content: r.content || '',
64
- score: r.score || 0,
65
- metadata: r.metadata || {},
66
- })),
67
- };
68
- } catch (e) {
69
- return { success: false, error: e.message, results: [] };
70
- }
71
- }
72
-
73
- async list(userId) {
74
- await this._ensureClient();
75
- const tag = `user_${(userId || 'default').toLowerCase()}`;
76
- try {
77
- const docs = await this._client.documents.list({ containerTags: [tag] });
78
- return {
79
- success: true,
80
- memories: (docs.results || docs || []).map(r => ({
81
- id: r.id,
82
- content: r.content || '',
83
- score: 0,
84
- metadata: r.metadata || {},
85
- })),
86
- };
87
- } catch (e) {
88
- return { success: false, error: e.message, memories: [] };
89
- }
90
- }
91
-
92
- async remove(id) {
93
- await this._ensureClient();
94
- try {
95
- await this._client.documents.delete({ docId: id });
96
- return { success: true, message: 'Supermemory removed' };
97
- } catch (e) {
98
- return { success: false, error: e.message };
99
- }
100
- }
101
-
102
- async clear(userId) {
103
- const tag = `user_${(userId || 'default').toLowerCase()}`;
104
- try {
105
- const listed = await this.list(userId);
106
- for (const mem of listed.memories || []) {
107
- try { await this.remove(mem.id); } catch {}
108
- }
109
- return { success: true, message: `Supermemory cleared for ${tag}` };
110
- } catch (e) {
111
- return { success: false, error: e.message };
112
- }
113
- }
114
- }
115
-
116
- registerProvider('supermemory', SupermemoryMemoryProvider);
117
- module.exports = SupermemoryMemoryProvider;
1
+ /**
2
+ * supermemory-memory.js — Supermemory memory provider
3
+ *
4
+ * Uses the supermemory npm package.
5
+ * Requires SUPERMEMORY_API_KEY env var or config.supermemory.apiKey.
6
+ * npm install supermemory
7
+ */
8
+
9
+ const { MemoryProvider, registerProvider } = require('../utils/memory-provider');
10
+
11
+ class SupermemoryMemoryProvider extends MemoryProvider {
12
+ constructor(config = {}) {
13
+ super(config);
14
+ this.name = 'supermemory';
15
+ this._client = null;
16
+ }
17
+
18
+ _getConfig() {
19
+ return this.config.supermemory || this.config.Supermemory || {};
20
+ }
21
+
22
+ _apiKey() {
23
+ return process.env.SUPERMEMORY_API_KEY || this._getConfig().apiKey || '';
24
+ }
25
+
26
+ async _ensureClient() {
27
+ if (this._client) return;
28
+ try {
29
+ const Supermemory = (await import('supermemory')).default;
30
+ this._client = new Supermemory({
31
+ apiKey: this._apiKey() || undefined,
32
+ ...this._getConfig().options,
33
+ });
34
+ } catch (e) {
35
+ throw new Error('supermemory paketi yuklu degil. npm install supermemory', { cause: e });
36
+ }
37
+ }
38
+
39
+ async add(userId, content, metadata = {}) {
40
+ await this._ensureClient();
41
+ const tag = `user_${(userId || 'default').toLowerCase()}`;
42
+ await this._client.add({
43
+ content,
44
+ containerTags: [tag],
45
+ ...metadata,
46
+ });
47
+ return { success: true, id: content, message: 'Supermemory added', provider: 'supermemory' };
48
+ }
49
+
50
+ async search(query, options = {}) {
51
+ await this._ensureClient();
52
+ const tag = options.userId ? `user_${options.userId.toLowerCase()}` : undefined;
53
+ try {
54
+ const response = await this._client.search.documents({
55
+ q: query,
56
+ ...(tag ? { containerTags: [tag] } : {}),
57
+ limit: options.limit || 10,
58
+ });
59
+ return {
60
+ success: true,
61
+ results: (response.results || []).map(r => ({
62
+ id: r.id,
63
+ content: r.content || '',
64
+ score: r.score || 0,
65
+ metadata: r.metadata || {},
66
+ })),
67
+ };
68
+ } catch (e) {
69
+ return { success: false, error: e.message, results: [] };
70
+ }
71
+ }
72
+
73
+ async list(userId) {
74
+ await this._ensureClient();
75
+ const tag = `user_${(userId || 'default').toLowerCase()}`;
76
+ try {
77
+ const docs = await this._client.documents.list({ containerTags: [tag] });
78
+ return {
79
+ success: true,
80
+ memories: (docs.results || docs || []).map(r => ({
81
+ id: r.id,
82
+ content: r.content || '',
83
+ score: 0,
84
+ metadata: r.metadata || {},
85
+ })),
86
+ };
87
+ } catch (e) {
88
+ return { success: false, error: e.message, memories: [] };
89
+ }
90
+ }
91
+
92
+ async remove(id) {
93
+ await this._ensureClient();
94
+ try {
95
+ await this._client.documents.delete({ docId: id });
96
+ return { success: true, message: 'Supermemory removed' };
97
+ } catch (e) {
98
+ return { success: false, error: e.message };
99
+ }
100
+ }
101
+
102
+ async clear(userId) {
103
+ const tag = `user_${(userId || 'default').toLowerCase()}`;
104
+ try {
105
+ const listed = await this.list(userId);
106
+ for (const mem of listed.memories || []) {
107
+ try { await this.remove(mem.id); } catch {}
108
+ }
109
+ return { success: true, message: `Supermemory cleared for ${tag}` };
110
+ } catch (e) {
111
+ return { success: false, error: e.message };
112
+ }
113
+ }
114
+ }
115
+
116
+ registerProvider('supermemory', SupermemoryMemoryProvider);
117
+ module.exports = SupermemoryMemoryProvider;
@@ -1,163 +1,150 @@
1
- const { getConfig } = require('../utils/config');
2
-
3
- function stripCodeFences(s) {
4
- const m = s.trim().match(/^```(?:json)?\s*([\s\S]*?)\s*```$/i);
5
- if (m) return (m[1] || '').trim();
6
- return s.trim();
7
- }
8
-
9
- function validateAgainstSchema(value, schema) {
10
- if (!schema || typeof schema !== 'object') return { ok: true };
11
- if (schema.type === 'object' && schema.properties) {
12
- if (typeof value !== 'object' || Array.isArray(value)) return { ok: false, errors: [{ text: 'expected object' }] };
13
- const errors = [];
14
- for (const [key, prop] of Object.entries(schema.properties)) {
15
- if (prop.type && value[key] !== undefined) {
16
- const actual = typeof value[key];
17
- if (actual !== prop.type && !(prop.type === 'number' && actual === 'integer')) {
18
- errors.push({ text: `${key}: expected ${prop.type}, got ${actual}` });
19
- }
20
- }
21
- if (prop.required && value[key] === undefined) {
22
- errors.push({ text: `${key}: required but missing` });
23
- }
24
- }
25
- return errors.length ? { ok: false, errors } : { ok: true };
26
- }
27
- return { ok: true };
28
- }
29
-
30
- module.exports = {
31
- name: 'llm_task',
32
- description: 'Run a generic JSON-only LLM task and return schema-validated JSON. No tool calls, no commentary.',
33
- inputSchema: {
34
- type: 'object',
35
- properties: {
36
- prompt: { type: 'string', description: 'Task instruction for the LLM' },
37
- input: { type: 'object', description: 'Optional input payload for the task' },
38
- schema: { type: 'object', description: 'Optional JSON Schema to validate the returned JSON' },
39
- provider: { type: 'string', description: 'Provider override (e.g. openai, anthropic)' },
40
- model: { type: 'string', description: 'Model override' },
41
- // LLM'ler JSON'da sayıları string olarak dönebiliyor — esnek schema
42
- temperature: { type: ['number', 'string'], description: 'Temperature override' },
43
- maxTokens: { type: ['number', 'string'], description: 'Max tokens override' }
44
- },
45
- required: ['prompt']
46
- },
47
-
48
- async execute(params) {
49
- try {
50
- const config = getConfig();
51
- const provider = params.provider || config.provider || 'openai';
52
- let model = params.model || config.model || 'gpt-4o';
53
-
54
- // LLM'ler sayıları string olarak dönebiliyor — cast et
55
- const temperature = typeof params.temperature === 'string' ? parseFloat(params.temperature) : (params.temperature ?? 0.1);
56
- const maxTokens = typeof params.maxTokens === 'string' ? parseInt(params.maxTokens, 10) : (params.maxTokens ?? 4096);
57
-
58
- let apiKey;
59
- if (provider === 'openai') apiKey = params.apiKey || config.openaiApiKey || config.providerApiKey || process.env.OPENAI_API_KEY;
60
- else if (provider === 'anthropic') apiKey = params.apiKey || config.anthropicApiKey || config.providerApiKey || process.env.ANTHROPIC_API_KEY;
61
- else if (provider === 'groq') apiKey = params.apiKey || config.groqApiKey || config.providerApiKey || process.env.GROQ_API_KEY;
62
- else if (provider === 'together' || provider === 'openrouter') {
63
- apiKey = params.apiKey || config.providerApiKey;
64
- } else {
65
- apiKey = config.providerApiKey || params.apiKey;
66
- }
67
-
68
- if (!apiKey) {
69
- return { success: false, error: `API key required for ${provider}. Set: natureco config set ${provider}ApiKey <key> veya providerApiKey` };
70
- }
71
-
72
- // Provider URL ve model için config'deki varsayılanları kullan
73
- if (config.providerUrl && provider === 'openai' && !params.provider) {
74
- const url = config.providerUrl;
75
- const isGM = url.includes('generativelanguage.googleapis.com') || url.includes('gemini');
76
- if (isGM) {
77
- baseUrl = url.replace(/\/+$/, '') + '/openai';
78
- }
79
- }
80
- if (config.providerModel && provider === 'openai' && !params.model) {
81
- model = config.providerModel;
82
- }
83
-
84
- const systemPrompt = [
85
- 'You are a JSON-only function.',
86
- 'Return ONLY a valid JSON value.',
87
- 'Do not wrap in markdown fences.',
88
- 'Do not include commentary.',
89
- 'Do not call tools.'
90
- ].join(' ');
91
-
92
- const inputJson = JSON.stringify(params.input ?? null, null, 2);
93
- const fullPrompt = `${systemPrompt}\n\nTASK:\n${params.prompt}\n\nINPUT:\n${inputJson}\n`;
94
-
95
- // Provider URL'ini config'ten al (Groq, MiniMax, OpenRouter için)
96
- let baseUrl = provider === 'openai' ? 'https://api.openai.com/v1' : `https://api.${provider}.com/v1`;
97
- if (provider === 'groq') baseUrl = config.providerUrl || 'https://api.groq.com/openai/v1';
98
- if (provider === 'openrouter') baseUrl = 'https://openrouter.ai/api/v1';
99
- // MiniMax özel endpoint: /v1/text/chatcompletion_v2 (OpenAI uyumlu DEĞİL)
100
- if (provider === 'minimax') {
101
- baseUrl = config.providerUrl || 'https://api.minimax.io';
102
- }
103
-
104
- // MiniMax özel mi, OpenAI uyumlu mu?
105
- const isMiniMax = provider === 'minimax' || baseUrl.includes('minimax.io') || baseUrl.includes('minimaxi.com');
106
- const endpoint = isMiniMax
107
- ? `${baseUrl}/v1/text/chatcompletion_v2`
108
- : `${baseUrl}/chat/completions`;
109
-
110
- // MiniMax özel request format
111
- const requestBody = isMiniMax
112
- ? {
113
- model,
114
- messages: [{ role: 'user', content: fullPrompt }],
115
- temperature,
116
- max_tokens: maxTokens,
117
- }
118
- : {
119
- model,
120
- messages: [{ role: 'user', content: fullPrompt }],
121
- temperature,
122
- max_tokens: maxTokens
123
- };
124
-
125
- const response = await fetch(endpoint, {
126
- method: 'POST',
127
- headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${apiKey}` },
128
- body: JSON.stringify(requestBody)
129
- });
130
-
131
- if (!response.ok) {
132
- return { success: false, error: `${provider} error ${response.status}: ${await response.text()}` };
133
- }
134
-
135
- const data = await response.json();
136
- // MiniMax response format: choices[0].message.content (OpenAI ile aynı)
137
- const text = data.choices?.[0]?.message?.content?.trim();
138
- if (!text) return { success: false, error: 'LLM returned empty output' };
139
-
140
- const raw = stripCodeFences(text);
141
- let parsed;
142
- try { parsed = JSON.parse(raw); }
143
- catch { return { success: false, error: 'LLM returned invalid JSON', raw: text }; }
144
-
145
- const schema = params.schema;
146
- if (schema && typeof schema === 'object') {
147
- const validation = validateAgainstSchema(parsed, schema);
148
- if (!validation.ok) {
149
- return {
150
- success: false,
151
- error: `JSON did not match schema: ${validation.errors.map(e => e.text).join('; ')}`,
152
- raw: text,
153
- parsed
154
- };
155
- }
156
- }
157
-
158
- return { success: true, data: parsed, provider, model };
159
- } catch (error) {
160
- return { success: false, error: error.message };
161
- }
162
- }
163
- };
1
+ const { getConfig } = require('../utils/config');
2
+
3
+ function stripCodeFences(s) {
4
+ const m = s.trim().match(/^```(?:json)?\s*([\s\S]*?)\s*```$/i);
5
+ if (m) return (m[1] || '').trim();
6
+ return s.trim();
7
+ }
8
+
9
+ function validateAgainstSchema(value, schema) {
10
+ if (!schema || typeof schema !== 'object') return { ok: true };
11
+ if (schema.type === 'object' && schema.properties) {
12
+ if (typeof value !== 'object' || Array.isArray(value)) return { ok: false, errors: [{ text: 'expected object' }] };
13
+ const errors = [];
14
+ for (const [key, prop] of Object.entries(schema.properties)) {
15
+ if (prop.type && value[key] !== undefined) {
16
+ const actual = typeof value[key];
17
+ if (actual !== prop.type && !(prop.type === 'number' && actual === 'integer')) {
18
+ errors.push({ text: `${key}: expected ${prop.type}, got ${actual}` });
19
+ }
20
+ }
21
+ if (prop.required && value[key] === undefined) {
22
+ errors.push({ text: `${key}: required but missing` });
23
+ }
24
+ }
25
+ return errors.length ? { ok: false, errors } : { ok: true };
26
+ }
27
+ return { ok: true };
28
+ }
29
+
30
+ module.exports = {
31
+ name: 'llm_task',
32
+ description: 'Run a generic JSON-only LLM task and return schema-validated JSON. No tool calls, no commentary.',
33
+ inputSchema: {
34
+ type: 'object',
35
+ properties: {
36
+ prompt: { type: 'string', description: 'Task instruction for the LLM' },
37
+ input: { type: 'object', description: 'Optional input payload for the task' },
38
+ schema: { type: 'object', description: 'Optional JSON Schema to validate the returned JSON' },
39
+ provider: { type: 'string', description: 'Provider override (e.g. openai, anthropic)' },
40
+ model: { type: 'string', description: 'Model override' },
41
+ // LLM'ler JSON'da sayıları string olarak dönebiliyor — esnek schema
42
+ temperature: { type: ['number', 'string'], description: 'Temperature override' },
43
+ maxTokens: { type: ['number', 'string'], description: 'Max tokens override' }
44
+ },
45
+ required: ['prompt']
46
+ },
47
+
48
+ async execute(params) {
49
+ try {
50
+ const config = getConfig();
51
+ const provider = params.provider || config.provider || 'openai';
52
+ const model = params.model || config.model || 'gpt-4o';
53
+
54
+ // LLM'ler sayıları string olarak dönebiliyor — cast et
55
+ const temperature = typeof params.temperature === 'string' ? parseFloat(params.temperature) : (params.temperature ?? 0.1);
56
+ const maxTokens = typeof params.maxTokens === 'string' ? parseInt(params.maxTokens, 10) : (params.maxTokens ?? 4096);
57
+
58
+ let apiKey;
59
+ if (provider === 'openai') apiKey = params.apiKey || config.openaiApiKey || process.env.OPENAI_API_KEY;
60
+ else if (provider === 'anthropic') apiKey = params.apiKey || config.anthropicApiKey || process.env.ANTHROPIC_API_KEY;
61
+ else if (provider === 'groq') apiKey = params.apiKey || config.groqApiKey || process.env.GROQ_API_KEY;
62
+ else if (provider === 'groq' || provider === 'together' || provider === 'openrouter') {
63
+ // Yeni provider presetler için ana providerApiKey'i kullan
64
+ apiKey = config.providerApiKey;
65
+ }
66
+
67
+ if (!apiKey) {
68
+ return { success: false, error: `API key required for ${provider}. Set: natureco config set ${provider}ApiKey <key> veya providerApiKey` };
69
+ }
70
+
71
+ const systemPrompt = [
72
+ 'You are a JSON-only function.',
73
+ 'Return ONLY a valid JSON value.',
74
+ 'Do not wrap in markdown fences.',
75
+ 'Do not include commentary.',
76
+ 'Do not call tools.'
77
+ ].join(' ');
78
+
79
+ const inputJson = JSON.stringify(params.input ?? null, null, 2);
80
+ const fullPrompt = `${systemPrompt}\n\nTASK:\n${params.prompt}\n\nINPUT:\n${inputJson}\n`;
81
+
82
+ // Provider URL'ini config'ten al (Groq, MiniMax, OpenRouter için)
83
+ let baseUrl = provider === 'openai' ? 'https://api.openai.com/v1' : `https://api.${provider}.com/v1`;
84
+ if (provider === 'groq') baseUrl = config.providerUrl || 'https://api.groq.com/openai/v1';
85
+ if (provider === 'openrouter') baseUrl = 'https://openrouter.ai/api/v1';
86
+ // MiniMax özel endpoint: /v1/text/chatcompletion_v2 (OpenAI uyumlu DEĞİL)
87
+ if (provider === 'minimax') {
88
+ baseUrl = config.providerUrl || 'https://api.minimax.io';
89
+ }
90
+
91
+ // MiniMax özel mi, OpenAI uyumlu mu?
92
+ const isMiniMax = provider === 'minimax' || baseUrl.includes('minimax.io') || baseUrl.includes('minimaxi.com');
93
+ const endpoint = isMiniMax
94
+ ? `${baseUrl}/v1/text/chatcompletion_v2`
95
+ : `${baseUrl}/chat/completions`;
96
+
97
+ // MiniMax özel request format
98
+ const requestBody = isMiniMax
99
+ ? {
100
+ model,
101
+ messages: [{ role: 'user', content: fullPrompt }],
102
+ temperature,
103
+ max_tokens: maxTokens,
104
+ }
105
+ : {
106
+ model,
107
+ messages: [{ role: 'user', content: fullPrompt }],
108
+ temperature,
109
+ max_tokens: maxTokens
110
+ };
111
+
112
+ const response = await fetch(endpoint, {
113
+ method: 'POST',
114
+ headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${apiKey}` },
115
+ body: JSON.stringify(requestBody)
116
+ });
117
+
118
+ if (!response.ok) {
119
+ return { success: false, error: `${provider} error ${response.status}: ${await response.text()}` };
120
+ }
121
+
122
+ const data = await response.json();
123
+ // MiniMax response format: choices[0].message.content (OpenAI ile aynı)
124
+ const text = data.choices?.[0]?.message?.content?.trim();
125
+ if (!text) return { success: false, error: 'LLM returned empty output' };
126
+
127
+ const raw = stripCodeFences(text);
128
+ let parsed;
129
+ try { parsed = JSON.parse(raw); }
130
+ catch { return { success: false, error: 'LLM returned invalid JSON', raw: text }; }
131
+
132
+ const schema = params.schema;
133
+ if (schema && typeof schema === 'object') {
134
+ const validation = validateAgainstSchema(parsed, schema);
135
+ if (!validation.ok) {
136
+ return {
137
+ success: false,
138
+ error: `JSON did not match schema: ${validation.errors.map(e => e.text).join('; ')}`,
139
+ raw: text,
140
+ parsed
141
+ };
142
+ }
143
+ }
144
+
145
+ return { success: true, data: parsed, provider, model };
146
+ } catch (error) {
147
+ return { success: false, error: error.message };
148
+ }
149
+ }
150
+ };