diff --git a/backend/open_webui/utils/anthropic.py b/backend/open_webui/utils/anthropic.py index 7b8ef09b79..0d2ddf3b9c 100644 --- a/backend/open_webui/utils/anthropic.py +++ b/backend/open_webui/utils/anthropic.py @@ -350,41 +350,42 @@ def convert_anthropic_to_openai_payload(anthropic_payload: dict) -> dict: 'function': {'name': tc.get('name', '')}, } # === Add logic to convert Anthropic thinking/reasoning parameters to OpenAI reasoning_effort === - def map_effort_string(raw_str: str) -> str: + def get_reasoning_effort(effort_value: str) -> str: """Extract reasoning level via fuzzy matching, defaulting to safe compatible 'high' for max values.""" - s = raw_str.lower() - if any(keyword in s for keyword in ('high', 'max', 'ultra')): + effort_lower = str(effort_value).lower() + if any(keyword in effort_lower for keyword in ('high', 'max', 'ultra')): return 'high' - elif 'low' in s: + if 'low' in effort_lower: return 'low' - else: - return 'medium' + return 'medium' # 1. Prioritize capturing output_config.effort from the latest Claude Code versions - if 'output_config' in anthropic_payload and isinstance(anthropic_payload['output_config'], dict): - effort_val = anthropic_payload['output_config'].get('effort') - if effort_val: - openai_payload['reasoning_effort'] = map_effort_string(str(effort_val)) + output_config = anthropic_payload.get('output_config') + if isinstance(output_config, dict) and 'effort' in output_config: + openai_payload['reasoning_effort'] = get_reasoning_effort(output_config['effort']) # 2. Compatibility for effort field passed directly at the top level elif 'effort' in anthropic_payload: - openai_payload['reasoning_effort'] = map_effort_string(str(anthropic_payload['effort'])) + openai_payload['reasoning_effort'] = get_reasoning_effort(anthropic_payload['effort']) # 3. Fallback handling for thinking field (supports both adaptive and legacy budget_tokens) if 'thinking' in anthropic_payload: - thinking_cfg = anthropic_payload['thinking'] - if isinstance(thinking_cfg, dict): - # If using the latest adaptive thinking, and effort wasn't caught above, default to high intensity - if thinking_cfg.get('type') == 'adaptive' and 'reasoning_effort' not in openai_payload: + thinking = anthropic_payload['thinking'] + if isinstance(thinking, dict): + thinking_type = thinking.get('type') + + # If using the latest adaptive thinking, and effort wasn't caught above + if thinking_type == 'adaptive' and 'reasoning_effort' not in openai_payload: openai_payload['reasoning_effort'] = 'high' + # Legacy budget_tokens logic - elif 'budget_tokens' in thinking_cfg and 'reasoning_effort' not in openai_payload: - budget = thinking_cfg.get('budget_tokens', 0) - if budget == 0: + elif 'budget_tokens' in thinking and 'reasoning_effort' not in openai_payload: + budget_tokens = thinking.get('budget_tokens', 0) + if budget_tokens == 0: openai_payload['reasoning_effort'] = 'medium' - elif budget < 4000: + elif budget_tokens < 4000: openai_payload['reasoning_effort'] = 'low' - elif budget < 8000: + elif budget_tokens < 8000: openai_payload['reasoning_effort'] = 'medium' else: openai_payload['reasoning_effort'] = 'high'