modelmix 5.1.1 → 5.1.2
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/README.md +2 -2
- package/demo/free.js +2 -3
- package/effort.js +0 -1
- package/index.js +513 -2847
- package/lib/content-cache.js +31 -0
- package/lib/model-chain.js +51 -0
- package/lib/object-utils.js +7 -0
- package/lib/provider-debug.js +23 -0
- package/lib/providers/anthropic.js +337 -0
- package/lib/providers/base.js +409 -0
- package/lib/providers/google.js +293 -0
- package/lib/providers/openai-compatible.js +338 -0
- package/lib/providers/openai.js +622 -0
- package/lib/providers.js +26 -0
- package/lib/template-engine.js +168 -0
- package/lib/token-usage.js +299 -0
- package/package.json +1 -1
- package/skills/modelmix/SKILL.md +2 -2
- package/test/effort.test.js +20 -0
- package/test/model-chain.test.js +12 -0
- package/test/public-api.test.js +54 -0
- package/test/tokens.test.js +20 -0
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
const {
|
|
2
|
+
GROK420_REASONING,
|
|
3
|
+
GROK420_NON_REASONING
|
|
4
|
+
} = require('../../effort');
|
|
5
|
+
|
|
6
|
+
function createCompatibleProviders({ MixCustom, MixOpenAI }) {
|
|
7
|
+
class MixMiniMax extends MixOpenAI {
|
|
8
|
+
getDefaultConfig(customConfig) {
|
|
9
|
+
|
|
10
|
+
if (!process.env.MINIMAX_API_KEY) {
|
|
11
|
+
throw new Error('MiniMax API key not found. Please provide it in config or set MINIMAX_API_KEY environment variable.');
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return MixCustom.prototype.getDefaultConfig.call(this, {
|
|
15
|
+
url: 'https://api.minimax.io/v1/chat/completions',
|
|
16
|
+
apiKey: process.env.MINIMAX_API_KEY,
|
|
17
|
+
...customConfig
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
extractDelta(data) {
|
|
22
|
+
// MiniMax might send different formats during streaming
|
|
23
|
+
if (data.choices && data.choices[0] && data.choices[0].delta && data.choices[0].delta.content) {
|
|
24
|
+
return data.choices[0].delta.content;
|
|
25
|
+
}
|
|
26
|
+
return '';
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
class MixMiMo extends MixOpenAI {
|
|
31
|
+
getDefaultConfig(customConfig) {
|
|
32
|
+
if (!process.env.MIMO_API_KEY) {
|
|
33
|
+
throw new Error('MiMo API key not found. Please provide it in config or set MIMO_API_KEY environment variable.');
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return MixCustom.prototype.getDefaultConfig.call(this, {
|
|
37
|
+
url: 'https://api.xiaomimimo.com/v1/chat/completions',
|
|
38
|
+
apiKey: process.env.MIMO_API_KEY,
|
|
39
|
+
...customConfig
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
getDefaultHeaders(customHeaders) {
|
|
44
|
+
return {
|
|
45
|
+
'accept': 'application/json',
|
|
46
|
+
'content-type': 'application/json',
|
|
47
|
+
'api-key': this.config.apiKey,
|
|
48
|
+
...customHeaders
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
class MixPerplexity extends MixCustom {
|
|
54
|
+
getDefaultConfig(customConfig) {
|
|
55
|
+
|
|
56
|
+
if (!process.env.PPLX_API_KEY) {
|
|
57
|
+
throw new Error('Perplexity API key not found. Please provide it in config or set PPLX_API_KEY environment variable.');
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return super.getDefaultConfig({
|
|
61
|
+
url: 'https://api.perplexity.ai/chat/completions',
|
|
62
|
+
apiKey: process.env.PPLX_API_KEY,
|
|
63
|
+
...customConfig
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async create({ config = {}, options = {} } = {}) {
|
|
68
|
+
|
|
69
|
+
if (config.schema) {
|
|
70
|
+
options.response_format = {
|
|
71
|
+
type: 'json_schema',
|
|
72
|
+
json_schema: { schema: config.schema }
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return super.create({ config, options });
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
class MixOllama extends MixCustom {
|
|
81
|
+
|
|
82
|
+
getDefaultConfig(customConfig) {
|
|
83
|
+
return super.getDefaultConfig({
|
|
84
|
+
url: 'http://localhost:11434/api/chat',
|
|
85
|
+
...customConfig
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
getDefaultOptions(customOptions) {
|
|
90
|
+
return {
|
|
91
|
+
options: customOptions,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
extractDelta(data) {
|
|
96
|
+
if (data.message && data.message.content) return data.message.content;
|
|
97
|
+
return '';
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
extractMessage(data) {
|
|
101
|
+
return data.message.content.trim();
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
convertMessages(messages, config) {
|
|
105
|
+
return MixOllama.convertMessages(messages, config);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
static convertMessages(messages, config) {
|
|
109
|
+
const content = config.system;
|
|
110
|
+
messages = [{ role: 'system', content }, ...messages || []];
|
|
111
|
+
|
|
112
|
+
return messages.map(entry => {
|
|
113
|
+
let content = '';
|
|
114
|
+
let images = [];
|
|
115
|
+
|
|
116
|
+
entry.content.forEach(item => {
|
|
117
|
+
if (item.type === 'text') {
|
|
118
|
+
content += item.text + ' ';
|
|
119
|
+
} else if (item.type === 'image') {
|
|
120
|
+
images.push(item.source.data);
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
return {
|
|
125
|
+
role: entry.role,
|
|
126
|
+
content: content.trim(),
|
|
127
|
+
images: images
|
|
128
|
+
};
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
class MixGrok extends MixOpenAI {
|
|
134
|
+
getDefaultConfig(customConfig) {
|
|
135
|
+
|
|
136
|
+
if (!process.env.XAI_API_KEY) {
|
|
137
|
+
throw new Error('Grok API key not found. Please provide it in config or set XAI_API_KEY environment variable.');
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return super.getDefaultConfig({
|
|
141
|
+
url: 'https://api.x.ai/v1/chat/completions',
|
|
142
|
+
apiKey: process.env.XAI_API_KEY,
|
|
143
|
+
...customConfig
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
async create({ config = {}, options = {} } = {}) {
|
|
148
|
+
if (options.model === GROK420_REASONING || options.model === GROK420_NON_REASONING) {
|
|
149
|
+
delete options.reasoning_effort;
|
|
150
|
+
}
|
|
151
|
+
return super.create({ config, options });
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
class MixLambda extends MixCustom {
|
|
156
|
+
getDefaultConfig(customConfig) {
|
|
157
|
+
|
|
158
|
+
if (!process.env.LAMBDA_API_KEY) {
|
|
159
|
+
throw new Error('Lambda API key not found. Please provide it in config or set LAMBDA_API_KEY environment variable.');
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return super.getDefaultConfig({
|
|
163
|
+
url: 'https://api.lambda.ai/v1/chat/completions',
|
|
164
|
+
apiKey: process.env.LAMBDA_API_KEY,
|
|
165
|
+
...customConfig
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
class MixLMStudio extends MixCustom {
|
|
171
|
+
getDefaultConfig(customConfig) {
|
|
172
|
+
return super.getDefaultConfig({
|
|
173
|
+
url: 'http://localhost:1234/v1/chat/completions',
|
|
174
|
+
...customConfig
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
create({ config = {}, options = {} } = {}) {
|
|
179
|
+
if (config.schema) {
|
|
180
|
+
options.response_format = {
|
|
181
|
+
type: 'json_schema',
|
|
182
|
+
json_schema: { schema: config.schema }
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
return super.create({ config, options });
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
static extractThink(data) {
|
|
189
|
+
const message = data.choices[0].message?.content?.trim() || '';
|
|
190
|
+
|
|
191
|
+
// Check for LMStudio special tags
|
|
192
|
+
const startTag = '<|channel|>analysis<|message|>';
|
|
193
|
+
const endTag = '<|end|><|start|>assistant<|channel|>final<|message|>';
|
|
194
|
+
|
|
195
|
+
const startIndex = message.indexOf(startTag);
|
|
196
|
+
const endIndex = message.indexOf(endTag);
|
|
197
|
+
|
|
198
|
+
if (startIndex !== -1 && endIndex !== -1) {
|
|
199
|
+
// Extract content between the special tags
|
|
200
|
+
const thinkContent = message.substring(startIndex + startTag.length, endIndex).trim();
|
|
201
|
+
return thinkContent;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// Fall back to default extraction method
|
|
205
|
+
return MixCustom.extractThink(data);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
static extractMessage(data) {
|
|
209
|
+
const message = data.choices[0].message?.content?.trim() || '';
|
|
210
|
+
|
|
211
|
+
// Check for LMStudio special tags and extract final message
|
|
212
|
+
const endTag = '<|end|><|start|>assistant<|channel|>final<|message|>';
|
|
213
|
+
const endIndex = message.indexOf(endTag);
|
|
214
|
+
|
|
215
|
+
if (endIndex !== -1) {
|
|
216
|
+
// Return only the content after the final message tag
|
|
217
|
+
return message.substring(endIndex + endTag.length).trim();
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// Fall back to default extraction method
|
|
221
|
+
return MixCustom.extractMessage(data);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
processResponse(response) {
|
|
225
|
+
return {
|
|
226
|
+
message: MixLMStudio.extractMessage(response.data),
|
|
227
|
+
think: MixLMStudio.extractThink(response.data),
|
|
228
|
+
toolCalls: MixCustom.extractToolCalls(response.data),
|
|
229
|
+
tokens: MixCustom.extractTokens(response.data),
|
|
230
|
+
response: response.data
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
class MixGroq extends MixCustom {
|
|
236
|
+
getDefaultConfig(customConfig) {
|
|
237
|
+
|
|
238
|
+
if (!process.env.GROQ_API_KEY) {
|
|
239
|
+
throw new Error('Groq API key not found. Please provide it in config or set GROQ_API_KEY environment variable.');
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
return super.getDefaultConfig({
|
|
243
|
+
url: 'https://api.groq.com/openai/v1/chat/completions',
|
|
244
|
+
apiKey: process.env.GROQ_API_KEY,
|
|
245
|
+
...customConfig
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
class MixTogether extends MixCustom {
|
|
251
|
+
getDefaultConfig(customConfig) {
|
|
252
|
+
|
|
253
|
+
if (!process.env.TOGETHER_API_KEY) {
|
|
254
|
+
throw new Error('Together API key not found. Please provide it in config or set TOGETHER_API_KEY environment variable.');
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
return super.getDefaultConfig({
|
|
258
|
+
url: 'https://api.together.xyz/v1/chat/completions',
|
|
259
|
+
apiKey: process.env.TOGETHER_API_KEY,
|
|
260
|
+
...customConfig
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
getDefaultOptions(customOptions) {
|
|
265
|
+
return {
|
|
266
|
+
stop: ["<|eot_id|>", "<|eom_id|>"],
|
|
267
|
+
...customOptions
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
class MixCerebras extends MixCustom {
|
|
273
|
+
getDefaultConfig(customConfig) {
|
|
274
|
+
|
|
275
|
+
if (!process.env.CEREBRAS_API_KEY) {
|
|
276
|
+
throw new Error('Together API key not found. Please provide it in config or set CEREBRAS_API_KEY environment variable.');
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
return super.getDefaultConfig({
|
|
280
|
+
url: 'https://api.cerebras.ai/v1/chat/completions',
|
|
281
|
+
apiKey: process.env.CEREBRAS_API_KEY,
|
|
282
|
+
...customConfig
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
create({ config = {}, options = {} } = {}) {
|
|
287
|
+
delete options.response_format;
|
|
288
|
+
return super.create({ config, options });
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
class MixFireworks extends MixCustom {
|
|
293
|
+
getDefaultConfig(customConfig) {
|
|
294
|
+
|
|
295
|
+
if (!process.env.FIREWORKS_API_KEY) {
|
|
296
|
+
throw new Error('Fireworks API key not found. Please provide it in config or set FIREWORKS_API_KEY environment variable.');
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
return super.getDefaultConfig({
|
|
300
|
+
url: 'https://api.fireworks.ai/inference/v1/chat/completions',
|
|
301
|
+
apiKey: process.env.FIREWORKS_API_KEY,
|
|
302
|
+
...customConfig
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
class MixNVIDIA extends MixCustom {
|
|
308
|
+
getDefaultConfig(customConfig) {
|
|
309
|
+
|
|
310
|
+
if (!process.env.NVIDIA_API_KEY) {
|
|
311
|
+
throw new Error('NVIDIA API key not found. Please provide it in config or set NVIDIA_API_KEY environment variable.');
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
return super.getDefaultConfig({
|
|
315
|
+
url: 'https://integrate.api.nvidia.com/v1/chat/completions',
|
|
316
|
+
apiKey: process.env.NVIDIA_API_KEY,
|
|
317
|
+
...customConfig
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
return {
|
|
323
|
+
MixMiniMax,
|
|
324
|
+
MixMiMo,
|
|
325
|
+
MixPerplexity,
|
|
326
|
+
MixOllama,
|
|
327
|
+
MixGrok,
|
|
328
|
+
MixLambda,
|
|
329
|
+
MixLMStudio,
|
|
330
|
+
MixGroq,
|
|
331
|
+
MixTogether,
|
|
332
|
+
MixCerebras,
|
|
333
|
+
MixFireworks,
|
|
334
|
+
MixNVIDIA
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
module.exports = createCompatibleProviders;
|