@@ -278,12 +278,14 @@ def append_tool_output(self, output: list[ResponseInputOutputItem]) -> None:
278278 def need_builtin_tool_call (self ) -> bool :
279279 """Return true if the last message is a MCP tool call"""
280280 last_message = self .parser .response_messages [- 1 ]
281- # TODO: figure out which tools are MCP tools
282- if ( # noqa: SIM103
283- last_message .type == "function_call"
284- and last_message .name in ("code_interpreter" , "python" )
285- ):
286- return True
281+ # TODO(qandrew): figure out which tools are MCP tools
282+ if last_message .type == "function_call" : # noqa: SIM102
283+ if last_message .name in (
284+ "code_interpreter" ,
285+ "python" ,
286+ "web_search_preview" ,
287+ ) or last_message .name .startswith ("container" ):
288+ return True
287289
288290 return False
289291
@@ -310,12 +312,87 @@ async def call_python_tool(
310312
311313 return [message ]
312314
315+ async def call_search_tool (
316+ self , tool_session : Union ["ClientSession" , Tool ], last_msg : FunctionCall
317+ ) -> list [ResponseInputOutputItem ]:
318+ self .called_tools .add ("browser" )
319+ if isinstance (tool_session , Tool ):
320+ return await tool_session .get_result_parsable_context (self )
321+ if envs .VLLM_TOOL_JSON_ERROR_AUTOMATIC_RETRY :
322+ try :
323+ args = json .loads (last_msg .arguments )
324+ except json .JSONDecodeError as e :
325+ return _create_json_parse_error_messages (last_msg , e )
326+ else :
327+ args = json .loads (last_msg .arguments )
328+ result = await tool_session .call_tool ("search" , args )
329+ result_str = result .content [0 ].text
330+
331+ message = ResponseFunctionToolCallOutputItem (
332+ id = f"fco_{ random_uuid ()} " ,
333+ type = "function_call_output" ,
334+ call_id = f"call_{ random_uuid ()} " ,
335+ output = result_str ,
336+ status = "completed" ,
337+ )
338+
339+ return [message ]
340+
341+ async def call_container_tool (
342+ self , tool_session : Union ["ClientSession" , Tool ], last_msg : Message
343+ ) -> list [Message ]:
344+ """
345+ Call container tool. Expect this to be run in a stateful docker
346+ with command line terminal.
347+ The official container tool would at least
348+ expect the following format:
349+ - for tool name: exec
350+ - args:
351+ {
352+ "cmd":List[str] "command to execute",
353+ "workdir":optional[str] "current working directory",
354+ "env":optional[object/dict] "environment variables",
355+ "session_name":optional[str] "session name",
356+ "timeout":optional[int] "timeout in seconds",
357+ "user":optional[str] "user name",
358+ }
359+ """
360+ self .called_tools .add ("container" )
361+ if isinstance (tool_session , Tool ):
362+ return await tool_session .get_result_parsable_context (self )
363+ # tool_name = last_msg.recipient.split(".")[1].split(" ")[0]
364+ if envs .VLLM_TOOL_JSON_ERROR_AUTOMATIC_RETRY :
365+ try :
366+ args = json .loads (last_msg .arguments )
367+ except json .JSONDecodeError as e :
368+ return _create_json_parse_error_messages (last_msg , e )
369+ else :
370+ args = json .loads (last_msg .arguments )
371+ result = await tool_session .call_tool ("exec" , args )
372+ result_str = result .content [0 ].text
373+
374+ message = ResponseFunctionToolCallOutputItem (
375+ id = f"fco_{ random_uuid ()} " ,
376+ type = "function_call_output" ,
377+ call_id = f"call_{ random_uuid ()} " ,
378+ output = result_str ,
379+ status = "completed" ,
380+ )
381+
382+ return [message ]
383+
313384 async def call_tool (self ) -> list [ResponseInputOutputItem ]:
314385 if not self .parser .response_messages :
315386 return []
316387 last_msg = self .parser .response_messages [- 1 ]
317388 if last_msg .name == "code_interpreter" :
318389 return await self .call_python_tool (self ._tool_sessions ["python" ], last_msg )
390+ elif last_msg .name == "web_search_preview" :
391+ return await self .call_search_tool (self ._tool_sessions ["browser" ], last_msg )
392+ elif last_msg .name .startswith ("container" ):
393+ return await self .call_container_tool (
394+ self ._tool_sessions ["container" ], last_msg
395+ )
319396 return []
320397
321398 def render_for_completion (self ):
0 commit comments