feat(omo): enrich preset model defaults and metadata fallback

This commit is contained in:
YoVinchen
2026-02-11 23:09:43 +08:00
parent b551bb92e2
commit 3f50afbbf2
3 changed files with 221 additions and 54 deletions
@@ -60,6 +60,13 @@ const ADVANCED_PLACEHOLDER = `{
interface OmoFormFieldsProps { interface OmoFormFieldsProps {
modelOptions: Array<{ value: string; label: string }>; modelOptions: Array<{ value: string; label: string }>;
modelVariantsMap?: Record<string, string[]>; modelVariantsMap?: Record<string, string[]>;
presetMetaMap?: Record<
string,
{
options?: Record<string, unknown>;
limit?: { context?: number; output?: number };
}
>;
agents: Record<string, Record<string, unknown>>; agents: Record<string, Record<string, unknown>>;
onAgentsChange: (agents: Record<string, Record<string, unknown>>) => void; onAgentsChange: (agents: Record<string, Record<string, unknown>>) => void;
categories: Record<string, Record<string, unknown>>; categories: Record<string, Record<string, unknown>>;
@@ -276,6 +283,7 @@ function mergeCustomModelsIntoStore(
export function OmoFormFields({ export function OmoFormFields({
modelOptions, modelOptions,
modelVariantsMap = {}, modelVariantsMap = {},
presetMetaMap: _presetMetaMap = {},
agents, agents,
onAgentsChange, onAgentsChange,
categories, categories,
@@ -649,6 +649,13 @@ export function ProviderForm({
const empty = { const empty = {
options: [] as Array<{ value: string; label: string }>, options: [] as Array<{ value: string; label: string }>,
variantsMap: {} as Record<string, string[]>, variantsMap: {} as Record<string, string[]>,
presetMetaMap: {} as Record<
string,
{
options?: Record<string, unknown>;
limit?: { context?: number; output?: number };
}
>,
parseFailedProviders: [] as string[], parseFailedProviders: [] as string[],
usedFallbackSource: false, usedFallbackSource: false,
}; };
@@ -672,6 +679,13 @@ export function ProviderForm({
const dedupedOptions = new Map<string, string>(); const dedupedOptions = new Map<string, string>();
const variantsMap: Record<string, string[]> = {}; const variantsMap: Record<string, string[]> = {};
const presetMetaMap: Record<
string,
{
options?: Record<string, unknown>;
limit?: { context?: number; output?: number };
}
> = {};
const parseFailedProviders: string[] = []; const parseFailedProviders: string[] = [];
for (const [providerKey, provider] of Object.entries(allProviders)) { for (const [providerKey, provider] of Object.entries(allProviders)) {
@@ -727,21 +741,34 @@ export function ProviderForm({
} }
// Preset fallback: for models without config-defined variants, // 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]; const presetModels = OPENCODE_PRESET_MODEL_VARIANTS[parsedConfig.npm];
if (presetModels) { if (presetModels) {
for (const modelId of Object.keys(parsedConfig.models || {})) { for (const modelId of Object.keys(parsedConfig.models || {})) {
const fullKey = `${providerKey}/${modelId}`; const fullKey = `${providerKey}/${modelId}`;
if (variantsMap[fullKey]) {
continue;
}
const preset = presetModels.find((p) => p.id === modelId); 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); const presetKeys = Object.keys(preset.variants).filter(Boolean);
if (presetKeys.length > 0) { if (presetKeys.length > 0) {
variantsMap[fullKey] = presetKeys; 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 })) .map(([value, label]) => ({ value, label }))
.sort((a, b) => a.label.localeCompare(b.label, "zh-CN")), .sort((a, b) => a.label.localeCompare(b.label, "zh-CN")),
variantsMap, variantsMap,
presetMetaMap,
parseFailedProviders, parseFailedProviders,
usedFallbackSource: omoLiveIdsLoadFailed, usedFallbackSource: omoLiveIdsLoadFailed,
}; };
@@ -762,6 +790,7 @@ export function ProviderForm({
]); ]);
const omoModelOptions = omoModelBuild.options; const omoModelOptions = omoModelBuild.options;
const omoModelVariantsMap = omoModelBuild.variantsMap; const omoModelVariantsMap = omoModelBuild.variantsMap;
const omoPresetMetaMap = omoModelBuild.presetMetaMap;
useEffect(() => { useEffect(() => {
if (!isOmoCategory) return; if (!isOmoCategory) return;
@@ -1699,6 +1728,7 @@ export function ProviderForm({
<OmoFormFields <OmoFormFields
modelOptions={omoModelOptions} modelOptions={omoModelOptions}
modelVariantsMap={omoModelVariantsMap} modelVariantsMap={omoModelVariantsMap}
presetMetaMap={omoPresetMetaMap}
agents={omoAgents} agents={omoAgents}
onAgentsChange={setOmoAgents} onAgentsChange={setOmoAgents}
categories={omoCategories} categories={omoCategories}
+178 -49
View File
@@ -26,6 +26,11 @@ export const opencodeNpmPackages = [
export interface PresetModelVariant { export interface PresetModelVariant {
id: string; id: string;
name?: string;
contextLimit?: number;
outputLimit?: number;
modalities?: { input: string[]; output: string[] };
options?: Record<string, unknown>;
variants?: Record<string, Record<string, unknown>>; variants?: Record<string, Record<string, unknown>>;
} }
@@ -33,19 +38,58 @@ export const OPENCODE_PRESET_MODEL_VARIANTS: Record<
string, string,
PresetModelVariant[] 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": [ "@ai-sdk/google": [
{ {
id: "gemini-2.5-flash-lite", 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: { variants: {
auto: { thinkingConfig: { includeThoughts: true, thinkingBudget: -1 } }, auto: {
thinkingConfig: { includeThoughts: true, thinkingBudget: -1 },
},
"no-thinking": { thinkingConfig: { thinkingBudget: 0 } }, "no-thinking": { thinkingConfig: { thinkingBudget: 0 } },
}, },
}, },
{ {
id: "gemini-3-flash-preview", id: "gemini-3-flash-preview",
name: "Gemini 3 Flash Preview",
contextLimit: 1048576,
outputLimit: 65536,
modalities: {
input: ["text", "image", "pdf", "video", "audio"],
output: ["text"],
},
variants: { variants: {
high: { minimal: {
thinkingConfig: { includeThoughts: true, thinkingLevel: "high" }, thinkingConfig: { includeThoughts: true, thinkingLevel: "minimal" },
}, },
low: { low: {
thinkingConfig: { includeThoughts: true, thinkingLevel: "low" }, thinkingConfig: { includeThoughts: true, thinkingLevel: "low" },
@@ -53,29 +97,38 @@ export const OPENCODE_PRESET_MODEL_VARIANTS: Record<
medium: { medium: {
thinkingConfig: { includeThoughts: true, thinkingLevel: "medium" }, thinkingConfig: { includeThoughts: true, thinkingLevel: "medium" },
}, },
high: {
thinkingConfig: { includeThoughts: true, thinkingLevel: "high" },
},
}, },
}, },
{ {
id: "gemini-3-pro-preview", id: "gemini-3-pro-preview",
name: "Gemini 3 Pro Preview",
contextLimit: 1048576,
outputLimit: 65536,
modalities: {
input: ["text", "image", "pdf", "video", "audio"],
output: ["text"],
},
variants: { variants: {
high: {
thinkingConfig: { includeThoughts: true, thinkingLevel: "high" },
},
low: { low: {
thinkingConfig: { includeThoughts: true, thinkingLevel: "low" }, thinkingConfig: { includeThoughts: true, thinkingLevel: "low" },
}, },
high: {
thinkingConfig: { includeThoughts: true, thinkingLevel: "high" },
},
}, },
}, },
], ],
"@ai-sdk/openai": [ "@ai-sdk/openai": [
{ {
id: "gpt-5", id: "gpt-5",
name: "GPT-5",
contextLimit: 400000,
outputLimit: 128000,
modalities: { input: ["text", "image"], output: ["text"] },
variants: { variants: {
high: {
reasoningEffort: "high",
reasoningSummary: "auto",
textVerbosity: "high",
},
low: { low: {
reasoningEffort: "low", reasoningEffort: "low",
reasoningSummary: "auto", reasoningSummary: "auto",
@@ -86,16 +139,20 @@ export const OPENCODE_PRESET_MODEL_VARIANTS: Record<
reasoningSummary: "auto", reasoningSummary: "auto",
textVerbosity: "medium", textVerbosity: "medium",
}, },
high: {
reasoningEffort: "high",
reasoningSummary: "auto",
textVerbosity: "high",
},
}, },
}, },
{ {
id: "gpt-5.1", id: "gpt-5.1",
name: "GPT-5.1",
contextLimit: 400000,
outputLimit: 272000,
modalities: { input: ["text", "image"], output: ["text"] },
variants: { variants: {
high: {
reasoningEffort: "high",
reasoningSummary: "auto",
textVerbosity: "high",
},
low: { low: {
reasoningEffort: "low", reasoningEffort: "low",
reasoningSummary: "auto", reasoningSummary: "auto",
@@ -106,16 +163,21 @@ export const OPENCODE_PRESET_MODEL_VARIANTS: Record<
reasoningSummary: "auto", reasoningSummary: "auto",
textVerbosity: "medium", textVerbosity: "medium",
}, },
high: {
reasoningEffort: "high",
reasoningSummary: "auto",
textVerbosity: "high",
},
}, },
}, },
{ {
id: "gpt-5.1-codex", 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: { variants: {
high: {
reasoningEffort: "high",
reasoningSummary: "auto",
textVerbosity: "medium",
},
low: { low: {
reasoningEffort: "low", reasoningEffort: "low",
reasoningSummary: "auto", reasoningSummary: "auto",
@@ -126,16 +188,21 @@ export const OPENCODE_PRESET_MODEL_VARIANTS: Record<
reasoningSummary: "auto", reasoningSummary: "auto",
textVerbosity: "medium", textVerbosity: "medium",
}, },
high: {
reasoningEffort: "high",
reasoningSummary: "auto",
textVerbosity: "medium",
},
}, },
}, },
{ {
id: "gpt-5.1-codex-max", 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: { variants: {
high: {
reasoningEffort: "high",
reasoningSummary: "auto",
textVerbosity: "medium",
},
low: { low: {
reasoningEffort: "low", reasoningEffort: "low",
reasoningSummary: "auto", reasoningSummary: "auto",
@@ -146,6 +213,11 @@ export const OPENCODE_PRESET_MODEL_VARIANTS: Record<
reasoningSummary: "auto", reasoningSummary: "auto",
textVerbosity: "medium", textVerbosity: "medium",
}, },
high: {
reasoningEffort: "high",
reasoningSummary: "auto",
textVerbosity: "medium",
},
xhigh: { xhigh: {
reasoningEffort: "xhigh", reasoningEffort: "xhigh",
reasoningSummary: "auto", reasoningSummary: "auto",
@@ -155,12 +227,11 @@ export const OPENCODE_PRESET_MODEL_VARIANTS: Record<
}, },
{ {
id: "gpt-5.2", id: "gpt-5.2",
name: "GPT-5.2",
contextLimit: 400000,
outputLimit: 128000,
modalities: { input: ["text", "image"], output: ["text"] },
variants: { variants: {
high: {
reasoningEffort: "high",
reasoningSummary: "auto",
textVerbosity: "medium",
},
low: { low: {
reasoningEffort: "low", reasoningEffort: "low",
reasoningSummary: "auto", reasoningSummary: "auto",
@@ -171,6 +242,11 @@ export const OPENCODE_PRESET_MODEL_VARIANTS: Record<
reasoningSummary: "auto", reasoningSummary: "auto",
textVerbosity: "medium", textVerbosity: "medium",
}, },
high: {
reasoningEffort: "high",
reasoningSummary: "auto",
textVerbosity: "medium",
},
xhigh: { xhigh: {
reasoningEffort: "xhigh", reasoningEffort: "xhigh",
reasoningSummary: "auto", reasoningSummary: "auto",
@@ -180,12 +256,12 @@ export const OPENCODE_PRESET_MODEL_VARIANTS: Record<
}, },
{ {
id: "gpt-5.2-codex", 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: { variants: {
high: {
reasoningEffort: "high",
reasoningSummary: "auto",
textVerbosity: "medium",
},
low: { low: {
reasoningEffort: "low", reasoningEffort: "low",
reasoningSummary: "auto", reasoningSummary: "auto",
@@ -196,6 +272,11 @@ export const OPENCODE_PRESET_MODEL_VARIANTS: Record<
reasoningSummary: "auto", reasoningSummary: "auto",
textVerbosity: "medium", textVerbosity: "medium",
}, },
high: {
reasoningEffort: "high",
reasoningSummary: "auto",
textVerbosity: "medium",
},
xhigh: { xhigh: {
reasoningEffort: "xhigh", reasoningEffort: "xhigh",
reasoningSummary: "auto", reasoningSummary: "auto",
@@ -205,12 +286,12 @@ export const OPENCODE_PRESET_MODEL_VARIANTS: Record<
}, },
{ {
id: "gpt-5.3-codex", 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: { variants: {
high: {
reasoningEffort: "high",
reasoningSummary: "auto",
textVerbosity: "medium",
},
low: { low: {
reasoningEffort: "low", reasoningEffort: "low",
reasoningSummary: "auto", reasoningSummary: "auto",
@@ -221,6 +302,11 @@ export const OPENCODE_PRESET_MODEL_VARIANTS: Record<
reasoningSummary: "auto", reasoningSummary: "auto",
textVerbosity: "medium", textVerbosity: "medium",
}, },
high: {
reasoningEffort: "high",
reasoningSummary: "auto",
textVerbosity: "medium",
},
xhigh: { xhigh: {
reasoningEffort: "xhigh", reasoningEffort: "xhigh",
reasoningSummary: "auto", reasoningSummary: "auto",
@@ -232,50 +318,90 @@ export const OPENCODE_PRESET_MODEL_VARIANTS: Record<
"@ai-sdk/anthropic": [ "@ai-sdk/anthropic": [
{ {
id: "claude-sonnet-4-5-20250929", id: "claude-sonnet-4-5-20250929",
name: "Claude Sonnet 4.5",
contextLimit: 200000,
outputLimit: 64000,
modalities: { input: ["text", "image", "pdf"], output: ["text"] },
variants: { variants: {
high: { effort: "high" },
low: { effort: "low" }, low: { effort: "low" },
medium: { effort: "medium" }, medium: { effort: "medium" },
high: { effort: "high" },
}, },
}, },
{ {
id: "claude-opus-4-5-20251101", id: "claude-opus-4-5-20251101",
name: "Claude Opus 4.5",
contextLimit: 200000,
outputLimit: 64000,
modalities: { input: ["text", "image", "pdf"], output: ["text"] },
variants: { variants: {
high: { thinking: { budgetTokens: 18000, type: "enabled" } },
low: { thinking: { budgetTokens: 5000, type: "enabled" } }, low: { thinking: { budgetTokens: 5000, type: "enabled" } },
medium: { thinking: { budgetTokens: 13000, type: "enabled" } }, medium: { thinking: { budgetTokens: 13000, type: "enabled" } },
high: { thinking: { budgetTokens: 18000, type: "enabled" } },
}, },
}, },
{ {
id: "claude-opus-4-6", id: "claude-opus-4-6",
name: "Claude Opus 4.6",
contextLimit: 1000000,
outputLimit: 128000,
modalities: { input: ["text", "image", "pdf"], output: ["text"] },
variants: { variants: {
high: { thinking: { budgetTokens: 18000, type: "enabled" } }, low: { effort: "low" },
low: { thinking: { budgetTokens: 5000, type: "enabled" } }, medium: { effort: "medium" },
medium: { thinking: { budgetTokens: 13000, type: "enabled" } }, high: { effort: "high" },
max: { effort: "max" },
}, },
}, },
{ {
id: "claude-haiku-4-5-20251001", 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", 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: { variants: {
high: { effort: "high" },
low: { effort: "low" }, low: { effort: "low" },
medium: { effort: "medium" }, medium: { effort: "medium" },
high: { effort: "high" },
}, },
}, },
{ {
id: "gemini-claude-sonnet-4-5-thinking", 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: { variants: {
high: { thinking: { budgetTokens: 18000, type: "enabled" } },
low: { thinking: { budgetTokens: 5000, type: "enabled" } }, low: { thinking: { budgetTokens: 5000, type: "enabled" } },
medium: { thinking: { budgetTokens: 13000, 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[] = [ export const opencodeProviderPresets: OpenCodeProviderPreset[] = [
{ {
name: "DeepSeek", name: "DeepSeek",
@@ -916,7 +1042,10 @@ export const opencodeProviderPresets: OpenCodeProviderPreset[] = [
}, },
models: { models: {
"gpt-5.2": { name: "GPT-5.2" }, "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", category: "third_party",