modelmix 4.7.0 → 4.7.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 +6 -5
- package/demo/free.js +1 -1
- package/effort.js +42 -0
- package/index.d.ts +3 -3
- package/index.js +19 -11
- package/package.json +2 -2
- package/skills/modelmix/SKILL.md +7 -7
- package/test/grok.test.js +38 -2
- package/test/live.test.js +3 -3
package/README.md
CHANGED
|
@@ -89,7 +89,7 @@ console.log(ETH.price);
|
|
|
89
89
|
```javascript
|
|
90
90
|
ModelMix.new()
|
|
91
91
|
.gptOss()
|
|
92
|
-
.
|
|
92
|
+
.kimiK25()
|
|
93
93
|
.hermes3()
|
|
94
94
|
.addText('What is the capital of France?');
|
|
95
95
|
```
|
|
@@ -126,7 +126,7 @@ ModelMix.new().effort(-1).minimaxM3().addText('...').message();
|
|
|
126
126
|
|
|
127
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
128
|
|
|
129
|
-
Migration: former
|
|
129
|
+
Migration: former `*think()` shorthands are removed — use `.effort(n).<model>()` (or any 0–100 / `-1`). Kimi: `kimiK25()` / `kimiK26()`. Grok 4.20: `.grok420()` is non-reasoning; `.effort(20+).grok420()` (or `-1`) selects the reasoning model.
|
|
130
130
|
|
|
131
131
|
## 🔧 Model Context Protocol (MCP) Integration
|
|
132
132
|
|
|
@@ -194,7 +194,7 @@ Here's a comprehensive list of available methods:
|
|
|
194
194
|
| `grok45()` | Grok | grok-4.5 | [\$2.00 / \$6.00][6] |
|
|
195
195
|
| `grok43()` | Grok | grok-4.3 | [\$1.25 / \$2.50][6] |
|
|
196
196
|
| `grok420multiAgent()`| Grok | grok-4.20-multi-agent-0309 | [\$1.25 / \$2.50][6] |
|
|
197
|
-
| `grok420
|
|
197
|
+
| `grok420()` | Grok | grok-4.20-0309 (†) | [\$1.25 / \$2.50][6] |
|
|
198
198
|
| `qwen36plus()` | Fireworks/Together | qwen3p6-plus / Qwen3.6-Plus | [\$0.50 / \$3.00][10] |
|
|
199
199
|
| `qwen37plus()` | Fireworks | models/qwen3p7-plus | [\$0.40 / \$1.60][10] |
|
|
200
200
|
| `qwen38max()` | OpenRouter | qwen/qwen3.8-max | [\$2.00 / \$6.00][12] |
|
|
@@ -208,8 +208,8 @@ Here's a comprehensive list of available methods:
|
|
|
208
208
|
| `sonarPro()` | Perplexity | sonar-pro | [\$3.00 / \$15.00][4] |
|
|
209
209
|
| `hermes3()` | Lambda | Hermes-3-Llama-3.1-405B-FP8 | [\$0.80 / \$0.80][8] |
|
|
210
210
|
| `kimiK3()` | Moonshot | kimi-k3 | [\$3.00 / \$15.00][11] |
|
|
211
|
-
| `
|
|
212
|
-
| `
|
|
211
|
+
| `kimiK25()` | Together | Kimi-K2.5 | [\$0.50 / \$2.80][7] |
|
|
212
|
+
| `kimiK26()` | Fireworks | models/kimi-k2p6 | [\$0.95 / \$4.00][10] |
|
|
213
213
|
|
|
214
214
|
[1]: https://platform.openai.com/docs/pricing "Pricing | OpenAI"
|
|
215
215
|
[2]: https://docs.anthropic.com/en/docs/about-claude/pricing "Pricing - Anthropic"
|
|
@@ -225,6 +225,7 @@ Here's a comprehensive list of available methods:
|
|
|
225
225
|
[12]: https://openrouter.ai/qwen/qwen3.8-max "OpenRouter Pricing"
|
|
226
226
|
|
|
227
227
|
Each method accepts optional `options`, `config`, and (for multi-provider methods) `mix` parameters to customize behavior.
|
|
228
|
+
† `grok420()` resolves to `grok-4.20-0309-non-reasoning` by default, or `grok-4.20-0309-reasoning` when `.effort(20+)` / `-1` (or native non-`none` `reasoning_effort`) is set.
|
|
228
229
|
For NVIDIA on DeepSeek V4 Flash/Pro, use `deepseekV4Flash({ mix: { nvidia: true } })` or `deepseekV4Pro({ mix: { nvidia: true } })`.
|
|
229
230
|
For Together on Qwen 3.6 Plus, use `qwen36plus({ mix: { fireworks: false, together: true } })`.
|
|
230
231
|
For OpenRouter on Qwen 3.7 Plus, use `qwen37plus({ mix: { fireworks: false, openrouter: true } })`.
|
package/demo/free.js
CHANGED
package/effort.js
CHANGED
|
@@ -105,6 +105,39 @@ const PROVIDER_FAMILY_BY_CLASS = {
|
|
|
105
105
|
MixCustom: null,
|
|
106
106
|
};
|
|
107
107
|
|
|
108
|
+
/** Logical alias from `.grok420()` — resolved to reasoning / non-reasoning at request time. */
|
|
109
|
+
const GROK420_ALIAS = 'grok-4.20-0309';
|
|
110
|
+
const GROK420_REASONING = 'grok-4.20-0309-reasoning';
|
|
111
|
+
const GROK420_NON_REASONING = 'grok-4.20-0309-non-reasoning';
|
|
112
|
+
|
|
113
|
+
function isGrok420Alias(modelKey) {
|
|
114
|
+
return modelKey === GROK420_ALIAS;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Pick Grok 4.20 concrete model from unified effort (and native reasoning_effort).
|
|
119
|
+
* - no effort / OpenAI band `none` (0–19) / native `none` → non-reasoning
|
|
120
|
+
* - effort -1 or 20–100 / native non-none reasoning_effort → reasoning
|
|
121
|
+
*/
|
|
122
|
+
function resolveGrok420ModelKey(modelKey, effort, options = {}) {
|
|
123
|
+
if (!isGrok420Alias(modelKey)) return modelKey;
|
|
124
|
+
|
|
125
|
+
const native = options.reasoning_effort;
|
|
126
|
+
if (native != null && native !== '') {
|
|
127
|
+
return native === 'none' ? GROK420_NON_REASONING : GROK420_REASONING;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (effort === undefined || effort === null) {
|
|
131
|
+
return GROK420_NON_REASONING;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const normalized = normalizeEffort(effort);
|
|
135
|
+
if (normalized === -1) return GROK420_REASONING;
|
|
136
|
+
|
|
137
|
+
const level = levelFromBands(normalized, OPENAI_BANDS);
|
|
138
|
+
return level === 'none' ? GROK420_NON_REASONING : GROK420_REASONING;
|
|
139
|
+
}
|
|
140
|
+
|
|
108
141
|
function normalizeEffort(value) {
|
|
109
142
|
if (typeof value !== 'number' || !Number.isFinite(value) || !Number.isInteger(value)) {
|
|
110
143
|
throw new Error(`Invalid effort: expected integer -1 or 0..100, got ${JSON.stringify(value)}`);
|
|
@@ -332,6 +365,10 @@ function mapEffort(providerFamily, effort, modelKey) {
|
|
|
332
365
|
if (isMiniMax(modelKey)) {
|
|
333
366
|
return mapMiniMaxEffort(normalized);
|
|
334
367
|
}
|
|
368
|
+
// Non-reasoning Grok 4.20 has no reasoning_effort control
|
|
369
|
+
if (modelKey === GROK420_NON_REASONING) {
|
|
370
|
+
return null;
|
|
371
|
+
}
|
|
335
372
|
const desired = levelFromBands(normalized, OPENAI_BANDS);
|
|
336
373
|
const level = pickNearestLevel(desired, OPENAI_LEVELS, supportedOpenAILevels(modelKey));
|
|
337
374
|
return { reasoning_effort: level };
|
|
@@ -409,6 +446,8 @@ module.exports = {
|
|
|
409
446
|
applyUnifiedEffort,
|
|
410
447
|
hasNativeEffort,
|
|
411
448
|
resolveProviderFamily,
|
|
449
|
+
resolveGrok420ModelKey,
|
|
450
|
+
isGrok420Alias,
|
|
412
451
|
isDeepSeekV4,
|
|
413
452
|
isMiniMax,
|
|
414
453
|
usesAnthropicAdaptiveThinking,
|
|
@@ -423,4 +462,7 @@ module.exports = {
|
|
|
423
462
|
GEMINI_LEVELS,
|
|
424
463
|
DEEPSEEK_LEVELS,
|
|
425
464
|
ANTHROPIC_MANUAL_BUDGET_MAX,
|
|
465
|
+
GROK420_ALIAS,
|
|
466
|
+
GROK420_REASONING,
|
|
467
|
+
GROK420_NON_REASONING,
|
|
426
468
|
};
|
package/index.d.ts
CHANGED
|
@@ -313,7 +313,7 @@ export declare class ModelMix {
|
|
|
313
313
|
grok45(args?: ModelAttachArgs): this;
|
|
314
314
|
grok43(args?: ModelAttachArgs): this;
|
|
315
315
|
grok420multiAgent(args?: ModelAttachArgs): this;
|
|
316
|
-
|
|
316
|
+
/** Non-reasoning by default; with `.effort(20+)` / `-1` uses the reasoning model at request time. */
|
|
317
317
|
grok420(args?: ModelAttachArgs): this;
|
|
318
318
|
|
|
319
319
|
// Multi-provider
|
|
@@ -322,10 +322,10 @@ export declare class ModelMix {
|
|
|
322
322
|
qwen37plus(args?: ModelAttachArgs): this;
|
|
323
323
|
qwen38max(args?: ModelAttachArgs): this;
|
|
324
324
|
hermes3(args?: ModelAttachArgs): this;
|
|
325
|
-
|
|
325
|
+
kimiK26(args?: ModelAttachArgs): this;
|
|
326
326
|
kimiK27Code(args?: ModelAttachArgs): this;
|
|
327
327
|
kimiK3(args?: ModelAttachArgs): this;
|
|
328
|
-
|
|
328
|
+
kimiK25(args?: ModelAttachArgs): this;
|
|
329
329
|
lmstudio(model?: string, args?: ModelAttachArgs): this;
|
|
330
330
|
minimaxM25(args?: ModelAttachArgs): this;
|
|
331
331
|
minimaxM27(args?: ModelAttachArgs): this;
|
package/index.js
CHANGED
|
@@ -23,7 +23,8 @@ const {
|
|
|
23
23
|
const {
|
|
24
24
|
normalizeEffort,
|
|
25
25
|
applyUnifiedEffort,
|
|
26
|
-
resolveProviderFamily
|
|
26
|
+
resolveProviderFamily,
|
|
27
|
+
resolveGrok420ModelKey
|
|
27
28
|
} = require('./effort');
|
|
28
29
|
|
|
29
30
|
const DEFAULT_RETRYABLE_STATUS_CODES = [408, 425, 429, 500, 502, 503, 504, 529];
|
|
@@ -88,6 +89,7 @@ const MODEL_PRICING = {
|
|
|
88
89
|
'grok-4.5': [2.00, 6.00],
|
|
89
90
|
'grok-4.3': [1.25, 2.50],
|
|
90
91
|
'grok-4.20-multi-agent-0309': [1.25, 2.50],
|
|
92
|
+
'grok-4.20-0309': [1.25, 2.50],
|
|
91
93
|
'grok-4.20-0309-reasoning': [1.25, 2.50],
|
|
92
94
|
'grok-4.20-0309-non-reasoning': [1.25, 2.50],
|
|
93
95
|
// Fireworks
|
|
@@ -449,11 +451,9 @@ class ModelMix {
|
|
|
449
451
|
grok420multiAgent({ options = {}, config = {} } = {}) {
|
|
450
452
|
return this.attach('grok-4.20-multi-agent-0309', new MixGrok({ options, config }));
|
|
451
453
|
}
|
|
452
|
-
|
|
453
|
-
return this.attach('grok-4.20-0309-reasoning', new MixGrok({ options, config }));
|
|
454
|
-
}
|
|
454
|
+
/** Non-reasoning by default; with `.effort(20+)` / `-1` resolves to the reasoning model at request time. */
|
|
455
455
|
grok420({ options = {}, config = {} } = {}) {
|
|
456
|
-
return this.attach('grok-4.20-0309
|
|
456
|
+
return this.attach('grok-4.20-0309', new MixGrok({ options, config }));
|
|
457
457
|
}
|
|
458
458
|
|
|
459
459
|
qwen3({ options = {}, config = {}, mix = { together: true, cerebras: false } } = {}) {
|
|
@@ -489,7 +489,7 @@ class ModelMix {
|
|
|
489
489
|
return this;
|
|
490
490
|
}
|
|
491
491
|
|
|
492
|
-
|
|
492
|
+
kimiK26({ options = {}, config = {}, mix = { fireworks: true } } = {}) {
|
|
493
493
|
mix = { ...this.mix, ...mix };
|
|
494
494
|
if (mix.fireworks) this.attach('accounts/fireworks/models/kimi-k2p6', new MixFireworks({ options, config }));
|
|
495
495
|
if (mix.openrouter) this.attach('moonshotai/kimi-k2.6', new MixOpenRouter({ options, config }));
|
|
@@ -510,7 +510,7 @@ class ModelMix {
|
|
|
510
510
|
return this;
|
|
511
511
|
}
|
|
512
512
|
|
|
513
|
-
|
|
513
|
+
kimiK25({ options = {}, config = {}, mix = { together: true } } = {}) {
|
|
514
514
|
mix = { ...this.mix, ...mix };
|
|
515
515
|
if (mix.together) this.attach('moonshotai/Kimi-K2.5', new MixTogether({ options, config }));
|
|
516
516
|
if (mix.fireworks) this.attach('accounts/fireworks/models/kimi-k2p5', new MixFireworks({ options, config }));
|
|
@@ -991,9 +991,17 @@ class ModelMix {
|
|
|
991
991
|
}
|
|
992
992
|
};
|
|
993
993
|
|
|
994
|
+
// Grok 4.20 alias → reasoning / non-reasoning from unified effort
|
|
995
|
+
const resolvedModelKey = resolveGrok420ModelKey(
|
|
996
|
+
currentModelKey,
|
|
997
|
+
currentConfig.effort,
|
|
998
|
+
currentOptions
|
|
999
|
+
);
|
|
1000
|
+
currentOptions.model = resolvedModelKey;
|
|
1001
|
+
|
|
994
1002
|
// Unified effort → native provider fields (skipped if native already set)
|
|
995
1003
|
const providerFamily = resolveProviderFamily(providerInstance);
|
|
996
|
-
applyUnifiedEffort(currentOptions, currentConfig, providerFamily,
|
|
1004
|
+
applyUnifiedEffort(currentOptions, currentConfig, providerFamily, resolvedModelKey);
|
|
997
1005
|
|
|
998
1006
|
if (currentConfig.debug >= 1) {
|
|
999
1007
|
const isPrimary = i === 0;
|
|
@@ -1003,7 +1011,7 @@ class ModelMix {
|
|
|
1003
1011
|
: ' (fallback)';
|
|
1004
1012
|
// Extract provider name from class name (e.g., "MixOpenRouter" -> "openrouter")
|
|
1005
1013
|
const providerName = providerInstance.constructor.name.replace(/^Mix/, '').toLowerCase();
|
|
1006
|
-
const header = `\n${prefix} [${providerName}:${
|
|
1014
|
+
const header = `\n${prefix} [${providerName}:${resolvedModelKey}] #${originalIndex + 1}${suffix}`;
|
|
1007
1015
|
|
|
1008
1016
|
if (currentConfig.debug >= 2) {
|
|
1009
1017
|
console.log(`${header}\n${ModelMix.formatInputSummary(this.messages, currentConfig.system, currentConfig.debug)}`);
|
|
@@ -1048,7 +1056,7 @@ class ModelMix {
|
|
|
1048
1056
|
if (currentConfig.debug >= 1) {
|
|
1049
1057
|
const nextAttempt = attempt + 2;
|
|
1050
1058
|
const totalAttempts = retries + 1;
|
|
1051
|
-
console.log(`↺ Retrying [${
|
|
1059
|
+
console.log(`↺ Retrying [${resolvedModelKey}] due to status ${statusCode} (${nextAttempt}/${totalAttempts})`);
|
|
1052
1060
|
}
|
|
1053
1061
|
|
|
1054
1062
|
const delay = Math.min(baseDelayMs * Math.pow(2, attempt), maxDelayMs);
|
|
@@ -1060,7 +1068,7 @@ class ModelMix {
|
|
|
1060
1068
|
const elapsedMs = Date.now() - startTime;
|
|
1061
1069
|
|
|
1062
1070
|
if (result.tokens) {
|
|
1063
|
-
result.tokens.cost = ModelMix.calculateCost(
|
|
1071
|
+
result.tokens.cost = ModelMix.calculateCost(resolvedModelKey, result.tokens);
|
|
1064
1072
|
const elapsedSec = elapsedMs / 1000;
|
|
1065
1073
|
result.tokens.speed = elapsedSec > 0 ? Math.round(result.tokens.output / elapsedSec) : 0;
|
|
1066
1074
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "modelmix",
|
|
3
|
-
"version": "4.7.
|
|
3
|
+
"version": "4.7.2",
|
|
4
4
|
"description": "🧬 Reliable interface with automatic fallback for AI LLMs.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -72,6 +72,6 @@
|
|
|
72
72
|
"test:live": "mocha test/live.test.js --timeout 10000 --require test/setup.js",
|
|
73
73
|
"test:live.mcp": "mocha test/live.mcp.js --timeout 60000 --require test/setup.js",
|
|
74
74
|
"test:tokens": "mocha test/tokens.test.js --timeout 10000 --require test/setup.js",
|
|
75
|
-
"test:offline": "mocha test/json.test.js test/fallback.test.js test/templates.test.js test/images.test.js test/bottleneck.test.js test/tokens.test.js test/history.test.js test/anthropic.test.js test/effort.test.js --timeout 10000 --require test/setup.js"
|
|
75
|
+
"test:offline": "mocha test/json.test.js test/fallback.test.js test/templates.test.js test/images.test.js test/bottleneck.test.js test/tokens.test.js test/history.test.js test/anthropic.test.js test/effort.test.js test/grok.test.js --timeout 10000 --require test/setup.js"
|
|
76
76
|
}
|
|
77
77
|
}
|
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`. 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
|
|
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 `*think()` methods are removed — use `.effort(n).<model>()`. Kimi: `kimiK25()` / `kimiK26()`. Grok 4.20: `.grok420()` non-reasoning; `.effort(20+|-1).grok420()` selects reasoning.
|
|
118
118
|
|
|
119
119
|
## Available Model Shorthands
|
|
120
120
|
|
|
@@ -130,13 +130,13 @@ Use `.effort(n)` (or `config.effort`) to enable Anthropic thinking — e.g. `.ef
|
|
|
130
130
|
`gemini3pro()` `gemini3flash()` `gemini36flash()` `gemini35flash()` `gemini25pro()` `gemini25flash()`
|
|
131
131
|
|
|
132
132
|
### Grok
|
|
133
|
-
`grok45()` `grok43()` `grok420multiAgent()` `grok420()`
|
|
133
|
+
`grok45()` `grok43()` `grok420multiAgent()` `grok420()`
|
|
134
134
|
|
|
135
135
|
### Perplexity
|
|
136
136
|
`sonar()` `sonarPro()`
|
|
137
137
|
|
|
138
138
|
### Together
|
|
139
|
-
`qwen36plus()` `GLM52()` `
|
|
139
|
+
`qwen36plus()` `GLM52()` `kimiK25()` `kimiK26()` `gptOss()`
|
|
140
140
|
|
|
141
141
|
### Moonshot
|
|
142
142
|
`kimiK3()` — requires `MOONSHOT_API_KEY`; use `{ mix: { moonshot: false, openrouter: true } }` for OpenRouter.
|
|
@@ -145,7 +145,7 @@ Use `.effort(n)` (or `config.effort`) to enable Anthropic thinking — e.g. `.ef
|
|
|
145
145
|
`minimaxM25()` `minimaxM27()` `minimaxM3()`
|
|
146
146
|
|
|
147
147
|
### Fireworks
|
|
148
|
-
`qwen36plus()` `qwen37plus()` `deepseekV4Flash()` `deepseekV4Pro()`
|
|
148
|
+
`qwen36plus()` `qwen37plus()` `deepseekV4Flash()` `deepseekV4Pro()` `kimiK26()`
|
|
149
149
|
|
|
150
150
|
### Cerebras
|
|
151
151
|
`GLM46()`
|
|
@@ -154,7 +154,7 @@ Use `.effort(n)` (or `config.effort`) to enable Anthropic thinking — e.g. `.ef
|
|
|
154
154
|
`qwen38max()` `GLM45()`
|
|
155
155
|
|
|
156
156
|
### Multi-provider (auto-fallback across free/paid tiers)
|
|
157
|
-
`hermes3()` `
|
|
157
|
+
`hermes3()` `kimiK25()`
|
|
158
158
|
|
|
159
159
|
### Local
|
|
160
160
|
`lmstudio()` — for LM Studio local models
|
|
@@ -429,7 +429,7 @@ For full debug output, also set: `DEBUG=ModelMix* node script.js`
|
|
|
429
429
|
```javascript
|
|
430
430
|
const model = ModelMix.new()
|
|
431
431
|
.gptOss()
|
|
432
|
-
.
|
|
432
|
+
.kimiK25()
|
|
433
433
|
.hermes3()
|
|
434
434
|
.addText("What is the capital of France?");
|
|
435
435
|
console.log(await model.message());
|
|
@@ -452,7 +452,7 @@ const model = ModelMix.new({
|
|
|
452
452
|
minimax: false, // default: false
|
|
453
453
|
fireworks: false // default: false
|
|
454
454
|
}
|
|
455
|
-
}).
|
|
455
|
+
}).kimiK25();
|
|
456
456
|
```
|
|
457
457
|
|
|
458
458
|
## Agent Usage Rules
|
package/test/grok.test.js
CHANGED
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
const { expect } = require('chai');
|
|
2
2
|
const { ModelMix } = require('../index.js');
|
|
3
|
+
const {
|
|
4
|
+
resolveGrok420ModelKey,
|
|
5
|
+
GROK420_ALIAS,
|
|
6
|
+
GROK420_REASONING,
|
|
7
|
+
GROK420_NON_REASONING
|
|
8
|
+
} = require('../effort.js');
|
|
3
9
|
|
|
4
10
|
describe('Grok Model Registration Tests', () => {
|
|
5
11
|
const grokModels = [
|
|
6
12
|
{ method: 'grok45', key: 'grok-4.5' },
|
|
7
13
|
{ method: 'grok43', key: 'grok-4.3' },
|
|
8
14
|
{ method: 'grok420multiAgent', key: 'grok-4.20-multi-agent-0309' },
|
|
9
|
-
{ method: '
|
|
10
|
-
{ method: 'grok420', key: 'grok-4.20-0309-non-reasoning' }
|
|
15
|
+
{ method: 'grok420', key: GROK420_ALIAS }
|
|
11
16
|
];
|
|
12
17
|
|
|
13
18
|
for (const grokModel of grokModels) {
|
|
@@ -20,3 +25,34 @@ describe('Grok Model Registration Tests', () => {
|
|
|
20
25
|
});
|
|
21
26
|
}
|
|
22
27
|
});
|
|
28
|
+
|
|
29
|
+
describe('Grok 4.20 effort → model resolution', () => {
|
|
30
|
+
it('uses non-reasoning when effort is unset', () => {
|
|
31
|
+
expect(resolveGrok420ModelKey(GROK420_ALIAS, undefined)).to.equal(GROK420_NON_REASONING);
|
|
32
|
+
expect(resolveGrok420ModelKey(GROK420_ALIAS, null)).to.equal(GROK420_NON_REASONING);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('uses non-reasoning for OpenAI none band (0–19)', () => {
|
|
36
|
+
expect(resolveGrok420ModelKey(GROK420_ALIAS, 0)).to.equal(GROK420_NON_REASONING);
|
|
37
|
+
expect(resolveGrok420ModelKey(GROK420_ALIAS, 19)).to.equal(GROK420_NON_REASONING);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('uses reasoning for effort 20–100 and -1', () => {
|
|
41
|
+
expect(resolveGrok420ModelKey(GROK420_ALIAS, 20)).to.equal(GROK420_REASONING);
|
|
42
|
+
expect(resolveGrok420ModelKey(GROK420_ALIAS, 50)).to.equal(GROK420_REASONING);
|
|
43
|
+
expect(resolveGrok420ModelKey(GROK420_ALIAS, 100)).to.equal(GROK420_REASONING);
|
|
44
|
+
expect(resolveGrok420ModelKey(GROK420_ALIAS, -1)).to.equal(GROK420_REASONING);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('honors native reasoning_effort over config.effort', () => {
|
|
48
|
+
expect(resolveGrok420ModelKey(GROK420_ALIAS, 0, { reasoning_effort: 'high' }))
|
|
49
|
+
.to.equal(GROK420_REASONING);
|
|
50
|
+
expect(resolveGrok420ModelKey(GROK420_ALIAS, 100, { reasoning_effort: 'none' }))
|
|
51
|
+
.to.equal(GROK420_NON_REASONING);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('leaves non-alias keys unchanged', () => {
|
|
55
|
+
expect(resolveGrok420ModelKey(GROK420_REASONING, 50)).to.equal(GROK420_REASONING);
|
|
56
|
+
expect(resolveGrok420ModelKey('grok-4.3', 50)).to.equal('grok-4.3');
|
|
57
|
+
});
|
|
58
|
+
});
|
package/test/live.test.js
CHANGED
|
@@ -194,8 +194,8 @@ describe('Live Integration Tests', function () {
|
|
|
194
194
|
|
|
195
195
|
const grokSeriesTests = [
|
|
196
196
|
{ name: 'Grok 4.3', factory: (m) => m.grok43(), token: 'grok43' },
|
|
197
|
-
{ name: 'Grok 4.20 reasoning', factory: (m) => m.
|
|
198
|
-
{ name: 'Grok 4.20 non-reasoning', factory: (m) => m.grok420(), token: '
|
|
197
|
+
{ name: 'Grok 4.20 reasoning', factory: (m) => m.effort(50).grok420(), token: 'grok420' },
|
|
198
|
+
{ name: 'Grok 4.20 non-reasoning', factory: (m) => m.grok420(), token: 'grok420nr' }
|
|
199
199
|
];
|
|
200
200
|
|
|
201
201
|
for (const grokModel of grokSeriesTests) {
|
|
@@ -242,7 +242,7 @@ describe('Live Integration Tests', function () {
|
|
|
242
242
|
describe('JSON Structured Output for New Models', function () {
|
|
243
243
|
|
|
244
244
|
it('should return structured JSON with KimiK25 Thinking', async function () {
|
|
245
|
-
const model = ModelMix.new(setup).
|
|
245
|
+
const model = ModelMix.new(setup).kimiK25();
|
|
246
246
|
|
|
247
247
|
model.addText('Generate information about a fictional vehicle.');
|
|
248
248
|
|