"""Provider-neutral reasoning intent.""" from __future__ import annotations from dataclasses import dataclass from enum import StrEnum class ReasoningControl(StrEnum): """Whether a request explicitly controls reasoning computation.""" DEFAULT = "default" OFF = "off" ON = "on" class ReasoningEffort(StrEnum): """Named reasoning effort understood at the FCC application boundary.""" MINIMAL = "minimal" LOW = "low" MEDIUM = "medium" HIGH = "high" XHIGH = "xhigh" MAX = "max" @property def budget_tokens(self) -> int: """Return FCC's numeric token budget for this effort.""" return _EFFORT_BUDGET_TOKENS[self] _EFFORT_BUDGET_TOKENS = { ReasoningEffort.MINIMAL: 512, ReasoningEffort.LOW: 512, ReasoningEffort.MEDIUM: 1_024, ReasoningEffort.HIGH: 2_048, ReasoningEffort.XHIGH: 4_096, ReasoningEffort.MAX: 8_192, } @dataclass(frozen=True, slots=True) class ReasoningPolicy: """Resolved client and configuration intent passed to one provider. ``control`` and ``effort`` remain independent because clients may set an overall effort while separately disabling extended thinking. Providers translate the representable subset without changing the original intent. """ control: ReasoningControl = ReasoningControl.DEFAULT effort: ReasoningEffort | None = None budget_tokens: int | None = None def __post_init__(self) -> None: if self.budget_tokens is not None and ( not isinstance(self.budget_tokens, int) or isinstance(self.budget_tokens, bool) or self.budget_tokens <= 0 ): raise ValueError("Reasoning budget must be a positive integer.") if self.budget_tokens is not None and self.control is not ReasoningControl.ON: raise ValueError("A reasoning budget requires reasoning control to be on.") @classmethod def provider_default(cls) -> "ReasoningPolicy": """Leave reasoning computation to the provider.""" return cls() @classmethod def off(cls) -> "ReasoningPolicy": """Explicitly disable reasoning computation and output.""" return cls(control=ReasoningControl.OFF) @classmethod def on( cls, *, effort: ReasoningEffort | None = None, budget_tokens: int | None = None, ) -> "ReasoningPolicy": """Explicitly enable reasoning with optional client controls.""" return cls( control=ReasoningControl.ON, effort=effort, budget_tokens=budget_tokens, ) @property def output_enabled(self) -> bool: """Return whether provider reasoning may be exposed to the client.""" return self.control is not ReasoningControl.OFF @property def requests_reasoning(self) -> bool: """Return whether the request explicitly asks the provider to reason.""" return self.control is not ReasoningControl.OFF and ( self.control is ReasoningControl.ON or self.effort is not None or self.budget_tokens is not None ) @property def numeric_budget_tokens(self) -> int | None: """Express this intent as an exact or FCC-mapped numeric budget.""" if self.control is ReasoningControl.OFF: return None if self.budget_tokens is not None: return self.budget_tokens if self.effort is None: return None return self.effort.budget_tokens DEFAULT_REASONING_POLICY = ReasoningPolicy.provider_default()