From a0af0c1d829777d3793375c6c9e1e2823ffeeae9 Mon Sep 17 00:00:00 2001 From: RodiumAI Date: Mon, 25 May 2026 09:13:52 +0000 Subject: [PATCH 1/8] Add RodiumAi provider to Models.dev RodiumAi exposes an **OpenAI-compatible** API at `https://api.rodiumai.io/v1`. Model IDs in this PR match the slugs returned by `GET /v1/models` on the live gateway. --- providers/rodiumai/logo.svg | 10 +++++++++ .../anthropic/claude-haiku-4-5-20251001.toml | 21 +++++++++++++++++++ .../models/anthropic/claude-opus-4-7.toml | 21 +++++++++++++++++++ .../models/anthropic/claude-sonnet-4-6.toml | 21 +++++++++++++++++++ providers/rodiumai/models/auto.toml | 19 +++++++++++++++++ providers/rodiumai/models/basic.toml | 19 +++++++++++++++++ .../models/deepseek/deepseek-v4-flash.toml | 20 ++++++++++++++++++ .../models/deepseek/deepseek-v4-pro.toml | 20 ++++++++++++++++++ providers/rodiumai/models/fast.toml | 19 +++++++++++++++++ .../models/google/gemini-2.5-flash.toml | 20 ++++++++++++++++++ .../models/google/gemini-2.5-pro.toml | 20 ++++++++++++++++++ .../models/google/gemini-3.1-pro-preview.toml | 20 ++++++++++++++++++ .../models/google/gemini-3.5-flash.toml | 20 ++++++++++++++++++ providers/rodiumai/models/max.toml | 19 +++++++++++++++++ .../rodiumai/models/openai/gpt-5.4-mini.toml | 20 ++++++++++++++++++ providers/rodiumai/models/openai/gpt-5.4.toml | 20 ++++++++++++++++++ providers/rodiumai/models/openai/gpt-5.5.toml | 20 ++++++++++++++++++ providers/rodiumai/models/openai/o3.toml | 20 ++++++++++++++++++ providers/rodiumai/models/pro.toml | 19 +++++++++++++++++ providers/rodiumai/provider.toml | 5 +++++ 20 files changed, 373 insertions(+) create mode 100644 providers/rodiumai/logo.svg create mode 100644 providers/rodiumai/models/anthropic/claude-haiku-4-5-20251001.toml create mode 100644 providers/rodiumai/models/anthropic/claude-opus-4-7.toml create mode 100644 providers/rodiumai/models/anthropic/claude-sonnet-4-6.toml create mode 100644 providers/rodiumai/models/auto.toml create mode 100644 providers/rodiumai/models/basic.toml create mode 100644 providers/rodiumai/models/deepseek/deepseek-v4-flash.toml create mode 100644 providers/rodiumai/models/deepseek/deepseek-v4-pro.toml create mode 100644 providers/rodiumai/models/fast.toml create mode 100644 providers/rodiumai/models/google/gemini-2.5-flash.toml create mode 100644 providers/rodiumai/models/google/gemini-2.5-pro.toml create mode 100644 providers/rodiumai/models/google/gemini-3.1-pro-preview.toml create mode 100644 providers/rodiumai/models/google/gemini-3.5-flash.toml create mode 100644 providers/rodiumai/models/max.toml create mode 100644 providers/rodiumai/models/openai/gpt-5.4-mini.toml create mode 100644 providers/rodiumai/models/openai/gpt-5.4.toml create mode 100644 providers/rodiumai/models/openai/gpt-5.5.toml create mode 100644 providers/rodiumai/models/openai/o3.toml create mode 100644 providers/rodiumai/models/pro.toml create mode 100644 providers/rodiumai/provider.toml diff --git a/providers/rodiumai/logo.svg b/providers/rodiumai/logo.svg new file mode 100644 index 0000000000..a152e6d25f --- /dev/null +++ b/providers/rodiumai/logo.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/providers/rodiumai/models/anthropic/claude-haiku-4-5-20251001.toml b/providers/rodiumai/models/anthropic/claude-haiku-4-5-20251001.toml new file mode 100644 index 0000000000..48016c5f21 --- /dev/null +++ b/providers/rodiumai/models/anthropic/claude-haiku-4-5-20251001.toml @@ -0,0 +1,21 @@ +name = "Claude Haiku 4.5" +family = "claude-haiku" +attachment = true +reasoning = true +temperature = true +tool_call = true +open_weights = false + +[cost] +input = 1 +output = 5 +cache_read = 0.1 +cache_write = 1.25 + +[limit] +context = 200_000 +output = 64_000 + +[modalities] +input = ["text","image","pdf"] +output = ["text"] diff --git a/providers/rodiumai/models/anthropic/claude-opus-4-7.toml b/providers/rodiumai/models/anthropic/claude-opus-4-7.toml new file mode 100644 index 0000000000..d4796c271e --- /dev/null +++ b/providers/rodiumai/models/anthropic/claude-opus-4-7.toml @@ -0,0 +1,21 @@ +name = "Claude Opus 4.7" +family = "claude-opus" +attachment = true +reasoning = true +temperature = true +tool_call = true +open_weights = false + +[cost] +input = 5 +output = 25 +cache_read = 0.5 +cache_write = 6.25 + +[limit] +context = 1_000_000 +output = 128_000 + +[modalities] +input = ["text","image","pdf"] +output = ["text"] diff --git a/providers/rodiumai/models/anthropic/claude-sonnet-4-6.toml b/providers/rodiumai/models/anthropic/claude-sonnet-4-6.toml new file mode 100644 index 0000000000..05bd7e2009 --- /dev/null +++ b/providers/rodiumai/models/anthropic/claude-sonnet-4-6.toml @@ -0,0 +1,21 @@ +name = "Claude Sonnet 4.6" +family = "claude-sonnet" +attachment = true +reasoning = true +temperature = true +tool_call = true +open_weights = false + +[cost] +input = 3 +output = 15 +cache_read = 0.3 +cache_write = 3.75 + +[limit] +context = 1_000_000 +output = 64_000 + +[modalities] +input = ["text","image","pdf"] +output = ["text"] diff --git a/providers/rodiumai/models/auto.toml b/providers/rodiumai/models/auto.toml new file mode 100644 index 0000000000..85b065cb8a --- /dev/null +++ b/providers/rodiumai/models/auto.toml @@ -0,0 +1,19 @@ +name = "Auto (RodiumAi Smart Routing)" +family = "rodium-smart" +attachment = false +reasoning = false +temperature = true +tool_call = true +open_weights = false + +[cost] +input = 0.3 +output = 2.5 + +[limit] +context = 1_000_000 +output = 32_000 + +[modalities] +input = ["text"] +output = ["text"] diff --git a/providers/rodiumai/models/basic.toml b/providers/rodiumai/models/basic.toml new file mode 100644 index 0000000000..0cfc39565f --- /dev/null +++ b/providers/rodiumai/models/basic.toml @@ -0,0 +1,19 @@ +name = "Basic" +family = "rodium-smart" +attachment = false +reasoning = false +temperature = true +tool_call = true +open_weights = false + +[cost] +input = 0.05 +output = 0.08 + +[limit] +context = 128_000 +output = 8_192 + +[modalities] +input = ["text"] +output = ["text"] diff --git a/providers/rodiumai/models/deepseek/deepseek-v4-flash.toml b/providers/rodiumai/models/deepseek/deepseek-v4-flash.toml new file mode 100644 index 0000000000..833c652273 --- /dev/null +++ b/providers/rodiumai/models/deepseek/deepseek-v4-flash.toml @@ -0,0 +1,20 @@ +name = "DeepSeek V4 Flash" +family = "deepseek" +attachment = false +reasoning = true +temperature = true +tool_call = true +open_weights = false + +[cost] +input = 0.14 +output = 0.28 +cache_read = 0.0028 + +[limit] +context = 1_000_000 +output = 384_000 + +[modalities] +input = ["text"] +output = ["text"] diff --git a/providers/rodiumai/models/deepseek/deepseek-v4-pro.toml b/providers/rodiumai/models/deepseek/deepseek-v4-pro.toml new file mode 100644 index 0000000000..a9131934b6 --- /dev/null +++ b/providers/rodiumai/models/deepseek/deepseek-v4-pro.toml @@ -0,0 +1,20 @@ +name = "DeepSeek V4 Pro" +family = "deepseek" +attachment = false +reasoning = true +temperature = true +tool_call = true +open_weights = false + +[cost] +input = 0.435 +output = 0.87 +cache_read = 0.003625 + +[limit] +context = 1_000_000 +output = 384_000 + +[modalities] +input = ["text"] +output = ["text"] diff --git a/providers/rodiumai/models/fast.toml b/providers/rodiumai/models/fast.toml new file mode 100644 index 0000000000..6fd8edb82c --- /dev/null +++ b/providers/rodiumai/models/fast.toml @@ -0,0 +1,19 @@ +name = "Fast" +family = "rodium-smart" +attachment = false +reasoning = false +temperature = true +tool_call = true +open_weights = false + +[cost] +input = 0.11 +output = 0.34 + +[limit] +context = 128_000 +output = 16_384 + +[modalities] +input = ["text"] +output = ["text"] diff --git a/providers/rodiumai/models/google/gemini-2.5-flash.toml b/providers/rodiumai/models/google/gemini-2.5-flash.toml new file mode 100644 index 0000000000..3f640c6df1 --- /dev/null +++ b/providers/rodiumai/models/google/gemini-2.5-flash.toml @@ -0,0 +1,20 @@ +name = "Gemini 2.5 Flash" +family = "gemini" +attachment = true +reasoning = true +temperature = true +tool_call = true +open_weights = false + +[cost] +input = 0.3 +output = 2.5 +cache_read = 0.3 + +[limit] +context = 1_000_000 +output = 65_536 + +[modalities] +input = ["text","image","video","audio","pdf"] +output = ["text"] diff --git a/providers/rodiumai/models/google/gemini-2.5-pro.toml b/providers/rodiumai/models/google/gemini-2.5-pro.toml new file mode 100644 index 0000000000..333f0b6ab5 --- /dev/null +++ b/providers/rodiumai/models/google/gemini-2.5-pro.toml @@ -0,0 +1,20 @@ +name = "Gemini 2.5 Pro" +family = "gemini" +attachment = true +reasoning = true +temperature = true +tool_call = true +open_weights = false + +[cost] +input = 1.25 +output = 10 +cache_read = 0.31 + +[limit] +context = 1_000_000 +output = 65_536 + +[modalities] +input = ["text","image","video","audio","pdf"] +output = ["text"] diff --git a/providers/rodiumai/models/google/gemini-3.1-pro-preview.toml b/providers/rodiumai/models/google/gemini-3.1-pro-preview.toml new file mode 100644 index 0000000000..87aa74c48f --- /dev/null +++ b/providers/rodiumai/models/google/gemini-3.1-pro-preview.toml @@ -0,0 +1,20 @@ +name = "Gemini 3.1 Pro Preview" +family = "gemini" +attachment = true +reasoning = true +temperature = true +tool_call = true +open_weights = false + +[cost] +input = 2 +output = 12 +cache_read = 0.2 + +[limit] +context = 2_000_000 +output = 65_536 + +[modalities] +input = ["text","image","video","audio","pdf"] +output = ["text"] diff --git a/providers/rodiumai/models/google/gemini-3.5-flash.toml b/providers/rodiumai/models/google/gemini-3.5-flash.toml new file mode 100644 index 0000000000..2170820f65 --- /dev/null +++ b/providers/rodiumai/models/google/gemini-3.5-flash.toml @@ -0,0 +1,20 @@ +name = "Gemini 3.5 Flash" +family = "gemini" +attachment = true +reasoning = true +temperature = true +tool_call = true +open_weights = false + +[cost] +input = 1.5 +output = 9 +cache_read = 0.15 + +[limit] +context = 1_000_000 +output = 65_536 + +[modalities] +input = ["text","image","video","audio","pdf"] +output = ["text"] diff --git a/providers/rodiumai/models/max.toml b/providers/rodiumai/models/max.toml new file mode 100644 index 0000000000..162c07d934 --- /dev/null +++ b/providers/rodiumai/models/max.toml @@ -0,0 +1,19 @@ +name = "Max" +family = "rodium-smart" +attachment = false +reasoning = true +temperature = true +tool_call = true +open_weights = false + +[cost] +input = 3 +output = 15 + +[limit] +context = 200_000 +output = 16_384 + +[modalities] +input = ["text"] +output = ["text"] diff --git a/providers/rodiumai/models/openai/gpt-5.4-mini.toml b/providers/rodiumai/models/openai/gpt-5.4-mini.toml new file mode 100644 index 0000000000..30529943d1 --- /dev/null +++ b/providers/rodiumai/models/openai/gpt-5.4-mini.toml @@ -0,0 +1,20 @@ +name = "GPT-5.4 Mini" +family = "gpt" +attachment = true +reasoning = false +temperature = true +tool_call = true +open_weights = false + +[cost] +input = 0.75 +output = 4.5 +cache_read = 0.075 + +[limit] +context = 400_000 +output = 16_384 + +[modalities] +input = ["text","image","pdf"] +output = ["text"] diff --git a/providers/rodiumai/models/openai/gpt-5.4.toml b/providers/rodiumai/models/openai/gpt-5.4.toml new file mode 100644 index 0000000000..61213e3fac --- /dev/null +++ b/providers/rodiumai/models/openai/gpt-5.4.toml @@ -0,0 +1,20 @@ +name = "GPT-5.4" +family = "gpt" +attachment = true +reasoning = false +temperature = true +tool_call = true +open_weights = false + +[cost] +input = 2.5 +output = 15 +cache_read = 0.25 + +[limit] +context = 1_000_000 +output = 32_768 + +[modalities] +input = ["text","image","pdf"] +output = ["text"] diff --git a/providers/rodiumai/models/openai/gpt-5.5.toml b/providers/rodiumai/models/openai/gpt-5.5.toml new file mode 100644 index 0000000000..00ffb7950d --- /dev/null +++ b/providers/rodiumai/models/openai/gpt-5.5.toml @@ -0,0 +1,20 @@ +name = "GPT-5.5" +family = "gpt" +attachment = true +reasoning = false +temperature = true +tool_call = true +open_weights = false + +[cost] +input = 5 +output = 30 +cache_read = 0.5 + +[limit] +context = 1_050_000 +output = 128_000 + +[modalities] +input = ["text","image","pdf"] +output = ["text"] diff --git a/providers/rodiumai/models/openai/o3.toml b/providers/rodiumai/models/openai/o3.toml new file mode 100644 index 0000000000..7fa0220bc6 --- /dev/null +++ b/providers/rodiumai/models/openai/o3.toml @@ -0,0 +1,20 @@ +name = "o3" +family = "o-series" +attachment = true +reasoning = true +temperature = true +tool_call = true +open_weights = false + +[cost] +input = 2 +output = 8 +cache_read = 0.5 + +[limit] +context = 200_000 +output = 100_000 + +[modalities] +input = ["text","image","pdf"] +output = ["text"] diff --git a/providers/rodiumai/models/pro.toml b/providers/rodiumai/models/pro.toml new file mode 100644 index 0000000000..6863980119 --- /dev/null +++ b/providers/rodiumai/models/pro.toml @@ -0,0 +1,19 @@ +name = "Pro" +family = "rodium-smart" +attachment = false +reasoning = true +temperature = true +tool_call = true +open_weights = false + +[cost] +input = 0.3 +output = 2.5 + +[limit] +context = 1_000_000 +output = 32_000 + +[modalities] +input = ["text"] +output = ["text"] diff --git a/providers/rodiumai/provider.toml b/providers/rodiumai/provider.toml new file mode 100644 index 0000000000..05ddb06f62 --- /dev/null +++ b/providers/rodiumai/provider.toml @@ -0,0 +1,5 @@ +name = "RodiumAi" +env = ["RODIUMAI_API_KEY"] +npm = "@ai-sdk/openai-compatible" +api = "https://api.rodiumai.io/v1" +doc = "https://rodiumai.io/docs" From 1e9e1b217eb847b413080e073ac4313e0995fc14 Mon Sep 17 00:00:00 2001 From: RodiumAI Date: Mon, 25 May 2026 09:29:07 +0000 Subject: [PATCH 2/8] Edit logo.svg --- providers/rodiumai/logo.svg | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/providers/rodiumai/logo.svg b/providers/rodiumai/logo.svg index a152e6d25f..c9fcae145a 100644 --- a/providers/rodiumai/logo.svg +++ b/providers/rodiumai/logo.svg @@ -1,10 +1 @@ - - - - - - - - - - + \ No newline at end of file From 308887d214d79b25e4324f0de0bd531481f49ec1 Mon Sep 17 00:00:00 2001 From: RodiumAI Date: Mon, 25 May 2026 22:52:52 +0000 Subject: [PATCH 3/8] Update family.ts --- packages/core/src/family.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/core/src/family.ts b/packages/core/src/family.ts index f6ad3a08da..fbfb644483 100644 --- a/packages/core/src/family.ts +++ b/packages/core/src/family.ts @@ -337,6 +337,9 @@ export const ModelFamilyValues = [ "auto", "model-router", + // RodiumAi smart routing tiers + "rodium-smart", + // V0 "v0", From 3a276f6cd4c58636040bae7c869d9a157e89c16a Mon Sep 17 00:00:00 2001 From: RodiumAI Date: Mon, 25 May 2026 22:55:33 +0000 Subject: [PATCH 4/8] add: rodiumai provider Add RodiumAi as an OpenAI-compatible gateway (api.rodiumai.io) with smart routing tiers (auto, fast, basic, pro, max) and proxied upstream models. Register the rodium-smart model family and add required release_date and last_updated fields so bun validate passes in CI. --- providers/rodiumai/models/auto.toml | 2 ++ providers/rodiumai/models/basic.toml | 2 ++ providers/rodiumai/models/fast.toml | 2 ++ providers/rodiumai/models/max.toml | 2 ++ providers/rodiumai/models/pro.toml | 2 ++ 5 files changed, 10 insertions(+) diff --git a/providers/rodiumai/models/auto.toml b/providers/rodiumai/models/auto.toml index 85b065cb8a..a115d566d5 100644 --- a/providers/rodiumai/models/auto.toml +++ b/providers/rodiumai/models/auto.toml @@ -1,5 +1,7 @@ name = "Auto (RodiumAi Smart Routing)" family = "rodium-smart" +release_date = "2026-05-25" +last_updated = "2026-05-25" attachment = false reasoning = false temperature = true diff --git a/providers/rodiumai/models/basic.toml b/providers/rodiumai/models/basic.toml index 0cfc39565f..e49d6158f1 100644 --- a/providers/rodiumai/models/basic.toml +++ b/providers/rodiumai/models/basic.toml @@ -1,5 +1,7 @@ name = "Basic" family = "rodium-smart" +release_date = "2026-05-25" +last_updated = "2026-05-25" attachment = false reasoning = false temperature = true diff --git a/providers/rodiumai/models/fast.toml b/providers/rodiumai/models/fast.toml index 6fd8edb82c..c968b176f9 100644 --- a/providers/rodiumai/models/fast.toml +++ b/providers/rodiumai/models/fast.toml @@ -1,5 +1,7 @@ name = "Fast" family = "rodium-smart" +release_date = "2026-05-25" +last_updated = "2026-05-25" attachment = false reasoning = false temperature = true diff --git a/providers/rodiumai/models/max.toml b/providers/rodiumai/models/max.toml index 162c07d934..e5ada9ef8d 100644 --- a/providers/rodiumai/models/max.toml +++ b/providers/rodiumai/models/max.toml @@ -1,5 +1,7 @@ name = "Max" family = "rodium-smart" +release_date = "2026-05-25" +last_updated = "2026-05-25" attachment = false reasoning = true temperature = true diff --git a/providers/rodiumai/models/pro.toml b/providers/rodiumai/models/pro.toml index 6863980119..aa86ca2170 100644 --- a/providers/rodiumai/models/pro.toml +++ b/providers/rodiumai/models/pro.toml @@ -1,5 +1,7 @@ name = "Pro" family = "rodium-smart" +release_date = "2026-05-25" +last_updated = "2026-05-25" attachment = false reasoning = true temperature = true From 5f1e58a22c2d3efc8a2fea4332ae61f9b4a053f1 Mon Sep 17 00:00:00 2001 From: RodiumAI Date: Mon, 25 May 2026 23:01:11 +0000 Subject: [PATCH 5/8] put: rodiumai provider --- .../rodiumai/models/anthropic/claude-haiku-4-5-20251001.toml | 2 ++ providers/rodiumai/models/anthropic/claude-opus-4-7.toml | 2 ++ providers/rodiumai/models/anthropic/claude-sonnet-4-6.toml | 2 ++ providers/rodiumai/models/deepseek/deepseek-v4-flash.toml | 2 ++ providers/rodiumai/models/deepseek/deepseek-v4-pro.toml | 2 ++ providers/rodiumai/models/google/gemini-2.5-flash.toml | 2 ++ providers/rodiumai/models/google/gemini-2.5-pro.toml | 2 ++ providers/rodiumai/models/google/gemini-3.1-pro-preview.toml | 2 ++ providers/rodiumai/models/google/gemini-3.5-flash.toml | 2 ++ providers/rodiumai/models/openai/gpt-5.4-mini.toml | 2 ++ providers/rodiumai/models/openai/gpt-5.4.toml | 2 ++ providers/rodiumai/models/openai/gpt-5.5.toml | 2 ++ providers/rodiumai/models/openai/o3.toml | 4 +++- 13 files changed, 27 insertions(+), 1 deletion(-) diff --git a/providers/rodiumai/models/anthropic/claude-haiku-4-5-20251001.toml b/providers/rodiumai/models/anthropic/claude-haiku-4-5-20251001.toml index 48016c5f21..d69213c8a2 100644 --- a/providers/rodiumai/models/anthropic/claude-haiku-4-5-20251001.toml +++ b/providers/rodiumai/models/anthropic/claude-haiku-4-5-20251001.toml @@ -1,5 +1,7 @@ name = "Claude Haiku 4.5" family = "claude-haiku" +release_date = "2025-10-15" +last_updated = "2025-10-15" attachment = true reasoning = true temperature = true diff --git a/providers/rodiumai/models/anthropic/claude-opus-4-7.toml b/providers/rodiumai/models/anthropic/claude-opus-4-7.toml index d4796c271e..2ed191a6fa 100644 --- a/providers/rodiumai/models/anthropic/claude-opus-4-7.toml +++ b/providers/rodiumai/models/anthropic/claude-opus-4-7.toml @@ -1,5 +1,7 @@ name = "Claude Opus 4.7" family = "claude-opus" +release_date = "2026-04-16" +last_updated = "2026-04-16" attachment = true reasoning = true temperature = true diff --git a/providers/rodiumai/models/anthropic/claude-sonnet-4-6.toml b/providers/rodiumai/models/anthropic/claude-sonnet-4-6.toml index 05bd7e2009..b9f4998c1c 100644 --- a/providers/rodiumai/models/anthropic/claude-sonnet-4-6.toml +++ b/providers/rodiumai/models/anthropic/claude-sonnet-4-6.toml @@ -1,5 +1,7 @@ name = "Claude Sonnet 4.6" family = "claude-sonnet" +release_date = "2026-02-17" +last_updated = "2026-03-13" attachment = true reasoning = true temperature = true diff --git a/providers/rodiumai/models/deepseek/deepseek-v4-flash.toml b/providers/rodiumai/models/deepseek/deepseek-v4-flash.toml index 833c652273..a2bf327940 100644 --- a/providers/rodiumai/models/deepseek/deepseek-v4-flash.toml +++ b/providers/rodiumai/models/deepseek/deepseek-v4-flash.toml @@ -1,5 +1,7 @@ name = "DeepSeek V4 Flash" family = "deepseek" +release_date = "2026-04-24" +last_updated = "2026-04-24" attachment = false reasoning = true temperature = true diff --git a/providers/rodiumai/models/deepseek/deepseek-v4-pro.toml b/providers/rodiumai/models/deepseek/deepseek-v4-pro.toml index a9131934b6..bb453ae348 100644 --- a/providers/rodiumai/models/deepseek/deepseek-v4-pro.toml +++ b/providers/rodiumai/models/deepseek/deepseek-v4-pro.toml @@ -1,5 +1,7 @@ name = "DeepSeek V4 Pro" family = "deepseek" +release_date = "2026-04-24" +last_updated = "2026-04-24" attachment = false reasoning = true temperature = true diff --git a/providers/rodiumai/models/google/gemini-2.5-flash.toml b/providers/rodiumai/models/google/gemini-2.5-flash.toml index 3f640c6df1..5912743535 100644 --- a/providers/rodiumai/models/google/gemini-2.5-flash.toml +++ b/providers/rodiumai/models/google/gemini-2.5-flash.toml @@ -1,5 +1,7 @@ name = "Gemini 2.5 Flash" family = "gemini" +release_date = "2025-03-20" +last_updated = "2025-06-05" attachment = true reasoning = true temperature = true diff --git a/providers/rodiumai/models/google/gemini-2.5-pro.toml b/providers/rodiumai/models/google/gemini-2.5-pro.toml index 333f0b6ab5..ff0ccff109 100644 --- a/providers/rodiumai/models/google/gemini-2.5-pro.toml +++ b/providers/rodiumai/models/google/gemini-2.5-pro.toml @@ -1,5 +1,7 @@ name = "Gemini 2.5 Pro" family = "gemini" +release_date = "2025-03-20" +last_updated = "2025-06-05" attachment = true reasoning = true temperature = true diff --git a/providers/rodiumai/models/google/gemini-3.1-pro-preview.toml b/providers/rodiumai/models/google/gemini-3.1-pro-preview.toml index 87aa74c48f..70cf94b59b 100644 --- a/providers/rodiumai/models/google/gemini-3.1-pro-preview.toml +++ b/providers/rodiumai/models/google/gemini-3.1-pro-preview.toml @@ -1,5 +1,7 @@ name = "Gemini 3.1 Pro Preview" family = "gemini" +release_date = "2026-02-19" +last_updated = "2026-02-19" attachment = true reasoning = true temperature = true diff --git a/providers/rodiumai/models/google/gemini-3.5-flash.toml b/providers/rodiumai/models/google/gemini-3.5-flash.toml index 2170820f65..398ff1c58c 100644 --- a/providers/rodiumai/models/google/gemini-3.5-flash.toml +++ b/providers/rodiumai/models/google/gemini-3.5-flash.toml @@ -1,5 +1,7 @@ name = "Gemini 3.5 Flash" family = "gemini" +release_date = "2026-05-19" +last_updated = "2026-05-19" attachment = true reasoning = true temperature = true diff --git a/providers/rodiumai/models/openai/gpt-5.4-mini.toml b/providers/rodiumai/models/openai/gpt-5.4-mini.toml index 30529943d1..b2099a55d3 100644 --- a/providers/rodiumai/models/openai/gpt-5.4-mini.toml +++ b/providers/rodiumai/models/openai/gpt-5.4-mini.toml @@ -1,5 +1,7 @@ name = "GPT-5.4 Mini" family = "gpt" +release_date = "2026-03-17" +last_updated = "2026-03-17" attachment = true reasoning = false temperature = true diff --git a/providers/rodiumai/models/openai/gpt-5.4.toml b/providers/rodiumai/models/openai/gpt-5.4.toml index 61213e3fac..74b419f58f 100644 --- a/providers/rodiumai/models/openai/gpt-5.4.toml +++ b/providers/rodiumai/models/openai/gpt-5.4.toml @@ -1,5 +1,7 @@ name = "GPT-5.4" family = "gpt" +release_date = "2026-03-05" +last_updated = "2026-03-05" attachment = true reasoning = false temperature = true diff --git a/providers/rodiumai/models/openai/gpt-5.5.toml b/providers/rodiumai/models/openai/gpt-5.5.toml index 00ffb7950d..2d055bebda 100644 --- a/providers/rodiumai/models/openai/gpt-5.5.toml +++ b/providers/rodiumai/models/openai/gpt-5.5.toml @@ -1,5 +1,7 @@ name = "GPT-5.5" family = "gpt" +release_date = "2026-04-23" +last_updated = "2026-04-23" attachment = true reasoning = false temperature = true diff --git a/providers/rodiumai/models/openai/o3.toml b/providers/rodiumai/models/openai/o3.toml index 7fa0220bc6..b3b80a35e9 100644 --- a/providers/rodiumai/models/openai/o3.toml +++ b/providers/rodiumai/models/openai/o3.toml @@ -1,5 +1,7 @@ name = "o3" -family = "o-series" +family = "o" +release_date = "2025-04-16" +last_updated = "2025-04-16" attachment = true reasoning = true temperature = true From 5d3a76fd0cfb5dec0e6b1630ae7f87c6b230b783 Mon Sep 17 00:00:00 2001 From: Docteur-Parfait Date: Fri, 12 Jun 2026 00:58:30 +0000 Subject: [PATCH 6/8] feat(rodiumai): add sync provider with base_model and reasoning_options Add RodiumAi to bun models:sync from GET https://api.rodiumai.io/v1/models. Sync coding/chat models only (tools + text output; excludes embeddings, image, video). Vendor slugs factor canonical metadata via base_model; every model declares reasoning_options. Includes five smart-routing profiles and rodiumai-sync unit tests. --- package.json | 1 + packages/core/src/sync/index.ts | 5 +- packages/core/src/sync/providers/rodiumai.ts | 365 ++++++++++++++++++ packages/core/test/rodiumai-sync.test.ts | 111 ++++++ providers/rodiumai/logo.svg | 11 +- .../models/anthropic/claude-fable-5.toml | 8 + .../anthropic/claude-haiku-4-5-20251001.toml | 30 +- .../anthropic/claude-opus-4-1-20250805.toml | 5 + .../anthropic/claude-opus-4-5-20251101.toml | 9 + .../models/anthropic/claude-opus-4-6.toml | 5 + .../models/anthropic/claude-opus-4-7.toml | 27 +- .../models/anthropic/claude-opus-4-8.toml | 6 + .../anthropic/claude-sonnet-4-5-20250929.toml | 14 + .../models/anthropic/claude-sonnet-4-6.toml | 32 +- providers/rodiumai/models/auto.toml | 7 +- providers/rodiumai/models/basic.toml | 5 +- .../models/deepseek/deepseek-v3.2.toml | 19 + .../models/deepseek/deepseek-v4-flash.toml | 25 +- .../models/deepseek/deepseek-v4-pro.toml | 25 +- providers/rodiumai/models/fast.toml | 5 +- .../models/google/gemini-2.5-flash-lite.toml | 8 + .../models/google/gemini-2.5-flash.toml | 23 +- .../models/google/gemini-2.5-pro.toml | 23 +- .../models/google/gemini-3.1-flash-lite.toml | 8 + .../models/google/gemini-3.1-pro-preview.toml | 23 +- .../models/google/gemini-3.5-flash.toml | 23 +- providers/rodiumai/models/max.toml | 5 +- .../models/meta/llama-3.3-70b-instruct.toml | 9 + .../meta/llama-4-maverick-17b-128e.toml | 12 + .../rodiumai/models/minimax/minimax-m2-5.toml | 13 + .../rodiumai/models/minimax/minimax-m2-7.toml | 13 + .../models/mistral/mistral-large-3.toml | 9 + .../models/moonshot-ai/kimi-k2.5.toml | 8 + .../models/moonshot-ai/kimi-k2.6.toml | 6 + .../rodiumai/models/openai/gpt-4.1-mini.toml | 11 + .../rodiumai/models/openai/gpt-4.1-nano.toml | 8 + providers/rodiumai/models/openai/gpt-4.1.toml | 6 + .../rodiumai/models/openai/gpt-4o-mini.toml | 7 + providers/rodiumai/models/openai/gpt-4o.toml | 7 + .../rodiumai/models/openai/gpt-5-mini.toml | 9 + .../rodiumai/models/openai/gpt-5-nano.toml | 9 + .../rodiumai/models/openai/gpt-5-pro.toml | 9 + .../rodiumai/models/openai/gpt-5.3-codex.toml | 12 + .../rodiumai/models/openai/gpt-5.4-mini.toml | 24 +- .../rodiumai/models/openai/gpt-5.4-nano.toml | 10 + .../rodiumai/models/openai/gpt-5.4-pro.toml | 14 + providers/rodiumai/models/openai/gpt-5.4.toml | 23 +- .../rodiumai/models/openai/gpt-5.5-pro.toml | 5 + providers/rodiumai/models/openai/gpt-5.5.toml | 23 +- providers/rodiumai/models/openai/gpt-5.toml | 9 + providers/rodiumai/models/openai/o3-mini.toml | 4 + providers/rodiumai/models/openai/o3-pro.toml | 8 + providers/rodiumai/models/openai/o3.toml | 24 +- providers/rodiumai/models/openai/o4-mini.toml | 4 + providers/rodiumai/models/pro.toml | 5 +- .../xai/grok-4-1-fast-non-reasoning.toml | 19 + .../models/xai/grok-4-1-fast-reasoning.toml | 19 + .../models/xai/grok-4-20-non-reasoning.toml | 11 + .../models/xai/grok-4-20-reasoning.toml | 11 + providers/rodiumai/models/xai/grok-4.3.toml | 10 + sync.md | 12 + 61 files changed, 938 insertions(+), 273 deletions(-) create mode 100644 packages/core/src/sync/providers/rodiumai.ts create mode 100644 packages/core/test/rodiumai-sync.test.ts create mode 100644 providers/rodiumai/models/anthropic/claude-fable-5.toml create mode 100644 providers/rodiumai/models/anthropic/claude-opus-4-1-20250805.toml create mode 100644 providers/rodiumai/models/anthropic/claude-opus-4-5-20251101.toml create mode 100644 providers/rodiumai/models/anthropic/claude-opus-4-6.toml create mode 100644 providers/rodiumai/models/anthropic/claude-opus-4-8.toml create mode 100644 providers/rodiumai/models/anthropic/claude-sonnet-4-5-20250929.toml create mode 100644 providers/rodiumai/models/deepseek/deepseek-v3.2.toml create mode 100644 providers/rodiumai/models/google/gemini-2.5-flash-lite.toml create mode 100644 providers/rodiumai/models/google/gemini-3.1-flash-lite.toml create mode 100644 providers/rodiumai/models/meta/llama-3.3-70b-instruct.toml create mode 100644 providers/rodiumai/models/meta/llama-4-maverick-17b-128e.toml create mode 100644 providers/rodiumai/models/minimax/minimax-m2-5.toml create mode 100644 providers/rodiumai/models/minimax/minimax-m2-7.toml create mode 100644 providers/rodiumai/models/mistral/mistral-large-3.toml create mode 100644 providers/rodiumai/models/moonshot-ai/kimi-k2.5.toml create mode 100644 providers/rodiumai/models/moonshot-ai/kimi-k2.6.toml create mode 100644 providers/rodiumai/models/openai/gpt-4.1-mini.toml create mode 100644 providers/rodiumai/models/openai/gpt-4.1-nano.toml create mode 100644 providers/rodiumai/models/openai/gpt-4.1.toml create mode 100644 providers/rodiumai/models/openai/gpt-4o-mini.toml create mode 100644 providers/rodiumai/models/openai/gpt-4o.toml create mode 100644 providers/rodiumai/models/openai/gpt-5-mini.toml create mode 100644 providers/rodiumai/models/openai/gpt-5-nano.toml create mode 100644 providers/rodiumai/models/openai/gpt-5-pro.toml create mode 100644 providers/rodiumai/models/openai/gpt-5.3-codex.toml create mode 100644 providers/rodiumai/models/openai/gpt-5.4-nano.toml create mode 100644 providers/rodiumai/models/openai/gpt-5.4-pro.toml create mode 100644 providers/rodiumai/models/openai/gpt-5.5-pro.toml create mode 100644 providers/rodiumai/models/openai/gpt-5.toml create mode 100644 providers/rodiumai/models/openai/o3-mini.toml create mode 100644 providers/rodiumai/models/openai/o3-pro.toml create mode 100644 providers/rodiumai/models/openai/o4-mini.toml create mode 100644 providers/rodiumai/models/xai/grok-4-1-fast-non-reasoning.toml create mode 100644 providers/rodiumai/models/xai/grok-4-1-fast-reasoning.toml create mode 100644 providers/rodiumai/models/xai/grok-4-20-non-reasoning.toml create mode 100644 providers/rodiumai/models/xai/grok-4-20-reasoning.toml create mode 100644 providers/rodiumai/models/xai/grok-4.3.toml diff --git a/package.json b/package.json index aef2c3d8e5..214cbd6b21 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "databricks:generate": "bun ./packages/core/script/generate-databricks.ts", "helicone:generate": "bun ./packages/core/script/generate-helicone.ts", "venice:sync": "bun ./packages/core/script/sync-models.ts venice", + "rodiumai:sync": "bun ./packages/core/script/sync-models.ts rodiumai", "vercel:generate": "bun ./packages/core/script/sync-models.ts vercel", "wandb:generate": "bun ./packages/core/script/generate-wandb.ts", "digitalocean:generate": "bun ./packages/core/script/generate-digitalocean.ts", diff --git a/packages/core/src/sync/index.ts b/packages/core/src/sync/index.ts index 4cb51a923b..f84247206d 100644 --- a/packages/core/src/sync/index.ts +++ b/packages/core/src/sync/index.ts @@ -11,6 +11,7 @@ import { openrouter } from "./providers/openrouter.js"; import { ovhcloud } from "./providers/ovhcloud.js"; import { vercel } from "./providers/vercel.js"; import { venice } from "./providers/venice.js"; +import { rodiumai } from "./providers/rodiumai.js"; import { xai } from "./providers/xai.js"; const ExistingModelType = AuthoredModelShape.partial() @@ -84,6 +85,7 @@ export const providers: { ovhcloud: SyncProvider; vercel: SyncProvider; venice: SyncProvider; + rodiumai: SyncProvider; xai: SyncProvider; } = { baseten, @@ -93,11 +95,12 @@ export const providers: { ovhcloud, vercel, venice, + rodiumai, xai, }; export const groups = { - aggregators: ["openrouter", "vercel"], + aggregators: ["openrouter", "rodiumai", "vercel"], cloudflare: ["cloudflare-workers-ai"], direct: ["baseten", "google", "ovhcloud", "venice", "xai"], } as const; diff --git a/packages/core/src/sync/providers/rodiumai.ts b/packages/core/src/sync/providers/rodiumai.ts new file mode 100644 index 0000000000..54336046fd --- /dev/null +++ b/packages/core/src/sync/providers/rodiumai.ts @@ -0,0 +1,365 @@ +import { readdirSync } from "node:fs"; +import path from "node:path"; +import { z } from "zod"; + +import { ModelFamilyValues } from "../../family.js"; +import type { ExistingModel, SyncProvider, SyncedFullModel, SyncedModel } from "../index.js"; +import { factorBaseModel, resolveCanonicalBaseModel } from "./openrouter.js"; + +const API_ENDPOINT = "https://api.rodiumai.io/v1/models"; +const MODELS_DIR = path.join(import.meta.dirname, "..", "..", "..", "..", "..", "models"); + +const EXCLUDED_SLUG_PARTS = [ + "embed", + "embedding", + "veo", + "imagen", + "sora", + "tts", + "whisper", + "dall", + "image-", + "audio", +]; + +const BASE_MODEL_ALIASES: Record = { + "meta/llama-4-maverick-17b-128e": "meta/llama-4-maverick-17b-instruct", + "minimax/minimax-m2-7": "minimax/MiniMax-M2.7", + "minimax/minimax-m2-5": "minimax/MiniMax-M2.5", + "mistral/mistral-large-3": "mistral/mistral-large-latest", + "moonshot-ai/kimi-k2.5": "moonshotai/kimi-k2.5", + "moonshot-ai/kimi-k2.6": "moonshotai/kimi-k2.6", + "xai/grok-4-20-reasoning": "xai/grok-4.20-0309-reasoning", + "xai/grok-4-20-non-reasoning": "xai/grok-4.20-0309-non-reasoning", +}; + +const SMART_PROFILES = [ + { + id: "auto", + name: "Auto (RodiumAI Smart Routing)", + reasoning: false, + cost: { input: 0.3, output: 2.5 }, + limit: { context: 1_000_000, output: 32_000 }, + }, + { + id: "basic", + name: "Basic", + reasoning: false, + cost: { input: 0.05, output: 0.08 }, + limit: { context: 128_000, output: 8192 }, + }, + { + id: "fast", + name: "Fast", + reasoning: false, + cost: { input: 0.11, output: 0.34 }, + limit: { context: 128_000, output: 16_384 }, + }, + { + id: "pro", + name: "Pro", + reasoning: true, + cost: { input: 0.3, output: 2.5 }, + limit: { context: 1_000_000, output: 32_000 }, + }, + { + id: "max", + name: "Max", + reasoning: true, + cost: { input: 3.0, output: 15.0 }, + limit: { context: 200_000, output: 16_384 }, + }, +] as const; + +export const RodiumCapabilities = z.object({ + context_window: z.number().int().nonnegative().nullable().optional(), + max_output_tokens: z.number().int().nonnegative().nullable().optional(), + input_modalities: z.array(z.string()).optional(), + output_modalities: z.array(z.string()).optional(), + supports_streaming: z.boolean().optional(), + supports_tools: z.boolean().optional(), + supports_vision: z.boolean().optional(), + supports_json_mode: z.boolean().optional(), + supports_reasoning: z.boolean().optional(), +}).passthrough(); + +export const RodiumPricing = z.object({ + pricing_unit: z.string().optional(), + per_image: z.string().nullable().optional(), +}).passthrough(); + +export const RodiumApiModel = z.object({ + id: z.string().min(1), + created: z.number(), + rodiumai_display_name: z.string().optional(), + rodiumai_capabilities: RodiumCapabilities.optional(), + rodiumai_pricing: RodiumPricing.optional(), +}).passthrough(); + +export const RodiumResponse = z.object({ + data: z.array(RodiumApiModel), +}).passthrough(); + +export type RodiumApiModel = z.infer; +export type SmartProfile = (typeof SMART_PROFILES)[number]; + +type Modality = "text" | "audio" | "image" | "video" | "pdf"; +type ReasoningOption = NonNullable[number]; + +const metadataFilesByProvider = new Map>(); + +export const rodiumai = { + id: "rodiumai", + name: "RodiumAi", + modelsDir: "providers/rodiumai/models", + async fetchModels() { + const response = await fetch(API_ENDPOINT); + if (!response.ok) { + throw new Error(`RodiumAi request failed: ${response.status} ${response.statusText}`); + } + return response.json(); + }, + parseModels(raw) { + const data = RodiumResponse.parse(raw).data.filter(isCodingApiModel); + return [...SMART_PROFILES, ...data]; + }, + translateModel(model, context) { + if (isSmartProfile(model)) { + return { + id: model.id, + model: buildSmartProfile(model, context.existing(model.id)), + }; + } + return { + id: model.id, + model: buildRodiumVendorModel(model, context.existing(model.id)), + }; + }, +} satisfies SyncProvider; + +export function isCodingApiModel(model: RodiumApiModel): boolean { + const id = model.id.toLowerCase(); + if (EXCLUDED_SLUG_PARTS.some((part) => id.includes(part))) return false; + + const pricing = model.rodiumai_pricing ?? {}; + if (pricing.per_image) return false; + if (pricing.pricing_unit === "per_image") return false; + + const caps = model.rodiumai_capabilities ?? {}; + const outputs = caps.output_modalities ?? []; + if (!outputs.includes("text")) return false; + if (outputs.includes("video")) return false; + if (caps.supports_tools !== true) return false; + + return true; +} + +function isSmartProfile(model: RodiumApiModel | SmartProfile): model is SmartProfile { + return !("created" in model); +} + +function dateFromTimestamp(timestamp: number) { + return new Date(timestamp * 1000).toISOString().slice(0, 10); +} + +function modalities(values: string[], fallback: Modality[]): Modality[] { + const allowed = new Set(["text", "audio", "image", "video", "pdf"]); + const result = values + .map((value) => value.toLowerCase()) + .map((value) => (value === "document" ? "pdf" : value)) + .filter((value): value is Modality => allowed.has(value as Modality)); + return [...new Set(result.length > 0 ? result : fallback)]; +} + +function inferFamily(modelSlug: string, name: string) { + const target = `${modelSlug} ${name}`.toLowerCase(); + return [...ModelFamilyValues] + .sort((a, b) => b.length - a.length) + .find((family) => { + const value = family.toLowerCase().replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); + if (family === "o") { + return new RegExp(`(^|[^a-z0-9])${value}(?=\\d|$|[^a-z0-9])`).test(target); + } + return new RegExp(`(^|[^a-z0-9])${value}(?=$|[^a-z0-9])`).test(target); + }); +} + +function metadataFileExists(modelID: string) { + const [provider, ...parts] = modelID.split("/"); + if (provider === undefined || parts.length === 0) return false; + let files = metadataFilesByProvider.get(provider); + if (files === undefined) { + try { + files = new Set(readdirSync(path.join(MODELS_DIR, provider))); + } catch { + files = new Set(); + } + metadataFilesByProvider.set(provider, files); + } + return files.has(`${parts.join("/")}.toml`); +} + +export function resolveRodiumBaseModel(apiID: string): string | undefined { + const alias = BASE_MODEL_ALIASES[apiID]; + if (alias !== undefined && metadataFileExists(alias)) return alias; + + const canonical = resolveCanonicalBaseModel(apiID); + if (canonical !== undefined && metadataFileExists(canonical)) return canonical; + + const [brand, ...parts] = apiID.split("/"); + if (brand === undefined || parts.length === 0) return undefined; + const slug = parts.join("/"); + const directCandidates = [ + `${brand}/${slug}`, + brand === "moonshot-ai" ? `moonshotai/${slug}` : undefined, + brand === "minimax" ? `minimax/${slug.replace(/^minimax-m/, "MiniMax-M")}` : undefined, + ].filter((value): value is string => value !== undefined); + + return directCandidates.find((candidate) => metadataFileExists(candidate)); +} + +function defaultReasoningOptions( + baseModel: string | undefined, + reasoning: boolean, + existing: ExistingModel | undefined, +): ReasoningOption[] { + if (existing?.reasoning_options !== undefined) return existing.reasoning_options; + if (!reasoning) return []; + + if (baseModel === "anthropic/claude-fable-5") { + return [{ type: "effort", values: ["low", "medium", "high", "xhigh", "max"] }]; + } + if (baseModel?.startsWith("anthropic/claude-opus-4-8")) { + return [ + { type: "toggle" }, + { type: "effort", values: ["low", "medium", "high", "xhigh", "max"] }, + ]; + } + if (baseModel?.startsWith("anthropic/claude-opus-4-7")) { + return [ + { type: "toggle" }, + { type: "effort", values: ["low", "medium", "high", "xhigh", "max"] }, + ]; + } + if (baseModel?.startsWith("anthropic/claude-opus-4-6")) { + return [ + { type: "toggle" }, + { type: "effort", values: ["low", "medium", "high", "max"] }, + { type: "budget_tokens", min: 1024, max: 127_999 }, + ]; + } + if (baseModel?.startsWith("anthropic/claude-sonnet-4-6")) { + return [ + { type: "toggle" }, + { type: "effort", values: ["low", "medium", "high", "max"] }, + { type: "budget_tokens", min: 1024, max: 127_999 }, + ]; + } + if (baseModel?.startsWith("anthropic/")) { + return [{ type: "toggle" }, { type: "budget_tokens", min: 1024, max: 63_999 }]; + } + + return []; +} + +export function buildSmartProfile( + profile: SmartProfile, + existing: ExistingModel | undefined, + today = new Date().toISOString().slice(0, 10), +): SyncedFullModel { + const releaseDate = existing?.release_date ?? today; + const changed = existing !== undefined && ( + existing.name !== profile.name + || existing.reasoning !== profile.reasoning + || existing.cost?.input !== profile.cost.input + || existing.cost?.output !== profile.cost.output + || existing.limit?.context !== profile.limit.context + || existing.limit?.output !== profile.limit.output + ); + + return { + name: profile.name, + family: "rodium-smart", + release_date: releaseDate, + last_updated: existing === undefined || changed ? today : (existing.last_updated ?? today), + attachment: false, + reasoning: profile.reasoning, + reasoning_options: existing?.reasoning_options ?? [], + temperature: true, + tool_call: true, + open_weights: false, + cost: profile.cost, + limit: profile.limit, + modalities: { input: ["text"], output: ["text"] }, + }; +} + +export function buildRodiumVendorModel( + model: RodiumApiModel, + existing: ExistingModel | undefined, + today = new Date().toISOString().slice(0, 10), +): SyncedModel { + const caps = model.rodiumai_capabilities ?? {}; + const name = model.rodiumai_display_name ?? model.id.split("/").slice(1).join("/") ?? model.id; + const input = modalities(caps.input_modalities ?? ["text"], ["text"]); + const output = modalities(caps.output_modalities ?? ["text"], ["text"]); + const attachment = input.some((value) => value !== "text") || caps.supports_vision === true; + const reasoning = caps.supports_reasoning === true; + const toolCall = caps.supports_tools === true; + const structuredOutput = caps.supports_json_mode === true ? true : undefined; + const releaseDate = existing?.release_date ?? dateFromTimestamp(model.created); + const limit = { + context: caps.context_window ?? existing?.limit?.context ?? 128_000, + input: existing?.limit?.input, + output: caps.max_output_tokens ?? existing?.limit?.output ?? 32_768, + }; + const baseModel = existing?.base_model ?? resolveRodiumBaseModel(model.id); + const reasoningOptions = defaultReasoningOptions(baseModel, reasoning, existing); + const cost = existing?.cost; + const changed = existing !== undefined && ( + existing.name !== name + || existing.reasoning !== reasoning + || existing.tool_call !== toolCall + || existing.attachment !== attachment + || existing.limit?.context !== limit.context + || existing.limit?.output !== limit.output + ); + + if (baseModel !== undefined) { + return factorBaseModel( + baseModel, + { + name, + attachment, + reasoning, + reasoning_options: reasoningOptions, + temperature: true, + tool_call: toolCall, + structured_output: structuredOutput, + last_updated: existing === undefined || changed ? today : (existing.last_updated ?? today), + cost, + limit, + modalities: { input, output }, + }, + limit, + existing?.base_model === baseModel ? existing.base_model_omit : undefined, + ); + } + + return { + name, + family: existing?.family ?? inferFamily(model.id.split("/").slice(1).join("/"), name), + release_date: releaseDate, + last_updated: existing === undefined || changed ? today : (existing.last_updated ?? today), + attachment, + reasoning, + reasoning_options: reasoningOptions, + temperature: true, + tool_call: toolCall, + structured_output: structuredOutput, + open_weights: false, + cost, + limit, + modalities: { input, output }, + } satisfies SyncedFullModel; +} diff --git a/packages/core/test/rodiumai-sync.test.ts b/packages/core/test/rodiumai-sync.test.ts new file mode 100644 index 0000000000..3b4f93e9a6 --- /dev/null +++ b/packages/core/test/rodiumai-sync.test.ts @@ -0,0 +1,111 @@ +import { expect, test } from "bun:test"; + +import { + buildRodiumVendorModel, + buildSmartProfile, + isCodingApiModel, + resolveRodiumBaseModel, + rodiumai, + RodiumResponse, + type RodiumApiModel, +} from "../src/sync/providers/rodiumai.js"; + +const vendorModel: RodiumApiModel = { + id: "anthropic/claude-sonnet-4-6", + created: 1_773_888_000, + rodiumai_display_name: "Claude Sonnet 4.6", + rodiumai_capabilities: { + context_window: 1_000_000, + max_output_tokens: 64_000, + input_modalities: ["text", "image", "document"], + output_modalities: ["text"], + supports_tools: true, + supports_vision: true, + supports_json_mode: true, + supports_reasoning: true, + }, + rodiumai_pricing: { + pricing_unit: "per_million_tokens", + per_image: null, + }, +}; + +test("RodiumAi resolves canonical base_model metadata", () => { + expect(resolveRodiumBaseModel("anthropic/claude-sonnet-4-6")).toBe("anthropic/claude-sonnet-4-6"); + expect(resolveRodiumBaseModel("moonshot-ai/kimi-k2.5")).toBe("moonshotai/kimi-k2.5"); + expect(resolveRodiumBaseModel("meta/llama-4-maverick-17b-128e")) + .toBe("meta/llama-4-maverick-17b-instruct"); +}); + +test("RodiumAi filters non-coding models", () => { + expect(isCodingApiModel(vendorModel)).toBe(true); + expect(isCodingApiModel({ + ...vendorModel, + id: "openai/text-embedding-3-large", + rodiumai_capabilities: { + output_modalities: ["text"], + supports_tools: false, + }, + })).toBe(false); + expect(isCodingApiModel({ + ...vendorModel, + id: "google/veo-3.1-generate-preview", + rodiumai_capabilities: { + output_modalities: ["video"], + supports_tools: true, + }, + })).toBe(false); +}); + +test("RodiumAi smart profiles declare reasoning_options", () => { + const synced = buildSmartProfile({ + id: "pro", + name: "Pro", + reasoning: true, + cost: { input: 0.3, output: 2.5 }, + limit: { context: 1_000_000, output: 32_000 }, + }, undefined, "2026-06-12"); + + expect(synced.reasoning_options).toEqual([]); + expect(synced.family).toBe("rodium-smart"); +}); + +test("RodiumAi vendor models use base_model and reasoning_options", () => { + const synced = buildRodiumVendorModel(vendorModel, { + cost: { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 }, + limit: { context: 1_000_000, output: 64_000 }, + }, "2026-06-12"); + + expect(synced).toMatchObject({ + base_model: "anthropic/claude-sonnet-4-6", + reasoning_options: [ + { type: "toggle" }, + { type: "effort", values: ["low", "medium", "high", "max"] }, + { type: "budget_tokens", min: 1024, max: 127_999 }, + ], + cost: { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 }, + }); + expect(synced).not.toHaveProperty("family"); +}); + +test("RodiumAi skips models without tools support", () => { + const parsed = rodiumai.parseModels({ + data: [ + vendorModel, + { + ...vendorModel, + id: "google/gemini-embedding-001", + rodiumai_capabilities: { + output_modalities: ["text"], + supports_tools: false, + }, + }, + ], + }); + + expect(parsed.some((model) => "id" in model && model.id === "google/gemini-embedding-001")).toBe(false); +}); + +test("RodiumAi rejects malformed responses", () => { + expect(() => RodiumResponse.parse({ data: [{ id: "broken" }] })).toThrow(); +}); diff --git a/providers/rodiumai/logo.svg b/providers/rodiumai/logo.svg index c9fcae145a..a152e6d25f 100644 --- a/providers/rodiumai/logo.svg +++ b/providers/rodiumai/logo.svg @@ -1 +1,10 @@ - \ No newline at end of file + + + + + + + + + + diff --git a/providers/rodiumai/models/anthropic/claude-fable-5.toml b/providers/rodiumai/models/anthropic/claude-fable-5.toml new file mode 100644 index 0000000000..a5b049c3a2 --- /dev/null +++ b/providers/rodiumai/models/anthropic/claude-fable-5.toml @@ -0,0 +1,8 @@ +base_model = "anthropic/claude-fable-5" +last_updated = "2026-06-12" +temperature = true +structured_output = true + +[[reasoning_options]] +type = "effort" +values = ["low", "medium", "high", "xhigh", "max"] diff --git a/providers/rodiumai/models/anthropic/claude-haiku-4-5-20251001.toml b/providers/rodiumai/models/anthropic/claude-haiku-4-5-20251001.toml index d69213c8a2..c30b64871b 100644 --- a/providers/rodiumai/models/anthropic/claude-haiku-4-5-20251001.toml +++ b/providers/rodiumai/models/anthropic/claude-haiku-4-5-20251001.toml @@ -1,23 +1,11 @@ -name = "Claude Haiku 4.5" -family = "claude-haiku" -release_date = "2025-10-15" -last_updated = "2025-10-15" -attachment = true -reasoning = true -temperature = true -tool_call = true -open_weights = false +base_model = "anthropic/claude-haiku-4-5-20251001" +last_updated = "2026-06-12" +structured_output = true -[cost] -input = 1 -output = 5 -cache_read = 0.1 -cache_write = 1.25 +[[reasoning_options]] +type = "toggle" -[limit] -context = 200_000 -output = 64_000 - -[modalities] -input = ["text","image","pdf"] -output = ["text"] +[[reasoning_options]] +type = "budget_tokens" +min = 1_024 +max = 63_999 diff --git a/providers/rodiumai/models/anthropic/claude-opus-4-1-20250805.toml b/providers/rodiumai/models/anthropic/claude-opus-4-1-20250805.toml new file mode 100644 index 0000000000..3de6c3a09b --- /dev/null +++ b/providers/rodiumai/models/anthropic/claude-opus-4-1-20250805.toml @@ -0,0 +1,5 @@ +base_model = "anthropic/claude-opus-4-1-20250805" +last_updated = "2026-06-12" +reasoning = false +structured_output = true +reasoning_options = [] diff --git a/providers/rodiumai/models/anthropic/claude-opus-4-5-20251101.toml b/providers/rodiumai/models/anthropic/claude-opus-4-5-20251101.toml new file mode 100644 index 0000000000..ca76bf1596 --- /dev/null +++ b/providers/rodiumai/models/anthropic/claude-opus-4-5-20251101.toml @@ -0,0 +1,9 @@ +base_model = "anthropic/claude-opus-4-5-20251101" +last_updated = "2026-06-12" +reasoning = false +structured_output = true +reasoning_options = [] + +[limit] +context = 1_000_000 +output = 128_000 diff --git a/providers/rodiumai/models/anthropic/claude-opus-4-6.toml b/providers/rodiumai/models/anthropic/claude-opus-4-6.toml new file mode 100644 index 0000000000..7fd30548a1 --- /dev/null +++ b/providers/rodiumai/models/anthropic/claude-opus-4-6.toml @@ -0,0 +1,5 @@ +base_model = "anthropic/claude-opus-4-6" +last_updated = "2026-06-12" +reasoning = false +structured_output = true +reasoning_options = [] diff --git a/providers/rodiumai/models/anthropic/claude-opus-4-7.toml b/providers/rodiumai/models/anthropic/claude-opus-4-7.toml index 2ed191a6fa..bcbed80c15 100644 --- a/providers/rodiumai/models/anthropic/claude-opus-4-7.toml +++ b/providers/rodiumai/models/anthropic/claude-opus-4-7.toml @@ -1,23 +1,6 @@ -name = "Claude Opus 4.7" -family = "claude-opus" -release_date = "2026-04-16" -last_updated = "2026-04-16" -attachment = true -reasoning = true +base_model = "anthropic/claude-opus-4-7" +last_updated = "2026-06-12" +reasoning = false temperature = true -tool_call = true -open_weights = false - -[cost] -input = 5 -output = 25 -cache_read = 0.5 -cache_write = 6.25 - -[limit] -context = 1_000_000 -output = 128_000 - -[modalities] -input = ["text","image","pdf"] -output = ["text"] +structured_output = true +reasoning_options = [] diff --git a/providers/rodiumai/models/anthropic/claude-opus-4-8.toml b/providers/rodiumai/models/anthropic/claude-opus-4-8.toml new file mode 100644 index 0000000000..c343c46c23 --- /dev/null +++ b/providers/rodiumai/models/anthropic/claude-opus-4-8.toml @@ -0,0 +1,6 @@ +base_model = "anthropic/claude-opus-4-8" +last_updated = "2026-06-12" +reasoning = false +temperature = true +structured_output = true +reasoning_options = [] diff --git a/providers/rodiumai/models/anthropic/claude-sonnet-4-5-20250929.toml b/providers/rodiumai/models/anthropic/claude-sonnet-4-5-20250929.toml new file mode 100644 index 0000000000..ef3c74d7b5 --- /dev/null +++ b/providers/rodiumai/models/anthropic/claude-sonnet-4-5-20250929.toml @@ -0,0 +1,14 @@ +base_model = "anthropic/claude-sonnet-4-5-20250929" +last_updated = "2026-06-12" +structured_output = true + +[[reasoning_options]] +type = "toggle" + +[[reasoning_options]] +type = "budget_tokens" +min = 1_024 +max = 63_999 + +[limit] +context = 1_000_000 diff --git a/providers/rodiumai/models/anthropic/claude-sonnet-4-6.toml b/providers/rodiumai/models/anthropic/claude-sonnet-4-6.toml index b9f4998c1c..f7376c7792 100644 --- a/providers/rodiumai/models/anthropic/claude-sonnet-4-6.toml +++ b/providers/rodiumai/models/anthropic/claude-sonnet-4-6.toml @@ -1,23 +1,15 @@ -name = "Claude Sonnet 4.6" -family = "claude-sonnet" -release_date = "2026-02-17" -last_updated = "2026-03-13" -attachment = true -reasoning = true -temperature = true -tool_call = true -open_weights = false +base_model = "anthropic/claude-sonnet-4-6" +last_updated = "2026-06-12" +structured_output = true -[cost] -input = 3 -output = 15 -cache_read = 0.3 -cache_write = 3.75 +[[reasoning_options]] +type = "toggle" -[limit] -context = 1_000_000 -output = 64_000 +[[reasoning_options]] +type = "effort" +values = ["low", "medium", "high", "max"] -[modalities] -input = ["text","image","pdf"] -output = ["text"] +[[reasoning_options]] +type = "budget_tokens" +min = 1_024 +max = 127_999 diff --git a/providers/rodiumai/models/auto.toml b/providers/rodiumai/models/auto.toml index a115d566d5..33881fa408 100644 --- a/providers/rodiumai/models/auto.toml +++ b/providers/rodiumai/models/auto.toml @@ -1,12 +1,13 @@ -name = "Auto (RodiumAi Smart Routing)" +name = "Auto (RodiumAI Smart Routing)" family = "rodium-smart" -release_date = "2026-05-25" -last_updated = "2026-05-25" +release_date = "2026-06-12" +last_updated = "2026-06-12" attachment = false reasoning = false temperature = true tool_call = true open_weights = false +reasoning_options = [] [cost] input = 0.3 diff --git a/providers/rodiumai/models/basic.toml b/providers/rodiumai/models/basic.toml index e49d6158f1..703bbc2646 100644 --- a/providers/rodiumai/models/basic.toml +++ b/providers/rodiumai/models/basic.toml @@ -1,12 +1,13 @@ name = "Basic" family = "rodium-smart" -release_date = "2026-05-25" -last_updated = "2026-05-25" +release_date = "2026-06-12" +last_updated = "2026-06-12" attachment = false reasoning = false temperature = true tool_call = true open_weights = false +reasoning_options = [] [cost] input = 0.05 diff --git a/providers/rodiumai/models/deepseek/deepseek-v3.2.toml b/providers/rodiumai/models/deepseek/deepseek-v3.2.toml new file mode 100644 index 0000000000..5f46fd8bd5 --- /dev/null +++ b/providers/rodiumai/models/deepseek/deepseek-v3.2.toml @@ -0,0 +1,19 @@ +name = "DeepSeek V3.2" +family = "deepseek" +release_date = "2026-06-09" +last_updated = "2026-06-12" +attachment = false +reasoning = false +temperature = true +tool_call = true +structured_output = true +open_weights = false +reasoning_options = [] + +[limit] +context = 164_000 +output = 32_768 + +[modalities] +input = ["text"] +output = ["text"] diff --git a/providers/rodiumai/models/deepseek/deepseek-v4-flash.toml b/providers/rodiumai/models/deepseek/deepseek-v4-flash.toml index a2bf327940..8edea9bb5c 100644 --- a/providers/rodiumai/models/deepseek/deepseek-v4-flash.toml +++ b/providers/rodiumai/models/deepseek/deepseek-v4-flash.toml @@ -1,22 +1,3 @@ -name = "DeepSeek V4 Flash" -family = "deepseek" -release_date = "2026-04-24" -last_updated = "2026-04-24" -attachment = false -reasoning = true -temperature = true -tool_call = true -open_weights = false - -[cost] -input = 0.14 -output = 0.28 -cache_read = 0.0028 - -[limit] -context = 1_000_000 -output = 384_000 - -[modalities] -input = ["text"] -output = ["text"] +base_model = "deepseek/deepseek-v4-flash" +last_updated = "2026-06-12" +reasoning_options = [] diff --git a/providers/rodiumai/models/deepseek/deepseek-v4-pro.toml b/providers/rodiumai/models/deepseek/deepseek-v4-pro.toml index bb453ae348..c2f777e5af 100644 --- a/providers/rodiumai/models/deepseek/deepseek-v4-pro.toml +++ b/providers/rodiumai/models/deepseek/deepseek-v4-pro.toml @@ -1,22 +1,3 @@ -name = "DeepSeek V4 Pro" -family = "deepseek" -release_date = "2026-04-24" -last_updated = "2026-04-24" -attachment = false -reasoning = true -temperature = true -tool_call = true -open_weights = false - -[cost] -input = 0.435 -output = 0.87 -cache_read = 0.003625 - -[limit] -context = 1_000_000 -output = 384_000 - -[modalities] -input = ["text"] -output = ["text"] +base_model = "deepseek/deepseek-v4-pro" +last_updated = "2026-06-12" +reasoning_options = [] diff --git a/providers/rodiumai/models/fast.toml b/providers/rodiumai/models/fast.toml index c968b176f9..e995132797 100644 --- a/providers/rodiumai/models/fast.toml +++ b/providers/rodiumai/models/fast.toml @@ -1,12 +1,13 @@ name = "Fast" family = "rodium-smart" -release_date = "2026-05-25" -last_updated = "2026-05-25" +release_date = "2026-06-12" +last_updated = "2026-06-12" attachment = false reasoning = false temperature = true tool_call = true open_weights = false +reasoning_options = [] [cost] input = 0.11 diff --git a/providers/rodiumai/models/google/gemini-2.5-flash-lite.toml b/providers/rodiumai/models/google/gemini-2.5-flash-lite.toml new file mode 100644 index 0000000000..5edf31d4f3 --- /dev/null +++ b/providers/rodiumai/models/google/gemini-2.5-flash-lite.toml @@ -0,0 +1,8 @@ +base_model = "google/gemini-2.5-flash-lite" +last_updated = "2026-06-12" +reasoning = false +reasoning_options = [] + +[limit] +context = 1_000_000 +output = 32_768 diff --git a/providers/rodiumai/models/google/gemini-2.5-flash.toml b/providers/rodiumai/models/google/gemini-2.5-flash.toml index 5912743535..106c6491b6 100644 --- a/providers/rodiumai/models/google/gemini-2.5-flash.toml +++ b/providers/rodiumai/models/google/gemini-2.5-flash.toml @@ -1,22 +1,7 @@ -name = "Gemini 2.5 Flash" -family = "gemini" -release_date = "2025-03-20" -last_updated = "2025-06-05" -attachment = true -reasoning = true -temperature = true -tool_call = true -open_weights = false - -[cost] -input = 0.3 -output = 2.5 -cache_read = 0.3 +base_model = "google/gemini-2.5-flash" +last_updated = "2026-06-12" +reasoning_options = [] [limit] context = 1_000_000 -output = 65_536 - -[modalities] -input = ["text","image","video","audio","pdf"] -output = ["text"] +output = 32_768 diff --git a/providers/rodiumai/models/google/gemini-2.5-pro.toml b/providers/rodiumai/models/google/gemini-2.5-pro.toml index ff0ccff109..31c37e8e6c 100644 --- a/providers/rodiumai/models/google/gemini-2.5-pro.toml +++ b/providers/rodiumai/models/google/gemini-2.5-pro.toml @@ -1,22 +1,7 @@ -name = "Gemini 2.5 Pro" -family = "gemini" -release_date = "2025-03-20" -last_updated = "2025-06-05" -attachment = true -reasoning = true -temperature = true -tool_call = true -open_weights = false - -[cost] -input = 1.25 -output = 10 -cache_read = 0.31 +base_model = "google/gemini-2.5-pro" +last_updated = "2026-06-12" +reasoning_options = [] [limit] context = 1_000_000 -output = 65_536 - -[modalities] -input = ["text","image","video","audio","pdf"] -output = ["text"] +output = 32_768 diff --git a/providers/rodiumai/models/google/gemini-3.1-flash-lite.toml b/providers/rodiumai/models/google/gemini-3.1-flash-lite.toml new file mode 100644 index 0000000000..6b66f53179 --- /dev/null +++ b/providers/rodiumai/models/google/gemini-3.1-flash-lite.toml @@ -0,0 +1,8 @@ +base_model = "google/gemini-3.1-flash-lite" +name = "Gemini 3.1 Flash-Lite" +last_updated = "2026-06-12" +reasoning_options = [] + +[limit] +context = 1_000_000 +output = 32_768 diff --git a/providers/rodiumai/models/google/gemini-3.1-pro-preview.toml b/providers/rodiumai/models/google/gemini-3.1-pro-preview.toml index 70cf94b59b..4538c578e1 100644 --- a/providers/rodiumai/models/google/gemini-3.1-pro-preview.toml +++ b/providers/rodiumai/models/google/gemini-3.1-pro-preview.toml @@ -1,22 +1,7 @@ -name = "Gemini 3.1 Pro Preview" -family = "gemini" -release_date = "2026-02-19" -last_updated = "2026-02-19" -attachment = true -reasoning = true -temperature = true -tool_call = true -open_weights = false - -[cost] -input = 2 -output = 12 -cache_read = 0.2 +base_model = "google/gemini-3.1-pro-preview" +last_updated = "2026-06-12" +reasoning_options = [] [limit] context = 2_000_000 -output = 65_536 - -[modalities] -input = ["text","image","video","audio","pdf"] -output = ["text"] +output = 32_768 diff --git a/providers/rodiumai/models/google/gemini-3.5-flash.toml b/providers/rodiumai/models/google/gemini-3.5-flash.toml index 398ff1c58c..00cff62fa8 100644 --- a/providers/rodiumai/models/google/gemini-3.5-flash.toml +++ b/providers/rodiumai/models/google/gemini-3.5-flash.toml @@ -1,22 +1,7 @@ -name = "Gemini 3.5 Flash" -family = "gemini" -release_date = "2026-05-19" -last_updated = "2026-05-19" -attachment = true -reasoning = true -temperature = true -tool_call = true -open_weights = false - -[cost] -input = 1.5 -output = 9 -cache_read = 0.15 +base_model = "google/gemini-3.5-flash" +last_updated = "2026-06-12" +reasoning_options = [] [limit] context = 1_000_000 -output = 65_536 - -[modalities] -input = ["text","image","video","audio","pdf"] -output = ["text"] +output = 32_768 diff --git a/providers/rodiumai/models/max.toml b/providers/rodiumai/models/max.toml index e5ada9ef8d..9541e84b00 100644 --- a/providers/rodiumai/models/max.toml +++ b/providers/rodiumai/models/max.toml @@ -1,12 +1,13 @@ name = "Max" family = "rodium-smart" -release_date = "2026-05-25" -last_updated = "2026-05-25" +release_date = "2026-06-12" +last_updated = "2026-06-12" attachment = false reasoning = true temperature = true tool_call = true open_weights = false +reasoning_options = [] [cost] input = 3 diff --git a/providers/rodiumai/models/meta/llama-3.3-70b-instruct.toml b/providers/rodiumai/models/meta/llama-3.3-70b-instruct.toml new file mode 100644 index 0000000000..e10bea5b9c --- /dev/null +++ b/providers/rodiumai/models/meta/llama-3.3-70b-instruct.toml @@ -0,0 +1,9 @@ +base_model = "meta/llama-3.3-70b-instruct" +name = "Llama 3.3 70B Instruct" +last_updated = "2026-06-12" +attachment = false +structured_output = true +reasoning_options = [] + +[limit] +output = 32_768 diff --git a/providers/rodiumai/models/meta/llama-4-maverick-17b-128e.toml b/providers/rodiumai/models/meta/llama-4-maverick-17b-128e.toml new file mode 100644 index 0000000000..38a254ba8e --- /dev/null +++ b/providers/rodiumai/models/meta/llama-4-maverick-17b-128e.toml @@ -0,0 +1,12 @@ +base_model = "meta/llama-4-maverick-17b-instruct" +name = "Llama 4 Maverick 17B 128E" +last_updated = "2026-06-12" +attachment = false +structured_output = true +reasoning_options = [] + +[limit] +output = 32_768 + +[modalities] +input = ["text"] diff --git a/providers/rodiumai/models/minimax/minimax-m2-5.toml b/providers/rodiumai/models/minimax/minimax-m2-5.toml new file mode 100644 index 0000000000..fe303e221c --- /dev/null +++ b/providers/rodiumai/models/minimax/minimax-m2-5.toml @@ -0,0 +1,13 @@ +base_model = "minimax/MiniMax-M2.5" +name = "MiniMax M2.5" +last_updated = "2026-06-12" +attachment = true +reasoning = false +structured_output = true +reasoning_options = [] + +[limit] +output = 32_768 + +[modalities] +input = ["text", "image", "video", "audio"] diff --git a/providers/rodiumai/models/minimax/minimax-m2-7.toml b/providers/rodiumai/models/minimax/minimax-m2-7.toml new file mode 100644 index 0000000000..a2adf6252d --- /dev/null +++ b/providers/rodiumai/models/minimax/minimax-m2-7.toml @@ -0,0 +1,13 @@ +base_model = "minimax/MiniMax-M2.7" +name = "MiniMax M2.7" +last_updated = "2026-06-12" +attachment = true +reasoning = false +structured_output = true +reasoning_options = [] + +[limit] +output = 32_768 + +[modalities] +input = ["text", "image", "video", "audio"] diff --git a/providers/rodiumai/models/mistral/mistral-large-3.toml b/providers/rodiumai/models/mistral/mistral-large-3.toml new file mode 100644 index 0000000000..9c0d8109d5 --- /dev/null +++ b/providers/rodiumai/models/mistral/mistral-large-3.toml @@ -0,0 +1,9 @@ +base_model = "mistral/mistral-large-latest" +name = "Mistral Large 3" +last_updated = "2026-06-12" +structured_output = true +reasoning_options = [] + +[limit] +context = 128_000 +output = 4_096 diff --git a/providers/rodiumai/models/moonshot-ai/kimi-k2.5.toml b/providers/rodiumai/models/moonshot-ai/kimi-k2.5.toml new file mode 100644 index 0000000000..7d38226e42 --- /dev/null +++ b/providers/rodiumai/models/moonshot-ai/kimi-k2.5.toml @@ -0,0 +1,8 @@ +base_model = "moonshotai/kimi-k2.5" +last_updated = "2026-06-12" +attachment = true +temperature = true +reasoning_options = [] + +[modalities] +input = ["text", "image"] diff --git a/providers/rodiumai/models/moonshot-ai/kimi-k2.6.toml b/providers/rodiumai/models/moonshot-ai/kimi-k2.6.toml new file mode 100644 index 0000000000..2682d7421c --- /dev/null +++ b/providers/rodiumai/models/moonshot-ai/kimi-k2.6.toml @@ -0,0 +1,6 @@ +base_model = "moonshotai/kimi-k2.6" +last_updated = "2026-06-12" +reasoning_options = [] + +[modalities] +input = ["text", "image"] diff --git a/providers/rodiumai/models/openai/gpt-4.1-mini.toml b/providers/rodiumai/models/openai/gpt-4.1-mini.toml new file mode 100644 index 0000000000..77f121eea5 --- /dev/null +++ b/providers/rodiumai/models/openai/gpt-4.1-mini.toml @@ -0,0 +1,11 @@ +base_model = "openai/gpt-4.1-mini" +name = "GPT-4.1 Mini" +last_updated = "2026-06-12" +reasoning_options = [] + +[limit] +context = 1_000_000 +output = 16_384 + +[modalities] +input = ["text", "image"] diff --git a/providers/rodiumai/models/openai/gpt-4.1-nano.toml b/providers/rodiumai/models/openai/gpt-4.1-nano.toml new file mode 100644 index 0000000000..379d2bf16e --- /dev/null +++ b/providers/rodiumai/models/openai/gpt-4.1-nano.toml @@ -0,0 +1,8 @@ +base_model = "openai/gpt-4.1-nano" +name = "GPT-4.1 Nano" +last_updated = "2026-06-12" +reasoning_options = [] + +[limit] +context = 1_000_000 +output = 16_384 diff --git a/providers/rodiumai/models/openai/gpt-4.1.toml b/providers/rodiumai/models/openai/gpt-4.1.toml new file mode 100644 index 0000000000..42303dfb02 --- /dev/null +++ b/providers/rodiumai/models/openai/gpt-4.1.toml @@ -0,0 +1,6 @@ +base_model = "openai/gpt-4.1" +last_updated = "2026-06-12" +reasoning_options = [] + +[limit] +context = 1_000_000 diff --git a/providers/rodiumai/models/openai/gpt-4o-mini.toml b/providers/rodiumai/models/openai/gpt-4o-mini.toml new file mode 100644 index 0000000000..1e0868643a --- /dev/null +++ b/providers/rodiumai/models/openai/gpt-4o-mini.toml @@ -0,0 +1,7 @@ +base_model = "openai/gpt-4o-mini" +name = "GPT-4o Mini" +last_updated = "2026-06-12" +reasoning_options = [] + +[modalities] +input = ["text", "image"] diff --git a/providers/rodiumai/models/openai/gpt-4o.toml b/providers/rodiumai/models/openai/gpt-4o.toml new file mode 100644 index 0000000000..ce3ac7a55b --- /dev/null +++ b/providers/rodiumai/models/openai/gpt-4o.toml @@ -0,0 +1,7 @@ +base_model = "openai/gpt-4o" +last_updated = "2026-06-12" +reasoning_options = [] + +[modalities] +input = ["text", "image", "audio"] +output = ["text", "audio"] diff --git a/providers/rodiumai/models/openai/gpt-5-mini.toml b/providers/rodiumai/models/openai/gpt-5-mini.toml new file mode 100644 index 0000000000..d2d796a5c1 --- /dev/null +++ b/providers/rodiumai/models/openai/gpt-5-mini.toml @@ -0,0 +1,9 @@ +base_model = "openai/gpt-5-mini" +base_model_omit = ["limit.input"] +last_updated = "2026-06-12" +temperature = true +reasoning_options = [] + +[limit] +context = 272_000 +output = 32_768 diff --git a/providers/rodiumai/models/openai/gpt-5-nano.toml b/providers/rodiumai/models/openai/gpt-5-nano.toml new file mode 100644 index 0000000000..0c6d84e372 --- /dev/null +++ b/providers/rodiumai/models/openai/gpt-5-nano.toml @@ -0,0 +1,9 @@ +base_model = "openai/gpt-5-nano" +base_model_omit = ["limit.input"] +last_updated = "2026-06-12" +temperature = true +reasoning_options = [] + +[limit] +context = 272_000 +output = 16_384 diff --git a/providers/rodiumai/models/openai/gpt-5-pro.toml b/providers/rodiumai/models/openai/gpt-5-pro.toml new file mode 100644 index 0000000000..7e696b302a --- /dev/null +++ b/providers/rodiumai/models/openai/gpt-5-pro.toml @@ -0,0 +1,9 @@ +base_model = "openai/gpt-5-pro" +base_model_omit = ["limit.input"] +last_updated = "2026-06-12" +temperature = true +reasoning_options = [] + +[limit] +context = 272_000 +output = 32_768 diff --git a/providers/rodiumai/models/openai/gpt-5.3-codex.toml b/providers/rodiumai/models/openai/gpt-5.3-codex.toml new file mode 100644 index 0000000000..83a7687b62 --- /dev/null +++ b/providers/rodiumai/models/openai/gpt-5.3-codex.toml @@ -0,0 +1,12 @@ +base_model = "openai/gpt-5.3-codex" +base_model_omit = ["limit.input"] +last_updated = "2026-06-12" +temperature = true +reasoning_options = [] + +[limit] +context = 272_000 +output = 65_536 + +[modalities] +input = ["text", "image"] diff --git a/providers/rodiumai/models/openai/gpt-5.4-mini.toml b/providers/rodiumai/models/openai/gpt-5.4-mini.toml index b2099a55d3..b7fdb670a9 100644 --- a/providers/rodiumai/models/openai/gpt-5.4-mini.toml +++ b/providers/rodiumai/models/openai/gpt-5.4-mini.toml @@ -1,22 +1,10 @@ +base_model = "openai/gpt-5.4-mini" +base_model_omit = ["limit.input"] name = "GPT-5.4 Mini" -family = "gpt" -release_date = "2026-03-17" -last_updated = "2026-03-17" -attachment = true -reasoning = false +last_updated = "2026-06-12" temperature = true -tool_call = true -open_weights = false - -[cost] -input = 0.75 -output = 4.5 -cache_read = 0.075 +reasoning_options = [] [limit] -context = 400_000 -output = 16_384 - -[modalities] -input = ["text","image","pdf"] -output = ["text"] +context = 1_100_000 +output = 32_768 diff --git a/providers/rodiumai/models/openai/gpt-5.4-nano.toml b/providers/rodiumai/models/openai/gpt-5.4-nano.toml new file mode 100644 index 0000000000..7521f34b64 --- /dev/null +++ b/providers/rodiumai/models/openai/gpt-5.4-nano.toml @@ -0,0 +1,10 @@ +base_model = "openai/gpt-5.4-nano" +base_model_omit = ["limit.input"] +name = "GPT-5.4 Nano" +last_updated = "2026-06-12" +temperature = true +reasoning_options = [] + +[limit] +context = 1_100_000 +output = 16_384 diff --git a/providers/rodiumai/models/openai/gpt-5.4-pro.toml b/providers/rodiumai/models/openai/gpt-5.4-pro.toml new file mode 100644 index 0000000000..bd87cb4381 --- /dev/null +++ b/providers/rodiumai/models/openai/gpt-5.4-pro.toml @@ -0,0 +1,14 @@ +base_model = "openai/gpt-5.4-pro" +base_model_omit = ["limit.input"] +last_updated = "2026-06-12" +reasoning = false +temperature = true +structured_output = true +reasoning_options = [] + +[limit] +context = 1_000_000 +output = 32_768 + +[modalities] +input = ["text", "image", "pdf"] diff --git a/providers/rodiumai/models/openai/gpt-5.4.toml b/providers/rodiumai/models/openai/gpt-5.4.toml index 74b419f58f..b665c18e7b 100644 --- a/providers/rodiumai/models/openai/gpt-5.4.toml +++ b/providers/rodiumai/models/openai/gpt-5.4.toml @@ -1,22 +1,9 @@ -name = "GPT-5.4" -family = "gpt" -release_date = "2026-03-05" -last_updated = "2026-03-05" -attachment = true -reasoning = false +base_model = "openai/gpt-5.4" +base_model_omit = ["limit.input"] +last_updated = "2026-06-12" temperature = true -tool_call = true -open_weights = false - -[cost] -input = 2.5 -output = 15 -cache_read = 0.25 +reasoning_options = [] [limit] -context = 1_000_000 +context = 1_100_000 output = 32_768 - -[modalities] -input = ["text","image","pdf"] -output = ["text"] diff --git a/providers/rodiumai/models/openai/gpt-5.5-pro.toml b/providers/rodiumai/models/openai/gpt-5.5-pro.toml new file mode 100644 index 0000000000..f4fe7cfee1 --- /dev/null +++ b/providers/rodiumai/models/openai/gpt-5.5-pro.toml @@ -0,0 +1,5 @@ +base_model = "openai/gpt-5.5-pro" +last_updated = "2026-06-12" +reasoning = false +temperature = true +reasoning_options = [] diff --git a/providers/rodiumai/models/openai/gpt-5.5.toml b/providers/rodiumai/models/openai/gpt-5.5.toml index 2d055bebda..48038d36ce 100644 --- a/providers/rodiumai/models/openai/gpt-5.5.toml +++ b/providers/rodiumai/models/openai/gpt-5.5.toml @@ -1,22 +1,5 @@ -name = "GPT-5.5" -family = "gpt" -release_date = "2026-04-23" -last_updated = "2026-04-23" -attachment = true +base_model = "openai/gpt-5.5" +last_updated = "2026-06-12" reasoning = false temperature = true -tool_call = true -open_weights = false - -[cost] -input = 5 -output = 30 -cache_read = 0.5 - -[limit] -context = 1_050_000 -output = 128_000 - -[modalities] -input = ["text","image","pdf"] -output = ["text"] +reasoning_options = [] diff --git a/providers/rodiumai/models/openai/gpt-5.toml b/providers/rodiumai/models/openai/gpt-5.toml new file mode 100644 index 0000000000..4198954a85 --- /dev/null +++ b/providers/rodiumai/models/openai/gpt-5.toml @@ -0,0 +1,9 @@ +base_model = "openai/gpt-5" +base_model_omit = ["limit.input"] +last_updated = "2026-06-12" +temperature = true +reasoning_options = [] + +[limit] +context = 272_000 +output = 32_768 diff --git a/providers/rodiumai/models/openai/o3-mini.toml b/providers/rodiumai/models/openai/o3-mini.toml new file mode 100644 index 0000000000..94cd3bfb2c --- /dev/null +++ b/providers/rodiumai/models/openai/o3-mini.toml @@ -0,0 +1,4 @@ +base_model = "openai/o3-mini" +last_updated = "2026-06-12" +temperature = true +reasoning_options = [] diff --git a/providers/rodiumai/models/openai/o3-pro.toml b/providers/rodiumai/models/openai/o3-pro.toml new file mode 100644 index 0000000000..81c8d7e9ea --- /dev/null +++ b/providers/rodiumai/models/openai/o3-pro.toml @@ -0,0 +1,8 @@ +base_model = "openai/o3-pro" +name = "o3 Pro" +last_updated = "2026-06-12" +temperature = true +reasoning_options = [] + +[modalities] +input = ["text", "image", "pdf"] diff --git a/providers/rodiumai/models/openai/o3.toml b/providers/rodiumai/models/openai/o3.toml index b3b80a35e9..0fb4c30a67 100644 --- a/providers/rodiumai/models/openai/o3.toml +++ b/providers/rodiumai/models/openai/o3.toml @@ -1,22 +1,4 @@ -name = "o3" -family = "o" -release_date = "2025-04-16" -last_updated = "2025-04-16" -attachment = true -reasoning = true +base_model = "openai/o3" +last_updated = "2026-06-12" temperature = true -tool_call = true -open_weights = false - -[cost] -input = 2 -output = 8 -cache_read = 0.5 - -[limit] -context = 200_000 -output = 100_000 - -[modalities] -input = ["text","image","pdf"] -output = ["text"] +reasoning_options = [] diff --git a/providers/rodiumai/models/openai/o4-mini.toml b/providers/rodiumai/models/openai/o4-mini.toml new file mode 100644 index 0000000000..f45f6fbcb5 --- /dev/null +++ b/providers/rodiumai/models/openai/o4-mini.toml @@ -0,0 +1,4 @@ +base_model = "openai/o4-mini" +last_updated = "2026-06-12" +temperature = true +reasoning_options = [] diff --git a/providers/rodiumai/models/pro.toml b/providers/rodiumai/models/pro.toml index aa86ca2170..17a5b9eba6 100644 --- a/providers/rodiumai/models/pro.toml +++ b/providers/rodiumai/models/pro.toml @@ -1,12 +1,13 @@ name = "Pro" family = "rodium-smart" -release_date = "2026-05-25" -last_updated = "2026-05-25" +release_date = "2026-06-12" +last_updated = "2026-06-12" attachment = false reasoning = true temperature = true tool_call = true open_weights = false +reasoning_options = [] [cost] input = 0.3 diff --git a/providers/rodiumai/models/xai/grok-4-1-fast-non-reasoning.toml b/providers/rodiumai/models/xai/grok-4-1-fast-non-reasoning.toml new file mode 100644 index 0000000000..5e63c0d5be --- /dev/null +++ b/providers/rodiumai/models/xai/grok-4-1-fast-non-reasoning.toml @@ -0,0 +1,19 @@ +name = "Grok 4.1 Fast Non-Reasoning" +family = "grok" +release_date = "2026-06-09" +last_updated = "2026-06-12" +attachment = true +reasoning = false +temperature = true +tool_call = true +structured_output = true +open_weights = false +reasoning_options = [] + +[limit] +context = 131_000 +output = 8_192 + +[modalities] +input = ["text", "image"] +output = ["text"] diff --git a/providers/rodiumai/models/xai/grok-4-1-fast-reasoning.toml b/providers/rodiumai/models/xai/grok-4-1-fast-reasoning.toml new file mode 100644 index 0000000000..16fa068880 --- /dev/null +++ b/providers/rodiumai/models/xai/grok-4-1-fast-reasoning.toml @@ -0,0 +1,19 @@ +name = "Grok 4.1 Fast Reasoning" +family = "grok" +release_date = "2026-06-09" +last_updated = "2026-06-12" +attachment = true +reasoning = true +temperature = true +tool_call = true +structured_output = true +open_weights = false +reasoning_options = [] + +[limit] +context = 131_000 +output = 8_192 + +[modalities] +input = ["text", "image"] +output = ["text"] diff --git a/providers/rodiumai/models/xai/grok-4-20-non-reasoning.toml b/providers/rodiumai/models/xai/grok-4-20-non-reasoning.toml new file mode 100644 index 0000000000..133ab58fd5 --- /dev/null +++ b/providers/rodiumai/models/xai/grok-4-20-non-reasoning.toml @@ -0,0 +1,11 @@ +base_model = "xai/grok-4.20-0309-non-reasoning" +name = "Grok 4.20 Non-Reasoning" +last_updated = "2026-06-12" +reasoning_options = [] + +[limit] +context = 262_000 +output = 8_192 + +[modalities] +input = ["text", "image"] diff --git a/providers/rodiumai/models/xai/grok-4-20-reasoning.toml b/providers/rodiumai/models/xai/grok-4-20-reasoning.toml new file mode 100644 index 0000000000..b290fa2f18 --- /dev/null +++ b/providers/rodiumai/models/xai/grok-4-20-reasoning.toml @@ -0,0 +1,11 @@ +base_model = "xai/grok-4.20-0309-reasoning" +name = "Grok 4.20 Reasoning" +last_updated = "2026-06-12" +reasoning_options = [] + +[limit] +context = 262_000 +output = 8_192 + +[modalities] +input = ["text", "image"] diff --git a/providers/rodiumai/models/xai/grok-4.3.toml b/providers/rodiumai/models/xai/grok-4.3.toml new file mode 100644 index 0000000000..5de3430f67 --- /dev/null +++ b/providers/rodiumai/models/xai/grok-4.3.toml @@ -0,0 +1,10 @@ +base_model = "xai/grok-4.3" +last_updated = "2026-06-12" +reasoning_options = [] + +[limit] +context = 200_000 +output = 8_192 + +[modalities] +input = ["text", "image"] diff --git a/sync.md b/sync.md index c07e9547fc..84ef28e181 100644 --- a/sync.md +++ b/sync.md @@ -183,6 +183,18 @@ Venice is implemented in `packages/core/src/sync/providers/venice.ts`. - Every Venice model uses `base_model`; flattened IDs are matched to provider-agnostic metadata before provider-specific overrides are written. - Every Venice model declares `reasoning_options`; models without API-provided effort levels use an empty array. +## RodiumAi Notes + +RodiumAi is implemented in `packages/core/src/sync/providers/rodiumai.ts`. + +- Run it with `bun models:sync rodiumai` or `bun rodiumai:sync`. +- Source endpoint: `https://api.rodiumai.io/v1/models` (no auth required for listing). +- Only coding/chat models are synced: text output, tool support, and no image/video/embedding slugs. +- Five smart-routing profiles (`auto`, `basic`, `fast`, `pro`, `max`) are authored locally and always included. +- Vendor passthrough slugs use `base_model` when a matching `models/` metadata entry exists. +- Every model declares `reasoning_options`; Anthropic slugs inherit effort/toggle defaults, others default to `[]`. +- Existing `[cost]` overrides are preserved when updating factored models. + ## Standalone Generators Some provider scripts in `packages/core/script/generate-*.ts` are not wired into `bun models:sync`. When updating those scripts, preserve existing `base_model` and `base_model_omit` fields for generated TOMLs that already use model metadata inheritance. New inheritance-aware output should use `base_model`; do not reintroduce legacy `[extends]` syntax. From 5080ca64f8d13b062529e26ea6f203bcbcf6ca07 Mon Sep 17 00:00:00 2001 From: Docteur-Parfait Date: Fri, 12 Jun 2026 01:30:40 +0000 Subject: [PATCH 7/8] fix(rodiumai): align anthropic reasoning_options with direct provider --- packages/core/src/sync/providers/rodiumai.ts | 96 ++++++++++--------- packages/core/test/rodiumai-sync.test.ts | 6 +- .../models/anthropic/claude-fable-5.toml | 1 - .../anthropic/claude-haiku-4-5-20251001.toml | 4 - .../anthropic/claude-opus-4-1-20250805.toml | 6 +- .../anthropic/claude-opus-4-5-20251101.toml | 10 +- .../models/anthropic/claude-opus-4-6.toml | 10 +- .../models/anthropic/claude-opus-4-7.toml | 7 +- .../models/anthropic/claude-opus-4-8.toml | 7 +- .../anthropic/claude-sonnet-4-5-20250929.toml | 4 - .../models/anthropic/claude-sonnet-4-6.toml | 4 - sync.md | 2 +- 12 files changed, 84 insertions(+), 73 deletions(-) diff --git a/packages/core/src/sync/providers/rodiumai.ts b/packages/core/src/sync/providers/rodiumai.ts index 54336046fd..e3fdae3163 100644 --- a/packages/core/src/sync/providers/rodiumai.ts +++ b/packages/core/src/sync/providers/rodiumai.ts @@ -1,4 +1,4 @@ -import { readdirSync } from "node:fs"; +import { readFileSync, readdirSync } from "node:fs"; import path from "node:path"; import { z } from "zod"; @@ -7,7 +7,9 @@ import type { ExistingModel, SyncProvider, SyncedFullModel, SyncedModel } from " import { factorBaseModel, resolveCanonicalBaseModel } from "./openrouter.js"; const API_ENDPOINT = "https://api.rodiumai.io/v1/models"; -const MODELS_DIR = path.join(import.meta.dirname, "..", "..", "..", "..", "..", "models"); +const REPO_ROOT = path.join(import.meta.dirname, "..", "..", "..", "..", ".."); +const MODELS_DIR = path.join(REPO_ROOT, "models"); +const ANTHROPIC_PROVIDER_DIR = path.join(REPO_ROOT, "providers", "anthropic", "models"); const EXCLUDED_SLUG_PARTS = [ "embed", @@ -107,6 +109,7 @@ type Modality = "text" | "audio" | "image" | "video" | "pdf"; type ReasoningOption = NonNullable[number]; const metadataFilesByProvider = new Map>(); +const anthropicProviderModels = new Map>(); export const rodiumai = { id: "rodiumai", @@ -218,48 +221,52 @@ export function resolveRodiumBaseModel(apiID: string): string | undefined { return directCandidates.find((candidate) => metadataFileExists(candidate)); } -function defaultReasoningOptions( +function anthropicDirectProviderModel(baseModel: string): Record | undefined { + if (!baseModel.startsWith("anthropic/")) return undefined; + const slug = baseModel.slice("anthropic/".length); + let cached = anthropicProviderModels.get(slug); + if (cached === undefined) { + try { + cached = Bun.TOML.parse( + readFileSync(path.join(ANTHROPIC_PROVIDER_DIR, `${slug}.toml`), "utf8"), + ) as Record; + anthropicProviderModels.set(slug, cached); + } catch { + return undefined; + } + } + return cached; +} + +function resolveReasoningOptions( baseModel: string | undefined, - reasoning: boolean, existing: ExistingModel | undefined, ): ReasoningOption[] { if (existing?.reasoning_options !== undefined) return existing.reasoning_options; - if (!reasoning) return []; + if (baseModel === undefined) return []; + const direct = anthropicDirectProviderModel(baseModel); + const options = direct?.reasoning_options; + if (Array.isArray(options)) return options as ReasoningOption[]; + return []; +} - if (baseModel === "anthropic/claude-fable-5") { - return [{ type: "effort", values: ["low", "medium", "high", "xhigh", "max"] }]; - } - if (baseModel?.startsWith("anthropic/claude-opus-4-8")) { - return [ - { type: "toggle" }, - { type: "effort", values: ["low", "medium", "high", "xhigh", "max"] }, - ]; - } - if (baseModel?.startsWith("anthropic/claude-opus-4-7")) { - return [ - { type: "toggle" }, - { type: "effort", values: ["low", "medium", "high", "xhigh", "max"] }, - ]; - } - if (baseModel?.startsWith("anthropic/claude-opus-4-6")) { - return [ - { type: "toggle" }, - { type: "effort", values: ["low", "medium", "high", "max"] }, - { type: "budget_tokens", min: 1024, max: 127_999 }, - ]; - } - if (baseModel?.startsWith("anthropic/claude-sonnet-4-6")) { - return [ - { type: "toggle" }, - { type: "effort", values: ["low", "medium", "high", "max"] }, - { type: "budget_tokens", min: 1024, max: 127_999 }, - ]; - } - if (baseModel?.startsWith("anthropic/")) { - return [{ type: "toggle" }, { type: "budget_tokens", min: 1024, max: 63_999 }]; - } +function resolveProviderTemperature( + baseModel: string | undefined, +): boolean | undefined { + if (baseModel === undefined) return undefined; + const direct = anthropicDirectProviderModel(baseModel); + return typeof direct?.temperature === "boolean" ? direct.temperature : undefined; +} - return []; +function resolveReasoningFlag( + baseModel: string | undefined, + supportsReasoning: boolean | undefined, +): boolean | undefined { + if (supportsReasoning === true) return true; + // RodiumAi's supports_reasoning flag is unreliable for adaptive-thinking models. + // When factoring a base model, inherit reasoning from models/ metadata instead. + if (baseModel !== undefined) return undefined; + return supportsReasoning === true ? true : false; } export function buildSmartProfile( @@ -304,7 +311,8 @@ export function buildRodiumVendorModel( const input = modalities(caps.input_modalities ?? ["text"], ["text"]); const output = modalities(caps.output_modalities ?? ["text"], ["text"]); const attachment = input.some((value) => value !== "text") || caps.supports_vision === true; - const reasoning = caps.supports_reasoning === true; + const baseModel = existing?.base_model ?? resolveRodiumBaseModel(model.id); + const reasoning = resolveReasoningFlag(baseModel, caps.supports_reasoning); const toolCall = caps.supports_tools === true; const structuredOutput = caps.supports_json_mode === true ? true : undefined; const releaseDate = existing?.release_date ?? dateFromTimestamp(model.created); @@ -313,8 +321,8 @@ export function buildRodiumVendorModel( input: existing?.limit?.input, output: caps.max_output_tokens ?? existing?.limit?.output ?? 32_768, }; - const baseModel = existing?.base_model ?? resolveRodiumBaseModel(model.id); - const reasoningOptions = defaultReasoningOptions(baseModel, reasoning, existing); + const reasoningOptions = resolveReasoningOptions(baseModel, existing); + const temperature = resolveProviderTemperature(baseModel); const cost = existing?.cost; const changed = existing !== undefined && ( existing.name !== name @@ -333,7 +341,7 @@ export function buildRodiumVendorModel( attachment, reasoning, reasoning_options: reasoningOptions, - temperature: true, + temperature, tool_call: toolCall, structured_output: structuredOutput, last_updated: existing === undefined || changed ? today : (existing.last_updated ?? today), @@ -352,9 +360,9 @@ export function buildRodiumVendorModel( release_date: releaseDate, last_updated: existing === undefined || changed ? today : (existing.last_updated ?? today), attachment, - reasoning, + reasoning: reasoning ?? false, reasoning_options: reasoningOptions, - temperature: true, + temperature: temperature ?? true, tool_call: toolCall, structured_output: structuredOutput, open_weights: false, diff --git a/packages/core/test/rodiumai-sync.test.ts b/packages/core/test/rodiumai-sync.test.ts index 3b4f93e9a6..8299ae5db2 100644 --- a/packages/core/test/rodiumai-sync.test.ts +++ b/packages/core/test/rodiumai-sync.test.ts @@ -70,7 +70,7 @@ test("RodiumAi smart profiles declare reasoning_options", () => { expect(synced.family).toBe("rodium-smart"); }); -test("RodiumAi vendor models use base_model and reasoning_options", () => { +test("RodiumAi vendor models inherit anthropic reasoning_options from direct provider", () => { const synced = buildRodiumVendorModel(vendorModel, { cost: { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 }, limit: { context: 1_000_000, output: 64_000 }, @@ -79,13 +79,13 @@ test("RodiumAi vendor models use base_model and reasoning_options", () => { expect(synced).toMatchObject({ base_model: "anthropic/claude-sonnet-4-6", reasoning_options: [ - { type: "toggle" }, { type: "effort", values: ["low", "medium", "high", "max"] }, - { type: "budget_tokens", min: 1024, max: 127_999 }, + { type: "budget_tokens", min: 1024 }, ], cost: { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 }, }); expect(synced).not.toHaveProperty("family"); + expect(synced).not.toHaveProperty("reasoning"); }); test("RodiumAi skips models without tools support", () => { diff --git a/providers/rodiumai/models/anthropic/claude-fable-5.toml b/providers/rodiumai/models/anthropic/claude-fable-5.toml index a5b049c3a2..9b834b3685 100644 --- a/providers/rodiumai/models/anthropic/claude-fable-5.toml +++ b/providers/rodiumai/models/anthropic/claude-fable-5.toml @@ -1,6 +1,5 @@ base_model = "anthropic/claude-fable-5" last_updated = "2026-06-12" -temperature = true structured_output = true [[reasoning_options]] diff --git a/providers/rodiumai/models/anthropic/claude-haiku-4-5-20251001.toml b/providers/rodiumai/models/anthropic/claude-haiku-4-5-20251001.toml index c30b64871b..b6f6aba2a3 100644 --- a/providers/rodiumai/models/anthropic/claude-haiku-4-5-20251001.toml +++ b/providers/rodiumai/models/anthropic/claude-haiku-4-5-20251001.toml @@ -2,10 +2,6 @@ base_model = "anthropic/claude-haiku-4-5-20251001" last_updated = "2026-06-12" structured_output = true -[[reasoning_options]] -type = "toggle" - [[reasoning_options]] type = "budget_tokens" min = 1_024 -max = 63_999 diff --git a/providers/rodiumai/models/anthropic/claude-opus-4-1-20250805.toml b/providers/rodiumai/models/anthropic/claude-opus-4-1-20250805.toml index 3de6c3a09b..fdbe2fd01b 100644 --- a/providers/rodiumai/models/anthropic/claude-opus-4-1-20250805.toml +++ b/providers/rodiumai/models/anthropic/claude-opus-4-1-20250805.toml @@ -1,5 +1,7 @@ base_model = "anthropic/claude-opus-4-1-20250805" last_updated = "2026-06-12" -reasoning = false structured_output = true -reasoning_options = [] + +[[reasoning_options]] +type = "budget_tokens" +min = 1_024 diff --git a/providers/rodiumai/models/anthropic/claude-opus-4-5-20251101.toml b/providers/rodiumai/models/anthropic/claude-opus-4-5-20251101.toml index ca76bf1596..a019cb4baf 100644 --- a/providers/rodiumai/models/anthropic/claude-opus-4-5-20251101.toml +++ b/providers/rodiumai/models/anthropic/claude-opus-4-5-20251101.toml @@ -1,8 +1,14 @@ base_model = "anthropic/claude-opus-4-5-20251101" last_updated = "2026-06-12" -reasoning = false structured_output = true -reasoning_options = [] + +[[reasoning_options]] +type = "effort" +values = ["low", "medium", "high"] + +[[reasoning_options]] +type = "budget_tokens" +min = 1_024 [limit] context = 1_000_000 diff --git a/providers/rodiumai/models/anthropic/claude-opus-4-6.toml b/providers/rodiumai/models/anthropic/claude-opus-4-6.toml index 7fd30548a1..d2e584207a 100644 --- a/providers/rodiumai/models/anthropic/claude-opus-4-6.toml +++ b/providers/rodiumai/models/anthropic/claude-opus-4-6.toml @@ -1,5 +1,11 @@ base_model = "anthropic/claude-opus-4-6" last_updated = "2026-06-12" -reasoning = false structured_output = true -reasoning_options = [] + +[[reasoning_options]] +type = "effort" +values = ["low", "medium", "high", "max"] + +[[reasoning_options]] +type = "budget_tokens" +min = 1_024 diff --git a/providers/rodiumai/models/anthropic/claude-opus-4-7.toml b/providers/rodiumai/models/anthropic/claude-opus-4-7.toml index bcbed80c15..228f19ec8f 100644 --- a/providers/rodiumai/models/anthropic/claude-opus-4-7.toml +++ b/providers/rodiumai/models/anthropic/claude-opus-4-7.toml @@ -1,6 +1,7 @@ base_model = "anthropic/claude-opus-4-7" last_updated = "2026-06-12" -reasoning = false -temperature = true structured_output = true -reasoning_options = [] + +[[reasoning_options]] +type = "effort" +values = ["low", "medium", "high", "xhigh", "max"] diff --git a/providers/rodiumai/models/anthropic/claude-opus-4-8.toml b/providers/rodiumai/models/anthropic/claude-opus-4-8.toml index c343c46c23..1a83699974 100644 --- a/providers/rodiumai/models/anthropic/claude-opus-4-8.toml +++ b/providers/rodiumai/models/anthropic/claude-opus-4-8.toml @@ -1,6 +1,7 @@ base_model = "anthropic/claude-opus-4-8" last_updated = "2026-06-12" -reasoning = false -temperature = true structured_output = true -reasoning_options = [] + +[[reasoning_options]] +type = "effort" +values = ["low", "medium", "high", "xhigh", "max"] diff --git a/providers/rodiumai/models/anthropic/claude-sonnet-4-5-20250929.toml b/providers/rodiumai/models/anthropic/claude-sonnet-4-5-20250929.toml index ef3c74d7b5..98ff3cbcdb 100644 --- a/providers/rodiumai/models/anthropic/claude-sonnet-4-5-20250929.toml +++ b/providers/rodiumai/models/anthropic/claude-sonnet-4-5-20250929.toml @@ -2,13 +2,9 @@ base_model = "anthropic/claude-sonnet-4-5-20250929" last_updated = "2026-06-12" structured_output = true -[[reasoning_options]] -type = "toggle" - [[reasoning_options]] type = "budget_tokens" min = 1_024 -max = 63_999 [limit] context = 1_000_000 diff --git a/providers/rodiumai/models/anthropic/claude-sonnet-4-6.toml b/providers/rodiumai/models/anthropic/claude-sonnet-4-6.toml index f7376c7792..8ec6097854 100644 --- a/providers/rodiumai/models/anthropic/claude-sonnet-4-6.toml +++ b/providers/rodiumai/models/anthropic/claude-sonnet-4-6.toml @@ -2,9 +2,6 @@ base_model = "anthropic/claude-sonnet-4-6" last_updated = "2026-06-12" structured_output = true -[[reasoning_options]] -type = "toggle" - [[reasoning_options]] type = "effort" values = ["low", "medium", "high", "max"] @@ -12,4 +9,3 @@ values = ["low", "medium", "high", "max"] [[reasoning_options]] type = "budget_tokens" min = 1_024 -max = 127_999 diff --git a/sync.md b/sync.md index 84ef28e181..efba738194 100644 --- a/sync.md +++ b/sync.md @@ -192,7 +192,7 @@ RodiumAi is implemented in `packages/core/src/sync/providers/rodiumai.ts`. - Only coding/chat models are synced: text output, tool support, and no image/video/embedding slugs. - Five smart-routing profiles (`auto`, `basic`, `fast`, `pro`, `max`) are authored locally and always included. - Vendor passthrough slugs use `base_model` when a matching `models/` metadata entry exists. -- Every model declares `reasoning_options`; Anthropic slugs inherit effort/toggle defaults, others default to `[]`. +- Every model declares `reasoning_options`. For Anthropic passthrough slugs, the sync copies controls from `providers/anthropic/models/` when present; others default to `[]`. RodiumAi's `supports_reasoning` API flag is not used to override `reasoning` on factored models. - Existing `[cost]` overrides are preserved when updating factored models. ## Standalone Generators From 21d5b7cc32d706292923c983d1ef5286b1b44267 Mon Sep 17 00:00:00 2001 From: Docteur-Parfait Date: Fri, 12 Jun 2026 10:44:36 +0000 Subject: [PATCH 8/8] Removed synthetic smart profiles (auto/basic/fast/pro/max). RodiumAI provider models now use base_model + OpenRouter-aligned overrides (cost, reasoning_options, limits from live API). Re-run bun rodiumai:sync to refresh. Co-authored-by: Cursor --- packages/core/src/sync/index.ts | 8 +- packages/core/src/sync/providers/rodiumai.ts | 223 ++++++++++-------- packages/core/test/rodiumai-sync.test.ts | 14 -- .../models/anthropic/claude-fable-5.toml | 6 + providers/rodiumai/models/auto.toml | 22 -- providers/rodiumai/models/basic.toml | 22 -- .../models/deepseek/deepseek-v3.2.toml | 15 +- .../models/deepseek/deepseek-v4-flash.toml | 16 +- .../models/deepseek/deepseek-v4-pro.toml | 16 +- providers/rodiumai/models/fast.toml | 22 -- .../models/google/gemini-2.5-flash-lite.toml | 17 +- .../models/google/gemini-2.5-flash.toml | 16 +- .../models/google/gemini-2.5-pro.toml | 13 +- .../models/google/gemini-3.1-flash-lite.toml | 12 +- .../models/google/gemini-3.1-pro-preview.toml | 21 +- .../models/google/gemini-3.5-flash.toml | 12 +- providers/rodiumai/models/max.toml | 22 -- .../rodiumai/models/minimax/minimax-m2-5.toml | 1 - .../rodiumai/models/minimax/minimax-m2-7.toml | 1 - .../models/moonshot-ai/kimi-k2.5.toml | 1 - .../rodiumai/models/openai/gpt-4.1-mini.toml | 5 + .../rodiumai/models/openai/gpt-4.1-nano.toml | 5 + providers/rodiumai/models/openai/gpt-4.1.toml | 5 + .../rodiumai/models/openai/gpt-4o-mini.toml | 5 + providers/rodiumai/models/openai/gpt-4o.toml | 4 + .../rodiumai/models/openai/gpt-5-mini.toml | 11 +- .../rodiumai/models/openai/gpt-5-nano.toml | 11 +- .../rodiumai/models/openai/gpt-5-pro.toml | 5 +- .../rodiumai/models/openai/gpt-5.3-codex.toml | 11 +- .../rodiumai/models/openai/gpt-5.4-mini.toml | 11 +- .../rodiumai/models/openai/gpt-5.4-nano.toml | 11 +- .../rodiumai/models/openai/gpt-5.4-pro.toml | 11 +- providers/rodiumai/models/openai/gpt-5.4.toml | 11 +- .../rodiumai/models/openai/gpt-5.5-pro.toml | 11 +- providers/rodiumai/models/openai/gpt-5.5.toml | 12 +- providers/rodiumai/models/openai/gpt-5.toml | 11 +- providers/rodiumai/models/openai/o3-mini.toml | 12 +- providers/rodiumai/models/openai/o3-pro.toml | 10 +- providers/rodiumai/models/openai/o3.toml | 11 +- providers/rodiumai/models/openai/o4-mini.toml | 11 +- providers/rodiumai/models/pro.toml | 22 -- 41 files changed, 411 insertions(+), 275 deletions(-) delete mode 100644 providers/rodiumai/models/auto.toml delete mode 100644 providers/rodiumai/models/basic.toml delete mode 100644 providers/rodiumai/models/fast.toml delete mode 100644 providers/rodiumai/models/max.toml delete mode 100644 providers/rodiumai/models/pro.toml diff --git a/packages/core/src/sync/index.ts b/packages/core/src/sync/index.ts index f84247206d..afa7209f85 100644 --- a/packages/core/src/sync/index.ts +++ b/packages/core/src/sync/index.ts @@ -232,7 +232,7 @@ export async function syncProvider( } for (const [relativePath, file] of desired) { - const filePath = path.join(provider.modelsDir, relativePath); + const filePath = path.join(provider.modelsDir, ...relativePath.split("/")); const current = existing.get(relativePath); if (current === undefined) { @@ -285,7 +285,7 @@ export async function syncProvider( continue; } - const filePath = path.join(provider.modelsDir, relativePath); + const filePath = path.join(provider.modelsDir, ...relativePath.split("/")); files.push({ status: "deleted", path: filePath }); if (options.dryRun) { console.log(`Would remove ${relativePath}`); @@ -416,7 +416,7 @@ async function readModelMetadata(modelsDir: string) { absolute: true, followSymlinks: true, })) { - const modelID = path.relative(metadataDir, modelPath).slice(0, -5); + const modelID = path.relative(metadataDir, modelPath).slice(0, -5).replaceAll("\\", "/"); const toml = Bun.TOML.parse( await Bun.file(modelPath).text(), ) as Record; @@ -525,7 +525,7 @@ async function tomlFiles(root: string, dir = "") { const result: Array<{ file: string; symlink: boolean }> = []; for (const entry of await readdir(path.join(root, dir), { withFileTypes: true })) { - const file = path.join(dir, entry.name); + const file = path.join(dir, entry.name).replaceAll("\\", "/"); if (entry.isDirectory()) { result.push(...await tomlFiles(root, file)); } else if (entry.name.endsWith(".toml") && (entry.isFile() || entry.isSymbolicLink())) { diff --git a/packages/core/src/sync/providers/rodiumai.ts b/packages/core/src/sync/providers/rodiumai.ts index e3fdae3163..40f3b888b4 100644 --- a/packages/core/src/sync/providers/rodiumai.ts +++ b/packages/core/src/sync/providers/rodiumai.ts @@ -10,6 +10,7 @@ const API_ENDPOINT = "https://api.rodiumai.io/v1/models"; const REPO_ROOT = path.join(import.meta.dirname, "..", "..", "..", "..", ".."); const MODELS_DIR = path.join(REPO_ROOT, "models"); const ANTHROPIC_PROVIDER_DIR = path.join(REPO_ROOT, "providers", "anthropic", "models"); +const OPENROUTER_PROVIDER_DIR = path.join(REPO_ROOT, "providers", "openrouter", "models"); const EXCLUDED_SLUG_PARTS = [ "embed", @@ -35,44 +36,6 @@ const BASE_MODEL_ALIASES: Record = { "xai/grok-4-20-non-reasoning": "xai/grok-4.20-0309-non-reasoning", }; -const SMART_PROFILES = [ - { - id: "auto", - name: "Auto (RodiumAI Smart Routing)", - reasoning: false, - cost: { input: 0.3, output: 2.5 }, - limit: { context: 1_000_000, output: 32_000 }, - }, - { - id: "basic", - name: "Basic", - reasoning: false, - cost: { input: 0.05, output: 0.08 }, - limit: { context: 128_000, output: 8192 }, - }, - { - id: "fast", - name: "Fast", - reasoning: false, - cost: { input: 0.11, output: 0.34 }, - limit: { context: 128_000, output: 16_384 }, - }, - { - id: "pro", - name: "Pro", - reasoning: true, - cost: { input: 0.3, output: 2.5 }, - limit: { context: 1_000_000, output: 32_000 }, - }, - { - id: "max", - name: "Max", - reasoning: true, - cost: { input: 3.0, output: 15.0 }, - limit: { context: 200_000, output: 16_384 }, - }, -] as const; - export const RodiumCapabilities = z.object({ context_window: z.number().int().nonnegative().nullable().optional(), max_output_tokens: z.number().int().nonnegative().nullable().optional(), @@ -103,13 +66,14 @@ export const RodiumResponse = z.object({ }).passthrough(); export type RodiumApiModel = z.infer; -export type SmartProfile = (typeof SMART_PROFILES)[number]; type Modality = "text" | "audio" | "image" | "video" | "pdf"; type ReasoningOption = NonNullable[number]; +type ModelCost = NonNullable; const metadataFilesByProvider = new Map>(); const anthropicProviderModels = new Map>(); +const openRouterProviderModels = new Map | null>(); export const rodiumai = { id: "rodiumai", @@ -123,22 +87,15 @@ export const rodiumai = { return response.json(); }, parseModels(raw) { - const data = RodiumResponse.parse(raw).data.filter(isCodingApiModel); - return [...SMART_PROFILES, ...data]; + return RodiumResponse.parse(raw).data.filter(isCodingApiModel); }, translateModel(model, context) { - if (isSmartProfile(model)) { - return { - id: model.id, - model: buildSmartProfile(model, context.existing(model.id)), - }; - } return { id: model.id, model: buildRodiumVendorModel(model, context.existing(model.id)), }; }, -} satisfies SyncProvider; +} satisfies SyncProvider; export function isCodingApiModel(model: RodiumApiModel): boolean { const id = model.id.toLowerCase(); @@ -157,10 +114,6 @@ export function isCodingApiModel(model: RodiumApiModel): boolean { return true; } -function isSmartProfile(model: RodiumApiModel | SmartProfile): model is SmartProfile { - return !("created" in model); -} - function dateFromTimestamp(timestamp: number) { return new Date(timestamp * 1000).toISOString().slice(0, 10); } @@ -221,6 +174,22 @@ export function resolveRodiumBaseModel(apiID: string): string | undefined { return directCandidates.find((candidate) => metadataFileExists(candidate)); } +function openRouterProviderModel(apiID: string): Record | undefined { + if (openRouterProviderModels.has(apiID)) { + return openRouterProviderModels.get(apiID) ?? undefined; + } + + const filePath = path.join(OPENROUTER_PROVIDER_DIR, `${apiID}.toml`); + try { + const parsed = Bun.TOML.parse(readFileSync(filePath, "utf8")) as Record; + openRouterProviderModels.set(apiID, parsed); + return parsed; + } catch { + openRouterProviderModels.set(apiID, null); + return undefined; + } +} + function anthropicDirectProviderModel(baseModel: string): Record | undefined { if (!baseModel.startsWith("anthropic/")) return undefined; const slug = baseModel.slice("anthropic/".length); @@ -238,67 +207,85 @@ function anthropicDirectProviderModel(baseModel: string): Record { + return value !== null && typeof value === "object" && !Array.isArray(value); +} + function resolveReasoningOptions( + apiID: string, baseModel: string | undefined, existing: ExistingModel | undefined, -): ReasoningOption[] { - if (existing?.reasoning_options !== undefined) return existing.reasoning_options; - if (baseModel === undefined) return []; +): ReasoningOption[] | undefined { + if (existing?.reasoning_options !== undefined && existing.reasoning_options.length > 0) { + return existing.reasoning_options; + } + + const fromOpenRouter = openRouterProviderModel(apiID)?.reasoning_options; + if (Array.isArray(fromOpenRouter) && fromOpenRouter.length > 0) { + return fromOpenRouter as ReasoningOption[]; + } + + if (baseModel === undefined) return undefined; const direct = anthropicDirectProviderModel(baseModel); const options = direct?.reasoning_options; - if (Array.isArray(options)) return options as ReasoningOption[]; - return []; + if (Array.isArray(options) && options.length > 0) return options as ReasoningOption[]; + return undefined; } function resolveProviderTemperature( + apiID: string, baseModel: string | undefined, ): boolean | undefined { + const fromOpenRouter = openRouterProviderModel(apiID)?.temperature; + if (typeof fromOpenRouter === "boolean") return fromOpenRouter; if (baseModel === undefined) return undefined; const direct = anthropicDirectProviderModel(baseModel); return typeof direct?.temperature === "boolean" ? direct.temperature : undefined; } function resolveReasoningFlag( + apiID: string, baseModel: string | undefined, supportsReasoning: boolean | undefined, ): boolean | undefined { + const fromOpenRouter = openRouterProviderModel(apiID)?.reasoning; + if (typeof fromOpenRouter === "boolean") return fromOpenRouter; if (supportsReasoning === true) return true; - // RodiumAi's supports_reasoning flag is unreliable for adaptive-thinking models. - // When factoring a base model, inherit reasoning from models/ metadata instead. if (baseModel !== undefined) return undefined; return supportsReasoning === true ? true : false; } -export function buildSmartProfile( - profile: SmartProfile, - existing: ExistingModel | undefined, - today = new Date().toISOString().slice(0, 10), -): SyncedFullModel { - const releaseDate = existing?.release_date ?? today; - const changed = existing !== undefined && ( - existing.name !== profile.name - || existing.reasoning !== profile.reasoning - || existing.cost?.input !== profile.cost.input - || existing.cost?.output !== profile.cost.output - || existing.limit?.context !== profile.limit.context - || existing.limit?.output !== profile.limit.output - ); +function resolveProviderCost(apiID: string, existing: ExistingModel | undefined): ModelCost | undefined { + if (existing?.cost?.input !== undefined && existing.cost.output !== undefined) { + return existing.cost; + } + const fromOpenRouter = openRouterProviderModel(apiID)?.cost; + if (isPlainObject(fromOpenRouter) + && typeof fromOpenRouter.input === "number" + && typeof fromOpenRouter.output === "number") { + return fromOpenRouter as ModelCost; + } + return existing?.cost; +} - return { - name: profile.name, - family: "rodium-smart", - release_date: releaseDate, - last_updated: existing === undefined || changed ? today : (existing.last_updated ?? today), - attachment: false, - reasoning: profile.reasoning, - reasoning_options: existing?.reasoning_options ?? [], - temperature: true, - tool_call: true, - open_weights: false, - cost: profile.cost, - limit: profile.limit, - modalities: { input: ["text"], output: ["text"] }, - }; +function resolveOpenRouterBaseModel(apiID: string): string | undefined { + const reference = openRouterProviderModel(apiID); + return typeof reference?.base_model === "string" ? reference.base_model : undefined; +} + +function openRouterFactoredOverrides(apiID: string): Partial { + const reference = openRouterProviderModel(apiID); + if (reference === undefined) return {}; + + const overrides: Partial = {}; + if (typeof reference.structured_output === "boolean") { + overrides.structured_output = reference.structured_output; + } + if (typeof reference.tool_call === "boolean") overrides.tool_call = reference.tool_call; + if (reference.interleaved !== undefined) { + overrides.interleaved = reference.interleaved as SyncedFullModel["interleaved"]; + } + return overrides; } export function buildRodiumVendorModel( @@ -311,19 +298,31 @@ export function buildRodiumVendorModel( const input = modalities(caps.input_modalities ?? ["text"], ["text"]); const output = modalities(caps.output_modalities ?? ["text"], ["text"]); const attachment = input.some((value) => value !== "text") || caps.supports_vision === true; - const baseModel = existing?.base_model ?? resolveRodiumBaseModel(model.id); - const reasoning = resolveReasoningFlag(baseModel, caps.supports_reasoning); + const baseModel = existing?.base_model + ?? resolveRodiumBaseModel(model.id) + ?? resolveOpenRouterBaseModel(model.id); + const openRouterRef = openRouterProviderModel(model.id); + const reasoning = resolveReasoningFlag(model.id, baseModel, caps.supports_reasoning); const toolCall = caps.supports_tools === true; const structuredOutput = caps.supports_json_mode === true ? true : undefined; const releaseDate = existing?.release_date ?? dateFromTimestamp(model.created); const limit = { - context: caps.context_window ?? existing?.limit?.context ?? 128_000, + context: caps.context_window + ?? existing?.limit?.context + ?? (isPlainObject(openRouterRef?.limit) && typeof openRouterRef.limit.context === "number" + ? openRouterRef.limit.context + : 128_000), input: existing?.limit?.input, - output: caps.max_output_tokens ?? existing?.limit?.output ?? 32_768, + output: caps.max_output_tokens + ?? existing?.limit?.output + ?? (isPlainObject(openRouterRef?.limit) && typeof openRouterRef.limit.output === "number" + ? openRouterRef.limit.output + : 32_768), }; - const reasoningOptions = resolveReasoningOptions(baseModel, existing); - const temperature = resolveProviderTemperature(baseModel); - const cost = existing?.cost; + const reasoningOptions = resolveReasoningOptions(model.id, baseModel, existing); + const temperature = resolveProviderTemperature(model.id, baseModel); + const cost = resolveProviderCost(model.id, existing); + const referenceOverrides = openRouterFactoredOverrides(model.id); const changed = existing !== undefined && ( existing.name !== name || existing.reasoning !== reasoning @@ -337,13 +336,14 @@ export function buildRodiumVendorModel( return factorBaseModel( baseModel, { + ...referenceOverrides, name, - attachment, + attachment: typeof openRouterRef?.attachment === "boolean" ? openRouterRef.attachment : attachment, reasoning, reasoning_options: reasoningOptions, temperature, - tool_call: toolCall, - structured_output: structuredOutput, + tool_call: referenceOverrides.tool_call ?? toolCall, + structured_output: referenceOverrides.structured_output ?? structuredOutput, last_updated: existing === undefined || changed ? today : (existing.last_updated ?? today), cost, limit, @@ -354,6 +354,31 @@ export function buildRodiumVendorModel( ); } + if (openRouterRef !== undefined && openRouterRef.base_model === undefined) { + return { + name: typeof openRouterRef.name === "string" ? openRouterRef.name : name, + family: existing?.family + ?? (typeof openRouterRef.family === "string" ? openRouterRef.family : inferFamily(model.id.split("/").slice(1).join("/"), name)), + release_date: typeof openRouterRef.release_date === "string" ? openRouterRef.release_date : releaseDate, + last_updated: existing === undefined || changed ? today : (existing.last_updated ?? today), + attachment: typeof openRouterRef.attachment === "boolean" ? openRouterRef.attachment : attachment, + reasoning: typeof openRouterRef.reasoning === "boolean" ? openRouterRef.reasoning : (reasoning ?? false), + reasoning_options: reasoningOptions ?? (Array.isArray(openRouterRef.reasoning_options) + ? openRouterRef.reasoning_options as ReasoningOption[] + : []), + temperature: typeof openRouterRef.temperature === "boolean" ? openRouterRef.temperature : (temperature ?? true), + tool_call: typeof openRouterRef.tool_call === "boolean" ? openRouterRef.tool_call : toolCall, + structured_output: typeof openRouterRef.structured_output === "boolean" + ? openRouterRef.structured_output + : structuredOutput, + knowledge: typeof openRouterRef.knowledge === "string" ? openRouterRef.knowledge : existing?.knowledge, + open_weights: typeof openRouterRef.open_weights === "boolean" ? openRouterRef.open_weights : false, + cost: cost ?? (isPlainObject(openRouterRef.cost) ? openRouterRef.cost as ModelCost : undefined), + limit, + modalities: { input, output }, + } satisfies SyncedFullModel; + } + return { name, family: existing?.family ?? inferFamily(model.id.split("/").slice(1).join("/"), name), @@ -361,7 +386,7 @@ export function buildRodiumVendorModel( last_updated: existing === undefined || changed ? today : (existing.last_updated ?? today), attachment, reasoning: reasoning ?? false, - reasoning_options: reasoningOptions, + reasoning_options: reasoningOptions ?? [], temperature: temperature ?? true, tool_call: toolCall, structured_output: structuredOutput, diff --git a/packages/core/test/rodiumai-sync.test.ts b/packages/core/test/rodiumai-sync.test.ts index 8299ae5db2..b44553d695 100644 --- a/packages/core/test/rodiumai-sync.test.ts +++ b/packages/core/test/rodiumai-sync.test.ts @@ -2,7 +2,6 @@ import { expect, test } from "bun:test"; import { buildRodiumVendorModel, - buildSmartProfile, isCodingApiModel, resolveRodiumBaseModel, rodiumai, @@ -57,19 +56,6 @@ test("RodiumAi filters non-coding models", () => { })).toBe(false); }); -test("RodiumAi smart profiles declare reasoning_options", () => { - const synced = buildSmartProfile({ - id: "pro", - name: "Pro", - reasoning: true, - cost: { input: 0.3, output: 2.5 }, - limit: { context: 1_000_000, output: 32_000 }, - }, undefined, "2026-06-12"); - - expect(synced.reasoning_options).toEqual([]); - expect(synced.family).toBe("rodium-smart"); -}); - test("RodiumAi vendor models inherit anthropic reasoning_options from direct provider", () => { const synced = buildRodiumVendorModel(vendorModel, { cost: { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 }, diff --git a/providers/rodiumai/models/anthropic/claude-fable-5.toml b/providers/rodiumai/models/anthropic/claude-fable-5.toml index 9b834b3685..70a556bd86 100644 --- a/providers/rodiumai/models/anthropic/claude-fable-5.toml +++ b/providers/rodiumai/models/anthropic/claude-fable-5.toml @@ -5,3 +5,9 @@ structured_output = true [[reasoning_options]] type = "effort" values = ["low", "medium", "high", "xhigh", "max"] + +[cost] +input = 10 +output = 50 +cache_read = 1 +cache_write = 12.5 diff --git a/providers/rodiumai/models/auto.toml b/providers/rodiumai/models/auto.toml deleted file mode 100644 index 33881fa408..0000000000 --- a/providers/rodiumai/models/auto.toml +++ /dev/null @@ -1,22 +0,0 @@ -name = "Auto (RodiumAI Smart Routing)" -family = "rodium-smart" -release_date = "2026-06-12" -last_updated = "2026-06-12" -attachment = false -reasoning = false -temperature = true -tool_call = true -open_weights = false -reasoning_options = [] - -[cost] -input = 0.3 -output = 2.5 - -[limit] -context = 1_000_000 -output = 32_000 - -[modalities] -input = ["text"] -output = ["text"] diff --git a/providers/rodiumai/models/basic.toml b/providers/rodiumai/models/basic.toml deleted file mode 100644 index 703bbc2646..0000000000 --- a/providers/rodiumai/models/basic.toml +++ /dev/null @@ -1,22 +0,0 @@ -name = "Basic" -family = "rodium-smart" -release_date = "2026-06-12" -last_updated = "2026-06-12" -attachment = false -reasoning = false -temperature = true -tool_call = true -open_weights = false -reasoning_options = [] - -[cost] -input = 0.05 -output = 0.08 - -[limit] -context = 128_000 -output = 8_192 - -[modalities] -input = ["text"] -output = ["text"] diff --git a/providers/rodiumai/models/deepseek/deepseek-v3.2.toml b/providers/rodiumai/models/deepseek/deepseek-v3.2.toml index 5f46fd8bd5..6807baec50 100644 --- a/providers/rodiumai/models/deepseek/deepseek-v3.2.toml +++ b/providers/rodiumai/models/deepseek/deepseek-v3.2.toml @@ -1,14 +1,21 @@ name = "DeepSeek V3.2" family = "deepseek" -release_date = "2026-06-09" +release_date = "2025-12-01" last_updated = "2026-06-12" attachment = false -reasoning = false +reasoning = true temperature = true tool_call = true structured_output = true -open_weights = false -reasoning_options = [] +knowledge = "2024-07" +open_weights = true + +[[reasoning_options]] +type = "toggle" + +[cost] +input = 0.2288 +output = 0.3432 [limit] context = 164_000 diff --git a/providers/rodiumai/models/deepseek/deepseek-v4-flash.toml b/providers/rodiumai/models/deepseek/deepseek-v4-flash.toml index 8edea9bb5c..6c91b9a25d 100644 --- a/providers/rodiumai/models/deepseek/deepseek-v4-flash.toml +++ b/providers/rodiumai/models/deepseek/deepseek-v4-flash.toml @@ -1,3 +1,17 @@ base_model = "deepseek/deepseek-v4-flash" last_updated = "2026-06-12" -reasoning_options = [] + +[[reasoning_options]] +type = "toggle" + +[[reasoning_options]] +type = "effort" +values = ["high", "xhigh"] + +[interleaved] +field = "reasoning_content" + +[cost] +input = 0.0983 +output = 0.1966 +cache_read = 0.0197 diff --git a/providers/rodiumai/models/deepseek/deepseek-v4-pro.toml b/providers/rodiumai/models/deepseek/deepseek-v4-pro.toml index c2f777e5af..9ac571dbc9 100644 --- a/providers/rodiumai/models/deepseek/deepseek-v4-pro.toml +++ b/providers/rodiumai/models/deepseek/deepseek-v4-pro.toml @@ -1,3 +1,17 @@ base_model = "deepseek/deepseek-v4-pro" last_updated = "2026-06-12" -reasoning_options = [] + +[[reasoning_options]] +type = "toggle" + +[[reasoning_options]] +type = "effort" +values = ["high", "xhigh"] + +[interleaved] +field = "reasoning_content" + +[cost] +input = 0.435 +output = 0.87 +cache_read = 0.003625 diff --git a/providers/rodiumai/models/fast.toml b/providers/rodiumai/models/fast.toml deleted file mode 100644 index e995132797..0000000000 --- a/providers/rodiumai/models/fast.toml +++ /dev/null @@ -1,22 +0,0 @@ -name = "Fast" -family = "rodium-smart" -release_date = "2026-06-12" -last_updated = "2026-06-12" -attachment = false -reasoning = false -temperature = true -tool_call = true -open_weights = false -reasoning_options = [] - -[cost] -input = 0.11 -output = 0.34 - -[limit] -context = 128_000 -output = 16_384 - -[modalities] -input = ["text"] -output = ["text"] diff --git a/providers/rodiumai/models/google/gemini-2.5-flash-lite.toml b/providers/rodiumai/models/google/gemini-2.5-flash-lite.toml index 5edf31d4f3..3bf6914e81 100644 --- a/providers/rodiumai/models/google/gemini-2.5-flash-lite.toml +++ b/providers/rodiumai/models/google/gemini-2.5-flash-lite.toml @@ -1,7 +1,20 @@ base_model = "google/gemini-2.5-flash-lite" last_updated = "2026-06-12" -reasoning = false -reasoning_options = [] + +[[reasoning_options]] +type = "toggle" + +[[reasoning_options]] +type = "budget_tokens" +min = 512 +max = 24_576 + +[cost] +input = 0.1 +output = 0.4 +reasoning = 0.4 +cache_read = 0.01 +cache_write = 0.083333 [limit] context = 1_000_000 diff --git a/providers/rodiumai/models/google/gemini-2.5-flash.toml b/providers/rodiumai/models/google/gemini-2.5-flash.toml index 106c6491b6..5d02519d11 100644 --- a/providers/rodiumai/models/google/gemini-2.5-flash.toml +++ b/providers/rodiumai/models/google/gemini-2.5-flash.toml @@ -1,6 +1,20 @@ base_model = "google/gemini-2.5-flash" last_updated = "2026-06-12" -reasoning_options = [] + +[[reasoning_options]] +type = "toggle" + +[[reasoning_options]] +type = "budget_tokens" +min = 0 +max = 24_576 + +[cost] +input = 0.3 +output = 2.5 +reasoning = 2.5 +cache_read = 0.03 +cache_write = 0.083333 [limit] context = 1_000_000 diff --git a/providers/rodiumai/models/google/gemini-2.5-pro.toml b/providers/rodiumai/models/google/gemini-2.5-pro.toml index 31c37e8e6c..3bb514690f 100644 --- a/providers/rodiumai/models/google/gemini-2.5-pro.toml +++ b/providers/rodiumai/models/google/gemini-2.5-pro.toml @@ -1,6 +1,17 @@ base_model = "google/gemini-2.5-pro" last_updated = "2026-06-12" -reasoning_options = [] + +[[reasoning_options]] +type = "budget_tokens" +min = 128 +max = 32_768 + +[cost] +input = 1.25 +output = 10 +reasoning = 10 +cache_read = 0.125 +cache_write = 0.375 [limit] context = 1_000_000 diff --git a/providers/rodiumai/models/google/gemini-3.1-flash-lite.toml b/providers/rodiumai/models/google/gemini-3.1-flash-lite.toml index 6b66f53179..e5b8f3631c 100644 --- a/providers/rodiumai/models/google/gemini-3.1-flash-lite.toml +++ b/providers/rodiumai/models/google/gemini-3.1-flash-lite.toml @@ -1,7 +1,17 @@ base_model = "google/gemini-3.1-flash-lite" name = "Gemini 3.1 Flash-Lite" last_updated = "2026-06-12" -reasoning_options = [] + +[[reasoning_options]] +type = "effort" +values = ["minimal", "low", "medium", "high"] + +[cost] +input = 0.25 +output = 1.5 +reasoning = 1.5 +cache_read = 0.025 +cache_write = 0.083333 [limit] context = 1_000_000 diff --git a/providers/rodiumai/models/google/gemini-3.1-pro-preview.toml b/providers/rodiumai/models/google/gemini-3.1-pro-preview.toml index 4538c578e1..e25f7e0330 100644 --- a/providers/rodiumai/models/google/gemini-3.1-pro-preview.toml +++ b/providers/rodiumai/models/google/gemini-3.1-pro-preview.toml @@ -1,6 +1,25 @@ base_model = "google/gemini-3.1-pro-preview" last_updated = "2026-06-12" -reasoning_options = [] + +[[reasoning_options]] +type = "effort" +values = ["low", "medium", "high"] + +[interleaved] +field = "reasoning_details" + +[cost] +input = 2 +output = 12 +reasoning = 12 +cache_read = 0.2 +cache_write = 0.375 + +[[cost.tiers]] +tier = { type = "context", size = 200_000 } +input = 4 +output = 18 +cache_read = 0.4 [limit] context = 2_000_000 diff --git a/providers/rodiumai/models/google/gemini-3.5-flash.toml b/providers/rodiumai/models/google/gemini-3.5-flash.toml index 00cff62fa8..2f92076bb7 100644 --- a/providers/rodiumai/models/google/gemini-3.5-flash.toml +++ b/providers/rodiumai/models/google/gemini-3.5-flash.toml @@ -1,6 +1,16 @@ base_model = "google/gemini-3.5-flash" last_updated = "2026-06-12" -reasoning_options = [] + +[[reasoning_options]] +type = "effort" +values = ["minimal", "low", "medium", "high"] + +[cost] +input = 1.5 +output = 9 +reasoning = 9 +cache_read = 0.15 +cache_write = 0.083333 [limit] context = 1_000_000 diff --git a/providers/rodiumai/models/max.toml b/providers/rodiumai/models/max.toml deleted file mode 100644 index 9541e84b00..0000000000 --- a/providers/rodiumai/models/max.toml +++ /dev/null @@ -1,22 +0,0 @@ -name = "Max" -family = "rodium-smart" -release_date = "2026-06-12" -last_updated = "2026-06-12" -attachment = false -reasoning = true -temperature = true -tool_call = true -open_weights = false -reasoning_options = [] - -[cost] -input = 3 -output = 15 - -[limit] -context = 200_000 -output = 16_384 - -[modalities] -input = ["text"] -output = ["text"] diff --git a/providers/rodiumai/models/minimax/minimax-m2-5.toml b/providers/rodiumai/models/minimax/minimax-m2-5.toml index fe303e221c..a180fa8a3e 100644 --- a/providers/rodiumai/models/minimax/minimax-m2-5.toml +++ b/providers/rodiumai/models/minimax/minimax-m2-5.toml @@ -2,7 +2,6 @@ base_model = "minimax/MiniMax-M2.5" name = "MiniMax M2.5" last_updated = "2026-06-12" attachment = true -reasoning = false structured_output = true reasoning_options = [] diff --git a/providers/rodiumai/models/minimax/minimax-m2-7.toml b/providers/rodiumai/models/minimax/minimax-m2-7.toml index a2adf6252d..05208da415 100644 --- a/providers/rodiumai/models/minimax/minimax-m2-7.toml +++ b/providers/rodiumai/models/minimax/minimax-m2-7.toml @@ -2,7 +2,6 @@ base_model = "minimax/MiniMax-M2.7" name = "MiniMax M2.7" last_updated = "2026-06-12" attachment = true -reasoning = false structured_output = true reasoning_options = [] diff --git a/providers/rodiumai/models/moonshot-ai/kimi-k2.5.toml b/providers/rodiumai/models/moonshot-ai/kimi-k2.5.toml index 7d38226e42..56ae87e9bf 100644 --- a/providers/rodiumai/models/moonshot-ai/kimi-k2.5.toml +++ b/providers/rodiumai/models/moonshot-ai/kimi-k2.5.toml @@ -1,7 +1,6 @@ base_model = "moonshotai/kimi-k2.5" last_updated = "2026-06-12" attachment = true -temperature = true reasoning_options = [] [modalities] diff --git a/providers/rodiumai/models/openai/gpt-4.1-mini.toml b/providers/rodiumai/models/openai/gpt-4.1-mini.toml index 77f121eea5..0780bc3c01 100644 --- a/providers/rodiumai/models/openai/gpt-4.1-mini.toml +++ b/providers/rodiumai/models/openai/gpt-4.1-mini.toml @@ -3,6 +3,11 @@ name = "GPT-4.1 Mini" last_updated = "2026-06-12" reasoning_options = [] +[cost] +input = 0.4 +output = 1.6 +cache_read = 0.1 + [limit] context = 1_000_000 output = 16_384 diff --git a/providers/rodiumai/models/openai/gpt-4.1-nano.toml b/providers/rodiumai/models/openai/gpt-4.1-nano.toml index 379d2bf16e..41a7efde22 100644 --- a/providers/rodiumai/models/openai/gpt-4.1-nano.toml +++ b/providers/rodiumai/models/openai/gpt-4.1-nano.toml @@ -3,6 +3,11 @@ name = "GPT-4.1 Nano" last_updated = "2026-06-12" reasoning_options = [] +[cost] +input = 0.1 +output = 0.4 +cache_read = 0.025 + [limit] context = 1_000_000 output = 16_384 diff --git a/providers/rodiumai/models/openai/gpt-4.1.toml b/providers/rodiumai/models/openai/gpt-4.1.toml index 42303dfb02..27647a923f 100644 --- a/providers/rodiumai/models/openai/gpt-4.1.toml +++ b/providers/rodiumai/models/openai/gpt-4.1.toml @@ -2,5 +2,10 @@ base_model = "openai/gpt-4.1" last_updated = "2026-06-12" reasoning_options = [] +[cost] +input = 2 +output = 8 +cache_read = 0.5 + [limit] context = 1_000_000 diff --git a/providers/rodiumai/models/openai/gpt-4o-mini.toml b/providers/rodiumai/models/openai/gpt-4o-mini.toml index 1e0868643a..339d5c3239 100644 --- a/providers/rodiumai/models/openai/gpt-4o-mini.toml +++ b/providers/rodiumai/models/openai/gpt-4o-mini.toml @@ -3,5 +3,10 @@ name = "GPT-4o Mini" last_updated = "2026-06-12" reasoning_options = [] +[cost] +input = 0.15 +output = 0.6 +cache_read = 0.075 + [modalities] input = ["text", "image"] diff --git a/providers/rodiumai/models/openai/gpt-4o.toml b/providers/rodiumai/models/openai/gpt-4o.toml index ce3ac7a55b..8069eb480f 100644 --- a/providers/rodiumai/models/openai/gpt-4o.toml +++ b/providers/rodiumai/models/openai/gpt-4o.toml @@ -2,6 +2,10 @@ base_model = "openai/gpt-4o" last_updated = "2026-06-12" reasoning_options = [] +[cost] +input = 2.5 +output = 10 + [modalities] input = ["text", "image", "audio"] output = ["text", "audio"] diff --git a/providers/rodiumai/models/openai/gpt-5-mini.toml b/providers/rodiumai/models/openai/gpt-5-mini.toml index d2d796a5c1..63c69b64da 100644 --- a/providers/rodiumai/models/openai/gpt-5-mini.toml +++ b/providers/rodiumai/models/openai/gpt-5-mini.toml @@ -1,8 +1,15 @@ base_model = "openai/gpt-5-mini" base_model_omit = ["limit.input"] last_updated = "2026-06-12" -temperature = true -reasoning_options = [] + +[[reasoning_options]] +type = "effort" +values = ["minimal", "low", "medium", "high"] + +[cost] +input = 0.25 +output = 2 +cache_read = 0.025 [limit] context = 272_000 diff --git a/providers/rodiumai/models/openai/gpt-5-nano.toml b/providers/rodiumai/models/openai/gpt-5-nano.toml index 0c6d84e372..784de51b9b 100644 --- a/providers/rodiumai/models/openai/gpt-5-nano.toml +++ b/providers/rodiumai/models/openai/gpt-5-nano.toml @@ -1,8 +1,15 @@ base_model = "openai/gpt-5-nano" base_model_omit = ["limit.input"] last_updated = "2026-06-12" -temperature = true -reasoning_options = [] + +[[reasoning_options]] +type = "effort" +values = ["minimal", "low", "medium", "high"] + +[cost] +input = 0.05 +output = 0.4 +cache_read = 0.01 [limit] context = 272_000 diff --git a/providers/rodiumai/models/openai/gpt-5-pro.toml b/providers/rodiumai/models/openai/gpt-5-pro.toml index 7e696b302a..9ef4f22b55 100644 --- a/providers/rodiumai/models/openai/gpt-5-pro.toml +++ b/providers/rodiumai/models/openai/gpt-5-pro.toml @@ -1,9 +1,12 @@ base_model = "openai/gpt-5-pro" base_model_omit = ["limit.input"] last_updated = "2026-06-12" -temperature = true reasoning_options = [] +[cost] +input = 15 +output = 120 + [limit] context = 272_000 output = 32_768 diff --git a/providers/rodiumai/models/openai/gpt-5.3-codex.toml b/providers/rodiumai/models/openai/gpt-5.3-codex.toml index 83a7687b62..9256ea8801 100644 --- a/providers/rodiumai/models/openai/gpt-5.3-codex.toml +++ b/providers/rodiumai/models/openai/gpt-5.3-codex.toml @@ -1,8 +1,15 @@ base_model = "openai/gpt-5.3-codex" base_model_omit = ["limit.input"] last_updated = "2026-06-12" -temperature = true -reasoning_options = [] + +[[reasoning_options]] +type = "effort" +values = ["low", "medium", "high", "xhigh"] + +[cost] +input = 1.75 +output = 14 +cache_read = 0.175 [limit] context = 272_000 diff --git a/providers/rodiumai/models/openai/gpt-5.4-mini.toml b/providers/rodiumai/models/openai/gpt-5.4-mini.toml index b7fdb670a9..75039b03ba 100644 --- a/providers/rodiumai/models/openai/gpt-5.4-mini.toml +++ b/providers/rodiumai/models/openai/gpt-5.4-mini.toml @@ -2,8 +2,15 @@ base_model = "openai/gpt-5.4-mini" base_model_omit = ["limit.input"] name = "GPT-5.4 Mini" last_updated = "2026-06-12" -temperature = true -reasoning_options = [] + +[[reasoning_options]] +type = "effort" +values = ["none", "low", "medium", "high", "xhigh"] + +[cost] +input = 0.75 +output = 4.5 +cache_read = 0.075 [limit] context = 1_100_000 diff --git a/providers/rodiumai/models/openai/gpt-5.4-nano.toml b/providers/rodiumai/models/openai/gpt-5.4-nano.toml index 7521f34b64..124b217e85 100644 --- a/providers/rodiumai/models/openai/gpt-5.4-nano.toml +++ b/providers/rodiumai/models/openai/gpt-5.4-nano.toml @@ -2,8 +2,15 @@ base_model = "openai/gpt-5.4-nano" base_model_omit = ["limit.input"] name = "GPT-5.4 Nano" last_updated = "2026-06-12" -temperature = true -reasoning_options = [] + +[[reasoning_options]] +type = "effort" +values = ["none", "low", "medium", "high", "xhigh"] + +[cost] +input = 0.2 +output = 1.25 +cache_read = 0.02 [limit] context = 1_100_000 diff --git a/providers/rodiumai/models/openai/gpt-5.4-pro.toml b/providers/rodiumai/models/openai/gpt-5.4-pro.toml index bd87cb4381..32a8f9a27b 100644 --- a/providers/rodiumai/models/openai/gpt-5.4-pro.toml +++ b/providers/rodiumai/models/openai/gpt-5.4-pro.toml @@ -1,10 +1,15 @@ base_model = "openai/gpt-5.4-pro" base_model_omit = ["limit.input"] last_updated = "2026-06-12" -reasoning = false -temperature = true structured_output = true -reasoning_options = [] + +[[reasoning_options]] +type = "effort" +values = ["medium", "high", "xhigh"] + +[cost] +input = 30 +output = 180 [limit] context = 1_000_000 diff --git a/providers/rodiumai/models/openai/gpt-5.4.toml b/providers/rodiumai/models/openai/gpt-5.4.toml index b665c18e7b..852ad628b6 100644 --- a/providers/rodiumai/models/openai/gpt-5.4.toml +++ b/providers/rodiumai/models/openai/gpt-5.4.toml @@ -1,8 +1,15 @@ base_model = "openai/gpt-5.4" base_model_omit = ["limit.input"] last_updated = "2026-06-12" -temperature = true -reasoning_options = [] + +[[reasoning_options]] +type = "effort" +values = ["none", "low", "medium", "high", "xhigh"] + +[cost] +input = 2.5 +output = 15 +cache_read = 0.25 [limit] context = 1_100_000 diff --git a/providers/rodiumai/models/openai/gpt-5.5-pro.toml b/providers/rodiumai/models/openai/gpt-5.5-pro.toml index f4fe7cfee1..15bae32296 100644 --- a/providers/rodiumai/models/openai/gpt-5.5-pro.toml +++ b/providers/rodiumai/models/openai/gpt-5.5-pro.toml @@ -1,5 +1,10 @@ base_model = "openai/gpt-5.5-pro" last_updated = "2026-06-12" -reasoning = false -temperature = true -reasoning_options = [] + +[[reasoning_options]] +type = "effort" +values = ["medium", "high", "xhigh"] + +[cost] +input = 30 +output = 180 diff --git a/providers/rodiumai/models/openai/gpt-5.5.toml b/providers/rodiumai/models/openai/gpt-5.5.toml index 48038d36ce..4f5895fd5c 100644 --- a/providers/rodiumai/models/openai/gpt-5.5.toml +++ b/providers/rodiumai/models/openai/gpt-5.5.toml @@ -1,5 +1,11 @@ base_model = "openai/gpt-5.5" last_updated = "2026-06-12" -reasoning = false -temperature = true -reasoning_options = [] + +[[reasoning_options]] +type = "effort" +values = ["none", "low", "medium", "high", "xhigh"] + +[cost] +input = 5 +output = 30 +cache_read = 0.5 diff --git a/providers/rodiumai/models/openai/gpt-5.toml b/providers/rodiumai/models/openai/gpt-5.toml index 4198954a85..c5fb3d14b7 100644 --- a/providers/rodiumai/models/openai/gpt-5.toml +++ b/providers/rodiumai/models/openai/gpt-5.toml @@ -1,8 +1,15 @@ base_model = "openai/gpt-5" base_model_omit = ["limit.input"] last_updated = "2026-06-12" -temperature = true -reasoning_options = [] + +[[reasoning_options]] +type = "effort" +values = ["minimal", "low", "medium", "high"] + +[cost] +input = 1.25 +output = 10 +cache_read = 0.125 [limit] context = 272_000 diff --git a/providers/rodiumai/models/openai/o3-mini.toml b/providers/rodiumai/models/openai/o3-mini.toml index 94cd3bfb2c..880d5f4504 100644 --- a/providers/rodiumai/models/openai/o3-mini.toml +++ b/providers/rodiumai/models/openai/o3-mini.toml @@ -1,4 +1,12 @@ base_model = "openai/o3-mini" last_updated = "2026-06-12" -temperature = true -reasoning_options = [] +attachment = true + +[[reasoning_options]] +type = "effort" +values = ["low", "medium", "high"] + +[cost] +input = 1.1 +output = 4.4 +cache_read = 0.55 diff --git a/providers/rodiumai/models/openai/o3-pro.toml b/providers/rodiumai/models/openai/o3-pro.toml index 81c8d7e9ea..7274deab0e 100644 --- a/providers/rodiumai/models/openai/o3-pro.toml +++ b/providers/rodiumai/models/openai/o3-pro.toml @@ -1,8 +1,14 @@ base_model = "openai/o3-pro" name = "o3 Pro" last_updated = "2026-06-12" -temperature = true -reasoning_options = [] + +[[reasoning_options]] +type = "effort" +values = ["low", "medium", "high"] + +[cost] +input = 20 +output = 80 [modalities] input = ["text", "image", "pdf"] diff --git a/providers/rodiumai/models/openai/o3.toml b/providers/rodiumai/models/openai/o3.toml index 0fb4c30a67..8746145ee2 100644 --- a/providers/rodiumai/models/openai/o3.toml +++ b/providers/rodiumai/models/openai/o3.toml @@ -1,4 +1,11 @@ base_model = "openai/o3" last_updated = "2026-06-12" -temperature = true -reasoning_options = [] + +[[reasoning_options]] +type = "effort" +values = ["low", "medium", "high"] + +[cost] +input = 2 +output = 8 +cache_read = 0.5 diff --git a/providers/rodiumai/models/openai/o4-mini.toml b/providers/rodiumai/models/openai/o4-mini.toml index f45f6fbcb5..a14b271ea5 100644 --- a/providers/rodiumai/models/openai/o4-mini.toml +++ b/providers/rodiumai/models/openai/o4-mini.toml @@ -1,4 +1,11 @@ base_model = "openai/o4-mini" last_updated = "2026-06-12" -temperature = true -reasoning_options = [] + +[[reasoning_options]] +type = "effort" +values = ["low", "medium", "high"] + +[cost] +input = 1.1 +output = 4.4 +cache_read = 0.275 diff --git a/providers/rodiumai/models/pro.toml b/providers/rodiumai/models/pro.toml deleted file mode 100644 index 17a5b9eba6..0000000000 --- a/providers/rodiumai/models/pro.toml +++ /dev/null @@ -1,22 +0,0 @@ -name = "Pro" -family = "rodium-smart" -release_date = "2026-06-12" -last_updated = "2026-06-12" -attachment = false -reasoning = true -temperature = true -tool_call = true -open_weights = false -reasoning_options = [] - -[cost] -input = 0.3 -output = 2.5 - -[limit] -context = 1_000_000 -output = 32_000 - -[modalities] -input = ["text"] -output = ["text"]