mirror of
https://github.com/router-for-me/CLIProxyAPIPlus.git
synced 2026-04-26 22:45:48 +00:00
Fixed: #2022
test(translator): add tests for handling Claude system messages as string and array
This commit is contained in:
@@ -43,23 +43,32 @@ func ConvertClaudeRequestToCodex(modelName string, inputRawJSON []byte, _ bool)
|
|||||||
|
|
||||||
// Process system messages and convert them to input content format.
|
// Process system messages and convert them to input content format.
|
||||||
systemsResult := rootResult.Get("system")
|
systemsResult := rootResult.Get("system")
|
||||||
if systemsResult.IsArray() {
|
if systemsResult.Exists() {
|
||||||
systemResults := systemsResult.Array()
|
|
||||||
message := `{"type":"message","role":"developer","content":[]}`
|
message := `{"type":"message","role":"developer","content":[]}`
|
||||||
contentIndex := 0
|
contentIndex := 0
|
||||||
for i := 0; i < len(systemResults); i++ {
|
|
||||||
systemResult := systemResults[i]
|
appendSystemText := func(text string) {
|
||||||
systemTypeResult := systemResult.Get("type")
|
if text == "" || strings.HasPrefix(text, "x-anthropic-billing-header: ") {
|
||||||
if systemTypeResult.String() == "text" {
|
return
|
||||||
text := systemResult.Get("text").String()
|
}
|
||||||
if strings.HasPrefix(text, "x-anthropic-billing-header: ") {
|
|
||||||
continue
|
message, _ = sjson.Set(message, fmt.Sprintf("content.%d.type", contentIndex), "input_text")
|
||||||
|
message, _ = sjson.Set(message, fmt.Sprintf("content.%d.text", contentIndex), text)
|
||||||
|
contentIndex++
|
||||||
|
}
|
||||||
|
|
||||||
|
if systemsResult.Type == gjson.String {
|
||||||
|
appendSystemText(systemsResult.String())
|
||||||
|
} else if systemsResult.IsArray() {
|
||||||
|
systemResults := systemsResult.Array()
|
||||||
|
for i := 0; i < len(systemResults); i++ {
|
||||||
|
systemResult := systemResults[i]
|
||||||
|
if systemResult.Get("type").String() == "text" {
|
||||||
|
appendSystemText(systemResult.Get("text").String())
|
||||||
}
|
}
|
||||||
message, _ = sjson.Set(message, fmt.Sprintf("content.%d.type", contentIndex), "input_text")
|
|
||||||
message, _ = sjson.Set(message, fmt.Sprintf("content.%d.text", contentIndex), text)
|
|
||||||
contentIndex++
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if contentIndex > 0 {
|
if contentIndex > 0 {
|
||||||
template, _ = sjson.SetRaw(template, "input.-1", message)
|
template, _ = sjson.SetRaw(template, "input.-1", message)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,89 @@
|
|||||||
|
package claude
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/tidwall/gjson"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestConvertClaudeRequestToCodex_SystemMessageScenarios(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
inputJSON string
|
||||||
|
wantHasDeveloper bool
|
||||||
|
wantTexts []string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "No system field",
|
||||||
|
inputJSON: `{
|
||||||
|
"model": "claude-3-opus",
|
||||||
|
"messages": [{"role": "user", "content": "hello"}]
|
||||||
|
}`,
|
||||||
|
wantHasDeveloper: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Empty string system field",
|
||||||
|
inputJSON: `{
|
||||||
|
"model": "claude-3-opus",
|
||||||
|
"system": "",
|
||||||
|
"messages": [{"role": "user", "content": "hello"}]
|
||||||
|
}`,
|
||||||
|
wantHasDeveloper: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "String system field",
|
||||||
|
inputJSON: `{
|
||||||
|
"model": "claude-3-opus",
|
||||||
|
"system": "Be helpful",
|
||||||
|
"messages": [{"role": "user", "content": "hello"}]
|
||||||
|
}`,
|
||||||
|
wantHasDeveloper: true,
|
||||||
|
wantTexts: []string{"Be helpful"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Array system field with filtered billing header",
|
||||||
|
inputJSON: `{
|
||||||
|
"model": "claude-3-opus",
|
||||||
|
"system": [
|
||||||
|
{"type": "text", "text": "x-anthropic-billing-header: tenant-123"},
|
||||||
|
{"type": "text", "text": "Block 1"},
|
||||||
|
{"type": "text", "text": "Block 2"}
|
||||||
|
],
|
||||||
|
"messages": [{"role": "user", "content": "hello"}]
|
||||||
|
}`,
|
||||||
|
wantHasDeveloper: true,
|
||||||
|
wantTexts: []string{"Block 1", "Block 2"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
result := ConvertClaudeRequestToCodex("test-model", []byte(tt.inputJSON), false)
|
||||||
|
resultJSON := gjson.ParseBytes(result)
|
||||||
|
inputs := resultJSON.Get("input").Array()
|
||||||
|
|
||||||
|
hasDeveloper := len(inputs) > 0 && inputs[0].Get("role").String() == "developer"
|
||||||
|
if hasDeveloper != tt.wantHasDeveloper {
|
||||||
|
t.Fatalf("got hasDeveloper = %v, want %v. Output: %s", hasDeveloper, tt.wantHasDeveloper, resultJSON.Get("input").Raw)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !tt.wantHasDeveloper {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
content := inputs[0].Get("content").Array()
|
||||||
|
if len(content) != len(tt.wantTexts) {
|
||||||
|
t.Fatalf("got %d system content items, want %d. Content: %s", len(content), len(tt.wantTexts), inputs[0].Get("content").Raw)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, wantText := range tt.wantTexts {
|
||||||
|
if gotType := content[i].Get("type").String(); gotType != "input_text" {
|
||||||
|
t.Fatalf("content[%d] type = %q, want %q", i, gotType, "input_text")
|
||||||
|
}
|
||||||
|
if gotText := content[i].Get("text").String(); gotText != wantText {
|
||||||
|
t.Fatalf("content[%d] text = %q, want %q", i, gotText, wantText)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user