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...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...I'll use a tool.searchquerytest", 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 := "get_weatherlocationSan Franciscounitcelsius" _, _, 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<", "", 1}, {"hello", 2}, {"hello", 3}, {"hello", 4}, {"hello", 5}, {"hello", 6}, {"hello", 7}, {"hello", "", 8}, // Complete tag at end returns full length {"hello", "", 0}, {"", "", 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) } }) } }