defrun_tool_from_source( self, actor: User, tool_args: Dict[str, str], tool_source: str, tool_env_vars: Optional[Dict[str, str]] = None, tool_source_type: Optional[str] = None, tool_name: Optional[str] = None, tool_args_json_schema: Optional[Dict[str, Any]] = None, tool_json_schema: Optional[Dict[str, Any]] = None, ) -> ToolReturnMessage: """Run a tool from source code""" if tool_source_type isnotNoneand tool_source_type != "python": raise ValueError("Only Python source code is supported at this time")
# If tools_json_schema is explicitly passed in, override it on the created Tool object if tool_json_schema: tool = Tool(name=tool_name, source_code=tool_source, json_schema=tool_json_schema) else: # NOTE: we're creating a floating Tool object and NOT persisting to DB tool = Tool( name=tool_name, source_code=tool_source, args_json_schema=tool_args_json_schema, )
assert tool.name isnotNone, "Failed to create tool object"
# TODO eventually allow using agent state in tools agent_state = None
# Next, attempt to run the tool with the sandbox try: tool_execution_result = ToolExecutionSandbox(tool.name, tool_args, actor, tool_object=tool).run( agent_state=agent_state, additional_env_vars=tool_env_vars ) return ToolReturnMessage( id="null", tool_call_id="null", date=get_utc_time(), status=tool_execution_result.status, tool_return=str(tool_execution_result.func_return), stdout=tool_execution_result.stdout, stderr=tool_execution_result.stderr, )
defrun( self, agent_state: Optional[AgentState] = None, additional_env_vars: Optional[Dict] = None, ) -> ToolExecutionResult: """ Run the tool in a sandbox environment. Args: agent_state (Optional[AgentState]): The state of the agent invoking the tool additional_env_vars (Optional[Dict]): Environment variables to inject into the sandbox Returns: ToolExecutionResult: Object containing tool execution outcome (e.g. status, response) """ if tool_settings.e2b_api_key andnotself.privileged_tools: logger.debug(f"Using e2b sandbox to execute {self.tool_name}") result = self.run_e2b_sandbox(agent_state=agent_state, additional_env_vars=additional_env_vars) else: logger.debug(f"Using local sandbox to execute {self.tool_name}") result = self.run_local_dir_sandbox(agent_state=agent_state, additional_env_vars=additional_env_vars)
# Log out any stdout/stderr from the tool run logger.debug(f"Executed tool '{self.tool_name}', logging output from tool run: \n") for log_line in (result.stdout or []) + (result.stderr or []): logger.debug(f"{log_line}") logger.debug(f"Ending output log from tool run.")
# Get environment variables for the sandbox env = os.environ.copy() env_vars = self.sandbox_config_manager.get_sandbox_env_vars_as_dict(sandbox_config_id=sbx_config.id, actor=self.user, limit=100) env.update(env_vars)
# Get environment variables for this agent specifically if agent_state: env.update(agent_state.get_agent_env_vars_as_dict())
# Finally, get any that are passed explicitly into the `run` function call if additional_env_vars: env.update(additional_env_vars)
# Safety checks ifnot os.path.exists(local_configs.sandbox_dir) ornot os.path.isdir(local_configs.sandbox_dir): logger.warning(f"Sandbox directory does not exist, creating: {local_configs.sandbox_dir}") os.makedirs(local_configs.sandbox_dir)
# Write the code to a temp file in the sandbox_dir with tempfile.NamedTemporaryFile(mode="w", dir=local_configs.sandbox_dir, suffix=".py", delete=False) as temp_file: if local_configs.use_venv: # If using venv, we need to wrap with special string markers to separate out the output and the stdout (since it is all in stdout) code = self.generate_execution_script(agent_state=agent_state, wrap_print_with_markers=True) else: code = self.generate_execution_script(agent_state=agent_state)
temp_file.write(code) temp_file.flush() temp_file_path = temp_file.name try: if local_configs.use_venv: returnself.run_local_dir_sandbox_venv(sbx_config, env, temp_file_path) else: returnself.run_local_dir_sandbox_directly(sbx_config, env, temp_file_path) except Exception as e: logger.error(f"Executing tool {self.tool_name} has an unexpected error: {e}") logger.error(f"Logging out tool {self.tool_name} auto-generated code for debugging: \n\n{code}") raise e finally: # Clean up the temp file os.remove(temp_file_path)
try: if local_configs.use_venv: returnself.run_local_dir_sandbox_venv(sbx_config, env, temp_file_path) else: returnself.run_local_dir_sandbox_directly(sbx_config, env, temp_file_path) except Exception as e: logger.error(f"Executing tool {self.tool_name} has an unexpected error: {e}") logger.error(f"Logging out tool {self.tool_name} auto-generated code for debugging: \n\n{code}") raise e finally: # Clean up the temp file os.remove(temp_file_path)
# Read and compile the Python script withopen(temp_file_path, "r", encoding="utf-8") as f: source = f.read() code_obj = compile(source, temp_file_path, "exec")
# Provide a dict for globals. globals_dict = dict(env) # or {} # If you need to mimic `__main__` behavior: globals_dict["__name__"] = "__main__" globals_dict["__file__"] = temp_file_path
# Get result from the global dict func_result = globals_dict.get(self.LOCAL_SANDBOX_RESULT_VAR_NAME) func_return, agent_state = self.parse_best_effort(func_result)
except Exception as e: func_return = get_friendly_error_msg( function_name=self.tool_name, exception_name=type(e).__name__, exception_message=str(e), ) traceback.print_exc(file=sys.stderr) status = "error"