This commit is contained in:
2026-07-26 14:02:37 +07:00
parent bc56546b49
commit 367ebc1c7f
171 changed files with 4617 additions and 10402 deletions
+70 -3
View File
@@ -83,6 +83,7 @@ interface ModelsDevModel {
id: string;
name: string;
tool_call?: boolean;
structured_output?: boolean;
reasoning?: boolean;
reasoning_options?: ModelsDevReasoningOption[];
limit?: {
@@ -291,6 +292,7 @@ const ANT_LING_RING_THINKING_LEVEL_MAP = {
xhigh: "xhigh",
} as const;
const BEDROCK_INFERENCE_PROFILE_ONLY_MODEL_IDS = new Set(["anthropic.claude-opus-5"]);
const MODELS_DEV_OPENAI_UNSUPPORTED_MODEL_IDS = new Set(["gpt-5.6"]);
const OPENAI_TOOL_SEARCH_MODEL_IDS = new Set([
"gpt-5.4",
@@ -485,6 +487,8 @@ function isAnthropicAdaptiveThinkingModel(modelId: string): boolean {
modelId.includes("opus-4.7") ||
modelId.includes("opus-4-8") ||
modelId.includes("opus-4.8") ||
modelId.includes("opus-5") ||
modelId.includes("opus.5") ||
modelId.includes("sonnet-4-6") ||
modelId.includes("sonnet-4.6") ||
modelId.includes("sonnet-5") ||
@@ -495,7 +499,14 @@ function isAnthropicAdaptiveThinkingModel(modelId: string): boolean {
function isAnthropicTemperatureUnsupportedModel(modelId: string): boolean {
const id = modelId.toLowerCase();
return id.includes("opus-4-7") || id.includes("opus-4.7") || id.includes("opus-4-8") || id.includes("opus-4.8");
return (
id.includes("opus-4-7") ||
id.includes("opus-4.7") ||
id.includes("opus-4-8") ||
id.includes("opus-4.8") ||
id.includes("opus-5") ||
id.includes("opus.5")
);
}
const OPENAI_COMPLETIONS_DEFAULT_COMPAT = {
@@ -514,6 +525,7 @@ const OPENAI_COMPLETIONS_DEFAULT_COMPAT = {
chatTemplateKwargs: {},
zaiToolStream: false,
supportsStrictMode: true,
supportsOpenAIGrammarTools: false,
sendSessionAffinityHeaders: false,
supportsLongCacheRetention: true,
} satisfies Required<Omit<OpenAICompletionsCompat, "cacheControlFormat" | "deferredToolsMode">> & {
@@ -602,6 +614,7 @@ function detectOpenAICompletionsCompat(model: Model<"openai-completions">): Open
chatTemplateKwargs: {},
zaiToolStream: false,
supportsStrictMode: !isMoonshot && !isTogether && !isCloudflareAiGateway && !isNvidia,
supportsOpenAIGrammarTools: false,
...(cacheControlFormat ? { cacheControlFormat } : {}),
sendSessionAffinityHeaders: false,
supportsLongCacheRetention: !(
@@ -643,6 +656,39 @@ function applyOpenAICompletionsCompatMetadata(model: Model<Api>): void {
}
}
function applyStrictToolCompatMetadata(model: Model<Api>): void {
if (model.provider === "openai" && model.api === "openai-responses") {
model.compat = { ...(model.compat as OpenAIResponsesCompat | undefined), supportsStrictMode: true };
} else if (model.provider === "anthropic" && model.api === "anthropic-messages") {
mergeAnthropicMessagesCompat(model, { supportsStrictTools: true });
}
}
// Responses endpoints verified (OpenAI, ChatGPT Codex backend, GitHub Copilot,
// opencode zen) or documented (Azure OpenAI, Cloudflare AI Gateway) to pass
// OpenAI custom grammar tools through. OpenAI rejects `type: "custom"` tools
// for pre-GPT-5 models (gpt-4.x, gpt-4o, o-series).
const OPENAI_GRAMMAR_TOOL_PROVIDERS = new Set([
"openai",
"openai-codex",
"azure-openai-responses",
"github-copilot",
"opencode",
"cloudflare-ai-gateway",
]);
const OPENAI_GRAMMAR_TOOL_APIS = new Set<Api>([
"openai-responses",
"azure-openai-responses",
"openai-codex-responses",
]);
function applyOpenAIGrammarToolCompatMetadata(model: Model<Api>): void {
if (!OPENAI_GRAMMAR_TOOL_APIS.has(model.api) || !OPENAI_GRAMMAR_TOOL_PROVIDERS.has(model.provider)) return;
const match = /^gpt-(\d+)/.exec(model.id);
if (!match || Number(match[1]) < 5) return;
model.compat = { ...(model.compat as OpenAIResponsesCompat | undefined), supportsOpenAIGrammarTools: true };
}
function applyOpenAIToolSearchMetadata(model: Model<Api>): void {
const isOpenAIResponses = model.provider === "openai" && model.api === "openai-responses";
const isOpenAICodex = model.provider === "openai-codex" && model.api === "openai-codex-responses";
@@ -653,6 +699,18 @@ function applyOpenAIToolSearchMetadata(model: Model<Api>): void {
};
}
// OpenAI charges prompt-cache writes starting with the GPT-5.6 family, and exactly
// those models accept `prompt_cache_options`; older models reject the parameter.
// https://developers.openai.com/api/docs/guides/prompt-caching
function applyOpenAIExplicitPromptCacheMetadata(model: Model<Api>): void {
if (model.provider !== "openai" || model.api !== "openai-responses") return;
if (!(model.cost.cacheWrite > 0)) return;
model.compat = {
...(model.compat as OpenAIResponsesCompat | undefined),
supportsExplicitPromptCacheMode: true,
};
}
function isGemini3ProModel(modelId: string): boolean {
return /gemini-3(?:\.\d+)?-pro/.test(modelId.toLowerCase());
}
@@ -700,7 +758,7 @@ function applyThinkingLevelMetadata(model: Model<any>): void {
}
// Anthropic adaptive-thinking effort support (per Anthropic adaptive thinking docs):
// - "max" is available on all adaptive-thinking Claude models.
// - "xhigh" is only available on Opus 4.7/4.8, Sonnet 5, and Fable 5.
// - "xhigh" is only available on Opus 4.7/4.8/5, Sonnet 5, and Fable 5.
if (
model.id.includes("opus-4-6") ||
model.id.includes("opus-4.6") ||
@@ -714,6 +772,8 @@ function applyThinkingLevelMetadata(model: Model<any>): void {
model.id.includes("opus-4.7") ||
model.id.includes("opus-4-8") ||
model.id.includes("opus-4.8") ||
model.id.includes("opus-5") ||
model.id.includes("opus.5") ||
model.id.includes("sonnet-5") ||
model.id.includes("sonnet.5")
) {
@@ -1004,6 +1064,7 @@ async function loadModelsDevData(): Promise<Model<any>[]> {
for (const [modelId, model] of Object.entries(data["amazon-bedrock"].models)) {
const m = model as ModelsDevModel;
if (m.tool_call !== true) continue;
if (BEDROCK_INFERENCE_PROFILE_ONLY_MODEL_IDS.has(modelId)) continue;
let id = modelId;
@@ -1033,6 +1094,7 @@ async function loadModelsDevData(): Promise<Model<any>[]> {
},
contextWindow: m.limit?.context || 4096,
maxTokens: m.limit?.output || 4096,
...(m.structured_output === true && { compat: { supportsStrictMode: true } }),
});
recordModelsDevReasoningOptions("amazon-bedrock" as const, id, m);
}
@@ -2455,7 +2517,10 @@ async function generateModels() {
applyOpenAICompletionsCompatMetadata(model);
applyModelsDevReasoningOptionMetadata(model);
applyThinkingLevelMetadata(model);
applyStrictToolCompatMetadata(model);
applyOpenAIGrammarToolCompatMetadata(model);
applyOpenAIToolSearchMetadata(model);
applyOpenAIExplicitPromptCacheMetadata(model);
}
// Group by provider and deduplicate by model ID
@@ -2508,6 +2573,8 @@ async function generateModels() {
}
}
const generatedAt = new Date().toISOString();
if (!generatorOptions.jsonOnly) {
// Stage and validate all provider values before replacing the current generated data.
const providersDir = join(packageRoot, "src/providers");
@@ -2527,7 +2594,7 @@ async function generateModels() {
}
writeJson(
join(stagedDataDir, MODEL_DATA_MANIFEST_FILE),
createModelDataManifest(modelDataStructure, fileContents),
createModelDataManifest(modelDataStructure, fileContents, generatedAt),
);
validateModelDataDirectory(modelDataStructure, stagedDataDir);