@warlock.js/ai-mistral 5.30.0 → 5.32.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/CHANGELOG.md CHANGED
@@ -4,6 +4,31 @@ All notable changes to `@warlock.js/ai-mistral` are documented in this file.
4
4
 
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). `@warlock.js/*` packages are released in lockstep — every package shares the same version number, so a version below may list only the changes that affected this package.
6
6
 
7
+ ## 5.32.0 - 2026-10-18
8
+
9
+ ### Changed
10
+
11
+ - Pin the package development compiler to TypeScript 7.0.2 and use explicit Node types and source roots with supported module resolution.
12
+
13
+ ## 5.31.0 - 2026-10-18
14
+
15
+ ### Added
16
+
17
+ - An adapter contract test verifies that aborting `signal` rejects `complete()` and `stream()` on the model and cancels the HTTP request.
18
+ - `MistralModelConfig.promptCacheKey` is sent as `prompt_cache_key`.
19
+
20
+ ### Changed
21
+
22
+ - Chat calls inherit `providerOptions.openai.body` from the OpenAI adapter, including its protected fields and one-level plain-object merge. Use only this provider's accepted fields when sharing fallback options. Native `countTokens` remains absent; `sdk.count(text)` is an offline estimate.
23
+
24
+ ### Fixed
25
+
26
+ - `MISTRAL_DEFAULT_PRICING` matches Mistral's current price list (2026-10-17), with cache-read rates and API ids beside the `-latest` aliases. Retired Pixtral and Magistral entries are removed.
27
+
28
+ ### Upgrading
29
+
30
+ - **BREAKING** `pixtral-*` and `magistral-*` models no longer have built-in prices, so a USD budget on them rejects the run as unpriced. Pass `pricing` for them.
31
+
7
32
  ## 5.30.0 - 2026-10-16
8
33
 
9
34
  ### Changed
@@ -81,6 +106,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
81
106
  ### Changed
82
107
 
83
108
  - Lockstep release maintenance and dependency refresh.
109
+
84
110
  ## 5.20.0 - 2026-09-24
85
111
 
86
112
  ### Changed
package/README.md CHANGED
@@ -54,12 +54,12 @@ MistralModelConfig {
54
54
 
55
55
  The headline `-latest` aliases are exported as `MISTRAL_MODELS`, grouped by role:
56
56
 
57
- | Family | Aliases | Notes |
58
- | --- | --- | --- |
59
- | `chat` | `mistral-large-latest`, `mistral-medium-latest`, `mistral-small-latest` | General-purpose multimodal flagship / mid / small |
60
- | `vision` | `pixtral-large-latest`, `pixtral-12b` | Dedicated multimodal (image input) |
61
- | `reasoning` | `magistral-medium-latest`, `magistral-small-latest` | Chain-of-thought reasoning |
62
- | `embedding` | `mistral-embed` | Via the OpenAI-compatible `/v1/embeddings` |
57
+ | Family | Aliases | Notes |
58
+ | ----------- | ----------------------------------------------------------------------- | ------------------------------------------------- |
59
+ | `chat` | `mistral-large-latest`, `mistral-medium-latest`, `mistral-small-latest` | General-purpose multimodal flagship / mid / small |
60
+ | `vision` | `pixtral-large-latest`, `pixtral-12b` | Dedicated multimodal (image input) |
61
+ | `reasoning` | `magistral-medium-latest`, `magistral-small-latest` | Chain-of-thought reasoning |
62
+ | `embedding` | `mistral-embed` | Via the OpenAI-compatible `/v1/embeddings` |
63
63
 
64
64
  `mistral.model()` accepts any id string, so version-pinned ids (`mistral-large-2512`, `magistral-medium-2509`) work just as well — capability inference keys off the family fragment, not the alias list.
65
65
 
@@ -67,16 +67,16 @@ The headline `-latest` aliases are exported as `MISTRAL_MODELS`, grouped by role
67
67
 
68
68
  The wrapper injects **Mistral-aware** capability inference before delegating to the OpenAI adapter, because the OpenAI prefix lists (`gpt-4o`, `o3`, …) never match Mistral names. An explicit value always wins over inference.
69
69
 
70
- | Capability | Default |
71
- | --- | --- |
72
- | `vision` | Inferred from the model name — `true` for the `pixtral` family and the recent multimodal generations (`mistral-large`, `mistral-medium`, `ministral-3`); `false` otherwise. |
73
- | `reasoning` | Inferred from the model name — `true` for the `magistral` family and the hybrid `mistral-small` generation; `false` otherwise. Drives whether `reasoning.effort` maps to `reasoning_effort` on the wire. |
74
- | `structuredOutput` | `true`, unless `responseFormat` is forced to `"json_object"` / `"text"`. |
70
+ | Capability | Default |
71
+ | ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
72
+ | `vision` | Inferred from the model name — `true` for the `pixtral` family and the recent multimodal generations (`mistral-large`, `mistral-medium`, `ministral-3`); `false` otherwise. |
73
+ | `reasoning` | Inferred from the model name — `true` for the `magistral` family and the hybrid `mistral-small` generation; `false` otherwise. Drives whether `reasoning.effort` maps to `reasoning_effort` on the wire. |
74
+ | `structuredOutput` | `true`, unless `responseFormat` is forced to `"json_object"` / `"text"`. |
75
75
 
76
76
  ```ts
77
- mistral.model({ name: "pixtral-large-latest" }); // vision auto-true
78
- mistral.model({ name: "magistral-medium-latest" }); // reasoning auto-true
79
- mistral.model({ name: "some-fine-tune", vision: true }); // explicit override
77
+ mistral.model({ name: "pixtral-large-latest" }); // vision auto-true
78
+ mistral.model({ name: "magistral-medium-latest" }); // reasoning auto-true
79
+ mistral.model({ name: "some-fine-tune", vision: true }); // explicit override
80
80
  ```
81
81
 
82
82
  ## Embeddings
package/cjs/index.cjs CHANGED
@@ -106,49 +106,76 @@ const MISTRAL_MODELS = {
106
106
  embedding: ["mistral-embed"]
107
107
  };
108
108
  /**
109
- * Conservative default USD pricing registry (per 1,000,000 tokens),
110
- * keyed by stable `-latest` alias, surfaced onto every model unless the
111
- * caller overrides it via SDK-level or per-model `pricing`.
109
+ * Default USD pricing registry (per 1,000,000 tokens), keyed by API id
110
+ * and alias, surfaced onto every model unless the caller overrides it via
111
+ * SDK-level or per-model `pricing`. `cachedInput` is the prompt-cache
112
+ * rate (10% of input).
112
113
  *
113
- * These are sane published-list approximations for budgeting / cost-truth
114
- * out of the box — Mistral revises rates and ships new generations, so
115
- * pass an explicit `pricing` registry to `new MistralSDK({ pricing })`
116
- * for billing-grade numbers. Resolution at `model()` time always lets a
117
- * caller-supplied rate win: per-model `pricing` > SDK `pricing` > these
118
- * defaults > `undefined`.
114
+ * Source: https://docs.mistral.ai/inference/pricing and the model pages
115
+ * under https://docs.mistral.ai/models (API ids and aliases), fetched
116
+ * 2026-10-17. Mistral Large 4 (public preview, sale price) and the
117
+ * retired Pixtral / Magistral models are not included. Resolution at
118
+ * `model()` time always lets a caller-supplied rate win: per-model
119
+ * `pricing` > SDK `pricing` > these defaults > `undefined`.
119
120
  */
120
121
  const MISTRAL_DEFAULT_PRICING = {
121
122
  "mistral-large-latest": {
122
- input: 2,
123
- output: 6
123
+ input: .5,
124
+ output: 1.5,
125
+ cachedInput: .05
126
+ },
127
+ "mistral-large-2512": {
128
+ input: .5,
129
+ output: 1.5,
130
+ cachedInput: .05
124
131
  },
125
132
  "mistral-medium-latest": {
126
- input: .4,
127
- output: 2
133
+ input: 1.5,
134
+ output: 7.5,
135
+ cachedInput: .15
128
136
  },
129
- "mistral-small-latest": {
130
- input: .1,
131
- output: .3
137
+ "mistral-medium-3-5": {
138
+ input: 1.5,
139
+ output: 7.5,
140
+ cachedInput: .15
132
141
  },
133
- "pixtral-large-latest": {
134
- input: 2,
135
- output: 6
142
+ "mistral-small-latest": {
143
+ input: .15,
144
+ output: .6,
145
+ cachedInput: .015
136
146
  },
137
- "pixtral-12b": {
147
+ "mistral-small-2603": {
138
148
  input: .15,
139
- output: .15
149
+ output: .6,
150
+ cachedInput: .015
140
151
  },
141
- "magistral-medium-latest": {
142
- input: 2,
143
- output: 5
152
+ "ministral-14b-latest": {
153
+ input: .2,
154
+ output: .2,
155
+ cachedInput: .02
144
156
  },
145
- "magistral-small-latest": {
146
- input: .5,
147
- output: 1.5
157
+ "ministral-14b-2512": {
158
+ input: .2,
159
+ output: .2,
160
+ cachedInput: .02
161
+ },
162
+ "codestral-latest": {
163
+ input: .3,
164
+ output: .9,
165
+ cachedInput: .03
166
+ },
167
+ "codestral-2508": {
168
+ input: .3,
169
+ output: .9,
170
+ cachedInput: .03
148
171
  },
149
172
  "mistral-embed": {
150
173
  input: .1,
151
174
  output: 0
175
+ },
176
+ "mistral-embed-2312": {
177
+ input: .1,
178
+ output: 0
152
179
  }
153
180
  };
154
181
 
package/cjs/index.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["OpenAISDK"],"sources":["../../../../../../../packages/ai-mistral/src/known-models.ts","../../../../../../../packages/ai-mistral/src/sdk.ts"],"sourcesContent":["import type { ModelPricing } from \"@warlock.js/ai\";\n\n/**\n * Model-name fragments identifying Mistral families that accept image\n * input (vision / multimodal).\n *\n * - `pixtral` — Mistral's dedicated multimodal family\n * (`pixtral-large-latest`, `pixtral-12b`); documents, charts, and\n * natural images.\n * - `mistral-large` / `mistral-medium` — the recent frontier generations\n * (Large 3, Medium 3.5) are natively multimodal.\n * - `ministral-3` — the current small open-weight line ships with\n * best-in-class text + vision.\n *\n * Matched as a **substring** (not a strict prefix) so the date / version\n * suffixes Mistral appends (`pixtral-large-2411`, `mistral-large-2512`)\n * and the `-latest` aliases are all covered without enumerating every\n * release tag. Override per-model via\n * `mistral.model({ name, vision: true | false })` — explicit config\n * always wins over inference.\n *\n * Maintenance: append a fragment when Mistral ships a multimodal family\n * that doesn't already match.\n */\nconst VISION_CAPABLE_SUBSTRINGS = [\n \"pixtral\",\n \"mistral-large\",\n \"mistral-medium\",\n \"ministral-3\",\n] as const;\n\n/**\n * Model-name fragments identifying Mistral families that perform\n * explicit chain-of-thought reasoning.\n *\n * - `magistral` — Mistral's dedicated reasoning family\n * (`magistral-medium-latest`, `magistral-small-latest`); emits\n * tokenized thinking chunks.\n * - `mistral-small-4` / `mistral-small` — the current Small generation\n * is a hybrid model that unifies instruct + reasoning + coding.\n *\n * Matched as a **substring** so version-tagged ids\n * (`magistral-medium-2509`, `mistral-small-2603`) and `-latest` aliases\n * are covered. Override per-model via\n * `mistral.model({ name, reasoning: true | false })` — explicit config\n * always wins over inference.\n *\n * Maintenance: append a fragment when Mistral ships a reasoning family\n * that doesn't already match.\n */\nconst REASONING_CAPABLE_SUBSTRINGS = [\"magistral\", \"mistral-small\"] as const;\n\n/**\n * Infer whether a Mistral model id accepts image input (vision) based on\n * the known multimodal-family fragments. Unknown ids default to `false`\n * so passing an image attachment to a text-only model surfaces a clear,\n * agent-side capability error instead of an opaque Mistral 400.\n *\n * @example\n * inferVisionCapability(\"pixtral-large-latest\"); // → true\n * inferVisionCapability(\"mistral-large-2512\"); // → true\n * inferVisionCapability(\"magistral-medium-latest\");// → false\n * inferVisionCapability(\"mistral-embed\"); // → false\n */\nexport function inferVisionCapability(modelName: string): boolean {\n const normalized = modelName.toLowerCase();\n\n return VISION_CAPABLE_SUBSTRINGS.some((fragment) => normalized.includes(fragment));\n}\n\n/**\n * Infer whether a Mistral model id is a reasoning model (the `magistral`\n * family plus the hybrid `mistral-small` generation) based on the known\n * fragments. Unknown ids default to `false` so the adapter never forwards\n * an unsupported `reasoning_effort` param to a non-reasoning model.\n *\n * @example\n * inferReasoningCapability(\"magistral-medium-latest\"); // → true\n * inferReasoningCapability(\"mistral-small-2603\"); // → true\n * inferReasoningCapability(\"mistral-large-latest\"); // → false\n * inferReasoningCapability(\"pixtral-12b\"); // → false\n */\nexport function inferReasoningCapability(modelName: string): boolean {\n const normalized = modelName.toLowerCase();\n\n return REASONING_CAPABLE_SUBSTRINGS.some((fragment) => normalized.includes(fragment));\n}\n\n/**\n * Stable `-latest` alias ids for the headline Mistral chat / embeddings\n * models, grouped by role. Convenience constants only — `mistral.model()`\n * accepts any id string, so a version-pinned id\n * (`mistral-large-2512`, `magistral-medium-2509`) works just as well.\n * Capability inference keys off the family fragment, not this list, so a\n * newer alias is recognized the moment its name matches a fragment in\n * {@link inferVisionCapability} / {@link inferReasoningCapability}.\n */\nexport const MISTRAL_MODELS = {\n /** General-purpose multimodal flagship / mid / small chat aliases. */\n chat: [\"mistral-large-latest\", \"mistral-medium-latest\", \"mistral-small-latest\"],\n /** Dedicated multimodal (vision) aliases — the `pixtral` family. */\n vision: [\"pixtral-large-latest\", \"pixtral-12b\"],\n /** Dedicated reasoning aliases — the `magistral` family. */\n reasoning: [\"magistral-medium-latest\", \"magistral-small-latest\"],\n /** Embeddings model reachable via the OpenAI-compatible `/v1/embeddings`. */\n embedding: [\"mistral-embed\"],\n} as const;\n\n/**\n * Conservative default USD pricing registry (per 1,000,000 tokens),\n * keyed by stable `-latest` alias, surfaced onto every model unless the\n * caller overrides it via SDK-level or per-model `pricing`.\n *\n * These are sane published-list approximations for budgeting / cost-truth\n * out of the box — Mistral revises rates and ships new generations, so\n * pass an explicit `pricing` registry to `new MistralSDK({ pricing })`\n * for billing-grade numbers. Resolution at `model()` time always lets a\n * caller-supplied rate win: per-model `pricing` > SDK `pricing` > these\n * defaults > `undefined`.\n */\nexport const MISTRAL_DEFAULT_PRICING: Record<string, ModelPricing> = {\n \"mistral-large-latest\": { input: 2, output: 6 },\n \"mistral-medium-latest\": { input: 0.4, output: 2 },\n \"mistral-small-latest\": { input: 0.1, output: 0.3 },\n \"pixtral-large-latest\": { input: 2, output: 6 },\n \"pixtral-12b\": { input: 0.15, output: 0.15 },\n \"magistral-medium-latest\": { input: 2, output: 5 },\n \"magistral-small-latest\": { input: 0.5, output: 1.5 },\n \"mistral-embed\": { input: 0.1, output: 0 },\n};\n","import type {\n EmbedderConfig,\n EmbedderContract,\n ModelContract,\n ModelPricing,\n SDKAdapterContract,\n} from \"@warlock.js/ai\";\nimport { OpenAISDK } from \"@warlock.js/ai-openai\";\nimport type { MistralModelConfig, MistralSDKConfig } from \"./config.type\";\nimport {\n inferReasoningCapability,\n inferVisionCapability,\n MISTRAL_DEFAULT_PRICING,\n} from \"./known-models\";\n\n/** Default OpenAI-compatible base URL for the Mistral API. */\nconst MISTRAL_BASE_URL = \"https://api.mistral.ai/v1\";\n\n/** Default provider label stamped onto every model this SDK produces. */\nconst MISTRAL_PROVIDER = \"mistral\";\n\n/**\n * Mistral-backed implementation of `SDKAdapterContract`.\n *\n * **Role.** The package entry point for Mistral AI chat + embeddings.\n * Mistral exposes an **OpenAI-compatible** API (`/v1/chat/completions`,\n * `/v1/embeddings`), so `MistralSDK` is a *thin wrapper* over the\n * battle-tested {@link OpenAISDK} — it does NOT re-implement the wire\n * protocol, streaming loop, tool-call accumulation, structured-output\n * mapping, error wrapping, or token accounting. It constructs one\n * internal `OpenAISDK` pointed at Mistral's `baseURL` with\n * `provider: \"mistral\"`, and delegates `model()` / `embedder()` /\n * `count()` straight to it.\n *\n * **What this wrapper adds on top of the OpenAI adapter:**\n * - **Defaults.** Injects Mistral's `baseURL` + `provider` label and a\n * default {@link MISTRAL_DEFAULT_PRICING} registry so cost truth works\n * out of the box. All are overridable via config.\n * - **Provider-correct capability inference.** Mistral's model names\n * aren't OpenAI names, so the OpenAI prefix lists never match. Before\n * delegating `model()`, this wrapper infers `vision` (the `pixtral`\n * family + recent multimodal generations) and `reasoning` (the\n * `magistral` family + hybrid `mistral-small`) from *this provider's*\n * fragment lists and passes them as explicit overrides — which the\n * inner `OpenAISDK` honors verbatim. A caller-supplied explicit\n * `vision` / `reasoning` still wins.\n *\n * Construct one SDK per account and reuse it everywhere; the single\n * underlying `OpenAI` client (connection pool, auth, rate-limit state)\n * is shared by every model / embedder produced here.\n *\n * **Note — no image generation.** Mistral has no OpenAI-compatible image\n * endpoint, so `image()` is intentionally NOT exposed. The structural\n * absence of the method IS the capability guard (see\n * `SDKAdapterContract.image`): `ai.mistral.image(...)` is a compile-time\n * error rather than a runtime failure.\n *\n * @example\n * const mistral = new MistralSDK({ apiKey: process.env.MISTRAL_API_KEY! });\n * const model = mistral.model({ name: \"mistral-large-latest\", temperature: 0.7 });\n * const embedder = mistral.embedder({ name: \"mistral-embed\" });\n *\n * @example\n * // Compose into an `ai.mistral` namespace for ergonomic agent wiring.\n * const ai = { agent, tool, systemPrompt, mistral: new MistralSDK({ apiKey }) };\n * const reasoner = ai.agent({ model: ai.mistral.model({ name: \"magistral-medium-latest\" }) });\n */\nexport class MistralSDK implements SDKAdapterContract {\n /**\n * The wrapped OpenAI-compatible adapter doing all the real work. Built\n * once in the constructor with Mistral's `baseURL`, `provider` label,\n * and merged pricing registry; every public method delegates to it.\n */\n private readonly openai: OpenAISDK;\n\n public constructor(config: MistralSDKConfig) {\n const { provider, baseURL, pricing, ...clientOptions } = config;\n\n // Caller pricing wins per model id; otherwise fall back to this\n // provider's published-list defaults so cost truth works out of the box.\n const mergedPricing: Record<string, ModelPricing> = {\n ...MISTRAL_DEFAULT_PRICING,\n ...pricing,\n };\n\n this.openai = new OpenAISDK({\n ...clientOptions,\n baseURL: baseURL ?? MISTRAL_BASE_URL,\n provider: provider ?? MISTRAL_PROVIDER,\n pricing: mergedPricing,\n });\n }\n\n /**\n * Build a `ModelContract` for a Mistral chat model.\n *\n * Delegates to the inner `OpenAISDK.model()` but first injects\n * **Mistral-aware capability inference**: when the caller omits\n * `vision` / `reasoning`, they're inferred from this provider's family\n * fragments (`pixtral` → vision, `magistral` / `mistral-small` →\n * reasoning, see `known-models.ts`) and passed down as explicit\n * overrides. Without this step the wrapped OpenAI adapter would check\n * Mistral ids against OpenAI prefixes (`gpt-4o`, `o3`, …) and wrongly\n * report every Mistral model as non-vision / non-reasoning.\n *\n * A caller-supplied explicit `vision` / `reasoning` is preserved as-is\n * (explicit config always wins over inference). Pricing resolution is\n * handled downstream by `OpenAISDK` against the merged registry:\n * per-model `pricing` > SDK registry (caller + Mistral defaults) >\n * `undefined`.\n */\n public model(config: MistralModelConfig): ModelContract {\n const resolvedConfig: MistralModelConfig = {\n ...config,\n vision: config.vision ?? inferVisionCapability(config.name),\n reasoning: config.reasoning ?? inferReasoningCapability(config.name),\n };\n\n return this.openai.model(resolvedConfig);\n }\n\n /**\n * Rough offline token-count estimate. Delegates to the wrapped\n * `OpenAISDK.count()` (the shared character-heuristic from the core\n * package) — good for budgeting / quota guards, not billing. The\n * optional model id is forwarded but currently ignored.\n */\n public async count(text: string, model?: string): Promise<number> {\n return this.openai.count(text, model);\n }\n\n /**\n * Build an `EmbedderContract` bound to this SDK's client. Mistral\n * serves embeddings (`mistral-embed`) through the OpenAI-compatible\n * `/v1/embeddings` endpoint, so this delegates straight to\n * `OpenAISDK.embedder()`.\n *\n * @example\n * const embedder = mistral.embedder({ name: \"mistral-embed\" });\n * const { vector } = await embedder.embed(\"Hello world\");\n */\n public embedder(config: EmbedderConfig): EmbedderContract {\n // `embedder` is optional on the contract but always present on the\n // wrapped OpenAI adapter — assert it for the delegation.\n return this.openai.embedder!(config);\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAwBA,MAAM,4BAA4B;CAChC;CACA;CACA;CACA;AACF;;;;;;;;;;;;;;;;;;;;AAqBA,MAAM,+BAA+B,CAAC,aAAa,eAAe;;;;;;;;;;;;;AAclE,SAAgB,sBAAsB,WAA4B;CAChE,MAAM,aAAa,UAAU,YAAY;CAEzC,OAAO,0BAA0B,MAAM,aAAa,WAAW,SAAS,QAAQ,CAAC;AACnF;;;;;;;;;;;;;AAcA,SAAgB,yBAAyB,WAA4B;CACnE,MAAM,aAAa,UAAU,YAAY;CAEzC,OAAO,6BAA6B,MAAM,aAAa,WAAW,SAAS,QAAQ,CAAC;AACtF;;;;;;;;;;AAWA,MAAa,iBAAiB;;CAE5B,MAAM;EAAC;EAAwB;EAAyB;CAAsB;;CAE9E,QAAQ,CAAC,wBAAwB,aAAa;;CAE9C,WAAW,CAAC,2BAA2B,wBAAwB;;CAE/D,WAAW,CAAC,eAAe;AAC7B;;;;;;;;;;;;;AAcA,MAAa,0BAAwD;CACnE,wBAAwB;EAAE,OAAO;EAAG,QAAQ;CAAE;CAC9C,yBAAyB;EAAE,OAAO;EAAK,QAAQ;CAAE;CACjD,wBAAwB;EAAE,OAAO;EAAK,QAAQ;CAAI;CAClD,wBAAwB;EAAE,OAAO;EAAG,QAAQ;CAAE;CAC9C,eAAe;EAAE,OAAO;EAAM,QAAQ;CAAK;CAC3C,2BAA2B;EAAE,OAAO;EAAG,QAAQ;CAAE;CACjD,0BAA0B;EAAE,OAAO;EAAK,QAAQ;CAAI;CACpD,iBAAiB;EAAE,OAAO;EAAK,QAAQ;CAAE;AAC3C;;;;;ACjHA,MAAM,mBAAmB;;AAGzB,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgDzB,IAAa,aAAb,MAAsD;CAQpD,AAAO,YAAY,QAA0B;EAC3C,MAAM,EAAE,UAAU,SAAS,SAAS,GAAG,kBAAkB;EAIzD,MAAM,gBAA8C;GAClD,GAAG;GACH,GAAG;EACL;EAEA,KAAK,SAAS,IAAIA,gCAAU;GAC1B,GAAG;GACH,SAAS,WAAW;GACpB,UAAU,YAAY;GACtB,SAAS;EACX,CAAC;CACH;;;;;;;;;;;;;;;;;;;CAoBA,AAAO,MAAM,QAA2C;EACtD,MAAM,iBAAqC;GACzC,GAAG;GACH,QAAQ,OAAO,UAAU,sBAAsB,OAAO,IAAI;GAC1D,WAAW,OAAO,aAAa,yBAAyB,OAAO,IAAI;EACrE;EAEA,OAAO,KAAK,OAAO,MAAM,cAAc;CACzC;;;;;;;CAQA,MAAa,MAAM,MAAc,OAAiC;EAChE,OAAO,KAAK,OAAO,MAAM,MAAM,KAAK;CACtC;;;;;;;;;;;CAYA,AAAO,SAAS,QAA0C;EAGxD,OAAO,KAAK,OAAO,SAAU,MAAM;CACrC;AACF"}
1
+ {"version":3,"file":"index.cjs","names":["OpenAISDK"],"sources":["../../../../../../../packages/ai-mistral/src/known-models.ts","../../../../../../../packages/ai-mistral/src/sdk.ts"],"sourcesContent":["import type { ModelPricing } from \"@warlock.js/ai\";\n\n/**\n * Model-name fragments identifying Mistral families that accept image\n * input (vision / multimodal).\n *\n * - `pixtral` — Mistral's dedicated multimodal family\n * (`pixtral-large-latest`, `pixtral-12b`); documents, charts, and\n * natural images.\n * - `mistral-large` / `mistral-medium` — the recent frontier generations\n * (Large 3, Medium 3.5) are natively multimodal.\n * - `ministral-3` — the current small open-weight line ships with\n * best-in-class text + vision.\n *\n * Matched as a **substring** (not a strict prefix) so the date / version\n * suffixes Mistral appends (`pixtral-large-2411`, `mistral-large-2512`)\n * and the `-latest` aliases are all covered without enumerating every\n * release tag. Override per-model via\n * `mistral.model({ name, vision: true | false })` — explicit config\n * always wins over inference.\n *\n * Maintenance: append a fragment when Mistral ships a multimodal family\n * that doesn't already match.\n */\nconst VISION_CAPABLE_SUBSTRINGS = [\n \"pixtral\",\n \"mistral-large\",\n \"mistral-medium\",\n \"ministral-3\",\n] as const;\n\n/**\n * Model-name fragments identifying Mistral families that perform\n * explicit chain-of-thought reasoning.\n *\n * - `magistral` — Mistral's dedicated reasoning family\n * (`magistral-medium-latest`, `magistral-small-latest`); emits\n * tokenized thinking chunks.\n * - `mistral-small-4` / `mistral-small` — the current Small generation\n * is a hybrid model that unifies instruct + reasoning + coding.\n *\n * Matched as a **substring** so version-tagged ids\n * (`magistral-medium-2509`, `mistral-small-2603`) and `-latest` aliases\n * are covered. Override per-model via\n * `mistral.model({ name, reasoning: true | false })` — explicit config\n * always wins over inference.\n *\n * Maintenance: append a fragment when Mistral ships a reasoning family\n * that doesn't already match.\n */\nconst REASONING_CAPABLE_SUBSTRINGS = [\"magistral\", \"mistral-small\"] as const;\n\n/**\n * Infer whether a Mistral model id accepts image input (vision) based on\n * the known multimodal-family fragments. Unknown ids default to `false`\n * so passing an image attachment to a text-only model surfaces a clear,\n * agent-side capability error instead of an opaque Mistral 400.\n *\n * @example\n * inferVisionCapability(\"pixtral-large-latest\"); // → true\n * inferVisionCapability(\"mistral-large-2512\"); // → true\n * inferVisionCapability(\"magistral-medium-latest\");// → false\n * inferVisionCapability(\"mistral-embed\"); // → false\n */\nexport function inferVisionCapability(modelName: string): boolean {\n const normalized = modelName.toLowerCase();\n\n return VISION_CAPABLE_SUBSTRINGS.some((fragment) => normalized.includes(fragment));\n}\n\n/**\n * Infer whether a Mistral model id is a reasoning model (the `magistral`\n * family plus the hybrid `mistral-small` generation) based on the known\n * fragments. Unknown ids default to `false` so the adapter never forwards\n * an unsupported `reasoning_effort` param to a non-reasoning model.\n *\n * @example\n * inferReasoningCapability(\"magistral-medium-latest\"); // → true\n * inferReasoningCapability(\"mistral-small-2603\"); // → true\n * inferReasoningCapability(\"mistral-large-latest\"); // → false\n * inferReasoningCapability(\"pixtral-12b\"); // → false\n */\nexport function inferReasoningCapability(modelName: string): boolean {\n const normalized = modelName.toLowerCase();\n\n return REASONING_CAPABLE_SUBSTRINGS.some((fragment) => normalized.includes(fragment));\n}\n\n/**\n * Stable `-latest` alias ids for the headline Mistral chat / embeddings\n * models, grouped by role. Convenience constants only — `mistral.model()`\n * accepts any id string, so a version-pinned id\n * (`mistral-large-2512`, `magistral-medium-2509`) works just as well.\n * Capability inference keys off the family fragment, not this list, so a\n * newer alias is recognized the moment its name matches a fragment in\n * {@link inferVisionCapability} / {@link inferReasoningCapability}.\n */\nexport const MISTRAL_MODELS = {\n /** General-purpose multimodal flagship / mid / small chat aliases. */\n chat: [\"mistral-large-latest\", \"mistral-medium-latest\", \"mistral-small-latest\"],\n /** Dedicated multimodal (vision) aliases — the `pixtral` family. */\n vision: [\"pixtral-large-latest\", \"pixtral-12b\"],\n /** Dedicated reasoning aliases — the `magistral` family. */\n reasoning: [\"magistral-medium-latest\", \"magistral-small-latest\"],\n /** Embeddings model reachable via the OpenAI-compatible `/v1/embeddings`. */\n embedding: [\"mistral-embed\"],\n} as const;\n\n/**\n * Default USD pricing registry (per 1,000,000 tokens), keyed by API id\n * and alias, surfaced onto every model unless the caller overrides it via\n * SDK-level or per-model `pricing`. `cachedInput` is the prompt-cache\n * rate (10% of input).\n *\n * Source: https://docs.mistral.ai/inference/pricing and the model pages\n * under https://docs.mistral.ai/models (API ids and aliases), fetched\n * 2026-10-17. Mistral Large 4 (public preview, sale price) and the\n * retired Pixtral / Magistral models are not included. Resolution at\n * `model()` time always lets a caller-supplied rate win: per-model\n * `pricing` > SDK `pricing` > these defaults > `undefined`.\n */\nexport const MISTRAL_DEFAULT_PRICING: Readonly<Record<string, ModelPricing>> = {\n \"mistral-large-latest\": { input: 0.5, output: 1.5, cachedInput: 0.05 },\n \"mistral-large-2512\": { input: 0.5, output: 1.5, cachedInput: 0.05 },\n \"mistral-medium-latest\": { input: 1.5, output: 7.5, cachedInput: 0.15 },\n \"mistral-medium-3-5\": { input: 1.5, output: 7.5, cachedInput: 0.15 },\n \"mistral-small-latest\": { input: 0.15, output: 0.6, cachedInput: 0.015 },\n \"mistral-small-2603\": { input: 0.15, output: 0.6, cachedInput: 0.015 },\n \"ministral-14b-latest\": { input: 0.2, output: 0.2, cachedInput: 0.02 },\n \"ministral-14b-2512\": { input: 0.2, output: 0.2, cachedInput: 0.02 },\n \"codestral-latest\": { input: 0.3, output: 0.9, cachedInput: 0.03 },\n \"codestral-2508\": { input: 0.3, output: 0.9, cachedInput: 0.03 },\n \"mistral-embed\": { input: 0.1, output: 0 },\n \"mistral-embed-2312\": { input: 0.1, output: 0 },\n};\n","import type {\n EmbedderConfig,\n EmbedderContract,\n ModelContract,\n ModelPricing,\n SDKAdapterContract,\n} from \"@warlock.js/ai\";\nimport { OpenAISDK } from \"@warlock.js/ai-openai\";\nimport type { MistralModelConfig, MistralSDKConfig } from \"./config.type\";\nimport {\n inferReasoningCapability,\n inferVisionCapability,\n MISTRAL_DEFAULT_PRICING,\n} from \"./known-models\";\n\n/** Default OpenAI-compatible base URL for the Mistral API. */\nconst MISTRAL_BASE_URL = \"https://api.mistral.ai/v1\";\n\n/** Default provider label stamped onto every model this SDK produces. */\nconst MISTRAL_PROVIDER = \"mistral\";\n\n/**\n * Mistral-backed implementation of `SDKAdapterContract`.\n *\n * **Role.** The package entry point for Mistral AI chat + embeddings.\n * Mistral exposes an **OpenAI-compatible** API (`/v1/chat/completions`,\n * `/v1/embeddings`), so `MistralSDK` is a *thin wrapper* over the\n * battle-tested {@link OpenAISDK} — it does NOT re-implement the wire\n * protocol, streaming loop, tool-call accumulation, structured-output\n * mapping, error wrapping, or token accounting. It constructs one\n * internal `OpenAISDK` pointed at Mistral's `baseURL` with\n * `provider: \"mistral\"`, and delegates `model()` / `embedder()` /\n * `count()` straight to it.\n *\n * **What this wrapper adds on top of the OpenAI adapter:**\n * - **Defaults.** Injects Mistral's `baseURL` + `provider` label and a\n * default {@link MISTRAL_DEFAULT_PRICING} registry so cost truth works\n * out of the box. All are overridable via config.\n * - **Provider-correct capability inference.** Mistral's model names\n * aren't OpenAI names, so the OpenAI prefix lists never match. Before\n * delegating `model()`, this wrapper infers `vision` (the `pixtral`\n * family + recent multimodal generations) and `reasoning` (the\n * `magistral` family + hybrid `mistral-small`) from *this provider's*\n * fragment lists and passes them as explicit overrides — which the\n * inner `OpenAISDK` honors verbatim. A caller-supplied explicit\n * `vision` / `reasoning` still wins.\n *\n * Construct one SDK per account and reuse it everywhere; the single\n * underlying `OpenAI` client (connection pool, auth, rate-limit state)\n * is shared by every model / embedder produced here.\n *\n * **Note — no image generation.** Mistral has no OpenAI-compatible image\n * endpoint, so `image()` is intentionally NOT exposed. The structural\n * absence of the method IS the capability guard (see\n * `SDKAdapterContract.image`): `ai.mistral.image(...)` is a compile-time\n * error rather than a runtime failure.\n *\n * @example\n * const mistral = new MistralSDK({ apiKey: process.env.MISTRAL_API_KEY! });\n * const model = mistral.model({ name: \"mistral-large-latest\", temperature: 0.7 });\n * const embedder = mistral.embedder({ name: \"mistral-embed\" });\n *\n * @example\n * // Compose into an `ai.mistral` namespace for ergonomic agent wiring.\n * const ai = { agent, tool, systemPrompt, mistral: new MistralSDK({ apiKey }) };\n * const reasoner = ai.agent({ model: ai.mistral.model({ name: \"magistral-medium-latest\" }) });\n */\nexport class MistralSDK implements SDKAdapterContract {\n /**\n * The wrapped OpenAI-compatible adapter doing all the real work. Built\n * once in the constructor with Mistral's `baseURL`, `provider` label,\n * and merged pricing registry; every public method delegates to it.\n */\n private readonly openai: OpenAISDK;\n\n public constructor(config: MistralSDKConfig) {\n const { provider, baseURL, pricing, ...clientOptions } = config;\n\n // Caller pricing wins per model id; otherwise fall back to this\n // provider's published-list defaults so cost truth works out of the box.\n const mergedPricing: Record<string, ModelPricing> = {\n ...MISTRAL_DEFAULT_PRICING,\n ...pricing,\n };\n\n this.openai = new OpenAISDK({\n ...clientOptions,\n baseURL: baseURL ?? MISTRAL_BASE_URL,\n provider: provider ?? MISTRAL_PROVIDER,\n pricing: mergedPricing,\n });\n }\n\n /**\n * Build a `ModelContract` for a Mistral chat model.\n *\n * Delegates to the inner `OpenAISDK.model()` but first injects\n * **Mistral-aware capability inference**: when the caller omits\n * `vision` / `reasoning`, they're inferred from this provider's family\n * fragments (`pixtral` → vision, `magistral` / `mistral-small` →\n * reasoning, see `known-models.ts`) and passed down as explicit\n * overrides. Without this step the wrapped OpenAI adapter would check\n * Mistral ids against OpenAI prefixes (`gpt-4o`, `o3`, …) and wrongly\n * report every Mistral model as non-vision / non-reasoning.\n *\n * A caller-supplied explicit `vision` / `reasoning` is preserved as-is\n * (explicit config always wins over inference). Pricing resolution is\n * handled downstream by `OpenAISDK` against the merged registry:\n * per-model `pricing` > SDK registry (caller + Mistral defaults) >\n * `undefined`.\n */\n public model(config: MistralModelConfig): ModelContract {\n const resolvedConfig: MistralModelConfig = {\n ...config,\n vision: config.vision ?? inferVisionCapability(config.name),\n reasoning: config.reasoning ?? inferReasoningCapability(config.name),\n };\n\n return this.openai.model(resolvedConfig);\n }\n\n /**\n * Rough offline token-count estimate. Delegates to the wrapped\n * `OpenAISDK.count()` (the shared character-heuristic from the core\n * package) — good for budgeting / quota guards, not billing. The\n * optional model id is forwarded but currently ignored.\n */\n public async count(text: string, model?: string): Promise<number> {\n return this.openai.count(text, model);\n }\n\n /**\n * Build an `EmbedderContract` bound to this SDK's client. Mistral\n * serves embeddings (`mistral-embed`) through the OpenAI-compatible\n * `/v1/embeddings` endpoint, so this delegates straight to\n * `OpenAISDK.embedder()`.\n *\n * @example\n * const embedder = mistral.embedder({ name: \"mistral-embed\" });\n * const { vector } = await embedder.embed(\"Hello world\");\n */\n public embedder(config: EmbedderConfig): EmbedderContract {\n // `embedder` is optional on the contract but always present on the\n // wrapped OpenAI adapter — assert it for the delegation.\n return this.openai.embedder!(config);\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAwBA,MAAM,4BAA4B;CAChC;CACA;CACA;CACA;AACF;;;;;;;;;;;;;;;;;;;;AAqBA,MAAM,+BAA+B,CAAC,aAAa,eAAe;;;;;;;;;;;;;AAclE,SAAgB,sBAAsB,WAA4B;CAChE,MAAM,aAAa,UAAU,YAAY;CAEzC,OAAO,0BAA0B,MAAM,aAAa,WAAW,SAAS,QAAQ,CAAC;AACnF;;;;;;;;;;;;;AAcA,SAAgB,yBAAyB,WAA4B;CACnE,MAAM,aAAa,UAAU,YAAY;CAEzC,OAAO,6BAA6B,MAAM,aAAa,WAAW,SAAS,QAAQ,CAAC;AACtF;;;;;;;;;;AAWA,MAAa,iBAAiB;;CAE5B,MAAM;EAAC;EAAwB;EAAyB;CAAsB;;CAE9E,QAAQ,CAAC,wBAAwB,aAAa;;CAE9C,WAAW,CAAC,2BAA2B,wBAAwB;;CAE/D,WAAW,CAAC,eAAe;AAC7B;;;;;;;;;;;;;;AAeA,MAAa,0BAAkE;CAC7E,wBAAwB;EAAE,OAAO;EAAK,QAAQ;EAAK,aAAa;CAAK;CACrE,sBAAsB;EAAE,OAAO;EAAK,QAAQ;EAAK,aAAa;CAAK;CACnE,yBAAyB;EAAE,OAAO;EAAK,QAAQ;EAAK,aAAa;CAAK;CACtE,sBAAsB;EAAE,OAAO;EAAK,QAAQ;EAAK,aAAa;CAAK;CACnE,wBAAwB;EAAE,OAAO;EAAM,QAAQ;EAAK,aAAa;CAAM;CACvE,sBAAsB;EAAE,OAAO;EAAM,QAAQ;EAAK,aAAa;CAAM;CACrE,wBAAwB;EAAE,OAAO;EAAK,QAAQ;EAAK,aAAa;CAAK;CACrE,sBAAsB;EAAE,OAAO;EAAK,QAAQ;EAAK,aAAa;CAAK;CACnE,oBAAoB;EAAE,OAAO;EAAK,QAAQ;EAAK,aAAa;CAAK;CACjE,kBAAkB;EAAE,OAAO;EAAK,QAAQ;EAAK,aAAa;CAAK;CAC/D,iBAAiB;EAAE,OAAO;EAAK,QAAQ;CAAE;CACzC,sBAAsB;EAAE,OAAO;EAAK,QAAQ;CAAE;AAChD;;;;;ACtHA,MAAM,mBAAmB;;AAGzB,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgDzB,IAAa,aAAb,MAAsD;CAQpD,AAAO,YAAY,QAA0B;EAC3C,MAAM,EAAE,UAAU,SAAS,SAAS,GAAG,kBAAkB;EAIzD,MAAM,gBAA8C;GAClD,GAAG;GACH,GAAG;EACL;EAEA,KAAK,SAAS,IAAIA,gCAAU;GAC1B,GAAG;GACH,SAAS,WAAW;GACpB,UAAU,YAAY;GACtB,SAAS;EACX,CAAC;CACH;;;;;;;;;;;;;;;;;;;CAoBA,AAAO,MAAM,QAA2C;EACtD,MAAM,iBAAqC;GACzC,GAAG;GACH,QAAQ,OAAO,UAAU,sBAAsB,OAAO,IAAI;GAC1D,WAAW,OAAO,aAAa,yBAAyB,OAAO,IAAI;EACrE;EAEA,OAAO,KAAK,OAAO,MAAM,cAAc;CACzC;;;;;;;CAQA,MAAa,MAAM,MAAc,OAAiC;EAChE,OAAO,KAAK,OAAO,MAAM,MAAM,KAAK;CACtC;;;;;;;;;;;CAYA,AAAO,SAAS,QAA0C;EAGxD,OAAO,KAAK,OAAO,SAAU,MAAM;CACrC;AACF"}
@@ -1,6 +1,5 @@
1
1
  import { OpenAISDKConfig } from "@warlock.js/ai-openai";
2
2
  import { ModelConfig } from "@warlock.js/ai";
3
-
4
3
  //#region ../../packages/ai-mistral/src/config.type.d.ts
5
4
  /**
6
5
  * Configuration for the Mistral SDK adapter.
@@ -34,7 +33,7 @@ import { ModelConfig } from "@warlock.js/ai";
34
33
  * pricing: { "mistral-large-latest": { input: 2, output: 6 } },
35
34
  * });
36
35
  */
37
- type MistralSDKConfig = OpenAISDKConfig;
36
+ export type MistralSDKConfig = OpenAISDKConfig;
38
37
  /**
39
38
  * Per-model configuration for `MistralSDK.model()`. Extends the neutral
40
39
  * {@link ModelConfig} with the same capability overrides the wrapped
@@ -52,7 +51,7 @@ type MistralSDKConfig = OpenAISDKConfig;
52
51
  * mistral.model({ name: "magistral-medium-latest" }); // reasoning auto-true
53
52
  * mistral.model({ name: "some-fine-tune", vision: true }); // explicit override
54
53
  */
55
- type MistralModelConfig = ModelConfig & {
54
+ export type MistralModelConfig = ModelConfig & {
56
55
  /**
57
56
  * Override the auto-inferred vision capability. When omitted, the
58
57
  * adapter checks the model id against this provider's multimodal
@@ -76,6 +75,16 @@ type MistralModelConfig = ModelConfig & {
76
75
  * `responseFormat` forces a loose mode (`"json_object"` / `"text"`).
77
76
  */
78
77
  structuredOutput?: boolean;
78
+ /**
79
+ * Prompt-cache routing key, sent as `prompt_cache_key` so requests that
80
+ * share a prefix land on the same Mistral cache. Use a stable value per
81
+ * conversation or tenant. Sent only while the SDK keeps its default
82
+ * provider label.
83
+ *
84
+ * @example
85
+ * model({ name: "mistral-large-latest", promptCacheKey: `conversation:${conversationId}` });
86
+ */
87
+ promptCacheKey?: string;
79
88
  /**
80
89
  * Override the wire-level `response_format` the adapter emits when the
81
90
  * caller supplies a response schema (`"json_schema"` | `"json_object"`
@@ -97,5 +106,4 @@ type MistralModelConfig = ModelConfig & {
97
106
  audio?: boolean;
98
107
  };
99
108
  //#endregion
100
- export { MistralModelConfig, MistralSDKConfig };
101
109
  //# sourceMappingURL=config.type.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.type.d.mts","names":[],"sources":["../../../../../../../packages/ai-mistral/src/config.type.ts"],"mappings":";;;;;;AAmCA;;;;AAA8C;AAmB9C;;;;;;;;;;;;AA0CO;;;;;;;;;;;;;KA7DK,gBAAA,GAAmB,eAAe;;;;;;;;;;;;;;;;;;KAmBlC,kBAAA,GAAqB,WAAW;;;;;;;;EAQ1C,MAAA;;;;;;;;;EASA,SAAA;;;;;;EAMA,gBAAA;;;;;;;EAOA,cAAA;;;;;;EAMA,GAAA;;;;;;EAMA,KAAA;AAAA"}
1
+ {"version":3,"file":"config.type.d.mts","names":[],"sources":["../../../../../../../packages/ai-mistral/src/config.type.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YAmCY,mBAAmB;;;;;;;;;;;;;;;;;;YAmBnB,qBAAqB;;;;;;;;EAQ/B;;;;;;;;;EASA;;;;;;EAMA;;;;;;;;;;EAUA;;;;;;;EAOA;;;;;;EAMA;;;;;;EAMA"}
@@ -1,5 +1,4 @@
1
1
  import { ModelPricing } from "@warlock.js/ai";
2
-
3
2
  //#region ../../packages/ai-mistral/src/known-models.d.ts
4
3
  /**
5
4
  * Infer whether a Mistral model id accepts image input (vision) based on
@@ -13,7 +12,7 @@ import { ModelPricing } from "@warlock.js/ai";
13
12
  * inferVisionCapability("magistral-medium-latest");// → false
14
13
  * inferVisionCapability("mistral-embed"); // → false
15
14
  */
16
- declare function inferVisionCapability(modelName: string): boolean;
15
+ export declare function inferVisionCapability(modelName: string): boolean;
17
16
  /**
18
17
  * Infer whether a Mistral model id is a reasoning model (the `magistral`
19
18
  * family plus the hybrid `mistral-small` generation) based on the known
@@ -26,7 +25,7 @@ declare function inferVisionCapability(modelName: string): boolean;
26
25
  * inferReasoningCapability("mistral-large-latest"); // → false
27
26
  * inferReasoningCapability("pixtral-12b"); // → false
28
27
  */
29
- declare function inferReasoningCapability(modelName: string): boolean;
28
+ export declare function inferReasoningCapability(modelName: string): boolean;
30
29
  /**
31
30
  * Stable `-latest` alias ids for the headline Mistral chat / embeddings
32
31
  * models, grouped by role. Convenience constants only — `mistral.model()`
@@ -36,25 +35,29 @@ declare function inferReasoningCapability(modelName: string): boolean;
36
35
  * newer alias is recognized the moment its name matches a fragment in
37
36
  * {@link inferVisionCapability} / {@link inferReasoningCapability}.
38
37
  */
39
- declare const MISTRAL_MODELS: {
40
- /** General-purpose multimodal flagship / mid / small chat aliases. */readonly chat: readonly ["mistral-large-latest", "mistral-medium-latest", "mistral-small-latest"]; /** Dedicated multimodal (vision) aliases — the `pixtral` family. */
41
- readonly vision: readonly ["pixtral-large-latest", "pixtral-12b"]; /** Dedicated reasoning aliases — the `magistral` family. */
42
- readonly reasoning: readonly ["magistral-medium-latest", "magistral-small-latest"]; /** Embeddings model reachable via the OpenAI-compatible `/v1/embeddings`. */
38
+ export declare const MISTRAL_MODELS: {
39
+ /** General-purpose multimodal flagship / mid / small chat aliases. */
40
+ readonly chat: readonly ["mistral-large-latest", "mistral-medium-latest", "mistral-small-latest"];
41
+ /** Dedicated multimodal (vision) aliases — the `pixtral` family. */
42
+ readonly vision: readonly ["pixtral-large-latest", "pixtral-12b"];
43
+ /** Dedicated reasoning aliases — the `magistral` family. */
44
+ readonly reasoning: readonly ["magistral-medium-latest", "magistral-small-latest"];
45
+ /** Embeddings model reachable via the OpenAI-compatible `/v1/embeddings`. */
43
46
  readonly embedding: readonly ["mistral-embed"];
44
47
  };
45
48
  /**
46
- * Conservative default USD pricing registry (per 1,000,000 tokens),
47
- * keyed by stable `-latest` alias, surfaced onto every model unless the
48
- * caller overrides it via SDK-level or per-model `pricing`.
49
+ * Default USD pricing registry (per 1,000,000 tokens), keyed by API id
50
+ * and alias, surfaced onto every model unless the caller overrides it via
51
+ * SDK-level or per-model `pricing`. `cachedInput` is the prompt-cache
52
+ * rate (10% of input).
49
53
  *
50
- * These are sane published-list approximations for budgeting / cost-truth
51
- * out of the box — Mistral revises rates and ships new generations, so
52
- * pass an explicit `pricing` registry to `new MistralSDK({ pricing })`
53
- * for billing-grade numbers. Resolution at `model()` time always lets a
54
- * caller-supplied rate win: per-model `pricing` > SDK `pricing` > these
55
- * defaults > `undefined`.
54
+ * Source: https://docs.mistral.ai/inference/pricing and the model pages
55
+ * under https://docs.mistral.ai/models (API ids and aliases), fetched
56
+ * 2026-10-17. Mistral Large 4 (public preview, sale price) and the
57
+ * retired Pixtral / Magistral models are not included. Resolution at
58
+ * `model()` time always lets a caller-supplied rate win: per-model
59
+ * `pricing` > SDK `pricing` > these defaults > `undefined`.
56
60
  */
57
- declare const MISTRAL_DEFAULT_PRICING: Record<string, ModelPricing>;
61
+ export declare const MISTRAL_DEFAULT_PRICING: Readonly<Record<string, ModelPricing>>;
58
62
  //#endregion
59
- export { MISTRAL_DEFAULT_PRICING, MISTRAL_MODELS, inferReasoningCapability, inferVisionCapability };
60
63
  //# sourceMappingURL=known-models.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"known-models.d.mts","names":[],"sources":["../../../../../../../packages/ai-mistral/src/known-models.ts"],"mappings":";;;;;AAgEA;;;;AAAuD;AAkBvD;;;;AAA0D;iBAlB1C,qBAAA,CAAsB,SAAiB;;;;;;;;;;AAwDvD;;;iBAtCgB,wBAAA,CAAyB,SAAiB;AAsCO;;;;;;;;;AAAA,cAvBpD,cAAA;;;;;;;;;;;;;;;;;;cAuBA,uBAAA,EAAyB,MAAM,SAAS,YAAA"}
1
+ {"version":3,"file":"known-models.d.mts","names":[],"sources":["../../../../../../../packages/ai-mistral/src/known-models.ts"],"mappings":";;;;;;;;;;;;;;wBAgEgB,sBAAsB;;;;;;;;;;;;;wBAkBtB,yBAAyB;;;;;;;;;;qBAe5B;;WAEX;;WAEA;;WAEA;;WAEA;;;;;;;;;;;;;;;qBAgBW,yBAAyB,SAAS,eAAe"}
@@ -103,49 +103,76 @@ const MISTRAL_MODELS = {
103
103
  embedding: ["mistral-embed"]
104
104
  };
105
105
  /**
106
- * Conservative default USD pricing registry (per 1,000,000 tokens),
107
- * keyed by stable `-latest` alias, surfaced onto every model unless the
108
- * caller overrides it via SDK-level or per-model `pricing`.
106
+ * Default USD pricing registry (per 1,000,000 tokens), keyed by API id
107
+ * and alias, surfaced onto every model unless the caller overrides it via
108
+ * SDK-level or per-model `pricing`. `cachedInput` is the prompt-cache
109
+ * rate (10% of input).
109
110
  *
110
- * These are sane published-list approximations for budgeting / cost-truth
111
- * out of the box — Mistral revises rates and ships new generations, so
112
- * pass an explicit `pricing` registry to `new MistralSDK({ pricing })`
113
- * for billing-grade numbers. Resolution at `model()` time always lets a
114
- * caller-supplied rate win: per-model `pricing` > SDK `pricing` > these
115
- * defaults > `undefined`.
111
+ * Source: https://docs.mistral.ai/inference/pricing and the model pages
112
+ * under https://docs.mistral.ai/models (API ids and aliases), fetched
113
+ * 2026-10-17. Mistral Large 4 (public preview, sale price) and the
114
+ * retired Pixtral / Magistral models are not included. Resolution at
115
+ * `model()` time always lets a caller-supplied rate win: per-model
116
+ * `pricing` > SDK `pricing` > these defaults > `undefined`.
116
117
  */
117
118
  const MISTRAL_DEFAULT_PRICING = {
118
119
  "mistral-large-latest": {
119
- input: 2,
120
- output: 6
120
+ input: .5,
121
+ output: 1.5,
122
+ cachedInput: .05
123
+ },
124
+ "mistral-large-2512": {
125
+ input: .5,
126
+ output: 1.5,
127
+ cachedInput: .05
121
128
  },
122
129
  "mistral-medium-latest": {
123
- input: .4,
124
- output: 2
130
+ input: 1.5,
131
+ output: 7.5,
132
+ cachedInput: .15
125
133
  },
126
- "mistral-small-latest": {
127
- input: .1,
128
- output: .3
134
+ "mistral-medium-3-5": {
135
+ input: 1.5,
136
+ output: 7.5,
137
+ cachedInput: .15
129
138
  },
130
- "pixtral-large-latest": {
131
- input: 2,
132
- output: 6
139
+ "mistral-small-latest": {
140
+ input: .15,
141
+ output: .6,
142
+ cachedInput: .015
133
143
  },
134
- "pixtral-12b": {
144
+ "mistral-small-2603": {
135
145
  input: .15,
136
- output: .15
146
+ output: .6,
147
+ cachedInput: .015
137
148
  },
138
- "magistral-medium-latest": {
139
- input: 2,
140
- output: 5
149
+ "ministral-14b-latest": {
150
+ input: .2,
151
+ output: .2,
152
+ cachedInput: .02
141
153
  },
142
- "magistral-small-latest": {
143
- input: .5,
144
- output: 1.5
154
+ "ministral-14b-2512": {
155
+ input: .2,
156
+ output: .2,
157
+ cachedInput: .02
158
+ },
159
+ "codestral-latest": {
160
+ input: .3,
161
+ output: .9,
162
+ cachedInput: .03
163
+ },
164
+ "codestral-2508": {
165
+ input: .3,
166
+ output: .9,
167
+ cachedInput: .03
145
168
  },
146
169
  "mistral-embed": {
147
170
  input: .1,
148
171
  output: 0
172
+ },
173
+ "mistral-embed-2312": {
174
+ input: .1,
175
+ output: 0
149
176
  }
150
177
  };
151
178
 
@@ -1 +1 @@
1
- {"version":3,"file":"known-models.mjs","names":[],"sources":["../../../../../../../packages/ai-mistral/src/known-models.ts"],"sourcesContent":["import type { ModelPricing } from \"@warlock.js/ai\";\n\n/**\n * Model-name fragments identifying Mistral families that accept image\n * input (vision / multimodal).\n *\n * - `pixtral` — Mistral's dedicated multimodal family\n * (`pixtral-large-latest`, `pixtral-12b`); documents, charts, and\n * natural images.\n * - `mistral-large` / `mistral-medium` — the recent frontier generations\n * (Large 3, Medium 3.5) are natively multimodal.\n * - `ministral-3` — the current small open-weight line ships with\n * best-in-class text + vision.\n *\n * Matched as a **substring** (not a strict prefix) so the date / version\n * suffixes Mistral appends (`pixtral-large-2411`, `mistral-large-2512`)\n * and the `-latest` aliases are all covered without enumerating every\n * release tag. Override per-model via\n * `mistral.model({ name, vision: true | false })` — explicit config\n * always wins over inference.\n *\n * Maintenance: append a fragment when Mistral ships a multimodal family\n * that doesn't already match.\n */\nconst VISION_CAPABLE_SUBSTRINGS = [\n \"pixtral\",\n \"mistral-large\",\n \"mistral-medium\",\n \"ministral-3\",\n] as const;\n\n/**\n * Model-name fragments identifying Mistral families that perform\n * explicit chain-of-thought reasoning.\n *\n * - `magistral` — Mistral's dedicated reasoning family\n * (`magistral-medium-latest`, `magistral-small-latest`); emits\n * tokenized thinking chunks.\n * - `mistral-small-4` / `mistral-small` — the current Small generation\n * is a hybrid model that unifies instruct + reasoning + coding.\n *\n * Matched as a **substring** so version-tagged ids\n * (`magistral-medium-2509`, `mistral-small-2603`) and `-latest` aliases\n * are covered. Override per-model via\n * `mistral.model({ name, reasoning: true | false })` — explicit config\n * always wins over inference.\n *\n * Maintenance: append a fragment when Mistral ships a reasoning family\n * that doesn't already match.\n */\nconst REASONING_CAPABLE_SUBSTRINGS = [\"magistral\", \"mistral-small\"] as const;\n\n/**\n * Infer whether a Mistral model id accepts image input (vision) based on\n * the known multimodal-family fragments. Unknown ids default to `false`\n * so passing an image attachment to a text-only model surfaces a clear,\n * agent-side capability error instead of an opaque Mistral 400.\n *\n * @example\n * inferVisionCapability(\"pixtral-large-latest\"); // → true\n * inferVisionCapability(\"mistral-large-2512\"); // → true\n * inferVisionCapability(\"magistral-medium-latest\");// → false\n * inferVisionCapability(\"mistral-embed\"); // → false\n */\nexport function inferVisionCapability(modelName: string): boolean {\n const normalized = modelName.toLowerCase();\n\n return VISION_CAPABLE_SUBSTRINGS.some((fragment) => normalized.includes(fragment));\n}\n\n/**\n * Infer whether a Mistral model id is a reasoning model (the `magistral`\n * family plus the hybrid `mistral-small` generation) based on the known\n * fragments. Unknown ids default to `false` so the adapter never forwards\n * an unsupported `reasoning_effort` param to a non-reasoning model.\n *\n * @example\n * inferReasoningCapability(\"magistral-medium-latest\"); // → true\n * inferReasoningCapability(\"mistral-small-2603\"); // → true\n * inferReasoningCapability(\"mistral-large-latest\"); // → false\n * inferReasoningCapability(\"pixtral-12b\"); // → false\n */\nexport function inferReasoningCapability(modelName: string): boolean {\n const normalized = modelName.toLowerCase();\n\n return REASONING_CAPABLE_SUBSTRINGS.some((fragment) => normalized.includes(fragment));\n}\n\n/**\n * Stable `-latest` alias ids for the headline Mistral chat / embeddings\n * models, grouped by role. Convenience constants only — `mistral.model()`\n * accepts any id string, so a version-pinned id\n * (`mistral-large-2512`, `magistral-medium-2509`) works just as well.\n * Capability inference keys off the family fragment, not this list, so a\n * newer alias is recognized the moment its name matches a fragment in\n * {@link inferVisionCapability} / {@link inferReasoningCapability}.\n */\nexport const MISTRAL_MODELS = {\n /** General-purpose multimodal flagship / mid / small chat aliases. */\n chat: [\"mistral-large-latest\", \"mistral-medium-latest\", \"mistral-small-latest\"],\n /** Dedicated multimodal (vision) aliases — the `pixtral` family. */\n vision: [\"pixtral-large-latest\", \"pixtral-12b\"],\n /** Dedicated reasoning aliases — the `magistral` family. */\n reasoning: [\"magistral-medium-latest\", \"magistral-small-latest\"],\n /** Embeddings model reachable via the OpenAI-compatible `/v1/embeddings`. */\n embedding: [\"mistral-embed\"],\n} as const;\n\n/**\n * Conservative default USD pricing registry (per 1,000,000 tokens),\n * keyed by stable `-latest` alias, surfaced onto every model unless the\n * caller overrides it via SDK-level or per-model `pricing`.\n *\n * These are sane published-list approximations for budgeting / cost-truth\n * out of the box — Mistral revises rates and ships new generations, so\n * pass an explicit `pricing` registry to `new MistralSDK({ pricing })`\n * for billing-grade numbers. Resolution at `model()` time always lets a\n * caller-supplied rate win: per-model `pricing` > SDK `pricing` > these\n * defaults > `undefined`.\n */\nexport const MISTRAL_DEFAULT_PRICING: Record<string, ModelPricing> = {\n \"mistral-large-latest\": { input: 2, output: 6 },\n \"mistral-medium-latest\": { input: 0.4, output: 2 },\n \"mistral-small-latest\": { input: 0.1, output: 0.3 },\n \"pixtral-large-latest\": { input: 2, output: 6 },\n \"pixtral-12b\": { input: 0.15, output: 0.15 },\n \"magistral-medium-latest\": { input: 2, output: 5 },\n \"magistral-small-latest\": { input: 0.5, output: 1.5 },\n \"mistral-embed\": { input: 0.1, output: 0 },\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAwBA,MAAM,4BAA4B;CAChC;CACA;CACA;CACA;AACF;;;;;;;;;;;;;;;;;;;;AAqBA,MAAM,+BAA+B,CAAC,aAAa,eAAe;;;;;;;;;;;;;AAclE,SAAgB,sBAAsB,WAA4B;CAChE,MAAM,aAAa,UAAU,YAAY;CAEzC,OAAO,0BAA0B,MAAM,aAAa,WAAW,SAAS,QAAQ,CAAC;AACnF;;;;;;;;;;;;;AAcA,SAAgB,yBAAyB,WAA4B;CACnE,MAAM,aAAa,UAAU,YAAY;CAEzC,OAAO,6BAA6B,MAAM,aAAa,WAAW,SAAS,QAAQ,CAAC;AACtF;;;;;;;;;;AAWA,MAAa,iBAAiB;;CAE5B,MAAM;EAAC;EAAwB;EAAyB;CAAsB;;CAE9E,QAAQ,CAAC,wBAAwB,aAAa;;CAE9C,WAAW,CAAC,2BAA2B,wBAAwB;;CAE/D,WAAW,CAAC,eAAe;AAC7B;;;;;;;;;;;;;AAcA,MAAa,0BAAwD;CACnE,wBAAwB;EAAE,OAAO;EAAG,QAAQ;CAAE;CAC9C,yBAAyB;EAAE,OAAO;EAAK,QAAQ;CAAE;CACjD,wBAAwB;EAAE,OAAO;EAAK,QAAQ;CAAI;CAClD,wBAAwB;EAAE,OAAO;EAAG,QAAQ;CAAE;CAC9C,eAAe;EAAE,OAAO;EAAM,QAAQ;CAAK;CAC3C,2BAA2B;EAAE,OAAO;EAAG,QAAQ;CAAE;CACjD,0BAA0B;EAAE,OAAO;EAAK,QAAQ;CAAI;CACpD,iBAAiB;EAAE,OAAO;EAAK,QAAQ;CAAE;AAC3C"}
1
+ {"version":3,"file":"known-models.mjs","names":[],"sources":["../../../../../../../packages/ai-mistral/src/known-models.ts"],"sourcesContent":["import type { ModelPricing } from \"@warlock.js/ai\";\n\n/**\n * Model-name fragments identifying Mistral families that accept image\n * input (vision / multimodal).\n *\n * - `pixtral` — Mistral's dedicated multimodal family\n * (`pixtral-large-latest`, `pixtral-12b`); documents, charts, and\n * natural images.\n * - `mistral-large` / `mistral-medium` — the recent frontier generations\n * (Large 3, Medium 3.5) are natively multimodal.\n * - `ministral-3` — the current small open-weight line ships with\n * best-in-class text + vision.\n *\n * Matched as a **substring** (not a strict prefix) so the date / version\n * suffixes Mistral appends (`pixtral-large-2411`, `mistral-large-2512`)\n * and the `-latest` aliases are all covered without enumerating every\n * release tag. Override per-model via\n * `mistral.model({ name, vision: true | false })` — explicit config\n * always wins over inference.\n *\n * Maintenance: append a fragment when Mistral ships a multimodal family\n * that doesn't already match.\n */\nconst VISION_CAPABLE_SUBSTRINGS = [\n \"pixtral\",\n \"mistral-large\",\n \"mistral-medium\",\n \"ministral-3\",\n] as const;\n\n/**\n * Model-name fragments identifying Mistral families that perform\n * explicit chain-of-thought reasoning.\n *\n * - `magistral` — Mistral's dedicated reasoning family\n * (`magistral-medium-latest`, `magistral-small-latest`); emits\n * tokenized thinking chunks.\n * - `mistral-small-4` / `mistral-small` — the current Small generation\n * is a hybrid model that unifies instruct + reasoning + coding.\n *\n * Matched as a **substring** so version-tagged ids\n * (`magistral-medium-2509`, `mistral-small-2603`) and `-latest` aliases\n * are covered. Override per-model via\n * `mistral.model({ name, reasoning: true | false })` — explicit config\n * always wins over inference.\n *\n * Maintenance: append a fragment when Mistral ships a reasoning family\n * that doesn't already match.\n */\nconst REASONING_CAPABLE_SUBSTRINGS = [\"magistral\", \"mistral-small\"] as const;\n\n/**\n * Infer whether a Mistral model id accepts image input (vision) based on\n * the known multimodal-family fragments. Unknown ids default to `false`\n * so passing an image attachment to a text-only model surfaces a clear,\n * agent-side capability error instead of an opaque Mistral 400.\n *\n * @example\n * inferVisionCapability(\"pixtral-large-latest\"); // → true\n * inferVisionCapability(\"mistral-large-2512\"); // → true\n * inferVisionCapability(\"magistral-medium-latest\");// → false\n * inferVisionCapability(\"mistral-embed\"); // → false\n */\nexport function inferVisionCapability(modelName: string): boolean {\n const normalized = modelName.toLowerCase();\n\n return VISION_CAPABLE_SUBSTRINGS.some((fragment) => normalized.includes(fragment));\n}\n\n/**\n * Infer whether a Mistral model id is a reasoning model (the `magistral`\n * family plus the hybrid `mistral-small` generation) based on the known\n * fragments. Unknown ids default to `false` so the adapter never forwards\n * an unsupported `reasoning_effort` param to a non-reasoning model.\n *\n * @example\n * inferReasoningCapability(\"magistral-medium-latest\"); // → true\n * inferReasoningCapability(\"mistral-small-2603\"); // → true\n * inferReasoningCapability(\"mistral-large-latest\"); // → false\n * inferReasoningCapability(\"pixtral-12b\"); // → false\n */\nexport function inferReasoningCapability(modelName: string): boolean {\n const normalized = modelName.toLowerCase();\n\n return REASONING_CAPABLE_SUBSTRINGS.some((fragment) => normalized.includes(fragment));\n}\n\n/**\n * Stable `-latest` alias ids for the headline Mistral chat / embeddings\n * models, grouped by role. Convenience constants only — `mistral.model()`\n * accepts any id string, so a version-pinned id\n * (`mistral-large-2512`, `magistral-medium-2509`) works just as well.\n * Capability inference keys off the family fragment, not this list, so a\n * newer alias is recognized the moment its name matches a fragment in\n * {@link inferVisionCapability} / {@link inferReasoningCapability}.\n */\nexport const MISTRAL_MODELS = {\n /** General-purpose multimodal flagship / mid / small chat aliases. */\n chat: [\"mistral-large-latest\", \"mistral-medium-latest\", \"mistral-small-latest\"],\n /** Dedicated multimodal (vision) aliases — the `pixtral` family. */\n vision: [\"pixtral-large-latest\", \"pixtral-12b\"],\n /** Dedicated reasoning aliases — the `magistral` family. */\n reasoning: [\"magistral-medium-latest\", \"magistral-small-latest\"],\n /** Embeddings model reachable via the OpenAI-compatible `/v1/embeddings`. */\n embedding: [\"mistral-embed\"],\n} as const;\n\n/**\n * Default USD pricing registry (per 1,000,000 tokens), keyed by API id\n * and alias, surfaced onto every model unless the caller overrides it via\n * SDK-level or per-model `pricing`. `cachedInput` is the prompt-cache\n * rate (10% of input).\n *\n * Source: https://docs.mistral.ai/inference/pricing and the model pages\n * under https://docs.mistral.ai/models (API ids and aliases), fetched\n * 2026-10-17. Mistral Large 4 (public preview, sale price) and the\n * retired Pixtral / Magistral models are not included. Resolution at\n * `model()` time always lets a caller-supplied rate win: per-model\n * `pricing` > SDK `pricing` > these defaults > `undefined`.\n */\nexport const MISTRAL_DEFAULT_PRICING: Readonly<Record<string, ModelPricing>> = {\n \"mistral-large-latest\": { input: 0.5, output: 1.5, cachedInput: 0.05 },\n \"mistral-large-2512\": { input: 0.5, output: 1.5, cachedInput: 0.05 },\n \"mistral-medium-latest\": { input: 1.5, output: 7.5, cachedInput: 0.15 },\n \"mistral-medium-3-5\": { input: 1.5, output: 7.5, cachedInput: 0.15 },\n \"mistral-small-latest\": { input: 0.15, output: 0.6, cachedInput: 0.015 },\n \"mistral-small-2603\": { input: 0.15, output: 0.6, cachedInput: 0.015 },\n \"ministral-14b-latest\": { input: 0.2, output: 0.2, cachedInput: 0.02 },\n \"ministral-14b-2512\": { input: 0.2, output: 0.2, cachedInput: 0.02 },\n \"codestral-latest\": { input: 0.3, output: 0.9, cachedInput: 0.03 },\n \"codestral-2508\": { input: 0.3, output: 0.9, cachedInput: 0.03 },\n \"mistral-embed\": { input: 0.1, output: 0 },\n \"mistral-embed-2312\": { input: 0.1, output: 0 },\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAwBA,MAAM,4BAA4B;CAChC;CACA;CACA;CACA;AACF;;;;;;;;;;;;;;;;;;;;AAqBA,MAAM,+BAA+B,CAAC,aAAa,eAAe;;;;;;;;;;;;;AAclE,SAAgB,sBAAsB,WAA4B;CAChE,MAAM,aAAa,UAAU,YAAY;CAEzC,OAAO,0BAA0B,MAAM,aAAa,WAAW,SAAS,QAAQ,CAAC;AACnF;;;;;;;;;;;;;AAcA,SAAgB,yBAAyB,WAA4B;CACnE,MAAM,aAAa,UAAU,YAAY;CAEzC,OAAO,6BAA6B,MAAM,aAAa,WAAW,SAAS,QAAQ,CAAC;AACtF;;;;;;;;;;AAWA,MAAa,iBAAiB;;CAE5B,MAAM;EAAC;EAAwB;EAAyB;CAAsB;;CAE9E,QAAQ,CAAC,wBAAwB,aAAa;;CAE9C,WAAW,CAAC,2BAA2B,wBAAwB;;CAE/D,WAAW,CAAC,eAAe;AAC7B;;;;;;;;;;;;;;AAeA,MAAa,0BAAkE;CAC7E,wBAAwB;EAAE,OAAO;EAAK,QAAQ;EAAK,aAAa;CAAK;CACrE,sBAAsB;EAAE,OAAO;EAAK,QAAQ;EAAK,aAAa;CAAK;CACnE,yBAAyB;EAAE,OAAO;EAAK,QAAQ;EAAK,aAAa;CAAK;CACtE,sBAAsB;EAAE,OAAO;EAAK,QAAQ;EAAK,aAAa;CAAK;CACnE,wBAAwB;EAAE,OAAO;EAAM,QAAQ;EAAK,aAAa;CAAM;CACvE,sBAAsB;EAAE,OAAO;EAAM,QAAQ;EAAK,aAAa;CAAM;CACrE,wBAAwB;EAAE,OAAO;EAAK,QAAQ;EAAK,aAAa;CAAK;CACrE,sBAAsB;EAAE,OAAO;EAAK,QAAQ;EAAK,aAAa;CAAK;CACnE,oBAAoB;EAAE,OAAO;EAAK,QAAQ;EAAK,aAAa;CAAK;CACjE,kBAAkB;EAAE,OAAO;EAAK,QAAQ;EAAK,aAAa;CAAK;CAC/D,iBAAiB;EAAE,OAAO;EAAK,QAAQ;CAAE;CACzC,sBAAsB;EAAE,OAAO;EAAK,QAAQ;CAAE;AAChD"}
package/esm/sdk.d.mts CHANGED
@@ -1,6 +1,5 @@
1
1
  import { MistralModelConfig, MistralSDKConfig } from "./config.type.mjs";
2
2
  import { EmbedderConfig, EmbedderContract, ModelContract, SDKAdapterContract } from "@warlock.js/ai";
3
-
4
3
  //#region ../../packages/ai-mistral/src/sdk.d.ts
5
4
  /**
6
5
  * Mistral-backed implementation of `SDKAdapterContract`.
@@ -48,7 +47,7 @@ import { EmbedderConfig, EmbedderContract, ModelContract, SDKAdapterContract } f
48
47
  * const ai = { agent, tool, systemPrompt, mistral: new MistralSDK({ apiKey }) };
49
48
  * const reasoner = ai.agent({ model: ai.mistral.model({ name: "magistral-medium-latest" }) });
50
49
  */
51
- declare class MistralSDK implements SDKAdapterContract {
50
+ export declare class MistralSDK implements SDKAdapterContract {
52
51
  /**
53
52
  * The wrapped OpenAI-compatible adapter doing all the real work. Built
54
53
  * once in the constructor with Mistral's `baseURL`, `provider` label,
@@ -95,5 +94,4 @@ declare class MistralSDK implements SDKAdapterContract {
95
94
  embedder(config: EmbedderConfig): EmbedderContract;
96
95
  }
97
96
  //#endregion
98
- export { MistralSDK };
99
97
  //# sourceMappingURL=sdk.d.mts.map
package/esm/sdk.d.mts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"sdk.d.mts","names":[],"sources":["../../../../../../../packages/ai-mistral/src/sdk.ts"],"mappings":";;;;;;AAmEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0E2D;;;;;;;;;;;;;;cA1E9C,UAAA,YAAsB,kBAAA;;;;;;mBAMhB,MAAA;cAEE,MAAA,EAAQ,gBAAA;;;;;;;;;;;;;;;;;;;EAoCpB,KAAA,CAAM,MAAA,EAAQ,kBAAA,GAAqB,aAAA;;;;;;;EAgB7B,KAAA,CAAM,IAAA,UAAc,KAAA,YAAiB,OAAA;;;;;;;;;;;EAc3C,QAAA,CAAS,MAAA,EAAQ,cAAA,GAAiB,gBAAA;AAAA"}
1
+ {"version":3,"file":"sdk.d.mts","names":[],"sources":["../../../../../../../packages/ai-mistral/src/sdk.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAmEa,sBAAsB;;;;;;mBAMhB;EAEjB,YAAmB,QAAQ;;;;;;;;;;;;;;;;;;;EAoCpB,MAAM,QAAQ,qBAAqB;;;;;;;EAgB7B,MAAM,cAAc,iBAAiB;;;;;;;;;;;EAc3C,SAAS,QAAQ,iBAAiB"}
package/llms-full.txt CHANGED
@@ -8,7 +8,7 @@
8
8
 
9
9
  ---
10
10
  name: setup-mistral
11
- description: 'Wire @warlock.js/ai-mistral — new MistralSDK({apiKey, baseURL?, provider?, pricing?}) for Mistral AI, a thin wrapper over the OpenAI adapter that uses Mistral''s OpenAI-compatible endpoint (https://api.mistral.ai/v1). .model({name, vision?, reasoning?, structuredOutput?, responseFormat?, pdf?, audio?}) for a ModelContract with Mistral-aware capabilities (vision auto-inferred for the pixtral family, reasoning for the magistral family + hybrid mistral-small), .embedder({name, dimensions?}) for mistral-embed via /v1/embeddings. Triggers: `MistralSDK`, `mistral.model`, `mistral.embedder`, `pixtral`, `magistral`, `mistral-large`, `mistral-small`, `mistral-medium`, `ministral`, `mistral-embed`, `api.mistral.ai`, OpenAI-compatible Mistral, `reasoning_effort`, `responseFormat`, `pricing`; "use mistral", "wire mistral into a warlock agent", "configure mistral-large", "use magistral reasoning", "pixtral vision", "mistral embeddings with warlock". Skip: image generation (Mistral has no OpenAI-compatible image endpoint — `mistral.image()` does not exist); the wrapped adapter internals `@warlock.js/ai-openai`; agent wiring the `run-ai-agent` topic of the `warlock-js-ai` skill; embedder usage the `embed-text` topic of the `warlock-js-ai` skill; provider picking the `pick-ai-provider` topic of the `warlock-js-ai` skill; siblings `@warlock.js/ai-google`, `@warlock.js/ai-anthropic`, `@warlock.js/ai-bedrock`, `@warlock.js/ai-ollama`; raw `@mistralai/mistralai`, Vercel `@ai-sdk/mistral`.'
11
+ description: 'Wire @warlock.js/ai-mistral — new MistralSDK({apiKey, baseURL?, provider?, pricing?}) for Mistral AI, a thin wrapper over the OpenAI adapter that uses Mistral''s OpenAI-compatible endpoint (https://api.mistral.ai/v1). .model({name, vision?, reasoning?, structuredOutput?, responseFormat?, pdf?, audio?}) for a ModelContract with Mistral-aware capabilities (vision auto-inferred for the pixtral family, reasoning for the magistral family + hybrid mistral-small), .embedder({name, dimensions?}) for mistral-embed via /v1/embeddings. Triggers: `MistralSDK`, `mistral.model`, `mistral.embedder`, `pixtral`, `magistral`, `mistral-large`, `mistral-small`, `mistral-medium`, `ministral`, `mistral-embed`, `api.mistral.ai`, `MISTRAL_DEFAULT_PRICING`, `promptCacheKey`, OpenAI-compatible Mistral, `reasoning_effort`, `responseFormat`, `pricing`; "use mistral", "wire mistral into a warlock agent", "configure mistral-large", "use magistral reasoning", "pixtral vision", "mistral embeddings with warlock". Skip: image generation (Mistral has no OpenAI-compatible image endpoint — `mistral.image()` does not exist); the wrapped adapter internals `@warlock.js/ai-openai`; agent wiring the `run-ai-agent` topic of the `warlock-js-ai` skill; embedder usage the `embed-text` topic of the `warlock-js-ai` skill; provider picking the `pick-ai-provider` topic of the `warlock-js-ai` skill; siblings `@warlock.js/ai-google`, `@warlock.js/ai-anthropic`, `@warlock.js/ai-bedrock`, `@warlock.js/ai-ollama`; raw `@mistralai/mistralai`, Vercel `@ai-sdk/mistral`.'
12
12
  ---
13
13
 
14
14
  # `@warlock.js/ai-mistral`
@@ -28,10 +28,10 @@ const mistral = new MistralSDK({ apiKey: process.env.MISTRAL_API_KEY! });
28
28
  ## Producing a model
29
29
 
30
30
  ```ts
31
- mistral.model({ name: "mistral-large-latest" }) // multimodal flagship
32
- mistral.model({ name: "magistral-medium-latest" }) // reasoning
33
- mistral.model({ name: "pixtral-large-latest" }) // vision
34
- mistral.model({ name: "some-fine-tune", vision: true }) // explicit capability override
31
+ mistral.model({ name: "mistral-large-latest" }); // multimodal flagship
32
+ mistral.model({ name: "magistral-medium-latest" }); // reasoning
33
+ mistral.model({ name: "pixtral-large-latest" }); // vision
34
+ mistral.model({ name: "some-fine-tune", vision: true }); // explicit capability override
35
35
  ```
36
36
 
37
37
  Returns a `ModelContract` you pass straight into `ai.agent({ model })`.
@@ -40,13 +40,13 @@ Returns a `ModelContract` you pass straight into `ai.agent({ model })`.
40
40
 
41
41
  The wrapper injects **Mistral-aware** inference before delegating to the OpenAI adapter (the OpenAI prefix lists never match Mistral names):
42
42
 
43
- | Flag | Default |
44
- | --- | --- |
45
- | `vision` | Inferred from the model name. `true` for the `pixtral` family and the recent multimodal generations (`mistral-large`, `mistral-medium`, `ministral-3`); `false` otherwise. |
46
- | `reasoning` | Inferred from the model name. `true` for the `magistral` family and the hybrid `mistral-small` generation; `false` otherwise. Drives whether `reasoning_effort` is forwarded. |
47
- | `structuredOutput` | `true`, unless `responseFormat` is forced to `"json_object"` / `"text"` (loose modes). |
48
- | `promptCaching` | `true` (inherited from the OpenAI adapter — read-side `cachedTokens` accounting). |
49
- | `pdf` / `audio` | `false` by default (opt-in `.model({ pdf: true })` / `{ audio: true }`). |
43
+ | Flag | Default |
44
+ | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
45
+ | `vision` | Inferred from the model name. `true` for the `pixtral` family and the recent multimodal generations (`mistral-large`, `mistral-medium`, `ministral-3`); `false` otherwise. |
46
+ | `reasoning` | Inferred from the model name. `true` for the `magistral` family and the hybrid `mistral-small` generation; `false` otherwise. Drives whether `reasoning_effort` is forwarded. |
47
+ | `structuredOutput` | `true`, unless `responseFormat` is forced to `"json_object"` / `"text"` (loose modes). |
48
+ | `promptCaching` | `true` (inherited from the OpenAI adapter — read-side `cachedTokens` accounting). |
49
+ | `pdf` / `audio` | `false` by default (opt-in `.model({ pdf: true })` / `{ audio: true }`). |
50
50
 
51
51
  **Override any flag explicitly** via `.model({ name, vision?, reasoning?, structuredOutput?, responseFormat?, pdf?, audio? })` — an explicit value always wins over inference. The known-family fragments live in `known-models.ts` (`inferVisionCapability`, `inferReasoningCapability`).
52
52
 
@@ -71,24 +71,47 @@ const { vectors } = await embedder.embedMany(["doc 1", "doc 2"]);
71
71
 
72
72
  ## Pricing — per-model registry
73
73
 
74
- The adapter ships a conservative default registry (`MISTRAL_DEFAULT_PRICING`, USD per 1,000,000 tokens) so cost truth works out of the box. Pass your own `pricing` to win per model id:
74
+ The adapter ships a default registry (`MISTRAL_DEFAULT_PRICING`, USD per 1,000,000 tokens, with the 10%-of-input cache rate as `cachedInput`) so cost truth works out of the box, on agent reports and on each `model.complete()` / streaming `done` usage. Pass your own `pricing` to win per model id:
75
75
 
76
76
  ```ts
77
+ import { totalCost } from "@warlock.js/ai";
78
+ import { MISTRAL_DEFAULT_PRICING, MistralSDK } from "@warlock.js/ai-mistral";
79
+
77
80
  const mistral = new MistralSDK({
78
- apiKey,
81
+ apiKey: process.env.MISTRAL_API_KEY ?? "",
79
82
  pricing: {
80
- // USD per 1M tokens — billing-grade overrides.
81
- "mistral-large-latest": { input: 2, output: 6 },
82
- "magistral-medium-latest": { input: 2, output: 5 },
83
+ // USD per 1M tokens — contract rates win over the defaults.
84
+ "mistral-large-latest": { input: 0.45, output: 1.35, cachedInput: 0.045 },
83
85
  },
84
86
  });
87
+
88
+ MISTRAL_DEFAULT_PRICING["mistral-small-latest"]; // { input: 0.15, output: 0.6, cachedInput: 0.015 }
89
+
90
+ const { usage } = await mistral
91
+ .model({ name: "mistral-medium-latest" })
92
+ .complete([{ role: "user", content: "hi" }]);
93
+ console.log(totalCost(usage.cost));
85
94
  ```
86
95
 
87
- Resolution at `model()` time: per-model `pricing` (`mistral.model({ name, pricing })`) > SDK-level `pricing` > `MISTRAL_DEFAULT_PRICING` > `undefined`. The defaults are list-price approximations — pass explicit rates for billing.
96
+ Resolution at `model()` time: per-model `pricing` (`mistral.model({ name, pricing })`) > SDK-level `pricing` > `MISTRAL_DEFAULT_PRICING` > `undefined`.
97
+
98
+ - **Source.** https://docs.mistral.ai/inference/pricing plus the model pages under https://docs.mistral.ai/models (API ids and aliases), fetched 2026-10-17. Covered: `mistral-large-latest` / `mistral-large-2512`, `mistral-medium-latest` / `mistral-medium-3-5`, `mistral-small-latest` / `mistral-small-2603`, `ministral-14b-latest` / `ministral-14b-2512`, `codestral-latest` / `codestral-2508`, `mistral-embed` / `mistral-embed-2312`.
99
+ - **Not included:** Mistral Large 4 (public preview at a temporary sale price) and the retired Pixtral / Magistral models (no longer on the price list) — pass `pricing` if you still call them.
100
+
101
+ ## Prompt caching
102
+
103
+ Mistral's Chat Completions accepts `prompt_cache_key` (https://docs.mistral.ai/studio/conversations/advanced/prompt-caching). Set `promptCacheKey` on the model to route related requests to the same cache; it is sent while the SDK keeps its default `"mistral"` provider label. Cached tokens come back as `usage.cachedTokens` (inside `prompt_tokens`, so `inputIncludesCache: true`) and bill at `cachedInput`.
104
+
105
+ ```ts
106
+ import { MistralSDK } from "@warlock.js/ai-mistral";
107
+
108
+ const mistral = new MistralSDK({ apiKey: process.env.MISTRAL_API_KEY ?? "" });
109
+ const model = mistral.model({ name: "mistral-large-latest", promptCacheKey: "conversation:42" });
110
+ ```
88
111
 
89
112
  ## Errors
90
113
 
91
- Raw errors are wrapped into the typed `@warlock.js/ai` `AIError` hierarchy by the wrapped OpenAI adapter (dispatch keys on `APIError.status + code`) — see the `handle-ai-errors` topic of the `warlock-js-ai` skill.
114
+ Raw errors are wrapped into the typed `@warlock.js/ai` `AIError` hierarchy by the wrapped OpenAI adapter (dispatch keys on `APIError.status + code`) — see the `handle-ai-errors` topic of the `warlock-js-ai` skill. HTTP 503 (and OpenAI's `server_is_overloaded` code) maps to `ProviderOverloadedError` (`code: "PROVIDER_OVERLOADED"`, `retryable: true`); every wrapped error carries `status`, `retryable` and `billed` (`false` for 401 / 402 / 403, otherwise `"unknown"`).
92
115
 
93
116
  ## When NOT to use this skill
94
117
 
@@ -102,4 +125,18 @@ Raw errors are wrapped into the typed `@warlock.js/ai` `AIError` hierarchy by th
102
125
  - The `run-ai-agent` topic of the `warlock-js-ai` skill — passing the model into `ai.agent({...})`.
103
126
  - The `pick-ai-provider` topic of the `warlock-js-ai` skill — adapter comparison.
104
127
 
128
+ ## Provider body options and token estimates
129
+
130
+ This adapter delegates Chat Completions to the OpenAI adapter, so
131
+ `providerOptions.openai.body` adds native Chat request fields. Other provider
132
+ keys are ignored. Plain-object fields merge one level deep with neutral options;
133
+ caller-provided keys win, while arrays, scalars and `null` replace the field.
134
+ The OpenAI adapter's protected conversation, tool and transport fields remain
135
+ protected here too. Send only fields supported by this provider; do not reuse
136
+ OpenAI-only bodies across a mixed-provider fallback chain.
137
+
138
+ Models from this adapter have no native `countTokens` method. Check
139
+ `model.countTokens` before using an optional native counting capability;
140
+ `sdk.count(text)` is a separate offline estimate.
141
+
105
142
 
package/llms.txt CHANGED
@@ -6,4 +6,4 @@
6
6
 
7
7
  ## Skills
8
8
 
9
- - [setup-mistral](@warlock.js/ai-mistral/setup-mistral/SKILL.md): Wire @warlock.js/ai-mistral — new MistralSDK({apiKey, baseURL?, provider?, pricing?}) for Mistral AI, a thin wrapper over the OpenAI adapter that uses Mistral's OpenAI-compatible endpoint (https://api.mistral.ai/v1). .model({name, vision?, reasoning?, structuredOutput?, responseFormat?, pdf?, audio?}) for a ModelContract with Mistral-aware capabilities (vision auto-inferred for the pixtral family, reasoning for the magistral family + hybrid mistral-small), .embedder({name, dimensions?}) for mistral-embed via /v1/embeddings. Triggers: `MistralSDK`, `mistral.model`, `mistral.embedder`, `pixtral`, `magistral`, `mistral-large`, `mistral-small`, `mistral-medium`, `ministral`, `mistral-embed`, `api.mistral.ai`, OpenAI-compatible Mistral, `reasoning_effort`, `responseFormat`, `pricing`; "use mistral", "wire mistral into a warlock agent", "configure mistral-large", "use magistral reasoning", "pixtral vision", "mistral embeddings with warlock". Skip: image generation (Mistral has no OpenAI-compatible image endpoint — `mistral.image()` does not exist); the wrapped adapter internals `@warlock.js/ai-openai`; agent wiring the `run-ai-agent` topic of the `warlock-js-ai` skill; embedder usage the `embed-text` topic of the `warlock-js-ai` skill; provider picking the `pick-ai-provider` topic of the `warlock-js-ai` skill; siblings `@warlock.js/ai-google`, `@warlock.js/ai-anthropic`, `@warlock.js/ai-bedrock`, `@warlock.js/ai-ollama`; raw `@mistralai/mistralai`, Vercel `@ai-sdk/mistral`.
9
+ - [setup-mistral](@warlock.js/ai-mistral/setup-mistral/SKILL.md): Wire @warlock.js/ai-mistral — new MistralSDK({apiKey, baseURL?, provider?, pricing?}) for Mistral AI, a thin wrapper over the OpenAI adapter that uses Mistral's OpenAI-compatible endpoint (https://api.mistral.ai/v1). .model({name, vision?, reasoning?, structuredOutput?, responseFormat?, pdf?, audio?}) for a ModelContract with Mistral-aware capabilities (vision auto-inferred for the pixtral family, reasoning for the magistral family + hybrid mistral-small), .embedder({name, dimensions?}) for mistral-embed via /v1/embeddings. Triggers: `MistralSDK`, `mistral.model`, `mistral.embedder`, `pixtral`, `magistral`, `mistral-large`, `mistral-small`, `mistral-medium`, `ministral`, `mistral-embed`, `api.mistral.ai`, `MISTRAL_DEFAULT_PRICING`, `promptCacheKey`, OpenAI-compatible Mistral, `reasoning_effort`, `responseFormat`, `pricing`; "use mistral", "wire mistral into a warlock agent", "configure mistral-large", "use magistral reasoning", "pixtral vision", "mistral embeddings with warlock". Skip: image generation (Mistral has no OpenAI-compatible image endpoint — `mistral.image()` does not exist); the wrapped adapter internals `@warlock.js/ai-openai`; agent wiring the `run-ai-agent` topic of the `warlock-js-ai` skill; embedder usage the `embed-text` topic of the `warlock-js-ai` skill; provider picking the `pick-ai-provider` topic of the `warlock-js-ai` skill; siblings `@warlock.js/ai-google`, `@warlock.js/ai-anthropic`, `@warlock.js/ai-bedrock`, `@warlock.js/ai-ollama`; raw `@mistralai/mistralai`, Vercel `@ai-sdk/mistral`.
package/package.json CHANGED
@@ -16,13 +16,13 @@
16
16
  "directory": "packages/ai-mistral"
17
17
  },
18
18
  "dependencies": {
19
- "@warlock.js/ai-openai": "5.30.0",
20
- "@warlock.js/logger": "5.30.0"
19
+ "@warlock.js/ai-openai": "5.32.0",
20
+ "@warlock.js/logger": "5.32.0"
21
21
  },
22
22
  "peerDependencies": {
23
- "@warlock.js/ai": "5.30.0"
23
+ "@warlock.js/ai": "5.32.0"
24
24
  },
25
- "version": "5.30.0",
25
+ "version": "5.32.0",
26
26
  "main": "./cjs/index.cjs",
27
27
  "module": "./esm/index.mjs",
28
28
  "types": "./esm/index.d.mts",
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: setup-mistral
3
- description: 'Wire @warlock.js/ai-mistral — new MistralSDK({apiKey, baseURL?, provider?, pricing?}) for Mistral AI, a thin wrapper over the OpenAI adapter that uses Mistral''s OpenAI-compatible endpoint (https://api.mistral.ai/v1). .model({name, vision?, reasoning?, structuredOutput?, responseFormat?, pdf?, audio?}) for a ModelContract with Mistral-aware capabilities (vision auto-inferred for the pixtral family, reasoning for the magistral family + hybrid mistral-small), .embedder({name, dimensions?}) for mistral-embed via /v1/embeddings. Triggers: `MistralSDK`, `mistral.model`, `mistral.embedder`, `pixtral`, `magistral`, `mistral-large`, `mistral-small`, `mistral-medium`, `ministral`, `mistral-embed`, `api.mistral.ai`, OpenAI-compatible Mistral, `reasoning_effort`, `responseFormat`, `pricing`; "use mistral", "wire mistral into a warlock agent", "configure mistral-large", "use magistral reasoning", "pixtral vision", "mistral embeddings with warlock". Skip: image generation (Mistral has no OpenAI-compatible image endpoint — `mistral.image()` does not exist); the wrapped adapter internals `@warlock.js/ai-openai`; agent wiring the `run-ai-agent` topic of the `warlock-js-ai` skill; embedder usage the `embed-text` topic of the `warlock-js-ai` skill; provider picking the `pick-ai-provider` topic of the `warlock-js-ai` skill; siblings `@warlock.js/ai-google`, `@warlock.js/ai-anthropic`, `@warlock.js/ai-bedrock`, `@warlock.js/ai-ollama`; raw `@mistralai/mistralai`, Vercel `@ai-sdk/mistral`.'
3
+ description: 'Wire @warlock.js/ai-mistral — new MistralSDK({apiKey, baseURL?, provider?, pricing?}) for Mistral AI, a thin wrapper over the OpenAI adapter that uses Mistral''s OpenAI-compatible endpoint (https://api.mistral.ai/v1). .model({name, vision?, reasoning?, structuredOutput?, responseFormat?, pdf?, audio?}) for a ModelContract with Mistral-aware capabilities (vision auto-inferred for the pixtral family, reasoning for the magistral family + hybrid mistral-small), .embedder({name, dimensions?}) for mistral-embed via /v1/embeddings. Triggers: `MistralSDK`, `mistral.model`, `mistral.embedder`, `pixtral`, `magistral`, `mistral-large`, `mistral-small`, `mistral-medium`, `ministral`, `mistral-embed`, `api.mistral.ai`, `MISTRAL_DEFAULT_PRICING`, `promptCacheKey`, OpenAI-compatible Mistral, `reasoning_effort`, `responseFormat`, `pricing`; "use mistral", "wire mistral into a warlock agent", "configure mistral-large", "use magistral reasoning", "pixtral vision", "mistral embeddings with warlock". Skip: image generation (Mistral has no OpenAI-compatible image endpoint — `mistral.image()` does not exist); the wrapped adapter internals `@warlock.js/ai-openai`; agent wiring the `run-ai-agent` topic of the `warlock-js-ai` skill; embedder usage the `embed-text` topic of the `warlock-js-ai` skill; provider picking the `pick-ai-provider` topic of the `warlock-js-ai` skill; siblings `@warlock.js/ai-google`, `@warlock.js/ai-anthropic`, `@warlock.js/ai-bedrock`, `@warlock.js/ai-ollama`; raw `@mistralai/mistralai`, Vercel `@ai-sdk/mistral`.'
4
4
  ---
5
5
 
6
6
  # `@warlock.js/ai-mistral`
@@ -20,10 +20,10 @@ const mistral = new MistralSDK({ apiKey: process.env.MISTRAL_API_KEY! });
20
20
  ## Producing a model
21
21
 
22
22
  ```ts
23
- mistral.model({ name: "mistral-large-latest" }) // multimodal flagship
24
- mistral.model({ name: "magistral-medium-latest" }) // reasoning
25
- mistral.model({ name: "pixtral-large-latest" }) // vision
26
- mistral.model({ name: "some-fine-tune", vision: true }) // explicit capability override
23
+ mistral.model({ name: "mistral-large-latest" }); // multimodal flagship
24
+ mistral.model({ name: "magistral-medium-latest" }); // reasoning
25
+ mistral.model({ name: "pixtral-large-latest" }); // vision
26
+ mistral.model({ name: "some-fine-tune", vision: true }); // explicit capability override
27
27
  ```
28
28
 
29
29
  Returns a `ModelContract` you pass straight into `ai.agent({ model })`.
@@ -32,13 +32,13 @@ Returns a `ModelContract` you pass straight into `ai.agent({ model })`.
32
32
 
33
33
  The wrapper injects **Mistral-aware** inference before delegating to the OpenAI adapter (the OpenAI prefix lists never match Mistral names):
34
34
 
35
- | Flag | Default |
36
- | --- | --- |
37
- | `vision` | Inferred from the model name. `true` for the `pixtral` family and the recent multimodal generations (`mistral-large`, `mistral-medium`, `ministral-3`); `false` otherwise. |
38
- | `reasoning` | Inferred from the model name. `true` for the `magistral` family and the hybrid `mistral-small` generation; `false` otherwise. Drives whether `reasoning_effort` is forwarded. |
39
- | `structuredOutput` | `true`, unless `responseFormat` is forced to `"json_object"` / `"text"` (loose modes). |
40
- | `promptCaching` | `true` (inherited from the OpenAI adapter — read-side `cachedTokens` accounting). |
41
- | `pdf` / `audio` | `false` by default (opt-in `.model({ pdf: true })` / `{ audio: true }`). |
35
+ | Flag | Default |
36
+ | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
37
+ | `vision` | Inferred from the model name. `true` for the `pixtral` family and the recent multimodal generations (`mistral-large`, `mistral-medium`, `ministral-3`); `false` otherwise. |
38
+ | `reasoning` | Inferred from the model name. `true` for the `magistral` family and the hybrid `mistral-small` generation; `false` otherwise. Drives whether `reasoning_effort` is forwarded. |
39
+ | `structuredOutput` | `true`, unless `responseFormat` is forced to `"json_object"` / `"text"` (loose modes). |
40
+ | `promptCaching` | `true` (inherited from the OpenAI adapter — read-side `cachedTokens` accounting). |
41
+ | `pdf` / `audio` | `false` by default (opt-in `.model({ pdf: true })` / `{ audio: true }`). |
42
42
 
43
43
  **Override any flag explicitly** via `.model({ name, vision?, reasoning?, structuredOutput?, responseFormat?, pdf?, audio? })` — an explicit value always wins over inference. The known-family fragments live in `known-models.ts` (`inferVisionCapability`, `inferReasoningCapability`).
44
44
 
@@ -63,24 +63,47 @@ const { vectors } = await embedder.embedMany(["doc 1", "doc 2"]);
63
63
 
64
64
  ## Pricing — per-model registry
65
65
 
66
- The adapter ships a conservative default registry (`MISTRAL_DEFAULT_PRICING`, USD per 1,000,000 tokens) so cost truth works out of the box. Pass your own `pricing` to win per model id:
66
+ The adapter ships a default registry (`MISTRAL_DEFAULT_PRICING`, USD per 1,000,000 tokens, with the 10%-of-input cache rate as `cachedInput`) so cost truth works out of the box, on agent reports and on each `model.complete()` / streaming `done` usage. Pass your own `pricing` to win per model id:
67
67
 
68
68
  ```ts
69
+ import { totalCost } from "@warlock.js/ai";
70
+ import { MISTRAL_DEFAULT_PRICING, MistralSDK } from "@warlock.js/ai-mistral";
71
+
69
72
  const mistral = new MistralSDK({
70
- apiKey,
73
+ apiKey: process.env.MISTRAL_API_KEY ?? "",
71
74
  pricing: {
72
- // USD per 1M tokens — billing-grade overrides.
73
- "mistral-large-latest": { input: 2, output: 6 },
74
- "magistral-medium-latest": { input: 2, output: 5 },
75
+ // USD per 1M tokens — contract rates win over the defaults.
76
+ "mistral-large-latest": { input: 0.45, output: 1.35, cachedInput: 0.045 },
75
77
  },
76
78
  });
79
+
80
+ MISTRAL_DEFAULT_PRICING["mistral-small-latest"]; // { input: 0.15, output: 0.6, cachedInput: 0.015 }
81
+
82
+ const { usage } = await mistral
83
+ .model({ name: "mistral-medium-latest" })
84
+ .complete([{ role: "user", content: "hi" }]);
85
+ console.log(totalCost(usage.cost));
77
86
  ```
78
87
 
79
- Resolution at `model()` time: per-model `pricing` (`mistral.model({ name, pricing })`) > SDK-level `pricing` > `MISTRAL_DEFAULT_PRICING` > `undefined`. The defaults are list-price approximations — pass explicit rates for billing.
88
+ Resolution at `model()` time: per-model `pricing` (`mistral.model({ name, pricing })`) > SDK-level `pricing` > `MISTRAL_DEFAULT_PRICING` > `undefined`.
89
+
90
+ - **Source.** https://docs.mistral.ai/inference/pricing plus the model pages under https://docs.mistral.ai/models (API ids and aliases), fetched 2026-10-17. Covered: `mistral-large-latest` / `mistral-large-2512`, `mistral-medium-latest` / `mistral-medium-3-5`, `mistral-small-latest` / `mistral-small-2603`, `ministral-14b-latest` / `ministral-14b-2512`, `codestral-latest` / `codestral-2508`, `mistral-embed` / `mistral-embed-2312`.
91
+ - **Not included:** Mistral Large 4 (public preview at a temporary sale price) and the retired Pixtral / Magistral models (no longer on the price list) — pass `pricing` if you still call them.
92
+
93
+ ## Prompt caching
94
+
95
+ Mistral's Chat Completions accepts `prompt_cache_key` (https://docs.mistral.ai/studio/conversations/advanced/prompt-caching). Set `promptCacheKey` on the model to route related requests to the same cache; it is sent while the SDK keeps its default `"mistral"` provider label. Cached tokens come back as `usage.cachedTokens` (inside `prompt_tokens`, so `inputIncludesCache: true`) and bill at `cachedInput`.
96
+
97
+ ```ts
98
+ import { MistralSDK } from "@warlock.js/ai-mistral";
99
+
100
+ const mistral = new MistralSDK({ apiKey: process.env.MISTRAL_API_KEY ?? "" });
101
+ const model = mistral.model({ name: "mistral-large-latest", promptCacheKey: "conversation:42" });
102
+ ```
80
103
 
81
104
  ## Errors
82
105
 
83
- Raw errors are wrapped into the typed `@warlock.js/ai` `AIError` hierarchy by the wrapped OpenAI adapter (dispatch keys on `APIError.status + code`) — see the `handle-ai-errors` topic of the `warlock-js-ai` skill.
106
+ Raw errors are wrapped into the typed `@warlock.js/ai` `AIError` hierarchy by the wrapped OpenAI adapter (dispatch keys on `APIError.status + code`) — see the `handle-ai-errors` topic of the `warlock-js-ai` skill. HTTP 503 (and OpenAI's `server_is_overloaded` code) maps to `ProviderOverloadedError` (`code: "PROVIDER_OVERLOADED"`, `retryable: true`); every wrapped error carries `status`, `retryable` and `billed` (`false` for 401 / 402 / 403, otherwise `"unknown"`).
84
107
 
85
108
  ## When NOT to use this skill
86
109
 
@@ -93,3 +116,17 @@ Raw errors are wrapped into the typed `@warlock.js/ai` `AIError` hierarchy by th
93
116
  - The `setup-openai` topic of the `warlock-js-ai-openai` skill — the wrapped adapter; identical wire behavior.
94
117
  - The `run-ai-agent` topic of the `warlock-js-ai` skill — passing the model into `ai.agent({...})`.
95
118
  - The `pick-ai-provider` topic of the `warlock-js-ai` skill — adapter comparison.
119
+
120
+ ## Provider body options and token estimates
121
+
122
+ This adapter delegates Chat Completions to the OpenAI adapter, so
123
+ `providerOptions.openai.body` adds native Chat request fields. Other provider
124
+ keys are ignored. Plain-object fields merge one level deep with neutral options;
125
+ caller-provided keys win, while arrays, scalars and `null` replace the field.
126
+ The OpenAI adapter's protected conversation, tool and transport fields remain
127
+ protected here too. Send only fields supported by this provider; do not reuse
128
+ OpenAI-only bodies across a mixed-provider fallback chain.
129
+
130
+ Models from this adapter have no native `countTokens` method. Check
131
+ `model.countTokens` before using an optional native counting capability;
132
+ `sdk.count(text)` is a separate offline estimate.