diff --git a/litellm/_uuid.py b/litellm/_uuid.py index e9578b7287f..b68a1e4264f 100644 --- a/litellm/_uuid.py +++ b/litellm/_uuid.py @@ -1,10 +1,13 @@ """ Internal unified UUID helper. -Always uses fastuuid for performance. +Uses fastuuid for performance when installed, otherwise falls back to stdlib uuid. """ -import fastuuid as _uuid +try: + import fastuuid as _uuid +except ImportError: + import uuid as _uuid # Expose a module-like alias so callers can use: uuid.uuid4() uuid = _uuid @@ -13,3 +16,4 @@ uuid = _uuid def uuid4(): """Return a UUID4 using the selected backend.""" return uuid.uuid4() + diff --git a/litellm/litellm_core_utils/reasoning_effort_utils.py b/litellm/litellm_core_utils/reasoning_effort_utils.py index 5987392d070..7db390e46bd 100644 --- a/litellm/litellm_core_utils/reasoning_effort_utils.py +++ b/litellm/litellm_core_utils/reasoning_effort_utils.py @@ -1,22 +1,33 @@ -from typing import Literal +from typing import Literal, Optional from litellm.constants import ( DEFAULT_REASONING_EFFORT_HIGH_THINKING_BUDGET, DEFAULT_REASONING_EFFORT_LOW_THINKING_BUDGET, + DEFAULT_REASONING_EFFORT_MAX_THINKING_BUDGET, DEFAULT_REASONING_EFFORT_MEDIUM_THINKING_BUDGET, + DEFAULT_REASONING_EFFORT_MINIMAL_THINKING_BUDGET, + DEFAULT_REASONING_EFFORT_XHIGH_THINKING_BUDGET, ) -OpenAIStyleReasoningEffort = Literal["minimal", "low", "medium", "high"] +OpenAIStyleReasoningEffort = Literal[ + "minimal", "low", "medium", "high", "xhigh", "max" +] def reasoning_effort_from_thinking_budget( - budget_tokens: int, + budget_tokens: Optional[int], ) -> OpenAIStyleReasoningEffort: """Bucket an Anthropic ``thinking.budget_tokens`` into an OpenAI-style ``reasoning_effort`` using the shared ``DEFAULT_REASONING_EFFORT_*_THINKING_BUDGET`` thresholds, so every backend that translates a budget into an effort label reads the same numbers. """ + if budget_tokens is None or budget_tokens <= 0: + return "minimal" + if budget_tokens >= DEFAULT_REASONING_EFFORT_MAX_THINKING_BUDGET: + return "max" + if budget_tokens >= DEFAULT_REASONING_EFFORT_XHIGH_THINKING_BUDGET: + return "xhigh" if budget_tokens >= DEFAULT_REASONING_EFFORT_HIGH_THINKING_BUDGET: return "high" if budget_tokens >= DEFAULT_REASONING_EFFORT_MEDIUM_THINKING_BUDGET: @@ -24,3 +35,31 @@ def reasoning_effort_from_thinking_budget( if budget_tokens >= DEFAULT_REASONING_EFFORT_LOW_THINKING_BUDGET: return "low" return "minimal" + + +def thinking_budget_from_reasoning_effort( + reasoning_effort: Optional[str], +) -> int: + """Convert an OpenAI-style ``reasoning_effort`` string into a default + thinking token budget. + """ + if not reasoning_effort: + return DEFAULT_REASONING_EFFORT_MEDIUM_THINKING_BUDGET + + effort_lower = reasoning_effort.lower() + if effort_lower == "max": + return DEFAULT_REASONING_EFFORT_MAX_THINKING_BUDGET + if effort_lower == "xhigh": + return DEFAULT_REASONING_EFFORT_XHIGH_THINKING_BUDGET + if effort_lower == "high": + return DEFAULT_REASONING_EFFORT_HIGH_THINKING_BUDGET + if effort_lower == "medium": + return DEFAULT_REASONING_EFFORT_MEDIUM_THINKING_BUDGET + if effort_lower == "low": + return DEFAULT_REASONING_EFFORT_LOW_THINKING_BUDGET + if effort_lower == "minimal": + return DEFAULT_REASONING_EFFORT_MINIMAL_THINKING_BUDGET + if effort_lower == "none": + return 0 + return DEFAULT_REASONING_EFFORT_MEDIUM_THINKING_BUDGET + diff --git a/tests/test_litellm/test_reasoning_effort_utils.py b/tests/test_litellm/test_reasoning_effort_utils.py new file mode 100644 index 00000000000..35aafdf3ee9 --- /dev/null +++ b/tests/test_litellm/test_reasoning_effort_utils.py @@ -0,0 +1,39 @@ +""" +Unit tests for litellm_core_utils/reasoning_effort_utils.py. +""" + +from litellm.constants import ( + DEFAULT_REASONING_EFFORT_HIGH_THINKING_BUDGET, + DEFAULT_REASONING_EFFORT_LOW_THINKING_BUDGET, + DEFAULT_REASONING_EFFORT_MAX_THINKING_BUDGET, + DEFAULT_REASONING_EFFORT_MEDIUM_THINKING_BUDGET, + DEFAULT_REASONING_EFFORT_MINIMAL_THINKING_BUDGET, + DEFAULT_REASONING_EFFORT_XHIGH_THINKING_BUDGET, +) +from litellm.litellm_core_utils.reasoning_effort_utils import ( + reasoning_effort_from_thinking_budget, + thinking_budget_from_reasoning_effort, +) + + +def test_reasoning_effort_from_thinking_budget_levels(): + assert reasoning_effort_from_thinking_budget(None) == "minimal" + assert reasoning_effort_from_thinking_budget(0) == "minimal" + assert reasoning_effort_from_thinking_budget(-10) == "minimal" + assert reasoning_effort_from_thinking_budget(DEFAULT_REASONING_EFFORT_MINIMAL_THINKING_BUDGET) == "minimal" + assert reasoning_effort_from_thinking_budget(DEFAULT_REASONING_EFFORT_LOW_THINKING_BUDGET) == "low" + assert reasoning_effort_from_thinking_budget(DEFAULT_REASONING_EFFORT_MEDIUM_THINKING_BUDGET) == "medium" + assert reasoning_effort_from_thinking_budget(DEFAULT_REASONING_EFFORT_HIGH_THINKING_BUDGET) == "high" + assert reasoning_effort_from_thinking_budget(DEFAULT_REASONING_EFFORT_XHIGH_THINKING_BUDGET) == "xhigh" + assert reasoning_effort_from_thinking_budget(DEFAULT_REASONING_EFFORT_MAX_THINKING_BUDGET) == "max" + + +def test_thinking_budget_from_reasoning_effort_levels(): + assert thinking_budget_from_reasoning_effort(None) == DEFAULT_REASONING_EFFORT_MEDIUM_THINKING_BUDGET + assert thinking_budget_from_reasoning_effort("none") == 0 + assert thinking_budget_from_reasoning_effort("minimal") == DEFAULT_REASONING_EFFORT_MINIMAL_THINKING_BUDGET + assert thinking_budget_from_reasoning_effort("low") == DEFAULT_REASONING_EFFORT_LOW_THINKING_BUDGET + assert thinking_budget_from_reasoning_effort("medium") == DEFAULT_REASONING_EFFORT_MEDIUM_THINKING_BUDGET + assert thinking_budget_from_reasoning_effort("high") == DEFAULT_REASONING_EFFORT_HIGH_THINKING_BUDGET + assert thinking_budget_from_reasoning_effort("xhigh") == DEFAULT_REASONING_EFFORT_XHIGH_THINKING_BUDGET + assert thinking_budget_from_reasoning_effort("max") == DEFAULT_REASONING_EFFORT_MAX_THINKING_BUDGET diff --git a/tests/test_litellm/test_uuid_helper.py b/tests/test_litellm/test_uuid_helper.py index 589d3f96a17..3763f3afbaf 100644 --- a/tests/test_litellm/test_uuid_helper.py +++ b/tests/test_litellm/test_uuid_helper.py @@ -1,14 +1,20 @@ import importlib +import uuid as stdlib_uuid -def test_uses_fastuuid_and_uuid4_works(): +def test_uses_fastuuid_or_stdlib_and_uuid4_works(): mod = importlib.import_module("litellm._uuid") - fastuuid_mod = importlib.import_module("fastuuid") assert hasattr(mod, "uuid4") assert hasattr(mod, "uuid") - assert mod.uuid is fastuuid_mod + + try: + fastuuid_mod = importlib.import_module("fastuuid") + assert mod.uuid is fastuuid_mod + except ImportError: + assert mod.uuid is stdlib_uuid # Ensure uuid4 returns something that looks like a UUID string val = str(mod.uuid4()) assert isinstance(val, str) assert len(val) >= 8 +