Skip to content

Commit b16158d

Browse files
committed
fix: skip reasoning.summary for o1-pro and gpt-5-chat models
Exclude gpt-5-chat* variants from isOpenAIReasoningModel since they are non-reasoning chat models. Add supportsReasoningSummary helper to avoid sending reasoning.summary to o1-pro models which reject that parameter. Fixes #2165 Fixes #2166 Assisted-By: docker-agent
1 parent 3ff5495 commit b16158d

2 files changed

Lines changed: 76 additions & 3 deletions

File tree

pkg/model/provider/openai/client.go

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -375,8 +375,13 @@ func (c *Client) CreateResponseStream(
375375
// Skip reasoning configuration entirely if thinking is explicitly disabled (via /think command)
376376
thinkingEnabled := c.ModelOptions.Thinking() == nil || *c.ModelOptions.Thinking()
377377
if isOpenAIReasoningModel(c.ModelConfig.Model) && thinkingEnabled {
378-
params.Reasoning = shared.ReasoningParam{
379-
Summary: shared.ReasoningSummaryDetailed,
378+
// Only set reasoning.summary for models that support it.
379+
// Some reasoning models (e.g. o1-pro) reject this parameter.
380+
if supportsReasoningSummary(c.ModelConfig.Model) {
381+
params.Reasoning = shared.ReasoningParam{
382+
Summary: shared.ReasoningSummaryDetailed,
383+
}
384+
slog.Debug("OpenAI responses request configured with reasoning summary", "model", c.ModelConfig.Model, "summary", "detailed")
380385
}
381386
// Apply thinking budget as reasoning effort if configured
382387
if c.ModelConfig.ThinkingBudget != nil {
@@ -388,7 +393,6 @@ func (c *Client) CreateResponseStream(
388393
params.Reasoning.Effort = shared.ReasoningEffort(effort)
389394
slog.Debug("OpenAI responses request using thinking_budget", "reasoning_effort", effort)
390395
}
391-
slog.Debug("OpenAI responses request configured with reasoning summary", "model", c.ModelConfig.Model, "summary", "detailed")
392396
}
393397

394398
// Apply structured output configuration
@@ -903,12 +907,33 @@ func isResponsesModel(model string) bool {
903907

904908
func isOpenAIReasoningModel(model string) bool {
905909
m := strings.ToLower(model)
910+
911+
// gpt-5-chat variants are non-reasoning chat models.
912+
if strings.HasPrefix(m, "gpt-5-chat") {
913+
return false
914+
}
915+
906916
return strings.HasPrefix(m, "o1") ||
907917
strings.HasPrefix(m, "o3") ||
908918
strings.HasPrefix(m, "o4") ||
909919
strings.HasPrefix(m, "gpt-5")
910920
}
911921

922+
// supportsReasoningSummary returns true for reasoning models that support the
923+
// reasoning.summary parameter. Some reasoning models (e.g. o1-pro) do not
924+
// support it and will reject the request if it is set.
925+
func supportsReasoningSummary(model string) bool {
926+
if !isOpenAIReasoningModel(model) {
927+
return false
928+
}
929+
m := strings.ToLower(model)
930+
// o1-pro does not support reasoning.summary.
931+
if strings.HasPrefix(m, "o1-pro") {
932+
return false
933+
}
934+
return true
935+
}
936+
912937
// getOpenAIReasoningEffort resolves the reasoning effort value from the
913938
// model configuration's ThinkingBudget. Returns the effort (minimal|low|medium|high) or an error
914939
func getOpenAIReasoningEffort(cfg *latest.ModelConfig) (effort string, err error) {

pkg/model/provider/openai/thinking_budget_test.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,11 @@ func TestIsOpenAIReasoningModel(t *testing.T) {
4040
{"gpt-5-turbo", "gpt-5-turbo", true},
4141
{"GPT-5 uppercase", "GPT-5", true},
4242

43+
// GPT-5-chat variants are non-reasoning chat models
44+
{"gpt-5-chat-latest", "gpt-5-chat-latest", false},
45+
{"gpt-5-chat", "gpt-5-chat", false},
46+
{"GPT-5-CHAT uppercase", "GPT-5-CHAT-LATEST", false},
47+
4348
// GPT-4 series models - should NOT support reasoning
4449
{"gpt-4", "gpt-4", false},
4550
{"gpt-4o", "gpt-4o", false},
@@ -51,6 +56,11 @@ func TestIsOpenAIReasoningModel(t *testing.T) {
5156
{"gpt-3.5-turbo", "gpt-3.5-turbo", false},
5257
{"gpt-3.5-turbo-16k", "gpt-3.5-turbo-16k", false},
5358

59+
// O1-pro series models - should support reasoning
60+
{"o1-pro", "o1-pro", true},
61+
{"o1-pro-2025-03-19", "o1-pro-2025-03-19", true},
62+
{"O1-PRO uppercase", "O1-PRO", true},
63+
5464
// Other models - should NOT support reasoning
5565
{"text-davinci-003", "text-davinci-003", false},
5666
{"gpt-3", "gpt-3", false},
@@ -70,6 +80,44 @@ func TestIsOpenAIReasoningModel(t *testing.T) {
7080
}
7181
}
7282

83+
func TestSupportsReasoningSummary(t *testing.T) {
84+
t.Parallel()
85+
86+
tests := []struct {
87+
name string
88+
model string
89+
expected bool
90+
}{
91+
// Standard reasoning models - should support summary
92+
{"o1-preview", "o1-preview", true},
93+
{"o1-mini", "o1-mini", true},
94+
{"o3-mini", "o3-mini", true},
95+
{"o4-preview", "o4-preview", true},
96+
{"gpt-5", "gpt-5", true},
97+
{"gpt-5-mini", "gpt-5-mini", true},
98+
99+
// o1-pro models - do NOT support summary
100+
{"o1-pro", "o1-pro", false},
101+
{"o1-pro-2025-03-19", "o1-pro-2025-03-19", false},
102+
{"O1-PRO uppercase", "O1-PRO", false},
103+
104+
// Non-reasoning models - do NOT support summary
105+
{"gpt-4o", "gpt-4o", false},
106+
{"gpt-4-turbo", "gpt-4-turbo", false},
107+
{"gpt-5-chat-latest", "gpt-5-chat-latest", false},
108+
{"empty string", "", false},
109+
}
110+
111+
for _, tt := range tests {
112+
t.Run(tt.name, func(t *testing.T) {
113+
t.Parallel()
114+
115+
result := supportsReasoningSummary(tt.model)
116+
assert.Equal(t, tt.expected, result, "Model %s should return %v", tt.model, tt.expected)
117+
})
118+
}
119+
}
120+
73121
func TestGetOpenAIReasoningEffort_Success(t *testing.T) {
74122
t.Parallel()
75123

0 commit comments

Comments
 (0)