mirror of
https://github.com/countbot-ai/CountBot.git
synced 2026-09-14 20:46:47 +08:00
163 lines
4.7 KiB
Python
163 lines
4.7 KiB
Python
"""Provider-specific reasoning / thinking request helpers."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import Any, Dict, List, Optional, Tuple
|
|
|
|
from .registry import find_provider_by_api_base
|
|
|
|
_EXTRA_BODY_REASONING_KEYS = ("thinking", "enable_thinking", "reasoning")
|
|
_TOP_LEVEL_REASONING_KEYS = (
|
|
"thinking",
|
|
"reasoning",
|
|
"reasoning_effort",
|
|
"include_reasoning",
|
|
"reasoning_format",
|
|
)
|
|
|
|
|
|
def _normalize_provider_id(
|
|
provider_id: Optional[str],
|
|
api_base: Optional[str],
|
|
) -> str:
|
|
normalized = str(provider_id or "").strip().lower()
|
|
if normalized and normalized not in {"custom_openai", "custom_anthropic"}:
|
|
return normalized
|
|
|
|
guessed = find_provider_by_api_base(api_base or "")
|
|
if guessed:
|
|
return guessed.id
|
|
|
|
return normalized
|
|
|
|
|
|
def _normalized_model_name(model: Optional[str]) -> str:
|
|
return str(model or "").strip().lower()
|
|
|
|
|
|
def _ensure_extra_body(request_params: Dict[str, Any]) -> Dict[str, Any]:
|
|
extra_body = request_params.get("extra_body")
|
|
if isinstance(extra_body, dict):
|
|
return dict(extra_body)
|
|
return {}
|
|
|
|
|
|
def clear_reasoning_request_fields(request_params: Dict[str, Any]) -> List[str]:
|
|
"""Remove all known provider-specific reasoning control fields."""
|
|
removed: List[str] = []
|
|
|
|
for key in _TOP_LEVEL_REASONING_KEYS:
|
|
if key in request_params:
|
|
request_params.pop(key, None)
|
|
removed.append(key)
|
|
|
|
extra_body = request_params.get("extra_body")
|
|
if isinstance(extra_body, dict):
|
|
next_extra_body = dict(extra_body)
|
|
for key in _EXTRA_BODY_REASONING_KEYS:
|
|
if key in next_extra_body:
|
|
next_extra_body.pop(key, None)
|
|
removed.append(f"extra_body.{key}")
|
|
|
|
if next_extra_body:
|
|
request_params["extra_body"] = next_extra_body
|
|
else:
|
|
request_params.pop("extra_body", None)
|
|
|
|
request_params.pop("thinking_enabled", None)
|
|
return removed
|
|
|
|
|
|
def _set_extra_body_fields(
|
|
request_params: Dict[str, Any],
|
|
fields: Dict[str, Any],
|
|
) -> Tuple[str, ...]:
|
|
extra_body = _ensure_extra_body(request_params)
|
|
extra_body.update(fields)
|
|
request_params["extra_body"] = extra_body
|
|
return tuple(f"extra_body.{key}" for key in fields.keys())
|
|
|
|
|
|
def _resolve_openai_reasoning_effort(
|
|
model: Optional[str],
|
|
thinking_enabled: bool,
|
|
) -> Optional[str]:
|
|
"""Map GPT-5 family reasoning control to the chat.completions field."""
|
|
normalized_model = _normalized_model_name(model)
|
|
if "gpt-5" not in normalized_model:
|
|
return None
|
|
|
|
if thinking_enabled:
|
|
if "pro" in normalized_model:
|
|
return "high"
|
|
return "medium"
|
|
|
|
# Official docs show newer GPT-5 families accepting `none`.
|
|
if any(prefix in normalized_model for prefix in ("gpt-5.1", "gpt-5.2", "gpt-5.4")):
|
|
return "none"
|
|
|
|
# Older / codex-style GPT-5 variants do not consistently support `none`.
|
|
if "codex" in normalized_model:
|
|
return "low"
|
|
|
|
return "minimal"
|
|
|
|
|
|
def apply_reasoning_request_fields(
|
|
request_params: Dict[str, Any],
|
|
*,
|
|
provider_id: Optional[str],
|
|
model: Optional[str],
|
|
api_base: Optional[str],
|
|
thinking_enabled: Optional[bool],
|
|
) -> Tuple[str, ...]:
|
|
"""Apply provider-aware reasoning control fields to an OpenAI-compatible request."""
|
|
clear_reasoning_request_fields(request_params)
|
|
|
|
if thinking_enabled is None:
|
|
return ()
|
|
|
|
effective_provider_id = _normalize_provider_id(provider_id, api_base)
|
|
|
|
if effective_provider_id in {"deepseek", "zhipu", "moonshot"}:
|
|
return _set_extra_body_fields(
|
|
request_params,
|
|
{
|
|
"thinking": {
|
|
"type": "enabled" if thinking_enabled else "disabled",
|
|
}
|
|
},
|
|
)
|
|
|
|
if effective_provider_id == "qwen":
|
|
return _set_extra_body_fields(
|
|
request_params,
|
|
{"enable_thinking": bool(thinking_enabled)},
|
|
)
|
|
|
|
if effective_provider_id == "openrouter":
|
|
reasoning_payload: Dict[str, Any] = {
|
|
"exclude": not thinking_enabled,
|
|
}
|
|
reasoning_payload["effort"] = "medium" if thinking_enabled else "none"
|
|
return _set_extra_body_fields(
|
|
request_params,
|
|
{"reasoning": reasoning_payload},
|
|
)
|
|
|
|
if effective_provider_id == "openai":
|
|
reasoning_effort = _resolve_openai_reasoning_effort(
|
|
model=model,
|
|
thinking_enabled=bool(thinking_enabled),
|
|
)
|
|
if reasoning_effort:
|
|
request_params["reasoning_effort"] = reasoning_effort
|
|
return ("reasoning_effort",)
|
|
return ()
|
|
|
|
if effective_provider_id == "groq":
|
|
request_params["include_reasoning"] = bool(thinking_enabled)
|
|
return ("include_reasoning",)
|
|
|
|
return ()
|