modelmix 3.8.4 → 3.8.6
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 +5 -5
- package/demo/mcp-simple.mjs +166 -0
- package/demo/mcp-tools.mjs +344 -0
- package/index.js +219 -34
- package/mcp-tools.js +96 -0
- package/package.json +4 -3
- package/test/live.mcp.js +555 -0
- package/test/test-runner.js +2 -0
package/index.js
CHANGED
|
@@ -7,6 +7,7 @@ const path = require('path');
|
|
|
7
7
|
const generateJsonSchema = require('./schema');
|
|
8
8
|
const { Client } = require("@modelcontextprotocol/sdk/client/index.js");
|
|
9
9
|
const { StdioClientTransport } = require("@modelcontextprotocol/sdk/client/stdio.js");
|
|
10
|
+
const { MCPToolsManager } = require('./mcp-tools');
|
|
10
11
|
|
|
11
12
|
class ModelMix {
|
|
12
13
|
|
|
@@ -16,6 +17,7 @@ class ModelMix {
|
|
|
16
17
|
this.tools = {};
|
|
17
18
|
this.toolClient = {};
|
|
18
19
|
this.mcp = {};
|
|
20
|
+
this.mcpToolsManager = new MCPToolsManager();
|
|
19
21
|
this.options = {
|
|
20
22
|
max_tokens: 5000,
|
|
21
23
|
temperature: 1, // 1 --> More creative, 0 --> More deterministic.
|
|
@@ -99,11 +101,10 @@ class ModelMix {
|
|
|
99
101
|
gpt5nano({ options = {}, config = {} } = {}) {
|
|
100
102
|
return this.attach('gpt-5-nano', new MixOpenAI({ options, config }));
|
|
101
103
|
}
|
|
102
|
-
gptOss({ options = {}, config = {}, mix = { together: false, cerebras: false, groq: true
|
|
104
|
+
gptOss({ options = {}, config = {}, mix = { together: false, cerebras: false, groq: true } } = {}) {
|
|
103
105
|
if (mix.together) return this.attach('openai/gpt-oss-120b', new MixTogether({ options, config }));
|
|
104
106
|
if (mix.cerebras) return this.attach('gpt-oss-120b', new MixCerebras({ options, config }));
|
|
105
107
|
if (mix.groq) return this.attach('openai/gpt-oss-120b', new MixGroq({ options, config }));
|
|
106
|
-
if (mix.lmstudio) return this.attach('openai/gpt-oss-120b', new MixLMStudio({ options, config }));
|
|
107
108
|
return this;
|
|
108
109
|
}
|
|
109
110
|
|
|
@@ -199,11 +200,15 @@ class ModelMix {
|
|
|
199
200
|
}
|
|
200
201
|
|
|
201
202
|
kimiK2({ options = {}, config = {}, mix = { together: false, groq: true } } = {}) {
|
|
202
|
-
if (mix.together) this.attach('moonshotai/Kimi-K2-Instruct', new MixTogether({ options, config }));
|
|
203
|
-
if (mix.groq) this.attach('moonshotai/kimi-k2-instruct', new MixGroq({ options, config }));
|
|
203
|
+
if (mix.together) this.attach('moonshotai/Kimi-K2-Instruct-0905', new MixTogether({ options, config }));
|
|
204
|
+
if (mix.groq) this.attach('moonshotai/kimi-k2-instruct-0905', new MixGroq({ options, config }));
|
|
204
205
|
return this;
|
|
205
206
|
}
|
|
206
207
|
|
|
208
|
+
lmstudio({ options = {}, config = {} } = {}) {
|
|
209
|
+
return this.attach('lmstudio', new MixLMStudio({ options, config }));
|
|
210
|
+
}
|
|
211
|
+
|
|
207
212
|
addText(text, { role = "user" } = {}) {
|
|
208
213
|
const content = [{
|
|
209
214
|
type: "text",
|
|
@@ -468,7 +473,28 @@ class ModelMix {
|
|
|
468
473
|
async prepareMessages() {
|
|
469
474
|
await this.processImages();
|
|
470
475
|
this.applyTemplate();
|
|
471
|
-
|
|
476
|
+
|
|
477
|
+
// Smart message slicing to preserve tool call sequences
|
|
478
|
+
if (this.config.max_history > 0) {
|
|
479
|
+
let sliceStart = Math.max(0, this.messages.length - this.config.max_history);
|
|
480
|
+
|
|
481
|
+
// If we're slicing and there's a tool message at the start,
|
|
482
|
+
// ensure we include the preceding assistant message with tool_calls
|
|
483
|
+
while (sliceStart > 0 &&
|
|
484
|
+
sliceStart < this.messages.length &&
|
|
485
|
+
this.messages[sliceStart].role === 'tool') {
|
|
486
|
+
sliceStart--;
|
|
487
|
+
// Also need to include the assistant message with tool_calls
|
|
488
|
+
if (sliceStart > 0 &&
|
|
489
|
+
this.messages[sliceStart].role === 'assistant' &&
|
|
490
|
+
this.messages[sliceStart].tool_calls) {
|
|
491
|
+
break;
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
this.messages = this.messages.slice(sliceStart);
|
|
496
|
+
}
|
|
497
|
+
|
|
472
498
|
this.messages = this.groupByRoles(this.messages);
|
|
473
499
|
this.options.messages = this.messages;
|
|
474
500
|
}
|
|
@@ -490,7 +516,7 @@ class ModelMix {
|
|
|
490
516
|
|
|
491
517
|
async execute({ config = {}, options = {} } = {}) {
|
|
492
518
|
if (!this.models || this.models.length === 0) {
|
|
493
|
-
throw new Error("No models specified. Use methods like .
|
|
519
|
+
throw new Error("No models specified. Use methods like .gpt5(), .sonnet4() first.");
|
|
494
520
|
}
|
|
495
521
|
|
|
496
522
|
return this.limiter.schedule(async () => {
|
|
@@ -552,7 +578,7 @@ class ModelMix {
|
|
|
552
578
|
}
|
|
553
579
|
}
|
|
554
580
|
|
|
555
|
-
this.messages.push({ role: "assistant", content:
|
|
581
|
+
this.messages.push({ role: "assistant", content: null, tool_calls: result.toolCalls });
|
|
556
582
|
|
|
557
583
|
const content = await this.processToolCalls(result.toolCalls);
|
|
558
584
|
this.messages.push({ role: 'tool', content });
|
|
@@ -593,18 +619,67 @@ class ModelMix {
|
|
|
593
619
|
const result = []
|
|
594
620
|
|
|
595
621
|
for (const toolCall of toolCalls) {
|
|
596
|
-
|
|
622
|
+
// Handle different tool call formats more robustly
|
|
623
|
+
let toolName, toolArgs, toolId;
|
|
624
|
+
|
|
625
|
+
try {
|
|
626
|
+
if (toolCall.function) {
|
|
627
|
+
// Formato OpenAI/normalizado
|
|
628
|
+
toolName = toolCall.function.name;
|
|
629
|
+
toolArgs = typeof toolCall.function.arguments === 'string'
|
|
630
|
+
? JSON.parse(toolCall.function.arguments)
|
|
631
|
+
: toolCall.function.arguments;
|
|
632
|
+
toolId = toolCall.id;
|
|
633
|
+
} else if (toolCall.name) {
|
|
634
|
+
// Formato directo (posible formato alternativo)
|
|
635
|
+
toolName = toolCall.name;
|
|
636
|
+
toolArgs = toolCall.input || toolCall.arguments || {};
|
|
637
|
+
toolId = toolCall.id;
|
|
638
|
+
} else {
|
|
639
|
+
console.error('Unknown tool call format:', JSON.stringify(toolCall, null, 2));
|
|
640
|
+
continue;
|
|
641
|
+
}
|
|
597
642
|
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
643
|
+
// Validar que tenemos los datos necesarios
|
|
644
|
+
if (!toolName) {
|
|
645
|
+
console.error('Tool call missing name:', JSON.stringify(toolCall, null, 2));
|
|
646
|
+
continue;
|
|
647
|
+
}
|
|
602
648
|
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
649
|
+
// Verificar si es una herramienta local registrada
|
|
650
|
+
if (this.mcpToolsManager.hasTool(toolName)) {
|
|
651
|
+
const response = await this.mcpToolsManager.executeTool(toolName, toolArgs);
|
|
652
|
+
result.push({
|
|
653
|
+
name: toolName,
|
|
654
|
+
tool_call_id: toolId,
|
|
655
|
+
content: response.content.map(item => item.text).join("\n")
|
|
656
|
+
});
|
|
657
|
+
} else {
|
|
658
|
+
// Usar el cliente MCP externo
|
|
659
|
+
const client = this.toolClient[toolName];
|
|
660
|
+
if (!client) {
|
|
661
|
+
throw new Error(`No client found for tool: ${toolName}`);
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
const response = await client.callTool({
|
|
665
|
+
name: toolName,
|
|
666
|
+
arguments: toolArgs
|
|
667
|
+
});
|
|
668
|
+
|
|
669
|
+
result.push({
|
|
670
|
+
name: toolName,
|
|
671
|
+
tool_call_id: toolId,
|
|
672
|
+
content: response.content.map(item => item.text).join("\n")
|
|
673
|
+
});
|
|
674
|
+
}
|
|
675
|
+
} catch (error) {
|
|
676
|
+
console.error(`Error processing tool call ${toolName}:`, error);
|
|
677
|
+
result.push({
|
|
678
|
+
name: toolName || 'unknown',
|
|
679
|
+
tool_call_id: toolId || 'unknown',
|
|
680
|
+
content: `Error: ${error.message}`
|
|
681
|
+
});
|
|
682
|
+
}
|
|
608
683
|
}
|
|
609
684
|
return result;
|
|
610
685
|
}
|
|
@@ -651,6 +726,56 @@ class ModelMix {
|
|
|
651
726
|
}
|
|
652
727
|
|
|
653
728
|
}
|
|
729
|
+
|
|
730
|
+
addTool(toolDefinition, callback) {
|
|
731
|
+
|
|
732
|
+
if (this.config.max_history < 3) {
|
|
733
|
+
log.warn(`MCP ${toolDefinition.name} requires at least 3 max_history. Setting to 3.`);
|
|
734
|
+
this.config.max_history = 3;
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
this.mcpToolsManager.registerTool(toolDefinition, callback);
|
|
738
|
+
|
|
739
|
+
// Agregar la herramienta al sistema de tools para que sea incluida en las requests
|
|
740
|
+
if (!this.tools.local) {
|
|
741
|
+
this.tools.local = [];
|
|
742
|
+
}
|
|
743
|
+
this.tools.local.push({
|
|
744
|
+
name: toolDefinition.name,
|
|
745
|
+
description: toolDefinition.description,
|
|
746
|
+
inputSchema: toolDefinition.inputSchema
|
|
747
|
+
});
|
|
748
|
+
|
|
749
|
+
return this;
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
addTools(toolsWithCallbacks) {
|
|
753
|
+
for (const { tool, callback } of toolsWithCallbacks) {
|
|
754
|
+
this.addTool(tool, callback);
|
|
755
|
+
}
|
|
756
|
+
return this;
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
removeTool(toolName) {
|
|
760
|
+
this.mcpToolsManager.removeTool(toolName);
|
|
761
|
+
|
|
762
|
+
// Also remove from the tools system
|
|
763
|
+
if (this.tools.local) {
|
|
764
|
+
this.tools.local = this.tools.local.filter(tool => tool.name !== toolName);
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
return this;
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
listTools() {
|
|
771
|
+
const localTools = this.mcpToolsManager.getToolsForMCP();
|
|
772
|
+
const mcpTools = Object.values(this.tools).flat();
|
|
773
|
+
|
|
774
|
+
return {
|
|
775
|
+
local: localTools,
|
|
776
|
+
mcp: mcpTools.filter(tool => !localTools.find(local => local.name === tool.name))
|
|
777
|
+
};
|
|
778
|
+
}
|
|
654
779
|
}
|
|
655
780
|
|
|
656
781
|
class MixCustom {
|
|
@@ -658,7 +783,7 @@ class MixCustom {
|
|
|
658
783
|
this.config = this.getDefaultConfig(config);
|
|
659
784
|
this.options = this.getDefaultOptions(options);
|
|
660
785
|
this.headers = this.getDefaultHeaders(headers);
|
|
661
|
-
this.streamCallback = null; //
|
|
786
|
+
this.streamCallback = null; // Define streamCallback here
|
|
662
787
|
}
|
|
663
788
|
|
|
664
789
|
getDefaultOptions(customOptions) {
|
|
@@ -878,14 +1003,18 @@ class MixOpenAI extends MixCustom {
|
|
|
878
1003
|
|
|
879
1004
|
if (message.role === 'tool') {
|
|
880
1005
|
for (const content of message.content) {
|
|
881
|
-
results.push({
|
|
1006
|
+
results.push({
|
|
1007
|
+
role: 'tool',
|
|
1008
|
+
tool_call_id: content.tool_call_id,
|
|
1009
|
+
content: content.content
|
|
1010
|
+
})
|
|
882
1011
|
}
|
|
883
1012
|
continue;
|
|
884
1013
|
}
|
|
885
1014
|
|
|
886
1015
|
if (Array.isArray(message.content)) {
|
|
887
|
-
message.content = message.content.map(content => {
|
|
888
|
-
if (content.type === 'image') {
|
|
1016
|
+
message.content = message.content.filter(content => content !== null && content !== undefined).map(content => {
|
|
1017
|
+
if (content && content.type === 'image') {
|
|
889
1018
|
const { media_type, data } = content.source;
|
|
890
1019
|
return {
|
|
891
1020
|
type: 'image_url',
|
|
@@ -900,6 +1029,7 @@ class MixOpenAI extends MixCustom {
|
|
|
900
1029
|
|
|
901
1030
|
results.push(message);
|
|
902
1031
|
}
|
|
1032
|
+
|
|
903
1033
|
return results;
|
|
904
1034
|
}
|
|
905
1035
|
|
|
@@ -964,7 +1094,16 @@ class MixAnthropic extends MixCustom {
|
|
|
964
1094
|
delete options.response_format;
|
|
965
1095
|
|
|
966
1096
|
options.system = config.system;
|
|
967
|
-
|
|
1097
|
+
|
|
1098
|
+
try {
|
|
1099
|
+
return await super.create({ config, options });
|
|
1100
|
+
} catch (error) {
|
|
1101
|
+
// Log the error details for debugging
|
|
1102
|
+
if (error.response && error.response.data) {
|
|
1103
|
+
console.error('Anthropic API Error:', JSON.stringify(error.response.data, null, 2));
|
|
1104
|
+
}
|
|
1105
|
+
throw error;
|
|
1106
|
+
}
|
|
968
1107
|
}
|
|
969
1108
|
|
|
970
1109
|
convertMessages(messages, config) {
|
|
@@ -972,7 +1111,27 @@ class MixAnthropic extends MixCustom {
|
|
|
972
1111
|
}
|
|
973
1112
|
|
|
974
1113
|
static convertMessages(messages, config) {
|
|
975
|
-
|
|
1114
|
+
// Filter out orphaned tool results for Anthropic
|
|
1115
|
+
const filteredMessages = [];
|
|
1116
|
+
for (let i = 0; i < messages.length; i++) {
|
|
1117
|
+
if (messages[i].role === 'tool') {
|
|
1118
|
+
// Check if there's a preceding assistant message with tool_calls
|
|
1119
|
+
let foundToolCall = false;
|
|
1120
|
+
for (let j = i - 1; j >= 0; j--) {
|
|
1121
|
+
if (messages[j].role === 'assistant' && messages[j].tool_calls) {
|
|
1122
|
+
foundToolCall = true;
|
|
1123
|
+
break;
|
|
1124
|
+
}
|
|
1125
|
+
}
|
|
1126
|
+
if (!foundToolCall) {
|
|
1127
|
+
// Skip orphaned tool results
|
|
1128
|
+
continue;
|
|
1129
|
+
}
|
|
1130
|
+
}
|
|
1131
|
+
filteredMessages.push(messages[i]);
|
|
1132
|
+
}
|
|
1133
|
+
|
|
1134
|
+
return filteredMessages.map(message => {
|
|
976
1135
|
if (message.role === 'tool') {
|
|
977
1136
|
return {
|
|
978
1137
|
role: "user",
|
|
@@ -984,17 +1143,31 @@ class MixAnthropic extends MixCustom {
|
|
|
984
1143
|
}
|
|
985
1144
|
}
|
|
986
1145
|
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
1146
|
+
// Handle messages with tool_calls (assistant messages that call tools)
|
|
1147
|
+
if (message.tool_calls) {
|
|
1148
|
+
const content = message.tool_calls.map(call => ({
|
|
1149
|
+
type: 'tool_use',
|
|
1150
|
+
id: call.id,
|
|
1151
|
+
name: call.function.name,
|
|
1152
|
+
input: JSON.parse(call.function.arguments)
|
|
1153
|
+
}));
|
|
1154
|
+
return { role: 'assistant', content };
|
|
1155
|
+
}
|
|
1156
|
+
|
|
1157
|
+
// Handle content conversion for other messages
|
|
1158
|
+
if (message.content && Array.isArray(message.content)) {
|
|
1159
|
+
message.content = message.content.filter(content => content !== null && content !== undefined).map(content => {
|
|
1160
|
+
if (content && content.type === 'function') {
|
|
1161
|
+
return {
|
|
1162
|
+
type: 'tool_use',
|
|
1163
|
+
id: content.id,
|
|
1164
|
+
name: content.function.name,
|
|
1165
|
+
input: JSON.parse(content.function.arguments)
|
|
1166
|
+
}
|
|
994
1167
|
}
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
}
|
|
1168
|
+
return content;
|
|
1169
|
+
});
|
|
1170
|
+
}
|
|
998
1171
|
|
|
999
1172
|
return message;
|
|
1000
1173
|
});
|
|
@@ -1065,7 +1238,6 @@ class MixAnthropic extends MixCustom {
|
|
|
1065
1238
|
for (const tool in tools) {
|
|
1066
1239
|
for (const item of tools[tool]) {
|
|
1067
1240
|
options.tools.push({
|
|
1068
|
-
type: 'custom',
|
|
1069
1241
|
name: item.name,
|
|
1070
1242
|
description: item.description,
|
|
1071
1243
|
input_schema: item.inputSchema
|
|
@@ -1326,6 +1498,19 @@ class MixGoogle extends MixCustom {
|
|
|
1326
1498
|
static convertMessages(messages, config) {
|
|
1327
1499
|
return messages.map(message => {
|
|
1328
1500
|
|
|
1501
|
+
// Handle assistant messages with tool_calls (content is null)
|
|
1502
|
+
if (message.role === 'assistant' && message.tool_calls) {
|
|
1503
|
+
return {
|
|
1504
|
+
role: 'model',
|
|
1505
|
+
parts: message.tool_calls.map(toolCall => ({
|
|
1506
|
+
functionCall: {
|
|
1507
|
+
name: toolCall.function.name,
|
|
1508
|
+
args: JSON.parse(toolCall.function.arguments)
|
|
1509
|
+
}
|
|
1510
|
+
}))
|
|
1511
|
+
}
|
|
1512
|
+
}
|
|
1513
|
+
|
|
1329
1514
|
if (!Array.isArray(message.content)) return message;
|
|
1330
1515
|
const role = (message.role === 'assistant' || message.role === 'tool') ? 'model' : 'user'
|
|
1331
1516
|
|
package/mcp-tools.js
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
const log = require('lemonlog')('ModelMix:MCP-Tools');
|
|
2
|
+
|
|
3
|
+
class MCPToolsManager {
|
|
4
|
+
constructor() {
|
|
5
|
+
this.tools = new Map();
|
|
6
|
+
this.callbacks = new Map();
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
registerTool(toolDefinition, callback) {
|
|
10
|
+
const { name, description, inputSchema } = toolDefinition;
|
|
11
|
+
|
|
12
|
+
if (!name || !description || !inputSchema) {
|
|
13
|
+
throw new Error('Tool definition must include name, description, and inputSchema');
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
if (typeof callback !== 'function') {
|
|
17
|
+
throw new Error('Callback must be a function');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Registrar la herramienta
|
|
21
|
+
this.tools.set(name, {
|
|
22
|
+
name,
|
|
23
|
+
description,
|
|
24
|
+
inputSchema
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
// Registrar el callback
|
|
28
|
+
this.callbacks.set(name, callback);
|
|
29
|
+
|
|
30
|
+
log.debug(`Tool registered: ${name}`);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
registerTools(toolsWithCallbacks) {
|
|
34
|
+
for (const { tool, callback } of toolsWithCallbacks) {
|
|
35
|
+
this.registerTool(tool, callback);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
async executeTool(name, args) {
|
|
40
|
+
const callback = this.callbacks.get(name);
|
|
41
|
+
if (!callback) {
|
|
42
|
+
throw new Error(`Tool not found: ${name}`);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
try {
|
|
46
|
+
const result = await callback(args);
|
|
47
|
+
// For primitive values (numbers, booleans), convert to string
|
|
48
|
+
// For objects/arrays, stringify them
|
|
49
|
+
let textResult;
|
|
50
|
+
if (typeof result === 'string') {
|
|
51
|
+
textResult = result;
|
|
52
|
+
} else if (typeof result === 'number' || typeof result === 'boolean') {
|
|
53
|
+
textResult = String(result);
|
|
54
|
+
} else {
|
|
55
|
+
textResult = JSON.stringify(result, null, 2);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return {
|
|
59
|
+
content: [{
|
|
60
|
+
type: "text",
|
|
61
|
+
text: textResult
|
|
62
|
+
}]
|
|
63
|
+
};
|
|
64
|
+
} catch (error) {
|
|
65
|
+
log.error(`Error executing tool ${name}:`, error);
|
|
66
|
+
return {
|
|
67
|
+
content: [{
|
|
68
|
+
type: "text",
|
|
69
|
+
text: `Error executing ${name}: ${error.message}`
|
|
70
|
+
}]
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
getToolsForMCP() {
|
|
76
|
+
return Array.from(this.tools.values());
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
hasTool(name) {
|
|
80
|
+
return this.tools.has(name);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
removeTool(name) {
|
|
84
|
+
this.tools.delete(name);
|
|
85
|
+
this.callbacks.delete(name);
|
|
86
|
+
log.debug(`Tool removed: ${name}`);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
clear() {
|
|
90
|
+
this.tools.clear();
|
|
91
|
+
this.callbacks.clear();
|
|
92
|
+
log.debug('All tools cleared');
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
module.exports = { MCPToolsManager };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "modelmix",
|
|
3
|
-
"version": "3.8.
|
|
3
|
+
"version": "3.8.6",
|
|
4
4
|
"description": "🧬 ModelMix - Unified API for Diverse AI LLM.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"repository": {
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"bottleneck": "^2.19.5",
|
|
53
53
|
"file-type": "^16.5.4",
|
|
54
54
|
"form-data": "^4.0.4",
|
|
55
|
-
"lemonlog": "^1.
|
|
55
|
+
"lemonlog": "^1.2.0"
|
|
56
56
|
},
|
|
57
57
|
"devDependencies": {
|
|
58
58
|
"chai": "^5.2.1",
|
|
@@ -69,6 +69,7 @@
|
|
|
69
69
|
"test:templates": "mocha test/templates.test.js --timeout 10000 --require test/setup.js",
|
|
70
70
|
"test:images": "mocha test/images.test.js --timeout 10000 --require test/setup.js",
|
|
71
71
|
"test:bottleneck": "mocha test/bottleneck.test.js --timeout 10000 --require test/setup.js",
|
|
72
|
-
"test:live": "mocha test/live.test.js --timeout 10000 --require dotenv/config --require test/setup.js"
|
|
72
|
+
"test:live": "mocha test/live.test.js --timeout 10000 --require dotenv/config --require test/setup.js",
|
|
73
|
+
"test:live.mcp": "mocha test/live.mcp.js --timeout 60000 --require dotenv/config --require test/setup.js"
|
|
73
74
|
}
|
|
74
75
|
}
|