@flink-app/mistral-adapter
v2.0.0-alpha.134
Published
Mistral AI adapter for Flink AI framework
Readme
@flink-app/mistral-adapter
Mistral AI adapter for the Flink AI framework. Provides integration with Mistral's models via the Chat Completions API using the official @mistralai/mistralai SDK.
Installation
npm install @flink-app/mistral-adapter
# or
pnpm add @flink-app/mistral-adapterThe @mistralai/mistralai package is included as a dependency, so you don't need to install it separately.
Usage
Basic Setup
import { MistralAdapter } from "@flink-app/mistral-adapter";
import { FlinkApp } from "@flink-app/flink";
const app = new FlinkApp({
ai: {
llms: {
default: new MistralAdapter({
apiKey: process.env.MISTRAL_API_KEY!,
model: "mistral-large-4-0"
}),
},
},
});
await app.start();Legacy API (still supported):
// Backward-compatible constructor
new MistralAdapter(process.env.MISTRAL_API_KEY!, "mistral-medium-latest")Agent Instructions
Define your agent's behavior using the instructions property:
// src/agents/support_agent.ts
export const Agent: FlinkAgentProps = {
name: "support_agent",
instructions: "You are a helpful customer support agent.",
tools: ["get_order_status"],
model: { adapterId: "default" },
};How it works:
- Instructions are prepended as a system message to every conversation
- Follows Vercel AI SDK pattern for consistency
- Additional system messages in the conversation are passed through as-is
Multiple Adapters
You can register multiple Mistral adapters with different configurations:
const app = new FlinkApp({
ai: {
llms: {
// Frontier model - best for agentic and coding use cases
default: new MistralAdapter({
apiKey: process.env.MISTRAL_API_KEY!,
model: "mistral-medium-latest"
}),
// Efficient model - good balance of capability and cost
fast: new MistralAdapter({
apiKey: process.env.MISTRAL_API_KEY!,
model: "mistral-small-latest"
}),
// Code completion specialist
code: new MistralAdapter({
apiKey: process.env.MISTRAL_API_KEY!,
model: "codestral-latest"
}),
},
},
});Reasoning (Mistral Large 4, Medium 3.5, Small 4)
Mistral's current generation are hybrid instruct-and-reasoning models: the same model answers directly or thinks first, controlled per request with reasoning_effort. The adapter exposes this as the reasoningEffort option:
const adapter = new MistralAdapter({
apiKey: process.env.MISTRAL_API_KEY!,
model: "mistral-large-4-0",
reasoningEffort: "high", // "high" | "none" (+ "minimal" | "low" | "medium" | "xhigh" accepted by the API)
});| Value | Behaviour |
|-------|-----------|
| (omitted) | Parameter not sent; the model uses its default |
| "high" | Full thinking trace before the answer / tool calls. Mistral recommends this for agentic and coding work. Costs more output tokens. |
| "none" | Minimal thinking, no thinking chunks returned |
How thinking flows through Flink:
- Thinking is streamed as
reasoningchunks and surfaced by the agent asreasoning_deltaevents onfullStream. It is never included intextStreamorresult.message. - The trace is stored as a
thinkingcontent block on the assistant message and replayed to Mistral on later turns and alongside tool calls. Mistral's docs warn that dropping the trace between turns significantly degrades output quality, so this happens automatically. - Assistant messages that carry no trace are still sent as plain strings, exactly as before.
for await (const event of response.fullStream) {
if (event.type === "reasoning_delta") process.stderr.write(event.delta); // model's thinking
if (event.type === "text_delta") process.stdout.write(event.delta); // answer
}Tool calling is unchanged: Mistral Large 4 uses the same tools / tool_calls / role: "tool" Chat Completions format as earlier models, including parallel tool calls.
Structured Output and Tool Choice
An agent's model.structuredOutput is sent as responseFormat: { type: "json_schema", jsonSchema: { name, description, schemaDefinition, strict } } (strict defaults to true). The parsed reply is available as result.structured.
model.toolChoice is sent as toolChoice: "auto", "none" and "required" pass through, { type: "tool", name } becomes { type: "function", function: { name } }. Only sent when the request carries tools.
Debug Logging
const adapter = new MistralAdapter({
apiKey: process.env.MISTRAL_API_KEY!,
model: "mistral-medium-latest",
debug: true // Enable debug logging for this adapter
});When debug: true, the adapter logs full request parameters and tool call decisions made by the LLM.
Supported Models
This adapter works with all Mistral chat models. As of October 2026:
| Use Case | Recommended Model | Why |
|----------|------------------|-----|
| Frontier / agentic / coding / reasoning | mistral-large-4-0 | Mistral Large 4 - 1T-parameter (52B active) open-weight hybrid instruct-and-reasoning MoE, natively multimodal, 160+ languages. Mistral advertises a 1M-token context, but preview API routes currently report ~512K; check the limit on the endpoint you use. Supports reasoningEffort. |
| Balanced agentic / coding | mistral-medium-latest | Mistral Medium 3.5 - frontier-class multimodal model optimized for agentic and coding use cases. Supports reasoningEffort. |
| Cost-efficient tasks | mistral-small-latest | Mistral Small 4 - hybrid model unifying instruct, reasoning, and coding. Supports reasoningEffort. |
| Previous generation (Apache 2.0) | mistral-large-latest | Mistral Large 3 - general-purpose multimodal model. Verify which version the -latest alias resolves to in Mistral's model docs. |
| Code completion | codestral-latest | Codestral - code completion specialist |
| Edge / small footprint | Ministral 3 series (3B, 8B, 14B) | Compact text and vision models |
Mistral Large 4 is in public preview on Mistral's API (released 2026-10-06). Pin the explicit mistral-large-4-0 id rather than a -latest alias.
See the Mistral models overview for the full, up-to-date list of model IDs.
Features
- ✅ Full tool calling support - including parallel tool calls in a single response
- ✅ Reasoning -
reasoning_effortfor hybrid models; thinking streamed asreasoning_delta, kept out of answer text, and replayed across turns - ✅ Event-based streaming - via the SDK's
chat.stream() - ✅ Multimodal input - text + image content blocks (https URLs and base64 data URLs)
- ✅ Tool call ID normalization - Mistral requires tool call IDs to be exactly 9 alphanumeric characters; IDs from conversation history that originated with another provider are deterministically remapped
- ✅ Token usage tracking - prompt and completion tokens reported per request
- ✅ Schema sanitization - tool input schemas cleaned for Mistral compatibility
API
MistralAdapter
new MistralAdapter(options: MistralAdapterOptions)
new MistralAdapter(apiKey: string, model: string) // legacy| Option | Type | Default | Description |
|--------|------|---------|-------------|
| apiKey | string | — | Mistral API key |
| model | string | — | Model id, e.g. mistral-large-4-0 |
| reasoningEffort | MistralReasoningEffort | (not sent) | "none" \| "minimal" \| "low" \| "medium" \| "high" \| "xhigh"; sent as reasoning_effort |
| debug | boolean | false | Log full request params and tool call decisions |
Exports: MistralAdapter, MistralAdapterOptions, MistralReasoningEffort.
Architecture Notes
Flink Integration
The adapter implements Flink's LLMAdapter interface:
- Flink's
instructions→ prepended as{ role: "system" }message - Flink's
messages→ converted to Mistral chat messages (system/user/assistant/tool roles) - Flink's tool schema → converted to Mistral's function format (
{ type: "function", function: {...} }) - Streamed deltas → mapped to Flink's
LLMStreamChunkevents (text, reasoning, tool_call, usage, done) - Flink's
thinkingcontent blocks ↔ MistralThinkChunks ({ type: "thinking", thinking: [{ type: "text", text }], signature? })
Each API call is one turn:
- Flink's AgentRunner handles the multi-turn loop (call API → execute tools → call API again)
- Tool results are sent back as
{ role: "tool", toolCallId, content }messages
ESM-only SDK
The @mistralai/mistralai SDK v2 is ESM-only. This adapter is compiled to CommonJS (like the rest of the Flink ecosystem) and loads the SDK via a dynamic import(), so it works in both CommonJS and ESM applications without configuration.
Temperature
Temperature is only sent to the API when the agent explicitly configured one — Mistral recommends values between 0.0 and 0.7, and the default varies by model.
Requirements
- Node.js >= 18
- @flink-app/flink >= 2.0.0-alpha.125 (for
reasoningstream chunks andthinkingcontent blocks)
License
MIT
Resources
- Mistral AI documentation
- Mistral models overview
- Function calling guide
- Reasoning guide (
reasoning_effort, thinking chunks) - Mistral Large 4 announcement
