formatter: skip temperature override for reasoning models

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.
This commit is contained in:
cmos dev
2026-04-10 21:30:59 -04:00
parent 4cad38ef30
commit ee0bcd107e
+20 -5
View File
@@ -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: def _openai_caller(system: str, user: str) -> str:
"""Default caller — hits the real OpenAI API. """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 from openai import OpenAI # imported lazily so unit tests do not need the network
client = OpenAI() client = OpenAI()
response = client.chat.completions.create( kwargs: dict = {
model=MODEL, "model": MODEL,
temperature=0, "messages": [
messages=[
{"role": "system", "content": system}, {"role": "system", "content": system},
{"role": "user", "content": user}, {"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 "" return response.choices[0].message.content or ""