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
4ac4849a
authored
Nov 20, 2025
by
Seefs
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: Fill thoughtSignature only for Gemini/Vertex channels using the OpenAI format
parent
266e272e
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
80 additions
and
13 deletions
+80
-13
relay/channel/gemini/adaptor.go
+1
-1
relay/channel/gemini/relay-gemini.go
+35
-1
relay/channel/vertex/adaptor.go
+1
-1
setting/model_setting/gemini.go
+2
-0
web/bun.lock
+1
-0
web/src/i18n/locales/en.json
+2
-0
web/src/i18n/locales/fr.json
+2
-0
web/src/i18n/locales/ja.json
+2
-0
web/src/i18n/locales/ru.json
+2
-0
web/src/i18n/locales/zh.json
+2
-0
web/src/pages/Setting/Model/SettingGeminiModel.jsx
+30
-10
No files found.
relay/channel/gemini/adaptor.go
View file @
4ac4849a
...
@@ -177,7 +177,7 @@ func (a *Adaptor) ConvertOpenAIRequest(c *gin.Context, info *relaycommon.RelayIn
...
@@ -177,7 +177,7 @@ func (a *Adaptor) ConvertOpenAIRequest(c *gin.Context, info *relaycommon.RelayIn
return
nil
,
errors
.
New
(
"request is nil"
)
return
nil
,
errors
.
New
(
"request is nil"
)
}
}
geminiRequest
,
err
:=
Covert
Gemini2OpenAI
(
c
,
*
request
,
info
)
geminiRequest
,
err
:=
Covert
OpenAI2Gemini
(
c
,
*
request
,
info
)
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
err
return
nil
,
err
}
}
...
...
relay/channel/gemini/relay-gemini.go
View file @
4ac4849a
...
@@ -44,6 +44,8 @@ var geminiSupportedMimeTypes = map[string]bool{
...
@@ -44,6 +44,8 @@ var geminiSupportedMimeTypes = map[string]bool{
"video/flv"
:
true
,
"video/flv"
:
true
,
}
}
const
thoughtSignatureBypassValue
=
"context_engineering_is_the_way_to_go"
// Gemini 允许的思考预算范围
// Gemini 允许的思考预算范围
const
(
const
(
pro25MinBudget
=
128
pro25MinBudget
=
128
...
@@ -181,7 +183,7 @@ func ThinkingAdaptor(geminiRequest *dto.GeminiChatRequest, info *relaycommon.Rel
...
@@ -181,7 +183,7 @@ func ThinkingAdaptor(geminiRequest *dto.GeminiChatRequest, info *relaycommon.Rel
}
}
// Setting safety to the lowest possible values since Gemini is already powerless enough
// Setting safety to the lowest possible values since Gemini is already powerless enough
func
Covert
Gemini2OpenAI
(
c
*
gin
.
Context
,
textRequest
dto
.
GeneralOpenAIRequest
,
info
*
relaycommon
.
RelayInfo
)
(
*
dto
.
GeminiChatRequest
,
error
)
{
func
Covert
OpenAI2Gemini
(
c
*
gin
.
Context
,
textRequest
dto
.
GeneralOpenAIRequest
,
info
*
relaycommon
.
RelayInfo
)
(
*
dto
.
GeminiChatRequest
,
error
)
{
geminiRequest
:=
dto
.
GeminiChatRequest
{
geminiRequest
:=
dto
.
GeminiChatRequest
{
Contents
:
make
([]
dto
.
GeminiChatContent
,
0
,
len
(
textRequest
.
Messages
)),
Contents
:
make
([]
dto
.
GeminiChatContent
,
0
,
len
(
textRequest
.
Messages
)),
...
@@ -193,6 +195,10 @@ func CovertGemini2OpenAI(c *gin.Context, textRequest dto.GeneralOpenAIRequest, i
...
@@ -193,6 +195,10 @@ func CovertGemini2OpenAI(c *gin.Context, textRequest dto.GeneralOpenAIRequest, i
},
},
}
}
attachThoughtSignature
:=
(
info
.
ChannelType
==
constant
.
ChannelTypeGemini
||
info
.
ChannelType
==
constant
.
ChannelTypeVertexAi
)
&&
model_setting
.
GetGeminiSettings
()
.
FunctionCallThoughtSignatureEnabled
if
model_setting
.
IsGeminiModelSupportImagine
(
info
.
UpstreamModelName
)
{
if
model_setting
.
IsGeminiModelSupportImagine
(
info
.
UpstreamModelName
)
{
geminiRequest
.
GenerationConfig
.
ResponseModalities
=
[]
string
{
geminiRequest
.
GenerationConfig
.
ResponseModalities
=
[]
string
{
"TEXT"
,
"TEXT"
,
...
@@ -371,6 +377,8 @@ func CovertGemini2OpenAI(c *gin.Context, textRequest dto.GeneralOpenAIRequest, i
...
@@ -371,6 +377,8 @@ func CovertGemini2OpenAI(c *gin.Context, textRequest dto.GeneralOpenAIRequest, i
content
:=
dto
.
GeminiChatContent
{
content
:=
dto
.
GeminiChatContent
{
Role
:
message
.
Role
,
Role
:
message
.
Role
,
}
}
shouldAttachThoughtSignature
:=
attachThoughtSignature
&&
(
message
.
Role
==
"assistant"
||
message
.
Role
==
"model"
)
signatureAttached
:=
false
// isToolCall := false
// isToolCall := false
if
message
.
ToolCalls
!=
nil
{
if
message
.
ToolCalls
!=
nil
{
// message.Role = "model"
// message.Role = "model"
...
@@ -388,6 +396,10 @@ func CovertGemini2OpenAI(c *gin.Context, textRequest dto.GeneralOpenAIRequest, i
...
@@ -388,6 +396,10 @@ func CovertGemini2OpenAI(c *gin.Context, textRequest dto.GeneralOpenAIRequest, i
Arguments
:
args
,
Arguments
:
args
,
},
},
}
}
if
shouldAttachThoughtSignature
&&
!
signatureAttached
&&
hasFunctionCallContent
(
toolCall
.
FunctionCall
)
&&
len
(
toolCall
.
ThoughtSignature
)
==
0
{
toolCall
.
ThoughtSignature
=
json
.
RawMessage
(
strconv
.
Quote
(
thoughtSignatureBypassValue
))
signatureAttached
=
true
}
parts
=
append
(
parts
,
toolCall
)
parts
=
append
(
parts
,
toolCall
)
tool_call_ids
[
call
.
ID
]
=
call
.
Function
.
Name
tool_call_ids
[
call
.
ID
]
=
call
.
Function
.
Name
}
}
...
@@ -496,6 +508,28 @@ func CovertGemini2OpenAI(c *gin.Context, textRequest dto.GeneralOpenAIRequest, i
...
@@ -496,6 +508,28 @@ func CovertGemini2OpenAI(c *gin.Context, textRequest dto.GeneralOpenAIRequest, i
return
&
geminiRequest
,
nil
return
&
geminiRequest
,
nil
}
}
func
hasFunctionCallContent
(
call
*
dto
.
FunctionCall
)
bool
{
if
call
==
nil
{
return
false
}
if
strings
.
TrimSpace
(
call
.
FunctionName
)
!=
""
{
return
true
}
switch
v
:=
call
.
Arguments
.
(
type
)
{
case
nil
:
return
false
case
string
:
return
strings
.
TrimSpace
(
v
)
!=
""
case
map
[
string
]
interface
{}
:
return
len
(
v
)
>
0
case
[]
interface
{}
:
return
len
(
v
)
>
0
default
:
return
true
}
}
// Helper function to get a list of supported MIME types for error messages
// Helper function to get a list of supported MIME types for error messages
func
getSupportedMimeTypesList
()
[]
string
{
func
getSupportedMimeTypesList
()
[]
string
{
keys
:=
make
([]
string
,
0
,
len
(
geminiSupportedMimeTypes
))
keys
:=
make
([]
string
,
0
,
len
(
geminiSupportedMimeTypes
))
...
...
relay/channel/vertex/adaptor.go
View file @
4ac4849a
...
@@ -296,7 +296,7 @@ func (a *Adaptor) ConvertOpenAIRequest(c *gin.Context, info *relaycommon.RelayIn
...
@@ -296,7 +296,7 @@ func (a *Adaptor) ConvertOpenAIRequest(c *gin.Context, info *relaycommon.RelayIn
info
.
UpstreamModelName
=
claudeReq
.
Model
info
.
UpstreamModelName
=
claudeReq
.
Model
return
vertexClaudeReq
,
nil
return
vertexClaudeReq
,
nil
}
else
if
a
.
RequestMode
==
RequestModeGemini
{
}
else
if
a
.
RequestMode
==
RequestModeGemini
{
geminiRequest
,
err
:=
gemini
.
Covert
Gemini2OpenAI
(
c
,
*
request
,
info
)
geminiRequest
,
err
:=
gemini
.
Covert
OpenAI2Gemini
(
c
,
*
request
,
info
)
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
err
return
nil
,
err
}
}
...
...
setting/model_setting/gemini.go
View file @
4ac4849a
...
@@ -11,6 +11,7 @@ type GeminiSettings struct {
...
@@ -11,6 +11,7 @@ type GeminiSettings struct {
SupportedImagineModels
[]
string
`json:"supported_imagine_models"`
SupportedImagineModels
[]
string
`json:"supported_imagine_models"`
ThinkingAdapterEnabled
bool
`json:"thinking_adapter_enabled"`
ThinkingAdapterEnabled
bool
`json:"thinking_adapter_enabled"`
ThinkingAdapterBudgetTokensPercentage
float64
`json:"thinking_adapter_budget_tokens_percentage"`
ThinkingAdapterBudgetTokensPercentage
float64
`json:"thinking_adapter_budget_tokens_percentage"`
FunctionCallThoughtSignatureEnabled
bool
`json:"function_call_thought_signature_enabled"`
}
}
// 默认配置
// 默认配置
...
@@ -29,6 +30,7 @@ var defaultGeminiSettings = GeminiSettings{
...
@@ -29,6 +30,7 @@ var defaultGeminiSettings = GeminiSettings{
},
},
ThinkingAdapterEnabled
:
false
,
ThinkingAdapterEnabled
:
false
,
ThinkingAdapterBudgetTokensPercentage
:
0.6
,
ThinkingAdapterBudgetTokensPercentage
:
0.6
,
FunctionCallThoughtSignatureEnabled
:
true
,
}
}
// 全局实例
// 全局实例
...
...
web/bun.lock
View file @
4ac4849a
{
{
"lockfileVersion": 1,
"lockfileVersion": 1,
"configVersion": 0,
"workspaces": {
"workspaces": {
"": {
"": {
"name": "react-template",
"name": "react-template",
...
...
web/src/i18n/locales/en.json
View file @
4ac4849a
...
@@ -69,6 +69,8 @@
...
@@ -69,6 +69,8 @@
"Gemini思考适配设置"
:
"Gemini thinking adaptation settings"
,
"Gemini思考适配设置"
:
"Gemini thinking adaptation settings"
,
"Gemini版本设置"
:
"Gemini version settings"
,
"Gemini版本设置"
:
"Gemini version settings"
,
"Gemini设置"
:
"Gemini settings"
,
"Gemini设置"
:
"Gemini settings"
,
"启用FunctionCall思维签名填充"
:
"Enable FunctionCall thoughtSignature fill"
,
"仅为使用OpenAI格式的Gemini/Vertex渠道填充thoughtSignature"
:
"Fill thoughtSignature only for Gemini/Vertex channels using the OpenAI format"
,
"GitHub"
:
"GitHub"
,
"GitHub"
:
"GitHub"
,
"GitHub Client ID"
:
"GitHub Client ID"
,
"GitHub Client ID"
:
"GitHub Client ID"
,
"GitHub Client Secret"
:
"GitHub Client Secret"
,
"GitHub Client Secret"
:
"GitHub Client Secret"
,
...
...
web/src/i18n/locales/fr.json
View file @
4ac4849a
...
@@ -71,6 +71,8 @@
...
@@ -71,6 +71,8 @@
"Gemini思考适配设置"
:
"Paramètres d'adaptation de la pensée Gemini"
,
"Gemini思考适配设置"
:
"Paramètres d'adaptation de la pensée Gemini"
,
"Gemini版本设置"
:
"Paramètres de version Gemini"
,
"Gemini版本设置"
:
"Paramètres de version Gemini"
,
"Gemini设置"
:
"Paramètres Gemini"
,
"Gemini设置"
:
"Paramètres Gemini"
,
"启用FunctionCall思维签名填充"
:
"Activer le remplissage de thoughtSignature pour FunctionCall"
,
"仅为使用OpenAI格式的Gemini/Vertex渠道填充thoughtSignature"
:
"Remplit thoughtSignature uniquement pour les canaux Gemini/Vertex utilisant le format OpenAI"
,
"GitHub"
:
"GitHub"
,
"GitHub"
:
"GitHub"
,
"GitHub Client ID"
:
"ID client GitHub"
,
"GitHub Client ID"
:
"ID client GitHub"
,
"GitHub Client Secret"
:
"Secret client GitHub"
,
"GitHub Client Secret"
:
"Secret client GitHub"
,
...
...
web/src/i18n/locales/ja.json
View file @
4ac4849a
...
@@ -69,6 +69,8 @@
...
@@ -69,6 +69,8 @@
"Gemini思考适配设置"
:
"Gemini思考モード設定"
,
"Gemini思考适配设置"
:
"Gemini思考モード設定"
,
"Gemini版本设置"
:
"Geminiバージョン設定"
,
"Gemini版本设置"
:
"Geminiバージョン設定"
,
"Gemini设置"
:
"Gemini設定"
,
"Gemini设置"
:
"Gemini設定"
,
"启用FunctionCall思维签名填充"
:
"FunctionCall用のthoughtSignature自動付与を有効化"
,
"仅为使用OpenAI格式的Gemini/Vertex渠道填充thoughtSignature"
:
"OpenAI形式を利用するGemini/VertexチャネルにのみthoughtSignatureを付与します"
,
"GitHub"
:
"GitHub"
,
"GitHub"
:
"GitHub"
,
"GitHub Client ID"
:
"GitHub Client ID"
,
"GitHub Client ID"
:
"GitHub Client ID"
,
"GitHub Client Secret"
:
"GitHub Client Secret"
,
"GitHub Client Secret"
:
"GitHub Client Secret"
,
...
...
web/src/i18n/locales/ru.json
View file @
4ac4849a
...
@@ -73,6 +73,8 @@
...
@@ -73,6 +73,8 @@
"Gemini思考适配设置"
:
"Настройки адаптации мышления Gemini"
,
"Gemini思考适配设置"
:
"Настройки адаптации мышления Gemini"
,
"Gemini版本设置"
:
"Настройки версии Gemini"
,
"Gemini版本设置"
:
"Настройки версии Gemini"
,
"Gemini设置"
:
"Настройки Gemini"
,
"Gemini设置"
:
"Настройки Gemini"
,
"启用FunctionCall思维签名填充"
:
"Включить автозаполнение thoughtSignature для FunctionCall"
,
"仅为使用OpenAI格式的Gemini/Vertex渠道填充thoughtSignature"
:
"Заполнять thoughtSignature только для каналов Gemini/Vertex, использующих формат OpenAI"
,
"GitHub"
:
"GitHub"
,
"GitHub"
:
"GitHub"
,
"GitHub Client ID"
:
"ID клиента GitHub"
,
"GitHub Client ID"
:
"ID клиента GitHub"
,
"GitHub Client Secret"
:
"Секрет клиента GitHub"
,
"GitHub Client Secret"
:
"Секрет клиента GitHub"
,
...
...
web/src/i18n/locales/zh.json
View file @
4ac4849a
...
@@ -67,6 +67,8 @@
...
@@ -67,6 +67,8 @@
"Gemini思考适配设置"
:
"Gemini思考适配设置"
,
"Gemini思考适配设置"
:
"Gemini思考适配设置"
,
"Gemini版本设置"
:
"Gemini版本设置"
,
"Gemini版本设置"
:
"Gemini版本设置"
,
"Gemini设置"
:
"Gemini设置"
,
"Gemini设置"
:
"Gemini设置"
,
"启用FunctionCall思维签名填充"
:
"启用FunctionCall思维签名填充"
,
"仅为使用OpenAI格式的Gemini/Vertex渠道填充thoughtSignature"
:
"仅为使用OpenAI格式的Gemini/Vertex渠道填充thoughtSignature"
,
"GitHub"
:
"GitHub"
,
"GitHub"
:
"GitHub"
,
"GitHub Client ID"
:
"GitHub Client ID"
,
"GitHub Client ID"
:
"GitHub Client ID"
,
"GitHub Client Secret"
:
"GitHub Client Secret"
,
"GitHub Client Secret"
:
"GitHub Client Secret"
,
...
...
web/src/pages/Setting/Model/SettingGeminiModel.jsx
View file @
4ac4849a
...
@@ -39,19 +39,22 @@ const GEMINI_VERSION_EXAMPLE = {
...
@@ -39,19 +39,22 @@ const GEMINI_VERSION_EXAMPLE = {
default
:
'v1beta'
,
default
:
'v1beta'
,
};
};
const
DEFAULT_GEMINI_INPUTS
=
{
'gemini.safety_settings'
:
''
,
'gemini.version_settings'
:
''
,
'gemini.supported_imagine_models'
:
''
,
'gemini.thinking_adapter_enabled'
:
false
,
'gemini.thinking_adapter_budget_tokens_percentage'
:
0.6
,
'gemini.function_call_thought_signature_enabled'
:
true
,
};
export
default
function
SettingGeminiModel
(
props
)
{
export
default
function
SettingGeminiModel
(
props
)
{
const
{
t
}
=
useTranslation
();
const
{
t
}
=
useTranslation
();
const
[
loading
,
setLoading
]
=
useState
(
false
);
const
[
loading
,
setLoading
]
=
useState
(
false
);
const
[
inputs
,
setInputs
]
=
useState
({
const
[
inputs
,
setInputs
]
=
useState
(
DEFAULT_GEMINI_INPUTS
);
'gemini.safety_settings'
:
''
,
'gemini.version_settings'
:
''
,
'gemini.supported_imagine_models'
:
''
,
'gemini.thinking_adapter_enabled'
:
false
,
'gemini.thinking_adapter_budget_tokens_percentage'
:
0.6
,
});
const
refForm
=
useRef
();
const
refForm
=
useRef
();
const
[
inputsRow
,
setInputsRow
]
=
useState
(
inputs
);
const
[
inputsRow
,
setInputsRow
]
=
useState
(
DEFAULT_GEMINI_INPUTS
);
async
function
onSubmit
()
{
async
function
onSubmit
()
{
await
refForm
.
current
await
refForm
.
current
...
@@ -92,9 +95,9 @@ export default function SettingGeminiModel(props) {
...
@@ -92,9 +95,9 @@ export default function SettingGeminiModel(props) {
}
}
useEffect
(()
=>
{
useEffect
(()
=>
{
const
currentInputs
=
{};
const
currentInputs
=
{
...
DEFAULT_GEMINI_INPUTS
};
for
(
let
key
in
props
.
options
)
{
for
(
let
key
in
props
.
options
)
{
if
(
Object
.
keys
(
inputs
).
includes
(
key
))
{
if
(
Object
.
prototype
.
hasOwnProperty
.
call
(
DEFAULT_GEMINI_INPUTS
,
key
))
{
currentInputs
[
key
]
=
props
.
options
[
key
];
currentInputs
[
key
]
=
props
.
options
[
key
];
}
}
}
}
...
@@ -167,6 +170,23 @@ export default function SettingGeminiModel(props) {
...
@@ -167,6 +170,23 @@ export default function SettingGeminiModel(props) {
</
Col
>
</
Col
>
</
Row
>
</
Row
>
<
Row
>
<
Row
>
<
Col
span=
{
16
}
>
<
Form
.
Switch
label=
{
t
(
'启用FunctionCall思维签名填充'
)
}
field=
{
'gemini.function_call_thought_signature_enabled'
}
extraText=
{
t
(
'仅为使用OpenAI格式的Gemini/Vertex渠道填充thoughtSignature'
,
)
}
onChange=
{
(
value
)
=>
setInputs
({
...
inputs
,
'gemini.function_call_thought_signature_enabled'
:
value
,
})
}
/>
</
Col
>
</
Row
>
<
Row
>
<
Col
xs=
{
24
}
sm=
{
12
}
md=
{
8
}
lg=
{
8
}
xl=
{
8
}
>
<
Col
xs=
{
24
}
sm=
{
12
}
md=
{
8
}
lg=
{
8
}
xl=
{
8
}
>
<
Form
.
TextArea
<
Form
.
TextArea
field=
{
'gemini.supported_imagine_models'
}
field=
{
'gemini.supported_imagine_models'
}
...
...
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