diff --git a/src/askui/models/shared/thinking.py b/src/askui/models/shared/thinking.py index b668a12b..5fe1f94b 100644 --- a/src/askui/models/shared/thinking.py +++ b/src/askui/models/shared/thinking.py @@ -159,10 +159,17 @@ def make_thinking_settings( **make_thinking_settings(self._vlm_provider.model_id), ) - Models that support adaptive thinking get ``thinking={"type": "adaptive"}`` - (with ``effort`` sent via ``provider_options["output_config"]`` when given); - older models get a fixed token budget of - ``thinking={"type": "enabled", "budget_tokens": 2048}`` and ignore ``effort``. + Models that support adaptive thinking get + ``thinking={"type": "adaptive", "display": "summarized"}`` (with ``effort`` + sent via ``provider_options["output_config"]`` when given); older models + get a fixed token budget of + ``thinking={"type": "enabled", "budget_tokens": 2048}`` and ignore + ``effort``. ``display`` is set explicitly because the newest adaptive + models (Sonnet 5 generation onward) default it to ``"omitted"``, which + returns thinking blocks whose text is EMPTY while the full thinking + tokens are still billed — reasoning silently disappears from reports and + logs. ``"summarized"`` restores the visible text at no extra cost (billing + is identical for both display modes). Args: model_id (str): The model identifier (bare or gateway-prefixed). @@ -176,7 +183,9 @@ def make_thinking_settings( when applicable, ``provider_options``). """ if uses_adaptive_thinking(model_id): - settings: dict[str, Any] = {"thinking": {"type": "adaptive"}} + settings: dict[str, Any] = { + "thinking": {"type": "adaptive", "display": "summarized"} + } if effort is not None: settings["provider_options"] = {"output_config": {"effort": effort}} return settings diff --git a/tests/unit/models/test_thinking.py b/tests/unit/models/test_thinking.py index 58682494..7249d82d 100644 --- a/tests/unit/models/test_thinking.py +++ b/tests/unit/models/test_thinking.py @@ -50,7 +50,9 @@ @pytest.mark.parametrize("model_id", _ADAPTIVE_MODELS) def test_adaptive_models_use_adaptive_thinking(model_id: str) -> None: assert uses_adaptive_thinking(model_id) is True - assert make_thinking_settings(model_id) == {"thinking": {"type": "adaptive"}} + assert make_thinking_settings(model_id) == { + "thinking": {"type": "adaptive", "display": "summarized"} + } @pytest.mark.parametrize("model_id", _BUDGET_MODELS) @@ -63,7 +65,7 @@ def test_other_models_use_budget_tokens(model_id: str) -> None: def test_effort_is_added_via_provider_options_for_adaptive_models() -> None: assert make_thinking_settings("claude-sonnet-5", effort="high") == { - "thinking": {"type": "adaptive"}, + "thinking": {"type": "adaptive", "display": "summarized"}, "provider_options": {"output_config": {"effort": "high"}}, } @@ -139,6 +141,6 @@ def test_non_thinking_settings_omit_thinking_on_always_on_models() -> None: def test_effort_supports_xhigh() -> None: assert make_thinking_settings("claude-opus-4-8", effort="xhigh") == { - "thinking": {"type": "adaptive"}, + "thinking": {"type": "adaptive", "display": "summarized"}, "provider_options": {"output_config": {"effort": "xhigh"}}, }