.agents/skills/modelmix/SKILL.md
Instructions for using the ModelMix Node.js library to interact with multiple AI LLM providers through a unified interface. Use when integrating AI models (OpenAI, Anthropic, Google, Groq, Perplexity, Grok, etc.), chaining models with fallback, getting structured JSON from LLMs, adding MCP tools, streaming responses, or managing multi-provider AI workflows in Node.js.
npx skillsauth add clasen/gptrans modelmixInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
ModelMix is a Node.js library that provides a unified fluent API to interact with multiple AI LLM providers. It handles automatic fallback between models, round-robin load balancing, structured JSON output, streaming, MCP tool integration, rate limiting, and token tracking.
Use this skill when:
Do NOT use this skill for:
npm install modelmix
import { ModelMix } from 'modelmix';
// Static factory (preferred)
const model = ModelMix.new();
// With global options
const model = ModelMix.new({
options: { max_tokens: 4096, temperature: 0.7 },
config: {
system: "You are a helpful assistant.",
max_history: 5,
debug: 0, // 0=silent, 1=minimal, 2=summary, 3=full
roundRobin: false // false=fallback, true=rotate models
}
});
Chain shorthand methods to attach providers. First model is primary; others are fallbacks:
const model = ModelMix.new()
.sonnet45() // primary
.gpt5mini() // fallback 1
.gemini3flash() // fallback 2
.addText("Hello!")
If sonnet45 fails, it automatically tries gpt5mini, then gemini3flash.
gpt52 gpt51 gpt5 gpt5mini gpt5nano gpt41 gpt41mini gpt41nanoopus46 opus45 sonnet45 sonnet4 haiku45 haiku35 (thinking variants: add think suffix)gemini3pro gemini3flash gemini25pro gemini25flashgrok4 grok41 (thinking variant available)sonar sonarProscout maverickqwen3 kimiK2deepseekR1 gptOssminimaxM21deepseekV32 GLM47Each method is called as mix.methodName() and accepts optional { options, config } to override per-model settings.
const answer = await ModelMix.new()
.gpt5mini()
.addText("What is the capital of France?")
.message();
const result = await ModelMix.new()
.gpt5mini()
.addText("Name and capital of 3 South American countries.")
.json(
{ countries: [{ name: "", capital: "" }] }, // schema example
{ countries: [{ name: "country name", capital: "in uppercase" }] }, // descriptions
{ addNote: true } // options
);
// result.countries → [{ name: "Brazil", capital: "BRASILIA" }, ...]
json() signature: json(schemaExample, schemaDescription?, { addSchema, addExample, addNote }?)
await ModelMix.new()
.gpt5mini()
.addText("Tell me a story.")
.stream(({ delta, message }) => {
process.stdout.write(delta);
});
const raw = await ModelMix.new()
.sonnet45think()
.addText("Solve this step by step: 2+2*3")
.raw();
// raw.message, raw.think, raw.tokens, raw.toolCalls, raw.response
message() or json() with lastRawAfter calling message(), json(), block(), or stream(), use lastRaw to access the complete response (tokens, thinking, tool calls, etc.). It has the same structure as raw().
const model = ModelMix.new().gpt5mini().addText("Hello!");
const text = await model.message();
console.log(model.lastRaw.tokens);
// { input: 122, output: 86, total: 541, cost: 0.000319 }
console.log(model.lastRaw.think); // reasoning content (if available)
console.log(model.lastRaw.response); // raw API response
const model = ModelMix.new().sonnet45();
model.addImage('./photo.jpg'); // from file
model.addImageFromUrl('https://example.com/img.png'); // from URL
model.addText('Describe this image.');
const description = await model.message();
const model = ModelMix.new().gpt5mini();
model.setSystemFromFile('./prompts/system.md');
model.addTextFromFile('./prompts/task.md');
model.replace({
'{role}': 'data analyst',
'{language}': 'Spanish'
});
model.replaceKeyFromFile('{code}', './src/utils.js');
console.log(await model.message());
const pool = ModelMix.new({ config: { roundRobin: true } })
.gpt5mini()
.sonnet45()
.gemini3flash();
// Each call rotates to the next model
const r1 = await pool.new().addText("Request 1").message();
const r2 = await pool.new().addText("Request 2").message();
const model = ModelMix.new({ config: { max_history: 10 } }).gpt5nano();
model.setSystem('You are an assistant. Today is ' + new Date().toISOString());
await model.addMCP('@modelcontextprotocol/server-brave-search');
model.addText('Use Internet: What is the latest news about AI?');
console.log(await model.message());
Requires BRAVE_API_KEY in .env for Brave Search MCP.
const model = ModelMix.new({ config: { max_history: 10 } }).gpt5mini();
model.addTool({
name: "get_weather",
description: "Get weather for a city",
inputSchema: {
type: "object",
properties: { city: { type: "string" } },
required: ["city"]
}
}, async ({ city }) => {
return `The weather in ${city} is sunny, 25C`;
});
model.addText("What's the weather in Tokyo?");
console.log(await model.message());
const model = ModelMix.new({
config: {
bottleneck: {
maxConcurrent: 4,
minTime: 1000
}
}
}).gpt5mini();
const model = ModelMix.new({
config: { debug: 2 } // 0=silent, 1=minimal, 2=summary, 3=full
}).gpt5mini();
For full debug output, also set the env: DEBUG=ModelMix* node script.js
// These use providers with free quotas (OpenRouter, Groq, Cerebras)
const model = ModelMix.new()
.gptOss()
.kimiK2()
.deepseekR1()
.hermes3()
.addText("What is the capital of France?");
console.log(await model.message());
const chat = ModelMix.new({ config: { max_history: 10 } }).gpt5mini();
chat.addText("My name is Martin.");
await chat.message();
chat.addText("What's my name?");
const reply = await chat.message(); // "Martin"
package.json for modelmix before running npm install.ModelMix.new() static factory to create instances (not new ModelMix())..env and load with dotenv/config or process.loadEnvFile(). Never hardcode keys.addTool(), set max_history to at least 3..json() for structured output instead of parsing text manually..message() for simple text, .raw() when you need tokens/thinking/toolCalls.think to the method name (e.g. sonnet45think()).{key} syntax in both system prompts and user messages.require) but supports ESM import via { ModelMix }.MixOpenAI, MixAnthropic, MixGoogle, MixPerplexity, MixGroq, MixTogether, MixGrok, MixOpenRouter, MixOllama, MixLMStudio, MixCustom, MixCerebras, MixFireworks, MixMiniMax.| Method | Returns | Description |
| --- | --- | --- |
| .addText(text) | this | Add user message |
| .addTextFromFile(path) | this | Add user message from file |
| .setSystem(text) | this | Set system prompt |
| .setSystemFromFile(path) | this | Set system prompt from file |
| .addImage(path) | this | Add image from file |
| .addImageFromUrl(url) | this | Add image from URL or data URI |
| .replace({}) | this | Set placeholder replacements |
| .replaceKeyFromFile(key, path) | this | Replace placeholder with file content |
| .message() | Promise<string> | Get text response |
| .json(example, desc?, opts?) | Promise<object> | Get structured JSON |
| .raw() | Promise<{message, think, toolCalls, tokens, response}> | Full response |
| .lastRaw | object \| null | Full response from last message()/json()/block()/stream() call |
| .stream(callback) | Promise | Stream response |
| .block() | Promise<string> | Extract code block from response |
| .addMCP(package) | Promise | Add MCP server tools |
| .addTool(def, callback) | this | Register custom local tool |
| .addTools([{tool, callback}]) | this | Register multiple tools |
| .removeTool(name) | this | Remove a tool |
| .listTools() | {local, mcp} | List registered tools |
| .new() | ModelMix | Clone instance sharing models |
| .attach(key, provider) | this | Attach custom provider |
tools
Use when work should span one or more detached tasks but still behave like one job with a single owner context. TaskFlow is the durable flow substrate under authoring layers like Lobster, ACPX, plugins, or plain code. Keep conditional logic in the caller; use TaskFlow for flow identity, child-task linkage, waiting state, revision-checked mutations, and user-facing emergence.
tools
# Lobster Lobster executes multi-step workflows with approval checkpoints. Use it when: - User wants a repeatable automation (triage, monitor, sync) - Actions need human approval before executing (send, post, delete) - Multiple tool calls should run as one deterministic operation ## When to use Lobster | User intent | Use Lobster? | | ------------------------------------------------------ | --------------------------
tools
# Lobster Lobster executes multi-step workflows with approval checkpoints. Use it when: - User wants a repeatable automation (triage, monitor, sync) - Actions need human approval before executing (send, post, delete) - Multiple tool calls should run as one deterministic operation ## When to use Lobster | User intent | Use Lobster? | | ------------------------------------------------------ | --------------------------
tools
A CLI tool for making authenticated requests to the X (Twitter) API. Use this skill when you need to post tweets, reply, quote, search, read posts, manage followers, send DMs, upload media, or interact with any X API v2 endpoint.