From ee0bcd107e7a3d252fd6d80999932ab7899917ef Mon Sep 17 00:00:00 2001 From: cmos dev Date: Fri, 10 Apr 2026 21:30:59 -0400 Subject: [PATCH] formatter: skip temperature override for reasoning models MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GPT-5 and the o-series reject temperature=0 with a 400 BadRequestError — only the default (1) is supported for reasoning models. Add an _is_reasoning_model helper and pass temperature only when the model name does not start with gpt-5/o1/o3/o4. Determinism on reasoning models is a property of the architecture, not a parameter. Discovered on the first real LLM run against the seed exemplars. --- src/cmos/formatter.py | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/src/cmos/formatter.py b/src/cmos/formatter.py index fd2cfee..f7c435c 100644 --- a/src/cmos/formatter.py +++ b/src/cmos/formatter.py @@ -88,6 +88,17 @@ def build_user_message(messy_entry: str) -> str: ) +def _is_reasoning_model(model: str) -> bool: + """Reasoning-model families (GPT-5, o-series) don't accept temperature overrides. + + OpenAI rejects ``temperature=0`` on these with a 400 BadRequestError; + only the default (1) is supported. Determinism on reasoning models is a + property of the architecture, not a parameter. + """ + prefixes = ("gpt-5", "o1", "o3", "o4") + return any(model.startswith(p) for p in prefixes) + + def _openai_caller(system: str, user: str) -> str: """Default caller — hits the real OpenAI API. @@ -99,14 +110,18 @@ def _openai_caller(system: str, user: str) -> str: from openai import OpenAI # imported lazily so unit tests do not need the network client = OpenAI() - response = client.chat.completions.create( - model=MODEL, - temperature=0, - messages=[ + kwargs: dict = { + "model": MODEL, + "messages": [ {"role": "system", "content": system}, {"role": "user", "content": user}, ], - ) + } + # Non-reasoning models still benefit from temperature=0; reasoning models + # reject it. + if not _is_reasoning_model(MODEL): + kwargs["temperature"] = 0 + response = client.chat.completions.create(**kwargs) return response.choices[0].message.content or ""