Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
phsl
/
new-api
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
4746b2bf
authored
Feb 19, 2026
by
Seefs
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: add missing OpenAI/Claude/Gemini request fields and responses stream options
parent
d45cd9af
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
113 additions
and
51 deletions
+113
-51
dto/channel_settings.go
+9
-8
dto/claude.go
+6
-4
dto/gemini.go
+40
-35
dto/openai_request.go
+14
-3
relay/common/relay_info.go
+17
-0
web/src/components/table/channels/modals/EditChannelModal.jsx
+27
-1
No files found.
dto/channel_settings.go
View file @
4746b2bf
...
...
@@ -24,14 +24,15 @@ const (
)
type
ChannelOtherSettings
struct
{
AzureResponsesVersion
string
`json:"azure_responses_version,omitempty"`
VertexKeyType
VertexKeyType
`json:"vertex_key_type,omitempty"`
// "json" or "api_key"
OpenRouterEnterprise
*
bool
`json:"openrouter_enterprise,omitempty"`
ClaudeBetaQuery
bool
`json:"claude_beta_query,omitempty"`
// Claude 渠道是否强制追加 ?beta=true
AllowServiceTier
bool
`json:"allow_service_tier,omitempty"`
// 是否允许 service_tier 透传(默认过滤以避免额外计费)
DisableStore
bool
`json:"disable_store,omitempty"`
// 是否禁用 store 透传(默认允许透传,禁用后可能导致 Codex 无法使用)
AllowSafetyIdentifier
bool
`json:"allow_safety_identifier,omitempty"`
// 是否允许 safety_identifier 透传(默认过滤以保护用户隐私)
AwsKeyType
AwsKeyType
`json:"aws_key_type,omitempty"`
AzureResponsesVersion
string
`json:"azure_responses_version,omitempty"`
VertexKeyType
VertexKeyType
`json:"vertex_key_type,omitempty"`
// "json" or "api_key"
OpenRouterEnterprise
*
bool
`json:"openrouter_enterprise,omitempty"`
ClaudeBetaQuery
bool
`json:"claude_beta_query,omitempty"`
// Claude 渠道是否强制追加 ?beta=true
AllowServiceTier
bool
`json:"allow_service_tier,omitempty"`
// 是否允许 service_tier 透传(默认过滤以避免额外计费)
DisableStore
bool
`json:"disable_store,omitempty"`
// 是否禁用 store 透传(默认允许透传,禁用后可能导致 Codex 无法使用)
AllowSafetyIdentifier
bool
`json:"allow_safety_identifier,omitempty"`
// 是否允许 safety_identifier 透传(默认过滤以保护用户隐私)
AllowIncludeObfuscation
bool
`json:"allow_include_obfuscation,omitempty"`
// 是否允许 stream_options.include_obfuscation 透传(默认过滤以避免关闭流混淆保护)
AwsKeyType
AwsKeyType
`json:"aws_key_type,omitempty"`
}
func
(
s
*
ChannelOtherSettings
)
IsOpenRouterEnterprise
()
bool
{
...
...
dto/claude.go
View file @
4746b2bf
...
...
@@ -190,10 +190,12 @@ type ClaudeToolChoice struct {
}
type
ClaudeRequest
struct
{
Model
string
`json:"model"`
Prompt
string
`json:"prompt,omitempty"`
System
any
`json:"system,omitempty"`
Messages
[]
ClaudeMessage
`json:"messages,omitempty"`
Model
string
`json:"model"`
Prompt
string
`json:"prompt,omitempty"`
System
any
`json:"system,omitempty"`
Messages
[]
ClaudeMessage
`json:"messages,omitempty"`
// https://platform.claude.com/docs/en/build-with-claude/data-residency#inference-geo
// InferenceGeo string `json:"inference_geo,omitempty"`
MaxTokens
uint
`json:"max_tokens,omitempty"`
MaxTokensToSample
uint
`json:"max_tokens_to_sample,omitempty"`
StopSequences
[]
string
`json:"stop_sequences,omitempty"`
...
...
dto/gemini.go
View file @
4746b2bf
...
...
@@ -324,25 +324,26 @@ type GeminiChatTool struct {
}
type
GeminiChatGenerationConfig
struct
{
Temperature
*
float64
`json:"temperature,omitempty"`
TopP
float64
`json:"topP,omitempty"`
TopK
float64
`json:"topK,omitempty"`
MaxOutputTokens
uint
`json:"maxOutputTokens,omitempty"`
CandidateCount
int
`json:"candidateCount,omitempty"`
StopSequences
[]
string
`json:"stopSequences,omitempty"`
ResponseMimeType
string
`json:"responseMimeType,omitempty"`
ResponseSchema
any
`json:"responseSchema,omitempty"`
ResponseJsonSchema
json
.
RawMessage
`json:"responseJsonSchema,omitempty"`
PresencePenalty
*
float32
`json:"presencePenalty,omitempty"`
FrequencyPenalty
*
float32
`json:"frequencyPenalty,omitempty"`
ResponseLogprobs
bool
`json:"responseLogprobs,omitempty"`
Logprobs
*
int32
`json:"logprobs,omitempty"`
MediaResolution
MediaResolution
`json:"mediaResolution,omitempty"`
Seed
int64
`json:"seed,omitempty"`
ResponseModalities
[]
string
`json:"responseModalities,omitempty"`
ThinkingConfig
*
GeminiThinkingConfig
`json:"thinkingConfig,omitempty"`
SpeechConfig
json
.
RawMessage
`json:"speechConfig,omitempty"`
// RawMessage to allow flexible speech config
ImageConfig
json
.
RawMessage
`json:"imageConfig,omitempty"`
// RawMessage to allow flexible image config
Temperature
*
float64
`json:"temperature,omitempty"`
TopP
float64
`json:"topP,omitempty"`
TopK
float64
`json:"topK,omitempty"`
MaxOutputTokens
uint
`json:"maxOutputTokens,omitempty"`
CandidateCount
int
`json:"candidateCount,omitempty"`
StopSequences
[]
string
`json:"stopSequences,omitempty"`
ResponseMimeType
string
`json:"responseMimeType,omitempty"`
ResponseSchema
any
`json:"responseSchema,omitempty"`
ResponseJsonSchema
json
.
RawMessage
`json:"responseJsonSchema,omitempty"`
PresencePenalty
*
float32
`json:"presencePenalty,omitempty"`
FrequencyPenalty
*
float32
`json:"frequencyPenalty,omitempty"`
ResponseLogprobs
bool
`json:"responseLogprobs,omitempty"`
Logprobs
*
int32
`json:"logprobs,omitempty"`
EnableEnhancedCivicAnswers
*
bool
`json:"enableEnhancedCivicAnswers,omitempty"`
MediaResolution
MediaResolution
`json:"mediaResolution,omitempty"`
Seed
int64
`json:"seed,omitempty"`
ResponseModalities
[]
string
`json:"responseModalities,omitempty"`
ThinkingConfig
*
GeminiThinkingConfig
`json:"thinkingConfig,omitempty"`
SpeechConfig
json
.
RawMessage
`json:"speechConfig,omitempty"`
// RawMessage to allow flexible speech config
ImageConfig
json
.
RawMessage
`json:"imageConfig,omitempty"`
// RawMessage to allow flexible image config
}
// UnmarshalJSON allows GeminiChatGenerationConfig to accept both snake_case and camelCase fields.
...
...
@@ -350,22 +351,23 @@ func (c *GeminiChatGenerationConfig) UnmarshalJSON(data []byte) error {
type
Alias
GeminiChatGenerationConfig
var
aux
struct
{
Alias
TopPSnake
float64
`json:"top_p,omitempty"`
TopKSnake
float64
`json:"top_k,omitempty"`
MaxOutputTokensSnake
uint
`json:"max_output_tokens,omitempty"`
CandidateCountSnake
int
`json:"candidate_count,omitempty"`
StopSequencesSnake
[]
string
`json:"stop_sequences,omitempty"`
ResponseMimeTypeSnake
string
`json:"response_mime_type,omitempty"`
ResponseSchemaSnake
any
`json:"response_schema,omitempty"`
ResponseJsonSchemaSnake
json
.
RawMessage
`json:"response_json_schema,omitempty"`
PresencePenaltySnake
*
float32
`json:"presence_penalty,omitempty"`
FrequencyPenaltySnake
*
float32
`json:"frequency_penalty,omitempty"`
ResponseLogprobsSnake
bool
`json:"response_logprobs,omitempty"`
MediaResolutionSnake
MediaResolution
`json:"media_resolution,omitempty"`
ResponseModalitiesSnake
[]
string
`json:"response_modalities,omitempty"`
ThinkingConfigSnake
*
GeminiThinkingConfig
`json:"thinking_config,omitempty"`
SpeechConfigSnake
json
.
RawMessage
`json:"speech_config,omitempty"`
ImageConfigSnake
json
.
RawMessage
`json:"image_config,omitempty"`
TopPSnake
float64
`json:"top_p,omitempty"`
TopKSnake
float64
`json:"top_k,omitempty"`
MaxOutputTokensSnake
uint
`json:"max_output_tokens,omitempty"`
CandidateCountSnake
int
`json:"candidate_count,omitempty"`
StopSequencesSnake
[]
string
`json:"stop_sequences,omitempty"`
ResponseMimeTypeSnake
string
`json:"response_mime_type,omitempty"`
ResponseSchemaSnake
any
`json:"response_schema,omitempty"`
ResponseJsonSchemaSnake
json
.
RawMessage
`json:"response_json_schema,omitempty"`
PresencePenaltySnake
*
float32
`json:"presence_penalty,omitempty"`
FrequencyPenaltySnake
*
float32
`json:"frequency_penalty,omitempty"`
ResponseLogprobsSnake
bool
`json:"response_logprobs,omitempty"`
EnableEnhancedCivicAnswersSnake
*
bool
`json:"enable_enhanced_civic_answers,omitempty"`
MediaResolutionSnake
MediaResolution
`json:"media_resolution,omitempty"`
ResponseModalitiesSnake
[]
string
`json:"response_modalities,omitempty"`
ThinkingConfigSnake
*
GeminiThinkingConfig
`json:"thinking_config,omitempty"`
SpeechConfigSnake
json
.
RawMessage
`json:"speech_config,omitempty"`
ImageConfigSnake
json
.
RawMessage
`json:"image_config,omitempty"`
}
if
err
:=
common
.
Unmarshal
(
data
,
&
aux
);
err
!=
nil
{
...
...
@@ -408,6 +410,9 @@ func (c *GeminiChatGenerationConfig) UnmarshalJSON(data []byte) error {
if
aux
.
ResponseLogprobsSnake
{
c
.
ResponseLogprobs
=
aux
.
ResponseLogprobsSnake
}
if
aux
.
EnableEnhancedCivicAnswersSnake
!=
nil
{
c
.
EnableEnhancedCivicAnswers
=
aux
.
EnableEnhancedCivicAnswersSnake
}
if
aux
.
MediaResolutionSnake
!=
""
{
c
.
MediaResolution
=
aux
.
MediaResolutionSnake
}
...
...
dto/openai_request.go
View file @
4746b2bf
...
...
@@ -54,7 +54,9 @@ type GeneralOpenAIRequest struct {
ParallelTooCalls
*
bool
`json:"parallel_tool_calls,omitempty"`
Tools
[]
ToolCallRequest
`json:"tools,omitempty"`
ToolChoice
any
`json:"tool_choice,omitempty"`
FunctionCall
json
.
RawMessage
`json:"function_call,omitempty"`
User
string
`json:"user,omitempty"`
ServiceTier
string
`json:"service_tier,omitempty"`
LogProbs
bool
`json:"logprobs,omitempty"`
TopLogProbs
int
`json:"top_logprobs,omitempty"`
Dimensions
int
`json:"dimensions,omitempty"`
...
...
@@ -261,6 +263,8 @@ type FunctionRequest struct {
type
StreamOptions
struct
{
IncludeUsage
bool
`json:"include_usage,omitempty"`
// for /v1/responses
IncludeObfuscation
bool
`json:"include_obfuscation,omitempty"`
}
func
(
r
*
GeneralOpenAIRequest
)
GetMaxTokens
()
uint
{
...
...
@@ -799,11 +803,16 @@ type WebSearchOptions struct {
// https://platform.openai.com/docs/api-reference/responses/create
type
OpenAIResponsesRequest
struct
{
Model
string
`json:"model"`
Input
json
.
RawMessage
`json:"input,omitempty"`
Include
json
.
RawMessage
`json:"include,omitempty"`
Model
string
`json:"model"`
Input
json
.
RawMessage
`json:"input,omitempty"`
Include
json
.
RawMessage
`json:"include,omitempty"`
// 在后台运行推理,暂时还不支持依赖的接口
// Background json.RawMessage `json:"background,omitempty"`
Conversation
json
.
RawMessage
`json:"conversation,omitempty"`
ContextManagement
json
.
RawMessage
`json:"context_management,omitempty"`
Instructions
json
.
RawMessage
`json:"instructions,omitempty"`
MaxOutputTokens
uint
`json:"max_output_tokens,omitempty"`
TopLogProbs
*
int
`json:"top_logprobs,omitempty"`
Metadata
json
.
RawMessage
`json:"metadata,omitempty"`
ParallelToolCalls
json
.
RawMessage
`json:"parallel_tool_calls,omitempty"`
PreviousResponseID
string
`json:"previous_response_id,omitempty"`
...
...
@@ -813,7 +822,9 @@ type OpenAIResponsesRequest struct {
Store
json
.
RawMessage
`json:"store,omitempty"`
PromptCacheKey
json
.
RawMessage
`json:"prompt_cache_key,omitempty"`
PromptCacheRetention
json
.
RawMessage
`json:"prompt_cache_retention,omitempty"`
SafetyIdentifier
string
`json:"safety_identifier,omitempty"`
Stream
bool
`json:"stream,omitempty"`
StreamOptions
*
StreamOptions
`json:"stream_options,omitempty"`
Temperature
*
float64
`json:"temperature,omitempty"`
Text
json
.
RawMessage
`json:"text,omitempty"`
ToolChoice
json
.
RawMessage
`json:"tool_choice,omitempty"`
...
...
relay/common/relay_info.go
View file @
4746b2bf
...
...
@@ -702,6 +702,7 @@ func FailTaskInfo(reason string) *TaskInfo {
// service_tier: 服务层级字段,可能导致额外计费(OpenAI、Claude、Responses API 支持)
// store: 数据存储授权字段,涉及用户隐私(仅 OpenAI、Responses API 支持,默认允许透传,禁用后可能导致 Codex 无法使用)
// safety_identifier: 安全标识符,用于向 OpenAI 报告违规用户(仅 OpenAI 支持,涉及用户隐私)
// stream_options.include_obfuscation: 响应流混淆控制字段(仅 OpenAI Responses API 支持)
func
RemoveDisabledFields
(
jsonData
[]
byte
,
channelOtherSettings
dto
.
ChannelOtherSettings
)
([]
byte
,
error
)
{
var
data
map
[
string
]
interface
{}
if
err
:=
common
.
Unmarshal
(
jsonData
,
&
data
);
err
!=
nil
{
...
...
@@ -730,6 +731,22 @@ func RemoveDisabledFields(jsonData []byte, channelOtherSettings dto.ChannelOther
}
}
// 默认移除 stream_options.include_obfuscation,除非明确允许(避免关闭响应流混淆保护)
if
!
channelOtherSettings
.
AllowIncludeObfuscation
{
if
streamOptionsAny
,
exists
:=
data
[
"stream_options"
];
exists
{
if
streamOptions
,
ok
:=
streamOptionsAny
.
(
map
[
string
]
interface
{});
ok
{
if
_
,
includeExists
:=
streamOptions
[
"include_obfuscation"
];
includeExists
{
delete
(
streamOptions
,
"include_obfuscation"
)
}
if
len
(
streamOptions
)
==
0
{
delete
(
data
,
"stream_options"
)
}
else
{
data
[
"stream_options"
]
=
streamOptions
}
}
}
}
jsonDataAfter
,
err
:=
common
.
Marshal
(
data
)
if
err
!=
nil
{
common
.
SysError
(
"RemoveDisabledFields Marshal error :"
+
err
.
Error
())
...
...
web/src/components/table/channels/modals/EditChannelModal.jsx
View file @
4746b2bf
...
...
@@ -170,6 +170,7 @@ const EditChannelModal = (props) => {
allow_service_tier
:
false
,
disable_store
:
false
,
// false = 允许透传(默认开启)
allow_safety_identifier
:
false
,
allow_include_obfuscation
:
false
,
claude_beta_query
:
false
,
};
const
[
batch
,
setBatch
]
=
useState
(
false
);
...
...
@@ -634,6 +635,8 @@ const EditChannelModal = (props) => {
data
.
disable_store
=
parsedSettings
.
disable_store
||
false
;
data
.
allow_safety_identifier
=
parsedSettings
.
allow_safety_identifier
||
false
;
data
.
allow_include_obfuscation
=
parsedSettings
.
allow_include_obfuscation
||
false
;
data
.
claude_beta_query
=
parsedSettings
.
claude_beta_query
||
false
;
}
catch
(
error
)
{
console
.
error
(
'解析其他设置失败:'
,
error
);
...
...
@@ -645,6 +648,7 @@ const EditChannelModal = (props) => {
data
.
allow_service_tier
=
false
;
data
.
disable_store
=
false
;
data
.
allow_safety_identifier
=
false
;
data
.
allow_include_obfuscation
=
false
;
data
.
claude_beta_query
=
false
;
}
}
else
{
...
...
@@ -655,6 +659,7 @@ const EditChannelModal = (props) => {
data
.
allow_service_tier
=
false
;
data
.
disable_store
=
false
;
data
.
allow_safety_identifier
=
false
;
data
.
allow_include_obfuscation
=
false
;
data
.
claude_beta_query
=
false
;
}
...
...
@@ -1392,11 +1397,13 @@ const EditChannelModal = (props) => {
// type === 1 (OpenAI) 或 type === 14 (Claude): 设置字段透传控制(显式保存布尔值)
if
(
localInputs
.
type
===
1
||
localInputs
.
type
===
14
)
{
settings
.
allow_service_tier
=
localInputs
.
allow_service_tier
===
true
;
// 仅 OpenAI 渠道需要 store
和 safety_identifier
// 仅 OpenAI 渠道需要 store
/ safety_identifier / include_obfuscation
if
(
localInputs
.
type
===
1
)
{
settings
.
disable_store
=
localInputs
.
disable_store
===
true
;
settings
.
allow_safety_identifier
=
localInputs
.
allow_safety_identifier
===
true
;
settings
.
allow_include_obfuscation
=
localInputs
.
allow_include_obfuscation
===
true
;
}
if
(
localInputs
.
type
===
14
)
{
settings
.
claude_beta_query
=
localInputs
.
claude_beta_query
===
true
;
...
...
@@ -1421,6 +1428,7 @@ const EditChannelModal = (props) => {
delete
localInputs
.
allow_service_tier
;
delete
localInputs
.
disable_store
;
delete
localInputs
.
allow_safety_identifier
;
delete
localInputs
.
allow_include_obfuscation
;
delete
localInputs
.
claude_beta_query
;
let
res
;
...
...
@@ -3271,6 +3279,24 @@ const EditChannelModal = (props) => {
'safety_identifier 字段用于帮助 OpenAI 识别可能违反使用政策的应用程序用户。默认关闭以保护用户隐私'
,
)
}
/>
<
Form
.
Switch
field=
'allow_include_obfuscation'
label=
{
t
(
'允许 stream_options.include_obfuscation 透传'
,
)
}
checkedText=
{
t
(
'开'
)
}
uncheckedText=
{
t
(
'关'
)
}
onChange=
{
(
value
)
=>
handleChannelOtherSettingsChange
(
'allow_include_obfuscation'
,
value
,
)
}
extraText=
{
t
(
'include_obfuscation 用于控制 Responses 流混淆字段。默认关闭以避免客户端关闭该安全保护'
,
)
}
/>
</>
)
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment