diff --git a/server/routes.go b/server/routes.go index 80c00cb69f..f1770cb70c 100644 --- a/server/routes.go +++ b/server/routes.go @@ -1874,10 +1874,14 @@ func (s *Server) ChatHandler(c *gin.Context) { req.Options = map[string]any{} } - msgs := append(m.Messages, req.Messages...) - if req.Messages[0].Role != "system" && m.System != "" { - msgs = append([]api.Message{{Role: "system", Content: m.System}}, msgs...) + var msgs []api.Message + if len(req.Messages) > 0 { + msgs = append(m.Messages, req.Messages...) + if req.Messages[0].Role != "system" && m.System != "" { + msgs = append([]api.Message{{Role: "system", Content: m.System}}, msgs...) + } } + msgs = filterThinkTags(msgs, m) req.Messages = msgs diff --git a/server/routes_generate_test.go b/server/routes_generate_test.go index 75d4f012ee..bcd774fd11 100644 --- a/server/routes_generate_test.go +++ b/server/routes_generate_test.go @@ -6,6 +6,8 @@ import ( "encoding/json" "io" "net/http" + "net/http/httptest" + "net/url" "strings" "sync" "testing" @@ -52,6 +54,86 @@ func newMockServer(mock *mockRunner) func(discover.GpuInfoList, string, *ggml.GG } } +func TestGenerateChatRemote(t *testing.T) { + gin.SetMode(gin.TestMode) + + rs := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodPost { + t.Errorf("Expected POST request, got %s", r.Method) + } + if r.URL.Path != "/api/chat" { + t.Errorf("Expected path '/api/chat', got %s", r.URL.Path) + } + + w.WriteHeader(http.StatusOK) + w.Header().Set("Content-Type", "application/json") + resp := api.ChatResponse{ + Model: "test", + Done: true, + DoneReason: "load", + } + if err := json.NewEncoder(w).Encode(&resp); err != nil { + t.Fatal(err) + } + })) + defer rs.Close() + + p, err := url.Parse(rs.URL) + if err != nil { + t.Fatal(err) + } + + t.Setenv("OLLAMA_REMOTES", p.Hostname()) + s := Server{} + w := createRequest(t, s.CreateHandler, api.CreateRequest{ + Model: "test-cloud", + RemoteHost: rs.URL, + From: "test", + Info: map[string]any{ + "capabilities": []string{"completion", "thinking"}, + }, + Stream: &stream, + }) + + if w.Code != http.StatusOK { + t.Fatalf("expected status 200, got %d", w.Code) + } + + t.Run("missing messages", func(t *testing.T) { + w := createRequest(t, s.ChatHandler, api.ChatRequest{ + Model: "test-cloud", + }) + if w.Code != http.StatusOK { + t.Errorf("expected status 200, got %d", w.Code) + } + + var actual api.ChatResponse + if err := json.NewDecoder(w.Body).Decode(&actual); err != nil { + t.Fatal(err) + } + + if actual.Model != "test-cloud" { + t.Errorf("expected model test-cloud, got %s", actual.Model) + } + + if actual.RemoteModel != "test" { + t.Errorf("expected remote model test, got %s", actual.RemoteModel) + } + + if actual.RemoteHost != rs.URL { + t.Errorf("expected remote host '%s', got %s", rs.URL, actual.RemoteHost) + } + + if !actual.Done { + t.Errorf("expected done true, got false") + } + + if actual.DoneReason != "load" { + t.Errorf("expected done reason load, got %s", actual.DoneReason) + } + }) +} + func TestGenerateChat(t *testing.T) { gin.SetMode(gin.TestMode)