diff --git a/.github/workflows/sync-models.yml b/.github/workflows/sync-models.yml index 4a06c3cbd2..a9b9cd8a4e 100644 --- a/.github/workflows/sync-models.yml +++ b/.github/workflows/sync-models.yml @@ -74,6 +74,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 c2b7fd4690..c109b1ccc9 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", "nano-gpt:sync": "bun ./packages/core/script/sync-models.ts nano-gpt", "venice:sync": "bun ./packages/core/script/sync-models.ts venice", "vercel:generate": "bun ./packages/core/script/sync-models.ts vercel", diff --git a/packages/core/src/sync/index.ts b/packages/core/src/sync/index.ts index 60b9308ffe..d3b6e84f33 100644 --- a/packages/core/src/sync/index.ts +++ b/packages/core/src/sync/index.ts @@ -19,6 +19,7 @@ import { hyper } from "./providers/hyper.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 { nanoGpt } from "./providers/nano-gpt.js"; import { openai } from "./providers/openai.js"; import { openrouter } from "./providers/openrouter.js"; @@ -121,6 +122,7 @@ export const providers: { huggingface: SyncProvider; kilo: SyncProvider; llmgateway: SyncProvider; + "merge-gateway": SyncProvider; "nano-gpt": SyncProvider; openai: SyncProvider; openrouter: SyncProvider; @@ -145,6 +147,7 @@ export const providers: { huggingface, kilo, llmgateway, + "merge-gateway": mergeGateway, "nano-gpt": nanoGpt, openai, openrouter, @@ -157,7 +160,17 @@ export const providers: { }; export const groups = { - aggregators: ["crossmodel", "empiriolabs", "huggingface", "kilo", "llmgateway", "nano-gpt", "openrouter", "vercel"], + aggregators: [ + "crossmodel", + "empiriolabs", + "huggingface", + "kilo", + "llmgateway", + "merge-gateway", + "nano-gpt", + "openrouter", + "vercel", + ], cloudflare: ["cloudflare-workers-ai"], direct: ["ambient", "anthropic", "baseten", "chutes", "deepinfra", "digitalocean", "google", "hyper", "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..53d5693591 --- /dev/null +++ b/packages/core/src/sync/providers/merge-gateway.ts @@ -0,0 +1,337 @@ +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 VendorReasoning = z.object({ + configurable: z.boolean().optional(), + disable_supported: z.boolean().optional(), + default_enabled: z.boolean().optional(), + controls: z.array(z.string()).optional(), + output_style: z.string().nullable().optional(), +}).passthrough(); + +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(), + supports_reasoning: z.boolean().optional(), + reasoning: VendorReasoning.nullable().optional(), + 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().superRefine((model, context) => { + const namespace = model.model.split("/")[0]; + if (namespace !== model.provider) { + context.addIssue({ + code: z.ZodIssueCode.custom, + path: ["provider"], + message: `Model namespace ${namespace} does not match provider ${model.provider}`, + }); + } +}); + +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) { + if (models.has(model.model)) { + throw new Error(`Merge Gateway returned duplicate model ID: ${model.model}`); + } + 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 }; + } + + // 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"); + 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)[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); + // `supports_reasoning` is not part of the documented public schema + // (PublicVendorModelCapabilities) and is inconsistently populated across + // vendor routes: the same model can report `true` on one route and `false` + // on another (e.g. anthropic/claude-opus-4-6 reports `false` via `anthropic` + // and `true` via `bedrock`), and reasoning-only models such as + // deepseek/deepseek-r1 report `false` on their sole route. Treat it as a + // positive-only signal: `true` (always accompanied by route `reasoning` + // metadata) confirms the model reasons on the gateway, while `false`/absent + // means unknown and preserves curated reasoning metadata. + const routeConfirmsReasoning = Object.values(model.vendors).some( + (vendor) => vendor.availability_status === "available" && vendor.capabilities.supports_reasoning === true, + ); + const reasoning = routeConfirmsReasoning ? true : existing?.reasoning; + const existingReasoningOptions = existing?.reasoning_options ?? []; + const reasoningOptions = reasoning === true && existingReasoningOptions.length === 0 + && selected.info.capabilities.reasoning?.disable_supported === true + ? [{ type: "toggle" as const }] + : reasoning === true + ? existingReasoningOptions + : existing?.reasoning_options; + const modelSlug = model.model.split("/").at(-1)?.toLowerCase(); + const displayNameIsID = model.display_name.includes("/") + || model.display_name.toLowerCase() === modelSlug; + 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 && displayNameIsID ? 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, + reasoning_options: reasoningOptions, + 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, + 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: reasoning ?? false, + reasoning_options: reasoningOptions, + 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; + if (promptCaching?.mode === "none") { + return { read: undefined, write: undefined }; + } + return { + read: promptCaching?.cache_read_cost_per_million + ?? pricing.cache_read_per_million + ?? existing?.cost?.cache_read, + write: promptCaching?.cache_write_cost_per_million + ?? pricing.cache_write_per_million + ?? existing?.cost?.cache_write, + }; +} + +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/src/sync/providers/openrouter.ts b/packages/core/src/sync/providers/openrouter.ts index 9f7e51395a..9ea5d92e16 100644 --- a/packages/core/src/sync/providers/openrouter.ts +++ b/packages/core/src/sync/providers/openrouter.ts @@ -30,10 +30,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" }, "stepfun-ai": { provider: "stepfun", metadata: "stepfun" }, tencent: { provider: "tencent", metadata: "tencent" }, diff --git a/packages/core/test/sync.test.ts b/packages/core/test/sync.test.ts index 0ddfce9097..386fb36e74 100644 --- a/packages/core/test/sync.test.ts +++ b/packages/core/test/sync.test.ts @@ -33,6 +33,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 { buildNanoGptModel, nanoGpt, @@ -1495,6 +1503,23 @@ test("factors OpenRouter Pro routes against canonical OpenAI metadata", () => { expect("release_date" in model).toBe(false); }); +// Ensures Merge Gateway namespaces reuse the matching canonical model metadata. +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"), @@ -1633,6 +1658,376 @@ test("factors aliased LLM Gateway routes against canonical metadata", () => { }); }); +// Ensures catalog pagination preserves authentication and returns every page. +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"]); +}); + +// Prevents pagination overlap from publishing the same model ID twice. +test("rejects duplicate Merge Gateway model IDs across pages", async () => { + const fetcher = ((input: string | URL | Request) => { + const next = String(input).includes("cursor=next-page"); + return Promise.resolve(new Response(JSON.stringify({ + object: "list", + data: [mergeGatewayModel()], + has_more: !next, + next_cursor: next ? null : "next-page", + }))); + }) as typeof fetch; + + expect(fetchMergeGatewayModels(fetcher, "test-key")).rejects.toThrow( + "Merge Gateway returned duplicate model ID: openai/gpt-5.6-sol", + ); +}); + +// Rejects API records whose provider disagrees with the model ID namespace. +test("rejects Merge Gateway provider and model namespace mismatches", () => { + expect(() => MergeGatewayResponse.parse({ + object: "list", + data: [mergeGatewayModel({ provider: "anthropic" })], + has_more: false, + next_cursor: null, + })).toThrow("Model namespace openai does not match provider anthropic"); +}); + +// Keeps audio-capable records valid when the API advertises audio input. +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"); +}); + +// Emits only route-specific overrides when canonical metadata already matches. +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, + }, + }); +}); + +// Protects curated reasoning metadata from an unreliable negative API signal. +test("preserves curated reasoning when Merge Gateway routes report supports_reasoning = false", () => { + // `supports_reasoning = false` is a positive-only signal: the field is + // undocumented in the public schema and inconsistently populated across + // vendor routes, so it must not erase curated reasoning metadata. + 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_options: [{ type: "effort", values: ["low", "medium", "high"] }], + }); + expect(model).not.toMatchObject({ reasoning: false }); +}); + +// Treats a positive signal from any available route as model-level confirmation. +test("confirms reasoning when any available Merge Gateway route reports supports_reasoning = true", () => { + const selected = mergeGatewayVendor(); + selected.capabilities.supports_reasoning = false; + const confirming = mergeGatewayVendor({ + pricing: { currency: "USD", input_per_million: 9, output_per_million: 45 }, + }); + confirming.capabilities.supports_reasoning = true; + confirming.capabilities.reasoning = { + configurable: false, + disable_supported: false, + default_enabled: true, + controls: [], + output_style: "reasoning_content", + }; + const model = buildMergeGatewayModel(mergeGatewayModel({ + vendors: { openai: selected, fireworks: confirming }, + }), { + base_model: "openai/gpt-5.6-sol", + cost: { input: 5, output: 30 }, + }); + + // The model reasons on the gateway with no verified caller control. + expect(model).toMatchObject({ reasoning_options: [] }); + expect(model).not.toMatchObject({ reasoning: false }); +}); + +// Publishes a toggle only when the selected route explicitly supports disabling reasoning. +test("derives a Merge Gateway reasoning toggle when the selected route supports disabling", () => { + const selected = mergeGatewayVendor(); + selected.capabilities.reasoning = { + configurable: true, + disable_supported: true, + default_enabled: true, + controls: ["thinking"], + output_style: "reasoning_content", + }; + const model = buildMergeGatewayModel(mergeGatewayModel({ + vendors: { openai: selected }, + }), { + base_model: "openai/gpt-5.6-sol", + reasoning: true, + reasoning_options: [], + cost: { input: 5, output: 30 }, + }); + + expect(model).toMatchObject({ reasoning_options: [{ type: "toggle" }] }); +}); + +// Prevents deprecated routes from contributing capabilities to an available model. +test("ignores supports_reasoning = true on unavailable Merge Gateway routes", () => { + const selected = mergeGatewayVendor(); + selected.capabilities.supports_reasoning = false; + const deprecated = mergeGatewayVendor({ availability_status: "deprecated" }); + deprecated.capabilities.supports_reasoning = true; + const model = buildMergeGatewayModel(mergeGatewayModel({ + vendors: { openai: selected, legacy: deprecated }, + }), { + base_model: "openai/gpt-5.6-sol", + cost: { input: 5, output: 30 }, + }); + + expect(model).not.toHaveProperty("reasoning_options"); +}); + +// Updates API-provided cache prices without discarding curated cache fields. +test("merges authoritative Merge Gateway cache pricing field by field", () => { + 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, + cache_write: 6.25, + }, + }); +}); + +// Retains curated cache prices when the API confirms caching but omits prices. +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, + }, + }); +}); + +// Removes inherited cache prices when the selected route explicitly disables caching. +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"); +}); + +// Avoids overriding a curated name with a display value that is effectively an ID. +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"); +}); + +// Avoids overriding a curated name with an unformatted model slug. +test("inherits canonical names for slug-shaped Merge Gateway display names", () => { + const model = buildMergeGatewayModel(mergeGatewayModel({ + model: "openai/gpt-oss-safeguard-120b", + display_name: "gpt-oss-safeguard-120b", + vendors: { openai: mergeGatewayVendor() }, + }), undefined); + + expect(model).not.toHaveProperty("name"); +}); + +// Removes a canonical input limit that exceeds the selected route's context window. +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"]); +}); + +// Prefers the model provider's own route over alternate vendors. +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 }, + }); +}); + +// Falls back to the lowest-cost available route when the canonical vendor is absent. +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 } }, + }); +}); + +// Keeps API insertion order deterministic when fallback routes have equal prices. +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" }); +}); + +// Prevents a scoped API response from deleting catalog entries it cannot see. +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: [{ @@ -1954,6 +2349,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 hyperModel(overrides: Partial = {}): HyperModel { return { id: "deepseek-v4-flash", diff --git a/providers/merge-gateway/models/alibaba/qwen3.6-plus.toml b/providers/merge-gateway/models/alibaba/qwen3.6-plus.toml deleted file mode 100644 index 35d0b6af6d..0000000000 --- a/providers/merge-gateway/models/alibaba/qwen3.6-plus.toml +++ /dev/null @@ -1,13 +0,0 @@ -base_model = "alibaba/qwen3.6-plus" - -[[reasoning_options]] -type = "toggle" - -[[reasoning_options]] -type = "budget_tokens" -min = 1 -max = 250_000 - -[cost] -input = 0.5 -output = 3 diff --git a/providers/merge-gateway/models/alibaba/qwen3.7-max.toml b/providers/merge-gateway/models/alibaba/qwen3.7-max.toml deleted file mode 100644 index f7790f827f..0000000000 --- a/providers/merge-gateway/models/alibaba/qwen3.7-max.toml +++ /dev/null @@ -1,13 +0,0 @@ -base_model = "alibaba/qwen3.7-max" - -[[reasoning_options]] -type = "toggle" - -[[reasoning_options]] -type = "budget_tokens" -min = 1 -max = 250_000 - -[cost] -input = 1.65 -output = 4.95 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..d269e4b778 --- /dev/null +++ b/providers/merge-gateway/models/anthropic/claude-3-7-sonnet-20250219.toml @@ -0,0 +1,18 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=anthropic%2Fclaude-3-7-sonnet-20250219 (accessed 2026-07-21) +# 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 = [{ type = "toggle" }, { type = "budget_tokens", min = 1_024, max = 63_999 }] + +[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..cd3581469f --- /dev/null +++ b/providers/merge-gateway/models/anthropic/claude-fable-5.toml @@ -0,0 +1,15 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=anthropic%2Fclaude-fable-5 (accessed 2026-07-21) +# The selected route advertises reasoning.effort and supports disabling reasoning; +# exact effort values are not exposed, so only the verified toggle is listed. + +base_model = "anthropic/claude-fable-5" +structured_output = true + +[[reasoning_options]] +type = "toggle" + +[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..b32556bbac 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,9 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=anthropic%2Fclaude-haiku-4-5-20251001 (accessed 2026-07-21) + base_model = "anthropic/claude-haiku-4-5-20251001" +name = "Claude Haiku 4.5 (20251001)" reasoning_options = [{ type = "toggle" }, { type = "budget_tokens", min = 1_024, max = 63_999 }] +structured_output = true [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..f39052626c 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,9 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=anthropic%2Fclaude-opus-4-1-20250805 (accessed 2026-07-21) + base_model = "anthropic/claude-opus-4-1-20250805" +name = "Claude Opus 4.1 (20250805)" reasoning_options = [{ type = "toggle" }, { type = "budget_tokens", min = 1_024, max = 31_999 }] +structured_output = true [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..88602aae50 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,9 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=anthropic%2Fclaude-opus-4-20250514 (accessed 2026-07-21) + base_model = "anthropic/claude-opus-4-20250514" +name = "Claude Opus 4 (20250514)" reasoning_options = [{ type = "toggle" }, { type = "budget_tokens", min = 1_024, max = 31_999 }] +structured_output = true [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..c472a52abf 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,9 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=anthropic%2Fclaude-opus-4-5-20251101 (accessed 2026-07-21) + base_model = "anthropic/claude-opus-4-5-20251101" +name = "Claude Opus 4.5 (20251101)" reasoning_options = [{ type = "toggle" }, { type = "effort", values = ["low", "medium", "high"] }, { type = "budget_tokens", min = 1_024, max = 63_999 }] +structured_output = true [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..dad3022bc0 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,8 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=anthropic%2Fclaude-opus-4-6 (accessed 2026-07-21) + 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 [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..ba582a88f0 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,8 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=anthropic%2Fclaude-opus-4-7 (accessed 2026-07-21) + base_model = "anthropic/claude-opus-4-7" reasoning_options = [{ type = "toggle" }, { type = "effort", values = ["low", "medium", "high", "xhigh", "max"] }] +structured_output = true [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..d1fe70278e 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,7 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=anthropic%2Fclaude-opus-4-8 (accessed 2026-07-21) + base_model = "anthropic/claude-opus-4-8" +structured_output = true [[reasoning_options]] type = "toggle" @@ -11,3 +14,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..e53a7cc7e3 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,9 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=anthropic%2Fclaude-sonnet-4-5-20250929 (accessed 2026-07-21) + base_model = "anthropic/claude-sonnet-4-5-20250929" +name = "Claude Sonnet 4.5 (20250929)" reasoning_options = [{ type = "toggle" }, { type = "budget_tokens", min = 1_024, max = 63_999 }] +structured_output = true [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..0275ca71de 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,8 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=anthropic%2Fclaude-sonnet-4-6 (accessed 2026-07-21) + 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 [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..4ba9d259a9 --- /dev/null +++ b/providers/merge-gateway/models/anthropic/claude-sonnet-5.toml @@ -0,0 +1,13 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=anthropic%2Fclaude-sonnet-5 (accessed 2026-07-21) +# 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 = [{ type = "toggle" }, { type = "effort", values = ["low", "medium", "high", "xhigh", "max"] }] + +[cost] +input = 2 +output = 10 +cache_read = 0.2 +cache_write = 2.5 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..bb197c39c4 --- /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 (accessed 2026-07-21) + +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..588e728cdf --- /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 (accessed 2026-07-21) + +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..0b944fd765 --- /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 (accessed 2026-07-21) + +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..618e139fb5 --- /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 (accessed 2026-07-21) + +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..3b0c45668b --- /dev/null +++ b/providers/merge-gateway/models/bytedance/dola-seed-2.0-pro.toml @@ -0,0 +1,26 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=bytedance%2Fdola-seed-2.0-pro (accessed 2026-07-21) + +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 = true +temperature = true +tool_call = false +structured_output = false +open_weights = false +reasoning_options = [] + +[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/cohere/command-a-03-2025.toml b/providers/merge-gateway/models/cohere/command-a-03-2025.toml index 35796b0798..2c08c9b924 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,8 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=cohere%2Fcommand-a-03-2025 (accessed 2026-07-21) + 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..e31619e4d2 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,8 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=cohere%2Fcommand-r-08-2024 (accessed 2026-07-21) + 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..93b6fece2e 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,8 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=cohere%2Fcommand-r-plus-08-2024 (accessed 2026-07-21) + 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..9da61741b9 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,8 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=cohere%2Fcommand-r7b-12-2024 (accessed 2026-07-21) + 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..14374d319e --- /dev/null +++ b/providers/merge-gateway/models/deepseek/deepseek-r1.toml @@ -0,0 +1,15 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=deepseek%2Fdeepseek-r1 (accessed 2026-07-21) + +base_model = "deepseek/deepseek-r1" +name = "DeepSeek R1" +reasoning_options = [] +tool_call = false +structured_output = false + +[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..eb9a76c627 100644 --- a/providers/merge-gateway/models/deepseek/deepseek-v4-flash.toml +++ b/providers/merge-gateway/models/deepseek/deepseek-v4-flash.toml @@ -1,5 +1,9 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=deepseek%2Fdeepseek-v4-flash (accessed 2026-07-21) +# Selected route reasoning.controls = ["thinking"], disable_supported = true. + base_model = "deepseek/deepseek-v4-flash" -reasoning_options = [] +structured_output = false +reasoning_options = [{ type = "toggle" }] [interleaved] field = "reasoning_content" diff --git a/providers/merge-gateway/models/deepseek/deepseek-v4-pro.toml b/providers/merge-gateway/models/deepseek/deepseek-v4-pro.toml index a90bf4b82e..2761fd13bc 100644 --- a/providers/merge-gateway/models/deepseek/deepseek-v4-pro.toml +++ b/providers/merge-gateway/models/deepseek/deepseek-v4-pro.toml @@ -1,5 +1,9 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=deepseek%2Fdeepseek-v4-pro (accessed 2026-07-21) +# Selected route reasoning.controls = ["thinking"], disable_supported = true. + base_model = "deepseek/deepseek-v4-pro" -reasoning_options = [] +structured_output = false +reasoning_options = [{ type = "toggle" }] [interleaved] field = "reasoning_content" 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..1479efe777 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,23 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=google%2Fgemini-2.5-flash-lite (accessed 2026-07-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..33cf0f6f73 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,20 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=google%2Fgemini-2.5-flash (accessed 2026-07-21) + 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..4470063cd3 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,11 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=google%2Fgemini-2.5-pro (accessed 2026-07-21) + 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 +17,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..8ae1fb197c 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,16 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=google%2Fgemini-3-flash-preview (accessed 2026-07-21) + 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..998ca69aab 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,17 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=google%2Fgemini-3.1-flash-lite (accessed 2026-07-21) + 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..6ede2cae64 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,10 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=google%2Fgemini-3.1-pro-preview-customtools (accessed 2026-07-21) + 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 +16,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..e0978e4542 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,10 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=google%2Fgemini-3.1-pro-preview (accessed 2026-07-21) + 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 +16,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..1c16b6328b 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,16 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=google%2Fgemini-3.5-flash (accessed 2026-07-21) + 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/gemini-embedding-001.toml b/providers/merge-gateway/models/google/gemini-embedding-001.toml new file mode 100644 index 0000000000..01e3b2dce5 --- /dev/null +++ b/providers/merge-gateway/models/google/gemini-embedding-001.toml @@ -0,0 +1,11 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=google%2Fgemini-embedding-001 (accessed 2026-07-21) + +base_model = "google/gemini-embedding-001" +structured_output = false + +[cost] +input = 0.15 +output = 0 + +[limit] +output = 4_096 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..1228ad522f 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,20 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=google%2Fgemma-4-26b-a4b-it (accessed 2026-07-21) + base_model = "google/gemma-4-26b-a4b-it" -reasoning_options = [{ type = "toggle" }] +name = "Gemma 4 26B-A4B" +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..68a09e360b 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,19 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=google%2Fgemma-4-31b-it (accessed 2026-07-21) + 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..424d70a90d --- /dev/null +++ b/providers/merge-gateway/models/meta/llama-3.3-70b-instruct.toml @@ -0,0 +1,15 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=meta%2Fllama-3.3-70b-instruct (accessed 2026-07-21) + +base_model = "meta/llama-3.3-70b-instruct" +name = "Llama 3.3 70B Instruct" +attachment = false +structured_output = false + +[cost] +input = 0.22 +output = 0.5 +cache_read = 0.11 + +[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 new file mode 100644 index 0000000000..c47d211165 --- /dev/null +++ b/providers/merge-gateway/models/meta/muse-spark-1.1.toml @@ -0,0 +1,17 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=meta%2Fmuse-spark-1.1 (accessed 2026-07-21) + +base_model = "meta/muse-spark-1.1" +structured_output = false +reasoning_options = [] + +[cost] +input = 1.25 +output = 4.25 +cache_read = 0.15 + +[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..87d1dde34e 100644 --- a/providers/merge-gateway/models/minimax/minimax-m2.1.toml +++ b/providers/merge-gateway/models/minimax/minimax-m2.1.toml @@ -1,6 +1,15 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=minimax%2Fminimax-m2.1 (accessed 2026-07-21) + 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..7e4dc4ece1 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,8 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=minimax%2Fminimax-m2.5-highspeed (accessed 2026-07-21) + base_model = "minimax/MiniMax-M2.5-highspeed" +name = "MiniMax M2.5 Highspeed" +structured_output = false reasoning_options = [] [cost] @@ -6,3 +10,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..c2c6eccd75 100644 --- a/providers/merge-gateway/models/minimax/minimax-m2.5.toml +++ b/providers/merge-gateway/models/minimax/minimax-m2.5.toml @@ -1,4 +1,8 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=minimax%2Fminimax-m2.5 (accessed 2026-07-21) + base_model = "minimax/MiniMax-M2.5" +name = "MiniMax M2.5" +structured_output = false reasoning_options = [] [cost] @@ -6,3 +10,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..a8783c47c5 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,8 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=minimax%2Fminimax-m2.7-highspeed (accessed 2026-07-21) + base_model = "minimax/MiniMax-M2.7-highspeed" +name = "MiniMax M2.7 Highspeed" +structured_output = false reasoning_options = [] [cost] @@ -6,3 +10,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..296c2ddf4b 100644 --- a/providers/merge-gateway/models/minimax/minimax-m2.7.toml +++ b/providers/merge-gateway/models/minimax/minimax-m2.7.toml @@ -1,4 +1,8 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=minimax%2Fminimax-m2.7 (accessed 2026-07-21) + base_model = "minimax/MiniMax-M2.7" +name = "MiniMax M2.7" +structured_output = false reasoning_options = [] [cost] @@ -6,3 +10,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..e6f43e7c87 100644 --- a/providers/merge-gateway/models/minimax/minimax-m2.toml +++ b/providers/merge-gateway/models/minimax/minimax-m2.toml @@ -1,6 +1,15 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=minimax%2Fminimax-m2 (accessed 2026-07-21) + 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..ba921d7245 100644 --- a/providers/merge-gateway/models/minimax/minimax-m3.toml +++ b/providers/merge-gateway/models/minimax/minimax-m3.toml @@ -1,4 +1,8 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=minimax%2Fminimax-m3 (accessed 2026-07-21) + base_model = "minimax/MiniMax-M3" +name = "MiniMax M3" +structured_output = false [[reasoning_options]] type = "toggle" @@ -9,5 +13,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..faae35802b 100644 --- a/providers/merge-gateway/models/mistral/devstral-2512.toml +++ b/providers/merge-gateway/models/mistral/devstral-2512.toml @@ -1,6 +1,13 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=mistral%2Fdevstral-2512 (accessed 2026-07-21) + base_model = "mistral/devstral-2512" -status = "deprecated" +structured_output = true [cost] input = 0.4 output = 2 +cache_read = 0.04 + +[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..d5f71ce5bc 100644 --- a/providers/merge-gateway/models/mistral/mistral-large-2512.toml +++ b/providers/merge-gateway/models/mistral/mistral-large-2512.toml @@ -1,5 +1,13 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=mistral%2Fmistral-large-2512 (accessed 2026-07-21) + base_model = "mistral/mistral-large-2512" +structured_output = true [cost] input = 0.5 output = 1.5 +cache_read = 0.05 + +[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..dfea4e4361 100644 --- a/providers/merge-gateway/models/mistral/mistral-medium-2505.toml +++ b/providers/merge-gateway/models/mistral/mistral-medium-2505.toml @@ -1,5 +1,13 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=mistral%2Fmistral-medium-2505 (accessed 2026-07-21) + base_model = "mistral/mistral-medium-2505" +structured_output = true [cost] input = 0.4 output = 2 +cache_read = 0.04 + +[limit] +context = 128_000 +output = 128_000 diff --git a/providers/merge-gateway/models/moonshotai/kimi-k2.5.toml b/providers/merge-gateway/models/moonshot/kimi-k2.5.toml similarity index 55% rename from providers/merge-gateway/models/moonshotai/kimi-k2.5.toml rename to providers/merge-gateway/models/moonshot/kimi-k2.5.toml index cf77522a3f..6a59ee6f7e 100644 --- a/providers/merge-gateway/models/moonshotai/kimi-k2.5.toml +++ b/providers/merge-gateway/models/moonshot/kimi-k2.5.toml @@ -1,4 +1,10 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=moonshot%2Fkimi-k2.5 (accessed 2026-07-21) + base_model = "moonshotai/kimi-k2.5" +attachment = true + +[interleaved] +field = "reasoning_content" [[reasoning_options]] type = "toggle" @@ -8,9 +14,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 57% rename from providers/merge-gateway/models/moonshotai/kimi-k2.6.toml rename to providers/merge-gateway/models/moonshot/kimi-k2.6.toml index 59d14b6a7f..452440b668 100644 --- a/providers/merge-gateway/models/moonshotai/kimi-k2.6.toml +++ b/providers/merge-gateway/models/moonshot/kimi-k2.6.toml @@ -1,5 +1,10 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=moonshot%2Fkimi-k2.6 (accessed 2026-07-21) + base_model = "moonshotai/kimi-k2.6" +[interleaved] +field = "reasoning_content" + [[reasoning_options]] type = "toggle" @@ -8,9 +13,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 53% 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..f0129aa8dd 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,10 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=moonshot%2Fkimi-k2.7-code-highspeed (accessed 2026-07-21) + base_model = "moonshotai/kimi-k2.7-code-highspeed" +[interleaved] +field = "reasoning_content" + [[reasoning_options]] type = "toggle" @@ -8,9 +13,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 54% 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..7909c75370 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,10 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=moonshot%2Fkimi-k2.7-code (accessed 2026-07-21) + base_model = "moonshotai/kimi-k2.7-code" +[interleaved] +field = "reasoning_content" + [[reasoning_options]] type = "toggle" @@ -8,9 +13,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 new file mode 100644 index 0000000000..97a8008a68 --- /dev/null +++ b/providers/merge-gateway/models/nvidia/nemotron-nano-9b-v2.toml @@ -0,0 +1,15 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=nvidia%2Fnemotron-nano-9b-v2 (accessed 2026-07-21) + +base_model = "nvidia/nemotron-nano-9b-v2" +name = "Nemotron Nano 9B" +reasoning_options = [] +tool_call = false +structured_output = false + +[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..cedb0d4038 --- /dev/null +++ b/providers/merge-gateway/models/openai/gpt-3.5-turbo.toml @@ -0,0 +1,8 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=openai%2Fgpt-3.5-turbo (accessed 2026-07-21) + +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..73a5a02904 --- /dev/null +++ b/providers/merge-gateway/models/openai/gpt-4-turbo.toml @@ -0,0 +1,10 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=openai%2Fgpt-4-turbo (accessed 2026-07-21) + +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..8d95c3b13e 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,7 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=openai%2Fgpt-4.1-mini (accessed 2026-07-21) + 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..b761c99296 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,12 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=openai%2Fgpt-4.1-nano (accessed 2026-07-21) + 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.1.toml b/providers/merge-gateway/models/openai/gpt-4.1.toml index 1fdb518f62..f7dc9e2b89 100644 --- a/providers/merge-gateway/models/openai/gpt-4.1.toml +++ b/providers/merge-gateway/models/openai/gpt-4.1.toml @@ -1,3 +1,5 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=openai%2Fgpt-4.1 (accessed 2026-07-21) + base_model = "openai/gpt-4.1" [cost] 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..13e2d563e3 --- /dev/null +++ b/providers/merge-gateway/models/openai/gpt-4.toml @@ -0,0 +1,9 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=openai%2Fgpt-4 (accessed 2026-07-21) + +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..06df984cfd 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,11 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=openai%2Fgpt-4o-2024-05-13 (accessed 2026-07-21) + 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..a6ebb109cb 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 @@ -1,6 +1,11 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=openai%2Fgpt-4o-2024-08-06 (accessed 2026-07-21) + base_model = "openai/gpt-4o-2024-08-06" [cost] 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..00f8adb377 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 @@ -1,6 +1,11 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=openai%2Fgpt-4o-2024-11-20 (accessed 2026-07-21) + base_model = "openai/gpt-4o-2024-11-20" [cost] 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..418dbf5921 100644 --- a/providers/merge-gateway/models/openai/gpt-4o-mini.toml +++ b/providers/merge-gateway/models/openai/gpt-4o-mini.toml @@ -1,4 +1,7 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=openai%2Fgpt-4o-mini (accessed 2026-07-21) + base_model = "openai/gpt-4o-mini" +name = "GPT-4o Mini" [cost] input = 0.15 diff --git a/providers/merge-gateway/models/openai/gpt-4o.toml b/providers/merge-gateway/models/openai/gpt-4o.toml index 1b57e52012..0c687fa6cc 100644 --- a/providers/merge-gateway/models/openai/gpt-4o.toml +++ b/providers/merge-gateway/models/openai/gpt-4o.toml @@ -1,3 +1,5 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=openai%2Fgpt-4o (accessed 2026-07-21) + base_model = "openai/gpt-4o" [cost] 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..b3163c8c70 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,18 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=openai%2Fgpt-5-chat-latest (accessed 2026-07-21) + base_model = "openai/gpt-5-chat-latest" -reasoning_options = [] +base_model_omit = ["limit.input"] +name = "GPT-5 Chat Latest" +reasoning = false [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..b581eb9952 100644 --- a/providers/merge-gateway/models/openai/gpt-5-mini.toml +++ b/providers/merge-gateway/models/openai/gpt-5-mini.toml @@ -1,7 +1,15 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=openai%2Fgpt-5-mini (accessed 2026-07-21) + 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..1696ed22a9 100644 --- a/providers/merge-gateway/models/openai/gpt-5-nano.toml +++ b/providers/merge-gateway/models/openai/gpt-5-nano.toml @@ -1,7 +1,15 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=openai%2Fgpt-5-nano (accessed 2026-07-21) + 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..76e46da03a 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,13 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=openai%2Fgpt-5.1-chat-latest (accessed 2026-07-21) + base_model = "openai/gpt-5.1-chat-latest" -reasoning_options = [] +name = "GPT-5.1 Chat Latest" +reasoning = false [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..b69d656028 100644 --- a/providers/merge-gateway/models/openai/gpt-5.1.toml +++ b/providers/merge-gateway/models/openai/gpt-5.1.toml @@ -1,7 +1,15 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=openai%2Fgpt-5.1 (accessed 2026-07-21) + 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..dc6efbc6d0 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,13 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=openai%2Fgpt-5.2-chat-latest (accessed 2026-07-21) + base_model = "openai/gpt-5.2-chat-latest" -reasoning_options = [] +name = "GPT-5.2 Chat Latest" +reasoning = false [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..10a945fbe1 100644 --- a/providers/merge-gateway/models/openai/gpt-5.2.toml +++ b/providers/merge-gateway/models/openai/gpt-5.2.toml @@ -1,7 +1,15 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=openai%2Fgpt-5.2 (accessed 2026-07-21) + 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..f35e898329 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,12 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=openai%2Fgpt-5.3-chat-latest (accessed 2026-07-21) + 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..6a19d6e63d 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,20 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=openai%2Fgpt-5.4-mini (accessed 2026-07-21) + 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..9ee0ed96cf 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,16 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=openai%2Fgpt-5.4-nano (accessed 2026-07-21) + 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.4.toml b/providers/merge-gateway/models/openai/gpt-5.4.toml index 76ccd302ea..c6591d4b7c 100644 --- a/providers/merge-gateway/models/openai/gpt-5.4.toml +++ b/providers/merge-gateway/models/openai/gpt-5.4.toml @@ -1,3 +1,5 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=openai%2Fgpt-5.4 (accessed 2026-07-21) + base_model = "openai/gpt-5.4" reasoning_options = [{ type = "effort", values = ["none", "low", "medium", "high", "xhigh"] }] diff --git a/providers/merge-gateway/models/openai/gpt-5.5.toml b/providers/merge-gateway/models/openai/gpt-5.5.toml index 9b565dd3a2..5c040bc0fd 100644 --- a/providers/merge-gateway/models/openai/gpt-5.5.toml +++ b/providers/merge-gateway/models/openai/gpt-5.5.toml @@ -1,3 +1,5 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=openai%2Fgpt-5.5 (accessed 2026-07-21) + base_model = "openai/gpt-5.5" reasoning_options = [{ type = "effort", values = ["none", "low", "medium", "high", "xhigh"] }] 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..fd57002965 --- /dev/null +++ b/providers/merge-gateway/models/openai/gpt-5.6-luna.toml @@ -0,0 +1,12 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=openai%2Fgpt-5.6-luna (accessed 2026-07-21) +# 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 = [{ type = "effort", values = ["none", "low", "medium", "high", "xhigh", "max"] }] + +[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..d26085d5b8 --- /dev/null +++ b/providers/merge-gateway/models/openai/gpt-5.6-sol.toml @@ -0,0 +1,14 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=openai%2Fgpt-5.6-sol (accessed 2026-07-21) +# 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..1ee6a1d902 --- /dev/null +++ b/providers/merge-gateway/models/openai/gpt-5.6-terra.toml @@ -0,0 +1,12 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=openai%2Fgpt-5.6-terra (accessed 2026-07-21) +# 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 = [{ type = "effort", values = ["none", "low", "medium", "high", "xhigh", "max"] }] + +[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..4c4758eae1 100644 --- a/providers/merge-gateway/models/openai/gpt-5.toml +++ b/providers/merge-gateway/models/openai/gpt-5.toml @@ -1,7 +1,15 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=openai%2Fgpt-5 (accessed 2026-07-21) + 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..c2d674463d --- /dev/null +++ b/providers/merge-gateway/models/openai/gpt-oss-120b.toml @@ -0,0 +1,15 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=openai%2Fgpt-oss-120b (accessed 2026-07-21) +# Merge Gateway GET /v1/models?model=openai/gpt-oss-120b (accessed 2026-07-16): +# parasail and fireworks routes report `supports_reasoning = true` with +# `configurable = false` and no controls, so the model reasons on the gateway +# but callers have no reasoning control. + +base_model = "openai/gpt-oss-120b" +name = "GPT-OSS 120B" +tool_call = false +structured_output = false +reasoning_options = [] + +[cost] +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 new file mode 100644 index 0000000000..cd05ecea55 --- /dev/null +++ b/providers/merge-gateway/models/openai/gpt-oss-20b.toml @@ -0,0 +1,16 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=openai%2Fgpt-oss-20b (accessed 2026-07-21) +# Merge Gateway GET /v1/models?model=openai/gpt-oss-20b (accessed 2026-07-16): +# routes reporting `supports_reasoning = true` carry `configurable = false` and +# no controls, so the model reasons on the gateway but callers have no +# reasoning control. + +base_model = "openai/gpt-oss-20b" +name = "GPT-OSS 20B" +tool_call = false +structured_output = false +reasoning_options = [] + +[cost] +input = 0.04 +output = 0.2 +cache_read = 0.02 diff --git a/providers/merge-gateway/models/openai/gpt-oss-safeguard-120b.toml b/providers/merge-gateway/models/openai/gpt-oss-safeguard-120b.toml new file mode 100644 index 0000000000..b01b9bd349 --- /dev/null +++ b/providers/merge-gateway/models/openai/gpt-oss-safeguard-120b.toml @@ -0,0 +1,14 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=openai%2Fgpt-oss-safeguard-120b (accessed 2026-07-21) + +base_model = "openai/gpt-oss-safeguard-120b" +tool_call = false +structured_output = false +reasoning_options = [] + +[cost] +input = 0.15 +output = 0.6 + +[limit] +context = 4_096 +output = 4_096 diff --git a/providers/merge-gateway/models/openai/o1.toml b/providers/merge-gateway/models/openai/o1.toml index f1d328f31a..ca36309e40 100644 --- a/providers/merge-gateway/models/openai/o1.toml +++ b/providers/merge-gateway/models/openai/o1.toml @@ -1,3 +1,5 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=openai%2Fo1 (accessed 2026-07-21) + base_model = "openai/o1" reasoning_options = [{ type = "effort", values = ["low", "medium", "high"] }] diff --git a/providers/merge-gateway/models/openai/o3-mini.toml b/providers/merge-gateway/models/openai/o3-mini.toml index 716e4b6e1a..31dd58fec7 100644 --- a/providers/merge-gateway/models/openai/o3-mini.toml +++ b/providers/merge-gateway/models/openai/o3-mini.toml @@ -1,5 +1,11 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=openai%2Fo3-mini (accessed 2026-07-21) + 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/o3.toml b/providers/merge-gateway/models/openai/o3.toml index da90132d61..a9d1e851c3 100644 --- a/providers/merge-gateway/models/openai/o3.toml +++ b/providers/merge-gateway/models/openai/o3.toml @@ -1,3 +1,5 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=openai%2Fo3 (accessed 2026-07-21) + base_model = "openai/o3" reasoning_options = [{ type = "effort", values = ["low", "medium", "high"] }] diff --git a/providers/merge-gateway/models/openai/o4-mini.toml b/providers/merge-gateway/models/openai/o4-mini.toml index 0ff60822de..b2112ce298 100644 --- a/providers/merge-gateway/models/openai/o4-mini.toml +++ b/providers/merge-gateway/models/openai/o4-mini.toml @@ -1,7 +1,13 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=openai%2Fo4-mini (accessed 2026-07-21) + 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..c267bb48d7 --- /dev/null +++ b/providers/merge-gateway/models/qwen/qwen-flash.toml @@ -0,0 +1,16 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=qwen%2Fqwen-flash (accessed 2026-07-21) + +base_model = "alibaba/qwen-flash" +tool_call = false +structured_output = false + +[[reasoning_options]] +type = "toggle" + +[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 new file mode 100644 index 0000000000..aaca52cfa3 --- /dev/null +++ b/providers/merge-gateway/models/qwen/qwen-plus.toml @@ -0,0 +1,16 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=qwen%2Fqwen-plus (accessed 2026-07-21) + +base_model = "alibaba/qwen-plus" +tool_call = false +structured_output = false + +[[reasoning_options]] +type = "toggle" + +[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 new file mode 100644 index 0000000000..8aea9d7833 --- /dev/null +++ b/providers/merge-gateway/models/qwen/qwen3-235b-a22b.toml @@ -0,0 +1,17 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=qwen%2Fqwen3-235b-a22b (accessed 2026-07-21) + +base_model = "alibaba/qwen3-235b-a22b" +name = "Qwen3 235B A22B" +tool_call = false +structured_output = false + +[[reasoning_options]] +type = "toggle" + +[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 new file mode 100644 index 0000000000..86b61eb656 --- /dev/null +++ b/providers/merge-gateway/models/qwen/qwen3-32b.toml @@ -0,0 +1,12 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=qwen%2Fqwen3-32b (accessed 2026-07-21) + +base_model = "alibaba/qwen3-32b" +reasoning_options = [] +structured_output = false + +[cost] +input = 0.15 +output = 0.6 + +[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..804e404a49 --- /dev/null +++ b/providers/merge-gateway/models/qwen/qwen3-coder-480b-a35b-instruct.toml @@ -0,0 +1,13 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=qwen%2Fqwen3-coder-480b-a35b-instruct (accessed 2026-07-21) + +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..00cb0a4cff --- /dev/null +++ b/providers/merge-gateway/models/qwen/qwen3-coder-flash.toml @@ -0,0 +1,13 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=qwen%2Fqwen3-coder-flash (accessed 2026-07-21) + +base_model = "alibaba/qwen3-coder-flash" +tool_call = false +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 new file mode 100644 index 0000000000..fc5728818b --- /dev/null +++ b/providers/merge-gateway/models/qwen/qwen3-coder-plus.toml @@ -0,0 +1,14 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=qwen%2Fqwen3-coder-plus (accessed 2026-07-21) + +base_model = "alibaba/qwen3-coder-plus" +tool_call = false +structured_output = false + +[cost] +input = 0.574 +output = 2.294 +cache_read = 0.1148 + +[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..5856bb59f1 --- /dev/null +++ b/providers/merge-gateway/models/qwen/qwen3-max.toml @@ -0,0 +1,10 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=qwen%2Fqwen3-max (accessed 2026-07-21) + +base_model = "alibaba/qwen3-max" +tool_call = false +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 new file mode 100644 index 0000000000..d00ed2daba --- /dev/null +++ b/providers/merge-gateway/models/qwen/qwen3-next-80b-a3b-instruct.toml @@ -0,0 +1,11 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=qwen%2Fqwen3-next-80b-a3b-instruct (accessed 2026-07-21) + +base_model = "alibaba/qwen3-next-80b-a3b-instruct" +name = "Qwen3 Next 80B A3B Instruct" +tool_call = false +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 new file mode 100644 index 0000000000..af96fc5f6c --- /dev/null +++ b/providers/merge-gateway/models/qwen/qwen3-next-80b-a3b-thinking.toml @@ -0,0 +1,10 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=qwen%2Fqwen3-next-80b-a3b-thinking (accessed 2026-07-21) + +base_model = "alibaba/qwen3-next-80b-a3b-thinking" +reasoning_options = [] +tool_call = false +structured_output = false + +[cost] +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 new file mode 100644 index 0000000000..a00764633f --- /dev/null +++ b/providers/merge-gateway/models/qwen/qwen3-vl-plus.toml @@ -0,0 +1,15 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=qwen%2Fqwen3-vl-plus (accessed 2026-07-21) + +base_model = "alibaba/qwen3-vl-plus" +attachment = true +reasoning_options = [] +tool_call = false +structured_output = false + +[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 new file mode 100644 index 0000000000..ad3a3b8e18 --- /dev/null +++ b/providers/merge-gateway/models/qwen/qwen3.5-122b-a10b.toml @@ -0,0 +1,21 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=qwen%2Fqwen3.5-122b-a10b (accessed 2026-07-21) + +base_model = "alibaba/qwen3.5-122b-a10b" +attachment = false +tool_call = false +structured_output = false + +[[reasoning_options]] +type = "toggle" + +[cost] +input = 0.115 +output = 0.917 +cache_read = 0.023 + +[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..dc8a65f1ac --- /dev/null +++ b/providers/merge-gateway/models/qwen/qwen3.5-27b.toml @@ -0,0 +1,18 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=qwen%2Fqwen3.5-27b (accessed 2026-07-21) + +base_model = "alibaba/qwen3.5-27b" +tool_call = false +structured_output = false +reasoning_options = [] + +[cost] +input = 0.086 +output = 0.688 +cache_read = 0.0172 + +[limit] +context = 256_000 +output = 64_000 + +[modalities] +input = ["text", "image"] 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..fdf33dbf99 --- /dev/null +++ b/providers/merge-gateway/models/qwen/qwen3.5-35b-a3b.toml @@ -0,0 +1,21 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=qwen%2Fqwen3.5-35b-a3b (accessed 2026-07-21) +# Selected route reasoning.controls = ["thinking"], disable_supported = true. + +base_model = "alibaba/qwen3.5-35b-a3b" +name = "Qwen3.5 35B A3B" +attachment = false +reasoning_options = [{ type = "toggle" }] +tool_call = false +structured_output = false + +[cost] +input = 0.057 +output = 0.459 +cache_read = 0.020357 + +[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..5958cb16c4 --- /dev/null +++ b/providers/merge-gateway/models/qwen/qwen3.5-397b-a17b.toml @@ -0,0 +1,21 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=qwen%2Fqwen3.5-397b-a17b (accessed 2026-07-21) +# Selected route reasoning.controls = ["thinking"], disable_supported = true. + +base_model = "alibaba/qwen3.5-397b-a17b" +name = "Qwen3.5 397B A17B" +attachment = false +reasoning_options = [{ type = "toggle" }] +tool_call = false +structured_output = false + +[cost] +input = 0.172 +output = 1.032 +cache_read = 0.0344 + +[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..e499c01fa2 --- /dev/null +++ b/providers/merge-gateway/models/qwen/qwen3.5-9b.toml @@ -0,0 +1,16 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=qwen%2Fqwen3.5-9b (accessed 2026-07-21) + +base_model = "alibaba/qwen3.5-9b" +attachment = true +reasoning_options = [] +structured_output = false + +[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..d0f54b9942 --- /dev/null +++ b/providers/merge-gateway/models/qwen/qwen3.5-plus.toml @@ -0,0 +1,19 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=qwen%2Fqwen3.5-plus (accessed 2026-07-21) + +base_model = "alibaba/qwen3.5-plus" +tool_call = false +structured_output = false + +[[reasoning_options]] +type = "toggle" + +[cost] +input = 0.115 +output = 0.688 +cache_read = 0.023 + +[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..589894f2e0 --- /dev/null +++ b/providers/merge-gateway/models/qwen/qwen3.6-27b.toml @@ -0,0 +1,17 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=qwen%2Fqwen3.6-27b (accessed 2026-07-21) + +base_model = "alibaba/qwen3.6-27b" +reasoning_options = [] +tool_call = false +structured_output = false + +[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..d548955fc6 --- /dev/null +++ b/providers/merge-gateway/models/qwen/qwen3.6-35b-a3b.toml @@ -0,0 +1,18 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=qwen%2Fqwen3.6-35b-a3b (accessed 2026-07-21) + +base_model = "alibaba/qwen3.6-35b-a3b" +name = "Qwen3.6 35B A3B" +attachment = false +tool_call = false +structured_output = false + +[[reasoning_options]] +type = "toggle" + +[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 new file mode 100644 index 0000000000..bbf6ca5ec7 --- /dev/null +++ b/providers/merge-gateway/models/qwen/qwen3.6-flash.toml @@ -0,0 +1,20 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=qwen%2Fqwen3.6-flash (accessed 2026-07-21) + +base_model = "alibaba/qwen3.6-flash" +attachment = false +tool_call = false +structured_output = false + +[[reasoning_options]] +type = "toggle" + +[cost] +input = 0.165 +output = 0.99 +cache_read = 0.033 + +[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..d1b1b36129 --- /dev/null +++ b/providers/merge-gateway/models/qwen/qwen3.6-max-preview.toml @@ -0,0 +1,13 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=qwen%2Fqwen3.6-max-preview (accessed 2026-07-21) + +base_model = "alibaba/qwen3.6-max-preview" +reasoning_options = [] +tool_call = false +structured_output = false + +[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..fe832a7541 --- /dev/null +++ b/providers/merge-gateway/models/qwen/qwen3.6-plus.toml @@ -0,0 +1,18 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=qwen%2Fqwen3.6-plus (accessed 2026-07-21) +# Selected route reasoning.controls = ["thinking"], disable_supported = true. + +base_model = "alibaba/qwen3.6-plus" +reasoning_options = [{ type = "toggle" }] +tool_call = false +structured_output = false + +[cost] +input = 0.276 +output = 1.651 +cache_read = 0.0552 + +[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..b26cf83b54 --- /dev/null +++ b/providers/merge-gateway/models/qwen/qwen3.7-max.toml @@ -0,0 +1,16 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=qwen%2Fqwen3.7-max (accessed 2026-07-21) + +base_model = "alibaba/qwen3.7-max" +tool_call = false +structured_output = false + +[[reasoning_options]] +type = "toggle" + +[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 new file mode 100644 index 0000000000..84c900303d --- /dev/null +++ b/providers/merge-gateway/models/qwen/qwen3.7-plus.toml @@ -0,0 +1,14 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=qwen%2Fqwen3.7-plus (accessed 2026-07-21) + +base_model = "alibaba/qwen3.7-plus" +attachment = true +reasoning_options = [] +tool_call = false +structured_output = false + +[cost] +input = 0.4 +output = 1.6 + +[limit] +output = 65_536 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..6811bc61e5 --- /dev/null +++ b/providers/merge-gateway/models/sakana/fugu-ultra.toml @@ -0,0 +1,12 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=sakana%2Ffugu-ultra (accessed 2026-07-21) + +base_model = "sakana/fugu-ultra" +reasoning_options = [] +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..5b8c94a26b --- /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 (accessed 2026-07-21) + +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..5ded741a14 --- /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 (accessed 2026-07-21) + +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/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..f7ca1018d7 --- /dev/null +++ b/providers/merge-gateway/models/xai/grok-4.20-0309-non-reasoning.toml @@ -0,0 +1,15 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=xai%2Fgrok-4.20-0309-non-reasoning (accessed 2026-07-21) + +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..dacd64d727 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,7 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=xai%2Fgrok-4.20-0309-reasoning (accessed 2026-07-21) + base_model = "xai/grok-4.20-0309-reasoning" +name = "Grok 4.20" reasoning_options = [] [cost] @@ -11,3 +14,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..9ebf40c8f7 100644 --- a/providers/merge-gateway/models/xai/grok-4.3.toml +++ b/providers/merge-gateway/models/xai/grok-4.3.toml @@ -1,5 +1,8 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=xai%2Fgrok-4.3 (accessed 2026-07-21) +# Selected route reasoning.controls = ["reasoning.effort"], disable_supported = true; effort values not exposed. + base_model = "xai/grok-4.3" -reasoning_options = [] +reasoning_options = [{ type = "toggle" }] [cost] input = 1.25 @@ -11,3 +14,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..d1834d708a --- /dev/null +++ b/providers/merge-gateway/models/xai/grok-4.5.toml @@ -0,0 +1,9 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=xai%2Fgrok-4.5 (accessed 2026-07-21) + +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..ca8d567052 --- /dev/null +++ b/providers/merge-gateway/models/xai/grok-build-0.1.toml @@ -0,0 +1,12 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=xai%2Fgrok-build-0.1 (accessed 2026-07-21) + +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..cf057be39e 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,17 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=zai%2Fglm-4.5-air (accessed 2026-07-21) + 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..5a9e2beb7e 100644 --- a/providers/merge-gateway/models/zai/glm-4.5.toml +++ b/providers/merge-gateway/models/zai/glm-4.5.toml @@ -1,8 +1,16 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=zai%2Fglm-4.5 (accessed 2026-07-21) + 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..822f172a0a --- /dev/null +++ b/providers/merge-gateway/models/zai/glm-4.5v.toml @@ -0,0 +1,19 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=zai%2Fglm-4.5v (accessed 2026-07-21) + +base_model = "zhipuai/glm-4.5v" +name = "Glm 4.5V" +reasoning_options = [] +structured_output = false + +[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..68e6573180 100644 --- a/providers/merge-gateway/models/zai/glm-4.6.toml +++ b/providers/merge-gateway/models/zai/glm-4.6.toml @@ -1,8 +1,16 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=zai%2Fglm-4.6 (accessed 2026-07-21) + 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..1974407734 --- /dev/null +++ b/providers/merge-gateway/models/zai/glm-4.7-flash.toml @@ -0,0 +1,13 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=zai%2Fglm-4.7-flash (accessed 2026-07-21) + +base_model = "zhipuai/glm-4.7-flash" +name = "GLM 4.7 Flash" +reasoning_options = [] +structured_output = false + +[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..28d46a80dc 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,11 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=zai%2Fglm-4.7-flashx (accessed 2026-07-21) + 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..0067c6f4b6 100644 --- a/providers/merge-gateway/models/zai/glm-4.7.toml +++ b/providers/merge-gateway/models/zai/glm-4.7.toml @@ -1,11 +1,19 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=zai%2Fglm-4.7 (accessed 2026-07-21) + 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..7551ca6a3c 100644 --- a/providers/merge-gateway/models/zai/glm-5-turbo.toml +++ b/providers/merge-gateway/models/zai/glm-5-turbo.toml @@ -1,9 +1,15 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=zai%2Fglm-5-turbo (accessed 2026-07-21) + 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..7b1830b39a 100644 --- a/providers/merge-gateway/models/zai/glm-5.1.toml +++ b/providers/merge-gateway/models/zai/glm-5.1.toml @@ -1,9 +1,15 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=zai%2Fglm-5.1 (accessed 2026-07-21) + base_model = "zhipuai/glm-5.1" -reasoning_options = [{ type = "toggle" }] +name = "GLM 5.1" +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..f24278b7f9 100644 --- a/providers/merge-gateway/models/zai/glm-5.2.toml +++ b/providers/merge-gateway/models/zai/glm-5.2.toml @@ -1,4 +1,11 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=zai%2Fglm-5.2 (accessed 2026-07-21) + base_model = "zhipuai/glm-5.2" +name = "GLM 5.2" +structured_output = false + +[interleaved] +field = "reasoning_content" [[reasoning_options]] type = "toggle" @@ -8,9 +15,7 @@ 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 +cache_read = 0.195 diff --git a/providers/merge-gateway/models/zai/glm-5.toml b/providers/merge-gateway/models/zai/glm-5.toml index f56566e0a6..c048fb0af3 100644 --- a/providers/merge-gateway/models/zai/glm-5.toml +++ b/providers/merge-gateway/models/zai/glm-5.toml @@ -1,11 +1,19 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=zai%2Fglm-5 (accessed 2026-07-21) + 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/providers/merge-gateway/provider.toml b/providers/merge-gateway/provider.toml index 93c78884b5..7c4c7079e7 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-21): +# - 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 +name = "Merge Gateway" +env = ["MERGE_GATEWAY_API_KEY"] +npm = "merge-gateway-ai-sdk-provider" doc = "https://docs.merge.dev/merge-gateway" diff --git a/sync.md b/sync.md index 9322ba50ba..d99d0c15a5 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. @@ -162,6 +163,17 @@ 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. 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. +- 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`.