modelmix 4.7.4 → 5.0.0
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 +210 -89
- package/demo/demo.js +4 -4
- package/demo/prompt.md +2 -2
- package/http-client.js +15 -2
- package/index.d.ts +100 -11
- package/index.js +896 -273
- package/package.json +4 -1
- package/skills/modelmix/SKILL.md +75 -18
- package/test/README.md +10 -9
- package/test/anthropic.test.js +146 -9
- package/test/effort.test.js +2 -2
- package/test/fallback.test.js +192 -2
- package/test/fixtures/account-details.txt +4 -0
- package/test/fixtures/choice-options.txt +6 -0
- package/test/fixtures/choice-template.txt +2 -0
- package/test/fixtures/system-rules.txt +1 -0
- package/test/fixtures/system-template.txt +2 -0
- package/test/fixtures/template.txt +4 -11
- package/test/grok.test.js +28 -1
- package/test/history.test.js +2 -2
- package/test/live.mcp.js +20 -20
- package/test/live.test.js +11 -11
- package/test/templates.test.js +471 -281
- package/test/tokens.test.js +409 -16
|
@@ -1,15 +1,8 @@
|
|
|
1
|
-
Hello
|
|
1
|
+
Hello <%- name %>, welcome to <%- platform %>!
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
- Username: {{username}}
|
|
5
|
-
- Role: {{role}}
|
|
6
|
-
- Created: {{created_date}}
|
|
3
|
+
<% if (showAccount) { %><%- include('account-details.txt') %><% } %>
|
|
7
4
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
{{#if premium}}
|
|
11
|
-
Thank you for being a premium member!
|
|
12
|
-
{{/if}}
|
|
5
|
+
For more information, visit: <%- website %>
|
|
13
6
|
|
|
14
7
|
Best regards,
|
|
15
|
-
The
|
|
8
|
+
The <%- company %> Team
|
package/test/grok.test.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const { expect } = require('chai');
|
|
2
|
-
const
|
|
2
|
+
const nock = require('nock');
|
|
3
|
+
const { ModelMix, MixGrok } = require('../index.js');
|
|
3
4
|
const {
|
|
4
5
|
resolveGrok420ModelKey,
|
|
5
6
|
GROK420_ALIAS,
|
|
@@ -55,4 +56,30 @@ describe('Grok 4.20 effort → model resolution', () => {
|
|
|
55
56
|
expect(resolveGrok420ModelKey(GROK420_REASONING, 50)).to.equal(GROK420_REASONING);
|
|
56
57
|
expect(resolveGrok420ModelKey('grok-4.3', 50)).to.equal('grok-4.3');
|
|
57
58
|
});
|
|
59
|
+
|
|
60
|
+
it('does not send reasoning_effort to concrete Grok 4.20 variants', async () => {
|
|
61
|
+
const api = nock('https://api.x.ai')
|
|
62
|
+
.post('/v1/chat/completions', body => {
|
|
63
|
+
expect(body.model).to.equal(GROK420_REASONING);
|
|
64
|
+
expect(body).to.not.have.property('reasoning_effort');
|
|
65
|
+
return true;
|
|
66
|
+
})
|
|
67
|
+
.reply(200, {
|
|
68
|
+
choices: [{ message: { content: 'ok' } }],
|
|
69
|
+
usage: { prompt_tokens: 1, completion_tokens: 1, total_tokens: 2 }
|
|
70
|
+
});
|
|
71
|
+
const provider = new MixGrok({
|
|
72
|
+
config: { apiKey: 'test-key' }
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
await provider.create({
|
|
76
|
+
options: {
|
|
77
|
+
model: GROK420_REASONING,
|
|
78
|
+
reasoning_effort: 'medium',
|
|
79
|
+
messages: [{ role: 'user', content: 'Hi' }]
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
api.done();
|
|
84
|
+
});
|
|
58
85
|
});
|
package/test/history.test.js
CHANGED
|
@@ -463,7 +463,7 @@ describe('Conversation History Tests', () => {
|
|
|
463
463
|
const model = ModelMix.new({
|
|
464
464
|
config: { debug: false, max_history: 10 }
|
|
465
465
|
});
|
|
466
|
-
model.
|
|
466
|
+
model.opus50();
|
|
467
467
|
|
|
468
468
|
model.addText('Capital of France?');
|
|
469
469
|
nock('https://api.anthropic.com')
|
|
@@ -522,7 +522,7 @@ describe('Conversation History Tests', () => {
|
|
|
522
522
|
const model = ModelMix.new({
|
|
523
523
|
config: { debug: false, max_history: 10 }
|
|
524
524
|
});
|
|
525
|
-
model.effort(100).
|
|
525
|
+
model.effort(100).opus50();
|
|
526
526
|
|
|
527
527
|
model.addText('2+2?');
|
|
528
528
|
nock('https://api.anthropic.com')
|
package/test/live.mcp.js
CHANGED
|
@@ -60,8 +60,8 @@ describe('Live MCP Integration Tests', function () {
|
|
|
60
60
|
|
|
61
61
|
describe('Basic MCP Tool Integration', function () {
|
|
62
62
|
|
|
63
|
-
it('should use custom MCP tools with GPT-5.
|
|
64
|
-
const model = ModelMix.new(setup).
|
|
63
|
+
it('should use custom MCP tools with GPT-5.6 Luna', async function () {
|
|
64
|
+
const model = ModelMix.new(setup).gpt56luna();
|
|
65
65
|
|
|
66
66
|
// Add custom calculator tool
|
|
67
67
|
model.addTool({
|
|
@@ -91,14 +91,14 @@ describe('Live MCP Integration Tests', function () {
|
|
|
91
91
|
model.addText('What is 15 * 23?');
|
|
92
92
|
|
|
93
93
|
const response = await model.message();
|
|
94
|
-
console.log(`GPT-
|
|
94
|
+
console.log(`GPT-5.6 Luna with MCP tools: ${response}`);
|
|
95
95
|
|
|
96
96
|
expect(response).to.be.a('string');
|
|
97
97
|
expect(response).to.include('345');
|
|
98
98
|
});
|
|
99
99
|
|
|
100
|
-
it('should use custom MCP tools with Claude Sonnet
|
|
101
|
-
const model = ModelMix.new(setup).
|
|
100
|
+
it('should use custom MCP tools with Claude Sonnet 5', async function () {
|
|
101
|
+
const model = ModelMix.new(setup).sonnet50();
|
|
102
102
|
|
|
103
103
|
// Add time tool
|
|
104
104
|
model.addTool({
|
|
@@ -141,7 +141,7 @@ describe('Live MCP Integration Tests', function () {
|
|
|
141
141
|
|
|
142
142
|
it('should use custom MCP tools with Claude Opus 5', async function () {
|
|
143
143
|
// Opus 5 rejects temperature; MixAnthropic strips it on request.
|
|
144
|
-
const model = ModelMix.new({ config: setup.config }).
|
|
144
|
+
const model = ModelMix.new({ config: setup.config }).opus50();
|
|
145
145
|
|
|
146
146
|
model.addTool({
|
|
147
147
|
name: "get_current_time",
|
|
@@ -296,8 +296,8 @@ describe('Live MCP Integration Tests', function () {
|
|
|
296
296
|
expect(response).to.match(/[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}/i);
|
|
297
297
|
});
|
|
298
298
|
|
|
299
|
-
it('should use MCP tools with GPT-5
|
|
300
|
-
const model = ModelMix.new(setup).
|
|
299
|
+
it('should use MCP tools with GPT-5.6 Luna', async function () {
|
|
300
|
+
const model = ModelMix.new(setup).gpt56luna();
|
|
301
301
|
|
|
302
302
|
// Add data formatting tool
|
|
303
303
|
model.addTool({
|
|
@@ -337,7 +337,7 @@ describe('Live MCP Integration Tests', function () {
|
|
|
337
337
|
model.addText('Format this data as JSON: "apple, banana, cherry, date"');
|
|
338
338
|
|
|
339
339
|
const response = await model.message();
|
|
340
|
-
console.log(`GPT-
|
|
340
|
+
console.log(`GPT-5.6 Luna with MCP tools: ${response}`);
|
|
341
341
|
|
|
342
342
|
expect(response).to.be.a('string');
|
|
343
343
|
expect(response).to.include('apple');
|
|
@@ -348,8 +348,8 @@ describe('Live MCP Integration Tests', function () {
|
|
|
348
348
|
|
|
349
349
|
describe('MCP Tools with JSON Output', function () {
|
|
350
350
|
|
|
351
|
-
it('should combine MCP tools with JSON output using GPT-
|
|
352
|
-
const model = ModelMix.new(setup).
|
|
351
|
+
it('should combine MCP tools with JSON output using GPT-5.6 Luna', async function () {
|
|
352
|
+
const model = ModelMix.new(setup).gpt56luna();
|
|
353
353
|
|
|
354
354
|
// Add calculation tool
|
|
355
355
|
model.addTool({
|
|
@@ -400,7 +400,7 @@ describe('Live MCP Integration Tests', function () {
|
|
|
400
400
|
calculations: []
|
|
401
401
|
});
|
|
402
402
|
|
|
403
|
-
console.log(`GPT-
|
|
403
|
+
console.log(`GPT-5.6 Luna with MCP tools JSON result:`, JSON.stringify(result, null, 2));
|
|
404
404
|
|
|
405
405
|
expect(result).to.be.an('object');
|
|
406
406
|
expect(result.sqrt_result).to.equal(12);
|
|
@@ -459,8 +459,8 @@ describe('Live MCP Integration Tests', function () {
|
|
|
459
459
|
|
|
460
460
|
describe('MCP Tools Error Handling', function () {
|
|
461
461
|
|
|
462
|
-
it('should handle MCP tool errors gracefully with GPT-5
|
|
463
|
-
const model = ModelMix.new(setup).
|
|
462
|
+
it('should handle MCP tool errors gracefully with GPT-5.6 Luna', async function () {
|
|
463
|
+
const model = ModelMix.new(setup).gpt56luna();
|
|
464
464
|
|
|
465
465
|
// Add tool that can fail
|
|
466
466
|
model.addTool({
|
|
@@ -487,7 +487,7 @@ describe('Live MCP Integration Tests', function () {
|
|
|
487
487
|
model.addText('Try the risky operation with should_fail set to true, then explain what happened.');
|
|
488
488
|
|
|
489
489
|
const response = await model.message();
|
|
490
|
-
console.log(`GPT-5
|
|
490
|
+
console.log(`GPT-5.6 Luna with error handling: ${response}`);
|
|
491
491
|
|
|
492
492
|
expect(response).to.be.a('string');
|
|
493
493
|
expect(response.toLowerCase()).to.match(/(error|fail|problem|issue)/);
|
|
@@ -534,9 +534,9 @@ describe('Live MCP Integration Tests', function () {
|
|
|
534
534
|
|
|
535
535
|
it('should work with same MCP tools across different OpenAI models', async function () {
|
|
536
536
|
const models = [
|
|
537
|
-
{ name: 'GPT-5
|
|
538
|
-
{ name: 'GPT-5
|
|
539
|
-
{ name: 'GPT-5.
|
|
537
|
+
{ name: 'GPT-5.6 Luna', model: ModelMix.new(setup).gpt56luna() },
|
|
538
|
+
{ name: 'GPT-5.6 Terra', model: ModelMix.new(setup).gpt56terra() },
|
|
539
|
+
{ name: 'GPT-5.6 Sol', model: ModelMix.new(setup).gpt56sol() }
|
|
540
540
|
];
|
|
541
541
|
|
|
542
542
|
const results = [];
|
|
@@ -559,8 +559,8 @@ describe('Live MCP Integration Tests', function () {
|
|
|
559
559
|
|
|
560
560
|
it('should work with same MCP tools across different Anthropic models', async function () {
|
|
561
561
|
const models = [
|
|
562
|
-
{ name: 'Opus 5', model: ModelMix.new({ config: setup.config }).
|
|
563
|
-
{ name: 'Sonnet
|
|
562
|
+
{ name: 'Opus 5', model: ModelMix.new({ config: setup.config }).opus50() },
|
|
563
|
+
{ name: 'Sonnet 5', model: ModelMix.new(setup).sonnet50() },
|
|
564
564
|
{ name: 'Haiku 4.5', model: ModelMix.new(setup).haiku45() }
|
|
565
565
|
];
|
|
566
566
|
|
package/test/live.test.js
CHANGED
|
@@ -31,22 +31,22 @@ describe('Live Integration Tests', function () {
|
|
|
31
31
|
|
|
32
32
|
describe('Image Processing', function () {
|
|
33
33
|
|
|
34
|
-
it('should process images with OpenAI GPT-5
|
|
35
|
-
const model = ModelMix.new(setup).
|
|
34
|
+
it('should process images with OpenAI GPT-5.6 Luna', async function () {
|
|
35
|
+
const model = ModelMix.new(setup).gpt56luna();
|
|
36
36
|
|
|
37
37
|
model.addImageFromUrl(blueSquareBase64)
|
|
38
38
|
.addText('What color is this image? Answer in one word only.');
|
|
39
39
|
|
|
40
40
|
const response = await model.message();
|
|
41
41
|
|
|
42
|
-
console.log(`OpenAI GPT-5.
|
|
42
|
+
console.log(`OpenAI GPT-5.6 Luna response: ${response}`);
|
|
43
43
|
|
|
44
44
|
expect(response).to.be.a('string');
|
|
45
45
|
expect(response.toLowerCase()).to.include('blue');
|
|
46
46
|
});
|
|
47
47
|
|
|
48
|
-
it('should process images with Anthropic Sonnet
|
|
49
|
-
const model = ModelMix.new(setup).
|
|
48
|
+
it('should process images with Anthropic Sonnet 5', async function () {
|
|
49
|
+
const model = ModelMix.new(setup).sonnet50();
|
|
50
50
|
|
|
51
51
|
model.addImageFromUrl(blueSquareBase64)
|
|
52
52
|
.addText('What color is this image? Answer in one word only.');
|
|
@@ -76,7 +76,7 @@ describe('Live Integration Tests', function () {
|
|
|
76
76
|
describe('JSON Structured Output', function () {
|
|
77
77
|
|
|
78
78
|
it('should return structured JSON with OpenAI', async function () {
|
|
79
|
-
const model = ModelMix.new(setup).
|
|
79
|
+
const model = ModelMix.new(setup).gpt56luna();
|
|
80
80
|
|
|
81
81
|
model.addText('Generate information about a fictional character.');
|
|
82
82
|
|
|
@@ -97,8 +97,8 @@ describe('Live Integration Tests', function () {
|
|
|
97
97
|
expect(result.skills).to.be.an('array');
|
|
98
98
|
});
|
|
99
99
|
|
|
100
|
-
it('should return structured JSON with Sonnet
|
|
101
|
-
const model = ModelMix.new(setup).effort(100).
|
|
100
|
+
it('should return structured JSON with Sonnet 5 thinking', async function () {
|
|
101
|
+
const model = ModelMix.new(setup).effort(100).sonnet50();
|
|
102
102
|
|
|
103
103
|
model.addText('Generate information about a fictional city.');
|
|
104
104
|
|
|
@@ -150,7 +150,7 @@ describe('Live Integration Tests', function () {
|
|
|
150
150
|
// Create a model chain: non-existent model -> Claude
|
|
151
151
|
const model = ModelMix.new(setup)
|
|
152
152
|
.attach('non-existent-model', new MixOpenAI())
|
|
153
|
-
.
|
|
153
|
+
.sonnet50();
|
|
154
154
|
|
|
155
155
|
model.addText('Say "fallback test successful" and nothing else.');
|
|
156
156
|
|
|
@@ -165,7 +165,7 @@ describe('Live Integration Tests', function () {
|
|
|
165
165
|
// Create a model chain: non-existent model -> Claude
|
|
166
166
|
const model = ModelMix.new(setup)
|
|
167
167
|
.attach('non-existent-model', new MixAnthropic())
|
|
168
|
-
.
|
|
168
|
+
.gpt56luna();
|
|
169
169
|
|
|
170
170
|
model.addText('Say "fallback test successful" and nothing else.');
|
|
171
171
|
|
|
@@ -288,4 +288,4 @@ describe('Live Integration Tests', function () {
|
|
|
288
288
|
});
|
|
289
289
|
|
|
290
290
|
|
|
291
|
-
});
|
|
291
|
+
});
|