feat(anthropic): support adaptive thinking mode (#36293)

Thank you!
This commit is contained in:
vladpostoaca-stripe
2026-03-29 02:53:55 +02:00
committed by GitHub
parent 4d9842da67
commit fe2f105ce7
2 changed files with 67 additions and 3 deletions

View File

@@ -29,6 +29,7 @@ from langchain_anthropic.chat_models import (
_format_messages,
_is_builtin_tool,
_merge_messages,
_thinking_in_params,
convert_to_anthropic_tool,
)
@@ -2675,6 +2676,57 @@ def test_bind_tools_drops_forced_tool_choice_when_thinking_enabled() -> None:
assert len(w) == 1
def test_bind_tools_drops_forced_tool_choice_when_adaptive_thinking() -> None:
"""Adaptive thinking has the same forced tool_choice restriction as enabled."""
chat_model = ChatAnthropic(
model=MODEL_NAME,
anthropic_api_key="secret-api-key",
thinking={"type": "adaptive"},
)
# tool_choice="any" should be dropped with warning
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always")
result = chat_model.bind_tools([GetWeather], tool_choice="any")
assert "tool_choice" not in cast("RunnableBinding", result).kwargs
assert len(w) == 1
assert "thinking is enabled" in str(w[0].message)
# tool_choice="auto" should NOT be dropped (auto is allowed)
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always")
result = chat_model.bind_tools([GetWeather], tool_choice="auto")
assert cast("RunnableBinding", result).kwargs["tool_choice"] == {"type": "auto"}
assert len(w) == 0
# tool_choice=specific tool name should be dropped with warning
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always")
result = chat_model.bind_tools([GetWeather], tool_choice="GetWeather")
assert "tool_choice" not in cast("RunnableBinding", result).kwargs
assert len(w) == 1
# tool_choice=dict with type "tool" should be dropped with warning
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always")
result = chat_model.bind_tools(
[GetWeather],
tool_choice={"type": "tool", "name": "GetWeather"},
)
assert "tool_choice" not in cast("RunnableBinding", result).kwargs
assert len(w) == 1
# tool_choice=dict with type "any" should also be dropped
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always")
result = chat_model.bind_tools(
[GetWeather],
tool_choice={"type": "any"},
)
assert "tool_choice" not in cast("RunnableBinding", result).kwargs
assert len(w) == 1
def test_bind_tools_keeps_forced_tool_choice_when_thinking_disabled() -> None:
"""When thinking is not enabled, forced tool_choice should pass through."""
chat_model = ChatAnthropic(
@@ -2703,3 +2755,12 @@ def test_bind_tools_keeps_forced_tool_choice_when_thinking_disabled() -> None:
)
result = chat_model_disabled.bind_tools([GetWeather], tool_choice="any")
assert cast("RunnableBinding", result).kwargs["tool_choice"] == {"type": "any"}
def test_thinking_in_params_recognizes_adaptive() -> None:
"""_thinking_in_params should recognize both enabled and adaptive types."""
assert _thinking_in_params({"thinking": {"type": "enabled", "budget_tokens": 5000}})
assert _thinking_in_params({"thinking": {"type": "adaptive"}})
assert not _thinking_in_params({"thinking": {"type": "disabled"}})
assert not _thinking_in_params({"thinking": {}})
assert not _thinking_in_params({})