From 31a361200636c0559096fd3ee451116450c0df4f Mon Sep 17 00:00:00 2001 From: Matthew Feroz Date: Mon, 13 Jul 2026 16:45:48 -0400 Subject: [PATCH 1/4] feat(sync): add Merge Gateway model sync --- .github/workflows/sync-models.yml | 1 + package.json | 1 + packages/core/src/sync/index.ts | 5 +- .../core/src/sync/providers/merge-gateway.ts | 287 ++++++++++++++++++ packages/core/test/sync.test.ts | 193 ++++++++++++ .../anthropic/claude-3-7-sonnet-20250219.toml | 13 + .../models/anthropic/claude-fable-5.toml | 9 + .../anthropic/claude-haiku-4-5-20251001.toml | 11 +- .../anthropic/claude-opus-4-1-20250805.toml | 11 +- .../anthropic/claude-opus-4-20250514.toml | 11 +- .../anthropic/claude-opus-4-5-20251101.toml | 15 +- .../models/anthropic/claude-opus-4-6.toml | 14 +- .../models/anthropic/claude-opus-4-7.toml | 9 +- .../models/anthropic/claude-opus-4-8.toml | 3 + .../anthropic/claude-sonnet-4-5-20250929.toml | 11 +- .../models/anthropic/claude-sonnet-4-6.toml | 14 +- .../models/anthropic/claude-sonnet-5.toml | 9 + .../models/cohere/command-a-03-2025.toml | 2 + .../models/cohere/command-r-08-2024.toml | 2 + .../models/cohere/command-r-plus-08-2024.toml | 2 + .../models/cohere/command-r7b-12-2024.toml | 2 + .../models/deepseek/deepseek-r1.toml | 13 + .../models/deepseek/deepseek-v4-flash.toml | 1 + .../models/deepseek/deepseek-v4-pro.toml | 1 + .../models/google/gemini-2.5-flash-lite.toml | 15 +- .../models/google/gemini-2.5-flash.toml | 12 +- .../models/google/gemini-2.5-pro.toml | 9 +- .../models/google/gemini-3-flash-preview.toml | 8 +- .../models/google/gemini-3.1-flash-lite.toml | 9 +- .../gemini-3.1-pro-preview-customtools.toml | 8 +- .../models/google/gemini-3.1-pro-preview.toml | 8 +- .../models/google/gemini-3.5-flash.toml | 8 +- .../models/google/gemma-4-26b-a4b-it.toml | 17 +- .../models/google/gemma-4-31b-it.toml | 17 +- .../models/meta/llama-3.3-70b-instruct.toml | 7 + .../models/meta/muse-spark-1.1.toml | 14 + .../models/minimax/minimax-m2.1.toml | 7 + .../minimax/minimax-m2.5-highspeed.toml | 5 + .../models/minimax/minimax-m2.5.toml | 5 + .../minimax/minimax-m2.7-highspeed.toml | 5 + .../models/minimax/minimax-m2.7.toml | 5 + .../models/minimax/minimax-m2.toml | 7 + .../models/minimax/minimax-m3.toml | 13 +- .../models/mistral/devstral-2512.toml | 6 +- .../models/mistral/mistral-large-2512.toml | 5 + .../models/mistral/mistral-medium-2505.toml | 5 + .../models/nvidia/nemotron-nano-9b-v2.toml | 13 + .../models/openai/gpt-3.5-turbo.toml | 6 + .../models/openai/gpt-4-turbo.toml | 8 + .../models/openai/gpt-4.1-mini.toml | 1 + .../models/openai/gpt-4.1-nano.toml | 4 + .../merge-gateway/models/openai/gpt-4.toml | 7 + .../models/openai/gpt-4o-2024-05-13.toml | 4 + .../models/openai/gpt-4o-2024-08-06.toml | 3 + .../models/openai/gpt-4o-2024-11-20.toml | 3 + .../models/openai/gpt-4o-mini.toml | 1 + .../models/openai/gpt-5-chat-latest.toml | 9 + .../models/openai/gpt-5-mini.toml | 8 +- .../models/openai/gpt-5-nano.toml | 8 +- .../models/openai/gpt-5.1-chat-latest.toml | 4 + .../merge-gateway/models/openai/gpt-5.1.toml | 8 +- .../models/openai/gpt-5.2-chat-latest.toml | 4 + .../merge-gateway/models/openai/gpt-5.2.toml | 8 +- .../models/openai/gpt-5.3-chat-latest.toml | 4 + .../models/openai/gpt-5.4-mini.toml | 9 +- .../models/openai/gpt-5.4-nano.toml | 9 +- .../models/openai/gpt-5.6-luna.toml | 7 + .../models/openai/gpt-5.6-sol.toml | 12 + .../models/openai/gpt-5.6-terra.toml | 7 + .../merge-gateway/models/openai/gpt-5.toml | 8 +- .../models/openai/gpt-oss-120b.toml | 12 + .../models/openai/gpt-oss-20b.toml | 10 + .../merge-gateway/models/openai/o3-mini.toml | 6 +- .../merge-gateway/models/openai/o4-mini.toml | 4 + .../merge-gateway/models/qwen/qwen-flash.toml | 11 + .../merge-gateway/models/qwen/qwen-plus.toml | 11 + .../models/qwen/qwen3-235b-a22b.toml | 12 + .../merge-gateway/models/qwen/qwen3-32b.toml | 11 + .../qwen/qwen3-coder-480b-a35b-instruct.toml | 11 + .../models/qwen/qwen3-coder-flash.toml | 10 + .../models/qwen/qwen3-coder-plus.toml | 11 + .../merge-gateway/models/qwen/qwen3-max.toml | 7 + .../qwen/qwen3-next-80b-a3b-instruct.toml | 7 + .../qwen/qwen3-next-80b-a3b-thinking.toml | 8 + .../models/qwen/qwen3-vl-plus.toml | 12 + .../models/qwen/qwen3.5-122b-a10b.toml | 16 + .../models/qwen/qwen3.5-27b.toml | 16 + .../models/qwen/qwen3.5-35b-a3b.toml | 17 ++ .../models/qwen/qwen3.5-397b-a17b.toml | 17 ++ .../merge-gateway/models/qwen/qwen3.5-9b.toml | 14 + .../models/qwen/qwen3.5-plus.toml | 14 + .../models/qwen/qwen3.6-27b.toml | 15 + .../models/qwen/qwen3.6-35b-a3b.toml | 13 + .../models/qwen/qwen3.6-flash.toml | 15 + .../models/qwen/qwen3.6-max-preview.toml | 11 + .../models/qwen/qwen3.6-plus.toml | 14 + .../models/qwen/qwen3.7-max.toml | 11 + .../models/qwen/qwen3.7-plus.toml | 12 + .../xai/grok-4.20-0309-non-reasoning.toml | 13 + .../models/xai/grok-4.20-0309-reasoning.toml | 7 + .../merge-gateway/models/xai/grok-4.3.toml | 6 + .../merge-gateway/models/xai/grok-4.5.toml | 7 + .../models/xai/grok-build-0.1.toml | 10 + .../merge-gateway/models/zai/glm-4.5-air.toml | 9 +- .../merge-gateway/models/zai/glm-4.5.toml | 8 +- .../merge-gateway/models/zai/glm-4.5v.toml | 17 ++ .../merge-gateway/models/zai/glm-4.6.toml | 8 +- .../models/zai/glm-4.7-flash.toml | 11 + .../models/zai/glm-4.7-flashx.toml | 6 +- .../merge-gateway/models/zai/glm-4.7.toml | 8 +- .../merge-gateway/models/zai/glm-5-turbo.toml | 6 +- .../merge-gateway/models/zai/glm-5.1.toml | 5 +- .../merge-gateway/models/zai/glm-5.2.toml | 11 +- providers/merge-gateway/models/zai/glm-5.toml | 8 +- sync.md | 14 + 115 files changed, 1429 insertions(+), 43 deletions(-) create mode 100644 packages/core/src/sync/providers/merge-gateway.ts create mode 100644 providers/merge-gateway/models/anthropic/claude-3-7-sonnet-20250219.toml create mode 100644 providers/merge-gateway/models/anthropic/claude-fable-5.toml create mode 100644 providers/merge-gateway/models/anthropic/claude-sonnet-5.toml create mode 100644 providers/merge-gateway/models/deepseek/deepseek-r1.toml create mode 100644 providers/merge-gateway/models/meta/llama-3.3-70b-instruct.toml create mode 100644 providers/merge-gateway/models/meta/muse-spark-1.1.toml create mode 100644 providers/merge-gateway/models/nvidia/nemotron-nano-9b-v2.toml create mode 100644 providers/merge-gateway/models/openai/gpt-3.5-turbo.toml create mode 100644 providers/merge-gateway/models/openai/gpt-4-turbo.toml create mode 100644 providers/merge-gateway/models/openai/gpt-4.toml create mode 100644 providers/merge-gateway/models/openai/gpt-5.6-luna.toml create mode 100644 providers/merge-gateway/models/openai/gpt-5.6-sol.toml create mode 100644 providers/merge-gateway/models/openai/gpt-5.6-terra.toml create mode 100644 providers/merge-gateway/models/openai/gpt-oss-120b.toml create mode 100644 providers/merge-gateway/models/openai/gpt-oss-20b.toml create mode 100644 providers/merge-gateway/models/qwen/qwen-flash.toml create mode 100644 providers/merge-gateway/models/qwen/qwen-plus.toml create mode 100644 providers/merge-gateway/models/qwen/qwen3-235b-a22b.toml create mode 100644 providers/merge-gateway/models/qwen/qwen3-32b.toml create mode 100644 providers/merge-gateway/models/qwen/qwen3-coder-480b-a35b-instruct.toml create mode 100644 providers/merge-gateway/models/qwen/qwen3-coder-flash.toml create mode 100644 providers/merge-gateway/models/qwen/qwen3-coder-plus.toml create mode 100644 providers/merge-gateway/models/qwen/qwen3-max.toml create mode 100644 providers/merge-gateway/models/qwen/qwen3-next-80b-a3b-instruct.toml create mode 100644 providers/merge-gateway/models/qwen/qwen3-next-80b-a3b-thinking.toml create mode 100644 providers/merge-gateway/models/qwen/qwen3-vl-plus.toml create mode 100644 providers/merge-gateway/models/qwen/qwen3.5-122b-a10b.toml create mode 100644 providers/merge-gateway/models/qwen/qwen3.5-27b.toml create mode 100644 providers/merge-gateway/models/qwen/qwen3.5-35b-a3b.toml create mode 100644 providers/merge-gateway/models/qwen/qwen3.5-397b-a17b.toml create mode 100644 providers/merge-gateway/models/qwen/qwen3.5-9b.toml create mode 100644 providers/merge-gateway/models/qwen/qwen3.5-plus.toml create mode 100644 providers/merge-gateway/models/qwen/qwen3.6-27b.toml create mode 100644 providers/merge-gateway/models/qwen/qwen3.6-35b-a3b.toml create mode 100644 providers/merge-gateway/models/qwen/qwen3.6-flash.toml create mode 100644 providers/merge-gateway/models/qwen/qwen3.6-max-preview.toml create mode 100644 providers/merge-gateway/models/qwen/qwen3.6-plus.toml create mode 100644 providers/merge-gateway/models/qwen/qwen3.7-max.toml create mode 100644 providers/merge-gateway/models/qwen/qwen3.7-plus.toml create mode 100644 providers/merge-gateway/models/xai/grok-4.20-0309-non-reasoning.toml create mode 100644 providers/merge-gateway/models/xai/grok-4.5.toml create mode 100644 providers/merge-gateway/models/xai/grok-build-0.1.toml create mode 100644 providers/merge-gateway/models/zai/glm-4.5v.toml create mode 100644 providers/merge-gateway/models/zai/glm-4.7-flash.toml diff --git a/.github/workflows/sync-models.yml b/.github/workflows/sync-models.yml index 5edb83859a..0a1bc91169 100644 --- a/.github/workflows/sync-models.yml +++ b/.github/workflows/sync-models.yml @@ -73,6 +73,7 @@ jobs: OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} VENICE_API_KEY: ${{ secrets.VENICE_API_KEY }} LLMGATEWAY_API_KEY: ${{ secrets.LLMGATEWAY_API_KEY }} + MERGE_GATEWAY_API_KEY: ${{ secrets.MERGE_GATEWAY_API_KEY }} KILO_API_KEY: ${{ secrets.KILO_API_KEY }} GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }} GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }} diff --git a/package.json b/package.json index d4cab62ded..3a2159aaac 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "huggingface:sync": "bun ./packages/core/script/sync-models.ts huggingface", "kilo:sync": "bun ./packages/core/script/sync-models.ts kilo", "llmgateway:sync": "bun ./packages/core/script/sync-models.ts llmgateway", + "merge-gateway:sync": "bun ./packages/core/script/sync-models.ts merge-gateway", "venice:sync": "bun ./packages/core/script/sync-models.ts venice", "vercel:generate": "bun ./packages/core/script/sync-models.ts vercel", "wandb:generate": "bun ./packages/core/script/sync-models.ts wandb", diff --git a/packages/core/src/sync/index.ts b/packages/core/src/sync/index.ts index 3b8c8fce97..afc0fc57cc 100644 --- a/packages/core/src/sync/index.ts +++ b/packages/core/src/sync/index.ts @@ -17,6 +17,7 @@ import { google } from "./providers/google.js"; import { huggingface } from "./providers/huggingface.js"; import { kilo } from "./providers/kilo.js"; import { llmgateway } from "./providers/llmgateway.js"; +import { mergeGateway } from "./providers/merge-gateway.js"; import { openai } from "./providers/openai.js"; import { openrouter } from "./providers/openrouter.js"; import { ovhcloud } from "./providers/ovhcloud.js"; @@ -106,6 +107,7 @@ export const providers: { kilo: SyncProvider; huggingface: SyncProvider; llmgateway: SyncProvider; + "merge-gateway": SyncProvider; openai: SyncProvider; openrouter: SyncProvider; ovhcloud: SyncProvider; @@ -128,6 +130,7 @@ export const providers: { kilo, huggingface, llmgateway, + "merge-gateway": mergeGateway, openai, openrouter, ovhcloud, @@ -139,7 +142,7 @@ export const providers: { }; export const groups = { - aggregators: ["crossmodel", "empiriolabs", "huggingface", "kilo", "llmgateway", "openrouter", "vercel"], + aggregators: ["crossmodel", "empiriolabs", "huggingface", "kilo", "llmgateway", "merge-gateway", "openrouter", "vercel"], cloudflare: ["cloudflare-workers-ai"], direct: ["ambient", "anthropic", "baseten", "chutes", "deepinfra", "digitalocean", "google", "openai", "ovhcloud", "pioneer", "venice", "wandb", "xai"], } as const; diff --git a/packages/core/src/sync/providers/merge-gateway.ts b/packages/core/src/sync/providers/merge-gateway.ts new file mode 100644 index 0000000000..87829ede0e --- /dev/null +++ b/packages/core/src/sync/providers/merge-gateway.ts @@ -0,0 +1,287 @@ +import { z } from "zod"; + +import { describeModel } from "../../describe.js"; +import type { ExistingModel, SyncProvider, SyncedFullModel, SyncedModel } from "../index.js"; +import { factorBaseModel, resolveCanonicalBaseModel } from "./openrouter.js"; + +const API_ENDPOINT = "https://api-gateway.merge.dev/v1/models"; + +const AvailabilityStatus = z.enum(["available", "deprecated"]); + +const VendorCapabilities = z.object({ + input: z.array(z.enum(["text", "audio", "image", "document", "embedding"])), + output: z.array(z.enum(["text", "audio", "tool_use", "embedding"])), + supports_tool_calling: z.boolean(), + supports_tool_choice: z.boolean().default(false), + supports_structured_outputs: z.boolean(), + streaming: z.boolean(), +}).passthrough(); + +const PromptCaching = z.object({ + mode: z.enum(["automatic", "explicit", "none"]).optional(), + cache_read_cost_per_million: z.number().nonnegative().nullable().optional(), + cache_write_cost_per_million: z.number().nonnegative().nullable().optional(), +}).passthrough(); + +const VendorInfo = z.object({ + launch_date: z.string().nullable().optional(), + context_window: z.number().int().nonnegative(), + max_output_tokens: z.number().int().nonnegative(), + availability_status: AvailabilityStatus, + capabilities: VendorCapabilities, + pricing: z.object({ + currency: z.literal("USD").default("USD"), + input_per_million: z.number().nonnegative(), + output_per_million: z.number().nonnegative(), + cache_read_per_million: z.number().nonnegative().nullable().optional(), + cache_write_per_million: z.number().nonnegative().nullable().optional(), + }).passthrough(), + prompt_caching: PromptCaching.nullable().optional(), +}).passthrough(); + +export const MergeGatewayModel = z.object({ + model: z.string().min(1), + provider: z.string().min(1), + display_name: z.string().min(1), + vendors: z.record(VendorInfo), + availability_status: AvailabilityStatus, + created_at: z.string().nullable().optional(), + updated_at: z.string().nullable().optional(), +}).passthrough(); + +export const MergeGatewayResponse = z.object({ + object: z.literal("list").default("list"), + data: z.array(MergeGatewayModel), + has_more: z.boolean().default(false), + next_cursor: z.string().nullable().optional(), +}).passthrough(); + +export type MergeGatewayModel = z.infer; +export type MergeGatewayVendor = z.infer; + +export async function fetchMergeGatewayModels( + fetcher: typeof fetch = fetch, + apiKey = process.env.MERGE_GATEWAY_API_KEY, +) { + if (!apiKey) throw new Error("MERGE_GATEWAY_API_KEY is required to sync Merge Gateway models"); + + const models = new Map(); + const cursors = new Set(); + let cursor: string | undefined; + + do { + const url = new URL(API_ENDPOINT); + url.searchParams.set("limit", "500"); + if (cursor !== undefined) url.searchParams.set("cursor", cursor); + + const response = await fetcher(url, { + headers: { Authorization: `Bearer ${apiKey}` }, + }); + if (!response.ok) { + throw new Error(`Merge Gateway request failed: ${response.status} ${response.statusText}`); + } + + const page = MergeGatewayResponse.parse(await response.json()); + for (const model of page.data) models.set(model.model, model); + if (!page.has_more) break; + if (!page.next_cursor) throw new Error("Merge Gateway returned has_more=true without next_cursor"); + if (cursors.has(page.next_cursor)) throw new Error(`Merge Gateway repeated cursor: ${page.next_cursor}`); + cursors.add(page.next_cursor); + cursor = page.next_cursor; + } while (true); + + return { + object: "list" as const, + data: [...models.values()], + has_more: false, + next_cursor: null, + }; +} + +export const mergeGateway = { + id: "merge-gateway", + name: "Merge Gateway", + modelsDir: "providers/merge-gateway/models", + // API-key policy can affect catalog visibility. Retain missing local models + // until Merge exposes an account-independent catalog response. + deleteMissing: false, + sourceID(model) { + return model.model; + }, + skippedNotice(ids) { + if (ids.length === 0) return []; + return [ + `${ids.length} Merge Gateway models were skipped because they are not text models or lack canonical metadata.`, + `Skipped remote IDs: ${ids.map((id) => `\`${id}\``).join(", ")}`, + ]; + }, + missingNotice(paths) { + if (paths.length === 0) return []; + return [ + `${paths.length} local Merge Gateway models were absent from the API response and retained for manual lifecycle review.`, + `Retained local paths: ${paths.map((item) => `\`${item}\``).join(", ")}`, + ]; + }, + fetchModels() { + return fetchMergeGatewayModels(); + }, + parseModels(raw) { + return MergeGatewayResponse.parse(raw).data; + }, + translateModel(model, context) { + const existing = context.existing(model.model); + const translated = buildMergeGatewayModel(model, existing, context.authored(model.model)); + return translated === undefined ? undefined : { id: model.model, model: translated }; + }, +} satisfies SyncProvider; + +export function selectMergeGatewayVendor(model: MergeGatewayModel) { + const canonical = model.vendors[model.provider]; + if (canonical?.availability_status === "available") { + return { id: model.provider, info: canonical }; + } + + const available = Object.entries(model.vendors) + .filter(([, info]) => info.availability_status === "available") + .sort(([a], [b]) => a.localeCompare(b))[0]; + if (available !== undefined) return { id: available[0], info: available[1] }; + if (canonical !== undefined) return { id: model.provider, info: canonical }; + + const fallback = Object.entries(model.vendors).sort(([a], [b]) => a.localeCompare(b))[0]; + return fallback === undefined ? undefined : { id: fallback[0], info: fallback[1] }; +} + +export function buildMergeGatewayModel( + model: MergeGatewayModel, + existing: ExistingModel | undefined, + authored: ExistingModel | undefined = existing, +): SyncedModel | undefined { + const selected = selectMergeGatewayVendor(model); + if (selected === undefined || !selected.info.capabilities.output.includes("text")) return undefined; + + const input = modalities(selected.info.capabilities.input); + const output = modalities(selected.info.capabilities.output); + const limit = { + context: selected.info.context_window || existing?.limit?.context || 0, + // Preserve only a provider-authored input cap. `existing` is resolved + // against base-model metadata, so using its inherited input value here + // can keep an impossible cap when the gateway reports a smaller context. + input: authored?.limit?.input, + output: selected.info.max_output_tokens || existing?.limit?.output || selected.info.context_window, + }; + const cachePricing = mergeGatewayCachePricing(selected.info, existing); + const cost = { + input: selected.info.pricing.input_per_million, + output: selected.info.pricing.output_per_million, + reasoning: existing?.cost?.reasoning, + cache_read: cachePricing.read, + cache_write: cachePricing.write, + input_audio: existing?.cost?.input_audio, + output_audio: existing?.cost?.output_audio, + tiers: existing?.cost?.tiers, + }; + const status = model.availability_status === "deprecated" || selected.info.availability_status === "deprecated" + ? "deprecated" as const + : undefined; + const baseModel = existing?.base_model ?? resolveCanonicalBaseModel(model.model); + const authoritative = { + // Some catalog rows use an upstream org/model ID as display_name. Let + // canonical metadata provide the human-readable name for factored models. + name: baseModel !== undefined && model.display_name.includes("/") ? undefined : model.display_name, + attachment: input.some((value) => value !== "text"), + tool_call: selected.info.capabilities.supports_tool_calling, + structured_output: selected.info.capabilities.supports_structured_outputs, + status, + cost, + limit, + modalities: { input, output }, + }; + + if (baseModel !== undefined) { + return factorBaseModel( + baseModel, + { + ...authoritative, + description: existing?.description, + reasoning: existing?.reasoning, + reasoning_options: existing?.reasoning_options, + temperature: existing?.temperature, + interleaved: existing?.interleaved, + provider: existing?.provider, + experimental: existing?.experimental, + }, + limit, + existing?.base_model_omit, + ); + } + + if (existing === undefined) return undefined; + + const releaseDate = selected.info.launch_date + ?? model.created_at?.slice(0, 10) + ?? existing.release_date; + if (releaseDate === undefined) return undefined; + const lastUpdated = model.updated_at?.slice(0, 10) + ?? existing.last_updated + ?? releaseDate; + return { + ...authoritative, + description: existing.description ?? describeModel({ + id: model.model, + name: model.display_name, + family: existing.family, + reasoning: existing.reasoning, + tool_call: selected.info.capabilities.supports_tool_calling, + structured_output: selected.info.capabilities.supports_structured_outputs, + open_weights: existing.open_weights, + limit, + modalities: { input, output }, + }), + family: existing.family, + release_date: releaseDate, + last_updated: lastUpdated, + reasoning: existing.reasoning ?? false, + reasoning_options: existing.reasoning_options, + temperature: existing.temperature, + knowledge: existing.knowledge, + open_weights: existing.open_weights ?? false, + interleaved: existing.interleaved, + provider: existing.provider, + experimental: existing.experimental, + } satisfies SyncedFullModel; +} + +function mergeGatewayCachePricing( + vendor: MergeGatewayVendor, + existing: ExistingModel | undefined, +) { + const promptCaching = vendor.prompt_caching; + const pricing = vendor.pricing; + const authoritative = promptCaching !== undefined + || pricing.cache_read_per_million !== undefined + || pricing.cache_write_per_million !== undefined; + if (!authoritative) { + return { + read: existing?.cost?.cache_read, + write: existing?.cost?.cache_write, + }; + } + return { + read: promptCaching?.cache_read_cost_per_million + ?? pricing.cache_read_per_million + ?? undefined, + write: promptCaching?.cache_write_cost_per_million + ?? pricing.cache_write_per_million + ?? undefined, + }; +} + +type Modality = "text" | "audio" | "image" | "video" | "pdf"; + +function modalities(values: string[]): Modality[] { + const allowed = new Set(["text", "audio", "image", "video", "pdf"]); + return [...new Set(values + .map((value) => value === "document" ? "pdf" : value) + .filter((value): value is Modality => allowed.has(value as Modality)) + )]; +} diff --git a/packages/core/test/sync.test.ts b/packages/core/test/sync.test.ts index d9287ebca8..4fbd29f3e6 100644 --- a/packages/core/test/sync.test.ts +++ b/packages/core/test/sync.test.ts @@ -32,6 +32,14 @@ import { type OpenRouterModel, } from "../src/sync/providers/openrouter.js"; import { buildLLMGatewayModel, type LLMGatewayModel } from "../src/sync/providers/llmgateway.js"; +import { + buildMergeGatewayModel, + fetchMergeGatewayModels, + mergeGateway, + MergeGatewayResponse, + selectMergeGatewayVendor, + type MergeGatewayModel, +} from "../src/sync/providers/merge-gateway.js"; import { openai, parseOpenAIModels } from "../src/sync/providers/openai.js"; import { resolveVeniceBaseModel } from "../src/sync/providers/venice.js"; import { buildVercelModel, vercel } from "../src/sync/providers/vercel.js"; @@ -1062,6 +1070,153 @@ test("factors aliased LLM Gateway routes against canonical metadata", () => { }); }); +test("fetches every page of the Merge Gateway catalog", async () => { + const requests: string[] = []; + const authorizations: string[] = []; + const fetcher = ((input: string | URL | Request, init?: RequestInit) => { + const url = String(input); + requests.push(url); + authorizations.push(new Headers(init?.headers).get("Authorization") ?? ""); + const next = url.includes("cursor=next-page"); + return Promise.resolve(new Response(JSON.stringify({ + object: "list", + data: [mergeGatewayModel({ + model: next ? "openai/gpt-5.6-terra" : "openai/gpt-5.6-sol", + display_name: next ? "GPT-5.6 Terra" : "GPT-5.6 Sol", + })], + has_more: !next, + next_cursor: next ? null : "next-page", + }))); + }) as typeof fetch; + + const result = await fetchMergeGatewayModels(fetcher, "test-key"); + + expect(result.data.map((model) => model.model)).toEqual([ + "openai/gpt-5.6-sol", + "openai/gpt-5.6-terra", + ]); + expect(requests).toHaveLength(2); + expect(requests[0]).toContain("limit=500"); + expect(requests[1]).toContain("cursor=next-page"); + expect(authorizations).toEqual(["Bearer test-key", "Bearer test-key"]); +}); + +test("accepts audio modalities from the Merge Gateway catalog", () => { + const model = mergeGatewayModel(); + model.vendors.openai.capabilities.input.push("audio"); + + expect(MergeGatewayResponse.parse({ + object: "list", + data: [model], + has_more: false, + next_cursor: null, + }).data[0]?.vendors.openai.capabilities.input).toContain("audio"); +}); + +test("factors Merge Gateway GPT-5.6 Sol against canonical metadata", () => { + const model = buildMergeGatewayModel(mergeGatewayModel(), undefined); + + expect(model).toEqual({ + base_model: "openai/gpt-5.6-sol", + cost: { + input: 5, + output: 30, + }, + }); +}); + +test("syncs authoritative Merge Gateway cache pricing", () => { + const model = buildMergeGatewayModel(mergeGatewayModel({ + vendors: { + openai: mergeGatewayVendor({ + pricing: { + currency: "USD", + input_per_million: 3.75, + output_per_million: 22.5, + }, + prompt_caching: { + mode: "automatic", + cache_read_cost_per_million: 0.375, + }, + }), + }, + }), { + base_model: "openai/gpt-5.6-sol", + cost: { + input: 5, + output: 30, + cache_read: 0.5, + cache_write: 6.25, + }, + }); + + expect(model).toEqual({ + base_model: "openai/gpt-5.6-sol", + cost: { + input: 3.75, + output: 22.5, + cache_read: 0.375, + }, + }); +}); + +test("inherits canonical names for ID-shaped Merge Gateway display names", () => { + const model = buildMergeGatewayModel(mergeGatewayModel({ + model: "minimax/minimax-m2", + provider: "minimax", + display_name: "MiniMaxAI/MiniMax-M2", + vendors: { minimax: mergeGatewayVendor() }, + }), undefined); + + expect(model).not.toHaveProperty("name"); +}); + +test("omits inherited input limits above the Merge Gateway context", () => { + const model = buildMergeGatewayModel(mergeGatewayModel({ + model: "openai/gpt-5-chat-latest", + display_name: "GPT-5 Chat Latest", + vendors: { + openai: mergeGatewayVendor({ + context_window: 128_000, + max_output_tokens: 16_384, + }), + }, + }), { + base_model: "openai/gpt-5-chat-latest", + limit: { + context: 128_000, + input: 272_000, + output: 16_384, + }, + }, { + base_model: "openai/gpt-5-chat-latest", + limit: { + context: 128_000, + output: 16_384, + }, + }); + + expect(model).toHaveProperty("base_model_omit", ["limit.input"]); +}); + +test("uses the canonical Merge Gateway vendor as the catalog baseline", () => { + const model = mergeGatewayModel({ + vendors: { + azure: mergeGatewayVendor({ context_window: 200_000 }), + openai: mergeGatewayVendor({ context_window: 1_050_000 }), + }, + }); + + expect(selectMergeGatewayVendor(model)).toMatchObject({ + id: "openai", + info: { context_window: 1_050_000 }, + }); +}); + +test("retains Merge Gateway models missing from an API-key-scoped response", () => { + expect(mergeGateway.deleteMissing).toBe(false); +}); + test("parses Vercel pricing tiers with an implicit zero minimum", () => { const [model] = vercel.parseModels({ data: [{ @@ -1296,6 +1451,44 @@ function llmGatewayModel(overrides: Partial = {}): LLMGatewayMo }; } +function mergeGatewayVendor( + overrides: Partial = {}, +): MergeGatewayModel["vendors"][string] { + return { + launch_date: "2026-07-09", + context_window: 1_050_000, + max_output_tokens: 128_000, + availability_status: "available", + capabilities: { + input: ["text", "image", "document"], + output: ["text", "tool_use"], + supports_tool_calling: true, + supports_tool_choice: true, + supports_structured_outputs: true, + streaming: true, + }, + pricing: { + currency: "USD", + input_per_million: 5, + output_per_million: 30, + }, + ...overrides, + }; +} + +function mergeGatewayModel(overrides: Partial = {}): MergeGatewayModel { + return { + model: "openai/gpt-5.6-sol", + provider: "openai", + display_name: "GPT-5.6 Sol", + vendors: { openai: mergeGatewayVendor() }, + availability_status: "available", + created_at: "2026-07-09T00:00:00Z", + updated_at: "2026-07-09T00:00:00Z", + ...overrides, + }; +} + function openRouterModel(overrides: Partial = {}): OpenRouterModel { return { id: "anthropic/claude-sonnet-5", diff --git a/providers/merge-gateway/models/anthropic/claude-3-7-sonnet-20250219.toml b/providers/merge-gateway/models/anthropic/claude-3-7-sonnet-20250219.toml new file mode 100644 index 0000000000..8c0263b486 --- /dev/null +++ b/providers/merge-gateway/models/anthropic/claude-3-7-sonnet-20250219.toml @@ -0,0 +1,13 @@ +base_model = "anthropic/claude-3-7-sonnet-20250219" +name = "Claude 3.7 Sonnet" +structured_output = true +reasoning_options = [] + +[cost] +input = 3 +output = 15 +cache_read = 0.3 +cache_write = 3.75 + +[modalities] +input = ["text", "image"] diff --git a/providers/merge-gateway/models/anthropic/claude-fable-5.toml b/providers/merge-gateway/models/anthropic/claude-fable-5.toml new file mode 100644 index 0000000000..747fc86411 --- /dev/null +++ b/providers/merge-gateway/models/anthropic/claude-fable-5.toml @@ -0,0 +1,9 @@ +base_model = "anthropic/claude-fable-5" +structured_output = true +reasoning_options = [] + +[cost] +input = 10 +output = 50 +cache_read = 1 +cache_write = 12.5 diff --git a/providers/merge-gateway/models/anthropic/claude-haiku-4-5-20251001.toml b/providers/merge-gateway/models/anthropic/claude-haiku-4-5-20251001.toml index 251d373dcd..12beefa8b4 100644 --- a/providers/merge-gateway/models/anthropic/claude-haiku-4-5-20251001.toml +++ b/providers/merge-gateway/models/anthropic/claude-haiku-4-5-20251001.toml @@ -1,5 +1,14 @@ base_model = "anthropic/claude-haiku-4-5-20251001" -reasoning_options = [{ type = "toggle" }, { type = "budget_tokens", min = 1_024, max = 63_999 }] +name = "Claude Haiku 4.5 (20251001)" +structured_output = true + +[[reasoning_options]] +type = "toggle" + +[[reasoning_options]] +type = "budget_tokens" +min = 1_024 +max = 63_999 [cost] input = 1 diff --git a/providers/merge-gateway/models/anthropic/claude-opus-4-1-20250805.toml b/providers/merge-gateway/models/anthropic/claude-opus-4-1-20250805.toml index a83a37b18f..80cef05967 100644 --- a/providers/merge-gateway/models/anthropic/claude-opus-4-1-20250805.toml +++ b/providers/merge-gateway/models/anthropic/claude-opus-4-1-20250805.toml @@ -1,5 +1,14 @@ base_model = "anthropic/claude-opus-4-1-20250805" -reasoning_options = [{ type = "toggle" }, { type = "budget_tokens", min = 1_024, max = 31_999 }] +name = "Claude Opus 4.1 (20250805)" +structured_output = true + +[[reasoning_options]] +type = "toggle" + +[[reasoning_options]] +type = "budget_tokens" +min = 1_024 +max = 31_999 [cost] input = 15 diff --git a/providers/merge-gateway/models/anthropic/claude-opus-4-20250514.toml b/providers/merge-gateway/models/anthropic/claude-opus-4-20250514.toml index 78dc345257..0b0174e5b0 100644 --- a/providers/merge-gateway/models/anthropic/claude-opus-4-20250514.toml +++ b/providers/merge-gateway/models/anthropic/claude-opus-4-20250514.toml @@ -1,5 +1,14 @@ base_model = "anthropic/claude-opus-4-20250514" -reasoning_options = [{ type = "toggle" }, { type = "budget_tokens", min = 1_024, max = 31_999 }] +name = "Claude Opus 4 (20250514)" +structured_output = true + +[[reasoning_options]] +type = "toggle" + +[[reasoning_options]] +type = "budget_tokens" +min = 1_024 +max = 31_999 [cost] input = 15 diff --git a/providers/merge-gateway/models/anthropic/claude-opus-4-5-20251101.toml b/providers/merge-gateway/models/anthropic/claude-opus-4-5-20251101.toml index 32e8e536b3..e51f165765 100644 --- a/providers/merge-gateway/models/anthropic/claude-opus-4-5-20251101.toml +++ b/providers/merge-gateway/models/anthropic/claude-opus-4-5-20251101.toml @@ -1,5 +1,18 @@ base_model = "anthropic/claude-opus-4-5-20251101" -reasoning_options = [{ type = "toggle" }, { type = "effort", values = ["low", "medium", "high"] }, { type = "budget_tokens", min = 1_024, max = 63_999 }] +name = "Claude Opus 4.5 (20251101)" +structured_output = true + +[[reasoning_options]] +type = "toggle" + +[[reasoning_options]] +type = "effort" +values = ["low", "medium", "high"] + +[[reasoning_options]] +type = "budget_tokens" +min = 1_024 +max = 63_999 [cost] input = 5 diff --git a/providers/merge-gateway/models/anthropic/claude-opus-4-6.toml b/providers/merge-gateway/models/anthropic/claude-opus-4-6.toml index ab7ffef972..63d173c380 100644 --- a/providers/merge-gateway/models/anthropic/claude-opus-4-6.toml +++ b/providers/merge-gateway/models/anthropic/claude-opus-4-6.toml @@ -1,5 +1,17 @@ base_model = "anthropic/claude-opus-4-6" -reasoning_options = [{ type = "toggle" }, { type = "effort", values = ["low", "medium", "high", "max"] }, { type = "budget_tokens", min = 1_024, max = 127_999 }] +structured_output = true + +[[reasoning_options]] +type = "toggle" + +[[reasoning_options]] +type = "effort" +values = ["low", "medium", "high", "max"] + +[[reasoning_options]] +type = "budget_tokens" +min = 1_024 +max = 127_999 [cost] input = 5 diff --git a/providers/merge-gateway/models/anthropic/claude-opus-4-7.toml b/providers/merge-gateway/models/anthropic/claude-opus-4-7.toml index fd5f3197ae..0fe0cead33 100644 --- a/providers/merge-gateway/models/anthropic/claude-opus-4-7.toml +++ b/providers/merge-gateway/models/anthropic/claude-opus-4-7.toml @@ -1,5 +1,12 @@ base_model = "anthropic/claude-opus-4-7" -reasoning_options = [{ type = "toggle" }, { type = "effort", values = ["low", "medium", "high", "xhigh", "max"] }] +structured_output = true + +[[reasoning_options]] +type = "toggle" + +[[reasoning_options]] +type = "effort" +values = ["low", "medium", "high", "xhigh", "max"] [cost] input = 5 diff --git a/providers/merge-gateway/models/anthropic/claude-opus-4-8.toml b/providers/merge-gateway/models/anthropic/claude-opus-4-8.toml index dc3ed91fa4..7606299bdd 100644 --- a/providers/merge-gateway/models/anthropic/claude-opus-4-8.toml +++ b/providers/merge-gateway/models/anthropic/claude-opus-4-8.toml @@ -1,4 +1,5 @@ base_model = "anthropic/claude-opus-4-8" +structured_output = true [[reasoning_options]] type = "toggle" @@ -11,3 +12,5 @@ max = 128_000 [cost] input = 5 output = 25 +cache_read = 0.5 +cache_write = 6.25 diff --git a/providers/merge-gateway/models/anthropic/claude-sonnet-4-5-20250929.toml b/providers/merge-gateway/models/anthropic/claude-sonnet-4-5-20250929.toml index 638620a26f..e9bf085d46 100644 --- a/providers/merge-gateway/models/anthropic/claude-sonnet-4-5-20250929.toml +++ b/providers/merge-gateway/models/anthropic/claude-sonnet-4-5-20250929.toml @@ -1,5 +1,14 @@ base_model = "anthropic/claude-sonnet-4-5-20250929" -reasoning_options = [{ type = "toggle" }, { type = "budget_tokens", min = 1_024, max = 63_999 }] +name = "Claude Sonnet 4.5 (20250929)" +structured_output = true + +[[reasoning_options]] +type = "toggle" + +[[reasoning_options]] +type = "budget_tokens" +min = 1_024 +max = 63_999 [cost] input = 3 diff --git a/providers/merge-gateway/models/anthropic/claude-sonnet-4-6.toml b/providers/merge-gateway/models/anthropic/claude-sonnet-4-6.toml index b341540673..89818d9638 100644 --- a/providers/merge-gateway/models/anthropic/claude-sonnet-4-6.toml +++ b/providers/merge-gateway/models/anthropic/claude-sonnet-4-6.toml @@ -1,5 +1,17 @@ base_model = "anthropic/claude-sonnet-4-6" -reasoning_options = [{ type = "toggle" }, { type = "effort", values = ["low", "medium", "high", "max"] }, { type = "budget_tokens", min = 1_024, max = 63_999 }] +structured_output = true + +[[reasoning_options]] +type = "toggle" + +[[reasoning_options]] +type = "effort" +values = ["low", "medium", "high", "max"] + +[[reasoning_options]] +type = "budget_tokens" +min = 1_024 +max = 63_999 [cost] input = 3 diff --git a/providers/merge-gateway/models/anthropic/claude-sonnet-5.toml b/providers/merge-gateway/models/anthropic/claude-sonnet-5.toml new file mode 100644 index 0000000000..fc8b6671ee --- /dev/null +++ b/providers/merge-gateway/models/anthropic/claude-sonnet-5.toml @@ -0,0 +1,9 @@ +base_model = "anthropic/claude-sonnet-5" +structured_output = true +reasoning_options = [] + +[cost] +input = 2 +output = 10 +cache_read = 0.2 +cache_write = 2.5 diff --git a/providers/merge-gateway/models/cohere/command-a-03-2025.toml b/providers/merge-gateway/models/cohere/command-a-03-2025.toml index 35796b0798..663193e136 100644 --- a/providers/merge-gateway/models/cohere/command-a-03-2025.toml +++ b/providers/merge-gateway/models/cohere/command-a-03-2025.toml @@ -1,4 +1,6 @@ base_model = "cohere/command-a-03-2025" +name = "Command A 03-2025" +structured_output = true [cost] input = 2.5 diff --git a/providers/merge-gateway/models/cohere/command-r-08-2024.toml b/providers/merge-gateway/models/cohere/command-r-08-2024.toml index 5b6e7da099..481c8c3467 100644 --- a/providers/merge-gateway/models/cohere/command-r-08-2024.toml +++ b/providers/merge-gateway/models/cohere/command-r-08-2024.toml @@ -1,4 +1,6 @@ base_model = "cohere/command-r-08-2024" +name = "Command R 08-2024" +structured_output = true [cost] input = 0.15 diff --git a/providers/merge-gateway/models/cohere/command-r-plus-08-2024.toml b/providers/merge-gateway/models/cohere/command-r-plus-08-2024.toml index 419d99d79c..edb51176f7 100644 --- a/providers/merge-gateway/models/cohere/command-r-plus-08-2024.toml +++ b/providers/merge-gateway/models/cohere/command-r-plus-08-2024.toml @@ -1,4 +1,6 @@ base_model = "cohere/command-r-plus-08-2024" +name = "Command R+ 08-2024" +structured_output = true [cost] input = 2.5 diff --git a/providers/merge-gateway/models/cohere/command-r7b-12-2024.toml b/providers/merge-gateway/models/cohere/command-r7b-12-2024.toml index 815678c3b3..7a77f4353c 100644 --- a/providers/merge-gateway/models/cohere/command-r7b-12-2024.toml +++ b/providers/merge-gateway/models/cohere/command-r7b-12-2024.toml @@ -1,4 +1,6 @@ base_model = "cohere/command-r7b-12-2024" +name = "Command R7B 12-2024" +structured_output = true [cost] input = 0.0375 diff --git a/providers/merge-gateway/models/deepseek/deepseek-r1.toml b/providers/merge-gateway/models/deepseek/deepseek-r1.toml new file mode 100644 index 0000000000..283094ea09 --- /dev/null +++ b/providers/merge-gateway/models/deepseek/deepseek-r1.toml @@ -0,0 +1,13 @@ +base_model = "deepseek/deepseek-r1" +name = "DeepSeek R1" +tool_call = false +structured_output = false +reasoning_options = [] + +[cost] +input = 1.35 +output = 5.4 + +[limit] +context = 163_840 +output = 40_960 diff --git a/providers/merge-gateway/models/deepseek/deepseek-v4-flash.toml b/providers/merge-gateway/models/deepseek/deepseek-v4-flash.toml index 83ab2e7bde..12be6ee001 100644 --- a/providers/merge-gateway/models/deepseek/deepseek-v4-flash.toml +++ b/providers/merge-gateway/models/deepseek/deepseek-v4-flash.toml @@ -1,4 +1,5 @@ base_model = "deepseek/deepseek-v4-flash" +structured_output = false reasoning_options = [] [interleaved] diff --git a/providers/merge-gateway/models/deepseek/deepseek-v4-pro.toml b/providers/merge-gateway/models/deepseek/deepseek-v4-pro.toml index a90bf4b82e..cd7f2ca5bd 100644 --- a/providers/merge-gateway/models/deepseek/deepseek-v4-pro.toml +++ b/providers/merge-gateway/models/deepseek/deepseek-v4-pro.toml @@ -1,4 +1,5 @@ base_model = "deepseek/deepseek-v4-pro" +structured_output = false reasoning_options = [] [interleaved] diff --git a/providers/merge-gateway/models/google/gemini-2.5-flash-lite.toml b/providers/merge-gateway/models/google/gemini-2.5-flash-lite.toml index 99ae99972c..3905bebf13 100644 --- a/providers/merge-gateway/models/google/gemini-2.5-flash-lite.toml +++ b/providers/merge-gateway/models/google/gemini-2.5-flash-lite.toml @@ -1,8 +1,21 @@ base_model = "google/gemini-2.5-flash-lite" -reasoning_options = [{ type = "toggle" }, { type = "budget_tokens", min = 512, max = 24_576 }] + +[[reasoning_options]] +type = "toggle" + +[[reasoning_options]] +type = "budget_tokens" +min = 512 +max = 24_576 [cost] input = 0.1 output = 0.4 cache_read = 0.01 input_audio = 0.3 + +[limit] +context = 1_000_000 + +[modalities] +input = ["text", "image", "audio", "pdf"] diff --git a/providers/merge-gateway/models/google/gemini-2.5-flash.toml b/providers/merge-gateway/models/google/gemini-2.5-flash.toml index 49ba05adc1..7248eeda32 100644 --- a/providers/merge-gateway/models/google/gemini-2.5-flash.toml +++ b/providers/merge-gateway/models/google/gemini-2.5-flash.toml @@ -1,8 +1,18 @@ base_model = "google/gemini-2.5-flash" -reasoning_options = [{ type = "toggle" }, { type = "budget_tokens", min = 0, max = 24_576 }] + +[[reasoning_options]] +type = "toggle" + +[[reasoning_options]] +type = "budget_tokens" +min = 0 +max = 24_576 [cost] input = 0.3 output = 2.5 cache_read = 0.03 input_audio = 1 + +[modalities] +input = ["text", "image", "audio", "pdf"] diff --git a/providers/merge-gateway/models/google/gemini-2.5-pro.toml b/providers/merge-gateway/models/google/gemini-2.5-pro.toml index d5848f8ab3..273ccacf39 100644 --- a/providers/merge-gateway/models/google/gemini-2.5-pro.toml +++ b/providers/merge-gateway/models/google/gemini-2.5-pro.toml @@ -1,5 +1,9 @@ base_model = "google/gemini-2.5-pro" -reasoning_options = [{ type = "budget_tokens", min = 128, max = 32_768 }] + +[[reasoning_options]] +type = "budget_tokens" +min = 128 +max = 32_768 [cost] input = 1.25 @@ -11,3 +15,6 @@ tier = { type = "context", size = 200_000 } input = 2.5 output = 15 cache_read = 0.25 + +[modalities] +input = ["text", "image", "audio", "pdf"] diff --git a/providers/merge-gateway/models/google/gemini-3-flash-preview.toml b/providers/merge-gateway/models/google/gemini-3-flash-preview.toml index 56a17f3920..b8de1e8967 100644 --- a/providers/merge-gateway/models/google/gemini-3-flash-preview.toml +++ b/providers/merge-gateway/models/google/gemini-3-flash-preview.toml @@ -1,8 +1,14 @@ base_model = "google/gemini-3-flash-preview" -reasoning_options = [{ type = "effort", values = ["minimal", "low", "medium", "high"] }] + +[[reasoning_options]] +type = "effort" +values = ["minimal", "low", "medium", "high"] [cost] input = 0.5 output = 3 cache_read = 0.05 input_audio = 1 + +[modalities] +input = ["text", "image"] diff --git a/providers/merge-gateway/models/google/gemini-3.1-flash-lite.toml b/providers/merge-gateway/models/google/gemini-3.1-flash-lite.toml index d9d9b5d7dd..5c8f0f8a15 100644 --- a/providers/merge-gateway/models/google/gemini-3.1-flash-lite.toml +++ b/providers/merge-gateway/models/google/gemini-3.1-flash-lite.toml @@ -1,8 +1,15 @@ base_model = "google/gemini-3.1-flash-lite" -reasoning_options = [{ type = "effort", values = ["minimal", "low", "medium", "high"] }] +name = "Gemini 3.1 Flash-Lite" + +[[reasoning_options]] +type = "effort" +values = ["minimal", "low", "medium", "high"] [cost] input = 0.25 output = 1.5 cache_read = 0.025 input_audio = 0.5 + +[modalities] +input = ["text", "image", "audio", "pdf"] diff --git a/providers/merge-gateway/models/google/gemini-3.1-pro-preview-customtools.toml b/providers/merge-gateway/models/google/gemini-3.1-pro-preview-customtools.toml index 6669e542fc..a4183e8302 100644 --- a/providers/merge-gateway/models/google/gemini-3.1-pro-preview-customtools.toml +++ b/providers/merge-gateway/models/google/gemini-3.1-pro-preview-customtools.toml @@ -1,5 +1,8 @@ base_model = "google/gemini-3.1-pro-preview-customtools" -reasoning_options = [{ type = "effort", values = ["low", "medium", "high"] }] + +[[reasoning_options]] +type = "effort" +values = ["low", "medium", "high"] [cost] input = 2 @@ -11,3 +14,6 @@ tier = { type = "context", size = 200_000 } input = 4 output = 18 cache_read = 0.4 + +[modalities] +input = ["text", "image", "audio", "pdf"] diff --git a/providers/merge-gateway/models/google/gemini-3.1-pro-preview.toml b/providers/merge-gateway/models/google/gemini-3.1-pro-preview.toml index e2b3bf54f8..7c4de40066 100644 --- a/providers/merge-gateway/models/google/gemini-3.1-pro-preview.toml +++ b/providers/merge-gateway/models/google/gemini-3.1-pro-preview.toml @@ -1,5 +1,8 @@ base_model = "google/gemini-3.1-pro-preview" -reasoning_options = [{ type = "effort", values = ["low", "medium", "high"] }] + +[[reasoning_options]] +type = "effort" +values = ["low", "medium", "high"] [cost] input = 2 @@ -11,3 +14,6 @@ tier = { type = "context", size = 200_000 } input = 4 output = 18 cache_read = 0.4 + +[modalities] +input = ["text", "image", "audio", "pdf"] diff --git a/providers/merge-gateway/models/google/gemini-3.5-flash.toml b/providers/merge-gateway/models/google/gemini-3.5-flash.toml index 0d75d4a0d3..ef2d78e676 100644 --- a/providers/merge-gateway/models/google/gemini-3.5-flash.toml +++ b/providers/merge-gateway/models/google/gemini-3.5-flash.toml @@ -1,8 +1,14 @@ base_model = "google/gemini-3.5-flash" -reasoning_options = [{ type = "effort", values = ["minimal", "low", "medium", "high"] }] + +[[reasoning_options]] +type = "effort" +values = ["minimal", "low", "medium", "high"] [cost] input = 1.5 output = 9 cache_read = 0.15 input_audio = 1.5 + +[modalities] +input = ["text", "image", "audio", "pdf"] diff --git a/providers/merge-gateway/models/google/gemma-4-26b-a4b-it.toml b/providers/merge-gateway/models/google/gemma-4-26b-a4b-it.toml index a2c94934dc..a776b41646 100644 --- a/providers/merge-gateway/models/google/gemma-4-26b-a4b-it.toml +++ b/providers/merge-gateway/models/google/gemma-4-26b-a4b-it.toml @@ -1,2 +1,17 @@ base_model = "google/gemma-4-26b-a4b-it" -reasoning_options = [{ type = "toggle" }] +attachment = false +tool_call = false +structured_output = false + +[[reasoning_options]] +type = "toggle" + +[cost] +input = 0.13 +output = 0.4 + +[limit] +output = 65_536 + +[modalities] +input = ["text"] diff --git a/providers/merge-gateway/models/google/gemma-4-31b-it.toml b/providers/merge-gateway/models/google/gemma-4-31b-it.toml index 396158e520..fda08e4f1e 100644 --- a/providers/merge-gateway/models/google/gemma-4-31b-it.toml +++ b/providers/merge-gateway/models/google/gemma-4-31b-it.toml @@ -1,2 +1,17 @@ base_model = "google/gemma-4-31b-it" -reasoning_options = [{ type = "toggle" }] +attachment = false +tool_call = false +structured_output = false + +[[reasoning_options]] +type = "toggle" + +[cost] +input = 0.14 +output = 0.4 + +[limit] +output = 65_536 + +[modalities] +input = ["text"] diff --git a/providers/merge-gateway/models/meta/llama-3.3-70b-instruct.toml b/providers/merge-gateway/models/meta/llama-3.3-70b-instruct.toml new file mode 100644 index 0000000000..152e720938 --- /dev/null +++ b/providers/merge-gateway/models/meta/llama-3.3-70b-instruct.toml @@ -0,0 +1,7 @@ +base_model = "meta/llama-3.3-70b-instruct" +attachment = false +structured_output = false + +[cost] +input = 0.72 +output = 0.72 diff --git a/providers/merge-gateway/models/meta/muse-spark-1.1.toml b/providers/merge-gateway/models/meta/muse-spark-1.1.toml new file mode 100644 index 0000000000..d49ae48665 --- /dev/null +++ b/providers/merge-gateway/models/meta/muse-spark-1.1.toml @@ -0,0 +1,14 @@ +base_model = "meta/muse-spark-1.1" +structured_output = false +reasoning_options = [] + +[cost] +input = 1.25 +output = 4.25 + +[limit] +context = 1_048_576 +output = 262_144 + +[modalities] +input = ["text", "image"] diff --git a/providers/merge-gateway/models/minimax/minimax-m2.1.toml b/providers/merge-gateway/models/minimax/minimax-m2.1.toml index 124cf20365..0a6d4752dc 100644 --- a/providers/merge-gateway/models/minimax/minimax-m2.1.toml +++ b/providers/merge-gateway/models/minimax/minimax-m2.1.toml @@ -1,6 +1,13 @@ base_model = "minimax/MiniMax-M2.1" +name = "MiniMax M2.1" +structured_output = false reasoning_options = [] [cost] input = 0.3 output = 1.2 +cache_read = 0.03 +cache_write = 0.375 + +[limit] +output = 8_192 diff --git a/providers/merge-gateway/models/minimax/minimax-m2.5-highspeed.toml b/providers/merge-gateway/models/minimax/minimax-m2.5-highspeed.toml index d3be98c0fa..f37846f4fd 100644 --- a/providers/merge-gateway/models/minimax/minimax-m2.5-highspeed.toml +++ b/providers/merge-gateway/models/minimax/minimax-m2.5-highspeed.toml @@ -1,4 +1,6 @@ base_model = "minimax/MiniMax-M2.5-highspeed" +name = "MiniMax M2.5 Highspeed" +structured_output = false reasoning_options = [] [cost] @@ -6,3 +8,6 @@ input = 0.6 output = 2.4 cache_read = 0.06 cache_write = 0.375 + +[limit] +output = 8_192 diff --git a/providers/merge-gateway/models/minimax/minimax-m2.5.toml b/providers/merge-gateway/models/minimax/minimax-m2.5.toml index b884c3c158..f8b037d4b2 100644 --- a/providers/merge-gateway/models/minimax/minimax-m2.5.toml +++ b/providers/merge-gateway/models/minimax/minimax-m2.5.toml @@ -1,4 +1,6 @@ base_model = "minimax/MiniMax-M2.5" +name = "MiniMax M2.5" +structured_output = false reasoning_options = [] [cost] @@ -6,3 +8,6 @@ input = 0.3 output = 1.2 cache_read = 0.03 cache_write = 0.375 + +[limit] +output = 8_192 diff --git a/providers/merge-gateway/models/minimax/minimax-m2.7-highspeed.toml b/providers/merge-gateway/models/minimax/minimax-m2.7-highspeed.toml index 1539589db9..4212380399 100644 --- a/providers/merge-gateway/models/minimax/minimax-m2.7-highspeed.toml +++ b/providers/merge-gateway/models/minimax/minimax-m2.7-highspeed.toml @@ -1,4 +1,6 @@ base_model = "minimax/MiniMax-M2.7-highspeed" +name = "MiniMax M2.7 Highspeed" +structured_output = false reasoning_options = [] [cost] @@ -6,3 +8,6 @@ input = 0.6 output = 2.4 cache_read = 0.06 cache_write = 0.375 + +[limit] +output = 8_192 diff --git a/providers/merge-gateway/models/minimax/minimax-m2.7.toml b/providers/merge-gateway/models/minimax/minimax-m2.7.toml index d02224d535..287dd2e59c 100644 --- a/providers/merge-gateway/models/minimax/minimax-m2.7.toml +++ b/providers/merge-gateway/models/minimax/minimax-m2.7.toml @@ -1,4 +1,6 @@ base_model = "minimax/MiniMax-M2.7" +name = "MiniMax M2.7" +structured_output = false reasoning_options = [] [cost] @@ -6,3 +8,6 @@ input = 0.3 output = 1.2 cache_read = 0.06 cache_write = 0.375 + +[limit] +output = 8_192 diff --git a/providers/merge-gateway/models/minimax/minimax-m2.toml b/providers/merge-gateway/models/minimax/minimax-m2.toml index dd2a899f2a..b4aba3d972 100644 --- a/providers/merge-gateway/models/minimax/minimax-m2.toml +++ b/providers/merge-gateway/models/minimax/minimax-m2.toml @@ -1,6 +1,13 @@ base_model = "minimax/MiniMax-M2" +structured_output = false reasoning_options = [] [cost] input = 0.3 output = 1.2 +cache_read = 0.03 +cache_write = 0.375 + +[limit] +context = 204_800 +output = 8_192 diff --git a/providers/merge-gateway/models/minimax/minimax-m3.toml b/providers/merge-gateway/models/minimax/minimax-m3.toml index bb651110ea..db8f8f5f02 100644 --- a/providers/merge-gateway/models/minimax/minimax-m3.toml +++ b/providers/merge-gateway/models/minimax/minimax-m3.toml @@ -1,4 +1,6 @@ base_model = "minimax/MiniMax-M3" +name = "MiniMax M3" +structured_output = false [[reasoning_options]] type = "toggle" @@ -9,5 +11,12 @@ min = 1 max = 128_000 [cost] -input = 0.6 -output = 2.4 +input = 0.3 +output = 1.2 +cache_read = 0.06 + +[limit] +context = 1_000_000 + +[modalities] +input = ["text", "image"] diff --git a/providers/merge-gateway/models/mistral/devstral-2512.toml b/providers/merge-gateway/models/mistral/devstral-2512.toml index a42bb7446c..5be5751c96 100644 --- a/providers/merge-gateway/models/mistral/devstral-2512.toml +++ b/providers/merge-gateway/models/mistral/devstral-2512.toml @@ -1,6 +1,10 @@ base_model = "mistral/devstral-2512" -status = "deprecated" +structured_output = true [cost] input = 0.4 output = 2 + +[limit] +context = 256_000 +output = 256_000 diff --git a/providers/merge-gateway/models/mistral/mistral-large-2512.toml b/providers/merge-gateway/models/mistral/mistral-large-2512.toml index 49df75a634..98e5a5fac0 100644 --- a/providers/merge-gateway/models/mistral/mistral-large-2512.toml +++ b/providers/merge-gateway/models/mistral/mistral-large-2512.toml @@ -1,5 +1,10 @@ base_model = "mistral/mistral-large-2512" +structured_output = true [cost] input = 0.5 output = 1.5 + +[limit] +context = 256_000 +output = 256_000 diff --git a/providers/merge-gateway/models/mistral/mistral-medium-2505.toml b/providers/merge-gateway/models/mistral/mistral-medium-2505.toml index 24ec3b4fa5..6816500cc2 100644 --- a/providers/merge-gateway/models/mistral/mistral-medium-2505.toml +++ b/providers/merge-gateway/models/mistral/mistral-medium-2505.toml @@ -1,5 +1,10 @@ base_model = "mistral/mistral-medium-2505" +structured_output = true [cost] input = 0.4 output = 2 + +[limit] +context = 128_000 +output = 128_000 diff --git a/providers/merge-gateway/models/nvidia/nemotron-nano-9b-v2.toml b/providers/merge-gateway/models/nvidia/nemotron-nano-9b-v2.toml new file mode 100644 index 0000000000..a24d7e0cfb --- /dev/null +++ b/providers/merge-gateway/models/nvidia/nemotron-nano-9b-v2.toml @@ -0,0 +1,13 @@ +base_model = "nvidia/nemotron-nano-9b-v2" +name = "Nemotron Nano 9B" +tool_call = false +structured_output = false +reasoning_options = [] + +[cost] +input = 0.06 +output = 0.23 + +[limit] +context = 128_000 +output = 8_192 diff --git a/providers/merge-gateway/models/openai/gpt-3.5-turbo.toml b/providers/merge-gateway/models/openai/gpt-3.5-turbo.toml new file mode 100644 index 0000000000..de8ddba9d0 --- /dev/null +++ b/providers/merge-gateway/models/openai/gpt-3.5-turbo.toml @@ -0,0 +1,6 @@ +base_model = "openai/gpt-3.5-turbo" +name = "GPT-3.5 Turbo" + +[cost] +input = 0.5 +output = 1.5 diff --git a/providers/merge-gateway/models/openai/gpt-4-turbo.toml b/providers/merge-gateway/models/openai/gpt-4-turbo.toml new file mode 100644 index 0000000000..ac792634f8 --- /dev/null +++ b/providers/merge-gateway/models/openai/gpt-4-turbo.toml @@ -0,0 +1,8 @@ +base_model = "openai/gpt-4-turbo" + +[cost] +input = 10 +output = 30 + +[modalities] +input = ["text", "image", "pdf"] diff --git a/providers/merge-gateway/models/openai/gpt-4.1-mini.toml b/providers/merge-gateway/models/openai/gpt-4.1-mini.toml index b2d9217542..a6b4371ba1 100644 --- a/providers/merge-gateway/models/openai/gpt-4.1-mini.toml +++ b/providers/merge-gateway/models/openai/gpt-4.1-mini.toml @@ -1,4 +1,5 @@ base_model = "openai/gpt-4.1-mini" +name = "GPT-4.1 Mini" [cost] input = 0.4 diff --git a/providers/merge-gateway/models/openai/gpt-4.1-nano.toml b/providers/merge-gateway/models/openai/gpt-4.1-nano.toml index f85c094770..5deee39d9b 100644 --- a/providers/merge-gateway/models/openai/gpt-4.1-nano.toml +++ b/providers/merge-gateway/models/openai/gpt-4.1-nano.toml @@ -1,6 +1,10 @@ base_model = "openai/gpt-4.1-nano" +name = "GPT-4.1 Nano" [cost] input = 0.1 output = 0.4 cache_read = 0.025 + +[modalities] +input = ["text", "image", "pdf"] diff --git a/providers/merge-gateway/models/openai/gpt-4.toml b/providers/merge-gateway/models/openai/gpt-4.toml new file mode 100644 index 0000000000..a4363542ed --- /dev/null +++ b/providers/merge-gateway/models/openai/gpt-4.toml @@ -0,0 +1,7 @@ +base_model = "openai/gpt-4" +attachment = false +tool_call = false + +[cost] +input = 30 +output = 60 diff --git a/providers/merge-gateway/models/openai/gpt-4o-2024-05-13.toml b/providers/merge-gateway/models/openai/gpt-4o-2024-05-13.toml index c4a17bbcf7..6f72744fc8 100644 --- a/providers/merge-gateway/models/openai/gpt-4o-2024-05-13.toml +++ b/providers/merge-gateway/models/openai/gpt-4o-2024-05-13.toml @@ -1,5 +1,9 @@ base_model = "openai/gpt-4o-2024-05-13" +structured_output = false [cost] input = 5 output = 15 + +[modalities] +input = ["text", "image", "pdf"] diff --git a/providers/merge-gateway/models/openai/gpt-4o-2024-08-06.toml b/providers/merge-gateway/models/openai/gpt-4o-2024-08-06.toml index 344cd161a7..a02cb635cd 100644 --- a/providers/merge-gateway/models/openai/gpt-4o-2024-08-06.toml +++ b/providers/merge-gateway/models/openai/gpt-4o-2024-08-06.toml @@ -4,3 +4,6 @@ base_model = "openai/gpt-4o-2024-08-06" input = 2.5 output = 10 cache_read = 1.25 + +[modalities] +input = ["text", "image", "pdf"] diff --git a/providers/merge-gateway/models/openai/gpt-4o-2024-11-20.toml b/providers/merge-gateway/models/openai/gpt-4o-2024-11-20.toml index c807afdbe1..2df04ffa70 100644 --- a/providers/merge-gateway/models/openai/gpt-4o-2024-11-20.toml +++ b/providers/merge-gateway/models/openai/gpt-4o-2024-11-20.toml @@ -4,3 +4,6 @@ base_model = "openai/gpt-4o-2024-11-20" input = 2.5 output = 10 cache_read = 1.25 + +[modalities] +input = ["text", "image", "pdf"] diff --git a/providers/merge-gateway/models/openai/gpt-4o-mini.toml b/providers/merge-gateway/models/openai/gpt-4o-mini.toml index da284d5f15..5662c2ceca 100644 --- a/providers/merge-gateway/models/openai/gpt-4o-mini.toml +++ b/providers/merge-gateway/models/openai/gpt-4o-mini.toml @@ -1,4 +1,5 @@ base_model = "openai/gpt-4o-mini" +name = "GPT-4o Mini" [cost] input = 0.15 diff --git a/providers/merge-gateway/models/openai/gpt-5-chat-latest.toml b/providers/merge-gateway/models/openai/gpt-5-chat-latest.toml index 4dd858d1af..4af6a73a45 100644 --- a/providers/merge-gateway/models/openai/gpt-5-chat-latest.toml +++ b/providers/merge-gateway/models/openai/gpt-5-chat-latest.toml @@ -1,7 +1,16 @@ base_model = "openai/gpt-5-chat-latest" +base_model_omit = ["limit.input"] +name = "GPT-5 Chat Latest" reasoning_options = [] [cost] input = 1.25 output = 10 cache_read = 0.125 + +[limit] +context = 128_000 +output = 16_384 + +[modalities] +input = ["text", "image", "pdf"] diff --git a/providers/merge-gateway/models/openai/gpt-5-mini.toml b/providers/merge-gateway/models/openai/gpt-5-mini.toml index 5754d47df3..9ab4f24cca 100644 --- a/providers/merge-gateway/models/openai/gpt-5-mini.toml +++ b/providers/merge-gateway/models/openai/gpt-5-mini.toml @@ -1,7 +1,13 @@ base_model = "openai/gpt-5-mini" -reasoning_options = [{ type = "effort", values = ["minimal", "low", "medium", "high"] }] + +[[reasoning_options]] +type = "effort" +values = ["minimal", "low", "medium", "high"] [cost] input = 0.25 output = 2 cache_read = 0.025 + +[modalities] +input = ["text", "image", "pdf"] diff --git a/providers/merge-gateway/models/openai/gpt-5-nano.toml b/providers/merge-gateway/models/openai/gpt-5-nano.toml index b96eddfd6f..24bc4a0e65 100644 --- a/providers/merge-gateway/models/openai/gpt-5-nano.toml +++ b/providers/merge-gateway/models/openai/gpt-5-nano.toml @@ -1,7 +1,13 @@ base_model = "openai/gpt-5-nano" -reasoning_options = [{ type = "effort", values = ["minimal", "low", "medium", "high"] }] + +[[reasoning_options]] +type = "effort" +values = ["minimal", "low", "medium", "high"] [cost] input = 0.05 output = 0.4 cache_read = 0.005 + +[modalities] +input = ["text", "image", "pdf"] diff --git a/providers/merge-gateway/models/openai/gpt-5.1-chat-latest.toml b/providers/merge-gateway/models/openai/gpt-5.1-chat-latest.toml index 55e1ad4331..d1916353a0 100644 --- a/providers/merge-gateway/models/openai/gpt-5.1-chat-latest.toml +++ b/providers/merge-gateway/models/openai/gpt-5.1-chat-latest.toml @@ -1,7 +1,11 @@ base_model = "openai/gpt-5.1-chat-latest" +name = "GPT-5.1 Chat Latest" reasoning_options = [] [cost] input = 1.25 output = 10 cache_read = 0.125 + +[modalities] +input = ["text", "image", "pdf"] diff --git a/providers/merge-gateway/models/openai/gpt-5.1.toml b/providers/merge-gateway/models/openai/gpt-5.1.toml index 489f83fffc..b1e6e83622 100644 --- a/providers/merge-gateway/models/openai/gpt-5.1.toml +++ b/providers/merge-gateway/models/openai/gpt-5.1.toml @@ -1,7 +1,13 @@ base_model = "openai/gpt-5.1" -reasoning_options = [{ type = "effort", values = ["none", "low", "medium", "high"] }] + +[[reasoning_options]] +type = "effort" +values = ["none", "low", "medium", "high"] [cost] input = 1.25 output = 10 cache_read = 0.125 + +[modalities] +input = ["text", "image", "pdf"] diff --git a/providers/merge-gateway/models/openai/gpt-5.2-chat-latest.toml b/providers/merge-gateway/models/openai/gpt-5.2-chat-latest.toml index bbad0e8faf..c12b1689b0 100644 --- a/providers/merge-gateway/models/openai/gpt-5.2-chat-latest.toml +++ b/providers/merge-gateway/models/openai/gpt-5.2-chat-latest.toml @@ -1,7 +1,11 @@ base_model = "openai/gpt-5.2-chat-latest" +name = "GPT-5.2 Chat Latest" reasoning_options = [] [cost] input = 1.75 output = 14 cache_read = 0.175 + +[modalities] +input = ["text", "image", "pdf"] diff --git a/providers/merge-gateway/models/openai/gpt-5.2.toml b/providers/merge-gateway/models/openai/gpt-5.2.toml index a2a20d0e32..4cbeec6e34 100644 --- a/providers/merge-gateway/models/openai/gpt-5.2.toml +++ b/providers/merge-gateway/models/openai/gpt-5.2.toml @@ -1,7 +1,13 @@ base_model = "openai/gpt-5.2" -reasoning_options = [{ type = "effort", values = ["none", "low", "medium", "high", "xhigh"] }] + +[[reasoning_options]] +type = "effort" +values = ["none", "low", "medium", "high", "xhigh"] [cost] input = 1.75 output = 14 cache_read = 0.175 + +[modalities] +input = ["text", "image", "pdf"] diff --git a/providers/merge-gateway/models/openai/gpt-5.3-chat-latest.toml b/providers/merge-gateway/models/openai/gpt-5.3-chat-latest.toml index 197284ef5f..5d69491b2e 100644 --- a/providers/merge-gateway/models/openai/gpt-5.3-chat-latest.toml +++ b/providers/merge-gateway/models/openai/gpt-5.3-chat-latest.toml @@ -1,6 +1,10 @@ base_model = "openai/gpt-5.3-chat-latest" +name = "GPT-5.3 Chat Latest" [cost] input = 1.75 output = 14 cache_read = 0.175 + +[modalities] +input = ["text", "image", "pdf"] diff --git a/providers/merge-gateway/models/openai/gpt-5.4-mini.toml b/providers/merge-gateway/models/openai/gpt-5.4-mini.toml index 56a278d15d..913a608765 100644 --- a/providers/merge-gateway/models/openai/gpt-5.4-mini.toml +++ b/providers/merge-gateway/models/openai/gpt-5.4-mini.toml @@ -1,11 +1,18 @@ base_model = "openai/gpt-5.4-mini" -reasoning_options = [{ type = "effort", values = ["none", "low", "medium", "high", "xhigh"] }] +name = "GPT-5.4 Mini" + +[[reasoning_options]] +type = "effort" +values = ["none", "low", "medium", "high", "xhigh"] [cost] input = 0.75 output = 4.5 cache_read = 0.075 +[modalities] +input = ["text", "image", "pdf"] + [experimental.modes.fast] cost = { input = 1.5, output = 9, cache_read = 0.15 } provider = { body = { service_tier = "priority" } } diff --git a/providers/merge-gateway/models/openai/gpt-5.4-nano.toml b/providers/merge-gateway/models/openai/gpt-5.4-nano.toml index 3872b109a2..cd1ef0c661 100644 --- a/providers/merge-gateway/models/openai/gpt-5.4-nano.toml +++ b/providers/merge-gateway/models/openai/gpt-5.4-nano.toml @@ -1,7 +1,14 @@ base_model = "openai/gpt-5.4-nano" -reasoning_options = [{ type = "effort", values = ["none", "low", "medium", "high", "xhigh"] }] +name = "GPT-5.4 Nano" + +[[reasoning_options]] +type = "effort" +values = ["none", "low", "medium", "high", "xhigh"] [cost] input = 0.2 output = 1.25 cache_read = 0.02 + +[modalities] +input = ["text", "image", "pdf"] diff --git a/providers/merge-gateway/models/openai/gpt-5.6-luna.toml b/providers/merge-gateway/models/openai/gpt-5.6-luna.toml new file mode 100644 index 0000000000..409d016fa2 --- /dev/null +++ b/providers/merge-gateway/models/openai/gpt-5.6-luna.toml @@ -0,0 +1,7 @@ +base_model = "openai/gpt-5.6-luna" +reasoning_options = [] + +[cost] +input = 0.75 +output = 4.5 +cache_read = 0.075 diff --git a/providers/merge-gateway/models/openai/gpt-5.6-sol.toml b/providers/merge-gateway/models/openai/gpt-5.6-sol.toml new file mode 100644 index 0000000000..de3ff8acd3 --- /dev/null +++ b/providers/merge-gateway/models/openai/gpt-5.6-sol.toml @@ -0,0 +1,12 @@ +# Merge Gateway catalog: GET https://api-gateway.merge.dev/v1/models +# Reasoning controls: https://openai.com/index/gpt-5-6/ (accessed 2026-07-13) +base_model = "openai/gpt-5.6-sol" + +[[reasoning_options]] +type = "effort" +values = ["none", "low", "medium", "high", "xhigh", "max"] + +[cost] +input = 3.75 +output = 22.5 +cache_read = 0.375 diff --git a/providers/merge-gateway/models/openai/gpt-5.6-terra.toml b/providers/merge-gateway/models/openai/gpt-5.6-terra.toml new file mode 100644 index 0000000000..ca94a4583c --- /dev/null +++ b/providers/merge-gateway/models/openai/gpt-5.6-terra.toml @@ -0,0 +1,7 @@ +base_model = "openai/gpt-5.6-terra" +reasoning_options = [] + +[cost] +input = 1.875 +output = 11.25 +cache_read = 0.1875 diff --git a/providers/merge-gateway/models/openai/gpt-5.toml b/providers/merge-gateway/models/openai/gpt-5.toml index 104575502b..562d91dcdb 100644 --- a/providers/merge-gateway/models/openai/gpt-5.toml +++ b/providers/merge-gateway/models/openai/gpt-5.toml @@ -1,7 +1,13 @@ base_model = "openai/gpt-5" -reasoning_options = [{ type = "effort", values = ["minimal", "low", "medium", "high"] }] + +[[reasoning_options]] +type = "effort" +values = ["minimal", "low", "medium", "high"] [cost] input = 1.25 output = 10 cache_read = 0.125 + +[modalities] +input = ["text", "image", "pdf"] diff --git a/providers/merge-gateway/models/openai/gpt-oss-120b.toml b/providers/merge-gateway/models/openai/gpt-oss-120b.toml new file mode 100644 index 0000000000..f6ea8e4325 --- /dev/null +++ b/providers/merge-gateway/models/openai/gpt-oss-120b.toml @@ -0,0 +1,12 @@ +base_model = "openai/gpt-oss-120b" +tool_call = false +structured_output = false +reasoning_options = [] + +[cost] +input = 0.1 +output = 0.5 + +[limit] +context = 128_000 +output = 32_000 diff --git a/providers/merge-gateway/models/openai/gpt-oss-20b.toml b/providers/merge-gateway/models/openai/gpt-oss-20b.toml new file mode 100644 index 0000000000..6619d5300c --- /dev/null +++ b/providers/merge-gateway/models/openai/gpt-oss-20b.toml @@ -0,0 +1,10 @@ +base_model = "openai/gpt-oss-20b" +reasoning_options = [] + +[cost] +input = 0.07 +output = 0.3 + +[limit] +context = 128_000 +output = 128_000 diff --git a/providers/merge-gateway/models/openai/o3-mini.toml b/providers/merge-gateway/models/openai/o3-mini.toml index 716e4b6e1a..8e81e03022 100644 --- a/providers/merge-gateway/models/openai/o3-mini.toml +++ b/providers/merge-gateway/models/openai/o3-mini.toml @@ -1,5 +1,9 @@ base_model = "openai/o3-mini" -reasoning_options = [{ type = "effort", values = ["low", "medium", "high"] }] +name = "o3 Mini" + +[[reasoning_options]] +type = "effort" +values = ["low", "medium", "high"] [cost] input = 1.1 diff --git a/providers/merge-gateway/models/openai/o4-mini.toml b/providers/merge-gateway/models/openai/o4-mini.toml index 0ff60822de..e234a45f67 100644 --- a/providers/merge-gateway/models/openai/o4-mini.toml +++ b/providers/merge-gateway/models/openai/o4-mini.toml @@ -1,7 +1,11 @@ base_model = "openai/o4-mini" +name = "o4 Mini" reasoning_options = [] [cost] input = 1.1 output = 4.4 cache_read = 0.275 + +[modalities] +input = ["text", "image", "pdf"] diff --git a/providers/merge-gateway/models/qwen/qwen-flash.toml b/providers/merge-gateway/models/qwen/qwen-flash.toml new file mode 100644 index 0000000000..9d31fbbca2 --- /dev/null +++ b/providers/merge-gateway/models/qwen/qwen-flash.toml @@ -0,0 +1,11 @@ +base_model = "alibaba/qwen-flash" +tool_call = false +structured_output = false +reasoning_options = [] + +[cost] +input = 0.022 +output = 0.216 + +[limit] +output = 250_000 diff --git a/providers/merge-gateway/models/qwen/qwen-plus.toml b/providers/merge-gateway/models/qwen/qwen-plus.toml new file mode 100644 index 0000000000..eb288e33a6 --- /dev/null +++ b/providers/merge-gateway/models/qwen/qwen-plus.toml @@ -0,0 +1,11 @@ +base_model = "alibaba/qwen-plus" +tool_call = false +structured_output = false +reasoning_options = [] + +[cost] +input = 0.115 +output = 0.287 + +[limit] +output = 250_000 diff --git a/providers/merge-gateway/models/qwen/qwen3-235b-a22b.toml b/providers/merge-gateway/models/qwen/qwen3-235b-a22b.toml new file mode 100644 index 0000000000..0b3cf01e0d --- /dev/null +++ b/providers/merge-gateway/models/qwen/qwen3-235b-a22b.toml @@ -0,0 +1,12 @@ +base_model = "alibaba/qwen3-235b-a22b" +name = "Qwen3 235B A22B" +tool_call = false +structured_output = false +reasoning_options = [] + +[cost] +input = 0.287 +output = 1.147 + +[limit] +output = 32_768 diff --git a/providers/merge-gateway/models/qwen/qwen3-32b.toml b/providers/merge-gateway/models/qwen/qwen3-32b.toml new file mode 100644 index 0000000000..6799a8b98c --- /dev/null +++ b/providers/merge-gateway/models/qwen/qwen3-32b.toml @@ -0,0 +1,11 @@ +base_model = "alibaba/qwen3-32b" +tool_call = false +structured_output = false +reasoning_options = [] + +[cost] +input = 0.287 +output = 0.64 + +[limit] +output = 32_768 diff --git a/providers/merge-gateway/models/qwen/qwen3-coder-480b-a35b-instruct.toml b/providers/merge-gateway/models/qwen/qwen3-coder-480b-a35b-instruct.toml new file mode 100644 index 0000000000..2d2b7fe1ae --- /dev/null +++ b/providers/merge-gateway/models/qwen/qwen3-coder-480b-a35b-instruct.toml @@ -0,0 +1,11 @@ +base_model = "alibaba/qwen3-coder-480b-a35b-instruct" +tool_call = false +structured_output = false + +[cost] +input = 0.22 +output = 1.8 + +[limit] +context = 131_072 +output = 32_768 diff --git a/providers/merge-gateway/models/qwen/qwen3-coder-flash.toml b/providers/merge-gateway/models/qwen/qwen3-coder-flash.toml new file mode 100644 index 0000000000..171d33583d --- /dev/null +++ b/providers/merge-gateway/models/qwen/qwen3-coder-flash.toml @@ -0,0 +1,10 @@ +base_model = "alibaba/qwen3-coder-flash" +tool_call = false +structured_output = false + +[cost] +input = 0.144 +output = 0.574 + +[limit] +output = 250_000 diff --git a/providers/merge-gateway/models/qwen/qwen3-coder-plus.toml b/providers/merge-gateway/models/qwen/qwen3-coder-plus.toml new file mode 100644 index 0000000000..1a22f4698c --- /dev/null +++ b/providers/merge-gateway/models/qwen/qwen3-coder-plus.toml @@ -0,0 +1,11 @@ +base_model = "alibaba/qwen3-coder-plus" +tool_call = false +structured_output = false + +[cost] +input = 0.574 +output = 2.294 + +[limit] +context = 1_000_000 +output = 250_000 diff --git a/providers/merge-gateway/models/qwen/qwen3-max.toml b/providers/merge-gateway/models/qwen/qwen3-max.toml new file mode 100644 index 0000000000..a91ec8afd2 --- /dev/null +++ b/providers/merge-gateway/models/qwen/qwen3-max.toml @@ -0,0 +1,7 @@ +base_model = "alibaba/qwen3-max" +tool_call = false +structured_output = false + +[cost] +input = 0.359 +output = 1.434 diff --git a/providers/merge-gateway/models/qwen/qwen3-next-80b-a3b-instruct.toml b/providers/merge-gateway/models/qwen/qwen3-next-80b-a3b-instruct.toml new file mode 100644 index 0000000000..f936e5fb71 --- /dev/null +++ b/providers/merge-gateway/models/qwen/qwen3-next-80b-a3b-instruct.toml @@ -0,0 +1,7 @@ +base_model = "alibaba/qwen3-next-80b-a3b-instruct" +tool_call = false +structured_output = false + +[cost] +input = 0.144 +output = 0.574 diff --git a/providers/merge-gateway/models/qwen/qwen3-next-80b-a3b-thinking.toml b/providers/merge-gateway/models/qwen/qwen3-next-80b-a3b-thinking.toml new file mode 100644 index 0000000000..c5805b1218 --- /dev/null +++ b/providers/merge-gateway/models/qwen/qwen3-next-80b-a3b-thinking.toml @@ -0,0 +1,8 @@ +base_model = "alibaba/qwen3-next-80b-a3b-thinking" +tool_call = false +structured_output = false +reasoning_options = [] + +[cost] +input = 0.144 +output = 1.434 diff --git a/providers/merge-gateway/models/qwen/qwen3-vl-plus.toml b/providers/merge-gateway/models/qwen/qwen3-vl-plus.toml new file mode 100644 index 0000000000..62b7809fdb --- /dev/null +++ b/providers/merge-gateway/models/qwen/qwen3-vl-plus.toml @@ -0,0 +1,12 @@ +base_model = "alibaba/qwen3-vl-plus" +attachment = true +tool_call = false +structured_output = false +reasoning_options = [] + +[cost] +input = 0.143 +output = 1.434 + +[limit] +output = 65_536 diff --git a/providers/merge-gateway/models/qwen/qwen3.5-122b-a10b.toml b/providers/merge-gateway/models/qwen/qwen3.5-122b-a10b.toml new file mode 100644 index 0000000000..f6f7beb213 --- /dev/null +++ b/providers/merge-gateway/models/qwen/qwen3.5-122b-a10b.toml @@ -0,0 +1,16 @@ +base_model = "alibaba/qwen3.5-122b-a10b" +attachment = false +tool_call = false +structured_output = false +reasoning_options = [] + +[cost] +input = 0.115 +output = 0.917 + +[limit] +context = 131_072 +output = 32_768 + +[modalities] +input = ["text"] diff --git a/providers/merge-gateway/models/qwen/qwen3.5-27b.toml b/providers/merge-gateway/models/qwen/qwen3.5-27b.toml new file mode 100644 index 0000000000..61838ba5d2 --- /dev/null +++ b/providers/merge-gateway/models/qwen/qwen3.5-27b.toml @@ -0,0 +1,16 @@ +base_model = "alibaba/qwen3.5-27b" +attachment = false +tool_call = false +structured_output = false +reasoning_options = [] + +[cost] +input = 0.086 +output = 0.688 + +[limit] +context = 131_072 +output = 32_768 + +[modalities] +input = ["text"] diff --git a/providers/merge-gateway/models/qwen/qwen3.5-35b-a3b.toml b/providers/merge-gateway/models/qwen/qwen3.5-35b-a3b.toml new file mode 100644 index 0000000000..8a502a1b86 --- /dev/null +++ b/providers/merge-gateway/models/qwen/qwen3.5-35b-a3b.toml @@ -0,0 +1,17 @@ +base_model = "alibaba/qwen3.5-35b-a3b" +name = "Qwen3.5 35B A3B" +attachment = false +tool_call = false +structured_output = false +reasoning_options = [] + +[cost] +input = 0.057 +output = 0.459 + +[limit] +context = 131_072 +output = 32_768 + +[modalities] +input = ["text"] diff --git a/providers/merge-gateway/models/qwen/qwen3.5-397b-a17b.toml b/providers/merge-gateway/models/qwen/qwen3.5-397b-a17b.toml new file mode 100644 index 0000000000..9805d19df5 --- /dev/null +++ b/providers/merge-gateway/models/qwen/qwen3.5-397b-a17b.toml @@ -0,0 +1,17 @@ +base_model = "alibaba/qwen3.5-397b-a17b" +name = "Qwen3.5 397B A17B" +attachment = false +tool_call = false +structured_output = false +reasoning_options = [] + +[cost] +input = 0.172 +output = 1.032 + +[limit] +context = 131_072 +output = 32_768 + +[modalities] +input = ["text"] diff --git a/providers/merge-gateway/models/qwen/qwen3.5-9b.toml b/providers/merge-gateway/models/qwen/qwen3.5-9b.toml new file mode 100644 index 0000000000..2b4e2a3935 --- /dev/null +++ b/providers/merge-gateway/models/qwen/qwen3.5-9b.toml @@ -0,0 +1,14 @@ +base_model = "alibaba/qwen3.5-9b" +attachment = true +structured_output = false +reasoning_options = [] + +[cost] +input = 0.09 +output = 0.13 + +[limit] +output = 32_768 + +[modalities] +input = ["text", "image"] diff --git a/providers/merge-gateway/models/qwen/qwen3.5-plus.toml b/providers/merge-gateway/models/qwen/qwen3.5-plus.toml new file mode 100644 index 0000000000..8379f126f0 --- /dev/null +++ b/providers/merge-gateway/models/qwen/qwen3.5-plus.toml @@ -0,0 +1,14 @@ +base_model = "alibaba/qwen3.5-plus" +tool_call = false +structured_output = false +reasoning_options = [] + +[cost] +input = 0.115 +output = 0.688 + +[limit] +output = 250_000 + +[modalities] +input = ["text"] diff --git a/providers/merge-gateway/models/qwen/qwen3.6-27b.toml b/providers/merge-gateway/models/qwen/qwen3.6-27b.toml new file mode 100644 index 0000000000..9815022446 --- /dev/null +++ b/providers/merge-gateway/models/qwen/qwen3.6-27b.toml @@ -0,0 +1,15 @@ +base_model = "alibaba/qwen3.6-27b" +tool_call = false +structured_output = false +reasoning_options = [] + +[cost] +input = 0.4126 +output = 2.4754 + +[limit] +context = 256_000 +output = 64_000 + +[modalities] +input = ["text", "image"] diff --git a/providers/merge-gateway/models/qwen/qwen3.6-35b-a3b.toml b/providers/merge-gateway/models/qwen/qwen3.6-35b-a3b.toml new file mode 100644 index 0000000000..57394e6fad --- /dev/null +++ b/providers/merge-gateway/models/qwen/qwen3.6-35b-a3b.toml @@ -0,0 +1,13 @@ +base_model = "alibaba/qwen3.6-35b-a3b" +name = "Qwen3.6 35B A3B" +attachment = false +tool_call = false +structured_output = false +reasoning_options = [] + +[cost] +input = 0.248 +output = 1.485 + +[modalities] +input = ["text"] diff --git a/providers/merge-gateway/models/qwen/qwen3.6-flash.toml b/providers/merge-gateway/models/qwen/qwen3.6-flash.toml new file mode 100644 index 0000000000..b10df25cf3 --- /dev/null +++ b/providers/merge-gateway/models/qwen/qwen3.6-flash.toml @@ -0,0 +1,15 @@ +base_model = "alibaba/qwen3.6-flash" +attachment = false +tool_call = false +structured_output = false +reasoning_options = [] + +[cost] +input = 0.165 +output = 0.99 + +[limit] +output = 250_000 + +[modalities] +input = ["text"] diff --git a/providers/merge-gateway/models/qwen/qwen3.6-max-preview.toml b/providers/merge-gateway/models/qwen/qwen3.6-max-preview.toml new file mode 100644 index 0000000000..f2f9c11d1b --- /dev/null +++ b/providers/merge-gateway/models/qwen/qwen3.6-max-preview.toml @@ -0,0 +1,11 @@ +base_model = "alibaba/qwen3.6-max-preview" +tool_call = false +structured_output = false +reasoning_options = [] + +[cost] +input = 1.31 +output = 7.88 + +[limit] +context = 256_000 diff --git a/providers/merge-gateway/models/qwen/qwen3.6-plus.toml b/providers/merge-gateway/models/qwen/qwen3.6-plus.toml new file mode 100644 index 0000000000..a45e5743cf --- /dev/null +++ b/providers/merge-gateway/models/qwen/qwen3.6-plus.toml @@ -0,0 +1,14 @@ +base_model = "alibaba/qwen3.6-plus" +tool_call = false +structured_output = false +reasoning_options = [] + +[cost] +input = 0.276 +output = 1.651 + +[limit] +output = 250_000 + +[modalities] +input = ["text"] diff --git a/providers/merge-gateway/models/qwen/qwen3.7-max.toml b/providers/merge-gateway/models/qwen/qwen3.7-max.toml new file mode 100644 index 0000000000..b4ef76d4d8 --- /dev/null +++ b/providers/merge-gateway/models/qwen/qwen3.7-max.toml @@ -0,0 +1,11 @@ +base_model = "alibaba/qwen3.7-max" +tool_call = false +structured_output = false +reasoning_options = [] + +[cost] +input = 0.825 +output = 2.4755 + +[limit] +output = 250_000 diff --git a/providers/merge-gateway/models/qwen/qwen3.7-plus.toml b/providers/merge-gateway/models/qwen/qwen3.7-plus.toml new file mode 100644 index 0000000000..df3d175dc8 --- /dev/null +++ b/providers/merge-gateway/models/qwen/qwen3.7-plus.toml @@ -0,0 +1,12 @@ +base_model = "alibaba/qwen3.7-plus" +attachment = true +tool_call = false +structured_output = false +reasoning_options = [] + +[cost] +input = 0.4 +output = 1.6 + +[limit] +output = 65_536 diff --git a/providers/merge-gateway/models/xai/grok-4.20-0309-non-reasoning.toml b/providers/merge-gateway/models/xai/grok-4.20-0309-non-reasoning.toml new file mode 100644 index 0000000000..e803774686 --- /dev/null +++ b/providers/merge-gateway/models/xai/grok-4.20-0309-non-reasoning.toml @@ -0,0 +1,13 @@ +base_model = "xai/grok-4.20-0309-non-reasoning" +name = "Grok 4.20 Non-Reasoning" + +[cost] +input = 1.25 +output = 2.5 +cache_read = 0.2 + +[limit] +output = 1_000_000 + +[modalities] +input = ["text", "image"] diff --git a/providers/merge-gateway/models/xai/grok-4.20-0309-reasoning.toml b/providers/merge-gateway/models/xai/grok-4.20-0309-reasoning.toml index cfff36e939..eef910f466 100644 --- a/providers/merge-gateway/models/xai/grok-4.20-0309-reasoning.toml +++ b/providers/merge-gateway/models/xai/grok-4.20-0309-reasoning.toml @@ -1,4 +1,5 @@ base_model = "xai/grok-4.20-0309-reasoning" +name = "Grok 4.20" reasoning_options = [] [cost] @@ -11,3 +12,9 @@ tier = { type = "context", size = 200_000 } input = 2.5 output = 5 cache_read = 0.4 + +[limit] +output = 1_000_000 + +[modalities] +input = ["text", "image"] diff --git a/providers/merge-gateway/models/xai/grok-4.3.toml b/providers/merge-gateway/models/xai/grok-4.3.toml index faeaba94b5..cc89c88330 100644 --- a/providers/merge-gateway/models/xai/grok-4.3.toml +++ b/providers/merge-gateway/models/xai/grok-4.3.toml @@ -11,3 +11,9 @@ tier = { type = "context", size = 200_000 } input = 2.5 output = 5 cache_read = 0.4 + +[limit] +output = 1_000_000 + +[modalities] +input = ["text", "image"] diff --git a/providers/merge-gateway/models/xai/grok-4.5.toml b/providers/merge-gateway/models/xai/grok-4.5.toml new file mode 100644 index 0000000000..9179571704 --- /dev/null +++ b/providers/merge-gateway/models/xai/grok-4.5.toml @@ -0,0 +1,7 @@ +base_model = "xai/grok-4.5" +reasoning_options = [] + +[cost] +input = 2 +output = 6 +cache_read = 0.5 diff --git a/providers/merge-gateway/models/xai/grok-build-0.1.toml b/providers/merge-gateway/models/xai/grok-build-0.1.toml new file mode 100644 index 0000000000..2cd89e9a80 --- /dev/null +++ b/providers/merge-gateway/models/xai/grok-build-0.1.toml @@ -0,0 +1,10 @@ +base_model = "xai/grok-build-0.1" +reasoning_options = [] + +[cost] +input = 1 +output = 2 +cache_read = 0.2 + +[modalities] +input = ["text", "image"] diff --git a/providers/merge-gateway/models/zai/glm-4.5-air.toml b/providers/merge-gateway/models/zai/glm-4.5-air.toml index 2c9bfb4c1e..fb0ad87b7f 100644 --- a/providers/merge-gateway/models/zai/glm-4.5-air.toml +++ b/providers/merge-gateway/models/zai/glm-4.5-air.toml @@ -1,8 +1,15 @@ base_model = "zhipuai/glm-4.5-air" -reasoning_options = [{ type = "toggle" }] +name = "GLM-4.5 Air" +structured_output = false + +[[reasoning_options]] +type = "toggle" [cost] input = 0.2 output = 1.1 cache_read = 0.03 cache_write = 0 + +[limit] +context = 128_000 diff --git a/providers/merge-gateway/models/zai/glm-4.5.toml b/providers/merge-gateway/models/zai/glm-4.5.toml index d859695015..4286567606 100644 --- a/providers/merge-gateway/models/zai/glm-4.5.toml +++ b/providers/merge-gateway/models/zai/glm-4.5.toml @@ -1,8 +1,14 @@ base_model = "zhipuai/glm-4.5" -reasoning_options = [{ type = "toggle" }] +structured_output = false + +[[reasoning_options]] +type = "toggle" [cost] input = 0.6 output = 2.2 cache_read = 0.11 cache_write = 0 + +[limit] +context = 128_000 diff --git a/providers/merge-gateway/models/zai/glm-4.5v.toml b/providers/merge-gateway/models/zai/glm-4.5v.toml new file mode 100644 index 0000000000..167cbe1dac --- /dev/null +++ b/providers/merge-gateway/models/zai/glm-4.5v.toml @@ -0,0 +1,17 @@ +base_model = "zhipuai/glm-4.5v" +name = "Glm 4.5V" +structured_output = false +reasoning_options = [] + +[cost] +input = 0.6 +output = 1.8 +cache_read = 0.11 +cache_write = 0 + +[limit] +context = 128_000 +output = 32_000 + +[modalities] +input = ["text", "image"] diff --git a/providers/merge-gateway/models/zai/glm-4.6.toml b/providers/merge-gateway/models/zai/glm-4.6.toml index 1e32db1892..9b43877924 100644 --- a/providers/merge-gateway/models/zai/glm-4.6.toml +++ b/providers/merge-gateway/models/zai/glm-4.6.toml @@ -1,8 +1,14 @@ base_model = "zhipuai/glm-4.6" -reasoning_options = [{ type = "toggle" }] +structured_output = false + +[[reasoning_options]] +type = "toggle" [cost] input = 0.6 output = 2.2 cache_read = 0.11 cache_write = 0 + +[limit] +context = 200_000 diff --git a/providers/merge-gateway/models/zai/glm-4.7-flash.toml b/providers/merge-gateway/models/zai/glm-4.7-flash.toml new file mode 100644 index 0000000000..85c174b267 --- /dev/null +++ b/providers/merge-gateway/models/zai/glm-4.7-flash.toml @@ -0,0 +1,11 @@ +base_model = "zhipuai/glm-4.7-flash" +name = "GLM 4.7 Flash" +structured_output = false +reasoning_options = [] + +[cost] +input = 0.07 +output = 0.4 + +[limit] +output = 128_000 diff --git a/providers/merge-gateway/models/zai/glm-4.7-flashx.toml b/providers/merge-gateway/models/zai/glm-4.7-flashx.toml index 2ff24442cd..66e530d1d4 100644 --- a/providers/merge-gateway/models/zai/glm-4.7-flashx.toml +++ b/providers/merge-gateway/models/zai/glm-4.7-flashx.toml @@ -1,5 +1,9 @@ base_model = "zhipuai/glm-4.7-flashx" -reasoning_options = [{ type = "toggle" }] +name = "GLM-4.7 FlashX" +structured_output = false + +[[reasoning_options]] +type = "toggle" [cost] input = 0.07 diff --git a/providers/merge-gateway/models/zai/glm-4.7.toml b/providers/merge-gateway/models/zai/glm-4.7.toml index aaa77ab373..2645ef55ee 100644 --- a/providers/merge-gateway/models/zai/glm-4.7.toml +++ b/providers/merge-gateway/models/zai/glm-4.7.toml @@ -1,11 +1,17 @@ base_model = "zhipuai/glm-4.7" -reasoning_options = [{ type = "toggle" }] +structured_output = false [interleaved] field = "reasoning_content" +[[reasoning_options]] +type = "toggle" + [cost] input = 0.6 output = 2.2 cache_read = 0.11 cache_write = 0 + +[limit] +context = 200_000 diff --git a/providers/merge-gateway/models/zai/glm-5-turbo.toml b/providers/merge-gateway/models/zai/glm-5-turbo.toml index 685d533ed3..e0f648c6bb 100644 --- a/providers/merge-gateway/models/zai/glm-5-turbo.toml +++ b/providers/merge-gateway/models/zai/glm-5-turbo.toml @@ -1,9 +1,13 @@ base_model = "zhipuai/glm-5-turbo" -reasoning_options = [{ type = "toggle" }] +name = "GLM-5 Turbo" +structured_output = false [interleaved] field = "reasoning_content" +[[reasoning_options]] +type = "toggle" + [cost] input = 1.2 output = 4 diff --git a/providers/merge-gateway/models/zai/glm-5.1.toml b/providers/merge-gateway/models/zai/glm-5.1.toml index f359f73972..324ad86f62 100644 --- a/providers/merge-gateway/models/zai/glm-5.1.toml +++ b/providers/merge-gateway/models/zai/glm-5.1.toml @@ -1,9 +1,12 @@ base_model = "zhipuai/glm-5.1" -reasoning_options = [{ type = "toggle" }] +structured_output = false [interleaved] field = "reasoning_content" +[[reasoning_options]] +type = "toggle" + [cost] input = 1.4 output = 4.4 diff --git a/providers/merge-gateway/models/zai/glm-5.2.toml b/providers/merge-gateway/models/zai/glm-5.2.toml index 97a7dd870f..32140e8772 100644 --- a/providers/merge-gateway/models/zai/glm-5.2.toml +++ b/providers/merge-gateway/models/zai/glm-5.2.toml @@ -1,4 +1,8 @@ base_model = "zhipuai/glm-5.2" +structured_output = false + +[interleaved] +field = "reasoning_content" [[reasoning_options]] type = "toggle" @@ -8,9 +12,6 @@ type = "budget_tokens" min = 1 max = 50_000 -[interleaved] -field = "reasoning_content" - [cost] -input = 1.4 -output = 4.4 +input = 1.05 +output = 3.3 diff --git a/providers/merge-gateway/models/zai/glm-5.toml b/providers/merge-gateway/models/zai/glm-5.toml index f56566e0a6..0daa2719a0 100644 --- a/providers/merge-gateway/models/zai/glm-5.toml +++ b/providers/merge-gateway/models/zai/glm-5.toml @@ -1,11 +1,17 @@ base_model = "zhipuai/glm-5" -reasoning_options = [{ type = "toggle" }] +structured_output = false [interleaved] field = "reasoning_content" +[[reasoning_options]] +type = "toggle" + [cost] input = 1 output = 3.2 cache_read = 0.2 cache_write = 0 + +[limit] +context = 200_000 diff --git a/sync.md b/sync.md index 1f538b3640..0819c732ca 100644 --- a/sync.md +++ b/sync.md @@ -17,6 +17,7 @@ The grouped sync targets are available for local convenience, but CI syncs each - `bun models:sync digitalocean` syncs only DigitalOcean. - `bun models:sync xai` syncs only xAI. - `bun models:sync kilo` syncs only Kilo. +- `bun models:sync merge-gateway` syncs only Merge Gateway. - `bun models:sync openai` syncs only OpenAI catalog availability. - `bun models:sync aggregators --dry-run` prints changes without writing model files. - `bun models:sync aggregators --new-only` creates new model files but skips updates and removals. @@ -139,6 +140,19 @@ Kilo Gateway is implemented in `packages/core/src/sync/providers/kilo.ts`. - Canonical Kilo model IDs should emit `base_model` references to model metadata when a matching `models/` entry exists. - `reasoning_options` is derived from `opencode.variants` when present. +## Merge Gateway Notes + +Merge Gateway is implemented in `packages/core/src/sync/providers/merge-gateway.ts`. + +- Source endpoint: `https://api-gateway.merge.dev/v1/models`. +- Required auth: `MERGE_GATEWAY_API_KEY`. +- The sync follows `next_cursor` until every page has been fetched. +- The canonical provider's available vendor route supplies pricing, limits, and capabilities; another available vendor is used only when the canonical route is unavailable. +- Canonical model IDs emit `base_model` references to model metadata when a matching `models/` entry exists. +- Existing cache pricing, tiered pricing, reasoning controls, and experimental modes are preserved because the API does not expose them. +- When the API exposes route-level `prompt_caching` or cache pricing fields, those values authoritatively replace preserved cache prices. Cache prices curated before that API support remain in provider TOMLs and survive syncs. +- Local models missing from the response are retained because API-key policy can affect catalog visibility. + ## Cloudflare Workers AI Notes Cloudflare Workers AI is implemented in `packages/core/src/sync/providers/cloudflare-workers-ai.ts`. From 2d91d4583b6aae8c85d52591a5669d69daad887e Mon Sep 17 00:00:00 2001 From: Matthew Feroz Date: Tue, 14 Jul 2026 09:10:09 -0400 Subject: [PATCH 2/4] fix(merge-gateway): document reasoning controls --- .../anthropic/claude-3-7-sonnet-20250219.toml | 5 ++++- .../models/anthropic/claude-fable-5.toml | 3 +++ .../models/anthropic/claude-sonnet-5.toml | 4 +++- .../models/openai/gpt-5.6-luna.toml | 5 ++++- .../models/openai/gpt-5.6-terra.toml | 5 ++++- .../models/openai/gpt-oss-120b.toml | 3 +++ .../models/openai/gpt-oss-20b.toml | 3 +++ providers/merge-gateway/provider.toml | 20 +++++++++---------- 8 files changed, 33 insertions(+), 15 deletions(-) diff --git a/providers/merge-gateway/models/anthropic/claude-3-7-sonnet-20250219.toml b/providers/merge-gateway/models/anthropic/claude-3-7-sonnet-20250219.toml index 8c0263b486..10113cd6f7 100644 --- a/providers/merge-gateway/models/anthropic/claude-3-7-sonnet-20250219.toml +++ b/providers/merge-gateway/models/anthropic/claude-3-7-sonnet-20250219.toml @@ -1,7 +1,10 @@ +# Merge Gateway GET /v1/models?model=anthropic/claude-3-7-sonnet-20250219 +# (accessed 2026-07-14): the Bedrock route advertises configurable +# `thinking.budget_tokens` and disable support. base_model = "anthropic/claude-3-7-sonnet-20250219" name = "Claude 3.7 Sonnet" structured_output = true -reasoning_options = [] +reasoning_options = [{ type = "toggle" }, { type = "budget_tokens", min = 1_024, max = 63_999 }] [cost] input = 3 diff --git a/providers/merge-gateway/models/anthropic/claude-fable-5.toml b/providers/merge-gateway/models/anthropic/claude-fable-5.toml index 747fc86411..f8c3b236b2 100644 --- a/providers/merge-gateway/models/anthropic/claude-fable-5.toml +++ b/providers/merge-gateway/models/anthropic/claude-fable-5.toml @@ -1,3 +1,6 @@ +# Merge Gateway GET /v1/models?model=anthropic/claude-fable-5 (accessed 2026-07-14): +# the only available Anthropic route reports `supports_reasoning = false`, so +# callers have no reasoning control despite the base model being reasoning-capable. base_model = "anthropic/claude-fable-5" structured_output = true reasoning_options = [] diff --git a/providers/merge-gateway/models/anthropic/claude-sonnet-5.toml b/providers/merge-gateway/models/anthropic/claude-sonnet-5.toml index fc8b6671ee..0ef763168d 100644 --- a/providers/merge-gateway/models/anthropic/claude-sonnet-5.toml +++ b/providers/merge-gateway/models/anthropic/claude-sonnet-5.toml @@ -1,6 +1,8 @@ +# Merge Gateway GET /v1/models?model=anthropic/claude-sonnet-5 (accessed 2026-07-14): +# the Anthropic route advertises configurable `reasoning.effort` and disable support. base_model = "anthropic/claude-sonnet-5" structured_output = true -reasoning_options = [] +reasoning_options = [{ type = "toggle" }, { type = "effort", values = ["low", "medium", "high", "xhigh", "max"] }] [cost] input = 2 diff --git a/providers/merge-gateway/models/openai/gpt-5.6-luna.toml b/providers/merge-gateway/models/openai/gpt-5.6-luna.toml index 409d016fa2..37a38e5a9b 100644 --- a/providers/merge-gateway/models/openai/gpt-5.6-luna.toml +++ b/providers/merge-gateway/models/openai/gpt-5.6-luna.toml @@ -1,5 +1,8 @@ +# Merge Gateway GET /v1/models?model=openai/gpt-5.6-luna (accessed 2026-07-14): +# the OpenAI vendor route advertises configurable `reasoning.effort` and disable support. +# Effort values: https://openai.com/index/gpt-5-6/ base_model = "openai/gpt-5.6-luna" -reasoning_options = [] +reasoning_options = [{ type = "effort", values = ["none", "low", "medium", "high", "xhigh", "max"] }] [cost] input = 0.75 diff --git a/providers/merge-gateway/models/openai/gpt-5.6-terra.toml b/providers/merge-gateway/models/openai/gpt-5.6-terra.toml index ca94a4583c..592888015f 100644 --- a/providers/merge-gateway/models/openai/gpt-5.6-terra.toml +++ b/providers/merge-gateway/models/openai/gpt-5.6-terra.toml @@ -1,5 +1,8 @@ +# Merge Gateway GET /v1/models?model=openai/gpt-5.6-terra (accessed 2026-07-14): +# the OpenAI vendor route advertises configurable `reasoning.effort` and disable support. +# Effort values: https://openai.com/index/gpt-5-6/ base_model = "openai/gpt-5.6-terra" -reasoning_options = [] +reasoning_options = [{ type = "effort", values = ["none", "low", "medium", "high", "xhigh", "max"] }] [cost] input = 1.875 diff --git a/providers/merge-gateway/models/openai/gpt-oss-120b.toml b/providers/merge-gateway/models/openai/gpt-oss-120b.toml index f6ea8e4325..3eb069e5a6 100644 --- a/providers/merge-gateway/models/openai/gpt-oss-120b.toml +++ b/providers/merge-gateway/models/openai/gpt-oss-120b.toml @@ -1,3 +1,6 @@ +# Merge Gateway GET /v1/models?model=openai/gpt-oss-120b (accessed 2026-07-14): +# available routes either report `supports_reasoning = false` or reasoning with +# `configurable = false` and no controls, so callers have no reasoning control. base_model = "openai/gpt-oss-120b" tool_call = false structured_output = false diff --git a/providers/merge-gateway/models/openai/gpt-oss-20b.toml b/providers/merge-gateway/models/openai/gpt-oss-20b.toml index 6619d5300c..758d8dc047 100644 --- a/providers/merge-gateway/models/openai/gpt-oss-20b.toml +++ b/providers/merge-gateway/models/openai/gpt-oss-20b.toml @@ -1,3 +1,6 @@ +# Merge Gateway GET /v1/models?model=openai/gpt-oss-20b (accessed 2026-07-14): +# available routes either report `supports_reasoning = false` or reasoning with +# `configurable = false` and no controls, so callers have no reasoning control. base_model = "openai/gpt-oss-20b" reasoning_options = [] diff --git a/providers/merge-gateway/provider.toml b/providers/merge-gateway/provider.toml index 93c78884b5..293c689f4f 100644 --- a/providers/merge-gateway/provider.toml +++ b/providers/merge-gateway/provider.toml @@ -1,20 +1,18 @@ name = "Merge Gateway" env = ["MERGE_GATEWAY_API_KEY"] npm = "merge-gateway-ai-sdk-provider" -# Reasoning request surfaces (sources accessed 2026-06-25): -# - OpenAI compatibility: POST /v1/openai/chat/completions uses the native -# top-level `reasoning_effort`; the documented base accepts OpenAI SDK calls. -# - Anthropic compatibility: POST /v1/anthropic/v1/messages uses native -# `thinking = { type = "enabled"|"disabled", budget_tokens = N }` and -# `output_config.effort`. +# Reasoning request surfaces (sources accessed 2026-07-14): +# - Reasoning support and controls are vendor-route capabilities. Use the exact +# model response from GET /v1/models and inspect +# vendors..capabilities.reasoning; do not infer support solely from a +# compatibility endpoint's request shape. +# https://docs.merge.dev/merge-gateway/features/reasoning +# https://docs.merge.dev/merge-gateway/api-overview/models/list +# - OpenAI and Anthropic compatibility endpoints accept their native request +# shapes when the selected vendor route advertises the corresponding control. # https://docs.merge.dev/merge-gateway/get-started -# https://docs.anthropic.com/en/api/messages # - This npm package calls POST /v1/ai-sdk/chat/completions and maps # `providerOptions.mergeGateway.thinking` to # `thinking = { type = "enabled"|"disabled", budget_tokens = N }`. # https://github.com/merge-api/merge-gateway-ai-sdk-provider/blob/main/src/chat/index.ts -# - Native POST /v1/responses has no reasoning field in its strict request -# schema. Other normalized or dynamically routed routes do not document -# transparent native-field passthrough; do not infer support from them. -# https://docs.merge.dev/merge-gateway/api-overview/responses/create doc = "https://docs.merge.dev/merge-gateway" From 46c9418e600067dfdb01ce722108eb089299cf72 Mon Sep 17 00:00:00 2001 From: Matthew Feroz Date: Tue, 14 Jul 2026 09:23:39 -0400 Subject: [PATCH 3/4] fix(sync): preserve partial Merge Gateway metadata --- .../core/src/sync/providers/merge-gateway.ts | 13 ++------- packages/core/test/sync.test.ts | 28 ++++++++++++++++++- .../models/anthropic/claude-fable-5.toml | 6 ++-- sync.md | 2 +- 4 files changed, 33 insertions(+), 16 deletions(-) diff --git a/packages/core/src/sync/providers/merge-gateway.ts b/packages/core/src/sync/providers/merge-gateway.ts index 87829ede0e..575f7a5c2c 100644 --- a/packages/core/src/sync/providers/merge-gateway.ts +++ b/packages/core/src/sync/providers/merge-gateway.ts @@ -257,22 +257,13 @@ function mergeGatewayCachePricing( ) { const promptCaching = vendor.prompt_caching; const pricing = vendor.pricing; - const authoritative = promptCaching !== undefined - || pricing.cache_read_per_million !== undefined - || pricing.cache_write_per_million !== undefined; - if (!authoritative) { - return { - read: existing?.cost?.cache_read, - write: existing?.cost?.cache_write, - }; - } return { read: promptCaching?.cache_read_cost_per_million ?? pricing.cache_read_per_million - ?? undefined, + ?? existing?.cost?.cache_read, write: promptCaching?.cache_write_cost_per_million ?? pricing.cache_write_per_million - ?? undefined, + ?? existing?.cost?.cache_write, }; } diff --git a/packages/core/test/sync.test.ts b/packages/core/test/sync.test.ts index 4fbd29f3e6..407a694e26 100644 --- a/packages/core/test/sync.test.ts +++ b/packages/core/test/sync.test.ts @@ -1125,7 +1125,7 @@ test("factors Merge Gateway GPT-5.6 Sol against canonical metadata", () => { }); }); -test("syncs authoritative Merge Gateway cache pricing", () => { +test("merges authoritative Merge Gateway cache pricing field by field", () => { const model = buildMergeGatewayModel(mergeGatewayModel({ vendors: { openai: mergeGatewayVendor({ @@ -1156,6 +1156,32 @@ test("syncs authoritative Merge Gateway cache pricing", () => { input: 3.75, output: 22.5, cache_read: 0.375, + cache_write: 6.25, + }, + }); +}); + +test("preserves Merge Gateway cache pricing when prompt caching exposes only its mode", () => { + const model = buildMergeGatewayModel(mergeGatewayModel({ + vendors: { + openai: mergeGatewayVendor({ + prompt_caching: { mode: "automatic" }, + }), + }, + }), { + base_model: "openai/gpt-5.6-sol", + cost: { + input: 5, + output: 30, + cache_read: 0.5, + cache_write: 6.25, + }, + }); + + expect(model).toMatchObject({ + cost: { + cache_read: 0.5, + cache_write: 6.25, }, }); }); diff --git a/providers/merge-gateway/models/anthropic/claude-fable-5.toml b/providers/merge-gateway/models/anthropic/claude-fable-5.toml index f8c3b236b2..eaa41a5da3 100644 --- a/providers/merge-gateway/models/anthropic/claude-fable-5.toml +++ b/providers/merge-gateway/models/anthropic/claude-fable-5.toml @@ -1,9 +1,9 @@ # Merge Gateway GET /v1/models?model=anthropic/claude-fable-5 (accessed 2026-07-14): -# the only available Anthropic route reports `supports_reasoning = false`, so -# callers have no reasoning control despite the base model being reasoning-capable. +# the only available Anthropic route reports `supports_reasoning = false`, so this +# provider route does not expose the base model's reasoning capability. base_model = "anthropic/claude-fable-5" +reasoning = false structured_output = true -reasoning_options = [] [cost] input = 10 diff --git a/sync.md b/sync.md index 0819c732ca..ce8c22f5f5 100644 --- a/sync.md +++ b/sync.md @@ -150,7 +150,7 @@ Merge Gateway is implemented in `packages/core/src/sync/providers/merge-gateway. - The canonical provider's available vendor route supplies pricing, limits, and capabilities; another available vendor is used only when the canonical route is unavailable. - Canonical model IDs emit `base_model` references to model metadata when a matching `models/` entry exists. - Existing cache pricing, tiered pricing, reasoning controls, and experimental modes are preserved because the API does not expose them. -- When the API exposes route-level `prompt_caching` or cache pricing fields, those values authoritatively replace preserved cache prices. Cache prices curated before that API support remain in provider TOMLs and survive syncs. +- Route-level cache prices replace curated values field by field. A cache read or write price that the API does not expose remains preserved in the provider TOML, including when `prompt_caching` exposes only its mode. - Local models missing from the response are retained because API-key policy can affect catalog visibility. ## Cloudflare Workers AI Notes From 182176ea43ec0a9de36838507dbd9ebdf3d558a2 Mon Sep 17 00:00:00 2001 From: Matthew Feroz Date: Tue, 14 Jul 2026 23:15:53 -0400 Subject: [PATCH 4/4] fix(merge-gateway): align route metadata sync --- .../core/src/sync/providers/merge-gateway.ts | 34 +++++-- .../core/src/sync/providers/openrouter.ts | 2 + packages/core/test/sync.test.ts | 94 +++++++++++++++++++ .../anthropic/claude-haiku-4-5-20251001.toml | 9 +- .../anthropic/claude-opus-4-1-20250805.toml | 9 +- .../anthropic/claude-opus-4-20250514.toml | 9 +- .../anthropic/claude-opus-4-5-20251101.toml | 13 +-- .../models/anthropic/claude-opus-4-6.toml | 13 +-- .../models/anthropic/claude-opus-4-7.toml | 8 +- .../models/anthropic/claude-opus-4-8.toml | 9 +- .../anthropic/claude-sonnet-4-5-20250929.toml | 9 +- .../models/anthropic/claude-sonnet-4-6.toml | 13 +-- .../bytedance/dola-seed-2.0-code-preview.toml | 25 +++++ .../models/bytedance/dola-seed-2.0-code.toml | 25 +++++ .../models/bytedance/dola-seed-2.0-lite.toml | 25 +++++ .../models/bytedance/dola-seed-2.0-mini.toml | 25 +++++ .../models/bytedance/dola-seed-2.0-pro.toml | 25 +++++ .../models/deepseek/deepseek-r1.toml | 2 +- .../models/google/gemma-4-26b-a4b-it.toml | 4 +- .../models/google/gemma-4-31b-it.toml | 4 +- .../models/meta/llama-3.3-70b-instruct.toml | 8 +- .../models/meta/muse-spark-1.1.toml | 1 + .../{moonshotai => moonshot}/kimi-k2.5.toml | 11 ++- .../{moonshotai => moonshot}/kimi-k2.6.toml | 10 +- .../kimi-k2.7-code-highspeed.toml | 13 ++- .../kimi-k2.7-code.toml | 13 ++- .../models/moonshotai/kimi-k2-thinking.toml | 1 + .../models/nvidia/nemotron-nano-9b-v2.toml | 2 +- .../models/openai/gpt-5-chat-latest.toml | 2 +- .../models/openai/gpt-5.1-chat-latest.toml | 2 +- .../models/openai/gpt-5.2-chat-latest.toml | 2 +- .../models/openai/gpt-oss-120b.toml | 10 +- .../models/openai/gpt-oss-20b.toml | 13 ++- .../merge-gateway/models/qwen/qwen-flash.toml | 3 +- .../merge-gateway/models/qwen/qwen-plus.toml | 3 +- .../models/qwen/qwen3-235b-a22b.toml | 3 +- .../merge-gateway/models/qwen/qwen3-32b.toml | 7 +- .../models/qwen/qwen3-coder-flash.toml | 1 + .../models/qwen/qwen3-coder-plus.toml | 1 + .../merge-gateway/models/qwen/qwen3-max.toml | 1 + .../qwen/qwen3-next-80b-a3b-instruct.toml | 1 + .../qwen/qwen3-next-80b-a3b-thinking.toml | 6 +- .../models/qwen/qwen3-vl-plus.toml | 3 +- .../models/qwen/qwen3.5-122b-a10b.toml | 3 +- .../models/qwen/qwen3.5-27b.toml | 3 +- .../models/qwen/qwen3.5-35b-a3b.toml | 3 +- .../models/qwen/qwen3.5-397b-a17b.toml | 3 +- .../merge-gateway/models/qwen/qwen3.5-9b.toml | 2 +- .../models/qwen/qwen3.5-plus.toml | 3 +- .../models/qwen/qwen3.6-27b.toml | 2 +- .../models/qwen/qwen3.6-35b-a3b.toml | 3 +- .../models/qwen/qwen3.6-flash.toml | 3 +- .../models/qwen/qwen3.6-max-preview.toml | 2 +- .../models/qwen/qwen3.6-plus.toml | 3 +- .../models/qwen/qwen3.7-max.toml | 3 +- .../models/qwen/qwen3.7-plus.toml | 2 +- .../models/sakana/fugu-ultra.toml | 10 ++ .../models/writer/palmyra-x4.toml | 25 +++++ .../models/writer/palmyra-x5.toml | 25 +++++ .../merge-gateway/models/zai/glm-4.5v.toml | 2 +- .../models/zai/glm-4.7-flash.toml | 2 +- .../merge-gateway/models/zai/glm-5.2.toml | 10 +- sync.md | 6 +- 63 files changed, 422 insertions(+), 167 deletions(-) create mode 100644 providers/merge-gateway/models/bytedance/dola-seed-2.0-code-preview.toml create mode 100644 providers/merge-gateway/models/bytedance/dola-seed-2.0-code.toml create mode 100644 providers/merge-gateway/models/bytedance/dola-seed-2.0-lite.toml create mode 100644 providers/merge-gateway/models/bytedance/dola-seed-2.0-mini.toml create mode 100644 providers/merge-gateway/models/bytedance/dola-seed-2.0-pro.toml rename providers/merge-gateway/models/{moonshotai => moonshot}/kimi-k2.5.toml (74%) rename providers/merge-gateway/models/{moonshotai => moonshot}/kimi-k2.6.toml (78%) rename providers/merge-gateway/models/{moonshotai => moonshot}/kimi-k2.7-code-highspeed.toml (73%) rename providers/merge-gateway/models/{moonshotai => moonshot}/kimi-k2.7-code.toml (72%) create mode 100644 providers/merge-gateway/models/sakana/fugu-ultra.toml create mode 100644 providers/merge-gateway/models/writer/palmyra-x4.toml create mode 100644 providers/merge-gateway/models/writer/palmyra-x5.toml diff --git a/packages/core/src/sync/providers/merge-gateway.ts b/packages/core/src/sync/providers/merge-gateway.ts index 575f7a5c2c..4df225a75c 100644 --- a/packages/core/src/sync/providers/merge-gateway.ts +++ b/packages/core/src/sync/providers/merge-gateway.ts @@ -14,6 +14,7 @@ const VendorCapabilities = z.object({ supports_tool_calling: z.boolean(), supports_tool_choice: z.boolean().default(false), supports_structured_outputs: z.boolean(), + supports_reasoning: z.boolean().optional(), streaming: z.boolean(), }).passthrough(); @@ -141,13 +142,22 @@ export function selectMergeGatewayVendor(model: MergeGatewayModel) { return { id: model.provider, info: canonical }; } + // Match Gateway's default resolver: when the model author's native route is + // unavailable, use the cheapest active route by combined input + output + // price. Object order is preserved for equal prices; the public API emits + // vendors in CMS-priority order, which is Gateway's own tiebreaker. const available = Object.entries(model.vendors) - .filter(([, info]) => info.availability_status === "available") - .sort(([a], [b]) => a.localeCompare(b))[0]; - if (available !== undefined) return { id: available[0], info: available[1] }; + .filter(([, info]) => info.availability_status === "available"); + const selected = available.reduce((best, candidate) => { + if (best === undefined) return candidate; + const bestCost = best[1].pricing.input_per_million + best[1].pricing.output_per_million; + const candidateCost = candidate[1].pricing.input_per_million + candidate[1].pricing.output_per_million; + return candidateCost < bestCost ? candidate : best; + }, undefined); + if (selected !== undefined) return { id: selected[0], info: selected[1] }; if (canonical !== undefined) return { id: model.provider, info: canonical }; - const fallback = Object.entries(model.vendors).sort(([a], [b]) => a.localeCompare(b))[0]; + const fallback = Object.entries(model.vendors)[0]; return fallback === undefined ? undefined : { id: fallback[0], info: fallback[1] }; } @@ -184,6 +194,9 @@ export function buildMergeGatewayModel( ? "deprecated" as const : undefined; const baseModel = existing?.base_model ?? resolveCanonicalBaseModel(model.model); + const routeDisablesReasoning = selected.info.capabilities.supports_reasoning === false; + const reasoning = routeDisablesReasoning ? false : existing?.reasoning; + const reasoningOptions = routeDisablesReasoning ? undefined : existing?.reasoning_options; const authoritative = { // Some catalog rows use an upstream org/model ID as display_name. Let // canonical metadata provide the human-readable name for factored models. @@ -203,8 +216,8 @@ export function buildMergeGatewayModel( { ...authoritative, description: existing?.description, - reasoning: existing?.reasoning, - reasoning_options: existing?.reasoning_options, + reasoning, + reasoning_options: reasoningOptions, temperature: existing?.temperature, interleaved: existing?.interleaved, provider: existing?.provider, @@ -230,7 +243,7 @@ export function buildMergeGatewayModel( id: model.model, name: model.display_name, family: existing.family, - reasoning: existing.reasoning, + reasoning, tool_call: selected.info.capabilities.supports_tool_calling, structured_output: selected.info.capabilities.supports_structured_outputs, open_weights: existing.open_weights, @@ -240,8 +253,8 @@ export function buildMergeGatewayModel( family: existing.family, release_date: releaseDate, last_updated: lastUpdated, - reasoning: existing.reasoning ?? false, - reasoning_options: existing.reasoning_options, + reasoning: reasoning ?? false, + reasoning_options: reasoningOptions, temperature: existing.temperature, knowledge: existing.knowledge, open_weights: existing.open_weights ?? false, @@ -257,6 +270,9 @@ function mergeGatewayCachePricing( ) { const promptCaching = vendor.prompt_caching; const pricing = vendor.pricing; + if (promptCaching?.mode === "none") { + return { read: undefined, write: undefined }; + } return { read: promptCaching?.cache_read_cost_per_million ?? pricing.cache_read_per_million diff --git a/packages/core/src/sync/providers/openrouter.ts b/packages/core/src/sync/providers/openrouter.ts index d35cc3f978..7fe7bac2ad 100644 --- a/packages/core/src/sync/providers/openrouter.ts +++ b/packages/core/src/sync/providers/openrouter.ts @@ -27,10 +27,12 @@ const CANONICAL_PROVIDER_PREFIXES = { "meta-llama": { provider: "llama", metadata: "meta" }, minimax: { provider: "minimax", metadata: "minimax" }, mistralai: { provider: "mistral", metadata: "mistral" }, + moonshot: { provider: "moonshotai", metadata: "moonshotai" }, moonshotai: { provider: "moonshotai", metadata: "moonshotai" }, openai: { provider: "openai", metadata: "openai" }, nvidia: { provider: "nvidia", metadata: "nvidia" }, qwen: { provider: "alibaba", metadata: "alibaba" }, + sakana: { provider: "sakana", metadata: "sakana" }, stepfun: { provider: "stepfun", metadata: "stepfun" }, tencent: { provider: "tencent", metadata: "tencent" }, "x-ai": { provider: "xai", metadata: "xai" }, diff --git a/packages/core/test/sync.test.ts b/packages/core/test/sync.test.ts index 407a694e26..a7f10ddfd5 100644 --- a/packages/core/test/sync.test.ts +++ b/packages/core/test/sync.test.ts @@ -962,6 +962,22 @@ test("factors OpenRouter Pro routes against canonical OpenAI metadata", () => { expect("release_date" in model).toBe(false); }); +test("resolves Merge Gateway provider aliases to canonical metadata", () => { + expect([ + resolveCanonicalBaseModel("moonshot/kimi-k2.5"), + resolveCanonicalBaseModel("moonshot/kimi-k2.6"), + resolveCanonicalBaseModel("moonshot/kimi-k2.7-code"), + resolveCanonicalBaseModel("moonshot/kimi-k2.7-code-highspeed"), + resolveCanonicalBaseModel("sakana/fugu-ultra"), + ]).toEqual([ + "moonshotai/kimi-k2.5", + "moonshotai/kimi-k2.6", + "moonshotai/kimi-k2.7-code", + "moonshotai/kimi-k2.7-code-highspeed", + "sakana/fugu-ultra", + ]); +}); + test("resolves Venice Pro routes to canonical OpenAI metadata", () => { expect([ resolveVeniceBaseModel("openai-gpt-56-luna-pro", "GPT-5.6 Luna Pro"), @@ -1125,6 +1141,25 @@ test("factors Merge Gateway GPT-5.6 Sol against canonical metadata", () => { }); }); +test("disables reasoning when the selected Merge Gateway route explicitly does not support it", () => { + const vendor = mergeGatewayVendor(); + vendor.capabilities.supports_reasoning = false; + const model = buildMergeGatewayModel(mergeGatewayModel({ + vendors: { openai: vendor }, + }), { + base_model: "openai/gpt-5.6-sol", + reasoning: true, + reasoning_options: [{ type: "effort", values: ["low", "medium", "high"] }], + cost: { input: 5, output: 30 }, + }); + + expect(model).toMatchObject({ + base_model: "openai/gpt-5.6-sol", + reasoning: false, + }); + expect(model).not.toHaveProperty("reasoning_options"); +}); + test("merges authoritative Merge Gateway cache pricing field by field", () => { const model = buildMergeGatewayModel(mergeGatewayModel({ vendors: { @@ -1186,6 +1221,30 @@ test("preserves Merge Gateway cache pricing when prompt caching exposes only its }); }); +test("removes Merge Gateway cache pricing when prompt caching mode is none", () => { + const model = buildMergeGatewayModel(mergeGatewayModel({ + vendors: { + openai: mergeGatewayVendor({ + prompt_caching: { mode: "none" }, + }), + }, + }), { + base_model: "openai/gpt-5.6-sol", + cost: { + input: 5, + output: 30, + cache_read: 0.5, + cache_write: 6.25, + }, + }); + + expect(model).toMatchObject({ + cost: { input: 5, output: 30 }, + }); + expect(model.cost).not.toHaveProperty("cache_read"); + expect(model.cost).not.toHaveProperty("cache_write"); +}); + test("inherits canonical names for ID-shaped Merge Gateway display names", () => { const model = buildMergeGatewayModel(mergeGatewayModel({ model: "minimax/minimax-m2", @@ -1239,6 +1298,41 @@ test("uses the canonical Merge Gateway vendor as the catalog baseline", () => { }); }); +test("uses Merge Gateway's cheapest fallback route when no canonical route exists", () => { + const model = mergeGatewayModel({ + provider: "qwen", + vendors: { + bedrock: mergeGatewayVendor({ + pricing: { currency: "USD", input_per_million: 0.15, output_per_million: 0.6 }, + }), + alibaba: mergeGatewayVendor({ + pricing: { currency: "USD", input_per_million: 0.287, output_per_million: 0.64 }, + }), + }, + }); + + expect(selectMergeGatewayVendor(model)).toMatchObject({ + id: "bedrock", + info: { pricing: { input_per_million: 0.15, output_per_million: 0.6 } }, + }); +}); + +test("uses Merge Gateway's CMS order to break equal-cost fallback ties", () => { + const model = mergeGatewayModel({ + provider: "qwen", + vendors: { + empiriolabs: mergeGatewayVendor({ + pricing: { currency: "USD", input_per_million: 0.4, output_per_million: 1.6 }, + }), + fireworks: mergeGatewayVendor({ + pricing: { currency: "USD", input_per_million: 0.4, output_per_million: 1.6 }, + }), + }, + }); + + expect(selectMergeGatewayVendor(model)).toMatchObject({ id: "empiriolabs" }); +}); + test("retains Merge Gateway models missing from an API-key-scoped response", () => { expect(mergeGateway.deleteMissing).toBe(false); }); diff --git a/providers/merge-gateway/models/anthropic/claude-haiku-4-5-20251001.toml b/providers/merge-gateway/models/anthropic/claude-haiku-4-5-20251001.toml index 12beefa8b4..4b543cb668 100644 --- a/providers/merge-gateway/models/anthropic/claude-haiku-4-5-20251001.toml +++ b/providers/merge-gateway/models/anthropic/claude-haiku-4-5-20251001.toml @@ -1,15 +1,8 @@ base_model = "anthropic/claude-haiku-4-5-20251001" name = "Claude Haiku 4.5 (20251001)" +reasoning = false structured_output = true -[[reasoning_options]] -type = "toggle" - -[[reasoning_options]] -type = "budget_tokens" -min = 1_024 -max = 63_999 - [cost] input = 1 output = 5 diff --git a/providers/merge-gateway/models/anthropic/claude-opus-4-1-20250805.toml b/providers/merge-gateway/models/anthropic/claude-opus-4-1-20250805.toml index 80cef05967..dd3ffc4088 100644 --- a/providers/merge-gateway/models/anthropic/claude-opus-4-1-20250805.toml +++ b/providers/merge-gateway/models/anthropic/claude-opus-4-1-20250805.toml @@ -1,15 +1,8 @@ base_model = "anthropic/claude-opus-4-1-20250805" name = "Claude Opus 4.1 (20250805)" +reasoning = false structured_output = true -[[reasoning_options]] -type = "toggle" - -[[reasoning_options]] -type = "budget_tokens" -min = 1_024 -max = 31_999 - [cost] input = 15 output = 75 diff --git a/providers/merge-gateway/models/anthropic/claude-opus-4-20250514.toml b/providers/merge-gateway/models/anthropic/claude-opus-4-20250514.toml index 0b0174e5b0..91211fe012 100644 --- a/providers/merge-gateway/models/anthropic/claude-opus-4-20250514.toml +++ b/providers/merge-gateway/models/anthropic/claude-opus-4-20250514.toml @@ -1,15 +1,8 @@ base_model = "anthropic/claude-opus-4-20250514" name = "Claude Opus 4 (20250514)" +reasoning = false structured_output = true -[[reasoning_options]] -type = "toggle" - -[[reasoning_options]] -type = "budget_tokens" -min = 1_024 -max = 31_999 - [cost] input = 15 output = 75 diff --git a/providers/merge-gateway/models/anthropic/claude-opus-4-5-20251101.toml b/providers/merge-gateway/models/anthropic/claude-opus-4-5-20251101.toml index e51f165765..a68a8f006c 100644 --- a/providers/merge-gateway/models/anthropic/claude-opus-4-5-20251101.toml +++ b/providers/merge-gateway/models/anthropic/claude-opus-4-5-20251101.toml @@ -1,19 +1,8 @@ base_model = "anthropic/claude-opus-4-5-20251101" name = "Claude Opus 4.5 (20251101)" +reasoning = false structured_output = true -[[reasoning_options]] -type = "toggle" - -[[reasoning_options]] -type = "effort" -values = ["low", "medium", "high"] - -[[reasoning_options]] -type = "budget_tokens" -min = 1_024 -max = 63_999 - [cost] input = 5 output = 25 diff --git a/providers/merge-gateway/models/anthropic/claude-opus-4-6.toml b/providers/merge-gateway/models/anthropic/claude-opus-4-6.toml index 63d173c380..81b36cbff0 100644 --- a/providers/merge-gateway/models/anthropic/claude-opus-4-6.toml +++ b/providers/merge-gateway/models/anthropic/claude-opus-4-6.toml @@ -1,18 +1,7 @@ base_model = "anthropic/claude-opus-4-6" +reasoning = false structured_output = true -[[reasoning_options]] -type = "toggle" - -[[reasoning_options]] -type = "effort" -values = ["low", "medium", "high", "max"] - -[[reasoning_options]] -type = "budget_tokens" -min = 1_024 -max = 127_999 - [cost] input = 5 output = 25 diff --git a/providers/merge-gateway/models/anthropic/claude-opus-4-7.toml b/providers/merge-gateway/models/anthropic/claude-opus-4-7.toml index 0fe0cead33..2a438839af 100644 --- a/providers/merge-gateway/models/anthropic/claude-opus-4-7.toml +++ b/providers/merge-gateway/models/anthropic/claude-opus-4-7.toml @@ -1,13 +1,7 @@ base_model = "anthropic/claude-opus-4-7" +reasoning = false structured_output = true -[[reasoning_options]] -type = "toggle" - -[[reasoning_options]] -type = "effort" -values = ["low", "medium", "high", "xhigh", "max"] - [cost] input = 5 output = 25 diff --git a/providers/merge-gateway/models/anthropic/claude-opus-4-8.toml b/providers/merge-gateway/models/anthropic/claude-opus-4-8.toml index 7606299bdd..4ef7dcb879 100644 --- a/providers/merge-gateway/models/anthropic/claude-opus-4-8.toml +++ b/providers/merge-gateway/models/anthropic/claude-opus-4-8.toml @@ -1,14 +1,7 @@ base_model = "anthropic/claude-opus-4-8" +reasoning = false structured_output = true -[[reasoning_options]] -type = "toggle" - -[[reasoning_options]] -type = "budget_tokens" -min = 1 -max = 128_000 - [cost] input = 5 output = 25 diff --git a/providers/merge-gateway/models/anthropic/claude-sonnet-4-5-20250929.toml b/providers/merge-gateway/models/anthropic/claude-sonnet-4-5-20250929.toml index e9bf085d46..0790c8ef4c 100644 --- a/providers/merge-gateway/models/anthropic/claude-sonnet-4-5-20250929.toml +++ b/providers/merge-gateway/models/anthropic/claude-sonnet-4-5-20250929.toml @@ -1,15 +1,8 @@ base_model = "anthropic/claude-sonnet-4-5-20250929" name = "Claude Sonnet 4.5 (20250929)" +reasoning = false structured_output = true -[[reasoning_options]] -type = "toggle" - -[[reasoning_options]] -type = "budget_tokens" -min = 1_024 -max = 63_999 - [cost] input = 3 output = 15 diff --git a/providers/merge-gateway/models/anthropic/claude-sonnet-4-6.toml b/providers/merge-gateway/models/anthropic/claude-sonnet-4-6.toml index 89818d9638..0e668b3f41 100644 --- a/providers/merge-gateway/models/anthropic/claude-sonnet-4-6.toml +++ b/providers/merge-gateway/models/anthropic/claude-sonnet-4-6.toml @@ -1,18 +1,7 @@ base_model = "anthropic/claude-sonnet-4-6" +reasoning = false structured_output = true -[[reasoning_options]] -type = "toggle" - -[[reasoning_options]] -type = "effort" -values = ["low", "medium", "high", "max"] - -[[reasoning_options]] -type = "budget_tokens" -min = 1_024 -max = 63_999 - [cost] input = 3 output = 15 diff --git a/providers/merge-gateway/models/bytedance/dola-seed-2.0-code-preview.toml b/providers/merge-gateway/models/bytedance/dola-seed-2.0-code-preview.toml new file mode 100644 index 0000000000..abbba27194 --- /dev/null +++ b/providers/merge-gateway/models/bytedance/dola-seed-2.0-code-preview.toml @@ -0,0 +1,25 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=bytedance%2Fdola-seed-2.0-code-preview + +name = "Dola Seed 2.0 Code (preview)" +description = "Preview coding model for repository understanding, refactors, and engineering tasks" +family = "seed" +release_date = "2026-03-28" +last_updated = "2026-03-28" +attachment = false +reasoning = false +temperature = true +tool_call = false +structured_output = false +open_weights = false + +[cost] +input = 0.5 +output = 3 + +[limit] +context = 131_072 +output = 32_768 + +[modalities] +input = ["text"] +output = ["text"] diff --git a/providers/merge-gateway/models/bytedance/dola-seed-2.0-code.toml b/providers/merge-gateway/models/bytedance/dola-seed-2.0-code.toml new file mode 100644 index 0000000000..24901bca8a --- /dev/null +++ b/providers/merge-gateway/models/bytedance/dola-seed-2.0-code.toml @@ -0,0 +1,25 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=bytedance%2Fdola-seed-2.0-code + +name = "Seed 2.0 Code" +description = "Coding model for repository understanding, refactors, and agentic engineering tasks" +family = "seed" +release_date = "2026-02-14" +last_updated = "2026-02-14" +attachment = true +reasoning = false +temperature = true +tool_call = false +structured_output = false +open_weights = false + +[cost] +input = 0.4 +output = 2.4 + +[limit] +context = 256_000 +output = 128_000 + +[modalities] +input = ["text", "image"] +output = ["text"] diff --git a/providers/merge-gateway/models/bytedance/dola-seed-2.0-lite.toml b/providers/merge-gateway/models/bytedance/dola-seed-2.0-lite.toml new file mode 100644 index 0000000000..9c2e1aa96b --- /dev/null +++ b/providers/merge-gateway/models/bytedance/dola-seed-2.0-lite.toml @@ -0,0 +1,25 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=bytedance%2Fdola-seed-2.0-lite + +name = "Seed 2.0 Lite" +description = "Efficient Seed model for general chat, analysis, and lightweight production tasks" +family = "seed" +release_date = "2026-02-28" +last_updated = "2026-02-28" +attachment = false +reasoning = false +temperature = true +tool_call = false +structured_output = false +open_weights = false + +[cost] +input = 0.25 +output = 2 + +[limit] +context = 131_072 +output = 32_768 + +[modalities] +input = ["text"] +output = ["text"] diff --git a/providers/merge-gateway/models/bytedance/dola-seed-2.0-mini.toml b/providers/merge-gateway/models/bytedance/dola-seed-2.0-mini.toml new file mode 100644 index 0000000000..b5cea45ca4 --- /dev/null +++ b/providers/merge-gateway/models/bytedance/dola-seed-2.0-mini.toml @@ -0,0 +1,25 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=bytedance%2Fdola-seed-2.0-mini + +name = "Seed 2.0 Mini" +description = "Low-cost Seed model for general chat, extraction, and lightweight production tasks" +family = "seed" +release_date = "2026-02-15" +last_updated = "2026-02-15" +attachment = false +reasoning = false +temperature = true +tool_call = false +structured_output = false +open_weights = false + +[cost] +input = 0.1 +output = 0.4 + +[limit] +context = 131_072 +output = 32_768 + +[modalities] +input = ["text"] +output = ["text"] diff --git a/providers/merge-gateway/models/bytedance/dola-seed-2.0-pro.toml b/providers/merge-gateway/models/bytedance/dola-seed-2.0-pro.toml new file mode 100644 index 0000000000..b990a9d442 --- /dev/null +++ b/providers/merge-gateway/models/bytedance/dola-seed-2.0-pro.toml @@ -0,0 +1,25 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=bytedance%2Fdola-seed-2.0-pro + +name = "Seed 2.0 Pro" +description = "Higher-capability Seed model for complex chat, analysis, and production tasks" +family = "seed" +release_date = "2026-03-28" +last_updated = "2026-03-28" +attachment = false +reasoning = false +temperature = true +tool_call = false +structured_output = false +open_weights = false + +[cost] +input = 0.5 +output = 3 + +[limit] +context = 131_072 +output = 32_768 + +[modalities] +input = ["text"] +output = ["text"] diff --git a/providers/merge-gateway/models/deepseek/deepseek-r1.toml b/providers/merge-gateway/models/deepseek/deepseek-r1.toml index 283094ea09..669e074a17 100644 --- a/providers/merge-gateway/models/deepseek/deepseek-r1.toml +++ b/providers/merge-gateway/models/deepseek/deepseek-r1.toml @@ -1,8 +1,8 @@ base_model = "deepseek/deepseek-r1" name = "DeepSeek R1" +reasoning = false tool_call = false structured_output = false -reasoning_options = [] [cost] input = 1.35 diff --git a/providers/merge-gateway/models/google/gemma-4-26b-a4b-it.toml b/providers/merge-gateway/models/google/gemma-4-26b-a4b-it.toml index a776b41646..0814497dc9 100644 --- a/providers/merge-gateway/models/google/gemma-4-26b-a4b-it.toml +++ b/providers/merge-gateway/models/google/gemma-4-26b-a4b-it.toml @@ -1,11 +1,9 @@ base_model = "google/gemma-4-26b-a4b-it" attachment = false +reasoning = false tool_call = false structured_output = false -[[reasoning_options]] -type = "toggle" - [cost] input = 0.13 output = 0.4 diff --git a/providers/merge-gateway/models/google/gemma-4-31b-it.toml b/providers/merge-gateway/models/google/gemma-4-31b-it.toml index fda08e4f1e..1595362736 100644 --- a/providers/merge-gateway/models/google/gemma-4-31b-it.toml +++ b/providers/merge-gateway/models/google/gemma-4-31b-it.toml @@ -1,11 +1,9 @@ base_model = "google/gemma-4-31b-it" attachment = false +reasoning = false tool_call = false structured_output = false -[[reasoning_options]] -type = "toggle" - [cost] input = 0.14 output = 0.4 diff --git a/providers/merge-gateway/models/meta/llama-3.3-70b-instruct.toml b/providers/merge-gateway/models/meta/llama-3.3-70b-instruct.toml index 152e720938..c4416d75b9 100644 --- a/providers/merge-gateway/models/meta/llama-3.3-70b-instruct.toml +++ b/providers/merge-gateway/models/meta/llama-3.3-70b-instruct.toml @@ -3,5 +3,9 @@ attachment = false structured_output = false [cost] -input = 0.72 -output = 0.72 +input = 0.22 +output = 0.5 + +[limit] +context = 131_072 +output = 32_768 diff --git a/providers/merge-gateway/models/meta/muse-spark-1.1.toml b/providers/merge-gateway/models/meta/muse-spark-1.1.toml index d49ae48665..d1ed3666ff 100644 --- a/providers/merge-gateway/models/meta/muse-spark-1.1.toml +++ b/providers/merge-gateway/models/meta/muse-spark-1.1.toml @@ -5,6 +5,7 @@ reasoning_options = [] [cost] input = 1.25 output = 4.25 +cache_read = 0.15 [limit] context = 1_048_576 diff --git a/providers/merge-gateway/models/moonshotai/kimi-k2.5.toml b/providers/merge-gateway/models/moonshot/kimi-k2.5.toml similarity index 74% rename from providers/merge-gateway/models/moonshotai/kimi-k2.5.toml rename to providers/merge-gateway/models/moonshot/kimi-k2.5.toml index cf77522a3f..41fabf109c 100644 --- a/providers/merge-gateway/models/moonshotai/kimi-k2.5.toml +++ b/providers/merge-gateway/models/moonshot/kimi-k2.5.toml @@ -1,4 +1,8 @@ base_model = "moonshotai/kimi-k2.5" +attachment = true + +[interleaved] +field = "reasoning_content" [[reasoning_options]] type = "toggle" @@ -8,9 +12,10 @@ type = "budget_tokens" min = 1 max = 262_144 -[interleaved] -field = "reasoning_content" - [cost] input = 0.6 output = 3 +cache_read = 0.1 + +[modalities] +input = ["text", "image"] diff --git a/providers/merge-gateway/models/moonshotai/kimi-k2.6.toml b/providers/merge-gateway/models/moonshot/kimi-k2.6.toml similarity index 78% rename from providers/merge-gateway/models/moonshotai/kimi-k2.6.toml rename to providers/merge-gateway/models/moonshot/kimi-k2.6.toml index 59d14b6a7f..2ce0ba3019 100644 --- a/providers/merge-gateway/models/moonshotai/kimi-k2.6.toml +++ b/providers/merge-gateway/models/moonshot/kimi-k2.6.toml @@ -1,5 +1,8 @@ base_model = "moonshotai/kimi-k2.6" +[interleaved] +field = "reasoning_content" + [[reasoning_options]] type = "toggle" @@ -8,9 +11,10 @@ type = "budget_tokens" min = 1 max = 262_144 -[interleaved] -field = "reasoning_content" - [cost] input = 0.95 output = 4 +cache_read = 0.16 + +[modalities] +input = ["text", "image"] diff --git a/providers/merge-gateway/models/moonshotai/kimi-k2.7-code-highspeed.toml b/providers/merge-gateway/models/moonshot/kimi-k2.7-code-highspeed.toml similarity index 73% rename from providers/merge-gateway/models/moonshotai/kimi-k2.7-code-highspeed.toml rename to providers/merge-gateway/models/moonshot/kimi-k2.7-code-highspeed.toml index fbc261f9eb..97b6f81d47 100644 --- a/providers/merge-gateway/models/moonshotai/kimi-k2.7-code-highspeed.toml +++ b/providers/merge-gateway/models/moonshot/kimi-k2.7-code-highspeed.toml @@ -1,5 +1,8 @@ base_model = "moonshotai/kimi-k2.7-code-highspeed" +[interleaved] +field = "reasoning_content" + [[reasoning_options]] type = "toggle" @@ -8,9 +11,13 @@ type = "budget_tokens" min = 1 max = 32_768 -[interleaved] -field = "reasoning_content" - [cost] input = 1.9 output = 8 +cache_read = 0.38 + +[limit] +output = 32_768 + +[modalities] +input = ["text", "image"] diff --git a/providers/merge-gateway/models/moonshotai/kimi-k2.7-code.toml b/providers/merge-gateway/models/moonshot/kimi-k2.7-code.toml similarity index 72% rename from providers/merge-gateway/models/moonshotai/kimi-k2.7-code.toml rename to providers/merge-gateway/models/moonshot/kimi-k2.7-code.toml index 9286e04bc6..d2d7dd319a 100644 --- a/providers/merge-gateway/models/moonshotai/kimi-k2.7-code.toml +++ b/providers/merge-gateway/models/moonshot/kimi-k2.7-code.toml @@ -1,5 +1,8 @@ base_model = "moonshotai/kimi-k2.7-code" +[interleaved] +field = "reasoning_content" + [[reasoning_options]] type = "toggle" @@ -8,9 +11,13 @@ type = "budget_tokens" min = 1 max = 32_768 -[interleaved] -field = "reasoning_content" - [cost] input = 0.95 output = 4 +cache_read = 0.19 + +[limit] +output = 32_768 + +[modalities] +input = ["text", "image"] diff --git a/providers/merge-gateway/models/moonshotai/kimi-k2-thinking.toml b/providers/merge-gateway/models/moonshotai/kimi-k2-thinking.toml index dfc8f5290b..117e4fd856 100644 --- a/providers/merge-gateway/models/moonshotai/kimi-k2-thinking.toml +++ b/providers/merge-gateway/models/moonshotai/kimi-k2-thinking.toml @@ -1,4 +1,5 @@ base_model = "moonshotai/kimi-k2-thinking" +status = "deprecated" [[reasoning_options]] type = "toggle" diff --git a/providers/merge-gateway/models/nvidia/nemotron-nano-9b-v2.toml b/providers/merge-gateway/models/nvidia/nemotron-nano-9b-v2.toml index a24d7e0cfb..479e511a4b 100644 --- a/providers/merge-gateway/models/nvidia/nemotron-nano-9b-v2.toml +++ b/providers/merge-gateway/models/nvidia/nemotron-nano-9b-v2.toml @@ -1,8 +1,8 @@ base_model = "nvidia/nemotron-nano-9b-v2" name = "Nemotron Nano 9B" +reasoning = false tool_call = false structured_output = false -reasoning_options = [] [cost] input = 0.06 diff --git a/providers/merge-gateway/models/openai/gpt-5-chat-latest.toml b/providers/merge-gateway/models/openai/gpt-5-chat-latest.toml index 4af6a73a45..eb539d9998 100644 --- a/providers/merge-gateway/models/openai/gpt-5-chat-latest.toml +++ b/providers/merge-gateway/models/openai/gpt-5-chat-latest.toml @@ -1,7 +1,7 @@ base_model = "openai/gpt-5-chat-latest" base_model_omit = ["limit.input"] name = "GPT-5 Chat Latest" -reasoning_options = [] +reasoning = false [cost] input = 1.25 diff --git a/providers/merge-gateway/models/openai/gpt-5.1-chat-latest.toml b/providers/merge-gateway/models/openai/gpt-5.1-chat-latest.toml index d1916353a0..efc818ff44 100644 --- a/providers/merge-gateway/models/openai/gpt-5.1-chat-latest.toml +++ b/providers/merge-gateway/models/openai/gpt-5.1-chat-latest.toml @@ -1,6 +1,6 @@ base_model = "openai/gpt-5.1-chat-latest" name = "GPT-5.1 Chat Latest" -reasoning_options = [] +reasoning = false [cost] input = 1.25 diff --git a/providers/merge-gateway/models/openai/gpt-5.2-chat-latest.toml b/providers/merge-gateway/models/openai/gpt-5.2-chat-latest.toml index c12b1689b0..818ab9e704 100644 --- a/providers/merge-gateway/models/openai/gpt-5.2-chat-latest.toml +++ b/providers/merge-gateway/models/openai/gpt-5.2-chat-latest.toml @@ -1,6 +1,6 @@ base_model = "openai/gpt-5.2-chat-latest" name = "GPT-5.2 Chat Latest" -reasoning_options = [] +reasoning = false [cost] input = 1.75 diff --git a/providers/merge-gateway/models/openai/gpt-oss-120b.toml b/providers/merge-gateway/models/openai/gpt-oss-120b.toml index 3eb069e5a6..5fd494cee9 100644 --- a/providers/merge-gateway/models/openai/gpt-oss-120b.toml +++ b/providers/merge-gateway/models/openai/gpt-oss-120b.toml @@ -2,14 +2,10 @@ # available routes either report `supports_reasoning = false` or reasoning with # `configurable = false` and no controls, so callers have no reasoning control. base_model = "openai/gpt-oss-120b" +reasoning = false tool_call = false structured_output = false -reasoning_options = [] [cost] -input = 0.1 -output = 0.5 - -[limit] -context = 128_000 -output = 32_000 +input = 0.09 +output = 0.36 diff --git a/providers/merge-gateway/models/openai/gpt-oss-20b.toml b/providers/merge-gateway/models/openai/gpt-oss-20b.toml index 758d8dc047..cd7d74a531 100644 --- a/providers/merge-gateway/models/openai/gpt-oss-20b.toml +++ b/providers/merge-gateway/models/openai/gpt-oss-20b.toml @@ -2,12 +2,11 @@ # available routes either report `supports_reasoning = false` or reasoning with # `configurable = false` and no controls, so callers have no reasoning control. base_model = "openai/gpt-oss-20b" -reasoning_options = [] +reasoning = false +tool_call = false +structured_output = false [cost] -input = 0.07 -output = 0.3 - -[limit] -context = 128_000 -output = 128_000 +input = 0.04 +output = 0.2 +cache_read = 0.02 diff --git a/providers/merge-gateway/models/qwen/qwen-flash.toml b/providers/merge-gateway/models/qwen/qwen-flash.toml index 9d31fbbca2..299e89c391 100644 --- a/providers/merge-gateway/models/qwen/qwen-flash.toml +++ b/providers/merge-gateway/models/qwen/qwen-flash.toml @@ -1,11 +1,12 @@ base_model = "alibaba/qwen-flash" +reasoning = false tool_call = false structured_output = false -reasoning_options = [] [cost] input = 0.022 output = 0.216 +cache_read = 0.0044 [limit] output = 250_000 diff --git a/providers/merge-gateway/models/qwen/qwen-plus.toml b/providers/merge-gateway/models/qwen/qwen-plus.toml index eb288e33a6..a3fb0776eb 100644 --- a/providers/merge-gateway/models/qwen/qwen-plus.toml +++ b/providers/merge-gateway/models/qwen/qwen-plus.toml @@ -1,11 +1,12 @@ base_model = "alibaba/qwen-plus" +reasoning = false tool_call = false structured_output = false -reasoning_options = [] [cost] input = 0.115 output = 0.287 +cache_read = 0.023 [limit] output = 250_000 diff --git a/providers/merge-gateway/models/qwen/qwen3-235b-a22b.toml b/providers/merge-gateway/models/qwen/qwen3-235b-a22b.toml index 0b3cf01e0d..926127614d 100644 --- a/providers/merge-gateway/models/qwen/qwen3-235b-a22b.toml +++ b/providers/merge-gateway/models/qwen/qwen3-235b-a22b.toml @@ -1,12 +1,13 @@ base_model = "alibaba/qwen3-235b-a22b" name = "Qwen3 235B A22B" +reasoning = false tool_call = false structured_output = false -reasoning_options = [] [cost] input = 0.287 output = 1.147 +cache_read = 0.0574 [limit] output = 32_768 diff --git a/providers/merge-gateway/models/qwen/qwen3-32b.toml b/providers/merge-gateway/models/qwen/qwen3-32b.toml index 6799a8b98c..2033594162 100644 --- a/providers/merge-gateway/models/qwen/qwen3-32b.toml +++ b/providers/merge-gateway/models/qwen/qwen3-32b.toml @@ -1,11 +1,10 @@ base_model = "alibaba/qwen3-32b" -tool_call = false +reasoning = false structured_output = false -reasoning_options = [] [cost] -input = 0.287 -output = 0.64 +input = 0.15 +output = 0.6 [limit] output = 32_768 diff --git a/providers/merge-gateway/models/qwen/qwen3-coder-flash.toml b/providers/merge-gateway/models/qwen/qwen3-coder-flash.toml index 171d33583d..ba9dbb0ead 100644 --- a/providers/merge-gateway/models/qwen/qwen3-coder-flash.toml +++ b/providers/merge-gateway/models/qwen/qwen3-coder-flash.toml @@ -5,6 +5,7 @@ structured_output = false [cost] input = 0.144 output = 0.574 +cache_read = 0.0288 [limit] output = 250_000 diff --git a/providers/merge-gateway/models/qwen/qwen3-coder-plus.toml b/providers/merge-gateway/models/qwen/qwen3-coder-plus.toml index 1a22f4698c..8d12a803e8 100644 --- a/providers/merge-gateway/models/qwen/qwen3-coder-plus.toml +++ b/providers/merge-gateway/models/qwen/qwen3-coder-plus.toml @@ -5,6 +5,7 @@ structured_output = false [cost] input = 0.574 output = 2.294 +cache_read = 0.1148 [limit] context = 1_000_000 diff --git a/providers/merge-gateway/models/qwen/qwen3-max.toml b/providers/merge-gateway/models/qwen/qwen3-max.toml index a91ec8afd2..22f3b42dc8 100644 --- a/providers/merge-gateway/models/qwen/qwen3-max.toml +++ b/providers/merge-gateway/models/qwen/qwen3-max.toml @@ -5,3 +5,4 @@ structured_output = false [cost] input = 0.359 output = 1.434 +cache_read = 0.0718 diff --git a/providers/merge-gateway/models/qwen/qwen3-next-80b-a3b-instruct.toml b/providers/merge-gateway/models/qwen/qwen3-next-80b-a3b-instruct.toml index f936e5fb71..b2ad8e78bc 100644 --- a/providers/merge-gateway/models/qwen/qwen3-next-80b-a3b-instruct.toml +++ b/providers/merge-gateway/models/qwen/qwen3-next-80b-a3b-instruct.toml @@ -5,3 +5,4 @@ structured_output = false [cost] input = 0.144 output = 0.574 +cache_read = 0.0288 diff --git a/providers/merge-gateway/models/qwen/qwen3-next-80b-a3b-thinking.toml b/providers/merge-gateway/models/qwen/qwen3-next-80b-a3b-thinking.toml index c5805b1218..fe00a88b44 100644 --- a/providers/merge-gateway/models/qwen/qwen3-next-80b-a3b-thinking.toml +++ b/providers/merge-gateway/models/qwen/qwen3-next-80b-a3b-thinking.toml @@ -1,8 +1,8 @@ base_model = "alibaba/qwen3-next-80b-a3b-thinking" +reasoning = false tool_call = false structured_output = false -reasoning_options = [] [cost] -input = 0.144 -output = 1.434 +input = 0.15 +output = 1.2 diff --git a/providers/merge-gateway/models/qwen/qwen3-vl-plus.toml b/providers/merge-gateway/models/qwen/qwen3-vl-plus.toml index 62b7809fdb..0b7afd7e0f 100644 --- a/providers/merge-gateway/models/qwen/qwen3-vl-plus.toml +++ b/providers/merge-gateway/models/qwen/qwen3-vl-plus.toml @@ -1,12 +1,13 @@ base_model = "alibaba/qwen3-vl-plus" attachment = true +reasoning = false tool_call = false structured_output = false -reasoning_options = [] [cost] input = 0.143 output = 1.434 +cache_read = 0.0286 [limit] output = 65_536 diff --git a/providers/merge-gateway/models/qwen/qwen3.5-122b-a10b.toml b/providers/merge-gateway/models/qwen/qwen3.5-122b-a10b.toml index f6f7beb213..2a33d7879b 100644 --- a/providers/merge-gateway/models/qwen/qwen3.5-122b-a10b.toml +++ b/providers/merge-gateway/models/qwen/qwen3.5-122b-a10b.toml @@ -1,12 +1,13 @@ base_model = "alibaba/qwen3.5-122b-a10b" attachment = false +reasoning = false tool_call = false structured_output = false -reasoning_options = [] [cost] input = 0.115 output = 0.917 +cache_read = 0.023 [limit] context = 131_072 diff --git a/providers/merge-gateway/models/qwen/qwen3.5-27b.toml b/providers/merge-gateway/models/qwen/qwen3.5-27b.toml index 61838ba5d2..d6a2738a45 100644 --- a/providers/merge-gateway/models/qwen/qwen3.5-27b.toml +++ b/providers/merge-gateway/models/qwen/qwen3.5-27b.toml @@ -1,12 +1,13 @@ base_model = "alibaba/qwen3.5-27b" attachment = false +reasoning = false tool_call = false structured_output = false -reasoning_options = [] [cost] input = 0.086 output = 0.688 +cache_read = 0.0172 [limit] context = 131_072 diff --git a/providers/merge-gateway/models/qwen/qwen3.5-35b-a3b.toml b/providers/merge-gateway/models/qwen/qwen3.5-35b-a3b.toml index 8a502a1b86..2095aa4c17 100644 --- a/providers/merge-gateway/models/qwen/qwen3.5-35b-a3b.toml +++ b/providers/merge-gateway/models/qwen/qwen3.5-35b-a3b.toml @@ -1,13 +1,14 @@ base_model = "alibaba/qwen3.5-35b-a3b" name = "Qwen3.5 35B A3B" attachment = false +reasoning = false tool_call = false structured_output = false -reasoning_options = [] [cost] input = 0.057 output = 0.459 +cache_read = 0.020357 [limit] context = 131_072 diff --git a/providers/merge-gateway/models/qwen/qwen3.5-397b-a17b.toml b/providers/merge-gateway/models/qwen/qwen3.5-397b-a17b.toml index 9805d19df5..d7e0ddb495 100644 --- a/providers/merge-gateway/models/qwen/qwen3.5-397b-a17b.toml +++ b/providers/merge-gateway/models/qwen/qwen3.5-397b-a17b.toml @@ -1,13 +1,14 @@ base_model = "alibaba/qwen3.5-397b-a17b" name = "Qwen3.5 397B A17B" attachment = false +reasoning = false tool_call = false structured_output = false -reasoning_options = [] [cost] input = 0.172 output = 1.032 +cache_read = 0.0344 [limit] context = 131_072 diff --git a/providers/merge-gateway/models/qwen/qwen3.5-9b.toml b/providers/merge-gateway/models/qwen/qwen3.5-9b.toml index 2b4e2a3935..a72691682d 100644 --- a/providers/merge-gateway/models/qwen/qwen3.5-9b.toml +++ b/providers/merge-gateway/models/qwen/qwen3.5-9b.toml @@ -1,7 +1,7 @@ base_model = "alibaba/qwen3.5-9b" attachment = true +reasoning = false structured_output = false -reasoning_options = [] [cost] input = 0.09 diff --git a/providers/merge-gateway/models/qwen/qwen3.5-plus.toml b/providers/merge-gateway/models/qwen/qwen3.5-plus.toml index 8379f126f0..1bb324949b 100644 --- a/providers/merge-gateway/models/qwen/qwen3.5-plus.toml +++ b/providers/merge-gateway/models/qwen/qwen3.5-plus.toml @@ -1,11 +1,12 @@ base_model = "alibaba/qwen3.5-plus" +reasoning = false tool_call = false structured_output = false -reasoning_options = [] [cost] input = 0.115 output = 0.688 +cache_read = 0.023 [limit] output = 250_000 diff --git a/providers/merge-gateway/models/qwen/qwen3.6-27b.toml b/providers/merge-gateway/models/qwen/qwen3.6-27b.toml index 9815022446..b8e90ba940 100644 --- a/providers/merge-gateway/models/qwen/qwen3.6-27b.toml +++ b/providers/merge-gateway/models/qwen/qwen3.6-27b.toml @@ -1,7 +1,7 @@ base_model = "alibaba/qwen3.6-27b" +reasoning = false tool_call = false structured_output = false -reasoning_options = [] [cost] input = 0.4126 diff --git a/providers/merge-gateway/models/qwen/qwen3.6-35b-a3b.toml b/providers/merge-gateway/models/qwen/qwen3.6-35b-a3b.toml index 57394e6fad..c695e7ce73 100644 --- a/providers/merge-gateway/models/qwen/qwen3.6-35b-a3b.toml +++ b/providers/merge-gateway/models/qwen/qwen3.6-35b-a3b.toml @@ -1,13 +1,14 @@ base_model = "alibaba/qwen3.6-35b-a3b" name = "Qwen3.6 35B A3B" attachment = false +reasoning = false tool_call = false structured_output = false -reasoning_options = [] [cost] input = 0.248 output = 1.485 +cache_read = 0.0496 [modalities] input = ["text"] diff --git a/providers/merge-gateway/models/qwen/qwen3.6-flash.toml b/providers/merge-gateway/models/qwen/qwen3.6-flash.toml index b10df25cf3..e7edc55b2b 100644 --- a/providers/merge-gateway/models/qwen/qwen3.6-flash.toml +++ b/providers/merge-gateway/models/qwen/qwen3.6-flash.toml @@ -1,12 +1,13 @@ base_model = "alibaba/qwen3.6-flash" attachment = false +reasoning = false tool_call = false structured_output = false -reasoning_options = [] [cost] input = 0.165 output = 0.99 +cache_read = 0.033 [limit] output = 250_000 diff --git a/providers/merge-gateway/models/qwen/qwen3.6-max-preview.toml b/providers/merge-gateway/models/qwen/qwen3.6-max-preview.toml index f2f9c11d1b..1a31538776 100644 --- a/providers/merge-gateway/models/qwen/qwen3.6-max-preview.toml +++ b/providers/merge-gateway/models/qwen/qwen3.6-max-preview.toml @@ -1,7 +1,7 @@ base_model = "alibaba/qwen3.6-max-preview" +reasoning = false tool_call = false structured_output = false -reasoning_options = [] [cost] input = 1.31 diff --git a/providers/merge-gateway/models/qwen/qwen3.6-plus.toml b/providers/merge-gateway/models/qwen/qwen3.6-plus.toml index a45e5743cf..245c5d99d4 100644 --- a/providers/merge-gateway/models/qwen/qwen3.6-plus.toml +++ b/providers/merge-gateway/models/qwen/qwen3.6-plus.toml @@ -1,11 +1,12 @@ base_model = "alibaba/qwen3.6-plus" +reasoning = false tool_call = false structured_output = false -reasoning_options = [] [cost] input = 0.276 output = 1.651 +cache_read = 0.0552 [limit] output = 250_000 diff --git a/providers/merge-gateway/models/qwen/qwen3.7-max.toml b/providers/merge-gateway/models/qwen/qwen3.7-max.toml index b4ef76d4d8..3f3d85bc8a 100644 --- a/providers/merge-gateway/models/qwen/qwen3.7-max.toml +++ b/providers/merge-gateway/models/qwen/qwen3.7-max.toml @@ -1,11 +1,12 @@ base_model = "alibaba/qwen3.7-max" +reasoning = false tool_call = false structured_output = false -reasoning_options = [] [cost] input = 0.825 output = 2.4755 +cache_read = 0.165 [limit] output = 250_000 diff --git a/providers/merge-gateway/models/qwen/qwen3.7-plus.toml b/providers/merge-gateway/models/qwen/qwen3.7-plus.toml index df3d175dc8..5ae04e9d74 100644 --- a/providers/merge-gateway/models/qwen/qwen3.7-plus.toml +++ b/providers/merge-gateway/models/qwen/qwen3.7-plus.toml @@ -1,8 +1,8 @@ base_model = "alibaba/qwen3.7-plus" attachment = true +reasoning = false tool_call = false structured_output = false -reasoning_options = [] [cost] input = 0.4 diff --git a/providers/merge-gateway/models/sakana/fugu-ultra.toml b/providers/merge-gateway/models/sakana/fugu-ultra.toml new file mode 100644 index 0000000000..6738a5dfc1 --- /dev/null +++ b/providers/merge-gateway/models/sakana/fugu-ultra.toml @@ -0,0 +1,10 @@ +base_model = "sakana/fugu-ultra" +reasoning = false +structured_output = false + +[cost] +input = 5 +output = 30 + +[limit] +output = 250_000 diff --git a/providers/merge-gateway/models/writer/palmyra-x4.toml b/providers/merge-gateway/models/writer/palmyra-x4.toml new file mode 100644 index 0000000000..dba9900285 --- /dev/null +++ b/providers/merge-gateway/models/writer/palmyra-x4.toml @@ -0,0 +1,25 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=writer%2Fpalmyra-x4 + +name = "Palmyra X4" +description = "Enterprise language model for writing, analysis, and tool-assisted workflows" +family = "palmyra" +release_date = "2024-10-09" +last_updated = "2024-10-09" +attachment = false +reasoning = false +temperature = true +tool_call = true +structured_output = false +open_weights = false + +[cost] +input = 2.5 +output = 10 + +[limit] +context = 128_000 +output = 32_000 + +[modalities] +input = ["text"] +output = ["text"] diff --git a/providers/merge-gateway/models/writer/palmyra-x5.toml b/providers/merge-gateway/models/writer/palmyra-x5.toml new file mode 100644 index 0000000000..c7bdfefa40 --- /dev/null +++ b/providers/merge-gateway/models/writer/palmyra-x5.toml @@ -0,0 +1,25 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=writer%2Fpalmyra-x5 + +name = "Palmyra X5" +description = "Enterprise multimodal model for writing, analysis, and tool-assisted workflows" +family = "palmyra" +release_date = "2025-04-28" +last_updated = "2025-04-28" +attachment = true +reasoning = false +temperature = true +tool_call = true +structured_output = true +open_weights = false + +[cost] +input = 0.6 +output = 6 + +[limit] +context = 1_000_000 +output = 250_000 + +[modalities] +input = ["text", "image"] +output = ["text"] diff --git a/providers/merge-gateway/models/zai/glm-4.5v.toml b/providers/merge-gateway/models/zai/glm-4.5v.toml index 167cbe1dac..1d54a9953b 100644 --- a/providers/merge-gateway/models/zai/glm-4.5v.toml +++ b/providers/merge-gateway/models/zai/glm-4.5v.toml @@ -1,7 +1,7 @@ base_model = "zhipuai/glm-4.5v" name = "Glm 4.5V" +reasoning = false structured_output = false -reasoning_options = [] [cost] input = 0.6 diff --git a/providers/merge-gateway/models/zai/glm-4.7-flash.toml b/providers/merge-gateway/models/zai/glm-4.7-flash.toml index 85c174b267..cc8fb9703e 100644 --- a/providers/merge-gateway/models/zai/glm-4.7-flash.toml +++ b/providers/merge-gateway/models/zai/glm-4.7-flash.toml @@ -1,7 +1,7 @@ base_model = "zhipuai/glm-4.7-flash" name = "GLM 4.7 Flash" +reasoning = false structured_output = false -reasoning_options = [] [cost] input = 0.07 diff --git a/providers/merge-gateway/models/zai/glm-5.2.toml b/providers/merge-gateway/models/zai/glm-5.2.toml index 32140e8772..91542acaf2 100644 --- a/providers/merge-gateway/models/zai/glm-5.2.toml +++ b/providers/merge-gateway/models/zai/glm-5.2.toml @@ -1,17 +1,11 @@ base_model = "zhipuai/glm-5.2" +reasoning = false structured_output = false [interleaved] field = "reasoning_content" -[[reasoning_options]] -type = "toggle" - -[[reasoning_options]] -type = "budget_tokens" -min = 1 -max = 50_000 - [cost] input = 1.05 output = 3.3 +cache_read = 0.195 diff --git a/sync.md b/sync.md index ce8c22f5f5..1774f6892e 100644 --- a/sync.md +++ b/sync.md @@ -147,10 +147,12 @@ Merge Gateway is implemented in `packages/core/src/sync/providers/merge-gateway. - Source endpoint: `https://api-gateway.merge.dev/v1/models`. - Required auth: `MERGE_GATEWAY_API_KEY`. - The sync follows `next_cursor` until every page has been fetched. -- The canonical provider's available vendor route supplies pricing, limits, and capabilities; another available vendor is used only when the canonical route is unavailable. +- The canonical provider's available vendor route supplies pricing, limits, and capabilities. When it is unavailable, the sync matches Gateway's default resolver by selecting the active route with the lowest combined input and output price; the API's CMS-priority order breaks ties. - Canonical model IDs emit `base_model` references to model metadata when a matching `models/` entry exists. -- Existing cache pricing, tiered pricing, reasoning controls, and experimental modes are preserved because the API does not expose them. +- Existing cache pricing, tiered pricing, reasoning controls, and experimental modes are preserved because the public API does not currently expose the full CMS metadata. Cache prices curated from Gateway's route-level CMS remain stable across syncs until the public contract exposes them. - Route-level cache prices replace curated values field by field. A cache read or write price that the API does not expose remains preserved in the provider TOML, including when `prompt_caching` exposes only its mode. +- `prompt_caching.mode = "none"` explicitly removes preserved cache read and write prices because that route does not cache prompts. +- An explicit `supports_reasoning = false` on the selected vendor route overrides inherited reasoning metadata and removes preserved reasoning controls; supported routes retain curated controls when the API does not enumerate exact values. - Local models missing from the response are retained because API-key policy can affect catalog visibility. ## Cloudflare Workers AI Notes