@@ -283,6 +283,7 @@ def need_builtin_tool_call(self) -> bool:
283283 last_message .name == "code_interpreter"
284284 or last_message .name == "python"
285285 or last_message .name == "web_search_preview"
286+ or last_message .name .startswith ("container" )
286287 )
287288 ):
288289 return True
@@ -316,6 +317,8 @@ async def call_search_tool(
316317 self , tool_session : Union ["ClientSession" , Tool ], last_msg : FunctionCall
317318 ) -> list [ResponseInputOutputItem ]:
318319 self .called_tools .add ("browser" )
320+ if isinstance (tool_session , Tool ):
321+ return await tool_session .get_result_parsable_context (self )
319322 if envs .VLLM_TOOL_JSON_ERROR_AUTOMATIC_RETRY :
320323 try :
321324 args = json .loads (last_msg .arguments )
@@ -336,6 +339,49 @@ async def call_search_tool(
336339
337340 return [message ]
338341
342+ async def call_container_tool (
343+ self , tool_session : Union ["ClientSession" , Tool ], last_msg : Message
344+ ) -> list [Message ]:
345+ """
346+ Call container tool. Expect this to be run in a stateful docker
347+ with command line terminal.
348+ The official container tool would at least
349+ expect the following format:
350+ - for tool name: exec
351+ - args:
352+ {
353+ "cmd":List[str] "command to execute",
354+ "workdir":optional[str] "current working directory",
355+ "env":optional[object/dict] "environment variables",
356+ "session_name":optional[str] "session name",
357+ "timeout":optional[int] "timeout in seconds",
358+ "user":optional[str] "user name",
359+ }
360+ """
361+ self .called_tools .add ("container" )
362+ if isinstance (tool_session , Tool ):
363+ return await tool_session .get_result_parsable_context (self )
364+ # tool_name = last_msg.recipient.split(".")[1].split(" ")[0]
365+ if envs .VLLM_TOOL_JSON_ERROR_AUTOMATIC_RETRY :
366+ try :
367+ args = json .loads (last_msg .arguments )
368+ except json .JSONDecodeError as e :
369+ return _create_json_parse_error_messages (last_msg , e )
370+ else :
371+ args = json .loads (last_msg .arguments )
372+ result = await tool_session .call_tool ("cmd" , args )
373+ result_str = result .content [0 ].text
374+
375+ message = ResponseFunctionToolCallOutputItem (
376+ id = f"fco_{ random_uuid ()} " ,
377+ type = "function_call_output" ,
378+ call_id = f"call_{ random_uuid ()} " ,
379+ output = result_str ,
380+ status = "completed" ,
381+ )
382+
383+ return [message ]
384+
339385 async def call_tool (self ) -> list [ResponseInputOutputItem ]:
340386 if not self .parser .response_messages :
341387 return []
@@ -344,6 +390,10 @@ async def call_tool(self) -> list[ResponseInputOutputItem]:
344390 return await self .call_python_tool (self ._tool_sessions ["python" ], last_msg )
345391 elif last_msg .name == "web_search_preview" :
346392 return await self .call_search_tool (self ._tool_sessions ["browser" ], last_msg )
393+ elif last_msg .name .startswith ("container" ):
394+ return await self .call_container_tool (
395+ self ._tool_sessions ["container" ], last_msg
396+ )
347397 return []
348398
349399 def render_for_completion (self ):
0 commit comments