refactor(ollama): move reasoning_effort unwrapping into a shared helper

A Final local inside the param loop tripped basedpyright's reassignment
check in both configs and pushed reportGeneralTypeIssues over budget.
think_from_reasoning_effort in common_utils keeps the Final outside any
loop, guards on str so non-string efforts never reach the set check, and
lets both configs share one code path
This commit is contained in:
woongstardev 2026-09-22 21:11:25 +09:00
parent da7ec892af
commit 28f8e6d341
3 changed files with 24 additions and 18 deletions

View file

@ -28,7 +28,7 @@ from litellm.types.llms.openai import (
)
from litellm.types.utils import ModelResponse, ModelResponseStream
from ..common_utils import OllamaError
from ..common_utils import OllamaError, think_from_reasoning_effort
if TYPE_CHECKING:
from litellm.litellm_core_utils.litellm_logging import Logging as _LiteLLMLoggingObj
@ -170,13 +170,11 @@ class OllamaChatConfig(BaseConfig):
if param == "response_format" and isinstance(value, dict) and value.get("type") == "json_schema":
if value.get("json_schema") and value["json_schema"].get("schema"):
optional_params["format"] = value["json_schema"]["schema"]
if param == "reasoning_effort" and value is not None:
effort: Final = value.get("effort") if isinstance(value, Mapping) else value
if effort is not None:
if model.startswith("gpt-oss"):
optional_params["think"] = effort
else:
optional_params["think"] = effort in {"low", "medium", "high"}
if (
param == "reasoning_effort"
and (think := think_from_reasoning_effort(model, cast(object, value))) is not None
):
optional_params["think"] = think
### FUNCTION CALLING LOGIC ###
# Ollama 0.4+ supports native tool calling - pass tools directly
# and let Ollama handle model capability detection

View file

@ -1,5 +1,6 @@
import base64
import io
from collections.abc import Mapping
from typing import Any, Final
import httpx
@ -8,6 +9,15 @@ from litellm import verbose_logger
from litellm.llms.base_llm.chat.transformation import BaseLLMException
def think_from_reasoning_effort(model: str, reasoning_effort: object) -> str | bool | None:
effort: Final = reasoning_effort.get("effort") if isinstance(reasoning_effort, Mapping) else reasoning_effort
if not isinstance(effort, str):
return None
if model.startswith("gpt-oss"):
return effort
return effort in {"low", "medium", "high"}
class OllamaError(BaseLLMException):
def __init__(self, status_code: int, message: str, headers: dict | httpx.Headers):
super().__init__(status_code=status_code, message=message, headers=headers)

View file

@ -1,7 +1,7 @@
import json
import time
from collections.abc import AsyncIterator, Iterator, Mapping
from typing import TYPE_CHECKING, Any, Final
from collections.abc import AsyncIterator, Iterator
from typing import TYPE_CHECKING, Any, Final, cast
from httpx._models import Headers, Response
from pydantic import BaseModel, ConfigDict, ValidationError
@ -33,7 +33,7 @@ from litellm.types.utils import (
StreamingChoices,
)
from ..common_utils import OllamaError, OllamaModelInfo, _convert_image
from ..common_utils import OllamaError, OllamaModelInfo, _convert_image, think_from_reasoning_effort
if TYPE_CHECKING:
from litellm.litellm_core_utils.litellm_logging import Logging as _LiteLLMLoggingObj
@ -214,13 +214,11 @@ class OllamaConfig(BaseConfig):
optional_params["frequency_penalty"] = value
elif param == "stop":
optional_params["stop"] = value
elif param == "reasoning_effort" and value is not None:
effort: Final = value.get("effort") if isinstance(value, Mapping) else value
if effort is not None:
if model.startswith("gpt-oss"):
optional_params["think"] = effort
else:
optional_params["think"] = effort in {"low", "medium", "high"}
elif (
param == "reasoning_effort"
and (think := think_from_reasoning_effort(model, cast(object, value))) is not None
):
optional_params["think"] = think
elif param == "response_format" and isinstance(value, dict):
if value["type"] == "json_object":
optional_params["format"] = "json"