@@ -535,11 +535,17 @@ def get_place_to_travel():
535535 return "Paris"
536536
537537
538+ def get_horoscope (sign ):
539+ return f"{ sign } : Next Tuesday you will befriend a baby otter."
540+
541+
538542def call_function (name , args ):
539543 if name == "get_weather" :
540544 return get_weather (** args )
541545 elif name == "get_place_to_travel" :
542546 return get_place_to_travel ()
547+ elif name == "get_horoscope" :
548+ return get_horoscope (** args )
543549 else :
544550 raise ValueError (f"Unknown function: { name } " )
545551
@@ -828,3 +834,126 @@ async def test_output_messages_enabled(client: OpenAI, model_name: str, server):
828834 assert response .status == "completed"
829835 assert len (response .input_messages ) > 0
830836 assert len (response .output_messages ) > 0
837+
838+
839+ @pytest .mark .asyncio
840+ @pytest .mark .parametrize ("model_name" , [MODEL_NAME ])
841+ async def test_function_call_with_previous_input_messages (
842+ client : OpenAI , model_name : str
843+ ):
844+ """Test function calling using previous_input_messages
845+ for multi-turn conversation with a function call"""
846+
847+ # Define the get_horoscope tool
848+ tools = [
849+ {
850+ "type" : "function" ,
851+ "name" : "get_horoscope" ,
852+ "description" : "Get today's horoscope for an astrological sign." ,
853+ "parameters" : {
854+ "type" : "object" ,
855+ "properties" : {
856+ "sign" : {"type" : "string" },
857+ },
858+ "required" : ["sign" ],
859+ "additionalProperties" : False ,
860+ },
861+ "strict" : True ,
862+ }
863+ ]
864+
865+ # Step 1: First call with the function tool
866+ stream_response = await client .responses .create (
867+ model = model_name ,
868+ input = "What is the horoscope for Aquarius today?" ,
869+ tools = tools ,
870+ extra_body = {"enable_response_messages" : True },
871+ stream = True ,
872+ )
873+
874+ response = None
875+ async for event in stream_response :
876+ if event .type == "response.completed" :
877+ response = event .response
878+
879+ assert response is not None
880+ assert response .status == "completed"
881+
882+ # Step 2: Parse the first output to find the function_call type
883+ function_call = None
884+ for item in response .output :
885+ if item .type == "function_call" :
886+ function_call = item
887+ break
888+
889+ assert function_call is not None , "Expected a function_call in the output"
890+ assert function_call .name == "get_horoscope"
891+ assert function_call .call_id is not None
892+
893+ # Verify the format matches expectations
894+ args = json .loads (function_call .arguments )
895+ assert "sign" in args
896+
897+ # Step 3: Call the get_horoscope function
898+ result = call_function (function_call .name , args )
899+ assert "Aquarius" in result
900+ assert "baby otter" in result
901+
902+ # Get the input_messages and output_messages from the first response
903+ first_input_messages = response .input_messages
904+ first_output_messages = response .output_messages
905+
906+ # Construct the full conversation history using previous_input_messages
907+ previous_messages = (
908+ first_input_messages
909+ + first_output_messages
910+ + [
911+ {
912+ "role" : "tool" ,
913+ "name" : "functions.get_horoscope" ,
914+ "content" : [{"type" : "text" , "text" : str (result )}],
915+ }
916+ ]
917+ )
918+
919+ # Step 4: Make another responses.create() call with previous_input_messages
920+ stream_response_2 = await client .responses .create (
921+ model = model_name ,
922+ tools = tools ,
923+ input = "" ,
924+ extra_body = {
925+ "previous_input_messages" : previous_messages ,
926+ "enable_response_messages" : True ,
927+ },
928+ stream = True ,
929+ )
930+
931+ async for event in stream_response_2 :
932+ if event .type == "response.completed" :
933+ response_2 = event .response
934+
935+ assert response_2 is not None
936+ assert response_2 .status == "completed"
937+ assert response_2 .output_text is not None
938+
939+ # verify only one system message / developer message
940+ num_system_messages_input = 0
941+ num_developer_messages_input = 0
942+ num_function_call_input = 0
943+ for message_dict in response_2 .input_messages :
944+ message = Message .from_dict (message_dict )
945+ if message .author .role == "system" :
946+ num_system_messages_input += 1
947+ elif message .author .role == "developer" :
948+ num_developer_messages_input += 1
949+ elif message .author .role == "tool" :
950+ num_function_call_input += 1
951+ assert num_system_messages_input == 1
952+ assert num_developer_messages_input == 1
953+ assert num_function_call_input == 1
954+
955+ # Verify the output makes sense - should contain information about the horoscope
956+ output_text = response_2 .output_text .lower ()
957+ assert (
958+ "aquarius" in output_text or "otter" in output_text or "tuesday" in output_text
959+ )
0 commit comments