feat(advanced-custom): remove fallback option and enhance path matching for advanced custom routes
This commit is contained in:
+1
-30
@@ -33,7 +33,6 @@ import {
|
||||
SelectValue,
|
||||
} from '@/components/ui/select'
|
||||
import { Separator } from '@/components/ui/separator'
|
||||
import { Switch } from '@/components/ui/switch'
|
||||
import { Textarea } from '@/components/ui/textarea'
|
||||
import { Dialog } from '@/components/dialog'
|
||||
import {
|
||||
@@ -152,13 +151,6 @@ export function AdvancedCustomEditorDialog({
|
||||
})
|
||||
}
|
||||
|
||||
const setFallbackEnabled = (enabled: boolean) => {
|
||||
setConfig((current) => ({
|
||||
...normalizeAdvancedCustomConfig(current),
|
||||
advanced_fallback: { enabled },
|
||||
}))
|
||||
}
|
||||
|
||||
const parseJsonEditorConfig = (): AdvancedCustomConfig | null => {
|
||||
const parsed = parseAdvancedCustomConfig(jsonText)
|
||||
if (!parsed) {
|
||||
@@ -215,11 +207,6 @@ export function AdvancedCustomEditorDialog({
|
||||
...(base.advanced_routes || []),
|
||||
...(template.advanced_routes || []),
|
||||
],
|
||||
advanced_fallback: {
|
||||
enabled:
|
||||
base.advanced_fallback?.enabled === true ||
|
||||
template.advanced_fallback?.enabled === true,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -355,23 +342,7 @@ export function AdvancedCustomEditorDialog({
|
||||
|
||||
{editMode === 'visual' ? (
|
||||
<div className='flex flex-col gap-5 p-4'>
|
||||
<div className='flex flex-col gap-3 border-y py-4 sm:flex-row sm:items-center sm:justify-between'>
|
||||
<div className='flex items-center gap-3'>
|
||||
<Switch
|
||||
checked={normalizedConfig.advanced_fallback?.enabled === true}
|
||||
onCheckedChange={setFallbackEnabled}
|
||||
/>
|
||||
<div className='space-y-1'>
|
||||
<div className='text-sm font-medium'>
|
||||
{t('Fallback routing')}
|
||||
</div>
|
||||
<div className='text-muted-foreground max-w-2xl text-xs leading-relaxed'>
|
||||
{t(
|
||||
'When enabled, requests that do not match any advanced route are forwarded to the channel base URL. When disabled, unmatched requests return an error.'
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='flex justify-end border-y py-4'>
|
||||
<Button
|
||||
type='button'
|
||||
variant='outline'
|
||||
|
||||
+1
-12
@@ -1845,18 +1845,6 @@ export function ChannelMutateDrawer({
|
||||
{t('Routes')}:{' '}
|
||||
{advancedCustomStats.routeCount}
|
||||
</Badge>
|
||||
<Badge
|
||||
variant={
|
||||
advancedCustomStats.fallbackEnabled
|
||||
? 'default'
|
||||
: 'outline'
|
||||
}
|
||||
>
|
||||
{t('Fallback')}:{' '}
|
||||
{advancedCustomStats.fallbackEnabled
|
||||
? t('Enabled')
|
||||
: t('Disabled')}
|
||||
</Badge>
|
||||
{!advancedCustomStats.valid && (
|
||||
<Badge variant='destructive'>
|
||||
{t('Incomplete')}
|
||||
@@ -2254,6 +2242,7 @@ export function ChannelMutateDrawer({
|
||||
allowCreate
|
||||
createLabel='Add custom model "{{value}}"'
|
||||
maxVisibleChips={8}
|
||||
copyChipOnClick
|
||||
/>
|
||||
</FormControl>
|
||||
{modelMappingGuardrail.exposedTargetModels
|
||||
|
||||
+9
-9
@@ -28,14 +28,14 @@ export const CHANNEL_TYPES = {
|
||||
3: 'Azure',
|
||||
4: 'Ollama',
|
||||
5: 'MidjourneyPlus',
|
||||
6: 'OpenAIMax',
|
||||
// 6: 'OpenAIMax',
|
||||
7: 'OhMyGPT',
|
||||
8: 'Custom',
|
||||
9: 'AILS',
|
||||
10: 'AI Proxy',
|
||||
11: 'PaLM',
|
||||
12: 'API2GPT',
|
||||
13: 'AIGC2D',
|
||||
// 9: 'AILS',
|
||||
// 10: 'AI Proxy',
|
||||
// 11: 'PaLM',
|
||||
// 12: 'API2GPT',
|
||||
// 13: 'AIGC2D',
|
||||
14: 'Anthropic',
|
||||
15: 'Baidu',
|
||||
16: 'Zhipu',
|
||||
@@ -43,7 +43,7 @@ export const CHANNEL_TYPES = {
|
||||
18: 'Xunfei',
|
||||
19: '360',
|
||||
20: 'OpenRouter',
|
||||
21: 'AI Proxy Library',
|
||||
// 21: 'AI Proxy Library',
|
||||
22: 'FastGPT',
|
||||
23: 'Tencent',
|
||||
24: 'Gemini',
|
||||
@@ -80,8 +80,8 @@ export const CHANNEL_TYPES = {
|
||||
} as const
|
||||
|
||||
const CHANNEL_TYPE_DISPLAY_ORDER: number[] = [
|
||||
1, 14, 33, 24, 43, 3, 41, 48, 42, 34, 20, 4, 40, 27, 25, 17, 26, 15, 46, 23,
|
||||
18, 45, 31, 35, 49, 19, 47, 37, 38, 39, 11, 8, 58, 57, 22, 21, 44, 2, 5, 36,
|
||||
1, 14, 33, 24, 43, 3, 41, 48, 58, 42, 34, 20, 4, 40, 27, 25, 17, 26, 15, 46, 23,
|
||||
18, 45, 31, 35, 49, 19, 47, 37, 38, 39, 11, 8, 57, 22, 21, 44, 2, 5, 36,
|
||||
50, 51, 52, 53, 54, 55, 56,
|
||||
]
|
||||
|
||||
|
||||
+13
-32
@@ -176,12 +176,11 @@ export const ADVANCED_CUSTOM_TEMPLATE_OPTIONS: AdvancedCustomTemplateOption[] =
|
||||
advanced_routes: [
|
||||
{
|
||||
incoming_path: '/v1/chat/completions',
|
||||
upstream_path: 'https://api.openai.com/v1/chat/completions',
|
||||
upstream_path: '/v1/chat/completions',
|
||||
converter: 'none',
|
||||
auth: bearerHeaderAuth(),
|
||||
},
|
||||
],
|
||||
advanced_fallback: { enabled: false },
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -191,12 +190,11 @@ export const ADVANCED_CUSTOM_TEMPLATE_OPTIONS: AdvancedCustomTemplateOption[] =
|
||||
advanced_routes: [
|
||||
{
|
||||
incoming_path: '/v1/responses',
|
||||
upstream_path: 'https://api.openai.com/v1/responses',
|
||||
upstream_path: '/v1/responses',
|
||||
converter: 'none',
|
||||
auth: bearerHeaderAuth(),
|
||||
},
|
||||
],
|
||||
advanced_fallback: { enabled: false },
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -206,12 +204,11 @@ export const ADVANCED_CUSTOM_TEMPLATE_OPTIONS: AdvancedCustomTemplateOption[] =
|
||||
advanced_routes: [
|
||||
{
|
||||
incoming_path: '/v1/embeddings',
|
||||
upstream_path: 'https://api.openai.com/v1/embeddings',
|
||||
upstream_path: '/v1/embeddings',
|
||||
converter: 'none',
|
||||
auth: bearerHeaderAuth(),
|
||||
},
|
||||
],
|
||||
advanced_fallback: { enabled: false },
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -221,18 +218,17 @@ export const ADVANCED_CUSTOM_TEMPLATE_OPTIONS: AdvancedCustomTemplateOption[] =
|
||||
advanced_routes: [
|
||||
{
|
||||
incoming_path: '/v1/images/generations',
|
||||
upstream_path: 'https://api.openai.com/v1/images/generations',
|
||||
upstream_path: '/v1/images/generations',
|
||||
converter: 'none',
|
||||
auth: bearerHeaderAuth(),
|
||||
},
|
||||
{
|
||||
incoming_path: '/v1/images/edits',
|
||||
upstream_path: 'https://api.openai.com/v1/images/edits',
|
||||
upstream_path: '/v1/images/edits',
|
||||
converter: 'none',
|
||||
auth: bearerHeaderAuth(),
|
||||
},
|
||||
],
|
||||
advanced_fallback: { enabled: false },
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -242,12 +238,11 @@ export const ADVANCED_CUSTOM_TEMPLATE_OPTIONS: AdvancedCustomTemplateOption[] =
|
||||
advanced_routes: [
|
||||
{
|
||||
incoming_path: '/v1/messages',
|
||||
upstream_path: 'https://api.anthropic.com/v1/messages',
|
||||
upstream_path: '/v1/messages',
|
||||
converter: 'none',
|
||||
auth: apiKeyHeaderAuth(),
|
||||
},
|
||||
],
|
||||
advanced_fallback: { enabled: false },
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -257,27 +252,23 @@ export const ADVANCED_CUSTOM_TEMPLATE_OPTIONS: AdvancedCustomTemplateOption[] =
|
||||
advanced_routes: [
|
||||
{
|
||||
incoming_path: '/v1beta/models/{model}:generateContent',
|
||||
upstream_path:
|
||||
'https://generativelanguage.googleapis.com/v1beta/models/{model}:generateContent',
|
||||
upstream_path: '/v1beta/models/{model}:generateContent',
|
||||
converter: 'none',
|
||||
auth: geminiQueryAuth(),
|
||||
},
|
||||
{
|
||||
incoming_path: '/v1beta/models/{model}:embedContent',
|
||||
upstream_path:
|
||||
'https://generativelanguage.googleapis.com/v1beta/models/{model}:embedContent',
|
||||
upstream_path: '/v1beta/models/{model}:embedContent',
|
||||
converter: 'none',
|
||||
auth: geminiQueryAuth(),
|
||||
},
|
||||
{
|
||||
incoming_path: '/v1beta/models/{model}:batchEmbedContents',
|
||||
upstream_path:
|
||||
'https://generativelanguage.googleapis.com/v1beta/models/{model}:batchEmbedContents',
|
||||
upstream_path: '/v1beta/models/{model}:batchEmbedContents',
|
||||
converter: 'none',
|
||||
auth: geminiQueryAuth(),
|
||||
},
|
||||
],
|
||||
advanced_fallback: { enabled: false },
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -287,13 +278,11 @@ export const ADVANCED_CUSTOM_TEMPLATE_OPTIONS: AdvancedCustomTemplateOption[] =
|
||||
advanced_routes: [
|
||||
{
|
||||
incoming_path: '/v1/chat/completions',
|
||||
upstream_path:
|
||||
'https://generativelanguage.googleapis.com/v1beta/models/{model}:generateContent',
|
||||
upstream_path: '/v1beta/models/{model}:generateContent',
|
||||
converter: 'openai_chat_completions_to_gemini_generate_content',
|
||||
auth: geminiQueryAuth(),
|
||||
},
|
||||
],
|
||||
advanced_fallback: { enabled: false },
|
||||
},
|
||||
},
|
||||
]
|
||||
@@ -325,7 +314,6 @@ export function createAdvancedCustomRoute(): AdvancedCustomRoute {
|
||||
export function createAdvancedCustomConfig(): AdvancedCustomConfig {
|
||||
return {
|
||||
advanced_routes: [createAdvancedCustomRoute()],
|
||||
advanced_fallback: { enabled: false },
|
||||
}
|
||||
}
|
||||
|
||||
@@ -405,9 +393,6 @@ export function normalizeAdvancedCustomConfig(
|
||||
|
||||
return {
|
||||
advanced_routes: routes,
|
||||
advanced_fallback: {
|
||||
enabled: config.advanced_fallback?.enabled === true,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -420,11 +405,9 @@ export function validateAdvancedCustomConfig(
|
||||
|
||||
const normalized = normalizeAdvancedCustomConfig(config)
|
||||
const routes = normalized.advanced_routes || []
|
||||
const fallbackEnabled = normalized.advanced_fallback?.enabled === true
|
||||
if (routes.length === 0 && !fallbackEnabled) {
|
||||
if (routes.length === 0) {
|
||||
return {
|
||||
message:
|
||||
'Advanced custom configuration requires at least one route or fallback',
|
||||
message: 'Advanced custom configuration requires at least one route',
|
||||
}
|
||||
}
|
||||
|
||||
@@ -492,17 +475,15 @@ export function advancedCustomConfigUsesRelativeUpstreamPath(
|
||||
|
||||
export function getAdvancedCustomStats(value: string | undefined): {
|
||||
routeCount: number
|
||||
fallbackEnabled: boolean
|
||||
valid: boolean
|
||||
} {
|
||||
const config = parseAdvancedCustomConfig(value)
|
||||
if (!config) {
|
||||
return { routeCount: 0, fallbackEnabled: false, valid: false }
|
||||
return { routeCount: 0, valid: false }
|
||||
}
|
||||
const normalized = normalizeAdvancedCustomConfig(config)
|
||||
return {
|
||||
routeCount: normalized.advanced_routes?.length || 0,
|
||||
fallbackEnabled: normalized.advanced_fallback?.enabled === true,
|
||||
valid: validateAdvancedCustomConfig(normalized) === null,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -226,16 +226,6 @@ export const channelFormSchema = z
|
||||
if (advancedCustomError) {
|
||||
addRequiredIssue(ctx, 'advanced_custom', advancedCustomError.message)
|
||||
}
|
||||
if (
|
||||
advancedCustomConfig?.advanced_fallback?.enabled === true &&
|
||||
!data.base_url?.trim()
|
||||
) {
|
||||
addRequiredIssue(
|
||||
ctx,
|
||||
'base_url',
|
||||
'Base URL is required when fallback is enabled'
|
||||
)
|
||||
}
|
||||
if (
|
||||
advancedCustomConfigUsesRelativeUpstreamPath(advancedCustomConfig) &&
|
||||
!data.base_url?.trim()
|
||||
|
||||
-5
@@ -110,7 +110,6 @@ export interface ChannelOtherSettings {
|
||||
|
||||
export interface AdvancedCustomConfig {
|
||||
advanced_routes?: AdvancedCustomRoute[]
|
||||
advanced_fallback?: AdvancedCustomFallback
|
||||
}
|
||||
|
||||
export interface AdvancedCustomRoute {
|
||||
@@ -120,10 +119,6 @@ export interface AdvancedCustomRoute {
|
||||
auth?: AdvancedCustomRouteAuth
|
||||
}
|
||||
|
||||
export interface AdvancedCustomFallback {
|
||||
enabled?: boolean
|
||||
}
|
||||
|
||||
export interface AdvancedCustomRouteAuth {
|
||||
type?: AdvancedCustomAuthType
|
||||
name?: string
|
||||
|
||||
Reference in New Issue
Block a user