mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-06-16 13:34:04 +08:00
feat(omo): enrich preset model defaults and metadata fallback
This commit is contained in:
@@ -60,6 +60,13 @@ const ADVANCED_PLACEHOLDER = `{
|
||||
interface OmoFormFieldsProps {
|
||||
modelOptions: Array<{ value: string; label: string }>;
|
||||
modelVariantsMap?: Record<string, string[]>;
|
||||
presetMetaMap?: Record<
|
||||
string,
|
||||
{
|
||||
options?: Record<string, unknown>;
|
||||
limit?: { context?: number; output?: number };
|
||||
}
|
||||
>;
|
||||
agents: Record<string, Record<string, unknown>>;
|
||||
onAgentsChange: (agents: Record<string, Record<string, unknown>>) => void;
|
||||
categories: Record<string, Record<string, unknown>>;
|
||||
@@ -276,6 +283,7 @@ function mergeCustomModelsIntoStore(
|
||||
export function OmoFormFields({
|
||||
modelOptions,
|
||||
modelVariantsMap = {},
|
||||
presetMetaMap: _presetMetaMap = {},
|
||||
agents,
|
||||
onAgentsChange,
|
||||
categories,
|
||||
|
||||
@@ -649,6 +649,13 @@ export function ProviderForm({
|
||||
const empty = {
|
||||
options: [] as Array<{ value: string; label: string }>,
|
||||
variantsMap: {} as Record<string, string[]>,
|
||||
presetMetaMap: {} as Record<
|
||||
string,
|
||||
{
|
||||
options?: Record<string, unknown>;
|
||||
limit?: { context?: number; output?: number };
|
||||
}
|
||||
>,
|
||||
parseFailedProviders: [] as string[],
|
||||
usedFallbackSource: false,
|
||||
};
|
||||
@@ -672,6 +679,13 @@ export function ProviderForm({
|
||||
|
||||
const dedupedOptions = new Map<string, string>();
|
||||
const variantsMap: Record<string, string[]> = {};
|
||||
const presetMetaMap: Record<
|
||||
string,
|
||||
{
|
||||
options?: Record<string, unknown>;
|
||||
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({
|
||||
<OmoFormFields
|
||||
modelOptions={omoModelOptions}
|
||||
modelVariantsMap={omoModelVariantsMap}
|
||||
presetMetaMap={omoPresetMetaMap}
|
||||
agents={omoAgents}
|
||||
onAgentsChange={setOmoAgents}
|
||||
categories={omoCategories}
|
||||
|
||||
@@ -26,6 +26,11 @@ export const opencodeNpmPackages = [
|
||||
|
||||
export interface PresetModelVariant {
|
||||
id: string;
|
||||
name?: string;
|
||||
contextLimit?: number;
|
||||
outputLimit?: number;
|
||||
modalities?: { input: string[]; output: string[] };
|
||||
options?: Record<string, unknown>;
|
||||
variants?: Record<string, Record<string, unknown>>;
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
|
||||
Reference in New Issue
Block a user