|
24 | 24 | OpenAIResponseInputToolWebSearch, |
25 | 25 | OpenAIResponseMessage, |
26 | 26 | OpenAIResponseOutputMessageContentOutputText, |
| 27 | + OpenAIResponseOutputMessageFunctionToolCall, |
27 | 28 | OpenAIResponseOutputMessageMCPCall, |
28 | 29 | OpenAIResponseOutputMessageWebSearchToolCall, |
29 | 30 | OpenAIResponseText, |
@@ -1169,3 +1170,75 @@ async def test_create_openai_response_with_invalid_text_format(openai_responses_ |
1169 | 1170 | model=model, |
1170 | 1171 | text=OpenAIResponseText(format={"type": "invalid"}), |
1171 | 1172 | ) |
| 1173 | + |
| 1174 | + |
| 1175 | +async def test_create_openai_response_with_output_types_as_input( |
| 1176 | + openai_responses_impl, mock_inference_api, mock_responses_store |
| 1177 | +): |
| 1178 | + """Test that response outputs can be used as inputs in multi-turn conversations. |
| 1179 | + |
| 1180 | + Before adding OpenAIResponseOutput types to OpenAIResponseInput, |
| 1181 | + creating a _OpenAIResponseObjectWithInputAndMessages with some output types |
| 1182 | + in the input field would fail with a Pydantic ValidationError. |
| 1183 | + |
| 1184 | + This test simulates storing a response where the input contains output message |
| 1185 | + types (MCP calls, function calls), which happens in multi-turn conversations. |
| 1186 | + """ |
| 1187 | + model = "meta-llama/Llama-3.1-8B-Instruct" |
| 1188 | + |
| 1189 | + # Mock the inference response |
| 1190 | + mock_inference_api.openai_chat_completion.return_value = fake_stream() |
| 1191 | + |
| 1192 | + # Create a response with store=True to trigger the storage path |
| 1193 | + result = await openai_responses_impl.create_openai_response( |
| 1194 | + input="What's the weather?", |
| 1195 | + model=model, |
| 1196 | + stream=True, |
| 1197 | + temperature=0.1, |
| 1198 | + store=True, |
| 1199 | + ) |
| 1200 | + |
| 1201 | + # Consume the stream |
| 1202 | + _ = [chunk async for chunk in result] |
| 1203 | + |
| 1204 | + # Verify store was called |
| 1205 | + assert mock_responses_store.store_response_object.called |
| 1206 | + |
| 1207 | + # Get the stored data |
| 1208 | + store_call_args = mock_responses_store.store_response_object.call_args |
| 1209 | + stored_response = store_call_args.kwargs["response_object"] |
| 1210 | + |
| 1211 | + # Now simulate a multi-turn conversation where outputs become inputs |
| 1212 | + input_with_output_types = [ |
| 1213 | + OpenAIResponseMessage(role="user", content="What's the weather?", name=None), |
| 1214 | + # These output types need to be valid OpenAIResponseInput |
| 1215 | + OpenAIResponseOutputMessageFunctionToolCall( |
| 1216 | + call_id="call_123", |
| 1217 | + name="get_weather", |
| 1218 | + arguments='{"city": "Tokyo"}', |
| 1219 | + type="function_call", |
| 1220 | + ), |
| 1221 | + OpenAIResponseOutputMessageMCPCall( |
| 1222 | + id="mcp_456", |
| 1223 | + type="mcp_call", |
| 1224 | + server_label="weather_server", |
| 1225 | + name="get_temperature", |
| 1226 | + arguments='{"location": "Tokyo"}', |
| 1227 | + output="25°C", |
| 1228 | + ), |
| 1229 | + ] |
| 1230 | + |
| 1231 | + # This simulates storing a response in a multi-turn conversation |
| 1232 | + # where previous outputs are included in the input. |
| 1233 | + stored_with_outputs = _OpenAIResponseObjectWithInputAndMessages( |
| 1234 | + id=stored_response.id, |
| 1235 | + created_at=stored_response.created_at, |
| 1236 | + model=stored_response.model, |
| 1237 | + status=stored_response.status, |
| 1238 | + output=stored_response.output, |
| 1239 | + input=input_with_output_types, # This will trigger Pydantic validation |
| 1240 | + messages=None, |
| 1241 | + ) |
| 1242 | + |
| 1243 | + assert stored_with_outputs.input == input_with_output_types |
| 1244 | + assert len(stored_with_outputs.input) == 3 |
0 commit comments