From fb890b8d55e008996cee320c4488bbd320bf3d6e Mon Sep 17 00:00:00 2001 From: Aiden Cline Date: Mon, 8 Jun 2026 20:16:50 -0500 Subject: [PATCH 1/3] feat(venice): add reasoning options --- packages/core/script/generate-venice.ts | 60 +++++++++++++++++-- packages/core/test/venice-generator.test.ts | 58 ++++++++++++++++++ .../venice/models/aion-labs-aion-2-0.toml | 1 + .../models/arcee-trinity-large-thinking.toml | 1 + providers/venice/models/claude-opus-4-5.toml | 1 + .../venice/models/claude-opus-4-6-fast.toml | 1 + providers/venice/models/claude-opus-4-6.toml | 1 + .../venice/models/claude-opus-4-7-fast.toml | 1 + providers/venice/models/claude-opus-4-7.toml | 1 + .../venice/models/claude-opus-4-8-fast.toml | 1 + providers/venice/models/claude-opus-4-8.toml | 1 + .../venice/models/claude-sonnet-4-5.toml | 1 + .../venice/models/claude-sonnet-4-6.toml | 1 + providers/venice/models/deepseek-v3.2.toml | 1 + .../venice/models/deepseek-v4-flash.toml | 1 + providers/venice/models/deepseek-v4-pro.toml | 1 + .../venice/models/gemini-3-1-pro-preview.toml | 1 + providers/venice/models/gemini-3-5-flash.toml | 1 + .../venice/models/gemini-3-flash-preview.toml | 1 + .../models/google-gemma-4-26b-a4b-it.toml | 1 + .../venice/models/google-gemma-4-31b-it.toml | 1 + .../venice/models/grok-4-20-multi-agent.toml | 1 + providers/venice/models/grok-4-20.toml | 1 + providers/venice/models/grok-4-3.toml | 1 + providers/venice/models/grok-build-0-1.toml | 1 + providers/venice/models/kimi-k2-5.toml | 1 + providers/venice/models/kimi-k2-6.toml | 1 + providers/venice/models/mercury-2.toml | 1 + providers/venice/models/minimax-m25.toml | 1 + providers/venice/models/minimax-m27.toml | 1 + providers/venice/models/minimax-m3.toml | 1 + .../venice/models/mistral-small-2603.toml | 1 + .../nvidia-nemotron-3-ultra-550b-a55b.toml | 1 + .../nvidia-nemotron-cascade-2-30b-a3b.toml | 1 + .../olafangensan-glm-4.7-flash-heretic.toml | 1 + .../venice/models/openai-gpt-52-codex.toml | 1 + providers/venice/models/openai-gpt-52.toml | 1 + .../venice/models/openai-gpt-53-codex.toml | 1 + .../venice/models/openai-gpt-54-mini.toml | 1 + .../venice/models/openai-gpt-54-pro.toml | 1 + providers/venice/models/openai-gpt-54.toml | 1 + .../venice/models/openai-gpt-55-pro.toml | 1 + providers/venice/models/openai-gpt-55.toml | 1 + .../venice/models/openai-gpt-oss-120b.toml | 1 + providers/venice/models/qwen-3-6-plus.toml | 1 + providers/venice/models/qwen-3-7-max.toml | 1 + providers/venice/models/qwen-3-7-plus.toml | 1 + .../models/qwen3-235b-a22b-thinking-2507.toml | 1 + providers/venice/models/qwen3-5-35b-a3b.toml | 1 + .../venice/models/qwen3-5-397b-a17b.toml | 1 + providers/venice/models/qwen3-5-9b.toml | 1 + providers/venice/models/qwen3-6-27b.toml | 1 + providers/venice/models/z-ai-glm-5-turbo.toml | 1 + .../venice/models/z-ai-glm-5v-turbo.toml | 1 + providers/venice/models/zai-org-glm-4.6.toml | 1 + .../venice/models/zai-org-glm-4.7-flash.toml | 1 + providers/venice/models/zai-org-glm-4.7.toml | 1 + providers/venice/models/zai-org-glm-5-1.toml | 1 + providers/venice/models/zai-org-glm-5.toml | 1 + 59 files changed, 169 insertions(+), 6 deletions(-) create mode 100644 packages/core/test/venice-generator.test.ts diff --git a/packages/core/script/generate-venice.ts b/packages/core/script/generate-venice.ts index caad0fb91..038f4e565 100644 --- a/packages/core/script/generate-venice.ts +++ b/packages/core/script/generate-venice.ts @@ -9,6 +9,8 @@ import { ModelFamilyValues } from "../src/family.js"; const API_ENDPOINT = "https://api.venice.ai/api/v1/models?type=text"; // Zod schemas for API response validation +const ReasoningEffort = z.enum(["none", "minimal", "low", "medium", "high", "xhigh", "max"]); + const Capabilities = z .object({ optimizedForCode: z.boolean().optional(), @@ -17,12 +19,31 @@ const Capabilities = z supportsFunctionCalling: z.boolean().optional(), supportsLogProbs: z.boolean().optional(), supportsReasoning: z.boolean().optional(), + supportsReasoningEffort: z.boolean(), + reasoningEffortOptions: z.array(ReasoningEffort).optional(), + defaultReasoningEffort: ReasoningEffort.optional(), supportsResponseSchema: z.boolean().optional(), supportsVideoInput: z.boolean().optional(), supportsVision: z.boolean().optional(), supportsWebSearch: z.boolean().optional(), }) - .passthrough(); + .passthrough() + .superRefine((capabilities, context) => { + if (capabilities.supportsReasoningEffort && capabilities.reasoningEffortOptions === undefined) { + context.addIssue({ + code: z.ZodIssueCode.custom, + path: ["reasoningEffortOptions"], + message: "Reasoning effort options are required when reasoning effort is supported", + }); + } + if (capabilities.supportsReasoningEffort && capabilities.defaultReasoningEffort === undefined) { + context.addIssue({ + code: z.ZodIssueCode.custom, + path: ["defaultReasoningEffort"], + message: "Default reasoning effort is required when reasoning effort is supported", + }); + } + }); const PricingTier = z.object({ usd: z.number(), diem: z.number().optional() }).passthrough(); @@ -142,6 +163,10 @@ interface ExistingModel { family?: string; attachment?: boolean; reasoning?: boolean; + reasoning_options?: Array<{ + type: "effort"; + values: Array>; + }>; tool_call?: boolean; structured_output?: boolean; temperature?: boolean; @@ -235,6 +260,10 @@ interface MergedModel { family?: string; attachment: boolean; reasoning: boolean; + reasoning_options?: Array<{ + type: "effort"; + values: Array>; + }>; tool_call: boolean; structured_output?: boolean; temperature: boolean; @@ -267,7 +296,7 @@ interface MergedModel { }; } -function mergeModel( +export function mergeModel( apiModel: z.infer, existing: ExistingModel | null, ): MergedModel { @@ -309,6 +338,12 @@ function mergeModel( }, }; + if (merged.reasoning) { + merged.reasoning_options = caps.supportsReasoningEffort === true + ? [{ type: "effort", values: caps.reasoningEffortOptions ?? [] }] + : []; + } + // structured_output only if true if (caps.supportsResponseSchema === true) { merged.structured_output = true; @@ -352,7 +387,7 @@ function mergeModel( return merged; } -function formatToml(model: MergedModel): string { +export function formatToml(model: MergedModel): string { const lines: string[] = []; // Basic fields @@ -362,6 +397,9 @@ function formatToml(model: MergedModel): string { } lines.push(`attachment = ${model.attachment}`); lines.push(`reasoning = ${model.reasoning}`); + if (model.reasoning_options?.length === 0) { + lines.push("reasoning_options = []"); + } lines.push(`tool_call = ${model.tool_call}`); if (model.structured_output !== undefined) { lines.push(`structured_output = ${model.structured_output}`); @@ -377,6 +415,13 @@ function formatToml(model: MergedModel): string { lines.push(`status = "${model.status}"`); } + for (const option of model.reasoning_options ?? []) { + lines.push(""); + lines.push("[[reasoning_options]]"); + lines.push(`type = "${option.type}"`); + lines.push(`values = [${option.values.map((value) => `"${value}"`).join(", ")}]`); + } + // Interleaved section (if present) if (model.interleaved !== undefined) { lines.push(""); @@ -437,7 +482,7 @@ interface Changes { newValue: string; } -function detectChanges( +export function detectChanges( existing: ExistingModel | null, merged: MergedModel, ): Changes[] { @@ -459,7 +504,7 @@ function detectChanges( const formatValue = (val: unknown): string => { if (typeof val === "number") return formatNumber(val); - if (Array.isArray(val)) return `[${val.join(", ")}]`; + if (Array.isArray(val)) return JSON.stringify(val); if (val === undefined) return "(none)"; return String(val); }; @@ -468,6 +513,7 @@ function detectChanges( compare("family", existing.family, merged.family); compare("attachment", existing.attachment, merged.attachment); compare("reasoning", existing.reasoning, merged.reasoning); + compare("reasoning_options", existing.reasoning_options, merged.reasoning_options); compare("tool_call", existing.tool_call, merged.tool_call); compare("structured_output", existing.structured_output, merged.structured_output); compare("open_weights", existing.open_weights, merged.open_weights); @@ -650,4 +696,6 @@ async function main() { } } -await main(); +if (import.meta.main) { + await main(); +} diff --git a/packages/core/test/venice-generator.test.ts b/packages/core/test/venice-generator.test.ts new file mode 100644 index 000000000..ba75bcd50 --- /dev/null +++ b/packages/core/test/venice-generator.test.ts @@ -0,0 +1,58 @@ +import { expect, test } from "bun:test"; + +import { detectChanges, formatToml, mergeModel } from "../script/generate-venice.js"; + +function model(capabilities: Record) { + return { + created: 1_700_000_000, + id: "test-model", + model_spec: { + availableContextTokens: 128_000, + maxCompletionTokens: 32_000, + capabilities, + name: "Test Model", + }, + object: "model", + owned_by: "venice.ai", + type: "text", + }; +} + +test("Venice generator maps and formats reasoning effort options", () => { + const merged = mergeModel(model({ + supportsReasoning: true, + supportsReasoningEffort: true, + reasoningEffortOptions: ["none", "low", "high"], + defaultReasoningEffort: "low", + }), null); + + expect(merged.reasoning_options).toEqual([ + { type: "effort", values: ["none", "low", "high"] }, + ]); + expect(formatToml(merged)).toContain( + '[[reasoning_options]]\ntype = "effort"\nvalues = ["none", "low", "high"]', + ); + expect(detectChanges({ + reasoning_options: [{ type: "effort", values: ["low", "high"] }], + }, merged)).toContainEqual({ + field: "reasoning_options", + oldValue: '[{"type":"effort","values":["low","high"]}]', + newValue: '[{"type":"effort","values":["none","low","high"]}]', + }); +}); + +test("Venice generator distinguishes fixed and non-reasoning models", () => { + const fixed = mergeModel(model({ + supportsReasoning: true, + supportsReasoningEffort: false, + }), null); + const nonReasoning = mergeModel(model({ + supportsReasoning: false, + supportsReasoningEffort: false, + }), null); + + expect(fixed.reasoning_options).toEqual([]); + expect(formatToml(fixed)).toContain("reasoning = true\nreasoning_options = []"); + expect(nonReasoning.reasoning_options).toBeUndefined(); + expect(formatToml(nonReasoning)).not.toContain("reasoning_options"); +}); diff --git a/providers/venice/models/aion-labs-aion-2-0.toml b/providers/venice/models/aion-labs-aion-2-0.toml index 80558110e..d45edfc74 100644 --- a/providers/venice/models/aion-labs-aion-2-0.toml +++ b/providers/venice/models/aion-labs-aion-2-0.toml @@ -2,6 +2,7 @@ name = "Aion 2.0" family = "o" attachment = false reasoning = true +reasoning_options = [{ type = "effort", values = ["low", "medium", "high"] }] tool_call = false temperature = true release_date = "2026-03-24" diff --git a/providers/venice/models/arcee-trinity-large-thinking.toml b/providers/venice/models/arcee-trinity-large-thinking.toml index 90ef4296e..56edce975 100644 --- a/providers/venice/models/arcee-trinity-large-thinking.toml +++ b/providers/venice/models/arcee-trinity-large-thinking.toml @@ -2,6 +2,7 @@ name = "Trinity Large Thinking" family = "trinity" attachment = false reasoning = true +reasoning_options = [{ type = "effort", values = ["low", "medium", "high"] }] tool_call = true structured_output = true temperature = true diff --git a/providers/venice/models/claude-opus-4-5.toml b/providers/venice/models/claude-opus-4-5.toml index 03ad5fd06..7d10ee2d2 100644 --- a/providers/venice/models/claude-opus-4-5.toml +++ b/providers/venice/models/claude-opus-4-5.toml @@ -2,6 +2,7 @@ name = "Claude Opus 4.5" family = "claude-opus" attachment = true reasoning = true +reasoning_options = [] tool_call = true structured_output = true temperature = true diff --git a/providers/venice/models/claude-opus-4-6-fast.toml b/providers/venice/models/claude-opus-4-6-fast.toml index 54e9e68e7..d8f280822 100644 --- a/providers/venice/models/claude-opus-4-6-fast.toml +++ b/providers/venice/models/claude-opus-4-6-fast.toml @@ -2,6 +2,7 @@ name = "Claude Opus 4.6 Fast" family = "claude-opus" attachment = true reasoning = true +reasoning_options = [] tool_call = true structured_output = true temperature = true diff --git a/providers/venice/models/claude-opus-4-6.toml b/providers/venice/models/claude-opus-4-6.toml index d9c44413e..23618e503 100644 --- a/providers/venice/models/claude-opus-4-6.toml +++ b/providers/venice/models/claude-opus-4-6.toml @@ -2,6 +2,7 @@ name = "Claude Opus 4.6" family = "claude-opus" attachment = true reasoning = true +reasoning_options = [] tool_call = true structured_output = true temperature = true diff --git a/providers/venice/models/claude-opus-4-7-fast.toml b/providers/venice/models/claude-opus-4-7-fast.toml index a41375999..650ac025b 100644 --- a/providers/venice/models/claude-opus-4-7-fast.toml +++ b/providers/venice/models/claude-opus-4-7-fast.toml @@ -2,6 +2,7 @@ name = "Claude Opus 4.7 Fast" family = "claude-opus" attachment = true reasoning = true +reasoning_options = [] tool_call = true structured_output = true temperature = true diff --git a/providers/venice/models/claude-opus-4-7.toml b/providers/venice/models/claude-opus-4-7.toml index 72f1d4ff1..2669bae7f 100644 --- a/providers/venice/models/claude-opus-4-7.toml +++ b/providers/venice/models/claude-opus-4-7.toml @@ -2,6 +2,7 @@ name = "Claude Opus 4.7" family = "claude-opus" attachment = true reasoning = true +reasoning_options = [] tool_call = true structured_output = true temperature = false diff --git a/providers/venice/models/claude-opus-4-8-fast.toml b/providers/venice/models/claude-opus-4-8-fast.toml index 40ec2ede6..5dab55a9e 100644 --- a/providers/venice/models/claude-opus-4-8-fast.toml +++ b/providers/venice/models/claude-opus-4-8-fast.toml @@ -2,6 +2,7 @@ name = "Claude Opus 4.8 Fast" family = "claude-opus" attachment = true reasoning = true +reasoning_options = [] tool_call = true structured_output = true temperature = true diff --git a/providers/venice/models/claude-opus-4-8.toml b/providers/venice/models/claude-opus-4-8.toml index 43b5ed161..7a706e328 100644 --- a/providers/venice/models/claude-opus-4-8.toml +++ b/providers/venice/models/claude-opus-4-8.toml @@ -2,6 +2,7 @@ name = "Claude Opus 4.8" family = "claude-opus" attachment = true reasoning = true +reasoning_options = [] tool_call = true structured_output = true temperature = true diff --git a/providers/venice/models/claude-sonnet-4-5.toml b/providers/venice/models/claude-sonnet-4-5.toml index df26bf44d..a2eb40aa9 100644 --- a/providers/venice/models/claude-sonnet-4-5.toml +++ b/providers/venice/models/claude-sonnet-4-5.toml @@ -2,6 +2,7 @@ name = "Claude Sonnet 4.5" family = "claude-sonnet" attachment = true reasoning = true +reasoning_options = [] tool_call = true structured_output = true temperature = true diff --git a/providers/venice/models/claude-sonnet-4-6.toml b/providers/venice/models/claude-sonnet-4-6.toml index 6aa843933..b3b975f10 100644 --- a/providers/venice/models/claude-sonnet-4-6.toml +++ b/providers/venice/models/claude-sonnet-4-6.toml @@ -2,6 +2,7 @@ name = "Claude Sonnet 4.6" family = "claude-sonnet" attachment = true reasoning = true +reasoning_options = [] tool_call = true structured_output = true temperature = true diff --git a/providers/venice/models/deepseek-v3.2.toml b/providers/venice/models/deepseek-v3.2.toml index b3c5882fc..1caa91d61 100644 --- a/providers/venice/models/deepseek-v3.2.toml +++ b/providers/venice/models/deepseek-v3.2.toml @@ -2,6 +2,7 @@ name = "DeepSeek V3.2" family = "deepseek" attachment = false reasoning = true +reasoning_options = [{ type = "effort", values = ["none", "low", "medium", "high"] }] tool_call = true structured_output = true temperature = true diff --git a/providers/venice/models/deepseek-v4-flash.toml b/providers/venice/models/deepseek-v4-flash.toml index 7386d0765..0a5893c4c 100644 --- a/providers/venice/models/deepseek-v4-flash.toml +++ b/providers/venice/models/deepseek-v4-flash.toml @@ -2,6 +2,7 @@ name = "DeepSeek V4 Flash" family = "deepseek-flash" attachment = false reasoning = true +reasoning_options = [] tool_call = true structured_output = true temperature = true diff --git a/providers/venice/models/deepseek-v4-pro.toml b/providers/venice/models/deepseek-v4-pro.toml index df427c722..16f038e9d 100644 --- a/providers/venice/models/deepseek-v4-pro.toml +++ b/providers/venice/models/deepseek-v4-pro.toml @@ -2,6 +2,7 @@ name = "DeepSeek V4 Pro" family = "deepseek" attachment = false reasoning = true +reasoning_options = [] tool_call = true structured_output = true temperature = true diff --git a/providers/venice/models/gemini-3-1-pro-preview.toml b/providers/venice/models/gemini-3-1-pro-preview.toml index cfced90ef..f734d4a70 100644 --- a/providers/venice/models/gemini-3-1-pro-preview.toml +++ b/providers/venice/models/gemini-3-1-pro-preview.toml @@ -2,6 +2,7 @@ name = "Gemini 3.1 Pro Preview" family = "gemini-pro" attachment = true reasoning = true +reasoning_options = [{ type = "effort", values = ["low", "medium", "high"] }] tool_call = true structured_output = true temperature = true diff --git a/providers/venice/models/gemini-3-5-flash.toml b/providers/venice/models/gemini-3-5-flash.toml index 17e0ce36f..f1173bad3 100644 --- a/providers/venice/models/gemini-3-5-flash.toml +++ b/providers/venice/models/gemini-3-5-flash.toml @@ -2,6 +2,7 @@ name = "Gemini 3.5 Flash" family = "gemini-flash" attachment = true reasoning = true +reasoning_options = [{ type = "effort", values = ["low", "medium", "high"] }] tool_call = true structured_output = true temperature = true diff --git a/providers/venice/models/gemini-3-flash-preview.toml b/providers/venice/models/gemini-3-flash-preview.toml index b471548c0..4fb34cce1 100644 --- a/providers/venice/models/gemini-3-flash-preview.toml +++ b/providers/venice/models/gemini-3-flash-preview.toml @@ -2,6 +2,7 @@ name = "Gemini 3 Flash Preview" family = "gemini-flash" attachment = true reasoning = true +reasoning_options = [{ type = "effort", values = ["low", "medium", "high"] }] tool_call = true structured_output = true temperature = true diff --git a/providers/venice/models/google-gemma-4-26b-a4b-it.toml b/providers/venice/models/google-gemma-4-26b-a4b-it.toml index 5499d911f..77c93e63a 100644 --- a/providers/venice/models/google-gemma-4-26b-a4b-it.toml +++ b/providers/venice/models/google-gemma-4-26b-a4b-it.toml @@ -2,6 +2,7 @@ name = "Google Gemma 4 26B A4B Instruct" family = "gemma" attachment = true reasoning = true +reasoning_options = [{ type = "effort", values = ["none", "low", "medium", "high"] }] tool_call = true structured_output = true temperature = true diff --git a/providers/venice/models/google-gemma-4-31b-it.toml b/providers/venice/models/google-gemma-4-31b-it.toml index 014456bf2..18b7f4caa 100644 --- a/providers/venice/models/google-gemma-4-31b-it.toml +++ b/providers/venice/models/google-gemma-4-31b-it.toml @@ -2,6 +2,7 @@ name = "Google Gemma 4 31B Instruct" family = "gemma" attachment = true reasoning = true +reasoning_options = [{ type = "effort", values = ["none", "low", "medium", "high"] }] tool_call = true structured_output = true temperature = true diff --git a/providers/venice/models/grok-4-20-multi-agent.toml b/providers/venice/models/grok-4-20-multi-agent.toml index 2f12f71dd..121468a04 100644 --- a/providers/venice/models/grok-4-20-multi-agent.toml +++ b/providers/venice/models/grok-4-20-multi-agent.toml @@ -2,6 +2,7 @@ name = "Grok 4.20 Multi-Agent" family = "grok" attachment = true reasoning = true +reasoning_options = [] tool_call = false structured_output = true temperature = true diff --git a/providers/venice/models/grok-4-20.toml b/providers/venice/models/grok-4-20.toml index dc9edb09c..30f0e7911 100644 --- a/providers/venice/models/grok-4-20.toml +++ b/providers/venice/models/grok-4-20.toml @@ -2,6 +2,7 @@ name = "Grok 4.20" family = "grok" attachment = true reasoning = true +reasoning_options = [] tool_call = true structured_output = true temperature = true diff --git a/providers/venice/models/grok-4-3.toml b/providers/venice/models/grok-4-3.toml index 9776d7713..61205948f 100644 --- a/providers/venice/models/grok-4-3.toml +++ b/providers/venice/models/grok-4-3.toml @@ -2,6 +2,7 @@ name = "Grok 4.3" family = "grok" attachment = true reasoning = true +reasoning_options = [] tool_call = true structured_output = true temperature = true diff --git a/providers/venice/models/grok-build-0-1.toml b/providers/venice/models/grok-build-0-1.toml index 68e26f0f6..666cef732 100644 --- a/providers/venice/models/grok-build-0-1.toml +++ b/providers/venice/models/grok-build-0-1.toml @@ -2,6 +2,7 @@ name = "Grok Build 0.1" family = "grok-build" attachment = true reasoning = true +reasoning_options = [] tool_call = true structured_output = true temperature = true diff --git a/providers/venice/models/kimi-k2-5.toml b/providers/venice/models/kimi-k2-5.toml index 57fdf7b50..79430c9c1 100644 --- a/providers/venice/models/kimi-k2-5.toml +++ b/providers/venice/models/kimi-k2-5.toml @@ -2,6 +2,7 @@ name = "Kimi K2.5" family = "kimi" attachment = true reasoning = true +reasoning_options = [{ type = "effort", values = ["none", "low", "medium", "high"] }] tool_call = true structured_output = true temperature = true diff --git a/providers/venice/models/kimi-k2-6.toml b/providers/venice/models/kimi-k2-6.toml index 55a1edcbe..a69ea4177 100644 --- a/providers/venice/models/kimi-k2-6.toml +++ b/providers/venice/models/kimi-k2-6.toml @@ -2,6 +2,7 @@ name = "Kimi K2.6" family = "kimi" attachment = true reasoning = true +reasoning_options = [{ type = "effort", values = ["none", "low", "medium", "high"] }] tool_call = true structured_output = true temperature = true diff --git a/providers/venice/models/mercury-2.toml b/providers/venice/models/mercury-2.toml index bbbcd0a73..80e614527 100644 --- a/providers/venice/models/mercury-2.toml +++ b/providers/venice/models/mercury-2.toml @@ -2,6 +2,7 @@ name = "Mercury 2" family = "mercury" attachment = false reasoning = true +reasoning_options = [{ type = "effort", values = ["none", "low", "medium", "high"] }] tool_call = true structured_output = true temperature = true diff --git a/providers/venice/models/minimax-m25.toml b/providers/venice/models/minimax-m25.toml index 1301119c2..62d875766 100644 --- a/providers/venice/models/minimax-m25.toml +++ b/providers/venice/models/minimax-m25.toml @@ -2,6 +2,7 @@ name = "MiniMax M2.5" family = "minimax" attachment = false reasoning = true +reasoning_options = [{ type = "effort", values = ["low", "medium", "high"] }] tool_call = true temperature = true release_date = "2026-02-12" diff --git a/providers/venice/models/minimax-m27.toml b/providers/venice/models/minimax-m27.toml index 15e1acd9e..a0ed5b4db 100644 --- a/providers/venice/models/minimax-m27.toml +++ b/providers/venice/models/minimax-m27.toml @@ -2,6 +2,7 @@ name = "MiniMax M2.7" family = "minimax" attachment = false reasoning = true +reasoning_options = [{ type = "effort", values = ["low", "medium", "high"] }] tool_call = true temperature = true release_date = "2026-03-18" diff --git a/providers/venice/models/minimax-m3.toml b/providers/venice/models/minimax-m3.toml index 701ea4f1b..7e87a3919 100644 --- a/providers/venice/models/minimax-m3.toml +++ b/providers/venice/models/minimax-m3.toml @@ -2,6 +2,7 @@ name = "MiniMax M3" family = "minimax-m3" attachment = true reasoning = true +reasoning_options = [] tool_call = true temperature = true release_date = "2026-06-01" diff --git a/providers/venice/models/mistral-small-2603.toml b/providers/venice/models/mistral-small-2603.toml index 1f9f5b05a..72c76210e 100644 --- a/providers/venice/models/mistral-small-2603.toml +++ b/providers/venice/models/mistral-small-2603.toml @@ -2,6 +2,7 @@ name = "Mistral Small 4" family = "mistral-small" attachment = true reasoning = true +reasoning_options = [{ type = "effort", values = ["none", "high"] }] tool_call = true structured_output = true temperature = true diff --git a/providers/venice/models/nvidia-nemotron-3-ultra-550b-a55b.toml b/providers/venice/models/nvidia-nemotron-3-ultra-550b-a55b.toml index fbe82fb5e..c63de2e1d 100644 --- a/providers/venice/models/nvidia-nemotron-3-ultra-550b-a55b.toml +++ b/providers/venice/models/nvidia-nemotron-3-ultra-550b-a55b.toml @@ -2,6 +2,7 @@ name = "NVIDIA Nemotron 3 Ultra" family = "nemotron" attachment = true reasoning = true +reasoning_options = [{ type = "effort", values = ["none", "low", "medium", "high"] }] tool_call = true structured_output = true temperature = true diff --git a/providers/venice/models/nvidia-nemotron-cascade-2-30b-a3b.toml b/providers/venice/models/nvidia-nemotron-cascade-2-30b-a3b.toml index 0d1bd2e27..7844b6f90 100644 --- a/providers/venice/models/nvidia-nemotron-cascade-2-30b-a3b.toml +++ b/providers/venice/models/nvidia-nemotron-cascade-2-30b-a3b.toml @@ -3,6 +3,7 @@ base_model = "nvidia/nemotron-cascade-2-30b-a3b" family = "nemotron" attachment = false reasoning = true +reasoning_options = [{ type = "effort", values = ["none", "low", "medium", "high"] }] tool_call = true structured_output = true temperature = true diff --git a/providers/venice/models/olafangensan-glm-4.7-flash-heretic.toml b/providers/venice/models/olafangensan-glm-4.7-flash-heretic.toml index d85fa92da..c0f2f2b3c 100644 --- a/providers/venice/models/olafangensan-glm-4.7-flash-heretic.toml +++ b/providers/venice/models/olafangensan-glm-4.7-flash-heretic.toml @@ -2,6 +2,7 @@ name = "GLM 4.7 Flash Heretic" family = "glm-flash" attachment = false reasoning = true +reasoning_options = [{ type = "effort", values = ["none", "low", "medium", "high"] }] tool_call = true structured_output = true temperature = true diff --git a/providers/venice/models/openai-gpt-52-codex.toml b/providers/venice/models/openai-gpt-52-codex.toml index 937fd40f2..ed5c9c33f 100644 --- a/providers/venice/models/openai-gpt-52-codex.toml +++ b/providers/venice/models/openai-gpt-52-codex.toml @@ -2,6 +2,7 @@ name = "GPT-5.2 Codex" family = "gpt-codex" attachment = true reasoning = true +reasoning_options = [{ type = "effort", values = ["none", "minimal", "low", "medium", "high"] }] tool_call = true structured_output = true temperature = true diff --git a/providers/venice/models/openai-gpt-52.toml b/providers/venice/models/openai-gpt-52.toml index e7ec31cae..44bc73338 100644 --- a/providers/venice/models/openai-gpt-52.toml +++ b/providers/venice/models/openai-gpt-52.toml @@ -2,6 +2,7 @@ name = "GPT-5.2" family = "gpt" attachment = false reasoning = true +reasoning_options = [{ type = "effort", values = ["none", "minimal", "low", "medium", "high"] }] tool_call = true structured_output = true temperature = true diff --git a/providers/venice/models/openai-gpt-53-codex.toml b/providers/venice/models/openai-gpt-53-codex.toml index c14132f5c..bede658f6 100644 --- a/providers/venice/models/openai-gpt-53-codex.toml +++ b/providers/venice/models/openai-gpt-53-codex.toml @@ -2,6 +2,7 @@ name = "GPT-5.3 Codex" family = "gpt-codex" attachment = true reasoning = true +reasoning_options = [{ type = "effort", values = ["none", "minimal", "low", "medium", "high"] }] tool_call = true structured_output = true temperature = true diff --git a/providers/venice/models/openai-gpt-54-mini.toml b/providers/venice/models/openai-gpt-54-mini.toml index c1d4f7727..0e957c1d3 100644 --- a/providers/venice/models/openai-gpt-54-mini.toml +++ b/providers/venice/models/openai-gpt-54-mini.toml @@ -2,6 +2,7 @@ name = "GPT-5.4 Mini" family = "gpt-mini" attachment = true reasoning = true +reasoning_options = [{ type = "effort", values = ["none", "minimal", "low", "medium", "high"] }] tool_call = true structured_output = true temperature = true diff --git a/providers/venice/models/openai-gpt-54-pro.toml b/providers/venice/models/openai-gpt-54-pro.toml index ff376fe0b..075b8135f 100644 --- a/providers/venice/models/openai-gpt-54-pro.toml +++ b/providers/venice/models/openai-gpt-54-pro.toml @@ -2,6 +2,7 @@ name = "GPT-5.4 Pro" family = "gpt-pro" attachment = true reasoning = true +reasoning_options = [{ type = "effort", values = ["none", "minimal", "low", "medium", "high"] }] tool_call = true structured_output = true temperature = true diff --git a/providers/venice/models/openai-gpt-54.toml b/providers/venice/models/openai-gpt-54.toml index 4904d1264..512c4d201 100644 --- a/providers/venice/models/openai-gpt-54.toml +++ b/providers/venice/models/openai-gpt-54.toml @@ -2,6 +2,7 @@ name = "GPT-5.4" family = "gpt" attachment = true reasoning = true +reasoning_options = [{ type = "effort", values = ["none", "minimal", "low", "medium", "high"] }] tool_call = true structured_output = true temperature = true diff --git a/providers/venice/models/openai-gpt-55-pro.toml b/providers/venice/models/openai-gpt-55-pro.toml index a02dbc409..86afe0a92 100644 --- a/providers/venice/models/openai-gpt-55-pro.toml +++ b/providers/venice/models/openai-gpt-55-pro.toml @@ -2,6 +2,7 @@ name = "GPT-5.5 Pro" family = "gpt-pro" attachment = true reasoning = true +reasoning_options = [{ type = "effort", values = ["none", "minimal", "low", "medium", "high"] }] tool_call = true structured_output = true temperature = true diff --git a/providers/venice/models/openai-gpt-55.toml b/providers/venice/models/openai-gpt-55.toml index a262f8e98..db84c7016 100644 --- a/providers/venice/models/openai-gpt-55.toml +++ b/providers/venice/models/openai-gpt-55.toml @@ -2,6 +2,7 @@ name = "GPT-5.5" family = "gpt" attachment = true reasoning = true +reasoning_options = [{ type = "effort", values = ["none", "minimal", "low", "medium", "high"] }] tool_call = true structured_output = true temperature = true diff --git a/providers/venice/models/openai-gpt-oss-120b.toml b/providers/venice/models/openai-gpt-oss-120b.toml index 7c1508138..86272746f 100644 --- a/providers/venice/models/openai-gpt-oss-120b.toml +++ b/providers/venice/models/openai-gpt-oss-120b.toml @@ -2,6 +2,7 @@ name = "OpenAI GPT OSS 120B" family = "gpt-oss" attachment = false reasoning = true +reasoning_options = [{ type = "effort", values = ["none", "low", "medium", "high"] }] tool_call = true temperature = true knowledge = "2025-07" diff --git a/providers/venice/models/qwen-3-6-plus.toml b/providers/venice/models/qwen-3-6-plus.toml index 36f547216..e055c084b 100644 --- a/providers/venice/models/qwen-3-6-plus.toml +++ b/providers/venice/models/qwen-3-6-plus.toml @@ -2,6 +2,7 @@ name = "Qwen 3.6 Plus Uncensored" family = "qwen" attachment = true reasoning = true +reasoning_options = [] tool_call = true structured_output = true temperature = true diff --git a/providers/venice/models/qwen-3-7-max.toml b/providers/venice/models/qwen-3-7-max.toml index dc89fb2cb..0ab43d97f 100644 --- a/providers/venice/models/qwen-3-7-max.toml +++ b/providers/venice/models/qwen-3-7-max.toml @@ -2,6 +2,7 @@ name = "Qwen 3.7 Max" family = "qwen" attachment = false reasoning = true +reasoning_options = [] tool_call = true temperature = true release_date = "2026-05-22" diff --git a/providers/venice/models/qwen-3-7-plus.toml b/providers/venice/models/qwen-3-7-plus.toml index 98660260c..f1340f81a 100644 --- a/providers/venice/models/qwen-3-7-plus.toml +++ b/providers/venice/models/qwen-3-7-plus.toml @@ -2,6 +2,7 @@ name = "Qwen 3.7 Plus" family = "qwen" attachment = true reasoning = true +reasoning_options = [] tool_call = true structured_output = true temperature = true diff --git a/providers/venice/models/qwen3-235b-a22b-thinking-2507.toml b/providers/venice/models/qwen3-235b-a22b-thinking-2507.toml index 3444c2e9d..6899c0a4a 100644 --- a/providers/venice/models/qwen3-235b-a22b-thinking-2507.toml +++ b/providers/venice/models/qwen3-235b-a22b-thinking-2507.toml @@ -2,6 +2,7 @@ name = "Qwen 3 235B A22B Thinking 2507" family = "qwen" attachment = false reasoning = true +reasoning_options = [{ type = "effort", values = ["low", "medium", "high"] }] tool_call = true structured_output = true temperature = true diff --git a/providers/venice/models/qwen3-5-35b-a3b.toml b/providers/venice/models/qwen3-5-35b-a3b.toml index 0bc8a8911..0562eb770 100644 --- a/providers/venice/models/qwen3-5-35b-a3b.toml +++ b/providers/venice/models/qwen3-5-35b-a3b.toml @@ -2,6 +2,7 @@ name = "Qwen 3.5 35B A3B" family = "qwen" attachment = true reasoning = true +reasoning_options = [{ type = "effort", values = ["none", "low", "medium", "high"] }] tool_call = true structured_output = true temperature = true diff --git a/providers/venice/models/qwen3-5-397b-a17b.toml b/providers/venice/models/qwen3-5-397b-a17b.toml index 3e190b952..3a776ccb5 100644 --- a/providers/venice/models/qwen3-5-397b-a17b.toml +++ b/providers/venice/models/qwen3-5-397b-a17b.toml @@ -2,6 +2,7 @@ name = "Qwen 3.5 397B" family = "qwen" attachment = true reasoning = true +reasoning_options = [{ type = "effort", values = ["none", "low", "medium", "high"] }] tool_call = true structured_output = true temperature = true diff --git a/providers/venice/models/qwen3-5-9b.toml b/providers/venice/models/qwen3-5-9b.toml index 8e6f1be3f..c42c6590f 100644 --- a/providers/venice/models/qwen3-5-9b.toml +++ b/providers/venice/models/qwen3-5-9b.toml @@ -2,6 +2,7 @@ name = "Qwen 3.5 9B" family = "qwen" attachment = true reasoning = true +reasoning_options = [{ type = "effort", values = ["none", "low", "medium", "high"] }] tool_call = true structured_output = true temperature = true diff --git a/providers/venice/models/qwen3-6-27b.toml b/providers/venice/models/qwen3-6-27b.toml index d75a8156f..4e4885d26 100644 --- a/providers/venice/models/qwen3-6-27b.toml +++ b/providers/venice/models/qwen3-6-27b.toml @@ -2,6 +2,7 @@ name = "Qwen 3.6 27B" family = "qwen" attachment = true reasoning = true +reasoning_options = [{ type = "effort", values = ["none", "low", "medium", "high"] }] tool_call = true structured_output = true temperature = true diff --git a/providers/venice/models/z-ai-glm-5-turbo.toml b/providers/venice/models/z-ai-glm-5-turbo.toml index 453c551e5..5b283bc4a 100644 --- a/providers/venice/models/z-ai-glm-5-turbo.toml +++ b/providers/venice/models/z-ai-glm-5-turbo.toml @@ -2,6 +2,7 @@ name = "GLM 5 Turbo" family = "glm" attachment = false reasoning = true +reasoning_options = [{ type = "effort", values = ["none", "low", "medium", "high"] }] tool_call = true structured_output = true temperature = true diff --git a/providers/venice/models/z-ai-glm-5v-turbo.toml b/providers/venice/models/z-ai-glm-5v-turbo.toml index 39bc6881d..a4bbc6da5 100644 --- a/providers/venice/models/z-ai-glm-5v-turbo.toml +++ b/providers/venice/models/z-ai-glm-5v-turbo.toml @@ -2,6 +2,7 @@ name = "GLM 5V Turbo" family = "glmv" attachment = true reasoning = true +reasoning_options = [{ type = "effort", values = ["none", "low", "medium", "high"] }] tool_call = true structured_output = true temperature = true diff --git a/providers/venice/models/zai-org-glm-4.6.toml b/providers/venice/models/zai-org-glm-4.6.toml index 39cb2ae13..3ced9af6b 100644 --- a/providers/venice/models/zai-org-glm-4.6.toml +++ b/providers/venice/models/zai-org-glm-4.6.toml @@ -2,6 +2,7 @@ name = "GLM 4.6" family = "glm" attachment = false reasoning = true +reasoning_options = [{ type = "effort", values = ["low", "medium", "high"] }] tool_call = true structured_output = true temperature = true diff --git a/providers/venice/models/zai-org-glm-4.7-flash.toml b/providers/venice/models/zai-org-glm-4.7-flash.toml index f0604c94d..94b7e105e 100644 --- a/providers/venice/models/zai-org-glm-4.7-flash.toml +++ b/providers/venice/models/zai-org-glm-4.7-flash.toml @@ -2,6 +2,7 @@ name = "GLM 4.7 Flash" family = "glm-flash" attachment = false reasoning = true +reasoning_options = [{ type = "effort", values = ["none", "low", "medium", "high"] }] tool_call = true structured_output = true temperature = true diff --git a/providers/venice/models/zai-org-glm-4.7.toml b/providers/venice/models/zai-org-glm-4.7.toml index 7d64ce34f..e41aae6d8 100644 --- a/providers/venice/models/zai-org-glm-4.7.toml +++ b/providers/venice/models/zai-org-glm-4.7.toml @@ -2,6 +2,7 @@ name = "GLM 4.7" family = "glm" attachment = false reasoning = true +reasoning_options = [{ type = "effort", values = ["low", "medium", "high"] }] tool_call = true structured_output = true temperature = true diff --git a/providers/venice/models/zai-org-glm-5-1.toml b/providers/venice/models/zai-org-glm-5-1.toml index 4bf14c7fd..fdca1be73 100644 --- a/providers/venice/models/zai-org-glm-5-1.toml +++ b/providers/venice/models/zai-org-glm-5-1.toml @@ -2,6 +2,7 @@ name = "GLM 5.1" family = "glm" attachment = false reasoning = true +reasoning_options = [{ type = "effort", values = ["none", "low", "medium", "high"] }] tool_call = true structured_output = true temperature = true diff --git a/providers/venice/models/zai-org-glm-5.toml b/providers/venice/models/zai-org-glm-5.toml index fb88cf199..b375d1a03 100644 --- a/providers/venice/models/zai-org-glm-5.toml +++ b/providers/venice/models/zai-org-glm-5.toml @@ -2,6 +2,7 @@ name = "GLM 5" family = "glm" attachment = false reasoning = true +reasoning_options = [{ type = "effort", values = ["none", "low", "medium", "high"] }] tool_call = true structured_output = true temperature = true From fef032dae33ef0826b990995d93b0c28968d9cd6 Mon Sep 17 00:00:00 2001 From: Aiden Cline Date: Mon, 8 Jun 2026 22:03:04 -0500 Subject: [PATCH 2/3] fix(venice): preserve curated reasoning controls --- packages/core/script/generate-venice.ts | 92 +++++++++----- packages/core/test/venice-generator.test.ts | 114 +++++++++++++----- providers/venice/models/claude-opus-4-5.toml | 2 +- .../venice/models/claude-opus-4-6-fast.toml | 2 +- providers/venice/models/claude-opus-4-6.toml | 2 +- .../venice/models/claude-opus-4-7-fast.toml | 1 - providers/venice/models/claude-opus-4-7.toml | 1 - .../venice/models/claude-opus-4-8-fast.toml | 1 - providers/venice/models/claude-opus-4-8.toml | 1 - .../venice/models/claude-sonnet-4-5.toml | 2 +- .../venice/models/claude-sonnet-4-6.toml | 2 +- .../venice/models/deepseek-v4-flash.toml | 1 - providers/venice/models/deepseek-v4-pro.toml | 1 - .../venice/models/gemini-3-flash-preview.toml | 2 +- .../venice/models/grok-4-20-multi-agent.toml | 1 - providers/venice/models/grok-4-20.toml | 1 - providers/venice/models/grok-4-3.toml | 1 - providers/venice/models/grok-build-0-1.toml | 1 - providers/venice/models/kimi-k2-5.toml | 2 +- providers/venice/models/minimax-m3.toml | 1 - .../venice/models/openai-gpt-52-codex.toml | 2 +- providers/venice/models/openai-gpt-52.toml | 2 +- .../venice/models/openai-gpt-53-codex.toml | 2 +- .../venice/models/openai-gpt-54-mini.toml | 2 +- .../venice/models/openai-gpt-54-pro.toml | 2 +- providers/venice/models/openai-gpt-54.toml | 2 +- .../venice/models/openai-gpt-55-pro.toml | 2 +- providers/venice/models/openai-gpt-55.toml | 2 +- providers/venice/models/qwen-3-6-plus.toml | 1 - providers/venice/models/qwen-3-7-max.toml | 1 - providers/venice/models/qwen-3-7-plus.toml | 1 - providers/venice/models/qwen3-5-35b-a3b.toml | 2 +- providers/venice/models/zai-org-glm-5-1.toml | 2 +- 33 files changed, 162 insertions(+), 92 deletions(-) diff --git a/packages/core/script/generate-venice.ts b/packages/core/script/generate-venice.ts index 038f4e565..c8e6d94ba 100644 --- a/packages/core/script/generate-venice.ts +++ b/packages/core/script/generate-venice.ts @@ -10,6 +10,40 @@ const API_ENDPOINT = "https://api.venice.ai/api/v1/models?type=text"; // Zod schemas for API response validation const ReasoningEffort = z.enum(["none", "minimal", "low", "medium", "high", "xhigh", "max"]); +type ReasoningOption = { + type: "effort"; + values: Array>; +}; + +const effort = (...values: ReasoningOption["values"]): ReasoningOption[] => [{ type: "effort", values }]; + +// Venice documents these model-specific values even where /models is stale or incomplete. +// Source: https://docs.venice.ai/guides/features/reasoning-models +export const REASONING_OVERRIDES: Record = { + "claude-opus-4-5": effort("low", "medium", "high"), + "claude-opus-4-6": effort("low", "medium", "high", "max"), + "claude-opus-4-6-fast": effort("low", "medium", "high", "max"), + "claude-sonnet-4-5": effort("low", "medium", "high"), + "claude-sonnet-4-6": effort("low", "medium", "high"), + "gemini-3-flash-preview": effort("minimal", "low", "medium", "high"), + "kimi-k2-5": effort("low", "medium", "high"), + "openai-gpt-52": effort("none", "low", "medium", "high", "xhigh"), + "openai-gpt-52-codex": effort("low", "medium", "high", "xhigh"), + "openai-gpt-53-codex": effort("low", "medium", "high", "xhigh"), + "qwen3-5-35b-a3b": effort("low", "medium", "high"), + "zai-org-glm-5-1": [], + + // Provisional until funded Venice probes can confirm that its proxy preserves + // OpenAI's current controls. Sources: + // https://developers.openai.com/api/docs/models/gpt-5.4 + // https://developers.openai.com/api/docs/models/gpt-5.4-pro + // https://developers.openai.com/api/docs/guides/reasoning + "openai-gpt-54": effort("none", "low", "medium", "high", "xhigh"), + "openai-gpt-54-mini": effort("none", "low", "medium", "high", "xhigh"), + "openai-gpt-54-pro": effort("medium", "high", "xhigh"), + "openai-gpt-55": effort("none", "low", "medium", "high", "xhigh"), + "openai-gpt-55-pro": effort("medium", "high", "xhigh"), +}; const Capabilities = z .object({ @@ -19,7 +53,7 @@ const Capabilities = z supportsFunctionCalling: z.boolean().optional(), supportsLogProbs: z.boolean().optional(), supportsReasoning: z.boolean().optional(), - supportsReasoningEffort: z.boolean(), + supportsReasoningEffort: z.boolean().optional(), reasoningEffortOptions: z.array(ReasoningEffort).optional(), defaultReasoningEffort: ReasoningEffort.optional(), supportsResponseSchema: z.boolean().optional(), @@ -27,23 +61,7 @@ const Capabilities = z supportsVision: z.boolean().optional(), supportsWebSearch: z.boolean().optional(), }) - .passthrough() - .superRefine((capabilities, context) => { - if (capabilities.supportsReasoningEffort && capabilities.reasoningEffortOptions === undefined) { - context.addIssue({ - code: z.ZodIssueCode.custom, - path: ["reasoningEffortOptions"], - message: "Reasoning effort options are required when reasoning effort is supported", - }); - } - if (capabilities.supportsReasoningEffort && capabilities.defaultReasoningEffort === undefined) { - context.addIssue({ - code: z.ZodIssueCode.custom, - path: ["defaultReasoningEffort"], - message: "Default reasoning effort is required when reasoning effort is supported", - }); - } - }); + .passthrough(); const PricingTier = z.object({ usd: z.number(), diem: z.number().optional() }).passthrough(); @@ -163,10 +181,7 @@ interface ExistingModel { family?: string; attachment?: boolean; reasoning?: boolean; - reasoning_options?: Array<{ - type: "effort"; - values: Array>; - }>; + reasoning_options?: ReasoningOption[]; tool_call?: boolean; structured_output?: boolean; temperature?: boolean; @@ -260,10 +275,7 @@ interface MergedModel { family?: string; attachment: boolean; reasoning: boolean; - reasoning_options?: Array<{ - type: "effort"; - values: Array>; - }>; + reasoning_options?: ReasoningOption[]; tool_call: boolean; structured_output?: boolean; temperature: boolean; @@ -299,6 +311,7 @@ interface MergedModel { export function mergeModel( apiModel: z.infer, existing: ExistingModel | null, + reportDiscrepancy: (message: string) => void = console.warn, ): MergedModel { const spec = apiModel.model_spec; const caps = spec.capabilities; @@ -338,10 +351,29 @@ export function mergeModel( }, }; - if (merged.reasoning) { - merged.reasoning_options = caps.supportsReasoningEffort === true - ? [{ type: "effort", values: caps.reasoningEffortOptions ?? [] }] - : []; + const override = REASONING_OVERRIDES[apiModel.id]; + const catalogOptions = caps.supportsReasoningEffort === true && caps.reasoningEffortOptions !== undefined + ? effort(...caps.reasoningEffortOptions) + : undefined; + const curatedOptions = existing?.reasoning_options; + const selectedOptions = override ?? curatedOptions ?? catalogOptions; + + if (selectedOptions !== undefined) { + merged.reasoning_options = selectedOptions; + } + + const catalogClaim = catalogOptions ?? (caps.supportsReasoningEffort === false ? [] : undefined); + if (override !== undefined && JSON.stringify(override) !== JSON.stringify(curatedOptions) && curatedOptions !== undefined) { + reportDiscrepancy(`${apiModel.id}: documented override replaces curated reasoning_options`); + } + if ( + selectedOptions !== undefined && + catalogClaim !== undefined && + JSON.stringify(selectedOptions) !== JSON.stringify(catalogClaim) + ) { + reportDiscrepancy( + `${apiModel.id}: preserving ${override !== undefined ? "documented override" : "curated reasoning_options"} despite catalog ${caps.supportsReasoningEffort === false ? "supportsReasoningEffort=false" : "option mismatch"}`, + ); } // structured_output only if true diff --git a/packages/core/test/venice-generator.test.ts b/packages/core/test/venice-generator.test.ts index ba75bcd50..ed30c89dc 100644 --- a/packages/core/test/venice-generator.test.ts +++ b/packages/core/test/venice-generator.test.ts @@ -1,15 +1,23 @@ import { expect, test } from "bun:test"; -import { detectChanges, formatToml, mergeModel } from "../script/generate-venice.js"; +import { + detectChanges, + formatToml, + mergeModel, + REASONING_OVERRIDES, +} from "../script/generate-venice.js"; -function model(capabilities: Record) { +type Effort = "none" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max"; +const options = (...values: Effort[]) => [{ type: "effort" as const, values }]; + +function model(id: string, capabilities: Record) { return { created: 1_700_000_000, - id: "test-model", + id, model_spec: { availableContextTokens: 128_000, maxCompletionTokens: 32_000, - capabilities, + capabilities: { supportsReasoning: true, ...capabilities }, name: "Test Model", }, object: "model", @@ -18,41 +26,85 @@ function model(capabilities: Record) { }; } -test("Venice generator maps and formats reasoning effort options", () => { - const merged = mergeModel(model({ - supportsReasoning: true, +test("curated options survive false and stale Venice catalog metadata", () => { + const claude = options("low", "medium", "high", "max"); + const codex = options("low", "medium", "high", "xhigh"); + const discrepancies: string[] = []; + + expect(mergeModel(model("claude-opus-4-7", { + supportsReasoningEffort: false, + }), { reasoning_options: claude }, discrepancies.push.bind(discrepancies)).reasoning_options).toEqual(claude); + expect(mergeModel(model("openai-gpt-56-codex", { supportsReasoningEffort: true, - reasoningEffortOptions: ["none", "low", "high"], - defaultReasoningEffort: "low", + reasoningEffortOptions: ["none", "low"], + }), { reasoning_options: codex }, discrepancies.push.bind(discrepancies)).reasoning_options).toEqual(codex); + expect(discrepancies).toHaveLength(2); +}); + +test("documented override beats stale curated and catalog options", () => { + const discrepancies: string[] = []; + const merged = mergeModel(model("openai-gpt-52", { + supportsReasoningEffort: true, + reasoningEffortOptions: ["minimal", "low", "high"], + }), { reasoning_options: options("low", "high") }, discrepancies.push.bind(discrepancies)); + + expect(merged.reasoning_options).toEqual(options("none", "low", "medium", "high", "xhigh")); + expect(discrepancies).toHaveLength(2); +}); + +test("catalog fills only an uncurated new model", () => { + const merged = mergeModel(model("new-reasoner", { + supportsReasoningEffort: true, + reasoningEffortOptions: ["low", "high"], }), null); - expect(merged.reasoning_options).toEqual([ - { type: "effort", values: ["none", "low", "high"] }, - ]); - expect(formatToml(merged)).toContain( - '[[reasoning_options]]\ntype = "effort"\nvalues = ["none", "low", "high"]', - ); - expect(detectChanges({ - reasoning_options: [{ type: "effort", values: ["low", "high"] }], - }, merged)).toContainEqual({ - field: "reasoning_options", - oldValue: '[{"type":"effort","values":["low","high"]}]', - newValue: '[{"type":"effort","values":["none","low","high"]}]', - }); + expect(merged.reasoning_options).toEqual(options("low", "high")); }); -test("Venice generator distinguishes fixed and non-reasoning models", () => { - const fixed = mergeModel(model({ - supportsReasoning: true, +test("catalog false without curated evidence leaves options undefined", () => { + const merged = mergeModel(model("unknown-fixed-reasoner", { supportsReasoningEffort: false, }), null); - const nonReasoning = mergeModel(model({ - supportsReasoning: false, + + expect(merged.reasoning_options).toBeUndefined(); + expect(formatToml(merged)).not.toContain("reasoning_options"); +}); + +test("explicit curated empty options remain stable", () => { + const existing = { reasoning_options: [] }; + const merged = mergeModel(model("curated-fixed-reasoner", { supportsReasoningEffort: false, + }), existing); + + expect(merged.reasoning_options).toEqual([]); + expect(detectChanges({ ...existing, reasoning: true }, merged).find((change) => change.field === "reasoning_options")).toBeUndefined(); + expect(formatToml(merged)).toContain("reasoning = true\nreasoning_options = []"); +}); + +test("formatter emits nonempty options using model TOML convention", () => { + const merged = mergeModel(model("new-reasoner", { + supportsReasoningEffort: true, + reasoningEffortOptions: ["none", "high"], }), null); - expect(fixed.reasoning_options).toEqual([]); - expect(formatToml(fixed)).toContain("reasoning = true\nreasoning_options = []"); - expect(nonReasoning.reasoning_options).toBeUndefined(); - expect(formatToml(nonReasoning)).not.toContain("reasoning_options"); + expect(formatToml(merged)).toContain( + '[[reasoning_options]]\ntype = "effort"\nvalues = ["none", "high"]', + ); +}); + +test("official correction fixtures remain exact", () => { + const expected = { + "claude-opus-4-6": options("low", "medium", "high", "max"), + "openai-gpt-52": options("none", "low", "medium", "high", "xhigh"), + "openai-gpt-52-codex": options("low", "medium", "high", "xhigh"), + "openai-gpt-54-pro": options("medium", "high", "xhigh"), + "gemini-3-flash-preview": options("minimal", "low", "medium", "high"), + "kimi-k2-5": options("low", "medium", "high"), + "qwen3-5-35b-a3b": options("low", "medium", "high"), + "zai-org-glm-5-1": [], + }; + + for (const [id, reasoningOptions] of Object.entries(expected)) { + expect(REASONING_OVERRIDES[id]).toEqual(reasoningOptions); + } }); diff --git a/providers/venice/models/claude-opus-4-5.toml b/providers/venice/models/claude-opus-4-5.toml index 7d10ee2d2..4287e7d13 100644 --- a/providers/venice/models/claude-opus-4-5.toml +++ b/providers/venice/models/claude-opus-4-5.toml @@ -2,7 +2,7 @@ name = "Claude Opus 4.5" family = "claude-opus" attachment = true reasoning = true -reasoning_options = [] +reasoning_options = [{ type = "effort", values = ["low", "medium", "high"] }] tool_call = true structured_output = true temperature = true diff --git a/providers/venice/models/claude-opus-4-6-fast.toml b/providers/venice/models/claude-opus-4-6-fast.toml index d8f280822..0c06d4333 100644 --- a/providers/venice/models/claude-opus-4-6-fast.toml +++ b/providers/venice/models/claude-opus-4-6-fast.toml @@ -2,7 +2,7 @@ name = "Claude Opus 4.6 Fast" family = "claude-opus" attachment = true reasoning = true -reasoning_options = [] +reasoning_options = [{ type = "effort", values = ["low", "medium", "high", "max"] }] tool_call = true structured_output = true temperature = true diff --git a/providers/venice/models/claude-opus-4-6.toml b/providers/venice/models/claude-opus-4-6.toml index 23618e503..632d503f2 100644 --- a/providers/venice/models/claude-opus-4-6.toml +++ b/providers/venice/models/claude-opus-4-6.toml @@ -2,7 +2,7 @@ name = "Claude Opus 4.6" family = "claude-opus" attachment = true reasoning = true -reasoning_options = [] +reasoning_options = [{ type = "effort", values = ["low", "medium", "high", "max"] }] tool_call = true structured_output = true temperature = true diff --git a/providers/venice/models/claude-opus-4-7-fast.toml b/providers/venice/models/claude-opus-4-7-fast.toml index 650ac025b..a41375999 100644 --- a/providers/venice/models/claude-opus-4-7-fast.toml +++ b/providers/venice/models/claude-opus-4-7-fast.toml @@ -2,7 +2,6 @@ name = "Claude Opus 4.7 Fast" family = "claude-opus" attachment = true reasoning = true -reasoning_options = [] tool_call = true structured_output = true temperature = true diff --git a/providers/venice/models/claude-opus-4-7.toml b/providers/venice/models/claude-opus-4-7.toml index 2669bae7f..72f1d4ff1 100644 --- a/providers/venice/models/claude-opus-4-7.toml +++ b/providers/venice/models/claude-opus-4-7.toml @@ -2,7 +2,6 @@ name = "Claude Opus 4.7" family = "claude-opus" attachment = true reasoning = true -reasoning_options = [] tool_call = true structured_output = true temperature = false diff --git a/providers/venice/models/claude-opus-4-8-fast.toml b/providers/venice/models/claude-opus-4-8-fast.toml index 5dab55a9e..40ec2ede6 100644 --- a/providers/venice/models/claude-opus-4-8-fast.toml +++ b/providers/venice/models/claude-opus-4-8-fast.toml @@ -2,7 +2,6 @@ name = "Claude Opus 4.8 Fast" family = "claude-opus" attachment = true reasoning = true -reasoning_options = [] tool_call = true structured_output = true temperature = true diff --git a/providers/venice/models/claude-opus-4-8.toml b/providers/venice/models/claude-opus-4-8.toml index 7a706e328..43b5ed161 100644 --- a/providers/venice/models/claude-opus-4-8.toml +++ b/providers/venice/models/claude-opus-4-8.toml @@ -2,7 +2,6 @@ name = "Claude Opus 4.8" family = "claude-opus" attachment = true reasoning = true -reasoning_options = [] tool_call = true structured_output = true temperature = true diff --git a/providers/venice/models/claude-sonnet-4-5.toml b/providers/venice/models/claude-sonnet-4-5.toml index a2eb40aa9..eea038ce7 100644 --- a/providers/venice/models/claude-sonnet-4-5.toml +++ b/providers/venice/models/claude-sonnet-4-5.toml @@ -2,7 +2,7 @@ name = "Claude Sonnet 4.5" family = "claude-sonnet" attachment = true reasoning = true -reasoning_options = [] +reasoning_options = [{ type = "effort", values = ["low", "medium", "high"] }] tool_call = true structured_output = true temperature = true diff --git a/providers/venice/models/claude-sonnet-4-6.toml b/providers/venice/models/claude-sonnet-4-6.toml index b3b975f10..9590e74de 100644 --- a/providers/venice/models/claude-sonnet-4-6.toml +++ b/providers/venice/models/claude-sonnet-4-6.toml @@ -2,7 +2,7 @@ name = "Claude Sonnet 4.6" family = "claude-sonnet" attachment = true reasoning = true -reasoning_options = [] +reasoning_options = [{ type = "effort", values = ["low", "medium", "high"] }] tool_call = true structured_output = true temperature = true diff --git a/providers/venice/models/deepseek-v4-flash.toml b/providers/venice/models/deepseek-v4-flash.toml index 0a5893c4c..7386d0765 100644 --- a/providers/venice/models/deepseek-v4-flash.toml +++ b/providers/venice/models/deepseek-v4-flash.toml @@ -2,7 +2,6 @@ name = "DeepSeek V4 Flash" family = "deepseek-flash" attachment = false reasoning = true -reasoning_options = [] tool_call = true structured_output = true temperature = true diff --git a/providers/venice/models/deepseek-v4-pro.toml b/providers/venice/models/deepseek-v4-pro.toml index 16f038e9d..df427c722 100644 --- a/providers/venice/models/deepseek-v4-pro.toml +++ b/providers/venice/models/deepseek-v4-pro.toml @@ -2,7 +2,6 @@ name = "DeepSeek V4 Pro" family = "deepseek" attachment = false reasoning = true -reasoning_options = [] tool_call = true structured_output = true temperature = true diff --git a/providers/venice/models/gemini-3-flash-preview.toml b/providers/venice/models/gemini-3-flash-preview.toml index 4fb34cce1..05c0c1e32 100644 --- a/providers/venice/models/gemini-3-flash-preview.toml +++ b/providers/venice/models/gemini-3-flash-preview.toml @@ -2,7 +2,7 @@ name = "Gemini 3 Flash Preview" family = "gemini-flash" attachment = true reasoning = true -reasoning_options = [{ type = "effort", values = ["low", "medium", "high"] }] +reasoning_options = [{ type = "effort", values = ["minimal", "low", "medium", "high"] }] tool_call = true structured_output = true temperature = true diff --git a/providers/venice/models/grok-4-20-multi-agent.toml b/providers/venice/models/grok-4-20-multi-agent.toml index 121468a04..2f12f71dd 100644 --- a/providers/venice/models/grok-4-20-multi-agent.toml +++ b/providers/venice/models/grok-4-20-multi-agent.toml @@ -2,7 +2,6 @@ name = "Grok 4.20 Multi-Agent" family = "grok" attachment = true reasoning = true -reasoning_options = [] tool_call = false structured_output = true temperature = true diff --git a/providers/venice/models/grok-4-20.toml b/providers/venice/models/grok-4-20.toml index 30f0e7911..dc9edb09c 100644 --- a/providers/venice/models/grok-4-20.toml +++ b/providers/venice/models/grok-4-20.toml @@ -2,7 +2,6 @@ name = "Grok 4.20" family = "grok" attachment = true reasoning = true -reasoning_options = [] tool_call = true structured_output = true temperature = true diff --git a/providers/venice/models/grok-4-3.toml b/providers/venice/models/grok-4-3.toml index 61205948f..9776d7713 100644 --- a/providers/venice/models/grok-4-3.toml +++ b/providers/venice/models/grok-4-3.toml @@ -2,7 +2,6 @@ name = "Grok 4.3" family = "grok" attachment = true reasoning = true -reasoning_options = [] tool_call = true structured_output = true temperature = true diff --git a/providers/venice/models/grok-build-0-1.toml b/providers/venice/models/grok-build-0-1.toml index 666cef732..68e26f0f6 100644 --- a/providers/venice/models/grok-build-0-1.toml +++ b/providers/venice/models/grok-build-0-1.toml @@ -2,7 +2,6 @@ name = "Grok Build 0.1" family = "grok-build" attachment = true reasoning = true -reasoning_options = [] tool_call = true structured_output = true temperature = true diff --git a/providers/venice/models/kimi-k2-5.toml b/providers/venice/models/kimi-k2-5.toml index 79430c9c1..538cda95f 100644 --- a/providers/venice/models/kimi-k2-5.toml +++ b/providers/venice/models/kimi-k2-5.toml @@ -2,7 +2,7 @@ name = "Kimi K2.5" family = "kimi" attachment = true reasoning = true -reasoning_options = [{ type = "effort", values = ["none", "low", "medium", "high"] }] +reasoning_options = [{ type = "effort", values = ["low", "medium", "high"] }] tool_call = true structured_output = true temperature = true diff --git a/providers/venice/models/minimax-m3.toml b/providers/venice/models/minimax-m3.toml index 7e87a3919..701ea4f1b 100644 --- a/providers/venice/models/minimax-m3.toml +++ b/providers/venice/models/minimax-m3.toml @@ -2,7 +2,6 @@ name = "MiniMax M3" family = "minimax-m3" attachment = true reasoning = true -reasoning_options = [] tool_call = true temperature = true release_date = "2026-06-01" diff --git a/providers/venice/models/openai-gpt-52-codex.toml b/providers/venice/models/openai-gpt-52-codex.toml index ed5c9c33f..f67655195 100644 --- a/providers/venice/models/openai-gpt-52-codex.toml +++ b/providers/venice/models/openai-gpt-52-codex.toml @@ -2,7 +2,7 @@ name = "GPT-5.2 Codex" family = "gpt-codex" attachment = true reasoning = true -reasoning_options = [{ type = "effort", values = ["none", "minimal", "low", "medium", "high"] }] +reasoning_options = [{ type = "effort", values = ["low", "medium", "high", "xhigh"] }] tool_call = true structured_output = true temperature = true diff --git a/providers/venice/models/openai-gpt-52.toml b/providers/venice/models/openai-gpt-52.toml index 44bc73338..09228e69b 100644 --- a/providers/venice/models/openai-gpt-52.toml +++ b/providers/venice/models/openai-gpt-52.toml @@ -2,7 +2,7 @@ name = "GPT-5.2" family = "gpt" attachment = false reasoning = true -reasoning_options = [{ type = "effort", values = ["none", "minimal", "low", "medium", "high"] }] +reasoning_options = [{ type = "effort", values = ["none", "low", "medium", "high", "xhigh"] }] tool_call = true structured_output = true temperature = true diff --git a/providers/venice/models/openai-gpt-53-codex.toml b/providers/venice/models/openai-gpt-53-codex.toml index bede658f6..755ef9ad0 100644 --- a/providers/venice/models/openai-gpt-53-codex.toml +++ b/providers/venice/models/openai-gpt-53-codex.toml @@ -2,7 +2,7 @@ name = "GPT-5.3 Codex" family = "gpt-codex" attachment = true reasoning = true -reasoning_options = [{ type = "effort", values = ["none", "minimal", "low", "medium", "high"] }] +reasoning_options = [{ type = "effort", values = ["low", "medium", "high", "xhigh"] }] tool_call = true structured_output = true temperature = true diff --git a/providers/venice/models/openai-gpt-54-mini.toml b/providers/venice/models/openai-gpt-54-mini.toml index 0e957c1d3..6cc34de7c 100644 --- a/providers/venice/models/openai-gpt-54-mini.toml +++ b/providers/venice/models/openai-gpt-54-mini.toml @@ -2,7 +2,7 @@ name = "GPT-5.4 Mini" family = "gpt-mini" attachment = true reasoning = true -reasoning_options = [{ type = "effort", values = ["none", "minimal", "low", "medium", "high"] }] +reasoning_options = [{ type = "effort", values = ["none", "low", "medium", "high", "xhigh"] }] tool_call = true structured_output = true temperature = true diff --git a/providers/venice/models/openai-gpt-54-pro.toml b/providers/venice/models/openai-gpt-54-pro.toml index 075b8135f..9b1c0c179 100644 --- a/providers/venice/models/openai-gpt-54-pro.toml +++ b/providers/venice/models/openai-gpt-54-pro.toml @@ -2,7 +2,7 @@ name = "GPT-5.4 Pro" family = "gpt-pro" attachment = true reasoning = true -reasoning_options = [{ type = "effort", values = ["none", "minimal", "low", "medium", "high"] }] +reasoning_options = [{ type = "effort", values = ["medium", "high", "xhigh"] }] tool_call = true structured_output = true temperature = true diff --git a/providers/venice/models/openai-gpt-54.toml b/providers/venice/models/openai-gpt-54.toml index 512c4d201..8bcd66cbe 100644 --- a/providers/venice/models/openai-gpt-54.toml +++ b/providers/venice/models/openai-gpt-54.toml @@ -2,7 +2,7 @@ name = "GPT-5.4" family = "gpt" attachment = true reasoning = true -reasoning_options = [{ type = "effort", values = ["none", "minimal", "low", "medium", "high"] }] +reasoning_options = [{ type = "effort", values = ["none", "low", "medium", "high", "xhigh"] }] tool_call = true structured_output = true temperature = true diff --git a/providers/venice/models/openai-gpt-55-pro.toml b/providers/venice/models/openai-gpt-55-pro.toml index 86afe0a92..a8a766b40 100644 --- a/providers/venice/models/openai-gpt-55-pro.toml +++ b/providers/venice/models/openai-gpt-55-pro.toml @@ -2,7 +2,7 @@ name = "GPT-5.5 Pro" family = "gpt-pro" attachment = true reasoning = true -reasoning_options = [{ type = "effort", values = ["none", "minimal", "low", "medium", "high"] }] +reasoning_options = [{ type = "effort", values = ["medium", "high", "xhigh"] }] tool_call = true structured_output = true temperature = true diff --git a/providers/venice/models/openai-gpt-55.toml b/providers/venice/models/openai-gpt-55.toml index db84c7016..59555aa95 100644 --- a/providers/venice/models/openai-gpt-55.toml +++ b/providers/venice/models/openai-gpt-55.toml @@ -2,7 +2,7 @@ name = "GPT-5.5" family = "gpt" attachment = true reasoning = true -reasoning_options = [{ type = "effort", values = ["none", "minimal", "low", "medium", "high"] }] +reasoning_options = [{ type = "effort", values = ["none", "low", "medium", "high", "xhigh"] }] tool_call = true structured_output = true temperature = true diff --git a/providers/venice/models/qwen-3-6-plus.toml b/providers/venice/models/qwen-3-6-plus.toml index e055c084b..36f547216 100644 --- a/providers/venice/models/qwen-3-6-plus.toml +++ b/providers/venice/models/qwen-3-6-plus.toml @@ -2,7 +2,6 @@ name = "Qwen 3.6 Plus Uncensored" family = "qwen" attachment = true reasoning = true -reasoning_options = [] tool_call = true structured_output = true temperature = true diff --git a/providers/venice/models/qwen-3-7-max.toml b/providers/venice/models/qwen-3-7-max.toml index 0ab43d97f..dc89fb2cb 100644 --- a/providers/venice/models/qwen-3-7-max.toml +++ b/providers/venice/models/qwen-3-7-max.toml @@ -2,7 +2,6 @@ name = "Qwen 3.7 Max" family = "qwen" attachment = false reasoning = true -reasoning_options = [] tool_call = true temperature = true release_date = "2026-05-22" diff --git a/providers/venice/models/qwen-3-7-plus.toml b/providers/venice/models/qwen-3-7-plus.toml index f1340f81a..98660260c 100644 --- a/providers/venice/models/qwen-3-7-plus.toml +++ b/providers/venice/models/qwen-3-7-plus.toml @@ -2,7 +2,6 @@ name = "Qwen 3.7 Plus" family = "qwen" attachment = true reasoning = true -reasoning_options = [] tool_call = true structured_output = true temperature = true diff --git a/providers/venice/models/qwen3-5-35b-a3b.toml b/providers/venice/models/qwen3-5-35b-a3b.toml index 0562eb770..8098010f6 100644 --- a/providers/venice/models/qwen3-5-35b-a3b.toml +++ b/providers/venice/models/qwen3-5-35b-a3b.toml @@ -2,7 +2,7 @@ name = "Qwen 3.5 35B A3B" family = "qwen" attachment = true reasoning = true -reasoning_options = [{ type = "effort", values = ["none", "low", "medium", "high"] }] +reasoning_options = [{ type = "effort", values = ["low", "medium", "high"] }] tool_call = true structured_output = true temperature = true diff --git a/providers/venice/models/zai-org-glm-5-1.toml b/providers/venice/models/zai-org-glm-5-1.toml index fdca1be73..78ed6364c 100644 --- a/providers/venice/models/zai-org-glm-5-1.toml +++ b/providers/venice/models/zai-org-glm-5-1.toml @@ -2,7 +2,7 @@ name = "GLM 5.1" family = "glm" attachment = false reasoning = true -reasoning_options = [{ type = "effort", values = ["none", "low", "medium", "high"] }] +reasoning_options = [] tool_call = true structured_output = true temperature = true From 78d7327c0a2274aa3eca3c2ef57b37300a18dc7e Mon Sep 17 00:00:00 2001 From: Aiden Cline Date: Mon, 8 Jun 2026 22:05:40 -0500 Subject: [PATCH 3/3] fix(venice): preserve unresolved reasoning metadata --- packages/core/script/generate-venice.ts | 2 +- packages/core/test/venice-generator.test.ts | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/packages/core/script/generate-venice.ts b/packages/core/script/generate-venice.ts index c8e6d94ba..9a1a6d04d 100644 --- a/packages/core/script/generate-venice.ts +++ b/packages/core/script/generate-venice.ts @@ -356,7 +356,7 @@ export function mergeModel( ? effort(...caps.reasoningEffortOptions) : undefined; const curatedOptions = existing?.reasoning_options; - const selectedOptions = override ?? curatedOptions ?? catalogOptions; + const selectedOptions = override ?? curatedOptions ?? (existing === null ? catalogOptions : undefined); if (selectedOptions !== undefined) { merged.reasoning_options = selectedOptions; diff --git a/packages/core/test/venice-generator.test.ts b/packages/core/test/venice-generator.test.ts index ed30c89dc..b35560140 100644 --- a/packages/core/test/venice-generator.test.ts +++ b/packages/core/test/venice-generator.test.ts @@ -61,6 +61,17 @@ test("catalog fills only an uncurated new model", () => { expect(merged.reasoning_options).toEqual(options("low", "high")); }); +test("catalog does not fill an unresolved existing model", () => { + const existing = { reasoning: true }; + const merged = mergeModel(model("existing-unresolved-reasoner", { + supportsReasoningEffort: true, + reasoningEffortOptions: ["low", "high"], + }), existing); + + expect(merged.reasoning_options).toBeUndefined(); + expect(detectChanges(existing, merged).find((change) => change.field === "reasoning_options")).toBeUndefined(); +}); + test("catalog false without curated evidence leaves options undefined", () => { const merged = mergeModel(model("unknown-fixed-reasoner", { supportsReasoningEffort: false,