@@ -200,7 +200,7 @@ def my_func() -> str:
200200
201201
202202async def test_raw_foundry_agent_chat_client_prepare_options_strips_client_side_fields () -> None :
203- """Test that _prepare_options strips model and tool-loop fields from run_options."""
203+ """Test that _prepare_options strips model, tool-loop, and text fields from run_options."""
204204
205205 mock_project = MagicMock ()
206206 mock_openai = MagicMock ()
@@ -225,6 +225,8 @@ def my_func() -> str:
225225 "tools" : [{"type" : "function" , "function" : {"name" : "my_func" }}],
226226 "tool_choice" : "auto" ,
227227 "parallel_tool_calls" : True ,
228+ "text" : {"format" : {"type" : "json_schema" , "name" : "x" , "schema" : {"type" : "object" }}},
229+ "text_format" : MagicMock (),
228230 },
229231 ):
230232 result = await client ._prepare_options (
@@ -236,9 +238,72 @@ def my_func() -> str:
236238 assert "tools" not in result
237239 assert "tool_choice" not in result
238240 assert "parallel_tool_calls" not in result
241+ assert "text" not in result
242+ assert "text_format" not in result
239243 assert result == {}
240244
241245
246+ async def test_raw_foundry_agent_chat_client_prepare_options_strips_text_for_runtime_response_format () -> None :
247+ """Issue #5467: per-call response_format must not be sent to the Foundry agent endpoint.
248+
249+ The Foundry agent endpoint rejects requests that carry per-call ``text``
250+ when an agent is bound (``400 invalid_payload "Not allowed when agent is
251+ specified."``). The runtime ``response_format`` must instead be honored
252+ client-side via ``ChatResponse``'s lazy parsing path.
253+ """
254+ from pydantic import BaseModel
255+
256+ class OutputStruct (BaseModel ):
257+ location : str
258+ conditions : str
259+
260+ mock_project = MagicMock ()
261+ mock_project .get_openai_client .return_value = MagicMock ()
262+
263+ client = RawFoundryAgentChatClient (
264+ project_client = mock_project ,
265+ agent_name = "test-agent" ,
266+ )
267+
268+ # Simulate what the parent OpenAI Responses client produces for a Pydantic
269+ # ``response_format``: it sets ``text_format`` and would route through
270+ # ``responses.parse()``.
271+ with patch (
272+ "agent_framework_openai._chat_client.RawOpenAIChatClient._prepare_options" ,
273+ new_callable = AsyncMock ,
274+ return_value = {"text_format" : OutputStruct },
275+ ):
276+ result = await client ._prepare_options (
277+ messages = [Message (role = "user" , contents = "hi" )],
278+ options = {"response_format" : OutputStruct },
279+ )
280+
281+ assert "text" not in result
282+ assert "text_format" not in result
283+
284+ # And for the dict / json_schema variant the parent populates ``text``.
285+ with patch (
286+ "agent_framework_openai._chat_client.RawOpenAIChatClient._prepare_options" ,
287+ new_callable = AsyncMock ,
288+ return_value = {
289+ "text" : {
290+ "format" : {
291+ "type" : "json_schema" ,
292+ "name" : "WeatherDigest" ,
293+ "schema" : {"type" : "object" , "properties" : {"location" : {"type" : "string" }}},
294+ }
295+ }
296+ },
297+ ):
298+ result = await client ._prepare_options (
299+ messages = [Message (role = "user" , contents = "hi" )],
300+ options = {"response_format" : {"type" : "json_schema" , "json_schema" : {"name" : "WeatherDigest" }}},
301+ )
302+
303+ assert "text" not in result
304+ assert "text_format" not in result
305+
306+
242307async def test_raw_foundry_agent_chat_client_prepare_options_maps_agent_session_id_to_extra_body () -> None :
243308 """Test that service_session_id is forwarded as agent_session_id for hosted sessions."""
244309
0 commit comments