@@ -79,15 +79,18 @@ def print_info(msg):
7979# ---------------------------------------------------------------------------
8080
8181
82- def chat_completion (url , messages , tools = None , stream = False ):
82+ def chat_completion (url , messages , tools = None , stream = False , force_tools = False ):
8383 payload = {
8484 "messages" : messages ,
8585 "stream" : stream ,
8686 "max_tokens" : 4096 ,
8787 }
8888 if tools :
8989 payload ["tools" ] = tools
90- payload ["tool_choice" ] = "auto"
90+ if force_tools :
91+ payload ["tool_choice" ] = "required"
92+ else :
93+ payload ["tool_choice" ] = "auto"
9194
9295 try :
9396 response = requests .post (url , json = payload , stream = stream )
@@ -160,7 +163,13 @@ def chat_completion(url, messages, tools=None, stream=False):
160163 return result
161164
162165
163- def run_agentic_loop (url , messages , tools , mock_tool_responses , stream , max_turns = 6 ):
166+ def all_tools_called (tools , all_tool_calls ):
167+ all_tool_names = set ([tc ["function" ]["name" ] for tc in tools ])
168+ all_called_tool_names = set ([tc ["function" ]["name" ] for tc in all_tool_calls ])
169+ return all_tool_names == all_called_tool_names
170+
171+
172+ def run_agentic_loop (url , messages , tools , mock_tool_responses , stream , max_turns = 6 , force_tools = False ):
164173 """
165174 Drive the multi-turn tool-call loop:
166175 1. Send messages to model.
@@ -172,8 +181,8 @@ def run_agentic_loop(url, messages, tools, mock_tool_responses, stream, max_turn
172181 msgs = list (messages )
173182 all_tool_calls : list [dict ] = []
174183
175- for _ in range (max_turns ):
176- result = chat_completion (url , msgs , tools = tools , stream = stream )
184+ for t in range (max_turns ):
185+ result = chat_completion (url , msgs , tools = tools , stream = stream , force_tools = ( force_tools and not all_tools_called ( tools , all_tool_calls )) )
177186 if result is None :
178187 return all_tool_calls , None
179188
@@ -235,17 +244,18 @@ def run_agentic_loop(url, messages, tools, mock_tool_responses, stream, max_turn
235244# ---------------------------------------------------------------------------
236245
237246
238- def run_test (url , test_case , stream ):
247+ def run_test (url , test_case , stream , force_tools ):
239248 name = test_case ["name" ]
240249 mode = f"{ 'stream' if stream else 'non-stream' } "
241- print_header (f"{ name } [{ mode } ] " )
250+ print_header (f"{ name } [{ mode } , force_tools= { force_tools } ] " )
242251
243252 all_tool_calls , final_content = run_agentic_loop (
244253 url ,
245254 messages = test_case ["messages" ],
246255 tools = test_case ["tools" ],
247256 mock_tool_responses = test_case ["mock_tool_responses" ],
248257 stream = stream ,
258+ force_tools = force_tools
249259 )
250260
251261 if final_content is None and not all_tool_calls :
@@ -1093,6 +1103,9 @@ def main():
10931103 parser .add_argument (
10941104 "--stream-only" , action = "store_true" , help = "Only run streaming mode tests"
10951105 )
1106+ parser .add_argument (
1107+ "--force-tools" , action = "store_true" , help = "Change tool mode to forced instead of auto"
1108+ )
10961109 parser .add_argument (
10971110 "--test" ,
10981111 help = "Run only the test whose name contains this substring (case-insensitive)" ,
@@ -1103,10 +1116,13 @@ def main():
11031116 print_info (f"Testing server at { url } " )
11041117
11051118 modes = []
1119+ force_tools = False
11061120 if not args .stream_only :
11071121 modes .append (False )
11081122 if not args .no_stream :
11091123 modes .append (True )
1124+ if args .force_tools :
1125+ force_tools = True
11101126
11111127 cases : list [dict ] = ALL_TEST_CASES
11121128 if args .test :
@@ -1121,7 +1137,7 @@ def main():
11211137 for stream in modes :
11221138 for case in cases :
11231139 total += 1
1124- if run_test (url , case , stream = stream ):
1140+ if run_test (url , case , stream = stream , force_tools = force_tools ):
11251141 passed += 1
11261142
11271143 color = GREEN if passed == total else RED
0 commit comments