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:
@@ -31,6 +31,7 @@ export interface AvailableModelGroup {
|
|||||||
base_url: string
|
base_url: string
|
||||||
models: string[]
|
models: string[]
|
||||||
api_key: string
|
api_key: string
|
||||||
|
builtin?: boolean
|
||||||
/** 可选:模型 ID -> 元数据(preview/disabled)。目前仅 Copilot 提供。 */
|
/** 可选:模型 ID -> 元数据(preview/disabled)。目前仅 Copilot 提供。 */
|
||||||
model_meta?: Record<string, { preview?: boolean; disabled?: boolean }>
|
model_meta?: Record<string, { preview?: boolean; disabled?: boolean }>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ const chatStore = useChatStore()
|
|||||||
const message = useMessage()
|
const message = useMessage()
|
||||||
const dialog = useDialog()
|
const dialog = useDialog()
|
||||||
|
|
||||||
const isCustom = computed(() => props.provider.provider.startsWith('custom:'))
|
const isCustom = computed(() => !props.provider.builtin && props.provider.provider.startsWith('custom:'))
|
||||||
const isCopilot = computed(() => props.provider.provider === 'copilot')
|
const isCopilot = computed(() => props.provider.provider === 'copilot')
|
||||||
const displayName = computed(() => props.provider.label)
|
const displayName = computed(() => props.provider.label)
|
||||||
const deleting = ref(false)
|
const deleting = ref(false)
|
||||||
|
|||||||
@@ -60,6 +60,13 @@ const presetOptions = computed(() =>
|
|||||||
modelsStore.allProviders.map(g => ({ label: g.label, value: g.provider })),
|
modelsStore.allProviders.map(g => ({ label: g.label, value: g.provider })),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const FUN_LINK_MAP: Record<string, string> = {
|
||||||
|
'fun-codex': 'https://apikey.fun/register?aff=LIBAPI',
|
||||||
|
'fun-claude': 'https://apikey.fun/register?aff=LIBAPI',
|
||||||
|
}
|
||||||
|
|
||||||
|
const funProviderLink = computed(() => selectedPreset.value ? FUN_LINK_MAP[selectedPreset.value] || '' : '')
|
||||||
|
|
||||||
function autoGenerateName(url: string): string {
|
function autoGenerateName(url: string): string {
|
||||||
const clean = url.replace(/^https?:\/\//, '').replace(/\/v1\/?$/, '')
|
const clean = url.replace(/^https?:\/\//, '').replace(/\/v1\/?$/, '')
|
||||||
const host = clean.split('/')[0]
|
const host = clean.split('/')[0]
|
||||||
@@ -322,6 +329,12 @@ function handleClose() {
|
|||||||
:placeholder="t('models.chooseProvider')"
|
:placeholder="t('models.chooseProvider')"
|
||||||
filterable
|
filterable
|
||||||
/>
|
/>
|
||||||
|
<div v-if="selectedPreset && funProviderLink" class="fun-provider-hint">
|
||||||
|
<a :href="funProviderLink" target="_blank" rel="noopener noreferrer">
|
||||||
|
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M18 13v6a2 2 0 01-2 2H5a2 2 0 01-2-2V8a2 2 0 012-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg>
|
||||||
|
{{ t('models.getApiKey') }}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
</NFormItem>
|
</NFormItem>
|
||||||
|
|
||||||
<NFormItem v-if="providerType === 'custom'" :label="t('models.name')">
|
<NFormItem v-if="providerType === 'custom'" :label="t('models.name')">
|
||||||
@@ -417,6 +430,29 @@ function handleClose() {
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
|
.fun-provider-hint {
|
||||||
|
margin-top: 6px;
|
||||||
|
font-size: 12px;
|
||||||
|
|
||||||
|
a {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
padding: 4px 8px;
|
||||||
|
white-space: nowrap;
|
||||||
|
color: var(--accent-primary);
|
||||||
|
text-decoration: none;
|
||||||
|
opacity: 0.7;
|
||||||
|
transition: opacity 0.2s;
|
||||||
|
|
||||||
|
svg {
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover { opacity: 1; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.modal-footer {
|
.modal-footer {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
|
|||||||
@@ -18,7 +18,10 @@ onMounted(() => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const isCustom = (provider: string) => provider.startsWith('custom:')
|
const isCustom = (provider: string) => {
|
||||||
|
const g = modelsStore.providers.find(p => p.provider === provider)
|
||||||
|
return !g?.builtin && provider.startsWith('custom:')
|
||||||
|
}
|
||||||
|
|
||||||
function getEditKey(provider: string): string {
|
function getEditKey(provider: string): string {
|
||||||
if (!(provider in editKeys.value)) {
|
if (!(provider in editKeys.value)) {
|
||||||
|
|||||||
@@ -110,6 +110,10 @@ function openChangelog() {
|
|||||||
</svg>
|
</svg>
|
||||||
<span>{{ t("sidebar.search") }}</span>
|
<span>{{ t("sidebar.search") }}</span>
|
||||||
</button>
|
</button>
|
||||||
|
<a class="nav-item fun-link" href="https://apikey.fun/register?aff=LIBAPI" target="_blank" rel="noopener noreferrer">
|
||||||
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 01-2 2H5a2 2 0 01-2-2V8a2 2 0 012-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg>
|
||||||
|
<span>{{ t('sidebar.apiRelay') }}</span>
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -720,4 +724,8 @@ function openChangelog() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.fun-link {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ export default {
|
|||||||
sidebar: {
|
sidebar: {
|
||||||
chat: 'Chat',
|
chat: 'Chat',
|
||||||
search: 'Suche',
|
search: 'Suche',
|
||||||
|
apiRelay: 'API-Relay',
|
||||||
history: 'Verlauf',
|
history: 'Verlauf',
|
||||||
jobs: 'Geplante Aufgaben',
|
jobs: 'Geplante Aufgaben',
|
||||||
models: 'Modelle',
|
models: 'Modelle',
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ export default {
|
|||||||
sidebar: {
|
sidebar: {
|
||||||
chat: 'Chat',
|
chat: 'Chat',
|
||||||
search: 'Search',
|
search: 'Search',
|
||||||
|
apiRelay: 'API Relay',
|
||||||
history: 'History',
|
history: 'History',
|
||||||
jobs: 'Jobs',
|
jobs: 'Jobs',
|
||||||
models: 'Models',
|
models: 'Models',
|
||||||
@@ -331,6 +332,7 @@ export default {
|
|||||||
custom: 'Custom',
|
custom: 'Custom',
|
||||||
selectProvider: 'Select Provider',
|
selectProvider: 'Select Provider',
|
||||||
chooseProvider: 'Choose a provider...',
|
chooseProvider: 'Choose a provider...',
|
||||||
|
getApiKey: 'Get API Key',
|
||||||
name: 'Name',
|
name: 'Name',
|
||||||
autoGeneratedName: 'Auto-generated from Base URL',
|
autoGeneratedName: 'Auto-generated from Base URL',
|
||||||
baseUrl: 'Base URL',
|
baseUrl: 'Base URL',
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ export default {
|
|||||||
sidebar: {
|
sidebar: {
|
||||||
chat: 'Chat',
|
chat: 'Chat',
|
||||||
search: 'Buscar',
|
search: 'Buscar',
|
||||||
|
apiRelay: 'API Relay',
|
||||||
history: 'Historial',
|
history: 'Historial',
|
||||||
jobs: 'Tareas programadas',
|
jobs: 'Tareas programadas',
|
||||||
models: 'Modelos',
|
models: 'Modelos',
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ export default {
|
|||||||
sidebar: {
|
sidebar: {
|
||||||
chat: 'Discussion',
|
chat: 'Discussion',
|
||||||
search: 'Rechercher',
|
search: 'Rechercher',
|
||||||
|
apiRelay: 'API Relay',
|
||||||
history: 'Historique',
|
history: 'Historique',
|
||||||
jobs: 'Taches planifiees',
|
jobs: 'Taches planifiees',
|
||||||
models: 'Modeles',
|
models: 'Modeles',
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ export default {
|
|||||||
sidebar: {
|
sidebar: {
|
||||||
chat: 'チャット',
|
chat: 'チャット',
|
||||||
search: '検索',
|
search: '検索',
|
||||||
|
apiRelay: 'APIリレー',
|
||||||
history: '履歴',
|
history: '履歴',
|
||||||
jobs: 'ジョブ',
|
jobs: 'ジョブ',
|
||||||
models: 'モデル',
|
models: 'モデル',
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ export default {
|
|||||||
sidebar: {
|
sidebar: {
|
||||||
chat: '채팅',
|
chat: '채팅',
|
||||||
search: '검색',
|
search: '검색',
|
||||||
|
apiRelay: 'API 릴레이',
|
||||||
history: '기록',
|
history: '기록',
|
||||||
jobs: '예약 작업',
|
jobs: '예약 작업',
|
||||||
models: '모델',
|
models: '모델',
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ export default {
|
|||||||
sidebar: {
|
sidebar: {
|
||||||
chat: 'Chat',
|
chat: 'Chat',
|
||||||
search: 'Pesquisar',
|
search: 'Pesquisar',
|
||||||
|
apiRelay: 'API Relay',
|
||||||
history: 'Historico',
|
history: 'Historico',
|
||||||
jobs: 'Tarefas agendadas',
|
jobs: 'Tarefas agendadas',
|
||||||
models: 'Modelos',
|
models: 'Modelos',
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ export default {
|
|||||||
sidebar: {
|
sidebar: {
|
||||||
chat: '对话',
|
chat: '对话',
|
||||||
search: '搜索',
|
search: '搜索',
|
||||||
|
apiRelay: '中转站',
|
||||||
history: '历史',
|
history: '历史',
|
||||||
jobs: '任务',
|
jobs: '任务',
|
||||||
models: '模型',
|
models: '模型',
|
||||||
@@ -331,6 +332,7 @@ export default {
|
|||||||
custom: '自定义',
|
custom: '自定义',
|
||||||
selectProvider: '选择 Provider',
|
selectProvider: '选择 Provider',
|
||||||
chooseProvider: '选择一个 provider...',
|
chooseProvider: '选择一个 provider...',
|
||||||
|
getApiKey: '获取 API Key',
|
||||||
name: '名称',
|
name: '名称',
|
||||||
autoGeneratedName: '根据 Base URL 自动生成',
|
autoGeneratedName: '根据 Base URL 自动生成',
|
||||||
baseUrl: 'Base URL',
|
baseUrl: 'Base URL',
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ async function handleSaved() {
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.models-content {
|
.models-content {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ export async function getAvailable(ctx: any) {
|
|||||||
currentDefault = modelSection.trim()
|
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>()
|
const seenProviders = new Set<string>()
|
||||||
|
|
||||||
let envContent = ''
|
let envContent = ''
|
||||||
@@ -57,10 +57,10 @@ export async function getAvailable(ctx: any) {
|
|||||||
const match = envContent.match(new RegExp(`^${key}\\s*=\\s*(.+)`, 'm'))
|
const match = envContent.match(new RegExp(`^${key}\\s*=\\s*(.+)`, 'm'))
|
||||||
return match?.[1]?.trim() || ''
|
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
|
if (seenProviders.has(provider)) return
|
||||||
seenProviders.add(provider)
|
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 => {
|
const isOAuthAuthorized = (providerKey: string): boolean => {
|
||||||
@@ -150,7 +150,7 @@ export async function getAvailable(ctx: any) {
|
|||||||
}
|
}
|
||||||
if (modelsList.length > 0) {
|
if (modelsList.length > 0) {
|
||||||
const apiKey = envMapping.api_key_env ? envGetValue(envMapping.api_key_env) : ''
|
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 bareKey = cp.name.trim().toLowerCase().replace(/ /g, '-')
|
||||||
const builtinPreset = PROVIDER_PRESETS.find(p => p.value === bareKey)
|
const builtinPreset = PROVIDER_PRESETS.find(p => p.value === bareKey)
|
||||||
let models = builtinPreset?.models?.length ? [...builtinPreset.models] : [cp.model]
|
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 { }
|
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 label = builtinPreset?.label || cp.name
|
||||||
const presetBaseUrl = builtinPreset?.base_url || ''
|
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) {
|
for (const result of customFetches) {
|
||||||
if (result.status === 'fulfilled' && result.value) {
|
if (result.status === 'fulfilled' && result.value) {
|
||||||
const { providerKey, label, base_url, models, api_key: cpApiKey } = result.value
|
const { providerKey, label, base_url, models, api_key: cpApiKey, builtin: cpBuiltin } = result.value as any
|
||||||
addGroup(providerKey, label, base_url, models, cpApiKey)
|
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 { getActiveAuthPath } from '../../services/hermes/hermes-profile'
|
||||||
import * as hermesCli from '../../services/hermes/hermes-cli'
|
import * as hermesCli from '../../services/hermes/hermes-cli'
|
||||||
import { readConfigYaml, writeConfigYaml, saveEnvValue, PROVIDER_ENV_MAP } from '../../services/config-helpers'
|
import { readConfigYaml, writeConfigYaml, saveEnvValue, PROVIDER_ENV_MAP } from '../../services/config-helpers'
|
||||||
|
import { PROVIDER_PRESETS } from '../../shared/providers'
|
||||||
import { logger } from '../../services/logger'
|
import { logger } from '../../services/logger'
|
||||||
|
|
||||||
const OPTIONAL_API_KEY_PROVIDERS = new Set(['cliproxyapi'])
|
const OPTIONAL_API_KEY_PROVIDERS = new Set(['cliproxyapi'])
|
||||||
@@ -39,18 +40,22 @@ export async function create(ctx: any) {
|
|||||||
existing.base_url = base_url
|
existing.base_url = base_url
|
||||||
existing.api_key = api_key
|
existing.api_key = api_key
|
||||||
existing.model = model
|
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 (context_length && context_length > 0) {
|
||||||
if (!existing.models) existing.models = {}
|
if (!existing.models) existing.models = {}
|
||||||
existing.models[model] = existing.models[model] || {}
|
existing.models[model] = existing.models[model] || {}
|
||||||
existing.models[model].context_length = context_length
|
existing.models[model].context_length = context_length
|
||||||
}
|
}
|
||||||
} else {
|
} 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.default = model
|
||||||
config.model.provider = poolKey
|
config.model.provider = poolKey
|
||||||
} else {
|
} else {
|
||||||
console.log(PROVIDER_ENV_MAP[poolKey])
|
|
||||||
if (PROVIDER_ENV_MAP[poolKey].api_key_env) {
|
if (PROVIDER_ENV_MAP[poolKey].api_key_env) {
|
||||||
await saveEnvValue(PROVIDER_ENV_MAP[poolKey].api_key_env, api_key)
|
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) }
|
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.base_url = base_url
|
||||||
existing.api_key = api_key
|
existing.api_key = api_key
|
||||||
existing.model = model
|
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 (context_length && context_length > 0) {
|
||||||
if (!existing.models) existing.models = {}
|
if (!existing.models) existing.models = {}
|
||||||
existing.models[model] = existing.models[model] || {}
|
existing.models[model] = existing.models[model] || {}
|
||||||
existing.models[model].context_length = context_length
|
existing.models[model].context_length = context_length
|
||||||
}
|
}
|
||||||
} else {
|
} 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.default = model
|
||||||
config.model.provider = `custom:${poolKey}`
|
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) ---
|
// --- 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 }> = {
|
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: '' },
|
openrouter: { api_key_env: 'OPENROUTER_API_KEY', base_url_env: '' },
|
||||||
'glm-coding-plan': { api_key_env: '', base_url_env: '' },
|
'glm-coding-plan': { api_key_env: '', base_url_env: '' },
|
||||||
zai: { api_key_env: 'GLM_API_KEY', base_url_env: '' },
|
zai: { api_key_env: 'GLM_API_KEY', base_url_env: '' },
|
||||||
|
|||||||
@@ -9,9 +9,36 @@ export interface ProviderPreset {
|
|||||||
base_url: string
|
base_url: string
|
||||||
models: string[]
|
models: string[]
|
||||||
builtin: boolean
|
builtin: boolean
|
||||||
|
api_mode?: 'openai' | 'anthropic' | 'anthropic_messages'
|
||||||
}
|
}
|
||||||
|
|
||||||
export const PROVIDER_PRESETS: ProviderPreset[] = [
|
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',
|
label: 'Anthropic',
|
||||||
value: 'anthropic',
|
value: 'anthropic',
|
||||||
|
|||||||
Reference in New Issue
Block a user