diff --git a/lib/crewai/src/crewai/llm.py b/lib/crewai/src/crewai/llm.py index e6604805d4..73c14aa6d7 100644 --- a/lib/crewai/src/crewai/llm.py +++ b/lib/crewai/src/crewai/llm.py @@ -177,8 +177,11 @@ def _ensure_litellm() -> bool: "gpt-4.1": 1047576, # Based on official docs "gpt-4.1-mini-2025-04-14": 1047576, "gpt-4.1-nano-2025-04-14": 1047576, + "o1": 200000, + "o1-pro": 200000, "o1-preview": 128000, "o1-mini": 128000, + "o3": 200000, "o3-mini": 200000, "o4-mini": 200000, "gemini-3-pro-preview": 1048576, diff --git a/lib/crewai/src/crewai/llms/providers/azure/completion.py b/lib/crewai/src/crewai/llms/providers/azure/completion.py index eecc1a0592..a5a920ee23 100644 --- a/lib/crewai/src/crewai/llms/providers/azure/completion.py +++ b/lib/crewai/src/crewai/llms/providers/azure/completion.py @@ -1324,7 +1324,13 @@ def get_context_window_size(self) -> int: "gpt-4-turbo": 128000, "gpt-5.6": 1050000, "gpt-4o": 128000, + "o1-preview": 128000, + "o1-mini": 128000, + "o1-pro": 200000, + "o3-mini": 200000, "gpt-4": 8192, + "o1": 200000, + "o3": 200000, } for model_prefix, size in context_windows.items(): diff --git a/lib/crewai/src/crewai/llms/providers/openai/completion.py b/lib/crewai/src/crewai/llms/providers/openai/completion.py index 280c314eac..b41a1523de 100644 --- a/lib/crewai/src/crewai/llms/providers/openai/completion.py +++ b/lib/crewai/src/crewai/llms/providers/openai/completion.py @@ -2688,12 +2688,15 @@ def get_context_window_size(self) -> int: "o1-preview": 128000, "gpt-5.6": 1050000, "o1-mini": 128000, + "o1-pro": 200000, "o3-mini": 200000, "o4-mini": 200000, "gpt-4.1": 1047576, "gpt-4o": 128000, "gpt-5": 1047576, "gpt-4": 8192, + "o1": 200000, + "o3": 200000, } for model_prefix, size in context_windows.items(): diff --git a/lib/crewai/tests/test_llm.py b/lib/crewai/tests/test_llm.py index ec15e8a3c2..24b9d0ed70 100644 --- a/lib/crewai/tests/test_llm.py +++ b/lib/crewai/tests/test_llm.py @@ -386,6 +386,36 @@ def test_unrecognized_provider_prefix_is_not_stripped() -> None: ) +@pytest.mark.parametrize( + "model", + ["o1", "o1-pro", "o3"], +) +def test_o_series_reasoning_models_context_window(model: str) -> None: + """Official reasoning models (o1, o1-pro, o3) use 200,000 token context window.""" + llm = LLM(model=model, is_litellm=True) + assert llm.get_context_window_size() == int(200000 * CONTEXT_WINDOW_USAGE_RATIO) + + +def test_o_series_does_not_override_preview_and_mini() -> None: + """More specific o1-preview and o1-mini must keep their 128,000 window.""" + llm_preview = LLM(model="o1-preview", is_litellm=True) + assert llm_preview.get_context_window_size() == int(128000 * CONTEXT_WINDOW_USAGE_RATIO) + + llm_mini = LLM(model="o1-mini", is_litellm=True) + assert llm_mini.get_context_window_size() == int(128000 * CONTEXT_WINDOW_USAGE_RATIO) + + +@pytest.mark.parametrize( + "model", + ["openai/o1", "openai/o1-pro", "openai/o3"], +) +def test_openai_o_series_reasoning_models_context_window(model: str) -> None: + """Native OpenAI provider recognizes 200,000 token window for o1, o1-pro, and o3.""" + llm = LLM(model=model) + assert llm.get_context_window_size() == int(200000 * CONTEXT_WINDOW_USAGE_RATIO) + + + @pytest.fixture def get_weather_tool_schema(): return {