modelmix 5.1.15 → 5.1.16

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
@@ -88,7 +88,7 @@ const setup = {
88
88
  const model = await ModelMix.new(setup)
89
89
  .sonnet5() // (main model) Anthropic claude-sonnet-5
90
90
  .gpt56luna() // (fallback 2) OpenAI gpt-5.6-luna
91
- .gemini37flash() // (fallback 3) Google gemini-3.7-flash
91
+ .gemini38flash() // (fallback 3) Google gemini-3.8-flash
92
92
  .grok46() // (fallback 4) Grok grok-4.6
93
93
  .addText("What's your name?");
94
94
 
@@ -122,7 +122,7 @@ has no configured effort:
122
122
 
123
123
  ```javascript
124
124
  const model = ModelMix.new(setup)
125
- .chain('sonnet5', 'gpt56luna@20', 'gemini37flash@-1')
125
+ .chain('sonnet5', 'gpt56luna@20', 'gemini38flash@-1')
126
126
  .addText("What's your name?");
127
127
 
128
128
  console.log(await model.message());
@@ -185,6 +185,7 @@ ModelMix provides convenient shorthand methods for quickly accessing different A
185
185
  | `sonnet46()` | Anthropic | claude-sonnet-4-6 | [\$3.00][2] | [\$15.00][2] |
186
186
  | `haiku45()` | Anthropic | claude-haiku-4-5-20251001 | [\$1.00][2] | [\$5.00][2] |
187
187
  | `gemini31pro()` | Google | gemini-3.1-pro-preview | [\$2.00][3] | [\$12.00][3] |
188
+ | `gemini38flash()` | Google | gemini-3.8-flash | [\$0.75][3] | [\$3.75][3] |
188
189
  | `gemini37flash()` | Google | gemini-3.7-flash | [\$0.75][3] | [\$3.75][3] |
189
190
  | `gemini36flash()` | Google | gemini-3.6-flash | [\$0.75][3] | [\$3.75][3] |
190
191
  | `gemini35flash()` | Google | gemini-3.5-flash | [\$0.75][3] | [\$4.50][3] |
@@ -220,7 +221,7 @@ ModelMix provides convenient shorthand methods for quickly accessing different A
220
221
  | `kimiK25()` | Together | Kimi-K2.5 | [\$0.50][7] | [\$2.80][7] |
221
222
  | `kimiK26()` | Fireworks | models/kimi-k2p6 | [\$0.95][10] | [\$4.00][10] |
222
223
 
223
- Gemini 3.7 Flash and 3.6 Flash use Google's introductory standard pricing through December 31, 2026; standard rates double on January 1, 2027.
224
+ Gemini 3.8 Flash, 3.7 Flash, and 3.6 Flash use Google's introductory standard pricing through December 31, 2026; standard rates double on January 1, 2027.
224
225
 
225
226
  `museGlimmer30b()` uses Fireworks by default. OpenRouter, NVIDIA NIM, and Together are available through `mix.openrouter`, `mix.nvidia`, and `mix.together`.
226
227
 
@@ -291,7 +292,7 @@ ModelMix.new().effort(-1).minimaxM3().addText('...').message();
291
292
 
292
293
  ### Provider-specific behavior
293
294
 
294
- - **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`.
295
+ - **Gemini:** Gemini 3+ uses bands 0–24 / 25–49 / 50–74 / 75–100. Gemini 3.8 Flash and 3.7 Flash clamp these bands to `low` / `low` / `medium` / `high`; `-1` leaves their native `medium` default unchanged. Gemini 2.5 maps 0–100 to `thinkingBudget`.
295
296
  - **GPT-5.6:** `100` maps to `max`; 80–99 remains `xhigh`.
296
297
  - **Qwen 3.8 27B and Flash:** 0–39 / 40–79 / 80–100 map to `low` / `medium` / `xhigh`; `-1` leaves the native `xhigh` default unchanged. Qwen 3.8 Flash is the managed production version based on the open-weight Flash-Next architecture.
297
298
  - **GLM 5.3 and GLM 5.3 Flash:** reasoning is mandatory; 0–39 / 40–79 / 80–100 map to `low` / `high` / `max`; `-1` leaves the native `max` default unchanged.
package/demo/gemini.js CHANGED
@@ -12,9 +12,9 @@ const mmix = new ModelMix({
12
12
  }
13
13
  });
14
14
 
15
- // Using Gemini 3.7 Flash with the built-in method
16
- console.log("\n" + '--------| gemini37flash() |--------');
17
- const flash = await mmix.gemini37flash()
15
+ // Using Gemini 3.8 Flash with the built-in method
16
+ console.log("\n" + '--------| gemini38flash() |--------');
17
+ const flash = await mmix.gemini38flash()
18
18
  .addText('Hi there! Do you like cats?')
19
19
  .message();
20
20
 
package/demo/short.js CHANGED
@@ -12,7 +12,7 @@ const mmix = await ModelMix.new(setup)
12
12
  .fable51({ mix: { openrouter: true } }) // (main + provider fallback) Anthropic/OpenRouter Claude Fable 5.1
13
13
  .sonnet46() // (fallback 2) Anthropic claude-sonnet-4-6
14
14
  .gpt56luna({ mix: { openrouter: true } }) // (fallback 3 + provider fallback) OpenAI/OpenRouter gpt-5.6-luna
15
- .gemini37flash() // (fallback 4) Google gemini-3.7-flash
15
+ .gemini38flash() // (fallback 4) Google gemini-3.8-flash
16
16
  .gpt5nano({ mix: { openrouter: true } }) // (fallback 5 + provider fallback) OpenAI/OpenRouter gpt-5-nano
17
17
  .grok46() // (fallback 6) Grok grok-4.6
18
18
  .qwen35397b() // (fallback 7) OpenRouter qwen/qwen3.5-397b-a17b
package/effort.js CHANGED
@@ -96,6 +96,7 @@ const MINIMAX_BANDS = [
96
96
 
97
97
  /** Exact model → supported Gemini thinkingLevel values */
98
98
  const GEMINI_MODEL_LEVELS = {
99
+ 'gemini-3.8-flash': ['low', 'medium', 'high'],
99
100
  'gemini-3.7-flash': ['low', 'medium', 'high'],
100
101
  'gemini-3-pro-preview': ['low', 'high'],
101
102
  'gemini-3.1-pro-preview': ['low', 'medium', 'high'],
@@ -320,7 +321,7 @@ function mapAdaptiveEffort(providerFamily, modelKey) {
320
321
  return { thinking: { type: 'adaptive' } };
321
322
  }
322
323
  if (providerFamily === 'google') {
323
- if (modelKey === 'gemini-3.7-flash') return null;
324
+ if (modelKey === 'gemini-3.8-flash' || modelKey === 'gemini-3.7-flash') return null;
324
325
  // Gemini dynamic thinking: thinkingBudget -1 (2.5 official; accepted on 3.x as dynamic)
325
326
  return { thinkingConfig: { thinkingBudget: -1 } };
326
327
  }
package/index.d.ts CHANGED
@@ -482,6 +482,7 @@ export declare class ModelMix {
482
482
 
483
483
  // Google
484
484
  gemini31pro(args?: ModelAttachArgs): this;
485
+ gemini38flash(args?: ModelAttachArgs): this;
485
486
  gemini37flash(args?: ModelAttachArgs): this;
486
487
  gemini36flash(args?: ModelAttachArgs): this;
487
488
  gemini35flash(args?: ModelAttachArgs): this;
package/index.js CHANGED
@@ -573,6 +573,9 @@ class ModelMix {
573
573
  gemini31pro({ options = {}, config = {} } = {}) {
574
574
  return this.attach('gemini-3.1-pro-preview', new MixGoogle({ options, config }));
575
575
  }
576
+ gemini38flash({ options = {}, config = {} } = {}) {
577
+ return this.attach('gemini-3.8-flash', new MixGoogle({ options, config }));
578
+ }
576
579
  gemini37flash({ options = {}, config = {} } = {}) {
577
580
  return this.attach('gemini-3.7-flash', new MixGoogle({ options, config }));
578
581
  }
@@ -7,7 +7,7 @@ const CHAIN_MODEL_SHORTCUTS = new Set([
7
7
  'gptRealtime', 'gptRealtimeMini', 'gpt53codex', 'gpt53chat', 'gptOss',
8
8
  'fable51', 'fable50', 'fable5', 'opus50', 'opus5', 'opus48', 'opus47', 'opus46',
9
9
  'sonnet50', 'sonnet5', 'sonnet46', 'sonnet45', 'haiku45',
10
- 'gemini31pro', 'gemini37flash', 'gemini36flash', 'gemini35flash',
10
+ 'gemini31pro', 'gemini38flash', 'gemini37flash', 'gemini36flash', 'gemini35flash',
11
11
  'gemini35flashLite', 'gemini31flashLite', 'sonarPro', 'sonar',
12
12
  'grok46', 'grok45', 'grok43', 'grok420multiAgent', 'grok420',
13
13
  'museGlimmer30b', 'museSpark12Contributor',
@@ -64,6 +64,7 @@ const MODEL_PRICING = {
64
64
  'gemini-3.1-pro-preview': { input: 2.00, output: 12.00 },
65
65
  'gemini-3-pro-preview': { input: 2.00, output: 12.00 },
66
66
  'gemini-3-flash-preview': { input: 0.50, output: 3.00 },
67
+ 'gemini-3.8-flash': { input: 0.75, cachedInput: 0.075, output: 3.75 },
67
68
  'gemini-3.7-flash': { input: 0.75, cachedInput: 0.075, output: 3.75 },
68
69
  'gemini-3.6-flash': { input: 0.75, cachedInput: 0.075, output: 3.75 },
69
70
  'gemini-3.5-flash': { input: 0.75, output: 4.50 },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "modelmix",
3
- "version": "5.1.15",
3
+ "version": "5.1.16",
4
4
  "description": "🧬 Reliable interface with automatic fallback for AI LLMs.",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -86,11 +86,11 @@ Chain shorthand methods to attach providers. First model is primary; others are
86
86
  const model = ModelMix.new()
87
87
  .sonnet46() // primary
88
88
  .gpt52() // fallback 1
89
- .gemini37flash() // fallback 2
89
+ .gemini38flash() // fallback 2
90
90
  .addText("Hello!")
91
91
  ```
92
92
 
93
- If `sonnet46` fails, it automatically tries `gpt52`, then `gemini37flash`.
93
+ If `sonnet46` fails, it automatically tries `gpt52`, then `gemini38flash`.
94
94
 
95
95
  The equivalent `chain()` form accepts public shortcut names directly in the
96
96
  same order. Append `@effort` for a per-model unified effort override (`-1` or
@@ -99,7 +99,7 @@ provider default when no chain effort is configured:
99
99
 
100
100
  ```javascript
101
101
  const model = ModelMix.new()
102
- .chain('sonnet46', 'gpt52@20', 'gemini37flash@-1')
102
+ .chain('sonnet46', 'gpt52@20', 'gemini38flash@-1')
103
103
  .addText('Hello!');
104
104
  ```
105
105
 
@@ -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`. Qwen 3.8 27B and Flash map 0–39 / 40–79 / 80–100 to `low` / `medium` / `xhigh`; Qwen 3.8 Flash is the managed production version based on Flash-Next. GLM 5.3 and GLM 5.3 Flash require reasoning and map 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.
146
+ \* GPT-5.6 maps `100` to `max`; 80–99 remains `xhigh`. Qwen 3.8 27B and Flash map 0–39 / 40–79 / 80–100 to `low` / `medium` / `xhigh`; Qwen 3.8 Flash is the managed production version based on Flash-Next. GLM 5.3 and GLM 5.3 Flash require reasoning and map those bands to `low` / `high` / `max`. Gemini bands: 0–24 / 25–49 / 50–74 / 75–100. Gemini 3.8 Flash and 3.7 Flash support only `low` / `medium` / `high`, so the first two bands clamp to `low`; `-1` keeps their 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
 
@@ -163,7 +163,7 @@ Use `.effort(n)` (or `config.effort`) to enable Anthropic thinking — e.g. `.ef
163
163
  `fable51()` registers `claude-fable-5-1` through Anthropic by default. Pass `mix: { openrouter: true }` to append `anthropic/claude-fable-5.1` as its fallback.
164
164
 
165
165
  ### Google
166
- `gemini31pro()` `gemini37flash()` `gemini36flash()` `gemini35flash()` `gemini35flashLite()` `gemini31flashLite()`
166
+ `gemini31pro()` `gemini38flash()` `gemini37flash()` `gemini36flash()` `gemini35flash()` `gemini35flashLite()` `gemini31flashLite()`
167
167
 
168
168
  ### Grok
169
169
  `grok46()` `grok45()` `grok43()` `grok420multiAgent()` `grok420()`
@@ -485,7 +485,7 @@ Omit all weights for equal probabilities. Otherwise every option needs a positiv
485
485
  const pool = ModelMix.new({ config: { roundRobin: true } })
486
486
  .gpt5mini()
487
487
  .sonnet45()
488
- .gemini37flash();
488
+ .gemini38flash();
489
489
 
490
490
  const r1 = await pool.new().addText("Request 1").message();
491
491
  const r2 = await pool.new().addText("Request 2").message();
@@ -242,6 +242,19 @@ describe('Unified effort scale', () => {
242
242
  expect(mapEffort('google', -1, 'gemini-3.7-flash')).to.equal(null);
243
243
  });
244
244
 
245
+ it('clamps Gemini 3.8 Flash to low, medium, and high', () => {
246
+ expect(mapEffort('google', 0, 'gemini-3.8-flash')).to.deep.equal({
247
+ thinkingConfig: { thinkingLevel: 'low' }
248
+ });
249
+ expect(mapEffort('google', 50, 'gemini-3.8-flash')).to.deep.equal({
250
+ thinkingConfig: { thinkingLevel: 'medium' }
251
+ });
252
+ expect(mapEffort('google', 100, 'gemini-3.8-flash')).to.deep.equal({
253
+ thinkingConfig: { thinkingLevel: 'high' }
254
+ });
255
+ expect(mapEffort('google', -1, 'gemini-3.8-flash')).to.equal(null);
256
+ });
257
+
245
258
  it('clamps Gemini levels for models with fewer steps', () => {
246
259
  expect(mapEffort('google', 10, 'gemini-3-pro-preview')).to.deep.equal({
247
260
  thinkingConfig: { thinkingLevel: 'low' }
@@ -34,12 +34,12 @@ describe('Provider Fallback Chain Tests', () => {
34
34
  });
35
35
 
36
36
  it('should attach chain shortcuts from arguments with optional per-model effort', () => {
37
- model.chain('sonnet5', 'gpt56luna@20', 'gemini37flash@-1');
37
+ model.chain('sonnet5', 'gpt56luna@20', 'gemini38flash@-1');
38
38
 
39
39
  expect(model.models.map(({ key }) => key)).to.deep.equal([
40
40
  'claude-sonnet-5',
41
41
  'gpt-5.6-luna',
42
- 'gemini-3.7-flash'
42
+ 'gemini-3.8-flash'
43
43
  ]);
44
44
  expect(model.models[0].provider.config).to.not.have.property('effort');
45
45
  expect(model.models[1].provider.config.effort).to.equal(20);
package/test/live.mcp.js CHANGED
@@ -181,8 +181,8 @@ describe('Live MCP Integration Tests', function () {
181
181
  }
182
182
  });
183
183
 
184
- it('should use custom MCP tools with Gemini 3.7 Flash', async function () {
185
- const model = ModelMix.new(setup).gemini37flash();
184
+ it('should use custom MCP tools with Gemini 3.8 Flash', async function () {
185
+ const model = ModelMix.new(setup).gemini38flash();
186
186
 
187
187
  // Add password generator tool
188
188
  model.addTool({
@@ -220,7 +220,7 @@ describe('Live MCP Integration Tests', function () {
220
220
  model.addText('Generate a secure password of 16 characters with symbols.');
221
221
 
222
222
  const response = await model.message();
223
- console.log(`Gemini 3.7 Flash with MCP tools: ${response}`);
223
+ console.log(`Gemini 3.8 Flash with MCP tools: ${response}`);
224
224
 
225
225
  expect(response).to.be.a('string');
226
226
  // Check password is mentioned and a generated password string is present
@@ -407,8 +407,8 @@ describe('Live MCP Integration Tests', function () {
407
407
  expect(result.factorial_result).to.equal(120);
408
408
  });
409
409
 
410
- it('should use MCP tools with JSON output using Gemini 3.7 Flash', async function () {
411
- const model = ModelMix.new(setup).gemini37flash();
410
+ it('should use MCP tools with JSON output using Gemini 3.8 Flash', async function () {
411
+ const model = ModelMix.new(setup).gemini38flash();
412
412
 
413
413
  // Add system info tool
414
414
  model.addTool({
@@ -447,7 +447,7 @@ describe('Live MCP Integration Tests', function () {
447
447
  generated_at: ""
448
448
  });
449
449
 
450
- console.log(`Gemini 3.7 Flash with MCP tools JSON result:`, result);
450
+ console.log(`Gemini 3.8 Flash with MCP tools JSON result:`, result);
451
451
 
452
452
  expect(result).to.be.an('object');
453
453
  expect(result.timestamp).to.be.a('number');
package/test/live.test.js CHANGED
@@ -59,7 +59,7 @@ describe('Live Integration Tests', function () {
59
59
  });
60
60
 
61
61
  it('should process images with Google Gemini', async function () {
62
- const model = ModelMix.new(setup).gemini37flash();
62
+ const model = ModelMix.new(setup).gemini38flash();
63
63
 
64
64
  model.addImageFromUrl(blueSquareBase64)
65
65
  .addText('What color is this image? Answer in one word only.');
@@ -120,7 +120,7 @@ describe('Live Integration Tests', function () {
120
120
  });
121
121
 
122
122
  it('should return structured JSON with Google Gemini', async function () {
123
- const model = ModelMix.new(setup).gemini37flash();
123
+ const model = ModelMix.new(setup).gemini38flash();
124
124
 
125
125
  model.addText('Generate information about a fictional city.');
126
126
 
@@ -517,26 +517,29 @@ describe('Token Usage Tracking', () => {
517
517
 
518
518
  it('should register Gemini Flash shortcuts with Google provider', function () {
519
519
  const model = ModelMix.new()
520
+ .gemini38flash()
520
521
  .gemini37flash()
521
522
  .gemini36flash()
522
523
  .gemini35flash()
523
524
  .gemini35flashLite();
524
525
 
525
526
  expect(model.models.map(({ key }) => key)).to.deep.equal([
527
+ 'gemini-3.8-flash',
526
528
  'gemini-3.7-flash',
527
529
  'gemini-3.6-flash',
528
530
  'gemini-3.5-flash',
529
531
  'gemini-3.5-flash-lite'
530
532
  ]);
531
533
  expect(model.models.every(({ provider }) => provider instanceof MixGoogle)).to.equal(true);
534
+ expect(ModelMix.calculateCost('gemini-3.8-flash', { input: 1_000_000, output: 1_000_000 })).to.equal(4.5);
532
535
  expect(ModelMix.calculateCost('gemini-3.7-flash', { input: 1_000_000, output: 1_000_000 })).to.equal(4.5);
533
536
  expect(ModelMix.calculateCost('gemini-3.6-flash', { input: 1_000_000, output: 1_000_000 })).to.equal(4.5);
534
537
  expect(ModelMix.calculateCost('gemini-3.5-flash', { input: 1_000_000, output: 1_000_000 })).to.equal(5.25);
535
538
  expect(ModelMix.calculateCost('gemini-3.5-flash-lite', { input: 1_000_000, output: 1_000_000 })).to.equal(2.8);
536
539
  });
537
540
 
538
- it('should calculate Gemini 3.7 Flash cache reads at the introductory rate', function () {
539
- expect(ModelMix.calculateCostBreakdown('gemini-3.7-flash', {
541
+ it('should calculate Gemini 3.8 Flash cache reads and thinking at the introductory rate', function () {
542
+ expect(ModelMix.calculateCostBreakdown('gemini-3.8-flash', {
540
543
  input: 1_000_000,
541
544
  output: 1_000_000,
542
545
  thinking: 500_000,
@@ -552,10 +555,10 @@ describe('Token Usage Tracking', () => {
552
555
  });
553
556
  });
554
557
 
555
- it('should forward options and config through gemini37flash()', function () {
558
+ it('should forward options and config through gemini38flash()', function () {
556
559
  const options = { thinkingLevel: 'high' };
557
560
  const config = { max_history: 3 };
558
- const model = ModelMix.new().gemini37flash({ options, config });
561
+ const model = ModelMix.new().gemini38flash({ options, config });
559
562
 
560
563
  expect(model.models[0].provider).to.be.instanceOf(MixGoogle);
561
564
  expect(model.models[0].provider.options).to.deep.equal(options);
@@ -687,7 +690,7 @@ describe('Token Usage Tracking', () => {
687
690
  this.timeout(30000);
688
691
 
689
692
  const model = ModelMix.new()
690
- .gemini37flash()
693
+ .gemini38flash()
691
694
  .addText('Say hi');
692
695
 
693
696
  const result = await model.raw();
@@ -750,7 +753,7 @@ describe('Token Usage Tracking', () => {
750
753
  const providers = [
751
754
  { name: 'OpenAI', create: (m) => m.gpt56luna() },
752
755
  { name: 'Anthropic', create: (m) => m.haiku45() },
753
- { name: 'Google', create: (m) => m.gemini37flash() }
756
+ { name: 'Google', create: (m) => m.gemini38flash() }
754
757
  ];
755
758
 
756
759
  for (const provider of providers) {