Skip to content

Commit d24949e

Browse files
authored
feat(v2): complete model APIs, packages and prices for OpenAI, Anthropic, Google, Vertex, xAI, Mistral, Cohere, DeepSeek, Perplexity and Meta (#11135)
* feat(sync): write Mistral FIM, Moderations and OCR APIs from /v1/models capabilities * fix(v2): resolve @ai-sdk/xai's default protocol as Responses, matching v1; document Mistral API tables * feat(v2): list Chat Completions next to Responses for OpenAI chat models, and the Moderations API * feat(v2): list Anthropic's OpenAI-compatible Chat Completions API for Claude models * feat(v2): list Gemini API Chat Completions, Interactions and OpenAI-compatible embeddings * feat(v2): list Vertex Interactions for Gemini and Responses for Grok * feat(v2): list Responses then Chat Completions for xAI Grok chat models * feat(v2): list Mistral FIM, Moderations and OCR APIs (written by the sync) * feat(v2): list Cohere's Compatibility API next to native Chat * feat(v2): list DeepSeek's Anthropic-compatible Messages API * feat(v2): list Chat Completions and Messages next to Responses for Meta models * feat(v2): list every API for the 16 OpenAI, Google and Anthropic models Vercel symlinks (pending approval) Vercel's files for these models were symlinks to the first-party files, so the first-party API tables would leak into Vercel. This replaces the 16 symlinks with Vercel files (the 13 full OpenAI and Claude copies use base_model with only the overrides), then lists the same APIs as the other first-party models. v1: no field changes except canonical_model_id on the 13 base_model files; the 16 models also move within Vercel's model map. The next Vercel sync will start patching these files from Vercel's catalog.
1 parent ed2be3f commit d24949e

158 files changed

Lines changed: 1502 additions & 22 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎packages/core/src/generate-v2.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -437,7 +437,7 @@ export function resolveProtocol(
437437
if (npm === "@ai-sdk/anthropic" || npm === "@ai-sdk/google-vertex/anthropic") {
438438
return "messages";
439439
}
440-
if (npm === "@ai-sdk/openai" || npm === "@ai-sdk/azure") {
440+
if (npm === "@ai-sdk/openai" || npm === "@ai-sdk/azure" || npm === "@ai-sdk/xai") {
441441
return shape === "completions" ? "chat-completions" : "responses";
442442
}
443443
if (npm === "@ai-sdk/amazon-bedrock") {

‎packages/core/src/sync/providers/mistral.ts‎

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,13 @@ const DEPRECATED_IDS = new Set([
2525

2626
const MistralCapabilities = z.object({
2727
completion_chat: z.boolean(),
28+
completion_fim: z.boolean().optional(),
2829
function_calling: z.boolean(),
2930
reasoning: z.boolean(),
3031
vision: z.boolean(),
3132
audio: z.boolean(),
33+
moderation: z.boolean().optional(),
34+
ocr: z.boolean().optional(),
3235
}).passthrough();
3336

3437
export const MistralModel = z.object({
@@ -93,17 +96,45 @@ export const mistral = {
9396
// Embedding, OCR, moderation, transcription, and TTS rows carry no
9497
// chat metadata to sync; keep any authored entry exactly as it is.
9598
const authored = context.authored(model.id);
96-
return authored === undefined ? undefined : { id: model.id, model: authored as SyncedModel };
99+
return authored === undefined ? undefined : withApis(model, { id: model.id, model: authored as SyncedModel });
97100
}
98101
const existing = context.existing(model.id);
99102
if (existing === undefined) return undefined;
100-
return {
103+
return withApis(model, {
101104
id: model.id,
102105
model: buildMistralModel(model, existing),
103-
};
106+
});
104107
},
105108
} satisfies SyncProvider<MistralModel>;
106109

110+
const NO_PACKAGE = { sdk: { aisdk: "none", opencodeai: "none" } };
111+
112+
function withApis<T extends { id: string; model: SyncedModel }>(model: MistralModel, synced: T) {
113+
const api = mistralApis(model.capabilities);
114+
return api === undefined ? synced : { ...synced, v2Set: { api } };
115+
}
116+
117+
// The APIs /v1/models capabilities name besides chat: POST /v1/fim/completions
118+
// (completion_fim), /v1/moderations (moderation) and /v1/ocr (ocr). No AI SDK or
119+
// OpenCode package calls them. They follow the file's first API, which v1 reads
120+
// and stays as it is; a file with none starts with Chat Completions, or with the
121+
// model's only API.
122+
export function mistralApis(capabilities: z.infer<typeof MistralCapabilities>) {
123+
const extra: Record<string, unknown> = {};
124+
if (capabilities.completion_fim) extra.fim = NO_PACKAGE;
125+
if (capabilities.moderation) extra.moderations = NO_PACKAGE;
126+
if (capabilities.ocr) extra.ocr = NO_PACKAGE;
127+
if (Object.keys(extra).length === 0) return undefined;
128+
const fallback = capabilities.completion_chat ? "chat-completions" : Object.keys(extra)[0]!;
129+
return (current: unknown) => {
130+
const tables = current !== null && typeof current === "object" && !Array.isArray(current)
131+
? current as Record<string, unknown>
132+
: {};
133+
const first = Object.keys(tables)[0] ?? fallback;
134+
return { [first]: tables[first] ?? {}, ...tables, ...structuredClone(extra) };
135+
};
136+
}
137+
107138
export async function fetchMistralModels(
108139
key = process.env.MISTRAL_API_KEY,
109140
fetcher: typeof fetch = fetch,

‎packages/core/src/translate.ts‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,8 @@ function toV1Api(api: Record<string, AuthoredApiEntryV2> | undefined, providerNp
205205
}
206206

207207
// The v1 `shape` a protocol gets on an SDK: none where it's the SDK's default.
208-
// `@ai-sdk/openai`, `@ai-sdk/azure` and `@ai-sdk/xai` default to Responses.
208+
// `@ai-sdk/openai`, `@ai-sdk/azure` and `@ai-sdk/xai` default to Responses (`createXai().languageModel`
209+
// is `createResponsesLanguageModel` in packages/xai/src/xai-provider.ts).
209210
export function toV1Shape(protocol: string, npm: string | undefined) {
210211
const responsesByDefault = npm === "@ai-sdk/openai" || npm === "@ai-sdk/azure" || npm === "@ai-sdk/xai";
211212
if (protocol === "responses" && !responsesByDefault) return "responses";

‎packages/core/test/mistral.test.ts‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
buildMistralModel,
77
fetchMistralModels,
88
mistral,
9+
mistralApis,
910
parseMistralModels,
1011
parseSupportedEfforts,
1112
type MistralModel,
@@ -275,3 +276,22 @@ test("writes only provider overrides for base_model entries", () => {
275276
});
276277
expect(synced).not.toHaveProperty("name");
277278
});
279+
280+
test("lists the FIM, moderation and OCR APIs /v1/models names after the first API", () => {
281+
const none = { sdk: { aisdk: "none", opencodeai: "none" } };
282+
const base = { completion_chat: true, function_calling: true, reasoning: false, vision: false, audio: false };
283+
expect(mistralApis(base)).toBeUndefined();
284+
285+
const fim = mistralApis({ ...base, completion_fim: true })!;
286+
expect(fim(undefined)).toEqual({ "chat-completions": {}, fim: none });
287+
const first = { "chat-completions": { base_url: "https://example.com/v1" } };
288+
const once = fim(first);
289+
expect(once).toEqual({ ...first, fim: none });
290+
expect(fim(once)).toEqual(once);
291+
292+
// A model with no chat API starts with its only one.
293+
const ocr = mistralApis({ ...base, completion_chat: false, ocr: true })!;
294+
expect(ocr(undefined)).toEqual({ ocr: none });
295+
const moderation = mistralApis({ ...base, completion_chat: false, moderation: true })!;
296+
expect(moderation(undefined)).toEqual({ moderations: none });
297+
});

‎providers/anthropic/models/claude-fable-5-1.toml‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# tools.updates: tool_addition/tool_removal blocks (inline-tools-2026-09-15) keep the cache.
22
# Web search: $10 per 1,000 searches; each search counts once, however many results it returns: https://platform.claude.com/docs/en/about-claude/pricing#web-search-tool
33
# Token-only multipliers (object factor, so cost.web_search is unscaled): US data residency (https://platform.claude.com/docs/en/manage-claude/data-residency#pricing).
4+
# APIs: Messages, and Chat Completions through the OpenAI SDK compatibility layer (https://platform.claude.com/docs/en/api/openai-sdk)
45
schema = 2
56
base_model = "anthropic/claude-fable-5-1"
67

@@ -12,6 +13,12 @@ system_updates = true
1213
effort_updates = true
1314
cache = { explicit = { ttl = ["5m", "1h"], max_breakpoints = 4, targets = ["tools", "system", "messages"], min_tokens = 512 } }
1415

16+
[api.messages]
17+
18+
[api.chat-completions]
19+
base_url = "https://api.anthropic.com/v1"
20+
sdk = { aisdk = "@ai-sdk/openai-compatible", opencodeai = "@opencode/ai/providers/openai-compatible" }
21+
1522
[cost.text.input]
1623
price = 10
1724
cache = { read = 0.25, write = { "5m" = 12.5, "1h" = 20 } }

‎providers/anthropic/models/claude-fable-5.toml‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# tools.updates: tool_addition/tool_removal blocks (inline-tools-2026-09-15) keep the cache.
22
# Web search: $10 per 1,000 searches; each search counts once, however many results it returns: https://platform.claude.com/docs/en/about-claude/pricing#web-search-tool
33
# Token-only multipliers (object factor, so cost.web_search is unscaled): US data residency (https://platform.claude.com/docs/en/manage-claude/data-residency#pricing).
4+
# APIs: Messages, and Chat Completions through the OpenAI SDK compatibility layer (https://platform.claude.com/docs/en/api/openai-sdk)
45
schema = 2
56
name = "Claude Fable 5"
67
description = "Claude model for creative writing, analysis, and controlled agent workflows"
@@ -26,6 +27,12 @@ cache = { explicit = { ttl = ["5m", "1h"], max_breakpoints = 4, targets = ["tool
2627
context = 1_000_000
2728
output = 128_000
2829

30+
[api.messages]
31+
32+
[api.chat-completions]
33+
base_url = "https://api.anthropic.com/v1"
34+
sdk = { aisdk = "@ai-sdk/openai-compatible", opencodeai = "@opencode/ai/providers/openai-compatible" }
35+
2936
[cost.text.input]
3037
price = 10
3138
cache = { read = 1, write = { "5m" = 12.5, "1h" = 20 } }

‎providers/anthropic/models/claude-haiku-4-5-20251001.toml‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# Web search: $10 per 1,000 searches; each search counts once, however many results it returns: https://platform.claude.com/docs/en/about-claude/pricing#web-search-tool
2+
# APIs: Messages, and Chat Completions through the OpenAI SDK compatibility layer (https://platform.claude.com/docs/en/api/openai-sdk)
23
schema = 2
34
name = "Claude Haiku 4.5"
45
description = "Fast Claude model for responsive assistance, classification, and lightweight agents"
@@ -24,6 +25,12 @@ cache = { explicit = { ttl = ["5m", "1h"], max_breakpoints = 4, targets = ["tool
2425
context = 200_000
2526
output = 64_000
2627

28+
[api.messages]
29+
30+
[api.chat-completions]
31+
base_url = "https://api.anthropic.com/v1"
32+
sdk = { aisdk = "@ai-sdk/openai-compatible", opencodeai = "@opencode/ai/providers/openai-compatible" }
33+
2734
[cost.text.input]
2835
price = 1
2936
cache = { read = 0.1, write = { "5m" = 1.25, "1h" = 2 } }

‎providers/anthropic/models/claude-haiku-4-5.toml‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# Web search: $10 per 1,000 searches; each search counts once, however many results it returns: https://platform.claude.com/docs/en/about-claude/pricing#web-search-tool
2+
# APIs: Messages, and Chat Completions through the OpenAI SDK compatibility layer (https://platform.claude.com/docs/en/api/openai-sdk)
23
schema = 2
34
base_model = "anthropic/claude-haiku-4-5"
45
description = "Fast Claude lane for lightweight agents, office tasks, and responsive chat"
@@ -11,6 +12,12 @@ system_updates = false
1112
effort_updates = false
1213
cache = { explicit = { ttl = ["5m", "1h"], max_breakpoints = 4, targets = ["tools", "system", "messages"], min_tokens = 4_096 } }
1314

15+
[api.messages]
16+
17+
[api.chat-completions]
18+
base_url = "https://api.anthropic.com/v1"
19+
sdk = { aisdk = "@ai-sdk/openai-compatible", opencodeai = "@opencode/ai/providers/openai-compatible" }
20+
1421
[cost.text.input]
1522
price = 1
1623
cache = { read = 0.1, write = { "5m" = 1.25, "1h" = 2 } }

‎providers/anthropic/models/claude-haiku-5-5.toml‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
# tools.updates: tool_addition/tool_removal blocks (inline-tools-2026-09-15) keep the cache.
66
# Web search: $10 per 1,000 searches; each search counts once, however many results it returns: https://platform.claude.com/docs/en/about-claude/pricing#web-search-tool
77
# Token-only multipliers (object factor, so cost.web_search is unscaled): US data residency (https://platform.claude.com/docs/en/manage-claude/data-residency#pricing).
8+
# APIs: Messages, and Chat Completions through the OpenAI SDK compatibility layer (https://platform.claude.com/docs/en/api/openai-sdk)
89
schema = 2
910
base_model = "anthropic/claude-haiku-5-5"
1011

@@ -16,6 +17,12 @@ system_updates = true
1617
effort_updates = true
1718
cache = { explicit = { ttl = ["5m", "1h"], max_breakpoints = 4, targets = ["tools", "system", "messages"], min_tokens = 512 } }
1819

20+
[api.messages]
21+
22+
[api.chat-completions]
23+
base_url = "https://api.anthropic.com/v1"
24+
sdk = { aisdk = "@ai-sdk/openai-compatible", opencodeai = "@opencode/ai/providers/openai-compatible" }
25+
1926
[cost.text.input]
2027
price = 0.1
2128
cache = { read = 0.01, write = { "5m" = 0.125, "1h" = 0.2 } }

‎providers/anthropic/models/claude-opus-4-5-20251101.toml‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# Web search: $10 per 1,000 searches; each search counts once, however many results it returns: https://platform.claude.com/docs/en/about-claude/pricing#web-search-tool
2+
# APIs: Messages, and Chat Completions through the OpenAI SDK compatibility layer (https://platform.claude.com/docs/en/api/openai-sdk)
23
schema = 2
34
name = "Claude Opus 4.5"
45
description = "Flagship Claude model for deep reasoning, coding, and long-horizon agents"
@@ -25,6 +26,12 @@ cache = { explicit = { ttl = ["5m", "1h"], max_breakpoints = 4, targets = ["tool
2526
context = 200_000
2627
output = 64_000
2728

29+
[api.messages]
30+
31+
[api.chat-completions]
32+
base_url = "https://api.anthropic.com/v1"
33+
sdk = { aisdk = "@ai-sdk/openai-compatible", opencodeai = "@opencode/ai/providers/openai-compatible" }
34+
2835
[cost.text.input]
2936
price = 5
3037
cache = { read = 0.5, write = { "5m" = 6.25, "1h" = 10 } }

0 commit comments

Comments
 (0)