<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def get_all_tool_inputs(job, tools, outer_key='', mutation_caller_list=None):
 """ Iterate through all the tool options and download required files from their remote locations. :param dict tools: A dict of dicts of all tools, and their options :param str outer_key: If this is being called recursively, what was the outer dict called? :param list mutation_caller_list: A list of mutation caller keys to append the indexes to. :return: The fully resolved tool dictionary :rtype: dict """

    for tool in tools:
        for option in tools[tool]:
            if isinstance(tools[tool][option], dict):
                tools[tool][option] = get_all_tool_inputs(
                    job, {option: tools[tool][option]},
                    outer_key=':'.join([outer_key, tool]).lstrip(':'))[option]
            else:
                # If a file is of the type file, vcf, tar or fasta, it needs to be downloaded from
                # S3 if reqd, then written to job store.
                if option.split('_')[-1] in ['file', 'vcf', 'index', 'fasta', 'fai', 'idx', 'dict',
                                             'tbi', 'beds', 'gtf', 'config']:
                    tools[tool][option] = job.addChildJobFn(
                        get_pipeline_inputs, ':'.join([outer_key, tool, option]).lstrip(':'),
                        tools[tool][option]).rv()
                elif option == 'version':
                    tools[tool][option] = str(tools[tool][option])
    if mutation_caller_list is not None:
        # Guaranteed to occur only in the outermost loop
        indexes = tools.pop('indexes')
        indexes['chromosomes'] = parse_chromosome_string(job, indexes['chromosomes'])
        for mutation_caller in mutation_caller_list:
            if mutation_caller == 'indexes':
                continue
            tools[mutation_caller].update(indexes)
    return tools