Merge branch 'dev', commit 'refs/pull/3621/head' of github.com:router-for-me/CLIProxyAPI into dev

# Conflicts:
#	internal/translator/gemini/openai/responses/gemini_openai-responses_request_test.go
This commit is contained in:
Luis Pater
2026-05-30 20:57:14 +08:00
2 changed files with 75 additions and 1 deletions
@@ -119,7 +119,7 @@ func ConvertOpenAIResponsesRequestToGemini(modelName string, inputRawJSON []byte
switch itemType {
case "message":
if strings.EqualFold(itemRole, "system") {
if strings.EqualFold(itemRole, "system") || strings.EqualFold(itemRole, "developer") {
if contentArray := item.Get("content"); contentArray.Exists() {
systemInstr := []byte(`{"parts":[]}`)
if systemInstructionResult := gjson.GetBytes(out, "systemInstruction"); systemInstructionResult.Exists() {
@@ -55,6 +55,80 @@ func TestConvertOpenAIResponsesRequestToGemini_ReasoningSignatureCompatibility(t
}
}
func TestConvertOpenAIResponsesRequestToGemini_SystemAndDeveloperRoles(t *testing.T) {
tests := []struct {
name string
role string
wantText string
}{
{
name: "system role",
role: "system",
wantText: "System message text",
},
{
name: "developer role",
role: "developer",
wantText: "Developer message text",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
input := []byte(`{
"instructions": "Be a helpful assistant",
"input": [
{
"type": "message",
"role": "` + tt.role + `",
"content": [
{
"type": "input_text",
"text": "` + tt.wantText + `"
}
]
},
{
"type": "message",
"role": "user",
"content": [
{
"type": "input_text",
"text": "Hello"
}
]
}
]
}`)
output := ConvertOpenAIResponsesRequestToGemini("gemini-3.5-flash", input, false)
result := gjson.ParseBytes(output)
systemInstruction := result.Get("systemInstruction")
if !systemInstruction.Exists() {
t.Fatalf("systemInstruction missing. Output: %s", output)
}
parts := systemInstruction.Get("parts")
if got := parts.Get("#").Int(); got != 2 {
t.Fatalf("systemInstruction parts = %d, want 2. Output: %s", got, output)
}
if got := parts.Get("0.text").String(); got != "Be a helpful assistant" {
t.Fatalf("first systemInstruction part = %q, want %q. Output: %s", got, "Be a helpful assistant", output)
}
if got := parts.Get("1.text").String(); got != tt.wantText {
t.Fatalf("second systemInstruction part = %q, want %q. Output: %s", got, tt.wantText, output)
}
result.Get("contents").ForEach(func(_, value gjson.Result) bool {
if role := value.Get("role").String(); role == tt.role {
t.Fatalf("role %q leaked into contents array. Output: %s", tt.role, output)
}
return true
})
})
}
}
func validResponsesGPTReasoningSignature() string {
raw := make([]byte, 1+8+16+16+32)
raw[0] = 0x80