From 9d50e90f6777eca8776bc4437bf625f6c3530ca3 Mon Sep 17 00:00:00 2001 From: Patrick Buckley Date: Thu, 28 May 2026 19:04:20 -0700 Subject: [PATCH] feat(providers): add Claude Opus 4.8 model support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Register `claude-opus-4-8` in the Anthropic capability table. Opus 4.8 shares Opus 4.7's request/response surface exactly — adaptive-thinking only (`budget_tokens` rejected), sampling params removed, the low/medium/high/xhigh/max effort levels, `thinking.display` defaulting to omitted, 1M context, and 128K output — so the entry is a verbatim copy of the 4.7 row. `_lookup_capabilities` longest-prefix matching then resolves date-suffixed ids (e.g. `claude-opus-4-8-20260601`) without colliding with the 4.7 key. No provider code paths change: the existing 4.7 handling already covers all of 4.8's behavior. Models are selected via config.toml / the admin ConfigStore UI, so there is no catalog or dropdown to update. - _anthropic.py: new claude-opus-4-8 capability entry + effort comment - tests/test_providers.py: opus 4.8 bare + dated capability tests - turnstone.example.toml: bump the showcased model example to 4.8 --- tests/test_providers.py | 27 ++++++++++++++++++++++++++ turnstone.example.toml | 2 +- turnstone/core/providers/_anthropic.py | 16 ++++++++++++++- 3 files changed, 43 insertions(+), 2 deletions(-) diff --git a/tests/test_providers.py b/tests/test_providers.py index c658ebbd..2cef427f 100644 --- a/tests/test_providers.py +++ b/tests/test_providers.py @@ -1265,6 +1265,33 @@ class TestAnthropicHelpers: assert caps.token_param == "max_tokens" assert caps.thinking_mode == "adaptive" + def test_capabilities_opus_4_8(self) -> None: + from turnstone.core.providers._anthropic import AnthropicProvider + + provider = AnthropicProvider() + caps = provider.get_capabilities("claude-opus-4-8") + assert caps.context_window == 1000000 + assert caps.max_output_tokens == 128000 + assert caps.thinking_mode == "adaptive" + assert caps.supports_effort is True + assert "xhigh" in caps.effort_levels + assert "max" in caps.effort_levels + assert caps.supports_temperature is False + assert caps.thinking_display == "summarized" + assert caps.supports_web_search is True + assert caps.supports_tool_search is True + assert caps.supports_vision is True + assert caps.supports_reasoning_replay is True + + def test_capabilities_opus_4_8_dated(self) -> None: + from turnstone.core.providers._anthropic import AnthropicProvider + + provider = AnthropicProvider() + caps = provider.get_capabilities("claude-opus-4-8-20260601") + assert caps.context_window == 1000000 + assert caps.supports_temperature is False + assert caps.thinking_display == "summarized" + def test_capabilities_opus_4_7(self) -> None: from turnstone.core.providers._anthropic import AnthropicProvider diff --git a/turnstone.example.toml b/turnstone.example.toml index 3b3d9aa1..5c5b976f 100644 --- a/turnstone.example.toml +++ b/turnstone.example.toml @@ -54,7 +54,7 @@ # supports_web_search = false # # [models.claude] -# name = "claude-opus-4-7" +# name = "claude-opus-4-8" # provider = "anthropic" # --- Database (turnstone, node, console) --- diff --git a/turnstone/core/providers/_anthropic.py b/turnstone/core/providers/_anthropic.py index 063a46c8..c78daf76 100644 --- a/turnstone/core/providers/_anthropic.py +++ b/turnstone/core/providers/_anthropic.py @@ -85,6 +85,20 @@ _ANTHROPIC_DEFAULT = ModelCapabilities( ) _ANTHROPIC_CAPABILITIES: dict[str, ModelCapabilities] = { + "claude-opus-4-8": ModelCapabilities( + context_window=1000000, + max_output_tokens=128000, + token_param="max_tokens", + thinking_mode="adaptive", + supports_effort=True, + effort_levels=("low", "medium", "high", "xhigh", "max"), + supports_web_search=True, + supports_tool_search=True, + supports_vision=True, + supports_temperature=False, + thinking_display="summarized", + supports_reasoning_replay=True, + ), "claude-opus-4-7": ModelCapabilities( context_window=1000000, max_output_tokens=128000, @@ -311,7 +325,7 @@ class AnthropicProvider: kwargs["tools"] = anthropic_tools kwargs.update(thinking_params) - # Effort param for models that support it (Opus 4.7, Opus 4.6, Sonnet 4.6, Opus 4.5) + # Effort param for models that support it (Opus 4.8, Opus 4.7, Opus 4.6, Sonnet 4.6, Opus 4.5) if caps.supports_effort and reasoning_effort: effort = _map_reasoning_to_effort(reasoning_effort, caps.effort_levels) if effort: