LastNoob's picture
Make reasoning policy provider-neutral and client-aware (#1148)
dc04eee unverified
Raw
History Blame Contribute Delete
3.19 kB
"""Resolve client reasoning input and FCC configuration exactly once."""
from collections.abc import Mapping
from typing import Any
from free_claude_code.config.reasoning import ReasoningPreference
from free_claude_code.core.anthropic.models import MessagesRequest, ThinkingConfig
from free_claude_code.core.reasoning import (
ReasoningControl,
ReasoningEffort,
ReasoningPolicy,
)
def resolve_reasoning_policy(
request: MessagesRequest,
preference: ReasoningPreference,
) -> ReasoningPolicy:
"""Apply one resolved configuration preference to the client request."""
if preference is ReasoningPreference.INHERIT:
raise ValueError("Reasoning preference must be resolved before application.")
if preference is ReasoningPreference.OFF:
return ReasoningPolicy.off()
if preference is not ReasoningPreference.CLIENT:
return ReasoningPolicy.on(effort=ReasoningEffort(preference.value))
return client_reasoning_policy(request)
def client_reasoning_policy(request: MessagesRequest) -> ReasoningPolicy:
"""Return the lossless reasoning intent expressed by one client request."""
budget_tokens = _positive_budget(request.thinking)
thinking_control = _thinking_control(
request.thinking,
budget_tokens=budget_tokens,
)
effort, effort_disables = _output_effort(request.output_config)
if effort_disables:
return ReasoningPolicy.off()
if thinking_control is ReasoningControl.OFF:
return ReasoningPolicy(
control=ReasoningControl.OFF,
effort=effort,
)
if thinking_control is ReasoningControl.ON or budget_tokens is not None:
return ReasoningPolicy.on(
effort=effort,
budget_tokens=budget_tokens,
)
return ReasoningPolicy(
control=ReasoningControl.DEFAULT,
effort=effort,
)
def _thinking_control(
thinking: ThinkingConfig | None,
*,
budget_tokens: int | None,
) -> ReasoningControl:
if thinking is None:
return ReasoningControl.DEFAULT
if thinking.type == "disabled" or (
"enabled" in thinking.model_fields_set and thinking.enabled is False
):
return ReasoningControl.OFF
if (
thinking.type in {"adaptive", "enabled"}
or ("enabled" in thinking.model_fields_set and thinking.enabled is True)
or budget_tokens is not None
):
return ReasoningControl.ON
return ReasoningControl.DEFAULT
def _output_effort(value: Any) -> tuple[ReasoningEffort | None, bool]:
if not isinstance(value, Mapping):
return None, False
raw = value.get("effort")
if not isinstance(raw, str):
return None, False
normalized = raw.strip().lower()
if normalized == "none":
return None, True
try:
return ReasoningEffort(normalized), False
except ValueError:
return None, False
def _positive_budget(thinking: ThinkingConfig | None) -> int | None:
if thinking is None:
return None
value = thinking.budget_tokens
if isinstance(value, int) and not isinstance(value, bool) and value > 0:
return value
return None