| @@ -135,3 +135,71 @@ func TestConvertOpenAIRequestToClaude_ToolResultURLImageOnly(t *testing.T) { · 134 unmodified lines |
| 135 | 135 | t.Fatalf("Unexpected image URL: %q", got) |
| 136 | 136 | } |
| 137 | 137 | } |
| 138 | + |
| 139 | +func TestConvertOpenAIRequestToClaude_SystemRoleBecomesTopLevelSystem(t *testing.T) { |
| 140 | + inputJSON := `{ |
| 141 | + "model": "gpt-4.1", |
| 142 | + "messages": [ |
| 143 | + {"role": "system", "content": "You are a helpful assistant."}, |
| 144 | + {"role": "user", "content": "Hello"} |
| 145 | + ] |
| 146 | + }` |
| 147 | + |
| 148 | + result := ConvertOpenAIRequestToClaude("claude-sonnet-4-5", []byte(inputJSON), false) |
| 149 | + resultJSON := gjson.ParseBytes(result) |
| 150 | + |
| 151 | + system := resultJSON.Get("system") |
| 152 | + if !system.IsArray() { |
| 153 | + t.Fatalf("Expected top-level system array, got %s", system.Raw) |
| 154 | + } |
| 155 | + if len(system.Array()) != 1 { |
| 156 | + t.Fatalf("Expected 1 system block, got %d. System: %s", len(system.Array()), system.Raw) |
| 157 | + } |
| 158 | + if got := system.Get("0.type").String(); got != "text" { |
| 159 | + t.Fatalf("Expected system block type %q, got %q", "text", got) |
| 160 | + } |
| 161 | + if got := system.Get("0.text").String(); got != "You are a helpful assistant." { |
| 162 | + t.Fatalf("Expected system text %q, got %q", "You are a helpful assistant.", got) |
| 163 | + } |
| 164 | + |
| 165 | + messages := resultJSON.Get("messages").Array() |
| 166 | + if len(messages) != 1 { |
| 167 | + t.Fatalf("Expected 1 non-system message, got %d. Messages: %s", len(messages), resultJSON.Get("messages").Raw) |
| 168 | + } |
| 169 | + if got := messages[0].Get("role").String(); got != "user" { |
| 170 | + t.Fatalf("Expected remaining message role %q, got %q", "user", got) |
| 171 | + } |
| 172 | + if got := messages[0].Get("content.0.text").String(); got != "Hello" { |
| 173 | + t.Fatalf("Expected user text %q, got %q", "Hello", got) |
| 174 | + } |
| 175 | +} |
| 176 | + |
| 177 | +func TestConvertOpenAIRequestToClaude_MultipleSystemMessagesMergedIntoTopLevelSystem(t *testing.T) { |
| 178 | + inputJSON := `{ |
| 179 | + "model": "gpt-4.1", |
| 180 | + "messages": [ |
| 181 | + {"role": "system", "content": "Rule 1"}, |
| 182 | + {"role": "system", "content": [{"type": "text", "text": "Rule 2"}]}, |
| 183 | + {"role": "user", "content": "Hello"} |
| 184 | + ] |
| 185 | + }` |
| 186 | + |
| 187 | + result := ConvertOpenAIRequestToClaude("claude-sonnet-4-5", []byte(inputJSON), false) |
| 188 | + resultJSON := gjson.ParseBytes(result) |
| 189 | + |
| 190 | + system := resultJSON.Get("system").Array() |
| 191 | + if len(system) != 2 { |
| 192 | + t.Fatalf("Expected 2 system blocks, got %d. System: %s", len(system), resultJSON.Get("system").Raw) |
| 193 | + } |
| 194 | + if got := system[0].Get("text").String(); got != "Rule 1" { |
| 195 | + t.Fatalf("Expected first system text %q, got %q", "Rule 1", got) |
| 196 | + } |
| 197 | + if got := system[1].Get("text").String(); got != "Rule 2" { |
| 198 | + t.Fatalf("Expected second system text %q, got %q", "Rule 2", got) |
| 199 | + } |
| 200 | + |
| 201 | + messages := resultJSON.Get("messages").Array() |
| 202 | + if len(messages) != 1 { |
| 203 | + t.Fatalf("Expected 1 non-system message, got %d. Messages: %s", len(messages), resultJSON.Get("messages").Raw) |
| 204 | + } |
| 205 | +} |