Skip to content
Merged
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
15 changes: 12 additions & 3 deletions bot/agents.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from agents.mcp import MCPServerStdio
from agents.mcp import MCPServerStreamableHttp
from agents.models.openai_chatcompletions import OpenAIChatCompletionsModel
from agents.models.openai_responses import OpenAIResponsesModel
from openai import AsyncAzureOpenAI
from openai import AsyncOpenAI

Expand All @@ -25,9 +26,15 @@
MCP_SESSION_TIMEOUT_SECONDS = 30.0


def _get_model() -> OpenAIChatCompletionsModel:
"""Create an OpenAI model from environment variables."""
def _get_model() -> OpenAIResponsesModel | OpenAIChatCompletionsModel:
"""Create an OpenAI model from environment variables.

OPENAI_API_TYPE controls which API the model uses:
- "responses" (default): OpenAI Responses API — recommended by the SDK
- "chat_completions": Chat Completions API — use for Azure OpenAI or compatible providers
"""
model_name = os.getenv("OPENAI_MODEL", "gpt-5.4")
api_type = os.getenv("OPENAI_API_TYPE", "responses")

client: AsyncOpenAI
if os.getenv("AZURE_OPENAI_API_KEY") and os.getenv("AZURE_OPENAI_ENDPOINT"):
Expand All @@ -39,7 +46,9 @@ def _get_model() -> OpenAIChatCompletionsModel:
else:
client = AsyncOpenAI()

return OpenAIChatCompletionsModel(model=model_name, openai_client=client)
if api_type == "chat_completions":
return OpenAIChatCompletionsModel(model=model_name, openai_client=client)
return OpenAIResponsesModel(model=model_name, openai_client=client)


class OpenAIAgent:
Expand Down
29 changes: 29 additions & 0 deletions tests/test_agents.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

import pytest
from agents.models.interface import Model
from agents.models.openai_chatcompletions import OpenAIChatCompletionsModel
from agents.models.openai_responses import OpenAIResponsesModel

from bot.agents import DEFAULT_INSTRUCTIONS
from bot.agents import MAX_TURNS
Expand Down Expand Up @@ -51,6 +53,33 @@ def test_uses_standard_openai_when_no_azure_vars(self, monkeypatch):
mock_openai.assert_called_once()
mock_azure.assert_not_called()

def test_returns_responses_model_by_default(self, monkeypatch):
monkeypatch.delenv("OPENAI_API_TYPE", raising=False)
monkeypatch.delenv("AZURE_OPENAI_API_KEY", raising=False)
monkeypatch.delenv("AZURE_OPENAI_ENDPOINT", raising=False)

with patch("bot.agents.AsyncOpenAI", return_value=MagicMock()):
model = _get_model()
assert isinstance(model, OpenAIResponsesModel)

def test_returns_responses_model_when_api_type_is_responses(self, monkeypatch):
monkeypatch.setenv("OPENAI_API_TYPE", "responses")
monkeypatch.delenv("AZURE_OPENAI_API_KEY", raising=False)
monkeypatch.delenv("AZURE_OPENAI_ENDPOINT", raising=False)

with patch("bot.agents.AsyncOpenAI", return_value=MagicMock()):
model = _get_model()
assert isinstance(model, OpenAIResponsesModel)

def test_returns_chat_completions_model_when_api_type_is_chat_completions(self, monkeypatch):
monkeypatch.setenv("OPENAI_API_TYPE", "chat_completions")
monkeypatch.delenv("AZURE_OPENAI_API_KEY", raising=False)
monkeypatch.delenv("AZURE_OPENAI_ENDPOINT", raising=False)

with patch("bot.agents.AsyncOpenAI", return_value=MagicMock()):
model = _get_model()
assert isinstance(model, OpenAIChatCompletionsModel)


class TestPerChatConversations:
def test_separate_chats_have_independent_history(self):
Expand Down
Loading