From 5d9f01c66bc61a8ca73c817273d37bd5f6bb291f Mon Sep 17 00:00:00 2001 From: AstroHan Date: Tue, 1 Sep 2026 18:15:31 +0800 Subject: [PATCH 1/9] feat(core): represent video and pdf model modalities MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit models.dev now declares video on either side of a model and pdf as an output. The projector named four input and three output values and threw on anything else, so 324 of the 1906 models in the selected providers took the whole refresh down with them: `npm run refresh:model-metadata` could not write a byte, and the snapshot could not be regenerated at all. Admit both values across the three places that name them — the wire type, the model-facts guard, and the catalog decoder — so a refresh reaches the models that carry them. Both directions now accept the same set, so the two decoders collapse into one that takes the direction; keeping two copies only lets one drift behind the catalog it decodes. The decoder rejects any value it does not name, so a newer Host describing such a model fails an older client's catalog decode outright rather than losing one field. That is a compatibility break, hence the epoch bump: the handshake keeps the pairing from forming. The snapshot itself is untouched here. Its content refresh belongs to the scheduled job's own review pull request, not to this change. Generated-by: Claude Code --- .../__tests__/runtime-policy-codec.test.ts | 13 ++++++++ packages/core/src/llm-connections.ts | 4 +-- packages/core/src/model-catalog.ts | 7 ++-- packages/core/src/model-facts.ts | 15 +++++---- .../connection-catalog-codec.ts | 32 +++++++++++-------- packages/runtime-host/src/protocol/index.ts | 8 ++++- scripts/sync-model-metadata.mjs | 12 +++---- scripts/sync-model-metadata.test.mjs | 32 ++++++++++++++++++- 8 files changed, 89 insertions(+), 34 deletions(-) diff --git a/packages/core/src/__tests__/runtime-policy-codec.test.ts b/packages/core/src/__tests__/runtime-policy-codec.test.ts index 06bdd1328c..d6aba85a60 100644 --- a/packages/core/src/__tests__/runtime-policy-codec.test.ts +++ b/packages/core/src/__tests__/runtime-policy-codec.test.ts @@ -511,6 +511,19 @@ test('normalizes extended model facts used by the runtime host catalog', () => { }); }); +test('carries the video and pdf modalities models.dev declares', () => { + const modalities = { + input: ['text', 'image', 'video'], + output: ['text', 'pdf', 'video'], + }; + const result = normalizeConnectionModelDiscoveryResult({ + models: [{ id: 'custom-model', modalities }], + source: 'fetched', + fetchedAt: 42, + }); + assert.deepEqual(result.models[0], { id: 'custom-model', modalities }); +}); + test('rejects sparse model modality arrays', () => { assert.throws( () => diff --git a/packages/core/src/llm-connections.ts b/packages/core/src/llm-connections.ts index 5a4a839058..232a3a60e3 100644 --- a/packages/core/src/llm-connections.ts +++ b/packages/core/src/llm-connections.ts @@ -116,8 +116,8 @@ export interface ModelInfo { }; /** Multimodal input/output support from provider catalog metadata. */ modalities?: { - input: Array<'text' | 'image' | 'audio' | 'pdf'>; - output: Array<'text' | 'image' | 'audio'>; + input: Array<'text' | 'image' | 'audio' | 'pdf' | 'video'>; + output: Array<'text' | 'image' | 'audio' | 'pdf' | 'video'>; }; /** * Read-time provenance for values overlaid from model-facts.json. This is diff --git a/packages/core/src/model-catalog.ts b/packages/core/src/model-catalog.ts index 12d2609ac4..45e5db3c0d 100644 --- a/packages/core/src/model-catalog.ts +++ b/packages/core/src/model-catalog.ts @@ -515,10 +515,9 @@ function displayNameForKnownModel( * never set `capabilities.imageGeneration` for any of them, so the capability * check below could not fire on bundled data. * - * An EMPTY list is not evidence. `modalities.output` is typed to text, image, - * and audio, so a video model's real output has no representation and - * serializes as `[]` — the same shape a future generator bug would produce. - * Only a non-empty list says something, and what it says is what it lists. + * An EMPTY list is not evidence. A provider that declared no output modality + * and a generator bug that dropped them produce the same shape. Only a + * non-empty list says something, and what it says is what it lists. */ function declaresNoTextOutput(model: ModelInfo): boolean { const output = model.modalities?.output; diff --git a/packages/core/src/model-facts.ts b/packages/core/src/model-facts.ts index 99f9ecbbef..11336a5dfd 100644 --- a/packages/core/src/model-facts.ts +++ b/packages/core/src/model-facts.ts @@ -194,7 +194,7 @@ function normalizeModalities(value: unknown): NonNullable( return [...new Set(entries)]; } -function isModality(value: unknown): value is 'text' | 'image' | 'audio' | 'pdf' { - return value === 'text' || value === 'image' || value === 'audio' || value === 'pdf'; -} -function isOutputModality(value: unknown): value is 'text' | 'image' | 'audio' { - return value === 'text' || value === 'image' || value === 'audio'; +function isModality(value: unknown): value is 'text' | 'image' | 'audio' | 'pdf' | 'video' { + return ( + value === 'text' || + value === 'image' || + value === 'audio' || + value === 'pdf' || + value === 'video' + ); } function isPositiveBoundedInteger(value: unknown): value is number { return ( diff --git a/packages/core/src/runtime-policy/connection-catalog-codec.ts b/packages/core/src/runtime-policy/connection-catalog-codec.ts index fa0c6a1c15..9292b69cfe 100644 --- a/packages/core/src/runtime-policy/connection-catalog-codec.ts +++ b/packages/core/src/runtime-policy/connection-catalog-codec.ts @@ -600,23 +600,27 @@ function decodeModelModalities(value: unknown): NonNullable decodeModelInputModality(entry)); - const output = Array.from(item.output, (entry) => decodeModelOutputModality(entry)); + const input = Array.from(item.input, (entry) => decodeModelModality(entry, 'input')); + const output = Array.from(item.output, (entry) => decodeModelModality(entry, 'output')); return { input, output }; } -function decodeModelInputModality(value: unknown): 'text' | 'image' | 'audio' | 'pdf' { - const modality = stringValue(value, 'connection model input modality', 16); - if (modality !== 'text' && modality !== 'image' && modality !== 'audio' && modality !== 'pdf') { - throw domainError('connection model input modality is invalid'); - } - return modality; -} - -function decodeModelOutputModality(value: unknown): 'text' | 'image' | 'audio' { - const modality = stringValue(value, 'connection model output modality', 16); - if (modality !== 'text' && modality !== 'image' && modality !== 'audio') { - throw domainError('connection model output modality is invalid'); +// Both directions accept the same set. models.dev declares video on either +// side and pdf on both, so splitting them again only invites one direction to +// drift behind the catalog it decodes. +function decodeModelModality( + value: unknown, + direction: 'input' | 'output', +): 'text' | 'image' | 'audio' | 'pdf' | 'video' { + const modality = stringValue(value, `connection model ${direction} modality`, 16); + if ( + modality !== 'text' && + modality !== 'image' && + modality !== 'audio' && + modality !== 'pdf' && + modality !== 'video' + ) { + throw domainError(`connection model ${direction} modality is invalid`); } return modality; } diff --git a/packages/runtime-host/src/protocol/index.ts b/packages/runtime-host/src/protocol/index.ts index 8aff63a16a..0a7784ff03 100644 --- a/packages/runtime-host/src/protocol/index.ts +++ b/packages/runtime-host/src/protocol/index.ts @@ -95,7 +95,13 @@ export const RUNTIME_HOST_REGISTRATION_SCHEMA_VERSION = 1 as const; export const RUNTIME_HOST_PROTOCOL_VERSION = 0 as const; // Increment when the same protocol version no longer guarantees safe Client-Host // interoperability. Mismatches are rejected before domain commands are admitted. -export const RUNTIME_HOST_COMPATIBILITY_EPOCH = 87 as const; +export const RUNTIME_HOST_COMPATIBILITY_EPOCH = 88 as const; +// 88: Catalog model modalities admit video on either side and pdf as output. +// models.dev declares both, and the modality decoder rejects any value it does +// not name, so a newer Host describing such a model fails an older client's +// catalog decode outright rather than losing one field. The handshake keeps +// that pairing from forming; a newer client simply never sees the new values +// from an older Host. // 87: The connection catalog projects each model as the Host resolved it — // a `catalog_entry` item per model, counted by the connection header. Clients // render those entries instead of merging the stored row against their own diff --git a/scripts/sync-model-metadata.mjs b/scripts/sync-model-metadata.mjs index 2869c04416..1a6496357a 100644 --- a/scripts/sync-model-metadata.mjs +++ b/scripts/sync-model-metadata.mjs @@ -25,6 +25,10 @@ import { dirname } from 'node:path'; import { pathToFileURL } from 'node:url'; const SOURCE_URL = 'https://models.dev/api.json'; +// Must stay in step with ModelInfo['modalities'] in packages/core. A value +// that reaches the projection but not the wire type fails the build; a value +// missing here drops the whole refresh, not just the model that declares it. +const MODALITIES = new Set(['text', 'image', 'audio', 'pdf', 'video']); const DEFAULT_SNAPSHOT = 'scripts/model-metadata/models-dev-api.snapshot.json'; const DEFAULT_OUTPUT = 'packages/core/src/model-metadata.generated.ts'; const DEFAULT_PRICING_OUTPUT = 'packages/runtime/src/telemetry/model-pricing.generated.ts'; @@ -540,12 +544,8 @@ export function toMetadata(providerId, modelId, provider, model) { throw new Error(`models.dev model ${providerId}/${modelId} has an unsupported shape`); } if ( - model.modalities?.input.some( - (value) => value !== 'text' && value !== 'image' && value !== 'audio' && value !== 'pdf', - ) || - model.modalities?.output.some( - (value) => value !== 'text' && value !== 'image' && value !== 'audio', - ) + model.modalities?.input.some((value) => !MODALITIES.has(value)) || + model.modalities?.output.some((value) => !MODALITIES.has(value)) ) { throw new Error(`models.dev model ${providerId}/${modelId} has unsupported modalities`); } diff --git a/scripts/sync-model-metadata.test.mjs b/scripts/sync-model-metadata.test.mjs index 021b2aaf85..b0c9f0eef3 100644 --- a/scripts/sync-model-metadata.test.mjs +++ b/scripts/sync-model-metadata.test.mjs @@ -280,7 +280,7 @@ test('refresh rejects unknown model modalities instead of dropping them', async const snapshot = join(root, 'snapshot.json'); const metadata = join(root, 'metadata.ts'); const catalog = fixtureCatalog(); - catalog.anthropic.models.model.modalities = { input: ['text', 'video'], output: ['text'] }; + catalog.anthropic.models.model.modalities = { input: ['text', 'hologram'], output: ['text'] }; await writeFile(input, JSON.stringify(catalog)); await assert.rejects( @@ -302,6 +302,36 @@ test('refresh rejects unknown model modalities instead of dropping them', async } }); +test('refresh carries the video and pdf modalities models.dev declares', async () => { + const root = await mkdtemp(join(tmpdir(), 'maka-model-snapshot-video-')); + try { + const input = join(root, 'api.json'); + const snapshot = join(root, 'snapshot.json'); + const metadata = join(root, 'metadata.ts'); + const catalog = fixtureCatalog(); + const modalities = { input: ['text', 'video'], output: ['text', 'pdf', 'video'] }; + catalog.anthropic.models.model.modalities = modalities; + await writeFile(input, JSON.stringify(catalog)); + + await main([ + 'node', + 'sync-model-metadata.mjs', + '--refresh', + '--refresh-input', + input, + '--snapshot', + snapshot, + '--output', + metadata, + ]); + + const written = JSON.parse(await readFile(snapshot, 'utf8')); + assert.deepEqual(written.projection.metadata.anthropic.model.modalities, modalities); + } finally { + await rm(root, { recursive: true, force: true }); + } +}); + test('refresh rejects a partial provider shrink until it is explicitly accepted', async () => { const root = await mkdtemp(join(tmpdir(), 'maka-model-snapshot-provider-shrink-')); try { From 5488f7c4096b85471c37d87efd1109419ac16117 Mon Sep 17 00:00:00 2001 From: AstroHan Date: Tue, 1 Sep 2026 18:16:37 +0800 Subject: [PATCH 2/9] refactor(core): drop the unread ModelMetadata.docsUrl Nothing in packages or apps ever read `docsUrl`. It was a per-model copy of the provider's `doc` field, which the generated provider facts already carry once per provider, so every model row paid for a duplicate no renderer asked for. The snapshot stores the projected shape rather than the upstream bytes, so the field cannot leave the type without leaving the snapshot in the same change: 1871 keys removed and the projection digest recomputed. That is a shape migration of a generated artifact, the same kind its own `origin.kind` already records. A refresh run against today's upstream produces exactly this shape, and `check:model-metadata` re-derives the digest, so the migrated file is not taken on trust. The snapshot's content vintage is unchanged; only the field is gone. Generated-by: Claude Code --- .../core/src/__tests__/model-metadata.test.ts | 1 - packages/core/src/model-metadata.ts | 8 - .../models-dev-api.snapshot.json | 1873 +---------------- scripts/sync-model-metadata.mjs | 1 - 4 files changed, 1 insertion(+), 1882 deletions(-) diff --git a/packages/core/src/__tests__/model-metadata.test.ts b/packages/core/src/__tests__/model-metadata.test.ts index 8f9e01cfe0..2696510d85 100644 --- a/packages/core/src/__tests__/model-metadata.test.ts +++ b/packages/core/src/__tests__/model-metadata.test.ts @@ -138,7 +138,6 @@ describe('deepseek v4 flash vision exp metadata regression', () => { metadata.description, 'Experimental DeepSeek V4 Flash model for image understanding and multimodal agent tasks', ); - assert.equal(metadata.docsUrl, 'https://api-docs.deepseek.com/guides/vision/'); assert.equal(metadata.contextWindow, 1_000_000); assert.equal(metadata.maxOutputTokens, 384_000); assert.equal(metadata.structuredOutput, true); diff --git a/packages/core/src/model-metadata.ts b/packages/core/src/model-metadata.ts index 4c8268be63..81366ad80f 100644 --- a/packages/core/src/model-metadata.ts +++ b/packages/core/src/model-metadata.ts @@ -28,7 +28,6 @@ export interface ModelMetadata { displayName?: string; description?: string; lifecycle?: 'active' | 'beta' | 'alpha' | 'deprecated' | 'retired'; - docsUrl?: string; contextWindow?: number; inputLimit?: number; maxOutputTokens?: number; @@ -242,8 +241,6 @@ const SILICONFLOW_MODEL_OVERRIDES: Record = Object.fromEn .map(([id]) => [id, { capabilities: { chat: true } }]), ); -const VOLCENGINE_CODING_PLAN_DOCS = 'https://www.volcengine.com/docs/82379/1925114'; -const VOLCENGINE_AGENT_PLAN_DOCS = 'https://www.volcengine.com/docs/82379/2366394'; const VOLCENGINE_CODING_PLAN_MODEL_METADATA: Record = { 'ark-code-latest': planModel('Ark Code Latest', false), 'doubao-seed-2.0-code': planModel('Doubao Seed 2.0 Code', true), @@ -351,7 +348,6 @@ const STATIC_MODEL_METADATA: Partial Date: Tue, 1 Sep 2026 18:19:06 +0800 Subject: [PATCH 3/9] feat(scripts): report models.dev snapshot drift against upstream MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `check:model-metadata` proves the generated modules match the committed snapshot. Nothing proved the snapshot still matches models.dev, so the snapshot could sit weeks behind upstream with every check green — which is exactly what happened: models.dev listed glm-5.3 from 2026-08-14 and the snapshot regenerated on 2026-08-29 without it. `--drift` fetches upstream and compares model by model, printing what differs and exiting non-zero. Per model rather than per projection on purpose: a refresh aborts on the first shape it cannot project, so one surprising model would otherwise hide every other difference. A rejected shape becomes its own bucket instead. The mode never writes, so it is safe to run against a checkout that must stay clean. It stays out of check:asf-source and check:release: both run on every affected pull request, and neither should need models.dev to be reachable. Generated-by: Claude Code --- package.json | 1 + scripts/sync-model-metadata.mjs | 130 ++++++++++++++++++++++++--- scripts/sync-model-metadata.test.mjs | 98 ++++++++++++++++++++ 3 files changed, 216 insertions(+), 13 deletions(-) diff --git a/package.json b/package.json index 08a3131b68..ccbba4bcdb 100644 --- a/package.json +++ b/package.json @@ -92,6 +92,7 @@ "sync:model-metadata": "node scripts/sync-model-metadata.mjs", "refresh:model-metadata": "node scripts/sync-model-metadata.mjs --refresh", "check:model-metadata": "node scripts/sync-model-metadata.mjs --check", + "check:model-metadata-drift": "node scripts/sync-model-metadata.mjs --drift", "generate:bundled-skills": "node scripts/gen-bundled-skill-catalog.mjs", "computer-use": "node scripts/computer-use.mjs", "windows:inventory": "node --test scripts/windows-test-inventory.test.mjs && node scripts/windows-test-inventory.mjs --check", diff --git a/scripts/sync-model-metadata.mjs b/scripts/sync-model-metadata.mjs index 02782434d4..8f820cdf95 100644 --- a/scripts/sync-model-metadata.mjs +++ b/scripts/sync-model-metadata.mjs @@ -117,11 +117,22 @@ export async function main(argv = process.argv) { (outputPath === DEFAULT_OUTPUT ? DEFAULT_PRICING_OUTPUT : undefined); const refresh = argv.includes('--refresh'); const check = argv.includes('--check'); + const drift = argv.includes('--drift'); const acceptUpstreamRemovals = argv.includes('--accept-upstream-removals'); - if (refreshInputPath && !refresh) throw new Error('--refresh-input requires --refresh'); + if (drift && (refresh || check)) { + throw new Error('--drift reports without writing and cannot combine with --refresh or --check'); + } + if (refreshInputPath && !refresh && !drift) { + throw new Error('--refresh-input requires --refresh or --drift'); + } if (acceptUpstreamRemovals && !refresh) { throw new Error('--accept-upstream-removals requires --refresh'); } + if (drift) { + const report = await collectDrift(await loadSnapshot(snapshotPath), refreshInputPath); + process.stdout.write(`${formatDrift(report)}\n`); + return report; + } const source = refresh ? await refreshSnapshot(snapshotPath, refreshInputPath, { acceptUpstreamRemovals }) @@ -235,19 +246,25 @@ function buildProjection(catalog) { return { metadata, pricing, providerFacts, providerOverrides }; } -async function refreshSnapshot(snapshotPath, refreshInputPath, options = {}) { - let sourceText; - let sourceEtag = null; - let retrievedAt = new Date().toISOString(); +async function readUpstream(refreshInputPath) { if (refreshInputPath) { - sourceText = await readFile(refreshInputPath, 'utf8'); - } else { - const response = await fetch(SOURCE_URL, { signal: AbortSignal.timeout(10_000) }); - if (!response.ok) throw new Error(`models.dev returned HTTP ${response.status}`); - sourceText = await response.text(); - sourceEtag = response.headers.get('etag'); - retrievedAt = new Date(response.headers.get('date') ?? Date.now()).toISOString(); + return { + text: await readFile(refreshInputPath, 'utf8'), + etag: null, + retrievedAt: new Date().toISOString(), + }; } + const response = await fetch(SOURCE_URL, { signal: AbortSignal.timeout(10_000) }); + if (!response.ok) throw new Error(`models.dev returned HTTP ${response.status}`); + return { + text: await response.text(), + etag: response.headers.get('etag'), + retrievedAt: new Date(response.headers.get('date') ?? Date.now()).toISOString(), + }; +} + +async function refreshSnapshot(snapshotPath, refreshInputPath, options = {}) { + const { text: sourceText, etag: sourceEtag, retrievedAt } = await readUpstream(refreshInputPath); const projection = buildProjection(selectCatalog(JSON.parse(sourceText))); if (!options.acceptUpstreamRemovals) { const previous = await loadSnapshotIfPresent(snapshotPath); @@ -339,6 +356,91 @@ function projectionPath(path) { return `/${path.map((segment) => String(segment).replaceAll('~', '~0').replaceAll('/', '~1')).join('/')}`; } +// `--check` only proves the generated modules match the committed snapshot. +// Nothing compared that snapshot against models.dev, which is how it stayed +// weeks behind upstream without anything reporting it. This walks the two one +// model at a time, so a shape the projector rejects becomes its own finding +// instead of aborting the whole comparison the way a refresh does. +const DRIFT_LIST_LIMIT = 20; + +async function collectDrift(snapshot, refreshInputPath) { + const catalog = JSON.parse((await readUpstream(refreshInputPath)).text); + const previousMetadata = snapshot.projection.metadata; + const previousPricing = new Map( + snapshot.projection.pricing.map((entry) => [entry.modelKey, entry]), + ); + const report = { missingProviders: [], unprojectable: [], added: [], removed: [], changed: [] }; + for (const [providerType, sourceId] of Object.entries(PROVIDERS)) { + const provider = catalog[sourceId]; + const previousModels = previousMetadata[providerType] ?? {}; + const models = provider?.models; + if (!models || typeof models !== 'object' || Array.isArray(models)) { + report.missingProviders.push(`${providerType} (models.dev ${sourceId})`); + continue; + } + const priced = !PRICING_EXCLUDED_PROVIDER_TYPES.has(providerType); + const ids = [...new Set([...Object.keys(previousModels), ...Object.keys(models)])].sort(); + for (const id of ids) { + const model = models[id]; + const previous = previousModels[id]; + if (model === undefined) { + report.removed.push(`${providerType}/${id}`); + continue; + } + let metadata; + let pricing; + try { + metadata = toMetadata(sourceId, id, provider, model); + pricing = priced ? toPricing(providerType, id, model) : undefined; + } catch (error) { + report.unprojectable.push(`${providerType}/${id}: ${error.message}`); + continue; + } + if (previous === undefined) { + report.added.push(`${providerType}/${id}`); + continue; + } + const fields = driftedFields(previous, metadata); + if (priced && !sameValue(previousPricing.get(`${providerType}:${id}`), pricing)) { + fields.push('pricing'); + } + if (fields.length > 0) report.changed.push(`${providerType}/${id}: ${fields.join(', ')}`); + } + } + const drifted = Object.values(report).some((entries) => entries.length > 0); + return { ...report, drifted }; +} + +function driftedFields(previous, next) { + const keys = [...new Set([...Object.keys(previous), ...Object.keys(next)])].sort(); + return keys.filter((key) => !sameValue(previous[key], next[key])); +} + +// Both sides are projector output, so their keys are already in one order. +function sameValue(left, right) { + return JSON.stringify(left) === JSON.stringify(right); +} + +function formatDrift(report) { + const lines = []; + for (const [label, entries] of [ + ['providers missing upstream', report.missingProviders], + ['models the projector rejects', report.unprojectable], + ['models upstream has and the snapshot does not', report.added], + ['models the snapshot has and upstream does not', report.removed], + ['models whose projection changed', report.changed], + ]) { + if (entries.length === 0) continue; + lines.push(`${label}: ${entries.length}`); + for (const entry of entries.slice(0, DRIFT_LIST_LIMIT)) lines.push(` ${entry}`); + if (entries.length > DRIFT_LIST_LIMIT) { + lines.push(` ... and ${entries.length - DRIFT_LIST_LIMIT} more`); + } + } + if (!report.drifted) return `${SOURCE_URL} matches the committed snapshot.`; + return [`${SOURCE_URL} has drifted from the committed snapshot.`, ...lines].join('\n'); +} + async function replaceFilesTransactionally(writes) { if (new Set(writes.map((write) => write.path)).size !== writes.length) { throw new Error('model metadata outputs must use distinct paths'); @@ -705,7 +807,9 @@ function buildPricingModule(pricing, source) { } if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) { - await main(); + // Drift is a finding, not a crash: the report has already been printed, and + // the exit code is what a scheduled job branches on. + if ((await main())?.drifted) process.exitCode = 1; } function option(name, argv) { diff --git a/scripts/sync-model-metadata.test.mjs b/scripts/sync-model-metadata.test.mjs index b0c9f0eef3..cf63c04183 100644 --- a/scripts/sync-model-metadata.test.mjs +++ b/scripts/sync-model-metadata.test.mjs @@ -302,6 +302,104 @@ test('refresh rejects unknown model modalities instead of dropping them', async } }); +// The drift report goes to stdout for the scheduled job's summary; tests read +// the returned buckets instead of the printed text. +async function drift(argv) { + const written = []; + const original = process.stdout.write; + process.stdout.write = (chunk) => { + written.push(String(chunk)); + return true; + }; + try { + return { report: await main(['node', 'sync-model-metadata.mjs', '--drift', ...argv]) }; + } finally { + process.stdout.write = original; + assert.ok(written.join('').length > 0, 'drift must print a report'); + } +} + +test('drift finds nothing when the snapshot still matches upstream', async () => { + const root = await mkdtemp(join(tmpdir(), 'maka-model-drift-clean-')); + try { + const input = join(root, 'api.json'); + const snapshot = join(root, 'snapshot.json'); + await writeFile(input, JSON.stringify(fixtureCatalog())); + await main([ + 'node', + 'sync-model-metadata.mjs', + '--refresh', + '--refresh-input', + input, + '--snapshot', + snapshot, + '--output', + join(root, 'metadata.ts'), + ]); + + const { report } = await drift(['--snapshot', snapshot, '--refresh-input', input]); + assert.equal(report.drifted, false); + assert.deepEqual( + [report.added, report.removed, report.changed, report.unprojectable, report.missingProviders], + [[], [], [], [], []], + ); + } finally { + await rm(root, { recursive: true, force: true }); + } +}); + +test('drift separates a rejected shape from a real upstream difference', async () => { + const root = await mkdtemp(join(tmpdir(), 'maka-model-drift-')); + try { + const committed = join(root, 'api.json'); + const upstream = join(root, 'upstream.json'); + const snapshot = join(root, 'snapshot.json'); + const before = fixtureCatalog(); + before.anthropic.models.legacy = { ...before.anthropic.models.model, name: 'Legacy' }; + await writeFile(committed, JSON.stringify(before)); + await main([ + 'node', + 'sync-model-metadata.mjs', + '--refresh', + '--refresh-input', + committed, + '--snapshot', + snapshot, + '--output', + join(root, 'metadata.ts'), + ]); + + const after = JSON.parse(JSON.stringify(before)); + delete after.anthropic.models.legacy; + after.anthropic.models.added = { ...after.anthropic.models.model, name: 'Added' }; + after.anthropic.models.model.name = 'Renamed'; + after.anthropic.models.model.cost = { input: 9, output: 9 }; + after.groq.models.model.modalities = { input: ['text', 'hologram'], output: ['text'] }; + delete after.openai; + await writeFile(upstream, JSON.stringify(after)); + + const { report } = await drift(['--snapshot', snapshot, '--refresh-input', upstream]); + assert.equal(report.drifted, true); + assert.deepEqual(report.added, ['anthropic/added']); + assert.deepEqual(report.removed, ['anthropic/legacy']); + assert.deepEqual(report.changed, ['anthropic/model: displayName, pricing']); + assert.deepEqual(report.missingProviders, ['openai (models.dev openai)']); + assert.equal(report.unprojectable.length, 1); + assert.match(report.unprojectable[0], /^groq\/model: .*unsupported modalities/u); + } finally { + await rm(root, { recursive: true, force: true }); + } +}); + +test('drift refuses to combine with the modes that write', async () => { + for (const mode of ['--refresh', '--check']) { + await assert.rejects( + main(['node', 'sync-model-metadata.mjs', '--drift', mode]), + /--drift reports without writing/u, + ); + } +}); + test('refresh carries the video and pdf modalities models.dev declares', async () => { const root = await mkdtemp(join(tmpdir(), 'maka-model-snapshot-video-')); try { From e2b5fcd823cbf8ef6c88911adfaf2a417fde9a3a Mon Sep 17 00:00:00 2001 From: AstroHan Date: Tue, 1 Sep 2026 18:29:31 +0800 Subject: [PATCH 4/9] feat(scripts): cap what --accept-upstream-removals may acknowledge The refresh refuses to drop a committed projection path, and --accept-upstream-removals waives that so a person can acknowledge the handful of models a provider retired. Nothing bounded the waiver: an upstream serving a truncated catalog removes paths exactly the same way, and the flag would wave a gutted snapshot straight into the build input. Give the acknowledgement a ceiling. Removals past it are an outage, not a catalog change, and no flag clears them. This bounds the one hole rather than standing a second size check beside the guard that already computes the removals. The required-provider half of the sanity floor already exists: PROVIDERS is that list, and a provider that is missing or has no models fails the projection before any of this runs. Generated-by: Claude Code --- scripts/sync-model-metadata.mjs | 27 ++++++++++----- scripts/sync-model-metadata.test.mjs | 49 ++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 8 deletions(-) diff --git a/scripts/sync-model-metadata.mjs b/scripts/sync-model-metadata.mjs index 8f820cdf95..b1b74db6b3 100644 --- a/scripts/sync-model-metadata.mjs +++ b/scripts/sync-model-metadata.mjs @@ -266,9 +266,9 @@ async function readUpstream(refreshInputPath) { async function refreshSnapshot(snapshotPath, refreshInputPath, options = {}) { const { text: sourceText, etag: sourceEtag, retrievedAt } = await readUpstream(refreshInputPath); const projection = buildProjection(selectCatalog(JSON.parse(sourceText))); - if (!options.acceptUpstreamRemovals) { - const previous = await loadSnapshotIfPresent(snapshotPath); - if (previous) assertProjectionDoesNotShrink(previous.projection, projection); + const previous = await loadSnapshotIfPresent(snapshotPath); + if (previous) { + assertAcceptableRemovals(previous.projection, projection, options.acceptUpstreamRemovals); } const projectionText = JSON.stringify(projection); const snapshot = { @@ -292,14 +292,25 @@ async function refreshSnapshot(snapshotPath, refreshInputPath, options = {}) { }; } -function assertProjectionDoesNotShrink(previous, next) { +// What --accept-upstream-removals is for: a handful of models the provider +// retired. An upstream outage serving a truncated catalog removes paths the +// same way, so the acknowledgement stops here. +const MAXIMUM_ACKNOWLEDGED_REMOVALS = 100; + +function assertAcceptableRemovals(previous, next, acknowledged) { const removals = []; collectProjectionRemovals(previous, next, [], removals); if (removals.length === 0) return; - - throw new Error( - `models.dev refresh would remove committed projection paths: ${removals.sort().join(', ')}; inspect the upstream change and rerun with --accept-upstream-removals to acknowledge it`, - ); + if (!acknowledged) { + throw new Error( + `models.dev refresh would remove committed projection paths: ${removals.sort().join(', ')}; inspect the upstream change and rerun with --accept-upstream-removals to acknowledge it`, + ); + } + if (removals.length > MAXIMUM_ACKNOWLEDGED_REMOVALS) { + throw new Error( + `models.dev refresh would remove ${removals.length} committed projection paths, more than the ${MAXIMUM_ACKNOWLEDGED_REMOVALS} --accept-upstream-removals acknowledges; treat a change this size as an upstream outage`, + ); + } } function collectProjectionRemovals(previous, next, path, removals) { diff --git a/scripts/sync-model-metadata.test.mjs b/scripts/sync-model-metadata.test.mjs index cf63c04183..eecdf11c5a 100644 --- a/scripts/sync-model-metadata.test.mjs +++ b/scripts/sync-model-metadata.test.mjs @@ -485,6 +485,55 @@ test('refresh rejects a partial provider shrink until it is explicitly accepted' } }); +test('accepting upstream removals still refuses a truncated catalog', async () => { + const root = await mkdtemp(join(tmpdir(), 'maka-model-snapshot-truncated-')); + try { + const committed = join(root, 'api.json'); + const outage = join(root, 'outage.json'); + const snapshot = join(root, 'snapshot.json'); + const metadata = join(root, 'metadata.ts'); + const full = fixtureCatalog(); + for (const provider of Object.values(full)) { + const [model] = Object.values(provider.models); + if (!model) continue; + for (const suffix of ['b', 'c', 'd']) provider.models[`model-${suffix}`] = { ...model }; + } + await writeFile(committed, JSON.stringify(full)); + await writeFile(outage, JSON.stringify(fixtureCatalog())); + await main([ + 'node', + 'sync-model-metadata.mjs', + '--refresh', + '--refresh-input', + committed, + '--snapshot', + snapshot, + '--output', + metadata, + ]); + const committedSnapshot = await readFile(snapshot, 'utf8'); + + await assert.rejects( + main([ + 'node', + 'sync-model-metadata.mjs', + '--refresh', + '--accept-upstream-removals', + '--refresh-input', + outage, + '--snapshot', + snapshot, + '--output', + metadata, + ]), + /more than the 100 --accept-upstream-removals acknowledges/u, + ); + assert.equal(await readFile(snapshot, 'utf8'), committedSnapshot); + } finally { + await rm(root, { recursive: true, force: true }); + } +}); + test('refresh rejects lost pricing coverage from an otherwise valid model', async () => { const root = await mkdtemp(join(tmpdir(), 'maka-model-snapshot-pricing-shrink-')); try { From 14a6a16d63a9d4b1004581069ff5415b7b6a8a23 Mon Sep 17 00:00:00 2001 From: AstroHan Date: Tue, 1 Sep 2026 18:22:23 +0800 Subject: [PATCH 5/9] ci: refresh the model metadata snapshot weekly into a review pull request Nothing ran refresh:model-metadata on a schedule, so the snapshot moved only when someone happened to think of it. Weekly, not nightly: the snapshot is a build input a person reviews, so a daily cadence stacks five near-identical pull requests against one week of upstream movement, on runners the whole foundation shares. The job reports drift, refreshes, verifies the regenerated outputs, and opens a draft pull request for review. It never merges its own work and never passes --accept-upstream-removals: a model leaving upstream is a decision for a person, so the job fails and says so. No pull_request trigger. The drift check needs models.dev to be reachable, which is not a precondition for reviewing a change, and a new workflow on every pull request costs a queue slot on shared runners. The workflow and its policy test join the existing asf_source lane instead, so ci.yml runs them through check:asf-source when either file moves. Generated-by: Claude Code --- .github/workflows/model-metadata-upkeep.yml | 135 ++++++++++++++++++ package.json | 2 +- scripts/ci-test-plan.mjs | 2 + ...l-metadata-upkeep-workflow-policy.test.mjs | 102 +++++++++++++ 4 files changed, 240 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/model-metadata-upkeep.yml create mode 100644 scripts/model-metadata-upkeep-workflow-policy.test.mjs diff --git a/.github/workflows/model-metadata-upkeep.yml b/.github/workflows/model-metadata-upkeep.yml new file mode 100644 index 0000000000..9960f0f3fe --- /dev/null +++ b/.github/workflows/model-metadata-upkeep.yml @@ -0,0 +1,135 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +name: Model metadata upkeep + +on: + schedule: + # Weekly, offset from the hour to reduce peak-time scheduling delays. The + # snapshot is a build input a human reviews, so a nightly cadence would + # only stack five near-identical pull requests against one week of upstream + # movement, on runners the whole foundation shares. + - cron: '41 6 * * 1' + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: model-metadata-upkeep + cancel-in-progress: false + +jobs: + refresh: + # A fork inherits the schedule but owns neither the branch this pushes nor + # the pull request it opens. + if: github.repository == 'apache/maka' + runs-on: ubuntu-latest + timeout-minutes: 30 + permissions: + contents: write + pull-requests: write + steps: + - name: Check out the repository + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + + - name: Set up Node.js + uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + with: + node-version: '24' + cache: npm + + - name: Install dependencies + run: npm ci --ignore-scripts + + - name: Report snapshot drift against models.dev + # Drift exits non-zero by design. The report is what this step is for, + # and the refresh below is what decides whether the run fails. + continue-on-error: true + run: npm run --silent check:model-metadata-drift 2>&1 | tee "$RUNNER_TEMP/drift.txt" + + - name: Publish the drift report + run: | + { + echo '### models.dev drift' + echo '' + echo '```text' + cat "$RUNNER_TEMP/drift.txt" + echo '```' + } >> "$GITHUB_STEP_SUMMARY" + + # No --accept-upstream-removals. A model leaving upstream is a decision + # for a person, so the job fails and says so rather than committing the + # removal into a pull request nobody asked for. + - name: Refresh the snapshot from models.dev + run: npm run refresh:model-metadata + + - name: Verify the regenerated outputs + run: npm run check:model-metadata + + - name: Detect a snapshot change + id: change + run: | + if git diff --quiet -- scripts/model-metadata/models-dev-api.snapshot.json; then + echo 'changed=false' >> "$GITHUB_OUTPUT" + else + echo 'changed=true' >> "$GITHUB_OUTPUT" + fi + + - name: Open the review pull request + if: steps.change.outputs.changed == 'true' + env: + BRANCH: automation/model-metadata-refresh + GH_TOKEN: ${{ github.token }} + TITLE: 'chore(model-metadata): refresh the models.dev snapshot' + run: | + { + echo '## Summary' + echo '' + echo 'Scheduled `refresh:model-metadata` run. The snapshot is the build' + echo 'input for the bundled model catalog; this only moves it to what' + echo 'models.dev serves today.' + echo '' + echo 'Refs #4398' + echo '' + echo '## Verification' + echo '' + echo 'The workflow ran `refresh:model-metadata` and `check:model-metadata`' + echo 'before opening this. Drift against upstream at refresh time:' + echo '' + echo '```text' + cat "$RUNNER_TEMP/drift.txt" + echo '```' + } > "$RUNNER_TEMP/pr-body.md" + git config user.name 'Apache Maka' + git config user.email 'commits@maka.apache.org' + git switch -c "$BRANCH" + git add scripts/model-metadata/models-dev-api.snapshot.json + git commit -m "$TITLE" + git push --force \ + "https://x-access-token:${GH_TOKEN}@github.com/${GITHUB_REPOSITORY}" \ + "HEAD:refs/heads/$BRANCH" + # A force push updates an open pull request in place, so only open one + # when none is waiting. + if gh pr view "$BRANCH" --json number >/dev/null 2>&1; then + echo "Updated the open pull request on $BRANCH." + else + gh pr create --draft --base main --head "$BRANCH" \ + --title "$TITLE" --body-file "$RUNNER_TEMP/pr-body.md" + fi diff --git a/package.json b/package.json index ccbba4bcdb..0cd0891641 100644 --- a/package.json +++ b/package.json @@ -62,7 +62,7 @@ "release:asf:source": "node scripts/asf-source-release.mjs create", "release:asf:verify": "node scripts/asf-source-release.mjs verify", "release:asf:sign": "node scripts/asf-source-release.mjs sign", - "check:asf-source": "npm run check:model-metadata && node --test scripts/asf-source-release.test.mjs scripts/asf-source-workflow-policy.test.mjs scripts/asf-license-headers.test.mjs scripts/source-legal-inventory.test.mjs scripts/sync-model-metadata.test.mjs", + "check:asf-source": "npm run check:model-metadata && node --test scripts/asf-source-release.test.mjs scripts/asf-source-workflow-policy.test.mjs scripts/asf-license-headers.test.mjs scripts/model-metadata-upkeep-workflow-policy.test.mjs scripts/source-legal-inventory.test.mjs scripts/sync-model-metadata.test.mjs", "check:asf-npm": "node --test scripts/asf-npm-workflow-policy.test.mjs", "check:product-release-identity": "node scripts/product-release-identity.mjs", "package:cli:macos-arm64": "node scripts/package-macos-arm64-cli.mjs", diff --git a/scripts/ci-test-plan.mjs b/scripts/ci-test-plan.mjs index 149dd30152..b66320136c 100644 --- a/scripts/ci-test-plan.mjs +++ b/scripts/ci-test-plan.mjs @@ -118,6 +118,7 @@ const CLI_PACKAGE_FILES = new Set([ const ASF_SOURCE_FILES = new Set([ '.github/workflows/asf-source-candidate.yml', + '.github/workflows/model-metadata-upkeep.yml', 'DISCLAIMER-WIP', 'LICENSE', 'NOTICE', @@ -131,6 +132,7 @@ const ASF_SOURCE_FILES = new Set([ 'scripts/asf-source-release.mjs', 'scripts/asf-source-release.test.mjs', 'scripts/asf-source-workflow-policy.test.mjs', + 'scripts/model-metadata-upkeep-workflow-policy.test.mjs', 'scripts/model-metadata/models-dev-api.snapshot.json', 'scripts/source-legal-inventory.test.mjs', 'scripts/sync-model-metadata.mjs', diff --git a/scripts/model-metadata-upkeep-workflow-policy.test.mjs b/scripts/model-metadata-upkeep-workflow-policy.test.mjs new file mode 100644 index 0000000000..2c3884c76c --- /dev/null +++ b/scripts/model-metadata-upkeep-workflow-policy.test.mjs @@ -0,0 +1,102 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import assert from 'node:assert/strict'; +import { readFile } from 'node:fs/promises'; +import { test } from 'node:test'; +import { parse } from 'yaml'; + +async function readUpkeepWorkflow() { + return parse( + await readFile( + new URL('../.github/workflows/model-metadata-upkeep.yml', import.meta.url), + 'utf8', + ), + ); +} + +async function readRootScripts() { + return JSON.parse(await readFile(new URL('../package.json', import.meta.url), 'utf8')).scripts; +} + +function stepNamed(workflow, name) { + const step = workflow.jobs.refresh.steps.find((candidate) => candidate.name === name); + assert.ok(step, `missing step: ${name}`); + return step; +} + +test('upkeep runs on a weekly schedule and never against a pull request', async () => { + const workflow = await readUpkeepWorkflow(); + assert.deepEqual(Object.keys(workflow.on).toSorted(), ['schedule', 'workflow_dispatch']); + assert.equal(workflow.on.schedule.length, 1); + const [minute, hour, dayOfMonth, month, dayOfWeek] = workflow.on.schedule[0].cron.split(' '); + // A single weekday with a fixed hour is the weekly cadence. Runners are a + // shared foundation resource and every daily run costs a queue slot. + assert.match(dayOfWeek, /^[0-6]$/u); + assert.deepEqual([dayOfMonth, month], ['*', '*']); + assert.doesNotMatch(minute, /^[*0]$/u); + assert.match(hour, /^\d+$/u); +}); + +test('only the scheduled job writes, and only on the canonical repository', async () => { + const workflow = await readUpkeepWorkflow(); + assert.deepEqual(workflow.permissions, { contents: 'read' }); + assert.deepEqual(workflow.jobs.refresh.permissions, { + contents: 'write', + 'pull-requests': 'write', + }); + assert.match(workflow.jobs.refresh.if, /github\.repository == 'apache\/maka'/u); + assert.equal(Object.keys(workflow.jobs).length, 1); + assert.equal(stepNamed(workflow, 'Check out the repository').with['persist-credentials'], false); +}); + +test('the refresh reports drift first and refuses to waive upstream removals', async () => { + const workflow = await readUpkeepWorkflow(); + const order = [ + 'Report snapshot drift against models.dev', + 'Refresh the snapshot from models.dev', + ].map((name) => workflow.jobs.refresh.steps.findIndex((step) => step.name === name)); + assert.ok(order.every((position) => position >= 0)); + assert.ok(order[0] < order[1]); + assert.equal( + stepNamed(workflow, 'Report snapshot drift against models.dev')['continue-on-error'], + true, + ); + assert.doesNotMatch(JSON.stringify(workflow), /--accept-upstream-removals/u); +}); + +test('the pull request is opened for review and never merged by the job', async () => { + const workflow = await readUpkeepWorkflow(); + const open = stepNamed(workflow, 'Open the review pull request'); + assert.match(open.run, /gh pr create --draft/u); + assert.doesNotMatch(JSON.stringify(workflow), /gh pr merge|--auto\b|--admin\b/u); +}); + +test('the drift check stays out of the checks that run on every pull request', async () => { + const scripts = await readRootScripts(); + assert.equal( + scripts['check:model-metadata-drift'], + 'node scripts/sync-model-metadata.mjs --drift', + ); + // Reaching models.dev is not a precondition for reviewing a pull request. + for (const gate of ['check:asf-source', 'check:release']) { + assert.doesNotMatch(scripts[gate], /check:model-metadata-drift|--drift/u); + } + assert.match(scripts['check:asf-source'], /model-metadata-upkeep-workflow-policy\.test\.mjs/u); +}); From 28b9414758f71cc7abb886fe6580c908a258302b Mon Sep 17 00:00:00 2001 From: AstroHan Date: Tue, 1 Sep 2026 18:34:03 +0800 Subject: [PATCH 6/9] chore(model-metadata): refresh the models.dev snapshot MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The snapshot was projected from a models.dev response old enough to predate glm-5.3, and the epoch bump two commits back declared a wire contract for video and pdf modalities that no committed data used. Both are the same gap: the machinery around the snapshot is worth nothing until the snapshot itself is current. Refreshed against a live models.dev response, which the origin now records with its etag rather than the migration marker it carried since the projection moved out of generated output. 1871 models become 1906, and 324 of them declare the modalities the projector could not represent until this branch. Ran with --accept-upstream-removals for 31 models models.dev has retired. The two that a reader will look for, deepseek-chat and deepseek-reasoner, stay selectable: provider-registry lists them under fallbackModels and builtin-pricing carries their rates, so only the bundled display metadata goes. 133 models now declare an output modality without text. model-catalog already refuses those as chat defaults and documented why it could not see the video ones; it can now. Three runtime assertions move with the catalog they read. MiniMax-M3's wire output limit is 512k upstream, not 128k. Tencent Token Plan's hy3 now documents `none` and `high` where it listed low/medium/high, so the exposed variants become off/high and `off` names the provider's own no-reasoning value instead of dropping the knob — the same shape the Vercel case in that file already asserts. Generated-by: Claude Code --- .../core/src/__tests__/model-catalog.test.ts | 23 +- .../computer-use-provider-protocol.test.ts | 2 +- .../__tests__/model-factory-thinking.test.ts | 11 +- .../models-dev-api.snapshot.json | 3684 +++++++++++------ 4 files changed, 2357 insertions(+), 1363 deletions(-) diff --git a/packages/core/src/__tests__/model-catalog.test.ts b/packages/core/src/__tests__/model-catalog.test.ts index afb0fff804..b6a6d7574a 100644 --- a/packages/core/src/__tests__/model-catalog.test.ts +++ b/packages/core/src/__tests__/model-catalog.test.ts @@ -112,19 +112,28 @@ test('a declared output modality without text rules a model out of chat', () => modelSource: 'fetched' as const, }; assert.deepEqual(verdict(audioOnly), { ok: false }); -}); -test('an empty output modality list is not evidence against chat', () => { - // `modalities.output` is typed to text, image, and audio, so a video model's - // real output has no representation and serializes as `[]` — the same shape - // a generator bug would produce. Blocking on it would be guessing. - const video = { + // Video-only says exactly what the other two say. It could not be read at + // all until `modalities.output` could carry the value. + const videoOnly = { providerType: 'google' as const, defaultModel: 'gemini-omni-flash-preview', models: [{ id: 'gemini-omni-flash-preview' }], modelSource: 'fetched' as const, }; - assert.deepEqual(verdict(video), { ok: true }); + assert.deepEqual(verdict(videoOnly), { ok: false }); +}); + +test('an empty output modality list is not evidence against chat', () => { + // A provider that declared no output modality and a generator bug that + // dropped them produce the same shape. Blocking on it would be guessing. + const undeclared = { + providerType: 'openai-compatible' as const, + defaultModel: 'relay-quiet', + models: [{ id: 'relay-quiet', modalities: { input: ['text' as const], output: [] } }], + modelSource: 'fetched' as const, + }; + assert.deepEqual(verdict(undeclared), { ok: true }); }); test('an explicit chat capability outranks the declared output modality', () => { diff --git a/packages/runtime/src/__tests__/computer-use-provider-protocol.test.ts b/packages/runtime/src/__tests__/computer-use-provider-protocol.test.ts index 70ae04705d..8923a1e74b 100644 --- a/packages/runtime/src/__tests__/computer-use-provider-protocol.test.ts +++ b/packages/runtime/src/__tests__/computer-use-provider-protocol.test.ts @@ -199,7 +199,7 @@ describe('Anthropic-compatible Computer Use product loops', () => { auth: 'x-api-key', expectedAuth: 'test-key', expectedThinking: undefined, - expectedWireOutputLimit: 128_000, + expectedWireOutputLimit: 512_000, apiProtocol: undefined, }, { diff --git a/packages/runtime/src/__tests__/model-factory-thinking.test.ts b/packages/runtime/src/__tests__/model-factory-thinking.test.ts index 6a33ad80f2..4762c2d72c 100644 --- a/packages/runtime/src/__tests__/model-factory-thinking.test.ts +++ b/packages/runtime/src/__tests__/model-factory-thinking.test.ts @@ -684,14 +684,15 @@ describe('buildProviderOptions: thinking level', () => { }); test('Tencent Token Plan sends its documented reasoning effort under the stable provider namespace', () => { - assert.deepEqual( - [...thinkingVariantsForModel('tencent-token-plan', 'hy3')], - ['low', 'medium', 'high'], - ); + assert.deepEqual([...thinkingVariantsForModel('tencent-token-plan', 'hy3')], ['off', 'high']); assert.deepEqual(buildProviderOptions(conn('tencent-token-plan'), 'hy3', 'high'), { tencentTokenPlan: { reasoningEffort: 'high' }, }); - assert.deepEqual(buildProviderOptions(conn('tencent-token-plan'), 'hy3', 'off'), {}); + // The plan documents an explicit no-reasoning value, so off names it rather + // than dropping the knob and leaving the provider to pick. + assert.deepEqual(buildProviderOptions(conn('tencent-token-plan'), 'hy3', 'off'), { + tencentTokenPlan: { reasoningEffort: 'none' }, + }); }); test('Vercel Gateway sends reasoning effort under its stable namespace and exact model id', () => { diff --git a/scripts/model-metadata/models-dev-api.snapshot.json b/scripts/model-metadata/models-dev-api.snapshot.json index 9f81accaa3..c7c5161db3 100644 --- a/scripts/model-metadata/models-dev-api.snapshot.json +++ b/scripts/model-metadata/models-dev-api.snapshot.json @@ -2,10 +2,12 @@ "formatVersion": 1, "sourceUrl": "https://models.dev/api.json", "origin": { - "kind": "generated-output-migration", - "commit": "729839ed8ada3e5498b0ad27e64fb42dfd283ae7" + "kind": "models-dev-response", + "retrievedAt": "2026-09-01T10:29:38.000Z", + "etag": "W/\"7559b5b3701539769901f1e20e89315d\"", + "responseSha256": "7559b5b3701539769901f1e20e89315d94975a7b289646590d6f854a21e12f17" }, - "projectionSha256": "ed57286d0b96112574c227b5a327bfa5bbd572233b0bf2a27fe41e00d511beee", + "projectionSha256": "85b25f334b65929079ea6dab9b0a2a66f433e3d66710fcd1aadff5f611b37345", "projection": { "metadata": { "anthropic": { @@ -436,7 +438,7 @@ "functionCalling": true }, "modalities": { - "input": ["text", "image", "audio"], + "input": ["text", "image", "audio", "video"], "output": ["text", "audio"] } }, @@ -658,7 +660,7 @@ "functionCalling": true }, "modalities": { - "input": ["text", "image", "audio"], + "input": ["text", "image", "audio", "video"], "output": ["text", "audio"] } }, @@ -886,7 +888,7 @@ "functionCalling": false }, "modalities": { - "input": ["text", "image", "audio"], + "input": ["text", "image", "audio", "video"], "output": ["text", "audio"] } }, @@ -961,7 +963,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image", "audio"], + "input": ["text", "image", "audio", "video"], "output": ["text", "audio"] } }, @@ -979,7 +981,7 @@ "functionCalling": true }, "modalities": { - "input": ["text", "image", "audio"], + "input": ["text", "image", "audio", "video"], "output": ["text", "audio"] } }, @@ -1057,7 +1059,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image", "audio"], + "input": ["text", "image", "video", "audio"], "output": ["text"] } }, @@ -1078,7 +1080,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image", "audio"], + "input": ["text", "image", "video", "audio"], "output": ["text"] } }, @@ -1099,7 +1101,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image", "audio"], + "input": ["text", "image", "video", "audio"], "output": ["text"] } }, @@ -1120,7 +1122,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image", "audio"], + "input": ["text", "image", "video", "audio"], "output": ["text"] } }, @@ -1141,7 +1143,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -1162,7 +1164,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image", "audio"], + "input": ["text", "image", "video", "audio"], "output": ["text"] } }, @@ -1183,7 +1185,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image", "audio"], + "input": ["text", "image", "video", "audio"], "output": ["text"] } }, @@ -1204,7 +1206,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -1246,7 +1248,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -1287,7 +1289,29 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], + "output": ["text"] + } + }, + "qwen3.8-flash": { + "displayName": "Qwen3.8 Flash", + "description": "Qwen vision-language model for visual reasoning, documents, and agent tasks", + "lifecycle": "active", + "contextWindow": 1000000, + "maxOutputTokens": 131072, + "structuredOutput": true, + "lastUpdated": "2026-08-26", + "capabilities": { + "vision": true, + "reasoning": true, + "functionCalling": true + }, + "thinkingOptions": { + "efforts": ["low", "medium", "xhigh"], + "toggle": true + }, + "modalities": { + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -1309,7 +1333,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image", "pdf"], + "input": ["text", "image", "video", "pdf"], "output": ["text"] } }, @@ -1391,6 +1415,7 @@ "contextWindow": 32768, "maxOutputTokens": 16384, "lastUpdated": "2025-01-01", + "isFree": true, "capabilities": { "vision": false, "reasoning": true, @@ -1408,6 +1433,7 @@ "contextWindow": 32768, "maxOutputTokens": 16384, "lastUpdated": "2025-01-01", + "isFree": true, "capabilities": { "vision": false, "reasoning": true, @@ -1661,7 +1687,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -1683,7 +1709,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -1705,7 +1731,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -1958,7 +1984,7 @@ "functionCalling": true }, "modalities": { - "input": ["text", "image", "audio"], + "input": ["text", "image", "audio", "video"], "output": ["text", "audio"] } }, @@ -2252,7 +2278,7 @@ "functionCalling": true }, "modalities": { - "input": ["text", "image", "audio"], + "input": ["text", "image", "audio", "video"], "output": ["text", "audio"] } }, @@ -2537,7 +2563,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image", "audio"], + "input": ["text", "image", "audio", "video"], "output": ["text", "audio"] } }, @@ -2633,7 +2659,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -2655,7 +2681,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -2676,7 +2702,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -2697,7 +2723,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -2739,7 +2765,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -2761,7 +2787,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -2802,7 +2828,29 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], + "output": ["text"] + } + }, + "qwen3.8-flash": { + "displayName": "Qwen3.8 Flash", + "description": "Qwen vision-language model for visual reasoning, documents, and agent tasks", + "lifecycle": "active", + "contextWindow": 1000000, + "maxOutputTokens": 131072, + "structuredOutput": true, + "lastUpdated": "2026-08-26", + "capabilities": { + "vision": true, + "reasoning": true, + "functionCalling": true + }, + "thinkingOptions": { + "efforts": ["low", "medium", "xhigh"], + "toggle": true + }, + "modalities": { + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -2824,7 +2872,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image", "pdf"], + "input": ["text", "image", "video", "pdf"], "output": ["text"] } }, @@ -3141,7 +3189,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -3163,7 +3211,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -3205,7 +3253,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } } @@ -3272,7 +3320,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -3370,7 +3418,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -3391,7 +3439,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -3413,7 +3461,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -3455,7 +3503,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } } @@ -3563,7 +3611,7 @@ "contextWindow": 1000000, "maxOutputTokens": 384000, "structuredOutput": true, - "lastUpdated": "2026-08-12", + "lastUpdated": "2026-08-22", "isFree": true, "capabilities": { "vision": false, @@ -3660,7 +3708,7 @@ }, "modalities": { "input": ["image", "text"], - "output": [] + "output": ["video"] } }, "happyhorse-1.1-r2v": { @@ -3678,7 +3726,7 @@ }, "modalities": { "input": ["image", "text"], - "output": [] + "output": ["video"] } }, "happyhorse-1.1-t2v": { @@ -3696,7 +3744,7 @@ }, "modalities": { "input": ["text"], - "output": [] + "output": ["video"] } }, "kimi-k2.5": { @@ -3718,7 +3766,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -3741,7 +3789,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -3764,7 +3812,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -3841,7 +3889,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -3864,7 +3912,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -3909,7 +3957,30 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], + "output": ["text"] + } + }, + "qwen3.8-flash": { + "displayName": "Qwen3.8 Flash", + "description": "Qwen vision-language model for visual reasoning, documents, and agent tasks", + "lifecycle": "active", + "contextWindow": 1000000, + "maxOutputTokens": 131072, + "structuredOutput": true, + "lastUpdated": "2026-08-26", + "isFree": true, + "capabilities": { + "vision": true, + "reasoning": true, + "functionCalling": true + }, + "thinkingOptions": { + "efforts": ["low", "medium", "xhigh"], + "toggle": true + }, + "modalities": { + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -3932,7 +4003,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image", "pdf"], + "input": ["text", "image", "video", "pdf"], "output": ["text"] } }, @@ -3954,7 +4025,7 @@ "efforts": ["low", "medium", "xhigh"] }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -4098,7 +4169,7 @@ "contextWindow": 1000000, "maxOutputTokens": 384000, "structuredOutput": true, - "lastUpdated": "2026-08-12", + "lastUpdated": "2026-08-22", "isFree": true, "capabilities": { "vision": false, @@ -4195,7 +4266,7 @@ }, "modalities": { "input": ["image", "text"], - "output": [] + "output": ["video"] } }, "happyhorse-1.1-r2v": { @@ -4213,7 +4284,7 @@ }, "modalities": { "input": ["image", "text"], - "output": [] + "output": ["video"] } }, "happyhorse-1.1-t2v": { @@ -4231,7 +4302,7 @@ }, "modalities": { "input": ["text"], - "output": [] + "output": ["video"] } }, "kimi-k2.5": { @@ -4253,7 +4324,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -4276,7 +4347,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -4299,7 +4370,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -4376,7 +4447,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -4399,7 +4470,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -4444,7 +4515,30 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], + "output": ["text"] + } + }, + "qwen3.8-flash": { + "displayName": "Qwen3.8 Flash", + "description": "Qwen vision-language model for visual reasoning, documents, and agent tasks", + "lifecycle": "active", + "contextWindow": 1000000, + "maxOutputTokens": 131072, + "structuredOutput": true, + "lastUpdated": "2026-08-26", + "isFree": true, + "capabilities": { + "vision": true, + "reasoning": true, + "functionCalling": true + }, + "thinkingOptions": { + "efforts": ["low", "medium", "xhigh"], + "toggle": true + }, + "modalities": { + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -4467,7 +4561,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image", "pdf"], + "input": ["text", "image", "video", "pdf"], "output": ["text"] } }, @@ -4489,7 +4583,7 @@ "efforts": ["low", "medium", "xhigh"] }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -4904,7 +4998,7 @@ "contextWindow": 1048576, "maxOutputTokens": 1048576, "structuredOutput": true, - "lastUpdated": "2026-08-12", + "lastUpdated": "2026-08-22", "capabilities": { "vision": false, "reasoning": true, @@ -5338,6 +5432,46 @@ "input": ["text"], "output": ["text"] } + }, + "@cf/zai-org/glm-5.3": { + "displayName": "Glm 5.3", + "description": "Flagship GLM model for hybrid reasoning, coding, and agentic engineering", + "lifecycle": "active", + "contextWindow": 1310720, + "maxOutputTokens": 1310720, + "structuredOutput": true, + "lastUpdated": "2026-08-14", + "capabilities": { + "vision": false, + "reasoning": true, + "functionCalling": true + }, + "thinkingOptions": { + "efforts": ["low", "medium", "high"], + "toggle": true + }, + "modalities": { + "input": ["text"], + "output": ["text"] + } + }, + "@cf/zai-org/glm-5.3-flash": { + "displayName": "Glm 5.3 Flash", + "description": "GLM vision model for visual reasoning, documents, and multimodal agents", + "lifecycle": "active", + "contextWindow": 1310720, + "maxOutputTokens": 1048576, + "structuredOutput": true, + "lastUpdated": "2026-08-26", + "capabilities": { + "vision": true, + "reasoning": true, + "functionCalling": true + }, + "modalities": { + "input": ["text", "image"], + "output": ["text"] + } } }, "deepinfra": { @@ -5571,7 +5705,7 @@ "contextWindow": 1048576, "maxOutputTokens": 384000, "structuredOutput": true, - "lastUpdated": "2026-08-12", + "lastUpdated": "2026-08-22", "capabilities": { "vision": false, "reasoning": true, @@ -5624,7 +5758,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -5743,7 +5877,7 @@ "description": "MiniMax multimodal model for long-context coding, perception, and agent planning", "lifecycle": "active", "contextWindow": 524288, - "maxOutputTokens": 128000, + "maxOutputTokens": 512000, "structuredOutput": true, "lastUpdated": "2026-06-01", "capabilities": { @@ -5752,7 +5886,7 @@ "functionCalling": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -5774,7 +5908,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -5796,7 +5930,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -5818,7 +5952,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -5895,7 +6029,7 @@ "functionCalling": true }, "modalities": { - "input": ["text", "image", "audio"], + "input": ["text", "image", "video", "audio"], "output": ["text"] } }, @@ -6086,7 +6220,7 @@ "functionCalling": true }, "modalities": { - "input": ["text", "image", "audio"], + "input": ["text", "image", "video", "audio"], "output": ["text"] } }, @@ -6104,7 +6238,7 @@ "functionCalling": true }, "modalities": { - "input": ["text", "image", "audio"], + "input": ["text", "image", "video", "audio"], "output": ["text"] } }, @@ -6123,7 +6257,7 @@ "functionCalling": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -6142,7 +6276,7 @@ "functionCalling": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -6160,7 +6294,7 @@ "functionCalling": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -6178,7 +6312,7 @@ "functionCalling": true }, "modalities": { - "input": ["text", "image", "audio"], + "input": ["text", "image", "video", "audio"], "output": ["text"] } }, @@ -6196,7 +6330,7 @@ "functionCalling": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -6275,7 +6409,7 @@ "functionCalling": true }, "modalities": { - "input": ["text", "image", "pdf"], + "input": ["text", "image", "video", "pdf"], "output": ["text"] } }, @@ -6293,7 +6427,7 @@ "functionCalling": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -6368,7 +6502,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image", "audio"], + "input": ["text", "image", "audio", "video"], "output": ["text"] } }, @@ -6522,117 +6656,53 @@ "input": ["text"], "output": ["text"] } - } - }, - "deepseek": { - "deepseek-chat": { - "displayName": "DeepSeek Chat", - "description": "DeepSeek chat model for instruction following, coding, and analysis", - "lifecycle": "active", - "contextWindow": 1000000, - "maxOutputTokens": 384000, - "knowledgeCutoff": "2025-09", - "lastUpdated": "2026-02-28", - "capabilities": { - "vision": false, - "reasoning": false, - "functionCalling": true - }, - "modalities": { - "input": ["text"], - "output": ["text"] - } - }, - "deepseek-reasoner": { - "displayName": "DeepSeek Reasoner", - "description": "DeepSeek reasoning model for multi-step analysis, math, coding, and tools", - "lifecycle": "active", - "contextWindow": 1000000, - "maxOutputTokens": 384000, - "knowledgeCutoff": "2025-09", - "lastUpdated": "2026-02-28", - "capabilities": { - "vision": false, - "reasoning": true, - "functionCalling": true - }, - "modalities": { - "input": ["text"], - "output": ["text"] - } }, - "deepseek-v4-flash": { - "displayName": "DeepSeek V4 Flash", - "description": "Official DeepSeek V4 Flash release with enhanced agentic capabilities and integrated DSpark speculative decoding", + "zai-org/GLM-5.3": { + "displayName": "GLM-5.3", + "description": "Flagship GLM model for long-horizon coding, agents, and complex project delivery", "lifecycle": "active", - "contextWindow": 1000000, - "maxOutputTokens": 384000, - "knowledgeCutoff": "2025-05", + "contextWindow": 1048576, + "maxOutputTokens": 131072, "structuredOutput": true, - "lastUpdated": "2026-07-31", + "lastUpdated": "2026-08-14", "capabilities": { "vision": false, "reasoning": true, "functionCalling": true }, "thinkingOptions": { - "efforts": ["low", "high", "max"], - "toggle": true + "efforts": ["low", "high", "max"] }, "modalities": { "input": ["text"], "output": ["text"] } }, - "deepseek-v4-pro": { - "displayName": "DeepSeek V4 Pro", - "description": "DeepSeek V4 Pro snapshot with million-token context and support for thinking and non-thinking modes", + "zai-org/GLM-5.3-Flash": { + "displayName": "GLM-5.3-Flash", + "description": "Native multimodal GLM model for efficient coding and long-horizon agent tasks", "lifecycle": "active", - "contextWindow": 1000000, - "maxOutputTokens": 384000, + "contextWindow": 1048576, + "maxOutputTokens": 131072, "structuredOutput": true, - "lastUpdated": "2026-08-12", + "lastUpdated": "2026-08-26", "capabilities": { - "vision": false, + "vision": true, "reasoning": true, "functionCalling": true }, "thinkingOptions": { - "efforts": ["high", "max"], - "toggle": true + "efforts": ["low", "high", "max"] }, "modalities": { - "input": ["text"], + "input": ["text", "image", "video", "pdf"], "output": ["text"] } } }, - "fireworks-ai": { - "accounts/fireworks/models/deepseek-v4-flash": { + "deepseek": { + "deepseek-v4-flash": { "displayName": "DeepSeek V4 Flash", - "description": "Fast DeepSeek V4 lane for economical reasoning, coding, and long-context work", - "lifecycle": "active", - "contextWindow": 1000000, - "maxOutputTokens": 384000, - "knowledgeCutoff": "2025-05", - "structuredOutput": true, - "lastUpdated": "2026-06-16", - "capabilities": { - "vision": false, - "reasoning": true, - "functionCalling": true - }, - "thinkingOptions": { - "efforts": ["high", "max"], - "toggle": true - }, - "modalities": { - "input": ["text"], - "output": ["text"] - } - }, - "accounts/fireworks/models/deepseek-v4-flash-0731": { - "displayName": "DeepSeek V4 Flash 0731", "description": "Official DeepSeek V4 Flash release with enhanced agentic capabilities and integrated DSpark speculative decoding", "lifecycle": "active", "contextWindow": 1000000, @@ -6654,15 +6724,36 @@ "output": ["text"] } }, - "accounts/fireworks/models/deepseek-v4-pro": { + "deepseek-v4-flash-vision-exp": { + "displayName": "DeepSeek V4 Flash Vision Exp", + "description": "Experimental multimodal DeepSeek V4 Flash model for image understanding, coding, and agentic work", + "lifecycle": "beta", + "contextWindow": 1000000, + "maxOutputTokens": 384000, + "structuredOutput": true, + "lastUpdated": "2026-08-21", + "capabilities": { + "vision": true, + "reasoning": true, + "functionCalling": true + }, + "thinkingOptions": { + "efforts": ["low", "high", "max"], + "toggle": true + }, + "modalities": { + "input": ["text", "image"], + "output": ["text"] + } + }, + "deepseek-v4-pro": { "displayName": "DeepSeek V4 Pro", - "description": "Open MoE flagship with million-token context for coding and long agent runs", + "description": "DeepSeek V4 Pro snapshot with million-token context and support for thinking and non-thinking modes", "lifecycle": "active", "contextWindow": 1000000, "maxOutputTokens": 384000, - "knowledgeCutoff": "2025-05", "structuredOutput": true, - "lastUpdated": "2026-04-24", + "lastUpdated": "2026-08-22", "capabilities": { "vision": false, "reasoning": true, @@ -6676,6 +6767,31 @@ "input": ["text"], "output": ["text"] } + } + }, + "fireworks-ai": { + "accounts/fireworks/models/deepseek-v4-flash-0731": { + "displayName": "DeepSeek V4 Flash 0731", + "description": "Official DeepSeek V4 Flash release with enhanced agentic capabilities and integrated DSpark speculative decoding", + "lifecycle": "active", + "contextWindow": 1000000, + "maxOutputTokens": 384000, + "knowledgeCutoff": "2025-05", + "structuredOutput": true, + "lastUpdated": "2026-07-31", + "capabilities": { + "vision": false, + "reasoning": true, + "functionCalling": true + }, + "thinkingOptions": { + "efforts": ["low", "high", "max"], + "toggle": true + }, + "modalities": { + "input": ["text"], + "output": ["text"] + } }, "accounts/fireworks/models/deepseek-v4-pro-0813": { "displayName": "DeepSeek V4 Pro 0813", @@ -6684,7 +6800,7 @@ "contextWindow": 1000000, "maxOutputTokens": 384000, "structuredOutput": true, - "lastUpdated": "2026-08-12", + "lastUpdated": "2026-08-22", "capabilities": { "vision": false, "reasoning": true, @@ -6720,33 +6836,55 @@ "output": ["text"] } }, - "accounts/fireworks/models/gpt-oss-120b": { - "displayName": "GPT OSS 120B", - "description": "Open-weight GPT model for self-hosted reasoning and instruction-following workloads", + "accounts/fireworks/models/glm-5p3": { + "displayName": "GLM 5.3", + "description": "Flagship GLM model for long-horizon coding, agents, and complex project delivery", "lifecycle": "active", - "contextWindow": 131072, - "maxOutputTokens": 32768, - "lastUpdated": "2026-06-16", + "contextWindow": 1000000, + "maxOutputTokens": 131072, + "structuredOutput": true, + "lastUpdated": "2026-08-28", "capabilities": { "vision": false, "reasoning": true, "functionCalling": true }, "thinkingOptions": { - "efforts": ["low", "medium", "high"] + "efforts": ["high", "max"] }, "modalities": { "input": ["text"], "output": ["text"] } }, - "accounts/fireworks/models/gpt-oss-20b": { - "displayName": "GPT OSS 20B", + "accounts/fireworks/models/glm-5p3-flash": { + "displayName": "GLM 5.3 Flash", + "description": "Native multimodal GLM model for efficient coding and long-horizon agent tasks", + "lifecycle": "active", + "contextWindow": 1000000, + "maxOutputTokens": 131072, + "structuredOutput": true, + "lastUpdated": "2026-08-26", + "capabilities": { + "vision": true, + "reasoning": true, + "functionCalling": true + }, + "thinkingOptions": { + "efforts": ["high", "max"] + }, + "modalities": { + "input": ["text", "image", "video", "pdf"], + "output": ["text"] + } + }, + "accounts/fireworks/models/gpt-oss-120b": { + "displayName": "GPT OSS 120B", "description": "Open-weight GPT model for self-hosted reasoning and instruction-following workloads", "lifecycle": "active", "contextWindow": 131072, "maxOutputTokens": 32768, - "lastUpdated": "2025-08-05", + "lastUpdated": "2026-06-16", "capabilities": { "vision": false, "reasoning": true, @@ -6839,26 +6977,6 @@ "output": ["text"] } }, - "accounts/fireworks/models/minimax-m2p7": { - "displayName": "MiniMax-M2.7", - "description": "MiniMax model for chat, coding, office work, and agentic tasks", - "lifecycle": "active", - "contextWindow": 196608, - "maxOutputTokens": 196608, - "lastUpdated": "2026-04-12", - "capabilities": { - "vision": false, - "reasoning": true, - "functionCalling": true - }, - "thinkingOptions": { - "efforts": ["low", "medium", "high"] - }, - "modalities": { - "input": ["text"], - "output": ["text"] - } - }, "accounts/fireworks/models/minimax-m3": { "displayName": "MiniMax-M3", "description": "MiniMax multimodal coding model for long-context reasoning and agent tasks", @@ -6875,7 +6993,7 @@ "efforts": ["low", "medium", "high"] }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -7004,66 +7122,6 @@ "output": ["text"] } }, - "accounts/fireworks/routers/kimi-k2p6-fast": { - "displayName": "Kimi K2.6 Fast", - "description": "Kimi reasoning model for long-horizon research, planning, and tool use", - "lifecycle": "active", - "contextWindow": 262000, - "maxOutputTokens": 262000, - "lastUpdated": "2026-06-05", - "capabilities": { - "vision": true, - "reasoning": true, - "functionCalling": true - }, - "thinkingOptions": { - "toggle": true - }, - "modalities": { - "input": ["text", "image"], - "output": ["text"] - } - }, - "accounts/fireworks/routers/kimi-k2p6-turbo": { - "displayName": "Kimi K2.6 Turbo", - "description": "Kimi reasoning model for long-horizon research, planning, and tool use", - "lifecycle": "active", - "contextWindow": 262000, - "maxOutputTokens": 262000, - "lastUpdated": "2026-04-17", - "capabilities": { - "vision": true, - "reasoning": true, - "functionCalling": true - }, - "thinkingOptions": { - "toggle": true - }, - "modalities": { - "input": ["text", "image"], - "output": ["text"] - } - }, - "accounts/fireworks/routers/kimi-k2p7-code-fast": { - "displayName": "Kimi K2.7 Code Fast", - "description": "Kimi coding model for software agents, refactors, and repository reasoning", - "lifecycle": "active", - "contextWindow": 262000, - "maxOutputTokens": 262000, - "lastUpdated": "2026-06-16", - "capabilities": { - "vision": true, - "reasoning": true, - "functionCalling": true - }, - "thinkingOptions": { - "toggle": true - }, - "modalities": { - "input": ["text", "image"], - "output": ["text"] - } - }, "accounts/fireworks/routers/kimi-k3-fast": { "displayName": "Kimi K3 Fast", "description": "Multimodal Kimi model with 1M context and toggleable max-effort thinking for long-horizon agent work", @@ -7336,7 +7394,7 @@ "efforts": ["low", "medium", "high"] }, "modalities": { - "input": ["text", "image", "audio", "pdf"], + "input": ["text", "image", "video", "audio", "pdf"], "output": ["text"] } }, @@ -7359,7 +7417,7 @@ "efforts": ["minimal", "low", "medium", "high"] }, "modalities": { - "input": ["text", "image", "audio", "pdf"], + "input": ["text", "image", "video", "audio", "pdf"], "output": ["text"] } }, @@ -7820,7 +7878,7 @@ "functionCalling": true }, "modalities": { - "input": ["text", "image", "audio", "pdf"], + "input": ["text", "image", "video", "audio", "pdf"], "output": ["text", "image"] } }, @@ -7838,7 +7896,7 @@ "functionCalling": true }, "modalities": { - "input": ["text", "image", "audio", "pdf"], + "input": ["text", "image", "video", "audio", "pdf"], "output": ["text", "image"] } }, @@ -7878,7 +7936,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image", "audio", "pdf"], + "input": ["text", "image", "audio", "video", "pdf"], "output": ["text"] } }, @@ -7918,7 +7976,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image", "audio", "pdf"], + "input": ["text", "image", "audio", "video", "pdf"], "output": ["text"] } }, @@ -7955,7 +8013,7 @@ "functionCalling": true }, "modalities": { - "input": ["text", "image", "audio", "pdf"], + "input": ["text", "image", "audio", "video", "pdf"], "output": ["text"] } }, @@ -7995,7 +8053,7 @@ "efforts": ["minimal", "low", "medium", "high"] }, "modalities": { - "input": ["text", "image", "audio", "pdf"], + "input": ["text", "image", "video", "audio", "pdf"], "output": ["text"] } }, @@ -8055,7 +8113,7 @@ "efforts": ["minimal", "high"] }, "modalities": { - "input": ["text", "image", "pdf"], + "input": ["text", "image", "video", "pdf"], "output": ["text", "image"] } }, @@ -8098,7 +8156,7 @@ "efforts": ["minimal", "low", "medium", "high"] }, "modalities": { - "input": ["text", "image", "audio", "pdf"], + "input": ["text", "image", "video", "audio", "pdf"], "output": ["text"] } }, @@ -8142,7 +8200,7 @@ "efforts": ["minimal", "low", "medium", "high"] }, "modalities": { - "input": ["text", "image", "audio", "pdf"], + "input": ["text", "image", "video", "audio", "pdf"], "output": ["text"] } }, @@ -8164,7 +8222,7 @@ "efforts": ["minimal", "low", "medium", "high"] }, "modalities": { - "input": ["text", "image", "audio"], + "input": ["text", "image", "video", "audio"], "output": ["text", "audio"] } }, @@ -8204,7 +8262,7 @@ "efforts": ["low", "medium", "high"] }, "modalities": { - "input": ["text", "image", "audio", "pdf"], + "input": ["text", "image", "video", "audio", "pdf"], "output": ["text"] } }, @@ -8226,7 +8284,7 @@ "efforts": ["low", "medium", "high"] }, "modalities": { - "input": ["text", "image", "audio", "pdf"], + "input": ["text", "image", "video", "audio", "pdf"], "output": ["text"] } }, @@ -8248,7 +8306,7 @@ "efforts": ["minimal", "low", "medium", "high"] }, "modalities": { - "input": ["text", "image", "audio", "pdf"], + "input": ["text", "image", "video", "audio", "pdf"], "output": ["text"] } }, @@ -8270,7 +8328,7 @@ "efforts": ["minimal", "low", "medium", "high"] }, "modalities": { - "input": ["text", "image", "audio", "pdf"], + "input": ["text", "image", "video", "audio", "pdf"], "output": ["text"] } }, @@ -8310,7 +8368,7 @@ "efforts": ["minimal", "low", "medium", "high"] }, "modalities": { - "input": ["text", "image", "audio", "pdf"], + "input": ["text", "image", "video", "audio", "pdf"], "output": ["text"] } }, @@ -8332,7 +8390,7 @@ "efforts": ["low", "medium", "high"] }, "modalities": { - "input": ["text", "image", "audio", "pdf"], + "input": ["text", "image", "video", "audio", "pdf"], "output": ["text"] } }, @@ -8368,7 +8426,7 @@ "functionCalling": false }, "modalities": { - "input": ["text", "image", "audio", "pdf"], + "input": ["text", "image", "audio", "video", "pdf"], "output": ["text"] } }, @@ -8390,7 +8448,7 @@ "efforts": ["low", "medium", "high"] }, "modalities": { - "input": ["text", "image", "audio", "pdf"], + "input": ["text", "image", "video", "audio", "pdf"], "output": ["text"] } }, @@ -8412,7 +8470,7 @@ "efforts": ["minimal", "low", "medium", "high"] }, "modalities": { - "input": ["text", "image", "audio", "pdf"], + "input": ["text", "image", "video", "audio", "pdf"], "output": ["text"] } }, @@ -8429,30 +8487,8 @@ "functionCalling": false }, "modalities": { - "input": ["text", "image"], - "output": [] - } - }, - "gemini-robotics-er-1.6-preview": { - "displayName": "Gemini Robotics-ER 1.6 Preview", - "description": "Vision-language model for embodied reasoning: spatial understanding, task planning, and physical-world agentic robotics", - "lifecycle": "active", - "contextWindow": 131072, - "maxOutputTokens": 65536, - "knowledgeCutoff": "2025-01", - "structuredOutput": true, - "lastUpdated": "2026-04-14", - "capabilities": { - "vision": true, - "reasoning": true, - "functionCalling": true - }, - "thinkingOptions": { - "toggle": true - }, - "modalities": { - "input": ["text", "image", "audio"], - "output": ["text"] + "input": ["text", "image", "video"], + "output": ["video"] } }, "gemma-4-26b-a4b-it": { @@ -8548,8 +8584,8 @@ "functionCalling": false }, "modalities": { - "input": ["text", "image"], - "output": [] + "input": ["text", "image", "video"], + "output": ["video"] } }, "veo-3.1-generate-preview": { @@ -8566,7 +8602,7 @@ }, "modalities": { "input": ["text", "image"], - "output": [] + "output": ["video"] } }, "veo-3.1-lite-generate-preview": { @@ -8583,7 +8619,7 @@ }, "modalities": { "input": ["text", "image"], - "output": [] + "output": ["video"] } } }, @@ -8828,6 +8864,27 @@ "output": ["text"] } }, + "qwen/qwen3.8-27b": { + "displayName": "Qwen3.8 27B", + "description": "Dense 27B vision-language model for coding, agent tasks, and image and video understanding", + "lifecycle": "active", + "contextWindow": 131042, + "maxOutputTokens": 16384, + "structuredOutput": true, + "lastUpdated": "2026-08-14", + "capabilities": { + "vision": true, + "reasoning": true, + "functionCalling": true + }, + "thinkingOptions": { + "efforts": ["none", "default", "low", "medium", "high"] + }, + "modalities": { + "input": ["text", "image"], + "output": ["text"] + } + }, "whisper-large-v3": { "displayName": "Whisper", "description": "Speech transcription model for accurate audio-to-text and captioning workflows", @@ -9043,7 +9100,7 @@ "contextWindow": 1000000, "maxOutputTokens": 384000, "structuredOutput": true, - "lastUpdated": "2026-08-12", + "lastUpdated": "2026-08-22", "capabilities": { "vision": false, "reasoning": true, @@ -9136,7 +9193,7 @@ "description": "Efficient open MiniMax model built for coding agents and tool-heavy workflows", "lifecycle": "active", "contextWindow": 204800, - "maxOutputTokens": 128000, + "maxOutputTokens": 131072, "lastUpdated": "2025-10-27", "capabilities": { "vision": false, @@ -9206,7 +9263,7 @@ "description": "MiniMax multimodal model for long-context coding, perception, and agent planning", "lifecycle": "active", "contextWindow": 524288, - "maxOutputTokens": 128000, + "maxOutputTokens": 512000, "structuredOutput": true, "lastUpdated": "2026-06-01", "capabilities": { @@ -9287,7 +9344,7 @@ "functionCalling": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -9305,7 +9362,7 @@ "functionCalling": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -9819,6 +9876,27 @@ "output": ["text"] } }, + "Qwen/Qwen3.8-27B": { + "displayName": "Qwen3.8 27B", + "description": "Qwen vision-language model for visual reasoning, documents, and agent tasks", + "lifecycle": "active", + "contextWindow": 262144, + "maxOutputTokens": 32768, + "structuredOutput": true, + "lastUpdated": "2026-08-14", + "capabilities": { + "vision": true, + "reasoning": true, + "functionCalling": true + }, + "thinkingOptions": { + "efforts": ["low", "medium", "xhigh"] + }, + "modalities": { + "input": ["text", "image"], + "output": ["text"] + } + }, "stepfun-ai/Step-3.5-Flash": { "displayName": "Step 3.5 Flash", "description": "StepFun flash lane for quick multimodal reasoning and coding assistance", @@ -9854,7 +9932,7 @@ "efforts": ["low", "medium", "high"] }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -10161,6 +10239,48 @@ "input": ["text"], "output": ["text"] } + }, + "zai-org/GLM-5.3": { + "displayName": "GLM-5.3", + "description": "Flagship GLM model for hybrid reasoning, coding, and agentic engineering", + "lifecycle": "active", + "contextWindow": 1048576, + "maxOutputTokens": 131072, + "structuredOutput": true, + "lastUpdated": "2026-08-14", + "capabilities": { + "vision": false, + "reasoning": true, + "functionCalling": true + }, + "thinkingOptions": { + "efforts": ["low", "high", "max"] + }, + "modalities": { + "input": ["text"], + "output": ["text"] + } + }, + "zai-org/GLM-5.3-Flash": { + "displayName": "GLM-5.3-Flash", + "description": "Efficient GLM model for fast reasoning, coding, and agent workflows", + "lifecycle": "active", + "contextWindow": 1048576, + "maxOutputTokens": 131072, + "structuredOutput": true, + "lastUpdated": "2026-08-26", + "capabilities": { + "vision": true, + "reasoning": true, + "functionCalling": true + }, + "thinkingOptions": { + "efforts": ["low", "high", "max"] + }, + "modalities": { + "input": ["text", "image"], + "output": ["text"] + } } }, "kimi-coding-plan": { @@ -10183,7 +10303,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -10225,7 +10345,7 @@ "functionCalling": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -10245,7 +10365,7 @@ "functionCalling": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } } @@ -10255,8 +10375,8 @@ "displayName": "MiniMax-M2", "description": "Efficient open MiniMax model built for coding agents and tool-heavy workflows", "lifecycle": "active", - "contextWindow": 196608, - "maxOutputTokens": 128000, + "contextWindow": 204800, + "maxOutputTokens": 131072, "lastUpdated": "2025-10-27", "capabilities": { "vision": false, @@ -10357,8 +10477,8 @@ "displayName": "MiniMax-M3", "description": "MiniMax multimodal model for long-context coding, perception, and agent planning", "lifecycle": "active", - "contextWindow": 1000000, - "maxOutputTokens": 128000, + "contextWindow": 1048576, + "maxOutputTokens": 512000, "lastUpdated": "2026-06-25", "capabilities": { "vision": true, @@ -10369,7 +10489,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } } @@ -10379,8 +10499,8 @@ "displayName": "MiniMax-M2", "description": "MiniMax model for chat, coding, office work, and agentic tasks", "lifecycle": "active", - "contextWindow": 196608, - "maxOutputTokens": 128000, + "contextWindow": 204800, + "maxOutputTokens": 131072, "lastUpdated": "2025-10-27", "capabilities": { "vision": false, @@ -10481,8 +10601,8 @@ "displayName": "MiniMax-M3", "description": "MiniMax multimodal coding model for long-context reasoning and agent tasks", "lifecycle": "active", - "contextWindow": 1000000, - "maxOutputTokens": 128000, + "contextWindow": 1048576, + "maxOutputTokens": 512000, "lastUpdated": "2026-06-25", "capabilities": { "vision": true, @@ -10493,7 +10613,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } } @@ -10503,8 +10623,8 @@ "displayName": "MiniMax-M2", "description": "MiniMax model for chat, coding, office work, and agentic tasks", "lifecycle": "active", - "contextWindow": 196608, - "maxOutputTokens": 128000, + "contextWindow": 204800, + "maxOutputTokens": 131072, "lastUpdated": "2025-10-27", "isFree": true, "capabilities": { @@ -10611,8 +10731,8 @@ "displayName": "MiniMax-M3", "description": "MiniMax multimodal coding model for long-context reasoning and agent tasks", "lifecycle": "active", - "contextWindow": 1000000, - "maxOutputTokens": 128000, + "contextWindow": 1048576, + "maxOutputTokens": 512000, "lastUpdated": "2026-06-25", "isFree": true, "capabilities": { @@ -10624,7 +10744,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } } @@ -11232,6 +11352,27 @@ "input": ["text", "audio"], "output": ["text"] } + }, + "zai-glm-5-2": { + "displayName": "GLM-5.2", + "description": "Open flagship GLM for long-horizon coding agents and million-token context work", + "lifecycle": "beta", + "contextWindow": 1000000, + "maxOutputTokens": 131072, + "structuredOutput": true, + "lastUpdated": "2026-06-13", + "capabilities": { + "vision": false, + "reasoning": true, + "functionCalling": true + }, + "thinkingOptions": { + "efforts": ["high", "max"] + }, + "modalities": { + "input": ["text"], + "output": ["text"] + } } }, "moonshot": { @@ -11343,7 +11484,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -11365,7 +11506,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -11384,7 +11525,7 @@ "functionCalling": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -11403,7 +11544,7 @@ "functionCalling": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -11425,7 +11566,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } } @@ -11585,6 +11726,29 @@ "output": ["text"] } }, + "deepseek-ai/deepseek-v4-flash-0731": { + "displayName": "DeepSeek V4 Flash 0731", + "description": "Official DeepSeek V4 Flash release with enhanced agentic capabilities and integrated DSpark speculative decoding", + "lifecycle": "active", + "contextWindow": 1000000, + "maxOutputTokens": 384000, + "knowledgeCutoff": "2025-05", + "structuredOutput": true, + "lastUpdated": "2026-07-31", + "isFree": true, + "capabilities": { + "vision": false, + "reasoning": true, + "functionCalling": true + }, + "thinkingOptions": { + "efforts": ["none", "high", "max"] + }, + "modalities": { + "input": ["text"], + "output": ["text"] + } + }, "deepseek-ai/deepseek-v4-pro": { "displayName": "DeepSeek V4 Pro", "description": "Open MoE flagship with million-token context for coding and long agent runs", @@ -11607,6 +11771,28 @@ "output": ["text"] } }, + "deepseek-ai/deepseek-v4-pro-0813": { + "displayName": "DeepSeek V4 Pro 0813", + "description": "DeepSeek V4 Pro snapshot with million-token context and support for thinking and non-thinking modes", + "lifecycle": "active", + "contextWindow": 1000000, + "maxOutputTokens": 384000, + "structuredOutput": true, + "lastUpdated": "2026-08-22", + "isFree": true, + "capabilities": { + "vision": false, + "reasoning": true, + "functionCalling": true + }, + "thinkingOptions": { + "efforts": ["none", "high", "max"] + }, + "modalities": { + "input": ["text"], + "output": ["text"] + } + }, "google/gemma-2-2b-it": { "displayName": "Gemma 2 2b It", "description": "Open Gemma instruction model for efficient chat and self-hosted deployments", @@ -11720,7 +11906,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -12048,7 +12234,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -12285,7 +12471,30 @@ "efforts": ["none", "minimal", "low", "medium", "high", "xhigh", "max"] }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], + "output": ["text"] + } + }, + "moonshotai/kimi-k3": { + "displayName": "Kimi K3", + "description": "Multimodal Kimi model with 1M context and toggleable max-effort thinking for long-horizon agent work", + "lifecycle": "active", + "contextWindow": 1048576, + "maxOutputTokens": 131072, + "structuredOutput": true, + "lastUpdated": "2026-07-16", + "isFree": true, + "capabilities": { + "vision": true, + "reasoning": true, + "functionCalling": true + }, + "thinkingOptions": { + "efforts": ["low", "high", "max"], + "toggle": true + }, + "modalities": { + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -12303,7 +12512,7 @@ "functionCalling": false }, "modalities": { - "input": [], + "input": ["video"], "output": ["text"] } }, @@ -12321,7 +12530,7 @@ "functionCalling": false }, "modalities": { - "input": [], + "input": ["video"], "output": ["text"] } }, @@ -12339,8 +12548,8 @@ "functionCalling": false }, "modalities": { - "input": ["text", "image"], - "output": [] + "input": ["text", "image", "video"], + "output": ["video"] } }, "nvidia/cosmos-reason2-8b": { @@ -12357,7 +12566,7 @@ "functionCalling": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -12375,8 +12584,8 @@ "functionCalling": false }, "modalities": { - "input": ["text", "image"], - "output": [] + "input": ["text", "image", "video"], + "output": ["video"] } }, "nvidia/cosmos-transfer2_5-2b": { @@ -12393,8 +12602,8 @@ "functionCalling": false }, "modalities": { - "input": ["text", "image"], - "output": [] + "input": ["text", "image", "video"], + "output": ["video"] } }, "nvidia/gliner-pii": { @@ -12683,7 +12892,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image", "audio"], + "input": ["text", "image", "video", "audio"], "output": ["text"] } }, @@ -12801,7 +13010,7 @@ "functionCalling": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -12931,7 +13140,7 @@ "functionCalling": false }, "modalities": { - "input": [], + "input": ["video"], "output": ["text"] } }, @@ -12949,7 +13158,7 @@ "functionCalling": false }, "modalities": { - "input": [], + "input": ["video"], "output": ["text"] } }, @@ -12985,7 +13194,7 @@ "functionCalling": false }, "modalities": { - "input": [], + "input": ["video"], "output": ["text"] } }, @@ -13221,7 +13430,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image", "audio"], + "input": ["text", "image", "video", "audio"], "output": ["text"] } }, @@ -13495,6 +13704,48 @@ "output": ["text"] } }, + "glm-5.3": { + "displayName": "GLM-5.3", + "description": "Flagship GLM model for long-horizon coding, agents, and complex project delivery", + "lifecycle": "active", + "contextWindow": 1048576, + "maxOutputTokens": 131072, + "structuredOutput": true, + "lastUpdated": "2026-08-14", + "capabilities": { + "vision": false, + "reasoning": true, + "functionCalling": true + }, + "thinkingOptions": { + "efforts": ["low", "high", "max"] + }, + "modalities": { + "input": ["text"], + "output": ["text"] + } + }, + "glm-5.3-flash": { + "displayName": "GLM-5.3-Flash", + "description": "Native multimodal GLM model for efficient coding and long-horizon agent tasks", + "lifecycle": "active", + "contextWindow": 1000000, + "maxOutputTokens": 131072, + "structuredOutput": true, + "lastUpdated": "2026-08-26", + "capabilities": { + "vision": true, + "reasoning": true, + "functionCalling": true + }, + "thinkingOptions": { + "efforts": ["low", "high", "max"] + }, + "modalities": { + "input": ["text", "image", "video", "pdf"], + "output": ["text"] + } + }, "gpt-oss:120b": { "displayName": "gpt-oss:120b", "description": "Open-weight GPT model for self-hosted reasoning and instruction-following workloads", @@ -13675,7 +13926,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -15132,7 +15383,7 @@ "efforts": ["minimal", "low", "medium", "high"] }, "modalities": { - "input": ["text", "image", "audio", "pdf"], + "input": ["text", "image", "video", "audio", "pdf"], "output": ["text"] } }, @@ -15154,7 +15405,7 @@ "efforts": ["low", "high"] }, "modalities": { - "input": ["text", "image", "audio", "pdf"], + "input": ["text", "image", "video", "audio", "pdf"], "output": ["text"] } }, @@ -15176,7 +15427,7 @@ "efforts": ["low", "medium", "high"] }, "modalities": { - "input": ["text", "image", "audio", "pdf"], + "input": ["text", "image", "video", "audio", "pdf"], "output": ["text"] } }, @@ -15198,7 +15449,7 @@ "efforts": ["minimal", "low", "medium", "high"] }, "modalities": { - "input": ["text", "image", "audio", "pdf"], + "input": ["text", "image", "video", "audio", "pdf"], "output": ["text"] } }, @@ -15220,7 +15471,7 @@ "efforts": ["minimal", "low", "medium", "high"] }, "modalities": { - "input": ["text", "image", "audio", "pdf"], + "input": ["text", "image", "video", "audio", "pdf"], "output": ["text"] } }, @@ -15242,7 +15493,7 @@ "efforts": ["minimal", "low", "medium", "high"] }, "modalities": { - "input": ["text", "image", "audio", "pdf"], + "input": ["text", "image", "video", "audio", "pdf"], "output": ["text"] } }, @@ -15264,7 +15515,7 @@ "efforts": ["low", "medium", "high"] }, "modalities": { - "input": ["text", "image", "audio", "pdf"], + "input": ["text", "image", "video", "audio", "pdf"], "output": ["text"] } }, @@ -15959,7 +16210,7 @@ "hy3-free": { "displayName": "Hy3 Free", "description": "Tencent Hy reasoning model for coding, instruction following, and agent tasks", - "lifecycle": "active", + "lifecycle": "deprecated", "contextWindow": 190000, "maxOutputTokens": 64000, "structuredOutput": true, @@ -16051,7 +16302,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -16073,7 +16324,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -16094,7 +16345,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -16113,7 +16364,7 @@ "functionCalling": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -16134,7 +16385,7 @@ "efforts": ["max"] }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -16179,6 +16430,28 @@ "output": ["text"] } }, + "ling-3.0-flash-fin-free": { + "displayName": "Ling 3.0 Flash Fin Free", + "description": "Finance-enhanced model for financial research, multi-step investment workflows, and long-horizon planning and execution", + "lifecycle": "active", + "contextWindow": 262144, + "maxOutputTokens": 32768, + "structuredOutput": false, + "lastUpdated": "2026-08-27", + "isFree": true, + "capabilities": { + "vision": false, + "reasoning": true, + "functionCalling": true + }, + "thinkingOptions": { + "toggle": true + }, + "modalities": { + "input": ["text"], + "output": ["text"] + } + }, "ling-3.0-flash-free": { "displayName": "Ling-3.0-flash Free", "description": "Efficient model for low-latency assistance, extraction, and routine automation", @@ -16313,7 +16586,7 @@ "functionCalling": true }, "modalities": { - "input": ["text", "image", "audio"], + "input": ["text", "image", "audio", "video"], "output": ["text"] } }, @@ -16422,7 +16695,7 @@ "functionCalling": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -16444,7 +16717,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -16465,7 +16738,7 @@ "efforts": ["minimal", "low", "medium", "high", "xhigh"] }, "modalities": { - "input": ["text", "image", "pdf", "audio"], + "input": ["text", "image", "video", "pdf", "audio"], "output": ["text"] } }, @@ -16487,7 +16760,7 @@ "efforts": ["minimal", "low", "medium", "high", "xhigh"] }, "modalities": { - "input": ["text", "image", "pdf", "audio"], + "input": ["text", "image", "video", "pdf", "audio"], "output": ["text"] } }, @@ -16606,7 +16879,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -16627,7 +16900,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -16649,7 +16922,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -16694,7 +16967,7 @@ "x-preview-f-free": { "displayName": "Ox Alpha Free (Unlimited)", "description": "Stealth reasoning model for coding, agentic tasks, and tool use", - "lifecycle": "active", + "lifecycle": "deprecated", "contextWindow": 1000000, "maxOutputTokens": 131072, "structuredOutput": true, @@ -16709,7 +16982,7 @@ "efforts": ["low", "high", "max"] }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } } @@ -16737,6 +17010,28 @@ "output": ["text"] } }, + "deepseek-v4-flash-vision-exp": { + "displayName": "DeepSeek V4 Flash Vision Exp", + "description": "Experimental multimodal DeepSeek V4 Flash model for image understanding, coding, and agentic work", + "lifecycle": "active", + "contextWindow": 1000000, + "maxOutputTokens": 384000, + "structuredOutput": true, + "lastUpdated": "2026-08-21", + "capabilities": { + "vision": true, + "reasoning": true, + "functionCalling": true + }, + "thinkingOptions": { + "efforts": ["low", "high", "max"], + "toggle": true + }, + "modalities": { + "input": ["text", "image"], + "output": ["text"] + } + }, "deepseek-v4-pro": { "displayName": "DeepSeek V4 Pro (New)", "description": "Flagship DeepSeek model for coding, reasoning, and agentic work", @@ -16837,6 +17132,27 @@ "output": ["text"] } }, + "glm-5.3-flash": { + "displayName": "GLM-5.3-Flash (2x usage)", + "description": "Native multimodal GLM model for efficient coding and long-horizon agent tasks", + "lifecycle": "active", + "contextWindow": 1000000, + "maxOutputTokens": 131072, + "structuredOutput": true, + "lastUpdated": "2026-08-26", + "capabilities": { + "vision": true, + "reasoning": true, + "functionCalling": true + }, + "thinkingOptions": { + "efforts": ["low", "high", "max"] + }, + "modalities": { + "input": ["text", "image", "video", "pdf"], + "output": ["text"] + } + }, "gpt-5.6-luna": { "displayName": "GPT-5.6 Luna", "description": "Cost-efficient GPT-5.6 model for fast, high-volume workloads", @@ -16863,7 +17179,7 @@ "grok-4.5": { "displayName": "Grok 4.5", "description": "xAI's Grok model for chat, coding, agentic tools, and lower hallucination risk", - "lifecycle": "active", + "lifecycle": "deprecated", "contextWindow": 500000, "maxOutputTokens": 500000, "structuredOutput": true, @@ -16881,8 +17197,30 @@ "output": ["text"] } }, + "grok-4.6": { + "displayName": "Grok 4.6", + "description": "xAI's frontier model for long-running agents, coding, knowledge work, and visual projects", + "lifecycle": "active", + "contextWindow": 500000, + "maxOutputTokens": 500000, + "knowledgeCutoff": "2026-02-01", + "structuredOutput": true, + "lastUpdated": "2026-08-12", + "capabilities": { + "vision": true, + "reasoning": true, + "functionCalling": true + }, + "thinkingOptions": { + "efforts": ["low", "medium", "high", "xhigh"] + }, + "modalities": { + "input": ["text", "image"], + "output": ["text"] + } + }, "hy3": { - "displayName": "Hy3 (8x usage)", + "displayName": "Hy3", "description": "Tencent Hy reasoning model for coding, instruction following, and agent tasks", "lifecycle": "active", "contextWindow": 256000, @@ -16901,6 +17239,26 @@ "output": ["text"] } }, + "hy4-preview": { + "displayName": "Hy4 preview", + "description": "A next-generation productivity model with significantly enhanced Agent and complex task execution capabilities.", + "lifecycle": "active", + "contextWindow": 1024000, + "maxOutputTokens": 64000, + "lastUpdated": "2026-08-28", + "capabilities": { + "vision": false, + "reasoning": true, + "functionCalling": true + }, + "thinkingOptions": { + "efforts": ["none", "high"] + }, + "modalities": { + "input": ["text"], + "output": ["text"] + } + }, "kimi-k2.5": { "displayName": "Kimi K2.5", "description": "Legacy model retained for compatibility with older integrations", @@ -16915,7 +17273,7 @@ "functionCalling": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -16933,7 +17291,7 @@ "functionCalling": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -16952,7 +17310,7 @@ "functionCalling": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -16973,7 +17331,27 @@ "efforts": ["max"] }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], + "output": ["text"] + } + }, + "longcat-2.0": { + "displayName": "LongCat-2.0", + "description": "Meituan LongCat-2.0, a reasoning model with tool calling and a 1M-token context window", + "lifecycle": "active", + "contextWindow": 1000000, + "maxOutputTokens": 131072, + "lastUpdated": "2026-06-30", + "capabilities": { + "vision": false, + "reasoning": true, + "functionCalling": true + }, + "thinkingOptions": { + "toggle": true + }, + "modalities": { + "input": ["text"], "output": ["text"] } }, @@ -17027,7 +17405,7 @@ "functionCalling": true }, "modalities": { - "input": ["text", "image", "audio"], + "input": ["text", "image", "audio", "video"], "output": ["text"] } }, @@ -17102,7 +17480,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -17123,14 +17501,14 @@ "efforts": ["minimal", "low", "medium", "high", "xhigh"] }, "modalities": { - "input": ["text", "image", "pdf", "audio"], + "input": ["text", "image", "video", "pdf", "audio"], "output": ["text"] } }, "ox-alpha-free": { "displayName": "Ox Alpha Free (Unlimited)", "description": "Stealth reasoning model for coding, agentic tasks, and tool use", - "lifecycle": "active", + "lifecycle": "deprecated", "contextWindow": 1000000, "maxOutputTokens": 131072, "structuredOutput": true, @@ -17145,7 +17523,7 @@ "efforts": ["low", "high", "max"] }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -17166,7 +17544,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -17187,7 +17565,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -17227,7 +17605,29 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], + "output": ["text"] + } + }, + "qwen3.8-flash": { + "displayName": "Qwen3.8 Flash", + "description": "Qwen vision-language model for visual reasoning, documents, and agent tasks", + "lifecycle": "active", + "contextWindow": 1000000, + "maxOutputTokens": 131072, + "structuredOutput": true, + "lastUpdated": "2026-08-26", + "capabilities": { + "vision": true, + "reasoning": true, + "functionCalling": true + }, + "thinkingOptions": { + "efforts": ["low", "medium", "xhigh"], + "toggle": true + }, + "modalities": { + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -17245,10 +17645,11 @@ "functionCalling": true }, "thinkingOptions": { + "efforts": ["low", "medium", "xhigh"], "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } } @@ -17346,7 +17747,7 @@ "description": "Fast DeepSeek model for efficient chat, coding help, and agent loops", "lifecycle": "active", "contextWindow": 1310720, - "maxOutputTokens": 1048576, + "maxOutputTokens": 393216, "structuredOutput": true, "lastUpdated": "2026-08-01", "capabilities": { @@ -17381,7 +17782,7 @@ "efforts": ["low", "medium", "high"] }, "modalities": { - "input": ["text", "image", "pdf", "audio"], + "input": ["text", "image", "video", "pdf", "audio"], "output": ["text"] } }, @@ -17403,7 +17804,7 @@ "efforts": ["low", "medium", "high"] }, "modalities": { - "input": ["audio", "pdf", "image", "text"], + "input": ["audio", "pdf", "image", "text", "video"], "output": ["text"] } }, @@ -17412,7 +17813,7 @@ "description": "Kimi multimodal agent model for visual understanding, coding, and planning", "lifecycle": "active", "contextWindow": 1048576, - "maxOutputTokens": 974842, + "maxOutputTokens": 943718, "structuredOutput": true, "lastUpdated": "2026-04-27", "capabilities": { @@ -17425,7 +17826,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -17478,7 +17879,7 @@ "description": "Grok model for agentic tool use, reasoning, coding, and live assistance", "lifecycle": "active", "contextWindow": 500000, - "maxOutputTokens": 1000000, + "maxOutputTokens": 450000, "structuredOutput": true, "lastUpdated": "2026-07-08", "capabilities": { @@ -17498,9 +17899,9 @@ "displayName": "GLM Latest", "description": "Flagship GLM model for hybrid reasoning, coding, and agentic engineering", "lifecycle": "active", - "contextWindow": 1048576, - "maxOutputTokens": 131072, - "structuredOutput": false, + "contextWindow": 1310720, + "maxOutputTokens": 943718, + "structuredOutput": true, "lastUpdated": "2026-08-19", "capabilities": { "vision": false, @@ -17574,7 +17975,7 @@ "description": "Open Llama instruction model for multilingual chat, reasoning, and coding", "lifecycle": "active", "contextWindow": 32768, - "maxOutputTokens": 32768, + "maxOutputTokens": 29491, "knowledgeCutoff": "2023-12-31", "structuredOutput": false, "lastUpdated": "2025-02-04", @@ -17588,24 +17989,6 @@ "output": ["text"] } }, - "allenai/olmo-3-32b-think": { - "displayName": "Olmo 3 32B Think", - "description": "Reasoning model for deliberate analysis, multi-step problem solving, and tool use", - "lifecycle": "active", - "contextWindow": 65536, - "maxOutputTokens": 65536, - "structuredOutput": true, - "lastUpdated": "2025-11-21", - "capabilities": { - "vision": false, - "reasoning": true, - "functionCalling": false - }, - "modalities": { - "input": ["text"], - "output": ["text"] - } - }, "amazon/nova-2-lite-v1": { "displayName": "Nova 2 Lite", "description": "Multimodal reasoning model for visual analysis, planning, and tool use", @@ -17619,8 +18002,11 @@ "reasoning": true, "functionCalling": true }, + "thinkingOptions": { + "toggle": true + }, "modalities": { - "input": ["text", "image", "pdf"], + "input": ["text", "image", "video", "pdf"], "output": ["text"] } }, @@ -17840,7 +18226,6 @@ "functionCalling": true }, "thinkingOptions": { - "efforts": ["low", "medium", "high"], "toggle": true }, "modalities": { @@ -18104,8 +18489,8 @@ "description": "Reasoning-optimized 398B MoE agent model with extended thinking for long-horizon and multi-turn tool use", "lifecycle": "active", "contextWindow": 262144, - "maxOutputTokens": 262144, - "structuredOutput": true, + "maxOutputTokens": 80000, + "structuredOutput": false, "lastUpdated": "2026-05-28", "capabilities": { "vision": false, @@ -18117,25 +18502,6 @@ "output": ["text"] } }, - "arcee-ai/virtuoso-large": { - "displayName": "Virtuoso Large", - "description": "Flagship model for demanding analysis, coding, and production agent workflows", - "lifecycle": "active", - "contextWindow": 131072, - "maxOutputTokens": 64000, - "knowledgeCutoff": "2025-03-31", - "structuredOutput": false, - "lastUpdated": "2025-05-05", - "capabilities": { - "vision": false, - "reasoning": false, - "functionCalling": true - }, - "modalities": { - "input": ["text"], - "output": ["text"] - } - }, "baidu/ernie-4.5-vl-424b-a47b": { "displayName": "ERNIE 4.5 VL 424B A47B ", "description": "Multimodal reasoning model for visual analysis, planning, and tool use", @@ -18150,6 +18516,9 @@ "reasoning": true, "functionCalling": false }, + "thinkingOptions": { + "toggle": true + }, "modalities": { "input": ["image", "text"], "output": ["text"] @@ -18168,8 +18537,11 @@ "reasoning": true, "functionCalling": true }, + "thinkingOptions": { + "toggle": true + }, "modalities": { - "input": ["image", "text"], + "input": ["image", "text", "video"], "output": ["text"] } }, @@ -18186,8 +18558,11 @@ "reasoning": true, "functionCalling": true }, + "thinkingOptions": { + "toggle": true + }, "modalities": { - "input": ["image", "text"], + "input": ["image", "text", "video"], "output": ["text"] } }, @@ -18196,7 +18571,7 @@ "description": "Multimodal reasoning model for visual analysis, planning, and tool use", "lifecycle": "active", "contextWindow": 262144, - "maxOutputTokens": 262144, + "maxOutputTokens": 235929, "structuredOutput": true, "lastUpdated": "2026-08-12", "capabilities": { @@ -18204,8 +18579,11 @@ "reasoning": true, "functionCalling": true }, + "thinkingOptions": { + "toggle": true + }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -18227,7 +18605,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -18249,7 +18627,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -18271,7 +18649,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -18403,23 +18781,8 @@ "reasoning": true, "functionCalling": true }, - "modalities": { - "input": ["text"], - "output": ["text"] - } - }, - "deepcogito/cogito-v2.1-671b": { - "displayName": "Cogito v2.1 671B", - "description": "Reasoning model for deliberate analysis, multi-step problem solving, and tool use", - "lifecycle": "active", - "contextWindow": 128000, - "maxOutputTokens": 128000, - "structuredOutput": true, - "lastUpdated": "2025-11-13", - "capabilities": { - "vision": false, - "reasoning": true, - "functionCalling": false + "thinkingOptions": { + "toggle": true }, "modalities": { "input": ["text"], @@ -18450,7 +18813,7 @@ "description": "DeepSeek chat model for instruction following, coding, and analysis", "lifecycle": "active", "contextWindow": 163840, - "maxOutputTokens": 163840, + "maxOutputTokens": 147456, "knowledgeCutoff": "2024-07-31", "structuredOutput": true, "lastUpdated": "2025-03-24", @@ -18469,7 +18832,7 @@ "description": "DeepSeek chat model for instruction following, coding, and analysis", "lifecycle": "active", "contextWindow": 163840, - "maxOutputTokens": 32768, + "maxOutputTokens": 144900, "knowledgeCutoff": "2025-03-31", "structuredOutput": true, "lastUpdated": "2025-08-21", @@ -18529,7 +18892,7 @@ "description": "DeepSeek reasoning model for multi-step analysis, math, coding, and tools", "lifecycle": "active", "contextWindow": 8192, - "maxOutputTokens": 8192, + "maxOutputTokens": 7372, "knowledgeCutoff": "2024-07-31", "structuredOutput": false, "lastUpdated": "2025-01-23", @@ -18538,6 +18901,9 @@ "reasoning": true, "functionCalling": false }, + "thinkingOptions": { + "toggle": true + }, "modalities": { "input": ["text"], "output": ["text"] @@ -18637,7 +19003,7 @@ "description": "Official DeepSeek V4 Flash release with enhanced agentic capabilities and integrated DSpark speculative decoding", "lifecycle": "active", "contextWindow": 1310720, - "maxOutputTokens": 384000, + "maxOutputTokens": 943718, "knowledgeCutoff": "2025-05", "structuredOutput": true, "lastUpdated": "2026-07-31", @@ -18707,7 +19073,7 @@ "contextWindow": 1048576, "maxOutputTokens": 384000, "structuredOutput": true, - "lastUpdated": "2026-08-12", + "lastUpdated": "2026-08-22", "capabilities": { "vision": false, "reasoning": true, @@ -18727,7 +19093,7 @@ "description": "Multimodal reasoning model for visual analysis, planning, and tool use", "lifecycle": "active", "contextWindow": 512000, - "maxOutputTokens": 512000, + "maxOutputTokens": 460800, "structuredOutput": true, "lastUpdated": "2026-08-14", "isFree": true, @@ -18736,6 +19102,9 @@ "reasoning": true, "functionCalling": true }, + "thinkingOptions": { + "toggle": true + }, "modalities": { "input": ["text", "image"], "output": ["text"] @@ -18759,7 +19128,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image", "audio", "pdf"], + "input": ["text", "image", "audio", "video", "pdf"], "output": ["text"] } }, @@ -18800,7 +19169,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image", "audio", "pdf"], + "input": ["text", "image", "audio", "video", "pdf"], "output": ["text"] } }, @@ -18819,7 +19188,7 @@ "functionCalling": true }, "modalities": { - "input": ["text", "image", "audio", "pdf"], + "input": ["text", "image", "audio", "video", "pdf"], "output": ["text"] } }, @@ -18857,7 +19226,7 @@ "functionCalling": true }, "modalities": { - "input": ["text", "image", "pdf", "audio"], + "input": ["text", "image", "pdf", "audio", "video"], "output": ["text"] } }, @@ -18880,7 +19249,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image", "audio", "pdf"], + "input": ["text", "image", "video", "audio", "pdf"], "output": ["text"] } }, @@ -18950,7 +19319,7 @@ "description": "Image model for prompt-driven generation, editing, and visual design workflows", "lifecycle": "active", "contextWindow": 65536, - "maxOutputTokens": 65536, + "maxOutputTokens": 58982, "knowledgeCutoff": "2025-01", "structuredOutput": true, "lastUpdated": "2026-02-26", @@ -18987,7 +19356,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image", "audio", "pdf"], + "input": ["text", "image", "video", "audio", "pdf"], "output": ["text"] } }, @@ -18996,7 +19365,7 @@ "description": "Image model for prompt-driven generation, editing, and visual design workflows", "lifecycle": "active", "contextWindow": 65536, - "maxOutputTokens": 65536, + "maxOutputTokens": 58982, "knowledgeCutoff": "2025-01", "structuredOutput": false, "lastUpdated": "2026-06-30", @@ -19033,7 +19402,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image", "audio", "pdf"], + "input": ["text", "image", "video", "audio", "pdf"], "output": ["text"] } }, @@ -19055,7 +19424,7 @@ "efforts": ["low", "medium", "high"] }, "modalities": { - "input": ["text", "image", "audio", "pdf"], + "input": ["text", "image", "video", "audio", "pdf"], "output": ["text"] } }, @@ -19077,7 +19446,7 @@ "efforts": ["low", "medium", "high"] }, "modalities": { - "input": ["text", "image", "audio", "pdf"], + "input": ["text", "image", "video", "audio", "pdf"], "output": ["text"] } }, @@ -19099,7 +19468,7 @@ "efforts": ["minimal", "low", "medium", "high"] }, "modalities": { - "input": ["text", "image", "audio", "pdf"], + "input": ["text", "image", "video", "audio", "pdf"], "output": ["text"] } }, @@ -19121,7 +19490,7 @@ "efforts": ["minimal", "low", "medium", "high"] }, "modalities": { - "input": ["text", "image", "audio", "pdf"], + "input": ["text", "image", "video", "audio", "pdf"], "output": ["text"] } }, @@ -19143,7 +19512,7 @@ "efforts": ["minimal", "low", "medium", "high"] }, "modalities": { - "input": ["text", "image", "audio", "pdf"], + "input": ["text", "image", "video", "audio", "pdf"], "output": ["text"] } }, @@ -19165,7 +19534,7 @@ "efforts": ["low", "medium", "high"] }, "modalities": { - "input": ["text", "image", "audio", "pdf"], + "input": ["text", "image", "video", "audio", "pdf"], "output": ["text"] } }, @@ -19211,8 +19580,8 @@ "displayName": "Gemma 3 27B", "description": "Open Gemma instruction model for efficient chat and self-hosted deployments", "lifecycle": "active", - "contextWindow": 262144, - "maxOutputTokens": 131072, + "contextWindow": 131072, + "maxOutputTokens": 117964, "knowledgeCutoff": "2024-08-31", "structuredOutput": true, "lastUpdated": "2025-03-12", @@ -19245,25 +19614,6 @@ "output": ["text"] } }, - "google/gemma-3n-e4b-it": { - "displayName": "Gemma 3n 4B", - "description": "Open Gemma instruction model for efficient chat and self-hosted deployments", - "lifecycle": "active", - "contextWindow": 32768, - "maxOutputTokens": 32768, - "knowledgeCutoff": "2024-08-31", - "structuredOutput": true, - "lastUpdated": "2025-05-20", - "capabilities": { - "vision": false, - "reasoning": false, - "functionCalling": false - }, - "modalities": { - "input": ["text"], - "output": ["text"] - } - }, "google/gemma-4-26b-a4b-it": { "displayName": "Gemma 4 26B A4B IT", "description": "Open Gemma instruction model for efficient chat and self-hosted deployments", @@ -19281,7 +19631,7 @@ "toggle": true }, "modalities": { - "input": ["image", "text"], + "input": ["image", "text", "video"], "output": ["text"] } }, @@ -19303,7 +19653,7 @@ "toggle": true }, "modalities": { - "input": ["image", "text"], + "input": ["image", "text", "video"], "output": ["text"] } }, @@ -19312,7 +19662,7 @@ "description": "Largest Gemma 4 instruction model for open, self-hosted chat and reasoning", "lifecycle": "active", "contextWindow": 262144, - "maxOutputTokens": 262144, + "maxOutputTokens": 16384, "structuredOutput": true, "lastUpdated": "2026-04-02", "capabilities": { @@ -19324,7 +19674,7 @@ "toggle": true }, "modalities": { - "input": ["image", "text"], + "input": ["image", "text", "video"], "output": ["text"] } }, @@ -19346,7 +19696,7 @@ "toggle": true }, "modalities": { - "input": ["image", "text"], + "input": ["image", "text", "video"], "output": ["text"] } }, @@ -19393,7 +19743,7 @@ "description": "Open-weight instruction model for adaptable chat and self-hosted production workloads", "lifecycle": "active", "contextWindow": 8192, - "maxOutputTokens": 4096, + "maxOutputTokens": 3686, "knowledgeCutoff": "2023-06-30", "structuredOutput": true, "lastUpdated": "2023-07-02", @@ -19412,7 +19762,7 @@ "description": "Efficient model for low-latency assistance, extraction, and routine automation", "lifecycle": "active", "contextWindow": 131000, - "maxOutputTokens": 131000, + "maxOutputTokens": 117900, "structuredOutput": false, "lastUpdated": "2025-10-20", "capabilities": { @@ -19430,7 +19780,7 @@ "description": "Open-weight instruction model for adaptable chat and self-hosted production workloads", "lifecycle": "active", "contextWindow": 131072, - "maxOutputTokens": 131072, + "maxOutputTokens": 117964, "structuredOutput": true, "lastUpdated": "2026-04-30", "capabilities": { @@ -19443,57 +19793,42 @@ "output": ["text"] } }, - "inception/mercury-2": { - "displayName": "Mercury 2", + "ibm-granite/granite-4.2-8b": { + "displayName": "Granite 4.2 8B", "description": "Reasoning model for deliberate analysis, multi-step problem solving, and tool use", "lifecycle": "active", - "contextWindow": 128000, - "maxOutputTokens": 50000, + "contextWindow": 131072, + "maxOutputTokens": 117964, "structuredOutput": true, - "lastUpdated": "2026-03-04", + "lastUpdated": "2026-08-31", "capabilities": { "vision": false, "reasoning": true, "functionCalling": true }, "thinkingOptions": { - "efforts": ["none", "low", "medium", "high"] + "efforts": ["none", "low", "high"] }, "modalities": { "input": ["text"], "output": ["text"] } }, - "inclusionai/ling-2.6-1t": { - "displayName": "Ling-2.6-1T", - "description": "Tool-capable chat model for instruction following and agentic application workflows", + "inception/mercury-2": { + "displayName": "Mercury 2", + "description": "Reasoning model for deliberate analysis, multi-step problem solving, and tool use", "lifecycle": "active", - "contextWindow": 262144, - "maxOutputTokens": 32768, + "contextWindow": 128000, + "maxOutputTokens": 50000, "structuredOutput": true, - "lastUpdated": "2026-04-23", + "lastUpdated": "2026-03-04", "capabilities": { "vision": false, - "reasoning": false, + "reasoning": true, "functionCalling": true }, - "modalities": { - "input": ["text"], - "output": ["text"] - } - }, - "inclusionai/ling-2.6-flash": { - "displayName": "Ling-2.6-flash", - "description": "Efficient model for low-latency assistance, extraction, and routine automation", - "lifecycle": "active", - "contextWindow": 262144, - "maxOutputTokens": 32768, - "structuredOutput": true, - "lastUpdated": "2026-04-21", - "capabilities": { - "vision": false, - "reasoning": false, - "functionCalling": true + "thinkingOptions": { + "efforts": ["none", "low", "medium", "high"] }, "modalities": { "input": ["text"], @@ -19513,44 +19848,30 @@ "reasoning": true, "functionCalling": true }, + "thinkingOptions": { + "toggle": true + }, "modalities": { "input": ["text"], "output": ["text"] } }, - "inclusionai/ring-2.6-1t": { - "displayName": "Ring-2.6-1T", - "description": "Reasoning model for deliberate analysis, multi-step problem solving, and tool use", + "inclusionai/ling-3.0-flash-fin:free": { + "displayName": "Ling 3.0 Flash Fin (free)", + "description": "Efficient model for low-latency assistance, extraction, and routine automation", "lifecycle": "active", "contextWindow": 262144, - "maxOutputTokens": 65536, + "maxOutputTokens": 32768, "structuredOutput": false, - "lastUpdated": "2026-05-08", + "lastUpdated": "2026-08-27", + "isFree": true, "capabilities": { "vision": false, "reasoning": true, "functionCalling": true }, "thinkingOptions": { - "efforts": ["high", "xhigh"] - }, - "modalities": { - "input": ["text"], - "output": ["text"] - } - }, - "kwaipilot/kat-coder-air-v2.5": { - "displayName": "KAT-Coder-Air V2.5", - "description": "Coding model for repository understanding, refactors, and agentic engineering tasks", - "lifecycle": "active", - "contextWindow": 256000, - "maxOutputTokens": 80000, - "structuredOutput": true, - "lastUpdated": "2026-07-10", - "capabilities": { - "vision": false, - "reasoning": false, - "functionCalling": true + "toggle": true }, "modalities": { "input": ["text"], @@ -19562,7 +19883,7 @@ "description": "Coding model for repository understanding, refactors, and agentic engineering tasks", "lifecycle": "active", "contextWindow": 262144, - "maxOutputTokens": 80000, + "maxOutputTokens": 144000, "structuredOutput": true, "lastUpdated": "2026-03-27", "capabilities": { @@ -19579,8 +19900,8 @@ "displayName": "KAT-Coder-Pro V2.5", "description": "Coding model for repository understanding, refactors, and agentic engineering tasks", "lifecycle": "active", - "contextWindow": 256000, - "maxOutputTokens": 80000, + "contextWindow": 262144, + "maxOutputTokens": 235929, "structuredOutput": true, "lastUpdated": "2026-07-10", "capabilities": { @@ -19644,6 +19965,9 @@ "reasoning": true, "functionCalling": true }, + "thinkingOptions": { + "toggle": true + }, "modalities": { "input": ["text"], "output": ["text"] @@ -19673,7 +19997,7 @@ "description": "Open Llama instruction model for multilingual chat, reasoning, and coding", "lifecycle": "active", "contextWindow": 131072, - "maxOutputTokens": 131072, + "maxOutputTokens": 117964, "knowledgeCutoff": "2023-12", "structuredOutput": true, "lastUpdated": "2024-07-23", @@ -19692,7 +20016,7 @@ "description": "Open Llama instruction model for multilingual chat, reasoning, and coding", "lifecycle": "active", "contextWindow": 60000, - "maxOutputTokens": 60000, + "maxOutputTokens": 54000, "knowledgeCutoff": "2023-12-31", "structuredOutput": false, "lastUpdated": "2024-09-25", @@ -19711,7 +20035,7 @@ "description": "Open Llama instruction model for multilingual chat, reasoning, and coding", "lifecycle": "active", "contextWindow": 131072, - "maxOutputTokens": 131072, + "maxOutputTokens": 117964, "knowledgeCutoff": "2023-12-31", "structuredOutput": true, "lastUpdated": "2024-09-25", @@ -19730,7 +20054,7 @@ "description": "Popular open Llama workhorse for multilingual chat, coding, and self-hosting", "lifecycle": "active", "contextWindow": 131072, - "maxOutputTokens": 16384, + "maxOutputTokens": 115200, "knowledgeCutoff": "2023-12", "structuredOutput": true, "lastUpdated": "2024-12-06", @@ -19749,7 +20073,7 @@ "description": "Open multimodal Llama model for strong reasoning and fast responses", "lifecycle": "active", "contextWindow": 1048576, - "maxOutputTokens": 16384, + "maxOutputTokens": 115200, "knowledgeCutoff": "2024-08-31", "structuredOutput": true, "lastUpdated": "2025-04-05", @@ -19786,7 +20110,7 @@ "displayName": "Llama Guard 4 12B", "description": "Safety model for policy screening, moderation, and risk-aware routing workflows", "lifecycle": "active", - "contextWindow": 1048576, + "contextWindow": 163840, "maxOutputTokens": 16384, "knowledgeCutoff": "2024-08-31", "structuredOutput": false, @@ -19806,7 +20130,7 @@ "description": "Muse Glimmer is a 30-billion-parameter open-weight multimodal model from Meta Superintelligence Labs, distilled from Muse Spark for always-on local agents, tool use, coding, and image understanding.", "lifecycle": "active", "contextWindow": 131072, - "maxOutputTokens": 131072, + "maxOutputTokens": 16384, "knowledgeCutoff": "2026-01-04", "structuredOutput": true, "lastUpdated": "2026-08-10", @@ -19828,7 +20152,7 @@ "description": "Open Llama multimodal model for image understanding and text reasoning", "lifecycle": "active", "contextWindow": 1048576, - "maxOutputTokens": 1048576, + "maxOutputTokens": 943718, "structuredOutput": true, "lastUpdated": "2026-07-09", "capabilities": { @@ -19840,7 +20164,7 @@ "efforts": ["minimal", "low", "medium", "high", "xhigh"] }, "modalities": { - "input": ["text", "image", "pdf", "audio"], + "input": ["text", "image", "video", "pdf", "audio"], "output": ["text"] } }, @@ -19849,7 +20173,7 @@ "description": "Muse Spark 1.2 is a coding-focused update to Muse Spark 1.1 with improvements in code generation, complex debugging, codebase understanding, and end-to-end developer workflows.", "lifecycle": "active", "contextWindow": 1048576, - "maxOutputTokens": 1048576, + "maxOutputTokens": 943718, "structuredOutput": true, "lastUpdated": "2026-08-05", "capabilities": { @@ -19861,7 +20185,28 @@ "efforts": ["minimal", "low", "medium", "high", "xhigh"] }, "modalities": { - "input": ["text", "image", "pdf", "audio"], + "input": ["text", "image", "video", "pdf", "audio"], + "output": ["text"] + } + }, + "meta/muse-spark-1.2-contributor": { + "displayName": "Muse Spark 1.2 Contributor", + "description": "Open Llama multimodal model for image understanding and text reasoning", + "lifecycle": "active", + "contextWindow": 1048576, + "maxOutputTokens": 943718, + "structuredOutput": true, + "lastUpdated": "2026-08-21", + "capabilities": { + "vision": true, + "reasoning": true, + "functionCalling": true + }, + "thinkingOptions": { + "efforts": ["minimal", "low", "medium", "high", "xhigh"] + }, + "modalities": { + "input": ["text", "image", "video", "pdf", "audio"], "output": ["text"] } }, @@ -19870,7 +20215,7 @@ "description": "Open-weight instruction model for adaptable chat and self-hosted production workloads", "lifecycle": "active", "contextWindow": 16384, - "maxOutputTokens": 16384, + "maxOutputTokens": 14745, "knowledgeCutoff": "2024-06-30", "structuredOutput": true, "lastUpdated": "2025-01-10", @@ -19908,7 +20253,7 @@ "description": "MiniMax multimodal coding model for long-context reasoning and agent tasks", "lifecycle": "active", "contextWindow": 1000192, - "maxOutputTokens": 1000192, + "maxOutputTokens": 900172, "knowledgeCutoff": "2024-03-31", "structuredOutput": false, "lastUpdated": "2025-01-15", @@ -19936,6 +20281,9 @@ "reasoning": true, "functionCalling": true }, + "thinkingOptions": { + "toggle": true + }, "modalities": { "input": ["text"], "output": ["text"] @@ -20000,7 +20348,7 @@ "description": "Prior MiniMax coding model for agent workflows, office edits, and automation", "lifecycle": "active", "contextWindow": 204800, - "maxOutputTokens": 32768, + "maxOutputTokens": 128000, "structuredOutput": true, "lastUpdated": "2026-02-12", "capabilities": { @@ -20031,6 +20379,25 @@ "output": ["text"] } }, + "minimax/minimax-m2.7:free": { + "displayName": "MiniMax M2.7 (free)", + "description": "MiniMax model for chat, coding, office work, and agentic tasks", + "lifecycle": "active", + "contextWindow": 196608, + "maxOutputTokens": 176947, + "structuredOutput": false, + "lastUpdated": "2026-03-18", + "isFree": true, + "capabilities": { + "vision": false, + "reasoning": true, + "functionCalling": true + }, + "modalities": { + "input": ["text"], + "output": ["text"] + } + }, "minimax/minimax-m3": { "displayName": "MiniMax-M3", "description": "MiniMax multimodal model for long-context coding, perception, and agent planning", @@ -20044,8 +20411,33 @@ "reasoning": true, "functionCalling": true }, + "thinkingOptions": { + "toggle": true + }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], + "output": ["text"] + } + }, + "minimax/minimax-m3:free": { + "displayName": "MiniMax M3 (free)", + "description": "MiniMax multimodal coding model for long-context reasoning and agent tasks", + "lifecycle": "active", + "contextWindow": 1048576, + "maxOutputTokens": 943718, + "structuredOutput": false, + "lastUpdated": "2026-06-01", + "isFree": true, + "capabilities": { + "vision": true, + "reasoning": true, + "functionCalling": true + }, + "thinkingOptions": { + "toggle": true + }, + "modalities": { + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -20054,7 +20446,7 @@ "description": "Mistral coding model for code completion, generation, and developer workflows", "lifecycle": "active", "contextWindow": 256000, - "maxOutputTokens": 256000, + "maxOutputTokens": 204800, "knowledgeCutoff": "2025-03-31", "structuredOutput": true, "lastUpdated": "2025-08-01", @@ -20068,30 +20460,31 @@ "output": ["text"] } }, - "mistralai/ministral-14b-2512": { - "displayName": "Ministral 3 14B 2512", - "description": "Compact Mistral model for edge, latency-sensitive, and cost-efficient workloads", + "mistralai/devstral-2512": { + "displayName": "Devstral 2", + "description": "Mistral coding agent model for repository tasks and software engineering workflows", "lifecycle": "active", "contextWindow": 262144, - "maxOutputTokens": 262144, + "maxOutputTokens": 209715, + "knowledgeCutoff": "2025-12", "structuredOutput": true, - "lastUpdated": "2025-12-02", + "lastUpdated": "2025-12-09", "capabilities": { - "vision": true, + "vision": false, "reasoning": false, "functionCalling": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "pdf"], "output": ["text"] } }, - "mistralai/ministral-3b-2512": { - "displayName": "Ministral 3 3B 2512", + "mistralai/ministral-14b-2512": { + "displayName": "Ministral 3 14B 2512", "description": "Compact Mistral model for edge, latency-sensitive, and cost-efficient workloads", "lifecycle": "active", - "contextWindow": 131072, - "maxOutputTokens": 131072, + "contextWindow": 262144, + "maxOutputTokens": 209715, "structuredOutput": true, "lastUpdated": "2025-12-02", "capabilities": { @@ -20104,22 +20497,21 @@ "output": ["text"] } }, - "mistralai/ministral-8b": { - "displayName": "Ministral 8B", + "mistralai/ministral-3b-2512": { + "displayName": "Ministral 3 3B 2512", "description": "Compact Mistral model for edge, latency-sensitive, and cost-efficient workloads", "lifecycle": "active", - "contextWindow": 128000, - "maxOutputTokens": 128000, - "knowledgeCutoff": "2024-09-30", + "contextWindow": 131072, + "maxOutputTokens": 104857, "structuredOutput": true, - "lastUpdated": "2024-10-17", + "lastUpdated": "2025-12-02", "capabilities": { - "vision": false, + "vision": true, "reasoning": false, - "functionCalling": false + "functionCalling": true }, "modalities": { - "input": ["text"], + "input": ["text", "image"], "output": ["text"] } }, @@ -20128,7 +20520,7 @@ "description": "Compact Mistral model for edge, latency-sensitive, and cost-efficient workloads", "lifecycle": "active", "contextWindow": 262144, - "maxOutputTokens": 262144, + "maxOutputTokens": 209715, "structuredOutput": true, "lastUpdated": "2025-12-02", "capabilities": { @@ -20146,7 +20538,7 @@ "description": "Flagship Mistral model for advanced reasoning, coding, and multilingual work", "lifecycle": "active", "contextWindow": 128000, - "maxOutputTokens": 128000, + "maxOutputTokens": 102400, "knowledgeCutoff": "2024-11-30", "structuredOutput": true, "lastUpdated": "2024-02-26", @@ -20165,7 +20557,7 @@ "description": "Flagship Mistral model for advanced reasoning, coding, and multilingual work", "lifecycle": "active", "contextWindow": 131072, - "maxOutputTokens": 131072, + "maxOutputTokens": 104857, "knowledgeCutoff": "2024-03-31", "structuredOutput": true, "lastUpdated": "2024-11-19", @@ -20184,7 +20576,7 @@ "description": "Mistral's largest general model for enterprise agents, coding, and multilingual reasoning", "lifecycle": "active", "contextWindow": 262144, - "maxOutputTokens": 262144, + "maxOutputTokens": 209715, "knowledgeCutoff": "2024-11", "structuredOutput": true, "lastUpdated": "2025-12-02", @@ -20203,7 +20595,7 @@ "description": "Mistral model for multilingual chat, reasoning, and tool-assisted workflows", "lifecycle": "active", "contextWindow": 131072, - "maxOutputTokens": 131072, + "maxOutputTokens": 104857, "knowledgeCutoff": "2025-03-31", "structuredOutput": true, "lastUpdated": "2025-05-07", @@ -20222,7 +20614,7 @@ "description": "Mistral model for multilingual chat, reasoning, and tool-assisted workflows", "lifecycle": "active", "contextWindow": 262144, - "maxOutputTokens": 262144, + "maxOutputTokens": 209715, "structuredOutput": true, "lastUpdated": "2026-04-30", "capabilities": { @@ -20243,7 +20635,7 @@ "description": "Mistral model for multilingual chat, reasoning, and tool-assisted workflows", "lifecycle": "active", "contextWindow": 131072, - "maxOutputTokens": 262144, + "maxOutputTokens": 104857, "knowledgeCutoff": "2025-06-30", "structuredOutput": true, "lastUpdated": "2025-08-13", @@ -20281,7 +20673,7 @@ "description": "Mistral model for multilingual chat, reasoning, and tool-assisted workflows", "lifecycle": "active", "contextWindow": 32768, - "maxOutputTokens": 32768, + "maxOutputTokens": 26214, "knowledgeCutoff": "2024-09-30", "structuredOutput": true, "lastUpdated": "2025-02-17", @@ -20319,7 +20711,7 @@ "description": "Fast Mistral production model for chat, extraction, and cost-sensitive agents", "lifecycle": "active", "contextWindow": 262144, - "maxOutputTokens": 262144, + "maxOutputTokens": 209715, "knowledgeCutoff": "2025-06", "structuredOutput": true, "lastUpdated": "2026-03-16", @@ -20341,7 +20733,7 @@ "description": "Efficient Mistral model for fast chat, extraction, and production assistants", "lifecycle": "active", "contextWindow": 128000, - "maxOutputTokens": 128000, + "maxOutputTokens": 102400, "knowledgeCutoff": "2023-10-31", "structuredOutput": false, "lastUpdated": "2025-03-17", @@ -20359,7 +20751,7 @@ "displayName": "Mistral Small 3.2 24B", "description": "Efficient Mistral model for fast chat, extraction, and production assistants", "lifecycle": "active", - "contextWindow": 256000, + "contextWindow": 131072, "maxOutputTokens": 16384, "knowledgeCutoff": "2023-10-31", "structuredOutput": true, @@ -20379,7 +20771,7 @@ "description": "Mistral model for multilingual chat, reasoning, and tool-assisted workflows", "lifecycle": "active", "contextWindow": 65536, - "maxOutputTokens": 65536, + "maxOutputTokens": 52428, "knowledgeCutoff": "2024-01-31", "structuredOutput": true, "lastUpdated": "2024-04-17", @@ -20397,8 +20789,8 @@ "displayName": "Voxtral Small 24B 2507", "description": "Efficient Mistral model for fast chat, extraction, and production assistants", "lifecycle": "active", - "contextWindow": 32000, - "maxOutputTokens": 32000, + "contextWindow": 32768, + "maxOutputTokens": 26214, "structuredOutput": true, "lastUpdated": "2025-10-30", "capabilities": { @@ -20473,7 +20865,7 @@ "description": "Earlier Kimi frontier model for long-context agents, coding, and multimodal work", "lifecycle": "active", "contextWindow": 262144, - "maxOutputTokens": 262144, + "maxOutputTokens": 235929, "knowledgeCutoff": "2025-01", "structuredOutput": true, "lastUpdated": "2026-01", @@ -20482,6 +20874,9 @@ "reasoning": true, "functionCalling": true }, + "thinkingOptions": { + "toggle": true + }, "modalities": { "input": ["text", "image"], "output": ["text"] @@ -20492,7 +20887,7 @@ "description": "Multimodal Kimi workhorse for agent loops, coding tasks, and visual context", "lifecycle": "active", "contextWindow": 262144, - "maxOutputTokens": 262144, + "maxOutputTokens": 235929, "knowledgeCutoff": "2025-01", "structuredOutput": true, "lastUpdated": "2026-04-21", @@ -20501,6 +20896,9 @@ "reasoning": true, "functionCalling": true }, + "thinkingOptions": { + "toggle": true + }, "modalities": { "input": ["text", "image"], "output": ["text"] @@ -20511,7 +20909,7 @@ "description": "Coding-focused Kimi model, stronger on long-horizon repo work with less overthinking", "lifecycle": "active", "contextWindow": 262144, - "maxOutputTokens": 262144, + "maxOutputTokens": 235929, "knowledgeCutoff": "2025-01", "structuredOutput": true, "lastUpdated": "2026-06-12", @@ -20530,7 +20928,7 @@ "description": "Kimi multimodal agent model for visual understanding, coding, and planning", "lifecycle": "active", "contextWindow": 1048576, - "maxOutputTokens": 1048576, + "maxOutputTokens": 943718, "structuredOutput": true, "lastUpdated": "2026-07-16", "capabilities": { @@ -20543,7 +20941,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -20588,7 +20986,7 @@ "description": "Multimodal reasoning model for visual analysis, planning, and tool use", "lifecycle": "active", "contextWindow": 262144, - "maxOutputTokens": 262144, + "maxOutputTokens": 235929, "structuredOutput": true, "lastUpdated": "2026-06-24", "capabilities": { @@ -20596,6 +20994,9 @@ "reasoning": true, "functionCalling": true }, + "thinkingOptions": { + "toggle": true + }, "modalities": { "input": ["text", "image"], "output": ["text"] @@ -20606,7 +21007,7 @@ "description": "Multimodal reasoning model for visual analysis, planning, and tool use", "lifecycle": "active", "contextWindow": 262144, - "maxOutputTokens": 262144, + "maxOutputTokens": 235929, "structuredOutput": false, "lastUpdated": "2026-06-08", "capabilities": { @@ -20614,6 +21015,9 @@ "reasoning": true, "functionCalling": true }, + "thinkingOptions": { + "toggle": true + }, "modalities": { "input": ["text", "image"], "output": ["text"] @@ -20662,7 +21066,7 @@ "description": "Reasoning model for deliberate analysis, multi-step problem solving, and tool use", "lifecycle": "active", "contextWindow": 131072, - "maxOutputTokens": 131072, + "maxOutputTokens": 117964, "knowledgeCutoff": "2024-08-31", "structuredOutput": false, "lastUpdated": "2025-08-26", @@ -20684,7 +21088,7 @@ "description": "Reasoning model for deliberate analysis, multi-step problem solving, and tool use", "lifecycle": "active", "contextWindow": 131072, - "maxOutputTokens": 131072, + "maxOutputTokens": 117964, "knowledgeCutoff": "2024-08-31", "structuredOutput": false, "lastUpdated": "2025-08-26", @@ -20706,7 +21110,7 @@ "description": "Small Nemotron 3 MoE for efficient coding, math, and long-context agents", "lifecycle": "active", "contextWindow": 262144, - "maxOutputTokens": 262144, + "maxOutputTokens": 228000, "structuredOutput": true, "lastUpdated": "2025-12-15", "capabilities": { @@ -20714,24 +21118,8 @@ "reasoning": true, "functionCalling": true }, - "modalities": { - "input": ["text"], - "output": ["text"] - } - }, - "nvidia/nemotron-3-nano-30b-a3b:free": { - "displayName": "Nemotron 3 Nano 30B A3B (free)", - "description": "Small Nemotron 3 MoE for efficient coding, math, and long-context agents", - "lifecycle": "active", - "contextWindow": 256000, - "maxOutputTokens": 256000, - "structuredOutput": false, - "lastUpdated": "2025-12-15", - "isFree": true, - "capabilities": { - "vision": false, - "reasoning": true, - "functionCalling": true + "thinkingOptions": { + "toggle": true }, "modalities": { "input": ["text"], @@ -20752,8 +21140,11 @@ "reasoning": true, "functionCalling": true }, + "thinkingOptions": { + "toggle": true + }, "modalities": { - "input": ["text", "image", "audio"], + "input": ["text", "image", "video", "audio"], "output": ["text"] } }, @@ -20784,7 +21175,7 @@ "description": "Nemotron middle tier for collaborative agents and high-volume reasoning workloads", "lifecycle": "active", "contextWindow": 262144, - "maxOutputTokens": 262144, + "maxOutputTokens": 235929, "structuredOutput": true, "lastUpdated": "2026-03-11", "isFree": true, @@ -20806,7 +21197,7 @@ "displayName": "Nemotron 3 Ultra 550B A55B", "description": "Largest Nemotron 3 model for maximum open-weight reasoning and agent accuracy", "lifecycle": "active", - "contextWindow": 512288, + "contextWindow": 262144, "maxOutputTokens": 16384, "structuredOutput": true, "lastUpdated": "2026-06-04", @@ -20861,6 +21252,9 @@ "reasoning": true, "functionCalling": false }, + "thinkingOptions": { + "toggle": true + }, "modalities": { "input": ["text", "image"], "output": ["text"] @@ -20909,44 +21303,6 @@ "output": ["text"] } }, - "nvidia/nemotron-nano-12b-v2-vl:free": { - "displayName": "Nemotron Nano 12B 2 VL (free)", - "description": "Nemotron multimodal model for visual reasoning and agentic AI workflows", - "lifecycle": "active", - "contextWindow": 128000, - "maxOutputTokens": 128000, - "structuredOutput": false, - "lastUpdated": "2025-10-28", - "isFree": true, - "capabilities": { - "vision": true, - "reasoning": true, - "functionCalling": true - }, - "modalities": { - "input": ["text", "image"], - "output": ["text"] - } - }, - "nvidia/nemotron-nano-9b-v2:free": { - "displayName": "Nemotron Nano 9B V2 (free)", - "description": "Compact Nemotron model for efficient reasoning and deployable AI agents", - "lifecycle": "active", - "contextWindow": 128000, - "maxOutputTokens": 128000, - "structuredOutput": true, - "lastUpdated": "2025-08-18", - "isFree": true, - "capabilities": { - "vision": false, - "reasoning": true, - "functionCalling": true - }, - "modalities": { - "input": ["text"], - "output": ["text"] - } - }, "openai/gpt-3.5-turbo": { "displayName": "GPT-3.5-turbo", "description": "Compact GPT model for low-latency assistance and high-volume workloads", @@ -20971,7 +21327,7 @@ "description": "Compact GPT model for low-latency assistance and high-volume workloads", "lifecycle": "active", "contextWindow": 4095, - "maxOutputTokens": 4096, + "maxOutputTokens": 3685, "knowledgeCutoff": "2021-09-30", "structuredOutput": true, "lastUpdated": "2024-01-25", @@ -21009,7 +21365,7 @@ "description": "Compact GPT model for low-latency assistance and high-volume workloads", "lifecycle": "active", "contextWindow": 4095, - "maxOutputTokens": 4096, + "maxOutputTokens": 3685, "knowledgeCutoff": "2021-09-30", "structuredOutput": true, "lastUpdated": "2023-09-28", @@ -21940,7 +22296,7 @@ "description": "Open GPT reasoning model for self-hosted agents and controllable deployments", "lifecycle": "active", "contextWindow": 131072, - "maxOutputTokens": 131072, + "maxOutputTokens": 117964, "structuredOutput": true, "lastUpdated": "2025-08-05", "capabilities": { @@ -21961,7 +22317,7 @@ "description": "Open-weight GPT model for self-hosted reasoning and instruction-following workloads", "lifecycle": "active", "contextWindow": 131072, - "maxOutputTokens": 131072, + "maxOutputTokens": 117964, "structuredOutput": true, "lastUpdated": "2025-08-05", "capabilities": { @@ -21977,28 +22333,6 @@ "output": ["text"] } }, - "openai/gpt-oss-20b:free": { - "displayName": "gpt-oss-20b (free)", - "description": "Open-weight GPT model for self-hosted reasoning and instruction-following workloads", - "lifecycle": "active", - "contextWindow": 131072, - "maxOutputTokens": 32768, - "structuredOutput": true, - "lastUpdated": "2025-08-05", - "isFree": true, - "capabilities": { - "vision": false, - "reasoning": true, - "functionCalling": true - }, - "thinkingOptions": { - "efforts": ["low", "medium", "high"] - }, - "modalities": { - "input": ["text"], - "output": ["text"] - } - }, "openai/gpt-oss-safeguard-20b": { "displayName": "gpt-oss-safeguard-20b", "description": "Safety model for policy screening, moderation, and risk-aware routing workflows", @@ -22035,7 +22369,7 @@ "functionCalling": true }, "thinkingOptions": { - "efforts": ["low", "medium", "high"] + "toggle": true }, "modalities": { "input": ["text", "image", "pdf"], @@ -22056,6 +22390,9 @@ "reasoning": true, "functionCalling": false }, + "thinkingOptions": { + "toggle": true + }, "modalities": { "input": ["text", "image", "pdf"], "output": ["text"] @@ -22076,7 +22413,7 @@ "functionCalling": true }, "thinkingOptions": { - "efforts": ["low", "medium", "high"] + "toggle": true }, "modalities": { "input": ["text", "image", "pdf"], @@ -22098,7 +22435,7 @@ "functionCalling": true }, "thinkingOptions": { - "efforts": ["low", "medium", "high"] + "toggle": true }, "modalities": { "input": ["text", "pdf"], @@ -22142,7 +22479,7 @@ "functionCalling": true }, "thinkingOptions": { - "efforts": ["low", "medium", "high"] + "toggle": true }, "modalities": { "input": ["text", "pdf", "image"], @@ -22164,7 +22501,7 @@ "functionCalling": true }, "thinkingOptions": { - "efforts": ["low", "medium", "high"] + "toggle": true }, "modalities": { "input": ["image", "text", "pdf"], @@ -22207,7 +22544,7 @@ "functionCalling": true }, "modalities": { - "input": ["text", "image", "audio", "pdf"], + "input": ["text", "image", "audio", "pdf", "video"], "output": ["text", "image"] } }, @@ -22298,8 +22635,11 @@ "reasoning": true, "functionCalling": false }, + "thinkingOptions": { + "toggle": true + }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -22308,7 +22648,7 @@ "description": "Sonar search model for current answers, retrieval, and citation-backed chat", "lifecycle": "active", "contextWindow": 127072, - "maxOutputTokens": 127072, + "maxOutputTokens": 114364, "structuredOutput": false, "lastUpdated": "2025-01-27", "capabilities": { @@ -22326,7 +22666,7 @@ "description": "Sonar search model for current answers, retrieval, and citation-backed chat", "lifecycle": "active", "contextWindow": 128000, - "maxOutputTokens": 128000, + "maxOutputTokens": 115200, "structuredOutput": false, "lastUpdated": "2025-03-07", "capabilities": { @@ -22334,6 +22674,9 @@ "reasoning": true, "functionCalling": false }, + "thinkingOptions": { + "toggle": true + }, "modalities": { "input": ["text"], "output": ["text"] @@ -22380,7 +22723,7 @@ "description": "Web-grounded reasoning model for multi-step research and cited answers", "lifecycle": "active", "contextWindow": 128000, - "maxOutputTokens": 128000, + "maxOutputTokens": 115200, "structuredOutput": false, "lastUpdated": "2025-03-07", "capabilities": { @@ -22388,6 +22731,9 @@ "reasoning": true, "functionCalling": false }, + "thinkingOptions": { + "toggle": true + }, "modalities": { "input": ["text", "image"], "output": ["text"] @@ -22406,6 +22752,9 @@ "reasoning": true, "functionCalling": true }, + "thinkingOptions": { + "toggle": true + }, "modalities": { "input": ["text"], "output": ["text"] @@ -22425,6 +22774,9 @@ "reasoning": true, "functionCalling": true }, + "thinkingOptions": { + "toggle": true + }, "modalities": { "input": ["text"], "output": ["text"] @@ -22443,6 +22795,9 @@ "reasoning": true, "functionCalling": true }, + "thinkingOptions": { + "toggle": true + }, "modalities": { "input": ["text"], "output": ["text"] @@ -22462,6 +22817,9 @@ "reasoning": true, "functionCalling": true }, + "thinkingOptions": { + "toggle": true + }, "modalities": { "input": ["text"], "output": ["text"] @@ -22491,7 +22849,7 @@ "description": "Qwen instruction model for multilingual chat, reasoning, and tool use", "lifecycle": "active", "contextWindow": 32768, - "maxOutputTokens": 32768, + "maxOutputTokens": 29491, "knowledgeCutoff": "2024-06-30", "structuredOutput": true, "lastUpdated": "2024-10-16", @@ -22510,7 +22868,7 @@ "description": "Qwen coding model for software agents, repository edits, and code reasoning", "lifecycle": "active", "contextWindow": 32768, - "maxOutputTokens": 32768, + "maxOutputTokens": 29491, "knowledgeCutoff": "2024-06-30", "structuredOutput": false, "lastUpdated": "2024-11-11", @@ -22562,31 +22920,12 @@ "output": ["text"] } }, - "qwen/qwen-plus-2025-07-28:thinking": { - "displayName": "Qwen Plus 0728 (thinking)", - "description": "Qwen reasoning model for deliberate problem solving, math, and coding", - "lifecycle": "active", - "contextWindow": 1000000, - "maxOutputTokens": 32768, - "knowledgeCutoff": "2025-03-31", - "structuredOutput": true, - "lastUpdated": "2025-09-08", - "capabilities": { - "vision": false, - "reasoning": true, - "functionCalling": true - }, - "modalities": { - "input": ["text"], - "output": ["text"] - } - }, "qwen/qwen2.5-vl-72b-instruct": { "displayName": "Qwen2.5 VL 72B Instruct", "description": "Qwen vision-language model for visual reasoning, documents, and agent tasks", "lifecycle": "active", "contextWindow": 128000, - "maxOutputTokens": 128000, + "maxOutputTokens": 28800, "knowledgeCutoff": "2024-06-30", "structuredOutput": true, "lastUpdated": "2025-02-01", @@ -22649,7 +22988,7 @@ "description": "Qwen instruction model for multilingual chat, reasoning, and tool use", "lifecycle": "active", "contextWindow": 262144, - "maxOutputTokens": 16384, + "maxOutputTokens": 235929, "knowledgeCutoff": "2025-06-30", "structuredOutput": true, "lastUpdated": "2025-07-21", @@ -22667,8 +23006,8 @@ "displayName": "Qwen3 235B A22B Thinking 2507", "description": "Qwen reasoning model for deliberate problem solving, math, and coding", "lifecycle": "active", - "contextWindow": 262144, - "maxOutputTokens": 32768, + "contextWindow": 131072, + "maxOutputTokens": 117964, "knowledgeCutoff": "2025-06-30", "structuredOutput": false, "lastUpdated": "2025-07-25", @@ -22687,7 +23026,7 @@ "description": "Qwen instruction model for multilingual chat, reasoning, and tool use", "lifecycle": "active", "contextWindow": 131072, - "maxOutputTokens": 8192, + "maxOutputTokens": 16384, "structuredOutput": false, "lastUpdated": "2025-04-28", "capabilities": { @@ -22809,7 +23148,7 @@ "description": "Smaller Qwen coder for efficient local agents and repo-level fixes", "lifecycle": "active", "contextWindow": 262144, - "maxOutputTokens": 262144, + "maxOutputTokens": 235929, "knowledgeCutoff": "2025-04", "structuredOutput": true, "lastUpdated": "2025-04", @@ -22847,7 +23186,7 @@ "description": "Qwen coding model for software agents, repository edits, and code reasoning", "lifecycle": "active", "contextWindow": 262144, - "maxOutputTokens": 262144, + "maxOutputTokens": 235929, "knowledgeCutoff": "2025-09", "structuredOutput": true, "lastUpdated": "2026-02-03", @@ -22912,6 +23251,9 @@ "reasoning": true, "functionCalling": true }, + "thinkingOptions": { + "toggle": true + }, "modalities": { "input": ["text"], "output": ["text"] @@ -22922,7 +23264,7 @@ "description": "Qwen instruction model for multilingual chat, reasoning, and tool use", "lifecycle": "active", "contextWindow": 262144, - "maxOutputTokens": 16384, + "maxOutputTokens": 235929, "knowledgeCutoff": "2025-04", "structuredOutput": true, "lastUpdated": "2025-09", @@ -22998,7 +23340,7 @@ "description": "Qwen vision-language model for visual reasoning, documents, and agent tasks", "lifecycle": "active", "contextWindow": 262144, - "maxOutputTokens": 32768, + "maxOutputTokens": 16384, "knowledgeCutoff": "2025-03-31", "structuredOutput": true, "lastUpdated": "2025-10-06", @@ -23090,7 +23432,7 @@ "description": "Qwen vision-language model for visual reasoning, documents, and agent tasks", "lifecycle": "active", "contextWindow": 262144, - "maxOutputTokens": 65536, + "maxOutputTokens": 81920, "structuredOutput": true, "lastUpdated": "2026-02-23", "capabilities": { @@ -23102,7 +23444,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -23123,7 +23465,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -23132,7 +23474,7 @@ "description": "Qwen vision-language model for visual reasoning, documents, and agent tasks", "lifecycle": "active", "contextWindow": 262144, - "maxOutputTokens": 262144, + "maxOutputTokens": 235929, "structuredOutput": true, "lastUpdated": "2026-02-23", "capabilities": { @@ -23144,7 +23486,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -23165,7 +23507,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -23174,7 +23516,7 @@ "description": "Qwen instruction model for multilingual chat, reasoning, and tool use", "lifecycle": "active", "contextWindow": 262144, - "maxOutputTokens": 262144, + "maxOutputTokens": 235929, "structuredOutput": true, "lastUpdated": "2026-02-23", "capabilities": { @@ -23186,7 +23528,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -23207,7 +23549,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -23229,7 +23571,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -23250,7 +23592,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -23259,7 +23601,7 @@ "description": "Qwen vision-language model for visual reasoning, documents, and agent tasks", "lifecycle": "active", "contextWindow": 262144, - "maxOutputTokens": 262144, + "maxOutputTokens": 235929, "structuredOutput": true, "lastUpdated": "2026-04-22", "capabilities": { @@ -23271,7 +23613,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -23280,7 +23622,7 @@ "description": "Open multimodal Qwen MoE for local agents that need vision, audio, and code", "lifecycle": "active", "contextWindow": 262144, - "maxOutputTokens": 262144, + "maxOutputTokens": 235929, "structuredOutput": true, "lastUpdated": "2026-04-17", "capabilities": { @@ -23292,7 +23634,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -23313,7 +23655,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -23357,7 +23699,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -23375,8 +23717,11 @@ "reasoning": true, "functionCalling": true }, + "thinkingOptions": { + "toggle": true + }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -23462,7 +23807,28 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], + "output": ["text"] + } + }, + "qwen/qwen3.8-flash": { + "displayName": "Qwen3.8 Flash", + "description": "Qwen vision-language model for visual reasoning, documents, and agent tasks", + "lifecycle": "active", + "contextWindow": 1000000, + "maxOutputTokens": 131072, + "structuredOutput": true, + "lastUpdated": "2026-08-26", + "capabilities": { + "vision": true, + "reasoning": true, + "functionCalling": true + }, + "thinkingOptions": { + "toggle": true + }, + "modalities": { + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -23483,7 +23849,7 @@ "efforts": ["minimal", "low", "medium", "high", "xhigh"] }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -23492,7 +23858,7 @@ "description": "Multimodal model for analyzing text, images, documents, and rich media", "lifecycle": "active", "contextWindow": 16384, - "maxOutputTokens": 16384, + "maxOutputTokens": 14745, "structuredOutput": true, "lastUpdated": "2026-03-20", "capabilities": { @@ -23501,7 +23867,7 @@ "functionCalling": true }, "modalities": { - "input": ["image", "text"], + "input": ["image", "text", "video"], "output": ["text"] } }, @@ -23510,7 +23876,7 @@ "description": "Efficient model for low-latency assistance, extraction, and routine automation", "lifecycle": "active", "contextWindow": 65536, - "maxOutputTokens": 65536, + "maxOutputTokens": 58982, "knowledgeCutoff": "2025-01-31", "structuredOutput": true, "lastUpdated": "2025-03-12", @@ -23607,7 +23973,7 @@ "description": "Open Llama instruction model for multilingual chat, reasoning, and coding", "lifecycle": "active", "contextWindow": 8192, - "maxOutputTokens": 16384, + "maxOutputTokens": 7372, "knowledgeCutoff": "2023-12-31", "structuredOutput": true, "lastUpdated": "2024-08-13", @@ -23659,28 +24025,6 @@ "output": ["text"] } }, - "stealth/ox-alpha": { - "displayName": "Ox Alpha", - "description": "Multimodal reasoning model for visual analysis, planning, and tool use", - "lifecycle": "active", - "contextWindow": 1048576, - "maxOutputTokens": 131072, - "structuredOutput": false, - "lastUpdated": "2026-08-20", - "isFree": true, - "capabilities": { - "vision": true, - "reasoning": true, - "functionCalling": true - }, - "thinkingOptions": { - "efforts": ["low", "high", "max"] - }, - "modalities": { - "input": ["text", "image"], - "output": ["text"] - } - }, "stepfun/step-3.5-flash": { "displayName": "Step 3.5 Flash", "description": "StepFun flash lane for quick multimodal reasoning and coding assistance", @@ -23706,7 +24050,7 @@ "lifecycle": "active", "contextWindow": 262144, "inputLimit": 256000, - "maxOutputTokens": 256000, + "maxOutputTokens": 230400, "knowledgeCutoff": "2026-03-01", "structuredOutput": true, "lastUpdated": "2026-05-29", @@ -23719,7 +24063,7 @@ "efforts": ["low", "medium", "high"] }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -23728,7 +24072,7 @@ "description": "Tencent Hy reasoning model for coding, instruction following, and agent tasks", "lifecycle": "active", "contextWindow": 131072, - "maxOutputTokens": 131072, + "maxOutputTokens": 117964, "knowledgeCutoff": "2025-03-31", "structuredOutput": true, "lastUpdated": "2025-07-08", @@ -23737,6 +24081,9 @@ "reasoning": true, "functionCalling": false }, + "thinkingOptions": { + "toggle": true + }, "modalities": { "input": ["text"], "output": ["text"] @@ -23778,6 +24125,24 @@ "output": ["text"] } }, + "tencent/hy-mt2-7b": { + "displayName": "Hy-MT2-7B", + "description": "Tencent Hy reasoning model for coding, instruction following, and agent tasks", + "lifecycle": "active", + "contextWindow": 8192, + "maxOutputTokens": 4096, + "structuredOutput": true, + "lastUpdated": "2026-08-19", + "capabilities": { + "vision": false, + "reasoning": false, + "functionCalling": false + }, + "modalities": { + "input": ["text"], + "output": ["text"] + } + }, "tencent/hy3": { "displayName": "Hy3", "description": "Tencent Hy reasoning model for coding, instruction following, and agent tasks", @@ -23804,7 +24169,7 @@ "description": "Tencent Hy reasoning model for coding, instruction following, and agent tasks", "lifecycle": "active", "contextWindow": 262144, - "maxOutputTokens": 262144, + "maxOutputTokens": 235929, "structuredOutput": false, "lastUpdated": "2026-04-20", "capabilities": { @@ -23820,34 +24185,36 @@ "output": ["text"] } }, - "thedrummer/cydonia-24b-v4.1": { - "displayName": "Cydonia 24B V4.1", - "description": "Open-weight instruction model for adaptable chat and self-hosted production workloads", + "tencent/hy4-preview": { + "displayName": "Hy4 preview", + "description": "Tencent Hy reasoning model for coding, instruction following, and agent tasks", "lifecycle": "active", - "contextWindow": 131072, - "maxOutputTokens": 131072, - "knowledgeCutoff": "2024-04-30", + "contextWindow": 1048576, + "maxOutputTokens": 64000, "structuredOutput": true, - "lastUpdated": "2025-09-27", + "lastUpdated": "2026-08-28", "capabilities": { "vision": false, - "reasoning": false, - "functionCalling": false + "reasoning": true, + "functionCalling": true + }, + "thinkingOptions": { + "efforts": ["none", "low", "high"] }, "modalities": { "input": ["text"], "output": ["text"] } }, - "thedrummer/rocinante-12b": { - "displayName": "Rocinante 12B", + "thedrummer/cydonia-24b-v4.1": { + "displayName": "Cydonia 24B V4.1", "description": "Open-weight instruction model for adaptable chat and self-hosted production workloads", "lifecycle": "active", - "contextWindow": 65536, - "maxOutputTokens": 65536, + "contextWindow": 131072, + "maxOutputTokens": 117964, "knowledgeCutoff": "2024-04-30", "structuredOutput": true, - "lastUpdated": "2024-09-30", + "lastUpdated": "2025-09-27", "capabilities": { "vision": false, "reasoning": false, @@ -23863,7 +24230,7 @@ "description": "Open-weight instruction model for adaptable chat and self-hosted production workloads", "lifecycle": "active", "contextWindow": 32768, - "maxOutputTokens": 32768, + "maxOutputTokens": 29491, "knowledgeCutoff": "2024-06-30", "structuredOutput": true, "lastUpdated": "2025-03-10", @@ -23882,7 +24249,7 @@ "description": "Open-weight instruction model for adaptable chat and self-hosted production workloads", "lifecycle": "active", "contextWindow": 1024000, - "maxOutputTokens": 1024000, + "maxOutputTokens": 26214, "knowledgeCutoff": "2024-04-30", "structuredOutput": true, "lastUpdated": "2024-11-08", @@ -23901,7 +24268,7 @@ "description": "Multimodal reasoning model for visual analysis, planning, and tool use", "lifecycle": "active", "contextWindow": 1048576, - "maxOutputTokens": 262144, + "maxOutputTokens": 471859, "structuredOutput": false, "lastUpdated": "2026-07-15", "capabilities": { @@ -23923,8 +24290,52 @@ "lifecycle": "active", "contextWindow": 1048576, "maxOutputTokens": 262144, - "structuredOutput": true, + "structuredOutput": false, + "lastUpdated": "2026-07-30", + "capabilities": { + "vision": true, + "reasoning": true, + "functionCalling": true + }, + "thinkingOptions": { + "efforts": ["none", "minimal", "low", "medium", "high", "max"] + }, + "modalities": { + "input": ["text", "image", "audio"], + "output": ["text"] + } + }, + "thinkingmachines/inkling-small:free": { + "displayName": "Inkling Small (free)", + "description": "Multimodal reasoning model for visual analysis, planning, and tool use", + "lifecycle": "active", + "contextWindow": 1048576, + "maxOutputTokens": 262144, + "structuredOutput": false, "lastUpdated": "2026-07-30", + "isFree": true, + "capabilities": { + "vision": true, + "reasoning": true, + "functionCalling": true + }, + "thinkingOptions": { + "efforts": ["none", "minimal", "low", "medium", "high", "max"] + }, + "modalities": { + "input": ["text", "image", "audio"], + "output": ["text"] + } + }, + "thinkingmachines/inkling:free": { + "displayName": "Inkling (free)", + "description": "Multimodal reasoning model for visual analysis, planning, and tool use", + "lifecycle": "active", + "contextWindow": 1048576, + "maxOutputTokens": 262144, + "structuredOutput": false, + "lastUpdated": "2026-07-15", + "isFree": true, "capabilities": { "vision": true, "reasoning": true, @@ -23943,7 +24354,7 @@ "description": "Open-weight instruction model for adaptable chat and self-hosted production workloads", "lifecycle": "active", "contextWindow": 6144, - "maxOutputTokens": 6144, + "maxOutputTokens": 4096, "knowledgeCutoff": "2023-06-30", "structuredOutput": true, "lastUpdated": "2023-07-22", @@ -23962,7 +24373,7 @@ "description": "Flagship model for demanding analysis, coding, and production agent workflows", "lifecycle": "active", "contextWindow": 131072, - "maxOutputTokens": 131072, + "maxOutputTokens": 117964, "structuredOutput": true, "lastUpdated": "2026-01-27", "capabilities": { @@ -23970,6 +24381,9 @@ "reasoning": true, "functionCalling": true }, + "thinkingOptions": { + "toggle": true + }, "modalities": { "input": ["text"], "output": ["text"] @@ -23988,6 +24402,9 @@ "reasoning": true, "functionCalling": true }, + "thinkingOptions": { + "toggle": true + }, "modalities": { "input": ["text"], "output": ["text"] @@ -24016,7 +24433,7 @@ "description": "Grok model for agentic tool use, reasoning, coding, and live assistance", "lifecycle": "active", "contextWindow": 2000000, - "maxOutputTokens": 2000000, + "maxOutputTokens": 1800000, "knowledgeCutoff": "2025-09-01", "structuredOutput": true, "lastUpdated": "2026-03-31", @@ -24025,6 +24442,9 @@ "reasoning": true, "functionCalling": true }, + "thinkingOptions": { + "toggle": true + }, "modalities": { "input": ["text", "image", "pdf"], "output": ["text"] @@ -24035,7 +24455,7 @@ "description": "Grok model for agentic tool use, reasoning, coding, and live assistance", "lifecycle": "active", "contextWindow": 2000000, - "maxOutputTokens": 2000000, + "maxOutputTokens": 1800000, "knowledgeCutoff": "2025-09-01", "structuredOutput": true, "lastUpdated": "2026-03-31", @@ -24057,7 +24477,7 @@ "description": "xAI's default Grok for chat, coding, agentic tools, and lower hallucination risk", "lifecycle": "active", "contextWindow": 1000000, - "maxOutputTokens": 1000000, + "maxOutputTokens": 900000, "structuredOutput": true, "lastUpdated": "2026-04-17", "capabilities": { @@ -24078,7 +24498,7 @@ "description": "xAI's Grok model for chat, coding, agentic tools, and lower hallucination risk", "lifecycle": "active", "contextWindow": 500000, - "maxOutputTokens": 500000, + "maxOutputTokens": 450000, "structuredOutput": true, "lastUpdated": "2026-07-08", "capabilities": { @@ -24099,7 +24519,7 @@ "description": "Grok model for agentic tool use, reasoning, coding, and live assistance", "lifecycle": "active", "contextWindow": 500000, - "maxOutputTokens": 500000, + "maxOutputTokens": 450000, "knowledgeCutoff": "2026-02-01", "structuredOutput": true, "lastUpdated": "2026-08-12", @@ -24121,7 +24541,7 @@ "description": "Fast Grok coding model tuned for agentic engineering and iterative edits", "lifecycle": "active", "contextWindow": 256000, - "maxOutputTokens": 256000, + "maxOutputTokens": 230400, "structuredOutput": true, "lastUpdated": "2026-04-16", "capabilities": { @@ -24152,7 +24572,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image", "audio"], + "input": ["text", "image", "audio", "video"], "output": ["text"] } }, @@ -24249,7 +24669,7 @@ "description": "Late GLM-4 workhorse for coding agents, reasoning, and structured tasks", "lifecycle": "active", "contextWindow": 204800, - "maxOutputTokens": 131072, + "maxOutputTokens": 16384, "knowledgeCutoff": "2025-04", "structuredOutput": true, "lastUpdated": "2025-09-30", @@ -24258,6 +24678,9 @@ "reasoning": true, "functionCalling": true }, + "thinkingOptions": { + "toggle": true + }, "modalities": { "input": ["text"], "output": ["text"] @@ -24277,8 +24700,11 @@ "reasoning": true, "functionCalling": true }, + "thinkingOptions": { + "toggle": true + }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -24296,6 +24722,9 @@ "reasoning": true, "functionCalling": true }, + "thinkingOptions": { + "toggle": true + }, "modalities": { "input": ["text"], "output": ["text"] @@ -24315,6 +24744,9 @@ "reasoning": true, "functionCalling": true }, + "thinkingOptions": { + "toggle": true + }, "modalities": { "input": ["text"], "output": ["text"] @@ -24333,6 +24765,9 @@ "reasoning": true, "functionCalling": true }, + "thinkingOptions": { + "toggle": true + }, "modalities": { "input": ["text"], "output": ["text"] @@ -24351,6 +24786,9 @@ "reasoning": true, "functionCalling": true }, + "thinkingOptions": { + "toggle": true + }, "modalities": { "input": ["text"], "output": ["text"] @@ -24369,6 +24807,9 @@ "reasoning": true, "functionCalling": true }, + "thinkingOptions": { + "toggle": true + }, "modalities": { "input": ["text"], "output": ["text"] @@ -24379,7 +24820,7 @@ "description": "Open flagship GLM for long-horizon coding agents and million-token context work", "lifecycle": "active", "contextWindow": 1048576, - "maxOutputTokens": 131072, + "maxOutputTokens": 262144, "structuredOutput": true, "lastUpdated": "2026-06-13", "capabilities": { @@ -24401,7 +24842,7 @@ "description": "Flagship GLM model for hybrid reasoning, coding, and agentic engineering", "lifecycle": "active", "contextWindow": 256000, - "maxOutputTokens": 256000, + "maxOutputTokens": 230400, "structuredOutput": true, "lastUpdated": "2026-06-13", "isFree": true, @@ -24423,9 +24864,9 @@ "displayName": "GLM-5.3", "description": "Flagship GLM model for hybrid reasoning, coding, and agentic engineering", "lifecycle": "active", - "contextWindow": 1048576, + "contextWindow": 1310720, "maxOutputTokens": 131072, - "structuredOutput": false, + "structuredOutput": true, "lastUpdated": "2026-08-14", "capabilities": { "vision": false, @@ -24440,6 +24881,27 @@ "output": ["text"] } }, + "z-ai/glm-5.3-flash": { + "displayName": "GLM-5.3-Flash", + "description": "GLM vision model for visual reasoning, documents, and multimodal agents", + "lifecycle": "active", + "contextWindow": 1310720, + "maxOutputTokens": 131072, + "structuredOutput": true, + "lastUpdated": "2026-08-26", + "capabilities": { + "vision": true, + "reasoning": true, + "functionCalling": true + }, + "thinkingOptions": { + "efforts": ["low", "high", "max"] + }, + "modalities": { + "input": ["text", "image", "video"], + "output": ["text"] + } + }, "z-ai/glm-5v-turbo": { "displayName": "GLM-5V-Turbo", "description": "Fast GLM vision model for screenshots, documents, and multimodal agent tasks", @@ -24453,8 +24915,11 @@ "reasoning": true, "functionCalling": true }, + "thinkingOptions": { + "toggle": true + }, "modalities": { - "input": ["image", "text"], + "input": ["image", "text", "video"], "output": ["text"] } } @@ -25474,7 +25939,7 @@ "efforts": ["low", "medium", "high"] }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -25631,7 +26096,7 @@ "efforts": ["low", "medium", "high"] }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -25750,7 +26215,7 @@ "efforts": ["low", "medium", "high"] }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } } @@ -25818,7 +26283,7 @@ "efforts": ["low", "medium", "high"] }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -25972,7 +26437,7 @@ "contextWindow": 1048576, "maxOutputTokens": 384000, "structuredOutput": true, - "lastUpdated": "2026-08-12", + "lastUpdated": "2026-08-22", "capabilities": { "vision": false, "reasoning": true, @@ -26186,7 +26651,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -26225,7 +26690,7 @@ "efforts": ["low", "high", "max"] }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -26544,6 +27009,48 @@ "input": ["text"], "output": ["text"] } + }, + "zai-org/GLM-5.3": { + "displayName": "GLM-5.3", + "description": "Flagship GLM model for long-horizon coding, agents, and complex project delivery", + "lifecycle": "active", + "contextWindow": 1048576, + "maxOutputTokens": 262144, + "structuredOutput": true, + "lastUpdated": "2026-08-14", + "capabilities": { + "vision": false, + "reasoning": true, + "functionCalling": true + }, + "thinkingOptions": { + "efforts": ["low", "high", "max"] + }, + "modalities": { + "input": ["text"], + "output": ["text"] + } + }, + "zai-org/GLM-5.3-Flash": { + "displayName": "GLM-5.3-Flash", + "description": "Native multimodal GLM model for efficient coding and long-horizon agent tasks", + "lifecycle": "active", + "contextWindow": 1048575, + "maxOutputTokens": 400000, + "structuredOutput": true, + "lastUpdated": "2026-08-26", + "capabilities": { + "vision": true, + "reasoning": true, + "functionCalling": true + }, + "thinkingOptions": { + "efforts": ["low", "high", "max"] + }, + "modalities": { + "input": ["text", "image", "video"], + "output": ["text"] + } } }, "tencent-coding-plan": { @@ -26658,7 +27165,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -26714,7 +27221,28 @@ "functionCalling": true }, "thinkingOptions": { - "efforts": ["low", "medium", "high"], + "efforts": ["none", "high"], + "toggle": true + }, + "modalities": { + "input": ["text"], + "output": ["text"] + } + }, + "hy4-preview": { + "displayName": "Hy4 preview", + "description": "A next-generation productivity model with significantly enhanced Agent and complex task execution capabilities.", + "lifecycle": "active", + "contextWindow": 1024000, + "maxOutputTokens": 64000, + "lastUpdated": "2026-08-28", + "capabilities": { + "vision": false, + "reasoning": true, + "functionCalling": true + }, + "thinkingOptions": { + "efforts": ["none", "high"], "toggle": true }, "modalities": { @@ -26738,7 +27266,7 @@ "functionCalling": true }, "thinkingOptions": { - "efforts": ["low", "medium", "high"], + "efforts": ["none", "high"], "toggle": true }, "modalities": { @@ -26767,6 +27295,27 @@ "input": ["text"], "output": ["text"] } + }, + "hy4-preview": { + "displayName": "Hy4 preview", + "description": "A next-generation productivity model with significantly enhanced Agent and complex task execution capabilities.", + "lifecycle": "active", + "contextWindow": 1024000, + "maxOutputTokens": 64000, + "lastUpdated": "2026-08-28", + "capabilities": { + "vision": false, + "reasoning": true, + "functionCalling": true + }, + "thinkingOptions": { + "efforts": ["none", "high"], + "toggle": true + }, + "modalities": { + "input": ["text"], + "output": ["text"] + } } }, "vercel": { @@ -27306,7 +27855,7 @@ "description": "Open-weight sparse MoE (2.4T total, 95B active), the open-weight twin of Qwen3.8 Max for coding, research, complex reasoning, and agentic workflows", "lifecycle": "active", "contextWindow": 262144, - "maxOutputTokens": 131072, + "maxOutputTokens": 128000, "structuredOutput": true, "lastUpdated": "2026-08-12", "capabilities": { @@ -27343,6 +27892,48 @@ "output": ["text"] } }, + "alibaba/qwen3.8-flash": { + "displayName": "Qwen 3.8 Flash", + "description": "Qwen vision-language model for visual reasoning, documents, and agent tasks", + "lifecycle": "active", + "contextWindow": 991000, + "maxOutputTokens": 128000, + "structuredOutput": true, + "lastUpdated": "2026-08-26", + "capabilities": { + "vision": true, + "reasoning": true, + "functionCalling": true + }, + "thinkingOptions": { + "toggle": true + }, + "modalities": { + "input": ["text", "image", "pdf"], + "output": ["text"] + } + }, + "alibaba/qwen3.8-flash-next": { + "displayName": "Qwen 3.8 Flash Next", + "description": "Open-weight experimental preview of the Qwen4 architecture: hybrid-attention MoE (125B total, 6B active) with vision encoder for coding, agent tasks, and image and video understanding", + "lifecycle": "active", + "contextWindow": 1048576, + "maxOutputTokens": 1048576, + "structuredOutput": true, + "lastUpdated": "2026-08-27", + "capabilities": { + "vision": true, + "reasoning": true, + "functionCalling": true + }, + "thinkingOptions": { + "efforts": ["low", "medium", "xhigh"] + }, + "modalities": { + "input": ["text", "image"], + "output": ["text"] + } + }, "alibaba/qwen3.8-max": { "displayName": "Qwen 3.8 Max", "description": "Preview Qwen flagship for million-token multimodal reasoning and long-horizon agentic workflows", @@ -27377,7 +27968,7 @@ }, "modalities": { "input": ["text"], - "output": [] + "output": ["video"] } }, "alibaba/wan-v2.6-i2v": { @@ -27394,7 +27985,7 @@ }, "modalities": { "input": ["text"], - "output": [] + "output": ["video"] } }, "alibaba/wan-v2.6-i2v-flash": { @@ -27411,7 +28002,7 @@ }, "modalities": { "input": ["text"], - "output": [] + "output": ["video"] } }, "alibaba/wan-v2.6-r2v": { @@ -27428,7 +28019,7 @@ }, "modalities": { "input": ["text"], - "output": [] + "output": ["video"] } }, "alibaba/wan-v2.6-r2v-flash": { @@ -27445,7 +28036,7 @@ }, "modalities": { "input": ["text"], - "output": [] + "output": ["video"] } }, "alibaba/wan-v2.6-t2v": { @@ -27462,7 +28053,7 @@ }, "modalities": { "input": ["text"], - "output": [] + "output": ["video"] } }, "alibaba/wan-v2.7-r2v": { @@ -27479,7 +28070,7 @@ }, "modalities": { "input": ["text"], - "output": [] + "output": ["video"] } }, "alibaba/wan-v2.7-t2v": { @@ -27496,7 +28087,41 @@ }, "modalities": { "input": ["text"], - "output": [] + "output": ["video"] + } + }, + "alibaba/wan-v3.0-video": { + "displayName": "Wan v3.0 Video", + "description": "Video model for prompt-guided generation, editing, and motion workflows", + "lifecycle": "active", + "contextWindow": 0, + "maxOutputTokens": 0, + "lastUpdated": "2026-08-23", + "capabilities": { + "vision": true, + "reasoning": false, + "functionCalling": false + }, + "modalities": { + "input": ["text", "image"], + "output": ["video"] + } + }, + "alibaba/wan-v3.0-video-prime": { + "displayName": "Wan v3.0 Video Prime", + "description": "Video model for prompt-guided generation, editing, and motion workflows", + "lifecycle": "active", + "contextWindow": 0, + "maxOutputTokens": 0, + "lastUpdated": "2026-08-28", + "capabilities": { + "vision": true, + "reasoning": false, + "functionCalling": false + }, + "modalities": { + "input": ["text", "image"], + "output": ["video"] } }, "amazon/nova-2-lite": { @@ -27535,7 +28160,7 @@ "functionCalling": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -27571,7 +28196,7 @@ "functionCalling": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -27920,24 +28545,6 @@ "output": ["text"] } }, - "arcee-ai/trinity-mini": { - "displayName": "Trinity Mini", - "description": "Reasoning-tuned 26B MoE model with 3B active parameters for agents, tools, and multi-step workloads", - "lifecycle": "active", - "contextWindow": 131072, - "maxOutputTokens": 131072, - "knowledgeCutoff": "2024-10", - "lastUpdated": "2025-12", - "capabilities": { - "vision": false, - "reasoning": false, - "functionCalling": false - }, - "modalities": { - "input": ["text"], - "output": ["text"] - } - }, "bfl/flux-2-flex": { "displayName": "FLUX.2 [flex]", "description": "Image model for prompt-driven generation, editing, and visual design workflows", @@ -28037,7 +28644,7 @@ }, "modalities": { "input": ["text"], - "output": [] + "output": ["video"] } }, "bfl/flux-kontext-max": { @@ -28182,7 +28789,7 @@ }, "modalities": { "input": ["text", "image"], - "output": [] + "output": ["video"] } }, "bytedance/seedance-2.0-fast": { @@ -28199,7 +28806,24 @@ }, "modalities": { "input": ["text", "image"], - "output": [] + "output": ["video"] + } + }, + "bytedance/seedance-2.0-mini": { + "displayName": "Seedance 2.0 Mini", + "description": "Video model for prompt-guided generation, editing, and motion workflows", + "lifecycle": "active", + "contextWindow": 0, + "maxOutputTokens": 0, + "lastUpdated": "2026-06-22", + "capabilities": { + "vision": true, + "reasoning": false, + "functionCalling": false + }, + "modalities": { + "input": ["text", "image"], + "output": ["video"] } }, "bytedance/seedance-2.5": { @@ -28216,7 +28840,7 @@ }, "modalities": { "input": ["text"], - "output": [] + "output": ["video"] } }, "bytedance/seedance-v1.0-pro": { @@ -28233,7 +28857,7 @@ }, "modalities": { "input": ["text"], - "output": [] + "output": ["video"] } }, "bytedance/seedance-v1.0-pro-fast": { @@ -28250,7 +28874,7 @@ }, "modalities": { "input": ["text"], - "output": [] + "output": ["video"] } }, "bytedance/seedance-v1.5-pro": { @@ -28267,7 +28891,7 @@ }, "modalities": { "input": ["text"], - "output": [] + "output": ["video"] } }, "bytedance/seedream-4.0": { @@ -28579,12 +29203,34 @@ "output": ["text"] } }, + "deepseek/deepseek-v4-flash-vision-exp": { + "displayName": "DeepSeek V4 Flash Vision Exp", + "description": "Experimental multimodal DeepSeek V4 Flash model for image understanding, coding, and agentic work", + "lifecycle": "active", + "contextWindow": 1000000, + "maxOutputTokens": 384000, + "structuredOutput": true, + "lastUpdated": "2026-08-21", + "capabilities": { + "vision": true, + "reasoning": true, + "functionCalling": true + }, + "thinkingOptions": { + "efforts": ["high", "xhigh"], + "toggle": true + }, + "modalities": { + "input": ["text", "image"], + "output": ["text"] + } + }, "deepseek/deepseek-v4-pro": { "displayName": "DeepSeek V4 Pro", "description": "Open MoE flagship with million-token context for coding and long agent runs", "lifecycle": "active", - "contextWindow": 1048600, - "maxOutputTokens": 1048600, + "contextWindow": 1000000, + "maxOutputTokens": 384000, "knowledgeCutoff": "2025-05", "structuredOutput": true, "lastUpdated": "2026-04-24", @@ -28609,7 +29255,7 @@ "contextWindow": 1000000, "maxOutputTokens": 384000, "structuredOutput": true, - "lastUpdated": "2026-08-12", + "lastUpdated": "2026-08-22", "capabilities": { "vision": false, "reasoning": true, @@ -28778,7 +29424,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image", "audio", "pdf"], + "input": ["text", "image", "audio", "video", "pdf"], "output": ["text"] } }, @@ -28837,7 +29483,7 @@ "functionCalling": true }, "modalities": { - "input": ["text", "image", "audio", "pdf"], + "input": ["text", "image", "audio", "video", "pdf"], "output": ["text"] } }, @@ -29029,6 +29675,40 @@ "output": ["text"] } }, + "google/gemini-3.5-transcribe": { + "displayName": "Gemini 3.5 Transcribe", + "description": "Speech transcription model for accurate audio-to-text and captioning workflows", + "lifecycle": "active", + "contextWindow": 0, + "maxOutputTokens": 0, + "lastUpdated": "2026-08-26", + "capabilities": { + "vision": false, + "reasoning": false, + "functionCalling": false + }, + "modalities": { + "input": ["audio"], + "output": ["text"] + } + }, + "google/gemini-3.5-transcribe-live": { + "displayName": "Gemini 3.5 Transcribe Live", + "description": "Speech transcription model for accurate audio-to-text and captioning workflows", + "lifecycle": "active", + "contextWindow": 0, + "maxOutputTokens": 0, + "lastUpdated": "2026-08-26", + "capabilities": { + "vision": false, + "reasoning": false, + "functionCalling": false + }, + "modalities": { + "input": ["audio"], + "output": ["text"] + } + }, "google/gemini-3.6-flash": { "displayName": "Gemini 3.6 Flash", "description": "Fast Gemini model balancing multimodal reasoning, tool use, and cost", @@ -29210,7 +29890,7 @@ }, "modalities": { "input": ["text"], - "output": [] + "output": ["video"] } }, "google/veo-3.0-generate-001": { @@ -29227,7 +29907,7 @@ }, "modalities": { "input": ["text"], - "output": [] + "output": ["video"] } }, "google/veo-3.1-fast-generate-001": { @@ -29244,7 +29924,7 @@ }, "modalities": { "input": ["text"], - "output": [] + "output": ["video"] } }, "google/veo-3.1-generate-001": { @@ -29261,7 +29941,7 @@ }, "modalities": { "input": ["text"], - "output": [] + "output": ["video"] } }, "google/veo-3.1-lite-generate-001": { @@ -29278,7 +29958,7 @@ }, "modalities": { "input": ["text"], - "output": [] + "output": ["video"] } }, "inception/mercury-2": { @@ -29335,6 +30015,48 @@ "output": ["text"] } }, + "inclusionai/ling-3.0-flash-fin": { + "displayName": "Ling 3.0 Flash Fin", + "description": "Finance-enhanced model for financial research, multi-step investment workflows, and long-horizon planning and execution", + "lifecycle": "active", + "contextWindow": 256000, + "maxOutputTokens": 32000, + "lastUpdated": "2026-08-27", + "isFree": true, + "capabilities": { + "vision": false, + "reasoning": true, + "functionCalling": true + }, + "thinkingOptions": { + "toggle": true + }, + "modalities": { + "input": ["text"], + "output": ["text"] + } + }, + "inclusionai/ling-3.0-flash-fin-free": { + "displayName": "Ling 3.0 Flash Fin (Free)", + "description": "Finance-enhanced model for financial research, multi-step investment workflows, and long-horizon planning and execution", + "lifecycle": "active", + "contextWindow": 256000, + "maxOutputTokens": 32000, + "lastUpdated": "2026-08-27", + "isFree": true, + "capabilities": { + "vision": false, + "reasoning": true, + "functionCalling": true + }, + "thinkingOptions": { + "toggle": true + }, + "modalities": { + "input": ["text"], + "output": ["text"] + } + }, "interfaze/interfaze-beta": { "displayName": "Interfaze Beta", "description": "Multimodal reasoning model for visual analysis, planning, and tool use", @@ -29369,7 +30091,7 @@ }, "modalities": { "input": ["text"], - "output": [] + "output": ["video"] } }, "klingai/kling-v2.5-turbo-t2v": { @@ -29386,7 +30108,7 @@ }, "modalities": { "input": ["text"], - "output": [] + "output": ["video"] } }, "klingai/kling-v2.6-i2v": { @@ -29403,7 +30125,7 @@ }, "modalities": { "input": ["text"], - "output": [] + "output": ["video"] } }, "klingai/kling-v2.6-motion-control": { @@ -29420,7 +30142,7 @@ }, "modalities": { "input": ["text"], - "output": [] + "output": ["video"] } }, "klingai/kling-v2.6-t2v": { @@ -29437,7 +30159,7 @@ }, "modalities": { "input": ["text"], - "output": [] + "output": ["video"] } }, "klingai/kling-v3.0-i2v": { @@ -29454,7 +30176,7 @@ }, "modalities": { "input": ["text"], - "output": [] + "output": ["video"] } }, "klingai/kling-v3.0-motion-control": { @@ -29471,7 +30193,7 @@ }, "modalities": { "input": ["text"], - "output": [] + "output": ["video"] } }, "klingai/kling-v3.0-t2v": { @@ -29488,7 +30210,7 @@ }, "modalities": { "input": ["text"], - "output": [] + "output": ["video"] } }, "kwaipilot/kat-coder-air-v2.5": { @@ -29675,6 +30397,23 @@ "output": ["text"] } }, + "meta/muse-image-1.0": { + "displayName": "Muse Image 1.0", + "description": "Image model for prompt-driven generation, editing, and visual design workflows", + "lifecycle": "active", + "contextWindow": 0, + "maxOutputTokens": 0, + "lastUpdated": "2026-08-26", + "capabilities": { + "vision": true, + "reasoning": false, + "functionCalling": false + }, + "modalities": { + "input": ["text", "image"], + "output": ["image"] + } + }, "meta/muse-spark-1.1": { "displayName": "Muse Spark 1.1", "description": "Open Llama instruction model for multilingual chat, reasoning, and coding", @@ -29745,7 +30484,24 @@ }, "modalities": { "input": ["text", "image"], - "output": [] + "output": ["video"] + } + }, + "minimax/minimax-h3-max": { + "displayName": "MiniMax H3 Max", + "description": "Video model for prompt-guided generation, editing, and motion workflows", + "lifecycle": "active", + "contextWindow": 0, + "maxOutputTokens": 0, + "lastUpdated": "2026-08-27", + "capabilities": { + "vision": true, + "reasoning": false, + "functionCalling": false + }, + "modalities": { + "input": ["text", "image"], + "output": ["video"] } }, "minimax/minimax-m2": { @@ -29852,6 +30608,24 @@ "output": ["text"] } }, + "minimax/minimax-m2.7-free": { + "displayName": "Minimax M2.7 (Free)", + "description": "Open MiniMax flagship for coding agents, office automation, and complex environments", + "lifecycle": "active", + "contextWindow": 196608, + "maxOutputTokens": 196608, + "lastUpdated": "2026-03-18", + "isFree": true, + "capabilities": { + "vision": false, + "reasoning": true, + "functionCalling": true + }, + "modalities": { + "input": ["text"], + "output": ["text"] + } + }, "minimax/minimax-m2.7-highspeed": { "displayName": "MiniMax M2.7 High Speed", "description": "Low-latency M2.7 variant for interactive coding plans and agent loops", @@ -29873,8 +30647,8 @@ "displayName": "MiniMax M3", "description": "MiniMax multimodal model for long-context coding, perception, and agent planning", "lifecycle": "active", - "contextWindow": 1000000, - "maxOutputTokens": 1000000, + "contextWindow": 512000, + "maxOutputTokens": 512000, "lastUpdated": "2026-06-01", "capabilities": { "vision": true, @@ -29889,6 +30663,27 @@ "output": ["text"] } }, + "minimax/minimax-m3-free": { + "displayName": "MiniMax M3 (Free)", + "description": "MiniMax multimodal model for long-context coding, perception, and agent planning", + "lifecycle": "active", + "contextWindow": 1048576, + "maxOutputTokens": 1048576, + "lastUpdated": "2026-06-01", + "isFree": true, + "capabilities": { + "vision": true, + "reasoning": true, + "functionCalling": true + }, + "thinkingOptions": { + "toggle": true + }, + "modalities": { + "input": ["text", "image"], + "output": ["text"] + } + }, "mistral/codestral": { "displayName": "Codestral (latest)", "description": "Mistral code model for completions, refactors, and developer IDE workflows", @@ -29960,42 +30755,6 @@ "output": ["text"] } }, - "mistral/magistral-medium": { - "displayName": "Magistral Medium (latest)", - "description": "Mistral reasoning model for transparent analysis, math, and complex decisions", - "lifecycle": "active", - "contextWindow": 128000, - "maxOutputTokens": 16384, - "knowledgeCutoff": "2025-06", - "lastUpdated": "2025-03-20", - "capabilities": { - "vision": false, - "reasoning": true, - "functionCalling": true - }, - "modalities": { - "input": ["text"], - "output": ["text"] - } - }, - "mistral/magistral-small": { - "displayName": "Magistral Small", - "description": "Mistral reasoning model for transparent analysis, math, and complex decisions", - "lifecycle": "active", - "contextWindow": 128000, - "maxOutputTokens": 128000, - "knowledgeCutoff": "2025-06", - "lastUpdated": "2025-03-17", - "capabilities": { - "vision": false, - "reasoning": true, - "functionCalling": true - }, - "modalities": { - "input": ["text"], - "output": ["text"] - } - }, "mistral/ministral-14b": { "displayName": "Ministral 14B", "description": "Compact Mistral model for edge, latency-sensitive, and cost-efficient workloads", @@ -30722,26 +31481,6 @@ "output": ["text"] } }, - "openai/gpt-4o-mini-search-preview": { - "displayName": "GPT 4o Mini Search Preview", - "description": "Compact GPT model for low-latency assistance and high-volume workloads", - "lifecycle": "active", - "contextWindow": 128000, - "inputLimit": 111616, - "maxOutputTokens": 16384, - "knowledgeCutoff": "2023-09", - "structuredOutput": false, - "lastUpdated": "2025-01", - "capabilities": { - "vision": false, - "reasoning": false, - "functionCalling": false - }, - "modalities": { - "input": ["text"], - "output": ["text"] - } - }, "openai/gpt-4o-mini-transcribe": { "displayName": "GPT-4o mini Transcribe", "description": "Speech transcription model for accurate audio-to-text and captioning workflows", @@ -30814,6 +31553,9 @@ "reasoning": true, "functionCalling": true }, + "thinkingOptions": { + "efforts": ["low", "medium", "high"] + }, "modalities": { "input": ["text", "image", "pdf"], "output": ["text"] @@ -31639,13 +32381,35 @@ "output": ["text"] } }, + "openai/gpt-oss-safeguard-120b": { + "displayName": "GPT OSS Safeguard 120B", + "description": "Safety model for policy screening, moderation, and risk-aware routing workflows", + "lifecycle": "active", + "contextWindow": 128000, + "inputLimit": 112000, + "maxOutputTokens": 16000, + "structuredOutput": true, + "lastUpdated": "2025-10-29", + "capabilities": { + "vision": false, + "reasoning": true, + "functionCalling": true + }, + "thinkingOptions": { + "efforts": ["low", "medium", "high"] + }, + "modalities": { + "input": ["text"], + "output": ["text"] + } + }, "openai/gpt-oss-safeguard-20b": { "displayName": "gpt-oss-safeguard-20b", "description": "Safety model for policy screening, moderation, and risk-aware routing workflows", "lifecycle": "active", - "contextWindow": 131072, - "inputLimit": 65536, - "maxOutputTokens": 65536, + "contextWindow": 128000, + "inputLimit": 112000, + "maxOutputTokens": 16000, "knowledgeCutoff": "2024-10", "lastUpdated": "2024-12-01", "capabilities": { @@ -31796,28 +32560,6 @@ "output": ["text"] } }, - "openai/o3-deep-research": { - "displayName": "o3-deep-research", - "description": "Research model for long-horizon investigation, synthesis, and analytical reports", - "lifecycle": "active", - "contextWindow": 200000, - "inputLimit": 100000, - "maxOutputTokens": 100000, - "knowledgeCutoff": "2024-05", - "lastUpdated": "2024-06-26", - "capabilities": { - "vision": true, - "reasoning": true, - "functionCalling": true - }, - "thinkingOptions": { - "efforts": ["medium"] - }, - "modalities": { - "input": ["text", "image", "pdf"], - "output": ["text"] - } - }, "openai/o3-fast": { "displayName": "o3 (Fast)", "description": "Deliberate o-series reasoner for hard math, coding, and multi-step analysis", @@ -32517,12 +33259,16 @@ "lifecycle": "active", "contextWindow": 1000000, "maxOutputTokens": 1000000, - "lastUpdated": "2026-04-30", + "structuredOutput": true, + "lastUpdated": "2026-04-17", "capabilities": { "vision": true, "reasoning": true, "functionCalling": true }, + "thinkingOptions": { + "efforts": ["low", "medium", "high"] + }, "modalities": { "input": ["text", "image", "pdf"], "output": ["text"] @@ -32534,12 +33280,16 @@ "lifecycle": "active", "contextWindow": 500000, "maxOutputTokens": 500000, + "structuredOutput": true, "lastUpdated": "2026-07-08", "capabilities": { "vision": true, "reasoning": true, "functionCalling": true }, + "thinkingOptions": { + "efforts": ["low", "medium", "high"] + }, "modalities": { "input": ["text", "image", "pdf"], "output": ["text"] @@ -32551,12 +33301,17 @@ "lifecycle": "active", "contextWindow": 500000, "maxOutputTokens": 500000, + "knowledgeCutoff": "2026-02-01", + "structuredOutput": true, "lastUpdated": "2026-08-12", "capabilities": { "vision": true, "reasoning": true, "functionCalling": true }, + "thinkingOptions": { + "efforts": ["low", "medium", "high"] + }, "modalities": { "input": ["text", "image"], "output": ["text"] @@ -32568,7 +33323,8 @@ "lifecycle": "active", "contextWindow": 256000, "maxOutputTokens": 256000, - "lastUpdated": "2026-05-20", + "structuredOutput": true, + "lastUpdated": "2026-04-16", "capabilities": { "vision": true, "reasoning": true, @@ -32627,7 +33383,7 @@ }, "modalities": { "input": ["text"], - "output": [] + "output": ["video"] } }, "spacexai/grok-imagine-video-1.5": { @@ -32636,7 +33392,7 @@ "lifecycle": "active", "contextWindow": 0, "maxOutputTokens": 0, - "lastUpdated": "2026-06-22", + "lastUpdated": "2026-05-30", "capabilities": { "vision": false, "reasoning": false, @@ -32644,7 +33400,7 @@ }, "modalities": { "input": ["text"], - "output": [] + "output": ["video"] } }, "spacexai/grok-imagine-video-1.5-preview": { @@ -32661,7 +33417,7 @@ }, "modalities": { "input": ["text"], - "output": [] + "output": ["video"] } }, "spacexai/grok-stt": { @@ -32830,8 +33586,8 @@ "displayName": "Hy3", "description": "Tencent Hy reasoning model for coding, instruction following, and agent tasks", "lifecycle": "active", - "contextWindow": 256000, - "maxOutputTokens": 128000, + "contextWindow": 262144, + "maxOutputTokens": 262144, "lastUpdated": "2026-07-06", "capabilities": { "vision": false, @@ -32846,6 +33602,26 @@ "output": ["text"] } }, + "tencent/hy4-preview": { + "displayName": "Tencent Hy4 Preview", + "description": "A next-generation productivity model with significantly enhanced Agent and complex task execution capabilities.", + "lifecycle": "active", + "contextWindow": 1024000, + "maxOutputTokens": 64000, + "lastUpdated": "2026-08-28", + "capabilities": { + "vision": false, + "reasoning": true, + "functionCalling": true + }, + "thinkingOptions": { + "efforts": ["none", "high"] + }, + "modalities": { + "input": ["text"], + "output": ["text"] + } + }, "thinkingmachines/inkling": { "displayName": "Inkling", "description": "Multimodal MoE reasoning model (975B total, 41B active) for text, image, and audio", @@ -33132,6 +33908,27 @@ "output": ["text"] } }, + "xiaomi/mimo-v2.5-pro-ultraspeed": { + "displayName": "MiMo V2.5 Pro UltraSpeed", + "description": "MiMo pro model for strong multimodal reasoning and agent execution", + "lifecycle": "active", + "contextWindow": 1048576, + "maxOutputTokens": 131072, + "knowledgeCutoff": "2024-12", + "lastUpdated": "2026-06-09", + "capabilities": { + "vision": false, + "reasoning": true, + "functionCalling": true + }, + "thinkingOptions": { + "toggle": true + }, + "modalities": { + "input": ["text"], + "output": ["text"] + } + }, "zai/glm-4.5": { "displayName": "GLM 4.5", "description": "Hybrid-reasoning GLM release that made the 4.5 line broadly useful", @@ -33390,7 +34187,7 @@ "description": "Flagship GLM model for long-horizon coding, agents, and complex project delivery", "lifecycle": "active", "contextWindow": 1000000, - "maxOutputTokens": 12800, + "maxOutputTokens": 1000000, "structuredOutput": true, "lastUpdated": "2026-08-14", "capabilities": { @@ -33406,6 +34203,27 @@ "output": ["text"] } }, + "zai/glm-5.3-flash": { + "displayName": "GLM 5.3 Flash", + "description": "Native multimodal GLM model for efficient coding and long-horizon agent tasks", + "lifecycle": "active", + "contextWindow": 1000000, + "maxOutputTokens": 131000, + "structuredOutput": true, + "lastUpdated": "2026-08-26", + "capabilities": { + "vision": true, + "reasoning": true, + "functionCalling": true + }, + "thinkingOptions": { + "efforts": ["low", "high", "max"] + }, + "modalities": { + "input": ["text", "image"], + "output": ["text"] + } + }, "zai/glm-5v-turbo": { "displayName": "GLM 5V Turbo", "description": "Fast GLM vision model for screenshots, documents, and multimodal agent tasks", @@ -33581,7 +34399,7 @@ }, "modalities": { "input": ["text", "image", "pdf"], - "output": ["image"] + "output": ["image", "pdf"] } }, "grok-imagine-image-2.0": { @@ -33598,7 +34416,7 @@ }, "modalities": { "input": ["text", "image", "pdf"], - "output": ["image"] + "output": ["image", "pdf"] } }, "grok-imagine-image-quality": { @@ -33615,7 +34433,7 @@ }, "modalities": { "input": ["text", "image", "pdf"], - "output": ["image"] + "output": ["image", "pdf"] } }, "grok-imagine-video": { @@ -33631,8 +34449,8 @@ "functionCalling": false }, "modalities": { - "input": ["text", "image", "pdf"], - "output": [] + "input": ["text", "image", "video", "pdf"], + "output": ["video"] } }, "grok-imagine-video-1.5": { @@ -33649,7 +34467,7 @@ }, "modalities": { "input": ["text", "image", "audio", "pdf"], - "output": [] + "output": ["video"] } } }, @@ -33692,7 +34510,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image", "audio", "pdf"], + "input": ["text", "image", "audio", "video", "pdf"], "output": ["text"] } }, @@ -33734,7 +34552,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image", "audio"], + "input": ["text", "image", "audio", "video"], "output": ["text"] } }, @@ -33840,7 +34658,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image", "audio"], + "input": ["text", "image", "audio", "video"], "output": ["text"] } }, @@ -33980,7 +34798,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image", "audio"], + "input": ["text", "image", "audio", "video"], "output": ["text"] } }, @@ -34120,7 +34938,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image", "audio"], + "input": ["text", "image", "audio", "video"], "output": ["text"] } }, @@ -34283,7 +35101,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -34325,7 +35143,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -34476,6 +35294,48 @@ "output": ["text"] } }, + "glm-5.3": { + "displayName": "GLM-5.3", + "description": "Flagship GLM model for long-horizon coding, agents, and complex project delivery", + "lifecycle": "active", + "contextWindow": 1000000, + "maxOutputTokens": 131072, + "structuredOutput": true, + "lastUpdated": "2026-08-14", + "capabilities": { + "vision": false, + "reasoning": true, + "functionCalling": true + }, + "thinkingOptions": { + "efforts": ["low", "high", "max"] + }, + "modalities": { + "input": ["text"], + "output": ["text"] + } + }, + "glm-5.3-flash": { + "displayName": "GLM-5.3-Flash", + "description": "Native multimodal GLM model for efficient coding and long-horizon agent tasks", + "lifecycle": "active", + "contextWindow": 1000000, + "maxOutputTokens": 131072, + "structuredOutput": true, + "lastUpdated": "2026-08-26", + "capabilities": { + "vision": true, + "reasoning": true, + "functionCalling": true + }, + "thinkingOptions": { + "efforts": ["low", "high", "max"] + }, + "modalities": { + "input": ["text", "image", "video", "pdf"], + "output": ["text"] + } + }, "glm-5v-turbo": { "displayName": "GLM-5V-Turbo", "description": "Fast GLM vision model for screenshots, documents, and multimodal agent tasks", @@ -34492,7 +35352,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image", "pdf"], + "input": ["text", "image", "video", "pdf"], "output": ["text"] } } @@ -34607,6 +35467,50 @@ "input": ["text"], "output": ["text"] } + }, + "glm-5.3-flash": { + "displayName": "GLM-5.3-Flash", + "description": "Native multimodal GLM model for efficient coding and long-horizon agent tasks", + "lifecycle": "active", + "contextWindow": 1000000, + "maxOutputTokens": 131072, + "structuredOutput": true, + "lastUpdated": "2026-08-26", + "isFree": true, + "capabilities": { + "vision": true, + "reasoning": true, + "functionCalling": true + }, + "thinkingOptions": { + "efforts": ["low", "high", "max"] + }, + "modalities": { + "input": ["text", "image", "video", "pdf"], + "output": ["text"] + } + }, + "glm-5.3-highspeed": { + "displayName": "GLM-5.3 Highspeed", + "description": "Flagship GLM model for long-horizon coding, agents, and complex project delivery", + "lifecycle": "active", + "contextWindow": 1000000, + "maxOutputTokens": 131072, + "structuredOutput": true, + "lastUpdated": "2026-08-14", + "isFree": true, + "capabilities": { + "vision": false, + "reasoning": true, + "functionCalling": true + }, + "thinkingOptions": { + "efforts": ["low", "high", "max"] + }, + "modalities": { + "input": ["text"], + "output": ["text"] + } } }, "zenmux": { @@ -34934,7 +35838,7 @@ "functionCalling": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -35100,7 +36004,7 @@ "efforts": ["low", "medium", "high"] }, "modalities": { - "input": ["pdf", "image", "text", "audio"], + "input": ["pdf", "image", "text", "audio", "video"], "output": ["text"] } }, @@ -35143,7 +36047,7 @@ "efforts": ["low", "medium", "high"] }, "modalities": { - "input": ["text", "image", "audio", "pdf"], + "input": ["text", "image", "video", "audio", "pdf"], "output": ["text"] } }, @@ -35160,7 +36064,7 @@ "functionCalling": true }, "modalities": { - "input": ["text", "image", "audio"], + "input": ["text", "image", "audio", "video"], "output": ["text"] } }, @@ -35181,7 +36085,7 @@ "efforts": ["low", "medium", "high"] }, "modalities": { - "input": ["text", "image", "pdf", "audio"], + "input": ["text", "image", "pdf", "audio", "video"], "output": ["text"] } }, @@ -35203,7 +36107,7 @@ "efforts": ["low", "medium", "high"] }, "modalities": { - "input": ["text", "image", "audio", "pdf"], + "input": ["text", "image", "video", "audio", "pdf"], "output": ["text"] } }, @@ -35390,8 +36294,8 @@ "displayName": "MiniMax-M3", "description": "MiniMax multimodal model for long-context coding, perception, and agent planning", "lifecycle": "active", - "contextWindow": 512000, - "maxOutputTokens": 128000, + "contextWindow": 1048576, + "maxOutputTokens": 512000, "lastUpdated": "2026-06-01", "capabilities": { "vision": true, @@ -35402,7 +36306,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -35477,7 +36381,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -35498,7 +36402,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -35517,7 +36421,7 @@ "functionCalling": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -35537,7 +36441,7 @@ "functionCalling": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -35559,7 +36463,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -35582,7 +36486,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -36159,7 +37063,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -36251,7 +37155,7 @@ "efforts": ["low", "medium", "high"] }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -36274,7 +37178,7 @@ "efforts": ["low", "medium", "high"] }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -36315,7 +37219,7 @@ "efforts": ["low", "medium", "high"] }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -36354,7 +37258,7 @@ "efforts": ["low", "medium", "high"] }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -36375,7 +37279,7 @@ "efforts": ["low", "medium", "high"] }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -36396,7 +37300,7 @@ "efforts": ["low", "medium", "high"] }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -36513,7 +37417,7 @@ "functionCalling": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -36531,7 +37435,7 @@ "functionCalling": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -36651,7 +37555,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image", "audio", "pdf"], + "input": ["text", "image", "audio", "video", "pdf"], "output": ["text"] } }, @@ -36693,7 +37597,7 @@ "toggle": true }, "modalities": { - "input": ["text", "image", "audio"], + "input": ["text", "image", "audio", "video"], "output": ["text"] } }, @@ -36792,7 +37696,7 @@ "functionCalling": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -36810,7 +37714,7 @@ "functionCalling": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -36829,7 +37733,7 @@ "functionCalling": true }, "modalities": { - "input": ["text", "image"], + "input": ["text", "image", "video"], "output": ["text"] } }, @@ -37001,7 +37905,7 @@ "functionCalling": true }, "modalities": { - "input": ["text", "image", "pdf"], + "input": ["text", "image", "video", "pdf"], "output": ["text"] } } @@ -37237,16 +38141,6 @@ "inputUsdPer1M": 0.035, "outputUsdPer1M": 0.035 }, - { - "modelKey": "alibaba:qwen3-coder-30b-a3b-instruct", - "inputUsdPer1M": 0.45, - "outputUsdPer1M": 2.25 - }, - { - "modelKey": "alibaba:qwen3-coder-480b-a35b-instruct", - "inputUsdPer1M": 1.5, - "outputUsdPer1M": 7.5 - }, { "modelKey": "alibaba:qwen3-coder-flash", "inputUsdPer1M": 0.3, @@ -37357,6 +38251,13 @@ "cacheReadUsdPer1M": 0.5, "cacheWriteUsdPer1M": 3.125 }, + { + "modelKey": "alibaba:qwen3.8-flash", + "inputUsdPer1M": 0.15, + "outputUsdPer1M": 0.47, + "cacheReadUsdPer1M": 0.016, + "cacheWriteUsdPer1M": 0.2 + }, { "modelKey": "alibaba:qwen3.8-max", "inputUsdPer1M": 2, @@ -37436,17 +38337,6 @@ "outputUsdPer1M": 0.87, "cacheReadUsdPer1M": 0.003625 }, - { - "modelKey": "alibaba-cn:glm-5", - "inputUsdPer1M": 0.86, - "outputUsdPer1M": 3.15 - }, - { - "modelKey": "alibaba-cn:glm-5.1", - "inputUsdPer1M": 0.87, - "outputUsdPer1M": 3.48, - "cacheReadUsdPer1M": 0.17 - }, { "modelKey": "alibaba-cn:glm-5.2", "inputUsdPer1M": 1.1, @@ -37555,7 +38445,9 @@ { "modelKey": "alibaba-cn:qwen-plus", "inputUsdPer1M": 0.115, - "outputUsdPer1M": 0.287 + "outputUsdPer1M": 0.287, + "cacheReadUsdPer1M": 0.012, + "cacheWriteUsdPer1M": 0.144 }, { "modelKey": "alibaba-cn:qwen-plus-character", @@ -37662,16 +38554,6 @@ "inputUsdPer1M": 0.032, "outputUsdPer1M": 0.032 }, - { - "modelKey": "alibaba-cn:qwen3-coder-30b-a3b-instruct", - "inputUsdPer1M": 0.216, - "outputUsdPer1M": 0.861 - }, - { - "modelKey": "alibaba-cn:qwen3-coder-480b-a35b-instruct", - "inputUsdPer1M": 0.861, - "outputUsdPer1M": 3.441 - }, { "modelKey": "alibaba-cn:qwen3-coder-flash", "inputUsdPer1M": 0.144, @@ -37722,11 +38604,6 @@ "inputUsdPer1M": 0.143353, "outputUsdPer1M": 1.433525 }, - { - "modelKey": "alibaba-cn:qwen3.5-397b-a17b", - "inputUsdPer1M": 0.43, - "outputUsdPer1M": 2.58 - }, { "modelKey": "alibaba-cn:qwen3.5-flash", "inputUsdPer1M": 0.172, @@ -37756,6 +38633,13 @@ "cacheReadUsdPer1M": 0.5, "cacheWriteUsdPer1M": 3.125 }, + { + "modelKey": "alibaba-cn:qwen3.8-flash", + "inputUsdPer1M": 0.11875, + "outputUsdPer1M": 0.40073, + "cacheReadUsdPer1M": 0.01187, + "cacheWriteUsdPer1M": 0.14844 + }, { "modelKey": "alibaba-cn:qwen3.8-max", "inputUsdPer1M": 1.77744, @@ -37989,6 +38873,18 @@ "outputUsdPer1M": 4.4, "cacheReadUsdPer1M": 0.26 }, + { + "modelKey": "cloudflare-workers-ai:@cf/zai-org/glm-5.3", + "inputUsdPer1M": 1.4, + "outputUsdPer1M": 4.4, + "cacheReadUsdPer1M": 0.26 + }, + { + "modelKey": "cloudflare-workers-ai:@cf/zai-org/glm-5.3-flash", + "inputUsdPer1M": 0.15, + "outputUsdPer1M": 0.5, + "cacheReadUsdPer1M": 0.03 + }, { "modelKey": "deepinfra:deepseek-ai/DeepSeek-R1-0528", "inputUsdPer1M": 0.5, @@ -38300,19 +39196,25 @@ "cacheReadUsdPer1M": 0.14 }, { - "modelKey": "deepseek:deepseek-chat", - "inputUsdPer1M": 0.14, - "outputUsdPer1M": 0.28, - "cacheReadUsdPer1M": 0.0028 + "modelKey": "deepinfra:zai-org/GLM-5.3", + "inputUsdPer1M": 1.2, + "outputUsdPer1M": 4, + "cacheReadUsdPer1M": 0.12 + }, + { + "modelKey": "deepinfra:zai-org/GLM-5.3-Flash", + "inputUsdPer1M": 0.15, + "outputUsdPer1M": 0.5, + "cacheReadUsdPer1M": 0.03 }, { - "modelKey": "deepseek:deepseek-reasoner", + "modelKey": "deepseek:deepseek-v4-flash", "inputUsdPer1M": 0.14, "outputUsdPer1M": 0.28, "cacheReadUsdPer1M": 0.0028 }, { - "modelKey": "deepseek:deepseek-v4-flash", + "modelKey": "deepseek:deepseek-v4-flash-vision-exp", "inputUsdPer1M": 0.14, "outputUsdPer1M": 0.28, "cacheReadUsdPer1M": 0.0028 @@ -38323,24 +39225,12 @@ "outputUsdPer1M": 0.87, "cacheReadUsdPer1M": 0.003625 }, - { - "modelKey": "fireworks-ai:accounts/fireworks/models/deepseek-v4-flash", - "inputUsdPer1M": 0.14, - "outputUsdPer1M": 0.28, - "cacheReadUsdPer1M": 0.028 - }, { "modelKey": "fireworks-ai:accounts/fireworks/models/deepseek-v4-flash-0731", "inputUsdPer1M": 0.14, "outputUsdPer1M": 0.28, "cacheReadUsdPer1M": 0.028 }, - { - "modelKey": "fireworks-ai:accounts/fireworks/models/deepseek-v4-pro", - "inputUsdPer1M": 1.74, - "outputUsdPer1M": 3.48, - "cacheReadUsdPer1M": 0.145 - }, { "modelKey": "fireworks-ai:accounts/fireworks/models/deepseek-v4-pro-0813", "inputUsdPer1M": 1.32, @@ -38353,18 +39243,24 @@ "outputUsdPer1M": 4.4, "cacheReadUsdPer1M": 0.14 }, + { + "modelKey": "fireworks-ai:accounts/fireworks/models/glm-5p3", + "inputUsdPer1M": 1.4, + "outputUsdPer1M": 4.4, + "cacheReadUsdPer1M": 0.26 + }, + { + "modelKey": "fireworks-ai:accounts/fireworks/models/glm-5p3-flash", + "inputUsdPer1M": 0.15, + "outputUsdPer1M": 0.5, + "cacheReadUsdPer1M": 0.029 + }, { "modelKey": "fireworks-ai:accounts/fireworks/models/gpt-oss-120b", "inputUsdPer1M": 0.15, "outputUsdPer1M": 0.6, "cacheReadUsdPer1M": 0.015 }, - { - "modelKey": "fireworks-ai:accounts/fireworks/models/gpt-oss-20b", - "inputUsdPer1M": 0.07, - "outputUsdPer1M": 0.3, - "cacheReadUsdPer1M": 0.035 - }, { "modelKey": "fireworks-ai:accounts/fireworks/models/inkling", "inputUsdPer1M": 1, @@ -38389,12 +39285,6 @@ "outputUsdPer1M": 15, "cacheReadUsdPer1M": 0.3 }, - { - "modelKey": "fireworks-ai:accounts/fireworks/models/minimax-m2p7", - "inputUsdPer1M": 0.3, - "outputUsdPer1M": 1.2, - "cacheReadUsdPer1M": 0.06 - }, { "modelKey": "fireworks-ai:accounts/fireworks/models/minimax-m3", "inputUsdPer1M": 0.3, @@ -38437,24 +39327,6 @@ "outputUsdPer1M": 6.6, "cacheReadUsdPer1M": 0.21 }, - { - "modelKey": "fireworks-ai:accounts/fireworks/routers/kimi-k2p6-fast", - "inputUsdPer1M": 2, - "outputUsdPer1M": 8, - "cacheReadUsdPer1M": 0.3 - }, - { - "modelKey": "fireworks-ai:accounts/fireworks/routers/kimi-k2p6-turbo", - "inputUsdPer1M": 2, - "outputUsdPer1M": 8, - "cacheReadUsdPer1M": 0.3 - }, - { - "modelKey": "fireworks-ai:accounts/fireworks/routers/kimi-k2p7-code-fast", - "inputUsdPer1M": 1.9, - "outputUsdPer1M": 8, - "cacheReadUsdPer1M": 0.38 - }, { "modelKey": "fireworks-ai:accounts/fireworks/routers/kimi-k3-fast", "inputUsdPer1M": 4.5, @@ -38598,11 +39470,6 @@ "inputUsdPer1M": 1.5, "outputUsdPer1M": 17.5 }, - { - "modelKey": "google:gemini-robotics-er-1.6-preview", - "inputUsdPer1M": 1, - "outputUsdPer1M": 5 - }, { "modelKey": "google:lyria-3-clip-preview", "inputUsdPer1M": 0, @@ -38661,6 +39528,11 @@ "outputUsdPer1M": 3, "cacheReadUsdPer1M": 0.3 }, + { + "modelKey": "groq:qwen/qwen3.8-27b", + "inputUsdPer1M": 0.8, + "outputUsdPer1M": 4 + }, { "modelKey": "huggingface:deepseek-ai/DeepSeek-R1", "inputUsdPer1M": 0.7, @@ -38922,6 +39794,11 @@ "inputUsdPer1M": 2.5, "outputUsdPer1M": 6.25 }, + { + "modelKey": "huggingface:Qwen/Qwen3.8-27B", + "inputUsdPer1M": 0.4, + "outputUsdPer1M": 3 + }, { "modelKey": "huggingface:stepfun-ai/Step-3.5-Flash", "inputUsdPer1M": 0.1, @@ -39015,6 +39892,16 @@ "inputUsdPer1M": 1.4, "outputUsdPer1M": 4.4 }, + { + "modelKey": "huggingface:zai-org/GLM-5.3", + "inputUsdPer1M": 1.4, + "outputUsdPer1M": 4.4 + }, + { + "modelKey": "huggingface:zai-org/GLM-5.3-Flash", + "inputUsdPer1M": 0.15, + "outputUsdPer1M": 0.5 + }, { "modelKey": "MiniMax:MiniMax-M2", "inputUsdPer1M": 0.3, @@ -39210,6 +40097,12 @@ "inputUsdPer1M": 0.1, "outputUsdPer1M": 0.3 }, + { + "modelKey": "mistral:zai-glm-5-2", + "inputUsdPer1M": 1.4, + "outputUsdPer1M": 4.4, + "cacheReadUsdPer1M": 0.14 + }, { "modelKey": "moonshot:kimi-k2-0711-preview", "inputUsdPer1M": 0.6, @@ -39311,12 +40204,22 @@ "outputUsdPer1M": 0.28, "cacheReadUsdPer1M": 0.0028 }, + { + "modelKey": "nvidia:deepseek-ai/deepseek-v4-flash-0731", + "inputUsdPer1M": 0, + "outputUsdPer1M": 0 + }, { "modelKey": "nvidia:deepseek-ai/deepseek-v4-pro", "inputUsdPer1M": 0.435, "outputUsdPer1M": 0.87, "cacheReadUsdPer1M": 0.003625 }, + { + "modelKey": "nvidia:deepseek-ai/deepseek-v4-pro-0813", + "inputUsdPer1M": 0, + "outputUsdPer1M": 0 + }, { "modelKey": "nvidia:google/gemma-2-2b-it", "inputUsdPer1M": 0, @@ -39492,6 +40395,11 @@ "inputUsdPer1M": 0, "outputUsdPer1M": 0 }, + { + "modelKey": "nvidia:moonshotai/kimi-k3", + "inputUsdPer1M": 0, + "outputUsdPer1M": 0 + }, { "modelKey": "nvidia:nvidia/active-speaker-detection", "inputUsdPer1M": 0, @@ -40315,6 +41223,12 @@ "inputUsdPer1M": 0, "outputUsdPer1M": 0 }, + { + "modelKey": "opencode:ling-3.0-flash-fin-free", + "inputUsdPer1M": 0, + "outputUsdPer1M": 0, + "cacheReadUsdPer1M": 0 + }, { "modelKey": "opencode:ling-3.0-flash-free", "inputUsdPer1M": 0, @@ -40504,22 +41418,22 @@ }, { "modelKey": "openrouter:~deepseek/deepseek-v4-flash-latest", - "inputUsdPer1M": 0.065, - "outputUsdPer1M": 0.18, - "cacheReadUsdPer1M": 0.02 + "inputUsdPer1M": 0.05, + "outputUsdPer1M": 0.16, + "cacheReadUsdPer1M": 0.013 }, { "modelKey": "openrouter:~google/gemini-flash-latest", - "inputUsdPer1M": 0.375, - "outputUsdPer1M": 1.875, - "cacheReadUsdPer1M": 0.0375, - "cacheWriteUsdPer1M": 0.020833 + "inputUsdPer1M": 0.75, + "outputUsdPer1M": 3.75, + "cacheReadUsdPer1M": 0.075, + "cacheWriteUsdPer1M": 0.041667 }, { "modelKey": "openrouter:~moonshotai/kimi-latest", - "inputUsdPer1M": 2.6, - "outputUsdPer1M": 13, - "cacheReadUsdPer1M": 0.29 + "inputUsdPer1M": 2.55, + "outputUsdPer1M": 12.75, + "cacheReadUsdPer1M": 0.256 }, { "modelKey": "openrouter:~openai/gpt-mini-latest", @@ -40529,9 +41443,9 @@ }, { "modelKey": "openrouter:~z-ai/glm-latest", - "inputUsdPer1M": 1.4, - "outputUsdPer1M": 4.4, - "cacheReadUsdPer1M": 0.26 + "inputUsdPer1M": 1.17, + "outputUsdPer1M": 3.96, + "cacheReadUsdPer1M": 0.234 }, { "modelKey": "openrouter:aion-labs/aion-2.0", @@ -40556,11 +41470,6 @@ "inputUsdPer1M": 0.8, "outputUsdPer1M": 1.6 }, - { - "modelKey": "openrouter:allenai/olmo-3-32b-think", - "inputUsdPer1M": 0.15, - "outputUsdPer1M": 0.5 - }, { "modelKey": "openrouter:amazon/nova-2-lite-v1", "inputUsdPer1M": 0.3, @@ -40589,7 +41498,7 @@ }, { "modelKey": "openrouter:anthracite-org/magnum-v4-72b", - "inputUsdPer1M": 3, + "inputUsdPer1M": 2.5, "outputUsdPer1M": 5 }, { @@ -40678,15 +41587,10 @@ }, { "modelKey": "openrouter:arcee-ai/trinity-large-thinking", - "inputUsdPer1M": 0.22, - "outputUsdPer1M": 0.85, + "inputUsdPer1M": 0.25, + "outputUsdPer1M": 0.8, "cacheReadUsdPer1M": 0.06 }, - { - "modelKey": "openrouter:arcee-ai/virtuoso-large", - "inputUsdPer1M": 0.75, - "outputUsdPer1M": 1.2 - }, { "modelKey": "openrouter:baidu/ernie-4.5-vl-424b-a47b", "inputUsdPer1M": 0.42, @@ -40733,11 +41637,6 @@ "inputUsdPer1M": 0, "outputUsdPer1M": 0 }, - { - "modelKey": "openrouter:deepcogito/cogito-v2.1-671b", - "inputUsdPer1M": 1.25, - "outputUsdPer1M": 1.25 - }, { "modelKey": "openrouter:deepseek/deepseek-chat", "inputUsdPer1M": 0.2574, @@ -40750,9 +41649,9 @@ }, { "modelKey": "openrouter:deepseek/deepseek-chat-v3.1", - "inputUsdPer1M": 0.25, - "outputUsdPer1M": 0.95, - "cacheReadUsdPer1M": 0.13 + "inputUsdPer1M": 0.55, + "outputUsdPer1M": 1.65, + "cacheReadUsdPer1M": 0.55 }, { "modelKey": "openrouter:deepseek/deepseek-r1", @@ -40789,21 +41688,21 @@ }, { "modelKey": "openrouter:deepseek/deepseek-v4-flash", - "inputUsdPer1M": 0.0826, - "outputUsdPer1M": 0.1652, - "cacheReadUsdPer1M": 0.01652 + "inputUsdPer1M": 0.08092, + "outputUsdPer1M": 0.16184, + "cacheReadUsdPer1M": 0.016184 }, { "modelKey": "openrouter:deepseek/deepseek-v4-flash-0731", - "inputUsdPer1M": 0.08, + "inputUsdPer1M": 0.065, "outputUsdPer1M": 0.18, "cacheReadUsdPer1M": 0.016 }, { "modelKey": "openrouter:deepseek/deepseek-v4-flash-vision-exp", - "inputUsdPer1M": 0.22, - "outputUsdPer1M": 0.66, - "cacheReadUsdPer1M": 0.007 + "inputUsdPer1M": 0.44, + "outputUsdPer1M": 1.32, + "cacheReadUsdPer1M": 0.014 }, { "modelKey": "openrouter:deepseek/deepseek-v4-pro", @@ -40813,9 +41712,9 @@ }, { "modelKey": "openrouter:deepseek/deepseek-v4-pro-0813", - "inputUsdPer1M": 1.188, - "outputUsdPer1M": 3.564, - "cacheReadUsdPer1M": 0.0396 + "inputUsdPer1M": 1.1154, + "outputUsdPer1M": 3.3462, + "cacheReadUsdPer1M": 0.03718 }, { "modelKey": "openrouter:dots-studio/dots-3-note-preview:free", @@ -40916,10 +41815,10 @@ }, { "modelKey": "openrouter:google/gemini-3.7-flash", - "inputUsdPer1M": 0.375, - "outputUsdPer1M": 1.875, - "cacheReadUsdPer1M": 0.0375, - "cacheWriteUsdPer1M": 0.020833 + "inputUsdPer1M": 0.75, + "outputUsdPer1M": 3.75, + "cacheReadUsdPer1M": 0.075, + "cacheWriteUsdPer1M": 0.041667 }, { "modelKey": "openrouter:google/gemma-2-27b-it", @@ -40942,11 +41841,6 @@ "inputUsdPer1M": 0.05, "outputUsdPer1M": 0.1 }, - { - "modelKey": "openrouter:google/gemma-3n-e4b-it", - "inputUsdPer1M": 0.06, - "outputUsdPer1M": 0.12 - }, { "modelKey": "openrouter:google/gemma-4-26b-a4b-it", "inputUsdPer1M": 0.07, @@ -40959,9 +41853,9 @@ }, { "modelKey": "openrouter:google/gemma-4-31b-it", - "inputUsdPer1M": 0.1, + "inputUsdPer1M": 0.09, "outputUsdPer1M": 0.34, - "cacheReadUsdPer1M": 0.1 + "cacheReadUsdPer1M": 0.05 }, { "modelKey": "openrouter:google/gemma-4-31b-it:free", @@ -40994,24 +41888,18 @@ "outputUsdPer1M": 0.1, "cacheReadUsdPer1M": 0.05 }, + { + "modelKey": "openrouter:ibm-granite/granite-4.2-8b", + "inputUsdPer1M": 0.1, + "outputUsdPer1M": 0.15, + "cacheReadUsdPer1M": 0.05 + }, { "modelKey": "openrouter:inception/mercury-2", "inputUsdPer1M": 0.25, "outputUsdPer1M": 0.75, "cacheReadUsdPer1M": 0.025 }, - { - "modelKey": "openrouter:inclusionai/ling-2.6-1t", - "inputUsdPer1M": 0.075, - "outputUsdPer1M": 0.625, - "cacheReadUsdPer1M": 0.015 - }, - { - "modelKey": "openrouter:inclusionai/ling-2.6-flash", - "inputUsdPer1M": 0.01, - "outputUsdPer1M": 0.03, - "cacheReadUsdPer1M": 0.002 - }, { "modelKey": "openrouter:inclusionai/ling-3.0-flash", "inputUsdPer1M": 0.021, @@ -41019,16 +41907,9 @@ "cacheReadUsdPer1M": 0.0042 }, { - "modelKey": "openrouter:inclusionai/ring-2.6-1t", - "inputUsdPer1M": 0.075, - "outputUsdPer1M": 0.625, - "cacheReadUsdPer1M": 0.015 - }, - { - "modelKey": "openrouter:kwaipilot/kat-coder-air-v2.5", - "inputUsdPer1M": 0.15, - "outputUsdPer1M": 0.6, - "cacheReadUsdPer1M": 0.03 + "modelKey": "openrouter:inclusionai/ling-3.0-flash-fin:free", + "inputUsdPer1M": 0, + "outputUsdPer1M": 0 }, { "modelKey": "openrouter:kwaipilot/kat-coder-pro-v2", @@ -41049,7 +41930,7 @@ }, { "modelKey": "openrouter:mancer/weaver", - "inputUsdPer1M": 0.5, + "inputUsdPer1M": 0.4, "outputUsdPer1M": 0.75 }, { @@ -41081,13 +41962,14 @@ }, { "modelKey": "openrouter:meta-llama/llama-3.3-70b-instruct", - "inputUsdPer1M": 0.1, - "outputUsdPer1M": 0.32 + "inputUsdPer1M": 0.71, + "outputUsdPer1M": 0.71, + "cacheReadUsdPer1M": 0.71 }, { "modelKey": "openrouter:meta-llama/llama-4-maverick", "inputUsdPer1M": 0.2, - "outputUsdPer1M": 0.8 + "outputUsdPer1M": 0.696 }, { "modelKey": "openrouter:meta-llama/llama-4-scout", @@ -41102,7 +41984,7 @@ { "modelKey": "openrouter:meta/muse-glimmer-30b", "inputUsdPer1M": 0.3, - "outputUsdPer1M": 1.1, + "outputUsdPer1M": 1.2, "cacheReadUsdPer1M": 0.04 }, { @@ -41117,6 +41999,12 @@ "outputUsdPer1M": 4.25, "cacheReadUsdPer1M": 0.15 }, + { + "modelKey": "openrouter:meta/muse-spark-1.2-contributor", + "inputUsdPer1M": 0.1, + "outputUsdPer1M": 0.2, + "cacheReadUsdPer1M": 0.002 + }, { "modelKey": "openrouter:microsoft/phi-4", "inputUsdPer1M": 0.07, @@ -41157,8 +42045,8 @@ { "modelKey": "openrouter:minimax/minimax-m2.5", "inputUsdPer1M": 0.27, - "outputUsdPer1M": 0.95, - "cacheReadUsdPer1M": 0.03 + "outputUsdPer1M": 1.08, + "cacheReadUsdPer1M": 0.027 }, { "modelKey": "openrouter:minimax/minimax-m2.7", @@ -41166,18 +42054,34 @@ "outputUsdPer1M": 1.2, "cacheReadUsdPer1M": 0.06 }, + { + "modelKey": "openrouter:minimax/minimax-m2.7:free", + "inputUsdPer1M": 0, + "outputUsdPer1M": 0 + }, { "modelKey": "openrouter:minimax/minimax-m3", "inputUsdPer1M": 0.3, "outputUsdPer1M": 1.2, "cacheReadUsdPer1M": 0.06 }, + { + "modelKey": "openrouter:minimax/minimax-m3:free", + "inputUsdPer1M": 0, + "outputUsdPer1M": 0 + }, { "modelKey": "openrouter:mistralai/codestral-2508", "inputUsdPer1M": 0.3, "outputUsdPer1M": 0.9, "cacheReadUsdPer1M": 0.03 }, + { + "modelKey": "openrouter:mistralai/devstral-2512", + "inputUsdPer1M": 0.4, + "outputUsdPer1M": 2, + "cacheReadUsdPer1M": 0.04 + }, { "modelKey": "openrouter:mistralai/ministral-14b-2512", "inputUsdPer1M": 0.2, @@ -41190,11 +42094,6 @@ "outputUsdPer1M": 0.1, "cacheReadUsdPer1M": 0.01 }, - { - "modelKey": "openrouter:mistralai/ministral-8b", - "inputUsdPer1M": 0.11, - "outputUsdPer1M": 0.11 - }, { "modelKey": "openrouter:mistralai/ministral-8b-2512", "inputUsdPer1M": 0.15, @@ -41265,8 +42164,8 @@ }, { "modelKey": "openrouter:mistralai/mistral-small-3.2-24b-instruct", - "inputUsdPer1M": 0.09375, - "outputUsdPer1M": 0.25 + "inputUsdPer1M": 0.075, + "outputUsdPer1M": 0.2 }, { "modelKey": "openrouter:mistralai/mixtral-8x22b-instruct", @@ -41310,9 +42209,9 @@ }, { "modelKey": "openrouter:moonshotai/kimi-k2.7-code", - "inputUsdPer1M": 0.67, + "inputUsdPer1M": 0.66, "outputUsdPer1M": 3.4, - "cacheReadUsdPer1M": 0.17 + "cacheReadUsdPer1M": 0.18 }, { "modelKey": "openrouter:moonshotai/kimi-k3", @@ -41366,12 +42265,7 @@ "modelKey": "openrouter:nvidia/nemotron-3-nano-30b-a3b", "inputUsdPer1M": 0.05, "outputUsdPer1M": 0.2, - "cacheReadUsdPer1M": 0.03 - }, - { - "modelKey": "openrouter:nvidia/nemotron-3-nano-30b-a3b:free", - "inputUsdPer1M": 0, - "outputUsdPer1M": 0 + "cacheReadUsdPer1M": 0.025 }, { "modelKey": "openrouter:nvidia/nemotron-3-nano-omni-30b-a3b-reasoning:free", @@ -41390,9 +42284,9 @@ }, { "modelKey": "openrouter:nvidia/nemotron-3-ultra-550b-a55b", - "inputUsdPer1M": 0.6, - "outputUsdPer1M": 3.6, - "cacheReadUsdPer1M": 0.2 + "inputUsdPer1M": 0.5, + "outputUsdPer1M": 2.2, + "cacheReadUsdPer1M": 0.1 }, { "modelKey": "openrouter:nvidia/nemotron-3-ultra-550b-a55b:free", @@ -41415,16 +42309,6 @@ "inputUsdPer1M": 0, "outputUsdPer1M": 0 }, - { - "modelKey": "openrouter:nvidia/nemotron-nano-12b-v2-vl:free", - "inputUsdPer1M": 0, - "outputUsdPer1M": 0 - }, - { - "modelKey": "openrouter:nvidia/nemotron-nano-9b-v2:free", - "inputUsdPer1M": 0, - "outputUsdPer1M": 0 - }, { "modelKey": "openrouter:openai/gpt-3.5-turbo", "inputUsdPer1M": 0.5, @@ -41637,9 +42521,8 @@ }, { "modelKey": "openrouter:openai/gpt-oss-120b", - "inputUsdPer1M": 0.03, - "outputUsdPer1M": 0.17, - "cacheReadUsdPer1M": 0.03 + "inputUsdPer1M": 0.037, + "outputUsdPer1M": 0.17 }, { "modelKey": "openrouter:openai/gpt-oss-20b", @@ -41647,11 +42530,6 @@ "outputUsdPer1M": 0.13, "cacheReadUsdPer1M": 0.03 }, - { - "modelKey": "openrouter:openai/gpt-oss-20b:free", - "inputUsdPer1M": 0, - "outputUsdPer1M": 0 - }, { "modelKey": "openrouter:openai/gpt-oss-safeguard-20b", "inputUsdPer1M": 0.075, @@ -41778,9 +42656,8 @@ }, { "modelKey": "openrouter:qwen/qwen2.5-vl-72b-instruct", - "inputUsdPer1M": 0.8, - "outputUsdPer1M": 1, - "cacheReadUsdPer1M": 0.4 + "inputUsdPer1M": 0.25, + "outputUsdPer1M": 0.75 }, { "modelKey": "openrouter:qwen/qwen3-14b", @@ -41794,8 +42671,9 @@ }, { "modelKey": "openrouter:qwen/qwen3-235b-a22b-2507", - "inputUsdPer1M": 0.09, - "outputUsdPer1M": 0.55 + "inputUsdPer1M": 0.0875, + "outputUsdPer1M": 0.35, + "cacheReadUsdPer1M": 0.0175 }, { "modelKey": "openrouter:qwen/qwen3-235b-a22b-thinking-2507", @@ -41804,8 +42682,8 @@ }, { "modelKey": "openrouter:qwen/qwen3-30b-a3b", - "inputUsdPer1M": 0.13, - "outputUsdPer1M": 0.52 + "inputUsdPer1M": 0.12, + "outputUsdPer1M": 0.5 }, { "modelKey": "openrouter:qwen/qwen3-30b-a3b-instruct-2507", @@ -41846,8 +42724,9 @@ }, { "modelKey": "openrouter:qwen/qwen3-next-80b-a3b-instruct", - "inputUsdPer1M": 0.09, - "outputUsdPer1M": 1.1 + "inputUsdPer1M": 0.1, + "outputUsdPer1M": 1.1, + "cacheReadUsdPer1M": 0.07 }, { "modelKey": "openrouter:qwen/qwen3-next-80b-a3b-thinking", @@ -41867,8 +42746,8 @@ }, { "modelKey": "openrouter:qwen/qwen3-vl-30b-a3b-instruct", - "inputUsdPer1M": 0.13, - "outputUsdPer1M": 0.52 + "inputUsdPer1M": 0.15, + "outputUsdPer1M": 0.6 }, { "modelKey": "openrouter:qwen/qwen3-vl-30b-a3b-thinking", @@ -41892,8 +42771,8 @@ }, { "modelKey": "openrouter:qwen/qwen3.5-122b-a10b", - "inputUsdPer1M": 0.26, - "outputUsdPer1M": 2.08 + "inputUsdPer1M": 0.29, + "outputUsdPer1M": 2.4 }, { "modelKey": "openrouter:qwen/qwen3.5-27b", @@ -41929,8 +42808,8 @@ }, { "modelKey": "openrouter:qwen/qwen3.6-35b-a3b", - "inputUsdPer1M": 0.14, - "outputUsdPer1M": 1, + "inputUsdPer1M": 0.1, + "outputUsdPer1M": 0.9, "cacheReadUsdPer1M": 0.05 }, { @@ -41948,9 +42827,17 @@ }, { "modelKey": "openrouter:qwen/qwen3.8-27b", - "inputUsdPer1M": 0.45, - "outputUsdPer1M": 3.2, - "cacheReadUsdPer1M": 0.05 + "inputUsdPer1M": 0.425, + "outputUsdPer1M": 2.55, + "cacheReadUsdPer1M": 0.085, + "cacheWriteUsdPer1M": 0.53125 + }, + { + "modelKey": "openrouter:qwen/qwen3.8-flash", + "inputUsdPer1M": 0.15, + "outputUsdPer1M": 0.47, + "cacheReadUsdPer1M": 0.016, + "cacheWriteUsdPer1M": 0.2 }, { "modelKey": "openrouter:qwen/qwen3.8-max", @@ -42000,11 +42887,6 @@ "inputUsdPer1M": 0.65, "outputUsdPer1M": 0.75 }, - { - "modelKey": "openrouter:stealth/ox-alpha", - "inputUsdPer1M": 0, - "outputUsdPer1M": 0 - }, { "modelKey": "openrouter:stepfun/step-3.5-flash", "inputUsdPer1M": 0.1, @@ -42031,6 +42913,11 @@ "inputUsdPer1M": 0.074, "outputUsdPer1M": 0.295 }, + { + "modelKey": "openrouter:tencent/hy-mt2-7b", + "inputUsdPer1M": 0.074, + "outputUsdPer1M": 0.295 + }, { "modelKey": "openrouter:tencent/hy3", "inputUsdPer1M": 0.132, @@ -42043,17 +42930,18 @@ "outputUsdPer1M": 0.6, "cacheReadUsdPer1M": 0.06 }, + { + "modelKey": "openrouter:tencent/hy4-preview", + "inputUsdPer1M": 0.834, + "outputUsdPer1M": 2.501, + "cacheReadUsdPer1M": 0.042 + }, { "modelKey": "openrouter:thedrummer/cydonia-24b-v4.1", "inputUsdPer1M": 0.3, "outputUsdPer1M": 0.5, "cacheReadUsdPer1M": 0.15 }, - { - "modelKey": "openrouter:thedrummer/rocinante-12b", - "inputUsdPer1M": 0.25, - "outputUsdPer1M": 0.5 - }, { "modelKey": "openrouter:thedrummer/skyfall-36b-v2", "inputUsdPer1M": 0.55, @@ -42067,9 +42955,9 @@ }, { "modelKey": "openrouter:thinkingmachines/inkling", - "inputUsdPer1M": 0.95, + "inputUsdPer1M": 1, "outputUsdPer1M": 4.05, - "cacheReadUsdPer1M": 0.16 + "cacheReadUsdPer1M": 0.17 }, { "modelKey": "openrouter:thinkingmachines/inkling-small", @@ -42077,6 +42965,16 @@ "outputUsdPer1M": 1.2, "cacheReadUsdPer1M": 0.1 }, + { + "modelKey": "openrouter:thinkingmachines/inkling-small:free", + "inputUsdPer1M": 0, + "outputUsdPer1M": 0 + }, + { + "modelKey": "openrouter:thinkingmachines/inkling:free", + "inputUsdPer1M": 0, + "outputUsdPer1M": 0 + }, { "modelKey": "openrouter:undi95/remm-slerp-l2-13b", "inputUsdPer1M": 0.45, @@ -42131,9 +43029,9 @@ }, { "modelKey": "openrouter:z-ai/glm-4.6", - "inputUsdPer1M": 0.5, - "outputUsdPer1M": 2, - "cacheReadUsdPer1M": 0.1 + "inputUsdPer1M": 0.43, + "outputUsdPer1M": 1.75, + "cacheReadUsdPer1M": 0.08 }, { "modelKey": "openrouter:z-ai/glm-4.6v", @@ -42173,9 +43071,9 @@ }, { "modelKey": "openrouter:z-ai/glm-5.2", - "inputUsdPer1M": 0.966, - "outputUsdPer1M": 3.036, - "cacheReadUsdPer1M": 0.1932 + "inputUsdPer1M": 1.19, + "outputUsdPer1M": 3.74, + "cacheReadUsdPer1M": 0.221 }, { "modelKey": "openrouter:z-ai/glm-5.2:free", @@ -42188,6 +43086,12 @@ "outputUsdPer1M": 4.4, "cacheReadUsdPer1M": 0.26 }, + { + "modelKey": "openrouter:z-ai/glm-5.3-flash", + "inputUsdPer1M": 0.075, + "outputUsdPer1M": 0.25, + "cacheReadUsdPer1M": 0.015 + }, { "modelKey": "openrouter:z-ai/glm-5v-turbo", "inputUsdPer1M": 1.2, @@ -42707,6 +43611,18 @@ "outputUsdPer1M": 4.4, "cacheReadUsdPer1M": 0.26 }, + { + "modelKey": "togetherai:zai-org/GLM-5.3", + "inputUsdPer1M": 1.4, + "outputUsdPer1M": 4.4, + "cacheReadUsdPer1M": 0.26 + }, + { + "modelKey": "togetherai:zai-org/GLM-5.3-Flash", + "inputUsdPer1M": 0.15, + "outputUsdPer1M": 0.5, + "cacheReadUsdPer1M": 0.03 + }, { "modelKey": "tencent-tokenhub:hy3", "inputUsdPer1M": 0, @@ -42721,6 +43637,12 @@ "cacheReadUsdPer1M": 0, "cacheWriteUsdPer1M": 0 }, + { + "modelKey": "tencent-tokenhub:hy4-preview", + "inputUsdPer1M": 0.834, + "outputUsdPer1M": 2.501, + "cacheReadUsdPer1M": 0.042 + }, { "modelKey": "vercel:alibaba/qwen-3-14b", "inputUsdPer1M": 0.12, @@ -42869,13 +43791,27 @@ "modelKey": "vercel:alibaba/qwen3.8-2.4t-a95b", "inputUsdPer1M": 2, "outputUsdPer1M": 6, - "cacheReadUsdPer1M": 0.2 + "cacheReadUsdPer1M": 0.25 }, { "modelKey": "vercel:alibaba/qwen3.8-27b", - "inputUsdPer1M": 0.55, - "outputUsdPer1M": 3.3, - "cacheReadUsdPer1M": 0.11 + "inputUsdPer1M": 0.5, + "outputUsdPer1M": 3, + "cacheReadUsdPer1M": 0.1, + "cacheWriteUsdPer1M": 0.625 + }, + { + "modelKey": "vercel:alibaba/qwen3.8-flash", + "inputUsdPer1M": 0.16, + "outputUsdPer1M": 0.47, + "cacheReadUsdPer1M": 0.016, + "cacheWriteUsdPer1M": 0.2 + }, + { + "modelKey": "vercel:alibaba/qwen3.8-flash-next", + "inputUsdPer1M": 0.12, + "outputUsdPer1M": 0.4, + "cacheReadUsdPer1M": 0.01 }, { "modelKey": "vercel:alibaba/qwen3.8-max", @@ -43011,11 +43947,6 @@ "inputUsdPer1M": 0.25, "outputUsdPer1M": 0.8999999999999999 }, - { - "modelKey": "vercel:arcee-ai/trinity-mini", - "inputUsdPer1M": 0.045, - "outputUsdPer1M": 0.15 - }, { "modelKey": "vercel:bytedance/seed-1.6", "inputUsdPer1M": 0.25, @@ -43075,21 +44006,27 @@ }, { "modelKey": "vercel:deepseek/deepseek-v4-flash-0731", - "inputUsdPer1M": 0.13, - "outputUsdPer1M": 0.26, - "cacheReadUsdPer1M": 0.028 + "inputUsdPer1M": 0.076, + "outputUsdPer1M": 0.153, + "cacheReadUsdPer1M": 0.014 + }, + { + "modelKey": "vercel:deepseek/deepseek-v4-flash-vision-exp", + "inputUsdPer1M": 0.22, + "outputUsdPer1M": 0.66, + "cacheReadUsdPer1M": 0.007 }, { "modelKey": "vercel:deepseek/deepseek-v4-pro", - "inputUsdPer1M": 1.74, - "outputUsdPer1M": 3.48, - "cacheReadUsdPer1M": 0.14 + "inputUsdPer1M": 0.66, + "outputUsdPer1M": 1.98, + "cacheReadUsdPer1M": 0.022 }, { "modelKey": "vercel:deepseek/deepseek-v4-pro-0813", - "inputUsdPer1M": 1.32, - "outputUsdPer1M": 3.96, - "cacheReadUsdPer1M": 0.132 + "inputUsdPer1M": 0.66, + "outputUsdPer1M": 1.98, + "cacheReadUsdPer1M": 0.066 }, { "modelKey": "vercel:google/gemini-2.5-flash", @@ -43163,6 +44100,11 @@ "outputUsdPer1M": 2.5, "cacheReadUsdPer1M": 0.03 }, + { + "modelKey": "vercel:google/gemini-3.5-transcribe", + "inputUsdPer1M": 2, + "outputUsdPer1M": 12 + }, { "modelKey": "vercel:google/gemini-3.6-flash", "inputUsdPer1M": 0.75, @@ -43208,6 +44150,16 @@ "outputUsdPer1M": 0.18, "cacheReadUsdPer1M": 0.012 }, + { + "modelKey": "vercel:inclusionai/ling-3.0-flash-fin", + "inputUsdPer1M": 0, + "outputUsdPer1M": 0 + }, + { + "modelKey": "vercel:inclusionai/ling-3.0-flash-fin-free", + "inputUsdPer1M": 0, + "outputUsdPer1M": 0 + }, { "modelKey": "vercel:interfaze/interfaze-beta", "inputUsdPer1M": 1.5, @@ -43328,6 +44280,11 @@ "cacheReadUsdPer1M": 0.06, "cacheWriteUsdPer1M": 0.375 }, + { + "modelKey": "vercel:minimax/minimax-m2.7-free", + "inputUsdPer1M": 0, + "outputUsdPer1M": 0 + }, { "modelKey": "vercel:minimax/minimax-m2.7-highspeed", "inputUsdPer1M": 0.6, @@ -43341,6 +44298,12 @@ "outputUsdPer1M": 1.2, "cacheReadUsdPer1M": 0.06 }, + { + "modelKey": "vercel:minimax/minimax-m3-free", + "inputUsdPer1M": 0, + "outputUsdPer1M": 0, + "cacheReadUsdPer1M": 0 + }, { "modelKey": "vercel:mistral/codestral", "inputUsdPer1M": 0.3, @@ -43356,16 +44319,6 @@ "inputUsdPer1M": 0.1, "outputUsdPer1M": 0.3 }, - { - "modelKey": "vercel:mistral/magistral-medium", - "inputUsdPer1M": 2, - "outputUsdPer1M": 5 - }, - { - "modelKey": "vercel:mistral/magistral-small", - "inputUsdPer1M": 0.5, - "outputUsdPer1M": 1.5 - }, { "modelKey": "vercel:mistral/ministral-14b", "inputUsdPer1M": 0.2, @@ -43438,7 +44391,7 @@ "modelKey": "vercel:moonshotai/kimi-k2.7-code", "inputUsdPer1M": 0.95, "outputUsdPer1M": 4, - "cacheReadUsdPer1M": 0.19 + "cacheReadUsdPer1M": 0.16 }, { "modelKey": "vercel:moonshotai/kimi-k2.7-code-highspeed", @@ -43570,11 +44523,6 @@ "outputUsdPer1M": 1, "cacheReadUsdPer1M": 0.125 }, - { - "modelKey": "vercel:openai/gpt-4o-mini-search-preview", - "inputUsdPer1M": 0.15, - "outputUsdPer1M": 0.6 - }, { "modelKey": "vercel:openai/gpt-4o-mini-transcribe", "inputUsdPer1M": 1.25, @@ -43759,17 +44707,17 @@ }, { "modelKey": "vercel:openai/gpt-5.6-sol", - "inputUsdPer1M": 2.5, - "outputUsdPer1M": 15, - "cacheReadUsdPer1M": 0.25, - "cacheWriteUsdPer1M": 3.125 + "inputUsdPer1M": 2, + "outputUsdPer1M": 10, + "cacheReadUsdPer1M": 0.2, + "cacheWriteUsdPer1M": 2.5 }, { "modelKey": "vercel:openai/gpt-5.6-sol-fast", - "inputUsdPer1M": 5, - "outputUsdPer1M": 30, - "cacheReadUsdPer1M": 0.5, - "cacheWriteUsdPer1M": 3.125 + "inputUsdPer1M": 4, + "outputUsdPer1M": 20, + "cacheReadUsdPer1M": 0.4, + "cacheWriteUsdPer1M": 2.5 }, { "modelKey": "vercel:openai/gpt-5.6-terra", @@ -43819,11 +44767,15 @@ "inputUsdPer1M": 0.05, "outputUsdPer1M": 0.2 }, + { + "modelKey": "vercel:openai/gpt-oss-safeguard-120b", + "inputUsdPer1M": 0.15, + "outputUsdPer1M": 0.6 + }, { "modelKey": "vercel:openai/gpt-oss-safeguard-20b", - "inputUsdPer1M": 0.075, - "outputUsdPer1M": 0.3, - "cacheReadUsdPer1M": 0.037 + "inputUsdPer1M": 0.07, + "outputUsdPer1M": 0.2 }, { "modelKey": "vercel:openai/gpt-realtime-1.5", @@ -43861,12 +44813,6 @@ "outputUsdPer1M": 8, "cacheReadUsdPer1M": 0.5 }, - { - "modelKey": "vercel:openai/o3-deep-research", - "inputUsdPer1M": 10, - "outputUsdPer1M": 40, - "cacheReadUsdPer1M": 2.5 - }, { "modelKey": "vercel:openai/o3-fast", "inputUsdPer1M": 3.5, @@ -44020,9 +44966,15 @@ }, { "modelKey": "vercel:tencent/hy3", - "inputUsdPer1M": 0.132, - "outputUsdPer1M": 0.528, - "cacheReadUsdPer1M": 0.033 + "inputUsdPer1M": 0.14, + "outputUsdPer1M": 0.58, + "cacheReadUsdPer1M": 0.035 + }, + { + "modelKey": "vercel:tencent/hy4-preview", + "inputUsdPer1M": 0.834, + "outputUsdPer1M": 2.501, + "cacheReadUsdPer1M": 0.042 }, { "modelKey": "vercel:thinkingmachines/inkling", @@ -44048,6 +45000,12 @@ "outputUsdPer1M": 0.87, "cacheReadUsdPer1M": 0.0036 }, + { + "modelKey": "vercel:xiaomi/mimo-v2.5-pro-ultraspeed", + "inputUsdPer1M": 1.305, + "outputUsdPer1M": 2.61, + "cacheReadUsdPer1M": 0.0108 + }, { "modelKey": "vercel:zai/glm-4.5", "inputUsdPer1M": 0.6, @@ -44122,7 +45080,13 @@ "modelKey": "vercel:zai/glm-5.3", "inputUsdPer1M": 1.4, "outputUsdPer1M": 4.4, - "cacheReadUsdPer1M": 0.26 + "cacheReadUsdPer1M": 0.14 + }, + { + "modelKey": "vercel:zai/glm-5.3-flash", + "inputUsdPer1M": 0.15, + "outputUsdPer1M": 0.5, + "cacheReadUsdPer1M": 0.03 }, { "modelKey": "vercel:zai/glm-5v-turbo", @@ -44253,6 +45217,20 @@ "cacheReadUsdPer1M": 0.26, "cacheWriteUsdPer1M": 0 }, + { + "modelKey": "zai:glm-5.3", + "inputUsdPer1M": 1.4, + "outputUsdPer1M": 4.4, + "cacheReadUsdPer1M": 0.26, + "cacheWriteUsdPer1M": 0 + }, + { + "modelKey": "zai:glm-5.3-flash", + "inputUsdPer1M": 0.075, + "outputUsdPer1M": 0.25, + "cacheReadUsdPer1M": 0.015, + "cacheWriteUsdPer1M": 0 + }, { "modelKey": "zai:glm-5v-turbo", "inputUsdPer1M": 1.2, @@ -45378,6 +46356,9 @@ "grok-4.5": { "npm": "@ai-sdk/openai" }, + "grok-4.6": { + "npm": "@ai-sdk/openai" + }, "minimax-m2.5": { "npm": "@ai-sdk/anthropic" }, @@ -45389,6 +46370,9 @@ }, "muse-spark-1.2-contributor": { "npm": "@ai-sdk/openai" + }, + "qwen3.8-flash": { + "npm": "@ai-sdk/anthropic" } }, "openrouter": {}, From e8a95e104b0aada0162c072fb241d0e639b9f839 Mon Sep 17 00:00:00 2001 From: AstroHan Date: Tue, 1 Sep 2026 21:04:19 +0800 Subject: [PATCH 7/9] refactor(core): give the model modality set one owner Five hand-written copies of `text | image | audio | pdf | video` existed: the wire type, the model-facts overlay normalizer, the catalog decoder, the projector's MODALITIES guard, and model-fetcher's knownOutputModalities. The epoch-88 widening updated four and missed the fifth, so a live-fetched model declaring `output: ["video"]` is still offered as a chat default while the same model from bundled metadata is excluded. The type owns the set now and every validator that admits a modality reads it. The projector keeps a copy because it runs before packages/core is built; the build is what keeps that one honest, since a value that reaches the projection but not the type fails to compile. Generated-by: Claude Code --- packages/core/src/llm-connections.ts | 18 ++++++++++++++++-- packages/core/src/model-facts.ts | 14 +++----------- .../runtime-policy/connection-catalog-codec.ts | 15 ++++----------- packages/runtime/src/model-fetcher.ts | 9 ++++----- 4 files changed, 27 insertions(+), 29 deletions(-) diff --git a/packages/core/src/llm-connections.ts b/packages/core/src/llm-connections.ts index 232a3a60e3..1d6c605d19 100644 --- a/packages/core/src/llm-connections.ts +++ b/packages/core/src/llm-connections.ts @@ -86,6 +86,20 @@ export type ConnectionAuth = | { kind: 'oauth_token'; oauthToken: string; expiresAt?: number } | { kind: 'none' }; +/** + * The modalities a model may declare on either side. Every validator that + * admits a modality reads this one set: a decoder, an overlay normalizer, and + * a live-fetch reader each holding their own copy is how one of them stayed a + * catalog behind the others. + */ +export type ModelModality = 'text' | 'image' | 'audio' | 'pdf' | 'video'; + +const MODEL_MODALITIES: readonly ModelModality[] = ['text', 'image', 'audio', 'pdf', 'video']; + +export function isModelModality(value: unknown): value is ModelModality { + return MODEL_MODALITIES.includes(value as ModelModality); +} + export interface ModelInfo { id: string; displayName?: string; @@ -116,8 +130,8 @@ export interface ModelInfo { }; /** Multimodal input/output support from provider catalog metadata. */ modalities?: { - input: Array<'text' | 'image' | 'audio' | 'pdf' | 'video'>; - output: Array<'text' | 'image' | 'audio' | 'pdf' | 'video'>; + input: ModelModality[]; + output: ModelModality[]; }; /** * Read-time provenance for values overlaid from model-facts.json. This is diff --git a/packages/core/src/model-facts.ts b/packages/core/src/model-facts.ts index 11336a5dfd..7b166481e9 100644 --- a/packages/core/src/model-facts.ts +++ b/packages/core/src/model-facts.ts @@ -18,6 +18,7 @@ */ import { providerDefaultsOf, type ProviderType } from './provider-registry.js'; +import { isModelModality } from './llm-connections.js'; import type { ModelFactField, ModelInfo } from './llm-connections.js'; import { CONNECTION_CATALOG_MAX_MODELS_PER_CONNECTION, @@ -193,8 +194,8 @@ function normalizeModalities(value: unknown): NonNullable( return [...new Set(entries)]; } -function isModality(value: unknown): value is 'text' | 'image' | 'audio' | 'pdf' | 'video' { - return ( - value === 'text' || - value === 'image' || - value === 'audio' || - value === 'pdf' || - value === 'video' - ); -} function isPositiveBoundedInteger(value: unknown): value is number { return ( typeof value === 'number' && diff --git a/packages/core/src/runtime-policy/connection-catalog-codec.ts b/packages/core/src/runtime-policy/connection-catalog-codec.ts index 9292b69cfe..cf2664fed8 100644 --- a/packages/core/src/runtime-policy/connection-catalog-codec.ts +++ b/packages/core/src/runtime-policy/connection-catalog-codec.ts @@ -18,10 +18,12 @@ */ import { + isModelModality, isRelayProviderType, PROVIDER_REGISTRY, providerDefaultsOf, validateSlug, + type ModelModality, type ProviderType, } from '../llm-connections.js'; import { MAX_PREPENDED_FALLBACK_MODELS } from '../model-catalog.js'; @@ -608,18 +610,9 @@ function decodeModelModalities(value: unknown): NonNullable( * non-string — is dropped rather than guessed at, so an unrecognized list * reads as "said nothing" instead of "said not text". */ -function knownOutputModalities(declared: readonly unknown[] | undefined): string[] { +function knownOutputModalities(declared: readonly unknown[] | undefined): ModelModality[] { if (declared === undefined) return []; - return declared.filter( - (value): value is 'text' | 'image' | 'audio' => - value === 'text' || value === 'image' || value === 'audio', - ); + return declared.filter(isModelModality); } function assertOptionalArray( From 3b9a2562311906fe131cbeff49ac46da7dfd416e Mon Sep 17 00:00:00 2001 From: AstroHan Date: Tue, 1 Sep 2026 21:04:26 +0800 Subject: [PATCH 8/9] refactor(scripts): let one projector answer what a refresh changed The drift report re-implemented buildProjection's provider loop and then hand-named the sections it compared, so it saw metadata and pricing and was blind to providerFacts and providerOverrides. A renamed provider or a swapped npm package reported "matches the committed snapshot" and then landed in the snapshot on the next refresh anyway. buildProjection now takes its failure policy as an argument: a refresh passes none and aborts on the first bad shape, the report passes one and turns a bad shape into its own finding instead of stopping the comparison. Both read the projection's sections through one table, so a section added to the projection is compared without editing the comparison. MAXIMUM_ACKNOWLEDGED_REMOVALS goes with it. It counted projection paths, not retired models -- this repository's own refresh spent 68 of its 100 on 31 retirements -- and the truncated catalog it guarded against is already caught per provider, where buildProjection refuses a missing or empty models object. Drift exits 2. Drift and a crash both reported 1, which left the one job that has to tell them apart unable to. Generated-by: Claude Code --- scripts/sync-model-metadata.mjs | 270 ++++++++++++++++----------- scripts/sync-model-metadata.test.mjs | 107 ++++++----- 2 files changed, 217 insertions(+), 160 deletions(-) diff --git a/scripts/sync-model-metadata.mjs b/scripts/sync-model-metadata.mjs index b1b74db6b3..5203456772 100644 --- a/scripts/sync-model-metadata.mjs +++ b/scripts/sync-model-metadata.mjs @@ -25,9 +25,10 @@ import { dirname } from 'node:path'; import { pathToFileURL } from 'node:url'; const SOURCE_URL = 'https://models.dev/api.json'; -// Must stay in step with ModelInfo['modalities'] in packages/core. A value -// that reaches the projection but not the wire type fails the build; a value -// missing here drops the whole refresh, not just the model that declares it. +// This script runs before packages/core is built, so it cannot read +// ModelModality itself. The build keeps the two in step: a value that reaches +// the projection but not that type fails to compile. A value missing here +// drops the whole refresh, not just the model that declares it. const MODALITIES = new Set(['text', 'image', 'audio', 'pdf', 'video']); const DEFAULT_SNAPSHOT = 'scripts/model-metadata/models-dev-api.snapshot.json'; const DEFAULT_OUTPUT = 'packages/core/src/model-metadata.generated.ts'; @@ -191,30 +192,25 @@ export async function main(argv = process.argv) { await replaceFilesTransactionally(writes); } -function buildProjection(catalog) { +// `options.onReject` decides what an unprojectable provider or model costs. A +// refresh has none, so the first bad shape aborts the whole snapshot rather +// than silently committing a catalog with a hole in it. The drift report +// passes one, because there a bad shape is the finding it exists to print and +// must not stop it comparing everything else. +function buildProjection(catalog, options = {}) { + const onReject = options.onReject; const metadata = {}; const pricing = []; const providerFacts = {}; const providerOverrides = {}; for (const [providerType, sourceId] of Object.entries(PROVIDERS)) { const provider = catalog[sourceId]; - if (!provider) { - throw new Error(`models.dev provider ${sourceId} is missing`); - } - if ( - !provider.models || - typeof provider.models !== 'object' || - Array.isArray(provider.models) || - Object.keys(provider.models).length === 0 - ) { - throw new Error(`models.dev provider ${sourceId} has no non-empty models object`); - } - if ( - typeof provider.id !== 'string' || - typeof provider.name !== 'string' || - typeof provider.doc !== 'string' - ) { - throw new Error(`models.dev provider ${sourceId} has an unsupported shape`); + try { + assertProviderShape(sourceId, provider); + } catch (error) { + if (!onReject) throw error; + onReject('provider', providerType, error); + continue; } providerFacts[providerType] = { id: provider.id, @@ -222,30 +218,59 @@ function buildProjection(catalog) { ...(typeof provider.api === 'string' ? { api: provider.api } : {}), doc: provider.doc, }; - metadata[providerType] = Object.fromEntries( - Object.entries(provider.models) - .sort(([left], [right]) => left.localeCompare(right)) - .map(([id, model]) => [id, toMetadata(sourceId, id, provider, model)]), - ); - providerOverrides[providerType] = Object.fromEntries( - Object.entries(provider.models) - .sort(([left], [right]) => left.localeCompare(right)) - .filter(([, model]) => model.provider !== undefined) - .map(([id, model]) => [id, toModelProviderOverride(sourceId, id, model.provider)]), + metadata[providerType] = {}; + providerOverrides[providerType] = {}; + const priced = !PRICING_EXCLUDED_PROVIDER_TYPES.has(providerType); + const models = Object.entries(provider.models).sort(([left], [right]) => + left.localeCompare(right), ); - if (!PRICING_EXCLUDED_PROVIDER_TYPES.has(providerType)) { - pricing.push( - ...Object.entries(provider.models) - .sort(([left], [right]) => left.localeCompare(right)) - .map(([id, model]) => toPricing(providerType, id, model)) - .filter((pricing) => pricing !== undefined), - ); + for (const [id, model] of models) { + let projected; + try { + projected = { + metadata: toMetadata(sourceId, id, provider, model), + override: + model.provider === undefined + ? undefined + : toModelProviderOverride(sourceId, id, model.provider), + pricing: priced ? toPricing(providerType, id, model) : undefined, + }; + } catch (error) { + if (!onReject) throw error; + onReject('model', `${providerType}/${id}`, error); + continue; + } + metadata[providerType][id] = projected.metadata; + if (projected.override !== undefined) + providerOverrides[providerType][id] = projected.override; + if (projected.pricing !== undefined) pricing.push(projected.pricing); } } return { metadata, pricing, providerFacts, providerOverrides }; } +function assertProviderShape(sourceId, provider) { + if (!provider) { + throw new Error(`models.dev provider ${sourceId} is missing`); + } + if ( + !provider.models || + typeof provider.models !== 'object' || + Array.isArray(provider.models) || + Object.keys(provider.models).length === 0 + ) { + throw new Error(`models.dev provider ${sourceId} has no non-empty models object`); + } + if ( + typeof provider.id !== 'string' || + typeof provider.name !== 'string' || + typeof provider.doc !== 'string' + ) { + throw new Error(`models.dev provider ${sourceId} has an unsupported shape`); + } +} + async function readUpstream(refreshInputPath) { if (refreshInputPath) { return { @@ -266,9 +291,9 @@ async function readUpstream(refreshInputPath) { async function refreshSnapshot(snapshotPath, refreshInputPath, options = {}) { const { text: sourceText, etag: sourceEtag, retrievedAt } = await readUpstream(refreshInputPath); const projection = buildProjection(selectCatalog(JSON.parse(sourceText))); - const previous = await loadSnapshotIfPresent(snapshotPath); - if (previous) { - assertAcceptableRemovals(previous.projection, projection, options.acceptUpstreamRemovals); + if (!options.acceptUpstreamRemovals) { + const previous = await loadSnapshotIfPresent(snapshotPath); + if (previous) assertProjectionDoesNotShrink(previous.projection, projection); } const projectionText = JSON.stringify(projection); const snapshot = { @@ -292,25 +317,14 @@ async function refreshSnapshot(snapshotPath, refreshInputPath, options = {}) { }; } -// What --accept-upstream-removals is for: a handful of models the provider -// retired. An upstream outage serving a truncated catalog removes paths the -// same way, so the acknowledgement stops here. -const MAXIMUM_ACKNOWLEDGED_REMOVALS = 100; - -function assertAcceptableRemovals(previous, next, acknowledged) { +function assertProjectionDoesNotShrink(previous, next) { const removals = []; collectProjectionRemovals(previous, next, [], removals); if (removals.length === 0) return; - if (!acknowledged) { - throw new Error( - `models.dev refresh would remove committed projection paths: ${removals.sort().join(', ')}; inspect the upstream change and rerun with --accept-upstream-removals to acknowledge it`, - ); - } - if (removals.length > MAXIMUM_ACKNOWLEDGED_REMOVALS) { - throw new Error( - `models.dev refresh would remove ${removals.length} committed projection paths, more than the ${MAXIMUM_ACKNOWLEDGED_REMOVALS} --accept-upstream-removals acknowledges; treat a change this size as an upstream outage`, - ); - } + + throw new Error( + `models.dev refresh would remove committed projection paths: ${removals.sort().join(', ')}; inspect the upstream change and rerun with --accept-upstream-removals to acknowledge it`, + ); } function collectProjectionRemovals(previous, next, path, removals) { @@ -374,57 +388,100 @@ function projectionPath(path) { // instead of aborting the whole comparison the way a refresh does. const DRIFT_LIST_LIMIT = 20; +// Every section of the projection, flattened to one value per entity. The +// report reads sections through this table instead of naming them itself, +// which is how it went out comparing only two of the four. A section added to +// buildProjection is compared here without touching the comparison. +const PROJECTION_SECTIONS = { + metadata: entitiesByProviderAndModel, + // modelKey is `${providerType}:${id}`, so replacing the first colon yields + // the label every other section already uses. + pricing: (section) => new Map(section.map((entry) => [entry.modelKey.replace(':', '/'), entry])), + providerFacts: (section) => new Map(Object.entries(section)), + providerOverrides: entitiesByProviderAndModel, +}; + async function collectDrift(snapshot, refreshInputPath) { - const catalog = JSON.parse((await readUpstream(refreshInputPath)).text); - const previousMetadata = snapshot.projection.metadata; - const previousPricing = new Map( - snapshot.projection.pricing.map((entry) => [entry.modelKey, entry]), - ); - const report = { missingProviders: [], unprojectable: [], added: [], removed: [], changed: [] }; - for (const [providerType, sourceId] of Object.entries(PROVIDERS)) { - const provider = catalog[sourceId]; - const previousModels = previousMetadata[providerType] ?? {}; - const models = provider?.models; - if (!models || typeof models !== 'object' || Array.isArray(models)) { - report.missingProviders.push(`${providerType} (models.dev ${sourceId})`); + const rejectedProviders = []; + const rejectedModels = []; + const rejected = new Set(); + // The raw catalog, not selectCatalog's: a provider that vanished upstream is + // the report's most important finding, and selectCatalog throws on it. + const upstream = buildProjection(JSON.parse((await readUpstream(refreshInputPath)).text), { + onReject: (kind, label, error) => { + rejected.add(label); + (kind === 'provider' ? rejectedProviders : rejectedModels).push(`${label}: ${error.message}`); + }, + }); + const previous = projectionEntities(snapshot.projection); + const next = projectionEntities(upstream); + const report = { rejectedProviders, rejectedModels, added: [], removed: [], changed: [] }; + for (const label of [...new Set([...previous.keys(), ...next.keys()])].sort()) { + const before = previous.get(label); + const after = next.get(label); + if (before === undefined) { + report.added.push(label); continue; } - const priced = !PRICING_EXCLUDED_PROVIDER_TYPES.has(providerType); - const ids = [...new Set([...Object.keys(previousModels), ...Object.keys(models)])].sort(); - for (const id of ids) { - const model = models[id]; - const previous = previousModels[id]; - if (model === undefined) { - report.removed.push(`${providerType}/${id}`); - continue; - } - let metadata; - let pricing; - try { - metadata = toMetadata(sourceId, id, provider, model); - pricing = priced ? toPricing(providerType, id, model) : undefined; - } catch (error) { - report.unprojectable.push(`${providerType}/${id}: ${error.message}`); - continue; - } - if (previous === undefined) { - report.added.push(`${providerType}/${id}`); - continue; - } - const fields = driftedFields(previous, metadata); - if (priced && !sameValue(previousPricing.get(`${providerType}:${id}`), pricing)) { - fields.push('pricing'); - } - if (fields.length > 0) report.changed.push(`${providerType}/${id}: ${fields.join(', ')}`); + if (after === undefined) { + // A shape the projector rejected already has its own finding above. It + // is not upstream saying the entity is gone. + if (!isRejected(label, rejected)) report.removed.push(label); + continue; } + const fields = driftedFields(before, after); + if (fields.length > 0) report.changed.push(`${label}: ${fields.join(', ')}`); } const drifted = Object.values(report).some((entries) => entries.length > 0); return { ...report, drifted }; } +function entitiesByProviderAndModel(section) { + const entities = new Map(); + for (const [providerType, models] of Object.entries(section)) { + for (const [id, value] of Object.entries(models)) entities.set(`${providerType}/${id}`, value); + } + return entities; +} + +function projectionEntities(projection) { + const entities = new Map(); + for (const [section, flatten] of Object.entries(PROJECTION_SECTIONS)) { + for (const [label, value] of flatten(projection[section])) { + const entity = entities.get(label); + if (entity) entity[section] = value; + else entities.set(label, { [section]: value }); + } + } + return entities; +} + +function isRejected(label, rejected) { + if (rejected.has(label)) return true; + const slash = label.indexOf('/'); + return slash !== -1 && rejected.has(label.slice(0, slash)); +} + function driftedFields(previous, next) { - const keys = [...new Set([...Object.keys(previous), ...Object.keys(next)])].sort(); - return keys.filter((key) => !sameValue(previous[key], next[key])); + const fields = []; + for (const section of Object.keys(PROJECTION_SECTIONS)) { + const before = previous[section]; + const after = next[section]; + if (sameValue(before, after)) continue; + if (isPlainObject(before) && isPlainObject(after)) { + const keys = [...new Set([...Object.keys(before), ...Object.keys(after)])].sort(); + for (const key of keys) { + if (!sameValue(before[key], after[key])) fields.push(`${section}.${key}`); + } + continue; + } + fields.push(section); + } + return fields; +} + +function isPlainObject(value) { + return typeof value === 'object' && value !== null && !Array.isArray(value); } // Both sides are projector output, so their keys are already in one order. @@ -435,11 +492,11 @@ function sameValue(left, right) { function formatDrift(report) { const lines = []; for (const [label, entries] of [ - ['providers missing upstream', report.missingProviders], - ['models the projector rejects', report.unprojectable], - ['models upstream has and the snapshot does not', report.added], - ['models the snapshot has and upstream does not', report.removed], - ['models whose projection changed', report.changed], + ['providers the projector rejects', report.rejectedProviders], + ['models the projector rejects', report.rejectedModels], + ['entries upstream has and the snapshot does not', report.added], + ['entries the snapshot has and upstream does not', report.removed], + ['entries whose projection changed', report.changed], ]) { if (entries.length === 0) continue; lines.push(`${label}: ${entries.length}`); @@ -818,9 +875,10 @@ function buildPricingModule(pricing, source) { } if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) { - // Drift is a finding, not a crash: the report has already been printed, and - // the exit code is what a scheduled job branches on. - if ((await main())?.drifted) process.exitCode = 1; + // Drift is a finding, not a crash. Exit 2 so a caller can tell "upstream + // moved" from "this command failed"; both reported 1 before, which made the + // difference unreadable to the one job that has to act on it. + if ((await main())?.drifted) process.exitCode = 2; } function option(name, argv) { diff --git a/scripts/sync-model-metadata.test.mjs b/scripts/sync-model-metadata.test.mjs index eecdf11c5a..52c1e35cbf 100644 --- a/scripts/sync-model-metadata.test.mjs +++ b/scripts/sync-model-metadata.test.mjs @@ -340,7 +340,13 @@ test('drift finds nothing when the snapshot still matches upstream', async () => const { report } = await drift(['--snapshot', snapshot, '--refresh-input', input]); assert.equal(report.drifted, false); assert.deepEqual( - [report.added, report.removed, report.changed, report.unprojectable, report.missingProviders], + [ + report.added, + report.removed, + report.changed, + report.rejectedModels, + report.rejectedProviders, + ], [[], [], [], [], []], ); } finally { @@ -382,10 +388,52 @@ test('drift separates a rejected shape from a real upstream difference', async ( assert.equal(report.drifted, true); assert.deepEqual(report.added, ['anthropic/added']); assert.deepEqual(report.removed, ['anthropic/legacy']); - assert.deepEqual(report.changed, ['anthropic/model: displayName, pricing']); - assert.deepEqual(report.missingProviders, ['openai (models.dev openai)']); - assert.equal(report.unprojectable.length, 1); - assert.match(report.unprojectable[0], /^groq\/model: .*unsupported modalities/u); + assert.deepEqual(report.changed, [ + 'anthropic/model: metadata.displayName, pricing.inputUsdPer1M, pricing.outputUsdPer1M', + ]); + assert.equal(report.rejectedProviders.length, 1); + assert.match(report.rejectedProviders[0], /^openai: .*provider openai is missing/u); + assert.equal(report.rejectedModels.length, 1); + assert.match(report.rejectedModels[0], /^groq\/model: .*unsupported modalities/u); + } finally { + await rm(root, { recursive: true, force: true }); + } +}); + +test('drift reports the projection sections that carry no model metadata', async () => { + const root = await mkdtemp(join(tmpdir(), 'maka-model-drift-sections-')); + try { + const committed = join(root, 'api.json'); + const upstream = join(root, 'upstream.json'); + const snapshot = join(root, 'snapshot.json'); + const before = fixtureCatalog(); + before.anthropic.models.model.provider = { npm: '@example/before' }; + await writeFile(committed, JSON.stringify(before)); + await main([ + 'node', + 'sync-model-metadata.mjs', + '--refresh', + '--refresh-input', + committed, + '--snapshot', + snapshot, + '--output', + join(root, 'metadata.ts'), + ]); + + // Neither a renamed provider nor a swapped npm package touches a model's + // metadata or its pricing, which is all the report used to compare. + const after = JSON.parse(JSON.stringify(before)); + after.anthropic.name = 'Anthropic Renamed'; + after.anthropic.models.model.provider = { npm: '@example/after' }; + await writeFile(upstream, JSON.stringify(after)); + + const { report } = await drift(['--snapshot', snapshot, '--refresh-input', upstream]); + assert.equal(report.drifted, true); + assert.deepEqual(report.changed, [ + 'anthropic: providerFacts.name', + 'anthropic/model: providerOverrides.npm', + ]); } finally { await rm(root, { recursive: true, force: true }); } @@ -485,55 +533,6 @@ test('refresh rejects a partial provider shrink until it is explicitly accepted' } }); -test('accepting upstream removals still refuses a truncated catalog', async () => { - const root = await mkdtemp(join(tmpdir(), 'maka-model-snapshot-truncated-')); - try { - const committed = join(root, 'api.json'); - const outage = join(root, 'outage.json'); - const snapshot = join(root, 'snapshot.json'); - const metadata = join(root, 'metadata.ts'); - const full = fixtureCatalog(); - for (const provider of Object.values(full)) { - const [model] = Object.values(provider.models); - if (!model) continue; - for (const suffix of ['b', 'c', 'd']) provider.models[`model-${suffix}`] = { ...model }; - } - await writeFile(committed, JSON.stringify(full)); - await writeFile(outage, JSON.stringify(fixtureCatalog())); - await main([ - 'node', - 'sync-model-metadata.mjs', - '--refresh', - '--refresh-input', - committed, - '--snapshot', - snapshot, - '--output', - metadata, - ]); - const committedSnapshot = await readFile(snapshot, 'utf8'); - - await assert.rejects( - main([ - 'node', - 'sync-model-metadata.mjs', - '--refresh', - '--accept-upstream-removals', - '--refresh-input', - outage, - '--snapshot', - snapshot, - '--output', - metadata, - ]), - /more than the 100 --accept-upstream-removals acknowledges/u, - ); - assert.equal(await readFile(snapshot, 'utf8'), committedSnapshot); - } finally { - await rm(root, { recursive: true, force: true }); - } -}); - test('refresh rejects lost pricing coverage from an otherwise valid model', async () => { const root = await mkdtemp(join(tmpdir(), 'maka-model-snapshot-pricing-shrink-')); try { From b9e9bbb7eee043d564579501e7c727e4c44e809f Mon Sep 17 00:00:00 2001 From: AstroHan Date: Tue, 1 Sep 2026 21:04:35 +0800 Subject: [PATCH 9/9] fix(ci): let the scheduled refresh reach the pull request it exists to open The job refused --accept-upstream-removals, and the removal guard's remediation is "inspect the upstream change and rerun with the flag" -- an action only a person at a terminal can take. Upstream retires roughly seven projection paths a day, so a weekly run failed at the refresh and never reached the step that opens the pull request. A snapshot one day old was already enough: one retired openrouter model. The review seat is the draft pull request. Every removal is in its diff, the drift report is in its body, and a committer still approves before anything merges; the flag says that is where the acknowledgement happens. Three further repairs to the same step: - `gh pr view` succeeds for a CLOSED pull request. A maintainer closing an unwanted refresh would have left every later run force-pushing, printing "updated the open pull request", creating nothing, and exiting green. Only an open-state listing decides now, and the body is rewritten on update so it cannot describe an older commit. - The force push is leased, and the job refuses a branch tip it did not write, so a reviewer's commit on the open pull request survives. - The token travels in a header rather than the remote URL, which git echoes back in its own error messages. The drift step no longer swallows failure. Piping to tee discarded the exit status under the default shell, which made continue-on-error dead configuration; the step now tolerates the documented drift status and stops the job on anything else. Generated-by: Claude Code --- .github/workflows/model-metadata-upkeep.yml | 56 ++++++++++++++----- ...l-metadata-upkeep-workflow-policy.test.mjs | 26 +++++++-- 2 files changed, 62 insertions(+), 20 deletions(-) diff --git a/.github/workflows/model-metadata-upkeep.yml b/.github/workflows/model-metadata-upkeep.yml index 9960f0f3fe..07016276d0 100644 --- a/.github/workflows/model-metadata-upkeep.yml +++ b/.github/workflows/model-metadata-upkeep.yml @@ -59,10 +59,15 @@ jobs: run: npm ci --ignore-scripts - name: Report snapshot drift against models.dev - # Drift exits non-zero by design. The report is what this step is for, - # and the refresh below is what decides whether the run fails. - continue-on-error: true - run: npm run --silent check:model-metadata-drift 2>&1 | tee "$RUNNER_TEMP/drift.txt" + # Exit 2 is "upstream moved", which is the expected outcome and the + # reason this step exists. Any other non-zero status is the command + # itself failing, and the job stops on it. + run: | + npm run --silent check:model-metadata-drift > "$RUNNER_TEMP/drift.txt" || { + status=$? + cat "$RUNNER_TEMP/drift.txt" + [ "$status" -eq 2 ] || exit "$status" + } - name: Publish the drift report run: | @@ -74,11 +79,13 @@ jobs: echo '```' } >> "$GITHUB_STEP_SUMMARY" - # No --accept-upstream-removals. A model leaving upstream is a decision - # for a person, so the job fails and says so rather than committing the - # removal into a pull request nobody asked for. + # --accept-upstream-removals, because the review seat this job is built + # around is the draft pull request below. A person still inspects every + # removal and still decides, in the diff, with the drift report in the + # body; refusing here would only make the job red every week, since it + # cannot rerun itself the way the acknowledgement asks a human to. - name: Refresh the snapshot from models.dev - run: npm run refresh:model-metadata + run: npm run refresh:model-metadata -- --accept-upstream-removals - name: Verify the regenerated outputs run: npm run check:model-metadata @@ -122,12 +129,33 @@ jobs: git switch -c "$BRANCH" git add scripts/model-metadata/models-dev-api.snapshot.json git commit -m "$TITLE" - git push --force \ - "https://x-access-token:${GH_TOKEN}@github.com/${GITHUB_REPOSITORY}" \ - "HEAD:refs/heads/$BRANCH" - # A force push updates an open pull request in place, so only open one - # when none is waiting. - if gh pr view "$BRANCH" --json number >/dev/null 2>&1; then + # The token travels in a header rather than the remote URL, which git + # echoes back in its own error messages. + AUTH="$(printf 'x-access-token:%s' "$GH_TOKEN" | base64 | tr -d '\n')" + REMOTE="https://github.com/${GITHUB_REPOSITORY}" + TIP="$(git -c "http.extraheader=Authorization: Basic $AUTH" \ + ls-remote "$REMOTE" "refs/heads/$BRANCH" | cut -f1)" + if [ -n "$TIP" ]; then + # This branch only ever carries commits this job wrote. Anything + # else is a person working on the open pull request, and a force + # push would erase it. + git -c "http.extraheader=Authorization: Basic $AUTH" \ + fetch --depth=1 "$REMOTE" "refs/heads/$BRANCH" + if [ "$(git log -1 --format=%s FETCH_HEAD)" != "$TITLE" ]; then + echo "::error::$BRANCH carries a commit this workflow did not write; refusing to overwrite it." + exit 1 + fi + git -c "http.extraheader=Authorization: Basic $AUTH" push \ + "--force-with-lease=refs/heads/$BRANCH:$TIP" "$REMOTE" "HEAD:refs/heads/$BRANCH" + else + git -c "http.extraheader=Authorization: Basic $AUTH" push \ + "$REMOTE" "HEAD:refs/heads/$BRANCH" + fi + # A plain existence lookup also succeeds for a closed pull request, + # which would leave a maintainer's decision to close one silently + # disabling this job forever. Only an open one is one to update. + if [ "$(gh pr list --head "$BRANCH" --state open --json number --jq 'length')" -gt 0 ]; then + gh pr edit "$BRANCH" --body-file "$RUNNER_TEMP/pr-body.md" echo "Updated the open pull request on $BRANCH." else gh pr create --draft --base main --head "$BRANCH" \ diff --git a/scripts/model-metadata-upkeep-workflow-policy.test.mjs b/scripts/model-metadata-upkeep-workflow-policy.test.mjs index 2c3884c76c..8e82644b2a 100644 --- a/scripts/model-metadata-upkeep-workflow-policy.test.mjs +++ b/scripts/model-metadata-upkeep-workflow-policy.test.mjs @@ -66,7 +66,7 @@ test('only the scheduled job writes, and only on the canonical repository', asyn assert.equal(stepNamed(workflow, 'Check out the repository').with['persist-credentials'], false); }); -test('the refresh reports drift first and refuses to waive upstream removals', async () => { +test('the refresh reports drift before it writes, and tolerates only drift', async () => { const workflow = await readUpkeepWorkflow(); const order = [ 'Report snapshot drift against models.dev', @@ -74,11 +74,11 @@ test('the refresh reports drift first and refuses to waive upstream removals', a ].map((name) => workflow.jobs.refresh.steps.findIndex((step) => step.name === name)); assert.ok(order.every((position) => position >= 0)); assert.ok(order[0] < order[1]); - assert.equal( - stepNamed(workflow, 'Report snapshot drift against models.dev')['continue-on-error'], - true, - ); - assert.doesNotMatch(JSON.stringify(workflow), /--accept-upstream-removals/u); + const drift = stepNamed(workflow, 'Report snapshot drift against models.dev'); + // A blanket continue-on-error would hide the command failing outright. Only + // the documented drift status is tolerated. + assert.equal(drift['continue-on-error'], undefined); + assert.match(drift.run, /\[ "\$status" -eq 2 \] \|\| exit "\$status"/u); }); test('the pull request is opened for review and never merged by the job', async () => { @@ -86,6 +86,20 @@ test('the pull request is opened for review and never merged by the job', async const open = stepNamed(workflow, 'Open the review pull request'); assert.match(open.run, /gh pr create --draft/u); assert.doesNotMatch(JSON.stringify(workflow), /gh pr merge|--auto\b|--admin\b/u); + // A closed pull request must not read as one to update; gh pr view says it + // does, so only an open-state listing decides. + assert.doesNotMatch(open.run, /gh pr view/u); + assert.match(open.run, /gh pr list --head "\$BRANCH" --state open/u); +}); + +test('the branch this job pushes never loses a commit someone else wrote', async () => { + const workflow = await readUpkeepWorkflow(); + const open = stepNamed(workflow, 'Open the review pull request'); + assert.doesNotMatch(open.run, /push\s+--force\b|push\s+-f\b/u); + assert.match(open.run, /--force-with-lease=refs\/heads\/\$BRANCH:\$TIP/u); + // The token belongs in a header. A remote URL carrying it is echoed back by + // git's own error messages. + assert.doesNotMatch(JSON.stringify(workflow), /x-access-token:\$\{?GH_TOKEN/u); }); test('the drift check stays out of the checks that run on every pull request', async () => {