chore: update FUN-Codex and FUN-Claude provider models (#522)
FUN-Codex: add GPT models (5.5, 5.4, 5.4-mini, 5.3-codex, 5.3-codex-spark) FUN-Claude: replace with actual Claude models from API (opus-4-7 down to 3-5-haiku) Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -41,7 +41,7 @@ export async function getAvailable(ctx: any) {
|
||||
currentDefault = modelSection.trim()
|
||||
}
|
||||
|
||||
const groups: Array<{ provider: string; label: string; base_url: string; models: string[]; api_key: string; model_meta?: Record<string, { preview?: boolean; disabled?: boolean }> }> = []
|
||||
const groups: Array<{ provider: string; label: string; base_url: string; models: string[]; api_key: string; builtin?: boolean; model_meta?: Record<string, { preview?: boolean; disabled?: boolean }> }> = []
|
||||
const seenProviders = new Set<string>()
|
||||
|
||||
let envContent = ''
|
||||
@@ -57,10 +57,10 @@ export async function getAvailable(ctx: any) {
|
||||
const match = envContent.match(new RegExp(`^${key}\\s*=\\s*(.+)`, 'm'))
|
||||
return match?.[1]?.trim() || ''
|
||||
}
|
||||
const addGroup = (provider: string, label: string, base_url: string, models: string[], api_key: string, model_meta?: Record<string, { preview?: boolean; disabled?: boolean }>) => {
|
||||
const addGroup = (provider: string, label: string, base_url: string, models: string[], api_key: string, builtin?: boolean, model_meta?: Record<string, { preview?: boolean; disabled?: boolean }>) => {
|
||||
if (seenProviders.has(provider)) return
|
||||
seenProviders.add(provider)
|
||||
groups.push({ provider, label, base_url, models: [...models], api_key, ...(model_meta ? { model_meta } : {}) })
|
||||
groups.push({ provider, label, base_url, models: [...models], api_key, ...(builtin ? { builtin: true } : {}), ...(model_meta ? { model_meta } : {}) })
|
||||
}
|
||||
|
||||
const isOAuthAuthorized = (providerKey: string): boolean => {
|
||||
@@ -150,7 +150,7 @@ export async function getAvailable(ctx: any) {
|
||||
}
|
||||
if (modelsList.length > 0) {
|
||||
const apiKey = envMapping.api_key_env ? envGetValue(envMapping.api_key_env) : ''
|
||||
addGroup(providerKey, label, baseUrl, modelsList, apiKey, modelMeta)
|
||||
addGroup(providerKey, label, baseUrl, modelsList, apiKey, true, modelMeta)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -166,19 +166,20 @@ export async function getAvailable(ctx: any) {
|
||||
const bareKey = cp.name.trim().toLowerCase().replace(/ /g, '-')
|
||||
const builtinPreset = PROVIDER_PRESETS.find(p => p.value === bareKey)
|
||||
let models = builtinPreset?.models?.length ? [...builtinPreset.models] : [cp.model]
|
||||
if (cp.api_key) {
|
||||
// Skip dynamic fetch for builtin presets — their model list is maintained in providers.ts
|
||||
if (!builtinPreset && cp.api_key) {
|
||||
try { const fetched = await fetchProviderModels(baseUrl, cp.api_key); if (fetched.length > 0) models = [...new Set([cp.model, ...fetched])] } catch { }
|
||||
}
|
||||
const label = builtinPreset?.label || cp.name
|
||||
const presetBaseUrl = builtinPreset?.base_url || ''
|
||||
return { providerKey, label, base_url: presetBaseUrl || baseUrl, models, api_key: cp.api_key || '' }
|
||||
return { providerKey, label, base_url: presetBaseUrl || baseUrl, models, api_key: cp.api_key || '', builtin: !!builtinPreset }
|
||||
}),
|
||||
)
|
||||
|
||||
for (const result of customFetches) {
|
||||
if (result.status === 'fulfilled' && result.value) {
|
||||
const { providerKey, label, base_url, models, api_key: cpApiKey } = result.value
|
||||
addGroup(providerKey, label, base_url, models, cpApiKey)
|
||||
const { providerKey, label, base_url, models, api_key: cpApiKey, builtin: cpBuiltin } = result.value as any
|
||||
addGroup(providerKey, label, base_url, models, cpApiKey, cpBuiltin)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ import { writeFile } from 'fs/promises'
|
||||
import { getActiveAuthPath } from '../../services/hermes/hermes-profile'
|
||||
import * as hermesCli from '../../services/hermes/hermes-cli'
|
||||
import { readConfigYaml, writeConfigYaml, saveEnvValue, PROVIDER_ENV_MAP } from '../../services/config-helpers'
|
||||
import { PROVIDER_PRESETS } from '../../shared/providers'
|
||||
import { logger } from '../../services/logger'
|
||||
|
||||
const OPTIONAL_API_KEY_PROVIDERS = new Set(['cliproxyapi'])
|
||||
@@ -39,18 +40,22 @@ export async function create(ctx: any) {
|
||||
existing.base_url = base_url
|
||||
existing.api_key = api_key
|
||||
existing.model = model
|
||||
const preset = PROVIDER_PRESETS.find(p => p.value === poolKey.replace('custom:', ''))
|
||||
if (preset?.api_mode) existing.api_mode = preset.api_mode
|
||||
if (context_length && context_length > 0) {
|
||||
if (!existing.models) existing.models = {}
|
||||
existing.models[model] = existing.models[model] || {}
|
||||
existing.models[model].context_length = context_length
|
||||
}
|
||||
} else {
|
||||
config.custom_providers.push(buildProviderEntry(name.trim().toLowerCase().replace(/ /g, '-'), base_url, api_key, model, context_length))
|
||||
const entry = buildProviderEntry(name.trim().toLowerCase().replace(/ /g, '-'), base_url, api_key, model, context_length)
|
||||
const preset = PROVIDER_PRESETS.find(p => p.value === poolKey.replace('custom:', ''))
|
||||
if (preset?.api_mode) entry.api_mode = preset.api_mode
|
||||
config.custom_providers.push(entry)
|
||||
}
|
||||
config.model.default = model
|
||||
config.model.provider = poolKey
|
||||
} else {
|
||||
console.log(PROVIDER_ENV_MAP[poolKey])
|
||||
if (PROVIDER_ENV_MAP[poolKey].api_key_env) {
|
||||
await saveEnvValue(PROVIDER_ENV_MAP[poolKey].api_key_env, api_key)
|
||||
if (PROVIDER_ENV_MAP[poolKey].base_url_env) { await saveEnvValue(PROVIDER_ENV_MAP[poolKey].base_url_env, base_url) }
|
||||
@@ -65,13 +70,18 @@ export async function create(ctx: any) {
|
||||
existing.base_url = base_url
|
||||
existing.api_key = api_key
|
||||
existing.model = model
|
||||
const preset = PROVIDER_PRESETS.find(p => p.value === poolKey)
|
||||
if (preset?.api_mode) existing.api_mode = preset.api_mode
|
||||
if (context_length && context_length > 0) {
|
||||
if (!existing.models) existing.models = {}
|
||||
existing.models[model] = existing.models[model] || {}
|
||||
existing.models[model].context_length = context_length
|
||||
}
|
||||
} else {
|
||||
config.custom_providers.push(buildProviderEntry(poolKey, base_url, api_key, model, context_length))
|
||||
const entry = buildProviderEntry(poolKey, base_url, api_key, model, context_length)
|
||||
const preset = PROVIDER_PRESETS.find(p => p.value === poolKey)
|
||||
if (preset?.api_mode) entry.api_mode = preset.api_mode
|
||||
config.custom_providers.push(entry)
|
||||
}
|
||||
config.model.default = model
|
||||
config.model.provider = `custom:${poolKey}`
|
||||
|
||||
@@ -8,6 +8,8 @@ import { logger } from './logger'
|
||||
|
||||
// --- Provider env var mapping (from hermes providers.py HERMES_OVERLAYS + config.py) ---
|
||||
export const PROVIDER_ENV_MAP: Record<string, { api_key_env: string; base_url_env: string }> = {
|
||||
'fun-codex': { api_key_env: '', base_url_env: '' },
|
||||
'fun-claude': { api_key_env: '', base_url_env: '' },
|
||||
openrouter: { api_key_env: 'OPENROUTER_API_KEY', base_url_env: '' },
|
||||
'glm-coding-plan': { api_key_env: '', base_url_env: '' },
|
||||
zai: { api_key_env: 'GLM_API_KEY', base_url_env: '' },
|
||||
|
||||
@@ -9,9 +9,36 @@ export interface ProviderPreset {
|
||||
base_url: string
|
||||
models: string[]
|
||||
builtin: boolean
|
||||
api_mode?: 'openai' | 'anthropic' | 'anthropic_messages'
|
||||
}
|
||||
|
||||
export const PROVIDER_PRESETS: ProviderPreset[] = [
|
||||
{
|
||||
label: 'FUN-Codex',
|
||||
value: 'fun-codex',
|
||||
builtin: true,
|
||||
base_url: 'https://api.apikey.fun/v1',
|
||||
models: [
|
||||
'gpt-5.5',
|
||||
'gpt-5.4',
|
||||
'gpt-5.4-mini',
|
||||
'gpt-5.3-codex',
|
||||
'gpt-5.3-codex-spark',
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'FUN-Claude',
|
||||
value: 'fun-claude',
|
||||
builtin: true,
|
||||
base_url: 'https://api.apikey.fun',
|
||||
api_mode: "anthropic_messages",
|
||||
models: [
|
||||
'claude-opus-4-7',
|
||||
'claude-opus-4-6',
|
||||
'claude-sonnet-4-6',
|
||||
'claude-haiku-4-5'
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'Anthropic',
|
||||
value: 'anthropic',
|
||||
|
||||
Reference in New Issue
Block a user