From 518ed3360ddd1e12d8db53db809cf5c67105b3a9 Mon Sep 17 00:00:00 2001 From: LangSmith Issues Agent Date: Tue, 26 May 2026 18:58:50 +0000 Subject: [PATCH] xai: drop unsupported 'stop' parameter for grok-3 models The grok-3 model family rejects the legacy 'stop' parameter with a 400 BadRequestError rather than ignoring it. Override _get_request_payload on ChatXAI to silently strip 'stop' from the outbound payload when the model name starts with 'grok-3', so shared configurations across xAI models don't hard-fail on grok-3. Other models (e.g. grok-4) continue to forward 'stop' unchanged. --- .../partners/xai/langchain_xai/chat_models.py | 15 +++++++++++++++ .../xai/tests/unit_tests/test_chat_models.py | 19 +++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/libs/partners/xai/langchain_xai/chat_models.py b/libs/partners/xai/langchain_xai/chat_models.py index 359667376e4..a5cbec2f2e5 100644 --- a/libs/partners/xai/langchain_xai/chat_models.py +++ b/libs/partners/xai/langchain_xai/chat_models.py @@ -535,6 +535,21 @@ class ChatXAI(BaseChatOpenAI): # type: ignore[override] def _resolve_model_profile(self) -> ModelProfile | None: return _get_default_model_profile(self.model_name) or None + def _get_request_payload( + self, + input_: LanguageModelInput, + *, + stop: list[str] | None = None, + **kwargs: Any, + ) -> dict: + payload = super()._get_request_payload(input_, stop=stop, **kwargs) + # The grok-3 family rejects the `stop` parameter with a 400 error + # rather than ignoring it. Drop it silently so calls that set `stop` + # for other models in a shared code path don't hard-fail on grok-3. + if self.model_name and self.model_name.startswith("grok-3"): + payload.pop("stop", None) + return payload + def _stream(self, *args: Any, **kwargs: Any) -> Iterator[ChatGenerationChunk]: """Route to Chat Completions or Responses API.""" if self._use_responses_api({**kwargs, **self.model_kwargs}): diff --git a/libs/partners/xai/tests/unit_tests/test_chat_models.py b/libs/partners/xai/tests/unit_tests/test_chat_models.py index 1e4b3d30672..d70e1f1c73c 100644 --- a/libs/partners/xai/tests/unit_tests/test_chat_models.py +++ b/libs/partners/xai/tests/unit_tests/test_chat_models.py @@ -159,3 +159,22 @@ def test_stream_usage_metadata() -> None: model = ChatXAI(model=MODEL_NAME, stream_usage=False) assert model.stream_usage is False + + +def test_chat_xai_grok_3_strips_stop_from_payload() -> None: + """grok-3 family rejects the `stop` param; ensure it's stripped from payload.""" + llm = ChatXAI(model="grok-3", api_key=SecretStr("test-api-key"), stop=["END"]) + payload = llm._get_request_payload([HumanMessage(content="hi")]) + assert "stop" not in payload + + # Also covers forward-compat variants like `grok-3-mini`, `grok-3-fast`, etc. + llm_variant = ChatXAI( + model="grok-3-mini", api_key=SecretStr("test-api-key"), stop=["END"] + ) + payload_variant = llm_variant._get_request_payload([HumanMessage(content="hi")]) + assert "stop" not in payload_variant + + # Sanity check: other models still forward `stop`. + llm_other = ChatXAI(model="grok-4", api_key=SecretStr("test-api-key"), stop=["END"]) + payload_other = llm_other._get_request_payload([HumanMessage(content="hi")]) + assert payload_other.get("stop") == ["END"]