3838 UserPromptPart ,
3939)
4040from ..profiles import ModelProfileSpec
41- from ..profiles .anthropic import models_that_support_json_schema_output
41+ from ..profiles .anthropic import ANTHROPIC_MODELS_THAT_SUPPORT_JSON_SCHEMA_OUTPUT
4242from ..providers import Provider , infer_provider
4343from ..providers .anthropic import AsyncAnthropicClient
4444from ..settings import ModelSettings , merge_model_settings
@@ -311,14 +311,15 @@ def prepare_request(
311311 )
312312
313313 if model_request_parameters .output_mode == 'native' :
314- if model_request_parameters .output_object is None : # pragma: no cover
315- raise UserError ('Unreachable code: can never set `output_type=NativeOutput(None)`.' )
314+ assert model_request_parameters .output_object is not None
316315 if model_request_parameters .output_object .strict is False :
317- raise UserError ('Cannot use `output_type=NativeOutput(...)` with `strict=False`.' )
316+ raise UserError (
317+ 'Setting `strict=False` on `output_type=NativeOutput(...)` is not allowed for Anthropic models.'
318+ )
318319 if not self .profile .supports_json_schema_output :
319320 raise UserError (
320321 f'Model { self .model_name } does not support native output. Use `output_type=PromptedOutput(...)` instead.'
321- f'Models that support native output include: { models_that_support_json_schema_output } .'
322+ f'Models that support native output include: { ANTHROPIC_MODELS_THAT_SUPPORT_JSON_SCHEMA_OUTPUT } .'
322323 )
323324 model_request_parameters = replace (
324325 model_request_parameters , output_object = replace (model_request_parameters .output_object , strict = True )
@@ -365,11 +366,11 @@ async def _messages_create(
365366 system_prompt , anthropic_messages = await self ._map_message (messages , model_request_parameters , model_settings )
366367
367368 output_format = self ._native_output_format (model_request_parameters )
368- betas_set = self ._get_betas_set (tools , model_request_parameters )
369- betas_set .update (builtin_tool_betas )
369+ betas = self ._get_betas_set (tools , model_request_parameters )
370+ betas .update (builtin_tool_betas )
370371
371372 try :
372- betas , extra_headers = self ._prepare_betas_and_headers (betas_set , model_settings )
373+ betas , extra_headers = self ._prepare_betas_and_headers (betas , model_settings )
373374
374375 return await self .client .beta .messages .create (
375376 max_tokens = model_settings .get ('max_tokens' , 4096 ),
@@ -380,7 +381,7 @@ async def _messages_create(
380381 tool_choice = tool_choice or OMIT ,
381382 mcp_servers = mcp_servers or OMIT ,
382383 output_format = output_format or OMIT ,
383- betas = betas or OMIT ,
384+ betas = sorted ( betas ) or OMIT ,
384385 stream = stream ,
385386 thinking = model_settings .get ('anthropic_thinking' , OMIT ),
386387 stop_sequences = model_settings .get ('stop_sequences' , OMIT ),
@@ -416,11 +417,11 @@ async def _messages_count_tokens(
416417 system_prompt , anthropic_messages = await self ._map_message (messages , model_request_parameters , model_settings )
417418
418419 output_format = self ._native_output_format (model_request_parameters )
419- betas_set = self ._get_betas_set (tools , model_request_parameters )
420- betas_set .update (builtin_tool_betas )
420+ betas = self ._get_betas_set (tools , model_request_parameters )
421+ betas .update (builtin_tool_betas )
421422
422423 try :
423- betas , extra_headers = self ._prepare_betas_and_headers (betas_set , model_settings )
424+ betas , extra_headers = self ._prepare_betas_and_headers (betas , model_settings )
424425
425426 return await self .client .beta .messages .count_tokens (
426427 system = system_prompt or OMIT ,
@@ -429,7 +430,7 @@ async def _messages_count_tokens(
429430 tools = tools or OMIT ,
430431 tool_choice = tool_choice or OMIT ,
431432 mcp_servers = mcp_servers or OMIT ,
432- betas = betas or OMIT ,
433+ betas = sorted ( betas ) or OMIT ,
433434 output_format = output_format or OMIT ,
434435 thinking = model_settings .get ('anthropic_thinking' , OMIT ),
435436 timeout = model_settings .get ('timeout' , NOT_GIVEN ),
@@ -578,7 +579,7 @@ def _add_builtin_tools(
578579 if 'memory' not in model_request_parameters .tool_defs :
579580 raise UserError ("Built-in `MemoryTool` requires a 'memory' tool to be defined." )
580581 # Replace the memory tool definition with the built-in memory tool
581- tools = [tool for tool in tools if tool [ 'name' ] != 'memory' ]
582+ tools = [tool for tool in tools if tool . get ( 'name' ) != 'memory' ]
582583 tools .append (BetaMemoryTool20250818Param (name = 'memory' , type = 'memory_20250818' ))
583584 beta_features .add ('context-management-2025-06-27' )
584585 elif isinstance (tool , MCPServerTool ) and tool .url :
@@ -625,26 +626,19 @@ def _infer_tool_choice(
625626
626627 def _prepare_betas_and_headers (
627628 self , betas : set [str ], model_settings : AnthropicModelSettings
628- ) -> tuple [list [str ], dict [str , str ]]:
629+ ) -> tuple [set [str ], dict [str , str ]]:
629630 """Prepare beta features list and extra headers for API request.
630631
631- Handles merging custom anthropic-beta header from extra_headers into betas set
632- and ensuring User-Agent is set.
633-
634- Args:
635- betas: Set of beta feature strings (naturally deduplicated)
636- model_settings: Model settings containing extra_headers
637-
638- Returns:
639- Tuple of (betas list, extra_headers dict)
632+ Handles merging custom `anthropic-beta` header from `extra_headers` into betas set
633+ and ensuring `User-Agent` is set.
640634 """
641635 extra_headers = model_settings .get ('extra_headers' , {})
642636 extra_headers .setdefault ('User-Agent' , get_user_agent ())
643637
644638 if beta_header := extra_headers .pop ('anthropic-beta' , None ):
645639 betas .update ({stripped_beta for beta in beta_header .split (',' ) if (stripped_beta := beta .strip ())})
646640
647- return sorted ( betas ) , extra_headers
641+ return betas , extra_headers
648642
649643 async def _map_message ( # noqa: C901
650644 self ,
@@ -922,8 +916,7 @@ def _map_tool_definition(self, f: ToolDefinition) -> BetaToolParam:
922916 'description' : f .description or '' ,
923917 'input_schema' : f .parameters_json_schema ,
924918 }
925- if f .strict and self .profile .supports_json_schema_output : # pragma: no branch
926- # NOTE we could warn the user that the model doesn't support strict mode to nudge them into one that does
919+ if f .strict and self .profile .supports_json_schema_output :
927920 tool_param ['strict' ] = f .strict
928921 return tool_param
929922
@@ -1143,6 +1136,9 @@ def _map_server_tool_use_block(item: BetaServerToolUseBlock, provider_name: str)
11431136 )
11441137 elif item .name in ('web_fetch' , 'bash_code_execution' , 'text_editor_code_execution' ): # pragma: no cover
11451138 raise NotImplementedError (f'Anthropic built-in tool { item .name !r} is not currently supported.' )
1139+ elif item .name in ('tool_search_tool_regex' , 'tool_search_tool_bm25' ): # pragma: no cover
1140+ # TODO 0.75
1141+ raise NotImplementedError (f'Anthropic built-in tool { item .name !r} is not currently supported.' )
11461142 else :
11471143 assert_never (item .name )
11481144
0 commit comments