When using the anthropic provider with reasoning_effort set (i.e. adaptive thinking), tool_choice is intentionally not sent (_providers/anthropic.py around L410) — which is correct, since Anthropic's API disables extended thinking when tool_choice is {type: "tool"} or {type: "any"}; only auto yields both a thinking block and a tool call.
That means the only way to get both reasoning and a schema-guaranteed tool call on Anthropic is tool_choice: auto + strict: true on the tool definition (Anthropic supports this: https://docs.anthropic.com/en/docs/build-with-claude/tool-use#strict-tool-use). But AnthropicAPI.tool_params_for_tool_info hardcodes:
ToolParam(name=tool.name, description=tool.description, input_schema=json_schema_dump(tool.parameters))
with no strict field and no ToolInfo.options passthrough, so there's no way to opt in.
Repro (v0.3.220):
from inspect_ai.model import get_model, GenerateConfig
from inspect_ai.tool import ToolInfo, ToolParams, ToolFunction
from inspect_ai.util import json_schema
from pydantic import BaseModel
class Out(BaseModel):
reasoning: str
x: int
s = json_schema(Out)
tool = ToolInfo(
name="emit", description="emit",
parameters=ToolParams(properties=s.properties, required=s.required, additionalProperties=False),
)
m = get_model("anthropic/claude-sonnet-5", config=GenerateConfig(reasoning_effort="high"))
out = await m.generate("call emit with x=1", tools=[tool], tool_choice=ToolFunction(name="emit"))
# request sent has thinking:{type:adaptive}, tool_choice omitted (correctly),
# and the tool has no `strict` — so the model may return malformed/partial args
Proposed fix: honour ToolInfo.options["strict"] = True (or add a top-level ToolInfo.strict) in tool_params_for_tool_info, and drop minimum/maximum from input_schema when strict is set (Anthropic rejects those keywords under strict).
Happy to send a PR if this direction sounds right.
When using the anthropic provider with
reasoning_effortset (i.e. adaptive thinking),tool_choiceis intentionally not sent (_providers/anthropic.pyaround L410) — which is correct, since Anthropic's API disables extended thinking whentool_choiceis{type: "tool"}or{type: "any"}; onlyautoyields both a thinking block and a tool call.That means the only way to get both reasoning and a schema-guaranteed tool call on Anthropic is
tool_choice: auto+strict: trueon the tool definition (Anthropic supports this: https://docs.anthropic.com/en/docs/build-with-claude/tool-use#strict-tool-use). ButAnthropicAPI.tool_params_for_tool_infohardcodes:with no
strictfield and noToolInfo.optionspassthrough, so there's no way to opt in.Repro (v0.3.220):
Proposed fix: honour
ToolInfo.options["strict"] = True(or add a top-levelToolInfo.strict) intool_params_for_tool_info, and dropminimum/maximumfrominput_schemawhen strict is set (Anthropic rejects those keywords under strict).Happy to send a PR if this direction sounds right.