Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 30 additions & 20 deletions unstract/sdk1/src/unstract/sdk1/adapters/base1.py
Original file line number Diff line number Diff line change
Expand Up @@ -565,6 +565,35 @@ def _minimax_context_window(model_id: str) -> int | None:
return None


def _normalize_minimax_thinking(
adapter_metadata: dict[str, "Any"], model_id: str
) -> None:
is_m2_model = _is_minimax_m2_model(model_id)
if "enable_thinking" in adapter_metadata:
enable_thinking = adapter_metadata.pop("enable_thinking")
if not isinstance(enable_thinking, bool):
raise ValueError("enable_thinking must be a boolean.")
if is_m2_model and not enable_thinking:
raise ValueError(f"{model_id} does not support disabling thinking.")
if not is_m2_model:
adapter_metadata["thinking"] = {
"type": "adaptive" if enable_thinking else "disabled"
}

thinking = adapter_metadata.get("thinking")
if thinking is None:
return
if is_m2_model:
# M2.x always thinks; the provider accepts this parameter but ignores it.
adapter_metadata.pop("thinking")
return
if not isinstance(thinking, dict) or thinking.get("type") not in {
"adaptive",
"disabled",
}:
raise ValueError("thinking.type must be adaptive or disabled.")


class NvidiaBuildLLMParameters(OpenAICompatibleLLMParameters):
"""OpenAI-compatible adapter for NVIDIA's hosted models (build.nvidia.com)."""

Expand Down Expand Up @@ -601,26 +630,7 @@ def validate(adapter_metadata: dict[str, "Any"]) -> dict[str, "Any"]:
if service_tier not in {None, "standard", "priority"}:
raise ValueError("service_tier must be standard or priority.")

if "enable_thinking" in adapter_metadata:
enable_thinking = adapter_metadata.pop("enable_thinking")
if not isinstance(enable_thinking, bool):
raise ValueError("enable_thinking must be a boolean.")
adapter_metadata["thinking"] = {
"type": "adaptive" if enable_thinking else "disabled"
}

thinking = adapter_metadata.get("thinking")
if thinking is None and _is_minimax_m2_model(model_id):
thinking = {"type": "adaptive"}
adapter_metadata["thinking"] = thinking
if thinking is not None:
if not isinstance(thinking, dict) or thinking.get("type") not in {
"adaptive",
"disabled",
}:
raise ValueError("thinking.type must be adaptive or disabled.")
if _is_minimax_m2_model(model_id) and thinking["type"] == "disabled":
raise ValueError(f"{model_id} does not support disabling thinking.")
_normalize_minimax_thinking(adapter_metadata, model_id)

validated = MiniMaxLLMParameters(**adapter_metadata).model_dump()
Comment thread
greptile-apps[bot] marked this conversation as resolved.
validated["cost_model"] = f"{_MINIMAX_PROVIDER_PREFIX}{model_id}"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@
"enable_thinking": {
"type": "boolean",
"title": "Enable Thinking",
"description": "Override the protocol default for MiniMax-M3: OpenAI-compatible requests default to adaptive thinking, while Anthropic-compatible requests default to disabled thinking. MiniMax-M2.x models always keep thinking enabled. See [MiniMax API docs](https://platform.minimax.io/docs/api-reference/text-openai-api)."
"description": "Override the protocol default for MiniMax-M3: OpenAI-compatible requests default to adaptive thinking, while Anthropic-compatible requests default to disabled thinking. MiniMax-M2.x models use always-on thinking and only accept this setting as true. See [MiniMax API docs](https://platform.minimax.io/docs/api-reference/text-openai-api)."
}
}
}
24 changes: 22 additions & 2 deletions unstract/sdk1/tests/test_branded_openai_adapters.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,10 +186,30 @@ def test_minimax_m2_rejects_disabling_thinking() -> None:
)


def test_minimax_m2_defaults_to_adaptive_thinking() -> None:
def test_minimax_m2_uses_always_on_thinking_without_request_parameter() -> None:
validated = MiniMaxLLMParameters.validate({"model": "MiniMax-M2.7", "api_key": "k"})

assert validated["thinking"] == {"type": "adaptive"}
assert validated["thinking"] is None
assert MiniMaxLLMParameters.validate(dict(validated))["thinking"] is None

explicitly_enabled = MiniMaxLLMParameters.validate(
{"model": "MiniMax-M2.7", "api_key": "k", "enable_thinking": True}
)
assert explicitly_enabled["thinking"] is None


def test_minimax_m2_strips_explicit_thinking_payload() -> None:
# The provider accepts a thinking payload for M2.x but ignores it, so drop it
# instead of failing a call that works today.
validated = MiniMaxLLMParameters.validate(
{
"model": "MiniMax-M2.7",
"api_key": "k",
"thinking": {"type": "disabled"},
}
)

assert validated["thinking"] is None


def test_minimax_m2_thinking_rules_require_model_family_boundary() -> None:
Expand Down