Skip to content

Commit 3a54fb7

Browse files
committed
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
2 parents 430e679 + 776a9c0 commit 3a54fb7

2 files changed

Lines changed: 75 additions & 1 deletion

File tree

internal/translator/gemini/openai/responses/gemini_openai-responses_request.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ func ConvertOpenAIResponsesRequestToGemini(modelName string, inputRawJSON []byte
119119

120120
switch itemType {
121121
case "message":
122-
if strings.EqualFold(itemRole, "system") {
122+
if strings.EqualFold(itemRole, "system") || strings.EqualFold(itemRole, "developer") {
123123
if contentArray := item.Get("content"); contentArray.Exists() {
124124
systemInstr := []byte(`{"parts":[]}`)
125125
if systemInstructionResult := gjson.GetBytes(out, "systemInstruction"); systemInstructionResult.Exists() {

internal/translator/gemini/openai/responses/gemini_openai-responses_request_test.go

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,80 @@ func TestConvertOpenAIResponsesRequestToGemini_ReasoningSignatureCompatibility(t
5555
}
5656
}
5757

58+
func TestConvertOpenAIResponsesRequestToGemini_SystemAndDeveloperRoles(t *testing.T) {
59+
tests := []struct {
60+
name string
61+
role string
62+
wantText string
63+
}{
64+
{
65+
name: "system role",
66+
role: "system",
67+
wantText: "System message text",
68+
},
69+
{
70+
name: "developer role",
71+
role: "developer",
72+
wantText: "Developer message text",
73+
},
74+
}
75+
76+
for _, tt := range tests {
77+
t.Run(tt.name, func(t *testing.T) {
78+
input := []byte(`{
79+
"instructions": "Be a helpful assistant",
80+
"input": [
81+
{
82+
"type": "message",
83+
"role": "` + tt.role + `",
84+
"content": [
85+
{
86+
"type": "input_text",
87+
"text": "` + tt.wantText + `"
88+
}
89+
]
90+
},
91+
{
92+
"type": "message",
93+
"role": "user",
94+
"content": [
95+
{
96+
"type": "input_text",
97+
"text": "Hello"
98+
}
99+
]
100+
}
101+
]
102+
}`)
103+
104+
output := ConvertOpenAIResponsesRequestToGemini("gemini-3.5-flash", input, false)
105+
result := gjson.ParseBytes(output)
106+
107+
systemInstruction := result.Get("systemInstruction")
108+
if !systemInstruction.Exists() {
109+
t.Fatalf("systemInstruction missing. Output: %s", output)
110+
}
111+
parts := systemInstruction.Get("parts")
112+
if got := parts.Get("#").Int(); got != 2 {
113+
t.Fatalf("systemInstruction parts = %d, want 2. Output: %s", got, output)
114+
}
115+
if got := parts.Get("0.text").String(); got != "Be a helpful assistant" {
116+
t.Fatalf("first systemInstruction part = %q, want %q. Output: %s", got, "Be a helpful assistant", output)
117+
}
118+
if got := parts.Get("1.text").String(); got != tt.wantText {
119+
t.Fatalf("second systemInstruction part = %q, want %q. Output: %s", got, tt.wantText, output)
120+
}
121+
122+
result.Get("contents").ForEach(func(_, value gjson.Result) bool {
123+
if role := value.Get("role").String(); role == tt.role {
124+
t.Fatalf("role %q leaked into contents array. Output: %s", tt.role, output)
125+
}
126+
return true
127+
})
128+
})
129+
}
130+
}
131+
58132
func validResponsesGPTReasoningSignature() string {
59133
raw := make([]byte, 1+8+16+16+32)
60134
raw[0] = 0x80

0 commit comments

Comments
 (0)