mirror of
https://github.com/TauricResearch/TradingAgents.git
synced 2026-06-16 21:06:15 +03:00
fix(llm): send MiniMax reasoning_split via extra_body so the openai SDK accepts it (#826)
This commit is contained in:
@@ -25,34 +25,22 @@ def _client(model: str = "MiniMax-M2.7"):
|
|||||||
|
|
||||||
@pytest.mark.unit
|
@pytest.mark.unit
|
||||||
class TestMinimaxReasoningSplit:
|
class TestMinimaxReasoningSplit:
|
||||||
def test_request_payload_sets_reasoning_split(self):
|
def test_reasoning_split_sent_via_extra_body_not_top_level(self):
|
||||||
|
# Must be in extra_body, not top-level: the openai SDK validates
|
||||||
|
# top-level params and rejects unknown ones like reasoning_split (#826).
|
||||||
payload = _client()._get_request_payload([HumanMessage(content="hi")])
|
payload = _client()._get_request_payload([HumanMessage(content="hi")])
|
||||||
assert payload.get("reasoning_split") is True
|
assert payload.get("extra_body", {}).get("reasoning_split") is True
|
||||||
|
assert "reasoning_split" not in payload # never top-level
|
||||||
def test_caller_supplied_reasoning_split_is_preserved(self):
|
|
||||||
"""If the user explicitly sets reasoning_split, don't override it
|
|
||||||
(setdefault semantics — caller wins)."""
|
|
||||||
client = _client()
|
|
||||||
payload = client._get_request_payload(
|
|
||||||
[HumanMessage(content="hi")],
|
|
||||||
reasoning_split=False,
|
|
||||||
)
|
|
||||||
# langchain may or may not surface that kwarg into the payload;
|
|
||||||
# what matters is we don't blindly overwrite a non-default value
|
|
||||||
# the caller passed. setdefault leaves an existing value alone.
|
|
||||||
assert payload.get("reasoning_split") in (False, True)
|
|
||||||
|
|
||||||
def test_non_reasoning_minimax_does_not_inject_reasoning_split(self):
|
def test_non_reasoning_minimax_does_not_inject_reasoning_split(self):
|
||||||
"""Coding Plan / MiniMax-Text-01 / any non-M2-prefixed model must NOT
|
"""Coding Plan / MiniMax-Text-01 / any non-M2-prefixed model must NOT
|
||||||
receive reasoning_split — the openai SDK rejects unknown kwargs with
|
receive reasoning_split at all (top-level or extra_body) (#826)."""
|
||||||
TypeError (#826)."""
|
|
||||||
for model in ("minimax-text-01", "MiniMax-Coding-Plan"):
|
for model in ("minimax-text-01", "MiniMax-Coding-Plan"):
|
||||||
payload = _client(model)._get_request_payload(
|
payload = _client(model)._get_request_payload(
|
||||||
[HumanMessage(content="hi")]
|
[HumanMessage(content="hi")]
|
||||||
)
|
)
|
||||||
assert "reasoning_split" not in payload, (
|
assert "reasoning_split" not in payload
|
||||||
f"{model!r} payload unexpectedly contains reasoning_split"
|
assert "reasoning_split" not in payload.get("extra_body", {})
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.unit
|
@pytest.mark.unit
|
||||||
|
|||||||
@@ -114,14 +114,15 @@ class MinimaxChatOpenAI(NormalizedChatOpenAI):
|
|||||||
|
|
||||||
M2.x reasoning models embed ``<think>...</think>`` blocks directly in
|
M2.x reasoning models embed ``<think>...</think>`` blocks directly in
|
||||||
``message.content`` by default, which would pollute saved reports.
|
``message.content`` by default, which would pollute saved reports.
|
||||||
Per platform.minimax.io/docs/api-reference/text-openai-api, setting
|
Per platform.minimax.io/docs/api-reference/text-openai-api,
|
||||||
``reasoning_split=True`` in the request body redirects the thinking
|
``reasoning_split=True`` redirects the thinking block into
|
||||||
block into ``reasoning_details`` so ``content`` stays clean.
|
``reasoning_details`` so ``content`` stays clean. It is sent via
|
||||||
|
``extra_body`` (not a top-level kwarg) because the openai SDK validates
|
||||||
|
top-level params and rejects unknown ones like reasoning_split (#826).
|
||||||
|
|
||||||
The flag is gated by ``ModelCapabilities.requires_reasoning_split``
|
The flag is gated by ``ModelCapabilities.requires_reasoning_split`` so
|
||||||
because non-reasoning MiniMax endpoints (Coding Plan, MiniMax-Text-01)
|
only M2.x reasoning models receive it; non-reasoning MiniMax endpoints
|
||||||
reject the parameter via the openai SDK's strict kwarg validation
|
(Coding Plan, MiniMax-Text-01) never see it.
|
||||||
(#826).
|
|
||||||
|
|
||||||
Tool-choice handling for M2.x — those models accept only the string
|
Tool-choice handling for M2.x — those models accept only the string
|
||||||
enum ``{"none", "auto"}`` and reject langchain's function-spec dict —
|
enum ``{"none", "auto"}`` and reject langchain's function-spec dict —
|
||||||
@@ -132,7 +133,12 @@ class MinimaxChatOpenAI(NormalizedChatOpenAI):
|
|||||||
def _get_request_payload(self, input_, *, stop=None, **kwargs):
|
def _get_request_payload(self, input_, *, stop=None, **kwargs):
|
||||||
payload = super()._get_request_payload(input_, stop=stop, **kwargs)
|
payload = super()._get_request_payload(input_, stop=stop, **kwargs)
|
||||||
if get_capabilities(self.model_name).requires_reasoning_split:
|
if get_capabilities(self.model_name).requires_reasoning_split:
|
||||||
payload.setdefault("reasoning_split", True)
|
# Pass via extra_body, not as a top-level kwarg: the openai SDK
|
||||||
|
# (>=1.56) validates top-level params against Completions.create
|
||||||
|
# and rejects unknown ones like reasoning_split (#826). extra_body
|
||||||
|
# is forwarded into the request body untouched.
|
||||||
|
extra_body = payload.setdefault("extra_body", {})
|
||||||
|
extra_body.setdefault("reasoning_split", True)
|
||||||
return payload
|
return payload
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user