From d0cf6c82811c2268a396888347ff95087a618d56 Mon Sep 17 00:00:00 2001 From: Michael Yang Date: Tue, 12 Aug 2025 11:02:01 -0700 Subject: [PATCH] fix(openai): handle reasoning_effort (#11868) --- api/types.go | 8 ++++---- openai/openai.go | 11 +++++++---- server/prompt.go | 8 ++++---- server/routes.go | 16 ++++++++-------- 4 files changed, 23 insertions(+), 20 deletions(-) diff --git a/api/types.go b/api/types.go index 0f99de18cd..0309ebbe37 100644 --- a/api/types.go +++ b/api/types.go @@ -769,8 +769,8 @@ func (t *ThinkValue) IsString() bool { return ok } -// AsBool returns the value as a bool (true if enabled in any way) -func (t *ThinkValue) AsBool() bool { +// Bool returns the value as a bool (true if enabled in any way) +func (t *ThinkValue) Bool() bool { if t == nil || t.Value == nil { return false } @@ -786,8 +786,8 @@ func (t *ThinkValue) AsBool() bool { } } -// AsString returns the value as a string -func (t *ThinkValue) AsString() string { +// String returns the value as a string +func (t *ThinkValue) String() string { if t == nil || t.Value == nil { return "" } diff --git a/openai/openai.go b/openai/openai.go index 50fdb81e90..13b9c425fa 100644 --- a/openai/openai.go +++ b/openai/openai.go @@ -103,6 +103,7 @@ type ChatCompletionRequest struct { ResponseFormat *ResponseFormat `json:"response_format"` Tools []api.Tool `json:"tools"` Reasoning *Reasoning `json:"reasoning,omitempty"` + ReasoningEffort *string `json:"reasoning_effort,omitempty"` } type ChatCompletion struct { @@ -541,10 +542,6 @@ func fromChatRequest(r ChatCompletionRequest) (*api.ChatRequest, error) { options["top_p"] = 1.0 } - if r.Reasoning != nil { - options["reasoning"] = *r.Reasoning.Effort - } - var format json.RawMessage if r.ResponseFormat != nil { switch strings.ToLower(strings.TrimSpace(r.ResponseFormat.Type)) { @@ -560,9 +557,15 @@ func fromChatRequest(r ChatCompletionRequest) (*api.ChatRequest, error) { var think *api.ThinkValue if r.Reasoning != nil { + options["reasoning"] = *r.Reasoning.Effort think = &api.ThinkValue{ Value: *r.Reasoning.Effort, } + } else if r.ReasoningEffort != nil { + options["reasoning"] = *r.ReasoningEffort + think = &api.ThinkValue{ + Value: *r.ReasoningEffort, + } } return &api.ChatRequest{ diff --git a/server/prompt.go b/server/prompt.go index 5d6c3e27cb..f1d8020ea6 100644 --- a/server/prompt.go +++ b/server/prompt.go @@ -44,8 +44,8 @@ func chatPrompt(ctx context.Context, m *Model, tokenize tokenizeFunc, opts *api. thinkVal := false thinkLevel := "" if think != nil { - thinkVal = think.AsBool() - thinkLevel = think.AsString() + thinkVal = think.Bool() + thinkLevel = think.String() } var b bytes.Buffer if err := m.Template.Execute(&b, template.Values{Messages: append(system, msgs[i:]...), Tools: tools, Think: thinkVal, ThinkLevel: thinkLevel, IsThinkSet: think != nil}); err != nil { @@ -105,8 +105,8 @@ func chatPrompt(ctx context.Context, m *Model, tokenize tokenizeFunc, opts *api. thinkVal := false thinkLevel := "" if think != nil { - thinkVal = think.AsBool() - thinkLevel = think.AsString() + thinkVal = think.Bool() + thinkLevel = think.String() } if err := m.Template.Execute(&b, template.Values{Messages: append(system, msgs[currMsgIdx:]...), Tools: tools, Think: thinkVal, ThinkLevel: thinkLevel, IsThinkSet: think != nil}); err != nil { return "", nil, err diff --git a/server/routes.go b/server/routes.go index d8d1e301c5..3c044cd008 100644 --- a/server/routes.go +++ b/server/routes.go @@ -205,7 +205,7 @@ func (s *Server) GenerateHandler(c *gin.Context) { // Validate Think value: string values currently only allowed for gptoss models if req.Think != nil && req.Think.IsString() && !useHarmony { - c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("think value %q is not supported for this model", req.Think.AsString())}) + c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("think value %q is not supported for this model", req.Think.String())}) return } @@ -213,7 +213,7 @@ func (s *Server) GenerateHandler(c *gin.Context) { if req.Suffix != "" { caps = append(caps, model.CapabilityInsert) } - if req.Think != nil && req.Think.AsBool() { + if req.Think != nil && req.Think.Bool() { caps = append(caps, model.CapabilityThinking) // TODO(drifkin): consider adding a warning if it's false and the model // doesn't support thinking. It's not strictly required, but it can be a @@ -288,10 +288,10 @@ func (s *Server) GenerateHandler(c *gin.Context) { values.Messages = append(msgs, api.Message{Role: "user", Content: req.Prompt}) } - values.Think = req.Think != nil && req.Think.AsBool() + values.Think = req.Think != nil && req.Think.Bool() values.ThinkLevel = "" if req.Think != nil { - values.ThinkLevel = req.Think.AsString() + values.ThinkLevel = req.Think.String() } values.IsThinkSet = req.Think != nil @@ -317,7 +317,7 @@ func (s *Server) GenerateHandler(c *gin.Context) { var thinkingState *thinking.Parser if !useHarmony { openingTag, closingTag := thinking.InferTags(m.Template.Template) - if req.Think != nil && req.Think.AsBool() && openingTag != "" && closingTag != "" { + if req.Think != nil && req.Think.Bool() && openingTag != "" && closingTag != "" { thinkingState = &thinking.Parser{ OpeningTag: openingTag, ClosingTag: closingTag, @@ -1547,7 +1547,7 @@ func (s *Server) ChatHandler(c *gin.Context) { if len(req.Tools) > 0 { caps = append(caps, model.CapabilityTools) } - if req.Think != nil && req.Think.AsBool() { + if req.Think != nil && req.Think.Bool() { caps = append(caps, model.CapabilityThinking) } @@ -1601,7 +1601,7 @@ func (s *Server) ChatHandler(c *gin.Context) { // Validate Think value: string values currently only allowed for gptoss models if req.Think != nil && req.Think.IsString() && !useHarmony { - c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("think value %q is not supported for this model", req.Think.AsString())}) + c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("think value %q is not supported for this model", req.Think.String())}) return } @@ -1620,7 +1620,7 @@ func (s *Server) ChatHandler(c *gin.Context) { var thinkingState *thinking.Parser openingTag, closingTag := thinking.InferTags(m.Template.Template) - if req.Think != nil && req.Think.AsBool() && openingTag != "" && closingTag != "" { + if req.Think != nil && req.Think.Bool() && openingTag != "" && closingTag != "" { thinkingState = &thinking.Parser{ OpeningTag: openingTag, ClosingTag: closingTag,