nomadcode/internal/adapters/openai/client_test.go

140 lines
3.9 KiB
Go

package openai
import (
"context"
"encoding/json"
"net/http"
"net/http/httptest"
"testing"
"github.com/nomadcode/nomadcode-core/internal/model"
)
func TestGenerateCallsResponsesAPI(t *testing.T) {
var gotPath string
var gotAuth string
var gotBody map[string]any
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
gotPath = r.URL.Path
gotAuth = r.Header.Get("Authorization")
if err := json.NewDecoder(r.Body).Decode(&gotBody); err != nil {
t.Fatalf("decode request: %v", err)
}
w.Header().Set("Content-Type", "application/json")
_, _ = w.Write([]byte(`{
"id": "resp_test",
"model": "qwen3.6:35b-a3b-bf16",
"output_text": "hello from model",
"usage": {
"input_tokens": 3,
"output_tokens": 4,
"total_tokens": 7
}
}`))
}))
defer server.Close()
client := NewClient(Config{
BaseURL: server.URL,
APIKey: "test-key",
Model: "qwen3.6:35b-a3b-bf16",
ContextSize: 262144,
}, nil)
result, err := client.Generate(context.Background(), model.GenerateInput{
Input: "say hello",
Instructions: "be brief",
})
if err != nil {
t.Fatalf("Generate returned error: %v", err)
}
if gotPath != "/v1/responses" {
t.Fatalf("expected /v1/responses, got %q", gotPath)
}
if gotAuth != "Bearer test-key" {
t.Fatalf("expected auth header, got %q", gotAuth)
}
if gotBody["model"] != "qwen3.6:35b-a3b-bf16" {
t.Fatalf("unexpected model: %#v", gotBody["model"])
}
if gotBody["input"] != "say hello" {
t.Fatalf("unexpected input: %#v", gotBody["input"])
}
if gotBody["instructions"] != "be brief" {
t.Fatalf("unexpected instructions: %#v", gotBody["instructions"])
}
if _, ok := gotBody["context_size"]; ok {
t.Fatal("Responses API request must not include unsupported context_size")
}
options, ok := gotBody["options"].(map[string]any)
if !ok {
t.Fatalf("expected options object, got %#v", gotBody["options"])
}
if options["num_ctx"] != float64(262144) {
t.Fatalf("unexpected options.num_ctx: %#v", options["num_ctx"])
}
if result.Text != "hello from model" {
t.Fatalf("unexpected result text: %q", result.Text)
}
if result.Usage.TotalTokens != 7 {
t.Fatalf("unexpected usage: %#v", result.Usage)
}
}
func TestGenerateExtractsOutputContent(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.Header().Set("Content-Type", "application/json")
_, _ = w.Write([]byte(`{
"id": "resp_test",
"output": [
{
"type": "message",
"content": [
{"type": "output_text", "text": "hello "},
{"type": "output_text", "text": "again"}
]
}
],
"usage": {
"prompt_tokens": 2,
"completion_tokens": 5
}
}`))
}))
defer server.Close()
client := NewClient(Config{BaseURL: server.URL, Model: "model-a"}, nil)
result, err := client.Generate(context.Background(), model.GenerateInput{Input: "say hello"})
if err != nil {
t.Fatalf("Generate returned error: %v", err)
}
if result.Text != "hello again" {
t.Fatalf("unexpected result text: %q", result.Text)
}
if result.Usage.InputTokens != 2 || result.Usage.OutputTokens != 5 || result.Usage.TotalTokens != 7 {
t.Fatalf("unexpected usage: %#v", result.Usage)
}
}
func TestResponsesURL(t *testing.T) {
tests := map[string]string{
"http://localhost:11434": "http://localhost:11434/v1/responses",
"http://localhost:11434/": "http://localhost:11434/v1/responses",
"http://localhost:11434/v1": "http://localhost:11434/v1/responses",
"http://localhost:11434/v1/": "http://localhost:11434/v1/responses",
"http://localhost:11434/v1/responses": "http://localhost:11434/v1/responses",
}
for input, want := range tests {
got, err := responsesURL(input)
if err != nil {
t.Fatalf("responsesURL(%q) returned error: %v", input, err)
}
if got != want {
t.Fatalf("responsesURL(%q) = %q, want %q", input, got, want)
}
}
}