modelmix 4.6.14 → 4.7.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/README.md +16 -10
- package/demo/opus5.js +2 -2
- package/demo/short.js +3 -3
- package/demo/stream.js +1 -1
- package/demo/tokens.js +1 -1
- package/effort.js +59 -3
- package/index.d.ts +3 -17
- package/index.js +22 -89
- package/package.json +1 -1
- package/skills/modelmix/SKILL.md +9 -9
- package/test/anthropic.test.js +31 -36
- package/test/effort.test.js +50 -7
- package/test/grok.test.js +1 -0
- package/test/history.test.js +1 -1
- package/test/live.test.js +4 -16
- package/test/qwen.test.js +32 -0
package/README.md
CHANGED
|
@@ -124,7 +124,9 @@ ModelMix.new().effort(-1).minimaxM3().addText('...').message();
|
|
|
124
124
|
| DeepSeek V4 | off | `low`↑ | `high`↑ | `high`↑ | `max`↑ | — |
|
|
125
125
|
| MiniMax M3 | off | adaptive | adaptive | adaptive | adaptive | adaptive |
|
|
126
126
|
|
|
127
|
-
\* Gemini bands: 0–24 / 25–49 / 50–74 / 75–100. DeepSeek `↑` = thinking on; `off` = thinking disabled. MiniMax `off`/`adaptive` = `thinking.disabled` / `thinking.type=adaptive`. Gemini 2.5 maps 0–100 to `thinkingBudget`. `-1` = provider adaptive/dynamic when available, else no-op. Levels clamp to what each model supports.
|
|
127
|
+
\* Gemini bands: 0–24 / 25–49 / 50–74 / 75–100. DeepSeek `↑` = thinking on; `off` = thinking disabled. MiniMax `off`/`adaptive` = `thinking.disabled` / `thinking.type=adaptive`. Gemini 2.5 maps 0–100 to `thinkingBudget`. Anthropic maps adaptive thinking + `output_config.effort` on Claude 5 / Fable / Opus 4.6+ / Sonnet 4.6+; older models (Sonnet 4.5, Haiku 4.5) get `thinking.type=enabled` + `budget_tokens`. `-1` = provider adaptive/dynamic when available, else no-op. Levels clamp to what each model supports.
|
|
128
|
+
|
|
129
|
+
Migration: former Anthropic `*think()` shorthands are removed — use `.effort(100).opus5()` (or any 0–100 / `-1`) instead.
|
|
128
130
|
|
|
129
131
|
## 🔧 Model Context Protocol (MCP) Integration
|
|
130
132
|
|
|
@@ -177,23 +179,25 @@ Here's a comprehensive list of available methods:
|
|
|
177
179
|
| `gpt41mini()` | OpenAI | gpt-4.1-mini | [\$0.40 / \$1.60][1] |
|
|
178
180
|
| `gpt41nano()` | OpenAI | gpt-4.1-nano | [\$0.10 / \$0.40][1] |
|
|
179
181
|
| `gptOss()` | Together | gpt-oss-120B | [\$0.15 / \$0.60][7] |
|
|
180
|
-
| `fable5
|
|
181
|
-
| `opus5
|
|
182
|
-
| `opus48
|
|
183
|
-
| `opus47
|
|
184
|
-
| `opus46
|
|
185
|
-
| `sonnet5
|
|
186
|
-
| `sonnet46
|
|
187
|
-
| `haiku45
|
|
182
|
+
| `fable5()` | Anthropic | claude-fable-5 | [\$10.00 / \$50.00][2] |
|
|
183
|
+
| `opus5()` | Anthropic | claude-opus-5 | [\$5.00 / \$25.00][2] |
|
|
184
|
+
| `opus48()` | Anthropic | claude-opus-4-8 | [\$5.00 / \$25.00][2] |
|
|
185
|
+
| `opus47()` | Anthropic | claude-opus-4-7 | [\$5.00 / \$25.00][2] |
|
|
186
|
+
| `opus46()` | Anthropic | claude-opus-4-6 | [\$5.00 / \$25.00][2] |
|
|
187
|
+
| `sonnet5()` | Anthropic | claude-sonnet-5 | [\$3.00 / \$15.00][2] |
|
|
188
|
+
| `sonnet46()` | Anthropic | claude-sonnet-4-6 | [\$3.00 / \$15.00][2] |
|
|
189
|
+
| `haiku45()` | Anthropic | claude-haiku-4-5-20251001 | [\$1.00 / \$5.00][2] |
|
|
188
190
|
| `gemini31pro()` | Google | gemini-3.1-pro-preview | [\$2.00 / \$12.00][3] |
|
|
189
191
|
| `gemini36flash()` | Google | gemini-3.6-flash | [\$1.50 / \$7.50][3] |
|
|
190
192
|
| `gemini35flash()` | Google | gemini-3.5-flash | [\$0.75 / \$4.50][3] |
|
|
191
193
|
| `gemini31flashLite()`| Google | gemini-3.1-flash-lite-preview | [\$0.25 / \$1.50][3] |
|
|
194
|
+
| `grok45()` | Grok | grok-4.5 | [\$2.00 / \$6.00][6] |
|
|
192
195
|
| `grok43()` | Grok | grok-4.3 | [\$1.25 / \$2.50][6] |
|
|
193
196
|
| `grok420multiAgent()`| Grok | grok-4.20-multi-agent-0309 | [\$1.25 / \$2.50][6] |
|
|
194
197
|
| `grok420[think]()` | Grok | grok-4.20-0309 | [\$1.25 / \$2.50][6] |
|
|
195
|
-
| `grok41[think]()` | Grok | grok-4-1-fast | [\$0.20 / \$0.50][6] |
|
|
196
198
|
| `qwen36plus()` | Fireworks/Together | qwen3p6-plus / Qwen3.6-Plus | [\$0.50 / \$3.00][10] |
|
|
199
|
+
| `qwen37plus()` | Fireworks | models/qwen3p7-plus | [\$0.40 / \$1.60][10] |
|
|
200
|
+
| `qwen38max()` | OpenRouter | qwen/qwen3.8-max | [\$2.00 / \$6.00][12] |
|
|
197
201
|
| `deepseekV4Flash()` | Fireworks | models/deepseek-v4-flash | [\$0.14 / \$0.28][10] |
|
|
198
202
|
| `deepseekV4Pro()` | Fireworks | models/deepseek-v4-pro | [\$1.74 / \$3.48][10] |
|
|
199
203
|
| `GLM52()` | Together | zai-org/GLM-5.2 | [\$1.40 / \$4.40][7] |
|
|
@@ -218,10 +222,12 @@ Here's a comprehensive list of available methods:
|
|
|
218
222
|
[9]: https://platform.minimax.io/docs/api-reference/anthropic-api-compatible-cache#supported-models-and-pricing "MiniMax Pricing"
|
|
219
223
|
[10]: https://fireworks.ai/pricing#serverless-pricing "Fireworks Pricing"
|
|
220
224
|
[11]: https://platform.kimi.ai/docs/guide/kimi-k3-pricing "Kimi K3 Pricing"
|
|
225
|
+
[12]: https://openrouter.ai/qwen/qwen3.8-max "OpenRouter Pricing"
|
|
221
226
|
|
|
222
227
|
Each method accepts optional `options`, `config`, and (for multi-provider methods) `mix` parameters to customize behavior.
|
|
223
228
|
For NVIDIA on DeepSeek V4 Flash/Pro, use `deepseekV4Flash({ mix: { nvidia: true } })` or `deepseekV4Pro({ mix: { nvidia: true } })`.
|
|
224
229
|
For Together on Qwen 3.6 Plus, use `qwen36plus({ mix: { fireworks: false, together: true } })`.
|
|
230
|
+
For OpenRouter on Qwen 3.7 Plus, use `qwen37plus({ mix: { fireworks: false, openrouter: true } })`.
|
|
225
231
|
For OpenRouter instead of Moonshot's native API, use `kimiK3({ mix: { moonshot: false, openrouter: true } })`.
|
|
226
232
|
|
|
227
233
|
```javascript
|
package/demo/opus5.js
CHANGED
|
@@ -15,9 +15,9 @@ opus.addText("Explain quantum entanglement in simple terms.");
|
|
|
15
15
|
const response = await opus.message();
|
|
16
16
|
console.log(response);
|
|
17
17
|
|
|
18
|
-
console.log("\n" + '--------|
|
|
18
|
+
console.log("\n" + '--------| effort(100).opus5() |--------');
|
|
19
19
|
|
|
20
|
-
const opusThink = mmix.new().
|
|
20
|
+
const opusThink = mmix.new().effort(100).opus5();
|
|
21
21
|
opusThink.addText("A bat and a ball cost $1.10 in total. The bat costs $1.00 more than the ball. How much does the ball cost?");
|
|
22
22
|
const thinkResponse = await opusThink.raw();
|
|
23
23
|
console.log(thinkResponse);
|
package/demo/short.js
CHANGED
|
@@ -9,9 +9,9 @@ const setup = {
|
|
|
9
9
|
};
|
|
10
10
|
|
|
11
11
|
const mmix = await ModelMix.new(setup)
|
|
12
|
-
.
|
|
13
|
-
.
|
|
14
|
-
.
|
|
12
|
+
.sonnet46() // (main model) Anthropic claude-sonnet-4-6
|
|
13
|
+
.gpt56luna() // (fallback 1) OpenAI gpt-5.6-luna
|
|
14
|
+
.gemini36flash({ config: { temperature: 0 } }) // (fallback 2) Google gemini-3.6-flash
|
|
15
15
|
.gpt41nano() // (fallback 3) OpenAI gpt-4.1-nano
|
|
16
16
|
.grok43() // (fallback 4) Grok grok-4.3
|
|
17
17
|
.addText("What's your name?");
|
package/demo/stream.js
CHANGED
|
@@ -6,7 +6,7 @@ await ModelMix.new().gpt41nano()
|
|
|
6
6
|
.addText('describe')
|
|
7
7
|
.stream((data) => { console.log(data.message); });
|
|
8
8
|
|
|
9
|
-
await ModelMix.new().
|
|
9
|
+
await ModelMix.new().haiku45()
|
|
10
10
|
.addImageFromUrl('https://pbs.twimg.com/media/F6-GsjraAAADDGy?format=jpg')
|
|
11
11
|
.addText('describe')
|
|
12
12
|
.stream((data) => { console.log(data.message); });
|
package/demo/tokens.js
CHANGED
|
@@ -25,7 +25,7 @@ console.log('-'.repeat(60));
|
|
|
25
25
|
|
|
26
26
|
const providers = [
|
|
27
27
|
{ name: 'OpenAI GPT-5-nano', fn: (m) => m.gpt5nano() },
|
|
28
|
-
{ name: 'Anthropic Haiku', fn: (m) => m.
|
|
28
|
+
{ name: 'Anthropic Haiku', fn: (m) => m.haiku45() },
|
|
29
29
|
{ name: 'Google Gemini', fn: (m) => m.gemini25flash() }
|
|
30
30
|
];
|
|
31
31
|
|
package/effort.js
CHANGED
|
@@ -170,6 +170,62 @@ function isMiniMax(modelKey) {
|
|
|
170
170
|
return typeof modelKey === 'string' && modelKey.toLowerCase().includes('minimax');
|
|
171
171
|
}
|
|
172
172
|
|
|
173
|
+
/** Max budget_tokens when mapping unified effort onto manual Anthropic thinking. */
|
|
174
|
+
const ANTHROPIC_MANUAL_BUDGET_MAX = 16384;
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Models that use adaptive thinking + output_config.effort (Claude 5 / Fable /
|
|
178
|
+
* Opus 4.6+ / Sonnet 4.6+). Older ones (Sonnet 4.5, Haiku 4.5, Opus 4.5) use
|
|
179
|
+
* thinking.type=enabled + budget_tokens.
|
|
180
|
+
*/
|
|
181
|
+
function usesAnthropicAdaptiveThinking(modelKey) {
|
|
182
|
+
const id = String(modelKey || '').toLowerCase();
|
|
183
|
+
if (!id) return true;
|
|
184
|
+
if (!id.includes('claude')) return true;
|
|
185
|
+
if (id.includes('fable') || id.includes('mythos')) return true;
|
|
186
|
+
|
|
187
|
+
const opus = id.match(/claude-opus-(\d+)(?:-(\d+))?/);
|
|
188
|
+
if (opus) {
|
|
189
|
+
const major = Number(opus[1]);
|
|
190
|
+
const minor = opus[2] !== undefined ? Number(opus[2]) : 0;
|
|
191
|
+
return major > 4 || (major === 4 && minor >= 6);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const sonnet = id.match(/claude-sonnet-(\d+)(?:-(\d+))?/);
|
|
195
|
+
if (sonnet) {
|
|
196
|
+
const major = Number(sonnet[1]);
|
|
197
|
+
const minor = sonnet[2] !== undefined ? Number(sonnet[2]) : 0;
|
|
198
|
+
return major > 4 || (major === 4 && minor >= 6);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Haiku 4.5 and earlier: manual extended thinking only
|
|
202
|
+
if (id.includes('haiku')) return false;
|
|
203
|
+
|
|
204
|
+
return true;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function mapAnthropicManualBudget(normalized) {
|
|
208
|
+
return Math.max(1024, Math.round((normalized / 100) * ANTHROPIC_MANUAL_BUDGET_MAX));
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function mapAnthropicEffort(normalized, modelKey) {
|
|
212
|
+
if (!usesAnthropicAdaptiveThinking(modelKey)) {
|
|
213
|
+
return {
|
|
214
|
+
thinking: {
|
|
215
|
+
type: 'enabled',
|
|
216
|
+
budget_tokens: mapAnthropicManualBudget(normalized)
|
|
217
|
+
}
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
const desired = levelFromBands(normalized, ANTHROPIC_BANDS);
|
|
222
|
+
const level = pickNearestLevel(desired, ANTHROPIC_LEVELS, ANTHROPIC_LEVELS);
|
|
223
|
+
return {
|
|
224
|
+
thinking: { type: 'adaptive', display: 'summarized' },
|
|
225
|
+
output_config: { effort: level }
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
|
|
173
229
|
function mapDeepSeekEffort(normalized) {
|
|
174
230
|
// DeepSeek V4 has no adaptive mode (only enabled/disabled + low|high|max)
|
|
175
231
|
if (normalized === -1) return null;
|
|
@@ -282,9 +338,7 @@ function mapEffort(providerFamily, effort, modelKey) {
|
|
|
282
338
|
}
|
|
283
339
|
|
|
284
340
|
if (providerFamily === 'anthropic') {
|
|
285
|
-
|
|
286
|
-
const level = pickNearestLevel(desired, ANTHROPIC_LEVELS, ANTHROPIC_LEVELS);
|
|
287
|
-
return { output_config: { effort: level } };
|
|
341
|
+
return mapAnthropicEffort(normalized, modelKey);
|
|
288
342
|
}
|
|
289
343
|
|
|
290
344
|
if (providerFamily === 'google') {
|
|
@@ -357,6 +411,7 @@ module.exports = {
|
|
|
357
411
|
resolveProviderFamily,
|
|
358
412
|
isDeepSeekV4,
|
|
359
413
|
isMiniMax,
|
|
414
|
+
usesAnthropicAdaptiveThinking,
|
|
360
415
|
levelFromBands,
|
|
361
416
|
pickNearestLevel,
|
|
362
417
|
OPENAI_BANDS,
|
|
@@ -367,4 +422,5 @@ module.exports = {
|
|
|
367
422
|
ANTHROPIC_LEVELS,
|
|
368
423
|
GEMINI_LEVELS,
|
|
369
424
|
DEEPSEEK_LEVELS,
|
|
425
|
+
ANTHROPIC_MANUAL_BUDGET_MAX,
|
|
370
426
|
};
|
package/index.d.ts
CHANGED
|
@@ -286,28 +286,14 @@ export declare class ModelMix {
|
|
|
286
286
|
|
|
287
287
|
// Anthropic
|
|
288
288
|
fable5(args?: ModelAttachArgs): this;
|
|
289
|
-
fable5think(args?: ModelAttachArgs): this;
|
|
290
289
|
opus5(args?: ModelAttachArgs): this;
|
|
291
|
-
opus5think(args?: ModelAttachArgs): this;
|
|
292
|
-
opus48think(args?: ModelAttachArgs): this;
|
|
293
|
-
opus47think(args?: ModelAttachArgs): this;
|
|
294
|
-
opus46think(args?: ModelAttachArgs): this;
|
|
295
290
|
opus48(args?: ModelAttachArgs): this;
|
|
296
291
|
opus47(args?: ModelAttachArgs): this;
|
|
297
292
|
opus46(args?: ModelAttachArgs): this;
|
|
298
|
-
opus41(args?: ModelAttachArgs): this;
|
|
299
|
-
opus41think(args?: ModelAttachArgs): this;
|
|
300
293
|
sonnet5(args?: ModelAttachArgs): this;
|
|
301
|
-
sonnet5think(args?: ModelAttachArgs): this;
|
|
302
|
-
sonnet4(args?: ModelAttachArgs): this;
|
|
303
|
-
sonnet4think(args?: ModelAttachArgs): this;
|
|
304
294
|
sonnet46(args?: ModelAttachArgs): this;
|
|
305
|
-
sonnet46think(args?: ModelAttachArgs): this;
|
|
306
295
|
sonnet45(args?: ModelAttachArgs): this;
|
|
307
|
-
sonnet45think(args?: ModelAttachArgs): this;
|
|
308
|
-
haiku35(args?: ModelAttachArgs): this;
|
|
309
296
|
haiku45(args?: ModelAttachArgs): this;
|
|
310
|
-
haiku45think(args?: ModelAttachArgs): this;
|
|
311
297
|
|
|
312
298
|
// Google
|
|
313
299
|
gemini25flash(args?: ModelAttachArgs): this;
|
|
@@ -324,16 +310,17 @@ export declare class ModelMix {
|
|
|
324
310
|
sonar(args?: ModelAttachArgs): this;
|
|
325
311
|
|
|
326
312
|
// Grok
|
|
313
|
+
grok45(args?: ModelAttachArgs): this;
|
|
327
314
|
grok43(args?: ModelAttachArgs): this;
|
|
328
315
|
grok420multiAgent(args?: ModelAttachArgs): this;
|
|
329
316
|
grok420think(args?: ModelAttachArgs): this;
|
|
330
317
|
grok420(args?: ModelAttachArgs): this;
|
|
331
|
-
grok41think(args?: ModelAttachArgs): this;
|
|
332
|
-
grok41(args?: ModelAttachArgs): this;
|
|
333
318
|
|
|
334
319
|
// Multi-provider
|
|
335
320
|
qwen3(args?: ModelAttachArgs): this;
|
|
336
321
|
qwen36plus(args?: ModelAttachArgs): this;
|
|
322
|
+
qwen37plus(args?: ModelAttachArgs): this;
|
|
323
|
+
qwen38max(args?: ModelAttachArgs): this;
|
|
337
324
|
hermes3(args?: ModelAttachArgs): this;
|
|
338
325
|
kimiK26think(args?: ModelAttachArgs): this;
|
|
339
326
|
kimiK27Code(args?: ModelAttachArgs): this;
|
|
@@ -349,7 +336,6 @@ export declare class ModelMix {
|
|
|
349
336
|
deepseekV4Flash(args?: ModelAttachArgs): this;
|
|
350
337
|
GLM51(args?: ModelAttachArgs): this;
|
|
351
338
|
GLM52(args?: ModelAttachArgs): this;
|
|
352
|
-
GLM5(args?: ModelAttachArgs): this;
|
|
353
339
|
|
|
354
340
|
addText(text: string, options?: RoleOptions): this;
|
|
355
341
|
addTextFromFile(filePath: string, options?: RoleOptions): this;
|
package/index.js
CHANGED
|
@@ -72,11 +72,8 @@ const MODEL_PRICING = {
|
|
|
72
72
|
'claude-opus-4-8': [5.00, 25.00],
|
|
73
73
|
'claude-opus-4-7': [5.00, 25.00],
|
|
74
74
|
'claude-opus-4-6': [5.00, 25.00],
|
|
75
|
-
'claude-opus-4-1-20250805': [15.00, 75.00],
|
|
76
75
|
'claude-sonnet-4-6': [3.00, 15.00],
|
|
77
76
|
'claude-sonnet-4-5-20250929': [3.00, 15.00],
|
|
78
|
-
'claude-sonnet-4-20250514': [3.00, 15.00],
|
|
79
|
-
'claude-3-5-haiku-20241022': [0.80, 4.00],
|
|
80
77
|
'claude-haiku-4-5-20251001': [1.00, 5.00],
|
|
81
78
|
// Google
|
|
82
79
|
'gemini-3.1-pro-preview':[2.00, 12.00],
|
|
@@ -88,12 +85,11 @@ const MODEL_PRICING = {
|
|
|
88
85
|
'gemini-2.5-flash': [0.30, 2.50],
|
|
89
86
|
'gemini-3.1-flash-lite-preview': [0.25, 1.50],
|
|
90
87
|
// Grok
|
|
88
|
+
'grok-4.5': [2.00, 6.00],
|
|
91
89
|
'grok-4.3': [1.25, 2.50],
|
|
92
90
|
'grok-4.20-multi-agent-0309': [1.25, 2.50],
|
|
93
91
|
'grok-4.20-0309-reasoning': [1.25, 2.50],
|
|
94
92
|
'grok-4.20-0309-non-reasoning': [1.25, 2.50],
|
|
95
|
-
'grok-4-1-fast-reasoning': [0.20, 0.50],
|
|
96
|
-
'grok-4-1-fast-non-reasoning': [0.20, 0.50],
|
|
97
93
|
// Fireworks
|
|
98
94
|
'accounts/fireworks/models/deepseek-v4-flash': [0.14, 0.28],
|
|
99
95
|
'accounts/fireworks/models/deepseek-v4-pro': [1.74, 3.48],
|
|
@@ -106,12 +102,13 @@ const MODEL_PRICING = {
|
|
|
106
102
|
'accounts/fireworks/models/kimi-k2p5': [0.50, 2.80],
|
|
107
103
|
'accounts/fireworks/models/qwen3p6-plus': [0.50, 3.00],
|
|
108
104
|
'Qwen/Qwen3.6-Plus': [0.50, 3.00],
|
|
109
|
-
'fireworks/
|
|
105
|
+
'accounts/fireworks/models/qwen3p7-plus': [0.40, 1.60],
|
|
106
|
+
'qwen/qwen3.7-plus': [0.32, 1.28],
|
|
107
|
+
'qwen/qwen3.8-max': [2.00, 6.00],
|
|
110
108
|
// MiniMax
|
|
111
109
|
'MiniMax-M2.5': [0.30, 1.20],
|
|
112
110
|
'MiniMax-M2.7': [0.30, 1.20],
|
|
113
111
|
'MiniMax-M3': [0.30, 1.20],
|
|
114
|
-
'fireworks/minimax-m2p5': [0.30, 1.20],
|
|
115
112
|
'minimax/minimax-m2.7': [0.30, 1.20],
|
|
116
113
|
'minimax/minimax-m3': [0.30, 1.20],
|
|
117
114
|
'MiniMaxAI/MiniMax-M3': [0.30, 1.20],
|
|
@@ -388,29 +385,9 @@ class ModelMix {
|
|
|
388
385
|
fable5({ options = {}, config = {} } = {}) {
|
|
389
386
|
return this.attach('claude-fable-5', new MixAnthropic({ options, config }));
|
|
390
387
|
}
|
|
391
|
-
fable5think({ options = {}, config = {} } = {}) {
|
|
392
|
-
options = { ...MixAnthropic.maxEffortThinkingOptions, ...options };
|
|
393
|
-
return this.attach('claude-fable-5', new MixAnthropic({ options, config }));
|
|
394
|
-
}
|
|
395
388
|
opus5({ options = {}, config = {} } = {}) {
|
|
396
389
|
return this.attach('claude-opus-5', new MixAnthropic({ options, config }));
|
|
397
390
|
}
|
|
398
|
-
opus5think({ options = {}, config = {} } = {}) {
|
|
399
|
-
options = { ...MixAnthropic.maxEffortThinkingOptions, ...options };
|
|
400
|
-
return this.attach('claude-opus-5', new MixAnthropic({ options, config }));
|
|
401
|
-
}
|
|
402
|
-
opus48think({ options = {}, config = {} } = {}) {
|
|
403
|
-
options = { ...MixAnthropic.thinkingOptions, ...options };
|
|
404
|
-
return this.attach('claude-opus-4-8', new MixAnthropic({ options, config }));
|
|
405
|
-
}
|
|
406
|
-
opus47think({ options = {}, config = {} } = {}) {
|
|
407
|
-
options = { ...MixAnthropic.thinkingOptions, ...options };
|
|
408
|
-
return this.attach('claude-opus-4-7', new MixAnthropic({ options, config }));
|
|
409
|
-
}
|
|
410
|
-
opus46think({ options = {}, config = {} } = {}) {
|
|
411
|
-
options = { ...MixAnthropic.thinkingOptions, ...options };
|
|
412
|
-
return this.attach('claude-opus-4-6', new MixAnthropic({ options, config }));
|
|
413
|
-
}
|
|
414
391
|
opus48({ options = {}, config = {} } = {}) {
|
|
415
392
|
return this.attach('claude-opus-4-8', new MixAnthropic({ options, config }));
|
|
416
393
|
}
|
|
@@ -420,52 +397,18 @@ class ModelMix {
|
|
|
420
397
|
opus46({ options = {}, config = {} } = {}) {
|
|
421
398
|
return this.attach('claude-opus-4-6', new MixAnthropic({ options, config }));
|
|
422
399
|
}
|
|
423
|
-
opus41({ options = {}, config = {} } = {}) {
|
|
424
|
-
return this.attach('claude-opus-4-1-20250805', new MixAnthropic({ options, config }));
|
|
425
|
-
}
|
|
426
|
-
opus41think({ options = {}, config = {} } = {}) {
|
|
427
|
-
options = { ...MixAnthropic.thinkingOptions, ...options };
|
|
428
|
-
return this.attach('claude-opus-4-1-20250805', new MixAnthropic({ options, config }));
|
|
429
|
-
}
|
|
430
400
|
sonnet5({ options = {}, config = {} } = {}) {
|
|
431
401
|
return this.attach('claude-sonnet-5', new MixAnthropic({ options, config }));
|
|
432
402
|
}
|
|
433
|
-
sonnet5think({ options = {}, config = {} } = {}) {
|
|
434
|
-
options = { ...MixAnthropic.thinkingOptions, ...options };
|
|
435
|
-
return this.attach('claude-sonnet-5', new MixAnthropic({ options, config }));
|
|
436
|
-
}
|
|
437
|
-
sonnet4({ options = {}, config = {} } = {}) {
|
|
438
|
-
return this.attach('claude-sonnet-4-20250514', new MixAnthropic({ options, config }));
|
|
439
|
-
}
|
|
440
|
-
sonnet4think({ options = {}, config = {} } = {}) {
|
|
441
|
-
options = { ...MixAnthropic.thinkingOptions, ...options };
|
|
442
|
-
return this.attach('claude-sonnet-4-20250514', new MixAnthropic({ options, config }));
|
|
443
|
-
}
|
|
444
403
|
sonnet46({ options = {}, config = {} } = {}) {
|
|
445
404
|
return this.attach('claude-sonnet-4-6', new MixAnthropic({ options, config }));
|
|
446
405
|
}
|
|
447
|
-
sonnet46think({ options = {}, config = {} } = {}) {
|
|
448
|
-
options = { ...MixAnthropic.thinkingOptions, ...options };
|
|
449
|
-
return this.attach('claude-sonnet-4-6', new MixAnthropic({ options, config }));
|
|
450
|
-
}
|
|
451
|
-
|
|
452
406
|
sonnet45({ options = {}, config = {} } = {}) {
|
|
453
407
|
return this.attach('claude-sonnet-4-5-20250929', new MixAnthropic({ options, config }));
|
|
454
408
|
}
|
|
455
|
-
sonnet45think({ options = {}, config = {} } = {}) {
|
|
456
|
-
options = { ...MixAnthropic.thinkingOptions, ...options };
|
|
457
|
-
return this.attach('claude-sonnet-4-5-20250929', new MixAnthropic({ options, config }));
|
|
458
|
-
}
|
|
459
|
-
haiku35({ options = {}, config = {} } = {}) {
|
|
460
|
-
return this.attach('claude-3-5-haiku-20241022', new MixAnthropic({ options, config }));
|
|
461
|
-
}
|
|
462
409
|
haiku45({ options = {}, config = {} } = {}) {
|
|
463
410
|
return this.attach('claude-haiku-4-5-20251001', new MixAnthropic({ options, config }));
|
|
464
411
|
}
|
|
465
|
-
haiku45think({ options = {}, config = {} } = {}) {
|
|
466
|
-
options = { ...MixAnthropic.thinkingOptions, ...options };
|
|
467
|
-
return this.attach('claude-haiku-4-5-20251001', new MixAnthropic({ options, config }));
|
|
468
|
-
}
|
|
469
412
|
gemini25flash({ options = {}, config = {} } = {}) {
|
|
470
413
|
return this.attach('gemini-2.5-flash', new MixGoogle({ options, config }));
|
|
471
414
|
}
|
|
@@ -497,6 +440,9 @@ class ModelMix {
|
|
|
497
440
|
return this.attach('sonar', new MixPerplexity({ options, config }));
|
|
498
441
|
}
|
|
499
442
|
|
|
443
|
+
grok45({ options = {}, config = {} } = {}) {
|
|
444
|
+
return this.attach('grok-4.5', new MixGrok({ options, config }));
|
|
445
|
+
}
|
|
500
446
|
grok43({ options = {}, config = {} } = {}) {
|
|
501
447
|
return this.attach('grok-4.3', new MixGrok({ options, config }));
|
|
502
448
|
}
|
|
@@ -509,12 +455,6 @@ class ModelMix {
|
|
|
509
455
|
grok420({ options = {}, config = {} } = {}) {
|
|
510
456
|
return this.attach('grok-4.20-0309-non-reasoning', new MixGrok({ options, config }));
|
|
511
457
|
}
|
|
512
|
-
grok41think({ options = {}, config = {} } = {}) {
|
|
513
|
-
return this.attach('grok-4-1-fast-reasoning', new MixGrok({ options, config }));
|
|
514
|
-
}
|
|
515
|
-
grok41({ options = {}, config = {} } = {}) {
|
|
516
|
-
return this.attach('grok-4-1-fast-non-reasoning', new MixGrok({ options, config }));
|
|
517
|
-
}
|
|
518
458
|
|
|
519
459
|
qwen3({ options = {}, config = {}, mix = { together: true, cerebras: false } } = {}) {
|
|
520
460
|
if (mix.together) this.attach('Qwen/Qwen3-235B-A22B-fp8-tput', new MixTogether({ options, config }));
|
|
@@ -527,7 +467,20 @@ class ModelMix {
|
|
|
527
467
|
if (mix.fireworks) this.attach('accounts/fireworks/models/qwen3p6-plus', new MixFireworks({ options, config }));
|
|
528
468
|
if (mix.together) this.attach('Qwen/Qwen3.6-Plus', new MixTogether({ options, config }));
|
|
529
469
|
return this;
|
|
530
|
-
}
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
qwen37plus({ options = {}, config = {}, mix = { fireworks: true } } = {}) {
|
|
473
|
+
mix = { ...this.mix, ...mix };
|
|
474
|
+
if (mix.fireworks) this.attach('accounts/fireworks/models/qwen3p7-plus', new MixFireworks({ options, config }));
|
|
475
|
+
if (mix.openrouter) this.attach('qwen/qwen3.7-plus', new MixOpenRouter({ options, config }));
|
|
476
|
+
return this;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
qwen38max({ options = {}, config = {}, mix = { openrouter: true } } = {}) {
|
|
480
|
+
mix = { ...this.mix, ...mix };
|
|
481
|
+
if (mix.openrouter) this.attach('qwen/qwen3.8-max', new MixOpenRouter({ options, config }));
|
|
482
|
+
return this;
|
|
483
|
+
}
|
|
531
484
|
|
|
532
485
|
hermes3({ options = {}, config = {}, mix = {} } = {}) {
|
|
533
486
|
mix = { ...this.mix, ...mix };
|
|
@@ -573,7 +526,6 @@ class ModelMix {
|
|
|
573
526
|
minimaxM25({ options = {}, config = {}, mix = { minimax: true } } = {}) {
|
|
574
527
|
mix = { ...this.mix, ...mix };
|
|
575
528
|
if (mix.minimax) this.attach('MiniMax-M2.5', new MixMiniMax({ options, config }));
|
|
576
|
-
if (mix.fireworks) this.attach('fireworks/minimax-m2p5', new MixFireworks({ options, config }));
|
|
577
529
|
return this;
|
|
578
530
|
}
|
|
579
531
|
|
|
@@ -641,12 +593,6 @@ class ModelMix {
|
|
|
641
593
|
return this;
|
|
642
594
|
}
|
|
643
595
|
|
|
644
|
-
GLM5({ options = {}, config = {}, mix = { fireworks: true } } = {}) {
|
|
645
|
-
mix = { ...this.mix, ...mix };
|
|
646
|
-
if (mix.fireworks) this.attach('fireworks/glm-5', new MixFireworks({ options, config }));
|
|
647
|
-
return this;
|
|
648
|
-
}
|
|
649
|
-
|
|
650
596
|
addText(text, { role = "user" } = {}) {
|
|
651
597
|
const content = [{
|
|
652
598
|
type: "text",
|
|
@@ -987,7 +933,7 @@ class ModelMix {
|
|
|
987
933
|
|
|
988
934
|
async execute({ config = {}, options = {} } = {}) {
|
|
989
935
|
if (!this.models || this.models.length === 0) {
|
|
990
|
-
throw new Error("No models specified. Use methods like .gpt5(), .
|
|
936
|
+
throw new Error("No models specified. Use methods like .gpt5(), .sonnet46() first.");
|
|
991
937
|
}
|
|
992
938
|
|
|
993
939
|
return this.limiter.schedule(async () => {
|
|
@@ -2197,19 +2143,6 @@ class MixKimi extends MixOpenAI {
|
|
|
2197
2143
|
|
|
2198
2144
|
class MixAnthropic extends MixCustom {
|
|
2199
2145
|
|
|
2200
|
-
static thinkingOptions = {
|
|
2201
|
-
thinking: {
|
|
2202
|
-
"type": "enabled",
|
|
2203
|
-
"budget_tokens": 1638
|
|
2204
|
-
},
|
|
2205
|
-
temperature: 1
|
|
2206
|
-
};
|
|
2207
|
-
|
|
2208
|
-
static maxEffortThinkingOptions = {
|
|
2209
|
-
output_config: { effort: 'max' },
|
|
2210
|
-
thinking: { display: 'summarized' }
|
|
2211
|
-
};
|
|
2212
|
-
|
|
2213
2146
|
/**
|
|
2214
2147
|
* Opus 4.7+ and Claude 5 family reject sampling params (temperature/top_p/top_k).
|
|
2215
2148
|
* See: https://platform.claude.com/docs/en/about-claude/models/migration-guide
|
package/package.json
CHANGED
package/skills/modelmix/SKILL.md
CHANGED
|
@@ -114,7 +114,7 @@ ModelMix.new({ config: { effort: 80 } })
|
|
|
114
114
|
| DeepSeek V4 | off | `low`↑ | `high`↑ | `high`↑ | `max`↑ | — |
|
|
115
115
|
| MiniMax M3 | off | adaptive | adaptive | adaptive | adaptive | adaptive |
|
|
116
116
|
|
|
117
|
-
\* Gemini bands: 0–24 / 25–49 / 50–74 / 75–100. DeepSeek `↑` = thinking on; `off` = thinking disabled. MiniMax `off`/`adaptive` = `thinking.disabled` / `thinking.type=adaptive`. Gemini 2.5 maps 0–100 to `thinkingBudget`. `-1` = adaptive/dynamic when available, else no-op. Levels clamp per model. `*think()`
|
|
117
|
+
\* Gemini bands: 0–24 / 25–49 / 50–74 / 75–100. DeepSeek `↑` = thinking on; `off` = thinking disabled. MiniMax `off`/`adaptive` = `thinking.disabled` / `thinking.type=adaptive`. Gemini 2.5 maps 0–100 to `thinkingBudget`. Anthropic: adaptive + `output_config.effort` on Claude 5 / Fable / Opus 4.6+ / Sonnet 4.6+; Sonnet 4.5 / Haiku 4.5 use `thinking.type=enabled` + `budget_tokens`. `-1` = adaptive/dynamic when available, else no-op. Levels clamp per model. Former Anthropic `*think()` methods are removed — use `.effort(n).<model>()`.
|
|
118
118
|
|
|
119
119
|
## Available Model Shorthands
|
|
120
120
|
|
|
@@ -122,15 +122,15 @@ ModelMix.new({ config: { effort: 80 } })
|
|
|
122
122
|
`gpt52()` `gpt52chat()` `gpt51()` `gpt5()` `gpt5mini()` `gpt5nano()` `gpt45()` `gpt41()` `gpt41mini()` `gpt41nano()` `o3()` `o4mini()`
|
|
123
123
|
|
|
124
124
|
### Anthropic
|
|
125
|
-
`fable5()` `opus5()` `opus48()` `opus47()` `opus46()` `
|
|
125
|
+
`fable5()` `opus5()` `opus48()` `opus47()` `opus46()` `sonnet5()` `sonnet46()` `sonnet45()` `haiku45()`
|
|
126
126
|
|
|
127
|
-
|
|
127
|
+
Use `.effort(n)` (or `config.effort`) to enable Anthropic thinking — e.g. `.effort(100).opus5()`.
|
|
128
128
|
|
|
129
129
|
### Google
|
|
130
130
|
`gemini3pro()` `gemini3flash()` `gemini36flash()` `gemini35flash()` `gemini25pro()` `gemini25flash()`
|
|
131
131
|
|
|
132
132
|
### Grok
|
|
133
|
-
`
|
|
133
|
+
`grok45()` `grok43()` `grok420multiAgent()` `grok420()` `grok420think()`
|
|
134
134
|
|
|
135
135
|
### Perplexity
|
|
136
136
|
`sonar()` `sonarPro()`
|
|
@@ -145,13 +145,13 @@ Thinking variants: append `think` — e.g. `fable5think()` `opus5think()` `opus4
|
|
|
145
145
|
`minimaxM25()` `minimaxM27()` `minimaxM3()`
|
|
146
146
|
|
|
147
147
|
### Fireworks
|
|
148
|
-
`
|
|
148
|
+
`qwen36plus()` `qwen37plus()` `deepseekV4Flash()` `deepseekV4Pro()`
|
|
149
149
|
|
|
150
150
|
### Cerebras
|
|
151
151
|
`GLM46()`
|
|
152
152
|
|
|
153
153
|
### OpenRouter
|
|
154
|
-
`GLM45()`
|
|
154
|
+
`qwen38max()` `GLM45()`
|
|
155
155
|
|
|
156
156
|
### Multi-provider (auto-fallback across free/paid tiers)
|
|
157
157
|
`hermes3()` `kimiK25think()`
|
|
@@ -286,7 +286,8 @@ const code = await ModelMix.new()
|
|
|
286
286
|
|
|
287
287
|
```javascript
|
|
288
288
|
const raw = await ModelMix.new()
|
|
289
|
-
.
|
|
289
|
+
.effort(100)
|
|
290
|
+
.sonnet45()
|
|
290
291
|
.addText("Solve this step by step: 2+2*3")
|
|
291
292
|
.raw();
|
|
292
293
|
// raw.message, raw.think, raw.tokens, raw.toolCalls, raw.response
|
|
@@ -463,8 +464,7 @@ const model = ModelMix.new({
|
|
|
463
464
|
- When using MCP tools or `addTool()`, set `max_history` to at least 3 — tool call/response pairs consume history slots.
|
|
464
465
|
- Use `.json()` for structured output instead of parsing text manually. Use descriptor objects `{ description, required, enum, default, nullable }` for richer schema control.
|
|
465
466
|
- Use `.message()` for simple text, `.raw()` when you need tokens/thinking/toolCalls.
|
|
466
|
-
- For thinking
|
|
467
|
-
- For cross-provider reasoning intensity, use unified `effort` (`-1` or `0`–`100`) via `config.effort` or `.effort(n)` — never put it in `options`. Native fields win if already set.
|
|
467
|
+
- For Anthropic thinking, use unified `effort` (`-1` or `0`–`100`) via `config.effort` or `.effort(n)` — e.g. `.effort(100).opus5()`. Never put `effort` in `options`. Native fields win if already set.
|
|
468
468
|
- Template placeholders use `{key}` syntax in both system prompts and user messages.
|
|
469
469
|
- The library uses CommonJS internally but supports ESM import via `{ ModelMix }`.
|
|
470
470
|
- GPT-5+ models automatically use `max_completion_tokens` instead of `max_tokens`.
|
package/test/anthropic.test.js
CHANGED
|
@@ -12,15 +12,15 @@ describe('Anthropic Model Registration Tests', () => {
|
|
|
12
12
|
expect(model.models[0].provider).to.be.instanceOf(MixAnthropic);
|
|
13
13
|
});
|
|
14
14
|
|
|
15
|
-
it('should
|
|
16
|
-
const model = ModelMix.new();
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
expect(model.
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
expect(
|
|
23
|
-
expect(
|
|
15
|
+
it('should apply max effort thinking via .effort(100).fable5()', () => {
|
|
16
|
+
const model = ModelMix.new().effort(100).fable5();
|
|
17
|
+
const { applyUnifiedEffort } = require('../effort.js');
|
|
18
|
+
|
|
19
|
+
expect(model.config.effort).to.equal(100);
|
|
20
|
+
const options = { model: 'claude-fable-5' };
|
|
21
|
+
applyUnifiedEffort(options, model.config, 'anthropic', 'claude-fable-5');
|
|
22
|
+
expect(options.output_config).to.deep.equal({ effort: 'max' });
|
|
23
|
+
expect(options.thinking).to.deep.equal({ type: 'adaptive', display: 'summarized' });
|
|
24
24
|
});
|
|
25
25
|
|
|
26
26
|
it('should register Claude Opus 5', () => {
|
|
@@ -32,15 +32,15 @@ describe('Anthropic Model Registration Tests', () => {
|
|
|
32
32
|
expect(model.models[0].provider).to.be.instanceOf(MixAnthropic);
|
|
33
33
|
});
|
|
34
34
|
|
|
35
|
-
it('should
|
|
36
|
-
const model = ModelMix.new();
|
|
37
|
-
|
|
35
|
+
it('should apply max effort thinking via .effort(100).opus5()', () => {
|
|
36
|
+
const model = ModelMix.new().effort(100).opus5();
|
|
37
|
+
const { applyUnifiedEffort } = require('../effort.js');
|
|
38
38
|
|
|
39
|
-
expect(model.
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
expect(
|
|
43
|
-
expect(
|
|
39
|
+
expect(model.config.effort).to.equal(100);
|
|
40
|
+
const options = { model: 'claude-opus-5' };
|
|
41
|
+
applyUnifiedEffort(options, model.config, 'anthropic', 'claude-opus-5');
|
|
42
|
+
expect(options.output_config).to.deep.equal({ effort: 'max' });
|
|
43
|
+
expect(options.thinking).to.deep.equal({ type: 'adaptive', display: 'summarized' });
|
|
44
44
|
});
|
|
45
45
|
|
|
46
46
|
describe('Sampling params (temperature/top_p/top_k)', () => {
|
|
@@ -53,7 +53,6 @@ describe('Anthropic Model Registration Tests', () => {
|
|
|
53
53
|
expect(MixAnthropic.rejectsSamplingParams('anthropic/claude-opus-5')).to.equal(true);
|
|
54
54
|
|
|
55
55
|
expect(MixAnthropic.rejectsSamplingParams('claude-opus-4-6')).to.equal(false);
|
|
56
|
-
expect(MixAnthropic.rejectsSamplingParams('claude-opus-4-1-20250805')).to.equal(false);
|
|
57
56
|
expect(MixAnthropic.rejectsSamplingParams('claude-sonnet-4-6')).to.equal(false);
|
|
58
57
|
expect(MixAnthropic.rejectsSamplingParams('claude-haiku-4-5-20251001')).to.equal(false);
|
|
59
58
|
});
|
|
@@ -143,16 +142,14 @@ describe('Anthropic Model Registration Tests', () => {
|
|
|
143
142
|
expect(model.models[0].provider).to.be.instanceOf(MixAnthropic);
|
|
144
143
|
});
|
|
145
144
|
|
|
146
|
-
it('should
|
|
147
|
-
const model = ModelMix.new();
|
|
148
|
-
|
|
145
|
+
it('should apply adaptive thinking via .effort(100).opus48()', () => {
|
|
146
|
+
const model = ModelMix.new().effort(100).opus48();
|
|
147
|
+
const { applyUnifiedEffort } = require('../effort.js');
|
|
149
148
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
expect(
|
|
153
|
-
|
|
154
|
-
budget_tokens: 1638
|
|
155
|
-
});
|
|
149
|
+
const options = { model: 'claude-opus-4-8' };
|
|
150
|
+
applyUnifiedEffort(options, model.config, 'anthropic', 'claude-opus-4-8');
|
|
151
|
+
expect(options.thinking).to.deep.equal({ type: 'adaptive', display: 'summarized' });
|
|
152
|
+
expect(options.output_config).to.deep.equal({ effort: 'max' });
|
|
156
153
|
});
|
|
157
154
|
|
|
158
155
|
it('should register Claude Sonnet 5', () => {
|
|
@@ -164,16 +161,14 @@ describe('Anthropic Model Registration Tests', () => {
|
|
|
164
161
|
expect(model.models[0].provider).to.be.instanceOf(MixAnthropic);
|
|
165
162
|
});
|
|
166
163
|
|
|
167
|
-
it('should
|
|
168
|
-
const model = ModelMix.new();
|
|
169
|
-
|
|
164
|
+
it('should apply adaptive thinking via .effort(100).sonnet5()', () => {
|
|
165
|
+
const model = ModelMix.new().effort(100).sonnet5();
|
|
166
|
+
const { applyUnifiedEffort } = require('../effort.js');
|
|
170
167
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
expect(
|
|
174
|
-
|
|
175
|
-
budget_tokens: 1638
|
|
176
|
-
});
|
|
168
|
+
const options = { model: 'claude-sonnet-5' };
|
|
169
|
+
applyUnifiedEffort(options, model.config, 'anthropic', 'claude-sonnet-5');
|
|
170
|
+
expect(options.thinking).to.deep.equal({ type: 'adaptive', display: 'summarized' });
|
|
171
|
+
expect(options.output_config).to.deep.equal({ effort: 'max' });
|
|
177
172
|
});
|
|
178
173
|
|
|
179
174
|
describe('Thinking block extraction', () => {
|
package/test/effort.test.js
CHANGED
|
@@ -81,9 +81,31 @@ describe('Unified effort scale', () => {
|
|
|
81
81
|
expect(mapEffort('openai', 10, 'gpt-oss-120b')).to.deep.equal({ reasoning_effort: 'low' });
|
|
82
82
|
});
|
|
83
83
|
|
|
84
|
-
it('maps Anthropic
|
|
85
|
-
expect(mapEffort('anthropic', 10)).to.deep.equal({
|
|
86
|
-
|
|
84
|
+
it('maps Anthropic adaptive models to thinking + output_config.effort', () => {
|
|
85
|
+
expect(mapEffort('anthropic', 10, 'claude-opus-5')).to.deep.equal({
|
|
86
|
+
thinking: { type: 'adaptive', display: 'summarized' },
|
|
87
|
+
output_config: { effort: 'low' }
|
|
88
|
+
});
|
|
89
|
+
expect(mapEffort('anthropic', 90, 'claude-fable-5')).to.deep.equal({
|
|
90
|
+
thinking: { type: 'adaptive', display: 'summarized' },
|
|
91
|
+
output_config: { effort: 'max' }
|
|
92
|
+
});
|
|
93
|
+
expect(mapEffort('anthropic', 50, 'claude-sonnet-4-6')).to.deep.equal({
|
|
94
|
+
thinking: { type: 'adaptive', display: 'summarized' },
|
|
95
|
+
output_config: { effort: 'high' }
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('maps Anthropic manual models to thinking.type=enabled + budget_tokens', () => {
|
|
100
|
+
expect(mapEffort('anthropic', 50, 'claude-sonnet-4-5-20250929')).to.deep.equal({
|
|
101
|
+
thinking: { type: 'enabled', budget_tokens: 8192 }
|
|
102
|
+
});
|
|
103
|
+
expect(mapEffort('anthropic', 100, 'claude-haiku-4-5-20251001')).to.deep.equal({
|
|
104
|
+
thinking: { type: 'enabled', budget_tokens: 16384 }
|
|
105
|
+
});
|
|
106
|
+
expect(mapEffort('anthropic', 0, 'claude-sonnet-4-5-20250929')).to.deep.equal({
|
|
107
|
+
thinking: { type: 'enabled', budget_tokens: 1024 }
|
|
108
|
+
});
|
|
87
109
|
});
|
|
88
110
|
|
|
89
111
|
it('maps Anthropic adaptive to thinking.type=adaptive', () => {
|
|
@@ -223,6 +245,14 @@ describe('Unified effort scale', () => {
|
|
|
223
245
|
const options = {};
|
|
224
246
|
applyUnifiedEffort(options, { effort: 90 }, 'anthropic', 'claude-opus-5');
|
|
225
247
|
expect(options.output_config).to.deep.equal({ effort: 'max' });
|
|
248
|
+
expect(options.thinking).to.deep.equal({ type: 'adaptive', display: 'summarized' });
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
it('applies Anthropic manual thinking for Sonnet 4.5', () => {
|
|
252
|
+
const options = {};
|
|
253
|
+
applyUnifiedEffort(options, { effort: 50 }, 'anthropic', 'claude-sonnet-4-5-20250929');
|
|
254
|
+
expect(options.thinking).to.deep.equal({ type: 'enabled', budget_tokens: 8192 });
|
|
255
|
+
expect(options.output_config).to.equal(undefined);
|
|
226
256
|
});
|
|
227
257
|
|
|
228
258
|
it('skips Anthropic mapping when output_config.effort is set', () => {
|
|
@@ -306,16 +336,29 @@ describe('Unified effort scale', () => {
|
|
|
306
336
|
expect(request.reasoning).to.deep.equal({ effort: 'none' });
|
|
307
337
|
});
|
|
308
338
|
|
|
309
|
-
it('Anthropic
|
|
310
|
-
const model = ModelMix.new(
|
|
311
|
-
expect(model.
|
|
339
|
+
it('Anthropic config.effort maps through .effort().opus5()', () => {
|
|
340
|
+
const model = ModelMix.new().effort(100).opus5();
|
|
341
|
+
expect(model.config.effort).to.equal(100);
|
|
312
342
|
|
|
313
343
|
const options = {
|
|
314
344
|
...model.models[0].provider.options,
|
|
315
345
|
model: 'claude-opus-5'
|
|
316
346
|
};
|
|
317
|
-
applyUnifiedEffort(options,
|
|
347
|
+
applyUnifiedEffort(options, model.config, 'anthropic', 'claude-opus-5');
|
|
318
348
|
expect(options.output_config.effort).to.equal('max');
|
|
349
|
+
expect(options.thinking).to.deep.equal({ type: 'adaptive', display: 'summarized' });
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
it('Anthropic .effort(50).sonnet45() maps to manual budget_tokens', () => {
|
|
353
|
+
const model = ModelMix.new().effort(50).sonnet45();
|
|
354
|
+
expect(model.config.effort).to.equal(50);
|
|
355
|
+
|
|
356
|
+
const options = {
|
|
357
|
+
...model.models[0].provider.options,
|
|
358
|
+
model: 'claude-sonnet-4-5-20250929'
|
|
359
|
+
};
|
|
360
|
+
applyUnifiedEffort(options, model.config, 'anthropic', 'claude-sonnet-4-5-20250929');
|
|
361
|
+
expect(options.thinking).to.deep.equal({ type: 'enabled', budget_tokens: 8192 });
|
|
319
362
|
});
|
|
320
363
|
|
|
321
364
|
it('MixGoogle generationConfig includes thinkingConfig from options', async () => {
|
package/test/grok.test.js
CHANGED
|
@@ -3,6 +3,7 @@ const { ModelMix } = require('../index.js');
|
|
|
3
3
|
|
|
4
4
|
describe('Grok Model Registration Tests', () => {
|
|
5
5
|
const grokModels = [
|
|
6
|
+
{ method: 'grok45', key: 'grok-4.5' },
|
|
6
7
|
{ method: 'grok43', key: 'grok-4.3' },
|
|
7
8
|
{ method: 'grok420multiAgent', key: 'grok-4.20-multi-agent-0309' },
|
|
8
9
|
{ method: 'grok420think', key: 'grok-4.20-0309-reasoning' },
|
package/test/history.test.js
CHANGED
|
@@ -522,7 +522,7 @@ describe('Conversation History Tests', () => {
|
|
|
522
522
|
const model = ModelMix.new({
|
|
523
523
|
config: { debug: false, max_history: 10 }
|
|
524
524
|
});
|
|
525
|
-
model.
|
|
525
|
+
model.effort(100).opus5();
|
|
526
526
|
|
|
527
527
|
model.addText('2+2?');
|
|
528
528
|
nock('https://api.anthropic.com')
|
package/test/live.test.js
CHANGED
|
@@ -98,7 +98,7 @@ describe('Live Integration Tests', function () {
|
|
|
98
98
|
});
|
|
99
99
|
|
|
100
100
|
it('should return structured JSON with Sonnet 4.6 thinking', async function () {
|
|
101
|
-
const model = ModelMix.new(setup).
|
|
101
|
+
const model = ModelMix.new(setup).effort(100).sonnet46();
|
|
102
102
|
|
|
103
103
|
model.addText('Generate information about a fictional city.');
|
|
104
104
|
|
|
@@ -192,18 +192,6 @@ describe('Live Integration Tests', function () {
|
|
|
192
192
|
expect(response.toLowerCase()).to.include('gptoss test successful');
|
|
193
193
|
});
|
|
194
194
|
|
|
195
|
-
it('should work with Grok 4.1 model', async function () {
|
|
196
|
-
const model = ModelMix.new(setup).grok41();
|
|
197
|
-
|
|
198
|
-
model.addText('Say "grok41 test successful" and nothing else.');
|
|
199
|
-
|
|
200
|
-
const response = await model.message();
|
|
201
|
-
console.log(`Grok 4.1 response: ${response}`);
|
|
202
|
-
|
|
203
|
-
expect(response).to.be.a('string');
|
|
204
|
-
expect(response.toLowerCase()).to.include('grok41 test successful');
|
|
205
|
-
});
|
|
206
|
-
|
|
207
195
|
const grokSeriesTests = [
|
|
208
196
|
{ name: 'Grok 4.3', factory: (m) => m.grok43(), token: 'grok43' },
|
|
209
197
|
{ name: 'Grok 4.20 reasoning', factory: (m) => m.grok420think(), token: 'grok420think' },
|
|
@@ -275,8 +263,8 @@ describe('Live Integration Tests', function () {
|
|
|
275
263
|
expect(result.features).to.be.an('array');
|
|
276
264
|
});
|
|
277
265
|
|
|
278
|
-
it('should return structured JSON with
|
|
279
|
-
const model = ModelMix.new(setup).
|
|
266
|
+
it('should return structured JSON with Grok 4.3', async function () {
|
|
267
|
+
const model = ModelMix.new(setup).grok43();
|
|
280
268
|
|
|
281
269
|
model.addText('Generate information about a fictional technology.');
|
|
282
270
|
|
|
@@ -287,7 +275,7 @@ describe('Live Integration Tests', function () {
|
|
|
287
275
|
power: "1000 qubits"
|
|
288
276
|
});
|
|
289
277
|
|
|
290
|
-
console.log(`
|
|
278
|
+
console.log(`Grok 4.3 JSON result:`, result);
|
|
291
279
|
|
|
292
280
|
expect(result).to.be.an('object');
|
|
293
281
|
expect(result).to.have.property('name');
|
package/test/qwen.test.js
CHANGED
|
@@ -17,4 +17,36 @@ describe('Qwen Model Registration Tests', () => {
|
|
|
17
17
|
expect(model.models).to.have.length(1);
|
|
18
18
|
expect(model.models[0].key).to.equal('Qwen/Qwen3.6-Plus');
|
|
19
19
|
});
|
|
20
|
+
|
|
21
|
+
it('should register Fireworks Qwen 3.7 Plus by default', () => {
|
|
22
|
+
const model = ModelMix.new();
|
|
23
|
+
model.qwen37plus({ mix: { fireworks: true, openrouter: false } });
|
|
24
|
+
|
|
25
|
+
expect(model.models).to.have.length(1);
|
|
26
|
+
expect(model.models[0].key).to.equal('accounts/fireworks/models/qwen3p7-plus');
|
|
27
|
+
expect(ModelMix.calculateCost('accounts/fireworks/models/qwen3p7-plus', {
|
|
28
|
+
input: 1_000_000,
|
|
29
|
+
output: 1_000_000
|
|
30
|
+
})).to.equal(2.00);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it('should register OpenRouter Qwen 3.7 Plus when openrouter mix is enabled', () => {
|
|
34
|
+
const model = ModelMix.new();
|
|
35
|
+
model.qwen37plus({ mix: { fireworks: false, openrouter: true } });
|
|
36
|
+
|
|
37
|
+
expect(model.models).to.have.length(1);
|
|
38
|
+
expect(model.models[0].key).to.equal('qwen/qwen3.7-plus');
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('should register OpenRouter Qwen 3.8 Max by default', () => {
|
|
42
|
+
const model = ModelMix.new();
|
|
43
|
+
model.qwen38max();
|
|
44
|
+
|
|
45
|
+
expect(model.models).to.have.length(1);
|
|
46
|
+
expect(model.models[0].key).to.equal('qwen/qwen3.8-max');
|
|
47
|
+
expect(ModelMix.calculateCost('qwen/qwen3.8-max', {
|
|
48
|
+
input: 1_000_000,
|
|
49
|
+
output: 1_000_000
|
|
50
|
+
})).to.equal(8.00);
|
|
51
|
+
});
|
|
20
52
|
});
|