From 3f50afbbf21bed8e4fa3223210b13dedcdec74b8 Mon Sep 17 00:00:00 2001 From: YoVinchen Date: Wed, 11 Feb 2026 23:09:43 +0800 Subject: [PATCH] feat(omo): enrich preset model defaults and metadata fallback --- .../providers/forms/OmoFormFields.tsx | 8 + .../providers/forms/ProviderForm.tsx | 40 ++- src/config/opencodeProviderPresets.ts | 227 ++++++++++++++---- 3 files changed, 221 insertions(+), 54 deletions(-) diff --git a/src/components/providers/forms/OmoFormFields.tsx b/src/components/providers/forms/OmoFormFields.tsx index 94f2359fb..9ec647472 100644 --- a/src/components/providers/forms/OmoFormFields.tsx +++ b/src/components/providers/forms/OmoFormFields.tsx @@ -60,6 +60,13 @@ const ADVANCED_PLACEHOLDER = `{ interface OmoFormFieldsProps { modelOptions: Array<{ value: string; label: string }>; modelVariantsMap?: Record; + presetMetaMap?: Record< + string, + { + options?: Record; + limit?: { context?: number; output?: number }; + } + >; agents: Record>; onAgentsChange: (agents: Record>) => void; categories: Record>; @@ -276,6 +283,7 @@ function mergeCustomModelsIntoStore( export function OmoFormFields({ modelOptions, modelVariantsMap = {}, + presetMetaMap: _presetMetaMap = {}, agents, onAgentsChange, categories, diff --git a/src/components/providers/forms/ProviderForm.tsx b/src/components/providers/forms/ProviderForm.tsx index f3d4a01df..d1c909720 100644 --- a/src/components/providers/forms/ProviderForm.tsx +++ b/src/components/providers/forms/ProviderForm.tsx @@ -649,6 +649,13 @@ export function ProviderForm({ const empty = { options: [] as Array<{ value: string; label: string }>, variantsMap: {} as Record, + presetMetaMap: {} as Record< + string, + { + options?: Record; + limit?: { context?: number; output?: number }; + } + >, parseFailedProviders: [] as string[], usedFallbackSource: false, }; @@ -672,6 +679,13 @@ export function ProviderForm({ const dedupedOptions = new Map(); const variantsMap: Record = {}; + const presetMetaMap: Record< + string, + { + options?: Record; + limit?: { context?: number; output?: number }; + } + > = {}; const parseFailedProviders: string[] = []; for (const [providerKey, provider] of Object.entries(allProviders)) { @@ -727,21 +741,34 @@ export function ProviderForm({ } // Preset fallback: for models without config-defined variants, - // check if the npm package has preset variant definitions + // check if the npm package has preset variant definitions. + // Also collect preset metadata (options, limit) for enrichment. const presetModels = OPENCODE_PRESET_MODEL_VARIANTS[parsedConfig.npm]; if (presetModels) { for (const modelId of Object.keys(parsedConfig.models || {})) { const fullKey = `${providerKey}/${modelId}`; - if (variantsMap[fullKey]) { - continue; - } const preset = presetModels.find((p) => p.id === modelId); - if (preset?.variants) { + if (!preset) continue; + + // Variant fallback + if (!variantsMap[fullKey] && preset.variants) { const presetKeys = Object.keys(preset.variants).filter(Boolean); if (presetKeys.length > 0) { variantsMap[fullKey] = presetKeys; } } + + // Collect preset metadata for model enrichment + const meta: (typeof presetMetaMap)[string] = {}; + if (preset.options) meta.options = preset.options; + if (preset.contextLimit || preset.outputLimit) { + meta.limit = {}; + if (preset.contextLimit) meta.limit.context = preset.contextLimit; + if (preset.outputLimit) meta.limit.output = preset.outputLimit; + } + if (Object.keys(meta).length > 0) { + presetMetaMap[fullKey] = meta; + } } } } @@ -751,6 +778,7 @@ export function ProviderForm({ .map(([value, label]) => ({ value, label })) .sort((a, b) => a.label.localeCompare(b.label, "zh-CN")), variantsMap, + presetMetaMap, parseFailedProviders, usedFallbackSource: omoLiveIdsLoadFailed, }; @@ -762,6 +790,7 @@ export function ProviderForm({ ]); const omoModelOptions = omoModelBuild.options; const omoModelVariantsMap = omoModelBuild.variantsMap; + const omoPresetMetaMap = omoModelBuild.presetMetaMap; useEffect(() => { if (!isOmoCategory) return; @@ -1699,6 +1728,7 @@ export function ProviderForm({ ; variants?: Record>; } @@ -33,19 +38,58 @@ export const OPENCODE_PRESET_MODEL_VARIANTS: Record< string, PresetModelVariant[] > = { + "@ai-sdk/openai-compatible": [ + { + id: "MiniMax-M2.1", + name: "MiniMax M2.1", + contextLimit: 204800, + outputLimit: 131072, + modalities: { input: ["text"], output: ["text"] }, + }, + { + id: "glm-4.7", + name: "GLM 4.7", + contextLimit: 204800, + outputLimit: 131072, + modalities: { input: ["text"], output: ["text"] }, + }, + { + id: "kimi-k2.5", + name: "Kimi K2.5", + contextLimit: 262144, + outputLimit: 262144, + modalities: { input: ["text", "image", "video"], output: ["text"] }, + }, + ], "@ai-sdk/google": [ { id: "gemini-2.5-flash-lite", + name: "Gemini 2.5 Flash Lite", + contextLimit: 1048576, + outputLimit: 65536, + modalities: { + input: ["text", "image", "pdf", "video", "audio"], + output: ["text"], + }, variants: { - auto: { thinkingConfig: { includeThoughts: true, thinkingBudget: -1 } }, + auto: { + thinkingConfig: { includeThoughts: true, thinkingBudget: -1 }, + }, "no-thinking": { thinkingConfig: { thinkingBudget: 0 } }, }, }, { id: "gemini-3-flash-preview", + name: "Gemini 3 Flash Preview", + contextLimit: 1048576, + outputLimit: 65536, + modalities: { + input: ["text", "image", "pdf", "video", "audio"], + output: ["text"], + }, variants: { - high: { - thinkingConfig: { includeThoughts: true, thinkingLevel: "high" }, + minimal: { + thinkingConfig: { includeThoughts: true, thinkingLevel: "minimal" }, }, low: { thinkingConfig: { includeThoughts: true, thinkingLevel: "low" }, @@ -53,29 +97,38 @@ export const OPENCODE_PRESET_MODEL_VARIANTS: Record< medium: { thinkingConfig: { includeThoughts: true, thinkingLevel: "medium" }, }, + high: { + thinkingConfig: { includeThoughts: true, thinkingLevel: "high" }, + }, }, }, { id: "gemini-3-pro-preview", + name: "Gemini 3 Pro Preview", + contextLimit: 1048576, + outputLimit: 65536, + modalities: { + input: ["text", "image", "pdf", "video", "audio"], + output: ["text"], + }, variants: { - high: { - thinkingConfig: { includeThoughts: true, thinkingLevel: "high" }, - }, low: { thinkingConfig: { includeThoughts: true, thinkingLevel: "low" }, }, + high: { + thinkingConfig: { includeThoughts: true, thinkingLevel: "high" }, + }, }, }, ], "@ai-sdk/openai": [ { id: "gpt-5", + name: "GPT-5", + contextLimit: 400000, + outputLimit: 128000, + modalities: { input: ["text", "image"], output: ["text"] }, variants: { - high: { - reasoningEffort: "high", - reasoningSummary: "auto", - textVerbosity: "high", - }, low: { reasoningEffort: "low", reasoningSummary: "auto", @@ -86,16 +139,20 @@ export const OPENCODE_PRESET_MODEL_VARIANTS: Record< reasoningSummary: "auto", textVerbosity: "medium", }, + high: { + reasoningEffort: "high", + reasoningSummary: "auto", + textVerbosity: "high", + }, }, }, { id: "gpt-5.1", + name: "GPT-5.1", + contextLimit: 400000, + outputLimit: 272000, + modalities: { input: ["text", "image"], output: ["text"] }, variants: { - high: { - reasoningEffort: "high", - reasoningSummary: "auto", - textVerbosity: "high", - }, low: { reasoningEffort: "low", reasoningSummary: "auto", @@ -106,16 +163,21 @@ export const OPENCODE_PRESET_MODEL_VARIANTS: Record< reasoningSummary: "auto", textVerbosity: "medium", }, + high: { + reasoningEffort: "high", + reasoningSummary: "auto", + textVerbosity: "high", + }, }, }, { id: "gpt-5.1-codex", + name: "GPT-5.1 Codex", + contextLimit: 400000, + outputLimit: 128000, + modalities: { input: ["text", "image"], output: ["text"] }, + options: { include: ["reasoning.encrypted_content"], store: false }, variants: { - high: { - reasoningEffort: "high", - reasoningSummary: "auto", - textVerbosity: "medium", - }, low: { reasoningEffort: "low", reasoningSummary: "auto", @@ -126,16 +188,21 @@ export const OPENCODE_PRESET_MODEL_VARIANTS: Record< reasoningSummary: "auto", textVerbosity: "medium", }, + high: { + reasoningEffort: "high", + reasoningSummary: "auto", + textVerbosity: "medium", + }, }, }, { id: "gpt-5.1-codex-max", + name: "GPT-5.1 Codex Max", + contextLimit: 400000, + outputLimit: 128000, + modalities: { input: ["text", "image"], output: ["text"] }, + options: { include: ["reasoning.encrypted_content"], store: false }, variants: { - high: { - reasoningEffort: "high", - reasoningSummary: "auto", - textVerbosity: "medium", - }, low: { reasoningEffort: "low", reasoningSummary: "auto", @@ -146,6 +213,11 @@ export const OPENCODE_PRESET_MODEL_VARIANTS: Record< reasoningSummary: "auto", textVerbosity: "medium", }, + high: { + reasoningEffort: "high", + reasoningSummary: "auto", + textVerbosity: "medium", + }, xhigh: { reasoningEffort: "xhigh", reasoningSummary: "auto", @@ -155,12 +227,11 @@ export const OPENCODE_PRESET_MODEL_VARIANTS: Record< }, { id: "gpt-5.2", + name: "GPT-5.2", + contextLimit: 400000, + outputLimit: 128000, + modalities: { input: ["text", "image"], output: ["text"] }, variants: { - high: { - reasoningEffort: "high", - reasoningSummary: "auto", - textVerbosity: "medium", - }, low: { reasoningEffort: "low", reasoningSummary: "auto", @@ -171,6 +242,11 @@ export const OPENCODE_PRESET_MODEL_VARIANTS: Record< reasoningSummary: "auto", textVerbosity: "medium", }, + high: { + reasoningEffort: "high", + reasoningSummary: "auto", + textVerbosity: "medium", + }, xhigh: { reasoningEffort: "xhigh", reasoningSummary: "auto", @@ -180,12 +256,12 @@ export const OPENCODE_PRESET_MODEL_VARIANTS: Record< }, { id: "gpt-5.2-codex", + name: "GPT-5.2 Codex", + contextLimit: 400000, + outputLimit: 128000, + modalities: { input: ["text", "image"], output: ["text"] }, + options: { include: ["reasoning.encrypted_content"], store: false }, variants: { - high: { - reasoningEffort: "high", - reasoningSummary: "auto", - textVerbosity: "medium", - }, low: { reasoningEffort: "low", reasoningSummary: "auto", @@ -196,6 +272,11 @@ export const OPENCODE_PRESET_MODEL_VARIANTS: Record< reasoningSummary: "auto", textVerbosity: "medium", }, + high: { + reasoningEffort: "high", + reasoningSummary: "auto", + textVerbosity: "medium", + }, xhigh: { reasoningEffort: "xhigh", reasoningSummary: "auto", @@ -205,12 +286,12 @@ export const OPENCODE_PRESET_MODEL_VARIANTS: Record< }, { id: "gpt-5.3-codex", + name: "GPT-5.3 Codex", + contextLimit: 400000, + outputLimit: 128000, + modalities: { input: ["text", "image"], output: ["text"] }, + options: { include: ["reasoning.encrypted_content"], store: false }, variants: { - high: { - reasoningEffort: "high", - reasoningSummary: "auto", - textVerbosity: "medium", - }, low: { reasoningEffort: "low", reasoningSummary: "auto", @@ -221,6 +302,11 @@ export const OPENCODE_PRESET_MODEL_VARIANTS: Record< reasoningSummary: "auto", textVerbosity: "medium", }, + high: { + reasoningEffort: "high", + reasoningSummary: "auto", + textVerbosity: "medium", + }, xhigh: { reasoningEffort: "xhigh", reasoningSummary: "auto", @@ -232,50 +318,90 @@ export const OPENCODE_PRESET_MODEL_VARIANTS: Record< "@ai-sdk/anthropic": [ { id: "claude-sonnet-4-5-20250929", + name: "Claude Sonnet 4.5", + contextLimit: 200000, + outputLimit: 64000, + modalities: { input: ["text", "image", "pdf"], output: ["text"] }, variants: { - high: { effort: "high" }, low: { effort: "low" }, medium: { effort: "medium" }, + high: { effort: "high" }, }, }, { id: "claude-opus-4-5-20251101", + name: "Claude Opus 4.5", + contextLimit: 200000, + outputLimit: 64000, + modalities: { input: ["text", "image", "pdf"], output: ["text"] }, variants: { - high: { thinking: { budgetTokens: 18000, type: "enabled" } }, low: { thinking: { budgetTokens: 5000, type: "enabled" } }, medium: { thinking: { budgetTokens: 13000, type: "enabled" } }, + high: { thinking: { budgetTokens: 18000, type: "enabled" } }, }, }, { id: "claude-opus-4-6", + name: "Claude Opus 4.6", + contextLimit: 1000000, + outputLimit: 128000, + modalities: { input: ["text", "image", "pdf"], output: ["text"] }, variants: { - high: { thinking: { budgetTokens: 18000, type: "enabled" } }, - low: { thinking: { budgetTokens: 5000, type: "enabled" } }, - medium: { thinking: { budgetTokens: 13000, type: "enabled" } }, + low: { effort: "low" }, + medium: { effort: "medium" }, + high: { effort: "high" }, + max: { effort: "max" }, }, }, { id: "claude-haiku-4-5-20251001", + name: "Claude Haiku 4.5", + contextLimit: 200000, + outputLimit: 64000, + modalities: { input: ["text", "image", "pdf"], output: ["text"] }, }, { id: "gemini-claude-opus-4-5-thinking", + name: "Antigravity - Claude Opus 4.5", + contextLimit: 200000, + outputLimit: 64000, + modalities: { input: ["text", "image", "pdf"], output: ["text"] }, variants: { - high: { effort: "high" }, low: { effort: "low" }, medium: { effort: "medium" }, + high: { effort: "high" }, }, }, { id: "gemini-claude-sonnet-4-5-thinking", + name: "Antigravity - Claude Sonnet 4.5", + contextLimit: 200000, + outputLimit: 64000, + modalities: { input: ["text", "image", "pdf"], output: ["text"] }, variants: { - high: { thinking: { budgetTokens: 18000, type: "enabled" } }, low: { thinking: { budgetTokens: 5000, type: "enabled" } }, medium: { thinking: { budgetTokens: 13000, type: "enabled" } }, + high: { thinking: { budgetTokens: 18000, type: "enabled" } }, }, }, ], }; +/** + * Look up preset metadata for a model by npm package and model ID. + * Returns enrichment fields (options, limit, modalities) that can be + * merged into a model definition when the user's config doesn't already + * provide them. + */ +export function getPresetModelDefaults( + npm: string, + modelId: string, +): PresetModelVariant | undefined { + const models = OPENCODE_PRESET_MODEL_VARIANTS[npm]; + if (!models) return undefined; + return models.find((m) => m.id === modelId); +} + export const opencodeProviderPresets: OpenCodeProviderPreset[] = [ { name: "DeepSeek", @@ -916,7 +1042,10 @@ export const opencodeProviderPresets: OpenCodeProviderPreset[] = [ }, models: { "gpt-5.2": { name: "GPT-5.2" }, - "gpt-5.2-codex": { name: "GPT-5.2 Codex" }, + "gpt-5.2-codex": { + name: "GPT-5.2 Codex", + options: { include: ["reasoning.encrypted_content"], store: false }, + }, }, }, category: "third_party",