modelmix 5.0.6 → 5.1.1
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 +86 -110
- package/RLM_PLUGIN_SPEC.md +2 -2
- package/demo/fallback.js +2 -2
- package/demo/gemini.js +2 -2
- package/demo/json.js +2 -2
- package/demo/mcp-simple.js +2 -2
- package/demo/mcp-tools.js +6 -6
- package/demo/mcp.js +1 -1
- package/demo/parallel-strategy.js +3 -3
- package/demo/parallel.js +2 -2
- package/demo/repl-powers.js +2 -3
- package/demo/rlm-basic.js +2 -2
- package/demo/rlm-fast.js +3 -3
- package/demo/rlm-simple.js +3 -3
- package/demo/short.js +1 -1
- package/demo/stream.js +1 -1
- package/demo/tokens.js +1 -1
- package/demo/verbose.js +5 -5
- package/effort.js +9 -2
- package/index.d.ts +0 -8
- package/index.js +4 -32
- package/package.json +1 -1
- package/skills/modelmix/SKILL.md +8 -8
- package/test/effort.test.js +16 -0
- package/test/fallback.test.js +15 -3
- package/test/history.test.js +1 -1
- package/test/moderation.test.js +1 -1
package/README.md
CHANGED
|
@@ -15,9 +15,9 @@ Ever found yourself wanting to integrate AI models into your projects but worrie
|
|
|
15
15
|
- [Token Usage Tracking](#-token-usage-tracking)
|
|
16
16
|
- [Prompt Caching](#-prompt-caching)
|
|
17
17
|
- [Model Context Protocol (MCP) Integration](#-model-context-protocol-mcp-integration)
|
|
18
|
-
- [Enabling Debug Mode](#-enabling-debug-mode)
|
|
19
|
-
- [Bottleneck Integration](#-bottleneck-integration)
|
|
20
18
|
- [Retry (Opt-In)](#-retry-optin)
|
|
19
|
+
- [Bottleneck Integration](#-bottleneck-integration)
|
|
20
|
+
- [Enabling Debug Mode](#-enabling-debug-mode)
|
|
21
21
|
- [Instance Plugins](#-instance-plugins)
|
|
22
22
|
- [ModelMix Class Overview](#-modelmix-class-overview)
|
|
23
23
|
- [Contributing](#-contributing)
|
|
@@ -136,63 +136,59 @@ This pattern allows you to:
|
|
|
136
136
|
## ⚡️ Shorthand Methods
|
|
137
137
|
|
|
138
138
|
ModelMix provides convenient shorthand methods for quickly accessing different AI models.
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
|
142
|
-
|
|
|
143
|
-
| `
|
|
144
|
-
| `
|
|
145
|
-
| `
|
|
146
|
-
| `
|
|
147
|
-
| `
|
|
148
|
-
| `
|
|
149
|
-
| `
|
|
150
|
-
| `
|
|
151
|
-
| `
|
|
152
|
-
| `
|
|
153
|
-
| `
|
|
154
|
-
| `
|
|
155
|
-
| `
|
|
156
|
-
| `
|
|
157
|
-
| `
|
|
158
|
-
| `
|
|
159
|
-
| `
|
|
160
|
-
| `
|
|
161
|
-
| `
|
|
162
|
-
| `
|
|
163
|
-
| `
|
|
164
|
-
| `
|
|
165
|
-
| `
|
|
166
|
-
| `
|
|
167
|
-
| `
|
|
168
|
-
| `
|
|
169
|
-
| `
|
|
170
|
-
| `
|
|
171
|
-
| `
|
|
172
|
-
| `
|
|
173
|
-
| `
|
|
174
|
-
| `
|
|
175
|
-
| `
|
|
176
|
-
| `
|
|
177
|
-
| `
|
|
178
|
-
| `
|
|
179
|
-
| `
|
|
180
|
-
| `
|
|
181
|
-
| `
|
|
182
|
-
| `
|
|
183
|
-
| `
|
|
184
|
-
| `
|
|
185
|
-
| `
|
|
186
|
-
| `
|
|
187
|
-
| `
|
|
188
|
-
| `
|
|
189
|
-
| `
|
|
190
|
-
| `
|
|
191
|
-
| `
|
|
192
|
-
| `hermes3()` | Lambda | Hermes-3-Llama-3.1-405B-FP8 | [\$0.80/\$0.80][8] |
|
|
193
|
-
| `kimiK3()` | Moonshot | kimi-k3 | [\$3.00/\$15.00][11] |
|
|
194
|
-
| `kimiK25()` | Together | Kimi-K2.5 | [\$0.50/\$2.80][7] |
|
|
195
|
-
| `kimiK26()` | Fireworks | models/kimi-k2p6 | [\$0.95/\$4.00][10] |
|
|
139
|
+
|
|
140
|
+
| Method | Provider | Model | Input / 1M | Output / 1M |
|
|
141
|
+
| --- | --- | --- | ---: | ---: |
|
|
142
|
+
| `gpt56sol()` | OpenAI | gpt-5.6-sol | [\$5.00][1] | [\$30.00][1] |
|
|
143
|
+
| `gpt56terra()` | OpenAI | gpt-5.6-terra | [\$2.00][1] | [\$12.00][1] |
|
|
144
|
+
| `gpt56luna()` | OpenAI | gpt-5.6-luna | [\$0.20][1] | [\$1.20][1] |
|
|
145
|
+
| `gpt55()` | OpenAI | gpt-5.5 | [\$5.00][1] | [\$30.00][1] |
|
|
146
|
+
| `gpt54()` | OpenAI | gpt-5.4 | [\$2.50][1] | [\$15.00][1] |
|
|
147
|
+
| `gpt54mini()` | OpenAI | gpt-5.4-mini | [\$0.75][1] | [\$4.50][1] |
|
|
148
|
+
| `gpt54nano()` | OpenAI | gpt-5.4-nano | [\$0.20][1] | [\$1.25][1] |
|
|
149
|
+
| `gpt53codex()` | OpenAI | gpt-5.3-codex | [\$1.25][1] | [\$14.00][1] |
|
|
150
|
+
| `gpt52()` | OpenAI | gpt-5.2 | [\$1.75][1] | [\$14.00][1] |
|
|
151
|
+
| `gpt51()` | OpenAI | gpt-5.1 | [\$1.25][1] | [\$10.00][1] |
|
|
152
|
+
| `gpt5mini()` | OpenAI | gpt-5-mini | [\$0.25][1] | [\$2.00][1] |
|
|
153
|
+
| `gpt5nano()` | OpenAI | gpt-5-nano | [\$0.05][1] | [\$0.40][1] |
|
|
154
|
+
| `gptOss()` | Together | gpt-oss-120B | [\$0.15][7] | [\$0.60][7] |
|
|
155
|
+
| `fable5()` | Anthropic | claude-fable-5 | [\$10.00][2] | [\$50.00][2] |
|
|
156
|
+
| `opus5()` | Anthropic | claude-opus-5 | [\$5.00][2] | [\$25.00][2] |
|
|
157
|
+
| `opus48()` | Anthropic | claude-opus-4-8 | [\$5.00][2] | [\$25.00][2] |
|
|
158
|
+
| `opus47()` | Anthropic | claude-opus-4-7 | [\$5.00][2] | [\$25.00][2] |
|
|
159
|
+
| `opus46()` | Anthropic | claude-opus-4-6 | [\$5.00][2] | [\$25.00][2] |
|
|
160
|
+
| `sonnet5()` | Anthropic | claude-sonnet-5 | [\$3.00][2] | [\$15.00][2] |
|
|
161
|
+
| `sonnet46()` | Anthropic | claude-sonnet-4-6 | [\$3.00][2] | [\$15.00][2] |
|
|
162
|
+
| `haiku45()` | Anthropic | claude-haiku-4-5-20251001 | [\$1.00][2] | [\$5.00][2] |
|
|
163
|
+
| `gemini31pro()` | Google | gemini-3.1-pro-preview | [\$2.00][3] | [\$12.00][3] |
|
|
164
|
+
| `gemini37flash()` | Google | gemini-3.7-flash | [\$0.75][3] | [\$3.75][3] |
|
|
165
|
+
| `gemini36flash()` | Google | gemini-3.6-flash | [\$0.75][3] | [\$3.75][3] |
|
|
166
|
+
| `gemini35flash()` | Google | gemini-3.5-flash | [\$0.75][3] | [\$4.50][3] |
|
|
167
|
+
| `gemini35flashLite()` | Google | gemini-3.5-flash-lite | [\$0.30][3] | [\$2.50][3] |
|
|
168
|
+
| `gemini31flashLite()` | Google | gemini-3.1-flash-lite-preview | [\$0.25][3] | [\$1.50][3] |
|
|
169
|
+
| `grok46()` | Grok | grok-4.6 | [\$2.00][6] | [\$6.00][6] |
|
|
170
|
+
| `grok45()` | Grok | grok-4.5 | [\$2.00][6] | [\$6.00][6] |
|
|
171
|
+
| `grok43()` | Grok | grok-4.3 | [\$1.25][6] | [\$2.50][6] |
|
|
172
|
+
| `grok420multiAgent()` | Grok | grok-4.20-multi-agent-0309 | [\$1.25][6] | [\$2.50][6] |
|
|
173
|
+
| `grok420()` | Grok | grok-4.20-0309 (†) | [\$1.25][6] | [\$2.50][6] |
|
|
174
|
+
| `qwen35397b()` | OpenRouter | qwen/qwen3.5-397b-a17b | [\$0.385][14] | [\$2.45][14] |
|
|
175
|
+
| `qwen36plus()` | Fireworks | qwen3p6-plus | [\$0.50][10] | [\$3.00][10] |
|
|
176
|
+
| `qwen37plus()` | Fireworks | models/qwen3p7-plus | [\$0.40][10] | [\$1.60][10] |
|
|
177
|
+
| `qwen38max()` | Fireworks | qwen3p8-2p4t-a95b | [\$2.00][10] | [\$6.00][10] |
|
|
178
|
+
| `deepseekV4Flash()` | Fireworks | models/deepseek-v4-flash | [\$0.14][10] | [\$0.28][10] |
|
|
179
|
+
| `deepseekV4Pro()` | Fireworks | models/deepseek-v4-pro-0813 | [\$1.32][12] | [\$3.96][12] |
|
|
180
|
+
| `GLM52()` | Together | zai-org/GLM-5.2 | [\$1.40][7] | [\$4.40][7] |
|
|
181
|
+
| `GLM51()` | Fireworks | models/glm-5p1 | [\$1.05][10] | [\$3.50][10] |
|
|
182
|
+
| `minimaxM3()` | MiniMax | MiniMax-M3 | [\$0.30][9] | [\$1.20][9] |
|
|
183
|
+
| `minimaxM27()` | MiniMax | MiniMax-M2.7 | [\$0.30][9] | [\$1.20][9] |
|
|
184
|
+
| `sonar()` | Perplexity | sonar | [\$1.00][4] | [\$1.00][4] |
|
|
185
|
+
| `sonarPro()` | Perplexity | sonar-pro | [\$3.00][4] | [\$15.00][4] |
|
|
186
|
+
| `hermes470b()` | OpenRouter | nousresearch/hermes-4-70b | [\$0.13][13] | [\$0.40][13] |
|
|
187
|
+
| `hermes4405b()` | OpenRouter | nousresearch/hermes-4-405b | [\$1.00][13] | [\$3.00][13] |
|
|
188
|
+
| `hermes3()` | Lambda | Hermes-3-Llama-3.1-405B-FP8 | [\$0.80][8] | [\$0.80][8] |
|
|
189
|
+
| `kimiK3()` | Moonshot | kimi-k3 | [\$3.00][11] | [\$15.00][11] |
|
|
190
|
+
| `kimiK25()` | Together | Kimi-K2.5 | [\$0.50][7] | [\$2.80][7] |
|
|
191
|
+
| `kimiK26()` | Fireworks | models/kimi-k2p6 | [\$0.95][10] | [\$4.00][10] |
|
|
196
192
|
|
|
197
193
|
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.
|
|
198
194
|
|
|
@@ -249,6 +245,7 @@ ModelMix.new().effort(-1).minimaxM3().addText('...').message();
|
|
|
249
245
|
### Provider-specific behavior
|
|
250
246
|
|
|
251
247
|
- **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
|
+
- **GPT-5.6:** `100` maps to `max`; 80–99 remains `xhigh`.
|
|
252
249
|
- **DeepSeek:** `↑` means thinking is enabled; `off` means it is disabled.
|
|
253
250
|
- **MiniMax:** `off` maps to `thinking.disabled`; `adaptive` maps to `thinking.type=adaptive`.
|
|
254
251
|
- **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`.
|
|
@@ -841,56 +838,6 @@ This simple integration allows your model to:
|
|
|
841
838
|
|
|
842
839
|
The Model Context Protocol makes it easy to add any capability to your models, from web search to code execution, database queries, or custom functions. All with just a few lines of code!
|
|
843
840
|
|
|
844
|
-
## 🐛 Enabling Debug Mode
|
|
845
|
-
|
|
846
|
-
To activate debug mode in ModelMix and view detailed request information, follow these two steps:
|
|
847
|
-
|
|
848
|
-
1. In the ModelMix constructor, include a `debug` level in the configuration:
|
|
849
|
-
|
|
850
|
-
```javascript
|
|
851
|
-
const mix = ModelMix.new({
|
|
852
|
-
config: {
|
|
853
|
-
debug: 4 // 0=silent, 1=minimal, 2=summary, 3=full (no truncate), 4=verbose (raw details)
|
|
854
|
-
// ... other configuration options ...
|
|
855
|
-
}
|
|
856
|
-
});
|
|
857
|
-
```
|
|
858
|
-
|
|
859
|
-
2. When running your script from the command line, use the `DEBUG=ModelMix*` prefix:
|
|
860
|
-
|
|
861
|
-
```
|
|
862
|
-
DEBUG=ModelMix* node your_script.js
|
|
863
|
-
```
|
|
864
|
-
|
|
865
|
-
When you run your script this way, you'll see detailed information about the requests in the console, including the configuration and options used for each AI model request.
|
|
866
|
-
|
|
867
|
-
This information is valuable for debugging and understanding how ModelMix is processing your requests.
|
|
868
|
-
|
|
869
|
-
## 🚦 Bottleneck Integration
|
|
870
|
-
|
|
871
|
-
ModelMix now uses Bottleneck for efficient rate limiting of API requests. This integration helps prevent exceeding API rate limits and ensures smooth operation when working with multiple models or high request volumes.
|
|
872
|
-
|
|
873
|
-
### How it works:
|
|
874
|
-
|
|
875
|
-
1. **Configuration**: Bottleneck is configured in the ModelMix constructor. You can customize the settings or use the default configuration:
|
|
876
|
-
|
|
877
|
-
```javascript
|
|
878
|
-
const setup = {
|
|
879
|
-
config: {
|
|
880
|
-
bottleneck: {
|
|
881
|
-
maxConcurrent: 8, // Maximum number of concurrent requests
|
|
882
|
-
minTime: 500 // Minimum time between requests (in ms)
|
|
883
|
-
}
|
|
884
|
-
}
|
|
885
|
-
};
|
|
886
|
-
```
|
|
887
|
-
|
|
888
|
-
2. **Rate Limiting**: When you make a request using any of the attached models, Bottleneck automatically manages the request flow based on the configured settings.
|
|
889
|
-
|
|
890
|
-
3. **Automatic Queueing**: If the rate limit is reached, Bottleneck will automatically queue subsequent requests and process them as capacity becomes available.
|
|
891
|
-
|
|
892
|
-
This integration ensures that your application respects API rate limits while maximizing throughput, providing a robust solution for managing multiple AI model interactions.
|
|
893
|
-
|
|
894
841
|
## 🔁 Retry (Opt-In)
|
|
895
842
|
|
|
896
843
|
ModelMix supports optional intra-model retries for transient HTTP failures. When enabled, it retries the same provider before moving to fallback models.
|
|
@@ -914,6 +861,35 @@ Behavior summary:
|
|
|
914
861
|
- If retry is enabled, ModelMix retries the same model only for configured transient status codes.
|
|
915
862
|
- After retries are exhausted (or for non-retryable errors), ModelMix continues with normal fallback chain.
|
|
916
863
|
|
|
864
|
+
## 🚦 Bottleneck Integration
|
|
865
|
+
|
|
866
|
+
ModelMix uses Bottleneck for efficient rate limiting of API requests.
|
|
867
|
+
|
|
868
|
+
```javascript
|
|
869
|
+
const setup = {
|
|
870
|
+
config: {
|
|
871
|
+
bottleneck: {
|
|
872
|
+
maxConcurrent: 8,
|
|
873
|
+
minTime: 500
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
};
|
|
877
|
+
```
|
|
878
|
+
|
|
879
|
+
Attached models share this limiter, which queues requests when capacity is exhausted.
|
|
880
|
+
|
|
881
|
+
## 🐛 Enabling Debug Mode
|
|
882
|
+
|
|
883
|
+
Set `config.debug` to `0` (silent), `1` (minimal), `2` (summary), `3` (full), or `4` (verbose raw details), then run with `DEBUG=ModelMix*`:
|
|
884
|
+
|
|
885
|
+
```javascript
|
|
886
|
+
const mix = ModelMix.new({ config: { debug: 4 } });
|
|
887
|
+
```
|
|
888
|
+
|
|
889
|
+
```bash
|
|
890
|
+
DEBUG=ModelMix* node your-script.js
|
|
891
|
+
```
|
|
892
|
+
|
|
917
893
|
## 🔌 Instance Plugins
|
|
918
894
|
|
|
919
895
|
Plugins wrap one ModelMix instance without changing global behavior. They run in registration order after templates are rendered and before provider-specific request conversion:
|
|
@@ -958,7 +934,7 @@ The separately publishable `@modelmix/rlm` workspace package keeps document pars
|
|
|
958
934
|
const { ModelMix } = require('modelmix');
|
|
959
935
|
const { rlm } = require('@modelmix/rlm');
|
|
960
936
|
|
|
961
|
-
const fast = ModelMix.new().
|
|
937
|
+
const fast = ModelMix.new().gpt5nano();
|
|
962
938
|
|
|
963
939
|
const result = await ModelMix.new()
|
|
964
940
|
.gpt56luna()
|
package/RLM_PLUGIN_SPEC.md
CHANGED
|
@@ -204,14 +204,14 @@ Proposed configuration:
|
|
|
204
204
|
```js
|
|
205
205
|
const workers = {
|
|
206
206
|
fast: {
|
|
207
|
-
model: ModelMix.new().
|
|
207
|
+
model: ModelMix.new().gpt5nano(),
|
|
208
208
|
intelligence: 1,
|
|
209
209
|
cost: 1,
|
|
210
210
|
speed: 5,
|
|
211
211
|
description: 'Extraction, classification, and simple transformations'
|
|
212
212
|
},
|
|
213
213
|
balanced: {
|
|
214
|
-
model: ModelMix.new().
|
|
214
|
+
model: ModelMix.new().gpt5nano(),
|
|
215
215
|
intelligence: 3,
|
|
216
216
|
cost: 2,
|
|
217
217
|
speed: 4,
|
package/demo/fallback.js
CHANGED
|
@@ -15,7 +15,7 @@ const mmix = new ModelMix({
|
|
|
15
15
|
}
|
|
16
16
|
});
|
|
17
17
|
|
|
18
|
-
mmix.sonnet46({ config: { url: 'fail' } }).
|
|
18
|
+
mmix.sonnet46({ config: { url: 'fail' } }).gpt5nano();
|
|
19
19
|
|
|
20
20
|
async function main() {
|
|
21
21
|
mmix.addText('hola, como estas?');
|
|
@@ -23,4 +23,4 @@ async function main() {
|
|
|
23
23
|
console.log(response);
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
main();
|
|
26
|
+
main();
|
package/demo/gemini.js
CHANGED
|
@@ -20,8 +20,8 @@ const flash = await mmix.gemini37flash()
|
|
|
20
20
|
|
|
21
21
|
console.log(flash);
|
|
22
22
|
|
|
23
|
-
// Using
|
|
24
|
-
console.log("\n" + '--------|
|
|
23
|
+
// Using Gemini 3.1 Pro with custom config
|
|
24
|
+
console.log("\n" + '--------| gemini31pro() with JSON response |--------');
|
|
25
25
|
const pro = mmix.new().gemini31pro();
|
|
26
26
|
|
|
27
27
|
pro.addText('Give me a fun fact about cats');
|
package/demo/json.js
CHANGED
|
@@ -6,7 +6,7 @@ const model = await ModelMix.new({ options: { max_tokens: 10000 }, config: { deb
|
|
|
6
6
|
// .gptOss()
|
|
7
7
|
// .o4mini()
|
|
8
8
|
// .gpt45()
|
|
9
|
-
// .
|
|
9
|
+
// .gemini37flash()
|
|
10
10
|
.addText("Name and capital of 3 South American countries.")
|
|
11
11
|
|
|
12
12
|
const jsonResult = await model.json([{
|
|
@@ -24,4 +24,4 @@ const jsonResult = await model.json([{
|
|
|
24
24
|
}], { addNote: true });
|
|
25
25
|
|
|
26
26
|
console.log(jsonResult);
|
|
27
|
-
console.log(model.lastRaw.tokens);
|
|
27
|
+
console.log(model.lastRaw.tokens);
|
package/demo/mcp-simple.js
CHANGED
|
@@ -8,7 +8,7 @@ async function simpleCalculator() {
|
|
|
8
8
|
console.log('\n=== Smart Calculator ===');
|
|
9
9
|
|
|
10
10
|
const mmix = ModelMix.new()
|
|
11
|
-
.
|
|
11
|
+
.gpt5nano()
|
|
12
12
|
.setSystem('You are a smart calculator. Use the available tools to perform calculations.');
|
|
13
13
|
|
|
14
14
|
// Add custom tool for advanced operations
|
|
@@ -93,7 +93,7 @@ async function contentGenerator() {
|
|
|
93
93
|
console.log('\n=== Content Generator ===');
|
|
94
94
|
|
|
95
95
|
const mmix = ModelMix.new({ config: { debug: 2, max_history: 1 } })
|
|
96
|
-
.
|
|
96
|
+
.gemini37flash()
|
|
97
97
|
.setSystem('You are a creative assistant that can generate different types of content.');
|
|
98
98
|
|
|
99
99
|
// Tool for generating passwords
|
package/demo/mcp-tools.js
CHANGED
|
@@ -9,7 +9,7 @@ async function example1() {
|
|
|
9
9
|
console.log('\n=== Example 1: Common Tools ===');
|
|
10
10
|
|
|
11
11
|
const mmix = ModelMix.new({ config: { max_history: 10 } })
|
|
12
|
-
.
|
|
12
|
+
.gpt5nano();
|
|
13
13
|
|
|
14
14
|
// Add custom tools
|
|
15
15
|
mmix.addTool({
|
|
@@ -66,7 +66,7 @@ async function example2() {
|
|
|
66
66
|
console.log('\n=== Example 2: Custom Tool - Read Files ===');
|
|
67
67
|
|
|
68
68
|
const mmix = ModelMix.new({ config: { max_history: 10 } })
|
|
69
|
-
.
|
|
69
|
+
.gpt5nano();
|
|
70
70
|
|
|
71
71
|
// Register custom tool for reading files
|
|
72
72
|
mmix.addTool({
|
|
@@ -102,7 +102,7 @@ async function example3() {
|
|
|
102
102
|
console.log('\n=== Example 3: HTTP Request Tool ===');
|
|
103
103
|
|
|
104
104
|
const mmix = ModelMix.new({ config: { max_history: 10 } })
|
|
105
|
-
.
|
|
105
|
+
.gpt5nano();
|
|
106
106
|
|
|
107
107
|
// Register tool for making HTTP requests
|
|
108
108
|
mmix.addTool({
|
|
@@ -158,7 +158,7 @@ async function example4() {
|
|
|
158
158
|
console.log('\n=== Example 4: Multiple Tools Working Together ===');
|
|
159
159
|
|
|
160
160
|
const mmix = ModelMix.new({ config: { max_history: 10 } })
|
|
161
|
-
.
|
|
161
|
+
.gpt5nano();
|
|
162
162
|
|
|
163
163
|
// Register multiple tools at once
|
|
164
164
|
mmix.addTools([
|
|
@@ -248,7 +248,7 @@ async function example5() {
|
|
|
248
248
|
console.log('\n=== Example 5: External MCP + Local Tools ===');
|
|
249
249
|
|
|
250
250
|
const mmix = ModelMix.new({ config: { max_history: 10 } })
|
|
251
|
-
.
|
|
251
|
+
.gpt5nano();
|
|
252
252
|
|
|
253
253
|
// Add external MCP (if available)
|
|
254
254
|
try {
|
|
@@ -341,7 +341,7 @@ async function runExamples() {
|
|
|
341
341
|
console.log('\n✅ All examples completed');
|
|
342
342
|
|
|
343
343
|
// Show registered tools
|
|
344
|
-
const mmix = ModelMix.new().
|
|
344
|
+
const mmix = ModelMix.new().gpt5nano();
|
|
345
345
|
mmix.addTool({
|
|
346
346
|
name: "example_tool",
|
|
347
347
|
description: "Example tool for demonstration",
|
package/demo/mcp.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ModelMix } from '../index.js';
|
|
2
2
|
try { process.loadEnvFile(); } catch {}
|
|
3
3
|
|
|
4
|
-
const mmix = ModelMix.new({ config: { max_history: 10 } }).
|
|
4
|
+
const mmix = ModelMix.new({ config: { max_history: 10 } }).gpt5nano();
|
|
5
5
|
mmix.setSystem('You are an assistant and today is ' + new Date().toISOString());
|
|
6
6
|
|
|
7
7
|
// Add web search capability through MCP
|
|
@@ -129,7 +129,7 @@ async function genericRLMExample(variableName, variableData, task) {
|
|
|
129
129
|
}
|
|
130
130
|
}
|
|
131
131
|
})
|
|
132
|
-
.
|
|
132
|
+
.gpt5nano()
|
|
133
133
|
.setSystem(`You are a Recursive Language Model (RLM) agent.
|
|
134
134
|
|
|
135
135
|
Data is in the ENVIRONMENT as variables, not in your context. You work programmatically:
|
|
@@ -282,7 +282,7 @@ You decide the strategy based on the data and task.`);
|
|
|
282
282
|
}
|
|
283
283
|
});
|
|
284
284
|
|
|
285
|
-
callMmix.
|
|
285
|
+
callMmix.gpt5nano();
|
|
286
286
|
|
|
287
287
|
if (call.system_prompt) {
|
|
288
288
|
callMmix.setSystem(call.system_prompt);
|
|
@@ -376,7 +376,7 @@ You decide the strategy based on the data and task.`);
|
|
|
376
376
|
max_history: 10
|
|
377
377
|
}
|
|
378
378
|
})
|
|
379
|
-
.
|
|
379
|
+
.gpt5nano();
|
|
380
380
|
|
|
381
381
|
if (system_prompt) {
|
|
382
382
|
recursiveMmix.setSystem(system_prompt);
|
package/demo/parallel.js
CHANGED
|
@@ -14,7 +14,7 @@ const mix = new ModelMix({
|
|
|
14
14
|
}
|
|
15
15
|
})
|
|
16
16
|
|
|
17
|
-
mix.
|
|
17
|
+
mix.gpt5nano();
|
|
18
18
|
|
|
19
19
|
// Function to create a promise that resolves after a random time
|
|
20
20
|
const randomDelay = () => new Promise(resolve => setTimeout(resolve, Math.random() * 2000 + 1000));
|
|
@@ -48,4 +48,4 @@ async function runExample() {
|
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
// Run the example
|
|
51
|
-
runExample().catch(console.error);
|
|
51
|
+
runExample().catch(console.error);
|
package/demo/repl-powers.js
CHANGED
|
@@ -12,9 +12,9 @@ async function replPowersExample() {
|
|
|
12
12
|
console.log('\n=== JavaScript REPL - Potencias de 2 ===\n');
|
|
13
13
|
const gptArgs = { options: { reasoning_effort: "none", verbosity: null } };
|
|
14
14
|
const mmix = ModelMix.new({ config: { debug: 2, max_history: 10 } })
|
|
15
|
-
.
|
|
15
|
+
.gpt5nano()
|
|
16
16
|
.gpt52(gptArgs)
|
|
17
|
-
.
|
|
17
|
+
.gemini37flash()
|
|
18
18
|
.setSystem('You are a helpful assistant with access to a JavaScript REPL. When you use the REPL and get results, always show them to the user in your response.');
|
|
19
19
|
|
|
20
20
|
// Variable para capturar el resultado de la herramienta
|
|
@@ -74,4 +74,3 @@ try {
|
|
|
74
74
|
} catch (error) {
|
|
75
75
|
console.error('❌ Error:', error);
|
|
76
76
|
}
|
|
77
|
-
|
package/demo/rlm-basic.js
CHANGED
|
@@ -36,7 +36,7 @@ async function basicRLM() {
|
|
|
36
36
|
console.log('🎯 Query: "Find top Engineering talents with Python skills"\n');
|
|
37
37
|
|
|
38
38
|
const mmix = ModelMix.new({ config: { debug: false, max_history: 20 } })
|
|
39
|
-
.
|
|
39
|
+
.gpt5nano()
|
|
40
40
|
.setSystem(`You are an RLM (Recursive Language Model).
|
|
41
41
|
|
|
42
42
|
Instead of reading all data at once, you:
|
|
@@ -135,7 +135,7 @@ Be strategic: think about what information you need and query only that.`);
|
|
|
135
135
|
|
|
136
136
|
// Create a focused recursive call
|
|
137
137
|
const subMmix = ModelMix.new({ config: { debug: false } })
|
|
138
|
-
.
|
|
138
|
+
.gpt5nano()
|
|
139
139
|
.setSystem(`Solve this focused sub-task concisely. Recursion level: ${recursionCount}`);
|
|
140
140
|
|
|
141
141
|
subMmix.addText(`Context: ${context}\n\nTask: ${task}`);
|
package/demo/rlm-fast.js
CHANGED
|
@@ -50,7 +50,7 @@ async function createIvmContext(isolate, contextData, mmixInstance) {
|
|
|
50
50
|
await jail.set('__mmixCallback', new ivm.Reference(async (system, message, outputJson) => {
|
|
51
51
|
const output = JSON.parse(outputJson);
|
|
52
52
|
const result = await mmixInstance.new()
|
|
53
|
-
.
|
|
53
|
+
.gpt5nano()
|
|
54
54
|
.setSystem(system)
|
|
55
55
|
.addText(message)
|
|
56
56
|
.json(output, output);
|
|
@@ -209,8 +209,8 @@ async function demo() {
|
|
|
209
209
|
// Create base mmix instance for the callbacks
|
|
210
210
|
const model = ModelMix.new({ config: { debug: 2, bottleneck: {} } })
|
|
211
211
|
.gpt52({ options: { reasoning_effort: 'none', verbosity: null } })
|
|
212
|
-
.
|
|
213
|
-
.
|
|
212
|
+
.gpt5nano()
|
|
213
|
+
.gemini37flash();
|
|
214
214
|
|
|
215
215
|
// Run the IVM task
|
|
216
216
|
const result = await runIvmWithMmix({
|
package/demo/rlm-simple.js
CHANGED
|
@@ -105,9 +105,9 @@ async function rlmExample() {
|
|
|
105
105
|
|
|
106
106
|
const gptArgs = { options: { reasoning_effort: "none", verbosity: null } };
|
|
107
107
|
const mmix = ModelMix.new({ config: { debug: false, max_history: 15 } })
|
|
108
|
-
.
|
|
108
|
+
.gpt5nano()
|
|
109
109
|
.gpt52(gptArgs)
|
|
110
|
-
.
|
|
110
|
+
.gemini37flash()
|
|
111
111
|
.setSystem(`You are an RLM (Recursive Language Model) agent.
|
|
112
112
|
|
|
113
113
|
KEY PRINCIPLE: Instead of processing the entire document directly, you can:
|
|
@@ -216,7 +216,7 @@ Current recursion depth: ${recursionDepth}/${maxDepth}`);
|
|
|
216
216
|
|
|
217
217
|
// Crear una nueva instancia para la llamada recursiva
|
|
218
218
|
const recursiveMmix = ModelMix.new({ config: { debug: false } })
|
|
219
|
-
.
|
|
219
|
+
.gpt5nano()
|
|
220
220
|
.setSystem(`You are processing a sub-task. Be concise and direct.
|
|
221
221
|
Recursion depth: ${recursionDepth}/${maxDepth}
|
|
222
222
|
${document_chunk ? 'Document chunk provided.' : 'No document chunk provided.'}`);
|
package/demo/short.js
CHANGED
|
@@ -12,7 +12,7 @@ const mmix = await ModelMix.new(setup)
|
|
|
12
12
|
.sonnet46() // (main model) Anthropic claude-sonnet-4-6
|
|
13
13
|
.gpt56luna() // (fallback 1) OpenAI gpt-5.6-luna
|
|
14
14
|
.gemini37flash() // (fallback 2) Google gemini-3.7-flash
|
|
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
18
|
.hermes470b() // (fallback 6) OpenRouter nousresearch/hermes-4-70b
|
package/demo/stream.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ModelMix } from '../index.js';
|
|
2
2
|
try { process.loadEnvFile(); } catch {}
|
|
3
3
|
|
|
4
|
-
await ModelMix.new().
|
|
4
|
+
await ModelMix.new().gpt5nano()
|
|
5
5
|
.addImageFromUrl('https://pbs.twimg.com/media/F6-GsjraAAADDGy?format=jpg')
|
|
6
6
|
.addText('describe')
|
|
7
7
|
.stream((data) => { console.log(data.message); });
|
package/demo/tokens.js
CHANGED
|
@@ -26,7 +26,7 @@ console.log('-'.repeat(60));
|
|
|
26
26
|
const providers = [
|
|
27
27
|
{ name: 'OpenAI GPT-5-nano', fn: (m) => m.gpt5nano() },
|
|
28
28
|
{ name: 'Anthropic Haiku', fn: (m) => m.haiku45() },
|
|
29
|
-
{ name: 'Google Gemini', fn: (m) => m.
|
|
29
|
+
{ name: 'Google Gemini', fn: (m) => m.gemini37flash() }
|
|
30
30
|
];
|
|
31
31
|
|
|
32
32
|
const prompt = 'Explain quantum computing in one sentence.';
|
package/demo/verbose.js
CHANGED
|
@@ -18,7 +18,7 @@ console.log('──────────────────────
|
|
|
18
18
|
|
|
19
19
|
await ModelMix
|
|
20
20
|
.new({ config: { verbose: 0 } })
|
|
21
|
-
.
|
|
21
|
+
.gpt5nano()
|
|
22
22
|
.addText(prompt)
|
|
23
23
|
.message();
|
|
24
24
|
|
|
@@ -33,7 +33,7 @@ console.log('──────────────────────
|
|
|
33
33
|
|
|
34
34
|
await ModelMix
|
|
35
35
|
.new({ config: { verbose: 1 } })
|
|
36
|
-
.
|
|
36
|
+
.gpt5nano()
|
|
37
37
|
.addText(prompt)
|
|
38
38
|
.message();
|
|
39
39
|
|
|
@@ -48,7 +48,7 @@ console.log('──────────────────────
|
|
|
48
48
|
|
|
49
49
|
await ModelMix
|
|
50
50
|
.new({ config: { verbose: 2 } })
|
|
51
|
-
.
|
|
51
|
+
.gpt5nano()
|
|
52
52
|
.addText(prompt)
|
|
53
53
|
.json({ message: 'string' });
|
|
54
54
|
|
|
@@ -63,7 +63,7 @@ console.log('──────────────────────
|
|
|
63
63
|
|
|
64
64
|
await ModelMix
|
|
65
65
|
.new({ config: { verbose: 3 } })
|
|
66
|
-
.
|
|
66
|
+
.gpt5nano()
|
|
67
67
|
.addText(prompt)
|
|
68
68
|
.message();
|
|
69
69
|
|
|
@@ -79,7 +79,7 @@ try {
|
|
|
79
79
|
const resultFallback = await ModelMix
|
|
80
80
|
.new({ config: { verbose: 2 } })
|
|
81
81
|
.attach('fake-model-that-will-fail', new MixOpenAI())
|
|
82
|
-
.
|
|
82
|
+
.gpt5nano() // This will be the fallback
|
|
83
83
|
.addText(prompt)
|
|
84
84
|
.message();
|
|
85
85
|
|
package/effort.js
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
const OPENAI_LEVELS = ['none', 'low', 'medium', 'high', 'xhigh'];
|
|
10
|
+
const OPENAI_LEVEL_LADDER = [...OPENAI_LEVELS, 'max'];
|
|
10
11
|
const ANTHROPIC_LEVELS = ['low', 'medium', 'high', 'xhigh', 'max'];
|
|
11
12
|
const GEMINI_LEVELS = ['minimal', 'low', 'medium', 'high'];
|
|
12
13
|
|
|
@@ -35,6 +36,9 @@ const GEMINI_BANDS = [
|
|
|
35
36
|
|
|
36
37
|
/** Exact model → supported OpenAI reasoning_effort values */
|
|
37
38
|
const OPENAI_MODEL_LEVELS = {
|
|
39
|
+
'gpt-5.6-sol': ['none', 'low', 'medium', 'high', 'xhigh', 'max'],
|
|
40
|
+
'gpt-5.6-terra': ['none', 'low', 'medium', 'high', 'xhigh', 'max'],
|
|
41
|
+
'gpt-5.6-luna': ['none', 'low', 'medium', 'high', 'xhigh', 'max'],
|
|
38
42
|
'accounts/fireworks/models/qwen3p8-2p4t-a95b': ['none', 'low', 'medium', 'high'],
|
|
39
43
|
'grok-4.6': ['low', 'medium', 'high', 'xhigh'],
|
|
40
44
|
'gpt-5': ['minimal', 'low', 'medium', 'high'],
|
|
@@ -373,8 +377,11 @@ function mapEffort(providerFamily, effort, modelKey) {
|
|
|
373
377
|
if (modelKey === GROK420_NON_REASONING) {
|
|
374
378
|
return null;
|
|
375
379
|
}
|
|
376
|
-
const
|
|
377
|
-
const
|
|
380
|
+
const supported = supportedOpenAILevels(modelKey);
|
|
381
|
+
const desired = normalized === 100 && supported.includes('max')
|
|
382
|
+
? 'max'
|
|
383
|
+
: levelFromBands(normalized, OPENAI_BANDS);
|
|
384
|
+
const level = pickNearestLevel(desired, OPENAI_LEVEL_LADDER, supported);
|
|
378
385
|
return { reasoning_effort: level };
|
|
379
386
|
}
|
|
380
387
|
|
package/index.d.ts
CHANGED
|
@@ -441,9 +441,6 @@ export declare class ModelMix {
|
|
|
441
441
|
attach(key: string, provider: MixCustom): this;
|
|
442
442
|
|
|
443
443
|
// OpenAI
|
|
444
|
-
gpt41(args?: ModelAttachArgs): this;
|
|
445
|
-
gpt41mini(args?: ModelAttachArgs): this;
|
|
446
|
-
gpt41nano(args?: ModelAttachArgs): this;
|
|
447
444
|
gpt5(args?: ModelAttachArgs): this;
|
|
448
445
|
gpt5mini(args?: ModelAttachArgs): this;
|
|
449
446
|
gpt5nano(args?: ModelAttachArgs): this;
|
|
@@ -479,16 +476,12 @@ export declare class ModelMix {
|
|
|
479
476
|
haiku45(args?: ModelAttachArgs): this;
|
|
480
477
|
|
|
481
478
|
// Google
|
|
482
|
-
gemini25flash(args?: ModelAttachArgs): this;
|
|
483
479
|
gemini31pro(args?: ModelAttachArgs): this;
|
|
484
|
-
gemini3pro(args?: ModelAttachArgs): this;
|
|
485
|
-
gemini3flash(args?: ModelAttachArgs): this;
|
|
486
480
|
gemini37flash(args?: ModelAttachArgs): this;
|
|
487
481
|
gemini36flash(args?: ModelAttachArgs): this;
|
|
488
482
|
gemini35flash(args?: ModelAttachArgs): this;
|
|
489
483
|
gemini35flashLite(args?: ModelAttachArgs): this;
|
|
490
484
|
gemini31flashLite(args?: ModelAttachArgs): this;
|
|
491
|
-
gemini25pro(args?: ModelAttachArgs): this;
|
|
492
485
|
|
|
493
486
|
// Perplexity
|
|
494
487
|
sonarPro(args?: ModelAttachArgs): this;
|
|
@@ -516,7 +509,6 @@ export declare class ModelMix {
|
|
|
516
509
|
kimiK3(args?: ModelAttachArgs): this;
|
|
517
510
|
kimiK25(args?: ModelAttachArgs): this;
|
|
518
511
|
lmstudio(model?: string, args?: ModelAttachArgs): this;
|
|
519
|
-
minimaxM25(args?: ModelAttachArgs): this;
|
|
520
512
|
minimaxM27(args?: ModelAttachArgs): this;
|
|
521
513
|
minimaxM3(args?: ModelAttachArgs): this;
|
|
522
514
|
mimo25(args?: ModelAttachArgs): this;
|
package/index.js
CHANGED
|
@@ -408,20 +408,19 @@ const MODEL_PRICING = {
|
|
|
408
408
|
};
|
|
409
409
|
|
|
410
410
|
const CHAIN_MODEL_SHORTCUTS = new Set([
|
|
411
|
-
'
|
|
411
|
+
'gpt5', 'gpt5mini', 'gpt5nano',
|
|
412
412
|
'gpt51', 'gpt52', 'gpt54', 'gpt54mini', 'gpt54nano', 'gpt54pro',
|
|
413
413
|
'gpt55', 'gpt55pro', 'gpt56sol', 'gpt56terra', 'gpt56luna',
|
|
414
414
|
'gptRealtime', 'gptRealtimeMini', 'gpt53codex', 'gpt53chat', 'gptOss',
|
|
415
415
|
'fable50', 'fable5', 'opus50', 'opus5', 'opus48', 'opus47', 'opus46',
|
|
416
416
|
'sonnet50', 'sonnet5', 'sonnet46', 'sonnet45', 'haiku45',
|
|
417
|
-
'
|
|
418
|
-
'
|
|
419
|
-
'gemini31flashLite', 'gemini25pro', 'sonarPro', 'sonar',
|
|
417
|
+
'gemini31pro', 'gemini37flash', 'gemini36flash', 'gemini35flash',
|
|
418
|
+
'gemini35flashLite', 'gemini31flashLite', 'sonarPro', 'sonar',
|
|
420
419
|
'grok46', 'grok45', 'grok43', 'grok420multiAgent', 'grok420',
|
|
421
420
|
'qwen3', 'qwen35397b', 'qwen36plus', 'qwen37plus', 'qwen38max',
|
|
422
421
|
'hermes470b', 'hermes4405b', 'hermes3',
|
|
423
422
|
'kimiK26', 'kimiK27Code', 'kimiK3', 'kimiK25',
|
|
424
|
-
'
|
|
423
|
+
'minimaxM27', 'minimaxM3', 'mimo25', 'mimo25pro',
|
|
425
424
|
'deepseekV4Pro', 'deepseekV4Flash', 'GLM51', 'GLM52'
|
|
426
425
|
]);
|
|
427
426
|
|
|
@@ -930,15 +929,6 @@ class ModelMix {
|
|
|
930
929
|
return this;
|
|
931
930
|
}
|
|
932
931
|
|
|
933
|
-
gpt41({ options = {}, config = {} } = {}) {
|
|
934
|
-
return this.attach('gpt-4.1', new MixOpenAI({ options, config }));
|
|
935
|
-
}
|
|
936
|
-
gpt41mini({ options = {}, config = {} } = {}) {
|
|
937
|
-
return this.attach('gpt-4.1-mini', new MixOpenAI({ options, config }));
|
|
938
|
-
}
|
|
939
|
-
gpt41nano({ options = {}, config = {} } = {}) {
|
|
940
|
-
return this.attach('gpt-4.1-nano', new MixOpenAI({ options, config }));
|
|
941
|
-
}
|
|
942
932
|
gpt5({ options = {}, config = {} } = {}) {
|
|
943
933
|
return this.attach('gpt-5', new MixOpenAI({ options, config }));
|
|
944
934
|
}
|
|
@@ -1037,18 +1027,9 @@ class ModelMix {
|
|
|
1037
1027
|
haiku45({ options = {}, config = {} } = {}) {
|
|
1038
1028
|
return this.attach('claude-haiku-4-5-20251001', new MixAnthropic({ options, config }));
|
|
1039
1029
|
}
|
|
1040
|
-
gemini25flash({ options = {}, config = {} } = {}) {
|
|
1041
|
-
return this.attach('gemini-2.5-flash', new MixGoogle({ options, config }));
|
|
1042
|
-
}
|
|
1043
1030
|
gemini31pro({ options = {}, config = {} } = {}) {
|
|
1044
1031
|
return this.attach('gemini-3.1-pro-preview', new MixGoogle({ options, config }));
|
|
1045
1032
|
}
|
|
1046
|
-
gemini3pro({ options = {}, config = {} } = {}) {
|
|
1047
|
-
return this.attach('gemini-3-pro-preview', new MixGoogle({ options, config }));
|
|
1048
|
-
}
|
|
1049
|
-
gemini3flash({ options = {}, config = {} } = {}) {
|
|
1050
|
-
return this.attach('gemini-3-flash-preview', new MixGoogle({ options, config }));
|
|
1051
|
-
}
|
|
1052
1033
|
gemini37flash({ options = {}, config = {} } = {}) {
|
|
1053
1034
|
return this.attach('gemini-3.7-flash', new MixGoogle({ options, config }));
|
|
1054
1035
|
}
|
|
@@ -1064,9 +1045,6 @@ class ModelMix {
|
|
|
1064
1045
|
gemini31flashLite({ options = {}, config = {} } = {}) {
|
|
1065
1046
|
return this.attach('gemini-3.1-flash-lite-preview', new MixGoogle({ options, config }));
|
|
1066
1047
|
}
|
|
1067
|
-
gemini25pro({ options = {}, config = {} } = {}) {
|
|
1068
|
-
return this.attach('gemini-2.5-pro', new MixGoogle({ options, config }));
|
|
1069
|
-
}
|
|
1070
1048
|
sonarPro({ options = {}, config = {} } = {}) {
|
|
1071
1049
|
return this.attach('sonar-pro', new MixPerplexity({ options, config }));
|
|
1072
1050
|
}
|
|
@@ -1171,12 +1149,6 @@ class ModelMix {
|
|
|
1171
1149
|
}
|
|
1172
1150
|
|
|
1173
1151
|
|
|
1174
|
-
minimaxM25({ options = {}, config = {}, mix = { minimax: true } } = {}) {
|
|
1175
|
-
mix = { ...this.mix, ...mix };
|
|
1176
|
-
if (mix.minimax) this.attach('MiniMax-M2.5', new MixMiniMax({ options, config }));
|
|
1177
|
-
return this;
|
|
1178
|
-
}
|
|
1179
|
-
|
|
1180
1152
|
minimaxM27({ options = {}, config = {}, mix = { openrouter: true, minimax: true } } = {}) {
|
|
1181
1153
|
mix = { ...this.mix, ...mix };
|
|
1182
1154
|
if (mix.nvidia) this.attach('minimaxai/minimax-m2.7', new MixNVIDIA({ options, config }));
|
package/package.json
CHANGED
package/skills/modelmix/SKILL.md
CHANGED
|
@@ -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
|
-
.
|
|
89
|
+
.gemini37flash() // fallback 2
|
|
90
90
|
.addText("Hello!")
|
|
91
91
|
```
|
|
92
92
|
|
|
93
|
-
If `sonnet46` fails, it automatically tries `gpt52`, then `
|
|
93
|
+
If `sonnet46` fails, it automatically tries `gpt52`, then `gemini37flash`.
|
|
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', '
|
|
102
|
+
.chain('sonnet46', 'gpt52@20', 'gemini37flash@-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
|
-
\* 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`. 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
|
|
|
@@ -151,7 +151,7 @@ ModelMix.new({ config: { effort: 80 } })
|
|
|
151
151
|
|
|
152
152
|
Use `ModerationMix.new().openai()` with `.raw()` to classify text and images through OpenAI's Moderations endpoint. Read the results from `raw.moderation`. `ModerationMix` accepts moderation providers as ordered fallbacks, rejects generative providers, and does not generate text or support streaming.
|
|
153
153
|
|
|
154
|
-
`gpt52()` `gpt52chat()` `gpt51()` `gpt5()` `gpt5mini()` `gpt5nano()` `gpt45()` `
|
|
154
|
+
`gpt52()` `gpt52chat()` `gpt51()` `gpt5()` `gpt5mini()` `gpt5nano()` `gpt45()` `o3()` `o4mini()`
|
|
155
155
|
|
|
156
156
|
### Anthropic
|
|
157
157
|
`fable50()` `opus50()` `opus48()` `opus47()` `opus46()` `sonnet5()` `sonnet46()` `sonnet45()` `haiku45()`
|
|
@@ -159,7 +159,7 @@ Use `ModerationMix.new().openai()` with `.raw()` to classify text and images thr
|
|
|
159
159
|
Use `.effort(n)` (or `config.effort`) to enable Anthropic thinking — e.g. `.effort(100).opus50()`. `fable5()` and `opus5()` remain available as compatibility aliases.
|
|
160
160
|
|
|
161
161
|
### Google
|
|
162
|
-
`
|
|
162
|
+
`gemini31pro()` `gemini37flash()` `gemini36flash()` `gemini35flash()` `gemini35flashLite()` `gemini31flashLite()`
|
|
163
163
|
|
|
164
164
|
### Grok
|
|
165
165
|
`grok46()` `grok45()` `grok43()` `grok420multiAgent()` `grok420()`
|
|
@@ -174,7 +174,7 @@ Use `.effort(n)` (or `config.effort`) to enable Anthropic thinking — e.g. `.ef
|
|
|
174
174
|
`kimiK3()` — requires `MOONSHOT_API_KEY`; use `{ mix: { moonshot: false, openrouter: true } }` for OpenRouter.
|
|
175
175
|
|
|
176
176
|
### MiniMax
|
|
177
|
-
`
|
|
177
|
+
`minimaxM27()` `minimaxM3()`
|
|
178
178
|
|
|
179
179
|
### Fireworks
|
|
180
180
|
`qwen36plus()` `qwen37plus()` `qwen38max()` `deepseekV4Flash()` `deepseekV4Pro()` `kimiK26()`
|
|
@@ -460,7 +460,7 @@ Omit all weights for equal probabilities. Otherwise every option needs a positiv
|
|
|
460
460
|
const pool = ModelMix.new({ config: { roundRobin: true } })
|
|
461
461
|
.gpt5mini()
|
|
462
462
|
.sonnet45()
|
|
463
|
-
.
|
|
463
|
+
.gemini37flash();
|
|
464
464
|
|
|
465
465
|
const r1 = await pool.new().addText("Request 1").message();
|
|
466
466
|
const r2 = await pool.new().addText("Request 2").message();
|
package/test/effort.test.js
CHANGED
|
@@ -69,6 +69,14 @@ describe('Unified effort scale', () => {
|
|
|
69
69
|
expect(mapEffort('openai', 10)).to.deep.equal({ reasoning_effort: 'none' });
|
|
70
70
|
expect(mapEffort('openai', 50)).to.deep.equal({ reasoning_effort: 'medium' });
|
|
71
71
|
expect(mapEffort('openai', 90)).to.deep.equal({ reasoning_effort: 'xhigh' });
|
|
72
|
+
expect(mapEffort('openai', 100)).to.deep.equal({ reasoning_effort: 'xhigh' });
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it('maps GPT-5.6 maximum unified effort to max', () => {
|
|
76
|
+
expect(mapEffort('openai', 99, 'gpt-5.6-luna')).to.deep.equal({ reasoning_effort: 'xhigh' });
|
|
77
|
+
for (const model of ['gpt-5.6-sol', 'gpt-5.6-terra', 'gpt-5.6-luna']) {
|
|
78
|
+
expect(mapEffort('openai', 100, model)).to.deep.equal({ reasoning_effort: 'max' });
|
|
79
|
+
}
|
|
72
80
|
});
|
|
73
81
|
|
|
74
82
|
it('sets OpenAI adaptive only when supported (otherwise no-op)', () => {
|
|
@@ -359,6 +367,14 @@ describe('Unified effort scale', () => {
|
|
|
359
367
|
expect(request.reasoning).to.deep.equal({ effort: 'none' });
|
|
360
368
|
});
|
|
361
369
|
|
|
370
|
+
it('GPT-5.6 Luna .effort(100) sends max reasoning effort', () => {
|
|
371
|
+
const model = ModelMix.new().effort(100).gpt56luna();
|
|
372
|
+
const options = { model: 'gpt-5.6-luna', messages: [] };
|
|
373
|
+
applyUnifiedEffort(options, model.config, 'openai', 'gpt-5.6-luna');
|
|
374
|
+
const request = MixOpenAIResponses.buildResponsesRequest(options, {});
|
|
375
|
+
expect(request.reasoning).to.deep.equal({ effort: 'max' });
|
|
376
|
+
});
|
|
377
|
+
|
|
362
378
|
it('Anthropic config.effort maps through .effort().opus50()', () => {
|
|
363
379
|
const model = ModelMix.new().effort(100).opus50();
|
|
364
380
|
expect(model.config.effort).to.equal(100);
|
package/test/fallback.test.js
CHANGED
|
@@ -60,6 +60,18 @@ describe('Provider Fallback Chain Tests', () => {
|
|
|
60
60
|
.to.throw('Invalid chain model at index 0: expected a model shortcut string.');
|
|
61
61
|
});
|
|
62
62
|
|
|
63
|
+
it('should reject removed shortcuts from the public chain API', () => {
|
|
64
|
+
for (const shortcut of [
|
|
65
|
+
'gpt41', 'gpt41mini', 'gpt41nano',
|
|
66
|
+
'gemini25flash', 'gemini25pro', 'gemini3pro', 'gemini3flash',
|
|
67
|
+
'minimaxM25'
|
|
68
|
+
]) {
|
|
69
|
+
expect(model[shortcut]).to.equal(undefined);
|
|
70
|
+
expect(() => model.chain(shortcut))
|
|
71
|
+
.to.throw(`Unknown model shortcut "${shortcut}" in chain().`);
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
|
|
63
75
|
it('should use primary provider when available', async () => {
|
|
64
76
|
model.gpt5mini().sonnet46().addText('Hello');
|
|
65
77
|
|
|
@@ -195,7 +207,7 @@ describe('Provider Fallback Chain Tests', () => {
|
|
|
195
207
|
});
|
|
196
208
|
|
|
197
209
|
it('should cascade through multiple fallbacks', async () => {
|
|
198
|
-
model.gpt5mini().sonnet46().
|
|
210
|
+
model.gpt5mini().sonnet46().gemini37flash().addText('Hello');
|
|
199
211
|
|
|
200
212
|
// Mock failed OpenAI response
|
|
201
213
|
nock('https://api.openai.com')
|
|
@@ -279,7 +291,7 @@ describe('Provider Fallback Chain Tests', () => {
|
|
|
279
291
|
});
|
|
280
292
|
|
|
281
293
|
it('should fallback from Anthropic to Google', async () => {
|
|
282
|
-
model.sonnet46().
|
|
294
|
+
model.sonnet46().gemini37flash().addText('Test message');
|
|
283
295
|
|
|
284
296
|
// Mock Anthropic failure
|
|
285
297
|
nock('https://api.anthropic.com')
|
|
@@ -665,7 +677,7 @@ describe('Provider Fallback Chain Tests', () => {
|
|
|
665
677
|
});
|
|
666
678
|
|
|
667
679
|
it('should provide detailed error information when all fallbacks fail', async () => {
|
|
668
|
-
model.gpt5mini().sonnet46().
|
|
680
|
+
model.gpt5mini().sonnet46().gemini37flash().addText('Test');
|
|
669
681
|
|
|
670
682
|
// Mock all providers failing with different errors
|
|
671
683
|
nock('https://api.openai.com')
|
package/test/history.test.js
CHANGED
|
@@ -570,7 +570,7 @@ describe('Conversation History Tests', () => {
|
|
|
570
570
|
const model = ModelMix.new({
|
|
571
571
|
config: { debug: false, max_history: 10 }
|
|
572
572
|
});
|
|
573
|
-
model.
|
|
573
|
+
model.gemini37flash();
|
|
574
574
|
|
|
575
575
|
model.addText('Hello');
|
|
576
576
|
nock('https://generativelanguage.googleapis.com')
|
package/test/moderation.test.js
CHANGED
|
@@ -100,7 +100,7 @@ describe('OpenAI moderation', () => {
|
|
|
100
100
|
it('rejects generative providers from the moderation chain', () => {
|
|
101
101
|
const model = ModerationMix.new();
|
|
102
102
|
|
|
103
|
-
expect(() => model.
|
|
103
|
+
expect(() => model.gpt5nano({ config: { apiKey: 'test-key' } })).to.throw(
|
|
104
104
|
'ModerationMix only accepts moderation providers.'
|
|
105
105
|
);
|
|
106
106
|
});
|