From a0a536e73715acd32961e2295401fb9f7863726f Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Thu, 1 May 2025 19:57:17 +0000 Subject: [PATCH] Fix issue #2738: Exclude stop parameter for o3 model Co-Authored-By: Joe Moura --- src/crewai/llm.py | 4 +++- tests/unit/test_llm.py | 52 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 tests/unit/test_llm.py diff --git a/src/crewai/llm.py b/src/crewai/llm.py index c8c456297..d00631c79 100644 --- a/src/crewai/llm.py +++ b/src/crewai/llm.py @@ -351,7 +351,6 @@ class LLM(BaseLLM): "temperature": self.temperature, "top_p": self.top_p, "n": self.n, - "stop": self.stop, "max_tokens": self.max_tokens or self.max_completion_tokens, "presence_penalty": self.presence_penalty, "frequency_penalty": self.frequency_penalty, @@ -369,6 +368,9 @@ class LLM(BaseLLM): "reasoning_effort": self.reasoning_effort, **self.additional_params, } + + if self.stop and self.supports_stop_words(): + params["stop"] = self.stop # Remove None values from params return {k: v for k, v in params.items() if v is not None} diff --git a/tests/unit/test_llm.py b/tests/unit/test_llm.py new file mode 100644 index 000000000..525c23884 --- /dev/null +++ b/tests/unit/test_llm.py @@ -0,0 +1,52 @@ +import unittest +from unittest.mock import patch, MagicMock +from types import SimpleNamespace + +from crewai.llm import LLM + + +class TestLLM(unittest.TestCase): + @patch("crewai.llm.litellm.completion") + @patch("crewai.llm.LLM.supports_stop_words") + def test_call_with_supported_stop_words(self, mock_supports_stop_words, mock_completion): + mock_supports_stop_words.return_value = True + + message = SimpleNamespace(content="Hello, World!") + choice = SimpleNamespace(message=message) + response = SimpleNamespace(choices=[choice]) + mock_completion.return_value = response + + llm = LLM(model="gpt-4", stop=["STOP"]) + + messages = [{"role": "user", "content": "Say Hello"}] + result = llm.call(messages) + + mock_completion.assert_called_once() + call_args = mock_completion.call_args[1] + self.assertIn("stop", call_args) + self.assertEqual(call_args["stop"], ["STOP"]) + self.assertEqual(result, "Hello, World!") + + @patch("crewai.llm.litellm.completion") + @patch("crewai.llm.LLM.supports_stop_words") + def test_call_with_unsupported_stop_words(self, mock_supports_stop_words, mock_completion): + mock_supports_stop_words.return_value = False + + message = SimpleNamespace(content="Hello, World!") + choice = SimpleNamespace(message=message) + response = SimpleNamespace(choices=[choice]) + mock_completion.return_value = response + + llm = LLM(model="o3", stop=["STOP"]) + + messages = [{"role": "user", "content": "Say Hello"}] + result = llm.call(messages) + + mock_completion.assert_called_once() + call_args = mock_completion.call_args[1] + self.assertNotIn("stop", call_args) + self.assertEqual(result, "Hello, World!") + + +if __name__ == "__main__": + unittest.main()