@@ -121,6 +121,16 @@ class AnthropicTool(TypedDict):
121121 cache_control : NotRequired [dict [str , str ]]
122122
123123
124+ # Some tool types require specific beta headers to be enabled
125+ # Mapping of tool type patterns to required beta headers
126+ _TOOL_TYPE_TO_BETA : dict [str , str ] = {
127+ "web_fetch_20250910" : "web-fetch-2025-09-10" ,
128+ "code_execution_20250522" : "code-execution-2025-05-22" ,
129+ "code_execution_20250825" : "code-execution-2025-08-25" ,
130+ "memory_20250818" : "context-management-2025-06-27" ,
131+ }
132+
133+
124134def _is_builtin_tool (tool : Any ) -> bool :
125135 """Check if a tool is a built-in Anthropic tool.
126136
@@ -1393,12 +1403,11 @@ class Joke(BaseModel):
13931403
13941404 ??? example "Web fetch (beta)"
13951405
1396- ```python hl_lines="5 8-12 "
1406+ ```python hl_lines="7-11 "
13971407 from langchain_anthropic import ChatAnthropic
13981408
13991409 model = ChatAnthropic(
14001410 model="claude-3-5-haiku-20241022",
1401- betas=["web-fetch-2025-09-10"], # Enable web fetch beta
14021411 )
14031412
14041413 tool = {
@@ -1411,16 +1420,19 @@ class Joke(BaseModel):
14111420 response = model_with_tools.invoke("Please analyze the content at https://example.com/article")
14121421 ```
14131422
1423+ !!! note "Automatic beta header"
1424+
1425+ The required `web-fetch-2025-09-10` beta header is automatically
1426+ appended to the request when using the `web_fetch_20250910` tool type.
1427+ You don't need to manually specify it in the `betas` parameter.
1428+
14141429 See the [Claude docs](https://platform.claude.com/docs/en/agents-and-tools/tool-use/web-fetch-tool)
14151430 for more info.
14161431
14171432 ??? example "Code execution"
14181433
1419- ```python hl_lines="3 6-9"
1420- model = ChatAnthropic(
1421- model="claude-sonnet-4-5-20250929",
1422- betas=["code-execution-2025-05-22"], # Enable code execution beta
1423- )
1434+ ```python hl_lines="3-6"
1435+ model = ChatAnthropic(model="claude-sonnet-4-5-20250929")
14241436
14251437 tool = {
14261438 "type": "code_execution_20250522",
@@ -1433,18 +1445,21 @@ class Joke(BaseModel):
14331445 )
14341446 ```
14351447
1448+ !!! note "Automatic beta header"
1449+
1450+ The required `code-execution-2025-05-22` beta header is automatically
1451+ appended to the request when using the `code_execution_20250522` tool
1452+ type. You don't need to manually specify it in the `betas` parameter.
1453+
14361454 See the [Claude docs](https://platform.claude.com/docs/en/agents-and-tools/tool-use/code-execution-tool)
14371455 for more info.
14381456
14391457 ??? example "Memory tool"
14401458
1441- ```python hl_lines="5 8-11 "
1459+ ```python hl_lines="5-8 "
14421460 from langchain_anthropic import ChatAnthropic
14431461
1444- model = ChatAnthropic(
1445- model="claude-sonnet-4-5-20250929",
1446- betas=["context-management-2025-06-27"], # Enable context management beta
1447- )
1462+ model = ChatAnthropic(model="claude-sonnet-4-5-20250929")
14481463
14491464 tool = {
14501465 "type": "memory_20250818",
@@ -1455,6 +1470,12 @@ class Joke(BaseModel):
14551470 response = model_with_tools.invoke("What are my interests?")
14561471 ```
14571472
1473+ !!! note "Automatic beta header"
1474+
1475+ The required `context-management-2025-06-27` beta header is automatically
1476+ appended to the request when using the `memory_20250818` tool type.
1477+ You don't need to manually specify it in the `betas` parameter.
1478+
14581479 See the [Claude docs](https://platform.claude.com/docs/en/agents-and-tools/tool-use/memory-tool)
14591480 for more info.
14601481
@@ -1592,6 +1613,12 @@ class Joke(BaseModel):
15921613
15931614 Example: `#!python betas=["mcp-client-2025-04-04"]`
15941615 """
1616+ # Can also be passed in w/ model_kwargs, but having it as a param makes better devx
1617+ #
1618+ # Precedence order:
1619+ # 1. Call-time kwargs (e.g., llm.invoke(..., betas=[...]))
1620+ # 2. model_kwargs (e.g., ChatAnthropic(model_kwargs={"betas": [...]}))
1621+ # 3. Direct parameter (e.g., ChatAnthropic(betas=[...]))
15951622
15961623 model_kwargs : dict [str , Any ] = Field (default_factory = dict )
15971624
@@ -1842,21 +1869,74 @@ def _get_request_payload(
18421869 payload ["thinking" ] = self .thinking
18431870
18441871 if "response_format" in payload :
1872+ # response_format present when using agents.create_agent's ProviderStrategy
1873+ # ---
1874+ # ProviderStrategy converts to OpenAI-style format, which passes kwargs to
1875+ # ChatAnthropic, ending up in our payload
18451876 response_format = payload .pop ("response_format" )
18461877 if (
18471878 isinstance (response_format , dict )
18481879 and response_format .get ("type" ) == "json_schema"
18491880 and "schema" in response_format .get ("json_schema" , {})
18501881 ):
1851- # compat with langchain.agents.create_agent response_format, which is
1852- # an approximation of OpenAI format
18531882 response_format = cast (dict , response_format ["json_schema" ]["schema" ])
1883+ # Convert OpenAI-style response_format to Anthropic's output_format
18541884 payload ["output_format" ] = _convert_to_anthropic_output_format (
18551885 response_format
18561886 )
18571887
1858- if "output_format" in payload and not payload ["betas" ]:
1859- payload ["betas" ] = ["structured-outputs-2025-11-13" ]
1888+ if "output_format" in payload :
1889+ # Native structured output requires the structured outputs beta
1890+ if payload ["betas" ]:
1891+ if "structured-outputs-2025-11-13" not in payload ["betas" ]:
1892+ # Merge with existing betas
1893+ payload ["betas" ] = [
1894+ * payload ["betas" ],
1895+ "structured-outputs-2025-11-13" ,
1896+ ]
1897+ else :
1898+ payload ["betas" ] = ["structured-outputs-2025-11-13" ]
1899+
1900+ # Check if any tools have strict mode enabled
1901+ if "tools" in payload and isinstance (payload ["tools" ], list ):
1902+ has_strict_tool = any (
1903+ isinstance (tool , dict ) and tool .get ("strict" ) is True
1904+ for tool in payload ["tools" ]
1905+ )
1906+ if has_strict_tool :
1907+ # Strict tool use requires the structured outputs beta
1908+ if payload ["betas" ]:
1909+ if "structured-outputs-2025-11-13" not in payload ["betas" ]:
1910+ # Merge with existing betas
1911+ payload ["betas" ] = [
1912+ * payload ["betas" ],
1913+ "structured-outputs-2025-11-13" ,
1914+ ]
1915+ else :
1916+ payload ["betas" ] = ["structured-outputs-2025-11-13" ]
1917+
1918+ # Auto-append required betas for specific tool types
1919+ for tool in payload ["tools" ]:
1920+ if isinstance (tool , dict ) and "type" in tool :
1921+ tool_type = tool ["type" ]
1922+ if tool_type in _TOOL_TYPE_TO_BETA :
1923+ required_beta = _TOOL_TYPE_TO_BETA [tool_type ]
1924+ if payload ["betas" ]:
1925+ # Append to existing betas if not already present
1926+ if required_beta not in payload ["betas" ]:
1927+ payload ["betas" ] = [* payload ["betas" ], required_beta ]
1928+ else :
1929+ payload ["betas" ] = [required_beta ]
1930+
1931+ # Auto-append required beta for mcp_servers
1932+ if payload .get ("mcp_servers" ):
1933+ required_beta = "mcp-client-2025-11-20"
1934+ if payload ["betas" ]:
1935+ # Append to existing betas if not already present
1936+ if required_beta not in payload ["betas" ]:
1937+ payload ["betas" ] = [* payload ["betas" ], required_beta ]
1938+ else :
1939+ payload ["betas" ] = [required_beta ]
18601940
18611941 return {k : v for k , v in payload .items () if v is not None }
18621942
@@ -2300,17 +2380,13 @@ class GetPrice(BaseModel):
23002380 - Claude Sonnet 4.5 or Opus 4.1
23012381 - `langchain-anthropic>=1.1.0`
23022382
2303- To enable strict tool use:
2304-
2305- 1. Specify the `structured-outputs-2025-11-13` beta header
2306- 2. Specify `strict=True` when calling `bind_tools`
2383+ To enable strict tool use, specify `strict=True` when calling `bind_tools`.
23072384
2308- ```python hl_lines="5 12 "
2385+ ```python hl_lines="11 "
23092386 from langchain_anthropic import ChatAnthropic
23102387
23112388 model = ChatAnthropic(
23122389 model="claude-sonnet-4-5",
2313- betas=["structured-outputs-2025-11-13"],
23142390 )
23152391
23162392 def get_weather(location: str) -> str:
@@ -2320,6 +2396,12 @@ def get_weather(location: str) -> str:
23202396 model_with_tools = model.bind_tools([get_weather], strict=True)
23212397 ```
23222398
2399+ !!! note "Automatic beta header"
2400+
2401+ The required `structured-outputs-2025-11-13` beta header is
2402+ automatically appended to the request when using `strict=True`, so you
2403+ don't need to manually specify it in the `betas` parameter.
2404+
23232405 See LangChain [docs](https://docs.langchain.com/oss/python/integrations/chat/anthropic#strict-tool-use)
23242406 for more detail.
23252407 """ # noqa: E501
@@ -2513,19 +2595,15 @@ class AnswerWithJustification(BaseModel):
25132595 - Claude Sonnet 4.5 or Opus 4.1
25142596 - `langchain-anthropic>=1.1.0`
25152597
2516- To enable native structured output:
2598+ To enable native structured output, specify `method="json_schema"` when
2599+ calling `with_structured_output`. (Under the hood, LangChain will
2600+ append the required `structured-outputs-2025-11-13` beta header)
25172601
2518- 1. Specify the `structured-outputs-2025-11-13` beta header
2519- 2. Specify `method="json_schema"` when calling `with_structured_output`
2520-
2521- ```python hl_lines="6 16"
2602+ ```python hl_lines="13"
25222603 from langchain_anthropic import ChatAnthropic
25232604 from pydantic import BaseModel, Field
25242605
2525- model = ChatAnthropic(
2526- model="claude-sonnet-4-5",
2527- betas=["structured-outputs-2025-11-13"],
2528- )
2606+ model = ChatAnthropic(model="claude-sonnet-4-5")
25292607
25302608 class Movie(BaseModel):
25312609 \" \" \" A movie with details.\" \" \"
@@ -2713,8 +2791,7 @@ def convert_to_anthropic_tool(
27132791
27142792 !!! note
27152793
2716- Requires Claude Sonnet 4.5 or Opus 4.1 and the
2717- `structured-outputs-2025-11-13` beta header.
2794+ Requires Claude Sonnet 4.5 or Opus 4.1.
27182795
27192796 Returns:
27202797 An Anthropic tool definition dict.
0 commit comments