Compare commits

..

381 Commits

Author SHA1 Message Date
Aiden Cline 3e3918929c [opencode/anthropic] Add reasoning options 2026-06-13 16:00:47 -05:00
Aiden Cline 1ddcd9bc32 Merge pull request #2286 from anomalyco/fix/remove-glm-5.2-standard-apis
fix: remove GLM-5.2 from standard Z.AI APIs
2026-06-13 15:41:30 -05:00
Aiden Cline 7a9b4a167c Merge pull request #2206 from anomalyco/feat/berget-reasoning-options-wave3
[berget] Add reasoning options
2026-06-13 15:40:33 -05:00
Aiden Cline 33d88e41df Merge pull request #2203 from anomalyco/feat/the-grid-ai-reasoning-options-wave3
[the-grid-ai] Add reasoning options
2026-06-13 15:40:11 -05:00
Aiden Cline 300a46cfdc Merge pull request #2201 from anomalyco/feat/neuralwatt-reasoning-options-wave3
[neuralwatt] Add reasoning options
2026-06-13 15:36:53 -05:00
Aiden Cline 0e3c00595b [neuralwatt] Correct reasoning controls 2026-06-13 15:35:31 -05:00
Aiden Cline 1c9b748976 fix: remove GLM-5.2 from standard Z.AI APIs 2026-06-13 15:33:40 -05:00
Aiden Cline cf4ccf92ae Merge pull request #2285 from niushuai1991/add-glm-5.2-config
Add GLM-5.2 model config to zai and zhipuai providers
2026-06-13 15:31:44 -05:00
Aiden Cline a4a9d29c99 [berget] Correct remaining reasoning efforts 2026-06-13 15:30:02 -05:00
Aiden Cline 4670f99aac Merge pull request #2283 from anomalyco/fix/venice-sync-last-updated
fix(venice): preserve model update dates
2026-06-13 15:28:40 -05:00
Aiden Cline 3839c610a6 [berget] Remove unsupported GLM efforts 2026-06-13 15:28:06 -05:00
Aiden Cline b1095231a5 Merge pull request #2215 from anomalyco/feat/dinference-reasoning-options-wave3
[dinference] Mark reasoning controls fixed
2026-06-13 15:27:56 -05:00
Aiden Cline e8333b63a1 Merge pull request #2202 from anomalyco/feat/regolo-ai-reasoning-options-wave3
[regolo-ai] Add reasoning options
2026-06-13 15:27:32 -05:00
Aiden Cline 704ffc7371 Merge pull request #2229 from anomalyco/feat/anyapi-reasoning-options-wave4
[anyapi] Add reasoning options
2026-06-13 15:26:41 -05:00
Aiden Cline 4fdda4f262 [anyapi] Correct Claude reasoning options 2026-06-13 15:20:11 -05:00
Aiden Cline 41c243713f [berget] Correct Kimi reasoning option 2026-06-13 15:16:12 -05:00
Aiden Cline 36024f1bd2 Merge pull request #2218 from anomalyco/feat/gmicloud-reasoning-options-wave3
[gmicloud] Add reasoning options
2026-06-13 15:14:50 -05:00
Aiden Cline bfb0d3722a [gmicloud] Correct Claude reasoning options 2026-06-13 15:12:38 -05:00
Niu Shuai 3877dcf8b6 feat: add GLM-5.2 model config to zai and zhipuai providers 2026-06-14 04:10:00 +08:00
Aiden Cline d171755a90 Merge pull request #2220 from anomalyco/feat/azure-reasoning-options-wave3
[azure] Backfill DeepSeek V4 reasoning options
2026-06-13 14:39:42 -05:00
Aiden Cline 5394af4d63 Merge pull request #2189 from anomalyco/feat/upstage-reasoning-options-wave3
[upstage] Add reasoning options
2026-06-13 14:39:01 -05:00
Aiden Cline b78f6fb53e Merge pull request #2191 from anomalyco/feat/tencent-coding-plan-reasoning-options-wave3
[tencent-coding-plan] Add reasoning options
2026-06-13 14:36:46 -05:00
Aiden Cline 9e3c7d41ff Merge pull request #2200 from anomalyco/feat/modelscope-reasoning-options-wave3
[modelscope] Add reasoning options
2026-06-13 14:36:35 -05:00
Aiden Cline e8b1862dc2 Merge pull request #2195 from anomalyco/feat/minimax-cn-coding-plan-reasoning-options-wave3
[minimax-cn-coding-plan] Complete reasoning options
2026-06-13 14:36:20 -05:00
Aiden Cline 63da7583b5 Merge pull request #2188 from anomalyco/feat/moonshotai-reasoning-options-wave3
[moonshotai] Complete reasoning options
2026-06-13 14:36:03 -05:00
Aiden Cline e5b1221baa fix(venice): preserve model update dates 2026-06-13 14:31:04 -05:00
Aiden Cline 43e502a0bc Merge pull request #2282 from anomalyco/fix/mimo-reasoning-options-audit
fix MiMo reasoning options across providers
2026-06-13 14:16:58 -05:00
Aiden Cline b19a423f31 fix MiMo reasoning options across providers 2026-06-13 14:13:33 -05:00
Aiden Cline 77e04a5f1a Merge pull request #2184 from anomalyco/feat/nova-reasoning-options-wave3
[nova] Add reasoning options
2026-06-13 13:32:23 -05:00
Aiden Cline 2e1a8245c6 Merge pull request #2181 from anomalyco/feat/cloudferro-sherlock-reasoning-options-wave3
[cloudferro-sherlock] Add reasoning options
2026-06-13 13:32:14 -05:00
Aiden Cline b197346558 Merge pull request #2183 from anomalyco/feat/drun-reasoning-options-wave3
[drun] Add reasoning options
2026-06-13 13:32:03 -05:00
Aiden Cline a04024bd21 Merge pull request #2185 from anomalyco/feat/moark-reasoning-options-wave3
[moark] Add reasoning options
2026-06-13 13:31:53 -05:00
Aiden Cline 0186f9e638 Merge pull request #2187 from anomalyco/feat/poolside-reasoning-options-wave3
[poolside] Add reasoning options
2026-06-13 13:31:35 -05:00
Aiden Cline deb664d9c6 Merge pull request #2186 from anomalyco/feat/lucidquery-reasoning-options-wave3
[lucidquery] Add reasoning options
2026-06-13 13:31:26 -05:00
Aiden Cline 8ade756d9b Merge pull request #2182 from anomalyco/feat/inception-reasoning-options-wave3
[inception] Add reasoning options
2026-06-13 13:31:14 -05:00
Aiden Cline fc109cc2c2 Merge pull request #2221 from anomalyco/feat/xiaomi-token-plan-cn-reasoning-options-wave3
[xiaomi-token-plan] Add reasoning toggles
2026-06-13 13:30:47 -05:00
Aiden Cline 0427b955c6 Merge pull request #2222 from anomalyco/feat/ambient-reasoning-options-wave3
[ambient] Add reasoning options
2026-06-13 13:23:26 -05:00
Aiden Cline e1c887294a Merge pull request #2225 from anomalyco/feat/abacus-reasoning-options-wave4
[abacus] Add reasoning options
2026-06-13 13:23:10 -05:00
Aiden Cline 67cbb6e5f4 Merge pull request #2226 from anomalyco/feat/cloudflare-ai-gateway-reasoning-options-wave4
[cloudflare-ai-gateway] Add reasoning options
2026-06-13 13:18:42 -05:00
Aiden Cline 3f183e2962 Merge pull request #2227 from anomalyco/feat/chutes-reasoning-options-wave4
[chutes] Add reasoning options
2026-06-13 13:18:23 -05:00
Aiden Cline b2ada02538 Merge pull request #2238 from anomalyco/feat/digitalocean-reasoning-options-wave4
[digitalocean] Add reasoning options
2026-06-13 13:16:48 -05:00
Aiden Cline 6dcd5d65a0 Merge pull request #2244 from anomalyco/feat/huggingface-reasoning-options-wave4
[huggingface] Add reasoning options
2026-06-13 13:14:23 -05:00
Aiden Cline 9f2265f81f Merge pull request #2281 from anomalyco/automation/sync-models-openrouter
chore(sync): update OpenRouter model catalog
2026-06-13 13:13:02 -05:00
Aiden Cline b0e4f07b73 Merge pull request #2224 from anomalyco/feat/auriko-reasoning-options-wave4
[auriko] Add reasoning options
2026-06-13 13:12:39 -05:00
Aiden Cline 503b07ddfa Merge pull request #2219 from anomalyco/feat/mistral-reasoning-options-wave3
[mistral] Mark Magistral reasoning controls fixed
2026-06-13 13:11:11 -05:00
Aiden Cline d13507ee94 Merge pull request #2217 from anomalyco/feat/lilac-reasoning-options-wave3
[lilac] Add reasoning options
2026-06-13 13:10:58 -05:00
github-actions[bot] 1f391a1908 chore(sync): update OpenRouter model catalog 2026-06-13 17:46:55 +00:00
Aiden Cline f31519bf52 Merge pull request #2280 from CodeAnimal/az-deepseek-v4
Correct Azure DeepSeek V4 model prices
2026-06-13 11:25:26 -05:00
Aiden Cline d56e8387ba Merge pull request #2274 from anomalyco/automation/sync-models-openrouter
chore(sync): update OpenRouter model catalog
2026-06-13 11:25:15 -05:00
CodeAnimal 0132340a2c Correct Azure DeepSeek V4 model prices 2026-06-13 17:23:18 +01:00
Aiden Cline ead650e6b0 Merge pull request #2277 from ririnto/feat/zai-coding-plan-glm-5-2-anthropic
Add ZAI Coding Plan GLM-5.2 with Anthropic provider model
2026-06-13 11:19:37 -05:00
Aiden Cline c3beda0405 fix(zai-coding-plan): use default GLM-5.2 provider 2026-06-13 11:17:47 -05:00
Aiden Cline 814770c1c7 Merge dev and reuse Kimi K2.7 metadata 2026-06-13 11:09:49 -05:00
Aiden Cline e3d49ae6e2 Merge pull request #2279 from mathiasloh/feat_add_ollama_cloud_kimi_k27_code
feat(ollama-cloud): add kimi-k2.7-code
2026-06-13 11:07:44 -05:00
Aiden Cline fdabca87a0 Merge pull request #2275 from jubalm/add-zai-glm-5-2
Add ZAI Coding Plan GLM-5.2
2026-06-13 11:07:27 -05:00
github-actions[bot] acd9fa80ad chore(sync): update OpenRouter model catalog 2026-06-13 15:49:42 +00:00
mathias.loh 00c5b75ed9 feat(ollama-cloud): add kimi-k2.7-code 2026-06-13 22:42:54 +08:00
ririnto d210e45dd5 refactor(zai-coding-plan): split GLM-5.2 metadata into model + base_model reference
Move provider-agnostic facts (name, family, dates, capability flags,
limit, modalities) into models/zhipuai/glm-5.2.toml and reference it
via base_model in the provider TOML, which now keeps only provider-
specific fields (reasoning_options, interleaved, cost, per-model
anthropic [provider] override). Per README wrapper-provider guidance.
2026-06-13 22:39:29 +09:00
ririnto c9e026b5de feat(zai-coding-plan): add GLM-5.2 model metadata 2026-06-13 18:04:46 +09:00
Jubal Mabaquiao 3be537dad4 Add ZAI Coding Plan GLM-5.2 2026-06-13 16:45:57 +08:00
Aiden Cline 63a7bc11a9 Merge pull request #2216 from anomalyco/feat/inceptron-reasoning-options-wave3
[inceptron] Add reasoning options
2026-06-13 00:30:24 -05:00
Aiden Cline 0d2db5359d Merge pull request #2258 from anomalyco/feat/alibaba-coding-plan-cn-reasoning-options-final
[alibaba-coding-plan-cn] Add reasoning options
2026-06-13 00:27:45 -05:00
Aiden Cline a2d9f79f7e Merge pull request #2255 from anomalyco/feat/alibaba-coding-plan-reasoning-options-final
[alibaba-coding-plan] Add reasoning options
2026-06-13 00:27:30 -05:00
Aiden Cline e4d366cf4f Merge pull request #2256 from anomalyco/feat/evroc-reasoning-options-final
[evroc] Add reasoning options
2026-06-13 00:27:15 -05:00
Aiden Cline 9631b93843 Merge pull request #2260 from anomalyco/feat/alibaba-token-plan-cn-reasoning-options-final
feat(alibaba-token-plan-cn): add reasoning options
2026-06-13 00:27:01 -05:00
Aiden Cline 5424fbd2de Merge pull request #2270 from anomalyco/automation/sync-models-openrouter
chore(sync): update OpenRouter model catalog
2026-06-13 00:26:42 -05:00
Aiden Cline 73cbf85a43 Merge pull request #2272 from anomalyco/automation/sync-models-vercel
chore(sync): update Vercel AI Gateway model catalog
2026-06-13 00:26:27 -05:00
Aiden Cline 097afb7e31 Merge pull request #2273 from zainhas/dev
[Together AI] add minimax m3
2026-06-13 00:26:12 -05:00
Zain Hasan 2c5ebe8219 [Together AI] add minimax m3 2026-06-12 22:12:45 -07:00
Frank 3a7b0ba2dc update zen models 2026-06-13 01:00:30 -04:00
github-actions[bot] e6c0abd6a9 chore(sync): update Vercel AI Gateway model catalog 2026-06-13 03:26:15 +00:00
github-actions[bot] 5288464365 chore(sync): update OpenRouter model catalog 2026-06-13 03:26:13 +00:00
Aiden Cline 7900fcd5a6 Merge pull request #2271 from shzdehmd/dev
feat(fireworks-ai): adding Kimi K2.7 Code, Qwen 3.7 Plus, and Minimax M3; removing deprecated models
2026-06-12 21:51:13 -05:00
Ahmad Shahzad 2df2c13060 feat(fireworks-ai): add K2.7 Code variants, Qwen 3.7 Plus, Minimax M3; remove deprecated models
- Add Kimi K2.7 Code (accounts/fireworks/models/kimi-k2p7-code)

- Add Kimi K2.7 Code Fast (accounts/fireworks/routers/kimi-k2p7-code-fast)

- Add Qwen 3.7 Plus (accounts/fireworks/models/qwen3p7-plus)

- Add Minimax M3 (accounts/fireworks/models/minimax-m3)

- Remove deprecated Kimi K2.5, Minimax M2.5, and Qwen 3.6 Plus
2026-06-13 07:48:41 +05:00
Aiden Cline f846124b1f Merge pull request #2257 from anomalyco/feat/google-reasoning-options-final
[google] Complete reasoning options
2026-06-12 17:47:42 -05:00
Aiden Cline cc81c1843f Merge pull request #2259 from anomalyco/feat/freemodel-reasoning-options-final
[freemodel] Add reasoning options
2026-06-12 17:47:16 -05:00
Aiden Cline c7823958d4 [freemodel] Add Anthropic reasoning controls 2026-06-12 17:42:25 -05:00
Aiden Cline 0178741953 [freemodel] Add OpenAI reasoning efforts 2026-06-12 17:34:32 -05:00
Aiden Cline 75db7752f5 Merge pull request #2156 from anomalyco/automation/sync-models-openrouter
chore(sync): update OpenRouter model catalog
2026-06-12 17:31:09 -05:00
Aiden Cline 48d1bc2ee6 Merge pull request #2265 from jcraftsman/update-umans-ai-provider
Update Umans AI Coding Plan + add Umans AI (pay-per-token) provider
2026-06-12 17:30:09 -05:00
Aiden Cline d147b31d97 Merge pull request #2266 from anomalyco/automation/sync-models-vercel
chore(sync): update Vercel AI Gateway model catalog
2026-06-12 17:29:37 -05:00
github-actions[bot] b6fea3d470 chore(sync): update Vercel AI Gateway model catalog 2026-06-12 21:54:31 +00:00
github-actions[bot] d3fe5e3f4e chore(sync): update OpenRouter model catalog 2026-06-12 21:54:30 +00:00
Frank 1280fc51bc update go models 2026-06-12 16:24:50 -04:00
Aiden Cline 0e6590cc7a Merge pull request #2269 from anomalyco/fix/kimi-family-sync
fix(sync): normalize Kimi model families
2026-06-12 14:13:38 -05:00
Aiden Cline 78cb28fe8e fix(sync): normalize Kimi model families 2026-06-12 13:50:14 -05:00
Aiden Cline fcd71901fc Merge pull request #2267 from anomalyco/automation/sync-models-cloudflare-workers-ai
chore(sync): update Cloudflare Workers AI model catalog
2026-06-12 13:40:14 -05:00
github-actions[bot] 5ffe02911a chore(sync): update Cloudflare Workers AI model catalog 2026-06-12 18:04:11 +00:00
Aiden Cline add04f88a2 Merge pull request #2268 from leszek3737/zenmux/k2.7
Add Kimi K2.7 Code and version free model configuration
2026-06-12 12:32:38 -05:00
wassel alazhar 9fdad9f497 Add temperature = false for Kimi and Flash models (locked by Umans) 2026-06-12 19:28:31 +02:00
Leszek 1545b64010 [zenmux] Add Kimi K2.7 Code (Free) model configuration 2026-06-12 19:26:12 +02:00
Adrian Rogala 0382da663b Merge branch 'anomalyco:dev' into zenmux/k2.7 2026-06-12 19:22:21 +02:00
Leszek 0a933025aa [zenmux] Add kimi-k2.7-code model configuration 2026-06-12 19:20:59 +02:00
wassel alazhar 735e5f7f08 Remove umans-flash-beta from Coding Plan (deprecated, sunset 2026-06-07) 2026-06-12 19:16:05 +02:00
wassel alazhar a414765865 Update Umans AI Coding Plan and add Umans AI (pay-per-token) provider
Umans AI Coding Plan (subscription):
- Add umans-kimi-k2.7 (Kimi K2.7 Code) model
- Add umans-flash-beta (deprecated alias for umans-flash)
- Fix umans-glm-5.1: add vision modality (via handoff) and interleaved reasoning
- Fix umans-flash: add interleaved reasoning field
- Fix umans-qwen3.6-35b-a3b: add interleaved reasoning field
- Add reasoning_options to all models
- Add explicit name field to models using base_model

Umans AI (new provider - pay-per-token for orgs):
- New provider for organization service-account usage
- Per-token pricing from the org billing page:
  - Kimi K2.6: /bin/bash.95/.00 (input/output), /bin/bash.20 cache read
  - Kimi K2.7 Code: /bin/bash.95/.00, /bin/bash.19 cache read
  - GLM 5.1: .40/.40, /bin/bash.29 cache read
  - Umans Flash (Qwen3.6-35B-A3B): /bin/bash.15/.00, /bin/bash.05 cache read
  - Umans Coder: routes to Kimi K2.6 rates
- Same endpoint (api.code.umans.ai), different billing model
2026-06-12 19:08:15 +02:00
Aiden Cline 32f2c6de2a Merge pull request #2263 from anomalyco/feat/kimi-k2.7-code
feat(models): add Kimi K2.7 Code
2026-06-12 11:36:40 -05:00
Aiden Cline bd6fc4b145 feat(models): add Kimi K2.7 Code 2026-06-12 11:35:17 -05:00
Aiden Cline a0957ebea8 Merge pull request #2237 from anomalyco/feat/crof-reasoning-options-wave4
[crof] Add reasoning options
2026-06-12 11:17:12 -05:00
Aiden Cline 8b50fa5029 [crof] Add DeepSeek V4 reasoning efforts 2026-06-12 11:01:44 -05:00
Aiden Cline d6f87b6e64 Merge pull request #2233 from anomalyco/feat/gitlab-reasoning-options-wave4
[gitlab] Add reasoning options
2026-06-12 10:51:47 -05:00
Aiden Cline a66ef9ca19 Merge pull request #2209 from anomalyco/feat/meganova-reasoning-options-wave3
[meganova] Add reasoning options
2026-06-12 10:30:41 -05:00
Aiden Cline a48f0722e8 Merge pull request #2240 from anomalyco/feat/fastrouter-reasoning-options-wave4
[fastrouter] Add reasoning options
2026-06-12 10:28:15 -05:00
Aiden Cline aed6a48d73 Merge pull request #2241 from anomalyco/feat/neon-reasoning-options-wave4
[neon] Add reasoning options
2026-06-12 10:27:49 -05:00
Aiden Cline 1b24a035da Merge pull request #2245 from anomalyco/feat/helicone-reasoning-options-wave4
[helicone] Add reasoning options
2026-06-12 10:27:20 -05:00
Aiden Cline 560dceadf3 Merge pull request #2261 from anomalyco/feat/alibaba-token-plan-reasoning-options-final
[alibaba-token-plan] Add reasoning options
2026-06-12 10:26:40 -05:00
Aiden Cline f3607ba954 Merge pull request #2262 from anomalyco/feat/lmstudio-reasoning-options-final
[lmstudio] Add GPT-OSS reasoning options
2026-06-12 10:26:18 -05:00
Aiden Cline 6b90987895 Merge pull request #2248 from anomalyco/automation/sync-models-xai
chore(sync): update xAI model catalog
2026-06-12 10:26:05 -05:00
github-actions[bot] ec6b7af421 chore(sync): update xAI model catalog 2026-06-12 15:25:05 +00:00
Aiden Cline 25c2cf9224 [lmstudio] Add GPT-OSS reasoning options 2026-06-12 10:22:51 -05:00
Aiden Cline a4cdec5316 [alibaba-token-plan] Add reasoning options 2026-06-12 10:21:30 -05:00
Aiden Cline 90f36e0550 [freemodel] Add reasoning options 2026-06-12 10:21:27 -05:00
Aiden Cline f15aad08ef feat(alibaba-token-plan-cn): add reasoning options 2026-06-12 10:21:26 -05:00
Aiden Cline 063429a4ae [digitalocean] Cover remaining reasoning options 2026-06-12 10:20:56 -05:00
Aiden Cline b21c08dc44 [alibaba-coding-plan-cn] Add reasoning options 2026-06-12 10:20:42 -05:00
Aiden Cline 592da7f45c [google] Complete reasoning options 2026-06-12 10:20:36 -05:00
Aiden Cline 717892fd72 [evroc] Add reasoning options 2026-06-12 10:20:26 -05:00
Aiden Cline deef87451d [alibaba-coding-plan] Add reasoning options 2026-06-12 10:20:23 -05:00
Aiden Cline cd3c1f22f7 Merge remote-tracking branch 'origin/dev' into feat/digitalocean-reasoning-options-wave4 2026-06-12 10:19:56 -05:00
Aiden Cline 3f9980168e Merge pull request #2251 from houtanb/dev
Fix release dates
2026-06-12 09:51:58 -05:00
Jack 6f900fa761 Merge pull request #2180 from anomalyco/fix/opencode-go-minimax-m3-pricing
fix(opencode-go): update MiniMax M3 pricing
2026-06-12 21:09:49 +08:00
Houtan Bastani 61a153e6bb Update Mistral Large 2411 release date
Set mistral-large-2411 release_date and last_updated  metadata to 2024-11-18.

Evidence:

https://github.com/mistralai/platform-docs-public/blob/main/src/schema/models/models/mistral-large-2-1-24-11.ts#L9
2026-06-12 11:35:43 +02:00
Houtan Bastani 5a8f9d44d5 Update Gemini 2.5 Flash and Gemini 2.5 Pro release dates
Set Gemini 2.5 Flash and Gemini 2.5 Pro release_date and last_updated metadata to 2025-06-17.

Evidence:

https://ai.google.dev/gemini-api/docs/deprecations#gemini-2.5-flash-models

https://ai.google.dev/gemini-api/docs/deprecations#gemini-2.5-pro-models
2026-06-12 11:35:33 +02:00
Aiden Cline 629ce9b9f7 Merge pull request #2243 from anomalyco/feat/opencode-go-reasoning-options-wave4
[opencode-go] Add reasoning options
2026-06-12 00:07:39 -05:00
Aiden Cline 074022b5ad [huggingface] Correct fixed reasoning controls 2026-06-11 23:58:31 -05:00
Aiden Cline c562522e4f [opencode-go] Normalize DeepSeek V4 efforts 2026-06-11 23:57:47 -05:00
Aiden Cline dd051fd682 [helicone] Add reasoning options 2026-06-11 23:56:41 -05:00
Aiden Cline 074a288d15 [huggingface] Add reasoning options 2026-06-11 23:56:40 -05:00
Aiden Cline 2d0173d177 [opencode-go] Add reasoning options 2026-06-11 23:56:33 -05:00
Aiden Cline df75f7c438 [neon] Add reasoning options 2026-06-11 23:56:10 -05:00
Aiden Cline ffe754d81c [fastrouter] Add reasoning options 2026-06-11 23:56:04 -05:00
Aiden Cline c67d3e84ff [digitalocean] Add reasoning options 2026-06-11 23:55:32 -05:00
Aiden Cline 2f5d53cdf3 [crof] Add reasoning options 2026-06-11 23:54:59 -05:00
Aiden Cline 08b5fd9061 [gitlab] Add reasoning options 2026-06-11 23:54:10 -05:00
Aiden Cline 5aeaaa8d47 [anyapi] Add reasoning options 2026-06-11 23:52:40 -05:00
Aiden Cline 12280f413b [chutes] Add reasoning options 2026-06-11 23:52:31 -05:00
Aiden Cline 1a772fd297 Merge pull request #2223 from anomalyco/feat/google-vertex-reasoning-options-wave3
[google-vertex] Add MaaS reasoning options
2026-06-11 23:52:15 -05:00
Aiden Cline 38c708714f [cloudflare-ai-gateway] Add reasoning options 2026-06-11 23:52:04 -05:00
Aiden Cline 13abc41ac9 [abacus] Add reasoning options 2026-06-11 23:51:42 -05:00
Aiden Cline cf6a5e104d [auriko] Add reasoning options 2026-06-11 23:51:41 -05:00
Aiden Cline 128e0fbd8a [ambient] Add reasoning options 2026-06-11 23:50:16 -05:00
Aiden Cline c63920050a [google-vertex] Add MaaS reasoning options 2026-06-11 23:50:13 -05:00
Aiden Cline 24d2a74f4d [xiaomi-token-plan] Add reasoning toggles 2026-06-11 23:50:05 -05:00
Aiden Cline e62b47a005 [azure] Backfill DeepSeek V4 reasoning options 2026-06-11 23:49:52 -05:00
Aiden Cline eac6d1aaed [mistral] Mark Magistral reasoning controls fixed 2026-06-11 23:49:47 -05:00
Aiden Cline a914876008 [gmicloud] Add reasoning options 2026-06-11 23:49:46 -05:00
Aiden Cline 794203e12c [lilac] Add reasoning options 2026-06-11 23:49:45 -05:00
Aiden Cline 2624678dbe [dinference] Mark reasoning controls fixed 2026-06-11 23:49:42 -05:00
Aiden Cline 2d18ebb301 [inceptron] Mark reasoning controls fixed 2026-06-11 23:49:40 -05:00
Aiden Cline df45483742 Merge pull request #2211 from anomalyco/feat/wafer.ai-reasoning-options-wave3
[wafer.ai] Add reasoning options
2026-06-11 23:49:22 -05:00
Aiden Cline 4ecdcb8f2b Merge pull request #2196 from anomalyco/feat/hpc-ai-reasoning-options-wave3
[hpc-ai] Add reasoning options
2026-06-11 23:48:29 -05:00
Aiden Cline 4644def1ae [hpc-ai] Remove unsupported reasoning efforts 2026-06-11 23:45:03 -05:00
Aiden Cline f9091af5ee Merge pull request #2198 from anomalyco/feat/mixlayer-reasoning-options-wave3
[mixlayer] Add reasoning options
2026-06-11 23:41:20 -05:00
Aiden Cline 7022a48bfc Merge pull request #2205 from anomalyco/feat/vultr-reasoning-options-wave3
[vultr] Add reasoning options
2026-06-11 23:40:45 -05:00
Aiden Cline dda69225d8 Merge pull request #2190 from anomalyco/feat/perplexity-reasoning-options-wave3
[perplexity] Add reasoning options
2026-06-11 23:38:49 -05:00
Aiden Cline 2e020b1dd2 Merge pull request #2194 from anomalyco/feat/minimax-coding-plan-reasoning-options-wave3
[minimax-coding-plan] Complete reasoning options
2026-06-11 23:38:32 -05:00
Aiden Cline 67252bda30 Merge pull request #2197 from anomalyco/feat/submodel-reasoning-options-wave3
[submodel] Add reasoning options
2026-06-11 23:38:20 -05:00
Aiden Cline ac1566f622 Merge pull request #2193 from anomalyco/feat/minimax-reasoning-options-wave3
[minimax] Complete reasoning options
2026-06-11 23:38:02 -05:00
Aiden Cline 48837609aa Merge pull request #2199 from anomalyco/feat/v0-reasoning-options-wave3
[v0] Add reasoning options
2026-06-11 23:37:49 -05:00
Aiden Cline c2a0ff023a Merge pull request #2138 from martinmose/add-zeldoc-provider
feat(provider): add zeldoc provider
2026-06-11 23:28:07 -05:00
Aiden Cline 282821e7b6 Merge pull request #2208 from anomalyco/feat/qihang-ai-reasoning-options-wave3
[qihang-ai] Add reasoning options
2026-06-11 23:25:07 -05:00
Aiden Cline 1b8e53bcbd Merge pull request #2192 from anomalyco/feat/minimax-cn-reasoning-options-wave3
[minimax-cn] Complete reasoning options
2026-06-11 23:14:09 -05:00
Aiden Cline f671147f71 Merge pull request #2207 from anomalyco/feat/scaleway-reasoning-options-wave3
[scaleway] Add reasoning options
2026-06-11 23:13:54 -05:00
Aiden Cline e23e759601 Merge pull request #2204 from anomalyco/feat/clarifai-reasoning-options-wave3
[clarifai] Add reasoning options
2026-06-11 23:13:40 -05:00
Aiden Cline 4b4546f3e3 Merge pull request #2213 from anomalyco/feat/friendli-reasoning-options-wave3
[friendli] Add reasoning options
2026-06-11 23:13:24 -05:00
Aiden Cline 040f0ca995 [wafer.ai] Add DeepSeek V4 effort controls 2026-06-11 23:12:29 -05:00
Aiden Cline 9acac34889 [friendli] Remove unsupported reasoning efforts 2026-06-11 23:11:37 -05:00
Aiden Cline 78ad91f773 Merge pull request #2212 from anomalyco/feat/iflowcn-reasoning-options-wave3
[iflowcn] Add reasoning options
2026-06-11 23:10:34 -05:00
Aiden Cline 4b0aeef538 Merge pull request #2214 from anomalyco/feat/io-net-reasoning-options-wave3
[io-net] Add reasoning options
2026-06-11 23:09:58 -05:00
Aiden Cline 856787cb84 [friendli] Add reasoning options 2026-06-11 23:08:36 -05:00
Aiden Cline 084f0bb4ba [iflowcn] Add reasoning options 2026-06-11 23:08:36 -05:00
Aiden Cline ee1301fb63 [io-net] Add reasoning options 2026-06-11 23:08:36 -05:00
Aiden Cline 502957b778 [wafer.ai] Add reasoning options 2026-06-11 23:08:29 -05:00
Aiden Cline 3fba77ee56 [the-grid-ai] Add reasoning options 2026-06-11 23:07:50 -05:00
Aiden Cline 0a6286e468 [regolo-ai] Add reasoning options 2026-06-11 23:07:50 -05:00
Aiden Cline 8af96ce933 [berget] Add reasoning options 2026-06-11 23:07:50 -05:00
Aiden Cline 4a056bd1ef [meganova] Add reasoning options 2026-06-11 23:07:50 -05:00
Aiden Cline 9f11a93d06 [vultr] Add reasoning options 2026-06-11 23:07:50 -05:00
Aiden Cline be8d8a2ec2 [qihang-ai] Add reasoning options 2026-06-11 23:07:50 -05:00
Aiden Cline d4193dbad6 [scaleway] Add reasoning options 2026-06-11 23:07:50 -05:00
Aiden Cline fb6b0985ce [clarifai] Add reasoning options 2026-06-11 23:07:50 -05:00
Aiden Cline 506ca0f7c3 [neuralwatt] Add reasoning options 2026-06-11 23:07:49 -05:00
Aiden Cline 4cafdb31ff [tencent-coding-plan] Add reasoning options 2026-06-11 23:07:20 -05:00
Aiden Cline d97aedf7a1 [modelscope] Add reasoning options 2026-06-11 23:07:20 -05:00
Aiden Cline 404bba4d1f [minimax-cn-coding-plan] Add reasoning options 2026-06-11 23:07:20 -05:00
Aiden Cline 2bb4fe287e [hpc-ai] Add reasoning options 2026-06-11 23:07:20 -05:00
Aiden Cline b58c396106 [mixlayer] Add reasoning options 2026-06-11 23:07:20 -05:00
Aiden Cline 575f078887 [minimax-coding-plan] Add reasoning options 2026-06-11 23:07:20 -05:00
Aiden Cline acf194ec01 [submodel] Add reasoning options 2026-06-11 23:07:20 -05:00
Aiden Cline c80ff1ad2c [minimax] Add reasoning options 2026-06-11 23:07:20 -05:00
Aiden Cline a41f6f5913 [v0] Add reasoning options 2026-06-11 23:07:20 -05:00
Aiden Cline 8dffe03a9c [minimax-cn] Add reasoning options 2026-06-11 23:07:20 -05:00
Aiden Cline 9ea761af1a [perplexity] Add reasoning options 2026-06-11 23:07:07 -05:00
Aiden Cline c10ba76860 [upstage] Add reasoning options 2026-06-11 23:06:33 -05:00
Aiden Cline 30a019056f [moonshotai] Add reasoning options 2026-06-11 23:06:33 -05:00
Aiden Cline d7c4b11163 [nova] Add reasoning options 2026-06-11 23:06:33 -05:00
Aiden Cline 1018ddf139 [cloudferro-sherlock] Add reasoning options 2026-06-11 23:06:33 -05:00
Aiden Cline a5e572bcf6 [drun] Add reasoning options 2026-06-11 23:06:33 -05:00
Aiden Cline 2d52062693 [moark] Add reasoning options 2026-06-11 23:06:33 -05:00
Aiden Cline 6f3b739418 [poolside] Add reasoning options 2026-06-11 23:06:33 -05:00
Aiden Cline f52cc7e895 [lucidquery] Add reasoning options 2026-06-11 23:06:33 -05:00
Aiden Cline 473d12c44b [inception] Add reasoning options 2026-06-11 23:06:33 -05:00
Jack 9401952857 chore(opencode-go): preserve MiniMax M3 file ending 2026-06-12 12:01:40 +08:00
Jack 623f5e8ea4 fix(opencode-go): update MiniMax M3 pricing 2026-06-12 11:59:03 +08:00
Aiden Cline 526b4cd543 Merge pull request #2179 from anomalyco/feat/deepseek-reasoning-options-wave2
[deepseek] Complete reasoning options
2026-06-11 22:55:29 -05:00
Aiden Cline b7d165296c Merge pull request #2172 from anomalyco/feat/privatemode-ai-reasoning-options
[privatemode-ai] Add reasoning options
2026-06-11 22:55:21 -05:00
Aiden Cline 655f757925 Merge pull request #2177 from anomalyco/feat/llmtr-reasoning-options
[llmtr] Complete reasoning options
2026-06-11 22:55:07 -05:00
Aiden Cline cce129dfd9 Merge pull request #2173 from anomalyco/feat/zai-coding-plan-reasoning-options
[zai-coding-plan] Complete reasoning options
2026-06-11 22:54:57 -05:00
Aiden Cline 548f3b5869 Merge pull request #2175 from anomalyco/feat/zhipuai-coding-plan-reasoning-options
[zhipuai-coding-plan] Complete reasoning options
2026-06-11 22:54:51 -05:00
Aiden Cline f349a9dde6 Merge pull request #2176 from anomalyco/feat/kuae-cloud-reasoning-options
[kuae-cloud-coding-plan] Add reasoning options
2026-06-11 22:54:34 -05:00
Aiden Cline 05c1041160 [deepseek] Mark reasoner controls fixed 2026-06-11 22:54:19 -05:00
Aiden Cline 215c3dfbc8 Merge pull request #2174 from anomalyco/feat/kimi-for-coding-reasoning-options
[kimi-for-coding] Complete reasoning options
2026-06-11 22:54:16 -05:00
Aiden Cline ddc6ad75a2 Merge pull request #2178 from anomalyco/feat/firepass-reasoning-options
[firepass] Add reasoning options
2026-06-11 22:54:05 -05:00
Aiden Cline 757bee7de8 Merge pull request #2167 from anomalyco/feat/claudinio-reasoning-options
[claudinio] Add reasoning options
2026-06-11 22:53:39 -05:00
Aiden Cline 5ee32a47ae Merge pull request #2170 from anomalyco/feat/bailing-reasoning-options
[bailing] Add reasoning options
2026-06-11 22:53:30 -05:00
Aiden Cline 2c22f4b488 [privatemode-ai] Add reasoning options 2026-06-11 22:51:42 -05:00
Aiden Cline 097296f6c6 [llmtr] Add reasoning options 2026-06-11 22:51:42 -05:00
Aiden Cline 2559ed64c5 [zai-coding-plan] Add reasoning options 2026-06-11 22:51:42 -05:00
Aiden Cline c56ac404d3 [zhipuai-coding-plan] Add reasoning options 2026-06-11 22:51:42 -05:00
Aiden Cline 4681e30afb [kuae-cloud-coding-plan] Add reasoning options 2026-06-11 22:51:42 -05:00
Aiden Cline 94cd023a88 [kimi-for-coding] Add reasoning options 2026-06-11 22:51:42 -05:00
Aiden Cline b5c33b6347 [deepseek] Add reasoning options 2026-06-11 22:51:41 -05:00
Aiden Cline 2014d883e4 [firepass] Add reasoning options 2026-06-11 22:51:41 -05:00
Aiden Cline 2f749b7cf9 [claudinio] Add reasoning options 2026-06-11 22:51:31 -05:00
Aiden Cline d7ab976e3c [bailing] Add reasoning options 2026-06-11 22:51:31 -05:00
Aiden Cline 32066b7856 Merge pull request #2131 from anomalyco/feat/ovhcloud-reasoning-audit
feat(ovhcloud): add reasoning options
2026-06-11 22:42:30 -05:00
Aiden Cline 3ded2fae72 Merge pull request #2130 from anomalyco/audit/nebius-models
[nebius] Audit reasoning controls
2026-06-11 22:38:33 -05:00
Aiden Cline 9771180f83 [nebius] Correct reasoning controls 2026-06-11 22:31:54 -05:00
Aiden Cline fa65113f37 Merge pull request #2162 from mikeyp/chore/update-digitalocean-models
Add anthropic-claude-fable-5 and nemotron-3-ultra-550b to DigitalOcean
2026-06-11 22:19:22 -05:00
Aiden Cline 1ab5784118 Merge pull request #2161 from andrelandgraf/feat/add-neon-provider
Add Neon provider
2026-06-11 22:17:07 -05:00
Mike Prasuhn 411bc157e6 Add anthropic-claude-fable-5 and nemotron-3-ultra-550b to DigitalOcean 2026-06-11 23:09:08 -04:00
Andre Landgraf 58ab76b8f3 Add Neon provider
Neon serves the same Databricks-backed model catalog through its
branch-scoped AI Gateway via an OpenAI-compatible endpoint, so this mirrors
the `databricks` provider's models.

- `api` uses the branch-scoped `NEON_AI_GATEWAY_BASE_URL` + the unified MLflow
  OpenAI-compatible route; `NEON_AI_GATEWAY_TOKEN` is the bearer key. Both are
  emitted by `neonctl env pull`.
- Model ids drop the `databricks-` prefix (the gateway accepts the bare ids),
  so models resolve as `neon/claude-haiku-4-5`, `neon/gpt-5-nano`, etc.
2026-06-11 19:52:37 -07:00
Martin Mose Facondini 8f2607fcdb fix(zeldoc): make logo black 2026-06-12 00:12:49 +02:00
Martin Mose Facondini 23e07a27d2 fix(zeldoc): correct z-code model fields 2026-06-12 00:12:44 +02:00
Aiden Cline 37e8e0cf95 Merge pull request #2086 from anomalyco/feat/openrouter-reasoning-options
feat(openrouter): add reasoning options
2026-06-11 16:21:15 -05:00
Aiden Cline 0e0fe311ab Merge dev into feat/openrouter-reasoning-options 2026-06-11 16:14:33 -05:00
Aiden Cline 3d763d081e fix(openrouter): document Claude effort mapping 2026-06-11 16:14:03 -05:00
Aiden Cline ebbd3416e2 Merge pull request #2154 from anomalyco/automation/sync-models-openrouter
chore(sync): update OpenRouter model catalog
2026-06-11 16:07:40 -05:00
Aiden Cline a3509f9a3d Merge pull request #2155 from anomalyco/automation/sync-models-vercel
chore(sync): update Vercel AI Gateway model catalog
2026-06-11 16:07:24 -05:00
github-actions[bot] 71d00e7dfc chore(sync): update Vercel AI Gateway model catalog 2026-06-11 21:06:24 +00:00
github-actions[bot] 26f7b6f6b6 chore(sync): update OpenRouter model catalog 2026-06-11 21:06:21 +00:00
Aiden Cline 270009bd93 fix(openrouter): correct reasoning controls 2026-06-11 15:03:25 -05:00
Aiden Cline 91cc389af3 fix(openrouter): correct Claude reasoning controls 2026-06-11 14:57:34 -05:00
Aiden Cline 1c7b7e8247 Merge dev into feat/openrouter-reasoning-options 2026-06-11 14:27:05 -05:00
Aiden Cline a382026ce9 Merge pull request #2153 from anomalyco/automation/sync-models-vercel
chore(sync): update Vercel AI Gateway model catalog
2026-06-11 14:21:25 -05:00
github-actions[bot] 1fc7261c14 chore(sync): update Vercel AI Gateway model catalog 2026-06-11 19:15:03 +00:00
Aiden Cline 765dae9f61 Merge pull request #2134 from anomalyco/audit/deepinfra-reasoning
fix(deepinfra): reconcile reasoning controls
2026-06-11 13:02:22 -05:00
Aiden Cline 02cd80a2ab Merge pull request #2032 from anthraxx/alibaba-qwen3.7-plus
add Qwen3.7 Plus model configuration to Alibana coding plan
2026-06-11 12:57:58 -05:00
Aiden Cline fcbd02fa84 Merge pull request #2148 from anomalyco/automation/sync-models-venice
chore(sync): update Venice model catalog
2026-06-11 12:56:57 -05:00
Aiden Cline e07a0bab97 Merge pull request #2132 from anomalyco/chore/fireworks-reasoning
fix(fireworks-ai): reconcile reasoning controls
2026-06-11 12:55:12 -05:00
Aiden Cline ad166f7448 fix(fireworks-ai): verify reasoning toggles 2026-06-11 12:33:12 -05:00
github-actions[bot] 660350c5fa chore(sync): update Venice model catalog 2026-06-11 17:29:06 +00:00
Aiden Cline 54d94bdc79 fix(deepinfra): restore Kimi K2.5 toggle 2026-06-11 12:28:40 -05:00
Aiden Cline 912ee1fe86 fix(deepinfra): restore V4 effort enum 2026-06-11 12:23:47 -05:00
Aiden Cline 9379be8911 Merge pull request #2151 from anomalyco/fix/togetherai-required-reasoning-options
[togetherai] Require reasoning options metadata
2026-06-11 12:21:18 -05:00
Aiden Cline 1ccb247f7f [togetherai] Require reasoning options metadata 2026-06-11 12:05:22 -05:00
Aiden Cline 7d5469898d [nebius] Complete reasoning option coverage 2026-06-11 12:04:48 -05:00
Aiden Cline ec3c4ed8ea fix(fireworks-ai): mark unresolved reasoning controls 2026-06-11 12:04:47 -05:00
Aiden Cline 2b42408582 fix(deepinfra): mark unresolved reasoning controls 2026-06-11 12:04:46 -05:00
Aiden Cline 8521822a96 Merge pull request #2135 from anomalyco/audit/togetherai-reasoning-20260610
Audit Together AI models and reasoning controls
2026-06-11 12:01:15 -05:00
Aiden Cline 6b62d03ac0 chore(deepinfra): remove provider test 2026-06-11 12:00:46 -05:00
Aiden Cline 9df50e0ccc chore(ovhcloud): remove test changes 2026-06-11 12:00:37 -05:00
Aiden Cline 9b3d25aae8 [nebius] Remove provider matrix test 2026-06-11 12:00:36 -05:00
Aiden Cline ea4d10b219 chore(fireworks-ai): remove catalog test 2026-06-11 12:00:36 -05:00
Aiden Cline d3d163dd95 Remove Together provider matrix test 2026-06-11 12:00:35 -05:00
Aiden Cline 78f8fb92fc Merge pull request #2129 from anomalyco/audit/cerebras-models-20260610
[cerebras] Refresh public model catalog
2026-06-11 12:00:23 -05:00
Aiden Cline 62b4296b3d Delete packages/core/test/cerebras.test.ts 2026-06-11 12:00:10 -05:00
Aiden Cline 12057804f5 Merge pull request #2143 from Nindaleth/feature/ghcp-fable
feat(github-copilot): add Claude Fable 5 model
2026-06-11 11:48:42 -05:00
Aiden Cline 127290ebec Merge pull request #2142 from anomalyco/automation/sync-models-openrouter
chore(sync): update OpenRouter model catalog
2026-06-11 11:45:55 -05:00
Aiden Cline 5abbfce7d6 Merge pull request #2120 from davidfierro/feat/snowflake-cortex-models
feat(snowflake-cortex): add missing but officially supported models
2026-06-11 11:45:36 -05:00
Aiden Cline 6ff6ab4028 Merge pull request #2145 from Omee11/feat/token-plan-cn
feat(alibaba-token-plan-cn): add Alibaba Token Plan (China) provider
2026-06-11 11:36:16 -05:00
Aiden Cline 0f3e0d7337 Merge pull request #2146 from Omee11/feat/token-plan-qwen3.7-plus
feat(alibaba-token-plan): add qwen3.7-plus
2026-06-11 10:51:52 -05:00
github-actions[bot] 8381089b11 chore(sync): update OpenRouter model catalog 2026-06-11 15:28:27 +00:00
Oliver Mee 98bed4baf6 feat(alibaba-token-plan-cn): add Alibaba Token Plan (China) provider 2026-06-11 18:14:20 +08:00
Oliver Mee e55ab2daf8 feat(alibaba-token-plan): add qwen3.7-plus 2026-06-11 18:14:20 +08:00
Radek Liska c60784fab5 feat(github-copilot): add Claude Fable 5 model 2026-06-11 09:15:02 +02:00
Aiden Cline 21581d8f4c test(sync): cover factored reasoning overrides 2026-06-10 23:20:55 -05:00
Aiden Cline 20bfe37a53 fix(sync): resolve changed canonical base 2026-06-10 23:19:32 -05:00
Aiden Cline fc4a781c2f fix(ovhcloud): complete reasoning controls 2026-06-10 23:16:08 -05:00
Aiden Cline 28674e1af4 [cerebras] Assert complete resolved models 2026-06-10 23:16:01 -05:00
Aiden Cline 1e76995f8e Test resolved Together provider matrix 2026-06-10 23:15:34 -05:00
Aiden Cline 0e371b761d fix(sync): resolve reasoning before preservation 2026-06-10 23:14:13 -05:00
Aiden Cline 7a5bf4f56e [cerebras] Test resolved model matrix 2026-06-10 23:13:39 -05:00
Aiden Cline 4c5b17b1db [nebius] Test generated provider matrix 2026-06-10 23:13:35 -05:00
Aiden Cline c4650219c3 fix(sync): drop stale reasoning options 2026-06-10 23:13:06 -05:00
Aiden Cline 9fb0474d1c feat(ovhcloud): add reasoning options 2026-06-10 23:13:06 -05:00
Aiden Cline 8807bb0069 Correct Together reasoning and pricing metadata 2026-06-10 23:12:12 -05:00
Aiden Cline 56426cc834 fix(deepinfra): preserve cache pricing 2026-06-10 23:11:28 -05:00
Aiden Cline 18c35709c5 Merge pull request #2139 from anomalyco/fix/venice-sync-models
Venice: fix synced model metadata
2026-06-10 20:14:38 -05:00
Aiden Cline b618a32341 fix(deepinfra): verify R1 reasoning controls 2026-06-10 20:13:26 -05:00
Aiden Cline f8229eba2e fix(deepinfra): narrow reasoning controls 2026-06-10 20:07:25 -05:00
Aiden Cline 6799ff1078 [nebius] Correct verified reasoning controls 2026-06-10 20:02:58 -05:00
Aiden Cline 236ff0e39b fix(fireworks-ai): add Qwen reasoning budget 2026-06-10 20:02:44 -05:00
Aiden Cline cb4fd81c59 Correct Together Qwen reasoning metadata 2026-06-10 19:51:01 -05:00
Aiden Cline 79e47be952 fix(deepinfra): use model-specific reasoning controls 2026-06-10 19:50:58 -05:00
Aiden Cline 03c161f038 [cerebras] Correct GLM reasoning option 2026-06-10 19:50:19 -05:00
Aiden Cline 38a2f09999 [nebius] Reconcile model lifecycle evidence 2026-06-10 19:49:42 -05:00
Aiden Cline 1f77766834 fix(fireworks-ai): remove unverified toggles 2026-06-10 19:48:27 -05:00
Aiden Cline da1032a1cb [venice] Fix synced model metadata 2026-06-10 19:46:52 -05:00
Aiden Cline 55848d41c6 Merge pull request #2123 from BlockListed/cortecs-add-claude-opus-4-8
add claude opus 4.8 to cortecs
2026-06-10 19:36:26 -05:00
BlockListed e8304a0b0f add claude opus 4.8 to cortecs 2026-06-10 23:48:02 +02:00
Martin Mose Facondini 23b4754d23 rename agentic-coding model to z-code 2026-06-10 23:06:51 +02:00
Martin Mose Facondini 20ffc3909f add zeldoc provider with agentic-coding model 2026-06-10 23:06:21 +02:00
Aiden Cline 09c7f864f2 Audit Together AI model catalog and reasoning 2026-06-10 16:05:11 -05:00
Aiden Cline c71d0c8065 fix(deepinfra): reconcile reasoning controls 2026-06-10 16:05:01 -05:00
Aiden Cline 5a3e0cacea test(fireworks-ai): lock reasoning controls 2026-06-10 16:04:34 -05:00
Aiden Cline f8ccb57731 [nebius] Audit reasoning controls 2026-06-10 16:04:09 -05:00
Aiden Cline c0b03ed655 [cerebras] Refresh public model catalog 2026-06-10 16:03:52 -05:00
Aiden Cline 63feee7eca Merge pull request #2128 from anomalyco/chore/close-stale-pull-requests
Automate stale pull request cleanup
2026-06-10 15:55:45 -05:00
Aiden Cline 233d636579 Merge pull request #2118 from dpuyosa/feat/venice-base-model
Venice: Update generation script to use base_model and reasoning_options
2026-06-10 15:55:01 -05:00
Aiden Cline 337d50d90f Automate stale pull request cleanup 2026-06-10 15:54:40 -05:00
Aiden Cline dfb3f2a421 Merge pull request #2062 from knowhycodata/add-llmtr-provider
feat: add LLMTR provider
2026-06-10 15:53:35 -05:00
Aiden Cline a87f44dc06 [venice] Remove stale generated metadata 2026-06-10 14:59:51 -05:00
Aiden Cline 19cb771778 [venice] Generate metadata for new models 2026-06-10 14:40:06 -05:00
Aiden Cline 1f1a82c280 [venice] Reconcile synced model overrides 2026-06-10 14:24:32 -05:00
Aiden Cline d9b2cd9076 Merge remote-tracking branch 'refs/remotes/contributor/feat/venice-base-model' into feat/venice-base-model 2026-06-10 14:24:21 -05:00
Aiden Cline 0ce7da24b6 [venice] Factor all models through metadata 2026-06-10 14:23:52 -05:00
Aiden Cline 44dabca8de Merge pull request #2093 from jatingomnet/fastrouter_model_update
feat(sync): sync FastRouter model catalog
2026-06-10 14:22:20 -05:00
Aiden Cline 62c62ec36f Merge pull request #2113 from anomalyco/automation/sync-models-openrouter
chore(sync): update OpenRouter model catalog
2026-06-10 14:21:33 -05:00
Aiden Cline c3dcc2730f Merge pull request #2114 from anomalyco/automation/sync-models-vercel
chore(sync): update Vercel AI Gateway model catalog
2026-06-10 14:21:16 -05:00
Aiden Cline 4d90460f96 Merge pull request #2127 from leszek3737/zenmux/step-free
feat(zenmux): remove of Step 3.5 Flash (Free) model and add Step 3.7 Flash (Free)
2026-06-10 14:16:59 -05:00
github-actions[bot] 87b37096fc chore(sync): update OpenRouter model catalog 2026-06-10 19:10:45 +00:00
github-actions[bot] 1ea8f58f13 chore(sync): update Vercel AI Gateway model catalog 2026-06-10 19:10:44 +00:00
Aiden Cline 9a13c66393 Merge pull request #2126 from vglafirov/feat/gitlab-claude-fable-5
feat(gitlab): add Claude Fable 5 model
2026-06-10 11:57:34 -05:00
Leszek f8a551f850 Remove of Step 3.5 Flash (Free) model and add Step 3.7 Flash (Free) 2026-06-10 18:55:15 +02:00
Vladimir Glafirov 1751dc2671 feat(gitlab): add Claude Fable 5 model 2026-06-10 18:50:26 +02:00
Aiden Cline d333702d19 Merge pull request #2115 from pawelsierant/dev
Add Claude Fable 5 support for Azure
2026-06-10 11:40:16 -05:00
Aiden Cline 8f323c3a78 Merge pull request #2125 from Nichokas/add-freemodel-provider
feat(providers): add Claude Fable 5 to FreeModel
2026-06-10 11:40:03 -05:00
dpuyosa 8d3c8cfe21 Merge branch 'dev' into feat/venice-base-model 2026-06-10 18:39:23 +02:00
Aiden Cline 1f8adf44e7 Merge pull request #2091 from dpuyosa/feat/venice-models
Venice: Add tencent-hy3-preview and update minimax-m27
2026-06-10 11:13:10 -05:00
Aiden Cline 4201586665 [venice] Remove models missing from API 2026-06-10 11:08:15 -05:00
Nichokas 28d6a54256 feat: add Claude Fable 5 to FreeModel 2026-06-10 18:06:54 +02:00
Aiden Cline 33bceb35a5 Merge remote-tracking branch 'origin/dev' into feat/venice-base-model
# Conflicts:
#	providers/venice/models/claude-fable-5.toml
2026-06-10 11:00:48 -05:00
Aiden Cline 25c3d6cd23 [venice] Migrate generator to sync runner 2026-06-10 10:58:12 -05:00
David Fierro Iglesias 5dcd077370 feat(snowflake-cortex): add officially supported models 2026-06-10 16:29:41 +02:00
Aiden Cline 987ca2d2f8 Merge pull request #2117 from dpuyosa/feat/venice-claude-fable-5
Venice: Add claude-fable-5 model
2026-06-10 09:28:58 -05:00
dpuyosa 07d2e3e23f [venice] Update models with the new generation script version
- Use new `base_model` and `reasoning_options`
2026-06-10 13:37:13 +02:00
dpuyosa 5d5a421b35 [venice] Add claude-fable-5 model
- Add new provider model configuration inheriting from anthropic base
- Enable structured_output and define cost/modalities
- New file: providers/venice/models/claude-fable-5.toml
2026-06-10 13:15:23 +02:00
dpuyosa 63f56867b9 [venice] Add tencent-hy3-preview and update minimax-m27
- Inherit base_model metadata for both models
- Add reasoning_options with effort levels
- Remove redundant fields now provided by base
2026-06-10 13:06:17 +02:00
dpuyosa d4bf232f91 [venice] Add base_model + reasoning_options to generator
- Derive open_weights from base model metadata when present
- Remove open_weights from baseModelOverrides and formatBaseModelToml
- Add temperature comparison in detectChanges for provider models
2026-06-10 12:59:38 +02:00
dpuyosa 0b27d6034d [venice] Add base_model + reasoning_options to generator
- Add base_model lookup via models/ metadata directory
- Support new reasoning field (reasoning_options effort), audio pricing, and full TOML formatting
- Preserve existing fields and emit minimal override TOMLs when base_model present
- Update change detection and formatting for base_model mode
2026-06-10 12:42:39 +02:00
Frank 57caaf88a2 update zen models 2026-06-10 03:55:32 -04:00
Pawel Sierant 3b3d7ac3aa Add Claude Fable 5 support for Azure 2026-06-10 08:37:24 +02:00
jatin.go 015679c420 chore(fastrouter): use base_model for grok-build-0.1 and sarvam models
Addresses PR #2093 review feedback to use base_model inheritance where a
canonical models/ entry exists or can be added.

- providers/fastrouter/models/x-ai/grok-build-0.1.toml: switch to
  base_model = "xai/grok-build-0.1" (canonical already existed); drop
  duplicated/conflicting facts.
- models/sarvam/sarvam-30b.toml, models/sarvam/sarvam-105b.toml: add new
  canonical metadata so multiple sarvam-hosting providers can share it.
- providers/fastrouter/models/sarvam/sarvam-30b.toml,
  providers/fastrouter/models/sarvam/sarvam-105b.toml: switch to
  base_model with only [cost] override.

bun validate exits 0.
2026-06-10 11:22:29 +05:30
Aiden Cline de6034494d Merge pull request #2112 from anomalyco/feat/groq-reasoning-options
fix(groq): reconcile model catalog and reasoning options
2026-06-10 00:29:38 -05:00
Aiden Cline feb387982b fix(groq): reconcile active model catalog 2026-06-10 00:14:39 -05:00
Aiden Cline 3beb135e23 feat(groq): add reasoning options 2026-06-10 00:08:17 -05:00
Aiden Cline eb2dc1750e Merge pull request #2111 from anomalyco/feat/nvidia-reasoning-options
feat(nvidia): add reasoning options
2026-06-09 23:44:39 -05:00
Aiden Cline 0fa6f6a983 feat(schema): support unbounded reasoning budgets 2026-06-09 23:20:21 -05:00
Aiden Cline aba6cae853 fix(nvidia): narrow reasoning controls 2026-06-09 23:16:13 -05:00
Aiden Cline 83e2a3437f feat(nvidia): add reasoning options 2026-06-09 20:48:07 -05:00
Aiden Cline f3d8034335 Merge pull request #2109 from anomalyco/fix/cloudflare-sync-reasoning-options
fix(sync): preserve reasoning options
2026-06-09 19:54:25 -05:00
Aiden Cline 42fbb1d9ca Merge pull request #2067 from CodeAnimal/az-deepseek-v4
Azure DeepSeek-V4-Pro and DeepSeek-V4-Flash
2026-06-09 19:53:46 -05:00
Aiden Cline e9f798225c Merge pull request #2090 from coder-wangbin/fix/qwen3.7-plus-params
fix(alibaba/qwen3.7-plus): correct max output to 64K and tier size to 256K
2026-06-09 19:47:27 -05:00
Aiden Cline 8bc3d0b602 Merge pull request #2095 from anomalyco/automation/sync-models-openrouter
chore(sync): update OpenRouter model catalog
2026-06-09 19:45:58 -05:00
Aiden Cline bcfcaccbd3 Merge pull request #2077 from anomalyco/feat/novita-reasoning-options
feat(novita-ai): add reasoning options
2026-06-09 19:45:42 -05:00
github-actions[bot] e0f2b8a542 chore(sync): update OpenRouter model catalog 2026-06-09 23:45:17 +00:00
Aiden Cline e0c0f0202d fix(novita-ai): omit unusable V4 none effort 2026-06-09 17:32:35 -05:00
Aiden Cline d06fc9dfc8 fix(novita-ai): add DeepSeek V4 reasoning efforts 2026-06-09 13:47:34 -05:00
jatin.go eaffc05654 chore(fastrouter): drop unrequested models from prior sync
Removes ~117 model TOMLs introduced by the merged-in big sync commit and
keeps only the 32 explicitly-requested new models. Also reverts the two
pricing changes (deepseek-r1-distill-llama-70b, z-ai/glm-5) and restores
the two previously-deleted files (moonshotai/kimi-k2.toml, z-ai/glm-4.5)
to their original pre-sync state.

bun validate exits 0.
2026-06-09 16:28:15 +05:30
jatin.go c8adf1e849 Merge branch 'fastrouter_model_update' of https://github.com/jatingomnet/models.dev into fastrouter_model_update 2026-06-09 16:25:01 +05:30
jatin.go 8a8912c39d feat(sync): add new FastRouter models
Adds 32 new model TOMLs matching the latest fastrouter.ai/models listing.

- Anthropic: claude-opus-4.8, claude-sonnet-4.6
- xAI: grok-4.3, grok-build-0.1
- OpenAI: gpt-5.5, gpt-5.5-pro, gpt-5.4-mini, gpt-5.4-nano,
  gpt-5.3-codex, gpt-image-2, gpt-realtime-1.5
- Google: gemini-3.5-flash, gemini-3.1-pro-preview, gemma-4-31b-it,
  gemini-3.1-flash-image-preview, gemini-3-pro-image-preview,
  imagen-4.0-fast, imagen-4.0-ultra, veo3.1, veo3.1-fast, veo3.1-lite
- DeepSeek: deepseek-v4-pro
- MoonshotAI: kimi-k2.6
- Z.AI: glm-5.1
- MiniMax: minimax-m2.7, minimax-m2.7-highspeed
- Sarvam: sarvam-105b, sarvam-30b
- ByteDance: seedance-2
- Alibaba: wanx/wan-v2-6
- Leonardo.AI: lucid-origin, lucid-realism

Uses base_model inheritance where canonical models/ entries exist;
self-contained TOMLs otherwise. bun validate exits 0.
2026-06-09 16:20:29 +05:30
jatin.go c6641ba93d feat(sync): sync FastRouter model catalog
Adds ~117 new model TOMLs, removes 1 stale entry, and updates 2 pricing
files to match the current fastrouter.ai/models listing.

- Remove moonshotai/kimi-k2 (replaced by kimi-k2.5 and kimi-k2.6)
- Fix z-ai/glm-4.5 (missing .toml extension); convert to base_model ref
- Update pricing: deepseek-r1-distill-llama-70b, z-ai/glm-5
- Add Anthropic claude-opus-4.5 through claude-3-5-haiku-20241022
- Add OpenAI gpt-5.x/4.x/3.5, o-series, realtime, image, sora, embeddings
- Add Google gemini-3.x/gemma-4, imagen-4, veo2/veo3/veo3.1 families
- Add xAI grok-4.x/3.x/2, DeepSeek v3.x/v4-pro/R1 variants
- Add Qwen, MoonshotAI, MiniMax, Perplexity, Meta, Mistral, Z.AI, Sarvam
- Add FLUX, ByteDance seedream/seedance, Leonardo AI, Kling, Runway,
  Pika, Pollo, Vidu, Wanx video/image models and ace-step audio

Uses base_model inheritance where canonical models/ entries exist;
self-contained TOMLs otherwise. bun validate exits 0.
2026-06-09 15:40:27 +05:30
dpuyosa fc7493b27b [venice] Add tencent-hy3-preview and update minimax-m27
- Add new tencent-hy3-preview model with cost/limit/modality config
- Update minimax-m27 last_updated and cache_read pricing
2026-06-09 11:56:16 +02:00
wangbin d4d0b483b5 fix(alibaba/qwen3.7-plus): correct output to 64K and tier size to 256K
- output: 16,384 → 65,536 (official max output is 64K)
- tier.size: 128,000 → 256,000 (matches qwen3.6-plus tier threshold)

Verified against official spec:
https://bailian.console.aliyun.com/cn-beijing/?tab=model#/model-market/detail/qwen3.7-plus
Context: 1M | Max Output: 64K | Modalities: text + image + video
2026-06-09 16:57:14 +08:00
CodeAnimal f83b8ea4a1 Introduce base_model and other corrections based on feedback 2026-06-09 09:53:54 +01:00
Aiden Cline aeecf3b66f fix(novita-ai): add GPT OSS reasoning efforts 2026-06-08 22:41:16 -05:00
Aiden Cline 5e7769cb71 fix(openrouter): expose Claude Opus effort 2026-06-08 20:22:10 -05:00
Aiden Cline add3daacea feat(openrouter): add reasoning options 2026-06-08 20:17:16 -05:00
Aiden Cline c347e8b438 feat(novita-ai): add reasoning options 2026-06-08 20:16:40 -05:00
CodeAnimal b821602bbd Add DeepSeek-V4-Flash to Azure provider 2026-06-08 17:21:48 +01:00
CodeAnimal 74bf471580 Add DeepSeek-V4-Pro to Azure provider 2026-06-08 17:21:36 +01:00
knowhy e043cc6da1 refactor(llmtr): use base_model for qwen3-6-35b 2026-06-08 18:19:40 +03:00
knowhy 6c523206aa feat(llmtr): add logo 2026-06-08 18:19:39 +03:00
knowhy 5ccbf972a5 feat(llmtr): add models/sincap.toml 2026-06-08 08:30:28 +03:00
knowhy c178001cca feat(llmtr): add models/magibu-11b-v8.toml 2026-06-08 08:30:27 +03:00
knowhy 69a833ef58 feat(llmtr): add models/trendyol-7b.toml 2026-06-08 08:30:26 +03:00
knowhy 33c79f65b1 feat(llmtr): add models/medgemma-4b.toml 2026-06-08 08:30:25 +03:00
knowhy c4fba0747f feat(llmtr): add models/qwen3-6-35b.toml 2026-06-08 08:30:24 +03:00
knowhy daf5f684b8 feat(llmtr): add models/gemma-4.toml 2026-06-08 08:30:23 +03:00
knowhy fa17e02dc2 feat(llmtr): add provider.toml 2026-06-08 08:30:22 +03:00
Levente Polyak 15f015fd4a add Qwen3.7 Plus model configuration to Alibana coding plan
Coding-plan models are at a fixed monthly fee.

Link: https://modelstudio.console.alibabacloud.com/eu-central-1?tab=doc#/doc/?type=model&url=3005961
2026-06-07 21:54:13 +02:00
1286 changed files with 4548 additions and 2477 deletions
@@ -0,0 +1,68 @@
name: Close stale pull requests
on:
schedule:
- cron: "17 3 * * *"
workflow_dispatch:
permissions:
issues: write
pull-requests: write
jobs:
close-stale-pull-requests:
runs-on: ubuntu-latest
steps:
- uses: actions/github-script@v8
env:
REVIEWER: rekram1-node
with:
script: |
const { owner, repo } = context.repo
const now = Date.now()
const weekAgo = now - 7 * 24 * 60 * 60 * 1000
const monthAgo = now - 30 * 24 * 60 * 60 * 1000
const pulls = await github.paginate(github.rest.pulls.list, {
owner,
repo,
state: "open",
per_page: 100,
})
const feedbackPulls = new Set()
for (const qualifier of ["commenter", "reviewed-by"]) {
const results = await github.paginate(
github.rest.search.issuesAndPullRequests,
{
q: `repo:${owner}/${repo} is:pr is:open ${qualifier}:${process.env.REVIEWER}`,
per_page: 100,
},
)
for (const result of results) feedbackPulls.add(result.number)
}
for (const pull of pulls) {
const updatedAt = Date.parse(pull.updated_at)
const monthStale = updatedAt < monthAgo
const feedbackStale = updatedAt < weekAgo && feedbackPulls.has(pull.number)
if (!monthStale && !feedbackStale) continue
const reason = monthStale
? "it has not been updated in 30 days"
: `it has not been updated in 7 days after feedback from @${process.env.REVIEWER}`
await github.rest.issues.createComment({
owner,
repo,
issue_number: pull.number,
body: `Closing this pull request as stale because ${reason}. Feel free to reopen it or submit a new pull request if the work is resumed.`,
})
await github.rest.pulls.update({
owner,
repo,
pull_number: pull.number,
state: "closed",
})
}
+3 -2
View File
@@ -65,6 +65,7 @@ jobs:
env:
BASETEN_API_KEY: ${{ secrets.BASETEN_API_KEY }}
OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }}
VENICE_API_KEY: ${{ secrets.VENICE_API_KEY }}
GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }}
GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
GOOGLE_GENERATIVE_AI_API_KEY: ${{ secrets.GOOGLE_GENERATIVE_AI_API_KEY }}
@@ -82,7 +83,7 @@ jobs:
LABELS: automation,model-sync,provider:${{ matrix.provider }}
TITLE: "chore(sync): update ${{ matrix.name }} model catalog"
run: |
if [ -z "$(git status --porcelain -- providers)" ]; then
if [ -z "$(git status --porcelain -- models providers)" ]; then
echo "No model catalog changes found."
exit 0
fi
@@ -91,7 +92,7 @@ jobs:
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git fetch --no-tags --depth=1 origin "+refs/heads/$BRANCH:refs/remotes/origin/$BRANCH" || true
git checkout -B "$BRANCH"
git add providers
git add models providers
git commit -m "$TITLE"
git push --force-with-lease origin "$BRANCH"
+2 -2
View File
@@ -1,7 +1,7 @@
name = "Gemini 2.5 Flash"
family = "gemini-flash"
release_date = "2025-03-20"
last_updated = "2025-06-05"
release_date = "2025-06-17"
last_updated = "2025-06-17"
attachment = true
reasoning = true
temperature = true
+2 -2
View File
@@ -1,7 +1,7 @@
name = "Gemini 2.5 Pro"
family = "gemini-pro"
release_date = "2025-03-20"
last_updated = "2025-06-05"
release_date = "2025-06-17"
last_updated = "2025-06-17"
attachment = true
reasoning = true
temperature = true
+2 -2
View File
@@ -1,7 +1,7 @@
name = "Mistral Large 2.1"
family = "mistral-large"
release_date = "2024-11-01"
last_updated = "2024-11-04"
release_date = "2024-11-18"
last_updated = "2024-11-18"
attachment = false
reasoning = false
temperature = true
+1 -1
View File
@@ -1,5 +1,5 @@
name = "Kimi K2.5"
family = "kimi-k2.5"
family = "kimi-k2"
release_date = "2026-01"
last_updated = "2026-01"
attachment = false
+1 -1
View File
@@ -1,5 +1,5 @@
name = "Kimi K2.6"
family = "kimi-k2.6"
family = "kimi-k2"
release_date = "2026-04-21"
last_updated = "2026-04-21"
attachment = true
+23
View File
@@ -0,0 +1,23 @@
name = "Kimi K2.7 Code"
family = "kimi-k2"
release_date = "2026-06-12"
last_updated = "2026-06-12"
attachment = true
reasoning = true
temperature = false
tool_call = true
structured_output = true
knowledge = "2025-01"
open_weights = true
[limit]
context = 262_144
output = 262_144
[modalities]
input = ["text", "image", "video"]
output = ["text"]
[[weights]]
label = "Hugging Face"
url = "https://huggingface.co/moonshotai/Kimi-K2.7-Code"
+17
View File
@@ -0,0 +1,17 @@
name = "Sarvam 105B"
family = "sarvam"
release_date = "2025-09-01"
last_updated = "2025-09-01"
attachment = false
reasoning = true
temperature = true
tool_call = true
open_weights = true
[limit]
context = 131_072
output = 131_072
[modalities]
input = ["text"]
output = ["text"]
+17
View File
@@ -0,0 +1,17 @@
name = "Sarvam 30B"
family = "sarvam"
release_date = "2026-02-18"
last_updated = "2026-02-18"
attachment = false
reasoning = true
temperature = true
tool_call = true
open_weights = true
[limit]
context = 128_000
output = 128_000
[modalities]
input = ["text"]
output = ["text"]
+18
View File
@@ -0,0 +1,18 @@
name = "GLM-5.2"
family = "glm"
release_date = "2026-06-13"
last_updated = "2026-06-13"
attachment = false
reasoning = true
temperature = true
tool_call = true
structured_output = true
open_weights = false
[limit]
context = 1_000_000
output = 131_072
[modalities]
input = ["text"]
output = ["text"]
+1 -1
View File
@@ -23,7 +23,7 @@
"chutes:generate": "bun ./packages/core/script/generate-chutes.ts",
"databricks:generate": "bun ./packages/core/script/generate-databricks.ts",
"helicone:generate": "bun ./packages/core/script/generate-helicone.ts",
"venice:generate": "bun ./packages/core/script/generate-venice.ts",
"venice:sync": "bun ./packages/core/script/sync-models.ts venice",
"vercel:generate": "bun ./packages/core/script/sync-models.ts vercel",
"wandb:generate": "bun ./packages/core/script/generate-wandb.ts",
"digitalocean:generate": "bun ./packages/core/script/generate-digitalocean.ts",
+4 -1
View File
@@ -13,7 +13,7 @@ import { z } from "zod";
import path from "node:path";
import { existsSync, readFileSync } from "node:fs";
import { mkdir } from "node:fs/promises";
import { ModelFamilyValues } from "../src/family.js";
import { inferKimiFamily, ModelFamilyValues } from "../src/family.js";
const API_ENDPOINT = "https://llm.chutes.ai/v1/models";
const MODEL_METADATA_DIR = path.join(import.meta.dirname, "..", "..", "..", "models");
@@ -261,6 +261,9 @@ function matchesFamily(target: string, family: string): boolean {
}
function inferFamily(modelId: string, modelName: string): string | undefined {
const kimiFamily = inferKimiFamily(modelId, modelName);
if (kimiFamily !== undefined) return kimiFamily;
const sortedFamilies = [...ModelFamilyValues].sort((a, b) => b.length - a.length);
// First pass: try exact substring matches
@@ -26,7 +26,7 @@
import { z } from "zod";
import path from "node:path";
import { mkdir } from "node:fs/promises";
import { ModelFamilyValues } from "../src/family.js";
import { inferKimiFamily, 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";
@@ -142,7 +142,7 @@ const PRICING_NAME_MAP: Record<string, string> = {
// DO-hosted
"qwen3-32b": "alibaba-qwen3-32b",
"minimax m2.5 (public preview)": "minimax-m2.5",
"kimi k2.5": "kimi-k2.5",
"kimi k2.5": "kimi-k2",
"nvidia nemotron 3 super 120b (public preview)": "nvidia-nemotron-3-super-120b",
"glm 5": "glm-5",
};
@@ -311,6 +311,9 @@ function formatNumber(n: number): string {
}
function inferFamily(modelId: string, modelName: string): string | undefined {
const kimiFamily = inferKimiFamily(modelId, modelName);
if (kimiFamily !== undefined) return kimiFamily;
const sorted = [...ModelFamilyValues].sort((a, b) => b.length - a.length);
const targets = [modelId.toLowerCase(), modelName.toLowerCase()];
for (const family of sorted) {
@@ -4,6 +4,8 @@ import { mkdir } from "node:fs/promises";
import path from "node:path";
import { z } from "zod";
import { inferKimiFamily } from "../src/family.js";
// Friendli API endpoint
const API_ENDPOINT = "https://api.friendli.ai/serverless/v1/models";
@@ -53,6 +55,9 @@ const familyPatterns: [RegExp, string][] = [
];
function inferFamily(modelId: string, modelName: string): string | undefined {
const kimiFamily = inferKimiFamily(modelId, modelName);
if (kimiFamily !== undefined) return kimiFamily;
for (const [pattern, family] of familyPatterns) {
if (pattern.test(modelId) || pattern.test(modelName)) {
return family;
-653
View File
@@ -1,653 +0,0 @@
#!/usr/bin/env bun
import { z } from "zod";
import path from "node:path";
import { readdir } from "node:fs/promises";
import { ModelFamilyValues } from "../src/family.js";
// Venice API endpoint
const API_ENDPOINT = "https://api.venice.ai/api/v1/models?type=text";
// Zod schemas for API response validation
const Capabilities = z
.object({
optimizedForCode: z.boolean().optional(),
quantization: z.string().optional(),
supportsAudioInput: z.boolean().optional(),
supportsFunctionCalling: z.boolean().optional(),
supportsLogProbs: z.boolean().optional(),
supportsReasoning: z.boolean().optional(),
supportsResponseSchema: z.boolean().optional(),
supportsVideoInput: z.boolean().optional(),
supportsVision: z.boolean().optional(),
supportsWebSearch: z.boolean().optional(),
})
.passthrough();
const PricingTier = z.object({ usd: z.number(), diem: z.number().optional() }).passthrough();
const ExtendedPricing = z
.object({
context_token_threshold: z.number(),
input: PricingTier,
output: PricingTier,
cache_input: PricingTier.optional(),
cache_write: PricingTier.optional(),
})
.passthrough();
const Pricing = z
.object({
input: PricingTier,
output: PricingTier,
cache_input: PricingTier.optional(),
cache_write: PricingTier.optional(),
extended: ExtendedPricing.optional(),
})
.passthrough();
const ModelSpec = z
.object({
pricing: Pricing.optional(),
availableContextTokens: z.number(),
maxCompletionTokens: z.number().optional(),
capabilities: Capabilities,
constraints: z.any().optional(),
name: z.string(),
modelSource: z.string().optional(),
offline: z.boolean().optional(),
privacy: z.string().optional(),
traits: z.array(z.string()).optional(),
})
.passthrough();
const VeniceModel = z
.object({
created: z.number(),
id: z.string(),
model_spec: ModelSpec,
object: z.string(),
owned_by: z.string(),
type: z.string(),
})
.passthrough();
const VeniceResponse = z
.object({
data: z.array(VeniceModel),
object: z.string(),
type: z.string(),
})
.passthrough();
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);
for (const family of sortedFamilies) {
if (matchesFamily(modelId, family)) {
return family;
}
}
for (const family of sortedFamilies) {
if (matchesFamily(modelName, family)) {
return family;
}
}
return undefined;
}
function buildInputModalities(capabilities: z.infer<typeof Capabilities>): string[] {
const mods: string[] = ["text"];
if (capabilities.supportsVision) mods.push("image");
if (capabilities.supportsAudioInput) mods.push("audio");
if (capabilities.supportsVideoInput) mods.push("video");
return mods;
}
function formatNumber(n: number): string {
if (n >= 1000) {
// Format with underscores for readability (e.g., 131_072)
return n.toString().replace(/\B(?=(\d{3})+(?!\d))/g, "_");
}
return n.toString();
}
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);
}
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;
reasoning?: 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[];
};
provider?: {
npm?: string;
api?: string;
};
}
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;
}
}
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;
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[];
};
}
function mergeModel(
apiModel: z.infer<typeof VeniceModel>,
existing: ExistingModel | null,
): MergedModel {
const spec = apiModel.model_spec;
const caps = spec.capabilities;
const contextTokens = spec.availableContextTokens;
const outputTokens = spec.maxCompletionTokens ?? Math.floor(contextTokens / 4);
const openWeights = spec.modelSource?.toLowerCase().includes("huggingface") ?? false;
const inputModalities = buildInputModalities(caps);
if (existing?.modalities?.input?.includes("pdf") && !inputModalities.includes("pdf")) {
inputModalities.push("pdf");
}
const attachment =
caps.supportsVision === true ||
caps.supportsAudioInput === true ||
caps.supportsVideoInput === true;
const merged: MergedModel = {
name: spec.name,
attachment,
reasoning: caps.supportsReasoning === true,
tool_call: caps.supportsFunctionCalling === true,
temperature: true,
release_date: timestampToDate(apiModel.created),
last_updated: getTodayDate(),
open_weights: openWeights,
limit: {
context: contextTokens,
output: outputTokens,
},
modalities: {
input: inputModalities,
output: ["text"],
},
};
// structured_output only if true
if (caps.supportsResponseSchema === true) {
merged.structured_output = true;
}
// Cost from API
if (spec.pricing) {
merged.cost = {
input: spec.pricing.input.usd,
output: spec.pricing.output.usd,
...(spec.pricing.cache_input && { cache_read: spec.pricing.cache_input.usd }),
...(spec.pricing.cache_write && { cache_write: spec.pricing.cache_write.usd }),
};
// Extended pricing maps to context_over_200k
if (spec.pricing.extended) {
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 }),
};
}
}
const inferred = inferFamily(apiModel.id, spec.name);
merged.family = inferred ?? existing?.family;
// Preserve manual fields from existing
if (existing?.knowledge) {
merged.knowledge = existing.knowledge;
}
if (existing?.interleaved !== undefined) {
merged.interleaved = existing.interleaved;
}
if (existing?.status !== undefined) {
merged.status = existing.status;
}
return merged;
}
function formatToml(model: MergedModel): string {
const lines: string[] = [];
// Basic fields
lines.push(`name = "${model.name.replace(/"/g, '\\"')}"`);
if (model.family) {
lines.push(`family = "${model.family}"`);
}
lines.push(`attachment = ${model.attachment}`);
lines.push(`reasoning = ${model.reasoning}`);
lines.push(`tool_call = ${model.tool_call}`);
if (model.structured_output !== undefined) {
lines.push(`structured_output = ${model.structured_output}`);
}
lines.push(`temperature = ${model.temperature}`);
if (model.knowledge) {
lines.push(`knowledge = "${model.knowledge}"`);
}
lines.push(`release_date = "${model.release_date}"`);
lines.push(`last_updated = "${model.last_updated}"`);
lines.push(`open_weights = ${model.open_weights}`);
if (model.status) {
lines.push(`status = "${model.status}"`);
}
// Interleaved section (if present)
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}"`);
}
}
// Cost section
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 = ${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) {
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}`);
}
}
}
// Limit section
lines.push("");
lines.push(`[limit]`);
lines.push(`context = ${formatNumber(model.limit.context)}`);
lines.push(`output = ${formatNumber(model.limit.output)}`);
// Modalities section
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";
}
interface Changes {
field: string;
oldValue: string;
newValue: string;
}
function detectChanges(
existing: ExistingModel | null,
merged: MergedModel,
): Changes[] {
if (!existing) return [];
const changes: Changes[] = [];
const compare = (field: string, oldVal: unknown, newVal: unknown) => {
const oldStr = JSON.stringify(oldVal);
const newStr = JSON.stringify(newVal);
if (oldStr !== newStr) {
changes.push({
field,
oldValue: formatValue(oldVal),
newValue: formatValue(newVal),
});
}
};
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);
};
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("cost.cache_write", existing.cost?.cache_write, merged.cost?.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);
return changes;
}
async function main() {
const args = process.argv.slice(2);
const dryRun = args.includes("--dry-run");
const modelsDir = path.join(
import.meta.dirname,
"..",
"..",
"..",
"providers",
"venice",
"models",
);
// Check for API key from CLI argument or environment variable
let apiKey: string | null = null;
// Check CLI args for --api-key=xxx or --api-key xxx
const apiKeyArgIndex = args.findIndex((arg) => arg.startsWith("--api-key"));
if (apiKeyArgIndex !== -1) {
const arg = args[apiKeyArgIndex];
if (arg?.includes("=")) {
apiKey = arg.split("=")[1] ?? null;
} else if (args[apiKeyArgIndex + 1]) {
apiKey = args[apiKeyArgIndex + 1] ?? null;
}
}
// Fall back to environment variable
if (!apiKey) {
apiKey = process.env.VENICE_API_KEY ?? null;
}
const includeAlpha = apiKey !== null;
if (dryRun) {
console.log(
`[DRY RUN] Fetching Venice models from API${includeAlpha ? " (including alpha models)" : ""}...`,
);
} else {
console.log(
`Fetching Venice models from API${includeAlpha ? " (including alpha models)" : ""}...`,
);
}
// Fetch API data
const fetchOptions: RequestInit = {};
if (apiKey) {
fetchOptions.headers = {
Authorization: `Bearer ${apiKey}`,
};
}
const res = await fetch(API_ENDPOINT, fetchOptions);
if (!res.ok) {
console.error(`Failed to fetch API: ${res.status} ${res.statusText}`);
if (res.status === 401) {
console.error("Invalid API key. Please check your VENICE_API_KEY.");
}
process.exit(1);
}
const json = await res.json();
const parsed = VeniceResponse.safeParse(json);
if (!parsed.success) {
console.error("Invalid API response:", parsed.error.errors);
process.exit(1);
}
const apiModels = parsed.data.data;
// Get existing files
const existingFiles = new Set<string>();
try {
const files = await readdir(modelsDir);
for (const file of files) {
if (file.endsWith(".toml")) {
existingFiles.add(file);
}
}
} catch {
// Directory might not exist yet
}
console.log(`Found ${apiModels.length} models in API, ${existingFiles.size} existing files\n`);
// Track API model IDs for orphan detection
const apiModelIds = new Set<string>();
let created = 0;
let updated = 0;
let unchanged = 0;
for (const apiModel of apiModels) {
const safeId = apiModel.id.replace(/\//g, "-");
const filename = `${safeId}.toml`;
const filePath = path.join(modelsDir, filename);
apiModelIds.add(filename);
const existing = await loadExistingModel(filePath);
const merged = mergeModel(apiModel, existing);
const tomlContent = formatToml(merged);
if (existing === null) {
// New file
created++;
if (dryRun) {
console.log(`[DRY RUN] Would create: ${filename}`);
console.log(` name = "${merged.name}"`);
if (merged.family) {
console.log(` family = "${merged.family}" (inferred)`);
}
console.log("");
} else {
await Bun.write(filePath, tomlContent);
console.log(`Created: ${filename}`);
}
} else {
// Check for changes
const changes = detectChanges(existing, merged);
if (changes.length > 0) {
updated++;
if (dryRun) {
console.log(`[DRY RUN] Would update: ${filename}`);
} else {
await Bun.write(filePath, tomlContent);
console.log(`Updated: ${filename}`);
}
for (const change of changes) {
console.log(` ${change.field}: ${change.oldValue}${change.newValue}`);
}
console.log("");
} else {
unchanged++;
}
}
}
// Check for orphaned files
const orphaned: string[] = [];
for (const file of existingFiles) {
if (!apiModelIds.has(file)) {
orphaned.push(file);
console.log(`Warning: Orphaned file (not in API): ${file}`);
}
}
// Summary
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();
+4 -1
View File
@@ -3,7 +3,7 @@
import path from "node:path";
import { mkdir } from "node:fs/promises";
import { z } from "zod";
import { ModelFamilyValues } from "../src/family.js";
import { inferKimiFamily, ModelFamilyValues } from "../src/family.js";
const API_ENDPOINT = "https://trace.wandb.ai/inference/analysis/artificialanalysis/models";
@@ -176,6 +176,9 @@ function matchesFamily(target: string, family: string): boolean {
}
function inferFamily(modelId: string, modelName: string): string | undefined {
const kimiFamily = inferKimiFamily(modelId, modelName);
if (kimiFamily !== undefined) return kimiFamily;
const sortedFamilies = [...ModelFamilyValues].sort((a, b) => b.length - a.length);
for (const family of sortedFamilies) {
+8 -2
View File
@@ -66,8 +66,7 @@ export const ModelFamilyValues = [
// Moonshot Kimi
"kimi",
"kimi-k2.5",
"kimi-k2.6",
"kimi-k2",
"kimi-free",
"kimi-thinking",
@@ -423,3 +422,10 @@ export const ModelFamilyValues = [
export const ModelFamily = z.enum(ModelFamilyValues);
export type ModelFamily = z.infer<typeof ModelFamily>;
export function inferKimiFamily(...values: string[]): ModelFamily | undefined {
const target = values.join(" ").toLowerCase();
if (/kimi[^a-z0-9]*k2(?:[^a-z0-9]*\d+)?[^a-z0-9]*thinking/.test(target)) return "kimi-thinking";
if (/kimi[\s_-]*k2/.test(target)) return "kimi-k2";
return undefined;
}
+2 -2
View File
@@ -25,7 +25,7 @@ const ReasoningEffortValue = z.preprocess(
(value) => (value === "null" ? null : value),
z.union([
z.null(),
z.enum(["none", "minimal", "low", "medium", "high", "xhigh", "max"]),
z.enum(["none", "minimal", "low", "medium", "high", "xhigh", "max", "default"]),
]),
);
@@ -47,7 +47,7 @@ const ReasoningOption = z
type: z.literal("budget_tokens"),
min: z
.number()
.min(0, "Minimum reasoning budget cannot be negative")
.min(-1, "Minimum reasoning budget cannot be less than -1")
.optional(),
max: z
.number()
+127 -17
View File
@@ -3,13 +3,14 @@ import { lstat, mkdir, readdir, rm } from "node:fs/promises";
import { mergeDeep } from "remeda";
import { z } from "zod";
import { AuthoredModel, AuthoredModelShape } from "../schema.js";
import { AuthoredModel, AuthoredModelShape, ModelMetadata } from "../schema.js";
import { baseten } from "./providers/baseten.js";
import { cloudflareWorkersAi } from "./providers/cloudflare-workers-ai.js";
import { google } from "./providers/google.js";
import { openrouter } from "./providers/openrouter.js";
import { ovhcloud } from "./providers/ovhcloud.js";
import { vercel } from "./providers/vercel.js";
import { venice } from "./providers/venice.js";
import { xai } from "./providers/xai.js";
const ExistingModelType = AuthoredModelShape.partial()
@@ -40,14 +41,17 @@ export type ExistingModel = z.infer<typeof ExistingModelType>;
export type SyncedFullModel = Omit<z.infer<typeof AuthoredModelShape>, "id">;
export type SyncedBaseModel = Omit<z.infer<typeof SyncedBaseModel>, "id">;
export type SyncedModel = SyncedFullModel | SyncedBaseModel;
export type SyncedMetadata = Omit<z.infer<typeof ModelMetadata>, "id">;
export interface SyncProvider<SourceModel> {
id: string;
name: string;
modelsDir: string;
metadataNamespace?: string;
skipCreates?: boolean;
deleteMissing?: boolean;
preserveSymlinks?: boolean;
preserveBaseModels?: boolean;
sameModel?(current: ExistingModel, desired: SyncedModel): boolean;
missingNotice?(paths: string[]): string[];
sourceID?(model: SourceModel): string;
@@ -57,7 +61,7 @@ export interface SyncProvider<SourceModel> {
translateModel(
model: SourceModel,
context: { existing(id: string): ExistingModel | undefined },
): { id: string; model: SyncedModel } | undefined;
): { id: string; model: SyncedModel; metadata?: { id: string; model: SyncedMetadata } } | undefined;
}
export interface SyncResult {
@@ -79,6 +83,7 @@ export const providers: {
openrouter: SyncProvider<any>;
ovhcloud: SyncProvider<any>;
vercel: SyncProvider<any>;
venice: SyncProvider<any>;
xai: SyncProvider<any>;
} = {
baseten,
@@ -87,13 +92,14 @@ export const providers: {
openrouter,
ovhcloud,
vercel,
venice,
xai,
};
export const groups = {
aggregators: ["openrouter", "vercel"],
cloudflare: ["cloudflare-workers-ai"],
direct: ["baseten", "google", "ovhcloud", "xai"],
direct: ["baseten", "google", "ovhcloud", "venice", "xai"],
} as const;
type ProviderID = keyof typeof providers;
@@ -113,9 +119,12 @@ export async function syncProvider<SourceModel>(
): Promise<SyncResult> {
console.log(`\nSyncing ${provider.name}...`);
const { models: existing, brokenSymlinks } = await readExisting(provider.modelsDir);
const existingState = await readExisting(provider.modelsDir);
const { models: existing, brokenSymlinks } = existingState;
let { modelMetadata } = existingState;
const sourceModels = provider.parseModels(await provider.fetchModels());
const desired = new Map<string, { model: z.infer<typeof SyncedAuthoredModel>; content: string }>();
const desiredMetadata = new Map<string, { model: z.infer<typeof ModelMetadata>; content: string }>();
const skippedRemote: string[] = [];
for (const sourceModel of sourceModels) {
@@ -139,11 +148,45 @@ export async function syncProvider<SourceModel>(
throw new Error(`Duplicate synced model path: ${provider.id}/${relativePath}`);
}
if (translated.metadata !== undefined) {
const parsedMetadata = ModelMetadata.safeParse({
id: translated.metadata.id,
...stripUndefined(translated.metadata.model),
});
if (!parsedMetadata.success) {
parsedMetadata.error.cause = { provider: provider.id, metadata: translated.metadata.id };
throw parsedMetadata.error;
}
const metadataPath = `${translated.metadata.id}.toml`;
if (desiredMetadata.has(metadataPath)) throw new Error(`Duplicate synced metadata path: ${metadataPath}`);
desiredMetadata.set(metadataPath, {
model: parsedMetadata.data,
content: formatMetadataToml(parsedMetadata.data),
});
}
const translatedModel = provider.preserveBaseModels === false
? translated.model
: preserveBaseModel(translated.model, existing.get(relativePath)?.authored);
const translatedBase = "base_model" in translatedModel ? translatedModel.base_model : undefined;
let resolvedReasoning: boolean | undefined;
if (translatedBase !== undefined) {
if (translated.metadata?.id === translatedBase) {
resolvedReasoning = translated.metadata.model.reasoning;
} else {
modelMetadata ??= await readModelMetadata(provider.modelsDir);
const canonicalReasoning = modelMetadata[translatedBase]?.reasoning;
resolvedReasoning = typeof canonicalReasoning === "boolean" ? canonicalReasoning : undefined;
}
} else {
resolvedReasoning = existing.get(relativePath)?.toml.reasoning;
}
const parsed = SyncedAuthoredModel.safeParse(stripUndefined({
id: translated.id,
...preserveReasoningOptions(
preserveBaseModel(translated.model, existing.get(relativePath)?.authored),
translatedModel,
existing.get(relativePath)?.authored,
resolvedReasoning,
),
}));
if (!parsed.success) {
@@ -160,6 +203,48 @@ export async function syncProvider<SourceModel>(
const files: SyncResult["files"] = [];
let unchanged = 0;
const metadataDir = modelMetadataDir(provider.modelsDir);
for (const [relativePath, file] of desiredMetadata) {
const filePath = path.join(metadataDir, relativePath);
const currentFile = Bun.file(filePath);
const current = await currentFile.exists()
? ModelMetadata.safeParse({
id: relativePath.slice(0, -5),
...Bun.TOML.parse(await currentFile.text()) as Record<string, unknown>,
})
: undefined;
if (current?.success && stable(current.data) === stable(file.model)) continue;
files.push({ status: current === undefined ? "created" : "updated", path: filePath });
if (options.dryRun) {
console.log(`Would ${current === undefined ? "create" : "update"} metadata ${relativePath}`);
} else {
await mkdir(path.dirname(filePath), { recursive: true });
await Bun.write(filePath, file.content);
}
}
if (provider.metadataNamespace !== undefined) {
if (!/^[a-z0-9-]+$/.test(provider.metadataNamespace)) {
throw new Error(`Invalid metadata namespace: ${provider.metadataNamespace}`);
}
const namespaceDir = path.join(metadataDir, provider.metadataNamespace);
for (const { file } of await tomlFiles(namespaceDir)) {
const relativePath = path.join(provider.metadataNamespace, file);
if (desiredMetadata.has(relativePath) || provider.deleteMissing === false) continue;
if (options.newOnly) {
console.log(`Skipping metadata removal in new-only mode: ${relativePath}`);
continue;
}
const filePath = path.join(metadataDir, relativePath);
files.push({ status: "deleted", path: filePath });
if (options.dryRun) {
console.log(`Would remove metadata ${relativePath}`);
} else {
await rm(filePath, { force: true });
}
}
}
for (const [relativePath, file] of desired) {
const filePath = path.join(provider.modelsDir, relativePath);
const current = existing.get(relativePath);
@@ -251,7 +336,12 @@ export function preserveBaseModel(model: SyncedModel, existing: ExistingModel |
export function preserveReasoningOptions(
model: SyncedModel,
existing: ExistingModel | undefined,
resolvedReasoning: boolean | undefined = existing?.reasoning,
): SyncedModel {
if ((model.reasoning ?? resolvedReasoning) === false) {
const { reasoning_options: _reasoningOptions, ...withoutReasoningOptions } = model;
return withoutReasoningOptions as SyncedModel;
}
if (model.reasoning_options !== undefined || existing?.reasoning_options === undefined) return model;
return {
...model,
@@ -324,7 +414,7 @@ async function readExisting(modelsDir: string) {
existing.set(file, { authored, toml, symlink });
}
return { models: existing, brokenSymlinks };
return { models: existing, brokenSymlinks, modelMetadata };
}
async function isSymlink(filePath: string) {
@@ -337,8 +427,7 @@ async function isSymlink(filePath: string) {
}
async function readModelMetadata(modelsDir: string) {
const root = path.dirname(path.dirname(path.dirname(modelsDir)));
const metadataDir = path.join(root, "models");
const metadataDir = modelMetadataDir(modelsDir);
const result: Record<string, Record<string, unknown>> = {};
for await (const modelPath of new Bun.Glob("**/*.toml").scan({
@@ -356,6 +445,10 @@ async function readModelMetadata(modelsDir: string) {
return result;
}
function modelMetadataDir(modelsDir: string) {
return path.join(path.dirname(path.dirname(path.dirname(modelsDir))), "models");
}
function resolveBaseModel(
authored: ExistingModel,
modelMetadata: Record<string, Record<string, unknown>>,
@@ -602,15 +695,19 @@ function formatToml(model: z.infer<typeof SyncedAuthoredModel>) {
if (model.open_weights !== undefined) lines.push(`open_weights = ${model.open_weights}`);
if (model.status !== undefined) lines.push(`status = ${quote(model.status)}`);
for (const option of model.reasoning_options ?? []) {
lines.push("", "[[reasoning_options]]");
lines.push(`type = ${quote(option.type)}`);
if (option.type === "effort") {
lines.push(`values = [${option.values.map(formatReasoningValue).join(", ")}]`);
}
if (option.type === "budget_tokens") {
if (option.min !== undefined) lines.push(`min = ${formatInteger(option.min)}`);
if (option.max !== undefined) lines.push(`max = ${formatInteger(option.max)}`);
if (model.reasoning_options?.length === 0) {
lines.push("reasoning_options = []");
} else {
for (const option of model.reasoning_options ?? []) {
lines.push("", "[[reasoning_options]]");
lines.push(`type = ${quote(option.type)}`);
if (option.type === "effort") {
lines.push(`values = [${option.values.map(formatReasoningValue).join(", ")}]`);
}
if (option.type === "budget_tokens") {
if (option.min !== undefined) lines.push(`min = ${formatInteger(option.min)}`);
if (option.max !== undefined) lines.push(`max = ${formatInteger(option.max)}`);
}
}
}
@@ -675,6 +772,19 @@ function formatToml(model: z.infer<typeof SyncedAuthoredModel>) {
return `${lines.join("\n")}\n`;
}
function formatMetadataToml(model: z.infer<typeof ModelMetadata>) {
const content = formatToml(model as unknown as z.infer<typeof SyncedAuthoredModel>).trimEnd();
const lines = [content];
for (const weight of model.weights ?? []) {
lines.push("", "[[weights]]");
if (weight.label !== undefined) lines.push(`label = ${quote(weight.label)}`);
lines.push(`url = ${quote(weight.url)}`);
if (weight.format !== undefined) lines.push(`format = ${quote(weight.format)}`);
if (weight.quantization !== undefined) lines.push(`quantization = ${quote(weight.quantization)}`);
}
return `${lines.join("\n")}\n`;
}
export async function main(args = process.argv.slice(2)) {
if (args.includes("--list-providers")) {
console.log(JSON.stringify(syncProviderMatrix()));
@@ -2,7 +2,7 @@ import { z } from "zod";
import { readFileSync, readdirSync } from "node:fs";
import path from "node:path";
import { ModelFamilyValues } from "../../family.js";
import { inferKimiFamily, ModelFamilyValues } from "../../family.js";
import type { ExistingModel, SyncProvider, SyncedFullModel, SyncedModel } from "../index.js";
const API_ENDPOINT = "https://openrouter.ai/api/v1/models";
@@ -113,6 +113,9 @@ function modalities(values: string[], fallback: Modality[]): Modality[] {
}
function inferFamily(model: OpenRouterModel, name: string) {
const kimiFamily = inferKimiFamily(model.id, name);
if (kimiFamily !== undefined) return kimiFamily;
const target = `${model.id} ${name}`.toLowerCase();
return [...ModelFamilyValues]
.sort((a, b) => b.length - a.length)
@@ -121,6 +121,7 @@ export function buildOvhcloudModel(
last_updated: lastUpdated,
attachment,
reasoning,
reasoning_options: reasoning ? existing?.reasoning_options : undefined,
temperature: temperature || undefined,
tool_call: toolCall,
structured_output: structuredOutput || undefined,
+241
View File
@@ -0,0 +1,241 @@
import { readdirSync } from "node:fs";
import path from "node:path";
import { z } from "zod";
import { inferKimiFamily, ModelFamilyValues } from "../../family.js";
import type { ExistingModel, SyncProvider, SyncedFullModel, SyncedModel } from "../index.js";
import { factorBaseModel } from "./openrouter.js";
const API_ENDPOINT = "https://api.venice.ai/api/v1/models?type=text";
const MODELS_DIR = path.join(import.meta.dirname, "..", "..", "..", "..", "..", "models");
const Capabilities = z.object({
supportsAudioInput: z.boolean().optional(),
supportsE2EE: z.boolean().optional(),
supportsFunctionCalling: z.boolean().optional(),
supportsReasoning: z.boolean().optional(),
supportsReasoningEffort: z.boolean().optional(),
reasoningEffortOptions: z.array(z.string()).optional(),
supportsResponseSchema: z.boolean().optional(),
supportsVideoInput: z.boolean().optional(),
supportsVision: z.boolean().optional(),
}).passthrough();
const PricingTier = z.object({
usd: z.number().nonnegative(),
}).passthrough();
const ExtendedPricing = z.object({
context_token_threshold: z.number().int().nonnegative(),
input: PricingTier,
output: PricingTier,
cache_input: PricingTier.optional(),
cache_write: PricingTier.optional(),
}).passthrough();
const Pricing = z.object({
input: PricingTier,
output: PricingTier,
cache_input: PricingTier.optional(),
cache_write: PricingTier.optional(),
extended: ExtendedPricing.optional(),
}).passthrough();
const ModelSpec = z.object({
pricing: Pricing.optional(),
availableContextTokens: z.number().int().nonnegative(),
maxCompletionTokens: z.number().int().nonnegative().optional(),
capabilities: Capabilities,
name: z.string().min(1),
modelSource: z.string().optional(),
}).passthrough();
export const VeniceModel = z.object({
created: z.number(),
id: z.string().min(1),
model_spec: ModelSpec,
}).passthrough();
export const VeniceResponse = z.object({
data: z.array(VeniceModel),
}).passthrough();
export type VeniceModel = z.infer<typeof VeniceModel>;
type ReasoningEffort = "default" | "max" | "low" | "high" | "none" | "medium" | "minimal" | "xhigh";
interface MetadataEntry {
id: string;
filename: string;
normalizedFull: string;
normalizedFilename: string;
}
let metadataEntries: MetadataEntry[] | undefined;
const BASE_MODEL_ALIASES: Record<string, string> = {
"claude-opus-4-6-fast": "anthropic/claude-opus-4-6",
"claude-opus-4-7-fast": "anthropic/claude-opus-4-7",
"claude-opus-4-8-fast": "anthropic/claude-opus-4-8",
};
export const venice = {
id: "venice",
name: "Venice",
modelsDir: "providers/venice/models",
preserveBaseModels: false,
async fetchModels() {
const headers = process.env.VENICE_API_KEY
? { Authorization: `Bearer ${process.env.VENICE_API_KEY}` }
: undefined;
const response = await fetch(API_ENDPOINT, { headers });
if (!response.ok) {
throw new Error(`Venice models request failed: ${response.status} ${response.statusText}`);
}
return response.json();
},
parseModels(raw) {
return VeniceResponse.parse(raw).data;
},
translateModel(model, context) {
if (model.model_spec.capabilities.supportsE2EE === true) return undefined;
const id = model.id.replaceAll("/", "-");
const existing = context.existing(id);
const existingBase = existing?.base_model?.startsWith("venice/") === false ? existing.base_model : undefined;
const resolvedBase = existingBase ?? resolveVeniceBaseModel(model.id, model.model_spec.name);
return {
id,
model: buildVeniceModel(model, existing, resolvedBase ?? null),
};
},
} satisfies SyncProvider<VeniceModel>;
export function buildVeniceModel(
model: VeniceModel,
existing: ExistingModel | undefined,
baseModel: string | null | undefined = existing?.base_model ?? resolveVeniceBaseModel(model.id, model.model_spec.name),
today = new Date().toISOString().slice(0, 10),
): SyncedModel {
const spec = model.model_spec;
const capabilities = spec.capabilities;
const input = [
"text" as const,
...(capabilities.supportsVision ? ["image" as const] : []),
...(capabilities.supportsAudioInput ? ["audio" as const] : []),
...(capabilities.supportsVideoInput ? ["video" as const] : []),
...(existing?.modalities?.input.includes("pdf") ? ["pdf" as const] : []),
];
const limit = {
context: spec.availableContextTokens,
input: existing?.limit?.input,
output: spec.maxCompletionTokens ?? Math.floor(spec.availableContextTokens / 4),
};
const reasoningEfforts = capabilities.reasoningEffortOptions?.filter(isReasoningEffort);
const reasoningOptions = reasoningEfforts?.length
? [{ type: "effort" as const, values: reasoningEfforts }]
: [];
const cost = spec.pricing === undefined
? existing?.cost
: {
input: spec.pricing.input.usd,
output: spec.pricing.output.usd,
reasoning: existing?.cost?.reasoning,
cache_read: spec.pricing.cache_input?.usd,
cache_write: spec.pricing.cache_write?.usd,
input_audio: existing?.cost?.input_audio,
output_audio: existing?.cost?.output_audio,
tiers: spec.pricing.extended === undefined
? existing?.cost?.tiers
: [{
tier: { type: "context" as const, size: spec.pricing.extended.context_token_threshold },
input: spec.pricing.extended.input.usd,
output: spec.pricing.extended.output.usd,
cache_read: spec.pricing.extended.cache_input?.usd,
cache_write: spec.pricing.extended.cache_write?.usd,
}],
};
const authoritative = {
name: spec.name,
attachment: input.some((value) => value !== "text"),
reasoning: capabilities.supportsReasoning === true,
reasoning_options: reasoningOptions,
tool_call: capabilities.supportsFunctionCalling === true,
structured_output: capabilities.supportsResponseSchema === true ? true : undefined,
temperature: undefined,
cost,
limit,
modalities: { input: [...new Set(input)], output: ["text" as const] },
};
const releaseDate = new Date(model.created * 1000).toISOString().slice(0, 10);
const values: SyncedFullModel = {
...authoritative,
family: baseModel == null ? inferFamily(model.id, spec.name) ?? existing?.family : existing?.family,
release_date: releaseDate,
last_updated: existing?.last_updated ?? today,
knowledge: existing?.knowledge,
open_weights: spec.modelSource?.toLowerCase().includes("huggingface")
?? existing?.open_weights
?? false,
status: existing?.status,
interleaved: existing?.interleaved,
};
return baseModel == null
? values
: factorBaseModel(baseModel, values, limit, existing?.base_model_omit);
}
export function resolveVeniceBaseModel(id: string, name: string) {
const alias = BASE_MODEL_ALIASES[id];
if (alias !== undefined) return alias;
const entries = getMetadataEntries();
const normalizedID = normalize(id);
const normalizedName = normalize(name);
const ranked = [
entries.filter((entry) => entry.normalizedFull === normalizedID),
entries.filter((entry) => entry.normalizedFilename === normalizedID),
entries.filter((entry) => entry.normalizedFilename === normalizedName),
];
return ranked.find((matches) => matches.length === 1)?.[0]?.id;
}
function getMetadataEntries() {
if (metadataEntries !== undefined) return metadataEntries;
metadataEntries = [];
for (const provider of readdirSync(MODELS_DIR, { withFileTypes: true })) {
if (!provider.isDirectory()) continue;
for (const file of readdirSync(path.join(MODELS_DIR, provider.name), { withFileTypes: true })) {
if (!file.isFile() || !file.name.endsWith(".toml")) continue;
const filename = file.name.slice(0, -5);
metadataEntries.push({
id: `${provider.name}/${filename}`,
filename,
normalizedFull: normalize(`${provider.name}/${filename}`),
normalizedFilename: normalize(filename),
});
}
}
return metadataEntries;
}
function normalize(value: string) {
return value.toLowerCase().replaceAll(/[^a-z0-9]/g, "");
}
function isReasoningEffort(value: string): value is ReasoningEffort {
return ["default", "max", "low", "high", "none", "medium", "minimal", "xhigh"].includes(value);
}
function inferFamily(id: string, name: string) {
const kimiFamily = inferKimiFamily(id, name);
if (kimiFamily !== undefined) return kimiFamily;
const target = `${id} ${name}`.toLowerCase();
return [...ModelFamilyValues]
.sort((a, b) => b.length - a.length)
.find((family) => {
const value = family.toLowerCase().replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
if (family === "o") return new RegExp(`(^|[^a-z0-9])${value}(?=\\d|$|[^a-z0-9])`).test(target);
return new RegExp(`(^|[^a-z0-9])${value}(?=$|[^a-z0-9])`).test(target);
});
}
+4 -1
View File
@@ -1,6 +1,6 @@
import { z } from "zod";
import { ModelFamilyValues } from "../../family.js";
import { inferKimiFamily, ModelFamilyValues } from "../../family.js";
import type { ExistingModel, SyncProvider, SyncedFullModel, SyncedModel } from "../index.js";
import { factorBaseModel, resolveCanonicalBaseModel } from "./openrouter.js";
@@ -153,6 +153,9 @@ function buildCost(pricing: VercelModel["pricing"], existing?: ExistingModel["co
}
function inferFamily(modelID: string, name: string) {
const kimiFamily = inferKimiFamily(modelID, name);
if (kimiFamily !== undefined) return kimiFamily;
const targets = [modelID, name].map((value) => value.toLowerCase());
const families = [...ModelFamilyValues].sort((a, b) => b.length - a.length);
return families.find((family) => targets.some((target) => target.includes(family.toLowerCase())))
+15
View File
@@ -0,0 +1,15 @@
import { expect, test } from "bun:test";
import { inferKimiFamily } from "../src/family.js";
test("Kimi family inference ignores K2 versions", () => {
expect(inferKimiFamily("moonshotai/kimi-k2.5")).toBe("kimi-k2");
expect(inferKimiFamily("moonshotai/kimi-k2.7-code")).toBe("kimi-k2");
expect(inferKimiFamily("Kimi K2.6")).toBe("kimi-k2");
});
test("Kimi family inference preserves thinking variants", () => {
expect(inferKimiFamily("moonshotai/kimi-k2-thinking")).toBe("kimi-thinking");
expect(inferKimiFamily("Kimi K2.5 Thinking")).toBe("kimi-thinking");
expect(inferKimiFamily("moonshotai/kimi-k2.6:thinking")).toBe("kimi-thinking");
});
+84
View File
@@ -3,6 +3,7 @@ import path from "node:path";
import { mkdtemp, mkdir, readlink, symlink } from "node:fs/promises";
import os from "node:os";
import { AuthoredModelShape } from "../src/schema.js";
import { syncProvider, type SyncProvider, type SyncedFullModel } from "../src/sync/index.js";
const model: SyncedFullModel = {
@@ -18,6 +19,28 @@ const model: SyncedFullModel = {
modalities: { input: ["text"], output: ["text"] },
};
test("reasoning budgets allow only the -1 negative sentinel", () => {
const authored = { id: "model", ...model };
expect(AuthoredModelShape.safeParse({
...authored,
reasoning_options: [{ type: "budget_tokens", min: -1, max: 32_768 }],
}).success).toBe(true);
expect(AuthoredModelShape.safeParse({
...authored,
reasoning_options: [{ type: "budget_tokens", min: -2, max: 32_768 }],
}).success).toBe(false);
});
test("reasoning efforts accept the provider default value", () => {
expect(AuthoredModelShape.safeParse({
id: "model",
...model,
reasoning: true,
reasoning_options: [{ type: "effort", values: ["none", "default"] }],
}).success).toBe(true);
});
async function fixture() {
const root = await mkdtemp(path.join(os.tmpdir(), "models-dev-sync-"));
const modelsDir = path.join(root, "providers", "test", "models");
@@ -113,6 +136,11 @@ open_weights = false
type = "effort"
values = ["low", "high"]
[[reasoning_options]]
type = "budget_tokens"
min = -1
max = 32768
[cost]
input = 1
output = 2
@@ -138,6 +166,62 @@ output = ["text"]
expect(first.updated).toBe(1);
expect(content).toContain("[[reasoning_options]]");
expect(content).toContain('values = ["low", "high"]');
expect(content).toContain("min = -1");
expect(content).toContain("max = 32_768");
expect(second.updated).toBe(0);
expect(second.unchanged).toBe(1);
});
test("sync writes metadata returned by a provider translator", async () => {
const root = await mkdtemp(path.join(os.tmpdir(), "models-dev-sync-metadata-"));
const modelsDir = path.join(root, "providers", "test", "models");
await mkdir(modelsDir, { recursive: true });
const sync = provider(modelsDir, ["model"]);
sync.translateModel = () => ({
id: "model",
model: {
base_model: "test/model",
reasoning_options: [],
cost: { input: 1, output: 2 },
},
metadata: {
id: "test/model",
model: {
name: "Model",
release_date: "2026-06-10",
last_updated: "2026-06-10",
attachment: false,
reasoning: false,
tool_call: true,
open_weights: false,
limit: { context: 1_000, output: 100 },
modalities: { input: ["text"], output: ["text"] },
},
},
});
const first = await syncProvider(sync);
const second = await syncProvider(sync);
expect(first).toMatchObject({ created: 2, updated: 0 });
expect(second).toMatchObject({ created: 0, updated: 0 });
expect(await Bun.file(path.join(root, "models", "test", "model.toml")).text()).toContain('name = "Model"');
});
test("sync removes missing metadata only from its owned namespace", async () => {
const { root, modelsDir } = await fixture();
const ownedDir = path.join(root, "models", "test");
const otherDir = path.join(root, "models", "other");
await mkdir(ownedDir, { recursive: true });
await mkdir(otherDir, { recursive: true });
await Bun.write(path.join(ownedDir, "stale.toml"), 'name = "Stale"\n');
await Bun.write(path.join(otherDir, "retained.toml"), 'name = "Retained"\n');
const sync = provider(modelsDir, []);
sync.metadataNamespace = "test";
const result = await syncProvider(sync);
expect(result.deleted).toBe(1);
expect(await Bun.file(path.join(ownedDir, "stale.toml")).exists()).toBe(false);
expect(await Bun.file(path.join(otherDir, "retained.toml")).exists()).toBe(true);
});
+167
View File
@@ -0,0 +1,167 @@
import { expect, test } from "bun:test";
import { readdirSync } from "node:fs";
import path from "node:path";
import {
buildVeniceModel,
resolveVeniceBaseModel,
venice,
VeniceResponse,
type VeniceModel,
} from "../src/sync/providers/venice.js";
const catalogModel: VeniceModel = {
id: "openai-gpt-54",
created: 1_772_668_800,
model_spec: {
name: "GPT-5.4",
availableContextTokens: 400_000,
maxCompletionTokens: 128_000,
modelSource: "OpenAI",
capabilities: {
supportsVision: true,
supportsReasoning: true,
supportsReasoningEffort: true,
reasoningEffortOptions: ["none", "low", "medium", "high"],
supportsFunctionCalling: true,
supportsResponseSchema: true,
},
pricing: {
input: { usd: 3.13 },
output: { usd: 18.75 },
cache_input: { usd: 0.313 },
extended: {
context_token_threshold: 200_000,
input: { usd: 6.26 },
output: { usd: 28.125 },
},
},
},
};
test("Venice resolves flattened IDs to canonical metadata", () => {
expect(resolveVeniceBaseModel("openai-gpt-54", "GPT-5.4")).toBe("openai/gpt-5.4");
expect(resolveVeniceBaseModel("claude-opus-4-8-fast", "Claude Opus 4.8 Fast"))
.toBe("anthropic/claude-opus-4-8");
});
test("Venice emits empty reasoning options when efforts are unavailable", () => {
const synced = buildVeniceModel({
...catalogModel,
id: "reasoning-without-efforts",
model_spec: {
...catalogModel.model_spec,
name: "Reasoning Without Efforts",
capabilities: {
...catalogModel.model_spec.capabilities,
reasoningEffortOptions: [],
},
},
}, undefined, undefined, "2026-06-10");
expect(synced).toMatchObject({ reasoning: true, reasoning_options: [] });
});
test("Venice does not infer temperature support", () => {
const synced = buildVeniceModel(catalogModel, undefined, null, "2026-06-10");
expect(synced.temperature).toBeUndefined();
});
test("Venice skips E2EE models", () => {
const translated = venice.translateModel({
...catalogModel,
id: "e2ee-test-model",
model_spec: {
...catalogModel.model_spec,
capabilities: { ...catalogModel.model_spec.capabilities, supportsE2EE: true },
},
}, { existing: () => undefined });
expect(translated).toBeUndefined();
});
test("Venice uses boundary-aware family matching", () => {
const synced = buildVeniceModel({
...catalogModel,
id: "google-gemma-4-31b-it",
model_spec: { ...catalogModel.model_spec, name: "Google Gemma 4 31B Instruct" },
}, undefined, null, "2026-06-10");
expect(synced).toMatchObject({ family: "gemma" });
});
test("Venice maps API fields without bumping inherited model timestamps", () => {
const synced = buildVeniceModel(catalogModel, {
base_model: "openai/gpt-5.4",
name: "GPT-5.4",
family: "gpt",
release_date: "2026-03-05",
last_updated: "2026-03-09",
attachment: true,
reasoning: true,
tool_call: true,
structured_output: true,
temperature: true,
open_weights: false,
interleaved: { field: "reasoning_content" },
cost: { input: 3, output: 18, input_audio: 4 },
limit: { context: 400_000, output: 128_000 },
modalities: { input: ["text", "image", "pdf"], output: ["text"] },
}, "openai/gpt-5.4", "2026-06-10");
expect(synced).toMatchObject({
base_model: "openai/gpt-5.4",
base_model_omit: ["limit.input"],
last_updated: "2026-03-09",
reasoning_options: [{ type: "effort", values: ["none", "low", "medium", "high"] }],
interleaved: { field: "reasoning_content" },
cost: {
input: 3.13,
output: 18.75,
cache_read: 0.313,
input_audio: 4,
tiers: [{ tier: { type: "context", size: 200_000 }, input: 6.26, output: 28.125 }],
},
});
expect(synced).not.toHaveProperty("family");
expect(synced).not.toHaveProperty("release_date");
expect(synced).not.toHaveProperty("open_weights");
expect(synced).not.toHaveProperty("modalities");
expect(synced).not.toHaveProperty("temperature");
});
test("Venice preserves last_updated when authoritative data is unchanged", () => {
const providerModel = {
...catalogModel,
id: "venice-only-test-model",
model_spec: { ...catalogModel.model_spec, name: "Venice Only Test Model" },
};
const full = buildVeniceModel(providerModel, undefined, undefined, "2026-06-10");
if ("base_model" in full) throw new Error("Expected a full provider model fixture");
const synced = buildVeniceModel(providerModel, full, undefined, "2026-06-11");
expect(synced).toMatchObject({ last_updated: "2026-06-10" });
});
test("Venice rejects malformed responses", () => {
expect(() => VeniceResponse.parse({ data: [{ id: "broken" }] })).toThrow();
});
test("Venice models use only canonical metadata and declare reasoning options", async () => {
const root = path.join(import.meta.dirname, "..", "..", "..");
const modelsDir = path.join(root, "providers", "venice", "models");
for (const file of readdirSync(modelsDir).filter((item) => item.endsWith(".toml"))) {
const model = Bun.TOML.parse(await Bun.file(path.join(modelsDir, file)).text()) as {
base_model?: string;
reasoning_options?: unknown[];
};
expect(model.reasoning_options, file).toBeDefined();
if (model.base_model !== undefined) {
expect(model.base_model.startsWith("venice/"), file).toBe(false);
expect(await Bun.file(path.join(root, "models", `${model.base_model}.toml`)).exists(), file).toBe(true);
}
expect(file.startsWith("e2ee-"), file).toBe(false);
}
});
@@ -4,6 +4,7 @@ release_date = "2024-11-28"
last_updated = "2024-11-28"
attachment = false
reasoning = true
reasoning_options = []
temperature = true
tool_call = true
open_weights = true
@@ -4,6 +4,7 @@ release_date = "2025-07-01"
last_updated = "2025-07-01"
attachment = false
reasoning = true
reasoning_options = []
temperature = true
tool_call = true
open_weights = true
@@ -4,6 +4,7 @@ release_date = "2025-04-29"
last_updated = "2025-04-29"
attachment = false
reasoning = true
reasoning_options = []
temperature = true
tool_call = true
open_weights = true
@@ -4,6 +4,7 @@ release_date = "2025-07-22"
last_updated = "2025-07-22"
attachment = false
reasoning = true
reasoning_options = []
temperature = true
tool_call = true
open_weights = true
@@ -4,6 +4,7 @@ release_date = "2025-02-19"
last_updated = "2025-02-19"
attachment = true
reasoning = true
reasoning_options = []
temperature = true
tool_call = true
knowledge = "2024-10-31"
@@ -4,6 +4,7 @@ release_date = "2025-10-15"
last_updated = "2025-10-15"
attachment = true
reasoning = true
reasoning_options = []
temperature = true
tool_call = true
knowledge = "2025-02-28"
@@ -4,6 +4,7 @@ release_date = "2025-08-05"
last_updated = "2025-08-05"
attachment = true
reasoning = true
reasoning_options = []
temperature = true
tool_call = true
open_weights = false
@@ -4,6 +4,7 @@ release_date = "2025-05-14"
last_updated = "2025-05-14"
attachment = true
reasoning = true
reasoning_options = []
temperature = true
tool_call = true
open_weights = false
@@ -4,6 +4,7 @@ release_date = "2025-11-01"
last_updated = "2025-11-01"
attachment = true
reasoning = true
reasoning_options = []
temperature = true
tool_call = true
knowledge = "2025-03-31"
@@ -4,6 +4,7 @@ release_date = "2026-02-05"
last_updated = "2026-02-05"
attachment = true
reasoning = true
reasoning_options = []
temperature = true
tool_call = true
knowledge = "2025-05-31"
@@ -4,6 +4,7 @@ release_date = "2025-05-14"
last_updated = "2025-05-14"
attachment = true
reasoning = true
reasoning_options = []
temperature = true
tool_call = true
open_weights = false
@@ -4,6 +4,7 @@ release_date = "2025-09-29"
last_updated = "2025-09-29"
attachment = true
reasoning = true
reasoning_options = []
temperature = true
tool_call = true
knowledge = "2025-07-31"
@@ -4,6 +4,7 @@ release_date = "2026-02-17"
last_updated = "2026-02-17"
attachment = true
reasoning = true
reasoning_options = []
temperature = true
tool_call = true
knowledge = "2025-08-31"
@@ -4,6 +4,7 @@ release_date = "2025-01-20"
last_updated = "2025-01-20"
attachment = false
reasoning = true
reasoning_options = []
temperature = true
tool_call = true
open_weights = true
@@ -4,6 +4,7 @@ release_date = "2025-06-01"
last_updated = "2025-06-01"
attachment = false
reasoning = true
reasoning_options = []
temperature = true
tool_call = true
open_weights = true
@@ -4,6 +4,7 @@ release_date = "2025-06-15"
last_updated = "2025-06-15"
attachment = false
reasoning = true
reasoning_options = []
temperature = true
tool_call = true
open_weights = true
@@ -4,6 +4,7 @@ release_date = "2025-01-20"
last_updated = "2025-01-20"
attachment = false
reasoning = true
reasoning_options = []
temperature = true
tool_call = true
open_weights = true
@@ -4,6 +4,7 @@ release_date = "2025-03-20"
last_updated = "2025-06-05"
attachment = true
reasoning = true
reasoning_options = []
temperature = true
tool_call = true
knowledge = "2025-01"
@@ -4,6 +4,7 @@ release_date = "2025-03-25"
last_updated = "2025-03-25"
attachment = true
reasoning = true
reasoning_options = []
temperature = true
tool_call = true
knowledge = "2025-01"
@@ -4,6 +4,7 @@ release_date = "2025-12-17"
last_updated = "2025-12-17"
attachment = true
reasoning = true
reasoning_options = []
temperature = true
tool_call = true
knowledge = "2025-01"
@@ -4,6 +4,7 @@ release_date = "2026-03-01"
last_updated = "2026-03-01"
attachment = true
reasoning = true
reasoning_options = []
temperature = true
tool_call = true
structured_output = true
@@ -4,6 +4,7 @@ release_date = "2026-02-19"
last_updated = "2026-02-19"
attachment = true
reasoning = true
reasoning_options = []
temperature = true
tool_call = true
structured_output = true
+1
View File
@@ -4,6 +4,7 @@ release_date = "2025-09-15"
last_updated = "2025-09-15"
attachment = false
reasoning = true
reasoning_options = []
temperature = false
knowledge = "2024-09-30"
tool_call = true
+1
View File
@@ -4,6 +4,7 @@ release_date = "2025-08-07"
last_updated = "2025-08-07"
attachment = true
reasoning = true
reasoning_options = []
temperature = false
knowledge = "2024-05-30"
tool_call = true
+1
View File
@@ -4,6 +4,7 @@ release_date = "2025-08-07"
last_updated = "2025-08-07"
attachment = true
reasoning = true
reasoning_options = []
temperature = false
knowledge = "2024-05-30"
tool_call = true
@@ -4,6 +4,7 @@ release_date = "2025-11-13"
last_updated = "2025-11-13"
attachment = true
reasoning = true
reasoning_options = []
temperature = false
knowledge = "2024-09-30"
tool_call = true
@@ -4,6 +4,7 @@ release_date = "2025-11-13"
last_updated = "2025-11-13"
attachment = true
reasoning = true
reasoning_options = []
temperature = false
knowledge = "2024-09-30"
tool_call = true
@@ -4,6 +4,7 @@ release_date = "2025-11-13"
last_updated = "2025-11-13"
attachment = true
reasoning = true
reasoning_options = []
temperature = false
knowledge = "2024-09-30"
tool_call = true
+1
View File
@@ -4,6 +4,7 @@ release_date = "2025-11-13"
last_updated = "2025-11-13"
attachment = true
reasoning = true
reasoning_options = []
temperature = false
knowledge = "2024-09-30"
tool_call = true
@@ -4,6 +4,7 @@ release_date = "2026-01-01"
last_updated = "2026-01-01"
attachment = true
reasoning = true
reasoning_options = []
temperature = true
knowledge = "2024-09-30"
tool_call = true
@@ -4,6 +4,7 @@ release_date = "2025-12-11"
last_updated = "2025-12-11"
attachment = true
reasoning = true
reasoning_options = []
temperature = false
knowledge = "2025-08-31"
tool_call = true
+1
View File
@@ -4,6 +4,7 @@ release_date = "2025-12-11"
last_updated = "2025-12-11"
attachment = true
reasoning = true
reasoning_options = []
temperature = false
knowledge = "2025-08-31"
tool_call = true
@@ -4,6 +4,7 @@ release_date = "2026-03-01"
last_updated = "2026-03-01"
attachment = true
reasoning = true
reasoning_options = []
temperature = true
tool_call = true
open_weights = false
@@ -4,6 +4,7 @@ release_date = "2026-02-05"
last_updated = "2026-02-05"
attachment = true
reasoning = true
reasoning_options = []
temperature = false
knowledge = "2025-08-31"
tool_call = true
@@ -4,6 +4,7 @@ release_date = "2026-02-05"
last_updated = "2026-02-05"
attachment = true
reasoning = true
reasoning_options = []
temperature = false
knowledge = "2025-08-31"
tool_call = true
+1
View File
@@ -4,6 +4,7 @@ release_date = "2026-03-05"
last_updated = "2026-03-05"
attachment = true
reasoning = true
reasoning_options = []
temperature = false
knowledge = "2025-08-31"
tool_call = true
+1
View File
@@ -4,6 +4,7 @@ release_date = "2025-08-07"
last_updated = "2025-08-07"
attachment = true
reasoning = true
reasoning_options = []
temperature = false
knowledge = "2024-09-30"
tool_call = true
+1
View File
@@ -4,6 +4,7 @@ release_date = "2025-07-09"
last_updated = "2025-07-09"
attachment = true
reasoning = true
reasoning_options = []
temperature = true
tool_call = true
open_weights = false
@@ -1,5 +1,5 @@
name = "Kimi K2 Turbo Preview"
family = "kimi"
family = "kimi-k2"
release_date = "2025-07-08"
last_updated = "2025-07-08"
attachment = false
+2 -1
View File
@@ -1,9 +1,10 @@
name = "Kimi K2.5"
family = "kimi"
family = "kimi-k2"
release_date = "2026-01"
last_updated = "2026-01"
attachment = false
reasoning = true
reasoning_options = []
structured_output = true
temperature = true
tool_call = true
+1
View File
@@ -4,6 +4,7 @@ release_date = "2024-12-20"
last_updated = "2025-01-29"
attachment = false
reasoning = true
reasoning_options = []
temperature = false
knowledge = "2024-05"
tool_call = true
+1
View File
@@ -4,6 +4,7 @@ release_date = "2025-06-10"
last_updated = "2025-06-10"
attachment = true
reasoning = true
reasoning_options = []
temperature = false
knowledge = "2024-05"
tool_call = true
+1
View File
@@ -4,6 +4,7 @@ release_date = "2025-04-16"
last_updated = "2025-04-16"
attachment = true
reasoning = true
reasoning_options = []
temperature = false
knowledge = "2024-05"
tool_call = true
+1
View File
@@ -4,6 +4,7 @@ release_date = "2025-04-16"
last_updated = "2025-04-16"
attachment = true
reasoning = true
reasoning_options = []
temperature = false
knowledge = "2024-05"
tool_call = true
@@ -4,6 +4,7 @@ release_date = "2025-08-05"
last_updated = "2025-08-05"
attachment = true
reasoning = true
reasoning_options = [{ type = "effort", values = ["low", "medium", "high"] }]
temperature = true
tool_call = true
open_weights = true
+1
View File
@@ -4,6 +4,7 @@ release_date = "2025-05-28"
last_updated = "2025-05-28"
attachment = false
reasoning = true
reasoning_options = []
temperature = true
tool_call = true
open_weights = false
@@ -4,6 +4,7 @@ release_date = "2025-07-28"
last_updated = "2025-07-28"
attachment = false
reasoning = true
reasoning_options = []
temperature = true
tool_call = true
open_weights = true
@@ -4,6 +4,7 @@ release_date = "2026-02-11"
last_updated = "2026-02-11"
attachment = false
reasoning = true
reasoning_options = []
temperature = true
tool_call = true
open_weights = true
@@ -1,4 +1,5 @@
base_model = "xiaomi/mimo-v2.5-pro"
reasoning_options = [{ type = "toggle" }]
name = "Coding Xiaomi MiMo-V2.5-Pro"
family = "mimo-v2.5-pro"
last_updated = "2026-05-13"
@@ -1,4 +1,5 @@
base_model = "xiaomi/mimo-v2.5"
reasoning_options = [{ type = "toggle" }]
name = "Coding Xiaomi MiMo-V2.5"
family = "mimo-v2.5"
last_updated = "2026-05-13"
+1 -1
View File
@@ -1,5 +1,5 @@
name = "Kimi K2.5"
family = "kimi-k2.5"
family = "kimi-k2"
release_date = "2026-01"
last_updated = "2026-01"
attachment = true
+1 -1
View File
@@ -1,5 +1,5 @@
name = "Kimi K2.6"
family = "kimi-k2.6"
family = "kimi-k2"
release_date = "2026-04-21"
last_updated = "2026-04-21"
attachment = true
@@ -1,4 +1,5 @@
base_model = "xiaomi/mimo-v2.5"
reasoning_options = [{ type = "toggle" }]
name = "Xiaomi MiMo-V2.5 (free)"
family = "mimo-v2.5"
last_updated = "2026-05-13"
@@ -1,4 +1,5 @@
base_model = "xiaomi/mimo-v2.5-pro"
reasoning_options = [{ type = "toggle" }]
name = "Xiaomi MiMo-V2.5-Pro (free)"
family = "mimo-v2.5-pro"
last_updated = "2026-05-13"
@@ -1,4 +1,5 @@
base_model = "xiaomi/mimo-v2.5-pro"
reasoning_options = [{ type = "toggle" }]
name = "Xiaomi MiMo-V2.5-Pro"
family = "mimo-v2.5-pro"
last_updated = "2026-05-13"
@@ -1,4 +1,5 @@
base_model = "xiaomi/mimo-v2.5"
reasoning_options = [{ type = "toggle" }]
name = "Xiaomi MiMo-V2.5"
family = "mimo-v2.5"
last_updated = "2026-05-13"
@@ -1,5 +1,5 @@
name = "Moonshot Kimi K2 Thinking"
family = "kimi"
family = "kimi-thinking"
release_date = "2025-11-06"
last_updated = "2025-11-06"
attachment = false
+1 -1
View File
@@ -1,5 +1,5 @@
name = "Moonshot Kimi K2.5"
family = "kimi"
family = "kimi-k2"
release_date = "2026-01-27"
last_updated = "2026-01-27"
attachment = false
+1 -1
View File
@@ -1,5 +1,5 @@
name = "Moonshot Kimi K2.6"
family = "kimi"
family = "kimi-k2"
release_date = "2026-04-21"
last_updated = "2026-04-21"
attachment = true
@@ -1,5 +1,5 @@
name = "kimi/kimi-k2.5"
family = "kimi"
family = "kimi-k2"
release_date = "2026-01-27"
last_updated = "2026-01-27"
attachment = false
@@ -1,5 +1,5 @@
name = "Moonshot Kimi K2 Instruct"
family = "kimi"
family = "kimi-k2"
release_date = "2025-01-01"
last_updated = "2025-01-01"
attachment = false
@@ -4,6 +4,7 @@ release_date = "2026-02-12"
last_updated = "2026-02-12"
attachment = false
reasoning = true
reasoning_options = []
temperature = true
tool_call = true
open_weights = true
@@ -4,6 +4,7 @@ release_date = "2025-12-22"
last_updated = "2025-12-22"
attachment = false
reasoning = true
reasoning_options = [{ type = "toggle" }]
temperature = true
tool_call = true
knowledge = "2025-04"
@@ -4,6 +4,7 @@ release_date = "2026-02-11"
last_updated = "2026-02-11"
attachment = false
reasoning = true
reasoning_options = [{ type = "toggle" }]
temperature = true
tool_call = true
open_weights = false
@@ -1,9 +1,10 @@
name = "Kimi K2.5"
family = "kimi"
family = "kimi-k2"
release_date = "2026-01-27"
last_updated = "2026-01-27"
attachment = true
reasoning = true
reasoning_options = [{ type = "toggle" }]
temperature = true
tool_call = true
knowledge = "2025-01"
@@ -4,6 +4,7 @@ release_date = "2026-02-03"
last_updated = "2026-02-03"
attachment = false
reasoning = false
reasoning_options = []
temperature = true
tool_call = true
structured_output = true
@@ -4,6 +4,7 @@ release_date = "2025-07-23"
last_updated = "2025-07-23"
attachment = false
reasoning = false
reasoning_options = []
temperature = true
knowledge = "2025-04"
tool_call = true
@@ -4,6 +4,7 @@ release_date = "2026-01-23"
last_updated = "2026-01-23"
attachment = false
reasoning = false
reasoning_options = [{ type = "toggle" }]
temperature = true
knowledge = "2025-04"
tool_call = true
@@ -4,6 +4,7 @@ release_date = "2026-02-16"
last_updated = "2026-02-16"
attachment = false
reasoning = true
reasoning_options = [{ type = "toggle" }]
temperature = true
knowledge = "2025-04"
tool_call = true
@@ -1,4 +1,5 @@
base_model = "alibaba/qwen3.6-flash"
reasoning_options = [{ type = "toggle" }]
[cost]
input = 0.1875
@@ -4,6 +4,7 @@ release_date = "2026-04-02"
last_updated = "2026-04-02"
attachment = false
reasoning = true
reasoning_options = [{ type = "toggle" }]
temperature = true
knowledge = "2025-04"
tool_call = true
@@ -1,4 +1,5 @@
base_model = "alibaba/qwen3.7-max"
reasoning_options = [{ type = "toggle" }]
[cost]
input = 2.5
@@ -1,4 +1,5 @@
base_model = "alibaba/qwen3.7-plus"
reasoning_options = [{ type = "toggle" }]
[cost]
input = 0

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