Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion src/celeste/modalities/text/providers/anthropic/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@
streaming=True,
parameter_constraints={
Parameter.MAX_TOKENS: Range(min=1, max=64000),
TextParameter.THINKING_BUDGET: Range(min=-1, max=32000),
TextParameter.THINKING_BUDGET: Range(min=1024, max=32000),
TextParameter.OUTPUT_SCHEMA: Schema(),
TextParameter.TOOLS: ToolSupport(tools=[WebSearch]),
TextParameter.TOOL_CHOICE: ToolChoiceSupport(),
Expand Down Expand Up @@ -217,3 +217,15 @@
},
),
]

# Models that support web_search dynamic filtering (web_search_20260209); others use basic.
DYNAMIC_FILTERING_MODELS = frozenset(
{
"claude-fable-5",
"claude-opus-4-8",
"claude-opus-4-7",
"claude-opus-4-6",
"claude-sonnet-5",
"claude-sonnet-4-6",
}
)
17 changes: 16 additions & 1 deletion src/celeste/modalities/text/providers/anthropic/parameters.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
from celeste.types import TextContent

from ...parameters import TextParameter
from .models import DYNAMIC_FILTERING_MODELS


class TemperatureMapper(_TemperatureMapper):
Expand Down Expand Up @@ -80,10 +81,24 @@ class OutputSchemaMapper(_OutputFormatMapper):


class ToolsMapper(_ToolsMapper):
"""Map tools to Anthropic's tools parameter."""
"""Map tools to Anthropic's tools parameter (web_search version per model)."""

name = TextParameter.TOOLS

def map(
self,
request: dict[str, Any],
value: object,
model: Model,
) -> dict[str, Any]:
"""Upgrade web_search to dynamic filtering (web_search_20260209) where the model supports it."""
request = super().map(request, value, model)
if model.id in DYNAMIC_FILTERING_MODELS:
for tool in request.get("tools", []):
if tool.get("name") == "web_search":
tool["type"] = "web_search_20260209"
return request


class ToolChoiceMapper(_ToolChoiceMapper):
"""Map tool_choice to Anthropic's tool_choice parameter."""
Expand Down
8 changes: 3 additions & 5 deletions src/celeste/providers/anthropic/messages/parameters.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,8 @@ def map(
class ThinkingLevelMapper(ParameterMapper[TextContent]):
"""Map thinking_level to adaptive thinking plus output_config.effort.

Emits {"thinking": {"type": "adaptive"}, "output_config": {"effort": <value>}}
where <value> is one of "low" | "medium" | "high" | "xhigh" | "max" — the
Messages API rejects an "effort" key inside the thinking object
("thinking.adaptive.effort: Extra inputs are not permitted").
display="summarized" so thinking summaries stream (API default "omitted" is empty).
effort goes in output_config, not the thinking object (the API rejects it there).
"""

def map(
Expand All @@ -90,7 +88,7 @@ def map(
validated_value = self._validate_value(value, model)
if validated_value is None:
return request
request["thinking"] = {"type": "adaptive"}
request["thinking"] = {"type": "adaptive", "display": "summarized"}
request.setdefault("output_config", {})["effort"] = validated_value
return request

Expand Down
Loading