mirror of
https://github.com/ollama/ollama.git
synced 2026-04-18 12:54:12 +02:00
* prefer rocm v6 on windows Avoid building with v7 - more changes are needed * MLX: add header vendoring and remove go build tag This switches to using a vendoring approach for the mlx-c headers so that Go can build without requiring a cmake first. This enables building the new MLX based code by default. Every time cmake runs, the headers are refreshed, so we can easily keep them in sync when we bump mlx versions. Basic Windows and Linux support are verified. * ci: harden for flaky choco repo servers CI sometimes fails due to choco not actually installing cache. Since it just speeds up the build, we can proceed without. * review comments
191 lines
4.6 KiB
Go
191 lines
4.6 KiB
Go
package glm4_moe_lite
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/ollama/ollama/api"
|
|
)
|
|
|
|
func TestParserThinking(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
input string
|
|
thinkEnabled bool
|
|
wantContent string
|
|
wantThinking string
|
|
wantToolCalls int
|
|
}{
|
|
{
|
|
name: "thinking enabled - simple thinking then content",
|
|
input: "Let me think about this...</think>Here is my answer.",
|
|
thinkEnabled: true,
|
|
wantThinking: "Let me think about this...",
|
|
wantContent: "Here is my answer.",
|
|
},
|
|
{
|
|
name: "thinking enabled - only thinking",
|
|
input: "I need to consider multiple factors...",
|
|
thinkEnabled: true,
|
|
wantThinking: "I need to consider multiple factors...",
|
|
wantContent: "",
|
|
},
|
|
{
|
|
name: "thinking disabled - direct content",
|
|
input: "Here is my direct answer.",
|
|
thinkEnabled: false,
|
|
wantThinking: "",
|
|
wantContent: "Here is my direct answer.",
|
|
},
|
|
{
|
|
name: "thinking with tool call",
|
|
input: "Let me search for that...</think>I'll use a tool.<tool_call>search<arg_key>query</arg_key><arg_value>test</arg_value></tool_call>",
|
|
thinkEnabled: true,
|
|
wantThinking: "Let me search for that...",
|
|
wantContent: "I'll use a tool.",
|
|
wantToolCalls: 1,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
p := &Parser{}
|
|
|
|
var thinkValue *api.ThinkValue
|
|
if tt.thinkEnabled {
|
|
thinkValue = &api.ThinkValue{Value: true}
|
|
} else {
|
|
thinkValue = &api.ThinkValue{Value: false}
|
|
}
|
|
|
|
// Define tools for tool call tests
|
|
props := api.NewToolPropertiesMap()
|
|
props.Set("query", api.ToolProperty{Type: api.PropertyType{"string"}})
|
|
tools := []api.Tool{
|
|
{
|
|
Function: api.ToolFunction{
|
|
Name: "search",
|
|
Parameters: api.ToolFunctionParameters{
|
|
Properties: props,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
p.Init(tools, nil, thinkValue)
|
|
|
|
content, thinking, calls, err := p.Add(tt.input, true)
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
|
|
if thinking != tt.wantThinking {
|
|
t.Errorf("thinking = %q, want %q", thinking, tt.wantThinking)
|
|
}
|
|
if content != tt.wantContent {
|
|
t.Errorf("content = %q, want %q", content, tt.wantContent)
|
|
}
|
|
if len(calls) != tt.wantToolCalls {
|
|
t.Errorf("len(calls) = %d, want %d", len(calls), tt.wantToolCalls)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestParserToolCall(t *testing.T) {
|
|
p := &Parser{}
|
|
|
|
props := api.NewToolPropertiesMap()
|
|
props.Set("location", api.ToolProperty{Type: api.PropertyType{"string"}})
|
|
props.Set("unit", api.ToolProperty{Type: api.PropertyType{"string"}})
|
|
tools := []api.Tool{
|
|
{
|
|
Function: api.ToolFunction{
|
|
Name: "get_weather",
|
|
Parameters: api.ToolFunctionParameters{
|
|
Properties: props,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
// Initialize with thinking disabled
|
|
tv := &api.ThinkValue{Value: false}
|
|
p.Init(tools, nil, tv)
|
|
|
|
input := "<tool_call>get_weather<arg_key>location</arg_key><arg_value>San Francisco</arg_value><arg_key>unit</arg_key><arg_value>celsius</arg_value></tool_call>"
|
|
|
|
_, _, calls, err := p.Add(input, true)
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
|
|
if len(calls) != 1 {
|
|
t.Fatalf("expected 1 tool call, got %d", len(calls))
|
|
}
|
|
|
|
call := calls[0]
|
|
if call.Function.Name != "get_weather" {
|
|
t.Errorf("function name = %q, want %q", call.Function.Name, "get_weather")
|
|
}
|
|
|
|
location, ok := call.Function.Arguments.Get("location")
|
|
if !ok || location != "San Francisco" {
|
|
t.Errorf("location = %v, want %q", location, "San Francisco")
|
|
}
|
|
|
|
unit, ok := call.Function.Arguments.Get("unit")
|
|
if !ok || unit != "celsius" {
|
|
t.Errorf("unit = %v, want %q", unit, "celsius")
|
|
}
|
|
}
|
|
|
|
func TestOverlap(t *testing.T) {
|
|
tests := []struct {
|
|
s string
|
|
tag string
|
|
want int
|
|
}{
|
|
{"hello<", "</think>", 1},
|
|
{"hello</", "</think>", 2},
|
|
{"hello</t", "</think>", 3},
|
|
{"hello</th", "</think>", 4},
|
|
{"hello</thi", "</think>", 5},
|
|
{"hello</thin", "</think>", 6},
|
|
{"hello</think", "</think>", 7},
|
|
{"hello</think>", "</think>", 8}, // Complete tag at end returns full length
|
|
{"hello", "</think>", 0},
|
|
{"", "</think>", 0},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.s+"_"+tt.tag, func(t *testing.T) {
|
|
got := overlap(tt.s, tt.tag)
|
|
if got != tt.want {
|
|
t.Errorf("overlap(%q, %q) = %d, want %d", tt.s, tt.tag, got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestTrailingWhitespaceLen(t *testing.T) {
|
|
tests := []struct {
|
|
s string
|
|
want int
|
|
}{
|
|
{"hello ", 3},
|
|
{"hello\n\t ", 3},
|
|
{"hello", 0},
|
|
{"", 0},
|
|
{" ", 3},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.s, func(t *testing.T) {
|
|
got := trailingWhitespaceLen(tt.s)
|
|
if got != tt.want {
|
|
t.Errorf("trailingWhitespaceLen(%q) = %d, want %d", tt.s, got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|