[PR #15664] openai: honor reasoning_effort in /v1/responses endpoint #25743

Open
opened 2026-04-19 18:25:27 -05:00 by GiteaMirror · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/ollama/ollama/pull/15664
Author: @balgaly
Created: 4/18/2026
Status: 🔄 Open

Base: mainHead: fix/responses-reasoning-effort


📝 Commits (1)

  • 42f6239 openai: honor reasoning_effort in /v1/responses endpoint

📊 Changes

2 files changed (+87 additions, -0 deletions)

View changed files

📝 openai/responses.go (+14 -0)
📝 openai/responses_test.go (+73 -0)

📄 Description

Fixes #15635.

Problem

/v1/chat/completions correctly disables thinking when reasoning_effort: "none" is passed, but /v1/responses ignores reasoning.effort entirely. Reproduction from the issue:

# Chat Completions — works (0.5s, no reasoning)
curl -s http://localhost:11434/v1/chat/completions \
  -d '{"model":"gemma4:e2b","messages":[{"role":"user","content":"Reply with ONLY: [1,3]"}],"reasoning_effort":"none","stream":false}'

# Responses — thinking NOT disabled (4.7s, full reasoning)
curl -s http://localhost:11434/v1/responses \
  -d '{"model":"gemma4:e2b","input":"Reply with ONLY: [1,3]","reasoning":{"effort":"none"},"stream":false}'

Root cause

openai/responses.go:FromResponsesRequest deserializes r.Reasoning.Effort (it is already used later for echoing reasoning config back to the client) but never converts it into the api.ChatRequest.Think field. The Chat Completions path at openai/openai.go:625-644 already performs this mapping.

Fix

Mirror the existing Chat Completions logic in FromResponsesRequest:

  • effort == "none"Think{Value: false} (suppresses thinking)
  • effort == "high" | "medium" | "low"Think{Value: <effort>}
  • any other value → the same validation error the Chat Completions path returns

Validation, error message, and accepted effort values are identical across the two endpoints, so behavior stays consistent.

Tests

TestFromResponsesRequest_ReasoningEffort covers:

  • "none" disables thinking (Think.Value == false)
  • "low", "medium", "high" set the string value
  • missing reasoning leaves Think unset
  • invalid effort returns an error

All existing ./openai/... and ./middleware/... tests still pass.

Notes

  • Only reasoning.effort is handled here — OpenAI's Responses API does not expose a flat reasoning_effort (that is a Chat Completions shape). Clients that sent {"reasoning_effort": "none"} on /v1/responses before this PR were effectively sending an unknown field; after the PR they should move to the canonical {"reasoning": {"effort": "none"}} form (which also did not work before).

🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/ollama/ollama/pull/15664 **Author:** [@balgaly](https://github.com/balgaly) **Created:** 4/18/2026 **Status:** 🔄 Open **Base:** `main` ← **Head:** `fix/responses-reasoning-effort` --- ### 📝 Commits (1) - [`42f6239`](https://github.com/ollama/ollama/commit/42f62397864275a9510f95f8dbc29bc46f7a7d86) openai: honor reasoning_effort in /v1/responses endpoint ### 📊 Changes **2 files changed** (+87 additions, -0 deletions) <details> <summary>View changed files</summary> 📝 `openai/responses.go` (+14 -0) 📝 `openai/responses_test.go` (+73 -0) </details> ### 📄 Description Fixes #15635. ## Problem `/v1/chat/completions` correctly disables thinking when `reasoning_effort: "none"` is passed, but `/v1/responses` ignores `reasoning.effort` entirely. Reproduction from the issue: ```bash # Chat Completions — works (0.5s, no reasoning) curl -s http://localhost:11434/v1/chat/completions \ -d '{"model":"gemma4:e2b","messages":[{"role":"user","content":"Reply with ONLY: [1,3]"}],"reasoning_effort":"none","stream":false}' # Responses — thinking NOT disabled (4.7s, full reasoning) curl -s http://localhost:11434/v1/responses \ -d '{"model":"gemma4:e2b","input":"Reply with ONLY: [1,3]","reasoning":{"effort":"none"},"stream":false}' ``` ## Root cause `openai/responses.go:FromResponsesRequest` deserializes `r.Reasoning.Effort` (it is already used later for echoing reasoning config back to the client) but never converts it into the `api.ChatRequest.Think` field. The Chat Completions path at `openai/openai.go:625-644` already performs this mapping. ## Fix Mirror the existing Chat Completions logic in `FromResponsesRequest`: - `effort == "none"` → `Think{Value: false}` (suppresses thinking) - `effort == "high" | "medium" | "low"` → `Think{Value: <effort>}` - any other value → the same validation error the Chat Completions path returns Validation, error message, and accepted effort values are identical across the two endpoints, so behavior stays consistent. ## Tests `TestFromResponsesRequest_ReasoningEffort` covers: - `"none"` disables thinking (`Think.Value == false`) - `"low"`, `"medium"`, `"high"` set the string value - missing `reasoning` leaves `Think` unset - invalid effort returns an error All existing `./openai/...` and `./middleware/...` tests still pass. ## Notes - Only `reasoning.effort` is handled here — OpenAI's Responses API does not expose a flat `reasoning_effort` (that is a Chat Completions shape). Clients that sent `{"reasoning_effort": "none"}` on `/v1/responses` before this PR were effectively sending an unknown field; after the PR they should move to the canonical `{"reasoning": {"effort": "none"}}` form (which also did not work before). --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
GiteaMirror added the pull-request label 2026-04-19 18:25:27 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/ollama#25743