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) } } }