mirror of
https://github.com/fawney19/Aether.git
synced 2026-10-09 18:59:50 +08:00
Normalize canonical API formats
This commit is contained in:
@@ -264,7 +264,7 @@ async function handleTestModel(modelName: string) {
|
||||
provider_id: props.providerId,
|
||||
model_name: modelName,
|
||||
api_key_id: props.keyId,
|
||||
api_format: 'gemini:chat',
|
||||
api_format: 'gemini:generate_content',
|
||||
})
|
||||
|
||||
if (result.success) {
|
||||
|
||||
@@ -1338,10 +1338,6 @@ function hasDefaultBodyRules(apiFormat: string): boolean {
|
||||
|
||||
function normalizeLegacyOpenAIFormatAlias(apiFormat: string): string {
|
||||
switch (apiFormat.trim().toLowerCase()) {
|
||||
case 'openai:cli':
|
||||
return 'openai:responses'
|
||||
case 'openai:compact':
|
||||
return 'openai:responses:compact'
|
||||
default:
|
||||
return apiFormat.trim().toLowerCase()
|
||||
}
|
||||
@@ -1385,10 +1381,10 @@ function getDefaultPath(apiFormat: string, baseUrl?: string): string {
|
||||
const providerType = (props.provider?.provider_type || '').toLowerCase()
|
||||
const normalizedApiFormat = normalizeLegacyOpenAIFormatAlias(apiFormat)
|
||||
if (providerType === 'vertex_ai') {
|
||||
if (normalizedApiFormat === 'gemini:chat') {
|
||||
if (normalizedApiFormat === 'gemini:generate_content') {
|
||||
return '/v1/publishers/google/models/{model}:{action}'
|
||||
}
|
||||
if (normalizedApiFormat === 'claude:chat') {
|
||||
if (normalizedApiFormat === 'claude:messages') {
|
||||
return '/v1/projects/{project_id}/locations/{region}/publishers/anthropic/models/{model}:{action}'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -350,7 +350,7 @@ import {
|
||||
type CapabilityDefinition,
|
||||
type ProviderType
|
||||
} from '@/api/endpoints'
|
||||
import { formatApiFormat } from '@/api/endpoints/types/api-format'
|
||||
import { formatApiFormat, normalizeApiFormatAlias } from '@/api/endpoints/types/api-format'
|
||||
|
||||
const props = defineProps<{
|
||||
open: boolean
|
||||
@@ -370,13 +370,13 @@ const { success, error: showError } = useToast()
|
||||
|
||||
function getVertexAllowedFormatsByAuth(authType: 'api_key' | 'service_account'): Set<string> {
|
||||
if (authType === 'api_key') {
|
||||
return new Set(['gemini:chat'])
|
||||
return new Set(['gemini:generate_content'])
|
||||
}
|
||||
return new Set(['gemini:chat', 'claude:chat'])
|
||||
return new Set(['gemini:generate_content', 'claude:messages'])
|
||||
}
|
||||
|
||||
function normalizeApiFormat(format: string): string {
|
||||
return String(format || '').trim().toLowerCase()
|
||||
return normalizeApiFormatAlias(format).trim().toLowerCase()
|
||||
}
|
||||
|
||||
function getAvailableApiFormatSet(): Set<string> {
|
||||
|
||||
@@ -529,7 +529,7 @@ function handleDialogUpdate(value: boolean) {
|
||||
|
||||
// 主 Tab 状态
|
||||
const activeMainTab = ref<'provider' | 'key'>('provider')
|
||||
const activeFormatTab = ref<string>('claude:chat')
|
||||
const activeFormatTab = ref<string>('claude:messages')
|
||||
|
||||
// 提供商排序状态
|
||||
const sortedProviders = ref<ProviderWithEndpointsSummary[]>([])
|
||||
@@ -614,17 +614,16 @@ async function loadBalances() {
|
||||
}
|
||||
|
||||
const LEGACY_API_FORMAT_MAP: Record<string, string> = {
|
||||
CLAUDE: 'claude:chat',
|
||||
CLAUDE_CLI: 'claude:cli',
|
||||
CLAUDE: 'claude:messages',
|
||||
CLAUDE_MESSAGES: 'claude:messages',
|
||||
OPENAI: 'openai:chat',
|
||||
OPENAI_CLI: 'openai:responses',
|
||||
OPENAI_COMPACT: 'openai:responses:compact',
|
||||
OPENAI_RESPONSES: 'openai:responses',
|
||||
OPENAI_RESPONSES_COMPACT: 'openai:responses:compact',
|
||||
OPENAI_VIDEO: 'openai:video',
|
||||
GEMINI: 'gemini:chat',
|
||||
GEMINI_CLI: 'gemini:cli',
|
||||
GEMINI: 'gemini:generate_content',
|
||||
GEMINI_GENERATE_CONTENT: 'gemini:generate_content',
|
||||
GEMINI_VIDEO: 'gemini:video',
|
||||
GEMINI_FILES: 'gemini:files',
|
||||
}
|
||||
|
||||
function normalizeApiFormatKey(value: string | null | undefined): string {
|
||||
@@ -635,6 +634,12 @@ function normalizeApiFormatKey(value: string | null | undefined): string {
|
||||
const [family, kind] = raw.split(':', 2)
|
||||
const familyNorm = family?.trim().toLowerCase()
|
||||
const kindNorm = kind?.trim().toLowerCase()
|
||||
if (familyNorm === 'claude' && ['chat', 'cli', 'messages'].includes(kindNorm)) {
|
||||
return 'claude:messages'
|
||||
}
|
||||
if (familyNorm === 'gemini' && ['chat', 'cli', 'generate_content'].includes(kindNorm)) {
|
||||
return 'gemini:generate_content'
|
||||
}
|
||||
if (familyNorm && kindNorm) return `${familyNorm}:${kindNorm}`
|
||||
}
|
||||
|
||||
|
||||
@@ -4,15 +4,14 @@ import type { EndpointHealthDetail } from '@/api/endpoints'
|
||||
export type EndpointStatus = 'disabled' | 'no_keys' | 'keys_disabled' | 'available'
|
||||
|
||||
const ENDPOINT_SORT_ORDER = [
|
||||
'claude:chat',
|
||||
'claude:cli',
|
||||
'claude:messages',
|
||||
'openai:chat',
|
||||
'openai:responses',
|
||||
'openai:responses:compact',
|
||||
'gemini:chat',
|
||||
'gemini:cli',
|
||||
'gemini:generate_content',
|
||||
'openai:video',
|
||||
'gemini:video',
|
||||
'gemini:files',
|
||||
]
|
||||
|
||||
/**
|
||||
|
||||
@@ -23,13 +23,11 @@ export function useProviderFilters(
|
||||
|
||||
const apiFormatFilters: FilterOption[] = [
|
||||
{ value: 'all', label: '全部格式' },
|
||||
{ value: 'claude:chat', label: 'Claude Chat' },
|
||||
{ value: 'claude:cli', label: 'Claude CLI' },
|
||||
{ value: 'claude:messages', label: 'Claude Messages' },
|
||||
{ value: 'openai:chat', label: 'OpenAI Chat' },
|
||||
{ value: 'openai:responses', label: 'OpenAI Responses' },
|
||||
{ value: 'openai:responses:compact', label: 'OpenAI Responses Compact' },
|
||||
{ value: 'gemini:chat', label: 'Gemini Chat' },
|
||||
{ value: 'gemini:cli', label: 'Gemini CLI' },
|
||||
{ value: 'gemini:generate_content', label: 'Gemini Generate Content' },
|
||||
]
|
||||
|
||||
const modelFilters = computed<FilterOption[]>(() => {
|
||||
|
||||
Reference in New Issue
Block a user