modelmix 4.6.12 → 4.6.15
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/MODELS.md +1 -0
- package/README.md +5 -0
- package/index.d.ts +3 -0
- package/index.js +50 -3
- package/package.json +1 -1
- package/skills/modelmix/SKILL.md +4 -3
- package/test/anthropic.test.js +94 -0
- package/test/grok.test.js +1 -0
- package/test/live.mcp.js +1 -1
- package/test/qwen.test.js +32 -0
package/MODELS.md
CHANGED
|
@@ -128,6 +128,7 @@ All providers inherit from `MixCustom` base class which provides common function
|
|
|
128
128
|
}
|
|
129
129
|
```
|
|
130
130
|
- **Special Notes**:
|
|
131
|
+
- Removes `temperature`, `top_p`, and `top_k` for Opus 4.7+ / Claude 5 family (API rejects them)
|
|
131
132
|
- Removes `top_p` when thinking mode is enabled
|
|
132
133
|
- Uses `x-api-key` header instead of `authorization`
|
|
133
134
|
- Requires `anthropic-version` header
|
package/README.md
CHANGED
|
@@ -189,11 +189,14 @@ Here's a comprehensive list of available methods:
|
|
|
189
189
|
| `gemini36flash()` | Google | gemini-3.6-flash | [\$1.50 / \$7.50][3] |
|
|
190
190
|
| `gemini35flash()` | Google | gemini-3.5-flash | [\$0.75 / \$4.50][3] |
|
|
191
191
|
| `gemini31flashLite()`| Google | gemini-3.1-flash-lite-preview | [\$0.25 / \$1.50][3] |
|
|
192
|
+
| `grok45()` | Grok | grok-4.5 | [\$2.00 / \$6.00][6] |
|
|
192
193
|
| `grok43()` | Grok | grok-4.3 | [\$1.25 / \$2.50][6] |
|
|
193
194
|
| `grok420multiAgent()`| Grok | grok-4.20-multi-agent-0309 | [\$1.25 / \$2.50][6] |
|
|
194
195
|
| `grok420[think]()` | Grok | grok-4.20-0309 | [\$1.25 / \$2.50][6] |
|
|
195
196
|
| `grok41[think]()` | Grok | grok-4-1-fast | [\$0.20 / \$0.50][6] |
|
|
196
197
|
| `qwen36plus()` | Fireworks/Together | qwen3p6-plus / Qwen3.6-Plus | [\$0.50 / \$3.00][10] |
|
|
198
|
+
| `qwen37plus()` | Fireworks | models/qwen3p7-plus | [\$0.40 / \$1.60][10] |
|
|
199
|
+
| `qwen38max()` | OpenRouter | qwen/qwen3.8-max | [\$2.00 / \$6.00][12] |
|
|
197
200
|
| `deepseekV4Flash()` | Fireworks | models/deepseek-v4-flash | [\$0.14 / \$0.28][10] |
|
|
198
201
|
| `deepseekV4Pro()` | Fireworks | models/deepseek-v4-pro | [\$1.74 / \$3.48][10] |
|
|
199
202
|
| `GLM52()` | Together | zai-org/GLM-5.2 | [\$1.40 / \$4.40][7] |
|
|
@@ -218,10 +221,12 @@ Here's a comprehensive list of available methods:
|
|
|
218
221
|
[9]: https://platform.minimax.io/docs/api-reference/anthropic-api-compatible-cache#supported-models-and-pricing "MiniMax Pricing"
|
|
219
222
|
[10]: https://fireworks.ai/pricing#serverless-pricing "Fireworks Pricing"
|
|
220
223
|
[11]: https://platform.kimi.ai/docs/guide/kimi-k3-pricing "Kimi K3 Pricing"
|
|
224
|
+
[12]: https://openrouter.ai/qwen/qwen3.8-max "OpenRouter Pricing"
|
|
221
225
|
|
|
222
226
|
Each method accepts optional `options`, `config`, and (for multi-provider methods) `mix` parameters to customize behavior.
|
|
223
227
|
For NVIDIA on DeepSeek V4 Flash/Pro, use `deepseekV4Flash({ mix: { nvidia: true } })` or `deepseekV4Pro({ mix: { nvidia: true } })`.
|
|
224
228
|
For Together on Qwen 3.6 Plus, use `qwen36plus({ mix: { fireworks: false, together: true } })`.
|
|
229
|
+
For OpenRouter on Qwen 3.7 Plus, use `qwen37plus({ mix: { fireworks: false, openrouter: true } })`.
|
|
225
230
|
For OpenRouter instead of Moonshot's native API, use `kimiK3({ mix: { moonshot: false, openrouter: true } })`.
|
|
226
231
|
|
|
227
232
|
```javascript
|
package/index.d.ts
CHANGED
|
@@ -324,6 +324,7 @@ export declare class ModelMix {
|
|
|
324
324
|
sonar(args?: ModelAttachArgs): this;
|
|
325
325
|
|
|
326
326
|
// Grok
|
|
327
|
+
grok45(args?: ModelAttachArgs): this;
|
|
327
328
|
grok43(args?: ModelAttachArgs): this;
|
|
328
329
|
grok420multiAgent(args?: ModelAttachArgs): this;
|
|
329
330
|
grok420think(args?: ModelAttachArgs): this;
|
|
@@ -334,6 +335,8 @@ export declare class ModelMix {
|
|
|
334
335
|
// Multi-provider
|
|
335
336
|
qwen3(args?: ModelAttachArgs): this;
|
|
336
337
|
qwen36plus(args?: ModelAttachArgs): this;
|
|
338
|
+
qwen37plus(args?: ModelAttachArgs): this;
|
|
339
|
+
qwen38max(args?: ModelAttachArgs): this;
|
|
337
340
|
hermes3(args?: ModelAttachArgs): this;
|
|
338
341
|
kimiK26think(args?: ModelAttachArgs): this;
|
|
339
342
|
kimiK27Code(args?: ModelAttachArgs): this;
|
package/index.js
CHANGED
|
@@ -88,6 +88,7 @@ const MODEL_PRICING = {
|
|
|
88
88
|
'gemini-2.5-flash': [0.30, 2.50],
|
|
89
89
|
'gemini-3.1-flash-lite-preview': [0.25, 1.50],
|
|
90
90
|
// Grok
|
|
91
|
+
'grok-4.5': [2.00, 6.00],
|
|
91
92
|
'grok-4.3': [1.25, 2.50],
|
|
92
93
|
'grok-4.20-multi-agent-0309': [1.25, 2.50],
|
|
93
94
|
'grok-4.20-0309-reasoning': [1.25, 2.50],
|
|
@@ -106,6 +107,9 @@ const MODEL_PRICING = {
|
|
|
106
107
|
'accounts/fireworks/models/kimi-k2p5': [0.50, 2.80],
|
|
107
108
|
'accounts/fireworks/models/qwen3p6-plus': [0.50, 3.00],
|
|
108
109
|
'Qwen/Qwen3.6-Plus': [0.50, 3.00],
|
|
110
|
+
'accounts/fireworks/models/qwen3p7-plus': [0.40, 1.60],
|
|
111
|
+
'qwen/qwen3.7-plus': [0.32, 1.28],
|
|
112
|
+
'qwen/qwen3.8-max': [2.00, 6.00],
|
|
109
113
|
'fireworks/glm-5': [1.00, 3.20],
|
|
110
114
|
// MiniMax
|
|
111
115
|
'MiniMax-M2.5': [0.30, 1.20],
|
|
@@ -497,6 +501,9 @@ class ModelMix {
|
|
|
497
501
|
return this.attach('sonar', new MixPerplexity({ options, config }));
|
|
498
502
|
}
|
|
499
503
|
|
|
504
|
+
grok45({ options = {}, config = {} } = {}) {
|
|
505
|
+
return this.attach('grok-4.5', new MixGrok({ options, config }));
|
|
506
|
+
}
|
|
500
507
|
grok43({ options = {}, config = {} } = {}) {
|
|
501
508
|
return this.attach('grok-4.3', new MixGrok({ options, config }));
|
|
502
509
|
}
|
|
@@ -527,7 +534,20 @@ class ModelMix {
|
|
|
527
534
|
if (mix.fireworks) this.attach('accounts/fireworks/models/qwen3p6-plus', new MixFireworks({ options, config }));
|
|
528
535
|
if (mix.together) this.attach('Qwen/Qwen3.6-Plus', new MixTogether({ options, config }));
|
|
529
536
|
return this;
|
|
530
|
-
}
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
qwen37plus({ options = {}, config = {}, mix = { fireworks: true } } = {}) {
|
|
540
|
+
mix = { ...this.mix, ...mix };
|
|
541
|
+
if (mix.fireworks) this.attach('accounts/fireworks/models/qwen3p7-plus', new MixFireworks({ options, config }));
|
|
542
|
+
if (mix.openrouter) this.attach('qwen/qwen3.7-plus', new MixOpenRouter({ options, config }));
|
|
543
|
+
return this;
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
qwen38max({ options = {}, config = {}, mix = { openrouter: true } } = {}) {
|
|
547
|
+
mix = { ...this.mix, ...mix };
|
|
548
|
+
if (mix.openrouter) this.attach('qwen/qwen3.8-max', new MixOpenRouter({ options, config }));
|
|
549
|
+
return this;
|
|
550
|
+
}
|
|
531
551
|
|
|
532
552
|
hermes3({ options = {}, config = {}, mix = {} } = {}) {
|
|
533
553
|
mix = { ...this.mix, ...mix };
|
|
@@ -2207,10 +2227,31 @@ class MixAnthropic extends MixCustom {
|
|
|
2207
2227
|
|
|
2208
2228
|
static maxEffortThinkingOptions = {
|
|
2209
2229
|
output_config: { effort: 'max' },
|
|
2210
|
-
thinking: { display: 'summarized' }
|
|
2211
|
-
temperature: 1
|
|
2230
|
+
thinking: { display: 'summarized' }
|
|
2212
2231
|
};
|
|
2213
2232
|
|
|
2233
|
+
/**
|
|
2234
|
+
* Opus 4.7+ and Claude 5 family reject sampling params (temperature/top_p/top_k).
|
|
2235
|
+
* See: https://platform.claude.com/docs/en/about-claude/models/migration-guide
|
|
2236
|
+
*/
|
|
2237
|
+
static rejectsSamplingParams(model = '') {
|
|
2238
|
+
const id = String(model).toLowerCase();
|
|
2239
|
+
if (!id.includes('claude')) return false;
|
|
2240
|
+
if (id.includes('mythos') || id.includes('fable')) return true;
|
|
2241
|
+
|
|
2242
|
+
const opus = id.match(/claude-opus-(\d+)(?:-(\d+))?/);
|
|
2243
|
+
if (opus) {
|
|
2244
|
+
const major = Number(opus[1]);
|
|
2245
|
+
const minor = opus[2] !== undefined ? Number(opus[2]) : 0;
|
|
2246
|
+
return major > 4 || (major === 4 && minor >= 7);
|
|
2247
|
+
}
|
|
2248
|
+
|
|
2249
|
+
const sonnet = id.match(/claude-sonnet-(\d+)/);
|
|
2250
|
+
if (sonnet) return Number(sonnet[1]) >= 5;
|
|
2251
|
+
|
|
2252
|
+
return false;
|
|
2253
|
+
}
|
|
2254
|
+
|
|
2214
2255
|
getDefaultConfig(customConfig) {
|
|
2215
2256
|
|
|
2216
2257
|
if (!process.env.ANTHROPIC_API_KEY) {
|
|
@@ -2228,6 +2269,12 @@ class MixAnthropic extends MixCustom {
|
|
|
2228
2269
|
|
|
2229
2270
|
delete options.response_format;
|
|
2230
2271
|
|
|
2272
|
+
if (MixAnthropic.rejectsSamplingParams(options.model)) {
|
|
2273
|
+
delete options.temperature;
|
|
2274
|
+
delete options.top_p;
|
|
2275
|
+
delete options.top_k;
|
|
2276
|
+
}
|
|
2277
|
+
|
|
2231
2278
|
options.system = config.system;
|
|
2232
2279
|
|
|
2233
2280
|
try {
|
package/package.json
CHANGED
package/skills/modelmix/SKILL.md
CHANGED
|
@@ -130,7 +130,7 @@ Thinking variants: append `think` — e.g. `fable5think()` `opus5think()` `opus4
|
|
|
130
130
|
`gemini3pro()` `gemini3flash()` `gemini36flash()` `gemini35flash()` `gemini25pro()` `gemini25flash()`
|
|
131
131
|
|
|
132
132
|
### Grok
|
|
133
|
-
`grok43()` `grok420multiAgent()` `grok420()` `grok420think()` `grok41()` `grok41think()`
|
|
133
|
+
`grok45()` `grok43()` `grok420multiAgent()` `grok420()` `grok420think()` `grok41()` `grok41think()`
|
|
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
|
-
`deepseekV4Flash()` `deepseekV4Pro()` `GLM5()`
|
|
148
|
+
`qwen36plus()` `qwen37plus()` `deepseekV4Flash()` `deepseekV4Pro()` `GLM5()`
|
|
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()`
|
|
@@ -469,6 +469,7 @@ const model = ModelMix.new({
|
|
|
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`.
|
|
471
471
|
- o-series models (o3, o4mini) automatically strip `max_tokens` and `temperature` since those APIs don't support them.
|
|
472
|
+
- Anthropic Opus 4.7+ / Claude 5 family automatically strip `temperature`, `top_p`, and `top_k` (API rejects them).
|
|
472
473
|
- `addText()`, `addImage()`, `addImageFromUrl()`, and `addImageFromBuffer()` all accept `{ role }` as second argument (default `"user"`).
|
|
473
474
|
|
|
474
475
|
## API Quick Reference
|
package/test/anthropic.test.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const { expect } = require('chai');
|
|
2
|
+
const nock = require('nock');
|
|
2
3
|
const { ModelMix, MixAnthropic } = require('../index.js');
|
|
3
4
|
|
|
4
5
|
describe('Anthropic Model Registration Tests', () => {
|
|
@@ -19,6 +20,7 @@ describe('Anthropic Model Registration Tests', () => {
|
|
|
19
20
|
expect(model.models[0].key).to.equal('claude-fable-5');
|
|
20
21
|
expect(model.models[0].provider.options.output_config).to.deep.equal({ effort: 'max' });
|
|
21
22
|
expect(model.models[0].provider.options.thinking).to.deep.equal({ display: 'summarized' });
|
|
23
|
+
expect(model.models[0].provider.options).to.not.have.property('temperature');
|
|
22
24
|
});
|
|
23
25
|
|
|
24
26
|
it('should register Claude Opus 5', () => {
|
|
@@ -38,6 +40,98 @@ describe('Anthropic Model Registration Tests', () => {
|
|
|
38
40
|
expect(model.models[0].key).to.equal('claude-opus-5');
|
|
39
41
|
expect(model.models[0].provider.options.output_config).to.deep.equal({ effort: 'max' });
|
|
40
42
|
expect(model.models[0].provider.options.thinking).to.deep.equal({ display: 'summarized' });
|
|
43
|
+
expect(model.models[0].provider.options).to.not.have.property('temperature');
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
describe('Sampling params (temperature/top_p/top_k)', () => {
|
|
47
|
+
it('should detect models that reject sampling params', () => {
|
|
48
|
+
expect(MixAnthropic.rejectsSamplingParams('claude-opus-5')).to.equal(true);
|
|
49
|
+
expect(MixAnthropic.rejectsSamplingParams('claude-opus-4-8')).to.equal(true);
|
|
50
|
+
expect(MixAnthropic.rejectsSamplingParams('claude-opus-4-7')).to.equal(true);
|
|
51
|
+
expect(MixAnthropic.rejectsSamplingParams('claude-sonnet-5')).to.equal(true);
|
|
52
|
+
expect(MixAnthropic.rejectsSamplingParams('claude-fable-5')).to.equal(true);
|
|
53
|
+
expect(MixAnthropic.rejectsSamplingParams('anthropic/claude-opus-5')).to.equal(true);
|
|
54
|
+
|
|
55
|
+
expect(MixAnthropic.rejectsSamplingParams('claude-opus-4-6')).to.equal(false);
|
|
56
|
+
expect(MixAnthropic.rejectsSamplingParams('claude-opus-4-1-20250805')).to.equal(false);
|
|
57
|
+
expect(MixAnthropic.rejectsSamplingParams('claude-sonnet-4-6')).to.equal(false);
|
|
58
|
+
expect(MixAnthropic.rejectsSamplingParams('claude-haiku-4-5-20251001')).to.equal(false);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('should strip sampling params for Opus 5 requests', async () => {
|
|
62
|
+
const originalApiKey = process.env.ANTHROPIC_API_KEY;
|
|
63
|
+
process.env.ANTHROPIC_API_KEY = 'test-anthropic-key';
|
|
64
|
+
|
|
65
|
+
try {
|
|
66
|
+
const provider = new MixAnthropic();
|
|
67
|
+
let requestBody;
|
|
68
|
+
nock('https://api.anthropic.com')
|
|
69
|
+
.post('/v1/messages', body => {
|
|
70
|
+
requestBody = body;
|
|
71
|
+
return true;
|
|
72
|
+
})
|
|
73
|
+
.reply(200, {
|
|
74
|
+
content: [{ type: 'text', text: 'Done' }],
|
|
75
|
+
usage: { input_tokens: 1, output_tokens: 1 }
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
await provider.create({
|
|
79
|
+
config: { system: 'You are an assistant.' },
|
|
80
|
+
options: {
|
|
81
|
+
model: 'claude-opus-5',
|
|
82
|
+
messages: [{ role: 'user', content: 'Hello' }],
|
|
83
|
+
max_tokens: 100,
|
|
84
|
+
temperature: 0.5,
|
|
85
|
+
top_p: 0.9,
|
|
86
|
+
top_k: 40
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
expect(requestBody).to.not.have.property('temperature');
|
|
91
|
+
expect(requestBody).to.not.have.property('top_p');
|
|
92
|
+
expect(requestBody).to.not.have.property('top_k');
|
|
93
|
+
expect(requestBody.model).to.equal('claude-opus-5');
|
|
94
|
+
} finally {
|
|
95
|
+
if (originalApiKey === undefined) delete process.env.ANTHROPIC_API_KEY;
|
|
96
|
+
else process.env.ANTHROPIC_API_KEY = originalApiKey;
|
|
97
|
+
nock.cleanAll();
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it('should keep temperature for Opus 4.6 requests', async () => {
|
|
102
|
+
const originalApiKey = process.env.ANTHROPIC_API_KEY;
|
|
103
|
+
process.env.ANTHROPIC_API_KEY = 'test-anthropic-key';
|
|
104
|
+
|
|
105
|
+
try {
|
|
106
|
+
const provider = new MixAnthropic();
|
|
107
|
+
let requestBody;
|
|
108
|
+
nock('https://api.anthropic.com')
|
|
109
|
+
.post('/v1/messages', body => {
|
|
110
|
+
requestBody = body;
|
|
111
|
+
return true;
|
|
112
|
+
})
|
|
113
|
+
.reply(200, {
|
|
114
|
+
content: [{ type: 'text', text: 'Done' }],
|
|
115
|
+
usage: { input_tokens: 1, output_tokens: 1 }
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
await provider.create({
|
|
119
|
+
config: { system: 'You are an assistant.' },
|
|
120
|
+
options: {
|
|
121
|
+
model: 'claude-opus-4-6',
|
|
122
|
+
messages: [{ role: 'user', content: 'Hello' }],
|
|
123
|
+
max_tokens: 100,
|
|
124
|
+
temperature: 0.5
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
expect(requestBody.temperature).to.equal(0.5);
|
|
129
|
+
} finally {
|
|
130
|
+
if (originalApiKey === undefined) delete process.env.ANTHROPIC_API_KEY;
|
|
131
|
+
else process.env.ANTHROPIC_API_KEY = originalApiKey;
|
|
132
|
+
nock.cleanAll();
|
|
133
|
+
}
|
|
134
|
+
});
|
|
41
135
|
});
|
|
42
136
|
|
|
43
137
|
it('should register Claude Opus 4.8', () => {
|
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/live.mcp.js
CHANGED
|
@@ -140,7 +140,7 @@ describe('Live MCP Integration Tests', function () {
|
|
|
140
140
|
});
|
|
141
141
|
|
|
142
142
|
it('should use custom MCP tools with Claude Opus 5', async function () {
|
|
143
|
-
// Opus 5 rejects temperature
|
|
143
|
+
// Opus 5 rejects temperature; MixAnthropic strips it on request.
|
|
144
144
|
const model = ModelMix.new({ config: setup.config }).opus5();
|
|
145
145
|
|
|
146
146
|
model.addTool({
|
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
|
});
|