modelmix 5.1.2 → 5.1.4

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,8 +175,10 @@ ModelMix provides convenient shorthand methods for quickly accessing different A
175
175
  | `qwen36plus()` | Fireworks | qwen3p6-plus | [\$0.50][10] | [\$3.00][10] |
176
176
  | `qwen37plus()` | Fireworks | models/qwen3p7-plus | [\$0.40][10] | [\$1.60][10] |
177
177
  | `qwen38max()` | Fireworks | qwen3p8-2p4t-a95b | [\$2.00][10] | [\$6.00][10] |
178
+ | `qwen3827b()` | OpenRouter | qwen/qwen3.8-27b | [\$0.45][15] | [\$3.20][15] |
178
179
  | `deepseekV4Flash()` | Fireworks | models/deepseek-v4-flash | [\$0.14][10] | [\$0.28][10] |
179
180
  | `deepseekV4Pro()` | Fireworks | models/deepseek-v4-pro-0813 | [\$1.32][12] | [\$3.96][12] |
181
+ | `GLM53()` | OpenRouter | z-ai/glm-5.3 | [\$1.40][16] | [\$4.40][16] |
180
182
  | `GLM52()` | Together | zai-org/GLM-5.2 | [\$1.40][7] | [\$4.40][7] |
181
183
  | `GLM51()` | Fireworks | models/glm-5p1 | [\$1.05][10] | [\$3.50][10] |
182
184
  | `minimaxM3()` | MiniMax | MiniMax-M3 | [\$0.30][9] | [\$1.20][9] |
@@ -206,6 +208,8 @@ Gemini 3.7 Flash and 3.6 Flash use Google's introductory standard pricing throug
206
208
  [12]: https://fireworks.ai/models/deepseek-ai/deepseek-v4-pro-0813 "DeepSeek V4 Pro 0813 Pricing"
207
209
  [13]: https://openrouter.ai/nousresearch "Nous Research Models on OpenRouter"
208
210
  [14]: https://openrouter.ai/qwen/qwen3.5-397b-a17b "Qwen3.5 397B A17B on OpenRouter"
211
+ [15]: https://openrouter.ai/qwen/qwen3.8-27b "Qwen3.8 27B on OpenRouter"
212
+ [16]: https://openrouter.ai/z-ai/glm-5.3 "GLM 5.3 on OpenRouter"
209
213
 
210
214
  Each method accepts optional `options`, `config`, and (for multi-provider methods) `mix` parameters to customize behavior.
211
215
 
@@ -246,6 +250,8 @@ ModelMix.new().effort(-1).minimaxM3().addText('...').message();
246
250
 
247
251
  - **Gemini:** Gemini 3+ uses bands 0–24 / 25–49 / 50–74 / 75–100. Gemini 3.7 Flash clamps these bands to `low` / `low` / `medium` / `high`; `-1` leaves its native `medium` default unchanged. Gemini 2.5 maps 0–100 to `thinkingBudget`.
248
252
  - **GPT-5.6:** `100` maps to `max`; 80–99 remains `xhigh`.
253
+ - **Qwen 3.8 27B:** 0–39 / 40–79 / 80–100 map to `low` / `medium` / `xhigh`; `-1` leaves the native `xhigh` default unchanged.
254
+ - **GLM 5.3:** reasoning is mandatory; 0–39 / 40–79 / 80–100 map to `low` / `high` / `max`; `-1` leaves the native `max` default unchanged.
249
255
  - **DeepSeek:** `↑` means thinking is enabled; `off` means it is disabled.
250
256
  - **MiniMax:** `off` maps to `thinking.disabled`; `adaptive` maps to `thinking.type=adaptive`.
251
257
  - **Anthropic:** Claude 5, Fable, Opus 4.6+, and Sonnet 4.6+ use adaptive thinking with `output_config.effort`. Sonnet 4.5 and Haiku 4.5 use `thinking.type=enabled` with `budget_tokens`.
package/demo/short.js CHANGED
@@ -15,8 +15,10 @@ const mmix = await ModelMix.new(setup)
15
15
  .gpt5nano() // (fallback 3) OpenAI gpt-5-nano
16
16
  .grok46() // (fallback 4) Grok grok-4.6
17
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
18
+ .qwen3827b() // (fallback 6) OpenRouter qwen/qwen3.8-27b
19
+ .GLM53() // (fallback 7) OpenRouter z-ai/glm-5.3
20
+ .hermes470b() // (fallback 8) OpenRouter nousresearch/hermes-4-70b
21
+ .hermes4405b() // (fallback 9) OpenRouter nousresearch/hermes-4-405b
20
22
  .addText("What's your name?");
21
23
 
22
24
  console.log(await mmix.message());
package/effort.js CHANGED
@@ -34,12 +34,20 @@ const GEMINI_BANDS = [
34
34
  [75, 100, 'high'],
35
35
  ];
36
36
 
37
+ const GLM53_BANDS = [
38
+ [0, 39, 'low'],
39
+ [40, 79, 'high'],
40
+ [80, 100, 'max'],
41
+ ];
42
+
37
43
  /** Exact model → supported OpenAI reasoning_effort values */
38
44
  const OPENAI_MODEL_LEVELS = {
39
45
  'gpt-5.6-sol': ['none', 'low', 'medium', 'high', 'xhigh', 'max'],
40
46
  'gpt-5.6-terra': ['none', 'low', 'medium', 'high', 'xhigh', 'max'],
41
47
  'gpt-5.6-luna': ['none', 'low', 'medium', 'high', 'xhigh', 'max'],
42
48
  'accounts/fireworks/models/qwen3p8-2p4t-a95b': ['none', 'low', 'medium', 'high'],
49
+ 'qwen/qwen3.8-27b': ['low', 'medium', 'xhigh'],
50
+ 'z-ai/glm-5.3': ['low', 'high', 'max'],
43
51
  'grok-4.6': ['low', 'medium', 'high', 'xhigh'],
44
52
  'gpt-5': ['minimal', 'low', 'medium', 'high'],
45
53
  'gpt-5-mini': ['minimal', 'low', 'medium', 'high'],
@@ -377,9 +385,11 @@ function mapEffort(providerFamily, effort, modelKey) {
377
385
  return null;
378
386
  }
379
387
  const supported = supportedOpenAILevels(modelKey);
380
- const desired = normalized === 100 && supported.includes('max')
381
- ? 'max'
382
- : levelFromBands(normalized, OPENAI_BANDS);
388
+ const desired = modelKey === 'z-ai/glm-5.3'
389
+ ? levelFromBands(normalized, GLM53_BANDS)
390
+ : normalized === 100 && supported.includes('max')
391
+ ? 'max'
392
+ : levelFromBands(normalized, OPENAI_BANDS);
383
393
  const level = pickNearestLevel(desired, OPENAI_LEVEL_LADDER, supported);
384
394
  return { reasoning_effort: level };
385
395
  }
package/index.d.ts CHANGED
@@ -501,6 +501,7 @@ export declare class ModelMix {
501
501
  qwen36plus(args?: ModelAttachArgs): this;
502
502
  qwen37plus(args?: ModelAttachArgs): this;
503
503
  qwen38max(args?: ModelAttachArgs): this;
504
+ qwen3827b(args?: ModelAttachArgs): this;
504
505
  hermes470b(args?: ModelAttachArgs): this;
505
506
  hermes4405b(args?: ModelAttachArgs): this;
506
507
  hermes3(args?: ModelAttachArgs): this;
@@ -517,6 +518,7 @@ export declare class ModelMix {
517
518
  deepseekV4Flash(args?: ModelAttachArgs): this;
518
519
  GLM51(args?: ModelAttachArgs): this;
519
520
  GLM52(args?: ModelAttachArgs): this;
521
+ GLM53(args?: ModelAttachArgs): this;
520
522
 
521
523
  addText(text: string, options?: RoleOptions): this;
522
524
  addTextFromFile(filePath: string, options?: RoleOptions): this;
package/index.js CHANGED
@@ -605,6 +605,10 @@ class ModelMix {
605
605
  return this;
606
606
  }
607
607
 
608
+ qwen3827b({ options = {}, config = {} } = {}) {
609
+ return this.attach('qwen/qwen3.8-27b', new MixOpenRouter({ options, config }));
610
+ }
611
+
608
612
  hermes470b({ options = {}, config = {} } = {}) {
609
613
  return this.attach('nousresearch/hermes-4-70b', new MixOpenRouter({ options, config }));
610
614
  }
@@ -718,6 +722,10 @@ class ModelMix {
718
722
  return this;
719
723
  }
720
724
 
725
+ GLM53({ options = {}, config = {} } = {}) {
726
+ return this.attach('z-ai/glm-5.3', new MixOpenRouter({ options, config }));
727
+ }
728
+
721
729
  addText(text, { role = "user", cache } = {}) {
722
730
  return this._addText(text, {
723
731
  role,
@@ -10,11 +10,11 @@ const CHAIN_MODEL_SHORTCUTS = new Set([
10
10
  'gemini31pro', 'gemini37flash', 'gemini36flash', 'gemini35flash',
11
11
  'gemini35flashLite', 'gemini31flashLite', 'sonarPro', 'sonar',
12
12
  'grok46', 'grok45', 'grok43', 'grok420multiAgent', 'grok420',
13
- 'qwen3', 'qwen35397b', 'qwen36plus', 'qwen37plus', 'qwen38max',
13
+ 'qwen3', 'qwen35397b', 'qwen36plus', 'qwen37plus', 'qwen38max', 'qwen3827b',
14
14
  'hermes470b', 'hermes4405b', 'hermes3',
15
15
  'kimiK26', 'kimiK27Code', 'kimiK3', 'kimiK25',
16
16
  'minimaxM27', 'minimaxM3', 'mimo25', 'mimo25pro',
17
- 'deepseekV4Pro', 'deepseekV4Flash', 'GLM51', 'GLM52'
17
+ 'deepseekV4Pro', 'deepseekV4Flash', 'GLM51', 'GLM52', 'GLM53'
18
18
  ]);
19
19
 
20
20
  function parseChainModels(modelSpecs) {
@@ -84,6 +84,7 @@ const MODEL_PRICING = {
84
84
  'accounts/fireworks/models/glm-4p7': { input: 0.55, output: 2.19 },
85
85
  'accounts/fireworks/models/glm-5p1': { input: 1.05, output: 3.50 },
86
86
  'zai-org/GLM-5.2': { input: 1.40, output: 4.40 },
87
+ 'z-ai/glm-5.3': { input: 1.40, cachedInput: 0.26, output: 4.40 },
87
88
  'accounts/fireworks/models/kimi-k2p5': { input: 0.50, output: 2.80 },
88
89
  'qwen/qwen3.5-397b-a17b': { input: 0.385, output: 2.45 },
89
90
  'accounts/fireworks/models/qwen3p6-plus': { input: 0.50, output: 3.00 },
@@ -92,6 +93,7 @@ const MODEL_PRICING = {
92
93
  'qwen/qwen3.7-plus': { input: 0.32, output: 1.28 },
93
94
  'accounts/fireworks/models/qwen3p8-2p4t-a95b': { input: 2.00, cachedInput: 0.25, output: 6.00 },
94
95
  'qwen/qwen3.8-max': { input: 2.00, output: 6.00 },
96
+ 'qwen/qwen3.8-27b': { input: 0.45, cachedInput: 0.05, output: 3.20 },
95
97
  // MiniMax
96
98
  'MiniMax-M2.5': { input: 0.30, output: 1.20 },
97
99
  'MiniMax-M2.7': { input: 0.30, output: 1.20 },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "modelmix",
3
- "version": "5.1.2",
3
+ "version": "5.1.4",
4
4
  "description": "🧬 Reliable interface with automatic fallback for AI LLMs.",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -143,7 +143,7 @@ ModelMix.new({ config: { effort: 80 } })
143
143
  | DeepSeek V4 | off | `low`↑ | `high`↑ | `high`↑ | `max`↑ | — |
144
144
  | MiniMax M3 | off | adaptive | adaptive | adaptive | adaptive | adaptive |
145
145
 
146
- \* GPT-5.6 maps `100` to `max`; 80–99 remains `xhigh`. Gemini bands: 0–24 / 25–49 / 50–74 / 75–100. Gemini 3.7 Flash supports only `low` / `medium` / `high`, so the first two bands clamp to `low`; `-1` keeps its native `medium` default. 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`. Grok 4.6 maps 0–39 / 40–59 / 60–79 / 80–100 to `low` / `medium` / `high` / `xhigh`; without effort it uses native `high`. `-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.
146
+ \* GPT-5.6 maps `100` to `max`; 80–99 remains `xhigh`. Qwen 3.8 27B maps 0–39 / 40–79 / 80–100 to `low` / `medium` / `xhigh`. GLM 5.3 requires reasoning and maps those bands to `low` / `high` / `max`. Gemini bands: 0–24 / 25–49 / 50–74 / 75–100. Gemini 3.7 Flash supports only `low` / `medium` / `high`, so the first two bands clamp to `low`; `-1` keeps its native `medium` default. 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`. Grok 4.6 maps 0–39 / 40–59 / 60–79 / 80–100 to `low` / `medium` / `high` / `xhigh`; without effort it uses native `high`. `-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.
147
147
 
148
148
  ## Available Model Shorthands
149
149
 
@@ -183,7 +183,7 @@ Use `.effort(n)` (or `config.effort`) to enable Anthropic thinking — e.g. `.ef
183
183
  `GLM46()`
184
184
 
185
185
  ### OpenRouter
186
- `qwen35397b()` `hermes470b()` `hermes4405b()` `qwen38max()` `GLM45()`
186
+ `qwen35397b()` `qwen3827b()` `hermes470b()` `hermes4405b()` `qwen38max()` `GLM45()` `GLM53()`
187
187
 
188
188
  ### Multi-provider (auto-fallback across free/paid tiers)
189
189
  `hermes3()` `kimiK25()`
@@ -96,6 +96,23 @@ describe('Unified effort scale', () => {
96
96
  expect(mapEffort('openai', 100, key)).to.deep.equal({ reasoning_effort: 'high' });
97
97
  });
98
98
 
99
+ it('maps Qwen 3.8 27B to its supported reasoning levels', () => {
100
+ const key = 'qwen/qwen3.8-27b';
101
+ expect(mapEffort('openai', 0, key)).to.deep.equal({ reasoning_effort: 'low' });
102
+ expect(mapEffort('openai', 50, key)).to.deep.equal({ reasoning_effort: 'medium' });
103
+ expect(mapEffort('openai', 100, key)).to.deep.equal({ reasoning_effort: 'xhigh' });
104
+ expect(mapEffort('openai', -1, key)).to.equal(null);
105
+ });
106
+
107
+ it('maps GLM 5.3 to mandatory low, high, and max reasoning', () => {
108
+ const key = 'z-ai/glm-5.3';
109
+ expect(mapEffort('openai', 39, key)).to.deep.equal({ reasoning_effort: 'low' });
110
+ expect(mapEffort('openai', 40, key)).to.deep.equal({ reasoning_effort: 'high' });
111
+ expect(mapEffort('openai', 79, key)).to.deep.equal({ reasoning_effort: 'high' });
112
+ expect(mapEffort('openai', 80, key)).to.deep.equal({ reasoning_effort: 'max' });
113
+ expect(mapEffort('openai', -1, key)).to.equal(null);
114
+ });
115
+
99
116
  it('maps Anthropic adaptive models to thinking + output_config.effort', () => {
100
117
  expect(mapEffort('anthropic', 10, 'claude-opus-5')).to.deep.equal({
101
118
  thinking: { type: 'adaptive', display: 'summarized' },
package/test/glm.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('GLM Model Registration Tests', () => {
5
5
  it('should register Together GLM 5.2 by default', () => {
@@ -9,4 +9,24 @@ describe('GLM Model Registration Tests', () => {
9
9
  expect(model.models).to.have.length(1);
10
10
  expect(model.models[0].key).to.equal('zai-org/GLM-5.2');
11
11
  });
12
+
13
+ it('should register GLM 5.3 through OpenRouter', () => {
14
+ const model = ModelMix.new().GLM53();
15
+
16
+ expect(model.models).to.have.length(1);
17
+ expect(model.models[0].key).to.equal('z-ai/glm-5.3');
18
+ expect(model.models[0].provider).to.be.instanceOf(MixOpenRouter);
19
+ expect(ModelMix.calculateCost('z-ai/glm-5.3', {
20
+ input: 1_000_000,
21
+ cached: 500_000,
22
+ output: 1_000_000
23
+ })).to.equal(5.23);
24
+ });
25
+
26
+ it('should support GLM 5.3 in chain()', () => {
27
+ const model = ModelMix.new().chain('GLM53');
28
+
29
+ expect(model.models).to.have.length(1);
30
+ expect(model.models[0].key).to.equal('z-ai/glm-5.3');
31
+ });
12
32
  });
package/test/qwen.test.js CHANGED
@@ -61,6 +61,26 @@ describe('Qwen Model Registration Tests', () => {
61
61
  expect(model.models[0].key).to.equal('qwen/qwen3.8-max');
62
62
  });
63
63
 
64
+ it('should register Qwen 3.8 27B through OpenRouter', () => {
65
+ const model = ModelMix.new().qwen3827b();
66
+
67
+ expect(model.models).to.have.length(1);
68
+ expect(model.models[0].key).to.equal('qwen/qwen3.8-27b');
69
+ expect(model.models[0].provider).to.be.instanceOf(MixOpenRouter);
70
+ expect(ModelMix.calculateCost('qwen/qwen3.8-27b', {
71
+ input: 1_000_000,
72
+ cached: 250_000,
73
+ output: 1_000_000
74
+ })).to.equal(3.55);
75
+ });
76
+
77
+ it('should support Qwen 3.8 27B in chain()', () => {
78
+ const model = ModelMix.new().chain('qwen3827b');
79
+
80
+ expect(model.models).to.have.length(1);
81
+ expect(model.models[0].key).to.equal('qwen/qwen3.8-27b');
82
+ });
83
+
64
84
  it('should register Qwen 3.5 397B A17B through OpenRouter', () => {
65
85
  const model = ModelMix.new().qwen35397b();
66
86