diff --git a/models/aion-labs/aion-2.0.toml b/models/aion-labs/aion-2.0.toml new file mode 100644 index 00000000000..3cf31ab3610 --- /dev/null +++ b/models/aion-labs/aion-2.0.toml @@ -0,0 +1,20 @@ +# Lab metadata carried over from providers/openrouter/models/aion-labs/aion-2.0.toml (curated catalogue data already in this repo), +# with provider-specific fields (cost, reasoning_options, status) stripped. +name = "Aion-2.0" +description = "Reasoning model for deliberate analysis, multi-step problem solving, and tool use" +release_date = "2026-02-23" +last_updated = "2026-02-23" +attachment = false +reasoning = true +temperature = true +tool_call = true +structured_output = false +open_weights = false + +[limit] +context = 131072 +output = 32768 + +[modalities] +input = ["text"] +output = ["text"] diff --git a/models/aion-labs/aion-3.0-mini.toml b/models/aion-labs/aion-3.0-mini.toml new file mode 100644 index 00000000000..646234c201e --- /dev/null +++ b/models/aion-labs/aion-3.0-mini.toml @@ -0,0 +1,20 @@ +# Lab metadata carried over from providers/openrouter/models/aion-labs/aion-3.0-mini.toml (curated catalogue data already in this repo), +# with provider-specific fields (cost, reasoning_options, status) stripped. +name = "Aion-3.0-Mini" +description = "Efficient model for low-latency assistance, extraction, and routine automation" +release_date = "2026-07-07" +last_updated = "2026-07-07" +attachment = false +reasoning = true +temperature = true +tool_call = true +structured_output = false +open_weights = false + +[limit] +context = 131072 +output = 32768 + +[modalities] +input = ["text"] +output = ["text"] diff --git a/models/aion-labs/aion-3.0.toml b/models/aion-labs/aion-3.0.toml new file mode 100644 index 00000000000..f20ebc9f86e --- /dev/null +++ b/models/aion-labs/aion-3.0.toml @@ -0,0 +1,20 @@ +# Lab metadata carried over from providers/openrouter/models/aion-labs/aion-3.0.toml (curated catalogue data already in this repo), +# with provider-specific fields (cost, reasoning_options, status) stripped. +name = "Aion-3.0" +description = "Reasoning model for deliberate analysis, multi-step problem solving, and tool use" +release_date = "2026-07-07" +last_updated = "2026-07-07" +attachment = false +reasoning = true +temperature = true +tool_call = true +structured_output = false +open_weights = false + +[limit] +context = 131072 +output = 32768 + +[modalities] +input = ["text"] +output = ["text"] diff --git a/models/aion-labs/aion-rp-llama-3.1-8b.toml b/models/aion-labs/aion-rp-llama-3.1-8b.toml new file mode 100644 index 00000000000..afb7ab2eb2c --- /dev/null +++ b/models/aion-labs/aion-rp-llama-3.1-8b.toml @@ -0,0 +1,22 @@ +# Lab metadata carried over from providers/openrouter/models/aion-labs/aion-rp-llama-3.1-8b.toml (curated catalogue data already in this repo), +# with provider-specific fields (cost, reasoning_options, status) stripped. +name = "Aion-RP 1.0 (8B)" +description = "Open Llama instruction model for multilingual chat, reasoning, and coding" +family = "llama" +release_date = "2025-02-04" +last_updated = "2025-02-04" +knowledge = "2023-12-31" +attachment = false +reasoning = false +temperature = true +tool_call = false +structured_output = false +open_weights = false + +[limit] +context = 32768 +output = 29491 + +[modalities] +input = ["text"] +output = ["text"] diff --git a/models/alibaba/qwen3-max-preview.toml b/models/alibaba/qwen3-max-preview.toml new file mode 100644 index 00000000000..06057747261 --- /dev/null +++ b/models/alibaba/qwen3-max-preview.toml @@ -0,0 +1,21 @@ +# Lab metadata carried over from providers/vercel/models/alibaba/qwen3-max-preview.toml (curated catalogue data already in this repo), +# with provider-specific fields (cost, reasoning_options, status) stripped. +name = "Qwen3 Max Preview" +description = "Flagship Qwen model for complex reasoning, coding, and agentic workflows" +family = "qwen" +release_date = "2025-09-05" +last_updated = "2025-09-23" +knowledge = "2025-04" +attachment = false +reasoning = false +temperature = true +tool_call = true +open_weights = false + +[limit] +context = 262144 +output = 32768 + +[modalities] +input = ["text"] +output = ["text"] diff --git a/models/alibaba/qwen3-vl-flash.toml b/models/alibaba/qwen3-vl-flash.toml new file mode 100644 index 00000000000..44e7e4530c8 --- /dev/null +++ b/models/alibaba/qwen3-vl-flash.toml @@ -0,0 +1,20 @@ +# Lab metadata carried over from providers/llmgateway-providers/models/alibaba/qwen3-vl-flash.toml (curated catalogue data already in this repo), +# with provider-specific fields (cost, reasoning_options, status) stripped. +name = "Qwen3 VL Flash (Alibaba Cloud)" +description = "Qwen vision-language model for visual reasoning, documents, and agent tasks" +release_date = "2025-10-15" +last_updated = "2025-10-15" +attachment = true +reasoning = false +temperature = true +tool_call = true +structured_output = false +open_weights = false + +[limit] +context = 262144 +output = 32768 + +[modalities] +input = ["text", "image"] +output = ["text"] diff --git a/models/amazon/nova-2-lite-v1.toml b/models/amazon/nova-2-lite-v1.toml new file mode 100644 index 00000000000..0443bb39758 --- /dev/null +++ b/models/amazon/nova-2-lite-v1.toml @@ -0,0 +1,21 @@ +# Lab metadata carried over from providers/openrouter/models/amazon/nova-2-lite-v1.toml (curated catalogue data already in this repo), +# with provider-specific fields (cost, reasoning_options, status) stripped. +name = "Nova 2 Lite" +description = "Multimodal reasoning model for visual analysis, planning, and tool use" +family = "nova" +release_date = "2025-12-02" +last_updated = "2025-12-02" +attachment = true +reasoning = true +temperature = true +tool_call = true +structured_output = false +open_weights = false + +[limit] +context = 1000000 +output = 65535 + +[modalities] +input = ["text", "image", "video", "pdf"] +output = ["text"] diff --git a/models/amazon/nova-lite-v1.toml b/models/amazon/nova-lite-v1.toml new file mode 100644 index 00000000000..1e14d079de0 --- /dev/null +++ b/models/amazon/nova-lite-v1.toml @@ -0,0 +1,22 @@ +# Lab metadata carried over from providers/openrouter/models/amazon/nova-lite-v1.toml (curated catalogue data already in this repo), +# with provider-specific fields (cost, reasoning_options, status) stripped. +name = "Nova Lite 1.0" +description = "Efficient model for low-latency assistance, extraction, and routine automation" +family = "nova-lite" +release_date = "2024-12-05" +last_updated = "2024-12-05" +knowledge = "2024-10-31" +attachment = true +reasoning = false +temperature = true +tool_call = true +structured_output = false +open_weights = false + +[limit] +context = 300000 +output = 5120 + +[modalities] +input = ["text", "image"] +output = ["text"] diff --git a/models/amazon/nova-micro-v1.toml b/models/amazon/nova-micro-v1.toml new file mode 100644 index 00000000000..99a208da255 --- /dev/null +++ b/models/amazon/nova-micro-v1.toml @@ -0,0 +1,22 @@ +# Lab metadata carried over from providers/openrouter/models/amazon/nova-micro-v1.toml (curated catalogue data already in this repo), +# with provider-specific fields (cost, reasoning_options, status) stripped. +name = "Nova Micro 1.0" +description = "Efficient model for low-latency assistance, extraction, and routine automation" +family = "nova-micro" +release_date = "2024-12-05" +last_updated = "2024-12-05" +knowledge = "2024-10-31" +attachment = false +reasoning = false +temperature = true +tool_call = true +structured_output = false +open_weights = false + +[limit] +context = 128000 +output = 5120 + +[modalities] +input = ["text"] +output = ["text"] diff --git a/models/amazon/nova-pro-v1.toml b/models/amazon/nova-pro-v1.toml new file mode 100644 index 00000000000..c79a705e822 --- /dev/null +++ b/models/amazon/nova-pro-v1.toml @@ -0,0 +1,22 @@ +# Lab metadata carried over from providers/openrouter/models/amazon/nova-pro-v1.toml (curated catalogue data already in this repo), +# with provider-specific fields (cost, reasoning_options, status) stripped. +name = "Nova Pro 1.0" +description = "Flagship model for demanding analysis, coding, and production agent workflows" +family = "nova-pro" +release_date = "2024-12-05" +last_updated = "2024-12-05" +knowledge = "2024-10-31" +attachment = true +reasoning = false +temperature = true +tool_call = true +structured_output = false +open_weights = false + +[limit] +context = 300000 +output = 5120 + +[modalities] +input = ["text", "image"] +output = ["text"] diff --git a/models/anthracite-org/magnum-v4-72b.toml b/models/anthracite-org/magnum-v4-72b.toml new file mode 100644 index 00000000000..1db329fbb63 --- /dev/null +++ b/models/anthracite-org/magnum-v4-72b.toml @@ -0,0 +1,21 @@ +# Lab metadata carried over from providers/openrouter/models/anthracite-org/magnum-v4-72b.toml (curated catalogue data already in this repo), +# with provider-specific fields (cost, reasoning_options, status) stripped. +name = "Magnum v4 72B" +description = "Open-weight instruction model for adaptable chat and self-hosted production workloads" +release_date = "2024-10-22" +last_updated = "2024-10-22" +knowledge = "2024-06-30" +attachment = false +reasoning = false +temperature = true +tool_call = false +structured_output = true +open_weights = true + +[limit] +context = 32768 +output = 4096 + +[modalities] +input = ["text"] +output = ["text"] diff --git a/models/baidu/ernie-4.5-vl-424b-a47b.toml b/models/baidu/ernie-4.5-vl-424b-a47b.toml new file mode 100644 index 00000000000..fc22e5ef9e1 --- /dev/null +++ b/models/baidu/ernie-4.5-vl-424b-a47b.toml @@ -0,0 +1,22 @@ +# Lab metadata carried over from providers/openrouter/models/baidu/ernie-4.5-vl-424b-a47b.toml (curated catalogue data already in this repo), +# with provider-specific fields (cost, reasoning_options, status) stripped. +name = "ERNIE 4.5 VL 424B A47B " +description = "Multimodal reasoning model for visual analysis, planning, and tool use" +family = "ernie" +release_date = "2025-06-30" +last_updated = "2025-06-30" +knowledge = "2025-03-31" +attachment = true +reasoning = true +temperature = true +tool_call = false +structured_output = false +open_weights = true + +[limit] +context = 123000 +output = 16000 + +[modalities] +input = ["image", "text"] +output = ["text"] diff --git a/models/cognitivecomputations/dolphin-mistral-24b-venice-edition.toml b/models/cognitivecomputations/dolphin-mistral-24b-venice-edition.toml new file mode 100644 index 00000000000..82363cdc7de --- /dev/null +++ b/models/cognitivecomputations/dolphin-mistral-24b-venice-edition.toml @@ -0,0 +1,22 @@ +# Lab metadata carried over from providers/openrouter/models/cognitivecomputations/dolphin-mistral-24b-venice-edition.toml (curated catalogue data already in this repo), +# with provider-specific fields (cost, reasoning_options, status) stripped. +name = "Uncensored" +description = "Mistral model for multilingual chat, reasoning, and tool-assisted workflows" +family = "mistral" +release_date = "2025-07-09" +last_updated = "2025-07-09" +knowledge = "2024-04-30" +attachment = false +reasoning = false +temperature = true +tool_call = false +structured_output = false +open_weights = true + +[limit] +context = 128000 +output = 8192 + +[modalities] +input = ["text"] +output = ["text"] diff --git a/models/cohere/command-a.toml b/models/cohere/command-a.toml new file mode 100644 index 00000000000..7d0079a0762 --- /dev/null +++ b/models/cohere/command-a.toml @@ -0,0 +1,22 @@ +# Lab metadata carried over from providers/openrouter/models/cohere/command-a.toml (curated catalogue data already in this repo), +# with provider-specific fields (cost, reasoning_options, status) stripped. +name = "Command A" +description = "Cohere command model for multilingual enterprise agents, tools, and chat" +family = "command-a" +release_date = "2025-03-13" +last_updated = "2025-03-13" +knowledge = "2024-08-31" +attachment = false +reasoning = false +temperature = true +tool_call = false +structured_output = true +open_weights = true + +[limit] +context = 256000 +output = 8192 + +[modalities] +input = ["text"] +output = ["text"] diff --git a/models/deepseek/deepseek-chat-v3-0324.toml b/models/deepseek/deepseek-chat-v3-0324.toml new file mode 100644 index 00000000000..a0496bf6d8b --- /dev/null +++ b/models/deepseek/deepseek-chat-v3-0324.toml @@ -0,0 +1,22 @@ +# Lab metadata carried over from providers/openrouter/models/deepseek/deepseek-chat-v3-0324.toml (curated catalogue data already in this repo), +# with provider-specific fields (cost, reasoning_options, status) stripped. +name = "DeepSeek V3 0324" +description = "DeepSeek chat model for instruction following, coding, and analysis" +family = "deepseek" +release_date = "2025-03-24" +last_updated = "2025-03-24" +knowledge = "2024-07-31" +attachment = false +reasoning = false +temperature = true +tool_call = true +structured_output = true +open_weights = true + +[limit] +context = 163840 +output = 147456 + +[modalities] +input = ["text"] +output = ["text"] diff --git a/models/deepseek/deepseek-chat-v3.1.toml b/models/deepseek/deepseek-chat-v3.1.toml new file mode 100644 index 00000000000..ad5acf3be28 --- /dev/null +++ b/models/deepseek/deepseek-chat-v3.1.toml @@ -0,0 +1,22 @@ +# Lab metadata carried over from providers/openrouter/models/deepseek/deepseek-chat-v3.1.toml (curated catalogue data already in this repo), +# with provider-specific fields (cost, reasoning_options, status) stripped. +name = "DeepSeek V3.1" +description = "DeepSeek chat model for instruction following, coding, and analysis" +family = "deepseek" +release_date = "2025-08-21" +last_updated = "2025-08-21" +knowledge = "2025-03-31" +attachment = false +reasoning = true +temperature = true +tool_call = true +structured_output = true +open_weights = true + +[limit] +context = 163840 +output = 32768 + +[modalities] +input = ["text"] +output = ["text"] diff --git a/models/google/gemini-2.5-pro-preview.toml b/models/google/gemini-2.5-pro-preview.toml new file mode 100644 index 00000000000..bb1b5d96ac2 --- /dev/null +++ b/models/google/gemini-2.5-pro-preview.toml @@ -0,0 +1,22 @@ +# Lab metadata carried over from providers/openrouter/models/google/gemini-2.5-pro-preview.toml (curated catalogue data already in this repo), +# with provider-specific fields (cost, reasoning_options, status) stripped. +name = "Gemini 2.5 Pro Preview 06-05" +description = "Advanced Gemini model for complex reasoning, coding, and multimodal analysis" +family = "gemini" +release_date = "2025-06-05" +last_updated = "2025-06-05" +knowledge = "2025-01-31" +attachment = true +reasoning = true +temperature = true +tool_call = true +structured_output = true +open_weights = false + +[limit] +context = 1048576 +output = 65536 + +[modalities] +input = ["pdf", "image", "text", "audio"] +output = ["text"] diff --git a/models/google/gemma-2-27b-it.toml b/models/google/gemma-2-27b-it.toml new file mode 100644 index 00000000000..f8cf6cdb0b8 --- /dev/null +++ b/models/google/gemma-2-27b-it.toml @@ -0,0 +1,22 @@ +# Lab metadata carried over from providers/openrouter/models/google/gemma-2-27b-it.toml (curated catalogue data already in this repo), +# with provider-specific fields (cost, reasoning_options, status) stripped. +name = "Gemma 2 27B" +description = "Open Gemma instruction model for efficient chat and self-hosted deployments" +family = "gemma" +release_date = "2024-07-13" +last_updated = "2024-07-13" +knowledge = "2024-06-30" +attachment = false +reasoning = false +temperature = true +tool_call = false +structured_output = true +open_weights = true + +[limit] +context = 8192 +output = 2048 + +[modalities] +input = ["text"] +output = ["text"] diff --git a/models/ibm/granite-4.2-8b.toml b/models/ibm/granite-4.2-8b.toml new file mode 100644 index 00000000000..e00d5060dbb --- /dev/null +++ b/models/ibm/granite-4.2-8b.toml @@ -0,0 +1,21 @@ +# Lab metadata carried over from providers/openrouter/models/ibm-granite/granite-4.2-8b.toml (curated catalogue data already in this repo), +# with provider-specific fields (cost, reasoning_options, status) stripped. +name = "Granite 4.2 8B" +description = "Reasoning model for deliberate analysis, multi-step problem solving, and tool use" +family = "granite" +release_date = "2026-08-31" +last_updated = "2026-08-31" +attachment = false +reasoning = true +temperature = true +tool_call = true +structured_output = true +open_weights = true + +[limit] +context = 131072 +output = 117964 + +[modalities] +input = ["text"] +output = ["text"] diff --git a/models/inception/mercury-2.5.toml b/models/inception/mercury-2.5.toml new file mode 100644 index 00000000000..b2f2957d8d1 --- /dev/null +++ b/models/inception/mercury-2.5.toml @@ -0,0 +1,21 @@ +# Lab metadata carried over from providers/openrouter/models/inception/mercury-2.5.toml (curated catalogue data already in this repo), +# with provider-specific fields (cost, reasoning_options, status) stripped. +name = "Mercury 2.5" +description = "Reasoning model for deliberate analysis, multi-step problem solving, and tool use" +family = "mercury" +release_date = "2026-09-08" +last_updated = "2026-09-08" +attachment = false +reasoning = true +temperature = true +tool_call = true +structured_output = true +open_weights = false + +[limit] +context = 260000 +output = 65536 + +[modalities] +input = ["text"] +output = ["text"] diff --git a/models/inception/mercury-2.toml b/models/inception/mercury-2.toml new file mode 100644 index 00000000000..875dc491ba7 --- /dev/null +++ b/models/inception/mercury-2.toml @@ -0,0 +1,21 @@ +# Lab metadata carried over from providers/openrouter/models/inception/mercury-2.toml (curated catalogue data already in this repo), +# with provider-specific fields (cost, reasoning_options, status) stripped. +name = "Mercury 2" +description = "Reasoning model for deliberate analysis, multi-step problem solving, and tool use" +family = "mercury" +release_date = "2026-03-04" +last_updated = "2026-03-04" +attachment = false +reasoning = true +temperature = true +tool_call = true +structured_output = true +open_weights = false + +[limit] +context = 128000 +output = 50000 + +[modalities] +input = ["text"] +output = ["text"] diff --git a/models/inference-net/schematron-v2-small.toml b/models/inference-net/schematron-v2-small.toml new file mode 100644 index 00000000000..db75e4ba5a1 --- /dev/null +++ b/models/inference-net/schematron-v2-small.toml @@ -0,0 +1,20 @@ +# Lab metadata carried over from providers/openrouter/models/inference-net/schematron-v2-small.toml (curated catalogue data already in this repo), +# with provider-specific fields (cost, reasoning_options, status) stripped. +name = "Schematron V2 Small" +description = "Efficient model for low-latency assistance, extraction, and routine automation" +release_date = "2026-09-12" +last_updated = "2026-09-12" +attachment = false +reasoning = false +temperature = true +tool_call = false +structured_output = true +open_weights = true + +[limit] +context = 128000 +output = 4096 + +[modalities] +input = ["text"] +output = ["text"] diff --git a/models/inference-net/schematron-v2-turbo.toml b/models/inference-net/schematron-v2-turbo.toml new file mode 100644 index 00000000000..d30a503287e --- /dev/null +++ b/models/inference-net/schematron-v2-turbo.toml @@ -0,0 +1,20 @@ +# Lab metadata carried over from providers/openrouter/models/inference-net/schematron-v2-turbo.toml (curated catalogue data already in this repo), +# with provider-specific fields (cost, reasoning_options, status) stripped. +name = "Schematron V2 Turbo" +description = "Efficient model for low-latency assistance, extraction, and routine automation" +release_date = "2026-09-12" +last_updated = "2026-09-12" +attachment = false +reasoning = false +temperature = true +tool_call = false +structured_output = true +open_weights = true + +[limit] +context = 128000 +output = 8192 + +[modalities] +input = ["text"] +output = ["text"] diff --git a/models/mancer/weaver.toml b/models/mancer/weaver.toml new file mode 100644 index 00000000000..271079aa01c --- /dev/null +++ b/models/mancer/weaver.toml @@ -0,0 +1,22 @@ +# Lab metadata carried over from providers/openrouter/models/mancer/weaver.toml (curated catalogue data already in this repo), +# with provider-specific fields (cost, reasoning_options, status) stripped. +name = "Weaver (alpha)" +description = "General-purpose chat model for instruction following, writing, and analysis" +family = "alpha" +release_date = "2023-08-02" +last_updated = "2023-08-02" +knowledge = "2023-06-30" +attachment = false +reasoning = false +temperature = true +tool_call = false +structured_output = false +open_weights = false + +[limit] +context = 8000 +output = 6000 + +[modalities] +input = ["text"] +output = ["text"] diff --git a/models/minimax/MiniMax-Text-01.toml b/models/minimax/MiniMax-Text-01.toml new file mode 100644 index 00000000000..70fd9bb3666 --- /dev/null +++ b/models/minimax/MiniMax-Text-01.toml @@ -0,0 +1,21 @@ +# Lab metadata carried over from providers/llmgateway-providers/models/minimax/MiniMax-Text-01.toml (curated catalogue data already in this repo), +# with provider-specific fields (cost, reasoning_options, status) stripped. +name = "MiniMax Text 01 (MiniMax)" +description = "MiniMax model for chat, coding, office work, and agentic tasks" +family = "minimax" +release_date = "2025-01-15" +last_updated = "2025-01-15" +attachment = false +reasoning = true +temperature = true +tool_call = true +structured_output = false +open_weights = false + +[limit] +context = 1000000 +output = 131072 + +[modalities] +input = ["text"] +output = ["text"] diff --git a/models/mistral/ministral-14b-2512.toml b/models/mistral/ministral-14b-2512.toml new file mode 100644 index 00000000000..a9cd5751fd3 --- /dev/null +++ b/models/mistral/ministral-14b-2512.toml @@ -0,0 +1,21 @@ +# Lab metadata carried over from providers/openrouter/models/mistralai/ministral-14b-2512.toml (curated catalogue data already in this repo), +# with provider-specific fields (cost, reasoning_options, status) stripped. +name = "Ministral 3 14B 2512" +description = "Compact Mistral model for edge, latency-sensitive, and cost-efficient workloads" +family = "ministral" +release_date = "2025-12-02" +last_updated = "2025-12-02" +attachment = true +reasoning = false +temperature = true +tool_call = true +structured_output = true +open_weights = true + +[limit] +context = 262144 +output = 209715 + +[modalities] +input = ["text", "image"] +output = ["text"] diff --git a/models/mistral/ministral-3b-2512.toml b/models/mistral/ministral-3b-2512.toml new file mode 100644 index 00000000000..59ebacedfe2 --- /dev/null +++ b/models/mistral/ministral-3b-2512.toml @@ -0,0 +1,21 @@ +# Lab metadata carried over from providers/openrouter/models/mistralai/ministral-3b-2512.toml (curated catalogue data already in this repo), +# with provider-specific fields (cost, reasoning_options, status) stripped. +name = "Ministral 3 3B 2512" +description = "Compact Mistral model for edge, latency-sensitive, and cost-efficient workloads" +family = "ministral" +release_date = "2025-12-02" +last_updated = "2025-12-02" +attachment = true +reasoning = false +temperature = true +tool_call = true +structured_output = true +open_weights = true + +[limit] +context = 131072 +output = 104857 + +[modalities] +input = ["text", "image"] +output = ["text"] diff --git a/models/mistral/ministral-8b-2512.toml b/models/mistral/ministral-8b-2512.toml new file mode 100644 index 00000000000..58fc7b588b7 --- /dev/null +++ b/models/mistral/ministral-8b-2512.toml @@ -0,0 +1,21 @@ +# Lab metadata carried over from providers/openrouter/models/mistralai/ministral-8b-2512.toml (curated catalogue data already in this repo), +# with provider-specific fields (cost, reasoning_options, status) stripped. +name = "Ministral 3 8B 2512" +description = "Compact Mistral model for edge, latency-sensitive, and cost-efficient workloads" +family = "ministral" +release_date = "2025-12-02" +last_updated = "2025-12-02" +attachment = true +reasoning = false +temperature = true +tool_call = true +structured_output = true +open_weights = true + +[limit] +context = 262144 +output = 209715 + +[modalities] +input = ["text", "image"] +output = ["text"] diff --git a/models/mistral/mistral-large-2407.toml b/models/mistral/mistral-large-2407.toml new file mode 100644 index 00000000000..3729790b144 --- /dev/null +++ b/models/mistral/mistral-large-2407.toml @@ -0,0 +1,22 @@ +# Lab metadata carried over from providers/openrouter/models/mistralai/mistral-large-2407.toml (curated catalogue data already in this repo), +# with provider-specific fields (cost, reasoning_options, status) stripped. +name = "Mistral Large 2407" +description = "Flagship Mistral model for advanced reasoning, coding, and multilingual work" +family = "mistral-large" +release_date = "2024-11-19" +last_updated = "2024-11-19" +knowledge = "2024-03-31" +attachment = true +reasoning = false +temperature = true +tool_call = true +structured_output = true +open_weights = false + +[limit] +context = 131072 +output = 104857 + +[modalities] +input = ["text", "pdf"] +output = ["text"] diff --git a/models/mistral/mistral-large.toml b/models/mistral/mistral-large.toml new file mode 100644 index 00000000000..5d4ccec0915 --- /dev/null +++ b/models/mistral/mistral-large.toml @@ -0,0 +1,22 @@ +# Lab metadata carried over from providers/openrouter/models/mistralai/mistral-large.toml (curated catalogue data already in this repo), +# with provider-specific fields (cost, reasoning_options, status) stripped. +name = "Mistral Large" +description = "Flagship Mistral model for advanced reasoning, coding, and multilingual work" +family = "mistral-large" +release_date = "2024-02-26" +last_updated = "2024-02-26" +knowledge = "2024-11-30" +attachment = true +reasoning = false +temperature = true +tool_call = true +structured_output = true +open_weights = false + +[limit] +context = 128000 +output = 102400 + +[modalities] +input = ["text", "pdf"] +output = ["text"] diff --git a/models/mistral/mistral-medium-3-5.toml b/models/mistral/mistral-medium-3-5.toml new file mode 100644 index 00000000000..57476a14c10 --- /dev/null +++ b/models/mistral/mistral-medium-3-5.toml @@ -0,0 +1,21 @@ +# Lab metadata carried over from providers/openrouter/models/mistralai/mistral-medium-3-5.toml (curated catalogue data already in this repo), +# with provider-specific fields (cost, reasoning_options, status) stripped. +name = "Mistral Medium 3.5" +description = "Mistral model for multilingual chat, reasoning, and tool-assisted workflows" +family = "mistral-medium" +release_date = "2026-04-30" +last_updated = "2026-04-30" +attachment = true +reasoning = true +temperature = true +tool_call = true +structured_output = true +open_weights = false + +[limit] +context = 262144 +output = 209715 + +[modalities] +input = ["text", "image", "pdf"] +output = ["text"] diff --git a/models/mistral/mistral-medium-3.1.toml b/models/mistral/mistral-medium-3.1.toml new file mode 100644 index 00000000000..99d1d2e7a0b --- /dev/null +++ b/models/mistral/mistral-medium-3.1.toml @@ -0,0 +1,22 @@ +# Lab metadata carried over from providers/openrouter/models/mistralai/mistral-medium-3.1.toml (curated catalogue data already in this repo), +# with provider-specific fields (cost, reasoning_options, status) stripped. +name = "Mistral Medium 3.1" +description = "Mistral model for multilingual chat, reasoning, and tool-assisted workflows" +family = "mistral-medium" +release_date = "2025-08-13" +last_updated = "2025-08-13" +knowledge = "2025-06-30" +attachment = true +reasoning = false +temperature = true +tool_call = true +structured_output = true +open_weights = false + +[limit] +context = 131072 +output = 104857 + +[modalities] +input = ["text", "image", "pdf"] +output = ["text"] diff --git a/models/mistral/mistral-medium-3.toml b/models/mistral/mistral-medium-3.toml new file mode 100644 index 00000000000..f76a8c3a676 --- /dev/null +++ b/models/mistral/mistral-medium-3.toml @@ -0,0 +1,22 @@ +# Lab metadata carried over from providers/openrouter/models/mistralai/mistral-medium-3.toml (curated catalogue data already in this repo), +# with provider-specific fields (cost, reasoning_options, status) stripped. +name = "Mistral Medium 3" +description = "Mistral model for multilingual chat, reasoning, and tool-assisted workflows" +family = "mistral-medium" +release_date = "2025-05-07" +last_updated = "2025-05-07" +knowledge = "2025-03-31" +attachment = true +reasoning = false +temperature = true +tool_call = true +structured_output = true +open_weights = false + +[limit] +context = 131072 +output = 104857 + +[modalities] +input = ["text", "image", "pdf"] +output = ["text"] diff --git a/models/mistral/mistral-saba.toml b/models/mistral/mistral-saba.toml new file mode 100644 index 00000000000..c484b1b8336 --- /dev/null +++ b/models/mistral/mistral-saba.toml @@ -0,0 +1,22 @@ +# Lab metadata carried over from providers/openrouter/models/mistralai/mistral-saba.toml (curated catalogue data already in this repo), +# with provider-specific fields (cost, reasoning_options, status) stripped. +name = "Saba" +description = "Mistral model for multilingual chat, reasoning, and tool-assisted workflows" +family = "mistral" +release_date = "2025-02-17" +last_updated = "2025-02-17" +knowledge = "2024-09-30" +attachment = true +reasoning = false +temperature = true +tool_call = true +structured_output = true +open_weights = false + +[limit] +context = 32768 +output = 26214 + +[modalities] +input = ["text", "pdf"] +output = ["text"] diff --git a/models/mistral/mistral-small-24b-instruct-2501.toml b/models/mistral/mistral-small-24b-instruct-2501.toml new file mode 100644 index 00000000000..6ee179d84fe --- /dev/null +++ b/models/mistral/mistral-small-24b-instruct-2501.toml @@ -0,0 +1,22 @@ +# Lab metadata carried over from providers/openrouter/models/mistralai/mistral-small-24b-instruct-2501.toml (curated catalogue data already in this repo), +# with provider-specific fields (cost, reasoning_options, status) stripped. +name = "Mistral Small 3" +description = "Efficient Mistral model for fast chat, extraction, and production assistants" +family = "mistral-small" +release_date = "2025-01-30" +last_updated = "2025-01-30" +knowledge = "2023-10-31" +attachment = false +reasoning = false +temperature = true +tool_call = false +structured_output = true +open_weights = true + +[limit] +context = 32768 +output = 16384 + +[modalities] +input = ["text"] +output = ["text"] diff --git a/models/mistral/mistral-small-3.1-24b-instruct.toml b/models/mistral/mistral-small-3.1-24b-instruct.toml new file mode 100644 index 00000000000..5ea4bbce239 --- /dev/null +++ b/models/mistral/mistral-small-3.1-24b-instruct.toml @@ -0,0 +1,22 @@ +# Lab metadata carried over from providers/openrouter/models/mistralai/mistral-small-3.1-24b-instruct.toml (curated catalogue data already in this repo), +# with provider-specific fields (cost, reasoning_options, status) stripped. +name = "Mistral Small 3.1 24B" +description = "Efficient Mistral model for fast chat, extraction, and production assistants" +family = "mistral-small" +release_date = "2025-03-17" +last_updated = "2025-03-17" +knowledge = "2023-10-31" +attachment = true +reasoning = false +temperature = true +tool_call = false +structured_output = false +open_weights = true + +[limit] +context = 128000 +output = 102400 + +[modalities] +input = ["text", "image"] +output = ["text"] diff --git a/models/mistral/mistral-small-3.2-24b-instruct.toml b/models/mistral/mistral-small-3.2-24b-instruct.toml new file mode 100644 index 00000000000..a2bde0dd2f3 --- /dev/null +++ b/models/mistral/mistral-small-3.2-24b-instruct.toml @@ -0,0 +1,22 @@ +# Lab metadata carried over from providers/openrouter/models/mistralai/mistral-small-3.2-24b-instruct.toml (curated catalogue data already in this repo), +# with provider-specific fields (cost, reasoning_options, status) stripped. +name = "Mistral Small 3.2 24B" +description = "Efficient Mistral model for fast chat, extraction, and production assistants" +family = "mistral-small" +release_date = "2025-06-20" +last_updated = "2025-06-20" +knowledge = "2023-10-31" +attachment = true +reasoning = false +temperature = true +tool_call = true +structured_output = true +open_weights = true + +[limit] +context = 256000 +output = 16384 + +[modalities] +input = ["image", "text"] +output = ["text"] diff --git a/models/mistral/mixtral-8x22b-instruct.toml b/models/mistral/mixtral-8x22b-instruct.toml new file mode 100644 index 00000000000..e4e5d1c2752 --- /dev/null +++ b/models/mistral/mixtral-8x22b-instruct.toml @@ -0,0 +1,22 @@ +# Lab metadata carried over from providers/openrouter/models/mistralai/mixtral-8x22b-instruct.toml (curated catalogue data already in this repo), +# with provider-specific fields (cost, reasoning_options, status) stripped. +name = "Mixtral 8x22B Instruct" +description = "Mistral model for multilingual chat, reasoning, and tool-assisted workflows" +family = "mistral" +release_date = "2024-04-17" +last_updated = "2024-04-17" +knowledge = "2024-01-31" +attachment = true +reasoning = false +temperature = true +tool_call = true +structured_output = true +open_weights = true + +[limit] +context = 65536 +output = 52428 + +[modalities] +input = ["text", "pdf"] +output = ["text"] diff --git a/models/moonshotai/kimi-k2.toml b/models/moonshotai/kimi-k2.toml new file mode 100644 index 00000000000..56672ef5fce --- /dev/null +++ b/models/moonshotai/kimi-k2.toml @@ -0,0 +1,22 @@ +# Lab metadata carried over from providers/openrouter/models/moonshotai/kimi-k2.toml (curated catalogue data already in this repo), +# with provider-specific fields (cost, reasoning_options, status) stripped. +name = "Kimi K2 0711" +description = "Kimi model for long-context chat, coding, and agentic reasoning" +family = "kimi-k2" +release_date = "2025-07-11" +last_updated = "2025-07-11" +knowledge = "2024-12-31" +attachment = false +reasoning = false +temperature = true +tool_call = true +structured_output = false +open_weights = true + +[limit] +context = 131072 +output = 98304 + +[modalities] +input = ["text"] +output = ["text"] diff --git a/models/morph/morph-v3-fast.toml b/models/morph/morph-v3-fast.toml new file mode 100644 index 00000000000..9cc00d00f92 --- /dev/null +++ b/models/morph/morph-v3-fast.toml @@ -0,0 +1,21 @@ +# Lab metadata carried over from providers/openrouter/models/morph/morph-v3-fast.toml (curated catalogue data already in this repo), +# with provider-specific fields (cost, reasoning_options, status) stripped. +name = "Morph V3 Fast" +description = "Efficient model for low-latency assistance, extraction, and routine automation" +family = "morph" +release_date = "2025-07-07" +last_updated = "2025-07-07" +attachment = false +reasoning = false +temperature = true +tool_call = false +structured_output = false +open_weights = false + +[limit] +context = 81920 +output = 38000 + +[modalities] +input = ["text"] +output = ["text"] diff --git a/models/morph/morph-v3-large.toml b/models/morph/morph-v3-large.toml new file mode 100644 index 00000000000..bd5153753eb --- /dev/null +++ b/models/morph/morph-v3-large.toml @@ -0,0 +1,21 @@ +# Lab metadata carried over from providers/openrouter/models/morph/morph-v3-large.toml (curated catalogue data already in this repo), +# with provider-specific fields (cost, reasoning_options, status) stripped. +name = "Morph V3 Large" +description = "Flagship model for demanding analysis, coding, and production agent workflows" +family = "morph" +release_date = "2025-07-07" +last_updated = "2025-07-07" +attachment = false +reasoning = false +temperature = true +tool_call = false +structured_output = true +open_weights = false + +[limit] +context = 262144 +output = 131072 + +[modalities] +input = ["text"] +output = ["text"] diff --git a/models/nousresearch/hermes-3-llama-3.1-405b.toml b/models/nousresearch/hermes-3-llama-3.1-405b.toml new file mode 100644 index 00000000000..c610bdab6b2 --- /dev/null +++ b/models/nousresearch/hermes-3-llama-3.1-405b.toml @@ -0,0 +1,22 @@ +# Lab metadata carried over from providers/openrouter/models/nousresearch/hermes-3-llama-3.1-405b.toml (curated catalogue data already in this repo), +# with provider-specific fields (cost, reasoning_options, status) stripped. +name = "Hermes 3 405B Instruct" +description = "Open Llama instruction model for multilingual chat, reasoning, and coding" +family = "nousresearch" +release_date = "2024-08-16" +last_updated = "2024-08-16" +knowledge = "2023-12-31" +attachment = false +reasoning = false +temperature = true +tool_call = false +structured_output = true +open_weights = true + +[limit] +context = 131072 +output = 16384 + +[modalities] +input = ["text"] +output = ["text"] diff --git a/models/nousresearch/hermes-3-llama-3.1-70b.toml b/models/nousresearch/hermes-3-llama-3.1-70b.toml new file mode 100644 index 00000000000..f18593e9fe0 --- /dev/null +++ b/models/nousresearch/hermes-3-llama-3.1-70b.toml @@ -0,0 +1,22 @@ +# Lab metadata carried over from providers/openrouter/models/nousresearch/hermes-3-llama-3.1-70b.toml (curated catalogue data already in this repo), +# with provider-specific fields (cost, reasoning_options, status) stripped. +name = "Hermes 3 70B Instruct" +description = "Open Llama instruction model for multilingual chat, reasoning, and coding" +family = "nousresearch" +release_date = "2024-08-18" +last_updated = "2024-08-18" +knowledge = "2023-12-31" +attachment = false +reasoning = false +temperature = true +tool_call = false +structured_output = true +open_weights = true + +[limit] +context = 131072 +output = 16384 + +[modalities] +input = ["text"] +output = ["text"] diff --git a/models/nousresearch/hermes-4-405b.toml b/models/nousresearch/hermes-4-405b.toml new file mode 100644 index 00000000000..8566af3e161 --- /dev/null +++ b/models/nousresearch/hermes-4-405b.toml @@ -0,0 +1,22 @@ +# Lab metadata carried over from providers/openrouter/models/nousresearch/hermes-4-405b.toml (curated catalogue data already in this repo), +# with provider-specific fields (cost, reasoning_options, status) stripped. +name = "Hermes 4 405B" +description = "Reasoning model for deliberate analysis, multi-step problem solving, and tool use" +family = "hermes" +release_date = "2025-08-26" +last_updated = "2025-08-26" +knowledge = "2024-08-31" +attachment = false +reasoning = true +temperature = true +tool_call = false +structured_output = false +open_weights = true + +[limit] +context = 131072 +output = 117964 + +[modalities] +input = ["text"] +output = ["text"] diff --git a/models/openai/gpt-5-image-mini.toml b/models/openai/gpt-5-image-mini.toml new file mode 100644 index 00000000000..aeb9a697038 --- /dev/null +++ b/models/openai/gpt-5-image-mini.toml @@ -0,0 +1,21 @@ +# Lab metadata carried over from providers/openrouter/models/openai/gpt-5-image-mini.toml (curated catalogue data already in this repo), +# with provider-specific fields (cost, reasoning_options, status) stripped. +name = "GPT-5 Image Mini" +description = "Image model for prompt-driven generation, editing, and visual design workflows" +family = "gpt" +release_date = "2025-10-16" +last_updated = "2025-10-16" +attachment = true +reasoning = true +temperature = true +tool_call = false +structured_output = true +open_weights = false + +[limit] +context = 400000 +output = 128000 + +[modalities] +input = ["pdf", "image", "text"] +output = ["image", "text"] diff --git a/models/openai/gpt-5-image.toml b/models/openai/gpt-5-image.toml new file mode 100644 index 00000000000..e693778b102 --- /dev/null +++ b/models/openai/gpt-5-image.toml @@ -0,0 +1,22 @@ +# Lab metadata carried over from providers/openrouter/models/openai/gpt-5-image.toml (curated catalogue data already in this repo), +# with provider-specific fields (cost, reasoning_options, status) stripped. +name = "GPT-5 Image" +description = "Image model for prompt-driven generation, editing, and visual design workflows" +family = "gpt" +release_date = "2025-10-14" +last_updated = "2025-10-14" +knowledge = "2024-10-01" +attachment = true +reasoning = true +temperature = true +tool_call = false +structured_output = true +open_weights = false + +[limit] +context = 400000 +output = 128000 + +[modalities] +input = ["image", "text", "pdf"] +output = ["image", "text"] diff --git a/models/openai/gpt-5.4-image-2.toml b/models/openai/gpt-5.4-image-2.toml new file mode 100644 index 00000000000..14841bb730a --- /dev/null +++ b/models/openai/gpt-5.4-image-2.toml @@ -0,0 +1,21 @@ +# Lab metadata carried over from providers/openrouter/models/openai/gpt-5.4-image-2.toml (curated catalogue data already in this repo), +# with provider-specific fields (cost, reasoning_options, status) stripped. +name = "GPT-5.4 Image 2" +description = "Image model for prompt-driven generation, editing, and visual design workflows" +family = "gpt" +release_date = "2026-04-21" +last_updated = "2026-04-21" +attachment = true +reasoning = true +temperature = false +tool_call = false +structured_output = true +open_weights = false + +[limit] +context = 272000 +output = 128000 + +[modalities] +input = ["image", "text", "pdf"] +output = ["image", "text"] diff --git a/models/perceptron/perceptron-mk1.toml b/models/perceptron/perceptron-mk1.toml new file mode 100644 index 00000000000..749030e5910 --- /dev/null +++ b/models/perceptron/perceptron-mk1.toml @@ -0,0 +1,20 @@ +# Lab metadata carried over from providers/openrouter/models/perceptron/perceptron-mk1.toml (curated catalogue data already in this repo), +# with provider-specific fields (cost, reasoning_options, status) stripped. +name = "Perceptron Mk1" +description = "Multimodal reasoning model for visual analysis, planning, and tool use" +release_date = "2026-05-12" +last_updated = "2026-05-12" +attachment = true +reasoning = true +temperature = true +tool_call = false +structured_output = true +open_weights = false + +[limit] +context = 32768 +output = 8192 + +[modalities] +input = ["text", "image", "video"] +output = ["text"] diff --git a/models/rekaai/reka-edge.toml b/models/rekaai/reka-edge.toml new file mode 100644 index 00000000000..9c864e0c372 --- /dev/null +++ b/models/rekaai/reka-edge.toml @@ -0,0 +1,21 @@ +# Lab metadata carried over from providers/openrouter/models/rekaai/reka-edge.toml (curated catalogue data already in this repo), +# with provider-specific fields (cost, reasoning_options, status) stripped. +name = "Reka Edge" +description = "Multimodal model for analyzing text, images, documents, and rich media" +family = "reka" +release_date = "2026-03-20" +last_updated = "2026-03-20" +attachment = true +reasoning = false +temperature = true +tool_call = true +structured_output = true +open_weights = true + +[limit] +context = 16384 +output = 14745 + +[modalities] +input = ["image", "text", "video"] +output = ["text"] diff --git a/models/rekaai/reka-flash-3.toml b/models/rekaai/reka-flash-3.toml new file mode 100644 index 00000000000..11c5ab2f517 --- /dev/null +++ b/models/rekaai/reka-flash-3.toml @@ -0,0 +1,22 @@ +# Lab metadata carried over from providers/openrouter/models/rekaai/reka-flash-3.toml (curated catalogue data already in this repo), +# with provider-specific fields (cost, reasoning_options, status) stripped. +name = "Reka Flash 3" +description = "Efficient model for low-latency assistance, extraction, and routine automation" +family = "reka" +release_date = "2025-03-12" +last_updated = "2025-03-12" +knowledge = "2025-01-31" +attachment = false +reasoning = true +temperature = true +tool_call = false +structured_output = true +open_weights = true + +[limit] +context = 65536 +output = 58982 + +[modalities] +input = ["text"] +output = ["text"] diff --git a/models/relace/relace-apply-3.toml b/models/relace/relace-apply-3.toml new file mode 100644 index 00000000000..b7b548e3b15 --- /dev/null +++ b/models/relace/relace-apply-3.toml @@ -0,0 +1,20 @@ +# Lab metadata carried over from providers/openrouter/models/relace/relace-apply-3.toml (curated catalogue data already in this repo), +# with provider-specific fields (cost, reasoning_options, status) stripped. +name = "Relace Apply 3" +description = "General-purpose chat model for instruction following, writing, and analysis" +release_date = "2025-09-26" +last_updated = "2025-09-26" +attachment = false +reasoning = false +temperature = false +tool_call = false +structured_output = false +open_weights = false + +[limit] +context = 256000 +output = 128000 + +[modalities] +input = ["text"] +output = ["text"] diff --git a/models/relace/relace-search.toml b/models/relace/relace-search.toml new file mode 100644 index 00000000000..e8164be7d1a --- /dev/null +++ b/models/relace/relace-search.toml @@ -0,0 +1,20 @@ +# Lab metadata carried over from providers/openrouter/models/relace/relace-search.toml (curated catalogue data already in this repo), +# with provider-specific fields (cost, reasoning_options, status) stripped. +name = "Relace Search" +description = "Tool-capable chat model for instruction following and agentic application workflows" +release_date = "2025-12-08" +last_updated = "2025-12-08" +attachment = false +reasoning = false +temperature = true +tool_call = true +structured_output = false +open_weights = false + +[limit] +context = 256000 +output = 128000 + +[modalities] +input = ["text"] +output = ["text"] diff --git a/models/sakana/fugu-max.toml b/models/sakana/fugu-max.toml new file mode 100644 index 00000000000..331f295fb38 --- /dev/null +++ b/models/sakana/fugu-max.toml @@ -0,0 +1,21 @@ +# Lab metadata carried over from providers/openrouter/models/sakana/fugu-max.toml (curated catalogue data already in this repo), +# with provider-specific fields (cost, reasoning_options, status) stripped. +name = "Fugu Max" +description = "Multi-agent model for routing expert agents across complex analytical tasks" +family = "fugu" +release_date = "2026-09-11" +last_updated = "2026-09-11" +attachment = true +reasoning = true +temperature = false +tool_call = true +structured_output = true +open_weights = false + +[limit] +context = 1000000 +output = 128000 + +[modalities] +input = ["text", "image", "pdf"] +output = ["text"] diff --git a/models/sakana/fugu-ultra-v2.toml b/models/sakana/fugu-ultra-v2.toml new file mode 100644 index 00000000000..56bb3f3426e --- /dev/null +++ b/models/sakana/fugu-ultra-v2.toml @@ -0,0 +1,22 @@ +# Lab metadata carried over from providers/openrouter/models/sakana/fugu-ultra-v2.toml (curated catalogue data already in this repo), +# with provider-specific fields (cost, reasoning_options, status) stripped. +name = "Fugu Ultra v2" +description = "Quality-first multi-agent model for hard research, analysis, and competitions" +family = "fugu" +release_date = "2026-09-11" +last_updated = "2026-09-11" +knowledge = "2026-08-28" +attachment = true +reasoning = true +temperature = false +tool_call = true +structured_output = true +open_weights = false + +[limit] +context = 1000000 +output = 128000 + +[modalities] +input = ["text", "image", "pdf"] +output = ["text"] diff --git a/models/sao10k/l3-lunaris-8b.toml b/models/sao10k/l3-lunaris-8b.toml new file mode 100644 index 00000000000..1e97130d072 --- /dev/null +++ b/models/sao10k/l3-lunaris-8b.toml @@ -0,0 +1,22 @@ +# Lab metadata carried over from providers/openrouter/models/sao10k/l3-lunaris-8b.toml (curated catalogue data already in this repo), +# with provider-specific fields (cost, reasoning_options, status) stripped. +name = "Llama 3 8B Lunaris" +description = "Open Llama instruction model for multilingual chat, reasoning, and coding" +family = "llama" +release_date = "2024-08-13" +last_updated = "2024-08-13" +knowledge = "2023-12-31" +attachment = false +reasoning = false +temperature = true +tool_call = false +structured_output = true +open_weights = true + +[limit] +context = 8192 +output = 7372 + +[modalities] +input = ["text"] +output = ["text"] diff --git a/models/sao10k/l3.1-euryale-70b.toml b/models/sao10k/l3.1-euryale-70b.toml new file mode 100644 index 00000000000..9bf2df1dc17 --- /dev/null +++ b/models/sao10k/l3.1-euryale-70b.toml @@ -0,0 +1,22 @@ +# Lab metadata carried over from providers/openrouter/models/sao10k/l3.1-euryale-70b.toml (curated catalogue data already in this repo), +# with provider-specific fields (cost, reasoning_options, status) stripped. +name = "Llama 3.1 Euryale 70B v2.2" +description = "Open Llama instruction model for multilingual chat, reasoning, and coding" +family = "llama" +release_date = "2024-08-28" +last_updated = "2024-08-28" +knowledge = "2023-12-31" +attachment = false +reasoning = false +temperature = true +tool_call = true +structured_output = true +open_weights = true + +[limit] +context = 131072 +output = 16384 + +[modalities] +input = ["text"] +output = ["text"] diff --git a/models/sao10k/l3.3-euryale-70b.toml b/models/sao10k/l3.3-euryale-70b.toml new file mode 100644 index 00000000000..1e4951eb5db --- /dev/null +++ b/models/sao10k/l3.3-euryale-70b.toml @@ -0,0 +1,22 @@ +# Lab metadata carried over from providers/openrouter/models/sao10k/l3.3-euryale-70b.toml (curated catalogue data already in this repo), +# with provider-specific fields (cost, reasoning_options, status) stripped. +name = "Llama 3.3 Euryale 70B" +description = "Open Llama instruction model for multilingual chat, reasoning, and coding" +family = "llama" +release_date = "2024-12-18" +last_updated = "2024-12-18" +knowledge = "2023-12-31" +attachment = false +reasoning = false +temperature = true +tool_call = false +structured_output = true +open_weights = true + +[limit] +context = 131072 +output = 16384 + +[modalities] +input = ["text"] +output = ["text"] diff --git a/models/tencent/hy-mt2-1.8b.toml b/models/tencent/hy-mt2-1.8b.toml new file mode 100644 index 00000000000..f6f57b60032 --- /dev/null +++ b/models/tencent/hy-mt2-1.8b.toml @@ -0,0 +1,21 @@ +# Lab metadata carried over from providers/openrouter/models/tencent/hy-mt2-1.8b.toml (curated catalogue data already in this repo), +# with provider-specific fields (cost, reasoning_options, status) stripped. +name = "Hy-MT2-1.8B" +description = "Tencent Hy reasoning model for coding, instruction following, and agent tasks" +family = "Hy" +release_date = "2026-08-20" +last_updated = "2026-08-20" +attachment = false +reasoning = false +temperature = true +tool_call = false +structured_output = false +open_weights = true + +[limit] +context = 8192 +output = 4096 + +[modalities] +input = ["text"] +output = ["text"] diff --git a/models/tencent/hy-mt2-30b-a3b.toml b/models/tencent/hy-mt2-30b-a3b.toml new file mode 100644 index 00000000000..db3d6a6faf4 --- /dev/null +++ b/models/tencent/hy-mt2-30b-a3b.toml @@ -0,0 +1,21 @@ +# Lab metadata carried over from providers/openrouter/models/tencent/hy-mt2-30b-a3b.toml (curated catalogue data already in this repo), +# with provider-specific fields (cost, reasoning_options, status) stripped. +name = "Hy-MT2-30B-A3B" +description = "Tencent Hy reasoning model for coding, instruction following, and agent tasks" +family = "Hy" +release_date = "2026-08-20" +last_updated = "2026-08-20" +attachment = false +reasoning = false +temperature = true +tool_call = false +structured_output = true +open_weights = true + +[limit] +context = 8192 +output = 4096 + +[modalities] +input = ["text"] +output = ["text"] diff --git a/models/tencent/hy-mt2-7b.toml b/models/tencent/hy-mt2-7b.toml new file mode 100644 index 00000000000..532e3df4c23 --- /dev/null +++ b/models/tencent/hy-mt2-7b.toml @@ -0,0 +1,21 @@ +# Lab metadata carried over from providers/openrouter/models/tencent/hy-mt2-7b.toml (curated catalogue data already in this repo), +# with provider-specific fields (cost, reasoning_options, status) stripped. +name = "Hy-MT2-7B" +description = "Tencent Hy reasoning model for coding, instruction following, and agent tasks" +family = "Hy" +release_date = "2026-08-19" +last_updated = "2026-08-19" +attachment = false +reasoning = false +temperature = true +tool_call = false +structured_output = true +open_weights = true + +[limit] +context = 8192 +output = 4096 + +[modalities] +input = ["text"] +output = ["text"] diff --git a/models/thedrummer/cydonia-24b-v4.1.toml b/models/thedrummer/cydonia-24b-v4.1.toml new file mode 100644 index 00000000000..e7cb43b8998 --- /dev/null +++ b/models/thedrummer/cydonia-24b-v4.1.toml @@ -0,0 +1,21 @@ +# Lab metadata carried over from providers/openrouter/models/thedrummer/cydonia-24b-v4.1.toml (curated catalogue data already in this repo), +# with provider-specific fields (cost, reasoning_options, status) stripped. +name = "Cydonia 24B V4.1" +description = "Open-weight instruction model for adaptable chat and self-hosted production workloads" +release_date = "2025-09-27" +last_updated = "2025-09-27" +knowledge = "2024-04-30" +attachment = false +reasoning = false +temperature = true +tool_call = false +structured_output = true +open_weights = true + +[limit] +context = 131072 +output = 117964 + +[modalities] +input = ["text"] +output = ["text"] diff --git a/models/thedrummer/skyfall-36b-v2.toml b/models/thedrummer/skyfall-36b-v2.toml new file mode 100644 index 00000000000..d3652f86fcb --- /dev/null +++ b/models/thedrummer/skyfall-36b-v2.toml @@ -0,0 +1,21 @@ +# Lab metadata carried over from providers/openrouter/models/thedrummer/skyfall-36b-v2.toml (curated catalogue data already in this repo), +# with provider-specific fields (cost, reasoning_options, status) stripped. +name = "Skyfall 36B V2" +description = "Open-weight instruction model for adaptable chat and self-hosted production workloads" +release_date = "2025-03-10" +last_updated = "2025-03-10" +knowledge = "2024-06-30" +attachment = false +reasoning = false +temperature = true +tool_call = false +structured_output = true +open_weights = true + +[limit] +context = 32768 +output = 29491 + +[modalities] +input = ["text"] +output = ["text"] diff --git a/models/thedrummer/unslopnemo-12b.toml b/models/thedrummer/unslopnemo-12b.toml new file mode 100644 index 00000000000..03660192a6f --- /dev/null +++ b/models/thedrummer/unslopnemo-12b.toml @@ -0,0 +1,21 @@ +# Lab metadata carried over from providers/openrouter/models/thedrummer/unslopnemo-12b.toml (curated catalogue data already in this repo), +# with provider-specific fields (cost, reasoning_options, status) stripped. +name = "UnslopNemo 12B" +description = "Open-weight instruction model for adaptable chat and self-hosted production workloads" +release_date = "2024-11-08" +last_updated = "2024-11-08" +knowledge = "2024-04-30" +attachment = false +reasoning = false +temperature = true +tool_call = false +structured_output = true +open_weights = true + +[limit] +context = 1024000 +output = 819200 + +[modalities] +input = ["text"] +output = ["text"] diff --git a/models/undi95/remm-slerp-l2-13b.toml b/models/undi95/remm-slerp-l2-13b.toml new file mode 100644 index 00000000000..2d7fc68c704 --- /dev/null +++ b/models/undi95/remm-slerp-l2-13b.toml @@ -0,0 +1,21 @@ +# Lab metadata carried over from providers/openrouter/models/undi95/remm-slerp-l2-13b.toml (curated catalogue data already in this repo), +# with provider-specific fields (cost, reasoning_options, status) stripped. +name = "ReMM SLERP 13B" +description = "Open-weight instruction model for adaptable chat and self-hosted production workloads" +release_date = "2023-07-22" +last_updated = "2023-07-22" +knowledge = "2023-06-30" +attachment = false +reasoning = false +temperature = true +tool_call = false +structured_output = true +open_weights = true + +[limit] +context = 6144 +output = 5529 + +[modalities] +input = ["text"] +output = ["text"] diff --git a/models/xai/grok-4-fast-non-reasoning.toml b/models/xai/grok-4-fast-non-reasoning.toml new file mode 100644 index 00000000000..1b06ed90483 --- /dev/null +++ b/models/xai/grok-4-fast-non-reasoning.toml @@ -0,0 +1,20 @@ +# Lab metadata carried over from providers/qiniu-ai/models/x-ai/grok-4-fast-non-reasoning.toml (curated catalogue data already in this repo), +# with provider-specific fields (cost, reasoning_options, status) stripped. +name = "X-Ai/Grok-4-Fast-Non-Reasoning" +description = "Fast Grok model for responsive chat, reasoning, and tool-assisted work" +release_date = "2025-12-18" +last_updated = "2025-12-18" +attachment = true +reasoning = false +temperature = true +tool_call = true +structured_output = false +open_weights = false + +[limit] +context = 2000000 +output = 2000000 + +[modalities] +input = ["text", "image", "audio", "video"] +output = ["text"] diff --git a/models/xai/grok-4-fast-reasoning.toml b/models/xai/grok-4-fast-reasoning.toml new file mode 100644 index 00000000000..4ce1b88d076 --- /dev/null +++ b/models/xai/grok-4-fast-reasoning.toml @@ -0,0 +1,20 @@ +# Lab metadata carried over from providers/qiniu-ai/models/x-ai/grok-4-fast-reasoning.toml (curated catalogue data already in this repo), +# with provider-specific fields (cost, reasoning_options, status) stripped. +name = "X-Ai/Grok-4-Fast-Reasoning" +description = "Fast Grok model for responsive chat, reasoning, and tool-assisted work" +release_date = "2025-12-18" +last_updated = "2025-12-18" +attachment = true +reasoning = true +temperature = true +tool_call = true +structured_output = false +open_weights = false + +[limit] +context = 2000000 +output = 2000000 + +[modalities] +input = ["text", "image", "audio", "video"] +output = ["text"] diff --git a/models/xai/grok-code-fast-1.toml b/models/xai/grok-code-fast-1.toml new file mode 100644 index 00000000000..bf40a934186 --- /dev/null +++ b/models/xai/grok-code-fast-1.toml @@ -0,0 +1,20 @@ +# Lab metadata carried over from providers/qiniu-ai/models/x-ai/grok-code-fast-1.toml (curated catalogue data already in this repo), +# with provider-specific fields (cost, reasoning_options, status) stripped. +name = "x-AI/Grok-Code-Fast 1" +description = "Fast Grok model for responsive chat, reasoning, and tool-assisted work" +release_date = "2025-09-02" +last_updated = "2025-09-02" +attachment = false +reasoning = true +temperature = true +tool_call = true +structured_output = false +open_weights = false + +[limit] +context = 256000 +output = 10000 + +[modalities] +input = ["text"] +output = ["text"] diff --git a/package.json b/package.json index a206c128fb5..40e35006f3a 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "test": "bun test", "validate": "bun ./packages/core/script/validate.ts", "compare:migrations": "bun ./packages/core/script/compare-model-migrations.ts", + "aimlapi:sync": "bun ./packages/core/script/sync-models.ts aimlapi", "anthropic:sync": "bun ./packages/core/script/sync-models.ts anthropic", "baseten:sync": "bun ./packages/core/script/sync-models.ts baseten", "deepinfra:sync": "bun ./packages/core/script/sync-models.ts deepinfra", diff --git a/packages/core/src/sync/index.ts b/packages/core/src/sync/index.ts index 94366560de6..cacde88b019 100644 --- a/packages/core/src/sync/index.ts +++ b/packages/core/src/sync/index.ts @@ -7,6 +7,7 @@ import { AuthoredModel, AuthoredModelShape, ModelMetadata } from "../schema.js"; import { openMissingModelIssues } from "./missing-issues.js"; import { MissingReasoningOptionsError } from "./missing-reasoning-options.js"; import { aiand } from "./providers/aiand.js"; +import { aimlapi } from "./providers/aimlapi.js"; import { ambient } from "./providers/ambient.js"; import { anthropic } from "./providers/anthropic.js"; import { baseten } from "./providers/baseten.js"; @@ -144,6 +145,7 @@ export interface SyncResult { export const providers: { aiand: SyncProvider; + aimlapi: SyncProvider; ambient: SyncProvider; anthropic: SyncProvider; baseten: SyncProvider; @@ -186,6 +188,7 @@ export const providers: { xai: SyncProvider; } = { aiand, + aimlapi, ambient, anthropic, baseten, @@ -230,6 +233,7 @@ export const providers: { export const groups = { aggregators: [ + "aimlapi", "crossmodel", "edenai", "empiriolabs", diff --git a/packages/core/src/sync/providers/aimlapi.ts b/packages/core/src/sync/providers/aimlapi.ts new file mode 100755 index 00000000000..5c8a2b80628 --- /dev/null +++ b/packages/core/src/sync/providers/aimlapi.ts @@ -0,0 +1,1286 @@ +import { existsSync, readFileSync } from "node:fs"; +import path from "node:path"; +import { z } from "zod"; + +import type { SyncProvider } from "../index.js"; +import { + factorBaseModel, + modelMetadata, + openrouterDirsForMetadataLab, + providerDirForMetadataLab, + resolveModelMetadataBaseModel, +} from "./openrouter.js"; + +// The public catalog needs no key, and `include` is what turns on the pricing +// and modality blocks this sync depends on. +const API_ENDPOINT = "https://api.aimlapi.com/v1/models?include=pricing,modalities"; + +// Per-model request schema. It is the only place the API states which reasoning +// controls a model actually accepts, so reasoning_options is read from here +// rather than assumed. +const DOCS_ENDPOINT = "https://api.aimlapi.com/docs-json"; + +// AI/ML API serves one id under several endpoint types — a model can be both a +// chat model and, say, an image model. Only the chat surface belongs here. +const CHAT_COMPLETIONS_TYPE = "openai/chat-completions"; + +// Values this schema accepts for an "effort" reasoning control, in the order a +// reader expects to see them. Anything the API documents outside this set is +// dropped rather than coerced. +const EFFORT_VALUES = ["none", "minimal", "low", "medium", "high", "xhigh", "max", "default"] as const; +type EffortValue = (typeof EFFORT_VALUES)[number]; +const EFFORT_RANK = new Map(EFFORT_VALUES.map((value, index) => [value as string, index])); +const isEffortValue = (value: string): value is EffortValue => EFFORT_RANK.has(value); + +/** + * Models whose documented schema and whose live behaviour disagree, with what + * the endpoint actually served when asked. + * + * `/docs-json` describes a request *shape* per fallback hop, and a hop can + * advertise a control the vendor behind it still refuses. Reading the schema + * alone therefore over-states these two, and reading only the first hop + * under-states others — neither direction is safe to publish unchecked. + * + * How these were established, because the method is the evidence: each value + * was sent to production with `max_tokens` high enough to leave room for an + * answer, and the **error body** was read rather than the status code. A + * reasoning model given a small budget returns 400 for an accepted value too + * ("max_tokens or model output limit was reached"), so a status-only probe + * reports a rejection that never happened. A real refusal says either + * "Validation failed" or, for gemini, "Reasoning is mandatory for this + * endpoint and cannot be disabled". + * + * Measured 2026-09-09. Re-probe before trusting these after a vendor change: + * an entry that has become wrong is worse than no entry. + */ +/** + * Models that accept any string in `reasoning_effort` — `banana` and `zzz9` both + * return 200 — so the parameter is not honoured and no ladder can be established + * by probing. The schema still lists one, inherited from the family template. + * + * Publishing it would state a control the caller does not have. Emitting nothing + * says only that we cannot describe it, which is the truth. Re-probe with a + * deliberately invalid value before adding a ladder back: a 400 means the field + * became real. + * + * Measured 2026-09-09 across all 87 entries that carry reasoning options; these + * were the only ones that failed the check. Re-probed 2026-09-10: five still + * accept `banana` with a 200 and stay. + * + * `moonshot/kimi-k3` was removed on 2026-09-10. Re-probed, its control answers + * 200 and a deliberately invalid effort answers 400 — the field is read and + * enforced, which is the one thing `[]` asserts is not true. Whether the levels + * ORDER is still unproven: `low` measured 919 and 1618 reasoning tokens and + * `high` measured 1943, so the spread within `low` is nearly the distance from + * `low` to `high`, and `max` timed out at the gateway on both attempts. The id + * therefore goes back to the schema-derived ladder its card declares, which is + * the host's own statement about itself, rather than to a claim of ours that + * the measurement does not support in either direction. + */ +/** + * Catalogue rows that cannot actually be called: `/v1/models` lists them with a + * name and prices, inference answers 404 "No endpoints found". Publishing one + * hands a reader a model id that fails on first use. + * + * Measured 2026-09-09; the sibling `-fast` and `-pro` aliases all answered 200, + * so this is one broken row rather than a broken family. Re-check before adding + * to this list — a row that starts working should come back. + * + * The guard sits on the publish path, so the entry is never created or updated. + * With `deleteMissing` enabled, a published row for one of these ids is + * removed by sync like any other model the host no longer serves. + */ +const NOT_CALLABLE: ReadonlySet = new Set([ + "anthropic/claude-opus-4.7-fast", + // Joined it on 2026-09-09: gone from `/v1/models` (785 rows, neither `-fast` + // id among them) and `/docs-json` answers 404 for it, so there is nothing + // left to describe. The host's own deprecation record calls both withdrawn. + "anthropic/claude-opus-4.8-fast", + // 2026-09-11: answers 404 to every request including the no-effort control — + // "0 endpoints out of 1 requested are available matching your guardrail + // restrictions and data policy", an OpenRouter refusal passed straight + // through. Found while probing its ladder; the ladder is moot. + "sakana/sakana-namazu", +]); + +/** + * Ladders the endpoint VALIDATES and then does not act on. + * + * Kept apart from `EFFORT_NOT_HONOURED` because the evidence is different and + * the two must not be confused. There, an invalid value returns 200, which + * proves the field is never read. Here an invalid value is rejected — the + * field is read, parsed and enforced — and the levels still fail to order. + * + * `moonshotai/kimi-k2-thinking`, measured 2026-09-10 on a prompt hard enough + * to make a difference visible: `low` produced 6723 and 8207 reasoning tokens + * across repeats, `high` produced 6508. Unset produced 2919 against `low`'s + * 2799 on a smaller budget. `low` above `high` is not a small delta in the + * wrong direction, it is the absence of an ordering, and the lab entry for + * this model publishes `reasoning_options = []` for the same reason: the + * model always reasons and the caller cannot steer it. + * + * Publishing a ladder here would sell a dial that turns nothing. + */ +/** + * ## Why this file reads `reasoning_effort` and nothing else + * + * The review asks repeatedly for `toggle` and `budget_tokens` options, on the + * grounds that the labs behind these models expose them and a relay should + * mirror the control family. The premise does not survive a control. + * + * Probed on 2026-09-10 against `deepseek-v4-pro`, `qwen-plus`, `kimi-k3` and + * `glm-5-turbo` on the OpenAI-compatible path, each alongside a no-field + * control that answered 200: + * + * enable_thinking: false 200 + * thinking: {type: 'disabled'} 200 + * thinking_budget: 128 200 + * banana_toggle: true 200 <- a field that exists nowhere + * + * An invented field is accepted exactly like the real ones, so this surface + * discards unknown top-level keys rather than forwarding them. A 200 on + * `enable_thinking` is therefore not evidence that a toggle exists; it is + * evidence that nothing is listening. Publishing `toggle` on that basis would + * hand callers a control the gateway throws away. + * + * `reasoning_effort` is different in kind: an invalid value is REJECTED on the + * models that read it, which is how this file tells a live control from a + * swallowed one, and it is why the two categories below are kept apart. + */ +const EFFORT_VALIDATED_BUT_INERT: ReadonlySet = new Set([ + "moonshotai/kimi-k2-thinking", + // 2026-09-11: an invalid value is rejected, and then `low` spends 2149 + // reasoning tokens to `high`'s 1533 with unset at 1801 between them. The + // lab publishes toggle only for this id, which the wire agrees with: there + // is thinking, and nothing the caller sends steers how much. + "z-ai/glm-4.7-flash", + // The other toggle-only labs, 2026-09-11, each on two repeats of low/high + // with the field validated. None orders, and the wire agrees with the lab: + // claude-haiku-4.5 188/182 vs 179/185 + // qwen3.6-max-preview 574/580 vs 552/554 (high below low, both times) + // gemma-4-31b-it reasoning count 1 at every rung + // mimo-v2.5-pro reasoning count 0 at every rung + // mimo-v2.5 307/234 vs 104/235 + // glm-4.5v 614/680 vs 641/643 + // glm-4.6v 191/116 vs 123/109 + // `claude-sonnet-4.5` is the one with a direction — 184/183 vs 220/210 — + // but a thirty-token delta on a model the host's own middleware lists as + // effort-unsupported (`strip-unsupported-effort.ts`) is not evidence + // enough to contradict a lab that publishes toggle only. Recorded so it can + // be revisited; it takes `[]` with the rest. + "anthropic/claude-haiku-4.5", + "anthropic/claude-sonnet-4.5", + "alibaba/qwen3.6-max-preview", + "google/gemma-4-31b-it", + "xiaomi/mimo-v2.5-pro", + "xiaomi/mimo-v2.5", + "z-ai/glm-4.5v", + "z-ai/glm-4.6v", +]); + +const EFFORT_NOT_HONOURED: ReadonlySet = new Set([ + // Re-verified 2026-09-10 by the token-scaling test the review asked for, + // rather than by status codes alone: `low` measured 3837 and 3841 reasoning + // tokens, `high` measured 3837 and 3838. Four runs, a spread of four tokens, + // no movement between the levels at all. Peers publish L/M/H for this id; + // this host accepts the names and steers nothing. + "google/gemini-3.1-pro-preview", + "google/gemma-4-26b-a4b-it", + "z-ai/glm-5v-turbo", + "z-ai/glm-5-turbo", + "alibaba/qwen-plus", +]); + +/** + * Ladders this host was measured to accept AND honour, where that differs from + * what its schema advertises. `accepted` is not enough on its own: a rung the + * endpoint takes and then ignores publishes worse advice than one it refuses, + * because the caller asks for more thinking, is told yes, and is billed for a + * reply produced with less. + */ +/** + * `deepseek-chat` and `deepseek-v4-flash` publish identical prices on purpose. + * + * The review read the coincidence as a unit-mapping bug and asked for a + * re-check. It is not one: DeepSeek retired `deepseek-chat` as a model and + * routes the id to its current Flash build, so the host bills it on the Flash + * grid — 0.3 in / 1.2 out / 0.006 cached, times the host margin, which is + * exactly the 0.39 / 1.56 / 0.0078 both rows carry. + * + * The check was worth running anyway. It turned up the real defect beside the + * prices: the row still carried V3's name and a 128K context for a model with + * 1M, which the host has since corrected. Kept here so the next reviewer does + * not spend the same round on it. + */ + +/** + * The OpenAI pro/codex/5.6 batch, probed 2026-09-10 because the review asked + * for each id to be intersected with a live accept-and-honour test. + * + * An invalid effort is rejected on all nine, so every ladder below is a live + * control rather than a swallowed field. + * + * The rungs the review wanted ADDED are refused here. `xhigh` answers 400 on + * `gpt-5.2-pro`, `gpt-5.5-pro` and `gpt-5.3-codex`; `max` answers 400 on + * `gpt-5.6-luna`. Publishing the lab's wider sets would hand callers an error, + * so the host's narrower enum stands. + * + * The rung the review worried was fake is real. `none` measured 0 reasoning + * tokens on every id that offers it — `gpt-5.3-codex`, `gpt-5.6-luna`, `-sol`, + * `-terra` and `-terra-pro` — against non-zero at `high` on each. That is the + * check Sonnet 5 failed, and these pass it. + * + * Ordering, on a deliberately light prompt so the batch could finish: + * + * gpt-5.2-codex low 90 high 192 ordered + * gpt-5.1-codex low 0 high 103 ordered + * gpt-5.6-terra low 9 high 25 ordered + * gpt-5.6-terra-pro low 91 high 129 ordered + * gpt-5.6-sol low 0 high 9 ordered, barely + * gpt-5.6-luna low 26 high 27 not separated + * gpt-5.5-pro low 33 high 31 not separated + * gpt-5.2-pro 0 at every rung — the model did not reason at all here + * + * The last three are left alone rather than trimmed. `gpt-5.2-pro` is the + * `kwaipilot` case from the Method section: when the control itself produces + * nothing, the cells say nothing about the ladder. The other two would need a + * harder prompt than this batch could afford, and a rung the host accepts is + * not removed on a probe that failed to separate anything. + */ +/** + * `none` on the Claude ladders, which the review asked to justify or drop. + * + * It is a real control, and what it does depends on which link serves the + * request — so the honest answer is per model rather than per family. + * + * `claude-opus-4.7` and `4.8` reach OpenRouter for every rung up to `high`, + * and only `xhigh`/`max` go to Anthropic natively. On that link `none` + * measured 0 reasoning tokens against 191 at `low` and 1228 at `high`: an off + * switch, and the reason `none` stays on those ids. + * + * `claude-sonnet-5` has no OpenRouter link, so every rung goes native, and + * Anthropic has no off switch on its adaptive models — `thinking: + * {type: 'disabled'}` returns 200 there and is ignored. The host used to drop + * the field entirely for `none`, which handed the request to Anthropic's + * default: 6000 output tokens spent thinking and an EMPTY reply. That is fixed + * upstream and `none` now maps to `low`, the cheapest rung the vendor has, so + * on this id it means minimum rather than off. + * + * Both are worth publishing — a caller sending `none` gets the least thinking + * available either way — but they are not the same promise, and this is where + * that is written down. + */ +/** + * `alibaba/qwen3.8-2.4t-a95b` keeps `high` as its top rung. + * + * The review asked for `xhigh` instead, on the peer ladder for this model. + * Probed twice: `xhigh` answers 400 with `Expected 'low' | 'medium' | 'high'`, + * so the host does not offer it and publishing it would hand callers an error. + * `high` at 4000 tokens times out at the gateway rather than returning, so + * whether the rungs order is still unmeasured — the enum, however, is settled. + */ +const MEASURED_EFFORTS: Readonly> = { + // schema offers none+minimal; both refused, `none` explicitly and by name. + // `max` is kept on evidence the review asked to see recorded here: measured + // 2131 reasoning tokens at `low`, 3841 at `high` and 6585 at `max` on one + // prompt, a monotone spread far outside the noise on this family. Peers stop + // at `high`; this host both accepts `max` and spends visibly more for it. + "google/gemini-3.7-flash": ["low", "medium", "high", "max"], + // schema offers none; refused as a validation error + "google/gemini-3.6-flash": ["minimal", "low", "medium", "high", "max"], + // The schema offers `xhigh` on both and the endpoint answers 200 for it, so + // no status-code probe could catch this. Pinned to the direct hop on a prompt + // hard enough to show the difference, `xhigh` produced 0 reasoning tokens on + // o1 and 192 on o3-mini, where `high` produced 10176 and 16000 and even `low` + // produced ~4500. The rung is accepted and dropped. The review asked for + // exactly this set on both ids and was right; the host has since stopped + // advertising `xhigh` here, so this entry becomes a no-op rather than an + // override once that reaches production. + // `low` measured indistinguishable from `medium` on a prompt hard enough to + // separate them: low 2230 and 2273 reasoning tokens, medium 2180 and 2420, + // overlapping ranges across repeats, while `high` sat clearly above at 2984. + // Two names for one behaviour is worse than one name, so `low` goes. The + // review asked for this too, on the different ground that the lab omits it; + // the measurement is what this entry rests on. `xhigh` is not added back — + // this host's schema stops at `high` and refuses it. + // Re-probed on a hard prompt at the review's suggestion, because the light + // one had `gpt-5.2-pro` not reasoning at all. `low` and `medium` come back + // indistinguishable on both — 1400 against 1311, and 2345 against 2336 — + // while `high` sits above where it could be measured at all. Same call as + // `gpt-5.4-pro` below: two names for one behaviour, so the lower goes. + "openai/gpt-5.2-pro": ["medium", "high"], + "openai/gpt-5.5-pro": ["medium", "high"], + "openai/gpt-5.4-pro": ["medium", "high"], + // `none` dropped 2026-09-10. On this id every rung reaches Anthropic + // natively, and Anthropic has no off switch on its adaptive models, so the + // host maps `none` to `low` — the cheapest real rung. Publishing it as + // `none` tells a caller reading the catalogue that reasoning can be turned + // off here, which is not what they would get. The sibling opus-4.7/4.8 keep + // `none` because their lower rungs reach OpenRouter, where it measured 0 + // reasoning tokens against 191 at `low`: there it really is off. + // `none` dropped 2026-09-10: it is accepted, but nothing shows it turns + // reasoning off. Two runs returned no `reasoning_tokens` field at all while + // still producing 1703 and 2000 output tokens, so there is no reading of + // that as an off switch — and `high` on the same model does report 2000 + // reasoning tokens. A rung whose semantics cannot be shown does not belong + // in a catalogue other people build against. + "alibaba/qwen3.8-max": ["low", "medium", "high"], + "anthropic/claude-sonnet-5": ["low", "medium", "high", "xhigh", "max"], + // `medium` dropped 2026-09-10, and this is a correction to an earlier call + // in this file rather than a new measurement. It measured 5563 and then 7204 + // against `high`'s 5662: a spread inside the rung wider than any gap to the + // rung above. That was recorded as "unsettled, so keep it" — but publishing + // a rung is a claim too, and `gpt-5.4-pro` above had the identical shape and + // lost `low` for it. Two rules for one situation is worse than either rule. + // `none` (0 twice) and `low` (4175 against 5662) stay: those are measured. + "deepseek/deepseek-v4-pro": ["none", "low", "high"], + // Same cut on the dated snapshot, measured rather than copied: `medium` + // exhausted a 4000-token budget on reasoning twice while `high` used 2318. + // A rung that spends more than the one above it is not a lower rung. + "deepseek/deepseek-v4-pro-0813": ["none", "low", "high"], + "openai/o1": ["low", "medium", "high"], + "openai/o3-mini": ["low", "medium", "high"], +}; + +/** + * Models whose reasoning arrives on a side channel rather than in `content`. + * + * The review asked whether this gateway returns one, and it does — but the lab + * entries that declare it are NOT inherited through `base_model`, so the built + * catalogue showed `interleaved` unset on every aimlapi row while the provider + * was in fact emitting 20K characters of chain-of-thought in a separate field. + * A client reading only this provider would render that as the answer. + * + * Probed across all 81 ids that carry a reasoning ladder, 2026-09-10, by + * reading the keys actually present on the response message rather than by + * family: 14 return `reasoning_content`, 44 return `reasoning_details` + * alongside `reasoning`. + * + * Six ids the review asked about — `deepseek-chat`, the base `gpt-5.6-luna`, + * `-sol` and `-terra`, `o1` and `o3-mini` — return NO side channel, and that + * was re-checked under forced reasoning so it could not be the prompt: `o1` + * spent 2500 reasoning tokens and `gpt-5.6-luna` 1023 with nothing beside + * `content` on the message. The `-pro` siblings that do declare a field reach + * OpenRouter, which exposes one; the base ids reach OpenAI natively, which + * does not. Same family, different link, different wire. `deepseek-chat` is + * non-thinking by default and produced no reasoning tokens at all. + * + * Fifteen more return a bare `reasoning`, and two Gemini Flash ids return + * `extra_content`. Neither name is in the schema's enum, so those stay unset — + * recorded here so the gap reads as known rather than missed. Most of that + * group is the Anthropic line, where the field carries the summarised thinking + * block. + */ +const INTERLEAVED_FIELD: Readonly> = { + "alibaba/qwen3.5-flash": "reasoning_content", + "alibaba/qwen3.6-27b": "reasoning_content", + "alibaba/qwen3.6-35b-a3b": "reasoning_content", + "alibaba/qwen3.6-max-preview": "reasoning_content", + "alibaba/qwen3.7-max": "reasoning_content", + "alibaba/qwen3.8-flash": "reasoning_content", + "alibaba/qwen3.8-max": "reasoning_content", + "anthropic/claude-fable-5": "reasoning_content", + "anthropic/claude-sonnet-5": "reasoning_content", + "deepseek/deepseek-v4-flash": "reasoning_content", + "deepseek/deepseek-v4-flash-vision-exp": "reasoning_content", + "deepseek/deepseek-v4-pro": "reasoning_content", + "moonshot/kimi-k3": "reasoning_content", + "z-ai/glm-5.3-flash": "reasoning_content", + "alibaba/qwen3.8-2.4t-a95b": "reasoning_details", + "alibaba/qwen3.8-27b": "reasoning_details", + "arcee-ai/trinity-large-thinking": "reasoning_details", + "bytedance-seed/seed-2.0-code": "reasoning_details", + "bytedance-seed/seed-2.0-lite": "reasoning_details", + "bytedance-seed/seed-2.0-mini": "reasoning_details", + "deepseek/deepseek-v4-pro-0813": "reasoning_details", + "google/gemini-3.1-flash-lite-preview": "reasoning_details", + "google/gemini-3.1-pro-preview-customtools": "reasoning_details", + "google/gemini-flash-latest": "reasoning_details", + "inclusionai/ling-3.0-flash-fin": "reasoning_details", + "meta/muse-glimmer-30b": "reasoning_details", + "meta/muse-spark-1.1": "reasoning_details", + "meta/muse-spark-1.2": "reasoning_details", + "openai/gpt-5": "reasoning_details", + "openai/gpt-5-mini": "reasoning_details", + "openai/gpt-5-nano": "reasoning_details", + "openai/gpt-5-pro": "reasoning_details", + "openai/gpt-5.1-codex": "reasoning_details", + "openai/gpt-5.1-codex-max": "reasoning_details", + "openai/gpt-5.1-codex-mini": "reasoning_details", + "openai/gpt-5.2-codex": "reasoning_details", + "openai/gpt-5.2-pro": "reasoning_details", + "openai/gpt-5.3-codex": "reasoning_details", + "openai/gpt-5.4-pro": "reasoning_details", + "openai/gpt-5.5-pro": "reasoning_details", + "openai/gpt-5.6-luna-pro": "reasoning_details", + "openai/gpt-5.6-sol-pro": "reasoning_details", + "openai/gpt-5.6-terra-pro": "reasoning_details", + "openai/gpt-oss-120b": "reasoning_details", + "openai/gpt-oss-20b": "reasoning_details", + "openai/o1-pro": "reasoning_details", + "openai/o3-pro": "reasoning_details", + "poolside/laguna-s-2.1": "reasoning_details", + "poolside/laguna-xs-2.1": "reasoning_details", + "tencent/hy3": "reasoning_details", + "tencent/hy4-preview": "reasoning_details", + "thinkingmachines/inkling": "reasoning_details", + "thinkingmachines/inkling-small": "reasoning_details", + "xiaomi/mimo-v2.5": "reasoning_details", + "xiaomi/mimo-v2.5-pro": "reasoning_details", + "z-ai/glm-4.5v": "reasoning_details", + "z-ai/glm-4.6v": "reasoning_details", + "z-ai/glm-4.7-flash": "reasoning_details", +}; + +/** + * Upstream rows this catalogue never publishes, so they are neither created + * nor routed to the missing-model issue flow: + * + * - Dated snapshots (`-YYYY-MM-DD` / `-YYYYMMDD` suffixes) whose undated + * canonical model is the catalogue entry. (Dated ids the PR already + * publishes, e.g. the `gpt-4o-2024-*` cards, are not listed here.) + * - Moving `-latest` aliases whose versioned card is published instead. + * - Duplicate spellings of a model already covered under its canonical + * aimlapi id (`gemini-3-7-flash` for `gemini-3.7-flash`, `bytedance/…` for + * `bytedance-seed/…`). + * + * Explicit ids, not patterns: a pattern would also match published cards. + * Add new upstream junk here as it appears; one entry suppresses it forever. + */ +const BLACKLISTED: ReadonlySet = new Set([ + "deepseek/deepseek-v4-flash-latest", + "anthropic/claude-fable-latest", + "openai/gpt-chat-latest", + "anthropic/claude-haiku-latest", + "anthropic/claude-sonnet-latest", + "google/gemini-pro-latest", + "moonshotai/kimi-latest", + "openai/gpt-latest", + "openai/gpt-mini-latest", + "openai/gpt-5.5-2026-04-23", + "anthropic/claude-opus-latest", + "minimax/m2-7-20260402", + "openai/gpt-5.4-2026-03-05", + "alibaba/qwen3.5-plus-20260218", + "minimax/m2-5-20260218", + "minimax/m2-5-highspeed-20260218", + "openai/gpt-5.2-2025-12-11", + "openai/gpt-5.1-2025-11-13", + "openai/gpt-5-2025-08-07", + "openai/gpt-5-mini-2025-08-07", + "openai/gpt-5-nano-2025-08-07", + "openai/o3-2025-04-16", + "openai/o4-mini-2025-04-16", + "openai/gpt-4.1-2025-04-14", + "openai/gpt-4.1-mini-2025-04-14", + "openai/gpt-4.1-nano-2025-04-14", + "openai/o3-mini-2025-01-31", + "openai/o1-2024-12-17", + "openai/gpt-4o-mini-2024-07-18", + "openai/gpt-4-turbo-2024-04-09", + "google/gemini-3-7-flash", + "google/gemini-3-6-flash", + "bytedance/seed-2-0-lite", + "bytedance/seed-2-0-mini", + "google/gemini-3-1-flash-lite-preview", + // Dated duplicate spellings of canonical cards already published. + "anthropic/claude-haiku-4-5-20251001", + "anthropic/claude-sonnet-4-5-20250929", + "anthropic/claude-opus-4-5-20251101", + "openai/gpt-3.5-turbo-0125", +]); + +const PROVIDERS_DIR = path.join(import.meta.dirname, "..", "..", "..", "..", "..", "providers"); + +const DOCS_CONCURRENCY = 8; + +const PricingUnit = z + .object({ + name: z.string().nullish(), + content: z.string().nullish(), + origin: z.string().nullish(), + price: z.number().nullish(), + per: z.number().nullish(), + }) + .passthrough(); + +const Info = z + .object({ + name: z.string().nullish(), + contextLength: z.number().int().nonnegative().nullish(), + outputMax: z.number().int().nonnegative().nullish(), + }) + .passthrough(); + +export const AimlapiModel = z + .object({ + id: z.string().min(1), + type: z.string().nullish(), + info: Info.nullish(), + modalities: z + .object({ + input: z.array(z.string()).nullish(), + output: z.array(z.string()).nullish(), + }) + .passthrough() + .nullish(), + pricing: z + .object({ + units: z.array(PricingUnit).nullish(), + }) + .passthrough() + .nullish(), + /** Attached by fetchModels; not part of the upstream payload. */ + reasoningEffort: z.array(z.string()).nullish(), + }) + .passthrough(); + +export const AimlapiResponse = z + .object({ + data: z.array(AimlapiModel).min(1), + }) + .passthrough(); + +export type AimlapiModel = z.infer; + +type Modality = "text" | "audio" | "image" | "video" | "pdf"; + +const MODALITIES = new Set(["text", "audio", "image", "video", "pdf"]); + +function normalizeModalities(values: readonly string[] | null | undefined): Modality[] { + const seen = new Set(); + for (const value of values ?? []) { + const normalized = value.toLowerCase(); + if (MODALITIES.has(normalized)) seen.add(normalized as Modality); + } + if (seen.size === 0) seen.add("text"); + return [...seen]; +} + +/** + * Ids this host also serves on a non-text surface. + * + * The catalog lists an id once per endpoint type, and the chat-surface record of + * an image model claims text output. Measured 2026-09-04: + * `google/gemini-2.5-flash-image` appears both as `openai/image-generations` + * with `output: ["image"]` and as `openai/chat-completions` with + * `output: ["text"]`; the same holds for the `gemini-3-pro-image` and + * `gemini-3.1-flash-image` families. Judging a record only by its own modalities + * therefore admits image generators into a chat catalog. + * + * An id this host serves as a media model is not a text-only chat model, whatever + * its chat record claims. Populated from the whole response before any record is + * judged, because the answer is not in the record itself. + */ +const mediaOutputIDs = new Set(); + +function indexMediaOutputs(models: readonly AimlapiModel[]): void { + mediaOutputIDs.clear(); + for (const model of models) { + const declared = model.modalities?.output ?? []; + // `normalizeModalities` treats an empty list as text, so an undeclared + // record must not be read as evidence of anything. + if (declared.length === 0) continue; + if (normalizeModalities(declared).some((modality) => modality !== "text")) { + mediaOutputIDs.add(model.id); + } + } +} + +/** + * Ids that are a second spelling of a model already in the catalogue. + * + * The host lists a dotted id and a dashed one for the same Anthropic model — + * `anthropic/claude-opus-4.8` and `anthropic/claude-opus-4-8`, `claude-sonnet-4.6` + * and `claude-sonnet-4-6` — because the dashed form is an alias its router also + * answers to. `/v1/models` returns both as full rows, so a sync that trusts the + * listing publishes the same model twice under two ids. + * + * The rule is deliberately narrow, because "looks like an alias" is not enough + * to delete a row: the dotted twin must be present in the SAME payload and + * carry the SAME display name. Two genuinely different models that happen to + * collide on spelling would differ in one of those, and both survive. + * + * The dotted form wins because it is what the host's own docs and its + * `base_model` mapping use; the dashed alias keeps working for callers either + * way, it just stops being a catalogue entry of its own. + */ +const ALIAS_DUPLICATE_IDS = new Set(); + +/** `anthropic/claude-opus-4-8` -> `anthropic/claude-opus-4.8`; undefined if not that shape. */ +function dottedTwin(id: string): string | undefined { + const dotted = id.replace(/-(\d+)-(\d+)$/, "-$1.$2"); + return dotted === id ? undefined : dotted; +} + +function indexAliasDuplicates(models: readonly AimlapiModel[]): void { + ALIAS_DUPLICATE_IDS.clear(); + const nameByID = new Map(); + for (const model of models) nameByID.set(model.id, model.info?.name ?? undefined); + + for (const model of models) { + const twin = dottedTwin(model.id); + if (twin === undefined || !nameByID.has(twin)) continue; + if (nameByID.get(twin) !== nameByID.get(model.id)) continue; + ALIAS_DUPLICATE_IDS.add(model.id); + } +} + +function isChatTextModel(model: AimlapiModel): boolean { + if (model.type !== CHAT_COMPLETIONS_TYPE) return false; + // Cross-surface check first: the chat record of a media model does not admit + // to being one. + if (mediaOutputIDs.has(model.id)) return false; + const output = normalizeModalities(model.modalities?.output); + // A chat model whose output is not purely text is a media model riding the + // chat protocol, and does not belong in a chat catalog. + return output.length === 1 && output[0] === "text"; +} + +/** + * Lab entry this id is a host for. AI/ML API is an aggregator and authors none + * of these models, so every entry has to point at the lab file rather than + * restate it. + */ +/** + * Ids whose `base_model` is not the lab entry their own name resolves to. + * + * `deepseek-chat` is the case this exists for. Confirmed on production + * 2026-09-10 rather than inferred: three calls to that id each answered + * `"model": "deepseek-flash"`, the same string `deepseek-v4-flash` returns. + * DeepSeek retired the model + * behind that name and routes the id to its current Flash build, so pointing + * at the chat lab entry inherits the wrong everything: a 128K window for a + * model with 1M, and `reasoning = false` for one that reasons. The host itself + * bills the id on the Flash grid and has since corrected its own row's name + * and limits; this is the same correction on the catalogue side. + */ +/** + * Ids whose host ROW must not override the lab entry it factors onto. + * + * Only `deepseek/deepseek-chat`. The host has corrected its row since this + * began (it now reads "DeepSeek Chat (V4.1 Flash)", 1,048,576 context), but + * republishing either beside the Flash `base_model` would still contradict + * it: the lab has folded its Flash ids into V4.1 and lists the window as + * 1,000,000, and the host's 1,048,576 is a rounding of that same window, not a + * different one. Name and limits stay suppressed so the alias inherits the + * lab's figures exactly as `deepseek-v4-flash` does. + */ +const STALE_HOST_ROW: ReadonlySet = new Set([ + "deepseek/deepseek-chat", +]); + +/** + * Ids whose host display NAME is stale while the rest of the row is fine. + * + * `google/gemini-2.5-flash-lite` still reads "Gemini 2.5 Flash Lite Preview" + * on the host although the route serves the GA model the lab entry names + * "Gemini 2.5 Flash-Lite" — a label left over from its preview period, the + * same mistake corrected for `openai/o1`. The host-side fix is open + * (aimlapi/aimlapi#6178); until it ships the override is dropped so the lab's + * name inherits. Limits and everything else still come from the host row. + */ +const STALE_HOST_NAME: ReadonlySet = new Set([ + "google/gemini-2.5-flash-lite", +]); + +const BASE_MODEL_OVERRIDES: Readonly> = { + "deepseek/deepseek-chat": "deepseek/deepseek-v4-flash", + // Upstream spellings (dashed versions, vendor-org aliases) of models whose + // lab entry lives under the canonical spelling. The host serves only the + // spelling on the left, so the card is published under it and factored onto + // the lab entry on the right. + "google/gemini-3-8-flash": "google/gemini-3.8-flash", + "zhipu/glm-5.3": "zhipuai/glm-5.3", + "bytedance-seed/seed-2-1-turbo": "bytedance-seed/seed-2.1-turbo", + "x-ai/grok-4-6": "xai/grok-4.6", + "x-ai/grok-4-5": "xai/grok-4.5", + "moonshot/kimi-k2-7-code-highspeed": "moonshotai/kimi-k2.7-code-highspeed", + "alibaba/glm-5.2": "zhipuai/glm-5.2", + "zhipu/glm-5.2": "zhipuai/glm-5.2", + "moonshot/kimi-k2-7-code": "moonshotai/kimi-k2.7-code", + "x-ai/grok-build-0-1": "xai/grok-build-0.1", + "x-ai/grok-4-3": "xai/grok-4.3", + "bytedance/seed-2-0-pro": "bytedance-seed/seed-2.0-pro", + "openai/gpt-5-5": "openai/gpt-5.5", + "moonshot/kimi-k2-6": "moonshotai/kimi-k2.6", + "x-ai/grok-4-20-0309-non-reasoning": "xai/grok-4.20-0309-non-reasoning", + "x-ai/grok-4-20-0309-reasoning": "xai/grok-4.20-0309-reasoning", + "zhipu/glm-5.1": "zhipuai/glm-5.1", + "openai/gpt-5-4": "openai/gpt-5.4", + "zhipu/glm-5": "zhipuai/glm-5", + "upstage/solar-pro-3": "upstage/solar-pro3", + "bytedance/seed-1-8": "bytedance-seed/seed-1-8", + "bytedance-seed/seed-1.6": "bytedance-seed/seed-1-6", + "bytedance-seed/seed-1.6-flash": "bytedance-seed/seed-1-6-flash", + "zhipu/glm-4.7": "zhipuai/glm-4.7", + "openai/gpt-5-2": "openai/gpt-5.2", + "x-ai/grok-4-1-fast-reasoning": "xai/grok-4.1-fast-reasoning", + "openai/gpt-5-1": "openai/gpt-5.1", + "zhipu/glm-4.6": "zhipuai/glm-4.6", + "zhipu/glm-4.5": "zhipuai/glm-4.5", + "zhipu/glm-4.5-air": "zhipuai/glm-4.5-air", + "minimax/m2-her": "minimax/MiniMax-M2-Her", + "anthropic/claude-sonnet-4": "anthropic/claude-sonnet-4-20250514", + "ibm-granite/granite-4.2-8b": "ibm/granite-4.2-8b", + "ibm-granite/granite-4.0-h-micro": "ibm/granite-4-h-micro", + "meta-llama/Llama-3.3-70B-Instruct-Turbo": "meta/llama-3.3-70b-instruct", +}; + +/** + * Ids that are aliases of another host id on the wire, keyed to the id whose + * measurements they share. `deepseek-chat` answers `"model": "deepseek-flash"` + * exactly as `deepseek-v4-flash` does, so every probe run against the latter + * — which rungs are honoured, whether `none` switches reasoning off, which + * field carries the chain of thought — holds for the alias, and the two cards + * must resolve identically rather than the alias falling through to the + * unmeasured default. Only the measurement tables read through this map; the + * host row itself (name, limits, allowlists) stays keyed by the alias's own id. + */ +const WIRE_ALIAS_OF: Readonly> = { + "deepseek/deepseek-chat": "deepseek/deepseek-v4-flash", +}; + +/** The id whose measurements apply to `id`: its wire alias target, else itself. */ +function measuredAs(id: string): string { + return WIRE_ALIAS_OF[id] ?? id; +} + +function baseModelFor(id: string): string | undefined { + return BASE_MODEL_OVERRIDES[id] ?? resolveModelMetadataBaseModel(id); +} + +/** + * The lab entry's own effort rungs, or `undefined` when it has none. + * + * This is the baseline the sync now derives from. Where the lab and this host + * disagree, the lab wins by construction — and that has a known price, paid + * on purpose after seven review rounds asked for it. Rungs this host accepts + * AND measurably honours are dropped because the lab does not list them: + * `low` on `deepseek-v4-pro` (4175 reasoning tokens against 5662 at `high`), + * `high` on `qwen3.8-max` (2000, spending its full budget), `max` on + * `gemini-3.7-flash` (6585 against 3841 at `high`, the largest effect measured + * anywhere in this file), and `low`/`medium` on `gpt-5-pro` (64/256/320 on a + * light prompt). Callers of those ids lose working levels. The measurements + * stay in the history so the decision can be reversed with evidence in hand. + * + * What the doctrine buys is that re-sync cannot reintroduce a rung the lab + * does not publish, and that this provider reads like its peers. + */ +/** What the lab's provider entry says about effort, three ways. */ +export type LabLadder = + | { kind: "effort"; values: readonly string[]; source: "lab" | "peer" } + | { kind: "no-effort"; source: "lab" | "peer" } // the entry exists and lists toggle/budget only + | { kind: "no-entry" }; // neither a first-party nor an OpenRouter entry for this base + +export function labEffortValues(baseModelID: string): readonly string[] | undefined { + const ladder = labLadder(baseModelID); + return ladder.kind === "effort" ? ladder.values : undefined; +} + +export function labLadder(baseModelID: string): LabLadder { + // The lab's ladder lives on its first-party PROVIDER entry, not on the + // shared model record: `models//.toml` carries name, family and + // capabilities and no `reasoning_options`. So this reads + // `providers//models/.toml`, the same file a reviewer means when + // they say "the lab publishes". + const slash = baseModelID.indexOf("/"); + if (slash === -1) return { kind: "no-entry" }; + // `base_model` names the METADATA lab; the ladder is under the PROVIDER + // directory, and for `zhipuai` -> `zai`, `meta` -> `llama` those differ. + // The first version of this lookup assumed they matched and silently kept + // the host enum for every GLM id — the review caught it from the TOMLs. + // The mapping is not one-to-one either: Meta's Llama cards live under + // `llama/` but its Muse cards under `meta/`, so both the mapped directory + // and the lab's own name are tried, and the lookup that assumed one + // directory per lab was the second silent miss of the same kind. + const metadataLab = baseModelID.slice(0, slash); + const labDirs = [providerDirForMetadataLab(metadataLab), metadataLab].filter( + (dir, index, all) => all.indexOf(dir) === index, + ); + const name = baseModelID.slice(slash + 1); + // A dated snapshot (`deepseek-v4-pro-0813`) has no lab entry of its own and + // is the same control surface as the model it snapshots, so it borrows that + // entry's ladder rather than falling through to the host's enum — which is + // what left `0813` wider than the sibling it is a copy of. + const candidates = [name, name.replace(/-\d{4}$/, "")].filter( + (candidate, index, all) => all.indexOf(candidate) === index, + ); + for (const labDir of labDirs) { + const own = readLadder(labDir, candidates, "lab"); + if (own.kind !== "no-entry") return own; + } + // No first-party entry. The next-best baseline is an established peer on + // the same surface: OpenRouter's card for the same lab id, which the review + // names as the reference whenever the lab is silent. Its ladder is used + // exactly like a lab ladder — intersected, never widened — and its + // toggle-only cards count as "no effort ladder" just as a lab's would. + // OpenRouter files Alibaba under `qwen/`, so every directory it uses for + // the lab is tried. Only when neither exists is the model unresolved. + const peerPaths = openrouterDirsForMetadataLab(metadataLab).flatMap((dir) => + candidates.map((candidate) => `${dir}/${candidate}`), + ); + return readLadder(PEER_DIR, peerPaths, "peer"); +} + +/** OpenRouter's provider directory: the peer baseline when the lab is silent. */ +const PEER_DIR = "openrouter"; + +function readLadder(providerDir: string, modelPaths: readonly string[], source: "lab" | "peer"): LabLadder { + let parsed: Record | undefined; + for (const candidate of modelPaths) { + const file = path.join(PROVIDERS_DIR, providerDir, "models", `${candidate}.toml`); + try { + parsed = Bun.TOML.parse(readFileSync(file, "utf8")) as Record; + break; + } catch { + /* try the next candidate */ + } + } + if (parsed === undefined) return { kind: "no-entry" }; + const opts = parsed["reasoning_options"]; + if (!Array.isArray(opts)) return { kind: "no-entry" }; + const effort = opts.find((o) => o && typeof o === "object" && (o as { type?: unknown }).type === "effort") as + | { values?: unknown } + | undefined; + return Array.isArray(effort?.values) + ? { kind: "effort", values: effort!.values as string[], source } + : { kind: "no-effort", source }; +} + +/** + * `gpt-5-pro` is worth a line here because it was argued over the longest. + * The lab publishes `["high"]`; this host accepts `low` and `medium` too and + * ordered them on a light prompt (64/256/320). The review asked for the same + * on a hard prompt before keeping the extras, and that probe cannot be run: + * every level times out at the gateway on it, three of three. Under the + * intersection the point is moot — the lab set wins and `["high"]` is what + * ships — but the light-prompt ordering is real and is recorded so nobody + * reads the narrower set as a finding that the rungs did nothing. + */ + +/** + * Toggle- or budget-only labs whose `reasoning_effort` on this host was + * nonetheless measured to be live, recorded so the decision not to publish + * them can be revisited with the evidence in hand: + * + * gemini-2.5-flash-lite low 863 -> high 2399 reasoning tokens + * qwen3.6-27b, qwen3.7-max, qwen3.6-35b-a3b + * `low`/`medium` select the lab's thinking budget: + * the gateway answers "must be greater than + * thinking_budget [8192]" / "[32768]" when + * max_tokens is below them. + * + * They are NOT published. The baseline rule is lab ∩ host, and a lab that + * lists only a toggle or a budget has no effort ladder to intersect with; an + * effort list here would be the host's control family under a name the lab + * and its peers (OpenRouter: toggle only) do not use. The review held that + * line across several rounds and it is the line this file follows: these + * four reasoners are unresolved and skipped until either the lab publishes + * an effort ladder or this host exposes the budget itself. The measurements + * above stay so nobody reads the skip as a finding that the field did nothing. + */ +export const HOST_EFFORT_MEASURED_BUT_UNPUBLISHED: ReadonlySet = new Set([ + "google/gemini-2.5-flash-lite", + "alibaba/qwen3.6-27b", + "alibaba/qwen3.7-max", + "alibaba/qwen3.6-35b-a3b", +]); + +/** + * Ids where `reasoning_effort: none` is a measured off switch on this wire — + * zero reasoning tokens against a non-zero count at a higher rung, with an + * invalid value rejected so the field is known to be read. The lab sets never + * carry `none`, so the intersection strips it; this is the only way back in. + * + * NOT here, deliberately: `claude-sonnet-5`, where `none` maps to `low`, and + * `qwen3.8-max`, where it never reported a reasoning count at all. + */ +const NONE_IS_REAL_OFF: ReadonlySet = new Set([ + "deepseek/deepseek-v4-pro", + "deepseek/deepseek-v4-pro-0813", + // Flash measured by the strongest signal there is, the side channel itself: + // `none` returns an EMPTY `reasoning_content` where `high` returns 23469 + // characters on `v4-flash` and 12826 on `vision-exp`. `reasoning_tokens` is + // absent rather than 0 on this link, which is why the count alone was not + // enough to call it — the same shape was left unclaimed on `qwen3.8-max`. + "deepseek/deepseek-v4-flash", + "deepseek/deepseek-v4-flash-vision-exp", + "openai/gpt-5.3-codex", + "openai/gpt-5.6-luna", + "openai/gpt-5.6-sol", + "openai/gpt-5.6-terra", + "openai/gpt-5.6-terra-pro", + "anthropic/claude-opus-4.7", + "anthropic/claude-opus-4.8", +]); + +function baseReasoning(baseModelID: string): boolean { + try { + return modelMetadata(baseModelID).reasoning === true; + } catch { + return false; + } +} + +/** + * Prices are quoted as `price` per `per` tokens; models.dev stores dollars per + * million. The unit discriminator is `origin`, not `measure`: provided is + * input, generated is output, cached is a cache read. Only text token charges + * are taken — a model's image or audio units are a different surface. + */ +function perMillion(units: readonly z.infer[], origin: string): number | undefined { + const unit = units.find( + (candidate) => candidate.name === "token" && candidate.content === "text" && candidate.origin === origin, + ); + if (!unit || unit.price == null || !unit.per) return undefined; + // Round before returning. `(0.0000000078 / 1) * 1e6` is + // 0.0078000000000000005 in IEEE double, and `formatNumber` serializes the + // residue verbatim — so the catalogue carried a price with fifteen decimals + // that changes shape whenever the upstream `per` does. Six decimals is finer + // than any published USD/MTok figure here. + return Math.round(((unit.price / unit.per) * 1_000_000) * 1e6) / 1e6; +} + +function positive(value: number | null | undefined): number | undefined { + return value != null && value > 0 ? value : undefined; +} + +/** + * Reads the documented `reasoning_effort` values for one model. Returns + * undefined when the docs do not describe the control, which is treated as + * "cannot state it" rather than "the model has none". + * + * One model's schema can carry the control more than once, because the request + * body is a union of per-family variants and several of them accept it with + * different ladders. Taking the first one found means taking whichever variant + * happens to be earliest in the document, which drops real values: at the time + * of writing that costs `minimal` on the gpt-5 family, `max` on claude-sonnet-4.6 + * and claude-opus-4.8, and `none` on the gemini flash models. The union across + * every occurrence is what the endpoint actually accepts. + */ +async function fetchReasoningEffort(id: string, base: string): Promise { + const url = `${DOCS_ENDPOINT}?model=${encodeURIComponent(id)}&endpoint=${encodeURIComponent(CHAT_COMPLETIONS_TYPE)}`; + let payload: unknown; + try { + const response = await fetch(url); + if (!response.ok) return undefined; + payload = await response.json(); + } catch { + return undefined; + } + + const measuredId = measuredAs(id); + if (EFFORT_NOT_HONOURED.has(measuredId) || EFFORT_VALIDATED_BUT_INERT.has(measuredId)) return undefined; + + const found = new Set(); + collectReasoningEffortEnums(payload, found); + + const host = [...found] + .filter((value) => EFFORT_RANK.has(value)) + .sort((a, b) => EFFORT_RANK.get(a)! - EFFORT_RANK.get(b)!); + if (host.length === 0) return undefined; + + return resolveLadder(id, base, host); +} + +/** + * The published ladder for `id`, given the rungs its host schema accepts. + * Pure, so the rules can be tested without the network: + * + * 1. Intersect with the lab's own ladder where it has one. A rung the host + * offers but the lab does not is dropped even when it measures as working + * — that is the doctrine, costed on `labEffortValues`. An empty + * intersection keeps the host enum: it means the lab's rungs are refused + * here, not that no control exists. + * 2. `none` is ours, not the lab's: kept only where the lab lists it or a + * probe showed a real off switch (`NONE_IS_REAL_OFF`), lab ladder or not. + * 3. A measurement may narrow the result — an accepted rung that turns out + * inert — but never widen it past the lab. + */ +export function resolveLadder(id: string, base: string, host: readonly string[]): string[] | undefined { + const ladder = labLadder(base); + let values: string[]; + let lab: readonly string[] | undefined; + // A peer's `none` is that relay's own off mapping, not the lab's word that + // the rung exists; it is not taken on trust the way a lab-listed `none` is. + const labSpeaks = ladder.kind !== "no-entry" && ladder.source === "lab"; + + switch (ladder.kind) { + case "effort": { + lab = ladder.values; + const shared = host.filter((value) => lab!.includes(value)); + // Every lab rung refused here. That is a contradiction, not a licence + // to publish the host's rungs under the lab's name: unresolved, so the + // model is skipped rather than shipped with an invented ladder. + if (shared.length === 0) return undefined; + values = shared; + break; + } + case "no-effort": + // The lab (or, failing it, the peer) has spoken and said "toggle / + // budget, no effort ladder". There is nothing to intersect with, and a + // host effort enum would claim a control family the baseline denies — + // even where the field measured live (see + // HOST_EFFORT_MEASURED_BUT_UNPUBLISHED). `[]` would claim no control, + // which a validated field rules out. So the model is unresolved and + // skipped. + return undefined; + case "no-entry": + // Neither the lab nor the peer publishes a ladder for this model, so + // there is nothing to intersect with and the host's enum would ship as + // a bare schema dump. Unresolved: the model is skipped until a baseline + // exists rather than given boilerplate rungs. + return undefined; + } + + const measuredId = measuredAs(id); + const labListsNone = labSpeaks && lab !== undefined && lab.includes("none"); + const noneAllowed = labListsNone || NONE_IS_REAL_OFF.has(measuredId); + if (!noneAllowed) values = values.filter((value) => value !== "none"); + else if (host.includes("none") && !values.includes("none")) values = ["none", ...values]; + + const measured = MEASURED_EFFORTS[measuredId]; + if (measured) values = values.filter((value) => measured.includes(value)); + + return values.length > 0 ? values : undefined; +} + +function collectReasoningEffortEnums(node: unknown, into: Set): void { + if (Array.isArray(node)) { + for (const item of node) collectReasoningEffortEnums(item, into); + return; + } + if (node === null || typeof node !== "object") return; + + const record = node as Record; + const effort = record["reasoning_effort"]; + if (effort !== null && typeof effort === "object") { + const values = (effort as Record)["enum"]; + if (Array.isArray(values) && values.every((value) => typeof value === "string")) { + for (const value of values as string[]) into.add(value); + } + } + + // Keep walking either way: the same schema can describe the control again in + // a sibling variant of the request-body union. + for (const value of Object.values(record)) collectReasoningEffortEnums(value, into); +} + +async function attachReasoningEffort(models: AimlapiModel[]): Promise { + // Only models whose lab entry says they reason need the control documented, + // and only those are worth a request. + const pending = models.filter((model) => { + if (NOT_CALLABLE.has(model.id)) return false; + if (ALIAS_DUPLICATE_IDS.has(model.id)) return false; + if (!isChatTextModel(model)) return false; + const base = baseModelFor(model.id); + return base !== undefined && baseReasoning(base); + }); + + let cursor = 0; + const workers = Array.from({ length: Math.min(DOCS_CONCURRENCY, pending.length) }, async () => { + while (cursor < pending.length) { + const model = pending[cursor++]; + if (model === undefined) return; + const base = baseModelFor(model.id); + if (base === undefined) continue; + model.reasoningEffort = await fetchReasoningEffort(model.id, base); + } + }); + await Promise.all(workers); +} + +/** + * The leading comment a card carries so a reader can see what the wire does + * without opening this file. Only cards whose control story is not plain + * "lab ladder ∩ host enum" get one — the ones a review has to ask about. + */ +function wireHeader(id: string, reasoningOptions: Array<{ type: "effort"; values: EffortValue[] }> | undefined): string | undefined { + const measuredId = measuredAs(id); + const lines: string[] = []; + if (measuredId !== id) { + lines.push(`# Alias: answers "model" as ${measuredId.slice(measuredId.indexOf("/") + 1)}; measured through that id.`); + } + if (reasoningOptions !== undefined && reasoningOptions.length === 0) { + lines.push( + EFFORT_NOT_HONOURED.has(measuredId) + ? "# No caller control: reasoning_effort is not read (an invalid value returns 200)," + : "# No caller control: reasoning_effort is validated (invalid value -> 400) but low/high", + EFFORT_NOT_HONOURED.has(measuredId) + ? "# and toggle/budget fields are dropped by the gateway (unknown top-level keys -> 200)." + : "# do not order reasoning tokens; toggle/budget fields are dropped by the gateway.", + ); + } + if (NONE_IS_REAL_OFF.has(measuredId)) { + lines.push("# Off: reasoning_effort = none (0 reasoning tokens); no toggle field on this surface."); + } + return lines.length > 0 ? lines.join("\n") + "\n" : undefined; +} + +/** + * The remote id to report for a chat candidate, or `undefined` for records + * sync intentionally ignores: uncallable rows, dashed alias duplicates, and + * anything that is not a text-output chat model. `sourceID` reports every + * candidate skip in the sync report. `missingModelID` is narrower — it routes + * a skip to the missing-model issue flow only when an issue can fix it: + * + * - No lab entry to point `base_model` at: the issue flow authors it. + * - A card already on disk that sync can no longer state (its reasoning + * control stopped resolving): preserved, and the issue asks for research. + * + * A new model whose lab exists but whose thinking control cannot be stated + * on this host is deliberately not issued: no entry an issue could write + * would make the control exist. It stays unlisted until the host offers one + * that resolves, and appears here only as a report notice. + */ +function candidateID(model: AimlapiModel): string | undefined { + if (BLACKLISTED.has(model.id)) return undefined; + if (NOT_CALLABLE.has(model.id)) return undefined; + if (ALIAS_DUPLICATE_IDS.has(model.id)) return undefined; + return isChatTextModel(model) ? model.id : undefined; +} + +function issueModelID(model: AimlapiModel): string | undefined { + if (candidateID(model) === undefined) return undefined; + if (baseModelFor(model.id) === undefined) return model.id; + const local = path.join(PROVIDERS_DIR, "aimlapi", "models", `${model.id}.toml`); + return existsSync(local) ? model.id : undefined; +} + +export const aimlapi = { + id: "aimlapi", + name: "AI/ML API", + modelsDir: "providers/aimlapi/models", + // Sync owns what the catalog can state for models already on disk: pricing, + // limits, reasoning controls, and removal once the host stops serving a + // model (`deleteMissing`). It never creates a model: the catalog cannot + // fully populate a new entry (no lab metadata, capabilities, or dates), so + // every remote-only model goes through the missing-model issue flow + // (`skipCreates`), where the lab entry and provider card are authored and + // reviewed. Later syncs then keep that file updated. + skipCreates: true, + trackMissingModels: true, + deleteMissing: true, + authoritativeHeaders: true, + sourceID(model) { + return candidateID(model); + }, + missingModelID(model) { + return issueModelID(model); + }, + skippedNotice(ids) { + if (ids.length === 0) return []; + return [ + `${ids.length} AI/ML API chat models were not written by sync. Models with no lab entry to point \`base_model\` at are routed to the missing-model issue flow for authoring; models whose thinking control cannot be stated on this host stay unlisted until the host offers one that resolves, and are listed here only. Existing files for skipped ids are preserved.`, + `Skipped remote IDs: ${ids.map((id) => `\`${id}\``).join(", ")}`, + ]; + }, + async fetchModels() { + const response = await fetch(API_ENDPOINT); + if (!response.ok) { + throw new Error(`AI/ML API request failed: ${response.status} ${response.statusText}`); + } + const raw = await response.json(); + const parsed = AimlapiResponse.parse(raw); + indexMediaOutputs(parsed.data); + indexAliasDuplicates(parsed.data); + await attachReasoningEffort(parsed.data); + return parsed; + }, + parseModels(raw) { + const models = AimlapiResponse.parse(raw).data; + // Replays parse a cached payload without going through fetchModels. + indexMediaOutputs(models); + indexAliasDuplicates(models); + return models; + }, + translateModel(model, context) { + if (BLACKLISTED.has(model.id)) return undefined; + if (NOT_CALLABLE.has(model.id)) return undefined; + if (ALIAS_DUPLICATE_IDS.has(model.id)) return undefined; + if (!isChatTextModel(model)) return undefined; + + const existing = context.existing(model.id); + + // AI/ML API hosts other people's models, so the entry must reference the + // lab file instead of duplicating it. Without a lab entry to point at there + // is nothing correct to write: inlining the metadata is what this schema + // forbids, and authoring the lab file would mean sourcing capability data + // the catalog does not publish. + const base = existing?.base_model ?? baseModelFor(model.id); + if (base === undefined) return undefined; + + // Required whenever the base model reasons. Only the API's own request + // schema can say which values it takes, so a model whose docs stay silent + // is skipped rather than given an invented control. + let reasoningOptions: Array<{ type: "effort"; values: EffortValue[] }> | undefined; + if (baseReasoning(base)) { + // A model that reasons but honours no caller control gets an empty list: + // the schema requires the field, and an empty one states the truth — + // reasoning happens, nothing about it is selectable. + if (EFFORT_NOT_HONOURED.has(measuredAs(model.id)) || EFFORT_VALIDATED_BUT_INERT.has(measuredAs(model.id))) { + reasoningOptions = []; + } else { + const values = model.reasoningEffort?.filter(isEffortValue); + if (values === undefined || values.length === 0) return undefined; + reasoningOptions = [{ type: "effort", values }]; + } + } + + const units = model.pricing?.units ?? []; + const info = model.info ?? {}; + const contextLimit = positive(info.contextLength); + const outputLimit = positive(info.outputMax); + // Only what the catalog actually publishes. It reports a context window and + // an output cap but no input cap, and equating the input cap with the whole + // context would overwrite the lab's correct split (e.g. 272k in + 128k out + // within a 400k window) with a wrong number. + const limit = + STALE_HOST_ROW.has(model.id) || + (contextLimit === undefined && outputLimit === undefined) + ? undefined + : { + ...(contextLimit === undefined ? {} : { context: contextLimit }), + ...(outputLimit === undefined ? {} : { output: outputLimit }), + }; + + // Everything else — the capability flags, description, dates, modalities — + // is the lab's to state and is inherited. factorBaseModel drops whatever + // matches the base, so the file carries only what is genuinely ours. + // A row the host lists but does not price is not sellable through it, and + // the schema (rightly) will not carry a card without a price. Skip it + // rather than invent zeros. + const inputCost = perMillion(units, "provided") ?? existing?.cost?.input; + const outputCost = perMillion(units, "generated") ?? existing?.cost?.output; + if (inputCost === undefined || outputCost === undefined) return undefined; + + return { + id: model.id, + header: wireHeader(model.id, reasoningOptions), + model: factorBaseModel( + base, + { + cost: { + input: inputCost, + output: outputCost, + cache_read: perMillion(units, "cached") ?? existing?.cost?.cache_read, + }, + // Aliases such as `-pro` and `-fast` factor onto the base model and + // would inherit its display name, so the catalogue would list two rows + // called "GPT-5.6 Luna". The host names them apart; carry that through + // and the override drops itself when the names already agree. + name: + STALE_HOST_ROW.has(model.id) || STALE_HOST_NAME.has(model.id) ? undefined : (info.name ?? undefined), + reasoning_options: reasoningOptions, + interleaved: INTERLEAVED_FIELD[measuredAs(model.id)] + ? { field: INTERLEAVED_FIELD[measuredAs(model.id)]! } + : undefined, + limit, + }, + limit, + existing?.base_model === base ? existing?.base_model_omit : undefined, + ), + }; + }, +} satisfies SyncProvider; diff --git a/packages/core/src/sync/providers/openrouter.ts b/packages/core/src/sync/providers/openrouter.ts index f90874363fa..018f8ce72e6 100644 --- a/packages/core/src/sync/providers/openrouter.ts +++ b/packages/core/src/sync/providers/openrouter.ts @@ -64,6 +64,36 @@ const CANONICAL_PROVIDER_PREFIXES = { "zai-org": { provider: "zai", metadata: "zhipuai" }, } as const; +/** + * The first-party provider directory for a metadata lab id. + * + * `base_model` ids are spelled with the METADATA lab (`zhipuai/glm-4.7-flash`, + * `meta/llama-...`) while a lab's own reasoning ladder lives under its + * PROVIDER directory (`providers/zai`, `providers/llama`). The two coincide for + * most labs and not for these, and a lookup that assumes they coincide fails + * silently — the caller falls back to whatever it had, which for a relay means + * publishing the host's enum as if it were the lab's. + */ +export function providerDirForMetadataLab(metadata: string): string { + for (const entry of Object.values(CANONICAL_PROVIDER_PREFIXES)) { + if (entry.metadata === metadata) return entry.provider; + } + return metadata; +} + +/** + * The OpenRouter model-directory prefixes that carry a metadata lab, in table + * order — e.g. `alibaba` lives under both `alibaba/` and `qwen/` on OpenRouter, + * and only the latter is populated. + */ +export function openrouterDirsForMetadataLab(metadata: string): string[] { + const dirs: string[] = []; + for (const [prefix, entry] of Object.entries(CANONICAL_PROVIDER_PREFIXES)) { + if (entry.metadata === metadata) dirs.push(prefix); + } + return dirs.length > 0 ? dirs : [metadata]; +} + export const OpenRouterModel = z.object({ id: z.string(), name: z.string(), diff --git a/packages/core/test/aimlapi.test.ts b/packages/core/test/aimlapi.test.ts new file mode 100644 index 00000000000..1013274da0e --- /dev/null +++ b/packages/core/test/aimlapi.test.ts @@ -0,0 +1,198 @@ +import { expect, test } from "bun:test"; + +import { aimlapi, labEffortValues, labLadder, resolveLadder } from "../src/sync/providers/aimlapi.js"; +import { providerDirForMetadataLab } from "../src/sync/providers/openrouter.js"; + +// The lookup that silently kept the host enum for every GLM id: `base_model` +// names the metadata lab, the ladder lives under the provider directory, and +// for these two they differ. +test("maps a metadata lab to its first-party provider directory", () => { + expect(providerDirForMetadataLab("zhipuai")).toBe("zai"); + expect(providerDirForMetadataLab("deepseek")).toBe("deepseek"); + expect(providerDirForMetadataLab("no-such-lab")).toBe("no-such-lab"); +}); + +test("a lab split across two provider directories is read from both", () => { + // Meta's Llama cards live under `llama/`, its Muse cards under `meta/`. + expect(providerDirForMetadataLab("meta")).toBe("llama"); + expect(labLadder("meta/muse-spark-1.1")).toEqual({ + kind: "effort", + values: ["minimal", "low", "medium", "high", "xhigh"], + source: "lab", + }); + expect(resolveLadder("meta/muse-spark-1.1", "meta/muse-spark-1.1", ["low", "medium", "high"])).toEqual([ + "low", + "medium", + "high", + ]); +}); + +test("reads the lab ladder through the provider directory, not the model record", () => { + // `models/zhipuai/*.toml` has no reasoning_options; `providers/zai/models` + // does. A lookup on the wrong one returns undefined and looks like "no lab + // ladder", which is a different claim. + expect(labEffortValues("zhipuai/glm-5.3-flash")).toEqual(["low", "high", "max"]); + expect(labEffortValues("deepseek/deepseek-v4-pro")).toEqual(["low", "high", "max"]); +}); + +test("a dated snapshot borrows the ladder of the model it snapshots", () => { + // There is no `deepseek-v4-pro-0813.toml` in the lab; without the borrow it + // fell through to the host enum and came out wider than its own base. + expect(labEffortValues("deepseek/deepseek-v4-pro-0813")).toEqual(labEffortValues("deepseek/deepseek-v4-pro")); +}); + +test("a lab entry with toggle only and no effort ladder yields undefined", () => { + expect(labEffortValues("zhipuai/glm-4.7-flash")).toBeUndefined(); +}); + +const HOST = ["none", "low", "medium", "high"] as const; + +test("intersects the host enum with the lab ladder and drops the rest", () => { + // lab low/high/max, host none..high: `medium` goes although the host + // accepts it — that is the doctrine, and this test pins its cost. + expect(resolveLadder("deepseek/deepseek-v4-pro", "deepseek/deepseek-v4-pro", HOST)).toEqual(["none", "low", "high"]); +}); + +test("`none` survives only where measured as a real off switch", () => { + // Same lab, same host enum; only the measurement differs. + expect(resolveLadder("deepseek/deepseek-v4-pro", "deepseek/deepseek-v4-pro", HOST)).toContain("none"); + expect(resolveLadder("deepseek/deepseek-v4-flash", "deepseek/deepseek-v4-flash", HOST)).toContain("none"); +}); + +test("`none` is kept where the lab itself lists it", () => { + const host = ["none", "low", "medium", "high"]; + expect(resolveLadder("openai/gpt-5.6-luna", "openai/gpt-5.6-luna", host)).toContain("none"); +}); + +test("a measurement narrows but never widens past the lab", () => { + // gpt-5.4-pro: lab medium/high/xhigh, host low/medium/high, measured medium/high. + expect(resolveLadder("openai/gpt-5.4-pro", "openai/gpt-5.4-pro", ["low", "medium", "high"])).toEqual(["medium", "high"]); +}); + +// The fallthrough the review found: a toggle-only lab must never turn into a +// host-schema L/M/H dump. Either the host field is measured live for that id, +// or the model is unresolved. +test("a toggle-only lab base never yields the host's effort dump", () => { + const host = ["none", "minimal", "low", "medium", "high"]; + // glm-4.5v: lab toggle-only -> unresolved. + expect(resolveLadder("z-ai/glm-4.5v", "zhipuai/glm-4.5v", host)).toBeUndefined(); + // qwen3.7-max: lab toggle+budget. The host's effort field measured live + // (its names select the budget tiers), and it is still unresolved: a + // toggle/budget baseline has no effort ladder to intersect with. + expect(resolveLadder("alibaba/qwen3.7-max", "alibaba/qwen3.7-max", host)).toBeUndefined(); + expect(resolveLadder("google/gemini-2.5-flash-lite", "google/gemini-2.5-flash-lite", host)).toBeUndefined(); +}); + +test("an empty intersection is unresolved, not the host enum", () => { + // lab low/high/max, host offers none of them -> skip, do not republish. + expect(resolveLadder("deepseek/deepseek-v4-pro", "deepseek/deepseek-v4-pro", ["medium"])).toBeUndefined(); +}); + +test("a base with no lab entry falls back to the OpenRouter peer's ladder, intersected", () => { + // No `providers/tencent/models/hy3.toml`; OpenRouter lists none/low/high. + expect(labLadder("tencent/hy3")).toEqual({ kind: "effort", values: ["none", "low", "high"], source: "peer" }); + expect(resolveLadder("tencent/hy3", "tencent/hy3", ["low", "medium", "high"])).toEqual(["low", "high"]); + // A peer-listed `none` is not taken on trust the way a lab-listed one is. + expect(resolveLadder("tencent/hy3", "tencent/hy3", ["none", "low", "medium", "high"])).toEqual(["low", "high"]); + // OpenRouter files Alibaba under `qwen/`. + expect(labLadder("alibaba/qwen3.8-27b")).toEqual({ kind: "effort", values: ["low", "medium", "xhigh"], source: "peer" }); +}); + +test("a peer that is toggle-only counts as no effort ladder, not as a licence for the host enum", () => { + // No lab entry for Opus 4.1; OpenRouter's card is toggle-only. + expect(labLadder("anthropic/claude-opus-4.1")).toEqual({ kind: "no-effort", source: "peer" }); + expect(resolveLadder("anthropic/claude-opus-4.1", "anthropic/claude-opus-4.1", ["low", "medium", "high"])).toBeUndefined(); +}); + +test("a base with neither a lab nor a peer entry is unresolved, not the host enum", () => { + expect(labLadder("nolab/nothing-here")).toEqual({ kind: "no-entry" }); + expect(resolveLadder("some/model", "nolab/nothing-here", ["low", "high"])).toBeUndefined(); +}); + +test("a wire alias resolves through the measurements of the id it answers as", () => { + const host = ["none", "low", "medium", "high"]; + // `deepseek-chat` answers `"model": "deepseek-flash"` exactly as + // `deepseek-v4-flash` does, so the probes run against the latter (`none` + // switches reasoning off; `medium` is inert) apply to the alias too. + expect(resolveLadder("deepseek/deepseek-chat", "deepseek/deepseek-v4-flash", host)).toEqual( + resolveLadder("deepseek/deepseek-v4-flash", "deepseek/deepseek-v4-flash", host), + ); + expect(resolveLadder("deepseek/deepseek-chat", "deepseek/deepseek-v4-flash", host)).toEqual(["none", "low", "high"]); +}); + +// Sync owns updates and removals for models already on disk, but never +// creates: a new model goes through the missing-model issue flow, where its +// lab entry and provider card are authored and reviewed. +test("sync updates and removes existing models but routes creates to issues", () => { + expect(aimlapi.skipCreates).toBe(true); + expect(aimlapi.trackMissingModels).toBe(true); + expect(aimlapi.deleteMissing).toBe(true); +}); + +test("only chat candidates are reported for the missing-model issue flow", () => { + const models = aimlapi.parseModels({ + data: [ + { + id: "acme/chat-1", + type: "openai/chat-completions", + info: { name: "Chat 1" }, + modalities: { input: ["text"], output: ["text"] }, + }, + { + id: "acme/image-1", + type: "openai/image-generations", + info: { name: "Image 1" }, + modalities: { input: ["text"], output: ["image"] }, + }, + { + id: "anthropic/claude-opus-4.8", + type: "openai/chat-completions", + info: { name: "Claude Opus 4.8" }, + modalities: { input: ["text"], output: ["text"] }, + }, + { + id: "anthropic/claude-opus-4-8", + type: "openai/chat-completions", + info: { name: "Claude Opus 4.8" }, + modalities: { input: ["text"], output: ["text"] }, + }, + { + id: "anthropic/claude-opus-4.7-fast", + type: "openai/chat-completions", + info: { name: "Claude Opus 4.7 Fast" }, + modalities: { input: ["text"], output: ["text"] }, + }, + ], + }); + const byID = new Map(models.map((model) => [model.id, model])); + // A chat candidate a skip cannot fully populate is reported and routed to + // an issue; intentional ignores (non-chat, alias duplicate, uncallable) + // are neither, so sync can still delete those files when they go stale. + expect(aimlapi.sourceID(byID.get("acme/chat-1")!)).toBe("acme/chat-1"); + expect(aimlapi.missingModelID(byID.get("acme/chat-1")!)).toBe("acme/chat-1"); expect(aimlapi.sourceID(byID.get("acme/image-1")!)).toBeUndefined(); + expect(aimlapi.missingModelID(byID.get("acme/image-1")!)).toBeUndefined(); + expect(aimlapi.sourceID(byID.get("anthropic/claude-opus-4-8")!)).toBeUndefined(); + expect(aimlapi.missingModelID(byID.get("anthropic/claude-opus-4-8")!)).toBeUndefined(); + expect(aimlapi.sourceID(byID.get("anthropic/claude-opus-4.7-fast")!)).toBeUndefined(); + expect(aimlapi.missingModelID(byID.get("anthropic/claude-opus-4.7-fast")!)).toBeUndefined(); +}); + +test("a lab-backed model with no card and no statable control is reported, not issued", () => { + // qwen3.7-max has a lab entry but publishes toggle/budget only, so sync + // cannot state its thinking control on this host. An issue cannot fix + // that; the model stays unlisted and is only reported. A candidate with + // no lab entry at all (acme/chat-1 above) is issued, because an issue + // can author the entry. + const [model] = aimlapi.parseModels({ + data: [ + { + id: "alibaba/qwen3.7-max", + type: "openai/chat-completions", + info: { name: "Qwen3.7 Max" }, + modalities: { input: ["text"], output: ["text"] }, + }, + ], + }); + expect(aimlapi.sourceID(model!)).toBe("alibaba/qwen3.7-max"); + expect(aimlapi.missingModelID(model!)).toBeUndefined(); +}); diff --git a/providers/aimlapi/logo.svg b/providers/aimlapi/logo.svg new file mode 100755 index 00000000000..5bd69eb5625 --- /dev/null +++ b/providers/aimlapi/logo.svg @@ -0,0 +1,3 @@ + + + diff --git a/providers/aimlapi/models/aion-labs/aion-rp-llama-3.1-8b.toml b/providers/aimlapi/models/aion-labs/aion-rp-llama-3.1-8b.toml new file mode 100644 index 00000000000..4d5f44a0ac6 --- /dev/null +++ b/providers/aimlapi/models/aion-labs/aion-rp-llama-3.1-8b.toml @@ -0,0 +1,8 @@ +base_model = "aion-labs/aion-rp-llama-3.1-8b" + +[cost] +input = 1.10032 +output = 2.20064 + +[limit] +output = 32_768 diff --git a/providers/aimlapi/models/alibaba/qwen-max.toml b/providers/aimlapi/models/alibaba/qwen-max.toml new file mode 100644 index 00000000000..b67b2dfda47 --- /dev/null +++ b/providers/aimlapi/models/alibaba/qwen-max.toml @@ -0,0 +1,9 @@ +base_model = "alibaba/qwen-max" + +[cost] +input = 2.08 +output = 8.32 +cache_read = 0.416 + +[limit] +context = 32_000 diff --git a/providers/aimlapi/models/alibaba/qwen-plus.toml b/providers/aimlapi/models/alibaba/qwen-plus.toml new file mode 100644 index 00000000000..c031d384512 --- /dev/null +++ b/providers/aimlapi/models/alibaba/qwen-plus.toml @@ -0,0 +1,13 @@ +# No caller control: reasoning_effort is not read (an invalid value returns 200), +# and toggle/budget fields are dropped by the gateway (unknown top-level keys -> 200). +base_model = "alibaba/qwen-plus" +reasoning_options = [] + +[cost] +input = 0.52 +output = 1.56 +cache_read = 0.104 + +[limit] +context = 131_000 +output = 16_384 diff --git a/providers/aimlapi/models/alibaba/qwen3-coder-480b-a35b-instruct.toml b/providers/aimlapi/models/alibaba/qwen3-coder-480b-a35b-instruct.toml new file mode 100644 index 00000000000..f1ee9a33c56 --- /dev/null +++ b/providers/aimlapi/models/alibaba/qwen3-coder-480b-a35b-instruct.toml @@ -0,0 +1,9 @@ +base_model = "alibaba/qwen3-coder-480b-a35b-instruct" +name = "Qwen3 Coder" + +[cost] +input = 1.95 +output = 9.75 + +[limit] +context = 262_000 diff --git a/providers/aimlapi/models/alibaba/qwen3-max-preview.toml b/providers/aimlapi/models/alibaba/qwen3-max-preview.toml new file mode 100644 index 00000000000..1a3872e1dad --- /dev/null +++ b/providers/aimlapi/models/alibaba/qwen3-max-preview.toml @@ -0,0 +1,9 @@ +base_model = "alibaba/qwen3-max-preview" + +[cost] +input = 1.56 +output = 7.8 +cache_read = 0.312 + +[limit] +context = 252_000 diff --git a/providers/aimlapi/models/alibaba/qwen3-max.toml b/providers/aimlapi/models/alibaba/qwen3-max.toml new file mode 100644 index 00000000000..a4de21068d7 --- /dev/null +++ b/providers/aimlapi/models/alibaba/qwen3-max.toml @@ -0,0 +1,7 @@ +base_model = "alibaba/qwen3-max" +name = "Qwen3 Max Instruct" + +[cost] +input = 1.56 +output = 7.8 +cache_read = 0.312 diff --git a/providers/aimlapi/models/alibaba/qwen3-next-80b-a3b-instruct.toml b/providers/aimlapi/models/alibaba/qwen3-next-80b-a3b-instruct.toml new file mode 100644 index 00000000000..4f84b4071c5 --- /dev/null +++ b/providers/aimlapi/models/alibaba/qwen3-next-80b-a3b-instruct.toml @@ -0,0 +1,10 @@ +base_model = "alibaba/qwen3-next-80b-a3b-instruct" +name = "Qwen3 Next 80B A3B Instruct" + +[cost] +input = 0.195 +output = 1.56 + +[limit] +context = 129_024 +output = 16_384 diff --git a/providers/aimlapi/models/alibaba/qwen3-vl-flash.toml b/providers/aimlapi/models/alibaba/qwen3-vl-flash.toml new file mode 100644 index 00000000000..12118077ccb --- /dev/null +++ b/providers/aimlapi/models/alibaba/qwen3-vl-flash.toml @@ -0,0 +1,7 @@ +base_model = "alibaba/qwen3-vl-flash" +name = "Qwen3 VL Flash" + +[cost] +input = 0.065 +output = 0.52 +cache_read = 0.065 diff --git a/providers/aimlapi/models/alibaba/qwen3.6-max-preview.toml b/providers/aimlapi/models/alibaba/qwen3.6-max-preview.toml new file mode 100644 index 00000000000..58be84db58e --- /dev/null +++ b/providers/aimlapi/models/alibaba/qwen3.6-max-preview.toml @@ -0,0 +1,11 @@ +# No caller control: reasoning_effort is validated (invalid value -> 400) but low/high +# do not order reasoning tokens; toggle/budget fields are dropped by the gateway. +base_model = "alibaba/qwen3.6-max-preview" +reasoning_options = [] + +[interleaved] +field = "reasoning_content" + +[cost] +input = 0.65 +output = 3.9 diff --git a/providers/aimlapi/models/alibaba/qwen3.8-2.4t-a95b.toml b/providers/aimlapi/models/alibaba/qwen3.8-2.4t-a95b.toml new file mode 100644 index 00000000000..642df5ea6fb --- /dev/null +++ b/providers/aimlapi/models/alibaba/qwen3.8-2.4t-a95b.toml @@ -0,0 +1,16 @@ +base_model = "alibaba/qwen3.8-2.4t-a95b" + +[interleaved] +field = "reasoning_details" + +[[reasoning_options]] +type = "effort" +values = ["low", "medium"] + +[cost] +input = 3.4385 +output = 8.59625 +cache_read = 0.6877 + +[limit] +output = 52_429 diff --git a/providers/aimlapi/models/alibaba/qwen3.8-27b.toml b/providers/aimlapi/models/alibaba/qwen3.8-27b.toml new file mode 100644 index 00000000000..0d757197e19 --- /dev/null +++ b/providers/aimlapi/models/alibaba/qwen3.8-27b.toml @@ -0,0 +1,15 @@ +base_model = "alibaba/qwen3.8-27b" + +[interleaved] +field = "reasoning_details" + +[[reasoning_options]] +type = "effort" +values = ["low", "medium"] + +[cost] +input = 0.61893 +output = 4.40128 + +[limit] +output = 131_072 diff --git a/providers/aimlapi/models/alibaba/qwen3.8-flash.toml b/providers/aimlapi/models/alibaba/qwen3.8-flash.toml new file mode 100644 index 00000000000..72dd3bc6871 --- /dev/null +++ b/providers/aimlapi/models/alibaba/qwen3.8-flash.toml @@ -0,0 +1,13 @@ +base_model = "alibaba/qwen3.8-flash" + +[interleaved] +field = "reasoning_content" + +[[reasoning_options]] +type = "effort" +values = ["low", "medium"] + +[cost] +input = 0.208 +output = 0.611 +cache_read = 0.0208 diff --git a/providers/aimlapi/models/alibaba/qwen3.8-max-prime.toml b/providers/aimlapi/models/alibaba/qwen3.8-max-prime.toml new file mode 100644 index 00000000000..3a5704dea80 --- /dev/null +++ b/providers/aimlapi/models/alibaba/qwen3.8-max-prime.toml @@ -0,0 +1,11 @@ +base_model = "alibaba/qwen3.8-max-prime" +name = "Qwen3.8 Max Prime" + +[[reasoning_options]] +type = "effort" +values = ["minimal", "low", "medium", "high", "xhigh"] + +[cost] +input = 5.5016 +output = 16.5048 +cache_read = 0.6877 diff --git a/providers/aimlapi/models/alibaba/qwen3.8-max.toml b/providers/aimlapi/models/alibaba/qwen3.8-max.toml new file mode 100644 index 00000000000..56fbe364cfa --- /dev/null +++ b/providers/aimlapi/models/alibaba/qwen3.8-max.toml @@ -0,0 +1,13 @@ +base_model = "alibaba/qwen3.8-max" + +[interleaved] +field = "reasoning_content" + +[[reasoning_options]] +type = "effort" +values = ["low", "medium"] + +[cost] +input = 2.6 +output = 7.8 +cache_read = 0.325 diff --git a/providers/aimlapi/models/amazon/nova-lite-v1.toml b/providers/aimlapi/models/amazon/nova-lite-v1.toml new file mode 100644 index 00000000000..aff8e7b8002 --- /dev/null +++ b/providers/aimlapi/models/amazon/nova-lite-v1.toml @@ -0,0 +1,5 @@ +base_model = "amazon/nova-lite-v1" + +[cost] +input = 0.082524 +output = 0.330096 diff --git a/providers/aimlapi/models/amazon/nova-micro-v1.toml b/providers/aimlapi/models/amazon/nova-micro-v1.toml new file mode 100644 index 00000000000..3d12109bed9 --- /dev/null +++ b/providers/aimlapi/models/amazon/nova-micro-v1.toml @@ -0,0 +1,5 @@ +base_model = "amazon/nova-micro-v1" + +[cost] +input = 0.048139 +output = 0.192556 diff --git a/providers/aimlapi/models/amazon/nova-pro-v1.toml b/providers/aimlapi/models/amazon/nova-pro-v1.toml new file mode 100644 index 00000000000..a8046221595 --- /dev/null +++ b/providers/aimlapi/models/amazon/nova-pro-v1.toml @@ -0,0 +1,5 @@ +base_model = "amazon/nova-pro-v1" + +[cost] +input = 1.10032 +output = 4.40128 diff --git a/providers/aimlapi/models/anthracite-org/magnum-v4-72b.toml b/providers/aimlapi/models/anthracite-org/magnum-v4-72b.toml new file mode 100644 index 00000000000..78e0215e958 --- /dev/null +++ b/providers/aimlapi/models/anthracite-org/magnum-v4-72b.toml @@ -0,0 +1,9 @@ +base_model = "anthracite-org/magnum-v4-72b" + +[cost] +input = 4.1262 +output = 6.877 + +[limit] +context = 32_000 +output = 16_384 diff --git a/providers/aimlapi/models/anthropic/claude-fable-5.1.toml b/providers/aimlapi/models/anthropic/claude-fable-5.1.toml new file mode 100644 index 00000000000..aa5422395fa --- /dev/null +++ b/providers/aimlapi/models/anthropic/claude-fable-5.1.toml @@ -0,0 +1,10 @@ +base_model = "anthropic/claude-fable-5-1" + +[[reasoning_options]] +type = "effort" +values = ["low", "medium", "high", "xhigh", "max"] + +[cost] +input = 13 +output = 65 +cache_read = 0.325 diff --git a/providers/aimlapi/models/anthropic/claude-fable-5.toml b/providers/aimlapi/models/anthropic/claude-fable-5.toml new file mode 100644 index 00000000000..185faf06ed2 --- /dev/null +++ b/providers/aimlapi/models/anthropic/claude-fable-5.toml @@ -0,0 +1,13 @@ +base_model = "anthropic/claude-fable-5" + +[interleaved] +field = "reasoning_content" + +[[reasoning_options]] +type = "effort" +values = ["low", "medium", "high", "xhigh", "max"] + +[cost] +input = 13 +output = 65 +cache_read = 1.3 diff --git a/providers/aimlapi/models/anthropic/claude-haiku-4.5.toml b/providers/aimlapi/models/anthropic/claude-haiku-4.5.toml new file mode 100644 index 00000000000..2381e2a5861 --- /dev/null +++ b/providers/aimlapi/models/anthropic/claude-haiku-4.5.toml @@ -0,0 +1,10 @@ +# No caller control: reasoning_effort is validated (invalid value -> 400) but low/high +# do not order reasoning tokens; toggle/budget fields are dropped by the gateway. +base_model = "anthropic/claude-haiku-4-5" +name = "Claude 4.5 Haiku" +reasoning_options = [] + +[cost] +input = 1.3754 +output = 6.877 +cache_read = 0.13754 diff --git a/providers/aimlapi/models/anthropic/claude-haiku-5.5.toml b/providers/aimlapi/models/anthropic/claude-haiku-5.5.toml new file mode 100644 index 00000000000..14d286c3af8 --- /dev/null +++ b/providers/aimlapi/models/anthropic/claude-haiku-5.5.toml @@ -0,0 +1,10 @@ +base_model = "anthropic/claude-haiku-5-5" + +[[reasoning_options]] +type = "effort" +values = ["low", "medium", "high", "xhigh", "max"] + +[cost] +input = 0.13 +output = 0.65 +cache_read = 0.013 diff --git a/providers/aimlapi/models/anthropic/claude-opus-4.5.toml b/providers/aimlapi/models/anthropic/claude-opus-4.5.toml new file mode 100644 index 00000000000..2019df716b4 --- /dev/null +++ b/providers/aimlapi/models/anthropic/claude-opus-4.5.toml @@ -0,0 +1,11 @@ +base_model = "anthropic/claude-opus-4-5" +name = "Claude 4.5 Opus" + +[[reasoning_options]] +type = "effort" +values = ["low", "medium", "high"] + +[cost] +input = 6.877 +output = 34.385 +cache_read = 0.6877 diff --git a/providers/aimlapi/models/anthropic/claude-opus-4.7.toml b/providers/aimlapi/models/anthropic/claude-opus-4.7.toml new file mode 100644 index 00000000000..a2780ee040c --- /dev/null +++ b/providers/aimlapi/models/anthropic/claude-opus-4.7.toml @@ -0,0 +1,12 @@ +# Off: reasoning_effort = none (0 reasoning tokens); no toggle field on this surface. +base_model = "anthropic/claude-opus-4-7" +name = "Claude 4.7 Opus" + +[[reasoning_options]] +type = "effort" +values = ["none", "low", "medium", "high", "xhigh", "max"] + +[cost] +input = 6.877 +output = 34.385 +cache_read = 0.6877 diff --git a/providers/aimlapi/models/anthropic/claude-opus-4.8.toml b/providers/aimlapi/models/anthropic/claude-opus-4.8.toml new file mode 100644 index 00000000000..16aac2d98aa --- /dev/null +++ b/providers/aimlapi/models/anthropic/claude-opus-4.8.toml @@ -0,0 +1,12 @@ +# Off: reasoning_effort = none (0 reasoning tokens); no toggle field on this surface. +base_model = "anthropic/claude-opus-4-8" +name = "Claude 4.8 Opus" + +[[reasoning_options]] +type = "effort" +values = ["none", "low", "medium", "high", "xhigh", "max"] + +[cost] +input = 6.877 +output = 34.385 +cache_read = 0.6877 diff --git a/providers/aimlapi/models/anthropic/claude-opus-5.5.toml b/providers/aimlapi/models/anthropic/claude-opus-5.5.toml new file mode 100644 index 00000000000..d74e5d769ba --- /dev/null +++ b/providers/aimlapi/models/anthropic/claude-opus-5.5.toml @@ -0,0 +1,10 @@ +base_model = "anthropic/claude-opus-5-5" + +[[reasoning_options]] +type = "effort" +values = ["low", "medium", "high", "xhigh", "max"] + +[cost] +input = 5.2 +output = 26 +cache_read = 0.26 diff --git a/providers/aimlapi/models/anthropic/claude-opus-5.toml b/providers/aimlapi/models/anthropic/claude-opus-5.toml new file mode 100644 index 00000000000..ece768da424 --- /dev/null +++ b/providers/aimlapi/models/anthropic/claude-opus-5.toml @@ -0,0 +1,10 @@ +base_model = "anthropic/claude-opus-5" + +[[reasoning_options]] +type = "effort" +values = ["low", "medium", "high", "xhigh", "max"] + +[cost] +input = 6.5 +output = 32.5 +cache_read = 0.65 diff --git a/providers/aimlapi/models/anthropic/claude-sonnet-4.5.toml b/providers/aimlapi/models/anthropic/claude-sonnet-4.5.toml new file mode 100644 index 00000000000..6ebb192f07e --- /dev/null +++ b/providers/aimlapi/models/anthropic/claude-sonnet-4.5.toml @@ -0,0 +1,10 @@ +# No caller control: reasoning_effort is validated (invalid value -> 400) but low/high +# do not order reasoning tokens; toggle/budget fields are dropped by the gateway. +base_model = "anthropic/claude-sonnet-4-5" +name = "Claude 4.5 Sonnet" +reasoning_options = [] + +[cost] +input = 4.1262 +output = 20.631 +cache_read = 0.41262 diff --git a/providers/aimlapi/models/anthropic/claude-sonnet-4.6.toml b/providers/aimlapi/models/anthropic/claude-sonnet-4.6.toml new file mode 100644 index 00000000000..a929c1d796d --- /dev/null +++ b/providers/aimlapi/models/anthropic/claude-sonnet-4.6.toml @@ -0,0 +1,14 @@ +base_model = "anthropic/claude-sonnet-4-6" +name = "Claude 4.6 Sonnet" + +[[reasoning_options]] +type = "effort" +values = ["low", "medium", "high", "max"] + +[cost] +input = 4.1262 +output = 20.631 +cache_read = 0.41262 + +[limit] +context = 200_000 diff --git a/providers/aimlapi/models/anthropic/claude-sonnet-5.5.toml b/providers/aimlapi/models/anthropic/claude-sonnet-5.5.toml new file mode 100644 index 00000000000..811dc266534 --- /dev/null +++ b/providers/aimlapi/models/anthropic/claude-sonnet-5.5.toml @@ -0,0 +1,10 @@ +base_model = "anthropic/claude-sonnet-5-5" + +[[reasoning_options]] +type = "effort" +values = ["low", "medium", "high", "xhigh", "max"] + +[cost] +input = 2.6 +output = 13 +cache_read = 0.26 diff --git a/providers/aimlapi/models/anthropic/claude-sonnet-5.toml b/providers/aimlapi/models/anthropic/claude-sonnet-5.toml new file mode 100644 index 00000000000..5aa47e77359 --- /dev/null +++ b/providers/aimlapi/models/anthropic/claude-sonnet-5.toml @@ -0,0 +1,13 @@ +base_model = "anthropic/claude-sonnet-5" + +[interleaved] +field = "reasoning_content" + +[[reasoning_options]] +type = "effort" +values = ["low", "medium", "high", "xhigh", "max"] + +[cost] +input = 2.6 +output = 13 +cache_read = 0.26 diff --git a/providers/aimlapi/models/bytedance-seed/seed-1.6-flash.toml b/providers/aimlapi/models/bytedance-seed/seed-1.6-flash.toml new file mode 100644 index 00000000000..3facbf7a46b --- /dev/null +++ b/providers/aimlapi/models/bytedance-seed/seed-1.6-flash.toml @@ -0,0 +1,9 @@ +base_model = "bytedance-seed/seed-1-6-flash" + +[cost] +input = 0.103155 +output = 0.41262 + +[limit] +context = 262_144 +output = 32_768 diff --git a/providers/aimlapi/models/bytedance-seed/seed-2.0-code.toml b/providers/aimlapi/models/bytedance-seed/seed-2.0-code.toml new file mode 100644 index 00000000000..7686d164300 --- /dev/null +++ b/providers/aimlapi/models/bytedance-seed/seed-2.0-code.toml @@ -0,0 +1,13 @@ +base_model = "bytedance-seed/seed-2.0-code" +name = "Seed-2.0-Code" + +[interleaved] +field = "reasoning_details" + +[[reasoning_options]] +type = "effort" +values = ["low", "medium", "high"] + +[cost] +input = 0.6877 +output = 4.1262 diff --git a/providers/aimlapi/models/bytedance-seed/seed-2.0-lite.toml b/providers/aimlapi/models/bytedance-seed/seed-2.0-lite.toml new file mode 100644 index 00000000000..ef3d8d0d0b7 --- /dev/null +++ b/providers/aimlapi/models/bytedance-seed/seed-2.0-lite.toml @@ -0,0 +1,17 @@ +base_model = "bytedance-seed/seed-2.0-lite" +name = "Seed-2.0-Lite" + +[interleaved] +field = "reasoning_details" + +[[reasoning_options]] +type = "effort" +values = ["low", "medium", "high"] + +[cost] +input = 0.34385 +output = 2.7508 + +[limit] +context = 262_144 +output = 131_072 diff --git a/providers/aimlapi/models/bytedance-seed/seed-2.0-mini.toml b/providers/aimlapi/models/bytedance-seed/seed-2.0-mini.toml new file mode 100644 index 00000000000..44bd5bec985 --- /dev/null +++ b/providers/aimlapi/models/bytedance-seed/seed-2.0-mini.toml @@ -0,0 +1,17 @@ +base_model = "bytedance-seed/seed-2.0-mini" +name = "Seed-2.0-Mini" + +[interleaved] +field = "reasoning_details" + +[[reasoning_options]] +type = "effort" +values = ["low", "medium", "high"] + +[cost] +input = 0.13754 +output = 0.55016 + +[limit] +context = 262_144 +output = 131_072 diff --git a/providers/aimlapi/models/cognitivecomputations/dolphin-mistral-24b-venice-edition.toml b/providers/aimlapi/models/cognitivecomputations/dolphin-mistral-24b-venice-edition.toml new file mode 100644 index 00000000000..343a5058bf3 --- /dev/null +++ b/providers/aimlapi/models/cognitivecomputations/dolphin-mistral-24b-venice-edition.toml @@ -0,0 +1,6 @@ +base_model = "cognitivecomputations/dolphin-mistral-24b-venice-edition" +name = "Venice Uncensored" + +[cost] +input = 0.27508 +output = 1.23786 diff --git a/providers/aimlapi/models/cohere/command-a.toml b/providers/aimlapi/models/cohere/command-a.toml new file mode 100644 index 00000000000..6a30a3a6fb6 --- /dev/null +++ b/providers/aimlapi/models/cohere/command-a.toml @@ -0,0 +1,8 @@ +base_model = "cohere/command-a" + +[cost] +input = 3.4385 +output = 13.754 + +[limit] +output = 256_000 diff --git a/providers/aimlapi/models/cohere/command-r-08-2024.toml b/providers/aimlapi/models/cohere/command-r-08-2024.toml new file mode 100644 index 00000000000..78df1b3c45e --- /dev/null +++ b/providers/aimlapi/models/cohere/command-r-08-2024.toml @@ -0,0 +1,6 @@ +base_model = "cohere/command-r-08-2024" +name = "Command R (08-2024)" + +[cost] +input = 0.20631 +output = 0.82524 diff --git a/providers/aimlapi/models/cohere/command-r-plus-08-2024.toml b/providers/aimlapi/models/cohere/command-r-plus-08-2024.toml new file mode 100644 index 00000000000..38ee6a60d77 --- /dev/null +++ b/providers/aimlapi/models/cohere/command-r-plus-08-2024.toml @@ -0,0 +1,6 @@ +base_model = "cohere/command-r-plus-08-2024" +name = "Command R+ (08-2024)" + +[cost] +input = 3.4385 +output = 13.754 diff --git a/providers/aimlapi/models/cohere/command-r7b-12-2024.toml b/providers/aimlapi/models/cohere/command-r7b-12-2024.toml new file mode 100644 index 00000000000..3f8f98173fd --- /dev/null +++ b/providers/aimlapi/models/cohere/command-r7b-12-2024.toml @@ -0,0 +1,6 @@ +base_model = "cohere/command-r7b-12-2024" +name = "Command R7B (12-2024)" + +[cost] +input = 0.051578 +output = 0.20631 diff --git a/providers/aimlapi/models/deepseek/deepseek-chat-v3-0324.toml b/providers/aimlapi/models/deepseek/deepseek-chat-v3-0324.toml new file mode 100644 index 00000000000..c5f54c267ae --- /dev/null +++ b/providers/aimlapi/models/deepseek/deepseek-chat-v3-0324.toml @@ -0,0 +1,11 @@ +base_model = "deepseek/deepseek-chat-v3-0324" +name = "DeepSeek V3" + +[cost] +input = 0.398866 +output = 1.567956 +cache_read = 0.192556 + +[limit] +context = 128_000 +output = 124_000 diff --git a/providers/aimlapi/models/deepseek/deepseek-chat.toml b/providers/aimlapi/models/deepseek/deepseek-chat.toml new file mode 100644 index 00000000000..a40e9780b00 --- /dev/null +++ b/providers/aimlapi/models/deepseek/deepseek-chat.toml @@ -0,0 +1,15 @@ +# Alias: answers "model" as deepseek-v4-flash; measured through that id. +# Off: reasoning_effort = none (0 reasoning tokens); no toggle field on this surface. +base_model = "deepseek/deepseek-v4-flash" + +[interleaved] +field = "reasoning_content" + +[[reasoning_options]] +type = "effort" +values = ["none", "low", "high"] + +[cost] +input = 0.39 +output = 1.56 +cache_read = 0.0078 diff --git a/providers/aimlapi/models/deepseek/deepseek-v4-flash-vision-exp.toml b/providers/aimlapi/models/deepseek/deepseek-v4-flash-vision-exp.toml new file mode 100644 index 00000000000..a9e9cfd5795 --- /dev/null +++ b/providers/aimlapi/models/deepseek/deepseek-v4-flash-vision-exp.toml @@ -0,0 +1,17 @@ +# Off: reasoning_effort = none (0 reasoning tokens); no toggle field on this surface. +base_model = "deepseek/deepseek-v4-flash-vision-exp" + +[interleaved] +field = "reasoning_content" + +[[reasoning_options]] +type = "effort" +values = ["none", "low", "high"] + +[cost] +input = 0.572 +output = 1.716 +cache_read = 0.0182 + +[limit] +context = 1_048_576 diff --git a/providers/aimlapi/models/deepseek/deepseek-v4-flash.toml b/providers/aimlapi/models/deepseek/deepseek-v4-flash.toml new file mode 100644 index 00000000000..641462df08f --- /dev/null +++ b/providers/aimlapi/models/deepseek/deepseek-v4-flash.toml @@ -0,0 +1,14 @@ +# Off: reasoning_effort = none (0 reasoning tokens); no toggle field on this surface. +base_model = "deepseek/deepseek-v4-flash" + +[interleaved] +field = "reasoning_content" + +[[reasoning_options]] +type = "effort" +values = ["none", "low", "high"] + +[cost] +input = 0.39 +output = 1.56 +cache_read = 0.0078 diff --git a/providers/aimlapi/models/deepseek/deepseek-v4-pro-0813.toml b/providers/aimlapi/models/deepseek/deepseek-v4-pro-0813.toml new file mode 100644 index 00000000000..8c630c37419 --- /dev/null +++ b/providers/aimlapi/models/deepseek/deepseek-v4-pro-0813.toml @@ -0,0 +1,17 @@ +# Off: reasoning_effort = none (0 reasoning tokens); no toggle field on this surface. +base_model = "deepseek/deepseek-v4-pro-0813" + +[interleaved] +field = "reasoning_details" + +[[reasoning_options]] +type = "effort" +values = ["none", "low", "high"] + +[cost] +input = 2.393196 +output = 4.786392 +cache_read = 0.199433 + +[limit] +context = 1_048_576 diff --git a/providers/aimlapi/models/deepseek/deepseek-v4-pro.toml b/providers/aimlapi/models/deepseek/deepseek-v4-pro.toml new file mode 100644 index 00000000000..b3d4d680544 --- /dev/null +++ b/providers/aimlapi/models/deepseek/deepseek-v4-pro.toml @@ -0,0 +1,14 @@ +# Off: reasoning_effort = none (0 reasoning tokens); no toggle field on this surface. +base_model = "deepseek/deepseek-v4-pro" + +[interleaved] +field = "reasoning_content" + +[[reasoning_options]] +type = "effort" +values = ["none", "low", "high"] + +[cost] +input = 1.17 +output = 3.51 +cache_read = 0.039 diff --git a/providers/aimlapi/models/deepseek/deepseek-v4.1-flash.toml b/providers/aimlapi/models/deepseek/deepseek-v4.1-flash.toml new file mode 100644 index 00000000000..a193dbfbcdf --- /dev/null +++ b/providers/aimlapi/models/deepseek/deepseek-v4.1-flash.toml @@ -0,0 +1,13 @@ +base_model = "deepseek/deepseek-v4.1-flash" + +[[reasoning_options]] +type = "effort" +values = ["low", "high"] + +[cost] +input = 0.39 +output = 1.56 +cache_read = 0.0078 + +[limit] +context = 1_048_576 diff --git a/providers/aimlapi/models/google/gemini-3-8-flash.toml b/providers/aimlapi/models/google/gemini-3-8-flash.toml new file mode 100644 index 00000000000..101dd659af2 --- /dev/null +++ b/providers/aimlapi/models/google/gemini-3-8-flash.toml @@ -0,0 +1,10 @@ +base_model = "google/gemini-3.8-flash" + +[[reasoning_options]] +type = "effort" +values = ["low", "medium", "high"] + +[cost] +input = 0.975 +output = 4.875 +cache_read = 0.0975 diff --git a/providers/aimlapi/models/google/gemini-3.1-flash-lite-preview.toml b/providers/aimlapi/models/google/gemini-3.1-flash-lite-preview.toml new file mode 100644 index 00000000000..fca57f817b8 --- /dev/null +++ b/providers/aimlapi/models/google/gemini-3.1-flash-lite-preview.toml @@ -0,0 +1,16 @@ +base_model = "google/gemini-3.1-flash-lite-preview" + +[interleaved] +field = "reasoning_details" + +[[reasoning_options]] +type = "effort" +values = ["low", "medium", "high"] + +[cost] +input = 0.34385 +output = 2.0631 +cache_read = 0.034385 + +[limit] +context = 1_000_000 diff --git a/providers/aimlapi/models/google/gemini-3.1-pro-preview-customtools.toml b/providers/aimlapi/models/google/gemini-3.1-pro-preview-customtools.toml new file mode 100644 index 00000000000..f4465ebdf4e --- /dev/null +++ b/providers/aimlapi/models/google/gemini-3.1-pro-preview-customtools.toml @@ -0,0 +1,16 @@ +base_model = "google/gemini-3.1-pro-preview-customtools" + +[interleaved] +field = "reasoning_details" + +[[reasoning_options]] +type = "effort" +values = ["low", "medium", "high"] + +[cost] +input = 2.7508 +output = 16.5048 +cache_read = 0.27508 + +[limit] +context = 1_048_756 diff --git a/providers/aimlapi/models/google/gemini-3.1-pro-preview.toml b/providers/aimlapi/models/google/gemini-3.1-pro-preview.toml new file mode 100644 index 00000000000..14fc3cf4e4f --- /dev/null +++ b/providers/aimlapi/models/google/gemini-3.1-pro-preview.toml @@ -0,0 +1,12 @@ +# No caller control: reasoning_effort is not read (an invalid value returns 200), +# and toggle/budget fields are dropped by the gateway (unknown top-level keys -> 200). +base_model = "google/gemini-3.1-pro-preview" +reasoning_options = [] + +[cost] +input = 2.6 +output = 15.6 +cache_read = 0.65 + +[limit] +context = 1_000_000 diff --git a/providers/aimlapi/models/google/gemini-3.6-flash.toml b/providers/aimlapi/models/google/gemini-3.6-flash.toml new file mode 100644 index 00000000000..cbb95c0086e --- /dev/null +++ b/providers/aimlapi/models/google/gemini-3.6-flash.toml @@ -0,0 +1,10 @@ +base_model = "google/gemini-3.6-flash" + +[[reasoning_options]] +type = "effort" +values = ["minimal", "low", "medium", "high"] + +[cost] +input = 1.95 +output = 9.75 +cache_read = 0.195 diff --git a/providers/aimlapi/models/google/gemini-3.7-flash.toml b/providers/aimlapi/models/google/gemini-3.7-flash.toml new file mode 100644 index 00000000000..ca994263e13 --- /dev/null +++ b/providers/aimlapi/models/google/gemini-3.7-flash.toml @@ -0,0 +1,10 @@ +base_model = "google/gemini-3.7-flash" + +[[reasoning_options]] +type = "effort" +values = ["low", "medium", "high"] + +[cost] +input = 0.975 +output = 4.875 +cache_read = 0.0975 diff --git a/providers/aimlapi/models/google/gemini-3.8-flash.toml b/providers/aimlapi/models/google/gemini-3.8-flash.toml new file mode 100644 index 00000000000..101dd659af2 --- /dev/null +++ b/providers/aimlapi/models/google/gemini-3.8-flash.toml @@ -0,0 +1,10 @@ +base_model = "google/gemini-3.8-flash" + +[[reasoning_options]] +type = "effort" +values = ["low", "medium", "high"] + +[cost] +input = 0.975 +output = 4.875 +cache_read = 0.0975 diff --git a/providers/aimlapi/models/google/gemini-flash-latest.toml b/providers/aimlapi/models/google/gemini-flash-latest.toml new file mode 100644 index 00000000000..99fc46d49b8 --- /dev/null +++ b/providers/aimlapi/models/google/gemini-flash-latest.toml @@ -0,0 +1,13 @@ +base_model = "google/gemini-flash-latest" + +[interleaved] +field = "reasoning_details" + +[[reasoning_options]] +type = "effort" +values = ["low", "medium", "high"] + +[cost] +input = 2.0631 +output = 12.3786 +cache_read = 0.20631 diff --git a/providers/aimlapi/models/google/gemma-2-27b-it.toml b/providers/aimlapi/models/google/gemma-2-27b-it.toml new file mode 100644 index 00000000000..76cddcc675d --- /dev/null +++ b/providers/aimlapi/models/google/gemma-2-27b-it.toml @@ -0,0 +1,5 @@ +base_model = "google/gemma-2-27b-it" + +[cost] +input = 0.89401 +output = 0.89401 diff --git a/providers/aimlapi/models/google/gemma-3-12b-it.toml b/providers/aimlapi/models/google/gemma-3-12b-it.toml new file mode 100644 index 00000000000..7a4a9af3642 --- /dev/null +++ b/providers/aimlapi/models/google/gemma-3-12b-it.toml @@ -0,0 +1,11 @@ +base_model = "google/gemma-3-12b-it" +name = "Gemma 3 12B" + +[cost] +input = 0.06877 +output = 0.20631 +cache_read = 0.055016 + +[limit] +context = 131_000 +output = 96_000 diff --git a/providers/aimlapi/models/google/gemma-3-27b-it.toml b/providers/aimlapi/models/google/gemma-3-27b-it.toml new file mode 100644 index 00000000000..12f843f35f3 --- /dev/null +++ b/providers/aimlapi/models/google/gemma-3-27b-it.toml @@ -0,0 +1,11 @@ +base_model = "google/gemma-3-27b-it" +name = "Gemma 3 27B" + +[cost] +input = 0.20631 +output = 0.632684 +cache_read = 0.103155 + +[limit] +context = 128_000 +output = 117_964 diff --git a/providers/aimlapi/models/google/gemma-3-4b-it.toml b/providers/aimlapi/models/google/gemma-3-4b-it.toml new file mode 100644 index 00000000000..da2030fb30d --- /dev/null +++ b/providers/aimlapi/models/google/gemma-3-4b-it.toml @@ -0,0 +1,11 @@ +base_model = "google/gemma-3-4b-it" +name = "Gemma 3 4B" + +[cost] +input = 0.06877 +output = 0.13754 +cache_read = 0.055016 + +[limit] +context = 131_000 +output = 32_768 diff --git a/providers/aimlapi/models/google/gemma-4-26b-a4b-it.toml b/providers/aimlapi/models/google/gemma-4-26b-a4b-it.toml new file mode 100644 index 00000000000..19c7b65f3a2 --- /dev/null +++ b/providers/aimlapi/models/google/gemma-4-26b-a4b-it.toml @@ -0,0 +1,12 @@ +# No caller control: reasoning_effort is not read (an invalid value returns 200), +# and toggle/budget fields are dropped by the gateway (unknown top-level keys -> 200). +base_model = "google/gemma-4-26b-a4b-it" +reasoning_options = [] + +[cost] +input = 0.20631 +output = 0.82524 +cache_read = 0.20631 + +[limit] +output = 128_000 diff --git a/providers/aimlapi/models/google/gemma-4-31b-it.toml b/providers/aimlapi/models/google/gemma-4-31b-it.toml new file mode 100644 index 00000000000..47a3c16d39d --- /dev/null +++ b/providers/aimlapi/models/google/gemma-4-31b-it.toml @@ -0,0 +1,14 @@ +# No caller control: reasoning_effort is validated (invalid value -> 400) but low/high +# do not order reasoning tokens; toggle/budget fields are dropped by the gateway. +base_model = "google/gemma-4-31b-it" +name = "Gemma 4 31B Instruct" +reasoning_options = [] + +[cost] +input = 1.361646 +output = 2.049346 +cache_read = 1.361646 + +[limit] +context = 256_000 +output = 16_384 diff --git a/providers/aimlapi/models/gryphe/mythomax-l2-13b.toml b/providers/aimlapi/models/gryphe/mythomax-l2-13b.toml new file mode 100644 index 00000000000..d426a8f63a2 --- /dev/null +++ b/providers/aimlapi/models/gryphe/mythomax-l2-13b.toml @@ -0,0 +1,10 @@ +base_model = "gryphe/mythomax-l2-13b" +name = "MythoMax 13B" + +[cost] +input = 2.578875 +output = 2.578875 +cache_read = 2.578875 + +[limit] +output = 4_096 diff --git a/providers/aimlapi/models/ibm-granite/granite-4.0-h-micro.toml b/providers/aimlapi/models/ibm-granite/granite-4.0-h-micro.toml new file mode 100644 index 00000000000..a310c769582 --- /dev/null +++ b/providers/aimlapi/models/ibm-granite/granite-4.0-h-micro.toml @@ -0,0 +1,10 @@ +base_model = "ibm/granite-4-h-micro" +name = "Granite 4.0 Micro" + +[cost] +input = 0.023382 +output = 0.154045 + +[limit] +context = 131_000 +output = 131_000 diff --git a/providers/aimlapi/models/inception/mercury-2.5.toml b/providers/aimlapi/models/inception/mercury-2.5.toml new file mode 100644 index 00000000000..e568676fa32 --- /dev/null +++ b/providers/aimlapi/models/inception/mercury-2.5.toml @@ -0,0 +1,10 @@ +base_model = "inception/mercury-2.5" + +[[reasoning_options]] +type = "effort" +values = ["low", "medium", "high"] + +[cost] +input = 0.27508 +output = 1.03155 +cache_read = 0.027508 diff --git a/providers/aimlapi/models/inception/mercury-2.toml b/providers/aimlapi/models/inception/mercury-2.toml new file mode 100644 index 00000000000..f7b3df2928a --- /dev/null +++ b/providers/aimlapi/models/inception/mercury-2.toml @@ -0,0 +1,10 @@ +base_model = "inception/mercury-2" + +[[reasoning_options]] +type = "effort" +values = ["low", "medium", "high"] + +[cost] +input = 0.34385 +output = 1.03155 +cache_read = 0.034385 diff --git a/providers/aimlapi/models/inference-net/schematron-v2-small.toml b/providers/aimlapi/models/inference-net/schematron-v2-small.toml new file mode 100644 index 00000000000..7e7b140ecc8 --- /dev/null +++ b/providers/aimlapi/models/inference-net/schematron-v2-small.toml @@ -0,0 +1,5 @@ +base_model = "inference-net/schematron-v2-small" + +[cost] +input = 0.06877 +output = 0.316342 diff --git a/providers/aimlapi/models/inference-net/schematron-v2-turbo.toml b/providers/aimlapi/models/inference-net/schematron-v2-turbo.toml new file mode 100644 index 00000000000..60883e0b0bd --- /dev/null +++ b/providers/aimlapi/models/inference-net/schematron-v2-turbo.toml @@ -0,0 +1,5 @@ +base_model = "inference-net/schematron-v2-turbo" + +[cost] +input = 0.041262 +output = 0.20631 diff --git a/providers/aimlapi/models/mancer/weaver.toml b/providers/aimlapi/models/mancer/weaver.toml new file mode 100644 index 00000000000..46e19411608 --- /dev/null +++ b/providers/aimlapi/models/mancer/weaver.toml @@ -0,0 +1,8 @@ +base_model = "mancer/weaver" + +[cost] +input = 1.03155 +output = 1.3754 + +[limit] +output = 2_000 diff --git a/providers/aimlapi/models/meta-llama/Llama-3.3-70B-Instruct-Turbo.toml b/providers/aimlapi/models/meta-llama/Llama-3.3-70B-Instruct-Turbo.toml new file mode 100644 index 00000000000..ed4d8df1fe9 --- /dev/null +++ b/providers/aimlapi/models/meta-llama/Llama-3.3-70B-Instruct-Turbo.toml @@ -0,0 +1,9 @@ +base_model = "meta/llama-3.3-70b-instruct" +name = "Llama 3.3 70B Instruct Turbo" + +[cost] +input = 1.352 +output = 1.352 + +[limit] +output = 127_000 diff --git a/providers/aimlapi/models/meta/muse-glimmer-30b.toml b/providers/aimlapi/models/meta/muse-glimmer-30b.toml new file mode 100644 index 00000000000..25a525a4ded --- /dev/null +++ b/providers/aimlapi/models/meta/muse-glimmer-30b.toml @@ -0,0 +1,13 @@ +base_model = "meta/muse-glimmer-30b" + +[interleaved] +field = "reasoning_details" + +[[reasoning_options]] +type = "effort" +values = ["low", "medium", "high"] + +[cost] +input = 0.48139 +output = 2.0631 +cache_read = 0.055016 diff --git a/providers/aimlapi/models/meta/muse-spark-1.1.toml b/providers/aimlapi/models/meta/muse-spark-1.1.toml new file mode 100644 index 00000000000..edb4ee9b056 --- /dev/null +++ b/providers/aimlapi/models/meta/muse-spark-1.1.toml @@ -0,0 +1,13 @@ +base_model = "meta/muse-spark-1.1" + +[interleaved] +field = "reasoning_details" + +[[reasoning_options]] +type = "effort" +values = ["low", "medium", "high"] + +[cost] +input = 1.71925 +output = 5.84545 +cache_read = 0.20631 diff --git a/providers/aimlapi/models/meta/muse-spark-1.2.toml b/providers/aimlapi/models/meta/muse-spark-1.2.toml new file mode 100644 index 00000000000..049015208c0 --- /dev/null +++ b/providers/aimlapi/models/meta/muse-spark-1.2.toml @@ -0,0 +1,13 @@ +base_model = "meta/muse-spark-1.2" + +[interleaved] +field = "reasoning_details" + +[[reasoning_options]] +type = "effort" +values = ["low", "medium", "high"] + +[cost] +input = 1.71925 +output = 5.84545 +cache_read = 0.20631 diff --git a/providers/aimlapi/models/meta/muse-spark-1.3.toml b/providers/aimlapi/models/meta/muse-spark-1.3.toml new file mode 100644 index 00000000000..6314ce0e3a2 --- /dev/null +++ b/providers/aimlapi/models/meta/muse-spark-1.3.toml @@ -0,0 +1,10 @@ +base_model = "meta/muse-spark-1.3" + +[[reasoning_options]] +type = "effort" +values = ["low", "medium", "high"] + +[cost] +input = 1.71925 +output = 5.84545 +cache_read = 0.20631 diff --git a/providers/aimlapi/models/mistralai/codestral-2508.toml b/providers/aimlapi/models/mistralai/codestral-2508.toml new file mode 100644 index 00000000000..f18edca97c0 --- /dev/null +++ b/providers/aimlapi/models/mistralai/codestral-2508.toml @@ -0,0 +1,10 @@ +base_model = "mistral/codestral-2508" +name = "Codestral 2508" + +[cost] +input = 0.41262 +output = 1.23786 +cache_read = 0.041262 + +[limit] +context = 256_000 diff --git a/providers/aimlapi/models/mistralai/devstral-2512.toml b/providers/aimlapi/models/mistralai/devstral-2512.toml new file mode 100644 index 00000000000..f0bb6422d14 --- /dev/null +++ b/providers/aimlapi/models/mistralai/devstral-2512.toml @@ -0,0 +1,7 @@ +base_model = "mistral/devstral-2512" +name = "Devstral 2 2512" + +[cost] +input = 0.605176 +output = 3.02588 +cache_read = 0.060518 diff --git a/providers/aimlapi/models/mistralai/ministral-14b-2512.toml b/providers/aimlapi/models/mistralai/ministral-14b-2512.toml new file mode 100644 index 00000000000..542aaaed7e2 --- /dev/null +++ b/providers/aimlapi/models/mistralai/ministral-14b-2512.toml @@ -0,0 +1,6 @@ +base_model = "mistral/ministral-14b-2512" + +[cost] +input = 0.48139 +output = 0.48139 +cache_read = 0.027508 diff --git a/providers/aimlapi/models/mistralai/ministral-3b-2512.toml b/providers/aimlapi/models/mistralai/ministral-3b-2512.toml new file mode 100644 index 00000000000..71d2d7f564a --- /dev/null +++ b/providers/aimlapi/models/mistralai/ministral-3b-2512.toml @@ -0,0 +1,6 @@ +base_model = "mistral/ministral-3b-2512" + +[cost] +input = 0.20631 +output = 0.20631 +cache_read = 0.013754 diff --git a/providers/aimlapi/models/mistralai/ministral-8b-2512.toml b/providers/aimlapi/models/mistralai/ministral-8b-2512.toml new file mode 100644 index 00000000000..902d3bd46e9 --- /dev/null +++ b/providers/aimlapi/models/mistralai/ministral-8b-2512.toml @@ -0,0 +1,6 @@ +base_model = "mistral/ministral-8b-2512" + +[cost] +input = 0.41262 +output = 0.41262 +cache_read = 0.020631 diff --git a/providers/aimlapi/models/mistralai/mistral-large-2407.toml b/providers/aimlapi/models/mistralai/mistral-large-2407.toml new file mode 100644 index 00000000000..72fbac2c328 --- /dev/null +++ b/providers/aimlapi/models/mistralai/mistral-large-2407.toml @@ -0,0 +1,7 @@ +base_model = "mistral/mistral-large-2407" +name = "Large 2407" + +[cost] +input = 2.7508 +output = 8.2524 +cache_read = 0.27508 diff --git a/providers/aimlapi/models/mistralai/mistral-large.toml b/providers/aimlapi/models/mistralai/mistral-large.toml new file mode 100644 index 00000000000..86be31b54eb --- /dev/null +++ b/providers/aimlapi/models/mistralai/mistral-large.toml @@ -0,0 +1,7 @@ +base_model = "mistral/mistral-large" +name = "Large" + +[cost] +input = 2.7508 +output = 8.2524 +cache_read = 0.27508 diff --git a/providers/aimlapi/models/mistralai/mistral-medium-3-5.toml b/providers/aimlapi/models/mistralai/mistral-medium-3-5.toml new file mode 100644 index 00000000000..809232b427e --- /dev/null +++ b/providers/aimlapi/models/mistralai/mistral-medium-3-5.toml @@ -0,0 +1,10 @@ +base_model = "mistral/mistral-medium-3-5" +name = "Medium 3.5" + +[[reasoning_options]] +type = "effort" +values = ["high"] + +[cost] +input = 2.0631 +output = 10.3155 diff --git a/providers/aimlapi/models/mistralai/mistral-medium-3.1.toml b/providers/aimlapi/models/mistralai/mistral-medium-3.1.toml new file mode 100644 index 00000000000..78d184a4232 --- /dev/null +++ b/providers/aimlapi/models/mistralai/mistral-medium-3.1.toml @@ -0,0 +1,7 @@ +base_model = "mistral/mistral-medium-3.1" +name = "Medium 3.1" + +[cost] +input = 0.55016 +output = 2.7508 +cache_read = 0.055016 diff --git a/providers/aimlapi/models/mistralai/mistral-medium-3.toml b/providers/aimlapi/models/mistralai/mistral-medium-3.toml new file mode 100644 index 00000000000..c26192e693c --- /dev/null +++ b/providers/aimlapi/models/mistralai/mistral-medium-3.toml @@ -0,0 +1,7 @@ +base_model = "mistral/mistral-medium-3" +name = "Medium 3" + +[cost] +input = 0.55016 +output = 2.7508 +cache_read = 0.055016 diff --git a/providers/aimlapi/models/mistralai/mistral-nemo.toml b/providers/aimlapi/models/mistralai/mistral-nemo.toml new file mode 100644 index 00000000000..f1ce595b79b --- /dev/null +++ b/providers/aimlapi/models/mistralai/mistral-nemo.toml @@ -0,0 +1,10 @@ +base_model = "mistral/mistral-nemo" +name = "Mistral NeMo" + +[cost] +input = 0.20631 +output = 0.233818 +cache_read = 0.20631 + +[limit] +output = 16_384 diff --git a/providers/aimlapi/models/mistralai/mistral-saba.toml b/providers/aimlapi/models/mistralai/mistral-saba.toml new file mode 100644 index 00000000000..b7fce0dac1f --- /dev/null +++ b/providers/aimlapi/models/mistralai/mistral-saba.toml @@ -0,0 +1,6 @@ +base_model = "mistral/mistral-saba" + +[cost] +input = 0.27508 +output = 0.82524 +cache_read = 0.027508 diff --git a/providers/aimlapi/models/mistralai/mistral-small-24b-instruct-2501.toml b/providers/aimlapi/models/mistralai/mistral-small-24b-instruct-2501.toml new file mode 100644 index 00000000000..d9ab08544eb --- /dev/null +++ b/providers/aimlapi/models/mistralai/mistral-small-24b-instruct-2501.toml @@ -0,0 +1,6 @@ +base_model = "mistral/mistral-small-24b-instruct-2501" +name = "Small 3" + +[cost] +input = 0.06877 +output = 0.110032 diff --git a/providers/aimlapi/models/mistralai/mistral-small-2603.toml b/providers/aimlapi/models/mistralai/mistral-small-2603.toml new file mode 100644 index 00000000000..1186ce660e0 --- /dev/null +++ b/providers/aimlapi/models/mistralai/mistral-small-2603.toml @@ -0,0 +1,14 @@ +base_model = "mistral/mistral-small-2603" +name = "Small 4" + +[[reasoning_options]] +type = "effort" +values = ["none", "high"] + +[cost] +input = 0.257888 +output = 1.03155 +cache_read = 0.020631 + +[limit] +context = 262_144 diff --git a/providers/aimlapi/models/mistralai/mistral-small-3.1-24b-instruct.toml b/providers/aimlapi/models/mistralai/mistral-small-3.1-24b-instruct.toml new file mode 100644 index 00000000000..94f1b496b46 --- /dev/null +++ b/providers/aimlapi/models/mistralai/mistral-small-3.1-24b-instruct.toml @@ -0,0 +1,9 @@ +base_model = "mistral/mistral-small-3.1-24b-instruct" +name = "Small 3.1 24B" + +[cost] +input = 0.482765 +output = 0.763347 + +[limit] +output = 128_000 diff --git a/providers/aimlapi/models/mistralai/mistral-small-3.2-24b-instruct.toml b/providers/aimlapi/models/mistralai/mistral-small-3.2-24b-instruct.toml new file mode 100644 index 00000000000..dcf659da99c --- /dev/null +++ b/providers/aimlapi/models/mistralai/mistral-small-3.2-24b-instruct.toml @@ -0,0 +1,9 @@ +base_model = "mistral/mistral-small-3.2-24b-instruct" +name = "Small 3.2 24B" + +[cost] +input = 0.103155 +output = 0.27508 + +[limit] +context = 128_000 diff --git a/providers/aimlapi/models/mistralai/mixtral-8x22b-instruct.toml b/providers/aimlapi/models/mistralai/mixtral-8x22b-instruct.toml new file mode 100644 index 00000000000..17fbb52b2f8 --- /dev/null +++ b/providers/aimlapi/models/mistralai/mixtral-8x22b-instruct.toml @@ -0,0 +1,6 @@ +base_model = "mistral/mixtral-8x22b-instruct" + +[cost] +input = 2.7508 +output = 8.2524 +cache_read = 0.27508 diff --git a/providers/aimlapi/models/mistralai/voxtral-small-24b-2507.toml b/providers/aimlapi/models/mistralai/voxtral-small-24b-2507.toml new file mode 100644 index 00000000000..ec8e9ab7a20 --- /dev/null +++ b/providers/aimlapi/models/mistralai/voxtral-small-24b-2507.toml @@ -0,0 +1,9 @@ +base_model = "mistral/voxtral-small-24b-2507" + +[cost] +input = 0.13754 +output = 0.41262 +cache_read = 0.013754 + +[limit] +context = 32_000 diff --git a/providers/aimlapi/models/moonshot/kimi-k3.toml b/providers/aimlapi/models/moonshot/kimi-k3.toml new file mode 100644 index 00000000000..081843bca0d --- /dev/null +++ b/providers/aimlapi/models/moonshot/kimi-k3.toml @@ -0,0 +1,13 @@ +base_model = "moonshotai/kimi-k3" + +[interleaved] +field = "reasoning_content" + +[[reasoning_options]] +type = "effort" +values = ["low", "high", "max"] + +[cost] +input = 3.9 +output = 19.5 +cache_read = 0.39 diff --git a/providers/aimlapi/models/moonshotai/kimi-k2-0905.toml b/providers/aimlapi/models/moonshotai/kimi-k2-0905.toml new file mode 100644 index 00000000000..85cd08d0945 --- /dev/null +++ b/providers/aimlapi/models/moonshotai/kimi-k2-0905.toml @@ -0,0 +1,6 @@ +base_model = "moonshotai/kimi-k2-0905" +name = "Kimi K2 0905" + +[cost] +input = 1.3754 +output = 4.1262 diff --git a/providers/aimlapi/models/moonshotai/kimi-k2-thinking.toml b/providers/aimlapi/models/moonshotai/kimi-k2-thinking.toml new file mode 100644 index 00000000000..e2547928dc6 --- /dev/null +++ b/providers/aimlapi/models/moonshotai/kimi-k2-thinking.toml @@ -0,0 +1,12 @@ +# No caller control: reasoning_effort is validated (invalid value -> 400) but low/high +# do not order reasoning tokens; toggle/budget fields are dropped by the gateway. +base_model = "moonshotai/kimi-k2-thinking" +reasoning_options = [] + +[cost] +input = 0.82524 +output = 3.4385 +cache_read = 0.20631 + +[limit] +output = 98_304 diff --git a/providers/aimlapi/models/moonshotai/kimi-k2.toml b/providers/aimlapi/models/moonshotai/kimi-k2.toml new file mode 100644 index 00000000000..d1475011c94 --- /dev/null +++ b/providers/aimlapi/models/moonshotai/kimi-k2.toml @@ -0,0 +1,5 @@ +base_model = "moonshotai/kimi-k2" + +[cost] +input = 0.783978 +output = 3.16342 diff --git a/providers/aimlapi/models/morph/morph-v3-fast.toml b/providers/aimlapi/models/morph/morph-v3-fast.toml new file mode 100644 index 00000000000..cdbdba35303 --- /dev/null +++ b/providers/aimlapi/models/morph/morph-v3-fast.toml @@ -0,0 +1,6 @@ +base_model = "morph/morph-v3-fast" +name = "V3 Fast" + +[cost] +input = 1.10032 +output = 1.65048 diff --git a/providers/aimlapi/models/morph/morph-v3-large.toml b/providers/aimlapi/models/morph/morph-v3-large.toml new file mode 100644 index 00000000000..eaf467c1a9e --- /dev/null +++ b/providers/aimlapi/models/morph/morph-v3-large.toml @@ -0,0 +1,6 @@ +base_model = "morph/morph-v3-large" +name = "V3 Large" + +[cost] +input = 1.23786 +output = 2.61326 diff --git a/providers/aimlapi/models/nousresearch/hermes-3-llama-3.1-405b.toml b/providers/aimlapi/models/nousresearch/hermes-3-llama-3.1-405b.toml new file mode 100644 index 00000000000..3644710bfbd --- /dev/null +++ b/providers/aimlapi/models/nousresearch/hermes-3-llama-3.1-405b.toml @@ -0,0 +1,5 @@ +base_model = "nousresearch/hermes-3-llama-3.1-405b" + +[cost] +input = 1.3754 +output = 1.3754 diff --git a/providers/aimlapi/models/nousresearch/hermes-3-llama-3.1-70b.toml b/providers/aimlapi/models/nousresearch/hermes-3-llama-3.1-70b.toml new file mode 100644 index 00000000000..e893dd909ac --- /dev/null +++ b/providers/aimlapi/models/nousresearch/hermes-3-llama-3.1-70b.toml @@ -0,0 +1,5 @@ +base_model = "nousresearch/hermes-3-llama-3.1-70b" + +[cost] +input = 0.96278 +output = 0.96278 diff --git a/providers/aimlapi/models/openai/gpt-3.5-turbo.toml b/providers/aimlapi/models/openai/gpt-3.5-turbo.toml new file mode 100644 index 00000000000..993c07fdbcd --- /dev/null +++ b/providers/aimlapi/models/openai/gpt-3.5-turbo.toml @@ -0,0 +1,9 @@ +base_model = "openai/gpt-3.5-turbo" +name = "GPT-3.5 Turbo" + +[cost] +input = 0.65 +output = 1.95 + +[limit] +context = 16_000 diff --git a/providers/aimlapi/models/openai/gpt-4-turbo.toml b/providers/aimlapi/models/openai/gpt-4-turbo.toml new file mode 100644 index 00000000000..d90a9e47eb8 --- /dev/null +++ b/providers/aimlapi/models/openai/gpt-4-turbo.toml @@ -0,0 +1,5 @@ +base_model = "openai/gpt-4-turbo" + +[cost] +input = 13 +output = 39 diff --git a/providers/aimlapi/models/openai/gpt-4.1-mini.toml b/providers/aimlapi/models/openai/gpt-4.1-mini.toml new file mode 100644 index 00000000000..454fbbfbba1 --- /dev/null +++ b/providers/aimlapi/models/openai/gpt-4.1-mini.toml @@ -0,0 +1,10 @@ +base_model = "openai/gpt-4.1-mini" +name = "GPT-4.1 Mini" + +[cost] +input = 0.52 +output = 2.08 +cache_read = 0.13 + +[limit] +context = 1_000_000 diff --git a/providers/aimlapi/models/openai/gpt-4.1-nano.toml b/providers/aimlapi/models/openai/gpt-4.1-nano.toml new file mode 100644 index 00000000000..162a49cc035 --- /dev/null +++ b/providers/aimlapi/models/openai/gpt-4.1-nano.toml @@ -0,0 +1,10 @@ +base_model = "openai/gpt-4.1-nano" +name = "GPT-4.1 Nano" + +[cost] +input = 0.13 +output = 0.52 +cache_read = 0.0325 + +[limit] +context = 1_000_000 diff --git a/providers/aimlapi/models/openai/gpt-4.1.toml b/providers/aimlapi/models/openai/gpt-4.1.toml new file mode 100644 index 00000000000..e522294beb7 --- /dev/null +++ b/providers/aimlapi/models/openai/gpt-4.1.toml @@ -0,0 +1,6 @@ +base_model = "openai/gpt-4.1" + +[cost] +input = 2.6 +output = 10.4 +cache_read = 0.65 diff --git a/providers/aimlapi/models/openai/gpt-4.toml b/providers/aimlapi/models/openai/gpt-4.toml new file mode 100644 index 00000000000..2977fbeb28b --- /dev/null +++ b/providers/aimlapi/models/openai/gpt-4.toml @@ -0,0 +1,9 @@ +base_model = "openai/gpt-4" + +[cost] +input = 39 +output = 78 +cache_read = 39 + +[limit] +context = 8_000 diff --git a/providers/aimlapi/models/openai/gpt-4o-2024-05-13.toml b/providers/aimlapi/models/openai/gpt-4o-2024-05-13.toml new file mode 100644 index 00000000000..bb1db38bebf --- /dev/null +++ b/providers/aimlapi/models/openai/gpt-4o-2024-05-13.toml @@ -0,0 +1,9 @@ +base_model = "openai/gpt-4o-2024-05-13" +name = "GPT-4o" + +[cost] +input = 6.5 +output = 19.5 + +[limit] +output = 16_384 diff --git a/providers/aimlapi/models/openai/gpt-4o-2024-08-06.toml b/providers/aimlapi/models/openai/gpt-4o-2024-08-06.toml new file mode 100644 index 00000000000..ccee26a9c14 --- /dev/null +++ b/providers/aimlapi/models/openai/gpt-4o-2024-08-06.toml @@ -0,0 +1,7 @@ +base_model = "openai/gpt-4o-2024-08-06" +name = "GPT-4o" + +[cost] +input = 3.25 +output = 13 +cache_read = 1.625 diff --git a/providers/aimlapi/models/openai/gpt-4o-2024-11-20.toml b/providers/aimlapi/models/openai/gpt-4o-2024-11-20.toml new file mode 100644 index 00000000000..e6424f40c0e --- /dev/null +++ b/providers/aimlapi/models/openai/gpt-4o-2024-11-20.toml @@ -0,0 +1,7 @@ +base_model = "openai/gpt-4o-2024-11-20" +name = "GPT-4o" + +[cost] +input = 3.25 +output = 13 +cache_read = 1.625 diff --git a/providers/aimlapi/models/openai/gpt-4o-mini.toml b/providers/aimlapi/models/openai/gpt-4o-mini.toml new file mode 100644 index 00000000000..30907a5f8e7 --- /dev/null +++ b/providers/aimlapi/models/openai/gpt-4o-mini.toml @@ -0,0 +1,7 @@ +base_model = "openai/gpt-4o-mini" +name = "GPT-4o Mini" + +[cost] +input = 0.195 +output = 0.78 +cache_read = 0.0975 diff --git a/providers/aimlapi/models/openai/gpt-4o.toml b/providers/aimlapi/models/openai/gpt-4o.toml new file mode 100644 index 00000000000..88760223978 --- /dev/null +++ b/providers/aimlapi/models/openai/gpt-4o.toml @@ -0,0 +1,6 @@ +base_model = "openai/gpt-4o" + +[cost] +input = 3.25 +output = 13 +cache_read = 1.625 diff --git a/providers/aimlapi/models/openai/gpt-5-1.toml b/providers/aimlapi/models/openai/gpt-5-1.toml new file mode 100644 index 00000000000..882c534fa1f --- /dev/null +++ b/providers/aimlapi/models/openai/gpt-5-1.toml @@ -0,0 +1,10 @@ +base_model = "openai/gpt-5.1" + +[[reasoning_options]] +type = "effort" +values = ["none", "low", "medium", "high"] + +[cost] +input = 1.625 +output = 13 +cache_read = 0.1625 diff --git a/providers/aimlapi/models/openai/gpt-5-2.toml b/providers/aimlapi/models/openai/gpt-5-2.toml new file mode 100644 index 00000000000..49a3e7c0a17 --- /dev/null +++ b/providers/aimlapi/models/openai/gpt-5-2.toml @@ -0,0 +1,10 @@ +base_model = "openai/gpt-5.2" + +[[reasoning_options]] +type = "effort" +values = ["none", "low", "medium", "high"] + +[cost] +input = 2.275 +output = 18.2 +cache_read = 0.2275 diff --git a/providers/aimlapi/models/openai/gpt-5-4.toml b/providers/aimlapi/models/openai/gpt-5-4.toml new file mode 100644 index 00000000000..55003cd4967 --- /dev/null +++ b/providers/aimlapi/models/openai/gpt-5-4.toml @@ -0,0 +1,10 @@ +base_model = "openai/gpt-5.4" + +[[reasoning_options]] +type = "effort" +values = ["none", "low", "medium", "high"] + +[cost] +input = 3.25 +output = 19.5 +cache_read = 0.325 diff --git a/providers/aimlapi/models/openai/gpt-5-5.toml b/providers/aimlapi/models/openai/gpt-5-5.toml new file mode 100644 index 00000000000..7484a293062 --- /dev/null +++ b/providers/aimlapi/models/openai/gpt-5-5.toml @@ -0,0 +1,10 @@ +base_model = "openai/gpt-5.5" + +[[reasoning_options]] +type = "effort" +values = ["none", "low", "medium", "high"] + +[cost] +input = 6.5 +output = 39 +cache_read = 0.65 diff --git a/providers/aimlapi/models/openai/gpt-5-mini.toml b/providers/aimlapi/models/openai/gpt-5-mini.toml new file mode 100644 index 00000000000..936dc22c60e --- /dev/null +++ b/providers/aimlapi/models/openai/gpt-5-mini.toml @@ -0,0 +1,13 @@ +base_model = "openai/gpt-5-mini" + +[interleaved] +field = "reasoning_details" + +[[reasoning_options]] +type = "effort" +values = ["minimal", "low", "medium", "high"] + +[cost] +input = 0.378235 +output = 3.02588 +cache_read = 0.34385 diff --git a/providers/aimlapi/models/openai/gpt-5-nano.toml b/providers/aimlapi/models/openai/gpt-5-nano.toml new file mode 100644 index 00000000000..d038994a673 --- /dev/null +++ b/providers/aimlapi/models/openai/gpt-5-nano.toml @@ -0,0 +1,13 @@ +base_model = "openai/gpt-5-nano" + +[interleaved] +field = "reasoning_details" + +[[reasoning_options]] +type = "effort" +values = ["minimal", "low", "medium", "high"] + +[cost] +input = 0.075647 +output = 0.605176 +cache_read = 0.06877 diff --git a/providers/aimlapi/models/openai/gpt-5-pro.toml b/providers/aimlapi/models/openai/gpt-5-pro.toml new file mode 100644 index 00000000000..53f5d36b39f --- /dev/null +++ b/providers/aimlapi/models/openai/gpt-5-pro.toml @@ -0,0 +1,12 @@ +base_model = "openai/gpt-5-pro" + +[interleaved] +field = "reasoning_details" + +[[reasoning_options]] +type = "effort" +values = ["high"] + +[cost] +input = 20.631 +output = 165.048 diff --git a/providers/aimlapi/models/openai/gpt-5.1-codex-max.toml b/providers/aimlapi/models/openai/gpt-5.1-codex-max.toml new file mode 100644 index 00000000000..3abda7bb2ef --- /dev/null +++ b/providers/aimlapi/models/openai/gpt-5.1-codex-max.toml @@ -0,0 +1,14 @@ +base_model = "openai/gpt-5.1-codex-max" +name = "GPT-5.1-Codex-Max" + +[interleaved] +field = "reasoning_details" + +[[reasoning_options]] +type = "effort" +values = ["low", "medium", "high"] + +[cost] +input = 3.4385 +output = 27.508 +cache_read = 0.34385 diff --git a/providers/aimlapi/models/openai/gpt-5.1-codex-mini.toml b/providers/aimlapi/models/openai/gpt-5.1-codex-mini.toml new file mode 100644 index 00000000000..dccf0944ca6 --- /dev/null +++ b/providers/aimlapi/models/openai/gpt-5.1-codex-mini.toml @@ -0,0 +1,14 @@ +base_model = "openai/gpt-5.1-codex-mini" +name = "GPT-5.1 Codex Mini" + +[interleaved] +field = "reasoning_details" + +[[reasoning_options]] +type = "effort" +values = ["low", "medium", "high"] + +[cost] +input = 0.34385 +output = 2.7508 +cache_read = 0.041262 diff --git a/providers/aimlapi/models/openai/gpt-5.1-codex.toml b/providers/aimlapi/models/openai/gpt-5.1-codex.toml new file mode 100644 index 00000000000..33b2d94cbe8 --- /dev/null +++ b/providers/aimlapi/models/openai/gpt-5.1-codex.toml @@ -0,0 +1,13 @@ +base_model = "openai/gpt-5.1-codex" + +[interleaved] +field = "reasoning_details" + +[[reasoning_options]] +type = "effort" +values = ["low", "medium", "high"] + +[cost] +input = 3.4385 +output = 27.508 +cache_read = 0.34385 diff --git a/providers/aimlapi/models/openai/gpt-5.2-codex.toml b/providers/aimlapi/models/openai/gpt-5.2-codex.toml new file mode 100644 index 00000000000..5b16e1f8b2c --- /dev/null +++ b/providers/aimlapi/models/openai/gpt-5.2-codex.toml @@ -0,0 +1,13 @@ +base_model = "openai/gpt-5.2-codex" + +[interleaved] +field = "reasoning_details" + +[[reasoning_options]] +type = "effort" +values = ["low", "medium", "high"] + +[cost] +input = 4.8139 +output = 38.5112 +cache_read = 0.48139 diff --git a/providers/aimlapi/models/openai/gpt-5.2-pro.toml b/providers/aimlapi/models/openai/gpt-5.2-pro.toml new file mode 100644 index 00000000000..fb64e3c84fe --- /dev/null +++ b/providers/aimlapi/models/openai/gpt-5.2-pro.toml @@ -0,0 +1,12 @@ +base_model = "openai/gpt-5.2-pro" + +[interleaved] +field = "reasoning_details" + +[[reasoning_options]] +type = "effort" +values = ["medium", "high"] + +[cost] +input = 28.8834 +output = 231.0672 diff --git a/providers/aimlapi/models/openai/gpt-5.3-codex.toml b/providers/aimlapi/models/openai/gpt-5.3-codex.toml new file mode 100644 index 00000000000..a4f39525490 --- /dev/null +++ b/providers/aimlapi/models/openai/gpt-5.3-codex.toml @@ -0,0 +1,14 @@ +# Off: reasoning_effort = none (0 reasoning tokens); no toggle field on this surface. +base_model = "openai/gpt-5.3-codex" + +[interleaved] +field = "reasoning_details" + +[[reasoning_options]] +type = "effort" +values = ["none", "low", "medium", "high"] + +[cost] +input = 4.8139 +output = 38.5112 +cache_read = 0.48139 diff --git a/providers/aimlapi/models/openai/gpt-5.4-image-2.toml b/providers/aimlapi/models/openai/gpt-5.4-image-2.toml new file mode 100644 index 00000000000..9f9107d117d --- /dev/null +++ b/providers/aimlapi/models/openai/gpt-5.4-image-2.toml @@ -0,0 +1,10 @@ +base_model = "openai/gpt-5.4-image-2" + +[[reasoning_options]] +type = "effort" +values = ["low", "medium", "high"] + +[cost] +input = 11.0032 +output = 20.631 +cache_read = 2.7508 diff --git a/providers/aimlapi/models/openai/gpt-5.4-mini.toml b/providers/aimlapi/models/openai/gpt-5.4-mini.toml new file mode 100644 index 00000000000..5a493e14a40 --- /dev/null +++ b/providers/aimlapi/models/openai/gpt-5.4-mini.toml @@ -0,0 +1,11 @@ +base_model = "openai/gpt-5.4-mini" +name = "GPT-5.4 Mini" + +[[reasoning_options]] +type = "effort" +values = ["none", "low", "medium", "high"] + +[cost] +input = 2.0631 +output = 12.3786 +cache_read = 0.20631 diff --git a/providers/aimlapi/models/openai/gpt-5.4-nano.toml b/providers/aimlapi/models/openai/gpt-5.4-nano.toml new file mode 100644 index 00000000000..a8f744792e0 --- /dev/null +++ b/providers/aimlapi/models/openai/gpt-5.4-nano.toml @@ -0,0 +1,11 @@ +base_model = "openai/gpt-5.4-nano" +name = "GPT-5.4 Nano" + +[[reasoning_options]] +type = "effort" +values = ["none", "low", "medium", "high"] + +[cost] +input = 0.27508 +output = 1.71925 +cache_read = 0.027508 diff --git a/providers/aimlapi/models/openai/gpt-5.4-pro.toml b/providers/aimlapi/models/openai/gpt-5.4-pro.toml new file mode 100644 index 00000000000..9cbfce2f1cf --- /dev/null +++ b/providers/aimlapi/models/openai/gpt-5.4-pro.toml @@ -0,0 +1,12 @@ +base_model = "openai/gpt-5.4-pro" + +[interleaved] +field = "reasoning_details" + +[[reasoning_options]] +type = "effort" +values = ["medium", "high"] + +[cost] +input = 41.262 +output = 247.572 diff --git a/providers/aimlapi/models/openai/gpt-5.5-pro.toml b/providers/aimlapi/models/openai/gpt-5.5-pro.toml new file mode 100644 index 00000000000..1ed1ce270cc --- /dev/null +++ b/providers/aimlapi/models/openai/gpt-5.5-pro.toml @@ -0,0 +1,12 @@ +base_model = "openai/gpt-5.5-pro" + +[interleaved] +field = "reasoning_details" + +[[reasoning_options]] +type = "effort" +values = ["medium", "high"] + +[cost] +input = 41.262 +output = 247.572 diff --git a/providers/aimlapi/models/openai/gpt-5.6-luna-pro.toml b/providers/aimlapi/models/openai/gpt-5.6-luna-pro.toml new file mode 100644 index 00000000000..cbb21e9c66e --- /dev/null +++ b/providers/aimlapi/models/openai/gpt-5.6-luna-pro.toml @@ -0,0 +1,14 @@ +base_model = "openai/gpt-5.6-luna" +name = "GPT-5.6 Luna Pro" + +[interleaved] +field = "reasoning_details" + +[[reasoning_options]] +type = "effort" +values = ["none", "low", "medium", "high"] + +[cost] +input = 0.27508 +output = 1.65048 +cache_read = 0.027508 diff --git a/providers/aimlapi/models/openai/gpt-5.6-luna.toml b/providers/aimlapi/models/openai/gpt-5.6-luna.toml new file mode 100644 index 00000000000..42e83f452c3 --- /dev/null +++ b/providers/aimlapi/models/openai/gpt-5.6-luna.toml @@ -0,0 +1,11 @@ +# Off: reasoning_effort = none (0 reasoning tokens); no toggle field on this surface. +base_model = "openai/gpt-5.6-luna" + +[[reasoning_options]] +type = "effort" +values = ["none", "low", "medium", "high"] + +[cost] +input = 0.26 +output = 1.56 +cache_read = 0.026 diff --git a/providers/aimlapi/models/openai/gpt-5.6-sol-pro.toml b/providers/aimlapi/models/openai/gpt-5.6-sol-pro.toml new file mode 100644 index 00000000000..d350abe9f0b --- /dev/null +++ b/providers/aimlapi/models/openai/gpt-5.6-sol-pro.toml @@ -0,0 +1,14 @@ +base_model = "openai/gpt-5.6-sol" +name = "GPT-5.6 Sol Pro" + +[interleaved] +field = "reasoning_details" + +[[reasoning_options]] +type = "effort" +values = ["none", "low", "medium", "high"] + +[cost] +input = 5.5016 +output = 27.508 +cache_read = 0.55016 diff --git a/providers/aimlapi/models/openai/gpt-5.6-sol.toml b/providers/aimlapi/models/openai/gpt-5.6-sol.toml new file mode 100644 index 00000000000..b5fefa47a8a --- /dev/null +++ b/providers/aimlapi/models/openai/gpt-5.6-sol.toml @@ -0,0 +1,11 @@ +# Off: reasoning_effort = none (0 reasoning tokens); no toggle field on this surface. +base_model = "openai/gpt-5.6-sol" + +[[reasoning_options]] +type = "effort" +values = ["none", "low", "medium", "high"] + +[cost] +input = 5.2 +output = 26 +cache_read = 0.52 diff --git a/providers/aimlapi/models/openai/gpt-5.6-terra-pro.toml b/providers/aimlapi/models/openai/gpt-5.6-terra-pro.toml new file mode 100644 index 00000000000..22cea416553 --- /dev/null +++ b/providers/aimlapi/models/openai/gpt-5.6-terra-pro.toml @@ -0,0 +1,15 @@ +# Off: reasoning_effort = none (0 reasoning tokens); no toggle field on this surface. +base_model = "openai/gpt-5.6-terra" +name = "GPT-5.6 Terra Pro" + +[interleaved] +field = "reasoning_details" + +[[reasoning_options]] +type = "effort" +values = ["none", "low", "medium", "high"] + +[cost] +input = 2.7508 +output = 16.5048 +cache_read = 0.27508 diff --git a/providers/aimlapi/models/openai/gpt-5.6-terra.toml b/providers/aimlapi/models/openai/gpt-5.6-terra.toml new file mode 100644 index 00000000000..c8e9ac4525e --- /dev/null +++ b/providers/aimlapi/models/openai/gpt-5.6-terra.toml @@ -0,0 +1,11 @@ +# Off: reasoning_effort = none (0 reasoning tokens); no toggle field on this surface. +base_model = "openai/gpt-5.6-terra" + +[[reasoning_options]] +type = "effort" +values = ["none", "low", "medium", "high"] + +[cost] +input = 2.6 +output = 15.6 +cache_read = 0.26 diff --git a/providers/aimlapi/models/openai/gpt-5.toml b/providers/aimlapi/models/openai/gpt-5.toml new file mode 100644 index 00000000000..5e43e7e65e0 --- /dev/null +++ b/providers/aimlapi/models/openai/gpt-5.toml @@ -0,0 +1,13 @@ +base_model = "openai/gpt-5" + +[interleaved] +field = "reasoning_details" + +[[reasoning_options]] +type = "effort" +values = ["minimal", "low", "medium", "high"] + +[cost] +input = 1.891175 +output = 15.1294 +cache_read = 1.71925 diff --git a/providers/aimlapi/models/openai/gpt-6-astra.toml b/providers/aimlapi/models/openai/gpt-6-astra.toml new file mode 100644 index 00000000000..1b1eac5d7f7 --- /dev/null +++ b/providers/aimlapi/models/openai/gpt-6-astra.toml @@ -0,0 +1,10 @@ +base_model = "openai/gpt-6-astra" + +[[reasoning_options]] +type = "effort" +values = ["low", "medium", "high", "xhigh", "max"] + +[cost] +input = 13 +output = 65 +cache_read = 1.3 diff --git a/providers/aimlapi/models/openai/gpt-6-luna.toml b/providers/aimlapi/models/openai/gpt-6-luna.toml new file mode 100644 index 00000000000..11b562ce379 --- /dev/null +++ b/providers/aimlapi/models/openai/gpt-6-luna.toml @@ -0,0 +1,10 @@ +base_model = "openai/gpt-6-luna" + +[[reasoning_options]] +type = "effort" +values = ["none", "low", "medium", "high"] + +[cost] +input = 0.13 +output = 0.65 +cache_read = 0.013 diff --git a/providers/aimlapi/models/openai/gpt-6-sol.toml b/providers/aimlapi/models/openai/gpt-6-sol.toml new file mode 100644 index 00000000000..688ca1ef448 --- /dev/null +++ b/providers/aimlapi/models/openai/gpt-6-sol.toml @@ -0,0 +1,10 @@ +base_model = "openai/gpt-6-sol" + +[[reasoning_options]] +type = "effort" +values = ["none", "low", "medium", "high"] + +[cost] +input = 2.6 +output = 13 +cache_read = 0.26 diff --git a/providers/aimlapi/models/openai/gpt-6.1-sol.toml b/providers/aimlapi/models/openai/gpt-6.1-sol.toml new file mode 100644 index 00000000000..92eb2770261 --- /dev/null +++ b/providers/aimlapi/models/openai/gpt-6.1-sol.toml @@ -0,0 +1,10 @@ +base_model = "openai/gpt-6.1-sol" + +[[reasoning_options]] +type = "effort" +values = ["low", "medium", "high"] + +[cost] +input = 2.6 +output = 13 +cache_read = 0.13 diff --git a/providers/aimlapi/models/openai/gpt-oss-120b.toml b/providers/aimlapi/models/openai/gpt-oss-120b.toml new file mode 100644 index 00000000000..847a6b2c517 --- /dev/null +++ b/providers/aimlapi/models/openai/gpt-oss-120b.toml @@ -0,0 +1,17 @@ +base_model = "openai/gpt-oss-120b" + +[interleaved] +field = "reasoning_details" + +[[reasoning_options]] +type = "effort" +values = ["low", "medium", "high"] + +[cost] +input = 0.48139 +output = 1.30663 +cache_read = 0.48139 + +[limit] +context = 131_000 +output = 117_964 diff --git a/providers/aimlapi/models/openai/gpt-oss-20b.toml b/providers/aimlapi/models/openai/gpt-oss-20b.toml new file mode 100644 index 00000000000..114b4f16097 --- /dev/null +++ b/providers/aimlapi/models/openai/gpt-oss-20b.toml @@ -0,0 +1,17 @@ +base_model = "openai/gpt-oss-20b" + +[interleaved] +field = "reasoning_details" + +[[reasoning_options]] +type = "effort" +values = ["low", "medium", "high"] + +[cost] +input = 0.103155 +output = 0.41262 +cache_read = 0.051578 + +[limit] +context = 131_000 +output = 117_964 diff --git a/providers/aimlapi/models/openai/gpt-oss-safeguard-20b.toml b/providers/aimlapi/models/openai/gpt-oss-safeguard-20b.toml new file mode 100644 index 00000000000..31fa4a68e7b --- /dev/null +++ b/providers/aimlapi/models/openai/gpt-oss-safeguard-20b.toml @@ -0,0 +1,14 @@ +base_model = "openai/gpt-oss-safeguard-20b" +name = "gpt-oss-safeguard-20b" + +[[reasoning_options]] +type = "effort" +values = ["low", "medium", "high"] + +[cost] +input = 0.103155 +output = 0.41262 +cache_read = 0.051578 + +[limit] +output = 65_536 diff --git a/providers/aimlapi/models/openai/o1-pro.toml b/providers/aimlapi/models/openai/o1-pro.toml new file mode 100644 index 00000000000..e340c6100d3 --- /dev/null +++ b/providers/aimlapi/models/openai/o1-pro.toml @@ -0,0 +1,12 @@ +base_model = "openai/o1-pro" + +[interleaved] +field = "reasoning_details" + +[[reasoning_options]] +type = "effort" +values = ["low", "medium", "high"] + +[cost] +input = 206.31 +output = 825.24 diff --git a/providers/aimlapi/models/openai/o1.toml b/providers/aimlapi/models/openai/o1.toml new file mode 100644 index 00000000000..151ea41109a --- /dev/null +++ b/providers/aimlapi/models/openai/o1.toml @@ -0,0 +1,13 @@ +base_model = "openai/o1" + +[[reasoning_options]] +type = "effort" +values = ["low", "medium", "high"] + +[cost] +input = 19.5 +output = 78 +cache_read = 9.75 + +[limit] +context = 128_000 diff --git a/providers/aimlapi/models/openai/o3-mini.toml b/providers/aimlapi/models/openai/o3-mini.toml new file mode 100644 index 00000000000..4790bb65f30 --- /dev/null +++ b/providers/aimlapi/models/openai/o3-mini.toml @@ -0,0 +1,11 @@ +base_model = "openai/o3-mini" +name = "o3 Mini" + +[[reasoning_options]] +type = "effort" +values = ["low", "medium", "high"] + +[cost] +input = 1.43 +output = 5.72 +cache_read = 0.715 diff --git a/providers/aimlapi/models/openai/o3-pro.toml b/providers/aimlapi/models/openai/o3-pro.toml new file mode 100644 index 00000000000..1e9022547c7 --- /dev/null +++ b/providers/aimlapi/models/openai/o3-pro.toml @@ -0,0 +1,13 @@ +base_model = "openai/o3-pro" +name = "o3 Pro" + +[interleaved] +field = "reasoning_details" + +[[reasoning_options]] +type = "effort" +values = ["low", "medium", "high"] + +[cost] +input = 27.508 +output = 110.032 diff --git a/providers/aimlapi/models/perplexity/sonar-pro.toml b/providers/aimlapi/models/perplexity/sonar-pro.toml new file mode 100644 index 00000000000..d353019ac3a --- /dev/null +++ b/providers/aimlapi/models/perplexity/sonar-pro.toml @@ -0,0 +1,8 @@ +base_model = "perplexity/sonar-pro" + +[cost] +input = 3.9 +output = 19.5 + +[limit] +output = 100_000 diff --git a/providers/aimlapi/models/perplexity/sonar.toml b/providers/aimlapi/models/perplexity/sonar.toml new file mode 100644 index 00000000000..8b062038318 --- /dev/null +++ b/providers/aimlapi/models/perplexity/sonar.toml @@ -0,0 +1,8 @@ +base_model = "perplexity/sonar" + +[cost] +input = 1.3 +output = 1.3 + +[limit] +output = 100_000 diff --git a/providers/aimlapi/models/rekaai/reka-edge.toml b/providers/aimlapi/models/rekaai/reka-edge.toml new file mode 100644 index 00000000000..ed94c5ecb3f --- /dev/null +++ b/providers/aimlapi/models/rekaai/reka-edge.toml @@ -0,0 +1,8 @@ +base_model = "rekaai/reka-edge" + +[cost] +input = 0.13754 +output = 0.13754 + +[limit] +output = 16_384 diff --git a/providers/aimlapi/models/relace/relace-apply-3.toml b/providers/aimlapi/models/relace/relace-apply-3.toml new file mode 100644 index 00000000000..c09cd04a080 --- /dev/null +++ b/providers/aimlapi/models/relace/relace-apply-3.toml @@ -0,0 +1,6 @@ +base_model = "relace/relace-apply-3" +name = "Apply 3" + +[cost] +input = 1.16909 +output = 1.71925 diff --git a/providers/aimlapi/models/relace/relace-search.toml b/providers/aimlapi/models/relace/relace-search.toml new file mode 100644 index 00000000000..8331590f1ce --- /dev/null +++ b/providers/aimlapi/models/relace/relace-search.toml @@ -0,0 +1,6 @@ +base_model = "relace/relace-search" +name = "Search" + +[cost] +input = 1.3754 +output = 4.1262 diff --git a/providers/aimlapi/models/sakana/fugu-max.toml b/providers/aimlapi/models/sakana/fugu-max.toml new file mode 100644 index 00000000000..7066f437b7a --- /dev/null +++ b/providers/aimlapi/models/sakana/fugu-max.toml @@ -0,0 +1,10 @@ +base_model = "sakana/fugu-max" + +[[reasoning_options]] +type = "effort" +values = ["high"] + +[cost] +input = 2.7508 +output = 8.2524 +cache_read = 0.34385 diff --git a/providers/aimlapi/models/sakana/fugu-ultra-v2.toml b/providers/aimlapi/models/sakana/fugu-ultra-v2.toml new file mode 100644 index 00000000000..bf358617468 --- /dev/null +++ b/providers/aimlapi/models/sakana/fugu-ultra-v2.toml @@ -0,0 +1,10 @@ +base_model = "sakana/fugu-ultra-v2" + +[[reasoning_options]] +type = "effort" +values = ["high"] + +[cost] +input = 6.877 +output = 41.262 +cache_read = 0.6877 diff --git a/providers/aimlapi/models/sakana/fugu-ultra.toml b/providers/aimlapi/models/sakana/fugu-ultra.toml new file mode 100644 index 00000000000..585cbf492e0 --- /dev/null +++ b/providers/aimlapi/models/sakana/fugu-ultra.toml @@ -0,0 +1,13 @@ +base_model = "sakana/fugu-ultra" + +[[reasoning_options]] +type = "effort" +values = ["high"] + +[cost] +input = 6.877 +output = 41.262 +cache_read = 0.6877 + +[limit] +output = 128_000 diff --git a/providers/aimlapi/models/sao10k/l3-lunaris-8b.toml b/providers/aimlapi/models/sao10k/l3-lunaris-8b.toml new file mode 100644 index 00000000000..11edc5c2b28 --- /dev/null +++ b/providers/aimlapi/models/sao10k/l3-lunaris-8b.toml @@ -0,0 +1,5 @@ +base_model = "sao10k/l3-lunaris-8b" + +[cost] +input = 0.06877 +output = 0.06877 diff --git a/providers/aimlapi/models/sao10k/l3.1-euryale-70b.toml b/providers/aimlapi/models/sao10k/l3.1-euryale-70b.toml new file mode 100644 index 00000000000..7a07568c1bb --- /dev/null +++ b/providers/aimlapi/models/sao10k/l3.1-euryale-70b.toml @@ -0,0 +1,5 @@ +base_model = "sao10k/l3.1-euryale-70b" + +[cost] +input = 1.99488 +output = 1.99488 diff --git a/providers/aimlapi/models/sao10k/l3.3-euryale-70b.toml b/providers/aimlapi/models/sao10k/l3.3-euryale-70b.toml new file mode 100644 index 00000000000..1d9a37dca11 --- /dev/null +++ b/providers/aimlapi/models/sao10k/l3.3-euryale-70b.toml @@ -0,0 +1,5 @@ +base_model = "sao10k/l3.3-euryale-70b" + +[cost] +input = 0.89401 +output = 1.03155 diff --git a/providers/aimlapi/models/stepfun/step-5-preview.toml b/providers/aimlapi/models/stepfun/step-5-preview.toml new file mode 100644 index 00000000000..d8ca6a58992 --- /dev/null +++ b/providers/aimlapi/models/stepfun/step-5-preview.toml @@ -0,0 +1,13 @@ +base_model = "stepfun/step-5-preview" + +[[reasoning_options]] +type = "effort" +values = ["low", "medium", "high"] + +[cost] +input = 1.3754 +output = 3.71358 +cache_read = 0.06877 + +[limit] +output = 64_000 diff --git a/providers/aimlapi/models/tencent/hy-mt2-1.8b.toml b/providers/aimlapi/models/tencent/hy-mt2-1.8b.toml new file mode 100644 index 00000000000..14d955fb660 --- /dev/null +++ b/providers/aimlapi/models/tencent/hy-mt2-1.8b.toml @@ -0,0 +1,5 @@ +base_model = "tencent/hy-mt2-1.8b" + +[cost] +input = 0.060518 +output = 0.243446 diff --git a/providers/aimlapi/models/tencent/hy-mt2-30b-a3b.toml b/providers/aimlapi/models/tencent/hy-mt2-30b-a3b.toml new file mode 100644 index 00000000000..ebc2d5465d9 --- /dev/null +++ b/providers/aimlapi/models/tencent/hy-mt2-30b-a3b.toml @@ -0,0 +1,5 @@ +base_model = "tencent/hy-mt2-30b-a3b" + +[cost] +input = 0.10178 +output = 0.405743 diff --git a/providers/aimlapi/models/tencent/hy-mt2-7b.toml b/providers/aimlapi/models/tencent/hy-mt2-7b.toml new file mode 100644 index 00000000000..09181507290 --- /dev/null +++ b/providers/aimlapi/models/tencent/hy-mt2-7b.toml @@ -0,0 +1,5 @@ +base_model = "tencent/hy-mt2-7b" + +[cost] +input = 0.10178 +output = 0.405743 diff --git a/providers/aimlapi/models/tencent/hy3.toml b/providers/aimlapi/models/tencent/hy3.toml new file mode 100644 index 00000000000..47856496a42 --- /dev/null +++ b/providers/aimlapi/models/tencent/hy3.toml @@ -0,0 +1,18 @@ +base_model = "tencent/hy3" +base_model_omit = ["limit.input"] + +[interleaved] +field = "reasoning_details" + +[[reasoning_options]] +type = "effort" +values = ["low", "high"] + +[cost] +input = 0.27508 +output = 1.10032 +cache_read = 0.06877 + +[limit] +context = 262_144 +output = 131_072 diff --git a/providers/aimlapi/models/tencent/hy4-preview.toml b/providers/aimlapi/models/tencent/hy4-preview.toml new file mode 100644 index 00000000000..9448d93b7f1 --- /dev/null +++ b/providers/aimlapi/models/tencent/hy4-preview.toml @@ -0,0 +1,16 @@ +base_model = "tencent/hy4-preview" + +[interleaved] +field = "reasoning_details" + +[[reasoning_options]] +type = "effort" +values = ["low", "high"] + +[cost] +input = 1.147084 +output = 3.439875 +cache_read = 0.057767 + +[limit] +context = 1_048_576 diff --git a/providers/aimlapi/models/thedrummer/cydonia-24b-v4.1.toml b/providers/aimlapi/models/thedrummer/cydonia-24b-v4.1.toml new file mode 100644 index 00000000000..15e83fbeb43 --- /dev/null +++ b/providers/aimlapi/models/thedrummer/cydonia-24b-v4.1.toml @@ -0,0 +1,9 @@ +base_model = "thedrummer/cydonia-24b-v4.1" + +[cost] +input = 0.41262 +output = 0.6877 +cache_read = 0.20631 + +[limit] +output = 131_072 diff --git a/providers/aimlapi/models/thedrummer/skyfall-36b-v2.toml b/providers/aimlapi/models/thedrummer/skyfall-36b-v2.toml new file mode 100644 index 00000000000..5caeaa3c10b --- /dev/null +++ b/providers/aimlapi/models/thedrummer/skyfall-36b-v2.toml @@ -0,0 +1,9 @@ +base_model = "thedrummer/skyfall-36b-v2" + +[cost] +input = 0.75647 +output = 1.10032 +cache_read = 0.34385 + +[limit] +output = 32_768 diff --git a/providers/aimlapi/models/thedrummer/unslopnemo-12b.toml b/providers/aimlapi/models/thedrummer/unslopnemo-12b.toml new file mode 100644 index 00000000000..94cca2175f2 --- /dev/null +++ b/providers/aimlapi/models/thedrummer/unslopnemo-12b.toml @@ -0,0 +1,9 @@ +base_model = "thedrummer/unslopnemo-12b" + +[cost] +input = 0.55016 +output = 0.55016 + +[limit] +context = 32_768 +output = 32_768 diff --git a/providers/aimlapi/models/thinkingmachines/inkling-small.toml b/providers/aimlapi/models/thinkingmachines/inkling-small.toml new file mode 100644 index 00000000000..eb41ee89285 --- /dev/null +++ b/providers/aimlapi/models/thinkingmachines/inkling-small.toml @@ -0,0 +1,17 @@ +base_model = "thinkingmachines/inkling-small" + +[interleaved] +field = "reasoning_details" + +[[reasoning_options]] +type = "effort" +values = ["low", "medium", "high"] + +[cost] +input = 0.797732 +output = 1.980576 +cache_read = 0.159546 + +[limit] +context = 524_288 +output = 262_144 diff --git a/providers/aimlapi/models/thinkingmachines/inkling.toml b/providers/aimlapi/models/thinkingmachines/inkling.toml new file mode 100644 index 00000000000..5ec8e4b621d --- /dev/null +++ b/providers/aimlapi/models/thinkingmachines/inkling.toml @@ -0,0 +1,13 @@ +base_model = "thinkingmachines/inkling" + +[interleaved] +field = "reasoning_details" + +[[reasoning_options]] +type = "effort" +values = ["low", "medium", "high"] + +[cost] +input = 1.3754 +output = 5.57037 +cache_read = 0.233818 diff --git a/providers/aimlapi/models/unbiased/pareto.toml b/providers/aimlapi/models/unbiased/pareto.toml new file mode 100644 index 00000000000..86d2239620f --- /dev/null +++ b/providers/aimlapi/models/unbiased/pareto.toml @@ -0,0 +1,6 @@ +base_model = "unbiased/pareto" + +[cost] +input = 3.4385 +output = 10.3155 +cache_read = 0.34385 diff --git a/providers/aimlapi/models/undi95/remm-slerp-l2-13b.toml b/providers/aimlapi/models/undi95/remm-slerp-l2-13b.toml new file mode 100644 index 00000000000..3ddfb241825 --- /dev/null +++ b/providers/aimlapi/models/undi95/remm-slerp-l2-13b.toml @@ -0,0 +1,8 @@ +base_model = "undi95/remm-slerp-l2-13b" + +[cost] +input = 0.6877 +output = 1.03155 + +[limit] +output = 4_096 diff --git a/providers/aimlapi/models/upstage/solar-pro-3.toml b/providers/aimlapi/models/upstage/solar-pro-3.toml new file mode 100644 index 00000000000..58747fef346 --- /dev/null +++ b/providers/aimlapi/models/upstage/solar-pro-3.toml @@ -0,0 +1,13 @@ +base_model = "upstage/solar-pro3" + +[[reasoning_options]] +type = "effort" +values = ["low", "medium", "high"] + +[cost] +input = 0.20631 +output = 0.82524 +cache_read = 0.020631 + +[limit] +context = 128_000 diff --git a/providers/aimlapi/models/upstage/solar-pro4.toml b/providers/aimlapi/models/upstage/solar-pro4.toml new file mode 100644 index 00000000000..4db867cd117 --- /dev/null +++ b/providers/aimlapi/models/upstage/solar-pro4.toml @@ -0,0 +1,10 @@ +base_model = "upstage/solar-pro4" + +[[reasoning_options]] +type = "effort" +values = ["none", "low", "medium", "high"] + +[cost] +input = 0.041262 +output = 0.165048 +cache_read = 0.008252 diff --git a/providers/aimlapi/models/x-ai/grok-4-20-0309-non-reasoning.toml b/providers/aimlapi/models/x-ai/grok-4-20-0309-non-reasoning.toml new file mode 100644 index 00000000000..fb630840cbb --- /dev/null +++ b/providers/aimlapi/models/x-ai/grok-4-20-0309-non-reasoning.toml @@ -0,0 +1,11 @@ +base_model = "xai/grok-4.20-0309-non-reasoning" +name = "Grok 4.20 Non-Reasoning" + +[cost] +input = 1.625 +output = 3.25 +cache_read = 0.26 + +[limit] +context = 2_000_000 +output = 1_999_000 diff --git a/providers/aimlapi/models/x-ai/grok-4-fast-non-reasoning.toml b/providers/aimlapi/models/x-ai/grok-4-fast-non-reasoning.toml new file mode 100644 index 00000000000..c7e60b9aa0f --- /dev/null +++ b/providers/aimlapi/models/x-ai/grok-4-fast-non-reasoning.toml @@ -0,0 +1,10 @@ +base_model = "xai/grok-4-fast-non-reasoning" +name = "Grok 4 Fast Non-Reasoning" + +[cost] +input = 1.625 +output = 3.25 +cache_read = 0.26 + +[limit] +output = 1_999_000 diff --git a/providers/aimlapi/models/xiaomi/mimo-v2.5-pro.toml b/providers/aimlapi/models/xiaomi/mimo-v2.5-pro.toml new file mode 100644 index 00000000000..33df4830dda --- /dev/null +++ b/providers/aimlapi/models/xiaomi/mimo-v2.5-pro.toml @@ -0,0 +1,17 @@ +# No caller control: reasoning_effort is validated (invalid value -> 400) but low/high +# do not order reasoning tokens; toggle/budget fields are dropped by the gateway. +base_model = "xiaomi/mimo-v2.5-pro" +name = "MiMo V2.5 Pro" +reasoning_options = [] + +[interleaved] +field = "reasoning_details" + +[cost] +input = 0.598299 +output = 1.196598 +cache_read = 0.004951 + +[limit] +context = 1_000_000 +output = 128_000 diff --git a/providers/aimlapi/models/xiaomi/mimo-v2.5.toml b/providers/aimlapi/models/xiaomi/mimo-v2.5.toml new file mode 100644 index 00000000000..185533b4a3c --- /dev/null +++ b/providers/aimlapi/models/xiaomi/mimo-v2.5.toml @@ -0,0 +1,17 @@ +# No caller control: reasoning_effort is validated (invalid value -> 400) but low/high +# do not order reasoning tokens; toggle/budget fields are dropped by the gateway. +base_model = "xiaomi/mimo-v2.5" +name = "MiMo V2.5" +reasoning_options = [] + +[interleaved] +field = "reasoning_details" + +[cost] +input = 0.192556 +output = 0.385112 +cache_read = 0.003851 + +[limit] +context = 1_000_000 +output = 128_000 diff --git a/providers/aimlapi/models/z-ai/glm-4.5v.toml b/providers/aimlapi/models/z-ai/glm-4.5v.toml new file mode 100644 index 00000000000..4fd16eee24f --- /dev/null +++ b/providers/aimlapi/models/z-ai/glm-4.5v.toml @@ -0,0 +1,16 @@ +# No caller control: reasoning_effort is validated (invalid value -> 400) but low/high +# do not order reasoning tokens; toggle/budget fields are dropped by the gateway. +base_model = "zhipuai/glm-4.5v" +name = "GLM 4.5V" +reasoning_options = [] + +[interleaved] +field = "reasoning_details" + +[cost] +input = 0.82524 +output = 2.47572 +cache_read = 0.151294 + +[limit] +context = 65_536 diff --git a/providers/aimlapi/models/z-ai/glm-4.6v.toml b/providers/aimlapi/models/z-ai/glm-4.6v.toml new file mode 100644 index 00000000000..973d13d224e --- /dev/null +++ b/providers/aimlapi/models/z-ai/glm-4.6v.toml @@ -0,0 +1,16 @@ +# No caller control: reasoning_effort is validated (invalid value -> 400) but low/high +# do not order reasoning tokens; toggle/budget fields are dropped by the gateway. +base_model = "zhipuai/glm-4.6v" +name = "GLM 4.6V" +reasoning_options = [] + +[interleaved] +field = "reasoning_details" + +[cost] +input = 0.41262 +output = 1.23786 +cache_read = 0.075647 + +[limit] +context = 131_072 diff --git a/providers/aimlapi/models/z-ai/glm-4.7-flash.toml b/providers/aimlapi/models/z-ai/glm-4.7-flash.toml new file mode 100644 index 00000000000..88b3d72d30c --- /dev/null +++ b/providers/aimlapi/models/z-ai/glm-4.7-flash.toml @@ -0,0 +1,17 @@ +# No caller control: reasoning_effort is validated (invalid value -> 400) but low/high +# do not order reasoning tokens; toggle/budget fields are dropped by the gateway. +base_model = "zhipuai/glm-4.7-flash" +name = "GLM 4.7 Flash" +reasoning_options = [] + +[interleaved] +field = "reasoning_details" + +[cost] +input = 0.171925 +output = 0.6877 +cache_read = 0.013754 + +[limit] +context = 202_752 +output = 16_384 diff --git a/providers/aimlapi/models/z-ai/glm-5-turbo.toml b/providers/aimlapi/models/z-ai/glm-5-turbo.toml new file mode 100644 index 00000000000..e7bcb32d106 --- /dev/null +++ b/providers/aimlapi/models/z-ai/glm-5-turbo.toml @@ -0,0 +1,13 @@ +# No caller control: reasoning_effort is not read (an invalid value returns 200), +# and toggle/budget fields are dropped by the gateway (unknown top-level keys -> 200). +base_model = "zhipuai/glm-5-turbo" +name = "GLM 5 Turbo" +reasoning_options = [] + +[cost] +input = 1.56 +output = 5.2 +cache_read = 0.312 + +[limit] +context = 262_144 diff --git a/providers/aimlapi/models/z-ai/glm-5.3-flash.toml b/providers/aimlapi/models/z-ai/glm-5.3-flash.toml new file mode 100644 index 00000000000..b17a00ac81b --- /dev/null +++ b/providers/aimlapi/models/z-ai/glm-5.3-flash.toml @@ -0,0 +1,17 @@ +base_model = "zhipuai/glm-5.3-flash" +name = "GLM 5.3 Flash" + +[interleaved] +field = "reasoning_content" + +[[reasoning_options]] +type = "effort" +values = ["low", "high", "max"] + +[cost] +input = 0.195 +output = 0.65 +cache_read = 0.039 + +[limit] +context = 1_048_576 diff --git a/providers/aimlapi/models/z-ai/glm-5v-turbo.toml b/providers/aimlapi/models/z-ai/glm-5v-turbo.toml new file mode 100644 index 00000000000..02230f0e612 --- /dev/null +++ b/providers/aimlapi/models/z-ai/glm-5v-turbo.toml @@ -0,0 +1,13 @@ +# No caller control: reasoning_effort is not read (an invalid value returns 200), +# and toggle/budget fields are dropped by the gateway (unknown top-level keys -> 200). +base_model = "zhipuai/glm-5v-turbo" +name = "GLM 5V Turbo" +reasoning_options = [] + +[cost] +input = 1.56 +output = 5.2 +cache_read = 0.312 + +[limit] +context = 202_752 diff --git a/providers/aimlapi/models/zhipu/glm-5.2.toml b/providers/aimlapi/models/zhipu/glm-5.2.toml new file mode 100644 index 00000000000..60dbb980080 --- /dev/null +++ b/providers/aimlapi/models/zhipu/glm-5.2.toml @@ -0,0 +1,11 @@ +base_model = "zhipuai/glm-5.2" +name = "GLM 5.2" + +[[reasoning_options]] +type = "effort" +values = ["high"] + +[cost] +input = 1.82 +output = 5.72 +cache_read = 0.338 diff --git a/providers/aimlapi/models/zhipu/glm-5.3.toml b/providers/aimlapi/models/zhipu/glm-5.3.toml new file mode 100644 index 00000000000..0a2bd93bba4 --- /dev/null +++ b/providers/aimlapi/models/zhipu/glm-5.3.toml @@ -0,0 +1,14 @@ +base_model = "zhipuai/glm-5.3" +name = "GLM 5.3" + +[[reasoning_options]] +type = "effort" +values = ["low", "high"] + +[cost] +input = 1.82 +output = 5.72 +cache_read = 0.338 + +[limit] +context = 1_024_000 diff --git a/providers/aimlapi/provider.toml b/providers/aimlapi/provider.toml new file mode 100755 index 00000000000..6b7a3f559b9 --- /dev/null +++ b/providers/aimlapi/provider.toml @@ -0,0 +1,5 @@ +name = "AI/ML API" +env = ["AIMLAPI_API_KEY"] +npm = "@ai-sdk/openai-compatible" +api = "https://api.aimlapi.com/v1" +doc = "https://docs.aimlapi.com"