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
6 changes: 5 additions & 1 deletion lib/crewai/src/crewai/llms/providers/openai/completion.py
Original file line number Diff line number Diff line change
Expand Up @@ -2445,7 +2445,11 @@ def get_context_window_size(self) -> int:
"o4-mini": 200000,
}

for model_prefix, size in context_windows.items():
# Match the most specific (longest) prefix first so that, e.g.,
# "gpt-4o" is not shadowed by the shorter "gpt-4" entry.
for model_prefix, size in sorted(
context_windows.items(), key=lambda x: len(x[0]), reverse=True
):
if self.model.startswith(model_prefix):
return int(size * CONTEXT_WINDOW_USAGE_RATIO)

Expand Down
26 changes: 26 additions & 0 deletions lib/crewai/tests/llms/openai/test_openai.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,32 @@ def test_openai_completion_is_used_when_no_provider_prefix():
assert llm.model == "gpt-4o"


def test_openai_context_window_uses_longest_prefix_match():
"""Model prefixes must resolve to the most specific match.

Regression test: ``gpt-4o`` (and other ``gpt-4*`` models) must not be
shadowed by the shorter ``gpt-4`` prefix, which would collapse their
context window to 8192. This mirrors the Azure provider, which already
matches the longest prefix first.
"""
from crewai.llm import CONTEXT_WINDOW_USAGE_RATIO

with patch.dict(os.environ, {"OPENAI_API_KEY": "test-key"}, clear=False):
llm_gpt4 = LLM(model="gpt-4")
llm_gpt4o = LLM(model="gpt-4o")
llm_gpt4o_mini = LLM(model="gpt-4o-mini")

assert isinstance(llm_gpt4o, OpenAICompletion)
assert llm_gpt4.get_context_window_size() == int(8192 * CONTEXT_WINDOW_USAGE_RATIO)
assert llm_gpt4o.get_context_window_size() == int(
128000 * CONTEXT_WINDOW_USAGE_RATIO
)
assert llm_gpt4o_mini.get_context_window_size() == int(
200000 * CONTEXT_WINDOW_USAGE_RATIO
)
assert llm_gpt4o.get_context_window_size() > llm_gpt4.get_context_window_size()


def test_custom_openai_flag_uses_native_openai_without_provider_prefix():
"""Custom OpenAI-compatible endpoints can serve arbitrary model ids."""
with patch.dict(os.environ, {"OPENAI_API_KEY": "test-key"}, clear=False):
Expand Down