package provider import ( "encoding/json" "strings" "testing" ) func TestResponsesToChatCompletion_StringInput(t *testing.T) { body := []byte(`{"model":"gpt-4o-mini","instructions":"Be brief","input":"Hello"}`) out, err := ResponsesToChatCompletion(body) if err != nil { t.Fatal(err) } var req map[string]any if err := json.Unmarshal(out, &req); err != nil { t.Fatal(err) } if req["model"] != "gpt-4o-mini" { t.Fatalf("model: %v", req["model"]) } msgs := req["messages"].([]any) if len(msgs) != 2 { t.Fatalf("messages len: %d", len(msgs)) } sys := msgs[0].(map[string]any) user := msgs[1].(map[string]any) if sys["role"] != "system" || sys["content"] != "Be brief" { t.Fatalf("system: %#v", sys) } if user["role"] != "user" || user["content"] != "Hello" { t.Fatalf("user: %#v", user) } } func TestChatCompletionToResponses(t *testing.T) { body := []byte(`{"id":"chatcmpl-abc123","model":"gpt-4o-mini","created":123,"choices":[{"message":{"role":"assistant","content":"Hi"}}],"usage":{"prompt_tokens":3,"completion_tokens":1,"total_tokens":4}}`) out, err := ChatCompletionToResponses(body) if err != nil { t.Fatal(err) } var resp map[string]any if err := json.Unmarshal(out, &resp); err != nil { t.Fatal(err) } if resp["object"] != "response" { t.Fatalf("object: %v", resp["object"]) } if resp["id"] != "resp_abc123" { t.Fatalf("id: %v", resp["id"]) } if resp["output_text"] != "Hi" { t.Fatalf("output_text: %v", resp["output_text"]) } output := resp["output"].([]any) msg := output[0].(map[string]any) content := msg["content"].([]any) text := content[0].(map[string]any) if text["type"] != "output_text" || text["text"] != "Hi" { t.Fatalf("text: %#v", text) } if _, ok := text["annotations"]; !ok { t.Fatalf("missing annotations: %#v", text) } usage := resp["usage"].(map[string]any) if usage["input_tokens"].(float64) != 3 { t.Fatalf("usage: %#v", usage) } if _, ok := usage["input_tokens_details"]; !ok { t.Fatalf("missing input_tokens_details") } } func TestResponsesToChatCompletion_InputTextParts(t *testing.T) { body := []byte(`{ "model":"gpt-4o-mini", "input":[{"role":"user","content":[{"type":"input_text","text":"Hello"}]}] }`) out, err := ResponsesToChatCompletion(body) if err != nil { t.Fatal(err) } var req map[string]any if err := json.Unmarshal(out, &req); err != nil { t.Fatal(err) } msgs := req["messages"].([]any) user := msgs[0].(map[string]any) if user["content"] != "Hello" { t.Fatalf("content: %#v", user["content"]) } } func TestResponsesToChatCompletion_InputTextAndImage(t *testing.T) { body := []byte(`{ "model":"gpt-4o-mini", "input":[{"role":"user","content":[ {"type":"input_text","text":"describe"}, {"type":"input_image","image_url":"https://example.com/a.png","detail":"auto"} ]}] }`) out, err := ResponsesToChatCompletion(body) if err != nil { t.Fatal(err) } var req map[string]any if err := json.Unmarshal(out, &req); err != nil { t.Fatal(err) } msgs := req["messages"].([]any) user := msgs[0].(map[string]any) parts := user["content"].([]any) if len(parts) != 2 { t.Fatalf("parts: %#v", parts) } textPart := parts[0].(map[string]any) if textPart["type"] != "text" || textPart["text"] != "describe" { t.Fatalf("text part: %#v", textPart) } imgPart := parts[1].(map[string]any) if imgPart["type"] != "image_url" { t.Fatalf("image part: %#v", imgPart) } } func TestResponsesToChatCompletion_MessageItem(t *testing.T) { body := []byte(`{ "model":"gpt-4o-mini", "input":[{"type":"message","role":"user","content":[{"type":"input_text","text":"Hi"}]}] }`) out, err := ResponsesToChatCompletion(body) if err != nil { t.Fatal(err) } if strings.Contains(string(out), "input_text") { t.Fatalf("should not contain input_text: %s", out) } var req map[string]any if err := json.Unmarshal(out, &req); err != nil { t.Fatal(err) } msgs := req["messages"].([]any) user := msgs[0].(map[string]any) if user["content"] != "Hi" { t.Fatalf("content: %#v", user["content"]) } } func TestAdaptResponsesStream(t *testing.T) { upstream := strings.NewReader("data: {\"id\":\"chatcmpl-1\",\"model\":\"gpt-4o-mini\",\"choices\":[{\"delta\":{\"content\":\"Hi\"}}]}\n\ndata: [DONE]\n\n") var out strings.Builder result, err := AdaptResponsesStream([]byte(`{"model":"gpt-4o-mini","stream":true}`), upstream, &out, nil) if err != nil { t.Fatal(err) } if result.StatusCode != 200 { t.Fatalf("status: %d", result.StatusCode) } s := out.String() for _, event := range []string{ "response.created", "response.in_progress", "response.output_item.added", "response.output_text.delta", "response.output_text.done", "response.output_item.done", "response.completed", } { if !strings.Contains(s, event) { t.Fatalf("missing event %s: %s", event, s) } } if !strings.Contains(s, `"delta":"Hi"`) { t.Fatalf("missing delta text: %s", s) } if !strings.Contains(s, `"output_text":"Hi"`) { t.Fatalf("missing output_text in completed: %s", s) } }