diff --git a/.github/workflows/sync-models.yml b/.github/workflows/sync-models.yml index 5edb83859a..0a1bc91169 100644 --- a/.github/workflows/sync-models.yml +++ b/.github/workflows/sync-models.yml @@ -73,6 +73,7 @@ jobs: OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} VENICE_API_KEY: ${{ secrets.VENICE_API_KEY }} LLMGATEWAY_API_KEY: ${{ secrets.LLMGATEWAY_API_KEY }} + MERGE_GATEWAY_API_KEY: ${{ secrets.MERGE_GATEWAY_API_KEY }} KILO_API_KEY: ${{ secrets.KILO_API_KEY }} GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }} GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }} diff --git a/package.json b/package.json index d4cab62ded..3a2159aaac 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "huggingface:sync": "bun ./packages/core/script/sync-models.ts huggingface", "kilo:sync": "bun ./packages/core/script/sync-models.ts kilo", "llmgateway:sync": "bun ./packages/core/script/sync-models.ts llmgateway", + "merge-gateway:sync": "bun ./packages/core/script/sync-models.ts merge-gateway", "venice:sync": "bun ./packages/core/script/sync-models.ts venice", "vercel:generate": "bun ./packages/core/script/sync-models.ts vercel", "wandb:generate": "bun ./packages/core/script/sync-models.ts wandb", diff --git a/packages/core/src/sync/index.ts b/packages/core/src/sync/index.ts index 3b8c8fce97..afc0fc57cc 100644 --- a/packages/core/src/sync/index.ts +++ b/packages/core/src/sync/index.ts @@ -17,6 +17,7 @@ import { google } from "./providers/google.js"; import { huggingface } from "./providers/huggingface.js"; import { kilo } from "./providers/kilo.js"; import { llmgateway } from "./providers/llmgateway.js"; +import { mergeGateway } from "./providers/merge-gateway.js"; import { openai } from "./providers/openai.js"; import { openrouter } from "./providers/openrouter.js"; import { ovhcloud } from "./providers/ovhcloud.js"; @@ -106,6 +107,7 @@ export const providers: { kilo: SyncProvider; huggingface: SyncProvider; llmgateway: SyncProvider; + "merge-gateway": SyncProvider; openai: SyncProvider; openrouter: SyncProvider; ovhcloud: SyncProvider; @@ -128,6 +130,7 @@ export const providers: { kilo, huggingface, llmgateway, + "merge-gateway": mergeGateway, openai, openrouter, ovhcloud, @@ -139,7 +142,7 @@ export const providers: { }; export const groups = { - aggregators: ["crossmodel", "empiriolabs", "huggingface", "kilo", "llmgateway", "openrouter", "vercel"], + aggregators: ["crossmodel", "empiriolabs", "huggingface", "kilo", "llmgateway", "merge-gateway", "openrouter", "vercel"], cloudflare: ["cloudflare-workers-ai"], direct: ["ambient", "anthropic", "baseten", "chutes", "deepinfra", "digitalocean", "google", "openai", "ovhcloud", "pioneer", "venice", "wandb", "xai"], } as const; diff --git a/packages/core/src/sync/providers/merge-gateway.ts b/packages/core/src/sync/providers/merge-gateway.ts new file mode 100644 index 0000000000..4df225a75c --- /dev/null +++ b/packages/core/src/sync/providers/merge-gateway.ts @@ -0,0 +1,294 @@ +import { z } from "zod"; + +import { describeModel } from "../../describe.js"; +import type { ExistingModel, SyncProvider, SyncedFullModel, SyncedModel } from "../index.js"; +import { factorBaseModel, resolveCanonicalBaseModel } from "./openrouter.js"; + +const API_ENDPOINT = "https://api-gateway.merge.dev/v1/models"; + +const AvailabilityStatus = z.enum(["available", "deprecated"]); + +const VendorCapabilities = z.object({ + input: z.array(z.enum(["text", "audio", "image", "document", "embedding"])), + output: z.array(z.enum(["text", "audio", "tool_use", "embedding"])), + supports_tool_calling: z.boolean(), + supports_tool_choice: z.boolean().default(false), + supports_structured_outputs: z.boolean(), + supports_reasoning: z.boolean().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(); + +export const MergeGatewayResponse = z.object({ + object: z.literal("list").default("list"), + data: z.array(MergeGatewayModel), + has_more: z.boolean().default(false), + next_cursor: z.string().nullable().optional(), +}).passthrough(); + +export type MergeGatewayModel = z.infer; +export type MergeGatewayVendor = z.infer; + +export async function fetchMergeGatewayModels( + fetcher: typeof fetch = fetch, + apiKey = process.env.MERGE_GATEWAY_API_KEY, +) { + if (!apiKey) throw new Error("MERGE_GATEWAY_API_KEY is required to sync Merge Gateway models"); + + const models = new Map(); + const cursors = new Set(); + let cursor: string | undefined; + + do { + const url = new URL(API_ENDPOINT); + url.searchParams.set("limit", "500"); + if (cursor !== undefined) url.searchParams.set("cursor", cursor); + + const response = await fetcher(url, { + headers: { Authorization: `Bearer ${apiKey}` }, + }); + if (!response.ok) { + throw new Error(`Merge Gateway request failed: ${response.status} ${response.statusText}`); + } + + const page = MergeGatewayResponse.parse(await response.json()); + for (const model of page.data) models.set(model.model, model); + if (!page.has_more) break; + if (!page.next_cursor) throw new Error("Merge Gateway returned has_more=true without next_cursor"); + if (cursors.has(page.next_cursor)) throw new Error(`Merge Gateway repeated cursor: ${page.next_cursor}`); + cursors.add(page.next_cursor); + cursor = page.next_cursor; + } while (true); + + return { + object: "list" as const, + data: [...models.values()], + has_more: false, + next_cursor: null, + }; +} + +export const mergeGateway = { + id: "merge-gateway", + name: "Merge Gateway", + modelsDir: "providers/merge-gateway/models", + // API-key policy can affect catalog visibility. Retain missing local models + // until Merge exposes an account-independent catalog response. + deleteMissing: false, + sourceID(model) { + return model.model; + }, + skippedNotice(ids) { + if (ids.length === 0) return []; + return [ + `${ids.length} Merge Gateway models were skipped because they are not text models or lack canonical metadata.`, + `Skipped remote IDs: ${ids.map((id) => `\`${id}\``).join(", ")}`, + ]; + }, + missingNotice(paths) { + if (paths.length === 0) return []; + return [ + `${paths.length} local Merge Gateway models were absent from the API response and retained for manual lifecycle review.`, + `Retained local paths: ${paths.map((item) => `\`${item}\``).join(", ")}`, + ]; + }, + fetchModels() { + return fetchMergeGatewayModels(); + }, + parseModels(raw) { + return MergeGatewayResponse.parse(raw).data; + }, + translateModel(model, context) { + const existing = context.existing(model.model); + const translated = buildMergeGatewayModel(model, existing, context.authored(model.model)); + return translated === undefined ? undefined : { id: model.model, model: translated }; + }, +} satisfies SyncProvider; + +export function selectMergeGatewayVendor(model: MergeGatewayModel) { + const canonical = model.vendors[model.provider]; + if (canonical?.availability_status === "available") { + return { id: model.provider, info: canonical }; + } + + // 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); + const routeDisablesReasoning = selected.info.capabilities.supports_reasoning === false; + const reasoning = routeDisablesReasoning ? false : existing?.reasoning; + const reasoningOptions = routeDisablesReasoning ? undefined : existing?.reasoning_options; + const authoritative = { + // Some catalog rows use an upstream org/model ID as display_name. Let + // canonical metadata provide the human-readable name for factored models. + name: baseModel !== undefined && model.display_name.includes("/") ? undefined : model.display_name, + attachment: input.some((value) => value !== "text"), + tool_call: selected.info.capabilities.supports_tool_calling, + structured_output: selected.info.capabilities.supports_structured_outputs, + status, + cost, + limit, + modalities: { input, output }, + }; + + if (baseModel !== undefined) { + return factorBaseModel( + baseModel, + { + ...authoritative, + description: existing?.description, + reasoning, + 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 d35cc3f978..7fe7bac2ad 100644 --- a/packages/core/src/sync/providers/openrouter.ts +++ b/packages/core/src/sync/providers/openrouter.ts @@ -27,10 +27,12 @@ const CANONICAL_PROVIDER_PREFIXES = { "meta-llama": { provider: "llama", metadata: "meta" }, minimax: { provider: "minimax", metadata: "minimax" }, mistralai: { provider: "mistral", metadata: "mistral" }, + moonshot: { provider: "moonshotai", metadata: "moonshotai" }, moonshotai: { provider: "moonshotai", metadata: "moonshotai" }, openai: { provider: "openai", metadata: "openai" }, nvidia: { provider: "nvidia", metadata: "nvidia" }, qwen: { provider: "alibaba", metadata: "alibaba" }, + sakana: { provider: "sakana", metadata: "sakana" }, stepfun: { provider: "stepfun", metadata: "stepfun" }, tencent: { provider: "tencent", metadata: "tencent" }, "x-ai": { provider: "xai", metadata: "xai" }, diff --git a/packages/core/test/sync.test.ts b/packages/core/test/sync.test.ts index d9287ebca8..a7f10ddfd5 100644 --- a/packages/core/test/sync.test.ts +++ b/packages/core/test/sync.test.ts @@ -32,6 +32,14 @@ import { type OpenRouterModel, } from "../src/sync/providers/openrouter.js"; import { buildLLMGatewayModel, type LLMGatewayModel } from "../src/sync/providers/llmgateway.js"; +import { + buildMergeGatewayModel, + fetchMergeGatewayModels, + mergeGateway, + MergeGatewayResponse, + selectMergeGatewayVendor, + type MergeGatewayModel, +} from "../src/sync/providers/merge-gateway.js"; import { openai, parseOpenAIModels } from "../src/sync/providers/openai.js"; import { resolveVeniceBaseModel } from "../src/sync/providers/venice.js"; import { buildVercelModel, vercel } from "../src/sync/providers/vercel.js"; @@ -954,6 +962,22 @@ test("factors OpenRouter Pro routes against canonical OpenAI metadata", () => { expect("release_date" in model).toBe(false); }); +test("resolves Merge Gateway provider aliases to canonical metadata", () => { + expect([ + resolveCanonicalBaseModel("moonshot/kimi-k2.5"), + resolveCanonicalBaseModel("moonshot/kimi-k2.6"), + resolveCanonicalBaseModel("moonshot/kimi-k2.7-code"), + resolveCanonicalBaseModel("moonshot/kimi-k2.7-code-highspeed"), + resolveCanonicalBaseModel("sakana/fugu-ultra"), + ]).toEqual([ + "moonshotai/kimi-k2.5", + "moonshotai/kimi-k2.6", + "moonshotai/kimi-k2.7-code", + "moonshotai/kimi-k2.7-code-highspeed", + "sakana/fugu-ultra", + ]); +}); + test("resolves Venice Pro routes to canonical OpenAI metadata", () => { expect([ resolveVeniceBaseModel("openai-gpt-56-luna-pro", "GPT-5.6 Luna Pro"), @@ -1062,6 +1086,257 @@ test("factors aliased LLM Gateway routes against canonical metadata", () => { }); }); +test("fetches every page of the Merge Gateway catalog", async () => { + const requests: string[] = []; + const authorizations: string[] = []; + const fetcher = ((input: string | URL | Request, init?: RequestInit) => { + const url = String(input); + requests.push(url); + authorizations.push(new Headers(init?.headers).get("Authorization") ?? ""); + const next = url.includes("cursor=next-page"); + return Promise.resolve(new Response(JSON.stringify({ + object: "list", + data: [mergeGatewayModel({ + model: next ? "openai/gpt-5.6-terra" : "openai/gpt-5.6-sol", + display_name: next ? "GPT-5.6 Terra" : "GPT-5.6 Sol", + })], + has_more: !next, + next_cursor: next ? null : "next-page", + }))); + }) as typeof fetch; + + const result = await fetchMergeGatewayModels(fetcher, "test-key"); + + expect(result.data.map((model) => model.model)).toEqual([ + "openai/gpt-5.6-sol", + "openai/gpt-5.6-terra", + ]); + expect(requests).toHaveLength(2); + expect(requests[0]).toContain("limit=500"); + expect(requests[1]).toContain("cursor=next-page"); + expect(authorizations).toEqual(["Bearer test-key", "Bearer test-key"]); +}); + +test("accepts audio modalities from the Merge Gateway catalog", () => { + const model = mergeGatewayModel(); + model.vendors.openai.capabilities.input.push("audio"); + + expect(MergeGatewayResponse.parse({ + object: "list", + data: [model], + has_more: false, + next_cursor: null, + }).data[0]?.vendors.openai.capabilities.input).toContain("audio"); +}); + +test("factors Merge Gateway GPT-5.6 Sol against canonical metadata", () => { + const model = buildMergeGatewayModel(mergeGatewayModel(), undefined); + + expect(model).toEqual({ + base_model: "openai/gpt-5.6-sol", + cost: { + input: 5, + output: 30, + }, + }); +}); + +test("disables reasoning when the selected Merge Gateway route explicitly does not support it", () => { + const vendor = mergeGatewayVendor(); + vendor.capabilities.supports_reasoning = false; + const model = buildMergeGatewayModel(mergeGatewayModel({ + vendors: { openai: vendor }, + }), { + base_model: "openai/gpt-5.6-sol", + reasoning: true, + reasoning_options: [{ type: "effort", values: ["low", "medium", "high"] }], + cost: { input: 5, output: 30 }, + }); + + expect(model).toMatchObject({ + base_model: "openai/gpt-5.6-sol", + reasoning: false, + }); + expect(model).not.toHaveProperty("reasoning_options"); +}); + +test("merges authoritative Merge Gateway cache pricing field by field", () => { + const model = buildMergeGatewayModel(mergeGatewayModel({ + vendors: { + 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, + }, + }); +}); + +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, + }, + }); +}); + +test("removes Merge Gateway cache pricing when prompt caching mode is none", () => { + const model = buildMergeGatewayModel(mergeGatewayModel({ + vendors: { + openai: mergeGatewayVendor({ + prompt_caching: { mode: "none" }, + }), + }, + }), { + base_model: "openai/gpt-5.6-sol", + cost: { + input: 5, + output: 30, + cache_read: 0.5, + cache_write: 6.25, + }, + }); + + expect(model).toMatchObject({ + cost: { input: 5, output: 30 }, + }); + expect(model.cost).not.toHaveProperty("cache_read"); + expect(model.cost).not.toHaveProperty("cache_write"); +}); + +test("inherits canonical names for ID-shaped Merge Gateway display names", () => { + const model = buildMergeGatewayModel(mergeGatewayModel({ + model: "minimax/minimax-m2", + provider: "minimax", + display_name: "MiniMaxAI/MiniMax-M2", + vendors: { minimax: mergeGatewayVendor() }, + }), undefined); + + expect(model).not.toHaveProperty("name"); +}); + +test("omits inherited input limits above the Merge Gateway context", () => { + const model = buildMergeGatewayModel(mergeGatewayModel({ + model: "openai/gpt-5-chat-latest", + display_name: "GPT-5 Chat Latest", + vendors: { + openai: mergeGatewayVendor({ + context_window: 128_000, + max_output_tokens: 16_384, + }), + }, + }), { + base_model: "openai/gpt-5-chat-latest", + limit: { + context: 128_000, + input: 272_000, + output: 16_384, + }, + }, { + base_model: "openai/gpt-5-chat-latest", + limit: { + context: 128_000, + output: 16_384, + }, + }); + + expect(model).toHaveProperty("base_model_omit", ["limit.input"]); +}); + +test("uses the canonical Merge Gateway vendor as the catalog baseline", () => { + const model = mergeGatewayModel({ + vendors: { + azure: mergeGatewayVendor({ context_window: 200_000 }), + openai: mergeGatewayVendor({ context_window: 1_050_000 }), + }, + }); + + expect(selectMergeGatewayVendor(model)).toMatchObject({ + id: "openai", + info: { context_window: 1_050_000 }, + }); +}); + +test("uses Merge Gateway's cheapest fallback route when no canonical route exists", () => { + const model = mergeGatewayModel({ + provider: "qwen", + vendors: { + bedrock: mergeGatewayVendor({ + pricing: { currency: "USD", input_per_million: 0.15, output_per_million: 0.6 }, + }), + alibaba: mergeGatewayVendor({ + pricing: { currency: "USD", input_per_million: 0.287, output_per_million: 0.64 }, + }), + }, + }); + + expect(selectMergeGatewayVendor(model)).toMatchObject({ + id: "bedrock", + info: { pricing: { input_per_million: 0.15, output_per_million: 0.6 } }, + }); +}); + +test("uses Merge Gateway's CMS order to break equal-cost fallback ties", () => { + const model = mergeGatewayModel({ + provider: "qwen", + vendors: { + empiriolabs: mergeGatewayVendor({ + pricing: { currency: "USD", input_per_million: 0.4, output_per_million: 1.6 }, + }), + fireworks: mergeGatewayVendor({ + pricing: { currency: "USD", input_per_million: 0.4, output_per_million: 1.6 }, + }), + }, + }); + + expect(selectMergeGatewayVendor(model)).toMatchObject({ id: "empiriolabs" }); +}); + +test("retains Merge Gateway models missing from an API-key-scoped response", () => { + expect(mergeGateway.deleteMissing).toBe(false); +}); + test("parses Vercel pricing tiers with an implicit zero minimum", () => { const [model] = vercel.parseModels({ data: [{ @@ -1296,6 +1571,44 @@ function llmGatewayModel(overrides: Partial = {}): LLMGatewayMo }; } +function mergeGatewayVendor( + overrides: Partial = {}, +): MergeGatewayModel["vendors"][string] { + return { + launch_date: "2026-07-09", + context_window: 1_050_000, + max_output_tokens: 128_000, + availability_status: "available", + capabilities: { + input: ["text", "image", "document"], + output: ["text", "tool_use"], + supports_tool_calling: true, + supports_tool_choice: true, + supports_structured_outputs: true, + streaming: true, + }, + pricing: { + currency: "USD", + input_per_million: 5, + output_per_million: 30, + }, + ...overrides, + }; +} + +function mergeGatewayModel(overrides: Partial = {}): MergeGatewayModel { + return { + model: "openai/gpt-5.6-sol", + provider: "openai", + display_name: "GPT-5.6 Sol", + vendors: { openai: mergeGatewayVendor() }, + availability_status: "available", + created_at: "2026-07-09T00:00:00Z", + updated_at: "2026-07-09T00:00:00Z", + ...overrides, + }; +} + function openRouterModel(overrides: Partial = {}): OpenRouterModel { return { id: "anthropic/claude-sonnet-5", diff --git a/providers/merge-gateway/models/anthropic/claude-3-7-sonnet-20250219.toml b/providers/merge-gateway/models/anthropic/claude-3-7-sonnet-20250219.toml new file mode 100644 index 0000000000..10113cd6f7 --- /dev/null +++ b/providers/merge-gateway/models/anthropic/claude-3-7-sonnet-20250219.toml @@ -0,0 +1,16 @@ +# 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..eaa41a5da3 --- /dev/null +++ b/providers/merge-gateway/models/anthropic/claude-fable-5.toml @@ -0,0 +1,12 @@ +# Merge Gateway GET /v1/models?model=anthropic/claude-fable-5 (accessed 2026-07-14): +# the only available Anthropic route reports `supports_reasoning = false`, so this +# provider route does not expose the base model's reasoning capability. +base_model = "anthropic/claude-fable-5" +reasoning = false +structured_output = true + +[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..4b543cb668 100644 --- a/providers/merge-gateway/models/anthropic/claude-haiku-4-5-20251001.toml +++ b/providers/merge-gateway/models/anthropic/claude-haiku-4-5-20251001.toml @@ -1,5 +1,7 @@ base_model = "anthropic/claude-haiku-4-5-20251001" -reasoning_options = [{ type = "toggle" }, { type = "budget_tokens", min = 1_024, max = 63_999 }] +name = "Claude Haiku 4.5 (20251001)" +reasoning = false +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..dd3ffc4088 100644 --- a/providers/merge-gateway/models/anthropic/claude-opus-4-1-20250805.toml +++ b/providers/merge-gateway/models/anthropic/claude-opus-4-1-20250805.toml @@ -1,5 +1,7 @@ base_model = "anthropic/claude-opus-4-1-20250805" -reasoning_options = [{ type = "toggle" }, { type = "budget_tokens", min = 1_024, max = 31_999 }] +name = "Claude Opus 4.1 (20250805)" +reasoning = false +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..91211fe012 100644 --- a/providers/merge-gateway/models/anthropic/claude-opus-4-20250514.toml +++ b/providers/merge-gateway/models/anthropic/claude-opus-4-20250514.toml @@ -1,5 +1,7 @@ base_model = "anthropic/claude-opus-4-20250514" -reasoning_options = [{ type = "toggle" }, { type = "budget_tokens", min = 1_024, max = 31_999 }] +name = "Claude Opus 4 (20250514)" +reasoning = false +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..a68a8f006c 100644 --- a/providers/merge-gateway/models/anthropic/claude-opus-4-5-20251101.toml +++ b/providers/merge-gateway/models/anthropic/claude-opus-4-5-20251101.toml @@ -1,5 +1,7 @@ base_model = "anthropic/claude-opus-4-5-20251101" -reasoning_options = [{ type = "toggle" }, { type = "effort", values = ["low", "medium", "high"] }, { type = "budget_tokens", min = 1_024, max = 63_999 }] +name = "Claude Opus 4.5 (20251101)" +reasoning = false +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..81b36cbff0 100644 --- a/providers/merge-gateway/models/anthropic/claude-opus-4-6.toml +++ b/providers/merge-gateway/models/anthropic/claude-opus-4-6.toml @@ -1,5 +1,6 @@ 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 }] +reasoning = false +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..2a438839af 100644 --- a/providers/merge-gateway/models/anthropic/claude-opus-4-7.toml +++ b/providers/merge-gateway/models/anthropic/claude-opus-4-7.toml @@ -1,5 +1,6 @@ base_model = "anthropic/claude-opus-4-7" -reasoning_options = [{ type = "toggle" }, { type = "effort", values = ["low", "medium", "high", "xhigh", "max"] }] +reasoning = false +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..4ef7dcb879 100644 --- a/providers/merge-gateway/models/anthropic/claude-opus-4-8.toml +++ b/providers/merge-gateway/models/anthropic/claude-opus-4-8.toml @@ -1,13 +1,9 @@ base_model = "anthropic/claude-opus-4-8" - -[[reasoning_options]] -type = "toggle" - -[[reasoning_options]] -type = "budget_tokens" -min = 1 -max = 128_000 +reasoning = false +structured_output = true [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..0790c8ef4c 100644 --- a/providers/merge-gateway/models/anthropic/claude-sonnet-4-5-20250929.toml +++ b/providers/merge-gateway/models/anthropic/claude-sonnet-4-5-20250929.toml @@ -1,5 +1,7 @@ base_model = "anthropic/claude-sonnet-4-5-20250929" -reasoning_options = [{ type = "toggle" }, { type = "budget_tokens", min = 1_024, max = 63_999 }] +name = "Claude Sonnet 4.5 (20250929)" +reasoning = false +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..0e668b3f41 100644 --- a/providers/merge-gateway/models/anthropic/claude-sonnet-4-6.toml +++ b/providers/merge-gateway/models/anthropic/claude-sonnet-4-6.toml @@ -1,5 +1,6 @@ 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 }] +reasoning = false +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..0ef763168d --- /dev/null +++ b/providers/merge-gateway/models/anthropic/claude-sonnet-5.toml @@ -0,0 +1,11 @@ +# 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..abbba27194 --- /dev/null +++ b/providers/merge-gateway/models/bytedance/dola-seed-2.0-code-preview.toml @@ -0,0 +1,25 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=bytedance%2Fdola-seed-2.0-code-preview + +name = "Dola Seed 2.0 Code (preview)" +description = "Preview coding model for repository understanding, refactors, and engineering tasks" +family = "seed" +release_date = "2026-03-28" +last_updated = "2026-03-28" +attachment = false +reasoning = false +temperature = true +tool_call = false +structured_output = false +open_weights = false + +[cost] +input = 0.5 +output = 3 + +[limit] +context = 131_072 +output = 32_768 + +[modalities] +input = ["text"] +output = ["text"] diff --git a/providers/merge-gateway/models/bytedance/dola-seed-2.0-code.toml b/providers/merge-gateway/models/bytedance/dola-seed-2.0-code.toml new file mode 100644 index 0000000000..24901bca8a --- /dev/null +++ b/providers/merge-gateway/models/bytedance/dola-seed-2.0-code.toml @@ -0,0 +1,25 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=bytedance%2Fdola-seed-2.0-code + +name = "Seed 2.0 Code" +description = "Coding model for repository understanding, refactors, and agentic engineering tasks" +family = "seed" +release_date = "2026-02-14" +last_updated = "2026-02-14" +attachment = true +reasoning = false +temperature = true +tool_call = false +structured_output = false +open_weights = false + +[cost] +input = 0.4 +output = 2.4 + +[limit] +context = 256_000 +output = 128_000 + +[modalities] +input = ["text", "image"] +output = ["text"] diff --git a/providers/merge-gateway/models/bytedance/dola-seed-2.0-lite.toml b/providers/merge-gateway/models/bytedance/dola-seed-2.0-lite.toml new file mode 100644 index 0000000000..9c2e1aa96b --- /dev/null +++ b/providers/merge-gateway/models/bytedance/dola-seed-2.0-lite.toml @@ -0,0 +1,25 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=bytedance%2Fdola-seed-2.0-lite + +name = "Seed 2.0 Lite" +description = "Efficient Seed model for general chat, analysis, and lightweight production tasks" +family = "seed" +release_date = "2026-02-28" +last_updated = "2026-02-28" +attachment = false +reasoning = false +temperature = true +tool_call = false +structured_output = false +open_weights = false + +[cost] +input = 0.25 +output = 2 + +[limit] +context = 131_072 +output = 32_768 + +[modalities] +input = ["text"] +output = ["text"] diff --git a/providers/merge-gateway/models/bytedance/dola-seed-2.0-mini.toml b/providers/merge-gateway/models/bytedance/dola-seed-2.0-mini.toml new file mode 100644 index 0000000000..b5cea45ca4 --- /dev/null +++ b/providers/merge-gateway/models/bytedance/dola-seed-2.0-mini.toml @@ -0,0 +1,25 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=bytedance%2Fdola-seed-2.0-mini + +name = "Seed 2.0 Mini" +description = "Low-cost Seed model for general chat, extraction, and lightweight production tasks" +family = "seed" +release_date = "2026-02-15" +last_updated = "2026-02-15" +attachment = false +reasoning = false +temperature = true +tool_call = false +structured_output = false +open_weights = false + +[cost] +input = 0.1 +output = 0.4 + +[limit] +context = 131_072 +output = 32_768 + +[modalities] +input = ["text"] +output = ["text"] diff --git a/providers/merge-gateway/models/bytedance/dola-seed-2.0-pro.toml b/providers/merge-gateway/models/bytedance/dola-seed-2.0-pro.toml new file mode 100644 index 0000000000..b990a9d442 --- /dev/null +++ b/providers/merge-gateway/models/bytedance/dola-seed-2.0-pro.toml @@ -0,0 +1,25 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=bytedance%2Fdola-seed-2.0-pro + +name = "Seed 2.0 Pro" +description = "Higher-capability Seed model for complex chat, analysis, and production tasks" +family = "seed" +release_date = "2026-03-28" +last_updated = "2026-03-28" +attachment = false +reasoning = false +temperature = true +tool_call = false +structured_output = false +open_weights = false + +[cost] +input = 0.5 +output = 3 + +[limit] +context = 131_072 +output = 32_768 + +[modalities] +input = ["text"] +output = ["text"] diff --git a/providers/merge-gateway/models/cohere/command-a-03-2025.toml b/providers/merge-gateway/models/cohere/command-a-03-2025.toml index 35796b0798..663193e136 100644 --- a/providers/merge-gateway/models/cohere/command-a-03-2025.toml +++ b/providers/merge-gateway/models/cohere/command-a-03-2025.toml @@ -1,4 +1,6 @@ base_model = "cohere/command-a-03-2025" +name = "Command A 03-2025" +structured_output = true [cost] input = 2.5 diff --git a/providers/merge-gateway/models/cohere/command-r-08-2024.toml b/providers/merge-gateway/models/cohere/command-r-08-2024.toml index 5b6e7da099..481c8c3467 100644 --- a/providers/merge-gateway/models/cohere/command-r-08-2024.toml +++ b/providers/merge-gateway/models/cohere/command-r-08-2024.toml @@ -1,4 +1,6 @@ base_model = "cohere/command-r-08-2024" +name = "Command R 08-2024" +structured_output = true [cost] input = 0.15 diff --git a/providers/merge-gateway/models/cohere/command-r-plus-08-2024.toml b/providers/merge-gateway/models/cohere/command-r-plus-08-2024.toml index 419d99d79c..edb51176f7 100644 --- a/providers/merge-gateway/models/cohere/command-r-plus-08-2024.toml +++ b/providers/merge-gateway/models/cohere/command-r-plus-08-2024.toml @@ -1,4 +1,6 @@ base_model = "cohere/command-r-plus-08-2024" +name = "Command R+ 08-2024" +structured_output = true [cost] input = 2.5 diff --git a/providers/merge-gateway/models/cohere/command-r7b-12-2024.toml b/providers/merge-gateway/models/cohere/command-r7b-12-2024.toml index 815678c3b3..7a77f4353c 100644 --- a/providers/merge-gateway/models/cohere/command-r7b-12-2024.toml +++ b/providers/merge-gateway/models/cohere/command-r7b-12-2024.toml @@ -1,4 +1,6 @@ base_model = "cohere/command-r7b-12-2024" +name = "Command R7B 12-2024" +structured_output = true [cost] input = 0.0375 diff --git a/providers/merge-gateway/models/deepseek/deepseek-r1.toml b/providers/merge-gateway/models/deepseek/deepseek-r1.toml new file mode 100644 index 0000000000..669e074a17 --- /dev/null +++ b/providers/merge-gateway/models/deepseek/deepseek-r1.toml @@ -0,0 +1,13 @@ +base_model = "deepseek/deepseek-r1" +name = "DeepSeek R1" +reasoning = false +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..12be6ee001 100644 --- a/providers/merge-gateway/models/deepseek/deepseek-v4-flash.toml +++ b/providers/merge-gateway/models/deepseek/deepseek-v4-flash.toml @@ -1,4 +1,5 @@ base_model = "deepseek/deepseek-v4-flash" +structured_output = false reasoning_options = [] [interleaved] diff --git a/providers/merge-gateway/models/deepseek/deepseek-v4-pro.toml b/providers/merge-gateway/models/deepseek/deepseek-v4-pro.toml index a90bf4b82e..cd7f2ca5bd 100644 --- a/providers/merge-gateway/models/deepseek/deepseek-v4-pro.toml +++ b/providers/merge-gateway/models/deepseek/deepseek-v4-pro.toml @@ -1,4 +1,5 @@ base_model = "deepseek/deepseek-v4-pro" +structured_output = false reasoning_options = [] [interleaved] diff --git a/providers/merge-gateway/models/google/gemini-2.5-flash-lite.toml b/providers/merge-gateway/models/google/gemini-2.5-flash-lite.toml index 99ae99972c..3905bebf13 100644 --- a/providers/merge-gateway/models/google/gemini-2.5-flash-lite.toml +++ b/providers/merge-gateway/models/google/gemini-2.5-flash-lite.toml @@ -1,8 +1,21 @@ base_model = "google/gemini-2.5-flash-lite" -reasoning_options = [{ type = "toggle" }, { type = "budget_tokens", min = 512, max = 24_576 }] + +[[reasoning_options]] +type = "toggle" + +[[reasoning_options]] +type = "budget_tokens" +min = 512 +max = 24_576 [cost] input = 0.1 output = 0.4 cache_read = 0.01 input_audio = 0.3 + +[limit] +context = 1_000_000 + +[modalities] +input = ["text", "image", "audio", "pdf"] diff --git a/providers/merge-gateway/models/google/gemini-2.5-flash.toml b/providers/merge-gateway/models/google/gemini-2.5-flash.toml index 49ba05adc1..7248eeda32 100644 --- a/providers/merge-gateway/models/google/gemini-2.5-flash.toml +++ b/providers/merge-gateway/models/google/gemini-2.5-flash.toml @@ -1,8 +1,18 @@ base_model = "google/gemini-2.5-flash" -reasoning_options = [{ type = "toggle" }, { type = "budget_tokens", min = 0, max = 24_576 }] + +[[reasoning_options]] +type = "toggle" + +[[reasoning_options]] +type = "budget_tokens" +min = 0 +max = 24_576 [cost] input = 0.3 output = 2.5 cache_read = 0.03 input_audio = 1 + +[modalities] +input = ["text", "image", "audio", "pdf"] diff --git a/providers/merge-gateway/models/google/gemini-2.5-pro.toml b/providers/merge-gateway/models/google/gemini-2.5-pro.toml index d5848f8ab3..273ccacf39 100644 --- a/providers/merge-gateway/models/google/gemini-2.5-pro.toml +++ b/providers/merge-gateway/models/google/gemini-2.5-pro.toml @@ -1,5 +1,9 @@ base_model = "google/gemini-2.5-pro" -reasoning_options = [{ type = "budget_tokens", min = 128, max = 32_768 }] + +[[reasoning_options]] +type = "budget_tokens" +min = 128 +max = 32_768 [cost] input = 1.25 @@ -11,3 +15,6 @@ tier = { type = "context", size = 200_000 } input = 2.5 output = 15 cache_read = 0.25 + +[modalities] +input = ["text", "image", "audio", "pdf"] diff --git a/providers/merge-gateway/models/google/gemini-3-flash-preview.toml b/providers/merge-gateway/models/google/gemini-3-flash-preview.toml index 56a17f3920..b8de1e8967 100644 --- a/providers/merge-gateway/models/google/gemini-3-flash-preview.toml +++ b/providers/merge-gateway/models/google/gemini-3-flash-preview.toml @@ -1,8 +1,14 @@ base_model = "google/gemini-3-flash-preview" -reasoning_options = [{ type = "effort", values = ["minimal", "low", "medium", "high"] }] + +[[reasoning_options]] +type = "effort" +values = ["minimal", "low", "medium", "high"] [cost] input = 0.5 output = 3 cache_read = 0.05 input_audio = 1 + +[modalities] +input = ["text", "image"] diff --git a/providers/merge-gateway/models/google/gemini-3.1-flash-lite.toml b/providers/merge-gateway/models/google/gemini-3.1-flash-lite.toml index d9d9b5d7dd..5c8f0f8a15 100644 --- a/providers/merge-gateway/models/google/gemini-3.1-flash-lite.toml +++ b/providers/merge-gateway/models/google/gemini-3.1-flash-lite.toml @@ -1,8 +1,15 @@ base_model = "google/gemini-3.1-flash-lite" -reasoning_options = [{ type = "effort", values = ["minimal", "low", "medium", "high"] }] +name = "Gemini 3.1 Flash-Lite" + +[[reasoning_options]] +type = "effort" +values = ["minimal", "low", "medium", "high"] [cost] input = 0.25 output = 1.5 cache_read = 0.025 input_audio = 0.5 + +[modalities] +input = ["text", "image", "audio", "pdf"] diff --git a/providers/merge-gateway/models/google/gemini-3.1-pro-preview-customtools.toml b/providers/merge-gateway/models/google/gemini-3.1-pro-preview-customtools.toml index 6669e542fc..a4183e8302 100644 --- a/providers/merge-gateway/models/google/gemini-3.1-pro-preview-customtools.toml +++ b/providers/merge-gateway/models/google/gemini-3.1-pro-preview-customtools.toml @@ -1,5 +1,8 @@ base_model = "google/gemini-3.1-pro-preview-customtools" -reasoning_options = [{ type = "effort", values = ["low", "medium", "high"] }] + +[[reasoning_options]] +type = "effort" +values = ["low", "medium", "high"] [cost] input = 2 @@ -11,3 +14,6 @@ tier = { type = "context", size = 200_000 } input = 4 output = 18 cache_read = 0.4 + +[modalities] +input = ["text", "image", "audio", "pdf"] diff --git a/providers/merge-gateway/models/google/gemini-3.1-pro-preview.toml b/providers/merge-gateway/models/google/gemini-3.1-pro-preview.toml index e2b3bf54f8..7c4de40066 100644 --- a/providers/merge-gateway/models/google/gemini-3.1-pro-preview.toml +++ b/providers/merge-gateway/models/google/gemini-3.1-pro-preview.toml @@ -1,5 +1,8 @@ base_model = "google/gemini-3.1-pro-preview" -reasoning_options = [{ type = "effort", values = ["low", "medium", "high"] }] + +[[reasoning_options]] +type = "effort" +values = ["low", "medium", "high"] [cost] input = 2 @@ -11,3 +14,6 @@ tier = { type = "context", size = 200_000 } input = 4 output = 18 cache_read = 0.4 + +[modalities] +input = ["text", "image", "audio", "pdf"] diff --git a/providers/merge-gateway/models/google/gemini-3.5-flash.toml b/providers/merge-gateway/models/google/gemini-3.5-flash.toml index 0d75d4a0d3..ef2d78e676 100644 --- a/providers/merge-gateway/models/google/gemini-3.5-flash.toml +++ b/providers/merge-gateway/models/google/gemini-3.5-flash.toml @@ -1,8 +1,14 @@ base_model = "google/gemini-3.5-flash" -reasoning_options = [{ type = "effort", values = ["minimal", "low", "medium", "high"] }] + +[[reasoning_options]] +type = "effort" +values = ["minimal", "low", "medium", "high"] [cost] input = 1.5 output = 9 cache_read = 0.15 input_audio = 1.5 + +[modalities] +input = ["text", "image", "audio", "pdf"] diff --git a/providers/merge-gateway/models/google/gemma-4-26b-a4b-it.toml b/providers/merge-gateway/models/google/gemma-4-26b-a4b-it.toml index a2c94934dc..0814497dc9 100644 --- a/providers/merge-gateway/models/google/gemma-4-26b-a4b-it.toml +++ b/providers/merge-gateway/models/google/gemma-4-26b-a4b-it.toml @@ -1,2 +1,15 @@ base_model = "google/gemma-4-26b-a4b-it" -reasoning_options = [{ type = "toggle" }] +attachment = false +reasoning = false +tool_call = false +structured_output = false + +[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..1595362736 100644 --- a/providers/merge-gateway/models/google/gemma-4-31b-it.toml +++ b/providers/merge-gateway/models/google/gemma-4-31b-it.toml @@ -1,2 +1,15 @@ base_model = "google/gemma-4-31b-it" -reasoning_options = [{ type = "toggle" }] +attachment = false +reasoning = false +tool_call = false +structured_output = false + +[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..c4416d75b9 --- /dev/null +++ b/providers/merge-gateway/models/meta/llama-3.3-70b-instruct.toml @@ -0,0 +1,11 @@ +base_model = "meta/llama-3.3-70b-instruct" +attachment = false +structured_output = false + +[cost] +input = 0.22 +output = 0.5 + +[limit] +context = 131_072 +output = 32_768 diff --git a/providers/merge-gateway/models/meta/muse-spark-1.1.toml b/providers/merge-gateway/models/meta/muse-spark-1.1.toml new file mode 100644 index 0000000000..d1ed3666ff --- /dev/null +++ b/providers/merge-gateway/models/meta/muse-spark-1.1.toml @@ -0,0 +1,15 @@ +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..0a6d4752dc 100644 --- a/providers/merge-gateway/models/minimax/minimax-m2.1.toml +++ b/providers/merge-gateway/models/minimax/minimax-m2.1.toml @@ -1,6 +1,13 @@ base_model = "minimax/MiniMax-M2.1" +name = "MiniMax M2.1" +structured_output = false reasoning_options = [] [cost] input = 0.3 output = 1.2 +cache_read = 0.03 +cache_write = 0.375 + +[limit] +output = 8_192 diff --git a/providers/merge-gateway/models/minimax/minimax-m2.5-highspeed.toml b/providers/merge-gateway/models/minimax/minimax-m2.5-highspeed.toml index d3be98c0fa..f37846f4fd 100644 --- a/providers/merge-gateway/models/minimax/minimax-m2.5-highspeed.toml +++ b/providers/merge-gateway/models/minimax/minimax-m2.5-highspeed.toml @@ -1,4 +1,6 @@ base_model = "minimax/MiniMax-M2.5-highspeed" +name = "MiniMax M2.5 Highspeed" +structured_output = false reasoning_options = [] [cost] @@ -6,3 +8,6 @@ input = 0.6 output = 2.4 cache_read = 0.06 cache_write = 0.375 + +[limit] +output = 8_192 diff --git a/providers/merge-gateway/models/minimax/minimax-m2.5.toml b/providers/merge-gateway/models/minimax/minimax-m2.5.toml index b884c3c158..f8b037d4b2 100644 --- a/providers/merge-gateway/models/minimax/minimax-m2.5.toml +++ b/providers/merge-gateway/models/minimax/minimax-m2.5.toml @@ -1,4 +1,6 @@ base_model = "minimax/MiniMax-M2.5" +name = "MiniMax M2.5" +structured_output = false reasoning_options = [] [cost] @@ -6,3 +8,6 @@ input = 0.3 output = 1.2 cache_read = 0.03 cache_write = 0.375 + +[limit] +output = 8_192 diff --git a/providers/merge-gateway/models/minimax/minimax-m2.7-highspeed.toml b/providers/merge-gateway/models/minimax/minimax-m2.7-highspeed.toml index 1539589db9..4212380399 100644 --- a/providers/merge-gateway/models/minimax/minimax-m2.7-highspeed.toml +++ b/providers/merge-gateway/models/minimax/minimax-m2.7-highspeed.toml @@ -1,4 +1,6 @@ base_model = "minimax/MiniMax-M2.7-highspeed" +name = "MiniMax M2.7 Highspeed" +structured_output = false reasoning_options = [] [cost] @@ -6,3 +8,6 @@ input = 0.6 output = 2.4 cache_read = 0.06 cache_write = 0.375 + +[limit] +output = 8_192 diff --git a/providers/merge-gateway/models/minimax/minimax-m2.7.toml b/providers/merge-gateway/models/minimax/minimax-m2.7.toml index d02224d535..287dd2e59c 100644 --- a/providers/merge-gateway/models/minimax/minimax-m2.7.toml +++ b/providers/merge-gateway/models/minimax/minimax-m2.7.toml @@ -1,4 +1,6 @@ base_model = "minimax/MiniMax-M2.7" +name = "MiniMax M2.7" +structured_output = false reasoning_options = [] [cost] @@ -6,3 +8,6 @@ input = 0.3 output = 1.2 cache_read = 0.06 cache_write = 0.375 + +[limit] +output = 8_192 diff --git a/providers/merge-gateway/models/minimax/minimax-m2.toml b/providers/merge-gateway/models/minimax/minimax-m2.toml index dd2a899f2a..b4aba3d972 100644 --- a/providers/merge-gateway/models/minimax/minimax-m2.toml +++ b/providers/merge-gateway/models/minimax/minimax-m2.toml @@ -1,6 +1,13 @@ base_model = "minimax/MiniMax-M2" +structured_output = false reasoning_options = [] [cost] input = 0.3 output = 1.2 +cache_read = 0.03 +cache_write = 0.375 + +[limit] +context = 204_800 +output = 8_192 diff --git a/providers/merge-gateway/models/minimax/minimax-m3.toml b/providers/merge-gateway/models/minimax/minimax-m3.toml index bb651110ea..db8f8f5f02 100644 --- a/providers/merge-gateway/models/minimax/minimax-m3.toml +++ b/providers/merge-gateway/models/minimax/minimax-m3.toml @@ -1,4 +1,6 @@ base_model = "minimax/MiniMax-M3" +name = "MiniMax M3" +structured_output = false [[reasoning_options]] type = "toggle" @@ -9,5 +11,12 @@ min = 1 max = 128_000 [cost] -input = 0.6 -output = 2.4 +input = 0.3 +output = 1.2 +cache_read = 0.06 + +[limit] +context = 1_000_000 + +[modalities] +input = ["text", "image"] diff --git a/providers/merge-gateway/models/mistral/devstral-2512.toml b/providers/merge-gateway/models/mistral/devstral-2512.toml index a42bb7446c..5be5751c96 100644 --- a/providers/merge-gateway/models/mistral/devstral-2512.toml +++ b/providers/merge-gateway/models/mistral/devstral-2512.toml @@ -1,6 +1,10 @@ base_model = "mistral/devstral-2512" -status = "deprecated" +structured_output = true [cost] input = 0.4 output = 2 + +[limit] +context = 256_000 +output = 256_000 diff --git a/providers/merge-gateway/models/mistral/mistral-large-2512.toml b/providers/merge-gateway/models/mistral/mistral-large-2512.toml index 49df75a634..98e5a5fac0 100644 --- a/providers/merge-gateway/models/mistral/mistral-large-2512.toml +++ b/providers/merge-gateway/models/mistral/mistral-large-2512.toml @@ -1,5 +1,10 @@ base_model = "mistral/mistral-large-2512" +structured_output = true [cost] input = 0.5 output = 1.5 + +[limit] +context = 256_000 +output = 256_000 diff --git a/providers/merge-gateway/models/mistral/mistral-medium-2505.toml b/providers/merge-gateway/models/mistral/mistral-medium-2505.toml index 24ec3b4fa5..6816500cc2 100644 --- a/providers/merge-gateway/models/mistral/mistral-medium-2505.toml +++ b/providers/merge-gateway/models/mistral/mistral-medium-2505.toml @@ -1,5 +1,10 @@ base_model = "mistral/mistral-medium-2505" +structured_output = true [cost] input = 0.4 output = 2 + +[limit] +context = 128_000 +output = 128_000 diff --git a/providers/merge-gateway/models/moonshotai/kimi-k2.5.toml b/providers/merge-gateway/models/moonshot/kimi-k2.5.toml similarity index 74% rename from providers/merge-gateway/models/moonshotai/kimi-k2.5.toml rename to providers/merge-gateway/models/moonshot/kimi-k2.5.toml index cf77522a3f..41fabf109c 100644 --- a/providers/merge-gateway/models/moonshotai/kimi-k2.5.toml +++ b/providers/merge-gateway/models/moonshot/kimi-k2.5.toml @@ -1,4 +1,8 @@ base_model = "moonshotai/kimi-k2.5" +attachment = true + +[interleaved] +field = "reasoning_content" [[reasoning_options]] type = "toggle" @@ -8,9 +12,10 @@ type = "budget_tokens" min = 1 max = 262_144 -[interleaved] -field = "reasoning_content" - [cost] input = 0.6 output = 3 +cache_read = 0.1 + +[modalities] +input = ["text", "image"] diff --git a/providers/merge-gateway/models/moonshotai/kimi-k2.6.toml b/providers/merge-gateway/models/moonshot/kimi-k2.6.toml similarity index 78% rename from providers/merge-gateway/models/moonshotai/kimi-k2.6.toml rename to providers/merge-gateway/models/moonshot/kimi-k2.6.toml index 59d14b6a7f..2ce0ba3019 100644 --- a/providers/merge-gateway/models/moonshotai/kimi-k2.6.toml +++ b/providers/merge-gateway/models/moonshot/kimi-k2.6.toml @@ -1,5 +1,8 @@ base_model = "moonshotai/kimi-k2.6" +[interleaved] +field = "reasoning_content" + [[reasoning_options]] type = "toggle" @@ -8,9 +11,10 @@ type = "budget_tokens" min = 1 max = 262_144 -[interleaved] -field = "reasoning_content" - [cost] input = 0.95 output = 4 +cache_read = 0.16 + +[modalities] +input = ["text", "image"] diff --git a/providers/merge-gateway/models/moonshotai/kimi-k2.7-code-highspeed.toml b/providers/merge-gateway/models/moonshot/kimi-k2.7-code-highspeed.toml similarity index 73% rename from providers/merge-gateway/models/moonshotai/kimi-k2.7-code-highspeed.toml rename to providers/merge-gateway/models/moonshot/kimi-k2.7-code-highspeed.toml index fbc261f9eb..97b6f81d47 100644 --- a/providers/merge-gateway/models/moonshotai/kimi-k2.7-code-highspeed.toml +++ b/providers/merge-gateway/models/moonshot/kimi-k2.7-code-highspeed.toml @@ -1,5 +1,8 @@ base_model = "moonshotai/kimi-k2.7-code-highspeed" +[interleaved] +field = "reasoning_content" + [[reasoning_options]] type = "toggle" @@ -8,9 +11,13 @@ type = "budget_tokens" min = 1 max = 32_768 -[interleaved] -field = "reasoning_content" - [cost] input = 1.9 output = 8 +cache_read = 0.38 + +[limit] +output = 32_768 + +[modalities] +input = ["text", "image"] diff --git a/providers/merge-gateway/models/moonshotai/kimi-k2.7-code.toml b/providers/merge-gateway/models/moonshot/kimi-k2.7-code.toml similarity index 72% rename from providers/merge-gateway/models/moonshotai/kimi-k2.7-code.toml rename to providers/merge-gateway/models/moonshot/kimi-k2.7-code.toml index 9286e04bc6..d2d7dd319a 100644 --- a/providers/merge-gateway/models/moonshotai/kimi-k2.7-code.toml +++ b/providers/merge-gateway/models/moonshot/kimi-k2.7-code.toml @@ -1,5 +1,8 @@ base_model = "moonshotai/kimi-k2.7-code" +[interleaved] +field = "reasoning_content" + [[reasoning_options]] type = "toggle" @@ -8,9 +11,13 @@ type = "budget_tokens" min = 1 max = 32_768 -[interleaved] -field = "reasoning_content" - [cost] input = 0.95 output = 4 +cache_read = 0.19 + +[limit] +output = 32_768 + +[modalities] +input = ["text", "image"] diff --git a/providers/merge-gateway/models/moonshotai/kimi-k2-thinking.toml b/providers/merge-gateway/models/moonshotai/kimi-k2-thinking.toml index dfc8f5290b..117e4fd856 100644 --- a/providers/merge-gateway/models/moonshotai/kimi-k2-thinking.toml +++ b/providers/merge-gateway/models/moonshotai/kimi-k2-thinking.toml @@ -1,4 +1,5 @@ base_model = "moonshotai/kimi-k2-thinking" +status = "deprecated" [[reasoning_options]] type = "toggle" diff --git a/providers/merge-gateway/models/nvidia/nemotron-nano-9b-v2.toml b/providers/merge-gateway/models/nvidia/nemotron-nano-9b-v2.toml new file mode 100644 index 0000000000..479e511a4b --- /dev/null +++ b/providers/merge-gateway/models/nvidia/nemotron-nano-9b-v2.toml @@ -0,0 +1,13 @@ +base_model = "nvidia/nemotron-nano-9b-v2" +name = "Nemotron Nano 9B" +reasoning = false +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..de8ddba9d0 --- /dev/null +++ b/providers/merge-gateway/models/openai/gpt-3.5-turbo.toml @@ -0,0 +1,6 @@ +base_model = "openai/gpt-3.5-turbo" +name = "GPT-3.5 Turbo" + +[cost] +input = 0.5 +output = 1.5 diff --git a/providers/merge-gateway/models/openai/gpt-4-turbo.toml b/providers/merge-gateway/models/openai/gpt-4-turbo.toml new file mode 100644 index 0000000000..ac792634f8 --- /dev/null +++ b/providers/merge-gateway/models/openai/gpt-4-turbo.toml @@ -0,0 +1,8 @@ +base_model = "openai/gpt-4-turbo" + +[cost] +input = 10 +output = 30 + +[modalities] +input = ["text", "image", "pdf"] diff --git a/providers/merge-gateway/models/openai/gpt-4.1-mini.toml b/providers/merge-gateway/models/openai/gpt-4.1-mini.toml index b2d9217542..a6b4371ba1 100644 --- a/providers/merge-gateway/models/openai/gpt-4.1-mini.toml +++ b/providers/merge-gateway/models/openai/gpt-4.1-mini.toml @@ -1,4 +1,5 @@ base_model = "openai/gpt-4.1-mini" +name = "GPT-4.1 Mini" [cost] input = 0.4 diff --git a/providers/merge-gateway/models/openai/gpt-4.1-nano.toml b/providers/merge-gateway/models/openai/gpt-4.1-nano.toml index f85c094770..5deee39d9b 100644 --- a/providers/merge-gateway/models/openai/gpt-4.1-nano.toml +++ b/providers/merge-gateway/models/openai/gpt-4.1-nano.toml @@ -1,6 +1,10 @@ base_model = "openai/gpt-4.1-nano" +name = "GPT-4.1 Nano" [cost] input = 0.1 output = 0.4 cache_read = 0.025 + +[modalities] +input = ["text", "image", "pdf"] diff --git a/providers/merge-gateway/models/openai/gpt-4.toml b/providers/merge-gateway/models/openai/gpt-4.toml new file mode 100644 index 0000000000..a4363542ed --- /dev/null +++ b/providers/merge-gateway/models/openai/gpt-4.toml @@ -0,0 +1,7 @@ +base_model = "openai/gpt-4" +attachment = false +tool_call = false + +[cost] +input = 30 +output = 60 diff --git a/providers/merge-gateway/models/openai/gpt-4o-2024-05-13.toml b/providers/merge-gateway/models/openai/gpt-4o-2024-05-13.toml index c4a17bbcf7..6f72744fc8 100644 --- a/providers/merge-gateway/models/openai/gpt-4o-2024-05-13.toml +++ b/providers/merge-gateway/models/openai/gpt-4o-2024-05-13.toml @@ -1,5 +1,9 @@ base_model = "openai/gpt-4o-2024-05-13" +structured_output = false [cost] input = 5 output = 15 + +[modalities] +input = ["text", "image", "pdf"] diff --git a/providers/merge-gateway/models/openai/gpt-4o-2024-08-06.toml b/providers/merge-gateway/models/openai/gpt-4o-2024-08-06.toml index 344cd161a7..a02cb635cd 100644 --- a/providers/merge-gateway/models/openai/gpt-4o-2024-08-06.toml +++ b/providers/merge-gateway/models/openai/gpt-4o-2024-08-06.toml @@ -4,3 +4,6 @@ base_model = "openai/gpt-4o-2024-08-06" input = 2.5 output = 10 cache_read = 1.25 + +[modalities] +input = ["text", "image", "pdf"] diff --git a/providers/merge-gateway/models/openai/gpt-4o-2024-11-20.toml b/providers/merge-gateway/models/openai/gpt-4o-2024-11-20.toml index c807afdbe1..2df04ffa70 100644 --- a/providers/merge-gateway/models/openai/gpt-4o-2024-11-20.toml +++ b/providers/merge-gateway/models/openai/gpt-4o-2024-11-20.toml @@ -4,3 +4,6 @@ base_model = "openai/gpt-4o-2024-11-20" input = 2.5 output = 10 cache_read = 1.25 + +[modalities] +input = ["text", "image", "pdf"] diff --git a/providers/merge-gateway/models/openai/gpt-4o-mini.toml b/providers/merge-gateway/models/openai/gpt-4o-mini.toml index da284d5f15..5662c2ceca 100644 --- a/providers/merge-gateway/models/openai/gpt-4o-mini.toml +++ b/providers/merge-gateway/models/openai/gpt-4o-mini.toml @@ -1,4 +1,5 @@ base_model = "openai/gpt-4o-mini" +name = "GPT-4o Mini" [cost] input = 0.15 diff --git a/providers/merge-gateway/models/openai/gpt-5-chat-latest.toml b/providers/merge-gateway/models/openai/gpt-5-chat-latest.toml index 4dd858d1af..eb539d9998 100644 --- a/providers/merge-gateway/models/openai/gpt-5-chat-latest.toml +++ b/providers/merge-gateway/models/openai/gpt-5-chat-latest.toml @@ -1,7 +1,16 @@ 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..9ab4f24cca 100644 --- a/providers/merge-gateway/models/openai/gpt-5-mini.toml +++ b/providers/merge-gateway/models/openai/gpt-5-mini.toml @@ -1,7 +1,13 @@ base_model = "openai/gpt-5-mini" -reasoning_options = [{ type = "effort", values = ["minimal", "low", "medium", "high"] }] + +[[reasoning_options]] +type = "effort" +values = ["minimal", "low", "medium", "high"] [cost] input = 0.25 output = 2 cache_read = 0.025 + +[modalities] +input = ["text", "image", "pdf"] diff --git a/providers/merge-gateway/models/openai/gpt-5-nano.toml b/providers/merge-gateway/models/openai/gpt-5-nano.toml index b96eddfd6f..24bc4a0e65 100644 --- a/providers/merge-gateway/models/openai/gpt-5-nano.toml +++ b/providers/merge-gateway/models/openai/gpt-5-nano.toml @@ -1,7 +1,13 @@ base_model = "openai/gpt-5-nano" -reasoning_options = [{ type = "effort", values = ["minimal", "low", "medium", "high"] }] + +[[reasoning_options]] +type = "effort" +values = ["minimal", "low", "medium", "high"] [cost] input = 0.05 output = 0.4 cache_read = 0.005 + +[modalities] +input = ["text", "image", "pdf"] diff --git a/providers/merge-gateway/models/openai/gpt-5.1-chat-latest.toml b/providers/merge-gateway/models/openai/gpt-5.1-chat-latest.toml index 55e1ad4331..efc818ff44 100644 --- a/providers/merge-gateway/models/openai/gpt-5.1-chat-latest.toml +++ b/providers/merge-gateway/models/openai/gpt-5.1-chat-latest.toml @@ -1,7 +1,11 @@ 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..b1e6e83622 100644 --- a/providers/merge-gateway/models/openai/gpt-5.1.toml +++ b/providers/merge-gateway/models/openai/gpt-5.1.toml @@ -1,7 +1,13 @@ base_model = "openai/gpt-5.1" -reasoning_options = [{ type = "effort", values = ["none", "low", "medium", "high"] }] + +[[reasoning_options]] +type = "effort" +values = ["none", "low", "medium", "high"] [cost] input = 1.25 output = 10 cache_read = 0.125 + +[modalities] +input = ["text", "image", "pdf"] diff --git a/providers/merge-gateway/models/openai/gpt-5.2-chat-latest.toml b/providers/merge-gateway/models/openai/gpt-5.2-chat-latest.toml index bbad0e8faf..818ab9e704 100644 --- a/providers/merge-gateway/models/openai/gpt-5.2-chat-latest.toml +++ b/providers/merge-gateway/models/openai/gpt-5.2-chat-latest.toml @@ -1,7 +1,11 @@ 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..4cbeec6e34 100644 --- a/providers/merge-gateway/models/openai/gpt-5.2.toml +++ b/providers/merge-gateway/models/openai/gpt-5.2.toml @@ -1,7 +1,13 @@ base_model = "openai/gpt-5.2" -reasoning_options = [{ type = "effort", values = ["none", "low", "medium", "high", "xhigh"] }] + +[[reasoning_options]] +type = "effort" +values = ["none", "low", "medium", "high", "xhigh"] [cost] input = 1.75 output = 14 cache_read = 0.175 + +[modalities] +input = ["text", "image", "pdf"] diff --git a/providers/merge-gateway/models/openai/gpt-5.3-chat-latest.toml b/providers/merge-gateway/models/openai/gpt-5.3-chat-latest.toml index 197284ef5f..5d69491b2e 100644 --- a/providers/merge-gateway/models/openai/gpt-5.3-chat-latest.toml +++ b/providers/merge-gateway/models/openai/gpt-5.3-chat-latest.toml @@ -1,6 +1,10 @@ base_model = "openai/gpt-5.3-chat-latest" +name = "GPT-5.3 Chat Latest" [cost] input = 1.75 output = 14 cache_read = 0.175 + +[modalities] +input = ["text", "image", "pdf"] diff --git a/providers/merge-gateway/models/openai/gpt-5.4-mini.toml b/providers/merge-gateway/models/openai/gpt-5.4-mini.toml index 56a278d15d..913a608765 100644 --- a/providers/merge-gateway/models/openai/gpt-5.4-mini.toml +++ b/providers/merge-gateway/models/openai/gpt-5.4-mini.toml @@ -1,11 +1,18 @@ base_model = "openai/gpt-5.4-mini" -reasoning_options = [{ type = "effort", values = ["none", "low", "medium", "high", "xhigh"] }] +name = "GPT-5.4 Mini" + +[[reasoning_options]] +type = "effort" +values = ["none", "low", "medium", "high", "xhigh"] [cost] input = 0.75 output = 4.5 cache_read = 0.075 +[modalities] +input = ["text", "image", "pdf"] + [experimental.modes.fast] cost = { input = 1.5, output = 9, cache_read = 0.15 } provider = { body = { service_tier = "priority" } } diff --git a/providers/merge-gateway/models/openai/gpt-5.4-nano.toml b/providers/merge-gateway/models/openai/gpt-5.4-nano.toml index 3872b109a2..cd1ef0c661 100644 --- a/providers/merge-gateway/models/openai/gpt-5.4-nano.toml +++ b/providers/merge-gateway/models/openai/gpt-5.4-nano.toml @@ -1,7 +1,14 @@ base_model = "openai/gpt-5.4-nano" -reasoning_options = [{ type = "effort", values = ["none", "low", "medium", "high", "xhigh"] }] +name = "GPT-5.4 Nano" + +[[reasoning_options]] +type = "effort" +values = ["none", "low", "medium", "high", "xhigh"] [cost] input = 0.2 output = 1.25 cache_read = 0.02 + +[modalities] +input = ["text", "image", "pdf"] diff --git a/providers/merge-gateway/models/openai/gpt-5.6-luna.toml b/providers/merge-gateway/models/openai/gpt-5.6-luna.toml new file mode 100644 index 0000000000..37a38e5a9b --- /dev/null +++ b/providers/merge-gateway/models/openai/gpt-5.6-luna.toml @@ -0,0 +1,10 @@ +# 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..de3ff8acd3 --- /dev/null +++ b/providers/merge-gateway/models/openai/gpt-5.6-sol.toml @@ -0,0 +1,12 @@ +# Merge Gateway catalog: GET https://api-gateway.merge.dev/v1/models +# Reasoning controls: https://openai.com/index/gpt-5-6/ (accessed 2026-07-13) +base_model = "openai/gpt-5.6-sol" + +[[reasoning_options]] +type = "effort" +values = ["none", "low", "medium", "high", "xhigh", "max"] + +[cost] +input = 3.75 +output = 22.5 +cache_read = 0.375 diff --git a/providers/merge-gateway/models/openai/gpt-5.6-terra.toml b/providers/merge-gateway/models/openai/gpt-5.6-terra.toml new file mode 100644 index 0000000000..592888015f --- /dev/null +++ b/providers/merge-gateway/models/openai/gpt-5.6-terra.toml @@ -0,0 +1,10 @@ +# 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..562d91dcdb 100644 --- a/providers/merge-gateway/models/openai/gpt-5.toml +++ b/providers/merge-gateway/models/openai/gpt-5.toml @@ -1,7 +1,13 @@ base_model = "openai/gpt-5" -reasoning_options = [{ type = "effort", values = ["minimal", "low", "medium", "high"] }] + +[[reasoning_options]] +type = "effort" +values = ["minimal", "low", "medium", "high"] [cost] input = 1.25 output = 10 cache_read = 0.125 + +[modalities] +input = ["text", "image", "pdf"] diff --git a/providers/merge-gateway/models/openai/gpt-oss-120b.toml b/providers/merge-gateway/models/openai/gpt-oss-120b.toml new file mode 100644 index 0000000000..5fd494cee9 --- /dev/null +++ b/providers/merge-gateway/models/openai/gpt-oss-120b.toml @@ -0,0 +1,11 @@ +# Merge Gateway GET /v1/models?model=openai/gpt-oss-120b (accessed 2026-07-14): +# available routes either report `supports_reasoning = false` or reasoning with +# `configurable = false` and no controls, so callers have no reasoning control. +base_model = "openai/gpt-oss-120b" +reasoning = false +tool_call = false +structured_output = false + +[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..cd7d74a531 --- /dev/null +++ b/providers/merge-gateway/models/openai/gpt-oss-20b.toml @@ -0,0 +1,12 @@ +# Merge Gateway GET /v1/models?model=openai/gpt-oss-20b (accessed 2026-07-14): +# available routes either report `supports_reasoning = false` or reasoning with +# `configurable = false` and no controls, so callers have no reasoning control. +base_model = "openai/gpt-oss-20b" +reasoning = false +tool_call = false +structured_output = false + +[cost] +input = 0.04 +output = 0.2 +cache_read = 0.02 diff --git a/providers/merge-gateway/models/openai/o3-mini.toml b/providers/merge-gateway/models/openai/o3-mini.toml index 716e4b6e1a..8e81e03022 100644 --- a/providers/merge-gateway/models/openai/o3-mini.toml +++ b/providers/merge-gateway/models/openai/o3-mini.toml @@ -1,5 +1,9 @@ base_model = "openai/o3-mini" -reasoning_options = [{ type = "effort", values = ["low", "medium", "high"] }] +name = "o3 Mini" + +[[reasoning_options]] +type = "effort" +values = ["low", "medium", "high"] [cost] input = 1.1 diff --git a/providers/merge-gateway/models/openai/o4-mini.toml b/providers/merge-gateway/models/openai/o4-mini.toml index 0ff60822de..e234a45f67 100644 --- a/providers/merge-gateway/models/openai/o4-mini.toml +++ b/providers/merge-gateway/models/openai/o4-mini.toml @@ -1,7 +1,11 @@ base_model = "openai/o4-mini" +name = "o4 Mini" reasoning_options = [] [cost] input = 1.1 output = 4.4 cache_read = 0.275 + +[modalities] +input = ["text", "image", "pdf"] diff --git a/providers/merge-gateway/models/qwen/qwen-flash.toml b/providers/merge-gateway/models/qwen/qwen-flash.toml new file mode 100644 index 0000000000..299e89c391 --- /dev/null +++ b/providers/merge-gateway/models/qwen/qwen-flash.toml @@ -0,0 +1,12 @@ +base_model = "alibaba/qwen-flash" +reasoning = false +tool_call = false +structured_output = false + +[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..a3fb0776eb --- /dev/null +++ b/providers/merge-gateway/models/qwen/qwen-plus.toml @@ -0,0 +1,12 @@ +base_model = "alibaba/qwen-plus" +reasoning = false +tool_call = false +structured_output = false + +[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..926127614d --- /dev/null +++ b/providers/merge-gateway/models/qwen/qwen3-235b-a22b.toml @@ -0,0 +1,13 @@ +base_model = "alibaba/qwen3-235b-a22b" +name = "Qwen3 235B A22B" +reasoning = false +tool_call = false +structured_output = false + +[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..2033594162 --- /dev/null +++ b/providers/merge-gateway/models/qwen/qwen3-32b.toml @@ -0,0 +1,10 @@ +base_model = "alibaba/qwen3-32b" +reasoning = false +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..2d2b7fe1ae --- /dev/null +++ b/providers/merge-gateway/models/qwen/qwen3-coder-480b-a35b-instruct.toml @@ -0,0 +1,11 @@ +base_model = "alibaba/qwen3-coder-480b-a35b-instruct" +tool_call = false +structured_output = false + +[cost] +input = 0.22 +output = 1.8 + +[limit] +context = 131_072 +output = 32_768 diff --git a/providers/merge-gateway/models/qwen/qwen3-coder-flash.toml b/providers/merge-gateway/models/qwen/qwen3-coder-flash.toml new file mode 100644 index 0000000000..ba9dbb0ead --- /dev/null +++ b/providers/merge-gateway/models/qwen/qwen3-coder-flash.toml @@ -0,0 +1,11 @@ +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..8d12a803e8 --- /dev/null +++ b/providers/merge-gateway/models/qwen/qwen3-coder-plus.toml @@ -0,0 +1,12 @@ +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..22f3b42dc8 --- /dev/null +++ b/providers/merge-gateway/models/qwen/qwen3-max.toml @@ -0,0 +1,8 @@ +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..b2ad8e78bc --- /dev/null +++ b/providers/merge-gateway/models/qwen/qwen3-next-80b-a3b-instruct.toml @@ -0,0 +1,8 @@ +base_model = "alibaba/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..fe00a88b44 --- /dev/null +++ b/providers/merge-gateway/models/qwen/qwen3-next-80b-a3b-thinking.toml @@ -0,0 +1,8 @@ +base_model = "alibaba/qwen3-next-80b-a3b-thinking" +reasoning = false +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..0b7afd7e0f --- /dev/null +++ b/providers/merge-gateway/models/qwen/qwen3-vl-plus.toml @@ -0,0 +1,13 @@ +base_model = "alibaba/qwen3-vl-plus" +attachment = true +reasoning = false +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..2a33d7879b --- /dev/null +++ b/providers/merge-gateway/models/qwen/qwen3.5-122b-a10b.toml @@ -0,0 +1,17 @@ +base_model = "alibaba/qwen3.5-122b-a10b" +attachment = false +reasoning = false +tool_call = false +structured_output = false + +[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..d6a2738a45 --- /dev/null +++ b/providers/merge-gateway/models/qwen/qwen3.5-27b.toml @@ -0,0 +1,17 @@ +base_model = "alibaba/qwen3.5-27b" +attachment = false +reasoning = false +tool_call = false +structured_output = false + +[cost] +input = 0.086 +output = 0.688 +cache_read = 0.0172 + +[limit] +context = 131_072 +output = 32_768 + +[modalities] +input = ["text"] diff --git a/providers/merge-gateway/models/qwen/qwen3.5-35b-a3b.toml b/providers/merge-gateway/models/qwen/qwen3.5-35b-a3b.toml new file mode 100644 index 0000000000..2095aa4c17 --- /dev/null +++ b/providers/merge-gateway/models/qwen/qwen3.5-35b-a3b.toml @@ -0,0 +1,18 @@ +base_model = "alibaba/qwen3.5-35b-a3b" +name = "Qwen3.5 35B A3B" +attachment = false +reasoning = false +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..d7e0ddb495 --- /dev/null +++ b/providers/merge-gateway/models/qwen/qwen3.5-397b-a17b.toml @@ -0,0 +1,18 @@ +base_model = "alibaba/qwen3.5-397b-a17b" +name = "Qwen3.5 397B A17B" +attachment = false +reasoning = false +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..a72691682d --- /dev/null +++ b/providers/merge-gateway/models/qwen/qwen3.5-9b.toml @@ -0,0 +1,14 @@ +base_model = "alibaba/qwen3.5-9b" +attachment = true +reasoning = false +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..1bb324949b --- /dev/null +++ b/providers/merge-gateway/models/qwen/qwen3.5-plus.toml @@ -0,0 +1,15 @@ +base_model = "alibaba/qwen3.5-plus" +reasoning = false +tool_call = false +structured_output = false + +[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..b8e90ba940 --- /dev/null +++ b/providers/merge-gateway/models/qwen/qwen3.6-27b.toml @@ -0,0 +1,15 @@ +base_model = "alibaba/qwen3.6-27b" +reasoning = false +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..c695e7ce73 --- /dev/null +++ b/providers/merge-gateway/models/qwen/qwen3.6-35b-a3b.toml @@ -0,0 +1,14 @@ +base_model = "alibaba/qwen3.6-35b-a3b" +name = "Qwen3.6 35B A3B" +attachment = false +reasoning = false +tool_call = false +structured_output = false + +[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..e7edc55b2b --- /dev/null +++ b/providers/merge-gateway/models/qwen/qwen3.6-flash.toml @@ -0,0 +1,16 @@ +base_model = "alibaba/qwen3.6-flash" +attachment = false +reasoning = false +tool_call = false +structured_output = false + +[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..1a31538776 --- /dev/null +++ b/providers/merge-gateway/models/qwen/qwen3.6-max-preview.toml @@ -0,0 +1,11 @@ +base_model = "alibaba/qwen3.6-max-preview" +reasoning = false +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..245c5d99d4 --- /dev/null +++ b/providers/merge-gateway/models/qwen/qwen3.6-plus.toml @@ -0,0 +1,15 @@ +base_model = "alibaba/qwen3.6-plus" +reasoning = false +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..3f3d85bc8a --- /dev/null +++ b/providers/merge-gateway/models/qwen/qwen3.7-max.toml @@ -0,0 +1,12 @@ +base_model = "alibaba/qwen3.7-max" +reasoning = false +tool_call = false +structured_output = false + +[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..5ae04e9d74 --- /dev/null +++ b/providers/merge-gateway/models/qwen/qwen3.7-plus.toml @@ -0,0 +1,12 @@ +base_model = "alibaba/qwen3.7-plus" +attachment = true +reasoning = false +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..6738a5dfc1 --- /dev/null +++ b/providers/merge-gateway/models/sakana/fugu-ultra.toml @@ -0,0 +1,10 @@ +base_model = "sakana/fugu-ultra" +reasoning = false +structured_output = false + +[cost] +input = 5 +output = 30 + +[limit] +output = 250_000 diff --git a/providers/merge-gateway/models/writer/palmyra-x4.toml b/providers/merge-gateway/models/writer/palmyra-x4.toml new file mode 100644 index 0000000000..dba9900285 --- /dev/null +++ b/providers/merge-gateway/models/writer/palmyra-x4.toml @@ -0,0 +1,25 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=writer%2Fpalmyra-x4 + +name = "Palmyra X4" +description = "Enterprise language model for writing, analysis, and tool-assisted workflows" +family = "palmyra" +release_date = "2024-10-09" +last_updated = "2024-10-09" +attachment = false +reasoning = false +temperature = true +tool_call = true +structured_output = false +open_weights = false + +[cost] +input = 2.5 +output = 10 + +[limit] +context = 128_000 +output = 32_000 + +[modalities] +input = ["text"] +output = ["text"] diff --git a/providers/merge-gateway/models/writer/palmyra-x5.toml b/providers/merge-gateway/models/writer/palmyra-x5.toml new file mode 100644 index 0000000000..c7bdfefa40 --- /dev/null +++ b/providers/merge-gateway/models/writer/palmyra-x5.toml @@ -0,0 +1,25 @@ +# Source: https://api-gateway.merge.dev/v1/models?model=writer%2Fpalmyra-x5 + +name = "Palmyra X5" +description = "Enterprise multimodal model for writing, analysis, and tool-assisted workflows" +family = "palmyra" +release_date = "2025-04-28" +last_updated = "2025-04-28" +attachment = true +reasoning = false +temperature = true +tool_call = true +structured_output = true +open_weights = false + +[cost] +input = 0.6 +output = 6 + +[limit] +context = 1_000_000 +output = 250_000 + +[modalities] +input = ["text", "image"] +output = ["text"] diff --git a/providers/merge-gateway/models/xai/grok-4.20-0309-non-reasoning.toml b/providers/merge-gateway/models/xai/grok-4.20-0309-non-reasoning.toml new file mode 100644 index 0000000000..e803774686 --- /dev/null +++ b/providers/merge-gateway/models/xai/grok-4.20-0309-non-reasoning.toml @@ -0,0 +1,13 @@ +base_model = "xai/grok-4.20-0309-non-reasoning" +name = "Grok 4.20 Non-Reasoning" + +[cost] +input = 1.25 +output = 2.5 +cache_read = 0.2 + +[limit] +output = 1_000_000 + +[modalities] +input = ["text", "image"] diff --git a/providers/merge-gateway/models/xai/grok-4.20-0309-reasoning.toml b/providers/merge-gateway/models/xai/grok-4.20-0309-reasoning.toml index cfff36e939..eef910f466 100644 --- a/providers/merge-gateway/models/xai/grok-4.20-0309-reasoning.toml +++ b/providers/merge-gateway/models/xai/grok-4.20-0309-reasoning.toml @@ -1,4 +1,5 @@ base_model = "xai/grok-4.20-0309-reasoning" +name = "Grok 4.20" reasoning_options = [] [cost] @@ -11,3 +12,9 @@ tier = { type = "context", size = 200_000 } input = 2.5 output = 5 cache_read = 0.4 + +[limit] +output = 1_000_000 + +[modalities] +input = ["text", "image"] diff --git a/providers/merge-gateway/models/xai/grok-4.3.toml b/providers/merge-gateway/models/xai/grok-4.3.toml index faeaba94b5..cc89c88330 100644 --- a/providers/merge-gateway/models/xai/grok-4.3.toml +++ b/providers/merge-gateway/models/xai/grok-4.3.toml @@ -11,3 +11,9 @@ tier = { type = "context", size = 200_000 } input = 2.5 output = 5 cache_read = 0.4 + +[limit] +output = 1_000_000 + +[modalities] +input = ["text", "image"] diff --git a/providers/merge-gateway/models/xai/grok-4.5.toml b/providers/merge-gateway/models/xai/grok-4.5.toml new file mode 100644 index 0000000000..9179571704 --- /dev/null +++ b/providers/merge-gateway/models/xai/grok-4.5.toml @@ -0,0 +1,7 @@ +base_model = "xai/grok-4.5" +reasoning_options = [] + +[cost] +input = 2 +output = 6 +cache_read = 0.5 diff --git a/providers/merge-gateway/models/xai/grok-build-0.1.toml b/providers/merge-gateway/models/xai/grok-build-0.1.toml new file mode 100644 index 0000000000..2cd89e9a80 --- /dev/null +++ b/providers/merge-gateway/models/xai/grok-build-0.1.toml @@ -0,0 +1,10 @@ +base_model = "xai/grok-build-0.1" +reasoning_options = [] + +[cost] +input = 1 +output = 2 +cache_read = 0.2 + +[modalities] +input = ["text", "image"] diff --git a/providers/merge-gateway/models/zai/glm-4.5-air.toml b/providers/merge-gateway/models/zai/glm-4.5-air.toml index 2c9bfb4c1e..fb0ad87b7f 100644 --- a/providers/merge-gateway/models/zai/glm-4.5-air.toml +++ b/providers/merge-gateway/models/zai/glm-4.5-air.toml @@ -1,8 +1,15 @@ base_model = "zhipuai/glm-4.5-air" -reasoning_options = [{ type = "toggle" }] +name = "GLM-4.5 Air" +structured_output = false + +[[reasoning_options]] +type = "toggle" [cost] input = 0.2 output = 1.1 cache_read = 0.03 cache_write = 0 + +[limit] +context = 128_000 diff --git a/providers/merge-gateway/models/zai/glm-4.5.toml b/providers/merge-gateway/models/zai/glm-4.5.toml index d859695015..4286567606 100644 --- a/providers/merge-gateway/models/zai/glm-4.5.toml +++ b/providers/merge-gateway/models/zai/glm-4.5.toml @@ -1,8 +1,14 @@ base_model = "zhipuai/glm-4.5" -reasoning_options = [{ type = "toggle" }] +structured_output = false + +[[reasoning_options]] +type = "toggle" [cost] input = 0.6 output = 2.2 cache_read = 0.11 cache_write = 0 + +[limit] +context = 128_000 diff --git a/providers/merge-gateway/models/zai/glm-4.5v.toml b/providers/merge-gateway/models/zai/glm-4.5v.toml new file mode 100644 index 0000000000..1d54a9953b --- /dev/null +++ b/providers/merge-gateway/models/zai/glm-4.5v.toml @@ -0,0 +1,17 @@ +base_model = "zhipuai/glm-4.5v" +name = "Glm 4.5V" +reasoning = false +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..9b43877924 100644 --- a/providers/merge-gateway/models/zai/glm-4.6.toml +++ b/providers/merge-gateway/models/zai/glm-4.6.toml @@ -1,8 +1,14 @@ base_model = "zhipuai/glm-4.6" -reasoning_options = [{ type = "toggle" }] +structured_output = false + +[[reasoning_options]] +type = "toggle" [cost] input = 0.6 output = 2.2 cache_read = 0.11 cache_write = 0 + +[limit] +context = 200_000 diff --git a/providers/merge-gateway/models/zai/glm-4.7-flash.toml b/providers/merge-gateway/models/zai/glm-4.7-flash.toml new file mode 100644 index 0000000000..cc8fb9703e --- /dev/null +++ b/providers/merge-gateway/models/zai/glm-4.7-flash.toml @@ -0,0 +1,11 @@ +base_model = "zhipuai/glm-4.7-flash" +name = "GLM 4.7 Flash" +reasoning = false +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..66e530d1d4 100644 --- a/providers/merge-gateway/models/zai/glm-4.7-flashx.toml +++ b/providers/merge-gateway/models/zai/glm-4.7-flashx.toml @@ -1,5 +1,9 @@ base_model = "zhipuai/glm-4.7-flashx" -reasoning_options = [{ type = "toggle" }] +name = "GLM-4.7 FlashX" +structured_output = false + +[[reasoning_options]] +type = "toggle" [cost] input = 0.07 diff --git a/providers/merge-gateway/models/zai/glm-4.7.toml b/providers/merge-gateway/models/zai/glm-4.7.toml index aaa77ab373..2645ef55ee 100644 --- a/providers/merge-gateway/models/zai/glm-4.7.toml +++ b/providers/merge-gateway/models/zai/glm-4.7.toml @@ -1,11 +1,17 @@ base_model = "zhipuai/glm-4.7" -reasoning_options = [{ type = "toggle" }] +structured_output = false [interleaved] field = "reasoning_content" +[[reasoning_options]] +type = "toggle" + [cost] input = 0.6 output = 2.2 cache_read = 0.11 cache_write = 0 + +[limit] +context = 200_000 diff --git a/providers/merge-gateway/models/zai/glm-5-turbo.toml b/providers/merge-gateway/models/zai/glm-5-turbo.toml index 685d533ed3..e0f648c6bb 100644 --- a/providers/merge-gateway/models/zai/glm-5-turbo.toml +++ b/providers/merge-gateway/models/zai/glm-5-turbo.toml @@ -1,9 +1,13 @@ base_model = "zhipuai/glm-5-turbo" -reasoning_options = [{ type = "toggle" }] +name = "GLM-5 Turbo" +structured_output = false [interleaved] field = "reasoning_content" +[[reasoning_options]] +type = "toggle" + [cost] input = 1.2 output = 4 diff --git a/providers/merge-gateway/models/zai/glm-5.1.toml b/providers/merge-gateway/models/zai/glm-5.1.toml index f359f73972..324ad86f62 100644 --- a/providers/merge-gateway/models/zai/glm-5.1.toml +++ b/providers/merge-gateway/models/zai/glm-5.1.toml @@ -1,9 +1,12 @@ base_model = "zhipuai/glm-5.1" -reasoning_options = [{ type = "toggle" }] +structured_output = false [interleaved] field = "reasoning_content" +[[reasoning_options]] +type = "toggle" + [cost] input = 1.4 output = 4.4 diff --git a/providers/merge-gateway/models/zai/glm-5.2.toml b/providers/merge-gateway/models/zai/glm-5.2.toml index 97a7dd870f..91542acaf2 100644 --- a/providers/merge-gateway/models/zai/glm-5.2.toml +++ b/providers/merge-gateway/models/zai/glm-5.2.toml @@ -1,16 +1,11 @@ base_model = "zhipuai/glm-5.2" - -[[reasoning_options]] -type = "toggle" - -[[reasoning_options]] -type = "budget_tokens" -min = 1 -max = 50_000 +reasoning = false +structured_output = false [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..0daa2719a0 100644 --- a/providers/merge-gateway/models/zai/glm-5.toml +++ b/providers/merge-gateway/models/zai/glm-5.toml @@ -1,11 +1,17 @@ base_model = "zhipuai/glm-5" -reasoning_options = [{ type = "toggle" }] +structured_output = false [interleaved] field = "reasoning_content" +[[reasoning_options]] +type = "toggle" + [cost] input = 1 output = 3.2 cache_read = 0.2 cache_write = 0 + +[limit] +context = 200_000 diff --git a/providers/merge-gateway/provider.toml b/providers/merge-gateway/provider.toml index 93c78884b5..293c689f4f 100644 --- a/providers/merge-gateway/provider.toml +++ b/providers/merge-gateway/provider.toml @@ -1,20 +1,18 @@ name = "Merge Gateway" env = ["MERGE_GATEWAY_API_KEY"] npm = "merge-gateway-ai-sdk-provider" -# Reasoning request surfaces (sources accessed 2026-06-25): -# - OpenAI compatibility: POST /v1/openai/chat/completions uses the native -# top-level `reasoning_effort`; the documented base accepts OpenAI SDK calls. -# - Anthropic compatibility: POST /v1/anthropic/v1/messages uses native -# `thinking = { type = "enabled"|"disabled", budget_tokens = N }` and -# `output_config.effort`. +# Reasoning request surfaces (sources accessed 2026-07-14): +# - Reasoning support and controls are vendor-route capabilities. Use the exact +# model response from GET /v1/models and inspect +# vendors..capabilities.reasoning; do not infer support solely from a +# compatibility endpoint's request shape. +# https://docs.merge.dev/merge-gateway/features/reasoning +# https://docs.merge.dev/merge-gateway/api-overview/models/list +# - OpenAI and Anthropic compatibility endpoints accept their native request +# shapes when the selected vendor route advertises the corresponding control. # https://docs.merge.dev/merge-gateway/get-started -# https://docs.anthropic.com/en/api/messages # - This npm package calls POST /v1/ai-sdk/chat/completions and maps # `providerOptions.mergeGateway.thinking` to # `thinking = { type = "enabled"|"disabled", budget_tokens = N }`. # https://github.com/merge-api/merge-gateway-ai-sdk-provider/blob/main/src/chat/index.ts -# - Native POST /v1/responses has no reasoning field in its strict request -# schema. Other normalized or dynamically routed routes do not document -# transparent native-field passthrough; do not infer support from them. -# https://docs.merge.dev/merge-gateway/api-overview/responses/create doc = "https://docs.merge.dev/merge-gateway" diff --git a/sync.md b/sync.md index 1f538b3640..1774f6892e 100644 --- a/sync.md +++ b/sync.md @@ -17,6 +17,7 @@ The grouped sync targets are available for local convenience, but CI syncs each - `bun models:sync digitalocean` syncs only DigitalOcean. - `bun models:sync xai` syncs only xAI. - `bun models:sync kilo` syncs only Kilo. +- `bun models:sync merge-gateway` syncs only Merge Gateway. - `bun models:sync openai` syncs only OpenAI catalog availability. - `bun models:sync aggregators --dry-run` prints changes without writing model files. - `bun models:sync aggregators --new-only` creates new model files but skips updates and removals. @@ -139,6 +140,21 @@ 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. +- Existing cache pricing, tiered pricing, reasoning controls, and experimental modes are preserved because the public API does not currently expose the full CMS metadata. Cache prices curated from Gateway's route-level CMS remain stable across syncs until the public contract exposes them. +- Route-level cache prices replace curated values field by field. A cache read or write price that the API does not expose remains preserved in the provider TOML, including when `prompt_caching` exposes only its mode. +- `prompt_caching.mode = "none"` explicitly removes preserved cache read and write prices because that route does not cache prompts. +- An explicit `supports_reasoning = false` on the selected vendor route overrides inherited reasoning metadata and removes preserved reasoning controls; supported routes retain curated controls when the API does not enumerate exact values. +- Local models missing from the response are retained because API-key policy can affect catalog visibility. + ## Cloudflare Workers AI Notes Cloudflare Workers AI is implemented in `packages/core/src/sync/providers/cloudflare-workers-ai.ts`.