feat(code): add GPT-5.6 model family (#4600)

Deep Agents Code now supports GPT-5.6 Sol, Terra, and Luna through
OpenAI API keys and ChatGPT sign-in, including the new `max` reasoning
effort.

---

OpenAI's GPT-5.6 profiles have not reached `langchain-openai` yet, which
would otherwise keep the new family out of the model selector. This adds
Sol, Terra, and Luna as curated recommendations while preserving
upstream profiles as the authoritative metadata source once they are
released.

- Surface all three models through the OpenAI API and ChatGPT
OAuth/Codex paths.
- Support the documented `medium` default and new `max` reasoning
effort.
- Cover model discovery, display names, Codex allowlisting, and
reasoning behavior.
This commit is contained in:
Johannes du Plessis
2026-07-09 11:31:49 -07:00
committed by GitHub
parent b0a209da3a
commit 4a806bc703
6 changed files with 56 additions and 8 deletions
@@ -594,6 +594,9 @@ source, model class, and request endpoint all differ. See
CODEX_MODELS: frozenset[str] = frozenset(
{
"gpt-5.6-luna",
"gpt-5.6-sol",
"gpt-5.6-terra",
"gpt-5.5",
"gpt-5.4",
"gpt-5.4-mini",
@@ -53,11 +53,14 @@ class ReasoningProviderConfig(NamedTuple):
OPENAI_EFFORTS: tuple[EffortLabel, ...] = ("none", "low", "medium", "high", "xhigh")
"""OpenAI GPT-5 effort labels for `reasoning.effort`.
"""OpenAI GPT-5 effort labels before GPT-5.6 for `reasoning.effort`.
See https://platform.openai.com/docs/guides/reasoning.
"""
OPENAI_56_EFFORTS: tuple[EffortLabel, ...] = (*OPENAI_EFFORTS, "max")
"""OpenAI GPT-5.6 effort labels for `reasoning.effort`."""
ANTHROPIC_EFFORTS: tuple[EffortLabel, ...] = ("low", "medium", "high", "xhigh", "max")
"""Anthropic `output_config.effort` labels for Opus 4.7+ and Sonnet 5.
@@ -132,17 +135,16 @@ _REASONING_KEYS: frozenset[str] = frozenset(
"""Runtime config keys that may already carry provider reasoning settings."""
def _openai_supported_efforts(_model: str) -> tuple[EffortLabel, ...]:
def _openai_supported_efforts(model: str) -> tuple[EffortLabel, ...]:
"""Return OpenAI reasoning effort levels."""
return OPENAI_EFFORTS
return OPENAI_56_EFFORTS if _has_version(model, "gpt-5.6") else OPENAI_EFFORTS
def _openai_default_effort(model: str) -> EffortLabel | None:
"""Return the OpenAI default reasoning effort when known."""
# Only gpt-5.5 documents `medium` as its default; other/newer gpt-5 variants
# fall through to `None` until their default is confirmed against
# https://platform.openai.com/docs/guides/reasoning.
return "medium" if model.startswith("gpt-5.5") else None
if _has_version(model, "gpt-5.5") or _has_version(model, "gpt-5.6"):
return "medium"
return None
def _openai_model_params(effort: str) -> dict[str, Any]:
@@ -89,11 +89,17 @@ _RECOMMENDED_MODELS: dict[str, str] = {
"openai:gpt-5.4-pro": "GPT-5.4 Pro",
"openai:gpt-5.5": "GPT-5.5",
"openai:gpt-5.5-pro": "GPT-5.5 Pro",
"openai:gpt-5.6-luna": "GPT-5.6 Luna",
"openai:gpt-5.6-sol": "GPT-5.6 Sol",
"openai:gpt-5.6-terra": "GPT-5.6 Terra",
"openai_codex:gpt-5.2": "GPT-5.2",
"openai_codex:gpt-5.3-codex": "GPT-5.3 Codex",
"openai_codex:gpt-5.4": "GPT-5.4",
"openai_codex:gpt-5.4-mini": "GPT-5.4 mini",
"openai_codex:gpt-5.5": "GPT-5.5",
"openai_codex:gpt-5.6-luna": "GPT-5.6 Luna",
"openai_codex:gpt-5.6-sol": "GPT-5.6 Sol",
"openai_codex:gpt-5.6-terra": "GPT-5.6 Terra",
"openrouter:anthropic/claude-opus-4.6": "Claude Opus 4.6",
"openrouter:anthropic/claude-opus-4.7": "Claude Opus 4.7",
"openrouter:anthropic/claude-opus-4.7-fast": "Claude Opus 4.7 Fast",
@@ -5815,6 +5815,13 @@ class TestCodexProviderMirror:
`openai_codex`; other openai models are not mirrored.
"""
def test_gpt_56_models_are_allowlisted(self) -> None:
assert {
"gpt-5.6-luna",
"gpt-5.6-sol",
"gpt-5.6-terra",
} <= model_config.CODEX_MODELS
def test_available_models_mirror_codex_allowlist(self) -> None:
model_config.clear_caches()
available = model_config.get_available_models()
@@ -39,8 +39,25 @@ def _restore_settings() -> Iterator[None]:
[
("openai:gpt-5.5", ("none", "low", "medium", "high", "xhigh")),
("openai_codex:gpt-5.5", ("none", "low", "medium", "high", "xhigh")),
(
"openai:gpt-5.6-sol",
("none", "low", "medium", "high", "xhigh", "max"),
),
(
"openai:gpt-5.6-terra",
("none", "low", "medium", "high", "xhigh", "max"),
),
(
"openai:gpt-5.6-luna",
("none", "low", "medium", "high", "xhigh", "max"),
),
(
"openai_codex:gpt-5.6-sol",
("none", "low", "medium", "high", "xhigh", "max"),
),
# A generic (non-5.5) gpt-5 still gets the full OpenAI range.
("openai:gpt-5.4", ("none", "low", "medium", "high", "xhigh")),
("openai:gpt-5.60-sol", ("none", "low", "medium", "high", "xhigh")),
("anthropic:claude-opus-4-8", ("low", "medium", "high", "xhigh", "max")),
# Opus 4.7 is the first version documented for the full range; assert the
# named boundary directly rather than relying on 4.8 to exercise it.
@@ -97,8 +114,12 @@ def test_supported_efforts_for_model(model_spec: str, efforts: tuple[str, ...])
[
("openai:gpt-5.5", "medium"),
("openai_codex:gpt-5.5", "medium"),
# Only gpt-5.5 has a documented default; other gpt-5 variants are None.
("openai:gpt-5.6-sol", "medium"),
("openai:gpt-5.6-terra", "medium"),
("openai:gpt-5.6-luna", "medium"),
("openai_codex:gpt-5.6-sol", "medium"),
("openai:gpt-5.4", None),
("openai:gpt-5.60-sol", None),
("anthropic:claude-opus-4-8", "high"),
("anthropic:claude-opus-4-7", "high"),
("anthropic:claude-sonnet-4-6", "high"),
@@ -123,6 +144,9 @@ def test_model_params_for_effort_maps_provider_kwargs() -> None:
assert model_params_for_effort("openai:gpt-5.5", "high") == {
"reasoning": {"effort": "high", "summary": "auto"}
}
assert model_params_for_effort("openai:gpt-5.6-sol", "max") == {
"reasoning": {"effort": "max", "summary": "auto"}
}
assert model_params_for_effort("anthropic:claude-opus-4-8", "xhigh") == {
"thinking": {"type": "adaptive", "display": "summarized"},
"output_config": {"effort": "xhigh"},
@@ -2255,6 +2255,12 @@ class TestGetModelDisplayName:
("spec", "name"),
[
("fireworks:accounts/fireworks/models/kimi-k2p7-code", "Kimi K2.7 Code"),
("openai:gpt-5.6-luna", "GPT-5.6 Luna"),
("openai:gpt-5.6-sol", "GPT-5.6 Sol"),
("openai:gpt-5.6-terra", "GPT-5.6 Terra"),
("openai_codex:gpt-5.6-luna", "GPT-5.6 Luna"),
("openai_codex:gpt-5.6-sol", "GPT-5.6 Sol"),
("openai_codex:gpt-5.6-terra", "GPT-5.6 Terra"),
("xai:grok-4.5", "Grok 4.5"),
],
)