feat: add field passthrough controls for gateway channels (#6847)

This commit is contained in:
Seefs
2026-08-15 13:54:25 +08:00
committed by GitHub
parent 7d09c6954e
commit e90a7c48e5
3 changed files with 129 additions and 88 deletions
@@ -138,13 +138,16 @@ import {
} from '../../api'
import {
ADD_MODE_OPTIONS,
CLAUDE_FIELD_PASSTHROUGH_TYPES,
CHANNEL_STATUS_LABELS,
CHANNEL_TYPE_OPTIONS,
CHANNEL_TYPE_WARNINGS,
ERROR_MESSAGES,
FIELD_PASSTHROUGH_TYPES,
FIELD_DESCRIPTIONS,
FIELD_PLACEHOLDERS,
MODEL_FETCHABLE_TYPES,
OPENAI_FIELD_PASSTHROUGH_TYPES,
} from '../../constants'
import { useChannelMutateForm } from '../../hooks/use-channel-mutate-form'
import {
@@ -1026,7 +1029,7 @@ export function ChannelMutateDrawer({
(currentHttp2ConnectionShards != null && currentHttp2ConnectionShards > 1)
)
let fieldPassthroughConfigured = false
if (currentType === 1 || currentType === 57) {
if (OPENAI_FIELD_PASSTHROUGH_TYPES.has(currentType)) {
fieldPassthroughConfigured = Boolean(
currentAllowServiceTier ||
currentDisableStore ||
@@ -1034,13 +1037,16 @@ export function ChannelMutateDrawer({
currentAllowIncludeObfuscation ||
currentAllowInferenceGeo
)
} else if (currentType === 14) {
fieldPassthroughConfigured = Boolean(
currentAllowServiceTier ||
currentAllowInferenceGeo ||
currentAllowSpeed ||
currentClaudeBetaQuery
)
}
if (CLAUDE_FIELD_PASSTHROUGH_TYPES.has(currentType)) {
fieldPassthroughConfigured =
fieldPassthroughConfigured ||
Boolean(
currentAllowServiceTier ||
currentAllowInferenceGeo ||
currentAllowSpeed ||
(currentType === 14 && currentClaudeBetaQuery)
)
}
const upstreamModelDetectionConfigured = Boolean(
upstreamModelUpdateCheckEnabled ||
@@ -1077,7 +1083,7 @@ export function ChannelMutateDrawer({
configured: extraSettingsConfigured,
},
]
if (currentType === 1 || currentType === 14 || currentType === 57) {
if (FIELD_PASSTHROUGH_TYPES.has(currentType)) {
advancedNavChildren.push({
id: ADVANCED_SETTINGS_SECTION_IDS.fieldPassthrough,
title: t('Field passthrough controls'),
@@ -4233,9 +4239,7 @@ export function ChannelMutateDrawer({
<SelectValue />
</SelectTrigger>
</FormControl>
<SelectContent
alignItemWithTrigger={false}
>
<SelectContent alignItemWithTrigger={false}>
<SelectGroup>
<SelectItem value='auto'>
{t('Auto')}
@@ -4369,9 +4373,7 @@ export function ChannelMutateDrawer({
</fieldset>
</div>
{(currentType === 1 ||
currentType === 14 ||
currentType === 57) && (
{FIELD_PASSTHROUGH_TYPES.has(currentType) && (
<div
id={ADVANCED_SETTINGS_SECTION_IDS.fieldPassthrough}
className={sideDrawerSectionClassName(
@@ -4416,7 +4418,9 @@ export function ChannelMutateDrawer({
)}
/>
{(currentType === 1 || currentType === 57) && (
{OPENAI_FIELD_PASSTHROUGH_TYPES.has(
currentType
) && (
<>
<FormField
control={form.control}
@@ -4526,34 +4530,38 @@ export function ChannelMutateDrawer({
</>
)}
{currentType === 14 && (
{CLAUDE_FIELD_PASSTHROUGH_TYPES.has(
currentType
) && (
<>
<FormField
control={form.control}
name='allow_inference_geo'
render={({ field }) => (
<FormItem className='flex items-center justify-between gap-3 px-4 py-3'>
<div className='space-y-0.5'>
<FormLabel className='text-sm'>
{t(
'Allow inference_geo passthrough'
)}
</FormLabel>
<FormDescription>
{t(
'Pass through the inference_geo field for Claude data residency region control'
)}
</FormDescription>
</div>
<FormControl>
<Switch
checked={field.value}
onCheckedChange={field.onChange}
/>
</FormControl>
</FormItem>
)}
/>
{currentType === 14 && (
<FormField
control={form.control}
name='allow_inference_geo'
render={({ field }) => (
<FormItem className='flex items-center justify-between gap-3 px-4 py-3'>
<div className='space-y-0.5'>
<FormLabel className='text-sm'>
{t(
'Allow inference_geo passthrough'
)}
</FormLabel>
<FormDescription>
{t(
'Pass through the inference_geo field for Claude data residency region control'
)}
</FormDescription>
</div>
<FormControl>
<Switch
checked={field.value}
onCheckedChange={field.onChange}
/>
</FormControl>
</FormItem>
)}
/>
)}
<FormField
control={form.control}
@@ -4580,32 +4588,34 @@ export function ChannelMutateDrawer({
)}
/>
<FormField
control={form.control}
name='claude_beta_query'
render={({ field }) => (
<FormItem className='flex items-center justify-between gap-3 px-4 py-3'>
<div className='space-y-0.5'>
<FormLabel className='text-sm'>
{t(
'Allow Claude beta query passthrough'
)}
</FormLabel>
<FormDescription>
{t(
'Pass through the anthropic-beta header for beta features'
)}
</FormDescription>
</div>
<FormControl>
<Switch
checked={field.value}
onCheckedChange={field.onChange}
/>
</FormControl>
</FormItem>
)}
/>
{currentType === 14 && (
<FormField
control={form.control}
name='claude_beta_query'
render={({ field }) => (
<FormItem className='flex items-center justify-between gap-3 px-4 py-3'>
<div className='space-y-0.5'>
<FormLabel className='text-sm'>
{t(
'Allow Claude beta query passthrough'
)}
</FormLabel>
<FormDescription>
{t(
'Pass through the anthropic-beta header for beta features'
)}
</FormDescription>
</div>
<FormControl>
<Switch
checked={field.value}
onCheckedChange={field.onChange}
/>
</FormControl>
</FormItem>
)}
/>
)}
</>
)}
</div>
+24
View File
@@ -392,6 +392,30 @@ export const MODEL_FETCHABLE_TYPES = new Set([
59, 60,
])
export const FIELD_PASSTHROUGH_TYPES = new Set([
1,
14,
57,
58,
59,
CHANNEL_TYPE_NEW_API,
])
export const OPENAI_FIELD_PASSTHROUGH_TYPES = new Set([
1,
57,
58,
59,
CHANNEL_TYPE_NEW_API,
])
export const CLAUDE_FIELD_PASSTHROUGH_TYPES = new Set([
14,
58,
59,
CHANNEL_TYPE_NEW_API,
])
export const TYPE_TO_KEY_PROMPT: Record<number, string> = {
15: 'Format: APIKey|SecretKey',
18: 'Format: APPID|APISecret|APIKey',
+26 -19
View File
@@ -19,10 +19,13 @@ For commercial licensing, please contact support@quantumnous.com
import { z } from 'zod'
import {
CLAUDE_FIELD_PASSTHROUGH_TYPES,
CHANNEL_TYPE_NEW_API,
CHANNEL_STATUS,
ERROR_MESSAGES,
FIELD_PASSTHROUGH_TYPES,
MODEL_FETCHABLE_TYPES,
OPENAI_FIELD_PASSTHROUGH_TYPES,
} from '../constants'
import type { Channel } from '../types'
import {
@@ -487,8 +490,7 @@ export function transformChannelToFormDefaults(
thinking_to_content: parsed.thinking_to_content || false,
proxy: parsed.proxy || '',
http_protocol: protocol,
http2_connection_shards:
protocol === HTTP_PROTOCOL_HTTP1 ? 1 : shards,
http2_connection_shards: protocol === HTTP_PROTOCOL_HTTP1 ? 1 : shards,
pass_through_body_enabled: parsed.pass_through_body_enabled || false,
system_prompt: parsed.system_prompt || '',
system_prompt_override: parsed.system_prompt_override || false,
@@ -672,21 +674,21 @@ function buildSettingsJSON(formData: ChannelFormValues): string {
}
// Field passthrough controls:
// - OpenAI (type 1) and Anthropic (type 14): allow_service_tier
// - OpenAI only: disable_store, allow_safety_identifier
if (formData.type === 1 || formData.type === 14 || formData.type === 57) {
// - OpenAI, Anthropic, Codex, and New API: allow_service_tier
// - OpenAI request fields: OpenAI, Codex, and New API
// - Claude request fields: Anthropic and New API
if (FIELD_PASSTHROUGH_TYPES.has(formData.type)) {
settingsObj.allow_service_tier = formData.allow_service_tier === true
} else if ('allow_service_tier' in settingsObj) {
delete settingsObj.allow_service_tier
}
if (formData.type === 1 || formData.type === 57) {
if (OPENAI_FIELD_PASSTHROUGH_TYPES.has(formData.type)) {
settingsObj.disable_store = formData.disable_store === true
settingsObj.allow_safety_identifier =
formData.allow_safety_identifier === true
settingsObj.allow_include_obfuscation =
formData.allow_include_obfuscation === true
settingsObj.allow_inference_geo = formData.allow_inference_geo === true
} else {
if ('disable_store' in settingsObj) {
delete settingsObj.disable_store
@@ -697,23 +699,28 @@ function buildSettingsJSON(formData: ChannelFormValues): string {
if ('allow_include_obfuscation' in settingsObj) {
delete settingsObj.allow_include_obfuscation
}
if (formData.type !== 14 && 'allow_inference_geo' in settingsObj) {
delete settingsObj.allow_inference_geo
}
}
// Anthropic (type 14): claude_beta_query, allow_inference_geo, allow_speed
if (formData.type === 14) {
if (
OPENAI_FIELD_PASSTHROUGH_TYPES.has(formData.type) ||
CLAUDE_FIELD_PASSTHROUGH_TYPES.has(formData.type)
) {
settingsObj.allow_inference_geo = formData.allow_inference_geo === true
} else if ('allow_inference_geo' in settingsObj) {
delete settingsObj.allow_inference_geo
}
if (CLAUDE_FIELD_PASSTHROUGH_TYPES.has(formData.type)) {
settingsObj.allow_speed = formData.allow_speed === true
} else if ('allow_speed' in settingsObj) {
delete settingsObj.allow_speed
}
// Only the Anthropic adaptor supports forcing the Claude beta query.
if (formData.type === 14) {
settingsObj.claude_beta_query = formData.claude_beta_query === true
} else {
if ('allow_speed' in settingsObj) {
delete settingsObj.allow_speed
}
if ('claude_beta_query' in settingsObj) {
delete settingsObj.claude_beta_query
}
} else if ('claude_beta_query' in settingsObj) {
delete settingsObj.claude_beta_query
}
settingsObj.disable_task_polling_sleep =