natureco-cli 5.20.4 → 5.21.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 +52 -62
- 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 +424 -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 +136 -136
- package/src/utils/tools.js +324 -324
- package/README.md.bak +0 -565
- package/src/tools/http.js.bak +0 -78
|
@@ -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;
|
package/src/tools/llm_task.js
CHANGED
|
@@ -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
|
-
|
|
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 ||
|
|
60
|
-
else if (provider === 'anthropic') apiKey = params.apiKey || config.anthropicApiKey ||
|
|
61
|
-
else if (provider === 'groq') apiKey = params.apiKey || config.groqApiKey ||
|
|
62
|
-
else if (provider === 'together' || provider === 'openrouter') {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
const
|
|
93
|
-
const
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
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
|
+
};
|