modelmix 5.0.5 → 5.0.6

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 CHANGED
@@ -175,17 +175,20 @@ Here's a comprehensive list of available methods:
175
175
  | `grok43()` | Grok | grok-4.3 | [\$1.25/\$2.50][6] |
176
176
  | `grok420multiAgent()`| Grok | grok-4.20-multi-agent-0309 | [\$1.25/\$2.50][6] |
177
177
  | `grok420()` | Grok | grok-4.20-0309 (†) | [\$1.25/\$2.50][6] |
178
+ | `qwen35397b()` | OpenRouter | qwen/qwen3.5-397b-a17b | [\$0.385/\$2.45][14] |
178
179
  | `qwen36plus()` | Fireworks | qwen3p6-plus | [\$0.50/\$3.00][10] |
179
180
  | `qwen37plus()` | Fireworks | models/qwen3p7-plus | [\$0.40/\$1.60][10] |
180
- | `qwen38max()` | OpenRouter | qwen/qwen3.8-max | [\$2.00/\$6.00][12] |
181
+ | `qwen38max()` | Fireworks | qwen3p8-2p4t-a95b | [\$2.00/\$6.00][10] |
181
182
  | `deepseekV4Flash()` | Fireworks | models/deepseek-v4-flash | [\$0.14/\$0.28][10] |
182
- | `deepseekV4Pro()` | Fireworks | models/deepseek-v4-pro | [\$1.74/\$3.48][10] |
183
+ | `deepseekV4Pro()` | Fireworks | models/deepseek-v4-pro-0813 | [\$1.32/\$3.96][12] |
183
184
  | `GLM52()` | Together | zai-org/GLM-5.2 | [\$1.40/\$4.40][7] |
184
185
  | `GLM51()` | Fireworks | models/glm-5p1 | [\$1.05/\$3.50][10] |
185
186
  | `minimaxM3()` | MiniMax | MiniMax-M3 | [\$0.30/\$1.20][9] |
186
187
  | `minimaxM27()` | MiniMax | MiniMax-M2.7 | [\$0.30/\$1.20][9] |
187
188
  | `sonar()` | Perplexity | sonar | [\$1.00/\$1.00][4] |
188
189
  | `sonarPro()` | Perplexity | sonar-pro | [\$3.00/\$15.00][4] |
190
+ | `hermes470b()` | OpenRouter | nousresearch/hermes-4-70b | [\$0.13/\$0.40][13] |
191
+ | `hermes4405b()` | OpenRouter | nousresearch/hermes-4-405b | [\$1.00/\$3.00][13] |
189
192
  | `hermes3()` | Lambda | Hermes-3-Llama-3.1-405B-FP8 | [\$0.80/\$0.80][8] |
190
193
  | `kimiK3()` | Moonshot | kimi-k3 | [\$3.00/\$15.00][11] |
191
194
  | `kimiK25()` | Together | Kimi-K2.5 | [\$0.50/\$2.80][7] |
@@ -204,7 +207,9 @@ Gemini 3.7 Flash and 3.6 Flash use Google's introductory standard pricing throug
204
207
  [9]: https://platform.minimax.io/docs/api-reference/anthropic-api-compatible-cache#supported-models-and-pricing "MiniMax Pricing"
205
208
  [10]: https://fireworks.ai/pricing#serverless-pricing "Fireworks Pricing"
206
209
  [11]: https://platform.kimi.ai/docs/guide/kimi-k3-pricing "Kimi K3 Pricing"
207
- [12]: https://openrouter.ai/qwen/qwen3.8-max "OpenRouter Pricing"
210
+ [12]: https://fireworks.ai/models/deepseek-ai/deepseek-v4-pro-0813 "DeepSeek V4 Pro 0813 Pricing"
211
+ [13]: https://openrouter.ai/nousresearch "Nous Research Models on OpenRouter"
212
+ [14]: https://openrouter.ai/qwen/qwen3.5-397b-a17b "Qwen3.5 397B A17B on OpenRouter"
208
213
 
209
214
  Each method accepts optional `options`, `config`, and (for multi-provider methods) `mix` parameters to customize behavior.
210
215
 
package/demo/short.js CHANGED
@@ -14,6 +14,9 @@ const mmix = await ModelMix.new(setup)
14
14
  .gemini37flash() // (fallback 2) Google gemini-3.7-flash
15
15
  .gpt41nano() // (fallback 3) OpenAI gpt-4.1-nano
16
16
  .grok46() // (fallback 4) Grok grok-4.6
17
+ .qwen35397b() // (fallback 5) OpenRouter qwen/qwen3.5-397b-a17b
18
+ .hermes470b() // (fallback 6) OpenRouter nousresearch/hermes-4-70b
19
+ .hermes4405b() // (fallback 7) OpenRouter nousresearch/hermes-4-405b
17
20
  .addText("What's your name?");
18
21
 
19
22
  console.log(await mmix.message());
package/effort.js CHANGED
@@ -35,6 +35,7 @@ const GEMINI_BANDS = [
35
35
 
36
36
  /** Exact model → supported OpenAI reasoning_effort values */
37
37
  const OPENAI_MODEL_LEVELS = {
38
+ 'accounts/fireworks/models/qwen3p8-2p4t-a95b': ['none', 'low', 'medium', 'high'],
38
39
  'grok-4.6': ['low', 'medium', 'high', 'xhigh'],
39
40
  'gpt-5': ['minimal', 'low', 'medium', 'high'],
40
41
  'gpt-5-mini': ['minimal', 'low', 'medium', 'high'],
package/index.d.ts CHANGED
@@ -504,9 +504,12 @@ export declare class ModelMix {
504
504
 
505
505
  // Multi-provider
506
506
  qwen3(args?: ModelAttachArgs): this;
507
+ qwen35397b(args?: ModelAttachArgs): this;
507
508
  qwen36plus(args?: ModelAttachArgs): this;
508
509
  qwen37plus(args?: ModelAttachArgs): this;
509
510
  qwen38max(args?: ModelAttachArgs): this;
511
+ hermes470b(args?: ModelAttachArgs): this;
512
+ hermes4405b(args?: ModelAttachArgs): this;
510
513
  hermes3(args?: ModelAttachArgs): this;
511
514
  kimiK26(args?: ModelAttachArgs): this;
512
515
  kimiK27Code(args?: ModelAttachArgs): this;
package/index.js CHANGED
@@ -362,6 +362,7 @@ const MODEL_PRICING = {
362
362
  // Fireworks
363
363
  'accounts/fireworks/models/deepseek-v4-flash': { input: 0.14, output: 0.28 },
364
364
  'accounts/fireworks/models/deepseek-v4-pro': { input: 1.74, output: 3.48 },
365
+ 'accounts/fireworks/models/deepseek-v4-pro-0813': { input: 1.32, cachedInput: 0.044, output: 3.96 },
365
366
  'deepseek-ai/DeepSeek-V4-Flash': { input: 0.14, output: 0.28 },
366
367
  'deepseek-ai/DeepSeek-V4-Pro': { input: 2.10, output: 4.40 },
367
368
  'deepseek/deepseek-v4-flash': { input: 0.09, output: 0.18 },
@@ -369,10 +370,12 @@ const MODEL_PRICING = {
369
370
  'accounts/fireworks/models/glm-5p1': { input: 1.05, output: 3.50 },
370
371
  'zai-org/GLM-5.2': { input: 1.40, output: 4.40 },
371
372
  'accounts/fireworks/models/kimi-k2p5': { input: 0.50, output: 2.80 },
373
+ 'qwen/qwen3.5-397b-a17b': { input: 0.385, output: 2.45 },
372
374
  'accounts/fireworks/models/qwen3p6-plus': { input: 0.50, output: 3.00 },
373
375
  'Qwen/Qwen3.6-Plus': { input: 0.50, output: 3.00 },
374
376
  'accounts/fireworks/models/qwen3p7-plus': { input: 0.40, output: 1.60 },
375
377
  'qwen/qwen3.7-plus': { input: 0.32, output: 1.28 },
378
+ 'accounts/fireworks/models/qwen3p8-2p4t-a95b': { input: 2.00, cachedInput: 0.25, output: 6.00 },
376
379
  'qwen/qwen3.8-max': { input: 2.00, output: 6.00 },
377
380
  // MiniMax
378
381
  'MiniMax-M2.5': { input: 0.30, output: 1.20 },
@@ -384,7 +387,10 @@ const MODEL_PRICING = {
384
387
  // Perplexity
385
388
  'sonar': { input: 1.00, output: 1.00 },
386
389
  'sonar-pro': { input: 3.00, output: 15.00 },
387
- // Hermes3 (Lambda/OpenRouter)
390
+ // Hermes 4 (OpenRouter)
391
+ 'nousresearch/hermes-4-70b': { input: 0.13, output: 0.40 },
392
+ 'nousresearch/hermes-4-405b': { input: 1.00, output: 3.00 },
393
+ // Hermes 3 (Lambda/OpenRouter)
388
394
  'Hermes-3-Llama-3.1-405B-FP8': { input: 0.80, output: 0.80 },
389
395
  'nousresearch/hermes-3-llama-3.1-405b:free': { input: 0, output: 0 },
390
396
  // Qwen3 (Together/Cerebras)
@@ -412,7 +418,8 @@ const CHAIN_MODEL_SHORTCUTS = new Set([
412
418
  'gemini37flash', 'gemini36flash', 'gemini35flash', 'gemini35flashLite',
413
419
  'gemini31flashLite', 'gemini25pro', 'sonarPro', 'sonar',
414
420
  'grok46', 'grok45', 'grok43', 'grok420multiAgent', 'grok420',
415
- 'qwen3', 'qwen36plus', 'qwen37plus', 'qwen38max', 'hermes3',
421
+ 'qwen3', 'qwen35397b', 'qwen36plus', 'qwen37plus', 'qwen38max',
422
+ 'hermes470b', 'hermes4405b', 'hermes3',
416
423
  'kimiK26', 'kimiK27Code', 'kimiK3', 'kimiK25',
417
424
  'minimaxM25', 'minimaxM27', 'minimaxM3', 'mimo25', 'mimo25pro',
418
425
  'deepseekV4Pro', 'deepseekV4Flash', 'GLM51', 'GLM52'
@@ -1090,6 +1097,10 @@ class ModelMix {
1090
1097
  return this;
1091
1098
  }
1092
1099
 
1100
+ qwen35397b({ options = {}, config = {} } = {}) {
1101
+ return this.attach('qwen/qwen3.5-397b-a17b', new MixOpenRouter({ options, config }));
1102
+ }
1103
+
1093
1104
  qwen36plus({ options = {}, config = {}, mix = { fireworks: true } } = {}) {
1094
1105
  mix = { ...this.mix, ...mix };
1095
1106
  if (mix.fireworks) this.attach('accounts/fireworks/models/qwen3p6-plus', new MixFireworks({ options, config }));
@@ -1104,12 +1115,21 @@ class ModelMix {
1104
1115
  return this;
1105
1116
  }
1106
1117
 
1107
- qwen38max({ options = {}, config = {}, mix = { openrouter: true } } = {}) {
1118
+ qwen38max({ options = {}, config = {}, mix = { fireworks: true } } = {}) {
1108
1119
  mix = { ...this.mix, ...mix };
1120
+ if (mix.fireworks) this.attach('accounts/fireworks/models/qwen3p8-2p4t-a95b', new MixFireworks({ options, config }));
1109
1121
  if (mix.openrouter) this.attach('qwen/qwen3.8-max', new MixOpenRouter({ options, config }));
1110
1122
  return this;
1111
1123
  }
1112
1124
 
1125
+ hermes470b({ options = {}, config = {} } = {}) {
1126
+ return this.attach('nousresearch/hermes-4-70b', new MixOpenRouter({ options, config }));
1127
+ }
1128
+
1129
+ hermes4405b({ options = {}, config = {} } = {}) {
1130
+ return this.attach('nousresearch/hermes-4-405b', new MixOpenRouter({ options, config }));
1131
+ }
1132
+
1113
1133
  hermes3({ options = {}, config = {}, mix = {} } = {}) {
1114
1134
  mix = { ...this.mix, ...mix };
1115
1135
  if (mix.lambda) this.attach('Hermes-3-Llama-3.1-405B-FP8', new MixLambda({ options, config }));
@@ -1191,7 +1211,7 @@ class ModelMix {
1191
1211
  deepseekV4Pro({ options = {}, config = {}, mix = { fireworks: true } } = {}) {
1192
1212
  mix = { ...this.mix, ...mix };
1193
1213
  if (mix.nvidia) this.attach('deepseek-ai/deepseek-v4-pro', new MixNVIDIA({ options, config }));
1194
- if (mix.fireworks) this.attach('accounts/fireworks/models/deepseek-v4-pro', new MixFireworks({ options, config }));
1214
+ if (mix.fireworks) this.attach('accounts/fireworks/models/deepseek-v4-pro-0813', new MixFireworks({ options, config }));
1195
1215
  if (mix.openrouter) this.attach('deepseek/deepseek-v4-pro', new MixOpenRouter({ options, config }));
1196
1216
  if (mix.together) this.attach('deepseek-ai/DeepSeek-V4-Pro', new MixTogether({ options, config }));
1197
1217
  return this;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "modelmix",
3
- "version": "5.0.5",
3
+ "version": "5.0.6",
4
4
  "description": "🧬 Reliable interface with automatic fallback for AI LLMs.",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -177,13 +177,13 @@ Use `.effort(n)` (or `config.effort`) to enable Anthropic thinking — e.g. `.ef
177
177
  `minimaxM25()` `minimaxM27()` `minimaxM3()`
178
178
 
179
179
  ### Fireworks
180
- `qwen36plus()` `qwen37plus()` `deepseekV4Flash()` `deepseekV4Pro()` `kimiK26()`
180
+ `qwen36plus()` `qwen37plus()` `qwen38max()` `deepseekV4Flash()` `deepseekV4Pro()` `kimiK26()`
181
181
 
182
182
  ### Cerebras
183
183
  `GLM46()`
184
184
 
185
185
  ### OpenRouter
186
- `qwen38max()` `GLM45()`
186
+ `qwen35397b()` `hermes470b()` `hermes4405b()` `qwen38max()` `GLM45()`
187
187
 
188
188
  ### Multi-provider (auto-fallback across free/paid tiers)
189
189
  `hermes3()` `kimiK25()`
@@ -7,7 +7,12 @@ describe('DeepSeek Model Registration Tests', () => {
7
7
  model.deepseekV4Pro({ mix: { fireworks: true, openrouter: false } });
8
8
 
9
9
  expect(model.models).to.have.length(1);
10
- expect(model.models[0].key).to.equal('accounts/fireworks/models/deepseek-v4-pro');
10
+ expect(model.models[0].key).to.equal('accounts/fireworks/models/deepseek-v4-pro-0813');
11
+ expect(ModelMix.calculateCost('accounts/fireworks/models/deepseek-v4-pro-0813', {
12
+ input: 1_000_000,
13
+ cached: 250_000,
14
+ output: 1_000_000
15
+ })).to.be.closeTo(4.961, 1e-10);
11
16
  });
12
17
 
13
18
  it('should register Together DeepSeek V4 Pro when together mix is enabled', () => {
@@ -81,6 +81,12 @@ 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('clamps Fireworks Qwen 3.8 Max to its supported reasoning levels', () => {
85
+ const key = 'accounts/fireworks/models/qwen3p8-2p4t-a95b';
86
+ expect(mapEffort('openai', 0, key)).to.deep.equal({ reasoning_effort: 'none' });
87
+ expect(mapEffort('openai', 100, key)).to.deep.equal({ reasoning_effort: 'high' });
88
+ });
89
+
84
90
  it('maps Anthropic adaptive models to thinking + output_config.effort', () => {
85
91
  expect(mapEffort('anthropic', 10, 'claude-opus-5')).to.deep.equal({
86
92
  thinking: { type: 'adaptive', display: 'summarized' },
@@ -178,6 +184,10 @@ describe('Unified effort scale', () => {
178
184
  reasoning_effort: 'max',
179
185
  thinking: { type: 'enabled' }
180
186
  });
187
+ expect(mapEffort('openai', 100, 'accounts/fireworks/models/deepseek-v4-pro-0813')).to.deep.equal({
188
+ reasoning_effort: 'max',
189
+ thinking: { type: 'enabled' }
190
+ });
181
191
  // No adaptive control on DeepSeek → no-op
182
192
  expect(mapEffort('openai', -1, 'deepseek/deepseek-v4-flash')).to.equal(null);
183
193
  });
@@ -0,0 +1,37 @@
1
+ const { expect } = require('chai');
2
+ const { ModelMix, MixOpenRouter } = require('../index.js');
3
+
4
+ describe('Hermes Model Registration Tests', () => {
5
+ it('should register Hermes 4 70B through OpenRouter', () => {
6
+ const model = ModelMix.new().hermes470b();
7
+
8
+ expect(model.models).to.have.length(1);
9
+ expect(model.models[0].key).to.equal('nousresearch/hermes-4-70b');
10
+ expect(model.models[0].provider).to.be.instanceOf(MixOpenRouter);
11
+ expect(ModelMix.calculateCost('nousresearch/hermes-4-70b', {
12
+ input: 1_000_000,
13
+ output: 1_000_000
14
+ })).to.equal(0.53);
15
+ });
16
+
17
+ it('should register Hermes 4 405B through OpenRouter', () => {
18
+ const model = ModelMix.new().hermes4405b();
19
+
20
+ expect(model.models).to.have.length(1);
21
+ expect(model.models[0].key).to.equal('nousresearch/hermes-4-405b');
22
+ expect(model.models[0].provider).to.be.instanceOf(MixOpenRouter);
23
+ expect(ModelMix.calculateCost('nousresearch/hermes-4-405b', {
24
+ input: 1_000_000,
25
+ output: 1_000_000
26
+ })).to.equal(4);
27
+ });
28
+
29
+ it('should support both Hermes 4 shortcuts in chain()', () => {
30
+ const model = ModelMix.new().chain('hermes470b', 'hermes4405b');
31
+
32
+ expect(model.models.map(({ key }) => key)).to.deep.equal([
33
+ 'nousresearch/hermes-4-70b',
34
+ 'nousresearch/hermes-4-405b'
35
+ ]);
36
+ });
37
+ });
package/test/qwen.test.js CHANGED
@@ -1,5 +1,5 @@
1
1
  const { expect } = require('chai');
2
- const { ModelMix } = require('../index.js');
2
+ const { ModelMix, MixOpenRouter } = require('../index.js');
3
3
 
4
4
  describe('Qwen Model Registration Tests', () => {
5
5
  it('should register Fireworks Qwen 3.6 Plus by default', () => {
@@ -38,15 +38,45 @@ describe('Qwen Model Registration Tests', () => {
38
38
  expect(model.models[0].key).to.equal('qwen/qwen3.7-plus');
39
39
  });
40
40
 
41
- it('should register OpenRouter Qwen 3.8 Max by default', () => {
41
+ it('should register Fireworks Qwen 3.8 Max before the OpenRouter fallback by default', () => {
42
42
  const model = ModelMix.new();
43
43
  model.qwen38max();
44
44
 
45
+ expect(model.models.map(({ key }) => key)).to.deep.equal([
46
+ 'accounts/fireworks/models/qwen3p8-2p4t-a95b',
47
+ 'qwen/qwen3.8-max'
48
+ ]);
49
+ expect(ModelMix.calculateCost('accounts/fireworks/models/qwen3p8-2p4t-a95b', {
50
+ input: 1_000_000,
51
+ cached: 250_000,
52
+ output: 1_000_000
53
+ })).to.equal(7.5625);
54
+ });
55
+
56
+ it('should register only OpenRouter Qwen 3.8 Max when Fireworks is disabled', () => {
57
+ const model = ModelMix.new();
58
+ model.qwen38max({ mix: { fireworks: false, openrouter: true } });
59
+
45
60
  expect(model.models).to.have.length(1);
46
61
  expect(model.models[0].key).to.equal('qwen/qwen3.8-max');
47
- expect(ModelMix.calculateCost('qwen/qwen3.8-max', {
62
+ });
63
+
64
+ it('should register Qwen 3.5 397B A17B through OpenRouter', () => {
65
+ const model = ModelMix.new().qwen35397b();
66
+
67
+ expect(model.models).to.have.length(1);
68
+ expect(model.models[0].key).to.equal('qwen/qwen3.5-397b-a17b');
69
+ expect(model.models[0].provider).to.be.instanceOf(MixOpenRouter);
70
+ expect(ModelMix.calculateCost('qwen/qwen3.5-397b-a17b', {
48
71
  input: 1_000_000,
49
72
  output: 1_000_000
50
- })).to.equal(8.00);
73
+ })).to.equal(2.835);
74
+ });
75
+
76
+ it('should support Qwen 3.5 397B A17B in chain()', () => {
77
+ const model = ModelMix.new().chain('qwen35397b');
78
+
79
+ expect(model.models).to.have.length(1);
80
+ expect(model.models[0].key).to.equal('qwen/qwen3.5-397b-a17b');
51
81
  });
52
82
  });