From ae4ba3cb1fc33c8c3662adc7df6a8fa6e9c75b5c Mon Sep 17 00:00:00 2001 From: Kazuhiro Sera Date: Thu, 17 Jul 2025 07:43:58 +0900 Subject: [PATCH 1/4] Add a new GH Actions job to automatically update translated document pagse (#598) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This pull request adds a new GitHub Actions job to automate the translation of document pages. - Before this job can run, **OPENAI_API_KEY must be added to the project secrets.** - It typically takes 8–10 minutes using the o3 model, so the job is configured to run only when there are changes under docs/ or in mkdocs.yml. - The job commits and pushes the translated changes, but it does not deploy the documents to GitHub Pages. If we think it’s better to deploy the latest changes automatically as well, I’m happy to update the workflow. (Personally, I don’t think it’s necessary, since the changes will be deployed with the next deployment job execution) --- .github/workflows/update-docs.yml | 47 +++++++++++++++++++++++++++++++ docs/scripts/translate_docs.py | 3 +- 2 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/update-docs.yml diff --git a/.github/workflows/update-docs.yml b/.github/workflows/update-docs.yml new file mode 100644 index 000000000..fb7ad61e6 --- /dev/null +++ b/.github/workflows/update-docs.yml @@ -0,0 +1,47 @@ +name: "Update Translated Docs" + +# This GitHub Actions job automates the process of updating all translated document pages. Please note the following: +# 1. The translation results may vary each time; some differences in detail are expected. +# 2. When you add a new page to the left-hand menu, **make sure to manually update mkdocs.yml** to include the new item. +# 3. If you switch to a different LLM (for example, from o3 to a newer model), be sure to conduct thorough testing before making the switch. + +on: + push: + branches: + - main + paths: + - 'docs/**' + - mkdocs.yml + +jobs: + update-docs: + name: Build and Push Translated Docs + runs-on: ubuntu-latest + timeout-minutes: 20 + env: + PROD_OPENAI_API_KEY: ${{ secrets.PROD_OPENAI_API_KEY }} + steps: + - name: Checkout repository + uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Setup uv + uses: astral-sh/setup-uv@v5 + with: + enable-cache: true + - name: Install dependencies + run: make sync + - name: Build full docs + run: make build-full-docs + + - name: Commit and push changes + run: | + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + git add docs/ + if [ -n "$(git status --porcelain)" ]; then + git commit -m "Update all translated document pages" + git push + else + echo "No changes to commit" + fi diff --git a/docs/scripts/translate_docs.py b/docs/scripts/translate_docs.py index ac40b6fa8..a337a90ef 100644 --- a/docs/scripts/translate_docs.py +++ b/docs/scripts/translate_docs.py @@ -30,7 +30,8 @@ } # Initialize OpenAI client -openai_client = OpenAI(api_key=os.getenv("OPENAI_API_KEY")) +api_key = os.getenv("PROD_OPENAI_API_KEY") or os.getenv("OPENAI_API_KEY") +openai_client = OpenAI(api_key=api_key) # Define dictionaries for translation control do_not_translate = [ From 2f8ea0ae3081538d2cd6c04ea464019f2ea83e72 Mon Sep 17 00:00:00 2001 From: Kazuhiro Sera Date: Thu, 17 Jul 2025 11:58:48 +0900 Subject: [PATCH 2/4] Adjust #598 to only create a PR rather than pushing changes to main branch (#1162) This pull request resolves the execution error of #598 CI job. The job pushes the changes directly to the main branch. However, our branch policies do not allow bypassing required checks, so it always fails. This pull request changes its behavior just to create a pull request and then ask humans to review (actually you don't need to check translation results though) and merge it. --- .github/workflows/update-docs.yml | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/.github/workflows/update-docs.yml b/.github/workflows/update-docs.yml index fb7ad61e6..2def4f03e 100644 --- a/.github/workflows/update-docs.yml +++ b/.github/workflows/update-docs.yml @@ -15,6 +15,7 @@ on: jobs: update-docs: + if: "!contains(github.event.head_commit.message, 'Update all translated document pages')" name: Build and Push Translated Docs runs-on: ubuntu-latest timeout-minutes: 20 @@ -34,14 +35,26 @@ jobs: - name: Build full docs run: make build-full-docs - - name: Commit and push changes + - name: Commit changes + id: commit run: | git config user.name "github-actions[bot]" git config user.email "github-actions[bot]@users.noreply.github.com" git add docs/ if [ -n "$(git status --porcelain)" ]; then git commit -m "Update all translated document pages" - git push + echo "committed=true" >> "$GITHUB_OUTPUT" else echo "No changes to commit" + echo "committed=false" >> "$GITHUB_OUTPUT" fi + + - name: Create Pull Request + if: steps.commit.outputs.committed == 'true' + uses: peter-evans/create-pull-request@v6 + with: + commit-message: "Update all translated document pages" + title: "Update all translated document pages" + body: "Automated update of translated documentation" + branch: update-translated-docs-${{ github.run_id }} + delete-branch: true From a25dac771b70f87bd9da1a176dd506872846f53f Mon Sep 17 00:00:00 2001 From: Rohan Mehta Date: Thu, 17 Jul 2025 13:04:02 -0400 Subject: [PATCH 3/4] Realtime: only update model settings from session (#1169) ### Summary: Was running into bugs. Because the model settings were being set from both runner and session, and that was causing issues. Among other things, handoffs were broken because the runner wasn't reading them, and the session wasn't setting them in the connect() call. ### Test Plan: Unit tests. --- src/agents/realtime/runner.py | 44 +-------- src/agents/realtime/session.py | 30 +++++-- tests/realtime/test_runner.py | 149 ++++++++++++++++++------------- tests/realtime/test_session.py | 116 +++++++++++++++++++++++- tests/realtime/test_tracing.py | 41 ++++----- tests/test_session_exceptions.py | 2 + 6 files changed, 244 insertions(+), 138 deletions(-) diff --git a/src/agents/realtime/runner.py b/src/agents/realtime/runner.py index a7047a6f5..e51a094d8 100644 --- a/src/agents/realtime/runner.py +++ b/src/agents/realtime/runner.py @@ -2,13 +2,10 @@ from __future__ import annotations -import asyncio - -from ..run_context import RunContextWrapper, TContext +from ..run_context import TContext from .agent import RealtimeAgent from .config import ( RealtimeRunConfig, - RealtimeSessionModelSettings, ) from .model import ( RealtimeModel, @@ -67,16 +64,6 @@ async def run( print(event) ``` """ - model_settings = await self._get_model_settings( - agent=self._starting_agent, - disable_tracing=self._config.get("tracing_disabled", False) if self._config else False, - initial_settings=model_config.get("initial_model_settings") if model_config else None, - overrides=self._config.get("model_settings") if self._config else None, - ) - - model_config = model_config.copy() if model_config else {} - model_config["initial_model_settings"] = model_settings - # Create and return the connection session = RealtimeSession( model=self._model, @@ -87,32 +74,3 @@ async def run( ) return session - - async def _get_model_settings( - self, - agent: RealtimeAgent, - disable_tracing: bool, - context: TContext | None = None, - initial_settings: RealtimeSessionModelSettings | None = None, - overrides: RealtimeSessionModelSettings | None = None, - ) -> RealtimeSessionModelSettings: - context_wrapper = RunContextWrapper(context) - model_settings = initial_settings.copy() if initial_settings else {} - - instructions, tools = await asyncio.gather( - agent.get_system_prompt(context_wrapper), - agent.get_all_tools(context_wrapper), - ) - - if instructions is not None: - model_settings["instructions"] = instructions - if tools is not None: - model_settings["tools"] = tools - - if overrides: - model_settings.update(overrides) - - if disable_tracing: - model_settings["tracing"] = None - - return model_settings diff --git a/src/agents/realtime/session.py b/src/agents/realtime/session.py index 6df35b438..83e56d5fc 100644 --- a/src/agents/realtime/session.py +++ b/src/agents/realtime/session.py @@ -114,8 +114,13 @@ async def __aenter__(self) -> RealtimeSession: # Add ourselves as a listener self._model.add_listener(self) + model_config = self._model_config.copy() + model_config["initial_model_settings"] = await self._get_updated_model_settings_from_agent( + self._current_agent + ) + # Connect to the model - await self._model.connect(self._model_config) + await self._model.connect(model_config) # Emit initial history update await self._put_event( @@ -319,7 +324,9 @@ async def _handle_tool_call(self, event: RealtimeModelToolCallEvent) -> None: self._current_agent = result # Get updated model settings from new agent - updated_settings = await self._get__updated_model_settings(self._current_agent) + updated_settings = await self._get_updated_model_settings_from_agent( + self._current_agent + ) # Send handoff event await self._put_event( @@ -495,19 +502,28 @@ async def _cleanup(self) -> None: # Mark as closed self._closed = True - async def _get__updated_model_settings( - self, new_agent: RealtimeAgent + async def _get_updated_model_settings_from_agent( + self, + agent: RealtimeAgent, ) -> RealtimeSessionModelSettings: updated_settings: RealtimeSessionModelSettings = {} instructions, tools, handoffs = await asyncio.gather( - new_agent.get_system_prompt(self._context_wrapper), - new_agent.get_all_tools(self._context_wrapper), - self._get_handoffs(new_agent, self._context_wrapper), + agent.get_system_prompt(self._context_wrapper), + agent.get_all_tools(self._context_wrapper), + self._get_handoffs(agent, self._context_wrapper), ) updated_settings["instructions"] = instructions or "" updated_settings["tools"] = tools or [] updated_settings["handoffs"] = handoffs or [] + # Override with initial settings + initial_settings = self._model_config.get("initial_model_settings", {}) + updated_settings.update(initial_settings) + + disable_tracing = self._run_config.get("tracing_disabled", False) + if disable_tracing: + updated_settings["tracing"] = None + return updated_settings @classmethod diff --git a/tests/realtime/test_runner.py b/tests/realtime/test_runner.py index aabdff140..1e6eccbae 100644 --- a/tests/realtime/test_runner.py +++ b/tests/realtime/test_runner.py @@ -1,18 +1,21 @@ from unittest.mock import AsyncMock, Mock, patch import pytest -from inline_snapshot import snapshot from agents.realtime.agent import RealtimeAgent from agents.realtime.config import RealtimeRunConfig, RealtimeSessionModelSettings from agents.realtime.model import RealtimeModel, RealtimeModelConfig from agents.realtime.runner import RealtimeRunner from agents.realtime.session import RealtimeSession +from agents.tool import function_tool class MockRealtimeModel(RealtimeModel): + def __init__(self): + self.connect_args = None + async def connect(self, options=None): - pass + self.connect_args = options def add_listener(self, listener): pass @@ -53,7 +56,9 @@ def mock_model(): @pytest.mark.asyncio -async def test_run_creates_session_with_no_settings(mock_agent, mock_model): +async def test_run_creates_session_with_no_settings( + mock_agent: Mock, mock_model: MockRealtimeModel +): """Test that run() creates a session correctly if no settings are provided""" runner = RealtimeRunner(mock_agent, model=mock_model) @@ -71,22 +76,17 @@ async def test_run_creates_session_with_no_settings(mock_agent, mock_model): assert call_args[1]["agent"] == mock_agent assert call_args[1]["context"] is None - # Verify model_config contains expected settings from agent + # With no settings provided, model_config should be None model_config = call_args[1]["model_config"] - assert model_config == snapshot( - { - "initial_model_settings": { - "instructions": "Test instructions", - "tools": [{"type": "function", "name": "test_tool"}], - } - } - ) + assert model_config is None assert session == mock_session @pytest.mark.asyncio -async def test_run_creates_session_with_settings_only_in_init(mock_agent, mock_model): +async def test_run_creates_session_with_settings_only_in_init( + mock_agent: Mock, mock_model: MockRealtimeModel +): """Test that it creates a session with the right settings if they are provided only in init""" config = RealtimeRunConfig( model_settings=RealtimeSessionModelSettings(model_name="gpt-4o-realtime", voice="nova") @@ -99,28 +99,19 @@ async def test_run_creates_session_with_settings_only_in_init(mock_agent, mock_m _ = await runner.run() - # Verify session was created with config overrides + # Verify session was created - runner no longer processes settings call_args = mock_session_class.call_args model_config = call_args[1]["model_config"] - # Should have agent settings plus config overrides - assert model_config == snapshot( - { - "initial_model_settings": { - "instructions": "Test instructions", - "tools": [{"type": "function", "name": "test_tool"}], - "model_name": "gpt-4o-realtime", - "voice": "nova", - } - } - ) + # Runner should pass None for model_config when none provided to run() + assert model_config is None @pytest.mark.asyncio async def test_run_creates_session_with_settings_in_both_init_and_run_overrides( - mock_agent, mock_model + mock_agent: Mock, mock_model: MockRealtimeModel ): - """Test settings in both init and run() - init should override run()""" + """Test settings provided in run() parameter are passed through""" init_config = RealtimeRunConfig( model_settings=RealtimeSessionModelSettings(model_name="gpt-4o-realtime", voice="nova") ) @@ -138,26 +129,18 @@ async def test_run_creates_session_with_settings_in_both_init_and_run_overrides( _ = await runner.run(model_config=run_model_config) - # Verify run() settings override init settings + # Verify run() model_config is passed through as-is call_args = mock_session_class.call_args model_config = call_args[1]["model_config"] - # Should have agent settings, then init config, then run config overrides - assert model_config == snapshot( - { - "initial_model_settings": { - "voice": "nova", - "input_audio_format": "pcm16", - "instructions": "Test instructions", - "tools": [{"type": "function", "name": "test_tool"}], - "model_name": "gpt-4o-realtime", - } - } - ) + # Runner should pass the model_config from run() parameter directly + assert model_config == run_model_config @pytest.mark.asyncio -async def test_run_creates_session_with_settings_only_in_run(mock_agent, mock_model): +async def test_run_creates_session_with_settings_only_in_run( + mock_agent: Mock, mock_model: MockRealtimeModel +): """Test settings provided only in run()""" runner = RealtimeRunner(mock_agent, model=mock_model) @@ -173,26 +156,16 @@ async def test_run_creates_session_with_settings_only_in_run(mock_agent, mock_mo _ = await runner.run(model_config=run_model_config) - # Verify run() settings are applied + # Verify run() model_config is passed through as-is call_args = mock_session_class.call_args model_config = call_args[1]["model_config"] - # Should have agent settings plus run() settings - assert model_config == snapshot( - { - "initial_model_settings": { - "model_name": "gpt-4o-realtime-preview", - "voice": "shimmer", - "modalities": ["text", "audio"], - "instructions": "Test instructions", - "tools": [{"type": "function", "name": "test_tool"}], - } - } - ) + # Runner should pass the model_config from run() parameter directly + assert model_config == run_model_config @pytest.mark.asyncio -async def test_run_with_context_parameter(mock_agent, mock_model): +async def test_run_with_context_parameter(mock_agent: Mock, mock_model: MockRealtimeModel): """Test that context parameter is passed through to session""" runner = RealtimeRunner(mock_agent, model=mock_model) test_context = {"user_id": "test123"} @@ -208,17 +181,69 @@ async def test_run_with_context_parameter(mock_agent, mock_model): @pytest.mark.asyncio -async def test_get_model_settings_with_none_values(mock_model): - """Test _get_model_settings handles None values from agent properly""" +async def test_run_with_none_values_from_agent_does_not_crash(mock_model: MockRealtimeModel): + """Test that runner handles agents with None values without crashing""" agent = Mock(spec=RealtimeAgent) agent.get_system_prompt = AsyncMock(return_value=None) agent.get_all_tools = AsyncMock(return_value=None) runner = RealtimeRunner(agent, model=mock_model) - with patch("agents.realtime.runner.RealtimeSession"): - await runner.run() + with patch("agents.realtime.runner.RealtimeSession") as mock_session_class: + mock_session = Mock(spec=RealtimeSession) + mock_session_class.return_value = mock_session + + session = await runner.run() + + # Should not crash and return session + assert session == mock_session + # Runner no longer calls agent methods directly - session does that + agent.get_system_prompt.assert_not_called() + agent.get_all_tools.assert_not_called() + + +@pytest.mark.asyncio +async def test_tool_and_handoffs_are_correct(mock_model: MockRealtimeModel): + @function_tool + def tool_one(): + return "result_one" + + agent_1 = RealtimeAgent( + name="one", + instructions="instr_one", + ) + agent_2 = RealtimeAgent( + name="two", + instructions="instr_two", + tools=[tool_one], + handoffs=[agent_1], + ) + + session = RealtimeSession( + model=mock_model, + agent=agent_2, + context=None, + model_config=None, + run_config=None, + ) + + async with session: + pass - # Should not crash and agent methods should be called - agent.get_system_prompt.assert_called_once() - agent.get_all_tools.assert_called_once() + # Assert that the model.connect() was called with the correct settings + connect_args = mock_model.connect_args + assert connect_args is not None + assert isinstance(connect_args, dict) + initial_model_settings = connect_args["initial_model_settings"] + assert initial_model_settings is not None + assert isinstance(initial_model_settings, dict) + assert initial_model_settings["instructions"] == "instr_two" + assert len(initial_model_settings["tools"]) == 1 + tool = initial_model_settings["tools"][0] + assert tool.name == "tool_one" + + handoffs = initial_model_settings["handoffs"] + assert len(handoffs) == 1 + handoff = handoffs[0] + assert handoff.tool_name == "transfer_to_one" + assert handoff.agent_name == "one" diff --git a/tests/realtime/test_session.py b/tests/realtime/test_session.py index 7c1eb53ff..3bb9b5931 100644 --- a/tests/realtime/test_session.py +++ b/tests/realtime/test_session.py @@ -29,7 +29,7 @@ RealtimeItem, UserMessageItem, ) -from agents.realtime.model import RealtimeModel +from agents.realtime.model import RealtimeModel, RealtimeModelConfig from agents.realtime.model_events import ( RealtimeModelAudioDoneEvent, RealtimeModelAudioEvent, @@ -1206,3 +1206,117 @@ def guardrail_func(context, agent, output): guardrail_events = [e for e in events if isinstance(e, RealtimeGuardrailTripped)] assert len(guardrail_events) == 1 assert len(guardrail_events[0].guardrail_results) == 2 + + +class TestModelSettingsIntegration: + """Test suite for model settings integration in RealtimeSession.""" + + @pytest.mark.asyncio + async def test_session_gets_model_settings_from_agent_during_connection(self): + """Test that session properly gets model settings from agent during __aenter__.""" + # Create mock model that records the config passed to connect() + mock_model = Mock(spec=RealtimeModel) + mock_model.connect = AsyncMock() + mock_model.add_listener = Mock() + + # Create agent with specific settings + agent = Mock(spec=RealtimeAgent) + agent.get_system_prompt = AsyncMock(return_value="Test agent instructions") + agent.get_all_tools = AsyncMock(return_value=[{"type": "function", "name": "test_tool"}]) + agent.handoffs = [] + + session = RealtimeSession(mock_model, agent, None) + + # Connect the session + await session.__aenter__() + + # Verify model.connect was called with settings from agent + mock_model.connect.assert_called_once() + connect_config = mock_model.connect.call_args[0][0] + + initial_settings = connect_config["initial_model_settings"] + assert initial_settings["instructions"] == "Test agent instructions" + assert initial_settings["tools"] == [{"type": "function", "name": "test_tool"}] + assert initial_settings["handoffs"] == [] + + await session.__aexit__(None, None, None) + + @pytest.mark.asyncio + async def test_model_config_overrides_agent_settings(self): + """Test that initial_model_settings from model_config override agent settings.""" + mock_model = Mock(spec=RealtimeModel) + mock_model.connect = AsyncMock() + mock_model.add_listener = Mock() + + agent = Mock(spec=RealtimeAgent) + agent.get_system_prompt = AsyncMock(return_value="Agent instructions") + agent.get_all_tools = AsyncMock(return_value=[{"type": "function", "name": "agent_tool"}]) + agent.handoffs = [] + + # Provide model config with overrides + model_config: RealtimeModelConfig = { + "initial_model_settings": { + "instructions": "Override instructions", + "voice": "nova", + "model_name": "gpt-4o-realtime", + } + } + + session = RealtimeSession(mock_model, agent, None, model_config=model_config) + + await session.__aenter__() + + # Verify overrides were applied + connect_config = mock_model.connect.call_args[0][0] + initial_settings = connect_config["initial_model_settings"] + + # Should have override values + assert initial_settings["instructions"] == "Override instructions" + assert initial_settings["voice"] == "nova" + assert initial_settings["model_name"] == "gpt-4o-realtime" + # Should still have agent tools since not overridden + assert initial_settings["tools"] == [{"type": "function", "name": "agent_tool"}] + + await session.__aexit__(None, None, None) + + @pytest.mark.asyncio + async def test_handoffs_are_included_in_model_settings(self): + """Test that handoffs from agent are properly processed into model settings.""" + mock_model = Mock(spec=RealtimeModel) + mock_model.connect = AsyncMock() + mock_model.add_listener = Mock() + + # Create agent with handoffs + agent = Mock(spec=RealtimeAgent) + agent.get_system_prompt = AsyncMock(return_value="Agent with handoffs") + agent.get_all_tools = AsyncMock(return_value=[]) + + # Create a mock handoff + handoff_agent = Mock(spec=RealtimeAgent) + handoff_agent.name = "handoff_target" + + mock_handoff = Mock(spec=Handoff) + mock_handoff.tool_name = "transfer_to_specialist" + mock_handoff.is_enabled = True + + agent.handoffs = [handoff_agent] # Agent handoff + + # Mock the _get_handoffs method since it's complex + with pytest.MonkeyPatch().context() as m: + + async def mock_get_handoffs(cls, agent, context_wrapper): + return [mock_handoff] + + m.setattr("agents.realtime.session.RealtimeSession._get_handoffs", mock_get_handoffs) + + session = RealtimeSession(mock_model, agent, None) + + await session.__aenter__() + + # Verify handoffs were included + connect_config = mock_model.connect.call_args[0][0] + initial_settings = connect_config["initial_model_settings"] + + assert initial_settings["handoffs"] == [mock_handoff] + + await session.__aexit__(None, None, None) diff --git a/tests/realtime/test_tracing.py b/tests/realtime/test_tracing.py index 85da63897..6ef1ae9a7 100644 --- a/tests/realtime/test_tracing.py +++ b/tests/realtime/test_tracing.py @@ -1,8 +1,11 @@ -from unittest.mock import AsyncMock, patch +from unittest.mock import AsyncMock, Mock, patch import pytest +from agents.realtime.agent import RealtimeAgent +from agents.realtime.model import RealtimeModel from agents.realtime.openai_realtime import OpenAIRealtimeWebSocketModel +from agents.realtime.session import RealtimeSession class TestRealtimeTracingIntegration: @@ -219,36 +222,24 @@ async def async_websocket(*args, **kwargs): @pytest.mark.asyncio async def test_tracing_disabled_prevents_tracing(self, mock_websocket): """Test that tracing_disabled=True prevents tracing configuration.""" - from agents.realtime.agent import RealtimeAgent - from agents.realtime.runner import RealtimeRunner - # Create a test agent and runner with tracing disabled + # Create a test agent and mock model agent = RealtimeAgent(name="test_agent", instructions="test") + agent.handoffs = [] - runner = RealtimeRunner(starting_agent=agent, config={"tracing_disabled": True}) + mock_model = Mock(spec=RealtimeModel) - # Test the _get_model_settings method directly since that's where the logic is - model_settings = await runner._get_model_settings( + # Create session with tracing disabled + session = RealtimeSession( + model=mock_model, agent=agent, - disable_tracing=True, # This should come from config["tracing_disabled"] - initial_settings=None, - overrides=None, + context=None, + model_config=None, + run_config={"tracing_disabled": True}, ) + # Test the _get_updated_model_settings_from_agent method directly + model_settings = await session._get_updated_model_settings_from_agent(agent) + # When tracing is disabled, model settings should have tracing=None assert model_settings["tracing"] is None - - # Also test that the runner passes disable_tracing=True correctly - with patch.object(runner, "_get_model_settings") as mock_get_settings: - mock_get_settings.return_value = {"tracing": None} - - with patch("agents.realtime.session.RealtimeSession") as mock_session_class: - mock_session = AsyncMock() - mock_session_class.return_value = mock_session - - await runner.run() - - # Verify that _get_model_settings was called with disable_tracing=True - mock_get_settings.assert_called_once_with( - agent=agent, disable_tracing=True, initial_settings=None, overrides=None - ) diff --git a/tests/test_session_exceptions.py b/tests/test_session_exceptions.py index a454cca92..da9390236 100644 --- a/tests/test_session_exceptions.py +++ b/tests/test_session_exceptions.py @@ -90,6 +90,8 @@ def fake_agent(): """Create a fake agent for testing.""" agent = Mock() agent.get_all_tools = AsyncMock(return_value=[]) + agent.get_system_prompt = AsyncMock(return_value="test instructions") + agent.handoffs = [] return agent From 362144eb8f6a68910f9e98f229689ca33a13b4b6 Mon Sep 17 00:00:00 2001 From: Rohan Mehta Date: Thu, 17 Jul 2025 13:30:03 -0400 Subject: [PATCH 4/4] v0.2.2 (#1170) --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index b72ccd594..5bc0456b8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai-agents" -version = "0.2.1" +version = "0.2.2" description = "OpenAI Agents SDK" readme = "README.md" requires-python = ">=3.9"