reverse changes

This commit is contained in:
Grace Guo
2025-11-03 15:51:48 -08:00
parent 2a5214930e
commit c51ab4aa80
4 changed files with 118 additions and 99 deletions

View File

@@ -381,3 +381,30 @@ func TestAPIShowModel(t *testing.T) {
t.Errorf("%s missing modified_at: %#v", modelName, resp) t.Errorf("%s missing modified_at: %#v", modelName, resp)
} }
} }
func TestAPIEmbeddings(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Minute)
defer cancel()
client, _, cleanup := InitServerConnection(ctx, t)
defer cleanup()
req := api.EmbeddingRequest{
Model: libraryEmbedModels[0],
Prompt: "why is the sky blue?",
Options: map[string]interface{}{
"temperature": 0,
"seed": 123,
},
}
if err := PullIfMissing(ctx, client, req.Model); err != nil {
t.Fatalf("pull failed %s", err)
}
resp, err := client.Embeddings(ctx, &req)
if err != nil {
t.Fatalf("embeddings call failed %s", err)
}
if len(resp.Embedding) == 0 {
t.Errorf("zero length embedding response")
}
}

View File

@@ -12,18 +12,22 @@ import (
"github.com/ollama/ollama/api" "github.com/ollama/ollama/api"
) )
// TestQwen3VLStreaming tests Qwen3-VL with streaming enabled // getTestConfig returns model and streaming mode based on environment variables or defaults
func TestQwen3VLStreaming(t *testing.T) { func getTestConfig() (model string, stream bool) {
runQwen3VLTests(t, true) model = os.Getenv("QWEN3VL_MODEL")
if model == "" {
model = "qwen3-vl:235b-cloud" // default
}
streamStr := os.Getenv("QWEN3VL_STREAM")
stream = streamStr != "false" // default to true
return model, stream
} }
// TestQwen3VLNonStreaming tests Qwen3-VL with streaming disabled func TestQwen3VL(t *testing.T) {
func TestQwen3VLNonStreaming(t *testing.T) { model, stream := getTestConfig()
runQwen3VLTests(t, false)
}
func runQwen3VLTests(t *testing.T, stream bool) {
models := []string{"qwen3-vl:235b-cloud", "qwen3-vl:235b-instruct-cloud"}
tests := []struct { tests := []struct {
name string name string
messages []api.Message messages []api.Message
@@ -46,10 +50,10 @@ func runQwen3VLTests(t *testing.T, stream bool) {
}, },
{ {
Role: "user", Role: "user",
Content: "What is the answer to this question?", Content: "What is in this image?",
}, },
}, },
images: []string{"testdata/question.png"}, images: []string{"testdata/menu.png"},
}, },
{ {
name: "Multiple Images Scenario", name: "Multiple Images Scenario",
@@ -63,7 +67,7 @@ func runQwen3VLTests(t *testing.T, stream bool) {
Content: "Use both images to answer the question.", Content: "Use both images to answer the question.",
}, },
}, },
images: []string{"testdata/question.png", "testdata/menu.png"}, images: []string{"testdata/satmath1.png", "testdata/satmath2.png"},
}, },
{ {
name: "Tools Scenario", name: "Tools Scenario",
@@ -158,101 +162,89 @@ func runQwen3VLTests(t *testing.T, stream bool) {
}, },
} }
for _, model := range models { for _, tt := range tests {
for _, tt := range tests { t.Run(tt.name, func(t *testing.T) {
t.Run(tt.name, func(t *testing.T) { // Load and attach images to last user message
// Load and attach images if specified messages := tt.messages
if len(tt.images) > 0 { if len(tt.images) > 0 {
var imgs []api.ImageData var imgs []api.ImageData
for _, path := range tt.images { for _, path := range tt.images {
imgs = append(imgs, loadImageData(t, path)) imgs = append(imgs, loadImageData(t, path))
} }
if len(tt.messages) > 0 { // Find last user message and attach images
lastMessage := &tt.messages[len(tt.messages)-1] for i := len(messages) - 1; i >= 0; i-- {
if lastMessage.Role == "user" { if messages[i].Role == "user" {
lastMessage.Images = imgs messages[i].Images = imgs
} break
} }
} }
}
// Build chat request ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
req := api.ChatRequest{ defer cancel()
Model: model, client, _, cleanup := InitServerConnection(ctx, t)
Messages: tt.messages, defer cleanup()
Tools: tt.tools,
Stream: &stream, // Pull/preload model if not using remote server
Options: map[string]any{ if os.Getenv("OLLAMA_TEST_EXISTING") == "" {
"seed": 42, if err := PullIfMissing(ctx, client, model); err != nil {
"temperature": 0.0, t.Fatal(err)
},
} }
// Preload to reduce startup latency
_ = client.Generate(ctx, &api.GenerateRequest{Model: model}, func(api.GenerateResponse) error { return nil })
}
isRemote := os.Getenv("OLLAMA_TEST_EXISTING") != "" // Build and execute chat request
req := &api.ChatRequest{
Model: model,
Messages: messages,
Tools: tt.tools,
Stream: &stream,
Options: map[string]any{"seed": 42, "temperature": 0.0},
}
// Use integration helpers var contentBuf, thinkingBuf strings.Builder
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute) var toolCalls []api.ToolCall
defer cancel()
client, _, cleanup := InitServerConnection(ctx, t)
defer cleanup()
// Skip pulling/preloading when using an existing (cloud) server err := client.Chat(ctx, req, func(r api.ChatResponse) error {
if !isRemote { contentBuf.WriteString(r.Message.Content)
if err := PullIfMissing(ctx, client, req.Model); err != nil { thinkingBuf.WriteString(r.Message.Thinking)
t.Fatal(err) toolCalls = append(toolCalls, r.Message.ToolCalls...)
} return nil
// Preload model once to reduce startup latency
_ = client.Generate(ctx, &api.GenerateRequest{Model: req.Model}, func(r api.GenerateResponse) error { return nil })
}
var contentBuf, thinkingBuf strings.Builder
var gotCalls []api.ToolCall
err := client.Chat(ctx, &req, func(r api.ChatResponse) error {
contentBuf.WriteString(r.Message.Content)
thinkingBuf.WriteString(r.Message.Thinking)
if len(r.Message.ToolCalls) > 0 {
gotCalls = append(gotCalls, r.Message.ToolCalls...)
}
return nil
})
if err != nil {
t.Fatalf("chat error: %v", err)
}
// Log responses (truncated)
content := contentBuf.String()
thinking := thinkingBuf.String()
const maxLog = 800
if len(thinking) > 0 {
if len(thinking) > maxLog {
thinking = thinking[:maxLog] + "... [truncated]"
}
t.Logf("Thinking: %s", thinking)
}
if len(content) > 0 {
if len(content) > maxLog {
content = content[:maxLog] + "... [truncated]"
}
t.Logf("Content: %s", content)
}
if len(gotCalls) > 0 {
t.Logf("Tool calls: %d", len(gotCalls))
for i, call := range gotCalls {
t.Logf(" [%d] %s(%+v)", i, call.Function.Name, call.Function.Arguments)
}
}
// If this is a tools scenario, validate tool_calls
if len(tt.tools) > 0 {
if len(gotCalls) == 0 {
t.Fatalf("expected at least one tool call, got none")
}
if gotCalls[0].Function.Name == "" {
t.Fatalf("tool call missing function name: %#v", gotCalls[0])
}
}
}) })
} if err != nil {
t.Fatalf("chat error: %v", err)
}
// Log truncated responses
logTruncated := func(label, text string) {
if text != "" {
if len(text) > 800 {
text = text[:800] + "... [truncated]"
}
t.Logf("%s: %s", label, text)
}
}
logTruncated("Thinking", thinkingBuf.String())
logTruncated("Content", contentBuf.String())
if len(toolCalls) > 0 {
t.Logf("Tool calls: %d", len(toolCalls))
for i, call := range toolCalls {
t.Logf(" [%d] %s(%+v)", i, call.Function.Name, call.Function.Arguments)
}
}
// Validate tool calls if tools were provided
if len(tt.tools) > 0 {
if len(toolCalls) == 0 {
t.Fatal("expected at least one tool call, got none")
}
if toolCalls[0].Function.Name == "" {
t.Fatalf("tool call missing function name: %#v", toolCalls[0])
}
}
})
} }
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 569 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 MiB