Files
2026-07-13 13:06:23 +08:00

223 lines
9.5 KiB
Python

from autoagent.registry import registry
from autoagent.environment import LocalEnv, DockerEnv
from typing import Union
from autoagent.tools.terminal_tools import (
create_file,
create_directory,
run_python,
print_stream,
terminal_page_up,
terminal_page_down,
terminal_page_to,
process_terminal_response
)
from autoagent.registry import register_tool
import json
def get_metachain_path(env: Union[LocalEnv, DockerEnv]) -> str:
result = env.run_command('pip show autoagent')
if result['status'] != 0:
raise Exception("Failed to list tools. Error: " + result['result'])
stdout = result['result']
for line in stdout.split('\n'):
if line.startswith('Editable project location:'):
path = line.split(':', 1)[1].strip()
return path
raise Exception("Failed to list tools. The MetaChain is not installed in editable mode.")
def protect_tools(tool_name: str):
if tool_name in registry.tools_info.keys():
raise Exception(f"The tool `{tool_name}` can NOT be modified. You can DIRECTLY use the `{tool_name}` tool by USING the `run_tool` tool. Or you can create a new tool using this tool by `from autoagent.tools import {tool_name}`.")
@register_tool("list_tools")
def list_tools(context_variables):
"""
List all plugin tools in the MetaChain.
Returns:
A list of information of all plugin tools including name, args, docstring, body, return_type, file_path.
"""
env: Union[LocalEnv, DockerEnv] = context_variables.get("code_env", LocalEnv())
try:
path = get_metachain_path(env)
except Exception as e:
return "Failed to list tools. Error: " + str(e)
python_code = '"from autoagent.registry import registry; import json; print(\\"TOOL_LIST_START\\"); print(json.dumps(registry.display_plugin_tools_info, indent=4)); print(\\"TOOL_LIST_END\\")"'
list_tools_cmd = f"cd {path} && DEFAULT_LOG=False python -c {python_code}"
result = env.run_command(list_tools_cmd)
if result['status'] != 0:
return "Failed to list tools. Error: " + result['result']
try:
output = result['result']
start_marker = "TOOL_LIST_START"
end_marker = "TOOL_LIST_END"
start_idx = output.find(start_marker) + len(start_marker)
end_idx = output.find(end_marker)
if start_idx == -1 or end_idx == -1:
return "Failed to parse tool list: markers not found"
json_str = output[start_idx:end_idx].strip()
return json_str
except Exception as e:
return f"Failed to process output: {str(e)}"
# return result['result']
def check_tool_name(tool_name: str):
if tool_name == "visual_question_answering":
raise Exception("The tool `visual_question_answering` is not allowed to be modified. Directly use the `visual_question_answering` tool to handlen ANY visual tasks.")
@register_tool("create_tool")
def create_tool(tool_name: str, tool_code: str, context_variables):
"""
Create a plugin tool.
Args:
tool_name: The name of the tool.
tool_code: The code of creating the tool. (You should strictly follow the format of the template given to you to create the tool.)
Returns:
A string representation of the result of the tool creation.
"""
# try:
# check_tool_name(tool_name)
# except Exception as e:
# return str(e)
env: Union[LocalEnv, DockerEnv] = context_variables.get("code_env", LocalEnv())
try:
protect_tools(tool_name)
except Exception as e:
return "[ERROR] Failed to protect the tool `" + tool_name + "` with the following error: " + str(e)
try:
path = get_metachain_path(env)
except Exception as e:
return "[ERROR] Failed to list tools. Error: " + str(e)
tools_dir = path + "/autoagent/tools"
try:
tool_path = tools_dir + "/" + tool_name + ".py"
if "from autoagent.registry import register_plugin_tool" not in tool_code:
tool_code = "from autoagent.registry import register_plugin_tool\n" + tool_code
msg = create_file(tool_path, tool_code, context_variables)
if msg.startswith("Error creating file:"):
return "[ERROR] Failed to create tool. Error: " + msg
results = env.run_command(f'cd {path} && python {tool_path}')
if results['status'] != 0:
return "[ERROR] Failed to create tool. The python code of the tool is not correct. Error: " + results['result']
return "[SUCCESS] Successfully created tool: " + tool_name + " in " + tools_dir + "/" + tool_name + ".py"
except Exception as e:
return "[ERROR] Failed to create tool. Error: " + str(e)
def tool_exists(tool_name: str, context_variables):
try:
list_res = list_tools(context_variables)
tool_dict = json.loads(list_res)
if tool_name not in tool_dict.keys():
return False, tool_dict
return True, tool_dict
except Exception as e:
return "Before deleting a tool, you should list all tools first. But the following error occurred: " + str(e), None
@register_tool("delete_tool")
def delete_tool(tool_name: str, context_variables):
"""
Delete a plugin tool.
Args:
tool_name: The name of the tool to be deleted.
Returns:
A string representation of the result of the tool deletion.
"""
# try:
# check_tool_name(tool_name)
# except Exception as e:
# return str(e)
env: Union[LocalEnv, DockerEnv] = context_variables.get("code_env", LocalEnv())
# try:
# exist_flag, tool_dict = tool_exists(tool_name, context_variables)
# if isinstance(exist_flag, str):
# return "Before deleting a tool, you should list all tools first. But the following error occurred: " + exist_flag
# if not exist_flag:
# return f"The tool `{tool_name}` does not exist."
# except Exception as e:
# return "Before deleting a tool, you should list all tools first. But the following error occurred: " + str(e)
try:
protect_tools(tool_name)
except Exception as e:
return "[ERROR] Failed to delete the tool `" + tool_name + "` with the following error: " + str(e)
list_res = list_tools(context_variables)
tool_dict = json.loads(list_res)
try:
tool_path = tool_dict[tool_name]['file_path']
except KeyError:
return "The tool `" + tool_name + "` does not exist."
except Exception as e:
return "Error: " + str(e)
try:
result = env.run_command(f"rm {tool_path}")
if result['status'] != 0:
return f"[ERROR] Failed to delete tool: `{tool_name}`. Error: " + result['result']
return f"[SUCCESS] Successfully deleted tool: `{tool_name}`."
except Exception as e:
return f"[ERROR] Failed to delete tool: `{tool_name}`. Error: " + str(e)
@register_tool("run_tool")
@process_terminal_response
def run_tool(tool_name: str, run_code: str, context_variables):
"""
Run a tool with the given code.
Args:
tool_name: The name of the tool to be run.
run_code: The code to be run.
Returns:
A string representation of the result of the tool running.
"""
env: Union[LocalEnv, DockerEnv] = context_variables.get("code_env", LocalEnv())
try:
path = get_metachain_path(env)
except Exception as e:
return "Failed to get the path of the MetaChain. Error: " + str(e)
# try:
# exist_flag, tool_dict = tool_exists(tool_name, context_variables)
# if isinstance(exist_flag, str):
# return "Before deleting a tool, you should list all tools first. But the following error occurred: " + exist_flag
# if not exist_flag:
# return f"The tool `{tool_name}` does not exist."
# except Exception as e:
# return "Before testing a tool, you should list all tools first. But the following error occurred: " + str(e)
test_dir = path + "/test_tools"
try:
msg = create_directory(test_dir, context_variables)
if msg.startswith("Error creating directory:"):
return "[ERROR] Failed to create the test directory. Error: " + msg
except Exception as e:
return "[ERROR] Failed to create the test directory. Error: " + str(e)
test_file_path = test_dir + "/" + "test_" + tool_name + ".py"
try:
msg = create_file(test_file_path, run_code, context_variables)
if msg.startswith("Error creating file:"):
return "[ERROR] Failed to create the test file. Error: " + msg
except Exception as e:
return "[ERROR] Failed to create the test file. Error: " + str(e)
try:
# result = run_python(context_variables, test_file_path, cwd=path, env_vars={"DEFAULT_LOG": "False"})
# if "[SUCCESS]" not in result:
# return "[ERROR] Failed to test the tool. The test case is not correct. The result is: " + result
# return f"The result is of the tool `{tool_name}`: \n{result.replace('[SUCCESS]', '')}"
run_cmd = f"cd {path} && DEFAULT_LOG=False python {test_file_path}"
result = env.run_command(run_cmd, print_stream)
return result
except Exception as e:
return "[ERROR] Failed to test the tool. Error: " + str(e)
if __name__ == "__main__":
# print(list_tools({}))
# print(create_tool("visual_question_answering", "print('Hello, World!')", {}))
test_code = """
from autoagent.tools import test_file_tools
print(test_file_tools())
"""
print(run_tool("test_file_tools", test_code, {}))
print(terminal_page_down())