Compare commits

..

470 Commits

Author SHA1 Message Date
Aiden Cline 458b7f4d1a use Venice context tier thresholds 2026-05-12 17:39:40 -05:00
Aiden Cline 8f9adc7567 fix generated tier change detection 2026-05-12 17:01:35 -05:00
Aiden Cline a671cc05d5 align cost tiers with model schema 2026-05-12 16:01:49 -05:00
Aiden Cline 2e015de42d preserve generated tier thresholds 2026-05-11 17:07:19 -05:00
Aiden Cline 151e9c9071 fix tiered cost generation 2026-05-11 16:43:32 -05:00
Aiden Cline b96b074a3b fix long-context cost tier omissions 2026-05-11 16:31:07 -05:00
Aiden Cline 2593e131a1 wip 2026-05-11 16:11:19 -05:00
Frank bc95b42ccd update zen models 2026-05-11 11:26:08 -04:00
Aiden Cline 6139fb8c69 Merge pull request #1598 from mugnimaestra/feat/chutes-generate-script
feat(chutes): add API-driven model generator script
2026-05-11 09:30:38 -05:00
Aiden Cline 3070758007 Merge pull request #1678 from 5kahoisaac/chore/nvidia-models
Sync NVIDIA endpoint model catalog
2026-05-11 09:29:54 -05:00
Frank 5525e83de4 update zen models 2026-05-11 10:00:09 -04:00
Frank 359fd879b8 update zen models 2026-05-10 03:54:03 -04:00
Frank 01b5a1a656 update zen models 2026-05-10 02:52:44 -04:00
Frank b1958be099 update zen models 2026-05-10 02:42:44 -04:00
Aiden Cline 08aa068523 Temporarily remove kiro provider and models 2026-05-10 01:19:47 -05:00
Aiden Cline f31ad0b02f Merge pull request #1738 from mattiacerutti/chore/remove-gh-copilot-deprecated
chore(copilot): mark deprecated models
2026-05-09 15:42:19 -05:00
Aiden Cline 585aa7fa1b Merge pull request #1741 from EriDeLee/dev
Update aihubmix models
2026-05-09 15:42:03 -05:00
Aiden Cline c42a327b3e Merge pull request #1745 from mads-digitial-solutions/patch-1
Update Google provider docs url from pricing page to models page
2026-05-09 15:41:51 -05:00
mads-digitial-solutions 92ebbfb5c4 Update provider.toml
Update Google provider docs URL from the pricing page to the models page
2026-05-09 19:49:19 +01:00
Aiden Cline 535fe8c971 Merge pull request #1744 from OpeOginni/fix/bedrock-model-ids
chore(bedrock): Getting rid of legacy Amazon Bedrock model offerings
2026-05-09 13:48:52 -05:00
OpeOginni a3b4bfc16c fix(bedrock): remove uneeded model configurations 2026-05-09 20:35:34 +02:00
OpeOginni d0fcd6f11f fix(bedrock): align models with current docs 2026-05-09 20:29:11 +02:00
OpeOginni e55cd54218 fix(bedrock): remove legacy model entries 2026-05-09 20:21:33 +02:00
OpeOginni 0d73b82b9f fix(bedrock): restore regional model IDs 2026-05-09 20:18:59 +02:00
Aiden Cline 83c7e2b63f Merge pull request #1742 from Adam8234/add-firepass-provider
feat: add Fireworks (Firepass) provider
2026-05-09 12:45:09 -05:00
Adam 83ae4cf813 feat: add Fireworks (Firepass) provider
Adds the Fireworks AI Firepass subscription provider.
- Provider uses a dedicated FIREPASS_API_KEY
- Uses @ai-sdk/openai-compatible SDK
- Includes Kimi K2.6 Turbo (accounts/fireworks/routers/kimi-k2p6-turbo)
- Zero per-token cost since covered by subscription
2026-05-09 12:22:13 -05:00
EriDeLee 77eae6eef7 Update aihubmix models 2026-05-09 20:53:57 +08:00
Aiden Cline 8cbf6ed10e Merge pull request #1736 from vercel/update-vercel-models-1778258030
Update Vercel models
2026-05-08 21:58:40 -05:00
Mattia Cerutti 06d87e4411 chore(copilot): remove deprecated models 2026-05-09 00:19:50 +02:00
Frank 2cb3832618 update zen models 2026-05-08 17:11:05 -04:00
github-actions[bot] df960d1a90 chore(vercel): update Vercel model definitions
Auto-generated by weekly workflow from Vercel AI Gateway API.

Co-Authored-By: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-05-08 16:33:52 +00:00
Aiden Cline 8f2f83ef61 Merge pull request #1735 from slpdy/dev
Create DeepSeek-V4-Pro.toml
2026-05-08 10:59:33 -05:00
Aiden Cline b133426465 Merge pull request #1734 from oskarkocol/chore/update-novita-deepseek-prices
chore: update novita deepseek-v4-pro prices
2026-05-08 10:59:25 -05:00
Aiden Cline dafff5a770 Merge pull request #1730 from smakosh/add-llmgateway-models
Add new LLM Gateway text models (gpt-5.5, grok-4-3, gemini-3.1-flash-lite, qwen3.6, MiMo v2)
2026-05-08 10:58:20 -05:00
smakosh dd894f077f Merge remote-tracking branch 'upstream/dev' into add-llmgateway-models
# Conflicts:
#	providers/google/models/gemini-3.1-flash-lite.toml
2026-05-08 17:46:52 +02:00
smakosh 91590874e7 Revert "fix(models): use canonical entries for qwen3.6-max-preview and grok-4.3"
This reverts commit 70ac6fccda.
2026-05-08 17:43:07 +02:00
Jj a436236146 Create DeepSeek-V4-Pro.toml
Added DeepSeek-v4-Pro model to Nebius provider
2026-05-08 11:03:16 +01:00
oskar 1415b4be97 chore: update novita deepseek prices 2026-05-08 14:21:27 +07:00
Aiden Cline 1437da86e7 Merge pull request #1685 from 8023/dev
Add kimi-k2.6/deepseek-v4 model and EmpirioLabs AI integration for poe.com
2026-05-07 22:38:51 -05:00
Aiden Cline e7d57885d1 Merge pull request #1733 from chl-0537/feature/add-tencent
add model by openrouter
2026-05-07 22:21:07 -05:00
Aiden Cline 8157916515 fix: attachment 2026-05-07 22:12:11 -05:00
Aiden Cline 2e5b87a9c2 Merge pull request #1731 from mikeyp/chore/update-digitalocean-models
Add script to generate/update Digitalocean models
2026-05-07 16:42:09 -05:00
Aiden Cline 92e19432d3 add google gemini 3.1 flash lite 2026-05-07 15:44:25 -05:00
smakosh 70ac6fccda fix(models): use canonical entries for qwen3.6-max-preview and grok-4.3
Apply the canonical TOML provided by the LLM Gateway team for the
Qwen3.6 Max Preview and Grok 4.3 parent definitions, replacing the
upstream-merged variants whose dates and pricing did not match.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 22:34:01 +02:00
smakosh dc3283417d Merge remote-tracking branch 'upstream/dev' into add-llmgateway-models
# Conflicts:
#	providers/alibaba/models/qwen3.6-max-preview.toml
#	providers/llmgateway/models/qwen3.6-max-preview.toml
2026-05-07 22:28:23 +02:00
smakosh 34fd6673e5 chore(llmgateway): add new text models from llmgateway catalog
Add gemini-3.1-flash-lite, grok-4-3, gpt-5.5, gpt-5.5-pro, qwen3.6
and MiMo v2 models that exist in llmgateway.io but were missing
from models.dev. Adds parent definitions for grok-4-3,
gemini-3.1-flash-lite, and qwen3.6-max-preview where they did not
already exist.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 22:20:52 +02:00
Mike Prasuhn 5df9293314 Add script to generate/update Digitalocean models 2026-05-07 15:28:07 -04:00
Aiden Cline a81a9559d7 Merge pull request #1726 from Ardakilic/chore/sync-kilo-models
Chore: Sync Kilo models with upstream gateway
2026-05-07 13:04:51 -05:00
Aiden Cline 4197bf57a6 Merge pull request #1725 from dpuyosa/chore/venice-grok-costs
Venice: Update grok-4-20 pricing
2026-05-07 13:04:26 -05:00
Aiden Cline d0ac772507 Merge pull request #1717 from juls0730/refactor/mimo-extends/token-plan
refactor(xiaomi-token-plan): extends xiaomi base provider for xiaomi token plans
2026-05-07 13:04:05 -05:00
Aiden Cline 1afaa053e7 Merge pull request #1727 from sergeykonkin/update-nebius-models-2026-05
chore: update nebius provider models
2026-05-07 13:03:46 -05:00
Aiden Cline 9b77ce1c9e Merge pull request #1729 from Sewer56/add-minimax-m27-wafer
Added: MiniMax-M2.7 model for wafer.ai
2026-05-07 12:59:49 -05:00
Aiden Cline 68dc6d1820 Merge pull request #1728 from arafatkatze/codex/openrouter-qwen-cache-pricing
Add OpenRouter Qwen cache pricing
2026-05-07 12:59:29 -05:00
Arafatkatze a1eb5eece3 Add OpenRouter Qwen cache pricing 2026-05-07 10:29:48 -07:00
Sewer56 f7ec2c517f Added: wafer.ai/MiniMax-M2.7 model 2026-05-07 18:12:50 +01:00
Sergey Konkin f98e8ec793 chore: update nebius provider models 2026-05-07 15:37:18 +02:00
Arda Kilicdagi d210066793 chore: sync kilo gw models 2026-05-07 14:17:15 +03:00
Frank 06908cbf36 update zen models 2026-05-07 04:47:22 -04:00
dpuyosa b0614d2088 [venice] Update grok-4-20 pricing
- Lower grok-4-20 and multi-agent input/output costs to latest Venice pricing
2026-05-07 10:29:48 +02:00
mickalchen 32c1c45c52 add openrouter model 2026-05-07 11:22:11 +08:00
Frank 7c033f27e6 update zen models 2026-05-06 23:00:15 -04:00
mickalchen d648e63499 Merge remote-tracking branch 'origin/dev' into feature/add-tencent 2026-05-07 10:54:56 +08:00
Zoe 1353f965b9 refactor(xiaomi-token-plan): extends xiaomi base provider for xiaomi token plan 2026-05-06 18:53:49 -05:00
Aiden Cline bba0a9c3f4 Merge pull request #1312 from NachoFLizaur/feat/kiro-provider
feat: add Kiro provider with 12 models
2026-05-06 12:16:47 -05:00
Frank 4bdb195178 update zen models 2026-05-06 12:56:58 -04:00
Aiden Cline 12706b7652 Merge pull request #1716 from juls0730/refactor/mimo-extends/zenmux
refactor(zenmux): extends mimo models from xiaomi provider
2026-05-06 10:45:01 -05:00
Aiden Cline d8c76d0c67 Merge pull request #1715 from juls0730/refactor/mimo-extends/qiniu-ai
refactor(qiniu-ai): extends mimo models from xiaomi provider
2026-05-06 10:30:46 -05:00
Aiden Cline 3963dd13d5 Merge pull request #1714 from juls0730/refactor/mimo-extends/openrouter
refactor(openrouter): extends mimo models from xiaomi provider
2026-05-06 10:30:32 -05:00
Aiden Cline 8749a56efa Merge pull request #1711 from juls0730/refactor/mimo-extends/kilo
refactor(kilo/xiaomi): extends mimo models from xiaomi provider
2026-05-06 10:29:31 -05:00
Aiden Cline 25de2ee27d Merge pull request #1718 from juls0730/refactor/mimo-extends/xiaomi
refactor(xiaomi): round xiaomi models to powers of 2 & fix small errors
2026-05-06 10:27:36 -05:00
Aiden Cline 438df7f03c Merge pull request #1723 from CloudFerro/fix/cloudferro-sherlock/minimax-m2.5
fix: cloudferro sherlock - update context values for minimax m2.5
2026-05-06 10:25:54 -05:00
Aiden Cline 7d18558aa3 Merge pull request #1722 from dpuyosa/chore/venice-model-updates
Venice: Remove deprecated models, enable reasoning on gpt-oss-120b
2026-05-06 10:25:36 -05:00
Jan Szypulski c82f736fcc fix: cloudferro sherlock - update context values for minimax m2.5 2026-05-06 10:52:39 +02:00
dpuyosa 6a436805b3 [venice] Remove deprecated models, enable reasoning on gpt-oss-120b
- Remove kimi-k2-thinking, qwen3-coder-480b-a35b-instruct, and venice-uncensored models
- Enable reasoning capability on openai-gpt-oss-120b
2026-05-06 09:44:24 +02:00
Jack ce7823f073 Merge pull request #1720 from anomalyco/fix/opencode-go-kimi-k26-pricing
fix(opencode-go): restore kimi k2.6 pricing
2026-05-06 12:33:24 +08:00
Jack 033efdb7d4 fix(opencode-go): restore kimi k2.6 pricing 2026-05-06 12:32:06 +08:00
Zoe bd9e0c2677 refactor(xiaomi): round xiaomi models to powers of 2 & fix small errors 2026-05-05 18:40:05 -05:00
Zoe 38545d63a5 refactor(zenmux): extends mimo models from xiaomi provider 2026-05-05 18:17:21 -05:00
Zoe 014be328d6 refactor(qiniu-ai): extends mimo models from xiaomi provider 2026-05-05 18:05:39 -05:00
Zoe c139147540 refactor(openrouter): extends mimo models from xiaomi provider 2026-05-05 17:49:39 -05:00
Zoe 59cd93cafc refactor(kilo/xiaomi): extends mimo models from xiaomi provider 2026-05-05 17:13:06 -05:00
Aiden Cline e91db96d83 Merge pull request #1710 from Spherrrical/add-digitalocean-kimi-2-6
feat(digitalocean): add kimi-k2.6 model
2026-05-05 14:07:50 -05:00
Spherrrical d70dd8dcdc feat(digitalocean): add kimi-k2.6 model 2026-05-05 12:05:16 -07:00
Frank b18e681457 update deepseek flash on deepinfra 2026-05-05 14:24:03 -04:00
Aiden Cline b73a6a2130 Merge pull request #1709 from xiaomochn/fix/xiaomi-mimo-v2.5-modalities
fix(xiaomi): swap modalities for MiMo-V2.5 and MiMo-V2.5-Pro
2026-05-05 11:36:43 -05:00
Aiden Cline 153c1cc420 Merge pull request #1614 from Yashwanth-Kumar-26/patch-1
Add Qwen 3.6 27B model configuration
2026-05-05 11:22:43 -05:00
Aiden Cline ca0b30569e update google vertex to include all anthropic models 2026-05-05 11:12:23 -05:00
xiaomochn 8345bfbd06 fix(xiaomi): correct modalities for MiMo V2.5 models across providers
Issues fixed:
1. MiMo-V2.5 and MiMo-V2.5-Pro had their modalities swapped in the
   xiaomi canonical source (affects OpenRouter/ZenMux via extends)
2. Removed 'pdf' from V2.5 models — not a supported input modality
3. Fixed vercel provider: V2.5-Pro incorrectly marked as multimodal
4. Fixed opencode-go and vercel V2.5: added missing 'video', removed pdf

Correct modalities:
- MiMo-V2.5: input = ["text", "image", "audio", "video"]
- MiMo-V2.5-Pro: input = ["text"]

Affected providers: xiaomi, opencode-go, vercel, openrouter (extends),
zenmux (extends)

Fixes #1708
2026-05-05 22:46:44 +08:00
Aiden Cline c16f3da694 Merge pull request #1707 from deathbeam/revert-1664-fix/glm-qwen-ollama-output-limit
Revert "fix(ollama): set glm-5.1 and qwen3.5:397b output limits to match context"
2026-05-04 23:51:53 -05:00
Tomas Slusny 6aa6e55d60 fix(ollam): use correct output limit for qwen3.5:397b
{"error":"max_tokens (262144) exceeds model's maximum output tokens (65536) for model qwen3.5:397b (ref: 8554a681-e6a8-45d7-9fdd-433785eb6c67)"}

Signed-off-by: Tomas Slusny <slusnucky@gmail.com>
2026-05-05 01:31:20 +02:00
Tomas Slusny 9efaf754a5 Revert "fix(ollama): set glm-5.1 and qwen3.5:397b output limits to match context" 2026-05-05 01:04:11 +02:00
Aiden Cline 104e4bdc1f Merge pull request #1684 from TheBaconWizard/add-clarifai-kimi-k2.6
provider(clarifai): add Kimi-K2.6 (moonshotai/chat-completion)
2026-05-04 12:00:33 -05:00
Aiden Cline db16c113f7 Merge pull request #1704 from stylings/stylings/add-openrouter-grok-4-3
feat: add OpenRouter Grok 4.3
2026-05-04 12:00:08 -05:00
Alex 64a122a13d fix: update OpenRouter Grok 4.3 file 2026-05-04 12:44:07 -04:00
Alex fcc6521d1d fix: simplify OpenRouter Grok 4.3 file 2026-05-04 12:41:56 -04:00
Alex c623b4a55f feat: add OpenRouter Grok 4.3 2026-05-04 12:36:33 -04:00
Aiden Cline 1d730fea16 Merge pull request #1696 from cgilly2fast/dev
chore(frogbot): convert firmware provider to frogbot
2026-05-04 10:26:36 -05:00
Aiden Cline 5457215e29 Merge pull request #1650 from PedroACosta/feat/add-dinference-models
feat(dinference): add GLM-5.1 and MiniMax-M2.5 models
2026-05-04 10:26:02 -05:00
Aiden Cline b3ab45990f Merge pull request #1697 from rocuevas9511/feat/add-deepinfra-gemma4
add gemma4 26b a4b and 31b to deepinfra
2026-05-04 10:25:31 -05:00
Aiden Cline d906a07e31 Merge pull request #1703 from dpuyosa/feat/venice-grok-4-3
Venice: Add Grok 4.3 model configuration
2026-05-04 10:25:16 -05:00
dpuyosa 4b1f6edd52 [venice] Add Grok 4.3 model configuration
- Add Grok 4.3 model with 1M context and 32K output
- Configure standard and >200K cost tiers
- Enable text+image input with text output modalities
2026-05-04 09:54:01 +02:00
Aiden Cline a92a2cfe3d Merge pull request #1702 from langyo/fix/glm-5v-turbo-naming
fix: use proper GLM family casing for GLM-5V-Turbo
2026-05-03 16:53:44 -05:00
Aiden Cline 70891f58e5 Merge pull request #1701 from kaeltrn/add-perplexity-agent-opus-4-7-gpt-5-5
Add Claude Opus 4.7 and GPT-5.5 models for perplexity-agent
2026-05-03 16:53:26 -05:00
Aiden Cline 1600c827fc Merge pull request #1698 from tim-mcdonald/add-kimi-k2.6-nvidia
Add Kimi K2.6 model for NVIDIA provider
2026-05-03 16:53:01 -05:00
Aiden Cline 5851cdc136 Merge pull request #1700 from JDinABox/dev
Add Synthetic Kimi-K2.6 model configuration
2026-05-03 16:52:46 -05:00
langyo 4fd0e38c58 fix: use proper GLM family casing for GLM-5V-Turbo
- Rename glm-5v-turbo to GLM-5V-Turbo in zai, zhipuai, and 302ai providers
- Add GLM-5V-Turbo back to zhipuai-coding-plan (removed in #1589)

Ref: #1589
2026-05-04 00:51:54 +08:00
Pedro dd685ea42c refactor(dinference): use extends format for GLM and MiniMax models 2026-05-03 17:54:18 +02:00
kaeltrn 7835298241 Add Claude Opus 4.7 and GPT-5.5 models for perplexity-agent 2026-05-03 20:09:14 +07:00
Isaac Ng c5fbcc2c9b 📦 CHORE: remove senera 2026-05-03 16:17:37 +08:00
Isaac Ng ab2eb51b4e chore(nvidia): align Nemotron endpoint slugs
Replace stale NVIDIA Nemotron entries with the live Build catalog slugs so the local provider catalog matches current free and partner endpoints.
2026-05-03 15:47:19 +08:00
Isaac Ng 8e19ec580c 📦 CHORE: sync latest nvidia model 2026-05-03 15:19:17 +08:00
Isaac Ng 3aecc94c46 chore(nvidia): sync endpoint model catalog
Update NVIDIA model TOMLs to match the live Build endpoint list by removing stale entries and adding missing ones.

This keeps the provider catalog aligned with the current free and partner endpoint inventory.
2026-05-03 14:47:30 +08:00
JD Crawford 2ac7912ee7 use extends format 2026-05-03 01:04:53 -04:00
JD Crawford 9ac5b5f625 Add Synthetic Kimi-K2.6 model configuration 2026-05-03 00:17:37 -04:00
Aiden Cline 8c4d9f4696 Merge pull request #1699 from cfal/qwen3.6-max-preview
providers/alibaba/models/qwen3.6-max-preview.toml: add qwen 3.6 max
2026-05-02 21:35:02 -05:00
cfal c4bb0b4b11 providers/alibaba/models/qwen3.6-max-preview.toml: add qwen 3.6 max 2026-05-03 09:25:31 +08:00
Tim McDonald db4d03c171 Add Kimi K2.6 model for NVIDIA provider 2026-05-02 16:09:37 -06:00
rocuevas9511 60d1d4df77 add gemma4 26b a4b and 31b to deepinfra 2026-05-02 14:26:19 -06:00
Colby Gilbert 31654fc2ef chore(frogbot): convert firmware provider to frogbot 2026-05-02 12:36:20 -07:00
Aiden Cline 01e56b1e1e Merge pull request #1682 from varunrandery/poolside/laguna-openrouter
Add Poolside Laguna series models (OpenRouter)
2026-05-02 14:30:20 -05:00
Aiden Cline 4a7d9275d6 Merge pull request #1695 from hgraca/cortecs
Cortecs
2026-05-02 14:04:00 -05:00
Aiden Cline 978fe11e0c Merge pull request #1694 from cgilly2fast/dev
feat(firmware): add deepseek v4, remove gemini 3 pro add gpt 5.4 min,…
2026-05-02 14:03:14 -05:00
Herberto Graca 0b4198955f refactor(cortecs): use extends for models with canonical bases
Convert 7 Cortecs models to extends format, inheriting from their
canonical provider definitions (deepseek, llama, mistral, alibaba).
Reduces duplication by ~55 lines while preserving Cortecs-specific
cost overrides.
2026-05-02 20:56:11 +02:00
Herberto Graca 66b568b681 Add deepseek-v4-pro model for cortecs 2026-05-02 20:56:11 +02:00
Herberto Graca 589fddeed7 Add codestral-2508 model for cortecs 2026-05-02 20:56:10 +02:00
Herberto Graca 6f75266d42 Add deepseek-v3.2 model for cortecs 2026-05-02 20:56:10 +02:00
Herberto Graca 0f03115ee0 Add deepseek-r1-0528 model for cortecs 2026-05-02 20:56:09 +02:00
Herberto Graca ae2564edc2 Add mixtral-8x7B-instruct-v0.1 model for cortecs 2026-05-02 20:56:09 +02:00
Herberto Graca 629856cf41 Add hermes-4-70b model for cortecs 2026-05-02 20:56:08 +02:00
Herberto Graca 567bc13ab4 Add llama-3.3-70b-instruct model for cortecs 2026-05-02 20:56:08 +02:00
Herberto Graca 5eac173bc5 Add qwen3-235b-a22b-instruct-2507 model for cortecs 2026-05-02 20:56:07 +02:00
Herberto Graca cb0d640afd Add qwen3-coder-30b-a3b-instruct model for cortecs 2026-05-02 20:56:07 +02:00
Herberto Graca b5e27e652f Add nemotron-3-super-120b-a12b model for cortecs 2026-05-02 20:56:06 +02:00
Herberto Graca 650c27411f Add qwen3.5-122b-a10b model for cortecs 2026-05-02 20:56:06 +02:00
Herberto Graca 98c55325bf Add mistral-large-2512 model for cortecs 2026-05-02 20:56:05 +02:00
Herberto Graca 2fdd33b8a7 Add qwen3.5-397b-a17b model for cortecs 2026-05-02 20:55:57 +02:00
Colby Gilbert e4dea0a3d8 feat(firmware): grok 4.3 2026-05-02 10:53:24 -07:00
Colby Gilbert b4b3622bfd feat(firmware): add deepseek v4, remove gemini 3 pro add gpt 5.4 min, add gpt 5.4 nano, add gpt 5.5, and minimax m2.7 2026-05-02 09:23:42 -07:00
Aiden Cline 3b35b5598a Merge pull request #1693 from hgraca/add-deepseek-v4-flash-cortecs
Add deepseek-v4-flash model for cortecs
2026-05-02 10:46:57 -05:00
Aiden Cline d2e16bab34 Merge pull request #1610 from monotykamary/feat/neuralwatt-provider
feat: add neuralwatt provider with 14 models
2026-05-02 10:45:50 -05:00
Tom X Nguyen 051dc6236a fix(neuralwatt): sync model capabilities with provider API 2026-05-02 20:42:00 +07:00
Herberto Graca 5b9dee1f3d Add deepseek-v4-flash model for cortecs 2026-05-02 12:50:59 +02:00
8023 426dfe7be5 fix validate error 2026-05-02 12:15:50 +08:00
8023 fddfb083d1 add EmpirioLabs AI and deepseek v4 2026-05-02 11:14:51 +08:00
8023 4eccfaba87 Add Kimi-K2.6 model configuration file 2026-05-02 11:08:32 +08:00
Jeff Lim ea46d016d3 fix(clarifai): drop redundant cost override for Kimi-K2.6
Clarifai's published pricing ($0.95 input, $4.00 output) matches the
canonical moonshotai/kimi-k2.6, so the explicit [cost] block was just
duplicating upstream. Inherit it via extends instead.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 18:20:39 -07:00
Jeff Lim 1bd1449ec5 provider(clarifai): add Kimi-K2.6 (moonshotai/chat-completion)
Extends moonshotai/kimi-k2.6 with Clarifai-specific cost and modalities
(text+image only on Clarifai; cache pricing not exposed).

Model URL: https://clarifai.com/moonshotai/chat-completion/models/Kimi-K2_6

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 18:14:19 -07:00
Varun Randery 7d334a51c9 Add Laguna models 2026-05-01 23:35:13 +01:00
Aiden Cline 10ae0b5a1d Merge pull request #1664 from fernandoenzo/fix/glm-qwen-ollama-output-limit
fix(ollama): set glm-5.1 and qwen3.5:397b output limits to match context
2026-05-01 15:50:22 -05:00
Aiden Cline d25cce170d Merge pull request #1665 from Ardakilic/chore/cleanup-kilo-provider
Chore: Sync Kilo Gateway provider models with upstream API changes and add Owl Alpha model.
2026-05-01 15:49:53 -05:00
Aiden Cline 3e097a5d89 Merge pull request #1671 from hgraca/add-qwen-2.5-72b-instruct-cortecs
Add qwen-2.5-72b-instruct model for cortecs
2026-05-01 15:49:28 -05:00
Aiden Cline 074b38eb98 Merge pull request #1663 from fernandoenzo/fix/minimax-m2.7-ollama-context-output-limit
fix(ollama): set minimax-m2.7 context and output limits to match Ollama API
2026-05-01 14:24:35 -05:00
Aiden Cline d474922588 Merge pull request #1679 from Spherrrical/add-digitalocean-deepseek-v4-pro
feat(digitalocean): add deepseek-v4-pro model
2026-05-01 13:46:50 -05:00
Spherrrical 56ddb9017c feat(digitalocean): add deepseek-v4-pro model 2026-05-01 11:20:09 -07:00
Rohan Taneja a565bbebc0 Merge pull request #1677 from vercel/update-vercel-models-1777652649 2026-05-01 10:47:39 -07:00
github-actions[bot] 5b97fca592 chore(vercel): update Vercel model definitions
Auto-generated by weekly workflow from Vercel AI Gateway API.

Co-Authored-By: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-05-01 16:24:16 +00:00
Arda Kilicdagi aec3f94081 feat: owl alpha, chore: sync kilo code upstream
feat: owl alpha, chore: sync kilo code upstream
2026-05-01 14:09:51 +03:00
Fernando Guarini e5c63d671e fix(ollama): set glm-5.1 and qwen3.5:397b output limits to match context 2026-05-01 11:29:49 +02:00
Fernando Guarini 22e87ab31b fix(ollama): set minimax-m2.7 context and output limits to match Ollama API 2026-05-01 11:29:41 +02:00
Herberto Graca 97d93676bc Add qwen-2.5-72b-instruct model for cortecs 2026-05-01 09:36:16 +02:00
Aiden Cline 692fbd0f19 Merge pull request #1628 from fanweixiao/dev
provider(vivgrid): remove GLM-5, add GPT-5.5 and DeepSeek-v4-Pro model
2026-04-30 23:57:52 -05:00
C.C. Fan c3bd263a67 provider(vivgrid): add deepseek-v4-pro model
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-01 11:46:39 +08:00
Aiden Cline 9b9685c297 Merge pull request #1658 from v1gnesh/dev
Create grok-4.3.toml
2026-04-30 22:46:08 -05:00
C.C. Fan b3f063da79 provider(vivgrid): use extends for gpt-5.5 instead of duplicating fields
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-01 11:45:13 +08:00
C.C. a33d0aea81 Merge branch 'anomalyco:dev' into dev 2026-05-01 11:38:42 +08:00
v1gnesh ca380a136e Create grok-4.3.toml 2026-05-01 08:17:12 +05:30
Arda Kılıçdağı dfa186a768 feat: owl alpha 2026-05-01 01:47:25 +03:00
Aiden Cline d63ffa53e8 Merge pull request #1654 from zainhas/dev
[Together AI] add qwen 3.6 plus
2026-04-30 16:34:28 -05:00
Aiden Cline 284def86ef Merge pull request #1653 from smakosh/feat/llmgateway-add-gpt-5-5-and-qwen3-6
feat(llmgateway): add gpt-5.5, gpt-5.5-pro, qwen3.6-35b-a3b, qwen3.6-plus, qwen3.6-max-preview
2026-04-30 16:34:18 -05:00
Siddharth Dhulipalla c19936565d Remove Fire Pass from Fireworks Kimi K2.5 Turbo description (#1655) 2026-04-30 17:28:36 -04:00
Zain Hasan 73b872e141 output 500_000 2026-04-30 14:22:41 -07:00
Zain Hasan 7373bb5878 [Together AI] add qwen 3.6 plus 2026-04-30 14:21:40 -07:00
smakosh d11c151c25 feat(llmgateway): add gpt-5.5, gpt-5.5-pro, qwen3.6-35b-a3b, qwen3.6-plus, qwen3.6-max-preview
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-30 22:05:40 +02:00
Aiden Cline f3f4fea66c Merge pull request #1645 from stylings/stylings/add-mistral-medium-3-5
feat: add Mistral Medium 3.5
2026-04-30 14:37:16 -05:00
Aiden Cline 90116256a6 Merge pull request #1652 from Spherrrical/add-digitalocean-provider
feat(digitalocean): sync model catalog
2026-04-30 14:32:07 -05:00
Spherrrical 5008df8bcc feat(digitalocean): sync model catalog with /v1/models API
Add 16 new models (anthropic, openai, alibaba, deepseek, google,
meta, mistral, nvidia, baai, intfloat, fal-hosted) to match the
current DigitalOcean Gradient AI Platform catalog, and rename
openai-gpt-5-2-pro to openai-gpt-5.2-pro to match the API id.
2026-04-30 12:08:57 -07:00
Alex 696aa80dec revert(openrouter): remove Mistral Medium 3.5 stub 2026-04-30 14:59:56 -04:00
Aiden Cline 7d00d863dc Merge pull request #1647 from dpuyosa/chore/venice-kimi-pricing
Venice: Update Kimi K2.5 and K2.6 pricing and dates
2026-04-30 11:29:08 -05:00
Aiden Cline ad9eb83b8c Merge pull request #1648 from Snat3r/patch-1
Fix casing in model name MiniMax m2.7 foor cortects provider
2026-04-30 11:28:55 -05:00
Aiden Cline 467da9a82c Merge pull request #1649 from berget-ai/feat/berget-mistral-medium-3.5
feat: add Mistral Medium 3.5 128B to berget.ai
2026-04-30 11:28:43 -05:00
Pedro 22786bcf4b feat(dinference): add GLM-5.1 and MiniMax-M2.5 models 2026-04-30 13:43:44 +02:00
Christian Landgren c8d258b7cb feat: add Mistral Medium 3.5 128B to berget.ai 2026-04-30 12:31:28 +02:00
Snat3r 70309829ca Fix casing in model name and update output limit 2026-04-30 11:59:44 +02:00
dpuyosa 71e00f193b [venice] Update Kimi K2.5 and K2.6 pricing and dates
- Bump kimi-k2-5 cache_read from 0.11 to 0.22
- Bump kimi-k2-6 input from 0.7448 to 0.85 and cache_read from 0.1463 to 0.22
- Update last_updated dates to 2026-04-30
2026-04-30 11:18:54 +02:00
Alex d44e724170 feat(openrouter): add Mistral Medium 3.5 2026-04-29 18:58:26 -04:00
Alex 414695db9f feat(mistral): add Mistral Medium 3.5 2026-04-29 18:44:28 -04:00
Aiden Cline e8b5a27723 Merge pull request #1642 from Sewer56/add-wafer-deepseek-v4-pro
feat(wafer.ai): add DeepSeek V4 Pro
2026-04-29 17:14:17 -05:00
Aiden Cline 6dc9d805db Merge pull request #1643 from Sawyerb/patch-1
Delete providers/vercel/models/inception/mercury-coder-small.toml
2026-04-29 17:14:00 -05:00
Aiden Cline bdf56c9111 add kimi k2.6 to azure cognitive services 2026-04-29 17:13:19 -05:00
Sewer56 293cc3e82f feat(wafer.ai): add DeepSeek V4 Pro 2026-04-29 23:12:04 +01:00
Sawyer Birnbaum 7f5bd4f231 Delete providers/vercel/models/inception/mercury-coder-small.toml
Mercury Coder Small has been deprecated. People should use Mercury Edit 2 instead.
2026-04-29 14:50:35 -07:00
Aiden Cline c4826babc5 Merge pull request #1497 from Lydanne/fix/302ai-models
Update 302ai model metadata and add GPT-5.4 configs
2026-04-29 14:26:01 -05:00
Rohan Taneja 91e8bb985e Merge pull request #1641 from vercel/update-vercel-models-1777480545
Update Vercel models
2026-04-29 11:29:45 -07:00
Aiden Cline 56723051d4 Merge pull request #1615 from deaquino/dev
Add Qwen3.5-9B model configuration file to OVHCloud
2026-04-29 13:09:19 -05:00
Aiden Cline 0bb3e55c08 Merge pull request #1640 from dpuyosa/chore/venice-update-pricing
Venice: Update DeepSeek v4 and Qwen 3.6 model pricing and metadata
2026-04-29 13:02:40 -05:00
github-actions[bot] 080b7a328b chore(vercel): update Vercel model definitions
Auto-generated by weekly workflow from Vercel AI Gateway API.

Co-Authored-By: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-04-29 16:35:47 +00:00
Frank c5d696583e update zen models 2026-04-29 09:38:00 -04:00
dpuyosa 70490d892f [venice] Update DeepSeek v4 and Qwen 3.6 model pricing and metadata
- Reduce DeepSeek v4 Flash/Pro input and output pricing
- Add cache_read pricing for DeepSeek v4 models
- Fix Qwen 3.6 27B model name formatting
2026-04-29 09:39:11 +02:00
Aiden Cline f858a85ba6 Merge pull request #1625 from xinrui-z/fix-aihubmix-2026-04-28
fix: sync AIHubMix models (2026-04-28)
2026-04-28 23:03:28 -05:00
Aiden Cline 44e4c92882 Merge pull request #1620 from kill74/add-zai-coding-plan-glm-5v-turbo
Add GLM-5V-Turbo to Z.ai coding plan
2026-04-28 19:28:48 -05:00
Aiden Cline 43eafcb258 Merge pull request #1581 from xiaojiezj/zenmux_0425
feat: add models for zenmux provider
2026-04-28 19:27:38 -05:00
Aiden Cline b382ac7af9 Merge branch 'dev' into zenmux_0425 2026-04-28 19:08:09 -05:00
Tom X Nguyen ca21110644 fix: sync neuralwatt models with updated API pricing and capabilities
The Neuralwatt API now returns accurate pricing and capabilities,
eliminating the need for manual patches (patch.json is now empty).

Changes:
- Update pricing for all 14 models from API (significant changes for
  GLM, GPT-OSS, Qwen, and MiniMax models)
- Devstral Small 2 now supports image input (vision)
- kimi-k2.5-fast now supports image input (vision)
- kimi-k2.6-fast now supports reasoning + image input (was non-reasoning)
- Qwen3.6-35B-A3B now supports reasoning (was non-reasoning)
- GLM models context window: 202,752 → 200,000
- Rename fast variant model IDs to match API (dropped org prefix):
  zai-org/glm-5-fast → glm-5-fast
  zai-org/glm-5.1-fast → glm-5.1-fast
  moonshotai/kimi-k2.5-fast → kimi-k2.5-fast
  moonshotai/kimi-k2.6-fast → kimi-k2.6-fast
  Qwen/qwen3.5-397b-fast → qwen3.5-397b-fast
  Qwen/qwen3.6-35b-fast → qwen3.6-35b-fast
2026-04-29 07:05:23 +07:00
Aiden Cline 6a0704574b Merge pull request #1621 from YuzhongHuangCS/dev
feat(wandb): Add GLM-5.1
2026-04-28 15:51:43 -05:00
Aiden Cline 1cb1341516 Merge pull request #1635 from stylings/feat/nemotron-3-nano-omni
feat: add Nemotron 3 Nano Omni model
2026-04-28 15:04:07 -05:00
Alex bc47e95427 fix: rename Nemotron Omni metadata 2026-04-28 15:20:24 -04:00
Aiden Cline b071e8add8 Merge pull request #1619 from fernandoenzo/fix/deepseek-v4-pro-ollama-cloud
fix(ollama-cloud): correct deepseek-v4-pro model config
2026-04-28 14:00:42 -05:00
Aiden Cline 23e527753e Merge pull request #1623 from itsnebulalol/dev
feat: add gpt-5.5 pro on openai and openrouter
2026-04-28 14:00:34 -05:00
Aiden Cline e81c045ed0 Merge pull request #1636 from dsingal0/feat/openrouter-deepseek-v4
feat(baseten): add DeepSeek V4 Pro
2026-04-28 13:49:11 -05:00
Dhruv Singal 0c602ca936 feat(baseten): update DeepSeek V4 Pro pricing 2026-04-28 11:45:02 -07:00
Dhruv Singal 9866f84989 feat(baseten): add DeepSeek V4 Pro 2026-04-28 11:38:22 -07:00
Alex 6b397ffe37 fix: align nvidia output limit 2026-04-28 14:35:31 -04:00
Alex bc21596889 fix: drop openrouter provider prefix 2026-04-28 14:22:04 -04:00
Alex 20abba3190 feat: add Nemotron 3 Nano Omni 2026-04-28 14:17:22 -04:00
Dominic Frye 5881bf98a0 fix: enable pdf input modality for gpt-5.5 pro 2026-04-28 13:33:31 -04:00
Aiden Cline 595f7d028c Merge pull request #1632 from rocuevas9511/feat/deepinfra-deepseek-v4-pro
feat: add DeepSeek-V4-Pro to deepinfra
2026-04-28 12:07:22 -05:00
rocuevas9511 c81dec9c5d feat: add DeepSeek-V4-Pro to deepinfra 2026-04-28 10:56:44 -06:00
Guiii 4d45ed25d2 Use extended GLM-5V-Turbo config
Removed various fields and added extends section.
2026-04-28 17:49:34 +01:00
Yuzhong Huang 03cf48de53 use extends instead 2026-04-28 09:19:26 -07:00
Aiden Cline 0d3a284395 Merge pull request #1622 from eduqr/feat/fireworks-ai-deepseek-v4-pro
feat(fireworks-ai): add deepseek-v4-pro
2026-04-28 10:52:54 -05:00
Aiden Cline 5b1bb0fc80 Merge pull request #1624 from shelvick/add-azure-kimi-k2-6
Add Kimi K2.6 to Azure
2026-04-28 10:38:07 -05:00
Aiden Cline 332ebb8811 Merge pull request #1627 from ceoAppsknight/kilo/add-mimo-models
Add Kilo Mimo v2.5 models
2026-04-28 10:37:40 -05:00
Aiden Cline 2111813bd4 Merge pull request #1629 from ndeybach/PR-azure-5.4-limits
fix(azure): correct GPT-5.4 series limits and cleanup
2026-04-28 10:37:01 -05:00
Nils DEYBACH f5b8521af6 fix: use extends and not symlinks 2026-04-28 17:34:44 +02:00
Nils DEYBACH 79481cff40 fix(azure): update GPT-5.4 metadata
Use `extends` for Azure GPT-5.4 variants and keep Azure-specific overrides for
PDF input and omitted fast mode.

Validated with `bun validate`.

Azure runtime manual probing confirmed GPT-5.4 uses the documented 1.05M context /
922K input / 128K output limits.
2026-04-28 14:00:20 +02:00
Nils DEYBACH 40dc356d4c fix(azure): correct GPT-5.4 and GPT-5.4 Pro limits (and convert to extend)
Correct Azure GPT-5.4 and GPT-5.4 Pro limits to `1_050_000` context,
`922_000` input, and `128_000` output based on Azure runtime results and
Microsoft Learn docs. Mini and Nano already matched and are unchanged.

The limits were tested directly (see script at : https://github.com/ndeybach/Azure_endpoint_limit_test_script )
2026-04-28 12:33:27 +02:00
C.C. Fan f929fe89e7 provider(vivgrid): remove GLM-5, add GPT-5.5 model 2026-04-28 16:44:59 +08:00
Syed Assadullah Shah cbd245d454 add Kilo Mimo v2.5 models 2026-04-28 13:04:36 +05:00
xinrui e5289e9b3a fix: sync AIHubMix models (2026-04-28) 2026-04-28 11:33:25 +08:00
Scott Helvick bb623f3ff9 Add Kimi K2.6 to Azure 2026-04-28 02:28:46 +00:00
Dominic Frye 37fffafafc feat: add gpt-5.5 pro on openai and openrouter 2026-04-27 22:24:32 -04:00
eduqr d329310745 feat(fireworks-ai): add deepseek-v4-pro 2026-04-27 21:05:55 -05:00
Yuzhong Huang 8016a6c45a Add GLM-5.1 to wandb provider 2026-04-27 17:35:38 -07:00
Guilherme Sales 1eeaa0b756 Add GLM-5V-Turbo to Z.ai coding plan 2026-04-28 00:47:15 +01:00
Frank dd3533b4e0 update zen models 2026-04-27 19:31:24 -04:00
Fernando Guarini 3a5867834f fix(ollama-cloud): correct deepseek-v4-pro model config
- Remove fields that don't belong in ollama-cloud: temperature, structured_output, knowledge, interleaved
- Set output = context (1048576) per ollama-cloud convention
- Set name to lowercase per ollama-cloud convention
- Reorder fields to match existing ollama-cloud model files
2026-04-28 00:24:54 +02:00
Aiden Cline 1e83bca7a3 Merge pull request #1617 from JoshuaDietz/dev
feat(ollama cloud): add deepseek v4 pro
2026-04-27 16:42:56 -05:00
Aiden Cline cd8853f88b Merge pull request #1616 from fhennerkes/dev
poe: add GPT-5.5 and GPT-5.5-Pro models
2026-04-27 16:08:36 -05:00
Joshua Dietz 23b290c6a8 fix(ollama cloud): fix model name
Model name was inconsistent with naming schema of flash model on ollama cloud
2026-04-27 21:47:30 +02:00
fhennerkes 4e7849cee7 poe: reduce omits in gpt-5.5 extends configs
Inherit family, knowledge, and structured_output from base models
instead of omitting them. Only omit fields that genuinely don't
apply to Poe (provider-specific pricing tiers, different context
limits, opencode-specific provider config).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 12:44:49 -07:00
Joshua Dietz e3e63a7247 feat(ollama cloud): add deepseek v4 pro 2026-04-27 21:42:10 +02:00
Aiden Cline fb297153e4 Merge pull request #1572 from YoshiTabletopGamer/qwen3.5-3.6-alibaba-open
[alibaba] Add remaining open Qwen 3.5 and 3.6 models, fix Qwen-3.5 397B-A17B
2026-04-27 14:36:51 -05:00
fhennerkes e8dd06e0ce poe: use extends format for gpt-5.5-pro
Address PR review comment to use extends format. Inherit from
opencode/gpt-5.5-pro since no openai/gpt-5.5-pro base exists yet.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 10:49:36 -07:00
fhennerkes bdee3d438b poe: use extends format for gpt-5.5
Address PR review comment to use extends format and inherit from
openai/gpt-5.5 base model.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 10:36:10 -07:00
fhennerkes b410bc3ef2 poe: add GPT-5.5 and GPT-5.5-Pro models 2026-04-27 10:34:52 -07:00
Aiden Cline 870e3d1d26 Merge pull request #1612 from hanouticelina/add-deepseek-v4-for-huggingface
feat(huggingface): add DeepSeek V4 Pro
2026-04-27 11:20:12 -05:00
Aiden Cline 5f21f3b603 Merge pull request #1586 from fernandoenzo/add-ollama-cloud-deepseek-v4-flash
feat(ollama-cloud): add deepseek-v4-flash model
2026-04-27 10:42:53 -05:00
Celina Hanouti 27dad05e25 extend deepseek/deepseek-v4-pro 2026-04-27 16:38:36 +01:00
Aiden Cline 2ed88cbcc0 Merge pull request #1604 from ndeybach/PR-gpt-5.5
feat(azure): add GPT-5.5 model metadata
2026-04-27 10:20:32 -05:00
Nils DEYBACH 4d199c932e fix: base azure-cognitive-services model not on azure
extend of extend does not seem to be supported
2026-04-27 17:04:20 +02:00
Jaime de Aquino 2d142f920c Add Qwen3.5-9B model configuration file 2026-04-27 16:46:04 +02:00
Celina Hanouti 47dea9e551 fix 2026-04-27 15:40:35 +01:00
Celina Hanouti 0d25c3dcac use extends 2026-04-27 15:37:31 +01:00
Aiden Cline 3d7f9256cb Merge pull request #1583 from abliteration-ai/codex/add-abliteration-provider
Add abliteration.ai provider
2026-04-27 09:29:26 -05:00
Aiden Cline 6aa1ebd4be Merge pull request #1595 from Contraboi/contra/add-openrouter-nano-banana-2
feat(openrouter): add Gemini 3.1 flash image preview (Nano Banana 2)
2026-04-27 09:28:23 -05:00
Aiden Cline f9ebebaffd Merge pull request #1601 from shikbupt/alibaba-deepseek
add alibaba-cn deepseek-v4
2026-04-27 09:28:08 -05:00
sk 7b3fe83c09 use extend format 2026-04-27 21:48:26 +08:00
Yashwanth Kumar 0a06b3efc2 Update Qwen model configuration in TOML file 2026-04-27 16:40:28 +05:30
Yashwanth Kumar 90dcbbbcc5 Add Qwen3.6 27B model configuration 2026-04-27 16:29:56 +05:30
Yashwanth Kumar b17f5fd8ae Delete providers/openrouter/models/qwen/qwen-3.6-27b.toml 2026-04-27 16:28:19 +05:30
Yashwanth Kumar 68691ac3f9 Update providers/openrouter/models/qwen/qwen-3.6-27b.toml
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-04-27 16:27:56 +05:30
Yashwanth Kumar 78fe905fcb Add Qwen 3.6 27B model configuration 2026-04-27 16:22:24 +05:30
Nils DEYBACH 6b488802cf fix: parsing error and add context over price
- adds the context over X price capability from parent (awaiting refactor to be correct on exact limit threashold)
- fix parsing since anything must be before extends.
2026-04-27 12:27:47 +02:00
Jack 4d0505b70e Merge pull request #1611 from anomalyco/fix/opencode-go-deepseek-v4-flash-cache-read-20260427
fix(opencode-go): update deepseek v4 flash cache pricing in Go
2026-04-27 17:34:52 +08:00
Jack b729923bd9 fix(opencode-go): correct deepseek v4 flash cache pricing 2026-04-27 17:31:41 +08:00
Celina Hanouti 34c7aa7dfe update context limit 2026-04-27 09:33:57 +01:00
Celina Hanouti 09b4d3548b add support for DeepSeek V4 Pro for Hugging Face provider 2026-04-27 09:31:55 +01:00
xiaojie.zj f1cad8fdc0 feat: add zenmux models 2026-04-27 16:27:46 +08:00
Tom X Nguyen b2f7f57f26 feat: add neuralwatt provider with 14 models
Add Neuralwatt as an OpenAI-compatible inference provider with
energy-aware GPU optimization. Includes 14 models across 6
sub-providers (Mistral, ZAI, OpenAI, Moonshot, MiniMax, Qwen).

Models include reasoning variants (Kimi K2.5/K2.6, GLM 5.1 FP8,
MiniMax M2.5, Qwen3.5 397B, GPT OSS 20B) and fast non-reasoning
variants (Kimi K2.5/K2.6 Fast, GLM 5/5.1 Fast, Qwen3.5/3.6 Fast),
plus Devstral Small 2 and Qwen3.6 35B A3B.

Logo derived from official Neuralwatt favicon (currentColor variant).
Pricing sourced from Neuralwatt's published rates.
2026-04-27 15:01:56 +07:00
Aiden Cline 925d4eba1f Merge pull request #1536 from philipmat/add-openrouter-pareto-code-router
Adds support for openrouter/pareto-code
2026-04-26 23:52:04 -05:00
Aiden Cline bc1e4b870b Merge pull request #1608 from Alex-wuhu/dev
add deepseek-v4, qwen3.6 on novita
2026-04-26 23:16:56 -05:00
Alex-wuhu ef913f9645 refactor: use extends format for novita deepseek v4 models
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-27 12:00:04 +08:00
Alex-wuhu cec747ade3 fix: add cache_read pricing for deepseek v4 models 2026-04-27 11:09:15 +08:00
Aiden Cline 2ced32d52f Merge pull request #1596 from NathanDrake2406/add-cf-ai-gateway-gpt-5.5
feat(cloudflare-ai-gateway): add openai/gpt-5.5
2026-04-26 21:57:13 -05:00
Alex-wuhu 92cc5a79df feat: add deepseek-v4, qwen3.6 on novita 2026-04-27 10:49:13 +08:00
Aiden Cline 4cf8661f92 Merge pull request #1602 from shikbupt/alibaba-qwen3.6-max
add alibaba-cn qwen3.6 max
2026-04-26 17:48:14 -05:00
Aiden Cline ebe431c0dc Merge pull request #1606 from LightAndy1/dev
Add gemini-3.1-flash-preview for google-vertex
2026-04-26 17:30:05 -05:00
LightAndy 8b2c5f30a0 ✏️ Fix typo 2026-04-26 21:48:54 +03:00
Nils DEYBACH 0fc92e1c47 fix: align limit on base 5.5 model
now that limits were fixed in base, we align azure on it
2026-04-26 20:48:00 +02:00
Nils DEYBACH d73ca9024a Merge remote-tracking branch 'upstream/dev' into PR-gpt-5.5 2026-04-26 20:45:20 +02:00
LightAndy bff48f9fde Merge branch 'anomalyco:dev' into dev 2026-04-26 21:43:13 +03:00
Aiden Cline c5c803f415 fix: ensure openai gpt-5.5 limits are exact 2026-04-26 13:38:56 -05:00
Nils DEYBACH cd69509b48 fix: simplify by extending the azure model from opeani 2026-04-26 20:04:27 +02:00
Aiden Cline 83d15fd756 Merge pull request #1574 from juls0730/dev
feat: add mimo v2.5/pro to xiaomi and openrouter providers
2026-04-26 13:55:57 -04:00
LightAndy b3c09451d9 Add gemini-3.1-flash-preview model configuration 2026-04-26 20:27:17 +03:00
Frank d98bdb5eff Merge pull request #1560 from TigerBeanst/patch-1
fix: opencode go mimo-v2.5 context limit to 1,000,000
2026-04-26 13:16:33 -04:00
Frank ea205913ce update zen models 2026-04-26 12:49:37 -04:00
Frank 3532801639 update zen models 2026-04-26 11:48:32 -04:00
Nils DEYBACH 1bb50141c2 feat(azure): add GPT-5.5 model metadata
## Summary

Adds GPT-5.5 metadata for:

- Azure
- Azure Cognitive Services

The Azure Cognitive Services entry mirrors the existing local convention of full TOML model definitions.

## Sources

- Microsoft Learn lists `gpt-5.5` for Azure OpenAI / Microsoft Foundry with version `2026-04-24`, `1,050,000` context, `922,000` input, `128,000` output, structured outputs, tools, image input, and December 2025 training data.
- Microsoft’s Azure GPT-5.5 announcement lists pricing at `$5.00` input, `$0.50` cached input, and `$30.00` output per 1M tokens.
- Azure Responses API docs list PDF input support for vision-capable models and include `gpt-5.5` version `2026-04-24`.

## Notes

This intentionally does not add `gpt-5.5-pro`, since Azure Learn currently lists `gpt-5.5` but not `gpt-5.5-pro` in the Azure model catalog.

This also intentionally omits OpenAI-specific `context_over_200k` and `experimental.modes.fast` metadata because the Azure sources confirm the standard pricing and limits, but not those OpenAI-specific fields.
2026-04-26 17:45:25 +02:00
sk fa8bdd63fb add alibaba-cn qwen3.6 max 2026-04-26 19:39:41 +08:00
sk 56f64577ce add alibaba-cn deepseek-v4 2026-04-26 19:23:04 +08:00
Nathan Nguyen f726af5767 refactor(cloudflare-ai-gateway): use [extends] for openai/gpt-5.5
The model entry duplicated every field from providers/openai/models/gpt-5.5.toml,
so any future change to the upstream OpenAI definition would silently drift here.

Switch to the `[extends] from = "openai/gpt-5.5"` form already used by sibling
providers (openrouter, requesty), omitting `experimental.modes.fast` since the
gateway does not surface the OpenAI priority service tier. Validation output is
byte-identical to the prior expanded form.
2026-04-26 13:33:39 +10:00
Zoe 4838e3cb9b feat: add mimo v2.5/pro to xiaomi and openrouter providers 2026-04-25 21:32:24 -05:00
Muhammad Mugni Hadi dbe92646c3 chore(chutes): add header comments to generated TOML files
Each generated TOML now includes a comment noting which fields are
auto-managed vs manually overridable on re-run.
2026-04-26 06:52:21 +07:00
Muhammad Mugni Hadi 4717c67054 feat(chutes): add API-driven model generator script
Add generate-chutes.ts that fetches models from https://llm.chutes.ai/v1/models
and generates/updates TOML files, following the same pattern as generate-vercel.ts.

Supports --dry-run, --new-only, and --keep-orphans flags. Auto-deletes TOML files
for models no longer in the API (with empty directory cleanup).

Preserves manually-set fields (family, knowledge, interleaved, status) when merging
with API data. Also syncs current models from the API.
2026-04-26 06:51:16 +07:00
Nathan Nguyen d4c77c14fd feat(cloudflare-ai-gateway): add openai/gpt-5.5
Mirrors the existing direct openai/gpt-5.5 entry under the
cloudflare-ai-gateway provider so opencode and other consumers can
route GPT-5.5 traffic through Cloudflare AI Gateway without hitting
ProviderModelNotFoundError.

Pricing, limits, modalities, and dates copied from
providers/openai/models/gpt-5.5.toml; provider stanza follows the
sibling gpt-5.4 entry (npm = "ai-gateway-provider").
2026-04-26 05:22:29 +10:00
Selmir Nedzibi 96b3d65307 feat(openrouter): add Gemini 3.1 flash image preview (Nano Banana 2) 2026-04-25 21:14:44 +02:00
Aiden Cline b491c29cf9 Merge pull request #1573 from zainhas/dev
[Together AI] add deepseek-v4
2026-04-25 13:47:14 -04:00
Aiden Cline d937abd849 Merge pull request #1539 from manascb1344/fix-xiaomi-provider-ids
feat: add MiMo-V2.5 and MiMo-V2.5-Pro to xiaomi-token-plan providers
2026-04-25 13:33:42 -04:00
Aiden Cline df52175b0c Merge pull request #1580 from LeGazeon/add-nvidia-deepseek-v4-pro/flash
Add NVIDIA DeepSeek-V4 models
2026-04-25 13:32:41 -04:00
Aiden Cline bee8339c07 Merge pull request #1589 from MiyakoMeow/feat/restrict-zai-zhipuai-coding-plan-models
rm: unavailable models in zai/zhipuai coding plan
2026-04-25 13:30:39 -04:00
Aiden Cline 181bf96fa3 Merge pull request #1585 from saju01/add-copilot-gpt-5.5
feat(github-copilot): add gpt-5.5
2026-04-25 13:30:16 -04:00
Aiden Cline 9d49d2fd52 Merge pull request #1587 from smakosh/claude/rebase-add-llmgateway-models-yqKLn
feat(llmgateway): add deepseek-v4-pro, deepseek-v4-flash, kimi-k2.6
2026-04-25 13:29:39 -04:00
Aiden Cline 648776aa85 Merge pull request #1590 from dpuyosa/feat/venice-models
Venice: Add GPT-5.5 and Qwen3.6 model configs
2026-04-25 13:29:03 -04:00
Aiden Cline 421cb099b0 Merge pull request #1591 from dpuyosa/fix/venice-deepseek-family
Venice: Fix DeepSeek V4 Flash family classification
2026-04-25 13:28:54 -04:00
Aiden Cline f458b19994 Merge pull request #1592 from MiyakoMeow/feat/deepseek-1m-context
fix(deepseek): all has 1M context / 384k output / adjusted price
2026-04-25 13:28:45 -04:00
MiyakoMeow d347093b03 feat(deepseek): 1M context / 384k output 2026-04-25 18:58:12 +08:00
MiyakoMeow 3328712262 feat: restrict zai/zhipuai coding plan models to glm-5.1, glm-5-turbo, glm-4.7, glm-4.5-air only
Based on official documentation:
- ZAI DevPack Coding Plan: https://docs.z.ai/devpack/overview
- Zhipu AI BigModel Coding Plan: https://docs.bigmodel.cn/cn/coding-plan/overview

Both providers only officially support the following GLM models for coding plans:
- glm-5.1
- glm-5-turbo
- glm-4.7
- glm-4.5-air

Removed unsupported models from zai-coding-plan:
- glm-4.5, glm-4.5-flash, glm-4.5v
- glm-4.6, glm-4.6v
- glm-4.7-flash, glm-4.7-flashx
- glm-5, glm-5v-turbo

Removed unsupported models from zhipuai-coding-plan:
- glm-4.5, glm-4.5-flash, glm-4.5v
- glm-4.6, glm-4.6v, glm-4.6v-flash
- glm-4.7-flash, glm-4.7-flashx
- glm-5, glm-5v-turbo
2026-04-25 18:49:10 +08:00
dpuyosa 60edc1b52d [venice] Add GPT-5.5 and Qwen3.6 model configs
- Add OpenAI GPT-5.5 with 1M context window and tiered pricing
- Add OpenAI GPT-5.5 Pro with premium pricing and 128K output limit
- Add Qwen3.6 27B with text, image, and video input modalities
2026-04-25 12:41:31 +02:00
dpuyosa eee44cd080 [venice] Fix DeepSeek V4 Flash family classification
- Correct family from "deepseek" to "deepseek-flash" for accurate model categorization
2026-04-25 12:36:06 +02:00
smakosh 048a3235e8 feat(llmgateway): add deepseek-v4-pro, deepseek-v4-flash, kimi-k2.6 2026-04-25 12:19:40 +02:00
Fernando Guarini 1db03ec1e6 feat(ollama-cloud): add deepseek-v4-flash model 2026-04-25 11:24:12 +02:00
Saju Sarangdharan 6d283349ad feat(github-copilot): add gpt-5.5
GitHub Copilot now serves gpt-5.5 (verified via GET https://api.githubcopilot.com/models with a Copilot Enterprise token). Adding the catalog row so downstream consumers (e.g. pi-ai) can route requests.
2026-04-25 10:31:21 +02:00
Abliteration.ai 7e07302ecd add abliteration.ai provider 2026-04-24 22:46:54 -07:00
LeGazeon 8bc407a617 chore: remove deepseek-v4-pro config (duplicated by #1578)
The Pro model configuration was already added via #1578 which
has been merged. Removing the duplicate from this branch to
keep only the Flash variant.
2026-04-25 13:17:12 +08:00
LeGazeon 5305d2bae2 refactor: extend flash config from deepseek base
Remove duplicated fields by inheriting common settings
from providers/deepseek base config via [extends].

This addresses the review comment in #1580
2026-04-25 13:11:26 +08:00
Aiden Cline fee96c27b9 Merge pull request #1578 from panwar-stack/dev
feat(nvidia): add DeepSeek V4 model
2026-04-25 00:41:03 -04:00
Aiden Cline 66520adbc6 Merge pull request #1577 from ezShroom/dev
add openrouter gpt-5.5
2026-04-25 00:40:34 -04:00
Zain Hasan 40714995cc Add interleaved section to DeepSeek-V4-Pro.toml 2026-04-24 18:59:45 -07:00
LeGazeon 66c4896003 Add NVIDIA DeepSeek-V4 models
Add model entries for DeepSeek V4 Pro and DeepSeek V4 Flash to the NVIDIA NIM provider.

## Changes
- Added `providers/nvidia/deepseek-v4-pro.toml`
- Added `providers/nvidia/deepseek-v4-flash.toml`

## Data Sources
- NVIDIA NIM Model Cards:
  - DeepSeek V4 Pro: https://build.nvidia.com/deepseek-ai/deepseek-v4-pro/modelcard
  - DeepSeek V4 Flash: https://build.nvidia.com/deepseek-ai/deepseek-v4-flash/modelcard
2026-04-25 09:57:43 +08:00
panwar-stack 31091f3d4e Rename deepseek-v4.toml to deepseek-v4-pro.toml 2026-04-24 17:09:12 -07:00
panwar-stack 5fe512c1b1 Follow extends pattern
Follow extends pattern
2026-04-24 17:08:49 -07:00
panwar-stack 63efa131e7 feat(nvidia): add DeepSeek V4 model
add DeepSeek V4 model
2026-04-24 17:05:12 -07:00
Shroom 29cd503070 Add gpt-5.5.toml configuration file 2026-04-25 00:08:04 +01:00
Rohan Taneja a9b704c656 Merge pull request #1575 from vercel/update-vercel-models-1777063875 2026-04-24 15:29:39 -07:00
Aiden Cline 0a88e412e5 Merge pull request #1576 from dsingal0/feat/openrouter-deepseek-v4
Add OpenRouter DeepSeek V4 models
2026-04-24 17:42:48 -04:00
Dhruv Singal b46e29ccd5 fix(openrouter): use DeepSeek reasoning content field 2026-04-24 14:06:05 -07:00
Jerilyn Zheng a181b770d6 Update kimi-k2.6.toml 2026-04-24 13:55:27 -07:00
Jerilyn Zheng fa71201f20 Update deepseek-v4-pro.toml 2026-04-24 13:54:56 -07:00
Jerilyn Zheng 3ac17aefb6 Enable open_weights in deepseek-v4-flash configuration 2026-04-24 13:54:34 -07:00
Jerilyn Zheng 1f2ceb91a5 Update qwen-3.6-max-preview.toml 2026-04-24 13:53:57 -07:00
github-actions[bot] d82681900c chore(vercel): update Vercel model definitions
Auto-generated by weekly workflow from Vercel AI Gateway API.

Co-Authored-By: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-04-24 20:51:22 +00:00
Zain Hasan 7e296f4cbd ds recommend 384,000 2026-04-24 12:39:09 -07:00
Zain Hasan f202ff51e4 Reduce output limit from 512000 to 300000 2026-04-24 12:13:53 -07:00
Zain Hasan 4085a0b536 Merge branch 'anomalyco:dev' into dev 2026-04-24 12:12:28 -07:00
Zain Hasan 935fdeca65 [Together AI] Add deepseekv4 pro 2026-04-24 12:08:33 -07:00
Frank cef8828fbe update zen models 2026-04-24 14:51:59 -04:00
Frank 9277a23a29 update zen models 2026-04-24 14:50:50 -04:00
Frank d7bfb16b0f update zen models 2026-04-24 14:42:25 -04:00
Frank 37ae6fe7c8 update zen models 2026-04-24 12:11:33 -04:00
Aiden Cline 87ce527476 Merge pull request #1571 from cgilly2fast/dev
fix(firmware): glm 5.1 name
2026-04-24 11:49:51 -04:00
Aiden Cline 34bed30fa1 Merge pull request #1567 from dsingal0/feat/openrouter-deepseek-v4
feat(openrouter): add DeepSeek V4 Pro and V4 Flash
2026-04-24 11:49:35 -04:00
Dhruv Singal 8a0c3cb75f refactor(openrouter): extend official DeepSeek V4 Pro/Flash
Use [extends] from deepseek/ with OpenRouter-specific overrides
(attachment, interleaved reasoning_details, limits).

Made-with: Cursor
2026-04-24 08:43:38 -07:00
Colby Gilbert f65460ac16 fix(firmware): glm 5.1 name 2026-04-24 08:40:19 -07:00
YoshiTabletopGamer 8ea92aed9a [alibaba] Add remaining open Qwen 3.5 models, fix Qwen-3.5 397B-A17B, add open Qwen 3.6 models
- Added Qwen 3.5 122B-A10B
- Added Qwen 3.5 27B
- Added Qwen 3.5 35B-A3B
- Fixed Qwen 3.5 397B-A17B (see below)
- Added Qwen 3.6 27b
- Added Qwen 3.6-35B-A3B

I was not able to find a reliable source for the knowledge cutoff of any of these models.
2025-04 was already set as the cutoff for Qwen 3, and Qwen 3.5 is newer.
All data is from the ModelStudio webpage.
It seems to not include audio, but the ModelStudio page clearly has an audio symbol and the model is capable of this.
And I found no data for a price for reasoning tokens in particular, unlike what was in the file for Qwen 3.5 397B-A17B.
The models are all capable of structured output.
2026-04-24 12:38:52 -03:00
Dhruv Singal f340d82fc3 feat(openrouter): add DeepSeek V4 Pro and V4 Flash
Add model configs aligned with OpenRouter pricing and limits
(1M context, 384K max output, cache read rates from provider page).

Made-with: Cursor
2026-04-24 08:25:17 -07:00
Frank c7431ae24c update zen models 2026-04-24 10:53:10 -04:00
Frank 3d1888b7b5 update zen models 2026-04-24 10:24:34 -04:00
Aiden Cline dcd37ccdbb add deepseek v4 flash 2026-04-24 08:34:03 -04:00
Aiden Cline d18c3f910c Merge pull request #1562 from dpuyosa/update/venice-kimi-pricing
Venice: Update kimi-k2-6 pricing
2026-04-24 08:08:23 -04:00
Aiden Cline 2cec5a492c Merge pull request #1563 from dpuyosa/feat/venice-deepseek-v4
Venice: Add DeepSeek V4 Flash and Pro models
2026-04-24 08:08:13 -04:00
dpuyosa 61dd0ec489 [venice] Add DeepSeek V4 Flash and Pro models
- Add DeepSeek V4 Flash with 1M context, reasoning, and tool support
- Add DeepSeek V4 Pro with 1M context, reasoning, and tool support
- Set pricing and interleaved reasoning_content field for both
2026-04-24 12:21:07 +02:00
dpuyosa c7758204b5 [venice] Update kimi-k2-6 pricing
- Update input, output, and cache_read costs to current rates
- Update last_updated timestamp to 2026-04-24
2026-04-24 12:17:51 +02:00
manascb1344 ed91520aa2 feat: add MiMo-V2.5 and MiMo-V2.5-Pro to xiaomi-token-plan providers 2026-04-24 15:38:55 +05:30
Frank 3e82669a82 Merge pull request #1561 from wenbindu/dev
add deepseek new moels
2026-04-24 03:04:52 -04:00
Frank 1cc0c9c074 sync 2026-04-24 03:03:06 -04:00
TigerBeanst d73d7f6453 fix: opencode go mimo-v2.5 context limit to 1,000,000
https://platform.xiaomimimo.com/docs/pricing
2026-04-24 12:48:34 +08:00
Aiden Cline afb59f86ee Merge pull request #1557 from seffhunnn/dev
feat: add AU Sonnet and Opus models for Amazon Bedrock
2026-04-24 00:30:51 -04:00
wenbindu 05242f68d4 add deepseek new moel 2026-04-24 12:06:19 +08:00
Mohd Saif c1b029dcc1 feat: add AU Opus model for Amazon Bedrock 2026-04-24 03:26:28 +05:30
Mohd Saif bc2dd5137a feat: add AU Sonnet model for Amazon Bedrock 2026-04-24 03:25:38 +05:30
Aiden Cline 99ec4900c7 Merge pull request #1555 from brentdurksen/add-azure-claude-sonnet-4-6
feat(azure): add Claude Sonnet 4.6 model
2026-04-23 17:33:44 -04:00
Brent Durksen a8c124ac9e refactor: use extends to inherit from anthropic/claude-sonnet-4-6 2026-04-23 15:16:38 -06:00
Aiden Cline 0d20a363a9 Merge pull request #1556 from fhennerkes/dev
poe: add GPT-Image-2 model
2026-04-23 17:12:20 -04:00
fhennerkes 3ac613678b poe: add GPT-Image-2 model 2026-04-23 12:38:22 -07:00
Brent Durksen e2ead1b4e6 feat(azure): add Claude Sonnet 4.6 model 2026-04-23 13:37:50 -06:00
Aiden Cline be53c33588 Merge pull request #1550 from BlockListed/cortecs-kimi-k2.6
Add kimi k2.6 to cortecs
2026-04-23 15:26:58 -04:00
Aiden Cline 55cf5fa310 Merge pull request #1554 from mattyatea/add-gpt-5-5
[codex] Add GPT-5.5
2026-04-23 15:17:20 -04:00
mattyatea 3e0fe362f2 add gpt-5.5 model 2026-04-24 04:13:51 +09:00
BlockListed 89d06ae31f add kimi k2.6 to cortecs 2026-04-23 19:49:18 +02:00
Aiden Cline c994b116ae Merge pull request #1542 from u007/patch-1
Add Chutes: Kimi K2.6 TEE
2026-04-23 12:47:49 -04:00
Aiden Cline 833e8f7a66 Merge pull request #1548 from fernandoenzo/fix/gemma4-ollama-output-limit
fix(ollama): set gemma4:31b output limit to match context
2026-04-23 12:46:00 -04:00
Aiden Cline 32bd1427fb Merge pull request #1545 from Alex-wuhu/dev
Add deepseek, gemma, ling, llama, kimi on NovitaAI
2026-04-23 12:36:06 -04:00
Frank ae7672b87e update zen models 2026-04-23 11:11:30 -04:00
Fernando Guarini 9b27cc5a76 fix(ollama): set gemma4:31b output limit to match context
Ollama does not impose official output limits. The existing convention for Gemma models on Ollama (gemma3:4b, gemma3:12b, gemma3:27b) is to set output equal to context. gemma4:31b was the only exception with output=8192 vs context=262144.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-04-23 11:42:30 +02:00
Alex-wuhu 7014e3e318 feat: add missing Novita AI model configurations
Add 6 models served by Novita:
- deepseek/deepseek-r1-distill-qwen-14b
- deepseek/deepseek-r1-distill-qwen-32b
- google/gemma-3-12b-it
- inclusionai/ling-2.6-1t
- meta-llama/llama-3.2-3b-instruct
- moonshotai/kimi-k2.6

Capabilities, pricing, context, and modalities sourced from Novita's
/v1/models API; family slugs and release dates aligned with existing
same-model entries in the repo.
2026-04-23 14:58:43 +08:00
Frank e0e153e8d6 update zen models 2026-04-23 02:51:28 -04:00
mickalchen a0fbef93e4 revert 2026-04-23 14:41:05 +08:00
mickalchen e4a89229be add model by openrouter 2026-04-23 14:23:06 +08:00
mickalchen 9ad15e97cd add model by openrouter 2026-04-23 14:18:51 +08:00
James e3b4df4e87 Update Kimi-K2.6-TEE.toml
fix reasoning
2026-04-23 13:53:37 +08:00
Aiden Cline e3e2066c83 Merge pull request #1544 from GodTamIt/deepinfra/kimi-k2.6
deepinfra: Add Kimi-K2.6 support
2026-04-23 00:40:50 -04:00
Aiden Cline 208dcd12a2 Merge pull request #1533 from qychen2001/dev
Add Kimi-K2.6 and Qwen3.6-35B-A3B, update Kimi-K2.5 config for siliconflow and siliconflow-cn
2026-04-23 00:40:40 -04:00
Aiden Cline d166444aa1 Merge pull request #1541 from zainhas/dev
[Together AI] add Kimi k2.6 support
2026-04-23 00:40:15 -04:00
Aiden Cline cd35f96e73 Merge pull request #1528 from seffhunnn/dev
Fix incorrect model ID for Gemma 4 26B (Google provider)
2026-04-23 00:39:12 -04:00
Christopher Tam 2b0c21e0b4 deepinfra: Add Kimi-K2.6 support 2026-04-22 23:39:42 -04:00
James 787b0bf9e9 Update Kimi K2.5 TEE to Kimi K2.6 TEE 2026-04-23 10:58:39 +08:00
Zain Hasan 77fbf02ff6 remove interleaved 2026-04-22 16:19:10 -07:00
Zain Hasan 89973fd122 [Together AI] add Kimi k2.6 support 2026-04-22 16:16:08 -07:00
Frank e458a9f5b8 Merge pull request #1540 from dsingal0/feat/baseten-kimi-k2.6
feat(baseten): add Kimi K2.6
2026-04-22 16:59:51 -04:00
Dhruv Singal 61d95afae2 feat(baseten): add Kimi K2.6 2026-04-22 13:53:46 -07:00
Jack 4a2df5e008 Merge pull request #1537 from anomalyco/feat/opencode-go-mimo-v2.5
Feat/opencode go mimo-v2.5-pro & mimo-v2.5
2026-04-23 00:51:49 +08:00
Aiden Cline 3db907f3ce Merge pull request #758 from regolo-ai/dev
Add Regolo-ai Provider
2026-04-22 12:33:02 -04:00
Jack 70d8f9cc6e update mimo v2 output limits to 128k 2026-04-22 23:32:16 +08:00
Jack b9b354ada0 update mimo v2.5 output limits to 128k 2026-04-22 23:17:40 +08:00
Jack 95632ad376 remove mimo-v2.5-omni (renamed to mimo-v2.5) 2026-04-22 23:15:00 +08:00
Philip M 7153506989 Adds support for openrouter/pareto-code
The Pareto Router is a way to have OpenRouter always pick a strong coding model for your needs without committing to a specific one. You express a single min_coding_score preference between 0 and 1, and the router routes your request to a coding model that meets that bar.

The Pareto Router is tuned for coding use cases. Under the hood it keeps a curated shortlist of strong coding models currently available on OpenRouter. The exact shortlist and selection logic evolve over time as new models land and benchmarks shift.
2026-04-22 10:14:46 -05:00
Jack c73bab2e7e providers(opencode-go): rename mimo-v2.5-omni to mimo-v2.5 2026-04-22 23:14:27 +08:00
Jack a783dc808d providers(opencode-go): add mimo v2.5 models and separate v2 families 2026-04-22 23:07:40 +08:00
Daniele Scasciafratte 58e72802bc feat(models): update 2026-04-22 16:05:48 +02:00
Mohd Saif 19233d93c4 fix: remove unnecessary id field 2026-04-22 15:19:47 +05:30
QiyuanChen 7eea45e078 feat(siliconflow-cn): add Kimi-K2.6, Qwen3.6-35B-A3B and update Kimi-K2.5 config 2026-04-22 13:38:34 +08:00
QiyuanChen 001ec226f6 feat(siliconflow): add Kimi-K2.6 and update Kimi-K2.5 config 2026-04-22 13:37:59 +08:00
Jack 32461d5b44 Merge pull request #1532 from chl-0537/feature/add-tencent
Remove tencent token plan
2026-04-22 13:12:06 +08:00
mickalchen 9f078294c0 Remove tencent token plan 2026-04-22 13:07:03 +08:00
Aiden Cline c885ed49cd Merge pull request #1531 from zhiyuan1024/zhiyuan/alibaba-cn_kimi-k2.6
feat(alibaba-cn): add Kimi K2.6 model configuration
2026-04-21 23:41:29 -04:00
Aiden Cline 2fc434062f Merge pull request #1529 from compumike/compumike/fix-openrouter-openai-gpt-5.4-pricing
Fix pricing for openrouter/openai gpt-5.4-[mini,nano] off by 10^6
2026-04-21 23:40:51 -04:00
Aiden Cline dbcb7e6d69 Merge pull request #1530 from cgilly2fast/dev
feat(firmware): kimi k2.6 model
2026-04-21 23:40:22 -04:00
Zhiyuan Hou b58392fc62 feat(alibaba-cn): add Kimi K2.6 model configuration
Signed-off-by: Zhiyuan Hou <zhiyuan2048@outlook.com>
2026-04-22 10:37:37 +08:00
Frank a4818c90ca update zen models 2026-04-21 20:18:35 -04:00
Colby Gilbert 49fbdba49f feat(firmware): kimi k2.6 model 2026-04-21 17:14:46 -07:00
Mike Robbins f2dd4da7f9 Fix pricing for openrouter/openai gpt-5.4-[mini,nano] off by 10^6 2026-04-21 18:41:02 -04:00
Frank a3ed215038 update zen models 2026-04-21 17:43:38 -04:00
Mohd Saif d45df0530b fix: correct Gemma 4 26B model ID for Google provider
Updated model ID from gemma-4-26b-it to gemma-4-26b-a4b-it to match actual Gemini API. Also added missing id field and renamed the file accordingly.
2026-04-22 01:51:23 +05:30
Jack 990531258b Merge pull request #1527 from anomalyco/feat/opencode-go-kimi-k2.6-3x-name
providers(opencode-go): rename kimi k2.6
2026-04-21 22:59:26 +08:00
Jack cd2c9e3b62 providers(opencode-go): rename kimi k2.6 2026-04-21 22:54:53 +08:00
Aiden Cline a114991278 Merge pull request #1505 from rocuevas9511/feat/deepinfra-qwen-3.5-35b
feat: add Qwen 3.5 35B A3B to deepinfra
2026-04-21 10:02:27 -04:00
Aiden Cline 5ff2035cee Merge pull request #1520 from Marenz/add-deepinfra-qwen3.6-35b-a3b
Add Qwen3.6-35B-A3B to Deep Infra
2026-04-21 10:01:56 -04:00
Aiden Cline a5993cc140 Merge pull request #1515 from llc1123/chore/zenmux-update
providers(zenmux): add support for kimi k2.6
2026-04-21 10:00:06 -04:00
Aiden Cline aebe4b6cd0 Merge pull request #1517 from otterDeveloper/kimi2.6-pull
add Firework's kimi k2.6
2026-04-21 09:59:54 -04:00
Aiden Cline 214adb1154 Merge pull request #1522 from ceoAppsknight/kilo/kimi-k2.6
Added kilo/kimi-k2.6
2026-04-21 09:59:33 -04:00
Aiden Cline b301c1f8b6 Merge pull request #1523 from sk0x0y/feature/nanogpt-kimi-k2.6-qwen-3.6
feat(nano-gpt): add Kimi K2.6 and Qwen 3.6 models
2026-04-21 09:58:45 -04:00
Aiden Cline b81c8b385b Merge pull request #1507 from rocuevas9511/feat/deepinfra-qwen-3.5-397b
feat: add Qwen 3.5 397B A17B to deepinfra
2026-04-21 09:58:28 -04:00
rocuevas9511 1caa438b3e fix: remove id field (per Marenz feedback) 2026-04-21 07:35:52 -06:00
rocuevas9511 673bc92f4d fix: remove id field (per Marenz feedback) 2026-04-21 07:35:38 -06:00
Jack 0159eaa158 Merge pull request #1526 from anomalyco/feat/moonshotai-cn-kimi-k2.6
providers(moonshotai-cn): add kimi k2.6
2026-04-21 20:39:05 +08:00
Jack efdc7b9a54 providers(moonshotai-cn): add kimi k2.6 2026-04-21 20:26:19 +08:00
Jack b08721206d Merge pull request #1525 from anomalyco/feat/moonshotai-kimi-k2.6
providers(moonshotai): add kimi k2.6
2026-04-21 19:35:13 +08:00
Jack fe0d4cd9fa providers(moonshotai): add kimi k2.6 2026-04-21 19:33:06 +08:00
sk0x0y 738ad6ed70 feat(nano-gpt): add Kimi K2.6 and Qwen 3.6 model family 2026-04-21 19:22:38 +09:00
Syed Assadullah Shah 19b66fbaf2 Added kilo/kimi-k2.6 2026-04-21 15:19:17 +05:00
Mathias L. Baumann c416836497 Add Qwen3.6-35B-A3B to Deep Infra
35B-total / 3B-active MoE (256 experts, 8 routed + 1 shared).
262K native context, vision + video input, thinking mode, tool calls.
Apache 2.0, $0.20 in / $1.00 out per 1M tokens.
2026-04-21 11:58:04 +02:00
rocuevas9511 059cc4b91f fix: update model id to match DeepInfra API 2026-04-21 00:33:20 -06:00
rocuevas9511 116bd328a6 fix: update model id to match DeepInfra API 2026-04-21 00:31:22 -06:00
Frank aa30ce3ef2 update zen models 2026-04-21 02:12:27 -04:00
Frank 9533a47906 update zen models 2026-04-21 01:20:47 -04:00
Miguel Medina ad18f780f0 add firework's kimi 2.6 2026-04-20 23:12:11 -06:00
粒粒橙 a48519e557 providers(zenmux): add support for kimi k2.6 2026-04-21 10:13:22 +08:00
Aiden Cline 23f5e74392 Merge pull request #1514 from mfbalestra/add/kimi-k2.6-ollama-cloud
providers/ollama-cloud: add kimi-k2.6:cloud
2026-04-20 21:47:51 -04:00
Aiden Cline 7a50ea28a1 Merge pull request #1510 from dpuyosa/feat/venice-add-kimi-k2-6
Venice: Add Kimi K2.6 model configuration
2026-04-20 21:45:49 -04:00
mfbalestra 5944f94197 providers(ollama-cloud): add kimi-k2.6:cloud 2026-04-20 22:45:01 -03:00
Aiden Cline 98732b7d76 Merge pull request #1512 from SomeoneWithOptions/dev
add kimi-K2.6 for OpenRouter provider
2026-04-20 21:44:39 -04:00
SomeoneWithOptions c6412d7e59 add kimi-K2.6 for OpenRouter provider 2026-04-20 18:59:49 -05:00
dpuyosa b5a7a6e974 [venice] Add Kimi K2.6 model configuration
- Add new model definition for Venice provider
- Include cost, limits, and modality specs
- Enable reasoning, tool calling, and image input
2026-04-21 00:40:19 +02:00
Aiden Cline ba7c3d7b0b Merge pull request #1509 from kostiak/patch-1
Add support for Kimi-K2.6 in Kimi For Coding provider
2026-04-20 18:02:04 -04:00
Aiden Cline 53a9a2a36d Merge pull request #1508 from hanouticelina/add-kimi-k2.6-modeling
feat(huggingface): add Kimi K2.6
2026-04-20 18:01:32 -04:00
kostiak 3b6bca9b90 Add support for Kimi-K2.6 for Kimi For Coding provider 2026-04-21 00:24:51 +03:00
Celina Hanouti f5a048060f add support for Kimi-K2.6 for Hugging Face provider 2026-04-20 21:41:14 +01:00
rocuevas9511 9e6178a5e3 fix: update cost for Qwen 3.5 397B A17B 2026-04-20 13:38:45 -06:00
rocuevas9511 e4150361b3 fix: update cost for Qwen 3.5 35B A3B 2026-04-20 13:38:06 -06:00
rocuevas9511 8de0fc059d add Qwen 3.5 397B A17B to deepinfra 2026-04-20 13:34:56 -06:00
rocuevas9511 054733884f add Qwen 3.5 35B A3B to deepinfra 2026-04-20 13:32:54 -06:00
Aiden Cline 3d09981eda Merge pull request #1499 from rovo89/patch-1
[google] Fix cache_read cost in gemini-2.5-flash model
2026-04-20 14:43:53 -04:00
Aiden Cline 6877af7770 Merge pull request #1501 from mchenco/kimi-k2.6
Add Kimi K2.6 to Workers AI and AI Gateway
2026-04-20 14:41:58 -04:00
Nacho F. Lizaur 802985f76c feat: update kiro provider to use kiro-acp-ai-provider, add opus 4.7 2026-04-20 20:13:43 +02:00
mchen 794993fd48 Add Kimi K2.6 to Workers AI and AI Gateway 2026-04-20 13:54:31 -04:00
Jack 00b53a422a separate opencode-go kimi k2 families 2026-04-21 01:00:50 +08:00
Jack 2ccecb6011 Merge pull request #1500 from chl-0537/feature/add-tencent
feat: rename model
2026-04-20 22:49:09 +08:00
mickalchen 9b7e3abf00 rename model 2026-04-20 22:02:37 +08:00
Robert Vollmer 27d6a3d503 [google] Fix cache_read cost in gemini-2.5-flash model
https://ai.google.dev/gemini-api/docs/pricing#gemini-2.5-flash

There's no cache_read_audio, is there?
2026-04-20 15:02:54 +02:00
Lyda 6beb1f8be2 feat(302ai): standardize Claude model metadata and capabilities
- Add family field for all Claude models (claude-haiku, claude-opus, claude-sonnet)
- Standardize knowledge cutoff dates to full date format (YYYY-MM-DD)
- Enable reasoning capability for Claude Opus 4.x and Sonnet 4.x series models
- Add PDF input modality support for claude-opus-4-1-20250805
- Update claude-opus-4-7 context limit to 1,000,000 tokens
2026-04-20 16:10:52 +08:00
Lyda e0c1124fe2 feat(302ai): update GPT model capabilities and specifications
- Add structured_output capability for GPT-4.1, GPT-4o, and GPT-5 series models
- Enable reasoning capability and disable temperature for GPT-5 series models
- Update context limits: GPT-4.1 series to 1,047,576 tokens, GPT-5.4 series to 1,050,000 tokens
- Add input token limits for GPT-5 series models (272,000 or 922,000 tokens)
- Update knowledge cutoffs across GPT-5 series (2024-05-30 to 2025-08-31)
- Add PDF input modality support for GPT-4
2026-04-20 15:58:32 +08:00
Lyda bf4ceb7baa feat(302ai): update GLM model capabilities and knowledge cutoffs
- Enable reasoning capability for GLM-4.5-air, GLM-4.5, GLM-4.5V, and GLM-4.6V models
- Update knowledge cutoff to 2025-04 for GLM-4.5, GLM-4.5V, GLM-4.6, GLM-4.6V, and GLM-4.7
- Add video input modality support for GLM-4.5V and GLM-4.6V
- Add structured_output capability for GLM-5-turbo and GLM-5.1
- Add interleaved reasoning_content field for GLM-4.7, GLM-5, GLM-5-turbo, GLM-5.1, and GLM-5V-turbo
2026-04-20 15:48:29 +08:00
Nacho F. Lizaur 8f340e1eb2 feat: update kiro provider to use kiro-ai-provider npm package 2026-04-13 23:12:11 +02:00
Nacho F. Lizaur 62da5b0cbd feat: enable reasoning on Kiro Claude models 2026-04-13 19:49:25 +02:00
Nacho F. Lizaur 4e49abc10c feat: add Kiro provider 2026-04-13 19:49:25 +02:00
massaindustries 6ecd9ec509 add qwen-next-coder-2 2026-02-05 09:11:08 +00:00
massaindustries bb42d0b855 add qwen-next-coder 2026-02-05 09:09:30 +00:00
massaindustries a46966efef add-regolo-02 2026-01-29 15:14:02 +00:00
massaindustries 19ace4436f add-regolo-01 2026-01-29 12:36:44 +00:00
799 changed files with 9497 additions and 4490 deletions
+4 -12
View File
@@ -5,7 +5,7 @@
"": {
"name": "models.dev",
"dependencies": {
"@cloudflare/workers-types": "^4.20250801.0",
"@cloudflare/workers-types": "^4.20260424.1",
"sst": "3.17.23",
},
},
@@ -49,7 +49,7 @@
"zod": "3.24.2",
},
"packages": {
"@cloudflare/workers-types": ["@cloudflare/workers-types@4.20250801.0", "", {}, "sha512-BQmMdoOGClY23TesgkR1PeGrPvPsSFD/zW7pDzWZHkOEsqkPk2A91h52bP8GbtKYTl1vdaYjQgJlGsP6Ih4G0w=="],
"@cloudflare/workers-types": ["@cloudflare/workers-types@4.20260424.1", "", {}, "sha512-0DLJ9yEk1KKzPbqop80Gw/P1wkKKzawmipULiJWdBXIBCoMvE0OVWms3IrL/Q/G7tfmPop9yF4XlZ69k9JLYng=="],
"@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.6.1", "", { "dependencies": { "content-type": "^1.0.5", "cors": "^2.8.5", "eventsource": "^3.0.2", "express": "^5.0.1", "express-rate-limit": "^7.5.0", "pkce-challenge": "^4.1.0", "raw-body": "^3.0.0", "zod": "^3.23.8", "zod-to-json-schema": "^3.24.1" } }, "sha512-oxzMzYCkZHMntzuyerehK3fV6A2Kwh5BD6CGEJSVDU2QNEhfLOptf2X7esQgaHZXHZY0oHmMsOtIDLP71UJXgA=="],
@@ -59,7 +59,7 @@
"@tsconfig/bun": ["@tsconfig/bun@1.0.8", "", {}, "sha512-JlJaRaS4hBTypxtFe8WhnwV8blf0R+3yehLk8XuyxUYNx6VXsKCjACSCvOYEFUiqlhlBWxtYCn/zRlOb8BzBQg=="],
"@types/bun": ["@types/bun@1.2.16", "", { "dependencies": { "bun-types": "1.2.16" } }, "sha512-1aCZJ/6nSiViw339RsaNhkNoEloLaPzZhxMOYEa7OzRzO41IGg5n/7I43/ZIAW/c+Q6cT12Vf7fOZOoVIzb5BQ=="],
"@types/bun": ["@types/bun@1.3.0", "", { "dependencies": { "bun-types": "1.3.0" } }, "sha512-+lAGCYjXjip2qY375xX/scJeVRmZ5cY0wyHYyCYxNcdEXrQ4AOe3gACgd4iQ8ksOslJtW4VNxBJ8llUwc3a6AA=="],
"@types/node": ["@types/node@22.13.9", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="],
@@ -79,7 +79,7 @@
"buffer": ["buffer@4.9.2", "", { "dependencies": { "base64-js": "^1.0.2", "ieee754": "^1.1.4", "isarray": "^1.0.0" } }, "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg=="],
"bun-types": ["bun-types@1.2.16", "", { "dependencies": { "@types/node": "*" } }, "sha512-ciXLrHV4PXax9vHvUrkvun9VPVGOVwbbbBF/Ev1cXz12lyEZMoJpIJABOfPcN9gDJRaiKF9MVbSygLg4NXu3/A=="],
"bun-types": ["bun-types@1.3.0", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-u8X0thhx+yJ0KmkxuEo9HAtdfgCBaM/aI9K90VQcQioAmkVp3SG3FkwWGibUFz3WdXAdcsqOcbU40lK7tbHdkQ=="],
"bytes": ["bytes@3.1.2", "", {}, "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="],
@@ -325,8 +325,6 @@
"http-errors/statuses": ["statuses@2.0.1", "", {}, "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="],
"models.dev/@types/bun": ["@types/bun@1.3.0", "", { "dependencies": { "bun-types": "1.3.0" } }, "sha512-+lAGCYjXjip2qY375xX/scJeVRmZ5cY0wyHYyCYxNcdEXrQ4AOe3gACgd4iQ8ksOslJtW4VNxBJ8llUwc3a6AA=="],
"opencontrol/@tsconfig/bun": ["@tsconfig/bun@1.0.7", "", {}, "sha512-udGrGJBNQdXGVulehc1aWT73wkR9wdaGBtB6yL70RJsqwW/yJhIg6ZbRlPOfIUiFNrnBuYLBi9CSmMKfDC7dvA=="],
"opencontrol/hono": ["hono@4.7.4", "", {}, "sha512-Pst8FuGqz3L7tFF+u9Pu70eI0xa5S3LPUmrNd5Jm8nTHze9FxLTK9Kaj5g/k4UcwuJSXTP65SyHOPLrffpcAJg=="],
@@ -334,11 +332,5 @@
"openid-client/jose": ["jose@4.15.9", "", {}, "sha512-1vUQX+IdDMVPj4k8kOxgUqlcK518yluMuGZwqlr44FS1ppZB/5GWh4rZG89erpOBOJjU/OBsnCVFfapsRz6nEA=="],
"bun-types/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="],
"models.dev/@types/bun/bun-types": ["bun-types@1.3.0", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-u8X0thhx+yJ0KmkxuEo9HAtdfgCBaM/aI9K90VQcQioAmkVp3SG3FkwWGibUFz3WdXAdcsqOcbU40lK7tbHdkQ=="],
"models.dev/@types/bun/bun-types/@types/node": ["@types/node@24.0.3", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-R4I/kzCYAdRLzfiCabn9hxWfbuHS573x+r0dJMkkzThEa7pbrcDWK+9zu3e7aBOouf+rQAciqPFMnxwr0aWgKg=="],
"models.dev/@types/bun/bun-types/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="],
}
}
+4 -2
View File
@@ -17,13 +17,15 @@
"scripts": {
"validate": "bun ./packages/core/script/validate.ts",
"compare:migrations": "bun ./packages/core/script/compare-model-migrations.ts",
"chutes:generate": "bun ./packages/core/script/generate-chutes.ts",
"helicone:generate": "bun ./packages/core/script/generate-helicone.ts",
"venice:generate": "bun ./packages/core/script/generate-venice.ts",
"vercel:generate": "bun ./packages/core/script/generate-vercel.ts",
"wandb:generate": "bun ./packages/core/script/generate-wandb.ts"
"wandb:generate": "bun ./packages/core/script/generate-wandb.ts",
"digitalocean:generate": "bun ./packages/core/script/generate-digitalocean.ts"
},
"dependencies": {
"@cloudflare/workers-types": "^4.20250801.0",
"@cloudflare/workers-types": "^4.20260424.1",
"sst": "3.17.23"
}
}
+589
View File
@@ -0,0 +1,589 @@
#!/usr/bin/env bun
/**
* Generates Chutes model TOML files from the Chutes LLM API.
*
* Flags:
* --dry-run: Preview changes without writing files
* --new-only: Only create new models, skip updating existing ones
* --keep-orphans: Don't delete TOML files for models no longer in the API
*/
import { z } from "zod";
import path from "node:path";
import { mkdir } from "node:fs/promises";
import { ModelFamilyValues } from "../src/family.js";
const API_ENDPOINT = "https://llm.chutes.ai/v1/models";
enum SkipZeroFields {
LimitContext = "limit.context",
LimitOutput = "limit.output",
}
const Pricing = z.object({
prompt: z.number().optional(),
completion: z.number().optional(),
input_cache_read: z.number().optional(),
}).passthrough();
const ChutesModel = z.object({
id: z.string(),
created: z.number(),
pricing: Pricing.optional(),
context_length: z.number().optional(),
max_output_length: z.number().optional(),
max_model_len: z.number().optional(),
input_modalities: z.array(z.string()).optional(),
output_modalities: z.array(z.string()).optional(),
supported_features: z.array(z.string()).optional(),
supported_sampling_parameters: z.array(z.string()).optional(),
quantization: z.string().optional(),
}).passthrough();
const ChutesResponse = z.object({
data: z.array(ChutesModel),
}).passthrough();
interface ExistingModel {
name?: string;
family?: string;
attachment?: boolean;
reasoning?: boolean;
tool_call?: boolean;
structured_output?: boolean;
temperature?: boolean;
knowledge?: string;
release_date?: string;
last_updated?: string;
open_weights?: boolean;
interleaved?: boolean | { field: string };
status?: string;
cost?: {
input?: number;
output?: number;
cache_read?: number;
};
limit?: {
context?: number;
output?: number;
};
modalities?: {
input?: string[];
output?: string[];
};
}
interface MergedModel {
name: string;
family?: string;
attachment: boolean;
reasoning: boolean;
tool_call: boolean;
structured_output?: boolean;
temperature: boolean;
knowledge?: string;
release_date: string;
last_updated: string;
open_weights: boolean;
interleaved?: boolean | { field: string };
status?: string;
cost?: {
input: number;
output: number;
cache_read?: number;
};
limit: {
context: number;
output: number;
};
modalities: {
input: string[];
output: string[];
};
}
interface Changes {
field: string;
oldValue: string;
newValue: string;
}
// ── Utility functions ────────────────────────────────────────────────
function timestampToDate(timestamp: number): string {
const date = new Date(timestamp * 1000);
return date.toISOString().slice(0, 10);
}
function getTodayDate(): string {
return new Date().toISOString().slice(0, 10);
}
function formatNumber(n: number): string {
if (n >= 1000) {
return n.toString().replace(/\B(?=(\d{3})+(?!\d))/g, "_");
}
return n.toString();
}
/**
* Humanize a model ID into a readable name.
* Strips the org prefix and replaces hyphens with spaces.
* e.g. "Qwen/Qwen3-32B-TEE" → "Qwen3 32B TEE"
*/
function humanizeModelName(modelId: string): string {
const parts = modelId.split("/");
const modelPart = parts[parts.length - 1];
return modelPart.replace(/-/g, " ");
}
// ── Family inference (same approach as generate-vercel.ts) ───────────
function isSubstring(target: string, family: string): boolean {
return target.toLowerCase().includes(family.toLowerCase());
}
function matchesFamily(target: string, family: string): boolean {
const targetLower = target.toLowerCase();
const familyLower = family.toLowerCase();
let familyIdx = 0;
for (let i = 0; i < targetLower.length && familyIdx < familyLower.length; i++) {
if (targetLower[i] === familyLower[familyIdx]) {
familyIdx++;
}
}
return familyIdx === familyLower.length;
}
function inferFamily(modelId: string, modelName: string): string | undefined {
const sortedFamilies = [...ModelFamilyValues].sort((a, b) => b.length - a.length);
// First pass: try exact substring matches
for (const family of sortedFamilies) {
if (isSubstring(modelId, family)) {
return family;
}
}
for (const family of sortedFamilies) {
if (isSubstring(modelName, family)) {
return family;
}
}
// Second pass: fall back to subsequence matching
for (const family of sortedFamilies) {
if (matchesFamily(modelId, family)) {
return family;
}
}
for (const family of sortedFamilies) {
if (matchesFamily(modelName, family)) {
return family;
}
}
return undefined;
}
// ── Load existing TOML ───────────────────────────────────────────────
async function loadExistingModel(filePath: string): Promise<ExistingModel | null> {
try {
const file = Bun.file(filePath);
if (!(await file.exists())) {
return null;
}
const toml = await import(filePath, { with: { type: "toml" } }).then(
(mod) => mod.default,
);
return toml as ExistingModel;
} catch (e) {
console.warn(`Warning: Failed to parse existing file ${filePath}:`, e);
return null;
}
}
// ── Merge API data with existing TOML ────────────────────────────────
function mergeModel(
apiModel: z.infer<typeof ChutesModel>,
existing: ExistingModel | null,
): MergedModel {
const features = new Set(apiModel.supported_features ?? []);
const samplingParams = new Set(apiModel.supported_sampling_parameters ?? []);
const inputMods = apiModel.input_modalities ?? ["text"];
const outputMods = apiModel.output_modalities ?? ["text"];
// Capabilities from API features
const hasAttachment = inputMods.some((m) =>
m === "image" || m === "video" || m === "pdf",
);
const hasReasoning = features.has("reasoning");
const hasToolCall = features.has("tools");
const hasStructuredOutput = features.has("structured_outputs");
const hasTemperature = samplingParams.size > 0
? samplingParams.has("temperature")
: true; // default true if no sampling params info
// Preserve existing values when available (manually specified)
const modelName = existing?.name ?? humanizeModelName(apiModel.id);
const family = existing?.family ?? inferFamily(apiModel.id, modelName);
const knowledge = existing?.knowledge;
const interleaved = existing?.interleaved;
const status = existing?.status;
// Release date: existing > API created timestamp > today
const releaseDate = existing?.release_date
?? timestampToDate(apiModel.created)
?? getTodayDate();
// Context limit: prefer context_length, fallback to max_model_len
const apiContext = apiModel.context_length ?? apiModel.max_model_len ?? 0;
const contextLimit = apiContext > 0
? apiContext
: (existing?.limit?.context ?? 0);
// Output limit: prefer max_output_length, fallback to existing
const apiOutput = apiModel.max_output_length ?? 0;
const outputLimit = apiOutput > 0
? apiOutput
: (existing?.limit?.output ?? 0);
const merged: MergedModel = {
name: modelName,
family,
attachment: hasAttachment,
reasoning: hasReasoning,
tool_call: hasToolCall,
temperature: hasTemperature,
release_date: releaseDate,
last_updated: getTodayDate(),
open_weights: true, // Chutes hosts open-weight models
...(hasStructuredOutput && { structured_output: hasStructuredOutput }),
...(knowledge && { knowledge }),
...(interleaved !== undefined && { interleaved }),
...(status && { status }),
limit: {
context: contextLimit,
output: outputLimit,
},
modalities: {
input: inputMods,
output: outputMods,
},
};
// Cost: API values are already in USD per 1M tokens — use directly
if (apiModel.pricing) {
const inputPrice = apiModel.pricing.prompt;
const outputPrice = apiModel.pricing.completion;
const cacheReadPrice = apiModel.pricing.input_cache_read;
if (inputPrice !== undefined && outputPrice !== undefined) {
merged.cost = {
input: inputPrice,
output: outputPrice,
...(cacheReadPrice !== undefined && { cache_read: cacheReadPrice }),
};
}
}
return merged;
}
// ── TOML formatting ──────────────────────────────────────────────────
function formatToml(model: MergedModel): string {
const lines: string[] = [];
lines.push(`# Auto-generated by generate-chutes.ts — do not edit pricing, limits, or capabilities.`);
lines.push(`# Manual overrides preserved on re-run: name, family, knowledge, interleaved, status`);
lines.push(`name = "${model.name.replace(/"/g, '\\"')}"`);
if (model.family) {
lines.push(`family = "${model.family}"`);
}
lines.push(`release_date = "${model.release_date}"`);
lines.push(`last_updated = "${model.last_updated}"`);
lines.push(`attachment = ${model.attachment}`);
lines.push(`reasoning = ${model.reasoning}`);
lines.push(`temperature = ${model.temperature}`);
lines.push(`tool_call = ${model.tool_call}`);
if (model.structured_output !== undefined) {
lines.push(`structured_output = ${model.structured_output}`);
}
lines.push(`open_weights = ${model.open_weights}`);
if (model.knowledge) {
lines.push(`knowledge = "${model.knowledge}"`);
}
if (model.status) {
lines.push(`status = "${model.status}"`);
}
if (model.cost) {
lines.push("");
lines.push(`[cost]`);
lines.push(`input = ${model.cost.input}`);
lines.push(`output = ${model.cost.output}`);
if (model.cost.cache_read !== undefined) {
lines.push(`cache_read = ${model.cost.cache_read}`);
}
}
lines.push("");
lines.push(`[limit]`);
lines.push(`context = ${formatNumber(model.limit.context)}`);
lines.push(`output = ${formatNumber(model.limit.output)}`);
lines.push("");
lines.push(`[modalities]`);
lines.push(`input = [${model.modalities.input.map((m) => `"${m}"`).join(", ")}]`);
lines.push(`output = [${model.modalities.output.map((m) => `"${m}"`).join(", ")}]`);
if (model.interleaved !== undefined) {
lines.push("");
if (model.interleaved === true) {
lines.push(`interleaved = true`);
} else if (typeof model.interleaved === "object") {
lines.push(`[interleaved]`);
lines.push(`field = "${model.interleaved.field}"`);
}
}
return lines.join("\n") + "\n";
}
// ── Change detection ─────────────────────────────────────────────────
function detectChanges(
existing: ExistingModel | null,
merged: MergedModel,
): Changes[] {
if (!existing) return [];
const changes: Changes[] = [];
const EPSILON = 0.001;
const shouldSkipZero = (field: string, oldVal: unknown, newVal: unknown): boolean => {
if (!Object.values(SkipZeroFields).includes(field as SkipZeroFields)) {
return false;
}
return (typeof oldVal === "number" && oldVal === 0) || (typeof newVal === "number" && newVal === 0);
};
const formatValue = (val: unknown): string => {
if (typeof val === "number") return formatNumber(val);
if (Array.isArray(val)) return `[${val.join(", ")}]`;
if (val === undefined) return "(none)";
return String(val);
};
const isMaterialPriceDiff = (oldPrice: unknown, newPrice: unknown): boolean => {
if (oldPrice === 0 && newPrice === undefined) return false;
if (oldPrice !== undefined && newPrice !== undefined) {
return Math.abs((oldPrice as number) - (newPrice as number)) > EPSILON;
}
return oldPrice !== newPrice;
};
const compare = (field: string, oldVal: unknown, newVal: unknown) => {
if (shouldSkipZero(field, oldVal, newVal)) return;
const isDiff = field.startsWith("cost.")
? isMaterialPriceDiff(oldVal, newVal)
: JSON.stringify(oldVal) !== JSON.stringify(newVal);
if (isDiff) {
changes.push({
field,
oldValue: formatValue(oldVal),
newValue: formatValue(newVal),
});
}
};
compare("name", existing.name, merged.name);
compare("family", existing.family, merged.family);
compare("attachment", existing.attachment, merged.attachment);
compare("reasoning", existing.reasoning, merged.reasoning);
compare("tool_call", existing.tool_call, merged.tool_call);
compare("structured_output", existing.structured_output, merged.structured_output);
compare("open_weights", existing.open_weights, merged.open_weights);
compare("release_date", existing.release_date, merged.release_date);
compare("cost.input", existing.cost?.input, merged.cost?.input);
compare("cost.output", existing.cost?.output, merged.cost?.output);
compare("cost.cache_read", existing.cost?.cache_read, merged.cost?.cache_read);
compare("limit.context", existing.limit?.context, merged.limit.context);
compare("limit.output", existing.limit?.output, merged.limit.output);
compare("modalities.input", existing.modalities?.input, merged.modalities.input);
compare("modalities.output", existing.modalities?.output, merged.modalities.output);
return changes;
}
// ── Main ─────────────────────────────────────────────────────────────
async function main() {
const args = process.argv.slice(2);
const dryRun = args.includes("--dry-run");
const newOnly = args.includes("--new-only");
const keepOrphans = args.includes("--keep-orphans");
const modelsDir = path.join(
import.meta.dirname,
"..",
"..",
"..",
"providers",
"chutes",
"models",
);
console.log(`${dryRun ? "[DRY RUN] " : ""}${newOnly ? "[NEW ONLY] " : ""}${keepOrphans ? "[KEEP ORPHANS] " : ""}Fetching Chutes models from API...`);
const res = await fetch(API_ENDPOINT);
if (!res.ok) {
console.error(`Failed to fetch API: ${res.status} ${res.statusText}`);
process.exit(1);
}
const json = await res.json();
const parsed = ChutesResponse.safeParse(json);
if (!parsed.success) {
console.error("Invalid API response:", parsed.error.errors);
process.exit(1);
}
const apiModels = parsed.data.data;
// Scan existing TOML files
const existingFiles = new Set<string>();
try {
for await (const file of new Bun.Glob("**/*.toml").scan({
cwd: modelsDir,
absolute: false,
})) {
existingFiles.add(file);
}
} catch {
}
console.log(`Found ${apiModels.length} models in API, ${existingFiles.size} existing files\n`);
const apiModelIds = new Set<string>();
let created = 0;
let updated = 0;
let unchanged = 0;
for (const apiModel of apiModels) {
const relativePath = `${apiModel.id}.toml`;
const filePath = path.join(modelsDir, relativePath);
const dirPath = path.dirname(filePath);
apiModelIds.add(relativePath);
const existing = await loadExistingModel(filePath);
const merged = mergeModel(apiModel, existing);
const tomlContent = formatToml(merged);
if (existing === null) {
created++;
if (dryRun) {
console.log(`[DRY RUN] Would create: ${relativePath}`);
console.log(` name = "${merged.name}"`);
if (merged.family) {
console.log(` family = "${merged.family}" (inferred)`);
}
console.log("");
} else {
await mkdir(dirPath, { recursive: true });
await Bun.write(filePath, tomlContent);
console.log(`Created: ${relativePath}`);
}
} else {
if (newOnly) {
unchanged++;
continue;
}
const changes = detectChanges(existing, merged);
const existingContent = await Bun.file(filePath).text();
const formatChanged = existingContent !== tomlContent;
if (changes.length > 0 || formatChanged) {
updated++;
if (dryRun) {
console.log(`[DRY RUN] Would update: ${relativePath}`);
} else {
await mkdir(dirPath, { recursive: true });
await Bun.write(filePath, tomlContent);
console.log(`Updated: ${relativePath}`);
}
for (const change of changes) {
console.log(` ${change.field}: ${change.oldValue}${change.newValue}`);
}
if (changes.length === 0 && formatChanged) {
console.log(` (format-only change)`);
}
console.log("");
} else {
unchanged++;
}
}
}
// Handle orphaned files (on disk but not in API)
const orphaned: string[] = [];
for (const file of existingFiles) {
if (!apiModelIds.has(file)) {
orphaned.push(file);
const orphanPath = path.join(modelsDir, file);
if (keepOrphans) {
console.log(`Orphaned (kept): ${file}`);
} else if (dryRun) {
console.log(`[DRY RUN] Would delete: ${file}`);
} else {
await Bun.file(orphanPath).delete();
console.log(`Deleted: ${file}`);
// Clean up empty parent directories
const parentDir = path.dirname(orphanPath);
try {
const remaining = [];
for await (const entry of new Bun.Glob("*").scan({ cwd: parentDir })) {
remaining.push(entry);
}
if (remaining.length === 0) {
const { rmdir } = await import("node:fs/promises");
await rmdir(parentDir);
console.log(` Removed empty directory: ${path.basename(parentDir)}/`);
}
} catch {
// Directory not empty or other error, ignore
}
}
}
}
console.log("");
if (dryRun) {
console.log(
`Summary: ${created} would be created, ${updated} would be updated, ${unchanged} unchanged, ${orphaned.length} would be deleted`,
);
} else if (keepOrphans) {
console.log(
`Summary: ${created} created, ${updated} updated, ${unchanged} unchanged, ${orphaned.length} orphaned (kept)`,
);
} else {
console.log(
`Summary: ${created} created, ${updated} updated, ${unchanged} unchanged, ${orphaned.length} deleted`,
);
}
}
await main();
@@ -0,0 +1,732 @@
#!/usr/bin/env bun
/**
* Generates DigitalOcean model TOML files from two public APIs:
*
* - https://api.digitalocean.com/v2/gen-ai/models (model metadata, lifecycle, modalities, limits)
* - https://www.digitalocean.com/api/static-content/v1/products (pricing, including >200k tiers)
*
* The v2 models API requires a DigitalOcean personal access token or model access key,
* read from the DIGITALOCEAN_API_TOKEN environment variable (or --api-key flag).
* The static-content pricing API is public and requires no auth.
*
* Cache pricing (cache_read, cache_write) is NOT available from any DO API and is
* preserved from existing TOML files when present.
*
* Fields the APIs cannot provide (preserved from existing TOMLs, never overwritten):
* family, knowledge, open_weights, interleaved, attachment, release_date,
* cache_read, cache_write
*
* Flags:
* --dry-run Preview changes without writing files
* --new-only Only create new models, skip updating existing ones
* --api-key=<key> DigitalOcean API key (overrides DIGITALOCEAN_API_TOKEN env var)
*/
import { z } from "zod";
import path from "node:path";
import { mkdir } from "node:fs/promises";
import { ModelFamilyValues } from "../src/family.js";
const MODELS_API = "https://api.digitalocean.com/v2/gen-ai/models";
const PRICING_API = "https://www.digitalocean.com/api/static-content/v1/products";
// ---------------------------------------------------------------------------
// v2 models API schema
// ---------------------------------------------------------------------------
const DoModel = z
.object({
id: z.string(),
name: z.string(),
lifecycle_status: z.string(),
type: z.string().optional(),
thinking: z.boolean().optional(),
context_window: z.union([z.number(), z.string()]).optional(),
modalities: z
.object({
input: z.array(z.string()).optional(),
output: z.array(z.string()).optional(),
})
.optional(),
settings: z
.array(
z.object({
name: z.string(),
max: z.number().optional(),
default_value: z.number().optional(),
}),
)
.optional(),
created_at: z.string().optional(),
})
.passthrough();
const DoModelsResponse = z
.object({
models: z.array(DoModel),
})
.passthrough();
// ---------------------------------------------------------------------------
// static-content pricing API schema
// ---------------------------------------------------------------------------
const PricingEntry = z
.object({
name: z.string(),
slug: z.string(),
model: z.string(),
prompt_tokens: z.string().optional(), // "≤200k" | ">200k" | undefined
price: z.object({ rate: z.number() }),
})
.passthrough();
const StaticContentResponse = z
.object({
gradient: z.object({
models: z.array(PricingEntry),
}),
})
.passthrough();
// ---------------------------------------------------------------------------
// Derived pricing map
// ---------------------------------------------------------------------------
interface ModelPricing {
input: number;
output: number;
inputOver200k?: number;
outputOver200k?: number;
}
// Map marketing names from /v1/products to API model IDs from /v2/gen-ai/models.
// The pricing API uses display names, not the machine IDs, so this table is the
// join key. Add entries here when DO adds new models with tiered pricing.
const PRICING_NAME_MAP: Record<string, string> = {
// Anthropic
"claude sonnet 4.6": "anthropic-claude-4.6-sonnet",
"claude sonnet 4.5": "anthropic-claude-4.5-sonnet",
"claude sonnet 4": "anthropic-claude-sonnet-4",
"claude haiku 4.5": "anthropic-claude-haiku-4.5",
"claude opus 4.6": "anthropic-claude-opus-4.6",
"claude opus 4.5": "anthropic-claude-opus-4.5",
"claude opus 4.1": "anthropic-claude-4.1-opus",
"claude opus 4": "anthropic-claude-opus-4",
// OpenAI
"gpt-5.4": "openai-gpt-5.4",
"gpt-5.4 mini": "openai-gpt-5.4-mini",
"gpt-5.4 nano": "openai-gpt-5.4-nano",
"gpt-5.4 pro": "openai-gpt-5.4-pro",
"gpt-5.3-codex": "openai-gpt-5.3-codex",
"gpt-5.2": "openai-gpt-5.2",
"gpt-5.2 pro": "openai-gpt-5.2-pro",
"gpt-5.1-codex-max": "openai-gpt-5.1-codex-max",
"gpt-5": "openai-gpt-5",
"gpt-5 mini": "openai-gpt-5-mini",
"gpt-5 nano": "openai-gpt-5-nano",
"gpt-4.1": "openai-gpt-4.1",
"gpt image 1": "openai-gpt-image-1",
"gpt image 1.5": "openai-gpt-image-1.5",
"gpt-oss-120b": "openai-gpt-oss-120b",
"gpt-oss-20b": "openai-gpt-oss-20b",
"gpt-4o": "openai-gpt-4o",
"gpt-4o mini": "openai-gpt-4o-mini",
"o1": "openai-o1",
"o3-mini": "openai-o3-mini",
// DeepSeek
"deepseek r1 distill llama 70b": "deepseek-r1-distill-llama-70b",
// Llama
"llama 3.3 70b": "llama3.3-70b-instruct",
// DO-hosted
"qwen3-32b": "alibaba-qwen3-32b",
"minimax m2.5 (public preview)": "minimax-m2.5",
"kimi k2.5": "kimi-k2.5",
"nvidia nemotron 3 super 120b (public preview)": "nvidia-nemotron-3-super-120b",
"glm 5": "glm-5",
};
function normalizeDisplayName(raw: string): string {
// Strip " Input Tokens" / " Output Tokens" suffix and lowercase
return raw
.replace(/\s+(input|output)\s+tokens$/i, "")
.trim()
.toLowerCase();
}
function buildPricingMap(entries: z.infer<typeof PricingEntry>[]): Map<string, ModelPricing> {
const map = new Map<string, ModelPricing>();
for (const entry of entries) {
const displayName = normalizeDisplayName(entry.name);
const modelId = PRICING_NAME_MAP[displayName];
if (!modelId) continue;
const isInput = entry.name.toLowerCase().includes("input tokens");
const isOver200k = entry.prompt_tokens === ">200k";
// Round to avoid float noise (e.g. 0.9900000000000001)
const rate = Math.round(entry.price.rate * 10000) / 10000;
const existing = map.get(modelId) ?? ({} as ModelPricing);
if (isInput && isOver200k) existing.inputOver200k = rate;
else if (!isInput && isOver200k) existing.outputOver200k = rate;
else if (isInput) existing.input = rate;
else existing.output = rate;
map.set(modelId, existing);
}
return map;
}
// ---------------------------------------------------------------------------
// Existing TOML shape (fields we read and may preserve)
// ---------------------------------------------------------------------------
interface ExistingModel {
name?: string;
family?: string;
attachment?: boolean;
reasoning?: boolean;
tool_call?: boolean;
structured_output?: boolean;
temperature?: boolean;
knowledge?: string;
release_date?: string;
last_updated?: string;
open_weights?: boolean;
interleaved?: boolean | { field: string };
status?: string;
cost?: {
input?: number;
output?: number;
cache_read?: number;
cache_write?: number;
context_over_200k?: {
input?: number;
output?: number;
cache_read?: number;
cache_write?: number;
context_min?: number;
};
tiers?: Array<{
tier: {
type?: "context";
size: number;
};
input?: number;
output?: number;
cache_read?: number;
cache_write?: number;
}>;
};
limit?: {
context?: number;
input?: number;
output?: number;
};
modalities?: {
input?: string[];
output?: string[];
};
}
async function loadExisting(filePath: string): Promise<ExistingModel | null> {
const file = Bun.file(filePath);
if (!(await file.exists())) return null;
try {
const mod = await import(filePath, { with: { type: "toml" } });
return mod.default as ExistingModel;
} catch (e) {
console.warn(`Warning: failed to parse ${filePath}:`, e);
return null;
}
}
// ---------------------------------------------------------------------------
// Merged model shape (what we write)
// ---------------------------------------------------------------------------
interface MergedModel {
name: string;
family?: string;
attachment: boolean;
reasoning: boolean;
tool_call: boolean;
structured_output?: boolean;
temperature: boolean;
knowledge?: string;
release_date: string;
last_updated: string;
open_weights: boolean;
interleaved?: boolean | { field: string };
status?: string;
cost?: {
input: number;
output: number;
cache_read?: number;
cache_write?: number;
context_over_200k?: {
input: number;
output: number;
cache_read?: number;
cache_write?: number;
context_min?: number;
};
};
limit: {
context: number;
output: number;
};
modalities: {
input: string[];
output: string[];
};
}
// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------
const VALID_INPUT_MODALITIES = new Set(["text", "audio", "image", "video", "pdf"]);
const VALID_OUTPUT_MODALITIES = new Set(["text", "audio", "image", "video", "pdf"]);
function filterInputModalities(raw: string[]): string[] {
return raw.filter((m) => VALID_INPUT_MODALITIES.has(m));
}
function filterOutputModalities(raw: string[]): string[] {
// "code" is not a valid modality in the schema — map to "text"
return [...new Set(raw.map((m) => (m === "code" ? "text" : m)).filter((m) => VALID_OUTPUT_MODALITIES.has(m)))];
}
function getTodayDate(): string {
return new Date().toISOString().slice(0, 10);
}
function formatNumber(n: number): string {
return n >= 1000 ? n.toString().replace(/\B(?=(\d{3})+(?!\d))/g, "_") : n.toString();
}
function inferFamily(modelId: string, modelName: string): string | undefined {
const sorted = [...ModelFamilyValues].sort((a, b) => b.length - a.length);
const targets = [modelId.toLowerCase(), modelName.toLowerCase()];
for (const family of sorted) {
const f = family.toLowerCase();
for (const t of targets) {
if (t.includes(f)) return family;
}
}
return undefined;
}
function getExistingLongContextCost(existing: ExistingModel | null) {
const tier = existing?.cost?.tiers?.find(
(tier) =>
(tier.tier.type === undefined || tier.tier.type === "context") &&
tier.tier.size >= 200_000,
);
if (tier) {
return {
...tier,
context_min: tier.tier.size,
};
}
return existing?.cost?.context_over_200k === undefined
? undefined
: {
...existing.cost.context_over_200k,
context_min: 200_000,
};
}
function getLongContextMin(cost: { context_min?: number }) {
return cost.context_min ?? 200_000;
}
function formatInlineNumber(n: number): string {
return n >= 1000 ? n.toString().replace(/\B(?=(\d{3})+(?!\d))/g, "_") : n.toString();
}
// ---------------------------------------------------------------------------
// Merge API data with existing TOML
// ---------------------------------------------------------------------------
function mergeModel(
apiModel: z.infer<typeof DoModel>,
pricing: ModelPricing | undefined,
existing: ExistingModel | null,
): MergedModel {
const rawInput = apiModel.modalities?.input ?? [];
const rawOutput = apiModel.modalities?.output ?? [];
const inputMods = filterInputModalities(rawInput.length > 0 ? rawInput : existing?.modalities?.input ?? ["text"]);
const outputMods = filterOutputModalities(rawOutput.length > 0 ? rawOutput : existing?.modalities?.output ?? ["text"]);
const maxTokensSetting = apiModel.settings?.find((s) => s.name === "max_tokens");
const maxTokens = maxTokensSetting?.max ?? existing?.limit?.output ?? 0;
const rawContext = apiModel.context_window;
const contextWindow =
rawContext !== undefined
? typeof rawContext === "string"
? parseInt(rawContext, 10)
: rawContext
: (existing?.limit?.context ?? 0);
const isDeprecated = apiModel.lifecycle_status === "end_of_life";
// Fields preserved from existing TOML (APIs don't provide these)
const family = existing?.family ?? inferFamily(apiModel.id, apiModel.name);
const knowledge = existing?.knowledge;
const openWeights = existing?.open_weights ?? false;
const interleaved = existing?.interleaved;
const attachment = existing?.attachment ?? inputMods.some((m) => m !== "text");
// reasoning: trust existing if set, else use API thinking flag as a hint
// (thinking flag is unreliable for non-LLM models so gate on output modality)
const isTextOutput = outputMods.includes("text") && !outputMods.includes("image") && !outputMods.includes("video");
const reasoning = existing?.reasoning ?? (isTextOutput && (apiModel.thinking ?? false));
// tool_call: no API signal, preserve existing or default true for text models
const toolCall = existing?.tool_call ?? isTextOutput;
// temperature: no API signal, preserve or default true
const temperature = existing?.temperature ?? true;
// structured_output: no API signal, preserve only
const structuredOutput = existing?.structured_output;
const releaseDate = existing?.release_date ?? apiModel.created_at?.slice(0, 10) ?? getTodayDate();
const merged: MergedModel = {
name: apiModel.name,
family,
attachment,
reasoning,
tool_call: toolCall,
temperature,
release_date: releaseDate,
last_updated: getTodayDate(),
open_weights: openWeights,
...(structuredOutput !== undefined && { structured_output: structuredOutput }),
...(knowledge && { knowledge }),
...(interleaved !== undefined && { interleaved }),
...(isDeprecated && { status: "deprecated" }),
limit: { context: contextWindow, output: maxTokens },
modalities: { input: inputMods, output: outputMods },
};
// Pricing: static-content API is the sole source of truth for prices.
// The v2 models API pricing is intentionally ignored. If a model has no
// entry in the static-content API, preserve existing TOML prices.
const inputPrice = pricing?.input ?? existing?.cost?.input;
const outputPrice = pricing?.output ?? existing?.cost?.output;
if (inputPrice !== undefined && outputPrice !== undefined) {
merged.cost = {
input: inputPrice,
output: outputPrice,
// Always preserve cache pricing — not available from any DO API
...(existing?.cost?.cache_read !== undefined && { cache_read: existing.cost.cache_read }),
...(existing?.cost?.cache_write !== undefined && { cache_write: existing.cost.cache_write }),
};
// Context-tiered pricing (>200k) from the static-content API
const existingLongContextCost = getExistingLongContextCost(existing);
if (pricing?.inputOver200k !== undefined && pricing?.outputOver200k !== undefined) {
merged.cost.context_over_200k = {
input: pricing.inputOver200k,
output: pricing.outputOver200k,
context_min: existingLongContextCost?.context_min ?? 200_000,
...(existingLongContextCost?.cache_read !== undefined && {
cache_read: existingLongContextCost.cache_read,
}),
...(existingLongContextCost?.cache_write !== undefined && {
cache_write: existingLongContextCost.cache_write,
}),
};
} else if (existingLongContextCost) {
// Preserve manually-entered tiered pricing if API has no data
merged.cost.context_over_200k = {
input: existingLongContextCost.input ?? inputPrice,
output: existingLongContextCost.output ?? outputPrice,
context_min: existingLongContextCost.context_min,
...(existingLongContextCost.cache_read !== undefined && {
cache_read: existingLongContextCost.cache_read,
}),
...(existingLongContextCost.cache_write !== undefined && {
cache_write: existingLongContextCost.cache_write,
}),
};
}
}
return merged;
}
// ---------------------------------------------------------------------------
// TOML serialiser
// ---------------------------------------------------------------------------
function formatToml(model: MergedModel): string {
const lines: string[] = [];
lines.push(`name = "${model.name.replace(/"/g, '\\"')}"`);
if (model.family) lines.push(`family = "${model.family}"`);
lines.push(`release_date = "${model.release_date}"`);
lines.push(`last_updated = "${model.last_updated}"`);
lines.push(`attachment = ${model.attachment}`);
lines.push(`reasoning = ${model.reasoning}`);
lines.push(`temperature = ${model.temperature}`);
lines.push(`tool_call = ${model.tool_call}`);
if (model.structured_output !== undefined) lines.push(`structured_output = ${model.structured_output}`);
if (model.knowledge) lines.push(`knowledge = "${model.knowledge}"`);
lines.push(`open_weights = ${model.open_weights}`);
if (model.status) lines.push(`status = "${model.status}"`);
if (model.interleaved !== undefined) {
lines.push("");
if (model.interleaved === true) {
lines.push(`interleaved = true`);
} else if (typeof model.interleaved === "object") {
lines.push(`[interleaved]`);
lines.push(`field = "${model.interleaved.field}"`);
}
}
if (model.cost) {
lines.push("");
lines.push(`[cost]`);
lines.push(`input = ${model.cost.input}`);
lines.push(`output = ${model.cost.output}`);
if (model.cost.cache_read !== undefined) lines.push(`cache_read = ${model.cost.cache_read}`);
if (model.cost.cache_write !== undefined) lines.push(`cache_write = ${model.cost.cache_write}`);
if (model.cost.context_over_200k) {
lines.push("");
lines.push(`[[cost.tiers]]`);
lines.push(`tier = { size = ${formatInlineNumber(getLongContextMin(model.cost.context_over_200k))} }`);
lines.push(`input = ${model.cost.context_over_200k.input}`);
lines.push(`output = ${model.cost.context_over_200k.output}`);
if (model.cost.context_over_200k.cache_read !== undefined)
lines.push(`cache_read = ${model.cost.context_over_200k.cache_read}`);
if (model.cost.context_over_200k.cache_write !== undefined)
lines.push(`cache_write = ${model.cost.context_over_200k.cache_write}`);
}
}
lines.push("");
lines.push(`[limit]`);
lines.push(`context = ${formatNumber(model.limit.context)}`);
lines.push(`output = ${formatNumber(model.limit.output)}`);
lines.push("");
lines.push(`[modalities]`);
lines.push(`input = [${model.modalities.input.map((m) => `"${m}"`).join(", ")}]`);
lines.push(`output = [${model.modalities.output.map((m) => `"${m}"`).join(", ")}]`);
return lines.join("\n") + "\n";
}
// ---------------------------------------------------------------------------
// Change detection
// ---------------------------------------------------------------------------
interface Change {
field: string;
oldValue: string;
newValue: string;
}
function formatValue(val: unknown): string {
if (val === undefined) return "(none)";
if (Array.isArray(val)) return `[${val.join(", ")}]`;
if (typeof val === "number") return formatNumber(val);
return String(val);
}
function detectChanges(existing: ExistingModel | null, merged: MergedModel): Change[] {
if (!existing) return [];
const changes: Change[] = [];
const EPSILON = 0.001;
const compare = (field: string, oldVal: unknown, newVal: unknown) => {
if (oldVal === undefined && newVal === undefined) return;
const isDiff = field.startsWith("cost.")
? Math.abs((oldVal as number ?? 0) - (newVal as number ?? 0)) > EPSILON
: JSON.stringify(oldVal) !== JSON.stringify(newVal);
if (isDiff) changes.push({ field, oldValue: formatValue(oldVal), newValue: formatValue(newVal) });
};
compare("name", existing.name, merged.name);
compare("reasoning", existing.reasoning, merged.reasoning);
compare("tool_call", existing.tool_call, merged.tool_call);
compare("attachment", existing.attachment, merged.attachment);
compare("status", existing.status, merged.status);
compare("cost.input", existing.cost?.input, merged.cost?.input);
compare("cost.output", existing.cost?.output, merged.cost?.output);
const existingLongContextCost = getExistingLongContextCost(existing);
compare("cost.context_over_200k.input", existingLongContextCost?.input, merged.cost?.context_over_200k?.input);
compare("cost.context_over_200k.output", existingLongContextCost?.output, merged.cost?.context_over_200k?.output);
compare("limit.context", existing.limit?.context, merged.limit.context);
compare("limit.output", existing.limit?.output, merged.limit.output);
compare("modalities.input", existing.modalities?.input, merged.modalities.input);
compare("modalities.output", existing.modalities?.output, merged.modalities.output);
return changes;
}
// ---------------------------------------------------------------------------
// Main
// ---------------------------------------------------------------------------
async function main() {
const args = process.argv.slice(2);
const dryRun = args.includes("--dry-run");
const newOnly = args.includes("--new-only");
// Resolve API key
const apiKeyArg = args.find((a) => a.startsWith("--api-key"));
const apiKey =
(apiKeyArg?.includes("=") ? apiKeyArg.split("=")[1] : args[args.indexOf(apiKeyArg!) + 1]) ??
process.env.DIGITALOCEAN_API_TOKEN;
if (!apiKey) {
console.error("Error: DIGITALOCEAN_API_TOKEN is required (or pass --api-key=<key>)");
console.error("Get one from: https://cloud.digitalocean.com/account/api/tokens");
process.exit(1);
}
const modelsDir = path.join(import.meta.dirname, "..", "..", "..", "providers", "digitalocean", "models");
const prefix = dryRun ? "[DRY RUN] " : "";
console.log(`${prefix}Fetching DigitalOcean models from API...`);
// Fetch both APIs in parallel
const [modelsRes, pricingRes] = await Promise.all([
fetch(MODELS_API, { headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" } }),
fetch(PRICING_API, { headers: { "User-Agent": "models.dev/digitalocean-sync" } }),
]);
if (!modelsRes.ok) {
console.error(`Failed to fetch models API: ${modelsRes.status} ${modelsRes.statusText}`);
if (modelsRes.status === 401 || modelsRes.status === 403)
console.error("Check your DIGITALOCEAN_API_TOKEN has read access.");
process.exit(1);
}
if (!pricingRes.ok) {
console.error(`Failed to fetch pricing API: ${pricingRes.status} ${pricingRes.statusText}`);
process.exit(1);
}
const modelsParsed = DoModelsResponse.safeParse(await modelsRes.json());
if (!modelsParsed.success) {
console.error("Unexpected models API response:", modelsParsed.error.errors);
process.exit(1);
}
const pricingParsed = StaticContentResponse.safeParse(await pricingRes.json());
if (!pricingParsed.success) {
console.error("Unexpected pricing API response:", pricingParsed.error.errors);
process.exit(1);
}
const apiModels = modelsParsed.data.models;
const pricingMap = buildPricingMap(pricingParsed.data.gradient.models);
// Collect existing TOML filenames for orphan detection
const existingFiles = new Set<string>();
for await (const file of new Bun.Glob("**/*.toml").scan({ cwd: modelsDir, absolute: false })) {
existingFiles.add(file);
}
console.log(`Found ${apiModels.length} models in API, ${existingFiles.size} existing TOML files\n`);
const apiModelFiles = new Set<string>();
let created = 0;
let updated = 0;
let unchanged = 0;
for (const apiModel of apiModels) {
// Skip non-text models that opencode can't use: image, video, audio, embedding, reranking
const outputMods = filterOutputModalities(apiModel.modalities?.output ?? []);
const isTextModel = outputMods.includes("text");
const isEmbedding = apiModel.type === "embedding";
const isReranking = apiModel.type === "reranking";
if (!isTextModel || isEmbedding || isReranking) continue;
// Model IDs may contain slashes (e.g. fal-ai/flux/schnell) — use as subpath
const relativePath = `${apiModel.id}.toml`;
const filePath = path.join(modelsDir, relativePath);
const dirPath = path.dirname(filePath);
apiModelFiles.add(relativePath);
const existing = await loadExisting(filePath);
const pricing = pricingMap.get(apiModel.id);
const merged = mergeModel(apiModel, pricing, existing);
const toml = formatToml(merged);
if (existing === null) {
created++;
if (dryRun) {
console.log(`[DRY RUN] Would create: ${relativePath}`);
console.log(` name = "${merged.name}"`);
if (pricing) console.log(` pricing: $${merged.cost?.input}/$${merged.cost?.output} per M tokens`);
if (merged.family) console.log(` family = "${merged.family}" (inferred)`);
console.log("");
} else {
await mkdir(dirPath, { recursive: true });
await Bun.write(filePath, toml);
console.log(`Created: ${relativePath}`);
}
continue;
}
if (newOnly) {
unchanged++;
continue;
}
const changes = detectChanges(existing, merged);
if (changes.length > 0) {
updated++;
if (dryRun) {
console.log(`[DRY RUN] Would update: ${relativePath}`);
} else {
await mkdir(dirPath, { recursive: true });
await Bun.write(filePath, toml);
console.log(`Updated: ${relativePath}`);
}
for (const c of changes) console.log(` ${c.field}: ${c.oldValue}${c.newValue}`);
console.log("");
} else {
unchanged++;
}
}
// Orphan detection: files in the TOML directory but not in the API
const orphaned: string[] = [];
for (const file of existingFiles) {
if (!apiModelFiles.has(file)) {
orphaned.push(file);
console.log(`Warning: orphaned file (not in API): ${file}`);
}
}
console.log("");
if (dryRun) {
console.log(
`Summary: ${created} would be created, ${updated} would be updated, ${unchanged} unchanged, ${orphaned.length} orphaned`,
);
} else {
console.log(`Summary: ${created} created, ${updated} updated, ${unchanged} unchanged, ${orphaned.length} orphaned`);
}
}
await main();
+44 -5
View File
@@ -162,7 +162,18 @@ interface ExistingModel {
output?: number;
cache_read?: number;
cache_write?: number;
context_min?: number;
};
tiers?: Array<{
tier: {
type?: "context";
size: number;
};
input?: number;
output?: number;
cache_read?: number;
cache_write?: number;
}>;
};
limit?: {
context?: number;
@@ -195,6 +206,30 @@ async function loadExistingModel(filePath: string): Promise<ExistingModel | null
}
}
function getExistingLongContextMin(existing: ExistingModel | null) {
return (
existing?.cost?.tiers?.find(
(tier) =>
(tier.tier.type === undefined || tier.tier.type === "context") &&
tier.tier.size >= 200_000,
)?.tier.size ?? 200_000
);
}
function getExistingLongContextCost(existing: ExistingModel | null) {
return (
existing?.cost?.tiers?.find(
(tier) =>
(tier.tier.type === undefined || tier.tier.type === "context") &&
tier.tier.size >= 200_000,
) ?? existing?.cost?.context_over_200k
);
}
function getLongContextMin(cost: { context_min?: number }) {
return cost.context_min ?? 200_000;
}
interface MergedModel {
name: string;
family?: string;
@@ -219,6 +254,7 @@ interface MergedModel {
output: number;
cache_read?: number;
cache_write?: number;
context_min?: number;
};
};
limit: {
@@ -292,6 +328,7 @@ function mergeModel(
merged.cost.context_over_200k = {
input: spec.pricing.extended.input.usd,
output: spec.pricing.extended.output.usd,
context_min: spec.pricing.extended.context_token_threshold,
...(spec.pricing.extended.cache_input && { cache_read: spec.pricing.extended.cache_input.usd }),
...(spec.pricing.extended.cache_write && { cache_write: spec.pricing.extended.cache_write.usd }),
};
@@ -366,7 +403,8 @@ function formatToml(model: MergedModel): string {
if (model.cost.context_over_200k) {
lines.push("");
lines.push(`[cost.context_over_200k]`);
lines.push(`[[cost.tiers]]`);
lines.push(`tier = { size = ${formatNumber(getLongContextMin(model.cost.context_over_200k))} }`);
lines.push(`input = ${model.cost.context_over_200k.input}`);
lines.push(`output = ${model.cost.context_over_200k.output}`);
if (model.cost.context_over_200k.cache_read !== undefined) {
@@ -438,10 +476,11 @@ function detectChanges(
compare("cost.output", existing.cost?.output, merged.cost?.output);
compare("cost.cache_read", existing.cost?.cache_read, merged.cost?.cache_read);
compare("cost.cache_write", existing.cost?.cache_write, merged.cost?.cache_write);
compare("cost.context_over_200k.input", existing.cost?.context_over_200k?.input, merged.cost?.context_over_200k?.input);
compare("cost.context_over_200k.output", existing.cost?.context_over_200k?.output, merged.cost?.context_over_200k?.output);
compare("cost.context_over_200k.cache_read", existing.cost?.context_over_200k?.cache_read, merged.cost?.context_over_200k?.cache_read);
compare("cost.context_over_200k.cache_write", existing.cost?.context_over_200k?.cache_write, merged.cost?.context_over_200k?.cache_write);
const existingLongContextCost = getExistingLongContextCost(existing);
compare("cost.context_over_200k.input", existingLongContextCost?.input, merged.cost?.context_over_200k?.input);
compare("cost.context_over_200k.output", existingLongContextCost?.output, merged.cost?.context_over_200k?.output);
compare("cost.context_over_200k.cache_read", existingLongContextCost?.cache_read, merged.cost?.context_over_200k?.cache_read);
compare("cost.context_over_200k.cache_write", existingLongContextCost?.cache_write, merged.cost?.context_over_200k?.cache_write);
compare("limit.context", existing.limit?.context, merged.limit.context);
compare("limit.output", existing.limit?.output, merged.limit.output);
compare("modalities.input", existing.modalities?.input, merged.modalities.input);
+17 -2
View File
@@ -54,12 +54,17 @@ export const ModelFamilyValues = [
// DeepSeek
"deepseek",
"deepseek-thinking",
"deepseek-flash",
"deepseek-flash-free",
"deepseek-flash-think",
// Microsoft Phi
"phi",
// Moonshot Kimi
"kimi",
"kimi-k2.5",
"kimi-k2.6",
"kimi-free",
"kimi-thinking",
@@ -115,8 +120,8 @@ export const ModelFamilyValues = [
// Hunyuan
"hunyuan",
// HY
"HY",
// Hy
"Hy",
// Yi
"yi",
@@ -205,6 +210,10 @@ export const ModelFamilyValues = [
"mimo",
"mimo-pro",
"mimo-omni",
"mimo-v2-pro",
"mimo-v2-omni",
"mimo-v2.5-pro",
"mimo-v2.5",
"mimo-pro-free",
"mimo-omni-free",
"mimo-flash-free",
@@ -280,9 +289,15 @@ export const ModelFamilyValues = [
// RNJ
"rnj",
// Tecent Hy
"hy3",
"hy3-free",
// Ling & Ring (InclusionAI)
"ling",
"ling-flash-free",
"ring",
"ring-1t-free",
// Kat Coder
"kat-coder",
+53 -5
View File
@@ -2,9 +2,9 @@ import path from "path";
import { mergeDeep } from "remeda";
import { z } from "zod";
import { Provider, Model } from "./schema.js";
import { Provider, Model, AuthoredModel, AuthoredModelShape } from "./schema.js";
const ExtendsModel = Model.sourceType()
const ExtendsModel = AuthoredModelShape
.partial()
.extend({
extends: z
@@ -71,12 +71,12 @@ export async function generate(directory: string) {
});
continue;
}
const model = Model.safeParse(toml);
const model = AuthoredModel.safeParse(toml);
if (!model.success) {
model.error.cause = { modelPath, toml };
throw model.error;
}
provider.data.models[modelID] = model.data;
provider.data.models[modelID] = normalizeModelCost(model.data);
}
result[providerID] = provider.data;
}
@@ -144,7 +144,7 @@ export async function generate(directory: string) {
}
}
const model = Model.safeParse(merged);
const model = Model.safeParse(normalizeCost(merged));
if (!model.success) {
model.error.cause = { modelPath: pendingModel.modelPath, toml: merged };
throw model.error;
@@ -155,3 +155,51 @@ export async function generate(directory: string) {
return result;
}
function normalizeModelCost(model: z.infer<typeof AuthoredModel>): Model {
return normalizeCost(model) as Model;
}
function normalizeCost(model: Record<string, unknown>) {
const cost = model.cost;
if (cost === undefined || cost === null || typeof cost !== "object" || Array.isArray(cost)) {
return model;
}
const tiers = (cost as { tiers?: unknown }).tiers;
if (!Array.isArray(tiers)) {
return model;
}
if (tiers.length !== 1) {
return model;
}
const contextOver200k = tiers.find((tier) => {
if (tier === null || typeof tier !== "object" || Array.isArray(tier)) return false;
const tierConfig = (tier as { tier?: unknown }).tier;
if (tierConfig === null || typeof tierConfig !== "object" || Array.isArray(tierConfig)) return false;
const type = (tierConfig as { type?: unknown }).type;
const size = (tierConfig as { size?: unknown }).size;
// context_over_200k is a legacy compatibility field. It intentionally
// includes higher thresholds; cost.tiers carries the exact threshold.
return (
(type === undefined || type === "context") &&
typeof size === "number" &&
size >= 200_000
);
});
if (contextOver200k === undefined) {
return model;
}
const { tier: _tier, ...legacyCost } = contextOver200k as Record<string, unknown>;
return {
...model,
cost: {
...(cost as Record<string, unknown>),
context_over_200k: legacyCost,
},
};
}
+156 -98
View File
@@ -21,110 +21,164 @@ const JsonValue: z.ZodType<JsonValue> = z.lazy(() =>
]),
);
const Cost = z.object({
input: z.number().min(0, "Input price cannot be negative"),
output: z.number().min(0, "Output price cannot be negative"),
reasoning: z.number().min(0, "Input price cannot be negative").optional(),
cache_read: z
.number()
.min(0, "Cache read price cannot be negative")
const Cost = z
.object({
input: z.number().min(0, "Input price cannot be negative"),
output: z.number().min(0, "Output price cannot be negative"),
reasoning: z
.number()
.min(0, "Reasoning price cannot be negative")
.optional(),
cache_read: z
.number()
.min(0, "Cache read price cannot be negative")
.optional(),
cache_write: z
.number()
.min(0, "Cache write price cannot be negative")
.optional(),
input_audio: z
.number()
.min(0, "Audio input price cannot be negative")
.optional(),
output_audio: z
.number()
.min(0, "Audio output price cannot be negative")
.optional(),
});
const CostTier = Cost.extend({
tier: z
.object({
type: z.literal("context").default("context"),
size: z.number().int().min(0, "Context tier size cannot be negative"),
})
.strict(),
}).strict();
const AuthoredCost = Cost.extend({
context_over_200k: z.never().optional(),
tiers: z.array(CostTier).optional(),
});
const OutputCost = Cost.extend({
context_over_200k: Cost.optional(),
tiers: z.array(CostTier).optional(),
});
const ModelBase = z.object({
id: z.string(),
name: z.string().min(1, "Model name cannot be empty"),
family: ModelFamily.optional(),
attachment: z.boolean(),
reasoning: z.boolean(),
tool_call: z.boolean(),
interleaved: z
.union([
z.literal(true),
z
.object({
field: z.enum(["reasoning_content", "reasoning_details"]),
})
.strict(),
])
.optional(),
cache_write: z
.number()
.min(0, "Cache write price cannot be negative")
structured_output: z.boolean().optional(),
temperature: z.boolean().optional(),
knowledge: z
.string()
.regex(/^\d{4}-\d{2}(-\d{2})?$/, {
message: "Must be in YYYY-MM or YYYY-MM-DD format",
})
.optional(),
input_audio: z
.number()
.min(0, "Audio input price cannot be negative")
release_date: z.string().regex(/^\d{4}-\d{2}(-\d{2})?$/, {
message: "Must be in YYYY-MM or YYYY-MM-DD format",
}),
last_updated: z.string().regex(/^\d{4}-\d{2}(-\d{2})?$/, {
message: "Must be in YYYY-MM or YYYY-MM-DD format",
}),
modalities: z.object({
input: z.array(z.enum(["text", "audio", "image", "video", "pdf"])),
output: z.array(z.enum(["text", "audio", "image", "video", "pdf"])),
}),
open_weights: z.boolean(),
limit: z.object({
context: z.number().min(0, "Context window must be positive"),
input: z.number().min(0, "Input tokens must be positive").optional(),
output: z.number().min(0, "Output tokens must be positive"),
}),
status: z.enum(["alpha", "beta", "deprecated"]).optional(),
experimental: z
.object({
modes: z
.record(
z.object({
cost: Cost.optional(),
provider: z
.object({
body: z.record(JsonValue).optional(),
headers: z.record(z.string()).optional(),
})
.optional(),
}),
)
.optional(),
})
.optional(),
output_audio: z
.number()
.min(0, "Audio output price cannot be negative")
provider: z
.object({
npm: z.string().optional(),
api: z.string().optional(),
shape: z.enum(["responses", "completions"]).optional(),
body: z.record(JsonValue).optional(),
headers: z.record(z.string()).optional(),
})
.optional(),
});
export const Model = z
function refineModel<T extends z.ZodTypeAny>(schema: T) {
return schema
.refine(
(data) => {
return !(data.reasoning === false && data.cost?.reasoning !== undefined);
},
{
message: "Cannot set cost.reasoning when reasoning is false",
path: ["cost", "reasoning"],
},
)
.refine(
(data) => {
const tiers = data.cost?.tiers;
if (tiers === undefined) return true;
const sizes = tiers.map((tier: { tier: { size: number } }) => tier.tier.size);
return new Set(sizes).size === sizes.length;
},
{
message: "Cost context tiers must not have duplicate sizes",
path: ["cost", "tiers"],
},
);
}
export const ModelShape = z
.object({
id: z.string(),
name: z.string().min(1, "Model name cannot be empty"),
family: ModelFamily.optional(),
attachment: z.boolean(),
reasoning: z.boolean(),
tool_call: z.boolean(),
interleaved: z
.union([
z.literal(true),
z
.object({
field: z.enum(["reasoning_content", "reasoning_details"]),
})
.strict(),
])
.optional(),
structured_output: z.boolean().optional(),
temperature: z.boolean().optional(),
knowledge: z
.string()
.regex(/^\d{4}-\d{2}(-\d{2})?$/, {
message: "Must be in YYYY-MM or YYYY-MM-DD format",
})
.optional(),
release_date: z.string().regex(/^\d{4}-\d{2}(-\d{2})?$/, {
message: "Must be in YYYY-MM or YYYY-MM-DD format",
}),
last_updated: z.string().regex(/^\d{4}-\d{2}(-\d{2})?$/, {
message: "Must be in YYYY-MM or YYYY-MM-DD format",
}),
modalities: z.object({
input: z.array(z.enum(["text", "audio", "image", "video", "pdf"])),
output: z.array(z.enum(["text", "audio", "image", "video", "pdf"])),
}),
open_weights: z.boolean(),
cost: Cost.extend({
context_over_200k: Cost.optional(),
}).optional(),
limit: z.object({
context: z.number().min(0, "Context window must be positive"),
input: z.number().min(0, "Input tokens must be positive").optional(),
output: z.number().min(0, "Output tokens must be positive"),
}),
status: z.enum(["alpha", "beta", "deprecated"]).optional(),
experimental: z
.object({
modes: z
.record(
z.object({
cost: Cost.optional(),
provider: z
.object({
body: z.record(JsonValue).optional(),
headers: z.record(z.string()).optional(),
})
.optional(),
}),
)
.optional(),
})
.optional(),
provider: z
.object({
npm: z.string().optional(),
api: z.string().optional(),
shape: z.enum(["responses", "completions"]).optional(),
body: z.record(JsonValue).optional(),
headers: z.record(z.string()).optional(),
})
.optional(),
...ModelBase.shape,
cost: OutputCost.optional(),
})
.strict()
.refine(
(data) => {
return !(data.reasoning === false && data.cost?.reasoning !== undefined);
},
{
message: "Cannot set cost.reasoning when reasoning is false",
path: ["cost", "reasoning"],
},
);
.strict();
export const AuthoredModelShape = z
.object({
...ModelBase.shape,
cost: AuthoredCost.optional(),
})
.strict();
export const Model = refineModel(ModelShape);
export const AuthoredModel = refineModel(AuthoredModelShape);
export type Model = z.infer<typeof Model>;
@@ -150,6 +204,7 @@ export const Provider = z
const isOpenAIcompatible = data.npm === "@ai-sdk/openai-compatible";
const isOpenrouter = data.npm === "@openrouter/ai-sdk-provider";
const isAnthropic = data.npm === "@ai-sdk/anthropic";
const isKiro = data.npm === "kiro-acp-ai-provider";
const hasApi = data.api !== undefined;
return (
@@ -161,17 +216,20 @@ export const Provider = z
isAnthropic ||
// openai: api optional (always allowed)
isOpenAI ||
// kiro: api optional (always allowed)
isKiro ||
// all others: must NOT have api
(!isOpenAI &&
!isOpenAIcompatible &&
!isOpenrouter &&
!isAnthropic &&
!isKiro &&
!hasApi)
);
},
{
message:
"'api' is required for openai-compatible and openrouter, optional for anthropic and openai, forbidden otherwise",
"'api' is required for openai-compatible and openrouter, optional for anthropic, openai, and kiro, forbidden otherwise",
path: ["api"],
},
);
+2 -9
View File
@@ -1,7 +1,6 @@
#!/usr/bin/env bun
import { Rendered, Providers } from "../src/render";
import { normalizeLogoSvg } from "../src/logo.js";
import fs from "fs/promises";
import path from "path";
import { $ } from "bun";
@@ -24,10 +23,7 @@ await fs.mkdir("./dist/logos", { recursive: true });
const defaultLogoPath = "../../providers/logo.svg";
const defaultLogo = Bun.file(defaultLogoPath);
if (await defaultLogo.exists()) {
await Bun.write(
"./dist/logos/default.svg",
normalizeLogoSvg(await defaultLogo.text())
);
await Bun.write("./dist/logos/default.svg", defaultLogo);
}
// Then copy provider-specific logos
@@ -40,10 +36,7 @@ for (const entry of entries) {
const logoFile = Bun.file(logoPath);
if (await logoFile.exists()) {
await Bun.write(
`./dist/logos/${provider}.svg`,
normalizeLogoSvg(await logoFile.text())
);
await Bun.write(`./dist/logos/${provider}.svg`, logoFile);
}
}
}
+6 -14
View File
@@ -319,12 +319,15 @@ tbody {
gap: 0.375rem;
}
.provider-logo {
.provider-cell span:first-child {
flex: 0 0 auto;
}
.provider-cell svg {
display: block;
width: 1rem;
height: 1rem;
object-fit: contain;
color: var(--color-text-secondary);
}
.model-id-cell {
@@ -413,17 +416,6 @@ tbody {
.modality-icon:hover::after {
opacity: 1;
}
tr.loading-row td,
tr.error-row td {
padding: 1rem 0.75rem;
text-align: center;
font-family: inherit;
font-size: 0.875rem;
font-weight: 400;
text-transform: none;
color: var(--color-text-secondary);
}
}
dialog::backdrop {
@@ -554,4 +546,4 @@ dialog {
}
}
}
}
+65 -367
View File
@@ -1,248 +1,7 @@
interface ApiCost {
input?: number;
output?: number;
reasoning?: number;
cache_read?: number;
cache_write?: number;
input_audio?: number;
output_audio?: number;
}
interface ApiLimit {
context: number;
input?: number;
output: number;
}
interface ApiModel {
name: string;
family?: string;
status?: string;
tool_call: boolean;
reasoning: boolean;
modalities: {
input: string[];
output: string[];
};
cost?: ApiCost;
limit: ApiLimit;
structured_output?: boolean;
temperature: boolean;
open_weights: boolean;
knowledge?: string;
release_date: string;
last_updated: string;
}
interface ApiProvider {
name: string;
models: Record<string, ApiModel>;
}
type ApiResponse = Record<string, ApiProvider>;
const COLUMN_COUNT = 25;
const modal = document.getElementById("modal") as HTMLDialogElement;
const modalClose = document.getElementById("close")!;
const help = document.getElementById("help")!;
const search = document.getElementById("search")! as HTMLInputElement;
const tableBody = document.getElementById("table-body")! as HTMLTableSectionElement;
const copyIcon = `
<svg
class="copy-icon"
xmlns="http://www.w3.org/2000/svg"
width="14"
height="14"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<rect width="14" height="14" x="8" y="8" rx="2" ry="2"></rect>
<path d="m4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"></path>
</svg>
`;
const checkIcon = `
<svg
class="check-icon"
xmlns="http://www.w3.org/2000/svg"
width="14"
height="14"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
style="display: none;"
>
<polyline points="20,6 9,17 4,12"></polyline>
</svg>
`;
const modalityIcons: Record<string, { label: string; svg: string }> = {
text: {
label: "Text",
svg: `
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polyline points="4,7 4,4 20,4 20,7"></polyline>
<line x1="9" y1="20" x2="15" y2="20"></line>
<line x1="12" y1="4" x2="12" y2="20"></line>
</svg>
`,
},
image: {
label: "Image",
svg: `
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<rect width="18" height="18" x="3" y="3" rx="2" ry="2"></rect>
<circle cx="9" cy="9" r="2"></circle>
<path d="m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21"></path>
</svg>
`,
},
audio: {
label: "Audio",
svg: `
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polygon points="11 5 6 9 2 9 2 15 6 15 11 19 11 5"></polygon>
<path d="m19.07 4.93a10 10 0 0 1 0 14.14M15.54 8.46a5 5 0 0 1 0 7.07"></path>
</svg>
`,
},
video: {
label: "Video",
svg: `
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="m22 8-6 4 6 4V8Z"></path>
<rect width="14" height="12" x="2" y="6" rx="2" ry="2"></rect>
</svg>
`,
},
pdf: {
label: "PDF",
svg: `
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path>
<polyline points="14,2 14,8 20,8"></polyline>
<line x1="16" y1="13" x2="8" y2="13"></line>
<line x1="16" y1="17" x2="8" y2="17"></line>
<polyline points="10,9 9,9 8,9"></polyline>
</svg>
`,
},
};
function escapeHtml(value: string) {
return value
.replaceAll("&", "&amp;")
.replaceAll("<", "&lt;")
.replaceAll(">", "&gt;")
.replaceAll('"', "&quot;")
.replaceAll("'", "&#39;");
}
function renderCost(cost?: number) {
return cost === undefined ? "-" : `$${cost.toFixed(2)}`;
}
function renderModalityIcon(modality: string) {
const icon = modalityIcons[modality];
if (!icon) return "";
return `<span class="modality-icon" data-tooltip="${icon.label}">${icon.svg}</span>`;
}
function renderModalities(modalities: string[]) {
return `<div class="modalities">${modalities.map(renderModalityIcon).join("")}</div>`;
}
function renderProviderLogo(providerId: string) {
return `<img class="provider-logo" src="/logos/${encodeURIComponent(providerId)}.svg" alt="" width="16" height="16" loading="lazy" decoding="async" />`;
}
function renderRow(
providerId: string,
providerName: string,
modelId: string,
model: ApiModel
) {
const safeProviderId = escapeHtml(providerId);
const safeProviderName = escapeHtml(providerName);
const safeModelId = escapeHtml(modelId);
const safeModelName = escapeHtml(model.name);
const safeFamily = escapeHtml(model.family ?? "-");
const safeKnowledge = escapeHtml(model.knowledge?.substring(0, 7) ?? "-");
const safeReleaseDate = escapeHtml(model.release_date);
const safeLastUpdated = escapeHtml(model.last_updated);
return `
<tr data-model-row="true">
<td>
<div class="provider-cell">
${renderProviderLogo(providerId)}
<span>${safeProviderName}</span>
</div>
</td>
<td>${safeModelName}</td>
<td>${safeFamily}</td>
<td>${safeProviderId}</td>
<td>
<div class="model-id-cell">
<span class="model-id-text">${safeModelId}</span>
<button class="copy-button" type="button" data-model-id="${safeModelId}" aria-label="Copy model ID">
${copyIcon}
${checkIcon}
</button>
</div>
</td>
<td>${model.tool_call ? "Yes" : "No"}</td>
<td>${model.reasoning ? "Yes" : "No"}</td>
<td>${renderModalities(model.modalities.input)}</td>
<td>${renderModalities(model.modalities.output)}</td>
<td>${renderCost(model.cost?.input)}</td>
<td>${renderCost(model.cost?.output)}</td>
<td>${renderCost(model.cost?.reasoning)}</td>
<td>${renderCost(model.cost?.cache_read)}</td>
<td>${renderCost(model.cost?.cache_write)}</td>
<td>${renderCost(model.cost?.input_audio)}</td>
<td>${renderCost(model.cost?.output_audio)}</td>
<td>${model.limit.context.toLocaleString()}</td>
<td>${model.limit.input?.toLocaleString() ?? "-"}</td>
<td>${model.limit.output.toLocaleString()}</td>
<td>${model.structured_output === undefined ? "-" : model.structured_output ? "Yes" : "No"}</td>
<td>${model.temperature ? "Yes" : "No"}</td>
<td>${model.open_weights ? "Open" : "Closed"}</td>
<td>${safeKnowledge}</td>
<td>${safeReleaseDate}</td>
<td>${safeLastUpdated}</td>
</tr>
`;
}
function renderTableRows(providers: ApiResponse) {
return Object.entries(providers)
.sort(([, providerA], [, providerB]) =>
providerA.name.localeCompare(providerB.name)
)
.flatMap(([providerId, provider]) =>
Object.entries(provider.models)
.filter(([, model]) => model.status !== "alpha")
.sort(([, modelA], [, modelB]) => modelA.name.localeCompare(modelB.name))
.map(([modelId, model]) =>
renderRow(providerId, provider.name, modelId, model)
)
)
.join("");
}
function setStatusRow(message: string, className = "loading-row") {
tableBody.innerHTML = `<tr class="${className}"><td colspan="${COLUMN_COUNT}">${escapeHtml(message)}</td></tr>`;
}
/////////////////////////
// URL State Management
@@ -251,10 +10,7 @@ function getQueryParams() {
return new URLSearchParams(window.location.search);
}
function updateQueryParams(
updates: Record<string, string | null>,
historyMode: "push" | "replace" = "push"
) {
function updateQueryParams(updates: Record<string, string | null>) {
const params = getQueryParams();
for (const [key, value] of Object.entries(updates)) {
if (value) {
@@ -263,18 +19,9 @@ function updateQueryParams(
params.delete(key);
}
}
const newPath = params.toString()
? `${window.location.pathname}?${params.toString()}`
: window.location.pathname;
if (newPath === `${window.location.pathname}${window.location.search}`) return;
if (historyMode === "replace") {
window.history.replaceState({}, "", newPath);
return;
}
window.history.pushState({}, "", newPath);
}
@@ -318,71 +65,66 @@ modal.addEventListener("click", (e) => {
////////////////////
// Handle Sorting
////////////////////
let currentSort = { column: -1, direction: "asc" as "asc" | "desc" };
let currentSort = { column: -1, direction: "asc" };
function updateSortIndicators(column: number, direction: "asc" | "desc") {
const headers = document.querySelectorAll("th.sortable");
headers.forEach((header, i) => {
const indicator = header.querySelector(".sort-indicator")!;
indicator.textContent = i === column ? (direction === "asc" ? "↑" : "↓") : "";
});
}
function clearSortIndicators() {
updateSortIndicators(-1, "asc");
}
function sortTable(
column: number,
direction: "asc" | "desc",
syncUrl = true
) {
function sortTable(column: number, direction: "asc" | "desc") {
const header = document.querySelectorAll("th.sortable")[column];
const columnType = header?.getAttribute("data-type");
const columnType = header.getAttribute("data-type");
if (!columnType) return;
// update state
currentSort = { column, direction };
if (syncUrl) {
updateQueryParams(
{
sort: getColumnNameForURL(header),
order: direction,
},
"push"
);
}
updateQueryParams({
sort: getColumnNameForURL(header),
order: direction,
});
// sort rows
const tbody = document.querySelector("table tbody")!;
const rows = Array.from(
tableBody.querySelectorAll('tr[data-model-row="true"]')
tbody.querySelectorAll("tr")
) as HTMLTableRowElement[];
rows.sort((a, b) => {
const aValue = getCellValue(a.cells[column], columnType);
const bValue = getCellValue(b.cells[column], columnType);
// Handle undefined values - always sort to bottom
if (aValue === undefined && bValue === undefined) return 0;
if (aValue === undefined) return 1;
if (bValue === undefined) return -1;
const comparison =
columnType === "number" || columnType === "modalities"
? (aValue as number) - (bValue as number)
: (aValue as string).localeCompare(bValue as string);
let comparison = 0;
if (columnType === "number" || columnType === "modalities") {
comparison = (aValue as number) - (bValue as number);
} else if (columnType === "boolean") {
comparison = (aValue as string).localeCompare(bValue as string);
} else {
comparison = (aValue as string).localeCompare(bValue as string);
}
return direction === "asc" ? comparison : -comparison;
});
rows.forEach((row) => tbody.appendChild(row));
rows.forEach((row) => tableBody.appendChild(row));
updateSortIndicators(column, direction);
// update sort indicators
const headers = document.querySelectorAll("th.sortable");
headers.forEach((header, i) => {
const indicator = header.querySelector(".sort-indicator")!;
if (i === column) {
indicator.textContent = direction === "asc" ? "↑" : "↓";
} else {
indicator.textContent = "";
}
});
}
function getCellValue(
cell: HTMLTableCellElement,
type: string
): string | number | undefined {
if (type === "modalities") {
if (type === "modalities")
return cell.querySelectorAll(".modality-icon").length;
}
const text = cell.textContent?.trim() || "";
if (text === "-") return;
@@ -404,31 +146,22 @@ document.querySelectorAll("th.sortable").forEach((header) => {
///////////////////
// Handle Search
///////////////////
function filterTable(value: string, syncUrl = true) {
const lowerCaseValues = value
.toLowerCase()
.split(",")
.map((part) => part.trim())
.filter(Boolean);
const rows = tableBody.querySelectorAll(
'tr[data-model-row="true"]'
function filterTable(value: string) {
const lowerCaseValues = value.toLowerCase().split(",").filter(str => str.trim() !== "");
const rows = document.querySelectorAll(
"table tbody tr"
) as NodeListOf<HTMLTableRowElement>;
rows.forEach((row) => {
const cellTexts = Array.from(row.cells).map((cell) =>
cell.textContent!.toLowerCase()
);
const isVisible =
lowerCaseValues.length === 0 ||
lowerCaseValues.some((lowerCaseValue) =>
cellTexts.some((text) => text.includes(lowerCaseValue))
);
const isVisible = lowerCaseValues.length === 0 ||
lowerCaseValues.some((lowerCaseValue) => cellTexts.some((text) => text.includes(lowerCaseValue)));
row.style.display = isVisible ? "" : "none";
});
if (syncUrl) {
updateQueryParams({ search: value || null }, "replace");
}
updateQueryParams({ search: value || null });
}
search.addEventListener("input", () => {
@@ -452,22 +185,22 @@ search.addEventListener("keydown", (e) => {
///////////////////////////////////
// Handle Copy model ID function
///////////////////////////////////
tableBody.addEventListener("click", async (event) => {
const target = event.target as HTMLElement;
const button = target.closest(".copy-button") as HTMLButtonElement | null;
const modelId = button?.dataset.modelId;
if (!button || !modelId) return;
(window as any).copyModelId = async (
button: HTMLButtonElement,
modelId: string
) => {
try {
if (navigator.clipboard) {
await navigator.clipboard.writeText(modelId);
// Switch to check icon
const copyIcon = button.querySelector(".copy-icon") as HTMLElement;
const checkIcon = button.querySelector(".check-icon") as HTMLElement;
copyIcon.style.display = "none";
checkIcon.style.display = "block";
// Switch back after 1 second
setTimeout(() => {
copyIcon.style.display = "block";
checkIcon.style.display = "none";
@@ -476,67 +209,32 @@ tableBody.addEventListener("click", async (event) => {
} catch (err) {
console.error("Failed to copy text: ", err);
}
});
};
///////////////////////////////////
// Initialize State from URL
///////////////////////////////////
let tableLoaded = false;
function initializeFromURL() {
if (!tableLoaded) return;
const params = getQueryParams();
const searchQuery = params.get("search") ?? "";
search.value = searchQuery;
filterTable(searchQuery, false);
const columnName = params.get("sort");
if (!columnName) {
currentSort = { column: -1, direction: "asc" };
clearSortIndicators();
return;
}
(() => {
const searchQuery = params.get("search");
if (!searchQuery) return;
search.value = searchQuery;
filterTable(searchQuery);
})();
const columnIndex = getColumnIndexByUrlName(columnName);
if (columnIndex === -1) return;
(() => {
const columnName = params.get("sort");
if (!columnName) return;
const direction = (params.get("order") as "asc" | "desc") || "asc";
sortTable(columnIndex, direction, false);
const columnIndex = getColumnIndexByUrlName(columnName);
if (columnIndex === -1) return;
const direction = (params.get("order") as "asc" | "desc") || "asc";
sortTable(columnIndex, direction);
})();
}
async function loadTable() {
try {
const response = await fetch("/api.json");
if (!response.ok) {
throw new Error(`Failed to fetch models: ${response.status}`);
}
const providers = (await response.json()) as ApiResponse;
const rows = renderTableRows(providers);
tableBody.innerHTML = rows || "";
if (!rows) {
setStatusRow("No models found.");
return;
}
tableLoaded = true;
initializeFromURL();
window.addEventListener("popstate", initializeFromURL);
} catch (error) {
console.error("Failed to load model data:", error);
setStatusRow("Failed to load models.", "loading-row error-row");
}
}
function initializeApp() {
search.value = getQueryParams().get("search") ?? "";
void loadTable();
}
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", initializeApp);
} else {
initializeApp();
}
document.addEventListener("DOMContentLoaded", initializeFromURL);
window.addEventListener("popstate", initializeFromURL);
-16
View File
@@ -1,16 +0,0 @@
const LOGO_THEME_MARKER = "models-dev-logo-theme";
const LOGO_THEME_STYLE = `<style id="${LOGO_THEME_MARKER}">:root{color:#666}@media (prefers-color-scheme: dark){:root{color:#AAA}}</style>`;
export function normalizeLogoSvg(svgText: string) {
if (svgText.includes(LOGO_THEME_MARKER)) {
return svgText;
}
return svgText.replace(/<svg\b[^>]*>/i, (svgTag) => {
const themedTag = svgTag.includes("fill=")
? svgTag
: svgTag.replace("<svg", '<svg fill="currentColor"');
return `${themedTag}${LOGO_THEME_STYLE}`;
});
}
+282 -5
View File
@@ -1,15 +1,184 @@
/** @jsx jsx */
/** @jsxImportSource hono/jsx */
import { generate } from "models.dev";
import { Fragment } from "hono/jsx";
import { renderToString } from "hono/jsx/dom/server";
import { generate } from "models.dev";
import { existsSync } from "fs";
import path from "path";
export const Providers = await generate(
path.join(import.meta.dir, "..", "..", "..", "providers")
);
// Function to load SVG content
const loadProviderSvg = async (providerId: string): Promise<string | null> => {
const providerLogoPath = path.join(
import.meta.dir,
"..",
"..",
"..",
"providers",
providerId,
"logo.svg"
);
const defaultLogoPath = path.join(
import.meta.dir,
"..",
"..",
"..",
"providers",
"logo.svg"
);
try {
// Try provider-specific logo first
if (existsSync(providerLogoPath)) {
const file = Bun.file(providerLogoPath);
return await file.text();
}
//
// Fall back to default logo
if (existsSync(defaultLogoPath)) {
const file = Bun.file(defaultLogoPath);
return await file.text();
}
return null;
} catch (error) {
console.warn(`Failed to load logo for provider ${providerId}:`, error);
return null;
}
};
// Create a cache of loaded SVGs at build time
const providerLogos = new Map<string, string>();
// Pre-load all provider logos
for (const [providerId] of Object.entries(Providers)) {
const svgContent = await loadProviderSvg(providerId);
if (svgContent) {
providerLogos.set(providerId, svgContent);
}
}
function renderProviderLogo(providerId: string) {
const svgContent = providerLogos.get(providerId) || "";
return <span dangerouslySetInnerHTML={{ __html: svgContent }} />;
}
const getModalityIcon = (modality: string) => {
switch (modality) {
case "text":
return (
<span class="modality-icon" data-tooltip="Text">
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<polyline points="4,7 4,4 20,4 20,7"></polyline>
<line x1="9" y1="20" x2="15" y2="20"></line>
<line x1="12" y1="4" x2="12" y2="20"></line>
</svg>
</span>
);
case "image":
return (
<span class="modality-icon" data-tooltip="Image">
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<rect width="18" height="18" x="3" y="3" rx="2" ry="2"></rect>
<circle cx="9" cy="9" r="2"></circle>
<path d="m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21"></path>
</svg>
</span>
);
case "audio":
return (
<span class="modality-icon" data-tooltip="Audio">
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<polygon points="11 5 6 9 2 9 2 15 6 15 11 19 11 5"></polygon>
<path d="m19.07 4.93a10 10 0 0 1 0 14.14M15.54 8.46a5 5 0 0 1 0 7.07"></path>
</svg>
</span>
);
case "video":
return (
<span class="modality-icon" data-tooltip="Video">
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="m22 8-6 4 6 4V8Z"></path>
<rect width="14" height="12" x="2" y="6" rx="2" ry="2"></rect>
</svg>
</span>
);
case "pdf":
return (
<span class="modality-icon" data-tooltip="PDF">
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path>
<polyline points="14,2 14,8 20,8"></polyline>
<line x1="16" y1="13" x2="8" y2="13"></line>
<line x1="16" y1="17" x2="8" y2="17"></line>
<polyline points="10,9 9,9 8,9"></polyline>
</svg>
</span>
);
default:
return null;
}
};
const renderCost = (cost?: number) => {
return cost === undefined ? "-" : `$${cost.toFixed(2)}`;
};
export const Rendered = renderToString(
<Fragment>
<header>
@@ -173,10 +342,118 @@ export const Rendered = renderToString(
</th>
</tr>
</thead>
<tbody id="table-body">
<tr class="loading-row">
<td colspan={25}>Loading models...</td>
</tr>
<tbody>
{Object.entries(Providers)
.sort(([, providerA], [, providerB]) =>
providerA.name.localeCompare(providerB.name)
)
.flatMap(([providerId, provider]) =>
Object.entries(provider.models)
.filter(([, model]) => model.status !== "alpha")
.sort(([, modelA], [, modelB]) =>
modelA.name.localeCompare(modelB.name)
)
.map(([modelId, model]) => (
<tr key={`${providerId}-${modelId}`}>
<td>
<div class="provider-cell">
{renderProviderLogo(providerId)}
<span>{provider.name}</span>
</div>
</td>
<td>{model.name}</td>
<td>{model.family ?? "-"}</td>
<td>{providerId}</td>
<td>
<div class="model-id-cell">
<span class="model-id-text">{modelId}</span>
<button
class="copy-button"
onclick={`copyModelId(this, '${modelId}')`}
>
<svg
class="copy-icon"
xmlns="http://www.w3.org/2000/svg"
width="14"
height="14"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<rect
width="14"
height="14"
x="8"
y="8"
rx="2"
ry="2"
/>
<path d="m4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2" />
</svg>
<svg
class="check-icon"
xmlns="http://www.w3.org/2000/svg"
width="14"
height="14"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
style="display: none;"
>
<polyline points="20,6 9,17 4,12" />
</svg>
</button>
</div>
</td>
<td>{model.tool_call ? "Yes" : "No"}</td>
<td>{model.reasoning ? "Yes" : "No"}</td>
<td>
<div class="modalities">
{model.modalities.input.map((modality) =>
getModalityIcon(modality)
)}
</div>
</td>
<td>
<div class="modalities">
{model.modalities.output.map((modality) =>
getModalityIcon(modality)
)}
</div>
</td>
<td>{renderCost(model.cost?.input)}</td>
<td>{renderCost(model.cost?.output)}</td>
<td>{renderCost(model.cost?.reasoning)}</td>
<td>{renderCost(model.cost?.cache_read)}</td>
<td>{renderCost(model.cost?.cache_write)}</td>
<td>{renderCost(model.cost?.input_audio)}</td>
<td>{renderCost(model.cost?.output_audio)}</td>
<td>{model.limit.context.toLocaleString()}</td>
<td>{model.limit.input?.toLocaleString() ?? "-"}</td>
<td>{model.limit.output.toLocaleString()}</td>
<td>
{model.structured_output === undefined
? "-"
: model.structured_output
? "Yes"
: "No"}
</td>
<td>{model.temperature ? "Yes" : "No"}</td>
<td>{model.open_weights ? "Open" : "Closed"}</td>
<td>
{model.knowledge ? model.knowledge.substring(0, 7) : "-"}
</td>
<td>{model.release_date}</td>
<td>{model.last_updated}</td>
</tr>
))
)}
</tbody>
</table>
<dialog id="modal">
+2 -10
View File
@@ -1,19 +1,11 @@
import Index from "../index.html";
import { normalizeLogoSvg } from "./logo.js";
import { Providers, Rendered } from "./render";
import { Rendered } from "./render";
import path from "path";
Bun.serve({
port: 16_000,
routes: {
"/": Index,
"/api.json": () => {
return Response.json(Providers, {
headers: {
"Cache-Control": "public, max-age=3600",
},
});
},
"/assets/*": (req) => {
const file = Bun.file(
path.join(import.meta.dir, new URL(req.url).pathname)
@@ -46,7 +38,7 @@ Bun.serve({
file = Bun.file(defaultLogoPath);
}
return new Response(normalizeLogoSvg(await file.text()), {
return new Response(file, {
headers: {
"Content-Type": "image/svg+xml",
"Cache-Control": "public, max-age=3600",
@@ -1,4 +1,5 @@
name = "claude-3-5-haiku-20241022"
family = "claude-haiku"
release_date = "2024-10-22"
last_updated = "2024-10-22"
attachment = true
@@ -6,7 +7,7 @@ reasoning = false
temperature = true
tool_call = true
open_weights = false
knowledge = "2024-07"
knowledge = "2024-07-31"
[cost]
input = 0.800
@@ -1,4 +1,5 @@
name = "claude-3-5-haiku-latest"
family = "claude-haiku"
release_date = "2024-10-22"
last_updated = "2024-10-22"
attachment = true
@@ -6,7 +7,7 @@ reasoning = false
temperature = true
tool_call = true
open_weights = false
knowledge = "2024-07"
knowledge = "2024-07-31"
[cost]
input = 0.800
@@ -1,4 +1,5 @@
name = "claude-haiku-4-5-20251001"
family = "claude-haiku"
release_date = "2025-10-16"
last_updated = "2025-10-16"
attachment = true
@@ -6,7 +7,7 @@ reasoning = true
temperature = true
tool_call = true
open_weights = false
knowledge = "2025-03"
knowledge = "2025-02-28"
[cost]
input = 1.000
+2 -1
View File
@@ -1,4 +1,5 @@
name = "claude-haiku-4-5"
family = "claude-haiku"
release_date = "2025-10-16"
last_updated = "2025-10-16"
attachment = true
@@ -6,7 +7,7 @@ reasoning = true
temperature = true
tool_call = true
open_weights = false
knowledge = "2025-02"
knowledge = "2025-02-28"
[cost]
input = 1.000
@@ -1,12 +1,13 @@
name = "claude-opus-4-1-20250805"
family = "claude-opus"
release_date = "2025-08-05"
last_updated = "2025-08-05"
attachment = true
reasoning = false
reasoning = true
temperature = true
tool_call = true
open_weights = false
knowledge = "2025-03"
knowledge = "2025-03-31"
[cost]
input = 15.000
@@ -17,5 +18,5 @@ context = 200_000
output = 32_000
[modalities]
input = ["text", "image"]
input = ["text", "image", "pdf"]
output = ["text"]
@@ -1,12 +1,13 @@
name = "claude-opus-4-20250514"
family = "claude-opus"
release_date = "2025-05-22"
last_updated = "2025-05-22"
attachment = true
reasoning = false
reasoning = true
temperature = true
tool_call = true
open_weights = false
knowledge = "2025-03"
knowledge = "2025-03-31"
[cost]
input = 15.000
@@ -1,4 +1,5 @@
name = "claude-opus-4-5-20251101"
family = "claude-opus"
release_date = "2025-11-25"
last_updated = "2025-11-25"
attachment = true
@@ -6,7 +7,7 @@ reasoning = true
temperature = true
tool_call = true
open_weights = false
knowledge = "2025-03"
knowledge = "2025-03-31"
[cost]
input = 5.000
+2 -1
View File
@@ -1,4 +1,5 @@
name = "claude-opus-4-5"
family = "claude-opus"
release_date = "2025-11-25"
last_updated = "2025-11-25"
attachment = true
@@ -6,7 +7,7 @@ reasoning = true
temperature = true
tool_call = true
open_weights = false
knowledge = "2025-03"
knowledge = "2025-03-31"
[cost]
input = 5.000
+2 -1
View File
@@ -1,4 +1,5 @@
name = "claude-opus-4-6"
family = "claude-opus"
release_date = "2026-02-06"
last_updated = "2026-03-13"
attachment = true
@@ -6,7 +7,7 @@ reasoning = true
temperature = true
tool_call = true
open_weights = false
knowledge = "2025-05"
knowledge = "2025-05-31"
[cost]
input = 5.000
+5 -3
View File
@@ -1,4 +1,5 @@
name = "claude-opus-4-7"
family = "claude-opus"
release_date = "2026-04-17"
last_updated = "2026-04-17"
attachment = true
@@ -6,7 +7,7 @@ reasoning = true
temperature = true
tool_call = true
open_weights = false
knowledge = "2025-05"
knowledge = "2026-01-31"
[cost]
input = 5.000
@@ -14,14 +15,15 @@ output = 25.000
cache_read = 0.500
cache_write = 6.250
[cost.context_over_200k]
[[cost.tiers]]
tier = { size = 200_000 }
input = 10.000
output = 37.500
cache_read = 1.000
cache_write = 12.500
[limit]
context = 200_000
context = 1_000_000
output = 128_000
[modalities]
@@ -1,12 +1,13 @@
name = "claude-sonnet-4-20250514"
family = "claude-sonnet"
release_date = "2025-05-22"
last_updated = "2025-05-22"
attachment = true
reasoning = false
reasoning = true
temperature = true
tool_call = true
open_weights = false
knowledge = "2025-03"
knowledge = "2025-03-31"
[cost]
input = 3.000
@@ -1,12 +1,13 @@
name = "claude-sonnet-4-5-20250929"
family = "claude-sonnet"
release_date = "2025-09-30"
last_updated = "2025-09-30"
attachment = true
reasoning = false
reasoning = true
temperature = true
tool_call = true
open_weights = false
knowledge = "2025-03"
knowledge = "2025-07-31"
[cost]
input = 3.000
@@ -1,12 +1,13 @@
name = "claude-sonnet-4-5"
family = "claude-sonnet"
release_date = "2025-09-30"
last_updated = "2025-09-30"
attachment = true
reasoning = false
reasoning = true
temperature = true
tool_call = true
open_weights = false
knowledge = "2025-07"
knowledge = "2025-07-31"
[cost]
input = 3.000
@@ -1,12 +1,13 @@
name = "claude-sonnet-4-6"
family = "claude-sonnet"
release_date = "2026-02-18"
last_updated = "2026-03-13"
attachment = true
reasoning = false
reasoning = true
temperature = true
tool_call = true
open_weights = false
knowledge = "2025-08"
knowledge = "2025-08-31"
[cost]
input = 3.000
+4 -3
View File
@@ -1,11 +1,12 @@
name = "glm-4.5-air"
family = "glm-air"
release_date = "2025-07-29"
last_updated = "2025-07-29"
attachment = false
reasoning = false
reasoning = true
temperature = true
tool_call = true
open_weights = false
open_weights = true
knowledge = "2025-04"
[cost]
@@ -13,7 +14,7 @@ input = 0.1143
output = 0.286
[limit]
context = 128_000
context = 131_072
output = 98_304
[modalities]
+1
View File
@@ -1,4 +1,5 @@
name = "glm-4.5-airx"
family = "glm"
release_date = "2025-07-29"
last_updated = "2025-07-29"
attachment = false
+1
View File
@@ -1,4 +1,5 @@
name = "glm-4.5-x"
family = "glm"
release_date = "2025-07-29"
last_updated = "2025-07-29"
attachment = false
+5 -4
View File
@@ -1,19 +1,20 @@
name = "GLM-4.5"
family = "glm"
release_date = "2025-07-29"
last_updated = "2025-07-29"
attachment = false
reasoning = false
reasoning = true
temperature = true
tool_call = true
open_weights = false
knowledge = "2024-10"
open_weights = true
knowledge = "2025-04"
[cost]
input = 0.286
output = 1.142
[limit]
context = 128_000
context = 131_072
output = 98_304
[modalities]
+5 -4
View File
@@ -1,12 +1,13 @@
name = "GLM-4.5V"
family = "glm"
release_date = "2025-08-12"
last_updated = "2025-08-12"
attachment = true
reasoning = false
reasoning = true
temperature = true
tool_call = true
open_weights = false
knowledge = "2024-10"
open_weights = true
knowledge = "2025-04"
[cost]
input = 0.290
@@ -17,5 +18,5 @@ context = 64_000
output = 16_384
[modalities]
input = ["text", "image"]
input = ["text", "image", "video"]
output = ["text"]
+4 -3
View File
@@ -1,19 +1,20 @@
name = "glm-4.6"
family = "glm"
release_date = "2025-09-30"
last_updated = "2025-09-30"
attachment = false
reasoning = true
temperature = true
tool_call = true
open_weights = false
knowledge = "2025-03"
open_weights = true
knowledge = "2025-04"
[cost]
input = 0.286
output = 1.142
[limit]
context = 200_000
context = 204_800
output = 131_072
[modalities]
+5 -4
View File
@@ -1,12 +1,13 @@
name = "GLM-4.6V"
family = "glm"
release_date = "2025-12-08"
last_updated = "2025-12-08"
attachment = true
reasoning = false
reasoning = true
temperature = true
tool_call = true
open_weights = false
knowledge = "2025-03"
open_weights = true
knowledge = "2025-04"
[cost]
input = 0.145
@@ -17,5 +18,5 @@ context = 128_000
output = 32_768
[modalities]
input = ["text", "image"]
input = ["text", "image", "video"]
output = ["text"]
+2 -1
View File
@@ -1,11 +1,12 @@
name = "glm-4.7-flashx"
family = "glm-flash"
release_date = "2026-01-20"
last_updated = "2026-01-20"
attachment = false
reasoning = true
temperature = true
tool_call = true
open_weights = false
open_weights = true
knowledge = "2025-04"
[cost]
+7 -3
View File
@@ -1,19 +1,23 @@
name = "glm-4.7"
family = "glm"
release_date = "2025-12-22"
last_updated = "2025-12-22"
attachment = false
reasoning = true
temperature = true
tool_call = true
open_weights = false
knowledge = "2025-06"
open_weights = true
knowledge = "2025-04"
[interleaved]
field = "reasoning_content"
[cost]
input = 0.286
output = 1.142
[limit]
context = 200_000
context = 204_800
output = 131_072
[modalities]
+5
View File
@@ -1,12 +1,17 @@
name = "glm-5-turbo"
family = "glm"
release_date = "2026-03-16"
last_updated = "2026-03-16"
attachment = false
reasoning = true
temperature = true
tool_call = true
structured_output = true
open_weights = false
[interleaved]
field = "reasoning_content"
[cost]
input = 0.720
output = 3.200
+5
View File
@@ -1,12 +1,17 @@
name = "glm-5.1"
family = "glm"
release_date = "2026-04-10"
last_updated = "2026-04-10"
attachment = false
reasoning = true
temperature = true
tool_call = true
structured_output = true
open_weights = false
[interleaved]
field = "reasoning_content"
[cost]
input = 0.860
output = 3.500
+6 -2
View File
@@ -1,18 +1,22 @@
name = "glm-5"
family = "glm"
release_date = "2026-02-12"
last_updated = "2026-02-12"
attachment = false
reasoning = true
temperature = true
tool_call = true
open_weights = false
open_weights = true
[interleaved]
field = "reasoning_content"
[cost]
input = 0.600
output = 2.600
[limit]
context = 200_000
context = 204_800
output = 131_072
[modalities]
+5 -1
View File
@@ -1,4 +1,5 @@
name = "glm-5v-turbo"
name = "GLM-5V-Turbo"
family = "glm"
release_date = "2026-04-02"
last_updated = "2026-04-02"
attachment = true
@@ -7,6 +8,9 @@ temperature = true
tool_call = true
open_weights = false
[interleaved]
field = "reasoning_content"
[cost]
input = 0.720
output = 3.200
@@ -1,4 +1,5 @@
name = "glm-for-coding"
family = "glm"
release_date = "2025-09-30"
last_updated = "2025-09-30"
attachment = false
+3 -2
View File
@@ -6,6 +6,7 @@ attachment = true
reasoning = false
temperature = true
tool_call = true
structured_output = true
open_weights = false
knowledge = "2024-04"
@@ -14,9 +15,9 @@ input = 0.400
output = 1.600
[limit]
context = 1_000_000
context = 1_047_576
output = 32_768
[modalities]
input = ["text", "image"]
input = ["text", "image", "pdf"]
output = ["text"]
+2 -1
View File
@@ -6,6 +6,7 @@ attachment = true
reasoning = false
temperature = true
tool_call = true
structured_output = true
open_weights = false
knowledge = "2024-04"
@@ -14,7 +15,7 @@ input = 0.100
output = 0.400
[limit]
context = 1_000_000
context = 1_047_576
output = 32_768
[modalities]
+3 -2
View File
@@ -6,6 +6,7 @@ attachment = true
reasoning = false
temperature = true
tool_call = true
structured_output = true
open_weights = false
knowledge = "2024-04"
@@ -14,9 +15,9 @@ input = 2.000
output = 8.000
[limit]
context = 1_000_000
context = 1_047_576
output = 32_768
[modalities]
input = ["text", "image"]
input = ["text", "image", "pdf"]
output = ["text"]
+2 -1
View File
@@ -6,6 +6,7 @@ attachment = true
reasoning = false
temperature = true
tool_call = true
structured_output = true
open_weights = false
knowledge = "2023-09"
@@ -18,5 +19,5 @@ context = 128_000
output = 16_384
[modalities]
input = ["text", "image"]
input = ["text", "image", "pdf"]
output = ["text"]
+6 -3
View File
@@ -1,12 +1,14 @@
name = "gpt-5-mini"
family = "gpt-mini"
release_date = "2025-08-08"
last_updated = "2025-08-08"
attachment = true
reasoning = false
temperature = true
reasoning = true
temperature = false
tool_call = true
structured_output = true
open_weights = false
knowledge = "2024-10"
knowledge = "2024-05-30"
[cost]
input = 0.250
@@ -14,6 +16,7 @@ output = 2.000
[limit]
context = 400_000
input = 272_000
output = 128_000
[modalities]
+6 -3
View File
@@ -1,12 +1,14 @@
name = "gpt-5-pro"
family = "gpt-pro"
release_date = "2025-10-08"
last_updated = "2025-10-08"
attachment = true
reasoning = false
temperature = true
reasoning = true
temperature = false
tool_call = true
structured_output = true
open_weights = false
knowledge = "2024-10"
knowledge = "2024-09-30"
[cost]
input = 15.000
@@ -14,6 +16,7 @@ output = 120.000
[limit]
context = 400_000
input = 272_000
output = 272_000
[modalities]
@@ -1,12 +1,14 @@
name = "gpt-5.1-chat-latest"
family = "gpt-codex"
release_date = "2025-11-14"
last_updated = "2025-11-14"
attachment = true
reasoning = false
temperature = true
reasoning = true
temperature = false
tool_call = true
structured_output = true
open_weights = false
knowledge = "2024-10"
knowledge = "2024-09-30"
[cost]
input = 1.250
+6 -3
View File
@@ -1,12 +1,14 @@
name = "gpt-5.1"
family = "gpt"
release_date = "2025-11-14"
last_updated = "2025-11-14"
attachment = true
reasoning = false
temperature = true
reasoning = true
temperature = false
tool_call = true
structured_output = true
open_weights = false
knowledge = "2024-10"
knowledge = "2024-09-30"
[cost]
input = 1.250
@@ -14,6 +16,7 @@ output = 10.000
[limit]
context = 400_000
input = 272_000
output = 128_000
[modalities]
@@ -1,12 +1,14 @@
name = "gpt-5.2-chat-latest"
family = "gpt-codex"
release_date = "2025-12-12"
last_updated = "2025-12-12"
attachment = true
reasoning = false
temperature = true
reasoning = true
temperature = false
tool_call = true
structured_output = true
open_weights = false
knowledge = "2024-10"
knowledge = "2025-08-31"
[cost]
input = 1.750
+6 -3
View File
@@ -1,12 +1,14 @@
name = "gpt-5.2"
family = "gpt"
release_date = "2025-12-12"
last_updated = "2025-12-12"
attachment = true
reasoning = false
temperature = true
reasoning = true
temperature = false
tool_call = true
structured_output = true
open_weights = false
knowledge = "2024-10"
knowledge = "2025-08-31"
[cost]
input = 1.750
@@ -14,6 +16,7 @@ output = 14.000
[limit]
context = 400_000
input = 272_000
output = 128_000
[modalities]
@@ -1,12 +1,14 @@
name = "gpt-5.4-mini-2026-03-17"
family = "gpt-mini"
release_date = "2026-03-19"
last_updated = "2026-03-19"
attachment = true
reasoning = false
temperature = true
reasoning = true
temperature = false
tool_call = true
structured_output = true
open_weights = false
knowledge = "2025-08"
knowledge = "2025-08-31"
[cost]
input = 0.750
@@ -14,6 +16,7 @@ output = 4.500
[limit]
context = 400_000
input = 272_000
output = 128_000
[modalities]
+6 -3
View File
@@ -1,12 +1,14 @@
name = "gpt-5.4-mini"
family = "gpt-mini"
release_date = "2026-03-19"
last_updated = "2026-03-19"
attachment = true
reasoning = false
temperature = true
reasoning = true
temperature = false
tool_call = true
structured_output = true
open_weights = false
knowledge = "2025-08"
knowledge = "2025-08-31"
[cost]
input = 0.750
@@ -14,6 +16,7 @@ output = 4.500
[limit]
context = 400_000
input = 272_000
output = 128_000
[modalities]
@@ -1,12 +1,14 @@
name = "gpt-5.4-nano-2026-03-17"
family = "gpt-nano"
release_date = "2026-03-19"
last_updated = "2026-03-19"
attachment = true
reasoning = false
temperature = true
reasoning = true
temperature = false
tool_call = true
structured_output = true
open_weights = false
knowledge = "2025-08"
knowledge = "2025-08-31"
[cost]
input = 0.200
@@ -14,6 +16,7 @@ output = 1.250
[limit]
context = 400_000
input = 272_000
output = 128_000
[modalities]
+6 -3
View File
@@ -1,12 +1,14 @@
name = "gpt-5.4-nano"
family = "gpt-nano"
release_date = "2026-03-19"
last_updated = "2026-03-19"
attachment = true
reasoning = false
temperature = true
reasoning = true
temperature = false
tool_call = true
structured_output = true
open_weights = false
knowledge = "2025-08"
knowledge = "2025-08-31"
[cost]
input = 0.200
@@ -14,6 +16,7 @@ output = 1.250
[limit]
context = 400_000
input = 272_000
output = 128_000
[modalities]
+31
View File
@@ -0,0 +1,31 @@
name = "gpt-5.4-pro"
family = "gpt-pro"
release_date = "2026-03-05"
last_updated = "2026-03-05"
attachment = true
reasoning = true
temperature = false
tool_call = true
structured_output = false
open_weights = false
knowledge = "2025-08-31"
[cost]
input = 30.000
output = 180.000
cache_read = 0
cache_write = 0
[[cost.tiers]]
tier = { size = 272_000 }
input = 60.000
output = 270.000
[limit]
context = 1_050_000
input = 922_000
output = 128_000
[modalities]
input = ["text", "image"]
output = ["text"]
+31
View File
@@ -0,0 +1,31 @@
name = "gpt-5.4"
family = "gpt"
release_date = "2026-03-05"
last_updated = "2026-03-05"
attachment = true
reasoning = true
temperature = false
tool_call = true
structured_output = true
open_weights = false
knowledge = "2025-08-31"
[cost]
input = 2.500
output = 15.000
cache_read = 0.250
cache_write = 0
[[cost.tiers]]
tier = { size = 272_000 }
input = 5.000
output = 22.500
[limit]
context = 1_050_000
input = 922_000
output = 128_000
[modalities]
input = ["text", "image", "pdf"]
output = ["text"]
+6 -3
View File
@@ -1,12 +1,14 @@
name = "gpt-5"
family = "gpt"
release_date = "2025-08-08"
last_updated = "2025-08-08"
attachment = true
reasoning = false
temperature = true
reasoning = true
temperature = false
tool_call = true
structured_output = true
open_weights = false
knowledge = "2024-10"
knowledge = "2024-09-30"
[cost]
input = 1.250
@@ -14,6 +16,7 @@ output = 10.000
[limit]
context = 400_000
input = 272_000
output = 128_000
[modalities]
+6
View File
@@ -0,0 +1,6 @@
<svg viewBox="0 0 220 32" xmlns="http://www.w3.org/2000/svg">
<text x="0" y="24" fill="currentColor">
<tspan font-size="24">Abliteration</tspan>
<tspan dx="8" dy="2" font-size="12" fill-opacity="0.6">.ai</tspan>
</text>
</svg>

After

Width:  |  Height:  |  Size: 239 B

@@ -0,0 +1,22 @@
name = "Abliterated Model"
release_date = "2026-01-06"
last_updated = "2026-01-06"
attachment = true
reasoning = false
tool_call = true
structured_output = false
temperature = true
open_weights = true
[cost]
input = 3.00
output = 3.00
[limit]
context = 150_000
input = 150_000
output = 8_192
[modalities]
input = ["text", "image"]
output = ["text"]
+5
View File
@@ -0,0 +1,5 @@
name = "abliteration.ai"
env = ["ABLIT_KEY"]
npm = "@ai-sdk/openai-compatible"
api = "https://api.abliteration.ai/v1"
doc = "https://docs.abliteration.ai/models"
@@ -1,23 +0,0 @@
name = "Claude Opus 4.5"
release_date = "2025-11-25"
last_updated = "2025-11-25"
attachment = true
reasoning = true
temperature = true
tool_call = true
knowledge = "2025-03"
open_weights = false
[cost]
input = 5.00
output = 25.00
cache_read = 0.50
cache_write = 6.25
[limit]
context = 200_000
output = 32_000
[modalities]
input = ["text", "image"]
output = ["text"]
@@ -1,7 +1,7 @@
name = "Claude Opus 4.6 Think"
name = "Claude Opus 4.6"
family = "claude-opus"
release_date = "2026-02-05"
last_updated = "2026-02-05"
last_updated = "2026-03-13"
attachment = true
reasoning = true
temperature = true
@@ -10,20 +10,14 @@ knowledge = "2025-05-31"
open_weights = false
[cost]
input = 5.00
output = 25.00
cache_read = 0.30
cache_write = 3.75
[cost.context_over_200k]
input = 6.00
output = 22.00
cache_read = 0.60
cache_write = 7.50
input = 5
output = 25
cache_read = 0.5
cache_write = 6.25
[limit]
context = 200_000
output = 128_000
output = 32_000
[modalities]
input = ["text", "image", "pdf"]
+6 -12
View File
@@ -1,7 +1,7 @@
name = "Claude Opus 4.6"
family = "claude-opus"
release_date = "2026-02-05"
last_updated = "2026-02-05"
last_updated = "2026-03-13"
attachment = true
reasoning = true
temperature = true
@@ -10,19 +10,13 @@ knowledge = "2025-05-31"
open_weights = false
[cost]
input = 5.00
output = 25.00
cache_read = 0.30
cache_write = 3.75
[cost.context_over_200k]
input = 6.00
output = 22.00
cache_read = 0.60
cache_write = 7.50
input = 5
output = 25
cache_read = 0.5
cache_write = 6.25
[limit]
context = 200_000
context = 1_000_000
output = 128_000
[modalities]
@@ -0,0 +1,25 @@
name = "Claude Opus 4.7 Thinking"
family = "claude-opus"
release_date = "2026-04-16"
last_updated = "2026-04-16"
attachment = true
reasoning = true
temperature = false
tool_call = true
structured_output = true
knowledge = "2026-01-31"
open_weights = false
[cost]
input = 5
output = 25
cache_read = 0.5
cache_write = 6.25
[limit]
context = 200_000
output = 32_000
[modalities]
input = ["text", "image"]
output = ["text"]
@@ -0,0 +1,24 @@
name = "Claude Opus 4.7"
family = "claude-opus"
release_date = "2026-04-16"
last_updated = "2026-04-16"
attachment = true
reasoning = true
temperature = false
tool_call = true
knowledge = "2026-01-31"
open_weights = false
[cost]
input = 5
output = 25
cache_read = 0.5
cache_write = 6.25
[limit]
context = 1_000_000
output = 128_000
[modalities]
input = ["text", "image", "pdf"]
output = ["text"]
@@ -15,7 +15,8 @@ output = 15.00
cache_read = 0.30
cache_write = 3.75
[cost.context_over_200k]
[[cost.tiers]]
tier = { size = 200_000 }
input = 6.00
output = 22.50
cache_read = 0.60
@@ -15,7 +15,8 @@ output = 15.00
cache_read = 0.30
cache_write = 3.75
[cost.context_over_200k]
[[cost.tiers]]
tier = { size = 200_000 }
input = 6.00
output = 22.50
cache_read = 0.60
@@ -1,28 +0,0 @@
name = "Coding GLM 4.7 Free"
family = "glm"
release_date = "2025-12-22"
last_updated = "2025-12-22"
attachment = false
reasoning = true
temperature = true
tool_call = true
knowledge = "2025-04"
open_weights = true
[interleaved]
field = "reasoning_details"
[cost]
input = 0
output = 0
cache_read = 0
cache_write = 0
[limit]
context = 204800
output = 131072
[modalities]
input = ["text"]
output = ["text"]
@@ -1,27 +0,0 @@
name = "Coding-GLM-4.7"
family = "glm"
release_date = "2025-12-22"
last_updated = "2025-12-22"
attachment = false
reasoning = true
temperature = true
tool_call = true
knowledge = "2025-04"
open_weights = true
[interleaved]
field = "reasoning_details"
[cost]
input = 0.06
output = 0.22
cache_read = 0.01
[limit]
context = 204800
output = 131072
[modalities]
input = ["text"]
output = ["text"]
@@ -1,25 +1,26 @@
name = "GLM 4.5 TEE"
name = "Coding GLM 5.1 (free)"
family = "glm"
release_date = "2025-12-29"
last_updated = "2026-01-10"
release_date = "2026-04-11"
last_updated = "2026-04-11"
attachment = false
reasoning = true
temperature = true
tool_call = true
structured_output = true
open_weights = true
open_weights = false
[interleaved]
field = "reasoning_content"
[cost]
input = 0.35
output = 1.55
input = 0
output = 0
cache_read = 0
[limit]
context = 131_072
output = 65_536
context = 204_800
output = 128_000
[modalities]
input = ["text"]
output = ["text"]
[interleaved]
field = "reasoning_content"
@@ -1,7 +1,7 @@
name = "MiniMax-M2.5"
name = "Coding-MiniMax-M2.7-Free"
family = "minimax"
release_date = "2026-02-12"
last_updated = "2026-02-12"
release_date = "2026-03-18"
last_updated = "2026-03-18"
attachment = false
reasoning = true
temperature = true
@@ -9,12 +9,12 @@ tool_call = true
open_weights = true
[cost]
input = 0.29
output = 1.15
input = 0
output = 0
[limit]
context = 204_800
output = 131_072
output = 13_100
[modalities]
input = ["text"]
@@ -1,25 +1,22 @@
name = "MiniMax M2.1"
name = "Coding MiniMax M2.7 Highspeed"
family = "minimax"
release_date = "2026-03-18"
last_updated = "2026-03-18"
attachment = false
reasoning = true
tool_call = true
temperature = true
release_date = "2025-12-23"
last_updated = "2025-12-23"
tool_call = true
structured_output = true
open_weights = true
[interleaved]
field = "reasoning_details"
[cost]
input = 0.29
output = 1.15
input = 0.2
output = 0.2
[limit]
context = 204_800
output = 131_072
output = 13_100
[modalities]
input = ["text"]
output = ["text"]
@@ -1,20 +1,21 @@
name = "MiniMax-M2.1"
name = "Coding MiniMax M2.7"
family = "minimax"
release_date = "2025-12-23"
last_updated = "2025-12-23"
release_date = "2026-03-18"
last_updated = "2026-03-18"
attachment = false
reasoning = true
temperature = true
tool_call = true
structured_output = true
open_weights = true
[cost]
input = 0.0
output = 0.0
input = 0.2
output = 0.2
[limit]
context = 204_800
output = 131_072
output = 13_100
[modalities]
input = ["text"]
@@ -1,21 +0,0 @@
name = "DeepSeek-V3.2-Fast"
family = "deepseek"
release_date = "2025-12-01"
last_updated = "2025-12-01"
attachment = false
reasoning = false
knowledge = "2024-07"
tool_call = false
open_weights = true
[cost]
input = 1.10
output = 3.29
[limit]
context = 128_000
output = 128_000
[modalities]
input = ["text"]
output = ["text"]
@@ -0,0 +1,27 @@
name = "DeepSeek V4 Flash Think"
family = "deepseek"
release_date = "2026-04-24"
last_updated = "2026-04-24"
attachment = false
reasoning = true
temperature = true
tool_call = true
structured_output = true
knowledge = "2025-05"
open_weights = true
[interleaved]
field = "reasoning_content"
[cost]
input = 0.154
output = 0.308
cache_read = 0.0308
[limit]
context = 1_000_000
output = 384_000
[modalities]
input = ["text"]
output = ["text"]
@@ -0,0 +1,27 @@
name = "DeepSeek V4 Flash"
family = "deepseek-flash"
release_date = "2026-04-24"
last_updated = "2026-04-24"
attachment = false
reasoning = true
temperature = true
tool_call = true
structured_output = true
knowledge = "2025-05"
open_weights = true
[interleaved]
field = "reasoning_content"
[cost]
input = 0.154
output = 0.308
cache_read = 0.0308
[limit]
context = 1_000_000
output = 384_000
[modalities]
input = ["text"]
output = ["text"]
@@ -0,0 +1,27 @@
name = "DeepSeek V4 Pro"
family = "deepseek-thinking"
release_date = "2026-04-24"
last_updated = "2026-04-24"
attachment = false
reasoning = true
temperature = true
tool_call = true
structured_output = true
knowledge = "2025-05"
open_weights = true
[interleaved]
field = "reasoning_content"
[cost]
input = 0.478
output = 0.956
cache_read = 0.004302
[limit]
context = 1_000_000
output = 384_000
[modalities]
input = ["text"]
output = ["text"]
+11 -10
View File
@@ -1,23 +1,24 @@
name = "Gemini 2.5 Flash"
family = "gemini-flash"
release_date = "2025-09-15"
last_updated = "2025-09-15"
release_date = "2025-03-20"
last_updated = "2025-06-05"
attachment = true
reasoning = false
reasoning = true
temperature = true
knowledge = "2025-04"
tool_call = true
structured_output = true
knowledge = "2025-01"
open_weights = false
[cost]
input = 0.075
output = 0.30
cache_read = 0.02
input = 0.3
output = 2.499
cache_read = 0.03
[limit]
context = 1_000_000
output = 65_000
context = 1_048_576
output = 65_536
[modalities]
input = ["text", "image", "audio", "video"]
input = ["text", "image", "audio", "video", "pdf"]
output = ["text"]
@@ -1,23 +1,24 @@
name = "Gemini 2.5 Pro"
family = "gemini-pro"
release_date = "2025-09-15"
last_updated = "2025-09-15"
release_date = "2025-03-20"
last_updated = "2025-06-05"
attachment = true
reasoning = true
temperature = true
knowledge = "2025-04"
tool_call = true
structured_output = true
knowledge = "2025-01"
open_weights = false
[cost]
input = 1.25
output = 5.00
cache_read = 0.31
output = 10
cache_read = 0.125
[limit]
context = 2_000_000
output = 65_000
context = 1_048_576
output = 65_536
[modalities]
input = ["text", "image", "audio", "video"]
input = ["text", "image", "audio", "video", "pdf"]
output = ["text"]
@@ -0,0 +1,24 @@
name = "Gemini 3 Flash Preview"
family = "gemini-flash"
release_date = "2025-12-17"
last_updated = "2025-12-17"
attachment = true
reasoning = true
temperature = true
tool_call = true
structured_output = true
knowledge = "2025-01"
open_weights = false
[cost]
input = 0.5
output = 3
cache_read = 0.05
[limit]
context = 1_048_576
output = 65_536
[modalities]
input = ["text", "image", "audio", "video", "pdf"]
output = ["text"]
@@ -1,23 +0,0 @@
name = "Gemini 3 Pro Preview Search"
family = "gemini-pro"
release_date = "2025-11-19"
last_updated = "2025-11-19"
attachment = true
reasoning = true
temperature = true
tool_call = true
knowledge = "2025-11"
open_weights = false
[cost]
input = 2.00
output = 12.00
cache_read = 0.50
[limit]
context = 1_000_000
output = 65_000
[modalities]
input = ["text", "image", "audio", "video"]
output = ["text"]
@@ -1,23 +0,0 @@
name = "Gemini 3 Pro Preview"
family = "gemini-pro"
release_date = "2025-11-19"
last_updated = "2025-11-19"
attachment = true
reasoning = true
temperature = true
tool_call = true
knowledge = "2025-11"
open_weights = false
[cost]
input = 2.00
output = 12.00
cache_read = 0.50
[limit]
context = 1_000_000
output = 65_000
[modalities]
input = ["text", "image", "audio", "video"]
output = ["text"]
@@ -0,0 +1,24 @@
name = "Gemini 3.1 Flash Lite"
family = "gemini-flash-lite"
release_date = "2026-03-03"
last_updated = "2026-03-03"
attachment = true
reasoning = true
temperature = true
tool_call = true
structured_output = true
knowledge = "2025-01"
open_weights = false
[cost]
input = 0.25
output = 1.5
cache_read = 0.25
[limit]
context = 1_048_576
output = 65_536
[modalities]
input = ["text", "image", "audio", "video", "pdf"]
output = ["text"]
@@ -0,0 +1,30 @@
name = "Gemini 3.1 Pro Preview Custom Tools"
family = "gemini-pro"
release_date = "2026-02-19"
last_updated = "2026-02-19"
attachment = true
reasoning = true
temperature = true
tool_call = true
structured_output = true
knowledge = "2025-01"
open_weights = false
[cost]
input = 2
output = 12
cache_read = 0.2
[[cost.tiers]]
tier = { size = 200_000 }
input = 4
output = 18
cache_read = 0.4
[limit]
context = 1_048_576
output = 65_536
[modalities]
input = ["text", "image", "audio", "video", "pdf"]
output = ["text"]
@@ -1,7 +1,7 @@
name = "Gemini 3 Pro Preview"
name = "Gemini 3.1 Pro Preview"
family = "gemini-pro"
release_date = "2025-11-18"
last_updated = "2025-11-18"
release_date = "2026-02-19"
last_updated = "2026-02-19"
attachment = true
reasoning = true
temperature = true
@@ -16,9 +16,9 @@ output = 12
cache_read = 0.2
[limit]
context = 1_000_000
output = 64_000
context = 1_048_576
output = 65_536
[modalities]
input = ["text", "image", "video", "audio", "pdf"]
input = ["text", "image", "audio", "video", "pdf"]
output = ["text"]
-22
View File
@@ -1,22 +0,0 @@
name = "GLM-4.6V"
family = "glm"
release_date = "2025-12-08"
last_updated = "2025-12-08"
attachment = true
reasoning = true
temperature = true
tool_call = true
knowledge = "2025-04"
open_weights = true
[cost]
input = 0.14
output = 0.41
[limit]
context = 128000
output = 32768
[modalities]
input = ["text", "image", "video"]
output = ["text"]
-27
View File
@@ -1,27 +0,0 @@
name = "GLM-4.7"
family = "glm"
release_date = "2025-12-22"
last_updated = "2025-12-22"
attachment = false
reasoning = true
temperature = true
tool_call = true
knowledge = "2025-04"
open_weights = true
[interleaved]
field = "reasoning_details"
[cost]
input = 0.27
output = 1.10
cache_read = 0.548
[limit]
context = 204800
output = 131072
[modalities]
input = ["text"]
output = ["text"]
+7 -5
View File
@@ -1,23 +1,25 @@
name = "GLM-5.1"
family = "glm"
release_date = "2026-04-11"
last_updated = "2026-04-11"
release_date = "2026-03-27"
last_updated = "2026-03-27"
attachment = false
reasoning = true
temperature = true
tool_call = true
structured_output = true
open_weights = false
[interleaved]
field = "reasoning_content"
[cost]
input = 0.84
input = 0.845
output = 3.38
cache_read = 0.183112
[limit]
context = 200000
output = 128000
context = 200_000
output = 128_000
[modalities]
input = ["text"]
-24
View File
@@ -1,24 +0,0 @@
name = "GLM-5"
family = "glm"
release_date = "2026-02-11"
last_updated = "2026-02-11"
attachment = false
reasoning = true
temperature = true
tool_call = true
open_weights = false
[interleaved]
field = "reasoning_content"
[cost]
input = 0.88
output = 2.82
[limit]
context = 204800
output = 131072
[modalities]
input = ["text"]
output = ["text"]
@@ -0,0 +1,26 @@
name = "GLM 5 Vision Turbo"
family = "glm"
release_date = "2026-05-09"
last_updated = "2026-05-09"
attachment = true
reasoning = true
temperature = true
tool_call = true
structured_output = true
open_weights = false
[interleaved]
field = "reasoning_content"
[cost]
input = 0.7042
output = 3.09848
cache_read = 0.169008
[limit]
context = 200_000
output = 128_000
[modalities]
input = ["text", "image", "video"]
output = ["text"]
@@ -1,23 +0,0 @@
name = "GPT-4.1 nano"
family = "gpt-nano"
release_date = "2025-04-14"
last_updated = "2025-04-14"
attachment = true
reasoning = false
temperature = true
knowledge = "2024-04"
tool_call = true
open_weights = false
[cost]
input = 0.10
output = 0.40
cache_read = 0.03
[limit]
context = 1_047_576
output = 32_768
[modalities]
input = ["text", "image"]
output = ["text"]
-23
View File
@@ -1,23 +0,0 @@
name = "GPT-4o"
family = "gpt"
release_date = "2024-05-13"
last_updated = "2024-08-06"
attachment = true
reasoning = false
temperature = true
knowledge = "2023-09"
tool_call = true
open_weights = false
[cost]
input = 2.50
output = 10.00
cache_read = 1.25
[limit]
context = 128_000
output = 16_384
[modalities]
input = ["text", "image"]
output = ["text"]
-23
View File
@@ -1,23 +0,0 @@
name = "GPT-5-Mini"
family = "gpt-mini"
release_date = "2025-09-15"
last_updated = "2025-09-15"
attachment = true
reasoning = true
temperature = true
knowledge = "2024-09-30"
tool_call = true
open_weights = false
[cost]
input = 1.50
output = 6.00
cache_read = 0.75
[limit]
context = 200_000
output = 64_000
[modalities]
input = ["text", "image"]
output = ["text"]
-23
View File
@@ -1,23 +0,0 @@
name = "GPT-5-Nano"
family = "gpt-nano"
release_date = "2025-09-15"
last_updated = "2025-09-15"
attachment = true
reasoning = false
temperature = true
knowledge = "2024-09-30"
tool_call = true
open_weights = false
[cost]
input = 0.50
output = 2.00
cache_read = 0.25
[limit]
context = 128_000
output = 16_384
[modalities]
input = ["text", "image"]
output = ["text"]
@@ -1,23 +0,0 @@
name = "GPT-5.1-Codex-Max"
release_date = "2025-11-13"
last_updated = "2025-11-13"
attachment = true
reasoning = true
temperature = false
knowledge = "2024-09-30"
tool_call = true
structured_output = true
open_weights = false
[cost]
input = 1.25
output = 10.00
cache_read = 0.125
[limit]
context = 400_000
output = 128_000
[modalities]
input = ["text", "image"]
output = ["text"]
@@ -1,22 +1,24 @@
name = "GPT-5.1 Codex Mini"
name = "GPT-5.1 Codex mini"
family = "gpt-codex"
release_date = "2025-11-15"
last_updated = "2025-11-15"
release_date = "2025-11-13"
last_updated = "2025-11-13"
attachment = true
reasoning = true
temperature = true
temperature = false
tool_call = true
knowledge = "2025-11"
structured_output = true
knowledge = "2024-09-30"
open_weights = false
[cost]
input = 0.25
output = 2.00
cache_read = 0.03
output = 2
cache_read = 0.025
[limit]
context = 400_000
output = 128_000
input = 272_000
[modalities]
input = ["text", "image"]
+8 -6
View File
@@ -1,22 +1,24 @@
name = "GPT-5.1 Codex"
family = "gpt-codex"
release_date = "2025-11-15"
last_updated = "2025-11-15"
release_date = "2025-11-13"
last_updated = "2025-11-13"
attachment = true
reasoning = true
temperature = true
temperature = false
tool_call = true
knowledge = "2025-11"
structured_output = true
knowledge = "2024-09-30"
open_weights = false
[cost]
input = 1.25
output = 10.00
cache_read = 0.13
output = 10
cache_read = 0.125
[limit]
context = 400_000
output = 128_000
input = 272_000
[modalities]
input = ["text", "image"]
@@ -0,0 +1,25 @@
name = "GPT-5.3 Codex"
family = "gpt-codex"
release_date = "2026-02-05"
last_updated = "2026-02-05"
attachment = true
reasoning = true
temperature = false
tool_call = true
structured_output = true
knowledge = "2025-08-31"
open_weights = false
[cost]
input = 1.75
output = 14
cache_read = 0.175
[limit]
context = 400_000
output = 128_000
input = 272_000
[modalities]
input = ["text", "image", "pdf"]
output = ["text"]

Some files were not shown because too many files have changed in this diff Show More